diff options
| author | David S. Miller <davem@nuts.ninka.net> | 2002-10-13 09:28:42 -0700 |
|---|---|---|
| committer | David S. Miller <davem@nuts.ninka.net> | 2002-10-13 09:28:42 -0700 |
| commit | a6805352ac064bcdca2b90aaa78efe6df2243b47 (patch) | |
| tree | 4c385f016c82c0d19d451e4b1547caab7f258027 | |
| parent | f10972bec12a21510c21371ef66270844a164964 (diff) | |
| parent | 71660e156c8516c75e63d40d9f6c19af82340071 (diff) | |
Merge nuts.ninka.net:/home/davem/src/BK/network-2.5
into nuts.ninka.net:/home/davem/src/BK/net-2.5
204 files changed, 5964 insertions, 5373 deletions
diff --git a/Documentation/Changes b/Documentation/Changes index 1d7b57d29ee1..34bfa20dc2a6 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -95,7 +95,7 @@ your version of gcc 2.95.x, may necessitate using -fno-strict-aliasing). Make ---- -You will need Gnu make 3.77 or later to build the kernel. +You will need Gnu make 3.78 or later to build the kernel. Binutils -------- @@ -287,9 +287,9 @@ gcc 2.95.3 ---------- o <ftp://ftp.gnu.org/gnu/gcc/gcc-2.95.3.tar.gz> -Make 3.77 +Make 3.78 --------- -o <ftp://ftp.gnu.org/gnu/make/make-3.77.tar.gz> +o <ftp://ftp.gnu.org/gnu/make/make-3.78.1.tar.gz> Binutils -------- diff --git a/Documentation/arm/XScale/ADIFCC/80200EVB b/Documentation/arm/XScale/ADIFCC/80200EVB new file mode 100644 index 000000000000..1be2f340eb78 --- /dev/null +++ b/Documentation/arm/XScale/ADIFCC/80200EVB @@ -0,0 +1,111 @@ + +Board Overview +----------------------------- + +This is an beta release of the Xscale Linux port to the ADI 80200EVB +evaluation board. + +The 80200EVB is an evaluation platform for ADI Engineering's high-performance +80200FCC chipset for the Intel 80200 XScale CPU. The 80200FCC is an open +source FPGA based system that contains a PCI unit and a high performance +memory controller. + +In addition to the 80200FCC, the board also contains a 16C550 UART, and 4MB +of flash. + +The board is still under development and currently only the UART is functional +as the PCI bits have not been programmed into the FPGA. + +For more information on the board, see http://www.adiengineering.com + +Port Status +----------------------------- + +Supported: + +- Onboard UART (Polled operation only) +- Cache/TLB locking on 80200 CPU + +TODO: + +- PCI when hardware supports it + +Building the Kernel +----------------------------- +change Linux makefile +make adi_evb_config +make oldconfig +make dep +make zImage + +Loading Linux +----------------------------- + +Before you can use Linux on the ADI board, you need to grab the following: + +ADI 80200EVB Monitor: + ftp://source.mvista.com/pub/xscale/ADI_EVB/monitor.srec + +ADI JFFS2 Image: + ftp://source.mvista.com/pub/xscale/ADI_EVB/adi.jffs2 + +Once you've got the Cygnus prompt, type in the following command: + + load + +On another terminal window: + + cat monitor.srec > /dev/ttyS0 + +(replace ttyS0 with the serial port you are using) + +Once completed, just type 'go' at the cygmon prompt and you should see: + + MontaVista IQ80310 Monitor Version 0.1 + monitor> + +Type 'b 115200' at the prompt and change your terminal speed to 115200 + +The first thing to do is to upload and burn the jffs2 filesystem image +onto the boards 4MB of flash: + + monitor> u c1000000 + Uploading file at 0xc1000000 + Now send file with ymodem + +Do as the monitor says and transfer the file adi.jffs2. Once complete, +the following will copy the jffs2 image to location 0x80000 in the flash. + + monitor> f 8000 c1000000 200000 + Erasing sector 0x00080000 + Writing sector 0x00080000 with data at 0xC1000000 + Erasing sector 0x000A0000 + Writing sector 0x000A0000 with data at 0xC1020000 + Erasing sector 0x000C0000 + ... + +Now use the same command as above to upload your zImage to location c1000000. +When you've done that, type 'j c1000000' to run Linux. Login as +root and you're all set to go. + +Misc Notes +----------------------------- + +The current version of the HW does not have an onboard timer, so the 80200 +PMU is not available for general use as it is being used for a timer source. + +By default, the MTD driver reserves the first 512K for bootloaders and +the remaining 3.5MB for the filesystem. You can edit drivers/mtd/map/adi_evb.c +to change this as needed for your application. + +Contributors +----------------------------- + +Thanks to ADI Engineering for providing the hardware for development + +Deepak Saxena <dsaxena@mvista.com> - Initial port + +----------------------------- +Enjoy. If you have any problem please contact Deepak Saxena +dsaxena@mvista.com + diff --git a/Documentation/arm/XScale/IOP310/IQ80310 b/Documentation/arm/XScale/IOP310/IQ80310 new file mode 100644 index 000000000000..4284d458e6f9 --- /dev/null +++ b/Documentation/arm/XScale/IOP310/IQ80310 @@ -0,0 +1,295 @@ + +Board Overview +----------------------------- + +The Cyclone IQ80310 board is an evaluation platform for Intel's 80200 Xscale +CPU and 80312 Intelligent I/O chipset (collectively called IOP310 chipset). + +The 80312 contains dual PCI hoses (called the ATUs), a PCI-to-PCI bridge, +three DMA channels (1 on secondary PCI, one on primary PCI ), I2C, I2O +messaging unit, XOR unit for RAID operations, a bus performance monitoring +unit, and a memory controller with ECC features. + +For more information on the board, see http://developer.intel.com/iio + +Port Status +----------------------------- + +Supported: + +- MTD/JFFS/JFFS2 +- NFS root +- RAMDISK root +- 2ndary PCI slots +- Onboard ethernet +- Serial ports (ttyS0/S1) +- Cache/TLB locking on 80200 CPU +- Performance monitoring unit on 80200 CPU +- 80200 Performance Monitoring Unit +- Acting as a system controller on Cyclone 80303BP PCI backplane +- DMA engines (EXPERIMENTAL) +- 80312 Bus Performance Monitor (EXPERIMENTAL) +- Application Accelerator Unit (XOR engine for RAID) (EXPERIMENTAL) +- Messaging Unit (EXPERIMENTAL) + +TODO: +- I2C + +Building the Kernel +----------------------------- +make iq80310_config +make oldconfig +make dep +make zImage + +This will build an image setup for BOOTP/NFS root support. To change this, +just run make menuconfig and disable nfs root or add a "root=" option. + +Preparing the Hardware +----------------------------- + +This document assumes you're using a Rev D or newer board running +Redboot as the bootloader. + +The as-supplied RedBoot image appears to leave the first page of RAM +in a corrupt state such that certain words in that page are unwritable +and contain random data. The value of the data, and the location within +the first page changes with each boot, but is generally in the range +0xa0000150 to 0xa0000fff. + +You can grab the source from the ECOS CVS or you can get a prebuilt image +from: + + ftp://source.mvista.com/pub/xscale/iop310/IQ80310/redboot.bin + +which is: + + # strings redboot.bin | grep bootstrap + RedBoot(tm) bootstrap and debug environment, version UNKNOWN - built 14:58:21, Aug 15 2001 + +md5sum of this version: + + bcb96edbc6f8e55b16c165930b6e4439 redboot.bin + +You have two options to program it: + +1. Using the FRU program (see the instructions in the user manual). + +2. Using a Linux host, with MTD support built into the host kernel: + - ensure that the RedBoot image is not locked (issue the following + command under the existing RedBoot image): + RedBoot> fis unlock -f 0 -l 0x40000 + - switch S3-1 and S3-2 on. + - reboot the host + - login as root + - identify the 80310 card: + # lspci + ... + 00:0c.1 Memory controller: Intel Corporation 80310 IOP [IO Processor] (rev 01) + - in this example, bus 0, slot 0c, function 1. + - insert the MTD modules, and the PCI map module: + # insmod drivers/mtd/maps/pci.o + - locate the MTD device (using the bus, slot, function) + # cat /proc/mtd + dev: size erasesize name + mtd0: 00800000 00020000 "00:0c.1" + - in this example, it is mtd device 0. Yours will be different. + Check carefully. + - program the flash + # cat redboot.bin > /dev/mtdblock0 + - check the kernel message log for errors (some cat commands don't + error on failure) + # dmesg + - switch S3-1 and S3-2 off + - reboot host + +In any case, make sure you do an 'fis init' command once you boot with the new +RedBoot image. + + + +Downloading Linux +----------------------------- + +Assuming you have your development system setup to act as a bootp/dhcp +server and running tftp: + + RedBoot> load -r -b 0xa1008000 /tftpboot/zImage.xs + Raw file loaded 0xa1008000-0xa1094bd8 + +If you're not using dhcp/tftp, you can use y-modem instead: + + RedBoot> load -r -b 0xa1008000 -m y + +Note that on Rev D. of the board, tftp does not work due to intermittent +interrupt issues, so you need to download using ymodem. + +Once the download is completed: + + RedBoot> go 0xa1008000 + +Root Devices +----------------------------- + +A kernel is not useful without a root filesystem, and you have several +choices with this board: NFS root, RAMDISK, or JFFS/JFFS2. For development +purposes, it is suggested that you use NFS root for easy access to various +tools. Once you're ready to deploy, probably want to utilize JFFS/JFFS2 on +the flash device. + +MTD on the IQ80310 +----------------------------- + +Linux on the IQ80310 supports RedBoot FIS paritioning if it is enabled. +Out of the box, once you've done 'fis init' on RedBoot, you will get +the following partitioning scheme: + + root@192.168.0.14:~# cat /proc/mtd + dev: size erasesize name + mtd0: 00040000 00020000 "RedBoot" + mtd1: 00040000 00020000 "RedBoot[backup]" + mtd2: 0075f000 00020000 "unallocated space" + mtd3: 00001000 00020000 "RedBoot config" + mtd4: 00020000 00020000 "FIS directory" + +To create an FIS directory, you need to use the fis command in RedBoot. +As an example, you can burn the kernel into the flash once it's downloaded: + + RedBoot> fis create -b 0xa1008000 -l 0x8CBAC -r 0xa1008000 -f 0x80000 kernel + ... Erase from 0x00080000-0x00120000: ..... + ... Program from 0xa1008000-0xa1094bac at 0x00080000: ..... + ... Unlock from 0x007e0000-0x00800000: . + ... Erase from 0x007e0000-0x00800000: . + ... Program from 0xa1fdf000-0xa1fff000 at 0x007e0000: . + ... Lock from 0x007e0000-0x00800000: . + + RedBoot> fis list + Name FLASH addr Mem addr Length Entry point + RedBoot 0x00000000 0x00000000 0x00040000 0x00000000 + RedBoot[backup] 0x00040000 0x00040000 0x00040000 0x00000000 + RedBoot config 0x007DF000 0x007DF000 0x00001000 0x00000000 + FIS directory 0x007E0000 0x007E0000 0x00020000 0x00000000 + kernel 0x00080000 0xA1008000 0x000A0000 0x00000000 + +This leads to the following Linux MTD setup: + + mtroot@192.168.0.14:~# cat /proc/mtd + dev: size erasesize name + mtd0: 00040000 00020000 "RedBoot" + mtd1: 00040000 00020000 "RedBoot[backup]" + mtd2: 000a0000 00020000 "kernel" + mtd3: 006bf000 00020000 "unallocated space" + mtd4: 00001000 00020000 "RedBoot config" + mtd5: 00020000 00020000 "FIS directory" + +Note that there is not a 1:1 mapping to the number of RedBoot paritions to +MTD partitions as unused space also gets allocated into MTD partitions. + +As an aside, the -r option when creating the Kernel entry allows you to +simply do an 'fis load kernel' to copy the image from flash into memory. +You can then do an 'fis go 0xa1008000' to start Linux. + +If you choose to use static partitioning instead of the RedBoot partioning: + + /dev/mtd0 0x00000000 - 0x0007ffff: Boot Monitor (512k) + /dev/mtd1 0x00080000 - 0x0011ffff: Kernel Image (640K) + /dev/mtd2 0x00120000 - 0x0071ffff: File System (6M) + /dev/mtd3 0x00720000 - 0x00800000: RedBoot Reserved (896K) + +To use a JFFS1/2 root FS, you need to donwload the JFFS image using either +tftp or ymodem, and then copy it to flash: + + RedBoot> load -r -b 0xa1000000 /tftpboot/jffs.img + Raw file loaded 0xa1000000-0xa1600000 + RedBoot> fis create -b 0xa1000000 -l 0x600000 -f 0x120000 jffs + ... Erase from 0x00120000-0x00720000: .................................. + ... Program from 0xa1000000-0xa1600000 at 0x00120000: .................. + ...................... + ... Unlock from 0x007e0000-0x00800000: . + ... Erase from 0x007e0000-0x00800000: . + ... Program from 0xa1fdf000-0xa1fff000 at 0x007e0000: . + ... Lock from 0x007e0000-0x00800000: . + RedBoot> fis list + Name FLASH addr Mem addr Length Entry point + RedBoot 0x00000000 0x00000000 0x00040000 0x00000000 + RedBoot[backup] 0x00040000 0x00040000 0x00040000 0x00000000 + RedBoot config 0x007DF000 0x007DF000 0x00001000 0x00000000 + FIS directory 0x007E0000 0x007E0000 0x00020000 0x00000000 + kernel 0x00080000 0xA1008000 0x000A0000 0xA1008000 + jffs 0x00120000 0x00120000 0x00600000 0x00000000 + +This looks like this in Linux: + + root@192.168.0.14:~# cat /proc/mtd + dev: size erasesize name + mtd0: 00040000 00020000 "RedBoot" + mtd1: 00040000 00020000 "RedBoot[backup]" + mtd2: 000a0000 00020000 "kernel" + mtd3: 00600000 00020000 "jffs" + mtd4: 000bf000 00020000 "unallocated space" + mtd5: 00001000 00020000 "RedBoot config" + mtd6: 00020000 00020000 "FIS directory" + +You need to boot the kernel once and watch the boot messages to see how the +JFFS RedBoot partition mapped into the MTD partition scheme. + +You can grab a pre-built JFFS image to use as a root file system at: + + ftp://source.mvista.com/pub/xscale/iop310/IQ80310/jffs.img + +For detailed info on using MTD and creating a JFFS image go to: + + http://www.linux-mtd.infradead.org. + +For details on using RedBoot's FIS commands, type 'fis help' or consult +your RedBoot manual. + +Contributors +----------------------------- + +Thanks to Intel Corporation for providing the hardware. + +John Clark <jclark@teamasa.com> - Initial discovery of RedBoot issues +Dave Jiang <dave.jiang@intel.com> - IRQ demux fixes, AAU, DMA, MU +Nicolas Pitre <nico@cam.org> - Initial port, cleanup, debugging +Matt Porter <mporter@mvista.com> - PCI subsystem development, debugging +Tim Sanders <tsanders@sanders.org> - Initial PCI code +Mark Salter <msalter@redhat.com> - RedBoot fixes +Deepak Saxena <dsaxena@mvista.com> - Cleanup, debug, cache lock, PMU + +----------------------------- +Enjoy. + +If you have any problems please contact Deepak Saxena <dsaxena@mvista.com> + +A few notes from rmk +----------------------------- + +These are notes of my initial experience getting the IQ80310 Rev D up and +running. In total, it has taken many hours to work out what's going on... +The version of redboot used is: + + RedBoot(tm) bootstrap and debug environment, version UNKNOWN - built 14:58:21, Aug 15 2001 + + +1. I've had a corrupted download of the redboot.bin file from Montavista's + FTP site. It would be a good idea if there were md5sums, sum or gpg + signatures available to ensure the integrity of the downloaded files. + The result of this was an apparantly 100% dead card. + +2. RedBoot Intel EtherExpress Pro 100 driver seems to be very unstable - + I've had it take out the whole of a 100mbit network for several minutes. + The Hub indiates ZERO activity, despite machines attempting to communicate. + Further to this, while tftping the kernel, the transfer will stall regularly, + and might even drop the link LED. + +3. There appears to be a bug in the Intel Documentation Pack that comes with + the IQ80310 board. Serial port 1, which is the socket next to the LEDs + is address 0xfe810000, not 0xfe800000. + + Note that RedBoot uses either serial port 1 OR serial port 2, so if you + have your console connected to the wrong port, you'll see redboot messages + but not kernel boot messages. + +4. Trying to use fconfig to setup a boot script fails - it hangs when trying + to erase the flash. diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 3ad9c3fd7f08..e7f223b0b9df 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -966,7 +966,7 @@ dirty_background_ratio Contains, as a percentage of total system memory, the number of pages at which the pdflush background writeback daemon will start writing out dirty data. -dirty_async_ratio +dirty_ratio ----------------- Contains, as a percentage of total system memory, the number of pages at which diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index ed6ccff766f4..e6f8c613c879 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -18,14 +18,14 @@ files can be found in mm/swap.c. Currently, these files are in /proc/sys/vm: - overcommit_memory - page-cluster -- dirty_async_ratio +- dirty_ratio - dirty_background_ratio - dirty_expire_centisecs - dirty_writeback_centisecs ============================================================== -dirty_async_ratio, dirty_background_ratio, dirty_expire_centisecs, +dirty_ratio, dirty_background_ratio, dirty_expire_centisecs, dirty_writeback_centisecs: See Documentation/filesystems/proc.txt diff --git a/MAINTAINERS b/MAINTAINERS index 23c9f7b02d97..a9b191413d74 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1592,6 +1592,11 @@ P: Julien Blache M: jb@technologeek.org S: Maintained +TI PARALLEL LINK CABLE DRIVER +P: Romain Lievin +M: roms@lpg.ticalc.org +S: Maintained + TIEMAN VOYAGER USB BRAILLE DISPLAY DRIVER P: Stephane Dalton M: sdalton@videotron.ca diff --git a/arch/arm/Makefile b/arch/arm/Makefile index d57501118e68..c38ea2d36835 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -8,6 +8,7 @@ # Copyright (C) 1995-2001 by Russell King LDFLAGS_vmlinux :=-p -X +AFLAGS_vmlinux.lds.o = -DTEXTADDR=$(TEXTADDR) -DDATAADDR=$(DATAADDR) OBJCOPYFLAGS :=-O binary -R .note -R .comment -S GZFLAGS :=-9 #CFLAGS +=-pipe @@ -50,18 +51,29 @@ tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110 tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100 tune-$(CONFIG_CPU_XSCALE) :=-mtune=strongarm #-mtune=xscale -CFLAGS_BOOT :=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -CFLAGS +=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -AFLAGS +=$(apcs-y) $(arch-y) -mno-fpu -msoft-float +# Force -mno-fpu to be passed to the assembler. Some versions of gcc don't +# do this with -msoft-float +CFLAGS_BOOT :=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Wa,-mno-fpu +CFLAGS +=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Wa,-mno-fpu +AFLAGS +=$(apcs-y) $(arch-y) -mno-fpu -msoft-float -Wa,-mno-fpu ifeq ($(CONFIG_CPU_26),y) PROCESSOR := armo HEAD := arch/arm/mach-arc/head.o arch/arm/kernel/init_task.o + ifeq ($(CONFIG_ROM_KERNEL),y) + DATAADDR = 0x02080000 + TEXTADDR = 0x03800000 + LDSCRIPT = arch/arm/vmlinux-armo-rom.lds.in + else + TEXTADDR = 0x02080000 + LDSCRIPT = arch/arm/vmlinux-armo.lds.in + endif endif ifeq ($(CONFIG_CPU_32),y) PROCESSOR = armv HEAD := arch/arm/kernel/head.o arch/arm/kernel/init_task.o +TEXTADDR = 0xC0008000 endif ifeq ($(CONFIG_ARCH_ARCA5K),y) @@ -175,7 +187,7 @@ core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/ core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ) drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/ -drivers-$(CONFIG_ARCH_L7200)) += drivers/acorn/char/ +drivers-$(CONFIG_ARCH_L7200) += drivers/acorn/char/ libs-y += arch/arm/lib/ diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 67278fa673f1..7078453e2c44 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -18,7 +18,7 @@ ZLDFLAGS = -p -X -T vmlinux.lds # ifeq ($(CONFIG_ARCH_ACORN),y) OBJS += ll_char_wr.o font.o -ZLDFLAGS += -defsym params=$(PARAMS_PHYS) +CFLAGS += -DPARAMS_PHYS=$(PARAMS_PHYS) endif ifeq ($(CONFIG_ARCH_NETWINDER),y) diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 4f22cecbb047..824831c320b0 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -55,6 +55,18 @@ .macro writeb, rb strb \rb, [r3, #0] .endm +#elif defined(CONFIG_ARCH_SA1100) + .macro loadsp, rb + mov \rb, #0x80000000 @ physical base address +# if defined(CONFIG_DEBUG_LL_SER3) + add \rb, \rb, #0x00050000 @ Ser3 +# else + add \rb, \rb, #0x00010000 @ Ser1 +# endif + .endm + .macro writeb, rb + str \rb, [r3, #0x14] @ UTDR + .endm #else #error no serial architecture defined #endif @@ -151,22 +163,55 @@ not_angel: ldmia r0, {r1, r2, r3, r4, r5, r6, ip, sp} subs r0, r0, r1 @ calculate the delta offset - teq r0, #0 @ if delta is zero, we're + @ if delta is zero, we're beq not_relocated @ running at the address we @ were linked at. - add r2, r2, r0 @ different address, so we - add r3, r3, r0 @ need to fix up various - add r5, r5, r0 @ pointers. + /* + * We're running at a different address. We need to fix + * up various pointers: + * r5 - zImage base address + * r6 - GOT start + * ip - GOT end + */ + add r5, r5, r0 add r6, r6, r0 add ip, ip, r0 + +#ifndef CONFIG_ZBOOT_ROM + /* + * If we're running fully PIC === CONFIG_ZBOOT_ROM = n, + * we need to fix up pointers into the BSS region. + * r2 - BSS start + * r3 - BSS end + * sp - stack pointer + */ + add r2, r2, r0 + add r3, r3, r0 add sp, sp, r0 + /* + * Relocate all entries in the GOT table. + */ 1: ldr r1, [r6, #0] @ relocate entries in the GOT add r1, r1, r0 @ table. This fixes up the str r1, [r6], #4 @ C references. cmp r6, ip blo 1b +#else + + /* + * Relocate entries in the GOT table. We only relocate + * the entries that are outside the (relocated) BSS region. + */ +1: ldr r1, [r6, #0] @ relocate entries in the GOT + cmp r1, r2 @ entry < bss_start || + cmphs r3, r1 @ _end < entry + addlo r1, r1, r0 @ table. This fixes up the + str r1, [r6], #4 @ C references. + cmp r6, ip + blo 1b +#endif not_relocated: mov r0, #0 1: str r0, [r2], #4 @ clear bss @@ -176,6 +221,11 @@ not_relocated: mov r0, #0 cmp r2, r3 blo 1b + /* + * The C runtime environment should now be setup + * sufficiently. Turn the cache on, set up some + * pointers, and start decompressing. + */ bl cache_on mov r1, sp @ malloc space above stack diff --git a/arch/arm/boot/compressed/ll_char_wr.S b/arch/arm/boot/compressed/ll_char_wr.S index c25ce8129aa6..d7bbd9da2fca 100644 --- a/arch/arm/boot/compressed/ll_char_wr.S +++ b/arch/arm/boot/compressed/ll_char_wr.S @@ -19,144 +19,116 @@ #include <linux/linkage.h> #include <asm/assembler.h> - .text + .text -#define BOLD 0x01 -#define ITALIC 0x02 -#define UNDERLINE 0x04 -#define FLASH 0x08 -#define INVERSE 0x10 - -LC0: .word bytes_per_char_h - .word video_size_row - .word acorndata_8x8 - .word con_charconvtable +LC0: .word LC0 + .word bytes_per_char_h + .word video_size_row + .word acorndata_8x8 + .word con_charconvtable +/* + * r0 = ptr + * r1 = char + * r2 = white + */ ENTRY(ll_write_char) - stmfd sp!, {r4 - r7, lr} + stmfd sp!, {r4 - r7, lr} @ @ Smashable regs: {r0 - r3}, [r4 - r7], (r8 - fp), [ip], (sp), [lr], (pc) @ - eor ip, r1, #UNDERLINE << 9 -/* - * calculate colours - */ - tst r1, #INVERSE << 9 - moveq r2, r1, lsr #16 - moveq r3, r1, lsr #24 - movne r2, r1, lsr #24 - movne r3, r1, lsr #16 - and r3, r3, #255 - and r2, r2, #255 -/* - * calculate offset into character table - */ - mov r1, r1, lsl #23 - mov r1, r1, lsr #20 -/* - * calculate offset required for each row [maybe I should make this an argument to this fn. - * Have to see what the register usage is like in the calling routines. - */ - adr r4, LC0 - ldmia r4, {r4, r5, r6, lr} - ldr r4, [r4] - ldr r5, [r5] -/* - * Go to resolution-dependent routine... - */ - cmp r4, #4 - blt Lrow1bpp - eor r2, r3, r2 @ Create eor mask to change colour from bg - orr r3, r3, r3, lsl #8 @ to fg. - orr r3, r3, r3, lsl #16 - add r0, r0, r5, lsl #3 @ Move to bottom of character - add r1, r1, #7 - ldrb r7, [r6, r1] - tst ip, #UNDERLINE << 9 - eoreq r7, r7, #255 - teq r4, #8 - beq Lrow8bpplp + /* + * calculate offset into character table + */ + mov r1, r1, lsl #3 + /* + * calculate offset required for each row. + */ + adr ip, LC0 + ldmia ip, {r3, r4, r5, r6, lr} + sub ip, ip, r3 + add r6, r6, ip + add lr, lr, ip + ldr r4, [r4, ip] + ldr r5, [r5, ip] + /* + * Go to resolution-dependent routine... + */ + cmp r4, #4 + blt Lrow1bpp + add r0, r0, r5, lsl #3 @ Move to bottom of character + orr r1, r1, #7 + ldrb r7, [r6, r1] + teq r4, #8 + beq Lrow8bpplp @ @ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc) @ - orr r3, r3, r3, lsl #4 -Lrow4bpplp: ldr r7, [lr, r7, lsl #2] - mul r7, r2, r7 - tst r1, #7 @ avoid using r7 directly after - eor ip, r3, r7 - str ip, [r0, -r5]! - LOADREGS(eqfd, sp!, {r4 - r7, pc}) - sub r1, r1, #1 - ldrb r7, [r6, r1] - ldr r7, [lr, r7, lsl #2] - mul r7, r2, r7 - tst r1, #7 @ avoid using r7 directly after - eor ip, r3, r7 - str ip, [r0, -r5]! - subne r1, r1, #1 - ldrneb r7, [r6, r1] - bne Lrow4bpplp - LOADREGS(fd, sp!, {r4 - r7, pc}) +Lrow4bpplp: + ldr r7, [lr, r7, lsl #2] + mul r7, r2, r7 + sub r1, r1, #1 @ avoid using r7 directly after + str r7, [r0, -r5]! + ldrb r7, [r6, r1] + ldr r7, [lr, r7, lsl #2] + mul r7, r2, r7 + tst r1, #7 @ avoid using r7 directly after + str r7, [r0, -r5]! + subne r1, r1, #1 + ldrneb r7, [r6, r1] + bne Lrow4bpplp + LOADREGS(fd, sp!, {r4 - r7, pc}) @ @ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc) @ -Lrow8bpplp: mov ip, r7, lsr #4 - ldr ip, [lr, ip, lsl #2] - mul r4, r2, ip - and ip, r7, #15 @ avoid r4 - ldr ip, [lr, ip, lsl #2] @ avoid r4 - mul ip, r2, ip @ avoid r4 - eor r4, r3, r4 @ avoid ip - tst r1, #7 @ avoid ip - sub r0, r0, r5 @ avoid ip - eor ip, r3, ip - stmia r0, {r4, ip} - LOADREGS(eqfd, sp!, {r4 - r7, pc}) - sub r1, r1, #1 - ldrb r7, [r6, r1] - mov ip, r7, lsr #4 - ldr ip, [lr, ip, lsl #2] - mul r4, r2, ip - and ip, r7, #15 @ avoid r4 - ldr ip, [lr, ip, lsl #2] @ avoid r4 - mul ip, r2, ip @ avoid r4 - eor r4, r3, r4 @ avoid ip - tst r1, #7 @ avoid ip - sub r0, r0, r5 @ avoid ip - eor ip, r3, ip - stmia r0, {r4, ip} - subne r1, r1, #1 - ldrneb r7, [r6, r1] - bne Lrow8bpplp - LOADREGS(fd, sp!, {r4 - r7, pc}) +Lrow8bpplp: + mov ip, r7, lsr #4 + ldr ip, [lr, ip, lsl #2] + mul r4, r2, ip + and ip, r7, #15 @ avoid r4 + ldr ip, [lr, ip, lsl #2] @ avoid r4 + mul ip, r2, ip @ avoid r4 + sub r1, r1, #1 @ avoid ip + sub r0, r0, r5 @ avoid ip + stmia r0, {r4, ip} + ldrb r7, [r6, r1] + mov ip, r7, lsr #4 + ldr ip, [lr, ip, lsl #2] + mul r4, r2, ip + and ip, r7, #15 @ avoid r4 + ldr ip, [lr, ip, lsl #2] @ avoid r4 + mul ip, r2, ip @ avoid r4 + tst r1, #7 @ avoid ip + sub r0, r0, r5 @ avoid ip + stmia r0, {r4, ip} + subne r1, r1, #1 + ldrneb r7, [r6, r1] + bne Lrow8bpplp + LOADREGS(fd, sp!, {r4 - r7, pc}) @ @ Smashable regs: {r0 - r3}, [r4], {r5, r6}, [r7], (r8 - fp), [ip], (sp), [lr], (pc) @ -Lrow1bpp: add r6, r6, r1 - ldmia r6, {r4, r7} - tst ip, #INVERSE << 9 - mvnne r4, r4 - mvnne r7, r7 - strb r4, [r0], r5 - mov r4, r4, lsr #8 - strb r4, [r0], r5 - mov r4, r4, lsr #8 - strb r4, [r0], r5 - mov r4, r4, lsr #8 - strb r4, [r0], r5 - strb r7, [r0], r5 - mov r7, r7, lsr #8 - strb r7, [r0], r5 - mov r7, r7, lsr #8 - strb r7, [r0], r5 - mov r7, r7, lsr #8 - tst ip, #UNDERLINE << 9 - mvneq r7, r7 - strb r7, [r0], r5 - LOADREGS(fd, sp!, {r4 - r7, pc}) +Lrow1bpp: + add r6, r6, r1 + ldmia r6, {r4, r7} + strb r4, [r0], r5 + mov r4, r4, lsr #8 + strb r4, [r0], r5 + mov r4, r4, lsr #8 + strb r4, [r0], r5 + mov r4, r4, lsr #8 + strb r4, [r0], r5 + strb r7, [r0], r5 + mov r7, r7, lsr #8 + strb r7, [r0], r5 + mov r7, r7, lsr #8 + strb r7, [r0], r5 + mov r7, r7, lsr #8 + strb r7, [r0], r5 + LOADREGS(fd, sp!, {r4 - r7, pc}) - .bss + .bss ENTRY(con_charconvtable) - .space 1024 + .space 1024 diff --git a/arch/arm/config.in b/arch/arm/config.in index 635874b18bfc..9e6605c5a4e4 100644 --- a/arch/arm/config.in +++ b/arch/arm/config.in @@ -94,6 +94,8 @@ if [ "$CONFIG_ASSABET_NEPONSET" = "y" -o \ "$CONFIG_SA1100_XP860" = "y" ]; then define_bool CONFIG_SA1111 y define_int CONFIG_FORCE_MAX_ZONEORDER 9 +else + define_bool CONFIG_SA1111 n fi comment 'Processor Type' @@ -231,6 +233,8 @@ if [ "$CONFIG_CPU_ARM720T" = "y" -o "$CONFIG_CPU_ARM920T" = "y" -o \ "$CONFIG_CPU_ARM922T" = "y" -o "$CONFIG_CPU_ARM926T" = "y" -o \ "$CONFIG_CPU_ARM1020" = "y" -o "$CONFIG_CPU_XSCALE" = "y" ]; then dep_bool 'Support Thumb instructions (EXPERIMENTAL)' CONFIG_ARM_THUMB $CONFIG_EXPERIMENTAL +else + define_bool CONFIG_ARM_THUMB n fi if [ "$CONFIG_CPU_ARM920T" = "y" -o "$CONFIG_CPU_ARM922T" = "y" -o \ "$CONFIG_CPU_ARM926T" = "y" -o "$CONFIG_CPU_ARM1020" = "y" ]; then diff --git a/arch/arm/kernel/arch.c b/arch/arm/kernel/arch.c index e1e97a8b7bce..ba96bea03746 100644 --- a/arch/arm/kernel/arch.c +++ b/arch/arm/kernel/arch.c @@ -8,6 +8,7 @@ #include <linux/types.h> #include <asm/elf.h> +#include <asm/page.h> #include <asm/setup.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index 201f14368eb2..8b359fa51a47 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -599,7 +599,7 @@ void pcibios_align_resource(void *data, struct resource *res, * pcibios_enable_device - Enable I/O and memory. * @dev: PCI device to be enabled */ -int pcibios_enable_device(struct pci_dev *dev) +int pcibios_enable_device(struct pci_dev *dev, int mask) { u16 cmd, old_cmd; int idx; @@ -608,6 +608,10 @@ int pcibios_enable_device(struct pci_dev *dev) pci_read_config_word(dev, PCI_COMMAND, &cmd); old_cmd = cmd; for (idx = 0; idx < 6; idx++) { + /* Only set up the requested stuff */ + if (!(mask & (1 << idx))) + continue; + r = dev->resource + idx; if (!r->start && r->end) { printk(KERN_ERR "PCI: Device %s not available because" @@ -626,3 +630,29 @@ int pcibios_enable_device(struct pci_dev *dev) } return 0; } + +int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, int write_combine) +{ + struct pci_sys_data *root = dev->sysdata; + unsigned long prot, phys; + + if (mmap_state == pci_mmap_io) { + return -EINVAL; + } else { + phys = root->mem_offset + (vma->vm_pgoff << PAGE_SHIFT); + } + + /* + * Mark this as IO + */ + vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + if (remap_page_range(vma, vma->vm_start, phys, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index 4a4d89003ecc..4cb68c31b86e 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c @@ -38,6 +38,7 @@ #include <linux/slab.h> #include <linux/proc_fs.h> #include <linux/notifier.h> +#include <linux/device.h> #include <linux/init.h> #include <asm/dma.h> @@ -48,6 +49,7 @@ #include <asm/pgalloc.h> #include <asm/mmu_context.h> #include <asm/mach/irq.h> +#include <asm/tlbflush.h> #ifndef CONFIG_ARCH_RPC #define HAVE_EXPMASK @@ -92,6 +94,8 @@ ecard_loader_reset(volatile unsigned char *pa, loader_t loader); asmlinkage extern int ecard_loader_read(int off, volatile unsigned char *pa, loader_t loader); +static const struct ecard_id * +ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec); static inline unsigned short ecard_getu16(unsigned char *v) @@ -969,6 +973,14 @@ ecard_probe(int slot, card_type_t type) *ecp = ec; slot_to_expcard[slot] = ec; + + snprintf(ec->dev.bus_id, sizeof(ec->dev.bus_id), "ecard%d", slot); + strcpy(ec->dev.name, "fixme!"); + ec->dev.parent = NULL; + ec->dev.bus = &ecard_bus_type; + + device_register(&ec->dev); + return 0; nodev: @@ -995,22 +1007,17 @@ ecard_t *ecard_find(int cid, const card_ids *cids) if (finding_pos->claimed) continue; + if (finding_pos->dev.driver) + continue; + if (!cids) { if ((finding_pos->cid.id ^ cid) == 0) break; } else { - unsigned int manufacturer, product; - int i; - - manufacturer = finding_pos->cid.manufacturer; - product = finding_pos->cid.product; - - for (i = 0; cids[i].manufacturer != 65535; i++) - if (manufacturer == cids[i].manufacturer && - product == cids[i].product) - break; + const struct ecard_id *id; - if (cids[i].manufacturer != 65535) + id = ecard_match_device(cids, finding_pos); + if (id) break; } } @@ -1023,7 +1030,7 @@ ecard_t *ecard_find(int cid, const card_ids *cids) * Locate all hardware - interrupt management and * actual cards. */ -void __init ecard_init(void) +static int __init ecard_init(void) { int slot, irqhw; @@ -1053,11 +1060,96 @@ void __init ecard_init(void) irqhw ? ecard_irqexp_handler : ecard_irq_handler); ecard_proc_init(); + + return 0; } subsys_initcall(ecard_init); +/* + * ECARD "bus" + */ +static const struct ecard_id * +ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec) +{ + int i; + + for (i = 0; ids[i].manufacturer != 65535; i++) + if (ec->cid.manufacturer == ids[i].manufacturer && + ec->cid.product == ids[i].product) + return ids + i; + + return NULL; +} + +static int ecard_drv_probe(struct device *dev) +{ + struct expansion_card *ec = ECARD_DEV(dev); + struct ecard_driver *drv = ECARD_DRV(dev->driver); + const struct ecard_id *id; + + id = ecard_match_device(drv->id_table, ec); + + return drv->probe(ec, id); +} + +static int ecard_drv_remove(struct device *dev) +{ + struct expansion_card *ec = ECARD_DEV(dev); + struct ecard_driver *drv = ECARD_DRV(dev->driver); + + drv->remove(ec); + + return 0; +} + +int ecard_register_driver(struct ecard_driver *drv) +{ + drv->drv.bus = &ecard_bus_type; + drv->drv.probe = ecard_drv_probe; + drv->drv.remove = ecard_drv_remove; + + return driver_register(&drv->drv); +} + +void ecard_remove_driver(struct ecard_driver *drv) +{ + remove_driver(&drv->drv); +} + +static int ecard_match(struct device *_dev, struct device_driver *_drv) +{ + struct expansion_card *ec = ECARD_DEV(_dev); + struct ecard_driver *drv = ECARD_DRV(_drv); + int ret; + + if (drv->id_table) { + ret = ecard_match_device(drv->id_table, ec) != NULL; + } else { + ret = ec->cid.id == drv->id; + } + + return ret; +} + +struct bus_type ecard_bus_type = { + .name = "ecard", + .match = ecard_match, +}; + +static int ecard_bus_init(void) +{ + return bus_register(&ecard_bus_type); +} + +postcore_initcall(ecard_bus_init); + EXPORT_SYMBOL(ecard_startfind); EXPORT_SYMBOL(ecard_find); EXPORT_SYMBOL(ecard_readchunk); EXPORT_SYMBOL(ecard_address); + +EXPORT_SYMBOL(ecard_register_driver); +EXPORT_SYMBOL(ecard_remove_driver); + +EXPORT_SYMBOL(ecard_bus_type); diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index e1c42aa3ec1e..3bafe5bb1c97 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -189,11 +189,10 @@ irq_prio_ld: .byte 40,40,41,40,42,42,42,42,43,43,43,43,43,43,43,43 .macro get_irqnr_and_base, irqnr, irqstat, base, tmp mov r4, #0xe0000000 - orr r4, r4, #0x20 mov \irqstat, #0x0C - strb \irqstat, [r4] @outb(0x0C, 0x20) /* Poll command */ - ldrb \irqnr, [r4] @irq = inb(0x20) & 7 + strb \irqstat, [r4, #0x20] @outb(0x0C, 0x20) /* Poll command */ + ldrb \irqnr, [r4, #0x10] @irq = inb(0x20) & 7 and \irqstat, \irqnr, #0x80 teq \irqstat, #0 beq 43f @@ -201,8 +200,8 @@ irq_prio_ld: .byte 40,40,41,40,42,42,42,42,43,43,43,43,43,43,43,43 teq \irqnr, #2 bne 44f 43: mov \irqstat, #0x0C - strb \irqstat, [r4, #0x80] @outb(0x0C, 0xA0) /* Poll command */ - ldrb \irqnr, [r4, #0x80] @irq = (inb(0xA0) & 7) + 8 + strb \irqstat, [r4, #0xa0] @outb(0x0C, 0xA0) /* Poll command */ + ldrb \irqnr, [r4, #0xa0] @irq = (inb(0xA0) & 7) + 8 and \irqstat, \irqnr, #0x80 teq \irqstat, #0 beq 44f @@ -655,7 +654,7 @@ __und_invalid: sub sp, sp, #S_FRAME_SIZE and r2, r6, #31 @ int mode b bad_mode -#if defined CONFIG_FPE_NWFPE || defined CONFIG_FPE_FASTFPE +#if 1 /* defined CONFIG_FPE_NWFPE || defined CONFIG_FPE_FASTFPE */ /* The FPE is always present */ .equ fpe_not_present, fpundefinstr #else @@ -766,6 +765,8 @@ preempt_return: msr spsr, r0 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr + .ltorg + #ifdef CONFIG_PREEMPT svc_preempt: teq r9, #0 @ was preempt count = 0 ldreq r6, .LCirq_stat @@ -902,6 +903,8 @@ __irq_usr: sub sp, sp, #S_FRAME_SIZE mov why, #0 b ret_to_user + .ltorg + .align 5 __und_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go stmia sp, {r0 - r12} @ Save r0 - r12 diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index eff2a147014b..cff2f0508439 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -367,8 +367,8 @@ void dump_thread(struct pt_regs * regs, struct user * dump) dump->u_debugreg[0] = tsk->thread.debug.bp[0].address; dump->u_debugreg[1] = tsk->thread.debug.bp[1].address; - dump->u_debugreg[2] = tsk->thread.debug.bp[0].insn; - dump->u_debugreg[3] = tsk->thread.debug.bp[1].insn; + dump->u_debugreg[2] = tsk->thread.debug.bp[0].insn.arm; + dump->u_debugreg[3] = tsk->thread.debug.bp[1].insn.arm; dump->u_debugreg[4] = tsk->thread.debug.nsaved; if (dump->start_stack < 0x04000000) diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 65a96d722b29..8e4b131eff89 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -32,10 +32,24 @@ * in exit.c or in signal.c. */ +#if 1 /* * Breakpoint SWI instruction: SWI &9F0001 */ #define BREAKINST_ARM 0xef9f0001 +#define BREAKINST_THUMB 0xdf00 /* fill this in later */ +#else +/* + * New breakpoints - use an undefined instruction. The ARM architecture + * reference manual guarantees that the following instruction space + * will produce an undefined instruction exception on all CPUs: + * + * ARM: xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx + * Thumb: 1101 1110 xxxx xxxx + */ +#define BREAKINST_ARM 0xe7f001f0 +#define BREAKINST_THUMB 0xde01 +#endif /* * Get the address of the live pt_regs for the specified task. @@ -89,23 +103,32 @@ put_user_reg(struct task_struct *task, int offset, long data) } static inline int -read_tsk_long(struct task_struct *child, unsigned long addr, unsigned long *res) +read_u32(struct task_struct *task, unsigned long addr, u32 *res) { - int copied; + int ret; - copied = access_process_vm(child, addr, res, sizeof(*res), 0); + ret = access_process_vm(task, addr, res, sizeof(*res), 0); - return copied != sizeof(*res) ? -EIO : 0; + return ret == sizeof(*res) ? 0 : -EIO; } static inline int -write_tsk_long(struct task_struct *child, unsigned long addr, unsigned long val) +read_instr(struct task_struct *task, unsigned long addr, u32 *res) { - int copied; - - copied = access_process_vm(child, addr, &val, sizeof(val), 1); + int ret; - return copied != sizeof(val) ? -EIO : 0; + if (addr & 1) { + u16 val; + ret = access_process_vm(task, addr & ~1, &val, sizeof(val), 0); + ret = ret == sizeof(val) ? 0 : -EIO; + *res = val; + } else { + u32 val; + ret = access_process_vm(task, addr & ~3, &val, sizeof(val), 0); + ret = ret == sizeof(val) ? 0 : -EIO; + *res = val; + } + return ret; } /* @@ -206,7 +229,7 @@ ptrace_getldrop2(struct task_struct *child, unsigned long insn) static unsigned long get_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn) { - unsigned long alt = 0; + u32 alt = 0; switch (insn & 0x0e000000) { case 0x00000000: @@ -262,7 +285,7 @@ get_branch_address(struct task_struct *child, unsigned long pc, unsigned long in else base -= aluop2; } - if (read_tsk_long(child, base, &alt) == 0) + if (read_u32(child, base, &alt) == 0) alt = pc_pointer(alt); } break; @@ -289,7 +312,7 @@ get_branch_address(struct task_struct *child, unsigned long pc, unsigned long in base = ptrace_getrn(child, insn); - if (read_tsk_long(child, base + nr_regs, &alt) == 0) + if (read_u32(child, base + nr_regs, &alt) == 0) alt = pc_pointer(alt); break; } @@ -319,30 +342,71 @@ get_branch_address(struct task_struct *child, unsigned long pc, unsigned long in } static int -add_breakpoint(struct task_struct *child, struct debug_info *dbg, unsigned long addr) +swap_insn(struct task_struct *task, unsigned long addr, + void *old_insn, void *new_insn, int size) +{ + int ret; + + ret = access_process_vm(task, addr, old_insn, size, 0); + if (ret == size) + ret = access_process_vm(task, addr, new_insn, size, 1); + return ret; +} + +static void +add_breakpoint(struct task_struct *task, struct debug_info *dbg, unsigned long addr) { int nr = dbg->nsaved; - int res = -EINVAL; if (nr < 2) { - res = read_tsk_long(child, addr, &dbg->bp[nr].insn); - if (res == 0) - res = write_tsk_long(child, addr, BREAKINST_ARM); + u32 new_insn = BREAKINST_ARM; + int res; - if (res == 0) { + res = swap_insn(task, addr, &dbg->bp[nr].insn, &new_insn, 4); + + if (res == 4) { dbg->bp[nr].address = addr; dbg->nsaved += 1; } } else printk(KERN_ERR "ptrace: too many breakpoints\n"); +} + +/* + * Clear one breakpoint in the user program. We copy what the hardware + * does and use bit 0 of the address to indicate whether this is a Thumb + * breakpoint or an ARM breakpoint. + */ +static void clear_breakpoint(struct task_struct *task, struct debug_entry *bp) +{ + unsigned long addr = bp->address; + union debug_insn old_insn; + int ret; + + if (addr & 1) { + ret = swap_insn(task, addr & ~1, &old_insn.thumb, + &bp->insn.thumb, 2); - return res; + if (ret != 2 || old_insn.thumb != BREAKINST_THUMB) + printk(KERN_ERR "%s:%d: corrupted Thumb breakpoint at " + "0x%08lx (0x%04x)\n", task->comm, task->pid, + addr, old_insn.thumb); + } else { + ret = swap_insn(task, addr & ~3, &old_insn.arm, + &bp->insn.arm, 4); + + if (ret != 4 || old_insn.arm != BREAKINST_ARM) + printk(KERN_ERR "%s:%d: corrupted ARM breakpoint at " + "0x%08lx (0x%08x)\n", task->comm, task->pid, + addr, old_insn.arm); + } } void ptrace_set_bpt(struct task_struct *child) { struct pt_regs *regs; - unsigned long pc, insn; + unsigned long pc; + u32 insn; int res; regs = get_user_regs(child); @@ -353,7 +417,7 @@ void ptrace_set_bpt(struct task_struct *child) return; } - res = read_tsk_long(child, pc, &insn); + res = read_instr(child, pc, &insn); if (!res) { struct debug_info *dbg = &child->thread.debug; unsigned long alt; @@ -362,7 +426,7 @@ void ptrace_set_bpt(struct task_struct *child) alt = get_branch_address(child, pc, insn); if (alt) - res = add_breakpoint(child, dbg, alt); + add_breakpoint(child, dbg, alt); /* * Note that we ignore the result of setting the above @@ -374,7 +438,7 @@ void ptrace_set_bpt(struct task_struct *child) * loose control of the thread during single stepping. */ if (!alt || predicate(insn) != PREDICATE_ALWAYS) - res = add_breakpoint(child, dbg, pc + 4); + add_breakpoint(child, dbg, pc + 4); } } @@ -384,24 +448,17 @@ void ptrace_set_bpt(struct task_struct *child) */ void __ptrace_cancel_bpt(struct task_struct *child) { - struct debug_info *dbg = &child->thread.debug; - int i, nsaved = dbg->nsaved; + int i, nsaved = child->thread.debug.nsaved; - dbg->nsaved = 0; + child->thread.debug.nsaved = 0; if (nsaved > 2) { printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); nsaved = 2; } - for (i = 0; i < nsaved; i++) { - unsigned long tmp; - - read_tsk_long(child, dbg->bp[i].address, &tmp); - write_tsk_long(child, dbg->bp[i].address, dbg->bp[i].insn); - if (tmp != BREAKINST_ARM) - printk(KERN_ERR "ptrace_cancel_bpt: weirdness\n"); - } + for (i = 0; i < nsaved; i++) + clear_breakpoint(child, &child->thread.debug.bp[i]); } /* @@ -537,9 +594,12 @@ static int do_ptrace(int request, struct task_struct *child, long addr, long dat */ case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: - ret = read_tsk_long(child, addr, &tmp); - if (!ret) + ret = access_process_vm(child, addr, &tmp, + sizeof(unsigned long), 0); + if (ret == sizeof(unsigned long)) ret = put_user(tmp, (unsigned long *) data); + else + ret = -EIO; break; case PTRACE_PEEKUSR: @@ -551,7 +611,12 @@ static int do_ptrace(int request, struct task_struct *child, long addr, long dat */ case PTRACE_POKETEXT: case PTRACE_POKEDATA: - ret = write_tsk_long(child, addr, data); + ret = access_process_vm(child, addr, &data, + sizeof(unsigned long), 1); + if (ret == sizeof(unsigned long)) + ret = 0; + else + ret = -EIO; break; case PTRACE_POKEUSR: diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index cf6c528b3947..51463c237002 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -193,26 +193,25 @@ static inline void dump_cache(const char *prefix, unsigned int cache) CACHE_LINE(cache))); } -static inline void dump_cpu_cache_id(void) +static void __init dump_cpu_info(void) { - unsigned int cache_info; + unsigned int info; - asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (cache_info)); + asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (info)); - if (cache_info == processor_id) - return; - - printk("CPU: D %s cache\n", cache_types[CACHE_TYPE(cache_info)]); - if (CACHE_S(cache_info)) { - dump_cache("CPU: I cache", CACHE_ISIZE(cache_info)); - dump_cache("CPU: D cache", CACHE_DSIZE(cache_info)); - } else { - dump_cache("CPU: cache", CACHE_ISIZE(cache_info)); + if (info != processor_id) { + printk("CPU: D %s cache\n", cache_types[CACHE_TYPE(info)]); + if (CACHE_S(info)) { + dump_cache("CPU: I cache", CACHE_ISIZE(info)); + dump_cache("CPU: D cache", CACHE_DSIZE(info)); + } else { + dump_cache("CPU: cache", CACHE_ISIZE(info)); + } } } #else -#define dump_cpu_cache_id() do { } while (0) +#define dump_cpu_info() do { } while (0) #endif static void __init setup_processor(void) @@ -255,7 +254,7 @@ static void __init setup_processor(void) proc_info.manufacturer, proc_info.cpu_name, (int)processor_id & 15); - dump_cpu_cache_id(); + dump_cpu_info(); sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS); sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 6f6701c99712..93dc50e3ccc6 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -59,11 +59,11 @@ asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t m sigset_t saveset; mask &= _BLOCKABLE; - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sig->siglock); saveset = current->blocked; siginitset(¤t->blocked, mask); recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sig->siglock); regs->ARM_r0 = -EINTR; while (1) { @@ -87,11 +87,11 @@ sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs *regs) return -EFAULT; sigdelsetmask(&newset, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sig->siglock); saveset = current->blocked; current->blocked = newset; recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sig->siglock); regs->ARM_r0 = -EINTR; while (1) { @@ -207,10 +207,10 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sig->siglock); current->blocked = set; recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sig->siglock); if (restore_sigcontext(regs, &frame->sc)) goto badframe; @@ -247,10 +247,10 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sig->siglock); current->blocked = set; recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sig->siglock); if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; @@ -477,12 +477,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, ka->sa.sa_handler = SIG_DFL; if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(&tsk->sigmask_lock); + spin_lock_irq(&tsk->sig->siglock); sigorsets(&tsk->blocked, &tsk->blocked, &ka->sa.sa_mask); sigaddset(&tsk->blocked, sig); recalc_sigpending(); - spin_unlock_irq(&tsk->sigmask_lock); + spin_unlock_irq(&tsk->sig->siglock); } return; } @@ -520,20 +520,10 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) for (;;) { unsigned long signr = 0; struct k_sigaction *ka; - sigset_t *mask = ¤t->blocked; - local_irq_disable(); - if (current->sig->shared_pending.head) { - spin_lock(¤t->sig->siglock); - signr = dequeue_signal(¤t->sig->shared_pending, mask, &info); - spin_unlock(¤t->sig->siglock); - } - if (!signr) { - spin_lock(¤t->sigmask_lock); - signr = dequeue_signal(¤t->pending, mask, &info); - spin_unlock(¤t->sigmask_lock); - } - local_irq_enable(); + spin_lock_irq(¤t->sig->siglock); + signr = dequeue_signal(¤t->blocked, &info); + spin_unlock_irq(¤t->sig->siglock); if (!signr) break; diff --git a/arch/arm/kernel/time-acorn.c b/arch/arm/kernel/time-acorn.c index 91f9e1a134c2..eb637801c7a5 100644 --- a/arch/arm/kernel/time-acorn.c +++ b/arch/arm/kernel/time-acorn.c @@ -25,44 +25,37 @@ extern unsigned long (*gettimeoffset)(void); static unsigned long ioctime_gettimeoffset(void) { - unsigned int count1, count2, status1, status2; - unsigned long offset = 0; + unsigned int count1, count2, status; + long offset; - status1 = ioc_readb(IOC_IRQREQA); - barrier (); ioc_writeb (0, IOC_T0LATCH); barrier (); count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); barrier (); - status2 = ioc_readb(IOC_IRQREQA); + status = ioc_readb(IOC_IRQREQA); barrier (); ioc_writeb (0, IOC_T0LATCH); barrier (); count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); + offset = count2; if (count2 < count1) { /* - * This means that we haven't just had an interrupt - * while reading into status2. + * We have not had an interrupt between reading count1 + * and count2. */ - if (status2 & (1 << 5)) - offset = tick; - count1 = count2; + if (status & (1 << 5)) + offset -= LATCH; } else if (count2 > count1) { /* - * We have just had another interrupt while reading - * status2. + * We have just had another interrupt between reading + * count1 and count2. */ - offset += tick; - count1 = count2; + offset -= LATCH; } - count1 = LATCH - count1; - /* - * count1 = number of clock ticks since last interrupt - */ - offset += count1 * tick / LATCH; - return offset; + offset = (LATCH - offset) * (tick_nsec / 1000); + return (offset + LATCH/2) / LATCH; } void __init ioctime_init(void) diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index 3d79e5c47367..07df8125c4cb 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -115,8 +115,8 @@ static inline void do_set_rtc(void) time_before(xtime.tv_sec, next_rtc_update)) return; - if (xtime.tv_usec < 50000 - (tick >> 1) && - xtime.tv_usec >= 50000 + (tick >> 1)) + if (xtime.tv_nsec < 500000000 - ((unsigned) tick_nsec >> 1) && + xtime.tv_nsec >= 500000000 + ((unsigned) tick_nsec >> 1)) return; if (set_rtc()) @@ -166,7 +166,7 @@ void do_gettimeofday(struct timeval *tv) usec += lost * USECS_PER_JIFFY; sec = xtime.tv_sec; - usec += xtime.tv_usec; + usec += xtime.tv_nsec / 1000; read_unlock_irqrestore(&xtime_lock, flags); /* usec may have gone up a lot: be safe */ @@ -196,7 +196,8 @@ void do_settimeofday(struct timeval *tv) tv->tv_sec--; } - xtime = *tv; + xtime.tv_sec = tv->tv_sec; + xtime.tv_nsec = tv->tv_usec * 1000; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index f0f7daf2d7d6..86a60a6e5022 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -32,6 +32,7 @@ #include <asm/system.h> #include <asm/uaccess.h> #include <asm/unistd.h> +#include <asm/semaphore.h> #include "ptrace.h" @@ -77,8 +78,7 @@ static void dump_mem(const char *str, unsigned long bottom, unsigned long top) fs = get_fs(); set_fs(KERNEL_DS); - printk("%s", str); - printk("(0x%08lx to 0x%08lx)\n", bottom, top); + printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top); for (p = bottom & ~31; p < top;) { printk("%04lx: ", p & 0xffff); @@ -136,7 +136,7 @@ static void dump_instr(struct pt_regs *regs) set_fs(fs); } -static void dump_stack(struct task_struct *tsk, unsigned long sp) +static void __dump_stack(struct task_struct *tsk, unsigned long sp) { dump_mem("Stack: ", sp, 8192+(unsigned long)tsk->thread_info); } @@ -163,15 +163,20 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) } /* - * This is called from SysRq-T (show_task) to display the current - * call trace for each process. Very useful. + * This is called from SysRq-T (show_task) to display the current call + * trace for each process. This version will also display the running + * threads call trace (ie, us.) */ void show_trace_task(struct task_struct *tsk) { - if (tsk != current) { - unsigned int fp = thread_saved_fp(tsk); - c_backtrace(fp, 0x10); - } + unsigned int fp; + + if (tsk != current) + fp = thread_saved_fp(tsk); + else + asm("mov%? %0, fp" : "=r" (fp)); + + c_backtrace(fp, 0x10); } spinlock_t die_lock = SPIN_LOCK_UNLOCKED; @@ -193,7 +198,7 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err) current->comm, current->pid, tsk->thread_info + 1); if (!user_mode(regs) || in_interrupt()) { - dump_stack(tsk, (unsigned long)(regs + 1)); + __dump_stack(tsk, (unsigned long)(regs + 1)); dump_backtrace(regs, tsk); dump_instr(regs); } diff --git a/arch/arm/mach-integrator/cpu.c b/arch/arm/mach-integrator/cpu.c index 17acb2bc21da..773955c92d14 100644 --- a/arch/arm/mach-integrator/cpu.c +++ b/arch/arm/mach-integrator/cpu.c @@ -73,36 +73,37 @@ static struct vco freq_to_vco(unsigned int freq_khz, int factor) * Validate the speed in khz. If it is outside our * range, then return the lowest. */ -static unsigned int -integrator_validatespeed(unsigned int cpu, unsigned int freq_khz) +static void integrator_verify_speed(struct cpufreq_policy *policy) { struct vco vco; - if (freq_khz < 12000) - freq_khz = 12000; - if (freq_khz > 160000) - freq_khz = 160000; + if (policy->max > policy->max_cpu_freq) + policy->max = policy->max_cpu_freq; - vco = freq_to_vco(freq_khz, 1); + if (policy->max < 12000) + policy->max = 12000; + if (policy->max > 160000) + policy->max = 160000; - if (vco.vdw < 4 || vco.vdw > 152) - return -EINVAL; + vco = freq_to_vco(policy->max, 1); - return vco_to_freq(vco, 1); + if (vco.vdw < 4) + vco.vdw = 4; + if (vco.vdw > 152) + vco.vdw = 152; + + policy->min = policy->max = vco_to_freq(vco, 1); } -static void integrator_setspeed(unsigned int cpu, unsigned int freq_khz) +static void do_set_policy(int cpu, struct cpufreq_policy *policy) { - struct vco vco = freq_to_vco(freq_khz, 1); - unsigned long cpus_allowed; + struct vco vco = freq_to_vco(policy->max, 1); u_int cm_osc; /* - * Save this threads cpus_allowed mask, and bind to the - * specified CPU. When this call returns, we should be - * running on the right CPU. + * Bind to the specified CPU. When this call returns, + * we should be running on the right CPU. */ - cpus_allowed = current->cpus_allowed; set_cpus_allowed(current, 1 << cpu); BUG_ON(cpu != smp_processor_id()); @@ -113,6 +114,26 @@ static void integrator_setspeed(unsigned int cpu, unsigned int freq_khz) __raw_writel(0xa05f, CM_LOCK); __raw_writel(cm_osc, CM_OSC); __raw_writel(0, CM_LOCK); +} + +static void integrator_set_policy(struct cpufreq_policy *policy) +{ + unsigned long cpus_allowed; + int cpu; + + /* + * Save this threads cpus_allowed mask. + */ + cpus_allowed = current->cpus_allowed; + + if (policy->cpu == CPUFREQ_ALL_CPUS) { + for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (!cpu_online(cpu)) + continue; + do_set_policy(cpu, policy); + } + } else + do_set_policy(policy->cpu, policy); /* * Restore the CPUs allowed mask. @@ -120,23 +141,30 @@ static void integrator_setspeed(unsigned int cpu, unsigned int freq_khz) set_cpus_allowed(current, cpus_allowed); } +static struct cpufreq_policy integrator_policy = { + .cpu = 0, + .policy = CPUFREQ_POLICY_POWERSAVE, + .max_cpu_freq = 160000, +}; + static struct cpufreq_driver integrator_driver = { - .validate = integrator_validatespeed, - .setspeed = integrator_setspeed, - .sync = 1, + .verify = integrator_verify_speed, + .setpolicy = integrator_set_policy, + .policy = &integrator_policy, + .cpu_min_freq = 12000, }; #endif static int __init integrator_cpu_init(void) { - struct cpufreq_freqs *freqs; + struct cpufreq_policy *policies; unsigned long cpus_allowed; int cpu; - freqs = kmalloc(sizeof(struct cpufreq_freqs) * NR_CPUS, - GFP_KERNEL); - if (!freqs) { - printk(KERN_ERR "CPU: unable to allocate cpufreqs structure\n"); + policies = kmalloc(sizeof(struct cpufreq_freqs) * NR_CPUS, + GFP_KERNEL); + if (!policies) { + printk(KERN_ERR "CPU: unable to allocate policies structure\n"); return -ENOMEM; } @@ -164,18 +192,20 @@ static int __init integrator_cpu_init(void) vco.od = (cm_osc >> 8) & 7; vco.vdw = cm_osc & 255; - freqs[cpu].min = 12000; - freqs[cpu].max = 160000; - freqs[cpu].cur = vco_to_freq(vco, 1); + policies[cpu].cpu = cpu; + policies[cpu].policy = CPUFREQ_POLICY_POWERSAVE, + policies[cpu].max_cpu_freq = 160000; + policies[cpu].min = + policies[cpu].max = vco_to_freq(vco, 1); } set_cpus_allowed(current, cpus_allowed); #ifdef CONFIG_CPU_FREQ - integrator_driver.freq = freqs; + integrator_driver.policy = policies; cpufreq_register(&integrator_driver); #else - kfree(freqs); + kfree(policies); #endif return 0; diff --git a/arch/arm/mach-iop310/iop310-pci.c b/arch/arm/mach-iop310/iop310-pci.c index c7fddcdf9107..50faa6fecfcd 100644 --- a/arch/arm/mach-iop310/iop310-pci.c +++ b/arch/arm/mach-iop310/iop310-pci.c @@ -145,7 +145,7 @@ iop310_pri_read_config(struct pci_bus *bus, unsigned int devfn, int where, } static int -iop310_pri_write_config(struct pci_bus *bus, unsigned int devfn, int where +iop310_pri_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { unsigned long addr = iop310_cfg_address(bus, devfn, where); @@ -163,7 +163,7 @@ iop310_pri_write_config(struct pci_bus *bus, unsigned int devfn, int where else val &= ~(0xffff << where); - *IOP310_POCCDR = val | v << where; + *IOP310_POCCDR = val | value << where; } else { asm volatile( "str %1, [%2]\n\t" @@ -173,7 +173,7 @@ iop310_pri_write_config(struct pci_bus *bus, unsigned int devfn, int where "nop\n\t" "nop\n\t" : - : "r" (val), "r" (addr), + : "r" (value), "r" (addr), "r" (IOP310_POCCAR), "r" (IOP310_POCCDR)); } @@ -246,7 +246,7 @@ iop310_sec_read_config(struct pci_bus *bus, unsigned int devfn, int where, } static int -iop310_sec_write_config(struct pci_bus *bus, unsigned int devfn, int where +iop310_sec_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { unsigned long addr = iop310_cfg_address(bus, devfn, where); @@ -265,7 +265,7 @@ iop310_sec_write_config(struct pci_bus *bus, unsigned int devfn, int where else val &= ~(0xffff << where); - *IOP310_SOCCDR = val | v << where; + *IOP310_SOCCDR = val | value << where; } else { asm volatile( "str %1, [%2]\n\t" @@ -275,7 +275,7 @@ iop310_sec_write_config(struct pci_bus *bus, unsigned int devfn, int where "nop\n\t" "nop\n\t" : - : "r" (val), "r" (addr), + : "r" (value), "r" (addr), "r" (IOP310_SOCCAR), "r" (IOP310_SOCCDR)); } diff --git a/arch/arm/mach-iop310/iq80310-time.c b/arch/arm/mach-iop310/iq80310-time.c index a986a2346836..1151c6b3db28 100644 --- a/arch/arm/mach-iop310/iq80310-time.c +++ b/arch/arm/mach-iop310/iq80310-time.c @@ -85,7 +85,7 @@ static unsigned long iq80310_gettimeoffset (void) /* * Now convert them to usec. */ - usec = (unsigned long)(elapsed*tick)/LATCH; + usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH; return usec; } diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile index d5b92e4637ad..520d8fefdcd0 100644 --- a/arch/arm/mach-sa1100/Makefile +++ b/arch/arm/mach-sa1100/Makefile @@ -2,20 +2,17 @@ # Makefile for the linux kernel. # -# Common support (must be linked before board specific support) +# Common support obj-y := generic.o irq.o dma.o obj-m := obj-n := obj- := led-y := leds.o -export-objs := dma.o generic.o pcipool.o pm.o sa1111.o sa1111-pcibuf.o \ - usb_ctl.o usb_recv.o usb_send.o +export-objs := dma.o generic.o pcipool.o pm.o sa1111.o sa1111-pcibuf.o # This needs to be cleaned up. We probably need to have SA1100 # and SA1110 config symbols. -# -# We link the CPU support next, so that RAM timings can be tuned. ifeq ($(CONFIG_CPU_FREQ),y) obj-$(CONFIG_SA1100_ASSABET) += cpu-sa1110.o obj-$(CONFIG_SA1100_CERF) += cpu-sa1110.o @@ -107,10 +104,7 @@ export-objs += yopy.o obj-$(CONFIG_LEDS) += $(led-y) # SA1110 USB client support -sa1100usb_core-objs := usb_ctl.o usb_ep0.o usb_recv.o usb_send.o -obj-$(CONFIG_SA1100_USB) += sa1100usb_core.o -obj-$(CONFIG_SA1100_USB_NETLINK) += usb-eth.o -obj-$(CONFIG_SA1100_USB_CHAR) += usb-char.o +#obj-$(CONFIG_SA1100_USB) += usb/ # Miscelaneous functions obj-$(CONFIG_PM) += pm.o sleep.o diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c index b05c727a5b6a..d538b98d4284 100644 --- a/arch/arm/mach-sa1100/assabet.c +++ b/arch/arm/mach-sa1100/assabet.c @@ -302,21 +302,24 @@ static void __init assabet_map_io(void) */ neponset_map_io(); #endif - /* - * When Neponset is attached, the first UART should be - * UART3. That's what Angel is doing and many documents - * are stating this. - * We do the Neponset mapping even if Neponset support - * isn't compiled in so the user will still get something on - * the expected physical serial port. - */ - sa1100_register_uart(0, 3); - sa1100_register_uart(2, 1); } else { sa1100_register_uart_fns(&assabet_port_fns); - sa1100_register_uart(0, 1); /* com port */ - sa1100_register_uart(2, 3); /* radio module */ } + + /* + * When Neponset is attached, the first UART should be + * UART3. That's what Angel is doing and many documents + * are stating this. + * + * We do the Neponset mapping even if Neponset support + * isn't compiled in so the user will still get something on + * the expected physical serial port. + * + * We no longer do this; not all boot loaders support it, + * and UART3 appears to be somewhat unreliable with blob. + */ + sa1100_register_uart(0, 1); + sa1100_register_uart(2, 3); } diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 45eae6434f68..461bec6b956b 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -55,8 +55,8 @@ unsigned int sa11x0_freq_to_ppcr(unsigned int khz) khz /= 100; - for (i = 0; i < ARRAY_SIZE(cclk_frequency_100khz); i--) - if (cclk_frequency_100khz[i] >= khz) + for (i = NR_FREQS - 1; i > 0; i--) + if (cclk_frequency_100khz[i] <= khz) break; return i; diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c index 9d3a939de4ae..71c60c3c1467 100644 --- a/arch/arm/mach-sa1100/neponset.c +++ b/arch/arm/mach-sa1100/neponset.c @@ -193,20 +193,30 @@ static int neponset_resume(struct device *dev, u32 level) } static struct device_driver neponset_device_driver = { - .suspend = neponset_suspend, - .resume = neponset_resume, + .name = "NEPONSET", + .bus = &system_bus_type, + .suspend = neponset_suspend, + .resume = neponset_resume, }; -static struct device neponset_device = { - .name = "Neponset", - .bus_id = "neponset", - .driver = &neponset_device_driver, +static struct sys_device neponset_device = { + .name = "NEPONSET", + .id = 0, + .root = NULL, + .dev = { + .name = "Neponset", + .bus_id = "neponset", + .bus = &system_bus_type, + .driver = &neponset_device_driver, + }, }; static int __init neponset_init(void) { int ret; + driver_register(&neponset_device_driver); + /* * The Neponset is only present on the Assabet machine type. */ @@ -231,7 +241,7 @@ static int __init neponset_init(void) return -ENODEV; } - ret = register_sys_device(&neponset_device); + ret = sys_device_register(&neponset_device); if (ret) return ret; @@ -256,7 +266,7 @@ static int __init neponset_init(void) return sa1111_init(0x40000000, IRQ_NEPONSET_SA1111); } -arch_initcall(neponset_init); +subsys_initcall(neponset_init); static struct map_desc neponset_io_desc[] __initdata = { /* virtual physical length type */ diff --git a/arch/arm/mach-sa1100/sa1111.c b/arch/arm/mach-sa1100/sa1111.c index 9ded8fe5f98e..54a40462b2dc 100644 --- a/arch/arm/mach-sa1100/sa1111.c +++ b/arch/arm/mach-sa1100/sa1111.c @@ -43,7 +43,7 @@ * anchor point for all the other drivers. */ struct sa1111 { - struct device dev; + struct device *dev; struct resource res; int irq; spinlock_t lock; @@ -64,7 +64,7 @@ static struct sa1111_dev usb_dev = { .devid = SA1111_DEVID_USB, .irq = { IRQ_USBPWR, - IRQ_NHCIM, + IRQ_HCIM, IRQ_HCIBUFFACC, IRQ_HCIRMTWKP, IRQ_NHCIMFCIR, @@ -148,7 +148,6 @@ static struct sa1111_dev *devs[] = { &ssp_dev, &kbd_dev, &mse_dev, - &int_dev, &pcmcia_dev, }; @@ -158,7 +157,6 @@ static unsigned int dev_offset[] = { 0x0800, SA1111_KBD, SA1111_MSE, - SA1111_INTC, 0x1800, }; @@ -372,7 +370,106 @@ static void __init sa1111_init_irq(struct sa1111_dev *sadev) set_irq_chained_handler(sadev->irq[0], sa1111_irq_handler); } -static struct device_driver sa1111_device_driver; +/* + * Bring the SA1111 out of reset. This requires a set procedure: + * 1. nRESET asserted (by hardware) + * 2. CLK turned on from SA1110 + * 3. nRESET deasserted + * 4. VCO turned on, PLL_BYPASS turned off + * 5. Wait lock time, then assert RCLKEn + * 7. PCR set to allow clocking of individual functions + * + * Until we've done this, the only registers we can access are: + * SBI_SKCR + * SBI_SMCR + * SBI_SKID + */ +static void sa1111_wake(struct sa1111 *sachip) +{ + unsigned long flags, r; + + spin_lock_irqsave(&sachip->lock, flags); + + /* + * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111: + * (SA-1110 Developer's Manual, section 9.1.2.1) + */ + GAFR |= GPIO_32_768kHz; + GPDR |= GPIO_32_768kHz; + TUCR = TUCR_3_6864MHz; + + /* + * Turn VCO on, and disable PLL Bypass. + */ + r = sa1111_readl(sachip->base + SA1111_SKCR); + r &= ~SKCR_VCO_OFF; + sa1111_writel(r, sachip->base + SA1111_SKCR); + r |= SKCR_PLL_BYPASS | SKCR_OE_EN; + sa1111_writel(r, sachip->base + SA1111_SKCR); + + /* + * Wait lock time. SA1111 manual _doesn't_ + * specify a figure for this! We choose 100us. + */ + udelay(100); + + /* + * Enable RCLK. We also ensure that RDYEN is set. + */ + r |= SKCR_RCLKEN | SKCR_RDYEN; + sa1111_writel(r, sachip->base + SA1111_SKCR); + + /* + * Wait 14 RCLK cycles for the chip to finish coming out + * of reset. (RCLK=24MHz). This is 590ns. + */ + udelay(1); + + /* + * Ensure all clocks are initially off. + */ + sa1111_writel(0, sachip->base + SA1111_SKPCR); + + spin_unlock_irqrestore(&sachip->lock, flags); +} + +/* + * Configure the SA1111 shared memory controller. + */ +void +sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac, + unsigned int cas_latency) +{ + unsigned int smcr = SMCR_DTIM | SMCR_MBGE | FInsrt(drac, SMCR_DRAC); + + if (cas_latency == 3) + smcr |= SMCR_CLAT; + + sa1111_writel(smcr, sachip->base + SA1111_SMCR); +} + +static void +sa1111_init_one_child(struct sa1111 *sachip, struct sa1111_dev *sadev, unsigned int offset) +{ + snprintf(sadev->dev.bus_id, sizeof(sadev->dev.bus_id), + "%4.4x", offset); + + sadev->dev.parent = sachip->dev; + sadev->dev.bus = &sa1111_bus_type; + sadev->res.start = sachip->res.start + offset; + sadev->res.end = sadev->res.start + 511; + sadev->res.name = sadev->dev.name; + sadev->res.flags = IORESOURCE_MEM; + sadev->mapbase = sachip->base + offset; + + if (request_resource(&sachip->res, &sadev->res)) { + printk("SA1111: failed to allocate resource for %s\n", + sadev->res.name); + return; + } + + device_register(&sadev->dev); +} /** * sa1111_probe - probe for a single SA1111 chip. @@ -387,11 +484,11 @@ static struct device_driver sa1111_device_driver; * %0 successful. */ static int __init -sa1111_probe(unsigned long phys_addr, int irq) +__sa1111_probe(struct device *me, unsigned long phys_addr, int irq) { struct sa1111 *sachip; unsigned long id; - unsigned int has_devs; + unsigned int has_devs, val; int i, ret = -ENODEV; sachip = kmalloc(sizeof(struct sa1111), GFP_KERNEL); @@ -402,12 +499,10 @@ sa1111_probe(unsigned long phys_addr, int irq) spin_lock_init(&sachip->lock); - strncpy(sachip->dev.name, "Intel Corporation SA1111", sizeof(sachip->dev.name)); - snprintf(sachip->dev.bus_id, sizeof(sachip->dev.bus_id), "%8.8lx", phys_addr); - sachip->dev.driver = &sa1111_device_driver; - sachip->dev.driver_data = sachip; + sachip->dev = me; + dev_set_drvdata(sachip->dev, sachip); - sachip->res.name = sachip->dev.name; + sachip->res.name = me->name; sachip->res.start = phys_addr; sachip->res.end = phys_addr + 0x2000; sachip->irq = irq; @@ -417,6 +512,10 @@ sa1111_probe(unsigned long phys_addr, int irq) goto out; } + /* + * Map the whole region. This also maps the + * registers for our children. + */ sachip->base = ioremap(phys_addr, PAGE_SIZE * 2); if (!sachip->base) { ret = -ENOMEM; @@ -433,17 +532,47 @@ sa1111_probe(unsigned long phys_addr, int irq) goto unmap; } - /* - * We found the chip. - */ - ret = register_sys_device(&sachip->dev); - if (ret) - printk("sa1111 device_register failed: %d\n", ret); - printk(KERN_INFO "SA1111 Microprocessor Companion Chip: " "silicon revision %lx, metal revision %lx\n", (id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK)); + /* + * We found it. Wake the chip up, and initialise. + */ + sa1111_wake(sachip); + + /* + * The SDRAM configuration of the SA1110 and the SA1111 must + * match. This is very important to ensure that SA1111 accesses + * don't corrupt the SDRAM. Note that this ungates the SA1111's + * MBGNT signal, so we must have called sa1110_mb_disable() + * beforehand. + */ + sa1111_configure_smc(sachip, 1, + FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), + FExtr(MDCNFG, MDCNFG_SA1110_TDL0)); + + /* + * We only need to turn on DCLK whenever we want to use the + * DMA. It can otherwise be held firmly in the off position. + * (currently, we always enable it.) + */ + val = sa1111_readl(sachip->base + SA1111_SKPCR); + sa1111_writel(val | SKPCR_DCLKEN, sachip->base + SA1111_SKPCR); + + /* + * Enable the SA1110 memory bus request and grant signals. + */ + sa1110_mb_enable(); + + /* + * The interrupt controller must be initialised before any + * other device to ensure that the interrupts are available. + */ + int_dev.irq[0] = irq; + sa1111_init_one_child(sachip, &int_dev, SA1111_INTC); + sa1111_init_irq(&int_dev); + g_sa1111 = sachip; has_devs = ~0; @@ -453,29 +582,9 @@ sa1111_probe(unsigned long phys_addr, int irq) else has_devs &= ~(1 << 1); - for (i = 0; i < ARRAY_SIZE(devs); i++) { - if (!(has_devs & (1 << i))) - continue; - - snprintf(devs[i]->dev.bus_id, sizeof(devs[i]->dev.bus_id), - "%4.4x", dev_offset[i]); - - devs[i]->dev.parent = &sachip->dev; - devs[i]->dev.bus = &sa1111_bus_type; - devs[i]->res.start = sachip->res.start + dev_offset[i]; - devs[i]->res.end = devs[i]->res.start + 511; - devs[i]->res.name = devs[i]->dev.name; - devs[i]->res.flags = IORESOURCE_MEM; - devs[i]->mapbase = sachip->base + dev_offset[i]; - - if (request_resource(&sachip->res, &devs[i]->res)) { - printk("SA1111: failed to allocate resource for %s\n", - devs[i]->res.name); - continue; - } - - device_register(&devs[i]->dev); - } + for (i = 0; i < ARRAY_SIZE(devs); i++) + if (has_devs & (1 << i)) + sa1111_init_one_child(sachip, devs[i], dev_offset[i]); return 0; @@ -503,84 +612,6 @@ static void __sa1111_remove(struct sa1111 *sachip) } /* - * Bring the SA1111 out of reset. This requires a set procedure: - * 1. nRESET asserted (by hardware) - * 2. CLK turned on from SA1110 - * 3. nRESET deasserted - * 4. VCO turned on, PLL_BYPASS turned off - * 5. Wait lock time, then assert RCLKEn - * 7. PCR set to allow clocking of individual functions - * - * Until we've done this, the only registers we can access are: - * SBI_SKCR - * SBI_SMCR - * SBI_SKID - */ -static void sa1111_wake(struct sa1111 *sachip) -{ - unsigned long flags, r; - - spin_lock_irqsave(&sachip->lock, flags); - - /* - * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111: - * (SA-1110 Developer's Manual, section 9.1.2.1) - */ - GAFR |= GPIO_32_768kHz; - GPDR |= GPIO_32_768kHz; - TUCR = TUCR_3_6864MHz; - - /* - * Turn VCO on, and disable PLL Bypass. - */ - r = sa1111_readl(sachip->base + SA1111_SKCR); - r &= ~SKCR_VCO_OFF; - sa1111_writel(r, sachip->base + SA1111_SKCR); - r |= SKCR_PLL_BYPASS | SKCR_OE_EN; - sa1111_writel(r, sachip->base + SA1111_SKCR); - - /* - * Wait lock time. SA1111 manual _doesn't_ - * specify a figure for this! We choose 100us. - */ - udelay(100); - - /* - * Enable RCLK. We also ensure that RDYEN is set. - */ - r |= SKCR_RCLKEN | SKCR_RDYEN; - sa1111_writel(r, sachip->base + SA1111_SKCR); - - /* - * Wait 14 RCLK cycles for the chip to finish coming out - * of reset. (RCLK=24MHz). This is 590ns. - */ - udelay(1); - - /* - * Ensure all clocks are initially off. - */ - sa1111_writel(0, sachip->base + SA1111_SKPCR); - - spin_unlock_irqrestore(&sachip->lock, flags); -} - -/* - * Configure the SA1111 shared memory controller. - */ -void -sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac, - unsigned int cas_latency) -{ - unsigned int smcr = SMCR_DTIM | SMCR_MBGE | FInsrt(drac, SMCR_DRAC); - - if (cas_latency == 3) - smcr |= SMCR_CLAT; - - sa1111_writel(smcr, sachip->base + SA1111_SMCR); -} - -/* * According to the "Intel StrongARM SA-1111 Microprocessor Companion * Chip Specification Update" (June 2000), erratum #7, there is a * significant bug in the SA1111 SDRAM shared memory controller. If @@ -648,52 +679,6 @@ int sa1111_check_dma_bug(dma_addr_t addr) return 0; } -int sa1111_init(unsigned long phys, unsigned int irq) -{ - unsigned int val; - int ret; - - ret = sa1111_probe(phys, irq); - if (ret < 0) - return ret; - - /* - * We found it. Wake the chip up. - */ - sa1111_wake(g_sa1111); - - /* - * The SDRAM configuration of the SA1110 and the SA1111 must - * match. This is very important to ensure that SA1111 accesses - * don't corrupt the SDRAM. Note that this ungates the SA1111's - * MBGNT signal, so we must have called sa1110_mb_disable() - * beforehand. - */ - sa1111_configure_smc(g_sa1111, 1, - FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), - FExtr(MDCNFG, MDCNFG_SA1110_TDL0)); - - /* - * We only need to turn on DCLK whenever we want to use the - * DMA. It can otherwise be held firmly in the off position. - */ - val = sa1111_readl(g_sa1111->base + SA1111_SKPCR); - sa1111_writel(val | SKPCR_DCLKEN, g_sa1111->base + SA1111_SKPCR); - - /* - * Enable the SA1110 memory bus request and grant signals. - */ - sa1110_mb_enable(); - - /* - * Initialise SA1111 IRQs - */ - int_dev.irq[0] = irq; - sa1111_init_irq(&int_dev); - - return 0; -} - struct sa1111_save_data { unsigned int skcr; unsigned int skpcr; @@ -717,7 +702,7 @@ struct sa1111_save_data { static int sa1111_suspend(struct device *dev, u32 state, u32 level) { - struct sa1111 *sachip = dev->driver_data; + struct sa1111 *sachip = dev_get_drvdata(dev); unsigned long flags; char *base; @@ -789,7 +774,7 @@ static int sa1111_suspend(struct device *dev, u32 state, u32 level) */ static int sa1111_resume(struct device *dev, u32 level) { - struct sa1111 *sachip = dev->driver_data; + struct sa1111 *sachip = dev_get_drvdata(dev); struct sa1111_save_data *save; unsigned long flags, id; char *base; @@ -809,6 +794,7 @@ static int sa1111_resume(struct device *dev, u32 level) id = sa1111_readl(sachip->base + SA1111_SKID); if ((id & SKID_ID_MASK) != SKID_SA1111_ID) { __sa1111_remove(sachip); + dev_set_drvdata(dev, NULL); kfree(save); return 0; } @@ -840,18 +826,85 @@ static int sa1111_resume(struct device *dev, u32 level) return 0; } +static int sa1111_probe(struct device *dev) +{ + return -ENODEV; +} + +static int sa1111_remove(struct device *dev) +{ + struct sa1111 *sachip = dev_get_drvdata(dev); + + if (sachip) { + __sa1111_remove(sachip); + dev_set_drvdata(dev, NULL); + + kfree(dev->saved_state); + dev->saved_state = NULL; + } + + return 0; +} + +/* + * Not sure if this should be on the system bus or not yet. + * We really want some way to register a system device at + * the per-machine level, and then have this driver pick + * up the registered devices. + * + * We also need to handle the SDRAM configuration for + * PXA250/SA1110 machine classes. + */ static struct device_driver sa1111_device_driver = { + .name = "SA1111", + .bus = &system_bus_type, + .probe = sa1111_probe, + .remove = sa1111_remove, .suspend = sa1111_suspend, .resume = sa1111_resume, }; /* + * Register the SA1111 driver with LDM. + */ +static int sa1111_driver_init(void) +{ + driver_register(&sa1111_device_driver); + return 0; +} + +arch_initcall(sa1111_driver_init); + +static struct sys_device sa1111_device = { + .name = "SA1111", + .id = 0, + .root = NULL, + .dev = { + .name = "Intel Corporation SA1111", + .driver = &sa1111_device_driver, + }, +}; + +int sa1111_init(unsigned long phys, unsigned int irq) +{ + int ret; + + snprintf(sa1111_device.dev.bus_id, sizeof(sa1111_device.dev.bus_id), "%8.8lx", phys); + + ret = sys_device_register(&sa1111_device); + if (ret) + printk("sa1111 device_register failed: %d\n", ret); + + return __sa1111_probe(&sa1111_device.dev, phys, irq); +} + +/* * Get the parent device driver (us) structure * from a child function device */ static inline struct sa1111 *sa1111_chip_driver(struct sa1111_dev *sadev) { - return (struct sa1111 *)sadev->dev.parent->driver_data; + return (struct sa1111 *)dev_get_drvdata(sadev->dev.parent); } /* diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index fb05656bdb6a..f8ad035fdf01 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -16,8 +16,10 @@ #include <linux/bitops.h> #include <linux/init.h> +#include <asm/cacheflush.h> #include <asm/pgalloc.h> #include <asm/pgtable.h> +#include <asm/tlbflush.h> #include "fault.h" diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 45b70123774c..ff3347e2669f 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -519,6 +519,10 @@ void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc) bdata->node_boot_start >> PAGE_SHIFT, zhole_size); } +#ifndef CONFIG_DISCONTIGMEM + mem_map = contig_page_data.node_mem_map; +#endif + /* * finish off the bad pages once * the mem_map is initialised @@ -559,7 +563,9 @@ void __init mem_init(void) initpages = &__init_end - &__init_begin; high_memory = (void *)__va(meminfo.end); +#ifndef CONFIG_DISCONTIGMEM max_mapnr = virt_to_page(high_memory) - mem_map; +#endif /* * We may have non-contiguous memory. diff --git a/arch/arm/mm/minicache.c b/arch/arm/mm/minicache.c index 96ae5be2b642..0ef53e8e4ec0 100644 --- a/arch/arm/mm/minicache.c +++ b/arch/arm/mm/minicache.c @@ -15,9 +15,11 @@ */ #include <linux/init.h> #include <linux/mm.h> + #include <asm/page.h> #include <asm/pgalloc.h> #include <asm/pgtable.h> +#include <asm/tlbflush.h> /* * 0xffff8000 to 0xffffffff is reserved for any ARM architecture diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index 259f7541a875..7898ede4b702 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -13,6 +13,7 @@ #include <linux/mm.h> #include <linux/init.h> #include <linux/bootmem.h> +#include <linux/highmem.h> #include <asm/pgtable.h> #include <asm/pgalloc.h> @@ -20,6 +21,7 @@ #include <asm/rmap.h> #include <asm/io.h> #include <asm/setup.h> +#include <asm/tlbflush.h> #include <asm/mach/map.h> @@ -213,6 +215,50 @@ static inline void clear_mapping(unsigned long virt) pmd_clear(pmd_offset(pgd_offset_k(virt), virt)); } +struct mem_types { + unsigned int prot_pte; + unsigned int prot_sect; + unsigned int domain; +}; + +static struct mem_types mem_types[] __initdata = { + [MT_DEVICE] = { + .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | + L_PTE_WRITE, + .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, + .domain = DOMAIN_IO, + }, + [MT_CACHECLEAN] = { + .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | + L_PTE_CACHEABLE | L_PTE_BUFFERABLE, + .prot_sect = PMD_TYPE_SECT | PMD_SECT_CACHEABLE | + PMD_SECT_BUFFERABLE, + .domain = DOMAIN_KERNEL, + }, + [MT_MINICLEAN] = { + .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | + L_PTE_CACHEABLE, + .prot_sect = PMD_TYPE_SECT | PMD_SECT_CACHEABLE, + .domain = DOMAIN_KERNEL, + }, + [MT_VECTORS] = { + .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | + L_PTE_CACHEABLE | L_PTE_BUFFERABLE | + L_PTE_EXEC, + .prot_sect = PMD_TYPE_SECT | PMD_SECT_CACHEABLE | + PMD_SECT_BUFFERABLE, + .domain = DOMAIN_USER, + }, + [MT_MEMORY] = { + .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | + L_PTE_CACHEABLE | L_PTE_BUFFERABLE | + L_PTE_EXEC | L_PTE_WRITE, + .prot_sect = PMD_TYPE_SECT | PMD_SECT_CACHEABLE | + PMD_SECT_BUFFERABLE | PMD_SECT_AP_WRITE, + .domain = DOMAIN_KERNEL, + } +}; + /* * Create the page directory entries and any necessary * page tables for the mapping specified by `md'. We @@ -232,42 +278,9 @@ static void __init create_mapping(struct map_desc *md) return; } - prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY; - prot_sect = PMD_TYPE_SECT; - - switch (md->type) { - case MT_DEVICE: - prot_pte |= L_PTE_WRITE; - prot_sect |= PMD_SECT_AP_WRITE; - domain = DOMAIN_IO; - break; - - case MT_CACHECLEAN: - prot_pte |= L_PTE_CACHEABLE | L_PTE_BUFFERABLE; - prot_sect |= PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE; - domain = DOMAIN_KERNEL; - break; - - case MT_MINICLEAN: - prot_pte |= L_PTE_CACHEABLE; - prot_sect |= PMD_SECT_CACHEABLE; - domain = DOMAIN_KERNEL; - break; - - case MT_VECTORS: - prot_pte |= L_PTE_EXEC | L_PTE_CACHEABLE | L_PTE_BUFFERABLE; - prot_sect |= PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE; - domain = DOMAIN_USER; - break; - - case MT_MEMORY: - prot_pte |= L_PTE_WRITE | L_PTE_EXEC | L_PTE_CACHEABLE | L_PTE_BUFFERABLE; - prot_sect |= PMD_SECT_AP_WRITE | PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE; - domain = DOMAIN_KERNEL; - break; - } - - prot_sect |= PMD_DOMAIN(domain); + domain = mem_types[md->type].domain; + prot_pte = mem_types[md->type].prot_pte; + prot_sect = mem_types[md->type].prot_sect | PMD_DOMAIN(domain); virt = md->virtual; off = md->physical - virt; diff --git a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c index c21c843ecd21..fe84d27a9681 100644 --- a/arch/arm/mm/proc-syms.c +++ b/arch/arm/mm/proc-syms.c @@ -10,8 +10,10 @@ #include <linux/module.h> #include <linux/mm.h> +#include <asm/cacheflush.h> #include <asm/pgalloc.h> #include <asm/proc-fns.h> +#include <asm/tlbflush.h> #ifndef MULTI_CPU EXPORT_SYMBOL(cpu_cache_clean_invalidate_all); @@ -29,11 +31,11 @@ EXPORT_SYMBOL(cpu_set_pte); EXPORT_SYMBOL(processor); #endif -#ifndef MULTI_TLB -EXPORT_SYMBOL_NOVERS(__cpu_flush_kern_tlb_all); -EXPORT_SYMBOL_NOVERS(__cpu_flush_user_tlb_mm); -EXPORT_SYMBOL_NOVERS(__cpu_flush_user_tlb_range); -EXPORT_SYMBOL_NOVERS(__cpu_flush_user_tlb_page); -#else +/* + * No module should need to touch the TLB (and currently + * no modules do. We export this for "loadkernel" support + * (booting a new kernel from within a running kernel.) + */ +#ifdef MULTI_TLB EXPORT_SYMBOL(cpu_tlb); #endif diff --git a/arch/arm/mm/tlb-v3.S b/arch/arm/mm/tlb-v3.S index 270108bb40c0..063d50ab88dd 100644 --- a/arch/arm/mm/tlb-v3.S +++ b/arch/arm/mm/tlb-v3.S @@ -13,32 +13,11 @@ */ #include <linux/linkage.h> #include <asm/constants.h> +#include <asm/tlbflush.h> #include "proc-macros.S" .align 5 /* - * v3_flush_user_tlb_mm(mm) - * - * Invalidate all TLB entries in a particular address space - * - * - mm - mm_struct describing address space - */ -ENTRY(v3_flush_user_tlb_mm) - act_mm r1 @ get current->active_mm - teq r0, r1 @ == mm ? - movne pc, lr @ no, we dont do anything - -/* - * v3_flush_kern_tlb_all() - * - * Invalidate the entire TLB - */ -ENTRY(v3_flush_kern_tlb_all) - mov r0, #0 - mcr p15, 0, r0, c5, c0, 0 @ invalidate TLB - mov pc, lr - -/* * v3_flush_user_tlb_range(start, end, mm) * * Invalidate a range of TLB entries in the specified address space. @@ -62,32 +41,11 @@ ENTRY(v3_flush_kern_tlb_range) blo 1b mov pc, lr -/* - * v3_flush_user_tlb_page(vaddr,vma) - * - * Invalidate the specified page in the specified address space. - * - * - vaddr - virtual address (may not be aligned) - * - vma - vma_struct describing address range - */ - .align 5 -ENTRY(v3_flush_user_tlb_page) - vma_vm_mm r2, r1 @ get vma->vm_mm - act_mm r3 @ get current->active_mm - teq r2, r3 @ equal - movne pc, lr @ no -ENTRY(v3_flush_kern_tlb_page) - mcr p15, 0, r0, c6, c0, 0 @ invalidate TLB entry - mov pc, lr - .section ".text.init", #alloc, #execinstr .type v3_tlb_fns, #object ENTRY(v3_tlb_fns) - .long v3_flush_kern_tlb_all - .long v3_flush_user_tlb_mm .long v3_flush_user_tlb_range - .long v3_flush_user_tlb_page .long v3_flush_kern_tlb_range - .long v3_flush_kern_tlb_page + .long v3_tlb_flags .size v3_tlb_fns, . - v3_tlb_fns diff --git a/arch/arm/mm/tlb-v4.S b/arch/arm/mm/tlb-v4.S index 2dd035b2281f..2ab22d9f3454 100644 --- a/arch/arm/mm/tlb-v4.S +++ b/arch/arm/mm/tlb-v4.S @@ -14,32 +14,11 @@ */ #include <linux/linkage.h> #include <asm/constants.h> +#include <asm/tlbflush.h> #include "proc-macros.S" .align 5 /* - * v4_flush_user_tlb_mm(mm) - * - * Invalidate all TLB entries in a particular address space - * - * - mm - mm_struct describing address space - */ -ENTRY(v4_flush_user_tlb_mm) - act_mm r1 @ get current->active_mm - teq r0, r1 @ == mm ? - movne pc, lr @ no, we dont do anything - -/* - * v4_flush_kern_tlb_all() - * - * Invalidate the entire TLB - */ -ENTRY(v4_flush_kern_tlb_all) - mov r0, #0 - mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs - mov pc, lr - -/* * v4_flush_user_tlb_range(start, end, mm) * * Invalidate a range of TLB entries in the specified user address space. @@ -65,25 +44,6 @@ ENTRY(v4_flush_user_tlb_range) mov pc, lr /* - * v4_flush_user_tlb_page(vaddr,vma) - * - * Invalidate the specified page in the specified address space. - * - * - vaddr - virtual address (may not be aligned) - * - vma - vma_struct describing address range - */ - .align 5 -ENTRY(v4_flush_user_tlb_page) - vma_vm_mm r2, r1 @ get vma->vm_mm - act_mm r3 @ get current->active_mm - teq r2, r3 @ equal - movne pc, lr @ no - vma_vm_flags r2, r1 -.v4_flush_kern_tlb_page: - mcr p15, 0, r0, c8, c7, 1 @ invalidate TLB entry - mov pc, lr - -/* * v4_flush_kerm_tlb_range(start, end) * * Invalidate a range of TLB entries in the specified kernel @@ -95,27 +55,11 @@ ENTRY(v4_flush_user_tlb_page) .globl v4_flush_kern_tlb_range .equ v4_flush_kern_tlb_range, .v4_flush_kern_tlb_range - -/* - * v4_flush_kern_tlb_page(kaddr) - * - * Invalidate the TLB entry for the specified page. The address - * will be in the kernels virtual memory space. Current uses - * only require the D-TLB to be invalidated. - * - * - kaddr - Kernel virtual memory address - */ -.globl v4_flush_kern_tlb_page -.equ v4_flush_kern_tlb_page, .v4_flush_kern_tlb_page - .section ".text.init", #alloc, #execinstr .type v4_tlb_fns, #object ENTRY(v4_tlb_fns) - .long v4_flush_kern_tlb_all - .long v4_flush_user_tlb_mm .long v4_flush_user_tlb_range - .long v4_flush_user_tlb_page .long v4_flush_kern_tlb_range - .long v4_flush_kern_tlb_page + .long v4_tlb_flags .size v4_tlb_fns, . - v4_tlb_fns diff --git a/arch/arm/mm/tlb-v4wb.S b/arch/arm/mm/tlb-v4wb.S index 3cdca44fcfb2..e9f8fb16b635 100644 --- a/arch/arm/mm/tlb-v4wb.S +++ b/arch/arm/mm/tlb-v4wb.S @@ -14,35 +14,11 @@ */ #include <linux/linkage.h> #include <asm/constants.h> +#include <asm/tlbflush.h> #include "proc-macros.S" .align 5 /* - * v4wb_flush_user_tlb_mm(mm) - * - * Invalidate all TLB entries in a particular address space - * - * - mm - mm_struct describing address space - */ -ENTRY(v4wb_flush_user_tlb_mm) -ENTRY(v4wbi_flush_user_tlb_mm) - act_mm r1 @ get current->active_mm - teq r0, r1 @ == mm ? - movne pc, lr @ no, we dont do anything - -/* - * v4wb_flush_tlb_all() - * - * Invalidate the entire TLB - */ -ENTRY(v4wb_flush_kern_tlb_all) -ENTRY(v4wbi_flush_kern_tlb_all) - mov r0, #0 - mcr p15, 0, r0, c7, c10, 4 @ drain WB - mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs - mov pc, lr - -/* * v4wb_flush_user_tlb_range(start, end, mm) * * Invalidate a range of TLB entries in the specified address space. @@ -70,28 +46,6 @@ ENTRY(v4wb_flush_user_tlb_range) mov pc, lr /* - * v4wb_flush_user_tlb_page(vaddr,vma) - * - * Invalidate the specified page in the specified address space. - * - * - vaddr - virtual address (may not be aligned) - * - vma - vma_struct describing address range - */ - .align 5 -ENTRY(v4wb_flush_user_tlb_page) - vma_vm_mm r2, r1 @ get vma->vm_mm - act_mm r3 @ get current->active_mm - teq r2, r3 @ equal - movne pc, lr @ no - vma_vm_flags r2, r1 - mov r3, #0 - mcr p15, 0, r3, c7, c10, 4 @ drain WB - tst r2, #VM_EXEC - mcrne p15, 0, r3, c8, c5, 0 @ invalidate I TLB - mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mov pc, lr - -/* * v4_flush_kerm_tlb_range(start, end) * * Invalidate a range of TLB entries in the specified kernel @@ -113,20 +67,6 @@ ENTRY(v4wb_flush_kern_tlb_range) mov pc, lr /* - * v4_flush_kern_tlb_page(kaddr) - * - * Invalidate the TLB entry for the specified page. The address - * will be in the kernels virtual memory space. Current uses - * only require the D-TLB to be invalidated. - * - * - kaddr - Kernel virtual memory address - */ -ENTRY(v4wb_flush_kern_tlb_page) - mcr p15, 0, r3, c8, c5, 0 @ invalidate I TLB - mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mov pc, lr - -/* * These two are optimised for ARM920, ARM922, ARM926, Xscale */ @@ -158,28 +98,6 @@ ENTRY(v4wbi_flush_user_tlb_range) blo 1b mov pc, lr -/* - * v4wb_flush_tlb_page(vaddr,vma) - * - * Invalidate the specified page in the specified address space. - * - * - vaddr - virtual address (may not be aligned) - * - vma - vma_struct describing address range - */ - .align 5 -ENTRY(v4wbi_flush_user_tlb_page) - vma_vm_mm r2, r1 @ get vma->vm_mm - act_mm r3 @ get current->active_mm - teq r2, r3 @ equal - movne pc, lr @ no - vma_vm_flags r2, r1 - mov r3, #0 - mcr p15, 0, r3, c7, c10, 4 @ drain WB - tst r2, #VM_EXEC - mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry - mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mov pc, lr - ENTRY(v4wbi_flush_kern_tlb_range) mov r3, #0 mcr p15, 0, r3, c7, c10, 4 @ drain WB @@ -192,29 +110,18 @@ ENTRY(v4wbi_flush_kern_tlb_range) blo 1b mov pc, lr -ENTRY(v4wbi_flush_kern_tlb_page) - mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry - mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mov pc, lr - .section ".text.init", #alloc, #execinstr .type v4wb_tlb_fns, #object ENTRY(v4wb_tlb_fns) - .long v4wb_flush_kern_tlb_all - .long v4wb_flush_user_tlb_mm .long v4wb_flush_user_tlb_range - .long v4wb_flush_user_tlb_page .long v4wb_flush_kern_tlb_range - .long v4wb_flush_kern_tlb_page + .long v4wb_tlb_flags .size v4wb_tlb_fns, . - v4wb_tlb_fns .type v4wbi_tlb_fns, #object ENTRY(v4wbi_tlb_fns) - .long v4wbi_flush_kern_tlb_all - .long v4wbi_flush_user_tlb_mm .long v4wbi_flush_user_tlb_range - .long v4wbi_flush_user_tlb_page .long v4wbi_flush_kern_tlb_range - .long v4wbi_flush_kern_tlb_page + .long v4wbi_tlb_flags .size v4wbi_tlb_fns, . - v4wbi_tlb_fns diff --git a/arch/arm/vmlinux.lds.S b/arch/arm/vmlinux.lds.S index 008dbc027c57..ec99a51eece9 100644 --- a/arch/arm/vmlinux.lds.S +++ b/arch/arm/vmlinux.lds.S @@ -4,13 +4,10 @@ #ifdef CONFIG_ROM_KERNEL -#define DATAADDR 0x02080000 -#define TEXTADDR 0x03800000 #include "vmlinux-armo-rom.lds.in" #else -#define TEXTADDR 0x02080000 #include "vmlinux-armo.lds.in" #endif @@ -19,7 +16,6 @@ #ifdef CONFIG_CPU_32 -#define TEXTADDR 0xC0008000 #include "vmlinux-armv.lds.in" #endif diff --git a/arch/cris/drivers/examples/kiobuftest.c b/arch/cris/drivers/examples/kiobuftest.c deleted file mode 100644 index 784418f9c4d6..000000000000 --- a/arch/cris/drivers/examples/kiobuftest.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Example showing how to pin down a range of virtual pages from user-space - * to be able to do for example DMA directly into them. - * - * It is necessary because the pages the virtual pointers reference, might - * not exist in memory (could be mapped to the zero-page, filemapped etc) - * and DMA cannot trigger the MMU to force them in (and would have time - * contraints making it impossible to wait for it anyway). - * - * Author: Bjorn Wesen - * - * $Log: kiobuftest.c,v $ - * Revision 1.1.1.1 2001/12/17 13:59:27 bjornw - * Import of Linux 2.5.1 - * - * Revision 1.2 2001/02/27 13:52:50 bjornw - * malloc.h -> slab.h - * - * Revision 1.1 2001/01/19 15:57:49 bjornw - * Example of how to do direct HW -> user-mode DMA - * - * - */ - -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/fs.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/mm.h> -#include <linux/iobuf.h> - -#define KIOBUFTEST_MAJOR 124 /* in the local range, experimental */ - - -static ssize_t -kiobuf_read(struct file *filp, char *buf, size_t len, loff_t *ppos) -{ - - struct kiobuf *iobuf; - int res, i; - - /* Make a kiobuf that maps the entire length the reader has given - * us - */ - - res = alloc_kiovec(1, &iobuf); - if (res) - return res; - - if((res = map_user_kiobuf(READ, iobuf, (unsigned long)buf, len))) { - printk("map_user_kiobuf failed, return %d\n", res); - return res; - } - - /* At this point, the virtual area buf[0] -> buf[len-1] will - * have corresponding pages mapped in physical memory and locked - * until we unmap the kiobuf. They cannot be swapped out or moved - * around. - */ - - printk("nr_pages == %d\noffset == %d\nlength == %d\n", - iobuf->nr_pages, iobuf->offset, iobuf->length); - - for(i = 0; i < iobuf->nr_pages; i++) { - printk("page_add(maplist[%d]) == 0x%x\n", i, - page_address(iobuf->maplist[i])); - } - - /* This is the place to create the necessary scatter-gather vector - * for the DMA using the iobuf->maplist array and page_address - * (don't forget __pa if the DMA needs the actual physical DRAM address) - * and run it. - */ - - - - - /* Release the mapping and exit */ - - unmap_kiobuf(iobuf); /* The unlock_kiobuf is implicit here */ - - return len; -} - - -static struct file_operations kiobuf_fops = { - owner: THIS_MODULE, - read: kiobuf_read -}; - -static int __init -kiobuftest_init(void) -{ - int res; - - /* register char device */ - - res = register_chrdev(KIOBUFTEST_MAJOR, "kiobuftest", &kiobuf_fops); - if(res < 0) { - printk(KERN_ERR "kiobuftest: couldn't get a major number.\n"); - return res; - } - - printk("Initializing kiobuf-test device\n"); -} - -module_init(kiobuftest_init); diff --git a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c index 1ff190bd68b4..ce54c1886dbc 100644 --- a/arch/i386/mm/discontig.c +++ b/arch/i386/mm/discontig.c @@ -70,6 +70,7 @@ static void __init allocate_pgdat(int nid) node_datasz = PFN_UP(sizeof(struct pglist_data)); NODE_DATA(nid) = (pg_data_t *)(__va(min_low_pfn << PAGE_SHIFT)); min_low_pfn += node_datasz; + memset(NODE_DATA(nid), 0, sizeof(struct pglist_data)); } /* diff --git a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c index d7d9939af12c..85b5b9cd8859 100644 --- a/drivers/acorn/block/fd1772.c +++ b/drivers/acorn/block/fd1772.c @@ -345,8 +345,6 @@ static void fd_select_drive(int drive); static void fd_deselect(void); static void fd_motor_off_timer(unsigned long dummy); static void check_change(unsigned long dummy); -static __inline__ void set_head_settle_flag(void); -static __inline__ int get_head_settle_flag(void); static void floppy_irqconsequencehandler(void); static void fd_error(void); static void do_fd_action(int drive); @@ -363,7 +361,6 @@ static void fd_times_out(unsigned long dummy); static void finish_fdc(void); static void finish_fdc_done(int dummy); static void floppy_off(unsigned int nr); -static __inline__ void copy_buffer(void *from, void *to); static void setup_req_params(int drive); static void redo_fd_request(void); static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int @@ -543,12 +540,12 @@ static void check_change(unsigned long dummy) * seek operation, because we don't use seeks with verify. */ -static __inline__ void set_head_settle_flag(void) +static inline void set_head_settle_flag(void) { HeadSettleFlag = FDC1772CMDADD_E; } -static __inline__ int get_head_settle_flag(void) +static inline int get_head_settle_flag(void) { int tmp = HeadSettleFlag; HeadSettleFlag = 0; @@ -560,6 +557,15 @@ static __inline__ int get_head_settle_flag(void) /* General Interrupt Handling */ +static inline void copy_buffer(void *from, void *to) +{ + ulong *p1 = (ulong *) from, *p2 = (ulong *) to; + int cnt; + + for (cnt = 512 / 4; cnt; cnt--) + *p2++ = *p1++; +} + static void (*FloppyIRQHandler) (int status) = NULL; static void floppy_irqconsequencehandler(void) @@ -1175,16 +1181,6 @@ static int floppy_revalidate(dev_t dev) return 0; } -static __inline__ void copy_buffer(void *from, void *to) -{ - ulong *p1 = (ulong *) from, *p2 = (ulong *) to; - int cnt; - - for (cnt = 512 / 4; cnt; cnt--) - *p2++ = *p1++; -} - - /* This sets up the global variables describing the current request. */ static void setup_req_params(int drive) diff --git a/drivers/acorn/char/Makefile b/drivers/acorn/char/Makefile index 456c7e3c5124..b5cc8486bbd2 100644 --- a/drivers/acorn/char/Makefile +++ b/drivers/acorn/char/Makefile @@ -3,18 +3,11 @@ # # All the objects that export symbols. -obj-arc := keyb_arc.o -obj-rpc := keyb_ps2.o -obj-clps7500 := keyb_ps2.o defkeymap-acorn.o - -obj-$(CONFIG_RPCMOUSE) += mouse_rpc.o -obj-$(CONFIG_ATOMWIDE_SERIAL) += serial-atomwide.o -obj-$(CONFIG_DUALSP_SERIAL) += serial-dualsp.o -obj-$(CONFIG_ARCH_ACORN) += defkeymap-acorn.o i2c.o pcf8583.o -obj-$(CONFIG_L7200_KEYB) += defkeymap-l7200.o keyb_l7200.o +obj-arc := keyb_arc.o defkeymap-acorn.o -# Do the i2c and rtc last -obj-y += $(obj-$(MACHINE)) +obj-$(CONFIG_ARCH_ACORN) += i2c.o pcf8583.o +obj-$(CONFIG_L7200_KEYB) += defkeymap-l7200.o keyb_l7200.o +obj-y += $(obj-$(MACHINE)) include $(TOPDIR)/Rules.make diff --git a/drivers/acorn/char/i2c.c b/drivers/acorn/char/i2c.c index e01e017dfcbe..6a5c0da68983 100644 --- a/drivers/acorn/char/i2c.c +++ b/drivers/acorn/char/i2c.c @@ -132,7 +132,7 @@ static int k_set_rtc_time(void) if (rtc_command(RTC_GETDATETIME, &old_rtctm)) return 0; - new_rtctm.cs = xtime.tv_usec / 10000; + new_rtctm.cs = xtime.tv_nsec / 10000000; new_rtctm.secs = nowtime % 60; nowtime /= 60; new_rtctm.mins = nowtime % 60; nowtime /= 60; new_rtctm.hours = nowtime % 24; @@ -283,7 +283,7 @@ static int ioc_client_reg(struct i2c_client *client) rtc_client = client; get_rtc_time(&rtctm, &year); - xtime.tv_usec = rtctm.cs * 10000; + xtime.tv_nsec = rtctm.cs * 10000000; xtime.tv_sec = mktime(year, rtctm.mon, rtctm.mday, rtctm.hours, rtctm.mins, rtctm.secs); set_rtc = k_set_rtc_time; diff --git a/drivers/acorn/char/keyb_ps2.c b/drivers/acorn/char/keyb_ps2.c deleted file mode 100644 index 033c111572a9..000000000000 --- a/drivers/acorn/char/keyb_ps2.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - * linux/drivers/acorn/char/keyb_ps2.c - * - * Copyright (C) 2000 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Keyboard driver for RiscPC ARM Linux. - * - * Note!!! This driver talks directly to the keyboard. - */ -#include <linux/config.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/ptrace.h> -#include <linux/signal.h> -#include <linux/timer.h> -#include <linux/random.h> -#include <linux/ctype.h> -#include <linux/kbd_ll.h> -#include <linux/delay.h> -#include <linux/init.h> - -#include <asm/bitops.h> -#include <asm/irq.h> -#include <asm/hardware.h> -#include <asm/keyboard.h> -#include <asm/io.h> -#include <asm/hardware/iomd.h> -#include <asm/system.h> - -extern struct tasklet_struct keyboard_tasklet; -extern void kbd_reset_kdown(void); -int kbd_read_mask; - -#define TX_DONE 0 -#define TX_SENT 1 -#define TX_SEND 2 - -static volatile int tx_state; - -#define VERSION 100 - -#define KBD_REPORT_ERR -#define KBD_REPORT_UNKN - -#define KBD_ESCAPEE0 0xe0 /* in */ -#define KBD_ESCAPEE1 0xe1 /* in */ - -#define ESCE0(x) (0xe000|(x)) -#define ESCE1(x) (0xe100|(x)) - -#define KBD_BAT 0xaa /* in */ -#define KBD_SETLEDS 0xed /* out */ -#define KBD_ECHO 0xee /* in/out */ -#define KBD_BREAK 0xf0 /* in */ -#define KBD_TYPRATEDLY 0xf3 /* out */ -#define KBD_SCANENABLE 0xf4 /* out */ -#define KBD_DEFDISABLE 0xf5 /* out */ -#define KBD_DEFAULT 0xf6 /* out */ -#define KBD_ACK 0xfa /* in */ -#define KBD_DIAGFAIL 0xfd /* in */ -#define KBD_RESEND 0xfe /* in/out */ -#define KBD_RESET 0xff /* out */ - -#define CODE_BREAK 1 -#define CODE_ESCAPEE0 2 -#define CODE_ESCAPEE1 4 -#define CODE_ESCAPE12 8 - -#define K_NONE 0x7f -#define K_ESC 0x00 -#define K_F1 0x01 -#define K_F2 0x02 -#define K_F3 0x03 -#define K_F4 0x04 -#define K_F5 0x05 -#define K_F6 0x06 -#define K_F7 0x07 -#define K_F8 0x08 -#define K_F9 0x09 -#define K_F10 0x0a -#define K_F11 0x0b -#define K_F12 0x0c -#define K_PRNT 0x0d -#define K_SCRL 0x0e -#define K_BRK 0x0f -#define K_AGR 0x10 -#define K_1 0x11 -#define K_2 0x12 -#define K_3 0x13 -#define K_4 0x14 -#define K_5 0x15 -#define K_6 0x16 -#define K_7 0x17 -#define K_8 0x18 -#define K_9 0x19 -#define K_0 0x1a -#define K_MINS 0x1b -#define K_EQLS 0x1c -#define K_BKSP 0x1e -#define K_INS 0x1f -#define K_HOME 0x20 -#define K_PGUP 0x21 -#define K_NUML 0x22 -#define KP_SLH 0x23 -#define KP_STR 0x24 -#define KP_MNS 0x3a -#define K_TAB 0x26 -#define K_Q 0x27 -#define K_W 0x28 -#define K_E 0x29 -#define K_R 0x2a -#define K_T 0x2b -#define K_Y 0x2c -#define K_U 0x2d -#define K_I 0x2e -#define K_O 0x2f -#define K_P 0x30 -#define K_LSBK 0x31 -#define K_RSBK 0x32 -#define K_ENTR 0x47 -#define K_DEL 0x34 -#define K_END 0x35 -#define K_PGDN 0x36 -#define KP_7 0x37 -#define KP_8 0x38 -#define KP_9 0x39 -#define KP_PLS 0x4b -#define K_CAPS 0x5d -#define K_A 0x3c -#define K_S 0x3d -#define K_D 0x3e -#define K_F 0x3f -#define K_G 0x40 -#define K_H 0x41 -#define K_J 0x42 -#define K_K 0x43 -#define K_L 0x44 -#define K_SEMI 0x45 -#define K_SQOT 0x46 -#define K_HASH 0x1d -#define KP_4 0x48 -#define KP_5 0x49 -#define KP_6 0x4a -#define K_LSFT 0x4c -#define K_BSLH 0x33 -#define K_Z 0x4e -#define K_X 0x4f -#define K_C 0x50 -#define K_V 0x51 -#define K_B 0x52 -#define K_N 0x53 -#define K_M 0x54 -#define K_COMA 0x55 -#define K_DOT 0x56 -#define K_FSLH 0x57 -#define K_RSFT 0x58 -#define K_UP 0x59 -#define KP_1 0x5a -#define KP_2 0x5b -#define KP_3 0x5c -#define KP_ENT 0x67 -#define K_LCTL 0x3b -#define K_LALT 0x5e -#define K_SPCE 0x5f -#define K_RALT 0x60 -#define K_RCTL 0x61 -#define K_LEFT 0x62 -#define K_DOWN 0x63 -#define K_RGHT 0x64 -#define KP_0 0x65 -#define KP_DOT 0x66 - -static unsigned char keycode_translate[256] = -{ -/* 00 */ K_NONE, K_F9 , K_NONE, K_F5 , K_F3 , K_F1 , K_F2 , K_F12 , -/* 08 */ K_NONE, K_F10 , K_F8 , K_F6 , K_F4 , K_TAB , K_AGR , K_NONE, -/* 10 */ K_NONE, K_LALT, K_LSFT, K_NONE, K_LCTL, K_Q , K_1 , K_NONE, -/* 18 */ K_NONE, K_NONE, K_Z , K_S , K_A , K_W , K_2 , K_NONE, -/* 20 */ K_NONE, K_C , K_X , K_D , K_E , K_4 , K_3 , K_NONE, -/* 28 */ K_NONE, K_SPCE, K_V , K_F , K_T , K_R , K_5 , K_NONE, -/* 30 */ K_NONE, K_N , K_B , K_H , K_G , K_Y , K_6 , K_NONE, -/* 38 */ K_NONE, K_NONE, K_M , K_J , K_U , K_7 , K_8 , K_NONE, -/* 40 */ K_NONE, K_COMA, K_K , K_I , K_O , K_0 , K_9 , K_NONE, -/* 48 */ K_NONE, K_DOT , K_FSLH, K_L , K_SEMI, K_P , K_MINS, K_NONE, -/* 50 */ K_NONE, K_NONE, K_SQOT, K_NONE, K_LSBK, K_EQLS, K_NONE, K_NONE, -/* 58 */ K_CAPS, K_RSFT, K_ENTR, K_RSBK, K_NONE, K_HASH, K_NONE, K_NONE, -/* 60 */ K_NONE, K_BSLH, K_NONE, K_NONE, K_NONE, K_NONE, K_BKSP, K_NONE, -/* 68 */ K_NONE, KP_1 , K_NONE, KP_4 , KP_7 , K_NONE, K_NONE, K_NONE, -/* 70 */ KP_0 , KP_DOT, KP_2 , KP_5 , KP_6 , KP_8 , K_ESC , K_NUML, -/* 78 */ K_F11 , KP_PLS, KP_3 , KP_MNS, KP_STR, KP_9 , K_SCRL, K_NONE, - K_NONE, K_NONE, K_NONE, K_F7 , K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE -}; - -#ifdef CONFIG_MAGIC_SYSRQ -static unsigned char ps2kbd_sysrq_xlate[] = -{ - 27, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - '`', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '0', '-', '=', '£', 127, 0, - 0, 0, 0, '/', '*', '#', 9, 'q', - 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', - 'p', '[', ']', '\\', 22, 23, 25, '7', - '8', '9', '-', 0, 'a', 's', 'd', 'f', - 'g', 'h', 'j', 'k', 'l', ';', '\'', 13, - '4', '5', '6', '+', 0, 0, 'z', 'x', - 'c', 'v', 'b', 'n', 'm', ',', '.', '/', - 0, 0, '1', '2', '3', 0, 0, ' ', - 0, 0, 0, 0, 0, '0', '.', 10, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, -}; -#endif - -static inline void ps2kbd_key(unsigned int keycode, unsigned int up_flag) -{ - handle_scancode(keycode, !up_flag); -} - -static inline void ps2kbd_sendbyte(unsigned char val) -{ - int tries = 3, timeout = 1000; - - tx_state = TX_SEND; - - do { - switch (tx_state) { - case TX_SEND: - tx_state = TX_SENT; - timeout = 1000; - tries --; - - while(!(iomd_readb(IOMD_KCTRL) & (1 << 7))); - iomd_writeb(val, IOMD_KARTTX); - break; - - case TX_SENT: - udelay(1000); - if (--timeout == 0) { - printk(KERN_ERR "Keyboard timeout\n"); - tx_state = TX_DONE; - } - break; - - case TX_DONE: - break; - } - } while (tries > 0 && tx_state != TX_DONE); -} - -static unsigned char status; -static unsigned char ncodes; -static unsigned char bi; -static unsigned char buffer[4]; - -static inline void ps2kbd_reset(void) -{ - status = 0; - kbd_reset_kdown(); -} - -static void handle_rawcode(int keyval) -{ - int keysym; - - if (keyval > 0x83) { - switch (keyval) { - case KBD_ESCAPEE0: - ncodes = 2; - bi = 0; - break; - - case KBD_ESCAPEE1: - ncodes = 3; - bi = 0; - break; - - case KBD_ACK: - tx_state = TX_DONE; - return; - - case KBD_RESEND: - tx_state = TX_SEND; - return; - - case KBD_BREAK: - status |= CODE_BREAK; - return; - - default: - return; - } - } - - if (ncodes) { - buffer[bi++] = keyval; - ncodes -= 1; - if (ncodes) - return; - keysym = K_NONE; - switch (buffer[0] << 8 | buffer[1]) { - case ESCE0(0x11): keysym = K_RALT; break; - case ESCE0(0x14): keysym = K_RCTL; break; - /* - * take care of MS extra keys (actually - * 0x7d - 0x7f, but last one is already K_NONE - */ - case ESCE0(0x1f): keysym = 124; break; - case ESCE0(0x27): keysym = 125; break; - case ESCE0(0x2f): keysym = 126; break; - case ESCE0(0x4a): keysym = KP_SLH; break; - case ESCE0(0x5a): keysym = KP_ENT; break; - case ESCE0(0x69): keysym = K_END; break; - case ESCE0(0x6b): keysym = K_LEFT; break; - case ESCE0(0x6c): keysym = K_HOME; break; - case ESCE0(0x70): keysym = K_INS; break; - case ESCE0(0x71): keysym = K_DEL; break; - case ESCE0(0x72): keysym = K_DOWN; break; - case ESCE0(0x74): keysym = K_RGHT; break; - case ESCE0(0x75): keysym = K_UP; break; - case ESCE0(0x7a): keysym = K_PGDN; break; - case ESCE0(0x7c): keysym = K_PRNT; break; - case ESCE0(0x7d): keysym = K_PGUP; break; - case ESCE1(0x14): - if (buffer[2] == 0x77) - keysym = K_BRK; - break; - case ESCE0(0x12): /* ignore escaped shift key */ - status = 0; - return; - } - } else { - bi = 0; - keysym = keycode_translate[keyval]; - } - - if (keysym != K_NONE) - ps2kbd_key(keysym, status & CODE_BREAK); - status = 0; -} - -static void ps2kbd_leds(unsigned char leds) -{ - ps2kbd_sendbyte(KBD_SETLEDS); - ps2kbd_sendbyte(leds); - ps2kbd_sendbyte(KBD_SCANENABLE); -} - -static void ps2kbd_rx(int irq, void *dev_id, struct pt_regs *regs) -{ - kbd_pt_regs = regs; - - while (iomd_readb(IOMD_KCTRL) & (1 << 5)) - handle_rawcode(iomd_readb(IOMD_KARTRX)); - tasklet_schedule(&keyboard_tasklet); -} - -static void ps2kbd_tx(int irq, void *dev_id, struct pt_regs *regs) -{ -} - -static int ps2kbd_translate(unsigned char scancode, unsigned char *keycode, char rawmode) -{ - *keycode = scancode; - return 1; -} - -static char ps2kbd_unexpected_up(unsigned char scancode) -{ - return 0200; -} - -int __init ps2kbd_init_hw(void) -{ - /* Reset the keyboard state machine. */ - iomd_writeb(0, IOMD_KCTRL); - iomd_writeb(8, IOMD_KCTRL); - iomd_readb(IOMD_KARTRX); - - if (request_irq (IRQ_KEYBOARDRX, ps2kbd_rx, 0, "keyboard", NULL) != 0) - panic("Could not allocate keyboard receive IRQ!"); - if (request_irq (IRQ_KEYBOARDTX, ps2kbd_tx, 0, "keyboard", NULL) != 0) - panic("Could not allocate keyboard transmit IRQ!"); - - k_translate = ps2kbd_translate; - k_unexpected_up = ps2kbd_unexpected_up; - k_leds = ps2kbd_leds; -#ifdef CONFIG_MAGIC_SYSRQ - k_sysrq_xlate = ps2kbd_sysrq_xlate; - k_sysrq_key = 13; -#endif - - return 0; -} diff --git a/drivers/acorn/char/mouse_rpc.c b/drivers/acorn/char/mouse_rpc.c deleted file mode 100644 index bf6d2fd25923..000000000000 --- a/drivers/acorn/char/mouse_rpc.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * linux/drivers/char/mouse_rpc.c - * - * Copyright (C) 1996-1998 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This handles the Acorn RiscPCs mouse. We basically have a couple - * of hardware registers that track the sensor count for the X-Y movement - * and another register holding the button state. On every VSYNC interrupt - * we read the complete state and then work out if something has changed. - */ -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/ptrace.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/errno.h> - -#include <asm/hardware.h> -#include <asm/irq.h> -#include <asm/io.h> -#include <asm/hardware/iomd.h> - -#include "../../char/busmouse.h" - -static short old_x, old_y, old_b; -static int mousedev; - -void -mouse_rpc_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - short x, y, dx, dy; - int buttons; - - x = (short)iomd_readl(IOMD_MOUSEX); - y = (short)iomd_readl(IOMD_MOUSEY); - buttons = (__raw_readl(0xe0310000) >> 4) & 7; - - dx = x - old_x; - old_x = x; - dy = y - old_y; - old_y = y; - - if (dx || dy || buttons != old_b) { - busmouse_add_movementbuttons(mousedev, dx, dy, buttons); - old_b = buttons; - } -} - -static struct busmouse rpcmouse = { - 6, "arcmouse", NULL, NULL, NULL, 7 -}; - -static int __init mouse_rpc_init(void) -{ - mousedev = register_busmouse(&rpcmouse); - - if (mousedev < 0) - printk("rpcmouse: could not register mouse driver\n"); - else { - old_x = (short)iomd_readl(IOMD_MOUSEX); - old_y = (short)iomd_readl(IOMD_MOUSEY); - old_b = (__raw_readl(0xe0310000) >> 4) & 7; - if (request_irq(IRQ_VSYNCPULSE, mouse_rpc_irq, SA_SHIRQ, "mouse", &mousedev)) { - printk("rpcmouse: unable to allocate VSYNC interrupt\n"); - unregister_busmouse(mousedev); - mousedev = -1; - } - } - - return mousedev >= 0 ? 0 : -ENODEV; -} - -static void __exit mouse_rpc_exit(void) -{ - if (mousedev >= 0) { - unregister_busmouse(mousedev); - free_irq(IRQ_VSYNCPULSE, &mousedev); - } -} - -module_init(mouse_rpc_init); -module_exit(mouse_rpc_exit); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("RiscPC mouse driver"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/acorn/char/serial-atomwide.c b/drivers/acorn/char/serial-atomwide.c deleted file mode 100644 index 8f55b80c31de..000000000000 --- a/drivers/acorn/char/serial-atomwide.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * linux/arch/arm/drivers/char/serial-atomwide.c - * - * Copyright (C) 1996 Russell King. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Changelog: - * 02-05-1996 RMK Created - * 07-05-1996 RMK Altered for greater number of cards. - * 30-07-1996 RMK Now uses generic card code. - */ -#define MY_CARD_LIST { MANU_ATOMWIDE, PROD_ATOMWIDE_3PSERIAL } -#define MY_NUMPORTS 3 -#define MY_BAUD_BASE (7372800 / 16) -#define MY_BASE_ADDRESS(ec) \ - ecard_address ((ec), ECARD_IOC, ECARD_SLOW) + (0x2000 >> 2) -#define MY_PORT_ADDRESS(port,cardaddr) \ - ((cardaddr) + 0x200 - (port) * 0x100) - -#include "serial-card.c" diff --git a/drivers/acorn/char/serial-card.c b/drivers/acorn/char/serial-card.c deleted file mode 100644 index ae05095bb6bc..000000000000 --- a/drivers/acorn/char/serial-card.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * linux/drivers/acorn/char/serial-card.c - * - * Copyright (C) 1996-1999 Russell King. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * A generic handler of serial expansion cards that use 16550s or - * the like. - * - * Definitions: - * MY_PRODS Product numbers to identify this card by - * MY_MANUS Manufacturer numbers to identify this card by - * MY_NUMPORTS Number of ports per card - * MY_BAUD_BASE Baud base for the card - * MY_INIT Initialisation routine name - * MY_BASE_ADDRESS(ec) Return base address for ports - * MY_PORT_ADDRESS - * (port,cardaddr) Return address for port using base address - * from above. - * - * Changelog: - * 30-07-1996 RMK Created - * 22-04-1998 RMK Removed old register_pre_init_serial - */ -#include <linux/module.h> -#include <linux/types.h> -#include <linux/serial.h> -#include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/init.h> - -#include <asm/ecard.h> -#include <asm/string.h> - -#ifndef NUM_SERIALS -#define NUM_SERIALS MY_NUMPORTS * MAX_ECARDS -#endif - -static int serial_ports[NUM_SERIALS]; -static int serial_pcount; -static int serial_addr[NUM_SERIALS]; -static struct expansion_card *expcard[MAX_ECARDS]; - -static const card_ids serial_cids[] = { MY_CARD_LIST, { 0xffff, 0xffff } }; - -static inline int serial_register_onedev (unsigned long port, int irq) -{ - struct serial_struct req; - - memset(&req, 0, sizeof(req)); - req.baud_base = MY_BAUD_BASE; - req.irq = irq; - req.port = port; - req.flags = 0; - - return register_serial(&req); -} - -static int __init serial_card_init(void) -{ - int card = 0; - - ecard_startfind (); - - do { - struct expansion_card *ec; - unsigned long cardaddr; - int port; - - ec = ecard_find (0, serial_cids); - if (!ec) - break; - - cardaddr = MY_BASE_ADDRESS(ec); - - for (port = 0; port < MY_NUMPORTS; port ++) { - unsigned long address; - int line; - - address = MY_PORT_ADDRESS(port, cardaddr); - - line = serial_register_onedev (address, ec->irq); - if (line < 0) - break; - serial_ports[serial_pcount] = line; - serial_addr[serial_pcount] = address; - serial_pcount += 1; - } - - if (port) { - ecard_claim (ec); - expcard[card] = ec; - } else - break; - } while (++card < MAX_ECARDS); - return card ? 0 : -ENODEV; -} - -static void __exit serial_card_exit(void) -{ - int i; - - for (i = 0; i < serial_pcount; i++) { - unregister_serial(serial_ports[i]); - release_region(serial_addr[i], 8); - } - - for (i = 0; i < MAX_ECARDS; i++) - if (expcard[i]) - ecard_release (expcard[i]); -} - -MODULE_AUTHOR("Russell King"); -MODULE_LICENSE("GPL"); - -module_init(serial_card_init); -module_exit(serial_card_exit); diff --git a/drivers/acorn/char/serial-dualsp.c b/drivers/acorn/char/serial-dualsp.c deleted file mode 100644 index dcd26c1f8d29..000000000000 --- a/drivers/acorn/char/serial-dualsp.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * linux/drivers/acorn/char/serial-dualsp.c - * - * Copyright (C) 1996 Russell King. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Changelog: - * 30-07-1996 RMK Created - */ -#define MY_CARD_LIST { MANU_SERPORT, PROD_SERPORT_DSPORT } -#define MY_NUMPORTS 2 -#define MY_BAUD_BASE (3686400 / 16) -#define MY_BASE_ADDRESS(ec) \ - ecard_address (ec, ECARD_IOC, ECARD_SLOW) + (0x2000 >> 2) -#define MY_PORT_ADDRESS(port,cardaddress) \ - ((cardaddress) + (port) * 8) - -#include "serial-card.c" diff --git a/drivers/acorn/net/ether1.c b/drivers/acorn/net/ether1.c index 9b91f7642abb..d20d361c85a6 100644 --- a/drivers/acorn/net/ether1.c +++ b/drivers/acorn/net/ether1.c @@ -43,6 +43,7 @@ #include <linux/slab.h> #include <linux/string.h> #include <linux/errno.h> +#include <linux/device.h> #include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -80,11 +81,6 @@ static char version[] __initdata = "ether1 ethernet driver (c) 2000 Russell King #define BUS_16 16 #define BUS_8 8 -static const card_ids __init ether1_cids[] = { - { MANU_ACORN, PROD_ACORN_ETHER1 }, - { 0xffff, 0xffff } -}; - /* ------------------------------------------------------------------------- */ #define DISABLEIRQS 1 @@ -647,6 +643,12 @@ ether1_open (struct net_device *dev) { struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + if (!is_valid_ether_addr(dev->dev_addr)) { + printk(KERN_WARNING "%s: invalid ethernet MAC address\n", + dev->name); + return -EINVAL; + } + if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev)) return -EAGAIN; @@ -971,6 +973,23 @@ ether1_getstats (struct net_device *dev) return &priv->stats; } +static int +ether1_set_mac_address(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + + if (netif_running(dev)) + return -EBUSY; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + /* + * We'll set the MAC address on the chip when we open it. + */ + + return 0; +} + /* * Set or clear the multicast filter for this adaptor. * num_addrs == -1 Promiscuous mode, receive all packets. @@ -993,19 +1012,22 @@ static void __init ether1_banner(void) printk(KERN_INFO "%s", version); } -static struct net_device * __init ether1_init_one(struct expansion_card *ec) +static int __devinit +ether1_probe(struct expansion_card *ec, const struct ecard_id *id) { struct net_device *dev; struct ether1_priv *priv; - int i; + int i, ret = 0; ether1_banner(); ecard_claim(ec); dev = init_etherdev(NULL, sizeof(struct ether1_priv)); - if (!dev) + if (!dev) { + ret = -ENOMEM; goto out; + } SET_MODULE_OWNER(dev); @@ -1019,8 +1041,10 @@ static struct net_device * __init ether1_init_one(struct expansion_card *ec) request_region(dev->base_addr + 0x800, 4096, dev->name); priv = (struct ether1_priv *)dev->priv; - if ((priv->bus_type = ether1_reset(dev)) == 0) + if ((priv->bus_type = ether1_reset(dev)) == 0) { + ret = -ENODEV; goto release; + } printk(KERN_INFO "%s: ether1 in slot %d, ", dev->name, ec->slot_no); @@ -1030,16 +1054,21 @@ static struct net_device * __init ether1_init_one(struct expansion_card *ec) printk ("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); } - if (ether1_init_2(dev)) + if (ether1_init_2(dev)) { + ret = -ENODEV; goto release; + } dev->open = ether1_open; dev->stop = ether1_close; dev->hard_start_xmit = ether1_sendpacket; dev->get_stats = ether1_getstats; dev->set_multicast_list = ether1_setmulticastlist; + dev->set_mac_address = ether1_set_mac_address; dev->tx_timeout = ether1_timeout; dev->watchdog_timeo = 5 * HZ / 100; + + ecard_set_drvdata(ec, dev); return 0; release: @@ -1049,55 +1078,46 @@ release: kfree(dev); out: ecard_release(ec); - return dev; + return ret; } -static struct expansion_card *e_card[MAX_ECARDS]; -static struct net_device *e_dev[MAX_ECARDS]; - -static int __init ether1_init(void) +static void __devexit ether1_remove(struct expansion_card *ec) { - int i, ret = -ENODEV; + struct net_device *dev = ecard_get_drvdata(ec); - ecard_startfind(); + ecard_set_drvdata(ec, NULL); - for (i = 0; i < MAX_ECARDS; i++) { - struct expansion_card *ec; - struct net_device *dev; + unregister_netdev(dev); - ec = ecard_find(0, ether1_cids); - if (!ec) - break; + release_region(dev->base_addr, 16); + release_region(dev->base_addr + 0x800, 4096); + kfree(dev); - dev = ether1_init_one(ec); - if (!dev) - break; + ecard_release(ec); +} - e_card[i] = ec; - e_dev[i] = dev; - ret = 0; - } +static const struct ecard_id ether1_ids[] = { + { MANU_ACORN, PROD_ACORN_ETHER1 }, + { 0xffff, 0xffff } +}; - return ret; +static struct ecard_driver ether1_driver = { + .probe = ether1_probe, + .remove = __devexit_p(ether1_remove), + .id_table = ether1_ids, + .drv = { + .name = "ether1", + }, +}; + +static int __init ether1_init(void) +{ + return ecard_register_driver(ðer1_driver); } static void __exit ether1_exit(void) { - int i; - - for (i = 0; i < MAX_ECARDS; i++) { - if (e_dev[i]) { - unregister_netdev(e_dev[i]); - release_region(e_dev[i]->base_addr, 16); - release_region(e_dev[i]->base_addr + 0x800, 4096); - kfree(e_dev[i]); - e_dev[i] = NULL; - } - if (e_card[i]) { - ecard_release(e_card[i]); - e_card[i] = NULL; - } - } + ecard_remove_driver(ðer1_driver); } module_init(ether1_init); diff --git a/drivers/acorn/net/ether3.c b/drivers/acorn/net/ether3.c index 4f5dac26ad4d..1300a42e2b03 100644 --- a/drivers/acorn/net/ether3.c +++ b/drivers/acorn/net/ether3.c @@ -61,6 +61,7 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> +#include <linux/device.h> #include <linux/init.h> #include <linux/delay.h> @@ -75,12 +76,6 @@ static char version[] __initdata = "ether3 ethernet driver (c) 1995-2000 R.M.Kin #include "ether3.h" static unsigned int net_debug = NET_DEBUG; -static const card_ids __init ether3_cids[] = { - { MANU_ANT2, PROD_ANT_ETHER3 }, - { MANU_ANT, PROD_ANT_ETHER3 }, - { MANU_ANT, PROD_ANT_ETHERB }, - { 0xffff, 0xffff } -}; static void ether3_setmulticastlist(struct net_device *dev); static int ether3_rx(struct net_device *dev, struct dev_priv *priv, unsigned int maxcnt); @@ -417,6 +412,12 @@ ether3_probe_bus_16(struct net_device *dev, int val) static int ether3_open(struct net_device *dev) { + if (!is_valid_ether_addr(dev->dev_addr)) { + printk(KERN_WARNING "%s: invalid ethernet MAC address\n", + dev->name); + return -EINVAL; + } + if (request_irq(dev->irq, ether3_interrupt, 0, "ether3", dev)) return -EAGAIN; @@ -460,6 +461,23 @@ static struct net_device_stats *ether3_getstats(struct net_device *dev) return &priv->stats; } +static int +ether3_set_mac_address(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + + if (netif_running(dev)) + return -EBUSY; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + /* + * We'll set the MAC address on the chip when we open it. + */ + + return 0; +} + /* * Set or clear promiscuous/multicast mode filter for this adaptor. * @@ -784,6 +802,7 @@ static const char * __init ether3_get_dev(struct net_device *dev, struct expansion_card *ec) { const char *name = "ether3"; + dev->base_addr = ecard_address(ec, ECARD_MEMC, 0); dev->irq = ec->irq; @@ -796,38 +815,44 @@ ether3_get_dev(struct net_device *dev, struct expansion_card *ec) ec->irqaddr = (volatile unsigned char *)ioaddr(dev->base_addr); ec->irqmask = 0xf0; - if (ether3_addr(dev->dev_addr, ec)) - name = NULL; + ether3_addr(dev->dev_addr, ec); return name; } -static struct net_device * __init ether3_init_one(struct expansion_card *ec) +static int __devinit +ether3_probe(struct expansion_card *ec, const struct ecard_id *id) { struct net_device *dev; struct dev_priv *priv; const char *name; - int i, bus_type; + int i, bus_type, ret; ether3_banner(); ecard_claim(ec); dev = init_etherdev(NULL, sizeof(struct dev_priv)); - if (!dev) + if (!dev) { + ret = -ENOMEM; goto out; + } SET_MODULE_OWNER(dev); name = ether3_get_dev(dev, ec); - if (!name) + if (!name) { + ret = -ENODEV; goto free; + } /* * this will not fail - the nature of the bus ensures this */ - if (!request_region(dev->base_addr, 128, dev->name)) + if (!request_region(dev->base_addr, 128, dev->name)) { + ret = -EBUSY; goto free; + } priv = (struct dev_priv *) dev->priv; @@ -852,11 +877,13 @@ static struct net_device * __init ether3_init_one(struct expansion_card *ec) switch (bus_type) { case BUS_UNKNOWN: printk(KERN_ERR "%s: unable to identify bus width\n", dev->name); + ret = -ENODEV; goto failed; case BUS_8: printk(KERN_ERR "%s: %s found, but is an unsupported " "8-bit card\n", dev->name, name); + ret = -ENODEV; goto failed; default: @@ -867,16 +894,21 @@ static struct net_device * __init ether3_init_one(struct expansion_card *ec) for (i = 0; i < 6; i++) printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); - if (ether3_init_2(dev)) + if (ether3_init_2(dev)) { + ret = -ENODEV; goto failed; + } dev->open = ether3_open; dev->stop = ether3_close; dev->hard_start_xmit = ether3_sendpacket; dev->get_stats = ether3_getstats; dev->set_multicast_list = ether3_setmulticastlist; + dev->set_mac_address = ether3_set_mac_address; dev->tx_timeout = ether3_timeout; dev->watchdog_timeo = 5 * HZ / 100; + + ecard_set_drvdata(ec, dev); return 0; failed: @@ -886,54 +918,46 @@ free: kfree(dev); out: ecard_release(ec); - return NULL; + return ret; } -static struct expansion_card *e_card[MAX_ECARDS]; -static struct net_device *e_dev[MAX_ECARDS]; - -static int ether3_init(void) +static void __devexit ether3_remove(struct expansion_card *ec) { - int i, ret = -ENODEV; + struct net_device *dev = ecard_get_drvdata(ec); - ecard_startfind(); + ecard_set_drvdata(ec, NULL); - for (i = 0; i < MAX_ECARDS; i++) { - struct net_device *dev; - struct expansion_card *ec; + unregister_netdev(dev); + release_region(dev->base_addr, 128); + kfree(dev); - ec = ecard_find(0, ether3_cids); - if (!ec) - break; + ecard_release(ec); +} - dev = ether3_init_one(ec); - if (!dev) - break; +static const struct ecard_id ether3_ids[] = { + { MANU_ANT2, PROD_ANT_ETHER3 }, + { MANU_ANT, PROD_ANT_ETHER3 }, + { MANU_ANT, PROD_ANT_ETHERB }, + { 0xffff, 0xffff } +}; - e_card[i] = ec; - e_dev[i] = dev; - ret = 0; - } +static struct ecard_driver ether3_driver = { + .probe = ether3_probe, + .remove = __devexit_p(ether3_remove), + .id_table = ether3_ids, + .drv = { + .name = "ether3", + }, +}; - return ret; +static int __init ether3_init(void) +{ + return ecard_register_driver(ðer3_driver); } -static void ether3_exit(void) +static void __exit ether3_exit(void) { - int i; - - for (i = 0; i < MAX_ECARDS; i++) { - if (e_dev[i]) { - unregister_netdev(e_dev[i]); - release_region(e_dev[i]->base_addr, 128); - kfree(e_dev[i]); - e_dev[i] = NULL; - } - if (e_card[i]) { - ecard_release(e_card[i]); - e_card[i] = NULL; - } - } + ecard_remove_driver(ðer3_driver); } module_init(ether3_init); diff --git a/drivers/acorn/net/etherh.c b/drivers/acorn/net/etherh.c index 2a36107257dd..4ffe92dd478f 100644 --- a/drivers/acorn/net/etherh.c +++ b/drivers/acorn/net/etherh.c @@ -42,6 +42,7 @@ #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/delay.h> +#include <linux/device.h> #include <linux/init.h> #include <asm/system.h> @@ -57,14 +58,6 @@ static unsigned int net_debug = NET_DEBUG; -static const card_ids __init etherh_cids[] = { - { MANU_ANT, PROD_ANT_ETHERM }, - { MANU_I3, PROD_I3_ETHERLAN500 }, - { MANU_I3, PROD_I3_ETHERLAN600 }, - { MANU_I3, PROD_I3_ETHERLAN600A }, - { 0xffff, 0xffff } -}; - struct etherh_priv { struct ei_device eidev; unsigned int id; @@ -441,6 +434,12 @@ etherh_open(struct net_device *dev) { struct ei_device *ei_local = (struct ei_device *) dev->priv; + if (!is_valid_ether_addr(dev->dev_addr)) { + printk(KERN_WARNING "%s: invalid ethernet MAC address\n", + dev->name); + return -EINVAL; + } + if (request_irq(dev->irq, ei_interrupt, 0, dev->name, dev)) return -EAGAIN; @@ -483,6 +482,23 @@ etherh_close(struct net_device *dev) return 0; } +static int +etherh_set_mac_address(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + + if (netif_running(dev)) + return -EBUSY; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + /* + * We'll set the MAC address on the chip when we open it. + */ + + return 0; +} + /* * Initialisation */ @@ -541,21 +557,24 @@ static int __init etherm_addr(char *addr) static u32 etherh_regoffsets[16]; static u32 etherm_regoffsets[16]; -static struct net_device * __init etherh_init_one(struct expansion_card *ec) +static int __init +etherh_probe(struct expansion_card *ec, const struct ecard_id *id) { struct ei_device *ei_local; struct net_device *dev; struct etherh_priv *eh; const char *dev_type; - int i, size; + int i, size, ret; etherh_banner(); ecard_claim(ec); dev = init_etherdev(NULL, sizeof(struct etherh_priv)); - if (!dev) + if (!dev) { + ret = -ENOMEM; goto out; + } /* * init_etherdev allocs and zeros dev->priv @@ -566,33 +585,33 @@ static struct net_device * __init etherh_init_one(struct expansion_card *ec) SET_MODULE_OWNER(dev); - dev->open = etherh_open; - dev->stop = etherh_close; - dev->set_config = etherh_set_config; - dev->irq = ec->irq; - dev->base_addr = ecard_address(ec, ECARD_MEMC, 0); - dev->priv = eh; + dev->open = etherh_open; + dev->stop = etherh_close; + dev->set_mac_address = etherh_set_mac_address; + dev->set_config = etherh_set_config; + dev->irq = ec->irq; + dev->base_addr = ecard_address(ec, ECARD_MEMC, 0); /* * IRQ and control port handling */ - ec->ops = ðerh_ops; - ec->irq_data = eh; - eh->ctrl = 0; - eh->id = ec->cid.product; + if (ec->irq != 11) { + ec->ops = ðerh_ops; + ec->irq_data = eh; + } + eh->ctrl = 0; + eh->id = ec->cid.product; switch (ec->cid.product) { case PROD_ANT_ETHERM: - if (etherm_addr(dev->dev_addr)) - goto free; + etherm_addr(dev->dev_addr); dev->base_addr += ETHERM_NS8390; dev->mem_start = dev->base_addr + ETHERM_DATAPORT; eh->ctrl_port = dev->base_addr + ETHERM_CTRLPORT; break; case PROD_I3_ETHERLAN500: - if (etherh_addr(dev->dev_addr, ec)) - goto free; + etherh_addr(dev->dev_addr, ec); dev->base_addr += ETHERH500_NS8390; dev->mem_start = dev->base_addr + ETHERH500_DATAPORT; eh->ctrl_port = ecard_address (ec, ECARD_IOC, ECARD_FAST) @@ -601,8 +620,7 @@ static struct net_device * __init etherh_init_one(struct expansion_card *ec) case PROD_I3_ETHERLAN600: case PROD_I3_ETHERLAN600A: - if (etherh_addr(dev->dev_addr, ec)) - goto free; + etherh_addr(dev->dev_addr, ec); dev->base_addr += ETHERH600_NS8390; dev->mem_start = dev->base_addr + ETHERH600_DATAPORT; eh->ctrl_port = dev->base_addr + ETHERH600_CTRLPORT; @@ -611,6 +629,7 @@ static struct net_device * __init etherh_init_one(struct expansion_card *ec) default: printk(KERN_ERR "%s: unknown card type %x\n", dev->name, ec->cid.product); + ret = -ENODEV; goto free; } @@ -618,11 +637,15 @@ static struct net_device * __init etherh_init_one(struct expansion_card *ec) if (ec->cid.product == PROD_ANT_ETHERM) size <<= 3; - if (!request_region(dev->base_addr, size, dev->name)) + if (!request_region(dev->base_addr, size, dev->name)) { + ret = -EBUSY; goto free; + } - if (ethdev_init(dev)) + if (ethdev_init(dev)) { + ret = -ENODEV; goto release; + } /* * If we're in the NIC slot, make sure the IRQ is enabled @@ -690,7 +713,10 @@ static struct net_device * __init etherh_init_one(struct expansion_card *ec) etherh_reset(dev); NS8390_init(dev, 0); - return dev; + + ecard_set_drvdata(ec, dev); + + return 0; release: release_region(dev->base_addr, 16); @@ -700,67 +726,59 @@ free: kfree(dev); out: ecard_release(ec); - return NULL; + return ret; +} + +static void __devexit etherh_remove(struct expansion_card *ec) +{ + struct net_device *dev = ecard_get_drvdata(ec); + int size = 16; + + ecard_set_drvdata(ec, NULL); + + unregister_netdev(dev); + if (ec->cid.product == PROD_ANT_ETHERM) + size <<= 3; + release_region(dev->base_addr, size); + kfree(dev); + + ec->ops = NULL; + kfree(ec->irq_data); + ecard_release(ec); } -#define MAX_ETHERH_CARDS 2 +static const struct ecard_id etherh_ids[] = { + { MANU_ANT, PROD_ANT_ETHERM }, + { MANU_I3, PROD_I3_ETHERLAN500 }, + { MANU_I3, PROD_I3_ETHERLAN600 }, + { MANU_I3, PROD_I3_ETHERLAN600A }, + { 0xffff, 0xffff } +}; -static struct net_device *e_dev[MAX_ETHERH_CARDS]; -static struct expansion_card *e_card[MAX_ETHERH_CARDS]; +static struct ecard_driver etherh_driver = { + .probe = etherh_probe, + .remove = __devexit_p(etherh_remove), + .id_table = etherh_ids, + .drv = { + .name = "etherh", + }, +}; static int __init etherh_init(void) { - int i, ret = -ENODEV; + int i; for (i = 0; i < 16; i++) { etherh_regoffsets[i] = i; etherm_regoffsets[i] = i << 3; } - ecard_startfind(); - - for (i = 0; i < MAX_ECARDS; i++) { - struct expansion_card *ec; - struct net_device *dev; - - ec = ecard_find(0, etherh_cids); - if (!ec) - break; - - dev = etherh_init_one(ec); - if (!dev) - break; - - e_card[i] = ec; - e_dev[i] = dev; - ret = 0; - } - - return ret; + return ecard_register_driver(ðerh_driver); } static void __exit etherh_exit(void) { - int i; - - for (i = 0; i < MAX_ETHERH_CARDS; i++) { - if (e_dev[i]) { - int size; - unregister_netdev(e_dev[i]); - size = 16; - if (e_card[i]->cid.product == PROD_ANT_ETHERM) - size <<= 3; - release_region(e_dev[i]->base_addr, size); - kfree(e_dev[i]); - e_dev[i] = NULL; - } - if (e_card[i]) { - e_card[i]->ops = NULL; - kfree(e_card[i]->irq_data); - ecard_release(e_card[i]); - e_card[i] = NULL; - } - } + ecard_remove_driver(ðerh_driver); } module_init(etherh_init); diff --git a/drivers/acorn/scsi/acornscsi.c b/drivers/acorn/scsi/acornscsi.c index ba98aa489f5c..b0b8a490a214 100644 --- a/drivers/acorn/scsi/acornscsi.c +++ b/drivers/acorn/scsi/acornscsi.c @@ -319,12 +319,12 @@ acornscsi_csdelay(unsigned int cs) target_jiffies = jiffies + 1 + cs * HZ / 100; - save_flags(flags); - sti(); + local_save_flags(flags); + local_irq_enable(); while (time_before(jiffies, target_jiffies)) barrier(); - restore_flags(flags); + local_irq_restore(flags); } static @@ -403,8 +403,9 @@ void acornscsi_resetcard(AS_Host *host) host->scsi.phase = PHASE_IDLE; host->scsi.disconnectable = 0; + memset(host->busyluns, 0, sizeof(host->busyluns)); + for (i = 0; i < 8; i++) { - host->busyluns[i] = 0; host->device[i].sync_state = SYNC_NEGOCIATE; host->device[i].disconnect_ok = 1; } @@ -1593,7 +1594,7 @@ void acornscsi_message(AS_Host *host) printk(KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n", host->host->host_no, acornscsi_target(host)); host->SCpnt->device->tagged_queue = 0; - set_bit(host->SCpnt->target * 8 + host->SCpnt->lun, &host->busyluns); + set_bit(host->SCpnt->target * 8 + host->SCpnt->lun, host->busyluns); break; #endif case EXTENDED_MESSAGE | (EXTENDED_SDTR << 8): @@ -2637,8 +2638,7 @@ acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt) printk("executing "); //#endif - save_flags(flags); - cli(); + local_irq_save(flags); switch (host->scsi.phase) { /* * If the interface is idle, and the command is 'disconnectable', @@ -2671,7 +2671,7 @@ acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt) acornscsi_abortcmd(host, host->SCpnt->tag); res = res_snooze; } - restore_flags(flags); + local_irq_restore(flags); } else if (host->origSCpnt == SCpnt) { /* * The command will be executed next, but a command diff --git a/drivers/acorn/scsi/acornscsi.h b/drivers/acorn/scsi/acornscsi.h index 191d16af8c45..457929b24925 100644 --- a/drivers/acorn/scsi/acornscsi.h +++ b/drivers/acorn/scsi/acornscsi.h @@ -326,7 +326,7 @@ typedef struct acornscsi_hostdata { syncxfer_t sync_state; /* sync xfer negociation state */ unsigned char disconnect_ok:1; /* device can disconnect */ } device[8]; - unsigned char busyluns[8]; /* array of bits indicating LUNs busy */ + unsigned long busyluns[64 / sizeof(unsigned long)];/* array of bits indicating LUNs busy */ /* DMA info */ struct { diff --git a/drivers/acorn/scsi/cumana_1.c b/drivers/acorn/scsi/cumana_1.c index 4e9e68960782..bb9e6d66daaf 100644 --- a/drivers/acorn/scsi/cumana_1.c +++ b/drivers/acorn/scsi/cumana_1.c @@ -83,11 +83,9 @@ static const card_ids cumanascsi_cids[] = { #define NCR5380_read(reg) cumanascsi_read(_instance, reg) #define NCR5380_write(reg, value) cumanascsi_write(_instance, reg, value) -#define do_NCR5380_intr do_cumanascsi_intr -#define NCR5380_queue_command cumanascsi_queue_command -#define NCR5380_abort cumanascsi_abort -#define NCR5380_reset cumanascsi_reset -#define NCR5380_proc_info cumanascsi_proc_info +#define NCR5380_intr cumanascsi_intr +#define NCR5380_queue_command cumanascsi_queue_command +#define NCR5380_proc_info cumanascsi_proc_info int NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); @@ -159,7 +157,7 @@ int cumanascsi_detect(Scsi_Host_Template * tpnt) outb(0x00, instance->io_port - 577); if (instance->irq != IRQ_NONE) - if (request_irq(instance->irq, do_cumanascsi_intr, SA_INTERRUPT, "CumanaSCSI-1", NULL)) { + if (request_irq(instance->irq, cumanascsi_intr, SA_INTERRUPT, "CumanaSCSI-1", NULL)) { printk("scsi%d: IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); instance->irq = IRQ_NONE; @@ -401,8 +399,10 @@ static Scsi_Host_Template cumanascsi_template = { .release = cumanascsi_release, .info = cumanascsi_info, .queuecommand = cumanascsi_queue_command, - .abort = cumanascsi_abort, - .reset = cumanascsi_reset, + .eh_abort_handler = NCR5380_abort, + .eh_device_reset_handler= NCR5380_device_reset, + .eh_bus_reset_handler = NCR5380_bus_reset, + .eh_host_reset_handler = NCR5380_host_reset, .bios_param = scsicam_bios_param, .can_queue = 16, .this_id = 7, diff --git a/drivers/acorn/scsi/ecoscsi.c b/drivers/acorn/scsi/ecoscsi.c index 93c2fe570177..9a8e70376295 100644 --- a/drivers/acorn/scsi/ecoscsi.c +++ b/drivers/acorn/scsi/ecoscsi.c @@ -248,11 +248,9 @@ printk("reading %p len %d\n",addr, len); #define NCR5380_read(reg) ecoscsi_read(_instance, reg) #define NCR5380_write(reg, value) ecoscsi_write(_instance, reg, value) -#define do_NCR5380_intr do_ecoscsi_intr -#define NCR5380_queue_command ecoscsi_queue_command -#define NCR5380_abort ecoscsi_abort -#define NCR5380_reset ecoscsi_reset -#define NCR5380_proc_info ecoscsi_proc_info +#define NCR5380_intr ecoscsi_intr +#define NCR5380_queue_command ecoscsi_queue_command +#define NCR5380_proc_info ecoscsi_proc_info int NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); @@ -269,8 +267,10 @@ static Scsi_Host_Template ecoscsi_template = { .release = ecoscsi_release, .info = ecoscsi_info, .queuecommand = ecoscsi_queue_command, - .abort = ecoscsi_abort, - .reset = ecoscsi_reset, + .eh_abort_handler = NCR5380_abort, + .eh_device_reset_handler= NCR5380_device_reset, + .eh_bus_reset_handler = NCR5380_bus_reset, + .eh_host_reset_handler = NCR5380_host_reset, .can_queue = 16, .this_id = 7, .sg_tablesize = SG_ALL, diff --git a/drivers/acorn/scsi/fas216.c b/drivers/acorn/scsi/fas216.c index 445c1574453d..77bd624a7b95 100644 --- a/drivers/acorn/scsi/fas216.c +++ b/drivers/acorn/scsi/fas216.c @@ -603,7 +603,7 @@ fas216_updateptrs(FAS216_Info *info, int bytes_transferred) * next buffer. */ bytes_transferred -= SCp->this_residual; - if (!next_SCp(&info->scsi.SCp)) { + if (!next_SCp(&info->scsi.SCp) && bytes_transferred) { printk(KERN_WARNING "scsi%d.%c: out of buffers\n", info->host->host_no, '0' + info->SCpnt->target); return; @@ -2300,8 +2300,8 @@ int fas216_eh_device_reset(Scsi_Cmnd *SCpnt) { FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; - printk("scsi%d.%c: "__FUNCTION__": called\n", - info->host->host_no, '0' + SCpnt->target); + printk("scsi%d.%c: %s: called\n", + info->host->host_no, '0' + SCpnt->target, __FUNCTION__); return FAILED; } @@ -2320,8 +2320,8 @@ int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt) info->stats.bus_resets += 1; - printk("scsi%d.%c: "__FUNCTION__": resetting bus\n", - info->host->host_no, '0' + SCpnt->target); + printk("scsi%d.%c: %s: resetting bus\n", + info->host->host_no, '0' + SCpnt->target, __FUNCTION__); /* * Attempt to stop all activity on this interface. @@ -2381,8 +2381,8 @@ int fas216_eh_host_reset(Scsi_Cmnd *SCpnt) fas216_checkmagic(info); - printk("scsi%d.%c: "__FUNCTION__": resetting host\n", - info->host->host_no, '0' + SCpnt->target); + printk("scsi%d.%c: %s: resetting host\n", + info->host->host_no, '0' + SCpnt->target, __FUNCTION__); /* * Reset the SCSI chip. diff --git a/drivers/acorn/scsi/fas216.h b/drivers/acorn/scsi/fas216.h index a5b107182873..7d11ef613dc2 100644 --- a/drivers/acorn/scsi/fas216.h +++ b/drivers/acorn/scsi/fas216.h @@ -288,7 +288,7 @@ typedef struct { neg_t sync_state; /* synchronous transfer mode */ neg_t wide_state; /* wide transfer mode */ } device[8]; - unsigned char busyluns[8]; /* array of bits indicating LUNs busy */ + unsigned long busyluns[64/sizeof(unsigned long)];/* array of bits indicating LUNs busy */ /* dma */ struct { diff --git a/drivers/acorn/scsi/oak.c b/drivers/acorn/scsi/oak.c index 409efb4084c0..922deb68a7cf 100644 --- a/drivers/acorn/scsi/oak.c +++ b/drivers/acorn/scsi/oak.c @@ -64,10 +64,8 @@ #define NCR5380_read(reg) oakscsi_read(_instance, reg) #define NCR5380_write(reg, value) oakscsi_write(_instance, reg, value) -#define do_NCR5380_intr do_oakscsi_intr +#define NCR5380_intr oakscsi_intr #define NCR5380_queue_command oakscsi_queue_command -#define NCR5380_abort oakscsi_abort -#define NCR5380_reset oakscsi_reset #define NCR5380_proc_info oakscsi_proc_info int NCR5380_proc_info(char *buffer, char **start, off_t offset, @@ -142,7 +140,7 @@ int oakscsi_detect(Scsi_Host_Template * tpnt) } if (instance->irq != IRQ_NONE) - if (request_irq(instance->irq, do_oakscsi_intr, SA_INTERRUPT, "Oak SCSI", NULL)) { + if (request_irq(instance->irq, oakscsi_intr, SA_INTERRUPT, "Oak SCSI", NULL)) { printk("scsi%d: IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); instance->irq = IRQ_NONE; @@ -264,8 +262,10 @@ static Scsi_Host_Template oakscsi_template = { .release = oakscsi_release, .info = oakscsi_info, .queuecommand = oakscsi_queue_command, - .abort = oakscsi_abort, - .reset = oakscsi_reset, + .eh_abort_handler = NCR5380_abort, + .eh_device_reset_handler= NCR5380_device_reset, + .eh_bus_reset_handler = NCR5380_bus_reset, + .eh_host_reset_handler = NCR5380_host_reset, .can_queue = 16, .this_id = 7, .sg_tablesize = SG_ALL, diff --git a/drivers/acorn/scsi/queue.c b/drivers/acorn/scsi/queue.c index 127bbb59f9fa..82e247e1fb16 100644 --- a/drivers/acorn/scsi/queue.c +++ b/drivers/acorn/scsi/queue.c @@ -161,7 +161,7 @@ static Scsi_Cmnd *__queue_remove(Queue_t *queue, struct list_head *ent) * exclude - bit array of target&lun which is busy * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available */ -Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, void *exclude) +Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude) { unsigned long flags; struct list_head *l; diff --git a/drivers/acorn/scsi/queue.h b/drivers/acorn/scsi/queue.h index 08f5c4697d75..508b42ec7a1e 100644 --- a/drivers/acorn/scsi/queue.h +++ b/drivers/acorn/scsi/queue.h @@ -46,7 +46,7 @@ extern Scsi_Cmnd *queue_remove (Queue_t *queue); * exclude - array of busy LUNs * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available */ -extern Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, void *exclude); +extern Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, unsigned long *exclude); #define queue_add_cmd_ordered(queue,SCpnt) \ __queue_add(queue,SCpnt,(SCpnt)->cmnd[0] == REQUEST_SENSE) diff --git a/drivers/acorn/scsi/scsi.h b/drivers/acorn/scsi/scsi.h index fe4e8c80a04a..f9c6c5869a6c 100644 --- a/drivers/acorn/scsi/scsi.h +++ b/drivers/acorn/scsi/scsi.h @@ -51,7 +51,7 @@ static inline int next_SCp(Scsi_Pointer *SCp) static inline unsigned char get_next_SCp_byte(Scsi_Pointer *SCp) { - char c = SCp->ptr; + char c = *SCp->ptr; SCp->ptr += 1; SCp->this_residual -= 1; @@ -63,7 +63,7 @@ static inline unsigned char get_next_SCp_byte(Scsi_Pointer *SCp) static inline void put_next_SCp_byte(Scsi_Pointer *SCp, unsigned char c) { - SCp->ptr = c; + *SCp->ptr = c; SCp->ptr += 1; SCp->this_residual -= 1; if (SCp->this_residual == 0) diff --git a/drivers/block/Config.in b/drivers/block/Config.in index 6d2d99d8124c..49ba18434d92 100644 --- a/drivers/block/Config.in +++ b/drivers/block/Config.in @@ -49,7 +49,6 @@ fi dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM if [ "$CONFIG_X86" = "y" -o "$CONFIG_PPC32" = "y" ]; then -# bool 'Support for Large Block Devices' CONFIG_LBD - define_bool CONFIG_LBD y + bool 'Support for Large Block Devices' CONFIG_LBD fi endmenu diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 276189c6957a..ea56c1d8456c 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -1878,7 +1878,7 @@ end_io: */ int submit_bio(int rw, struct bio *bio) { - int count = bio_sectors(bio) >> 1; + int count = bio_sectors(bio); BUG_ON(!bio->bi_end_io); BIO_BUG_ON(!bio->bi_size); diff --git a/drivers/char/Config.help b/drivers/char/Config.help index acc31b2a2416..b03cd9da93b0 100644 --- a/drivers/char/Config.help +++ b/drivers/char/Config.help @@ -1033,3 +1033,24 @@ CONFIG_SCx200_GPIO If compiled as a module, it will be called scx200_gpio.o. +Texas Instruments parallel link cable support +CONFIG_TIPAR + If you own a Texas Instruments graphing calculator and use a + parallel link cable, then you might be interested in this driver. + + If you enable this driver, you will be able to communicate with + your calculator through a set of device nodes under /dev. The + main advantage of this driver is that you don't have to be root + to use this precise link cable (depending on the permissions on + the device nodes, though). + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called tipar.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + If you don't know what a parallel link cable is or what a Texas + Instruments graphing calculator is, then you probably don't need this + driver. + + If unsure, say N.
\ No newline at end of file diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 680bafe4ca4a..84eec6579e76 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -80,6 +80,7 @@ if [ "$CONFIG_PARPORT" != "n" ]; then bool ' Support for console on line printer' CONFIG_LP_CONSOLE fi dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT + dep_tristate 'Texas Instruments parallel link cable support' CONFIG_TIPAR $CONFIG_PARPORT fi if [ "$CONFIG_PPC_PSERIES" = "y" ]; then bool 'pSeries Hypervisor Virtual Console support' CONFIG_HVC_CONSOLE diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 80a28ced908c..d0be4dd0e8cb 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_PRINTER) += lp.o +obj-$(CONFIG_TIPAR) += tipar.o obj-$(CONFIG_BUSMOUSE) += busmouse.o obj-$(CONFIG_DTLK) += dtlk.o diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c index 365fc0b59d1e..06801b2dc8df 100644 --- a/drivers/char/n_r3964.c +++ b/drivers/char/n_r3964.c @@ -1126,7 +1126,7 @@ static int r3964_open(struct tty_struct *tty) tty->disc_data = pInfo; - INIT_LIST_HEAD(&pInfo->tmr.list); + init_timer(&pInfo->tmr); pInfo->tmr.data = (unsigned long)pInfo; pInfo->tmr.function = on_timeout; diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c new file mode 100644 index 000000000000..16adba7c4148 --- /dev/null +++ b/drivers/char/tipar.c @@ -0,0 +1,541 @@ +/* Hey EMACS -*- linux-c -*- + * + * tipar - low level driver for handling a parallel link cable designed + * for Texas Instruments graphing calculators (http://lpg.ticalc.org). + * A part of the TiLP project. + * + * Copyright (C) 2000-2002, Romain Lievin <roms@lpg.ticalc.org> + * under the terms of the GNU General Public License. + * + * Various fixes & clean-up from the Linux Kernel Mailing List + * (Alan Cox, Richard B. Johnson, Christoph Hellwig). + */ + +/* This driver should, in theory, work with any parallel port that has an + * appropriate low-level driver; all I/O is done through the parport + * abstraction layer. + * + * If this driver is built into the kernel, you can configure it using the + * kernel command-line. For example: + * + * tipar=timeout,delay (set timeout and delay) + * + * If the driver is loaded as a module, similar functionality is available + * using module parameters. The equivalent of the above commands would be: + * + * # insmod tipar timeout=15 delay=10 + */ + +/* COMPATIBILITY WITH OLD KERNELS + * + * Usually, parallel cables were bound to ports at + * particular I/O addresses, as follows: + * + * tipar0 0x378 + * tipar1 0x278 + * tipar2 0x3bc + * + * + * This driver, by default, binds tipar devices according to parport and + * the minor number. + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/fcntl.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <asm/uaccess.h> +#include <linux/ioport.h> +#include <asm/io.h> +#include <asm/bitops.h> +#include <linux/devfs_fs_kernel.h> /* DevFs support */ +#include <linux/parport.h> /* Our code depend on parport */ + +/* + * TI definitions + */ +#include <linux/ticable.h> + +/* + * Version Information + */ +#define DRIVER_VERSION "1.17" +#define DRIVER_AUTHOR "Romain Lievin <roms@lpg.ticalc.org>" +#define DRIVER_DESC "Device driver for TI/PC parallel link cables" +#define DRIVER_LICENSE "GPL" + +#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq)) +#if LINUX_VERSION_CODE < VERSION(2,5,0) +# define minor(x) MINOR(x) +# define need_resched() (current->need_resched) +#endif + +/* ----- global variables --------------------------------------------- */ + +struct tipar_struct { + struct pardevice *dev; /* Parport device entry */ +}; + +#define PP_NO 3 +static struct tipar_struct table[PP_NO]; + +static int delay = IO_DELAY; /* inter-bit delay in microseconds */ +static int timeout = TIMAXTIME; /* timeout in tenth of seconds */ + +static devfs_handle_t devfs_handle; +static unsigned int tp_count; /* tipar count */ +static unsigned long opened; /* opened devices */ + +/* --- macros for parport access -------------------------------------- */ + +#define r_dtr(x) (parport_read_data(table[(x)].dev->port)) +#define r_str(x) (parport_read_status(table[(x)].dev->port)) +#define w_ctr(x,y) (parport_write_control(table[(x)].dev->port, (y))) +#define w_dtr(x,y) (parport_write_data(table[(x)].dev->port, (y))) + +/* --- setting states on the D-bus with the right timing: ------------- */ + +static inline void +outbyte(int value, int minor) +{ + w_dtr(minor, value); +} + +static inline int +inbyte(int minor) +{ + return (r_str(minor)); +} + +static inline void +init_ti_parallel(int minor) +{ + outbyte(3, minor); +} + +/* ----- global defines ----------------------------------------------- */ + +#define START(x) { x=jiffies+HZ/(timeout/10); } +#define WAIT(x) { \ + if (time_before((x), jiffies)) return -1; \ + if (need_resched()) schedule(); } + +/* ----- D-bus bit-banging functions ---------------------------------- */ + +/* D-bus protocol (45kbit/s max): + 1 0 0 + _______ ______|______ __________|________ __________ +Red : ________ | ____ | ____ + _ ____________|________ ______|__________ _____ +White: ________ | ______ | _______ +*/ + +/* Try to transmit a byte on the specified port (-1 if error). */ +static int +put_ti_parallel(int minor, unsigned char data) +{ + int bit; + unsigned long max; + + for (bit = 0; bit < 8; bit++) { + if (data & 1) { + outbyte(2, minor); + START(max); + do { + WAIT(max); + } while (inbyte(minor) & 0x10); + + outbyte(3, minor); + START(max); + do { + WAIT(max); + } while (!(inbyte(minor) & 0x10)); + } else { + outbyte(1, minor); + START(max); + do { + WAIT(max); + } while (inbyte(minor) & 0x20); + + outbyte(3, minor); + START(max); + do { + WAIT(max); + } while (!(inbyte(minor) & 0x20)); + } + + data >>= 1; + udelay(delay); + + if (need_resched()) + schedule(); + } + + return 0; +} + +/* Receive a byte on the specified port or -1 if error. */ +static int +get_ti_parallel(int minor) +{ + int bit; + unsigned char v, data = 0; + unsigned long max; + + for (bit = 0; bit < 8; bit++) { + START(max); + do { + WAIT(max); + } while ((v = inbyte(minor) & 0x30) == 0x30); + + if (v == 0x10) { + data = (data >> 1) | 0x80; + outbyte(1, minor); + START(max); + do { + WAIT(max); + } while (!(inbyte(minor) & 0x20)); + outbyte(3, minor); + } else { + data = data >> 1; + outbyte(2, minor); + START(max); + do { + WAIT(max); + } while (!(inbyte(minor) & 0x10)); + outbyte(3, minor); + } + + udelay(delay); + if (need_resched()) + schedule(); + } + + return (int) data; +} + +/* Try to detect a parallel link cable on the specified port */ +static int +probe_ti_parallel(int minor) +{ + int i; + int seq[] = { 0x00, 0x20, 0x10, 0x30 }; + + for (i = 3; i >= 0; i--) { + outbyte(3, minor); + outbyte(i, minor); + udelay(delay); + /*printk(KERN_DEBUG "Probing -> %i: 0x%02x 0x%02x\n", i, data & 0x30, seq[i]); */ + if ((inbyte(minor) & 0x30) != seq[i]) { + outbyte(3, minor); + return -1; + } + } + + outbyte(3, minor); + return 0; +} + +/* ----- kernel module functions--------------------------------------- */ + +static int +tipar_open(struct inode *inode, struct file *file) +{ + unsigned int minor = minor(inode->i_rdev) - TIPAR_MINOR; + + if (minor > tp_count - 1) + return -ENXIO; + + if (test_and_set_bit(minor, &opened)) + return -EBUSY; + + parport_claim_or_block(table[minor].dev); + init_ti_parallel(minor); + parport_release(table[minor].dev); + + return 0; +} + +static int +tipar_close(struct inode *inode, struct file *file) +{ + unsigned int minor = minor(inode->i_rdev) - TIPAR_MINOR; + + if (minor > tp_count - 1) + return -ENXIO; + + clear_bit(minor, &opened); + + return 0; +} + +static ssize_t +tipar_write(struct file *file, const char *buf, size_t count, loff_t * ppos) +{ + unsigned int minor = + minor(file->f_dentry->d_inode->i_rdev) - TIPAR_MINOR; + ssize_t n; + + printk("_write\n"); + parport_claim_or_block(table[minor].dev); + + for (n = 0; n < count; n++) { + unsigned char b; + + if (get_user(b, buf + n)) { + n = -EFAULT; + goto out; + } + + if (put_ti_parallel(minor, b) == -1) { + init_ti_parallel(minor); + n = -ETIMEDOUT; + goto out; + } + } + out: + parport_release(table[minor].dev); + return n; +} + +static ssize_t +tipar_read(struct file *file, char *buf, size_t count, loff_t * ppos) +{ + int b = 0; + unsigned int minor = + minor(file->f_dentry->d_inode->i_rdev) - TIPAR_MINOR; + ssize_t retval = 0; + ssize_t n = 0; + + if (count == 0) + return 0; + + if (ppos != &file->f_pos) + return -ESPIPE; + + printk("_read\n"); + parport_claim_or_block(table[minor].dev); + + while (n < count) { + b = get_ti_parallel(minor); + if (b == -1) { + init_ti_parallel(minor); + retval = -ETIMEDOUT; + goto out; + } else { + if (put_user(b, ((unsigned char *) buf) + n)) { + retval = -EFAULT; + break; + } else + retval = ++n; + } + + /* Non-blocking mode : try again ! */ + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } + + /* Signal pending, try again ! */ + if (signal_pending(current)) { + retval = -ERESTARTSYS; + goto out; + } + + if (need_resched()) + schedule(); + } + + out: + parport_release(table[minor].dev); + return retval; +} + +static int +tipar_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int retval = 0; + + switch (cmd) { + case IOCTL_TIPAR_DELAY: + delay = (int)arg; //get_user(delay, &arg); + break; + case IOCTL_TIPAR_TIMEOUT: + timeout = (int)arg; //get_user(timeout, &arg); + break; + default: + retval = -ENOTTY; + break; + } + + return retval; +} + +/* ----- kernel module registering ------------------------------------ */ + +static struct file_operations tipar_fops = { + owner:THIS_MODULE, + llseek:no_llseek, + read:tipar_read, + write:tipar_write, + ioctl:tipar_ioctl, + open:tipar_open, + release:tipar_close, +}; + +/* --- initialisation code ------------------------------------- */ + +#ifndef MODULE +/* You must set these - there is no sane way to probe for this cable. + * You can use 'tipar=timeout,delay' to set these now. */ +static int __init +tipar_setup(char *str) +{ + int ints[2]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + if (ints[0] > 0) { + timeout = ints[1]; + if (ints[0] > 1) { + delay = ints[2]; + } + } + + return 1; +} +#endif + +/* + * Register our module into parport. + * Pass also 2 callbacks functions to parport: a pre-emptive function and an + * interrupt handler function (unused). + * Display a message such "tipar0: using parport0 (polling)". + */ +static int +tipar_register(int nr, struct parport *port) +{ + char name[8]; + + /* Register our module into parport */ + table[nr].dev = parport_register_device(port, "tipar", + NULL, NULL, NULL, 0, + (void *) &table[nr]); + + if (table[nr].dev == NULL) + return 1; + + /* Use devfs, tree: /dev/ticables/par/[0..2] */ + sprintf(name, "%d", nr); + printk + ("tipar: registering to devfs : major = %d, minor = %d, node = %s\n", + TISER_MAJOR, (TIPAR_MINOR + nr), name); + devfs_register(devfs_handle, name, DEVFS_FL_DEFAULT, TIPAR_MAJOR, + TIPAR_MINOR + nr, S_IFCHR | S_IRUGO | S_IWUGO, + &tipar_fops, NULL); + + /* Display informations */ + printk(KERN_INFO "tipar%d: using %s (%s).\n", nr, port->name, + (port->irq == + PARPORT_IRQ_NONE) ? "polling" : "interrupt-driven"); + + if (probe_ti_parallel(nr) != -1) + printk("tipar%d: link cable found !\n", nr); + else + printk("tipar%d: link cable not found.\n", nr); + + return 0; +} + +static void +tipar_attach(struct parport *port) +{ + if (tp_count == PP_NO) { + printk("tipar: ignoring parallel port (max. %d)\n", PP_NO); + return; + } + + if (!tipar_register(tp_count, port)) + tp_count++; +} + +static void +tipar_detach(struct parport *port) +{ + /* Nothing to do */ +} + +static struct parport_driver tipar_driver = { + "tipar", + tipar_attach, + tipar_detach, + NULL +}; + +int __init +tipar_init_module(void) +{ + printk("tipar: parallel link cable driver, version %s\n", + DRIVER_VERSION); + + if (register_chrdev(TIPAR_MAJOR, "tipar", &tipar_fops)) { + printk("tipar: unable to get major %d\n", TIPAR_MAJOR); + return -EIO; + } + + /* Use devfs with tree: /dev/ticables/par/[0..2] */ + devfs_handle = devfs_mk_dir(NULL, "ticables/par", NULL); + + if (parport_register_driver(&tipar_driver)) { + printk("tipar: unable to register with parport\n"); + return -EIO; + } + + return 0; +} + +void __exit +tipar_cleanup_module(void) +{ + unsigned int i; + + /* Unregistering module */ + parport_unregister_driver(&tipar_driver); + + devfs_unregister(devfs_handle); + unregister_chrdev(TIPAR_MAJOR, "tipar"); + + for (i = 0; i < PP_NO; i++) { + if (table[i].dev == NULL) + continue; + parport_unregister_device(table[i].dev); + } + + printk("tipar: module unloaded !\n"); +} + +/* --------------------------------------------------------------------- */ + +__setup("tipar=", tipar_setup); +module_init(tipar_init_module); +module_exit(tipar_cleanup_module); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE(DRIVER_LICENSE); + +EXPORT_NO_SYMBOLS; + +MODULE_PARM(timeout, "i"); +MODULE_PARM_DESC(timeout, "Timeout (default=1.5 seconds)"); +MODULE_PARM(delay, "i"); +MODULE_PARM_DESC(delay, "Inter-bit delay (default=10 microseconds)"); diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index fd3d89421421..012381dd73d9 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -678,7 +678,7 @@ static int cdrom_decode_status (ide_startstop_t *startstop, ide_drive_t *drive, *startstop = DRIVER(drive)->error(drive, "request sense failure", stat); return 1; - } else if (rq->flags & REQ_PC) { + } else if (rq->flags & (REQ_PC | REQ_BLOCK_PC)) { /* All other functions, except for READ. */ struct completion *wait = NULL; pc = (struct packet_command *) rq->buffer; diff --git a/drivers/media/video/bttv-risc.c b/drivers/media/video/bttv-risc.c index d63b5b48481c..ddb6f4328189 100644 --- a/drivers/media/video/bttv-risc.c +++ b/drivers/media/video/bttv-risc.c @@ -29,7 +29,6 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/pci.h> -#include <linux/iobuf.h> #include <linux/vmalloc.h> #include <linux/interrupt.h> #include <asm/page.h> diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h index c58be937f95f..01443316cf39 100644 --- a/drivers/media/video/bttvp.h +++ b/drivers/media/video/bttvp.h @@ -31,7 +31,6 @@ #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> #include <linux/videodev.h> -#include <linux/iobuf.h> #include <linux/pci.h> #include <asm/scatterlist.h> diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c index d1c783401b29..03d3bbd1356a 100644 --- a/drivers/media/video/video-buf.c +++ b/drivers/media/video/video-buf.c @@ -18,8 +18,8 @@ #include <linux/init.h> #include <linux/module.h> -#include <linux/iobuf.h> #include <linux/vmalloc.h> +#include <linux/pagemap.h> #include <linux/slab.h> #include <linux/pci.h> #include <linux/interrupt.h> @@ -65,32 +65,31 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) return NULL; } -struct scatterlist* -videobuf_iobuf_to_sg(struct kiobuf *iobuf) +struct scatterlist * +videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) { struct scatterlist *sglist; int i = 0; - - sglist = kmalloc(sizeof(struct scatterlist) * iobuf->nr_pages, - GFP_KERNEL); + + if (NULL == pages[0]) + return NULL; + sglist = kmalloc(sizeof(*sglist) * nr_pages, GFP_KERNEL); if (NULL == sglist) return NULL; - memset(sglist,0,sizeof(struct scatterlist) * iobuf->nr_pages); + memset(sglist, 0, sizeof(*sglist) * nr_pages); - if (NULL == iobuf->maplist[0]) - goto err; - if (PageHighMem(iobuf->maplist[0])) + if (PageHighMem(pages[0])) /* DMA to highmem pages might not work */ goto err; - sglist[0].page = iobuf->maplist[0]; - sglist[0].offset = iobuf->offset; - sglist[0].length = PAGE_SIZE - iobuf->offset; - for (i = 1; i < iobuf->nr_pages; i++) { - if (NULL == iobuf->maplist[i]) + sglist[0].page = pages[0]; + sglist[0].offset = offset; + sglist[0].length = PAGE_SIZE - offset; + for (i = 1; i < nr_pages; i++) { + if (NULL == pages[i]) goto err; - if (PageHighMem(iobuf->maplist[i])) + if (PageHighMem(pages[i])) goto err; - sglist[i].page = iobuf->maplist[i]; + sglist[i].page = pages[i]; sglist[i].length = PAGE_SIZE; } return sglist; @@ -100,6 +99,30 @@ videobuf_iobuf_to_sg(struct kiobuf *iobuf) return NULL; } +int videobuf_lock(struct page **pages, int nr_pages) +{ + int i; + + for (i = 0; i < nr_pages; i++) + if (TestSetPageLocked(pages[i])) + goto err; + return 0; + + err: + while (i > 0) + unlock_page(pages[--i]); + return -EINVAL; +} + +int videobuf_unlock(struct page **pages, int nr_pages) +{ + int i; + + for (i = 0; i < nr_pages; i++) + unlock_page(pages[i]); + return 0; +} + /* --------------------------------------------------------------------- */ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, @@ -113,14 +136,21 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, case PCI_DMA_TODEVICE: rw = WRITE; break; default: BUG(); } - if (0 != (err = alloc_kiovec(1,&dma->iobuf))) - return err; - if (0 != (err = map_user_kiobuf(rw, dma->iobuf, data, size))) { - dprintk(1,"map_user_kiobuf: %d\n",err); - return err; - } - dma->nr_pages = dma->iobuf->nr_pages; - return 0; + + dma->offset = data & PAGE_MASK; + dma->nr_pages = ((((data+size) & ~PAGE_MASK) - + (data & ~PAGE_MASK)) >> PAGE_SHIFT) +1; + dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*), + GFP_KERNEL); + if (NULL == dma->pages) + return -ENOMEM; + down_read(¤t->mm->mmap_sem); + err = get_user_pages(current,current->mm, + data, dma->nr_pages, + rw == READ, 0, /* don't force */ + dma->pages, NULL); + up_read(¤t->mm->mmap_sem); + return err; } int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, @@ -144,13 +174,15 @@ int videobuf_dma_pci_map(struct pci_dev *dev, struct videobuf_dmabuf *dma) if (0 == dma->nr_pages) BUG(); - if (dma->iobuf) { - if (0 != (err = lock_kiovec(1,&dma->iobuf,1))) { - dprintk(1,"lock_kiovec: %d\n",err); + if (dma->pages) { + if (0 != (err = videobuf_lock(dma->pages, dma->nr_pages))) { + dprintk(1,"videobuf_lock_pages: %d\n",err); return err; } - dma->sglist = videobuf_iobuf_to_sg(dma->iobuf); + dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages, + dma->offset); } + if (dma->vmalloc) { dma->sglist = videobuf_vmalloc_to_sg (dma->vmalloc,dma->nr_pages); @@ -160,7 +192,7 @@ int videobuf_dma_pci_map(struct pci_dev *dev, struct videobuf_dmabuf *dma) return -ENOMEM; } dma->sglen = pci_map_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); + dma->direction); return 0; } @@ -182,8 +214,8 @@ int videobuf_dma_pci_unmap(struct pci_dev *dev, struct videobuf_dmabuf *dma) kfree(dma->sglist); dma->sglist = NULL; dma->sglen = 0; - if (dma->iobuf) - unlock_kiovec(1,&dma->iobuf); + if (dma->pages) + videobuf_lock(dma->pages, dma->nr_pages); return 0; } @@ -192,11 +224,14 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma) if (dma->sglen) BUG(); - if (dma->iobuf) { - unmap_kiobuf(dma->iobuf); - free_kiovec(1,&dma->iobuf); - dma->iobuf = NULL; + if (dma->pages) { + int i; + for (i=0; i < dma->nr_pages; i++) + page_cache_release(dma->pages[i]); + kfree(dma->pages); + dma->pages = NULL; } + if (dma->vmalloc) { vfree(dma->vmalloc); dma->vmalloc = NULL; @@ -959,6 +994,7 @@ int videobuf_mmap_mapper(struct vm_area_struct *vma, map->q = q; vma->vm_ops = &videobuf_vm_ops; vma->vm_flags |= VM_DONTEXPAND; + vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */ vma->vm_private_data = map; dprintk(1,"mmap %p: %08lx-%08lx pgoff %08lx bufs %d-%d\n", map,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last); @@ -972,7 +1008,6 @@ int videobuf_mmap_mapper(struct vm_area_struct *vma, /* --------------------------------------------------------------------- */ EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg); -EXPORT_SYMBOL_GPL(videobuf_iobuf_to_sg); EXPORT_SYMBOL_GPL(videobuf_dma_init_user); EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel); diff --git a/drivers/media/video/video-buf.h b/drivers/media/video/video-buf.h index 0e2c5860b953..3d8710848ca1 100644 --- a/drivers/media/video/video-buf.h +++ b/drivers/media/video/video-buf.h @@ -28,11 +28,12 @@ struct scatterlist* videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages); /* - * Return a scatterlist for a locked iobuf (NULL on errors). Memory + * Return a scatterlist for a an array of userpages (NULL on errors). Memory * for the scatterlist is allocated using kmalloc. The caller must * free the memory. */ -struct scatterlist* videobuf_iobuf_to_sg(struct kiobuf *iobuf); +struct scatterlist *videobuf_pages_to_sg(struct page **pages, int nr_pages, + int offset); /* --------------------------------------------------------------------- */ @@ -57,7 +58,8 @@ struct scatterlist* videobuf_iobuf_to_sg(struct kiobuf *iobuf); struct videobuf_dmabuf { /* for userland buffer */ - struct kiobuf *iobuf; + struct page **pages; + int offset; /* for kernel buffers */ void *vmalloc; diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c index 0bd163307af9..23d980122df3 100644 --- a/drivers/mtd/afs.c +++ b/drivers/mtd/afs.c @@ -21,7 +21,7 @@ This is access code for flashes using ARM's flash partitioning standards. - $Id: afs.c,v 1.6 2001/10/02 10:04:51 rmk Exp $ + $Id: afs.c,v 1.8 2002/05/04 08:49:09 rmk Exp $ ======================================================================*/ @@ -82,6 +82,12 @@ afs_read_footer(struct mtd_info *mtd, u_int *img_start, u_int *iis_start, if (fs.signature != 0xa0ffff9f) ret = 1; + /* + * Don't touch the SIB. + */ + if (fs.type == 2) + ret = 1; + *iis_start = fs.image_info_base & mask; *img_start = fs.image_start & mask; @@ -163,6 +169,7 @@ int parse_afs_partitions(struct mtd_info *mtd, struct mtd_partition **pparts) if (!parts) return -ENOMEM; + memset(parts, 0, sz); str = (char *)(parts + idx); /* diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c index 0b22c6e60417..cd58f8fae012 100644 --- a/drivers/mtd/maps/integrator-flash.c +++ b/drivers/mtd/maps/integrator-flash.c @@ -21,7 +21,7 @@ This is access code for flashes using ARM's flash partitioning standards. - $Id: integrator-flash.c,v 1.6 2001/10/02 16:00:01 dwmw2 Exp $ + $Id: integrator-flash.c,v 1.7 2001/11/01 20:55:47 rmk Exp $ ======================================================================*/ @@ -208,10 +208,10 @@ static struct map_info armflash_map = }; static struct mtd_info *mtd; +static struct mtd_partition *parts; static int __init armflash_cfi_init(void *base, u_int size) { - struct mtd_partition *parts; int ret; armflash_flash_init(); @@ -238,8 +238,6 @@ static int __init armflash_cfi_init(void *base, u_int size) ret = parse_afs_partitions(mtd, &parts); if (ret > 0) { ret = add_mtd_partitions(mtd, parts, ret); - /* we don't need the partition info any longer */ - kfree(parts); if (ret) printk(KERN_ERR "mtd partition registration " "failed: %d\n", ret); @@ -262,6 +260,8 @@ static void armflash_cfi_exit(void) del_mtd_partitions(mtd); map_destroy(mtd); } + if (parts) + kfree(parts); } static int __init armflash_init(void) diff --git a/drivers/pcmcia/sa1100_adsbitsy.c b/drivers/pcmcia/sa1100_adsbitsy.c index 202524e4c354..a7f533ca5c05 100644 --- a/drivers/pcmcia/sa1100_adsbitsy.c +++ b/drivers/pcmcia/sa1100_adsbitsy.c @@ -84,14 +84,14 @@ adsbitsy_pcmcia_configure_socket(const struct pcmcia_configure *conf) } static struct pcmcia_low_level adsbitsy_pcmcia_ops = { - init: adsbitsy_pcmcia_init, - shutdown: sa1111_pcmcia_shutdown, - socket_state: sa1111_pcmcia_socket_state, - get_irq_info: sa1111_pcmcia_get_irq_info, - configure_socket: adsbitsy_pcmcia_configure_socket, - - socket_init: sa1111_pcmcia_socket_init, - socket_suspend: sa1111_pcmcia_socket_suspend, + .init = adsbitsy_pcmcia_init, + .shutdown = sa1111_pcmcia_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .get_irq_info = sa1111_pcmcia_get_irq_info, + .configure_socket = adsbitsy_pcmcia_configure_socket, + + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_adsbitsy_init(void) diff --git a/drivers/pcmcia/sa1100_assabet.c b/drivers/pcmcia/sa1100_assabet.c index eb883f64e239..494f6b625ee7 100644 --- a/drivers/pcmcia/sa1100_assabet.c +++ b/drivers/pcmcia/sa1100_assabet.c @@ -11,6 +11,7 @@ #include <linux/init.h> #include <asm/hardware.h> +#include <asm/mach-types.h> #include <asm/irq.h> #include <asm/arch/assabet.h> @@ -192,14 +193,14 @@ static int assabet_pcmcia_socket_suspend(int sock) } static struct pcmcia_low_level assabet_pcmcia_ops = { - init: assabet_pcmcia_init, - shutdown: assabet_pcmcia_shutdown, - socket_state: assabet_pcmcia_socket_state, - get_irq_info: assabet_pcmcia_get_irq_info, - configure_socket: assabet_pcmcia_configure_socket, - - socket_init: assabet_pcmcia_socket_init, - socket_suspend: assabet_pcmcia_socket_suspend, + .init = assabet_pcmcia_init, + .shutdown = assabet_pcmcia_shutdown, + .socket_state = assabet_pcmcia_socket_state, + .get_irq_info = assabet_pcmcia_get_irq_info, + .configure_socket = assabet_pcmcia_configure_socket, + + .socket_init = assabet_pcmcia_socket_init, + .socket_suspend = assabet_pcmcia_socket_suspend, }; int __init pcmcia_assabet_init(void) diff --git a/drivers/pcmcia/sa1100_badge4.c b/drivers/pcmcia/sa1100_badge4.c index 77174645d6c1..255872d64f10 100644 --- a/drivers/pcmcia/sa1100_badge4.c +++ b/drivers/pcmcia/sa1100_badge4.c @@ -146,14 +146,14 @@ badge4_pcmcia_configure_socket(const struct pcmcia_configure *conf) } static struct pcmcia_low_level badge4_pcmcia_ops = { - init: badge4_pcmcia_init, - shutdown: badge4_pcmcia_shutdown, - socket_state: sa1111_pcmcia_socket_state, - get_irq_info: sa1111_pcmcia_get_irq_info, - configure_socket: badge4_pcmcia_configure_socket, - - socket_init: sa1111_pcmcia_socket_init, - socket_suspend: sa1111_pcmcia_socket_suspend, + .init = badge4_pcmcia_init, + .shutdown = badge4_pcmcia_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .get_irq_info = sa1111_pcmcia_get_irq_info, + .configure_socket = badge4_pcmcia_configure_socket, + + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_badge4_init(void) diff --git a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c index f3142cea6deb..28c808f95d1e 100644 --- a/drivers/pcmcia/sa1100_cerf.c +++ b/drivers/pcmcia/sa1100_cerf.c @@ -11,6 +11,7 @@ #include <linux/init.h> #include <asm/hardware.h> +#include <asm/mach-types.h> #include <asm/irq.h> #include "sa1100_generic.h" @@ -160,14 +161,14 @@ static int cerf_pcmcia_socket_suspend(int sock) } static struct pcmcia_low_level cerf_pcmcia_ops = { - init: cerf_pcmcia_init, - shutdown: cerf_pcmcia_shutdown, - socket_state: cerf_pcmcia_socket_state, - get_irq_info: cerf_pcmcia_get_irq_info, - configure_socket: cerf_pcmcia_configure_socket, - - socket_init: cerf_pcmcia_socket_init, - socket_suspend: cerf_pcmcia_socket_suspend, + .init = cerf_pcmcia_init, + .shutdown = cerf_pcmcia_shutdown, + .socket_state = cerf_pcmcia_socket_state, + .get_irq_info = cerf_pcmcia_get_irq_info, + .configure_socket = cerf_pcmcia_configure_socket, + + .socket_init = cerf_pcmcia_socket_init, + .socket_suspend = cerf_pcmcia_socket_suspend, }; int __init pcmcia_cerf_init(void) diff --git a/drivers/pcmcia/sa1100_flexanet.c b/drivers/pcmcia/sa1100_flexanet.c index edb8c9c029cf..3d4e35efa8b5 100644 --- a/drivers/pcmcia/sa1100_flexanet.c +++ b/drivers/pcmcia/sa1100_flexanet.c @@ -11,6 +11,7 @@ #include <linux/init.h> #include <asm/hardware.h> +#include <asm/mach-types.h> #include <asm/irq.h> #include "sa1100_generic.h" @@ -221,14 +222,14 @@ static int flexanet_pcmcia_socket_suspend(int sock) * */ static struct pcmcia_low_level flexanet_pcmcia_ops = { - init: flexanet_pcmcia_init, - shutdown: flexanet_pcmcia_shutdown, - socket_state: flexanet_pcmcia_socket_state, - get_irq_info: flexanet_pcmcia_get_irq_info, - configure_socket: flexanet_pcmcia_configure_socket, - - socket_init: flexanet_pcmcia_socket_init, - socket_suspend: flexanet_pcmcia_socket_suspend, + .init = flexanet_pcmcia_init, + .shutdown = flexanet_pcmcia_shutdown, + .socket_state = flexanet_pcmcia_socket_state, + .get_irq_info = flexanet_pcmcia_get_irq_info, + .configure_socket = flexanet_pcmcia_configure_socket, + + .socket_init = flexanet_pcmcia_socket_init, + .socket_suspend = flexanet_pcmcia_socket_suspend, }; int __init pcmcia_flexanet_init(void) diff --git a/drivers/pcmcia/sa1100_freebird.c b/drivers/pcmcia/sa1100_freebird.c index 99cbb28a0e66..dc8fc02839db 100644 --- a/drivers/pcmcia/sa1100_freebird.c +++ b/drivers/pcmcia/sa1100_freebird.c @@ -9,6 +9,7 @@ #include <linux/init.h> #include <asm/hardware.h> +#include <asm/mach-types.h> #include <asm/irq.h> #include "sa1100_generic.h" @@ -178,14 +179,14 @@ static int freebird_pcmcia_socket_suspend(int sock) } static struct pcmcia_low_level freebird_pcmcia_ops = { - init: freebird_pcmcia_init, - shutdown: freebird_pcmcia_shutdown, - socket_state: freebird_pcmcia_socket_state, - get_irq_info: freebird_pcmcia_get_irq_info, - configure_socket: freebird_pcmcia_configure_socket, - - socket_init: freebird_pcmcia_socket_init, - socket_suspend: freebird_pcmcia_socket_suspend, + .init = freebird_pcmcia_init, + .shutdown = freebird_pcmcia_shutdown, + .socket_state = freebird_pcmcia_socket_state, + .get_irq_info = freebird_pcmcia_get_irq_info, + .configure_socket = freebird_pcmcia_configure_socket, + + .socket_init = freebird_pcmcia_socket_init, + .socket_suspend = freebird_pcmcia_socket_suspend, }; int __init pcmcia_freebird_init(void) diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index a31365bb73fe..4083ae37cfb2 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -719,7 +719,7 @@ sa1100_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map) (map->flags&MAP_ATTRIB)?"ATTRIB ":"", (map->flags&MAP_USE_WAIT)?"USE_WAIT ":""); - if (map->map >= MAX_WIN){ + if (map->map >= MAX_WIN) { printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, map->map); return -1; @@ -853,19 +853,19 @@ sa1100_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base) #endif /* defined(CONFIG_PROC_FS) */ static struct pccard_operations sa1100_pcmcia_operations = { - init: sa1100_pcmcia_sock_init, - suspend: sa1100_pcmcia_suspend, - register_callback: sa1100_pcmcia_register_callback, - inquire_socket: sa1100_pcmcia_inquire_socket, - get_status: sa1100_pcmcia_get_status, - get_socket: sa1100_pcmcia_get_socket, - set_socket: sa1100_pcmcia_set_socket, - get_io_map: sa1100_pcmcia_get_io_map, - set_io_map: sa1100_pcmcia_set_io_map, - get_mem_map: sa1100_pcmcia_get_mem_map, - set_mem_map: sa1100_pcmcia_set_mem_map, + .init = sa1100_pcmcia_sock_init, + .suspend = sa1100_pcmcia_suspend, + .register_callback = sa1100_pcmcia_register_callback, + .inquire_socket = sa1100_pcmcia_inquire_socket, + .get_status = sa1100_pcmcia_get_status, + .get_socket = sa1100_pcmcia_get_socket, + .set_socket = sa1100_pcmcia_set_socket, + .get_io_map = sa1100_pcmcia_get_io_map, + .set_io_map = sa1100_pcmcia_set_io_map, + .get_mem_map = sa1100_pcmcia_get_mem_map, + .set_mem_map = sa1100_pcmcia_set_mem_map, #ifdef CONFIG_PROC_FS - proc_setup: sa1100_pcmcia_proc_setup + .proc_setup = sa1100_pcmcia_proc_setup #endif }; @@ -927,7 +927,7 @@ sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val, } static struct notifier_block sa1100_pcmcia_notifier_block = { - notifier_call: sa1100_pcmcia_notifier + .notifier_call = sa1100_pcmcia_notifier }; #endif @@ -1148,6 +1148,9 @@ static int __init sa1100_pcmcia_init(void) #ifdef CONFIG_SA1100_GRAPHICSCLIENT pcmcia_gcplus_init(); #endif +#ifdef CONFIG_SA1100_H3600 + pcmcia_h3600_init(); +#endif #ifdef CONFIG_SA1100_PANGOLIN pcmcia_pangolin_init(); #endif @@ -1192,6 +1195,9 @@ static void __exit sa1100_pcmcia_exit(void) #ifdef CONFIG_SA1100_GRAPHICSCLIENT pcmcia_gcplus_exit(); #endif +#ifdef CONFIG_SA1100_H3600 + pcmcia_h3600_exit(); +#endif #ifdef CONFIG_SA1100_PANGOLIN pcmcia_pangolin_exit(); #endif diff --git a/drivers/pcmcia/sa1100_graphicsclient.c b/drivers/pcmcia/sa1100_graphicsclient.c index 6a3691df82ef..1268e6d88018 100644 --- a/drivers/pcmcia/sa1100_graphicsclient.c +++ b/drivers/pcmcia/sa1100_graphicsclient.c @@ -17,6 +17,7 @@ #include <linux/init.h> #include <asm/hardware.h> +#include <asm/mach-types.h> #include <asm/irq.h> #include "sa1100_generic.h" @@ -159,14 +160,14 @@ static int gcplus_pcmcia_socket_suspend(int sock) } static struct pcmcia_low_level gcplus_pcmcia_ops = { - init: gcplus_pcmcia_init, - shutdown: gcplus_pcmcia_shutdown, - socket_state: gcplus_pcmcia_socket_state, - get_irq_info: gcplus_pcmcia_get_irq_info, - configure_socket: gcplus_pcmcia_configure_socket, - - socket_init: gcplus_pcmcia_socket_init, - socket_suspend: gcplus_pcmcia_socket_suspend, + .init = gcplus_pcmcia_init, + .shutdown = gcplus_pcmcia_shutdown, + .socket_state = gcplus_pcmcia_socket_state, + .get_irq_info = gcplus_pcmcia_get_irq_info, + .configure_socket = gcplus_pcmcia_configure_socket, + + .socket_init = gcplus_pcmcia_socket_init, + .socket_suspend = gcplus_pcmcia_socket_suspend, }; int __init pcmcia_gcplus_init(void) diff --git a/drivers/pcmcia/sa1100_graphicsmaster.c b/drivers/pcmcia/sa1100_graphicsmaster.c index 9552dfa55816..34ca7f144201 100644 --- a/drivers/pcmcia/sa1100_graphicsmaster.c +++ b/drivers/pcmcia/sa1100_graphicsmaster.c @@ -82,14 +82,14 @@ graphicsmaster_pcmcia_configure_socket(const struct pcmcia_configure *conf) } static struct pcmcia_low_level graphicsmaster_pcmcia_ops = { - init: graphicsmaster_pcmcia_init, - shutdown: sa1111_pcmcia_shutdown, - socket_state: sa1111_pcmcia_socket_state, - get_irq_info: sa1111_pcmcia_get_irq_info, - configure_socket: graphicsmaster_pcmcia_configure_socket, - - socket_init: sa1111_pcmcia_socket_init, - socket_suspend: sa1111_pcmcia_socket_suspend, + .init = graphicsmaster_pcmcia_init, + .shutdown = sa1111_pcmcia_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .get_irq_info = sa1111_pcmcia_get_irq_info, + .configure_socket = graphicsmaster_pcmcia_configure_socket, + + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_graphicsmaster_init(void) diff --git a/drivers/pcmcia/sa1100_h3600.c b/drivers/pcmcia/sa1100_h3600.c index b9310ea18e51..e25fed19f7fb 100644 --- a/drivers/pcmcia/sa1100_h3600.c +++ b/drivers/pcmcia/sa1100_h3600.c @@ -10,6 +10,9 @@ #include <asm/hardware.h> #include <asm/irq.h> +#include <asm/mach-types.h> +#include <asm/arch/h3600.h> + #include "sa1100_generic.h" static struct irqs { @@ -185,13 +188,27 @@ static int h3600_pcmcia_socket_suspend(int sock) } struct pcmcia_low_level h3600_pcmcia_ops = { - init: h3600_pcmcia_init, - shutdown: h3600_pcmcia_shutdown, - socket_state: h3600_pcmcia_socket_state, - get_irq_info: h3600_pcmcia_get_irq_info, - configure_socket: h3600_pcmcia_configure_socket, - - socket_init: h3600_pcmcia_socket_init, - socket_suspend: h3600_pcmcia_socket_suspend, + .init = h3600_pcmcia_init, + .shutdown = h3600_pcmcia_shutdown, + .socket_state = h3600_pcmcia_socket_state, + .get_irq_info = h3600_pcmcia_get_irq_info, + .configure_socket = h3600_pcmcia_configure_socket, + + .socket_init = h3600_pcmcia_socket_init, + .socket_suspend = h3600_pcmcia_socket_suspend, }; +int __init pcmcia_h3600_init(void) +{ + int ret = -ENODEV; + + if (machine_is_h3600()) + ret = sa1100_register_pcmcia(&h3600_pcmcia_ops); + + return ret; +} + +void __exit pcmcia_h3600_exit(void) +{ + sa1100_unregister_pcmcia(&h3600_pcmcia_ops); +} diff --git a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c index d15f51eedba6..2563902ec01a 100644 --- a/drivers/pcmcia/sa1100_jornada720.c +++ b/drivers/pcmcia/sa1100_jornada720.c @@ -97,14 +97,14 @@ printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__, } static struct pcmcia_low_level jornada720_pcmcia_ops = { - init: jornada720_pcmcia_init, - shutdown: sa1111_pcmcia_shutdown, - socket_state: sa1111_pcmcia_socket_state, - get_irq_info: sa1111_pcmcia_get_irq_info, - configure_socket: jornada720_pcmcia_configure_socket, - - socket_init: sa1111_pcmcia_socket_init, - socket_suspend: sa1111_pcmcia_socket_suspend, + .init = jornada720_pcmcia_init, + .shutdown = sa1111_pcmcia_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .get_irq_info = sa1111_pcmcia_get_irq_info, + .configure_socket = jornada720_pcmcia_configure_socket, + + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_jornada720_init(void) diff --git a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c index 12d6c5c662f9..c9a37dd4bcce 100644 --- a/drivers/pcmcia/sa1100_neponset.c +++ b/drivers/pcmcia/sa1100_neponset.c @@ -127,14 +127,14 @@ neponset_pcmcia_configure_socket(const struct pcmcia_configure *conf) } static struct pcmcia_low_level neponset_pcmcia_ops = { - init: neponset_pcmcia_init, - shutdown: sa1111_pcmcia_shutdown, - socket_state: sa1111_pcmcia_socket_state, - get_irq_info: sa1111_pcmcia_get_irq_info, - configure_socket: neponset_pcmcia_configure_socket, - - socket_init: sa1111_pcmcia_socket_init, - socket_suspend: sa1111_pcmcia_socket_suspend, + .init = neponset_pcmcia_init, + .shutdown = sa1111_pcmcia_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .get_irq_info = sa1111_pcmcia_get_irq_info, + .configure_socket = neponset_pcmcia_configure_socket, + + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_neponset_init(void) diff --git a/drivers/pcmcia/sa1100_pangolin.c b/drivers/pcmcia/sa1100_pangolin.c index 35455466f8f7..6221fa149cae 100644 --- a/drivers/pcmcia/sa1100_pangolin.c +++ b/drivers/pcmcia/sa1100_pangolin.c @@ -10,6 +10,7 @@ #include <linux/init.h> #include <asm/hardware.h> +#include <asm/mach-types.h> #include <asm/irq.h> #include "sa1100_generic.h" @@ -159,13 +160,13 @@ static int pangolin_pcmcia_socket_suspend(int sock) } static struct pcmcia_low_level pangolin_pcmcia_ops = { - init: pangolin_pcmcia_init, - shutdown: pangolin_pcmcia_shutdown, - socket_state: pangolin_pcmcia_socket_state, - get_irq_info: pangolin_pcmcia_get_irq_info, - configure_socket: pangolin_pcmcia_configure_socket, + .init = pangolin_pcmcia_init, + .shutdown = pangolin_pcmcia_shutdown, + .socket_state = pangolin_pcmcia_socket_state, + .get_irq_info = pangolin_pcmcia_get_irq_info, + .configure_socket = pangolin_pcmcia_configure_socket, - socket_init: pangolin_pcmcia_socket_init, + .socket_init = pangolin_pcmcia_socket_init, socket_suspend, pangolin_pcmcia_socket_suspend, }; diff --git a/drivers/pcmcia/sa1100_pfs168.c b/drivers/pcmcia/sa1100_pfs168.c index 511afebb38a3..770132ee9fc2 100644 --- a/drivers/pcmcia/sa1100_pfs168.c +++ b/drivers/pcmcia/sa1100_pfs168.c @@ -119,14 +119,14 @@ pfs168_pcmcia_configure_socket(const struct pcmcia_configure *conf) } static struct pcmcia_low_level pfs168_pcmcia_ops = { - init: pfs168_pcmcia_init, - shutdown: sa1111_pcmcia_shutdown, - socket_state: sa1111_pcmcia_socket_state, - get_irq_info: sa1111_pcmcia_get_irq_info, - configure_socket: pfs168_pcmcia_configure_socket, - - socket_init: sa1111_pcmcia_socket_init, - socket_suspend: sa1111_pcmcia_socket_suspend, + .init = pfs168_pcmcia_init, + .shutdown = sa1111_pcmcia_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .get_irq_info = sa1111_pcmcia_get_irq_info, + .configure_socket = pfs168_pcmcia_configure_socket, + + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_pfs168_init(void) diff --git a/drivers/pcmcia/sa1100_shannon.c b/drivers/pcmcia/sa1100_shannon.c index 7cfe0105a225..41e25ddaa461 100644 --- a/drivers/pcmcia/sa1100_shannon.c +++ b/drivers/pcmcia/sa1100_shannon.c @@ -9,6 +9,7 @@ #include <linux/init.h> #include <asm/hardware.h> +#include <asm/mach-types.h> #include <asm/arch/shannon.h> #include <asm/irq.h> #include "sa1100_generic.h" @@ -151,14 +152,14 @@ static int shannon_pcmcia_socket_suspend(int sock) } static struct pcmcia_low_level shannon_pcmcia_ops = { - init: shannon_pcmcia_init, - shutdown: shannon_pcmcia_shutdown, - socket_state: shannon_pcmcia_socket_state, - get_irq_info: shannon_pcmcia_get_irq_info, - configure_socket: shannon_pcmcia_configure_socket, - - socket_init: shannon_pcmcia_socket_init, - socket_suspend: shannon_pcmcia_socket_suspend, + .init = shannon_pcmcia_init, + .shutdown = shannon_pcmcia_shutdown, + .socket_state = shannon_pcmcia_socket_state, + .get_irq_info = shannon_pcmcia_get_irq_info, + .configure_socket = shannon_pcmcia_configure_socket, + + .socket_init = shannon_pcmcia_socket_init, + .socket_suspend = shannon_pcmcia_socket_suspend, }; int __init pcmcia_shannon_init(void) diff --git a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c index bbe79bdf8fc1..7d699fc475f5 100644 --- a/drivers/pcmcia/sa1100_simpad.c +++ b/drivers/pcmcia/sa1100_simpad.c @@ -9,6 +9,7 @@ #include <linux/init.h> #include <asm/hardware.h> +#include <asm/mach-types.h> #include <asm/irq.h> #include "sa1100_generic.h" @@ -158,14 +159,14 @@ static int simpad_pcmcia_socket_suspend(int sock) } static struct pcmcia_low_level simpad_pcmcia_ops = { - init: simpad_pcmcia_init, - shutdown: simpad_pcmcia_shutdown, - socket_state: simpad_pcmcia_socket_state, - get_irq_info: simpad_pcmcia_get_irq_info, - configure_socket: simpad_pcmcia_configure_socket, - - socket_init: simpad_pcmcia_socket_init, - socket_suspend: simpad_pcmcia_socket_suspend, + .init = simpad_pcmcia_init, + .shutdown = simpad_pcmcia_shutdown, + .socket_state = simpad_pcmcia_socket_state, + .get_irq_info = simpad_pcmcia_get_irq_info, + .configure_socket = simpad_pcmcia_configure_socket, + + .socket_init = simpad_pcmcia_socket_init, + .socket_suspend = simpad_pcmcia_socket_suspend, }; int __init pcmcia_simpad_init(void) diff --git a/drivers/pcmcia/sa1100_stork.c b/drivers/pcmcia/sa1100_stork.c index c172acce8305..597d164ea0f7 100644 --- a/drivers/pcmcia/sa1100_stork.c +++ b/drivers/pcmcia/sa1100_stork.c @@ -25,6 +25,7 @@ #include <linux/i2c.h> #include <asm/hardware.h> +#include <asm/mach-types.h> #include <asm/irq.h> #include "sa1100_generic.h" @@ -227,14 +228,14 @@ static int stork_pcmcia_socket_suspend(int sock) } static struct pcmcia_low_level stork_pcmcia_ops = { - init: stork_pcmcia_init, - shutdown: stork_pcmcia_shutdown, - socket_state: stork_pcmcia_socket_state, - get_irq_info: stork_pcmcia_get_irq_info, - configure_socket: stork_pcmcia_configure_socket, - - socket_init: stork_pcmcia_socket_init, - socket_suspend: stork_pcmcia_socket_suspend, + .init = stork_pcmcia_init, + .shutdown = stork_pcmcia_shutdown, + .socket_state = stork_pcmcia_socket_state, + .get_irq_info = stork_pcmcia_get_irq_info, + .configure_socket = stork_pcmcia_configure_socket, + + .socket_init = stork_pcmcia_socket_init, + .socket_suspend = stork_pcmcia_socket_suspend, }; int __init pcmcia_stork_init(void) diff --git a/drivers/pcmcia/sa1100_system3.c b/drivers/pcmcia/sa1100_system3.c index 2ab0d4537d0d..c6076fee5bcb 100644 --- a/drivers/pcmcia/sa1100_system3.c +++ b/drivers/pcmcia/sa1100_system3.c @@ -106,14 +106,14 @@ static int system3_pcmcia_socket_state(struct pcmcia_state_array } struct pcmcia_low_level system3_pcmcia_ops = { - init: system3_pcmcia_init, - shutdown: system3_pcmcia_shutdown, - socket_state: system3_pcmcia_socket_state, - get_irq_info: sa1111_pcmcia_get_irq_info, - configure_socket: system3_pcmcia_configure_socket, - - socket_init: sa1111_pcmcia_socket_init, - socket_suspend: sa1111_pcmcia_socket_suspend, + .init = system3_pcmcia_init, + .shutdown = system3_pcmcia_shutdown, + .socket_state = system3_pcmcia_socket_state, + .get_irq_info = sa1111_pcmcia_get_irq_info, + .configure_socket = system3_pcmcia_configure_socket, + + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_system3_init(void) diff --git a/drivers/pcmcia/sa1100_trizeps.c b/drivers/pcmcia/sa1100_trizeps.c index c06a041bac8c..07660b5e77af 100644 --- a/drivers/pcmcia/sa1100_trizeps.c +++ b/drivers/pcmcia/sa1100_trizeps.c @@ -14,6 +14,7 @@ #include <linux/init.h> #include <asm/hardware.h> // included trizeps.h +#include <asm/mach-types.h> #include <asm/system.h> #include <asm/irq.h> #include "sa1100_generic.h" @@ -191,13 +192,13 @@ static int trizeps_pcmcia_socket_suspend(int sock) * ******************************************************/ struct pcmcia_low_level trizeps_pcmcia_ops = { - init: trizeps_pcmcia_init, - shutdown: trizeps_pcmcia_shutdown, - socket_state: trizeps_pcmcia_socket_state, - get_irq_info: trizeps_pcmcia_get_irq_info, - configure_socket: trizeps_pcmcia_configure_socket, - socket_init: trizeps_pcmcia_socket_init, - socket_suspend: trizeps_pcmcia_socket_suspend, + .init = trizeps_pcmcia_init, + .shutdown = trizeps_pcmcia_shutdown, + .socket_state = trizeps_pcmcia_socket_state, + .get_irq_info = trizeps_pcmcia_get_irq_info, + .configure_socket = trizeps_pcmcia_configure_socket, + .socket_init = trizeps_pcmcia_socket_init, + .socket_suspend = trizeps_pcmcia_socket_suspend, }; int __init pcmcia_trizeps_init(void) diff --git a/drivers/pcmcia/sa1100_xp860.c b/drivers/pcmcia/sa1100_xp860.c index 69d3f3ddaacc..c1eb6ae18249 100644 --- a/drivers/pcmcia/sa1100_xp860.c +++ b/drivers/pcmcia/sa1100_xp860.c @@ -132,14 +132,14 @@ xp860_pcmcia_configure_socket(const struct pcmcia_configure *conf) } static struct pcmcia_low_level xp860_pcmcia_ops = { - init: xp860_pcmcia_init, - shutdown: sa1111_pcmcia_shutdown, - socket_state: sa1111_pcmcia_socket_state, - get_irq_info: sa1111_pcmcia_get_irq_info, - configure_socket: xp860_pcmcia_configure_socket, - - socket_init: sa1111_pcmcia_socket_init, - socket_suspend: sa1111_pcmcia_socket_suspend, + .init = xp860_pcmcia_init, + .shutdown = sa1111_pcmcia_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .get_irq_info = sa1111_pcmcia_get_irq_info, + .configure_socket = xp860_pcmcia_configure_socket, + + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_xp860_init(void) diff --git a/drivers/pcmcia/sa1100_yopy.c b/drivers/pcmcia/sa1100_yopy.c index 4bdb837cd6f1..138f2b07f067 100644 --- a/drivers/pcmcia/sa1100_yopy.c +++ b/drivers/pcmcia/sa1100_yopy.c @@ -9,6 +9,7 @@ #include <linux/init.h> #include <asm/hardware.h> +#include <asm/mach-types.h> #include <asm/irq.h> #include "sa1100_generic.h" @@ -160,14 +161,14 @@ static int yopy_pcmcia_socket_suspend(int sock) } static struct pcmcia_low_level yopy_pcmcia_ops = { - init: yopy_pcmcia_init, - shutdown: yopy_pcmcia_shutdown, - socket_state: yopy_pcmcia_socket_state, - get_irq_info: yopy_pcmcia_get_irq_info, - configure_socket: yopy_pcmcia_configure_socket, - - socket_init: yopy_pcmcia_socket_init, - socket_suspend: yopy_pcmcia_socket_suspend, + .init = yopy_pcmcia_init, + .shutdown = yopy_pcmcia_shutdown, + .socket_state = yopy_pcmcia_socket_state, + .get_irq_info = yopy_pcmcia_get_irq_info, + .configure_socket = yopy_pcmcia_configure_socket, + + .socket_init = yopy_pcmcia_socket_init, + .socket_suspend = yopy_pcmcia_socket_suspend, }; int __init pcmcia_yopy_init(void) diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h index 36e18809fca9..cd936544cef6 100644 --- a/drivers/scsi/scsi.h +++ b/drivers/scsi/scsi.h @@ -977,4 +977,6 @@ static inline Scsi_Cmnd *scsi_find_tag(Scsi_Device *SDpnt, int tag) { #define SCSI_SENSE_VALID(scmd) ((scmd->sense_buffer[0] & 0x70) == 0x70) +int scsi_set_medium_removal(Scsi_Device *dev, char state); + #endif diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index bc5909c98ee3..5863cdcf9bba 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -916,7 +916,7 @@ sd_read_cache_type(Scsi_Disk *sdkp, char *diskname, SRpnt->sr_data_direction = SCSI_DATA_READ; scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer, - 24, SD_TIMEOUT, MAX_RETRIES); + 128, SD_TIMEOUT, MAX_RETRIES); the_result = SRpnt->sr_result; retries--; diff --git a/drivers/serial/8250_acorn.c b/drivers/serial/8250_acorn.c new file mode 100644 index 000000000000..80160e093967 --- /dev/null +++ b/drivers/serial/8250_acorn.c @@ -0,0 +1,150 @@ +/* + * linux/drivers/serial/acorn.c + * + * Copyright (C) 1996-2002 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/module.h> +#include <linux/types.h> +#include <linux/serial.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/init.h> + +#include <asm/ecard.h> +#include <asm/string.h> + +#define MAX_PORTS 3 + +struct serial_card_type { + unsigned int num_ports; + unsigned int baud_base; + int type; + int speed; + int offset[MAX_PORTS]; +}; + +struct serial_card_info { + unsigned int num_ports; + int ports[MAX_PORTS]; + unsigned long base[MAX_PORTS]; +}; + +static inline int serial_register_onedev(unsigned long port, int irq, unsigned int baud_base) +{ + struct serial_struct req; + + memset(&req, 0, sizeof(req)); + req.baud_base = baud_base; + req.irq = irq; + req.port = port; + req.flags = 0; + + return register_serial(&req); +} + +static int __devinit serial_card_probe(struct expansion_card *ec, const struct ecard_id *id) +{ + struct serial_card_info *info; + struct serial_card_type *type = id->data; + unsigned long cardaddr, address; + int port; + + ecard_claim (ec); + + info = kmalloc(sizeof(struct serial_card_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + memset(info, 0, sizeof(struct serial_card_info)); + info->num_ports = type->num_ports; + + cardaddr = ecard_address(ec, type->type, type->speed); + + for (port = 0; port < info->num_ports; port ++) { + address = cardaddr + type->offset[port]; + + info->ports[port] = -1; + info->base[port] = address; + + if (!request_region(address, 8, "acornserial")) + continue; + + info->ports[port] = serial_register_onedev(address, ec->irq, type->baud_base); + if (info->ports[port] < 0) + break; + } + + return 0; +} + +static void __devexit serial_card_remove(struct expansion_card *ec) +{ + struct serial_card_info *info = ecard_get_drvdata(ec); + int i; + + ecard_set_drvdata(ec, NULL); + + for (i = 0; i < info->num_ports; i++) { + if (info->ports[i] > 0) { + unregister_serial(info->ports[i]); + release_region(info->base[i], 8); + } + } + + kfree(info); + + ecard_release(ec); +} + +static struct serial_card_type atomwide_type = { + .num_ports = 3, + .baud_base = 7372800 / 16, + .type = ECARD_IOC, + .speed = ECARD_SLOW, + .offset = { 0xa00, 0x900, 0x800 }, +}; + +static struct serial_card_type serport_type = { + .num_ports = 2, + .baud_base = 3686400 / 16, + .type = ECARD_IOC, + .speed = ECARD_SLOW, + .offset = { 0x800, 0x808 }, +}; + +static const struct ecard_id serial_cids[] = { + { MANU_ATOMWIDE, PROD_ATOMWIDE_3PSERIAL, &atomwide_type }, + { MANU_SERPORT, PROD_SERPORT_DSPORT, &serport_type }, + { 0xffff, 0xffff } +}; + +static struct ecard_driver serial_card_driver = { + .probe = serial_card_probe, + .remove = __devexit_p(serial_card_remove), + .id_table = serial_cids, + .drv = { + .name = "acornserial", + }, +}; + +static int __init serial_card_init(void) +{ + return ecard_register_driver(&serial_card_driver); +} + +static void __exit serial_card_exit(void) +{ + ecard_remove_driver(&serial_card_driver); +} + +MODULE_AUTHOR("Russell King"); +MODULE_LICENSE("GPL"); + +module_init(serial_card_init); +module_exit(serial_card_exit); diff --git a/drivers/serial/Config.help b/drivers/serial/Config.help index c5907d78e1b2..fccf27c710f9 100644 --- a/drivers/serial/Config.help +++ b/drivers/serial/Config.help @@ -103,20 +103,15 @@ CONFIG_SERIAL_8250_MULTIPORT CONFIG_SERIAL_8250_RSA ::: To be written ::: -CONFIG_ATOMWIDE_SERIAL - If you have an Atomwide Serial card for an Acorn system, say Y to - this option. The driver can handle 1, 2, or 3 port cards. - If unsure, say N. - -CONFIG_DUALSP_SERIAL - If you have the Serial Port's dual serial card for an Acorn system, - say Y to this option. If unsure, say N. +CONFIG_SERIAL_8250_ACORN + If you have an Atomwide Serial card or Serial Port card for an Acorn + system, say Y to this option. The driver can handle 1, 2, or 3 port + cards. If unsure, say N. CONFIG_SERIAL_ANAKIN ::: To be written ::: -CONFIG_SERIAL_ANAKIN_CONSOLE - ::: To be written ::: +CONFIG_SERIAL_ANAKIN_CONSOLE Even if you say Y here, the currently visible virtual console (/dev/tty0) will still be used as the system console by default, but you can alter that using a kernel command line option such as @@ -149,8 +144,6 @@ CONFIG_SERIAL_CLPS711X ::: To be written ::: CONFIG_SERIAL_CLPS711X_CONSOLE - ::: To be written ::: - Even if you say Y here, the currently visible virtual console (/dev/tty0) will still be used as the system console by default, but you can alter that using a kernel command line option such as diff --git a/drivers/serial/Config.in b/drivers/serial/Config.in index 5a7841d7deeb..71637638d4d8 100644 --- a/drivers/serial/Config.in +++ b/drivers/serial/Config.in @@ -22,8 +22,7 @@ dep_bool ' Support RSA serial ports' CONFIG_SERIAL_8250_RSA $CONFIG_SERIAL_8250 comment 'Non-8250 serial port support' if [ "$CONFIG_ARM" = "y" ]; then - dep_tristate 'Acorn Atomwide 16550 serial port support' CONFIG_ATOMWIDE_SERIAL $CONFIG_ARCH_ACORN $CONFIG_SERIAL_8250 - dep_tristate 'Acorn Dual 16550 serial port support' CONFIG_DUALSP_SERIAL $CONFIG_ARCH_ACORN $CONFIG_SERIAL_8250 + dep_tristate 'Acorn expansion card serial port support' CONFIG_SERIAL_8250_ACORN $CONFIG_ARCH_ACORN $CONFIG_SERIAL_8250 dep_bool 'Anakin serial port support' CONFIG_SERIAL_ANAKIN $CONFIG_ARCH_ANAKIN dep_bool ' Console on Anakin serial port' CONFIG_SERIAL_ANAKIN_CONSOLE $CONFIG_SERIAL_ANAKIN if [ "$CONFIG_SERIAL_ANAKIN" = "y" ]; then diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 6b7a12d08bf7..bbf7e26cf521 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_SERIAL_CORE) += core.o obj-$(CONFIG_SERIAL_21285) += 21285.o obj-$(CONFIG_SERIAL_8250) += 8250.o $(serial-8250-y) obj-$(CONFIG_SERIAL_8250_CS) += 8250_cs.o +obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o obj-$(CONFIG_SERIAL_ANAKIN) += anakin.o obj-$(CONFIG_SERIAL_AMBA) += amba.o obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 5ef04cef469e..142115d509b1 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -62,6 +62,9 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) int retval, region; char buf [8], *bufp = buf; + if (usb_disabled()) + return -ENODEV; + if (!id || !(driver = (struct hc_driver *) id->driver_data)) return -EINVAL; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 204cf874c8e6..e12b720f0145 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -943,7 +943,9 @@ static void usb_hub_events(void) list_del_init(tmp); - down(&hub->khubd_sem); /* never blocks, we were on list */ + if (unlikely(down_trylock(&hub->khubd_sem))) + BUG(); /* never blocks, we were on list */ + spin_unlock_irqrestore(&hub_event_lock, flags); if (hub->error) { @@ -1067,10 +1069,10 @@ static int usb_hub_thread(void *__hub) } static struct usb_device_id hub_id_table [] = { - { match_flags: USB_DEVICE_ID_MATCH_DEV_CLASS, - bDeviceClass: USB_CLASS_HUB}, - { match_flags: USB_DEVICE_ID_MATCH_INT_CLASS, - bInterfaceClass: USB_CLASS_HUB}, + { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS, + .bDeviceClass = USB_CLASS_HUB}, + { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, + .bInterfaceClass = USB_CLASS_HUB}, { } /* Terminating entry */ }; diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 96575bb2b465..9c35f4a3698f 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -45,7 +45,8 @@ static struct inode_operations usbfs_dir_inode_operations; static struct vfsmount *usbdevfs_mount; static struct vfsmount *usbfs_mount; static spinlock_t mount_lock = SPIN_LOCK_UNLOCKED; -static int mount_count; /* = 0 */ +static int usbdevfs_mount_count; /* = 0 */ +static int usbfs_mount_count; /* = 0 */ static struct dentry *devices_usbdevfs_dentry; static struct dentry *devices_usbfs_dentry; @@ -507,14 +508,14 @@ static struct file_system_type usb_fs_type = { }; /* --------------------------------------------------------------------- */ -static int get_mount (struct file_system_type *fs_type, struct vfsmount **mount) +static int get_mount (struct file_system_type *fs_type, struct vfsmount **mount, int *mount_count) { struct vfsmount *mnt; spin_lock (&mount_lock); if (*mount) { mntget(*mount); - ++mount_count; + ++(*mount_count); spin_unlock (&mount_lock); goto go_ahead; } @@ -528,33 +529,33 @@ static int get_mount (struct file_system_type *fs_type, struct vfsmount **mount) spin_lock (&mount_lock); if (!*mount) { *mount = mnt; - ++mount_count; + ++(*mount_count); spin_unlock (&mount_lock); goto go_ahead; } mntget(*mount); - ++mount_count; + ++(*mount_count); spin_unlock (&mount_lock); mntput(mnt); go_ahead: - dbg("mount_count = %d", mount_count); + dbg("mount_count = %d", *mount_count); return 0; } -static void put_mount (struct vfsmount **mount) +static void put_mount (struct vfsmount **mount, int *mount_count) { struct vfsmount *mnt; spin_lock (&mount_lock); mnt = *mount; - --mount_count; - if (!mount_count) + --(*mount_count); + if (!(*mount_count)) *mount = NULL; spin_unlock (&mount_lock); mntput(mnt); - dbg("mount_count = %d", mount_count); + dbg("mount_count = %d", *mount_count); } static int create_special_files (void) @@ -563,13 +564,13 @@ static int create_special_files (void) int retval = 0; /* create the devices special file */ - retval = get_mount (&usbdevice_fs_type, &usbdevfs_mount); + retval = get_mount (&usbdevice_fs_type, &usbdevfs_mount, &usbdevfs_mount_count); if (retval) { err ("Unable to get usbdevfs mount"); goto exit; } - retval = get_mount (&usb_fs_type, &usbfs_mount); + retval = get_mount (&usb_fs_type, &usbfs_mount, &usbfs_mount_count); if (retval) { err ("Unable to get usbfs mount"); goto error_clean_usbdevfs_mount; @@ -604,10 +605,10 @@ error_remove_file: devices_usbfs_dentry = NULL; error_clean_mounts: - put_mount (&usbfs_mount); + put_mount (&usbfs_mount, &usbfs_mount_count); error_clean_usbdevfs_mount: - put_mount (&usbdevfs_mount); + put_mount (&usbdevfs_mount, &usbdevfs_mount_count); exit: return retval; @@ -621,8 +622,8 @@ static void remove_special_files (void) fs_remove_file (devices_usbfs_dentry); devices_usbdevfs_dentry = NULL; devices_usbfs_dentry = NULL; - put_mount (&usbdevfs_mount); - put_mount (&usbfs_mount); + put_mount (&usbdevfs_mount, &usbdevfs_mount_count); + put_mount (&usbfs_mount, &usbfs_mount_count); } void usbfs_update_special (void) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 17ab912a3f4b..0d1dad8253fc 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -756,6 +756,7 @@ int usb_clear_halt(struct usb_device *dev, int pipe) * * This is used to enable data transfers on interfaces that may not * be enabled by default. Not all devices support such configurability. + * Only the driver bound to an interface may change its setting. * * Within any given configuration, each interface may have several * alternative settings. These are often used to control levels of @@ -808,6 +809,22 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) interface, NULL, 0, HZ * 5)) < 0) return ret; + /* FIXME drivers shouldn't need to replicate/bugfix the logic here + * when they implement async or easily-killable versions of this or + * other "should-be-internal" functions (like clear_halt). + * should hcd+usbcore postprocess control requests? + */ + + /* prevent submissions using previous endpoint settings */ + iface_as = iface->altsetting + iface->act_altsetting; + for (i = 0; i < iface_as->bNumEndpoints; i++) { + u8 ep = iface_as->endpoint [i].bEndpointAddress; + int out = !(ep & USB_DIR_IN); + + ep &= USB_ENDPOINT_NUMBER_MASK; + (out ? dev->epmaxpacketout : dev->epmaxpacketin ) [ep] = 0; + // FIXME want hcd hook here, "no such endpoint" + } iface->act_altsetting = alternate; /* 9.1.1.5: reset toggles for all endpoints affected by this iface-as @@ -819,21 +836,20 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) * any SetInterface request and hence assume toggles need to be reset. * However, EP0 toggles are re-synced for every individual transfer * during the SETUP stage - hence EP0 toggles are "don't care" here. + * (Likewise, EP0 never "halts" on well designed devices.) */ iface_as = &iface->altsetting[alternate]; for (i = 0; i < iface_as->bNumEndpoints; i++) { u8 ep = iface_as->endpoint[i].bEndpointAddress; + int out = !(ep & USB_DIR_IN); - usb_settoggle(dev, ep&USB_ENDPOINT_NUMBER_MASK, usb_endpoint_out(ep), 0); + ep &= USB_ENDPOINT_NUMBER_MASK; + usb_settoggle (dev, ep, out, 0); + (out ? dev->epmaxpacketout : dev->epmaxpacketin) [ep] + = iface_as->endpoint [ep].wMaxPacketSize; } - /* usb_set_maxpacket() sets the maxpacket size for all EP in all - * interfaces but it shouldn't do any harm here: we have changed - * the AS for the requested interface only, hence for unaffected - * interfaces it's just re-application of still-valid values. - */ - usb_set_maxpacket(dev); return 0; } diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 30a2ba8585b1..aaf31af0a45b 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -272,9 +272,9 @@ int usb_submit_urb(struct urb *urb, int mem_flags) /* enforce simple/standard policy */ allowed = USB_ASYNC_UNLINK; // affects later unlinks allowed |= URB_NO_DMA_MAP; + allowed |= URB_NO_INTERRUPT; switch (temp) { case PIPE_BULK: - allowed |= URB_NO_INTERRUPT; if (is_out) allowed |= USB_ZERO_PACKET; /* FALLTHROUGH */ diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 5b3ec48092ad..556dbacb7c23 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -50,6 +50,9 @@ extern int usb_major_init(void); extern void usb_major_cleanup(void); +int nousb; /* Disable USB when built into kernel image */ + /* Not honored on modular build */ + static int generic_probe (struct device *dev) { @@ -167,6 +170,9 @@ int usb_register(struct usb_driver *new_driver) { int retval = 0; + if (nousb) + return -ENODEV; + new_driver->driver.name = (char *)new_driver->name; new_driver->driver.bus = &usb_bus_type; new_driver->driver.probe = usb_device_probe; @@ -1338,11 +1344,37 @@ struct bus_type usb_bus_type = { .hotplug = usb_hotplug, }; +#ifndef MODULE + +static int __init usb_setup_disable(char *str) +{ + nousb = 1; + return 1; +} + +/* format to disable USB on kernel command line is: nousb */ +__setup("nousb", usb_setup_disable); + +#endif + +/* + * for external read access to <nousb> + */ +int usb_disabled(void) +{ + return nousb; +} + /* * Init */ static int __init usb_init(void) { + if (nousb) { + info("USB support disabled\n"); + return 0; + } + bus_register(&usb_bus_type); usb_major_init(); usbfs_init(); @@ -1358,6 +1390,10 @@ static int __init usb_init(void) */ static void __exit usb_exit(void) { + /* This will matter if shutdown/reboot does exitcalls. */ + if (nousb) + return; + remove_driver(&usb_generic_driver); usb_major_cleanup(); usbfs_cleanup(); @@ -1377,6 +1413,7 @@ EXPORT_SYMBOL(usb_epnum_to_ep_desc); EXPORT_SYMBOL(usb_register); EXPORT_SYMBOL(usb_deregister); +EXPORT_SYMBOL(usb_disabled); EXPORT_SYMBOL(usb_device_probe); EXPORT_SYMBOL(usb_device_remove); diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index ed92a80f66d0..0398d58d7f3a 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -985,6 +985,9 @@ MODULE_LICENSE ("GPL"); static int __init init (void) { dbg (DRIVER_INFO); + if (usb_disabled()) + return -ENODEV; + dbg ("block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd", sizeof (struct ehci_qh), sizeof (struct ehci_qtd), sizeof (struct ehci_itd), sizeof (struct ehci_sitd)); diff --git a/drivers/usb/host/hc_sl811.c b/drivers/usb/host/hc_sl811.c index 334d30ba13a4..a83f7e83ac33 100644 --- a/drivers/usb/host/hc_sl811.c +++ b/drivers/usb/host/hc_sl811.c @@ -1321,6 +1321,9 @@ static int __init hci_hcd_init (void) int ret; DBGFUNC ("Enter hci_hcd_init\n"); + if (usb_disabled()) + return -ENODEV; + ret = hc_found_hci (base_addr, data_reg_addr, irq); return ret; diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index a1979e532787..29b767ec52b7 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -365,6 +365,9 @@ static struct pci_driver ohci_pci_driver = { static int __init ohci_hcd_pci_init (void) { dbg (DRIVER_INFO " (PCI)"); + if (usb_disabled()) + return -ENODEV; + dbg ("block sizes: ed %d td %d", sizeof (struct ed), sizeof (struct td)); return pci_module_init (&ohci_pci_driver); diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index a6a34619d4fd..98996cd62d6e 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -23,6 +23,8 @@ #error "This file is SA-1111 bus glue. CONFIG_SA1111 must be defined." #endif +extern int usb_disabled(void); + /*-------------------------------------------------------------------------*/ static void sa1111_start_hc(struct sa1111_dev *dev) @@ -355,6 +357,9 @@ static int ohci_hcd_sa1111_drv_probe(struct device *_dev) struct usb_hcd *hcd = NULL; int ret; + if (usb_disabled()) + return -ENODEV; + ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, &hcd, dev); if (ret == 0) diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 8d8a5cd42fa5..1e4038ac97ca 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -2484,6 +2484,9 @@ static int __init uhci_hcd_init(void) info(DRIVER_DESC " " DRIVER_VERSION); + if (usb_disabled()) + return -ENODEV; + if (debug) { errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL); if (!errbuf) diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c index ac7bdcace180..d5016e83ba62 100644 --- a/drivers/usb/input/wacom.c +++ b/drivers/usb/input/wacom.c @@ -402,7 +402,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i struct usb_device *dev = interface_to_usbdev(intf); struct usb_endpoint_descriptor *endpoint; struct wacom *wacom; - char rep_data[2] = {0x02, 0x02}; char path[64]; if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) diff --git a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile index b3aa1f558bbe..d30da815bf8f 100644 --- a/drivers/usb/media/Makefile +++ b/drivers/usb/media/Makefile @@ -14,6 +14,6 @@ obj-$(CONFIG_USB_OV511) += ov511.o obj-$(CONFIG_USB_PWC) += pwc.o obj-$(CONFIG_USB_SE401) += se401.o obj-$(CONFIG_USB_STV680) += stv680.o -obj-$(CONFIG_USB_VICAM) += vicam.o +obj-$(CONFIG_USB_VICAM) += vicam.o usbvideo.o include $(TOPDIR)/Rules.make diff --git a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c index 5b673019b7e1..709cdf93afa3 100644 --- a/drivers/usb/media/vicam.c +++ b/drivers/usb/media/vicam.c @@ -1,102 +1,356 @@ -/* -*- linux-c -*- - * USB ViCAM driver - * - * Copyright (c) 2001 Christopher L Cheney (ccheney@cheney.cx) - * Copyright (c) 2001 Pavel Machek (pavel@suse.cz) sponsored by SuSE +/* + * USB ViCam WebCam driver + * Copyright (c) 2002 Joe Burks (jburks@wavicle.org) * - * 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. + * Supports 3COM HomeConnect PC Digital WebCam * - * This driver is for the Vista Imaging ViCAM and 3Com HomeConnect USB + * 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. * - * Thanks to Greg Kroah-Hartman for the USB Skeleton driver + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * TODO: - * - find out the ids for the Vista Imaging ViCAM + * You 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. * - * History: + * This source code is based heavily on the CPiA webcam driver which was + * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt * - * 2001_07_07 - 0.1 - christopher: first version - * 2001_08_28 - 0.2 - pavel: messed it up, but for some fun, try - while true; do dd if=/dev/video of=/dev/fb0 bs=$[0x1e480] count=1 2> /dev/null; done - yep, moving pictures. - * 2001_08_29 - 0.3 - pavel: played a little bit more. Experimental mmap support. For some fun, - get gqcam-0.9, compile it and run. Better than dd ;-). - * 2001_08_29 - 0.4 - pavel: added shutter speed control (not much functional) - kill update_params if it does not seem to work for you. - * 2001_08_30 - 0.5 - pavel: fixed stupid bug with update_params & vicam_bulk - + * Portions of this code were also copied from usbvideo.c * - * FIXME: It crashes on rmmod with camera plugged. - */ -#define DEBUG 1 + * Special thanks to the the whole team at Sourceforge for help making + * this driver become a reality. Notably: + * Andy Armstrong who reverse engineered the color encoding and + * Pavel Machek and Chris Cheney who worked on reverse engineering the + * camera controls and wrote the first generation driver. + * */ -#include <linux/config.h> #include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/signal.h> -#include <linux/errno.h> -#include <linux/poll.h> -#include <linux/init.h> -#include <linux/mm.h> -#include <linux/pagemap.h> -#include <linux/slab.h> -#include <linux/fcntl.h> +#include <linux/wrapper.h> #include <linux/module.h> -#include <linux/spinlock.h> -#include <linux/list.h> -#include <linux/smp_lock.h> -#include <linux/devfs_fs_kernel.h> +#include <linux/init.h> +#include <linux/videodev.h> #include <linux/usb.h> - -#include <asm/io.h> -#include <linux/wrapper.h> #include <linux/vmalloc.h> +#include <linux/slab.h> +#include <linux/proc_fs.h> +#include "usbvideo.h" -#include <linux/videodev.h> +// #define VICAM_DEBUG -#include "vicam.h" -#include "vicamurbs.h" +#ifndef MODULE_LICENSE +#define MODULE_LICENSE(a) +#endif + +#ifndef bool +#define bool int +#endif + +#ifdef VICAM_DEBUG +#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args) +#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args) +#else +#define DBG(fmn,args...) do {} while(0) +#endif /* Version Information */ -#define DRIVER_VERSION "v0" -#define DRIVER_AUTHOR "Christopher L Cheney <ccheney@cheney.cx>, Pavel Machek <pavel@suse.cz>" -#define DRIVER_DESC "USB ViCAM Driver" +#define DRIVER_VERSION "v1.0" +#define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org" +#define DRIVER_DESC "ViCam WebCam Driver" /* Define these values to match your device */ -#define USB_VICAM_VENDOR_ID 0x04C1 -#define USB_VICAM_PRODUCT_ID 0x009D +#define USB_VICAM_VENDOR_ID 0x04c1 +#define USB_VICAM_PRODUCT_ID 0x009d -/* table of devices that work with this driver */ -static struct usb_device_id vicam_table [] = { - { USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID) }, - { } /* Terminating entry */ -}; +#define VICAM_BYTES_PER_PIXEL 3 +#define VICAM_MAX_READ_SIZE (512*242+128) +#define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240) +#define VICAM_FRAMES 2 -MODULE_DEVICE_TABLE (usb, vicam_table); +/* Not sure what all the bytes in these char + * arrays do, but they're necessary to make + * the camera work. + */ -static int video_nr = -1; /* next avail video device */ -static struct usb_driver vicam_driver; +static unsigned char setup1[] = { + 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67, + 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00, + 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17, + 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00, + 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00 +}; -static char *buf, *buf2; -static volatile int change_pending = 0; +static unsigned char setup2[] = { + 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00, + 0x00, 0x00 +}; -static int vicam_parameters(struct usb_vicam *vicam); +static unsigned char setup3[] = { + 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00 +}; -/****************************************************************************** - * - * Memory management functions - * - * Taken from bttv-drivers.c 2.4.7-pre3 - * - ******************************************************************************/ +static unsigned char setup4[] = { + 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07, + 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00, + 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00, + 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07, + 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00, + 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00, + 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07, + 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF, + 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0, + 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07, + 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00, + 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0, + 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1, + 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09, + 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00, + 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF, + 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02, + 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00, + 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF, + 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00, + 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00, + 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05, + 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA, + 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06, + 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF, + 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05, + 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01, + 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09, + 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06, + 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05, + 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA, + 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05, + 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, + 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00, + 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF, + 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00, + 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0, + 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06, + 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00, + 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07, + 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF, + 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00, + 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06, + 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57, + 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57, + 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00, + 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0, + 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B, + 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06, + 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06, + 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E, + 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00, + 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05, + 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00, + 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06, + 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF, + 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0, + 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, + 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05, + 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF, + 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0, + 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07, + 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07, + 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF, + 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF, + 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, + 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01, + 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1, + 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67, + 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00, + 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07, + 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07, + 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07, + 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00, + 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06, + 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67, + 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8, + 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0, + 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF, + 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02, + 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07, + 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06, + 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05, + 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80, + 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00, + 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06, + 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07, + 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05, + 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05, + 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80, + 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04, + 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF, + 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06, + 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, + 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00, + 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05, + 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07, + 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07, + 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07, + 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF, + 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07, + 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06, + 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05, + 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07, + 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00, + 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00, + 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77, + 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04, + 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0, + 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1, + 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07, + 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF, + 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, + 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, + 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, + 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77, + 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1, + 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07, + 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF, + 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06, + 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, + 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07, + 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07, + 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00, + 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00, + 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, + 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, + 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F, + 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00, + 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00, + 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA, + 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, + 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06, + 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF, + 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B, + 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, + 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09, + 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05, + 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07, + 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00, + 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF, + 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05, + 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00, + 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00, + 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05, + 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05, + 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00, + 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF, + 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09, + 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, + 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1, + 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00, + 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05, + 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00, + 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00, + 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05, + 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0, + 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67, + 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87, + 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9, + 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1, + 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF, + 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00, + 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0, + 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87, + 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, + 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67, + 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, + 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, + 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67, + 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, + 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, + 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01, + 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00, + 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF, + 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, + 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67, + 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09, + 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, + 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA, + 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87, + 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07, + 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80, + 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07, + 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80, + 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02, + 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09, + 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x05, 0x81, 0x02, 0x40, 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, 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, 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, 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, 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, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; -/* Here we want the physical address of the memory. - * This is used when initializing the contents of the area. - */ -static inline unsigned long kvirt_to_pa(unsigned long adr) +static unsigned char setup5[] = { + 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00, + 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00, + 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00, + 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00, + 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00, + 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00, + 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00, + 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01, + 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01, + 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01, + 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01, + 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01, + 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01, + 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01, + 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01, + 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02, + 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02, + 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02, + 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02, + 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02, + 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02, + 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02, + 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02, + 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03, + 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03, + 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03, + 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03, + 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03, + 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03, + 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03, + 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04, + 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04, + 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04, + 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04, + 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04, + 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04, + 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04, + 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05, + 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00 +}; + +static unsigned long kvirt_to_pa(unsigned long adr) { unsigned long kva, ret; @@ -106,526 +360,734 @@ static inline unsigned long kvirt_to_pa(unsigned long adr) return ret; } -static void * rvmalloc(unsigned long size) +/* rvmalloc / rvfree copied from usbvideo.c + * + * Not sure why these are not yet non-statics which I can reference through + * usbvideo.h the same as it is in 2.4.20. I bet this will get fixed sometime + * in the future. + * +*/ +static void *rvmalloc(unsigned long size) { - void * mem; + void *mem; unsigned long adr; - size=PAGE_ALIGN(size); - mem=vmalloc_32(size); - if (mem) - { - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr=(unsigned long) mem; - while (size > 0) - { - mem_map_reserve(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } + 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) { + mem_map_reserve(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; } + return mem; } -static void rvfree(void * mem, unsigned long size) +static void rvfree(void *mem, unsigned long size) { unsigned long adr; - if (mem) - { - adr=(unsigned long) mem; - while ((long) size > 0) - { - mem_map_unreserve(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - vfree(mem); + if (!mem) + return; + + adr = (unsigned long) mem; + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; } + vfree(mem); } + +struct vicam_camera { + u16 shutter_speed; // capture shutter speed + u16 gain; // capture gain -/****************************************************************************** - * - * Foo Bar - * - ******************************************************************************/ + u8 *raw_image; // raw data captured from the camera + u8 *framebuf; // processed data in RGB24 format -/** - * usb_vicam_debug_data - */ -static inline void usb_vicam_debug_data (const char *function, int size, const unsigned char *data) -{ - int i; + struct video_device vdev; // v4l video device + struct usb_device *udev; // usb device - if (!debug) - return; + struct semaphore busy_lock; // guard against SMP multithreading - printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", - function, size); - for (i = 0; i < size; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); -} + bool is_initialized; + u8 open_count; + u8 bulkEndpoint; + bool needsDummyRead; -/***************************************************************************** - * - * Send command to vicam - * - *****************************************************************************/ + u32 framebuf_size; // # of valid bytes in framebuf + u32 framebuf_read_start; // position in frame buf that a read is happening at. + +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *proc_entry; +#endif -static int vicam_sndctrl(int set, struct usb_vicam *vicam, unsigned short req, - unsigned short value, unsigned char *cp, int size) +}; + +static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id); +static void vicam_disconnect(struct usb_interface *intf); +static void read_frame(struct vicam_camera *cam, int framenum); + +static int +send_control_msg(struct usb_device *udev, u8 request, u16 value, u16 index, + unsigned char *cp, u16 size) { - int ret; - unsigned char *transfer_buffer = kmalloc (size, GFP_KERNEL); + int status; - /* Needs to return data I think, works for sending though */ + // for reasons not yet known to me, you can't send USB control messages + // with data in the module (if you are compiled as a module). Whatever + // the reason, copying it to memory allocated as kernel memory then + // doing the usb control message fixes the problem. + + unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL); memcpy(transfer_buffer, cp, size); - - ret = usb_control_msg ( vicam->udev, set ? usb_sndctrlpipe(vicam->udev, 0) : usb_rcvctrlpipe(vicam->udev, 0), req, (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, 0, transfer_buffer, size, HZ); + + status = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + request, + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, value, index, + transfer_buffer, size, HZ); kfree(transfer_buffer); - if (ret) - printk("vicam: error: %d\n", ret); - mdelay(100); - return ret; -} + if (status < 0) { + printk(KERN_INFO "Failed sending control message, error %d.\n", + status); + } -/***************************************************************************** - * - * Video4Linux Helpers - * - *****************************************************************************/ + return status; +} -static int vicam_get_capability(struct usb_vicam *vicam, struct video_capability *b) +static int +initialize_camera(struct vicam_camera *cam) { - dbg("vicam_get_capability"); - - strcpy(b->name, vicam->camera_name); - b->type = VID_TYPE_CAPTURE | VID_TYPE_MONOCHROME; - b->channels = 1; - b->audios = 0; - - b->maxwidth = vicam->width[vicam->sizes-1]; - b->maxheight = vicam->height[vicam->sizes-1]; - b->minwidth = vicam->width[0]; - b->minheight = vicam->height[0]; + struct usb_device *udev = cam->udev; + int status; + + if ((status = + send_control_msg(udev, 0xff, 0, 0, setup1, sizeof (setup1))) < 0) + return status; + if ((status = + send_control_msg(udev, 0xff, 0, 0, setup2, sizeof (setup2))) < 0) + return status; + if ((status = + send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0) + return status; + if ((status = + send_control_msg(udev, 0xff, 0, 0, setup4, sizeof (setup4))) < 0) + return status; + if ((status = + send_control_msg(udev, 0xff, 0, 0, setup5, sizeof (setup5))) < 0) + return status; + if ((status = + send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0) + return status; return 0; } - -static int vicam_get_channel(struct usb_vicam *vicam, struct video_channel *v) + +static int +set_camera_power(struct vicam_camera *cam, int state) { - dbg("vicam_get_channel"); + int status; - if (v->channel != 0) - return -EINVAL; - - v->flags = 0; - v->tuners = 0; - v->type = VIDEO_TYPE_CAMERA; - strcpy(v->name, "Camera"); + if ((status = send_control_msg(cam->udev, 0x50, state, 0, NULL, 0)) < 0) + return status; - return 0; -} - -static int vicam_set_channel(struct usb_vicam *vicam, struct video_channel *v) -{ - dbg("vicam_set_channel"); + if (state) { + send_control_msg(cam->udev, 0x55, 1, 0, NULL, 0); + } - if (v->channel != 0) - return -EINVAL; - return 0; } - -static int vicam_get_mmapbuffer(struct usb_vicam *vicam, struct video_mbuf *vm) + +static int +vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long ul_arg) { - int i; + void *arg = (void *)ul_arg; + struct vicam_camera *cam = file->private_data; + int retval = 0; - dbg("vicam_get_mmapbuffer"); + if (!cam) + return -ENODEV; - memset(vm, 0, sizeof(vm)); - vm->size = VICAM_NUMFRAMES * vicam->maxframesize; - vm->frames = VICAM_NUMFRAMES; + /* make this _really_ smp-safe */ + if (down_interruptible(&cam->busy_lock)) + return -EINTR; - for (i=0; i<VICAM_NUMFRAMES; i++) - vm->offsets[i] = vicam->maxframesize * i; + switch (ioctlnr) { + /* query capabilites */ + case VIDIOCGCAP: + { + struct video_capability b; + + DBG("VIDIOCGCAP\n"); + strcpy(b.name, "ViCam-based Camera"); + b.type = VID_TYPE_CAPTURE; + b.channels = 1; + b.audios = 0; + b.maxwidth = 320; /* VIDEOSIZE_CIF */ + b.maxheight = 240; + b.minwidth = 320; /* VIDEOSIZE_48_48 */ + b.minheight = 240; + + if (copy_to_user(arg, &b, sizeof (b))) + retval = -EFAULT; + + break; + } + /* get/set video source - we are a camera and nothing else */ + case VIDIOCGCHAN: + { + struct video_channel v; + + DBG("VIDIOCGCHAN\n"); + if (copy_from_user(&v, arg, sizeof (v))) { + retval = -EFAULT; + break; + } + if (v.channel != 0) { + retval = -EINVAL; + break; + } + + v.channel = 0; + strcpy(v.name, "Camera"); + v.tuners = 0; + v.flags = 0; + v.type = VIDEO_TYPE_CAMERA; + v.norm = 0; + + if (copy_to_user(arg, &v, sizeof (v))) + retval = -EFAULT; + break; + } - return 0; -} + case VIDIOCSCHAN: + { + int v; -static int vicam_get_picture(struct usb_vicam *vicam, struct video_picture *p) -{ - dbg("vicam_get_picture"); + if (copy_from_user(&v, arg, sizeof (v))) + retval = -EFAULT; + DBG("VIDIOCSCHAN %d\n", v); - /* This is probably where that weird 0x56 call goes */ - p->brightness = vicam->win.brightness; - p->hue = vicam->win.hue; - p->colour = vicam->win.colour; - p->contrast = vicam->win.contrast; - p->whiteness = vicam->win.whiteness; - p->depth = vicam->win.depth; - p->palette = vicam->win.palette; + if (retval == 0 && v != 0) + retval = -EINVAL; - return 0; -} + break; + } -static void synchronize(struct usb_vicam *vicam) -{ - DECLARE_WAITQUEUE(wait, current); - change_pending = 1; - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&vicam->wait, &wait); - if (change_pending) - schedule(); - remove_wait_queue(&vicam->wait, &wait); - set_current_state(TASK_RUNNING); - vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); - mdelay(10); - vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); - mdelay(10); -} + /* image properties */ + case VIDIOCGPICT: + { + struct video_picture vp; + DBG("VIDIOCGPICT\n"); + memset(&vp, 0, sizeof (struct video_picture)); + vp.brightness = cam->gain << 8; + vp.depth = 24; + vp.palette = VIDEO_PALETTE_RGB24; + if (copy_to_user + (arg, &vp, sizeof (struct video_picture))) + retval = -EFAULT; + break; + } -static void params_changed(struct usb_vicam *vicam) -{ -#if 1 - synchronize(vicam); - mdelay(10); - vicam_parameters(vicam); - printk(KERN_DEBUG "Submiting urb: %d\n", usb_submit_urb(vicam->readurb, GFP_KERNEL)); -#endif + case VIDIOCSPICT: + { + struct video_picture *vp = (struct video_picture *) arg; + + DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp->depth, + vp->palette); + + cam->gain = vp->brightness >> 8; + + if (vp->depth != 24 + || vp->palette != VIDEO_PALETTE_RGB24) + retval = -EINVAL; + + break; + } + + /* get/set capture window */ + case VIDIOCGWIN: + { + struct video_window vw; + vw.x = 0; + vw.y = 0; + vw.width = 320; + vw.height = 240; + vw.chromakey = 0; + vw.flags = 0; + vw.clips = NULL; + vw.clipcount = 0; + + DBG("VIDIOCGWIN\n"); + + if (copy_to_user + ((void *) arg, (void *) &vw, sizeof (vw))) + retval = -EFAULT; + + // I'm not sure what the deal with a capture window is, it is very poorly described + // in the doc. So I won't support it now. + break; + } + + case VIDIOCSWIN: + { + + struct video_window *vw = (struct video_window *) arg; + DBG("VIDIOCSWIN %d x %d\n", vw->width, vw->height); + + if ( vw->width != 320 || vw->height != 240 ) + retval = -EFAULT; + + break; + } + + /* mmap interface */ + case VIDIOCGMBUF: + { + struct video_mbuf vm; + int i; + + DBG("VIDIOCGMBUF\n"); + memset(&vm, 0, sizeof (vm)); + vm.size = + VICAM_MAX_FRAME_SIZE * VICAM_FRAMES; + vm.frames = VICAM_FRAMES; + for (i = 0; i < VICAM_FRAMES; i++) + vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i; + + if (copy_to_user + ((void *) arg, (void *) &vm, sizeof (vm))) + retval = -EFAULT; + + break; + } + + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + // int video_size; + + if (copy_from_user + ((void *) &vm, (void *) arg, sizeof (vm))) { + retval = -EFAULT; + break; + } + + DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format); + + if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 ) + retval = -EINVAL; + + // in theory right here we'd start the image capturing + // (fill in a bulk urb and submit it asynchronously) + // + // Instead we're going to do a total hack job for now and + // retrieve the frame in VIDIOCSYNC + + break; + } + + case VIDIOCSYNC: + { + int frame; + + if (copy_from_user((void *) &frame, arg, sizeof (int))) { + retval = -EFAULT; + break; + } + DBG("VIDIOCSYNC: %d\n", frame); + + read_frame(cam, frame); + + break; + } + + /* pointless to implement overlay with this camera */ + case VIDIOCCAPTURE: + case VIDIOCGFBUF: + case VIDIOCSFBUF: + case VIDIOCKEY: + retval = -EINVAL; + break; + + /* tuner interface - we have none */ + case VIDIOCGTUNER: + case VIDIOCSTUNER: + case VIDIOCGFREQ: + case VIDIOCSFREQ: + retval = -EINVAL; + break; + + /* audio interface - we have none */ + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + retval = -EINVAL; + break; + default: + retval = -ENOIOCTLCMD; + break; + } + + up(&cam->busy_lock); + return retval; } -static int vicam_set_picture(struct usb_vicam *vicam, struct video_picture *p) +static int +vicam_open(struct inode *inode, struct file *file) { - int changed = 0; - info("vicam_set_picture (%d)", p->brightness); - - -#define SET(x) \ - if (vicam->win.x != p->x) \ - vicam->win.x = p->x, changed = 1; - SET(brightness); - SET(hue); - SET(colour); - SET(contrast); - SET(whiteness); - SET(depth); - SET(palette); - if (changed) - params_changed(vicam); + struct video_device *dev = video_devdata(file); + struct vicam_camera *cam = + (struct vicam_camera *) dev->priv; + DBG("open\n"); + + if (!cam) { + printk(KERN_ERR + "vicam video_device improperly initialized"); + } - return 0; - /* Investigate what should be done maybe 0x56 type call */ - if (p->depth != 8) return 1; - if (p->palette != VIDEO_PALETTE_GREY) return 1; + down_interruptible(&cam->busy_lock); + + if (cam->open_count > 0) { + printk(KERN_INFO + "vicam_open called on already opened camera"); + up(&cam->busy_lock); + return -EBUSY; + } + + if (!cam->raw_image) { + cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL); + if (!cam->raw_image) { + up(&cam->busy_lock); + return -ENOMEM; + } + } + + if (!cam->framebuf) { + cam->framebuf = + rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); + if (!cam->framebuf) { + kfree(cam->raw_image); + up(&cam->busy_lock); + return -ENOMEM; + } + } + // First upload firmware, then turn the camera on + + if (!cam->is_initialized) { + initialize_camera(cam); + + cam->is_initialized = 1; + } + + set_camera_power(cam, 1); + + cam->needsDummyRead = 1; + cam->open_count++; + up(&cam->busy_lock); + + file->private_data = cam; + return 0; } -/* FIXME - vicam_sync_frame - important */ -static int vicam_sync_frame(struct usb_vicam *vicam, int frame) +static int +vicam_close(struct inode *inode, struct file *file) { - dbg("vicam_sync_frame"); + struct vicam_camera *cam = file->private_data; + DBG("close\n"); + set_camera_power(cam, 0); - if(frame <0 || frame >= VICAM_NUMFRAMES) - return -EINVAL; + cam->open_count--; - /* Probably need to handle various cases */ -/* ret=vicam_newframe(vicam, frame); - vicam->frame[frame].grabstate=FRAME_UNUSED; -*/ return 0; } - -static int vicam_get_window(struct usb_vicam *vicam, struct video_window *vw) -{ - dbg("vicam_get_window"); - vw->x = 0; - vw->y = 0; - vw->chromakey = 0; - vw->flags = 0; - vw->clipcount = 0; - vw->width = vicam->win.width; - vw->height = vicam->win.height; +inline int pin(int x) +{ + return((x > 255) ? 255 : ((x < 0) ? 0 : x)); +} - return 0; +inline void writepixel(char *rgb, int Y, int Cr, int Cb) +{ + Y = 1160 * (Y - 16); + + rgb[2] = pin( ( ( Y + ( 1594 * Cr ) ) + 500 ) / 1300 ); + rgb[1] = pin( ( ( Y - ( 392 * Cb ) - ( 813 * Cr ) ) + 500 ) / 1000 ); + rgb[0] = pin( ( ( Y + ( 2017 * Cb ) ) + 500 ) / 900 ); } -static int vicam_set_window(struct usb_vicam *vicam, struct video_window *vw) +#define DATA_HEADER_SIZE 64 + +// -------------------------------------------------------------------------------- +// vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB +// +// Copyright (C) 2002 Monroe Williams (monroe@pobox.com) +// -------------------------------------------------------------------------------- + +void vicam_decode_color( char *data, char *rgb) { - info("vicam_set_window"); - - if (vw->flags) - return -EINVAL; - if (vw->clipcount) - return -EINVAL; + int x,y; + int Cr, Cb; + int sign; + int prevX, nextX, prevY, nextY; + int skip; + unsigned char *src; + unsigned char *dst; - if (vicam->win.width == vw->width && vicam->win.height == vw->height) - return 0; + prevY = 512; + nextY = 512; - /* Pick largest mode that is smaller than specified res */ - /* If specified res is too small reject */ + src = data + DATA_HEADER_SIZE; + dst = rgb; - /* Add urb send to device... */ + for(y = 1; y < 241; y += 2) + { + // even line + sign = 1; + prevX = 1; + nextX = 1; - vicam->win.width = vw->width; - vicam->win.height = vw->height; - params_changed(vicam); + skip = 0; - return 0; -} + dst = rgb + (y-1)*320*3; + + for(x = 0; x < 512; x++) + { + if(x == 512-1) + nextX = -1; -/* FIXME - vicam_mmap_capture - important */ -static int vicam_mmap_capture(struct usb_vicam *vicam, struct video_mmap *vm) -{ - dbg("vicam_mmap_capture"); + Cr = sign * ((src[prevX] - src[0]) + (src[nextX] - src[0])) >> 1; + Cb = sign * ((src[prevY] - src[prevX + prevY]) + (src[prevY] - src[nextX + prevY]) + (src[nextY] - src[prevX + nextY]) + (src[nextY] - src[nextX + nextY])) >> 2; - /* usbvideo.c looks good for using here */ + writepixel( + dst + ((x*5)>>3)*3, + src[0] + (sign * (Cr >> 1)), + Cr, + Cb); - /* - if (vm->frame >= VICAM_NUMFRAMES) - return -EINVAL; - if (vicam->frame[vm->frame].grabstate != FRAME_UNUSED) - return -EBUSY; - vicam->frame[vm->frame].grabstate=FRAME_READY; - */ + src++; + sign *= -1; + prevX = -1; + } - /* No need to vicam_set_window here according to Alan */ + prevY = -512; - /* - if (!vicam->streaming) - vicam_start_stream(vicam); - */ + if(y == (242 - 2)) + nextY = -512; - /* set frame as ready */ + // odd line + sign = 1; + prevX = 1; + nextX = 1; - return 0; -} + skip = 0; -/***************************************************************************** - * - * Video4Linux - * - *****************************************************************************/ + dst = rgb + (y)*320*3; + + for(x = 0; x < 512; x++) + { + if(x == 512-1) + nextX = -1; + + Cr = sign * ((src[prevX + prevY] - src[prevY]) + (src[nextX + prevY] - src[prevY]) + (src[prevX + nextY] - src[nextY]) + (src[nextX + nextY] - src[nextY])) >> 2; + Cb = sign * ((src[0] - src[prevX]) + (src[0] - src[nextX])) >> 1; + + writepixel( + dst + ((x * 5)>>3)*3, + src[0] - (sign * (Cb >> 1)), + Cr, + Cb); + + src++; + sign *= -1; + prevX = -1; + } + } +} -static int vicam_v4l_open(struct inode *inode, struct file *file) +static void +read_frame(struct vicam_camera *cam, int framenum) { - struct video_device *vdev = video_devdata(file); - struct usb_vicam *vicam = (struct usb_vicam *)vdev; - int err = 0; - - dbg("vicam_v4l_open"); - down(&vicam->sem); - - vicam->fbuf = rvmalloc(vicam->maxframesize * VICAM_NUMFRAMES); - if (vicam->open_count) { - err = -EBUSY; - } else if (!vicam->fbuf) { - err =- ENOMEM; + unsigned char request[16]; + int realShutter; + int n; + int actual_length; + + memset(request, 0, 16); + request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain + + request[1] = 0; // 512x242 capture + + request[2] = 0x90; // the function of these two bytes + request[3] = 0x07; // is not yet understood + + if (cam->shutter_speed > 60) { + // Short exposure + realShutter = + ((-15631900 / cam->shutter_speed) + 260533) / 1000; + request[4] = realShutter & 0xFF; + request[5] = (realShutter >> 8) & 0xFF; + request[6] = 0x03; + request[7] = 0x01; } else { -#ifdef BLINKING - vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0); - info ("led on"); - vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0); -#endif - vicam->open_count++; - file->private_data = vdev; + // Long exposure + realShutter = 15600 / cam->shutter_speed - 1; + request[4] = 0; + request[5] = 0; + request[6] = realShutter & 0xFF; + request[7] = realShutter >> 8; } - up(&vicam->sem); - return err; -} - -static int vicam_v4l_close(struct inode *inode, struct file *file) -{ - struct video_device *vdev = file->private_data; - struct usb_vicam *vicam = (struct usb_vicam *)vdev; + // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0 + request[8] = 0; + // bytes 9-15 do not seem to affect exposure or image quality - dbg("vicam_v4l_close"); - - down(&vicam->sem); + n = send_control_msg(cam->udev, 0x51, 0x80, 0, request, 16); -#ifdef BLINKING - info ("led off"); - vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); -// vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); Leave it on -#endif + if (n < 0) { + printk(KERN_ERR + " Problem sending frame capture control message"); + return; + } - rvfree(vicam->fbuf, vicam->maxframesize * VICAM_NUMFRAMES); - vicam->fbuf = 0; - vicam->open_count=0; - file->private_data = NULL; + n = usb_bulk_msg(cam->udev, + usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint), + cam->raw_image, + 512 * 242 + 128, &actual_length, HZ*10); - up(&vicam->sem); - /* Why does se401.c have a usbdevice check here? */ - /* If device is unplugged while open, I guess we only may unregister now */ - return 0; -} + if (n < 0) { + printk(KERN_ERR "Problem during bulk read of frame data: %d\n", + n); + } -static int vicam_v4l_read(struct file *file, char *user_buf, - size_t buflen, loff_t *ppos) -{ - struct video_device *vdev = file->private_data; - //struct usb_vicam *vicam = (struct usb_vicam *)vdev; + vicam_decode_color(cam->raw_image, + cam->framebuf + + framenum * VICAM_MAX_FRAME_SIZE ); - dbg("vicam_v4l_read(%d)", buflen); + cam->framebuf_size = + 320 * 240 * VICAM_BYTES_PER_PIXEL; + cam->framebuf_read_start = 0; - if (!vdev || !buf) - return -EFAULT; + return; - if (copy_to_user(user_buf, buf2, buflen)) - return -EFAULT; - return buflen; } -static int vicam_v4l_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int +vicam_read( struct file *file, char *buf, size_t count, loff_t *ppos ) { - struct video_device *vdev = file->private_data; - struct usb_vicam *vicam = (struct usb_vicam *)vdev; - int ret = -EL3RST; + struct vicam_camera *cam = file->private_data; + DBG("read %d bytes.\n", (int) count); - if (!vicam->udev) - return -EIO; + if (!buf) + return -EINVAL; - down(&vicam->sem); + if (!count) + return -EINVAL; - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability *b = arg; - ret = vicam_get_capability(vicam,b); - dbg("name %s",b->name); - break; - } - case VIDIOCGFBUF: - { - struct video_buffer *vb = arg; - info("vicam_v4l_ioctl - VIDIOCGBUF - query frame buffer param"); - /* frame buffer not supported, not used */ - memset(vb, 0, sizeof(*vb)); - ret = 0; - break; - } - case VIDIOCGWIN: - { - struct video_window *vw = arg; - ret = vicam_get_window(vicam, vw); - break; - } - case VIDIOCSWIN: - { - struct video_window *vw = arg; - ret = vicam_set_window(vicam, vw); - break; + // This is some code that will hopefully allow us to do shell copies from + // the /dev/videoX to a file and have it actually work. + if (cam->framebuf_size != 0) { + if (cam->framebuf_read_start == cam->framebuf_size) { + cam->framebuf_size = cam->framebuf_read_start = 0; + return 0; + } else { + if (cam->framebuf_read_start + count <= + cam->framebuf_size) { + // count does not exceed available bytes + copy_to_user(buf, + (cam->framebuf) + + cam->framebuf_read_start, count); + cam->framebuf_read_start += count; + return count; + } else { + count = + cam->framebuf_size - + cam->framebuf_read_start; + copy_to_user(buf, + (cam->framebuf) + + cam->framebuf_read_start, count); + cam->framebuf_read_start = cam->framebuf_size; + return count; + } + } } - case VIDIOCGCHAN: - { - struct video_channel *v = arg; - ret = vicam_get_channel(vicam,v); - break; - } - case VIDIOCSCHAN: - { - struct video_channel *v = arg; - ret = vicam_set_channel(vicam,v); - break; - } - case VIDIOCGPICT: - { - struct video_picture *p = arg; - ret = vicam_get_picture(vicam,p); - break; - } - case VIDIOCSPICT: - { - struct video_picture *p = arg; - ret = vicam_set_picture(vicam,p); - break; - } - case VIDIOCGMBUF: - { - struct video_mbuf *vm = arg; - ret = vicam_get_mmapbuffer(vicam,vm); - break; - } - case VIDIOCMCAPTURE: - { - struct video_mmap *vm = arg; - ret = vicam_mmap_capture(vicam,vm); - break; - } - case VIDIOCSYNC: - { - int *frame = arg; - ret = vicam_sync_frame(vicam,*frame); - break; + down_interruptible(&cam->busy_lock); + + if (cam->needsDummyRead) { + read_frame(cam, 0); + cam->needsDummyRead = 0; } + // read_frame twice because the camera doesn't seem to take the shutter speed for the first one. - case VIDIOCKEY: - ret = 0; - - case VIDIOCCAPTURE: - case VIDIOCSFBUF: - case VIDIOCGTUNER: - case VIDIOCSTUNER: - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - case VIDIOCGUNIT: - ret = -EINVAL; + read_frame(cam, 0); - default: - { - info("vicam_v4l_ioctl - %ui",cmd); - ret = -ENOIOCTLCMD; - } - } /* end switch */ + if (count > cam->framebuf_size) + count = cam->framebuf_size; - up(&vicam->sem); - return ret; -} + copy_to_user(buf, cam->framebuf, count); -static int vicam_v4l_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(inode, file, cmd, arg, vicam_v4l_do_ioctl); + if (count != cam->framebuf_size) + cam->framebuf_read_start = count; + else + cam->framebuf_size = 0; + + up(&cam->busy_lock); + + return count; } -static int vicam_v4l_mmap(struct file *file, struct vm_area_struct *vma) + +static int +vicam_mmap(struct file *file, struct vm_area_struct *vma) { - struct video_device *vdev = file->private_data; - struct usb_vicam *vicam = (struct usb_vicam *)vdev; + // TODO: allocate the raw frame buffer if necessary + unsigned long page, pos; unsigned long start = vma->vm_start; unsigned long size = vma->vm_end-vma->vm_start; - unsigned long page, pos; + struct vicam_camera *cam = file->private_data; - down(&vicam->sem); - - if (vicam->udev == NULL) { - up(&vicam->sem); - return -EIO; - } -#if 0 - if (size > (((VICAM_NUMFRAMES * vicam->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { - up(&vicam->sem); - return -EINVAL; + if (!cam) + return -ENODEV; + + DBG("vicam_mmap: %ld\n", size); + + /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes + * to the size the application requested for mmap and it was screwing apps up. + if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE) + return -EINVAL; + */ + + /* make this _really_ smp-safe */ + if (down_interruptible(&cam->busy_lock)) + return -EINTR; + + if (!cam->framebuf) { /* we do lazy allocation */ + cam->framebuf = + rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); + if (!cam->framebuf) { + up(&cam->busy_lock); + return -ENOMEM; + } } -#endif - pos = (unsigned long)vicam->fbuf; + + pos = (unsigned long)cam->framebuf; while (size > 0) { page = kvirt_to_pa(pos); - if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - up(&vicam->sem); + if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) return -EAGAIN; - } + start += PAGE_SIZE; pos += PAGE_SIZE; if (size > PAGE_SIZE) @@ -633,299 +1095,315 @@ static int vicam_v4l_mmap(struct file *file, struct vm_area_struct *vma) else size = 0; } - up(&vicam->sem); - return 0; + up(&cam->busy_lock); + + return 0; } -/* FIXME - vicam_template - important */ -static struct file_operations vicam_fops = { - .owner = THIS_MODULE, - .open = vicam_v4l_open, - .release = vicam_v4l_close, - .read = vicam_v4l_read, - .mmap = vicam_v4l_mmap, - .ioctl = vicam_v4l_ioctl, - .llseek = no_llseek, -}; -static struct video_device vicam_template = { - .owner = THIS_MODULE, - .name = "vicam USB camera", - .type = VID_TYPE_CAPTURE, - .hardware = VID_HARDWARE_SE401, /* need to ask for own id */ - .fops = &vicam_fops, -}; +#ifdef CONFIG_PROC_FS -/****************************************************************************** - * - * Some Routines - * - ******************************************************************************/ +static struct proc_dir_entry *vicam_proc_root = NULL; -/* -Flash the led -vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0); -info ("led on"); -vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0); -info ("led off"); -vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); -vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); -*/ +static int +vicam_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *out = page; + int len; + struct vicam_camera *cam = (struct vicam_camera *) data; + + out += + sprintf(out, "Vicam-based WebCam Linux Driver.\n"); + out += sprintf(out, "(c) 2002 Joe Burks (jburks@wavicle.org)\n"); + out += sprintf(out, "vicam stats:\n"); + out += sprintf(out, " Shutter Speed: 1/%d\n", cam->shutter_speed); + out += sprintf(out, " Gain: %d\n", cam->gain); + + len = out - page; + len -= off; + if (len < count) { + *eof = 1; + if (len <= 0) + return 0; + } else + len = count; + + *start = page + off; + return len; +} -static void vicam_bulk(struct urb *urb) +static int +vicam_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) { - struct usb_vicam *vicam = urb->context; + char *in; + char *start; + struct vicam_camera *cam = (struct vicam_camera *) data; - /* if (!vicam || !vicam->dev || !vicam->used) - return; - */ + in = kmalloc(count + 1, GFP_KERNEL); + if (!in) + return -ENOMEM; - if (urb->status) - printk("vicam%d: nonzero read/write bulk status received: %d", - 0, urb->status); + in[count] = 0; // I'm not sure buffer is gauranteed to be null terminated + // so I do this to make sure I have a null in there. - urb->actual_length = 0; - urb->dev = vicam->udev; + strncpy(in, buffer, count); - memcpy(buf2, buf+64, 0x1e480); - if (vicam->fbuf) - memcpy(vicam->fbuf, buf+64, 0x1e480); + start = strstr(in, "gain="); + if (start + && (start == in || *(start - 1) == ' ' || *(start - 1) == ',')) + cam->gain = simple_strtoul(start + 5, NULL, 10); - if (!change_pending) { - if (usb_submit_urb(urb, GFP_ATOMIC)) - dbg("failed resubmitting read urb"); - } else { - change_pending = 0; - wake_up_interruptible(&vicam->wait); - } + start = strstr(in, "shutter="); + if (start + && (start == in || *(start - 1) == ' ' || *(start - 1) == ',')) + cam->shutter_speed = simple_strtoul(start + 8, NULL, 10); + + kfree(in); + return count; } -static int vicam_parameters(struct usb_vicam *vicam) +void +vicam_create_proc_root(void) { - unsigned char req[0x10]; - unsigned int shutter; - shutter = 10; + vicam_proc_root = create_proc_entry("video/vicam", S_IFDIR, 0); - switch (vicam->win.width) { - case 512: - default: - memcpy(req, s512x242bw, 0x10); - break; - case 256: - memcpy(req, s256x242bw, 0x10); - break; - case 128: - memcpy(req, s128x122bw, 0x10); - break; - } + if (vicam_proc_root) + vicam_proc_root->owner = THIS_MODULE; + else + printk(KERN_ERR + "could not create /proc entry for vicam!"); +} +void +vicam_destroy_proc_root(void) +{ + if (vicam_proc_root) + remove_proc_entry("video/vicam", 0); +} - mdelay(10); - vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0); - info ("led on"); - vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0); +void +vicam_create_proc_entry(void *ptr) +{ + struct vicam_camera *cam = (struct vicam_camera *) ptr; - mdelay(10); + char name[7]; + struct proc_dir_entry *ent; - shutter = vicam->win.contrast / 256; - if (shutter == 0) - shutter = 1; - printk("vicam_parameters: brightness %d, shutter %d\n", vicam->win.brightness, shutter ); - req[0] = vicam->win.brightness /256; - shutter = 15600/shutter - 1; - req[6] = shutter & 0xff; - req[7] = (shutter >> 8) & 0xff; - vicam_sndctrl(1, vicam, VICAM_REQ_CAPTURE, 0x80, req, 0x10); - mdelay(10); - vicam_sndctrl(0, vicam, VICAM_REQ_GET_SOMETHIN, 0, buf, 0x10); - mdelay(10); + DBG(KERN_INFO "vicam: creating proc entry\n"); - return 0; + if (!vicam_proc_root || !cam) { + printk(KERN_INFO + "vicam: could not create proc entry, %s pointer is null.\n", + (!cam ? "camera" : "root")); + return; + } + + sprintf(name, "video%d", cam->vdev.minor); + + ent = + create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, + vicam_proc_root); + if (!ent) + return; + + ent->data = cam; + ent->read_proc = vicam_read_proc; + ent->write_proc = vicam_write_proc; + ent->size = 512; + cam->proc_entry = ent; } -static int vicam_init(struct usb_vicam *vicam) +void +vicam_destroy_proc_entry(void *ptr) { - int width[] = {128, 256, 512}; - int height[] = {122, 242, 242}; - - dbg("vicam_init"); - buf = kmalloc(0x1e480, GFP_KERNEL); - buf2 = kmalloc(0x1e480, GFP_KERNEL); - if ((!buf) || (!buf2)) { - printk("Not enough memory for vicam!\n"); - goto error; - } + struct vicam_camera *cam = (struct vicam_camera *) ptr; + char name[7]; - /* do we do aspect correction in kernel or not? */ - vicam->sizes = 3; - vicam->width = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL); - vicam->height = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL); - memcpy(vicam->width, &width, sizeof(width)); - memcpy(vicam->height, &height, sizeof(height)); - vicam->maxframesize = vicam->width[vicam->sizes-1] * vicam->height[vicam->sizes-1]; + if (!cam || !cam->proc_entry) + return; - /* Download firmware to camera */ - vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware1, sizeof(firmware1)); - vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex1, sizeof(findex1)); - vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup)); - vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware2, sizeof(firmware2)); - vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex2, sizeof(findex2)); - vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup)); + sprintf(name, "video%d", cam->vdev.minor); + remove_proc_entry(name, vicam_proc_root); + cam->proc_entry = NULL; - vicam_parameters(vicam); +} - FILL_BULK_URB(vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81), - buf, 0x1e480, vicam_bulk, vicam); - printk(KERN_DEBUG "Submiting urb: %d\n", usb_submit_urb(vicam->readurb, GFP_KERNEL)); +#endif +int +vicam_video_init(struct video_device *vdev) +{ + // This would normally create the proc entry for this camera +#ifdef CONFIG_PROC_FS + vicam_create_proc_entry(vdev->priv); +#endif return 0; -error: - if (buf) - kfree(buf); - if (buf2) - kfree(buf2); - return 1; } -static int vicam_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct usb_vicam *vicam; - char *camera_name=NULL; +static struct file_operations vicam_fops = { + .owner = THIS_MODULE, + .open = vicam_open, + .release =vicam_close, + .read = vicam_read, + .mmap = vicam_mmap, + .ioctl = vicam_ioctl, + .llseek = no_llseek, +}; + +static struct video_device vicam_template = { + .owner = THIS_MODULE, + .name = "ViCam-based USB Camera", + .type = VID_TYPE_CAPTURE, + .hardware = VID_HARDWARE_VICAM, + .fops = &vicam_fops, +// .initialize = vicam_video_init, + .minor = -1, +}; + +/* table of devices that work with this driver */ +static struct usb_device_id vicam_table[] = { + {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)}, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, vicam_table); - dbg("vicam_probe"); +static struct usb_driver vicam_driver = { + name:"vicam", + probe:vicam_probe, + disconnect:vicam_disconnect, + id_table:vicam_table +}; +/** + * vicam_probe + * + * Called by the usb core when a new device is connected that it thinks + * this driver might be interested in. + */ +static int +vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + int bulkEndpoint = 0; + const struct usb_interface_descriptor *interface; + const struct usb_endpoint_descriptor *endpoint; + struct vicam_camera *cam; + /* See if the device offered us matches what we can accept */ - if ((udev->descriptor.idVendor != USB_VICAM_VENDOR_ID) || - (udev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) { + if ((dev->descriptor.idVendor != USB_VICAM_VENDOR_ID) || + (dev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) { return -ENODEV; } - - camera_name="3Com HomeConnect USB"; - info("ViCAM camera found: %s", camera_name); - - vicam = kmalloc (sizeof(struct usb_vicam), GFP_KERNEL); - if (vicam == NULL) { - err ("couldn't kmalloc vicam struct"); - return -ENOMEM; + + printk(KERN_INFO "ViCam based webcam connected\n"); + + interface = &intf->altsetting[0]; + + DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n", + ifnum, (unsigned) (interface->bNumEndpoints)); + endpoint = &interface->endpoint[0]; + + if ((endpoint->bEndpointAddress & 0x80) && + ((endpoint->bmAttributes & 3) == 0x02)) { + /* we found a bulk in endpoint */ + bulkEndpoint = endpoint->bEndpointAddress; + } else { + printk(KERN_ERR + "No bulk in endpoint was found ?! (this is bad)\n"); } - memset(vicam, 0, sizeof(*vicam)); - vicam->readurb = usb_alloc_urb(0, GFP_KERNEL); - if (!vicam->readurb) { - kfree(vicam); + if ((cam = + kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) { + printk(KERN_WARNING + "could not allocate kernel memory for vicam_camera struct\n"); return -ENOMEM; } - vicam->udev = udev; - vicam->camera_name = camera_name; - vicam->win.brightness = 128; - vicam->win.contrast = 10; + memset(cam, 0, sizeof (struct vicam_camera)); - /* FIXME */ - if (vicam_init(vicam)) { - usb_free_urb(vicam->readurb); - kfree(vicam); - return -ENOMEM; - } - memcpy(&vicam->vdev, &vicam_template, sizeof(vicam_template)); - memcpy(vicam->vdev.name, vicam->camera_name, strlen(vicam->camera_name)); - - if (video_register_device(&vicam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { - err("video_register_device"); - usb_free_urb(vicam->readurb); - kfree(vicam); + cam->shutter_speed = 15; + + init_MUTEX(&cam->busy_lock); + + memcpy(&cam->vdev, &vicam_template, + sizeof (vicam_template)); + cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only + + cam->udev = dev; + cam->bulkEndpoint = bulkEndpoint; + + if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) { + kfree(cam); + printk(KERN_WARNING "video_register_device failed\n"); return -EIO; } - info("registered new video device: video%d", vicam->vdev.minor); - - init_MUTEX (&vicam->sem); - init_waitqueue_head(&vicam->wait); + printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor); + + dev_set_drvdata(&intf->dev, cam); - dev_set_drvdata (&intf->dev, vicam); return 0; } - -/* FIXME - vicam_disconnect - important */ -static void vicam_disconnect(struct usb_interface *intf) +static void +vicam_disconnect(struct usb_interface *intf) { - struct usb_vicam *vicam; + struct vicam_camera *cam = dev_get_drvdata(&intf->dev); - vicam = dev_get_drvdata (&intf->dev); + dev_set_drvdata ( &intf->dev, NULL ); + usb_put_dev(cam->udev); + + cam->udev = NULL; + + video_unregister_device(&cam->vdev); - dev_set_drvdata (&intf->dev, NULL); +#ifdef CONFIG_PROC_FS + vicam_destroy_proc_entry(cam); +#endif - if (vicam) { - video_unregister_device(&vicam->vdev); - vicam->udev = NULL; -/* - vicam->frame[0].grabstate = FRAME_ERROR; - vicam->frame[1].grabstate = FRAME_ERROR; -*/ + if (cam->raw_image) + kfree(cam->raw_image); + if (cam->framebuf) + rvfree(cam->framebuf, + VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); - /* Free buffers and shit */ - info("%s disconnected", vicam->camera_name); - synchronize(vicam); + kfree(cam); - if (!vicam->open_count) { - /* Other random junk */ - usb_free_urb(vicam->readurb); - kfree(vicam); - vicam = NULL; - } - } + printk(KERN_DEBUG "ViCam-based WebCam disconnected\n"); } -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver vicam_driver = { - .owner = THIS_MODULE, - .name = "vicam", - .probe = vicam_probe, - .disconnect = vicam_disconnect, - .id_table = vicam_table, -}; - -/****************************************************************************** - * - * Module Routines - * - ******************************************************************************/ - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -/* Module paramaters */ -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - -static int __init usb_vicam_init(void) +/* + */ +static int __init +usb_vicam_init(void) { - int result; - - printk("VICAM: initializing\n"); - /* register this driver with the USB subsystem */ - result = usb_register(&vicam_driver); - if (result < 0) { - err("usb_register failed for the "__FILE__" driver. Error number %d", - result); - return -1; - } - - info(DRIVER_VERSION " " DRIVER_AUTHOR); - info(DRIVER_DESC); + DBG(KERN_INFO "ViCam-based WebCam driver startup\n"); +#ifdef CONFIG_PROC_FS + vicam_create_proc_root(); +#endif + if (usb_register(&vicam_driver) != 0) + printk(KERN_WARNING "usb_register failed!\n"); return 0; } -static void __exit usb_vicam_exit(void) +static void __exit +usb_vicam_exit(void) { - /* deregister this driver with the USB subsystem */ + DBG(KERN_INFO + "ViCam-based WebCam driver shutdown\n"); + usb_deregister(&vicam_driver); +#ifdef CONFIG_PROC_FS + vicam_destroy_proc_root(); +#endif } module_init(usb_vicam_init); module_exit(usb_vicam_exit); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/media/vicam.h b/drivers/usb/media/vicam.h deleted file mode 100644 index 4527d8e644f7..000000000000 --- a/drivers/usb/media/vicam.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * - * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver - * Christopher L Cheney (C) 2001 - * - */ - -#ifndef __LINUX_VICAM_H -#define __LINUX_VICAM_H - - -#ifdef CONFIG_USB_DEBUG - static int debug = 1; -#else - static int debug; -#endif - -/* Use our own dbg macro */ -#undef dbg -#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0) - -#define VICAM_NUMFRAMES 30 -#define VICAM_NUMSBUF 1 - -/* USB REQUEST NUMBERS */ -#define VICAM_REQ_VENDOR 0xff -#define VICAM_REQ_CAMERA_POWER 0x50 -#define VICAM_REQ_CAPTURE 0x51 -#define VICAM_REQ_LED_CONTROL 0x55 -#define VICAM_REQ_GET_SOMETHIN 0x56 - -/* not required but lets you know camera is on */ -/* camera must be on to turn on led */ -/* 0x01 always on 0x03 on when picture taken (flashes) */ - -struct picture_parm -{ - int width; - int height; - int brightness; - int hue; - int colour; - int contrast; - int whiteness; - int depth; - int palette; -}; - -struct vicam_scratch { - unsigned char *data; - volatile int state; - int offset; - int length; -}; - -/* Structure to hold all of our device specific stuff */ -struct usb_vicam -{ - struct video_device vdev; - struct usb_device *udev; - - int open_count; /* number of times this port has been opened */ - struct semaphore sem; /* locks this structure */ - wait_queue_head_t wait; /* Processes waiting */ - - int streaming; - - /* v4l stuff */ - char *camera_name; - char *fbuf; - struct urb *urb[VICAM_NUMSBUF]; - int sizes; - int *width; - int *height; - int maxframesize; - struct picture_parm win; - struct proc_dir_entry *proc_entry; /* /proc/se401/videoX */ - struct urb *readurb; -}; - -#endif diff --git a/drivers/usb/media/vicamurbs.h b/drivers/usb/media/vicamurbs.h deleted file mode 100644 index 5068d01330c3..000000000000 --- a/drivers/usb/media/vicamurbs.h +++ /dev/null @@ -1,332 +0,0 @@ -/* - * - * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver - * Christopher L Cheney (C) 2001 - * - */ - - -#ifndef __LINUX_VICAMURBS_H -#define __LINUX_VICAMURBS_H - -/* -------------------------------------------------------------------------- */ - -/* FIXME - Figure out transfers so that this doesn't need to be here - * - * Notice: in pieces below, "0" means other code will fill it while "0x00" means this is zero */ - -/* Request 0x51 Image Setup */ - -#if 0 -/* 128x98 ? 0x3180 size */ -static unsigned char s128x98bw[] = { - 0, 0x34, 0xC4, 0x00, 0x00, 0x00, 0, 0, - 0x18, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 -}; -#endif - -/* 128x122 3D80 size */ -static unsigned char s128x122bw[] = { - 0, 0x34, 0xF4, 0x00, 0x00, 0x00, 0, 0, - 0x00, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 -}; - -/* 256x242 ? 0xF280 size */ -static unsigned char s256x242bw[] = { - 0, 0x03, 0xC8, 0x03, 0x00, 0x00, 0, 0, - 0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 -}; - -/* 512x242 0x1E480 size */ -static unsigned char s512x242bw[] = { - 0, 0x05, 0x90, 0x07, 0x00, 0x00, 0, 0, - 0x00, 0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 -}; - -/* In s512x242: - byte 0: gain -- higher number means brighter image - byte 6, 7: shutter speed, little-endian; set this to 15600 * (shutter speed) - 1. (Where shutter speed is something like 1/1000). -*/ - -/* -------------------------------------------------------------------------- */ - -static unsigned char fsetup[] = { - 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, - - 0x00, 0x00 -}; - -static unsigned char firmware1[] = { - 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, - - 0xE7, 0x67, 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, - 0xDE, 0x00, 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, - 0xC0, 0x17, 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, - 0x00, 0x00, 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00 -}; - -static unsigned char findex1[] = { - 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, - - 0x18, 0x00, 0x00, 0x00 -}; - -static unsigned char firmware2[] = { - 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, - - 0xE7, 0x07, 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, - 0x00, 0x00, 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, - 0xAA, 0x00, 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, - 0xE7, 0x07, 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, - 0x7C, 0x00, 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, - 0x18, 0x00, 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, - 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, - 0xFF, 0xFF, 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, - 0x24, 0xC0, 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, - 0xE7, 0x07, 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, - 0x01, 0x00, 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, - 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, - 0x09, 0xC1, 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, - 0xE7, 0x09, 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, - 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, - 0xC0, 0xDF, 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, - 0x17, 0x02, 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, - 0x01, 0x00, 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, - 0xFF, 0xFF, 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, - 0x00, 0x00, 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, - 0xC6, 0x00, 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, - 0xC1, 0x05, 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, - 0x27, 0xDA, 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, - 0x0B, 0x06, 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, - 0x9F, 0xAF, 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, - 0xFC, 0x05, 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, - 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, - 0xE7, 0x09, 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, - 0x02, 0x06, 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, - 0xFC, 0x05, 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, - 0x27, 0xDA, 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, - 0xFA, 0x05, 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, - 0x9F, 0xAF, 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, - 0x40, 0x00, 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, - 0x9F, 0xAF, 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, - 0x02, 0x00, 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, - 0x9F, 0xA0, 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, - 0x09, 0x06, 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, - 0x01, 0x00, 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, - 0xE7, 0x07, 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, - 0x47, 0xAF, 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, - 0x2E, 0x00, 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, - 0x09, 0x06, 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, - 0xC0, 0x57, 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, - 0xC0, 0x57, 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, - 0x55, 0x00, 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, - 0x9F, 0xC0, 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, - 0xC1, 0x0B, 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, - 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, - 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, - 0x2F, 0x0E, 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, - 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, - 0x28, 0x05, 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, - 0x02, 0x00, 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, - 0x09, 0x06, 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, - 0x7F, 0xFF, 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, - 0x22, 0xC0, 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, - 0xE7, 0x87, 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, - 0xB8, 0x05, 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, - 0x9F, 0xAF, 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, - 0x24, 0xC0, 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, - 0xC8, 0x07, 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, - 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, - 0x9F, 0xAF, 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, - 0x9F, 0xAF, 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, - 0x24, 0xC0, 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, - 0x00, 0x01, 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, - 0x0F, 0xC1, 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, - 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, - 0x08, 0x00, 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, - 0xEF, 0x07, 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, - 0xEF, 0x07, 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, - 0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, - 0x00, 0x00, 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, - 0x09, 0x06, 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, - 0xE7, 0x67, 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, - 0x17, 0xD8, 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, - 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, - 0x97, 0xCF, 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, - 0xDA, 0x02, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, - 0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, - 0x0E, 0x06, 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, - 0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, - 0x00, 0x80, 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, - 0x02, 0x00, 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, - 0x06, 0x06, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, - 0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, - 0xE2, 0x05, 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, - 0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, - 0x00, 0x80, 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, - 0x66, 0x04, 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, - 0x97, 0xCF, 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, - 0x0C, 0x06, 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, - 0xC0, 0x07, 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, - 0x68, 0x00, 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, - 0x44, 0x05, 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, - 0xE0, 0x07, 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, - 0xE8, 0x07, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, - 0xE0, 0x07, 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, - 0x97, 0xCF, 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, - 0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, - 0x0E, 0x06, 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, - 0xFE, 0x05, 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, - 0xE7, 0x07, 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, - 0x07, 0x00, 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, - 0x02, 0x00, 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, - 0xEF, 0x77, 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, - 0x14, 0x04, 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, - 0x37, 0xC0, 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, - 0x0F, 0xC1, 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, - 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, - 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, - 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, - 0xC8, 0x07, 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, - 0xC0, 0x07, 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, - 0xC1, 0x77, 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, - 0x75, 0xC1, 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, - 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, - 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, - 0x06, 0x06, 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, - 0xC1, 0x07, 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, - 0xEF, 0x07, 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, - 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, - 0x01, 0x00, 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, - 0x01, 0x00, 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, - 0x28, 0x05, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, - 0x30, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, - 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, - 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, - 0x03, 0x00, 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, - 0x08, 0xDA, 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, - 0xC1, 0x07, 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, - 0x06, 0x06, 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, - 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, - 0xC1, 0x0B, 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, - 0xC0, 0x07, 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, - 0xE7, 0x09, 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, - 0xFA, 0x05, 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, - 0xE7, 0x07, 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, - 0x40, 0x00, 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, - 0x9F, 0xAF, 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, - 0xE2, 0x05, 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, - 0x23, 0x00, 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, - 0x04, 0x00, 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, - 0x28, 0x05, 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, - 0xE6, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, - 0x07, 0x00, 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, - 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, - 0xC1, 0x09, 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, - 0xC0, 0x07, 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, - 0xC1, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, - 0x0D, 0x00, 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, - 0x28, 0x05, 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, - 0x32, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, - 0x0F, 0x00, 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, - 0x28, 0x05, 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, - 0x24, 0xC0, 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, - 0xC0, 0x67, 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, - 0xE7, 0x87, 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, - 0xFF, 0xF9, 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, - 0x72, 0xC1, 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, - 0x97, 0xCF, 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, - 0xFF, 0x00, 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, - 0x24, 0xC0, 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, - 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, - 0x9F, 0xAF, 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, - 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, - 0x40, 0x00, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, - 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, - 0xE7, 0x67, 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, - 0xFF, 0xFE, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, - 0x24, 0xC0, 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, - 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, - 0x40, 0x00, 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, - 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, - 0x24, 0xC0, 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, - 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, - 0xE8, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, - 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, - 0x00, 0xDA, 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, - 0xE7, 0x87, 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, - 0xE7, 0x07, 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, - 0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, - 0xE7, 0x07, 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, - 0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, - 0x09, 0x02, 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, - 0x96, 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 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, 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, 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, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static unsigned char findex2[] = { - 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, - - 0x0E, 0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, - 0x26, 0x00, 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, - 0x92, 0x00, 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, - 0xB8, 0x00, 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, - 0xCE, 0x00, 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, - 0xE0, 0x00, 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, - 0xEC, 0x00, 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, - 0x0A, 0x01, 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, - 0x22, 0x01, 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, - 0x36, 0x01, 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, - 0x72, 0x01, 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, - 0x88, 0x01, 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, - 0xA0, 0x01, 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, - 0xB4, 0x01, 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, - 0xF6, 0x01, 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, - 0x3C, 0x02, 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, - 0x56, 0x02, 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, - 0x84, 0x02, 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, - 0x8E, 0x02, 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, - 0xAE, 0x02, 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, - 0xC0, 0x02, 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, - 0xD4, 0x02, 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, - 0xF8, 0x02, 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, - 0x24, 0x03, 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, - 0x3C, 0x03, 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, - 0x58, 0x03, 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, - 0x7A, 0x03, 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, - 0xB2, 0x03, 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, - 0xD4, 0x03, 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, - 0xFC, 0x03, 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, - 0x32, 0x04, 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, - 0x42, 0x04, 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, - 0x54, 0x04, 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, - 0x62, 0x04, 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, - 0x80, 0x04, 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, - 0x9A, 0x04, 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, - 0xB4, 0x04, 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, - 0x2A, 0x05, 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00 -}; - -#endif diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 45c76c1b8b97..15b5030ebee8 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -2092,7 +2092,7 @@ static const struct usb_device_id products [] = { #ifdef CONFIG_USB_EPSON2888 { USB_DEVICE (0x0525, 0x2888), // EPSON USB client - driver_info: (unsigned long) &epson2888_info, + .driver_info = (unsigned long) &epson2888_info, }, #endif diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 81fa9f2479eb..11ec19125bcd 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2617,47 +2617,47 @@ static void edge_shutdown (struct usb_serial *serial) static struct usb_serial_device_type edgeport_1port_device = { - owner: THIS_MODULE, - name: "Edgeport TI 1 port adapter", - id_table: edgeport_1port_id_table, - num_interrupt_in: 1, - num_bulk_in: 1, - num_bulk_out: 1, - num_ports: 1, - open: edge_open, - close: edge_close, - throttle: edge_throttle, - unthrottle: edge_unthrottle, - attach: edge_startup, - shutdown: edge_shutdown, - ioctl: edge_ioctl, - set_termios: edge_set_termios, - write: edge_write, - write_room: edge_write_room, - chars_in_buffer: edge_chars_in_buffer, - break_ctl: edge_break, + .owner = THIS_MODULE, + .name = "Edgeport TI 1 port adapter", + .id_table = edgeport_1port_id_table, + .num_interrupt_in = 1, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = edge_open, + .close = edge_close, + .throttle = edge_throttle, + .unthrottle = edge_unthrottle, + .attach = edge_startup, + .shutdown = edge_shutdown, + .ioctl = edge_ioctl, + .set_termios = edge_set_termios, + .write = edge_write, + .write_room = edge_write_room, + .chars_in_buffer = edge_chars_in_buffer, + .break_ctl = edge_break, }; static struct usb_serial_device_type edgeport_2port_device = { - owner: THIS_MODULE, - name: "Edgeport TI 2 port adapter", - id_table: edgeport_2port_id_table, - num_interrupt_in: 1, - num_bulk_in: 2, - num_bulk_out: 2, - num_ports: 2, - open: edge_open, - close: edge_close, - throttle: edge_throttle, - unthrottle: edge_unthrottle, - attach: edge_startup, - shutdown: edge_shutdown, - ioctl: edge_ioctl, - set_termios: edge_set_termios, - write: edge_write, - write_room: edge_write_room, - chars_in_buffer: edge_chars_in_buffer, - break_ctl: edge_break, + .owner = THIS_MODULE, + .name = "Edgeport TI 2 port adapter", + .id_table = edgeport_2port_id_table, + .num_interrupt_in = 1, + .num_bulk_in = 2, + .num_bulk_out = 2, + .num_ports = 2, + .open = edge_open, + .close = edge_close, + .throttle = edge_throttle, + .unthrottle = edge_unthrottle, + .attach = edge_startup, + .shutdown = edge_shutdown, + .ioctl = edge_ioctl, + .set_termios = edge_set_termios, + .write = edge_write, + .write_room = edge_write_room, + .chars_in_buffer = edge_chars_in_buffer, + .break_ctl = edge_break, }; diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 4b133ec1ad66..4cb3cb879e1b 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1237,16 +1237,17 @@ int usb_serial_probe(struct usb_interface *interface, } #if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE) -#if 0 /* BEGIN HORRIBLE HACK FOR PL2303 */ /* this is needed due to the looney way its endpoints are set up */ - if (ifnum == 1) { - if (((dev->descriptor.idVendor == PL2303_VENDOR_ID) && - (dev->descriptor.idProduct == PL2303_PRODUCT_ID)) || - ((dev->descriptor.idVendor == ATEN_VENDOR_ID) && - (dev->descriptor.idProduct == ATEN_PRODUCT_ID))) { + if (((dev->descriptor.idVendor == PL2303_VENDOR_ID) && + (dev->descriptor.idProduct == PL2303_PRODUCT_ID)) || + ((dev->descriptor.idVendor == ATEN_VENDOR_ID) && + (dev->descriptor.idProduct == ATEN_PRODUCT_ID))) { + //if (ifnum == 1) { + if (interface != &dev->actconfig->interface[0]) { /* check out the endpoints of the other interface*/ - interface = &dev->actconfig->interface[ifnum ^ 1]; + //interface = &dev->actconfig->interface[ifnum ^ 1]; + interface = &dev->actconfig->interface[0]; iface_desc = &interface->altsetting[0]; for (i = 0; i < iface_desc->bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i]; @@ -1259,10 +1260,19 @@ int usb_serial_probe(struct usb_interface *interface, } } } + + /* Now make sure the PL-2303 is configured correctly. + * If not, give up now and hope this hack will work + * properly during a later invocation of usb_serial_probe + */ + if (num_bulk_in == 0 || num_bulk_out == 0) { + info("PL-2303 hack: descriptors matched but endpoints did not"); + kfree (serial); + return -ENODEV; + } } /* END HORRIBLE HACK FOR PL2303 */ #endif -#endif /* found all that we need */ info("%s converter detected", type->name); diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 69ede41337e6..65164618696c 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -669,7 +669,7 @@ static int clie_3_5_startup (struct usb_serial *serial) /* get the interface number */ result = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), USB_REQ_GET_INTERFACE, - USB_DIR_IN | USB_DT_DEVICE, + USB_DIR_IN | USB_RECIP_INTERFACE, 0, 0, &data, 1, HZ * 3); if (result < 0) { err("%s: get interface number failed: %d", __FUNCTION__, result); diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 57ad099241fd..5ba0d8471674 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -334,6 +334,12 @@ static int whiteheat_attach (struct usb_serial *serial) command_port = &serial->port[COMMAND_PORT]; pipe = usb_sndbulkpipe (serial->dev, command_port->bulk_out_endpointAddress); + /* + * When the module is reloaded the firmware is still there and + * the endpoints are still in the usb core unchanged. This is the + * unlinking bug in disguise. Same for the call below. + */ + usb_clear_halt(serial->dev, pipe); ret = usb_bulk_msg (serial->dev, pipe, command, sizeof(command), &alen, COMMAND_TIMEOUT); if (ret) { err("%s: Couldn't send command [%d]", serial->type->name, ret); @@ -344,6 +350,8 @@ static int whiteheat_attach (struct usb_serial *serial) } pipe = usb_rcvbulkpipe (serial->dev, command_port->bulk_in_endpointAddress); + /* See the comment on the usb_clear_halt() above */ + usb_clear_halt(serial->dev, pipe); ret = usb_bulk_msg (serial->dev, pipe, result, sizeof(result), &alen, COMMAND_TIMEOUT); if (ret) { err("%s: Couldn't get results [%d]", serial->type->name, ret); @@ -438,6 +446,10 @@ static int whiteheat_open (struct usb_serial_port *port, struct file *filp) if (retval) goto exit; + /* Work around HCD bugs */ + usb_clear_halt(port->serial->dev, port->read_urb->pipe); + usb_clear_halt(port->serial->dev, port->write_urb->pipe); + /* Start reading from the device */ port->read_urb->dev = port->serial->dev; retval = usb_submit_urb(port->read_urb, GFP_KERNEL); @@ -489,7 +501,8 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp) { dbg("%s - port %d", __FUNCTION__, port->number); - if (tty_hung_up_p(filp)) { + /* filp is NULL when called from usb_serial_disconnect */ + if (filp && (tty_hung_up_p(filp))) { return; } @@ -1145,6 +1158,9 @@ static int start_command_port(struct usb_serial *serial) command_info = (struct whiteheat_command_private *)command_port->private; spin_lock_irqsave(&command_info->lock, flags); if (!command_info->port_running) { + /* Work around HCD bugs */ + usb_clear_halt(serial->dev, command_port->read_urb->pipe); + command_port->read_urb->dev = serial->dev; retval = usb_submit_urb(command_port->read_urb, GFP_KERNEL); if (retval) { diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c index 8e1514ac51e2..980253839108 100644 --- a/drivers/usb/storage/datafab.c +++ b/drivers/usb/storage/datafab.c @@ -67,25 +67,23 @@ static int datafab_determine_lun(struct us_data *us, static inline int datafab_bulk_read(struct us_data *us, unsigned char *data, unsigned int len) { - unsigned int act_len; /* ignored */ - if (len == 0) return USB_STOR_XFER_GOOD; US_DEBUGP("datafab_bulk_read: len = %d\n", len); - return usb_storage_raw_bulk(us, SCSI_DATA_READ, data, len, &act_len); + return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + data, len, NULL); } static inline int datafab_bulk_write(struct us_data *us, unsigned char *data, unsigned int len) { - unsigned int act_len; /* ignored */ - if (len == 0) return USB_STOR_XFER_GOOD; US_DEBUGP("datafab_bulk_write: len = %d\n", len); - return usb_storage_raw_bulk(us, SCSI_DATA_WRITE, data, len, &act_len); + return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, + data, len, NULL); } @@ -522,6 +520,7 @@ int datafab_transport(Scsi_Cmnd * srb, struct us_data *us) 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 }; + srb->resid = 0; if (!us->extra) { us->extra = kmalloc(sizeof(struct datafab_info), GFP_NOIO); if (!us->extra) { diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c index 13c758c8a0e6..72112d97487a 100644 --- a/drivers/usb/storage/freecom.c +++ b/drivers/usb/storage/freecom.c @@ -108,72 +108,9 @@ struct freecom_status { /* All packets (except for status) are 64 bytes long. */ #define FCM_PACKET_LENGTH 64 -/* - * Transfer an entire SCSI command's worth of data payload over the bulk - * pipe. - * - * Note that this uses usb_stor_transfer_partial to achieve it's goals -- this - * function simply determines if we're going to use scatter-gather or not, - * and acts appropriately. For now, it also re-interprets the error codes. - */ -static void us_transfer_freecom(Scsi_Cmnd *srb, struct us_data* us, int transfer_amount) -{ - int i; - int result = -1; - struct scatterlist *sg; - unsigned int total_transferred = 0; - - /* was someone foolish enough to request more data than available - * buffer space? */ - if (transfer_amount > srb->request_bufflen) - transfer_amount = srb->request_bufflen; - - /* are we scatter-gathering? */ - if (srb->use_sg) { - - /* loop over all the scatter gather structures and - * make the appropriate requests for each, until done - */ - sg = (struct scatterlist *) srb->request_buffer; - for (i = 0; i < srb->use_sg; i++) { - - US_DEBUGP("transfer_amount: %d and total_transferred: %d\n", transfer_amount, total_transferred); - - /* End this if we're done */ - if (transfer_amount == total_transferred) - break; - - /* transfer the lesser of the next buffer or the - * remaining data */ - if (transfer_amount - total_transferred >= - sg[i].length) { - result = usb_stor_transfer_partial(us, - sg_address(sg[i]), sg[i].length); - total_transferred += sg[i].length; - } else { - result = usb_stor_transfer_partial(us, - sg_address(sg[i]), - transfer_amount - total_transferred); - total_transferred += transfer_amount - total_transferred; - } - - /* if we get an error, end the loop here */ - if (result) - break; - } - } - else - /* no scatter-gather, just make the request */ - result = usb_stor_transfer_partial(us, srb->request_buffer, - transfer_amount); - - /* return the result in the data structure itself */ - srb->result = result; -} - static int freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, - int ipipe, int opipe, int count) + unsigned int ipipe, unsigned int opipe, int count) { freecom_udata_t extra = (freecom_udata_t) us->extra; struct freecom_xfer_wrap *fxfr = @@ -206,15 +143,15 @@ freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, /* Now transfer all of our blocks. */ US_DEBUGP("Start of read\n"); - us_transfer_freecom(srb, us, count); + result = usb_stor_bulk_transfer_srb(us, ipipe, srb, count); US_DEBUGP("freecom_readdata done!\n"); - return USB_STOR_TRANSPORT_GOOD; + return result; } static int freecom_writedata (Scsi_Cmnd *srb, struct us_data *us, - int ipipe, int opipe, int count) + int unsigned ipipe, unsigned int opipe, int count) { freecom_udata_t extra = (freecom_udata_t) us->extra; struct freecom_xfer_wrap *fxfr = @@ -248,10 +185,10 @@ freecom_writedata (Scsi_Cmnd *srb, struct us_data *us, /* Now transfer all of our blocks. */ US_DEBUGP("Start of write\n"); - us_transfer_freecom(srb, us, count); + result = usb_stor_bulk_transfer_srb(us, opipe, srb, count); US_DEBUGP("freecom_writedata done!\n"); - return USB_STOR_TRANSPORT_GOOD; + return result; } /* @@ -262,7 +199,7 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) { struct freecom_cb_wrap *fcb; struct freecom_status *fst; - int ipipe, opipe; /* We need both pipes. */ + unsigned int ipipe, opipe; /* We need both pipes. */ int result; int partial; int length; @@ -276,8 +213,8 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us) US_DEBUGP("Freecom TRANSPORT STARTED\n"); /* Get handles for both transports. */ - opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out); - ipipe = usb_rcvbulkpipe (us->pusb_dev, us->ep_in); + opipe = us->send_bulk_pipe; + ipipe = us->recv_bulk_pipe; /* The ATAPI Command always goes out first. */ fcb->Type = FCM_PACKET_ATAPI | 0x00; @@ -515,8 +452,7 @@ freecom_init (struct us_data *us) } } - result = usb_control_msg(us->pusb_dev, - usb_rcvctrlpipe(us->pusb_dev, 0), + result = usb_control_msg(us->pusb_dev, us->recv_ctrl_pipe, 0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ); buffer[32] = '\0'; US_DEBUGP("String returned from FC init is: %s\n", buffer); @@ -528,8 +464,7 @@ freecom_init (struct us_data *us) */ /* send reset */ - result = usb_control_msg(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, 0), + result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, 0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ); US_DEBUGP("result from activate reset is %d\n", result); @@ -537,8 +472,7 @@ freecom_init (struct us_data *us) mdelay(250); /* clear reset */ - result = usb_control_msg(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, 0), + result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, 0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ); US_DEBUGP("result from clear reset is %d\n", result); diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index f89bd597bbfe..76b1782a24c2 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -50,7 +50,7 @@ int usb_stor_euscsi_init(struct us_data *us) int result; US_DEBUGP("Attempting to init eUSCSI bridge...\n"); - result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0), + result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, 0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR, 0x01, 0x0, &data, 0x1, 5*HZ); US_DEBUGP("-- result is %d\n", result); diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index f80db3ba115b..5fb82bfaa294 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -408,13 +408,13 @@ static int isd200_transfer_partial( struct us_data *us, { int result; int partial; - int pipe; + unsigned int pipe; /* calculate the appropriate pipe information */ if (dataDirection == SCSI_DATA_READ) - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); + pipe = us->recv_bulk_pipe; else - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); + pipe = us->send_bulk_pipe; /* transfer the data */ US_DEBUGP("isd200_transfer_partial(): xfer %d bytes\n", length); @@ -546,7 +546,6 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, struct bulk_cb_wrap bcb; struct bulk_cs_wrap bcs; int result; - int pipe; int partial; unsigned int transfer_amount; @@ -566,9 +565,6 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, bcb.Length = AtaCdbLength; - /* construct the pipe handle */ - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - /* copy the command payload */ memset(bcb.CDB, 0, sizeof(bcb.CDB)); memcpy(bcb.CDB, AtaCdb, bcb.Length); @@ -578,8 +574,8 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, le32_to_cpu(bcb.Signature), bcb.Tag, (bcb.Lun >> 4), (bcb.Lun & 0xFF), le32_to_cpu(bcb.DataTransferLength), bcb.Flags, bcb.Length); - result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, - &partial); + result = usb_stor_bulk_msg(us, &bcb, us->send_bulk_pipe, + US_BULK_CB_WRAP_LEN, &partial); US_DEBUGP("Bulk command transfer result=%d\n", result); /* did we abort this command? */ @@ -589,8 +585,9 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, else if (result == -EPIPE) { /* if we stall, we need to clear it before we go on */ - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - if (usb_stor_clear_halt(us, pipe) < 0) + US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", + us->send_bulk_pipe); + if (usb_stor_clear_halt(us, us->send_bulk_pipe) < 0) return ISD200_TRANSPORT_ERROR; } else if (result) return ISD200_TRANSPORT_ERROR; @@ -608,13 +605,10 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, * an explanation of how this code works. */ - /* construct the pipe handle */ - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - /* get CSW for device status */ US_DEBUGP("Attempting to get CSW...\n"); - result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, - &partial); + result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, + US_BULK_CS_WRAP_LEN, &partial); /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { return ISD200_TRANSPORT_ABORTED; @@ -622,13 +616,14 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - if (usb_stor_clear_halt(us, pipe) < 0) + US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", + us->recv_bulk_pipe); + if (usb_stor_clear_halt(us, us->recv_bulk_pipe) < 0) return ISD200_TRANSPORT_ERROR; /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); - result = usb_stor_bulk_msg(us, &bcs, pipe, + result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, US_BULK_CS_WRAP_LEN, &partial); /* if the command was aborted, indicate that */ @@ -638,8 +633,9 @@ int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { - US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us, pipe); + US_DEBUGP("clearing halt for pipe 0x%x\n", + us->recv_bulk_pipe); + usb_stor_clear_halt(us, us->recv_bulk_pipe); return ISD200_TRANSPORT_ERROR; } } @@ -937,7 +933,7 @@ int isd200_write_config( struct us_data *us ) /* let's send the command via the control pipe */ result = usb_stor_control_msg( us, - usb_sndctrlpipe(us->pusb_dev,0), + us->send_ctrl_pipe, 0x01, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 0x0000, @@ -978,7 +974,7 @@ int isd200_read_config( struct us_data *us ) result = usb_stor_control_msg( us, - usb_rcvctrlpipe(us->pusb_dev,0), + us->recv_ctrl_pipe, 0x02, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 0x0000, diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c index 34e639762b69..e599c83fbc31 100644 --- a/drivers/usb/storage/jumpshot.c +++ b/drivers/usb/storage/jumpshot.c @@ -62,13 +62,12 @@ static inline int jumpshot_bulk_read(struct us_data *us, unsigned char *data, unsigned int len) { - unsigned int act_len; /* ignored */ - if (len == 0) return USB_STOR_XFER_GOOD; US_DEBUGP("jumpshot_bulk_read: len = %d\n", len); - return usb_storage_raw_bulk(us, SCSI_DATA_READ, data, len, &act_len); + return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + data, len, NULL); } @@ -76,13 +75,12 @@ static inline int jumpshot_bulk_write(struct us_data *us, unsigned char *data, unsigned int len) { - unsigned int act_len; /* ignored */ - if (len == 0) return USB_STOR_XFER_GOOD; US_DEBUGP("jumpshot_bulk_write: len = %d\n", len); - return usb_storage_raw_bulk(us, SCSI_DATA_WRITE, data, len, &act_len); + return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, + data, len, NULL); } @@ -95,12 +93,11 @@ static int jumpshot_get_status(struct us_data *us) return USB_STOR_TRANSPORT_ERROR; // send the setup - rc = usb_storage_send_control(us, - usb_rcvctrlpipe(us->pusb_dev, 0), + rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe, 0, 0xA0, 0, 7, &reply, 1); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; + if (rc != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; if (reply != 0x50) { US_DEBUGP("jumpshot_get_status: 0x%2x\n", @@ -160,10 +157,9 @@ static int jumpshot_read_data(struct us_data *us, command[5] |= (sector >> 24) & 0x0F; // send the setup + command - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev, 0), + result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, 0, 0x20, 0, 1, command, 7); - if (result != USB_STOR_TRANSPORT_GOOD) + if (result != USB_STOR_XFER_GOOD) goto leave; // read the result @@ -247,9 +243,10 @@ static int jumpshot_write_data(struct us_data *us, command[5] |= (sector >> 24) & 0x0F; // send the setup + command - result = usb_storage_send_control( - us, usb_sndctrlpipe(us->pusb_dev, 0), + result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, 0, 0x20, 0, 1, command, 7); + if (result != USB_STOR_XFER_GOOD) + goto leave; // send the data result = jumpshot_bulk_write(us, ptr, len); @@ -302,11 +299,10 @@ static int jumpshot_id_device(struct us_data *us, return USB_STOR_TRANSPORT_ERROR; // send the setup - rc = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev, 0), + rc = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, 0, 0x20, 0, 6, command, 2); - if (rc != USB_STOR_TRANSPORT_GOOD) { + if (rc != USB_STOR_XFER_GOOD) { US_DEBUGP("jumpshot_id_device: Gah! " "send_control for read_capacity failed\n"); return rc; @@ -468,7 +464,7 @@ int jumpshot_transport(Scsi_Cmnd * srb, struct us_data *us) 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 }; - + srb->resid = 0; if (!us->extra) { us->extra = kmalloc(sizeof(struct jumpshot_info), GFP_NOIO); if (!us->extra) { diff --git a/drivers/usb/storage/raw_bulk.c b/drivers/usb/storage/raw_bulk.c index 4e3b755d5cdc..eef495ea97b5 100644 --- a/drivers/usb/storage/raw_bulk.c +++ b/drivers/usb/storage/raw_bulk.c @@ -13,219 +13,6 @@ #include "transport.h" #include "raw_bulk.h" -#ifdef CONFIG_USB_STORAGE_DEBUG -#define DEBUG_PRCT 12 -#else -#define DEBUG_PRCT 0 -#endif - -/* - * Send a control message and wait for the response. - * - * us - the pointer to the us_data structure for the device to use - * - * request - the URB Setup Packet's first 6 bytes. The first byte always - * corresponds to the request type, and the second byte always corresponds - * to the request. The other 4 bytes do not correspond to value and index, - * since they are used in a custom way by the SCM protocol. - * - * xfer_data - a buffer from which to get, or to which to store, any data - * that gets send or received, respectively, with the URB. Even though - * it looks like we allocate a buffer in this code for the data, xfer_data - * must contain enough allocated space. - * - * xfer_len - the number of bytes to send or receive with the URB. - * - */ - -int -usb_storage_send_control(struct us_data *us, - int pipe, - unsigned char request, - unsigned char requesttype, - unsigned int value, - unsigned int index, - unsigned char *xfer_data, - unsigned int xfer_len) { - - int result; - - // Send the URB to the device and wait for a response. - - /* Why are request and request type reversed in this call? */ - - result = usb_stor_control_msg(us, pipe, - request, requesttype, value, index, - xfer_data, xfer_len); - - /* did we abort this command? */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { - US_DEBUGP("usb_stor_send_control(): transfer aborted\n"); - return USB_STOR_TRANSPORT_ABORTED; - } - - // Check the return code for the command. - if (result < 0) { - - /* a stall indicates a protocol error */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - /* Uh oh... serious problem here */ - return USB_STOR_TRANSPORT_ERROR; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -int -usb_storage_raw_bulk(struct us_data *us, int direction, unsigned char *data, - unsigned int len, unsigned int *act_len) { - - int result; - int pipe; - - if (direction == SCSI_DATA_READ) - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - else - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - - result = usb_stor_bulk_msg(us, data, pipe, len, act_len); - - /* if we stall, we need to clear it before we go on */ - if (result == -EPIPE) { - US_DEBUGP("EPIPE: clearing endpoint halt for" - " pipe 0x%x, stalled at %d bytes\n", - pipe, *act_len); - if (usb_stor_clear_halt(us, pipe) < 0) - return USB_STOR_XFER_ERROR; - return USB_STOR_XFER_STALLED; - } - - /* did we abort this command? */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { - US_DEBUGP("usb_storage_raw_bulk(): transfer aborted\n"); - return USB_STOR_XFER_ABORTED; - } - - if (result) { - /* NAK - that means we've retried a few times already */ - if (result == -ETIMEDOUT) - US_DEBUGP("raw_bulk(): device NAKed\n"); - else if (result == -EOVERFLOW) - US_DEBUGP("raw_bulk(): babble/overflow\n"); - else if (result == -ECONNRESET) - US_DEBUGP("raw_bulk(): asynchronous reset\n"); - else if (result != -EPIPE) - US_DEBUGP("raw_bulk(): unknown error %d\n", - result); - - return USB_STOR_XFER_ERROR; - } - - if (*act_len != len) { - US_DEBUGP("Warning: Transferred only %d of %d bytes\n", - *act_len, len); - return USB_STOR_XFER_SHORT; - } - -#if 0 - US_DEBUGP("raw_bulk(): Transferred %s %d of %d bytes\n", - (direction == SCSI_DATA_READ) ? "in" : "out", - *act_len, len); -#endif - - return USB_STOR_XFER_GOOD; -} - -int -usb_storage_bulk_transport(struct us_data *us, int direction, - unsigned char *data, unsigned int len, - int use_sg) { - - int result = USB_STOR_XFER_ERROR; - int transferred = 0; - int i; - struct scatterlist *sg; - unsigned int act_len; - - if (len == 0) - return USB_STOR_XFER_GOOD; - -#if DEBUG_PRCT - - if (direction == SCSI_DATA_WRITE && !use_sg) { - char string[64]; - - /* Debug-print the first N bytes of the write transfer */ - - strcpy(string, "wr: "); - for (i=0; i<len && i<DEBUG_PRCT; i++) { - sprintf(string+strlen(string), "%02X ", data[i]); - if ((i%16) == 15) { - US_DEBUGP("%s\n", string); - strcpy(string, "wr: "); - } - } - if ((i%16)!=0) - US_DEBUGP("%s\n", string); - } - - US_DEBUGP("SCM data %s transfer %d sg buffers %d\n", - (direction == SCSI_DATA_READ) ? "in" : "out", - len, use_sg); - -#endif /* DEBUG_PRCT */ - - if (!use_sg) - result = usb_storage_raw_bulk(us, direction, - data, len, &act_len); - else { - sg = (struct scatterlist *)data; - - for (i=0; i<use_sg && transferred<len; i++) { - unsigned char *buf; - unsigned int length; - - buf = sg_address(sg[i]); - length = len-transferred; - if (length > sg[i].length) - length = sg[i].length; - - result = usb_storage_raw_bulk(us, direction, - buf, length, &act_len); - if (result != USB_STOR_XFER_GOOD) - break; - transferred += length; - } - } - -#if DEBUG_PRCT - - if (direction == SCSI_DATA_READ && !use_sg) { - char string[64]; - - /* Debug-print the first N bytes of the read transfer */ - - strcpy(string, "rd: "); - for (i=0; i<len && i<act_len && i<DEBUG_PRCT; i++) { - sprintf(string+strlen(string), "%02X ", data[i]); - if ((i%16) == 15) { - US_DEBUGP("%s\n", string); - strcpy(string, "rd: "); - } - } - if ((i%16)!=0) - US_DEBUGP("%s\n", string); - } - -#endif /* DEBUG_PRCT */ - - return result; -} - /* * The routines below convert scatter-gather to single buffer. * Some drivers claim this is necessary. diff --git a/drivers/usb/storage/raw_bulk.h b/drivers/usb/storage/raw_bulk.h index 0361b39ec1f9..9a0e479eaf2e 100644 --- a/drivers/usb/storage/raw_bulk.h +++ b/drivers/usb/storage/raw_bulk.h @@ -1,21 +1,6 @@ #ifndef _USB_STORAGE_RAW_BULK_H_ #define _USB_STORAGE_RAW_BULK_H_ -/* usb bulk */ -extern int usb_storage_send_control( - struct us_data *us, int pipe, - unsigned char request, unsigned char requesttype, - unsigned int value, unsigned int index, - unsigned char *xfer_data, unsigned int xfer_len); - -extern int usb_storage_raw_bulk( - struct us_data *us, int direction, - unsigned char *data, unsigned int len, unsigned int *act_len); - -extern int usb_storage_bulk_transport( - struct us_data *us, int direction, - unsigned char *data, unsigned int len, int use_sg); - /* scatter-gather */ extern unsigned char *us_copy_from_sgbuf( unsigned char *content, int buflen, diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index 718759ecd8d4..79ca7238af77 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -224,18 +224,21 @@ sddr09_send_command(struct us_data *us, unsigned char direction, unsigned char *xfer_data, unsigned int xfer_len) { - int pipe; + unsigned int pipe; unsigned char requesttype = (0x41 | direction); + int rc; // Get the receive or send control pipe number if (direction == USB_DIR_IN) - pipe = usb_rcvctrlpipe(us->pusb_dev,0); + pipe = us->recv_ctrl_pipe; else - pipe = usb_sndctrlpipe(us->pusb_dev,0); + pipe = us->send_ctrl_pipe; - return usb_storage_send_control(us, pipe, request, requesttype, + rc = usb_stor_ctrl_transfer(us, pipe, request, requesttype, 0, 0, xfer_data, xfer_len); + return (rc == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : + USB_STOR_TRANSPORT_ERROR); } static int @@ -276,7 +279,6 @@ sddr09_request_sense(struct us_data *us, unsigned char *sensebuf, int buflen) { 0x03, LUNBITS, 0, 0, buflen, 0, 0, 0, 0, 0, 0, 0 }; int result; - unsigned int act_len; result = sddr09_send_scsi_command(us, command, sizeof(command)); if (result != USB_STOR_TRANSPORT_GOOD) { @@ -284,7 +286,8 @@ sddr09_request_sense(struct us_data *us, unsigned char *sensebuf, int buflen) { return result; } - result = usb_storage_raw_bulk(us, SCSI_DATA_READ, sensebuf, buflen, &act_len); + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + sensebuf, buflen, NULL); if (result != USB_STOR_XFER_GOOD) { US_DEBUGP("request sense bulk in failed\n"); return USB_STOR_TRANSPORT_ERROR; @@ -343,11 +346,11 @@ sddr09_readX(struct us_data *us, int x, unsigned long fromaddress, return result; } - result = usb_storage_bulk_transport(us, SCSI_DATA_READ, - buf, bulklen, use_sg); + result = usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, + buf, bulklen, use_sg, NULL); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for bulk_transport in sddr09_read2%d %d\n", + US_DEBUGP("Result for bulk_transfer in sddr09_read2%d %d\n", x, result); return USB_STOR_TRANSPORT_ERROR; } @@ -510,11 +513,11 @@ sddr09_writeX(struct us_data *us, return result; } - result = usb_storage_bulk_transport(us, SCSI_DATA_WRITE, - buf, bulklen, use_sg); + result = usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, + buf, bulklen, use_sg, NULL); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for bulk_transport in sddr09_writeX %d\n", + US_DEBUGP("Result for bulk_transfer in sddr09_writeX %d\n", result); return USB_STOR_TRANSPORT_ERROR; } @@ -592,11 +595,11 @@ sddr09_read_sg_test_only(struct us_data *us) { if (!buf) return USB_STOR_TRANSPORT_ERROR; - result = usb_storage_bulk_transport(us, SCSI_DATA_READ, - buf, bulklen, 0); + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + buf, bulklen, NULL); kfree(buf); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for bulk_transport in sddr09_read_sg %d\n", + US_DEBUGP("Result for bulk_transfer in sddr09_read_sg %d\n", result); return USB_STOR_TRANSPORT_ERROR; } @@ -631,8 +634,8 @@ sddr09_read_status(struct us_data *us, unsigned char *status) { if (result != USB_STOR_TRANSPORT_GOOD) return result; - result = usb_storage_bulk_transport(us, SCSI_DATA_READ, - data, sizeof(data), 0); + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + data, sizeof(data), NULL); *status = data[0]; return (result == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); @@ -954,7 +957,8 @@ sddr09_read_deviceID(struct us_data *us, unsigned char *deviceID) { if (result != USB_STOR_TRANSPORT_GOOD) return result; - result = usb_storage_bulk_transport(us, SCSI_DATA_READ, content, 64, 0); + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + content, 64, NULL); for (i = 0; i < 4; i++) deviceID[i] = content[i]; @@ -1368,6 +1372,7 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + srb->resid = 0; info = (struct sddr09_card_info *)us->extra; if (!info) { nand_init_ecc(); @@ -1544,17 +1549,16 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us) if (srb->sc_data_direction == SCSI_DATA_WRITE || srb->sc_data_direction == SCSI_DATA_READ) { + unsigned int pipe = (srb->sc_data_direction == SCSI_DATA_WRITE) + ? us->send_bulk_pipe : us->recv_bulk_pipe; US_DEBUGP("SDDR09: %s %d bytes\n", (srb->sc_data_direction == SCSI_DATA_WRITE) ? "sending" : "receiving", srb->request_bufflen); - result = usb_storage_bulk_transport(us, - srb->sc_data_direction, - srb->request_buffer, - srb->request_bufflen, - srb->use_sg); + result = usb_stor_bulk_transfer_srb(us, pipe, srb, + srb->request_bufflen); return (result == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c index 20c9692c1027..484576cc3c90 100644 --- a/drivers/usb/storage/sddr55.c +++ b/drivers/usb/storage/sddr55.c @@ -75,10 +75,13 @@ static int sddr55_bulk_transport(struct us_data *us, int direction, unsigned char *data, unsigned int len) { struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra; + unsigned int pipe = (direction == SCSI_DATA_READ) ? + us->recv_bulk_pipe : us->send_bulk_pipe; - if (len) - info->last_access = jiffies; - return usb_storage_bulk_transport(us, direction, data, len, 0); + if (!len) + return USB_STOR_XFER_GOOD; + info->last_access = jiffies; + return usb_stor_bulk_transfer_buf(us, pipe, data, len, NULL); } /* check if card inserted, if there is, update read_only status @@ -743,6 +746,7 @@ int sddr55_transport(Scsi_Cmnd *srb, struct us_data *us) unsigned short pages; struct sddr55_card_info *info; + srb->resid = 0; if (!us->extra) { us->extra = kmalloc( sizeof(struct sddr55_card_info), GFP_NOIO); diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index 21a74c17df38..8bec05bdd5b5 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -50,12 +50,6 @@ #include <linux/errno.h> #include <linux/slab.h> -extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe, - u8 request, u8 requesttype, u16 value, u16 index, - void *data, u16 size); -extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, - unsigned int len, unsigned int *act_len); - #define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) ) #define LSB_of(s) ((s)&0xFF) #define MSB_of(s) ((s)>>8) @@ -69,8 +63,8 @@ int usbat_read(struct us_data *us, int result; - result = usb_storage_send_control(us, - usb_rcvctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->recv_ctrl_pipe, access, 0xC0, (u16)reg, @@ -88,8 +82,8 @@ int usbat_write(struct us_data *us, int result; - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, access|0x01, 0x40, short_pack(reg, content), @@ -114,8 +108,8 @@ int usbat_set_shuttle_features(struct us_data *us, test_pattern, mask_byte, subcountL, subcountH }; - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, 0x80, 0x40, 0, @@ -139,8 +133,11 @@ int usbat_read_block(struct us_data *us, LSB_of(len), MSB_of(len) }; - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + if (!len) + return USB_STOR_TRANSPORT_GOOD; + + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, 0x80, 0x40, 0, @@ -148,10 +145,11 @@ int usbat_read_block(struct us_data *us, command, 8); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; + if (result != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - result = usb_storage_bulk_transport(us, SCSI_DATA_READ, content, len, use_sg); + result = usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, + content, len, use_sg, NULL); return (result == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); @@ -178,8 +176,8 @@ int usbat_wait_not_busy(struct us_data *us, int minutes) { result = usbat_read(us, USBAT_ATA, 0x17, &status); - if (result!=USB_STOR_TRANSPORT_GOOD) - return result; + if (result!=USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; if (status&0x01) { // check condition result = usbat_read(us, USBAT_ATA, 0x10, &status); return USB_STOR_TRANSPORT_FAILED; @@ -221,8 +219,11 @@ int usbat_write_block(struct us_data *us, LSB_of(len), MSB_of(len) }; - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + if (!len) + return USB_STOR_TRANSPORT_GOOD; + + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, 0x80, 0x40, 0, @@ -230,10 +231,11 @@ int usbat_write_block(struct us_data *us, command, 8); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; + if (result != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - result = usb_storage_bulk_transport(us, SCSI_DATA_WRITE, content, len, use_sg); + result = usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, + content, len, use_sg, NULL); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -257,6 +259,8 @@ int usbat_rw_block_test(struct us_data *us, int minutes) { int result; + unsigned int pipe = (direction == SCSI_DATA_READ) ? + us->recv_bulk_pipe : us->send_bulk_pipe; // Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here, // but that's what came out of the trace every single time. @@ -292,8 +296,8 @@ int usbat_rw_block_test(struct us_data *us, * that, we just return a failure. */ - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, 0x80, 0x40, 0, @@ -301,16 +305,16 @@ int usbat_rw_block_test(struct us_data *us, (i==0 ? command : command+8), (i==0 ? 16 : 8)); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; + if (result != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; if (i==0) { - result = usb_storage_bulk_transport(us, - SCSI_DATA_WRITE, - data, num_registers*2, 0); + result = usb_stor_bulk_transfer_buf(us, + us->send_bulk_pipe, + data, num_registers*2, NULL); - if (result!=USB_STOR_XFER_GOOD) + if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; } @@ -320,8 +324,8 @@ int usbat_rw_block_test(struct us_data *us, // direction == SCSI_DATA_WRITE ? "out" : "in", // len, use_sg); - result = usb_storage_bulk_transport(us, - direction, content, len, use_sg); + result = usb_stor_bulk_transfer_sg(us, + pipe, content, len, use_sg, NULL); /* * If we get a stall on the bulk download, we'll retry @@ -352,8 +356,7 @@ int usbat_rw_block_test(struct us_data *us, if (direction==SCSI_DATA_READ && i==0) { if (usb_stor_clear_halt(us, - usb_sndbulkpipe(us->pusb_dev, - us->ep_out)) < 0) + us->send_bulk_pipe) < 0) return USB_STOR_TRANSPORT_ERROR; } @@ -365,8 +368,8 @@ int usbat_rw_block_test(struct us_data *us, direction==SCSI_DATA_WRITE ? 0x17 : 0x0E, &status); - if (result!=USB_STOR_TRANSPORT_GOOD) - return result; + if (result!=USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; if (status&0x01) // check condition return USB_STOR_TRANSPORT_FAILED; if (status&0x20) // device fault @@ -412,8 +415,8 @@ int usbat_multiple_write(struct us_data *us, data[1+(i<<1)] = data_out[i]; } - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, 0x80, 0x40, 0, @@ -421,11 +424,11 @@ int usbat_multiple_write(struct us_data *us, command, 8); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; + if (result != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - result = usb_storage_bulk_transport(us, - SCSI_DATA_WRITE, data, num_registers*2, 0); + result = usb_stor_bulk_transfer_buf(us, + us->send_bulk_pipe, data, num_registers*2, NULL); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -438,8 +441,8 @@ int usbat_read_user_io(struct us_data *us, int result; - result = usb_storage_send_control(us, - usb_rcvctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->recv_ctrl_pipe, 0x82, 0xC0, 0, @@ -456,8 +459,8 @@ int usbat_write_user_io(struct us_data *us, int result; - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, 0x82, 0x40, short_pack(enable_flags, data_flags), @@ -589,7 +592,6 @@ int usbat_handle_read10(struct us_data *us, static int hp_8200e_select_and_test_registers(struct us_data *us) { - int result; int selector; unsigned char status; @@ -597,44 +599,44 @@ static int hp_8200e_select_and_test_registers(struct us_data *us) { for (selector = 0xA0; selector <= 0xB0; selector += 0x10) { - if ( (result = usbat_write(us, USBAT_ATA, 0x16, selector)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_write(us, USBAT_ATA, 0x16, selector) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - if ( (result = usbat_read(us, USBAT_ATA, 0x17, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read(us, USBAT_ATA, 0x17, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - if ( (result = usbat_read(us, USBAT_ATA, 0x16, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read(us, USBAT_ATA, 0x16, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read(us, USBAT_ATA, 0x14, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - if ( (result = usbat_read(us, USBAT_ATA, 0x15, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read(us, USBAT_ATA, 0x15, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - if ( (result = usbat_write(us, USBAT_ATA, 0x14, 0x55)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_write(us, USBAT_ATA, 0x14, 0x55) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - if ( (result = usbat_write(us, USBAT_ATA, 0x15, 0xAA)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_write(us, USBAT_ATA, 0x15, 0xAA) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read(us, USBAT_ATA, 0x14, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - if ( (result = usbat_read(us, USBAT_ATA, 0x15, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read(us, USBAT_ATA, 0x15, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; } - return result; + return USB_STOR_TRANSPORT_GOOD; } int init_8200e(struct us_data *us) { @@ -644,44 +646,44 @@ int init_8200e(struct us_data *us) { // Enable peripheral control signals - if ( (result = usbat_write_user_io(us, + if (usbat_write_user_io(us, USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) - return result; + USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 1\n"); wait_ms(2000); - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read_user_io(us, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 2\n"); - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read_user_io(us, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 3\n"); // Reset peripheral, enable periph control signals // (bring reset signal up) - if ( (result = usbat_write_user_io(us, + if (usbat_write_user_io(us, USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) - return result; + USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 4\n"); // Enable periph control signals // (bring reset signal down) - if ( (result = usbat_write_user_io(us, + if (usbat_write_user_io(us, USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) - return result; + USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 5\n"); @@ -689,23 +691,23 @@ int init_8200e(struct us_data *us) { // Write 0x80 to ISA port 0x3F - if ( (result = usbat_write(us, USBAT_ISA, 0x3F, 0x80)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_write(us, USBAT_ISA, 0x3F, 0x80) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 6\n"); // Read ISA port 0x27 - if ( (result = usbat_read(us, USBAT_ISA, 0x27, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read(us, USBAT_ISA, 0x27, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 7\n"); - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read_user_io(us, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 8\n"); @@ -715,32 +717,32 @@ int init_8200e(struct us_data *us) { US_DEBUGP("INIT 9\n"); - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read_user_io(us, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 10\n"); // Enable periph control signals and card detect - if ( (result = usbat_write_user_io(us, + if (usbat_write_user_io(us, USBAT_UIO_ACKD |USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) - return result; + USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 11\n"); - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read_user_io(us, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 12\n"); wait_ms(1400); - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read_user_io(us, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 13\n"); @@ -750,14 +752,14 @@ int init_8200e(struct us_data *us) { US_DEBUGP("INIT 14\n"); - if ( (result = usbat_set_shuttle_features(us, - 0x83, 0x00, 0x88, 0x08, 0x15, 0x14)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_set_shuttle_features(us, + 0x83, 0x00, 0x88, 0x08, 0x15, 0x14) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 15\n"); - return result; + return USB_STOR_TRANSPORT_ERROR; } /* @@ -773,6 +775,7 @@ int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us) int i; char string[64]; + srb->resid = 0; len = srb->request_bufflen; /* Send A0 (ATA PACKET COMMAND). @@ -863,17 +866,16 @@ int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us) // How many bytes to read in? Check cylL register - if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) != - USB_STOR_TRANSPORT_GOOD) { - return result; + if (usbat_read(us, USBAT_ATA, 0x14, &status) != + USB_STOR_XFER_GOOD) { + return USB_STOR_TRANSPORT_ERROR; } - if (len>0xFF) { // need to read cylH also + if (len > 0xFF) { // need to read cylH also len = status; - if ( (result = usbat_read(us, USBAT_ATA, 0x15, - &status)) != - USB_STOR_TRANSPORT_GOOD) { - return result; + if (usbat_read(us, USBAT_ATA, 0x15, &status) != + USB_STOR_XFER_GOOD) { + return USB_STOR_TRANSPORT_ERROR; } len += ((unsigned int)status)<<8; } diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 9303b8b502a7..6281a3e5e81a 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -488,7 +488,7 @@ int usb_stor_control_msg(struct us_data *us, unsigned int pipe, /* This is our function to emulate usb_bulk_msg() with enough control * to make aborts/resets/timeouts work */ -int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, +int usb_stor_bulk_msg(struct us_data *us, void *data, unsigned int pipe, unsigned int len, unsigned int *act_len) { int status; @@ -515,13 +515,12 @@ int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, * Since many vendors in this space limit their testing to interoperability * with these two OSes, specification violations like this one are common. */ -int usb_stor_clear_halt(struct us_data *us, int pipe) +int usb_stor_clear_halt(struct us_data *us, unsigned int pipe) { int result; int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7); - result = usb_stor_control_msg(us, - usb_sndctrlpipe(us->pusb_dev, 0), + result = usb_stor_control_msg(us, us->send_ctrl_pipe, USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0); /* note: no 3*HZ timeout */ US_DEBUGP("usb_stor_clear_halt: result=%d\n", result); @@ -542,37 +541,81 @@ int usb_stor_clear_halt(struct us_data *us, int pipe) } /* - * Transfer one SCSI scatter-gather buffer via bulk transfer + * Transfer one control message * - * Note that this function is necessary because we want the ability to - * use scatter-gather memory. Good performance is achieved by a combination - * of scatter-gather and clustering (which makes each chunk bigger). + * This function does basically the same thing as usb_stor_control_msg() + * above, except that return codes are USB_STOR_XFER_xxx rather than the + * urb status or transfer length. + */ +int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, + u8 request, u8 requesttype, u16 value, u16 index, + void *data, u16 size) { + int result; + + US_DEBUGP("usb_stor_ctrl_transfer(): rq=%02x rqtype=%02x " + "value=%04x index=%02x len=%d\n", + request, requesttype, value, index, size); + result = usb_stor_control_msg(us, pipe, request, requesttype, + value, index, data, size); + US_DEBUGP("usb_stor_control_msg returned %d\n", result); + + /* did we abort this command? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("-- transfer aborted\n"); + return USB_STOR_XFER_ABORTED; + } + + /* a stall indicates a protocol error */ + if (result == -EPIPE) { + US_DEBUGP("-- stall on control pipe\n"); + return USB_STOR_XFER_ERROR; + } + + /* some other serious problem here */ + if (result < 0) { + US_DEBUGP("-- unknown error\n"); + return USB_STOR_XFER_ERROR; + } + + /* was the entire command transferred? */ + if (result < size) { + US_DEBUGP("-- transferred only %d bytes\n", result); + return USB_STOR_XFER_SHORT; + } + + US_DEBUGP("-- transfer completed successfully\n"); + return USB_STOR_XFER_GOOD; +} + +/* + * Transfer one buffer via bulk transfer + * + * This function does basically the same thing as usb_stor_bulk_msg() + * above, except that: * - * Note that the lower layer will always retry when a NAK occurs, up to the - * timeout limit. Thus we don't have to worry about it for individual - * packets. + * 1. If the bulk pipe stalls during the transfer, the halt is + * automatically cleared; + * 2. Return codes are USB_STOR_XFER_xxx rather than the + * urb status or transfer length. */ -int usb_stor_transfer_partial(struct us_data *us, char *buf, int length) +int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, + char *buf, unsigned int length, unsigned int *act_len) { int result; int partial; - int pipe; - - /* calculate the appropriate pipe information */ - if (us->srb->sc_data_direction == SCSI_DATA_READ) - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - else - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); /* transfer the data */ - US_DEBUGP("usb_stor_transfer_partial(): xfer %d bytes\n", length); + US_DEBUGP("usb_stor_bulk_transfer_buf(): xfer %d bytes\n", length); result = usb_stor_bulk_msg(us, buf, pipe, length, &partial); US_DEBUGP("usb_stor_bulk_msg() returned %d xferred %d/%d\n", result, partial, length); + if (act_len) + *act_len = partial; /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); + US_DEBUGP("clearing endpoint halt for pipe 0x%x," + " stalled at %d bytes\n", pipe, partial); if (usb_stor_clear_halt(us, pipe) < 0) return USB_STOR_XFER_ERROR; return USB_STOR_XFER_STALLED; @@ -580,25 +623,25 @@ int usb_stor_transfer_partial(struct us_data *us, char *buf, int length) /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { - US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n"); + US_DEBUGP("-- transfer aborted\n"); return USB_STOR_XFER_ABORTED; } /* NAK - that means we've retried a few times already */ if (result == -ETIMEDOUT) { - US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n"); + US_DEBUGP("-- device NAKed\n"); return USB_STOR_XFER_ERROR; } /* the catch-all error case */ if (result) { - US_DEBUGP("usb_stor_transfer_partial(): unknown error\n"); + US_DEBUGP("-- unknown error\n"); return USB_STOR_XFER_ERROR; } /* did we send all the data? */ if (partial == length) { - US_DEBUGP("usb_stor_transfer_partial(): transfer complete\n"); + US_DEBUGP("-- transfer complete\n"); return USB_STOR_XFER_GOOD; } @@ -611,59 +654,51 @@ int usb_stor_transfer_partial(struct us_data *us, char *buf, int length) * Transfer an entire SCSI command's worth of data payload over the bulk * pipe. * - * Note that this uses usb_stor_transfer_partial to achieve its goals -- this + * Note that this uses usb_stor_transfer_buf to achieve its goals -- this * function simply determines if we're going to use scatter-gather or not, * and acts appropriately. For now, it also re-interprets the error codes. */ -void usb_stor_transfer(Scsi_Cmnd *srb, struct us_data* us) +int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe, + char *buf, unsigned int length_left, int use_sg, int *residual) { int i; int result = -1; struct scatterlist *sg; - unsigned int total_transferred = 0; - unsigned int transfer_amount; - - /* calculate how much we want to transfer */ - transfer_amount = usb_stor_transfer_length(srb); - - /* was someone foolish enough to request more data than available - * buffer space? */ - if (transfer_amount > srb->request_bufflen) - transfer_amount = srb->request_bufflen; + unsigned int amount; + unsigned int partial; /* are we scatter-gathering? */ - if (srb->use_sg) { + if (use_sg) { /* loop over all the scatter gather structures and * make the appropriate requests for each, until done */ - sg = (struct scatterlist *) srb->request_buffer; - for (i = 0; i < srb->use_sg; i++) { + sg = (struct scatterlist *) buf; + for (i = 0; (i < use_sg) && (length_left > 0); (i++, ++sg)) { /* transfer the lesser of the next buffer or the * remaining data */ - if (transfer_amount - total_transferred >= - sg[i].length) { - result = usb_stor_transfer_partial(us, - sg_address(sg[i]), sg[i].length); - total_transferred += sg[i].length; - } else - result = usb_stor_transfer_partial(us, - sg_address(sg[i]), - transfer_amount - total_transferred); + amount = sg->length < length_left ? + sg->length : length_left; + result = usb_stor_bulk_transfer_buf(us, pipe, + sg_address(*sg), amount, &partial); + length_left -= partial; /* if we get an error, end the loop here */ - if (result) + if (result != USB_STOR_XFER_GOOD) break; } - } - else + } else { /* no scatter-gather, just make the request */ - result = usb_stor_transfer_partial(us, srb->request_buffer, - transfer_amount); + result = usb_stor_bulk_transfer_buf(us, pipe, buf, + length_left, &partial); + length_left -= partial; + } - /* return the result in the data structure itself */ - srb->result = result; + /* store the residual and return the error code */ + if (residual) + *residual = length_left; + return result; } /*********************************************************************** @@ -742,7 +777,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) * Also, if we have a short transfer on a command that can't have * a short transfer, we're going to do this. */ - if ((srb->result == USB_STOR_XFER_SHORT) && + if ((srb->resid > 0) && !((srb->cmnd[0] == REQUEST_SENSE) || (srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE) || @@ -974,6 +1009,7 @@ void usb_stor_CBI_irq(struct urb *urb) int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) { + unsigned int transfer_length = usb_stor_transfer_length(srb); int result; /* re-initialize the mutex so that we avoid any races with @@ -985,14 +1021,14 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) /* COMMAND STAGE */ /* let's send the command via the control pipe */ - result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, srb->cmnd, srb->cmd_len); /* check the return code for the command */ - US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result); - if (result < 0) { + US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result); + if (result != USB_STOR_XFER_GOOD) { /* Reset flag for status notification */ clear_bit(US_FLIDX_IP_WANTED, &us->flags); } @@ -1003,22 +1039,16 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) return USB_STOR_TRANSPORT_ABORTED; } - /* a stall indicates a protocol error */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - if (result < 0) { + if (result != USB_STOR_XFER_GOOD) { /* Uh oh... serious problem here */ return USB_STOR_TRANSPORT_ERROR; } /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ - if (usb_stor_transfer_length(srb)) { - usb_stor_transfer(srb, us); - result = srb->result; + if (transfer_length > 0) { + result = usb_stor_bulk_transfer_srb(us, us->send_bulk_pipe, + srb, transfer_length); US_DEBUGP("CBI data stage result is 0x%x\n", result); /* report any errors */ @@ -1093,39 +1123,34 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) */ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us) { + unsigned int transfer_length = usb_stor_transfer_length(srb); int result; /* COMMAND STAGE */ /* let's send the command via the control pipe */ - result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, srb->cmnd, srb->cmd_len); /* check the return code for the command */ - US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result); - if (result < 0) { - /* did we abort this command? */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { - US_DEBUGP("usb_stor_CB_transport(): transfer aborted\n"); - return USB_STOR_TRANSPORT_ABORTED; - } + US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result); - /* a stall indicates a protocol error */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe\n"); - return USB_STOR_TRANSPORT_ERROR; - } + /* did we abort this command? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("usb_stor_CB_transport(): transfer aborted\n"); + return USB_STOR_TRANSPORT_ABORTED; + if (result != USB_STOR_XFER_GOOD) { /* Uh oh... serious problem here */ return USB_STOR_TRANSPORT_ERROR; } /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ - if (usb_stor_transfer_length(srb)) { - usb_stor_transfer(srb, us); - result = srb->result; + if (transfer_length) + result = usb_stor_bulk_transfer_srb(us, us->send_bulk_pipe, + srb, transfer_length); US_DEBUGP("CB data stage result is 0x%x\n", result); /* report any errors */ @@ -1153,12 +1178,12 @@ int usb_stor_Bulk_max_lun(struct us_data *us) { unsigned char data; int result; - int pipe; - /* issue the command -- use usb_control_msg() because - * this is not a scsi queued-command */ - pipe = usb_rcvctrlpipe(us->pusb_dev, 0); - result = usb_control_msg(us->pusb_dev, pipe, + /* Issue the command -- use usb_control_msg() because this is + * not a scsi queued-command. Also note that at this point the + * cached pipe values have not yet been stored. */ + result = usb_control_msg(us->pusb_dev, + usb_rcvctrlpipe(us->pusb_dev, 0), US_BULK_GET_MAX_LUN, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, @@ -1179,13 +1204,13 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) { struct bulk_cb_wrap bcb; struct bulk_cs_wrap bcs; + unsigned int transfer_length = usb_stor_transfer_length(srb); int result; - int pipe; int partial; /* set up the command wrapper */ bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb.DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb)); + bcb.DataTransferLength = cpu_to_le32(transfer_length); bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0; bcb.Tag = srb->serial_number; bcb.Lun = srb->cmnd[1] >> 5; @@ -1193,9 +1218,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) bcb.Lun |= srb->target << 4; bcb.Length = srb->cmd_len; - /* construct the pipe handle */ - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - /* copy the command payload */ memset(bcb.CDB, 0, sizeof(bcb.CDB)); memcpy(bcb.CDB, srb->cmnd, bcb.Length); @@ -1205,8 +1227,8 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) le32_to_cpu(bcb.Signature), bcb.Tag, (bcb.Lun >> 4), (bcb.Lun & 0x0F), bcb.DataTransferLength, bcb.Flags, bcb.Length); - result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, - &partial); + result = usb_stor_bulk_msg(us, &bcb, us->send_bulk_pipe, + US_BULK_CB_WRAP_LEN, &partial); US_DEBUGP("Bulk command transfer result=%d\n", result); /* did we abort this command? */ @@ -1217,47 +1239,45 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - result = usb_stor_clear_halt(us, pipe); + US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", + us->send_bulk_pipe); + result = usb_stor_clear_halt(us, us->send_bulk_pipe); /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n"); return USB_STOR_TRANSPORT_ABORTED; } - if (result < 0) - return USB_STOR_TRANSPORT_ERROR; - result = -EPIPE; + return USB_STOR_TRANSPORT_ERROR; } else if (result) { /* unknown error -- we've got a problem */ return USB_STOR_TRANSPORT_ERROR; } - /* if the command transfered well, then we go to the data stage */ - if (result == 0) { - /* send/receive data payload, if there is any */ - if (bcb.DataTransferLength) { - usb_stor_transfer(srb, us); - result = srb->result; - US_DEBUGP("Bulk data transfer result 0x%x\n", result); - - /* if it was aborted, we need to indicate that */ - if (result == USB_STOR_XFER_ABORTED) - return USB_STOR_TRANSPORT_ABORTED; - } + /* DATA STAGE */ + /* send/receive data payload, if there is any */ + if (transfer_length) { + unsigned int pipe = srb->sc_data_direction == SCSI_DATA_READ ? + us->recv_bulk_pipe : us->send_bulk_pipe; + result = usb_stor_bulk_transfer_srb(us, pipe, srb, + transfer_length); + US_DEBUGP("Bulk data transfer result 0x%x\n", result); + + /* if it was aborted, we need to indicate that */ + if (result == USB_STOR_XFER_ABORTED) + return USB_STOR_TRANSPORT_ABORTED; + if (result == USB_STOR_XFER_ERROR) + return USB_STOR_TRANSPORT_ERROR; } /* See flow chart on pg 15 of the Bulk Only Transport spec for * an explanation of how this code works. */ - /* construct the pipe handle */ - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - /* get CSW for device status */ US_DEBUGP("Attempting to get CSW...\n"); - result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, - &partial); + result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, + US_BULK_CS_WRAP_LEN, &partial); /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { @@ -1267,8 +1287,9 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - result = usb_stor_clear_halt(us, pipe); + US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", + us->recv_bulk_pipe); + result = usb_stor_clear_halt(us, us->recv_bulk_pipe); /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { @@ -1280,7 +1301,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); - result = usb_stor_bulk_msg(us, &bcs, pipe, + result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, US_BULK_CS_WRAP_LEN, &partial); /* did we abort this command? */ @@ -1291,8 +1312,9 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { - US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); - result = usb_stor_clear_halt(us, pipe); + US_DEBUGP("clearing halt for pipe 0x%x\n", + us->recv_bulk_pipe); + result = usb_stor_clear_halt(us, us->recv_bulk_pipe); /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { @@ -1364,7 +1386,7 @@ static int usb_stor_reset_common(struct us_data *us, * following a powerup or USB attach event. */ /* Use usb_control_msg() because this is not a queued-command */ - result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), + result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, request, requesttype, value, index, data, size, 20*HZ); if (result < 0) @@ -1377,14 +1399,12 @@ static int usb_stor_reset_common(struct us_data *us, /* Use usb_clear_halt() because this is not a queued-command */ US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n"); - result = usb_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); + result = usb_clear_halt(us->pusb_dev, us->recv_bulk_pipe); if (result < 0) goto Done; US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n"); - result = usb_clear_halt(us->pusb_dev, - usb_sndbulkpipe(us->pusb_dev, us->ep_out)); + result = usb_clear_halt(us->pusb_dev, us->send_bulk_pipe); Done: diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h index 914ecb8be155..7b40bc350ae0 100644 --- a/drivers/usb/storage/transport.h +++ b/drivers/usb/storage/transport.h @@ -115,7 +115,7 @@ struct bulk_cs_wrap { #define US_BULK_GET_MAX_LUN 0xfe /* - * usb_stor_transfer() return codes, in order of severity + * usb_stor_bulk_transfer_xxx() return codes, in order of severity */ #define USB_STOR_XFER_GOOD 0 /* good transfer */ #define USB_STOR_XFER_SHORT 1 /* transfered less than expected */ @@ -151,14 +151,26 @@ extern int usb_stor_Bulk_reset(struct us_data*); extern unsigned int usb_stor_transfer_length(Scsi_Cmnd*); extern void usb_stor_invoke_transport(Scsi_Cmnd*, struct us_data*); extern void usb_stor_abort_transport(struct us_data*); -extern int usb_stor_transfer_partial(struct us_data*, char*, int); -extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, - unsigned int len, unsigned int *act_len); +extern int usb_stor_bulk_msg(struct us_data *us, void *data, + unsigned int pipe, unsigned int len, unsigned int *act_len); extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe, u8 request, u8 requesttype, u16 value, u16 index, void *data, u16 size); -extern int usb_stor_clear_halt(struct us_data*, int ); -extern void usb_stor_transfer(Scsi_Cmnd*, struct us_data*); +extern int usb_stor_clear_halt(struct us_data*, unsigned int pipe); +extern int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, + u8 request, u8 requesttype, u16 value, u16 index, + void *data, u16 size); +extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, + char *buf, unsigned int length, unsigned int *act_len); +extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe, + char *buf, unsigned int length, int use_sg, int *residual); + +static __inline__ int usb_stor_bulk_transfer_srb(struct us_data *us, + unsigned int pipe, Scsi_Cmnd *srb, unsigned int length) { + return usb_stor_bulk_transfer_sg(us, pipe, srb->request_buffer, + length, srb->use_sg, &srb->resid); +} + #endif diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index f423b7e69ab5..6eebb126156d 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -525,6 +525,12 @@ static int usb_stor_allocate_urbs(struct us_data *ss) int maxp; int result; + /* calculate and store the pipe values */ + ss->send_bulk_pipe = usb_sndbulkpipe(ss->pusb_dev, ss->ep_out); + ss->recv_bulk_pipe = usb_rcvbulkpipe(ss->pusb_dev, ss->ep_in); + ss->send_ctrl_pipe = usb_sndctrlpipe(ss->pusb_dev, 0); + ss->recv_ctrl_pipe = usb_rcvctrlpipe(ss->pusb_dev, 0); + /* allocate the usb_ctrlrequest for control packets */ US_DEBUGP("Allocating usb_ctrlrequest\n"); ss->dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index 2a9e9a1f6c2e..9b078b5c4c2a 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -134,6 +134,10 @@ struct us_data { struct semaphore dev_semaphore; /* protect pusb_dev */ struct usb_device *pusb_dev; /* this usb_device */ unsigned long flags; /* from filter initially */ + unsigned int send_bulk_pipe; /* cached pipe values */ + unsigned int recv_bulk_pipe; + unsigned int send_ctrl_pipe; + unsigned int recv_ctrl_pipe; /* information about the device -- always good */ char vendor[USB_STOR_STRING_LEN]; diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index 096014df8eaa..8271d0bbcbb1 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c @@ -380,7 +380,7 @@ acornfb_palette_decode(u_int regno, u_int *red, u_int *green, u_int *blue, * vder : >= vdsr */ static void -acornfb_set_timing(struct fb_var_screeninfo *var) +acornfb_set_timing(struct fb_info *info, struct fb_var_screeninfo *var) { struct vidc_timing vidc; u_int vcr, fsize; @@ -470,7 +470,7 @@ acornfb_set_timing(struct fb_var_screeninfo *var) words_per_line = var->xres * var->bits_per_pixel / 32; - if (current_par.using_vram && current_par.screen_size == 2048*1024) + if (current_par.using_vram && info->fix.smem_len == 2048*1024) words_per_line /= 2; /* RiscPC doesn't use the VIDC's VRAM control. */ @@ -549,7 +549,7 @@ acornfb_palette_decode(u_int regno, u_int *red, u_int *green, u_int *blue, * the resolution to fit the rules. */ static int -acornfb_adjust_timing(struct fb_var_screeninfo *var, int con) +acornfb_adjust_timing(struct fb_info *info, struct fb_var_screeninfo *var, int con) { u_int font_line_len; u_int fontht; @@ -595,13 +595,13 @@ acornfb_adjust_timing(struct fb_var_screeninfo *var, int con) * If minimum screen size is greater than that we have * available, reject it. */ - if (min_size > current_par.screen_size) + if (min_size > info->fix.smem_len) return -EINVAL; /* Find int 'y', such that y * fll == s * sam < maxsize * y = s * sam / fll; s = maxsize / sam */ - for (size = current_par.screen_size; + for (size = info->fix.smem_len; nr_y = size / font_line_len, min_size <= size; size -= sam_size) { if (nr_y * font_line_len == size) @@ -614,14 +614,14 @@ acornfb_adjust_timing(struct fb_var_screeninfo *var, int con) /* * failed, use ypan */ - size = current_par.screen_size; + size = info->fix.smem_len; var->yres_virtual = size / (font_line_len / fontht); } else var->yres_virtual = nr_y; } else if (var->yres_virtual > nr_y) var->yres_virtual = nr_y; - current_par.screen_end = current_par.screen_base_p + size; + current_par.screen_end = info->fix.smem_start + size; /* * Fix yres & yoffset if needed. @@ -691,7 +691,7 @@ acornfb_validate_timing(struct fb_var_screeninfo *var, } static inline void -acornfb_update_dma(struct fb_var_screeninfo *var) +acornfb_update_dma(struct fb_info *info, struct fb_var_screeninfo *var) { int off = (var->yoffset * var->xres_virtual * var->bits_per_pixel) >> 3; @@ -699,7 +699,7 @@ acornfb_update_dma(struct fb_var_screeninfo *var) #if defined(HAS_MEMC) memc_write(VDMA_INIT, off >> 2); #elif defined(HAS_IOMD) - iomd_writel(current_par.screen_base_p + off, IOMD_VIDINIT); + iomd_writel(info->fix.smem_start + off, IOMD_VIDINIT); #endif } @@ -792,7 +792,7 @@ acornfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, } static int -acornfb_decode_var(struct fb_var_screeninfo *var, int con) +acornfb_decode_var(struct fb_info *info, struct fb_var_screeninfo *var, int con) { int err; @@ -865,7 +865,7 @@ acornfb_decode_var(struct fb_var_screeninfo *var, int con) * Validate and adjust the resolution to * match the video generator hardware. */ - err = acornfb_adjust_timing(var, con); + err = acornfb_adjust_timing(info, var, con); if (err) return err; @@ -877,55 +877,18 @@ acornfb_decode_var(struct fb_var_screeninfo *var, int con) } static int -acornfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) -{ - struct display *display; - - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - strcpy(fix->id, "Acorn"); - - if (con >= 0) - display = fb_display + con; - else - display = &global_disp; - - fix->smem_start = current_par.screen_base_p; - fix->smem_len = current_par.screen_size; - fix->type = display->type; - fix->type_aux = display->type_aux; - fix->xpanstep = 0; - fix->ypanstep = display->ypanstep; - fix->ywrapstep = display->ywrapstep; - fix->visual = display->visual; - fix->line_length = display->line_length; - fix->accel = FB_ACCEL_NONE; - - return 0; -} - -static int -acornfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) -{ - if (con == -1) { - *var = global_disp.var; - } else - *var = fb_display[con].var; - - return 0; -} - -static int acornfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { struct display *display; - int err, chgvar = 0; + unsigned int visual, chgvar = 0; + int err; if (con >= 0) display = fb_display + con; else display = &global_disp; - err = acornfb_decode_var(var, con); + err = acornfb_decode_var(info, var, con); if (err) return err; @@ -969,21 +932,21 @@ acornfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) case 1: current_par.palette_size = 2; display->dispsw = &fbcon_mfb; - display->visual = FB_VISUAL_MONO10; + visual = FB_VISUAL_MONO10; break; #endif #ifdef FBCON_HAS_CFB2 case 2: current_par.palette_size = 4; display->dispsw = &fbcon_cfb2; - display->visual = FB_VISUAL_PSEUDOCOLOR; + visual = FB_VISUAL_PSEUDOCOLOR; break; #endif #ifdef FBCON_HAS_CFB4 case 4: current_par.palette_size = 16; display->dispsw = &fbcon_cfb4; - display->visual = FB_VISUAL_PSEUDOCOLOR; + visual = FB_VISUAL_PSEUDOCOLOR; break; #endif #ifdef FBCON_HAS_CFB8 @@ -991,9 +954,9 @@ acornfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) current_par.palette_size = VIDC_PALETTE_SIZE; display->dispsw = &fbcon_cfb8; #ifdef HAS_VIDC - display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR; + visual = FB_VISUAL_STATIC_PSEUDOCOLOR; #else - display->visual = FB_VISUAL_PSEUDOCOLOR; + visual = FB_VISUAL_PSEUDOCOLOR; #endif break; #endif @@ -1002,7 +965,7 @@ acornfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) current_par.palette_size = 32; display->dispsw = &fbcon_cfb16; display->dispsw_data = current_par.cmap.cfb16; - display->visual = FB_VISUAL_DIRECTCOLOR; + visual = FB_VISUAL_DIRECTCOLOR; break; #endif #ifdef FBCON_HAS_CFB32 @@ -1010,22 +973,17 @@ acornfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) current_par.palette_size = VIDC_PALETTE_SIZE; display->dispsw = &fbcon_cfb32; display->dispsw_data = current_par.cmap.cfb32; - display->visual = FB_VISUAL_TRUECOLOR; + visual = FB_VISUAL_TRUECOLOR; break; #endif default: display->dispsw = &fbcon_dummy; + visual = FB_VISUAL_MONO10; break; } - info->screen_base = (char *)current_par.screen_base; - display->type = FB_TYPE_PACKED_PIXELS; - display->type_aux = 0; - display->ypanstep = 1; - display->ywrapstep = 1; - display->line_length = display->next_line = (var->xres * var->bits_per_pixel) / 8; - display->can_soft_blank = display->visual == FB_VISUAL_PSEUDOCOLOR ? 1 : 0; + display->can_soft_blank = visual == FB_VISUAL_PSEUDOCOLOR ? 1 : 0; display->inverse = 0; if (chgvar && info && info->changevar) @@ -1036,16 +994,18 @@ acornfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) unsigned long start, size; int control; + info->fix.visual = visual; + #if defined(HAS_MEMC) start = 0; - size = current_par.screen_size - VDMA_XFERSIZE; + size = info->fix.smem_len - VDMA_XFERSIZE; control = 0; memc_write(VDMA_START, start); memc_write(VDMA_END, size >> 2); #elif defined(HAS_IOMD) - start = current_par.screen_base_p; + start = info->fix.smem_start; size = current_par.screen_end; if (current_par.using_vram) { @@ -1060,8 +1020,8 @@ acornfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) iomd_writel(size, IOMD_VIDEND); iomd_writel(control, IOMD_VIDCR); #endif - acornfb_update_dma(var); - acornfb_set_timing(var); + acornfb_update_dma(info, var); + acornfb_set_timing(info, var); if (display->cmap.len) cmap = &display->cmap; @@ -1090,7 +1050,7 @@ acornfb_pan_display(struct fb_var_screeninfo *var, int con, if (y_bottom > fb_display[con].var.yres_virtual) return -EINVAL; - acornfb_update_dma(var); + acornfb_update_dma(info, var); fb_display[con].var.yoffset = var->yoffset; if (var->vmode & FB_VMODE_YWRAP) @@ -1147,8 +1107,8 @@ acornfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma off = vma->vm_pgoff << PAGE_SHIFT; - start = current_par.screen_base_p; - len = PAGE_ALIGN(start & ~PAGE_MASK) + current_par.screen_size; + start = info->fix.smem_start; + len = PAGE_ALIGN(start & ~PAGE_MASK) + info->fix.smem_len; start &= PAGE_MASK; if ((vma->vm_end - vma->vm_start + off) > len) return -EINVAL; @@ -1176,23 +1136,21 @@ acornfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma } static struct fb_ops acornfb_ops = { - .owner = THIS_MODULE, - .fb_get_fix = acornfb_get_fix, - .fb_get_var = acornfb_get_var, - .fb_set_var = acornfb_set_var, - .fb_get_cmap = acornfb_get_cmap, - .fb_set_cmap = gen_set_cmap, - .fb_setcolreg = acornfb_setcolreg, - .fb_pan_display =acornfb_pan_display, - .fb_blank = acornfb_blank, - .fb_mmap = acornfb_mmap, + .owner = THIS_MODULE, + .fb_set_var = acornfb_set_var, + .fb_get_cmap = acornfb_get_cmap, + .fb_set_cmap = gen_set_cmap, + .fb_setcolreg = acornfb_setcolreg, + .fb_pan_display = acornfb_pan_display, + .fb_blank = acornfb_blank, + .fb_mmap = acornfb_mmap, }; static int acornfb_updatevar(int con, struct fb_info *info) { if (con == info->currcon) - acornfb_update_dma(&fb_display[con].var); + acornfb_update_dma(info, &fb_display[con].var); return 0; } @@ -1302,15 +1260,24 @@ acornfb_init_fbinfo(void) strcpy(fb_info.modename, "Acorn"); strcpy(fb_info.fontname, "Acorn8x8"); - fb_info.node = NODEV; - fb_info.fbops = &acornfb_ops; - fb_info.disp = &global_disp; - fb_info.changevar = NULL; - fb_info.switch_con = acornfb_switch; - fb_info.updatevar = acornfb_updatevar; - fb_info.flags = FBINFO_FLAG_DEFAULT; - - global_disp.dispsw = &fbcon_dummy; + fb_info.node = NODEV; + fb_info.fbops = &acornfb_ops; + fb_info.disp = &global_disp; + fb_info.changevar = NULL; + fb_info.switch_con = acornfb_switch; + fb_info.updatevar = acornfb_updatevar; + fb_info.flags = FBINFO_FLAG_DEFAULT; + + strcpy(fb_info.fix.id, "Acorn"); + fb_info.fix.type = FB_TYPE_PACKED_PIXELS; + fb_info.fix.type_aux = 0; + fb_info.fix.xpanstep = 0; + fb_info.fix.ypanstep = 1; + fb_info.fix.ywrapstep = 1; + fb_info.fix.line_length = 0; + fb_info.fix.accel = FB_ACCEL_NONE; + + global_disp.dispsw = &fbcon_dummy; /* * setup initial parameters @@ -1618,10 +1585,10 @@ acornfb_init(void) } } - fb_info.currcon = -1; - current_par.screen_base = SCREEN_BASE; - current_par.screen_base_p = SCREEN_START; - current_par.using_vram = 0; + fb_info.currcon = -1; + fb_info.screen_base = (char *)SCREEN_BASE; + fb_info.fix.smem_start = SCREEN_START; + current_par.using_vram = 0; /* * If vram_size is set, we are using VRAM in @@ -1653,27 +1620,26 @@ acornfb_init(void) * VRAM. Archimedes/A5000 machines use a * fixed address for their framebuffers. */ - int order = 0; - unsigned long page, top; - while (size > (PAGE_SIZE * (1 << order))) - order++; - current_par.screen_base = __get_free_pages(GFP_KERNEL, order); - if (current_par.screen_base == 0) { + unsigned long page, top, base; + int order = get_order(size); + + base = __get_free_pages(GFP_KERNEL, order); + if (base == 0) { printk(KERN_ERR "acornfb: unable to allocate screen " "memory\n"); return -ENOMEM; } - top = current_par.screen_base + (PAGE_SIZE * (1 << order)); + top = base + (PAGE_SIZE << order); + /* Mark the framebuffer pages as reserved so mmap will work. */ - for (page = current_par.screen_base; - page < PAGE_ALIGN(current_par.screen_base + size); - page += PAGE_SIZE) + for (page = base; page < PAGE_ALIGN(base + size); page += PAGE_SIZE) SetPageReserved(virt_to_page(page)); /* Hand back any excess pages that we allocated. */ - for (page = current_par.screen_base + size; page < top; page += PAGE_SIZE) + for (page = base + size; page < top; page += PAGE_SIZE) free_page(page); - current_par.screen_base_p = - virt_to_phys((void *)current_par.screen_base); + + fb_info.screen_base = (char *)base; + fb_info.fix.smem_start = virt_to_phys(fb_info.screen_base); } #endif #if defined(HAS_VIDC) @@ -1683,7 +1649,7 @@ acornfb_init(void) free_unused_pages(PAGE_OFFSET + size, PAGE_OFFSET + MAX_SIZE); #endif - current_par.screen_size = size; + fb_info.fix.smem_len = size; current_par.palette_size = VIDC_PALETTE_SIZE; /* @@ -1734,9 +1700,9 @@ acornfb_init(void) v_sync = h_sync / (init_var.yres + init_var.upper_margin + init_var.lower_margin + init_var.vsync_len); - printk(KERN_INFO "Acornfb: %ldkB %cRAM, %s, using %dx%d, " + printk(KERN_INFO "Acornfb: %dkB %cRAM, %s, using %dx%d, " "%d.%03dkHz, %dHz\n", - current_par.screen_size / 1024, + fb_info.fix.smem_len / 1024, current_par.using_vram ? 'V' : 'D', VIDC_NAME, init_var.xres, init_var.yres, h_sync / 1000, h_sync % 1000, v_sync); diff --git a/drivers/video/acornfb.h b/drivers/video/acornfb.h index c0e45dcecfab..fd08ae82bffa 100644 --- a/drivers/video/acornfb.h +++ b/drivers/video/acornfb.h @@ -47,10 +47,7 @@ union palette { }; struct acornfb_par { - unsigned long screen_base; - unsigned long screen_base_p; unsigned long screen_end; - unsigned long screen_size; unsigned int dram_size; unsigned int vram_half_sam; unsigned int palette_size; diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c index d00c96dccb1e..14a67d332255 100644 --- a/drivers/video/clps711xfb.c +++ b/drivers/video/clps711xfb.c @@ -25,6 +25,7 @@ #include <linux/fb.h> #include <linux/init.h> #include <linux/proc_fs.h> +#include <linux/delay.h> #include <video/fbcon.h> @@ -37,7 +38,7 @@ struct fb_info *cfb; -#define CMAP_SIZE 16 +#define CMAP_MAX_SIZE 16 /* The /proc entry for the backlight. */ static struct proc_dir_entry *clps7111fb_backlight_proc_entry = NULL; @@ -48,6 +49,13 @@ static int clps7111fb_proc_backlight_write(struct file *file, const char *buffer, unsigned long count, void *data); /* + * LCD AC Prescale. This comes from the LCD panel manufacturers specifications. + * This determines how many clocks + 1 of CL1 before the M signal toggles. + * The number of lines on the display must not be divisible by this number. + */ +static unsigned int lcd_ac_prescale = 13; + +/* * Set a single color register. Return != 0 for invalid regno. */ static int @@ -56,7 +64,7 @@ clps7111fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, { unsigned int level, mask, shift, pal; - if (regno >= CMAP_SIZE) + if (regno >= (1 << info->var.bits_per_pixel)) return 1; /* gray = 0.30*R + 0.58*G + 0.11*B */ @@ -104,6 +112,8 @@ clps7111fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) if (var->bits_per_pixel > 4) return -EINVAL; + + return 0; } /* @@ -112,32 +122,46 @@ clps7111fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) static int clps7111fb_set_par(struct fb_info *info) { - unsigned int lcdcon, syscon; + unsigned int lcdcon, syscon, pixclock; - switch (var->bits_per_pixel) { + switch (info->var.bits_per_pixel) { case 1: - info->fix.visual = FB_VISUAL_MONO01; + info->fix.visual = FB_VISUAL_MONO01; break; case 2: - info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; break; case 4: - info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; break; } info->fix.line_length = info->var.xres_virtual * info->var.bits_per_pixel / 8; - /* - * LCDCON must only be changed while the LCD is disabled - */ lcdcon = (info->var.xres_virtual * info->var.yres_virtual * info->var.bits_per_pixel) / 128 - 1; lcdcon |= ((info->var.xres_virtual / 16) - 1) << 13; - lcdcon |= 2 << 19; - lcdcon |= 13 << 25; - lcdcon |= LCDCON_GSEN; - lcdcon |= LCDCON_GSMD; + lcdcon |= lcd_ac_prescale << 25; + + /* + * Calculate pixel prescale value from the pixclock. This is: + * 36.864MHz / pixclock_mhz - 1. + * However, pixclock is in picoseconds, so this ends up being: + * 36864000 * pixclock_ps / 10^12 - 1 + * and this will overflow the 32-bit math. We perform this as + * (9 * 4096000 == 36864000): + * pixclock_ps * 9 * (4096000 / 10^12) - 1 + */ + pixclock = 9 * info->var.pixclock / 244140 - 1; + lcdcon |= pixclock << 19; + + if (info->var.bits_per_pixel == 4) + lcdcon |= LCDCON_GSMD; + if (info->var.bits_per_pixel >= 2) + lcdcon |= LCDCON_GSEN; + /* + * LCDCON must only be changed while the LCD is disabled + */ syscon = clps_readl(SYSCON1); clps_writel(syscon & ~SYSCON1_LCDEN, SYSCON1); clps_writel(lcdcon, LCDCON); @@ -149,8 +173,6 @@ static int clps7111fb_blank(int blank, struct fb_info *info) { if (blank) { if (machine_is_edb7211()) { - int i; - /* Turn off the LCD backlight. */ clps_writeb(clps_readb(PDDR) & ~EDB_PD3_LCDBL, PDDR); @@ -169,8 +191,6 @@ static int clps7111fb_blank(int blank, struct fb_info *info) } } else { if (machine_is_edb7211()) { - int i; - /* Power up the LCD controller. */ clps_writel(clps_readl(SYSCON1) | SYSCON1_LCDEN, SYSCON1); @@ -256,6 +276,93 @@ clps7111fb_proc_backlight_write(struct file *file, const char *buffer, return count; } +static void __init clps711x_guess_lcd_params(struct fb_info *info) +{ + unsigned int lcdcon, syscon, size; + unsigned long phys_base = PAGE_OFFSET; + void *virt_base = (void *)PAGE_OFFSET; + + info->var.xres_virtual = 640; + info->var.yres_virtual = 240; + info->var.bits_per_pixel = 4; + info->var.activate = FB_ACTIVATE_NOW; + info->var.height = -1; + info->var.width = -1; + info->var.pixclock = 93006; /* 10.752MHz pixel clock */ + + /* + * If the LCD controller is already running, decode the values + * in LCDCON to xres/yres/bpp/pixclock/acprescale + */ + syscon = clps_readl(SYSCON1); + if (syscon & SYSCON1_LCDEN) { + lcdcon = clps_readl(LCDCON); + + /* + * Decode GSMD and GSEN bits to bits per pixel + */ + switch (lcdcon & (LCDCON_GSMD | LCDCON_GSEN)) { + case LCDCON_GSMD | LCDCON_GSEN: + info->var.bits_per_pixel = 4; + break; + + case LCDCON_GSEN: + info->var.bits_per_pixel = 2; + break; + + default: + info->var.bits_per_pixel = 1; + break; + } + + /* + * Decode xres/yres + */ + info->var.xres_virtual = (((lcdcon >> 13) & 0x3f) + 1) * 16; + info->var.yres_virtual = (((lcdcon & 0x1fff) + 1) * 128) / + (info->var.xres_virtual * + info->var.bits_per_pixel); + + /* + * Calculate pixclock + */ + info->var.pixclock = (((lcdcon >> 19) & 0x3f) + 1) * 244140 / 9; + + /* + * Grab AC prescale + */ + lcd_ac_prescale = (lcdcon >> 25) & 0x1f; + } + + info->var.xres = info->var.xres_virtual; + info->var.yres = info->var.yres_virtual; + info->var.grayscale = info->var.bits_per_pixel > 1; + + size = info->var.xres * info->var.yres * info->var.bits_per_pixel / 8; + + /* + * Might be worth checking to see if we can use the on-board + * RAM if size here... + * CLPS7110 - no on-board SRAM + * EP7212 - 38400 bytes + */ + if (size < 38400) { + printk(KERN_INFO "CLPS711xFB: could use on-board SRAM?\n"); + } + + if ((syscon & SYSCON1_LCDEN) == 0) { + /* + * The display isn't running. Ensure that + * the display memory is empty. + */ + memset(virt_base, 0, size); + } + + info->screen_base = virt_base; + info->fix.smem_start = phys_base; + info->fix.smem_len = PAGE_ALIGN(size); + info->fix.type = FB_TYPE_PACKED_PIXELS; +} int __init clps711xfb_init(void) { @@ -266,34 +373,19 @@ int __init clps711xfb_init(void) goto out; memset(cfb, 0, sizeof(*cfb) + sizeof(struct display)); - memset((void *)PAGE_OFFSET, 0, 0x14000); + strcpy(cfb->fix.id, "clps711x"); cfb->currcon = -1; - - strcpy(cfb->fix.id, "clps7111"); - cfb->screen_base = (void *)PAGE_OFFSET; - cfb->fix.smem_start = PAGE_OFFSET; - cfb->fix.smem_len = 0x14000; - cfb->fix.type = FB_TYPE_PACKED_PIXELS; - - cfb->var.xres = 640; - cfb->var.xres_virtual = 640; - cfb->var.yres = 240; - cfb->var.yres_virtual = 240; - cfb->var.bits_per_pixel = 4; - cfb->var.grayscale = 1; - cfb->var.activate = FB_ACTIVATE_NOW; - cfb->var.height = -1; - cfb->var.width = -1; - cfb->fbops = &clps7111fb_ops; - cfb->changevar = NULL; - cfb->switch_con = gen_switch; - cfb->updatevar = gen_update_var; + cfb->changevar = NULL; + cfb->switch_con = gen_switch; + cfb->updatevar = gen_update_var; cfb->flags = FBINFO_FLAG_DEFAULT; cfb->disp = (struct display *)(cfb + 1); - fb_alloc_cmap(&cfb->cmap, CMAP_SIZE, 0); + clps711x_guess_lcd_params(cfb); + + fb_alloc_cmap(&cfb->cmap, CMAP_MAX_SIZE, 0); /* Register the /proc entries. */ clps7111fb_backlight_proc_entry = create_proc_entry("backlight", 0444, @@ -317,8 +409,6 @@ int __init clps711xfb_init(void) } if (machine_is_edb7211()) { - int i; - /* Power up the LCD panel. */ clps_writeb(clps_readb(PDDR) | EDB_PD2_LCDEN, PDDR); diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c index a090625f0483..e21e8e38e931 100644 --- a/drivers/video/cyber2000fb.c +++ b/drivers/video/cyber2000fb.c @@ -1,11 +1,14 @@ /* * linux/drivers/video/cyber2000fb.c * - * Copyright (C) 1998-2000 Russell King + * Copyright (C) 1998-2002 Russell King * * MIPS and 50xx clock support * Copyright (C) 2001 Bradley D. LaRonde <brad@ltc.com> * + * 32 bit support, text color and panning fixes for modes != 8 bit + * Copyright (C) 2002 Denis Oliver Kropp <dok@directfb.org> + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. @@ -14,17 +17,24 @@ * * Based on cyberfb.c. * - * Note that we now use the new fbcon fix, var and cmap scheme. We do still - * have to check which console is the currently displayed one however, since - * especially for the colourmap stuff. + * Note that we now use the new fbcon fix, var and cmap scheme. We do + * still have to check which console is the currently displayed one + * however, especially for the colourmap stuff. + * + * We also use the new hotplug PCI subsystem. I'm not sure if there + * are any such cards, but I'm erring on the side of caution. We don't + * want to go pop just because someone does have one. * - * We also use the new hotplug PCI subsystem. I'm not sure if there are any - * such cards, but I'm erring on the side of caution. We don't want to go - * pop just because someone does have one. + * Note that this doesn't work fully in the case of multiple CyberPro + * cards with grabbers. We currently can only attach to the first + * CyberPro card found. * - * Note that this doesn't work fully in the case of multiple CyberPro cards - * with grabbers. We currently can only attach to the first CyberPro card - * found. + * When we're in truecolour mode, we power down the LUT RAM as a power + * saving feature. Also, when we enter any of the powersaving modes + * (except soft blanking) we power down the RAMDACs. This saves about + * 1W, which is roughly 8% of the power consumption of a NetWinder + * (which, incidentally, is about the same saving as a 2.5in hard disk + * entering standby mode.) */ #include <linux/config.h> #include <linux/module.h> @@ -49,11 +59,7 @@ #include <video/fbcon-cfb8.h> #include <video/fbcon-cfb16.h> #include <video/fbcon-cfb24.h> - -/* - * Define this if you don't want RGB565, but RGB555 for 16bpp displays. - */ -/*#define CFB16_IS_CFB15*/ +#include <video/fbcon-cfb32.h> #include "cyber2000fb.h" @@ -64,6 +70,7 @@ struct cfb_info { struct pci_dev *dev; unsigned char *region; unsigned char *regs; + u_int id; int func_use_count; u_long ref_ps; @@ -80,6 +87,11 @@ struct cfb_info { u_char mem_ctl2; u_char mclk_mult; u_char mclk_div; + /* + * RAMDAC control register is both of these or'ed together + */ + u_char ramdac_ctrl; + u_char ramdac_powerdown; }; static char default_font_storage[40]; @@ -139,7 +151,7 @@ static void cyber2000_accel_wait(struct cfb_info *cfb) { int count = 100000; - while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & 0x80) { + while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & CO_CTRL_BUSY) { if (!count--) { debug_printf("accel_wait timed out\n"); cyber2000fb_writeb(0, CO_REG_CONTROL, cfb); @@ -163,8 +175,7 @@ cyber2000_accel_bmove(struct display *display, int sy, int sx, int dy, int dx, struct cfb_info *cfb = (struct cfb_info *)display->fb_info; struct fb_var_screeninfo *var = &display->var; u_long src, dst; - u_int fh, fw; - int cmd = CO_CMD_L_PATTERN_FGCOL; + u_int fh, fw, cmd = CO_CMD_L_PATTERN_FGCOL; fw = fontwidth(display); sx *= fw; @@ -194,22 +205,21 @@ cyber2000_accel_bmove(struct display *display, int sy, int sx, int dy, int dx, dst = dx + dy * var->xres_virtual; cyber2000_accel_wait(cfb); - cyber2000fb_writeb(0x00, CO_REG_CONTROL, cfb); - cyber2000fb_writeb(0x03, CO_REG_FORE_MIX, cfb); - cyber2000fb_writew(width, CO_REG_WIDTH, cfb); + cyber2000fb_writeb(0x00, CO_REG_CONTROL, cfb); + cyber2000fb_writew(width, CO_REG_PIXWIDTH, cfb); + cyber2000fb_writew(height, CO_REG_PIXHEIGHT, cfb); - if (var->bits_per_pixel != 24) { - cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb); - cyber2000fb_writel(src, CO_REG_SRC_PTR, cfb); - } else { - cyber2000fb_writel(dst * 3, CO_REG_DEST_PTR, cfb); - cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb); - cyber2000fb_writel(src * 3, CO_REG_SRC_PTR, cfb); + if (var->bits_per_pixel == 24) { + cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb); + dst *= 3; + src *= 3; } - cyber2000fb_writew(height, CO_REG_HEIGHT, cfb); - cyber2000fb_writew(cmd, CO_REG_CMD_L, cfb); - cyber2000fb_writew(0x2800, CO_REG_CMD_H, cfb); + cyber2000fb_writel(src, CO_REG_SRC1_PTR, cfb); + cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb); + cyber2000fb_writeb(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb); + cyber2000fb_writew(cmd, CO_REG_CMD_L, cfb); + cyber2000fb_writew(CO_CMD_H_FGSRCMAP|CO_CMD_H_BLITTER, CO_REG_CMD_H, cfb); } static void @@ -230,28 +240,25 @@ cyber2000_accel_clear(struct vc_data *conp, struct display *display, int sy, height = height * fh - 1; cyber2000_accel_wait(cfb); - cyber2000fb_writeb(0x00, CO_REG_CONTROL, cfb); - cyber2000fb_writeb(0x03, CO_REG_FORE_MIX, cfb); - cyber2000fb_writew(width, CO_REG_WIDTH, cfb); - cyber2000fb_writew(height, CO_REG_HEIGHT, cfb); + cyber2000fb_writeb(0x00, CO_REG_CONTROL, cfb); + cyber2000fb_writew(width, CO_REG_PIXWIDTH, cfb); + cyber2000fb_writew(height, CO_REG_PIXHEIGHT, cfb); - switch (var->bits_per_pixel) { - case 16: - bgx = ((u16 *)display->dispsw_data)[bgx]; - case 8: - cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb); - break; - - case 24: - cyber2000fb_writel(dst * 3, CO_REG_DEST_PTR, cfb); + if (var->bits_per_pixel == 24) { cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb); - bgx = ((u32 *)display->dispsw_data)[bgx]; - break; + dst *= 3; } - cyber2000fb_writel(bgx, CO_REG_FOREGROUND, cfb); + if (var->bits_per_pixel == 16) + bgx = ((u16 *)display->dispsw_data)[bgx]; + else if (var->bits_per_pixel >= 24) + bgx = ((u32 *)display->dispsw_data)[bgx]; + + cyber2000fb_writel(bgx, CO_REG_FGCOLOUR, cfb); + cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb); + cyber2000fb_writeb(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb); cyber2000fb_writew(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L, cfb); - cyber2000fb_writew(0x0800, CO_REG_CMD_H, cfb); + cyber2000fb_writew(CO_CMD_H_BLITTER, CO_REG_CMD_H, cfb); } static void @@ -292,16 +299,23 @@ cyber2000_accel_clear_margins(struct vc_data *conp, struct display *display, } static struct display_switch fbcon_cyber_accel = { - .setup = cyber2000_accel_setup, - .bmove = cyber2000_accel_bmove, - .clear = cyber2000_accel_clear, - .putc = cyber2000_accel_putc, - .putcs = cyber2000_accel_putcs, - .revc = cyber2000_accel_revc, - .clear_margins =cyber2000_accel_clear_margins, - .fontwidthmask =FONTWIDTH(8)|FONTWIDTH(16) + .setup = cyber2000_accel_setup, + .bmove = cyber2000_accel_bmove, + .clear = cyber2000_accel_clear, + .putc = cyber2000_accel_putc, + .putcs = cyber2000_accel_putcs, + .revc = cyber2000_accel_revc, + .clear_margins = cyber2000_accel_clear_margins, + .fontwidthmask = FONTWIDTH(8)|FONTWIDTH(16) }; +static inline u32 convert_bitfield(u_int val, struct fb_bitfield *bf) +{ + u_int mask = (1 << bf->length) - 1; + + return (val >> (16 - bf->length) & mask) << bf->offset; +} + /* * Set a single color register. Return != 0 for invalid regno. */ @@ -311,85 +325,145 @@ cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, { struct cfb_info *cfb = (struct cfb_info *)info; struct fb_var_screeninfo *var = &cfb->display->var; + u32 pseudo_val; + int ret = 1; - if (regno >= NR_PALETTE) + switch (cfb->fb.fix.visual) { + default: return 1; - red >>= 8; - green >>= 8; - blue >>= 8; +#ifdef FBCON_HAS_CFB8 + /* + * Pseudocolour: + * 8 8 + * pixel --/--+--/--> red lut --> red dac + * | 8 + * +--/--> green lut --> green dac + * | 8 + * +--/--> blue lut --> blue dac + */ + case FB_VISUAL_PSEUDOCOLOR: + if (regno >= NR_PALETTE) + return 1; - cfb->palette[regno].red = red; - cfb->palette[regno].green = green; - cfb->palette[regno].blue = blue; + red >>= 8; + green >>= 8; + blue >>= 8; + + cfb->palette[regno].red = red; + cfb->palette[regno].green = green; + cfb->palette[regno].blue = blue; - switch (var->bits_per_pixel) { -#ifdef FBCON_HAS_CFB8 - case 8: cyber2000fb_writeb(regno, 0x3c8, cfb); - cyber2000fb_writeb(red, 0x3c9, cfb); + cyber2000fb_writeb(red, 0x3c9, cfb); cyber2000fb_writeb(green, 0x3c9, cfb); - cyber2000fb_writeb(blue, 0x3c9, cfb); - break; + cyber2000fb_writeb(blue, 0x3c9, cfb); + return 0; #endif -#ifdef FBCON_HAS_CFB16 - case 16: -#ifndef CFB16_IS_CFB15 - if (var->green.length == 6) { - if (regno < 64) { - /* write green */ - cyber2000fb_writeb(regno << 2, 0x3c8, cfb); - cyber2000fb_writeb(cfb->palette[regno >> 1].red, 0x3c9, cfb); - cyber2000fb_writeb(green, 0x3c9, cfb); - cyber2000fb_writeb(cfb->palette[regno >> 1].blue, 0x3c9, cfb); - } - - if (regno < 32) { - /* write red,blue */ - cyber2000fb_writeb(regno << 3, 0x3c8, cfb); - cyber2000fb_writeb(red, 0x3c9, cfb); - cyber2000fb_writeb(cfb->palette[regno << 1].green, 0x3c9, cfb); - cyber2000fb_writeb(blue, 0x3c9, cfb); - } - - if (regno < 16) - ((u16 *)cfb->fb.pseudo_palette)[regno] = - regno | regno << 5 | regno << 11; - break; + /* + * Direct colour: + * n rl + * pixel --/--+--/--> red lut --> red dac + * | gl + * +--/--> green lut --> green dac + * | bl + * +--/--> blue lut --> blue dac + * n = bpp, rl = red length, gl = green length, bl = blue length + */ + case FB_VISUAL_DIRECTCOLOR: + red >>= 8; + green >>= 8; + blue >>= 8; + + if (var->green.length == 6 && regno < 64) { + cfb->palette[regno << 2].green = green; + + /* + * The 6 bits of the green component are applied + * to the high 6 bits of the LUT. + */ + cyber2000fb_writeb(regno << 2, 0x3c8, cfb); + cyber2000fb_writeb(cfb->palette[regno >> 1].red, 0x3c9, cfb); + cyber2000fb_writeb(green, 0x3c9, cfb); + cyber2000fb_writeb(cfb->palette[regno >> 1].blue, 0x3c9, cfb); + + green = cfb->palette[regno << 3].green; + + ret = 0; } -#endif - if (regno < 32) { + + if (var->green.length >= 5 && regno < 32) { + cfb->palette[regno << 3].red = red; + cfb->palette[regno << 3].green = green; + cfb->palette[regno << 3].blue = blue; + + /* + * The 5 bits of each colour component are + * applied to the high 5 bits of the LUT. + */ cyber2000fb_writeb(regno << 3, 0x3c8, cfb); cyber2000fb_writeb(red, 0x3c9, cfb); cyber2000fb_writeb(green, 0x3c9, cfb); cyber2000fb_writeb(blue, 0x3c9, cfb); + ret = 0; } - if (regno < 16) - ((u16 *)cfb->fb.pseudo_palette)[regno] = - regno | regno << 5 | regno << 10; - break; -#endif + if (var->green.length == 4 && regno < 16) { + cfb->palette[regno << 4].red = red; + cfb->palette[regno << 4].green = green; + cfb->palette[regno << 4].blue = blue; -#ifdef FBCON_HAS_CFB24 - case 24: - cyber2000fb_writeb(regno, 0x3c8, cfb); - cyber2000fb_writeb(red, 0x3c9, cfb); - cyber2000fb_writeb(green, 0x3c9, cfb); - cyber2000fb_writeb(blue, 0x3c9, cfb); + /* + * The 5 bits of each colour component are + * applied to the high 5 bits of the LUT. + */ + cyber2000fb_writeb(regno << 4, 0x3c8, cfb); + cyber2000fb_writeb(red, 0x3c9, cfb); + cyber2000fb_writeb(green, 0x3c9, cfb); + cyber2000fb_writeb(blue, 0x3c9, cfb); + ret = 0; + } - if (regno < 16) - ((u32 *)cfb->fb.pseudo_palette)[regno] = - regno | regno << 8 | regno << 16; + /* + * Since this is only used for the first 16 colours, we + * don't have to care about overflowing for regno >= 32 + */ + pseudo_val = regno << var->red.offset | + regno << var->green.offset | + regno << var->blue.offset; break; -#endif - default: - return 1; + /* + * True colour: + * n rl + * pixel --/--+--/--> red dac + * | gl + * +--/--> green dac + * | bl + * +--/--> blue dac + * n = bpp, rl = red length, gl = green length, bl = blue length + */ + case FB_VISUAL_TRUECOLOR: + pseudo_val = convert_bitfield(transp ^ 0xffff, &var->transp); + pseudo_val |= convert_bitfield(red, &var->red); + pseudo_val |= convert_bitfield(green, &var->green); + pseudo_val |= convert_bitfield(blue, &var->blue); + break; } - return 0; + /* + * Now set our pseudo palette for the CFB16/24/32 drivers. + */ + if (regno < 16) { + if (var->bits_per_pixel == 16) + ((u16 *)cfb->fb.pseudo_palette)[regno] = pseudo_val; + else + ((u32 *)cfb->fb.pseudo_palette)[regno] = pseudo_val; + ret = 0; + } + + return ret; } struct par_info { @@ -399,7 +473,7 @@ struct par_info { u_char clock_mult; u_char clock_div; u_char extseqmisc; - u_char pixformat; + u_char co_pixfmt; u_char crtc_ofl; u_char crtc[19]; u_int width; @@ -409,8 +483,7 @@ struct par_info { /* * Other */ - u_char palette_ctrl; - u_int vmode; + u_char ramdac; }; static const u_char crtc_idx[] = { @@ -419,6 +492,18 @@ static const u_char crtc_idx[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 }; +static void cyber2000fb_write_ramdac_ctrl(struct cfb_info *cfb) +{ + unsigned int i; + unsigned int val = cfb->ramdac_ctrl | cfb->ramdac_powerdown; + + cyber2000fb_writeb(0x56, 0x3ce, cfb); + i = cyber2000fb_readb(0x3cf, cfb); + cyber2000fb_writeb(i | 4, 0x3cf, cfb); + cyber2000fb_writeb(val, 0x3c6, cfb); + cyber2000fb_writeb(i, 0x3cf, cfb); +} + static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw) { u_int i; @@ -450,7 +535,7 @@ static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw) for (i = 0x0a; i < 0x10; i++) cyber2000_crtcw(i, 0, cfb); - cyber2000_grphw(0x11, hw->crtc_ofl, cfb); + cyber2000_grphw(EXT_CRT_VRTOFL, hw->crtc_ofl, cfb); cyber2000_grphw(0x00, 0x00, cfb); cyber2000_grphw(0x01, 0x00, cfb); cyber2000_grphw(0x02, 0x00, cfb); @@ -471,16 +556,6 @@ static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw) cyber2000_attrw(0x13, 0x00, cfb); cyber2000_attrw(0x14, 0x00, cfb); - /* woody: set the interlaced bit... */ - /* FIXME: what about doublescan? */ - cyber2000fb_writeb(0x11, 0x3ce, cfb); - i = cyber2000fb_readb(0x3cf, cfb); - if (hw->vmode == FB_VMODE_INTERLACED) - i |= 0x20; - else - i &= ~0x20; - cyber2000fb_writeb(i, 0x3cf, cfb); - /* PLL registers */ cyber2000_grphw(EXT_DCLK_MULT, hw->clock_mult, cfb); cyber2000_grphw(EXT_DCLK_DIV, hw->clock_div, cfb); @@ -490,11 +565,8 @@ static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw) cyber2000_grphw(0xb9, 0x80, cfb); cyber2000_grphw(0xb9, 0x00, cfb); - cyber2000fb_writeb(0x56, 0x3ce, cfb); - i = cyber2000fb_readb(0x3cf, cfb); - cyber2000fb_writeb(i | 4, 0x3cf, cfb); - cyber2000fb_writeb(hw->palette_ctrl, 0x3c6, cfb); - cyber2000fb_writeb(i, 0x3cf, cfb); + cfb->ramdac_ctrl = hw->ramdac; + cyber2000fb_write_ramdac_ctrl(cfb); cyber2000fb_writeb(0x20, 0x3c0, cfb); cyber2000fb_writeb(0xff, 0x3c6, cfb); @@ -504,25 +576,20 @@ static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw) ((hw->pitch >> 4) & 0x30), cfb); cyber2000_grphw(EXT_SEQ_MISC, hw->extseqmisc, cfb); - cyber2000_grphw(EXT_BIU_MISC, EXT_BIU_MISC_LIN_ENABLE | - EXT_BIU_MISC_COP_ENABLE | - EXT_BIU_MISC_COP_BFC, cfb); - /* * Set up accelerator registers */ cyber2000fb_writew(hw->width, CO_REG_SRC_WIDTH, cfb); cyber2000fb_writew(hw->width, CO_REG_DEST_WIDTH, cfb); - cyber2000fb_writeb(hw->pixformat, CO_REG_PIX_FORMAT, cfb); + cyber2000fb_writeb(hw->co_pixfmt, CO_REG_PIXFMT, cfb); } static inline int cyber2000fb_update_start(struct cfb_info *cfb, struct fb_var_screeninfo *var) { - u_int base; + u_int base = var->yoffset * var->xres_virtual + var->xoffset; - base = var->yoffset * var->xres_virtual * var->bits_per_pixel + - var->xoffset * var->bits_per_pixel; + base *= var->bits_per_pixel; /* * Convert to bytes and shift two extra bits because DAC @@ -606,8 +673,9 @@ cyber2000fb_decode_crtc(struct par_info *hw, struct cfb_info *cfb, hw->crtc[16] = Vblankend; hw->crtc[18] = 0xff; - /* overflow - graphics reg 0x11 */ - /* 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10 + /* + * overflow - graphics reg 0x11 + * 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10 * 4=LINECOMP:10 5-IVIDEO 6=FIXCNT */ hw->crtc_ofl = @@ -615,7 +683,12 @@ cyber2000fb_decode_crtc(struct par_info *hw, struct cfb_info *cfb, BIT(Vdispend, 10, 0x01, 1) | BIT(Vsyncstart, 10, 0x01, 2) | BIT(Vblankstart,10, 0x01, 3) | - 1 << 4; + EXT_CRT_VRTOFL_LINECOMP10; + + /* woody: set the interlaced bit... */ + /* FIXME: what about doublescan? */ + if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) + hw->crtc_ofl |= EXT_CRT_VRTOFL_INTERLACE; return 0; } @@ -735,51 +808,131 @@ static int cyber2000fb_decode_var(struct fb_var_screeninfo *var, struct cfb_info *cfb, struct par_info *hw) { + unsigned int mem; int err; hw->width = var->xres_virtual; - hw->palette_ctrl = 0x06; - hw->vmode = var->vmode; + hw->ramdac = RAMDAC_VREFEN | RAMDAC_DAC8BIT; + + var->transp.msb_right = 0; + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; switch (var->bits_per_pixel) { #ifdef FBCON_HAS_CFB8 case 8: /* PSEUDOCOLOUR, 256 */ - hw->pixformat = PIXFORMAT_8BPP; - hw->extseqmisc = EXT_SEQ_MISC_8; + hw->co_pixfmt = CO_PIXFMT_8BPP; hw->pitch = hw->width >> 3; + hw->extseqmisc = EXT_SEQ_MISC_8; + + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; break; #endif #ifdef FBCON_HAS_CFB16 - case 16: - hw->pixformat = PIXFORMAT_16BPP; + case 16:/* DIRECTCOLOUR, 64k or 32k */ + hw->co_pixfmt = CO_PIXFMT_16BPP; hw->pitch = hw->width >> 2; - hw->palette_ctrl |= 0x10; -#ifndef CFB16_IS_CFB15 - /* DIRECTCOLOUR, 64k */ - if (var->green.length == 6) { + switch (var->green.length) { + case 6: /* RGB565, 64k */ hw->extseqmisc = EXT_SEQ_MISC_16_RGB565; + + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + break; + + default: + case 5: /* RGB555, 32k */ + hw->extseqmisc = EXT_SEQ_MISC_16_RGB555; + + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + break; + + case 4: /* RGB444, 4k + transparency? */ + hw->extseqmisc = EXT_SEQ_MISC_16_RGB444; + + var->transp.offset = 12; + var->transp.length = 4; + var->red.offset = 8; + var->red.length = 4; + var->green.offset = 4; + var->green.length = 4; + var->blue.offset = 0; + var->blue.length = 4; break; } -#endif - /* DIRECTCOLOUR, 32k */ - hw->extseqmisc = EXT_SEQ_MISC_16_RGB555; break; - #endif #ifdef FBCON_HAS_CFB24 case 24:/* TRUECOLOUR, 16m */ - hw->pixformat = PIXFORMAT_24BPP; - hw->extseqmisc = EXT_SEQ_MISC_24_RGB888; + hw->co_pixfmt = CO_PIXFMT_24BPP; hw->width *= 3; hw->pitch = hw->width >> 3; - hw->palette_ctrl |= 0x10; + hw->ramdac |= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN); + hw->extseqmisc = EXT_SEQ_MISC_24_RGB888; + + var->transp.offset = 0; + var->transp.length = 0; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32:/* TRUECOLOUR, 16m */ + hw->co_pixfmt = CO_PIXFMT_32BPP; + hw->pitch = hw->width >> 1; + hw->ramdac |= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN); + hw->extseqmisc = EXT_SEQ_MISC_32; + + var->transp.offset = 24; + var->transp.length = 8; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; break; #endif default: return -EINVAL; } + mem = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8); + if (mem > cfb->fb.fix.smem_len) + var->yres_virtual = cfb->fb.fix.smem_len * 8 / + (var->bits_per_pixel * var->xres_virtual); + + if (var->yres > var->yres_virtual) + var->yres = var->yres_virtual; + if (var->xres > var->xres_virtual) + var->xres = var->xres_virtual; + err = cyber2000fb_decode_clock(hw, cfb, var); if (err) return err; @@ -807,7 +960,7 @@ cyber2000fb_set_var(struct fb_var_screeninfo *var, int con, struct cfb_info *cfb = (struct cfb_info *)info; struct display *display; struct par_info hw; - int err, chgvar = 0; + int err, chgvar; /* * CONUPDATE and SMOOTH_XPAN are equal. However, @@ -819,7 +972,7 @@ cyber2000fb_set_var(struct fb_var_screeninfo *var, int con, var->yoffset = cfb->display->var.yoffset; } - err = cyber2000fb_decode_var(var, (struct cfb_info *)info, &hw); + err = cyber2000fb_decode_var(var, cfb, &hw); if (err) return err; @@ -831,84 +984,62 @@ cyber2000fb_set_var(struct fb_var_screeninfo *var, int con, if (con < 0) { display = cfb->fb.disp; - chgvar = 0; } else { display = fb_display + con; } - if (display->var.xres != var->xres) - chgvar = 1; - if (display->var.yres != var->yres) - chgvar = 1; - if (display->var.xres_virtual != var->xres_virtual) - chgvar = 1; - if (display->var.yres_virtual != var->yres_virtual) - chgvar = 1; - if (display->var.bits_per_pixel != var->bits_per_pixel) + chgvar = cfb->fb.var.xres != var->xres || + cfb->fb.var.yres != var->yres || + cfb->fb.var.xres_virtual != var->xres_virtual || + cfb->fb.var.yres_virtual != var->yres_virtual || + cfb->fb.var.bits_per_pixel != var->bits_per_pixel; + + if (memcmp(&cfb->fb.var.red, &var->red, sizeof(var->red)) || + memcmp(&cfb->fb.var.green, &var->green, sizeof(var->green)) || + memcmp(&cfb->fb.var.blue, &var->blue, sizeof(var->blue))) chgvar = 1; + if (con >= 0 && chgvar == 0) + return 0; + if (con < 0) chgvar = 0; - var->red.msb_right = 0; - var->green.msb_right = 0; - var->blue.msb_right = 0; + /* + * If we are setting all the virtual consoles, also set the + * defaults used to create new consoles. + */ + err = var->activate; + var->activate = FB_ACTIVATE_NOW; + if (err & FB_ACTIVATE_ALL) + cfb->fb.disp->var = *var; + + cfb->fb.var = *var; + cfb->fb.fix.line_length = var->xres_virtual * var->bits_per_pixel / 8; switch (var->bits_per_pixel) { #ifdef FBCON_HAS_CFB8 case 8: /* PSEUDOCOLOUR, 256 */ - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 0; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - - cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; cfb->dispsw = &fbcon_cfb8; display->dispsw_data = NULL; - display->next_line = var->xres_virtual; break; #endif #ifdef FBCON_HAS_CFB16 - case 16: - var->bits_per_pixel = 16; - var->red.length = 5; - var->green.offset = 5; - var->blue.offset = 0; - var->blue.length = 5; - - cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR; + case 16:/* DIRECTCOLOUR */ cfb->dispsw = &fbcon_cfb16; display->dispsw_data = cfb->fb.pseudo_palette; - display->next_line = var->xres_virtual * 2; - -#ifndef CFB16_IS_CFB15 - /* DIRECTCOLOUR, 64k */ - if (var->green.length == 6) { - var->red.offset = 11; - var->green.length = 6; - break; - } -#endif - /* DIRECTCOLOUR, 32k */ - var->red.offset = 10; - var->green.length = 5; break; #endif #ifdef FBCON_HAS_CFB24 case 24:/* TRUECOLOUR, 16m */ - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - - cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; cfb->dispsw = &fbcon_cfb24; display->dispsw_data = cfb->fb.pseudo_palette; - display->next_line = var->xres_virtual * 3; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32:/* TRUECOLOUR, 16m */ + cfb->dispsw = &fbcon_cfb32; + display->dispsw_data = cfb->fb.pseudo_palette; break; #endif default:/* in theory this should never happen */ @@ -918,40 +1049,34 @@ cyber2000fb_set_var(struct fb_var_screeninfo *var, int con, break; } + /* + * 8bpp displays are always pseudo colour. + * 16bpp and above are direct colour or true colour, depending + * on whether the RAMDAC palettes are bypassed. (Direct colour + * has palettes, true colour does not.) + */ + if (var->bits_per_pixel == 8) + cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; + else if (hw.ramdac & RAMDAC_BYPASS) + cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; + else + cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR; + if (var->accel_flags & FB_ACCELF_TEXT && cfb->dispsw != &fbcon_dummy) display->dispsw = &fbcon_cyber_accel; else display->dispsw = cfb->dispsw; - cfb->fb.fix.line_length = display->next_line; - - display->line_length = cfb->fb.fix.line_length; - display->visual = cfb->fb.fix.visual; - display->type = cfb->fb.fix.type; - display->type_aux = cfb->fb.fix.type_aux; - display->ypanstep = cfb->fb.fix.ypanstep; - display->ywrapstep = cfb->fb.fix.ywrapstep; display->can_soft_blank = 1; display->inverse = 0; - display->var = *var; - display->var.activate &= ~FB_ACTIVATE_ALL; - - cfb->fb.var = display->var; - - /* - * If we are setting all the virtual consoles, also set the - * defaults used to create new consoles. - */ - if (var->activate & FB_ACTIVATE_ALL) - cfb->fb.disp->var = display->var; - - if (chgvar && info && cfb->fb.changevar) - cfb->fb.changevar(con); - cyber2000fb_update_start(cfb, var); cyber2000fb_set_timing(cfb, &hw); + cyber2000fb_update_start(cfb, var); fb_set_cmap(&cfb->fb.cmap, 1, &cfb->fb); + if (chgvar && cfb->fb.changevar) + cfb->fb.changevar(con); + return 0; } @@ -1044,6 +1169,20 @@ static int cyber2000fb_switch(int con, struct fb_info *info) /* * (Un)Blank the display. + * + * Blank the screen if blank_mode != 0, else unblank. If + * blank == NULL then the caller blanks by setting the CLUT + * (Color Look Up Table) to all black. Return 0 if blanking + * succeeded, != 0 if un-/blanking failed due to e.g. a + * video mode which doesn't support it. Implements VESA + * suspend and powerdown modes on hardware that supports + * disabling hsync/vsync: + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + * + * wms...Enable VESA DMPS compatible powerdown mode + * run "setterm -powersave powerdown" to take advantage */ static int cyber2000fb_blank(int blank, struct fb_info *info) { @@ -1051,22 +1190,6 @@ static int cyber2000fb_blank(int blank, struct fb_info *info) unsigned int sync = 0; int i; - /* - * Blank the screen if blank_mode != 0, else unblank. If - * blank == NULL then the caller blanks by setting the CLUT - * (Color Look Up Table) to all black. Return 0 if blanking - * succeeded, != 0 if un-/blanking failed due to e.g. a - * video mode which doesn't support it. Implements VESA - * suspend and powerdown modes on hardware that supports - * disabling hsync/vsync: - * blank_mode == 2: suspend vsync - * blank_mode == 3: suspend hsync - * blank_mode == 4: powerdown - * - * wms...Enable VESA DMPS compatible powerdown mode - * run "setterm -powersave powerdown" to take advantage - */ - switch (blank) { case 4: /* powerdown - both sync lines down */ sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_0; @@ -1078,44 +1201,54 @@ static int cyber2000fb_blank(int blank, struct fb_info *info) sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_NORMAL; break; case 1: /* soft blank */ - break; default: /* unblank */ break; } + cyber2000_grphw(EXT_SYNC_CTL, sync, cfb); - switch (blank) { - case 4: - case 3: - case 2: - case 1: /* soft blank */ + if (blank <= 1) { + /* turn on ramdacs */ + cfb->ramdac_powerdown &= ~(RAMDAC_DACPWRDN | RAMDAC_BYPASS | RAMDAC_RAMPWRDN); + cyber2000fb_write_ramdac_ctrl(cfb); + } + + /* + * Soft blank/unblank the display. + */ + if (blank) { /* soft blank */ for (i = 0; i < NR_PALETTE; i++) { cyber2000fb_writeb(i, 0x3c8, cfb); cyber2000fb_writeb(0, 0x3c9, cfb); cyber2000fb_writeb(0, 0x3c9, cfb); cyber2000fb_writeb(0, 0x3c9, cfb); } - break; - default: /* unblank */ + } else { /* unblank */ for (i = 0; i < NR_PALETTE; i++) { cyber2000fb_writeb(i, 0x3c8, cfb); cyber2000fb_writeb(cfb->palette[i].red, 0x3c9, cfb); cyber2000fb_writeb(cfb->palette[i].green, 0x3c9, cfb); cyber2000fb_writeb(cfb->palette[i].blue, 0x3c9, cfb); } - break; } + + if (blank >= 2) { + /* turn off ramdacs */ + cfb->ramdac_powerdown |= RAMDAC_DACPWRDN | RAMDAC_BYPASS | RAMDAC_RAMPWRDN; + cyber2000fb_write_ramdac_ctrl(cfb); + } + return 0; } static struct fb_ops cyber2000fb_ops = { .owner = THIS_MODULE, .fb_set_var = cyber2000fb_set_var, + .fb_get_cmap = gen_get_cmap, + .fb_set_cmap = gen_set_cmap, .fb_setcolreg = cyber2000fb_setcolreg, .fb_pan_display = cyber2000fb_pan_display, .fb_blank = cyber2000fb_blank, - .fb_get_cmap = gen_get_cmap, - .fb_set_cmap = gen_set_cmap, }; /* @@ -1206,18 +1339,18 @@ EXPORT_SYMBOL(cyber2000fb_get_fb_var); * 640x480, hsync 31.5kHz, vsync 60Hz */ static struct fb_videomode __devinitdata cyber2000fb_default_mode = { - .refresh = 60, - .xres = 640, - .yres = 480, - .pixclock = 39722, - .left_margin = 56, - .right_margin = 16, - .upper_margin = 34, - .lower_margin = 9, - .hsync_len = 88, - .vsync_len = 2, - .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, - .vmode = FB_VMODE_NONINTERLACED + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 39722, + .left_margin = 56, + .right_margin = 16, + .upper_margin = 34, + .lower_margin = 9, + .hsync_len = 88, + .vsync_len = 2, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED }; static char igs_regs[] __devinitdata = { @@ -1265,7 +1398,7 @@ static void cyberpro_init_hw(struct cfb_info *cfb) for (i = 0; i < sizeof(igs_regs); i += 2) cyber2000_grphw(igs_regs[i], igs_regs[i+1], cfb); - if (cfb->fb.fix.accel == FB_ACCEL_IGS_CYBER5000) { + if (cfb->id == ID_CYBERPRO_5000) { unsigned char val; cyber2000fb_writeb(0xba, 0x3ce, cfb); val = cyber2000fb_readb(0x3cf, cfb) & 0x80; @@ -1286,6 +1419,8 @@ cyberpro_alloc_fb_info(unsigned int id, char *name) memset(cfb, 0, sizeof(struct cfb_info) + sizeof(struct display)); + cfb->id = id; + if (id == ID_CYBERPRO_5000) cfb->ref_ps = 40690; // 24.576 MHz else @@ -1403,6 +1538,8 @@ static int __devinit cyberpro_common_probe(struct cfb_info *cfb) u_int h_sync, v_sync; int err; + cyberpro_init_hw(cfb); + /* * Get the video RAM size and width from the VGA register. * This should have been already initialised by the BIOS, @@ -1521,8 +1658,6 @@ cyberpro_vl_probe(void) cfb->mclk_mult = 0xdb; cfb->mclk_div = 0x54; - cyberpro_init_hw(cfb); - err = cyberpro_common_probe(cfb); if (err) goto failed; @@ -1559,6 +1694,8 @@ failed_release: */ static int cyberpro_pci_enable_mmio(struct cfb_info *cfb) { + unsigned char val; + #if defined(__sparc_v9__) #error "You loose, consult DaveM." #elif defined(__sparc__) @@ -1593,6 +1730,22 @@ static int cyberpro_pci_enable_mmio(struct cfb_info *cfb) outb(EXT_BIU_MISC, 0x3ce); outb(EXT_BIU_MISC_LIN_ENABLE, 0x3cf); #endif + + /* + * Allow the CyberPro to accept PCI burst accesses + */ + val = cyber2000_grphr(EXT_BUS_CTL, cfb); + if (!(val & EXT_BUS_CTL_PCIBURST_WRITE)) { + printk(KERN_INFO "%s: enabling PCI bursts\n", cfb->fb.fix.id); + + val |= EXT_BUS_CTL_PCIBURST_WRITE; + + if (cfb->id == ID_CYBERPRO_5000) + val |= EXT_BUS_CTL_PCIBURST_READ; + + cyber2000_grphw(EXT_BUS_CTL, val, cfb); + } + return 0; } @@ -1652,8 +1805,6 @@ cyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) cfb->mclk_div = 0x54; #endif - cyberpro_init_hw(cfb); - err = cyberpro_common_probe(cfb); if (err) goto failed; @@ -1742,12 +1893,12 @@ static struct pci_device_id cyberpro_pci_table[] __devinitdata = { MODULE_DEVICE_TABLE(pci,cyberpro_pci_table); static struct pci_driver cyberpro_driver = { - .name = "CyberPro", - .probe = cyberpro_pci_probe, - .remove = __devexit_p(cyberpro_pci_remove), - .suspend = cyberpro_pci_suspend, - .resume = cyberpro_pci_resume, - .id_table = cyberpro_pci_table + .name = "CyberPro", + .probe = cyberpro_pci_probe, + .remove = __devexit_p(cyberpro_pci_remove), + .suspend = cyberpro_pci_suspend, + .resume = cyberpro_pci_resume, + .id_table = cyberpro_pci_table }; #endif @@ -1758,17 +1909,20 @@ static struct pci_driver cyberpro_driver = { */ int __init cyber2000fb_init(void) { - int ret = -1, err = -ENODEV; + int ret = -1, err; + #ifdef CONFIG_ARCH_SHARK err = cyberpro_vl_probe(); if (!err) { - ret = err; + ret = 0; MOD_INC_USE_COUNT; } #endif +#ifdef CONFIG_PCI err = pci_module_init(&cyberpro_driver); if (!err) - ret = err; + ret = 0; +#endif return ret ? err : 0; } diff --git a/drivers/video/cyber2000fb.h b/drivers/video/cyber2000fb.h index 2f0eb757c1a4..261d157ccee0 100644 --- a/drivers/video/cyber2000fb.h +++ b/drivers/video/cyber2000fb.h @@ -36,9 +36,15 @@ static void debug_printf(char *fmt, ...) #define debug_printf(x...) do { } while (0) #endif -#define PIXFORMAT_8BPP 0 -#define PIXFORMAT_16BPP 1 -#define PIXFORMAT_24BPP 2 +#define RAMDAC_RAMPWRDN 0x01 +#define RAMDAC_DAC8BIT 0x02 +#define RAMDAC_VREFEN 0x04 +#define RAMDAC_BYPASS 0x10 +#define RAMDAC_DACPWRDN 0x40 + +#define EXT_CRT_VRTOFL 0x11 +#define EXT_CRT_VRTOFL_LINECOMP10 0x10 +#define EXT_CRT_VRTOFL_INTERLACE 0x20 #define EXT_CRT_IRQ 0x12 #define EXT_CRT_IRQ_ENABLE 0x01 @@ -61,7 +67,8 @@ static void debug_printf(char *fmt, ...) #define EXT_BUS_CTL_LIN_2MB 0x01 #define EXT_BUS_CTL_LIN_4MB 0x02 #define EXT_BUS_CTL_ZEROWAIT 0x04 -#define EXT_BUS_CTL_PCIBURST 0x20 +#define EXT_BUS_CTL_PCIBURST_WRITE 0x20 +#define EXT_BUS_CTL_PCIBURST_READ 0x80 /* CyberPro 5000 only */ #define EXT_SEG_WRITE_PTR 0x31 #define EXT_SEG_READ_PTR 0x32 @@ -401,24 +408,54 @@ static void debug_printf(char *fmt, ...) /* * Graphics Co-processor */ -#define CO_CMD_L_PATTERN_FGCOL 0x8000 -#define CO_CMD_L_INC_LEFT 0x0004 -#define CO_CMD_L_INC_UP 0x0002 - -#define CO_CMD_H_SRC_PIXMAP 0x2000 -#define CO_CMD_H_BLITTER 0x0800 - #define CO_REG_CONTROL 0xbf011 +#define CO_CTRL_BUSY 0x80 +#define CO_CTRL_CMDFULL 0x04 +#define CO_CTRL_FIFOEMPTY 0x02 +#define CO_CTRL_READY 0x01 + #define CO_REG_SRC_WIDTH 0xbf018 -#define CO_REG_PIX_FORMAT 0xbf01c -#define CO_REG_FORE_MIX 0xbf048 -#define CO_REG_FOREGROUND 0xbf058 -#define CO_REG_WIDTH 0xbf060 -#define CO_REG_HEIGHT 0xbf062 +#define CO_REG_PIXFMT 0xbf01c +#define CO_PIXFMT_32BPP 0x03 +#define CO_PIXFMT_24BPP 0x02 +#define CO_PIXFMT_16BPP 0x01 +#define CO_PIXFMT_8BPP 0x00 + +#define CO_REG_FGMIX 0xbf048 +#define CO_FG_MIX_ZERO 0x00 +#define CO_FG_MIX_SRC_AND_DST 0x01 +#define CO_FG_MIX_SRC_AND_NDST 0x02 +#define CO_FG_MIX_SRC 0x03 +#define CO_FG_MIX_NSRC_AND_DST 0x04 +#define CO_FG_MIX_DST 0x05 +#define CO_FG_MIX_SRC_XOR_DST 0x06 +#define CO_FG_MIX_SRC_OR_DST 0x07 +#define CO_FG_MIX_NSRC_AND_NDST 0x08 +#define CO_FG_MIX_SRC_XOR_NDST 0x09 +#define CO_FG_MIX_NDST 0x0a +#define CO_FG_MIX_SRC_OR_NDST 0x0b +#define CO_FG_MIX_NSRC 0x0c +#define CO_FG_MIX_NSRC_OR_DST 0x0d +#define CO_FG_MIX_NSRC_OR_NDST 0x0e +#define CO_FG_MIX_ONES 0x0f + +#define CO_REG_FGCOLOUR 0xbf058 +#define CO_REG_BGCOLOUR 0xbf05c +#define CO_REG_PIXWIDTH 0xbf060 +#define CO_REG_PIXHEIGHT 0xbf062 #define CO_REG_X_PHASE 0xbf078 #define CO_REG_CMD_L 0xbf07c +#define CO_CMD_L_PATTERN_FGCOL 0x8000 +#define CO_CMD_L_INC_LEFT 0x0004 +#define CO_CMD_L_INC_UP 0x0002 + #define CO_REG_CMD_H 0xbf07e -#define CO_REG_SRC_PTR 0xbf170 +#define CO_CMD_H_BGSRCMAP 0x8000 /* otherwise bg colour */ +#define CO_CMD_H_FGSRCMAP 0x2000 /* otherwise fg colour */ +#define CO_CMD_H_BLITTER 0x0800 + +#define CO_REG_SRC1_PTR 0xbf170 +#define CO_REG_SRC2_PTR 0xbf174 #define CO_REG_DEST_PTR 0xbf178 #define CO_REG_DEST_WIDTH 0xbf218 diff --git a/fs/Makefile b/fs/Makefile index 7f349ff168ad..d902bdd8bda3 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -11,7 +11,7 @@ export-objs := open.o dcache.o buffer.o bio.o inode.o dquot.o mpage.o aio.o \ obj-y := open.o read_write.o devices.o file_table.o buffer.o \ bio.o super.o block_dev.o char_dev.o stat.o exec.o pipe.o \ namei.o fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \ - dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \ + dcache.o inode.o attr.o bad_inode.o file.o dnotify.o \ filesystems.o namespace.o seq_file.o xattr.o libfs.o \ fs-writeback.o mpage.o direct-io.o aio.o diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c index 0e1775bb9a7c..7560c6cfd800 100644 --- a/fs/adfs/dir_f.c +++ b/fs/adfs/dir_f.c @@ -469,9 +469,9 @@ adfs_f_free(struct adfs_dir *dir) } struct adfs_dir_ops adfs_f_dir_ops = { - read: adfs_f_read, - setpos: adfs_f_setpos, - getnext: adfs_f_getnext, - update: adfs_f_update, - free: adfs_f_free + .read = adfs_f_read, + .setpos = adfs_f_setpos, + .getnext = adfs_f_getnext, + .update = adfs_f_update, + .free = adfs_f_free }; diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c index 372485ee4a9c..fc2ad89a10b1 100644 --- a/fs/adfs/dir_fplus.c +++ b/fs/adfs/dir_fplus.c @@ -172,8 +172,8 @@ adfs_fplus_free(struct adfs_dir *dir) } struct adfs_dir_ops adfs_fplus_dir_ops = { - read: adfs_fplus_read, - setpos: adfs_fplus_setpos, - getnext: adfs_fplus_getnext, - free: adfs_fplus_free + .read = adfs_fplus_read, + .setpos = adfs_fplus_setpos, + .getnext = adfs_fplus_getnext, + .free = adfs_fplus_free }; @@ -9,6 +9,7 @@ * See ../COPYING for licensing terms. */ #include <linux/kernel.h> +#include <linux/init.h> #include <linux/errno.h> #include <linux/time.h> #include <linux/aio_abi.h> @@ -21,15 +22,9 @@ #include <linux/file.h> #include <linux/mm.h> #include <linux/mman.h> -#include <linux/vmalloc.h> -#include <linux/iobuf.h> #include <linux/slab.h> #include <linux/timer.h> -#include <linux/brlock.h> #include <linux/aio.h> -#include <linux/smp_lock.h> -#include <linux/compiler.h> -#include <linux/brlock.h> #include <linux/module.h> #include <linux/highmem.h> #include <linux/workqueue.h> @@ -20,7 +20,7 @@ #include <linux/bio.h> #include <linux/blk.h> #include <linux/slab.h> -#include <linux/iobuf.h> +#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/mempool.h> @@ -438,128 +438,6 @@ retry_segments: return 0; } -static int bio_end_io_kio(struct bio *bio, unsigned int bytes_done, int error) -{ - struct kiobuf *kio = (struct kiobuf *) bio->bi_private; - - if (bio->bi_size) - return 1; - - end_kio_request(kio, error); - bio_put(bio); - return 0; -} - -/** - * ll_rw_kio - submit a &struct kiobuf for I/O - * @rw: %READ or %WRITE - * @kio: the kiobuf to do I/O on - * @bdev: target device - * @sector: start location on disk - * - * Description: - * ll_rw_kio will map the page list inside the &struct kiobuf to - * &struct bio and queue them for I/O. The kiobuf given must describe - * a continous range of data, and must be fully prepared for I/O. - **/ -void ll_rw_kio(int rw, struct kiobuf *kio, struct block_device *bdev, sector_t sector) -{ - int i, offset, size, err, map_i, total_nr_pages, nr_pages; - struct bio *bio; - - err = 0; - if ((rw & WRITE) && bdev_read_only(bdev)) { - printk("ll_rw_bio: WRITE to ro device %s\n", bdevname(bdev)); - err = -EPERM; - goto out; - } - - if (!kio->nr_pages) { - err = -EINVAL; - goto out; - } - - /* - * maybe kio is bigger than the max we can easily map into a bio. - * if so, split it up in appropriately sized chunks. - */ - total_nr_pages = kio->nr_pages; - offset = kio->offset & ~PAGE_MASK; - size = kio->length; - - atomic_set(&kio->io_count, 1); - - map_i = 0; - -next_chunk: - nr_pages = BIO_MAX_PAGES; - if (nr_pages > total_nr_pages) - nr_pages = total_nr_pages; - - atomic_inc(&kio->io_count); - - /* - * allocate bio and do initial setup - */ - if ((bio = bio_alloc(GFP_NOIO, nr_pages)) == NULL) { - err = -ENOMEM; - goto out; - } - - bio->bi_sector = sector; - bio->bi_bdev = bdev; - bio->bi_idx = 0; - bio->bi_end_io = bio_end_io_kio; - bio->bi_private = kio; - - for (i = 0; i < nr_pages; i++, map_i++) { - int nbytes = PAGE_SIZE - offset; - - if (nbytes > size) - nbytes = size; - - BUG_ON(kio->maplist[map_i] == NULL); - - /* - * if we can't add this page to the bio, submit for i/o - * and alloc a new one if needed - */ - if (bio_add_page(bio, kio->maplist[map_i], nbytes, offset)) - break; - - /* - * kiobuf only has an offset into the first page - */ - offset = 0; - - sector += nbytes >> 9; - size -= nbytes; - total_nr_pages--; - kio->offset += nbytes; - } - - submit_bio(rw, bio); - - if (total_nr_pages) - goto next_chunk; - - if (size) { - printk("ll_rw_kio: size %d left (kio %d)\n", size, kio->length); - BUG(); - } - -out: - if (err) - kio->errno = err; - - /* - * final atomic_dec of io_count to match our initial setting of 1. - * I/O may or may not have completed at this point, final completion - * handler is only run on last decrement. - */ - end_kio_request(kio, !err); -} - /** * bio_endio - end I/O on a bio * @bio: bio @@ -662,7 +540,6 @@ module_init(init_bio); EXPORT_SYMBOL(bio_alloc); EXPORT_SYMBOL(bio_put); -EXPORT_SYMBOL(ll_rw_kio); EXPORT_SYMBOL(bio_endio); EXPORT_SYMBOL(bio_init); EXPORT_SYMBOL(bio_copy); diff --git a/fs/block_dev.c b/fs/block_dev.c index 3b95ff2d40a4..33fc669b7842 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -14,7 +14,6 @@ #include <linux/major.h> #include <linux/devfs_fs_kernel.h> #include <linux/smp_lock.h> -#include <linux/iobuf.h> #include <linux/highmem.h> #include <linux/blkdev.h> #include <linux/module.h> diff --git a/fs/buffer.c b/fs/buffer.c index 30c0adeec762..d024b78c3e60 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -28,7 +28,6 @@ #include <linux/blkdev.h> #include <linux/file.h> #include <linux/quotaops.h> -#include <linux/iobuf.h> #include <linux/highmem.h> #include <linux/module.h> #include <linux/writeback.h> @@ -2300,65 +2299,6 @@ sector_t generic_block_bmap(struct address_space *mapping, sector_t block, return tmp.b_blocknr; } -/* - * Start I/O on a physical range of kernel memory, defined by a vector - * of kiobuf structs (much like a user-space iovec list). - * - * The kiobuf must already be locked for IO. IO is submitted - * asynchronously: you need to check page->locked and page->uptodate. - * - * It is up to the caller to make sure that there are enough blocks - * passed in to completely map the iobufs to disk. - */ -int brw_kiovec(int rw, int nr, struct kiobuf *iovec[], - struct block_device *bdev, sector_t b[], int size) -{ - int transferred; - int i; - int err; - struct kiobuf * iobuf; - - if (!nr) - return 0; - - /* - * First, do some alignment and validity checks - */ - for (i = 0; i < nr; i++) { - iobuf = iovec[i]; - if ((iobuf->offset & (size-1)) || (iobuf->length & (size-1))) - return -EINVAL; - if (!iobuf->nr_pages) - panic("brw_kiovec: iobuf not initialised"); - } - - /* - * OK to walk down the iovec doing page IO on each page we find. - */ - for (i = 0; i < nr; i++) { - iobuf = iovec[i]; - iobuf->errno = 0; - - ll_rw_kio(rw, iobuf, bdev, b[i] * (size >> 9)); - } - - /* - * now they are all submitted, wait for completion - */ - transferred = 0; - err = 0; - for (i = 0; i < nr; i++) { - iobuf = iovec[i]; - kiobuf_wait_for_io(iobuf); - if (iobuf->errno && !err) - err = iobuf->errno; - if (!err) - transferred += iobuf->length; - } - - return err ? err : transferred; -} - static int end_bio_bh_io_sync(struct bio *bio, unsigned int bytes_done, int err) { struct buffer_head *bh = bio->bi_private; diff --git a/fs/dcache.c b/fs/dcache.c index 4528be4d90d1..ef0871dbcdb2 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -328,7 +328,7 @@ static inline void prune_one_dentry(struct dentry * dentry) * all the dentries are in use. */ -void prune_dcache(int count) +static void prune_dcache(int count) { spin_lock(&dcache_lock); for (; count ; count--) { @@ -572,25 +572,24 @@ void shrink_dcache_anon(struct list_head *head) * This is called from kswapd when we think we need some * more memory. */ -int shrink_dcache_memory(int ratio, unsigned int gfp_mask) +static int shrink_dcache_memory(int nr, unsigned int gfp_mask) { - int entries = dentry_stat.nr_dentry / ratio + 1; - /* - * Nasty deadlock avoidance. - * - * ext2_new_block->getblk->GFP->shrink_dcache_memory->prune_dcache-> - * prune_one_dentry->dput->dentry_iput->iput->inode->i_sb->s_op-> - * put_inode->ext2_discard_prealloc->ext2_free_blocks->lock_super-> - * DEADLOCK. - * - * We should make sure we don't hold the superblock lock over - * block allocations, but for now: - */ - if (!(gfp_mask & __GFP_FS)) - return 0; - - prune_dcache(entries); - return entries; + if (nr) { + /* + * Nasty deadlock avoidance. + * + * ext2_new_block->getblk->GFP->shrink_dcache_memory-> + * prune_dcache->prune_one_dentry->dput->dentry_iput->iput-> + * inode->i_sb->s_op->put_inode->ext2_discard_prealloc-> + * ext2_free_blocks->lock_super->DEADLOCK. + * + * We should make sure we don't hold the superblock lock over + * block allocations, but for now: + */ + if (gfp_mask & __GFP_FS) + prune_dcache(nr); + } + return dentry_stat.nr_dentry; } #define NAME_ALLOC_LEN(len) ((len+16) & ~15) @@ -1330,6 +1329,8 @@ static void __init dcache_init(unsigned long mempages) NULL, NULL); if (!dentry_cache) panic("Cannot create dentry cache"); + + set_shrinker(DEFAULT_SEEKS, shrink_dcache_memory); #if PAGE_SHIFT < 13 mempages >>= (13 - PAGE_SHIFT); @@ -1375,9 +1376,6 @@ kmem_cache_t *names_cachep; /* SLAB cache for file structures */ kmem_cache_t *filp_cachep; -/* SLAB cache for dquot structures */ -kmem_cache_t *dquot_cachep; - EXPORT_SYMBOL(d_genocide); extern void bdev_cache_init(void); @@ -1397,14 +1395,6 @@ void __init vfs_caches_init(unsigned long mempages) if(!filp_cachep) panic("Cannot create filp SLAB cache"); -#if defined (CONFIG_QUOTA) - dquot_cachep = kmem_cache_create("dquot", - sizeof(struct dquot), sizeof(unsigned long) * 4, - SLAB_HWCACHE_ALIGN, NULL, NULL); - if (!dquot_cachep) - panic("Cannot create dquot SLAB cache"); -#endif - dcache_init(mempages); inode_init(mempages); files_init(mempages); diff --git a/fs/direct-io.c b/fs/direct-io.c index 84c71f9adc4c..49377aae2c90 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -388,7 +388,7 @@ static void dio_prep_bio(struct dio *dio) /* * There is no bio. Make one now. */ -static int dio_new_bio(struct dio *dio) +static int dio_new_bio(struct dio *dio, sector_t blkno) { sector_t sector; int ret, nr_pages; @@ -396,7 +396,7 @@ static int dio_new_bio(struct dio *dio) ret = dio_bio_reap(dio); if (ret) goto out; - sector = dio->next_block_in_bio << (dio->blkbits - 9); + sector = blkno << (dio->blkbits - 9); nr_pages = min(dio->pages_left, bio_get_nr_vecs(dio->map_bh.b_bdev)); BUG_ON(nr_pages <= 0); ret = dio_bio_alloc(dio, dio->map_bh.b_bdev, sector, nr_pages); @@ -408,23 +408,26 @@ out: static int dio_bio_add_page(struct dio *dio, struct page *page, - unsigned int bv_len, unsigned int bv_offset) + unsigned int bv_len, unsigned int bv_offset, sector_t blkno) { int ret = 0; if (bv_len == 0) goto out; + /* Take a ref against the page each time it is placed into a BIO */ page_cache_get(page); if (bio_add_page(dio->bio, page, bv_len, bv_offset)) { dio_bio_submit(dio); - ret = dio_new_bio(dio); + ret = dio_new_bio(dio, blkno); if (ret == 0) { ret = bio_add_page(dio->bio, page, bv_len, bv_offset); BUG_ON(ret != 0); + } else { + /* The page didn't make it into a BIO */ + page_cache_release(page); } } - page_cache_release(page); dio->pages_left--; out: return ret; @@ -460,6 +463,7 @@ int do_direct_IO(struct dio *dio) int new_page; /* Need to insert this page into the BIO? */ unsigned int bv_offset; unsigned int bv_len; + sector_t curr_blkno; page = dio_get_page(dio); if (IS_ERR(page)) { @@ -470,6 +474,7 @@ int do_direct_IO(struct dio *dio) new_page = 1; bv_offset = 0; bv_len = 0; + curr_blkno = 0; while (block_in_page < blocks_per_page) { unsigned this_chunk_bytes; /* # of bytes mapped */ unsigned this_chunk_blocks; /* # of blocks */ @@ -477,7 +482,7 @@ int do_direct_IO(struct dio *dio) ret = get_more_blocks(dio); if (ret) - goto out; + goto fail_release; /* Handle holes */ if (!buffer_mapped(&dio->map_bh)) { @@ -494,15 +499,16 @@ int do_direct_IO(struct dio *dio) dio_prep_bio(dio); if (dio->bio == NULL) { - ret = dio_new_bio(dio); + ret = dio_new_bio(dio, dio->next_block_in_bio); if (ret) - goto out; + goto fail_release; new_page = 1; } if (new_page) { bv_len = 0; bv_offset = block_in_page << blkbits; + curr_blkno = dio->next_block_in_bio; new_page = 0; } @@ -530,11 +536,18 @@ next_block: if (dio->block_in_file == dio->final_block_in_request) break; } - ret = dio_bio_add_page(dio, page, bv_len, bv_offset); + ret = dio_bio_add_page(dio, page, bv_len, + bv_offset, curr_blkno); if (ret) - goto out; + goto fail_release; + + /* Drop the ref which was taken in get_user_pages() */ + page_cache_release(page); block_in_page = 0; } + goto out; +fail_release: + page_cache_release(page); out: return ret; } diff --git a/fs/dquot.c b/fs/dquot.c index f97b3609c894..24d50ae34824 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -55,6 +55,7 @@ #include <linux/errno.h> #include <linux/kernel.h> #include <linux/fs.h> +#include <linux/mm.h> #include <linux/time.h> #include <linux/types.h> #include <linux/string.h> @@ -481,14 +482,14 @@ static void prune_dqcache(int count) * more memory */ -int shrink_dqcache_memory(int ratio, unsigned int gfp_mask) +static int shrink_dqcache_memory(int nr, unsigned int gfp_mask) { - int entries = dqstats.allocated_dquots / ratio + 1; - - lock_kernel(); - prune_dqcache(entries); - unlock_kernel(); - return entries; + if (nr) { + lock_kernel(); + prune_dqcache(nr); + unlock_kernel(); + } + return dqstats.allocated_dquots; } /* @@ -1490,6 +1491,9 @@ static ctl_table sys_table[] = { {}, }; +/* SLAB cache for dquot structures */ +kmem_cache_t *dquot_cachep; + static int __init dquot_init(void) { int i; @@ -1499,9 +1503,17 @@ static int __init dquot_init(void) INIT_LIST_HEAD(dquot_hash + i); printk(KERN_NOTICE "VFS: Disk quotas v%s\n", __DQUOT_VERSION__); + dquot_cachep = kmem_cache_create("dquot", + sizeof(struct dquot), sizeof(unsigned long) * 4, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if (!dquot_cachep) + panic("Cannot create dquot SLAB cache"); + + set_shrinker(DEFAULT_SEEKS, shrink_dqcache_memory); + return 0; } -__initcall(dquot_init); +module_init(dquot_init); EXPORT_SYMBOL(register_quota_format); EXPORT_SYMBOL(unregister_quota_format); diff --git a/fs/exec.c b/fs/exec.c index 1f7738682388..eef86f55c0cb 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1162,7 +1162,7 @@ void format_corename(char *corename, const char *pattern, long signr) struct timeval tv; do_gettimeofday(&tv); rc = snprintf(out_ptr, out_end - out_ptr, - "%d", tv.tv_sec); + "%lu", tv.tv_sec); if (rc > out_end - out_ptr) goto out; out_ptr += rc; diff --git a/fs/fcntl.c b/fs/fcntl.c index 539711ef1061..c2fc83cdfed6 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -10,7 +10,6 @@ #include <linux/dnotify.h> #include <linux/smp_lock.h> #include <linux/slab.h> -#include <linux/iobuf.h> #include <linux/module.h> #include <linux/security.h> diff --git a/fs/file_table.c b/fs/file_table.c index d6093fc0b1b5..fe6c048c2bab 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -11,7 +11,6 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/smp_lock.h> -#include <linux/iobuf.h> #include <linux/fs.h> #include <linux/security.h> diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index d5766176fe16..17b2f603efc9 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -327,6 +327,7 @@ writeback_inodes(struct writeback_control *wbc) } spin_unlock(&sb_lock); spin_unlock(&inode_lock); + blk_run_queues(); } /* diff --git a/fs/inode.c b/fs/inode.c index d56785889730..4f56d96031ea 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -243,22 +243,25 @@ void clear_inode(struct inode *inode) * Dispose-list gets a local list with local inodes in it, so it doesn't * need to worry about list corruption and SMP locks. */ -static void dispose_list(struct list_head * head) +static void dispose_list(struct list_head *head) { - struct list_head * inode_entry; - struct inode * inode; + int nr_disposed = 0; + + while (!list_empty(head)) { + struct inode *inode; - while ((inode_entry = head->next) != head) - { - list_del(inode_entry); + inode = list_entry(head->next, struct inode, i_list); + list_del(&inode->i_list); - inode = list_entry(inode_entry, struct inode, i_list); if (inode->i_data.nrpages) truncate_inode_pages(&inode->i_data, 0); clear_inode(inode); destroy_inode(inode); - inodes_stat.nr_inodes--; + nr_disposed++; } + spin_lock(&inode_lock); + inodes_stat.nr_inodes -= nr_disposed; + spin_unlock(&inode_lock); } /* @@ -377,7 +380,7 @@ int invalidate_device(kdev_t dev, int do_sync) !inode_has_buffers(inode)) #define INODE(entry) (list_entry(entry, struct inode, i_list)) -void prune_icache(int goal) +static inline void prune_icache(int goal) { LIST_HEAD(list); struct list_head *entry, *freeable = &list; @@ -417,23 +420,19 @@ void prune_icache(int goal) * This is called from kswapd when we think we need some * more memory. */ -int shrink_icache_memory(int ratio, unsigned int gfp_mask) +static int shrink_icache_memory(int nr, unsigned int gfp_mask) { - int entries = inodes_stat.nr_inodes / ratio + 1; - /* - * Nasty deadlock avoidance.. - * - * We may hold various FS locks, and we don't - * want to recurse into the FS that called us - * in clear_inode() and friends.. - */ - if (!(gfp_mask & __GFP_FS)) - return 0; - - prune_icache(entries); - return entries; + if (nr) { + /* + * Nasty deadlock avoidance. We may hold various FS locks, + * and we don't want to recurse into the FS that called us + * in clear_inode() and friends.. + */ + if (gfp_mask & __GFP_FS) + prune_icache(nr); + } + return inodes_stat.nr_inodes; } -EXPORT_SYMBOL(shrink_icache_memory); /* * Called with the inode lock held. @@ -1226,4 +1225,6 @@ void __init inode_init(unsigned long mempages) NULL); if (!inode_cachep) panic("cannot create inode slab cache"); + + set_shrinker(DEFAULT_SEEKS, shrink_icache_memory); } diff --git a/fs/iobuf.c b/fs/iobuf.c deleted file mode 100644 index 62c44534c68a..000000000000 --- a/fs/iobuf.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * iobuf.c - * - * Keep track of the general-purpose IO-buffer structures used to track - * abstract kernel-space io buffers. - * - */ - -#include <linux/iobuf.h> -#include <linux/slab.h> - -int end_kio_request(struct kiobuf *kiobuf, int uptodate) -{ - int ret = 1; - - if ((!uptodate) && !kiobuf->errno) - kiobuf->errno = -EIO; - - if (atomic_dec_and_test(&kiobuf->io_count)) { - ret = 0; - if (kiobuf->end_io) - kiobuf->end_io(kiobuf); - wake_up(&kiobuf->wait_queue); - } - - return ret; -} - -static void kiobuf_init(struct kiobuf *iobuf) -{ - init_waitqueue_head(&iobuf->wait_queue); - atomic_set(&iobuf->io_count, 0); - iobuf->array_len = KIO_STATIC_PAGES; - iobuf->maplist = iobuf->map_array; - iobuf->nr_pages = 0; - iobuf->locked = 0; - iobuf->io_count.counter = 0; - iobuf->end_io = NULL; -} - -int alloc_kiovec(int nr, struct kiobuf **bufp) -{ - int i; - struct kiobuf *iobuf; - - for (i = 0; i < nr; i++) { - iobuf = kmalloc(sizeof(struct kiobuf), GFP_KERNEL); - if (!iobuf) { - free_kiovec(i, bufp); - return -ENOMEM; - } - kiobuf_init(iobuf); - bufp[i] = iobuf; - } - - return 0; -} - -void free_kiovec(int nr, struct kiobuf **bufp) -{ - int i; - struct kiobuf *iobuf; - - for (i = 0; i < nr; i++) { - iobuf = bufp[i]; - if (iobuf->locked) - unlock_kiovec(1, &iobuf); - if (iobuf->array_len > KIO_STATIC_PAGES) - kfree (iobuf->maplist); - kfree(bufp[i]); - } -} - -int expand_kiobuf(struct kiobuf *iobuf, int wanted) -{ - struct page ** maplist; - - if (iobuf->array_len >= wanted) - return 0; - - maplist = (struct page **) - kmalloc(wanted * sizeof(struct page **), GFP_KERNEL); - if (!maplist) - return -ENOMEM; - - /* Did it grow while we waited? */ - if (iobuf->array_len >= wanted) { - kfree(maplist); - return 0; - } - - memcpy (maplist, iobuf->maplist, iobuf->array_len * sizeof(struct page **)); - - if (iobuf->array_len > KIO_STATIC_PAGES) - kfree (iobuf->maplist); - - iobuf->maplist = maplist; - iobuf->array_len = wanted; - return 0; -} - - -void kiobuf_wait_for_io(struct kiobuf *kiobuf) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - if (atomic_read(&kiobuf->io_count) == 0) - return; - - add_wait_queue(&kiobuf->wait_queue, &wait); -repeat: - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (atomic_read(&kiobuf->io_count) != 0) { - blk_run_queues(); - schedule(); - if (atomic_read(&kiobuf->io_count) != 0) - goto repeat; - } - tsk->state = TASK_RUNNING; - remove_wait_queue(&kiobuf->wait_queue, &wait); -} - - - diff --git a/fs/open.c b/fs/open.c index 673d20cd1ee8..3e690b0cd50d 100644 --- a/fs/open.c +++ b/fs/open.c @@ -14,7 +14,6 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/tty.h> -#include <linux/iobuf.h> #include <linux/namei.h> #include <linux/backing-dev.h> #include <linux/security.h> diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 32f9e7e9dce3..7bdea5bbe922 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -202,9 +202,9 @@ static int meminfo_read_proc(char *page, char **start, off_t off, { extern unsigned long htlbpagemem, htlbzone_pages; len += sprintf(page + len, - "HugePages: %8lu\n" - "Available: %8lu\n" - "Size: %8lu kB\n", + "HugePages_Total: %5lu\n" + "HugePages_Free: %5lu\n" + "Hugepagesize: %5lu kB\n", htlbzone_pages, htlbpagemem, HPAGE_SIZE/1024); diff --git a/fs/xfs/linux/xfs_aops.c b/fs/xfs/linux/xfs_aops.c index 184d173ee192..e749c3c3bbed 100644 --- a/fs/xfs/linux/xfs_aops.c +++ b/fs/xfs/linux/xfs_aops.c @@ -34,7 +34,6 @@ #include <linux/mm.h> #include <linux/pagemap.h> #include <linux/mpage.h> -#include <linux/iobuf.h> STATIC int delalloc_convert(struct inode *, struct page *, int, int); diff --git a/fs/xfs/linux/xfs_ioctl.c b/fs/xfs/linux/xfs_ioctl.c index a2b5f0162ccd..5dbf4fd9debf 100644 --- a/fs/xfs/linux/xfs_ioctl.c +++ b/fs/xfs/linux/xfs_ioctl.c @@ -35,7 +35,6 @@ #include <xfs_dfrag.h> #include <linux/dcache.h> #include <linux/namei.h> -#include <linux/iobuf.h> extern int xfs_change_file_space(bhv_desc_t *, int, @@ -605,6 +604,7 @@ xfs_ioctl( * it is set to the file system block size to * avoid having to do block zeroing on short writes. */ +#define KIO_MAX_ATOMIC_IO 512 /* FIXME: what do we really want here? */ da.d_maxiosz = XFS_FSB_TO_B(mp, XFS_B_TO_FSBT(mp, KIO_MAX_ATOMIC_IO << 10)); diff --git a/include/asm-arm/arch-ebsa285/time.h b/include/asm-arm/arch-ebsa285/time.h index 7b40c671daad..a500b9c08b8b 100644 --- a/include/asm-arm/arch-ebsa285/time.h +++ b/include/asm-arm/arch-ebsa285/time.h @@ -62,7 +62,7 @@ static unsigned long isa_gettimeoffset(void) count_p = count; - count = (((mSEC_10_from_14/6)-1) - count) * tick; + count = (((mSEC_10_from_14/6)-1) - count) * (tick_nsec / 1000); count = (count + (mSEC_10_from_14/6)/2) / (mSEC_10_from_14/6); return count; @@ -182,7 +182,7 @@ static unsigned long timer1_gettimeoffset (void) { unsigned long value = LATCH - *CSR_TIMER1_VALUE; - return (tick * value) / LATCH; + return ((tick_nsec / 1000) * value) / LATCH; } static void timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs) diff --git a/include/asm-arm/arch-rpc/ide.h b/include/asm-arm/arch-rpc/ide.h index aaf49b1be75c..15fecab1f7b8 100644 --- a/include/asm-arm/arch-rpc/ide.h +++ b/include/asm-arm/arch-rpc/ide.h @@ -44,5 +44,5 @@ ide_init_default_hwifs(void) ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL); hw.irq = IRQ_HARDDISK; - ide_register_hw(&hw); + ide_register_hw(&hw, NULL); } diff --git a/include/asm-arm/arch-rpc/serial.h b/include/asm-arm/arch-rpc/serial.h index 1497fc6fec8c..2f12e6da9bf6 100644 --- a/include/asm-arm/arch-rpc/serial.h +++ b/include/asm-arm/arch-rpc/serial.h @@ -29,7 +29,7 @@ /* UART CLK PORT IRQ FLAGS */ #define STD_SERIAL_PORT_DEFNS \ { 0, BASE_BAUD, 0x3F8, 10, STD_COM_FLAGS }, /* ttyS0 */ \ - { 0, BASE_BAUD, 0x2F8, 10, STD_COM_FLAGS }, /* ttyS1 */ \ + { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS1 */ \ { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS2 */ \ { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS3 */ \ { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS4 */ \ diff --git a/include/asm-arm/arch-rpc/uncompress.h b/include/asm-arm/arch-rpc/uncompress.h index dde1bfc7af20..4a3036dad1f2 100644 --- a/include/asm-arm/arch-rpc/uncompress.h +++ b/include/asm-arm/arch-rpc/uncompress.h @@ -56,7 +56,7 @@ static const unsigned long palette_4[16] = { #define palette_setpixel(p) *(unsigned long *)(IO_START+0x00400000) = 0x10000000|((p) & 255) #define palette_write(v) *(unsigned long *)(IO_START+0x00400000) = 0x00000000|((v) & 0x00ffffff) -extern struct param_struct params; +static struct param_struct *params = (struct param_struct *)PARAMS_PHYS; #ifndef STANDALONE_DEBUG /* @@ -64,13 +64,13 @@ extern struct param_struct params; */ static void puts(const char *s) { - extern void ll_write_char(char *, unsigned long); + extern void ll_write_char(char *, char c, char white); int x,y; unsigned char c; char *ptr; - x = params.video_x; - y = params.video_y; + x = params->video_x; + y = params->video_y; while ( ( c = *(unsigned char *)s++ ) != '\0' ) { if ( c == '\n' ) { @@ -79,8 +79,8 @@ static void puts(const char *s) y--; } } else { - ptr = VIDMEM + ((y*video_num_columns*params.bytes_per_char_v+x)*bytes_per_char_h); - ll_write_char(ptr, c|(white<<16)); + ptr = VIDMEM + ((y*video_num_columns*params->bytes_per_char_v+x)*bytes_per_char_h); + ll_write_char(ptr, c, white); if ( ++x >= video_num_columns ) { x = 0; if ( ++y >= video_num_lines ) { @@ -90,8 +90,8 @@ static void puts(const char *s) } } - params.video_x = x; - params.video_y = y; + params->video_x = x; + params->video_y = y; } static void error(char *x); @@ -103,9 +103,9 @@ static void arch_decomp_setup(void) { int i; - video_num_lines = params.video_num_rows; - video_num_columns = params.video_num_cols; - bytes_per_char_h = params.bytes_per_char_h; + video_num_lines = params->video_num_rows; + video_num_columns = params->video_num_cols; + bytes_per_char_h = params->bytes_per_char_h; video_size_row = video_num_columns * bytes_per_char_h; if (bytes_per_char_h == 4) for (i = 0; i < 256; i++) @@ -140,7 +140,7 @@ static void arch_decomp_setup(void) white = 7; } - if (params.nr_pages * params.page_size < 4096*1024) error("<4M of mem\n"); + if (params->nr_pages * params->page_size < 4096*1024) error("<4M of mem\n"); } #endif diff --git a/include/asm-arm/arch-sa1100/irqs.h b/include/asm-arm/arch-sa1100/irqs.h index 66e4f596c739..4d906d33a78e 100644 --- a/include/asm-arm/arch-sa1100/irqs.h +++ b/include/asm-arm/arch-sa1100/irqs.h @@ -109,7 +109,7 @@ #define AUDRDD (IRQ_BOARD_END + 41) #define AUDSTO (IRQ_BOARD_END + 42) #define IRQ_USBPWR (IRQ_BOARD_END + 43) -#define IRQ_NHCIM (IRQ_BOARD_END + 44) +#define IRQ_HCIM (IRQ_BOARD_END + 44) #define IRQ_HCIBUFFACC (IRQ_BOARD_END + 45) #define IRQ_HCIRMTWKP (IRQ_BOARD_END + 46) #define IRQ_NHCIMFCIR (IRQ_BOARD_END + 47) diff --git a/include/asm-arm/arch-sa1100/time.h b/include/asm-arm/arch-sa1100/time.h index 5e459a32e8f8..c52eb9588c3c 100644 --- a/include/asm-arm/arch-sa1100/time.h +++ b/include/asm-arm/arch-sa1100/time.h @@ -58,7 +58,7 @@ static unsigned long sa1100_gettimeoffset (void) elapsed = LATCH - ticks_to_match; /* Now convert them to usec */ - usec = (unsigned long)(elapsed*tick)/LATCH; + usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH; return usec; } diff --git a/include/asm-arm/ecard.h b/include/asm-arm/ecard.h index fa0adbaeb12d..7c719a206399 100644 --- a/include/asm-arm/ecard.h +++ b/include/asm-arm/ecard.h @@ -95,9 +95,10 @@ typedef enum { /* Speed for ECARD_IOC space */ ECARD_SYNC = 3 } card_speed_t; -typedef struct { /* Card ID structure */ - unsigned short manufacturer; - unsigned short product; +typedef struct ecard_id { /* Card ID structure */ + unsigned short manufacturer; + unsigned short product; + void *data; } card_ids; struct in_ecid { /* Packed card ID information */ @@ -132,6 +133,8 @@ typedef struct { /* Card handler routines */ struct expansion_card { struct expansion_card *next; + struct device dev; + /* Public data */ volatile unsigned char *irqaddr; /* address of IRQ register */ volatile unsigned char *fiqaddr; /* address of FIQ register */ @@ -248,4 +251,24 @@ struct ex_chunk_dir { #endif +extern struct bus_type ecard_bus_type; + +#define ECARD_DEV(_d) container_of((_d), struct expansion_card, dev) + +struct ecard_driver { + int (*probe)(struct expansion_card *, const struct ecard_id *id); + void (*remove)(struct expansion_card *); + const struct ecard_id *id_table; + unsigned int id; + struct device_driver drv; +}; + +#define ECARD_DRV(_d) container_of((_d), struct ecard_driver, drv) + +#define ecard_set_drvdata(ec,data) dev_set_drvdata(&(ec)->dev, (data)) +#define ecard_get_drvdata(ec) dev_get_drvdata(&(ec)->dev) + +int ecard_register_driver(struct ecard_driver *); +void ecard_remove_driver(struct ecard_driver *); + #endif diff --git a/include/asm-arm/glue.h b/include/asm-arm/glue.h index 84b5d77c7562..a29d70176c75 100644 --- a/include/asm-arm/glue.h +++ b/include/asm-arm/glue.h @@ -27,59 +27,6 @@ /* - * MMU TLB Model - * ============= - * - * We have the following to choose from: - * v3 - ARMv3 - * v4 - ARMv4 without write buffer - * v4wb - ARMv4 with write buffer without I TLB flush entry instruction - * v4wbi - ARMv4 with write buffer with I TLB flush entry instruction - */ -#undef _TLB -#undef MULTI_TLB - -#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710) -# ifdef _TLB -# define MULTI_TLB 1 -# else -# define _TLB v3 -# endif -#endif - -#if defined(CONFIG_CPU_ARM720T) -# ifdef _TLB -# define MULTI_TLB 1 -# else -# define _TLB v4 -# endif -#endif - -#if defined(CONFIG_CPU_ARM920T) || defined(CONFIG_CPU_ARM922T) || \ - defined(CONFIG_CPU_ARM926T) || defined(CONFIG_CPU_ARM1020) || \ - defined(CONFIG_CPU_XSCALE) -# ifdef _TLB -# define MULTI_TLB 1 -# else -# define _TLB v4wbi -# endif -#endif - -#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100) -# ifdef _TLB -# define MULTI_TLB 1 -# else -# define _TLB v4wb -# endif -#endif - -#ifndef _TLB -#error Unknown TLB model -#endif - - - -/* * Data Abort Model * ================ * @@ -156,69 +103,4 @@ #error Unknown data abort handler type #endif - -/* - * User Space Model - * ================ - * - * This section selects the correct set of functions for dealing with - * page-based copying and clearing for user space for the particular - * processor(s) we're building for. - * - * We have the following to choose from: - * v3 - ARMv3 - * v4wt - ARMv4 with writethrough cache, without minicache - * v4wb - ARMv4 with writeback cache, without minicache - * v4_mc - ARMv4 with minicache - * xscale - Xscale - */ -#undef _USER -#undef MULTI_USER - -#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710) -# ifdef _USER -# define MULTI_USER 1 -# else -# define _USER v3 -# endif -#endif - -#if defined(CONFIG_CPU_ARM720T) -# ifdef _USER -# define MULTI_USER 1 -# else -# define _USER v4wt -# endif -#endif - -#if defined(CONFIG_CPU_ARM920T) || defined(CONFIG_CPU_ARM922T) || \ - defined(CONFIG_CPU_ARM926T) || defined(CONFIG_CPU_SA110) || \ - defined(CONFIG_CPU_ARM1020) -# ifdef _USER -# define MULTI_USER 1 -# else -# define _USER v4wb -# endif -#endif - -#if defined(CONFIG_CPU_SA1100) -# ifdef _USER -# define MULTI_USER 1 -# else -# define _USER v4_mc -# endif -#endif - -#if defined(CONFIG_CPU_XSCALE) -# ifdef _USER -# define MULTI_USER 1 -# else -# define _USER xscale_mc -# endif -#endif - -#ifndef _USER -#error Unknown user operations model -#endif - #endif diff --git a/include/asm-arm/hardirq.h b/include/asm-arm/hardirq.h index 0e6a5492e1e4..3f164e01f7a1 100644 --- a/include/asm-arm/hardirq.h +++ b/include/asm-arm/hardirq.h @@ -69,10 +69,18 @@ typedef struct { #define irq_enter() (preempt_count() += HARDIRQ_OFFSET) +#ifdef CONFIG_PREEMPT +# define in_atomic() ((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked()) +# define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) +#else +# define in_atomic() (preempt_count() != 0) +# define IRQ_EXIT_OFFSET HARDIRQ_OFFSET +#endif + #ifndef CONFIG_SMP #define irq_exit() \ do { \ - preempt_count() -= HARDIRQ_OFFSET; \ + preempt_count() -= IRQ_EXIT_OFFSET; \ if (!in_interrupt() && softirq_pending(smp_processor_id())) \ __asm__("bl%? __do_softirq": : : "lr");/* out of line */\ preempt_enable_no_resched(); \ @@ -80,7 +88,7 @@ typedef struct { #define synchronize_irq(irq) barrier() #else -#error SMP not supported +extern void synchronize_irq(unsigned int irq); #endif #endif /* __ASM_HARDIRQ_H */ diff --git a/include/asm-arm/hardware/sa1111.h b/include/asm-arm/hardware/sa1111.h index 311e4832eb2f..30e1f8141633 100644 --- a/include/asm-arm/hardware/sa1111.h +++ b/include/asm-arm/hardware/sa1111.h @@ -64,10 +64,6 @@ #define SA1111_SMCR 0x0004 #define SA1111_SKID 0x0008 -#define SBI_SKCR __CCREG(SA1111_SKCR) -#define SBI_SMCR __CCREG(SA1111_SMCR) -#define SBI_SKID __CCREG(SA1111_SKID) - #define SKCR_PLL_BYPASS (1<<0) #define SKCR_RCLKEN (1<<1) #define SKCR_SLEEP (1<<2) @@ -131,16 +127,6 @@ #define SA1111_SKPEN1 0x021c #define SA1111_SKPWM1 0x0220 -#define SKPCR __CCREG(SA1111_SKPCR) -#define SKCDR __CCREG(SA1111_SKCDR) -#define SKAUD __CCREG(SA1111_SKAUD) -#define SKPMC __CCREG(SA1111_SKPMC) -#define SKPTC __CCREG(SA1111_SKPTC) -#define SKPEN0 __CCREG(SA1111_SKPEN0) -#define SKPWM0 __CCREG(SA1111_SKPWM0) -#define SKPEN1 __CCREG(SA1111_SKPEN1) -#define SKPWM1 __CCREG(SA1111_SKPWM1) - #define SKPCR_UCLKEN (1<<0) #define SKPCR_ACCLKEN (1<<1) #define SKPCR_I2SCLKEN (1<<2) diff --git a/include/asm-arm/ide.h b/include/asm-arm/ide.h index 3b9c4c18c6af..e872974aa009 100644 --- a/include/asm-arm/ide.h +++ b/include/asm-arm/ide.h @@ -36,7 +36,6 @@ * The following are not needed for the non-m68k ports */ #define ide_ack_intr(hwif) (1) -#define ide_fix_driveid(id) do {} while (0) #define ide_release_lock(lock) do {} while (0) #define ide_get_lock(lock, hdlr, data) do {} while (0) diff --git a/include/asm-arm/numnodes.h b/include/asm-arm/numnodes.h new file mode 100644 index 000000000000..4c12812f73dc --- /dev/null +++ b/include/asm-arm/numnodes.h @@ -0,0 +1,17 @@ +/* + * linux/include/asm-arm/numnodes.h + * + * Copyright (C) 2002 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_ARM_NUMNODES_H +#define __ASM_ARM_NUMNODES_H + +#include <asm/memory.h> + +#define MAX_NUMNODES NR_NODES + +#endif diff --git a/include/asm-arm/page.h b/include/asm-arm/page.h index 84b1f5970586..0b1a26ed991d 100644 --- a/include/asm-arm/page.h +++ b/include/asm-arm/page.h @@ -8,6 +8,70 @@ #include <asm/glue.h> +/* + * User Space Model + * ================ + * + * This section selects the correct set of functions for dealing with + * page-based copying and clearing for user space for the particular + * processor(s) we're building for. + * + * We have the following to choose from: + * v3 - ARMv3 + * v4wt - ARMv4 with writethrough cache, without minicache + * v4wb - ARMv4 with writeback cache, without minicache + * v4_mc - ARMv4 with minicache + * xscale - Xscale + */ +#undef _USER +#undef MULTI_USER + +#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710) +# ifdef _USER +# define MULTI_USER 1 +# else +# define _USER v3 +# endif +#endif + +#if defined(CONFIG_CPU_ARM720T) +# ifdef _USER +# define MULTI_USER 1 +# else +# define _USER v4wt +# endif +#endif + +#if defined(CONFIG_CPU_ARM920T) || defined(CONFIG_CPU_ARM922T) || \ + defined(CONFIG_CPU_ARM926T) || defined(CONFIG_CPU_SA110) || \ + defined(CONFIG_CPU_ARM1020) +# ifdef _USER +# define MULTI_USER 1 +# else +# define _USER v4wb +# endif +#endif + +#if defined(CONFIG_CPU_SA1100) +# ifdef _USER +# define MULTI_USER 1 +# else +# define _USER v4_mc +# endif +#endif + +#if defined(CONFIG_CPU_XSCALE) +# ifdef _USER +# define MULTI_USER 1 +# else +# define _USER xscale_mc +# endif +#endif + +#ifndef _USER +#error Unknown user operations model +#endif + struct cpu_user_fns { void (*cpu_clear_user_page)(void *p, unsigned long user); void (*cpu_copy_user_page)(void *to, const void *from, diff --git a/include/asm-arm/pci.h b/include/asm-arm/pci.h index 3a7310558dd2..cd074e0daf51 100644 --- a/include/asm-arm/pci.h +++ b/include/asm-arm/pci.h @@ -248,6 +248,10 @@ void *pci_pool_alloc (struct pci_pool *pool, int flags, dma_addr_t *handle); void pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t addr); #endif +#define HAVE_PCI_MMAP +extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, int write_combine); + #endif /* __KERNEL__ */ #endif diff --git a/include/asm-arm/pgalloc.h b/include/asm-arm/pgalloc.h index f0e2c9f5393d..81a7eccf2991 100644 --- a/include/asm-arm/pgalloc.h +++ b/include/asm-arm/pgalloc.h @@ -11,9 +11,6 @@ #define _ASMARM_PGALLOC_H #include <asm/processor.h> -#include <asm/cacheflush.h> -#include <asm/tlbflush.h> - #include <asm/proc/pgalloc.h> /* diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h index ca5bef29d81b..da98e2ee55b8 100644 --- a/include/asm-arm/pgtable.h +++ b/include/asm-arm/pgtable.h @@ -12,6 +12,7 @@ #include <linux/config.h> #include <asm/memory.h> +#include <asm/proc-fns.h> #include <asm/arch/vmalloc.h> /* diff --git a/include/asm-arm/proc-armo/system.h b/include/asm-arm/proc-armo/system.h index 23f2b96cb2d0..9e46e58f56e4 100644 --- a/include/asm-arm/proc-armo/system.h +++ b/include/asm-arm/proc-armo/system.h @@ -10,8 +10,6 @@ #ifndef __ASM_PROC_SYSTEM_H #define __ASM_PROC_SYSTEM_H -#include <asm/proc-fns.h> - #define vectors_base() (0) static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) diff --git a/include/asm-arm/proc-armv/pgalloc.h b/include/asm-arm/proc-armv/pgalloc.h index 99546c6fc1c8..53e760417601 100644 --- a/include/asm-arm/proc-armv/pgalloc.h +++ b/include/asm-arm/proc-armv/pgalloc.h @@ -5,6 +5,7 @@ * * Page table allocation/freeing primitives for 32-bit ARM processors. */ +#include <asm/cacheflush.h> #include "pgtable.h" /* diff --git a/include/asm-arm/proc-armv/tlbflush.h b/include/asm-arm/proc-armv/tlbflush.h index d465e954ae13..fd758b2e90f2 100644 --- a/include/asm-arm/proc-armv/tlbflush.h +++ b/include/asm-arm/proc-armv/tlbflush.h @@ -7,6 +7,113 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include <linux/config.h> +#include <asm/glue.h> + +#define TLB_V3_PAGE (1 << 0) +#define TLB_V4_U_PAGE (1 << 1) +#define TLB_V4_D_PAGE (1 << 2) +#define TLB_V4_I_PAGE (1 << 3) + +#define TLB_V3_FULL (1 << 8) +#define TLB_V4_U_FULL (1 << 9) +#define TLB_V4_D_FULL (1 << 10) +#define TLB_V4_I_FULL (1 << 11) + +#define TLB_WB (1 << 31) + +/* + * MMU TLB Model + * ============= + * + * We have the following to choose from: + * v3 - ARMv3 + * v4 - ARMv4 without write buffer + * v4wb - ARMv4 with write buffer without I TLB flush entry instruction + * v4wbi - ARMv4 with write buffer with I TLB flush entry instruction + */ +#undef _TLB +#undef MULTI_TLB + +#define v3_tlb_flags (TLB_V3_FULL | TLB_V3_PAGE) + +#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710) +# ifdef _TLB +# define MULTI_TLB 1 +# else +# define _TLB v3 +# endif +#endif + +#define v4_tlb_flags (TLB_V4_U_FULL | TLB_V4_U_PAGE) + +#if defined(CONFIG_CPU_ARM720T) +# ifdef _TLB +# define MULTI_TLB 1 +# else +# define _TLB v4 +# endif +#endif + +#define v4wbi_tlb_flags (TLB_WB | \ + TLB_V4_I_FULL | TLB_V4_D_FULL | \ + TLB_V4_I_PAGE | TLB_V4_D_PAGE) + +#if defined(CONFIG_CPU_ARM920T) || defined(CONFIG_CPU_ARM922T) || \ + defined(CONFIG_CPU_ARM926T) || defined(CONFIG_CPU_ARM1020) || \ + defined(CONFIG_CPU_XSCALE) +# ifdef _TLB +# define MULTI_TLB 1 +# else +# define _TLB v4wbi +# endif +#endif + +#define v4wb_tlb_flags (TLB_WB | \ + TLB_V4_I_FULL | TLB_V4_D_FULL | \ + TLB_V4_D_PAGE) + +#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100) +# ifdef _TLB +# define MULTI_TLB 1 +# else +# define _TLB v4wb +# endif +#endif + +#ifndef _TLB +#error Unknown TLB model +#endif + +#ifndef __ASSEMBLY__ + +struct cpu_tlb_fns { + void (*flush_user_range)(unsigned long, unsigned long, struct vm_area_struct *); + void (*flush_kern_range)(unsigned long, unsigned long); + unsigned long tlb_flags; +}; + +/* + * Select the calling method + */ +#ifdef MULTI_TLB + +extern struct cpu_tlb_fns cpu_tlb; + +#define __cpu_flush_user_tlb_range cpu_tlb.flush_user_range +#define __cpu_flush_kern_tlb_range cpu_tlb.flush_kern_range +#define __cpu_tlb_flags cpu_tlb.tlb_flags + +#else + +#define __cpu_flush_user_tlb_range __glue(_TLB,_flush_user_tlb_range) +#define __cpu_flush_kern_tlb_range __glue(_TLB,_flush_kern_tlb_range) +#define __cpu_tlb_flags __glue(_TLB,_tlb_flags) + +extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *); +extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long); + +#endif /* * TLB Management @@ -51,56 +158,94 @@ * - kaddr - Kernel virtual memory address */ -struct cpu_tlb_fns { - void (*flush_kern_all)(void); - void (*flush_user_mm)(struct mm_struct *); - void (*flush_user_range)(unsigned long, unsigned long, struct vm_area_struct *); - void (*flush_user_page)(unsigned long, struct vm_area_struct *); - void (*flush_kern_range)(unsigned long, unsigned long); - void (*flush_kern_page)(unsigned long); -}; +#define tlb_flag(f) (__cpu_tlb_flags & (f)) -/* - * Convert calls to our calling convention. - */ -#define flush_tlb_all() __cpu_flush_kern_tlb_all() -#define flush_tlb_mm(mm) __cpu_flush_user_tlb_mm(mm) -#define flush_tlb_range(vma,start,end) __cpu_flush_user_tlb_range(start,end,vma) -#define flush_tlb_page(vma,vaddr) __cpu_flush_user_tlb_page(vaddr,vma) -#define flush_tlb_kernel_range(s,e) __cpu_flush_kern_tlb_range(s,e) -#define flush_tlb_kernel_page(kaddr) __cpu_flush_kern_tlb_page(kaddr) +static inline void flush_tlb_all(void) +{ + const int zero = 0; -/* - * Now select the calling method - */ -#ifdef MULTI_TLB + if (tlb_flag(TLB_WB)) + asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero)); -extern struct cpu_tlb_fns cpu_tlb; + if (tlb_flag(TLB_V3_FULL)) + asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (zero)); + if (tlb_flag(TLB_V4_U_FULL)) + asm("mcr%? p15, 0, %0, c8, c7, 0" : : "r" (zero)); + if (tlb_flag(TLB_V4_D_FULL)) + asm("mcr%? p15, 0, %0, c8, c6, 0" : : "r" (zero)); + if (tlb_flag(TLB_V4_I_FULL)) + asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero)); +} -#define __cpu_flush_kern_tlb_all cpu_tlb.flush_kern_all -#define __cpu_flush_user_tlb_mm cpu_tlb.flush_user_mm -#define __cpu_flush_user_tlb_range cpu_tlb.flush_user_range -#define __cpu_flush_user_tlb_page cpu_tlb.flush_user_page -#define __cpu_flush_kern_tlb_range cpu_tlb.flush_kern_range -#define __cpu_flush_kern_tlb_page cpu_tlb.flush_kern_page +static inline void flush_tlb_mm(struct mm_struct *mm) +{ + const int zero = 0; -#else + if (tlb_flag(TLB_WB)) + asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero)); -#define __cpu_flush_kern_tlb_all __glue(_TLB,_flush_kern_tlb_all) -#define __cpu_flush_user_tlb_mm __glue(_TLB,_flush_user_tlb_mm) -#define __cpu_flush_user_tlb_range __glue(_TLB,_flush_user_tlb_range) -#define __cpu_flush_user_tlb_page __glue(_TLB,_flush_user_tlb_page) -#define __cpu_flush_kern_tlb_range __glue(_TLB,_flush_kern_tlb_range) -#define __cpu_flush_kern_tlb_page __glue(_TLB,_flush_kern_tlb_page) + if (mm == current->active_mm) { + if (tlb_flag(TLB_V3_FULL)) + asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (zero)); + if (tlb_flag(TLB_V4_U_FULL)) + asm("mcr%? p15, 0, %0, c8, c7, 0" : : "r" (zero)); + if (tlb_flag(TLB_V4_D_FULL)) + asm("mcr%? p15, 0, %0, c8, c6, 0" : : "r" (zero)); + if (tlb_flag(TLB_V4_I_FULL)) + asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero)); + } +} -extern void __cpu_flush_kern_tlb_all(void); -extern void __cpu_flush_user_tlb_mm(struct mm_struct *); -extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *); -extern void __cpu_flush_user_tlb_page(unsigned long, struct vm_area_struct *); -extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long); -extern void __cpu_flush_kern_tlb_page(unsigned long); +static inline void +flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) +{ + const int zero = 0; -#endif + uaddr &= PAGE_MASK; + + if (tlb_flag(TLB_WB)) + asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero)); + + if (vma->vm_mm == current->active_mm) { + if (tlb_flag(TLB_V3_PAGE)) + asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (uaddr)); + if (tlb_flag(TLB_V4_U_PAGE)) + asm("mcr%? p15, 0, %0, c8, c7, 1" : : "r" (uaddr)); + if (tlb_flag(TLB_V4_D_PAGE)) + asm("mcr%? p15, 0, %0, c8, c6, 1" : : "r" (uaddr)); + if (tlb_flag(TLB_V4_I_PAGE)) + asm("mcr%? p15, 0, %0, c8, c5, 1" : : "r" (uaddr)); + if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL)) + asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero)); + } +} + +static inline void flush_tlb_kernel_page(unsigned long kaddr) +{ + const int zero = 0; + + kaddr &= PAGE_MASK; + + if (tlb_flag(TLB_WB)) + asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero)); + + if (tlb_flag(TLB_V3_PAGE)) + asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (kaddr)); + if (tlb_flag(TLB_V4_U_PAGE)) + asm("mcr%? p15, 0, %0, c8, c7, 1" : : "r" (kaddr)); + if (tlb_flag(TLB_V4_D_PAGE)) + asm("mcr%? p15, 0, %0, c8, c6, 1" : : "r" (kaddr)); + if (tlb_flag(TLB_V4_I_PAGE)) + asm("mcr%? p15, 0, %0, c8, c5, 1" : : "r" (kaddr)); + if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL)) + asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero)); +} + +/* + * Convert calls to our calling convention. + */ +#define flush_tlb_range(vma,start,end) __cpu_flush_user_tlb_range(start,end,vma) +#define flush_tlb_kernel_range(s,e) __cpu_flush_kern_tlb_range(s,e) /* * if PG_dcache_dirty is set for the page, we need to ensure that any @@ -123,3 +268,4 @@ extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte #define memc_update_addr(mm,pte,log) do { } while (0) #define memc_clear(mm,physaddr) do { } while (0) +#endif diff --git a/include/asm-arm/processor.h b/include/asm-arm/processor.h index 7f3bed11ebd1..b13e4e54282c 100644 --- a/include/asm-arm/processor.h +++ b/include/asm-arm/processor.h @@ -28,22 +28,30 @@ #include <asm/procinfo.h> #include <asm/arch/memory.h> #include <asm/proc/processor.h> +#include <asm/types.h> + +union debug_insn { + u32 arm; + u16 thumb; +}; + +struct debug_entry { + u32 address; + union debug_insn insn; +}; struct debug_info { - int nsaved; - struct { - unsigned long address; - unsigned long insn; - } bp[2]; + int nsaved; + struct debug_entry bp[2]; }; struct thread_struct { /* fault info */ - unsigned long address; - unsigned long trap_no; - unsigned long error_code; + unsigned long address; + unsigned long trap_no; + unsigned long error_code; /* debugging */ - struct debug_info debug; + struct debug_info debug; }; #define INIT_THREAD { } diff --git a/include/asm-arm/procinfo.h b/include/asm-arm/procinfo.h index c143ffa712de..fced718b32be 100644 --- a/include/asm-arm/procinfo.h +++ b/include/asm-arm/procinfo.h @@ -12,8 +12,6 @@ #ifndef __ASSEMBLY__ -#include <asm/proc-fns.h> - struct cpu_tlb_fns; struct cpu_user_fns; struct processor; diff --git a/include/asm-arm/tlb.h b/include/asm-arm/tlb.h index 318357c01183..3aa4ee0feb67 100644 --- a/include/asm-arm/tlb.h +++ b/include/asm-arm/tlb.h @@ -1,21 +1,76 @@ +/* + * linux/include/asm-arm/tlb.h + * + * Copyright (C) 2002 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Experimentation shows that on a StrongARM, it appears to be faster + * to use the "invalidate whole tlb" rather than "invalidate single + * tlb" for this. + * + * This appears true for both the process fork+exit case, as well as + * the munmap-large-area case. + */ #ifndef __ASMARM_TLB_H #define __ASMARM_TLB_H -#include <asm/cacheflush.h> #include <asm/tlbflush.h> -#define tlb_flush(tlb) \ - flush_tlb_mm((tlb)->mm) -#define tlb_start_vma(tlb,vma) \ - flush_cache_range(vma, vma->vm_start, vma->vm_end) -#define tlb_end_vma(tlb,vma) \ - flush_tlb_range(vma, vma->vm_start, vma->vm_end) +/* + * TLB handling. This allows us to remove pages from the page + * tables, and efficiently handle the TLB issues. + */ +typedef struct free_pte_ctx { + struct mm_struct *mm; + unsigned int freed; -#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) + unsigned int flushes; + unsigned int avoided_flushes; +} mmu_gather_t; -#include <asm-generic/tlb.h> +extern mmu_gather_t mmu_gathers[NR_CPUS]; -#define __pmd_free_tlb(tlb, pmd) pmd_free(pmd) -#define __pte_free_tlb(tlb, pte) pte_free(pte) +static inline mmu_gather_t *tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush) +{ + int cpu = smp_processor_id(); + mmu_gather_t *tlb = &mmu_gathers[cpu]; + + tlb->mm = mm; + tlb->freed = 0; + + return tlb; +} + +static inline void tlb_finish_mmu(mmu_gather_t *tlb, unsigned long start, unsigned long end) +{ + struct mm_struct *mm = tlb->mm; + unsigned long freed = tlb->freed; + int rss = mm->rss; + + if (rss < freed) + freed = rss; + mm->rss = rss - freed; + + if (freed) { + flush_tlb_mm(mm); + tlb->flushes++; + } else { + tlb->avoided_flushes++; + } + + /* keep the page table cache within bounds */ + check_pgt_cache(); +} + +#define tlb_remove_tlb_entry(tlb,ptep,address) do { } while (0) +#define tlb_start_vma(tlb,vma) do { } while (0) +#define tlb_end_vma(tlb,vma) do { } while (0) + +#define tlb_remove_page(tlb,page) free_page_and_swap_cache(page) +#define pte_free_tlb(tlb,ptep) pte_free(ptep) +#define pmd_free_tlb(tlb,pmdp) pmd_free(pmdp) #endif diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 71732e1216fc..0760d97cd6f9 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -32,7 +32,6 @@ enum bh_state_bits { #define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512) struct page; -struct kiobuf; struct buffer_head; struct address_space; typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate); diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 0abaaaa2c96d..71708edafce9 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -180,17 +180,6 @@ extern void shrink_dcache_parent(struct dentry *); extern void shrink_dcache_anon(struct list_head *); extern int d_invalidate(struct dentry *); -/* dcache memory management */ -extern int shrink_dcache_memory(int, unsigned int); -extern void prune_dcache(int); - -/* icache memory management (defined in linux/fs/inode.c) */ -extern int shrink_icache_memory(int, unsigned int); -extern void prune_icache(int); - -/* quota cache memory management (defined in linux/fs/dquot.c) */ -extern int shrink_dqcache_memory(int, unsigned int); - /* only used at mount-time */ extern struct dentry * d_alloc_root(struct inode *); diff --git a/include/linux/iobuf.h b/include/linux/iobuf.h deleted file mode 100644 index fb147b5c48a7..000000000000 --- a/include/linux/iobuf.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * iobuf.h - * - * Defines the structures used to track abstract kernel-space io buffers. - * - */ - -#ifndef __LINUX_IOBUF_H -#define __LINUX_IOBUF_H - -#include <linux/mm.h> -#include <linux/init.h> -#include <linux/wait.h> -#include <asm/atomic.h> - -/* - * The kiobuf structure describes a physical set of pages reserved - * locked for IO. The reference counts on each page will have been - * incremented, and the flags field will indicate whether or not we have - * pre-locked all of the pages for IO. - * - * kiobufs may be passed in arrays to form a kiovec, but we must - * preserve the property that no page is present more than once over the - * entire iovec. - */ - -#define KIO_MAX_ATOMIC_IO 512 /* in kb */ -#define KIO_STATIC_PAGES (KIO_MAX_ATOMIC_IO / (PAGE_SIZE >> 10) + 1) -#define KIO_MAX_SECTORS (KIO_MAX_ATOMIC_IO * 2) - -/* The main kiobuf struct */ - -struct kiobuf -{ - int nr_pages; /* Pages actually referenced */ - int array_len; /* Space in the allocated lists */ - int offset; /* Offset to start of valid data */ - int length; /* Number of valid bytes of data */ - - /* Keep separate track of the physical addresses and page - * structs involved. If we do IO to a memory-mapped device - * region, there won't necessarily be page structs defined for - * every address. */ - - struct page ** maplist; - - unsigned int locked : 1; /* If set, pages has been locked */ - - /* Always embed enough struct pages for atomic IO */ - struct page * map_array[KIO_STATIC_PAGES]; - sector_t blocks[KIO_MAX_SECTORS]; - - /* Dynamic state for IO completion: */ - atomic_t io_count; /* IOs still in progress */ - int errno; /* Status of completed IO */ - void (*end_io) (struct kiobuf *); /* Completion callback */ - wait_queue_head_t wait_queue; -}; - - -/* mm/memory.c */ - -int map_user_kiobuf(int rw, struct kiobuf *, unsigned long va, size_t len); -void unmap_kiobuf(struct kiobuf *iobuf); -int lock_kiovec(int nr, struct kiobuf *iovec[], int wait); -int unlock_kiovec(int nr, struct kiobuf *iovec[]); -void mark_dirty_kiobuf(struct kiobuf *iobuf, int bytes); - -/* fs/iobuf.c */ - -int end_kio_request(struct kiobuf *, int); -void simple_wakeup_kiobuf(struct kiobuf *); -int alloc_kiovec(int nr, struct kiobuf **); -void free_kiovec(int nr, struct kiobuf **); -int expand_kiobuf(struct kiobuf *, int); -void kiobuf_wait_for_io(struct kiobuf *); -extern int alloc_kiobuf_bhs(struct kiobuf *); -extern void free_kiobuf_bhs(struct kiobuf *); - -/* fs/buffer.c */ - -int brw_kiovec(int rw, int nr, struct kiobuf *iovec[], - struct block_device *bdev, sector_t [], int size); - -/* fs/bio.c */ -void ll_rw_kio(int rw, struct kiobuf *kio, struct block_device *bdev, sector_t block); - -#endif /* __LINUX_IOBUF_H */ diff --git a/include/linux/mm.h b/include/linux/mm.h index a5107b5043f7..a6c66cc418ee 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -392,6 +392,29 @@ extern int free_hugepages(struct vm_area_struct *); /* + * Prototype to add a shrinker callback for ageable caches. + * + * These functions are passed a count `nr_to_scan' and a gfpmask. They should + * scan `nr_to_scan' objects, attempting to free them. + * + * The callback must the number of objects which remain in the cache. + * + * The callback will be passes nr_to_scan == 0 when the VM is querying the + * cache size, so a fastpath for that case is appropriate. + */ +typedef int (*shrinker_t)(int nr_to_scan, unsigned int gfp_mask); + +/* + * Add an aging callback. The int is the number of 'seeks' it takes + * to recreate one of the objects that these functions age. + */ + +#define DEFAULT_SEEKS 2 +struct shrinker; +extern struct shrinker *set_shrinker(int, shrinker_t); +extern void remove_shrinker(struct shrinker *shrinker); + +/* * If the mapping doesn't provide a set_page_dirty a_op, then * just fall through and assume that it wants buffer_heads. * FIXME: make the method unconditional. diff --git a/include/linux/swap.h b/include/linux/swap.h index 4ec8559245c6..4457c1dec40b 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -163,6 +163,8 @@ extern void swap_setup(void); /* linux/mm/vmscan.c */ extern int try_to_free_pages(struct zone *, unsigned int, unsigned int); +int shrink_all_memory(int nr_pages); +extern int vm_swappiness; /* linux/mm/page_io.c */ int swap_readpage(struct file *file, struct page *page); diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 8139ec747979..58055e1998cd 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -146,13 +146,14 @@ enum VM_UNUSED9=9, /* was: struct: Set page table cache parameters */ VM_PAGE_CLUSTER=10, /* int: set number of pages to swap together */ VM_DIRTY_BACKGROUND=11, /* dirty_background_ratio */ - VM_DIRTY_ASYNC=12, /* dirty_async_ratio */ + VM_DIRTY_RATIO=12, /* dirty_ratio */ VM_DIRTY_WB_CS=13, /* dirty_writeback_centisecs */ VM_DIRTY_EXPIRE_CS=14, /* dirty_expire_centisecs */ VM_NR_PDFLUSH_THREADS=15, /* nr_pdflush_threads */ VM_OVERCOMMIT_RATIO=16, /* percent of RAM to allow overcommit in */ VM_PAGEBUF=17, /* struct: Control pagebuf parameters */ VM_HUGETLB_PAGES=18, /* int: Number of available Huge Pages */ + VM_SWAPPINESS=19, /* Tendency to steal mapped memory */ }; diff --git a/include/linux/usb.h b/include/linux/usb.h index 5dbc3cb115f7..fe144bda56f0 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -222,12 +222,42 @@ struct usb_interface_descriptor { int extralen; }; +/** + * struct usb_interface - what usb device drivers talk to + * @altsetting: array of interface descriptors, one for each alternate + * setting that may be selected. each one includes a set of + * endpoint configurations. + * @num_altsetting: number of altsettings defined. + * @act_altsetting: index of current altsetting. this number is always + * less than num_altsetting. after the device is configured, each + * interface uses its default setting of zero. + * @dev: driver model's view of this device + * + * USB device drivers attach to interfaces on a physical device. Each + * interface encapsulates a single high level function, such as feeding + * an audio stream to a speaker or reporting a change in a volume control. + * Many USB devices only have one interface. The protocol used to talk to + * an interface's endpoints can be defined in a usb "class" specification, + * or by a product's vendor. The (default) control endpoint is part of + * every interface, but is never listed among the interface's descriptors. + * + * The driver that is bound to the interface can use standard driver model + * calls such as dev_get_drvdata() on the dev member of this structure. + * + * Each interface may have alternate settings. The initial configuration + * of a device sets the first of these, but the device driver can change + * that setting using usb_set_interface(). Alternate settings are often + * used to control the the use of periodic endpoints, such as by having + * different endpoints use different amounts of reserved USB bandwidth. + * All standards-conformant USB devices that use isochronous endpoints + * will use them in non-default settings. + */ struct usb_interface { struct usb_interface_descriptor *altsetting; - int act_altsetting; /* active alternate setting */ - int num_altsetting; /* number of alternate settings */ - int max_altsetting; /* total memory allocated */ + unsigned act_altsetting; /* active alternate setting */ + unsigned num_altsetting; /* number of alternate settings */ + unsigned max_altsetting; /* total memory allocated */ struct usb_driver *driver; /* driver */ struct device dev; /* interface specific device info */ @@ -670,6 +700,7 @@ extern void usb_deregister_dev(int num_minors, int start_minor); extern int usb_device_probe(struct device *dev); extern int usb_device_remove(struct device *dev); +extern int usb_disabled(void); /* -------------------------------------------------------------------------- */ diff --git a/include/linux/videodev.h b/include/linux/videodev.h index 80966ed8e288..a90d968374eb 100644 --- a/include/linux/videodev.h +++ b/include/linux/videodev.h @@ -397,6 +397,7 @@ struct video_code #define VID_HARDWARE_PWC 31 /* Philips webcams */ #define VID_HARDWARE_MEYE 32 /* Sony Vaio MotionEye cameras */ #define VID_HARDWARE_CPIA2 33 +#define VID_HARDWARE_VICAM 34 #endif /* __LINUX_VIDEODEV_H */ diff --git a/include/linux/writeback.h b/include/linux/writeback.h index b71468f8f072..687091648a3a 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -67,7 +67,7 @@ int wakeup_bdflush(long nr_pages); /* These 5 are exported to sysctl. */ extern int dirty_background_ratio; -extern int dirty_async_ratio; +extern int vm_dirty_ratio; extern int dirty_writeback_centisecs; extern int dirty_expire_centisecs; diff --git a/init/main.c b/init/main.c index f69c298b9a6f..c6023edc03f3 100644 --- a/init/main.c +++ b/init/main.c @@ -24,7 +24,6 @@ #include <linux/smp_lock.h> #include <linux/blk.h> #include <linux/hdreg.h> -#include <linux/iobuf.h> #include <linux/bootmem.h> #include <linux/tty.h> #include <linux/percpu.h> diff --git a/kernel/ksyms.c b/kernel/ksyms.c index 9beb67e2a999..4b3e40b10a76 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -33,7 +33,6 @@ #include <linux/swap.h> #include <linux/ctype.h> #include <linux/file.h> -#include <linux/iobuf.h> #include <linux/console.h> #include <linux/poll.h> #include <linux/mmzone.h> @@ -103,6 +102,8 @@ EXPORT_SYMBOL(kmem_cache_shrink); EXPORT_SYMBOL(kmem_cache_alloc); EXPORT_SYMBOL(kmem_cache_free); EXPORT_SYMBOL(kmem_cache_size); +EXPORT_SYMBOL(set_shrinker); +EXPORT_SYMBOL(remove_shrinker); EXPORT_SYMBOL(kmalloc); EXPORT_SYMBOL(kfree); EXPORT_SYMBOL(vfree); @@ -246,7 +247,6 @@ EXPORT_SYMBOL(dput); EXPORT_SYMBOL(have_submounts); EXPORT_SYMBOL(d_find_alias); EXPORT_SYMBOL(d_prune_aliases); -EXPORT_SYMBOL(prune_dcache); EXPORT_SYMBOL(shrink_dcache_sb); EXPORT_SYMBOL(shrink_dcache_parent); EXPORT_SYMBOL(shrink_dcache_anon); @@ -438,18 +438,6 @@ EXPORT_SYMBOL(__br_write_lock); EXPORT_SYMBOL(__br_write_unlock); #endif -/* Kiobufs */ -EXPORT_SYMBOL(alloc_kiovec); -EXPORT_SYMBOL(free_kiovec); -EXPORT_SYMBOL(expand_kiobuf); - -EXPORT_SYMBOL(map_user_kiobuf); -EXPORT_SYMBOL(unmap_kiobuf); -EXPORT_SYMBOL(lock_kiovec); -EXPORT_SYMBOL(unlock_kiovec); -EXPORT_SYMBOL(brw_kiovec); -EXPORT_SYMBOL(kiobuf_wait_for_io); - #ifdef HAVE_DISABLE_HLT EXPORT_SYMBOL(disable_hlt); EXPORT_SYMBOL(enable_hlt); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 53d13c96fbf2..0317dd749b2b 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -286,8 +286,8 @@ static ctl_table vm_table[] = { &dirty_background_ratio, sizeof(dirty_background_ratio), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, &zero, &one_hundred }, - {VM_DIRTY_ASYNC, "dirty_async_ratio", &dirty_async_ratio, - sizeof(dirty_async_ratio), 0644, NULL, &proc_dointvec_minmax, + {VM_DIRTY_RATIO, "dirty_ratio", &vm_dirty_ratio, + sizeof(vm_dirty_ratio), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, &zero, &one_hundred }, {VM_DIRTY_WB_CS, "dirty_writeback_centisecs", &dirty_writeback_centisecs, sizeof(dirty_writeback_centisecs), 0644, @@ -311,6 +311,9 @@ static ctl_table vm_table[] = { { VM_NR_PDFLUSH_THREADS, "nr_pdflush_threads", &nr_pdflush_threads, sizeof nr_pdflush_threads, 0444 /* read-only*/, NULL, &proc_dointvec}, + {VM_SWAPPINESS, "swappiness", &vm_swappiness, sizeof(vm_swappiness), + 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, &zero, + &one_hundred }, #ifdef CONFIG_HUGETLB_PAGE {VM_HUGETLB_PAGES, "nr_hugepages", &htlbpage_max, sizeof(int), 0644, NULL, &proc_dointvec}, diff --git a/mm/filemap.c b/mm/filemap.c index 4c25b92352c0..b2fbb1cbf90b 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -20,7 +20,6 @@ #include <linux/pagemap.h> #include <linux/file.h> #include <linux/uio.h> -#include <linux/iobuf.h> #include <linux/hash.h> #include <linux/writeback.h> #include <linux/pagevec.h> diff --git a/mm/memory.c b/mm/memory.c index 91a971df3e71..70403c0cb902 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -40,7 +40,6 @@ #include <linux/mm.h> #include <linux/mman.h> #include <linux/swap.h> -#include <linux/iobuf.h> #include <linux/highmem.h> #include <linux/pagemap.h> #include <linux/vcache.h> @@ -355,6 +354,9 @@ static void zap_pte_range(mmu_gather_t *tlb, pmd_t * pmd, unsigned long address, if (!PageReserved(page)) { if (pte_dirty(pte)) set_page_dirty(page); + if (page->mapping && pte_young(pte) && + !PageSwapCache(page)) + mark_page_accessed(page); tlb->freed++; page_remove_rmap(page, ptep); tlb_remove_page(tlb, page); @@ -501,7 +503,7 @@ out: /* * Given a physical address, is there a useful struct page pointing to * it? This may become more complex in the future if we start dealing - * with IO-aperture pages in kiobufs. + * with IO-aperture pages for direct-IO. */ static inline struct page *get_page_map(struct page *page) @@ -586,224 +588,6 @@ out: return i; } -/* - * Force in an entire range of pages from the current process's user VA, - * and pin them in physical memory. - */ -#define dprintk(x...) - -int map_user_kiobuf(int rw, struct kiobuf *iobuf, unsigned long va, size_t len) -{ - int pgcount, err; - struct mm_struct * mm; - - /* Make sure the iobuf is not already mapped somewhere. */ - if (iobuf->nr_pages) - return -EINVAL; - - mm = current->mm; - dprintk ("map_user_kiobuf: begin\n"); - - pgcount = (va + len + PAGE_SIZE - 1)/PAGE_SIZE - va/PAGE_SIZE; - /* mapping 0 bytes is not permitted */ - if (!pgcount) BUG(); - err = expand_kiobuf(iobuf, pgcount); - if (err) - return err; - - iobuf->locked = 0; - iobuf->offset = va & (PAGE_SIZE-1); - iobuf->length = len; - - /* Try to fault in all of the necessary pages */ - down_read(&mm->mmap_sem); - /* rw==READ means read from disk, write into memory area */ - err = get_user_pages(current, mm, va, pgcount, - (rw==READ), 0, iobuf->maplist, NULL); - up_read(&mm->mmap_sem); - if (err < 0) { - unmap_kiobuf(iobuf); - dprintk ("map_user_kiobuf: end %d\n", err); - return err; - } - iobuf->nr_pages = err; - while (pgcount--) { - /* FIXME: flush superflous for rw==READ, - * probably wrong function for rw==WRITE - */ - flush_dcache_page(iobuf->maplist[pgcount]); - } - dprintk ("map_user_kiobuf: end OK\n"); - return 0; -} - -/* - * Mark all of the pages in a kiobuf as dirty - * - * We need to be able to deal with short reads from disk: if an IO error - * occurs, the number of bytes read into memory may be less than the - * size of the kiobuf, so we have to stop marking pages dirty once the - * requested byte count has been reached. - */ - -void mark_dirty_kiobuf(struct kiobuf *iobuf, int bytes) -{ - int index, offset, remaining; - struct page *page; - - index = iobuf->offset >> PAGE_SHIFT; - offset = iobuf->offset & ~PAGE_MASK; - remaining = bytes; - if (remaining > iobuf->length) - remaining = iobuf->length; - - while (remaining > 0 && index < iobuf->nr_pages) { - page = iobuf->maplist[index]; - - if (!PageReserved(page)) - set_page_dirty(page); - - remaining -= (PAGE_SIZE - offset); - offset = 0; - index++; - } -} - -/* - * Unmap all of the pages referenced by a kiobuf. We release the pages, - * and unlock them if they were locked. - */ - -void unmap_kiobuf (struct kiobuf *iobuf) -{ - int i; - struct page *map; - - for (i = 0; i < iobuf->nr_pages; i++) { - map = iobuf->maplist[i]; - if (map) { - if (iobuf->locked) - unlock_page(map); - /* FIXME: cache flush missing for rw==READ - * FIXME: call the correct reference counting function - */ - page_cache_release(map); - } - } - - iobuf->nr_pages = 0; - iobuf->locked = 0; -} - - -/* - * Lock down all of the pages of a kiovec for IO. - * - * If any page is mapped twice in the kiovec, we return the error -EINVAL. - * - * The optional wait parameter causes the lock call to block until all - * pages can be locked if set. If wait==0, the lock operation is - * aborted if any locked pages are found and -EAGAIN is returned. - */ - -int lock_kiovec(int nr, struct kiobuf *iovec[], int wait) -{ - struct kiobuf *iobuf; - int i, j; - struct page *page, **ppage; - int doublepage = 0; - int repeat = 0; - - repeat: - - for (i = 0; i < nr; i++) { - iobuf = iovec[i]; - - if (iobuf->locked) - continue; - - ppage = iobuf->maplist; - for (j = 0; j < iobuf->nr_pages; ppage++, j++) { - page = *ppage; - if (!page) - continue; - - if (TestSetPageLocked(page)) { - while (j--) { - struct page *tmp = *--ppage; - if (tmp) - unlock_page(tmp); - } - goto retry; - } - } - iobuf->locked = 1; - } - - return 0; - - retry: - - /* - * We couldn't lock one of the pages. Undo the locking so far, - * wait on the page we got to, and try again. - */ - - unlock_kiovec(nr, iovec); - if (!wait) - return -EAGAIN; - - /* - * Did the release also unlock the page we got stuck on? - */ - if (!PageLocked(page)) { - /* - * If so, we may well have the page mapped twice - * in the IO address range. Bad news. Of - * course, it _might_ just be a coincidence, - * but if it happens more than once, chances - * are we have a double-mapped page. - */ - if (++doublepage >= 3) - return -EINVAL; - - /* Try again... */ - wait_on_page_locked(page); - } - - if (++repeat < 16) - goto repeat; - return -EAGAIN; -} - -/* - * Unlock all of the pages of a kiovec after IO. - */ - -int unlock_kiovec(int nr, struct kiobuf *iovec[]) -{ - struct kiobuf *iobuf; - int i, j; - struct page *page, **ppage; - - for (i = 0; i < nr; i++) { - iobuf = iovec[i]; - - if (!iobuf->locked) - continue; - iobuf->locked = 0; - - ppage = iobuf->maplist; - for (j = 0; j < iobuf->nr_pages; ppage++, j++) { - page = *ppage; - if (!page) - continue; - unlock_page(page); - } - } - return 0; -} - static inline void zeromap_pte_range(pte_t * pte, unsigned long address, unsigned long size, pgprot_t prot) { diff --git a/mm/msync.c b/mm/msync.c index 7559fb30a062..3674d92253d5 100644 --- a/mm/msync.c +++ b/mm/msync.c @@ -137,6 +137,9 @@ static int msync_interval(struct vm_area_struct * vma, int ret = 0; struct file * file = vma->vm_file; + if ((flags & MS_INVALIDATE) && (vma->vm_flags & VM_LOCKED)) + return -EBUSY; + if (file && (vma->vm_flags & VM_SHARED)) { ret = filemap_sync(vma, start, end-start, flags); @@ -173,6 +176,8 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags) goto out; if (start & ~PAGE_MASK) goto out; + if ((flags & MS_ASYNC) && (flags & MS_SYNC)) + goto out; error = -ENOMEM; len = (len + ~PAGE_MASK) & PAGE_MASK; end = start + len; diff --git a/mm/page-writeback.c b/mm/page-writeback.c index b8f9c354cffb..b2c0c682f847 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -63,9 +63,9 @@ static inline long sync_writeback_pages(void) int dirty_background_ratio = 10; /* - * The generator of dirty data starts async writeback at this percentage + * The generator of dirty data starts writeback at this percentage */ -int dirty_async_ratio = 40; +int vm_dirty_ratio = 40; /* * The interval between `kupdate'-style writebacks, in centiseconds @@ -84,9 +84,52 @@ int dirty_expire_centisecs = 30 * 100; static void background_writeout(unsigned long _min_pages); /* + * Work out the current dirty-memory clamping and background writeout + * thresholds. + * + * The main aim here is to lower them aggressively if there is a lot of mapped + * memory around. To avoid stressing page reclaim with lots of unreclaimable + * pages. It is better to clamp down on writers than to start swapping, and + * performing lots of scanning. + * + * We only allow 1/2 of the currently-unmapped memory to be dirtied. + * + * We don't permit the clamping level to fall below 5% - that is getting rather + * excessive. + * + * We make sure that the background writeout level is below the adjusted + * clamping level. + */ +static void +get_dirty_limits(struct page_state *ps, long *background, long *dirty) +{ + int background_ratio; /* Percentages */ + int dirty_ratio; + int unmapped_ratio; + + get_page_state(ps); + + unmapped_ratio = 100 - (ps->nr_mapped * 100) / total_pages; + + dirty_ratio = vm_dirty_ratio; + if (dirty_ratio > unmapped_ratio / 2) + dirty_ratio = unmapped_ratio / 2; + + if (dirty_ratio < 5) + dirty_ratio = 5; + + background_ratio = dirty_background_ratio; + if (background_ratio >= dirty_ratio) + background_ratio = dirty_ratio / 2; + + *background = (background_ratio * total_pages) / 100; + *dirty = (dirty_ratio * total_pages) / 100; +} + +/* * balance_dirty_pages() must be called by processes which are generating dirty * data. It looks at the number of dirty pages in the machine and will force - * the caller to perform writeback if the system is over `async_thresh'. + * the caller to perform writeback if the system is over `vm_dirty_ratio'. * If we're over `background_thresh' then pdflush is woken to perform some * writeout. */ @@ -94,33 +137,31 @@ void balance_dirty_pages(struct address_space *mapping) { struct page_state ps; long background_thresh; - long async_thresh; - unsigned long dirty_and_writeback; - struct backing_dev_info *bdi; + long dirty_thresh; + struct backing_dev_info *bdi = mapping->backing_dev_info; - get_page_state(&ps); - dirty_and_writeback = ps.nr_dirty + ps.nr_writeback; - - background_thresh = (dirty_background_ratio * total_pages) / 100; - async_thresh = (dirty_async_ratio * total_pages) / 100; - bdi = mapping->backing_dev_info; - - if (dirty_and_writeback > async_thresh) { + get_dirty_limits(&ps, &background_thresh, &dirty_thresh); + while (ps.nr_dirty + ps.nr_writeback > dirty_thresh) { struct writeback_control wbc = { .bdi = bdi, .sync_mode = WB_SYNC_NONE, .older_than_this = NULL, .nr_to_write = sync_writeback_pages(), }; - if (!dirty_exceeded) - dirty_exceeded = 1; - writeback_inodes(&wbc); - get_page_state(&ps); - } else { - if (dirty_exceeded) - dirty_exceeded = 0; + + dirty_exceeded = 1; + + if (ps.nr_dirty) + writeback_inodes(&wbc); + + get_dirty_limits(&ps, &background_thresh, &dirty_thresh); + if (ps.nr_dirty + ps.nr_writeback <= dirty_thresh) + break; + blk_congestion_wait(WRITE, HZ/10); } + dirty_exceeded = 0; + if (!writeback_in_progress(bdi) && ps.nr_dirty > background_thresh) pdflush_operation(background_writeout, 0); } @@ -168,7 +209,6 @@ void balance_dirty_pages_ratelimited(struct address_space *mapping) static void background_writeout(unsigned long _min_pages) { long min_pages = _min_pages; - long background_thresh; struct writeback_control wbc = { .bdi = NULL, .sync_mode = WB_SYNC_NONE, @@ -178,12 +218,12 @@ static void background_writeout(unsigned long _min_pages) }; CHECK_EMERGENCY_SYNC - - background_thresh = (dirty_background_ratio * total_pages) / 100; for ( ; ; ) { struct page_state ps; + long background_thresh; + long dirty_thresh; - get_page_state(&ps); + get_dirty_limits(&ps, &background_thresh, &dirty_thresh); if (ps.nr_dirty < background_thresh && min_pages <= 0) break; wbc.encountered_congestion = 0; @@ -336,8 +376,8 @@ static int __init page_writeback_init(void) if (correction < 100) { dirty_background_ratio *= correction; dirty_background_ratio /= 100; - dirty_async_ratio *= correction; - dirty_async_ratio /= 100; + vm_dirty_ratio *= correction; + vm_dirty_ratio /= 100; } init_timer(&wb_timer); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index d5af91e50bc8..5845586fb6bb 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1147,6 +1147,8 @@ static void *vmstat_start(struct seq_file *m, loff_t *pos) if (!ps) return ERR_PTR(-ENOMEM); get_full_page_state(ps); + ps->pgpgin /= 2; /* sectors -> kbytes */ + ps->pgpgout /= 2; return (unsigned long *)ps + *pos; } diff --git a/mm/swap.c b/mm/swap.c index f0cd9260bb29..72f4c9cdd5c4 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -194,8 +194,10 @@ void pagevec_deactivate_inactive(struct pagevec *pvec) } /* - * Add the passed pages to the inactive_list, then drop the caller's refcount + * Add the passed pages to the LRU, then drop the caller's refcount * on them. Reinitialises the caller's pagevec. + * + * Mapped pages go onto the active list. */ void __pagevec_lru_add(struct pagevec *pvec) { @@ -214,7 +216,13 @@ void __pagevec_lru_add(struct pagevec *pvec) } if (TestSetPageLRU(page)) BUG(); - add_page_to_inactive_list(zone, page); + if (page_mapped(page)) { + if (TestSetPageActive(page)) + BUG(); + add_page_to_active_list(zone, page); + } else { + add_page_to_inactive_list(zone, page); + } } if (zone) spin_unlock_irq(&zone->lru_lock); diff --git a/mm/vmscan.c b/mm/vmscan.c index 486f04e6b5a1..31856732ed7b 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -35,13 +35,18 @@ #include <linux/swapops.h> /* - * The "priority" of VM scanning is how much of the queues we - * will scan in one go. A value of 12 for DEF_PRIORITY implies - * that we'll scan 1/4096th of the queues ("queue_length >> 12") - * during a normal aging round. + * The "priority" of VM scanning is how much of the queues we will scan in one + * go. A value of 12 for DEF_PRIORITY implies that we will scan 1/4096th of the + * queues ("queue_length >> 12") during an aging round. */ #define DEF_PRIORITY 12 +/* + * From 0 .. 100. Higher means more swappy. + */ +int vm_swappiness = 60; +static long total_memory; + #ifdef ARCH_HAS_PREFETCH #define prefetch_prev_lru_page(_page, _base, _field) \ do { \ @@ -72,9 +77,94 @@ #define prefetchw_prev_lru_page(_page, _base, _field) do { } while (0) #endif -#ifndef CONFIG_QUOTA -#define shrink_dqcache_memory(ratio, gfp_mask) do { } while (0) -#endif +/* + * The list of shrinker callbacks used by to apply pressure to + * ageable caches. + */ +struct shrinker { + shrinker_t shrinker; + struct list_head list; + int seeks; /* seeks to recreate an obj */ + int nr; /* objs pending delete */ +}; + +static LIST_HEAD(shrinker_list); +static DECLARE_MUTEX(shrinker_sem); + +/* + * Add a shrinker callback to be called from the vm + */ +struct shrinker *set_shrinker(int seeks, shrinker_t theshrinker) +{ + struct shrinker *shrinker; + + shrinker = kmalloc(sizeof(*shrinker), GFP_KERNEL); + if (shrinker) { + shrinker->shrinker = theshrinker; + shrinker->seeks = seeks; + shrinker->nr = 0; + down(&shrinker_sem); + list_add(&shrinker->list, &shrinker_list); + up(&shrinker_sem); + } + return shrinker; +} + +/* + * Remove one + */ +void remove_shrinker(struct shrinker *shrinker) +{ + down(&shrinker_sem); + list_del(&shrinker->list); + up(&shrinker_sem); + kfree(shrinker); +} + +#define SHRINK_BATCH 32 +/* + * Call the shrink functions to age shrinkable caches + * + * Here we assume it costs one seek to replace a lru page and that it also + * takes a seek to recreate a cache object. With this in mind we age equal + * percentages of the lru and ageable caches. This should balance the seeks + * generated by these structures. + * + * If the vm encounted mapped pages on the LRU it increase the pressure on + * slab to avoid swapping. + * + * FIXME: do not do for zone highmem + */ +static int shrink_slab(int scanned, unsigned int gfp_mask) +{ + struct list_head *lh; + int pages; + + if (down_trylock(&shrinker_sem)) + return 0; + + pages = nr_used_zone_pages(); + list_for_each(lh, &shrinker_list) { + struct shrinker *shrinker; + int entries; + unsigned long delta; + + shrinker = list_entry(lh, struct shrinker, list); + entries = (*shrinker->shrinker)(0, gfp_mask); + if (!entries) + continue; + delta = scanned * shrinker->seeks * entries; + shrinker->nr += delta / (pages + 1); + if (shrinker->nr > SHRINK_BATCH) { + int nr = shrinker->nr; + + shrinker->nr = 0; + (*shrinker->shrinker)(nr, gfp_mask); + } + } + up(&shrinker_sem); + return 0; +} /* Must be called with page's pte_chain_lock held. */ static inline int page_mapping_inuse(struct page * page) @@ -101,7 +191,6 @@ static inline int is_page_cache_freeable(struct page *page) return page_count(page) - !!PagePrivate(page) == 2; } - /* * shrink_list returns the number of reclaimed pages */ @@ -439,7 +528,8 @@ done: * But we had to alter page->flags anyway. */ static /* inline */ void -refill_inactive_zone(struct zone *zone, const int nr_pages_in) +refill_inactive_zone(struct zone *zone, const int nr_pages_in, + struct page_state *ps, int priority) { int pgdeactivate = 0; int nr_pages = nr_pages_in; @@ -448,6 +538,10 @@ refill_inactive_zone(struct zone *zone, const int nr_pages_in) LIST_HEAD(l_active); /* Pages to go onto the active_list */ struct page *page; struct pagevec pvec; + int reclaim_mapped = 0; + long mapped_ratio; + long distress; + long swap_tendency; lru_add_drain(); spin_lock_irq(&zone->lru_lock); @@ -469,6 +563,37 @@ refill_inactive_zone(struct zone *zone, const int nr_pages_in) } spin_unlock_irq(&zone->lru_lock); + /* + * `distress' is a measure of how much trouble we're having reclaiming + * pages. 0 -> no problems. 100 -> great trouble. + */ + distress = 100 >> priority; + + /* + * The point of this algorithm is to decide when to start reclaiming + * mapped memory instead of just pagecache. Work out how much memory + * is mapped. + */ + mapped_ratio = (ps->nr_mapped * 100) / total_memory; + + /* + * Now decide how much we really want to unmap some pages. The mapped + * ratio is downgraded - just because there's a lot of mapped memory + * doesn't necessarily mean that page reclaim isn't succeeding. + * + * The distress ratio is important - we don't want to start going oom. + * + * A 100% value of vm_swappiness overrides this algorithm altogether. + */ + swap_tendency = mapped_ratio / 2 + distress + vm_swappiness; + + /* + * Now use this metric to decide whether to start moving mapped memory + * onto the inactive list. + */ + if (swap_tendency >= 100) + reclaim_mapped = 1; + while (!list_empty(&l_hold)) { page = list_entry(l_hold.prev, struct page, lru); list_del(&page->lru); @@ -480,6 +605,10 @@ refill_inactive_zone(struct zone *zone, const int nr_pages_in) continue; } pte_chain_unlock(page); + if (!reclaim_mapped) { + list_add(&page->lru, &l_active); + continue; + } } /* * FIXME: need to consider page_count(page) here if/when we @@ -546,7 +675,7 @@ refill_inactive_zone(struct zone *zone, const int nr_pages_in) */ static /* inline */ int shrink_zone(struct zone *zone, int max_scan, unsigned int gfp_mask, - const int nr_pages, int *nr_mapped) + const int nr_pages, int *nr_mapped, struct page_state *ps, int priority) { unsigned long ratio; @@ -563,37 +692,23 @@ shrink_zone(struct zone *zone, int max_scan, unsigned int gfp_mask, ratio = (unsigned long)nr_pages * zone->nr_active / ((zone->nr_inactive | 1) * 2); atomic_add(ratio+1, &zone->refill_counter); - while (atomic_read(&zone->refill_counter) > SWAP_CLUSTER_MAX) { - atomic_sub(SWAP_CLUSTER_MAX, &zone->refill_counter); - refill_inactive_zone(zone, SWAP_CLUSTER_MAX); - } - return shrink_cache(nr_pages, zone, gfp_mask, max_scan, nr_mapped); -} - -/* - * FIXME: don't do this for ZONE_HIGHMEM - */ -/* - * Here we assume it costs one seek to replace a lru page and that it also - * takes a seek to recreate a cache object. With this in mind we age equal - * percentages of the lru and ageable caches. This should balance the seeks - * generated by these structures. - * - * NOTE: for now I do this for all zones. If we find this is too aggressive - * on large boxes we may want to exclude ZONE_HIGHMEM. - * - * If we're encountering mapped pages on the LRU then increase the pressure on - * slab to avoid swapping. - */ -static void shrink_slab(int total_scanned, int gfp_mask) -{ - int shrink_ratio; - int pages = nr_used_zone_pages(); + if (atomic_read(&zone->refill_counter) > SWAP_CLUSTER_MAX) { + int count; - shrink_ratio = (pages / (total_scanned + 1)) + 1; - shrink_dcache_memory(shrink_ratio, gfp_mask); - shrink_icache_memory(shrink_ratio, gfp_mask); - shrink_dqcache_memory(shrink_ratio, gfp_mask); + /* + * Don't try to bring down too many pages in one attempt. + * If this fails, the caller will increase `priority' and + * we'll try again, with an increased chance of reclaiming + * mapped memory. + */ + count = atomic_read(&zone->refill_counter); + if (count > SWAP_CLUSTER_MAX * 4) + count = SWAP_CLUSTER_MAX * 4; + atomic_sub(count, &zone->refill_counter); + refill_inactive_zone(zone, count, ps, priority); + } + return shrink_cache(nr_pages, zone, gfp_mask, + max_scan, nr_mapped); } /* @@ -603,7 +718,8 @@ static void shrink_slab(int total_scanned, int gfp_mask) */ static int shrink_caches(struct zone *classzone, int priority, int *total_scanned, - int gfp_mask, const int nr_pages, int order) + int gfp_mask, const int nr_pages, int order, + struct page_state *ps) { struct zone *first_classzone; struct zone *zone; @@ -630,7 +746,7 @@ shrink_caches(struct zone *classzone, int priority, int *total_scanned, if (max_scan < to_reclaim * 2) max_scan = to_reclaim * 2; ret += shrink_zone(zone, max_scan, gfp_mask, - to_reclaim, &nr_mapped); + to_reclaim, &nr_mapped, ps, priority); *total_scanned += max_scan; *total_scanned += nr_mapped; if (ret >= nr_pages) @@ -638,7 +754,7 @@ shrink_caches(struct zone *classzone, int priority, int *total_scanned, } return ret; } - + /* * This is the main entry point to direct page reclaim. * @@ -666,12 +782,14 @@ try_to_free_pages(struct zone *classzone, inc_page_state(pageoutrun); - for (priority = DEF_PRIORITY; priority; priority--) { + for (priority = DEF_PRIORITY; priority >= 0; priority--) { int total_scanned = 0; + struct page_state ps; + get_page_state(&ps); nr_reclaimed += shrink_caches(classzone, priority, &total_scanned, gfp_mask, - nr_pages, order); + nr_pages, order, &ps); if (nr_reclaimed >= nr_pages) return 1; if (total_scanned == 0) @@ -695,12 +813,19 @@ try_to_free_pages(struct zone *classzone, } /* - * kswapd will work across all this node's zones until they are all at - * pages_high. + * For kswapd, balance_pgdat() will work across all this node's zones until + * they are all at pages_high. + * + * If `nr_pages' is non-zero then it is the number of pages which are to be + * reclaimed, regardless of the zone occupancies. This is a software suspend + * special. + * + * Returns the number of pages which were actually freed. */ -static void kswapd_balance_pgdat(pg_data_t *pgdat) +static int balance_pgdat(pg_data_t *pgdat, int nr_pages, struct page_state *ps) { - int priority = DEF_PRIORITY; + int to_free = nr_pages; + int priority; int i; for (priority = DEF_PRIORITY; priority; priority--) { @@ -713,20 +838,23 @@ static void kswapd_balance_pgdat(pg_data_t *pgdat) int to_reclaim; to_reclaim = zone->pages_high - zone->free_pages; + if (nr_pages && to_free > 0) + to_reclaim = min(to_free, SWAP_CLUSTER_MAX*8); if (to_reclaim <= 0) continue; success = 0; max_scan = zone->nr_inactive >> priority; if (max_scan < to_reclaim * 2) max_scan = to_reclaim * 2; - shrink_zone(zone, max_scan, GFP_KSWAPD, - to_reclaim, &nr_mapped); + to_free -= shrink_zone(zone, max_scan, GFP_KSWAPD, + to_reclaim, &nr_mapped, ps, priority); shrink_slab(max_scan + nr_mapped, GFP_KSWAPD); } if (success) - break; /* All zones are at pages_high */ + break; blk_congestion_wait(WRITE, HZ/4); } + return nr_pages - to_free; } /* @@ -768,16 +896,45 @@ int kswapd(void *p) tsk->flags |= PF_MEMALLOC|PF_KSWAPD; for ( ; ; ) { + struct page_state ps; + if (current->flags & PF_FREEZE) refrigerator(PF_IOTHREAD); prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE); schedule(); finish_wait(&pgdat->kswapd_wait, &wait); - kswapd_balance_pgdat(pgdat); + get_page_state(&ps); + balance_pgdat(pgdat, 0, &ps); blk_run_queues(); } } +#ifdef CONFIG_SOFTWARE_SUSPEND +/* + * Try to free `nr_pages' of memory, system-wide. Returns the number of freed + * pages. + */ +int shrink_all_memory(int nr_pages) +{ + pg_data_t *pgdat; + int nr_to_free = nr_pages; + int ret = 0; + + for_each_pgdat(pgdat) { + int freed; + struct page_state ps; + + get_page_state(&ps); + freed = balance_pgdat(pgdat, nr_to_free, &ps); + ret += freed; + nr_to_free -= freed; + if (nr_to_free <= 0) + break; + } + return ret; +} +#endif + static int __init kswapd_init(void) { pg_data_t *pgdat; @@ -785,6 +942,7 @@ static int __init kswapd_init(void) swap_setup(); for_each_pgdat(pgdat) kernel_thread(kswapd, pgdat, CLONE_KERNEL); + total_memory = nr_free_pagecache_pages(); return 0; } |
