summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@nuts.ninka.net>2002-10-13 09:28:42 -0700
committerDavid S. Miller <davem@nuts.ninka.net>2002-10-13 09:28:42 -0700
commita6805352ac064bcdca2b90aaa78efe6df2243b47 (patch)
tree4c385f016c82c0d19d451e4b1547caab7f258027
parentf10972bec12a21510c21371ef66270844a164964 (diff)
parent71660e156c8516c75e63d40d9f6c19af82340071 (diff)
Merge nuts.ninka.net:/home/davem/src/BK/network-2.5
into nuts.ninka.net:/home/davem/src/BK/net-2.5
-rw-r--r--Documentation/Changes6
-rw-r--r--Documentation/arm/XScale/ADIFCC/80200EVB111
-rw-r--r--Documentation/arm/XScale/IOP310/IQ80310295
-rw-r--r--Documentation/filesystems/proc.txt2
-rw-r--r--Documentation/sysctl/vm.txt4
-rw-r--r--MAINTAINERS5
-rw-r--r--arch/arm/Makefile20
-rw-r--r--arch/arm/boot/compressed/Makefile2
-rw-r--r--arch/arm/boot/compressed/head.S58
-rw-r--r--arch/arm/boot/compressed/ll_char_wr.S216
-rw-r--r--arch/arm/config.in4
-rw-r--r--arch/arm/kernel/arch.c1
-rw-r--r--arch/arm/kernel/bios32.c32
-rw-r--r--arch/arm/kernel/ecard.c116
-rw-r--r--arch/arm/kernel/entry-armv.S15
-rw-r--r--arch/arm/kernel/process.c4
-rw-r--r--arch/arm/kernel/ptrace.c139
-rw-r--r--arch/arm/kernel/setup.c27
-rw-r--r--arch/arm/kernel/signal.c36
-rw-r--r--arch/arm/kernel/time-acorn.c33
-rw-r--r--arch/arm/kernel/time.c9
-rw-r--r--arch/arm/kernel/traps.c25
-rw-r--r--arch/arm/mach-integrator/cpu.c90
-rw-r--r--arch/arm/mach-iop310/iop310-pci.c12
-rw-r--r--arch/arm/mach-iop310/iq80310-time.c2
-rw-r--r--arch/arm/mach-sa1100/Makefile12
-rw-r--r--arch/arm/mach-sa1100/assabet.c27
-rw-r--r--arch/arm/mach-sa1100/generic.c4
-rw-r--r--arch/arm/mach-sa1100/neponset.c26
-rw-r--r--arch/arm/mach-sa1100/sa1111.c391
-rw-r--r--arch/arm/mm/fault-armv.c2
-rw-r--r--arch/arm/mm/init.c6
-rw-r--r--arch/arm/mm/minicache.c2
-rw-r--r--arch/arm/mm/mm-armv.c85
-rw-r--r--arch/arm/mm/proc-syms.c14
-rw-r--r--arch/arm/mm/tlb-v3.S46
-rw-r--r--arch/arm/mm/tlb-v4.S60
-rw-r--r--arch/arm/mm/tlb-v4wb.S99
-rw-r--r--arch/arm/vmlinux.lds.S4
-rw-r--r--arch/cris/drivers/examples/kiobuftest.c111
-rw-r--r--arch/i386/mm/discontig.c1
-rw-r--r--drivers/acorn/block/fd1772.c26
-rw-r--r--drivers/acorn/char/Makefile15
-rw-r--r--drivers/acorn/char/i2c.c4
-rw-r--r--drivers/acorn/char/keyb_ps2.c416
-rw-r--r--drivers/acorn/char/mouse_rpc.c91
-rw-r--r--drivers/acorn/char/serial-atomwide.c23
-rw-r--r--drivers/acorn/char/serial-card.c120
-rw-r--r--drivers/acorn/char/serial-dualsp.c21
-rw-r--r--drivers/acorn/net/ether1.c112
-rw-r--r--drivers/acorn/net/ether3.c124
-rw-r--r--drivers/acorn/net/etherh.c168
-rw-r--r--drivers/acorn/scsi/acornscsi.c16
-rw-r--r--drivers/acorn/scsi/acornscsi.h2
-rw-r--r--drivers/acorn/scsi/cumana_1.c16
-rw-r--r--drivers/acorn/scsi/ecoscsi.c14
-rw-r--r--drivers/acorn/scsi/fas216.c14
-rw-r--r--drivers/acorn/scsi/fas216.h2
-rw-r--r--drivers/acorn/scsi/oak.c12
-rw-r--r--drivers/acorn/scsi/queue.c2
-rw-r--r--drivers/acorn/scsi/queue.h2
-rw-r--r--drivers/acorn/scsi/scsi.h4
-rw-r--r--drivers/block/Config.in3
-rw-r--r--drivers/block/ll_rw_blk.c2
-rw-r--r--drivers/char/Config.help21
-rw-r--r--drivers/char/Config.in1
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/n_r3964.c2
-rw-r--r--drivers/char/tipar.c541
-rw-r--r--drivers/ide/ide-cd.c2
-rw-r--r--drivers/media/video/bttv-risc.c1
-rw-r--r--drivers/media/video/bttvp.h1
-rw-r--r--drivers/media/video/video-buf.c109
-rw-r--r--drivers/media/video/video-buf.h8
-rw-r--r--drivers/mtd/afs.c9
-rw-r--r--drivers/mtd/maps/integrator-flash.c8
-rw-r--r--drivers/pcmcia/sa1100_adsbitsy.c16
-rw-r--r--drivers/pcmcia/sa1100_assabet.c17
-rw-r--r--drivers/pcmcia/sa1100_badge4.c16
-rw-r--r--drivers/pcmcia/sa1100_cerf.c17
-rw-r--r--drivers/pcmcia/sa1100_flexanet.c17
-rw-r--r--drivers/pcmcia/sa1100_freebird.c17
-rw-r--r--drivers/pcmcia/sa1100_generic.c34
-rw-r--r--drivers/pcmcia/sa1100_graphicsclient.c17
-rw-r--r--drivers/pcmcia/sa1100_graphicsmaster.c16
-rw-r--r--drivers/pcmcia/sa1100_h3600.c33
-rw-r--r--drivers/pcmcia/sa1100_jornada720.c16
-rw-r--r--drivers/pcmcia/sa1100_neponset.c16
-rw-r--r--drivers/pcmcia/sa1100_pangolin.c13
-rw-r--r--drivers/pcmcia/sa1100_pfs168.c16
-rw-r--r--drivers/pcmcia/sa1100_shannon.c17
-rw-r--r--drivers/pcmcia/sa1100_simpad.c17
-rw-r--r--drivers/pcmcia/sa1100_stork.c17
-rw-r--r--drivers/pcmcia/sa1100_system3.c16
-rw-r--r--drivers/pcmcia/sa1100_trizeps.c15
-rw-r--r--drivers/pcmcia/sa1100_xp860.c16
-rw-r--r--drivers/pcmcia/sa1100_yopy.c17
-rw-r--r--drivers/scsi/scsi.h2
-rw-r--r--drivers/scsi/sd.c2
-rw-r--r--drivers/serial/8250_acorn.c150
-rw-r--r--drivers/serial/Config.help17
-rw-r--r--drivers/serial/Config.in3
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/usb/core/hcd-pci.c3
-rw-r--r--drivers/usb/core/hub.c12
-rw-r--r--drivers/usb/core/inode.c33
-rw-r--r--drivers/usb/core/message.c30
-rw-r--r--drivers/usb/core/urb.c2
-rw-r--r--drivers/usb/core/usb.c37
-rw-r--r--drivers/usb/host/ehci-hcd.c3
-rw-r--r--drivers/usb/host/hc_sl811.c3
-rw-r--r--drivers/usb/host/ohci-pci.c3
-rw-r--r--drivers/usb/host/ohci-sa1111.c5
-rw-r--r--drivers/usb/host/uhci-hcd.c3
-rw-r--r--drivers/usb/input/wacom.c1
-rw-r--r--drivers/usb/media/Makefile2
-rw-r--r--drivers/usb/media/vicam.c1894
-rw-r--r--drivers/usb/media/vicam.h81
-rw-r--r--drivers/usb/media/vicamurbs.h332
-rw-r--r--drivers/usb/net/usbnet.c2
-rw-r--r--drivers/usb/serial/io_ti.c76
-rw-r--r--drivers/usb/serial/usb-serial.c26
-rw-r--r--drivers/usb/serial/visor.c2
-rw-r--r--drivers/usb/serial/whiteheat.c18
-rw-r--r--drivers/usb/storage/datafab.c11
-rw-r--r--drivers/usb/storage/freecom.c90
-rw-r--r--drivers/usb/storage/initializers.c2
-rw-r--r--drivers/usb/storage/isd200.c42
-rw-r--r--drivers/usb/storage/jumpshot.c34
-rw-r--r--drivers/usb/storage/raw_bulk.c213
-rw-r--r--drivers/usb/storage/raw_bulk.h15
-rw-r--r--drivers/usb/storage/sddr09.c50
-rw-r--r--drivers/usb/storage/sddr55.c10
-rw-r--r--drivers/usb/storage/shuttle_usbat.c254
-rw-r--r--drivers/usb/storage/transport.c280
-rw-r--r--drivers/usb/storage/transport.h24
-rw-r--r--drivers/usb/storage/usb.c6
-rw-r--r--drivers/usb/storage/usb.h4
-rw-r--r--drivers/video/acornfb.c190
-rw-r--r--drivers/video/acornfb.h3
-rw-r--r--drivers/video/clps711xfb.c174
-rw-r--r--drivers/video/cyber2000fb.c734
-rw-r--r--drivers/video/cyber2000fb.h71
-rw-r--r--fs/Makefile2
-rw-r--r--fs/adfs/dir_f.c10
-rw-r--r--fs/adfs/dir_fplus.c8
-rw-r--r--fs/aio.c7
-rw-r--r--fs/bio.c125
-rw-r--r--fs/block_dev.c1
-rw-r--r--fs/buffer.c60
-rw-r--r--fs/dcache.c50
-rw-r--r--fs/direct-io.c33
-rw-r--r--fs/dquot.c28
-rw-r--r--fs/exec.c2
-rw-r--r--fs/fcntl.c1
-rw-r--r--fs/file_table.c1
-rw-r--r--fs/fs-writeback.c1
-rw-r--r--fs/inode.c49
-rw-r--r--fs/iobuf.c125
-rw-r--r--fs/open.c1
-rw-r--r--fs/proc/proc_misc.c6
-rw-r--r--fs/xfs/linux/xfs_aops.c1
-rw-r--r--fs/xfs/linux/xfs_ioctl.c2
-rw-r--r--include/asm-arm/arch-ebsa285/time.h4
-rw-r--r--include/asm-arm/arch-rpc/ide.h2
-rw-r--r--include/asm-arm/arch-rpc/serial.h2
-rw-r--r--include/asm-arm/arch-rpc/uncompress.h24
-rw-r--r--include/asm-arm/arch-sa1100/irqs.h2
-rw-r--r--include/asm-arm/arch-sa1100/time.h2
-rw-r--r--include/asm-arm/ecard.h29
-rw-r--r--include/asm-arm/glue.h118
-rw-r--r--include/asm-arm/hardirq.h12
-rw-r--r--include/asm-arm/hardware/sa1111.h14
-rw-r--r--include/asm-arm/ide.h1
-rw-r--r--include/asm-arm/numnodes.h17
-rw-r--r--include/asm-arm/page.h64
-rw-r--r--include/asm-arm/pci.h4
-rw-r--r--include/asm-arm/pgalloc.h3
-rw-r--r--include/asm-arm/pgtable.h1
-rw-r--r--include/asm-arm/proc-armo/system.h2
-rw-r--r--include/asm-arm/proc-armv/pgalloc.h1
-rw-r--r--include/asm-arm/proc-armv/tlbflush.h230
-rw-r--r--include/asm-arm/processor.h26
-rw-r--r--include/asm-arm/procinfo.h2
-rw-r--r--include/asm-arm/tlb.h77
-rw-r--r--include/linux/buffer_head.h1
-rw-r--r--include/linux/dcache.h11
-rw-r--r--include/linux/iobuf.h88
-rw-r--r--include/linux/mm.h23
-rw-r--r--include/linux/swap.h2
-rw-r--r--include/linux/sysctl.h3
-rw-r--r--include/linux/usb.h37
-rw-r--r--include/linux/videodev.h1
-rw-r--r--include/linux/writeback.h2
-rw-r--r--init/main.c1
-rw-r--r--kernel/ksyms.c16
-rw-r--r--kernel/sysctl.c7
-rw-r--r--mm/filemap.c1
-rw-r--r--mm/memory.c224
-rw-r--r--mm/msync.c5
-rw-r--r--mm/page-writeback.c94
-rw-r--r--mm/page_alloc.c2
-rw-r--r--mm/swap.c12
-rw-r--r--mm/vmscan.c264
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(&current->sigmask_lock);
+ spin_lock_irq(&current->sig->siglock);
saveset = current->blocked;
siginitset(&current->blocked, mask);
recalc_sigpending();
- spin_unlock_irq(&current->sigmask_lock);
+ spin_unlock_irq(&current->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(&current->sigmask_lock);
+ spin_lock_irq(&current->sig->siglock);
saveset = current->blocked;
current->blocked = newset;
recalc_sigpending();
- spin_unlock_irq(&current->sigmask_lock);
+ spin_unlock_irq(&current->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(&current->sigmask_lock);
+ spin_lock_irq(&current->sig->siglock);
current->blocked = set;
recalc_sigpending();
- spin_unlock_irq(&current->sigmask_lock);
+ spin_unlock_irq(&current->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(&current->sigmask_lock);
+ spin_lock_irq(&current->sig->siglock);
current->blocked = set;
recalc_sigpending();
- spin_unlock_irq(&current->sigmask_lock);
+ spin_unlock_irq(&current->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 = &current->blocked;
- local_irq_disable();
- if (current->sig->shared_pending.head) {
- spin_lock(&current->sig->siglock);
- signr = dequeue_signal(&current->sig->shared_pending, mask, &info);
- spin_unlock(&current->sig->siglock);
- }
- if (!signr) {
- spin_lock(&current->sigmask_lock);
- signr = dequeue_signal(&current->pending, mask, &info);
- spin_unlock(&current->sigmask_lock);
- }
- local_irq_enable();
+ spin_lock_irq(&current->sig->siglock);
+ signr = dequeue_signal(&current->blocked, &info);
+ spin_unlock_irq(&current->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(&ether1_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(&ether1_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(&ether3_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(&ether3_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 = &etherh_ops;
- ec->irq_data = eh;
- eh->ctrl = 0;
- eh->id = ec->cid.product;
+ if (ec->irq != 11) {
+ ec->ops = &etherh_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(&etherh_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(&etherh_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(&current->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(&current->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
};
diff --git a/fs/aio.c b/fs/aio.c
index e561c8b83a00..6b51c1316ab2 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -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>
diff --git a/fs/bio.c b/fs/bio.c
index 407f18c90a48..6c196406c90a 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -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;
}