From 83e903468ce90de64dd6e87ace6ea28f72b6e5eb Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Thu, 29 Jan 2009 17:05:12 +0000 Subject: [PATCH] target/device: remove obsolete Sharp/LNode80 platform As discussed on the list and requested on irc: < prpplague> Jacmet: hey, just wanted to drop a note to confirm that the LNode80 can be removed, we never went into full scale production of it, only 20 were ever made --- target/device/Config.in | 1 - target/device/Sharp/Config.in | 14 - target/device/Sharp/LNode80/Makefile.in | 7 - target/device/Sharp/LNode80/device_table.txt | 172 - .../kernel-patches/001-patch-2.4.26-vrs1 | 89183 ---------------- .../002-patch-2.4.26-vrs1-lnode80 | 14498 --- target/device/Sharp/LNode80/linux.config | 804 - target/device/Sharp/LNode80/linux.mk | 117 - .../Sharp/LNode80/target_skeleton/etc/TZ | 1 - .../Sharp/LNode80/target_skeleton/etc/fstab | 8 - .../Sharp/LNode80/target_skeleton/etc/group | 10 - .../LNode80/target_skeleton/etc/hostname | 1 - .../Sharp/LNode80/target_skeleton/etc/hosts | 1 - .../LNode80/target_skeleton/etc/init.d/rcS | 27 - .../Sharp/LNode80/target_skeleton/etc/inittab | 48 - .../Sharp/LNode80/target_skeleton/etc/inputrc | 44 - .../Sharp/LNode80/target_skeleton/etc/issue | 4 - .../target_skeleton/etc/network/interfaces | 4 - .../Sharp/LNode80/target_skeleton/etc/passwd | 13 - .../Sharp/LNode80/target_skeleton/etc/profile | 48 - .../LNode80/target_skeleton/etc/protocols | 31 - .../LNode80/target_skeleton/etc/securetty | 14 - .../LNode80/target_skeleton/etc/services | 302 - .../Sharp/LNode80/target_skeleton/etc/shadow | 12 - .../LNode80/target_skeleton/root/.bash_logout | 7 - .../target_skeleton/root/.bash_profile | 15 - .../LNode80/target_skeleton/root/.bashrc | 48 - .../Sharp/LNode80/target_skeleton/root/.empty | 0 .../usr/share/udhcpc/default.script | 39 - target/device/Sharp/Makefile.in | 7 - 30 files changed, 105480 deletions(-) delete mode 100644 target/device/Sharp/Config.in delete mode 100644 target/device/Sharp/LNode80/Makefile.in delete mode 100644 target/device/Sharp/LNode80/device_table.txt delete mode 100644 target/device/Sharp/LNode80/kernel-patches/001-patch-2.4.26-vrs1 delete mode 100644 target/device/Sharp/LNode80/kernel-patches/002-patch-2.4.26-vrs1-lnode80 delete mode 100644 target/device/Sharp/LNode80/linux.config delete mode 100644 target/device/Sharp/LNode80/linux.mk delete mode 100644 target/device/Sharp/LNode80/target_skeleton/etc/TZ delete mode 100644 target/device/Sharp/LNode80/target_skeleton/etc/fstab delete mode 100644 target/device/Sharp/LNode80/target_skeleton/etc/group delete mode 100644 target/device/Sharp/LNode80/target_skeleton/etc/hostname delete mode 100644 target/device/Sharp/LNode80/target_skeleton/etc/hosts delete mode 100644 target/device/Sharp/LNode80/target_skeleton/etc/init.d/rcS delete mode 100644 target/device/Sharp/LNode80/target_skeleton/etc/inittab delete mode 100644 target/device/Sharp/LNode80/target_skeleton/etc/inputrc delete mode 100644 target/device/Sharp/LNode80/target_skeleton/etc/issue delete mode 100644 target/device/Sharp/LNode80/target_skeleton/etc/network/interfaces delete mode 100644 target/device/Sharp/LNode80/target_skeleton/etc/passwd delete mode 100644 target/device/Sharp/LNode80/target_skeleton/etc/profile delete mode 100644 target/device/Sharp/LNode80/target_skeleton/etc/protocols delete mode 100644 target/device/Sharp/LNode80/target_skeleton/etc/securetty delete mode 100644 target/device/Sharp/LNode80/target_skeleton/etc/services delete mode 100644 target/device/Sharp/LNode80/target_skeleton/etc/shadow delete mode 100644 target/device/Sharp/LNode80/target_skeleton/root/.bash_logout delete mode 100644 target/device/Sharp/LNode80/target_skeleton/root/.bash_profile delete mode 100644 target/device/Sharp/LNode80/target_skeleton/root/.bashrc delete mode 100644 target/device/Sharp/LNode80/target_skeleton/root/.empty delete mode 100644 target/device/Sharp/LNode80/target_skeleton/usr/share/udhcpc/default.script delete mode 100644 target/device/Sharp/Makefile.in diff --git a/target/device/Config.in b/target/device/Config.in index 80d2c80e1b..bedbf92553 100644 --- a/target/device/Config.in +++ b/target/device/Config.in @@ -10,7 +10,6 @@ source "target/device/Atmel/Config.in" source "target/device/Hitachi/Config.in" source "target/device/jp/Config.in" source "target/device/KwikByte/Config.in" -source "target/device/Sharp/Config.in" source "target/device/Soekris/Config.in" source "target/device/valka/Config.in" source "target/device/Via/Config.in" diff --git a/target/device/Sharp/Config.in b/target/device/Sharp/Config.in deleted file mode 100644 index b54a4a13fb..0000000000 --- a/target/device/Sharp/Config.in +++ /dev/null @@ -1,14 +0,0 @@ -menuconfig BR2_TARGET_SHARP - bool "Sharp Device Support" - depends on BR2_arm - -if BR2_TARGET_SHARP -comment "Sharp Specific Device Support" - depends on BR2_arm - -config BR2_TARGET_SHARP_LNODE80 - bool "Board support for the LNode80 development board" - depends on BR2_arm - help - Support for the LNode80 LH79520 based device -endif diff --git a/target/device/Sharp/LNode80/Makefile.in b/target/device/Sharp/LNode80/Makefile.in deleted file mode 100644 index d54306b387..0000000000 --- a/target/device/Sharp/LNode80/Makefile.in +++ /dev/null @@ -1,7 +0,0 @@ -# SHARP_LNODE80_PATH=target/device/Sharp/LNode80 -BOARD_PATH=target/device/Sharp/LNode80 - -TARGET_SKELETON=$(BOARD_PATH)/target_skeleton -TARGET_DEVICE_TABLE=$(BOARD_PATH)/device_table.txt - -TARGETS+=linux diff --git a/target/device/Sharp/LNode80/device_table.txt b/target/device/Sharp/LNode80/device_table.txt deleted file mode 100644 index cfea770dde..0000000000 --- a/target/device/Sharp/LNode80/device_table.txt +++ /dev/null @@ -1,172 +0,0 @@ -# When building a target filesystem, it is desirable to not have to -# become root and then run 'mknod' a thousand times. Using a device -# table you can create device nodes and directories "on the fly". -# -# This is a sample device table file for use with genext2fs. You can -# do all sorts of interesting things with a device table file. For -# example, if you want to adjust the permissions on a particular file -# you can just add an entry like: -# /sbin/foobar f 2755 0 0 - - - - - -# and (assuming the file /sbin/foobar exists) it will be made setuid -# root (regardless of what its permissions are on the host filesystem. -# Furthermore, you can use a single table entry to create a many device -# minors. For example, if I wanted to create /dev/hda and /dev/hda[0-15] -# I could just use the following two table entries: -# /dev/hda b 640 0 0 3 0 0 0 - -# /dev/hda b 640 0 0 3 1 1 1 15 -# -# Device table entries take the form of: -# -# where name is the file name, type can be one of: -# f A regular file -# d Directory -# c Character special device file -# b Block special device file -# p Fifo (named pipe) -# uid is the user id for the target file, gid is the group id for the -# target file. The rest of the entries (major, minor, etc) apply only -# to device special files. - -# Have fun -# -Erik Andersen -# - -# -/dev d 755 0 0 - - - - - -/dev/pts d 755 0 0 - - - - - -/dev/shm d 755 0 0 - - - - - -/tmp d 1777 0 0 - - - - - -/etc d 755 0 0 - - - - - -/home/default d 2755 1000 1000 - - - - - -# -/bin/busybox f 4755 0 0 - - - - - -/etc/shadow f 600 0 0 - - - - - -/etc/passwd f 644 0 0 - - - - - -/etc/network/if-up.d d 755 0 0 - - - - - -/etc/network/if-pre-up.d d 755 0 0 - - - - - -/etc/network/if-down.d d 755 0 0 - - - - - -/etc/network/if-post-down.d d 755 0 0 - - - - - -/usr/share/udhcpc/default.script f 755 0 0 - - - - - -# uncomment this to allow starting x as non-root -#/usr/X11R6/bin/Xfbdev f 4755 0 0 - - - - - -# Normal system devices -/dev/mem c 640 0 0 1 1 0 0 - -/dev/kmem c 640 0 0 1 2 0 0 - -/dev/null c 666 0 0 1 3 0 0 - -/dev/zero c 666 0 0 1 5 0 0 - -/dev/random c 666 0 0 1 8 0 0 - -/dev/urandom c 666 0 0 1 9 0 0 - -/dev/ram b 640 0 0 1 1 0 0 - -/dev/ram b 640 0 0 1 0 0 1 4 -/dev/loop b 640 0 0 7 0 0 1 2 -/dev/rtc c 640 0 0 10 135 - - - -/dev/console c 666 0 0 5 1 - - - -/dev/tty c 666 0 0 5 0 - - - -/dev/tty c 666 0 0 4 0 0 1 8 -/dev/ttyp c 666 0 0 3 0 0 1 10 -/dev/ptyp c 666 0 0 2 0 0 1 10 -/dev/ptmx c 666 0 0 5 2 - - - -/dev/ttyP c 666 0 0 57 0 0 1 4 -/dev/ttyS c 666 0 0 4 64 0 1 4 -/dev/fb c 640 0 5 29 0 0 32 4 -#/dev/ttySA c 666 0 0 204 5 0 1 3 -/dev/psaux c 666 0 0 10 1 0 0 - -#/dev/ppp c 666 0 0 108 0 - - - -/dev/ttyAM c 666 0 0 204 16 0 1 2 - -# Input stuff -/dev/input d 755 0 0 - - - - - -/dev/input/mice c 640 0 0 13 63 0 0 - -/dev/input/mouse c 660 0 0 13 32 0 1 4 -/dev/input/event c 660 0 0 13 64 0 1 4 -#/dev/input/js c 660 0 0 13 0 0 1 4 - - -# MTD stuff -/dev/mtd c 640 0 0 90 0 0 2 4 -/dev/mtdblock b 640 0 0 31 0 0 1 4 - -#Tun/tap driver -/dev/net d 755 0 0 - - - - - -/dev/net/tun c 660 0 0 10 200 - - - - -# Audio stuff -#/dev/audio c 666 0 29 14 4 - - - -#/dev/audio1 c 666 0 29 14 20 - - - -#/dev/dsp c 666 0 29 14 3 - - - -#/dev/dsp1 c 666 0 29 14 19 - - - -#/dev/sndstat c 666 0 29 14 6 - - - - -# User-mode Linux stuff -#/dev/ubda b 640 0 0 98 0 0 0 - -#/dev/ubda b 640 0 0 98 1 1 1 15 - -# IDE Devices -/dev/hda b 640 0 0 3 0 0 0 - -/dev/hda b 640 0 0 3 1 1 1 15 -/dev/hdb b 640 0 0 3 64 0 0 - -/dev/hdb b 640 0 0 3 65 1 1 15 -#/dev/hdc b 640 0 0 22 0 0 0 - -#/dev/hdc b 640 0 0 22 1 1 1 15 -#/dev/hdd b 640 0 0 22 64 0 0 - -#/dev/hdd b 640 0 0 22 65 1 1 15 -#/dev/hde b 640 0 0 33 0 0 0 - -#/dev/hde b 640 0 0 33 1 1 1 15 -#/dev/hdf b 640 0 0 33 64 0 0 - -#/dev/hdf b 640 0 0 33 65 1 1 15 -#/dev/hdg b 640 0 0 34 0 0 0 - -#/dev/hdg b 640 0 0 34 1 1 1 15 -#/dev/hdh b 640 0 0 34 64 0 0 - -#/dev/hdh b 640 0 0 34 65 1 1 15 - -# SCSI Devices -#/dev/sda b 640 0 0 8 0 0 0 - -#/dev/sda b 640 0 0 8 1 1 1 15 -#/dev/sdb b 640 0 0 8 16 0 0 - -#/dev/sdb b 640 0 0 8 17 1 1 15 -#/dev/sdc b 640 0 0 8 32 0 0 - -#/dev/sdc b 640 0 0 8 33 1 1 15 -#/dev/sdd b 640 0 0 8 48 0 0 - -#/dev/sdd b 640 0 0 8 49 1 1 15 -#/dev/sde b 640 0 0 8 64 0 0 - -#/dev/sde b 640 0 0 8 65 1 1 15 -#/dev/sdf b 640 0 0 8 80 0 0 - -#/dev/sdf b 640 0 0 8 81 1 1 15 -#/dev/sdg b 640 0 0 8 96 0 0 - -#/dev/sdg b 640 0 0 8 97 1 1 15 -#/dev/sdh b 640 0 0 8 112 0 0 - -#/dev/sdh b 640 0 0 8 113 1 1 15 -#/dev/sg c 640 0 0 21 0 0 1 15 -#/dev/scd b 640 0 0 11 0 0 1 15 -#/dev/st c 640 0 0 9 0 0 1 8 -#/dev/nst c 640 0 0 9 128 0 1 8 -#/dev/st c 640 0 0 9 32 1 1 4 -#/dev/st c 640 0 0 9 64 1 1 4 -#/dev/st c 640 0 0 9 96 1 1 4 - -# Floppy disk devices -#/dev/fd b 640 0 0 2 0 0 1 2 -#/dev/fd0d360 b 640 0 0 2 4 0 0 - -#/dev/fd1d360 b 640 0 0 2 5 0 0 - -#/dev/fd0h1200 b 640 0 0 2 8 0 0 - -#/dev/fd1h1200 b 640 0 0 2 9 0 0 - -#/dev/fd0u1440 b 640 0 0 2 28 0 0 - -#/dev/fd1u1440 b 640 0 0 2 29 0 0 - -#/dev/fd0u2880 b 640 0 0 2 32 0 0 - -#/dev/fd1u2880 b 640 0 0 2 33 0 0 - - -# All the proprietary cdrom devices in the world -#/dev/aztcd b 640 0 0 29 0 0 0 - -#/dev/bpcd b 640 0 0 41 0 0 0 - -#/dev/capi20 c 640 0 0 68 0 0 1 2 -#/dev/cdu31a b 640 0 0 15 0 0 0 - -#/dev/cdu535 b 640 0 0 24 0 0 0 - -#/dev/cm206cd b 640 0 0 32 0 0 0 - -#/dev/sjcd b 640 0 0 18 0 0 0 - -#/dev/sonycd b 640 0 0 15 0 0 0 - -#/dev/gscd b 640 0 0 16 0 0 0 - -#/dev/sbpcd b 640 0 0 25 0 0 0 - -#/dev/sbpcd b 640 0 0 25 0 0 1 4 -#/dev/mcd b 640 0 0 23 0 0 0 - -#/dev/optcd b 640 0 0 17 0 0 0 - - diff --git a/target/device/Sharp/LNode80/kernel-patches/001-patch-2.4.26-vrs1 b/target/device/Sharp/LNode80/kernel-patches/001-patch-2.4.26-vrs1 deleted file mode 100644 index 590da35f2e..0000000000 --- a/target/device/Sharp/LNode80/kernel-patches/001-patch-2.4.26-vrs1 +++ /dev/null @@ -1,89183 +0,0 @@ -diff -urN linux-2.4.26/Documentation/Configure.help linux-2.4.26-vrs1/Documentation/Configure.help ---- linux-2.4.26/Documentation/Configure.help 2004-04-19 11:44:14.000000000 +0100 -+++ linux-2.4.26-vrs1/Documentation/Configure.help 2004-04-18 21:47:49.000000000 +0100 -@@ -4879,6 +4879,13 @@ - Say Y to enable support for Permedia2 AGP frame buffer card from - 3Dlabs (aka `Graphic Blaster Exxtreme') on the PCI bus. - -+Permedia3 support (EXPERIMENTAL) -+CONFIG_FB_PM3 -+ This is the frame buffer device driver for the 3DLabs Permedia3 -+ chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 & -+ similar boards, 3DLabs Permedia3 Create!, Appian Jeronimo 2000 -+ and maybe other boards. -+ - Phase5 CVisionPPC/BVisionPPC support - CONFIG_FB_PM2_CVPPC - Say Y to enable support for the Amiga Phase 5 CVisionPPC BVisionPPC -@@ -13213,6 +13220,17 @@ - The module will be called tmspci.o. If you want to compile it - as a module, say M here and read . - -+Altera ether00 support -+CONFIG_ETHER00 -+ This is the driver for Altera's ether00 ethernet mac IP core. Say -+ Y here if you want to build support for this into the kernel. It -+ is also available as a module (say M here) that can be inserted/ -+ removed from the kernel at the same time as the PLD is configured. -+ If this driver is running on an epxa10 development board then it -+ will generate a suitable hw address based on the board serial -+ number (MTD support is required for this). Otherwise you will -+ need to set a suitable hw address using ifconfig. -+ - Generic TMS380 ISA support - CONFIG_TMSISA - This tms380 module supports generic TMS380-based ISA cards. -@@ -15157,6 +15175,16 @@ - support" be compiled as a module for this driver to be used - properly. - -+Altera's uart00 serial driver -+CONFIG_SERIAL_UART00 -+ Say Y here if you want to use the hard logic uart on Excalibur. This -+ driver also supports soft logic implentations of this uart core. -+ -+Serial console on uart00 -+CONFIG_SERIAL_UART00_CONSOLE -+ Say Y here if you want to support a serial console on an Excalibur -+ hard logic uart or uart00 IP core. -+ - USB ConnectTech WhiteHEAT Serial Driver - CONFIG_USB_SERIAL_WHITEHEAT - Say Y here if you want to use a ConnectTech WhiteHEAT 4 port -@@ -19173,6 +19201,20 @@ - . - The module will be called i2c-velleman.o. - -+Guide GPIO adapter -+CONFIG_I2C_GUIDE -+ This supports the Iders GUIDE I2C bit-bashing adapter. If you have -+ selected the GUIDE A07 as your ARM system type, you cannot deselect -+ this option, as it is required for proper operation of the GUIDE. -+ -+ This interface uses /dev/i2c-0 (major 89, minor 0). -+ -+ Say Y if you own such an adapter. -+ -+ This driver is also available as a module. If you want to compile -+ it as a module, say M here and read Documentation/modules.txt. The -+ module will be called i2c-guide.o. -+ - I2C PCF 8584 interfaces - CONFIG_I2C_ALGOPCF - This allows you to use a range of I2C adapters called PCF adapters. -@@ -20310,6 +20352,17 @@ - . The module will be called - softdog.o. - -+SA1100 Internal Watchdog -+CONFIG_SA1100_WATCHDOG -+ Watchdog timer embedded into SA11x0 chips. This will reboot your -+ system when timeout is reached. -+ NOTE, that once enabled, this timer cannot be disabled. -+ -+ This driver is also available as a module ( = code which can be -+ inserted in and removed from the running kernel whenever you want). -+ If you want to compile it as a module, say M here and read -+ Documentation/modules.txt. The module will be called sa1100_wdt.o. -+ - Berkshire Products PC Watchdog - CONFIG_PCWATCHDOG - This is the driver for the Berkshire Products PC Watchdog card. -@@ -21971,6 +22024,30 @@ - from RME. If you want to acess advanced features of the card, read - Documentation/sound/rme96xx. - -+Assabet audio (UDA1341) support -+CONFIG_SOUND_ASSABET_UDA1341 -+ Say Y or M if you have an Intel Assabet evaluation board and want to -+ use the Philips UDA 1341 audio chip (the one that drives the stereo -+ audio output) on the SA1100 SSP port. -+ -+Compaq iPAQ audio support -+CONFIG_SOUND_H3600_UDA1341 -+ Say Y or M if you have a Compaq iPaq handheld computer and want to -+ use its Philips UDA 1341 audio chip. -+ -+Audio support for SA1111/UDA1341 -+CONFIG_SOUND_SA1111_UDA1341 -+ Say Y or M if you have an SA11x0 system with a Philips UDA 1341 -+ connected to the SA11x1. An example of such a system is the Intel -+ Assabet evaluation board connected to a Neponset expansion board. -+ -+Generic DAC on the SA11x0 SSP port -+CONFIG_SOUND_SA1100SSP -+ Say Y or M if you have an SA-11x0 system with a DAC on the SSP port. -+ The LART has an Burr-Brown PCM 1710 digital to analog convertor on -+ the SSP port, so you want to say Y or M for the LART. It might work -+ on other SA-1100 platforms, too, but this is not tested. -+ - Are you using a crosscompiler - CONFIG_CROSSCOMPILE - Say Y here if you are compiling the kernel on a different -@@ -25674,6 +25751,20 @@ - Say Y if configuring for a Pangolin. - Say N otherwise. - -+Shannon -+CONFIG_SA1100_SHANNON -+ The Shannon (also known as a Tuxscreen, and also as a IS2630) was a -+ limited edition webphone produced by Philips. The Shannon is a SA1100 -+ platform with a 640x480 LCD, touchscreen, CIR keyboard, PCMCIA slots, -+ and a telco interface. -+ -+Simputer -+CONFIG_SA1100_SIMPUTER -+ Say Y here if you are using an Intel(R) StrongARM(R) SA-1110 -+ based Simputer. See http://www.simputer.org/ for information -+ on the Simputer. The Simputer software is actively maintained -+ by PicoPeta Simputers Pvt. Ltd. (http://www.picopeta.com) -+ - Victor - CONFIG_SA1100_VICTOR - Say Y here if you are using a Visu Aide Intel(R) StrongARM(R) -@@ -25681,6 +25772,14 @@ - for information on - this system. - -+Radisys Corp. Tulsa -+CONFIG_SA1100_PFS168 -+ The Radisys Corp. PFS-168 (aka Tulsa) is an IntelĀ® StrongArmĀ® SA-1110 based -+ computer which includes the SA-1111 Microprocessor Companion Chip and other -+ custom I/O designed to add connectivity and multimedia features for vending -+ and business machine applications. Say Y here if you require support for -+ this target. -+ - # Choice: cerf_ram - Cerf on-board RAM size - CONFIG_SA1100_CERF_8MB -@@ -25748,37 +25847,65 @@ - Say Y if you want support for the ARM920T processor. - Otherwise, say N. - --Support ARM1020 processor --CONFIG_CPU_ARM1020 -- The ARM1020 is the cached version of the ARM10 processor, -- with an addition of a floating-point unit. -+Support ARM922T processor -+CONFIG_CPU_ARM922T -+ The ARM922T is a version of the ARM920T, but with smaller -+ instruction and data caches. It is used in Altera's -+ Excalibur XA device family. - -- Say Y if you want support for the ARM1020 processor. -+ Say Y if you want support for the ARM922T processor. - Otherwise, say N. - --Disable I-Cache -+Disable instruction cache - CONFIG_CPU_ICACHE_DISABLE -- Say Y here to disable the processor instruction cache. Unless -- you have a reason not to or are unsure, say N. -+ Say Y here to disable the processor instruction cache. Unless -+ you have a reason to do this, say N. - --Disable D-Cache -+Disable data cache - CONFIG_CPU_DCACHE_DISABLE -- Say Y here to disable the processor data cache. Unless -- you have a reason not to or are unsure, say N. -+ Say Y here to disable the processor data cache. Unless -+ you have a reason to do this, say N. - --Force write through D-cache -+Use data cache in writethrough mode - CONFIG_CPU_DCACHE_WRITETHROUGH -- Say Y here to use the data cache in write-through mode. Unless you -- specifically require this or are unsure, say N. -+ Say Y here to use the data cache in writethough mode. Unless you -+ specifically require this, say N. -+ -+Support ARM1020 processor -+CONFIG_CPU_ARM1020 -+ The ARM1020 is the 32K cached version of the ARM10 processor, -+ with an addition of a floating-point unit. -+ -+ Say Y if you want support for the ARM1020 processor. -+ Otherwise, say N. -+ -+Support ARM1022 processor -+CONFIG_CPU_ARM1022 -+ The ARM1022E is the 16K cached version of the ARM10 processor, -+ with an addition of a floating-point unit. -+ -+ Say Y if you want support for the ARM1022 processor. -+ Otherwise, say N. - --Round robin I and D cache replacement algorithm -+Force round-robin cache line replacement - CONFIG_CPU_CACHE_ROUND_ROBIN -- Say Y here to use the predictable round-robin cache replacement -- policy. Unless you specifically require this or are unsure, say N. -+ Say Y here to force the caches to use a round-robin -+ algorithm when picking a cache line to evict. Unless you -+ specifically require this, say N. -+ -+Disable the write buffer -+CONFIG_CPU_WB_DISABLE -+ Say Y here to turn off the write buffer (if possible) -+ Unless you specifically require this, say N. Note that -+ not all ARM processors allow the write buffer to be -+ disabled. - - Disable branch prediction - CONFIG_CPU_BPREDICT_DISABLE -- Say Y here to disable branch prediction. If unsure, say N. -+ The ARM10 family of processors support branch prediction, -+ which can significantly speed up execution of loops. -+ Say Y here to disable branch prediction. Unless you -+ specifically require this, say N. - - Compressed boot loader in ROM/flash - CONFIG_ZBOOT_ROM -@@ -25825,6 +25952,11 @@ - Say Y here if you are using the inhand electronics OmniMeter. See - for details. - -+HP Laboratories BadgePAD 4 -+CONFIG_SA1100_BADGE4 -+ Say Y here if you want to build a kernel for the HP Laboratories -+ BadgePAD 4. -+ - Load kernel using Angel Debug Monitor - CONFIG_ANGELBOOT - Say Y if you plan to load the kernel using Angel, ARM Ltd's target -@@ -25837,6 +25969,15 @@ - board includes 2 serial ports, Ethernet, IRDA, and expansion headers. - It comes with 16 MB SDRAM and 8 MB flash ROM. - -+GUIDEA07 -+CONFIG_ARCH_GUIDEA07 -+ Say Y if you are using a GUIDE (A07) board. -+ -+ This board is based on the cs89712 processor and shares much common -+ hardware with the CDB89712 configuration. When you select this -+ option and the CDB89712 becomes enabled also, don't worry. It's -+ supposed to be that way. -+ - CLPS-711X internal ROM bootstrap - CONFIG_EP72XX_ROM_BOOT - If you say Y here, your CLPS711x-based kernel will use the bootstrap -@@ -25865,19 +26006,27 @@ - You may say N here if you are going to load the Acorn FPEmulator - early in the bootup. - -+Math emulation 80-bit support -+CONFIG_FPE_NWFPE_XP -+ Say Y to include 80-bit support in the kernel floating-point -+ emulator. Otherwise, only 32 and 64-bit support is compiled in. -+ Note that gcc does not generate 80-bit operations by default, -+ so in most cases this option only enlarges the size of the -+ floating point emulator without any good reason. -+ -+ You almost surely want to say N here. -+ - FastFPE math emulation - CONFIG_FPE_FASTFPE - Say Y here to include the FAST floating point emulator in the kernel. -- This is an experimental much faster emulator which has only 32 bit -+ This is an experimental much faster emulator which now also has full - precision for the mantissa. It does not support any exceptions. -- This makes it very simple, it is approximately 4-8 times faster than -- NWFPE. -+ It is very simple, and approximately 3-6 times faster than NWFPE. - -- It should be sufficient for most programs. It is definitely not -- suitable if you do scientific calculations that need double -- precision for iteration formulas that sum up lots of very small -- numbers. If you do not feel you need a faster FP emulation you -- should better choose NWFPE. -+ It should be sufficient for most programs. It may be not suitable -+ for scientific calculations, but you have to check this for yourself. -+ If you do not feel you need a faster FP emulation you should better -+ choose NWFPE. - - It is also possible to say M to build the emulator as a module - (fastfpe.o). But keep in mind that you should only load the FP -diff -urN linux-2.4.26/Documentation/arm/Porting linux-2.4.26-vrs1/Documentation/arm/Porting ---- linux-2.4.26/Documentation/arm/Porting 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/Documentation/arm/Porting 2004-02-22 17:29:23.000000000 +0000 -@@ -0,0 +1,135 @@ -+Taken from list archive at http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2001-July/004064.html -+ -+Initial definitions -+------------------- -+ -+The following symbol definitions rely on you knowing the translation that -+__virt_to_phys() does for your machine. This macro converts the passed -+virtual address to a physical address. Normally, it is simply: -+ -+ phys = virt - PAGE_OFFSET + PHYS_OFFSET -+ -+ -+Decompressor Symbols -+-------------------- -+ -+ZTEXTADDR -+ Start address of decompressor. There's no point in talking about -+ virtual or physical addresses here, since the MMU will be off at -+ the time when you call the decompressor code. You normally call -+ the kernel at this address to start it booting. This doesn't have -+ to be located in RAM, it can be in flash or other read-only or -+ read-write addressable medium. -+ -+ZBSSADDR -+ Start address of zero-initialised work area for the decompressor. -+ This must be pointing at RAM. The decompressor will zero initialise -+ this for you. Again, the MMU will be off. -+ -+ZRELADDR -+ This is the address where the decompressed kernel will be written, -+ and eventually executed. The following constraint must be valid: -+ -+ __virt_to_phys(TEXTADDR) == ZRELADDR -+ -+ The initial part of the kernel is carefully coded to be position -+ independent. -+ -+INITRD_PHYS -+ Physical address to place the initial RAM disk. Only relevant if -+ you are using the bootpImage stuff (which only works on the old -+ struct param_struct). -+ -+INITRD_VIRT -+ Virtual address of the initial RAM disk. The following constraint -+ must be valid: -+ -+ __virt_to_phys(INITRD_VIRT) == INITRD_PHYS -+ -+PARAMS_PHYS -+ Physical address of the struct param_struct or tag list, giving the -+ kernel various parameters about its execution environment. -+ -+ -+Kernel Symbols -+-------------- -+ -+PHYS_OFFSET -+ Physical start address of the first bank of RAM. -+ -+PAGE_OFFSET -+ Virtual start address of the first bank of RAM. During the kernel -+ boot phase, virtual address PAGE_OFFSET will be mapped to physical -+ address PHYS_OFFSET, along with any other mappings you supply. -+ This should be the same value as TASK_SIZE. -+ -+TASK_SIZE -+ The maximum size of a user process in bytes. Since user space -+ always starts at zero, this is the maximum address that a user -+ process can access+1. The user space stack grows down from this -+ address. -+ -+ Any virtual address below TASK_SIZE is deemed to be user process -+ area, and therefore managed dynamically on a process by process -+ basis by the kernel. I'll call this the user segment. -+ -+ Anything above TASK_SIZE is common to all processes. I'll call -+ this the kernel segment. -+ -+ (In other words, you can't put IO mappings below TASK_SIZE, and -+ hence PAGE_OFFSET). -+ -+TEXTADDR -+ Virtual start address of kernel, normally PAGE_OFFSET + 0x8000. -+ This is where the kernel image ends up. With the latest kernels, -+ it must be located at 32768 bytes into a 128MB region. Previous -+ kernels placed a restriction of 256MB here. -+ -+DATAADDR -+ Virtual address for the kernel data segment. Must not be defined -+ when using the decompressor. -+ -+VMALLOC_START -+VMALLOC_END -+ Virtual addresses bounding the vmalloc() area. There must not be -+ any static mappings in this area; vmalloc will overwrite them. -+ The addresses must also be in the kernel segment (see above). -+ Normally, the vmalloc() area starts VMALLOC_OFFSET bytes above the -+ last virtual RAM address (found using variable high_memory). -+ -+VMALLOC_OFFSET -+ Offset normally incorporated into VMALLOC_START to provide a hole -+ between virtual RAM and the vmalloc area. We do this to allow -+ out of bounds memory accesses (eg, something writing off the end -+ of the mapped memory map) to be caught. Normally set to 8MB. -+ -+Architecture Specific Macros -+---------------------------- -+ -+BOOT_MEM(pram,pio,vio) -+ `pram' specifies the physical start address of RAM. Must always -+ be present, and should be the same as PHYS_OFFSET. -+ -+ `pio' is the physical address of an 8MB region containing IO for -+ use with the debugging macros in arch/arm/kernel/debug-armv.S. -+ -+ `vio' is the virtual address of the 8MB debugging region. -+ -+ It is expected that the debugging region will be re-initialised -+ by the architecture specific code later in the code (via the -+ MAPIO function). -+ -+BOOT_PARAMS -+ Same as, and see PARAMS_PHYS. -+ -+FIXUP(func) -+ Machine specific fixups, run before memory subsystems have been -+ initialised. -+ -+MAPIO(func) -+ Machine specific function to map IO areas (including the debug -+ region above). -+ -+INITIRQ(func) -+ Machine specific function to initialise interrupts. -+ -diff -urN linux-2.4.26/Documentation/arm/mem_alignment linux-2.4.26-vrs1/Documentation/arm/mem_alignment ---- linux-2.4.26/Documentation/arm/mem_alignment 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/Documentation/arm/mem_alignment 2004-04-09 15:09:44.000000000 +0100 -@@ -0,0 +1,58 @@ -+Too many problems poped up because of unnoticed misaligned memory access in -+kernel code lately. Therefore the alignment fixup is now unconditionally -+configured in for SA11x0 based targets. According to Alan Cox, this is a -+bad idea to configure it out, but Russell King has some good reasons for -+doing so on some f***ed up ARM architectures like the EBSA110. However -+this is not the case on many design I'm aware of, like all SA11x0 based -+ones. -+ -+Of course this is a bad idea to rely on the alignment trap to perform -+unaligned memory access in general. If those access are predictable, you -+are better to use the macros provided by include/asm/unaligned.h. The -+alignment trap can fixup misaligned access for the exception cases, but at -+a high performance cost. It better be rare. -+ -+Now for user space applications, it is possible to configure the alignment -+trap to SIGBUS any code performing unaligned access (good for debugging bad -+code), or even fixup the access by software like for kernel code. The later -+mode isn't recommended for performance reasons (just think about the -+floating point emulation that works about the same way). Fix your code -+instead! -+ -+Please note that randomly changing the behaviour without good thought is -+real bad - it changes the behaviour of all unaligned instructions in user -+space, and might cause programs to fail unexpectedly. -+ -+To change the alignment trap behavior, simply echo a number into -+/proc/cpu/alignment. The number is made up from various bits: -+ -+bit behavior when set -+--- ----------------- -+ -+0 A user process performing an unaligned memory access -+ will cause the kernel to print a message indicating -+ process name, pid, pc, instruction, address, and the -+ fault code. -+ -+1 The kernel will attempt to fix up the user process -+ performing the unaligned access. This is of course -+ slow (think about the floating point emulator) and -+ not recommended for production use. -+ -+2 The kernel will send a SIGBUS signal to the user process -+ performing the unaligned access. -+ -+Note that not all combinations are supported - only values 0 through 5. -+(6 and 7 don't make sense). -+ -+For example, the following will turn on the warnings, but without -+fixing up or sending SIGBUS signals: -+ -+ echo 1 > /proc/cpu/alignment -+ -+You can also read the content of the same file to get statistical -+information on unaligned access occurrences plus the current mode of -+operation for user space code. -+ -+ -+Nicolas Pitre, Mar 13, 2001. Modified Russell King, Nov 30, 2001. -diff -urN linux-2.4.26/Documentation/arm/memory.txt linux-2.4.26-vrs1/Documentation/arm/memory.txt ---- linux-2.4.26/Documentation/arm/memory.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/Documentation/arm/memory.txt 2004-02-22 17:32:57.000000000 +0000 -@@ -0,0 +1,74 @@ -+ Kernel Memory Layout on ARM Linux -+ -+ Russell King -+ April 27, 2003 (2.5.68) -+ -+This document describes the virtual memory layout which the Linux -+kernel uses for ARM processors. It indicates which regions are -+free for platforms to use, and which are used by generic code. -+ -+The ARM CPU is capable of addressing a maximum of 4GB virtual memory -+space, and this must be shared between user space processes, the -+kernel, and hardware devices. -+ -+As the ARM architecture matures, it becomes necessary to reserve -+certain regions of VM space for use for new facilities; therefore -+this document may reserve more VM space over time. -+ -+Start End Use -+-------------------------------------------------------------------------- -+ffff8000 ffffffff copy_user_page / clear_user_page use. -+ For SA11xx and Xscale, this is used to -+ setup a minicache mapping. -+ -+ffff1000 ffff7fff Reserved. -+ Platforms must not use this address range. -+ -+ffff0000 ffff0fff CPU vector page. -+ The CPU vectors are mapped here if the -+ CPU supports vector relocation (control -+ register V bit.) -+ -+ffe00000 fffeffff Free for platform use, not recommended. -+ -+ffc00000 ffdfffff 2MB consistent memory mapping. -+ Memory returned by the consistent_alloc -+ low level function will be dynamically -+ mapped here. -+ -+ff000000 ffbfffff Free for platform use, not recommended. -+ -+VMALLOC_END ff000000 Free for platform use, recommended. -+ -+VMALLOC_START VMALLOC_END vmalloc() / ioremap() space. -+ Memory returned by vmalloc/ioremap will -+ be dynamically placed in this region. -+ VMALLOC_START may be based upon the value -+ of the high_memory variable. -+ -+PAGE_OFFSET high_memory Kernel direct-mapped RAM region. -+ This maps the platforms RAM, and typically -+ maps all platform RAM in a 1:1 relationship. -+ -+TASK_SIZE PAGE_OFFSET Kernel module space -+ Kernel modules inserted via insmod are -+ placed here using dynamic mappings. -+ -+00001000 TASK_SIZE User space mappings -+ Per-thread mappings are placed here via -+ the mmap() system call. -+ -+00000000 00000fff CPU vector page / null pointer trap -+ CPUs which do not support vector remapping -+ place their vector page here. NULL pointer -+ dereferences by both the kernel and user -+ space are also caught via this mapping. -+ -+Please note that mappings which collide with the above areas may result -+in a non-bootable kernel, or may cause the kernel to (eventually) panic -+at run time. -+ -+Since future CPUs may impact the kernel mapping layout, user programs -+must not access any memory which is not mapped inside their 0x0001000 -+to TASK_SIZE address range. If they wish to access these areas, they -+must set up their own mappings using open() and mmap(). -diff -urN linux-2.4.26/Documentation/cpufreq/core.txt linux-2.4.26-vrs1/Documentation/cpufreq/core.txt ---- linux-2.4.26/Documentation/cpufreq/core.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/Documentation/cpufreq/core.txt 2004-01-14 21:32:23.000000000 +0000 -@@ -0,0 +1,94 @@ -+ CPU frequency and voltage scaling code in the Linux(TM) kernel -+ -+ -+ L i n u x C P U F r e q -+ -+ C P U F r e q C o r e -+ -+ -+ Dominik Brodowski -+ David Kimdon -+ -+ -+ -+ Clock scaling allows you to change the clock speed of the CPUs on the -+ fly. This is a nice method to save battery power, because the lower -+ the clock speed, the less power the CPU consumes. -+ -+ -+Contents: -+--------- -+1. CPUFreq core and interfaces -+2. CPUFreq notifiers -+ -+1. General Information -+======================= -+ -+The CPUFreq core code is located in linux/kernel/cpufreq.c. This -+cpufreq code offers a standardized interface for the CPUFreq -+architecture drivers (those pieces of code that do actual -+frequency transitions), as well as to "notifiers". These are device -+drivers or other part of the kernel that need to be informed of -+policy changes (ex. thermal modules like ACPI) or of all -+frequency changes (ex. timing code) or even need to force certain -+speed limits (like LCD drivers on ARM architecture). Additionally, the -+kernel "constant" loops_per_jiffy is updated on frequency changes -+here. -+ -+Reference counting is done by cpufreq_get_cpu and cpufreq_put_cpu, -+which make sure that the cpufreq processor driver is correctly -+registered with the core, and will not be unloaded until -+cpufreq_put_cpu is called. -+ -+2. CPUFreq notifiers -+==================== -+ -+CPUFreq notifiers conform to the standard kernel notifier interface. -+See linux/include/linux/notifier.h for details on notifiers. -+ -+There are two different CPUFreq notifiers - policy notifiers and -+transition notifiers. -+ -+ -+2.1 CPUFreq policy notifiers -+---------------------------- -+ -+These are notified when a new policy is intended to be set. Each -+CPUFreq policy notifier is called three times for a policy transition: -+ -+1.) During CPUFREQ_ADJUST all CPUFreq notifiers may change the limit if -+ they see a need for this - may it be thermal considerations or -+ hardware limitations. -+ -+2.) During CPUFREQ_INCOMPATIBLE only changes may be done in order to avoid -+ hardware failure. -+ -+3.) And during CPUFREQ_NOTIFY all notifiers are informed of the new policy -+ - if two hardware drivers failed to agree on a new policy before this -+ stage, the incompatible hardware shall be shut down, and the user -+ informed of this. -+ -+The phase is specified in the second argument to the notifier. -+ -+The third argument, a void *pointer, points to a struct cpufreq_policy -+consisting of five values: cpu, min, max, policy and max_cpu_freq. min -+and max are the lower and upper frequencies (in kHz) of the new -+policy, policy the new policy, cpu the number of the affected CPU or -+CPUFREQ_ALL_CPUS for all CPUs; and max_cpu_freq the maximum supported -+CPU frequency. This value is given for informational purposes only. -+ -+ -+2.2 CPUFreq transition notifiers -+-------------------------------- -+ -+These are notified twice when the CPUfreq driver switches the CPU core -+frequency and this change has any external implications. -+ -+The second argument specifies the phase - CPUFREQ_PRECHANGE or -+CPUFREQ_POSTCHANGE. -+ -+The third argument is a struct cpufreq_freqs with the following -+values: -+cpu - number of the affected CPU or CPUFREQ_ALL_CPUS -+old - old frequency -+new - new frequency -diff -urN linux-2.4.26/Documentation/cpufreq/cpu-drivers.txt linux-2.4.26-vrs1/Documentation/cpufreq/cpu-drivers.txt ---- linux-2.4.26/Documentation/cpufreq/cpu-drivers.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/Documentation/cpufreq/cpu-drivers.txt 2004-01-14 21:32:23.000000000 +0000 -@@ -0,0 +1,210 @@ -+ CPU frequency and voltage scaling code in the Linux(TM) kernel -+ -+ -+ L i n u x C P U F r e q -+ -+ C P U D r i v e r s -+ -+ - information for developers - -+ -+ -+ Dominik Brodowski -+ -+ -+ -+ Clock scaling allows you to change the clock speed of the CPUs on the -+ fly. This is a nice method to save battery power, because the lower -+ the clock speed, the less power the CPU consumes. -+ -+ -+Contents: -+--------- -+1. What To Do? -+1.1 Initialization -+1.2 Per-CPU Initialization -+1.3 verify -+1.4 target or setpolicy? -+1.5 target -+1.6 setpolicy -+2. Frequency Table Helpers -+ -+ -+ -+1. What To Do? -+============== -+ -+So, you just got a brand-new CPU / chipset with datasheets and want to -+add cpufreq support for this CPU / chipset? Great. Here are some hints -+on what is neccessary: -+ -+ -+1.1 Initialization -+------------------ -+ -+First of all, in an __initcall level 7 or later (preferrably -+module_init() so that your driver is modularized) function check -+whether this kernel runs on the right CPU and the right chipset. If -+so, register a struct cpufreq_driver with the CPUfreq core using -+cpufreq_register_driver() -+ -+What shall this struct cpufreq_driver contain? -+ -+cpufreq_driver.name - The name of this driver. -+ -+cpufreq_driver.init - A pointer to the per-CPU initialization -+ function. -+ -+cpufreq_driver.verify - A pointer to a "verfication" funciton. -+ -+cpufreq_driver.setpolicy _or_ -+cpufreq_driver.target - See below on the differences. -+ -+And optionally -+ -+cpufreq_driver.exit - A pointer to a per-CPU cleanup function. -+ -+cpufreq_driver.attr - A pointer to a NULL-terminated list of -+ "struct freq_attr" which allow to -+ export values to sysfs. -+ -+ -+1.2 Per-CPU Initialization -+-------------------------- -+ -+Whenever a new CPU is registered with the device model, or after the -+cpufreq driver registers itself, the per-CPU initialization fucntion -+cpufreq_driver.init is called. It takes a struct cpufreq_policy -+*policy as argument. What to do now? -+ -+If necessary, activate the CPUfreq support on your CPU (unlock that -+register etc.). -+ -+Then, the driver must fill in the following values: -+ -+policy->cpuinfo.min_freq _and_ -+policy->cpuinfo.max_freq - the minimum and maximum frequency -+ (in kHz) which is supported by -+ this CPU -+policy->cpuinfo.transition_latency the time it takes on this CPU to -+ switch between two frequencies (if -+ appropriate, else specify -+ CPUFREQ_ETERNAL) -+ -+policy->cur The current operating frequency of -+ this CPU (if appropriate) -+policy->min, -+policy->max, -+policy->policy and, if neccessary, -+policy->governor must contain the "default policy" for -+ this CPU. A few moments later, -+ cpufreq_driver.verify and either -+ cpufreq_driver.setpolicy or -+ cpufreq_driver.target is called with -+ these values. -+ -+For setting some of these values, the frequency table helpers might be -+helpful. See the section 2 for more information on them. -+ -+ -+1.3 verify -+------------ -+ -+When the user decides a new policy (consisting of -+"policy,governor,min,max") shall be set, this policy must be validated -+so that incompatible values can be corrected. For verifying these -+values, a frequency table helper and/or the -+cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned -+int min_freq, unsigned int max_freq) function might be helpful. See -+section 2 for details on frequency table helpers. -+ -+You need to make sure that at least one valid frequency (or operating -+range) is within policy->min and policy->max. If necessary, increase -+policy->max fist, and only if this is no solution, decreas policy->min. -+ -+ -+1.4 target or setpolicy? -+---------------------------- -+ -+Most cpufreq drivers or even most cpu frequency scaling algorithms -+only allow the CPU to be set to one frequency. For these, you use the -+->target call. -+ -+Some cpufreq-capable processors switch the frequency between certain -+limits on their own. These shall use the ->setpolicy call -+ -+ -+1.4. target -+------------- -+ -+The target call has three arguments: struct cpufreq_policy *policy, -+unsigned int target_frequency, unsigned int relation. -+ -+The CPUfreq driver must set the new frequency when called here. The -+actual frequency must be determined using the following rules: -+ -+- keep close to "target_freq" -+- policy->min <= new_freq <= policy->max (THIS MUST BE VALID!!!) -+- if relation==CPUFREQ_REL_L, try to select a new_freq higher than or equal -+ target_freq. ("L for lowest, but no lower than") -+- if relation==CPUFREQ_REL_H, try to select a new_freq lower than or equal -+ target_freq. ("H for highest, but no higher than") -+ -+Here again the frequency table helper might assist you - see section 3 -+for details. -+ -+ -+1.5 setpolicy -+--------------- -+ -+The setpolicy call only takes a struct cpufreq_policy *policy as -+argument. You need to set the lower limit of the in-processor or -+in-chipset dynamic frequency switching to policy->min, the upper limit -+to policy->max, and -if supported- select a performance-oriented -+setting when policy->policy is CPUFREQ_POLICY_PERFORMANCE, and a -+powersaving-oriented setting when CPUFREQ_POLICY_POWERSAVE. Also check -+the reference implementation in arch/i386/kernel/cpu/cpufreq/longrun.c -+ -+ -+ -+2. Frequency Table Helpers -+========================== -+ -+As most cpufreq processors only allow for being set to a few specific -+frequencies, a "frequency table" with some functions might assist in -+some work of the processor driver. Such a "frequency table" consists -+of an array of struct cpufreq_freq_table entries, with any value in -+"index" you want to use, and the corresponding frequency in -+"frequency". At the end of the table, you need to add a -+cpufreq_freq_table entry with frequency set to CPUFREQ_TABLE_END. And -+if you want to skip one entry in the table, set the frequency to -+CPUFREQ_ENTRY_INVALID. The entries don't need to be in ascending -+order. -+ -+By calling cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, -+ struct cpufreq_frequency_table *table); -+the cpuinfo.min_freq and cpuinfo.max_freq values are detected, and -+policy->min and policy->max are set to the same values. This is -+helpful for the per-CPU initialization stage. -+ -+int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, -+ struct cpufreq_frequency_table *table); -+assures that at least one valid frequency is within policy->min and -+policy->max, and all other criteria are met. This is helpful for the -+->verify call. -+ -+int cpufreq_frequency_table_target(struct cpufreq_policy *policy, -+ struct cpufreq_frequency_table *table, -+ unsigned int target_freq, -+ unsigned int relation, -+ unsigned int *index); -+ -+is the corresponding frequency table helper for the ->target -+stage. Just pass the values to this function, and the unsigned int -+index returns the number of the frequency table entry which contains -+the frequency the CPU shall be set to. PLEASE NOTE: This is not the -+"index" which is in this cpufreq_table_entry.index, but instead -+cpufreq_table[index]. So, the new frequency is -+cpufreq_table[index].frequency, and the value you stored into the -+frequency table "index" field is -+cpufreq_table[index].index. -+ -diff -urN linux-2.4.26/Documentation/cpufreq/governors.txt linux-2.4.26-vrs1/Documentation/cpufreq/governors.txt ---- linux-2.4.26/Documentation/cpufreq/governors.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/Documentation/cpufreq/governors.txt 2004-01-14 21:32:23.000000000 +0000 -@@ -0,0 +1,155 @@ -+ CPU frequency and voltage scaling code in the Linux(TM) kernel -+ -+ -+ L i n u x C P U F r e q -+ -+ C P U F r e q G o v e r n o r s -+ -+ - information for users and developers - -+ -+ -+ Dominik Brodowski -+ -+ -+ -+ Clock scaling allows you to change the clock speed of the CPUs on the -+ fly. This is a nice method to save battery power, because the lower -+ the clock speed, the less power the CPU consumes. -+ -+ -+Contents: -+--------- -+1. What is a CPUFreq Governor? -+ -+2. Governors In the Linux Kernel -+2.1 Performance -+2.2 Powersave -+2.3 Userspace -+ -+3. The Governor Interface in the CPUfreq Core -+ -+ -+ -+1. What Is A CPUFreq Governor? -+============================== -+ -+Most cpufreq drivers (in fact, all except one, longrun) or even most -+cpu frequency scaling algorithms only offer the CPU to be set to one -+frequency. In order to offer dynamic frequency scaling, the cpufreq -+core must be able to tell these drivers of a "target frequency". So -+these specific drivers will be transformed to offer a "->target" -+call instead of the existing "->setpolicy" call. For "longrun", all -+stays the same, though. -+ -+How to decide what frequency within the CPUfreq policy should be used? -+That's done using "cpufreq governors". Two are already in this patch -+-- they're the already existing "powersave" and "performance" which -+set the frequency statically to the lowest or highest frequency, -+respectively. At least two more such governors will be ready for -+addition in the near future, but likely many more as there are various -+different theories and models about dynamic frequency scaling -+around. Using such a generic interface as cpufreq offers to scaling -+governors, these can be tested extensively, and the best one can be -+selected for each specific use. -+ -+Basically, it's the following flow graph: -+ -+CPU can be set to switch independetly | CPU can only be set -+ within specific "limits" | to specific frequencies -+ -+ "CPUfreq policy" -+ consists of frequency limits (policy->{min,max}) -+ and CPUfreq governor to be used -+ / \ -+ / \ -+ / the cpufreq governor decides -+ / (dynamically or statically) -+ / what target_freq to set within -+ / the limits of policy->{min,max} -+ / \ -+ / \ -+ Using the ->setpolicy call, Using the ->target call, -+ the limits and the the frequency closest -+ "policy" is set. to target_freq is set. -+ It is assured that it -+ is within policy->{min,max} -+ -+ -+2. Governors In the Linux Kernel -+================================ -+ -+2.1 Performance -+--------------- -+ -+The CPUfreq governor "performance" sets the CPU statically to the -+highest frequency within the borders of scaling_min_freq and -+scaling_max_freq. -+ -+ -+2.1 Powersave -+------------- -+ -+The CPUfreq governor "powersave" sets the CPU statically to the -+lowest frequency within the borders of scaling_min_freq and -+scaling_max_freq. -+ -+ -+2.2 Userspace -+------------- -+ -+The CPUfreq governor "userspace" allows the user, or any userspace -+program running with UID "root", to set the CPU to a specifc frequency -+by making a sysfs file "scaling_setspeed" available in the CPU-device -+directory. -+ -+ -+ -+3. The Governor Interface in the CPUfreq Core -+============================================= -+ -+A new governor must register itself with the CPUfreq core using -+"cpufreq_register_governor". The struct cpufreq_governor, which has to -+be passed to that function, must contain the following values: -+ -+governor->name - A unique name for this governor -+governor->governor - The governor callback function -+governor->owner - .THIS_MODULE for the governor module (if -+ appropriate) -+ -+The governor->governor callback is called with the current (or to-be-set) -+cpufreq_policy struct for that CPU, and an unsigned int event. The -+following events are currently defined: -+ -+CPUFREQ_GOV_START: This governor shall start its duty for the CPU -+ policy->cpu -+CPUFREQ_GOV_STOP: This governor shall end its duty for the CPU -+ policy->cpu -+CPUFREQ_GOV_LIMITS: The limits for CPU policy->cpu have changed to -+ policy->min and policy->max. -+ -+If you need other "events" externally of your driver, _only_ use the -+cpufreq_governor_l(unsigned int cpu, unsigned int event) call to the -+CPUfreq core to ensure proper locking. -+ -+ -+The CPUfreq governor may call the CPU processor driver using one of -+these two functions: -+ -+inline int cpufreq_driver_target(struct cpufreq_policy *policy, -+ unsigned int target_freq, -+ unsigned int relation); -+ -+inline int cpufreq_driver_target_l(struct cpufreq_policy *policy, -+ unsigned int target_freq, -+ unsigned int relation); -+ -+target_freq must be within policy->min and policy->max, of course. -+What's the difference between these two functions? When your governor -+still is in a direct code path of a call to governor->governor, the -+cpufreq_driver_sem lock is still held in the cpufreq core, and there's -+no need to lock it again (in fact, this would cause a deadlock). So -+use cpufreq_driver_target only in these cases. In all other cases (for -+example, when there's a "daemonized" function that wakes up every -+second), use cpufreq_driver_target_l to lock the cpufreq_driver_sem -+before the command is passed to the cpufreq processor driver. -+ -diff -urN linux-2.4.26/Documentation/cpufreq/index.txt linux-2.4.26-vrs1/Documentation/cpufreq/index.txt ---- linux-2.4.26/Documentation/cpufreq/index.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/Documentation/cpufreq/index.txt 2004-01-14 21:32:23.000000000 +0000 -@@ -0,0 +1,56 @@ -+ CPU frequency and voltage scaling code in the Linux(TM) kernel -+ -+ -+ L i n u x C P U F r e q -+ -+ -+ -+ -+ Dominik Brodowski -+ -+ -+ -+ Clock scaling allows you to change the clock speed of the CPUs on the -+ fly. This is a nice method to save battery power, because the lower -+ the clock speed, the less power the CPU consumes. -+ -+ -+ -+Documents in this directory: -+---------------------------- -+core.txt - General description of the CPUFreq core and -+ of CPUFreq notifiers -+ -+cpu-drivers.txt - How to implement a new cpufreq processor driver -+ -+governors.txt - What are cpufreq governors and how to -+ implement them? -+ -+index.txt - File index, Mailing list and Links (this document) -+ -+user-guide.txt - User Guide to CPUFreq -+ -+ -+Mailing List -+------------ -+There is a CPU frequency changing CVS commit and general list where -+you can report bugs, problems or submit patches. To post a message, -+send an email to cpufreq@www.linux.org.uk, to subscribe go to -+http://www.linux.org.uk/mailman/listinfo/cpufreq. Previous post to the -+mailing list are available to subscribers at -+http://www.linux.org.uk/mailman/private/cpufreq/. -+ -+ -+Links -+----- -+the FTP archives: -+* ftp://ftp.linux.org.uk/pub/linux/cpufreq/ -+ -+how to access the CVS repository: -+* http://cvs.arm.linux.org.uk/ -+ -+the CPUFreq Mailing list: -+* http://www.linux.org.uk/mailman/listinfo/cpufreq -+ -+Clock and voltage scaling for the SA-1100: -+* http://www.lart.tudelft.nl/projects/scaling -diff -urN linux-2.4.26/Documentation/cpufreq/user-guide.txt linux-2.4.26-vrs1/Documentation/cpufreq/user-guide.txt ---- linux-2.4.26/Documentation/cpufreq/user-guide.txt 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/Documentation/cpufreq/user-guide.txt 2004-01-14 21:32:23.000000000 +0000 -@@ -0,0 +1,166 @@ -+ CPU frequency and voltage scaling code in the Linux(TM) kernel -+ -+ -+ L i n u x C P U F r e q -+ -+ U S E R G U I D E -+ -+ -+ Dominik Brodowski -+ -+ -+ -+ Clock scaling allows you to change the clock speed of the CPUs on the -+ fly. This is a nice method to save battery power, because the lower -+ the clock speed, the less power the CPU consumes. -+ -+ -+Contents: -+--------- -+1. Supported Architectures and Processors -+1.1 ARM -+1.2 x86 -+1.3 sparc64 -+ -+2. "Policy" / "Governor"? -+2.1 Policy -+2.2 Governor -+ -+3. How to change the CPU cpufreq policy and/or speed -+3.1 Preferred interface: sysfs -+3.2 Deprecated interfaces -+ -+ -+ -+1. Supported Architectures and Processors -+========================================= -+ -+1.1 ARM -+------- -+ -+The following ARM processors are supported by cpufreq: -+ -+ARM Integrator -+ARM-SA1100 -+ARM-SA1110 -+ -+ -+1.2 x86 -+------- -+ -+The following processors for the x86 architecture are supported by cpufreq: -+ -+AMD Elan - SC400, SC410 -+AMD mobile K6-2+ -+AMD mobile K6-3+ -+Cyrix Media GXm -+Intel mobile PIII [*] and Intel mobile PIII-M on certain chipsets -+Intel Pentium 4, Intel Xeon -+National Semiconductors Geode GX -+Transmeta Crusoe -+varios processors on some ACPI 2.0-compatible systems [**] -+ -+[*] only certain Intel mobile PIII processors are supported. If you -+know that you own a speedstep-capable processor, pass the option -+"speedstep_coppermine=1" to the module speedstep.o -+ -+[**] Only if "ACPI Processor Performance States" are available -+to the ACPI<->BIOS interface. -+ -+ -+1.3 sparc64 -+----------- -+ -+The following processors for the sparc64 architecture are supported by -+cpufreq: -+ -+UltraSPARC-III -+ -+ -+ -+2. "Policy" / "Governor" ? -+========================== -+ -+Some CPU frequency scaling-capable processor switch between varios -+frequencies and operating voltages "on the fly" without any kernel or -+user involvement. This guarantuees very fast switching to a frequency -+which is high enough to serve the user's needs, but low enough to save -+power. -+ -+ -+2.1 Policy -+---------- -+ -+On these systems, all you can do is select the lower and upper -+frequency limit as well as whether you want more aggressive -+power-saving or more instantly avaialble processing power. -+ -+ -+2.2 Governor -+------------ -+ -+On all other cpufreq implementations, these boundaries still need to -+be set. Then, a "governor" must be selected. Such a "governor" decides -+what speed the processor shall run within the boundaries. One such -+"governor" is the "userspace" governor. This one allows the user - or -+a yet-to-implement userspace program - to decide what specific speed -+the processor shall run at. -+ -+ -+3. How to change the CPU cpufreq policy and/or speed -+==================================================== -+ -+3.1 Preferred Interface: sysfs -+------------------------------ -+ -+The preferred interface is located in the sysfs filesystem. If you -+mounted it at /sys, the cpufreq interface is located in a subdirectory -+"cpufreq" within the cpu-device directory -+(e.g. /sys/devices/sys/cpu0/cpufreq/ for the first CPU). -+ -+cpuinfo_min_freq : this file shows the minimum operating -+ frequency the processor can run at(in kHz) -+cpuinfo_max_freq : this file shows the maximum operating -+ frequency the processor can run at(in kHz) -+scaling_driver : this file shows what cpufreq driver is -+ used to set the frequency on this CPU -+ -+scaling_available_governors : this file shows the CPUfreq governors -+ available in this kernel. You can see the -+ currently activated governor in -+ -+scaling_governor, and by "echoing" the name of another -+ governor you can change it. Please note -+ that some governors won't load - they only -+ work on some specific architectures or -+ processors. -+scaling_min_freq and -+scaling_max_freq show the current "policy limits" (in -+ kHz). By echoing new values into these -+ files, you can change these limits. -+ -+ -+If you have selected the "userspace" governor which allows you to -+set the CPU operating frequency to a specific value, you can read out -+the current frequency in -+ -+scaling_setspeed. By "echoing" a new frequency into this -+ you can change the speed of the CPU, -+ but only within the limits of -+ scaling_min_freq and scaling_max_freq. -+ -+ -+3.2 Deprecated Interfaces -+------------------------- -+ -+Depending on your kernel configuration, you might find the following -+cpufreq-related files: -+/proc/cpufreq -+/proc/sys/cpu/*/speed -+/proc/sys/cpu/*/speed-min -+/proc/sys/cpu/*/speed-max -+ -+These are files for deprecated interfaces to cpufreq, which offer far -+less functionality. Because of this, these interfaces aren't described -+here. -+ -diff -urN linux-2.4.26/Documentation/cpufreq-old linux-2.4.26-vrs1/Documentation/cpufreq-old ---- linux-2.4.26/Documentation/cpufreq-old 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/Documentation/cpufreq-old 2004-01-14 21:32:23.000000000 +0000 -@@ -0,0 +1,332 @@ -+ CPU frequency and voltage scaling code in the Linux(TM) kernel -+ -+ -+ L i n u x C P U F r e q -+ -+ -+ -+ -+ Dominik Brodowski -+ -+ -+ -+ Clock scaling allows you to change the clock speed of the CPUs on the -+ fly. This is a nice method to save battery power, because the lower -+ the clock speed, the less power the CPU consumes. -+ -+ -+ -+Contents: -+--------- -+1. Supported architectures -+2. User interface -+2.1 Sample script for command line interface -+3. CPUFreq core and interfaces -+3.1 General information -+3.2 CPUFreq notifiers -+3.3 CPUFreq architecture drivers -+4. Mailing list and Links -+ -+ -+ -+1. Supported architectures -+========================== -+ -+Some architectures detect the lowest and highest possible speed -+settings, while others rely on user information on this. For the -+latter, a boot parameter is required, for the former, you can specify -+one to set the limits between speed settings may occur. -+The boot parameter has the following syntax: -+ -+ cpufreq=minspeed-maxspeed -+ -+with both minspeed and maxspeed being given in kHz. To set the lower -+limit to 59 MHz and the upper limit to 221 MHz, specify: -+ -+ cpufreq=59000-221000 -+ -+Check the "Speed Limits Detection" information below on whether -+the driver detects the lowest and highest allowed speed setting -+automatically. -+ -+ -+ARM Integrator: -+ SA 1100, SA1110 -+-------------------------------- -+ Speed Limits Detection: On Integrators, the minimum speed is set -+ and the maximum speed has to be specified using the boot -+ parameter. On SA11x0s, the frequencies are fixed (59 - 287 MHz) -+ -+ -+AMD Elan: -+ SC400, SC410 -+-------------------------------- -+ Speed Limits Detection: Not implemented. You need to specify the -+ minimum and maximum frequency in the boot parameter (see above). -+ -+ -+VIA Cyrix Longhaul: -+ VIA Samuel/CyrixIII, VIA Cyrix Samuel/C3, -+ VIA Cyrix Ezra, VIA Cyrix Ezra-T -+-------------------------------- -+ Speed Limits Detection: working. No need for boot parameters. -+ NOTE: Support for certain processors is currently disabled, -+ waiting on updated docs from VIA. -+ -+ -+Intel SpeedStep: -+ certain mobile Intel Pentium III (Coppermine), and all mobile -+ Intel Pentium III-M (Tulatin) and mobile Intel Pentium 4 P4-Ms. -+-------------------------------- -+ Speed Limits Detection: working. No need for boot parameters. -+ NOTE: -+ 1.) mobile Intel Pentium III (Coppermine): -+ The SpeedStep interface may only be used on SpeedStep -+ capable processors. Unforunately, due to lack of documentation, -+ such detection is not yet possible on mobile Intel PIII -+ (Coppermine) processors. In order to activate SpeedStep on such a -+ processor, you have to remove one line manually in -+ linux/drivers/arch/i386/speedstep.c -+ -+ -+P4 CPU Clock Modulation: -+ Intel Pentium 4 Xeon processors -+-------------------------------- -+ Speed Limits Detection: Not implemented. You need to specify the -+ minimum and maximum frequency in the boot parameter (see above). -+ -+ -+ -+2. User Interface -+================= -+ -+CPUFreq uses a "sysctl" interface which is located in -+ /proc/sys/cpu/0/ on UP (uniprocessor) kernels, or -+ /proc/sys/cpu/any/ on SMP (symmetric multiprocessoring) kernels. -+ -+ -+In this directory, you will find three files of importance for -+CPUFreq: speed-max, speed-min, and speed: -+ -+speed shows the current CPU frequency in kHz, -+speed-min the minimal supported CPU frequency, and -+speed-max the maximal supported CPU frequency. -+ -+Please note that you might have to specify these limits as a boot -+parameter depending on the architecture (see above). -+ -+ -+To change the CPU frequency, "echo" the desired CPU frequency (in kHz) -+to speed. For example, to set the CPU speed to the lowest/highest -+allowed frequency do: -+ -+root@notebook:# cat /proc/sys/cpu/0/speed-min > /proc/sys/cpu/0/speed -+root@notebook:# cat /proc/sys/cpu/0/speed-max > /proc/sys/cpu/0/speed -+ -+ -+2.1 Sample script for command line interface -+********************************************** -+ -+ -+Michael Ossmann has written a small command line -+interface for the infinitely lazy. -+ -+#!/bin/bash -+# -+# /usr/local/bin/freq -+# simple command line interface to cpufreq -+ -+[ -n "$1" ] && case "$1" in -+ "min" ) -+ # set frequency to minimum -+ cat /proc/sys/cpu/0/speed-min >/proc/sys/cpu/0/speed -+ ;; -+ "max" ) -+ # set frequency to maximum -+ cat /proc/sys/cpu/0/speed-max >/proc/sys/cpu/0/speed -+ ;; -+ * ) -+ echo "Usage: $0 [min|max]" -+ echo " min: set frequency to minimum and display new frequency" -+ echo " max: set frequency to maximum and display new frequency" -+ echo " no options: display current frequency" -+ exit 1 -+ ;; -+esac -+ -+# display current frequency -+cat /proc/sys/cpu/0/speed -+exit 0 -+ -+ -+ -+3. CPUFreq core and interfaces -+=============================== -+ -+3.1 General information -+************************* -+ -+The CPUFreq core code is located in linux/kernel/cpufreq.c. This -+cpufreq code offers a standardized interface for the CPUFreq -+architecture drivers (those pieces of code that do the actual -+frequency transition), as well as to "notifiers". These are device -+drivers or other part of the kernel that need to be informed of -+frequency changes (like timing code) or even need to force certain -+speed limits (like LCD drivers on ARM architecture). Aditionally, the -+kernel "constant" loops_per_jiffy is updated on frequency changes -+here. -+ -+ -+3.2 CPUFreq notifiers -+*********************** -+ -+CPUFreq notifiers are kernel code that need to be called to either -+a) define certain minimum or maximum speed settings, -+b) be informed of frequency changes in advance of the transition, or -+c) be informed of frequency changes directly after the transition. -+ -+A standard kernel notifier interface is offered for this. See -+linux/include/linux/notifier.h for details on notifiers. -+ -+ -+Data and value passed to CPUFreq notifiers -+------------------------------------------ -+The second argument passed to any notifier is an unsigned int stating -+the phase of the transition: -+CPUFREQ_MINMAX during the process of determing a valid new CPU -+ frequency, -+CPUFREQ_PRECHANGE right before the transition, and -+CPUFREQ_POSTCHANGE right after the transition. -+ -+The third argument, a void *pointer, points to a struct -+cpufreq_freqs. This consists of four values: min, max, cur and new. -+ -+min and max are the current speed limits. Please note: Never update -+these values directly, use cpufreq_updateminmax(struct cpufreq_freqs -+*freqs, unsigned int min, unsigned int max) instead. cur is the -+current/old speed, and new is the new speed, but might only be valid -+on CPUFREQ_PRECHANGE or CPUFREQ_POSTCHANGE. -+ -+Each notifier gets called all three times on any transition: -+ -+CPUFREQ_MINMAX -+Here the notifier is supposed to update the min and max values to the -+limits the protected device / kernel code needs. As stated above, -+always use cpufreq_updateminmax for this. -+ -+CPUFREQ_PRECHANGE -+CPUFREQ_POSTCHANGE -+Here the notifier is supposed to update all internal (e.g. device -+driver) code which is dependend on the CPU frequency. -+ -+ -+3.3 CPUFreq architecture drivers -+********************************** -+ -+CPUFreq architecture drivers are the pieces of kernel code that -+actually perform CPU frequency transitions. These need to be -+initialised separately (separate initcalls), and may be -+modularized. They interact with the CPUFreq core in the following way: -+ -+ -+cpufreq_register() -+------------------ -+cpufreq_register registers an arch driver to the CPUFreq core. Please -+note that only one arch driver may be registered at any time, -EBUSY -+is returned when an arch driver is already registered. The argument to -+cpufreq_register, cpufreq_driver_t driver, is described later. -+ -+ -+cpufreq_unregister() -+-------------------- -+cpufreq_unregister unregisters an arch driver, e.g. on module -+unloading. Please note that there is no check done that this is called -+from the driver which actually registered itself to the core, so -+please only call this function when you are sure the arch driver got -+registered correctly before. -+ -+ -+struct cpufreq_driver -+---------------- -+On initialisation, the arch driver is supposed to pass the following -+entries in struct cpufreq_driver cpufreq_driver: -+ -+cpufreq_verify_t validate: This is a pointer to a function with the -+following definition: -+ unsigned int validating_function (unsigned int kHz). -+It is called right before a transition occurs. The proposed new -+speed setting is passed as an argument in kHz; the validating code -+should verify this is a valid speed setting which is currently -+supported by the CPU. It shall return the closest valid CPU frequency -+in kHz. -+ -+cpufreq_setspeed_t setspeed: This is a pointer to a function with the -+following definition: -+ void setspeed_function (unsigned int kHz). -+This function shall perform the transition to the new CPU frequency -+given as argument in kHz. Note that this argument is exactly the same -+as the one returned by cpufreq_verify_t validate. -+ -+ -+unsigned int freq.cur: The current CPU core frequency. Note that this -+is a requirement while the next two entries are optional. -+ -+ -+unsigned int freq.min (optional): The minimal CPU core frequency this -+CPU supports. This value may be limited further by the -+cpufreq_verify_t validate function, and so this value should be the -+minimal core frequency allowed "theoretically" on this system in this -+configuration. -+ -+ -+unsigned int freq.max (optional): The maximum CPU core frequency this -+CPU supports. This value may be limited further by the -+cpufreq_verify_t validate function, and so this value should be the -+maximum core frequency allowed "theoretically" on this system in this -+configuration. -+ -+ -+Some Requirements to CPUFreq architecture drivers -+------------------------------------------------- -+* Only call cpufreq_register() when the ability to switch CPU -+ frequencies is _verified_ or can't be missing -+* cpufreq_unregister() may only be called if cpufreq_register() has -+ been successfully(!) called before -+* All CPUs have to be set to the same speed whenever setspeed() is -+ called -+* Be aware that there is currently no error management in the -+ setspeed() code in the CPUFreq core. So only call yourself a -+ cpufreq_driver if you are really a working cpufreq_driver! -+ -+ -+ -+4. Mailing list and Links -+************************** -+ -+ -+Mailing List -+------------ -+There is a CPU frequency changing CVS commit and general list where -+you can report bugs, problems or submit patches. To post a message, -+send an email to cpufreq@www.linux.org.uk, to subscribe go to -+http://www.linux.org.uk/mailman/listinfo/cpufreq. Previous post to the -+mailing list are available to subscribers at -+http://www.linux.org.uk/mailman/private/cpufreq/. -+ -+ -+Links -+----- -+the FTP archives: -+* ftp://ftp.linux.org.uk/pub/linux/cpufreq/ -+ -+how to access the CVS repository: -+* http://www.arm.linux.org.uk/cvs/ -+ -+the CPUFreq Mailing list: -+* http://www.linux.org.uk/mailman/listinfo/cpufreq -+ -+Clock and voltage scaling for the SA-1100: -+* http://www.lart.tudelft.nl/projects/scaling -+ -+CPUFreq project homepage -+* http://www.brodo.de/cpufreq/ -diff -urN linux-2.4.26/Documentation/l3/structure linux-2.4.26-vrs1/Documentation/l3/structure ---- linux-2.4.26/Documentation/l3/structure 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/Documentation/l3/structure 2004-01-14 21:32:23.000000000 +0000 -@@ -0,0 +1,36 @@ -+L3 Bus Driver -+------------- -+ -+The structure of the driver is as follows: -+ -+ +----------+ +----------+ +----------+ -+ | client 1 | | client 2 | | client 3 | -+ +-----^----+ +----^-----+ +----^-----+ -+ | | | -+ +-----v--------------v---------------v-----+ -+ | | -+ +-----^-------+ +-------^-----+ -+ | | core | | -+ +-----v----+ | | +----v-----+ -+ | device | | | | device | -+ | driver 1 | | | | driver 2 | -+ +-----^----+ | | +----^-----+ -+ | | services | | -+ +-----v-------+ +-------v-----+ -+ | | -+ +-----------------^----^-------------------+ -+ | | -+ | +-v---------+ -+ | | algorithm | -+ | | driver | -+ | +-v---------+ -+ | | -+ +-v----v-+ -+ | bus | -+ | driver | -+ +--------+ -+ -+Clients talk to the core to attach device drivers and bus adapters, and -+to instruct device drivers to perform actions. Device drivers then talk -+to the core to perform L3 bus transactions via the algorithm driver and -+ultimately bus driver. -diff -urN linux-2.4.26/Documentation/serial/driver linux-2.4.26-vrs1/Documentation/serial/driver ---- linux-2.4.26/Documentation/serial/driver 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/Documentation/serial/driver 2004-01-14 21:32:23.000000000 +0000 -@@ -0,0 +1,208 @@ -+ -+ Low Level Serial API -+ -------------------- -+ -+ -+ $Id: driver,v 1.3 2001/11/24 23:24:47 rmk Exp $ -+ -+ -+This document is meant as a brief overview of some aspects of the new serial -+driver. It is not complete, any questions you have should be directed to -+ -+ -+The reference implementation is contained within serial_amba.c. -+ -+ -+ -+Low Level Serial Hardware Driver -+-------------------------------- -+ -+The low level serial hardware driver is responsible for supplying port -+information (defined by uart_port) and a set of control methods (defined -+by uart_ops) to the core serial driver. The low level driver is also -+responsible for handling interrupts for the port, and providing any -+console support. -+ -+ -+Console Support -+--------------- -+ -+The serial core provides a few helper functions. This includes identifing -+the correct port structure (via uart_get_console) and decoding command line -+arguments (uart_parse_options). -+ -+ -+Locking -+------- -+ -+Generally, all locking is done by the core driver, except for the interrupt -+functions. It is the responsibility of the low level hardware driver to -+perform the necessary locking there using info->lock. (since it is running -+in an interrupt, you only need to use spin_lock() and spin_unlock() from -+the interrupt handler). -+ -+ -+uart_ops -+-------- -+ -+The uart_ops structure is the main interface between serial_core and the -+hardware specific driver. It contains all the methods to control the -+hardware. -+ -+ tx_empty(port) -+ This function tests whether the transmitter fifo and shifter -+ for the port described by 'port' is empty. If it is empty, -+ this function should return TIOCSER_TEMT, otherwise return 0. -+ If the port does not support this operation, then it should -+ return TIOCSER_TEMT. -+ -+ set_mctrl(port, mctrl) -+ This function sets the modem control lines for port described -+ by 'port' to the state described by mctrl. The relevant bits -+ of mctrl are: -+ - TIOCM_RTS RTS signal. -+ - TIOCM_DTR DTR signal. -+ - TIOCM_OUT1 OUT1 signal. -+ - TIOCM_OUT2 OUT2 signal. -+ If the appropriate bit is set, the signal should be driven -+ active. If the bit is clear, the signal should be driven -+ inactive. -+ -+ get_mctrl(port) -+ Returns the current state of modem control inputs. The state -+ of the outputs should not be returned, since the core keeps -+ track of their state. The state information should include: -+ - TIOCM_DCD state of DCD signal -+ - TIOCM_CTS state of CTS signal -+ - TIOCM_DSR state of DSR signal -+ - TIOCM_RI state of RI signal -+ The bit is set if the signal is currently driven active. If -+ the port does not support CTS, DCD or DSR, the driver should -+ indicate that the signal is permanently active. If RI is -+ not available, the signal should not be indicated as active. -+ -+ stop_tx(port,from_tty) -+ Stop transmitting characters. This might be due to the CTS -+ line becoming inactive or the tty layer indicating we want -+ to stop transmission. -+ -+ start_tx(port,nonempty,from_tty) -+ start transmitting characters. (incidentally, nonempty will -+ always be nonzero, and shouldn't be used - it will be dropped). -+ -+ stop_rx(port) -+ Stop receiving characters; the port is in the process of -+ being closed. -+ -+ enable_ms(port) -+ Enable the modem status interrupts. -+ -+ break_ctl(port,ctl) -+ Control the transmission of a break signal. If ctl is -+ nonzero, the break signal should be transmitted. The signal -+ should be terminated when another call is made with a zero -+ ctl. -+ -+ startup(port,info) -+ Grab any interrupt resources and initialise any low level driver -+ state. Enable the port for reception. It should not activate -+ RTS nor DTR; this will be done via a separate call to set_mctrl. -+ -+ shutdown(port,info) -+ Disable the port, disable any break condition that may be in -+ effect, and free any interrupt resources. It should not disable -+ RTS nor DTR; this will have already been done via a separate -+ call to set_mctrl. -+ -+ change_speed(port,cflag,iflag,quot) -+ Change the port parameters, including word length, parity, stop -+ bits. Update read_status_mask and ignore_status_mask to indicate -+ the types of events we are interested in receiving. Relevant -+ cflag bits are: -+ CSIZE - word size -+ CSTOPB - 2 stop bits -+ PARENB - parity enable -+ PARODD - odd parity (when PARENB is in force) -+ CREAD - enable reception of characters (if not set, -+ still receive characters from the port, but -+ throw them away. -+ CRTSCTS - if set, enable CTS status change reporting -+ CLOCAL - if not set, enable modem status change -+ reporting. -+ Relevant iflag bits are: -+ INPCK - enable frame and parity error events to be -+ passed to the TTY layer. -+ BRKINT -+ PARMRK - both of these enable break events to be -+ passed to the TTY layer. -+ -+ IGNPAR - ignore parity and framing errors -+ IGNBRK - ignore break errors, If IGNPAR is also -+ set, ignore overrun errors as well. -+ The interaction of the iflag bits is as follows (parity error -+ given as an example): -+ Parity error INPCK IGNPAR -+ None n/a n/a character received -+ Yes n/a 0 character discarded -+ Yes 0 1 character received, marked as -+ TTY_NORMAL -+ Yes 1 1 character received, marked as -+ TTY_PARITY -+ -+ pm(port,state,oldstate) -+ perform any power management related activities on the specified -+ port. state indicates the new state (defined by ACPI D0-D3), -+ oldstate indicates the previous state. Essentially, D0 means -+ fully on, D3 means powered down. -+ -+ This function should not be used to grab any resources. -+ -+ type(port) -+ Return a pointer to a string constant describing the specified -+ port, or return NULL, in which case the string 'unknown' is -+ substituted. -+ -+ release_port(port) -+ Release any memory and IO region resources currently in use by -+ the port. -+ -+ request_port(port) -+ Request any memory and IO region resources required by the port. -+ If any fail, no resources should be registered when this function -+ returns, and it should return -EBUSY on failure. -+ -+ config_port(port,type) -+ Perform any autoconfiguration steps required for the port. `type` -+ contains a bit mask of the required configuration. UART_CONFIG_TYPE -+ indicates that the port requires detection and identification. -+ port->type should be set to the type found, or PORT_UNKNOWN if -+ no port was detected. -+ -+ UART_CONFIG_IRQ indicates autoconfiguration of the interrupt signal, -+ which should be probed using standard kernel autoprobing techniques. -+ This is not necessary on platforms where ports have interrupts -+ internally hard wired (eg, system on a chip implementations). -+ -+ verify_port(port,serinfo) -+ Verify the new serial port information contained within serinfo is -+ suitable for this port type. -+ -+ ioctl(port,cmd,arg) -+ Perform any port specific IOCTLs. IOCTL commands must be defined -+ using the standard numbering system found in -+ -+ -+Other notes -+----------- -+ -+It is intended some day to drop the 'unused' entries from uart_port, and -+allow low level drivers to register their own individual uart_port's with -+the core. This will allow drivers to use uart_port as a pointer to a -+structure containing both the uart_port entry with their own extensions, -+thus: -+ -+ struct my_port { -+ struct uart_port port; -+ int my_stuff; -+ }; -+ -diff -urN linux-2.4.26/MAINTAINERS linux-2.4.26-vrs1/MAINTAINERS ---- linux-2.4.26/MAINTAINERS 2004-04-19 11:44:14.000000000 +0100 -+++ linux-2.4.26-vrs1/MAINTAINERS 2004-04-18 21:47:49.000000000 +0100 -@@ -256,6 +256,8 @@ - ARM/STRONGARM110 PORT - P: Russell King - M: rmk@arm.linux.org.uk -+P: Vincent Sanders -+M: vince@arm.linux.org.uk - L: linux-arm-kernel@lists.arm.linux.org.uk - W: http://www.arm.linux.org.uk/ - S: Maintained -diff -urN linux-2.4.26/Makefile linux-2.4.26-vrs1/Makefile ---- linux-2.4.26/Makefile 2004-04-19 11:44:14.000000000 +0100 -+++ linux-2.4.26-vrs1/Makefile 2004-04-18 21:50:41.000000000 +0100 -@@ -1,7 +1,7 @@ - VERSION = 2 - PATCHLEVEL = 4 - SUBLEVEL = 26 --EXTRAVERSION = -+EXTRAVERSION =-vrs1 - - KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) - -@@ -137,7 +137,10 @@ - - DRIVERS-$(CONFIG_ACPI_BOOT) += drivers/acpi/acpi.o - DRIVERS-$(CONFIG_PARPORT) += drivers/parport/driver.o --DRIVERS-y += drivers/char/char.o \ -+DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o -+DRIVERS-$(CONFIG_L3) += drivers/l3/l3.o -+DRIVERS-y += drivers/serial/serial.o \ -+ drivers/char/char.o \ - drivers/block/block.o \ - drivers/misc/misc.o \ - drivers/net/net.o -@@ -161,6 +164,7 @@ - DRIVERS-y += drivers/cdrom/driver.o - endif - -+DRIVERS-$(CONFIG_SSI) += drivers/ssi/ssi.o - DRIVERS-$(CONFIG_SOUND) += drivers/sound/sounddrivers.o - DRIVERS-$(CONFIG_PCI) += drivers/pci/driver.o - DRIVERS-$(CONFIG_MTD) += drivers/mtd/mtdlink.o -@@ -186,7 +190,6 @@ - DRIVERS-$(CONFIG_HIL) += drivers/hil/hil.o - DRIVERS-$(CONFIG_I2O) += drivers/message/i2o/i2o.o - DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o --DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o - DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o - DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o - DRIVERS-$(CONFIG_GSC) += drivers/gsc/gscbus.o -@@ -194,6 +197,8 @@ - DRIVERS-$(CONFIG_HOTPLUG_PCI) += drivers/hotplug/vmlinux-obj.o - DRIVERS-$(CONFIG_ISDN_BOOL) += drivers/isdn/vmlinux-obj.o - DRIVERS-$(CONFIG_CRYPTO) += crypto/crypto.o -+DRIVERS-$(CONFIG_PLD) += drivers/pld/pld.o -+DRIVERS-$(CONFIG_ARCH_AT91RM9200) += drivers/at91/at91drv.o - - DRIVERS := $(DRIVERS-y) - -@@ -274,11 +279,6 @@ - - export NETWORKS DRIVERS LIBS HEAD LDFLAGS LINKFLAGS MAKEBOOT ASFLAGS - --.S.s: -- $(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -traditional -o $*.s $< --.S.o: -- $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -traditional -c -o $*.o $< -- - Version: dummy - @rm -f include/linux/compile.h - -diff -urN linux-2.4.26/Rules.make linux-2.4.26-vrs1/Rules.make ---- linux-2.4.26/Rules.make 2004-02-27 20:03:23.000000000 +0000 -+++ linux-2.4.26-vrs1/Rules.make 2004-02-23 13:36:21.000000000 +0000 -@@ -51,15 +51,15 @@ - # - - %.s: %.c -- $(CC) $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -S $< -o $@ -+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$(*F)) $(CFLAGS_$@) -S $< -o $@ - - %.i: %.c -- $(CPP) $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) $< > $@ -+ $(CPP) $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$(*F)) $(CFLAGS_$@) $< > $@ - - %.o: %.c -- $(CC) $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -c -o $@ $< -+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$(*F)) $(CFLAGS_$@) -c -o $@ $< - @ ( \ -- echo 'ifeq ($(strip $(subst $(comma),:,$(CFLAGS) $(EXTRA_CFLAGS_nostdinc) $(CFLAGS_$@))),$$(strip $$(subst $$(comma),:,$$(CFLAGS) $$(EXTRA_CFLAGS_nostdinc) $$(CFLAGS_$@))))' ; \ -+ echo 'ifeq ($(strip $(subst $(comma),:,$(CFLAGS) $(EXTRA_CFLAGS_nostdinc) $(CFLAGS_$(*F)) $(CFLAGS_$@))),$$(strip $$(subst $$(comma),:,$$(CFLAGS) $$(EXTRA_CFLAGS_nostdinc) $$(CFLAGS_$(*F)) $$(CFLAGS_$@))))' ; \ - echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ - echo 'endif' \ - ) > $(dir $@)/.$(notdir $@).flags -@@ -272,7 +272,8 @@ - endif # CONFIG_MODVERSIONS - - ifneq "$(strip $(export-objs))" "" --$(export-objs): $(export-objs:.o=.c) $(TOPDIR)/include/linux/modversions.h -+$(export-objs): $(TOPDIR)/include/linux/modversions.h -+$(export-objs): %.o: %.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -DEXPORT_SYMTAB -c $(@:.o=.c) - @ ( \ - echo 'ifeq ($(strip $(subst $(comma),:,$(CFLAGS) $(EXTRA_CFLAGS_nostdinc) $(CFLAGS_$@) -DEXPORT_SYMTAB)),$$(strip $$(subst $$(comma),:,$$(CFLAGS) $$(EXTRA_CFLAGS_nostdinc) $$(CFLAGS_$@) -DEXPORT_SYMTAB)))' ; \ -diff -urN linux-2.4.26/arch/alpha/config.in linux-2.4.26-vrs1/arch/alpha/config.in ---- linux-2.4.26/arch/alpha/config.in 2004-02-27 20:03:23.000000000 +0000 -+++ linux-2.4.26-vrs1/arch/alpha/config.in 2004-02-23 13:36:21.000000000 +0000 -@@ -7,6 +7,7 @@ - define_bool CONFIG_UID16 n - define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n - define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y -+define_bool CONFIG_GENERIC_ISA_DMA y - - mainmenu_name "Kernel configuration of Linux for Alpha machines" - -diff -urN linux-2.4.26/arch/arm/Makefile linux-2.4.26-vrs1/arch/arm/Makefile ---- linux-2.4.26/arch/arm/Makefile 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/Makefile 2004-01-14 21:32:23.000000000 +0000 -@@ -52,7 +52,7 @@ - - CFLAGS_BOOT :=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm - CFLAGS +=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm --AFLAGS +=$(apcs-y) $(arch-y) -mno-fpu -msoft-float -+AFLAGS +=$(apcs-y) $(arch-y) -msoft-float - - ifeq ($(CONFIG_CPU_26),y) - PROCESSOR := armo -diff -urN linux-2.4.26/arch/arm/boot/compressed/head.S linux-2.4.26-vrs1/arch/arm/boot/compressed/head.S ---- linux-2.4.26/arch/arm/boot/compressed/head.S 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/boot/compressed/head.S 2004-03-04 20:31:57.000000000 +0000 -@@ -40,6 +40,14 @@ - .macro writeb, rb - strb \rb, [r3, #0x3f8 << 2] - .endm -+#elif defined(CONFIG_ARCH_RISCSTATION) -+ .macro loadsp, rb -+ mov \rb, #0x03000000 -+ orr \rb, \rb, #0x00010000 -+ .endm -+ .macro writeb, rb -+ strb \rb, [r3, #0x3f8 << 2] -+ .endm - #elif defined(CONFIG_ARCH_INTEGRATOR) - .macro loadsp, rb - mov \rb, #0x16000000 -@@ -396,6 +404,20 @@ - mcr p15, 0, r0, c1, c0, 0 @ load control register - mov pc, r12 - -+__arm7_cache_on: -+ mov r12, lr -+ bl __setup_mmu -+ mov r0, #0 -+ mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 -+ mcr p15, 0, r0, c5, c0, 0 @ invalidate whole TLB v3 -+ mcr p15, 0, r3, c2, c0, 0 @ load page table pointer -+ mov r0, #-1 -+ mcr p15, 0, r0, c3, c0, 0 @ load domain access control -+ mov r0, #0x7d -+ mcr p15, 0, r0, c1, c0, 0 @ load control register -+ mov pc, r12 -+ -+ - /* - * All code following this line is relocatable. It is relocated by - * the above code to the end of the decompressed kernel image and -@@ -480,9 +502,9 @@ - - .word 0x41007000 @ ARM7/710 - .word 0xfff8fe00 -+ b __arm7_cache_on - b __arm7_cache_off -- b __arm7_cache_off -- mov pc, lr -+ b __armv3_cache_flush - - .word 0x41807200 @ ARM720T (writethrough) - .word 0xffffff00 -@@ -490,14 +512,14 @@ - b __armv4_cache_off - mov pc, lr - -- .word 0x41129200 @ ARM920T -- .word 0xff00fff0 -+ .word 0x41009200 @ ARM920T, ARM922T, ARM926TEJ-S -+ .word 0xff00ff90 - b __armv4_cache_on - b __armv4_cache_off - b __armv4_cache_flush - -- .word 0x41029220 @ ARM922T -- .word 0xff00fff0 -+ .word 0x4100a200 @ ARM1020T/E, ARM1022E, ARM1026TEJ-S -+ .word 0xff00ff90 - b __armv4_cache_on - b __armv4_cache_off - b __armv4_cache_flush -diff -urN linux-2.4.26/arch/arm/config.in linux-2.4.26-vrs1/arch/arm/config.in ---- linux-2.4.26/arch/arm/config.in 2004-02-27 20:03:23.000000000 +0000 -+++ linux-2.4.26-vrs1/arch/arm/config.in 2004-04-10 12:21:08.000000000 +0100 -@@ -144,6 +144,7 @@ - mainmenu_option next_comment - comment 'AT91RM9200 Implementations' - dep_bool ' Atmel AT91RM9200 Development Board' CONFIG_ARCH_AT91RM9200DK $CONFIG_ARCH_AT91RM9200 -+dep_bool ' Cogent CSB337' CONFIG_MACH_CSB337 $CONFIG_ARCH_AT91RM9200 - endmenu - - mainmenu_option next_comment -@@ -189,6 +190,12 @@ - define_bool CONFIG_ARCH_ACORN n - fi - -+if [ "$CONFIG_ARCH_CAMELOT" = "y" ]; then -+ define_bool CONFIG_PLD y -+else -+ define_bool CONFIG_PLD n -+fi -+ - ##################################################################### - # Footbridge support - if [ "$CONFIG_ARCH_CO285" = "y" -o \ -@@ -315,26 +322,42 @@ - # ARM922T - if [ "$CONFIG_ARCH_CAMELOT" = "y" ]; then - define_bool CONFIG_CPU_ARM922T y -- define_bool CONFIG_PLD y - else -- define_bool CONFIG_CPU_ARM922T n -- define_bool CONFIG_PLD n -+ if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then -+ bool 'Support ARM922T(Excalibur) processor' CONFIG_ARM922T -+ else -+ define_bool CONFIG_CPU_ARM922T n -+ fi - fi - - # ARM926T - if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then -- bool 'Support ARM926T processor' CONFIG_CPU_ARM926T -+ bool 'Support ARM926TEJ-S processor' CONFIG_CPU_ARM926T - else - define_bool CONFIG_CPU_ARM926T n - fi - - # ARM1020 - if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then -- bool 'Support ARM1020 processor' CONFIG_CPU_ARM1020 -+ bool 'Support ARM1020T (Rev0) processor' CONFIG_CPU_ARM1020 - else - define_bool CONFIG_CPU_ARM1020 n - fi - -+# ARM1020E -+if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then -+ bool 'Support ARM1020E (Rev1) processor' CONFIG_CPU_ARM1020E -+else -+ define_bool CONFIG_CPU_ARM1020E n -+fi -+ -+# ARM1022 -+if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then -+ bool 'Support ARM1022 processor' CONFIG_CPU_ARM1020E -+else -+ define_bool CONFIG_CPU_ARM1022 n -+fi -+ - # ARM1026EJ-S - if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then - bool 'Support ARM1026EJ-S processor' CONFIG_CPU_ARM1026 -@@ -388,25 +411,29 @@ - - 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_ARM1026" = "y" ]; then -+ "$CONFIG_CPU_ARM1020" = "y" -o "$CONFIG_CPU_ARM1020E" = "y" -o \ -+ "$CONFIG_CPU_ARM1022" = "y" -o "$CONFIG_CPU_ARM1026" = "y" ]; then - dep_bool 'Support Thumb instructions (EXPERIMENTAL)' CONFIG_ARM_THUMB $CONFIG_EXPERIMENTAL - fi - if [ "$CONFIG_CPU_ARM920T" = "y" -o "$CONFIG_CPU_ARM922T" = "y" -o \ - "$CONFIG_CPU_ARM926T" = "y" -o "$CONFIG_CPU_ARM1020" = "y" -o \ -+ "$CONFIG_CPU_ARM1020E" = "y" -o "$CONFIG_CPU_ARM1022" = "y" -o \ - "$CONFIG_CPU_ARM1026" = "y" ]; then - bool 'Disable I-Cache' CONFIG_CPU_ICACHE_DISABLE - bool 'Disable D-Cache' CONFIG_CPU_DCACHE_DISABLE -- if [ "$CONFIG_CPU_DISABLE_DCACHE" = "n" ]; then -+ if [ "$CONFIG_CPU_DCACHE_DISABLE" = "n" ]; then - bool 'Force write through D-cache' CONFIG_CPU_DCACHE_WRITETHROUGH - fi - fi - if [ "$CONFIG_CPU_ARM926T" = "y" -o "$CONFIG_CPU_ARM1020" = "y" -o \ -+ "$CONFIG_CPU_ARM1020E" = "y" -o "$CONFIG_CPU_ARM1022" = "y" -o \ - "$CONFIG_CPU_ARM1026" = "y" ]; then - if [ "$CONFIG_CPU_ICACHE_DISABLE" = "n" -o "$CONFIG_CPU_DCACHE_DISABLE" = "n" ]; then - bool 'Round robin I and D cache replacement algorithm' CONFIG_CPU_CACHE_ROUND_ROBIN - fi - fi --if [ "$CONFIG_CPU_ARM1020" = "y" -o "$CONFIG_CPU_ARM1026" = "y" ]; then -+if [ "$CONFIG_CPU_ARM1020" = "y" -o "$CONFIG_CPU_ARM1020E" = "y" -o \ -+ "$CONFIG_CPU_ARM1026" = "y" -o "$CONFIG_CPU_ARM1022" = "y" ]; then - bool 'Disable branch prediction' CONFIG_CPU_BPREDICT_DISABLE - fi - -@@ -514,7 +541,8 @@ - "$CONFIG_ARCH_INTEGRATOR" = "y" -o \ - "$CONFIG_ARCH_CDB89712" = "y" -o \ - "$CONFIG_ARCH_P720T" = "y" -o \ -- "$CONFIG_ARCH_OMAHA" = "y" ]; then -+ "$CONFIG_ARCH_OMAHA" = "y" -o \ -+ "$CONFIG_ARCH_AT91RM9200" = "y" ]; then - bool 'Timer and CPU usage LEDs' CONFIG_LEDS - if [ "$CONFIG_LEDS" = "y" ]; then - if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ -@@ -524,7 +552,8 @@ - "$CONFIG_ARCH_SA1100" = "y" -o \ - "$CONFIG_ARCH_INTEGRATOR" = "y" -o \ - "$CONFIG_ARCH_P720T" = "y" -o \ -- "$CONFIG_ARCH_OMAHA" = "y" ]; then -+ "$CONFIG_ARCH_OMAHA" = "y" -o \ -+ "$CONFIG_ARCH_AT91RM9200" = "y" ]; then - bool ' Timer LED' CONFIG_LEDS_TIMER - bool ' CPU usage LED' CONFIG_LEDS_CPU - fi -@@ -729,10 +758,7 @@ - dep_bool ' Kernel low-level debugging functions' CONFIG_DEBUG_LL $CONFIG_DEBUG_KERNEL - dep_bool ' Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT $CONFIG_DEBUG_LL $CONFIG_FOOTBRIDGE - dep_bool ' Kernel low-level debugging messages via UART2' CONFIG_DEBUG_CLPS711X_UART2 $CONFIG_DEBUG_LL $CONFIG_ARCH_CLPS711X -- --int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0 -- - endmenu - --source crypto/Config.in - source lib/Config.in -+ -diff -urN linux-2.4.26/arch/arm/def-configs/at91rm9200dk linux-2.4.26-vrs1/arch/arm/def-configs/at91rm9200dk ---- linux-2.4.26/arch/arm/def-configs/at91rm9200dk 2004-02-27 20:03:23.000000000 +0000 -+++ linux-2.4.26-vrs1/arch/arm/def-configs/at91rm9200dk 2004-03-04 22:47:46.000000000 +0000 -@@ -111,6 +111,7 @@ - # AT91RM9200 Implementations - # - CONFIG_ARCH_AT91RM9200DK=y -+# CONFIG_MACH_CSB337 is not set - - # - # CLPS711X/EP721X Implementations -@@ -125,6 +126,7 @@ - # CONFIG_ARCH_EP7211 is not set - # CONFIG_ARCH_EP7212 is not set - # CONFIG_ARCH_ACORN is not set -+# CONFIG_PLD is not set - # CONFIG_FOOTBRIDGE is not set - # CONFIG_FOOTBRIDGE_HOST is not set - # CONFIG_FOOTBRIDGE_ADDIN is not set -@@ -135,9 +137,10 @@ - # CONFIG_CPU_ARM720T is not set - CONFIG_CPU_ARM920T=y - # CONFIG_CPU_ARM922T is not set --# CONFIG_PLD is not set - # CONFIG_CPU_ARM926T is not set - # CONFIG_CPU_ARM1020 is not set -+# CONFIG_CPU_ARM1020E is not set -+# CONFIG_CPU_ARM1022 is not set - # CONFIG_CPU_ARM1026 is not set - # CONFIG_CPU_SA110 is not set - # CONFIG_CPU_SA1100 is not set -@@ -146,6 +149,7 @@ - # CONFIG_ARM_THUMB is not set - # CONFIG_CPU_ICACHE_DISABLE is not set - # CONFIG_CPU_DCACHE_DISABLE is not set -+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set - # CONFIG_DISCONTIGMEM is not set - - # -@@ -164,6 +168,7 @@ - # CONFIG_BSD_PROCESS_ACCT is not set - CONFIG_SYSCTL=y - CONFIG_FPE_NWFPE=y -+# CONFIG_FPE_NWFPE_XP is not set - # CONFIG_FPE_FASTFPE is not set - CONFIG_KCORE_ELF=y - # CONFIG_KCORE_AOUT is not set -@@ -173,6 +178,9 @@ - # CONFIG_PM is not set - # CONFIG_ARTHUR is not set - CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x20210000,3145728 root=/dev/ram rw" -+CONFIG_LEDS=y -+CONFIG_LEDS_TIMER=y -+# CONFIG_LEDS_CPU is not set - CONFIG_ALIGNMENT_TRAP=y - - # -@@ -204,6 +212,7 @@ - # CONFIG_MTD_CFI_ADV_OPTIONS is not set - # CONFIG_MTD_CFI_INTELEXT is not set - CONFIG_MTD_CFI_AMDSTD=y -+# CONFIG_MTD_CFI_STAA is not set - # CONFIG_MTD_RAM is not set - # CONFIG_MTD_ROM is not set - # CONFIG_MTD_ABSENT is not set -@@ -230,7 +239,9 @@ - # CONFIG_MTD_AUTCPU12 is not set - # CONFIG_MTD_EDB7312 is not set - # CONFIG_MTD_IMPA7 is not set -+# CONFIG_MTD_CEIVA is not set - # CONFIG_MTD_PCI is not set -+# CONFIG_MTD_PCMCIA is not set - - # - # Self-contained MTD device drivers -@@ -250,9 +261,9 @@ - # NAND Flash Device Drivers - # - CONFIG_MTD_NAND=y --CONFIG_MTD_NAND_ECC=y - # CONFIG_MTD_NAND_VERIFY_WRITE is not set --CONFIG_MTD_AT91_SMARTMEDIA=y -+CONFIG_MTD_NAND_IDS=y -+# CONFIG_MTD_AT91_SMARTMEDIA is not set - - # - # Plug and Play configuration -@@ -269,6 +280,7 @@ - # CONFIG_BLK_CPQ_DA is not set - # CONFIG_BLK_CPQ_CISS_DA is not set - # CONFIG_CISS_SCSI_TAPE is not set -+# CONFIG_CISS_MONITOR_THREAD is not set - # CONFIG_BLK_DEV_DAC960 is not set - # CONFIG_BLK_DEV_UMEM is not set - # CONFIG_BLK_DEV_LOOP is not set -@@ -276,6 +288,7 @@ - CONFIG_BLK_DEV_RAM=y - CONFIG_BLK_DEV_RAM_SIZE=8192 - CONFIG_BLK_DEV_INITRD=y -+# CONFIG_BLK_STATS is not set - - # - # Multi-device support (RAID and LVM) -@@ -312,6 +325,12 @@ - # CONFIG_SYN_COOKIES is not set - # CONFIG_IPV6 is not set - # CONFIG_KHTTPD is not set -+ -+# -+# SCTP Configuration (EXPERIMENTAL) -+# -+CONFIG_IPV6_SCTP__=y -+# CONFIG_IP_SCTP is not set - # CONFIG_ATM is not set - # CONFIG_VLAN_8021Q is not set - # CONFIG_IPX is not set -@@ -382,10 +401,12 @@ - # - # CONFIG_ACENIC is not set - # CONFIG_DL2K is not set -+# CONFIG_E1000 is not set - # CONFIG_MYRI_SBUS is not set - # CONFIG_NS83820 is not set - # CONFIG_HAMACHI is not set - # CONFIG_YELLOWFIN is not set -+# CONFIG_R8169 is not set - # CONFIG_SK98LIN is not set - # CONFIG_TIGON3 is not set - # CONFIG_FDDI is not set -@@ -455,6 +476,8 @@ - # CONFIG_INPUT_MOUSEDEV is not set - # CONFIG_INPUT_JOYDEV is not set - # CONFIG_INPUT_EVDEV is not set -+# CONFIG_INPUT_UINPUT is not set -+# CONFIG_INPUT_MX1TS is not set - - # - # Character devices -@@ -502,6 +525,7 @@ - # - CONFIG_I2C=y - # CONFIG_I2C_ALGOBIT is not set -+# CONFIG_SCx200_ACB is not set - # CONFIG_I2C_ALGOPCF is not set - CONFIG_I2C_AT91=y - CONFIG_I2C_CHARDEV=y -@@ -528,6 +552,11 @@ - # - # CONFIG_INPUT_GAMEPORT is not set - # CONFIG_QIC02_TAPE is not set -+# CONFIG_IPMI_HANDLER is not set -+# CONFIG_IPMI_PANIC_EVENT is not set -+# CONFIG_IPMI_DEVICE_INTERFACE is not set -+# CONFIG_IPMI_KCS is not set -+# CONFIG_IPMI_WATCHDOG is not set - - # - # Watchdog Cards -@@ -536,12 +565,14 @@ - CONFIG_WATCHDOG_NOWAYOUT=y - # CONFIG_ACQUIRE_WDT is not set - # CONFIG_ADVANTECH_WDT is not set -+# CONFIG_ALIM1535_WDT is not set - # CONFIG_ALIM7101_WDT is not set - # CONFIG_SC520_WDT is not set - # CONFIG_PCWATCHDOG is not set - # CONFIG_21285_WATCHDOG is not set - # CONFIG_977_WATCHDOG is not set - # CONFIG_SA1100_WATCHDOG is not set -+# CONFIG_EPXA_WATCHDOG is not set - # CONFIG_OMAHA_WATCHDOG is not set - CONFIG_AT91_WATCHDOG=y - # CONFIG_EUROTECH_WDT is not set -@@ -551,11 +582,16 @@ - # CONFIG_MIXCOMWD is not set - # CONFIG_60XX_WDT is not set - # CONFIG_SC1200_WDT is not set -+# CONFIG_SCx200_WDT is not set - # CONFIG_SOFT_WATCHDOG is not set - # CONFIG_W83877F_WDT is not set - # CONFIG_WDT is not set - # CONFIG_WDTPCI is not set - # CONFIG_MACHZ_WDT is not set -+# CONFIG_AMD7XX_TCO is not set -+# CONFIG_SCx200 is not set -+# CONFIG_SCx200_GPIO is not set -+# CONFIG_AMD_PM768 is not set - # CONFIG_NVRAM is not set - # CONFIG_RTC is not set - CONFIG_AT91_RTC=y -@@ -568,6 +604,10 @@ - # - # CONFIG_FTAPE is not set - # CONFIG_AGP is not set -+ -+# -+# Direct Rendering Manager (XFree86 DRI support) -+# - # CONFIG_DRM is not set - - # -@@ -579,6 +619,7 @@ - # File systems - # - # CONFIG_QUOTA is not set -+# CONFIG_QFMT_V2 is not set - # CONFIG_AUTOFS_FS is not set - # CONFIG_AUTOFS4_FS is not set - # CONFIG_REISERFS_FS is not set -@@ -588,6 +629,9 @@ - # CONFIG_ADFS_FS_RW is not set - # CONFIG_AFFS_FS is not set - # CONFIG_HFS_FS is not set -+# CONFIG_HFSPLUS_FS is not set -+# CONFIG_BEFS_FS is not set -+# CONFIG_BEFS_DEBUG is not set - # CONFIG_BFS_FS is not set - # CONFIG_EXT3_FS is not set - # CONFIG_JBD is not set -@@ -605,6 +649,9 @@ - # CONFIG_ISO9660_FS is not set - # CONFIG_JOLIET is not set - # CONFIG_ZISOFS is not set -+# CONFIG_JFS_FS is not set -+# CONFIG_JFS_DEBUG is not set -+# CONFIG_JFS_STATISTICS is not set - # CONFIG_MINIX_FS is not set - # CONFIG_VXFS_FS is not set - # CONFIG_NTFS_FS is not set -@@ -624,6 +671,11 @@ - # CONFIG_UDF_RW is not set - # CONFIG_UFS_FS is not set - # CONFIG_UFS_FS_WRITE is not set -+# CONFIG_XFS_FS is not set -+# CONFIG_XFS_QUOTA is not set -+# CONFIG_XFS_RT is not set -+# CONFIG_XFS_TRACE is not set -+# CONFIG_XFS_DEBUG is not set - - # - # Network File Systems -@@ -632,9 +684,11 @@ - # CONFIG_INTERMEZZO_FS is not set - # CONFIG_NFS_FS is not set - # CONFIG_NFS_V3 is not set -+# CONFIG_NFS_DIRECTIO is not set - # CONFIG_ROOT_NFS is not set - # CONFIG_NFSD is not set - # CONFIG_NFSD_V3 is not set -+# CONFIG_NFSD_TCP is not set - # CONFIG_SUNRPC is not set - # CONFIG_LOCKD is not set - # CONFIG_SMB_FS is not set -@@ -648,7 +702,6 @@ - # CONFIG_NCPFS_NLS is not set - # CONFIG_NCPFS_EXTRAS is not set - # CONFIG_ZISOFS_FS is not set --# CONFIG_ZLIB_FS_INFLATE is not set - - # - # Partition Types -@@ -674,16 +727,18 @@ - # CONFIG_USB_DEBUG is not set - # CONFIG_USB_DEVICEFS is not set - # CONFIG_USB_BANDWIDTH is not set --# CONFIG_USB_LONG_TIMEOUT is not set - # CONFIG_USB_EHCI_HCD is not set - # CONFIG_USB_UHCI is not set - # CONFIG_USB_UHCI_ALT is not set - # CONFIG_USB_OHCI is not set - # CONFIG_USB_OHCI_SA1111 is not set -+# CONFIG_USB_SL811HS_ALT is not set -+# CONFIG_USB_SL811HS is not set - CONFIG_USB_OHCI_AT91=y - # CONFIG_USB_AUDIO is not set - # CONFIG_USB_EMI26 is not set - # CONFIG_USB_BLUETOOTH is not set -+# CONFIG_USB_MIDI is not set - # CONFIG_USB_STORAGE is not set - # CONFIG_USB_STORAGE_DEBUG is not set - # CONFIG_USB_STORAGE_DATAFAB is not set -@@ -692,6 +747,7 @@ - # CONFIG_USB_STORAGE_DPCM is not set - # CONFIG_USB_STORAGE_HP8200e is not set - # CONFIG_USB_STORAGE_SDDR09 is not set -+# CONFIG_USB_STORAGE_SDDR55 is not set - # CONFIG_USB_STORAGE_JUMPSHOT is not set - # CONFIG_USB_ACM is not set - # CONFIG_USB_PRINTER is not set -@@ -700,7 +756,10 @@ - # CONFIG_USB_HIDDEV is not set - # CONFIG_USB_KBD is not set - # CONFIG_USB_MOUSE is not set -+# CONFIG_USB_AIPTEK is not set - # CONFIG_USB_WACOM is not set -+# CONFIG_USB_KBTAB is not set -+# CONFIG_USB_POWERMATE is not set - # CONFIG_USB_DC2XX is not set - # CONFIG_USB_MDC800 is not set - # CONFIG_USB_SCANNER is not set -@@ -718,35 +777,16 @@ - # USB Serial Converter support - # - # CONFIG_USB_SERIAL is not set --# CONFIG_USB_SERIAL_GENERIC is not set --# CONFIG_USB_SERIAL_BELKIN is not set --# CONFIG_USB_SERIAL_WHITEHEAT is not set --# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set --# CONFIG_USB_SERIAL_EMPEG is not set --# CONFIG_USB_SERIAL_FTDI_SIO is not set --# CONFIG_USB_SERIAL_VISOR is not set --# CONFIG_USB_SERIAL_IPAQ is not set --# CONFIG_USB_SERIAL_IR is not set --# CONFIG_USB_SERIAL_EDGEPORT is not set --# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set --# CONFIG_USB_SERIAL_KEYSPAN is not set --# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set --# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set --# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set --# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set --# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set --# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set --# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set --# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set --# CONFIG_USB_SERIAL_MCT_U232 is not set --# CONFIG_USB_SERIAL_KLSI is not set --# CONFIG_USB_SERIAL_PL2303 is not set --# CONFIG_USB_SERIAL_CYBERJACK is not set --# CONFIG_USB_SERIAL_XIRCOM is not set --# CONFIG_USB_SERIAL_OMNINET is not set - # CONFIG_USB_RIO500 is not set - # CONFIG_USB_AUERSWALD is not set -+# CONFIG_USB_TIGL is not set - # CONFIG_USB_BRLVGER is not set -+# CONFIG_USB_LCD is not set -+ -+# -+# Support for USB gadgets -+# -+# CONFIG_USB_GADGET is not set - - # - # Bluetooth support -@@ -770,3 +810,10 @@ - CONFIG_DEBUG_LL=y - # CONFIG_DEBUG_DC21285_PORT is not set - # CONFIG_DEBUG_CLPS711X_UART2 is not set -+ -+# -+# Library routines -+# -+CONFIG_CRC32=y -+# CONFIG_ZLIB_INFLATE is not set -+# CONFIG_ZLIB_DEFLATE is not set -diff -urN linux-2.4.26/arch/arm/def-configs/csb337 linux-2.4.26-vrs1/arch/arm/def-configs/csb337 ---- linux-2.4.26/arch/arm/def-configs/csb337 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/def-configs/csb337 2004-03-04 22:44:33.000000000 +0000 -@@ -0,0 +1,760 @@ -+# -+# Automatically generated by make menuconfig: don't edit -+# -+CONFIG_ARM=y -+# CONFIG_EISA is not set -+# CONFIG_SBUS is not set -+# CONFIG_MCA is not set -+CONFIG_UID16=y -+CONFIG_RWSEM_GENERIC_SPINLOCK=y -+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set -+# CONFIG_GENERIC_BUST_SPINLOCK is not set -+# CONFIG_GENERIC_ISA_DMA is not set -+ -+# -+# Code maturity level options -+# -+CONFIG_EXPERIMENTAL=y -+# CONFIG_OBSOLETE is not set -+ -+# -+# Loadable module support -+# -+CONFIG_MODULES=y -+# CONFIG_MODVERSIONS is not set -+CONFIG_KMOD=y -+ -+# -+# System Type -+# -+# CONFIG_ARCH_ANAKIN is not set -+# CONFIG_ARCH_ARCA5K is not set -+# CONFIG_ARCH_CLPS7500 is not set -+# CONFIG_ARCH_CLPS711X is not set -+# CONFIG_ARCH_CO285 is not set -+# CONFIG_ARCH_EBSA110 is not set -+# CONFIG_ARCH_CAMELOT is not set -+# CONFIG_ARCH_FOOTBRIDGE is not set -+# CONFIG_ARCH_INTEGRATOR is not set -+# CONFIG_ARCH_OMAHA is not set -+# CONFIG_ARCH_L7200 is not set -+# CONFIG_ARCH_MX1ADS is not set -+# CONFIG_ARCH_RPC is not set -+# CONFIG_ARCH_RISCSTATION is not set -+# CONFIG_ARCH_SA1100 is not set -+# CONFIG_ARCH_SHARK is not set -+CONFIG_ARCH_AT91RM9200=y -+ -+# -+# Archimedes/A5000 Implementations -+# -+# CONFIG_ARCH_ARC is not set -+# CONFIG_ARCH_A5K is not set -+ -+# -+# Footbridge Implementations -+# -+# CONFIG_ARCH_CATS is not set -+# CONFIG_ARCH_PERSONAL_SERVER is not set -+# CONFIG_ARCH_EBSA285_ADDIN is not set -+# CONFIG_ARCH_EBSA285_HOST is not set -+# CONFIG_ARCH_NETWINDER is not set -+ -+# -+# SA11x0 Implementations -+# -+# CONFIG_SA1100_ACCELENT is not set -+# CONFIG_SA1100_ASSABET is not set -+# CONFIG_ASSABET_NEPONSET is not set -+# CONFIG_SA1100_ADSAGC is not set -+# CONFIG_SA1100_ADSBITSY is not set -+# CONFIG_SA1100_ADSBITSYPLUS is not set -+# CONFIG_SA1100_BRUTUS is not set -+# CONFIG_SA1100_CEP is not set -+# CONFIG_SA1100_CERF is not set -+# CONFIG_SA1100_H3100 is not set -+# CONFIG_SA1100_H3600 is not set -+# CONFIG_SA1100_H3800 is not set -+# CONFIG_SA1100_H3XXX is not set -+# CONFIG_H3600_SLEEVE is not set -+# CONFIG_SA1100_EXTENEX1 is not set -+# CONFIG_SA1100_FLEXANET is not set -+# CONFIG_SA1100_FREEBIRD is not set -+# CONFIG_SA1100_FRODO is not set -+# CONFIG_SA1100_GRAPHICSCLIENT is not set -+# CONFIG_SA1100_GRAPHICSMASTER is not set -+# CONFIG_SA1100_HACKKIT is not set -+# CONFIG_SA1100_BADGE4 is not set -+# CONFIG_SA1100_JORNADA720 is not set -+# CONFIG_SA1100_HUW_WEBPANEL is not set -+# CONFIG_SA1100_ITSY is not set -+# CONFIG_SA1100_LART is not set -+# CONFIG_SA1100_NANOENGINE is not set -+# CONFIG_SA1100_OMNIMETER is not set -+# CONFIG_SA1100_PANGOLIN is not set -+# CONFIG_SA1100_PLEB is not set -+# CONFIG_SA1100_PT_SYSTEM3 is not set -+# CONFIG_SA1100_SHANNON is not set -+# CONFIG_SA1100_SHERMAN is not set -+# CONFIG_SA1100_SIMPAD is not set -+# CONFIG_SA1100_SIMPUTER is not set -+# CONFIG_SA1100_PFS168 is not set -+# CONFIG_SA1100_VICTOR is not set -+# CONFIG_SA1100_XP860 is not set -+# CONFIG_SA1100_YOPY is not set -+# CONFIG_SA1100_USB is not set -+# CONFIG_SA1100_USB_NETLINK is not set -+# CONFIG_SA1100_USB_CHAR is not set -+# CONFIG_SA1100_SSP is not set -+ -+# -+# AT91RM9200 Implementations -+# -+# CONFIG_ARCH_AT91RM9200DK is not set -+CONFIG_MACH_CSB337=y -+ -+# -+# CLPS711X/EP721X Implementations -+# -+# CONFIG_ARCH_AUTCPU12 is not set -+# CONFIG_ARCH_CDB89712 is not set -+# CONFIG_ARCH_CLEP7312 is not set -+# CONFIG_ARCH_EDB7211 is not set -+# CONFIG_ARCH_FORTUNET is not set -+# CONFIG_ARCH_GUIDEA07 is not set -+# CONFIG_ARCH_P720T is not set -+# CONFIG_ARCH_EP7211 is not set -+# CONFIG_ARCH_EP7212 is not set -+# CONFIG_ARCH_ACORN is not set -+# CONFIG_PLD is not set -+# CONFIG_FOOTBRIDGE is not set -+# CONFIG_FOOTBRIDGE_HOST is not set -+# CONFIG_FOOTBRIDGE_ADDIN is not set -+CONFIG_CPU_32=y -+# CONFIG_CPU_26 is not set -+# CONFIG_CPU_ARM610 is not set -+# CONFIG_CPU_ARM710 is not set -+# CONFIG_CPU_ARM720T is not set -+CONFIG_CPU_ARM920T=y -+# CONFIG_CPU_ARM922T is not set -+# CONFIG_CPU_ARM926T is not set -+# CONFIG_CPU_ARM1020 is not set -+# CONFIG_CPU_ARM1020E is not set -+# CONFIG_CPU_ARM1022 is not set -+# CONFIG_CPU_ARM1026 is not set -+# CONFIG_CPU_SA110 is not set -+# CONFIG_CPU_SA1100 is not set -+# CONFIG_CPU_32v3 is not set -+CONFIG_CPU_32v4=y -+# CONFIG_ARM_THUMB is not set -+# CONFIG_CPU_ICACHE_DISABLE is not set -+# CONFIG_CPU_DCACHE_DISABLE is not set -+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set -+# CONFIG_DISCONTIGMEM is not set -+ -+# -+# General setup -+# -+# CONFIG_PCI is not set -+# CONFIG_ISA is not set -+# CONFIG_ISA_DMA is not set -+# CONFIG_ZBOOT_ROM is not set -+CONFIG_ZBOOT_ROM_TEXT=0 -+CONFIG_ZBOOT_ROM_BSS=0 -+# CONFIG_HOTPLUG is not set -+# CONFIG_PCMCIA is not set -+CONFIG_NET=y -+CONFIG_SYSVIPC=y -+# CONFIG_BSD_PROCESS_ACCT is not set -+CONFIG_SYSCTL=y -+CONFIG_FPE_NWFPE=y -+# CONFIG_FPE_NWFPE_XP is not set -+# CONFIG_FPE_FASTFPE is not set -+CONFIG_KCORE_ELF=y -+# CONFIG_KCORE_AOUT is not set -+# CONFIG_BINFMT_AOUT is not set -+CONFIG_BINFMT_ELF=y -+# CONFIG_BINFMT_MISC is not set -+# CONFIG_PM is not set -+# CONFIG_ARTHUR is not set -+CONFIG_CMDLINE="mem=32M console=ttyS0,38400 initrd=0x20210000,3145728 root=/dev/ram rw" -+# CONFIG_LEDS is not set -+CONFIG_ALIGNMENT_TRAP=y -+ -+# -+# Parallel port support -+# -+# CONFIG_PARPORT is not set -+ -+# -+# Memory Technology Devices (MTD) -+# -+CONFIG_MTD=y -+# CONFIG_MTD_DEBUG is not set -+# CONFIG_MTD_PARTITIONS is not set -+# CONFIG_MTD_CONCAT is not set -+# CONFIG_MTD_REDBOOT_PARTS is not set -+# CONFIG_MTD_CMDLINE_PARTS is not set -+# CONFIG_MTD_AFS_PARTS is not set -+CONFIG_MTD_CHAR=y -+CONFIG_MTD_BLOCK=y -+# CONFIG_FTL is not set -+# CONFIG_NFTL is not set -+ -+# -+# RAM/ROM/Flash chip drivers -+# -+CONFIG_MTD_CFI=y -+CONFIG_MTD_JEDECPROBE=y -+CONFIG_MTD_GEN_PROBE=y -+# CONFIG_MTD_CFI_ADV_OPTIONS is not set -+CONFIG_MTD_CFI_INTELEXT=y -+# CONFIG_MTD_CFI_AMDSTD is not set -+# CONFIG_MTD_CFI_STAA is not set -+# CONFIG_MTD_RAM is not set -+CONFIG_MTD_ROM=y -+# CONFIG_MTD_ABSENT is not set -+# CONFIG_MTD_OBSOLETE_CHIPS is not set -+# CONFIG_MTD_AMDSTD is not set -+# CONFIG_MTD_SHARP is not set -+# CONFIG_MTD_JEDEC is not set -+ -+# -+# Mapping drivers for chip access -+# -+CONFIG_MTD_PHYSMAP=y -+CONFIG_MTD_PHYSMAP_START=10000000 -+CONFIG_MTD_PHYSMAP_LEN=200000 -+CONFIG_MTD_PHYSMAP_BUSWIDTH=2 -+# CONFIG_MTD_NORA is not set -+# CONFIG_MTD_ARM_INTEGRATOR is not set -+# CONFIG_MTD_CDB89712 is not set -+# CONFIG_MTD_SA1100 is not set -+# CONFIG_MTD_DC21285 is not set -+# CONFIG_MTD_IQ80310 is not set -+# CONFIG_MTD_FORTUNET is not set -+# CONFIG_MTD_EPXA is not set -+# CONFIG_MTD_AUTCPU12 is not set -+# CONFIG_MTD_EDB7312 is not set -+# CONFIG_MTD_IMPA7 is not set -+# CONFIG_MTD_CEIVA is not set -+# CONFIG_MTD_PCI is not set -+# CONFIG_MTD_PCMCIA is not set -+ -+# -+# Self-contained MTD device drivers -+# -+# CONFIG_MTD_PMC551 is not set -+# CONFIG_MTD_SLRAM is not set -+CONFIG_MTD_AT91_DATAFLASH=y -+# CONFIG_MTD_AT91_DATAFLASH_CARD is not set -+# CONFIG_MTD_MTDRAM is not set -+# CONFIG_MTD_BLKMTD is not set -+# CONFIG_MTD_DOC1000 is not set -+# CONFIG_MTD_DOC2000 is not set -+# CONFIG_MTD_DOC2001 is not set -+# CONFIG_MTD_DOCPROBE is not set -+ -+# -+# NAND Flash Device Drivers -+# -+CONFIG_MTD_NAND=y -+# CONFIG_MTD_NAND_VERIFY_WRITE is not set -+CONFIG_MTD_NAND_IDS=y -+# CONFIG_MTD_AT91_SMARTMEDIA is not set -+ -+# -+# Plug and Play configuration -+# -+# CONFIG_PNP is not set -+# CONFIG_ISAPNP is not set -+ -+# -+# Block devices -+# -+# CONFIG_BLK_DEV_FD is not set -+# CONFIG_BLK_DEV_XD is not set -+# CONFIG_PARIDE is not set -+# CONFIG_BLK_CPQ_DA is not set -+# CONFIG_BLK_CPQ_CISS_DA is not set -+# CONFIG_CISS_SCSI_TAPE is not set -+# CONFIG_CISS_MONITOR_THREAD is not set -+# CONFIG_BLK_DEV_DAC960 is not set -+# CONFIG_BLK_DEV_UMEM is not set -+# CONFIG_BLK_DEV_LOOP is not set -+# CONFIG_BLK_DEV_NBD is not set -+CONFIG_BLK_DEV_RAM=y -+CONFIG_BLK_DEV_RAM_SIZE=8192 -+# CONFIG_BLK_DEV_INITRD is not set -+# CONFIG_BLK_STATS is not set -+ -+# -+# Multi-device support (RAID and LVM) -+# -+# CONFIG_MD is not set -+# CONFIG_BLK_DEV_MD is not set -+# CONFIG_MD_LINEAR is not set -+# CONFIG_MD_RAID0 is not set -+# CONFIG_MD_RAID1 is not set -+# CONFIG_MD_RAID5 is not set -+# CONFIG_MD_MULTIPATH is not set -+# CONFIG_BLK_DEV_LVM is not set -+ -+# -+# Networking options -+# -+CONFIG_PACKET=y -+# CONFIG_PACKET_MMAP is not set -+# CONFIG_NETLINK_DEV is not set -+# CONFIG_NETFILTER is not set -+# CONFIG_FILTER is not set -+CONFIG_UNIX=y -+CONFIG_INET=y -+# CONFIG_IP_MULTICAST is not set -+# CONFIG_IP_ADVANCED_ROUTER is not set -+CONFIG_IP_PNP=y -+CONFIG_IP_PNP_DHCP=y -+CONFIG_IP_PNP_BOOTP=y -+# CONFIG_IP_PNP_RARP is not set -+# CONFIG_NET_IPIP is not set -+# CONFIG_NET_IPGRE is not set -+# CONFIG_ARPD is not set -+# CONFIG_INET_ECN is not set -+# CONFIG_SYN_COOKIES is not set -+# CONFIG_IPV6 is not set -+# CONFIG_KHTTPD is not set -+ -+# -+# SCTP Configuration (EXPERIMENTAL) -+# -+CONFIG_IPV6_SCTP__=y -+# CONFIG_IP_SCTP is not set -+# CONFIG_ATM is not set -+# CONFIG_VLAN_8021Q is not set -+# CONFIG_IPX is not set -+# CONFIG_ATALK is not set -+ -+# -+# Appletalk devices -+# -+# CONFIG_DEV_APPLETALK is not set -+# CONFIG_DECNET is not set -+# CONFIG_BRIDGE is not set -+# CONFIG_X25 is not set -+# CONFIG_LAPB is not set -+# CONFIG_LLC is not set -+# CONFIG_NET_DIVERT is not set -+# CONFIG_ECONET is not set -+# CONFIG_WAN_ROUTER is not set -+# CONFIG_NET_FASTROUTE is not set -+# CONFIG_NET_HW_FLOWCONTROL is not set -+ -+# -+# QoS and/or fair queueing -+# -+# CONFIG_NET_SCHED is not set -+ -+# -+# Network testing -+# -+# CONFIG_NET_PKTGEN is not set -+ -+# -+# Network device support -+# -+CONFIG_NETDEVICES=y -+ -+# -+# ARCnet devices -+# -+# CONFIG_ARCNET is not set -+# CONFIG_DUMMY is not set -+# CONFIG_BONDING is not set -+# CONFIG_EQUALIZER is not set -+# CONFIG_TUN is not set -+# CONFIG_ETHERTAP is not set -+ -+# -+# Ethernet (10 or 100Mbit) -+# -+CONFIG_NET_ETHERNET=y -+# CONFIG_ARM_AM79C961A is not set -+# CONFIG_ARM_CIRRUS is not set -+CONFIG_AT91_ETHER=y -+# CONFIG_AT91_ETHER_RMII is not set -+# CONFIG_SUNLANCE is not set -+# CONFIG_SUNBMAC is not set -+# CONFIG_SUNQE is not set -+# CONFIG_SUNGEM is not set -+# CONFIG_NET_VENDOR_3COM is not set -+# CONFIG_LANCE is not set -+# CONFIG_NET_VENDOR_SMC is not set -+# CONFIG_NET_VENDOR_RACAL is not set -+# CONFIG_NET_ISA is not set -+# CONFIG_NET_PCI is not set -+# CONFIG_NET_POCKET is not set -+ -+# -+# Ethernet (1000 Mbit) -+# -+# CONFIG_ACENIC is not set -+# CONFIG_DL2K is not set -+# CONFIG_E1000 is not set -+# CONFIG_MYRI_SBUS is not set -+# CONFIG_NS83820 is not set -+# CONFIG_HAMACHI is not set -+# CONFIG_YELLOWFIN is not set -+# CONFIG_R8169 is not set -+# CONFIG_SK98LIN is not set -+# CONFIG_TIGON3 is not set -+# CONFIG_FDDI is not set -+# CONFIG_HIPPI is not set -+# CONFIG_PLIP is not set -+# CONFIG_PPP is not set -+# CONFIG_SLIP is not set -+ -+# -+# Wireless LAN (non-hamradio) -+# -+# CONFIG_NET_RADIO is not set -+ -+# -+# Token Ring devices -+# -+# CONFIG_TR is not set -+# CONFIG_NET_FC is not set -+# CONFIG_RCPCI is not set -+# CONFIG_SHAPER is not set -+ -+# -+# Wan interfaces -+# -+# CONFIG_WAN is not set -+ -+# -+# Amateur Radio support -+# -+# CONFIG_HAMRADIO is not set -+ -+# -+# IrDA (infrared) support -+# -+# CONFIG_IRDA is not set -+ -+# -+# ATA/ATAPI/MFM/RLL support -+# -+# CONFIG_IDE is not set -+# CONFIG_BLK_DEV_HD is not set -+ -+# -+# SCSI support -+# -+# CONFIG_SCSI is not set -+ -+# -+# I2O device support -+# -+# CONFIG_I2O is not set -+# CONFIG_I2O_BLOCK is not set -+# CONFIG_I2O_LAN is not set -+# CONFIG_I2O_SCSI is not set -+# CONFIG_I2O_PROC is not set -+ -+# -+# ISDN subsystem -+# -+# CONFIG_ISDN is not set -+ -+# -+# Input core support -+# -+# CONFIG_INPUT is not set -+# CONFIG_INPUT_KEYBDEV is not set -+# CONFIG_INPUT_MOUSEDEV is not set -+# CONFIG_INPUT_JOYDEV is not set -+# CONFIG_INPUT_EVDEV is not set -+# CONFIG_INPUT_UINPUT is not set -+# CONFIG_INPUT_MX1TS is not set -+ -+# -+# Character devices -+# -+# CONFIG_VT is not set -+# CONFIG_SERIAL is not set -+# CONFIG_SERIAL_EXTENDED is not set -+# CONFIG_SERIAL_NONSTANDARD is not set -+CONFIG_AT91_SPIDEV=y -+ -+# -+# Serial drivers -+# -+# CONFIG_SERIAL_ANAKIN is not set -+# CONFIG_SERIAL_ANAKIN_CONSOLE is not set -+# CONFIG_SERIAL_AMBA is not set -+# CONFIG_SERIAL_AMBA_CONSOLE is not set -+# CONFIG_SERIAL_CLPS711X is not set -+# CONFIG_SERIAL_CLPS711X_CONSOLE is not set -+# CONFIG_SERIAL_21285 is not set -+# CONFIG_SERIAL_21285_OLD is not set -+# CONFIG_SERIAL_21285_CONSOLE is not set -+# CONFIG_SERIAL_UART00 is not set -+# CONFIG_SERIAL_UART00_CONSOLE is not set -+# CONFIG_SERIAL_SA1100 is not set -+# CONFIG_SERIAL_SA1100_CONSOLE is not set -+# CONFIG_SERIAL_OMAHA is not set -+# CONFIG_SERIAL_OMAHA_CONSOLE is not set -+CONFIG_SERIAL_AT91=y -+CONFIG_SERIAL_AT91_CONSOLE=y -+# CONFIG_SERIAL_8250 is not set -+# CONFIG_SERIAL_8250_CONSOLE is not set -+# CONFIG_SERIAL_8250_EXTENDED is not set -+# CONFIG_SERIAL_8250_MANY_PORTS is not set -+# CONFIG_SERIAL_8250_SHARE_IRQ is not set -+# CONFIG_SERIAL_8250_DETECT_IRQ is not set -+# CONFIG_SERIAL_8250_MULTIPORT is not set -+# CONFIG_SERIAL_8250_HUB6 is not set -+CONFIG_SERIAL_CORE=y -+CONFIG_SERIAL_CORE_CONSOLE=y -+# CONFIG_UNIX98_PTYS is not set -+ -+# -+# I2C support -+# -+CONFIG_I2C=y -+# CONFIG_I2C_ALGOBIT is not set -+# CONFIG_SCx200_ACB is not set -+# CONFIG_I2C_ALGOPCF is not set -+CONFIG_I2C_AT91=y -+CONFIG_I2C_CHARDEV=y -+CONFIG_I2C_PROC=y -+CONFIG_I2C_DS1307=y -+ -+# -+# L3 serial bus support -+# -+# CONFIG_L3 is not set -+# CONFIG_L3_ALGOBIT is not set -+# CONFIG_L3_BIT_SA1100_GPIO is not set -+# CONFIG_L3_SA1111 is not set -+# CONFIG_BIT_SA1100_GPIO is not set -+ -+# -+# Mice -+# -+# CONFIG_BUSMOUSE is not set -+# CONFIG_MOUSE is not set -+ -+# -+# Joysticks -+# -+# CONFIG_INPUT_GAMEPORT is not set -+# CONFIG_QIC02_TAPE is not set -+# CONFIG_IPMI_HANDLER is not set -+# CONFIG_IPMI_PANIC_EVENT is not set -+# CONFIG_IPMI_DEVICE_INTERFACE is not set -+# CONFIG_IPMI_KCS is not set -+# CONFIG_IPMI_WATCHDOG is not set -+ -+# -+# Watchdog Cards -+# -+CONFIG_WATCHDOG=y -+CONFIG_WATCHDOG_NOWAYOUT=y -+# CONFIG_ACQUIRE_WDT is not set -+# CONFIG_ADVANTECH_WDT is not set -+# CONFIG_ALIM1535_WDT is not set -+# CONFIG_ALIM7101_WDT is not set -+# CONFIG_SC520_WDT is not set -+# CONFIG_PCWATCHDOG is not set -+# CONFIG_21285_WATCHDOG is not set -+# CONFIG_977_WATCHDOG is not set -+# CONFIG_SA1100_WATCHDOG is not set -+# CONFIG_EPXA_WATCHDOG is not set -+# CONFIG_OMAHA_WATCHDOG is not set -+CONFIG_AT91_WATCHDOG=y -+# CONFIG_EUROTECH_WDT is not set -+# CONFIG_IB700_WDT is not set -+# CONFIG_WAFER_WDT is not set -+# CONFIG_I810_TCO is not set -+# CONFIG_MIXCOMWD is not set -+# CONFIG_60XX_WDT is not set -+# CONFIG_SC1200_WDT is not set -+# CONFIG_SCx200_WDT is not set -+# CONFIG_SOFT_WATCHDOG is not set -+# CONFIG_W83877F_WDT is not set -+# CONFIG_WDT is not set -+# CONFIG_WDTPCI is not set -+# CONFIG_MACHZ_WDT is not set -+# CONFIG_AMD7XX_TCO is not set -+# CONFIG_SCx200 is not set -+# CONFIG_SCx200_GPIO is not set -+# CONFIG_AMD_PM768 is not set -+# CONFIG_NVRAM is not set -+# CONFIG_RTC is not set -+CONFIG_AT91_RTC=y -+# CONFIG_DTLK is not set -+# CONFIG_R3964 is not set -+# CONFIG_APPLICOM is not set -+ -+# -+# Ftape, the floppy tape device driver -+# -+# CONFIG_FTAPE is not set -+# CONFIG_AGP is not set -+ -+# -+# Direct Rendering Manager (XFree86 DRI support) -+# -+# CONFIG_DRM is not set -+ -+# -+# Multimedia devices -+# -+# CONFIG_VIDEO_DEV is not set -+ -+# -+# File systems -+# -+# CONFIG_QUOTA is not set -+# CONFIG_QFMT_V2 is not set -+# CONFIG_AUTOFS_FS is not set -+# CONFIG_AUTOFS4_FS is not set -+# CONFIG_REISERFS_FS is not set -+# CONFIG_REISERFS_CHECK is not set -+# CONFIG_REISERFS_PROC_INFO is not set -+# CONFIG_ADFS_FS is not set -+# CONFIG_ADFS_FS_RW is not set -+# CONFIG_AFFS_FS is not set -+# CONFIG_HFS_FS is not set -+# CONFIG_HFSPLUS_FS is not set -+# CONFIG_BEFS_FS is not set -+# CONFIG_BEFS_DEBUG is not set -+# CONFIG_BFS_FS is not set -+# CONFIG_EXT3_FS is not set -+# CONFIG_JBD is not set -+# CONFIG_JBD_DEBUG is not set -+# CONFIG_FAT_FS is not set -+# CONFIG_MSDOS_FS is not set -+# CONFIG_UMSDOS_FS is not set -+# CONFIG_VFAT_FS is not set -+# CONFIG_EFS_FS is not set -+# CONFIG_JFFS_FS is not set -+# CONFIG_JFFS2_FS is not set -+# CONFIG_CRAMFS is not set -+# CONFIG_TMPFS is not set -+CONFIG_RAMFS=y -+# CONFIG_ISO9660_FS is not set -+# CONFIG_JOLIET is not set -+# CONFIG_ZISOFS is not set -+# CONFIG_JFS_FS is not set -+# CONFIG_JFS_DEBUG is not set -+# CONFIG_JFS_STATISTICS is not set -+# CONFIG_MINIX_FS is not set -+# CONFIG_VXFS_FS is not set -+# CONFIG_NTFS_FS is not set -+# CONFIG_NTFS_RW is not set -+# CONFIG_HPFS_FS is not set -+CONFIG_PROC_FS=y -+CONFIG_DEVFS_FS=y -+CONFIG_DEVFS_MOUNT=y -+# CONFIG_DEVFS_DEBUG is not set -+# CONFIG_DEVPTS_FS is not set -+# CONFIG_QNX4FS_FS is not set -+# CONFIG_QNX4FS_RW is not set -+# CONFIG_ROMFS_FS is not set -+CONFIG_EXT2_FS=y -+# CONFIG_SYSV_FS is not set -+# CONFIG_UDF_FS is not set -+# CONFIG_UDF_RW is not set -+# CONFIG_UFS_FS is not set -+# CONFIG_UFS_FS_WRITE is not set -+# CONFIG_XFS_FS is not set -+# CONFIG_XFS_QUOTA is not set -+# CONFIG_XFS_RT is not set -+# CONFIG_XFS_TRACE is not set -+# CONFIG_XFS_DEBUG is not set -+ -+# -+# Network File Systems -+# -+# CONFIG_CODA_FS is not set -+# CONFIG_INTERMEZZO_FS is not set -+CONFIG_NFS_FS=y -+CONFIG_NFS_V3=y -+# CONFIG_NFS_DIRECTIO is not set -+CONFIG_ROOT_NFS=y -+# CONFIG_NFSD is not set -+# CONFIG_NFSD_V3 is not set -+# CONFIG_NFSD_TCP is not set -+CONFIG_SUNRPC=y -+CONFIG_LOCKD=y -+CONFIG_LOCKD_V4=y -+# CONFIG_SMB_FS is not set -+# CONFIG_NCP_FS is not set -+# CONFIG_NCPFS_PACKET_SIGNING is not set -+# CONFIG_NCPFS_IOCTL_LOCKING is not set -+# CONFIG_NCPFS_STRONG is not set -+# CONFIG_NCPFS_NFS_NS is not set -+# CONFIG_NCPFS_OS2_NS is not set -+# CONFIG_NCPFS_SMALLDOS is not set -+# CONFIG_NCPFS_NLS is not set -+# CONFIG_NCPFS_EXTRAS is not set -+# CONFIG_ZISOFS_FS is not set -+ -+# -+# Partition Types -+# -+# CONFIG_PARTITION_ADVANCED is not set -+CONFIG_MSDOS_PARTITION=y -+# CONFIG_SMB_NLS is not set -+# CONFIG_NLS is not set -+ -+# -+# Multimedia Capabilities Port drivers -+# -+# CONFIG_MCP is not set -+# CONFIG_MCP_SA1100 is not set -+# CONFIG_MCP_UCB1200 is not set -+# CONFIG_MCP_UCB1200_AUDIO is not set -+# CONFIG_MCP_UCB1200_TS is not set -+ -+# -+# USB support -+# -+# CONFIG_USB is not set -+ -+# -+# Support for USB gadgets -+# -+# CONFIG_USB_GADGET is not set -+ -+# -+# Bluetooth support -+# -+# CONFIG_BLUEZ is not set -+ -+# -+# Kernel hacking -+# -+CONFIG_FRAME_POINTER=y -+CONFIG_DEBUG_USER=y -+# CONFIG_DEBUG_INFO is not set -+# CONFIG_NO_PGT_CACHE is not set -+CONFIG_DEBUG_KERNEL=y -+# CONFIG_DEBUG_SLAB is not set -+# CONFIG_MAGIC_SYSRQ is not set -+# CONFIG_DEBUG_SPINLOCK is not set -+# CONFIG_DEBUG_WAITQ is not set -+# CONFIG_DEBUG_BUGVERBOSE is not set -+# CONFIG_DEBUG_ERRORS is not set -+CONFIG_DEBUG_LL=y -+# CONFIG_DEBUG_DC21285_PORT is not set -+# CONFIG_DEBUG_CLPS711X_UART2 is not set -+ -+# -+# Library routines -+# -+CONFIG_CRC32=y -+# CONFIG_ZLIB_INFLATE is not set -+# CONFIG_ZLIB_DEFLATE is not set -diff -urN linux-2.4.26/arch/arm/fastfpe/CPDO.S linux-2.4.26-vrs1/arch/arm/fastfpe/CPDO.S ---- linux-2.4.26/arch/arm/fastfpe/CPDO.S 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/fastfpe/CPDO.S 2004-01-14 21:32:23.000000000 +0000 -@@ -0,0 +1,682 @@ -+/* -+The FP structure has 4 words reserved for each register, the first is used just -+for the sign in bit 31, the second and third are for the mantissa (unsigned -+integer, high 32 bit first) and the fourth is the exponent (signed integer). -+The mantissa is always normalized. -+ -+If the exponent is 0x80000000, that is the most negative value, the number -+represented is 0 and both mantissa words are also 0. -+ -+If the exponent is 0x7fffffff, that is the biggest positive value, the number -+represented is infinity if the high 32 mantissa bit are also 0, otherwise it is -+a NaN. The low 32 mantissa bit are 0 if the number represented is infinity. -+ -+Decimal and packed decimal numbers are not supported yet. -+ -+The parameters to these functions are r0=destination pointer, r1 and r2 -+source pointers. r4 is the instruction. They may use r0-r8 and r14. They return -+to fastfpe_next, except CPDO_rnf_core which expects the return address in r14. -+*/ -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDO_adf -+CPDO_adf: -+ ldmia r1,{r1,r3,r5,r7} -+ ldmia r2,{r2,r4,r6,r8} -+ -+ cmp r7,#0x7fffffff -+ cmpne r8,#0x7fffffff -+ beq CPDO_adf_extra -+ -+ cmp r1,r2 -+ bne CPDO_suf_s -+ -+CPDO_adf_s: -+ subs r2,r7,r8 -+ bge CPDO_adf_2nd -+ -+ mov r7,r8 -+ rsb r2,r2,#0 -+ cmp r2,#32 -+ ble CPDO_adf_1st2 -+ -+ sub r2,r2,#32 -+ cmp r2,#32 -+ movgt r2,#32 -+ mov r5,r3,lsr r2 -+ mov r3,#0 -+ b CPDO_adf_add -+ -+CPDO_adf_1st2: -+ rsb r8,r2,#32 -+ mov r5,r5,lsr r2 -+ orr r5,r5,r3,lsl r8 -+ mov r3,r3,lsr r2 @ 1. op normalized -+ b CPDO_adf_add -+ -+CPDO_adf_2nd: -+ cmp r2,#32 -+ ble CPDO_adf_2nd2 -+ -+ sub r2,r2,#32 -+ cmp r2,#32 -+ movgt r2,#32 -+ mov r6,r4,lsr r2 -+ mov r4,#0 -+ b CPDO_adf_add -+ -+CPDO_adf_2nd2: -+ rsb r8,r2,#32 -+ mov r6,r6,lsr r2 -+ orr r6,r6,r4,lsl r8 -+ mov r4,r4,lsr r2 @ 2. op normalized -+ -+CPDO_adf_add: -+ adds r5,r5,r6 -+ adcs r3,r3,r4 @ do addition -+ bcc CPDO_adf_end -+ -+ add r7,r7,#1 -+ movs r3,r3,rrx -+ mov r5,r5,rrx @ correct for overflow -+ -+CPDO_adf_end: -+ cmp r7,#0x20000000 -+ bge CPDO_inf -+ -+ stmia r0,{r1,r3,r5,r7} -+ b fastfpe_next -+ -+CPDO_adf_extra: -+ cmp r7,#0x7fffffff @ was it the 1st ? -+ bne CPDO_infnan_2 @ no it was the 2nd -+ cmp r8,#0x7fffffff @ if 1st, 2nd too ? -+ bne CPDO_infnan_1 @ no only 1st -+ cmp r3,#0 -+ cmpeq r4,#0 -+ bne CPDO_nan_12 -+ b CPDO_inf -+ -+/*---------------------------------------------------------------------------*/ -+ -+CPDO_infnan_1: -+ stmia r0,{r1,r3,r5,r7} -+ b fastfpe_next -+ -+CPDO_infnan_2: -+ stmia r0,{r2,r4,r6,r8} -+ b fastfpe_next -+ -+CPDO_nan_12: -+ orr r2,r3,r4 -+ b CPDO_inf_1 -+ -+CPDO_nan: -+ mov r2,#0x40000000 @ create non signalling NaN -+ b CPDO_inf_1 -+ -+CPDO_inf: -+ mov r2,#0 -+CPDO_inf_1: -+ mov r3,#0 -+ mov r4,#0x7fffffff -+CPDO_store_1234: -+ stmia r0,{r1,r2,r3,r4} -+ b fastfpe_next -+ -+CPDO_zero: -+ mov r1,#0 -+CPDO_zero_1: -+ mov r2,#0 -+ mov r3,#0 -+ mov r4,#0x80000000 -+ stmia r0,{r1,r2,r3,r4} -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDO_suf -+CPDO_suf: -+ ldmia r1,{r1,r3,r5,r7} -+ ldmia r2,{r2,r4,r6,r8} -+ -+CPDO_suf_l: -+ cmp r7,#0x7fffffff -+ cmpne r8,#0x7fffffff -+ beq CPDO_suf_extra -+ -+ cmp r1,r2 -+ bne CPDO_adf_s -+ -+CPDO_suf_s: -+ subs r2,r7,r8 @ determine greater number -+ bgt CPDO_suf_2nd @ first number is greater -+ blt CPDO_suf_1st @ second number is greater -+ cmp r3,r4 @ also mantissa is important -+ cmpeq r5,r6 -+ bhi CPDO_suf_2nd @ first number is greater -+ beq CPDO_zero -+ -+CPDO_suf_1st: -+ eor r1,r1,#0x80000000 @ second number is greater, invert sign -+ mov r7,r8 -+ rsb r2,r2,#0 -+ cmp r2,#32 -+ ble CPDO_suf_1st2 -+ -+ sub r2,r2,#32 -+ cmp r2,#32 -+ movgt r2,#32 -+ mov r5,r3,lsr r2 -+ mov r3,#0 -+ b CPDO_suf_1st_sub -+ -+CPDO_suf_1st2: -+ rsb r8,r2,#32 -+ mov r5,r5,lsr r2 -+ orr r5,r5,r3,lsl r8 -+ mov r3,r3,lsr r2 @ 1. op normalized -+ -+CPDO_suf_1st_sub: -+ subs r5,r6,r5 @ do subtraction -+ sbc r3,r4,r3 -+ b CPDO_suf_norm -+ -+CPDO_suf_2nd: -+ cmp r2,#32 -+ ble CPDO_suf_2nd2 -+ -+ sub r2,r2,#32 -+ cmp r2,#32 -+ movgt r2,#32 -+ mov r6,r4,lsr r2 -+ mov r4,#0 -+ b CPDO_suf_2nd_sub -+ -+CPDO_suf_2nd2: -+ rsb r8,r2,#32 -+ mov r6,r6,lsr r2 -+ orr r6,r6,r4,lsl r8 -+ mov r4,r4,lsr r2 @ 2. op normalized -+ -+CPDO_suf_2nd_sub: -+ subs r5,r5,r6 -+ sbc r3,r3,r4 @ do subtraction -+ -+CPDO_suf_norm: -+ teq r3,#0 @ normalize 32bit -+ moveq r3,r5 -+ moveq r5,#0 -+ subeq r7,r7,#32 -+ -+ cmp r3,#0x00010000 @ 16bit -+ movcc r3,r3,lsl#16 -+ orrcc r3,r3,r5,lsr#16 -+ movcc r5,r5,lsl#16 -+ subcc r7,r7,#16 -+ -+ cmp r3,#0x01000000 @ 8bit -+ movcc r3,r3,lsl#8 -+ orrcc r3,r3,r5,lsr#24 -+ movcc r5,r5,lsl#8 -+ subcc r7,r7,#8 -+ -+ cmp r3,#0x10000000 @ 4bit -+ movcc r3,r3,lsl#4 -+ orrcc r3,r3,r5,lsr#28 -+ movcc r5,r5,lsl#4 -+ subcc r7,r7,#4 -+ -+ cmp r3,#0x40000000 @ 2bit -+ movcc r3,r3,lsl#2 -+ orrcc r3,r3,r5,lsr#30 -+ movcc r5,r5,lsl#2 -+ subcc r7,r7,#2 -+ -+ cmp r3,#0x80000000 @ 1bit -+ movcc r3,r3,lsl#1 -+ orrcc r3,r3,r5,lsr#31 -+ movcc r5,r5,lsl#1 -+ subcc r7,r7,#1 -+ -+ cmp r7,#0xe0000000 -+ ble CPDO_zero_1 -+ -+ stmia r0,{r1,r3,r5,r7} -+ b fastfpe_next -+ -+CPDO_suf_extra: -+ cmp r7,#0x7fffffff @ was it the 1st ? -+ eorne r2,r2,#0x80000000 @ change sign, might have been INF -+ bne CPDO_infnan_2 @ no it was the 2nd -+ cmp r8,#0x7fffffff @ if 1st, 2nd too ? -+ bne CPDO_infnan_1 @ no only 1st -+ cmp r3,#0 -+ cmpeq r4,#0 -+ bne CPDO_nan_12 -+ b CPDO_nan @ here is difference with adf ! -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDO_rsf -+CPDO_rsf: -+ mov r3,r2 -+ ldmia r1,{r2,r4,r6,r8} -+ ldmia r3,{r1,r3,r5,r7} -+ b CPDO_suf_l -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDO_muf -+CPDO_muf: -+ ldmia r1,{r1,r3,r5,r7} -+ ldmia r2,{r2,r4,r6,r8} -+ -+ cmp r7,#0x7fffffff -+ cmpne r8,#0x7fffffff -+ beq CPDO_muf_extra -+ -+ eor r1,r1,r2 -+ adds r8,r7,r8 -+ bvs CPDO_zero_1 -+ -+ umull r7,r2,r3,r4 -+ umull r14,r3,r6,r3 -+ adds r7,r7,r3 @ r2|r7|r14 = r2|r7|#0 + #0|r3|r14 -+ adc r2,r2,#0 -+ umull r4,r3,r5,r4 -+ adds r14,r14,r4 @ r2|r7|r14 += #0|r3|r4 -+ adcs r7,r7,r3 -+ adc r2,r2,#0 -+ umull r4,r3,r5,r6 -+ adds r14,r14,r3 @ r2|r7|r14 += #0|#0|r3 -+ adcs r7,r7,#0 -+ adcs r2,r2,#0 -+ -+ bpl CPDO_muf_norm -+ -+ add r8,r8,#1 -+ b CPDO_muf_end -+ -+CPDO_muf_norm: -+ adds r14,r14,r14 -+ adcs r7,r7,r7 -+ adcs r2,r2,r2 -+ -+CPDO_muf_end: -+ cmp r8,#0x20000000 -+ bge CPDO_inf -+ cmp r8,#0xe0000000 -+ ble CPDO_zero_1 -+ stmia r0,{r1,r2,r7,r8} -+ b fastfpe_next -+ -+CPDO_muf_extra: -+ cmp r7,#0x7fffffff @ was it the first? -+ bne CPDO_muf_extra_2nd @ no, so it was the second -+ cmp r8,#0x7fffffff @ yes, second too? -+ bne CPDO_muf_extra_1st @ no, only first -+ orr r3,r3,r4 @ if both inf -> inf, otherwise nan -+ eor r1,r1,r2 @ sign for the inf case -+ b CPDO_infnan_1 -+ -+CPDO_muf_extra_1st: -+ cmp r3,#0 @ is it a nan? -+ bne CPDO_infnan_1 -+ cmp r8,#0x80000000 @ is the second 0? -+ beq CPDO_nan -+ eor r1,r1,r2 @ correct sign for inf -+ b CPDO_inf -+ -+CPDO_muf_extra_2nd: -+ cmp r4,#0 @ is it a nan? -+ bne CPDO_infnan_2 -+ cmp r7,#0x80000000 @ is the first 0? -+ beq CPDO_nan -+ eor r1,r1,r2 @ correct sign for inf -+ b CPDO_inf -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDO_dvf -+CPDO_dvf: -+ ldmia r1,{r1,r3,r5,r7} -+ ldmia r2,{r2,r4,r6,r8} -+ -+CPDO_dvf_l: -+ cmp r7,#0x7fffffff -+ cmpne r8,#0x7fffffff -+ beq CPDO_dvf_extra -+ cmp r8,#0x80000000 -+ beq CPDO_dvf_by0 -+ -+ eor r1,r1,r2 -+ cmp r7,#0x80000000 -+ beq CPDO_zero_1 -+ -+ sub r8,r7,r8 -+ -+ mov r2,#0 -+ mov r7,#1 -+ -+ cmp r3,r4 -+ cmpeq r5,r6 -+ bcs CPDO_dvf_loop_ -+ -+ sub r8,r8,#1 -+ -+CPDO_dvf_loop: -+ adds r5,r5,r5 -+ adcs r3,r3,r3 -+ bcs CPDO_dvf_anyway -+CPDO_dvf_loop_: -+ subs r5,r5,r6 -+ sbcs r3,r3,r4 -+ bcs CPDO_dvf_okay -+ -+ adds r5,r5,r6 -+ adc r3,r3,r4 -+ adds r7,r7,r7 -+ adcs r2,r2,r2 -+ bcc CPDO_dvf_loop -+ b CPDO_dvf_end -+ -+CPDO_dvf_anyway: -+ adcs r7,r7,r7 -+ adcs r2,r2,r2 -+ bcs CPDO_dvf_end -+ subs r5,r5,r6 -+ sbc r3,r3,r4 -+ b CPDO_dvf_loop -+ -+CPDO_dvf_okay: -+ adcs r7,r7,r7 -+ adcs r2,r2,r2 -+ bcc CPDO_dvf_loop -+ -+CPDO_dvf_end: -+ b CPDO_muf_end -+ -+CPDO_dvf_by0: -+ cmp R7,#0x80000000 -+ beq CPDO_nan @ first also 0 -> nan -+ eor r1,r1,r2 @ otherwise calculatesign for inf -+ b CPDO_inf -+ -+CPDO_dvf_extra: -+ cmp r7,#0x7fffffff @ was it the first? -+ bne CPDO_dvf_extra_2nd @ no, so it was the second -+ cmp r8,#0x7fffffff @ yes, second too? -+ bne CPDO_dvf_extra_1st @ no, only first -+ orrs r3,r3,r4 -+ beq CPDO_nan @ if both inf -> create nan -+ b CPDO_nan_12 @ otherwise keep nan -+ -+CPDO_dvf_extra_1st: -+ eor r1,r1,r2 @ correct sign for inf -+ b CPDO_infnan_1 -+ -+CPDO_dvf_extra_2nd: -+ cmp r4,#0 @ is it a nan? -+ bne CPDO_infnan_2 -+ eor r1,r1,r2 @ correct sign for zero -+ b CPDO_zero_1 -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDO_rdf -+CPDO_rdf: -+ mov r3,r2 -+ ldmia r1,{r2,r4,r6,r8} -+ ldmia r3,{r1,r3,r5,r7} -+ b CPDO_dvf_l -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDO_rmf -+CPDO_rmf: -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDO_mvf -+CPDO_mvf: -+ ldmia r2,{r1,r2,r3,r4} -+ stmia r0,{r1,r2,r3,r4} -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDO_mnf -+CPDO_mnf: -+ ldmia r2,{r1,r2,r3,r4} -+ eor r1,r1,#0x80000000 -+ stmia r0,{r1,r2,r3,r4} -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDO_abs -+CPDO_abs: -+ ldmia r2,{r1,r2,r3,r4} -+ bic r1,r1,#0x80000000 -+ stmia r0,{r1,r2,r3,r4} -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDO_sqt -+CPDO_sqt: -+ ldmia r2,{r1,r2,r3,r4} -+ cmp r1,#0 -+ bne CPDO_nan -+ cmp r4,#0x7fffffff -+ beq CPDO_store_1234 -+ -+ tst r4,r4,lsr#1 @carry=exponent bit 0 -+ bcc CPDO_sqt_exponenteven -+ adds r3,r3,r3 -+ adcs r2,r2,r2 @carry is needed in loop! -+CPDO_sqt_exponenteven: -+ mov r4,r4,asr #1 -+ str r4,[r0,#12] -+ -+ mov r4,#0x80000000 -+ mov r5,#0 -+ sub r2,r2,#0x80000000 -+ -+ mov r8,#0x40000000 -+ mov r14,#0x80000000 -+ -+ mov r1,#1 -+ b CPDO_sqt_loop1_first -+CPDO_sqt_loop1: -+ adds r3,r3,r3 -+ adcs r2,r2,r2 -+CPDO_sqt_loop1_first: -+ add r6,r4,r8,lsr r1 @r7 const = r5 -+ bcs CPDO_sqt_loop1_1 -+ cmp r2,r6 -+ cmpeq r3,r5 @r5 for r7 -+ bcc CPDO_sqt_loop1_0 -+CPDO_sqt_loop1_1: -+ orr r4,r4,r14,lsr r1 -+ subs r3,r3,r5 @r5 for r7 -+ sbc r2,r2,r6 -+CPDO_sqt_loop1_0: -+ add r1,r1,#1 -+ cmp r1,#30 -+ ble CPDO_sqt_loop1 -+ -+ adds r3,r3,r3 -+ adcs r2,r2,r2 -+ bcs CPDO_sqt_between_1 -+ adds r7,r5,#0x80000000 -+ adc r6,r4,#0 -+ cmp r2,r6 -+ cmpeq r3,r7 -+ bcc CPDO_sqt_between_0 -+CPDO_sqt_between_1: -+ orr r4,r4,#0x00000001 -+ subs r3,r3,r5 -+ sbc r2,r2,r4 -+ subs r3,r3,#0x80000000 -+ sbc r2,r2,#0 -+CPDO_sqt_between_0: -+ mov r1,#0 -+ -+CPDO_sqt_loop2: -+ adds r3,r3,r3 -+ adcs r2,r2,r2 -+ bcs CPDO_sqt_loop2_1 -+ adds r7,r5,r8,lsr r1 -+ adc r6,r4,#0 -+ cmp r2,r6 -+ cmpeq r3,r7 -+ bcc CPDO_sqt_loop2_0 -+CPDO_sqt_loop2_1: -+ orr r5,r5,r14,lsr r1 -+ subs r3,r3,r5 -+ sbc r2,r2,r4 -+ subs r3,r3,r8,lsr r1 -+ sbc r2,r2,#0 -+CPDO_sqt_loop2_0: -+ add r1,r1,#1 -+ cmp r1,#30 -+ ble CPDO_sqt_loop2 -+ -+ adds r3,r3,r3 -+ adcs r2,r2,r2 -+ bcs CPDO_sqt_after_1 -+ cmp r2,r6 -+ cmpeq r3,r7 -+ bcc CPDO_sqt_after_0 -+CPDO_sqt_after_1: -+ orr r5,r5,#0x00000001 -+CPDO_sqt_after_0: -+ -+ mov r1,#0 -+ stmia r0,{r1,r4,r5} -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDO_rnd -+CPDO_rnd: -+ ldmia r2,{r1,r2,r3,r5} -+ bl CPDO_rnd_core -+ -+CPDO_rnd_store: -+ stmia r0,{r1,r2,r3,r5} -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDO_rnd_core -+CPDO_rnd_core: -+ and r4,r4,#0x00000060 -+ add pc,pc,r4,lsr#3 -+ mov r0,r0 -+ b CPDO_rnd_N -+ b CPDO_rnd_P -+ b CPDO_rnd_M -+ b CPDO_rnd_Z -+ -+CPDO_rnd_N: -+ cmp r5,#-1 -+ blt CPDO_rnd_zero -+ cmp r5,#63 -+ movge pc,r14 -+ mov r4,#0x40000000 -+ cmp r5,#31 -+ bge CPDO_rnd_N_2 -+ -+ adds r2,r2,r4,lsr r5 -+ bcc CPDO_rnd_end -+ b CPDO_rnd_end_norm -+ -+CPDO_rnd_N_2: -+CPDO_rnd_P_2: -+ sub r6,r5,#32 -+ adds r3,r3,r4,ror r6 @ror ist needed to handle a -1 correctly -+ adcs r2,r2,#0 -+ bcc CPDO_rnd_end -+ b CPDO_rnd_end_norm -+ -+CPDO_rnd_P: -+ tst r1,#0x80000000 -+ bne CPDO_rnd_M_entry -+CPDO_rnd_P_entry: -+ cmp r5,#0 -+ blt CPDO_rnd_P_small -+ cmp r5,#63 -+ movge pc,r14 -+ mov r4,#0x7fffffff -+ cmp r5,#32 -+ bge CPDO_rnd_P_2 -+ -+ adds r3,r3,#0xffffffff -+ adcs r2,r2,r4,lsr r5 -+ bcc CPDO_rnd_end -+ b CPDO_rnd_end_norm -+ -+CPDO_rnd_P_small: -+ cmp r5,#0x80000000 -+ moveq pc,r14 -+ b CPDO_rnd_one -+ -+CPDO_rnd_M: -+ tst r1,#0x80000000 -+ bne CPDO_rnd_P_entry -+CPDO_rnd_M_entry: -+ cmp r5,#0 -+ blt CPDO_rnd_zero -+ cmp r5,#63 -+ movge pc,r14 -+ -+ b CPDO_rnd_end -+ -+CPDO_rnd_Z: -+ cmp r5,#0 -+ blt CPDO_rnd_zero -+ cmp r5,#63 -+ movge pc,r14 -+ b CPDO_rnd_end -+ -+CPDO_rnd_end_norm: -+ add r5,r5,#1 -+ movs r2,r2,rrx -+ mov r3,r3,rrx -+CPDO_rnd_end: -+ rsbs r4,r5,#31 -+ bmi CPDO_rnd_end_2 -+ mov r3,#0 -+ mov r2,r2,lsr r4 -+ mov r2,r2,lsl r4 -+ mov pc,r14 -+ -+CPDO_rnd_end_2: -+ rsb r4,r5,#63 -+ mov r3,r3,lsr r4 -+ mov r3,r3,lsl r4 -+ mov pc,r14 -+ -+CPDO_rnd_one: -+ mov r2,#0x80000000 -+ mov r3,#0 -+ mov r5,#0 -+ mov pc,r14 -+ -+CPDO_rnd_zero: -+ mov r1,#0 -+ mov r2,#0 -+ mov r3,#0 -+ mov r5,#0x80000000 -+ mov pc,r14 -+ -+/*---------------------------------------------------------------------------*/ -diff -urN linux-2.4.26/arch/arm/fastfpe/CPDT.S linux-2.4.26-vrs1/arch/arm/fastfpe/CPDT.S ---- linux-2.4.26/arch/arm/fastfpe/CPDT.S 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/fastfpe/CPDT.S 2004-01-14 21:32:23.000000000 +0000 -@@ -0,0 +1,430 @@ -+/* -+The FP structure has 4 words reserved for each register, the first is used just -+for the sign in bit 31, the second and third are for the mantissa (unsigned -+integer, high 32 bit first) and the fourth is the exponent (signed integer). -+The mantissa is always normalized. -+ -+If the exponent is 0x80000000, that is the most negative value, the number -+represented is 0 and both mantissa words are also 0. -+ -+If the exponent is 0x7fffffff, that is the biggest positive value, the number -+represented is infinity if the high 32 mantissa bit are also 0, otherwise it is -+a NaN. The low 32 mantissa bit are 0 if the number represented is infinity. -+ -+Decimal and packed decimal numbers are not supported yet. -+*/ -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDT_load_single -+CPDT_load_single: -+ ldr r1,[r6] -+ -+ and r2,r1,#0x80000000 @ r2 = sign -+ -+ mov r5,r1,lsr#23 -+ bics r5,r5,#0x100 -+ beq CPDT_ls_e0 @ exponent = 0; zero/denormalized -+ teq r5,#255 -+ beq CPDT_ls_e255 @ exponent = 255; infinity/NaN -+ -+ sub r5,r5,#127 @ r5 = exponent, remove normalized bias -+ -+ mov r3,r1,lsl#8 -+ orr r3,r3,#0x80000000 -+ mov r4,#0 @ r3,r4 = mantissa -+ -+ stmia r0,{r2-r5} -+ b fastfpe_next -+ -+CPDT_ls_e0: -+ movs r3,r1,lsl#9 -+ beq CPDT_load_zero -+ -+ mov r5,#-127 -+ -+CPDT_ls_e0_norm: -+ tst r3,#0x80000000 -+ subeq r5,r5,#1 -+ moveq r3,r3,lsl#1 -+ beq CPDT_ls_e0_norm -+ -+ mov r4,#0 -+ stmia r0,{r2-r5} -+ b fastfpe_next -+ -+CPDT_ls_e255: -+ mov r3,r1,lsl#9 -+ mov r4,#0 -+ mov r5,#0x7fffffff -+ stmia r0,{r2-r5} -+ b fastfpe_next -+ -+CPDT_load_zero: -+ mov r3,#0 -+ mov r4,#0 -+ mov r5,#0x80000000 -+ stmia r0,{r2-r5} -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDT_load_double -+CPDT_load_double: -+ ldr r1,[r6] -+ ldr r6,[r6,#4] -+ -+ and r2,r1,#0x80000000 @ r2 = sign -+ -+ mov r5,r1,lsr#20 -+ bics r5,r5,#0x800 -+ beq CPDT_ld_e0 @ exponent = 0; zero/denormalized -+ add r4,r5,#1 -+ teq r4,#2048 -+ beq CPDT_ld_e2047 @ exponent = 2047; infinity/NaN -+ -+ add r5,r5,#1 -+ sub r5,r5,#1024 @ r5 = exponent, remove normalized bias -+ -+ mov r3,r1,lsl#11 -+ orr r3,r3,#0x80000000 -+ orr r3,r3,r6,lsr #21 -+ mov r4,r6,lsl#11 @ r3,r4 = mantissa -+ -+ stmia r0,{r2-r5} -+ b fastfpe_next -+ -+CPDT_ld_e0: -+ mov r3,r1,lsl#12 -+ orr r3,r3,r6,lsr#20 -+ movs r4,r6,lsl#12 -+ teqeq r3,#0 -+ beq CPDT_load_zero -+ -+ mov r5,#1 -+ sub r5,r5,#1024 -+ -+CPDT_ld_e0_norm: -+ tst r3,#0x80000000 -+ subeq r5,r5,#1 -+ moveqs r4,r4,lsl#1 -+ adceq r3,r3,r3 -+ beq CPDT_ld_e0_norm -+ -+ stmia r0,{r2-r5} -+ b fastfpe_next -+ -+CPDT_ld_e2047: -+ mov r3,r1,lsl#12 -+ orr r3,r3,r6,lsr#1 -+ bic r6,r6,#0x80000000 -+ orr r3,r3,r6 @ to get all fraction bits ! -+ mov r4,#0 -+ mov r5,#0x7fffffff -+ stmia r0,{r2-r5} -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDT_load_extended -+CPDT_load_extended: -+ ldr r1,[r6] -+ ldr r3,[r6,#4] -+ ldr r4,[r6,#8] -+ -+ and r2,r1,#0x80000000 -+ bics r5,r1,#0x80000000 -+ beq CPDT_le_e0 -+ add r1,r5,#1 -+ teq r4,#32768 -+ beq CPDT_le_e32767 -+ -+ add r5,r5,#1 -+ sub r5,r5,#16384 -+ -+ stmia r0,{r2-r5} -+ b fastfpe_next -+ -+CPDT_le_e0: -+ teq r3,#0 -+ teqeq r4,#0 -+ beq CPDT_load_zero -+ -+ mov r5,#2 -+ sub r5,r5,#16384 -+ b CPDT_ld_e0_norm -+ -+CPDT_le_e32767: -+ mov r3,r3,lsl#1 -+ orr r3,r3,r4,lsr#1 -+ bic r4,r4,#0x80000000 -+ orr r3,r3,r4 -+ mov r5,#0x7fffffff -+ stmia r0,{r2-r5} -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDT_load_decimal -+CPDT_load_decimal: -+ -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDT_store_single -+CPDT_store_single: -+ ldmia r0,{r1-r4} -+ -+ cmp r4,#-127 -+ ble CPDT_ss_e0 -+ cmp r4,#128 -+ bge CPDT_ss_e255 -+ -+ adds r2,r2,#1<<7 @ round to nearest -+ bcs CPDT_ss_rnd_ovfl @ very very seldom taken -+ -+CPDT_ss_store: -+ add r4,r4,#127 -+ orr r1,r1,r4,lsl#23 -+ -+ bic r2,r2,#0x80000000 -+ orr r1,r1,r2,lsr#8 -+ -+ str r1,[r6] -+ b fastfpe_next -+ -+CPDT_ss_rnd_ovfl: -+ add r4,r4,#1 -+ cmp r4,#128 -+ bge CPDT_ss_e255 -+ -+ mov r2,#0x80000000 -+ mov r3,#0 -+ b CPDT_ss_store -+ -+CPDT_ss_e0: -+ cmp r4,#-150 -+ ble CPDT_ss_zero -+ -+ add r4,r4,#126 -+CPDT_ss_unnormalize: -+ mov r2,r2,lsr#1 -+ adds r4,r4,#1 -+ bne CPDT_ss_unnormalize -+ -+ orr r1,r1,r2,lsr#8 -+ -+CPDT_ss_zero: -+ str r1,[r6] -+ b fastfpe_next -+ -+CPDT_ss_e255: -+ cmp r4,#0x7fffffff -+ bne CPDT_ss_inf -+ cmp r2,#0 -+ beq CPDT_ss_inf -+ -+ orr r1,r1,#0x00200000 @ for safety so that it is not INF -+ orr r1,r1,r2,lsr#9 @ get highest bit of mantissa -+ -+CPDT_ss_inf: -+ orr r1,r1,#0x7f000000 -+ orr r1,r1,#0x00800000 -+ str r1,[r6] -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDT_store_double -+CPDT_store_double: -+ ldmia r0,{r1-r4} -+ -+ cmp r4,#1024 @ this check has to be first, or -+ bge CPDT_sd_e2047 @ overflow can occur on second ! -+ add r0,r4,#3 -+ cmp r0,#-1023+3 @ cmp with -1023 -+ ble CPDT_sd_e0 -+ -+ adds r3,r3,#1<<10 @ round to nearest -+ adcs r2,r2,#0 -+ bcs CPDT_sd_rnd_ovfl @ very very seldom taken -+ -+CPDT_sd_store: -+ sub r4,r4,#1 -+ add r4,r4,#1024 -+ orr r1,r1,r4,lsl#20 -+ -+ bic r2,r2,#0x80000000 -+ orr r1,r1,r2,lsr#11 -+ -+ mov r2,r2,lsl#21 -+ orr r2,r2,r3,lsr#11 -+ -+ stmia r6,{r1,r2} -+ b fastfpe_next -+ -+CPDT_sd_rnd_ovfl: -+ add r4,r4,#1 -+ cmp r4,#1024 -+ bge CPDT_sd_e2047 -+ -+ mov r2,#0x80000000 -+ mov r3,#0 -+ b CPDT_sd_store -+ -+CPDT_sd_e0: -+ add r0,r4,#1075-1024 -+ cmp r0,#-1024 -+ ble CPDT_sd_zero -+ -+ add r4,r4,#1024 -+ sub r4,r4,#2 -+CPDT_sd_unnormalize: -+ movs r2,r2,lsr#1 -+ mov r3,r3,rrx -+ adds r4,r4,#1 -+ bne CPDT_sd_unnormalize -+ -+ orr r1,r1,r2,lsr#11 -+ mov r2,r2,lsl#21 -+ orr r2,r2,r3,lsr#11 -+ -+ stmia r6,{r1,r2} -+ b fastfpe_next -+ -+CPDT_sd_zero: -+ mov r2,#0 -+ stmia r6,{r1,r2} -+ b fastfpe_next -+ -+CPDT_sd_e2047: -+ cmp r4,#0x7fffffff -+ bne CPDT_sd_inf -+ cmp r2,#0 -+ beq CPDT_sd_inf -+ -+ orr r1,r1,#0x00040000 @ for safety so that it is not INF -+ orr r1,r1,r2,lsr#12 @ get highest bit of mantissa -+ -+CPDT_sd_inf: -+ orr r1,r1,#0x7f000000 -+ orr r1,r1,#0x00f00000 -+ stmia r6,{r1,r2} -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDT_store_extended -+CPDT_store_extended: -+ ldmia r0,{r1-r4} -+ -+ cmp r4,#16384 @ this check has to be first, or -+ bge CPDT_se_e32767 @ overflow can occur with second ! -+ add r0,r4,#63 -+ cmp r0,#-16383+63 -+ ble CPDT_se_e0 -+ -+ sub r4,r4,#1 -+ add r4,r4,#16384 -+ orr r1,r1,r4 -+ -+ stmia r6,{r1-r3} -+ b fastfpe_next -+ -+CPDT_se_e0: -+ add r0,r4,#16446-16384 -+ cmp r0,#-16384 -+ ble CPDT_se_zero -+ -+ add r4,r4,#16384 -+ sub r4,r4,#2 -+CPDT_se_unnormalize: -+ movs r2,r2,lsr#1 -+ mov r3,r3,rrx -+ adds r4,r4,#1 -+ bne CPDT_se_unnormalize -+ -+ stmia r6,{r1-r3} -+ b fastfpe_next -+ -+CPDT_se_zero: -+ mov r2,#0 -+ mov r3,#0 -+ stmia r6,{r1-r3} -+ b fastfpe_next -+ -+CPDT_se_e32767: -+ cmp r4,#0x7fffffff -+ bne CPDT_se_inf -+ cmp r2,#0 -+ beq CPDT_se_inf -+ -+ mov r2,r2,lsl#1 -+ orr r2,r2,#0x20000000 -+ -+CPDT_se_inf: -+ orr r1,r1,#0x00007f00 -+ orr r1,r1,#0x000000ff -+ stmia r6,{r1-r3} -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDT_store_decimal -+CPDT_store_decimal: -+ -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDT_sfm -+CPDT_sfm: -+ add r2,r10,r0,lsr#8 -+ ldr r4,[r2,#0] -+ ldr r3,[r2,#4] -+ bic r3,r3,#0x80000000 -+ orr r3,r3,r4 -+ str r3,[r6],#4 -+ ldr r3,[r2,#8] -+ str r3,[r6],#4 -+ ldr r3,[r2,#12] -+ str r3,[r6],#4 -+ -+ add r0,r0,#1<<12 -+ and r0,r0,#7<<12 -+ subs r1,r1,#1 -+ bne CPDT_sfm -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPDT_lfm -+CPDT_lfm: -+ add r2,r10,r0,lsr#8 -+ ldr r4,[r6],#4 -+ and r3,r4,#0x80000000 -+ str r3,[r2,#0] -+ ldr r3,[r6],#4 -+ str r3,[r2,#8] -+ ldr r3,[r6],#4 -+ str r3,[r2,#12] -+ -+ cmp r3,#0x80000000 @ does the exp indicate zero? -+ biceq r4,r4,#0x80000000 @ if so, indicate 'denormalized' -+ beq CPDT_lfm_storer4 -+ cmp r3,#0x7fffffff @ does the exp indicate inf or NaN? -+ biceq r4,r4,#0x80000000 @ if so, indicate 'denormalized' -+ beq CPDT_lfm_storer4 -+ orrne r4,r4,#0x80000000 @ otherwise, set normalized bit -+ -+CPDT_lfm_storer4: -+ str r4,[r2,#4] -+ -+ add r0,r0,#1<<12 -+ and r0,r0,#7<<12 -+ subs r1,r1,#1 -+ bne CPDT_lfm -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -diff -urN linux-2.4.26/arch/arm/fastfpe/CPRT.S linux-2.4.26-vrs1/arch/arm/fastfpe/CPRT.S ---- linux-2.4.26/arch/arm/fastfpe/CPRT.S 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/fastfpe/CPRT.S 2004-01-14 21:32:23.000000000 +0000 -@@ -0,0 +1,185 @@ -+/* -+The FP structure has 4 words reserved for each register, the first is used -+just -+for the sign in bit 31, the second and third are for the mantissa (unsigned -+integer, high 32 bit first) and the fourth is the exponent (signed integer). -+The mantissa is always normalized. -+ -+If the exponent is 0x80000000, that is the most negative value, the number -+represented is 0 and both mantissa words are also 0. -+ -+If the exponent is 0x7fffffff, that is the biggest positive value, the -+number -+represented is infinity if the high 32 mantissa bit are also 0, otherwise it -+is -+a NaN. The low 32 mantissa bit are 0 if the number represented is infinity. -+ -+Decimal and packed decimal numbers are not supported yet. -+*/ -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .text -+ .globl CPRT_flt -+CPRT_flt: -+ add r0,r13,r0,lsr#10 -+ ldr r2,[r0] -+ mov r3,#0 -+ cmp r2,#0 -+ beq CPRT_flt_zero -+ -+ ands r0,r2,#0x80000000 -+ rsbne r2,r2,#0 -+ mov r4,#31 -+ -+ cmp r2,#0x00010000 -+ movcc r2,r2,lsl#16 -+ subcc r4,r4,#16 -+ -+ cmp r2,#0x01000000 -+ movcc r2,r2,lsl#8 -+ subcc r4,r4,#8 -+ -+ cmp r2,#0x10000000 -+ movcc r2,r2,lsl#4 -+ subcc r4,r4,#4 -+ -+ cmp r2,#0x40000000 -+ movcc r2,r2,lsl#2 -+ subcc r4,r4,#2 -+ -+ cmp r2,#0x80000000 -+ movcc r2,r2,lsl#1 -+ subcc r4,r4,#1 -+ -+ stmia r1,{r0,r2,r3,r4} -+ b fastfpe_next -+ -+CPRT_flt_zero: -+ mov r0,#0 -+ mov r4,#0x80000000 -+ stmia r1,{r0,r2,r3,r4} -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPRT_fix -+CPRT_fix: -+ ldmia r2,{r1,r2,r3,r5} -+ bl CPDO_rnd_core -+ -+CPRT_back: -+ add r0,r13,r0,lsr#10 -+ cmp r5,#0 -+ blt CPRT_int_zero -+ cmp r5,#30 -+ bgt CPRT_overflow -+ -+ rsb r5,r5,#31 -+ mov r2,r2,lsr r5 -+ tst r1,#0x80000000 -+ rsbne r2,r2,#0 -+ -+ str r2,[r0] -+ b fastfpe_next -+ -+CPRT_int_zero: -+ mov r2,#0 -+ str r2,[r0] -+ b fastfpe_next -+ -+CPRT_overflow: -+ mov r2,#0x80000000 -+ tst r1,#0x80000000 -+ subeq r2,r2,#1 -+ str r2,[r0] -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPRT_wfs -+CPRT_wfs: -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPRT_rfs -+CPRT_rfs: -+ add r0,r13,r0,lsr#10 -+ mov r1,#0x02000000 @ Software Emulation, not Acorn FPE -+ str r1,[r0] -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPRT_cmf -+CPRT_cmf: -+ ldmia r1,{r1,r3,r5,r7} -+ ldmia r2,{r2,r4,r6,r8} -+ -+CPRT_cmf_e: -+ ldr r0,[r13,#16*4] -+ -+ cmp r7,#0x7fffffff -+ bic r0,r0,#0xf0000000 -+ -+ cmpeq r3,#0xffffffff -+ beq CPRT_cmf_unordered -+ cmp r8,#0x7fffffff -+ cmpeq r4,#0xffffffff -+ beq CPRT_cmf_unordered -+ -+ cmp r1,r2 -+ beq CPRT_cmf_equalsign -+ b CPRT_cmf_sign -+ -+CPRT_cmf_equalsign: -+ cmp r7,r8 -+ beq CPRT_cmf_equalexponent -+ bgt CPRT_cmf_sign -+ b CPRT_cmf_signb -+ -+CPRT_cmf_equalexponent: -+ cmp r3,r4 -+ cmpeq r5,r6 -+ beq CPRT_cmf_equal -+ bhi CPRT_cmf_sign -+ b CPRT_cmf_signb -+ -+CPRT_cmf_sign: -+ cmp r7,#0x80000000 @ (0.0 == -0.0)? -+ cmpeq r7,r8 -+ beq CPRT_cmf_equal -+ tst r1,#0x80000000 -+ orreq r0,r0,#0x20000000 -+ orrne r0,r0,#0x80000000 -+ str r0,[r13,#16*4] -+ b fastfpe_next -+ -+CPRT_cmf_signb: -+ tst r1,#0x80000000 -+ orrne r0,r0,#0x20000000 -+ orreq r0,r0,#0x80000000 -+ str r0,[r13,#16*4] -+ b fastfpe_next -+ -+CPRT_cmf_equal: -+ orr r0,r0,#0x60000000 -+ str r0,[r13,#16*4] -+ b fastfpe_next -+ -+CPRT_cmf_unordered: -+ orr r0,r0,#0x10000000 -+ str r0,[r13,#16*4] -+ b fastfpe_next -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl CPRT_cnf -+CPRT_cnf: -+ ldmia r1,{r1,r3,r5,r7} -+ ldmia r2,{r2,r4,r6,r8} -+ eor r2,r2,#0x80000000 -+ b CPRT_cmf_e -+ -+/*---------------------------------------------------------------------------*/ -diff -urN linux-2.4.26/arch/arm/fastfpe/Makefile linux-2.4.26-vrs1/arch/arm/fastfpe/Makefile ---- linux-2.4.26/arch/arm/fastfpe/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/fastfpe/Makefile 2004-01-14 21:32:23.000000000 +0000 -@@ -0,0 +1,25 @@ -+# -+# linux/arch/arm/fastfpe/Makefile -+# -+# Copyright (C) Peter Teichmann -+# -+ -+O_TARGET := fast-math-emu.o -+ -+obj-y := -+obj-m := -+obj-n := -+obj- := -+ -+fastfpe-objs := module.o entry.o CPDO.o CPRT.o CPDT.o -+ -+list-multi := fastfpe.o -+ -+obj-$(CONFIG_FPE_FASTFPE) += fastfpe.o -+ -+USE_STANDARD_AS_RULE := true -+ -+include $(TOPDIR)/Rules.make -+ -+fastfpe.o: $(fastfpe-objs) -+ $(LD) -r -o $@ $(fastfpe-objs) -diff -urN linux-2.4.26/arch/arm/fastfpe/entry.S linux-2.4.26-vrs1/arch/arm/fastfpe/entry.S ---- linux-2.4.26/arch/arm/fastfpe/entry.S 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/fastfpe/entry.S 2004-01-14 21:32:23.000000000 +0000 -@@ -0,0 +1,295 @@ -+/* -+At entry the registers contain the following information: -+ -+r14 return address for undefined exception return -+r9 return address for return from exception -+r13 user registers on stack, offset 0 up to offset 4*15 contains -+ registers r0..15, then the psr -+r10 FP workspace 35 words (init, reg[8][4], fpsr, fpcr) -+ -+*/ -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .data -+fp_const: -+ .word 0, 0x00000000, 0, 0x80000000 @ 0 -+ .word 0, 0x80000000, 0, 0 @ 1 -+ .word 0, 0x80000000, 0, 1 @ 2 -+ .word 0, 0xc0000000, 0, 1 @ 3 -+ .word 0, 0x80000000, 0, 2 @ 4 -+ .word 0, 0xa0000000, 0, 2 @ 5 -+ .word 0, 0x80000000, 0, -1 @ 0.5 -+ .word 0, 0xa0000000, 0, 3 @ 10 -+fp_undef: -+ .word 0 -+fp_cond: -+ .word 0xf0f0 @ eq -+ .word 0x0f0f @ ne -+ .word 0xcccc @ cs -+ .word 0x3333 @ cc -+ .word 0xff00 @ mi -+ .word 0x00ff @ pl -+ .word 0xaaaa @ vs -+ .word 0x5555 @ vc -+ .word 0x0c0c @ hi -+ .word 0xf3f3 @ ls -+ .word 0xaa55 @ ge -+ .word 0x55aa @ lt -+ .word 0x0a05 @ gt -+ .word 0xf5fa @ le -+ .word 0xffff @ al -+ .word 0x0000 @ nv -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .text -+ .globl fastfpe_enter -+fastfpe_enter: -+ ldr r4,=fp_undef -+ str r14,[r4] @ to free one register -+ add r10,r10,#4 @ to make the code simpler -+ ldr r4,[r13,#60] @ r4=saved PC -+ ldr r4,[r4,#-4] @ r4=trapped instruction -+ and r1,r4,#0x00000f00 @ r1=coprocessor << 8 -+next_enter: -+ cmp r1,#1<<8 @ copro 1 ? -+ beq copro_1 -+ cmp r1,#2<<8 -+ movne pc,r14 -+ -+copro_2: -+ and r1,r4,#0x0f000000 -+ cmp r1,#0x0c000000 @ CPDT with post indexing -+ cmpne r1,#0x0d000000 @ CPDT with pre indexing -+ beq CPDT_M_enter -+ mov pc,r14 -+ -+copro_1: -+ and r1,r4,#0x0f000000 -+ cmp r1,#0x0e000000 @ CPDO -+ beq CPDO_CPRT_enter -+ cmp r1,#0x0c000000 @ CPDT with post indexing -+ cmpne r1,#0x0d000000 @ CPDT with pre indexing -+ beq CPDT_1_enter -+ mov pc,r14 -+ -+/*---------------------------------------------------------------------------*/ -+ -+ .globl fastfpe_next -+fastfpe_next: -+ ldr r5,[r13,#60] -+next_after_cond: -+__x1: -+ ldrt r4,[r5],#4 -+ -+ ldr r0,=fp_cond @ check condition of next instruction -+ ldr r1,[r13,#64] @ psr containing flags -+ mov r2,r4,lsr#28 -+ mov r1,r1,lsr#28 -+ ldr r0,[r0,r2,lsl#2] -+ mov r0,r0,lsr r1 -+ tst r0,#1 -+ beq next_after_cond @ must not necessarily have been an -+ @ FP instruction ! -+ and r1,r4,#0x0f000000 @ Test for copro instruction -+ cmp r1,#0x0c000000 -+ rsbgts r0,r1,#0x0e000000 @ cmpgt #0x0e000000,r1 -+ movlt pc,r9 @ next is no copro instruction, return -+ -+ ands r1,r4,#0x00000f00 @ r1 = coprocessor << 8 -+ cmpne r1,#3<<8 -+ movge pc,r9 @ copro = 0 or >=3, return -+ -+ str r5,[r13,#60] @ save updated pc -+ b next_enter -+ -+/*---------------------------------------------------------------------------*/ -+ -+undefined: -+ ldr r4,=fp_undef -+ ldr pc,[r4] -+ -+/*---------------------------------------------------------------------------*/ -+ -+CPDT_1_enter: -+ and r5,r4,#0x000f0000 @ r5=base register number << 16 -+ ldr r6,[r13,r5,lsr#14] @ r6=base address -+ cmp r5,#0x000f0000 @ base register = pc ? -+ addeq r6,r6,#4 -+ and r7,r4,#0x000000ff @ r7=offset value -+ -+ tst r4,#0x00800000 @ up or down? -+ addne r7,r6,r7,lsl#2 -+ subeq r7,r6,r7,lsl#2 @ r6=base address +/- offset -+ tst r4,#0x01000000 @ preindexing ? -+ movne r6,r7 -+ tst r4,#0x00200000 @ write back ? -+ cmpne r5,#0x000f0000 @ base register = pc ? -+ strne r7,[r13,r5,lsr#14] -+ -+ and r0,r4,#0x00007000 @ r0=fp register number << 12 -+ add r0,r10,r0,lsr#8 @ r0=address of fp register -+ mov r1,#0 -+ tst r4,#0x00008000 -+ orrne r1,r1,#1 @ T0 -+ tst r4,#0x00400000 -+ orrne r1,r1,#2 @ T1 -+ tst r4,#0x00100000 -+ orrne r1,r1,#4 @ L/S -+ -+ add pc,pc,r1,lsl#2 -+ mov r0,r0 -+ b CPDT_store_single @ these functions get -+ b CPDT_store_double @ r0=address of fp register -+ b CPDT_store_extended @ r6=address of data -+ b undefined @ CPDT_store_decimal -+ b CPDT_load_single -+ b CPDT_load_double -+ b CPDT_load_extended -+ b undefined @ CPDT_load_decimal -+ -+/*---------------------------------------------------------------------------*/ -+ -+CPDT_M_enter: -+ and r5,r4,#0x000f0000 @ r5=base register number << 16 -+ ldr r6,[r13,r5,lsr#14] @ r6=base address -+ cmp r5,#0x000f0000 @ base register = pc ? -+ addeq r6,r6,#4 -+ and r7,r4,#0x000000ff @ r7=offset value -+ -+ tst r4,#0x00800000 @ up or down? -+ addne r7,r6,r7,lsl#2 -+ subeq r7,r6,r7,lsl#2 @ r7=base address +/- offset -+ tst r4,#0x01000000 @ preindexing ? -+ movne r6,r7 -+ tst r4,#0x00200000 @ write back ? -+ cmpne r5,#0x000f0000 @ base register = pc ? -+ strne r7,[r13,r5,lsr#14] -+ -+ and r0,r4,#0x00007000 @ r0=fp register number << 12 -+ and r1,r4,#0x00008000 -+ mov r1,r1,lsr#15 @ N0 -+ and r2,r4,#0x00400000 -+ orrs r1,r1,r2,lsr#21 @ N1 -+ addeq r1,r1,#4 @ r1=register count -+ -+ tst r4,#0x00100000 @ load/store -+ beq CPDT_sfm -+ b CPDT_lfm -+ -+/*---------------------------------------------------------------------------*/ -+ -+CPDO_CPRT_enter: -+ tst r4,#0x00000010 -+ bne CPRT_enter -+ -+ and r0,r4,#0x00007000 -+ add r0,r10,r0,lsr#8 @ r0=address of Fd -+ and r1,r4,#0x00070000 -+ add r1,r10,r1,lsr#12 @ r1=address of Fn -+ tst r4,#0x00000008 -+ bne CPDO_const -+ and r2,r4,#0x00000007 -+ add r2,r10,r2,lsl#4 @ r2=address of Fm -+ -+CPDO_constback: -+ and r3,r4,#0x00f00000 -+ tst r4,#0x00008000 -+ orrne r3,r3,#0x01000000 -+ -+ add pc,pc,r3,lsr#18 -+ mov r0,r0 -+ b CPDO_adf -+ b CPDO_muf -+ b CPDO_suf -+ b CPDO_rsf -+ b CPDO_dvf -+ b CPDO_rdf -+ b undefined -+ b undefined -+ b undefined @ CPDO_rmf -+ b CPDO_muf -+ b CPDO_dvf -+ b CPDO_rdf -+ b undefined -+ b undefined -+ b undefined -+ b undefined -+ b CPDO_mvf -+ b CPDO_mnf -+ b CPDO_abs -+ b CPDO_rnd -+ b CPDO_sqt -+ b undefined -+ b undefined -+ b undefined -+ b undefined -+ b undefined -+ b undefined -+ b undefined -+ b undefined -+ b undefined -+ b CPDO_rnd -+ b fastfpe_next -+ -+CPDO_const: -+ ldr r2,=fp_const -+ and r3,r4,#0x00000007 -+ add r2,r2,r3,lsl#4 -+ b CPDO_constback -+ -+/*---------------------------------------------------------------------------*/ -+ -+CPRT_enter: -+ and r0,r4,#0x0000f000 @ r0=Rd<<12 -+ and r1,r4,#0x00070000 -+ add r1,r10,r1,lsr#12 @ r1=address of Fn -+ tst r4,#0x00000008 -+ bne CPRT_const -+ and r2,r4,#0x00000007 -+ add r2,r10,r2,lsl#4 @ r2=address of Fm -+ -+CPRT_constback: -+ and r3,r4,#0x00f00000 -+ -+ add pc,pc,r3,lsr#18 -+ mov r0,r0 -+ b CPRT_flt -+ b CPRT_fix -+ b CPRT_wfs -+ b CPRT_rfs -+ b undefined -+ b undefined -+ b undefined -+ b undefined -+ b undefined -+ b CPRT_cmf -+ b undefined -+ b CPRT_cnf -+ b undefined -+ b CPRT_cmf -+ b undefined -+ b CPRT_cnf -+ -+CPRT_const: -+ ldr r2,=fp_const -+ and r3,r4,#0x00000007 -+ add r2,r2,r3,lsl#4 -+ b CPRT_constback -+ -+/*---------------------------------------------------------------------------*/ -+ -+ @ The fetch of the next instruction to emulate could fault -+ -+ .section .fixup,"ax" -+ .align -+__f1: -+ mov pc,r9 -+ .previous -+ .section __ex_table,"a" -+ .align 3 -+ .long __x1,__f1 -+ .previous -+ -+/*---------------------------------------------------------------------------*/ -diff -urN linux-2.4.26/arch/arm/fastfpe/module.c linux-2.4.26-vrs1/arch/arm/fastfpe/module.c ---- linux-2.4.26/arch/arm/fastfpe/module.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/fastfpe/module.c 2004-01-14 21:32:23.000000000 +0000 -@@ -0,0 +1,78 @@ -+/* -+ Fast Floating Point Emulator -+ (c) Peter Teichmann -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+*/ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifndef MODULE -+#define kern_fp_enter fp_enter -+ -+extern char fpe_type[]; -+#endif -+ -+static void (*orig_fp_enter)(void); /* old kern_fp_enter value */ -+extern void (*kern_fp_enter)(void); /* current FP handler */ -+extern void fastfpe_enter(void); /* forward declarations */ -+ -+#ifdef MODULE -+/* -+ * Return 0 if we can be unloaded. This can only happen if -+ * kern_fp_enter is still pointing at fastfpe_enter -+ */ -+static int fpe_unload(void) -+{ -+ return (kern_fp_enter == fastfpe_enter) ? 0 : 1; -+} -+#endif -+ -+static int __init fpe_init(void) -+{ -+#ifdef MODULE -+ if (!mod_member_present(&__this_module, can_unload)) -+ return -EINVAL; -+ __this_module.can_unload = fpe_unload; -+#else -+ if (fpe_type[0] && strcmp(fpe_type, "fastfpe")) -+ return 0; -+#endif -+ -+ printk("Fast Floating Point Emulator V0.9 (c) Peter Teichmann.\n"); -+ -+ /* Save pointer to the old FP handler and then patch ourselves in */ -+ orig_fp_enter = kern_fp_enter; -+ kern_fp_enter = fastfpe_enter; -+ -+ return 0; -+} -+ -+static void __exit fpe_exit(void) -+{ -+ /* Restore the values we saved earlier. */ -+ kern_fp_enter = orig_fp_enter; -+} -+ -+module_init(fpe_init); -+module_exit(fpe_exit); -+ -+MODULE_AUTHOR("Peter Teichmann "); -+MODULE_DESCRIPTION("Fast floating point emulator with full precision"); -diff -urN linux-2.4.26/arch/arm/kernel/calls.S linux-2.4.26-vrs1/arch/arm/kernel/calls.S ---- linux-2.4.26/arch/arm/kernel/calls.S 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/kernel/calls.S 2004-03-04 21:01:56.000000000 +0000 -@@ -115,7 +115,7 @@ - .long SYMBOL_NAME(sys_ni_syscall) /* was sys_profil */ - .long SYMBOL_NAME(sys_statfs) - /* 100 */ .long SYMBOL_NAME(sys_fstatfs) -- .long SYMBOL_NAME(sys_ni_syscall) -+ .long SYMBOL_NAME(sys_ni_syscall) /* 101 was sys_ioperm */ - .long SYMBOL_NAME(sys_socketcall) - .long SYMBOL_NAME(sys_syslog) - .long SYMBOL_NAME(sys_setitimer) -@@ -126,7 +126,7 @@ - .long SYMBOL_NAME(sys_ni_syscall) /* was sys_uname */ - /* 110 */ .long SYMBOL_NAME(sys_ni_syscall) /* was sys_iopl */ - .long SYMBOL_NAME(sys_vhangup) -- .long SYMBOL_NAME(sys_ni_syscall) -+ .long SYMBOL_NAME(sys_ni_syscall) /* 112 was sys_idle */ - .long SYMBOL_NAME(sys_syscall) /* call a syscall */ - .long SYMBOL_NAME(sys_wait4) - /* 115 */ .long SYMBOL_NAME(sys_swapoff) -@@ -137,7 +137,7 @@ - /* 120 */ .long SYMBOL_NAME(sys_clone_wapper) - .long SYMBOL_NAME(sys_setdomainname) - .long SYMBOL_NAME(sys_newuname) -- .long SYMBOL_NAME(sys_ni_syscall) -+ .long SYMBOL_NAME(sys_ni_syscall) /* 123 was sys_modify_ldt */ - .long SYMBOL_NAME(sys_adjtimex) - /* 125 */ .long SYMBOL_NAME(sys_mprotect) - .long SYMBOL_NAME(sys_sigprocmask) -@@ -180,7 +180,7 @@ - .long SYMBOL_NAME(sys_arm_mremap) - .long SYMBOL_NAME(sys_setresuid16) - /* 165 */ .long SYMBOL_NAME(sys_getresuid16) -- .long SYMBOL_NAME(sys_ni_syscall) -+ .long SYMBOL_NAME(sys_ni_syscall) /* 166 was sys_vm86 */ - .long SYMBOL_NAME(sys_query_module) - .long SYMBOL_NAME(sys_poll) - .long SYMBOL_NAME(sys_nfsservctl) -diff -urN linux-2.4.26/arch/arm/kernel/dma-rpc.c linux-2.4.26-vrs1/arch/arm/kernel/dma-rpc.c ---- linux-2.4.26/arch/arm/kernel/dma-rpc.c 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/kernel/dma-rpc.c 2004-01-14 21:38:42.000000000 +0000 -@@ -26,19 +26,6 @@ - #include - #include - --#if 0 --typedef enum { -- dma_size_8 = 1, -- dma_size_16 = 2, -- dma_size_32 = 4, -- dma_size_128 = 16 --} dma_size_t; -- --typedef struct { -- dma_size_t transfersize; --} dma_t; --#endif -- - #define TRANSFER_SIZE 2 - - #define CURA (0) -@@ -48,10 +35,6 @@ - #define CR (IOMD_IO0CR - IOMD_IO0CURA) - #define ST (IOMD_IO0ST - IOMD_IO0CURA) - --#define state_prog_a 0 --#define state_wait_a 1 --#define state_wait_b 2 -- - static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma) - { - unsigned long end, offset, flags = 0; -@@ -65,7 +48,7 @@ - if (end > PAGE_SIZE) - end = PAGE_SIZE; - -- if (offset + (int) TRANSFER_SIZE > end) -+ if (offset + TRANSFER_SIZE >= end) - flags |= DMA_END_L; - - sg->length = end - TRANSFER_SIZE; -@@ -103,27 +86,31 @@ - if (!(status & DMA_ST_INT)) - return; - -- if (status & DMA_ST_OFL && !dma->sg) -- break; -- -- iomd_get_next_sg(&dma->cur_sg, dma); -+ if ((dma->state ^ status) & DMA_ST_AB) -+ iomd_get_next_sg(&dma->cur_sg, dma); - - switch (status & (DMA_ST_OFL | DMA_ST_AB)) { - case DMA_ST_OFL: /* OIA */ - case DMA_ST_AB: /* .IB */ - iomd_writel(dma->cur_sg.dma_address, base + CURA); - iomd_writel(dma->cur_sg.length, base + ENDA); -+ dma->state = DMA_ST_AB; - break; - - case DMA_ST_OFL | DMA_ST_AB: /* OIB */ - case 0: /* .IA */ - iomd_writel(dma->cur_sg.dma_address, base + CURB); - iomd_writel(dma->cur_sg.length, base + ENDB); -+ dma->state = 0; - break; - } -+ -+ if (status & DMA_ST_OFL && -+ dma->cur_sg.length == (DMA_END_S|DMA_END_L)) -+ break; - } while (1); - -- iomd_writeb(0, base + CR); -+ dma->state = ~DMA_ST_AB; - disable_irq(irq); - } - -@@ -158,6 +145,7 @@ - } - - iomd_writeb(DMA_CR_C, dma_base + CR); -+ dma->state = DMA_ST_AB; - } - - if (dma->dma_mode == DMA_MODE_READ) -@@ -171,13 +159,11 @@ - { - unsigned long dma_base = dma->dma_base; - unsigned long flags; -- unsigned int ctrl; - - local_irq_save(flags); -- ctrl = iomd_readb(dma_base + CR); -- if (ctrl & DMA_CR_E) -+ if (dma->state != ~DMA_ST_AB) - disable_irq(dma->dma_irq); -- iomd_writeb(ctrl & ~DMA_CR_E, dma_base + CR); -+ iomd_writeb(0, dma_base + CR); - local_irq_restore(flags); - } - -diff -urN linux-2.4.26/arch/arm/kernel/entry-armv.S linux-2.4.26-vrs1/arch/arm/kernel/entry-armv.S ---- linux-2.4.26/arch/arm/kernel/entry-armv.S 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/kernel/entry-armv.S 2004-01-14 21:32:24.000000000 +0000 -@@ -677,12 +677,11 @@ - mrs r9, cpsr @ Enable interrupts if they were - tst r3, #I_BIT - biceq r9, r9, #I_BIT @ previously -- mov r0, r2 @ *** remove once everyones in sync - /* - * This routine must not corrupt r9 - */ - #ifdef MULTI_CPU -- ldr r4, .LCprocfns @ pass r0, r3 to -+ ldr r4, .LCprocfns @ pass r2, r3 to - mov lr, pc @ processor code - ldr pc, [r4] @ call processor specific code - #else -@@ -788,9 +787,8 @@ - stmdb r5, {sp, lr}^ - alignment_trap r7, r7, __temp_abt - zero_fp -- mov r0, r2 @ remove once everyones in sync - #ifdef MULTI_CPU -- ldr r4, .LCprocfns @ pass r0, r3 to -+ ldr r4, .LCprocfns @ pass r2, r3 to - mov lr, pc @ processor code - ldr pc, [r4] @ call processor specific code - #else -@@ -840,7 +838,8 @@ - adrsvc al, r9, ret_from_exception @ r9 = normal FP return - adrsvc al, lr, fpundefinstr @ lr = undefined instr return - --call_fpe: get_current_task r10 -+call_fpe: enable_irq r10 -+ get_current_task r10 - mov r8, #1 - strb r8, [r10, #TSK_USED_MATH] @ set current->used_math - ldr r4, .LCfp -diff -urN linux-2.4.26/arch/arm/kernel/fiq.c linux-2.4.26-vrs1/arch/arm/kernel/fiq.c ---- linux-2.4.26/arch/arm/kernel/fiq.c 2003-06-13 15:51:29.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/kernel/fiq.c 2004-04-09 19:55:21.000000000 +0100 -@@ -122,23 +122,23 @@ - register unsigned long tmp, tmp2; - __asm__ volatile ( - #ifdef CONFIG_CPU_26 -- "mov %0, pc -- bic %1, %0, #0x3 -- orr %1, %1, %3 -- teqp %1, #0 @ select FIQ mode -- mov r0, r0 -- ldmia %2, {r8 - r14} -- teqp %0, #0 @ return to SVC mode -- mov r0, r0" -+ "mov %0, pc \n" -+ "bic %1, %0, #0x3 \n" -+ "orr %1, %1, %3 \n" -+ "teqp %1, #0 @ select FIQ mode \n" -+ "mov r0, r0 \n" -+ "ldmia %2, {r8 - r14} \n" -+ "teqp %0, #0 @ return to SVC mode \n" -+ "mov r0, r0 \n" - #endif - #ifdef CONFIG_CPU_32 -- "mrs %0, cpsr -- mov %1, %3 -- msr cpsr_c, %1 @ select FIQ mode -- mov r0, r0 -- ldmia %2, {r8 - r14} -- msr cpsr_c, %0 @ return to SVC mode -- mov r0, r0" -+ "mrs %0, cpsr \n" -+ "mov %1, %3 \n" -+ "msr cpsr_c, %1 @ select FIQ mode \n" -+ "mov r0, r0 \n" -+ "ldmia %2, {r8 - r14} \n" -+ "msr cpsr_c, %0 @ return to SVC mode \n" -+ "mov r0, r0 \n" - #endif - : "=&r" (tmp), "=&r" (tmp2) - : "r" (®s->ARM_r8), "I" (I_BIT | F_BIT | FIQ_MODE) -@@ -154,23 +154,23 @@ - register unsigned long tmp, tmp2; - __asm__ volatile ( - #ifdef CONFIG_CPU_26 -- "mov %0, pc -- bic %1, %0, #0x3 -- orr %1, %1, %3 -- teqp %1, #0 @ select FIQ mode -- mov r0, r0 -- stmia %2, {r8 - r14} -- teqp %0, #0 @ return to SVC mode -- mov r0, r0" -+ "mov %0, pc \n" -+ "bic %1, %0, #0x3 \n" -+ "orr %1, %1, %3 \n" -+ "teqp %1, #0 @ select FIQ mode \n" -+ "mov r0, r0 \n" -+ "stmia %2, {r8 - r14} \n" -+ "teqp %0, #0 @ return to SVC mode \n" -+ "mov r0, r0 \n" - #endif - #ifdef CONFIG_CPU_32 -- "mrs %0, cpsr -- mov %1, %3 -- msr cpsr_c, %1 @ select FIQ mode -- mov r0, r0 -- stmia %2, {r8 - r14} -- msr cpsr_c, %0 @ return to SVC mode -- mov r0, r0" -+ "mrs %0, cpsr \n" -+ "mov %1, %3 \n" -+ "msr cpsr_c, %1 @ select FIQ mode \n" -+ "mov r0, r0 \n" -+ "stmia %2, {r8 - r14} \n" -+ "msr cpsr_c, %0 @ return to SVC mode \n" -+ "mov r0, r0 \n" - #endif - : "=&r" (tmp), "=&r" (tmp2) - : "r" (®s->ARM_r8), "I" (I_BIT | F_BIT | FIQ_MODE) -diff -urN linux-2.4.26/arch/arm/kernel/head-armv.S linux-2.4.26-vrs1/arch/arm/kernel/head-armv.S ---- linux-2.4.26/arch/arm/kernel/head-armv.S 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/kernel/head-armv.S 2004-01-14 21:32:24.000000000 +0000 -@@ -1,7 +1,7 @@ - /* - * linux/arch/arm/kernel/head-armv.S - * -- * Copyright (C) 1994-1999 Russell King -+ * Copyright (C) 1994-2003 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 -@@ -163,10 +163,10 @@ - */ - .type __ret, %function - __ret: ldr lr, __switch_data -- mcr p15, 0, r0, c1, c0 -- mrc p15, 0, r0, c1, c0, 0 @ read it back. -- mov r0, r0 -- mov r0, r0 -+ mcr p15, 0, r0, c1, c0, 0 -+ mrc p15, 0, r3, c0, c0, 0 -+ mov r3, r3 -+ mov r3, r3 - mov pc, lr - - /* -@@ -214,6 +214,11 @@ - */ - __create_page_tables: - pgtbl r4, r5 @ page table address -+#if defined(CONFIG_CPU_DCACHE_DISABLE) -+ bic r8, r8, #0x00c @ clear B, C -+#elif defined(CONFIG_CPU_DCACHE_WRITETHROUGH) -+ bic r8, r8, #0x004 @ clear B -+#endif - - /* - * Clear the 16K level 1 swapper page table -diff -urN linux-2.4.26/arch/arm/kernel/irq.c linux-2.4.26-vrs1/arch/arm/kernel/irq.c ---- linux-2.4.26/arch/arm/kernel/irq.c 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/kernel/irq.c 2004-01-14 21:32:24.000000000 +0000 -@@ -549,7 +549,7 @@ - kfree(action); - goto out; - } -- printk(KERN_ERR "Trying to free free IRQ%d\n",irq); -+ printk(KERN_ERR "Trying to free IRQ%d\n",irq); - #ifdef CONFIG_DEBUG_ERRORS - __backtrace(); - #endif -diff -urN linux-2.4.26/arch/arm/kernel/ptrace.c linux-2.4.26-vrs1/arch/arm/kernel/ptrace.c ---- linux-2.4.26/arch/arm/kernel/ptrace.c 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/kernel/ptrace.c 2004-01-14 21:32:24.000000000 +0000 -@@ -725,11 +725,8 @@ - goto out_tsk; - } - ret = -ESRCH; -- if (!(child->ptrace & PT_PTRACED)) -- goto out_tsk; -- if (child->state != TASK_STOPPED && request != PTRACE_KILL) -- goto out_tsk; -- if (child->p_pptr != current) -+ ret = ptrace_check_attach(child, request == PTRACE_KILL); -+ if (ret) - goto out_tsk; - - ret = do_ptrace(request, child, addr, data); -diff -urN linux-2.4.26/arch/arm/kernel/semaphore.c linux-2.4.26-vrs1/arch/arm/kernel/semaphore.c ---- linux-2.4.26/arch/arm/kernel/semaphore.c 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/kernel/semaphore.c 2004-01-14 21:38:42.000000000 +0000 -@@ -193,7 +193,7 @@ - bl __down_interruptible \n\ - mov ip, r0 \n\ - ldmfd sp!, {r0 - r3, pc}^ \n\ -- -+ \n\ - .align 5 \n\ - .globl __down_trylock_failed \n\ - __down_trylock_failed: \n\ -diff -urN linux-2.4.26/arch/arm/kernel/signal.c linux-2.4.26-vrs1/arch/arm/kernel/signal.c ---- linux-2.4.26/arch/arm/kernel/signal.c 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/kernel/signal.c 2004-01-14 21:32:24.000000000 +0000 -@@ -641,10 +641,7 @@ - /* FALLTHRU */ - - default: -- sigaddset(¤t->pending.signal, signr); -- recalc_sigpending(current); -- current->flags |= PF_SIGNALED; -- do_exit(exit_code); -+ sig_exit(signr, exit_code, &info); - /* NOTREACHED */ - } - } -diff -urN linux-2.4.26/arch/arm/lib/Makefile linux-2.4.26-vrs1/arch/arm/lib/Makefile ---- linux-2.4.26/arch/arm/lib/Makefile 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/lib/Makefile 2004-01-14 21:32:24.000000000 +0000 -@@ -15,7 +15,7 @@ - strnlen_user.o strchr.o strrchr.o testchangebit.o \ - testclearbit.o testsetbit.o uaccess.o getuser.o \ - putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ -- ucmpdi2.o udivdi3.o lib1funcs.o -+ ucmpdi2.o udivdi3.o lib1funcs.o div64.o - obj-m := - obj-n := - -diff -urN linux-2.4.26/arch/arm/lib/div64.S linux-2.4.26-vrs1/arch/arm/lib/div64.S ---- linux-2.4.26/arch/arm/lib/div64.S 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/lib/div64.S 2004-01-14 21:32:24.000000000 +0000 -@@ -0,0 +1,59 @@ -+#include -+ -+#ifndef __ARMEB__ -+ql .req r0 @ quotient low -+qh .req r1 @ quotient high -+onl .req r0 @ original dividend low -+onh .req r1 @ original dividend high -+nl .req r4 @ dividend low -+nh .req r5 @ dividend high -+res .req r4 @ result -+#else -+ql .req r1 -+qh .req r0 -+onl .req r1 -+onh .req r0 -+nl .req r5 -+nh .req r4 -+res .req r5 -+#endif -+ -+dl .req r3 @ divisor low -+dh .req r2 @ divsor high -+ -+ -+ENTRY(do_div64) -+ stmfd sp!, {r4, r5, lr} -+ mov nl, onl -+ movs nh, onh @ if high bits are zero -+ movne lr, #33 -+ moveq lr, #1 @ only divide low bits -+ moveq nh, onl -+ -+ tst dh, #0x80000000 -+ bne 2f -+1: cmp nh, dh -+ bls 2f -+ add lr, lr, #1 -+ movs dh, dh, lsl #1 @ left justify disor -+ bpl 1b -+ -+2: movs nh, onh -+ moveq dl, dh -+ moveq dh, #0 -+ movne dl, #0 -+ mov ql, #0 -+ mov qh, #0 -+3: subs ip, nl, dl @ trial subtraction -+ sbcs ip, nh, dh -+ movcs nh, ip @ only update if successful -+ subcs nl, nl, dl @ (repeat the subtraction) -+ adcs ql, ql, ql @ C=1 if successful, shift into -+ adc qh, qh, qh @ quotient -+ movs dh, dh, lsr #1 @ shift base high part right -+ mov dl, dl, rrx @ shift base low part right -+ subs lr, lr, #1 -+ bne 3b -+ -+ mov r2, res -+ ldmfd sp!, {r4, r5, pc} -diff -urN linux-2.4.26/arch/arm/lib/putuser.S linux-2.4.26-vrs1/arch/arm/lib/putuser.S ---- linux-2.4.26/arch/arm/lib/putuser.S 2001-10-11 17:04:57.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/lib/putuser.S 2004-01-14 21:32:24.000000000 +0000 -@@ -30,11 +30,11 @@ - - .global __put_user_1 - __put_user_1: -- bic r2, sp, #0x1f00 -- bic r2, r2, #0x00ff -- ldr r2, [r2, #TSK_ADDR_LIMIT] -- sub r2, r2, #1 -- cmp r0, r2 -+ bic ip, sp, #0x1f00 -+ bic ip, ip, #0x00ff -+ ldr ip, [ip, #TSK_ADDR_LIMIT] -+ sub ip, ip, #1 -+ cmp r0, ip - 1: strlsbt r1, [r0] - movls r0, #0 - movls pc, lr -@@ -42,11 +42,11 @@ - - .global __put_user_2 - __put_user_2: -- bic r2, sp, #0x1f00 -- bic r2, r2, #0x00ff -- ldr r2, [r2, #TSK_ADDR_LIMIT] -- sub r2, r2, #2 -- cmp r0, r2 -+ bic ip, sp, #0x1f00 -+ bic ip, ip, #0x00ff -+ ldr ip, [ip, #TSK_ADDR_LIMIT] -+ sub ip, ip, #2 -+ cmp r0, ip - 2: strlsbt r1, [r0], #1 - movls r1, r1, lsr #8 - 3: strlsbt r1, [r0] -@@ -56,11 +56,11 @@ - - .global __put_user_4 - __put_user_4: -- bic r2, sp, #0x1f00 -- bic r2, r2, #0x00ff -- ldr r2, [r2, #TSK_ADDR_LIMIT] -- sub r2, r2, #4 -- cmp r0, r2 -+ bic ip, sp, #0x1f00 -+ bic ip, ip, #0x00ff -+ ldr ip, [ip, #TSK_ADDR_LIMIT] -+ sub ip, ip, #4 -+ cmp r0, ip - 4: strlst r1, [r0] - movls r0, #0 - movls pc, lr -diff -urN linux-2.4.26/arch/arm/mach-at91rm9200/Makefile linux-2.4.26-vrs1/arch/arm/mach-at91rm9200/Makefile ---- linux-2.4.26/arch/arm/mach-at91rm9200/Makefile 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mach-at91rm9200/Makefile 2004-04-10 12:21:08.000000000 +0100 -@@ -18,4 +18,8 @@ - - export-objs := - -+# LEDs support -+leds-$(CONFIG_ARCH_AT91RM9200DK) += dk-leds.o -+obj-$(CONFIG_LEDS) += $(leds-y) -+ - include $(TOPDIR)/Rules.make -diff -urN linux-2.4.26/arch/arm/mach-at91rm9200/dk-leds.c linux-2.4.26-vrs1/arch/arm/mach-at91rm9200/dk-leds.c ---- linux-2.4.26/arch/arm/mach-at91rm9200/dk-leds.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mach-at91rm9200/dk-leds.c 2004-04-10 12:21:08.000000000 +0100 -@@ -0,0 +1,97 @@ -+/* -+ * LED driver for the Atmel AT91RM9200 Development Kit. -+ * -+ * (c) SAN People (Pty) Ltd -+ * -+ * 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. -+*/ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+ -+static inline void at91_led_on(void) -+{ -+ AT91_SYS->PIOB_CODR = AT91C_PIO_PB2; -+} -+ -+static inline void at91_led_off(void) -+{ -+ AT91_SYS->PIOB_SODR = AT91C_PIO_PB2; -+} -+ -+static inline void at91_led_toggle(void) -+{ -+ unsigned long curr = AT91_SYS->PIOB_ODSR; -+ if (curr & AT91C_PIO_PB2) -+ AT91_SYS->PIOB_CODR = AT91C_PIO_PB2; -+ else -+ AT91_SYS->PIOB_SODR = AT91C_PIO_PB2; -+} -+ -+ -+/* -+ * Handle LED events. -+ */ -+static void at91rm9200dk_leds_event(led_event_t evt) -+{ -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ switch(evt) { -+ case led_start: /* System startup */ -+ at91_led_on(); -+ break; -+ -+ case led_stop: /* System stop / suspend */ -+ at91_led_off(); -+ break; -+ -+#ifdef CONFIG_LEDS_TIMER -+ case led_timer: /* Every 50 timer ticks */ -+ at91_led_toggle(); -+ break; -+#endif -+ -+#ifdef CONFIG_LEDS_CPU -+ case led_idle_start: /* Entering idle state */ -+ at91_led_off(); -+ break; -+ -+ case led_idle_end: /* Exit idle state */ -+ at91_led_on(); -+ break; -+#endif -+ -+ default: -+ break; -+ } -+ -+ local_irq_restore(flags); -+} -+ -+ -+static int __init leds_init(void) -+{ -+ /* Enable PIO to access the LEDs */ -+ AT91_SYS->PIOB_PER = AT91C_PIO_PB2; -+ AT91_SYS->PIOB_OER = AT91C_PIO_PB2; -+ -+ leds_event = at91rm9200dk_leds_event; -+ -+ leds_event(led_start); -+ return 0; -+} -+ -+__initcall(leds_init); -diff -urN linux-2.4.26/arch/arm/mach-integrator/pci_v3.c linux-2.4.26-vrs1/arch/arm/mach-integrator/pci_v3.c ---- linux-2.4.26/arch/arm/mach-integrator/pci_v3.c 2003-06-13 15:51:29.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mach-integrator/pci_v3.c 2004-01-14 21:32:24.000000000 +0000 -@@ -21,7 +21,6 @@ - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - #include --#include - #include - #include - #include -@@ -32,6 +31,7 @@ - #include - - #include -+#include - #include - #include - #include -@@ -447,15 +447,16 @@ - #define SC_LBFADDR (IO_ADDRESS(INTEGRATOR_SC_BASE) + 0x20) - #define SC_LBFCODE (IO_ADDRESS(INTEGRATOR_SC_BASE) + 0x24) - --static int v3_fault(unsigned long addr, struct pt_regs *regs) -+static int -+v3_pci_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) - { - unsigned long pc = instruction_pointer(regs); - unsigned long instr = *(unsigned long *)pc; - #if 0 - char buf[128]; - -- sprintf(buf, "V3 fault: address=0x%08lx, pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n", -- addr, pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255, -+ sprintf(buf, "V3 fault: addr 0x%08lx, FSR 0x%03x, PC 0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n", -+ addr, fsr, pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255, - v3_readb(V3_LB_ISTAT)); - printk(KERN_DEBUG "%s", buf); - printascii(buf); -@@ -523,8 +524,6 @@ - #endif - } - --extern int (*external_fault)(unsigned long addr, struct pt_regs *regs); -- - /* - * V3_LB_BASE? - local bus address - * V3_LB_MAP? - pci bus address -@@ -539,7 +538,10 @@ - /* - * Hook in our fault handler for PCI errors - */ -- external_fault = v3_fault; -+ hook_fault_code(4, v3_pci_fault, SIGBUS, "external abort on linefetch"); -+ hook_fault_code(6, v3_pci_fault, SIGBUS, "external abort on linefetch"); -+ hook_fault_code(8, v3_pci_fault, SIGBUS, "external abort on non-linefetch"); -+ hook_fault_code(10, v3_pci_fault, SIGBUS, "external abort on non-linefetch"); - - spin_lock_irqsave(&v3_lock, flags); - -@@ -629,7 +631,7 @@ - #if 0 - ret = request_irq(IRQ_LBUSTIMEOUT, lb_timeout, 0, "bus timeout", NULL); - if (ret) -- printk(KERN_ERR "PCI: unable to grab local bus timeout ". -+ printk(KERN_ERR "PCI: unable to grab local bus timeout " - "interrupt: %d\n", ret); - #endif - } -diff -urN linux-2.4.26/arch/arm/mach-sa1100/pm.c linux-2.4.26-vrs1/arch/arm/mach-sa1100/pm.c ---- linux-2.4.26/arch/arm/mach-sa1100/pm.c 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mach-sa1100/pm.c 2004-01-14 21:38:43.000000000 +0000 -@@ -21,6 +21,8 @@ - * - * 2002-05-27: Nicolas Pitre Killed sleep.h and the kmalloced save array. - * Storage is local on the stack now. -+ * 2003-06-25: Jeff Corrall -+ * Saved the GPIO levels for resume after sleep. - */ - #include - #include -@@ -70,13 +72,20 @@ - int pm_do_suspend(void) - { - unsigned long sleep_save[SLEEP_SAVE_SIZE]; -+ unsigned long sleep_save_gpsr; -+ unsigned long sleep_save_gpcr; -+ unsigned long delta; - - cli(); - - leds_event(led_stop); - - /* preserve current time */ -- RCNR = xtime.tv_sec; -+ delta = xtime.tv_sec - RCNR; -+ -+ /* save the current state of the GPIO output pins */ -+ sleep_save_gpsr = GPDR & GPLR; -+ sleep_save_gpcr = GPDR & ~GPLR; - - /* save vital registers */ - SAVE(OSCR); -@@ -121,6 +130,10 @@ - printk(KERN_DEBUG "*** made it back from resume\n"); - #endif - -+ /* restore GPIO output state before enabling the pins */ -+ GPSR = sleep_save_gpsr; -+ GPCR = sleep_save_gpcr; -+ - /* restore registers */ - RESTORE(GPDR); - RESTORE(GRER); -@@ -151,7 +164,7 @@ - RESTORE(ICMR); - - /* restore current time */ -- xtime.tv_sec = RCNR; -+ xtime.tv_sec = RCNR + delta; - - leds_event(led_start); - -diff -urN linux-2.4.26/arch/arm/mach-sa1100/sa1100_usb.h linux-2.4.26-vrs1/arch/arm/mach-sa1100/sa1100_usb.h ---- linux-2.4.26/arch/arm/mach-sa1100/sa1100_usb.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mach-sa1100/sa1100_usb.h 2004-01-14 21:32:24.000000000 +0000 -@@ -0,0 +1,193 @@ -+/* -+ * sa1100_usb.h -+ * -+ * Public interface to the sa1100 USB core. For use by client modules -+ * like usb-eth and usb-char. -+ * -+ */ -+ -+#ifndef _SA1100_USB_H -+#define _SA1100_USB_H -+#include -+ -+typedef void (*usb_callback_t)(int flag, int size); -+ -+/* in usb_ctl.c (see also descriptor methods at bottom of file) */ -+ -+// Open the USB client for client and initialize data structures -+// to default values, but _do not_ start UDC. -+int sa1100_usb_open( const char * client_name ); -+ -+// Start UDC running -+int sa1100_usb_start( void ); -+ -+// Immediately stop udc, fire off completion routines w/-EINTR -+int sa1100_usb_stop( void ) ; -+ -+// Disconnect client from usb core -+int sa1100_usb_close( void ) ; -+ -+// set notify callback for when core reaches configured state -+// return previous pointer (if any) -+typedef void (*usb_notify_t)(void); -+usb_notify_t sa1100_set_configured_callback( usb_notify_t callback ); -+ -+/* in usb_send.c */ -+int sa1100_usb_xmitter_avail( void ); -+int sa1100_usb_send(char *buf, int len, usb_callback_t callback); -+void sa1100_usb_send_reset(void); -+ -+/* in usb_recev.c */ -+int sa1100_usb_recv(char *buf, int len, usb_callback_t callback); -+void sa1100_usb_recv_reset(void); -+ -+////////////////////////////////////////////////////////////////////////////// -+// Descriptor Management -+////////////////////////////////////////////////////////////////////////////// -+ -+#define DescriptorHeader \ -+ __u8 bLength; \ -+ __u8 bDescriptorType -+ -+ -+// --- Device Descriptor ------------------- -+ -+typedef struct { -+ DescriptorHeader; -+ __u16 bcdUSB; /* USB specification revision number in BCD */ -+ __u8 bDeviceClass; /* USB class for entire device */ -+ __u8 bDeviceSubClass; /* USB subclass information for entire device */ -+ __u8 bDeviceProtocol; /* USB protocol information for entire device */ -+ __u8 bMaxPacketSize0; /* Max packet size for endpoint zero */ -+ __u16 idVendor; /* USB vendor ID */ -+ __u16 idProduct; /* USB product ID */ -+ __u16 bcdDevice; /* vendor assigned device release number */ -+ __u8 iManufacturer; /* index of manufacturer string */ -+ __u8 iProduct; /* index of string that describes product */ -+ __u8 iSerialNumber; /* index of string containing device serial number */ -+ __u8 bNumConfigurations; /* number fo configurations */ -+} __attribute__ ((packed)) device_desc_t; -+ -+// --- Configuration Descriptor ------------ -+ -+typedef struct { -+ DescriptorHeader; -+ __u16 wTotalLength; /* total # of bytes returned in the cfg buf 4 this cfg */ -+ __u8 bNumInterfaces; /* number of interfaces in this cfg */ -+ __u8 bConfigurationValue; /* used to uniquely ID this cfg */ -+ __u8 iConfiguration; /* index of string describing configuration */ -+ __u8 bmAttributes; /* bitmap of attributes for ths cfg */ -+ __u8 MaxPower; /* power draw in 2ma units */ -+} __attribute__ ((packed)) config_desc_t; -+ -+// bmAttributes: -+enum { USB_CONFIG_REMOTEWAKE=0x20, USB_CONFIG_SELFPOWERED=0x40, -+ USB_CONFIG_BUSPOWERED=0x80 }; -+// MaxPower: -+#define USB_POWER( x) ((x)>>1) /* convert mA to descriptor units of A for MaxPower */ -+ -+// --- Interface Descriptor --------------- -+ -+typedef struct { -+ DescriptorHeader; -+ __u8 bInterfaceNumber; /* Index uniquely identfying this interface */ -+ __u8 bAlternateSetting; /* ids an alternate setting for this interface */ -+ __u8 bNumEndpoints; /* number of endpoints in this interface */ -+ __u8 bInterfaceClass; /* USB class info applying to this interface */ -+ __u8 bInterfaceSubClass; /* USB subclass info applying to this interface */ -+ __u8 bInterfaceProtocol; /* USB protocol info applying to this interface */ -+ __u8 iInterface; /* index of string describing interface */ -+} __attribute__ ((packed)) intf_desc_t; -+ -+// --- Endpoint Descriptor --------------- -+ -+typedef struct { -+ DescriptorHeader; -+ __u8 bEndpointAddress; /* 0..3 ep num, bit 7: 0 = 0ut 1= in */ -+ __u8 bmAttributes; /* 0..1 = 0: ctrl, 1: isoc, 2: bulk 3: intr */ -+ __u16 wMaxPacketSize; /* data payload size for this ep in this cfg */ -+ __u8 bInterval; /* polling interval for this ep in this cfg */ -+} __attribute__ ((packed)) ep_desc_t; -+ -+// bEndpointAddress: -+enum { USB_OUT= 0, USB_IN=1 }; -+#define USB_EP_ADDRESS(a,d) (((a)&0xf) | ((d) << 7)) -+// bmAttributes: -+enum { USB_EP_CNTRL=0, USB_EP_BULK=2, USB_EP_INT=3 }; -+ -+// --- String Descriptor ------------------- -+ -+typedef struct { -+ DescriptorHeader; -+ __u16 bString[1]; /* unicode string .. actaully 'n' __u16s */ -+} __attribute__ ((packed)) string_desc_t; -+ -+/*======================================================= -+ * Handy helpers when working with above -+ * -+ */ -+// these are x86-style 16 bit "words" ... -+#define make_word_c( w ) __constant_cpu_to_le16(w) -+#define make_word( w ) __cpu_to_le16(w) -+ -+// descriptor types -+enum { USB_DESC_DEVICE=1, USB_DESC_CONFIG=2, USB_DESC_STRING=3, -+ USB_DESC_INTERFACE=4, USB_DESC_ENDPOINT=5 }; -+ -+ -+/*======================================================= -+ * Default descriptor layout for SA-1100 and SA-1110 UDC -+ */ -+ -+/* "config descriptor buffer" - that is, one config, -+ ..one interface and 2 endpoints */ -+struct cdb { -+ config_desc_t cfg; -+ intf_desc_t intf; -+ ep_desc_t ep1; -+ ep_desc_t ep2; -+} __attribute__ ((packed)); -+ -+ -+/* all SA device descriptors */ -+typedef struct { -+ device_desc_t dev; /* device descriptor */ -+ struct cdb b; /* bundle of descriptors for this cfg */ -+} __attribute__ ((packed)) desc_t; -+ -+ -+/*======================================================= -+ * Descriptor API -+ */ -+ -+/* Get the address of the statically allocated desc_t structure -+ in the usb core driver. Clients can modify this between -+ the time they call sa1100_usb_open() and sa1100_usb_start() -+*/ -+desc_t * -+sa1100_usb_get_descriptor_ptr( void ); -+ -+ -+/* Set a pointer to the string descriptor at "index". The driver -+ ..has room for 8 string indicies internally. Index zero holds -+ ..a LANGID code and is set to US English by default. Inidices -+ ..1-7 are available for use in the config descriptors as client's -+ ..see fit. This pointer is assumed to be good as long as the -+ ..SA usb core is open (so statically allocate them). Returnes -EINVAL -+ ..if index out of range */ -+int sa1100_usb_set_string_descriptor( int index, string_desc_t * p ); -+ -+/* reverse of above */ -+string_desc_t * -+sa1100_usb_get_string_descriptor( int index ); -+ -+/* kmalloc() a string descriptor and convert "p" to unicode in it */ -+string_desc_t * -+sa1100_usb_kmalloc_string_descriptor( const char * p ); -+ -+ -+ -+ -+ -+ -+#endif /* _SA1100_USB_H */ -diff -urN linux-2.4.26/arch/arm/mach-sa1100/sa1111-ohci.c linux-2.4.26-vrs1/arch/arm/mach-sa1100/sa1111-ohci.c ---- linux-2.4.26/arch/arm/mach-sa1100/sa1111-ohci.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mach-sa1100/sa1111-ohci.c 2004-01-14 21:32:24.000000000 +0000 -@@ -0,0 +1,140 @@ -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_USB_OHCI -+ -+/* -+ * The SA-1111 errata says that the DMA hardware needs to be exercised -+ * before the clocks are turned on to work properly. This code does -+ * a tiny dma transfer to prime to hardware. -+ * -+ * What DMA errata? I've checked October 1999 and February 2001, both -+ * of which do not mention such a bug, let alone any details of this -+ * work-around. -+ */ -+static void __init sa1111_dma_setup(void) -+{ -+ dma_addr_t dma_buf; -+ void * vbuf; -+ -+ /* DMA init & setup */ -+ -+ /* WARNING: The SA-1111 L3 function is used as part of this -+ * SA-1111 DMA errata workaround. -+ * -+ * N.B., When the L3 function is enabled, it uses GPIO_B<4:5> -+ * and takes precedence over the PS/2 mouse and GPIO_B -+ * functions. Refer to "Intel StrongARM SA-1111 Microprocessor -+ * Companion Chip, Sect 10.2" for details. So this "fix" may -+ * "break" support of either PS/2 mouse or GPIO_B if -+ * precautions are not taken to avoid collisions in -+ * configuration and use of these pins. AFAIK, no precautions -+ * are taken at this time. So it is likely that the action -+ * taken here may cause problems in PS/2 mouse and/or GPIO_B -+ * pin use elsewhere. -+ * -+ * But wait, there's more... What we're doing here is -+ * obviously altogether a bad idea. We're indiscrimanately bit -+ * flipping config for a few different functions here which -+ * are "owned" by other drivers. This needs to be handled -+ * better than it is being done here at this time. */ -+ -+ /* prime the dma engine with a tiny dma */ -+ SKPCR |= SKPCR_I2SCLKEN; -+ SKAUD |= SKPCR_L3CLKEN | SKPCR_SCLKEN; -+ -+ SACR0 |= 0x00003305; -+ SACR1 = 0x00000000; -+ -+ /* -+ * We need memory below 1MB. -+ * NOTE: consistent_alloc gives you some random virtual -+ * address as its return value, and the DMA address via -+ * the dma_addr_t pointer. -+ */ -+ vbuf = consistent_alloc(GFP_KERNEL | GFP_DMA, 4, &dma_buf); -+ -+ SADTSA = (unsigned long)dma_buf; -+ SADTCA = 4; -+ -+ SADTCS |= 0x00000011; -+ SKPCR |= SKPCR_DCLKEN; -+ -+ /* wait */ -+ udelay(100); -+ -+ /* clear reserved but, then disable SAC */ -+ SACR0 &= ~(0x00000002); -+ SACR0 &= ~(0x00000001); -+ -+ /* toggle bit clock direction */ -+ SACR0 |= 0x00000004; -+ SACR0 &= ~(0x00000004); -+ -+ SKAUD &= ~(SKPCR_L3CLKEN | SKPCR_SCLKEN); -+ -+ SKPCR &= ~SKPCR_I2SCLKEN; -+ -+ consistent_free(vbuf, 4, dma_buf); -+} -+ -+/* -+ * reset the SA-1111 usb controller and turn on it's clocks -+ */ -+int __init sa1111_ohci_hcd_init(void) -+{ -+ unsigned int usb_reset = 0; -+ -+ if (machine_is_xp860() || -+ machine_has_neponset() || -+ machine_is_pfs168() || -+ machine_is_badge4()) -+ usb_reset = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW; -+ -+ /* -+ * turn on USB clocks -+ */ -+ SKPCR |= SKPCR_UCLKEN; -+ udelay(100); -+ -+ /* -+ * Force USB reset -+ */ -+ USB_RESET = USB_RESET_FORCEIFRESET; -+ USB_RESET |= USB_RESET_FORCEHCRESET; -+ udelay(100); -+ -+ /* -+ * Take out of reset -+ */ -+ USB_RESET = 0; -+ -+ /* -+ * set power sense and control lines (this from the diags code) -+ */ -+ USB_RESET = usb_reset; -+ -+ /* -+ * Huh? This is a _read only_ register --rmk -+ */ -+ USB_STATUS = 0; -+ -+ udelay(10); -+ -+ /* -+ * compensate for dma bug -+ */ -+ sa1111_dma_setup(); -+ -+ return 0; -+} -+ -+void sa1111_ohci_hcd_cleanup(void) -+{ -+ /* turn the USB clock off */ -+ SKPCR &= ~SKPCR_UCLKEN; -+} -+ -+#endif /* CONFIG_USB_OHCI */ -diff -urN linux-2.4.26/arch/arm/mach-sa1100/usb-char.c linux-2.4.26-vrs1/arch/arm/mach-sa1100/usb-char.c ---- linux-2.4.26/arch/arm/mach-sa1100/usb-char.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mach-sa1100/usb-char.c 2004-01-14 21:32:24.000000000 +0000 -@@ -0,0 +1,723 @@ -+/* -+ * (C) Copyright 2000-2001 Extenex Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ * usb-char.c -+ * -+ * Miscellaneous character device interface for SA1100 USB function -+ * driver. -+ * -+ * Background: -+ * The SA1100 function driver ported from the Compaq Itsy project -+ * has an interface, usb-eth.c, to feed network packets over the -+ * usb wire and into the Linux TCP/IP stack. -+ * -+ * This file replaces that one with a simple character device -+ * interface that allows unstructured "byte pipe" style reads and -+ * writes over the USB bulk endpoints by userspace programs. -+ * -+ * A new define, CONFIG_SA1100_USB_NETLINK, has been created that, -+ * when set, (the default) causes the ethernet interface to be used. -+ * When not set, this more pedestrian character interface is linked -+ * in instead. -+ * -+ * Please see linux/Documentation/arm/SA1100/SA1100_USB for details. -+ * -+ * ward.willats@extenex.com -+ * -+ * To do: -+ * - Can't dma into ring buffer directly with pci_map/unmap usb_recv -+ * uses and get bytes out at the same time DMA is going on. Investigate: -+ * a) changing usb_recv to use alloc_consistent() at client request; or -+ * b) non-ring-buffer based data structures. In the meantime, I am using -+ * a bounce buffer. Simple, but wasteful. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "usb-char.h" -+#include "sa1100_usb.h" -+ -+ -+ -+////////////////////////////////////////////////////////////////////////////// -+// Driver Options -+////////////////////////////////////////////////////////////////////////////// -+ -+#define VERSION "0.4" -+ -+ -+#define VERBOSITY 1 -+ -+#if VERBOSITY -+# define PRINTK(x, a...) printk (x, ## a) -+#else -+# define PRINTK(x, a...) /**/ -+#endif -+ -+////////////////////////////////////////////////////////////////////////////// -+// Globals - Macros - Enums - Structures -+////////////////////////////////////////////////////////////////////////////// -+#ifndef MIN -+#define MIN( a, b ) ((a)<(b)?(a):(b)) -+#endif -+ -+typedef int bool; enum { false = 0, true = 1 }; -+ -+static const char pszMe[] = "usbchr: "; -+ -+static wait_queue_head_t wq_read; -+static wait_queue_head_t wq_write; -+static wait_queue_head_t wq_poll; -+ -+/* Serialze multiple writers onto the transmit hardware -+.. since we sleep the writer during transmit to stay in -+.. sync. (Multiple writers don't make much sense, but..) */ -+static DECLARE_MUTEX( xmit_sem ); -+ -+// size of usb DATA0/1 packets. 64 is standard maximum -+// for bulk transport, though most hosts seem to be able -+// to handle larger. -+#define TX_PACKET_SIZE 64 -+#define RX_PACKET_SIZE 64 -+#define RBUF_SIZE (4*PAGE_SIZE) -+ -+static struct wcirc_buf { -+ char *buf; -+ int in; -+ int out; -+} rx_ring = { NULL, 0, 0 }; -+ -+static struct { -+ unsigned long cnt_rx_complete; -+ unsigned long cnt_rx_errors; -+ unsigned long bytes_rx; -+ unsigned long cnt_tx_timeouts; -+ unsigned long cnt_tx_errors; -+ unsigned long bytes_tx; -+} charstats; -+ -+ -+static char * tx_buf = NULL; -+static char * packet_buffer = NULL; -+static int sending = 0; -+static int usb_ref_count = 0; -+static int last_tx_result = 0; -+static int last_rx_result = 0; -+static int last_tx_size = 0; -+static struct timer_list tx_timer; -+ -+////////////////////////////////////////////////////////////////////////////// -+// Prototypes -+////////////////////////////////////////////////////////////////////////////// -+static char * what_the_f( int e ); -+static void free_txrx_buffers( void ); -+static void twiddle_descriptors( void ); -+static void free_string_descriptors( void ) ; -+static int usbc_open( struct inode *pInode, struct file *pFile ); -+static void rx_done_callback_packet_buffer( int flag, int size ); -+ -+static void tx_timeout( unsigned long ); -+static void tx_done_callback( int flag, int size ); -+ -+static ssize_t usbc_read( struct file *, char *, size_t, loff_t * ); -+static ssize_t usbc_write( struct file *, const char *, size_t, loff_t * ); -+static unsigned int usbc_poll( struct file *pFile, poll_table * pWait ); -+static int usbc_ioctl( struct inode *pInode, struct file *pFile, -+ unsigned int nCmd, unsigned long argument ); -+static int usbc_close( struct inode *pInode, struct file *pFile ); -+ -+#ifdef CONFIG_SA1100_EXTENEX1 -+static void extenex_configured_notify_proc( void ); -+#endif -+////////////////////////////////////////////////////////////////////////////// -+// Private Helpers -+////////////////////////////////////////////////////////////////////////////// -+ -+static char * what_the_f( int e ) -+{ -+ char * p; -+ switch( e ) { -+ case 0: -+ p = "noErr"; -+ break; -+ case -ENODEV: -+ p = "ENODEV - usb not in config state"; -+ break; -+ case -EBUSY: -+ p = "EBUSY - another request on the hardware"; -+ break; -+ case -EAGAIN: -+ p = "EAGAIN"; -+ break; -+ case -EINTR: -+ p = "EINTR - interrupted\n"; -+ break; -+ case -EPIPE: -+ p = "EPIPE - zero length xfer\n"; -+ break; -+ default: -+ p = "????"; -+ break; -+ } -+ return p; -+} -+ -+static void free_txrx_buffers( void ) -+{ -+ if ( rx_ring.buf != NULL ) { -+ kfree( rx_ring.buf ); -+ rx_ring.buf = NULL; -+ } -+ if ( packet_buffer != NULL ) { -+ kfree( packet_buffer ); -+ packet_buffer = NULL; -+ } -+ if ( tx_buf != NULL ) { -+ kfree( tx_buf ); -+ tx_buf = NULL; -+ } -+} -+ -+/* twiddle_descriptors() -+ * It is between open() and start(). Setup descriptors. -+ */ -+static void twiddle_descriptors( void ) -+{ -+ desc_t * pDesc = sa1100_usb_get_descriptor_ptr(); -+ string_desc_t * pString; -+ -+ pDesc->b.ep1.wMaxPacketSize = make_word_c( RX_PACKET_SIZE ); -+ pDesc->b.ep1.bmAttributes = USB_EP_BULK; -+ pDesc->b.ep2.wMaxPacketSize = make_word_c( TX_PACKET_SIZE ); -+ pDesc->b.ep2.bmAttributes = USB_EP_BULK; -+ -+ if ( machine_is_extenex1() ) { -+#ifdef CONFIG_SA1100_EXTENEX1 -+ pDesc->dev.idVendor = make_word_c( 0xC9F ); -+ pDesc->dev.idProduct = 1; -+ pDesc->dev.bcdDevice = make_word_c( 0x0001 ); -+ pDesc->b.cfg.bmAttributes = USB_CONFIG_SELFPOWERED; -+ pDesc->b.cfg.MaxPower = 0; -+ -+ pString = sa1100_usb_kmalloc_string_descriptor( "Extenex" ); -+ if ( pString ) { -+ sa1100_usb_set_string_descriptor( 1, pString ); -+ pDesc->dev.iManufacturer = 1; -+ } -+ -+ pString = sa1100_usb_kmalloc_string_descriptor( "Handheld Theater" ); -+ if ( pString ) { -+ sa1100_usb_set_string_descriptor( 2, pString ); -+ pDesc->dev.iProduct = 2; -+ } -+ -+ pString = sa1100_usb_kmalloc_string_descriptor( "00000000" ); -+ if ( pString ) { -+ sa1100_usb_set_string_descriptor( 3, pString ); -+ pDesc->dev.iSerialNumber = 3; -+ } -+ -+ pString = sa1100_usb_kmalloc_string_descriptor( "HHT Bulk Transfer" ); -+ if ( pString ) { -+ sa1100_usb_set_string_descriptor( 4, pString ); -+ pDesc->b.intf.iInterface = 4; -+ } -+ sa1100_set_configured_callback( extenex_configured_notify_proc ); -+#endif -+ } -+} -+ -+static void free_string_descriptors( void ) -+{ -+ if ( machine_is_extenex1() ) { -+ string_desc_t * pString; -+ int i; -+ for( i = 1 ; i <= 4 ; i++ ) { -+ pString = sa1100_usb_get_string_descriptor( i ); -+ if ( pString ) -+ kfree( pString ); -+ } -+ } -+} -+ -+////////////////////////////////////////////////////////////////////////////// -+// ASYNCHRONOUS -+////////////////////////////////////////////////////////////////////////////// -+static void kick_start_rx( void ) -+{ -+ if ( usb_ref_count ) { -+ int total_space = CIRC_SPACE( rx_ring.in, rx_ring.out, RBUF_SIZE ); -+ if ( total_space >= RX_PACKET_SIZE ) { -+ sa1100_usb_recv( packet_buffer, -+ RX_PACKET_SIZE, -+ rx_done_callback_packet_buffer -+ ); -+ } -+ } -+} -+/* -+ * rx_done_callback_packet_buffer() -+ * We have completed a DMA xfer into the temp packet buffer. -+ * Move to ring. -+ * -+ * flag values: -+ * on init, -EAGAIN -+ * on reset, -EINTR -+ * on RPE, -EIO -+ * on short packet -EPIPE -+ */ -+static void -+rx_done_callback_packet_buffer( int flag, int size ) -+{ -+ charstats.cnt_rx_complete++; -+ -+ if ( flag == 0 || flag == -EPIPE ) { -+ size_t n; -+ -+ charstats.bytes_rx += size; -+ -+ n = CIRC_SPACE_TO_END( rx_ring.in, rx_ring.out, RBUF_SIZE ); -+ n = MIN( n, size ); -+ size -= n; -+ -+ memcpy( &rx_ring.buf[ rx_ring.in ], packet_buffer, n ); -+ rx_ring.in = (rx_ring.in + n) & (RBUF_SIZE-1); -+ memcpy( &rx_ring.buf[ rx_ring.in ], packet_buffer + n, size ); -+ rx_ring.in = (rx_ring.in + size) & (RBUF_SIZE-1); -+ -+ wake_up_interruptible( &wq_read ); -+ wake_up_interruptible( &wq_poll ); -+ -+ last_rx_result = 0; -+ -+ kick_start_rx(); -+ -+ } else if ( flag != -EAGAIN ) { -+ charstats.cnt_rx_errors++; -+ last_rx_result = flag; -+ wake_up_interruptible( &wq_read ); -+ wake_up_interruptible( &wq_poll ); -+ } -+ else /* init, start a read */ -+ kick_start_rx(); -+} -+ -+ -+static void tx_timeout( unsigned long unused ) -+{ -+ printk( "%stx timeout\n", pszMe ); -+ sa1100_usb_send_reset(); -+ charstats.cnt_tx_timeouts++; -+} -+ -+ -+// on init, -EAGAIN -+// on reset, -EINTR -+// on TPE, -EIO -+static void tx_done_callback( int flags, int size ) -+{ -+ if ( flags == 0 ) -+ charstats.bytes_tx += size; -+ else -+ charstats.cnt_tx_errors++; -+ last_tx_size = size; -+ last_tx_result = flags; -+ sending = 0; -+ wake_up_interruptible( &wq_write ); -+ wake_up_interruptible( &wq_poll ); -+} -+ -+ -+////////////////////////////////////////////////////////////////////////////// -+// Workers -+////////////////////////////////////////////////////////////////////////////// -+ -+static int usbc_open( struct inode *pInode, struct file *pFile ) -+{ -+ int retval = 0; -+ -+ PRINTK( KERN_DEBUG "%sopen()\n", pszMe ); -+ -+ /* start usb core */ -+ retval = sa1100_usb_open( "usb-char" ); -+ if ( retval ) return retval; -+ -+ /* allocate memory */ -+ if ( usb_ref_count == 0 ) { -+ tx_buf = (char*) kmalloc( TX_PACKET_SIZE, GFP_KERNEL | GFP_DMA ); -+ if ( tx_buf == NULL ) { -+ printk( "%sARGHH! COULD NOT ALLOCATE TX BUFFER\n", pszMe ); -+ goto malloc_fail; -+ } -+ rx_ring.buf = -+ (char*) kmalloc( RBUF_SIZE, GFP_KERNEL ); -+ -+ if ( rx_ring.buf == NULL ) { -+ printk( "%sARGHH! COULD NOT ALLOCATE RX BUFFER\n", pszMe ); -+ goto malloc_fail; -+ } -+ -+ packet_buffer = -+ (char*) kmalloc( RX_PACKET_SIZE, GFP_KERNEL | GFP_DMA ); -+ -+ if ( packet_buffer == NULL ) { -+ printk( "%sARGHH! COULD NOT ALLOCATE RX PACKET BUFFER\n", pszMe ); -+ goto malloc_fail; -+ } -+ rx_ring.in = rx_ring.out = 0; -+ memset( &charstats, 0, sizeof( charstats ) ); -+ sending = 0; -+ last_tx_result = 0; -+ last_tx_size = 0; -+ } -+ -+ /* modify default descriptors */ -+ twiddle_descriptors(); -+ -+ retval = sa1100_usb_start(); -+ if ( retval ) { -+ printk( "%sAGHH! Could not USB core\n", pszMe ); -+ free_txrx_buffers(); -+ return retval; -+ } -+ usb_ref_count++; /* must do _before_ kick_start() */ -+ MOD_INC_USE_COUNT; -+ kick_start_rx(); -+ return 0; -+ -+ malloc_fail: -+ free_txrx_buffers(); -+ return -ENOMEM; -+} -+ -+/* -+ * Read endpoint. Note that you can issue a read to an -+ * unconfigured endpoint. Eventually, the host may come along -+ * and configure underneath this module and data will appear. -+ */ -+static ssize_t usbc_read( struct file *pFile, char *pUserBuffer, -+ size_t stCount, loff_t *pPos ) -+{ -+ ssize_t retval; -+ int flags; -+ DECLARE_WAITQUEUE( wait, current ); -+ -+ PRINTK( KERN_DEBUG "%sread()\n", pszMe ); -+ -+ local_irq_save( flags ); -+ if ( last_rx_result == 0 ) { -+ local_irq_restore( flags ); -+ } else { /* an error happended and receiver is paused */ -+ local_irq_restore( flags ); -+ last_rx_result = 0; -+ kick_start_rx(); -+ } -+ -+ add_wait_queue( &wq_read, &wait ); -+ while( 1 ) { -+ ssize_t bytes_avail; -+ ssize_t bytes_to_end; -+ -+ set_current_state( TASK_INTERRUPTIBLE ); -+ -+ /* snap ring buf state */ -+ local_irq_save( flags ); -+ bytes_avail = CIRC_CNT( rx_ring.in, rx_ring.out, RBUF_SIZE ); -+ bytes_to_end = CIRC_CNT_TO_END( rx_ring.in, rx_ring.out, RBUF_SIZE ); -+ local_irq_restore( flags ); -+ -+ if ( bytes_avail != 0 ) { -+ ssize_t bytes_to_move = MIN( stCount, bytes_avail ); -+ retval = 0; // will be bytes transfered -+ if ( bytes_to_move != 0 ) { -+ size_t n = MIN( bytes_to_end, bytes_to_move ); -+ if ( copy_to_user( pUserBuffer, -+ &rx_ring.buf[ rx_ring.out ], -+ n ) ) { -+ retval = -EFAULT; -+ break; -+ } -+ bytes_to_move -= n; -+ retval += n; -+ // might go 1 char off end, so wrap -+ rx_ring.out = ( rx_ring.out + n ) & (RBUF_SIZE-1); -+ if ( copy_to_user( pUserBuffer + n, -+ &rx_ring.buf[ rx_ring.out ], -+ bytes_to_move ) -+ ) { -+ retval = -EFAULT; -+ break; -+ } -+ rx_ring.out += bytes_to_move; // cannot wrap -+ retval += bytes_to_move; -+ kick_start_rx(); -+ } -+ break; -+ } -+ else if ( last_rx_result ) { -+ retval = last_rx_result; -+ break; -+ } -+ else if ( pFile->f_flags & O_NONBLOCK ) { // no data, can't sleep -+ retval = -EAGAIN; -+ break; -+ } -+ else if ( signal_pending( current ) ) { // no data, can sleep, but signal -+ retval = -ERESTARTSYS; -+ break; -+ } -+ schedule(); // no data, can sleep -+ } -+ set_current_state( TASK_RUNNING ); -+ remove_wait_queue( &wq_read, &wait ); -+ -+ if ( retval < 0 ) -+ printk( "%sread error %d - %s\n", pszMe, retval, what_the_f( retval ) ); -+ return retval; -+} -+ -+/* -+ * Write endpoint. This routine attempts to break the passed in buffer -+ * into usb DATA0/1 packet size chunks and send them to the host. -+ * (The lower-level driver tries to do this too, but easier for us -+ * to manage things here.) -+ * -+ * We are at the mercy of the host here, in that it must send an IN -+ * token to us to pull this data back, so hopefully some higher level -+ * protocol is expecting traffic to flow in that direction so the host -+ * is actually polling us. To guard against hangs, a 5 second timeout -+ * is used. -+ * -+ * This routine takes some care to only report bytes sent that have -+ * actually made it across the wire. Thus we try to stay in lockstep -+ * with the completion routine and only have one packet on the xmit -+ * hardware at a time. Multiple simultaneous writers will get -+ * "undefined" results. -+ * -+ */ -+static ssize_t usbc_write( struct file *pFile, const char * pUserBuffer, -+ size_t stCount, loff_t *pPos ) -+{ -+ ssize_t retval = 0; -+ ssize_t stSent = 0; -+ -+ DECLARE_WAITQUEUE( wait, current ); -+ -+ PRINTK( KERN_DEBUG "%swrite() %d bytes\n", pszMe, stCount ); -+ -+ down( &xmit_sem ); // only one thread onto the hardware at a time -+ -+ while( stCount != 0 && retval == 0 ) { -+ int nThisTime = MIN( TX_PACKET_SIZE, stCount ); -+ copy_from_user( tx_buf, pUserBuffer, nThisTime ); -+ sending = nThisTime; -+ retval = sa1100_usb_send( tx_buf, nThisTime, tx_done_callback ); -+ if ( retval < 0 ) { -+ char * p = what_the_f( retval ); -+ printk( "%sCould not queue xmission. rc=%d - %s\n", -+ pszMe, retval, p ); -+ sending = 0; -+ break; -+ } -+ /* now have something on the diving board */ -+ add_wait_queue( &wq_write, &wait ); -+ tx_timer.expires = jiffies + ( HZ * 5 ); -+ add_timer( &tx_timer ); -+ while( 1 ) { -+ set_current_state( TASK_INTERRUPTIBLE ); -+ if ( sending == 0 ) { /* it jumped into the pool */ -+ del_timer( &tx_timer ); -+ retval = last_tx_result; -+ if ( retval == 0 ) { -+ stSent += last_tx_size; -+ pUserBuffer += last_tx_size; -+ stCount -= last_tx_size; -+ } -+ else -+ printk( "%sxmission error rc=%d - %s\n", -+ pszMe, retval, what_the_f(retval) ); -+ break; -+ } -+ else if ( signal_pending( current ) ) { -+ del_timer( &tx_timer ); -+ printk( "%ssignal\n", pszMe ); -+ retval = -ERESTARTSYS; -+ break; -+ } -+ schedule(); -+ } -+ set_current_state( TASK_RUNNING ); -+ remove_wait_queue( &wq_write, &wait ); -+ } -+ -+ up( &xmit_sem ); -+ -+ if ( 0 == retval ) -+ retval = stSent; -+ return retval; -+} -+ -+static unsigned int usbc_poll( struct file *pFile, poll_table * pWait ) -+{ -+ unsigned int retval = 0; -+ -+ PRINTK( KERN_DEBUG "%poll()\n", pszMe ); -+ -+ poll_wait( pFile, &wq_poll, pWait ); -+ -+ if ( CIRC_CNT( rx_ring.in, rx_ring.out, RBUF_SIZE ) ) -+ retval |= POLLIN | POLLRDNORM; -+ if ( sa1100_usb_xmitter_avail() ) -+ retval |= POLLOUT | POLLWRNORM; -+ return retval; -+} -+ -+static int usbc_ioctl( struct inode *pInode, struct file *pFile, -+ unsigned int nCmd, unsigned long argument ) -+{ -+ int retval = 0; -+ -+ switch( nCmd ) { -+ -+ case USBC_IOC_FLUSH_RECEIVER: -+ sa1100_usb_recv_reset(); -+ rx_ring.in = rx_ring.out = 0; -+ break; -+ -+ case USBC_IOC_FLUSH_TRANSMITTER: -+ sa1100_usb_send_reset(); -+ break; -+ -+ case USBC_IOC_FLUSH_ALL: -+ sa1100_usb_recv_reset(); -+ rx_ring.in = rx_ring.out = 0; -+ sa1100_usb_send_reset(); -+ break; -+ -+ default: -+ retval = -ENOIOCTLCMD; -+ break; -+ -+ } -+ return retval; -+} -+ -+ -+static int usbc_close( struct inode *pInode, struct file * pFile ) -+{ -+ PRINTK( KERN_DEBUG "%sclose()\n", pszMe ); -+ if ( --usb_ref_count == 0 ) { -+ down( &xmit_sem ); -+ sa1100_usb_stop(); -+ free_txrx_buffers(); -+ free_string_descriptors(); -+ del_timer( &tx_timer ); -+ sa1100_usb_close(); -+ up( &xmit_sem ); -+ } -+ MOD_DEC_USE_COUNT; -+ return 0; -+} -+ -+#ifdef CONFIG_SA1100_EXTENEX1 -+#include "../../../drivers/char/ex_gpio.h" -+void extenex_configured_notify_proc( void ) -+{ -+ if ( exgpio_play_string( "440,1:698,1" ) == -EAGAIN ) -+ printk( "%sWanted to BEEP but ex_gpio not open\n", pszMe ); -+} -+#endif -+////////////////////////////////////////////////////////////////////////////// -+// Initialization -+////////////////////////////////////////////////////////////////////////////// -+ -+static struct file_operations usbc_fops = { -+ owner: THIS_MODULE, -+ open: usbc_open, -+ read: usbc_read, -+ write: usbc_write, -+ poll: usbc_poll, -+ ioctl: usbc_ioctl, -+ release: usbc_close, -+}; -+ -+static struct miscdevice usbc_misc_device = { -+ USBC_MINOR, "usb_char", &usbc_fops -+}; -+ -+/* -+ * usbc_init() -+ */ -+ -+int __init usbc_init( void ) -+{ -+ int rc; -+ -+#if !defined( CONFIG_ARCH_SA1100 ) -+ return -ENODEV; -+#endif -+ -+ if ( (rc = misc_register( &usbc_misc_device )) != 0 ) { -+ printk( KERN_WARNING "%sCould not register device 10, " -+ "%d. (%d)\n", pszMe, USBC_MINOR, rc ); -+ return -EBUSY; -+ } -+ -+ // initialize wait queues -+ init_waitqueue_head( &wq_read ); -+ init_waitqueue_head( &wq_write ); -+ init_waitqueue_head( &wq_poll ); -+ -+ // initialize tx timeout timer -+ init_timer( &tx_timer ); -+ tx_timer.function = tx_timeout; -+ -+ printk( KERN_INFO "USB Function Character Driver Interface" -+ " - %s, (C) 2001, Extenex Corp.\n", VERSION -+ ); -+ -+ return rc; -+} -+ -+void __exit usbc_exit( void ) -+{ -+} -+ -+EXPORT_NO_SYMBOLS; -+ -+module_init(usbc_init); -+module_exit(usbc_exit); -+ -+ -+ -+// end: usb-char.c -+ -+ -+ -diff -urN linux-2.4.26/arch/arm/mach-sa1100/usb-char.h linux-2.4.26-vrs1/arch/arm/mach-sa1100/usb-char.h ---- linux-2.4.26/arch/arm/mach-sa1100/usb-char.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mach-sa1100/usb-char.h 2004-01-14 21:32:24.000000000 +0000 -@@ -0,0 +1,34 @@ -+/* -+ * Copyright (C) 2001 Extenex Corporation -+ * -+ * usb-char.h -+ * -+ * Character device emulation client for SA-1100 client usb core. -+ * -+ * -+ * -+ */ -+#ifndef _USB_CHAR_H -+#define _USB_CHAR_H -+ -+#define USBC_MAJOR 10 /* miscellaneous character device */ -+#define USBC_MINOR 240 /* in the "reserved for local use" range */ -+ -+#define USBC_MAGIC 0x8E -+ -+/* zap everything in receive ring buffer */ -+#define USBC_IOC_FLUSH_RECEIVER _IO( USBC_MAGIC, 0x01 ) -+ -+/* reset transmitter */ -+#define USBC_IOC_FLUSH_TRANSMITTER _IO( USBC_MAGIC, 0x02 ) -+ -+/* do both of above */ -+#define USBC_IOC_FLUSH_ALL _IO( USBC_MAGIC, 0x03 ) -+ -+ -+ -+ -+ -+ -+#endif /* _USB_CHAR_H */ -+ -diff -urN linux-2.4.26/arch/arm/mach-sa1100/usb-eth.c linux-2.4.26-vrs1/arch/arm/mach-sa1100/usb-eth.c ---- linux-2.4.26/arch/arm/mach-sa1100/usb-eth.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mach-sa1100/usb-eth.c 2004-01-14 21:32:24.000000000 +0000 -@@ -0,0 +1,447 @@ -+ /* -+ * Ethernet driver for the SA1100 USB client function -+ * Copyright (c) 2001 by Nicolas Pitre -+ * -+ * This code was loosely inspired by the original initial ethernet test driver -+ * Copyright (c) Compaq Computer Corporation, 1999 -+ * -+ * 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 is still work in progress... -+ * -+ * 19/02/2001 - Now we are compatible with generic usbnet driver. green@iXcelerator.com -+ * 09/03/2001 - Dropped 'framing' scheme, as it seems to cause a lot of problems with little benefit. -+ * Now, since we do not know what size of packet we are receiving -+ * last usb packet in sequence will always be less than max packet -+ * receive endpoint can accept. -+ * Now the only way to check correct start of frame is to compare -+ * MAC address. Also now we are stalling on each receive error. -+ * -+ * 15/03/2001 - Using buffer to get data from UDC. DMA needs to have 8 byte -+ * aligned buffer, but this breaks IP code (unaligned access). -+ * -+ * 01/04/2001 - stall endpoint operations appeared to be very unstable, so -+ * they are disabled now. -+ * -+ * 03/06/2001 - Readded "zerocopy" receive path (tunable). -+ * -+ */ -+ -+// Define DMA_NO_COPY if you want data to arrive directly into the -+// receive network buffers, instead of arriving into bounce buffer -+// and then get copied to network buffer. -+// This does not work correctly right now. -+#undef DMA_NO_COPY -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "sa1100_usb.h" -+ -+ -+#define ETHERNET_VENDOR_ID 0x49f -+#define ETHERNET_PRODUCT_ID 0x505A -+#define MAX_PACKET 32768 -+#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -+ -+// Should be global, so that insmod can change these -+int usb_rsize=64; -+int usb_wsize=64; -+ -+static struct usbe_info_t { -+ struct net_device *dev; -+ u16 packet_id; -+ struct net_device_stats stats; -+} usbe_info; -+ -+static char usb_eth_name[16] = "usbf"; -+static struct net_device usb_eth_device; -+static struct sk_buff *cur_tx_skb, *next_tx_skb; -+static struct sk_buff *cur_rx_skb, *next_rx_skb; -+static volatile int terminating; -+#ifndef DMA_NO_COPY -+static char *dmabuf; // we need that, as dma expect it's buffers to be aligned on 8 bytes boundary -+#endif -+ -+static int usb_change_mtu (struct net_device *net, int new_mtu) -+{ -+ if (new_mtu <= sizeof (struct ethhdr) || new_mtu > MAX_PACKET) -+ return -EINVAL; -+ // no second zero-length packet read wanted after mtu-sized packets -+ if (((new_mtu + sizeof (struct ethhdr)) % usb_rsize) == 0) -+ return -EDOM; -+ -+ net->mtu = new_mtu; -+ return 0; -+} -+ -+static struct sk_buff * -+usb_new_recv_skb(void) -+{ -+ struct sk_buff *skb = alloc_skb( 2 + sizeof (struct ethhdr) + usb_eth_device.mtu,GFP_ATOMIC); -+ -+ if (skb) { -+ skb_reserve(skb, 2); -+ } -+ return skb; -+} -+ -+static u8 bcast_hwaddr[ETH_ALEN]={0xff,0xff,0xff,0xff,0xff,0xff}; -+static void -+usb_recv_callback(int flag, int size) -+{ -+ struct sk_buff *skb; -+ -+ if (terminating) -+ return; -+ -+ skb = cur_rx_skb; -+ -+ /* flag validation */ -+ if (flag == 0) { -+ if ( skb_tailroom (skb) < size ) { // hey! we are overloaded!!! -+ usbe_info.stats.rx_over_errors++; -+ goto error; -+ } -+#ifndef DMA_NO_COPY -+ memcpy(skb->tail,dmabuf,size); -+#endif -+ skb_put(skb, size); -+ } else { -+ if (flag == -EIO) { -+ usbe_info.stats.rx_errors++; -+ } -+ goto error; -+ } -+ -+ /* validate packet length */ -+ if (size == usb_rsize ) { -+ /* packet not complete yet */ -+ skb = NULL; -+ } -+ -+ /* -+ * At this point skb is non null if we have a complete packet. -+ * If so take a fresh skb right away and restart USB receive without -+ * further delays, then process the packet. Otherwise resume USB -+ * receive on the current skb and exit. -+ */ -+ -+ if (skb) -+ cur_rx_skb = next_rx_skb; -+#ifndef DMA_NO_COPY -+ sa1100_usb_recv(dmabuf, usb_rsize, -+ usb_recv_callback); -+#else -+ sa1100_usb_recv(cur_rx_skb->tail, MIN(usb_rsize, skb_tailroom (cur_rx_skb)), -+ usb_recv_callback); -+#endif -+ if (!skb) -+ return; -+ -+ next_rx_skb = usb_new_recv_skb(); -+ if (!next_rx_skb) { -+ /* -+ * We can't aford loosing buffer space... -+ * So we drop the current packet and recycle its skb. -+ */ -+ printk("%s: can't allocate new skb\n", __FUNCTION__); -+ usbe_info.stats.rx_dropped++; -+ skb_trim(skb, 0); -+ next_rx_skb = skb; -+ return; -+ } -+ if ( skb->len >= sizeof(struct ethhdr)) { -+ if (memcmp(skb->data,usb_eth_device.dev_addr,ETH_ALEN) && memcmp(skb->data,bcast_hwaddr,ETH_ALEN) ) { -+ // This frame is not for us. nor it is broadcast -+ usbe_info.stats.rx_frame_errors++; -+ kfree_skb(skb); -+ goto error; -+ } -+ } -+ -+ if (skb->len) { -+ int status; -+// FIXME: eth_copy_and_csum "small" packets to new SKB (small < ~200 bytes) ? -+ -+ skb->dev = &usb_eth_device; -+ skb->protocol = eth_type_trans (skb, &usb_eth_device); -+ usbe_info.stats.rx_packets++; -+ usbe_info.stats.rx_bytes += skb->len; -+ skb->ip_summed = CHECKSUM_NONE; -+ status = netif_rx (skb); -+ if (status != NET_RX_SUCCESS) -+ printk("netif_rx failed with code %d\n",status); -+ } else { -+error: -+ /* -+ * Error due to HW addr mismatch, or IO error. -+ * Recycle the current skb and reset USB reception. -+ */ -+ skb_trim(cur_rx_skb, 0); -+// if ( flag == -EINTR || flag == -EAGAIN ) // only if we are coming out of stall -+#ifndef DMA_NO_COPY -+ sa1100_usb_recv(dmabuf, usb_rsize, usb_recv_callback); -+#else -+ sa1100_usb_recv(cur_rx_skb->tail, MIN(usb_rsize, skb_tailroom (cur_rx_skb)), usb_recv_callback); -+#endif -+ } -+} -+ -+ -+static void -+usb_send_callback(int flag, int size) -+{ -+ struct net_device *dev = usbe_info.dev; -+ struct net_device_stats *stats; -+ struct sk_buff *skb=cur_tx_skb; -+ int ret; -+ -+ if (terminating) -+ return; -+ -+ stats = &usbe_info.stats; -+ switch (flag) { -+ case 0: -+ stats->tx_packets++; -+ stats->tx_bytes += size; -+ break; -+ case -EIO: -+ stats->tx_errors++; -+ break; -+ default: -+ stats->tx_dropped++; -+ break; -+ } -+ -+ cur_tx_skb = next_tx_skb; -+ next_tx_skb = NULL; -+ dev_kfree_skb_irq(skb); -+ if (!cur_tx_skb) -+ return; -+ -+ dev->trans_start = jiffies; -+ ret = sa1100_usb_send(cur_tx_skb->data, cur_tx_skb->len, usb_send_callback); -+ if (ret) { -+ /* If the USB core can't accept the packet, we drop it. */ -+ dev_kfree_skb_irq(cur_tx_skb); -+ cur_tx_skb = NULL; -+ usbe_info.stats.tx_carrier_errors++; -+ } -+ netif_wake_queue(dev); -+} -+ -+static int -+usb_eth_xmit(struct sk_buff *skb, struct net_device *dev) -+{ -+ int ret; -+ unsigned long flags; -+ -+ if (next_tx_skb) { -+ printk("%s: called with next_tx_skb != NULL\n", __FUNCTION__); -+ return 1; -+ } -+ -+ if (skb_shared (skb)) { -+ struct sk_buff *skb2 = skb_unshare(skb, GFP_ATOMIC); -+ if (!skb2) { -+ usbe_info.stats.tx_dropped++; -+ dev_kfree_skb(skb); -+ return 1; -+ } -+ skb = skb2; -+ } -+ -+ if ((skb->len % usb_wsize) == 0) { -+ skb->len++; // other side will ignore this one, anyway. -+ } -+ -+ local_irq_save(flags); -+ if (cur_tx_skb) { -+ next_tx_skb = skb; -+ netif_stop_queue(dev); -+ } else { -+ cur_tx_skb = skb; -+ dev->trans_start = jiffies; -+ ret = sa1100_usb_send(skb->data, skb->len, usb_send_callback); -+ if (ret) { -+ /* If the USB core can't accept the packet, we drop it. */ -+ dev_kfree_skb(skb); -+ cur_tx_skb = NULL; -+ usbe_info.stats.tx_carrier_errors++; -+ } -+ } -+ local_irq_restore(flags); -+ return 0; -+} -+ -+static void -+usb_xmit_timeout(struct net_device *dev ) -+{ -+ sa1100_usb_send_reset(); -+ dev->trans_start = jiffies; -+ netif_wake_queue(dev); -+} -+ -+ -+static int -+usb_eth_open(struct net_device *dev) -+{ -+ terminating = 0; -+ cur_tx_skb = next_tx_skb = NULL; -+ cur_rx_skb = usb_new_recv_skb(); -+ next_rx_skb = usb_new_recv_skb(); -+ if (!cur_rx_skb || !next_rx_skb) { -+ printk("%s: can't allocate new skb\n", __FUNCTION__); -+ if (cur_rx_skb) -+ kfree_skb(cur_rx_skb); -+ if (next_rx_skb) -+ kfree_skb(next_rx_skb); -+ return -ENOMEM;; -+ } -+ -+ MOD_INC_USE_COUNT; -+#ifndef DMA_NO_COPY -+ sa1100_usb_recv(dmabuf, usb_rsize, usb_recv_callback); -+#else -+ sa1100_usb_recv(cur_rx_skb->tail, MIN(usb_rsize, skb_tailroom (cur_rx_skb)), -+ usb_recv_callback); -+#endif -+ return 0; -+} -+ -+static int -+usb_eth_release(struct net_device *dev) -+{ -+ terminating = 1; -+ sa1100_usb_send_reset(); -+ sa1100_usb_recv_reset(); -+ if (cur_tx_skb) -+ kfree_skb(cur_tx_skb); -+ if (next_tx_skb) -+ kfree_skb(next_tx_skb); -+ if (cur_rx_skb) -+ kfree_skb(cur_rx_skb); -+ if (next_rx_skb) -+ kfree_skb(next_rx_skb); -+ MOD_DEC_USE_COUNT; -+ return 0; -+} -+ -+static struct net_device_stats * -+usb_eth_stats(struct net_device *dev) -+{ -+ struct usbe_info_t *priv = (struct usbe_info_t*) dev->priv; -+ struct net_device_stats *stats=NULL; -+ -+ if (priv) -+ stats = &priv->stats; -+ return stats; -+} -+ -+static int -+usb_eth_probe(struct net_device *dev) -+{ -+ u8 node_id [ETH_ALEN]; -+ -+ get_random_bytes (node_id, sizeof node_id); -+ node_id [0] &= 0xfe; // clear multicast bit -+ -+ /* -+ * Assign the hardware address of the board: -+ * generate it randomly, as there can be many such -+ * devices on the bus. -+ */ -+ memcpy (dev->dev_addr, node_id, sizeof node_id); -+ -+ dev->open = usb_eth_open; -+ dev->change_mtu = usb_change_mtu; -+ dev->stop = usb_eth_release; -+ dev->hard_start_xmit = usb_eth_xmit; -+ dev->get_stats = usb_eth_stats; -+ dev->watchdog_timeo = 1*HZ; -+ dev->tx_timeout = usb_xmit_timeout; -+ dev->priv = &usbe_info; -+ -+ usbe_info.dev = dev; -+ -+ /* clear the statistics */ -+ memset(&usbe_info.stats, 0, sizeof(struct net_device_stats)); -+ -+ ether_setup(dev); -+ dev->flags &= ~IFF_MULTICAST; -+ dev->flags &= ~IFF_BROADCAST; -+ //dev->flags |= IFF_NOARP; -+ -+ return 0; -+} -+ -+#ifdef MODULE -+MODULE_PARM(usb_rsize, "1i"); -+MODULE_PARM_DESC(usb_rsize, "number of bytes in packets from host to sa1100"); -+MODULE_PARM(usb_wsize, "1i"); -+MODULE_PARM_DESC(usb_wsize, "number of bytes in packets from sa1100 to host"); -+#endif -+ -+static int __init -+usb_eth_init(void) -+{ -+ int rc; -+ -+#ifndef DMA_NO_COPY -+ dmabuf = kmalloc( usb_rsize, GFP_KERNEL | GFP_DMA ); -+ if (!dmabuf) -+ return -ENOMEM; -+#endif -+ strncpy(usb_eth_device.name, usb_eth_name, IFNAMSIZ); -+ usb_eth_device.init = usb_eth_probe; -+ if (register_netdev(&usb_eth_device) != 0) -+ return -EIO; -+ -+ rc = sa1100_usb_open( "usb-eth" ); -+ if ( rc == 0 ) { -+ string_desc_t * pstr; -+ desc_t * pd = sa1100_usb_get_descriptor_ptr(); -+ -+ pd->b.ep1.wMaxPacketSize = make_word( usb_rsize ); -+ pd->b.ep2.wMaxPacketSize = make_word( usb_wsize ); -+ pd->dev.idVendor = ETHERNET_VENDOR_ID; -+ pd->dev.idProduct = ETHERNET_PRODUCT_ID; -+ pstr = sa1100_usb_kmalloc_string_descriptor( "SA1100 USB NIC" ); -+ if ( pstr ) { -+ sa1100_usb_set_string_descriptor( 1, pstr ); -+ pd->dev.iProduct = 1; -+ } -+ rc = sa1100_usb_start(); -+ } -+ return rc; -+} -+ -+module_init(usb_eth_init); -+ -+static void __exit -+usb_eth_cleanup(void) -+{ -+ string_desc_t * pstr; -+ sa1100_usb_stop(); -+ sa1100_usb_close(); -+ if ( (pstr = sa1100_usb_get_string_descriptor(1)) != NULL ) -+ kfree( pstr ); -+#ifndef DMA_NO_COPY -+ kfree(dmabuf); -+#endif -+ unregister_netdev(&usb_eth_device); -+} -+ -+module_exit(usb_eth_cleanup); -diff -urN linux-2.4.26/arch/arm/mach-sa1100/usb_ctl.c linux-2.4.26-vrs1/arch/arm/mach-sa1100/usb_ctl.c ---- linux-2.4.26/arch/arm/mach-sa1100/usb_ctl.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mach-sa1100/usb_ctl.c 2004-01-14 21:32:24.000000000 +0000 -@@ -0,0 +1,774 @@ -+ /* -+ * Copyright (C) Compaq Computer Corporation, 1998, 1999 -+ * Copyright (C) Extenex Corporation, 2001 -+ * -+ * usb_ctl.c -+ * -+ * SA1100 USB controller core driver. -+ * -+ * This file provides interrupt routing and overall coordination -+ * of the three endpoints in usb_ep0, usb_receive (1), and usb_send (2). -+ * -+ * Please see linux/Documentation/arm/SA1100/SA1100_USB for details. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "sa1100_usb.h" -+#include "usb_ctl.h" -+ -+////////////////////////////////////////////////////////////////////////////// -+// Prototypes -+////////////////////////////////////////////////////////////////////////////// -+ -+int usbctl_next_state_on_event( int event ); -+static void udc_int_hndlr(int, void *, struct pt_regs *); -+static void initialize_descriptors( void ); -+static void soft_connect_hook( int enable ); -+static void udc_disable(void); -+static void udc_enable(void); -+ -+#if CONFIG_PROC_FS -+#define PROC_NODE_NAME "sausb" -+static int usbctl_read_proc(char *page, char **start, off_t off, -+ int count, int *eof, void *data); -+#endif -+ -+////////////////////////////////////////////////////////////////////////////// -+// Globals -+////////////////////////////////////////////////////////////////////////////// -+static const char pszMe[] = "usbctl: "; -+struct usb_info_t usbd_info; /* global to ep0, usb_recv, usb_send */ -+ -+/* device descriptors */ -+static desc_t desc; -+ -+#define MAX_STRING_DESC 8 -+static string_desc_t * string_desc_array[ MAX_STRING_DESC ]; -+static string_desc_t sd_zero; /* special sd_zero holds language codes */ -+ -+// called when configured -+static usb_notify_t configured_callback = NULL; -+ -+enum { kStateZombie = 0, kStateZombieSuspend = 1, -+ kStateDefault = 2, kStateDefaultSuspend = 3, -+ kStateAddr = 4, kStateAddrSuspend = 5, -+ kStateConfig = 6, kStateConfigSuspend = 7 -+}; -+ -+static int device_state_machine[8][6] = { -+// suspend reset resume adddr config deconfig -+/* zombie */ { kStateZombieSuspend, kStateDefault, kError, kError, kError, kError }, -+/* zom sus */ { kError, kStateDefault, kStateZombie, kError, kError, kError }, -+/* default */ { kStateDefaultSuspend, kError, kStateDefault, kStateAddr, kError, kError }, -+/* def sus */ { kError, kStateDefault, kStateDefault, kError, kError, kError }, -+/* addr */ { kStateAddrSuspend, kStateDefault, kError, kError, kStateConfig, kError }, -+/* addr sus */{ kError, kStateDefault, kStateAddr, kError, kError, kError }, -+/* config */ { kStateConfigSuspend, kStateDefault, kError, kError, kError, kStateAddr }, -+/* cfg sus */ { kError, kStateDefault, kStateConfig, kError, kError, kError } -+}; -+ -+/* "device state" is the usb device framework state, as opposed to the -+ "state machine state" which is whatever the driver needs and is much -+ more fine grained -+*/ -+static int sm_state_to_device_state[8] = -+// zombie zom suspend default default sus -+{ USB_STATE_POWERED, USB_STATE_SUSPENDED, USB_STATE_DEFAULT, USB_STATE_SUSPENDED, -+// addr addr sus config config sus -+ USB_STATE_ADDRESS, USB_STATE_SUSPENDED, USB_STATE_CONFIGURED, USB_STATE_SUSPENDED -+}; -+ -+static char * state_names[8] = -+{ "zombie", "zombie suspended", "default", "default suspended", -+ "address", "address suspended", "configured", "config suspended" -+}; -+ -+static char * event_names[6] = -+{ "suspend", "reset", "resume", -+ "address assigned", "configure", "de-configure" -+}; -+ -+static char * device_state_names[] = -+{ "not attached", "attached", "powered", "default", -+ "address", "configured", "suspended" }; -+ -+static int sm_state = kStateZombie; -+ -+////////////////////////////////////////////////////////////////////////////// -+// Async -+////////////////////////////////////////////////////////////////////////////// -+static void core_kicker(void); -+ -+static inline void enable_resume_mask_suspend( void ); -+static inline void enable_suspend_mask_resume(void); -+ -+static void -+udc_int_hndlr(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ __u32 status = Ser0UDCSR; -+ -+ /* ReSeT Interrupt Request - UDC has been reset */ -+ if ( status & UDCSR_RSTIR ) -+ { -+ if ( usbctl_next_state_on_event( kEvReset ) != kError ) -+ { -+ /* starting 20ms or so reset sequence now... */ -+ printk("%sResetting\n", pszMe); -+ ep0_reset(); // just set state to idle -+ ep1_reset(); // flush dma, clear false stall -+ ep2_reset(); // flush dma, clear false stall -+ } -+ // mask reset ints, they flood during sequence, enable -+ // suspend and resume -+ Ser0UDCCR |= UDCCR_REM; // mask reset -+ Ser0UDCCR &= ~(UDCCR_SUSIM | UDCCR_RESIM); // enable suspend and resume -+ UDC_flip( Ser0UDCSR, status ); // clear all pending sources -+ return; // <-- no reason to continue if resetting -+ } -+ // else we have done something other than reset, so be sure reset enabled -+ UDC_clear( Ser0UDCCR, UDCCR_REM ); -+ -+ /* RESume Interrupt Request */ -+ if ( status & UDCSR_RESIR ) -+ { -+ usbctl_next_state_on_event( kEvResume ); -+ core_kicker(); -+ enable_suspend_mask_resume(); -+ } -+ -+ /* SUSpend Interrupt Request */ -+ if ( status & UDCSR_SUSIR ) -+ { -+ usbctl_next_state_on_event( kEvSuspend ); -+ enable_resume_mask_suspend(); -+ } -+ -+ UDC_flip(Ser0UDCSR, status); // clear all pending sources -+ -+ if (status & UDCSR_EIR) -+ ep0_int_hndlr(); -+ -+ if (status & UDCSR_RIR) -+ ep1_int_hndlr(status); -+ -+ if (status & UDCSR_TIR) -+ ep2_int_hndlr(status); -+} -+ -+static inline void enable_resume_mask_suspend( void ) -+{ -+ int i = 0; -+ -+ while( 1 ) { -+ Ser0UDCCR |= UDCCR_SUSIM; // mask future suspend events -+ udelay( i ); -+ if ( (Ser0UDCCR & UDCCR_SUSIM) || (Ser0UDCSR & UDCSR_RSTIR) ) -+ break; -+ if ( ++i == 50 ) { -+ printk( "%senable_resume(): Could not set SUSIM %8.8X\n", -+ pszMe, Ser0UDCCR ); -+ break; -+ } -+ } -+ -+ i = 0; -+ while( 1 ) { -+ Ser0UDCCR &= ~UDCCR_RESIM; -+ udelay( i ); -+ if ( ( Ser0UDCCR & UDCCR_RESIM ) == 0 -+ || -+ (Ser0UDCSR & UDCSR_RSTIR) -+ ) -+ break; -+ if ( ++i == 50 ) { -+ printk( "%senable_resume(): Could not clear RESIM %8.8X\n", -+ pszMe, Ser0UDCCR ); -+ break; -+ } -+ } -+} -+ -+static inline void enable_suspend_mask_resume(void) -+{ -+ int i = 0; -+ while( 1 ) { -+ Ser0UDCCR |= UDCCR_RESIM; // mask future resume events -+ udelay( i ); -+ if ( Ser0UDCCR & UDCCR_RESIM || (Ser0UDCSR & UDCSR_RSTIR) ) -+ break; -+ if ( ++i == 50 ) { -+ printk( "%senable_suspend(): Could not set RESIM %8.8X\n", -+ pszMe, Ser0UDCCR ); -+ break; -+ } -+ } -+ i = 0; -+ while( 1 ) { -+ Ser0UDCCR &= ~UDCCR_SUSIM; -+ udelay( i ); -+ if ( ( Ser0UDCCR & UDCCR_SUSIM ) == 0 -+ || -+ (Ser0UDCSR & UDCSR_RSTIR) -+ ) -+ break; -+ if ( ++i == 50 ) { -+ printk( "%senable_suspend(): Could not clear SUSIM %8.8X\n", -+ pszMe, Ser0UDCCR ); -+ break; -+ } -+ } -+} -+ -+ -+////////////////////////////////////////////////////////////////////////////// -+// Public Interface -+////////////////////////////////////////////////////////////////////////////// -+ -+/* Open SA usb core on behalf of a client, but don't start running */ -+ -+int -+sa1100_usb_open( const char * client ) -+{ -+ if ( usbd_info.client_name != NULL ) -+ return -EBUSY; -+ -+ usbd_info.client_name = (char*) client; -+ memset(&usbd_info.stats, 0, sizeof(struct usb_stats_t)); -+ memset(string_desc_array, 0, sizeof(string_desc_array)); -+ -+ /* hack to start in zombie suspended state */ -+ sm_state = kStateZombieSuspend; -+ usbd_info.state = USB_STATE_SUSPENDED; -+ -+ /* create descriptors for enumeration */ -+ initialize_descriptors(); -+ -+ printk( "%sOpened for %s\n", pszMe, client ); -+ return 0; -+} -+ -+/* Start running. Must have called usb_open (above) first */ -+int -+sa1100_usb_start( void ) -+{ -+ if ( usbd_info.client_name == NULL ) { -+ printk( "%s%s - no client registered\n", -+ pszMe, __FUNCTION__ ); -+ return -EPERM; -+ } -+ -+ /* start UDC internal machinery running */ -+ udc_enable(); -+ udelay( 100 ); -+ -+ /* clear stall - receiver seems to start stalled? 19Jan01ww */ -+ /* also clear other stuff just to be thurough 22Feb01ww */ -+ UDC_clear(Ser0UDCCS1, UDCCS1_FST | UDCCS1_RPE | UDCCS1_RPC ); -+ UDC_clear(Ser0UDCCS2, UDCCS2_FST | UDCCS2_TPE | UDCCS2_TPC ); -+ -+ /* mask everything */ -+ Ser0UDCCR = 0xFC; -+ -+ /* flush DMA and fire through some -EAGAINs */ -+ ep1_init( usbd_info.dmach_rx ); -+ ep2_init( usbd_info.dmach_tx ); -+ -+ /* give endpoint notification we are starting */ -+ ep1_state_change_notify( USB_STATE_SUSPENDED ); -+ ep2_state_change_notify( USB_STATE_SUSPENDED ); -+ -+ /* enable any platform specific hardware */ -+ soft_connect_hook( 1 ); -+ -+ /* clear all top-level sources */ -+ Ser0UDCSR = UDCSR_RSTIR | UDCSR_RESIR | UDCSR_EIR | -+ UDCSR_RIR | UDCSR_TIR | UDCSR_SUSIR ; -+ -+ /* EXERIMENT - a short line in the spec says toggling this -+ ..bit diddles the internal state machine in the udc to -+ ..expect a suspend */ -+ Ser0UDCCR |= UDCCR_RESIM; -+ /* END EXPERIMENT 10Feb01ww */ -+ -+ /* enable any platform specific hardware */ -+ soft_connect_hook( 1 ); -+ -+ /* enable interrupts. If you are unplugged you will -+ immediately get a suspend interrupt. If you are plugged -+ and have a soft connect-circuit, you will get a reset -+ If you are plugged without a soft-connect, I think you -+ also get suspend. In short, start with suspend masked -+ and everything else enabled */ -+ UDC_write( Ser0UDCCR, UDCCR_SUSIM ); -+ -+ printk( "%sStarted for %s\n", pszMe, usbd_info.client_name ); -+ return 0; -+} -+ -+/* Stop USB core from running */ -+int -+sa1100_usb_stop( void ) -+{ -+ if ( usbd_info.client_name == NULL ) { -+ printk( "%s%s - no client registered\n", -+ pszMe, __FUNCTION__ ); -+ return -EPERM; -+ } -+ /* mask everything */ -+ Ser0UDCCR = 0xFC; -+ ep1_reset(); -+ ep2_reset(); -+ udc_disable(); -+ printk( "%sStopped\n", pszMe ); -+ return 0; -+} -+ -+/* Tell SA core client is through using it */ -+int -+sa1100_usb_close( void ) -+{ -+ if ( usbd_info.client_name == NULL ) { -+ printk( "%s%s - no client registered\n", -+ pszMe, __FUNCTION__ ); -+ return -EPERM; -+ } -+ usbd_info.client_name = NULL; -+ printk( "%sClosed\n", pszMe ); -+ return 0; -+} -+ -+/* set a proc to be called when device is configured */ -+usb_notify_t sa1100_set_configured_callback( usb_notify_t func ) -+{ -+ usb_notify_t retval = configured_callback; -+ configured_callback = func; -+ return retval; -+} -+ -+/*==================================================== -+ * Descriptor Manipulation. -+ * Use these between open() and start() above to setup -+ * the descriptors for your device. -+ * -+ */ -+ -+/* get pointer to static default descriptor */ -+desc_t * -+sa1100_usb_get_descriptor_ptr( void ) { return &desc; } -+ -+/* optional: set a string descriptor */ -+int -+sa1100_usb_set_string_descriptor( int i, string_desc_t * p ) -+{ -+ int retval; -+ if ( i < MAX_STRING_DESC ) { -+ string_desc_array[i] = p; -+ retval = 0; -+ } else { -+ retval = -EINVAL; -+ } -+ return retval; -+} -+ -+/* optional: get a previously set string descriptor */ -+string_desc_t * -+sa1100_usb_get_string_descriptor( int i ) -+{ -+ return ( i < MAX_STRING_DESC ) -+ ? string_desc_array[i] -+ : NULL; -+} -+ -+ -+/* optional: kmalloc and unicode up a string descriptor */ -+string_desc_t * -+sa1100_usb_kmalloc_string_descriptor( const char * p ) -+{ -+ string_desc_t * pResult = NULL; -+ -+ if ( p ) { -+ int len = strlen( p ); -+ int uni_len = len * sizeof( __u16 ); -+ pResult = (string_desc_t*) kmalloc( uni_len + 2, GFP_KERNEL ); /* ugh! */ -+ if ( pResult != NULL ) { -+ int i; -+ pResult->bLength = uni_len + 2; -+ pResult->bDescriptorType = USB_DESC_STRING; -+ for( i = 0; i < len ; i++ ) { -+ pResult->bString[i] = make_word( (__u16) p[i] ); -+ } -+ } -+ } -+ return pResult; -+} -+ -+////////////////////////////////////////////////////////////////////////////// -+// Exports to rest of driver -+////////////////////////////////////////////////////////////////////////////// -+ -+/* called by the int handler here and the two endpoint files when interesting -+ .."events" happen */ -+ -+int -+usbctl_next_state_on_event( int event ) -+{ -+ int next_state = device_state_machine[ sm_state ][ event ]; -+ if ( next_state != kError ) -+ { -+ int next_device_state = sm_state_to_device_state[ next_state ]; -+ printk( "%s%s --> [%s] --> %s. Device in %s state.\n", -+ pszMe, state_names[ sm_state ], event_names[ event ], -+ state_names[ next_state ], device_state_names[ next_device_state ] ); -+ -+ sm_state = next_state; -+ if ( usbd_info.state != next_device_state ) -+ { -+ if ( configured_callback != NULL -+ && -+ next_device_state == USB_STATE_CONFIGURED -+ && -+ usbd_info.state != USB_STATE_SUSPENDED -+ ) { -+ configured_callback(); -+ } -+ usbd_info.state = next_device_state; -+ ep1_state_change_notify( next_device_state ); -+ ep2_state_change_notify( next_device_state ); -+ } -+ } -+#if 0 -+ else -+ printk( "%s%s --> [%s] --> ??? is an error.\n", -+ pszMe, state_names[ sm_state ], event_names[ event ] ); -+#endif -+ return next_state; -+} -+ -+////////////////////////////////////////////////////////////////////////////// -+// Private Helpers -+////////////////////////////////////////////////////////////////////////////// -+ -+/* setup default descriptors */ -+ -+static void -+initialize_descriptors(void) -+{ -+ desc.dev.bLength = sizeof( device_desc_t ); -+ desc.dev.bDescriptorType = USB_DESC_DEVICE; -+ desc.dev.bcdUSB = 0x100; /* 1.0 */ -+ desc.dev.bDeviceClass = 0xFF; /* vendor specific */ -+ desc.dev.bDeviceSubClass = 0; -+ desc.dev.bDeviceProtocol = 0; -+ desc.dev.bMaxPacketSize0 = 8; /* ep0 max fifo size */ -+ desc.dev.idVendor = 0; /* vendor ID undefined */ -+ desc.dev.idProduct = 0; /* product */ -+ desc.dev.bcdDevice = 0; /* vendor assigned device release num */ -+ desc.dev.iManufacturer = 0; /* index of manufacturer string */ -+ desc.dev.iProduct = 0; /* index of product description string */ -+ desc.dev.iSerialNumber = 0; /* index of string holding product s/n */ -+ desc.dev.bNumConfigurations = 1; -+ -+ desc.b.cfg.bLength = sizeof( config_desc_t ); -+ desc.b.cfg.bDescriptorType = USB_DESC_CONFIG; -+ desc.b.cfg.wTotalLength = make_word_c( sizeof(struct cdb) ); -+ desc.b.cfg.bNumInterfaces = 1; -+ desc.b.cfg.bConfigurationValue = 1; -+ desc.b.cfg.iConfiguration = 0; -+ desc.b.cfg.bmAttributes = USB_CONFIG_BUSPOWERED; -+ desc.b.cfg.MaxPower = USB_POWER( 500 ); -+ -+ desc.b.intf.bLength = sizeof( intf_desc_t ); -+ desc.b.intf.bDescriptorType = USB_DESC_INTERFACE; -+ desc.b.intf.bInterfaceNumber = 0; /* unique intf index*/ -+ desc.b.intf.bAlternateSetting = 0; -+ desc.b.intf.bNumEndpoints = 2; -+ desc.b.intf.bInterfaceClass = 0xFF; /* vendor specific */ -+ desc.b.intf.bInterfaceSubClass = 0; -+ desc.b.intf.bInterfaceProtocol = 0; -+ desc.b.intf.iInterface = 0; -+ -+ desc.b.ep1.bLength = sizeof( ep_desc_t ); -+ desc.b.ep1.bDescriptorType = USB_DESC_ENDPOINT; -+ desc.b.ep1.bEndpointAddress = USB_EP_ADDRESS( 1, USB_OUT ); -+ desc.b.ep1.bmAttributes = USB_EP_BULK; -+ desc.b.ep1.wMaxPacketSize = make_word_c( 64 ); -+ desc.b.ep1.bInterval = 0; -+ -+ desc.b.ep2.bLength = sizeof( ep_desc_t ); -+ desc.b.ep2.bDescriptorType = USB_DESC_ENDPOINT; -+ desc.b.ep2.bEndpointAddress = USB_EP_ADDRESS( 2, USB_IN ); -+ desc.b.ep2.bmAttributes = USB_EP_BULK; -+ desc.b.ep2.wMaxPacketSize = make_word_c( 64 ); -+ desc.b.ep2.bInterval = 0; -+ -+ /* set language */ -+ /* See: http://www.usb.org/developers/data/USB_LANGIDs.pdf */ -+ sd_zero.bDescriptorType = USB_DESC_STRING; -+ sd_zero.bLength = sizeof( string_desc_t ); -+ sd_zero.bString[0] = make_word_c( 0x409 ); /* American English */ -+ sa1100_usb_set_string_descriptor( 0, &sd_zero ); -+} -+ -+/* soft_connect_hook() -+ * Some devices have platform-specific circuitry to make USB -+ * not seem to be plugged in, even when it is. This allows -+ * software to control when a device 'appears' on the USB bus -+ * (after Linux has booted and this driver has loaded, for -+ * example). If you have such a circuit, control it here. -+ */ -+static void -+soft_connect_hook( int enable ) -+{ -+#ifdef CONFIG_SA1100_EXTENEX1 -+ if (machine_is_extenex1() ) { -+ if ( enable ) { -+ PPDR |= PPC_USB_SOFT_CON; -+ PPSR |= PPC_USB_SOFT_CON; -+ } else { -+ PPSR &= ~PPC_USB_SOFT_CON; -+ PPDR &= ~PPC_USB_SOFT_CON; -+ } -+ } -+#endif -+} -+ -+/* disable the UDC at the source */ -+static void -+udc_disable(void) -+{ -+ soft_connect_hook( 0 ); -+ UDC_set( Ser0UDCCR, UDCCR_UDD ); -+} -+ -+ -+/* enable the udc at the source */ -+static void -+udc_enable(void) -+{ -+ UDC_clear(Ser0UDCCR, UDCCR_UDD); -+} -+ -+// HACK DEBUG 3Mar01ww -+// Well, maybe not, it really seems to help! 08Mar01ww -+static void -+core_kicker( void ) -+{ -+ __u32 car = Ser0UDCAR; -+ __u32 imp = Ser0UDCIMP; -+ __u32 omp = Ser0UDCOMP; -+ -+ UDC_set( Ser0UDCCR, UDCCR_UDD ); -+ udelay( 300 ); -+ UDC_clear(Ser0UDCCR, UDCCR_UDD); -+ -+ Ser0UDCAR = car; -+ Ser0UDCIMP = imp; -+ Ser0UDCOMP = omp; -+} -+ -+////////////////////////////////////////////////////////////////////////////// -+// Proc Filesystem Support -+////////////////////////////////////////////////////////////////////////////// -+ -+#if CONFIG_PROC_FS -+ -+#define SAY( fmt, args... ) p += sprintf(p, fmt, ## args ) -+#define SAYV( num ) p += sprintf(p, num_fmt, "Value", num ) -+#define SAYC( label, yn ) p += sprintf(p, yn_fmt, label, yn ) -+#define SAYS( label, v ) p += sprintf(p, cnt_fmt, label, v ) -+ -+static int usbctl_read_proc(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ const char * num_fmt = "%25.25s: %8.8lX\n"; -+ const char * cnt_fmt = "%25.25s: %lu\n"; -+ const char * yn_fmt = "%25.25s: %s\n"; -+ const char * yes = "YES"; -+ const char * no = "NO"; -+ unsigned long v; -+ char * p = page; -+ int len; -+ -+ SAY( "SA1100 USB Controller Core\n" ); -+ SAY( "USB state: %s (%s) %d\n", -+ device_state_names[ sm_state_to_device_state[ sm_state ] ], -+ state_names[ sm_state ], -+ sm_state ); -+ -+ SAYS( "ep0 bytes read", usbd_info.stats.ep0_bytes_read ); -+ SAYS( "ep0 bytes written", usbd_info.stats.ep0_bytes_written ); -+ SAYS( "ep0 FIFO read failures", usbd_info.stats.ep0_fifo_write_failures ); -+ SAYS( "ep0 FIFO write failures", usbd_info.stats.ep0_fifo_write_failures ); -+ -+ SAY( "\n" ); -+ -+ v = Ser0UDCAR; -+ SAY( "%25.25s: 0x%8.8lX - %ld\n", "Address Register", v, v ); -+ v = Ser0UDCIMP; -+ SAY( "%25.25s: %ld (%8.8lX)\n", "IN max packet size", v+1, v ); -+ v = Ser0UDCOMP; -+ SAY( "%25.25s: %ld (%8.8lX)\n", "OUT max packet size", v+1, v ); -+ -+ v = Ser0UDCCR; -+ SAY( "\nUDC Mask Register\n" ); -+ SAYV( v ); -+ SAYC( "UDC Active", ( v & UDCCR_UDA ) ? yes : no ); -+ SAYC( "Suspend interrupts masked", ( v & UDCCR_SUSIM ) ? yes : no ); -+ SAYC( "Resume interrupts masked", ( v & UDCCR_RESIM ) ? yes : no ); -+ SAYC( "Reset interrupts masked", ( v & UDCCR_REM ) ? yes : no ); -+ -+ v = Ser0UDCSR; -+ SAY( "\nUDC Interrupt Request Register\n" ); -+ SAYV( v ); -+ SAYC( "Reset pending", ( v & UDCSR_RSTIR ) ? yes : no ); -+ SAYC( "Suspend pending", ( v & UDCSR_SUSIR ) ? yes : no ); -+ SAYC( "Resume pending", ( v & UDCSR_RESIR ) ? yes : no ); -+ SAYC( "ep0 pending", ( v & UDCSR_EIR ) ? yes : no ); -+ SAYC( "receiver pending", ( v & UDCSR_RIR ) ? yes : no ); -+ SAYC( "tramsitter pending", ( v & UDCSR_TIR ) ? yes : no ); -+ -+#ifdef CONFIG_SA1100_EXTENEX1 -+ SAYC( "\nSoft connect", (PPSR & PPC_USB_SOFT_CON) ? "Visible" : "Hidden" ); -+#endif -+ -+#if 0 -+ v = Ser0UDCCS0; -+ SAY( "\nUDC Endpoint Zero Status Register\n" ); -+ SAYV( v ); -+ SAYC( "Out Packet Ready", ( v & UDCCS0_OPR ) ? yes : no ); -+ SAYC( "In Packet Ready", ( v & UDCCS0_IPR ) ? yes : no ); -+ SAYC( "Sent Stall", ( v & UDCCS0_SST ) ? yes : no ); -+ SAYC( "Force Stall", ( v & UDCCS0_FST ) ? yes : no ); -+ SAYC( "Data End", ( v & UDCCS0_DE ) ? yes : no ); -+ SAYC( "Data Setup End", ( v & UDCCS0_SE ) ? yes : no ); -+ SAYC( "Serviced (SO)", ( v & UDCCS0_SO ) ? yes : no ); -+ -+ v = Ser0UDCCS1; -+ SAY( "\nUDC Receiver Status Register\n" ); -+ SAYV( v ); -+ SAYC( "Receive Packet Complete", ( v & UDCCS1_RPC ) ? yes : no ); -+ SAYC( "Sent Stall", ( v & UDCCS1_SST ) ? yes : no ); -+ SAYC( "Force Stall", ( v & UDCCS1_FST ) ? yes : no ); -+ SAYC( "Receive Packet Error", ( v & UDCCS1_RPE ) ? yes : no ); -+ SAYC( "Receive FIFO not empty", ( v & UDCCS1_RNE ) ? yes : no ); -+ -+ v = Ser0UDCCS2; -+ SAY( "\nUDC Transmitter Status Register\n" ); -+ SAYV( v ); -+ SAYC( "FIFO has < 8 of 16 chars", ( v & UDCCS2_TFS ) ? yes : no ); -+ SAYC( "Transmit Packet Complete", ( v & UDCCS2_TPC ) ? yes : no ); -+ SAYC( "Transmit FIFO underrun", ( v & UDCCS2_TUR ) ? yes : no ); -+ SAYC( "Transmit Packet Error", ( v & UDCCS2_TPE ) ? yes : no ); -+ SAYC( "Sent Stall", ( v & UDCCS2_SST ) ? yes : no ); -+ SAYC( "Force Stall", ( v & UDCCS2_FST ) ? yes : no ); -+#endif -+ -+ len = ( p - page ) - off; -+ if ( len < 0 ) -+ len = 0; -+ *eof = ( len <=count ) ? 1 : 0; -+ *start = page + off; -+ return len; -+} -+ -+#endif /* CONFIG_PROC_FS */ -+ -+////////////////////////////////////////////////////////////////////////////// -+// Module Initialization and Shutdown -+////////////////////////////////////////////////////////////////////////////// -+/* -+ * usbctl_init() -+ * Module load time. Allocate dma and interrupt resources. Setup /proc fs -+ * entry. Leave UDC disabled. -+ */ -+int __init usbctl_init( void ) -+{ -+ int retval = 0; -+ -+ udc_disable(); -+ -+ memset( &usbd_info, 0, sizeof( usbd_info ) ); -+ -+#if CONFIG_PROC_FS -+ create_proc_read_entry ( PROC_NODE_NAME, 0, NULL, usbctl_read_proc, NULL); -+#endif -+ -+ /* setup rx dma */ -+ retval = sa1100_request_dma(&usbd_info.dmach_rx, "USB receive", DMA_Ser0UDCRd); -+ if (retval) { -+ printk("%sunable to register for rx dma rc=%d\n", pszMe, retval ); -+ goto err_rx_dma; -+ } -+ -+ /* setup tx dma */ -+ retval = sa1100_request_dma(&usbd_info.dmach_tx, "USB transmit", DMA_Ser0UDCWr); -+ if (retval) { -+ printk("%sunable to register for tx dma rc=%d\n",pszMe,retval); -+ goto err_tx_dma; -+ } -+ -+ /* now allocate the IRQ. */ -+ retval = request_irq(IRQ_Ser0UDC, udc_int_hndlr, SA_INTERRUPT, -+ "SA USB core", NULL); -+ if (retval) { -+ printk("%sCouldn't request USB irq rc=%d\n",pszMe, retval); -+ goto err_irq; -+ } -+ -+ printk( "SA1100 USB Controller Core Initialized\n"); -+ return 0; -+ -+err_irq: -+ sa1100_free_dma(usbd_info.dmach_tx); -+ usbd_info.dmach_tx = 0; -+err_tx_dma: -+ sa1100_free_dma(usbd_info.dmach_rx); -+ usbd_info.dmach_rx = 0; -+err_rx_dma: -+ return retval; -+} -+/* -+ * usbctl_exit() -+ * Release DMA and interrupt resources -+ */ -+void __exit usbctl_exit( void ) -+{ -+ printk("Unloading SA1100 USB Controller\n"); -+ -+ udc_disable(); -+ -+#if CONFIG_PROC_FS -+ remove_proc_entry ( PROC_NODE_NAME, NULL); -+#endif -+ -+ sa1100_free_dma(usbd_info.dmach_rx); -+ sa1100_free_dma(usbd_info.dmach_tx); -+ free_irq(IRQ_Ser0UDC, NULL); -+} -+ -+EXPORT_SYMBOL( sa1100_usb_open ); -+EXPORT_SYMBOL( sa1100_usb_start ); -+EXPORT_SYMBOL( sa1100_usb_stop ); -+EXPORT_SYMBOL( sa1100_usb_close ); -+ -+ -+EXPORT_SYMBOL( sa1100_usb_get_descriptor_ptr ); -+EXPORT_SYMBOL( sa1100_usb_set_string_descriptor ); -+EXPORT_SYMBOL( sa1100_usb_get_string_descriptor ); -+EXPORT_SYMBOL( sa1100_usb_kmalloc_string_descriptor ); -+ -+ -+module_init( usbctl_init ); -+module_exit( usbctl_exit ); -diff -urN linux-2.4.26/arch/arm/mach-sa1100/usb_ctl.h linux-2.4.26-vrs1/arch/arm/mach-sa1100/usb_ctl.h ---- linux-2.4.26/arch/arm/mach-sa1100/usb_ctl.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mach-sa1100/usb_ctl.h 2004-01-14 21:32:24.000000000 +0000 -@@ -0,0 +1,123 @@ -+/* -+ * Copyright (C) Compaq Computer Corporation, 1998, 1999 -+ * Copyright (C) Extenex Corporation 2001 -+ * -+ * usb_ctl.h -+ * -+ * PRIVATE interface used to share info among components of the SA-1100 USB -+ * core: usb_ctl, usb_ep0, usb_recv and usb_send. Clients of the USB core -+ * should use sa1100_usb.h. -+ * -+ */ -+ -+#ifndef _USB_CTL_H -+#define _USB_CTL_H -+ -+#include /* dmach_t */ -+ -+ -+/* -+ * These states correspond to those in the USB specification v1.0 -+ * in chapter 8, Device Framework. -+ */ -+enum { USB_STATE_NOTATTACHED=0, USB_STATE_ATTACHED=1,USB_STATE_POWERED=2, -+ USB_STATE_DEFAULT=3, USB_STATE_ADDRESS=4, USB_STATE_CONFIGURED=5, -+ USB_STATE_SUSPENDED=6}; -+ -+struct usb_stats_t { -+ unsigned long ep0_fifo_write_failures; -+ unsigned long ep0_bytes_written; -+ unsigned long ep0_fifo_read_failures; -+ unsigned long ep0_bytes_read; -+}; -+ -+struct usb_info_t -+{ -+ char * client_name; -+ dmach_t dmach_tx, dmach_rx; -+ int state; -+ unsigned char address; -+ struct usb_stats_t stats; -+}; -+ -+/* in usb_ctl.c */ -+extern struct usb_info_t usbd_info; -+ -+/* -+ * Function Prototypes -+ */ -+enum { kError=-1, kEvSuspend=0, kEvReset=1, -+ kEvResume=2, kEvAddress=3, kEvConfig=4, kEvDeConfig=5 }; -+int usbctl_next_state_on_event( int event ); -+ -+/* endpoint zero */ -+void ep0_reset(void); -+void ep0_int_hndlr(void); -+ -+/* receiver */ -+void ep1_state_change_notify( int new_state ); -+int ep1_recv(void); -+int ep1_init(int chn); -+void ep1_int_hndlr(int status); -+void ep1_reset(void); -+void ep1_stall(void); -+ -+/* xmitter */ -+void ep2_state_change_notify( int new_state ); -+void ep2_reset(void); -+int ep2_init(int chn); -+void ep2_int_hndlr(int status); -+void ep2_stall(void); -+ -+#define UDC_write(reg, val) { \ -+ int i = 10000; \ -+ do { \ -+ (reg) = (val); \ -+ if (i-- <= 0) { \ -+ printk( "%s [%d]: write %#x to %p (%#x) failed\n", \ -+ __FUNCTION__, __LINE__, (val), &(reg), (reg)); \ -+ break; \ -+ } \ -+ } while((reg) != (val)); \ -+} -+ -+#define UDC_set(reg, val) { \ -+ int i = 10000; \ -+ do { \ -+ (reg) |= (val); \ -+ if (i-- <= 0) { \ -+ printk( "%s [%d]: set %#x of %p (%#x) failed\n", \ -+ __FUNCTION__, __LINE__, (val), &(reg), (reg)); \ -+ break; \ -+ } \ -+ } while(!((reg) & (val))); \ -+} -+ -+#define UDC_clear(reg, val) { \ -+ int i = 10000; \ -+ do { \ -+ (reg) &= ~(val); \ -+ if (i-- <= 0) { \ -+ printk( "%s [%d]: clear %#x of %p (%#x) failed\n", \ -+ __FUNCTION__, __LINE__, (val), &(reg), (reg)); \ -+ break; \ -+ } \ -+ } while((reg) & (val)); \ -+} -+ -+#define UDC_flip(reg, val) { \ -+ int i = 10000; \ -+ (reg) = (val); \ -+ do { \ -+ (reg) = (val); \ -+ if (i-- <= 0) { \ -+ printk( "%s [%d]: flip %#x of %p (%#x) failed\n", \ -+ __FUNCTION__, __LINE__, (val), &(reg), (reg)); \ -+ break; \ -+ } \ -+ } while(((reg) & (val))); \ -+} -+ -+ -+#define CHECK_ADDRESS { if ( Ser0UDCAR == 1 ) { printk("%s:%d I lost my address!!!\n",__FUNCTION__, __LINE__);}} -+#endif /* _USB_CTL_H */ -diff -urN linux-2.4.26/arch/arm/mach-sa1100/usb_ep0.c linux-2.4.26-vrs1/arch/arm/mach-sa1100/usb_ep0.c ---- linux-2.4.26/arch/arm/mach-sa1100/usb_ep0.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mach-sa1100/usb_ep0.c 2004-01-14 21:32:24.000000000 +0000 -@@ -0,0 +1,911 @@ -+/* -+ * Copyright (C) Extenex Corporation 2001 -+ * Much folklore gleaned from original code: -+ * Copyright (C) Compaq Computer Corporation, 1998, 1999 -+ * -+ * usb_ep0.c - SA1100 USB controller driver. -+ * Endpoint zero management -+ * -+ * Please see: -+ * linux/Documentation/arm/SA1100/SA1100_USB -+ * for details. (Especially since Intel docs are full of -+ * errors about ep0 operation.) ward.willats@extenex.com. -+ * -+ * Intel also has a "Universal Serial Bus Client Device -+ * Validation for the StrongARM SA-1100 Microprocessor" -+ * document, which has flow charts and assembler test driver, -+ * but be careful, since it is just for validation and not -+ * a "real world" solution. -+ * -+ * A summary of three types of data-returning setups: -+ * -+ * 1. Setup request <= 8 bytes. That is, requests that can -+ * be fullfilled in one write to the FIFO. DE is set -+ * with IPR in queue_and_start_write(). (I don't know -+ * if there really are any of these!) -+ * -+ * 2. Setup requests > 8 bytes (requiring more than one -+ * IN to get back to the host), and we have at least -+ * as much or more data than the host requested. In -+ * this case we pump out everything we've got, and -+ * when the final interrupt comes in due to the UDC -+ * clearing the last IPR, we just set DE. -+ * -+ * 3. Setup requests > 8 bytes, but we don't have enough -+ * data to satisfy the request. In this case, we send -+ * everything we've got, and when the final interrupt -+ * comes in due to the UDC clearing the last IPR -+ * we write nothing to the FIFO and set both IPR and DE -+ * so the UDC sends an empty packet and forces the host -+ * to perform short packet retirement instead of stalling -+ * out. -+ * -+ */ -+ -+#include -+#include "sa1100_usb.h" /* public interface */ -+#include "usb_ctl.h" /* private stuff */ -+ -+ -+// 1 == lots of trace noise, 0 = only "important' stuff -+#define VERBOSITY 0 -+ -+enum { true = 1, false = 0 }; -+typedef int bool; -+#ifndef MIN -+#define MIN( a, b ) ((a)<(b)?(a):(b)) -+#endif -+ -+#if 1 && !defined( ASSERT ) -+# define ASSERT(expr) \ -+ if(!(expr)) { \ -+ printk( "Assertion failed! %s,%s,%s,line=%d\n",\ -+ #expr,__FILE__,__FUNCTION__,__LINE__); \ -+ } -+#else -+# define ASSERT(expr) -+#endif -+ -+#if VERBOSITY -+#define PRINTKD(fmt, args...) printk( fmt , ## args) -+#else -+#define PRINTKD(fmt, args...) -+#endif -+ -+/*================================================ -+ * USB Protocol Stuff -+ */ -+ -+/* Request Codes */ -+enum { GET_STATUS=0, CLEAR_FEATURE=1, SET_FEATURE=3, -+ SET_ADDRESS=5, GET_DESCRIPTOR=6, SET_DESCRIPTOR=7, -+ GET_CONFIGURATION=8, SET_CONFIGURATION=9, GET_INTERFACE=10, -+ SET_INTERFACE=11 }; -+ -+ -+/* USB Device Requests */ -+typedef struct -+{ -+ __u8 bmRequestType; -+ __u8 bRequest; -+ __u16 wValue; -+ __u16 wIndex; -+ __u16 wLength; -+} usb_dev_request_t __attribute__ ((packed)); -+ -+/*************************************************************************** -+Prototypes -+***************************************************************************/ -+/* "setup handlers" -- the main functions dispatched to by the -+ .. isr. These represent the major "modes" of endpoint 0 operaton */ -+static void sh_setup_begin(void); /* setup begin (idle) */ -+static void sh_write( void ); /* writing data */ -+static void sh_write_with_empty_packet( void ); /* empty packet at end of xfer*/ -+/* called before both sh_write routines above */ -+static void common_write_preamble( void ); -+ -+/* other subroutines */ -+static __u32 queue_and_start_write( void * p, int req, int act ); -+static void write_fifo( void ); -+static int read_fifo( usb_dev_request_t * p ); -+static void get_descriptor( usb_dev_request_t * pReq ); -+ -+/* some voodo helpers 01Mar01ww */ -+static void set_cs_bits( __u32 set_bits ); -+static void set_de( void ); -+static void set_ipr( void ); -+static void set_ipr_and_de( void ); -+static bool clear_opr( void ); -+ -+/*************************************************************************** -+Inline Helpers -+***************************************************************************/ -+ -+/* Data extraction from usb_request_t fields */ -+enum { kTargetDevice=0, kTargetInterface=1, kTargetEndpoint=2 }; -+static inline int request_target( __u8 b ) { return (int) ( b & 0x0F); } -+ -+static inline int windex_to_ep_num( __u16 w ) { return (int) ( w & 0x000F); } -+inline int type_code_from_request( __u8 by ) { return (( by >> 4 ) & 3); } -+ -+/* following is hook for self-powered flag in GET_STATUS. Some devices -+ .. might like to override and return real info */ -+static inline bool self_powered_hook( void ) { return true; } -+ -+/* print string descriptor */ -+static inline void psdesc( string_desc_t * p ) -+{ -+ int i; -+ int nchars = ( p->bLength - 2 ) / sizeof( __u16 ); -+ printk( "'" ); -+ for( i = 0 ; i < nchars ; i++ ) { -+ printk( "%c", (char) p->bString[i] ); -+ } -+ printk( "'\n" ); -+} -+ -+ -+#if VERBOSITY -+/* "pcs" == "print control status" */ -+static inline void pcs( void ) -+{ -+ __u32 foo = Ser0UDCCS0; -+ printk( "%8.8X: %s %s %s %s\n", -+ foo, -+ foo & UDCCS0_SE ? "SE" : "", -+ foo & UDCCS0_OPR ? "OPR" : "", -+ foo & UDCCS0_IPR ? "IPR" : "", -+ foo & UDCCS0_SST ? "SST" : "" -+ ); -+} -+static inline void preq( usb_dev_request_t * pReq ) -+{ -+ static char * tnames[] = { "dev", "intf", "ep", "oth" }; -+ static char * rnames[] = { "std", "class", "vendor", "???" }; -+ char * psz; -+ switch( pReq->bRequest ) { -+ case GET_STATUS: psz = "get stat"; break; -+ case CLEAR_FEATURE: psz = "clr feat"; break; -+ case SET_FEATURE: psz = "set feat"; break; -+ case SET_ADDRESS: psz = "set addr"; break; -+ case GET_DESCRIPTOR: psz = "get desc"; break; -+ case SET_DESCRIPTOR: psz = "set desc"; break; -+ case GET_CONFIGURATION: psz = "get cfg"; break; -+ case SET_CONFIGURATION: psz = "set cfg"; break; -+ case GET_INTERFACE: psz = "get intf"; break; -+ case SET_INTERFACE: psz = "set intf"; break; -+ default: psz = "unknown"; break; -+ } -+ printk( "- [%s: %s req to %s. dir=%s]\n", psz, -+ rnames[ (pReq->bmRequestType >> 5) & 3 ], -+ tnames[ pReq->bmRequestType & 3 ], -+ ( pReq->bmRequestType & 0x80 ) ? "in" : "out" ); -+} -+ -+#else -+static inline void pcs( void ){} -+static inline void preq( void ){} -+#endif -+ -+/*************************************************************************** -+Globals -+***************************************************************************/ -+static const char pszMe[] = "usbep0: "; -+ -+/* pointer to current setup handler */ -+static void (*current_handler)(void) = sh_setup_begin; -+ -+/* global write struct to keep write -+ ..state around across interrupts */ -+static struct { -+ unsigned char *p; -+ int bytes_left; -+} wr; -+ -+/*************************************************************************** -+Public Interface -+***************************************************************************/ -+ -+/* reset received from HUB (or controller just went nuts and reset by itself!) -+ so udc core has been reset, track this state here */ -+void -+ep0_reset(void) -+{ -+ /* reset state machine */ -+ current_handler = sh_setup_begin; -+ wr.p = NULL; -+ wr.bytes_left = 0; -+ usbd_info.address=0; -+} -+ -+/* handle interrupt for endpoint zero */ -+void -+ep0_int_hndlr( void ) -+{ -+ PRINTKD( "/\\(%d)\n", Ser0UDCAR ); -+ pcs(); -+ -+ /* if not in setup begin, we are returning data. -+ execute a common preamble to both write handlers -+ */ -+ if ( current_handler != sh_setup_begin ) -+ common_write_preamble(); -+ -+ (*current_handler)(); -+ -+ PRINTKD( "---\n" ); -+ pcs(); -+ PRINTKD( "\\/\n" ); -+} -+ -+/*************************************************************************** -+Setup Handlers -+***************************************************************************/ -+/* -+ * sh_setup_begin() -+ * This setup handler is the "idle" state of endpoint zero. It looks for OPR -+ * (OUT packet ready) to see if a setup request has been been received from the -+ * host. Requests without a return data phase are immediately handled. Otherwise, -+ * in the case of GET_XXXX the handler may be set to one of the sh_write_xxxx -+ * data pumpers if more than 8 bytes need to get back to the host. -+ * -+ */ -+static void -+sh_setup_begin( void ) -+{ -+ unsigned char status_buf[2]; /* returned in GET_STATUS */ -+ usb_dev_request_t req; -+ int request_type; -+ int n; -+ __u32 cs_bits; -+ __u32 address; -+ __u32 cs_reg_in = Ser0UDCCS0; -+ -+ if (cs_reg_in & UDCCS0_SST) { -+ PRINTKD( "%ssetup begin: sent stall. Continuing\n", pszMe ); -+ set_cs_bits( UDCCS0_SST ); -+ } -+ -+ if ( cs_reg_in & UDCCS0_SE ) { -+ PRINTKD( "%ssetup begin: Early term of setup. Continuing\n", pszMe ); -+ set_cs_bits( UDCCS0_SSE ); /* clear setup end */ -+ } -+ -+ /* Be sure out packet ready, otherwise something is wrong */ -+ if ( (cs_reg_in & UDCCS0_OPR) == 0 ) { -+ /* we can get here early...if so, we'll int again in a moment */ -+ PRINTKD( "%ssetup begin: no OUT packet available. Exiting\n", pszMe ); -+ goto sh_sb_end; -+ } -+ -+ /* read the setup request */ -+ n = read_fifo( &req ); -+ if ( n != sizeof( req ) ) { -+ printk( "%ssetup begin: fifo READ ERROR wanted %d bytes got %d. " -+ " Stalling out...\n", -+ pszMe, sizeof( req ), n ); -+ /* force stall, serviced out */ -+ set_cs_bits( UDCCS0_FST | UDCCS0_SO ); -+ goto sh_sb_end; -+ } -+ -+ /* Is it a standard request? (not vendor or class request) */ -+ request_type = type_code_from_request( req.bmRequestType ); -+ if ( request_type != 0 ) { -+ printk( "%ssetup begin: unsupported bmRequestType: %d ignored\n", -+ pszMe, request_type ); -+ set_cs_bits( UDCCS0_DE | UDCCS0_SO ); -+ goto sh_sb_end; -+ } -+ -+#if VERBOSITY -+ { -+ unsigned char * pdb = (unsigned char *) &req; -+ PRINTKD( "%2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X ", -+ pdb[0], pdb[1], pdb[2], pdb[3], pdb[4], pdb[5], pdb[6], pdb[7] -+ ); -+ preq( &req ); -+ } -+#endif -+ -+ /* Handle it */ -+ switch( req.bRequest ) { -+ -+ /* This first bunch have no data phase */ -+ -+ case SET_ADDRESS: -+ address = (__u32) (req.wValue & 0x7F); -+ /* when SO and DE sent, UDC will enter status phase and ack, -+ ..propagating new address to udc core. Next control transfer -+ ..will be on the new address. You can't see the change in a -+ ..read back of CAR until then. (about 250us later, on my box). -+ ..The original Intel driver sets S0 and DE and code to check -+ ..that address has propagated here. I tried this, but it -+ ..would only work sometimes! The rest of the time it would -+ ..never propagate and we'd spin forever. So now I just set -+ ..it and pray... -+ */ -+ Ser0UDCAR = address; -+ usbd_info.address = address; -+ usbctl_next_state_on_event( kEvAddress ); -+ set_cs_bits( UDCCS0_SO | UDCCS0_DE ); /* no data phase */ -+ printk( "%sI have been assigned address: %d\n", pszMe, address ); -+ break; -+ -+ -+ case SET_CONFIGURATION: -+ if ( req.wValue == 1 ) { -+ /* configured */ -+ if (usbctl_next_state_on_event( kEvConfig ) != kError){ -+ /* (re)set the out and in max packet sizes */ -+ desc_t * pDesc = sa1100_usb_get_descriptor_ptr(); -+ __u32 out = __le16_to_cpu( pDesc->b.ep1.wMaxPacketSize ); -+ __u32 in = __le16_to_cpu( pDesc->b.ep2.wMaxPacketSize ); -+ Ser0UDCOMP = ( out - 1 ); -+ Ser0UDCIMP = ( in - 1 ); -+ printk( "%sConfigured (OMP=%8.8X IMP=%8.8X)\n", pszMe, out, in ); -+ } -+ } else if ( req.wValue == 0 ) { -+ /* de-configured */ -+ if (usbctl_next_state_on_event( kEvDeConfig ) != kError ) -+ printk( "%sDe-Configured\n", pszMe ); -+ } else { -+ printk( "%ssetup phase: Unknown " -+ "\"set configuration\" data %d\n", -+ pszMe, req.wValue ); -+ } -+ set_cs_bits( UDCCS0_SO | UDCCS0_DE ); /* no data phase */ -+ break; -+ -+ case CLEAR_FEATURE: -+ /* could check data length, direction...26Jan01ww */ -+ if ( req.wValue == 0 ) { /* clearing ENDPOINT_HALT/STALL */ -+ int ep = windex_to_ep_num( req.wIndex ); -+ if ( ep == 1 ) { -+ printk( "%sclear feature \"endpoint halt\" " -+ " on receiver\n", pszMe ); -+ ep1_reset(); -+ } -+ else if ( ep == 2 ) { -+ printk( "%sclear feature \"endpoint halt\" " -+ "on xmitter\n", pszMe ); -+ ep2_reset(); -+ } else { -+ printk( "%sclear feature \"endpoint halt\" " -+ "on unsupported ep # %d\n", -+ pszMe, ep ); -+ } -+ } else { -+ printk( "%sUnsupported feature selector (%d) " -+ "in clear feature. Ignored.\n" , -+ pszMe, req.wValue ); -+ } -+ set_cs_bits( UDCCS0_SO | UDCCS0_DE ); /* no data phase */ -+ break; -+ -+ case SET_FEATURE: -+ if ( req.wValue == 0 ) { /* setting ENDPOINT_HALT/STALL */ -+ int ep = windex_to_ep_num( req.wValue ); -+ if ( ep == 1 ) { -+ printk( "%set feature \"endpoint halt\" " -+ "on receiver\n", pszMe ); -+ ep1_stall(); -+ } -+ else if ( ep == 2 ) { -+ printk( "%sset feature \"endpoint halt\" " -+ " on xmitter\n", pszMe ); -+ ep2_stall(); -+ } else { -+ printk( "%sset feature \"endpoint halt\" " -+ "on unsupported ep # %d\n", -+ pszMe, ep ); -+ } -+ } -+ else { -+ printk( "%sUnsupported feature selector " -+ "(%d) in set feature\n", -+ pszMe, req.wValue ); -+ } -+ set_cs_bits( UDCCS0_SO | UDCCS0_DE ); /* no data phase */ -+ break; -+ -+ -+ /* The rest have a data phase that writes back to the host */ -+ case GET_STATUS: -+ /* return status bit flags */ -+ status_buf[0] = status_buf[1] = 0; -+ n = request_target(req.bmRequestType); -+ switch( n ) { -+ case kTargetDevice: -+ if ( self_powered_hook() ) -+ status_buf[0] |= 1; -+ break; -+ case kTargetInterface: -+ break; -+ case kTargetEndpoint: -+ /* return stalled bit */ -+ n = windex_to_ep_num( req.wIndex ); -+ if ( n == 1 ) -+ status_buf[0] |= (Ser0UDCCS1 & UDCCS1_FST) >> 4; -+ else if ( n == 2 ) -+ status_buf[0] |= (Ser0UDCCS2 & UDCCS2_FST) >> 5; -+ else { -+ printk( "%sUnknown endpoint (%d) " -+ "in GET_STATUS\n", pszMe, n ); -+ } -+ break; -+ default: -+ printk( "%sUnknown target (%d) in GET_STATUS\n", -+ pszMe, n ); -+ /* fall thru */ -+ break; -+ } -+ cs_bits = queue_and_start_write( status_buf, -+ req.wLength, -+ sizeof( status_buf ) ); -+ set_cs_bits( cs_bits ); -+ break; -+ case GET_DESCRIPTOR: -+ get_descriptor( &req ); -+ break; -+ -+ case GET_CONFIGURATION: -+ status_buf[0] = (usbd_info.state == USB_STATE_CONFIGURED) -+ ? 1 -+ : 0; -+ cs_bits = queue_and_start_write( status_buf, req.wLength, 1 ); -+ set_cs_bits( cs_bits ); -+ break; -+ case GET_INTERFACE: -+ printk( "%sfixme: get interface not supported\n", pszMe ); -+ cs_bits = queue_and_start_write( NULL, req.wLength, 0 ); -+ set_cs_bits( cs_bits ); -+ break; -+ case SET_INTERFACE: -+ printk( "%sfixme: set interface not supported\n", pszMe ); -+ set_cs_bits( UDCCS0_DE | UDCCS0_SO ); -+ break; -+ default : -+ printk("%sunknown request 0x%x\n", pszMe, req.bRequest); -+ break; -+ } /* switch( bRequest ) */ -+ -+sh_sb_end: -+ return; -+ -+} -+/* -+ * common_wrtie_preamble() -+ * Called before execution of sh_write() or sh_write_with_empty_packet() -+ * Handles common abort conditions. -+ * -+ */ -+static void common_write_preamble( void ) -+{ -+ /* If "setup end" has been set, the usb controller has -+ ..terminated a setup transaction before we set DE. This -+ ..happens during enumeration with some hosts. For example, -+ ..the host will ask for our device descriptor and specify -+ ..a return of 64 bytes. When we hand back the first 8, the -+ ..host will know our max packet size and turn around and -+ ..issue a new setup immediately. This causes the UDC to auto-ack -+ ..the new setup and set SE. We must then "unload" (process) -+ ..the new setup, which is what will happen after this preamble -+ ..is finished executing. -+ */ -+ __u32 cs_reg_in = Ser0UDCCS0; -+ -+ if ( cs_reg_in & UDCCS0_SE ) { -+ PRINTKD( "%swrite_preamble(): Early termination of setup\n", pszMe ); -+ Ser0UDCCS0 = UDCCS0_SSE; /* clear setup end */ -+ current_handler = sh_setup_begin; -+ } -+ -+ if ( cs_reg_in & UDCCS0_SST ) { -+ PRINTKD( "%swrite_preamble(): UDC sent stall\n", pszMe ); -+ Ser0UDCCS0 = UDCCS0_SST; /* clear setup end */ -+ current_handler = sh_setup_begin; -+ } -+ -+ if ( cs_reg_in & UDCCS0_OPR ) { -+ PRINTKD( "%swrite_preamble(): see OPR. Stopping write to " -+ "handle new SETUP\n", pszMe ); -+ /* very rarely, you can get OPR and leftover IPR. Try to clear */ -+ UDC_clear( Ser0UDCCS0, UDCCS0_IPR ); -+ current_handler = sh_setup_begin; -+ } -+} -+ -+/* -+ * sh_write() -+ * This is the setup handler when we are in the data return phase of -+ * a setup request and have as much (or more) data than the host -+ * requested. If we enter this routine and bytes left is zero, the -+ * last data packet has gone (int is because IPR was just cleared) -+ * so we just set DE and reset. Otheriwse, we write another packet -+ * and set IPR. -+ */ -+static void sh_write() -+{ -+ PRINTKD( "W\n" ); -+ -+ if ( Ser0UDCCS0 & UDCCS0_IPR ) { -+ PRINTKD( "%ssh_write(): IPR set, exiting\n", pszMe ); -+ return; -+ } -+ -+ /* If bytes left is zero, we are coming in on the -+ ..interrupt after the last packet went out. And -+ ..we know we don't have to empty packet this transfer -+ ..so just set DE and we are done */ -+ -+ if ( 0 == wr.bytes_left ) { -+ /* that's it, so data end */ -+ set_de(); -+ wr.p = NULL; /* be anal */ -+ current_handler = sh_setup_begin; -+ } else { -+ /* Otherwise, more data to go */ -+ write_fifo(); -+ set_ipr(); -+ } -+} -+/* -+ * sh_write_with_empty_packet() -+ * This is the setup handler when we don't have enough data to -+ * satisfy the host's request. After we send everything we've got -+ * we must send an empty packet (by setting IPR and DE) so the -+ * host can perform "short packet retirement" and not stall. -+ * -+ */ -+static void sh_write_with_empty_packet( void ) -+{ -+ __u32 cs_reg_out = 0; -+ PRINTKD( "WE\n" ); -+ -+ if ( Ser0UDCCS0 & UDCCS0_IPR ) { -+ PRINTKD( "%ssh_write(): IPR set, exiting\n", pszMe ); -+ return; -+ } -+ -+ /* If bytes left is zero, we are coming in on the -+ ..interrupt after the last packet went out. -+ ..we must do short packet suff, so set DE and IPR -+ */ -+ -+ if ( 0 == wr.bytes_left ) { -+ set_ipr_and_de(); -+ wr.p = NULL; -+ current_handler = sh_setup_begin; -+ PRINTKD( "%ssh_write empty() Sent empty packet \n", pszMe ); -+ } else { -+ write_fifo(); /* send data */ -+ set_ipr(); /* flag a packet is ready */ -+ } -+ Ser0UDCCS0 = cs_reg_out; -+} -+ -+/*************************************************************************** -+Other Private Subroutines -+***************************************************************************/ -+/* -+ * queue_and_start_write() -+ * p == data to send -+ * req == bytes host requested -+ * act == bytes we actually have -+ * Returns: bits to be flipped in ep0 control/status register -+ * -+ * Called from sh_setup_begin() to begin a data return phase. Sets up the -+ * global "wr"-ite structure and load the outbound FIFO with data. -+ * If can't send all the data, set appropriate handler for next interrupt. -+ * -+ */ -+static __u32 queue_and_start_write( void * in, int req, int act ) -+{ -+ __u32 cs_reg_bits = UDCCS0_IPR; -+ unsigned char * p = (unsigned char*) in; -+ -+ PRINTKD( "Qr=%d a=%d\n",req,act ); -+ -+ /* thou shalt not enter data phase until the serviced OUT is clear */ -+ if ( ! clear_opr() ) { -+ printk( "%sSO did not clear OPR\n", pszMe ); -+ return ( UDCCS0_DE | UDCCS0_SO ) ; -+ } -+ wr.p = p; -+ wr.bytes_left = MIN( act, req ); -+ -+ write_fifo(); -+ -+ if ( 0 == wr.bytes_left ) { -+ cs_reg_bits |= UDCCS0_DE; /* out in 1 so data end */ -+ wr.p = NULL; /* be anal */ -+ } -+ else if ( act < req ) /* we are going to short-change host */ -+ current_handler = sh_write_with_empty_packet; /* so need nul to not stall */ -+ else /* we have as much or more than requested */ -+ current_handler = sh_write; -+ -+ return cs_reg_bits; /* note: IPR was set uncondtionally at start of routine */ -+} -+/* -+ * write_fifo() -+ * Stick bytes in the 8 bytes endpoint zero FIFO. -+ * This version uses a variety of tricks to make sure the bytes -+ * are written correctly. 1. The count register is checked to -+ * see if the byte went in, and the write is attempted again -+ * if not. 2. An overall counter is used to break out so we -+ * don't hang in those (rare) cases where the UDC reverses -+ * direction of the FIFO underneath us without notification -+ * (in response to host aborting a setup transaction early). -+ * -+ */ -+static void write_fifo( void ) -+{ -+ int bytes_this_time = MIN( wr.bytes_left, 8 ); -+ int bytes_written = 0; -+ int i=0; -+ -+ PRINTKD( "WF=%d: ", bytes_this_time ); -+ -+ while( bytes_this_time-- ) { -+ PRINTKD( "%2.2X ", *wr.p ); -+ i = 0; -+ do { -+ Ser0UDCD0 = *wr.p; -+ udelay( 20 ); /* voodo 28Feb01ww */ -+ i++; -+ } while( Ser0UDCWC == bytes_written && i < 10 ); -+ if ( i == 50 ) { -+ printk( "%swrite_fifo: write failure\n", pszMe ); -+ usbd_info.stats.ep0_fifo_write_failures++; -+ } -+ -+ wr.p++; -+ bytes_written++; -+ } -+ wr.bytes_left -= bytes_written; -+ -+ /* following propagation voodo so maybe caller writing IPR in -+ ..a moment might actually get it to stick 28Feb01ww */ -+ udelay( 300 ); -+ -+ usbd_info.stats.ep0_bytes_written += bytes_written; -+ PRINTKD( "L=%d WCR=%8.8X\n", wr.bytes_left, Ser0UDCWC ); -+} -+/* -+ * read_fifo() -+ * Read 1-8 bytes out of FIFO and put in request. -+ * Called to do the initial read of setup requests -+ * from the host. Return number of bytes read. -+ * -+ * Like write fifo above, this driver uses multiple -+ * reads checked agains the count register with an -+ * overall timeout. -+ * -+ */ -+static int -+read_fifo( usb_dev_request_t * request ) -+{ -+ int bytes_read = 0; -+ int fifo_count; -+ int i; -+ -+ unsigned char * pOut = (unsigned char*) request; -+ -+ fifo_count = ( Ser0UDCWC & 0xFF ); -+ -+ ASSERT( fifo_count <= 8 ); -+ PRINTKD( "RF=%d ", fifo_count ); -+ -+ while( fifo_count-- ) { -+ i = 0; -+ do { -+ *pOut = (unsigned char) Ser0UDCD0; -+ udelay( 10 ); -+ } while( ( Ser0UDCWC & 0xFF ) != fifo_count && i < 10 ); -+ if ( i == 10 ) { -+ printk( "%sread_fifo(): read failure\n", pszMe ); -+ usbd_info.stats.ep0_fifo_read_failures++; -+ } -+ pOut++; -+ bytes_read++; -+ } -+ -+ PRINTKD( "fc=%d\n", bytes_read ); -+ usbd_info.stats.ep0_bytes_read++; -+ return bytes_read; -+} -+ -+/* -+ * get_descriptor() -+ * Called from sh_setup_begin to handle data return -+ * for a GET_DESCRIPTOR setup request. -+ */ -+static void get_descriptor( usb_dev_request_t * pReq ) -+{ -+ __u32 cs_bits = 0; -+ string_desc_t * pString; -+ ep_desc_t * pEndpoint; -+ -+ desc_t * pDesc = sa1100_usb_get_descriptor_ptr(); -+ int type = pReq->wValue >> 8; -+ int idx = pReq->wValue & 0xFF; -+ -+ switch( type ) { -+ case USB_DESC_DEVICE: -+ cs_bits = -+ queue_and_start_write( &pDesc->dev, -+ pReq->wLength, -+ pDesc->dev.bLength ); -+ break; -+ -+ // return config descriptor buffer, cfg, intf, 2 ep -+ case USB_DESC_CONFIG: -+ cs_bits = -+ queue_and_start_write( &pDesc->b, -+ pReq->wLength, -+ sizeof( struct cdb ) ); -+ break; -+ -+ // not quite right, since doesn't do language code checking -+ case USB_DESC_STRING: -+ pString = sa1100_usb_get_string_descriptor( idx ); -+ if ( pString ) { -+ if ( idx != 0 ) { // if not language index -+ printk( "%sReturn string %d: ", pszMe, idx ); -+ psdesc( pString ); -+ } -+ cs_bits = -+ queue_and_start_write( pString, -+ pReq->wLength, -+ pString->bLength ); -+ } -+ else { -+ printk("%sunkown string index %d Stall.\n", pszMe, idx ); -+ cs_bits = ( UDCCS0_DE | UDCCS0_SO | UDCCS0_FST ); -+ } -+ break; -+ -+ case USB_DESC_INTERFACE: -+ if ( idx == pDesc->b.intf.bInterfaceNumber ) { -+ cs_bits = -+ queue_and_start_write( &pDesc->b.intf, -+ pReq->wLength, -+ pDesc->b.intf.bLength ); -+ } -+ break; -+ -+ case USB_DESC_ENDPOINT: /* correct? 21Feb01ww */ -+ if ( idx == 1 ) -+ pEndpoint = &pDesc->b.ep1; -+ else if ( idx == 2 ) -+ pEndpoint = &pDesc->b.ep2; -+ else -+ pEndpoint = NULL; -+ if ( pEndpoint ) { -+ cs_bits = -+ queue_and_start_write( pEndpoint, -+ pReq->wLength, -+ pEndpoint->bLength ); -+ } else { -+ printk("%sunkown endpoint index %d Stall.\n", pszMe, idx ); -+ cs_bits = ( UDCCS0_DE | UDCCS0_SO | UDCCS0_FST ); -+ } -+ break; -+ -+ -+ default : -+ printk("%sunknown descriptor type %d. Stall.\n", pszMe, type ); -+ cs_bits = ( UDCCS0_DE | UDCCS0_SO | UDCCS0_FST ); -+ break; -+ -+ } -+ set_cs_bits( cs_bits ); -+} -+ -+ -+/* some voodo I am adding, since the vanilla macros just aren't doing it 1Mar01ww */ -+ -+#define ABORT_BITS ( UDCCS0_SST | UDCCS0_SE ) -+#define OK_TO_WRITE (!( Ser0UDCCS0 & ABORT_BITS )) -+#define BOTH_BITS (UDCCS0_IPR | UDCCS0_DE) -+ -+static void set_cs_bits( __u32 bits ) -+{ -+ if ( bits & ( UDCCS0_SO | UDCCS0_SSE | UDCCS0_FST ) ) -+ Ser0UDCCS0 = bits; -+ else if ( (bits & BOTH_BITS) == BOTH_BITS ) -+ set_ipr_and_de(); -+ else if ( bits & UDCCS0_IPR ) -+ set_ipr(); -+ else if ( bits & UDCCS0_DE ) -+ set_de(); -+} -+ -+static void set_de( void ) -+{ -+ int i = 1; -+ while( 1 ) { -+ if ( OK_TO_WRITE ) { -+ Ser0UDCCS0 |= UDCCS0_DE; -+ } else { -+ PRINTKD( "%sQuitting set DE because SST or SE set\n", pszMe ); -+ break; -+ } -+ if ( Ser0UDCCS0 & UDCCS0_DE ) -+ break; -+ udelay( i ); -+ if ( ++i == 50 ) { -+ printk( "%sDangnabbbit! Cannot set DE! (DE=%8.8X CCS0=%8.8X)\n", -+ pszMe, UDCCS0_DE, Ser0UDCCS0 ); -+ break; -+ } -+ } -+} -+ -+static void set_ipr( void ) -+{ -+ int i = 1; -+ while( 1 ) { -+ if ( OK_TO_WRITE ) { -+ Ser0UDCCS0 |= UDCCS0_IPR; -+ } else { -+ PRINTKD( "%sQuitting set IPR because SST or SE set\n", pszMe ); -+ break; -+ } -+ if ( Ser0UDCCS0 & UDCCS0_IPR ) -+ break; -+ udelay( i ); -+ if ( ++i == 50 ) { -+ printk( "%sDangnabbbit! Cannot set IPR! (IPR=%8.8X CCS0=%8.8X)\n", -+ pszMe, UDCCS0_IPR, Ser0UDCCS0 ); -+ break; -+ } -+ } -+} -+ -+ -+ -+static void set_ipr_and_de( void ) -+{ -+ int i = 1; -+ while( 1 ) { -+ if ( OK_TO_WRITE ) { -+ Ser0UDCCS0 |= BOTH_BITS; -+ } else { -+ PRINTKD( "%sQuitting set IPR/DE because SST or SE set\n", pszMe ); -+ break; -+ } -+ if ( (Ser0UDCCS0 & BOTH_BITS) == BOTH_BITS) -+ break; -+ udelay( i ); -+ if ( ++i == 50 ) { -+ printk( "%sDangnabbbit! Cannot set DE/IPR! (DE=%8.8X IPR=%8.8X CCS0=%8.8X)\n", -+ pszMe, UDCCS0_DE, UDCCS0_IPR, Ser0UDCCS0 ); -+ break; -+ } -+ } -+} -+ -+static bool clear_opr( void ) -+{ -+ int i = 10000; -+ bool is_clear; -+ do { -+ Ser0UDCCS0 = UDCCS0_SO; -+ is_clear = ! ( Ser0UDCCS0 & UDCCS0_OPR ); -+ if ( i-- <= 0 ) { -+ printk( "%sclear_opr(): failed\n", pszMe ); -+ break; -+ } -+ } while( ! is_clear ); -+ return is_clear; -+} -+ -+ -+ -+ -+ -+/* end usb_ep0.c */ -+ -diff -urN linux-2.4.26/arch/arm/mach-sa1100/usb_recv.c linux-2.4.26-vrs1/arch/arm/mach-sa1100/usb_recv.c ---- linux-2.4.26/arch/arm/mach-sa1100/usb_recv.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mach-sa1100/usb_recv.c 2004-01-14 21:32:24.000000000 +0000 -@@ -0,0 +1,205 @@ -+/* -+ * Generic receive layer for the SA1100 USB client function -+ * Copyright (c) 2001 by Nicolas Pitre -+ * -+ * This code was loosely inspired by the original version which was -+ * Copyright (c) Compaq Computer Corporation, 1998-1999 -+ * -+ * 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 is still work in progress... -+ * -+ * Please see linux/Documentation/arm/SA1100/SA1100_USB for details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "sa1100_usb.h" -+#include "usb_ctl.h" -+ -+ -+static char *ep1_buf; -+static int ep1_len; -+static usb_callback_t ep1_callback; -+static char *ep1_curdmabuf; -+static dma_addr_t ep1_curdmapos; -+static int ep1_curdmalen; -+static int ep1_remain; -+static int dmachn_rx; -+static int rx_pktsize; -+ -+static int naking; -+ -+static void -+ep1_start(void) -+{ -+ sa1100_dma_flush_all(dmachn_rx); -+ if (!ep1_curdmalen) { -+ ep1_curdmalen = rx_pktsize; -+ if (ep1_curdmalen > ep1_remain) -+ ep1_curdmalen = ep1_remain; -+ ep1_curdmapos = pci_map_single(NULL, ep1_curdmabuf, ep1_curdmalen, -+ PCI_DMA_FROMDEVICE); -+ } -+ sa1100_dma_queue_buffer(dmachn_rx, NULL, ep1_curdmapos, ep1_curdmalen); -+ if ( naking ) { -+ /* turn off NAK of OUT packets, if set */ -+ UDC_flip( Ser0UDCCS1, UDCCS1_RPC ); -+ naking = 0; -+ } -+} -+ -+static void -+ep1_done(int flag) -+{ -+ int size = ep1_len - ep1_remain; -+ -+ if (!ep1_len) -+ return; -+ if (ep1_curdmalen) -+ pci_unmap_single(NULL, ep1_curdmapos, ep1_curdmalen, -+ PCI_DMA_FROMDEVICE); -+ ep1_len = ep1_curdmalen = 0; -+ if (ep1_callback) { -+ ep1_callback(flag, size); -+ } -+} -+ -+void -+ep1_state_change_notify( int new_state ) -+{ -+ -+} -+ -+void -+ep1_stall( void ) -+{ -+ /* SET_FEATURE force stall at UDC */ -+ UDC_set( Ser0UDCCS1, UDCCS1_FST ); -+} -+ -+int -+ep1_init(int chn) -+{ -+ desc_t * pd = sa1100_usb_get_descriptor_ptr(); -+ rx_pktsize = __le16_to_cpu( pd->b.ep1.wMaxPacketSize ); -+ dmachn_rx = chn; -+ sa1100_dma_flush_all(dmachn_rx); -+ ep1_done(-EAGAIN); -+ return 0; -+} -+ -+void -+ep1_reset(void) -+{ -+ desc_t * pd = sa1100_usb_get_descriptor_ptr(); -+ rx_pktsize = __le16_to_cpu( pd->b.ep1.wMaxPacketSize ); -+ sa1100_dma_flush_all(dmachn_rx); -+ UDC_clear(Ser0UDCCS1, UDCCS1_FST); -+ ep1_done(-EINTR); -+} -+ -+void -+ep1_int_hndlr(int udcsr) -+{ -+ dma_addr_t dma_addr; -+ unsigned int len; -+ int status = Ser0UDCCS1; -+ -+ if ( naking ) printk( "%sEh? in ISR but naking = %d\n", "usbrx: ", naking ); -+ -+ if (status & UDCCS1_RPC) { -+ -+ if (!ep1_curdmalen) { -+ printk("usb_recv: RPC for non-existent buffer\n"); -+ naking=1; -+ return; -+ } -+ -+ sa1100_dma_stop(dmachn_rx); -+ -+ if (status & UDCCS1_SST) { -+ printk("usb_recv: stall sent OMP=%d\n",Ser0UDCOMP); -+ UDC_flip(Ser0UDCCS1, UDCCS1_SST); -+ ep1_done(-EIO); // UDC aborted current transfer, so we do -+ return; -+ } -+ -+ if (status & UDCCS1_RPE) { -+ printk("usb_recv: RPError %x\n", status); -+ UDC_flip(Ser0UDCCS1, UDCCS1_RPC); -+ ep1_done(-EIO); -+ return; -+ } -+ -+ sa1100_dma_get_current(dmachn_rx, NULL, &dma_addr); -+ pci_unmap_single(NULL, ep1_curdmapos, ep1_curdmalen, -+ PCI_DMA_FROMDEVICE); -+ len = dma_addr - ep1_curdmapos; -+ if (len < ep1_curdmalen) { -+ char *buf = ep1_curdmabuf + len; -+ while (Ser0UDCCS1 & UDCCS1_RNE) { -+ if (len >= ep1_curdmalen) { -+ printk("usb_recv: too much data in fifo\n"); -+ break; -+ } -+ *buf++ = Ser0UDCDR; -+ len++; -+ } -+ } else if (Ser0UDCCS1 & UDCCS1_RNE) { -+ printk("usb_recv: fifo screwed, shouldn't contain data\n"); -+ len = 0; -+ } -+ ep1_curdmalen = 0; /* dma unmap already done */ -+ ep1_remain -= len; -+ naking = 1; -+ ep1_done((len) ? 0 : -EPIPE); -+ } -+ /* else, you can get here if we are holding NAK */ -+} -+ -+int -+sa1100_usb_recv(char *buf, int len, usb_callback_t callback) -+{ -+ int flags; -+ -+ if (ep1_len) -+ return -EBUSY; -+ -+ local_irq_save(flags); -+ ep1_buf = buf; -+ ep1_len = len; -+ ep1_callback = callback; -+ ep1_remain = len; -+ ep1_curdmabuf = buf; -+ ep1_curdmalen = 0; -+ ep1_start(); -+ local_irq_restore(flags); -+ -+ return 0; -+} -+ -+EXPORT_SYMBOL(sa1100_usb_recv); -+ -+void -+sa1100_usb_recv_reset(void) -+{ -+ ep1_reset(); -+} -+ -+EXPORT_SYMBOL(sa1100_usb_recv_reset); -+ -+void -+sa1100_usb_recv_stall(void) -+{ -+ ep1_stall(); -+} -+ -+EXPORT_SYMBOL(sa1100_usb_recv_stall); -+ -diff -urN linux-2.4.26/arch/arm/mach-sa1100/usb_send.c linux-2.4.26-vrs1/arch/arm/mach-sa1100/usb_send.c ---- linux-2.4.26/arch/arm/mach-sa1100/usb_send.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mach-sa1100/usb_send.c 2004-01-14 21:32:24.000000000 +0000 -@@ -0,0 +1,205 @@ -+/* -+ * Generic xmit layer for the SA1100 USB client function -+ * Copyright (c) 2001 by Nicolas Pitre -+ * -+ * This code was loosely inspired by the original version which was -+ * Copyright (c) Compaq Computer Corporation, 1998-1999 -+ * -+ * 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 is still work in progress... -+ * -+ * Please see linux/Documentation/arm/SA1100/SA1100_USB for details. -+ * 15/03/2001 - ep2_start now sets UDCAR to overcome something that is hardware -+ * bug, I think. green@iXcelerator.com -+ */ -+ -+#include -+#include -+#include -+#include // for the massive_attack hack 28Feb01ww -+#include -+#include -+#include -+#include -+ -+#include "sa1100_usb.h" -+#include "usb_ctl.h" -+ -+ -+static char *ep2_buf; -+static int ep2_len; -+static usb_callback_t ep2_callback; -+static dma_addr_t ep2_dma; -+static dma_addr_t ep2_curdmapos; -+static int ep2_curdmalen; -+static int ep2_remain; -+static int dmachn_tx; -+static int tx_pktsize; -+ -+/* device state is changing, async */ -+void -+ep2_state_change_notify( int new_state ) -+{ -+} -+ -+/* set feature stall executing, async */ -+void -+ep2_stall( void ) -+{ -+ UDC_set( Ser0UDCCS2, UDCCS2_FST ); /* force stall at UDC */ -+} -+ -+static void -+ep2_start(void) -+{ -+ if (!ep2_len) -+ return; -+ -+ ep2_curdmalen = tx_pktsize; -+ if (ep2_curdmalen > ep2_remain) -+ ep2_curdmalen = ep2_remain; -+ -+ /* must do this _before_ queue buffer.. */ -+ UDC_flip( Ser0UDCCS2,UDCCS2_TPC ); /* stop NAKing IN tokens */ -+ UDC_write( Ser0UDCIMP, ep2_curdmalen-1 ); -+ -+ /* Remove if never seen...8Mar01ww */ -+ { -+ int massive_attack = 20; -+ while ( Ser0UDCIMP != ep2_curdmalen-1 && massive_attack-- ) { -+ printk( "usbsnd: Oh no you don't! Let me spin..." ); -+ udelay( 500 ); -+ printk( "and try again...\n" ); -+ UDC_write( Ser0UDCIMP, ep2_curdmalen-1 ); -+ } -+ if ( massive_attack != 20 ) { -+ if ( Ser0UDCIMP != ep2_curdmalen-1 ) -+ printk( "usbsnd: Massive attack FAILED :-( %d\n", -+ 20 - massive_attack ); -+ else -+ printk( "usbsnd: Massive attack WORKED :-) %d\n", -+ 20 - massive_attack ); -+ } -+ } -+ /* End remove if never seen... 8Mar01ww */ -+ -+ Ser0UDCAR = usbd_info.address; // fighting stupid silicon bug -+ sa1100_dma_queue_buffer(dmachn_tx, NULL, ep2_curdmapos, ep2_curdmalen); -+} -+ -+static void -+ep2_done(int flag) -+{ -+ int size = ep2_len - ep2_remain; -+ if (ep2_len) { -+ pci_unmap_single(NULL, ep2_dma, ep2_len, PCI_DMA_TODEVICE); -+ ep2_len = 0; -+ if (ep2_callback) -+ ep2_callback(flag, size); -+ } -+} -+ -+int -+ep2_init(int chn) -+{ -+ desc_t * pd = sa1100_usb_get_descriptor_ptr(); -+ tx_pktsize = __le16_to_cpu( pd->b.ep2.wMaxPacketSize ); -+ dmachn_tx = chn; -+ sa1100_dma_flush_all(dmachn_tx); -+ ep2_done(-EAGAIN); -+ return 0; -+} -+ -+void -+ep2_reset(void) -+{ -+ desc_t * pd = sa1100_usb_get_descriptor_ptr(); -+ tx_pktsize = __le16_to_cpu( pd->b.ep2.wMaxPacketSize ); -+ UDC_clear(Ser0UDCCS2, UDCCS2_FST); -+ sa1100_dma_flush_all(dmachn_tx); -+ ep2_done(-EINTR); -+} -+ -+void -+ep2_int_hndlr(int udcsr) -+{ -+ int status = Ser0UDCCS2; -+ -+ if (Ser0UDCAR != usbd_info.address) // check for stupid silicon bug. -+ Ser0UDCAR = usbd_info.address; -+ -+ UDC_flip(Ser0UDCCS2, UDCCS2_SST); -+ -+ if (status & UDCCS2_TPC) { -+ sa1100_dma_flush_all(dmachn_tx); -+ -+ if (status & (UDCCS2_TPE | UDCCS2_TUR)) { -+ printk("usb_send: transmit error %x\n", status); -+ ep2_done(-EIO); -+ } else { -+#if 1 // 22Feb01ww/Oleg -+ ep2_curdmapos += ep2_curdmalen; -+ ep2_remain -= ep2_curdmalen; -+#else -+ ep2_curdmapos += Ser0UDCIMP + 1; // this is workaround -+ ep2_remain -= Ser0UDCIMP + 1; // for case when setting of Ser0UDCIMP was failed -+#endif -+ -+ if (ep2_remain != 0) { -+ ep2_start(); -+ } else { -+ ep2_done(0); -+ } -+ } -+ } else { -+ printk("usb_send: Not TPC: UDCCS2 = %x\n", status); -+ } -+} -+ -+int -+sa1100_usb_send(char *buf, int len, usb_callback_t callback) -+{ -+ int flags; -+ -+ if (usbd_info.state != USB_STATE_CONFIGURED) -+ return -ENODEV; -+ -+ if (ep2_len) -+ return -EBUSY; -+ -+ local_irq_save(flags); -+ ep2_buf = buf; -+ ep2_len = len; -+ ep2_dma = pci_map_single(NULL, buf, len, PCI_DMA_TODEVICE); -+ ep2_callback = callback; -+ ep2_remain = len; -+ ep2_curdmapos = ep2_dma; -+ ep2_start(); -+ local_irq_restore(flags); -+ -+ return 0; -+} -+ -+ -+void -+sa1100_usb_send_reset(void) -+{ -+ ep2_reset(); -+} -+ -+int sa1100_usb_xmitter_avail( void ) -+{ -+ if (usbd_info.state != USB_STATE_CONFIGURED) -+ return -ENODEV; -+ if (ep2_len) -+ return -EBUSY; -+ return 0; -+} -+ -+ -+EXPORT_SYMBOL(sa1100_usb_xmitter_avail); -+EXPORT_SYMBOL(sa1100_usb_send); -+EXPORT_SYMBOL(sa1100_usb_send_reset); -diff -urN linux-2.4.26/arch/arm/mm/Makefile linux-2.4.26-vrs1/arch/arm/mm/Makefile ---- linux-2.4.26/arch/arm/mm/Makefile 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mm/Makefile 2004-01-14 21:38:43.000000000 +0000 -@@ -39,6 +39,8 @@ - p-$(CONFIG_CPU_ARM925T) += proc-arm925.o - p-$(CONFIG_CPU_ARM926T) += proc-arm926.o - p-$(CONFIG_CPU_ARM1020) += proc-arm1020.o -+p-$(CONFIG_CPU_ARM1020E) += proc-arm1020E.o -+p-$(CONFIG_CPU_ARM1022) += proc-arm1022.o - p-$(CONFIG_CPU_ARM1026) += proc-arm1026.o - p-$(CONFIG_CPU_SA110) += proc-sa110.o - p-$(CONFIG_CPU_SA1100) += proc-sa110.o -diff -urN linux-2.4.26/arch/arm/mm/alignment.c linux-2.4.26-vrs1/arch/arm/mm/alignment.c ---- linux-2.4.26/arch/arm/mm/alignment.c 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mm/alignment.c 2004-04-09 15:09:44.000000000 +0100 -@@ -11,7 +11,6 @@ - #include - #include - #include --#include - #include - #include - #include -@@ -19,7 +18,6 @@ - #include - #include - #include --#include - #include - #include - #include -@@ -30,13 +28,11 @@ - #include - #include - --extern void --do_bad_area(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr, -- int error_code, struct pt_regs *regs); -+#include "fault.h" - - /* - * 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998 -- * /proc/sys/debug/alignment, modified and integrated into -+ * /proc/cpu/alignment, modified and integrated into - * Linux 2.1 by Russell King - * - * Speed optimisations and better fault handling by Russell King. -@@ -130,31 +126,6 @@ - return count; - } - --/* -- * This needs to be done after sysctl_init, otherwise sys/ will be -- * overwritten. Actually, this shouldn't be in sys/ at all since -- * it isn't a sysctl, and it doesn't contain sysctl information. -- * We now locate it in /proc/cpu/alignment instead. -- */ --static int __init alignment_init(void) --{ -- struct proc_dir_entry *res; -- -- res = proc_mkdir("cpu", NULL); -- if (!res) -- return -ENOMEM; -- -- res = create_proc_entry("alignment", S_IWUSR | S_IRUGO, res); -- if (!res) -- return -ENOMEM; -- -- res->read_proc = proc_alignment_read; -- res->write_proc = proc_alignment_write; -- -- return 0; --} -- --__initcall(alignment_init); - #endif /* CONFIG_PROC_FS */ - - union offset_union { -@@ -429,7 +400,7 @@ - * For alignment faults on the ARM922T/ARM920T the MMU makes - * the FSR (and hence addr) equal to the updated base address - * of the multiple access rather than the restored value. -- * Switch this messsage off if we've got a ARM92[02], otherwise -+ * Switch this message off if we've got a ARM92[02], otherwise - * [ls]dm alignment faults are noisy! - */ - #if !(defined CONFIG_CPU_ARM922T) && !(defined CONFIG_CPU_ARM920T) -@@ -486,7 +457,8 @@ - return TYPE_ERROR; - } - --int do_alignment(unsigned long addr, int error_code, struct pt_regs *regs) -+static int -+do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) - { - union offset_union offset; - unsigned long instr, instrptr; -@@ -541,7 +513,7 @@ - case SHIFT_RORRRX: - if (shiftval == 0) { - offset.un >>= 1; -- if (regs->ARM_cpsr & CC_C_BIT) -+ if (regs->ARM_cpsr & PSR_C_BIT) - offset.un |= 1 << 31; - } else - offset.un = offset.un >> shiftval | -@@ -577,7 +549,7 @@ - /* - * We got a fault - fix it up, or die. - */ -- do_bad_area(current, current->mm, addr, error_code, regs); -+ do_bad_area(current, current->mm, addr, fsr, regs); - return 0; - - bad: -@@ -594,8 +566,8 @@ - - if (ai_usermode & 1) - printk("Alignment trap: %s (%d) PC=0x%08lx Instr=0x%08lx " -- "Address=0x%08lx Code 0x%02x\n", current->comm, -- current->pid, instrptr, instr, addr, error_code); -+ "Address=0x%08lx FSR 0x%03x\n", current->comm, -+ current->pid, instrptr, instr, addr, fsr); - - if (ai_usermode & 2) - goto fixup; -@@ -607,3 +579,34 @@ - - return 0; - } -+ -+/* -+ * This needs to be done after sysctl_init, otherwise sys/ will be -+ * overwritten. Actually, this shouldn't be in sys/ at all since -+ * it isn't a sysctl, and it doesn't contain sysctl information. -+ * We now locate it in /proc/cpu/alignment instead. -+ */ -+static int __init alignment_init(void) -+{ -+#ifdef CONFIG_PROC_FS -+ struct proc_dir_entry *res; -+ -+ res = proc_mkdir("cpu", NULL); -+ if (!res) -+ return -ENOMEM; -+ -+ res = create_proc_entry("alignment", S_IWUSR | S_IRUGO, res); -+ if (!res) -+ return -ENOMEM; -+ -+ res->read_proc = proc_alignment_read; -+ res->write_proc = proc_alignment_write; -+#endif -+ -+ hook_fault_code(1, do_alignment, SIGILL, "alignment exception"); -+ hook_fault_code(3, do_alignment, SIGILL, "alignment exception"); -+ -+ return 0; -+} -+ -+__initcall(alignment_init); -diff -urN linux-2.4.26/arch/arm/mm/fault-armv.c linux-2.4.26-vrs1/arch/arm/mm/fault-armv.c ---- linux-2.4.26/arch/arm/mm/fault-armv.c 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mm/fault-armv.c 2004-04-09 21:22:20.000000000 +0100 -@@ -2,116 +2,90 @@ - * linux/arch/arm/mm/fault-armv.c - * - * Copyright (C) 1995 Linus Torvalds -- * Modifications for ARM processor (c) 1995-2001 Russell King -+ * Modifications for ARM processor (c) 1995-2003 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 --#include - #include - #include --#include --#include - #include - #include --#include - #include --#include --#include - #include - #include - --#include --#include - #include - #include -+#include - --extern void show_pte(struct mm_struct *mm, unsigned long addr); --extern int do_page_fault(unsigned long addr, int error_code, -- struct pt_regs *regs); --extern int do_translation_fault(unsigned long addr, int error_code, -- struct pt_regs *regs); --extern void do_bad_area(struct task_struct *tsk, struct mm_struct *mm, -- unsigned long addr, int error_code, -- struct pt_regs *regs); -- --#ifdef CONFIG_ALIGNMENT_TRAP --extern int do_alignment(unsigned long addr, int error_code, struct pt_regs *regs); --#else --#define do_alignment do_bad --#endif -- -+#include "fault.h" - - /* - * Some section permission faults need to be handled gracefully. - * They can happen due to a __{get,put}_user during an oops. - */ - static int --do_sect_fault(unsigned long addr, int error_code, struct pt_regs *regs) -+do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) - { - struct task_struct *tsk = current; -- do_bad_area(tsk, tsk->active_mm, addr, error_code, regs); -+ do_bad_area(tsk, tsk->active_mm, addr, fsr, regs); - return 0; - } - - /* -- * Hook for things that need to trap external faults. Note that -- * we don't guarantee that this will be the final version of the -- * interface. -- */ --int (*external_fault)(unsigned long addr, struct pt_regs *regs); -- --static int --do_external_fault(unsigned long addr, int error_code, struct pt_regs *regs) --{ -- if (external_fault) -- return external_fault(addr, regs); -- return 1; --} -- --/* - * This abort handler always returns "fault". - */ - static int --do_bad(unsigned long addr, int error_code, struct pt_regs *regs) -+do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs) - { - return 1; - } - --static const struct fsr_info { -- int (*fn)(unsigned long addr, int error_code, struct pt_regs *regs); -+static struct fsr_info { -+ int (*fn)(unsigned long addr, unsigned int fsr, struct pt_regs *regs); - int sig; - const char *name; - } fsr_info[] = { - { do_bad, SIGSEGV, "vector exception" }, -- { do_alignment, SIGILL, "alignment exception" }, -+ { do_bad, SIGILL, "alignment exception" }, - { do_bad, SIGKILL, "terminal exception" }, -- { do_alignment, SIGILL, "alignment exception" }, -- { do_external_fault, SIGBUS, "external abort on linefetch" }, -+ { do_bad, SIGILL, "alignment exception" }, -+ { do_bad, SIGBUS, "external abort on linefetch" }, - { do_translation_fault, SIGSEGV, "section translation fault" }, -- { do_external_fault, SIGBUS, "external abort on linefetch" }, -+ { do_bad, SIGBUS, "external abort on linefetch" }, - { do_page_fault, SIGSEGV, "page translation fault" }, -- { do_external_fault, SIGBUS, "external abort on non-linefetch" }, -+ { do_bad, SIGBUS, "external abort on non-linefetch" }, - { do_bad, SIGSEGV, "section domain fault" }, -- { do_external_fault, SIGBUS, "external abort on non-linefetch" }, -+ { do_bad, SIGBUS, "external abort on non-linefetch" }, - { do_bad, SIGSEGV, "page domain fault" }, - { do_bad, SIGBUS, "external abort on translation" }, - { do_sect_fault, SIGSEGV, "section permission fault" }, - { do_bad, SIGBUS, "external abort on translation" }, -- { do_page_fault, SIGSEGV, "page permission fault" } -+ { do_page_fault, SIGSEGV, "page permission fault" }, - }; - -+void __init -+hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *), -+ int sig, const char *name) -+{ -+ if (nr >= 0 && nr < ARRAY_SIZE(fsr_info)) { -+ fsr_info[nr].fn = fn; -+ fsr_info[nr].sig = sig; -+ fsr_info[nr].name = name; -+ } -+} -+ - /* - * Dispatch a data abort to the relevant handler. - */ - asmlinkage void --do_DataAbort(unsigned long addr, int error_code, struct pt_regs *regs, int fsr) -+do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) - { - const struct fsr_info *inf = fsr_info + (fsr & 15); - -- if (!inf->fn(addr, error_code, regs)) -+ if (!inf->fn(addr, fsr, regs)) - return; - - printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n", -@@ -127,25 +101,28 @@ - do_translation_fault(addr, 0, regs); - } - -+static unsigned long shared_pte_mask = L_PTE_CACHEABLE; -+ - /* - * We take the easy way out of this problem - we make the - * PTE uncacheable. However, we leave the write buffer on. - */ --static void adjust_pte(struct vm_area_struct *vma, unsigned long address) -+static int adjust_pte(struct vm_area_struct *vma, unsigned long address) - { - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte, entry; -+ int ret = 0; - - pgd = pgd_offset(vma->vm_mm, address); - if (pgd_none(*pgd)) -- return; -+ goto no_pgd; - if (pgd_bad(*pgd)) - goto bad_pgd; - - pmd = pmd_offset(pgd, address); - if (pmd_none(*pmd)) -- return; -+ goto no_pmd; - if (pmd_bad(*pmd)) - goto bad_pmd; - -@@ -156,33 +133,38 @@ - * If this page isn't present, or is already setup to - * fault (ie, is old), we can safely ignore any issues. - */ -- if (pte_present(entry) && pte_val(entry) & L_PTE_CACHEABLE) { -+ if (pte_present(entry) && pte_val(entry) & shared_pte_mask) { - flush_cache_page(vma, address); -- pte_val(entry) &= ~L_PTE_CACHEABLE; -+ pte_val(entry) &= ~shared_pte_mask; - set_pte(pte, entry); - flush_tlb_page(vma, address); -+ ret = 1; - } -- return; -+ return ret; - - bad_pgd: - pgd_ERROR(*pgd); - pgd_clear(pgd); -- return; -+no_pgd: -+ return 0; - - bad_pmd: - pmd_ERROR(*pmd); - pmd_clear(pmd); -- return; -+no_pmd: -+ return 0; - } - - static void --make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page) -+make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, int dirty) - { - struct vm_area_struct *mpnt; - struct mm_struct *mm = vma->vm_mm; -- unsigned long pgoff = (addr - vma->vm_start) >> PAGE_SHIFT; -+ unsigned long pgoff; - int aliases = 0; - -+ pgoff = vma->vm_pgoff + ((addr - vma->vm_start) >> PAGE_SHIFT); -+ - /* - * If we have any shared mappings that are in the same mm - * space, then we need to handle them specially to maintain -@@ -194,7 +176,7 @@ - - /* - * If this VMA is not in our MM, we can ignore it. -- * Note that we intentionally don't mask out the VMA -+ * Note that we intentionally mask out the VMA - * that we are fixing up. - */ - if (mpnt->vm_mm != mm || mpnt == vma) -@@ -210,14 +192,17 @@ - if (off >= (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT) - continue; - -+ off = mpnt->vm_start + (off << PAGE_SHIFT); -+ - /* - * Ok, it is within mpnt. Fix it up. - */ -- adjust_pte(mpnt, mpnt->vm_start + (off << PAGE_SHIFT)); -- aliases ++; -+ aliases += adjust_pte(mpnt, off); - } - if (aliases) - adjust_pte(vma, addr); -+ else if (dirty) -+ flush_cache_page(vma, addr); - } - - /* -@@ -242,11 +227,85 @@ - return; - page = pfn_to_page(pfn); - if (page->mapping) { -- if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) { -+ int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags); -+ -+ if (dirty) { - unsigned long kvirt = (unsigned long)page_address(page); - cpu_cache_clean_invalidate_range(kvirt, kvirt + PAGE_SIZE, 0); - } - -- make_coherent(vma, addr, page); -+ make_coherent(vma, addr, page, dirty); -+ } -+} -+ -+/* -+ * Check whether the write buffer has physical address aliasing -+ * issues. If it has, we need to avoid them for the case where -+ * we have several shared mappings of the same object in user -+ * space. -+ */ -+static int __init check_writebuffer(unsigned long *p1, unsigned long *p2) -+{ -+ register unsigned long zero = 0, one = 1, val; -+ -+ mb(); -+ *p1 = one; -+ mb(); -+ *p2 = zero; -+ mb(); -+ val = *p1; -+ mb(); -+ return val != zero; -+} -+ -+static inline void *map_page(struct page *page) -+{ -+ void *map; -+ -+ map = __ioremap(page_to_phys(page), PAGE_SIZE, L_PTE_BUFFERABLE); -+ if (map) -+ get_page(page); -+ return map; -+} -+ -+static inline void unmap_page(void *map) -+{ -+ iounmap(map); -+} -+ -+void __init check_writebuffer_bugs(void) -+{ -+ struct page *page; -+ const char *reason; -+ unsigned long v = 1; -+ -+ printk(KERN_INFO "CPU: Testing write buffer: "); -+ -+ page = alloc_page(GFP_KERNEL); -+ if (page) { -+ unsigned long *p1, *p2; -+ -+ p1 = map_page(page); -+ p2 = map_page(page); -+ -+ if (p1 && p2) { -+ v = check_writebuffer(p1, p2); -+ reason = "enabling work-around"; -+ } else { -+ reason = "unable to map memory\n"; -+ } -+ -+ unmap_page(p1); -+ unmap_page(p2); -+ put_page(page); -+ } else { -+ reason = "unable to grab page\n"; -+ } -+ -+ if (v) { -+ printk("FAIL - %s\n", reason); -+ shared_pte_mask |= L_PTE_BUFFERABLE; -+ } else { -+ printk("pass\n"); - } - } -diff -urN linux-2.4.26/arch/arm/mm/fault-common.c linux-2.4.26-vrs1/arch/arm/mm/fault-common.c ---- linux-2.4.26/arch/arm/mm/fault-common.c 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mm/fault-common.c 2004-01-14 21:38:43.000000000 +0000 -@@ -11,21 +11,17 @@ - #include - #include - #include --#include --#include - #include --#include - #include --#include - #include - #include --#include - #include - - #include --#include - #include --#include -+#include -+ -+#include "fault.h" - - #ifdef CONFIG_CPU_26 - #define FAULT_CODE_WRITE 0x02 -@@ -34,13 +30,11 @@ - #define READ_FAULT(m) (!((m) & FAULT_CODE_WRITE)) - #else - /* -- * On 32-bit processors, we define "mode" to be zero when reading, -- * non-zero when writing. This now ties up nicely with the polarity -- * of the 26-bit machines, and also means that we avoid the horrible -- * gcc code for "int val = !other_val;". -+ * "code" is actually the FSR register. Bit 11 set means the -+ * instruction was performing a write. - */ --#define DO_COW(m) (m) --#define READ_FAULT(m) (!(m)) -+#define DO_COW(code) ((code) & (1 << 11)) -+#define READ_FAULT(code) (!DO_COW(code)) - #endif - - /* -@@ -54,16 +48,17 @@ - if (!mm) - mm = &init_mm; - -- printk(KERN_ALERT "mm = %p pgd = %p\n", mm, mm->pgd); -- - fs = get_fs(); - set_fs(get_ds()); -+ - do { -- pgd_t pg, *pgd = pgd_offset(mm, addr); -+ pgd_t pg, *pgd; - pmd_t pm, *pmd; - pte_t pt, *pte; - -- printk(KERN_ALERT "*pgd = "); -+ printk(KERN_ALERT "pgd = %p\n", mm->pgd); -+ pgd = pgd_offset(mm, addr); -+ printk(KERN_ALERT "[%08lx] *pgd=", addr); - - if (__get_user(pgd_val(pg), (unsigned long *)pgd)) { - printk("(faulted)"); -@@ -122,7 +117,7 @@ - * Oops. The kernel tried to access some page that wasn't present. - */ - static void --__do_kernel_fault(struct mm_struct *mm, unsigned long addr, int error_code, -+__do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, - struct pt_regs *regs) - { - unsigned long fixup; -@@ -148,7 +143,7 @@ - "paging request", addr); - - show_pte(mm, addr); -- die("Oops", regs, error_code); -+ die("Oops", regs, fsr); - do_exit(SIGKILL); - } - -@@ -157,20 +152,20 @@ - * User mode accesses just cause a SIGSEGV - */ - static void --__do_user_fault(struct task_struct *tsk, unsigned long addr, int error_code, -- int code, struct pt_regs *regs) -+__do_user_fault(struct task_struct *tsk, unsigned long addr, -+ unsigned int fsr, int code, struct pt_regs *regs) - { - struct siginfo si; - - #ifdef CONFIG_DEBUG_USER - printk(KERN_DEBUG "%s: unhandled page fault at pc=0x%08lx, " - "lr=0x%08lx (bad address=0x%08lx, code %d)\n", -- tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, error_code); -+ tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, fsr); - show_regs(regs); - #endif - - tsk->thread.address = addr; -- tsk->thread.error_code = error_code; -+ tsk->thread.error_code = fsr; - tsk->thread.trap_no = 14; - si.si_signo = SIGSEGV; - si.si_errno = 0; -@@ -181,20 +176,20 @@ - - void - do_bad_area(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr, -- int error_code, struct pt_regs *regs) -+ unsigned int fsr, struct pt_regs *regs) - { - /* - * If we are in kernel mode at this point, we - * have no context to handle this fault with. - */ - if (user_mode(regs)) -- __do_user_fault(tsk, addr, error_code, SEGV_MAPERR, regs); -+ __do_user_fault(tsk, addr, fsr, SEGV_MAPERR, regs); - else -- __do_kernel_fault(mm, addr, error_code, regs); -+ __do_kernel_fault(mm, addr, fsr, regs); - } - - static int --__do_page_fault(struct mm_struct *mm, unsigned long addr, int error_code, -+__do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, - struct task_struct *tsk) - { - struct vm_area_struct *vma; -@@ -212,7 +207,7 @@ - * memory access, so we can handle it. - */ - good_area: -- if (READ_FAULT(error_code)) /* read? */ -+ if (READ_FAULT(fsr)) /* read? */ - mask = VM_READ|VM_EXEC; - else - mask = VM_WRITE; -@@ -227,7 +222,7 @@ - * than endlessly redo the fault. - */ - survive: -- fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, DO_COW(error_code)); -+ fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, DO_COW(fsr)); - - /* - * Handle the "normal" cases first - successful and sigbus -@@ -260,7 +255,7 @@ - return fault; - } - --int do_page_fault(unsigned long addr, int error_code, struct pt_regs *regs) -+int do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) - { - struct task_struct *tsk; - struct mm_struct *mm; -@@ -277,7 +272,7 @@ - goto no_context; - - down_read(&mm->mmap_sem); -- fault = __do_page_fault(mm, addr, error_code, tsk); -+ fault = __do_page_fault(mm, addr, fsr, tsk); - up_read(&mm->mmap_sem); - - /* -@@ -308,7 +303,7 @@ - printk("VM: killing process %s\n", tsk->comm); - do_exit(SIGKILL); - } else -- __do_user_fault(tsk, addr, error_code, fault == -1 ? -+ __do_user_fault(tsk, addr, fsr, fault == -1 ? - SEGV_ACCERR : SEGV_MAPERR, regs); - return 0; - -@@ -323,7 +318,7 @@ - * or user mode. - */ - tsk->thread.address = addr; -- tsk->thread.error_code = error_code; -+ tsk->thread.error_code = fsr; - tsk->thread.trap_no = 14; - force_sig(SIGBUS, tsk); - #ifdef CONFIG_DEBUG_USER -@@ -336,7 +331,7 @@ - return 0; - - no_context: -- __do_kernel_fault(mm, addr, error_code, regs); -+ __do_kernel_fault(mm, addr, fsr, regs); - return 0; - } - -@@ -357,21 +352,23 @@ - * interrupt or a critical region, and should only copy the information - * from the master page table, nothing more. - */ --int do_translation_fault(unsigned long addr, int error_code, struct pt_regs *regs) -+int do_translation_fault(unsigned long addr, unsigned int fsr, -+ struct pt_regs *regs) - { - struct task_struct *tsk; -- struct mm_struct *mm; - int offset; - pgd_t *pgd, *pgd_k; - pmd_t *pmd, *pmd_k; - - if (addr < TASK_SIZE) -- return do_page_fault(addr, error_code, regs); -+ return do_page_fault(addr, fsr, regs); - - offset = __pgd_offset(addr); - - /* - * FIXME: CP15 C1 is write only on ARMv3 architectures. -+ * You really need to read the value in the page table -+ * register, not a copy. - */ - pgd = cpu_get_pgd() + offset; - pgd_k = init_mm.pgd + offset; -@@ -395,8 +392,7 @@ - - bad_area: - tsk = current; -- mm = tsk->active_mm; - -- do_bad_area(tsk, mm, addr, error_code, regs); -+ do_bad_area(tsk, tsk->active_mm, addr, fsr, regs); - return 0; - } -diff -urN linux-2.4.26/arch/arm/mm/fault.h linux-2.4.26-vrs1/arch/arm/mm/fault.h ---- linux-2.4.26/arch/arm/mm/fault.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mm/fault.h 2004-01-14 21:32:24.000000000 +0000 -@@ -0,0 +1,9 @@ -+void do_bad_area(struct task_struct *tsk, struct mm_struct *mm, -+ unsigned long addr, unsigned int fsr, struct pt_regs *regs); -+ -+void show_pte(struct mm_struct *mm, unsigned long addr); -+ -+int do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs); -+ -+int do_translation_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs); -+ -diff -urN linux-2.4.26/arch/arm/mm/init.c linux-2.4.26-vrs1/arch/arm/mm/init.c ---- linux-2.4.26/arch/arm/mm/init.c 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mm/init.c 2004-01-14 21:32:24.000000000 +0000 -@@ -9,7 +9,6 @@ - */ - #include - #include --#include - #include - #include - #include -@@ -18,7 +17,6 @@ - #include - #include - #include --#include - #include - #include - #include -diff -urN linux-2.4.26/arch/arm/mm/ioremap.c linux-2.4.26-vrs1/arch/arm/mm/ioremap.c ---- linux-2.4.26/arch/arm/mm/ioremap.c 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mm/ioremap.c 2004-02-25 22:03:38.000000000 +0000 -@@ -144,7 +144,7 @@ - */ - offset = phys_addr & ~PAGE_MASK; - phys_addr &= PAGE_MASK; -- size = PAGE_ALIGN(last_addr) - phys_addr; -+ size = PAGE_ALIGN(last_addr + 1) - phys_addr; - - /* - * Ok, go for it.. -diff -urN linux-2.4.26/arch/arm/mm/mm-armv.c linux-2.4.26-vrs1/arch/arm/mm/mm-armv.c ---- linux-2.4.26/arch/arm/mm/mm-armv.c 2003-11-28 18:26:19.000000000 +0000 -+++ linux-2.4.26-vrs1/arch/arm/mm/mm-armv.c 2004-01-14 21:38:43.000000000 +0000 -@@ -9,7 +9,6 @@ - * - * Page table sludge for ARM v3 and v4 processor architectures. - */ --#include - #include - #include - #include -@@ -390,6 +389,9 @@ - init_maps->bufferable = 0; - - create_mapping(init_maps); -+ -+ flush_cache_all(); -+ flush_tlb_all(); - } - - /* -diff -urN linux-2.4.26/arch/arm/mm/proc-arm1020.S linux-2.4.26-vrs1/arch/arm/mm/proc-arm1020.S ---- linux-2.4.26/arch/arm/mm/proc-arm1020.S 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mm/proc-arm1020.S 2004-01-14 21:32:24.000000000 +0000 -@@ -65,18 +65,21 @@ - * - * Returns: - * r0 = address of abort -- * r1 != 0 if writing -- * r3 = FSR -+ * r1 = FSR -+ * r3 = corrupted - * r4 = corrupted - */ - .align 5 - ENTRY(cpu_arm1020_data_abort) -- mrc p15, 0, r3, c5, c0, 0 @ get FSR -+ mrc p15, 0, r1, c5, c0, 0 @ get FSR - mrc p15, 0, r0, c6, c0, 0 @ get FAR -- ldr r1, [r2] @ read aborted instruction -- and r3, r3, #255 -- tst r1, r1, lsr #21 @ C = bit 20 -- sbc r1, r1, r1 @ r1 = C - 1 -+ tst r3, #PSR_T_BIT -+ ldrneh r3, [r2] @ read aborted thumb instruction -+ ldreq r3, [r2] @ read aborted ARM instruction -+ bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR -+ movne r3, r3, lsl #(21 - 12) @ move thumb bit 11 to ARM bit 20 -+ tst r3, #1 << 20 @ check write -+ orreq r1, r1, #1 << 11 - mov pc, lr - - /* -@@ -170,10 +173,10 @@ - #endif - subs r3, r3, #1 - cmp r3, #0 -- bge 2b @ entries 3F to 0 -+ bhs 2b @ entries 3F to 0 - subs r1, r1, #1 - cmp r1, #0 -- bge 1b @ segments 7 to 0 -+ bhs 1b @ segments 7 to 0 - #endif - - #ifndef CONFIG_CPU_ICACHE_DISABLE -@@ -201,7 +204,7 @@ - bic r0, r0, #DCACHELINESIZE - 1 - sub r3, r1, r0 - cmp r3, #MAX_AREA_SIZE -- bgt cpu_arm1020_cache_clean_invalidate_all_r2 -+ bhi cpu_arm1020_cache_clean_invalidate_all_r2 - mcr p15, 0, r3, c7, c10, 4 - #ifndef CONFIG_CPU_DCACHE_DISABLE - 1: mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry -@@ -214,7 +217,7 @@ - #endif - add r0, r0, #DCACHELINESIZE - cmp r0, r1 -- blt 1b -+ blo 1b - #endif - - #ifndef CONFIG_CPU_ICACHE_DISABLE -@@ -302,7 +305,7 @@ - #endif - add r0, r0, #DCACHELINESIZE - cmp r0, r1 -- blt 1b -+ blo 1b - #else - /* D cache off, but still drain the write buffer */ - mcr p15, 0, r0, c7, c10, 4 @ Drain write buffer -@@ -328,7 +331,7 @@ - bic r0, r0, #DCACHELINESIZE - 1 - sub r3, r1, r0 - cmp r3, #MAX_AREA_SIZE -- bgt cpu_arm1020_cache_clean_invalidate_all_r2 -+ bhi cpu_arm1020_cache_clean_invalidate_all_r2 - mcr p15, 0, r3, c7, c10, 4 - #ifndef CONFIG_CPU_DCACHE_DISABLE - 1: mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry -@@ -341,7 +344,7 @@ - #endif - add r0, r0, #DCACHELINESIZE - cmp r0, r1 -- blt 1b -+ blo 1b - #endif - - #ifndef CONFIG_CPU_BPREDICT_DISABLE -@@ -488,7 +491,7 @@ - mov r0, r0 - #endif - cmp r0, r1 -- blt 1b -+ blo 1b - mov pc, lr - - /* -@@ -541,10 +544,10 @@ - #endif - subs r3, r3, #1 - cmp r3, #0 -- bge 2b @ entries 3F to 0 -+ bhs 2b @ entries 3F to 0 - subs r1, r1, #1 - cmp r1, #0 -- bge 1b @ segments 15 to 0 -+ bhs 1b @ segments 15 to 0 - - #endif - mov r1, #0 -@@ -603,7 +606,7 @@ - bic r2, r2, #3 - orr r2, r2, #HPTE_TYPE_SMALL - -- tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? -+ tst r1, #LPTE_USER @ User? - orrne r2, r2, #HPTE_AP_READ - - tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? -@@ -740,12 +743,12 @@ - - .type cpu_arch_name, #object - cpu_arch_name: -- .asciz "armv4" -+ .asciz "armv5t" - .size cpu_arch_name, . - cpu_arch_name - - .type cpu_elf_name, #object - cpu_elf_name: -- .asciz "v4" -+ .asciz "v5" - .size cpu_elf_name, . - cpu_elf_name - .align - -@@ -753,9 +756,9 @@ - - .type __arm1020_proc_info,#object - __arm1020_proc_info: -- .long 0x4100a200 -- .long 0xff00fff0 -- .long 0x00000c02 @ mmuflags -+ .long 0x4104a200 @ ARM 1020T (Architecture v5T) -+ .long 0xff0ffff0 -+ .long 0x00000c0e @ mmuflags - b __arm1020_setup - .long cpu_arch_name - .long cpu_elf_name -diff -urN linux-2.4.26/arch/arm/mm/proc-arm1020E.S linux-2.4.26-vrs1/arch/arm/mm/proc-arm1020E.S ---- linux-2.4.26/arch/arm/mm/proc-arm1020E.S 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mm/proc-arm1020E.S 2004-01-14 21:32:24.000000000 +0000 -@@ -0,0 +1,718 @@ -+/* -+ * linux/arch/arm/mm/proc-arm1020E.S: MMU functions for ARM1020E -+ * -+ * Copyright (C) 2000 ARM Limited -+ * Copyright (C) 2000 Deep Blue Solutions Ltd. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * -+ * These are the low level assembler for performing cache and TLB -+ * functions on the arm1020E. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * This is the maximum size of an area which will be invalidated -+ * using the single invalidate entry instructions. Anything larger -+ * than this, and we go for the whole cache. -+ * -+ * This value should be chosen such that we choose the cheapest -+ * alternative. -+ */ -+#define MAX_AREA_SIZE 32768 -+ -+/* -+ * the cache line size of the I and D cache -+ */ -+#define DCACHELINESIZE 32 -+#define ICACHELINESIZE 32 -+ -+/* -+ * and the page size -+ */ -+#define LOG2PAGESIZE 12 /* == 4096 Bytes */ -+#define PAGESIZE (1 << LOG2PAGESIZE) -+ -+/* -+ * create some useful conditional macro definitions -+ * we often need to know if we are ((not dcache disable) and writethrough) or ((not dcache disable) and writeback) -+ */ -+#ifdef CONFIG_CPU_DCACHE_DISABLE -+ #undef CONFIG_CPU_DCACHE_WRITETHROUGH -+ #undef CONFIG_CPU_DCACHE_WRITEBACK -+ #undef CONFIG_CPU_DCACHE_ENABLE -+#else -+ #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -+ #undef CONFIG_CPU_DCACHE_WRITEBACK -+ #else -+ #define CONFIG_CPU_DCACHE_WRITEBACK -+ #endif -+ #define CONFIG_CPU_DCACHE_ENABLE -+#endif -+ -+#ifdef CONFIG_CPU_ICACHE_DISABLE -+ #undef CONFIG_CPU_ICACHE_ENABLE -+#else -+ #define CONFIG_CPU_ICACHE_ENABLE -+#endif -+ -+ .text -+ -+/* -+ * cpu_arm1020E_data_abort() -+ * -+ * obtain information about current aborted instruction -+ * Note: we read user space. This means we might cause a data -+ * abort here if the I-TLB and D-TLB aren't seeing the same -+ * picture. Unfortunately, this does happen. We live with it. -+ * -+ * r2 = address of aborted instruction -+ * r3 = cpsr -+ * -+ * Returns: -+ * r0 = address of abort -+ * r1 = FSR -+ * r3 = corrupted -+ * r4 = corrupted -+ */ -+ .align 5 -+ENTRY(cpu_arm1020E_data_abort) -+ mrc p15, 0, r1, c5, c0, 0 @ get FSR -+ mrc p15, 0, r0, c6, c0, 0 @ get FAR -+ tst r3, #PSR_T_BIT -+ ldrneh r3, [r2] @ read aborted thumb instruction -+ ldreq r3, [r2] @ read aborted ARM instruction -+ bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR -+ movne r3, r3, lsl #(21 - 12) @ move thumb bit 11 to ARM bit 20 -+ tst r3, #1 << 20 @ check write -+ orreq r1, r1, #1 << 11 -+ mov pc, lr -+ -+/* -+ * cpu_arm1020E_check_bugs() -+ */ -+ENTRY(cpu_arm1020E_check_bugs) -+ mrs ip, cpsr -+ bic ip, ip, #F_BIT -+ msr cpsr, ip -+ mov pc, lr -+ -+/* -+ * cpu_arm1020E_proc_init() -+ */ -+ENTRY(cpu_arm1020E_proc_init) -+ mov pc, lr -+ -+/* -+ * cpu_arm1020E_proc_fin() -+ */ -+ENTRY(cpu_arm1020E_proc_fin) -+ stmfd sp!, {lr} -+ mov ip, #F_BIT | I_BIT | SVC_MODE -+ msr cpsr_c, ip -+ bl cpu_arm1020E_cache_clean_invalidate_all -+ mrc p15, 0, r0, c1, c0, 0 @ ctrl register -+ bic r0, r0, #0x1000 @ ...i............ -+ bic r0, r0, #0x000e @ ............wca. -+ mcr p15, 0, r0, c1, c0, 0 @ disable caches -+ ldmfd sp!, {pc} -+ -+/* -+ * cpu_arm1020E_reset(loc) -+ * -+ * Perform a soft reset of the system. Put the CPU into the -+ * same state as it would be if it had been reset, and branch -+ * to what would be the reset vector. -+ * -+ * loc: location to jump to for soft reset -+ */ -+ .align 5 -+ENTRY(cpu_arm1020E_reset) -+ mov ip, #0 -+ mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches -+ mcr p15, 0, ip, c7, c10, 4 @ drain WB -+ mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs -+ mrc p15, 0, ip, c1, c0, 0 @ ctrl register -+ bic ip, ip, #0x000f @ ............wcam -+ bic ip, ip, #0x1100 @ ...i...s........ -+ mcr p15, 0, ip, c1, c0, 0 @ ctrl register -+ mov pc, r0 -+ -+/* -+ * cpu_arm1020E_do_idle() -+ */ -+ .align 5 -+ENTRY(cpu_arm1020E_do_idle) -+ mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt -+ mov pc, lr -+ -+/* ================================= CACHE ================================ */ -+ -+ -+/* -+ * cpu_arm1020E_cache_clean_invalidate_all() -+ * -+ * clean and invalidate all cache lines -+ * -+ * Note: -+ * 1. we should preserve r0 and ip at all times -+ */ -+ .align 5 -+ENTRY(cpu_arm1020E_cache_clean_invalidate_all) -+ mov r2, #1 -+cpu_arm1020E_cache_clean_invalidate_all_r2: -+ -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ mov r1, #0x0F << 5 @ 16 segments -+1: orr r3, r1, #63 << 26 @ 64 entries -+2: mcr p15, 0, r3, c7, c14, 2 @ clean and invalidate D index -+ subs r3, r3, #1 << 26 -+ bcs 2b -+ subs r1, r1, #1 << 5 -+ bcs 1b @ segments 15 to 0 -+#endif -+ -+ mov r1, #0 -+ -+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -+ mcr p15, 0, r1, c7, c6, 0 @ invalidate D cache -+#endif -+ -+#ifdef CONFIG_CPU_ICACHE_ENABLE -+ teq r2, #0 -+ mcrne p15, 0, r1, c7, c5, 0 @ invalidate I cache -+#endif -+ mcr p15, 0, r1, c7, c10, 4 @ drain WB -+ mov pc, lr -+ -+/* -+ * cpu_arm1020E_cache_clean_invalidate_range(start, end, flags) -+ * -+ * clean and invalidate all cache lines associated with this area of memory -+ * -+ * start: Area start address -+ * end: Area end address -+ * flags: nonzero for I cache as well -+ */ -+ .align 5 -+ENTRY(cpu_arm1020E_cache_clean_invalidate_range) -+ bic r0, r0, #DCACHELINESIZE - 1 -+ sub r3, r1, r0 -+ cmp r3, #MAX_AREA_SIZE -+ bhs cpu_arm1020E_cache_clean_invalidate_all_r2 -+1: -+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -+ mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry -+#endif -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry -+#endif -+#ifdef CONFIG_CPU_ICACHE_ENABLE -+ teq r2, #0 -+ mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry -+#endif -+ add r0, r0, #DCACHELINESIZE -+ cmp r0, r1 -+ bls 1b @ unsigned lower or same - must include end point (r1)! -+ -+ mov r1, #0 -+ mcr p15, 0, r1, c7, c10, 4 @ drain WB -+ mov pc, lr -+ -+/* -+ * cpu_arm1020E_flush_ram_page(page) -+ * -+ * clean and invalidate all cache lines associated with this area of memory -+ * -+ * page: page to clean and invalidate -+ */ -+ .align 5 -+ENTRY(cpu_arm1020E_flush_ram_page) -+ mov r1, #PAGESIZE -+ mov r0, r0, LSR #LOG2PAGESIZE @ round down to nearest page -+ mov r0, r0, LSL #LOG2PAGESIZE -+1: -+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -+ mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry -+#endif -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry -+#endif -+#ifdef CONFIG_CPU_ICACHE_ENABLE -+ mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry -+#endif -+ add r0, r0, #DCACHELINESIZE -+ subs r1, r1, #DCACHELINESIZE -+ bne 1b -+ -+ mcr p15, 0, r1, c7, c10, 4 @ drain WB -+ mov pc, lr -+ -+/* ================================ D-CACHE =============================== */ -+ -+/* -+ * cpu_arm1020E_dcache_invalidate_range(start, end) -+ * -+ * throw away all D-cached data in specified region without an obligation -+ * to write them back. Note however that we must clean the D-cached entries -+ * around the boundaries if the start and/or end address are not cache -+ * aligned. -+ * -+ * start: virtual start address -+ * end: virtual end address -+ */ -+ .align 5 -+ENTRY(cpu_arm1020E_dcache_invalidate_range) -+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -+ bic r0, r0, #DCACHELINESIZE - 1 -+#endif -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ tst r0, #DCACHELINESIZE - 1 -+ bic r0, r0, #DCACHELINESIZE - 1 -+ mcrne p15, 0, r0, c7, c10, 1 @ clean D entry at start -+ tst r1, #DCACHELINESIZE - 1 -+ mcrne p15, 0, r1, c7, c10, 1 @ clean D entry at end -+#endif -+ -+1: -+#ifdef CONFIG_CPU_DCACHE_ENABLE -+ mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry -+#endif -+#ifdef CONFIG_CPU_ICACHE_ENABLE -+ mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry -+#endif -+ add r0, r0, #DCACHELINESIZE -+ cmp r0, r1 -+ bls 1b -+ -+ /* Even if the D cache is off still drain the write buffer */ -+ mov r0, #0 -+ mcr p15, 0, r0, c7, c10, 4 @ Drain write buffer -+ mov pc, lr -+ -+/* -+ * cpu_arm1020E_dcache_clean_range(start, end) -+ * -+ * For the specified virtual address range, ensure that all caches contain -+ * clean data, such that peripheral accesses to the physical RAM fetch -+ * correct data. -+ * -+ * start: virtual start address -+ * end: virtual end address -+ */ -+ .align 5 -+ENTRY(cpu_arm1020E_dcache_clean_range) -+ -+ mov r2, #0 -+ -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ bic r0, r0, #DCACHELINESIZE - 1 -+ sub r3, r1, r0 -+ cmp r3, #MAX_AREA_SIZE -+ bhs cpu_arm1020E_cache_clean_invalidate_all_r2 -+ -+1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry -+ add r0, r0, #DCACHELINESIZE -+ cmp r0, r1 -+ bls 1b -+#endif -+ -+ mcr p15, 0, r2, c7, c10, 4 @ drain WB -+ mov pc, lr -+ -+/* -+ * cpu_arm1020E_dcache_clean_page(page) -+ * -+ * Cleans a single page of dcache so that if we have any future aliased -+ * mappings, they will be consistent at the time that they are created. -+ * -+ * page: virtual address of page to clean from dcache -+ * -+ * Note: -+ * we don't invalidate the entries since when we write the page -+ * out to disk, the entries may get reloaded into the cache. -+ */ -+ .align 5 -+ENTRY(cpu_arm1020E_dcache_clean_page) -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ mov r0, r0, LSR #LOG2PAGESIZE @ round down to nearest page -+ mov r0, r0, LSL #LOG2PAGESIZE -+ mov r1, #PAGESIZE -+1: -+ mcr p15, 0, r0, c7, c10, 1 @ clean D entry -+ add r0, r0, #DCACHELINESIZE -+ subs r1, r1, #DCACHELINESIZE -+ bne 1b -+#endif -+ mov r1, #0 -+ mcr p15, 0, r1, c7, c10, 4 @ drain WB -+ mov pc, lr -+ -+/* -+ * cpu_arm1020E_dcache_clean_entry(addr) -+ * -+ * Clean the specified entry of any caches such that the MMU -+ * translation fetches will obtain correct data. -+ * -+ * addr: cache-unaligned virtual address -+ */ -+ .align 5 -+ENTRY(cpu_arm1020E_dcache_clean_entry) -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ bic r0, r0, #DCACHELINESIZE - 1 -+ mcr p15, 0, r0, c7, c10, 1 @ clean single D entry -+#endif -+ mov r1, #0 -+ mcr p15, 0, r1, c7, c10, 4 @ drain WB -+ mov pc, lr -+ -+/* ================================ I-CACHE =============================== */ -+ -+/* -+ * cpu_arm1020E_icache_invalidate_range(start, end) -+ * -+ * invalidate a range of virtual addresses from the Icache -+ * -+ * This is a little misleading, it is not intended to clean out -+ * the i-cache but to make sure that any data written to the -+ * range is made consistent. This means that when we execute code -+ * in that region, everything works as we expect. -+ * -+ * This generally means writing back data in the Dcache and -+ * write buffer and invalidating the Icache over that region -+ * -+ * start: virtual start address -+ * end: virtual end address -+ * -+ * NOTE: ICACHELINESIZE == DCACHELINESIZE (so we don't need to -+ * loop twice, once for i-cache, once for d-cache) -+ */ -+ .align 5 -+ENTRY(cpu_arm1020E_icache_invalidate_range) -+ bic r0, r0, #ICACHELINESIZE - 1 -+ sub r3, r1, r0 -+ cmp r3, #MAX_AREA_SIZE -+ movhs r2, #1 -+ bhs cpu_arm1020E_cache_clean_invalidate_all_r2 -+ -+1: -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ mcr p15, 0, r0, c7, c10, 1 @ Clean D entry -+#endif -+#ifdef CONFIG_CPU_ICACHE_ENABLE -+ mcr p15, 0, r0, c7, c5, 1 @ Invalidate I entry -+#endif -+ add r0, r0, #DCACHELINESIZE -+ cmp r0, r1 -+ bls 1b @ unsigned lower or same - includes r1 entry -+ -+ mov r0, #0 -+ mcr p15, 0, r0, c7, c10, 4 @ drain WB -+ mov pc, lr -+ -+ENTRY(cpu_arm1020E_icache_invalidate_page) -+ mov r0, r0, LSR #LOG2PAGESIZE @ round down to nearest page -+ mov r0, r0, LSL #LOG2PAGESIZE -+ add r1, r0, #PAGESIZE -+ b cpu_arm1020E_icache_invalidate_range -+ -+/* ================================== TLB ================================= */ -+ -+/* -+ * cpu_arm1020E_tlb_invalidate_all() -+ * -+ * Invalidate all TLB entries -+ */ -+ .align 5 -+ENTRY(cpu_arm1020E_tlb_invalidate_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 -+ -+/* -+ * cpu_arm1020E_tlb_invalidate_range(start, end) -+ * -+ * invalidate TLB entries covering the specified range -+ * -+ * start: range start address -+ * end: range end address -+ */ -+ .align 5 -+ENTRY(cpu_arm1020E_tlb_invalidate_range) -+ sub r3, r1, r0 -+ cmp r3, #256 * PAGESIZE -+ bhs cpu_arm1020E_tlb_invalidate_all -+ mov r3, #0 -+ mcr p15, 0, r3, c7, c10, 4 @ drain WB -+ mov r3, #PAGESIZE -+ sub r3, r3, #1 -+ bic r0, r0, r3 -+1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry -+ mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry -+ add r0, r0, #PAGESIZE -+ cmp r0, r1 -+ bls 1b -+ mov pc, lr -+ -+/* -+ * cpu_arm1020E_tlb_invalidate_page(page, flags) -+ * -+ * invalidate the TLB entries for the specified page. -+ * -+ * page: page to invalidate -+ * flags: non-zero if we include the I TLB -+ */ -+ .align 5 -+ENTRY(cpu_arm1020E_tlb_invalidate_page) -+ mov r3, #0 -+ mcr p15, 0, r3, c7, c10, 4 @ drain WB -+ mov r0, r0, LSR #LOG2PAGESIZE @ round down to nearest page -+ mov r0, r0, LSL #LOG2PAGESIZE -+ teq r1, #0 -+ mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry -+ mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry -+ mov pc, lr -+ -+/* =============================== PageTable ============================== */ -+ -+/* -+ * cpu_arm1020E_set_pgd(pgd) -+ * -+ * Set the translation base pointer to be as described by pgd. -+ * -+ * pgd: new page tables -+ */ -+ .align 5 -+ENTRY(cpu_arm1020E_set_pgd) -+ stmfd sp!, {lr} -+ bl cpu_arm1020E_cache_clean_invalidate_all @ preserves r0 -+ mov r1, #0 -+ mcr p15, 0, r0, c2, c0, 0 @ load page table pointer -+ mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs -+ ldmfd sp!, {pc} -+ -+/* -+ * cpu_arm1020E_set_pmd(pmdp, pmd) -+ * -+ * Set a level 1 translation table entry, and clean it out of -+ * any caches such that the MMUs can load it correctly. -+ * -+ * pmdp: pointer to PMD entry -+ * pmd: PMD value to store -+ */ -+ .align 5 -+ENTRY(cpu_arm1020E_set_pmd) -+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -+ eor r2, r1, #0x0a @ C & Section -+ tst r2, #0x0b -+ biceq r1, r1, #4 @ clear bufferable bit -+#endif -+ str r1, [r0] -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ mcr p15, 0, r0, c7, c10, 1 @ clean D entry -+#endif -+ mov r0, #0 -+ mcr p15, 0, r0, c7, c10, 4 @ drain WB -+ mov pc, lr -+ -+/* -+ * cpu_arm1020E_set_pte(ptep, pte) -+ * -+ * Set a PTE and flush it out -+ */ -+ .align 5 -+ENTRY(cpu_arm1020E_set_pte) -+ str r1, [r0], #-1024 @ linux version -+ -+ eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY -+ -+ bic r2, r1, #0xff0 -+ bic r2, r2, #3 -+ orr r2, r2, #HPTE_TYPE_SMALL -+ -+ tst r1, #LPTE_USER @ User? -+ orrne r2, r2, #HPTE_AP_READ -+ -+ tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? -+ orreq r2, r2, #HPTE_AP_WRITE -+ -+ tst r1, #LPTE_PRESENT | LPTE_YOUNG @ Present and Young? -+ movne r2, #0 -+ -+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -+ eor r3, r2, #0x0a @ C and Small Page? -+ tst r3, #0x0b @ if so.. -+ biceq r2, r2, #0x04 @ clear the bufferable bit -+#endif -+ str r2, [r0] @ hardware version -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ mcr p15, 0, r0, c7, c10, 1 @ clean D entry -+#endif -+ mov r1, #0 -+ mcr p15, 0, r1, c7, c10, 4 @ drain WB -+ mov pc, lr -+ -+ -+cpu_manu_name: -+ .asciz "ARM" -+ENTRY(cpu_arm1020E_name) -+ .ascii "Arm1020E" -+#ifdef CONFIG_CPU_ICACHE_ENABLE -+ .ascii "i" -+#endif -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ .ascii "d" -+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -+ .ascii "(wt)" -+#endif -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ .ascii "(wb)" -+#endif -+#endif -+#ifndef CONFIG_CPU_BPREDICT_DISABLE -+ .ascii "B" -+#endif -+#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN -+ .ascii "RR" -+#endif -+ .ascii "\0" -+ .align -+ -+ .section ".text.init", #alloc, #execinstr -+ -+__arm1020E_setup: -+ mov r0, #0 -+ mcr p15, 0, r0, c7, c7, 0 @ invalidate I,D caches on v4 -+ mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 -+ mcr p15, 0, r0, c8, c7, 0 @ invalidate I,D TLBs on v4 -+ mcr p15, 0, r4, c2, c0, 0 @ load page table pointer -+ mov r0, #0x1f @ Domains 0, 1 = client -+ mcr p15, 0, r0, c3, c0, 0 @ load domain access register -+ -+ mrc p15, 0, r0, c1, c0, 0 @ Read current control register -+/* -+ * The only thing worth keeping from the initial control register is the endian bit -+ */ -+ -+ and r0, r0, #0x0080 @ ........B....... Preserve endian bit, zero all others. -+ orr r0, r0, #0x0070 @ .........111.... Set the SBO (Should Be One) bits -+/* -+ * Turn on what we want. -+ */ -+ orr r0, r0, #0x0001 @ ...............M Enable MMU (Alignment is special cased elsewhere) -+ orr r0, r0, #0x0100 @ .......S........ Enable system MMU protection -+ orr r0, r0, #0x2000 @ ..V............. Enable high vectors -+ -+#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN -+ orr r0, r0, #0x4000 @ .R.............. Force round-robin replacement -+#endif -+ -+#ifndef CONFIG_CPU_BPREDICT_DISABLE -+ orr r0, r0, #0x0800 @ ....Z........... Enable branch prediction -+#endif -+ -+#ifdef CONFIG_CPU_DCACHE_ENABLE -+ orr r0, r0, #0x0004 @ .............C.. Enable D cache -+#endif -+#ifndef CONFIG_CPU_WB_DISABLE -+ orr r0, r0, #0x0008 @ ............W... Write Buffer enabled -+#endif -+ -+#ifdef CONFIG_CPU_ICACHE_ENABLE -+ orr r0, r0, #0x1000 @ ...I............ Enable I Cache -+#endif -+ -+ mov pc, lr -+ -+ .text -+ -+/* -+ * Purpose : Function pointers used to access above functions - all calls -+ * come through these -+ */ -+ .type arm1020E_processor_functions, #object -+arm1020E_processor_functions: -+ .word cpu_arm1020E_data_abort -+ .word cpu_arm1020E_check_bugs -+ .word cpu_arm1020E_proc_init -+ .word cpu_arm1020E_proc_fin -+ .word cpu_arm1020E_reset -+ .word cpu_arm1020E_do_idle -+ -+ /* cache */ -+ .word cpu_arm1020E_cache_clean_invalidate_all -+ .word cpu_arm1020E_cache_clean_invalidate_range -+ .word cpu_arm1020E_flush_ram_page -+ -+ /* dcache */ -+ .word cpu_arm1020E_dcache_invalidate_range -+ .word cpu_arm1020E_dcache_clean_range -+ .word cpu_arm1020E_dcache_clean_page -+ .word cpu_arm1020E_dcache_clean_entry -+ -+ /* icache */ -+ .word cpu_arm1020E_icache_invalidate_range -+ .word cpu_arm1020E_icache_invalidate_page -+ -+ /* tlb */ -+ .word cpu_arm1020E_tlb_invalidate_all -+ .word cpu_arm1020E_tlb_invalidate_range -+ .word cpu_arm1020E_tlb_invalidate_page -+ -+ /* pgtable */ -+ .word cpu_arm1020E_set_pgd -+ .word cpu_arm1020E_set_pmd -+ .word cpu_arm1020E_set_pte -+ .size arm1020E_processor_functions, . - arm1020E_processor_functions -+ -+ .type cpu_arm1020E_info, #object -+cpu_arm1020E_info: -+ .long cpu_manu_name -+ .long cpu_arm1020E_name -+ .size cpu_arm1020E_info, . - cpu_arm1020E_info -+ -+ .type cpu_arch_name, #object -+cpu_arch_name: -+ .asciz "armv5te" -+ .size cpu_arch_name, . - cpu_arch_name -+ -+ .type cpu_elf_name, #object -+cpu_elf_name: -+ .asciz "v5" -+ .size cpu_elf_name, . - cpu_elf_name -+ .align -+ -+ .section ".proc.info", #alloc, #execinstr -+ -+ .type __arm1020E_proc_info,#object -+__arm1020E_proc_info: -+ .long 0x4105a200 @ ARM 1020E (Architecture v5TE) -+ .long 0xff0ffff0 -+ .long 0x00000c1e @ mmuflags -+ b __arm1020E_setup -+ .long cpu_arch_name -+ .long cpu_elf_name -+ .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB -+ .long cpu_arm1020E_info -+ .long arm1020E_processor_functions -+ .size __arm1020E_proc_info, . - __arm1020E_proc_info -+ -diff -urN linux-2.4.26/arch/arm/mm/proc-arm1022.S linux-2.4.26-vrs1/arch/arm/mm/proc-arm1022.S ---- linux-2.4.26/arch/arm/mm/proc-arm1022.S 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mm/proc-arm1022.S 2004-01-14 21:32:24.000000000 +0000 -@@ -0,0 +1,716 @@ -+/* -+ * linux/arch/arm/mm/proc-arm1022.S: MMU functions for ARM1022E -+ * -+ * Copyright (C) 2000 ARM Limited -+ * Copyright (C) 2000 Deep Blue Solutions Ltd. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * -+ * These are the low level assembler for performing cache and TLB -+ * functions on the arm1022E. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * This is the maximum size of an area which will be invalidated -+ * using the single invalidate entry instructions. Anything larger -+ * than this, and we go for the whole cache. -+ * -+ * This value should be chosen such that we choose the cheapest -+ * alternative. -+ */ -+#define MAX_AREA_SIZE 16384 -+ -+/* -+ * the cache line size of the I and D cache -+ */ -+#define DCACHELINESIZE 32 -+#define ICACHELINESIZE 32 -+ -+/* -+ * and the page size -+ */ -+#define LOG2PAGESIZE 12 /* == 4096 Bytes */ -+#define PAGESIZE (1 << LOG2PAGESIZE) -+ -+/* -+ * create some useful conditional macro definitions -+ * we often need to know if we are ((not dcache disable) and writethrough) or ((not dcache disable) and writeback) -+ */ -+#ifdef CONFIG_CPU_DCACHE_DISABLE -+ #undef CONFIG_CPU_DCACHE_WRITETHROUGH -+ #undef CONFIG_CPU_DCACHE_WRITEBACK -+ #undef CONFIG_CPU_DCACHE_ENABLE -+#else -+ #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -+ #undef CONFIG_CPU_DCACHE_WRITEBACK -+ #else -+ #define CONFIG_CPU_DCACHE_WRITEBACK -+ #endif -+ #define CONFIG_CPU_DCACHE_ENABLE -+#endif -+ -+#ifdef CONFIG_CPU_ICACHE_DISABLE -+ #undef CONFIG_CPU_ICACHE_ENABLE -+#else -+ #define CONFIG_CPU_ICACHE_ENABLE -+#endif -+ -+ .text -+ -+/* -+ * cpu_arm1022_data_abort() -+ * -+ * obtain information about current aborted instruction -+ * Note: we read user space. This means we might cause a data -+ * abort here if the I-TLB and D-TLB aren't seeing the same -+ * picture. Unfortunately, this does happen. We live with it. -+ * -+ * r2 = address of aborted instruction -+ * r3 = cpsr -+ * -+ * Returns: -+ * r0 = address of abort -+ * r1 = FSR -+ * r3 = corrupted -+ * r4 = corrupted -+ */ -+ .align 5 -+ENTRY(cpu_arm1022_data_abort) -+ mrc p15, 0, r1, c5, c0, 0 @ get FSR -+ mrc p15, 0, r0, c6, c0, 0 @ get FAR -+ tst r3, #PSR_T_BIT -+ ldrneh r3, [r2] @ read aborted thumb instruction -+ ldreq r3, [r2] @ read aborted ARM instruction -+ bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR -+ movne r3, r3, lsl #(21 - 12) @ move thumb bit 11 to ARM bit 20 -+ tst r3, #1 << 20 @ check write -+ orreq r1, r1, #1 << 11 -+ mov pc, lr -+ -+/* -+ * cpu_arm1022_check_bugs() -+ */ -+ENTRY(cpu_arm1022_check_bugs) -+ mrs ip, cpsr -+ bic ip, ip, #F_BIT -+ msr cpsr, ip -+ mov pc, lr -+ -+/* -+ * cpu_arm1022_proc_init() -+ */ -+ENTRY(cpu_arm1022_proc_init) -+ mov pc, lr -+ -+/* -+ * cpu_arm1022_proc_fin() -+ */ -+ENTRY(cpu_arm1022_proc_fin) -+ stmfd sp!, {lr} -+ mov ip, #F_BIT | I_BIT | SVC_MODE -+ msr cpsr_c, ip -+ bl cpu_arm1022_cache_clean_invalidate_all -+ mrc p15, 0, r0, c1, c0, 0 @ ctrl register -+ bic r0, r0, #0x1000 @ ...i............ -+ bic r0, r0, #0x000e @ ............wca. -+ mcr p15, 0, r0, c1, c0, 0 @ disable caches -+ ldmfd sp!, {pc} -+ -+/* -+ * cpu_arm1022_reset(loc) -+ * -+ * Perform a soft reset of the system. Put the CPU into the -+ * same state as it would be if it had been reset, and branch -+ * to what would be the reset vector. -+ * -+ * loc: location to jump to for soft reset -+ */ -+ .align 5 -+ENTRY(cpu_arm1022_reset) -+ mov ip, #0 -+ mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches -+ mcr p15, 0, ip, c7, c10, 4 @ drain WB -+ mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs -+ mrc p15, 0, ip, c1, c0, 0 @ ctrl register -+ bic ip, ip, #0x000f @ ............wcam -+ bic ip, ip, #0x1100 @ ...i...s........ -+ mcr p15, 0, ip, c1, c0, 0 @ ctrl register -+ mov pc, r0 -+ -+/* -+ * cpu_arm1022_do_idle() -+ */ -+ .align 5 -+ENTRY(cpu_arm1022_do_idle) -+ mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt -+ mov pc, lr -+ -+/* ================================= CACHE ================================ */ -+ -+ -+/* -+ * cpu_arm1022_cache_clean_invalidate_all() -+ * -+ * clean and invalidate all cache lines -+ * -+ * Note: -+ * 1. we should preserve r0 and ip at all times -+ */ -+ .align 5 -+ENTRY(cpu_arm1022_cache_clean_invalidate_all) -+ mov r2, #1 -+cpu_arm1022_cache_clean_invalidate_all_r2: -+ -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ mov r1, #7 << 5 @ 8 segments -+1: orr r3, r1, #63 << 26 @ 64 entries -+2: mcr p15, 0, r3, c7, c14, 2 @ clean and invalidate D index -+ subs r3, r3, #1 << 26 -+ bcs 2b -+ subs r1, r1, #1 << 5 -+ bcs 1b @ segments 7 to 0 -+#endif -+ -+ mov r1, #0 -+ -+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -+ mcr p15, 0, r1, c7, c6, 0 @ invalidate D cache -+#endif -+ -+#ifdef CONFIG_CPU_ICACHE_ENABLE -+ teq r2, #0 -+ mcrne p15, 0, r1, c7, c5, 0 @ invalidate I cache -+#endif -+ mcr p15, 0, r1, c7, c10, 4 @ drain WB -+ mov pc, lr -+ -+/* -+ * cpu_arm1022_cache_clean_invalidate_range(start, end, flags) -+ * -+ * clean and invalidate all cache lines associated with this area of memory -+ * -+ * start: Area start address -+ * end: Area end address -+ * flags: nonzero for I cache as well -+ */ -+ .align 5 -+ENTRY(cpu_arm1022_cache_clean_invalidate_range) -+ bic r0, r0, #DCACHELINESIZE - 1 -+ sub r3, r1, r0 -+ cmp r3, #MAX_AREA_SIZE -+ bhs cpu_arm1022_cache_clean_invalidate_all_r2 -+1: -+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -+ mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry -+#endif -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry -+#endif -+#ifdef CONFIG_CPU_ICACHE_ENABLE -+ teq r2, #0 -+ mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry -+#endif -+ add r0, r0, #DCACHELINESIZE -+ cmp r0, r1 -+ bls 1b @ unsigned lower or same - must include end point (r1)! -+ -+ mov r1, #0 -+ mcr p15, 0, r1, c7, c10, 4 @ drain WB -+ mov pc, lr -+ -+/* -+ * cpu_arm1022_flush_ram_page(page) -+ * -+ * clean and invalidate all cache lines associated with this area of memory -+ * -+ * page: page to clean and invalidate -+ */ -+ .align 5 -+ENTRY(cpu_arm1022_flush_ram_page) -+ mov r1, #PAGESIZE -+ mov r0, r0, LSR #LOG2PAGESIZE @ round down to nearest page -+ mov r0, r0, LSL #LOG2PAGESIZE -+1: -+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -+ mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry -+#endif -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry -+#endif -+#ifdef CONFIG_CPU_ICACHE_ENABLE -+ mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry -+#endif -+ add r0, r0, #DCACHELINESIZE -+ subs r1, r1, #DCACHELINESIZE -+ bne 1b -+ -+ mcr p15, 0, r1, c7, c10, 4 @ drain WB -+ mov pc, lr -+ -+/* ================================ D-CACHE =============================== */ -+ -+/* -+ * cpu_arm1022_dcache_invalidate_range(start, end) -+ * -+ * throw away all D-cached data in specified region without an obligation -+ * to write them back. Note however that we must clean the D-cached entries -+ * around the boundaries if the start and/or end address are not cache -+ * aligned. -+ * -+ * start: virtual start address -+ * end: virtual end address -+ */ -+ .align 5 -+ENTRY(cpu_arm1022_dcache_invalidate_range) -+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -+ bic r0, r0, #DCACHELINESIZE - 1 -+#endif -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ tst r0, #DCACHELINESIZE - 1 -+ bic r0, r0, #DCACHELINESIZE - 1 -+ mcrne p15, 0, r0, c7, c10, 1 @ clean D entry at start -+ tst r1, #DCACHELINESIZE - 1 -+ mcrne p15, 0, r1, c7, c10, 1 @ clean D entry at end -+#endif -+ -+1: -+#ifdef CONFIG_CPU_DCACHE_ENABLE -+ mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry -+#endif -+#ifdef CONFIG_CPU_ICACHE_ENABLE -+ mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry -+#endif -+ add r0, r0, #DCACHELINESIZE -+ cmp r0, r1 -+ bls 1b -+ -+ /* Even if the D cache is off still drain the write buffer */ -+ mov r0, #0 -+ mcr p15, 0, r0, c7, c10, 4 @ Drain write buffer -+ mov pc, lr -+ -+/* -+ * cpu_arm1022_dcache_clean_range(start, end) -+ * -+ * For the specified virtual address range, ensure that all caches contain -+ * clean data, such that peripheral accesses to the physical RAM fetch -+ * correct data. -+ * -+ * start: virtual start address -+ * end: virtual end address -+ */ -+ .align 5 -+ENTRY(cpu_arm1022_dcache_clean_range) -+ -+ mov r2, #0 -+ -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ bic r0, r0, #DCACHELINESIZE - 1 -+ sub r3, r1, r0 -+ cmp r3, #MAX_AREA_SIZE -+ bhs cpu_arm1022_cache_clean_invalidate_all_r2 -+ -+1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry -+ add r0, r0, #DCACHELINESIZE -+ cmp r0, r1 -+ bls 1b -+#endif -+ -+ mcr p15, 0, r2, c7, c10, 4 @ drain WB -+ mov pc, lr -+ -+/* -+ * cpu_arm1022_dcache_clean_page(page) -+ * -+ * Cleans a single page of dcache so that if we have any future aliased -+ * mappings, they will be consistent at the time that they are created. -+ * -+ * page: virtual address of page to clean from dcache -+ * -+ * Note: -+ * we don't invalidate the entries since when we write the page -+ * out to disk, the entries may get reloaded into the cache. -+ */ -+ .align 5 -+ENTRY(cpu_arm1022_dcache_clean_page) -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ mov r0, r0, LSR #LOG2PAGESIZE @ round down to nearest page -+ mov r0, r0, LSL #LOG2PAGESIZE -+ mov r1, #PAGESIZE -+1: -+ mcr p15, 0, r0, c7, c10, 1 @ clean D entry -+ add r0, r0, #DCACHELINESIZE -+ subs r1, r1, #DCACHELINESIZE -+ bne 1b -+#endif -+ mov r1, #0 -+ mcr p15, 0, r1, c7, c10, 4 @ drain WB -+ mov pc, lr -+ -+/* -+ * cpu_arm1022_dcache_clean_entry(addr) -+ * -+ * Clean the specified entry of any caches such that the MMU -+ * translation fetches will obtain correct data. -+ * -+ * addr: cache-unaligned virtual address -+ */ -+ .align 5 -+ENTRY(cpu_arm1022_dcache_clean_entry) -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ bic r0, r0, #DCACHELINESIZE - 1 -+ mcr p15, 0, r0, c7, c10, 1 @ clean single D entry -+#endif -+ mov r1, #0 -+ mcr p15, 0, r1, c7, c10, 4 @ drain WB -+ mov pc, lr -+ -+/* ================================ I-CACHE =============================== */ -+ -+/* -+ * cpu_arm1022_icache_invalidate_range(start, end) -+ * -+ * invalidate a range of virtual addresses from the Icache -+ * -+ * This is a little misleading, it is not intended to clean out -+ * the i-cache but to make sure that any data written to the -+ * range is made consistent. This means that when we execute code -+ * in that region, everything works as we expect. -+ * -+ * This generally means writing back data in the Dcache and -+ * write buffer and invalidating the Icache over that region -+ * -+ * start: virtual start address -+ * end: virtual end address -+ * -+ * NOTE: ICACHELINESIZE == DCACHELINESIZE (so we don't need to -+ * loop twice, once for i-cache, once for d-cache) -+ */ -+ .align 5 -+ENTRY(cpu_arm1022_icache_invalidate_range) -+ bic r0, r0, #ICACHELINESIZE - 1 -+ sub r3, r1, r0 -+ cmp r3, #MAX_AREA_SIZE -+ movhs r2, #1 -+ bhs cpu_arm1022_cache_clean_invalidate_all_r2 -+1: -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ mcr p15, 0, r0, c7, c10, 1 @ Clean D entry -+#endif -+#ifdef CONFIG_CPU_ICACHE_ENABLE -+ mcr p15, 0, r0, c7, c5, 1 @ Invalidate I entry -+#endif -+ add r0, r0, #DCACHELINESIZE -+ cmp r0, r1 -+ bls 1b @ unsigned lower or same - includes r1 entry -+ -+ mov r0, #0 -+ mcr p15, 0, r0, c7, c10, 4 @ drain WB -+ mov pc, lr -+ -+ENTRY(cpu_arm1022_icache_invalidate_page) -+ mov r0, r0, LSR #LOG2PAGESIZE @ round down to nearest page -+ mov r0, r0, LSL #LOG2PAGESIZE -+ add r1, r0, #PAGESIZE -+ b cpu_arm1022_icache_invalidate_range -+ -+/* ================================== TLB ================================= */ -+ -+/* -+ * cpu_arm1022_tlb_invalidate_all() -+ * -+ * Invalidate all TLB entries -+ */ -+ .align 5 -+ENTRY(cpu_arm1022_tlb_invalidate_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 -+ -+/* -+ * cpu_arm1022_tlb_invalidate_range(start, end) -+ * -+ * invalidate TLB entries covering the specified range -+ * -+ * start: range start address -+ * end: range end address -+ */ -+ .align 5 -+ENTRY(cpu_arm1022_tlb_invalidate_range) -+ sub r3, r1, r0 -+ cmp r3, #256 * PAGESIZE -+ bhs cpu_arm1022_tlb_invalidate_all -+ mov r3, #0 -+ mcr p15, 0, r3, c7, c10, 4 @ drain WB -+ mov r3, #PAGESIZE -+ sub r3, r3, #1 -+ bic r0, r0, r3 -+1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry -+ mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry -+ add r0, r0, #PAGESIZE -+ cmp r0, r1 -+ bls 1b -+ mov pc, lr -+ -+/* -+ * cpu_arm1022_tlb_invalidate_page(page, flags) -+ * -+ * invalidate the TLB entries for the specified page. -+ * -+ * page: page to invalidate -+ * flags: non-zero if we include the I TLB -+ */ -+ .align 5 -+ENTRY(cpu_arm1022_tlb_invalidate_page) -+ mov r3, #0 -+ mcr p15, 0, r3, c7, c10, 4 @ drain WB -+ mov r0, r0, LSR #LOG2PAGESIZE @ round down to nearest page -+ mov r0, r0, LSL #LOG2PAGESIZE -+ teq r1, #0 -+ mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry -+ mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry -+ mov pc, lr -+ -+/* =============================== PageTable ============================== */ -+ -+/* -+ * cpu_arm1022_set_pgd(pgd) -+ * -+ * Set the translation base pointer to be as described by pgd. -+ * -+ * pgd: new page tables -+ */ -+ .align 5 -+ENTRY(cpu_arm1022_set_pgd) -+ stmfd sp!, {lr} -+ bl cpu_arm1022_cache_clean_invalidate_all @ preserves r0 -+ mov r1, #0 -+ mcr p15, 0, r0, c2, c0, 0 @ load page table pointer -+ mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs -+ ldmfd sp!, {pc} -+ -+/* -+ * cpu_arm1022_set_pmd(pmdp, pmd) -+ * -+ * Set a level 1 translation table entry, and clean it out of -+ * any caches such that the MMUs can load it correctly. -+ * -+ * pmdp: pointer to PMD entry -+ * pmd: PMD value to store -+ */ -+ .align 5 -+ENTRY(cpu_arm1022_set_pmd) -+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -+ eor r2, r1, #0x0a @ C & Section -+ tst r2, #0x0b -+ biceq r1, r1, #4 @ clear bufferable bit -+#endif -+ str r1, [r0] -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ mcr p15, 0, r0, c7, c10, 1 @ clean D entry -+#endif -+ mov r0, #0 -+ mcr p15, 0, r0, c7, c10, 4 @ drain WB -+ mov pc, lr -+ -+/* -+ * cpu_arm1022_set_pte(ptep, pte) -+ * -+ * Set a PTE and flush it out -+ */ -+ .align 5 -+ENTRY(cpu_arm1022_set_pte) -+ str r1, [r0], #-1024 @ linux version -+ -+ eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY -+ -+ bic r2, r1, #0xff0 -+ bic r2, r2, #3 -+ orr r2, r2, #HPTE_TYPE_SMALL -+ -+ tst r1, #LPTE_USER @ User? -+ orrne r2, r2, #HPTE_AP_READ -+ -+ tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? -+ orreq r2, r2, #HPTE_AP_WRITE -+ -+ tst r1, #LPTE_PRESENT | LPTE_YOUNG @ Present and Young? -+ movne r2, #0 -+ -+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -+ eor r3, r2, #0x0a @ C and Small Page? -+ tst r3, #0x0b @ if so.. -+ biceq r2, r2, #0x04 @ clear the bufferable bit -+#endif -+ str r2, [r0] @ hardware version -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ mcr p15, 0, r0, c7, c10, 1 @ clean D entry -+#endif -+ mov r1, #0 -+ mcr p15, 0, r1, c7, c10, 4 @ drain WB -+ mov pc, lr -+ -+ -+cpu_manu_name: -+ .asciz "ARM" -+ENTRY(cpu_arm1022_name) -+ .ascii "Arm1022E" -+#ifdef CONFIG_CPU_ICACHE_ENABLE -+ .ascii "i" -+#endif -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ .ascii "d" -+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -+ .ascii "(wt)" -+#endif -+#ifdef CONFIG_CPU_DCACHE_WRITEBACK -+ .ascii "(wb)" -+#endif -+#endif -+#ifndef CONFIG_CPU_BPREDICT_DISABLE -+ .ascii "B" -+#endif -+#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN -+ .ascii "RR" -+#endif -+ .ascii "\0" -+ .align -+ -+ .section ".text.init", #alloc, #execinstr -+ -+__arm1022_setup: -+ mov r0, #0 -+ mcr p15, 0, r0, c7, c7, 0 @ invalidate I,D caches on v4 -+ mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 -+ mcr p15, 0, r0, c8, c7, 0 @ invalidate I,D TLBs on v4 -+ mcr p15, 0, r4, c2, c0, 0 @ load page table pointer -+ mov r0, #0x1f @ Domains 0, 1 = client -+ mcr p15, 0, r0, c3, c0, 0 @ load domain access register -+ -+ mrc p15, 0, r0, c1, c0, 0 @ Read current control register -+/* -+ * The only thing worth keeping from the initial control register is the endian bit -+ */ -+ -+ and r0, r0, #0x0080 @ ........B....... Preserve endian bit, zero all others. -+ orr r0, r0, #0x0070 @ .........111.... Set the SBO (Should Be One) bits -+/* -+ * Turn on what we want. -+ */ -+ orr r0, r0, #0x0001 @ ...............M Enable MMU (Alignment is special cased elsewhere) -+ orr r0, r0, #0x0100 @ .......S........ Enable system MMU protection -+ orr r0, r0, #0x2000 @ ..V............. Enable high vectors -+ -+#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN -+ orr r0, r0, #0x4000 @ .R.............. Force round-robin replacement -+#endif -+ -+#ifndef CONFIG_CPU_BPREDICT_DISABLE -+ orr r0, r0, #0x0800 @ ....Z........... Enable branch prediction -+#endif -+ -+#ifdef CONFIG_CPU_DCACHE_ENABLE -+ orr r0, r0, #0x0004 @ .............C.. Enable D cache -+#endif -+#ifndef CONFIG_CPU_WB_DISABLE -+ orr r0, r0, #0x0008 @ ............W... Write Buffer enabled -+#endif -+ -+#ifdef CONFIG_CPU_ICACHE_ENABLE -+ orr r0, r0, #0x1000 @ ...I............ Enable I Cache -+#endif -+ -+ mov pc, lr -+ -+ .text -+ -+/* -+ * Purpose : Function pointers used to access above functions - all calls -+ * come through these -+ */ -+ .type arm1022_processor_functions, #object -+arm1022_processor_functions: -+ .word cpu_arm1022_data_abort -+ .word cpu_arm1022_check_bugs -+ .word cpu_arm1022_proc_init -+ .word cpu_arm1022_proc_fin -+ .word cpu_arm1022_reset -+ .word cpu_arm1022_do_idle -+ -+ /* cache */ -+ .word cpu_arm1022_cache_clean_invalidate_all -+ .word cpu_arm1022_cache_clean_invalidate_range -+ .word cpu_arm1022_flush_ram_page -+ -+ /* dcache */ -+ .word cpu_arm1022_dcache_invalidate_range -+ .word cpu_arm1022_dcache_clean_range -+ .word cpu_arm1022_dcache_clean_page -+ .word cpu_arm1022_dcache_clean_entry -+ -+ /* icache */ -+ .word cpu_arm1022_icache_invalidate_range -+ .word cpu_arm1022_icache_invalidate_page -+ -+ /* tlb */ -+ .word cpu_arm1022_tlb_invalidate_all -+ .word cpu_arm1022_tlb_invalidate_range -+ .word cpu_arm1022_tlb_invalidate_page -+ -+ /* pgtable */ -+ .word cpu_arm1022_set_pgd -+ .word cpu_arm1022_set_pmd -+ .word cpu_arm1022_set_pte -+ .size arm1022_processor_functions, . - arm1022_processor_functions -+ -+ .type cpu_arm1022_info, #object -+cpu_arm1022_info: -+ .long cpu_manu_name -+ .long cpu_arm1022_name -+ .size cpu_arm1022_info, . - cpu_arm1022_info -+ -+ .type cpu_arch_name, #object -+cpu_arch_name: -+ .asciz "armv5t" -+ .size cpu_arch_name, . - cpu_arch_name -+ -+ .type cpu_elf_name, #object -+cpu_elf_name: -+ .asciz "v5" -+ .size cpu_elf_name, . - cpu_elf_name -+ .align -+ -+ .section ".proc.info", #alloc, #execinstr -+ -+ .type __arm1022_proc_info,#object -+__arm1022_proc_info: -+ .long 0x4100a220 @ ARM 1022 -+ .long 0xff00fff0 -+ .long 0x00000c1e @ mmuflags -+ b __arm1022_setup -+ .long cpu_arch_name -+ .long cpu_elf_name -+ .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB -+ .long cpu_arm1022_info -+ .long arm1022_processor_functions -+ .size __arm1022_proc_info, . - __arm1022_proc_info -diff -urN linux-2.4.26/arch/arm/mm/proc-arm1026.S linux-2.4.26-vrs1/arch/arm/mm/proc-arm1026.S ---- linux-2.4.26/arch/arm/mm/proc-arm1026.S 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mm/proc-arm1026.S 2004-02-10 23:03:10.000000000 +0000 -@@ -66,19 +66,24 @@ - * - * Returns: - * r0 = address of abort -- * r1 != 0 if writing -- * r3 = FSR -+ * r1 = FSR, bit 11 set if writing -+ * r3 = corrupted - * r4 = corrupted - */ - .align 5 - ENTRY(cpu_arm1026_data_abort) -- mrc p15, 0, r3, c5, c0, 0 @ get FSR -- and r2, r3, #0b1101 @ Check for translation error -- sub r1, r2, #0b0101 -- -- and r3, r3, #255 -+ mrc p15, 0, r1, c5, c0, 0 @ get FSR - mrc p15, 0, r0, c6, c0, 0 @ get FAR -- -+ bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR -+ tst r3, #PSR_J_BIT @ Java? -+ orrne r1, r1, #1 << 11 @ always assume write -+ movne pc, lr -+ tst r3, #PSR_T_BIT -+ ldrneh r3, [r2] @ read aborted thumb instruction -+ ldreq r3, [r2] @ read aborted ARM instruction -+ movne r3, r3, lsl #(21 - 12) @ move thumb bit 11 to ARM bit 20 -+ tst r3, #1 << 20 @ check write -+ orreq r1, r1, #1 << 11 - mov pc, lr - - /* -@@ -254,7 +259,7 @@ - */ - .align 5 - ENTRY(cpu_arm1026_dcache_invalidate_range) --#ifndef CONFIG_CPU_ARM1026_WRITETHROUGH -+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - tst r0, #DCACHELINESIZE - 1 - mcrne p15, 0, r0, c7, c10, 1 @ clean D entry - tst r1, #DCACHELINESIZE - 1 -@@ -279,7 +284,7 @@ - */ - .align 5 - ENTRY(cpu_arm1026_dcache_clean_range) --#ifndef CONFIG_CPU_ARM1026_WRITETHROUGH -+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - bic r0, r0, #DCACHELINESIZE - 1 - sub r3, r1, r0 - cmp r3, #MAX_AREA_SIZE -@@ -309,7 +314,7 @@ - */ - .align 5 - ENTRY(cpu_arm1026_dcache_clean_page) --#ifndef CONFIG_CPU_ARM1026_WRITETHROUGH -+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - mov r1, #PAGESIZE - 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry - add r0, r0, #DCACHELINESIZE -@@ -330,7 +335,7 @@ - */ - .align 5 - ENTRY(cpu_arm1026_dcache_clean_entry) --#ifndef CONFIG_CPU_ARM1026_WRITETHROUGH -+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - mcr p15, 0, r0, c7, c10, 1 @ clean D entry - #endif - mcr p15, 0, r0, c7, c10, 4 @ drain WB -@@ -473,7 +478,7 @@ - biceq r1, r1, #4 @ clear bufferable bit - #endif - str r1, [r0] --#ifndef CONFIG_CPU_ARM1026_WRITETHROUGH -+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - mcr p15, 0, r0, c7, c10, 1 @ clean D entry - #endif - mcr p15, 0, r0, c7, c10, 4 @ drain WB -@@ -494,7 +499,7 @@ - bic r2, r2, #3 - orr r2, r2, #HPTE_TYPE_SMALL - -- tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? -+ tst r1, #LPTE_USER @ User? - orrne r2, r2, #HPTE_AP_READ - - tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? -@@ -634,12 +639,12 @@ - - .type cpu_arch_name, #object - cpu_arch_name: -- .asciz "armv5EJ" -+ .asciz "armv5tej" - .size cpu_arch_name, . - cpu_arch_name - - .type cpu_elf_name, #object - cpu_elf_name: -- .asciz "v5EJ" -+ .asciz "v5" - .size cpu_elf_name, . - cpu_elf_name - .align - -diff -urN linux-2.4.26/arch/arm/mm/proc-arm6,7.S linux-2.4.26-vrs1/arch/arm/mm/proc-arm6,7.S ---- linux-2.4.26/arch/arm/mm/proc-arm6,7.S 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mm/proc-arm6,7.S 2004-01-14 21:38:43.000000000 +0000 -@@ -72,7 +72,7 @@ - 1: mcr p15, 0, r0, c6, c0, 0 @ purge TLB - add r0, r0, #4096 - cmp r0, r1 -- blt 1b -+ blo 1b - mov pc, lr - - ENTRY(cpu_arm7_tlb_invalidate_range) -@@ -85,7 +85,7 @@ - 1: mcr p15, 0, r0, c6, c0, 0 @ purge TLB - add r0, r0, #0x4000 - cmp r0, r1 -- blt 1b -+ blo 1b - mov pc, lr - #endif - -@@ -110,15 +110,13 @@ - * Purpose : obtain information about current aborted instruction - * - * Returns : r0 = address of abort -- * : r1 != 0 if writing -- * : r3 = FSR -+ * : r1 = FSR, bit 11 set if writing -+ * : r3 = corrupted - * : sp = pointer to registers - */ - - ENTRY(cpu_arm6_data_abort) - ldr r4, [r0] @ read instruction causing problem -- tst r4, r4, lsr #21 @ C = bit 20 -- sbc r1, r1, r1 @ r1 = C - 1 - and r2, r4, #14 << 24 - teq r2, #8 << 24 @ was it ldm/stm - bne Ldata_simple -@@ -144,14 +142,14 @@ - addeq r7, r0, r7, lsl #2 @ Do correction (signed) - Ldata_saver7: str r7, [sp, r5, lsr #14] @ Put register - Ldata_simple: mrc p15, 0, r0, c6, c0, 0 @ get FAR -- mrc p15, 0, r3, c5, c0, 0 @ get FSR -- and r3, r3, #255 -+ mrc p15, 0, r1, c5, c0, 0 @ get FSR -+ bic r1, r1, #1 << 11 | 1 << 10 -+ tst r4, #1 << 20 -+ orreq r1, r1, #1 << 11 - mov pc, lr - - ENTRY(cpu_arm7_data_abort) - ldr r4, [r0] @ read instruction causing problem -- tst r4, r4, lsr #21 @ C = bit 20 -- sbc r1, r1, r1 @ r1 = C - 1 - and r2, r4, #15 << 24 - add pc, pc, r2, lsr #22 @ Now branch to the relevent processing routine - movs pc, lr -@@ -336,7 +334,7 @@ - bic r2, r2, #3 - orr r2, r2, #HPTE_TYPE_SMALL - -- tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? -+ tst r1, #LPTE_USER @ User? - orrne r2, r2, #HPTE_AP_READ - - tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? -diff -urN linux-2.4.26/arch/arm/mm/proc-arm720.S linux-2.4.26-vrs1/arch/arm/mm/proc-arm720.S ---- linux-2.4.26/arch/arm/mm/proc-arm720.S 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mm/proc-arm720.S 2004-02-24 09:30:43.000000000 +0000 -@@ -97,7 +97,7 @@ - 1: mcr p15, 0, r0, c8, c7, 1 @ flush TLB (v4) - add r0, r0, #PAGESIZE - cmp r0, r1 -- blt 1b -+ blo 1b - mov pc, lr - - /* -@@ -124,8 +124,8 @@ - * picture. Unfortunately, this does happen. We live with it. - * - * Returns : r0 = address of abort -- * : r1 != 0 if writing -- * : r3 = FSR -+ * : r1 = FSR, bit 11 set if writing -+ * : r3 = corrupted - * : sp = pointer to registers - */ - -@@ -150,16 +150,16 @@ - addeq r7, r0, r7, lsl #2 @ Do correction (signed) - Ldata_saver7: str r7, [sp, r5, lsr #14] @ Put register - Ldata_simple: mrc p15, 0, r0, c6, c0, 0 @ get FAR -- mrc p15, 0, r3, c5, c0, 0 @ get FSR -- and r3, r3, #255 -+ mrc p15, 0, r1, c5, c0, 0 @ get FSR -+ bic r1, r1, #1 << 11 | 1 << 10 -+ tst r4, #1 << 20 -+ orreq r1, r1, #1 << 11 - mov pc, lr - - ENTRY(cpu_arm720_data_abort) -- tst r3, #T_BIT -+ tst r3, #PSR_T_BIT - bne .data_thumb_abort -- ldr r4, [r0] @ read instruction causing problem -- tst r4, r4, lsr #21 @ C = bit 20 -- sbc r1, r1, r1 @ r1 = C - 1 -+ ldr r4, [r2] @ read instruction causing problem - and r2, r4, #15 << 24 - add pc, pc, r2, lsr #22 @ Now branch to the relevent processing routine - movs pc, lr -@@ -270,9 +270,9 @@ - b Ldata_saver7 - - .data_thumb_abort: -- ldrh r4, [r0] @ read instruction -- tst r4, r4, lsr #12 @ C = bit 11 -- sbc r1, r1, r1 @ r1 = C - 1 -+ ldrh r4, [r2] @ read instruction -+ tst r4, #1 << 11 -+ orrne r4, r4, #1 << 20 - and r2, r4, #15 << 12 - add pc, pc, r2, lsr #10 @ lookup in table - nop -@@ -318,8 +318,8 @@ - and r0, r0, #15 @ number of regs to transfer - ldr r7, [sp, #13 << 2] - tst r4, #1 << 11 -- addne r7, r7, r0, lsl #2 @ increment SP if PUSH -- subeq r7, r7, r0, lsr #2 @ decrement SP if POP -+ addeq r7, r7, r0, lsl #2 @ increment SP if PUSH -+ subne r7, r7, r0, lsl #2 @ decrement SP if POP - str r7, [sp, #13 << 2] - b Ldata_simple - -@@ -336,7 +336,7 @@ - and r0, r0, #15 @ number of regs to transfer - and r5, r4, #7 << 8 - ldr r7, [sp, r5, lsr #6] -- sub r7, r7, r0, lsr #2 @ always decrement -+ sub r7, r7, r0, lsl #2 @ always decrement - str r7, [sp, r5, lsr #6] - b Ldata_simple - -@@ -418,7 +418,7 @@ - bic r2, r2, #3 - orr r2, r2, #HPTE_TYPE_SMALL - -- tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? -+ tst r1, #LPTE_USER @ User? - orrne r2, r2, #HPTE_AP_READ - - tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? -diff -urN linux-2.4.26/arch/arm/mm/proc-arm920.S linux-2.4.26-vrs1/arch/arm/mm/proc-arm920.S ---- linux-2.4.26/arch/arm/mm/proc-arm920.S 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mm/proc-arm920.S 2004-01-14 21:32:24.000000000 +0000 -@@ -71,12 +71,16 @@ - */ - .align 5 - ENTRY(cpu_arm920_data_abort) -- mrc p15, 0, r3, c5, c0, 0 @ get FSR -+ mrc p15, 0, r1, c5, c0, 0 @ get FSR - mrc p15, 0, r0, c6, c0, 0 @ get FAR -- ldr r1, [r2] @ read aborted instruction -- and r3, r3, #255 -- tst r1, r1, lsr #21 @ C = bit 20 -- sbc r1, r1, r1 @ r1 = C - 1 -+ -+ tst r3, #PSR_T_BIT -+ ldrneh r3, [r2] @ read aborted thumb instruction -+ ldreq r3, [r2] @ read aborted ARM instruction -+ bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR -+ movne r3, r3, lsl #(21 - 12) @ move thumb bit 11 to ARM bit 20 -+ tst r3, #1 << 20 @ check write -+ orreq r1, r1, #1 << 11 - mov pc, lr - - /* -@@ -186,10 +190,9 @@ - .align 5 - ENTRY(cpu_arm920_cache_clean_invalidate_range) - bic r0, r0, #DCACHELINESIZE - 1 @ && added by PGM -- bic r1, r1, #DCACHELINESIZE - 1 @ && added by DHM - sub r3, r1, r0 - cmp r3, #MAX_AREA_SIZE -- bgt cpu_arm920_cache_clean_invalidate_all_r2 -+ bhi cpu_arm920_cache_clean_invalidate_all_r2 - 1: teq r2, #0 - #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH - mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry -@@ -207,7 +210,7 @@ - add r0, r0, #DCACHELINESIZE - #endif - cmp r0, r1 -- blt 1b -+ blo 1b - - mcr p15, 0, r1, c7, c10, 4 @ drain WB - mov pc, lr -@@ -253,18 +256,17 @@ - */ - .align 5 - ENTRY(cpu_arm920_dcache_invalidate_range) --#ifndef CONFIG_CPU_ARM920_WRITETHROUGH -+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - tst r0, #DCACHELINESIZE - 1 - mcrne p15, 0, r0, c7, c10, 1 @ clean D entry - tst r1, #DCACHELINESIZE - 1 - mcrne p15, 0, r1, c7, c10, 1 @ clean D entry - #endif @ clean D entry - bic r0, r0, #DCACHELINESIZE - 1 -- bic r1, r1, #DCACHELINESIZE - 1 - 1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry - add r0, r0, #DCACHELINESIZE - cmp r0, r1 -- blt 1b -+ blo 1b - mov pc, lr - - /* -@@ -279,20 +281,17 @@ - */ - .align 5 - ENTRY(cpu_arm920_dcache_clean_range) --#ifndef CONFIG_CPU_ARM920_WRITETHROUGH -+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - bic r0, r0, #DCACHELINESIZE - 1 - sub r1, r1, r0 - cmp r1, #MAX_AREA_SIZE - mov r2, #0 -- bgt cpu_arm920_cache_clean_invalidate_all_r2 -- -- bic r1, r1, #DCACHELINESIZE -1 -- add r1, r1, #DCACHELINESIZE -+ bhi cpu_arm920_cache_clean_invalidate_all_r2 - - 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry - add r0, r0, #DCACHELINESIZE - subs r1, r1, #DCACHELINESIZE -- bpl 1b -+ bcs 1b - #endif - mcr p15, 0, r2, c7, c10, 4 @ drain WB - mov pc, lr -@@ -312,7 +311,7 @@ - */ - .align 5 - ENTRY(cpu_arm920_dcache_clean_page) --#ifndef CONFIG_CPU_ARM920_WRITETHROUGH -+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - mov r1, #PAGESIZE - 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry - add r0, r0, #DCACHELINESIZE -@@ -333,7 +332,7 @@ - */ - .align 5 - ENTRY(cpu_arm920_dcache_clean_entry) --#ifndef CONFIG_CPU_ARM920_WRITETHROUGH -+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - mcr p15, 0, r0, c7, c10, 1 @ clean D entry - #endif - mcr p15, 0, r0, c7, c10, 4 @ drain WB -@@ -365,16 +364,13 @@ - bic r0, r0, #ICACHELINESIZE - 1 @ Safety check - sub r1, r1, r0 - cmp r1, #MAX_AREA_SIZE -- bgt cpu_arm920_cache_clean_invalidate_all_r2 -- -- bic r1, r1, #ICACHELINESIZE - 1 -- add r1, r1, #ICACHELINESIZE -+ bhi cpu_arm920_cache_clean_invalidate_all_r2 - - 1: mcr p15, 0, r0, c7, c5, 1 @ Clean I entry - mcr p15, 0, r0, c7, c10, 1 @ Clean D entry - add r0, r0, #ICACHELINESIZE - subs r1, r1, #ICACHELINESIZE -- bne 1b -+ bcs 1b - - mov r0, #0 - mcr p15, 0, r0, c7, c10, 4 @ drain WB -@@ -418,13 +414,12 @@ - mov r3, #PAGESIZE - sub r3, r3, #1 - bic r0, r0, r3 -- bic r1, r1, r3 - - 1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry - add r0, r0, #PAGESIZE - cmp r0, r1 -- blt 1b -+ blo 1b - mov pc, lr - - /* -@@ -457,7 +452,6 @@ - ENTRY(cpu_arm920_set_pgd) - mov ip, #0 - #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH -- /* Any reason why we don't use mcr p15, 0, r0, c7, c7, 0 here? --rmk */ - mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache - #else - @ && 'Clean & Invalidate whole DCache' -@@ -514,7 +508,7 @@ - bic r2, r2, #3 - orr r2, r2, #HPTE_TYPE_SMALL - -- tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? -+ tst r1, #LPTE_USER @ User? - orrne r2, r2, #HPTE_AP_READ - - tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? -diff -urN linux-2.4.26/arch/arm/mm/proc-arm922.S linux-2.4.26-vrs1/arch/arm/mm/proc-arm922.S ---- linux-2.4.26/arch/arm/mm/proc-arm922.S 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mm/proc-arm922.S 2004-01-14 21:32:24.000000000 +0000 -@@ -62,17 +62,20 @@ - * - * Returns: - * r0 = address of abort -- * r1 != 0 if writing -- * r3 = FSR -+ * r1 = FSR, bit 11 set if writing -+ * r3 = corrupted - */ - .align 5 - ENTRY(cpu_arm922_data_abort) -- ldr r1, [r0] @ read aborted instruction -+ mrc p15, 0, r1, c5, c0, 0 @ get FSR - mrc p15, 0, r0, c6, c0, 0 @ get FAR -- tst r1, r1, lsr #21 @ C = bit 20 -- mrc p15, 0, r3, c5, c0, 0 @ get FSR -- sbc r1, r1, r1 @ r1 = C - 1 -- and r3, r3, #255 -+ tst r3, #PSR_T_BIT -+ ldrneh r3, [r2] @ read aborted thumb instruction -+ ldreq r3, [r2] @ read aborted ARM instruction -+ bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR -+ movne r3, r3, lsl #(21 - 12) @ move thumb bit 11 to ARM bit 20 -+ tst r3, #1 << 20 @ check write -+ orreq r1, r1, #1 << 11 - mov pc, lr - - /* -@@ -185,7 +188,7 @@ - bic r1, r1, #DCACHELINESIZE - 1 @ && added by DHM - sub r3, r1, r0 - cmp r3, #MAX_AREA_SIZE -- bgt cpu_arm922_cache_clean_invalidate_all_r2 -+ bhi cpu_arm922_cache_clean_invalidate_all_r2 - 1: teq r2, #0 - #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH - mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry -@@ -203,7 +206,7 @@ - add r0, r0, #DCACHELINESIZE - #endif - cmp r0, r1 -- blt 1b -+ blo 1b - - mcr p15, 0, r1, c7, c10, 4 @ drain WB - mov pc, lr -@@ -249,7 +252,7 @@ - */ - .align 5 - ENTRY(cpu_arm922_dcache_invalidate_range) --#ifndef CONFIG_CPU_ARM922_WRITETHROUGH -+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - tst r0, #DCACHELINESIZE - 1 - mcrne p15, 0, r0, c7, c10, 1 @ clean D entry - tst r1, #DCACHELINESIZE - 1 -@@ -260,7 +263,7 @@ - 1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry - add r0, r0, #DCACHELINESIZE - cmp r0, r1 -- blt 1b -+ blo 1b - mov pc, lr - - /* -@@ -275,12 +278,12 @@ - */ - .align 5 - ENTRY(cpu_arm922_dcache_clean_range) --#ifndef CONFIG_CPU_ARM922_WRITETHROUGH -+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - bic r0, r0, #DCACHELINESIZE - 1 - sub r1, r1, r0 - cmp r1, #MAX_AREA_SIZE - mov r2, #0 -- bgt cpu_arm922_cache_clean_invalidate_all_r2 -+ bhi cpu_arm922_cache_clean_invalidate_all_r2 - - bic r1, r1, #DCACHELINESIZE -1 - add r1, r1, #DCACHELINESIZE -@@ -308,7 +311,7 @@ - */ - .align 5 - ENTRY(cpu_arm922_dcache_clean_page) --#ifndef CONFIG_CPU_ARM922_WRITETHROUGH -+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - mov r1, #PAGESIZE - 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry - add r0, r0, #DCACHELINESIZE -@@ -329,7 +332,7 @@ - */ - .align 5 - ENTRY(cpu_arm922_dcache_clean_entry) --#ifndef CONFIG_CPU_ARM922_WRITETHROUGH -+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - mcr p15, 0, r0, c7, c10, 1 @ clean D entry - #endif - mcr p15, 0, r0, c7, c10, 4 @ drain WB -@@ -361,7 +364,7 @@ - bic r0, r0, #ICACHELINESIZE - 1 @ Safety check - sub r1, r1, r0 - cmp r1, #MAX_AREA_SIZE -- bgt cpu_arm922_cache_clean_invalidate_all_r2 -+ bhi cpu_arm922_cache_clean_invalidate_all_r2 - - bic r1, r1, #ICACHELINESIZE - 1 - add r1, r1, #ICACHELINESIZE -@@ -420,7 +423,7 @@ - mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry - add r0, r0, #PAGESIZE - cmp r0, r1 -- blt 1b -+ blo 1b - mov pc, lr - - /* -@@ -510,7 +513,7 @@ - bic r2, r2, #3 - orr r2, r2, #HPTE_TYPE_SMALL - -- tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? -+ tst r1, #LPTE_USER @ User? - orrne r2, r2, #HPTE_AP_READ - - tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? -diff -urN linux-2.4.26/arch/arm/mm/proc-arm925.S linux-2.4.26-vrs1/arch/arm/mm/proc-arm925.S ---- linux-2.4.26/arch/arm/mm/proc-arm925.S 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mm/proc-arm925.S 2004-01-14 21:32:24.000000000 +0000 -@@ -69,24 +69,24 @@ - * - * Returns: - * r0 = address of abort -- * r1 != 0 if writing -- * r3 = FSR -+ * r1 = FSR, bit 11 set if writing -+ * r3 = corrupted - * r4 = corrupted - */ - .align 5 - ENTRY(cpu_arm925_data_abort) -+ mrc p15, 0, r1, c5, c0, 0 @ get FSR - mrc p15, 0, r0, c6, c0, 0 @ get FAR -- mrc p15, 0, r4, c5, c0, 0 @ get FSR -- -- tst r3, #1<<5 @ Check for Thumb-bit (NE -> found) -- ldrneh r1, [r2] @ Read aborted Thumb instruction -- tstne r1, r1, lsr #12 @ C = bit 11 -- -- ldreq r1, [r2] @ Read aborted ARM instruction -- tsteq r1, r1, lsr #21 @ C = bit 20 -- -- sbc r1, r1, r1 @ r1 = C - 1 -- and r3, r4, #255 -+ bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR -+ tst r3, #PSR_J_BIT @ Java? -+ orrne r1, r1, #1 << 11 @ always assume write -+ movne pc, lr -+ tst r3, #PSR_T_BIT @ Thumb? -+ ldrneh r3, [r2] @ read aborted thumb instruction -+ ldreq r3, [r2] @ read aborted ARM instruction -+ movne r3, r3, lsl #(21 - 12) @ move thumb bit 11 to ARM bit 20 -+ tst r3, #1 << 20 @ L = 0 -> write -+ orreq r1, r1, #1 << 11 @ yes. - mov pc, lr - - /* -@@ -207,7 +207,7 @@ - bic r1, r1, #DCACHELINESIZE - 1 @ && added by DHM - sub r3, r1, r0 - cmp r3, #MAX_AREA_SIZE -- bgt cpu_arm925_cache_clean_invalidate_all_r2 -+ bhi cpu_arm925_cache_clean_invalidate_all_r2 - 1: teq r2, #0 - #ifdef CONFIG_CPU_ARM925_WRITETHROUGH - mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry -@@ -225,7 +225,7 @@ - add r0, r0, #DCACHELINESIZE - #endif - cmp r0, r1 -- blt 1b -+ blo 1b - - mcr p15, 0, r1, c7, c10, 4 @ drain WB - mov pc, lr -@@ -282,7 +282,7 @@ - 1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry - add r0, r0, #DCACHELINESIZE - cmp r0, r1 -- blt 1b -+ blo 1b - mov pc, lr - - /* -@@ -302,7 +302,7 @@ - sub r1, r1, r0 - cmp r1, #MAX_AREA_SIZE - mov r2, #0 -- bgt cpu_arm925_cache_clean_invalidate_all_r2 -+ bhi cpu_arm925_cache_clean_invalidate_all_r2 - - bic r1, r1, #DCACHELINESIZE -1 - add r1, r1, #DCACHELINESIZE -@@ -383,7 +383,7 @@ - bic r0, r0, #ICACHELINESIZE - 1 @ Safety check - sub r1, r1, r0 - cmp r1, #MAX_AREA_SIZE -- bgt cpu_arm925_cache_clean_invalidate_all_r2 -+ bhi cpu_arm925_cache_clean_invalidate_all_r2 - - bic r1, r1, #ICACHELINESIZE - 1 - add r1, r1, #ICACHELINESIZE -@@ -443,7 +443,7 @@ - mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry - add r0, r0, #PAGESIZE - cmp r0, r1 -- blt 1b -+ blo 1b - mov pc, lr - - /* -@@ -532,7 +532,7 @@ - bic r2, r2, #3 - orr r2, r2, #HPTE_TYPE_SMALL - -- tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? -+ tst r1, #LPTE_USER @ User? - orrne r2, r2, #HPTE_AP_READ - - tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? -diff -urN linux-2.4.26/arch/arm/mm/proc-arm926.S linux-2.4.26-vrs1/arch/arm/mm/proc-arm926.S ---- linux-2.4.26/arch/arm/mm/proc-arm926.S 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mm/proc-arm926.S 2004-01-14 21:38:43.000000000 +0000 -@@ -66,28 +66,24 @@ - * - * Returns: - * r0 = address of abort -- * r1 != 0 if writing -- * r3 = FSR -+ * r1 = FSR, bit 11 set if writing -+ * r3 = corrupted - * r4 = corrupted - */ - .align 5 - ENTRY(cpu_arm926_data_abort) -+ mrc p15, 0, r1, c5, c0, 0 @ get FSR - mrc p15, 0, r0, c6, c0, 0 @ get FAR -- mrc p15, 0, r4, c5, c0, 0 @ get FSR -- -- tst r3, #1<<24 @ Check for Jbit (NE -> found) -- movne r3, #-1 @ Mark as writing -- bne 2f -- -- tst r3, #1<<5 @ Check for Thumb-bit (NE -> found) -- ldrneh r1, [r2] @ Read aborted Thumb instruction -- ldreq r1, [r2] @ Read aborted ARM instruction -- movne r1, r1, lsl #(20-12) @ shift thumb bit 10 to ARM bit 20 -- tsteq r1, r1, lsr #21 @ C = bit 20 -- -- sbc r1, r1, r1 @ r1 = C - 1 --2: -- and r3, r4, #255 -+ bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR -+ tst r3, #PSR_J_BIT @ Java? -+ orrne r1, r1, #1 << 11 @ always assume write -+ movne pc, lr -+ tst r3, #PSR_T_BIT @ Thumb? -+ ldrneh r3, [r2] @ read aborted thumb instruction -+ ldreq r3, [r2] @ read aborted ARM instruction -+ movne r3, r3, lsl #(21 - 12) @ move thumb bit 11 to ARM bit 20 -+ tst r3, #1 << 20 @ L = 0 -> write -+ orreq r1, r1, #1 << 11 @ yes. - mov pc, lr - - /* -@@ -263,7 +259,7 @@ - */ - .align 5 - ENTRY(cpu_arm926_dcache_invalidate_range) --#ifndef CONFIG_CPU_ARM926_WRITETHROUGH -+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - tst r0, #DCACHELINESIZE - 1 - mcrne p15, 0, r0, c7, c10, 1 @ clean D entry - tst r1, #DCACHELINESIZE - 1 -@@ -288,7 +284,7 @@ - */ - .align 5 - ENTRY(cpu_arm926_dcache_clean_range) --#ifndef CONFIG_CPU_ARM926_WRITETHROUGH -+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - bic r0, r0, #DCACHELINESIZE - 1 - sub r3, r1, r0 - cmp r3, #MAX_AREA_SIZE -@@ -318,7 +314,7 @@ - */ - .align 5 - ENTRY(cpu_arm926_dcache_clean_page) --#ifndef CONFIG_CPU_ARM926_WRITETHROUGH -+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - mov r1, #PAGESIZE - 1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry - add r0, r0, #DCACHELINESIZE -@@ -339,7 +335,7 @@ - */ - .align 5 - ENTRY(cpu_arm926_dcache_clean_entry) --#ifndef CONFIG_CPU_ARM926_WRITETHROUGH -+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - mcr p15, 0, r0, c7, c10, 1 @ clean D entry - #endif - mcr p15, 0, r0, c7, c10, 4 @ drain WB -@@ -482,7 +478,7 @@ - biceq r1, r1, #4 @ clear bufferable bit - #endif - str r1, [r0] --#ifndef CONFIG_CPU_ARM926_WRITETHROUGH -+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH - mcr p15, 0, r0, c7, c10, 1 @ clean D entry - #endif - mcr p15, 0, r0, c7, c10, 4 @ drain WB -@@ -503,7 +499,7 @@ - bic r2, r2, #3 - orr r2, r2, #HPTE_TYPE_SMALL - -- tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? -+ tst r1, #LPTE_USER @ User? - orrne r2, r2, #HPTE_AP_READ - - tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? -diff -urN linux-2.4.26/arch/arm/mm/proc-sa110.S linux-2.4.26-vrs1/arch/arm/mm/proc-sa110.S ---- linux-2.4.26/arch/arm/mm/proc-sa110.S 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/mm/proc-sa110.S 2004-01-14 21:32:24.000000000 +0000 -@@ -86,12 +86,12 @@ - .align 5 - ENTRY(cpu_sa110_data_abort) - ENTRY(cpu_sa1100_data_abort) -- mrc p15, 0, r3, c5, c0, 0 @ get FSR -+ mrc p15, 0, r1, c5, c0, 0 @ get FSR - mrc p15, 0, r0, c6, c0, 0 @ get FAR -- ldr r1, [r2] @ read aborted instruction -- and r3, r3, #255 -- tst r1, r1, lsr #21 @ C = bit 20 -- sbc r1, r1, r1 @ r1 = C - 1 -+ ldr r3, [r2] @ read aborted instruction -+ bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR -+ tst r3, #1 << 20 @ check write -+ orreq r1, r1, #1 << 11 - mov pc, lr - - /* -@@ -551,7 +551,7 @@ - bic r2, r2, #3 - orr r2, r2, #HPTE_TYPE_SMALL - -- tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? -+ tst r1, #LPTE_USER @ User? - orrne r2, r2, #HPTE_AP_READ - - tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? -diff -urN linux-2.4.26/arch/arm/tools/mach-types linux-2.4.26-vrs1/arch/arm/tools/mach-types ---- linux-2.4.26/arch/arm/tools/mach-types 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/arm/tools/mach-types 2004-04-19 21:11:38.000000000 +0100 -@@ -6,7 +6,7 @@ - # To add an entry into this database, please see Documentation/arm/README, - # or contact rmk@arm.linux.org.uk - # --# Last update: Sat Jun 28 12:10:54 2003 -+# Last update: Mon Apr 19 21:11:35 2004 - # - # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number - # -@@ -202,7 +202,7 @@ - fester SA1100_FESTER FESTER 191 - gpi ARCH_GPI GPI 192 - smdk2410 ARCH_SMDK2410 SMDK2410 193 --premium ARCH_PREMIUM PREMIUM 194 -+i519 ARCH_I519 I519 194 - nexio SA1100_NEXIO NEXIO 195 - bitbox SA1100_BITBOX BITBOX 196 - g200 SA1100_G200 G200 197 -@@ -228,7 +228,7 @@ - arnold SA1100_ARNOLD ARNOLD 217 - psiboard SA1100_PSIBOARD PSIBOARD 218 - jz8028 ARCH_JZ8028 JZ8028 219 --h5400 ARCH_IPAQ3 IPAQ3 220 -+h5400 ARCH_H5400 H5400 220 - forte SA1100_FORTE FORTE 221 - acam SA1100_ACAM ACAM 222 - abox SA1100_ABOX ABOX 223 -@@ -259,7 +259,7 @@ - stork_egg ARCH_STORK_EGG STORK_EGG 248 - wismo SA1100_WISMO WISMO 249 - ezlinx ARCH_EZLINX EZLINX 250 --at91rm9200 ARCH_AT91 AT91 251 -+at91rm9200 ARCH_AT91RM9200 AT91RM9200 251 - orion ARCH_ORION ORION 252 - neptune ARCH_NEPTUNE NEPTUNE 253 - hackkit SA1100_HACKKIT HACKKIT 254 -@@ -295,12 +295,12 @@ - adsbitsyplus SA1100_ADSBITSYPLUS ADSBITSYPLUS 284 - adsagc SA1100_ADSAGC ADSAGC 285 - stp7312 ARCH_STP7312 STP7312 286 --nx_phnx ARCH_PXA255 PXA255 287 -+nx_phnx MACH_NX_PHNX NX_PHNX 287 - wep_ep250 ARCH_WEP_EP250 WEP_EP250 288 - inhandelf3 ARCH_INHANDELF3 INHANDELF3 289 - adi_coyote ARCH_ADI_COYOTE ADI_COYOTE 290 - iyonix ARCH_IYONIX IYONIX 291 --damicam_sa1110 ARCH_DAMICAM_SA1110 DAMICAM_SA1110 292 -+damicam1 ARCH_DAMICAM_SA1110 DAMICAM_SA1110 292 - meg03 ARCH_MEG03 MEG03 293 - pxa_whitechapel ARCH_PXA_WHITECHAPEL PXA_WHITECHAPEL 294 - nwsc ARCH_NWSC NWSC 295 -@@ -356,3 +356,172 @@ - seedpxa_c2 ARCH_SEEDPXA_C2 SEEDPXA_C2 345 - ixp4xx_mguardpci ARCH_IXP4XX_MGUARD_PCI IXP4XX_MGUARD_PCI 346 - h1940 ARCH_H1940 H1940 347 -+scorpio ARCH_SCORPIO SCORPIO 348 -+viva ARCH_VIVA VIVA 349 -+pxa_xcard ARCH_PXA_XCARD PXA_XCARD 350 -+csb335 ARCH_CSB335 CSB335 351 -+ixrd425 ARCH_IXRD425 IXRD425 352 -+iq80315 ARCH_IQ80315 IQ80315 353 -+nmp7312 ARCH_NMP7312 NMP7312 354 -+cx861xx ARCH_CX861XX CX861XX 355 -+enp2611 ARCH_ENP2611 ENP2611 356 -+xda SA1100_XDA XDA 357 -+csir_ims ARCH_CSIR_IMS CSIR_IMS 358 -+ixp421_dnaeeth ARCH_IXP421_DNAEETH IXP421_DNAEETH 359 -+pocketserv9200 ARCH_POCKETSERV9200 POCKETSERV9200 360 -+toto ARCH_TOTO TOTO 361 -+s3c2440 ARCH_S3C2440 S3C2440 362 -+ks8695p ARCH_KS8695P KS8695P 363 -+se4000 ARCH_SE4000 SE4000 364 -+quadriceps ARCH_QUADRICEPS QUADRICEPS 365 -+bronco ARCH_BRONCO BRONCO 366 -+esl_wireless_tab ARCH_ESL_WIRELESS_TABLETESL_WIRELESS_TABLET 367 -+esl_sofcomp ARCH_ESL_SOFCOMP ESL_SOFCOMP 368 -+s5c7375 ARCH_S5C7375 S5C7375 369 -+spearhead ARCH_SPEARHEAD SPEARHEAD 370 -+pantera ARCH_PANTERA PANTERA 371 -+prayoglite ARCH_PRAYOGLITE PRAYOGLITE 372 -+gumstik ARCH_GUMSTIK GUMSTIK 373 -+rcube ARCH_RCUBE RCUBE 374 -+rea_olv ARCH_REA_OLV REA_OLV 375 -+pxa_iphone ARCH_PXA_IPHONE PXA_IPHONE 376 -+s3c3410 ARCH_S3C3410 S3C3410 377 -+espd_4510b ARCH_ESPD_4510B ESPD_4510B 378 -+mp1x ARCH_MP1X MP1X 379 -+at91rm9200tb ARCH_AT91RM9200TB AT91RM9200TB 380 -+adsvgx ARCH_ADSVGX ADSVGX 381 -+omap_h2 ARCH_OMAP_H2 OMAP_H2 382 -+pelee ARCH_PELEE PELEE 383 -+e740 MACH_E740 E740 384 -+iq80331 ARCH_IQ80331 IQ80331 385 -+versatile_pb ARCH_VERSATILE_PB VERSATILE_PB 387 -+kev7a400 MACH_KEV7A400 KEV7A400 388 -+lpd7a400 MACH_LPD7A400 LPD7A400 389 -+lpd7a404 MACH_LPD7A404 LPD7A404 390 -+fujitsu_camelot ARCH_FUJITSU_CAMELOT FUJITSU_CAMELOT 391 -+janus2m ARCH_JANUS2M JANUS2M 392 -+embtf MACH_EMBTF EMBTF 393 -+hpm MACH_HPM HPM 394 -+smdk2410tk MACH_SMDK2410TK SMDK2410TK 395 -+smdk2410aj MACH_SMDK2410AJ SMDK2410AJ 396 -+streetracer MACH_STREETRACER STREETRACER 397 -+eframe MACH_EFRAME EFRAME 398 -+csb337 MACH_CSB337 CSB337 399 -+pxa_lark MACH_PXA_LARK PXA_LARK 400 -+pxa_pnp2110 MACH_PNP2110 PNP2110 401 -+tcc72x MACH_TCC72X TCC72X 402 -+altair MACH_ALTAIR ALTAIR 403 -+kc3 MACH_KC3 KC3 404 -+sinteftd MACH_SINTEFTD SINTEFTD 405 -+mainstone MACH_MAINSTONE MAINSTONE 406 -+aday4x MACH_ADAY4X ADAY4X 407 -+lite300 MACH_LITE300 LITE300 408 -+s5c7376 MACH_S5C7376 S5C7376 409 -+mt02 MACH_MT02 MT02 410 -+mport3s MACH_MPORT3S MPORT3S 411 -+ra_alpha MACH_RA_ALPHA RA_ALPHA 412 -+xcep MACH_XCEP XCEP 413 -+arcom_mercury MACH_ARCOM_MERCURY ARCOM_MERCURY 414 -+stargate MACH_STARGATE STARGATE 415 -+armadilloj MACH_ARMADILLOJ ARMADILLOJ 416 -+elroy_jack MACH_ELROY_JACK ELROY_JACK 417 -+backend MACH_BACKEND BACKEND 418 -+s5linbox MACH_S5LINBOX S5LINBOX 419 -+nomadik MACH_NOMADIK NOMADIK 420 -+ia_cpu_9200 MACH_IA_CPU_9200 IA_CPU_9200 421 -+at91_bja1 MACH_AT91_BJA1 AT91_BJA1 422 -+corgi MACH_CORGI CORGI 423 -+poodle MACH_POODLE POODLE 424 -+ten MACH_TEN TEN 425 -+roverp5p MACH_ROVERP5P ROVERP5P 426 -+sc2700 MACH_SC2700 SC2700 427 -+ex_eagle MACH_EX_EAGLE EX_EAGLE 428 -+nx_pxa12 MACH_NX_PXA12 NX_PXA12 429 -+nx_pxa5 MACH_NX_PXA5 NX_PXA5 430 -+blackboard2 MACH_BLACKBOARD2 BLACKBOARD2 431 -+i819 MACH_I819 I819 432 -+ixmb995e MACH_IXMB995E IXMB995E 433 -+skyrider MACH_SKYRIDER SKYRIDER 434 -+skyhawk MACH_SKYHAWK SKYHAWK 435 -+enterprise MACH_ENTERPRISE ENTERPRISE 436 -+dep2410 MACH_DEP2410 DEP2410 437 -+armcore MACH_ARMCORE ARMCORE 438 -+hobbit MACH_HOBBIT HOBBIT 439 -+h7210 MACH_H7210 H7210 440 -+pxa_netdcu5 MACH_PXA_NETDCU5 PXA_NETDCU5 441 -+acc MACH_ACC ACC 442 -+esl_sarva MACH_ESL_SARVA ESL_SARVA 443 -+xm250 MACH_XM250 XM250 444 -+t6tc1xb MACH_T6TC1XB T6TC1XB 445 -+ess710 MACH_ESS710 ESS710 446 -+mx3ads MACH_MX3ADS MX3ADS 447 -+himalaya MACH_HIMALAYA HIMALAYA 448 -+bolfenk MACH_BOLFENK BOLFENK 449 -+at91rm9200kr MACH_AT91RM9200KR AT91RM9200KR 450 -+edb9312 MACH_EDB9312 EDB9312 451 -+omap_generic MACH_OMAP_GENERIC OMAP_GENERIC 452 -+aximx3 MACH_AXIMX3 AXIMX3 453 -+eb67xdip MACH_EB67XDIP EB67XDIP 454 -+webtxs MACH_WEBTXS WEBTXS 455 -+hawk MACH_HAWK HAWK 456 -+ccat91sbc001 MACH_CCAT91SBC001 CCAT91SBC001 457 -+expresso MACH_EXPRESSO EXPRESSO 458 -+h4000 MACH_H4000 H4000 459 -+dino MACH_DINO DINO 460 -+ml675k MACH_ML675K ML675K 461 -+edb9301 MACH_EDB9301 EDB9301 462 -+edb9315 MACH_EDB9315 EDB9315 463 -+reciva_tt MACH_RECIVA_TT RECIVA_TT 464 -+cstcb01 MACH_CSTCB01 CSTCB01 465 -+cstcb1 MACH_CSTCB1 CSTCB1 466 -+shadwell MACH_SHADWELL SHADWELL 467 -+goepel263 MACH_GOEPEL263 GOEPEL263 468 -+acq100 MACH_ACQ100 ACQ100 469 -+mx1fs2 MACH_MX1FS2 MX1FS2 470 -+hiptop_g1 MACH_HIPTOP_G1 HIPTOP_G1 471 -+sparky MACH_SPARKY SPARKY 472 -+ns9750 MACH_NS9750 NS9750 473 -+phoenix MACH_PHOENIX PHOENIX 474 -+vr1000 MACH_VR1000 VR1000 475 -+deisterpxa MACH_DEISTERPXA DEISTERPXA 476 -+bcm1160 MACH_BCM1160 BCM1160 477 -+pcm022 MACH_PCM022 PCM022 478 -+adsgcx MACH_ADSGCX ADSGCX 479 -+dreadnaught MACH_DREADNAUGHT DREADNAUGHT 480 -+dm320 MACH_DM320 DM320 481 -+markov MACH_MARKOV MARKOV 482 -+cos7a400 MACH_COS7A400 COS7A400 483 -+milano MACH_MILANO MILANO 484 -+ue9328 MACH_UE9328 UE9328 485 -+uex255 MACH_UEX255 UEX255 486 -+ue2410 MACH_UE2410 UE2410 487 -+a620 MACH_A620 A620 488 -+ocelot MACH_OCELOT OCELOT 489 -+cheetah MACH_CHEETAH CHEETAH 490 -+omap_perseus2 MACH_OMAP_PERSEUS2 OMAP_PERSEUS2 491 -+zvue MACH_ZVUE ZVUE 492 -+roverp1 MACH_ROVERP1 ROVERP1 493 -+asidial2 MACH_ASIDIAL2 ASIDIAL2 494 -+s3c24a0 MACH_S3C24A0 S3C24A0 495 -+e800 MACH_E800 E800 496 -+e750 MACH_E750 E750 497 -+s3c5500 MACH_S3C5500 S3C5500 498 -+smdk5500 MACH_SMDK5500 SMDK5500 499 -+signalsync MACH_SIGNALSYNC SIGNALSYNC 500 -+nbc MACH_NBC NBC 501 -+er4525 MACH_ER4525 ER4525 502 -+netbookpro MACH_NETBOOKPRO NETBOOKPRO 503 -+hw90200 MACH_HW90200 HW90200 504 -+condor MACH_CONDOR CONDOR 505 -+cup MACH_CUP CUP 506 -+kite MACH_KITE KITE 507 -+scb9328 MACH_SCB9328 SCB9328 508 -+omap_h3 MACH_OMAP_H3 OMAP_H3 509 -+omap_h4 MACH_OMAP_H4 OMAP_H4 510 -+n10 MACH_N10 N10 511 -+montajade MACH_MONTAJADE MONTAJADE 512 -+sg560 MACH_SG560 SG560 513 -+dp1000 MACH_DP1000 DP1000 514 -+omap_osk MACH_OMAP_OSK OMAP_OSK 515 -+rg100v3 MACH_RG100V3 RG100V3 516 -+mx2ads MACH_MX2ADS MX2ADS 517 -diff -urN linux-2.4.26/arch/i386/config.in linux-2.4.26-vrs1/arch/i386/config.in ---- linux-2.4.26/arch/i386/config.in 2004-02-27 20:03:23.000000000 +0000 -+++ linux-2.4.26-vrs1/arch/i386/config.in 2004-02-23 13:36:21.000000000 +0000 -@@ -9,6 +9,7 @@ - - define_bool CONFIG_UID16 y - -+define_bool CONFIG_GENERIC_ISA_DMA y - mainmenu_option next_comment - comment 'Code maturity level options' - bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL -diff -urN linux-2.4.26/arch/i386/kernel/Makefile linux-2.4.26-vrs1/arch/i386/kernel/Makefile ---- linux-2.4.26/arch/i386/kernel/Makefile 2003-11-28 18:26:19.000000000 +0000 -+++ linux-2.4.26-vrs1/arch/i386/kernel/Makefile 2004-01-14 21:38:44.000000000 +0000 -@@ -7,8 +7,8 @@ - # - # Note 2! The CFLAGS definitions are now in the main makefile... - --.S.o: -- $(CC) $(AFLAGS) -traditional -c $< -o $*.o -+USE_STANDARD_AS_RULE := true -+EXTRA_AFLAGS := -traditional - - all: kernel.o head.o init_task.o - -diff -urN linux-2.4.26/arch/i386/kernel/apm.c linux-2.4.26-vrs1/arch/i386/kernel/apm.c ---- linux-2.4.26/arch/i386/kernel/apm.c 2003-08-25 12:44:39.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/i386/kernel/apm.c 2004-01-14 21:38:44.000000000 +0000 -@@ -1267,6 +1267,7 @@ - as->suspend_wait = 0; - as->suspend_result = err; - } -+ ignore_normal_resume = 1; - wake_up_interruptible(&apm_suspend_waitqueue); - return err; - } -@@ -1319,6 +1320,8 @@ - if (ignore_bounce - && ((jiffies - last_resume) > bounce_interval)) - ignore_bounce = 0; -+ if (ignore_normal_resume && (event != APM_NORMAL_RESUME)) -+ ignore_normal_resume = 0; - - switch (event) { - case APM_SYS_STANDBY: -diff -urN linux-2.4.26/arch/i386/lib/Makefile linux-2.4.26-vrs1/arch/i386/lib/Makefile ---- linux-2.4.26/arch/i386/lib/Makefile 2001-09-10 15:31:30.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/i386/lib/Makefile 2004-01-14 21:32:24.000000000 +0000 -@@ -2,8 +2,7 @@ - # Makefile for i386-specific library files.. - # - --.S.o: -- $(CC) $(AFLAGS) -c $< -o $*.o -+USE_STANDARD_AS_RULE := true - - L_TARGET = lib.a - -diff -urN linux-2.4.26/arch/i386/math-emu/Makefile linux-2.4.26-vrs1/arch/i386/math-emu/Makefile ---- linux-2.4.26/arch/i386/math-emu/Makefile 2000-12-29 22:07:20.000000000 +0000 -+++ linux-2.4.26-vrs1/arch/i386/math-emu/Makefile 2004-01-14 21:32:24.000000000 +0000 -@@ -2,15 +2,15 @@ - # Makefile for wm-FPU-emu - # - -+USE_STANDARD_AS_RULE := true -+ - O_TARGET := math.o - - #DEBUG = -DDEBUGGING - DEBUG = - PARANOID = -DPARANOID - CFLAGS := $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin $(MATH_EMULATION) -- --.S.o: -- $(CC) $(AFLAGS) $(PARANOID) -c $< -+EXTRA_AFLAGS := $(PARANOID) - - # From 'C' language sources: - C_OBJS =fpu_entry.o errors.o \ -diff -urN linux-2.4.26/arch/ia64/config.in linux-2.4.26-vrs1/arch/ia64/config.in ---- linux-2.4.26/arch/ia64/config.in 2004-02-27 20:03:23.000000000 +0000 -+++ linux-2.4.26-vrs1/arch/ia64/config.in 2004-02-23 13:36:21.000000000 +0000 -@@ -25,6 +25,7 @@ - define_bool CONFIG_SBUS n - define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n - define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y -+define_bool CONFIG_GENERIC_ISA_DMA y - - choice 'IA-64 processor type' \ - "Itanium CONFIG_ITANIUM \ -diff -urN linux-2.4.26/arch/m68k/config.in linux-2.4.26-vrs1/arch/m68k/config.in ---- linux-2.4.26/arch/m68k/config.in 2004-02-27 20:03:23.000000000 +0000 -+++ linux-2.4.26-vrs1/arch/m68k/config.in 2004-02-23 13:36:22.000000000 +0000 -@@ -6,6 +6,7 @@ - define_bool CONFIG_UID16 y - define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y - define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n -+define_bool CONFIG_GENERIC_ISA_DMA y - - mainmenu_name "Linux/68k Kernel Configuration" - -diff -urN linux-2.4.26/arch/mips/config.in linux-2.4.26-vrs1/arch/mips/config.in ---- linux-2.4.26/arch/mips/config.in 2002-11-28 23:53:09.000000000 +0000 -+++ linux-2.4.26-vrs1/arch/mips/config.in 2004-01-14 21:32:24.000000000 +0000 -@@ -5,5 +5,6 @@ - define_bool CONFIG_MIPS y - define_bool CONFIG_MIPS32 y - define_bool CONFIG_MIPS64 n -+define_bool CONFIG_GENERIC_ISA_DMA y - - source arch/mips/config-shared.in -diff -urN linux-2.4.26/arch/parisc/config.in linux-2.4.26-vrs1/arch/parisc/config.in ---- linux-2.4.26/arch/parisc/config.in 2004-02-27 20:03:24.000000000 +0000 -+++ linux-2.4.26-vrs1/arch/parisc/config.in 2004-02-23 13:36:26.000000000 +0000 -@@ -9,6 +9,7 @@ - define_bool CONFIG_UID16 n - define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y - define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n -+define_bool CONFIG_GENERIC_ISA_DMA y - - mainmenu_option next_comment - comment 'Code maturity level options' -diff -urN linux-2.4.26/arch/ppc/config.in linux-2.4.26-vrs1/arch/ppc/config.in ---- linux-2.4.26/arch/ppc/config.in 2004-04-19 11:44:15.000000000 +0100 -+++ linux-2.4.26-vrs1/arch/ppc/config.in 2004-04-18 21:47:50.000000000 +0100 -@@ -6,6 +6,7 @@ - define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n - define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y - define_bool CONFIG_HAVE_DEC_LOCK y -+define_bool CONFIG_GENERIC_ISA_DMA y - - mainmenu_name "Linux/PowerPC Kernel Configuration" - -diff -urN linux-2.4.26/arch/sh/config.in linux-2.4.26-vrs1/arch/sh/config.in ---- linux-2.4.26/arch/sh/config.in 2004-02-27 20:03:25.000000000 +0000 -+++ linux-2.4.26-vrs1/arch/sh/config.in 2004-02-23 13:36:27.000000000 +0000 -@@ -9,6 +9,7 @@ - define_bool CONFIG_UID16 y - define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y - define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n -+define_bool CONFIG_GENERIC_ISA_DMA y - - mainmenu_option next_comment - comment 'Code maturity level options' -diff -urN linux-2.4.26/arch/sparc/config.in linux-2.4.26-vrs1/arch/sparc/config.in ---- linux-2.4.26/arch/sparc/config.in 2004-02-27 20:03:25.000000000 +0000 -+++ linux-2.4.26-vrs1/arch/sparc/config.in 2004-02-23 13:36:27.000000000 +0000 -@@ -6,6 +6,7 @@ - - define_bool CONFIG_UID16 y - define_bool CONFIG_HIGHMEM y -+define_bool CONFIG_GENERIC_ISA_DMA y - - mainmenu_option next_comment - comment 'Code maturity level options' -diff -urN linux-2.4.26/arch/sparc64/config.in linux-2.4.26-vrs1/arch/sparc64/config.in ---- linux-2.4.26/arch/sparc64/config.in 2004-02-27 20:03:25.000000000 +0000 -+++ linux-2.4.26-vrs1/arch/sparc64/config.in 2004-02-23 13:36:27.000000000 +0000 -@@ -41,6 +41,7 @@ - define_bool CONFIG_HAVE_DEC_LOCK y - define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n - define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y -+define_bool CONFIG_GENERIC_ISA_DMA y - define_bool CONFIG_ISA n - define_bool CONFIG_ISAPNP n - define_bool CONFIG_EISA n -diff -urN linux-2.4.26/drivers/Makefile linux-2.4.26-vrs1/drivers/Makefile ---- linux-2.4.26/drivers/Makefile 2003-11-28 18:26:19.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/Makefile 2004-02-04 04:11:33.000000000 +0000 -@@ -8,9 +8,9 @@ - - mod-subdirs := dio hil mtd sbus video macintosh usb input telephony ide \ - message/i2o message/fusion scsi md ieee1394 pnp isdn atm \ -- fc4 net/hamradio i2c acpi bluetooth usb/gadget -+ fc4 net/hamradio i2c l3 acpi bluetooth serial usb/gadget - --subdir-y := parport char block net sound misc media cdrom hotplug -+subdir-y := parport serial char block net sound misc media cdrom hotplug pld - subdir-m := $(subdir-y) - - -@@ -45,8 +45,12 @@ - # CONFIG_HAMRADIO can be set without CONFIG_NETDEVICE being set -- ch - subdir-$(CONFIG_HAMRADIO) += net/hamradio - subdir-$(CONFIG_I2C) += i2c -+subdir-$(CONFIG_L3) += l3 - subdir-$(CONFIG_ACPI_BOOT) += acpi - - subdir-$(CONFIG_BLUEZ) += bluetooth -+subdir-$(CONFIG_SSI) += ssi -+ -+subdir-$(CONFIG_ARCH_AT91RM9200)+= at91 - - include $(TOPDIR)/Rules.make -diff -urN linux-2.4.26/drivers/acorn/char/i2c.c linux-2.4.26-vrs1/drivers/acorn/char/i2c.c ---- linux-2.4.26/drivers/acorn/char/i2c.c 2004-01-05 13:53:56.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/acorn/char/i2c.c 2004-04-10 11:43:00.000000000 +0100 -@@ -33,9 +33,13 @@ - static struct i2c_client *rtc_client; - static const unsigned char days_in_mon[] = - { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; --static unsigned int rtc_epoch = 1900; - - #define CMOS_CHECKSUM (63) -+ -+/* -+ * Acorn machines store the year in the static RAM at -+ * location 128. -+ */ - #define CMOS_YEAR (64 + 128) - - static inline int rtc_command(int cmd, void *data) -@@ -49,51 +53,91 @@ - } - - /* -+ * Update the century + year bytes in the CMOS RAM, ensuring -+ * that the check byte is correctly adjusted for the change. -+ */ -+static int rtc_update_year(unsigned int new_year) -+{ -+ unsigned char yr[2], chk; -+ struct mem cmos_year = { CMOS_YEAR, sizeof(yr), yr }; -+ struct mem cmos_check = { CMOS_CHECKSUM, 1, &chk }; -+ int ret; -+ -+ ret = rtc_command(MEM_READ, &cmos_check); -+ if (ret) -+ goto out; -+ ret = rtc_command(MEM_READ, &cmos_year); -+ if (ret) -+ goto out; -+ -+ chk -= yr[1] + yr[0]; -+ -+ yr[1] = new_year / 100; -+ yr[0] = new_year % 100; -+ -+ chk += yr[1] + yr[0]; -+ -+ ret = rtc_command(MEM_WRITE, &cmos_year); -+ if (ret == 0) -+ ret = rtc_command(MEM_WRITE, &cmos_check); -+ out: -+ return ret; -+} -+ -+ -+/* - * Read the current RTC time and date, and update xtime. - */ - static void get_rtc_time(struct rtc_tm *rtctm, unsigned int *year) - { - unsigned char ctrl, yr[2]; - struct mem rtcmem = { CMOS_YEAR, sizeof(yr), yr }; -+ int real_year, year_offset; - - /* - * Ensure that the RTC is running. - */ - rtc_command(RTC_GETCTRL, &ctrl); - if (ctrl & 0xc0) { -- unsigned char new_ctrl; -- -- new_ctrl = ctrl & ~0xc0; -+ unsigned char new_ctrl = ctrl & ~0xc0; - -- printk("RTC: resetting control %02X -> %02X\n", -- ctrl, new_ctrl); -+ printk(KERN_WARNING "RTC: resetting control %02x -> %02x\n", -+ ctrl, new_ctrl); - - rtc_command(RTC_SETCTRL, &new_ctrl); - } - -+ if (rtc_command(RTC_GETDATETIME, rtctm) || -+ rtc_command(MEM_READ, &rtcmem)) -+ return; -+ -+ real_year = yr[0]; -+ - /* -- * Acorn machines store the year in -- * the static RAM at location 192. -+ * The RTC year holds the LSB two bits of the current -+ * year, which should reflect the LSB two bits of the -+ * CMOS copy of the year. Any difference indicates -+ * that we have to correct the CMOS version. - */ -- if (rtc_command(MEM_READ, &rtcmem)) -- return; -+ year_offset = rtctm->year_off - (real_year & 3); -+ if (year_offset < 0) -+ /* -+ * RTC year wrapped. Adjust it appropriately. -+ */ -+ year_offset += 4; - -- if (rtc_command(RTC_GETDATETIME, rtctm)) -- return; -+ *year = real_year + year_offset + yr[1] * 100; - -- *year = yr[1] * 100 + yr[0]; - } - - static int set_rtc_time(struct rtc_tm *rtctm, unsigned int year) - { -- unsigned char yr[2], leap, chk; -- struct mem cmos_year = { CMOS_YEAR, sizeof(yr), yr }; -- struct mem cmos_check = { CMOS_CHECKSUM, 1, &chk }; -+ unsigned char leap; - int ret; - - leap = (!(year % 4) && (year % 100)) || !(year % 400); - -- if (rtctm->mon > 12 || rtctm->mday == 0) -+ if (rtctm->mon > 12 || rtctm->mon == 0 || rtctm->mday == 0) - return -EINVAL; - - if (rtctm->mday > (days_in_mon[rtctm->mon] + (rtctm->mon == 2 && leap))) -@@ -102,21 +146,16 @@ - if (rtctm->hours >= 24 || rtctm->mins >= 60 || rtctm->secs >= 60) - return -EINVAL; - -- ret = rtc_command(RTC_SETDATETIME, rtctm); -- if (ret == 0) { -- rtc_command(MEM_READ, &cmos_check); -- rtc_command(MEM_READ, &cmos_year); -- -- chk -= yr[1] + yr[0]; -- -- yr[1] = year / 100; -- yr[0] = year % 100; -+ /* -+ * The RTC's own 2-bit year must reflect the least -+ * significant two bits of the CMOS year. -+ */ -+ rtctm->year_off = (year % 100) & 3; - -- chk += yr[1] + yr[0]; -+ ret = rtc_command(RTC_SETDATETIME, rtctm); -+ if (ret == 0) -+ ret = rtc_update_year(year); - -- rtc_command(MEM_WRITE, &cmos_year); -- rtc_command(MEM_WRITE, &cmos_check); -- } - return ret; - } - -@@ -166,7 +205,6 @@ - break; - - case RTC_RD_TIME: -- memset(&rtctm, 0, sizeof(struct rtc_time)); - get_rtc_time(&rtc_raw, &year); - rtctm.tm_sec = rtc_raw.secs; - rtctm.tm_min = rtc_raw.mins; -@@ -188,13 +226,12 @@ - rtc_raw.hours = rtctm.tm_hour; - rtc_raw.mday = rtctm.tm_mday; - rtc_raw.mon = rtctm.tm_mon + 1; -- rtc_raw.year_off = 2; - year = rtctm.tm_year + 1900; - return set_rtc_time(&rtc_raw, year); - break; - - case RTC_EPOCH_READ: -- return put_user(rtc_epoch, (unsigned long *)arg); -+ return put_user(1900, (unsigned long *)arg); - - } - return -EINVAL; -diff -urN linux-2.4.26/drivers/acorn/net/ether1.c linux-2.4.26-vrs1/drivers/acorn/net/ether1.c ---- linux-2.4.26/drivers/acorn/net/ether1.c 2003-08-25 12:44:40.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/acorn/net/ether1.c 2004-04-09 19:55:21.000000000 +0100 -@@ -80,7 +80,7 @@ - #define BUS_16 16 - #define BUS_8 8 - --static const card_ids __init ether1_cids[] = { -+static card_ids __initdata ether1_cids[] = { - { MANU_ACORN, PROD_ACORN_ETHER1 }, - { 0xffff, 0xffff } - }; -@@ -153,35 +153,35 @@ - length -= thislen; - - __asm__ __volatile__( -- "subs %3, %3, #2 -- bmi 2f --1: ldr %0, [%1], #2 -- mov %0, %0, lsl #16 -- orr %0, %0, %0, lsr #16 -- str %0, [%2], #4 -- subs %3, %3, #2 -- bmi 2f -- ldr %0, [%1], #2 -- mov %0, %0, lsl #16 -- orr %0, %0, %0, lsr #16 -- str %0, [%2], #4 -- subs %3, %3, #2 -- bmi 2f -- ldr %0, [%1], #2 -- mov %0, %0, lsl #16 -- orr %0, %0, %0, lsr #16 -- str %0, [%2], #4 -- subs %3, %3, #2 -- bmi 2f -- ldr %0, [%1], #2 -- mov %0, %0, lsl #16 -- orr %0, %0, %0, lsr #16 -- str %0, [%2], #4 -- subs %3, %3, #2 -- bpl 1b --2: adds %3, %3, #1 -- ldreqb %0, [%1] -- streqb %0, [%2]" -+" subs %3, %3, #2 \n" -+" bmi 2f \n" -+"1: ldr %0, [%1], #2 \n" -+" mov %0, %0, lsl #16 \n" -+" orr %0, %0, %0, lsr #16 \n" -+" str %0, [%2], #4 \n" -+" subs %3, %3, #2 \n" -+" bmi 2f \n" -+" ldr %0, [%1], #2 \n" -+" mov %0, %0, lsl #16 \n" -+" orr %0, %0, %0, lsr #16 \n" -+" str %0, [%2], #4 \n" -+" subs %3, %3, #2 \n" -+" bmi 2f \n" -+" ldr %0, [%1], #2 \n" -+" mov %0, %0, lsl #16 \n" -+" orr %0, %0, %0, lsr #16 \n" -+" str %0, [%2], #4 \n" -+" subs %3, %3, #2 \n" -+" bmi 2f \n" -+" ldr %0, [%1], #2 \n" -+" mov %0, %0, lsl #16 \n" -+" orr %0, %0, %0, lsr #16 \n" -+" str %0, [%2], #4 \n" -+" subs %3, %3, #2 \n" -+" bpl 1b \n" -+"2: adds %3, %3, #1 \n" -+" ldreqb %0, [%1] \n" -+" streqb %0, [%2] \n" - : "=&r" (used), "=&r" (data) - : "r" (addr), "r" (thislen), "1" (data)); - -@@ -215,35 +215,35 @@ - length -= thislen; - - __asm__ __volatile__( -- "subs %3, %3, #2 -- bmi 2f --1: ldr %0, [%2], #4 -- strb %0, [%1], #1 -- mov %0, %0, lsr #8 -- strb %0, [%1], #1 -- subs %3, %3, #2 -- bmi 2f -- ldr %0, [%2], #4 -- strb %0, [%1], #1 -- mov %0, %0, lsr #8 -- strb %0, [%1], #1 -- subs %3, %3, #2 -- bmi 2f -- ldr %0, [%2], #4 -- strb %0, [%1], #1 -- mov %0, %0, lsr #8 -- strb %0, [%1], #1 -- subs %3, %3, #2 -- bmi 2f -- ldr %0, [%2], #4 -- strb %0, [%1], #1 -- mov %0, %0, lsr #8 -- strb %0, [%1], #1 -- subs %3, %3, #2 -- bpl 1b --2: adds %3, %3, #1 -- ldreqb %0, [%2] -- streqb %0, [%1]" -+" subs %3, %3, #2 \n" -+" bmi 2f \n" -+"1: ldr %0, [%2], #4 \n" -+" strb %0, [%1], #1 \n" -+" mov %0, %0, lsr #8 \n" -+" strb %0, [%1], #1 \n" -+" subs %3, %3, #2 \n" -+" bmi 2f \n" -+" ldr %0, [%2], #4 \n" -+" strb %0, [%1], #1 \n" -+" mov %0, %0, lsr #8 \n" -+" strb %0, [%1], #1 \n" -+" subs %3, %3, #2 \n" -+" bmi 2f \n" -+" ldr %0, [%2], #4 \n" -+" strb %0, [%1], #1 \n" -+" mov %0, %0, lsr #8 \n" -+" strb %0, [%1], #1 \n" -+" subs %3, %3, #2 \n" -+" bmi 2f \n" -+" ldr %0, [%2], #4 \n" -+" strb %0, [%1], #1 \n" -+" mov %0, %0, lsr #8 \n" -+" strb %0, [%1], #1 \n" -+" subs %3, %3, #2 \n" -+" bpl 1b \n" -+"2: adds %3, %3, #1 \n" -+" ldreqb %0, [%2] \n" -+" streqb %0, [%1] \n" - : "=&r" (used), "=&r" (data) - : "r" (addr), "r" (thislen), "1" (data)); - -diff -urN linux-2.4.26/drivers/acorn/net/ether3.c linux-2.4.26-vrs1/drivers/acorn/net/ether3.c ---- linux-2.4.26/drivers/acorn/net/ether3.c 2003-08-25 12:44:40.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/acorn/net/ether3.c 2004-01-14 21:32:24.000000000 +0000 -@@ -75,7 +75,7 @@ - #include "ether3.h" - - static unsigned int net_debug = NET_DEBUG; --static const card_ids __init ether3_cids[] = { -+static card_ids __initdata ether3_cids[] = { - { MANU_ANT2, PROD_ANT_ETHER3 }, - { MANU_ANT, PROD_ANT_ETHER3 }, - { MANU_ANT, PROD_ANT_ETHERB }, -diff -urN linux-2.4.26/drivers/acorn/net/etherh.c linux-2.4.26-vrs1/drivers/acorn/net/etherh.c ---- linux-2.4.26/drivers/acorn/net/etherh.c 2003-08-25 12:44:40.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/acorn/net/etherh.c 2004-01-14 21:32:24.000000000 +0000 -@@ -57,7 +57,7 @@ - - static unsigned int net_debug = NET_DEBUG; - --static const card_ids __init etherh_cids[] = { -+static card_ids __initdata etherh_cids[] = { - { MANU_ANT, PROD_ANT_ETHERM }, - { MANU_I3, PROD_I3_ETHERLAN500 }, - { MANU_I3, PROD_I3_ETHERLAN600 }, -diff -urN linux-2.4.26/drivers/acorn/scsi/cumana_1.c linux-2.4.26-vrs1/drivers/acorn/scsi/cumana_1.c ---- linux-2.4.26/drivers/acorn/scsi/cumana_1.c 2001-09-13 23:21:32.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/acorn/scsi/cumana_1.c 2004-03-07 11:05:38.000000000 +0000 -@@ -153,20 +153,20 @@ - ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0; - outb(0x00, instance->io_port - 577); - -- if (instance->irq != IRQ_NONE) -+ if (instance->irq != SCSI_IRQ_NONE) - if (request_irq(instance->irq, do_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; -+ instance->irq = SCSI_IRQ_NONE; - } - -- if (instance->irq == IRQ_NONE) { -+ if (instance->irq == SCSI_IRQ_NONE) { - printk("scsi%d: interrupts not enabled. for better interactive performance,\n", instance->host_no); - printk("scsi%d: please jumper the board for a free IRQ.\n", instance->host_no); - } - - printk("scsi%d: at port %lX irq", instance->host_no, instance->io_port); -- if (instance->irq == IRQ_NONE) -+ if (instance->irq == SCSI_IRQ_NONE) - printk ("s disabled"); - else - printk (" %d", instance->irq); -@@ -185,7 +185,7 @@ - { - int i; - -- if (shpnt->irq != IRQ_NONE) -+ if (shpnt->irq != SCSI_IRQ_NONE) - free_irq (shpnt->irq, NULL); - if (shpnt->io_port) - release_region (shpnt->io_port, shpnt->n_io_port); -diff -urN linux-2.4.26/drivers/acorn/scsi/ecoscsi.c linux-2.4.26-vrs1/drivers/acorn/scsi/ecoscsi.c ---- linux-2.4.26/drivers/acorn/scsi/ecoscsi.c 2002-08-03 01:39:43.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/acorn/scsi/ecoscsi.c 2004-03-07 11:06:45.000000000 +0000 -@@ -106,7 +106,7 @@ - instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - instance->io_port = 0x80ce8000; - instance->n_io_port = 144; -- instance->irq = IRQ_NONE; -+ instance->irq = SCSI_IRQ_NONE; - - if (check_region (instance->io_port, instance->n_io_port)) { - scsi_unregister (instance); -@@ -130,20 +130,20 @@ - return 0; - } - -- if (instance->irq != IRQ_NONE) -+ if (instance->irq != SCSI_IRQ_NONE) - if (request_irq(instance->irq, do_ecoscsi_intr, SA_INTERRUPT, "ecoscsi", NULL)) { - printk("scsi%d: IRQ%d not free, interrupts disabled\n", - instance->host_no, instance->irq); -- instance->irq = IRQ_NONE; -+ instance->irq = SCSI_IRQ_NONE; - } - -- if (instance->irq != IRQ_NONE) { -+ if (instance->irq != SCSI_IRQ_NONE) { - printk("scsi%d: eek! Interrupts enabled, but I don't think\n", instance->host_no); - printk("scsi%d: that the board had an interrupt!\n", instance->host_no); - } - - printk("scsi%d: at port %X irq", instance->host_no, instance->io_port); -- if (instance->irq == IRQ_NONE) -+ if (instance->irq == SCSI_IRQ_NONE) - printk ("s disabled"); - else - printk (" %d", instance->irq); -@@ -157,7 +157,7 @@ - - int ecoscsi_release (struct Scsi_Host *shpnt) - { -- if (shpnt->irq != IRQ_NONE) -+ if (shpnt->irq != SCSI_IRQ_NONE) - free_irq (shpnt->irq, NULL); - if (shpnt->io_port) - release_region (shpnt->io_port, shpnt->n_io_port); -diff -urN linux-2.4.26/drivers/acorn/scsi/oak.c linux-2.4.26-vrs1/drivers/acorn/scsi/oak.c ---- linux-2.4.26/drivers/acorn/scsi/oak.c 2001-10-11 17:04:57.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/acorn/scsi/oak.c 2004-03-07 11:05:55.000000000 +0000 -@@ -97,7 +97,7 @@ - }; - - #define OAK_ADDRESS(card) (ecard_address((card), ECARD_MEMC, 0)) --#define OAK_IRQ(card) (IRQ_NONE) -+#define OAK_IRQ(card) (SCSI_IRQ_NONE) - /* - * Function : int oakscsi_detect(Scsi_Host_Template * tpnt) - * -@@ -136,20 +136,20 @@ - instance->n_io_port = 255; - request_region (instance->io_port, instance->n_io_port, "Oak SCSI"); - -- if (instance->irq != IRQ_NONE) -+ if (instance->irq != SCSI_IRQ_NONE) - if (request_irq(instance->irq, do_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; -+ instance->irq = SCSI_IRQ_NONE; - } - -- if (instance->irq != IRQ_NONE) { -+ if (instance->irq != SCSI_IRQ_NONE) { - printk("scsi%d: eek! Interrupts enabled, but I don't think\n", instance->host_no); - printk("scsi%d: that the board had an interrupt!\n", instance->host_no); - } - - printk("scsi%d: at port %lX irq", instance->host_no, instance->io_port); -- if (instance->irq == IRQ_NONE) -+ if (instance->irq == SCSI_IRQ_NONE) - printk ("s disabled"); - else - printk (" %d", instance->irq); -@@ -172,7 +172,7 @@ - { - int i; - -- if (shpnt->irq != IRQ_NONE) -+ if (shpnt->irq != SCSI_IRQ_NONE) - free_irq (shpnt->irq, NULL); - if (shpnt->io_port) - release_region (shpnt->io_port, shpnt->n_io_port); -diff -urN linux-2.4.26/drivers/at91/Makefile linux-2.4.26-vrs1/drivers/at91/Makefile ---- linux-2.4.26/drivers/at91/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/Makefile 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,23 @@ -+# -+# Makefile for the AT91RM9200-specific Linux kernel device drivers. -+# -+# Note! Dependencies are done automagically by 'make dep', which also -+# removes any old dependencies. DON'T put your own dependencies here -+# unless it's something special (not a .c file). -+ -+O_TARGET := at91drv.o -+ -+subdir-y := serial net watchdog rtc usb i2c spi mtd -+subdir-m := $(subdir-y) -+ -+obj-$(CONFIG_SERIAL_AT91) += serial/at91serial.o -+obj-$(CONFIG_AT91_ETHER) += net/at91net.o -+obj-$(CONFIG_AT91_WATCHDOG) += watchdog/at91wdt.o -+obj-$(CONFIG_AT91_RTC) += rtc/at91rtc.o -+obj-$(CONFIG_USB) += usb/at91usb.o -+obj-$(CONFIG_I2C_AT91) += i2c/at91i2c.o -+obj-$(CONFIG_AT91_SPIDEV) += spi/at91spi.o -+obj-$(CONFIG_MTD_AT91_DATAFLASH) += spi/at91spi.o mtd/at91mtd.o -+obj-$(CONFIG_MTD_AT91_SMARTMEDIA) += mtd/at91mtd.o -+ -+include $(TOPDIR)/Rules.make -diff -urN linux-2.4.26/drivers/at91/i2c/Makefile linux-2.4.26-vrs1/drivers/at91/i2c/Makefile ---- linux-2.4.26/drivers/at91/i2c/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/i2c/Makefile 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,15 @@ -+# File: drivers/at91/i2c/Makefile -+# -+# Makefile for the Atmel AT91RM9200 I2C (TWI) device drivers -+# -+ -+O_TARGET := at91i2c.o -+ -+obj-y := -+obj-m := -+obj-n := -+obj- := -+ -+obj-$(CONFIG_I2C_AT91) += at91_i2c.o -+ -+include $(TOPDIR)/Rules.make -diff -urN linux-2.4.26/drivers/at91/i2c/at91_i2c.c linux-2.4.26-vrs1/drivers/at91/i2c/at91_i2c.c ---- linux-2.4.26/drivers/at91/i2c/at91_i2c.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/i2c/at91_i2c.c 2004-03-07 15:59:15.000000000 +0000 -@@ -0,0 +1,257 @@ -+/* -+ i2c Support for Atmel's AT91RM9200 Two-Wire Interface -+ -+ (c) Rick Bronson -+ -+ Borrowed heavily from original work by: -+ Copyright (c) 2000 Philip Edelbrock -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ -+*/ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include "at91_i2c.h" -+ -+#define DBG(x...) do {\ -+ if (debug > 0) \ -+ printk(KERN_DEBUG "i2c:" x); \ -+ } while(0) -+ -+int debug = 0; -+ -+static struct at91_i2c_local *at91_i2c_device; -+ -+/* -+ * Poll the i2c status register until the specified bit is set. -+ * Returns 0 if timed out (100 msec) -+ */ -+static short at91_poll_status(AT91PS_TWI twi, unsigned long bit) { -+ int loop_cntr = 10000; -+ do { -+ udelay(10); -+ } while (!(twi->TWI_SR & bit) && (--loop_cntr > 0)); -+ -+ return (loop_cntr > 0); -+} -+ -+/* -+ * Generic i2c master transfer entrypoint -+ */ -+static int at91_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) -+{ -+ struct at91_i2c_local *device = (struct at91_i2c_local *) adap->data; -+ AT91PS_TWI twi = (AT91PS_TWI) device->base_addr; -+ -+ struct i2c_msg *pmsg; -+ int length; -+ unsigned char *buf; -+ -+ /* -+ * i2c_smbus_xfer_emulated() in drivers/i2c/i2c-core.c states: -+ * "... In the case of writing, we need to use only one message; -+ * when reading, we need two..." -+ */ -+ -+ pmsg = msgs; /* look at 1st message, it contains the address/command */ -+ if (num >= 1 && num <= 2) { -+ DBG("xfer: doing %s %d bytes to 0x%02x - %d messages\n", -+ pmsg->flags & I2C_M_RD ? "read" : "write", -+ pmsg->len, pmsg->buf[0], num); -+ -+ /* Set the TWI Master Mode Register */ -+ twi->TWI_MMR = (pmsg->addr << 16) | (pmsg->len << 8) -+ | ((pmsg + 1)->flags & I2C_M_RD ? AT91C_TWI_MREAD : 0); -+ -+ /* Set TWI Internal Address Register with first messages data field */ -+ if (pmsg->len == 1) -+ twi->TWI_IADR = pmsg->buf[0]; -+ else if (pmsg->len == 2) -+ twi->TWI_IADR = pmsg->buf[0] << 8 | pmsg->buf[1]; -+ else /* must be 3 */ -+ twi->TWI_IADR = pmsg->buf[0] << 16 | pmsg->buf[1] << 8 | pmsg->buf[2]; -+ -+ /* 1st message contains the address/command */ -+ if (num > 1) -+ pmsg++; /* go to real message */ -+ -+ length = pmsg->len; -+ buf = pmsg->buf; -+ if (length && buf) { /* sanity check */ -+ if (pmsg->flags & I2C_M_RD) { -+ twi->TWI_CR = AT91C_TWI_START; -+ while (length--) { -+ if (!length) -+ twi->TWI_CR = AT91C_TWI_STOP; -+ /* Wait until transfer is finished */ -+ if (!at91_poll_status(twi, AT91C_TWI_RXRDY)) { -+ printk(KERN_ERR "at91_i2c: timeout 1\n"); -+ return 0; -+ } -+ *buf++ = twi->TWI_RHR; -+ } -+ if (!at91_poll_status(twi, AT91C_TWI_TXCOMP)) { -+ printk(KERN_ERR "at91_i2c: timeout 2\n"); -+ return 0; -+ } -+ } else { -+ twi->TWI_CR = AT91C_TWI_START; -+ while (length--) { -+ twi->TWI_THR = *buf++; -+ if (!length) -+ twi->TWI_CR = AT91C_TWI_STOP; -+ if (!at91_poll_status(twi, AT91C_TWI_TXRDY)) { -+ printk(KERN_ERR "at91_i2c: timeout 3\n"); -+ return 0; -+ } -+ } -+ /* Wait until transfer is finished */ -+ if (!at91_poll_status(twi, AT91C_TWI_TXCOMP)) { -+ printk(KERN_ERR "at91_i2c: timeout 4\n"); -+ return 0; -+ } -+ } -+ } -+ DBG("transfer complete\n"); -+ return num; -+ } -+ else { -+ printk(KERN_ERR "at91_i2c: unexpected number of messages: %d\n", num); -+ return 0; -+ } -+} -+ -+/* -+ * Return list of supported functionality -+ */ -+static u32 at91_func(struct i2c_adapter *adapter) -+{ -+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE -+ | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA -+ | I2C_FUNC_SMBUS_BLOCK_DATA; -+} -+ -+/* -+ * Open -+ */ -+static void at91_inc(struct i2c_adapter *adapter) -+{ -+ MOD_INC_USE_COUNT; -+} -+ -+/* -+ * Close -+ */ -+static void at91_dec(struct i2c_adapter *adapter) -+{ -+ MOD_DEC_USE_COUNT; -+} -+ -+/* For now, we only handle combined mode (smbus) */ -+static struct i2c_algorithm at91_algorithm = { -+ name:"at91 i2c", -+ id:I2C_ALGO_SMBUS, -+ master_xfer:at91_xfer, -+ functionality:at91_func, -+}; -+ -+/* -+ * Main initialization routine -+ */ -+static int __init i2c_at91_init(void) -+{ -+ AT91PS_TWI twi = (AT91PS_TWI) AT91C_VA_BASE_TWI; -+ struct at91_i2c_local *device; -+ int rc; -+ -+ AT91_CfgPIO_TWI(); -+ AT91_SYS->PMC_PCER = 1 << AT91C_ID_TWI; /* enable peripheral clock */ -+ -+ twi->TWI_IDR = 0x3ff; /* Disable all interrupts */ -+ twi->TWI_CR = AT91C_TWI_SWRST; /* Reset peripheral */ -+ twi->TWI_CR = AT91C_TWI_MSEN | AT91C_TWI_SVDIS; /* Set Master mode */ -+ -+ /* Here, CKDIV = 1 and CHDIV=CLDIV ==> CLDIV = CHDIV = 1/4*((Fmclk/FTWI) -6) */ -+ twi->TWI_CWGR = AT91C_TWI_CKDIV1 | AT91C_TWI_CLDIV3 | (AT91C_TWI_CLDIV3 << 8); -+ -+ device = (struct at91_i2c_local *) kmalloc(sizeof(struct at91_i2c_local), GFP_KERNEL); -+ if (device == NULL) { -+ printk(KERN_ERR "at91_i2c: can't allocate inteface!\n"); -+ return -ENOMEM; -+ } -+ memset(device, 0, sizeof(struct at91_i2c_local)); -+ at91_i2c_device = device; -+ -+ sprintf(device->adapter.name, "AT91RM9200"); -+ device->adapter.data = (void *) device; -+ device->adapter.id = I2C_ALGO_SMBUS; -+ device->adapter.algo = &at91_algorithm; -+ device->adapter.algo_data = NULL; -+ device->adapter.inc_use = at91_inc; -+ device->adapter.dec_use = at91_dec; -+ device->adapter.client_register = NULL; -+ device->adapter.client_unregister = NULL; -+ device->base_addr = AT91C_VA_BASE_TWI; -+ -+ rc = i2c_add_adapter(&device->adapter); -+ if (rc) { -+ printk(KERN_ERR "at91_i2c: Adapter %s registration failed\n", device->adapter.name); -+ device->adapter.data = NULL; -+ kfree(device); -+ } -+ else -+ printk(KERN_INFO "Found AT91 i2c\n"); -+ return rc; -+} -+ -+/* -+ * Clean up routine -+ */ -+static void __exit i2c_at91_cleanup(void) -+{ -+ struct at91_i2c_local *device = at91_i2c_device; -+ int rc; -+ -+ rc = i2c_del_adapter(&device->adapter); -+ device->adapter.data = NULL; -+ kfree(device); -+ -+ AT91_SYS->PMC_PCDR = 1 << AT91C_ID_TWI; /* disable peripheral clock */ -+ -+ /* We aren't that prepared to deal with this... */ -+ if (rc) -+ printk(KERN_ERR "at91_i2c: i2c_del_adapter failed (%i), that's bad!\n", rc); -+} -+ -+module_init(i2c_at91_init); -+module_exit(i2c_at91_cleanup); -+ -+MODULE_AUTHOR("Rick Bronson"); -+MODULE_DESCRIPTION("I2C driver for Atmel AT91RM9200"); -+MODULE_LICENSE("GPL"); -+MODULE_PARM(debug, "i"); -+ -+EXPORT_NO_SYMBOLS; -diff -urN linux-2.4.26/drivers/at91/i2c/at91_i2c.h linux-2.4.26-vrs1/drivers/at91/i2c/at91_i2c.h ---- linux-2.4.26/drivers/at91/i2c/at91_i2c.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/i2c/at91_i2c.h 2004-03-07 15:59:15.000000000 +0000 -@@ -0,0 +1,43 @@ -+/* -+ i2c Support for Atmel's AT91RM9200 Two-Wire Interface -+ -+ (c) Rick Bronson -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+*/ -+ -+#ifndef AT91_I2C_H -+#define AT91_I2C_H -+ -+#define AT91C_TWI_CLOCK 100000 -+#define AT91C_TWI_SCLOCK (10 * AT91C_MASTER_CLOCK / AT91C_TWI_CLOCK) -+#define AT91C_TWI_CKDIV1 (2 << 16) /* TWI clock divider. NOTE: see Errata #22 */ -+ -+#if (AT91C_TWI_SCLOCK % 10) >= 5 -+#define AT91C_TWI_CLDIV2 ((AT91C_TWI_SCLOCK / 10) - 5) -+#else -+#define AT91C_TWI_CLDIV2 ((AT91C_TWI_SCLOCK / 10) - 6) -+#endif -+#define AT91C_TWI_CLDIV3 ((AT91C_TWI_CLDIV2 + (4 - AT91C_TWI_CLDIV2 % 4)) >> 2) -+ -+#define AT91C_EEPROM_I2C_ADDRESS (0x50 << 16) -+ -+/* Physical interface */ -+struct at91_i2c_local { -+ struct i2c_adapter adapter; -+ unsigned long base_addr; -+}; -+ -+#endif -diff -urN linux-2.4.26/drivers/at91/mtd/Makefile linux-2.4.26-vrs1/drivers/at91/mtd/Makefile ---- linux-2.4.26/drivers/at91/mtd/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/mtd/Makefile 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,19 @@ -+# File: drivers/at91/mtd/Makefile -+# -+# Makefile for the Atmel AT91RM9200 MTD devices. -+# Includes: NAND flash (SmartMedia) & DataFlash -+# -+ -+O_TARGET := at91mtd.o -+ -+export-objs := -+ -+obj-y := -+obj-m := -+obj-n := -+obj- := -+ -+obj-$(CONFIG_MTD_AT91_DATAFLASH) += at91_dataflash.o -+obj-$(CONFIG_MTD_AT91_SMARTMEDIA) += at91_nand.o -+ -+include $(TOPDIR)/Rules.make -diff -urN linux-2.4.26/drivers/at91/mtd/at91_dataflash.c linux-2.4.26-vrs1/drivers/at91/mtd/at91_dataflash.c ---- linux-2.4.26/drivers/at91/mtd/at91_dataflash.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/mtd/at91_dataflash.c 2004-04-10 12:48:53.000000000 +0100 -@@ -0,0 +1,509 @@ -+/* -+ * Atmel DataFlash driver for Atmel AT91RM9200 (Thunder) -+ * -+ * (c) SAN People (Pty) Ltd -+ * -+ * 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. -+*/ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include "at91_dataflash.h" -+#include "../spi/at91_spi.h" -+ -+#undef DEBUG_DATAFLASH -+ -+/* Detected DataFlash devices */ -+static struct mtd_info* mtd_devices[DATAFLASH_MAX_DEVICES]; -+static int nr_devices = 0; -+ -+/* ......................................................................... */ -+ -+#ifdef CONFIG_MTD_PARTITIONS -+ -+static struct mtd_partition *mtd_parts = 0; -+static int mtd_parts_nr = 0; -+ -+#define NB_OF(x) (sizeof(x)/sizeof(x[0])) -+ -+static struct mtd_partition static_partitions[] = -+{ -+ { -+ name: "bootloader", -+ offset: 0, -+ size: 64 * 1024, /* 64 Kb */ -+ mask_flags: MTD_WRITEABLE /* read-only */ -+ }, -+ { -+ name: "kernel", -+ offset: MTDPART_OFS_NXTBLK, -+ size: 768 *1024, /* 768 Kb */ -+ }, -+ { -+ name: "filesystem", -+ offset: MTDPART_OFS_NXTBLK, -+ size: MTDPART_SIZ_FULL, -+ } -+}; -+ -+int parse_cmdline_partitions(struct mtd_info *master, -+ struct mtd_partition **pparts, const char *mtd_id); -+ -+#endif -+ -+/* ......................................................................... */ -+ -+/* Allocate a single SPI transfer descriptor. We're assuming that if multiple -+ SPI transfers occur at the same time, spi_access_bus() will serialize them. -+ If this is not valid, then either (i) each dataflash 'priv' structure -+ needs it's own transfer descriptor, (ii) we lock this one, or (iii) use -+ another mechanism. */ -+struct spi_transfer_list* spi_transfer_desc; -+ -+/* -+ * Perform a SPI transfer to access the DataFlash device. -+ */ -+int do_spi_transfer(int nr, char* tx, int tx_len, char* rx, int rx_len, -+ char* txnext, int txnext_len, char* rxnext, int rxnext_len) -+{ -+ struct spi_transfer_list* list = spi_transfer_desc; -+ -+ list->tx[0] = tx; list->txlen[0] = tx_len; -+ list->rx[0] = rx; list->rxlen[0] = rx_len; -+ -+ list->tx[1] = txnext; list->txlen[1] = txnext_len; -+ list->rx[1] = rxnext; list->rxlen[1] = rxnext_len; -+ -+ list->nr_transfers = nr; -+ -+ return spi_transfer(list); -+} -+ -+/* ......................................................................... */ -+ -+/* -+ * Poll the DataFlash device until it is READY. -+ */ -+void at91_dataflash_waitready(void) -+{ -+ char* command = kmalloc(2, GFP_KERNEL); -+ -+ if (!command) -+ return; -+ -+ do { -+ command[0] = OP_READ_STATUS; -+ command[1] = 0; -+ -+ do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0); -+ } while ((command[1] & 0x80) == 0); -+ -+ kfree(command); -+} -+ -+/* -+ * Return the status of the DataFlash device. -+ */ -+unsigned short at91_dataflash_status(void) -+{ -+ unsigned short status; -+ char* command = kmalloc(2, GFP_KERNEL); -+ -+ if (!command) -+ return 0; -+ -+ command[0] = OP_READ_STATUS; -+ command[1] = 0; -+ -+ do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0); -+ status = command[1]; -+ -+ kfree(command); -+ return status; -+} -+ -+/* ......................................................................... */ -+ -+/* -+ * Erase blocks of flash. -+ */ -+int at91_dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) -+{ -+ struct dataflash_local *priv = (struct dataflash_local *) mtd->priv; -+ unsigned int pageaddr; -+ char* command; -+ -+#ifdef DEBUG_DATAFLASH -+ printk("dataflash_erase: addr=%i len=%i\n", instr->addr, instr->len); -+#endif -+ -+ /* Sanity checks */ -+ if (instr->addr + instr->len > mtd->size) -+ return -EINVAL; -+ if ((instr->len % mtd->erasesize != 0) || (instr->len % priv->page_size != 0)) -+ return -EINVAL; -+ if ((instr->addr % priv->page_size) != 0) -+ return -EINVAL; -+ -+ command = kmalloc(4, GFP_KERNEL); -+ if (!command) -+ return -ENOMEM; -+ -+ while (instr->len > 0) { -+ /* Calculate flash page address */ -+ pageaddr = (instr->addr / priv->page_size) << priv->page_offset; -+ -+ command[0] = OP_ERASE_PAGE; -+ command[1] = (pageaddr & 0x00FF0000) >> 16; -+ command[2] = (pageaddr & 0x0000FF00) >> 8; -+ command[3] = 0; -+#ifdef DEBUG_DATAFLASH -+ printk("ERASE: (%x) %x %x %x [%i]\n", command[0], command[1], command[2], command[3], pageaddr); -+#endif -+ -+ /* Send command to SPI device */ -+ spi_access_bus(priv->spi); -+ do_spi_transfer(1, command, 4, command, 4, NULL, 0, NULL, 0); -+ -+ at91_dataflash_waitready(); /* poll status until ready */ -+ spi_release_bus(priv->spi); -+ -+ instr->addr += priv->page_size; /* next page */ -+ instr->len -= priv->page_size; -+ } -+ -+ kfree(command); -+ -+ /* Inform MTD subsystem that erase is complete */ -+ instr->state = MTD_ERASE_DONE; -+ if (instr->callback) -+ instr->callback(instr); -+ -+ return 0; -+} -+ -+/* -+ * Read from the DataFlash device. -+ * from : Start offset in flash device -+ * len : Amount to read -+ * retlen : About of data actually read -+ * buf : Buffer containing the data -+ */ -+int at91_dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) -+{ -+ struct dataflash_local *priv = (struct dataflash_local *) mtd->priv; -+ unsigned int addr; -+ char* command; -+ -+#ifdef DEBUG_DATAFLASH -+ printk("dataflash_read: %lli .. %lli\n", from, from+len); -+#endif -+ -+ *retlen = 0; -+ -+ /* Sanity checks */ -+ if (!len) -+ return 0; -+ if (from + len > mtd->size) -+ return -EINVAL; -+ -+ /* Calculate flash page/byte address */ -+ addr = (((unsigned)from / priv->page_size) << priv->page_offset) + ((unsigned)from % priv->page_size); -+ -+ command = kmalloc(8, GFP_KERNEL); -+ if (!command) -+ return -ENOMEM; -+ -+ command[0] = OP_READ_CONTINUOUS; -+ command[1] = (addr & 0x00FF0000) >> 16; -+ command[2] = (addr & 0x0000FF00) >> 8; -+ command[3] = (addr & 0x000000FF); -+#ifdef DEBUG_DATAFLASH -+ printk("READ: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); -+#endif -+ -+ /* Send command to SPI device */ -+ spi_access_bus(priv->spi); -+ do_spi_transfer(2, command, 8, command, 8, buf, len, buf, len); -+ spi_release_bus(priv->spi); -+ -+ *retlen = len; -+ kfree(command); -+ return 0; -+} -+ -+/* -+ * Write to the DataFlash device. -+ * to : Start offset in flash device -+ * len : Amount to write -+ * retlen : Amount of data actually written -+ * buf : Buffer containing the data -+ */ -+int at91_dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) -+{ -+ struct dataflash_local *priv = (struct dataflash_local *) mtd->priv; -+ unsigned int pageaddr, addr, offset, writelen; -+ size_t remaining; -+ u_char *writebuf; -+ unsigned short status; -+ int res = 0; -+ char* command; -+ char* tmpbuf = NULL; -+ -+#ifdef DEBUG_DATAFLASH -+ printk("dataflash_write: %lli .. %lli\n", to, to+len); -+#endif -+ -+ *retlen = 0; -+ -+ /* Sanity checks */ -+ if (!len) -+ return 0; -+ if (to + len > mtd->size) -+ return -EINVAL; -+ -+ command = kmalloc(4, GFP_KERNEL); -+ if (!command) -+ return -ENOMEM; -+ -+ pageaddr = ((unsigned)to / priv->page_size); -+ offset = ((unsigned)to % priv->page_size); -+ if (offset + len > priv->page_size) -+ writelen = priv->page_size - offset; -+ else -+ writelen = len; -+ writebuf = buf; -+ remaining = len; -+ -+ /* Allocate temporary buffer */ -+ tmpbuf = kmalloc(priv->page_size, GFP_KERNEL); -+ if (!tmpbuf) { -+ kfree(command); -+ return -ENOMEM; -+ } -+ -+ /* Gain access to the SPI bus */ -+ spi_access_bus(priv->spi); -+ -+ while (remaining > 0) { -+#ifdef DEBUG_DATAFLASH -+ printk("write @ %i:%i len=%i\n", pageaddr, offset, writelen); -+#endif -+ -+ /* (1) Transfer to Buffer1 */ -+ if (writelen != priv->page_size) { -+ addr = pageaddr << priv->page_offset; -+ command[0] = OP_TRANSFER_BUF1; -+ command[1] = (addr & 0x00FF0000) >> 16; -+ command[2] = (addr & 0x0000FF00) >> 8; -+ command[3] = 0; -+#ifdef DEBUG_DATAFLASH -+ printk("TRANSFER: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); -+#endif -+ do_spi_transfer(1, command, 4, command, 4, NULL, 0, NULL, 0); -+ at91_dataflash_waitready(); -+ } -+ -+ /* (2) Program via Buffer1 */ -+ addr = (pageaddr << priv->page_offset) + offset; -+ command[0] = OP_PROGRAM_VIA_BUF1; -+ command[1] = (addr & 0x00FF0000) >> 16; -+ command[2] = (addr & 0x0000FF00) >> 8; -+ command[3] = (addr & 0x000000FF); -+#ifdef DEBUG_DATAFLASH -+ printk("PROGRAM: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); -+#endif -+ do_spi_transfer(2, command, 4, command, 4, writebuf, writelen, tmpbuf, writelen); -+ at91_dataflash_waitready(); -+ -+ /* (3) Compare to Buffer1 */ -+ addr = pageaddr << priv->page_offset; -+ command[0] = OP_COMPARE_BUF1; -+ command[1] = (addr & 0x00FF0000) >> 16; -+ command[2] = (addr & 0x0000FF00) >> 8; -+ command[3] = 0; -+#ifdef DEBUG_DATAFLASH -+ printk("COMPARE: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); -+#endif -+ do_spi_transfer(1, command, 4, command, 4, NULL, 0, NULL, 0); -+ at91_dataflash_waitready(); -+ -+ /* Get result of the compare operation */ -+ status = at91_dataflash_status(); -+ if ((status & 0x40) == 1) { -+ printk("at91_dataflash: Write error on page %i\n", pageaddr); -+ remaining = 0; -+ res = -EIO; -+ } -+ -+ remaining = remaining - writelen; -+ pageaddr++; -+ offset = 0; -+ writebuf += writelen; -+ *retlen += writelen; -+ -+ if (remaining > priv->page_size) -+ writelen = priv->page_size; -+ else -+ writelen = remaining; -+ } -+ -+ /* Release SPI bus */ -+ spi_release_bus(priv->spi); -+ -+ kfree(tmpbuf); -+ kfree(command); -+ return res; -+} -+ -+/* ......................................................................... */ -+ -+/* -+ * Initialize and register DataFlash device with MTD subsystem. -+ */ -+int add_dataflash(int channel, char *name, int size, int pagesize, int pageoffset) -+{ -+ struct mtd_info *device; -+ struct dataflash_local *priv; -+#ifdef CONFIG_MTD_CMDLINE_PARTS -+ char mtdID[14]; -+#endif -+ -+ if (nr_devices >= DATAFLASH_MAX_DEVICES) { -+ printk(KERN_ERR "at91_dataflash: Too many devices detected\n"); -+ return 0; -+ } -+ -+ device = (struct mtd_info *) kmalloc(sizeof(struct mtd_info), GFP_KERNEL); -+ if (!device) -+ return -ENOMEM; -+ memset(device, 0, sizeof(struct mtd_info)); -+ -+ device->name = name; -+ device->size = size; -+ device->erasesize = pagesize; -+ device->module = THIS_MODULE; -+ device->type = MTD_NORFLASH; -+ device->flags = MTD_CAP_NORFLASH; -+ device->erase = at91_dataflash_erase; -+ device->read = at91_dataflash_read; -+ device->write = at91_dataflash_write; -+ -+ priv = (struct dataflash_local *) kmalloc(sizeof(struct dataflash_local), GFP_KERNEL); -+ if (!priv) { -+ kfree(device); -+ return -ENOMEM; -+ } -+ memset(priv, 0, sizeof(struct dataflash_local)); -+ -+ priv->spi = channel; -+ priv->page_size = pagesize; -+ priv->page_offset = pageoffset; -+ device->priv = priv; -+ -+ mtd_devices[nr_devices] = device; -+ nr_devices++; -+ printk("at91_dataflash: %s detected [spi%i] (%i bytes)\n", name, channel, size); -+ -+#ifdef CONFIG_MTD_PARTITIONS -+#ifdef CONFIG_MTD_CMDLINE_PARTS -+ sprintf(mtdID, "dataflash%i", nr_devices-1); -+ mtd_parts_nr = parse_cmdline_partitions(device, &mtd_parts, mtdID); -+#endif -+ if (mtd_parts_nr <= 0) { -+ mtd_parts = static_partitions; -+ mtd_parts_nr = NB_OF(static_partitions); -+ } -+ -+ return add_mtd_partitions(device, mtd_parts, mtd_parts_nr); -+#else -+ return add_mtd_device(device); -+#endif -+} -+ -+/* -+ * Detect and initialize DataFlash device connected to specified SPI channel. -+ */ -+int at91_dataflash_detect(int channel) -+{ -+ int res = 0; -+ unsigned short status; -+ -+ spi_access_bus(channel); -+ status = at91_dataflash_status(); -+ if (status != 0xff) { /* no dataflash device there */ -+ switch (status & 0x3c) { -+ case 0x2c: /* 1 0 1 1 */ -+ res = add_dataflash(channel, "Atmel AT45DB161B", 4096*528, 528, 10); -+ break; -+ case 0x34: /* 1 1 0 1 */ -+ res = add_dataflash(channel, "Atmel AT45DB321B", 8192*528, 528, 10); -+ break; -+ case 0x3c: /* 1 1 1 1 */ -+ res = add_dataflash(channel, "Atmel AT45DB642", 8192*1056, 1056, 11); -+ break; -+ default: -+ printk(KERN_ERR "at91_dataflash: Unknown device (%x)\n", status & 0x3c); -+ } -+ } -+ spi_release_bus(channel); -+ -+ return res; -+} -+ -+int __init at91_dataflash_init(void) -+{ -+ spi_transfer_desc = kmalloc(sizeof(struct spi_transfer_list), GFP_KERNEL); -+ if (!spi_transfer_desc) -+ return -ENOMEM; -+ -+ /* DataFlash (SPI chip select 0) */ -+ at91_dataflash_detect(0); -+ -+#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD -+ /* DataFlash card (SPI chip select 3) */ -+ AT91_CfgPIO_DataFlashCard(); -+ at91_dataflash_detect(3); -+#endif -+ -+ return 0; -+} -+ -+void __exit at91_dataflash_exit(void) -+{ -+ int i; -+ -+ for (i = 0; i < DATAFLASH_MAX_DEVICES; i++) { -+ if (mtd_devices[i]) { -+#ifdef CONFIG_MTD_PARTITIONS -+ del_mtd_partitions(mtd_devices[i]); -+#else -+ del_mtd_device(mtd_devices[i]); -+#endif -+ kfree(mtd_devices[i]->priv); -+ kfree(mtd_devices[i]); -+ } -+ } -+ nr_devices = 0; -+ kfree(spi_transfer_desc); -+} -+ -+ -+EXPORT_NO_SYMBOLS; -+ -+module_init(at91_dataflash_init); -+module_exit(at91_dataflash_exit); -+ -+MODULE_LICENSE("GPL") -+MODULE_AUTHOR("Andrew Victor") -+MODULE_DESCRIPTION("DataFlash driver for Atmel AT91RM9200") -diff -urN linux-2.4.26/drivers/at91/mtd/at91_dataflash.h linux-2.4.26-vrs1/drivers/at91/mtd/at91_dataflash.h ---- linux-2.4.26/drivers/at91/mtd/at91_dataflash.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/mtd/at91_dataflash.h 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,42 @@ -+/* -+ * Atmel DataFlash driver for the Atmel AT91RM9200 (Thunder) -+ * -+ * (c) SAN People (Pty) Ltd -+ * -+ * 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. -+ */ -+ -+#ifndef AT91_DATAFLASH_H -+#define AT91_DATAFLASH_H -+ -+#define DATAFLASH_MAX_DEVICES 4 /* max number of dataflash devices */ -+ -+#define OP_READ_CONTINUOUS 0xE8 -+#define OP_READ_PAGE 0xD2 -+#define OP_READ_BUFFER1 0xD4 -+#define OP_READ_BUFFER2 0xD6 -+#define OP_READ_STATUS 0xD7 -+ -+#define OP_ERASE_PAGE 0x81 -+#define OP_ERASE_BLOCK 0x50 -+ -+#define OP_TRANSFER_BUF1 0x53 -+#define OP_TRANSFER_BUF2 0x55 -+#define OP_COMPARE_BUF1 0x60 -+#define OP_COMPARE_BUF2 0x61 -+ -+#define OP_PROGRAM_VIA_BUF1 0x82 -+#define OP_PROGRAM_VIA_BUF2 0x85 -+ -+struct dataflash_local -+{ -+ int spi; /* SPI chip-select number */ -+ -+ unsigned int page_size; /* number of bytes per page */ -+ unsigned short page_offset; /* page offset in flash address */ -+}; -+ -+#endif -diff -urN linux-2.4.26/drivers/at91/mtd/at91_nand.c linux-2.4.26-vrs1/drivers/at91/mtd/at91_nand.c ---- linux-2.4.26/drivers/at91/mtd/at91_nand.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/mtd/at91_nand.c 2004-03-04 22:11:35.000000000 +0000 -@@ -0,0 +1,328 @@ -+/* -+ * drivers/at91/mtd/at91_nand.c -+ * -+ * Copyright (c) 2003 Rick Bronson -+ * -+ * Derived from drivers/mtd/nand/autcpu12.c -+ * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) -+ * -+ * Derived from drivers/mtd/spia.c -+ * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "at91_nand.h" -+ -+/* -+ * MTD structure for AT91 board -+ */ -+static struct mtd_info *at91_mtd = NULL; -+static struct nand_chip *my_nand_chip = NULL; -+ -+static int at91_fio_base; -+ -+#ifdef CONFIG_MTD_PARTITIONS -+ -+/* -+ * Define partitions for flash devices -+ */ -+ -+static struct mtd_partition partition_info32k[] = { -+ { name: "AT91 NAND partition 1, kernel", -+ offset: 0, -+ size: 1 * SZ_1M }, -+ { name: "AT91 NAND partition 2, filesystem", -+ offset: 1 * SZ_1M, -+ size: 16 * SZ_1M }, -+ { name: "AT91 NAND partition 3a, storage", -+ offset: (1 * SZ_1M) + (16 * SZ_1M), -+ size: 1 * SZ_1M }, -+ { name: "AT91 NAND partition 3b, storage", -+ offset: (2 * SZ_1M) + (16 * SZ_1M), -+ size: 1 * SZ_1M }, -+ { name: "AT91 NAND partition 3c, storage", -+ offset: (3 * SZ_1M) + (16 * SZ_1M), -+ size: 1 * SZ_1M }, -+ { name: "AT91 NAND partition 3d, storage", -+ offset: (4 * SZ_1M) + (16 * SZ_1M), -+ size: 1 * SZ_1M }, -+}; -+ -+static struct mtd_partition partition_info64k[] = { -+ { name: "AT91 NAND partition 1, kernel", -+ offset: 0, -+ size: 1 * SZ_1M }, -+ { name: "AT91 NAND partition 2, filesystem", -+ offset: 1 * SZ_1M, -+ size: 16 * SZ_1M }, -+ { name: "AT91 NAND partition 3, storage", -+ offset: (1 * SZ_1M) + (16 * SZ_1M), -+ size: 47 * SZ_1M }, -+}; -+ -+#endif -+ -+/* -+ * Hardware specific access to control-lines -+ */ -+static void at91_hwcontrol(int cmd) -+{ -+ struct nand_chip *my_nand = my_nand_chip; -+ switch(cmd) -+ { -+ case NAND_CTL_SETCLE: -+ my_nand->IO_ADDR_W = at91_fio_base + AT91_SMART_MEDIA_CLE; -+ break; -+ case NAND_CTL_CLRCLE: -+ my_nand->IO_ADDR_W = at91_fio_base; -+ break; -+ case NAND_CTL_SETALE: -+ my_nand->IO_ADDR_W = at91_fio_base + AT91_SMART_MEDIA_ALE; -+ break; -+ case NAND_CTL_CLRALE: -+ my_nand->IO_ADDR_W = at91_fio_base; -+ break; -+ case NAND_CTL_SETNCE: -+ break; -+ case NAND_CTL_CLRNCE: -+ break; -+ } -+} -+ -+/* -+ * Send command to NAND device -+ */ -+static void at91_nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr) -+{ -+ register struct nand_chip *my_nand = mtd->priv; -+ -+ /* Begin command latch cycle */ -+ register unsigned long NAND_IO_ADDR = my_nand->IO_ADDR_W + AT91_SMART_MEDIA_CLE; -+ -+ /* -+ * Write out the command to the device. -+ */ -+ if (command != NAND_CMD_SEQIN) -+ writeb (command, NAND_IO_ADDR); -+ else { -+ if (mtd->oobblock == 256 && column >= 256) { -+ column -= 256; -+ writeb (NAND_CMD_RESET, NAND_IO_ADDR); -+ writeb (NAND_CMD_READOOB, NAND_IO_ADDR); -+ writeb (NAND_CMD_SEQIN, NAND_IO_ADDR); -+ } -+ else -+ if (mtd->oobblock == 512 && column >= 256) { -+ if (column < 512) { -+ column -= 256; -+ writeb (NAND_CMD_READ1, NAND_IO_ADDR); -+ writeb (NAND_CMD_SEQIN, NAND_IO_ADDR); -+ } else { -+ column -= 512; -+ writeb (NAND_CMD_READOOB, NAND_IO_ADDR); -+ writeb (NAND_CMD_SEQIN, NAND_IO_ADDR); -+ } -+ } else { -+ writeb (NAND_CMD_READ0, NAND_IO_ADDR); -+ writeb (NAND_CMD_SEQIN, NAND_IO_ADDR); -+ } -+ } -+ -+ /* Set ALE and clear CLE to start address cycle */ -+ NAND_IO_ADDR = at91_fio_base; -+ -+ if (column != -1 || page_addr != -1) -+ NAND_IO_ADDR += AT91_SMART_MEDIA_ALE; -+ -+ /* Serially input address */ -+ if (column != -1) -+ writeb (column, NAND_IO_ADDR); -+ if (page_addr != -1) { -+ writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR); -+ writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR); -+ /* One more address cycle for higher density devices */ -+ if (mtd->size & 0x0c000000) { -+ writeb ((unsigned char) ((page_addr >> 16) & 0x0f), NAND_IO_ADDR); -+ } -+ } -+ -+ /* wait until command is processed */ -+ while (!my_nand->dev_ready()) -+ ; -+} -+ -+/* -+ * Read the Device Ready pin. -+ */ -+static int at91_device_ready(void) -+{ -+ return AT91_PIO_SmartMedia_RDY(); -+} -+/* -+ * Main initialization routine -+ */ -+static int __init at91_init (void) -+{ -+ struct nand_chip *my_nand; -+ int err = 0; -+ -+ /* Allocate memory for MTD device structure and private data */ -+ at91_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL); -+ if (!at91_mtd) { -+ printk ("Unable to allocate AT91 NAND MTD device structure.\n"); -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ /* map physical adress */ -+ at91_fio_base = (unsigned long) ioremap(AT91_SMARTMEDIA_BASE, SZ_8M); -+ if(!at91_fio_base) { -+ printk("ioremap AT91 NAND failed\n"); -+ err = -EIO; -+ goto out_mtd; -+ } -+ -+ /* Get pointer to private data */ -+ my_nand_chip = my_nand = (struct nand_chip *) (&at91_mtd[1]); -+ -+ /* Initialize structures */ -+ memset((char *) at91_mtd, 0, sizeof(struct mtd_info)); -+ memset((char *) my_nand, 0, sizeof(struct nand_chip)); -+ -+ /* Link the private data with the MTD structure */ -+ at91_mtd->priv = my_nand; -+ -+ /* Set address of NAND IO lines */ -+ my_nand->IO_ADDR_R = at91_fio_base; -+ my_nand->IO_ADDR_W = at91_fio_base; -+ my_nand->hwcontrol = at91_hwcontrol; -+ my_nand->dev_ready = at91_device_ready; -+ my_nand->cmdfunc = at91_nand_command; /* we need our own */ -+ my_nand->eccmode = NAND_ECC_SOFT; /* enable ECC */ -+ /* 20 us command delay time */ -+ my_nand->chip_delay = 20; -+ -+ /* Setup Smart Media, first enable the address range of CS3 */ -+ AT91_SYS->EBI_CSA |= AT91C_EBI_CS3A_SMC_SmartMedia; -+ /* set the bus interface characteristics based on -+ tDS Data Set up Time 30 - ns -+ tDH Data Hold Time 20 - ns -+ tALS ALE Set up Time 20 - ns -+ 16ns at 60 MHz ~= 3 */ -+#define AT91C_SM_ID_RWH (5 << 28) /* orig = 5 */ -+#define AT91C_SM_RWH (1 << 28) /* orig = 1 */ -+#define AT91C_SM_RWS (0 << 24) /* orig = 0 */ -+#define AT91C_SM_TDF (1 << 8) /* orig = 1 */ -+#define AT91C_SM_NWS (5) /* orig = 3 */ -+ AT91_SYS->EBI_SMC2_CSR[3] = ( AT91C_SM_RWH | AT91C_SM_RWS | -+ AT91C_SMC2_ACSS_STANDARD | -+ AT91C_SMC2_DBW_8 | AT91C_SM_TDF | -+ AT91C_SMC2_WSEN | AT91C_SM_NWS); -+ -+ AT91_CfgPIO_SmartMedia(); -+ -+ if (AT91_PIO_SmartMedia_CardDetect()) -+ printk ("No "); -+ printk ("SmartMedia card inserted.\n"); -+ -+ /* Scan to find existance of the device */ -+ if (nand_scan (at91_mtd)) { -+ err = -ENXIO; -+ goto out_ior; -+ } -+ -+ /* Allocate memory for internal data buffer */ -+ my_nand->data_buf = kmalloc (sizeof(u_char) * (at91_mtd->oobblock + at91_mtd->oobsize), GFP_KERNEL); -+ if (!my_nand->data_buf) { -+ printk ("Unable to allocate AT91 NAND data buffer.\n"); -+ err = -ENOMEM; -+ goto out_ior; -+ } -+ -+ /* Allocate memory for internal data buffer */ -+ my_nand->data_cache = kmalloc (sizeof(u_char) * (at91_mtd->oobblock + at91_mtd->oobsize), GFP_KERNEL); -+ if (!my_nand->data_cache) { -+ printk ("Unable to allocate AT91 NAND data cache.\n"); -+ err = -ENOMEM; -+ goto out_buf; -+ } -+ my_nand->cache_page = -1; -+ -+#ifdef CONFIG_MTD_PARTITIONS -+ /* Register the partitions */ -+ switch(at91_mtd->size) -+ { -+ case SZ_32M: -+ err = add_mtd_partitions(at91_mtd, partition_info32k, -+ ARRAY_SIZE (partition_info32k)); -+ break; -+ case SZ_64M: -+ err = add_mtd_partitions(at91_mtd, partition_info64k, -+ ARRAY_SIZE (partition_info64k)); -+ break; -+ default: -+ printk ("Unsupported SmartMedia device\n"); -+ err = -ENXIO; -+ goto out_cac; -+ } -+#else -+ err = add_mtd_device(at91_mtd); -+#endif -+ goto out; -+ -+ out_cac: -+ kfree (my_nand->data_cache); -+ out_buf: -+ kfree (my_nand->data_buf); -+ out_ior: -+ iounmap((void *)at91_fio_base); -+ out_mtd: -+ kfree (at91_mtd); -+ out: -+ return err; -+} -+ -+/* -+ * Clean up routine -+ */ -+static void __exit at91_cleanup (void) -+{ -+ struct nand_chip *my_nand = (struct nand_chip *) &at91_mtd[1]; -+ -+ /* Unregister partitions */ -+ del_mtd_partitions(at91_mtd); -+ -+ /* Unregister the device */ -+ del_mtd_device (at91_mtd); -+ -+ /* Free internal data buffers */ -+ kfree (my_nand->data_buf); -+ kfree (my_nand->data_cache); -+ -+ /* unmap physical adress */ -+ iounmap((void *)at91_fio_base); -+ -+ /* Free the MTD device structure */ -+ kfree (at91_mtd); -+} -+ -+module_init(at91_init); -+module_exit(at91_cleanup); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Rick Bronson"); -+MODULE_DESCRIPTION("Glue layer for SmartMediaCard on ATMEL AT91RM9200"); -diff -urN linux-2.4.26/drivers/at91/mtd/at91_nand.h linux-2.4.26-vrs1/drivers/at91/mtd/at91_nand.h ---- linux-2.4.26/drivers/at91/mtd/at91_nand.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/mtd/at91_nand.h 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,27 @@ -+/* -+ * AT91RM9200 specific NAND (SmartMedia) defines -+ * -+ * (c) 2003 Rick Bronson -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#ifndef __AT91_NAND_H -+#define __AT91_NAND_H -+ -+#define AT91_SMART_MEDIA_ALE (1 << 22) /* our ALE is AD22 */ -+#define AT91_SMART_MEDIA_CLE (1 << 21) /* our CLE is AD21 */ -+ -+#endif -diff -urN linux-2.4.26/drivers/at91/net/Makefile linux-2.4.26-vrs1/drivers/at91/net/Makefile ---- linux-2.4.26/drivers/at91/net/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/net/Makefile 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,15 @@ -+# File: drivers/at91/net/Makefile -+# -+# Makefile for the Atmel AT91RM9200 ethernet device drivers -+# -+ -+O_TARGET := at91net.o -+ -+obj-y := -+obj-m := -+obj-n := -+obj- := -+ -+obj-$(CONFIG_AT91_ETHER) += at91_ether.o -+ -+include $(TOPDIR)/Rules.make -diff -urN linux-2.4.26/drivers/at91/net/at91_ether.c linux-2.4.26-vrs1/drivers/at91/net/at91_ether.c ---- linux-2.4.26/drivers/at91/net/at91_ether.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/net/at91_ether.c 2004-03-04 22:07:29.000000000 +0000 -@@ -0,0 +1,877 @@ -+/* -+ * Ethernet driver for the Atmel AT91RM9200 (Thunder) -+ * -+ * (c) SAN People (Pty) Ltd -+ * -+ * Based on an earlier Atmel EMAC macrocell driver by Atmel and Lineo Inc. -+ * Initial version by Rick Bronson 01/11/2003 -+ * -+ * Intel LXT971A PHY support by Christopher Bahns & David Knickerbocker -+ * (Polaroid Corporation) -+ * -+ * 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. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include "at91_ether.h" -+ -+static struct net_device at91_dev; -+ -+/* ........................... PHY INTERFACE ........................... */ -+ -+/* -+ * Enable the MDIO bit in MAC control register -+ * When not called from an interrupt-handler, access to the PHY must be -+ * protected by a spinlock. -+ */ -+static void enable_mdi(AT91PS_EMAC regs) -+{ -+ regs->EMAC_CTL |= AT91C_EMAC_MPE; /* enable management port */ -+} -+ -+/* -+ * Disable the MDIO bit in the MAC control register -+ */ -+static void disable_mdi(AT91PS_EMAC regs) -+{ -+ regs->EMAC_CTL &= ~AT91C_EMAC_MPE; /* disable management port */ -+} -+ -+/* -+ * Write value to the a PHY register -+ * Note: MDI interface is assumed to already have been enabled. -+ */ -+static void write_phy(AT91PS_EMAC regs, unsigned char phy_addr, unsigned char address, unsigned int value) -+{ -+ regs->EMAC_MAN = (AT91C_EMAC_HIGH | AT91C_EMAC_CODE_802_3 | AT91C_EMAC_RW_W -+ | ((phy_addr & 0x1f) << 23) | (address << 18)) + (value & 0xffff); -+ -+ /* Wait until IDLE bit in Network Status register is cleared */ -+ // TODO: Enforce some maximum loop-count? -+ while (!(regs->EMAC_SR & AT91C_EMAC_IDLE)) { barrier(); } -+} -+ -+/* -+ * Read value stored in a PHY register. -+ * Note: MDI interface is assumed to already have been enabled. -+ */ -+static void read_phy(AT91PS_EMAC regs, unsigned char phy_addr, unsigned char address, unsigned int *value) -+{ -+ regs->EMAC_MAN = AT91C_EMAC_HIGH | AT91C_EMAC_CODE_802_3 | AT91C_EMAC_RW_R -+ | ((phy_addr & 0x1f) << 23) | (address << 18); -+ -+ /* Wait until IDLE bit in Network Status register is cleared */ -+ // TODO: Enforce some maximum loop-count? -+ while (!(regs->EMAC_SR & AT91C_EMAC_IDLE)) { barrier(); } -+ -+ *value = (regs->EMAC_MAN & 0x0000ffff); -+} -+ -+/* ........................... PHY MANAGEMENT .......................... */ -+ -+/* -+ * Access the PHY to determine the current Link speed and Mode, and update the -+ * MAC accordingly. -+ * If no link or auto-negotiation is busy, then no changes are made. -+ * Returns: 0 : OK -+ * -1 : No link -+ * -2 : AutoNegotiation still in progress -+ */ -+static int update_linkspeed(struct net_device *dev, AT91PS_EMAC regs) { -+ unsigned int bmsr, bmcr, lpa, mac_cfg; -+ unsigned int speed, duplex; -+ -+ /* Link status is latched, so read twice to get current value */ -+ read_phy(regs, 0, MII_BMSR, &bmsr); -+ read_phy(regs, 0, MII_BMSR, &bmsr); -+ if (!(bmsr & BMSR_LSTATUS)) return -1; /* no link */ -+ -+ read_phy(regs, 0, MII_BMCR, &bmcr); -+ if (bmcr & BMCR_ANENABLE) { /* AutoNegotiation is enabled */ -+ if (!(bmsr & BMSR_ANEGCOMPLETE)) return -2; /* auto-negotitation in progress */ -+ -+ read_phy(regs, 0, MII_LPA, &lpa); -+ if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) speed = SPEED_100; -+ else speed = SPEED_10; -+ if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL)) duplex = DUPLEX_FULL; -+ else duplex = DUPLEX_HALF; -+ } else { -+ speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10; -+ duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; -+ } -+ -+ /* Update the MAC */ -+ mac_cfg = regs->EMAC_CFG & ~(AT91C_EMAC_SPD | AT91C_EMAC_FD); -+ if (speed == SPEED_100) { -+ if (duplex == DUPLEX_FULL) /* 100 Full Duplex */ -+ regs->EMAC_CFG = mac_cfg | AT91C_EMAC_SPD | AT91C_EMAC_FD; -+ else /* 100 Half Duplex */ -+ regs->EMAC_CFG = mac_cfg | AT91C_EMAC_SPD; -+ } else { -+ if (duplex == DUPLEX_FULL) /* 10 Full Duplex */ -+ regs->EMAC_CFG = mac_cfg | AT91C_EMAC_FD; -+ else /* 10 Half Duplex */ -+ regs->EMAC_CFG = mac_cfg; -+ } -+ -+ printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex"); -+ return 0; -+} -+ -+/* -+ * Handle interrupts from the PHY -+ */ -+static void at91ether_phy_interrupt(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ struct net_device *dev = (struct net_device *) dev_id; -+ struct at91_private *lp = (struct at91_private *) dev->priv; -+ AT91PS_EMAC emac = (AT91PS_EMAC) dev->base_addr; -+ int status; -+ unsigned int phy; -+ -+ enable_mdi(emac); -+ if (lp->phy_type == MII_DM9161_ID) -+ read_phy(emac, 0, MII_DSINTR_REG, &phy); /* ack interrupt in Davicom PHY */ -+ else if (lp->phy_type == MII_LXT971A_ID) -+ read_phy(emac, 0, MII_ISINTS_REG, &phy); /* ack interrupt in Intel PHY */ -+ -+ status = AT91_SYS->PIOC_ISR; /* acknowledge interrupt in PIO */ -+ -+ status = update_linkspeed(dev, emac); -+ if (status == -1) { /* link is down */ -+ netif_carrier_off(dev); -+ printk(KERN_INFO "%s: Link down.\n", dev->name); -+ } else if (status == -2) { /* auto-negotiation in progress */ -+ /* Do nothing - another interrupt generated when negotiation complete */ -+ } else { /* link is operational */ -+ netif_carrier_on(dev); -+ } -+ disable_mdi(emac); -+} -+ -+/* -+ * Initialize and enable the PHY interrupt when link-state changes -+ */ -+static void enable_phyirq(struct net_device *dev, AT91PS_EMAC regs) -+{ -+ struct at91_private *lp = (struct at91_private *) dev->priv; -+ unsigned int dsintr, status; -+ -+ // TODO: Check error code. Really need a generic PIO (interrupt) -+ // layer since we're really only interested in the PC4 (DK) or PC2 (CSB337) line. -+ (void) request_irq(AT91C_ID_PIOC, at91ether_phy_interrupt, 0, dev->name, dev); -+ -+ status = AT91_SYS->PIOC_ISR; /* clear any pending PIO interrupts */ -+#ifdef CONFIG_MACH_CSB337 -+ AT91_SYS->PIOC_IER = AT91C_PIO_PC2; /* Enable interrupt */ -+#else -+ AT91_SYS->PIOC_IER = AT91C_PIO_PC4; /* Enable interrupt */ -+#endif -+ -+ spin_lock_irq(&lp->lock); -+ enable_mdi(regs); -+ -+ if (lp->phy_type == MII_DM9161_ID) { /* for Davicom PHY */ -+ read_phy(regs, 0, MII_DSINTR_REG, &dsintr); -+ dsintr = dsintr & ~0xf00; /* clear bits 8..11 */ -+ write_phy(regs, 0, MII_DSINTR_REG, dsintr); -+ } -+ else if (lp->phy_type == MII_LXT971A_ID) { /* for Intel PHY */ -+ read_phy(regs, 0, MII_ISINTE_REG, &dsintr); -+ dsintr = dsintr | 0xf2; /* set bits 1, 4..7 */ -+ write_phy(regs, 0, MII_ISINTE_REG, dsintr); -+ } -+ -+ disable_mdi(regs); -+ spin_unlock_irq(&lp->lock); -+} -+ -+/* -+ * Disable the PHY interrupt -+ */ -+static void disable_phyirq(struct net_device *dev, AT91PS_EMAC regs) -+{ -+ struct at91_private *lp = (struct at91_private *) dev->priv; -+ unsigned int dsintr; -+ -+ spin_lock_irq(&lp->lock); -+ enable_mdi(regs); -+ -+ if (lp->phy_type == MII_DM9161_ID) { /* for Davicom PHY */ -+ read_phy(regs, 0, MII_DSINTR_REG, &dsintr); -+ dsintr = dsintr | 0xf00; /* set bits 8..11 */ -+ write_phy(regs, 0, MII_DSINTR_REG, dsintr); -+ } -+ else if (lp->phy_type == MII_LXT971A_ID) { /* for Intel PHY */ -+ read_phy(regs, 0, MII_ISINTE_REG, &dsintr); -+ dsintr = dsintr & ~0xf2; /* clear bits 1, 4..7 */ -+ write_phy(regs, 0, MII_ISINTE_REG, dsintr); -+ } -+ -+ disable_mdi(regs); -+ spin_unlock_irq(&lp->lock); -+ -+#ifdef CONFIG_MACH_CSB337 -+ AT91_SYS->PIOC_IDR = AT91C_PIO_PC2; /* Disable interrupt */ -+#else -+ AT91_SYS->PIOC_IDR = AT91C_PIO_PC4; /* Disable interrupt */ -+#endif -+ free_irq(AT91C_ID_PIOC, dev); /* Free interrupt handler */ -+} -+ -+/* -+ * Perform a software reset of the PHY. -+ */ -+static void reset_phy(struct net_device *dev, AT91PS_EMAC regs) -+{ -+ struct at91_private *lp = (struct at91_private *) dev->priv; -+ unsigned int bmcr; -+ -+ spin_lock_irq(&lp->lock); -+ enable_mdi(regs); -+ -+ /* Perform PHY reset */ -+ write_phy(regs, 0, MII_BMCR, BMCR_RESET); -+ -+ /* Wait until PHY reset is complete */ -+ do { -+ read_phy(regs, 0, MII_BMCR, &bmcr); -+ } while (!(bmcr && BMCR_RESET)); -+ -+ disable_mdi(regs); -+ spin_unlock_irq(&lp->lock); -+} -+ -+ -+/* ......................... ADDRESS MANAGEMENT ........................ */ -+ -+/* -+ * Set the ethernet MAC address in dev->dev_addr -+ */ -+static void get_mac_address(struct net_device *dev) { -+ AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr; -+ char addr[6]; -+ unsigned int hi, lo; -+ -+ /* Check if bootloader set address in Specific-Address 1 */ -+ hi = regs->EMAC_SA1H; -+ lo = regs->EMAC_SA1L; -+ addr[0] = (lo & 0xff); -+ addr[1] = (lo & 0xff00) >> 8; -+ addr[2] = (lo & 0xff0000) >> 16; -+ addr[3] = (lo & 0xff000000) >> 24; -+ addr[4] = (hi & 0xff); -+ addr[5] = (hi & 0xff00) >> 8; -+ -+ if (is_valid_ether_addr(addr)) { -+ memcpy(dev->dev_addr, &addr, 6); -+ return; -+ } -+ -+ /* Check if bootloader set address in Specific-Address 2 */ -+ hi = regs->EMAC_SA2H; -+ lo = regs->EMAC_SA2L; -+ addr[0] = (lo & 0xff); -+ addr[1] = (lo & 0xff00) >> 8; -+ addr[2] = (lo & 0xff0000) >> 16; -+ addr[3] = (lo & 0xff000000) >> 24; -+ addr[4] = (hi & 0xff); -+ addr[5] = (hi & 0xff00) >> 8; -+ -+ if (is_valid_ether_addr(addr)) { -+ memcpy(dev->dev_addr, &addr, 6); -+ return; -+ } -+} -+ -+/* -+ * Program the hardware MAC address from dev->dev_addr. -+ */ -+static void update_mac_address(struct net_device *dev) -+{ -+ AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr; -+ -+ regs->EMAC_SA1L = (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | (dev->dev_addr[1] << 8) | (dev->dev_addr[0]); -+ regs->EMAC_SA1H = (dev->dev_addr[5] << 8) | (dev->dev_addr[4]); -+} -+ -+#ifdef AT91_ETHER_ADDR_CONFIGURABLE -+/* -+ * Store the new hardware address in dev->dev_addr, and update the MAC. -+ */ -+static int set_mac_address(struct net_device *dev, void* addr) -+{ -+ struct sockaddr *address = addr; -+ -+ if (!is_valid_ether_addr(address->sa_data)) -+ return -EADDRNOTAVAIL; -+ -+ memcpy(dev->dev_addr, address->sa_data, dev->addr_len); -+ update_mac_address(dev); -+ -+ printk("%s: Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, -+ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], -+ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); -+ -+ return 0; -+} -+#endif -+ -+/* -+ * Add multicast addresses to the internal multicast-hash table. -+ */ -+static void at91ether_sethashtable(struct net_device *dev, AT91PS_EMAC regs) -+{ -+ struct dev_mc_list *curr; -+ unsigned char mc_filter[2]; -+ unsigned int i, bitnr; -+ -+ mc_filter[0] = mc_filter[1] = 0; -+ -+ curr = dev->mc_list; -+ for (i = 0; i < dev->mc_count; i++, curr = curr->next) { -+ if (!curr) break; /* unexpected end of list */ -+ -+ bitnr = ether_crc(ETH_ALEN, curr->dmi_addr) >> 26; -+ mc_filter[bitnr >> 5] |= 1 << (bitnr & 31); -+ } -+ -+ regs->EMAC_HSH = mc_filter[1]; -+ regs->EMAC_HSL = mc_filter[0]; -+} -+ -+/* -+ * Enable/Disable promiscuous and multicast modes. -+ */ -+static void at91ether_set_rx_mode(struct net_device *dev) -+{ -+ AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr; -+ -+ if (dev->flags & IFF_PROMISC) { /* Enable promiscuous mode */ -+ regs->EMAC_CFG |= AT91C_EMAC_CAF; -+ } else if (dev->flags & (~IFF_PROMISC)) { /* Disable promiscuous mode */ -+ regs->EMAC_CFG &= ~AT91C_EMAC_CAF; -+ } -+ -+ if (dev->flags & IFF_ALLMULTI) { /* Enable all multicast mode */ -+ regs->EMAC_HSH = -1; -+ regs->EMAC_HSL = -1; -+ regs->EMAC_CFG |= AT91C_EMAC_MTI; -+ } else if (dev->mc_count > 0) { /* Enable specific multicasts */ -+ at91ether_sethashtable(dev, regs); -+ regs->EMAC_CFG |= AT91C_EMAC_MTI; -+ } else if (dev->flags & (~IFF_ALLMULTI)) { /* Disable all multicast mode */ -+ regs->EMAC_HSH = 0; -+ regs->EMAC_HSL = 0; -+ regs->EMAC_CFG &= ~AT91C_EMAC_MTI; -+ } -+} -+ -+/* ............................... IOCTL ............................... */ -+ -+static int mdio_read(struct net_device *dev, int phy_id, int location) -+{ -+ AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr; -+ unsigned int value; -+ -+ read_phy(regs, phy_id, location, &value); -+ return value; -+} -+ -+static void mdio_write(struct net_device *dev, int phy_id, int location, int value) -+{ -+ AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr; -+ -+ write_phy(regs, phy_id, location, value); -+} -+ -+/* -+ * ethtool support. -+ */ -+static int at91ether_ethtool_ioctl (struct net_device *dev, void *useraddr) -+{ -+ struct at91_private *lp = (struct at91_private *) dev->priv; -+ AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr; -+ u32 ethcmd; -+ int res = 0; -+ -+ if (copy_from_user (ðcmd, useraddr, sizeof (ethcmd))) -+ return -EFAULT; -+ -+ spin_lock_irq(&lp->lock); -+ enable_mdi(regs); -+ -+ switch (ethcmd) { -+ case ETHTOOL_GSET: { -+ struct ethtool_cmd ecmd = { ETHTOOL_GSET }; -+ res = mii_ethtool_gset(&lp->mii, &ecmd); -+ if (lp->phy_media == PORT_FIBRE) { /* override media type since mii.c doesn't know */ -+ ecmd.supported = SUPPORTED_FIBRE; -+ ecmd.port = PORT_FIBRE; -+ } -+ if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) -+ res = -EFAULT; -+ break; -+ } -+ case ETHTOOL_SSET: { -+ struct ethtool_cmd ecmd; -+ if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) -+ res = -EFAULT; -+ else -+ res = mii_ethtool_sset(&lp->mii, &ecmd); -+ break; -+ } -+ case ETHTOOL_NWAY_RST: { -+ res = mii_nway_restart(&lp->mii); -+ break; -+ } -+ case ETHTOOL_GLINK: { -+ struct ethtool_value edata = { ETHTOOL_GLINK }; -+ edata.data = mii_link_ok(&lp->mii); -+ if (copy_to_user(useraddr, &edata, sizeof(edata))) -+ res = -EFAULT; -+ break; -+ } -+ default: -+ res = -EOPNOTSUPP; -+ } -+ -+ disable_mdi(regs); -+ spin_unlock_irq(&lp->lock); -+ -+ return res; -+} -+ -+/* -+ * User-space ioctl interface. -+ */ -+static int at91ether_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -+{ -+ switch(cmd) { -+ case SIOCETHTOOL: -+ return at91ether_ethtool_ioctl(dev, (void *) rq->ifr_data); -+ default: -+ return -EOPNOTSUPP; -+ } -+} -+ -+/* ................................ MAC ................................ */ -+ -+/* -+ * Initialize and start the Receiver and Transmit subsystems -+ */ -+static void at91ether_start(struct net_device *dev) -+{ -+ AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr; -+ struct at91_private *lp = (struct at91_private *) dev->priv; -+ int i; -+ struct recv_desc_bufs *dlist, *dlist_phys; -+ -+ dlist = lp->dlist; -+ dlist_phys = lp->dlist_phys; -+ -+ for (i = 0; i < MAX_RX_DESCR; i++) { -+ dlist->descriptors[i].addr = (unsigned int) &dlist_phys->recv_buf[i][0]; -+ dlist->descriptors[i].size = 0; -+ } -+ -+ /* Set the Wrap bit on the last descriptor */ -+ dlist->descriptors[i-1].addr |= EMAC_DESC_WRAP; -+ -+ /* Reset buffer index */ -+ lp->rxBuffIndex = 0; -+ -+ /* Program address of descriptor list in Rx Buffer Queue register */ -+ regs->EMAC_RBQP = (AT91_REG) dlist_phys; -+ -+ /* Enable Receive and Transmit */ -+ regs->EMAC_CTL |= (AT91C_EMAC_RE | AT91C_EMAC_TE); -+} -+ -+/* -+ * Open the ethernet interface -+ */ -+static int at91ether_open(struct net_device *dev) -+{ -+ struct at91_private *lp = (struct at91_private *) dev->priv; -+ AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr; -+ -+ if (!is_valid_ether_addr(dev->dev_addr)) -+ return -EADDRNOTAVAIL; -+ -+ AT91_SYS->PMC_PCER = 1 << AT91C_ID_EMAC; /* Re-enable Peripheral clock */ -+ regs->EMAC_CTL |= AT91C_EMAC_CSR; /* Clear internal statistics */ -+ -+ /* Enable PHY interrupt */ -+ enable_phyirq(dev, regs); -+ -+ /* Enable MAC interrupts */ -+ regs->EMAC_IER = AT91C_EMAC_RCOM | AT91C_EMAC_RBNA -+ | AT91C_EMAC_TUND | AT91C_EMAC_RTRY | AT91C_EMAC_TCOM -+ | AT91C_EMAC_ROVR | AT91C_EMAC_HRESP; -+ -+ /* Determine current link speed */ -+ spin_lock_irq(&lp->lock); -+ enable_mdi(regs); -+ (void) update_linkspeed(dev, regs); -+ disable_mdi(regs); -+ spin_unlock_irq(&lp->lock); -+ -+ at91ether_start(dev); -+ netif_start_queue(dev); -+ return 0; -+} -+ -+/* -+ * Close the interface -+ */ -+static int at91ether_close(struct net_device *dev) -+{ -+ AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr; -+ -+ /* Disable Receiver and Transmitter */ -+ regs->EMAC_CTL &= ~(AT91C_EMAC_TE | AT91C_EMAC_RE); -+ -+ /* Disable PHY interrupt */ -+ disable_phyirq(dev, regs); -+ -+ /* Disable MAC interrupts */ -+ regs->EMAC_IDR = AT91C_EMAC_RCOM | AT91C_EMAC_RBNA -+ | AT91C_EMAC_TUND | AT91C_EMAC_RTRY | AT91C_EMAC_TCOM -+ | AT91C_EMAC_ROVR | AT91C_EMAC_HRESP; -+ -+ netif_stop_queue(dev); -+ -+ AT91_SYS->PMC_PCDR = 1 << AT91C_ID_EMAC; /* Disable Peripheral clock */ -+ -+ return 0; -+} -+ -+/* -+ * Transmit packet. -+ */ -+static int at91ether_tx(struct sk_buff *skb, struct net_device *dev) -+{ -+ AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr; -+ struct at91_private *lp = (struct at91_private *) dev->priv; -+ -+ if (regs->EMAC_TSR & AT91C_EMAC_BNQ) { -+ netif_stop_queue(dev); -+ -+ /* Store packet information (to free when Tx completed) */ -+ lp->skb = skb; -+ lp->skb_length = skb->len; -+ lp->skb_physaddr = pci_map_single(NULL, skb->data, skb->len, PCI_DMA_TODEVICE); -+ lp->stats.tx_bytes += skb->len; -+ -+ /* Set address of the data in the Transmit Address register */ -+ regs->EMAC_TAR = lp->skb_physaddr; -+ /* Set length of the packet in the Transmit Control register */ -+ regs->EMAC_TCR = skb->len; -+ -+ dev->trans_start = jiffies; -+ } else { -+ printk(KERN_ERR "at91_ether.c: at91ether_tx() called, but device is busy!\n"); -+ return 1; /* if we return anything but zero, dev.c:1055 calls kfree_skb(skb) -+ on this skb, he also reports -ENETDOWN and printk's, so either -+ we free and return(0) or don't free and return 1 */ -+ } -+ -+ return 0; -+} -+ -+/* -+ * Update the current statistics from the internal statistics registers. -+ */ -+static struct net_device_stats *at91ether_stats(struct net_device *dev) -+{ -+ struct at91_private *lp = (struct at91_private *) dev->priv; -+ AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr; -+ int ale, lenerr, seqe, lcol, ecol; -+ -+ if (netif_running(dev)) { -+ lp->stats.rx_packets += regs->EMAC_OK; /* Good frames received */ -+ ale = regs->EMAC_ALE; -+ lp->stats.rx_frame_errors += ale; /* Alignment errors */ -+ lenerr = regs->EMAC_ELR + regs->EMAC_USF; -+ lp->stats.rx_length_errors += lenerr; /* Excessive Length or Undersize Frame error */ -+ seqe = regs->EMAC_SEQE; -+ lp->stats.rx_crc_errors += seqe; /* CRC error */ -+ lp->stats.rx_fifo_errors += regs->EMAC_DRFC; /* Receive buffer not available */ -+ lp->stats.rx_errors += (ale + lenerr + seqe + regs->EMAC_CDE + regs->EMAC_RJB); -+ -+ lp->stats.tx_packets += regs->EMAC_FRA; /* Frames successfully transmitted */ -+ lp->stats.tx_fifo_errors += regs->EMAC_TUE; /* Transmit FIFO underruns */ -+ lp->stats.tx_carrier_errors += regs->EMAC_CSE; /* Carrier Sense errors */ -+ lp->stats.tx_heartbeat_errors += regs->EMAC_SQEE; /* Heartbeat error */ -+ -+ lcol = regs->EMAC_LCOL; -+ ecol = regs->EMAC_ECOL; -+ lp->stats.tx_window_errors += lcol; /* Late collisions */ -+ lp->stats.tx_aborted_errors += ecol; /* 16 collisions */ -+ -+ lp->stats.collisions += (regs->EMAC_SCOL + regs->EMAC_MCOL + lcol + ecol); -+ } -+ return &lp->stats; -+} -+ -+/* -+ * Extract received frame from buffer descriptors and sent to upper layers. -+ * (Called from interrupt context) -+ */ -+static void at91ether_rx(struct net_device *dev) -+{ -+ struct at91_private *lp = (struct at91_private *) dev->priv; -+ struct recv_desc_bufs *dlist; -+ unsigned char *p_recv; -+ struct sk_buff *skb; -+ unsigned int pktlen; -+ -+ dlist = lp->dlist; -+ while (dlist->descriptors[lp->rxBuffIndex].addr & EMAC_DESC_DONE) { -+ p_recv = dlist->recv_buf[lp->rxBuffIndex]; -+ pktlen = dlist->descriptors[lp->rxBuffIndex].size & 0x7ff; /* Length of frame including FCS */ -+ skb = alloc_skb(pktlen + 2, GFP_ATOMIC); -+ if (skb != NULL) { -+ skb_reserve(skb, 2); -+ memcpy(skb_put(skb, pktlen), p_recv, pktlen); -+ -+ skb->dev = dev; -+ skb->protocol = eth_type_trans(skb, dev); -+ skb->len = pktlen; -+ dev->last_rx = jiffies; -+ lp->stats.rx_bytes += pktlen; -+ netif_rx(skb); -+ } -+ else { -+ lp->stats.rx_dropped += 1; -+ printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); -+ } -+ -+ if (dlist->descriptors[lp->rxBuffIndex].size & EMAC_MULTICAST) -+ lp->stats.multicast++; -+ -+ dlist->descriptors[lp->rxBuffIndex].addr &= ~EMAC_DESC_DONE; /* reset ownership bit */ -+ if (lp->rxBuffIndex == MAX_RX_DESCR-1) /* wrap after last buffer */ -+ lp->rxBuffIndex = 0; -+ else -+ lp->rxBuffIndex++; -+ } -+} -+ -+/* -+ * MAC interrupt handler -+ */ -+static void at91ether_interrupt(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ struct net_device *dev = (struct net_device *) dev_id; -+ struct at91_private *lp = (struct at91_private *) dev->priv; -+ AT91PS_EMAC emac = (AT91PS_EMAC) dev->base_addr; -+ unsigned long intstatus; -+ -+ /* MAC Interrupt Status register indicates what interrupts are pending. -+ It is automatically cleared once read. */ -+ intstatus = emac->EMAC_ISR; -+ -+ if (intstatus & AT91C_EMAC_RCOM) /* Receive complete */ -+ at91ether_rx(dev); -+ -+ if (intstatus & AT91C_EMAC_TCOM) { /* Transmit complete */ -+ /* The TCOM bit is set even if the transmission failed. */ -+ if (intstatus & (AT91C_EMAC_TUND | AT91C_EMAC_RTRY)) -+ lp->stats.tx_errors += 1; -+ -+ dev_kfree_skb_irq(lp->skb); -+ pci_unmap_single(NULL, lp->skb_physaddr, lp->skb_length, PCI_DMA_TODEVICE); -+ netif_wake_queue(dev); -+ } -+ -+ if (intstatus & AT91C_EMAC_RBNA) -+ printk("%s: RBNA error\n", dev->name); -+ if (intstatus & AT91C_EMAC_ROVR) -+ printk("%s: ROVR error\n", dev->name); -+} -+ -+/* -+ * Initialize the ethernet interface -+ */ -+static int at91ether_setup(struct net_device *dev, unsigned long phy_type) -+{ -+ struct at91_private *lp; -+ AT91PS_EMAC regs; -+ static int already_initialized = 0; -+ unsigned int val; -+ -+ if (already_initialized) -+ return 0; -+ -+ dev = init_etherdev(dev, sizeof(struct at91_private)); -+ dev->base_addr = AT91C_VA_BASE_EMAC; -+ dev->irq = AT91C_ID_EMAC; -+ SET_MODULE_OWNER(dev); -+ -+ /* Install the interrupt handler */ -+ if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev)) -+ return -EBUSY; -+ -+ /* Allocate memory for private data structure */ -+ lp = (struct at91_private *) kmalloc(sizeof(struct at91_private), GFP_KERNEL); -+ if (lp == NULL) { -+ free_irq(dev->irq, dev); -+ return -ENOMEM; -+ } -+ memset(lp, 0, sizeof(struct at91_private)); -+ dev->priv = lp; -+ -+ /* Allocate memory for DMA Receive descriptors */ -+ lp->dlist = (struct recv_desc_bufs *) consistent_alloc(GFP_DMA | GFP_KERNEL, sizeof(struct recv_desc_bufs), (dma_addr_t *) &lp->dlist_phys); -+ if (lp->dlist == NULL) { -+ kfree(dev->priv); -+ free_irq(dev->irq, dev); -+ return -ENOMEM; -+ } -+ -+ spin_lock_init(&lp->lock); -+ -+ ether_setup(dev); -+ dev->open = at91ether_open; -+ dev->stop = at91ether_close; -+ dev->hard_start_xmit = at91ether_tx; -+ dev->get_stats = at91ether_stats; -+ dev->set_multicast_list = at91ether_set_rx_mode; -+ dev->do_ioctl = at91ether_ioctl; -+ -+#ifdef AT91_ETHER_ADDR_CONFIGURABLE -+ dev->set_mac_address = set_mac_address; -+#endif -+ -+ get_mac_address(dev); /* Get ethernet address and store it in dev->dev_addr */ -+ update_mac_address(dev); /* Program ethernet address into MAC */ -+ -+ regs = (AT91PS_EMAC) dev->base_addr; -+ regs->EMAC_CTL = 0; -+ -+#ifdef CONFIG_AT91_ETHER_RMII -+ regs->EMAC_CFG = AT91C_EMAC_BIG | AT91C_EMAC_RMII; -+#else -+ regs->EMAC_CFG = AT91C_EMAC_BIG; -+#endif -+ if (phy_type == MII_LXT971A_ID) -+ regs->EMAC_CFG |= AT91C_EMAC_CLK_HCLK_64; /* MDIO clock = system clock/64 */ -+ -+ if (phy_type == MII_DM9161_ID) { -+ spin_lock_irq(&lp->lock); -+ enable_mdi(regs); -+ -+ read_phy(regs, 0, MII_DSCR_REG, &val); -+ if ((val & (1 << 10)) == 0) /* DSCR bit 10 is 0 -- fiber mode */ -+ lp->phy_media = PORT_FIBRE; -+ -+ disable_mdi(regs); -+ spin_unlock_irq(&lp->lock); -+ } -+ -+ lp->mii.dev = dev; /* Support for ethtool */ -+ lp->mii.mdio_read = mdio_read; -+ lp->mii.mdio_write = mdio_write; -+ -+ lp->phy_type = phy_type; /* Type of PHY connected */ -+ -+ /* Determine current link speed */ -+ spin_lock_irq(&lp->lock); -+ enable_mdi(regs); -+ (void) update_linkspeed(dev, regs); -+ disable_mdi(regs); -+ spin_unlock_irq(&lp->lock); -+ -+ /* Display ethernet banner */ -+ printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n", -+ dev->name, (uint) dev->base_addr, dev->irq, -+ regs->EMAC_CFG & AT91C_EMAC_SPD ? "100-" : "10-", -+ regs->EMAC_CFG & AT91C_EMAC_FD ? "FullDuplex" : "HalfDuplex", -+ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], -+ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); -+ if (phy_type == MII_DM9161_ID) -+ printk(KERN_INFO "%s: Davicom 9196 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)"); -+ else if (phy_type == MII_LXT971A_ID) -+ printk(KERN_INFO "%s: Intel LXT971A PHY\n", dev->name); -+ -+ already_initialized = 1; -+ return 0; -+} -+ -+/* -+ * Detect MAC and PHY and perform initialization -+ */ -+static int at91ether_probe(struct net_device *dev) -+{ -+ AT91PS_EMAC regs = (AT91PS_EMAC) AT91C_VA_BASE_EMAC; -+ unsigned int phyid1, phyid2; -+ int detected = -1; -+ -+ /* Configure the hardware - RMII vs MII mode */ -+#ifdef CONFIG_AT91_ETHER_RMII -+ AT91_CfgPIO_EMAC_RMII(); -+#else -+ AT91_CfgPIO_EMAC_MII(); -+#endif -+ -+ AT91_CfgPIO_EMAC_PHY(); /* Configure PHY interrupt */ -+ AT91_SYS->PMC_PCER = 1 << AT91C_ID_EMAC; /* Enable Peripheral clock */ -+ -+ /* Read the PHY ID registers */ -+ enable_mdi(regs); -+ read_phy(regs, 0, MII_PHYSID1, &phyid1); -+ read_phy(regs, 0, MII_PHYSID2, &phyid2); -+ disable_mdi(regs); -+ -+ /* Davicom 9161: PHY_ID1 = 0x181 PHY_ID2 = B881 */ -+ if (((phyid1 << 16) | (phyid2 & 0xfff0)) == MII_DM9161_ID) { -+ detected = at91ether_setup(dev, MII_DM9161_ID); -+ } -+ /* Intel LXT971A: PHY_ID1 = 0x13 PHY_ID2 = 78E0 */ -+ else if (((phyid1 << 16) | (phyid2 & 0xfff0)) == MII_LXT971A_ID) { -+ detected = at91ether_setup(dev, MII_LXT971A_ID); -+ } -+ -+ AT91_SYS->PMC_PCDR = 1 << AT91C_ID_EMAC; /* Disable Peripheral clock */ -+ -+ return detected; -+} -+ -+static int __init at91ether_init(void) -+{ -+ if (!at91ether_probe(&at91_dev)) -+ return register_netdev(&at91_dev); -+ -+ return -1; -+} -+ -+static void __exit at91ether_exit(void) -+{ -+ unregister_netdev(&at91_dev); -+} -+ -+module_init(at91ether_init) -+module_exit(at91ether_exit) -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("AT91RM9200 EMAC Ethernet driver"); -+MODULE_AUTHOR("Andrew Victor"); -diff -urN linux-2.4.26/drivers/at91/net/at91_ether.h linux-2.4.26-vrs1/drivers/at91/net/at91_ether.h ---- linux-2.4.26/drivers/at91/net/at91_ether.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/net/at91_ether.h 2004-03-04 22:07:29.000000000 +0000 -@@ -0,0 +1,81 @@ -+/* -+ * Ethernet driver for the Atmel AT91RM9200 (Thunder) -+ * -+ * (c) SAN People (Pty) Ltd -+ * -+ * Based on an earlier Atmel EMAC macrocell driver by Atmel and Lineo Inc. -+ * Initial version by Rick Bronson. -+ * -+ * 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. -+ */ -+ -+#ifndef AT91_ETHERNET -+#define AT91_ETHERNET -+ -+#undef AT91_ETHER_ADDR_CONFIGURABLE /* MAC address can be changed? */ -+ -+ -+/* Davicom 9161 PHY */ -+#define MII_DM9161_ID 0x0181b880 -+ -+/* Davicom specific registers */ -+#define MII_DSCR_REG 16 -+#define MII_DSCSR_REG 17 -+#define MII_DSINTR_REG 21 -+ -+/* Intel LXT971A PHY */ -+#define MII_LXT971A_ID 0x001378E0 -+ -+/* Intel specific registers */ -+#define MII_ISINTE_REG 18 -+#define MII_ISINTS_REG 19 -+ -+/* ........................................................................ */ -+ -+#define MAX_RBUFF_SZ 0x600 /* 1518 rounded up */ -+#define MAX_RX_DESCR 9 /* max number of receive buffers */ -+ -+#define EMAC_DESC_DONE 0x00000001 /* bit for if DMA is done */ -+#define EMAC_DESC_WRAP 0x00000002 /* bit for wrap */ -+ -+#define EMAC_BROADCAST 0x80000000 /* broadcast address */ -+#define EMAC_MULTICAST 0x40000000 /* multicast address */ -+#define EMAC_UNICAST 0x20000000 /* unicast address */ -+ -+struct rbf_t -+{ -+ unsigned int addr; -+ unsigned long size; -+}; -+ -+struct recv_desc_bufs -+{ -+ struct rbf_t descriptors[MAX_RX_DESCR]; /* must be on sizeof (rbf_t) boundary */ -+ char recv_buf[MAX_RX_DESCR][MAX_RBUFF_SZ]; /* must be on long boundary */ -+}; -+ -+struct at91_private -+{ -+ struct net_device_stats stats; -+ struct mii_if_info mii; /* ethtool support */ -+ -+ /* PHY */ -+ unsigned long phy_type; /* type of PHY (PHY_ID) */ -+ spinlock_t lock; /* lock for MDI interface */ -+ short phy_media; /* media interface type */ -+ -+ /* Transmit */ -+ struct sk_buff *skb; /* holds skb until xmit interrupt completes */ -+ dma_addr_t skb_physaddr; /* phys addr from pci_map_single */ -+ int skb_length; /* saved skb length for pci_unmap_single */ -+ -+ /* Receive */ -+ int rxBuffIndex; /* index into receive descriptor list */ -+ struct recv_desc_bufs *dlist; /* descriptor list address */ -+ struct recv_desc_bufs *dlist_phys; /* descriptor list physical address */ -+}; -+ -+#endif -diff -urN linux-2.4.26/drivers/at91/rtc/Makefile linux-2.4.26-vrs1/drivers/at91/rtc/Makefile ---- linux-2.4.26/drivers/at91/rtc/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/rtc/Makefile 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,15 @@ -+# File: drivers/at91/rtc/Makefile -+# -+# Makefile for the Atmel AT91RM9200 real time clock device drivers -+# -+ -+O_TARGET := at91rtc.o -+ -+obj-y := -+obj-m := -+obj-n := -+obj- := -+ -+obj-$(CONFIG_AT91_RTC) += at91_rtc.o -+ -+include $(TOPDIR)/Rules.make -diff -urN linux-2.4.26/drivers/at91/rtc/at91_rtc.c linux-2.4.26-vrs1/drivers/at91/rtc/at91_rtc.c ---- linux-2.4.26/drivers/at91/rtc/at91_rtc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/rtc/at91_rtc.c 2004-03-04 22:31:24.000000000 +0000 -@@ -0,0 +1,441 @@ -+/* -+ * Real Time Clock interface for Linux on Atmel AT91RM9200 -+ * -+ * Copyright (c) 2002 Rick Bronson -+ * -+ * Based on sa1100-rtc.c by Nils Faerber -+ * Based on rtc.c by Paul Gortmaker -+ * Date/time conversion routines taken from arch/arm/kernel/time.c -+ * by Linus Torvalds and Russell King -+ * and the GNU C Library -+ * ( ... I love the GPL ... just take what you need! ;) -+ * -+ * 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. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define AT91_RTC_FREQ 1 -+#define EPOCH 1970 -+ -+/* Those are the bits from a classic RTC we want to mimic */ -+#define AT91_RTC_IRQF 0x80 /* any of the following 3 is active */ -+#define AT91_RTC_PF 0x40 -+#define AT91_RTC_AF 0x20 -+#define AT91_RTC_UF 0x10 -+ -+#define BCD2BIN(val) (((val)&15) + ((val)>>4)*10) -+#define BIN2BCD(val) ((((val)/10)<<4) + (val)%10) -+ -+static unsigned long rtc_status = 0; -+static unsigned long rtc_irq_data; -+static unsigned int at91_alarm_year = EPOCH; -+ -+static struct fasync_struct *at91_rtc_async_queue; -+static DECLARE_WAIT_QUEUE_HEAD(at91_rtc_wait); -+static DECLARE_WAIT_QUEUE_HEAD(at91_rtc_update); -+static spinlock_t at91_rtc_updlock; /* some spinlocks for saving/restoring interrupt levels */ -+extern spinlock_t at91_rtc_lock; -+ -+static const unsigned char days_in_mo[] = -+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; -+ -+#define is_leap(year) \ -+ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) -+ -+static const unsigned short int __mon_yday[2][13] = -+{ -+ /* Normal years. */ -+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, -+ /* Leap years. */ -+ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } -+}; -+ -+/* -+ * Returns day since start of the year [0-365] -+ * (from drivers/char/efirtc.c) -+ */ -+static inline int compute_yday(int year, int month, int day) -+{ -+ return __mon_yday[is_leap(year)][month] + day-1; -+} -+ -+/* -+ * Set current time and date in RTC -+ */ -+static void at91_rtc_settime(struct rtc_time *tval) -+{ -+ unsigned long flags; -+ -+ /* Stop Time/Calendar from counting */ -+ AT91_SYS->RTC_CR |= (AT91C_RTC_UPDCAL | AT91C_RTC_UPDTIM); -+ -+ spin_lock_irqsave(&at91_rtc_updlock, flags); /* stop int's else we wakeup b4 we sleep */ -+ AT91_SYS->RTC_IER = AT91C_RTC_ACKUPD; -+ interruptible_sleep_on(&at91_rtc_update); /* wait for ACKUPD interrupt to hit */ -+ spin_unlock_irqrestore(&at91_rtc_updlock, flags); -+ AT91_SYS->RTC_IDR = AT91C_RTC_ACKUPD; -+ -+ AT91_SYS->RTC_TIMR = BIN2BCD(tval->tm_sec) << 0 -+ | BIN2BCD(tval->tm_min) << 8 -+ | BIN2BCD(tval->tm_hour) << 16; -+ -+ AT91_SYS->RTC_CALR = BIN2BCD((tval->tm_year + 1900) / 100) /* century */ -+ | BIN2BCD(tval->tm_year % 100) << 8 /* year */ -+ | BIN2BCD(tval->tm_mon + 1) << 16 /* tm_mon starts at zero */ -+ | BIN2BCD(tval->tm_wday + 1) << 21 /* day of the week [0-6], Sunday=0 */ -+ | BIN2BCD(tval->tm_mday) << 24; -+ -+ /* Restart Time/Calendar */ -+ AT91_SYS->RTC_CR &= ~(AT91C_RTC_UPDCAL | AT91C_RTC_UPDTIM); -+} -+ -+/* -+ * Decode time/date into rtc_time structure -+ */ -+static void at91_rtc_decodetime(AT91_REG *timereg, AT91_REG *calreg, struct rtc_time *tval) -+{ -+ unsigned int time, date; -+ -+ do { /* must read twice in case it changes */ -+ time = *timereg; -+ date = *calreg; -+ } while ((time != *timereg) || (date != *calreg)); -+ -+ tval->tm_sec = BCD2BIN((time & AT91C_RTC_SEC) >> 0); -+ tval->tm_min = BCD2BIN((time & AT91C_RTC_MIN) >> 8); -+ tval->tm_hour = BCD2BIN((time & AT91C_RTC_HOUR) >> 16); -+ -+ /* The Calendar Alarm register does not have a field for -+ the year - so these will return an invalid value. When an -+ alarm is set, at91_alarm_year wille store the current year. */ -+ tval->tm_year = BCD2BIN(date & AT91C_RTC_CENT) * 100; /* century */ -+ tval->tm_year += BCD2BIN((date & AT91C_RTC_YEAR) >> 8); /* year */ -+ -+ tval->tm_wday = BCD2BIN((date & AT91C_RTC_DAY) >> 21) - 1; /* day of the week [0-6], Sunday=0 */ -+ tval->tm_mon = BCD2BIN(((date & AT91C_RTC_MONTH) >> 16) - 1); -+ tval->tm_mday = BCD2BIN((date & AT91C_RTC_DATE) >> 24); -+} -+ -+/* -+ * IRQ handler for the RTC -+ */ -+static void at91_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ unsigned int rtsr = AT91_SYS->RTC_SR & AT91_SYS->RTC_IMR; -+ -+ /* update irq data & counter */ -+ if (rtsr) { /* this interrupt is shared! Is it ours? */ -+ if (rtsr & AT91C_RTC_ALARM) -+ rtc_irq_data |= (AT91_RTC_AF | AT91_RTC_IRQF); -+ if (rtsr & AT91C_RTC_SECEV) -+ rtc_irq_data |= (AT91_RTC_UF | AT91_RTC_IRQF); -+ if (rtsr & AT91C_RTC_ACKUPD) -+ wake_up_interruptible(&at91_rtc_update); -+ rtc_irq_data += 0x100; -+ AT91_SYS->RTC_SCCR = rtsr; /* clear status reg */ -+ -+ /* wake up waiting process */ -+ wake_up_interruptible(&at91_rtc_wait); -+ kill_fasync(&at91_rtc_async_queue, SIGIO, POLL_IN); -+ } -+} -+ -+static int at91_rtc_open(struct inode *inode, struct file *file) -+{ -+ if (test_and_set_bit(1, &rtc_status)) -+ return -EBUSY; -+ rtc_irq_data = 0; -+ return 0; -+} -+ -+static int at91_rtc_release(struct inode *inode, struct file *file) -+{ -+ rtc_status = 0; -+ return 0; -+} -+ -+static int at91_rtc_fasync(int fd, struct file *filp, int on) -+{ -+ return fasync_helper(fd, filp, on, &at91_rtc_async_queue); -+} -+ -+static unsigned int at91_rtc_poll(struct file *file, poll_table * wait) -+{ -+ poll_wait(file, &at91_rtc_wait, wait); -+ return (rtc_irq_data) ? 0 : POLLIN | POLLRDNORM; -+} -+ -+static ssize_t at91_rtc_read(struct file * file, char *buf, size_t count, loff_t * ppos) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long data; -+ ssize_t retval; -+ -+ if (count < sizeof(unsigned long)) -+ return -EINVAL; -+ -+ add_wait_queue(&at91_rtc_wait, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ for (;;) { -+ spin_lock_irq(&at91_rtc_lock); -+ data = rtc_irq_data; -+ if (data != 0) { -+ rtc_irq_data = 0; -+ break; -+ } -+ spin_unlock_irq(&at91_rtc_lock); -+ -+ if (file->f_flags & O_NONBLOCK) { -+ retval = -EAGAIN; -+ goto out; -+ } -+ -+ if (signal_pending(current)) { -+ retval = -ERESTARTSYS; -+ goto out; -+ } -+ -+ schedule(); -+ } -+ spin_unlock_irq(&at91_rtc_lock); -+ -+ data -= 0x100; /* the first IRQ wasn't actually missed */ -+ retval = put_user(data, (unsigned long *) buf); -+ if (!retval) -+ retval = sizeof(unsigned long); -+ -+out: -+ set_current_state(TASK_RUNNING); -+ remove_wait_queue(&at91_rtc_wait, &wait); -+ return retval; -+} -+ -+/* -+ * Handle commands from user-space -+ */ -+static int at91_rtc_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ struct rtc_time tm, tm2; -+ int ret = 0; -+ -+ spin_lock_irq(&at91_rtc_lock); -+ switch (cmd) { -+ case RTC_AIE_OFF: /* alarm off */ -+ AT91_SYS->RTC_IDR = AT91C_RTC_ALARM; -+ rtc_irq_data = 0; -+ break; -+ case RTC_AIE_ON: /* alarm on */ -+ AT91_SYS->RTC_IER = AT91C_RTC_ALARM; -+ rtc_irq_data = 0; -+ break; -+ case RTC_UIE_OFF: /* update off */ -+ AT91_SYS->RTC_IDR = AT91C_RTC_SECEV; -+ rtc_irq_data = 0; -+ break; -+ case RTC_UIE_ON: /* update on */ -+ AT91_SYS->RTC_IER = AT91C_RTC_SECEV; -+ rtc_irq_data = 0; -+ break; -+ case RTC_PIE_OFF: /* periodic off */ -+ AT91_SYS->RTC_IDR = AT91C_RTC_SECEV; -+ rtc_irq_data = 0; -+ break; -+ case RTC_PIE_ON: /* periodic on */ -+ AT91_SYS->RTC_IER = AT91C_RTC_SECEV; -+ rtc_irq_data = 0; -+ break; -+ case RTC_ALM_READ: /* read alarm */ -+ memset(&tm, 0, sizeof(struct rtc_time)); -+ at91_rtc_decodetime(&(AT91_SYS->RTC_TIMALR), &(AT91_SYS->RTC_CALALR), &tm); -+ tm.tm_yday = compute_yday(tm.tm_year, tm.tm_mon, tm.tm_mday); -+ tm.tm_year = at91_alarm_year - 1900; -+ ret = copy_to_user((void *) arg, &tm, sizeof(tm)) ? -EFAULT : 0; -+ break; -+ case RTC_ALM_SET: /* set alarm */ -+ if (copy_from_user(&tm2, (struct rtc_time *) arg, sizeof(tm2))) -+ ret = -EFAULT; -+ else { -+ at91_rtc_decodetime(&(AT91_SYS->RTC_TIMR), &(AT91_SYS->RTC_CALR), &tm); -+ at91_alarm_year = tm.tm_year; -+ if ((unsigned) tm2.tm_hour < 24) /* do some range checking */ -+ tm.tm_hour = tm2.tm_hour; -+ if ((unsigned) tm2.tm_min < 60) -+ tm.tm_min = tm2.tm_min; -+ if ((unsigned) tm2.tm_sec < 60) -+ tm.tm_sec = tm2.tm_sec; -+ AT91_SYS->RTC_TIMALR = BIN2BCD(tm.tm_sec) << 0 -+ | BIN2BCD(tm.tm_min) << 8 -+ | BIN2BCD(tm.tm_hour) << 16 -+ | AT91C_RTC_HOUREN | AT91C_RTC_MINEN -+ | AT91C_RTC_SECEN; -+ AT91_SYS->RTC_CALALR = BIN2BCD(tm.tm_mon + 1) << 16 /* tm_mon starts at zero */ -+ | BIN2BCD(tm.tm_mday) << 24 -+ | AT91C_RTC_DATEEN | AT91C_RTC_MONTHEN; -+ } -+ break; -+ case RTC_RD_TIME: /* read time */ -+ memset(&tm, 0, sizeof(struct rtc_time)); -+ at91_rtc_decodetime(&(AT91_SYS->RTC_TIMR), &(AT91_SYS->RTC_CALR), &tm); -+ tm.tm_yday = compute_yday(tm.tm_year, tm.tm_mon, tm.tm_mday); -+ tm.tm_year = tm.tm_year - 1900; -+ ret = copy_to_user((void *) arg, &tm, sizeof(tm)) ? -EFAULT : 0; -+ break; -+ case RTC_SET_TIME: /* set time */ -+ if (!capable(CAP_SYS_TIME)) -+ ret = -EACCES; -+ else { -+ if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof(tm))) -+ ret = -EFAULT; -+ else { -+ int tm_year = tm.tm_year + 1900; -+ if (tm_year < EPOCH -+ || (unsigned) tm.tm_mon >= 12 -+ || tm.tm_mday < 1 -+ || tm.tm_mday > (days_in_mo[tm.tm_mon] + (tm.tm_mon == 1 && is_leap(tm_year))) -+ || (unsigned) tm.tm_hour >= 24 -+ || (unsigned) tm.tm_min >= 60 -+ || (unsigned) tm.tm_sec >= 60) -+ ret = -EINVAL; -+ else -+ at91_rtc_settime(&tm); -+ } -+ } -+ break; -+ case RTC_IRQP_READ: /* read periodic alarm frequency */ -+ ret = put_user(AT91_RTC_FREQ, (unsigned long *) arg); -+ break; -+ case RTC_IRQP_SET: /* set periodic alarm frequency */ -+ if (arg != AT91_RTC_FREQ) -+ ret = -EINVAL; -+ break; -+ case RTC_EPOCH_READ: /* read epoch */ -+ ret = put_user(EPOCH, (unsigned long *) arg); -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ spin_unlock_irq(&at91_rtc_lock); -+ return ret; -+} -+ -+/* -+ * Provide RTC information in /proc/driver/rtc -+ */ -+static int at91_rtc_read_proc(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ char *p = page; -+ int len; -+ struct rtc_time tm; -+ -+ at91_rtc_decodetime(&(AT91_SYS->RTC_TIMR), &(AT91_SYS->RTC_CALR), &tm); -+ p += sprintf(p, "rtc_time\t: %02d:%02d:%02d\n" -+ "rtc_date\t: %04d-%02d-%02d\n" -+ "rtc_epoch\t: %04d\n", -+ tm.tm_hour, tm.tm_min, tm.tm_sec, -+ tm.tm_year, tm.tm_mon + 1, tm.tm_mday, EPOCH); -+ at91_rtc_decodetime(&(AT91_SYS->RTC_TIMALR), &(AT91_SYS->RTC_CALALR), &tm); -+ p += sprintf(p, "alrm_time\t: %02d:%02d:%02d\n" -+ "alrm_date\t: %04d-%02d-%02d\n", -+ tm.tm_hour, tm.tm_min, tm.tm_sec, -+ at91_alarm_year, tm.tm_mon + 1, tm.tm_mday); -+ p += sprintf(p, "alarm_IRQ\t: %s\n", (AT91_SYS->RTC_IMR & AT91C_RTC_ALARM) ? "yes" : "no"); -+ p += sprintf(p, "update_IRQ\t: %s\n", (AT91_SYS->RTC_IMR & AT91C_RTC_ACKUPD) ? "yes" : "no"); -+ p += sprintf(p, "periodic_IRQ\t: %s\n", (AT91_SYS->RTC_IMR & AT91C_RTC_SECEV) ? "yes" : "no"); -+ p += sprintf(p, "periodic_freq\t: %ld\n", (unsigned long) AT91_RTC_FREQ); -+ -+ len = (p - page) - off; -+ if (len < 0) -+ len = 0; -+ -+ *eof = (len <= count) ? 1 : 0; -+ *start = page + off; -+ -+ return len; -+} -+ -+static struct file_operations at91_rtc_fops = { -+ owner:THIS_MODULE, -+ llseek:no_llseek, -+ read:at91_rtc_read, -+ poll:at91_rtc_poll, -+ ioctl:at91_rtc_ioctl, -+ open:at91_rtc_open, -+ release:at91_rtc_release, -+ fasync:at91_rtc_fasync, -+}; -+ -+static struct miscdevice at91_rtc_miscdev = { -+ minor:RTC_MINOR, -+ name:"rtc", -+ fops:&at91_rtc_fops, -+}; -+ -+/* -+ * Initialize and install RTC driver -+ */ -+static int __init at91_rtc_init(void) -+{ -+ int ret; -+ -+ AT91_SYS->RTC_CR = 0; -+ AT91_SYS->RTC_MR = 0; /* put in 24 hour format */ -+ /* Disable all interrupts */ -+ AT91_SYS->RTC_IDR = AT91C_RTC_ACKUPD | AT91C_RTC_ALARM | AT91C_RTC_SECEV | AT91C_RTC_TIMEV | AT91C_RTC_CALEV; -+ -+ spin_lock_init(&at91_rtc_updlock); -+ spin_lock_init(&at91_rtc_lock); -+ -+ misc_register(&at91_rtc_miscdev); -+ create_proc_read_entry("driver/rtc", 0, 0, at91_rtc_read_proc, NULL); -+ ret = request_irq(AT91C_ID_SYS, at91_rtc_interrupt, SA_SHIRQ, -+ "at91_rtc", &rtc_status); -+ if (ret) { -+ printk(KERN_ERR "at91_rtc: IRQ %d already in use.\n", AT91C_ID_SYS); -+ remove_proc_entry("driver/rtc", NULL); -+ misc_deregister(&at91_rtc_miscdev); -+ return ret; -+ } -+ -+ printk(KERN_INFO "AT91 Real Time Clock driver\n"); -+ return 0; -+} -+ -+/* -+ * Disable and remove the RTC driver -+ */ -+static void __exit at91_rtc_exit(void) -+{ -+ /* Disable all interrupts */ -+ AT91_SYS->RTC_IDR = AT91C_RTC_ACKUPD | AT91C_RTC_ALARM | AT91C_RTC_SECEV | AT91C_RTC_TIMEV | AT91C_RTC_CALEV; -+ free_irq(AT91C_ID_SYS, &rtc_status); -+ -+ rtc_status = 0; -+ remove_proc_entry("driver/rtc", NULL); -+ misc_deregister(&at91_rtc_miscdev); -+} -+ -+module_init(at91_rtc_init); -+module_exit(at91_rtc_exit); -+ -+MODULE_AUTHOR("Rick Bronson"); -+MODULE_DESCRIPTION("AT91 Realtime Clock Driver (AT91_RTC)"); -+MODULE_LICENSE("GPL"); -+EXPORT_NO_SYMBOLS; -diff -urN linux-2.4.26/drivers/at91/serial/Makefile linux-2.4.26-vrs1/drivers/at91/serial/Makefile ---- linux-2.4.26/drivers/at91/serial/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/serial/Makefile 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,15 @@ -+# File: drivers/at91/serial/Makefile -+# -+# Makefile for the Atmel AT91RM9200 serial and console device drivers -+# -+ -+O_TARGET := at91serial.o -+ -+obj-y := -+obj-m := -+obj-n := -+obj- := -+ -+obj-$(CONFIG_SERIAL_AT91) += at91_serial.o -+ -+include $(TOPDIR)/Rules.make -diff -urN linux-2.4.26/drivers/at91/serial/at91_serial.c linux-2.4.26-vrs1/drivers/at91/serial/at91_serial.c ---- linux-2.4.26/drivers/at91/serial/at91_serial.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/serial/at91_serial.c 2004-04-09 15:12:35.000000000 +0100 -@@ -0,0 +1,870 @@ -+/* -+ * linux/drivers/char/at91_serial.c -+ * -+ * Driver for Atmel AT91RM9200 Serial ports -+ * -+ * Copyright (c) Rick Bronson -+ * -+ * Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd. -+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+ -+#if defined(CONFIG_SERIAL_AT91_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -+#define SUPPORT_SYSRQ -+#endif -+ -+#include -+ -+#define SERIAL_AT91_MAJOR TTY_MAJOR -+#define CALLOUT_AT91_MAJOR TTYAUX_MAJOR -+#define MINOR_START 64 -+ -+#define AT91C_VA_BASE_DBGU ((unsigned long) &(AT91_SYS->DBGU_CR)) -+#define AT91_ISR_PASS_LIMIT 256 -+ -+#define UART_PUT_CR(port,v) ((AT91PS_USART)(port)->membase)->US_CR = v -+#define UART_GET_MR(port) ((AT91PS_USART)(port)->membase)->US_MR -+#define UART_PUT_MR(port,v) ((AT91PS_USART)(port)->membase)->US_MR = v -+#define UART_PUT_IER(port,v) ((AT91PS_USART)(port)->membase)->US_IER = v -+#define UART_PUT_IDR(port,v) ((AT91PS_USART)(port)->membase)->US_IDR = v -+#define UART_GET_IMR(port) ((AT91PS_USART)(port)->membase)->US_IMR -+#define UART_GET_CSR(port) ((AT91PS_USART)(port)->membase)->US_CSR -+#define UART_GET_CHAR(port) ((AT91PS_USART)(port)->membase)->US_RHR -+#define UART_PUT_CHAR(port,v) ((AT91PS_USART)(port)->membase)->US_THR = v -+#define UART_GET_BRGR(port) ((AT91PS_USART)(port)->membase)->US_BRGR -+#define UART_PUT_BRGR(port,v) ((AT91PS_USART)(port)->membase)->US_BRGR = v -+#define UART_PUT_RTOR(port,v) ((AT91PS_USART)(port)->membase)->US_RTOR = v -+ -+// #define UART_GET_CR(port) ((AT91PS_USART)(port)->membase)->US_CR // is write-only -+ -+ /* PDC registers */ -+#define UART_PUT_PTCR(port,v) ((AT91PS_USART)(port)->membase)->US_PTCR = v -+#define UART_PUT_RPR(port,v) ((AT91PS_USART)(port)->membase)->US_RPR = v -+#define UART_PUT_RCR(port,v) ((AT91PS_USART)(port)->membase)->US_RCR = v -+#define UART_GET_RCR(port) ((AT91PS_USART)(port)->membase)->US_RCR -+#define UART_PUT_RNPR(port,v) ((AT91PS_USART)(port)->membase)->US_RNPR = v -+#define UART_PUT_RNCR(port,v) ((AT91PS_USART)(port)->membase)->US_RNCR = v -+ -+static struct tty_driver normal, callout; -+static struct tty_struct *at91_table[AT91C_NR_UART]; -+static struct termios *at91_termios[AT91C_NR_UART], *at91_termios_locked[AT91C_NR_UART]; -+ -+const int at91_serialmap[AT91C_NR_UART] = AT91C_UART_MAP; -+ -+static int (*at91_open)(struct uart_port *); -+static void (*at91_close)(struct uart_port *); -+ -+#ifdef SUPPORT_SYSRQ -+static struct console at91_console; -+#endif -+ -+/* -+ * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty. -+ */ -+static u_int at91_tx_empty(struct uart_port *port) -+{ -+ return UART_GET_CSR(port) & AT91C_US_TXEMPTY ? TIOCSER_TEMT : 0; -+} -+ -+/* -+ * Set state of the modem control output lines -+ */ -+static void at91_set_mctrl(struct uart_port *port, u_int mctrl) -+{ -+ unsigned int control = 0; -+ -+ if (mctrl & TIOCM_RTS) -+ control |= AT91C_US_RTSEN; -+ else -+ control |= AT91C_US_RTSDIS; -+ -+ if (mctrl & TIOCM_DTR) -+ control |= AT91C_US_DTREN; -+ else -+ control |= AT91C_US_DTRDIS; -+ -+ UART_PUT_CR(port,control); -+} -+ -+/* -+ * Get state of the modem control input lines -+ */ -+static u_int at91_get_mctrl(struct uart_port *port) -+{ -+ unsigned int status, ret = 0; -+ -+ status = UART_GET_CSR(port); -+ if (status & AT91C_US_DCD) -+ ret |= TIOCM_CD; -+ if (status & AT91C_US_CTS) -+ ret |= TIOCM_CTS; -+ if (status & AT91C_US_DSR) -+ ret |= TIOCM_DSR; -+ if (status & AT91C_US_RI) -+ ret |= TIOCM_RI; -+ -+ return ret; -+} -+ -+/* -+ * Stop transmitting. -+ */ -+static void at91_stop_tx(struct uart_port *port, u_int from_tty) -+{ -+ UART_PUT_IDR(port, AT91C_US_TXRDY); -+ port->read_status_mask &= ~AT91C_US_TXRDY; -+} -+ -+/* -+ * Start transmitting. -+ */ -+static void at91_start_tx(struct uart_port *port, u_int from_tty) -+{ -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ port->read_status_mask |= AT91C_US_TXRDY; -+ UART_PUT_IER(port, AT91C_US_TXRDY); -+ local_irq_restore(flags); -+} -+ -+/* -+ * Stop receiving - port is in process of being closed. -+ */ -+static void at91_stop_rx(struct uart_port *port) -+{ -+ UART_PUT_IDR(port, AT91C_US_RXRDY); -+} -+ -+/* -+ * Enable modem status interrupts -+ */ -+static void at91_enable_ms(struct uart_port *port) -+{ -+ UART_PUT_IER(port, AT91C_US_RIIC | AT91C_US_DSRIC | AT91C_US_DCDIC | AT91C_US_CTSIC); -+} -+ -+/* -+ * Control the transmission of a break signal -+ */ -+static void at91_break_ctl(struct uart_port *port, int break_state) -+{ -+ if (break_state != 0) -+ UART_PUT_CR(port, AT91C_US_STTBRK); /* start break */ -+ else -+ UART_PUT_CR(port, AT91C_US_STPBRK); /* stop break */ -+} -+ -+/* -+ * Characters received (called from interrupt handler) -+ */ -+static void at91_rx_chars(struct uart_port *port, struct pt_regs *regs) -+{ -+ struct uart_info *info = port->info; -+ struct tty_struct *tty = info->tty; -+ unsigned int status, ch, flg, ignored = 0; -+ -+ status = UART_GET_CSR(port); -+ while (status & (AT91C_US_RXRDY)) { -+ ch = UART_GET_CHAR(port); -+ -+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) -+ goto ignore_char; -+ port->icount.rx++; -+ -+ flg = TTY_NORMAL; -+ -+ /* -+ * note that the error handling code is -+ * out of the main execution path -+ */ -+ if (status & (AT91C_US_PARE | AT91C_US_FRAME | AT91C_US_OVRE)) -+ goto handle_error; -+ -+ if (uart_handle_sysrq_char(port, ch, regs)) -+ goto ignore_char; -+ -+ error_return: -+ *tty->flip.flag_buf_ptr++ = flg; -+ *tty->flip.char_buf_ptr++ = ch; -+ tty->flip.count++; -+ ignore_char: -+ status = UART_GET_CSR(port); -+ } -+out: -+ tty_flip_buffer_push(tty); -+ return; -+ -+handle_error: -+ if (status & (AT91C_US_PARE | AT91C_US_FRAME | AT91C_US_OVRE)) -+ UART_PUT_CR(port, AT91C_US_RSTSTA); /* clear error */ -+ if (status & (AT91C_US_PARE)) -+ port->icount.parity++; -+ else if (status & (AT91C_US_FRAME)) -+ port->icount.frame++; -+ if (status & (AT91C_US_OVRE)) -+ port->icount.overrun++; -+ -+ if (status & port->ignore_status_mask) { -+ if (++ignored > 100) -+ goto out; -+ goto ignore_char; -+ } -+ -+ status &= port->read_status_mask; -+ -+ UART_PUT_CR(port, AT91C_US_RSTSTA); /* clear error */ -+ if (status & AT91C_US_PARE) -+ flg = TTY_PARITY; -+ else if (status & AT91C_US_FRAME) -+ flg = TTY_FRAME; -+ -+ if (status & AT91C_US_OVRE) { -+ /* -+ * overrun does *not* affect the character -+ * we read from the FIFO -+ */ -+ *tty->flip.flag_buf_ptr++ = flg; -+ *tty->flip.char_buf_ptr++ = ch; -+ tty->flip.count++; -+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) -+ goto ignore_char; -+ ch = 0; -+ flg = TTY_OVERRUN; -+ } -+#ifdef SUPPORT_SYSRQ -+ port->sysrq = 0; -+#endif -+ goto error_return; -+} -+ -+/* -+ * Transmit characters (called from interrupt handler) -+ */ -+static void at91_tx_chars(struct uart_port *port) -+{ -+ struct circ_buf *xmit = &port->info->xmit; -+ -+ if (port->x_char) { -+ UART_PUT_CHAR(port, port->x_char); -+ port->icount.tx++; -+ port->x_char = 0; -+ return; -+ } -+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { -+ at91_stop_tx(port, 0); -+ return; -+ } -+ -+ while (UART_GET_CSR(port) & AT91C_US_TXRDY) { -+ UART_PUT_CHAR(port, xmit->buf[xmit->tail]); -+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); -+ port->icount.tx++; -+ if (uart_circ_empty(xmit)) -+ break; -+ } -+ -+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) -+ uart_write_wakeup(port); -+ -+ if (uart_circ_empty(xmit)) -+ at91_stop_tx(port, 0); -+} -+ -+/* -+ * Interrupt handler -+ */ -+static void at91_interrupt(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ struct uart_port *port = dev_id; -+ unsigned int status, pending, pass_counter = 0; -+ -+ status = UART_GET_CSR(port); -+ pending = status & port->read_status_mask; -+ if (pending) { -+ do { -+ if (pending & AT91C_US_RXRDY) -+ at91_rx_chars(port, regs); -+ -+ /* Clear the relevent break bits */ -+ if (pending & AT91C_US_RXBRK) { -+ UART_PUT_CR(port, AT91C_US_RSTSTA); -+ port->icount.brk++; -+#ifdef SUPPORT_SYSRQ -+ if (port->line == at91_console.index && !port->sysrq) { -+ port->sysrq = jiffies + HZ*5; -+ } -+#endif -+ } -+ -+ // TODO: All reads to CSR will clear these interrupts! -+ if (pending & AT91C_US_RIIC) port->icount.rng++; -+ if (pending & AT91C_US_DSRIC) port->icount.dsr++; -+ if (pending & AT91C_US_DCDIC) { -+ port->icount.dcd++; -+ uart_handle_dcd_change(port, status & AT91C_US_DCD); -+ } -+ if (pending & AT91C_US_CTSIC) { -+ port->icount.cts++; -+ uart_handle_cts_change(port, status & AT91C_US_CTS); -+ } -+ if (pending & (AT91C_US_RIIC | AT91C_US_DSRIC | AT91C_US_DCDIC | AT91C_US_CTSIC)) -+ wake_up_interruptible(&port->info->delta_msr_wait); -+ -+ if (pending & AT91C_US_TXRDY) -+ at91_tx_chars(port); -+ if (pass_counter++ > AT91_ISR_PASS_LIMIT) -+ break; -+ -+ status = UART_GET_CSR(port); -+ pending = status & port->read_status_mask; -+ } while (pending); -+ } -+} -+ -+/* -+ * Perform initialization and enable port for reception -+ */ -+static int at91_startup(struct uart_port *port) -+{ -+ int retval; -+ -+ /* -+ * Allocate the IRQ -+ */ -+ retval = request_irq(port->irq, at91_interrupt, SA_SHIRQ, "at91_serial", port); -+ if (retval) { -+ printk("at91_serial: at91_startup - Can't get irq\n"); -+ return retval; -+ } -+ /* -+ * If there is a specific "open" function (to register -+ * control line interrupts) -+ */ -+ if (at91_open) { -+ retval = at91_open(port); -+ if (retval) { -+ free_irq(port->irq, port); -+ return retval; -+ } -+ } -+ -+ /* Enable peripheral clock if required */ -+ if (port->irq != AT91C_ID_SYS) -+ AT91_SYS->PMC_PCER = 1 << port->irq; -+ -+ port->read_status_mask = AT91C_US_RXRDY | AT91C_US_TXRDY | AT91C_US_OVRE -+ | AT91C_US_FRAME | AT91C_US_PARE | AT91C_US_RXBRK; -+ /* -+ * Finally, clear and enable interrupts -+ */ -+ UART_PUT_IDR(port, -1); -+ UART_PUT_CR(port, AT91C_US_TXEN | AT91C_US_RXEN); /* enable xmit & rcvr */ -+ UART_PUT_IER(port, AT91C_US_RXRDY); /* do receive only */ -+ return 0; -+} -+ -+/* -+ * Disable the port -+ */ -+static void at91_shutdown(struct uart_port *port) -+{ -+ /* -+ * Free the interrupt -+ */ -+ free_irq(port->irq, port); -+ -+ /* -+ * If there is a specific "close" function (to unregister -+ * control line interrupts) -+ */ -+ if (at91_close) -+ at91_close(port); -+ -+ /* -+ * Disable all interrupts, port and break condition. -+ */ -+ UART_PUT_CR(port, AT91C_US_RSTSTA); -+ UART_PUT_IDR(port, -1); -+ -+ /* Disable peripheral clock if required */ -+ if (port->irq != AT91C_ID_SYS) -+ AT91_SYS->PMC_PCDR = 1 << port->irq; -+} -+ -+static struct uart_ops at91_pops; /* forward declaration */ -+ -+/* -+ * Change the port parameters -+ */ -+static void at91_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot) -+{ -+ unsigned long flags; -+ unsigned int mode, imr; -+ -+ /* Get current mode register */ -+ mode = UART_GET_MR(port) & ~(AT91C_US_CHRL | AT91C_US_NBSTOP | AT91C_US_PAR); -+ -+ /* byte size */ -+ switch (cflag & CSIZE) { -+ case CS5: -+ mode |= AT91C_US_CHRL_5_BITS; -+ break; -+ case CS6: -+ mode |= AT91C_US_CHRL_6_BITS; -+ break; -+ case CS7: -+ mode |= AT91C_US_CHRL_7_BITS; -+ break; -+ default: -+ mode |= AT91C_US_CHRL_8_BITS; -+ break; -+ } -+ -+ /* stop bits */ -+ if (cflag & CSTOPB) -+ mode |= AT91C_US_NBSTOP_2_BIT; -+ -+ /* parity */ -+ if (cflag & PARENB) { -+ if (cflag & CMSPAR) { /* Mark or Space parity */ -+ if (cflag & PARODD) -+ mode |= AT91C_US_PAR_MARK; -+ else -+ mode |= AT91C_US_PAR_SPACE; -+ } -+ else if (cflag & PARODD) -+ mode |= AT91C_US_PAR_ODD; -+ else -+ mode |= AT91C_US_PAR_EVEN; -+ } -+ else -+ mode |= AT91C_US_PAR_NONE; -+ -+ port->read_status_mask |= AT91C_US_OVRE; -+ if (iflag & INPCK) -+ port->read_status_mask |= AT91C_US_FRAME | AT91C_US_PARE; -+ if (iflag & (BRKINT | PARMRK)) -+ port->read_status_mask |= AT91C_US_RXBRK; -+ -+ /* -+ * Characters to ignore -+ */ -+ port->ignore_status_mask = 0; -+ if (iflag & IGNPAR) -+ port->ignore_status_mask |= (AT91C_US_FRAME | AT91C_US_PARE); -+ if (iflag & IGNBRK) { -+ port->ignore_status_mask |= AT91C_US_RXBRK; -+ /* -+ * If we're ignoring parity and break indicators, -+ * ignore overruns too (for real raw support). -+ */ -+ if (iflag & IGNPAR) -+ port->ignore_status_mask |= AT91C_US_OVRE; -+ } -+ -+ // TODO: Ignore all characters if CREAD is set. -+ -+ /* first, disable interrupts and drain transmitter */ -+ local_irq_save(flags); -+ imr = UART_GET_IMR(port); /* get interrupt mask */ -+ UART_PUT_IDR(port, -1); /* disable all interrupts */ -+ local_irq_restore(flags); -+ while (!(UART_GET_CSR(port) & AT91C_US_TXEMPTY)) { barrier(); } -+ -+ /* disable receiver and transmitter */ -+ UART_PUT_CR(port, AT91C_US_TXDIS | AT91C_US_RXDIS); -+ -+ /* set the parity, stop bits and data size */ -+ UART_PUT_MR(port, mode); -+ -+ /* set the baud rate */ -+ UART_PUT_BRGR(port, quot); -+ UART_PUT_CR(port, AT91C_US_TXEN | AT91C_US_RXEN); -+ -+ /* restore interrupts */ -+ UART_PUT_IER(port, imr); -+ -+ /* CTS flow-control and modem-status interrupts */ -+ if (UART_ENABLE_MS(port, cflag)) -+ at91_pops.enable_ms(port); -+} -+ -+/* -+ * Return string describing the specified port -+ */ -+static const char *at91_type(struct uart_port *port) -+{ -+ return port->type == PORT_AT91RM9200 ? "AT91_SERIAL" : NULL; -+} -+ -+/* -+ * Release the memory region(s) being used by 'port'. -+ */ -+static void at91_release_port(struct uart_port *port) -+{ -+ release_mem_region(port->mapbase, -+ port->mapbase == AT91C_VA_BASE_DBGU ? 512 : SZ_16K); -+} -+ -+/* -+ * Request the memory region(s) being used by 'port'. -+ */ -+static int at91_request_port(struct uart_port *port) -+{ -+ return request_mem_region(port->mapbase, -+ port->mapbase == AT91C_VA_BASE_DBGU ? 512 : SZ_16K, -+ "at91_serial") != NULL ? 0 : -EBUSY; -+ -+} -+ -+/* -+ * Configure/autoconfigure the port. -+ */ -+static void at91_config_port(struct uart_port *port, int flags) -+{ -+ if (flags & UART_CONFIG_TYPE) { -+ port->type = PORT_AT91RM9200; -+ at91_request_port(port); -+ } -+} -+ -+/* -+ * Verify the new serial_struct (for TIOCSSERIAL). -+ */ -+static int at91_verify_port(struct uart_port *port, struct serial_struct *ser) -+{ -+ int ret = 0; -+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_AT91RM9200) -+ ret = -EINVAL; -+ if (port->irq != ser->irq) -+ ret = -EINVAL; -+ if (ser->io_type != SERIAL_IO_MEM) -+ ret = -EINVAL; -+ if (port->uartclk / 16 != ser->baud_base) -+ ret = -EINVAL; -+ if ((void *)port->mapbase != ser->iomem_base) -+ ret = -EINVAL; -+ if (port->iobase != ser->port) -+ ret = -EINVAL; -+ if (ser->hub6 != 0) -+ ret = -EINVAL; -+ return ret; -+} -+ -+static struct uart_ops at91_pops = { -+ tx_empty: at91_tx_empty, -+ set_mctrl: at91_set_mctrl, -+ get_mctrl: at91_get_mctrl, -+ stop_tx: at91_stop_tx, -+ start_tx: at91_start_tx, -+ stop_rx: at91_stop_rx, -+ enable_ms: at91_enable_ms, -+ break_ctl: at91_break_ctl, -+ startup: at91_startup, -+ shutdown: at91_shutdown, -+ change_speed: at91_change_speed, -+ type: at91_type, -+ release_port: at91_release_port, -+ request_port: at91_request_port, -+ config_port: at91_config_port, -+ verify_port: at91_verify_port, -+}; -+ -+static struct uart_port at91_ports[AT91C_NR_UART]; -+ -+void __init at91_init_ports(void) -+{ -+ static int first = 1; -+ int i; -+ -+ if (!first) -+ return; -+ first = 0; -+ -+ for (i = 0; i < AT91C_NR_UART; i++) { -+ at91_ports[i].iotype = SERIAL_IO_MEM; -+ at91_ports[i].flags = ASYNC_BOOT_AUTOCONF; -+ at91_ports[i].uartclk = AT91C_MASTER_CLOCK; -+ at91_ports[i].ops = &at91_pops; -+ at91_ports[i].fifosize = 1; -+ at91_ports[i].line = i; -+ } -+} -+ -+void __init at91_register_uart_fns(struct at91rm9200_port_fns *fns) -+{ -+ if (fns->enable_ms) -+ at91_pops.enable_ms = fns->enable_ms; -+ if (fns->get_mctrl) -+ at91_pops.get_mctrl = fns->get_mctrl; -+ if (fns->set_mctrl) -+ at91_pops.set_mctrl = fns->set_mctrl; -+ at91_open = fns->open; -+ at91_close = fns->close; -+ at91_pops.pm = fns->pm; -+ at91_pops.set_wake = fns->set_wake; -+} -+ -+/* -+ * Setup ports. -+ */ -+void __init at91_register_uart(int idx, int port) -+{ -+ if ((idx < 0) || (idx >= AT91C_NR_UART)) { -+ printk(KERN_ERR __FUNCTION__ ": bad index number %d\n", idx); -+ return; -+ } -+ -+ switch (port) { -+ case 0: -+ at91_ports[idx].membase = (void *) AT91C_VA_BASE_US0; -+ at91_ports[idx].mapbase = AT91C_VA_BASE_US0; -+ at91_ports[idx].irq = AT91C_ID_US0; -+ AT91_CfgPIO_USART0(); -+ break; -+ case 1: -+ at91_ports[idx].membase = (void *) AT91C_VA_BASE_US1; -+ at91_ports[idx].mapbase = AT91C_VA_BASE_US1; -+ at91_ports[idx].irq = AT91C_ID_US1; -+ AT91_CfgPIO_USART1(); -+ break; -+ case 2: -+ at91_ports[idx].membase = (void *) AT91C_VA_BASE_US2; -+ at91_ports[idx].mapbase = AT91C_VA_BASE_US2; -+ at91_ports[idx].irq = AT91C_ID_US2; -+ AT91_CfgPIO_USART2(); -+ break; -+ case 3: -+ at91_ports[idx].membase = (void *) AT91C_VA_BASE_US3; -+ at91_ports[idx].mapbase = AT91C_VA_BASE_US3; -+ at91_ports[idx].irq = AT91C_ID_US3; -+ AT91_CfgPIO_USART3(); -+ break; -+ case 4: -+ at91_ports[idx].membase = (void *) AT91C_VA_BASE_DBGU; -+ at91_ports[idx].mapbase = AT91C_VA_BASE_DBGU; -+ at91_ports[idx].irq = AT91C_ID_SYS; -+ AT91_CfgPIO_DBGU(); -+ break; -+ default: -+ printk(KERN_ERR __FUNCTION__ ": bad port number %d\n", port); -+ } -+} -+ -+#ifdef CONFIG_SERIAL_AT91_CONSOLE -+ -+/* -+ * Interrupts are disabled on entering -+ */ -+static void at91_console_write(struct console *co, const char *s, u_int count) -+{ -+ struct uart_port *port = at91_ports + co->index; -+ unsigned int status, i, imr; -+ -+ /* -+ * First, save IMR and then disable interrupts -+ */ -+ imr = UART_GET_IMR(port); /* get interrupt mask */ -+ UART_PUT_IDR(port, AT91C_US_RXRDY | AT91C_US_TXRDY); -+ -+ /* -+ * Now, do each character -+ */ -+ for (i = 0; i < count; i++) { -+ do { -+ status = UART_GET_CSR(port); -+ } while (!(status & AT91C_US_TXRDY)); -+ UART_PUT_CHAR(port, s[i]); -+ if (s[i] == '\n') { -+ do { -+ status = UART_GET_CSR(port); -+ } while (!(status & AT91C_US_TXRDY)); -+ UART_PUT_CHAR(port, '\r'); -+ } -+ } -+ -+ /* -+ * Finally, wait for transmitter to become empty -+ * and restore IMR -+ */ -+ do { -+ status = UART_GET_CSR(port); -+ } while (status & AT91C_US_TXRDY); -+ UART_PUT_IER(port, imr); /* set interrupts back the way they were */ -+} -+ -+static kdev_t at91_console_device(struct console *co) -+{ -+ return MKDEV(SERIAL_AT91_MAJOR, MINOR_START + co->index); -+} -+ -+/* -+ * If the port was already initialised (eg, by a boot loader), try to determine -+ * the current setup. -+ */ -+static void __init at91_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) -+{ -+ unsigned int mr, quot; -+ -+// TODO: CR is a write-only register -+// unsigned int cr; -+// -+// cr = UART_GET_CR(port) & (AT91C_US_RXEN | AT91C_US_TXEN); -+// if (cr == (AT91C_US_RXEN | AT91C_US_TXEN)) { -+// /* ok, the port was enabled */ -+// -+// mr = UART_GET_MR(port) & AT91C_US_PAR; -+// -+// *parity = 'n'; -+// if (mr == AT91C_US_PAR_EVEN) -+// *parity = 'e'; -+// else if (mr == AT91C_US_PAR_ODD) -+// *parity = 'o'; -+// } -+ -+ mr = UART_GET_MR(port) & AT91C_US_CHRL; -+ if (mr == AT91C_US_CHRL_8_BITS) -+ *bits = 8; -+ else -+ *bits = 7; -+ -+ quot = UART_GET_BRGR(port); -+ *baud = port->uartclk / (16 * (quot)); -+} -+ -+static int __init at91_console_setup(struct console *co, char *options) -+{ -+ struct uart_port *port; -+ int baud = AT91C_CONSOLE_DEFAULT_BAUDRATE; -+ int bits = 8; -+ int parity = 'n'; -+ int flow = 'n'; -+ -+ /* -+ * Check whether an invalid uart number has been specified, and -+ * if so, search for the first available port that does have -+ * console support. -+ */ -+ port = uart_get_console(at91_ports, AT91C_NR_UART, co); -+ -+ // TODO: The console port should be initialized, and clock enabled if -+ // we're not relying on the bootloader to do it. -+ -+ if (options) -+ uart_parse_options(options, &baud, &parity, &bits, &flow); -+ else -+ at91_console_get_options(port, &baud, &parity, &bits); -+ -+ return uart_set_options(port, co, baud, parity, bits, flow); -+} -+ -+static struct console at91_console = { -+ name: "ttyS", -+ write: at91_console_write, -+ device: at91_console_device, -+ setup: at91_console_setup, -+ flags: CON_PRINTBUFFER, -+ index: AT91C_CONSOLE, -+}; -+ -+#define AT91_CONSOLE_DEVICE &at91_console -+ -+void __init at91_console_init(void) -+{ -+ at91_init_ports(); -+ register_console(&at91_console); -+} -+ -+#else -+#define AT91_CONSOLE_DEVICE NULL -+#endif -+ -+static struct uart_driver at91_reg = { -+ owner: THIS_MODULE, -+ normal_major: SERIAL_AT91_MAJOR, -+#ifdef CONFIG_DEVFS_FS -+ normal_name: "ttyS%d", -+ callout_name: "cua%d", -+#else -+ normal_name: "ttyS", -+ callout_name: "cua", -+#endif -+ normal_driver: &normal, -+ callout_major: CALLOUT_AT91_MAJOR, -+ callout_driver: &callout, -+ table: at91_table, -+ termios: at91_termios, -+ termios_locked: at91_termios_locked, -+ minor: MINOR_START, -+ nr: AT91C_NR_UART, -+ cons: AT91_CONSOLE_DEVICE, -+}; -+ -+static int __init at91_serial_init(void) -+{ -+ int ret, i; -+ -+ at91_init_ports(); -+ -+ ret = uart_register_driver(&at91_reg); -+ if (ret) -+ return ret; -+ -+ for (i = 0; i < AT91C_NR_UART; i++) { -+ if (at91_serialmap[i] >= 0) -+ uart_add_one_port(&at91_reg, &at91_ports[i]); -+ } -+ -+ return 0; -+} -+ -+static void __exit at91_serial_exit(void) -+{ -+ int i; -+ -+ for (i = 0; i < AT91C_NR_UART; i++) { -+ if (at91_serialmap[i] >= 0) -+ uart_remove_one_port(&at91_reg, &at91_ports[i]); -+ } -+ -+ uart_unregister_driver(&at91_reg); -+} -+ -+module_init(at91_serial_init); -+module_exit(at91_serial_exit); -+ -+EXPORT_NO_SYMBOLS; -+ -+MODULE_AUTHOR("Rick Bronson"); -+MODULE_DESCRIPTION("AT91 generic serial port driver"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.4.26/drivers/at91/spi/Makefile linux-2.4.26-vrs1/drivers/at91/spi/Makefile ---- linux-2.4.26/drivers/at91/spi/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/spi/Makefile 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,17 @@ -+# File: drivers/at91/spi/Makefile -+# -+# Makefile for the Atmel AT91RM9200 SPI device drivers -+# -+ -+O_TARGET := at91spi.o -+ -+export-objs := at91_spi.o -+ -+obj-y := at91_spi.o -+obj-m := -+obj-n := -+obj- := -+ -+obj-$(CONFIG_AT91_SPIDEV) += at91_spidev.o -+ -+include $(TOPDIR)/Rules.make -diff -urN linux-2.4.26/drivers/at91/spi/at91_spi.c linux-2.4.26-vrs1/drivers/at91/spi/at91_spi.c ---- linux-2.4.26/drivers/at91/spi/at91_spi.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/spi/at91_spi.c 2004-04-10 12:23:48.000000000 +0100 -@@ -0,0 +1,275 @@ -+/* -+ * Serial Peripheral Interface (SPI) driver for the Atmel AT91RM9200 (Thunder) -+ * -+ * (c) SAN People (Pty) Ltd -+ * -+ * 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. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include "at91_spi.h" -+ -+#undef DEBUG_SPI -+ -+static struct spi_local spi_dev[NR_SPI_DEVICES]; /* state of the SPI devices */ -+static int spi_enabled = 0; -+static struct semaphore spi_lock; /* protect access to SPI bus */ -+static int current_device = -1; /* currently selected SPI device */ -+ -+DECLARE_COMPLETION(transfer_complete); -+ -+/* SPI controller device */ -+static AT91PS_SPI controller = (AT91PS_SPI) AT91C_VA_BASE_SPI; -+ -+/* ......................................................................... */ -+ -+/* -+ * Access and enable the SPI bus. -+ * This MUST be called before any transfers are performed. -+ */ -+void spi_access_bus(short device) -+{ -+ /* Ensure that requested device is valid */ -+ if ((device < 0) || (device >= NR_SPI_DEVICES)) -+ panic("at91_spi: spi_access_bus called with invalid device"); -+ -+ if (spi_enabled == 0) { -+ AT91_SYS->PMC_PCER = 1 << AT91C_ID_SPI; /* Enable Peripheral clock */ -+ controller->SPI_CR = AT91C_SPI_SPIEN; /* Enable SPI */ -+#ifdef DEBUG_SPI -+ printk("SPI on\n"); -+#endif -+ } -+ MOD_INC_USE_COUNT; -+ spi_enabled++; -+ -+ /* Lock the SPI bus */ -+ down(&spi_lock); -+ current_device = device; -+ -+ /* Enable PIO */ -+ if (!spi_dev[device].pio_enabled) { -+ switch (device) { -+ case 0: AT91_CfgPIO_SPI_CS0(); -+ case 1: AT91_CfgPIO_SPI_CS1(); -+ case 2: AT91_CfgPIO_SPI_CS2(); -+ case 3: AT91_CfgPIO_SPI_CS3(); -+ } -+ spi_dev[device].pio_enabled = 1; -+#ifdef DEBUG_SPI -+ printk("SPI CS%i enabled\n", device); -+#endif -+ } -+ -+ /* Configure SPI bus for device */ -+ controller->SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | (spi_dev[device].pcs << 16); -+} -+ -+/* -+ * Relinquish control of the SPI bus. -+ */ -+void spi_release_bus(short device) -+{ -+ if (device != current_device) -+ panic("at91_spi: spi_release called with invalid device"); -+ -+ /* Release the SPI bus */ -+ current_device = -1; -+ up(&spi_lock); -+ -+ spi_enabled--; -+ MOD_DEC_USE_COUNT; -+ if (spi_enabled == 0) { -+ controller->SPI_CR = AT91C_SPI_SPIDIS; /* Disable SPI */ -+ AT91_SYS->PMC_PCER = 1 << AT91C_ID_SPI; /* Disable Peripheral clock */ -+#ifdef DEBUG_SPI -+ printk("SPI off\n"); -+#endif -+ } -+} -+ -+/* -+ * Perform a data transfer over the SPI bus -+ */ -+int spi_transfer(struct spi_transfer_list* list) -+{ -+ struct spi_local *device = (struct spi_local *) &spi_dev[current_device]; -+ -+ if (!list) -+ panic("at91_spi: spi_transfer called with NULL transfer list"); -+ if (current_device == -1) -+ panic("at91_spi: spi_transfer called without acquiring bus"); -+ -+#ifdef DEBUG_SPI -+ printk("SPI transfer start [%i]\n", list->nr_transfers); -+#endif -+ -+ /* Store transfer list */ -+ device->xfers = list; -+ list->curr = 0; -+ -+ /* Assume there must be at least one transfer */ -+ device->tx = pci_map_single(NULL, list->tx[0], list->txlen[0], PCI_DMA_TODEVICE); -+ device->rx = pci_map_single(NULL, list->rx[0], list->rxlen[0], PCI_DMA_FROMDEVICE); -+ -+ /* Program PDC registers */ -+ controller->SPI_TPR = device->tx; -+ controller->SPI_RPR = device->rx; -+ controller->SPI_TCR = list->txlen[0]; -+ controller->SPI_RCR = list->rxlen[0]; -+ -+ /* Is there a second transfer? */ -+ if (list->nr_transfers > 1) { -+ device->txnext = pci_map_single(NULL, list->tx[1], list->txlen[1], PCI_DMA_TODEVICE); -+ device->rxnext = pci_map_single(NULL, list->rx[1], list->rxlen[1], PCI_DMA_FROMDEVICE); -+ -+ /* Program Next PDC registers */ -+ controller->SPI_TNPR = device->txnext; -+ controller->SPI_RNPR = device->rxnext; -+ controller->SPI_TNCR = list->txlen[1]; -+ controller->SPI_RNCR = list->rxlen[1]; -+ } -+ else { -+ device->txnext = 0; -+ device->rxnext = 0; -+ controller->SPI_TNCR = 0; -+ controller->SPI_RNCR = 0; -+ } -+ -+ // TODO: If we are doing consecutive transfers (at high speed, or -+ // small buffers), then it might be worth modifying the 'Delay between -+ // Consecutive Transfers' in the CSR registers. -+ // This is an issue if we cannot chain the next buffer fast enough -+ // in the interrupt handler. -+ -+ /* Enable transmitter and receiver */ -+ controller->SPI_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN; -+ -+ controller->SPI_IER = AT91C_SPI_SPENDRX; /* enable buffer complete interrupt */ -+ wait_for_completion(&transfer_complete); -+ -+#ifdef DEBUG_SPI -+ printk("SPI transfer end\n"); -+#endif -+ -+ return 0; -+} -+ -+/* ......................................................................... */ -+ -+/* -+ * Handle interrupts from the SPI controller. -+ */ -+static void spi_interrupt(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ unsigned int status; -+ struct spi_local *device = (struct spi_local *) &spi_dev[current_device]; -+ struct spi_transfer_list *list = device->xfers; -+ -+#ifdef DEBUG_SPI -+ printk("SPI interrupt %i\n", current_device); -+#endif -+ -+ if (!list) -+ panic("at91_spi: spi_interrupt with a NULL transfer list"); -+ -+ status = controller->SPI_SR & controller->SPI_IMR; /* read status */ -+ -+ pci_unmap_single(NULL, device->tx, list->txlen[list->curr], PCI_DMA_TODEVICE); -+ pci_unmap_single(NULL, device->rx, list->rxlen[list->curr], PCI_DMA_FROMDEVICE); -+ -+ device->tx = device->txnext; /* move next transfer to current transfer */ -+ device->rx = device->rxnext; -+ -+ list->curr = list->curr + 1; -+ if (list->curr == list->nr_transfers) { /* all transfers complete */ -+ controller->SPI_IDR = AT91C_SPI_SPENDRX; /* disable interrupt */ -+ -+ /* Disable transmitter and receiver */ -+ controller->SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS; -+ -+ device->xfers = NULL; -+ complete(&transfer_complete); -+ } -+ else if (list->curr+1 == list->nr_transfers) { /* no more next transfers */ -+ device->txnext = 0; -+ device->rxnext = 0; -+ controller->SPI_TNCR = 0; -+ controller->SPI_RNCR = 0; -+ } -+ else { -+ int i = (list->curr)+1; -+ -+ device->txnext = pci_map_single(NULL, list->tx[i], list->txlen[i], PCI_DMA_TODEVICE); -+ device->rxnext = pci_map_single(NULL, list->rx[i], list->rxlen[i], PCI_DMA_FROMDEVICE); -+ controller->SPI_TNPR = device->txnext; -+ controller->SPI_RNPR = device->rxnext; -+ controller->SPI_TNCR = list->txlen[i]; -+ controller->SPI_RNCR = list->rxlen[i]; -+ } -+} -+ -+/* ......................................................................... */ -+ -+/* -+ * Initialize the SPI controller -+ */ -+static int __init at91_spi_init(void) -+{ -+ init_MUTEX(&spi_lock); -+ -+ AT91_CfgPIO_SPI(); -+ -+ controller->SPI_CR = AT91C_SPI_SWRST; /* software reset of SPI controller */ -+ -+ /* Set Chip Select registers to good defaults */ -+ controller->SPI_CSR0 = AT91C_SPI_CPOL | AT91C_SPI_BITS_8 | (16 << 16) | (DEFAULT_SPI_BAUD << 8); -+ controller->SPI_CSR1 = AT91C_SPI_CPOL | AT91C_SPI_BITS_8 | (16 << 16) | (DEFAULT_SPI_BAUD << 8); -+ controller->SPI_CSR2 = AT91C_SPI_CPOL | AT91C_SPI_BITS_8 | (16 << 16) | (DEFAULT_SPI_BAUD << 8); -+ controller->SPI_CSR3 = AT91C_SPI_CPOL | AT91C_SPI_BITS_8 | (16 << 16) | (DEFAULT_SPI_BAUD << 8); -+ -+ controller->SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS; -+ -+ memset(&spi_dev, 0, sizeof(spi_dev)); -+ spi_dev[0].pcs = 0xE; -+ spi_dev[1].pcs = 0xD; -+ spi_dev[2].pcs = 0xB; -+ spi_dev[3].pcs = 0x7; -+ -+ if (request_irq(AT91C_ID_SPI, spi_interrupt, 0, "spi", NULL)) -+ return -EBUSY; -+ -+ controller->SPI_CR = AT91C_SPI_SPIEN; /* Enable SPI */ -+ -+ return 0; -+} -+ -+static void at91_spi_exit(void) -+{ -+ controller->SPI_CR = AT91C_SPI_SPIDIS; /* Disable SPI */ -+ -+ free_irq(AT91C_ID_SPI, 0); -+} -+ -+ -+EXPORT_SYMBOL(spi_access_bus); -+EXPORT_SYMBOL(spi_release_bus); -+EXPORT_SYMBOL(spi_transfer); -+ -+module_init(at91_spi_init); -+module_exit(at91_spi_exit); -+ -+MODULE_LICENSE("GPL") -+MODULE_AUTHOR("Andrew Victor") -+MODULE_DESCRIPTION("SPI driver for Atmel AT91RM9200") -diff -urN linux-2.4.26/drivers/at91/spi/at91_spi.h linux-2.4.26-vrs1/drivers/at91/spi/at91_spi.h ---- linux-2.4.26/drivers/at91/spi/at91_spi.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/spi/at91_spi.h 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,56 @@ -+/* -+ * Serial Peripheral Interface (SPI) driver for the Atmel AT91RM9200 -+ * -+ * (c) SAN People (Pty) Ltd -+ * -+ * 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. -+ */ -+ -+#ifndef AT91_SPI_H -+#define AT91_SPI_H -+ -+/* Maximum number of buffers in a single SPI transfer. -+ * DataFlash uses maximum of 2 -+ * spidev interface supports up to 8. -+ */ -+#define MAX_SPI_TRANSFERS 8 -+ -+#define NR_SPI_DEVICES 4 /* number of devices on SPI bus */ -+ -+#define DATAFLASH_CLK 6000000 -+#define DEFAULT_SPI_BAUD AT91C_MASTER_CLOCK / (2 * DATAFLASH_CLK) -+ -+#define SPI_MAJOR 153 /* registered device number */ -+ -+/* -+ * Describes the buffers for a SPI transfer. -+ * A transmit & receive buffer must be specified for each transfer -+ */ -+struct spi_transfer_list { -+ void* tx[MAX_SPI_TRANSFERS]; /* transmit */ -+ int txlen[MAX_SPI_TRANSFERS]; -+ void* rx[MAX_SPI_TRANSFERS]; /* receive */ -+ int rxlen[MAX_SPI_TRANSFERS]; -+ int nr_transfers; /* number of transfers */ -+ int curr; /* current transfer */ -+}; -+ -+struct spi_local { -+ unsigned int pcs; /* Peripheral Chip Select value */ -+ short pio_enabled; /* has PIO been enabled? */ -+ -+ struct spi_transfer_list *xfers; /* current transfer list */ -+ dma_addr_t tx, rx; /* DMA address for current transfer */ -+ dma_addr_t txnext, rxnext; /* DMA address for next transfer */ -+}; -+ -+ -+/* Exported functions */ -+extern void spi_access_bus(short device); -+extern void spi_release_bus(short device); -+extern int spi_transfer(struct spi_transfer_list* list); -+ -+#endif -diff -urN linux-2.4.26/drivers/at91/spi/at91_spidev.c linux-2.4.26-vrs1/drivers/at91/spi/at91_spidev.c ---- linux-2.4.26/drivers/at91/spi/at91_spidev.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/spi/at91_spidev.c 2004-04-10 12:23:48.000000000 +0100 -@@ -0,0 +1,226 @@ -+/* -+ * User-space interface to the SPI bus on Atmel AT91RM9200 -+ * -+ * (c) SAN People (Pty) Ltd -+ * -+ * Based on SPI driver by Rick Bronson -+ * -+ * 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. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_DEVFS_FS -+#include -+#endif -+ -+#include "at91_spi.h" -+ -+#undef DEBUG_SPIDEV -+ -+#ifdef CONFIG_DEVFS_FS -+static devfs_handle_t devfs_handle = NULL; -+static devfs_handle_t devfs_spi[NR_SPI_DEVICES]; -+#endif -+ -+/* ......................................................................... */ -+ -+/* -+ * Read or Write to SPI bus. -+ */ -+static ssize_t spidev_rd_wr(struct file *file, char *buf, size_t count, loff_t *offset) -+{ -+ unsigned int spi_device = (unsigned int) file->private_data; -+ struct kiobuf *iobuf; -+ unsigned int ofs, pagelen; -+ int res, i; -+ -+ struct spi_transfer_list* list = kmalloc(sizeof(struct spi_transfer_list), GFP_KERNEL); -+ if (!list) -+ return -ENOMEM; -+ -+ res = alloc_kiovec(1, &iobuf); -+ if (res) { -+ kfree(list); -+ return res; -+ } -+ -+ res = map_user_kiobuf(READ, iobuf, (unsigned long) buf, count); -+ if (res) { -+ free_kiovec(1, &iobuf); -+ kfree(list); -+ return res; -+ } -+ -+ /* More pages than transfer slots in spi_transfer_list */ -+ if (iobuf->nr_pages >= MAX_SPI_TRANSFERS) { -+ unmap_kiobuf(iobuf); -+ free_kiovec(1, &iobuf); -+ kfree(list); -+ return -EFBIG; -+ } -+ -+#ifdef DEBUG_SPIDEV -+ printk("spidev_rd_rw: %i %i\n", count, iobuf->nr_pages); -+#endif -+ -+ /* Set default return value = transfer length */ -+ res = count; -+ -+ /* -+ * At this point, the virtual area buf[0] .. buf[count-1] will have -+ * corresponding pages mapped in the physical memory and locked until -+ * we unmap the kiobuf. The pages cannot be swapped out or moved -+ * around. -+ */ -+ ofs = iobuf->offset; -+ pagelen = PAGE_SIZE - iobuf->offset; -+ if (count < pagelen) -+ pagelen = count; -+ -+ for (i = 0; i < iobuf->nr_pages; i++) { -+ list->tx[i] = list->rx[i] = page_address(iobuf->maplist[i]) + ofs; -+ list->txlen[i] = list->rxlen[i] = pagelen; -+ -+#ifdef DEBUG_SPIDEV -+ printk(" %i: %x (%i)\n", i, list->tx[i], list->txlen[i]); -+#endif -+ -+ ofs = 0; /* all subsequent transfers start at beginning of a page */ -+ count = count - pagelen; -+ pagelen = (count < PAGE_SIZE) ? count : PAGE_SIZE; -+ } -+ list->nr_transfers = iobuf->nr_pages; -+ -+ /* Perform transfer on SPI bus */ -+ spi_access_bus(spi_device); -+ spi_transfer(list); -+ spi_release_bus(spi_device); -+ -+ unmap_kiobuf(iobuf); -+ free_kiovec(1, &iobuf); -+ kfree(list); -+ -+ return res; -+} -+ -+static int spidev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ int spi_device = MINOR(inode->i_rdev); -+ -+ if (spi_device >= NR_SPI_DEVICES) -+ return -ENODEV; -+ -+ // TODO: This interface can be used to configure the SPI bus. -+ // Configurable options could include: Speed, Clock Polarity, Clock Phase -+ -+ switch(cmd) { -+ default: -+ return -ENOIOCTLCMD; -+ } -+} -+ -+/* -+ * Open the SPI device -+ */ -+static int spidev_open(struct inode *inode, struct file *file) -+{ -+ unsigned int spi_device = MINOR(inode->i_rdev); -+ -+ if (spi_device >= NR_SPI_DEVICES) -+ return -ENODEV; -+ -+ MOD_INC_USE_COUNT; -+ -+ /* -+ * 'private_data' is actually a pointer, but we overload it with the -+ * value we want to store. -+ */ -+ (unsigned int) file->private_data = spi_device; -+ -+ return 0; -+} -+ -+/* -+ * Close the SPI device -+ */ -+static int spidev_close(struct inode *inode, struct file *file) -+{ -+ MOD_DEC_USE_COUNT; -+ return 0; -+} -+ -+/* ......................................................................... */ -+ -+static struct file_operations spidev_fops = { -+ owner: THIS_MODULE, -+ llseek: no_llseek, -+ read: spidev_rd_wr, -+ write: spidev_rd_wr, -+ ioctl: spidev_ioctl, -+ open: spidev_open, -+ release: spidev_close, -+}; -+ -+/* -+ * Install the SPI /dev interface driver -+ */ -+static int __init at91_spidev_init(void) -+{ -+ int i; -+ char name[3]; -+ -+#ifdef CONFIG_DEVFS_FS -+ if (devfs_register_chrdev(SPI_MAJOR, "spi", &spidev_fops)) { -+#else -+ if (register_chrdev(SPI_MAJOR, "spi", &spidev_fops)) { -+#endif -+ printk(KERN_ERR "at91_spidev: Unable to get major %d for SPI bus\n", SPI_MAJOR); -+ return -EIO; -+ } -+ -+#ifdef CONFIG_DEVFS_FS -+ devfs_handle = devfs_mk_dir(NULL, "spi", NULL); -+ -+ for (i = 0; i < NR_SPI_DEVICES; i++) { -+ sprintf (name, "%d", i); -+ devfs_spi[i] = devfs_register (devfs_handle, name, -+ DEVFS_FL_DEFAULT, SPI_MAJOR, i, S_IFCHR | S_IRUSR | S_IWUSR, -+ &spidev_fops, NULL); -+ } -+#endif -+ printk(KERN_INFO "AT91 SPI driver loaded\n"); -+ -+ return 0; -+} -+ -+/* -+ * Remove the SPI /dev interface driver -+ */ -+static void __exit at91_spidev_exit(void) -+{ -+#ifdef CONFIG_DEVFS_FS -+ devfs_unregister(devfs_handle); -+ if (devfs_unregister_chrdev(SPI_MAJOR, "spi")) { -+#else -+ if (unregister_chrdev(SPI_MAJOR,"spi")) { -+#endif -+ printk(KERN_ERR "at91_spidev: Unable to release major %d for SPI bus\n", SPI_MAJOR); -+ return; -+ } -+} -+ -+module_init(at91_spidev_init); -+module_exit(at91_spidev_exit); -+ -+MODULE_LICENSE("GPL") -+MODULE_AUTHOR("Andrew Victor") -+MODULE_DESCRIPTION("SPI /dev interface for Atmel AT91RM9200") -diff -urN linux-2.4.26/drivers/at91/usb/Makefile linux-2.4.26-vrs1/drivers/at91/usb/Makefile ---- linux-2.4.26/drivers/at91/usb/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/usb/Makefile 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,17 @@ -+# File: drivers/at91/usb/Makefile -+# -+# Makefile for the Atmel AT91RM9200 USB device drivers -+# -+ -+O_TARGET := at91usb.o -+ -+export-objs := -+ -+obj-y := -+obj-m := -+obj-n := -+obj- := -+ -+obj-$(CONFIG_USB_OHCI_AT91) += at91_usb-ohci.o -+ -+include $(TOPDIR)/Rules.make -diff -urN linux-2.4.26/drivers/at91/usb/at91_usb-ohci.c linux-2.4.26-vrs1/drivers/at91/usb/at91_usb-ohci.c ---- linux-2.4.26/drivers/at91/usb/at91_usb-ohci.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/usb/at91_usb-ohci.c 2004-04-10 12:44:07.000000000 +0100 -@@ -0,0 +1,85 @@ -+/* -+ * linux/drivers/at91/usb/at91_usb_ohci-at91.c -+ * -+ * (c) Rick Bronson -+ * -+ * The outline of this code was taken from Brad Parkers -+ * original OHCI driver modifications, and reworked into a cleaner form -+ * by Russell King . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+/* -+ NOTE: -+ The following is so that we don't have to include usb-ohci.h or pci.h as the -+ usb-ohci.c driver needs these routines even when the architecture -+ has no PCI bus... -+*/ -+ -+extern int __devinit hc_add_ohci(struct pci_dev *dev, int irq, void *membase, -+ unsigned long flags, void *ohci, const char *name, -+ const char *slot_name); -+extern void hc_remove_ohci(void *ohci); -+ -+static void *at91_ohci; -+AT91PS_UHP ohci_regs; -+ -+static int __init at91_ohci_init(void) -+{ -+ int ret; -+ -+ ohci_regs = ioremap(AT91_UHP_BASE, SZ_4K); -+ if (!ohci_regs) { -+ printk(KERN_ERR "at91_usb-ohci: ioremap failed\n"); -+ return -EIO; -+ } -+ -+ /* Enable PLLB */ -+ AT91_SYS->CKGR_PLLBR = AT91_PLLB_INIT; -+ while ((AT91_SYS->PMC_SR & 4) == 0); -+ -+ /* Now, enable the USB clock */ -+ AT91_SYS->PMC_SCER = AT91C_PMC_UHP; /* enable system clock */ -+ AT91_SYS->PMC_PCER = 1 << AT91C_ID_UHP; /* enable peripheral clock */ -+ -+ /* Take Hc out of reset */ -+ ohci_regs->UHP_HcControl = 2 << 6; -+ -+ /* Initialise the generic OHCI driver. */ -+ ret = hc_add_ohci((struct pci_dev *) 1, AT91C_ID_UHP, -+ (void *)ohci_regs, 0, &at91_ohci, -+ "usb-ohci", "at91"); -+ if (ret) -+ iounmap(ohci_regs); -+ -+ return ret; -+} -+ -+static void __exit at91_ohci_exit(void) -+{ -+ hc_remove_ohci(at91_ohci); -+ -+ /* Force UHP_Hc to reset */ -+ ohci_regs->UHP_HcControl = 0; -+ -+ /* Stop the USB clock. */ -+ AT91_SYS->PMC_SCDR = AT91C_PMC_UHP; /* disable system clock */ -+ AT91_SYS->PMC_PCDR = 1 << AT91C_ID_UHP; /* disable peripheral clock */ -+ -+ iounmap(ohci_regs); -+} -+ -+module_init(at91_ohci_init); -+module_exit(at91_ohci_exit); -diff -urN linux-2.4.26/drivers/at91/watchdog/Makefile linux-2.4.26-vrs1/drivers/at91/watchdog/Makefile ---- linux-2.4.26/drivers/at91/watchdog/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/watchdog/Makefile 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,15 @@ -+# File: drivers/at91/watchdog/Makefile -+# -+# Makefile for the Atmel AT91RM9200 watchdog device driver -+# -+ -+O_TARGET := at91wdt.o -+ -+obj-y := -+obj-m := -+obj-n := -+obj- := -+ -+obj-$(CONFIG_AT91_WATCHDOG) += at91_wdt.o -+ -+include $(TOPDIR)/Rules.make -diff -urN linux-2.4.26/drivers/at91/watchdog/at91_wdt.c linux-2.4.26-vrs1/drivers/at91/watchdog/at91_wdt.c ---- linux-2.4.26/drivers/at91/watchdog/at91_wdt.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/at91/watchdog/at91_wdt.c 2004-04-10 12:23:48.000000000 +0100 -@@ -0,0 +1,193 @@ -+/* -+ * Watchdog driver for Atmel AT91RM9200 (Thunder) -+ * -+ * (c) SAN People (Pty) Ltd -+ * -+ * 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. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define WDT_DEFAULT_TIME 5 /* 5 seconds */ -+#define WDT_MAX_TIME 256 /* 256 seconds */ -+ -+static int at91wdt_time = WDT_DEFAULT_TIME; -+static int at91wdt_busy; -+ -+/* ......................................................................... */ -+ -+/* -+ * Disable the watchdog. -+ */ -+static void at91_wdt_stop(void) -+{ -+ AT91_SYS->ST_WDMR = AT91C_ST_EXTEN; -+} -+ -+/* -+ * Enable and reset the watchdog. -+ */ -+static void at91_wdt_start(void) -+{ -+ AT91_SYS->ST_WDMR = AT91C_ST_EXTEN | AT91C_ST_RSTEN | (((65536 * at91wdt_time) >> 8) & AT91C_ST_WDV); -+ AT91_SYS->ST_CR = AT91C_ST_WDRST; -+} -+ -+/* ......................................................................... */ -+ -+/* -+ * Watchdog device is opened, and watchdog starts running. -+ */ -+static int at91_wdt_open(struct inode *inode, struct file *file) -+{ -+ if (test_and_set_bit(1, &at91wdt_busy)) -+ return -EBUSY; -+ MOD_INC_USE_COUNT; -+ -+ /* -+ * All counting occurs at SLOW_CLOCK / 128 = 0.256 Hz -+ * -+ * Since WDV is a 16-bit counter, the maximum period is -+ * 65536 / 0.256 = 256 seconds. -+ */ -+ -+ at91_wdt_start(); -+ return 0; -+} -+ -+/* -+ * Close the watchdog device. -+ * If CONFIG_WATCHDOG_NOWAYOUT is NOT defined then the watchdog is also -+ * disabled. -+ */ -+static int at91_wdt_close(struct inode *inode, struct file *file) -+{ -+#ifndef CONFIG_WATCHDOG_NOWAYOUT -+ /* Disable the watchdog when file is closed */ -+ at91_wdt_stop(); -+#endif -+ -+ at91wdt_busy = 0; -+ MOD_DEC_USE_COUNT; -+ return 0; -+} -+ -+/* -+ * Handle commands from user-space. -+ */ -+static int at91_wdt_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ unsigned int new_value; -+ static struct watchdog_info info = { -+ identity: "at91 watchdog", -+ options: WDIOF_SETTIMEOUT, -+ }; -+ -+ switch(cmd) { -+ case WDIOC_KEEPALIVE: -+ AT91_SYS->ST_CR = AT91C_ST_WDRST; /* Pat the watchdog */ -+ return 0; -+ -+ case WDIOC_GETSUPPORT: -+ return copy_to_user((struct watchdog_info *)arg, &info, sizeof(info)); -+ -+ case WDIOC_SETTIMEOUT: -+ if (get_user(new_value, (int *)arg)) -+ return -EFAULT; -+ if ((new_value <= 0) || (new_value > WDT_MAX_TIME)) -+ return -EINVAL; -+ -+ /* Restart watchdog with new time */ -+ at91wdt_time = new_value; -+ at91_wdt_start(); -+ -+ /* Return current value */ -+ return put_user(at91wdt_time, (int *)arg); -+ -+ case WDIOC_GETTIMEOUT: -+ return put_user(at91wdt_time, (int *)arg); -+ -+ case WDIOC_GETSTATUS: -+ return put_user(0, (int *)arg); -+ -+ case WDIOC_SETOPTIONS: -+ if (get_user(new_value, (int *)arg)) -+ return -EFAULT; -+ if (new_value & WDIOS_DISABLECARD) -+ at91_wdt_stop(); -+ if (new_value & WDIOS_ENABLECARD) -+ at91_wdt_start(); -+ return 0; -+ -+ default: -+ return -ENOIOCTLCMD; -+ } -+} -+ -+/* -+ * Pat the watchdog whenever device is written to. -+ */ -+static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) -+{ -+ /* Can't seek (pwrite) on this device */ -+ if (ppos != &file->f_pos) -+ return -ESPIPE; -+ -+ if (len) { -+ AT91_SYS->ST_CR = AT91C_ST_WDRST; /* Pat the watchdog */ -+ return len; -+ } -+ -+ return 0; -+} -+ -+/* ......................................................................... */ -+ -+static struct file_operations at91wdt_fops = -+{ -+ .owner = THIS_MODULE, -+ .ioctl = at91_wdt_ioctl, -+ .open = at91_wdt_open, -+ .release = at91_wdt_close, -+ .write = at91_wdt_write, -+}; -+ -+static struct miscdevice at91wdt_miscdev = -+{ -+ .minor = WATCHDOG_MINOR, -+ .name = "watchdog", -+ .fops = &at91wdt_fops, -+}; -+ -+static int __init at91_wdt_init(void) -+{ -+ int res; -+ -+ res = misc_register(&at91wdt_miscdev); -+ if (res) -+ return res; -+ -+ printk("AT91 Watchdog Timer enabled (%d seconds)\n", WDT_DEFAULT_TIME); -+ return 0; -+} -+ -+static void __exit at91_wdt_exit(void) -+{ -+ misc_deregister(&at91wdt_miscdev); -+} -+ -+module_init(at91_wdt_init); -+module_exit(at91_wdt_exit); -+ -+MODULE_LICENSE("GPL") -+MODULE_AUTHOR("Andrew Victor") -+MODULE_DESCRIPTION("Watchdog driver for Atmel AT91RM9200") -diff -urN linux-2.4.26/drivers/block/Makefile linux-2.4.26-vrs1/drivers/block/Makefile ---- linux-2.4.26/drivers/block/Makefile 2003-06-13 15:51:32.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/block/Makefile 2004-01-14 21:32:25.000000000 +0000 -@@ -27,11 +27,17 @@ - obj-$(CONFIG_BLK_DEV_PS2) += ps2esdi.o - obj-$(CONFIG_BLK_DEV_XD) += xd.o - obj-$(CONFIG_BLK_CPQ_DA) += cpqarray.o --obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o -+obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o - obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o - obj-$(CONFIG_BLK_DEV_UMEM) += umem.o - obj-$(CONFIG_BLK_DEV_NBD) += nbd.o - - subdir-$(CONFIG_PARIDE) += paride - -+ifeq ($(CONFIG_ARCH_ACORN),y) -+mod-subdirs += ../acorn/block -+subdir-y += ../acorn/block -+obj-y += ../acorn/block/acorn-block.o -+endif -+ - include $(TOPDIR)/Rules.make -diff -urN linux-2.4.26/drivers/block/ll_rw_blk.c linux-2.4.26-vrs1/drivers/block/ll_rw_blk.c ---- linux-2.4.26/drivers/block/ll_rw_blk.c 2004-04-19 11:44:16.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/block/ll_rw_blk.c 2004-04-18 21:47:50.000000000 +0100 -@@ -32,6 +32,19 @@ - #include - #include - -+/* Maybe something to cleanup in 2.3? -+ * We shouldn't touch 0x3f2 on machines which don't have a PC floppy controller -+ * - it may contain something else which could cause a system hang. This is -+ * now selected by a configuration option, but maybe it ought to be in the -+ * floppy code itself? - rmk -+ */ -+#if defined(__i386__) || (defined(__arm__) && defined(CONFIG_ARCH_ACORN)) -+#define FLOPPY_BOOT_DISABLE -+#endif -+#ifdef CONFIG_BLK_DEV_FD -+#undef FLOPPY_BOOT_DISABLE -+#endif -+ - /* - * MAC Floppy IWM hooks - */ -@@ -524,7 +537,7 @@ - elevator_init(&q->elevator, ELEVATOR_LINUS); - blk_init_free_list(q); - q->request_fn = rfn; -- q->back_merge_fn = ll_back_merge_fn; -+ q->back_merge_fn = ll_back_merge_fn; - q->front_merge_fn = ll_front_merge_fn; - q->merge_requests_fn = ll_merge_requests_fn; - q->make_request_fn = __make_request; -@@ -1549,7 +1562,7 @@ - mfm_init(); - #endif - #ifdef CONFIG_PARIDE -- { extern void paride_init(void); paride_init(); }; -+ { extern void paride_init(void); paride_init(); } - #endif - #ifdef CONFIG_MAC_FLOPPY - swim3_init(); -@@ -1563,12 +1576,14 @@ - #ifdef CONFIG_ATARI_FLOPPY - atari_floppy_init(); - #endif -+#ifdef CONFIG_BLK_DEV_FD1772 -+ fd1772_init(); -+#endif - #ifdef CONFIG_BLK_DEV_FD - floppy_init(); --#else --#if defined(__i386__) /* Do we even need this? */ -- outb_p(0xc, 0x3f2); - #endif -+#ifdef FLOPPY_BOOT_DISABLE -+ outb_p(0xc, 0x3f2); - #endif - #ifdef CONFIG_CDU31A - cdu31a_init(); -@@ -1626,7 +1641,7 @@ - jsfd_init(); - #endif - return 0; --}; -+} - - EXPORT_SYMBOL(io_request_lock); - EXPORT_SYMBOL(end_that_request_first); -diff -urN linux-2.4.26/drivers/cdrom/cdrom.c linux-2.4.26-vrs1/drivers/cdrom/cdrom.c ---- linux-2.4.26/drivers/cdrom/cdrom.c 2003-11-28 18:26:20.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/cdrom/cdrom.c 2004-01-14 21:38:59.000000000 +0000 -@@ -246,8 +246,8 @@ - #define CD_DVD 0x80 - - /* Define this to remove _all_ the debugging messages */ --/* #define ERRLOGMASK CD_NOTHING */ --#define ERRLOGMASK (CD_WARNING) -+#define ERRLOGMASK CD_NOTHING -+/* #define ERRLOGMASK (CD_WARNING) */ - /* #define ERRLOGMASK (CD_WARNING|CD_OPEN|CD_COUNT_TRACKS|CD_CLOSE) */ - /* #define ERRLOGMASK (CD_WARNING|CD_REG_UNREG|CD_DO_IOCTL|CD_OPEN|CD_CLOSE|CD_COUNT_TRACKS) */ - -diff -urN linux-2.4.26/drivers/char/Config.in linux-2.4.26-vrs1/drivers/char/Config.in ---- linux-2.4.26/drivers/char/Config.in 2004-02-27 20:03:25.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/char/Config.in 2004-04-10 12:04:15.000000000 +0100 -@@ -20,10 +20,10 @@ - if [ "$CONFIG_IA64" = "y" ]; then - bool ' Support for serial port described by EFI HCDP table' CONFIG_SERIAL_HCDP - fi -- if [ "$CONFIG_ARCH_ACORN" = "y" ]; then -- tristate ' Atomwide serial port support' CONFIG_ATOMWIDE_SERIAL -- tristate ' Dual serial port support' CONFIG_DUALSP_SERIAL -- fi -+fi -+if [ "$CONFIG_ARCH_ACORN" = "y" ]; then -+ dep_tristate ' Atomwide serial port support' CONFIG_ATOMWIDE_SERIAL $CONFIG_SERIAL -+ dep_tristate ' Dual serial port support' CONFIG_DUALSP_SERIAL $CONFIG_SERIAL - fi - dep_mbool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL - if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then -@@ -132,18 +132,6 @@ - bool ' SGI SN2 IOC4 serial port support' CONFIG_SGI_IOC4_SERIAL - fi - fi --fi --if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then -- tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232 --fi --if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then -- bool 'DC21285 serial port support' CONFIG_SERIAL_21285 -- if [ "$CONFIG_SERIAL_21285" = "y" ]; then -- if [ "$CONFIG_OBSOLETE" = "y" ]; then -- bool ' Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD -- fi -- bool ' Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE -- fi - if [ "$CONFIG_PARISC" = "y" ]; then - bool ' PDC software console support' CONFIG_PDC_CONSOLE - fi -@@ -168,6 +156,16 @@ - if [ "$CONFIG_CPU_VR41XX" = "y" ]; then - bool 'NEC VR4100 series Keyboard Interface Unit Support ' CONFIG_VR41XX_KIU - fi -+if [ "$CONFIG_ARCH_AT91RM9200" = "y" ]; then -+ tristate 'AT91RM9200 SPI device interface' CONFIG_AT91_SPIDEV -+fi -+ -+source drivers/serial/Config.in -+ -+if [ "$CONFIG_ARCH_ANAKIN" = "y" ]; then -+ tristate 'Anakin touchscreen support' CONFIG_TOUCHSCREEN_ANAKIN -+fi -+ - bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS - if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then - int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 -@@ -190,6 +188,12 @@ - - source drivers/i2c/Config.in - -+if [ "$CONFIG_I2C" != "n" ]; then -+ dep_tristate ' DS1307 RTC' CONFIG_I2C_DS1307 $CONFIG_I2C -+fi -+ -+source drivers/l3/Config.in -+ - mainmenu_option next_comment - comment 'Mice' - tristate 'Bus Mouse Support' CONFIG_BUSMOUSE -@@ -245,11 +249,13 @@ - tristate ' ALi M7101 PMU Watchdog Timer' CONFIG_ALIM7101_WDT - tristate ' AMD "Elan" SC520 Watchdog Timer' CONFIG_SC520_WDT - tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG -- if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then -- tristate ' DC21285 watchdog' CONFIG_21285_WATCHDOG -- if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then -- tristate ' NetWinder WB83C977 watchdog' CONFIG_977_WATCHDOG -- fi -+ if [ "$CONFIG_ARM" = "y" ]; then -+ dep_tristate ' DC21285 watchdog' CONFIG_21285_WATCHDOG $CONFIG_FOOTBRIDGE -+ dep_tristate ' NetWinder WB83C977 watchdog' CONFIG_977_WATCHDOG $CONFIG_ARCH_NETWINDER -+ dep_tristate ' SA1100 watchdog' CONFIG_SA1100_WATCHDOG $CONFIG_ARCH_SA1100 -+ dep_tristate ' EPXA watchdog' CONFIG_EPXA_WATCHDOG $CONFIG_ARCH_CAMELOT -+ dep_tristate ' Omaha watchdog' CONFIG_OMAHA_WATCHDOG $CONFIG_ARCH_OMAHA -+ dep_tristate ' AT91RM9200 watchdog' CONFIG_AT91_WATCHDOG $CONFIG_ARCH_AT91RM9200 - fi - tristate ' Eurotech CPU-1220/1410 Watchdog Timer' CONFIG_EUROTECH_WDT - tristate ' IB700 SBC Watchdog Timer' CONFIG_IB700_WDT -@@ -326,6 +332,15 @@ - if [ "$CONFIG_TOSHIBA_RBTX4927" = "y" -o "$CONFIG_TOSHIBA_JMR3927" = "y" ]; then - tristate 'Dallas DS1742 RTC support' CONFIG_DS1742 - fi -+if [ "$CONFIG_ARCH_SA1100" = "y" ]; then -+ tristate 'SA1100 Real Time Clock' CONFIG_SA1100_RTC -+fi -+if [ "$CONFIG_ARCH_OMAHA" = "y" ]; then -+ tristate 'Omaha Real Time Clock' CONFIG_OMAHA_RTC -+fi -+if [ "$CONFIG_ARCH_AT91RM9200" = "y" ]; then -+ tristate 'AT91RM9200 Real Time Clock' CONFIG_AT91_RTC -+fi - - tristate 'Double Talk PC internal speech card support' CONFIG_DTLK - tristate 'Siemens R3964 line discipline' CONFIG_R3964 -diff -urN linux-2.4.26/drivers/char/Makefile linux-2.4.26-vrs1/drivers/char/Makefile ---- linux-2.4.26/drivers/char/Makefile 2004-02-27 20:03:25.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/char/Makefile 2004-04-10 12:07:34.000000000 +0100 -@@ -29,7 +29,7 @@ - - mod-subdirs := joystick ftape drm drm-4.0 pcmcia - --list-multi := -+list-multi := - - KEYMAP =defkeymap.o - KEYBD =pc_keyb.o -@@ -106,11 +106,39 @@ - endif - - ifeq ($(ARCH),arm) -- ifneq ($(CONFIG_PC_KEYMAP),y) -- KEYMAP = -+ KEYMAP := -+ KEYBD := -+ ifeq ($(CONFIG_PC_KEYMAP),y) -+ KEYMAP := defkeymap.o - endif -- ifneq ($(CONFIG_PC_KEYB),y) -- KEYBD = -+ ifeq ($(CONFIG_PC_KEYB),y) -+ KEYBD += pc_keyb.o -+ endif -+ ifeq ($(CONFIG_KMI_KEYB),y) -+ KEYBD += amba_kmi_keyb.o -+ endif -+ ifeq ($(CONFIG_SA1111),y) -+ KEYBD += sa1111_keyb.o -+ endif -+ ifeq ($(CONFIG_ARCH_EDB7211),y) -+ KEYBD += edb7211_keyb.o -+ endif -+ ifeq ($(CONFIG_ARCH_AUTCPU12),y) -+ KEYMAP := defkeymap.o -+ KEYBD += clps711x_keyb.o -+ endif -+ ifeq ($(CONFIG_SA1100_GRAPHICSCLIENT),y) -+ KEYMAP = gckeymap.o -+ KEYBD += gc_keyb.o -+ endif -+ ifeq ($(CONFIG_SA1100_CERF_CPLD),y) -+ KEYBD += cerf_keyb.o -+ endif -+ ifeq ($(CONFIG_ARCH_FORTUNET),y) -+ KEYMAP := defkeymap.o -+ endif -+ ifeq ($(CONFIG_ARCH_GUIDEA07),y) -+ KEYMAP := defkeymap.o - endif - endif - -@@ -172,11 +200,9 @@ - obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o - obj-$(CONFIG_SERIAL) += $(SERIAL) - obj-$(CONFIG_SERIAL_HCDP) += hcdp_serial.o --obj-$(CONFIG_SERIAL_21285) += serial_21285.o --obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o --obj-$(CONFIG_SERIAL_AMBA) += serial_amba.o - obj-$(CONFIG_TS_AU1X00_ADS7846) += au1000_ts.o - obj-$(CONFIG_SERIAL_DEC) += decserial.o -+obj-$(CONFIG_TOUCHSCREEN_ANAKIN) += anakin_ts.o - - ifndef CONFIG_SUN_KEYBOARD - obj-$(CONFIG_VT) += keyboard.o $(KEYMAP) $(KEYBD) -@@ -253,6 +279,8 @@ - obj-$(CONFIG_SGI_DS1286) += ds1286.o - obj-$(CONFIG_MIPS_RTC) += mips_rtc.o - obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o -+obj-$(CONFIG_SA1100_RTC) += sa1100-rtc.o -+obj-$(CONFIG_OMAHA_RTC) += omaha-rtc.o - ifeq ($(CONFIG_PPC),) - obj-$(CONFIG_NVRAM) += nvram.o - endif -@@ -291,6 +319,7 @@ - obj-$(CONFIG_NWFLASH) += nwflash.o - obj-$(CONFIG_SCx200) += scx200.o - obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o -+obj-$(CONFIG_SA1100_CONSUS) += consusbutton.o - - # Only one watchdog can succeed. We probe the hardware watchdog - # drivers first, then the softdog driver. This means if your hardware -@@ -319,16 +348,28 @@ - obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o - obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o - obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o -+obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o -+obj-$(CONFIG_EPXA_WATCHDOG) += epxa_wdt.o -+obj-$(CONFIG_OMAHA_WATCHDOG) += omaha_wdt.o - obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o - obj-$(CONFIG_AMD7XX_TCO) += amd7xx_tco.o - obj-$(CONFIG_INDYDOG) += indydog.o - obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o - -+# I2C char devices -+obj-$(CONFIG_I2C_DS1307) += ds1307.o -+ - subdir-$(CONFIG_MWAVE) += mwave - ifeq ($(CONFIG_MWAVE),y) - obj-y += mwave/mwave.o - endif - -+ifeq ($(CONFIG_ARCH_ACORN),y) -+mod-subdirs += ../acorn/char -+subdir-y += ../acorn/char -+obj-y += ../acorn/char/acorn-char.o -+endif -+ - subdir-$(CONFIG_IPMI_HANDLER) += ipmi - ifeq ($(CONFIG_IPMI_HANDLER),y) - obj-y += ipmi/ipmi.o -diff -urN linux-2.4.26/drivers/char/amba_kmi_keyb.c linux-2.4.26-vrs1/drivers/char/amba_kmi_keyb.c ---- linux-2.4.26/drivers/char/amba_kmi_keyb.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/amba_kmi_keyb.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,999 @@ -+/* -+ * linux/drivers/char/amba_kmi_keyb.c -+ * -+ * AMBA Keyboard and Mouse Interface Driver -+ * -+ * Copyright (C) 2000 Deep Blue Solutions Ltd. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * This keyboard driver drives a PS/2 keyboard and mouse connected -+ * to the KMI interfaces. The KMI interfaces are nothing more than -+ * a uart; there is no inteligence in them to do keycode translation. -+ * We leave all that up to the keyboard itself. -+ * -+ * FIXES: -+ * dirk.uffmann@nokia.com: enabled PS/2 reconnection -+ */ -+#include -+#include -+#include -+#include /* for in_interrupt */ -+#include -+#include -+#include /* for udelay */ -+#include /* for keyboard_tasklet */ -+#include -+ -+#include -+#include -+#include -+#include -+ -+//#define DEBUG(s) printk s -+#define DEBUG(s) do { } while (0) -+ -+#define CONFIG_AMBA_PS2_RECONNECT -+ -+#define KMI_BASE (kmi->base) -+ -+#define KMI_RESET 0x00 -+#define KMI_RESET_POR 0x01 -+#define KMI_RESET_DONE 0x02 -+ -+#define KMI_NO_ACK 0xffff -+ -+#define PS2_O_RESET 0xff -+#define PS2_O_RESEND 0xfe -+#define PS2_O_DISABLE 0xf5 -+#define PS2_O_ENABLE 0xf4 -+#define PS2_O_ECHO 0xee -+ -+/* -+ * Keyboard -+ */ -+#define PS2_O_SET_DEFAULT 0xf6 -+#define PS2_O_SET_RATE_DELAY 0xf3 -+#define PS2_O_SET_SCANSET 0xf0 -+#define PS2_O_INDICATORS 0xed -+ -+/* -+ * Mouse -+ */ -+#define PS2_O_SET_SAMPLE 0xf3 -+#define PS2_O_SET_STREAM 0xea -+#define PS2_O_SET_RES 0xe8 -+#define PS2_O_SET_SCALE21 0xe7 -+#define PS2_O_SET_SCALE11 0xe6 -+#define PS2_O_REQ_STATUS 0xe9 -+ -+/* -+ * Responses -+ */ -+#define PS2_I_RESEND 0xfe -+#define PS2_I_DIAGFAIL 0xfc -+#define PS2_I_ACK 0xfa -+#define PS2_I_BREAK 0xf0 -+#define PS2_I_ECHO 0xee -+#define PS2_I_BAT_OK 0xaa -+ -+static char *kmi_type[] = { "Keyboard", "Mouse" }; -+ -+static struct kmi_info *kmi_keyb; -+static struct kmi_info *kmi_mouse; -+ -+static inline void __kmi_send(struct kmi_info *kmi, u_int val) -+{ -+ u_int status; -+ -+ do { -+ status = __raw_readb(KMISTAT); -+ } while (!(status & KMISTAT_TXEMPTY)); -+ -+ kmi->resend_count += 1; -+ __raw_writeb(val, KMIDATA); -+} -+ -+static void kmi_send(struct kmi_info *kmi, u_int val) -+{ -+ kmi->last_tx = val; -+ kmi->resend_count = -1; -+ __kmi_send(kmi, val); -+} -+ -+static u_int kmi_send_and_wait(struct kmi_info *kmi, u_int val, u_int timeo) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ -+ if (kmi->present == 0) -+ return KMI_NO_ACK; -+ -+ kmi->res = KMI_NO_ACK; -+ kmi->last_tx = val; -+ kmi->resend_count = -1; -+ -+ if (current->pid != 0 && !in_interrupt()) { -+ add_wait_queue(&kmi->wait_q, &wait); -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ __kmi_send(kmi, val); -+ schedule_timeout(timeo); -+ current->state = TASK_RUNNING; -+ remove_wait_queue(&kmi->wait_q, &wait); -+ } else { -+ int i; -+ -+ __kmi_send(kmi, val); -+ for (i = 0; i < 1000; i++) { -+ if (kmi->res != KMI_NO_ACK) -+ break; -+ udelay(100); -+ } -+ } -+ -+ return kmi->res; -+} -+ -+/* -+ * This lot should probably be separated into a separate file... -+ */ -+#ifdef CONFIG_KMI_MOUSE -+ -+#include /* for struct file_ops */ -+#include /* for poll_table */ -+#include /* for struct miscdev */ -+#include /* for add_mouse_randomness */ -+#include /* for kmalloc */ -+#include /* for {un,}lock_kernel */ -+#include -+ -+#include -+ -+#define BUF_SZ 2048 -+ -+static spinlock_t kmi_mouse_lock; -+static int kmi_mouse_count; -+static struct queue { -+ u_int head; -+ u_int tail; -+ struct fasync_struct *fasync; -+ unsigned char buf[BUF_SZ]; -+} *queue; -+ -+#define queue_empty() (queue->head == queue->tail) -+ -+static u_char get_from_queue(void) -+{ -+ unsigned long flags; -+ u_char res; -+ -+ spin_lock_irqsave(&kmi_mouse_lock, flags); -+ res = queue->buf[queue->tail]; -+ queue->tail = (queue->tail + 1) & (BUF_SZ-1); -+ spin_unlock_irqrestore(&kmi_mouse_lock, flags); -+ -+ return res; -+} -+ -+static ssize_t -+kmi_mouse_read(struct file *file, char *buf, size_t count, loff_t *ppos) -+{ -+ ssize_t i = count; -+ -+ if (queue_empty()) { -+ int ret; -+ -+ if (file->f_flags & O_NONBLOCK) -+ return -EAGAIN; -+ ret = wait_event_interruptible(kmi_mouse->wait_q, !queue_empty()); -+ if (ret) -+ return ret; -+ } -+ while (i > 0 && !queue_empty()) { -+ u_char c; -+ c = get_from_queue(); -+ put_user(c, buf++); -+ i--; -+ } -+ if (count - i) -+ file->f_dentry->d_inode->i_atime = CURRENT_TIME; -+ return count - i; -+} -+ -+static ssize_t -+kmi_mouse_write(struct file *file, const char *buf, size_t count, loff_t *ppos) -+{ -+ ssize_t retval = 0; -+ -+ if (count > 32) -+ count = 32; -+ -+ do { -+ char c; -+ get_user(c, buf++); -+ kmi_send_and_wait(kmi_mouse, c, HZ); -+ retval++; -+ } while (--count); -+ -+ if (retval) -+ file->f_dentry->d_inode->i_mtime = CURRENT_TIME; -+ -+ return retval; -+} -+ -+static unsigned int -+kmi_mouse_poll(struct file *file, poll_table *wait) -+{ -+ poll_wait(file, &kmi_mouse->wait_q, wait); -+ return (!queue_empty()) ? POLLIN | POLLRDNORM : 0; -+} -+ -+static int -+kmi_mouse_release(struct inode *inode, struct file *file) -+{ -+ lock_kernel(); -+ fasync_helper(-1, file, 0, &queue->fasync); -+ if (--kmi_mouse_count == 0) -+ kmi_send_and_wait(kmi_mouse, PS2_O_DISABLE, HZ); -+ unlock_kernel(); -+ return 0; -+} -+ -+static int -+kmi_mouse_open(struct inode *inode, struct file *file) -+{ -+ if (kmi_mouse_count++) -+ return 0; -+ queue->head = queue->tail = 0; -+ kmi_send_and_wait(kmi_mouse, PS2_O_ENABLE, HZ); -+ return 0; -+} -+ -+static int -+kmi_mouse_fasync(int fd, struct file *filp, int on) -+{ -+ int retval = fasync_helper(fd, filp, on, &queue->fasync); -+ if (retval > 0) -+ retval = 0; -+ return retval; -+} -+ -+static struct file_operations ps_fops = { -+ read: kmi_mouse_read, -+ write: kmi_mouse_write, -+ poll: kmi_mouse_poll, -+ open: kmi_mouse_open, -+ release: kmi_mouse_release, -+ fasync: kmi_mouse_fasync, -+}; -+ -+static struct miscdevice ps_mouse = { -+ minor: PSMOUSE_MINOR, -+ name: "psaux", -+ fops: &ps_fops, -+}; -+ -+static u_char kmi_mse_init_string[] = { -+ PS2_O_DISABLE, -+ PS2_O_SET_SAMPLE, 100, -+ PS2_O_SET_RES, 3, -+ PS2_O_SET_SCALE21 -+}; -+ -+/* -+ * The "normal" mouse scancode processing -+ */ -+static void kmi_mse_intr(struct kmi_info *kmi, u_int val, struct pt_regs *regs) -+{ -+ u_int head; -+ -+ add_mouse_randomness(val); -+ -+#ifdef CONFIG_AMBA_PS2_RECONNECT -+ /* Try to detect a hot-plug event on the PS/2 mouse port */ -+ switch (kmi->hotplug_state) { -+ case 0: -+ /* Maybe we lost contact... */ -+ if (val == PS2_I_BAT_OK) { -+ kmi->hotplug_state++; -+ DEBUG(("%s: Saw 0xAA. Going to hotplug state %d\n", kmi->name, kmi->hotplug_state)); -+ } -+ break; -+ -+ case 1: -+ /* Again, maybe (but only maybe) we lost contact... */ -+ if (val == 0) { -+ kmi->hotplug_state++; -+ kmi_send(kmi, PS2_O_REQ_STATUS); -+ DEBUG(("%s: Got 0xAA 0x00. Sent Status Request\n", kmi->name)); -+ } else { -+ kmi->hotplug_state = 0; -+ DEBUG(("%s: No 0x00 followed 0xAA. No reconnect.\n", kmi->name)); -+ } -+ break; -+ -+ case 2: -+ /* Eat up acknowledge */ -+ if (val == PS2_I_ACK) -+ kmi->hotplug_state++; -+ else { -+ kmi->hotplug_state = 0; -+ DEBUG(("%s: didn't get ack (0x%2.2x)\n", kmi->name, val)); -+ } -+ break; -+ -+ case 3: -+ /* check if data reporting is still enabled, then no POR has happend */ -+ kmi->reconnect = !(val & 1<<5); -+ DEBUG(("%s: Data reporting disabled?: (%d)\n", kmi->name, kmi->reconnect)); -+ kmi->hotplug_state++; -+ DEBUG(("%s: Going to hotplug state %d\n", kmi->name, kmi->hotplug_state)); -+ break; -+ -+ case 4: -+ /* Eat up one status byte */ -+ kmi->hotplug_state++; -+ DEBUG(("%s: Going to hotplug state %d\n", kmi->name, kmi->hotplug_state)); -+ break; -+ -+ case 5: -+ /* Eat up another status byte */ -+ if (kmi->reconnect) { -+ kmi->config_num = 0; -+ kmi_send(kmi, kmi_mse_init_string[kmi->config_num]); -+ kmi->config_num++; -+ kmi->hotplug_state++; -+ DEBUG(("%s: Sending byte %d of PS/2 init string.\n", kmi->name, kmi->config_num)); -+ } else { -+ kmi->hotplug_state = 0; -+ DEBUG(("%s: False Alarm...\n", kmi->name)); -+ } -+ break; -+ -+ case 6: -+ if (val == PS2_I_ACK && kmi->config_num < sizeof(kmi_mse_init_string)) { -+ kmi_send(kmi, kmi_mse_init_string[kmi->config_num]); -+ kmi->config_num++; -+ DEBUG(("%s: Sending byte %d of PS/2 init string.\n", kmi->name, kmi->config_num)); -+ } else { -+ if (val == PS2_I_ACK) { -+ DEBUG(("%s: Now enable the mouse again...\n", kmi->name)); -+ queue->head = queue->tail = 0; -+ kmi_send(kmi, PS2_O_ENABLE); -+ kmi->hotplug_state++; -+ } else { -+ kmi->hotplug_state = 0; -+ DEBUG(("%s: didn't get ack (0x%2.2x)\n", kmi->name, val)); -+ } -+ } -+ break; -+ -+ case 7: -+ /* Eat up last acknowledge from enable */ -+ if (val == PS2_I_ACK) -+ printk(KERN_ERR "%s: reconnected\n", kmi->name); -+ else -+ DEBUG(("%s: didn't get ack (0x%2.2x)\n", kmi->name, val)); -+ -+ kmi->hotplug_state = 0; -+ break; -+ -+ } /* switch (kmi->hotplug_state) */ -+ -+ /* while inside hotplug mechanism, don't misinterpret values */ -+ if (kmi->hotplug_state > 2) -+ return; -+#endif -+ -+ /* We are waiting for the mouse to respond to a kmi_send_and_wait() */ -+ if (kmi->res == KMI_NO_ACK) { -+ if (val == PS2_I_RESEND) { -+ if (kmi->resend_count < 5) -+ __kmi_send(kmi, kmi->last_tx); -+ else { -+ printk(KERN_ERR "%s: too many resends\n", kmi->name); -+ return; -+ } -+ } -+ -+ if (val == PS2_I_ACK) { -+ kmi->res = val; -+ wake_up(&kmi->wait_q); -+ } -+ return; -+ } -+ -+ /* The mouse autonomously send new data, so wake up mouse_read() */ -+ if (queue) { -+ head = queue->head; -+ queue->buf[head] = val; -+ head = (head + 1) & (BUF_SZ - 1); -+ if (head != queue->tail) { -+ queue->head = head; -+ kill_fasync(&queue->fasync, SIGIO, POLL_IN); -+ wake_up_interruptible(&kmi->wait_q); -+ } -+ } -+} -+ -+static int kmi_init_mouse(struct kmi_info *kmi) -+{ -+ u_int ret, i; -+ -+ if (kmi->present) { -+ kmi->rx = kmi_mse_intr; -+ -+ for (i = 0; i < sizeof(kmi_mse_init_string); i++) { -+ ret = kmi_send_and_wait(kmi, kmi_mse_init_string[i], HZ); -+ if (ret != PS2_I_ACK) -+ printk("%s: didn't get ack (0x%2.2x)\n", -+ kmi->name, ret); -+ } -+ } -+ -+ queue = kmalloc(sizeof(*queue), GFP_KERNEL); -+ if (queue) { -+ memset(queue, 0, sizeof(*queue)); -+ misc_register(&ps_mouse); -+ ret = 0; -+ } else -+ ret = -ENOMEM; -+ -+ return ret; -+} -+#endif /* CONFIG_KMI_MOUSE */ -+ -+/* -+ * The "program" we send to the keyboard to set it up how we want it: -+ * - default typematic delays -+ * - scancode set 1 -+ */ -+static u_char kmi_kbd_init_string[] = { -+ PS2_O_DISABLE, -+ PS2_O_SET_DEFAULT, -+ PS2_O_SET_SCANSET, 0x01, -+ PS2_O_ENABLE -+}; -+ -+static void kmi_kbd_intr(struct kmi_info *kmi, u_int val, struct pt_regs *regs); -+ -+static int __kmi_init_keyboard(struct kmi_info *kmi) -+{ -+ u_int ret, i; -+ -+ if (!kmi->present) -+ return 0; -+ -+ kmi->rx = kmi_kbd_intr; -+ -+ for (i = 0; i < sizeof(kmi_kbd_init_string); i++) { -+ ret = kmi_send_and_wait(kmi, kmi_kbd_init_string[i], HZ); -+ if (ret != PS2_I_ACK) -+ printk("%s: didn't ack (0x%2.2x)\n", -+ kmi->name, ret); -+ } -+ -+ return 0; -+} -+ -+static void kmi_kbd_init_tasklet(unsigned long k) -+{ -+ struct kmi_info *kmi = (struct kmi_info *)k; -+ __kmi_init_keyboard(kmi); -+} -+ -+static DECLARE_TASKLET_DISABLED(kmikbd_init_tasklet, kmi_kbd_init_tasklet, 0); -+ -+/* -+ * The "normal" keyboard scancode processing -+ */ -+static void kmi_kbd_intr(struct kmi_info *kmi, u_int val, struct pt_regs *regs) -+{ -+#ifdef CONFIG_AMBA_PS2_RECONNECT -+ /* Try to detect a hot-plug event on the PS/2 keyboard port */ -+ switch (kmi->hotplug_state) { -+ case 0: -+ /* Maybe we lost contact... */ -+ if (val == PS2_I_BAT_OK) { -+ kmi_send(kmi, PS2_O_SET_SCANSET); -+ kmi->hotplug_state++; -+ DEBUG(("%s: Saw 0xAA. Going to hotplug state %d\n", kmi->name, kmi->hotplug_state)); -+ } -+ break; -+ -+ case 1: -+ /* Eat up acknowledge */ -+ if (val == PS2_I_ACK) { -+ /* Request scan code set: '2' if POR has happend, '1' is false alarm */ -+ kmi_send(kmi, 0); -+ kmi->hotplug_state++; -+ } -+ else { -+ kmi->hotplug_state = 0; -+ DEBUG(("%s: didn't get ack (0x%2.2x)\n", kmi->name, val)); -+ } -+ break; -+ -+ case 2: -+ /* Eat up acknowledge */ -+ if (val == PS2_I_ACK) -+ kmi->hotplug_state++; -+ else { -+ kmi->hotplug_state = 0; -+ DEBUG(("%s: didn't get ack (0x%2.2x)\n", kmi->name, val)); -+ } -+ break; -+ -+ case 3: -+ kmi->hotplug_state = 0; -+ if (val == 2) { -+ DEBUG(("%s: POR detected. Scan code is: (%d)\n", kmi->name, val)); -+ kmi->present = 1; -+ tasklet_schedule(&kmikbd_init_tasklet); -+ printk(KERN_ERR "%s: reconnected\n", kmi->name); -+ return; -+ } -+ else -+ DEBUG(("%s: False Alarm...\n", kmi->name)); -+ break; -+ -+ } /* switch (kmi->hotplug_state) */ -+#endif -+ -+ if (val == PS2_I_DIAGFAIL) { -+ printk(KERN_ERR "%s: diagnostic failed\n", kmi->name); -+ return; -+ } -+ -+ /* We are waiting for the keyboard to respond to a kmi_send_and_wait() */ -+ if (kmi->res == KMI_NO_ACK) { -+ if (val == PS2_I_RESEND) { -+ if (kmi->resend_count < 5) -+ __kmi_send(kmi, kmi->last_tx); -+ else { -+ printk(KERN_ERR "%s: too many resends\n", kmi->name); -+ return; -+ } -+ } -+ -+ if (val >= 0xee) { -+ kmi->res = val; -+ wake_up(&kmi->wait_q); -+ } -+ return; -+ } -+ -+#ifdef CONFIG_VT -+ kbd_pt_regs = regs; -+ handle_scancode(val, !(val & 0x80)); -+ tasklet_schedule(&keyboard_tasklet); -+#endif -+} -+ -+static void kmi_intr(int nr, void *devid, struct pt_regs *regs) -+{ -+ struct kmi_info *kmi = devid; -+ u_int status = __raw_readb(KMIIR); -+ -+ if (status & KMIIR_RXINTR) { -+ u_int val = __raw_readb(KMIDATA); -+ -+ if (kmi->rx) -+ kmi->rx(kmi, val, regs); -+ } -+} -+ -+static int kmi_init_keyboard(struct kmi_info *kmi) -+{ -+ kmikbd_init_tasklet.data = (unsigned long)kmi; -+ tasklet_enable(&kmikbd_init_tasklet); -+ -+ return __kmi_init_keyboard(kmi); -+} -+ -+/* -+ * Reset interrupt handler -+ */ -+static void __init -+kmi_reset_intr(struct kmi_info *kmi, u_int val, struct pt_regs *regs) -+{ -+ if (kmi->state == KMI_RESET) { -+ if (val == PS2_I_ACK) -+ kmi->state = KMI_RESET_POR; -+ else { -+ val = KMI_NO_ACK; -+ goto finished; -+ } -+ } else if (kmi->state == KMI_RESET_POR) { -+finished: -+ kmi->res = val; -+ kmi->state = KMI_RESET_DONE; -+ kmi->rx = NULL; -+ wake_up(&kmi->wait_q); -+ } -+} -+ -+/* -+ * Reset the device plugged into this interface -+ */ -+static int __init kmi_reset(struct kmi_info *kmi) -+{ -+ u_int res; -+ int ret = 0; -+ -+ kmi->state = KMI_RESET; -+ kmi->rx = kmi_reset_intr; -+ res = kmi_send_and_wait(kmi, PS2_O_RESET, HZ); -+ kmi->rx = NULL; -+ -+ if (res != PS2_I_BAT_OK) { -+ printk(KERN_ERR "%s: reset failed; ", kmi->name); -+ if (kmi->res != KMI_NO_ACK) -+ printk("code 0x%2.2x\n", kmi->res); -+ else -+ printk("no ack\n"); -+ ret = -EINVAL; -+ } -+ return ret; -+} -+ -+static int __init kmi_init_one_interface(struct kmi_info *kmi) -+{ -+ u_int stat; -+ int ret = -ENODEV; -+ -+ init_waitqueue_head(&kmi->wait_q); -+ -+ printk(KERN_INFO "%s at 0x%8.8x on irq %d (%s)\n", kmi->name, -+ kmi->base, kmi->irq, kmi_type[kmi->type]); -+ -+ /* -+ * Initialise the KMI interface -+ */ -+ __raw_writeb(kmi->divisor, KMICLKDIV); -+ __raw_writeb(KMICR_EN, KMICR); -+ -+ /* -+ * Check that the data and clock lines are OK. -+ */ -+ stat = __raw_readb(KMISTAT); -+ if ((stat & (KMISTAT_IC|KMISTAT_ID)) != (KMISTAT_IC|KMISTAT_ID)) { -+ printk(KERN_ERR "%s: %s%s%sline%s stuck low\n", kmi->name, -+ (stat & KMISTAT_IC) ? "" : "clock ", -+ (stat & (KMISTAT_IC | KMISTAT_ID)) ? "" : "and ", -+ (stat & KMISTAT_ID) ? "" : "data ", -+ (stat & (KMISTAT_IC | KMISTAT_ID)) ? "" : "s"); -+ goto bad; -+ } -+ -+ /* -+ * Claim the appropriate interrupts -+ */ -+ ret = request_irq(kmi->irq, kmi_intr, 0, kmi->name, kmi); -+ if (ret) -+ goto bad; -+ -+ /* -+ * Enable the receive interrupt, and reset the device. -+ */ -+ __raw_writeb(KMICR_EN | KMICR_RXINTREN, KMICR); -+ kmi->present = 1; -+ kmi->present = kmi_reset(kmi) == 0; -+ -+ switch (kmi->type) { -+ case KMI_KEYBOARD: -+ ret = kmi_init_keyboard(kmi); -+ break; -+ -+#ifdef CONFIG_KMI_MOUSE -+ case KMI_MOUSE: -+ ret = kmi_init_mouse(kmi); -+ break; -+#endif -+ } -+ -+ return ret; -+ -+bad: -+ /* -+ * Oh dear, the interface was bad, disable it. -+ */ -+ __raw_writeb(0, KMICR); -+ return ret; -+} -+ -+#ifdef CONFIG_VT -+/* -+ * The fragment between #ifdef above and #endif * CONFIG_VT * -+ * is from the pc_keyb.c driver. It is not copyrighted under the -+ * above notice. This code is by various authors; please see -+ * drivers/char/pc_keyb.c for further information. -+ */ -+ -+/* -+ * Translation of escaped scancodes to keycodes. -+ * This is now user-settable. -+ * The keycodes 1-88,96-111,119 are fairly standard, and -+ * should probably not be changed - changing might confuse X. -+ * X also interprets scancode 0x5d (KEY_Begin). -+ * -+ * For 1-88 keycode equals scancode. -+ */ -+ -+#define E0_KPENTER 96 -+#define E0_RCTRL 97 -+#define E0_KPSLASH 98 -+#define E0_PRSCR 99 -+#define E0_RALT 100 -+#define E0_BREAK 101 /* (control-pause) */ -+#define E0_HOME 102 -+#define E0_UP 103 -+#define E0_PGUP 104 -+#define E0_LEFT 105 -+#define E0_RIGHT 106 -+#define E0_END 107 -+#define E0_DOWN 108 -+#define E0_PGDN 109 -+#define E0_INS 110 -+#define E0_DEL 111 -+ -+#define E1_PAUSE 119 -+ -+/* BTC */ -+#define E0_MACRO 112 -+/* LK450 */ -+#define E0_F13 113 -+#define E0_F14 114 -+#define E0_HELP 115 -+#define E0_DO 116 -+#define E0_F17 117 -+#define E0_KPMINPLUS 118 -+/* -+ * My OmniKey generates e0 4c for the "OMNI" key and the -+ * right alt key does nada. [kkoller@nyx10.cs.du.edu] -+ */ -+#define E0_OK 124 -+/* -+ * New microsoft keyboard is rumoured to have -+ * e0 5b (left window button), e0 5c (right window button), -+ * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU] -+ * [or: Windows_L, Windows_R, TaskMan] -+ */ -+#define E0_MSLW 125 -+#define E0_MSRW 126 -+#define E0_MSTM 127 -+ -+static u_char e0_keys[128] = { -+ 0, 0, 0, 0, -+ 0, 0, 0, 0, -+ 0, 0, 0, 0, -+ 0, 0, 0, 0, -+ 0, 0, 0, 0, -+ 0, 0, 0, 0, -+ 0, 0, 0, 0, -+ E0_KPENTER, E0_RCTRL, 0, 0, -+ 0, 0, 0, 0, -+ 0, 0, 0, 0, -+ 0, 0, 0, 0, -+ 0, 0, 0, 0, -+ 0, 0, 0, 0, -+ 0, E0_KPSLASH, 0, E0_PRSCR, -+ E0_RALT, 0, 0, 0, -+ 0, E0_F13, E0_F14, E0_HELP, -+ E0_DO, E0_F17, 0, 0, -+ 0, 0, E0_BREAK, E0_HOME, -+ E0_UP, E0_PGUP, 0, E0_LEFT, -+ E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END, -+ E0_DOWN, E0_PGDN, E0_INS, E0_DEL, -+ 0, 0, 0, 0, -+ 0, 0, 0, E0_MSLW, -+ E0_MSRW, E0_MSTM, 0, 0, -+ 0, 0, 0, 0, -+ 0, 0, 0, 0, -+ 0, 0, 0, 0, -+ 0, 0, 0, E0_MACRO, -+ 0, 0, 0, 0, -+ 0, 0, 0, 0, -+ 0, 0, 0, 0, -+ 0, 0, 0, 0 -+}; -+ -+#ifdef CONFIG_MAGIC_SYSRQ -+u_char kmi_kbd_sysrq_xlate[128] = -+ "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ -+ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ -+ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ -+ "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ -+ "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ -+ "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ -+ "\r\000/"; /* 0x60 - 0x6f */ -+#endif -+ -+int kmi_kbd_setkeycode(u_int scancode, u_int keycode) -+{ -+ if (scancode < 128 || scancode > 255 || keycode > 127) -+ return -EINVAL; -+ e0_keys[scancode - 128] = keycode; -+ return 0; -+} -+ -+int kmi_kbd_getkeycode(u_int scancode) -+{ -+ if (scancode < 128 || scancode > 255) -+ return -EINVAL; -+ return e0_keys[scancode - 128]; -+} -+ -+int kmi_kbd_translate(u_char scancode, u_char *keycode, char raw_mode) -+{ -+ static int prev_scancode = 0; -+ -+ /* special prefix scancodes.. */ -+ if (scancode == 0xe0 || scancode == 0xe1) { -+ prev_scancode = scancode; -+ return 0; -+ } -+ -+ /* 0xff is sent by a few keyboards, ignore it. 0x00 is error */ -+ if (scancode == 0x00 || scancode == 0xff) { -+ prev_scancode = 0; -+ return 0; -+ } -+ -+ scancode &= 0x7f; -+ -+ if (prev_scancode) { -+ int old_scancode = prev_scancode; -+ -+ prev_scancode = 0; -+ switch (old_scancode) { -+ case 0xe0: -+ /* -+ * The keyboard maintains its own internal caps lock -+ * and num lock status. In caps lock mode, E0 AA -+ * precedes make code and E0 2A follows break code. -+ * In numlock mode, E0 2A precedes make code, and -+ * E0 AA follows break code. We do our own book- -+ * keeping, so we will just ignore these. -+ * -+ * For my keyboard there is no caps lock mode, but -+ * there are both Shift-L and Shift-R modes. The -+ * former mode generates E0 2A / E0 AA pairs, the -+ * latter E0 B6 / E0 36 pairs. So, we should also -+ * ignore the latter. - aeb@cwi.nl -+ */ -+ if (scancode == 0x2a || scancode == 0x36) -+ return 0; -+ if (e0_keys[scancode]) -+ *keycode = e0_keys[scancode]; -+ else { -+ if (!raw_mode) -+ printk(KERN_INFO "kbd: unknown " -+ "scancode e0 %02x\n", -+ scancode); -+ return 0; -+ } -+ break; -+ -+ case 0xe1: -+ if (scancode == 0x1d) -+ prev_scancode = 0x100; -+ else { -+ if (!raw_mode) -+ printk(KERN_INFO "kbd: unknown " -+ "scancode e1 %02x\n", -+ scancode); -+ return 0; -+ } -+ break; -+ -+ case 0x100: -+ if (scancode == 0x45) -+ *keycode = E1_PAUSE; -+ else { -+ if (!raw_mode) -+ printk(KERN_INFO "kbd: unknown " -+ "scan code e1 1d %02x\n", -+ scancode); -+ return 0; -+ } -+ break; -+ } -+ } else -+ *keycode = scancode; -+ return 1; -+} -+ -+char kmi_kbd_unexpected_up(u_char keycode) -+{ -+ return 0x80; -+} -+ -+void kmi_kbd_leds(u_char leds) -+{ -+ struct kmi_info *kmi = kmi_keyb; -+ u_int ret; -+ -+ if (kmi) { -+ ret = kmi_send_and_wait(kmi, PS2_O_INDICATORS, HZ); -+ if (ret != KMI_NO_ACK) -+ ret = kmi_send_and_wait(kmi, leds, HZ); -+ if (ret == KMI_NO_ACK) -+ kmi->present = 0; -+ } -+} -+ -+int __init kmi_kbd_init(void) -+{ -+ int ret = -ENODEV; -+ -+ if (kmi_keyb) { -+ strcpy(kmi_keyb->name, "kmikbd"); -+ ret = kmi_init_one_interface(kmi_keyb); -+ } -+ -+ if (ret == 0) { -+ k_setkeycode = kmi_kbd_setkeycode; -+ k_getkeycode = kmi_kbd_getkeycode; -+ k_translate = kmi_kbd_translate; -+ k_unexpected_up = kmi_kbd_unexpected_up; -+ k_leds = kmi_kbd_leds; -+#ifdef CONFIG_MAGIC_SYSRQ -+ k_sysrq_xlate = kmi_kbd_sysrq_xlate; -+ k_sysrq_key = 0x54; -+#endif -+ } -+ -+ return ret; -+} -+ -+#endif /* CONFIG_VT */ -+ -+int register_kmi(struct kmi_info *kmi) -+{ -+ struct kmi_info **kmip = NULL; -+ int ret; -+ -+ if (kmi->type == KMI_KEYBOARD) -+ kmip = &kmi_keyb; -+ else if (kmi->type == KMI_MOUSE) -+ kmip = &kmi_mouse; -+ -+ ret = -EINVAL; -+ if (kmip) { -+ ret = -EBUSY; -+ if (!*kmip) { -+ *kmip = kmi; -+ ret = 0; -+ } -+ } -+ -+ return ret; -+} -+ -+#ifdef CONFIG_KMI_MOUSE -+static int __init kmi_init(void) -+{ -+ int ret = -ENODEV; -+ -+ if (kmi_mouse) { -+ strcpy(kmi_mouse->name, "kmimouse"); -+ ret = kmi_init_one_interface(kmi_mouse); -+ } -+ -+ return ret; -+} -+ -+__initcall(kmi_init); -+#endif -diff -urN linux-2.4.26/drivers/char/anakin_ts.c linux-2.4.26-vrs1/drivers/char/anakin_ts.c ---- linux-2.4.26/drivers/char/anakin_ts.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/anakin_ts.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,208 @@ -+/* -+ * linux/drivers/char/anakin_ts.c -+ * -+ * Copyright (C) 2001 Aleph One Ltd. for Acunia N.V. -+ * -+ * 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: -+ * 18-Apr-2001 TTC Created -+ * 23-Oct-2001 dwmw2 Cleanup -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+/* -+ * TSBUF_SIZE must be a power of two -+ */ -+#define ANAKIN_TS_MINOR 16 -+#define TSBUF_SIZE 256 -+#define NEXT(index) (((index) + 1) & (TSBUF_SIZE - 1)) -+ -+static unsigned short buffer[TSBUF_SIZE][4]; -+static int head, tail; -+static DECLARE_WAIT_QUEUE_HEAD(queue); -+static DECLARE_MUTEX(open_sem); -+static spinlock_t tailptr_lock = SPIN_LOCK_UNLOCKED; -+static struct fasync_struct *fasync; -+ -+/* -+ * Interrupt handler and standard file operations -+ */ -+static void -+anakin_ts_handler(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ unsigned int status = __raw_readl(IO_BASE + IO_CONTROLLER + 0x24); -+ -+ /* -+ * iPAQ format (u16 pressure, x, y, millisecs) -+ */ -+ switch (status >> 20 & 3) { -+ case 0: -+ return; -+ case 2: -+ buffer[head][0] = 0; -+ break; -+ default: -+ buffer[head][0] = 0x7f; -+ } -+ -+ if (unlikely((volatile int)tail == NEXT(head))) { -+ /* Run out of space in the buffer. Move the tail pointer */ -+ spin_lock(&tailptr_lock); -+ -+ if ((volatile int)tail == NEXT(head)) { -+ tail = NEXT(NEXT(head)); -+ } -+ spin_unlock(&tailptr_lock); -+ } -+ -+ buffer[head][1] = status >> 2 & 0xff; -+ buffer[head][2] = status >> 12 & 0xff; -+ buffer[head][3] = jiffies; -+ mb(); -+ head = NEXT(head); -+ -+ wake_up_interruptible(&queue); -+ kill_fasync(&fasync, SIGIO, POLL_IN); -+ -+} -+ -+static ssize_t -+anakin_ts_read(struct file *filp, char *buf, size_t count, loff_t *l) -+{ -+ unsigned short data[4]; -+ ssize_t written = 0; -+ -+ if (head == tail) { -+ if (filp->f_flags & O_NONBLOCK) -+ return -EAGAIN; -+ if (wait_event_interruptible(queue, (volatile int)head != (volatile int)tail)) -+ return -ERESTARTSYS; -+ } -+ -+ while ((volatile int)head != (volatile int)tail && count >= sizeof data) { -+ /* Copy the data out with the spinlock held, so the -+ interrupt can't fill the buffer and move the tail -+ pointer while we're doing it */ -+ spin_lock_irq(&tailptr_lock); -+ -+ memcpy(data, buffer[tail], sizeof data); -+ tail = NEXT(tail); -+ -+ spin_unlock_irq(&tailptr_lock); -+ -+ if (copy_to_user(buf, data, sizeof data)) -+ return -EFAULT; -+ count -= sizeof data; -+ buf += sizeof data; -+ written += sizeof data; -+ } -+ return written ? written : -EINVAL; -+} -+ -+static unsigned int -+anakin_ts_poll(struct file *filp, poll_table *wait) -+{ -+ poll_wait(filp, &queue, wait); -+ return head != tail ? POLLIN | POLLRDNORM : 0; -+} -+ -+static int -+anakin_ts_ioctl(struct inode *inode, struct file *filp, -+ unsigned int cmd, unsigned long arg) -+{ -+ /* -+ * Future ioctl goes here -+ */ -+ return 0; -+} -+ -+static int -+anakin_ts_open(struct inode *inode, struct file *filp) -+{ -+ if (down_trylock(&open_sem)) -+ return -EBUSY; -+ return 0; -+} -+ -+static int -+anakin_ts_fasync(int fd, struct file *filp, int on) -+{ -+ return fasync_helper(fd, filp, on, &fasync); -+} -+ -+static int -+anakin_ts_release(struct inode *inode, struct file *filp) -+{ -+ anakin_ts_fasync(-1, filp, 0); -+ up(&open_sem); -+ return 0; -+} -+ -+static struct file_operations anakin_ts_fops = { -+ owner: THIS_MODULE, -+ read: anakin_ts_read, -+ poll: anakin_ts_poll, -+ ioctl: anakin_ts_ioctl, -+ open: anakin_ts_open, -+ release: anakin_ts_release, -+ fasync: anakin_ts_fasync, -+}; -+ -+static struct miscdevice anakin_ts_miscdev = { -+ ANAKIN_TS_MINOR, -+ "anakin_ts", -+ &anakin_ts_fops -+}; -+ -+/* -+ * Initialization and exit routines -+ */ -+int __init -+anakin_ts_init(void) -+{ -+ int retval; -+ -+ if ((retval = request_irq(IRQ_TOUCHSCREEN, anakin_ts_handler, -+ SA_INTERRUPT, "anakin_ts", 0))) { -+ printk(KERN_WARNING "anakin_ts: failed to get IRQ\n"); -+ return retval; -+ } -+ __raw_writel(1, IO_BASE + IO_CONTROLLER + 8); -+ misc_register(&anakin_ts_miscdev); -+ -+ printk(KERN_NOTICE "Anakin touchscreen driver initialised\n"); -+ -+ return 0; -+} -+ -+void __exit -+anakin_ts_exit(void) -+{ -+ __raw_writel(0, IO_BASE + IO_CONTROLLER + 8); -+ free_irq(IRQ_TOUCHSCREEN, 0); -+ misc_deregister(&anakin_ts_miscdev); -+} -+ -+module_init(anakin_ts_init); -+module_exit(anakin_ts_exit); -+ -+MODULE_AUTHOR("Tak-Shing Chan "); -+MODULE_DESCRIPTION("Anakin touchscreen driver"); -+MODULE_SUPPORTED_DEVICE("touchscreen/anakin"); -diff -urN linux-2.4.26/drivers/char/cerf_keyb.c linux-2.4.26-vrs1/drivers/char/cerf_keyb.c ---- linux-2.4.26/drivers/char/cerf_keyb.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/cerf_keyb.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,380 @@ -+/* -+ cerf_keyb.c: This is the end. Daniel is writing a device driver!!! -+*/ -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define KBD_REPORT_UNKN -+ -+#define KBD_REPORT_ERR /* Report keyboard errors */ -+#define KBD_REPORT_UNKN /* Report unknown scan codes */ -+#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */ -+#define KBD_NO_DATA (-1) /* No data */ -+#define KBD_REPEAT_START (0x20) -+#define KBD_REPEAT_CONTINUE (0x05) -+#define KBD_KEY_DOWN_MAX (0x10) -+#define UINT_LEN (20) -+#define SC_LIM (69) -+#define KBD_ROWS (5) -+#define KBD_COLUMNS (8) -+ -+#define KBD_KEYUP (0x80) -+#define KBD_MODESCAN (0x7f) -+#define KBD_CAPSSCAN (0x3a) -+#define KBD_SHIFTSCAN (0x2a) -+#define KBD_NUMCURSCAN (0x7c) -+#define KBD_CTRLSCAN (0x1d) -+#define KBD_ALTSCAN (0x38) -+ -+#define KBD_UP_OFF (0) -+#define KBD_UP_ON (1) -+#define KBD_DOWN (2) -+#define KBD_DOWN_HOLD (3) -+ -+ -+ -+static unsigned char handle_kbd_event(void); -+static unsigned char kbd_read_input(void); -+static void column_set(unsigned int column); -+static int scancodes(unsigned char codeval[KBD_ROWS][KBD_COLUMNS]); -+ -+static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; -+static struct timer_list kbd_timer; -+ -+static short mode_ena = 0; -+static short numcur_ena = 0; -+static short shift_ena = 0; -+ -+#define E0_KPENTER 96 -+#define E0_RCTRL 97 -+#define E0_KPSLASH 98 -+#define E0_PRSCR 99 -+#define E0_RALT 100 -+#define E0_BREAK 101 /* (control-pause) */ -+#define E0_HOME 102 -+#define E0_UP 103 -+#define E0_PGUP 104 -+#define E0_LEFT 105 -+#define E0_RIGHT 106 -+#define E0_END 107 -+#define E0_DOWN 108 -+#define E0_PGDN 109 -+#define E0_INS 110 -+#define E0_DEL 111 -+#define E1_PAUSE 119 -+#define E0_MACRO 112 -+#define E0_F13 113 -+#define E0_F14 114 -+#define E0_HELP 115 -+#define E0_DO 116 -+#define E0_F17 117 -+#define E0_KPMINPLUS 118 -+#define E0_OK 124 -+#define E0_MSLW 125 -+#define E0_MSRW 126 -+#define E0_MSTM 127 -+ -+static unsigned char e0_keys[128] = { -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */ -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */ -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ -+ 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */ -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ -+ 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */ -+ E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */ -+ E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */ -+ E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */ -+ E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */ -+ 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */ -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ -+ 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */ -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ -+ 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ -+}; -+ -+static unsigned char cerf_normal_map[KBD_ROWS][KBD_COLUMNS] = { -+ {KBD_ALTSCAN, KBD_MODESCAN, 0x1e, 0x30, 0x2e, 0x20, 0x00, 0x00}, -+ {0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x00}, -+ {0x26, 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x00}, -+ {0x1f, 0x14, 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x00}, -+ {0x2c, KBD_SHIFTSCAN, KBD_CTRLSCAN, 0x39, KBD_NUMCURSCAN, 0x2b, 0x1c, 0x00} -+}; -+ -+static unsigned char cerf_mode_map[KBD_ROWS][KBD_COLUMNS] = { -+ {0x00, 0x00, 0x02, 0x03, 0x04, 0x05, 0x00, 0x00}, -+ {0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x00, 0x00}, // -+ {0x0d, 0x0c, 0x37, 0x35, 0x0d, 0x48, 0x28, 0x00}, -+ {0x01, 0x33, 0x34, 0x00, 0x4b, 0x27, 0x4d, 0x00}, // -+ {0x0f, 0x00, KBD_CAPSSCAN, 0x0e, 0x00, 0x50, 0x00, 0x00} -+}; -+ -+static unsigned char cerf_numcur_map[KBD_ROWS][KBD_COLUMNS] = { -+ {0x00, 0x00, 0x02, 0x03, 0x04, 0x05, 0x00, 0x00}, -+ {0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x00, 0x00}, -+ {0x0d, 0x0c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00}, -+ {0x00, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x4d, 0x00}, -+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00} -+}; -+ -+static void column_set(unsigned int column) -+{ -+ if (column < 0) -+ { -+ CERF_PDA_CPLD_UnSet(CERF_PDA_CPLD_KEYPAD_A, 0xFF, 0xFF); -+ CERF_PDA_CPLD_UnSet(CERF_PDA_CPLD_KEYPAD_B, 0xFF, 0xFF); -+ } -+ else -+ { -+ if(column < 4) -+ { -+ CERF_PDA_CPLD_Set(CERF_PDA_CPLD_KEYPAD_A, 1 << (column % 4), 0xFF); -+ CERF_PDA_CPLD_UnSet(CERF_PDA_CPLD_KEYPAD_B, 0xFF, 0xFF); -+ } -+ else -+ { -+ CERF_PDA_CPLD_UnSet(CERF_PDA_CPLD_KEYPAD_A, 0xFF, 0xFF); -+ CERF_PDA_CPLD_Set(CERF_PDA_CPLD_KEYPAD_B, 1 << (column % 4), 0xFF); -+ } -+ } -+} -+ -+static int scancodes(unsigned char codeval[KBD_ROWS][KBD_COLUMNS]) -+{ -+ int i, j; -+ -+ for(i = 0; i < KBD_COLUMNS; i++) -+ { -+ column_set(i); -+ udelay(50); -+ for(j = 0; j < KBD_ROWS; j++) -+ { -+ if(mode_ena) -+ codeval[j][i] = (GPLR & (1 << (20 + j)))?(cerf_mode_map[j][i]?cerf_mode_map[j][i]:cerf_normal_map[j][i]):0; -+ else if(numcur_ena) -+ codeval[j][i] = (GPLR & (1 << (20 + j)))?(cerf_numcur_map[j][i]?cerf_numcur_map[j][i]:cerf_normal_map[j][i]):0; -+ else -+ codeval[j][i] = (GPLR & (1 << (20 + j)))?cerf_normal_map[j][i]:0; -+ } -+ } -+ column_set(-1); -+ -+ return 0; -+} -+ -+static unsigned char kbd_read_input(void) -+{ -+ int i, j, k, l; -+ unsigned char prev; -+ static unsigned char count = 0; -+ -+ static unsigned char oldcodes[KBD_ROWS][KBD_COLUMNS]={{0,0,0,0,0,0,0,0}, -+ {0,0,0,0,0,0,0,0}, -+ {0,0,0,0,0,0,0,0}, -+ {0,0,0,0,0,0,0,0}, -+ {0,0,0,0,0,0,0,0}}; -+ unsigned char inputcode[KBD_ROWS][KBD_COLUMNS]; -+ -+ memset(inputcode, 0, sizeof(unsigned char) * (KBD_ROWS * KBD_COLUMNS)); -+ scancodes(inputcode); -+ -+ for(i = 0; i < KBD_COLUMNS; i++) -+ { -+ for(j = 0; j < KBD_ROWS; j++) -+ { -+// if(oldcodes[j][i] == 0xe0) -+// oldcodes[j][i] = -+ if(oldcodes[j][i] != inputcode[j][i]) -+ { -+ // Value of the key before entering this function -+ prev = oldcodes[j][i]; -+ -+ // KEYUP -+ if(inputcode[j][i] == 0 && oldcodes[j][i] != 0 && !(oldcodes[j][i] & KBD_KEYUP)) -+ { -+ oldcodes[j][i] |= KBD_KEYUP; -+ -+ if(mode_ena == KBD_UP_ON) -+ mode_ena = KBD_UP_OFF; -+ if(prev == KBD_MODESCAN) -+ if(mode_ena == KBD_DOWN_HOLD) -+ mode_ena = KBD_UP_OFF; -+ else if(mode_ena == KBD_DOWN) -+ mode_ena = KBD_UP_ON; -+ if(mode_ena == KBD_DOWN) -+ mode_ena = KBD_DOWN_HOLD; -+ } -+ // RESET KEYUP -+ else if(oldcodes[j][i] & KBD_KEYUP) -+ oldcodes[j][i] = 0; -+ // KEY DOWN -+ else -+ { -+ oldcodes[j][i] = inputcode[j][i]; -+ -+ // Parse out mode modifiers before the keyboard interpreter can touch them -+ if(inputcode[j][i] == KBD_MODESCAN) -+ { -+ if(!mode_ena) -+ mode_ena = KBD_DOWN; -+ continue; -+ } -+ if(inputcode[j][i] == KBD_NUMCURSCAN) -+ { -+ numcur_ena = numcur_ena?0:1; -+ continue; -+ } -+ } -+ //printk("Modified: (%#x,%#x), ipv:%#x, To: (%#.2x), From: (%#.2x), Flags:%d,%d,%d\r\n", j, i, inputcode[j][i], oldcodes[j][i], prev, mode_ena, shift_ena, numcur_ena); -+ return oldcodes[j][i]; -+ } -+ } -+ } -+ -+ return (unsigned char)(KBD_NO_DATA); -+} -+ -+int cerf_kbd_translate(unsigned char scancode, unsigned char *keycode, -+ char raw_mode) -+{ -+ static int prev_scancode; -+ -+ if (scancode == 0xe0 || scancode == 0xe1) { -+ prev_scancode = scancode; -+ return 0; -+ } -+ -+ if (scancode == 0x00 || scancode == 0xff) { -+ prev_scancode = 0; -+ return 0; -+ } -+ -+ scancode &= 0x7f; -+ -+ if (prev_scancode) { -+ if (prev_scancode != 0xe0) { -+ if (prev_scancode == 0xe1 && scancode == 0x1d) { -+ prev_scancode = 0x100; -+ return 0; -+ } else if (prev_scancode == 0x100 && scancode == 0x45) { -+ prev_scancode = 0; -+ } else { -+#ifdef KBD_REPORT_UNKN -+ if (!raw_mode) -+ printk(KERN_INFO "keyboard: unknown e1 escape sequence\n"); -+#endif -+ prev_scancode = 0; -+ return 0; -+ } -+ } else { -+ prev_scancode = 0; -+ if (scancode == 0x2a || scancode == 0x36) -+ return 0; -+ else { -+#ifdef KBD_REPORT_UNKN -+ if (!raw_mode) -+ printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n", -+ scancode); -+#endif -+ return 0; -+ } -+ } -+ } else -+ *keycode = scancode; -+ return 1; -+} -+ -+static inline void handle_keyboard_event(unsigned char scancode) -+{ -+ if(scancode != (unsigned char)(KBD_NO_DATA)) -+ { -+#ifdef CONFIG_VT -+ handle_scancode(scancode, !(scancode & KBD_KEYUP)); -+#endif -+ tasklet_schedule(&keyboard_tasklet); -+ } -+} -+ -+static unsigned char handle_kbd_event(void) -+{ -+ unsigned char scancode; -+ -+ scancode = kbd_read_input(); -+ handle_keyboard_event(scancode); -+ -+ return 0; -+} -+ -+/* Handle the automatic interrupts handled by the timer */ -+static void keyboard_interrupt(unsigned long foo) -+{ -+ spin_lock_irq(&kbd_controller_lock); -+ handle_kbd_event(); -+ spin_unlock_irq(&kbd_controller_lock); -+ -+ kbd_timer.expires = 8 + jiffies; -+ kbd_timer.data = 0x00000000; -+ kbd_timer.function = (void(*)(unsigned long))&keyboard_interrupt; -+ -+ add_timer(&kbd_timer); -+} -+ -+void cerf_leds(unsigned char leds) -+{ -+} -+char cerf_unexpected_up(unsigned char keycode) -+{ -+return 0; -+} -+int cerf_getkeycode(unsigned int scancode) -+{ -+return 0; -+} -+int cerf_setkeycode(unsigned int scancode, unsigned int keycode) -+{ -+return 0; -+} -+ -+void cerf_kbd_init_hw(void) -+{ -+ printk("Starting Cerf PDA Keyboard Driver... "); -+ -+ k_setkeycode = cerf_setkeycode; -+ k_getkeycode = cerf_getkeycode; -+ k_translate = cerf_kbd_translate; -+ k_unexpected_up = cerf_unexpected_up; -+ k_leds = cerf_leds; -+ -+ GPDR &= ~(GPIO_GPIO(20) | GPIO_GPIO(21) | GPIO_GPIO(22) | GPIO_GPIO(23) | GPIO_GPIO(24)); -+ kbd_timer.expires = 40 + jiffies; -+ kbd_timer.data = 0x00000000; -+ kbd_timer.function = (void(*)(unsigned long))&keyboard_interrupt; -+ -+ add_timer(&kbd_timer); -+ -+ printk("Done\r\n"); -+} -diff -urN linux-2.4.26/drivers/char/clps711x_keyb.c linux-2.4.26-vrs1/drivers/char/clps711x_keyb.c ---- linux-2.4.26/drivers/char/clps711x_keyb.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/clps711x_keyb.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,547 @@ -+/* -+ * drivers/char/clps711x_keyb.c -+ * -+ * Copyright (C) 2001 Thomas Gleixner -+ * -+ * based on drivers/edb7211_keyb.c, which is copyright (C) 2000 Bluemug Inc. -+ * -+ * Keyboard driver for ARM Linux on EP7xxx and CS89712 processors -+ * -+ * 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. See the file COPYING -+ * in the main directory of this archive for more details. -+ * -+ * -+ * Hardware: -+ * -+ * matrix scan keyboards based on EP7209,7211,7212,7312 and CS89712 -+ * on chip keyboard scanner. -+ * Adaption for different machines is done in init function. -+ * -+ * Basic Function: -+ * -+ * Basicly the driver is interrupt driven. It sets all column drivers -+ * high. If any key is pressed, a interrupt occures. Now a separate scan of -+ * each column is done. This scan is timer based, because we use a keyboard -+ * interface with decoupling capacitors (neccecary if you want to survive -+ * EMC compliance tests). Always one line is set high. When next timer event -+ * occures the scan data on port A are valid. This makes also sure, that no -+ * spurious keys are scanned. The kbd int on these CPU's is not deglitched! -+ * After scanning all columns, we switch back to int mode, if no key is -+ * pressed. If any is pressed we reschedule the scan within a programmable -+ * delay. If we would switch back to interrupt mode as long as a key is pressed, -+ * we come right back to the interrupt, because the int. is level triggered ! -+ * The timer based scan of the separate columns can also be done in one -+ * timer event (set fastscan to 1). -+ * -+ * Summary: -+ * The design of this keyboard controller chip is stupid at all ! -+ * -+ * Matrix translation: -+ * The matrix translation table is based on standard XT scancodes. Maybe -+ * you have to adjust the KEYISPRINTABLE macro if you set other codes. -+ * -+ * HandyKey: -+ * -+ * On small matrix keyboards you don't have enough keys for operation. -+ * The intention was to implement a operation mode as it's used on handys. -+ * You can rotate trough four scancode levels and produce e.g. with a 4x3 -+ * matrix 4*3*4 = 48 different keycodes. That's basicly enough for editing -+ * filenames or things like that. The HandyKey function takes care about -+ * nonprintable keys like cursors, backspace, del ... -+ * If a key is pressed and is a printable keycode, the code is put to the -+ * main keyboard handler and a cursor left is applied. If you press the same -+ * key again, the current character is deleted and the next level character -+ * is applied. (e.g. 1, a, b, c, 1 ....). If you press a different key, the -+ * driver applies cursor right, before processing the new key. -+ * The autocomplete feature moves the cursor right, if you do not press a -+ * key within a programmable time. -+ * If HandyKey is off, the keyboard behaviour is that of a standard keyboard -+ * HandyKey can be en/disabled from userspace with the proc/keyboard entry -+ * -+ * proc/keyboard: -+ * -+ * Read access gives back the actual state of the HandyKey function -+ * h:0 Disabled -+ * h:1 Enabled -+ * Write access has two functions. Changing the HandyKey mode and applying -+ * a different scancode translation table. -+ * Syntax is: h:0 disable Handykey -+ * h:1 enabled Handykey -+ * t:array[256] of bytes Transfer translation table -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+void clps711x_kbd_init_hw(void); -+ -+/* -+ * Values for the keyboard column scan control register. -+ */ -+#define KBSC_HI 0x0 /* All driven high */ -+#define KBSC_LO 0x1 /* All driven low */ -+#define KBSC_X 0x2 /* All high impedance */ -+#define KBSC_COL0 0x8 /* Column 0 high, others high impedance */ -+#define KBSC_COL1 0x9 /* Column 1 high, others high impedance */ -+#define KBSC_COL2 0xa /* Column 2 high, others high impedance */ -+#define KBSC_COL3 0xb /* Column 3 high, others high impedance */ -+#define KBSC_COL4 0xc /* Column 4 high, others high impedance */ -+#define KBSC_COL5 0xd /* Column 5 high, others high impedance */ -+#define KBSC_COL6 0xe /* Column 6 high, others high impedance */ -+#define KBSC_COL7 0xf /* Column 7 high, others high impedance */ -+ -+/* -+* Keycodes for cursor left/right and delete (used by HandyKey) -+*/ -+#define KEYCODE_CLEFT 0x4b -+#define KEYCODE_CRIGHT 0x4d -+#define KEYCODE_DEL 0x53 -+#define KEYISPRINTABLE(code) ( (code > 0x01 && code < 0x37 && code != 0x1c \ -+ && code != 0x0e) || code == 0x39) -+ -+/* Simple translation table for the SysRq keys */ -+#ifdef CONFIG_MAGIC_SYSRQ -+unsigned char clps711x_kbd_sysrq_xlate[128] = -+ "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ -+ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ -+ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ -+ "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ -+ "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ -+ "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ -+ "\r\000/"; /* 0x60 - 0x6f */ -+#endif -+ -+/* -+ * This table maps row/column keyboard matrix positions to XT scancodes. -+ * It's a default table, which can be overriden by writing to proc/keyboard -+ */ -+#ifdef CONFIG_ARCH_AUTCPU12 -+static unsigned char autcpu12_scancode[256] = -+{ -+/* Column: -+ Row 0 1 2 3 4 5 6 7 */ -+/* A0 */ 0x08, 0x09, 0x0a, 0x0e, 0x05, 0x06, 0x00, 0x00, -+/* A1 */ 0x07, 0x53, 0x02, 0x03, 0x04, 0x0f, 0x00, 0x00, -+/* A2 */ 0x0c, 0x0b, 0x33, 0x1c, 0xff, 0x4b, 0x00, 0x00, -+/* A3 */ 0x48, 0x50, 0x4d, 0x3b, 0x3c, 0x3d, 0x00, 0x00, -+/* A4 */ 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+/* A5 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+/* A6 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+/* A7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ -+/* A0 */ 0x1e, 0x20, 0x22, 0x0e, 0x24, 0x32, 0x00, 0x00, -+/* A1 */ 0x19, 0x53, 0x1f, 0x2f, 0x15, 0x0f, 0x00, 0x00, -+/* A2 */ 0x0c, 0x39, 0x34, 0x1c, 0xff, 0x4b, 0x00, 0x00, -+/* A3 */ 0x48, 0x50, 0x4d, 0x3b, 0x3c, 0x3d, 0x00, 0x00, -+/* A4 */ 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+/* A5 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+/* A6 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+/* A7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ -+/* A0 */ 0x30, 0x12, 0x23, 0x0e, 0x25, 0x31, 0x00, 0x00, -+/* A1 */ 0x10, 0x53, 0x14, 0x11, 0x2c, 0x0f, 0x00, 0x00, -+/* A2 */ 0x0c, 0x0b, 0x27, 0x1c, 0xff, 0x4b, 0x00, 0x00, -+/* A3 */ 0x48, 0x50, 0x4d, 0x3b, 0x3c, 0x3d, 0x00, 0x00, -+/* A4 */ 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+/* A5 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+/* A6 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+/* A7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+ -+/* A0 */ 0x2e, 0x21, 0x17, 0x0e, 0x26, 0x18, 0x00, 0x00, -+/* A1 */ 0x13, 0x53, 0x16, 0x2D, 0x04, 0x0f, 0x00, 0x00, -+/* A2 */ 0x0c, 0x39, 0x35, 0x1c, 0xff, 0x4b, 0x00, 0x00, -+/* A3 */ 0x48, 0x50, 0x4d, 0x3b, 0x3c, 0x3d, 0x00, 0x00, -+/* A4 */ 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+/* A5 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+/* A6 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+/* A7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+}; -+#endif -+ -+static int keys[8]; -+static int new_keys[8]; -+static int previous_keys[8]; -+ -+static int fastscan; -+static int scan_interval; -+static int scan_delay; -+static int last_column; -+static int key_is_pressed; -+ -+static unsigned char *act_scancode; -+ -+static struct kbd_handy_key { -+ int ena; -+ int code; -+ int shift; -+ int autocomplete; -+ unsigned long expires; -+ unsigned long delay; -+ unsigned char left; -+ unsigned char right; -+ unsigned char del; -+} khandy; -+ -+static struct tq_struct kbd_process_task; -+static struct timer_list clps711x_kbd_timer; -+static struct timer_list clps711x_kbdhandy_timer; -+static struct proc_dir_entry *clps711x_keyboard_proc_entry = NULL; -+ -+/* -+ * Translate a raw keycode to an XT keyboard scancode. -+ */ -+static int clps711x_translate(unsigned char scancode, unsigned char *keycode, -+ char raw_mode) -+{ -+ *keycode = act_scancode[scancode]; -+ return 1; -+} -+ -+/* -+* Initialize handykey structure -+* clear code, clear shift -+* scan scancode for cursor right/left and delete -+*/ -+static void clps711x_handykey_init(void) { -+ -+ int i; -+ -+ khandy.ena = 0; -+ khandy.code = 0; -+ khandy.shift = 0; -+ khandy.autocomplete = 0; -+ for(i = 0; i < 64; i++) { -+ switch(act_scancode[i]) { -+ case KEYCODE_CLEFT: khandy.left = i; break; -+ case KEYCODE_CRIGHT: khandy.right = i; break; -+ case KEYCODE_DEL: khandy.del = i; break; -+ } -+ } -+} -+ -+/* -+* Check for handy key and process it -+*/ -+void inline clps711x_checkhandy(int col, int row) { -+ -+ int scode, down; -+ unsigned char kcode; -+ -+ scode = (row<<3) + col; -+ down = keys[col]>>row & 0x01; -+ kcode = act_scancode[scode]; -+ -+ if (!khandy.ena) { -+ if (khandy.code) { -+ handle_scancode(khandy.right,1); -+ handle_scancode(khandy.right,0); -+ } -+ khandy.code = 0; -+ khandy.shift = 0; -+ khandy.autocomplete = 0; -+ } -+ -+ if(!kcode) -+ return; -+ -+ if (!down || !khandy.ena) { -+ if (khandy.ena && KEYISPRINTABLE(act_scancode[scode])) -+ khandy.autocomplete = 1; -+ else -+ handle_scancode(scode + khandy.shift, down); -+ return; -+ } -+ -+ khandy.autocomplete = 0; -+ if (KEYISPRINTABLE(kcode)) { -+ if (khandy.code) { -+ if(khandy.code == (scode|0x100)) { -+ handle_scancode(khandy.del,1); -+ handle_scancode(khandy.del,0); -+ khandy.shift = khandy.shift < 3*64 ? khandy.shift + 64 : 0 ; -+ } else { -+ handle_scancode(khandy.right,1); -+ handle_scancode(khandy.right,0); -+ khandy.shift = 0; -+ } -+ } -+ handle_scancode(scode + khandy.shift, 1); -+ handle_scancode(scode + khandy.shift, 0); -+ khandy.code = scode | 0x100; -+ handle_scancode(khandy.left,1); -+ handle_scancode(khandy.left,0); -+ } else { -+ if (khandy.code) { -+ khandy.code = 0; -+ handle_scancode(khandy.right,1); -+ handle_scancode(khandy.right,0); -+ } -+ khandy.shift = 0; -+ handle_scancode(scode, down); -+ } -+} -+ -+ -+/* -+ * Process the new key data -+ */ -+static void clps711x_kbd_process(void* data) -+{ -+ int col,row,res; -+ -+ for (col = 0; col < 8; col++) { -+ if (( res = previous_keys[col] ^ keys[col]) == 0) -+ continue; -+ for(row = 0; row < 8; row++) { -+ if ( ((res >> row) & 0x01) != 0) -+ clps711x_checkhandy(col,row); -+ } -+ } -+ /* Update the state variables. */ -+ memcpy(previous_keys, keys, 8 * sizeof(int)); -+ -+ /* reschedule, if autocomplete pending */ -+ if (khandy.autocomplete) { -+ khandy.expires = jiffies + khandy.delay; -+ mod_timer(&clps711x_kbdhandy_timer,khandy.expires); -+ } -+ -+} -+ -+static char clps711x_unexpected_up(unsigned char scancode) -+{ -+ return 0200; -+} -+ -+/* -+* Handle timer event, for autocomplete function -+* Reschedule keyboard process task -+*/ -+static void clps711x_kbdhandy_timeout(unsigned long data) -+{ -+ if(khandy.autocomplete) { -+ khandy.code = 0; -+ khandy.shift = 0; -+ khandy.autocomplete = 0; -+ handle_scancode(khandy.right,1); -+ handle_scancode(khandy.right,0); -+ } -+} -+ -+/* -+* Handle timer event, while in pollmode -+*/ -+static void clps711x_kbd_timeout(unsigned long data) -+{ -+ int i; -+ unsigned long flags; -+ /* -+ * read bits of actual column or all columns in fastscan-mode -+ */ -+ for (i = 0; i < 8; i++) { -+ new_keys[last_column - KBSC_COL0] = clps_readb(PADR) & 0xff; -+ key_is_pressed |= new_keys[last_column - KBSC_COL0]; -+ last_column = last_column < KBSC_COL7 ? last_column + 1 : KBSC_COL0; -+ local_irq_save(flags); -+ clps_writel( (clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK) -+ | last_column, SYSCON1); -+ local_irq_restore(flags); -+ /* -+ * For fastscan, apply a short delay to settle scanlines -+ * else break and wait for next timeout -+ */ -+ if (fastscan) -+ udelay(5); -+ else -+ break; -+ } -+ -+ if (key_is_pressed) -+ khandy.autocomplete = 0; -+ -+ /* -+ * switch to interupt mode, if all columns scanned and no key pressed -+ * else reschedule scan -+ */ -+ if (last_column == KBSC_COL0) { -+ if (!key_is_pressed) { -+ local_irq_save(flags); -+ clps_writel( (clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK) -+ | KBSC_HI, SYSCON1); -+ local_irq_restore(flags); -+ clps_writel(0,KBDEOI); -+ enable_irq(IRQ_KBDINT); -+ } else { -+ clps711x_kbd_timer.expires = jiffies + scan_interval; -+ add_timer(&clps711x_kbd_timer); -+ } -+ key_is_pressed = 0; -+ memcpy(keys, new_keys, 8 * sizeof(int)); -+ for (i = 0; i < 8; i++) { -+ if (previous_keys[i] != keys[i]) { -+ queue_task(&kbd_process_task, &tq_timer); -+ return; -+ } -+ } -+ } else { -+ clps711x_kbd_timer.expires = jiffies + scan_delay; -+ add_timer(&clps711x_kbd_timer); -+ } -+} -+ -+/* -+* Keyboard interrupt, change to scheduling mode -+*/ -+static void clps711x_kbd_int(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ -+#ifdef CONFIG_VT -+ kbd_pt_regs = regs; -+#endif -+ disable_irq(IRQ_KBDINT); -+ khandy.autocomplete = 0; -+ clps_writel( (clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK) -+ | KBSC_COL0, SYSCON1); -+ clps711x_kbd_timer.expires = jiffies + scan_delay; -+ add_timer(&clps711x_kbd_timer); -+} -+ -+ -+static int clps711x_kbd_proc_keyboard_read(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ if (count < 2) -+ return -EINVAL; -+ -+ return sprintf(page,"h:%d\n",khandy.ena); -+} -+ -+static int clps711x_kbd_proc_keyboard_write(struct file *file, const char *buffer, -+ unsigned long count, void *data) -+{ -+ unsigned char buf[260]; -+ -+ if (count < 3|| count > 258) -+ return -EINVAL; -+ if (copy_from_user(buf, buffer, count)) -+ return -EFAULT; -+ if (buf[1] != ':') -+ return -EINVAL; -+ -+ if (buf[0] == 'h') { -+ switch (buf[2]) { -+ case '0': -+ case '1': -+ case '2': khandy.ena = buf[2]-'0'; return count; -+ } -+ } -+ -+ if (buf[0] == 't' && count == 258) { -+ memcpy(act_scancode,buf+2,256); -+ /* rescan cursor left/right and del */ -+ clps711x_handykey_init(); -+ return count; -+ } -+ -+ return -EINVAL; -+} -+ -+ -+/* -+ * Initialize the keyboard hardware. -+ * Set all columns high -+ * Install interrupt handler -+ * -+ * Machine dependent parameters: -+ * -+ * fastscan: 0 = timer based scan for each column -+ * 1 = full scan is done in one timer event -+ * scan_delay: time between column scans -+ * setup even if you use fastscan (leeds to timer mode) -+ * scan_interval: time between full scans -+ * handy.delay: timeout before last entry get's automatically valid -+ * -+ */ -+void __init clps711x_kbd_init_hw(void) -+{ -+ -+ /* -+ * put here machine dependent init stuff -+ */ -+ if (machine_is_autcpu12()) { -+ fastscan = 0; -+ scan_interval = 50*HZ/1000; -+ scan_delay = 20*HZ/1000; -+ khandy.delay = 750*HZ/1000; -+ act_scancode = autcpu12_scancode; -+ } else { -+ printk("No initialization, keyboard killed\n"); -+ return; -+ } -+ -+ last_column = KBSC_COL0; -+ key_is_pressed = 0; -+ -+ clps711x_handykey_init(); -+ -+ /* Register the /proc entry */ -+ clps711x_keyboard_proc_entry = create_proc_entry("keyboard", 0444, -+ &proc_root); -+ if (clps711x_keyboard_proc_entry == NULL) -+ printk("Couldn't create the /proc entry for the keyboard\n"); -+ else { -+ clps711x_keyboard_proc_entry->read_proc = -+ &clps711x_kbd_proc_keyboard_read; -+ clps711x_keyboard_proc_entry->write_proc = -+ &clps711x_kbd_proc_keyboard_write; -+ } -+ -+ /* Initialize the matrix processing task. */ -+ k_translate = clps711x_translate; -+ k_unexpected_up = clps711x_unexpected_up; -+ kbd_process_task.routine = clps711x_kbd_process; -+ kbd_process_task.data = 0; -+ -+ /* Setup the timer for keyboard polling, after kbd int */ -+ init_timer(&clps711x_kbd_timer); -+ clps711x_kbd_timer.function = clps711x_kbd_timeout; -+ clps711x_kbd_timer.data = 0; -+ init_timer(&clps711x_kbdhandy_timer); -+ clps711x_kbdhandy_timer.function = clps711x_kbdhandy_timeout; -+ clps711x_kbdhandy_timer.data = 1; -+ -+ /* Initialise scan hardware, request int */ -+ clps_writel( (clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK) -+ | KBSC_HI, SYSCON1); -+ request_irq(IRQ_KBDINT, clps711x_kbd_int, 0,"keyboard", NULL); -+ -+ printk("clps711x keyboard init done\n"); -+ -+} -diff -urN linux-2.4.26/drivers/char/console.c linux-2.4.26-vrs1/drivers/char/console.c ---- linux-2.4.26/drivers/char/console.c 2003-11-28 18:26:20.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/char/console.c 2004-01-14 21:38:59.000000000 +0000 -@@ -72,8 +72,14 @@ - * - * Removed console_lock, enabled interrupts across all console operations - * 13 March 2001, Andrew Morton -+ * -+ * Split out con_write_ctrl_* functions from do_con_write & changed -+ * vc_state to function pointer -+ * by Russell King , July 1998 - */ - -+#define CONSOLE_WIP -+ - #include - #include - #include -@@ -228,7 +234,7 @@ - static inline unsigned short *screenpos(int currcons, int offset, int viewed) - { - unsigned short *p; -- -+ - if (!viewed) - p = (unsigned short *)(origin + offset); - else if (!sw->con_screen_pos) -@@ -729,7 +735,7 @@ - else { - unsigned short *p = (unsigned short *) kmalloc(ss, GFP_USER); - if (!p) { -- for (i = first; i < currcons; i++) -+ for (i = first; i< currcons; i++) - if (newscreens[i]) - kfree(newscreens[i]); - return -ENOMEM; -@@ -847,7 +853,7 @@ - /* the default colour table, for VGA+ colour systems */ - int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa, - 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff}; --int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa, -+int default_grn[] = {0x00,0x00,0xaa,0xaa,0x00,0x00,0xaa,0xaa, - 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff}; - int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, - 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff}; -@@ -1393,6 +1399,19 @@ - need_wrap = 0; - } - -+static int con_write_ctrl_ESnormal(int, struct tty_struct *, unsigned int); -+static int con_write_ctrl_ESesc(int, struct tty_struct *, unsigned int); -+static int con_write_ctrl_ESnonstd(int, struct tty_struct *, unsigned int); -+static int con_write_ctrl_ESpalette(int, struct tty_struct *, unsigned int); -+static int con_write_ctrl_ESsquare(int, struct tty_struct *, unsigned int); -+static int con_write_ctrl_ESgetpars(int, struct tty_struct *, unsigned int); -+static int con_write_ctrl_ESgotpars(int, struct tty_struct *, unsigned int); -+static int con_write_ctrl_ESpercent(int, struct tty_struct *, unsigned int); -+static int con_write_ctrl_ESfunckey(int, struct tty_struct *, unsigned int); -+static int con_write_ctrl_EShash(int, struct tty_struct *, unsigned int); -+static int con_write_ctrl_ESsetG0(int, struct tty_struct *, unsigned int); -+static int con_write_ctrl_ESsetG1(int, struct tty_struct *, unsigned int); -+ - enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, - EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, - ESpalette }; -@@ -1402,7 +1421,7 @@ - { - top = 0; - bottom = video_num_lines; -- vc_state = ESnormal; -+ vc_state = con_write_ctrl_ESnormal; - ques = 0; - translate = set_translate(LAT1_MAP,currcons); - G0_charset = LAT1_MAP; -@@ -1500,328 +1519,426 @@ - disp_ctrl = 0; - return; - case 24: case 26: -- vc_state = ESnormal; -+ vc_state = con_write_ctrl_ESnormal; - return; - case 27: -- vc_state = ESesc; -+ vc_state = con_write_ctrl_ESesc; - return; - case 127: - del(currcons); - return; - case 128+27: -- vc_state = ESsquare; -+ vc_state = con_write_ctrl_ESsquare; - return; - } -- switch(vc_state) { -- case ESesc: -- vc_state = ESnormal; -- switch (c) { -- case '[': -- vc_state = ESsquare; -- return; -- case ']': -- vc_state = ESnonstd; -- return; -- case '%': -- vc_state = ESpercent; -- return; -- case 'E': -- cr(currcons); -- lf(currcons); -- return; -- case 'M': -- ri(currcons); -- return; -- case 'D': -- lf(currcons); -- return; -- case 'H': -- tab_stop[x >> 5] |= (1 << (x & 31)); -- return; -- case 'Z': -- respond_ID(tty); -- return; -- case '7': -- save_cur(currcons); -- return; -- case '8': -- restore_cur(currcons); -- return; -- case '(': -- vc_state = ESsetG0; -- return; -- case ')': -- vc_state = ESsetG1; -- return; -- case '#': -- vc_state = EShash; -- return; -- case 'c': -- reset_terminal(currcons,1); -- return; -- case '>': /* Numeric keypad */ -- clr_kbd(kbdapplic); -- return; -- case '=': /* Appl. keypad */ -- set_kbd(kbdapplic); -- return; -+ vc_state(currcons, tty, c); -+} -+ -+static int con_write_utf(int currcons, int c) -+{ -+ unsigned int chr; -+ -+ /* Combine UTF-8 into Unicode */ -+ /* Incomplete characters silently ignored */ -+ if (c < 0x80) { -+ utf_count = 0; -+ return c; -+ } -+ -+ if (utf_count > 0 && (c & 0xc0) == 0x80) { -+ chr = (utf_char << 6) | (c & 0x3f); -+ utf_count--; -+ if (utf_count == 0) -+ return chr; -+ } else { -+ unsigned int count; -+ if ((c & 0xe0) == 0xc0) { -+ count = 1; -+ chr = (c & 0x1f); -+ } else if ((c & 0xf0) == 0xe0) { -+ count = 2; -+ chr = (c & 0x0f); -+ } else if ((c & 0xf8) == 0xf0) { -+ count = 3; -+ chr = (c & 0x07); -+ } else if ((c & 0xfc) == 0xf8) { -+ count = 4; -+ chr = (c & 0x03); -+ } else if ((c & 0xfe) == 0xfc) { -+ count = 5; -+ chr = (c & 0x01); -+ } else { -+ count = 0; -+ chr = 0; - } -- return; -- case ESnonstd: -- if (c=='P') { /* palette escape sequence */ -- for (npar=0; npar='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) { -- par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ; -- if (npar==7) { -- int i = par[0]*3, j = 1; -- palette[i] = 16*par[j++]; -- palette[i++] += par[j++]; -- palette[i] = 16*par[j++]; -- palette[i++] += par[j++]; -- palette[i] = 16*par[j++]; -- palette[i] += par[j]; -- set_palette(currcons); -- vc_state = ESnormal; -- } -- } else -- vc_state = ESnormal; -- return; -- case ESsquare: -- for(npar = 0 ; npar < NPAR ; npar++) -- par[npar] = 0; -- npar = 0; -- vc_state = ESgetpars; -- if (c == '[') { /* Function key */ -- vc_state=ESfunckey; -- return; -+ utf_count = count; -+ } -+ -+ utf_char = chr; -+ return -1; -+} -+ -+static int con_write_ctrl_ESnormal(int currcons, struct tty_struct *tty, unsigned int c) -+{ -+ return 0; -+} -+ -+static int con_write_ctrl_ESesc(int currcons, struct tty_struct *tty, unsigned int c) -+{ -+ vc_state = con_write_ctrl_ESnormal; -+ switch (c) { -+ case '[': -+ vc_state = con_write_ctrl_ESsquare; -+ break; -+ case ']': -+ vc_state = con_write_ctrl_ESnonstd; -+ break; -+ case '%': -+ vc_state = con_write_ctrl_ESpercent; -+ break; -+ case 'E': -+ cr(currcons); -+ lf(currcons); -+ break; -+ case 'M': -+ ri(currcons); -+ break; -+ case 'D': -+ lf(currcons); -+ break; -+ case 'H': -+ tab_stop[x >> 5] |= (1 << (x & 31)); -+ break; -+ case 'Z': -+ respond_ID(tty); -+ break; -+ case '7': -+ save_cur(currcons); -+ break; -+ case '8': -+ restore_cur(currcons); -+ return 1; -+ case '(': -+ vc_state = con_write_ctrl_ESsetG0; -+ break; -+ case ')': -+ vc_state = con_write_ctrl_ESsetG1; -+ break; -+ case '#': -+ vc_state = con_write_ctrl_EShash; -+ break; -+ case 'c': -+ reset_terminal(currcons,1); -+ return 1; -+ case '>': /* Numeric keypad */ -+ clr_kbd(kbdapplic); -+ break; -+ case '=': /* Appl. keypad */ -+ set_kbd(kbdapplic); -+ break; -+ } -+ return 0; -+} -+ -+static int con_write_ctrl_ESnonstd(int currcons, struct tty_struct *tty, unsigned int c) -+{ -+ switch (c) { -+ case 'P': /* palette escape sequence */ -+ for (npar=0; npar='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) { -+ par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ; -+ if (npar==7) { -+ int i = par[0]*3, j = 1; -+ palette[i] = 16*par[j++]; -+ palette[i++] += par[j++]; -+ palette[i] = 16*par[j++]; -+ palette[i++] += par[j++]; -+ palette[i] = 16*par[j++]; -+ palette[i] += par[j]; -+ set_palette(currcons); -+ vc_state = con_write_ctrl_ESnormal; - } -- ques = (c=='?'); -- if (ques) -- return; -- case ESgetpars: -- if (c==';' && npar='0' && c<='9') { -- par[npar] *= 10; -- par[npar] += c-'0'; -- return; -- } else vc_state=ESgotpars; -- case ESgotpars: -- vc_state = ESnormal; -- switch(c) { -- case 'h': -- set_mode(currcons,1); -- return; -- case 'l': -- set_mode(currcons,0); -- return; -- case 'c': -- if (ques) { -- if (par[0]) -- cursor_type = par[0] | (par[1]<<8) | (par[2]<<16); -- else -- cursor_type = CUR_DEFAULT; -- return; -- } -- break; -- case 'm': -- if (ques) { -- clear_selection(); -- if (par[0]) -- complement_mask = par[0]<<8 | par[1]; -- else -- complement_mask = s_complement_mask; -- return; -- } -- break; -- case 'n': -- if (!ques) { -- if (par[0] == 5) -- status_report(tty); -- else if (par[0] == 6) -- cursor_report(currcons,tty); -- } -- return; -+ } else -+ vc_state = con_write_ctrl_ESnormal; -+ return 0; -+} -+ -+static int con_write_ctrl_ESsquare(int currcons, struct tty_struct *tty, unsigned int c) -+{ -+ for(npar = 0 ; npar < NPAR ; npar++) -+ par[npar] = 0; -+ npar = 0; -+ vc_state = con_write_ctrl_ESgetpars; -+ if (c == '[') { /* Function key */ -+ vc_state = con_write_ctrl_ESfunckey; -+ return 0; -+ } -+ ques = (c=='?'); -+ if (ques) -+ return 0; -+ return con_write_ctrl_ESgetpars(currcons, tty, c); -+} -+ -+static int con_write_ctrl_ESgetpars(int currcons, struct tty_struct *tty, unsigned int c) -+{ -+ if (c==';' && npar='0' && c<='9') { -+ par[npar] *= 10; -+ par[npar] += c-'0'; -+ return 0; -+ } else vc_state = con_write_ctrl_ESgotpars; -+ return con_write_ctrl_ESgotpars(currcons, tty, c); -+} -+ -+static int con_write_ctrl_ESgotpars(int currcons, struct tty_struct *tty, unsigned int c) -+{ -+ vc_state = con_write_ctrl_ESnormal; -+ switch(c) { -+ case 'h': -+ set_mode(currcons,1); -+ return 0; -+ case 'l': -+ set_mode(currcons,0); -+ return 0; -+ case 'c': -+ if (ques) { -+ if (par[0]) -+ cursor_type = par[0] | (par[1]<<8) | (par[2]<<16); -+ else -+ cursor_type = CUR_DEFAULT; -+ return 0; - } -+ break; -+ case 'm': - if (ques) { -- ques = 0; -- return; -+ clear_selection(); -+ if (par[0]) -+ complement_mask = par[0]<<8 | par[1]; -+ else -+ complement_mask = s_complement_mask; -+ return 0; - } -- switch(c) { -- case 'G': case '`': -- if (par[0]) par[0]--; -- gotoxy(currcons,par[0],y); -- return; -- case 'A': -- if (!par[0]) par[0]++; -- gotoxy(currcons,x,y-par[0]); -- return; -- case 'B': case 'e': -- if (!par[0]) par[0]++; -- gotoxy(currcons,x,y+par[0]); -- return; -- case 'C': case 'a': -- if (!par[0]) par[0]++; -- gotoxy(currcons,x+par[0],y); -- return; -- case 'D': -- if (!par[0]) par[0]++; -- gotoxy(currcons,x-par[0],y); -- return; -- case 'E': -- if (!par[0]) par[0]++; -- gotoxy(currcons,0,y+par[0]); -- return; -- case 'F': -- if (!par[0]) par[0]++; -- gotoxy(currcons,0,y-par[0]); -- return; -- case 'd': -- if (par[0]) par[0]--; -- gotoxay(currcons,x,par[0]); -- return; -- case 'H': case 'f': -- if (par[0]) par[0]--; -- if (par[1]) par[1]--; -- gotoxay(currcons,par[1],par[0]); -- return; -- case 'J': -- csi_J(currcons,par[0]); -- return; -- case 'K': -- csi_K(currcons,par[0]); -- return; -- case 'L': -- csi_L(currcons,par[0]); -- return; -- case 'M': -- csi_M(currcons,par[0]); -- return; -- case 'P': -- csi_P(currcons,par[0]); -- return; -- case 'c': -- if (!par[0]) -- respond_ID(tty); -- return; -- case 'g': -- if (!par[0]) -- tab_stop[x >> 5] &= ~(1 << (x & 31)); -- else if (par[0] == 3) { -- tab_stop[0] = -- tab_stop[1] = -- tab_stop[2] = -- tab_stop[3] = -- tab_stop[4] = 0; -- } -- return; -- case 'm': -- csi_m(currcons); -- return; -- case 'q': /* DECLL - but only 3 leds */ -- /* map 0,1,2,3 to 0,1,2,4 */ -- if (par[0] < 4) -- setledstate(kbd_table + currcons, -- (par[0] < 3) ? par[0] : 4); -- return; -- case 'r': -- if (!par[0]) -- par[0]++; -- if (!par[1]) -- par[1] = video_num_lines; -- /* Minimum allowed region is 2 lines */ -- if (par[0] < par[1] && -- par[1] <= video_num_lines) { -- top=par[0]-1; -- bottom=par[1]; -- gotoxay(currcons,0,0); -- } -- return; -- case 's': -- save_cur(currcons); -- return; -- case 'u': -- restore_cur(currcons); -- return; -- case 'X': -- csi_X(currcons, par[0]); -- return; -- case '@': -- csi_at(currcons,par[0]); -- return; -- case ']': /* setterm functions */ -- setterm_command(currcons); -- return; -+ break; -+ case 'n': -+ if (!ques) { -+ if (par[0] == 5) -+ status_report(tty); -+ else if (par[0] == 6) -+ cursor_report(currcons,tty); - } -- return; -- case ESpercent: -- vc_state = ESnormal; -- switch (c) { -- case '@': /* defined in ISO 2022 */ -- utf = 0; -- return; -- case 'G': /* prelim official escape code */ -- case '8': /* retained for compatibility */ -- utf = 1; -- return; -+ return 0; -+ } -+ if (ques) { -+ ques = 0; -+ return 0; -+ } -+ switch(c) { -+ case 'G': case '`': -+ if (par[0]) par[0]--; -+ gotoxy(currcons,par[0],y); -+ break; -+ case 'A': -+ if (!par[0]) par[0]++; -+ gotoxy(currcons,x,y-par[0]); -+ break; -+ case 'B': case 'e': -+ if (!par[0]) par[0]++; -+ gotoxy(currcons,x,y+par[0]); -+ break; -+ case 'C': case 'a': -+ if (!par[0]) par[0]++; -+ gotoxy(currcons,x+par[0],y); -+ break; -+ case 'D': -+ if (!par[0]) par[0]++; -+ gotoxy(currcons,x-par[0],y); -+ break; -+ case 'E': -+ if (!par[0]) par[0]++; -+ gotoxy(currcons,0,y+par[0]); -+ break; -+ case 'F': -+ if (!par[0]) par[0]++; -+ gotoxy(currcons,0,y-par[0]); -+ break; -+ case 'd': -+ if (par[0]) par[0]--; -+ gotoxay(currcons,x,par[0]); -+ break; -+ case 'H': case 'f': -+ if (par[0]) par[0]--; -+ if (par[1]) par[1]--; -+ gotoxay(currcons,par[1],par[0]); -+ break; -+ case 'J': -+ csi_J(currcons,par[0]); -+ break; -+ case 'K': -+ csi_K(currcons,par[0]); -+ break; -+ case 'L': -+ csi_L(currcons,par[0]); -+ break; -+ case 'M': -+ csi_M(currcons,par[0]); -+ break; -+ case 'P': -+ csi_P(currcons,par[0]); -+ break; -+ case 'c': -+ if (!par[0]) -+ respond_ID(tty); -+ break; -+ case 'g': -+ if (!par[0]) -+ tab_stop[x >> 5] &= ~(1 << (x & 31)); -+ else if (par[0] == 3) { -+ tab_stop[0] = -+ tab_stop[1] = -+ tab_stop[2] = -+ tab_stop[3] = -+ tab_stop[4] = 0; - } -- return; -- case ESfunckey: -- vc_state = ESnormal; -- return; -- case EShash: -- vc_state = ESnormal; -- if (c == '8') { -- /* DEC screen alignment test. kludge :-) */ -- video_erase_char = -- (video_erase_char & 0xff00) | 'E'; -- csi_J(currcons, 2); -- video_erase_char = -- (video_erase_char & 0xff00) | ' '; -- do_update_region(currcons, origin, screenbuf_size/2); -+ break; -+ case 'm': -+ csi_m(currcons); -+ return 1; -+ case 'q': /* DECLL - but only 3 leds */ -+ /* map 0,1,2,3 to 0,1,2,4 */ -+ if (par[0] < 4) -+ setledstate(kbd_table + currcons, -+ (par[0] < 3) ? par[0] : 4); -+ break; -+ case 'r': -+ if (!par[0]) -+ par[0]++; -+ if (!par[1]) -+ par[1] = video_num_lines; -+ /* Minimum allowed region is 2 lines */ -+ if (par[0] < par[1] && -+ par[1] <= video_num_lines) { -+ top=par[0]-1; -+ bottom=par[1]; -+ gotoxay(currcons,0,0); - } -- return; -- case ESsetG0: -- if (c == '0') -- G0_charset = GRAF_MAP; -- else if (c == 'B') -- G0_charset = LAT1_MAP; -- else if (c == 'U') -- G0_charset = IBMPC_MAP; -- else if (c == 'K') -- G0_charset = USER_MAP; -- if (charset == 0) -- translate = set_translate(G0_charset,currcons); -- vc_state = ESnormal; -- return; -- case ESsetG1: -- if (c == '0') -- G1_charset = GRAF_MAP; -- else if (c == 'B') -- G1_charset = LAT1_MAP; -- else if (c == 'U') -- G1_charset = IBMPC_MAP; -- else if (c == 'K') -- G1_charset = USER_MAP; -- if (charset == 1) -- translate = set_translate(G1_charset,currcons); -- vc_state = ESnormal; -- return; -- default: -- vc_state = ESnormal; -+ break; -+ case 's': -+ save_cur(currcons); -+ break; -+ case 'u': -+ restore_cur(currcons); -+ return 1; -+ case 'X': -+ csi_X(currcons, par[0]); -+ break; -+ case '@': -+ csi_at(currcons,par[0]); -+ break; -+ case ']': /* setterm functions */ -+ setterm_command(currcons); -+ break; -+ } -+ return 0; -+} -+ -+static int con_write_ctrl_ESpercent(int currcons, struct tty_struct *tty, unsigned int c) -+{ -+ vc_state = con_write_ctrl_ESnormal; -+ switch (c) { -+ case '@': /* defined in ISO 2022 */ -+ utf = 0; -+ break; -+ case 'G': /* prelim official escape code */ -+ case '8': /* retained for compatibility */ -+ utf = 1; -+ break; -+ } -+ return 0; -+} -+ -+static int con_write_ctrl_ESfunckey(int currcons, struct tty_struct *tty, unsigned int c) -+{ -+ vc_state = con_write_ctrl_ESnormal; -+ return 0; -+} -+ -+static int con_write_ctrl_EShash(int currcons, struct tty_struct *tty, unsigned int c) -+{ -+ vc_state = con_write_ctrl_ESnormal; -+ if (c == '8') { -+ /* DEC screen alignment test. kludge :-) */ -+ video_erase_char = -+ (video_erase_char & 0xff00) | 'E'; -+ csi_J(currcons, 2); -+ video_erase_char = -+ (video_erase_char & 0xff00) | ' '; -+ do_update_region(currcons, origin, screenbuf_size/2); -+ } -+ return 0; -+} -+ -+static int con_write_ctrl_ESsetG0(int currcons, struct tty_struct *tty, unsigned int c) -+{ -+ switch (c) { -+ case '0': -+ G0_charset = GRAF_MAP; -+ break; -+ case 'B': -+ G0_charset = LAT1_MAP; -+ break; -+ case 'U': -+ G0_charset = IBMPC_MAP; -+ break; -+ case 'K': -+ G0_charset = USER_MAP; -+ break; -+ } -+ if (charset == 0) { -+ translate = set_translate(G0_charset,currcons); -+ return 1; -+ } -+ vc_state = con_write_ctrl_ESnormal; -+ return 0; -+} -+ -+static int con_write_ctrl_ESsetG1(int currcons, struct tty_struct *tty, unsigned int c) -+{ -+ switch (c) { -+ case '0': -+ G1_charset = GRAF_MAP; -+ break; -+ case 'B': -+ G1_charset = LAT1_MAP; -+ break; -+ case 'U': -+ G1_charset = IBMPC_MAP; -+ break; -+ case 'K': -+ G1_charset = USER_MAP; -+ break; -+ } -+ if (charset == 1) { -+ translate = set_translate(G1_charset,currcons); -+ return 1; - } -+ vc_state = con_write_ctrl_ESnormal; -+ return 0; - } - - /* This is a temporary buffer used to prepare a tty console write -@@ -1855,7 +1972,7 @@ - unsigned long draw_from = 0, draw_to = 0; - struct vt_struct *vt = (struct vt_struct *)tty->driver_data; - u16 himask, charmask; -- const unsigned char *orig_buf = NULL; -+ const unsigned char *orig_buf; - int orig_count; - - if (in_interrupt()) -@@ -1913,42 +2030,12 @@ - count--; - - if (utf) { -- /* Combine UTF-8 into Unicode */ -- /* Incomplete characters silently ignored */ -- if(c > 0x7f) { -- if (utf_count > 0 && (c & 0xc0) == 0x80) { -- utf_char = (utf_char << 6) | (c & 0x3f); -- utf_count--; -- if (utf_count == 0) -- tc = c = utf_char; -- else continue; -- } else { -- if ((c & 0xe0) == 0xc0) { -- utf_count = 1; -- utf_char = (c & 0x1f); -- } else if ((c & 0xf0) == 0xe0) { -- utf_count = 2; -- utf_char = (c & 0x0f); -- } else if ((c & 0xf8) == 0xf0) { -- utf_count = 3; -- utf_char = (c & 0x07); -- } else if ((c & 0xfc) == 0xf8) { -- utf_count = 4; -- utf_char = (c & 0x03); -- } else if ((c & 0xfe) == 0xfc) { -- utf_count = 5; -- utf_char = (c & 0x01); -- } else -- utf_count = 0; -+ tc = con_write_utf(currcons, c); -+ if (tc < 0) - continue; -- } -- } else { -- tc = c; -- utf_count = 0; -- } -- } else { /* no utf */ -- tc = translate[toggle_meta ? (c|0x80) : c]; -- } -+ c = tc; -+ } else /* no utf */ -+ tc = translate[toggle_meta ? (c|0x80) : c]; - - /* If the original code was a control character we - * only allow a glyph to be displayed if the code is -@@ -1966,7 +2053,7 @@ - && (c != 127 || disp_ctrl) - && (c != 128+27); - -- if (vc_state == ESnormal && ok) { -+ if (vc_state == con_write_ctrl_ESnormal && ok) { - /* Now try to find out how to display it */ - tc = conv_uni_to_pc(vc_cons[currcons].d, tc); - if ( tc == -4 ) { -@@ -2112,7 +2199,7 @@ - if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1)) - currcons = kmsg_redirect - 1; - -- /* read `x' only after setting currecons properly (otherwise -+ /* read `x' only after setting currcons properly (otherwise - the `x' macro will read the x of the foreground console). */ - myx = x; - -@@ -2475,8 +2562,8 @@ - console_driver.init_termios = tty_std_termios; - console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; - /* Tell tty_register_driver() to skip consoles because they are -- * registered before kmalloc() is ready. We'll patch them in later. -- * See comments at console_init(); see also con_init_devfs(). -+ * registered before kmalloc() is ready. We'll patch them in later. -+ * See comments at console_init(); see also con_init_devfs(). - */ - console_driver.flags |= TTY_DRIVER_NO_DEVFS; - console_driver.refcount = &console_refcount; -@@ -2719,7 +2806,7 @@ - - if (console_blank_hook && console_blank_hook(1)) - return; -- if (vesa_blank_mode) -+ if (vesa_blank_mode) - sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1); - } - -@@ -2893,7 +2980,7 @@ - if (!op->height) { /* Need to guess font height [compat] */ - int h, i; - u8 *charmap = op->data, tmp; -- -+ - /* If from KDFONTOP ioctl, don't allow things which can be done in userland, - so that we can get rid of this soon */ - if (!(op->flags & KD_FONT_FLAG_OLD)) -@@ -2940,18 +3027,18 @@ - op->data = old_op.data; - if (!rc && !set) { - int c = (op->width+7)/8 * 32 * op->charcount; -- -+ - if (op->data && op->charcount > old_op.charcount) - rc = -ENOSPC; - if (!(op->flags & KD_FONT_FLAG_OLD)) { -- if (op->width > old_op.width || -+ if (op->width > old_op.width || - op->height > old_op.height) - rc = -ENOSPC; - } else { - if (op->width != 8) - rc = -EIO; - else if ((old_op.height && op->height > old_op.height) || -- op->height > 32) -+ op->height > 32) - rc = -ENOSPC; - } - if (!rc && op->data && copy_to_user(op->data, temp, c)) -diff -urN linux-2.4.26/drivers/char/ds1307.c linux-2.4.26-vrs1/drivers/char/ds1307.c ---- linux-2.4.26/drivers/char/ds1307.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/ds1307.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,604 @@ -+/* -+ * ds1307.c -+ * -+ * Device driver for Dallas Semiconductor's Real Time Controller DS1307. -+ * -+ * Copyright (C) 2002 Intrinsyc Software Inc. -+ * -+ * 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 -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "ds1307.h" -+ -+#define DEBUG 0 -+ -+#if DEBUG -+static unsigned int rtc_debug = DEBUG; -+#else -+#define rtc_debug 0 /* gcc will remove all the debug code for us */ -+#endif -+ -+static unsigned short slave_address = DS1307_I2C_SLAVE_ADDR; -+ -+struct i2c_driver ds1307_driver; -+struct i2c_client *ds1307_i2c_client = 0; -+ -+static unsigned short ignore[] = { I2C_CLIENT_END }; -+static unsigned short normal_addr[] = { DS1307_I2C_SLAVE_ADDR, I2C_CLIENT_END }; -+ -+static struct i2c_client_address_data addr_data = { -+ normal_i2c: normal_addr, -+ normal_i2c_range: ignore, -+ probe: ignore, -+ probe_range: ignore, -+ ignore: ignore, -+ ignore_range: ignore, -+ force: ignore, -+}; -+ -+static int ds1307_rtc_ioctl( struct inode *, struct file *, unsigned int, unsigned long); -+static int ds1307_rtc_open(struct inode *inode, struct file *file); -+static int ds1307_rtc_release(struct inode *inode, struct file *file); -+ -+static struct file_operations rtc_fops = { -+ owner: THIS_MODULE, -+ ioctl: ds1307_rtc_ioctl, -+ open: ds1307_rtc_open, -+ release: ds1307_rtc_release, -+}; -+ -+static struct miscdevice ds1307_rtc_miscdev = { -+ RTC_MINOR, -+ "rtc", -+ &rtc_fops -+}; -+ -+static int ds1307_probe(struct i2c_adapter *adap); -+static int ds1307_detach(struct i2c_client *client); -+static int ds1307_command(struct i2c_client *client, unsigned int cmd, void *arg); -+ -+struct i2c_driver ds1307_driver = { -+ name: "DS1307", -+ id: I2C_DRIVERID_DS1307, -+ flags: I2C_DF_NOTIFY, -+ attach_adapter: ds1307_probe, -+ detach_client: ds1307_detach, -+ command: ds1307_command -+}; -+ -+static spinlock_t ds1307_rtc_lock = SPIN_LOCK_UNLOCKED; -+ -+#define DAT(x) ((unsigned int)((x)->data)) /* keep the control register info */ -+ -+static int -+ds1307_readram( char *buf, int len) -+{ -+ unsigned long flags; -+ unsigned char ad[1] = { 0 }; -+ int ret; -+ struct i2c_msg msgs[2] = { -+ { ds1307_i2c_client->addr , 0, 1, ad }, -+ { ds1307_i2c_client->addr , I2C_M_RD, len, buf } }; -+ -+ spin_lock_irqsave(&ds1307_rtc_lock, flags); -+ ret = i2c_transfer(ds1307_i2c_client->adapter, msgs, 2); -+ spin_unlock_irqrestore(&ds1307_rtc_lock,flags); -+ -+ return ret; -+} -+ -+static void -+ds1307_dumpram( void) -+{ -+ unsigned char buf[DS1307_RAM_SIZE]; -+ int ret; -+ -+ ret = ds1307_readram( buf, DS1307_RAM_SIZE); -+ -+ if( ret > 0) -+ { -+ int i; -+ for( i=0; iaddr , 0, 1, ad }, -+ { ds1307_i2c_client->addr , I2C_M_RD, 1, buf } -+ }; -+ unsigned char ctrl_info; -+ int ret; -+ -+ if( enable) -+ ctrl_info = SQW_ENABLE | RATE_32768HZ; -+ else -+ ctrl_info = SQW_DISABLE; -+ ds1307_command(ds1307_i2c_client, DS1307_SETCTRL, &ctrl_info); -+ -+ /* read addr 0 (Clock-Halt bit and second counter */ -+ ret = i2c_transfer(ds1307_i2c_client->adapter, msgs, 2); -+ -+ if( enable) -+ buf[1] = buf[0] & ~CLOCK_HALT; /* clear Clock-Halt bit */ -+ else -+ buf[1] = buf[0] | CLOCK_HALT; /* set Clock-Halt bit */ -+ buf[0] = 0; /* control register address on DS1307 */ -+ -+ ret = i2c_master_send(ds1307_i2c_client, (char *)buf, 2); -+} -+ -+static int -+ds1307_attach(struct i2c_adapter *adap, int addr, unsigned short flags,int kind) -+{ -+ struct i2c_client *c; -+ unsigned char buf[1], ad[1] = { 7 }; -+ struct i2c_msg msgs[2] = { -+ { addr , 0, 1, ad }, -+ { addr , I2C_M_RD, 1, buf } -+ }; -+ int ret; -+ -+ c = (struct i2c_client *)kmalloc(sizeof(*c), GFP_KERNEL); -+ if (!c) -+ return -ENOMEM; -+ -+ strcpy(c->name, "DS1307"); -+ c->id = ds1307_driver.id; -+ c->flags = 0; -+ c->addr = addr; -+ c->adapter = adap; -+ c->driver = &ds1307_driver; -+ c->data = NULL; -+ -+ ret = i2c_transfer(c->adapter, msgs, 2); -+ -+ if ( ret == 2 ) -+ { -+ DAT(c) = buf[0]; -+ } -+ else -+ printk ("ds1307_attach(): i2c_transfer() returned %d.\n",ret); -+ -+ ds1307_i2c_client = c; -+ ds1307_enable_clock( 1); -+ -+ return i2c_attach_client(c); -+} -+ -+static int -+ds1307_probe(struct i2c_adapter *adap) -+{ -+ return i2c_probe(adap, &addr_data, ds1307_attach); -+} -+ -+static int -+ds1307_detach(struct i2c_client *client) -+{ -+ i2c_detach_client(client); -+ ds1307_enable_clock( 0); -+ -+ return 0; -+} -+ -+static void -+ds1307_convert_to_time( struct rtc_time *dt, char *buf) -+{ -+ dt->tm_sec = BCD_TO_BIN(buf[0]); -+ dt->tm_min = BCD_TO_BIN(buf[1]); -+ -+ if ( TWELVE_HOUR_MODE(buf[2]) ) -+ { -+ dt->tm_hour = HOURS_12(buf[2]); -+ if (HOURS_AP(buf[2])) /* PM */ -+ { -+ dt->tm_hour += 12; -+ } -+ } -+ else /* 24-hour-mode */ -+ { -+ dt->tm_hour = HOURS_24(buf[2]); -+ } -+ -+ dt->tm_mday = BCD_TO_BIN(buf[4]); -+ /* dt->tm_mon is zero-based */ -+ dt->tm_mon = BCD_TO_BIN(buf[5]) - 1; -+ /* year is 1900 + dt->tm_year */ -+ dt->tm_year = BCD_TO_BIN(buf[6]) + 100; -+ -+ if( rtc_debug > 2) -+ { -+ printk("ds1307_get_datetime: year = %d\n", dt->tm_year); -+ printk("ds1307_get_datetime: mon = %d\n", dt->tm_mon); -+ printk("ds1307_get_datetime: mday = %d\n", dt->tm_mday); -+ printk("ds1307_get_datetime: hour = %d\n", dt->tm_hour); -+ printk("ds1307_get_datetime: min = %d\n", dt->tm_min); -+ printk("ds1307_get_datetime: sec = %d\n", dt->tm_sec); -+ } -+} -+ -+static int -+ds1307_get_datetime(struct i2c_client *client, struct rtc_time *dt) -+{ -+ unsigned char buf[7], addr[1] = { 0 }; -+ struct i2c_msg msgs[2] = { -+ { client->addr, 0, 1, addr }, -+ { client->addr, I2C_M_RD, 7, buf } -+ }; -+ int ret = -EIO; -+ -+ memset(buf, 0, sizeof(buf)); -+ -+ ret = i2c_transfer(client->adapter, msgs, 2); -+ -+ if (ret == 2) { -+ ds1307_convert_to_time( dt, buf); -+ ret = 0; -+ } -+ else -+ printk("ds1307_get_datetime(), i2c_transfer() returned %d\n",ret); -+ -+ return ret; -+} -+ -+static int -+ds1307_set_datetime(struct i2c_client *client, struct rtc_time *dt, int datetoo) -+{ -+ unsigned char buf[8]; -+ int ret, len = 4; -+ -+ if( rtc_debug > 2) -+ { -+ printk("ds1307_set_datetime: tm_year = %d\n", dt->tm_year); -+ printk("ds1307_set_datetime: tm_mon = %d\n", dt->tm_mon); -+ printk("ds1307_set_datetime: tm_mday = %d\n", dt->tm_mday); -+ printk("ds1307_set_datetime: tm_hour = %d\n", dt->tm_hour); -+ printk("ds1307_set_datetime: tm_min = %d\n", dt->tm_min); -+ printk("ds1307_set_datetime: tm_sec = %d\n", dt->tm_sec); -+ } -+ -+ buf[0] = 0; /* register address on DS1307 */ -+ buf[1] = (BIN_TO_BCD(dt->tm_sec)); -+ buf[2] = (BIN_TO_BCD(dt->tm_min)); -+ buf[3] = (BIN_TO_BCD(dt->tm_hour)); -+ -+ if (datetoo) { -+ len = 8; -+ /* we skip buf[4] as we don't use day-of-week. */ -+ buf[5] = (BIN_TO_BCD(dt->tm_mday)); -+ buf[6] = (BIN_TO_BCD(dt->tm_mon + 1)); -+ /* The year only ranges from 0-99, we are being passed an offset from 1900, -+ * and the chip calulates leap years based on 2000, thus we adjust by 100. -+ */ -+ buf[7] = (BIN_TO_BCD(dt->tm_year - 100)); -+ } -+ ret = i2c_master_send(client, (char *)buf, len); -+ if (ret == len) -+ ret = 0; -+ else -+ printk("ds1307_set_datetime(), i2c_master_send() returned %d\n",ret); -+ -+ -+ return ret; -+} -+ -+static int -+ds1307_get_ctrl(struct i2c_client *client, unsigned char *ctrl) -+{ -+ *ctrl = DAT(client); -+ -+ return 0; -+} -+ -+static int -+ds1307_set_ctrl(struct i2c_client *client, unsigned char *cinfo) -+{ -+ unsigned char buf[2]; -+ int ret; -+ -+ -+ buf[0] = 7; /* control register address on DS1307 */ -+ buf[1] = *cinfo; -+ /* save the control reg info in the client data field so that get_ctrl -+ * function doesn't have to do an I2C transfer to get it. -+ */ -+ DAT(client) = buf[1]; -+ -+ ret = i2c_master_send(client, (char *)buf, 2); -+ -+ return ret; -+} -+ -+static int -+ds1307_read_mem(struct i2c_client *client, struct rtc_mem *mem) -+{ -+ unsigned char addr[1]; -+ struct i2c_msg msgs[2] = { -+ { client->addr, 0, 1, addr }, -+ { client->addr, I2C_M_RD, mem->nr, mem->data } -+ }; -+ -+ if ( (mem->loc < DS1307_RAM_ADDR_START) || -+ ((mem->loc + mem->nr -1) > DS1307_RAM_ADDR_END) ) -+ return -EINVAL; -+ -+ addr[0] = mem->loc; -+ -+ return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO; -+} -+ -+static int -+ds1307_write_mem(struct i2c_client *client, struct rtc_mem *mem) -+{ -+ unsigned char addr[1]; -+ struct i2c_msg msgs[2] = { -+ { client->addr, 0, 1, addr }, -+ { client->addr, 0, mem->nr, mem->data } -+ }; -+ -+ if ( (mem->loc < DS1307_RAM_ADDR_START) || -+ ((mem->loc + mem->nr -1) > DS1307_RAM_ADDR_END) ) -+ return -EINVAL; -+ -+ addr[0] = mem->loc; -+ -+ return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO; -+} -+ -+static int -+ds1307_command(struct i2c_client *client, unsigned int cmd, void *arg) -+{ -+ switch (cmd) { -+ case DS1307_GETDATETIME: -+ return ds1307_get_datetime(client, arg); -+ -+ case DS1307_SETTIME: -+ return ds1307_set_datetime(client, arg, 0); -+ -+ case DS1307_SETDATETIME: -+ return ds1307_set_datetime(client, arg, 1); -+ -+ case DS1307_GETCTRL: -+ return ds1307_get_ctrl(client, arg); -+ -+ case DS1307_SETCTRL: -+ return ds1307_set_ctrl(client, arg); -+ -+ case DS1307_MEM_READ: -+ return ds1307_read_mem(client, arg); -+ -+ case DS1307_MEM_WRITE: -+ return ds1307_write_mem(client, arg); -+ -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int -+ds1307_rtc_open(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static int -+ds1307_rtc_release(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static int -+ds1307_rtc_ioctl( struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ unsigned long flags; -+ struct rtc_time wtime; -+ int status = 0; -+ -+ switch (cmd) { -+ default: -+ case RTC_UIE_ON: -+ case RTC_UIE_OFF: -+ case RTC_PIE_ON: -+ case RTC_PIE_OFF: -+ case RTC_AIE_ON: -+ case RTC_AIE_OFF: -+ case RTC_ALM_SET: -+ case RTC_ALM_READ: -+ case RTC_IRQP_READ: -+ case RTC_IRQP_SET: -+ case RTC_EPOCH_READ: -+ case RTC_EPOCH_SET: -+ case RTC_WKALM_SET: -+ case RTC_WKALM_RD: -+ status = -EINVAL; -+ break; -+ -+ case RTC_RD_TIME: -+ spin_lock_irqsave(&ds1307_rtc_lock, flags); -+ ds1307_command( ds1307_i2c_client, DS1307_GETDATETIME, &wtime); -+ spin_unlock_irqrestore(&ds1307_rtc_lock,flags); -+ -+ if( copy_to_user((void *)arg, &wtime, sizeof (struct rtc_time))) -+ status = -EFAULT; -+ break; -+ -+ case RTC_SET_TIME: -+ if (!capable(CAP_SYS_TIME)) -+ { -+ status = -EACCES; -+ break; -+ } -+ -+ if (copy_from_user(&wtime, (struct rtc_time *)arg, sizeof(struct rtc_time)) ) -+ { -+ status = -EFAULT; -+ break; -+ } -+ -+ spin_lock_irqsave(&ds1307_rtc_lock, flags); -+ ds1307_command( ds1307_i2c_client, DS1307_SETDATETIME, &wtime); -+ spin_unlock_irqrestore(&ds1307_rtc_lock,flags); -+ break; -+ } -+ -+ return status; -+} -+ -+static char * -+ds1307_mon2str( unsigned int mon) -+{ -+ char *mon2str[12] = { -+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", -+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" -+ }; -+ if( mon > 11) return "error"; -+ else return mon2str[ mon]; -+} -+ -+static int ds1307_rtc_proc_output( char *buf) -+{ -+#define CHECK(ctrl,bit) ((ctrl & bit) ? "yes" : "no") -+ unsigned char ram[DS1307_RAM_SIZE]; -+ int ret; -+ -+ char *p = buf; -+ -+ ret = ds1307_readram( ram, DS1307_RAM_SIZE); -+ if( ret > 0) -+ { -+ int i; -+ struct rtc_time dt; -+ char text[9]; -+ -+ p += sprintf(p, "DS1307 (64x8 Serial Real Time Clock)\n"); -+ -+ ds1307_convert_to_time( &dt, ram); -+ p += sprintf(p, "Date/Time : %02d-%s-%04d %02d:%02d:%02d\n", -+ dt.tm_mday, ds1307_mon2str(dt.tm_mon), dt.tm_year + 1900, -+ dt.tm_hour, dt.tm_min, dt.tm_sec); -+ -+ p += sprintf(p, "Clock halted : %s\n", CHECK(ram[0],0x80)); -+ p += sprintf(p, "24h mode : %s\n", CHECK(ram[2],0x40)); -+ p += sprintf(p, "Square wave enabled : %s\n", CHECK(ram[7],0x10)); -+ p += sprintf(p, "Freq : "); -+ -+ switch( ram[7] & 0x03) -+ { -+ case RATE_1HZ: -+ p += sprintf(p, "1Hz\n"); -+ break; -+ case RATE_4096HZ: -+ p += sprintf(p, "4.096kHz\n"); -+ break; -+ case RATE_8192HZ: -+ p += sprintf(p, "8.192kHz\n"); -+ break; -+ case RATE_32768HZ: -+ default: -+ p += sprintf(p, "32.768kHz\n"); -+ break; -+ -+ } -+ -+ p += sprintf(p, "RAM dump:\n"); -+ text[8]='\0'; -+ for( i=0; i126)) ram[i]='.'; -+ text[i%8] = ram[i]; -+ if( (i%8) == 7) p += sprintf(p, "%s\n",text); -+ } -+ p += sprintf(p, "\n"); -+ } -+ else -+ { -+ p += sprintf(p, "Failed to read RTC memory!\n"); -+ } -+ -+ return p - buf; -+} -+ -+static int ds1307_rtc_read_proc(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = ds1307_rtc_proc_output (page); -+ if (len <= off+count) *eof = 1; -+ *start = page + off; -+ len -= off; -+ if (len>count) len = count; -+ if (len<0) len = 0; -+ return len; -+} -+ -+static __init int ds1307_init(void) -+{ -+ int retval=0; -+ -+ if( slave_address != 0xffff) -+ { -+ normal_addr[0] = slave_address; -+ } -+ -+ if( normal_addr[0] == 0xffff) -+ { -+ printk(KERN_ERR"I2C: Invalid slave address for DS1307 RTC (%#x)\n", -+ normal_addr[0]); -+ return -EINVAL; -+ } -+ -+ retval = i2c_add_driver(&ds1307_driver); -+ -+ if (retval==0) -+ { -+ misc_register (&ds1307_rtc_miscdev); -+ create_proc_read_entry (PROC_DS1307_NAME, 0, 0, ds1307_rtc_read_proc, NULL); -+ printk("I2C: DS1307 RTC driver successfully loaded\n"); -+ -+ if( rtc_debug) ds1307_dumpram(); -+ } -+ return retval; -+} -+ -+static __exit void ds1307_exit(void) -+{ -+ remove_proc_entry (PROC_DS1307_NAME, NULL); -+ misc_deregister(&ds1307_rtc_miscdev); -+ i2c_del_driver(&ds1307_driver); -+} -+ -+module_init(ds1307_init); -+module_exit(ds1307_exit); -+ -+MODULE_PARM (slave_address, "i"); -+MODULE_PARM_DESC (slave_address, "I2C slave address for DS1307 RTC."); -+ -+MODULE_AUTHOR ("Intrinsyc Software Inc."); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.4.26/drivers/char/ds1307.h linux-2.4.26-vrs1/drivers/char/ds1307.h ---- linux-2.4.26/drivers/char/ds1307.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/ds1307.h 2004-03-04 22:44:33.000000000 +0000 -@@ -0,0 +1,58 @@ -+/* -+ * ds1307.h -+ * -+ * Copyright (C) 2002 Intrinsyc Software Inc. -+ * -+ * 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 DS1307_H -+#define DS1307_H -+ -+#if defined(CONFIG_PXA_EMERSON_SBC) || defined(CONFIG_PXA_CERF_BOARD) || defined(CONFIG_MACH_CSB337) -+ #define DS1307_I2C_SLAVE_ADDR 0x68 -+#else -+ #define DS1307_I2C_SLAVE_ADDR 0xffff -+#endif -+ -+#define DS1307_RAM_ADDR_START 0x08 -+#define DS1307_RAM_ADDR_END 0x3F -+#define DS1307_RAM_SIZE 0x40 -+ -+#define PROC_DS1307_NAME "driver/ds1307" -+ -+struct rtc_mem { -+ unsigned int loc; -+ unsigned int nr; -+ unsigned char *data; -+}; -+ -+#define DS1307_GETDATETIME 0 -+#define DS1307_SETTIME 1 -+#define DS1307_SETDATETIME 2 -+#define DS1307_GETCTRL 3 -+#define DS1307_SETCTRL 4 -+#define DS1307_MEM_READ 5 -+#define DS1307_MEM_WRITE 6 -+ -+#define SQW_ENABLE 0x10 /* Square Wave Enable */ -+#define SQW_DISABLE 0x00 /* Square Wave disable */ -+ -+#define RATE_32768HZ 0x03 /* Rate Select 32.768KHz */ -+#define RATE_8192HZ 0x02 /* Rate Select 8.192KHz */ -+#define RATE_4096HZ 0x01 /* Rate Select 4.096KHz */ -+#define RATE_1HZ 0x00 /* Rate Select 1Hz */ -+ -+#define CLOCK_HALT 0x80 /* Clock Halt */ -+ -+#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10) -+#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10) -+ -+#define TWELVE_HOUR_MODE(n) (((n)>>6)&1) -+#define HOURS_AP(n) (((n)>>5)&1) -+#define HOURS_12(n) BCD_TO_BIN((n)&0x1F) -+#define HOURS_24(n) BCD_TO_BIN((n)&0x3F) -+ -+#endif -diff -urN linux-2.4.26/drivers/char/edb7211_keyb.c linux-2.4.26-vrs1/drivers/char/edb7211_keyb.c ---- linux-2.4.26/drivers/char/edb7211_keyb.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/edb7211_keyb.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,335 @@ -+/* -+ * drivers/char/edb7211_keyb.c -+ * -+ * Copyright (C) 2000 Blue Mug, Inc. All Rights Reserved. -+ * -+ * EDB7211 Keyboard driver for ARM Linux. -+ * -+ * The EP7211 keyboard hardware only supports generating interrupts for 64 keys. -+ * The EBD7211's keyboard has 84 keys. Therefore we need to poll for keys, -+ * instead of waiting for interrupts. -+ * -+ * In a real-world hardware situation, this would be a bad thing. It would -+ * kill power management. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+ -+/* -+ * The number of jiffies between keyboard scans. -+ */ -+#define KEYBOARD_SCAN_INTERVAL 5 -+ -+/* -+ * Values for the keyboard column scan control register. -+ */ -+#define KBSC_HI 0x0 /* All driven high */ -+#define KBSC_LO 0x1 /* All driven low */ -+#define KBSC_X 0x2 /* All high impedance */ -+#define KBSC_COL0 0x8 /* Column 0 high, others high impedance */ -+#define KBSC_COL1 0x9 /* Column 1 high, others high impedance */ -+#define KBSC_COL2 0xa /* Column 2 high, others high impedance */ -+#define KBSC_COL3 0xb /* Column 3 high, others high impedance */ -+#define KBSC_COL4 0xc /* Column 4 high, others high impedance */ -+#define KBSC_COL5 0xd /* Column 5 high, others high impedance */ -+#define KBSC_COL6 0xe /* Column 6 high, others high impedance */ -+#define KBSC_COL7 0xf /* Column 7 high, others high impedance */ -+ -+ -+/* XXX: Figure out what these values should be... */ -+/* Simple translation table for the SysRq keys */ -+#ifdef CONFIG_MAGIC_SYSRQ -+unsigned char edb7211_kbd_sysrq_xlate[128] = -+ "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ -+ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ -+ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ -+ "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ -+ "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ -+ "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ -+ "\r\000/"; /* 0x60 - 0x6f */ -+#endif -+ -+/* -+ * Row/column to scancode mappings. -+ * -+ * This table maps row/column keyboard matrix positions to XT scancodes. -+ * -+ * The port A rows come first, followed by the extended rows. -+ */ -+static unsigned char colrow_2_scancode[128] = -+{ -+/* Column: -+ Row 0 1 2 3 4 5 6 7 */ -+/* A0 */ 0x01, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x40, 0x41, -+/* A1 */ 0x02, 0x07, 0x06, 0x05, 0x04, 0x03, 0x08, 0x09, -+/* A2 */ 0x0f, 0x14, 0x13, 0x12, 0x11, 0x10, 0x15, 0x16, -+/* A3 */ 0x3a, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x23, 0x24, -+/* A4 */ 0x29, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x31, 0x32, -+/* A5 */ 0x39, 0x35, 0x6F, 0x52, 0x00, 0x6B, 0x34, 0x33, -+/* A6 */ 0x6A, 0x27, 0x28, 0x00, 0x1c, 0x6D, 0x26, 0x25, -+/* A7 */ 0x67, 0x19, 0x1a, 0x1b, 0x2b, 0x68, 0x18, 0x17, -+/* E0 */ 0x6C, 0x0c, 0x0d, 0x0e, 0x00, 0x66, 0x0b, 0x0a, -+/* E1 */ 0x69, 0x44, 0x45, 0x37, 0x46, 0x77, 0x43, 0x42, -+/* E2 */ 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+/* E3 */ 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+/* E4 */ 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+/* E5 */ 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+/* E6 */ 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -+/* E7 */ 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -+}; -+ -+/* -+ * A bitfield array which contains the state of the keyboard after the last -+ * scan. A bit set in this array corresponds to a key down. Only the lower -+ * 16 bits of each array element are used. -+ */ -+static unsigned long previous_keys[8]; -+static unsigned long keys[8]; -+ -+ -+/* This will be set to a non-zero value if a key was found to be pressed -+ * in the last scan. */ -+static int key_is_pressed; -+ -+static struct tq_struct kbd_process_task; -+static struct timer_list edb7211_kbd_timer; -+ -+/* -+ * External methods. -+ */ -+void edb7211_kbd_init_hw(void); -+ -+/* -+ * Internal methods. -+ */ -+static int edb7211_kbd_scan_matrix(u_long* keys); -+static void edb7211_kbd_timeout(unsigned long data); -+static void edb7211_kbd_process(void* data); -+ -+/* -+ * Translate a raw keycode to an XT keyboard scancode. -+ */ -+static int -+edb7211_translate(unsigned char scancode, unsigned char *keycode, -+ char raw_mode) -+{ -+ *keycode = colrow_2_scancode[scancode & 0x7f]; -+ return 1; -+} -+ -+/* -+ * Scan the keyboard matrix; for each key that is pressed, set the -+ * corresponding bit in the bitfield array. -+ * -+ * The parameter is expected to be an array of 8 32-bit values. Only the lower -+ * 16 bits of each value is used. Each value contains the row bits for the -+ * corresponding column. -+ */ -+static int -+edb7211_kbd_scan_matrix(u_long* keys) -+{ -+ int column, row, key_pressed; -+ unsigned char port_a_data, ext_port_data; -+ -+ key_pressed = 0; -+ -+ /* Drive all the columns low. */ -+ clps_writel((clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK) | KBSC_LO, -+ SYSCON1); -+ -+ for (column = 0; column < 8; column++) { -+ -+ /* Drive the column high. */ -+ clps_writel((clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK) | -+ (KBSC_COL0 + column), SYSCON1); -+ -+ /* Read port A and the extended port. */ -+ port_a_data = clps_readb(PADR) & 0xff; -+ ext_port_data = __raw_readb(EP7211_VIRT_EXTKBD) & 0xff; -+ -+ /* Drive all columns tri-state. */ -+ clps_writel((clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK) | KBSC_X, -+ SYSCON1); -+ -+ /* Look at each column in port A. */ -+ for (row=0; row < 8; row++) { -+ /* If the row's bit is set, set the bit in the bitfield. -+ * Otherwise, clear it. -+ */ -+ if (port_a_data & (1 << row)) { -+ keys[column] |= (1 << row); -+ key_pressed = 1; -+ } else { -+ keys[column] &= ~(1 << row); -+ } -+ } -+ -+ /* Look at each column in the extended port. */ -+ for (row=0; row < 8; row++) { -+ /* If the row's bit is set, set the bit in the bitfield. -+ * Otherwise, clear it. -+ */ -+ if (ext_port_data & (1 << row)) { -+ keys[column] |= (1 << (row + 8)); -+ key_pressed = 1; -+ } else { -+ keys[column] &= ~(1 << (row + 8)); -+ } -+ } -+ -+ /* -+ * Short delay: The example code for the EDB7211 runs an empty -+ * loop 256 times. At this rate, there were some spurious keys -+ * generated. I doubled the delay to let the column drives -+ * settle some. -+ */ -+ for (row=0; row < 512; row++) { } -+ } -+ -+ /* If we could use interrupts, we would drive all columns high so -+ * that interrupts will be generated on key presses. But we can't, -+ * so we leave all columns floating. -+ */ -+ clps_writel((clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK) | KBSC_X, -+ SYSCON1); -+ -+ return key_pressed; -+} -+ -+/* -+ * XXX: This is really ugly; this needs to be reworked to have less levels of -+ * indentation. -+ */ -+static void -+edb7211_kbd_timeout(unsigned long data) -+{ -+ /* Schedule the next timer event. */ -+ edb7211_kbd_timer.expires = jiffies + KEYBOARD_SCAN_INTERVAL; -+ add_timer(&edb7211_kbd_timer); -+ -+ if (edb7211_kbd_scan_matrix(keys) || key_is_pressed) { -+ queue_task(&kbd_process_task, &tq_timer); -+ } else { -+ key_is_pressed = 0; -+ } -+} -+ -+/* -+ * Process the keys that have been pressed. -+ */ -+static void -+edb7211_kbd_process(void* data) -+{ -+ int i; -+ -+ /* First check if any keys have been released. */ -+ if (key_is_pressed) { -+ for (i=0; i < 8; i++) { -+ if (previous_keys[i]) { -+ int row; -+ -+ for (row=0; row < 16; row++) { -+ if ((previous_keys[i] & (1 << row)) && -+ !(keys[i] & (1 << row))) { -+ /* Generate the up event. */ -+ handle_scancode( -+ (row<<3)+i, 0); -+ } -+ } -+ } -+ } -+ } -+ -+ key_is_pressed = 0; -+ -+ /* Now scan the keys and send press events. */ -+ for (i=0; i < 8; i++) { -+ if (keys[i]) { -+ int row; -+ -+ for (row=0; row < 16; row++) { -+ if (keys[i] & (1 << row)) { -+ if (previous_keys[i] & (1 << row)) { -+ /* Generate the hold event. */ -+ handle_scancode((row<<3)+i, 1); -+ } else { -+ /* Generate the down event. */ -+ handle_scancode((row<<3)+i, 1); -+ } -+ -+ key_is_pressed = 1; -+ } -+ } -+ } -+ } -+ -+ /* Update the state variables. */ -+ memcpy(previous_keys, keys, 8 * sizeof(unsigned long)); -+} -+ -+static char edb7211_unexpected_up(unsigned char scancode) -+{ -+ return 0200; -+} -+ -+static void edb7211_leds(unsigned char leds) -+{ -+} -+ -+/* -+ * Initialize the keyboard hardware. Set the column drives low and -+ * start the timer. -+ */ -+void __init -+edb7211_kbd_init_hw(void) -+{ -+ k_translate = edb7211_translate; -+ k_unexpected_up = edb7211_unexpected_up; -+ k_leds = edb7211_leds; -+ -+ /* -+ * If we had the ability to use interrupts, we would want to drive all -+ * columns high. But we have more keys than can generate interrupts, so -+ * we leave them floating. -+ */ -+ clps_writel((clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK) | KBSC_X, -+ SYSCON1); -+ -+ /* Initialize the matrix processing task. */ -+ kbd_process_task.routine = edb7211_kbd_process; -+ kbd_process_task.data = NULL; -+ -+ /* Setup the timer to poll the keyboard. */ -+ init_timer(&edb7211_kbd_timer); -+ edb7211_kbd_timer.function = edb7211_kbd_timeout; -+ edb7211_kbd_timer.data = (unsigned long)NULL; -+ edb7211_kbd_timer.expires = jiffies + KEYBOARD_SCAN_INTERVAL; -+ add_timer(&edb7211_kbd_timer); -+} -+ -+ -diff -urN linux-2.4.26/drivers/char/epxa_wdt.c linux-2.4.26-vrs1/drivers/char/epxa_wdt.c ---- linux-2.4.26/drivers/char/epxa_wdt.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/epxa_wdt.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,178 @@ -+/* -+ * Watchdog driver for the Altera Excalibur EPXA1DB -+ * -+ * (c) Copyright 2003 Krzysztof Marianski -+ * Based on SA11x0 Watchdog driver by Oleg Drokin -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ * -+ * This material is provided "AS-IS" and at no charge -+ * -+ * (c) Copyright 2003 Krzysztof Marianski -+ * -+ * 1/08/2003 Initial release -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define WATCHDOG00_TYPE (volatile unsigned int*) -+#include -+#include -+ -+#define TIMER_MARGIN 30 /* (secs) Default is 30 seconds */ -+ -+static int margin = TIMER_MARGIN; /* in seconds */ -+static int epxa1wdt_users; -+static unsigned char last_written_byte; -+ -+#ifdef CONFIG_WATCHDOG_NOWAYOUT -+static int nowayout=1; -+#else -+static int nowayout=0; -+#endif -+ -+#ifdef MODULE -+MODULE_PARM(margin,"i"); -+MODULE_PARM(nowayout, "i"); -+#endif -+ -+/* -+ * Allow only one person to hold it open -+ */ -+ -+static int epxa1dog_open(struct inode *inode, struct file *file) -+{ -+ if(test_and_set_bit(1,&epxa1wdt_users)) -+ return -EBUSY; -+ -+ /* Reset the Watchdog, just to be sure we don't set -+ a value close to actual value of WDOG_COUNT register */ -+ *WDOG_RELOAD(IO_ADDRESS(EXC_WATCHDOG00_BASE))=WDOG_RELOAD_MAGIC_1; -+ *WDOG_RELOAD(IO_ADDRESS(EXC_WATCHDOG00_BASE))=WDOG_RELOAD_MAGIC_2; -+ -+ /* Activate EPXA1DB Watchdog timer */ -+ *WDOG_CR(IO_ADDRESS(EXC_WATCHDOG00_BASE))= (EXC_INPUT_CLK_FREQUENCY * margin) & WDOG_CR_TRIGGER_MSK; -+ -+ last_written_byte = 'V'; //in case user opens it only to ioctl -+ return 0; -+} -+ -+static int epxa1dog_release(struct inode *inode, struct file *file) -+{ -+ /* -+ * Shut off the timer and set lock bit when no special -+ * character 'V' was last written -+ */ -+ -+ if ((last_written_byte != 'V') && (nowayout)) { -+ *WDOG_CR(IO_ADDRESS(EXC_WATCHDOG00_BASE)) |= WDOG_CR_LK_MSK; -+ printk("No special character 'V' was written to Watchdog just before closing it\n"); -+ printk("WATCHDOG LOCKED - Reboot expected!!!\n"); -+ } else -+ *WDOG_CR(IO_ADDRESS(EXC_WATCHDOG00_BASE))=0; -+ -+ epxa1wdt_users = 0; -+ -+ return 0; -+} -+ -+static ssize_t epxa1dog_write(struct file *file, const char *data, size_t len, loff_t *ppos) -+{ -+ /* Can't seek (pwrite) on this device */ -+ if (ppos != &file->f_pos) -+ return -ESPIPE; -+ -+ /* Reset Watchdog timer. */ -+ if(len) { -+ *WDOG_RELOAD(IO_ADDRESS(EXC_WATCHDOG00_BASE))=WDOG_RELOAD_MAGIC_1; -+ *WDOG_RELOAD(IO_ADDRESS(EXC_WATCHDOG00_BASE))=WDOG_RELOAD_MAGIC_2; -+ last_written_byte = *data; -+ return 1; -+ } -+ return 0; -+} -+ -+static int epxa1dog_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ static struct watchdog_info ident = { -+ identity: "EPXA Watchdog", -+ }; -+ -+ switch(cmd){ -+ default: -+ return -ENOIOCTLCMD; -+ case WDIOC_GETSUPPORT: -+ return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)); -+// case WDIOC_GETSTATUS: //TODO -+// return put_user(0,(int *)arg); -+// case WDIOC_GETBOOTSTATUS: //TODO -+// return 0; -+ case WDIOC_KEEPALIVE: -+ *WDOG_RELOAD(IO_ADDRESS(EXC_WATCHDOG00_BASE))=WDOG_RELOAD_MAGIC_1; -+ *WDOG_RELOAD(IO_ADDRESS(EXC_WATCHDOG00_BASE))=WDOG_RELOAD_MAGIC_2; -+ return 0; -+ case WDIOC_SETTIMEOUT: -+ *WDOG_CR(IO_ADDRESS(EXC_WATCHDOG00_BASE))= (EXC_INPUT_CLK_FREQUENCY * margin) & WDOG_CR_TRIGGER_MSK; -+ return 0; -+ case WDIOC_GETTIMEOUT: -+ return put_user( ((*WDOG_CR(IO_ADDRESS(EXC_WATCHDOG00_BASE)))/EXC_INPUT_CLK_FREQUENCY), (int*)arg); -+ } -+} -+ -+static struct file_operations epxa1dog_fops = { -+ .owner = THIS_MODULE, -+ .write = epxa1dog_write, -+ .ioctl = epxa1dog_ioctl, -+ .open = epxa1dog_open, -+ .release = epxa1dog_release, -+}; -+ -+static struct miscdevice epxa1dog_miscdev= -+{ -+ .minor = WATCHDOG_MINOR, -+ .name = "EPXA watchdog", -+ .fops = &epxa1dog_fops -+}; -+ -+static int __init epxa1dog_init(void) -+{ -+ int ret; -+ -+ ret = misc_register(&epxa1dog_miscdev); -+ -+ if (ret) -+ return ret; -+ -+ printk("EPXA Watchdog Timer: timer margin %d sec\n", margin); -+ printk("EPXA Watchdog Timer: no way out is %s\n", nowayout ? "enabled" : "disabled"); -+ -+ return 0; -+} -+ -+static void __exit epxa1dog_exit(void) -+{ -+ misc_deregister(&epxa1dog_miscdev); -+} -+ -+module_init(epxa1dog_init); -+module_exit(epxa1dog_exit); -+ -+MODULE_AUTHOR("Krzysztof Marianski "); -+MODULE_DESCRIPTION("EPXA Watchdog Timer"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.4.26/drivers/char/gc_kbmap.h linux-2.4.26-vrs1/drivers/char/gc_kbmap.h ---- linux-2.4.26/drivers/char/gc_kbmap.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/gc_kbmap.h 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,162 @@ -+ -+ -+#define KK_NONE 0x7f -+#define KK_ESC 0x00 -+#define KK_F1 0x01 -+#define KK_F2 0x02 -+#define KK_F3 0x03 -+#define KK_F4 0x04 -+#define KK_F5 0x05 -+#define KK_F6 0x06 -+#define KK_F7 0x07 -+#define KK_F8 0x08 -+#define KK_F9 0x09 -+#define KK_F10 0x0a -+#define KK_F11 0x0b -+#define KK_F12 0x0c -+#define KK_PRNT 0x0d -+#define KK_SCRL 0x0e -+#define KK_BRK 0x0f -+#define KK_AGR 0x10 -+#define KK_1 0x11 -+#define KK_2 0x12 -+#define KK_3 0x13 -+#define KK_4 0x14 -+#define KK_5 0x15 -+#define KK_6 0x16 -+#define KK_7 0x17 -+#define KK_8 0x18 -+#define KK_9 0x19 -+#define KK_0 0x1a -+#define KK_MINS 0x1b -+#define KK_EQLS 0x1c -+#define KK_BKSP 0x1e -+#define KK_INS 0x1f -+#define KK_HOME 0x20 -+#define KK_PGUP 0x21 -+#define KK_NUML 0x22 -+#define KP_SLH 0x23 -+#define KP_STR 0x24 -+#define KP_MNS 0x3a -+#define KK_TAB 0x26 -+#define KK_Q 0x27 -+#define KK_W 0x28 -+#define KK_E 0x29 -+#define KK_R 0x2a -+#define KK_T 0x2b -+#define KK_Y 0x2c -+#define KK_U 0x2d -+#define KK_I 0x2e -+#define KK_O 0x2f -+#define KK_P 0x30 -+#define KK_LSBK 0x31 -+#define KK_RSBK 0x32 -+#define KK_ENTR 0x47 -+#define KK_DEL 0x34 -+#define KK_END 0x35 -+#define KK_PGDN 0x36 -+#define KP_7 0x37 -+#define KP_8 0x38 -+#define KP_9 0x39 -+#define KP_PLS 0x4b -+#define KK_CAPS 0x5d -+#define KK_A 0x3c -+#define KK_S 0x3d -+#define KK_D 0x3e -+#define KK_F 0x3f -+#define KK_G 0x40 -+#define KK_H 0x41 -+#define KK_J 0x42 -+#define KK_K 0x43 -+#define KK_L 0x44 -+#define KK_SEMI 0x45 -+#define KK_SQOT 0x46 -+#define KK_HASH 0x1d -+#define KP_4 0x48 -+#define KP_5 0x49 -+#define KP_6 0x4a -+#define KK_LSFT 0x4c -+#define KK_BSLH 0x33 -+#define KK_Z 0x4e -+#define KK_X 0x4f -+#define KK_C 0x50 -+#define KK_V 0x51 -+#define KK_B 0x52 -+#define KK_N 0x53 -+#define KK_M 0x54 -+#define KK_COMA 0x55 -+#define KK_DOT 0x56 -+#define KK_FSLH 0x57 -+#define KK_RSFT 0x58 -+#define KK_UP 0x59 -+#define KP_1 0x5a -+#define KP_2 0x5b -+#define KP_3 0x5c -+#define KP_ENT 0x67 -+#define KK_LCTL 0x3b -+#define KK_LALT 0x5e -+#define KK_SPCE 0x5f -+#define KK_RALT 0x60 -+#define KK_RCTL 0x61 -+#define KK_LEFT 0x62 -+#define KK_DOWN 0x63 -+#define KK_RGHT 0x64 -+#define KP_0 0x65 -+#define KP_DOT 0x66 -+ -+static char kbmap[128] = { -+KK_NONE, KK_LALT, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_AGR, KK_BSLH, KK_TAB, KK_Z, KK_A, KK_X, KK_NONE, -+KK_NONE, KK_NONE, KK_LSFT, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_LCTL, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, 0x21, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_ESC, KK_DEL, KK_Q, KK_CAPS, KK_S, KK_C, KK_3, -+KK_NONE, KK_1, KK_NONE, KK_W, KK_NONE, KK_D, KK_V, KK_4, -+KK_NONE, KK_2, KK_T, KK_E, KK_NONE, KK_F, KK_B, KK_5, -+KK_NONE, KK_9, KK_Y, KK_R, KK_K, KK_G, KK_N, KK_6, -+KK_NONE, KK_0, KK_U, KK_O, KK_L, KK_H, KK_M, KK_7, -+KK_NONE, KK_MINS, KK_I, KK_P, KK_SEMI, KK_J, KK_COMA, KK_8, -+KK_NONE, KK_EQLS, KK_ENTR, KK_LSBK, KK_BSLH, KK_FSLH, KK_DOT, KK_NONE, -+KK_NONE, KK_NONE, KK_RSFT, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_BKSP, KK_DOWN, KK_RSBK, KK_UP, KK_LEFT, KK_SPCE, KK_RGHT, -+KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE}; -+ -+static char kbmapFN[128] = { -+KK_NONE, KK_LALT, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_NONE, KK_LSFT, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_LCTL, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, 0x21, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_F3, -+KK_NONE, KK_F1, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_F4, -+KK_NONE, KK_F2, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_F5, -+KK_NONE, KK_F9, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_F6, -+KK_NONE, KK_F10, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_F7, -+KK_NONE, KK_NUML, KK_NONE, KK_INS, KK_PRNT, KK_NONE, KK_NONE, KK_F8, -+KK_NONE, KK_BRK, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_NONE, KK_RSFT, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_NONE, KK_PGDN, KK_SCRL, KK_PGUP, KK_HOME, KK_NONE, KK_END, -+KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE}; -+ -+static char kbmapNL[128] = { -+KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KP_9, KK_NONE, KK_NONE, KP_2, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KP_STR, KP_4, KP_6, KP_3, KK_NONE, KP_0, KP_7, -+KK_NONE, KK_NONE, KP_5, KP_MNS, KP_PLS, KP_1, KK_NONE, KP_8, -+KK_NONE, KK_NONE, KP_ENT, KK_NONE, KK_NONE, KP_SLH, KP_DOT, KK_NONE, -+KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, -+KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE}; -+ -+ -+ -diff -urN linux-2.4.26/drivers/char/gc_keyb.c linux-2.4.26-vrs1/drivers/char/gc_keyb.c ---- linux-2.4.26/drivers/char/gc_keyb.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/gc_keyb.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,1145 @@ -+/* -+ * linux/arch/arm/drivers/char/gc_keyb.c -+ * -+ * Copyright 2000 Applied Data Systems -+ * -+ * Keyboard & Smartio driver for GraphicsClient ARM Linux. -+ * Graphics Client is SA1110 based single board computer by -+ * Applied Data Systems (http://www.applieddata.net) -+ * -+ * Change log: -+ * 7-10/6/01 Thomas Thaele -+ * - Added Keyboard Sniffer on /dev/sio12 -+ * - First implementation of PC- compatible Scancodes (thanks to pc_keyb.c) -+ * 3/23/01 Woojung Huh -+ * Power Management added -+ * 12/01/00 Woojung Huh -+ * Bug fixed -+ * 11/16/00 Woojung Huh [whuh@applieddata.net] -+ * Added smartio device driver on it -+ */ -+ -+/* -+ * Introduced setkeycode, ketkeycode for the GC+ by Thomas Thaele -+ * GC+ now performs like a real PC on the keyboard. -+ * Warning: this code is still beta! PrntScrn and Pause keys are not -+ * completely tested and implemented!!! Keyboard driver can be confused -+ * by hacking like crazy on the keyboard. (hardware problem on serial line?) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define ADS_AVR_IRQ 63 -+ -+#define SMARTIO_IOCTL_BASES 's' -+#define SMARTIO_KPD_TIMEOUT _IOW(SMARTIO_IOCTL_BASES, 0, int) -+#define SMARTIO_KPD_SETUP _IOW(SMARTIO_IOCTL_BASES, 1, short) -+#define SMARTIO_BL_CONTROL _IOW(SMARTIO_IOCTL_BASES, 2, char) -+#define SMARTIO_BL_CONTRAST _IOW(SMARTIO_IOCTL_BASES, 3, char) -+#define SMARTIO_PORT_CONFIG _IOW(SMARTIO_IOCTL_BASES, 4, char) -+#define SMARTIO_SNIFFER_TIMEOUT _IOW(SMARTIO_IOCTL_BASES, 5, long) -+ -+ -+/* Simple translation table for the SysRq keys */ -+ -+#ifdef CONFIG_MAGIC_SYSRQ -+unsigned char pckbd_sysrq_xlate[128] = -+ "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ -+ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ -+ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ -+ "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ -+ "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ -+ "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ -+ "\r\000/"; /* 0x60 - 0x6f */ -+#endif -+ -+/* -+ * Translation of escaped scancodes to keycodes. -+ * This is now user-settable. -+ * The keycodes 1-88,96-111,119 are fairly standard, and -+ * should probably not be changed - changing might confuse X. -+ * X also interprets scancode 0x5d (KEY_Begin). -+ * -+ * For 1-88 keycode equals scancode. -+ */ -+ -+#define E0_KPENTER 96 -+#define E0_RCTRL 97 -+#define E0_KPSLASH 98 -+#define E0_PRSCR 99 -+#define E0_RALT 100 -+#define E0_BREAK 101 /* (control-pause) */ -+#define E0_HOME 102 -+#define E0_UP 103 -+#define E0_PGUP 104 -+#define E0_LEFT 105 -+#define E0_RIGHT 106 -+#define E0_END 107 -+#define E0_DOWN 108 -+#define E0_PGDN 109 -+#define E0_INS 110 -+#define E0_DEL 111 -+ -+#define E1_PAUSE 119 -+ -+/* -+ * The keycodes below are randomly located in 89-95,112-118,120-127. -+ * They could be thrown away (and all occurrences below replaced by 0), -+ * but that would force many users to use the `setkeycodes' utility, where -+ * they needed not before. It does not matter that there are duplicates, as -+ * long as no duplication occurs for any single keyboard. -+ */ -+#define SC_LIM 89 -+ -+#define FOCUS_PF1 85 /* actual code! */ -+#define FOCUS_PF2 89 -+#define FOCUS_PF3 90 -+#define FOCUS_PF4 91 -+#define FOCUS_PF5 92 -+#define FOCUS_PF6 93 -+#define FOCUS_PF7 94 -+#define FOCUS_PF8 95 -+#define FOCUS_PF9 120 -+#define FOCUS_PF10 121 -+#define FOCUS_PF11 122 -+#define FOCUS_PF12 123 -+ -+#define JAP_86 124 -+/* tfj@olivia.ping.dk: -+ * The four keys are located over the numeric keypad, and are -+ * labelled A1-A4. It's an rc930 keyboard, from -+ * Regnecentralen/RC International, Now ICL. -+ * Scancodes: 59, 5a, 5b, 5c. -+ */ -+#define RGN1 124 -+#define RGN2 125 -+#define RGN3 126 -+#define RGN4 127 -+ -+static unsigned char high_keys[128 - SC_LIM] = { -+ RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */ -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ -+ 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */ -+ 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */ -+ FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */ -+ FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */ -+}; -+ -+/* BTC */ -+#define E0_MACRO 112 -+/* LK450 */ -+#define E0_F13 113 -+#define E0_F14 114 -+#define E0_HELP 115 -+#define E0_DO 116 -+#define E0_F17 117 -+#define E0_KPMINPLUS 118 -+/* -+ * My OmniKey generates e0 4c for the "OMNI" key and the -+ * right alt key does nada. [kkoller@nyx10.cs.du.edu] -+ */ -+#define E0_OK 124 -+/* -+ * New microsoft keyboard is rumoured to have -+ * e0 5b (left window button), e0 5c (right window button), -+ * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU] -+ * [or: Windows_L, Windows_R, TaskMan] -+ */ -+#define E0_MSLW 125 -+#define E0_MSRW 126 -+#define E0_MSTM 127 -+ -+static unsigned char e0_keys[128] = { -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */ -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */ -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ -+ 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */ -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ -+ 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */ -+ E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */ -+ E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */ -+ E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */ -+ E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */ -+ 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */ -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ -+ 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */ -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ -+ 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ -+}; -+ -+int gc_kbd_setkeycode(unsigned int scancode, unsigned int keycode) -+{ -+ if (scancode < SC_LIM || scancode > 255 || keycode > 127) -+ return -EINVAL; -+ if (scancode < 128) -+ high_keys[scancode - SC_LIM] = keycode; -+ else -+ e0_keys[scancode - 128] = keycode; -+ return 0; -+} -+ -+int gc_kbd_getkeycode(unsigned int scancode) -+{ -+ return -+ (scancode < SC_LIM || scancode > 255) ? -EINVAL : -+ (scancode < 128) ? high_keys[scancode - SC_LIM] : -+ e0_keys[scancode - 128]; -+} -+ -+int gc_kbd_translate(unsigned char scancode, unsigned char *keycode, -+ char raw_mode) -+{ -+ static int prev_scancode; -+ -+ /* special prefix scancodes.. */ -+ if (scancode == 0xe0 || scancode == 0xe1) { -+ prev_scancode = scancode; -+ return 0; -+ } -+ -+ /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */ -+ if (scancode == 0x00 || scancode == 0xff) { -+ prev_scancode = 0; -+ return 0; -+ } -+ -+ scancode &= 0x7f; -+ -+ if (prev_scancode) { -+ /* -+ * usually it will be 0xe0, but a Pause key generates -+ * e1 1d 45 e1 9d c5 when pressed, and nothing when released -+ */ -+ if (prev_scancode != 0xe0) { -+ if (prev_scancode == 0xe1 && scancode == 0x1d) { -+ prev_scancode = 0x100; -+ return 0; -+ } else if (prev_scancode == 0x100 && scancode == 0x45) { -+ *keycode = E1_PAUSE; -+ prev_scancode = 0; -+ } else { -+#ifdef KBD_REPORT_UNKN -+ if (!raw_mode) -+ printk(KERN_INFO "keyboard: unknown e1 escape sequence\n"); -+#endif -+ prev_scancode = 0; -+ return 0; -+ } -+ } else { -+ prev_scancode = 0; -+ /* -+ * The keyboard maintains its own internal caps lock and -+ * num lock statuses. In caps lock mode E0 AA precedes make -+ * code and E0 2A follows break code. In num lock mode, -+ * E0 2A precedes make code and E0 AA follows break code. -+ * We do our own book-keeping, so we will just ignore these. -+ */ -+ /* -+ * For my keyboard there is no caps lock mode, but there are -+ * both Shift-L and Shift-R modes. The former mode generates -+ * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs. -+ * So, we should also ignore the latter. - aeb@cwi.nl -+ */ -+ if (scancode == 0x2a || scancode == 0x36) -+ return 0; -+ -+ if (e0_keys[scancode]) -+ *keycode = e0_keys[scancode]; -+ else { -+#ifdef KBD_REPORT_UNKN -+ if (!raw_mode) -+ printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n", -+ scancode); -+#endif -+ return 0; -+ } -+ } -+ } else if (scancode >= SC_LIM) { -+ /* This happens with the FOCUS 9000 keyboard -+ Its keys PF1..PF12 are reported to generate -+ 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f -+ Moreover, unless repeated, they do not generate -+ key-down events, so we have to zero up_flag below */ -+ /* Also, Japanese 86/106 keyboards are reported to -+ generate 0x73 and 0x7d for \ - and \ | respectively. */ -+ /* Also, some Brazilian keyboard is reported to produce -+ 0x73 and 0x7e for \ ? and KP-dot, respectively. */ -+ -+ *keycode = high_keys[scancode - SC_LIM]; -+ -+ if (!*keycode) { -+ if (!raw_mode) { -+#ifdef KBD_REPORT_UNKN -+ printk(KERN_INFO "keyboard: unrecognized scancode (%02x)" -+ " - ignored\n", scancode); -+#endif -+ } -+ return 0; -+ } -+ } else -+ *keycode = scancode; -+ return 1; -+} -+ -+// this table converts the hardware dependent codes of a MF-2 Keyboard to -+// the codes normally comming out of a i8042. This table is 128 Bytes too -+// big, but for stability reasons it should be kept like it is! -+// There is no range checking in the code! -+static int mf_two_kbdmap[256] = { -+ 00, 67, 65, 63, 61, 59, 60, 88, 00, 68, 66, 64, 62, 15, 41, 00, -+ 00, 56, 42, 00, 29, 16, 02, 00, 00, 00, 44, 31, 30, 17, 03, 00, -+ 00, 46, 45, 32, 18, 05, 04, 00, 00, 57, 47, 33, 20, 19, 06, 00, -+ 00, 49, 48, 35, 34, 21, 7, 00, 00, 00, 50, 36, 22, 8, 9, 00, -+ 00, 51, 37, 23, 24, 11, 10, 00, 00, 52, 53, 38, 39, 25, 12, 00, -+ 00, 00, 40, 00, 26, 13, 00, 00, 58, 54, 28, 27, 00, 43, 00, 00, -+ 00, 86, 00, 00, 00, 00, 14, 00, 00, 79, 00, 75, 71, 00, 00, 00, -+ 82, 83, 80, 76, 77, 72, 01, 69, 87, 78, 81, 74, 55, 73, 70, 00, -+ 00, 00, 00, 65, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, -+ 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, -+ 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, -+ 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, -+ 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, -+ 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, -+ 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, -+ 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 }; -+ -+ -+// some texts displayed by the proc_file_system -+static char *kbd_sniff[2] = { "off", "on" }; -+static char *kbd_sniff_mode[2] = { "passive", "active" }; -+ -+#define PASSIVE 0 -+#define ACTIVE 1 -+ -+// is the sniffer active (1) or inactive (0) -+static int SNIFFER = 0; -+// do we get a copy (SNIFFMODE = PASSIVE) or do we get the original data (SNIFFMODE = ACTIVE) -+// and have to reinsert the data -+static int SNIFFMODE = PASSIVE; -+ -+// we allow only one process to sniff -+static int sniffer_in_use = 0; -+ -+// timeout for the keyboard sniffer -1 = blocking, otherwise timeout in msecs -+static long sniffer_timeout = -1; -+ -+// the value we sniffed from the keyboard -+static int sniffed_value; -+ -+static char *smartio_version = "1.02 MF-II compatibility patch "; -+static char *smartio_date = "Aug-27-2001"; -+ -+static int sio_reset_flag; -+static int kbd_press_flag; -+ -+static void send_SSP_msg(unchar *pBuf, int num) -+{ -+ ushort tmp; -+ int i; -+ -+ for (i=0;i 7)) -+ return 0xFFFF; -+ -+ CONV_ADC_CMD.Opt[0] = (unchar) channel; -+ -+ lock_smartio(&flags); -+ send_SSP_msg((unchar *) &CONV_ADC_CMD, 3); -+ unlock_smartio(&flags); -+ -+ interruptible_sleep_on(&smartio_adc_queue); -+ -+ return adc_value & 0x3FF; -+} -+ -+static ushort read_sio_port(int port) -+{ -+ unsigned long flags; -+ ushort ret; -+ -+ if ((port < SMARTIO_PORT_B) || (port > SMARTIO_PORT_D)) -+ return 0xFFFF; -+ -+ READ_PORT_CMD.Code = (unchar) port; -+ -+ lock_smartio(&flags); -+ send_SSP_msg((unchar *) &READ_PORT_CMD, 2); -+ ret = read_SSP_response(1); -+ unlock_smartio(&flags); -+ -+ return ret; -+} -+ -+static ushort read_sio_kpd(void) -+{ -+ long timeout; -+ -+ // kpd_timeout is mSec order -+ // interrupt_sleep_on_timeout is based on 10msec timer tick -+ if (kpd_timeout == -1) { -+ interruptible_sleep_on(&smartio_kpd_queue); -+ } -+ else { -+ timeout = interruptible_sleep_on_timeout(&smartio_kpd_queue, -+ kpd_timeout/10); -+ if (timeout == 0) { -+ // timeout without keypad input -+ return 0xFFFF; -+ } -+ } -+ return kpd_value; -+} -+ -+static ushort read_sio_sniff(void) -+{ -+ long timeout; -+ -+ // kpd_timeout is mSec order -+ // interrupt_sleep_on_timeout is based on 10msec timer tick -+ if (sniffer_timeout == -1) { -+ interruptible_sleep_on(&sniffer_queue); -+ } -+ else { -+ timeout = interruptible_sleep_on_timeout(&sniffer_queue, -+ sniffer_timeout/10); -+ if (timeout == 0) { -+ // timeout without keypad input -+ return -1; -+ } -+ } -+ return (ushort)sniffed_value; -+} -+ -+static struct sio_ver { -+ uint DevVer; -+ uint DevType; -+ uint FwLevel; -+}; -+ -+static ushort read_sio_version(struct sio_ver *ptr) -+{ -+ unsigned long flags; -+ ushort ret; -+ -+ // Read Device Version -+ lock_smartio(&flags); -+ send_SSP_msg((unchar *) &READ_DEVVER_CMD, 2); -+ ret = read_SSP_response(1); -+ unlock_smartio(&flags); -+ ptr->DevVer = (uint)ret; -+ // Read Device Type -+ lock_smartio(&flags); -+ send_SSP_msg((unchar *) &READ_DEVTYPE_CMD, 2); -+ ret = read_SSP_response(2); -+ unlock_smartio(&flags); -+ // swap MSB & LSB -+ ret = ((ret & 0xFF) << 8) | ((ret & 0xFF00) >> 8); -+ ptr->DevType = (uint)ret; -+ // Read Firmware Level -+ lock_smartio(&flags); -+ send_SSP_msg((unchar *) &READ_FWLEVEL_CMD, 2); -+ ret = read_SSP_response(2); -+ unlock_smartio(&flags); -+ // swap MSB & LSB -+ ret = ((ret & 0xFF) << 8) | ((ret & 0xFF00) >> 8); -+ ptr->FwLevel = (uint)ret; -+ -+ return 0; -+} -+ -+static ssize_t sio_read(struct file *file, char *buf, size_t count, loff_t *ppos) -+{ -+ struct inode *inode = file->f_dentry->d_inode; -+ unsigned int minor = MINOR(inode->i_rdev); -+ ushort *ret = (ushort *)buf; -+ -+ switch (minor) { -+ case SMARTIO_ADC: -+ if ((*ret = read_sio_adc(buf[0])) != 0xFFFF) -+ return sizeof(ushort); // 2 bytes -+ case SMARTIO_PORT_B: -+ case SMARTIO_PORT_C: -+ case SMARTIO_PORT_D: -+ if ((*ret = read_sio_port(minor)) != 0xFFFF) -+ return sizeof(ushort); -+ case SMARTIO_VERSION: -+ if ((read_sio_version((struct sio_ver *)buf)) != 0xFFFF) -+ return sizeof(struct sio_ver); -+ case SMARTIO_KEYPAD: -+ if ((*ret = read_sio_kpd()) != 0xFFFF) -+ return sizeof(ushort); -+ case SMARTIO_KBD_SNIFFER: -+ if ((*ret = read_sio_sniff()) != (ushort)-1) -+ return 1; -+ default : -+ return -ENXIO; -+ } -+} -+ -+static SMARTIO_CMD WRITE_PORT_CMD = { 0x81, 0x00, { 0x00, 0x00 } }; -+static SMARTIO_CMD SELECT_OPT_CMD = { 0x80, 0x00, { 0x00, 0x00 } }; -+static SMARTIO_CMD CONTROL_BL_CMD = { 0x80, 0x00, { 0x00, 0x00 } }; -+static SMARTIO_CMD CONTRAST_BL_CMD = { 0x80, 0x21, { 0x00, 0x00 } }; -+static SMARTIO_CMD CONTROL_KPD_CMD = { 0x80, 0x27, { 0x00, 0x00 } }; -+static SMARTIO_CMD CONTROL_VEE_CMD = { 0x80, 0x22, { 0x00, 0x00 } }; -+ -+static ushort write_sio_port(int port, unchar value) -+{ -+ unsigned long flags; -+ -+ if ((port < SMARTIO_PORT_B) || (port > SMARTIO_PORT_D)) -+ return 0xFFFF; -+ -+ WRITE_PORT_CMD.Code = (unchar) port; -+ WRITE_PORT_CMD.Opt[0] = (unchar) value; -+ -+ lock_smartio(&flags); -+ send_SSP_msg((unchar *) &WRITE_PORT_CMD, 3); -+ unlock_smartio(&flags); -+ -+ return 0; -+} -+ -+static ushort write_sio_select(unchar select) -+{ -+ unsigned long flags; -+ -+ if ((select < 1) || (select > 2)) -+ return 0xFFFF; -+ -+ SELECT_OPT_CMD.Code = (unchar) (select + 0x28); -+ -+ lock_smartio(&flags); -+ send_SSP_msg((unchar *) &SELECT_OPT_CMD, 2); -+ unlock_smartio(&flags); -+ -+ return 0; -+} -+ -+static ushort control_sio_backlite(int cmd, int value) -+{ -+ unsigned long flags; -+ -+ if (cmd == SMARTIO_BL_CONTRAST) { -+ value &= 0xFF; -+ CONTRAST_BL_CMD.Opt[0] = (unchar) value; -+ -+ lock_smartio(&flags); -+ send_SSP_msg((unchar *) &CONTRAST_BL_CMD, 3); -+ unlock_smartio(&flags); -+ } -+ else if (cmd == SMARTIO_BL_CONTROL) { -+ if (value == 0x00) { -+ // Backlite OFF -+ CONTROL_BL_CMD.Code = 0x24; -+ } -+ else { -+ // Backlite ON -+ CONTROL_BL_CMD.Code = 0x23; -+ } -+ lock_smartio(&flags); -+ send_SSP_msg((unchar *) &CONTROL_BL_CMD, 2); -+ unlock_smartio(&flags); -+ } -+ else -+ return 0xFFFF; -+ -+ return 0; -+} -+ -+static ushort control_sio_keypad(int x, int y) -+{ -+ unsigned long flags; -+ -+ if ( (x<1) || (x>8) || (y<1) || (y>8)) { -+ return 0xFFFF; -+ } -+ -+ CONTROL_KPD_CMD.Opt[0] = (unchar) x; -+ CONTROL_KPD_CMD.Opt[1] = (unchar) y; -+ -+ lock_smartio(&flags); -+ send_SSP_msg((unchar *) &CONTROL_KPD_CMD, 4); -+ unlock_smartio(&flags); -+ -+ return 0; -+} -+ -+static ushort control_sio_vee(int value) -+{ -+ unsigned long flags; -+ -+ value &= 0xFF; -+ CONTROL_VEE_CMD.Opt[0] = (unchar) value; -+ -+ lock_smartio(&flags); -+ send_SSP_msg((unchar *) &CONTROL_VEE_CMD, 3); -+ unlock_smartio(&flags); -+ -+ return 0; -+} -+ -+static ssize_t sio_write(struct file *file, const char *buf, size_t cont, loff_t *ppos) -+{ -+ struct inode *inode = file->f_dentry->d_inode; -+ unsigned int minor = MINOR(inode->i_rdev); -+ -+ switch (minor) { -+ case SMARTIO_PORT_B: -+ case SMARTIO_PORT_C: -+ case SMARTIO_PORT_D: -+ if (write_sio_port(minor, buf[0]) != 0xFFFF) -+ return 1; -+ case SMARTIO_SELECT_OPTION: -+ if (write_sio_select(buf[0]) != 0xFFFF) -+ return 1; -+ case SMARTIO_BACKLITE: -+ if (control_sio_backlite(SMARTIO_BL_CONTROL, buf[0]) != 0xFFFF) -+ return 1; -+ case SMARTIO_KEYPAD: -+ if (control_sio_keypad(buf[0], buf[1]) != 0xFFFF) -+ return 2; -+ case SMARTIO_VEE_PWM: -+ if (control_sio_vee(buf[0]) != 0xFFFF) -+ return 1; -+ case SMARTIO_KBD_SNIFFER: -+ // here are the scancodes injected -+ handle_scancode((unchar)buf[0], (buf[0] & 0x80) ? 0 : 1); -+ wake_up_interruptible(&keyboard_done_queue); -+ // give some time to process! File IO is a bit faster than manual typing ;-) -+ udelay(10000); -+ return 1; -+ default: -+ return -ENXIO; -+ } -+} -+ -+static unsigned int sio_poll(struct file *file, struct poll_table_struct *wait) -+{ -+ return 0; -+} -+ -+static SMARTIO_CMD IOCTL_PORT_CMD = { 0x81, 0x00, { 0x00, 0x00 } }; -+ -+static ushort ioctl_sio_port(int port, unchar value) -+{ -+ unsigned long flags; -+ -+ if ((port < SMARTIO_PORT_B) || (port > SMARTIO_PORT_D)) -+ return 0xFFFF; -+ -+ IOCTL_PORT_CMD.Code = (unchar) port + 0x04; // 0x05 ~ 0x08 -+ if (port == SMARTIO_PORT_B) { -+ // Port B has 4 bits only -+ IOCTL_PORT_CMD.Opt[0] = (unchar) value & 0x0F; -+ } -+ else -+ IOCTL_PORT_CMD.Opt[0] = (unchar) value; -+ -+ lock_smartio(&flags); -+ send_SSP_msg((unchar *) &IOCTL_PORT_CMD, 3); -+ unlock_smartio(&flags); -+ -+ return 0; -+} -+ -+static int sio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ unsigned int minor = MINOR(inode->i_rdev); -+ unchar *buf = (unchar *)arg; -+ -+ switch (minor) { -+ case SMARTIO_PORT_B: -+ case SMARTIO_PORT_C: -+ case SMARTIO_PORT_D: -+ if (cmd == SMARTIO_PORT_CONFIG) { -+ if (ioctl_sio_port(minor, buf[0]) != 0xFFFF) -+ return 0; -+ } -+ return -EINVAL; -+ case SMARTIO_SELECT_OPTION: -+ if (write_sio_select(buf[0]) != 0xFFFF) return 0; -+ return -EINVAL; -+ case SMARTIO_BACKLITE: -+ if (cmd == SMARTIO_BL_CONTROL) { -+ if (control_sio_backlite(SMARTIO_BL_CONTROL, buf[0]) != 0xFFFF) return 0; -+ } -+ else if (cmd == SMARTIO_BL_CONTRAST) { -+ if (control_sio_backlite(SMARTIO_BL_CONTRAST, buf[0]) != 0xFFFF) return 0; -+ } -+ else return -EINVAL; -+ case SMARTIO_KEYPAD: -+ if (cmd == SMARTIO_KPD_TIMEOUT) { -+ kpd_timeout = *(long*)buf; -+ return 0; -+ } -+ else if (cmd == SMARTIO_KPD_SETUP) { -+ if (control_sio_keypad(buf[0], buf[1]) != 0xFFFF) return 0; -+ } -+ return -EINVAL; -+ case SMARTIO_VEE_PWM: -+ if (control_sio_vee(buf[0]) != 0xFFFF) return 0; -+ return -EINVAL; -+ case SMARTIO_KBD_SNIFFER: -+ if (cmd == SMARTIO_SNIFFER_TIMEOUT) { -+ sniffer_timeout = *(long*)buf; -+ if (sniffer_timeout < 0) sniffer_timeout = -1; -+ // the value will be devided by 10 later on -+ if (!sniffer_timeout) sniffer_timeout = 10; -+ return 0; -+ } -+ return -EINVAL; -+ default: -+ return -ENXIO; -+ } -+} -+ -+static int sio_open(struct inode *inode, struct file *file) -+{ -+ unsigned int minor = MINOR(inode->i_rdev); -+ -+ // we open all by default. we only have a special handler for the kbd sniffer -+ switch (minor) { -+ case SMARTIO_KBD_SNIFFER: -+ if (sniffer_in_use) return -EBUSY; -+ sniffer_in_use = 1; -+ SNIFFER = 1; -+ // sniff in active or passive mode -+ if ((file->f_flags & O_RDWR) == O_RDWR) SNIFFMODE = 1; else SNIFFMODE = 0; -+ // do we have a blocking or non blocking sniffer? -+ if ((file->f_flags & O_NONBLOCK) == O_NONBLOCK) sniffer_timeout = 100; else sniffer_timeout = -1; -+ break; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+static int sio_close(struct inode *inode, struct file *file) -+{ -+ unsigned int minor = MINOR(inode->i_rdev); -+ -+ switch (minor) { -+ case SMARTIO_KBD_SNIFFER: -+ SNIFFER = 0; -+ SNIFFMODE = 0; -+ sniffer_in_use = 0; -+ break; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+static struct file_operations sio_fops = { -+ read: sio_read, -+ write: sio_write, -+ poll: sio_poll, -+ ioctl: sio_ioctl, -+ open: sio_open, -+ release: sio_close, -+}; -+ -+static struct proc_dir_entry *sio_dir, *parent_dir = NULL; -+ -+#define SMARTIO_MAJOR 58 -+#define MAJOR_NR SMARTIO_MAJOR -+ -+#define PROC_NAME "sio" -+ -+static int sio_read_proc(char *buf, char **start, off_t pos, int count, int *eof, void *data) -+{ -+ char *p = buf; -+ -+ p += sprintf(p, "ADS SMARTIO Status: \n"); -+ p += sprintf(p, "\t Keyboard Interrupt : %lu\n", kbd_int); -+ p += sprintf(p, "\t Keypad Interrupt : %lu\n", kpd_int); -+ p += sprintf(p, "\t ADC Interrupt : %lu\n", adc_int); -+ p += sprintf(p, "\t Keyboard Sniffer : %s mode : %s\n", kbd_sniff[ SNIFFER ], kbd_sniff_mode [ SNIFFMODE ]); -+ -+ return (p-buf); -+} -+ -+#ifdef CONFIG_PM -+static int pm_smartio_callback(struct pm_dev *dev, pm_request_t rqst, void *data) -+{ -+ switch (rqst) { -+ case PM_RESUME: -+ gc_sio_init(); -+ break; -+ case PM_SUSPEND: -+ // 4/5/01 Woojung -+ // It checks Keybard received pair of press/release code. -+ // System can sleep before receiving release code -+ if (kbd_press_flag) { -+ interruptible_sleep_on(&keyboard_done_queue); -+ } -+ break; -+ } -+ -+ return 0; -+} -+#endif -+ -+void __init sio_init(void) -+{ -+ if (register_chrdev(MAJOR_NR, "sio", &sio_fops)) { -+ printk("smartio : unable to get major %d\n", MAJOR_NR); -+ return; -+ } -+ else { -+ printk("smartio driver initialized. version %s, date:%s\n", -+ smartio_version, smartio_date); -+ -+ if (sio_reset_flag != 1) { -+ gc_sio_init(); -+ if (request_irq(ADS_AVR_IRQ, gc_sio_interrupt,0,"sio",NULL) != 0){ -+ printk("smartio : Could not allocate IRQ!\n"); -+ return; -+ } -+ } -+ -+ if ((sio_dir = create_proc_entry(PROC_NAME, 0, parent_dir)) == NULL) { -+ printk("smartio : Unable to create /proc entry\n"); -+ return; -+ } -+ else { -+ sio_dir->read_proc = sio_read_proc; -+#ifdef CONFIG_PM -+ pm_register(PM_SYS_DEV, PM_SYS_KBC, pm_smartio_callback); -+#endif -+ } -+ } -+} -diff -urN linux-2.4.26/drivers/char/gckeymap.c linux-2.4.26-vrs1/drivers/char/gckeymap.c ---- linux-2.4.26/drivers/char/gckeymap.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/gckeymap.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,262 @@ -+/* Do not edit this file! It was automatically generated by */ -+/* loadkeys --mktable defkeymap.map > defkeymap.c */ -+ -+#include -+#include -+#include -+ -+u_short plain_map[NR_KEYS] = { -+ 0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, -+ 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf07f, 0xf009, -+ 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, -+ 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73, -+ 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b, -+ 0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, -+ 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf30c, -+ 0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, -+ 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf209, 0xf307, -+ 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, -+ 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03c, 0xf10a, -+ 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -+ 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, -+ 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, -+ 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, -+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -+}; -+ -+u_short shift_map[NR_KEYS] = { -+ 0xf200, 0xf01b, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, -+ 0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07f, 0xf009, -+ 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49, -+ 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf201, 0xf702, 0xfb41, 0xfb53, -+ 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a, -+ 0xf022, 0xf07e, 0xf700, 0xf07c, 0xfb5a, 0xfb58, 0xfb43, 0xfb56, -+ 0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf700, 0xf30c, -+ 0xf703, 0xf020, 0xf207, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, -+ 0xf10f, 0xf110, 0xf111, 0xf112, 0xf113, 0xf213, 0xf203, 0xf307, -+ 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, -+ 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03e, 0xf10a, -+ 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -+ 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, -+ 0xf20b, 0xf601, 0xf602, 0xf117, 0xf600, 0xf20a, 0xf115, 0xf116, -+ 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, -+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -+}; -+ -+u_short altgr_map[NR_KEYS] = { -+ 0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, -+ 0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200, -+ 0xfb71, 0xfb77, 0xf918, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, -+ 0xfb6f, 0xfb70, 0xf200, 0xf07e, 0xf201, 0xf702, 0xf914, 0xfb73, -+ 0xf917, 0xf919, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf200, -+ 0xf200, 0xf200, 0xf700, 0xf200, 0xfb7a, 0xfb78, 0xf916, 0xfb76, -+ 0xf915, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c, -+ 0xf703, 0xf200, 0xf207, 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, -+ 0xf511, 0xf512, 0xf513, 0xf514, 0xf515, 0xf208, 0xf202, 0xf911, -+ 0xf912, 0xf913, 0xf30b, 0xf90e, 0xf90f, 0xf910, 0xf30a, 0xf90b, -+ 0xf90c, 0xf90d, 0xf90a, 0xf310, 0xf206, 0xf200, 0xf07c, 0xf516, -+ 0xf517, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -+ 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, -+ 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, -+ 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, -+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -+}; -+ -+u_short ctrl_map[NR_KEYS] = { -+ 0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, -+ 0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200, -+ 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, -+ 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013, -+ 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, -+ 0xf007, 0xf000, 0xf700, 0xf01c, 0xf01a, 0xf018, 0xf003, 0xf016, -+ 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf20e, 0xf07f, 0xf700, 0xf30c, -+ 0xf703, 0xf000, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, -+ 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf204, 0xf307, -+ 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, -+ 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf10a, -+ 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -+ 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, -+ 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, -+ 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, -+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -+}; -+ -+u_short shift_ctrl_map[NR_KEYS] = { -+ 0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, -+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, -+ 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, -+ 0xf00f, 0xf010, 0xf200, 0xf200, 0xf201, 0xf702, 0xf001, 0xf013, -+ 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, -+ 0xf200, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016, -+ 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c, -+ 0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf208, 0xf200, 0xf307, -+ 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, -+ 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf200, -+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -+ 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, -+ 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, -+ 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, -+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -+}; -+ -+u_short alt_map[NR_KEYS] = { -+ 0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, -+ 0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf87f, 0xf809, -+ 0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869, -+ 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf80d, 0xf702, 0xf861, 0xf873, -+ 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b, -+ 0xf827, 0xf860, 0xf700, 0xf85c, 0xf87a, 0xf878, 0xf863, 0xf876, -+ 0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf700, 0xf30c, -+ 0xf703, 0xf820, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, -+ 0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf209, 0xf907, -+ 0xf908, 0xf909, 0xf30b, 0xf904, 0xf905, 0xf906, 0xf30a, 0xf901, -+ 0xf902, 0xf903, 0xf900, 0xf310, 0xf206, 0xf200, 0xf83c, 0xf50a, -+ 0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -+ 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, -+ 0xf118, 0xf210, 0xf211, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, -+ 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, -+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -+}; -+ -+u_short ctrl_alt_map[NR_KEYS] = { -+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -+ 0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809, -+ 0xf80f, 0xf810, 0xf200, 0xf200, 0xf201, 0xf702, 0xf801, 0xf813, -+ 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200, -+ 0xf200, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816, -+ 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c, -+ 0xf703, 0xf200, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, -+ 0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf200, 0xf307, -+ 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, -+ 0xf302, 0xf303, 0xf300, 0xf20c, 0xf206, 0xf200, 0xf200, 0xf50a, -+ 0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -+ 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603, -+ 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf20c, -+ 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, -+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -+}; -+ -+ushort *key_maps[MAX_NR_KEYMAPS] = { -+ plain_map, shift_map, altgr_map, 0, -+ ctrl_map, shift_ctrl_map, 0, 0, -+ alt_map, 0, 0, 0, -+ ctrl_alt_map, 0 -+}; -+ -+unsigned int keymap_count = 7; -+ -+/* -+ * Philosophy: most people do not define more strings, but they who do -+ * often want quite a lot of string space. So, we statically allocate -+ * the default and allocate dynamically in chunks of 512 bytes. -+ */ -+ -+char func_buf[] = { -+ '\033', '[', '[', 'A', 0, -+ '\033', '[', '[', 'B', 0, -+ '\033', '[', '[', 'C', 0, -+ '\033', '[', '[', 'D', 0, -+ '\033', '[', '[', 'E', 0, -+ '\033', '[', '1', '7', '~', 0, -+ '\033', '[', '1', '8', '~', 0, -+ '\033', '[', '1', '9', '~', 0, -+ '\033', '[', '2', '0', '~', 0, -+ '\033', '[', '2', '1', '~', 0, -+ '\033', '[', '2', '3', '~', 0, -+ '\033', '[', '2', '4', '~', 0, -+ '\033', '[', '2', '5', '~', 0, -+ '\033', '[', '2', '6', '~', 0, -+ '\033', '[', '2', '8', '~', 0, -+ '\033', '[', '2', '9', '~', 0, -+ '\033', '[', '3', '1', '~', 0, -+ '\033', '[', '3', '2', '~', 0, -+ '\033', '[', '3', '3', '~', 0, -+ '\033', '[', '3', '4', '~', 0, -+ '\033', '[', '1', '~', 0, -+ '\033', '[', '2', '~', 0, -+ '\033', '[', '3', '~', 0, -+ '\033', '[', '4', '~', 0, -+ '\033', '[', '5', '~', 0, -+ '\033', '[', '6', '~', 0, -+ '\033', '[', 'M', 0, -+ '\033', '[', 'P', 0, -+}; -+ -+char *funcbufptr = func_buf; -+int funcbufsize = sizeof(func_buf); -+int funcbufleft = 0; /* space left */ -+ -+char *func_table[MAX_NR_FUNC] = { -+ func_buf + 0, -+ func_buf + 5, -+ func_buf + 10, -+ func_buf + 15, -+ func_buf + 20, -+ func_buf + 25, -+ func_buf + 31, -+ func_buf + 37, -+ func_buf + 43, -+ func_buf + 49, -+ func_buf + 55, -+ func_buf + 61, -+ func_buf + 67, -+ func_buf + 73, -+ func_buf + 79, -+ func_buf + 85, -+ func_buf + 91, -+ func_buf + 97, -+ func_buf + 103, -+ func_buf + 109, -+ func_buf + 115, -+ func_buf + 120, -+ func_buf + 125, -+ func_buf + 130, -+ func_buf + 135, -+ func_buf + 140, -+ func_buf + 145, -+ 0, -+ 0, -+ func_buf + 149, -+ 0, -+}; -+ -+struct kbdiacr accent_table[MAX_DIACR] = { -+ {'`', 'A', '\300'}, {'`', 'a', '\340'}, -+ {'\'', 'A', '\301'}, {'\'', 'a', '\341'}, -+ {'^', 'A', '\302'}, {'^', 'a', '\342'}, -+ {'~', 'A', '\303'}, {'~', 'a', '\343'}, -+ {'"', 'A', '\304'}, {'"', 'a', '\344'}, -+ {'O', 'A', '\305'}, {'o', 'a', '\345'}, -+ {'0', 'A', '\305'}, {'0', 'a', '\345'}, -+ {'A', 'A', '\305'}, {'a', 'a', '\345'}, -+ {'A', 'E', '\306'}, {'a', 'e', '\346'}, -+ {',', 'C', '\307'}, {',', 'c', '\347'}, -+ {'`', 'E', '\310'}, {'`', 'e', '\350'}, -+ {'\'', 'E', '\311'}, {'\'', 'e', '\351'}, -+ {'^', 'E', '\312'}, {'^', 'e', '\352'}, -+ {'"', 'E', '\313'}, {'"', 'e', '\353'}, -+ {'`', 'I', '\314'}, {'`', 'i', '\354'}, -+ {'\'', 'I', '\315'}, {'\'', 'i', '\355'}, -+ {'^', 'I', '\316'}, {'^', 'i', '\356'}, -+ {'"', 'I', '\317'}, {'"', 'i', '\357'}, -+ {'-', 'D', '\320'}, {'-', 'd', '\360'}, -+ {'~', 'N', '\321'}, {'~', 'n', '\361'}, -+ {'`', 'O', '\322'}, {'`', 'o', '\362'}, -+ {'\'', 'O', '\323'}, {'\'', 'o', '\363'}, -+ {'^', 'O', '\324'}, {'^', 'o', '\364'}, -+ {'~', 'O', '\325'}, {'~', 'o', '\365'}, -+ {'"', 'O', '\326'}, {'"', 'o', '\366'}, -+ {'/', 'O', '\330'}, {'/', 'o', '\370'}, -+ {'`', 'U', '\331'}, {'`', 'u', '\371'}, -+ {'\'', 'U', '\332'}, {'\'', 'u', '\372'}, -+ {'^', 'U', '\333'}, {'^', 'u', '\373'}, -+ {'"', 'U', '\334'}, {'"', 'u', '\374'}, -+ {'\'', 'Y', '\335'}, {'\'', 'y', '\375'}, -+ {'T', 'H', '\336'}, {'t', 'h', '\376'}, -+ {'s', 's', '\337'}, {'"', 'y', '\377'}, -+ {'s', 'z', '\337'}, {'i', 'j', '\377'}, -+}; -+ -+unsigned int accent_table_size = 68; -diff -urN linux-2.4.26/drivers/char/gckeymap.map linux-2.4.26-vrs1/drivers/char/gckeymap.map ---- linux-2.4.26/drivers/char/gckeymap.map 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/gckeymap.map 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,357 @@ -+# Default kernel keymap. This uses 7 modifier combinations. -+keymaps 0-2,4-5,8,12 -+# Change the above line into -+# keymaps 0-2,4-6,8,12 -+# in case you want the entries -+# altgr control keycode 83 = Boot -+# altgr control keycode 111 = Boot -+# below. -+# -+# In fact AltGr is used very little, and one more keymap can -+# be saved by mapping AltGr to Alt (and adapting a few entries): -+# keycode 100 = Alt -+# -+keycode 1 = Escape Escape -+ alt keycode 1 = Meta_Escape -+keycode 2 = one exclam -+ alt keycode 2 = Meta_one -+keycode 3 = two at at -+ control keycode 3 = nul -+ shift control keycode 3 = nul -+ alt keycode 3 = Meta_two -+keycode 4 = three numbersign -+ control keycode 4 = Escape -+ alt keycode 4 = Meta_three -+keycode 5 = four dollar dollar -+ control keycode 5 = Control_backslash -+ alt keycode 5 = Meta_four -+keycode 6 = five percent -+ control keycode 6 = Control_bracketright -+ alt keycode 6 = Meta_five -+keycode 7 = six asciicircum -+ control keycode 7 = Control_asciicircum -+ alt keycode 7 = Meta_six -+keycode 8 = seven ampersand braceleft -+ control keycode 8 = Control_underscore -+ alt keycode 8 = Meta_seven -+keycode 9 = eight asterisk bracketleft -+ control keycode 9 = Delete -+ alt keycode 9 = Meta_eight -+keycode 10 = nine parenleft bracketright -+ alt keycode 10 = Meta_nine -+keycode 11 = zero parenright braceright -+ alt keycode 11 = Meta_zero -+keycode 12 = minus underscore backslash -+ control keycode 12 = Control_underscore -+ shift control keycode 12 = Control_underscore -+ alt keycode 12 = Meta_minus -+keycode 13 = equal plus -+ alt keycode 13 = Meta_equal -+keycode 14 = Delete Delete -+ control keycode 14 = BackSpace -+ alt keycode 14 = Meta_Delete -+keycode 15 = Tab Tab -+ alt keycode 15 = Meta_Tab -+keycode 16 = q -+keycode 17 = w -+keycode 18 = e -+ altgr keycode 18 = Hex_E -+keycode 19 = r -+keycode 20 = t -+keycode 21 = y -+keycode 22 = u -+keycode 23 = i -+keycode 24 = o -+keycode 25 = p -+keycode 26 = bracketleft braceleft -+ control keycode 26 = Escape -+ alt keycode 26 = Meta_bracketleft -+keycode 27 = bracketright braceright asciitilde -+ control keycode 27 = Control_bracketright -+ alt keycode 27 = Meta_bracketright -+keycode 28 = Return -+ alt keycode 28 = Meta_Control_m -+keycode 29 = Control -+keycode 30 = a -+ altgr keycode 30 = Hex_A -+keycode 31 = s -+keycode 32 = d -+ altgr keycode 32 = Hex_D -+keycode 33 = f -+ altgr keycode 33 = Hex_F -+keycode 34 = g -+keycode 35 = h -+keycode 36 = j -+keycode 37 = k -+keycode 38 = l -+keycode 39 = semicolon colon -+ alt keycode 39 = Meta_semicolon -+keycode 40 = apostrophe quotedbl -+ control keycode 40 = Control_g -+ alt keycode 40 = Meta_apostrophe -+keycode 41 = grave asciitilde -+ control keycode 41 = nul -+ alt keycode 41 = Meta_grave -+keycode 42 = Shift -+keycode 43 = backslash bar -+ control keycode 43 = Control_backslash -+ alt keycode 43 = Meta_backslash -+keycode 44 = z -+keycode 45 = x -+keycode 46 = c -+ altgr keycode 46 = Hex_C -+keycode 47 = v -+keycode 48 = b -+ altgr keycode 48 = Hex_B -+keycode 49 = n -+keycode 50 = m -+keycode 51 = comma less -+ alt keycode 51 = Meta_comma -+keycode 52 = period greater -+ control keycode 52 = Compose -+ alt keycode 52 = Meta_period -+keycode 53 = slash question -+ control keycode 53 = Delete -+ alt keycode 53 = Meta_slash -+keycode 54 = Shift -+keycode 55 = KP_Multiply -+keycode 56 = Alt -+keycode 57 = space space -+ control keycode 57 = nul -+ alt keycode 57 = Meta_space -+keycode 58 = Caps_Lock -+keycode 59 = F1 F11 Console_13 -+ control keycode 59 = F1 -+ alt keycode 59 = Console_1 -+ control alt keycode 59 = Console_1 -+keycode 60 = F2 F12 Console_14 -+ control keycode 60 = F2 -+ alt keycode 60 = Console_2 -+ control alt keycode 60 = Console_2 -+keycode 61 = F3 F13 Console_15 -+ control keycode 61 = F3 -+ alt keycode 61 = Console_3 -+ control alt keycode 61 = Console_3 -+keycode 62 = F4 F14 Console_16 -+ control keycode 62 = F4 -+ alt keycode 62 = Console_4 -+ control alt keycode 62 = Console_4 -+keycode 63 = F5 F15 Console_17 -+ control keycode 63 = F5 -+ alt keycode 63 = Console_5 -+ control alt keycode 63 = Console_5 -+keycode 64 = F6 F16 Console_18 -+ control keycode 64 = F6 -+ alt keycode 64 = Console_6 -+ control alt keycode 64 = Console_6 -+keycode 65 = F7 F17 Console_19 -+ control keycode 65 = F7 -+ alt keycode 65 = Console_7 -+ control alt keycode 65 = Console_7 -+keycode 66 = F8 F18 Console_20 -+ control keycode 66 = F8 -+ alt keycode 66 = Console_8 -+ control alt keycode 66 = Console_8 -+keycode 67 = F9 F19 Console_21 -+ control keycode 67 = F9 -+ alt keycode 67 = Console_9 -+ control alt keycode 67 = Console_9 -+keycode 68 = F10 F20 Console_22 -+ control keycode 68 = F10 -+ alt keycode 68 = Console_10 -+ control alt keycode 68 = Console_10 -+keycode 69 = Num_Lock -+ shift keycode 69 = Bare_Num_Lock -+keycode 70 = Scroll_Lock Show_Memory Show_Registers -+ control keycode 70 = Show_State -+ alt keycode 70 = Scroll_Lock -+keycode 71 = KP_7 -+ alt keycode 71 = Ascii_7 -+ altgr keycode 71 = Hex_7 -+keycode 72 = KP_8 -+ alt keycode 72 = Ascii_8 -+ altgr keycode 72 = Hex_8 -+keycode 73 = KP_9 -+ alt keycode 73 = Ascii_9 -+ altgr keycode 73 = Hex_9 -+keycode 74 = KP_Subtract -+keycode 75 = KP_4 -+ alt keycode 75 = Ascii_4 -+ altgr keycode 75 = Hex_4 -+keycode 76 = KP_5 -+ alt keycode 76 = Ascii_5 -+ altgr keycode 76 = Hex_5 -+keycode 77 = KP_6 -+ alt keycode 77 = Ascii_6 -+ altgr keycode 77 = Hex_6 -+keycode 78 = KP_Add -+keycode 79 = KP_1 -+ alt keycode 79 = Ascii_1 -+ altgr keycode 79 = Hex_1 -+keycode 80 = KP_2 -+ alt keycode 80 = Ascii_2 -+ altgr keycode 80 = Hex_2 -+keycode 81 = KP_3 -+ alt keycode 81 = Ascii_3 -+ altgr keycode 81 = Hex_3 -+keycode 82 = KP_0 -+ alt keycode 82 = Ascii_0 -+ altgr keycode 82 = Hex_0 -+keycode 83 = KP_Period -+# altgr control keycode 83 = Boot -+ control alt keycode 83 = Boot -+keycode 84 = Last_Console -+keycode 85 = -+keycode 86 = less greater bar -+ alt keycode 86 = Meta_less -+keycode 87 = F11 F11 Console_23 -+ control keycode 87 = F11 -+ alt keycode 87 = Console_11 -+ control alt keycode 87 = Console_11 -+keycode 88 = F12 F12 Console_24 -+ control keycode 88 = F12 -+ alt keycode 88 = Console_12 -+ control alt keycode 88 = Console_12 -+keycode 89 = -+keycode 90 = -+keycode 91 = -+keycode 92 = -+keycode 93 = -+keycode 94 = -+keycode 95 = -+keycode 96 = KP_Enter -+keycode 97 = Control -+keycode 98 = KP_Divide -+keycode 99 = Control_backslash -+ control keycode 99 = Control_backslash -+ alt keycode 99 = Control_backslash -+keycode 100 = AltGr -+keycode 101 = Break -+keycode 102 = Find -+keycode 103 = Up -+keycode 104 = Prior -+ shift keycode 104 = Scroll_Backward -+keycode 105 = Left -+ alt keycode 105 = Decr_Console -+keycode 106 = Right -+ alt keycode 106 = Incr_Console -+keycode 107 = Select -+keycode 108 = Down -+keycode 109 = Next -+ shift keycode 109 = Scroll_Forward -+keycode 110 = Insert -+keycode 111 = Remove -+# altgr control keycode 111 = Boot -+ control alt keycode 111 = Boot -+keycode 112 = Macro -+keycode 113 = F13 -+keycode 114 = F14 -+keycode 115 = Help -+keycode 116 = Do -+keycode 117 = F17 -+keycode 118 = KP_MinPlus -+keycode 119 = Pause -+keycode 120 = -+keycode 121 = -+keycode 122 = -+keycode 123 = -+keycode 124 = -+keycode 125 = -+keycode 126 = -+keycode 127 = -+string F1 = "\033[[A" -+string F2 = "\033[[B" -+string F3 = "\033[[C" -+string F4 = "\033[[D" -+string F5 = "\033[[E" -+string F6 = "\033[17~" -+string F7 = "\033[18~" -+string F8 = "\033[19~" -+string F9 = "\033[20~" -+string F10 = "\033[21~" -+string F11 = "\033[23~" -+string F12 = "\033[24~" -+string F13 = "\033[25~" -+string F14 = "\033[26~" -+string F15 = "\033[28~" -+string F16 = "\033[29~" -+string F17 = "\033[31~" -+string F18 = "\033[32~" -+string F19 = "\033[33~" -+string F20 = "\033[34~" -+string Find = "\033[1~" -+string Insert = "\033[2~" -+string Remove = "\033[3~" -+string Select = "\033[4~" -+string Prior = "\033[5~" -+string Next = "\033[6~" -+string Macro = "\033[M" -+string Pause = "\033[P" -+compose '`' 'A' to 'ƀ' -+compose '`' 'a' to 'Ć ' -+compose '\'' 'A' to 'Ɓ' -+compose '\'' 'a' to 'Ć”' -+compose '^' 'A' to 'Ƃ' -+compose '^' 'a' to 'Ć¢' -+compose '~' 'A' to 'ƃ' -+compose '~' 'a' to 'Ć£' -+compose '"' 'A' to 'Ƅ' -+compose '"' 'a' to 'Ƥ' -+compose 'O' 'A' to 'ƅ' -+compose 'o' 'a' to 'Ć„' -+compose '0' 'A' to 'ƅ' -+compose '0' 'a' to 'Ć„' -+compose 'A' 'A' to 'ƅ' -+compose 'a' 'a' to 'Ć„' -+compose 'A' 'E' to 'Ɔ' -+compose 'a' 'e' to 'Ʀ' -+compose ',' 'C' to 'Ƈ' -+compose ',' 'c' to 'Ƨ' -+compose '`' 'E' to 'ƈ' -+compose '`' 'e' to 'ĆØ' -+compose '\'' 'E' to 'Ɖ' -+compose '\'' 'e' to 'Ć©' -+compose '^' 'E' to 'Ɗ' -+compose '^' 'e' to 'ĆŖ' -+compose '"' 'E' to 'Ƌ' -+compose '"' 'e' to 'Ć«' -+compose '`' 'I' to 'ƌ' -+compose '`' 'i' to 'Ƭ' -+compose '\'' 'I' to 'ƍ' -+compose '\'' 'i' to 'Ć­' -+compose '^' 'I' to 'Ǝ' -+compose '^' 'i' to 'Ć®' -+compose '"' 'I' to 'Ə' -+compose '"' 'i' to 'ĆÆ' -+compose '-' 'D' to 'Ɛ' -+compose '-' 'd' to 'Ć°' -+compose '~' 'N' to 'Ƒ' -+compose '~' 'n' to 'Ʊ' -+compose '`' 'O' to 'ƒ' -+compose '`' 'o' to 'Ć²' -+compose '\'' 'O' to 'Ɠ' -+compose '\'' 'o' to 'Ć³' -+compose '^' 'O' to 'Ɣ' -+compose '^' 'o' to 'Ć“' -+compose '~' 'O' to 'ƕ' -+compose '~' 'o' to 'Ƶ' -+compose '"' 'O' to 'Ɩ' -+compose '"' 'o' to 'ƶ' -+compose '/' 'O' to 'Ƙ' -+compose '/' 'o' to 'Ćø' -+compose '`' 'U' to 'ƙ' -+compose '`' 'u' to 'Ć¹' -+compose '\'' 'U' to 'ƚ' -+compose '\'' 'u' to 'Ćŗ' -+compose '^' 'U' to 'ƛ' -+compose '^' 'u' to 'Ć»' -+compose '"' 'U' to 'Ɯ' -+compose '"' 'u' to 'Ć¼' -+compose '\'' 'Y' to 'Ɲ' -+compose '\'' 'y' to 'Ć½' -+compose 'T' 'H' to 'ƞ' -+compose 't' 'h' to 'Ć¾' -+compose 's' 's' to 'Ɵ' -+compose '"' 'y' to 'Ćæ' -+compose 's' 'z' to 'Ɵ' -+compose 'i' 'j' to 'Ćæ' -diff -urN linux-2.4.26/drivers/char/generic_serial.c linux-2.4.26-vrs1/drivers/char/generic_serial.c ---- linux-2.4.26/drivers/char/generic_serial.c 2002-11-28 23:53:12.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/char/generic_serial.c 2004-01-14 21:32:25.000000000 +0000 -@@ -883,6 +883,9 @@ - if(!memcmp(tiosp->c_cc, old_termios->c_cc, NCC)) printk("c_cc changed\n"); - } - -+ /* -+ * should be using tty_get_baud_rate() here -- rmk -+ */ - baudrate = tiosp->c_cflag & CBAUD; - if (baudrate & CBAUDEX) { - baudrate &= ~CBAUDEX; -@@ -957,6 +960,11 @@ - unsigned long flags; - unsigned long page; - -+ /* -+ * Do we expect to allocate tmp_buf from an interrupt routine? -+ * If not, then save_flags() cli() and restore_flags() are -+ * redundant here and should be replaced by a semaphore. -- rmk -+ */ - save_flags (flags); - if (!tmp_buf) { - page = get_free_page(GFP_KERNEL); -@@ -976,6 +984,11 @@ - if (port->flags & ASYNC_INITIALIZED) - return 0; - -+ /* -+ * Do we expect to allocate xmit_buf from an interrupt routine? -+ * If not, then save_flags() cli() and restore_flags() are -+ * redundant here and should be replaced by a semaphore. -- rmk -+ */ - if (!port->xmit_buf) { - /* We may sleep in get_free_page() */ - unsigned long tmp; -@@ -1016,7 +1029,7 @@ - struct serial_struct sio; - - if (copy_from_user(&sio, sp, sizeof(struct serial_struct))) -- return(-EFAULT); -+ return -EFAULT; - - if (!capable(CAP_SYS_ADMIN)) { - if ((sio.baud_base != port->baud_base) || -diff -urN linux-2.4.26/drivers/char/keyboard.c linux-2.4.26-vrs1/drivers/char/keyboard.c ---- linux-2.4.26/drivers/char/keyboard.c 2003-11-28 18:26:20.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/char/keyboard.c 2004-02-11 01:12:05.000000000 +0000 -@@ -14,13 +14,17 @@ - * `Sticky' modifier keys, 951006. - * - * 11-11-96: SAK should now work in the raw mode (Martin Mares) -- * -+ * - * Modified to provide 'generic' keyboard support by Hamish Macdonald - * Merge with the m68k keyboard driver and split-off of the PC low-level - * parts by Geert Uytterhoeven, May 1997 - * - * 27-05-97: Added support for the Magic SysRq Key (Martin Mares) - * 30-07-98: Dead keys redone, aeb@cwi.nl. -+ * -+ * 04-04-1998: Added keyboard autorepeat support (some keyboards don't -+ * autorepeat, and some keyboard changers interfere with keyboard -+ * autorepeat settings). - Russell King (rmk@arm.linux.org.uk) - */ - - #include -@@ -30,6 +34,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -61,6 +66,14 @@ - #define KBD_DEFLOCK 0 - #endif - -+/* -+ * Default autorepeat settings. -+ * DEFAULT_REPEAT_TIMEOUT is the timeout from the keypress to the first repeat -+ * DEFAULT_REPEAT_INTERVAL is the timeout between successive repeats -+ */ -+#define DEFAULT_REPEAT_TIMEOUT HZ*300/1000 -+#define DEFAULT_REPEAT_INTERVAL HZ*30/1000 -+ - void (*kbd_ledfunc)(unsigned int led); - EXPORT_SYMBOL(handle_scancode); - EXPORT_SYMBOL(kbd_ledfunc); -@@ -82,21 +95,25 @@ - static unsigned long key_down[256/BITS_PER_LONG]; - - static int dead_key_next; --/* -+/* - * In order to retrieve the shift_state (for the mouse server), either -- * the variable must be global, or a new procedure must be created to -+ * the variable must be global, or a new procedure must be created to - * return the value. I chose the former way. - */ - int shift_state; - static int npadch = -1; /* -1 or number assembled on pad */ - static unsigned char diacr; - static char rep; /* flag telling character repeat */ -+static int kbd_repeatkeycode= -1; -+static int kbd_repeattimeout = DEFAULT_REPEAT_TIMEOUT; -+static int kbd_repeatinterval= DEFAULT_REPEAT_INTERVAL; - struct kbd_struct kbd_table[MAX_NR_CONSOLES]; - static struct tty_struct **ttytab; - static struct kbd_struct * kbd = kbd_table; - static struct tty_struct * tty; - static unsigned char prev_scancode; - -+static void kbd_processkeycode(unsigned char scancode, char up_flag, int autorepeat); - void compute_shiftstate(void); - - typedef void (*k_hand)(unsigned char value, char up_flag); -@@ -163,7 +180,8 @@ - * string, and in both cases we might assume that it is - * in utf-8 already. - */ --void to_utf8(ushort c) { -+void to_utf8(ushort c) -+{ - if (c < 0x80) - put_queue(c); /* 0******* */ - else if (c < 0x800) { -@@ -182,17 +200,23 @@ - * Translation of escaped scancodes to keycodes. - * This is now user-settable (for machines were it makes sense). - */ -- - int setkeycode(unsigned int scancode, unsigned int keycode) - { -- return kbd_setkeycode(scancode, keycode); -+ return kbd_setkeycode(scancode, keycode); - } - - int getkeycode(unsigned int scancode) - { -- return kbd_getkeycode(scancode); -+ return kbd_getkeycode(scancode); - } - -+static void key_callback(unsigned long nr); -+ -+static struct timer_list key_autorepeat_timer = -+{ -+ function: key_callback -+}; -+ - void handle_scancode(unsigned char scancode, int down) - { - unsigned char keycode; -@@ -201,6 +225,7 @@ - char have_keycode; - - pm_access(pm_kbd); -+ - add_keyboard_randomness(scancode | up_flag); - - tty = ttytab? ttytab[fg_console]: NULL; -@@ -223,15 +248,15 @@ - if (raw_mode) { - /* - * The following is a workaround for hardware -- * which sometimes send the key release event twice -+ * which sometimes send the key release event twice - */ - unsigned char next_scancode = scancode|up_flag; - if (have_keycode && up_flag && next_scancode==prev_scancode) { - /* unexpected 2nd release event */ - } else { -- /* -+ /* - * Only save previous scancode if it was a key-up -- * and had a single-byte scancode. -+ * and had a single-byte scancode. - */ - if (!have_keycode) - prev_scancode = 1; -@@ -256,12 +281,35 @@ - * return the keycode if in MEDIUMRAW mode. - */ - -+ kbd_processkeycode(keycode, up_flag, 0); -+ -+out: -+ do_poke_blanked_console = 1; -+ schedule_console_callback(); -+} -+ -+static void -+kbd_processkeycode(unsigned char keycode, char up_flag, int autorepeat) -+{ -+ char raw_mode = (kbd->kbdmode == VC_RAW); -+ - if (up_flag) { - rep = 0; - if(!test_and_clear_bit(keycode, key_down)) - up_flag = kbd_unexpected_up(keycode); -- } else -+ } else { - rep = test_and_set_bit(keycode, key_down); -+ /* If the keyboard autorepeated for us, ignore it. -+ * We do our own autorepeat processing. -+ */ -+ if (rep && !autorepeat) -+ return; -+ } -+ -+ if (kbd_repeatkeycode == keycode || !up_flag || raw_mode) { -+ kbd_repeatkeycode = -1; -+ del_timer(&key_autorepeat_timer); -+ } - - #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ - if (keycode == SYSRQ_KEY) { -@@ -275,6 +323,23 @@ - } - #endif - -+ /* -+ * Calculate the next time when we have to do some autorepeat -+ * processing. Note that we do not do autorepeat processing -+ * while in raw mode but we do do autorepeat processing in -+ * medium raw mode. -+ */ -+ if (!up_flag && !raw_mode) { -+ kbd_repeatkeycode = keycode; -+ if (vc_kbd_mode(kbd, VC_REPEAT)) { -+ if (rep) -+ key_autorepeat_timer.expires = jiffies + kbd_repeatinterval; -+ else -+ key_autorepeat_timer.expires = jiffies + kbd_repeattimeout; -+ add_timer(&key_autorepeat_timer); -+ } -+ } -+ - if (kbd->kbdmode == VC_MEDIUMRAW) { - /* soon keycodes will require more than one byte */ - put_queue(keycode + up_flag); -@@ -343,9 +408,24 @@ - #endif - } - } -+ rep = 0; - out: -- do_poke_blanked_console = 1; -- schedule_console_callback(); -+} -+ -+/* -+ * This clears the key down arrays when the keyboard is reset. On -+ * keyboard reset, this must be called before any keycodes are -+ * received. -+ */ -+void kbd_reset_kdown(void) -+{ -+ int i; -+ -+ for (i = 0; i < NR_SHIFT; i++) -+ k_down[i] = 0; -+ for (i = 0; i < SIZE(key_down); i++) -+ key_down[i] = 0; -+ shift_state = 0; - } - - void put_queue(int ch) -@@ -453,7 +533,7 @@ - static void decr_console(void) - { - int i; -- -+ - for (i = fg_console-1; i != fg_console; i--) { - if (i == -1) - i = MAX_NR_CONSOLES-1; -@@ -531,7 +611,7 @@ - { - } - --static void do_null() -+static void do_null(void) - { - compute_shiftstate(); - } -@@ -646,8 +726,8 @@ - - static void do_pad(unsigned char value, char up_flag) - { -- static const char *pad_chars = "0123456789+-*/\015,.?()"; -- static const char *app_map = "pqrstuvwxylSRQMnnmPQ"; -+ static const char *pad_chars = "0123456789+-*/\015,.?()#"; -+ static const char *app_map = "pqrstuvwxylSRQMnnmPQS"; - - if (up_flag) - return; /* no action, if this is a key release */ -@@ -748,9 +828,10 @@ - } - } - --/* called after returning from RAW mode or when changing consoles - -- recompute k_down[] and shift_state from key_down[] */ --/* maybe called when keymap is undefined, so that shiftkey release is seen */ -+/* Called after returning from RAW mode or when changing consoles - -+ * recompute k_down[] and shift_state from key_down[] -+ * Maybe called when keymap is undefined so that shift key release is seen -+ */ - void compute_shiftstate(void) - { - int i, j, k, sym, val; -@@ -829,19 +910,22 @@ - } - - /* -- * The leds display either (i) the status of NumLock, CapsLock, ScrollLock, -- * or (ii) whatever pattern of lights people want to show using KDSETLED, -- * or (iii) specified bits of specified words in kernel memory. -+ * The leds display either -+ * (i) the status of NumLock, CapsLock, ScrollLock, or -+ * (ii) whatever pattern of lights people want to show using KDSETLED, or -+ * (iii) specified bits of specified words in kernel memory. - */ - - static unsigned char ledstate = 0xff; /* undefined */ - static unsigned char ledioctl; - --unsigned char getledstate(void) { -+unsigned char getledstate(void) -+{ - return ledstate; - } - --void setledstate(struct kbd_struct *kbd, unsigned int led) { -+void setledstate(struct kbd_struct *kbd, unsigned int led) -+{ - if (!(led & ~7)) { - ledioctl = led; - kbd->ledmode = LED_SHOW_IOCTL; -@@ -857,7 +941,8 @@ - } ledptrs[3]; - - void register_leds(int console, unsigned int led, -- unsigned int *addr, unsigned int mask) { -+ unsigned int *addr, unsigned int mask) -+{ - struct kbd_struct *kbd = kbd_table + console; - if (led < 3) { - ledptrs[led].addr = addr; -@@ -868,7 +953,8 @@ - kbd->ledmode = LED_SHOW_FLAGS; - } - --static inline unsigned char getleds(void){ -+static inline unsigned char getleds(void) -+{ - struct kbd_struct *kbd = kbd_table + fg_console; - unsigned char leds; - -@@ -915,6 +1001,19 @@ - { - unsigned char leds = getleds(); - -+ if (rep && kbd_repeatkeycode != -1) { -+ tty = ttytab? ttytab[fg_console]: NULL; -+ kbd = kbd_table + fg_console; -+ -+ /* This prevents the kbd_key routine from being called -+ * twice, once by this BH, and once by the interrupt -+ * routine. -+ */ -+ kbd_disable_irq(); -+ kbd_processkeycode(kbd_repeatkeycode, 0, 1); -+ kbd_enable_irq(); -+ } -+ - if (leds != ledstate) { - ledstate = leds; - kbd_leds(leds); -@@ -937,6 +1036,12 @@ - tasklet_enable(&keyboard_tasklet); - } - -+static void key_callback(unsigned long nr) -+{ -+ rep = 1; -+ tasklet_schedule(&keyboard_tasklet); -+} -+ - typedef void (pm_kbd_func) (void); - - pm_callback pm_kbd_request_override = NULL; -@@ -953,7 +1058,7 @@ - kbd0.slockstate = 0; - kbd0.modeflags = KBD_DEFMODE; - kbd0.kbdmode = VC_XLATE; -- -+ - for (i = 0 ; i < MAX_NR_CONSOLES ; i++) - kbd_table[i] = kbd0; - -@@ -963,7 +1068,7 @@ - - tasklet_enable(&keyboard_tasklet); - tasklet_schedule(&keyboard_tasklet); -- -+ - pm_kbd = pm_register(PM_SYS_DEV, PM_SYS_KBC, pm_kbd_request_override); - - return 0; -diff -urN linux-2.4.26/drivers/char/mem.c linux-2.4.26-vrs1/drivers/char/mem.c ---- linux-2.4.26/drivers/char/mem.c 2003-11-28 18:26:20.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/char/mem.c 2004-01-14 21:39:01.000000000 +0000 -@@ -27,9 +27,6 @@ - #include - #include - --#ifdef CONFIG_I2C --extern int i2c_init_all(void); --#endif - #ifdef CONFIG_FB - extern void fbmem_init(void); - #endif -@@ -740,9 +737,6 @@ - printk("unable to get major %d for memory devs\n", MEM_MAJOR); - memory_devfs_register(); - rand_initialize(); --#ifdef CONFIG_I2C -- i2c_init_all(); --#endif - #if defined (CONFIG_FB) - fbmem_init(); - #endif -diff -urN linux-2.4.26/drivers/char/omaha-rtc.c linux-2.4.26-vrs1/drivers/char/omaha-rtc.c ---- linux-2.4.26/drivers/char/omaha-rtc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/omaha-rtc.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,566 @@ -+/* -+ * (C) ARM Limited 2002. -+ * -+ * Real Time Clock interface for Linux on Omaha -+ * -+ * Based on sa1100-rtc.c -+ * -+ * Copyright (c) 2000 Nils Faerber -+ * -+ * Based on rtc.c by Paul Gortmaker -+ * Date/time conversion routines taken from arch/arm/kernel/time.c -+ * by Linus Torvalds and Russell King -+ * and the GNU C Library -+ * ( ... I love the GPL ... just take what you need! ;) -+ * -+ * 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. -+ * -+ * 1.00 2001-06-08 Nicolas Pitre -+ * - added periodic timer capability using OSMR1 -+ * - flag compatibility with other RTC chips -+ * - permission checks for ioctls -+ * - major cleanup, partial rewrite -+ * -+ * 0.03 2001-03-07 CIH -+ * - Modify the bug setups RTC clock. -+ * -+ * 0.02 2001-02-27 Nils Faerber -+ * - removed mktime(), added alarm irq clear -+ * -+ * 0.01 2000-10-01 Nils Faerber -+ * - initial release -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DRIVER_VERSION "1.00" -+ -+#define epoch 1970 -+ -+#define TIMER_FREQ 3686400 -+ -+#define RTC_DEF_DIVIDER 32768 - 1 -+#define RTC_DEF_TRIM 0 -+ -+/* Those are the bits from a classic RTC we want to mimic */ -+#define RTC_IRQF 0x80 /* any of the following 3 is active */ -+#define RTC_PF 0x40 -+#define RTC_AF 0x20 -+#define RTC_UF 0x10 -+ -+// bitdefs for rtc registers -+#define TICNT_ENABLE 0x80 // Enable tick interrupt -+#define TICNT_PERIOD 0x7F // Divisor required for 1Hz tick -+#define RTC_ENABLE 0x1 // Enable bit for RTC -+ -+static unsigned long rtc_status; -+static unsigned long rtc_irq_data; -+static unsigned long rtc_freq = 1024; -+ -+static struct fasync_struct *rtc_async_queue; -+static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); -+ -+extern spinlock_t rtc_lock; -+ -+static const unsigned char days_in_mo[] = -+ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; -+ -+#define is_leap(year) \ -+ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) -+ -+// all the alarm and rtc registers -+static volatile unsigned int almsec = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_ALMSEC); -+static volatile unsigned int almmin = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_ALMMIN); -+static volatile unsigned int almhour = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_ALMHOUR); -+static volatile unsigned int almday = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_ALMDAY); -+static volatile unsigned int almmon = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_ALMMON); -+static volatile unsigned int almyear = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_ALMYEAR); -+ -+static volatile unsigned int bcdsec = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_BCDSEC); -+static volatile unsigned int bcdmin = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_BCDMIN); -+static volatile unsigned int bcdhour = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_BCDHOUR); -+static volatile unsigned int bcdday = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_BCDDAY); -+static volatile unsigned int bcddate = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_BCDDATE); -+static volatile unsigned int bcdmon = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_BCDMON); -+static volatile unsigned int bcdyear = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_BCDYEAR); -+ -+/* -+ * Converts seconds since 1970-01-01 00:00:00 to Gregorian date. -+ */ -+ -+static void decodetime (unsigned long t, struct rtc_time *tval) -+{ -+ long days, month, year, rem; -+ -+ days = t / 86400; -+ rem = t % 86400; -+ tval->tm_hour = rem / 3600; -+ rem %= 3600; -+ tval->tm_min = rem / 60; -+ tval->tm_sec = rem % 60; -+ tval->tm_wday = (4 + days) % 7; -+ -+#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) -+ -+ year = epoch; -+ while (days >= (365 + is_leap(year))) { -+ unsigned long yg = year + days / 365; -+ days -= ((yg - year) * 365 -+ + LEAPS_THRU_END_OF (yg - 1) -+ - LEAPS_THRU_END_OF (year - 1)); -+ year = yg; -+ } -+ tval->tm_year = year - 1900; -+ tval->tm_yday = days + 1; -+ -+ month = 0; -+ if (days >= 31) { -+ days -= 31; -+ month++; -+ if (days >= (28 + is_leap(year))) { -+ days -= (28 + is_leap(year)); -+ month++; -+ while (days >= days_in_mo[month]) { -+ days -= days_in_mo[month]; -+ month++; -+ } -+ } -+ } -+ tval->tm_mon = month; -+ tval->tm_mday = days + 1; -+} -+ -+// Get alarm time in seconds -+static unsigned long get_alarm_time(void) -+{ -+ int sec, min,hour,date,mon,year; -+ -+ // Read data from h/w -+ year = __raw_readb(almyear); -+ mon = __raw_readb(almmon); -+ date = __raw_readb(almday); -+ hour = __raw_readb(almhour); -+ min = __raw_readb(almmin); -+ sec = __raw_readb(almsec); -+ -+ // convert all the data into binary -+ year = BCD_TO_BIN(year); -+ mon = BCD_TO_BIN(mon); -+ date = BCD_TO_BIN(date); -+ hour = BCD_TO_BIN(hour); -+ min = BCD_TO_BIN(min); -+ sec = BCD_TO_BIN(sec); -+ -+ // convert year to 19xx or 20xx as appropriate -+ if (year > 69) -+ year += 1900; -+ else -+ year += 2000; -+ -+ // Now calculate number of seconds since time began... -+ return mktime(year,mon,date,hour,min,sec); -+} -+ -+// Get rtc time in seconds -+static unsigned long get_rtc_time(void) -+{ -+ int sec,min,hour,day,date,mon,year; -+ -+ // Read data from h/w -+ year = __raw_readb(bcdyear); -+ mon = __raw_readb(bcdmon); -+ date = __raw_readb(bcdday); -+ day = __raw_readb(bcddate); -+ hour = __raw_readb(bcdhour); -+ min = __raw_readb(bcdmin); -+ sec = __raw_readb(bcdsec); -+ -+ // convert all the data into binary -+ year = BCD_TO_BIN(year); -+ mon = BCD_TO_BIN(mon); -+ date = BCD_TO_BIN(date); -+ day = BCD_TO_BIN(day); -+ hour = BCD_TO_BIN(hour); -+ min = BCD_TO_BIN(min); -+ sec = BCD_TO_BIN(sec); -+ -+ // convert year to 19xx or 20xx as appropriate -+ if (year > 69) -+ year += 1900; -+ else -+ year += 2000; -+ -+ // Now calculate number of seconds since time began... -+ return mktime(year,mon,date,hour,min,sec); -+} -+ -+/* Sets time of alarm */ -+static void set_alarm_time(struct rtc_time *tval) -+{ -+ -+ int sec,min,hour,day,mon,year; -+ -+ // Convert data from binary to 8-bit bcd -+ sec = BIN_TO_BCD(tval->tm_sec); -+ min = BIN_TO_BCD(tval->tm_min); -+ hour = BIN_TO_BCD(tval->tm_hour); -+ day = BIN_TO_BCD(tval->tm_mday); -+ mon = BIN_TO_BCD(tval->tm_mon); -+ -+ // Year is special -+ year = tval->tm_year; -+ if(year > 1999) -+ year -=2000; -+ else -+ year -=1900; -+ -+ year = BIN_TO_BCD(year); -+ -+ // Write all the registers -+ __raw_writeb(year,almyear); -+ __raw_writeb(mon,almmon); -+ __raw_writeb(day,almday); -+ __raw_writeb(hour,almhour); -+ __raw_writeb(min,almmin); -+ __raw_writeb(sec,almsec); -+} -+ -+/* Sets time of alarm */ -+static void set_rtc_time(struct rtc_time *tval) -+{ -+ -+ int sec,min,hour,day,date,mon,year; -+ -+ // Convert data from binary to 8-bit bcd -+ sec = BIN_TO_BCD(tval->tm_sec); -+ min = BIN_TO_BCD(tval->tm_min); -+ hour = BIN_TO_BCD(tval->tm_hour); -+ day = BIN_TO_BCD(tval->tm_mday); -+ date = BIN_TO_BCD(tval->tm_wday); -+ mon = BIN_TO_BCD(tval->tm_mon); -+ -+ // Year is special -+ year = tval->tm_year; -+ if(year > 1999) -+ year -=2000; -+ else -+ year -=1900; -+ -+ year = BIN_TO_BCD(year); -+ -+ // Write all the registers -+ __raw_writeb(year,bcdyear); -+ __raw_writeb(mon,bcdmon); -+ __raw_writeb(date,bcddate); -+ __raw_writeb(day,bcdday); -+ __raw_writeb(hour,bcdhour); -+ __raw_writeb(min,bcdmin); -+ __raw_writeb(sec,bcdsec); -+} -+ -+static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ /* update irq data & counter */ -+ rtc_irq_data += 0x100; -+ -+ /* wake up waiting process */ -+ wake_up_interruptible(&rtc_wait); -+ kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); -+} -+ -+static int rtc_open(struct inode *inode, struct file *file) -+{ -+ if (test_and_set_bit (1, &rtc_status)) -+ return -EBUSY; -+ MOD_INC_USE_COUNT; -+ rtc_irq_data = 0; -+ return 0; -+} -+ -+static int rtc_release(struct inode *inode, struct file *file) -+{ -+ rtc_status = 0; -+ MOD_DEC_USE_COUNT; -+ return 0; -+} -+ -+static int rtc_fasync (int fd, struct file *filp, int on) -+{ -+ return fasync_helper (fd, filp, on, &rtc_async_queue); -+} -+ -+static unsigned int rtc_poll(struct file *file, poll_table *wait) -+{ -+ poll_wait (file, &rtc_wait, wait); -+ return (rtc_irq_data) ? 0 : POLLIN | POLLRDNORM; -+} -+ -+static loff_t rtc_llseek(struct file *file, loff_t offset, int origin) -+{ -+ return -ESPIPE; -+} -+ -+ssize_t rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long data; -+ ssize_t retval; -+ -+ if (count < sizeof(unsigned long)) -+ return -EINVAL; -+ -+ add_wait_queue(&rtc_wait, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ for (;;) { -+ spin_lock_irq (&rtc_lock); -+ data = rtc_irq_data; -+ if (data != 0) { -+ rtc_irq_data = 0; -+ break; -+ } -+ spin_unlock_irq (&rtc_lock); -+ -+ if (file->f_flags & O_NONBLOCK) { -+ retval = -EAGAIN; -+ goto out; -+ } -+ -+ if (signal_pending(current)) { -+ retval = -ERESTARTSYS; -+ goto out; -+ } -+ -+ schedule(); -+ } -+ -+ spin_unlock_irq (&rtc_lock); -+ -+ data -= 0x100; /* the first IRQ wasn't actually missed */ -+ -+ retval = put_user(data, (unsigned long *)buf); -+ if (!retval) -+ retval = sizeof(unsigned long); -+ -+out: -+ set_current_state(TASK_RUNNING); -+ remove_wait_queue(&rtc_wait, &wait); -+ return retval; -+} -+ -+static int rtc_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ volatile unsigned int rtcalm = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_RTCALM); -+ volatile unsigned int ticnt = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_TICINT); -+ -+ struct rtc_time tm, tm2; -+ switch (cmd) { -+ case RTC_AIE_OFF: -+ spin_lock_irq(&rtc_lock); -+ __raw_writel(0,rtcalm); -+ rtc_irq_data = 0; -+ spin_unlock_irq(&rtc_lock); -+ return 0; -+ case RTC_AIE_ON: -+ spin_lock_irq(&rtc_lock); -+ __raw_writel(0x7F,rtcalm); -+ rtc_irq_data = 0; -+ spin_unlock_irq(&rtc_lock); -+ return 0; -+ case RTC_UIE_OFF: -+ spin_lock_irq(&rtc_lock); -+ __raw_writel(~TICNT_ENABLE,ticnt); -+ rtc_irq_data = 0; -+ spin_unlock_irq(&rtc_lock); -+ return 0; -+ case RTC_UIE_ON: -+ spin_lock_irq(&rtc_lock); -+ __raw_writel(TICNT_ENABLE|TICNT_PERIOD,ticnt); -+ rtc_irq_data = 0; -+ spin_unlock_irq(&rtc_lock); -+ return 0; -+ case RTC_PIE_OFF: -+ spin_lock_irq(&rtc_lock); -+ // Periodic int not available -+ rtc_irq_data = 0; -+ spin_unlock_irq(&rtc_lock); -+ return 0; -+ case RTC_PIE_ON: -+ spin_lock_irq(&rtc_lock); -+ // Periodic int not available -+ rtc_irq_data = 0; -+ spin_unlock_irq(&rtc_lock); -+ return 0; -+ case RTC_ALM_READ: -+ decodetime(get_alarm_time(),&tm); -+ break; -+ case RTC_ALM_SET: -+ if (copy_from_user (&tm2, (struct rtc_time*)arg, sizeof (tm2))) -+ return -EFAULT; -+ decodetime(get_rtc_time(),&tm); -+ if ((unsigned)tm2.tm_hour < 24) -+ tm.tm_hour = tm2.tm_hour; -+ if ((unsigned)tm2.tm_min < 60) -+ tm.tm_min = tm2.tm_min; -+ if ((unsigned)tm2.tm_sec < 60) -+ tm.tm_sec = tm2.tm_sec; -+ -+ // Munge (as per sa1100) -+ tm.tm_year+=1900; -+ tm.tm_mon+=1; -+ -+ // Set the alarm -+ set_alarm_time(&tm); -+ return 0; -+ case RTC_RD_TIME: -+ decodetime (get_rtc_time(), &tm); -+ break; -+ case RTC_SET_TIME: -+ if (!capable(CAP_SYS_TIME)) -+ return -EACCES; -+ if (copy_from_user (&tm, (struct rtc_time*)arg, sizeof (tm))) -+ return -EFAULT; -+ tm.tm_year += 1900; -+ if (tm.tm_year < epoch || (unsigned)tm.tm_mon >= 12 || -+ tm.tm_mday < 1 || tm.tm_mday > (days_in_mo[tm.tm_mon] + -+ (tm.tm_mon == 1 && is_leap(tm.tm_year))) || -+ (unsigned)tm.tm_hour >= 24 || -+ (unsigned)tm.tm_min >= 60 || -+ (unsigned)tm.tm_sec >= 60) -+ return -EINVAL; -+ tm.tm_mon +=1; // wierd: same as sa1100 though (gets month wrong otherwise!) -+ set_rtc_time(&tm); -+ return 0; -+ case RTC_IRQP_READ: -+ return put_user(rtc_freq, (unsigned long *)arg); -+ case RTC_IRQP_SET: -+ if (arg < 1 || arg > TIMER_FREQ) -+ return -EINVAL; -+ if ((arg > 64) && (!capable(CAP_SYS_RESOURCE))) -+ return -EACCES; -+ rtc_freq = arg; -+ return 0; -+ case RTC_EPOCH_READ: -+ return put_user (epoch, (unsigned long *)arg); -+ default: -+ return -EINVAL; -+ } -+ return copy_to_user ((void *)arg, &tm, sizeof (tm)) ? -EFAULT : 0; -+} -+ -+static struct file_operations rtc_fops = { -+ .owner = THIS_MODULE, -+ .llseek = rtc_llseek, -+ .read = rtc_read, -+ .poll = rtc_poll, -+ .ioctl = rtc_ioctl, -+ .open = rtc_open, -+ .release = rtc_release, -+ .fasync = rtc_fasync, -+}; -+ -+static struct miscdevice omahartc_miscdev = { -+ .minor = RTC_MINOR, -+ .name = "rtc", -+ .fops = &rtc_fops, -+}; -+ -+static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) -+{ -+ char *p = page; -+ int len; -+ struct rtc_time tm; -+ -+ decodetime (get_rtc_time(), &tm); -+ p += sprintf(p, "rtc_time\t: %02d:%02d:%02d\n" -+ "rtc_date\t: %04d-%02d-%02d\n" -+ "rtc_epoch\t: %04d\n", -+ tm.tm_hour, tm.tm_min, tm.tm_sec, -+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); -+ decodetime (get_alarm_time(), &tm); -+ p += sprintf(p, "alrm_time\t: %02d:%02d:%02d\n" -+ "alrm_date\t: %04d-%02d-%02d\n", -+ tm.tm_hour, tm.tm_min, tm.tm_sec, -+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); -+ p += sprintf(p, "periodic_freq\t: %ld\n", rtc_freq); -+ -+ len = (p - page) - off; -+ if (len < 0) -+ len = 0; -+ -+ *eof = (len <= count) ? 1 : 0; -+ *start = page + off; -+ -+ return len; -+} -+ -+static int __init rtc_init(void) -+{ -+ volatile unsigned int ticnt = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_TICINT); -+ volatile unsigned int rtccon = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_RTCCON); -+ int ret; -+ -+ misc_register (&omahartc_miscdev); -+ create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL); -+ -+ // Enable RTC -+ __raw_writel(RTC_ENABLE,rtccon); -+ -+ // Acquire 1Hz timer -+ ret = request_irq (OMAHA_INT_TICK, rtc_interrupt, SA_INTERRUPT, "rtc 1Hz", NULL); -+ if (ret) { -+ printk (KERN_ERR "rtc: IRQ %d already in use.\n", OMAHA_INT_TICK); -+ goto IRQ_TICK_failed; -+ } -+ -+ // Acquire RTC (Alarm interrupt) -+ ret = request_irq (OMAHA_INT_RTC, rtc_interrupt, SA_INTERRUPT, "rtc Alrm", NULL); -+ if (ret) { -+ printk (KERN_ERR "rtc: IRQ %d already in use.\n", OMAHA_INT_RTC); -+ goto IRQ_RTC_failed; -+ } -+ -+ printk (KERN_INFO "Omaha Real Time Clock driver v" DRIVER_VERSION "\n"); -+ -+ // Program tick interrupt divisor to generate real 1Hz clock and enable the interrupt -+ __raw_writeb(TICNT_ENABLE|TICNT_PERIOD,ticnt); -+ -+ return 0; -+ -+IRQ_TICK_failed: -+ free_irq (OMAHA_INT_TICK, NULL); -+IRQ_RTC_failed: -+ free_irq(OMAHA_INT_RTC, NULL); -+ remove_proc_entry ("driver/rtc", NULL); -+ misc_deregister (&omahartc_miscdev); -+ return ret; -+} -+ -+static void __exit rtc_exit(void) -+{ -+ free_irq (OMAHA_INT_TICK, NULL); -+ remove_proc_entry ("driver/rtc", NULL); -+ misc_deregister (&omahartc_miscdev); -+} -+ -+module_init(rtc_init); -+module_exit(rtc_exit); -+ -+MODULE_AUTHOR("ARM Limited "); -+MODULE_DESCRIPTION("Omaha Realtime Clock Driver (RTC)"); -+EXPORT_NO_SYMBOLS; -diff -urN linux-2.4.26/drivers/char/omaha_wdt.c linux-2.4.26-vrs1/drivers/char/omaha_wdt.c ---- linux-2.4.26/drivers/char/omaha_wdt.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/omaha_wdt.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,193 @@ -+/* -+ * Watchdog driver for the Omaha -+ * (C) ARM Limited 2002. -+ * -+ * Based on sa1100_wdt.c -+ * -+ * (c) Copyright 2000 Oleg Drokin -+ * Based on SoftDog driver by Alan Cox -+ * -+ * 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. -+ * -+ * Neither Oleg Drokin nor iXcelerator.com admit liability nor provide -+ * warranty for any of this software. This material is provided -+ * "AS-IS" and at no charge. -+ * -+ * (c) Copyright 2000 Oleg Drokin -+ * -+ * 27/11/2000 Initial release -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define TIMER_MARGIN 8 /* (secs) Default is 1 minute */ -+#define WT_TPS 7812 /* Watchdog ticks per second. */ -+#define WT_ENABLE 0x21 // Enable bits for watchdog -+#define WT_CLKSEL_128 0x18 // Select 1/128 divider -+ -+static int omaha_margin = TIMER_MARGIN; /* in seconds */ -+static int omahawdt_users; -+static int pre_margin; -+#ifdef MODULE -+MODULE_PARM(omaha_margin,"i"); -+#endif -+ -+/* -+ * Allow only one person to hold it open -+ */ -+ -+static int omahadog_open(struct inode *inode, struct file *file) -+{ -+ volatile unsigned int wtcon = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_WTCON); -+ volatile unsigned int wtdat = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_WTDAT); -+ volatile unsigned int wtcnt = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_WTCNT); -+ unsigned int tmp; -+ -+ if(test_and_set_bit(1,&omahawdt_users)) -+ return -EBUSY; -+ MOD_INC_USE_COUNT; -+ /* Activate omaha Watchdog timer */ -+ -+ /* Assume that uhal has set up pre-scaler according -+ * to the system clock frequency (don't change it!) -+ * -+ * Ie. all counting occurs at 1MHz / 128 = 7812.5Hz -+ * -+ * Since we have 16-bit counter, maximum period is -+ * 65536/7812.5 = 8.338608 seconds! -+ */ -+ -+ pre_margin = WT_TPS * omaha_margin; -+ -+ // Set count to the maximum -+ __raw_writel(pre_margin,wtcnt); -+ -+ // Set the clock division factor -+ tmp = __raw_readl(wtcon); -+ tmp |= WT_CLKSEL_128; -+ __raw_writel(tmp,wtcon); -+ -+ // Program an initial count into WTDAT -+ __raw_writel(0x8000,wtdat); -+ -+ // enable the watchdog -+ tmp = __raw_readl(wtcon); -+ tmp |= WT_ENABLE; -+ -+ __raw_writel(tmp,wtcon); -+ -+ return 0; -+} -+ -+static int omahadog_release(struct inode *inode, struct file *file) -+{ -+ volatile unsigned int wtcon = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_WTCON); -+ unsigned int tmp; -+ -+ /* -+ * Shut off the timer. -+ * Lock it in if it's a module and we defined ...NOWAYOUT -+ */ -+#ifndef CONFIG_WATCHDOG_NOWAYOUT -+ tmp = __raw_readl(wtcon); -+ tmp &= ~WT_ENABLE; -+ __raw_writel(tmp,wtcon); -+#endif -+ omahawdt_users = 0; -+ MOD_DEC_USE_COUNT; -+ return 0; -+} -+ -+static ssize_t omahadog_write(struct file *file, const char *data, size_t len, loff_t *ppos) -+{ -+ volatile unsigned int wtcnt = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_WTCNT); -+ -+ /* Can't seek (pwrite) on this device */ -+ if (ppos != &file->f_pos) -+ return -ESPIPE; -+ -+ /* Refresh timer. */ -+ if(len) { -+ __raw_writel(pre_margin,wtcnt); -+ return 1; -+ } -+ return 0; -+} -+ -+static int omahadog_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ volatile unsigned int wtdat = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_WTDAT); -+ static struct watchdog_info ident = { -+ identity: "omaha Watchdog", -+ }; -+ -+ switch(cmd){ -+ default: -+ return -ENOIOCTLCMD; -+ case WDIOC_GETSUPPORT: -+ return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)); -+ case WDIOC_GETSTATUS: -+ return put_user(0,(int *)arg); -+ case WDIOC_GETBOOTSTATUS: -+ return 0; -+ case WDIOC_KEEPALIVE: -+ __raw_writel(pre_margin,wtdat); -+ return 0; -+ } -+} -+ -+static struct file_operations omahadog_fops= -+{ -+ .owner = THIS_MODULE, -+ .write = omahadog_write, -+ .ioctl = omahadog_ioctl, -+ .open = omahadog_open, -+ .release = omahadog_release, -+}; -+ -+static struct miscdevice omahadog_miscdev= -+{ -+ .minor = WATCHDOG_MINOR, -+ .name = "omaha watchdog", -+ .fops = &omahadog_fops -+}; -+ -+static int __init omahadog_init(void) -+{ -+ int ret; -+ -+ ret = misc_register(&omahadog_miscdev); -+ -+ if (ret) -+ return ret; -+ -+ printk("Omaha Watchdog Timer: timer margin %d sec\n", omaha_margin); -+ -+ return 0; -+} -+ -+static void __exit omahadog_exit(void) -+{ -+ misc_deregister(&omahadog_miscdev); -+} -+ -+module_init(omahadog_init); -+module_exit(omahadog_exit); -diff -urN linux-2.4.26/drivers/char/pcmcia/Config.in linux-2.4.26-vrs1/drivers/char/pcmcia/Config.in ---- linux-2.4.26/drivers/char/pcmcia/Config.in 2002-11-28 23:53:12.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/char/pcmcia/Config.in 2004-01-14 21:32:25.000000000 +0000 -@@ -5,7 +5,13 @@ - mainmenu_option next_comment - comment 'PCMCIA character devices' - --dep_tristate 'PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS $CONFIG_SERIAL -+if [ "$CONFIG_SERIAL" = "y" -o "$CONFIG_SERIAL_8250" = "y" ]; then -+ dep_tristate 'PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS y -+else -+ if [ "$CONFIG_SERIAL" = "m" -o "$CONFIG_SERIAL_8250" = "m" ]; then -+ dep_tristate 'PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS m -+ fi -+fi - if [ "$CONFIG_PCMCIA_SERIAL_CS" = "y" ]; then - define_bool CONFIG_PCMCIA_CHRDEV y - fi -diff -urN linux-2.4.26/drivers/char/pcmcia/memory_cs.c linux-2.4.26-vrs1/drivers/char/pcmcia/memory_cs.c ---- linux-2.4.26/drivers/char/pcmcia/memory_cs.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/pcmcia/memory_cs.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,214 @@ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+static dev_info_t dev_info = "memory_cs"; -+static dev_link_t *dev_list; -+ -+struct memcs_dev { -+ dev_link_t link; -+ struct map_info map; -+}; -+ -+static __u8 mem_cs_read8(struct map_info *map, unsigned long ofs) -+{ -+ return readb(map->map_priv_1 + ofs); -+} -+ -+static __u16 mem_cs_read16(struct map_info *map, unsigned long ofs) -+{ -+ return readw(map->map_priv_1 + ofs); -+} -+ -+static __u32 mem_cs_read32(struct map_info *map, unsigned long ofs) -+{ -+ return readl(map->map_priv_1 + ofs); -+} -+ -+static void mem_cs_copy_from(struct map_info *map, void *to, unsigned long ofs, ssize_t size) -+{ -+ memcpy_fromio(to, map->map_priv_1 + ofs, size); -+} -+ -+static void mem_cs_write8(struct map_info *map, __u8 val, unsigned long ofs) -+{ -+ writeb(val, map->map_priv_1 + ofs); -+} -+ -+static void mem_cs_write16(struct map_info *map, __u16 val, unsigned long ofs) -+{ -+ writew(val, map->map_priv_1 + ofs); -+} -+ -+static void mem_cs_write32(struct map_info *map, __u32 val, unsigned long ofs) -+{ -+ writel(val, map->map_priv_1 + ofs); -+} -+ -+static void mem_cs_copy_to(struct map_info *map, unsigned long ofs, const void *to, ssize_t size) -+{ -+ memcpy_toio(map->map_priv_1 + ofs, from, size); -+} -+ -+static void mem_cs_release(u_long arg); -+ -+static void mem_cs_detach(dev_link_t *link) -+{ -+ del_timer(&link->release); -+ if (link->state & DEV_CONFIG) { -+ mem_cs_release((u_long)link); -+ if (link->state & DEV_STALE_CONFIG) { -+ link->state |= DEV_STALE_LINK; -+ return; -+ } -+ } -+ -+ if (link->handle) -+ CardServices(DeregisterClient, link->handle); -+ -+ kfree(link); -+} -+ -+static void mem_cs_release(u_long arg) -+{ -+ dev_link_t *link = (dev_link_t *)arg; -+ -+ link->dev = NULL; -+ if (link->win) { -+ CardServices(ReleaseWindow, link->win); -+ } -+ link->state &= ~DEV_CONFIG; -+ -+ if (link->state & DEV_STALE_LINK) -+ mem_cs_detach(link); -+} -+ -+static void mem_cs_config(dev_link_t *link) -+{ -+ struct memcs_dev *dev = link->priv; -+ cs_status_t status; -+ win_req_t req; -+ -+ link->state |= DEV_CONFIG; -+ -+ req.Attributes = word_width ? WIN_DATA_WIDTH_16 : WIN_DATA_WIDTH_8; -+ req.Base = 0; -+ req.Size = 0; -+ req.AccessSpeed = mem_speed; -+ -+ link->win = (window_handle_t)link->handle; -+ -+ CS_CHECK(RequestWindow, &link->win, &req); -+ -+ CS_CHECK(GetStatus, link->handle, &status); -+ -+ dev->map.buswidth = word_width ? 2 : 1; -+ dev->map.size = req.Size; -+ dev->map.map_priv_1 = ioremap(req.Base, req.Size); -+} -+ -+static int -+mem_cs_event(event_t event, int priority, event_callback_args_t *args) -+{ -+ dev_link_t *link = args->client_data; -+ -+ switch (event) { -+ case CS_EVENT_CARD_REMOVAL: -+ link->state &= ~DEV_PRESENT; -+ if (link->state & DEV_CONFIG) -+ mod_timer(&link->release, jiffies + HZ/20); -+ break; -+ -+ case CS_EVENT_CARD_INSERTION: -+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; -+ mem_cs_config(link); -+ break; -+ } -+ return 0; -+} -+ -+static dev_link_t *mem_cs_attach(void) -+{ -+ struct memcs_dev *dev; -+ client_reg_t clnt; -+ -+ dev = kmalloc(sizeof(*dev), GFP_KERNEL); -+ if (dev) { -+ memset(dev, 0, sizeof(*dev)); -+ -+ dev->map.read8 = mem_cs_read8; -+ dev->map.read16 = mem_cs_read16; -+ dev->map.read32 = mem_cs_read32; -+ dev->map.copy_from = mem_cs_copy_from; -+ dev->map.write8 = mem_cs_write8; -+ dev->map.write16 = mem_cs_write16; -+ dev->map.write32 = mem_cs_write32; -+ dev->map.copy_to = mem_cs_copy_to; -+ -+ dev->link.release.function = &mem_cs_release; -+ dev->link.release.data = (u_long)link; -+ dev->link.priv = dev; -+ -+ dev->link.next = dev_list; -+ dev_list = &dev->link; -+ -+ clnt.dev_info = &dev_info; -+ clnt.Attributes = INOF_IO_CLIENT | INFO_CARD_SHARE; -+ clnt.EventMask = -+ CS_EVENT_WRITE_PROTECT | CS_EVENT_CARD_INSERTION | -+ CS_EVENT_CARD_REMOVAL | CS_EVENT_BATTERY_DEAD | -+ CS_EVENT_BATTERY_LOW; -+ -+ clnt.event_handler = &mem_cs_event; -+ clnt.Version = 0x0210; -+ clnt.event_callback_args.client_data = &dev->link; -+ -+ ret = CardServices(RegisterClient, &dev->link.handle, &clnt); -+ if (ret != CS_SUCCESS) { -+ error_info_t err = { RegisterClient, ret }; -+ CardServices(ReportError, dev->link.handle, &err); -+ mem_cs_detach(&dev->link); -+ dev = NULL; -+ } -+ } -+ -+ return &dev->link; -+} -+ -+static int __init mem_cs_init(void) -+{ -+ servinfo_t serv; -+ -+ CardServices(GetCardServicesInfo, &serv); -+ if (serv.Revision != CS_RELEASE_CODE) { -+ printk(KERN_NOTICE "memory_cs: Card services release " -+ "does not match\n"); -+ return -ENXIO; -+ } -+ register_pccard_driver(&dev_info, mem_cs_attach, mem_cs_detach); -+ return 0; -+} -+ -+static void __exit mem_cs_exit(void) -+{ -+ unregister_pccard_driver(&dev_info); -+ while (dev_list != NULL) -+ memory_detach(dev_list); -+} -+ -+module_init(mem_cs_init); -+module_exit(mem_cs_exit); -+ -+MODULE_LICENSE("GPL"); -diff -urN linux-2.4.26/drivers/char/sa1100-rtc.c linux-2.4.26-vrs1/drivers/char/sa1100-rtc.c ---- linux-2.4.26/drivers/char/sa1100-rtc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/sa1100-rtc.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,474 @@ -+/* -+ * Real Time Clock interface for Linux on StrongARM SA1100 -+ * -+ * Copyright (c) 2000 Nils Faerber -+ * -+ * Based on rtc.c by Paul Gortmaker -+ * Date/time conversion routines taken from arch/arm/kernel/time.c -+ * by Linus Torvalds and Russel King -+ * and the GNU C Library -+ * ( ... I love the GPL ... just take what you need! ;) -+ * -+ * 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. -+ * -+ * 1.00 2001-06-08 Nicolas Pitre -+ * - added periodic timer capability using OSMR1 -+ * - flag compatibility with other RTC chips -+ * - permission checks for ioctls -+ * - major cleanup, partial rewrite -+ * -+ * 0.03 2001-03-07 CIH -+ * - Modify the bug setups RTC clock. -+ * -+ * 0.02 2001-02-27 Nils Faerber -+ * - removed mktime(), added alarm irq clear -+ * -+ * 0.01 2000-10-01 Nils Faerber -+ * - initial release -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DRIVER_VERSION "1.00" -+ -+#define TIMER_FREQ 3686400 -+ -+#define RTC_DEF_DIVIDER 32768 - 1 -+#define RTC_DEF_TRIM 0 -+ -+/* Those are the bits from a classic RTC we want to mimic */ -+#define RTC_IRQF 0x80 /* any of the following 3 is active */ -+#define RTC_PF 0x40 -+#define RTC_AF 0x20 -+#define RTC_UF 0x10 -+ -+static unsigned long rtc_status; -+static unsigned long rtc_irq_data; -+static unsigned long rtc_freq = 1024; -+ -+static struct fasync_struct *rtc_async_queue; -+static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); -+ -+extern spinlock_t rtc_lock; -+ -+static const unsigned char days_in_mo[] = -+ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; -+ -+#define is_leap(year) \ -+ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) -+ -+/* -+ * Converts seconds since 1970-01-01 00:00:00 to Gregorian date. -+ */ -+ -+static void decodetime (unsigned long t, struct rtc_time *tval) -+{ -+ long days, month, year, rem; -+ -+ days = t / 86400; -+ rem = t % 86400; -+ tval->tm_hour = rem / 3600; -+ rem %= 3600; -+ tval->tm_min = rem / 60; -+ tval->tm_sec = rem % 60; -+ tval->tm_wday = (4 + days) % 7; -+ -+#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) -+ -+ year = 1970 + days / 365; -+ days -= ((year - 1970) * 365 -+ + LEAPS_THRU_END_OF (year - 1) -+ - LEAPS_THRU_END_OF (1970 - 1)); -+ if (days < 0) { -+ year -= 1; -+ days += 365 + is_leap(year); -+ } -+ tval->tm_year = year - 1900; -+ tval->tm_yday = days + 1; -+ -+ month = 0; -+ if (days >= 31) { -+ days -= 31; -+ month++; -+ if (days >= (28 + is_leap(year))) { -+ days -= (28 + is_leap(year)); -+ month++; -+ while (days >= days_in_mo[month]) { -+ days -= days_in_mo[month]; -+ month++; -+ } -+ } -+ } -+ tval->tm_mon = month; -+ tval->tm_mday = days + 1; -+} -+ -+static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ unsigned int rtsr = RTSR; -+ -+ /* clear interrupt sources */ -+ RTSR = 0; -+ RTSR = (RTSR_AL|RTSR_HZ); -+ -+ /* clear alarm interrupt if it has occurred */ -+ if (rtsr & RTSR_AL) -+ rtsr &= ~RTSR_ALE; -+ RTSR = rtsr & (RTSR_ALE|RTSR_HZE); -+ -+ /* update irq data & counter */ -+ if (rtsr & RTSR_AL) -+ rtc_irq_data |= (RTC_AF|RTC_IRQF); -+ if (rtsr & RTSR_HZ) -+ rtc_irq_data |= (RTC_UF|RTC_IRQF); -+ rtc_irq_data += 0x100; -+ -+ /* wake up waiting process */ -+ wake_up_interruptible(&rtc_wait); -+ kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); -+} -+ -+static void timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ /* -+ * If we match for the first time, the periodic interrupt flag won't -+ * be set. If it is, then we did wrap around (very unlikely but -+ * still possible) and compute the amount of missed periods. -+ * The match reg is updated only when the data is actually retrieved -+ * to avoid unnecessary interrupts. -+ */ -+ OSSR = OSSR_M1; /* clear match on timer1 */ -+ if (rtc_irq_data & RTC_PF) { -+ rtc_irq_data += (rtc_freq * ((1<<30)/(TIMER_FREQ>>2))) << 8; -+ } else { -+ rtc_irq_data += (0x100|RTC_PF|RTC_IRQF); -+ } -+ -+ wake_up_interruptible(&rtc_wait); -+ kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); -+} -+ -+static int rtc_open(struct inode *inode, struct file *file) -+{ -+ if (test_and_set_bit (1, &rtc_status)) -+ return -EBUSY; -+ rtc_irq_data = 0; -+ return 0; -+} -+ -+static int rtc_release(struct inode *inode, struct file *file) -+{ -+ spin_lock_irq (&rtc_lock); -+ RTSR = 0; -+ RTSR = (RTSR_AL|RTSR_HZ); -+ OIER &= ~OIER_E1; -+ OSSR = OSSR_M1; -+ spin_unlock_irq (&rtc_lock); -+ rtc_status = 0; -+ return 0; -+} -+ -+static int rtc_fasync (int fd, struct file *filp, int on) -+{ -+ return fasync_helper (fd, filp, on, &rtc_async_queue); -+} -+ -+static unsigned int rtc_poll(struct file *file, poll_table *wait) -+{ -+ poll_wait (file, &rtc_wait, wait); -+ return (rtc_irq_data) ? 0 : POLLIN | POLLRDNORM; -+} -+ -+static loff_t rtc_llseek(struct file *file, loff_t offset, int origin) -+{ -+ return -ESPIPE; -+} -+ -+ssize_t rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned long data; -+ ssize_t retval; -+ -+ if (count < sizeof(unsigned long)) -+ return -EINVAL; -+ -+ add_wait_queue(&rtc_wait, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ for (;;) { -+ spin_lock_irq (&rtc_lock); -+ data = rtc_irq_data; -+ if (data != 0) { -+ rtc_irq_data = 0; -+ break; -+ } -+ spin_unlock_irq (&rtc_lock); -+ -+ if (file->f_flags & O_NONBLOCK) { -+ retval = -EAGAIN; -+ goto out; -+ } -+ -+ if (signal_pending(current)) { -+ retval = -ERESTARTSYS; -+ goto out; -+ } -+ -+ schedule(); -+ } -+ -+ if (data & RTC_PF) { -+ /* interpolate missed periods and set match for the next one */ -+ unsigned long period = TIMER_FREQ/rtc_freq; -+ unsigned long oscr = OSCR; -+ unsigned long osmr1 = OSMR1; -+ unsigned long missed = (oscr - osmr1)/period; -+ data += missed << 8; -+ OSSR = OSSR_M1; /* clear match on timer 1 */ -+ OSMR1 = osmr1 + (missed + 1)*period; -+ /* ensure we didn't miss another match in the mean time */ -+ while( (signed long)((osmr1 = OSMR1) - OSCR) <= 0 ) { -+ data += 0x100; -+ OSSR = OSSR_M1; /* clear match on timer 1 */ -+ OSMR1 = osmr1 + period; -+ } -+ } -+ spin_unlock_irq (&rtc_lock); -+ -+ data -= 0x100; /* the first IRQ wasn't actually missed */ -+ -+ retval = put_user(data, (unsigned long *)buf); -+ if (!retval) -+ retval = sizeof(unsigned long); -+ -+out: -+ set_current_state(TASK_RUNNING); -+ remove_wait_queue(&rtc_wait, &wait); -+ return retval; -+} -+ -+static int rtc_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ struct rtc_time tm, tm2; -+ -+ switch (cmd) { -+ case RTC_AIE_OFF: -+ spin_lock_irq(&rtc_lock); -+ RTSR &= ~RTSR_ALE; -+ rtc_irq_data = 0; -+ spin_unlock_irq(&rtc_lock); -+ return 0; -+ case RTC_AIE_ON: -+ spin_lock_irq(&rtc_lock); -+ RTSR |= RTSR_ALE; -+ rtc_irq_data = 0; -+ spin_unlock_irq(&rtc_lock); -+ return 0; -+ case RTC_UIE_OFF: -+ spin_lock_irq(&rtc_lock); -+ RTSR &= ~RTSR_HZE; -+ rtc_irq_data = 0; -+ spin_unlock_irq(&rtc_lock); -+ return 0; -+ case RTC_UIE_ON: -+ spin_lock_irq(&rtc_lock); -+ RTSR |= RTSR_HZE; -+ rtc_irq_data = 0; -+ spin_unlock_irq(&rtc_lock); -+ return 0; -+ case RTC_PIE_OFF: -+ spin_lock_irq(&rtc_lock); -+ OIER &= ~OIER_E1; -+ rtc_irq_data = 0; -+ spin_unlock_irq(&rtc_lock); -+ return 0; -+ case RTC_PIE_ON: -+ if ((rtc_freq > 64) && !capable(CAP_SYS_RESOURCE)) -+ return -EACCES; -+ spin_lock_irq(&rtc_lock); -+ OSMR1 = TIMER_FREQ/rtc_freq + OSCR; -+ OIER |= OIER_E1; -+ rtc_irq_data = 0; -+ spin_unlock_irq(&rtc_lock); -+ return 0; -+ case RTC_ALM_READ: -+ decodetime (RTAR, &tm); -+ break; -+ case RTC_ALM_SET: -+ if (copy_from_user (&tm2, (struct rtc_time*)arg, sizeof (tm2))) -+ return -EFAULT; -+ decodetime (RCNR, &tm); -+ if ((unsigned)tm2.tm_hour < 24) -+ tm.tm_hour = tm2.tm_hour; -+ if ((unsigned)tm2.tm_min < 60) -+ tm.tm_min = tm2.tm_min; -+ if ((unsigned)tm2.tm_sec < 60) -+ tm.tm_sec = tm2.tm_sec; -+ RTAR = mktime ( tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, -+ tm.tm_hour, tm.tm_min, tm.tm_sec); -+ return 0; -+ case RTC_RD_TIME: -+ decodetime (RCNR, &tm); -+ break; -+ case RTC_SET_TIME: -+ if (!capable(CAP_SYS_TIME)) -+ return -EACCES; -+ if (copy_from_user (&tm, (struct rtc_time*)arg, sizeof (tm))) -+ return -EFAULT; -+ tm.tm_year += 1900; -+ if (tm.tm_year < 1970 || (unsigned)tm.tm_mon >= 12 || -+ tm.tm_mday < 1 || tm.tm_mday > (days_in_mo[tm.tm_mon] + -+ (tm.tm_mon == 1 && is_leap(tm.tm_year))) || -+ (unsigned)tm.tm_hour >= 24 || -+ (unsigned)tm.tm_min >= 60 || -+ (unsigned)tm.tm_sec >= 60) -+ return -EINVAL; -+ RCNR = mktime ( tm.tm_year, tm.tm_mon + 1, tm.tm_mday, -+ tm.tm_hour, tm.tm_min, tm.tm_sec); -+ return 0; -+ case RTC_IRQP_READ: -+ return put_user(rtc_freq, (unsigned long *)arg); -+ case RTC_IRQP_SET: -+ if (arg < 1 || arg > TIMER_FREQ) -+ return -EINVAL; -+ if ((arg > 64) && (!capable(CAP_SYS_RESOURCE))) -+ return -EACCES; -+ rtc_freq = arg; -+ return 0; -+ case RTC_EPOCH_READ: -+ return put_user (1970, (unsigned long *)arg); -+ default: -+ return -EINVAL; -+ } -+ return copy_to_user ((void *)arg, &tm, sizeof (tm)) ? -EFAULT : 0; -+} -+ -+static struct file_operations rtc_fops = { -+ owner: THIS_MODULE, -+ llseek: rtc_llseek, -+ read: rtc_read, -+ poll: rtc_poll, -+ ioctl: rtc_ioctl, -+ open: rtc_open, -+ release: rtc_release, -+ fasync: rtc_fasync, -+}; -+ -+static struct miscdevice sa1100rtc_miscdev = { -+ RTC_MINOR, -+ "rtc", -+ &rtc_fops -+}; -+ -+static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) -+{ -+ char *p = page; -+ int len; -+ struct rtc_time tm; -+ -+ decodetime (RCNR, &tm); -+ p += sprintf(p, "rtc_time\t: %02d:%02d:%02d\n" -+ "rtc_date\t: %04d-%02d-%02d\n" -+ "rtc_epoch\t: %04d\n", -+ tm.tm_hour, tm.tm_min, tm.tm_sec, -+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 1970); -+ decodetime (RTAR, &tm); -+ p += sprintf(p, "alrm_time\t: %02d:%02d:%02d\n" -+ "alrm_date\t: %04d-%02d-%02d\n", -+ tm.tm_hour, tm.tm_min, tm.tm_sec, -+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); -+ p += sprintf(p, "trim/divider\t: 0x%08x\n", RTTR); -+ p += sprintf(p, "alarm_IRQ\t: %s\n", (RTSR & RTSR_ALE) ? "yes" : "no" ); -+ p += sprintf(p, "update_IRQ\t: %s\n", (RTSR & RTSR_HZE) ? "yes" : "no"); -+ p += sprintf(p, "periodic_IRQ\t: %s\n", (OIER & OIER_E1) ? "yes" : "no"); -+ p += sprintf(p, "periodic_freq\t: %ld\n", rtc_freq); -+ -+ len = (p - page) - off; -+ if (len < 0) -+ len = 0; -+ -+ *eof = (len <= count) ? 1 : 0; -+ *start = page + off; -+ -+ return len; -+} -+ -+static int __init rtc_init(void) -+{ -+ int ret; -+ -+ misc_register (&sa1100rtc_miscdev); -+ create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL); -+ ret = request_irq (IRQ_RTC1Hz, rtc_interrupt, SA_INTERRUPT, "rtc 1Hz", NULL); -+ if (ret) { -+ printk (KERN_ERR "rtc: IRQ %d already in use.\n", IRQ_RTC1Hz); -+ goto IRQ_RTC1Hz_failed; -+ } -+ ret = request_irq (IRQ_RTCAlrm, rtc_interrupt, SA_INTERRUPT, "rtc Alrm", NULL); -+ if (ret) { -+ printk(KERN_ERR "rtc: IRQ %d already in use.\n", IRQ_RTCAlrm); -+ goto IRQ_RTCAlrm_failed; -+ } -+ ret = request_irq (IRQ_OST1, timer1_interrupt, SA_INTERRUPT, "rtc timer", NULL); -+ if (ret) { -+ printk(KERN_ERR "rtc: IRQ %d already in use.\n", IRQ_OST1); -+ goto IRQ_OST1_failed; -+ } -+ -+ printk (KERN_INFO "SA1100 Real Time Clock driver v" DRIVER_VERSION "\n"); -+ -+ /* -+ * According to the manual we should be able to let RTTR be zero -+ * and then a default diviser for a 32.768KHz clock is used. -+ * Apparently this doesn't work, at least for my SA1110 rev 5. -+ * If the clock divider is uninitialized then reset it to the -+ * default value to get the 1Hz clock. -+ */ -+ if (RTTR == 0) { -+ RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); -+ printk (KERN_WARNING "rtc: warning: initializing default clock divider/trim value\n"); -+ /* The current RTC value probably doesn't make sense either */ -+ RCNR = 0; -+ } -+ -+ return 0; -+ -+IRQ_OST1_failed: -+ free_irq (IRQ_RTCAlrm, NULL); -+IRQ_RTCAlrm_failed: -+ free_irq (IRQ_RTC1Hz, NULL); -+IRQ_RTC1Hz_failed: -+ remove_proc_entry ("driver/rtc", NULL); -+ misc_deregister (&sa1100rtc_miscdev); -+ return ret; -+} -+ -+static void __exit rtc_exit(void) -+{ -+ free_irq (IRQ_OST1, NULL); -+ free_irq (IRQ_RTCAlrm, NULL); -+ free_irq (IRQ_RTC1Hz, NULL); -+ remove_proc_entry ("driver/rtc", NULL); -+ misc_deregister (&sa1100rtc_miscdev); -+} -+ -+module_init(rtc_init); -+module_exit(rtc_exit); -+ -+MODULE_AUTHOR("Nils Faerber "); -+MODULE_DESCRIPTION("SA1100 Realtime Clock Driver (RTC)"); -+EXPORT_NO_SYMBOLS; -diff -urN linux-2.4.26/drivers/char/sa1100_wdt.c linux-2.4.26-vrs1/drivers/char/sa1100_wdt.c ---- linux-2.4.26/drivers/char/sa1100_wdt.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/sa1100_wdt.c 2004-04-10 12:04:15.000000000 +0100 -@@ -0,0 +1,150 @@ -+/* -+ * Watchdog driver for the SA11x0 -+ * -+ * (c) Copyright 2000 Oleg Drokin -+ * Based on SoftDog driver by Alan Cox -+ * -+ * 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. -+ * -+ * Neither Oleg Drokin nor iXcelerator.com admit liability nor provide -+ * warranty for any of this software. This material is provided -+ * "AS-IS" and at no charge. -+ * -+ * (c) Copyright 2000 Oleg Drokin -+ * -+ * 27/11/2000 Initial release -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define TIMER_MARGIN 60 /* (secs) Default is 1 minute */ -+ -+static int sa1100_margin = TIMER_MARGIN; /* in seconds */ -+static int sa1100wdt_users; -+static int pre_margin; -+#ifdef MODULE -+MODULE_PARM(sa1100_margin,"i"); -+#endif -+ -+/* -+ * Allow only one person to hold it open -+ */ -+ -+static int sa1100dog_open(struct inode *inode, struct file *file) -+{ -+ if(test_and_set_bit(1,&sa1100wdt_users)) -+ return -EBUSY; -+ MOD_INC_USE_COUNT; -+ /* Activate SA1100 Watchdog timer */ -+ pre_margin=3686400 * sa1100_margin; -+ OSMR3 = OSCR + pre_margin; -+ OSSR = OSSR_M3; -+ OWER = OWER_WME; -+ OIER |= OIER_E3; -+ return 0; -+} -+ -+static int sa1100dog_release(struct inode *inode, struct file *file) -+{ -+ /* -+ * Shut off the timer. -+ * Lock it in if it's a module and we defined ...NOWAYOUT -+ */ -+ OSMR3 = OSCR + pre_margin; -+#ifndef CONFIG_WATCHDOG_NOWAYOUT -+ OIER &= ~OIER_E3; -+#endif -+ sa1100wdt_users = 0; -+ MOD_DEC_USE_COUNT; -+ return 0; -+} -+ -+static ssize_t sa1100dog_write(struct file *file, const char *data, size_t len, loff_t *ppos) -+{ -+ /* Can't seek (pwrite) on this device */ -+ if (ppos != &file->f_pos) -+ return -ESPIPE; -+ -+ /* Refresh OSMR3 timer. */ -+ if(len) { -+ OSMR3 = OSCR + pre_margin; -+ return 1; -+ } -+ return 0; -+} -+ -+static int sa1100dog_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ static struct watchdog_info ident = { -+ identity: "SA1100 Watchdog", -+ }; -+ -+ switch(cmd){ -+ default: -+ return -ENOIOCTLCMD; -+ case WDIOC_GETSUPPORT: -+ return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)); -+ case WDIOC_GETSTATUS: -+ return put_user(0,(int *)arg); -+ case WDIOC_GETBOOTSTATUS: -+ return put_user((RCSR & RCSR_WDR) ? WDIOF_CARDRESET : 0, (int *)arg); -+ case WDIOC_KEEPALIVE: -+ OSMR3 = OSCR + pre_margin; -+ return 0; -+ } -+} -+ -+static struct file_operations sa1100dog_fops= -+{ -+ owner: THIS_MODULE, -+ write: sa1100dog_write, -+ ioctl: sa1100dog_ioctl, -+ open: sa1100dog_open, -+ release: sa1100dog_release, -+}; -+ -+static struct miscdevice sa1100dog_miscdev= -+{ -+ WATCHDOG_MINOR, -+ "SA1100 watchdog", -+ &sa1100dog_fops -+}; -+ -+static int __init sa1100dog_init(void) -+{ -+ int ret; -+ -+ ret = misc_register(&sa1100dog_miscdev); -+ -+ if (ret) -+ return ret; -+ -+ printk("SA1100 Watchdog Timer: timer margin %d sec\n", sa1100_margin); -+ -+ return 0; -+} -+ -+static void __exit sa1100dog_exit(void) -+{ -+ misc_deregister(&sa1100dog_miscdev); -+} -+ -+module_init(sa1100dog_init); -+module_exit(sa1100dog_exit); -diff -urN linux-2.4.26/drivers/char/sa1111_keyb.c linux-2.4.26-vrs1/drivers/char/sa1111_keyb.c ---- linux-2.4.26/drivers/char/sa1111_keyb.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/sa1111_keyb.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,1153 @@ -+/* -+ * SA1111 PS/2 keyboard/mouse driver -+ * -+ * 2000 by VASARA RESEARCH INC. -+ * -+ * Changelog: -+ * Jun.xx,2000: Kunihiko IMAI -+ * Port to 2.4.0test1-ac19-rmk1-np1 -+ * Apr.17,2000: Takafumi Kawana -+ * Internal Release for XP860 -+ * -+ * -+ * This driver is based on linux/drivers/char/pc_keyb.c -+ * Original declaration follows: -+ -+ * -+ * linux/drivers/char/pc_keyb.c -+ * -+ * Separation of the PC low-level part by Geert Uytterhoeven, May 1997 -+ * See keyboard.c for the whole history. -+ * -+ * Major cleanup by Martin Mares, May 1997 -+ * -+ * Combined the keyboard and PS/2 mouse handling into one file, -+ * because they share the same hardware. -+ * Johan Myreen 1998-10-08. -+ * -+ * Code fixes to handle mouse ACKs properly. -+ * C. Scott Ananian 1999-01-29. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+/* Some configuration switches are present in the include file... */ -+ -+#include -+#include -+#include -+ -+#define KBD_STAT_RXB (1<<4) -+#define KBD_STAT_RXF (1<<5) -+#define KBD_STAT_TXB (1<<6) -+#define KBD_STAT_TXE (1<<7) -+#define KBD_STAT_STP (1<<8) -+ -+#define MSE_STAT_RXB (1<<4) -+#define MSE_STAT_RXF (1<<5) -+#define MSE_STAT_TXB (1<<6) -+#define MSE_STAT_TXE (1<<7) -+#define MSE_STAT_STP (1<<8) -+ -+/* Simple translation table for the SysRq keys */ -+ -+#ifdef CONFIG_MAGIC_SYSRQ -+unsigned char sa1111_sysrq_xlate[128] = "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ -+ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ -+ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ -+ "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ -+ "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ -+ "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ -+ "\r\000/"; /* 0x60 - 0x6f */ -+#endif -+ -+// static void kbd_write_command_w(int data); -+static void kbd_write_output_w(int data); -+ -+spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; -+static void handle_kbd_event(void); -+ -+/* used only by send_data - set by keyboard_interrupt */ -+static volatile unsigned char reply_expected = 0; -+static volatile unsigned char acknowledge = 0; -+static volatile unsigned char resend = 0; -+ -+ -+#if defined CONFIG_PSMOUSE -+/* -+ * PS/2 Auxiliary Device -+ */ -+ -+static int __init psaux_init(void); -+ -+static struct aux_queue *queue; /* Mouse data buffer. */ -+static int aux_count = 0; -+/* used when we send commands to the mouse that expect an ACK. */ -+static unsigned char mouse_reply_expected = 0; -+ -+#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT) -+#define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT) -+ -+#define MAX_RETRIES 60 /* some aux operations take long time */ -+#endif /* CONFIG_PSMOUSE */ -+ -+/* -+ * Wait for keyboard controller input buffer to drain. -+ * -+ * Don't use 'jiffies' so that we don't depend on -+ * interrupts.. -+ * -+ * Quote from PS/2 System Reference Manual: -+ * -+ * "Address hex 0060 and address hex 0064 should be written only when -+ * the input-buffer-full bit and output-buffer-full bit in the -+ * Controller Status register are set 0." -+ */ -+ -+static void kb_wait(void) -+{ -+ unsigned long timeout = KBC_TIMEOUT; -+ -+ do { -+ /* -+ * "handle_kbd_event()" will handle any incoming events -+ * while we wait - keypresses or mouse movement. -+ */ -+ handle_kbd_event(); -+ if (KBDSTAT & KBD_STAT_TXE) -+ return; -+ mdelay(1); -+ timeout--; -+ } -+ while (timeout); -+#ifdef KBD_REPORT_TIMEOUTS -+ printk(KERN_WARNING "Keyboard timed out[1]\n"); -+#endif -+} -+ -+/* -+ * Translation of escaped scancodes to keycodes. -+ * This is now user-settable. -+ * The keycodes 1-88,96-111,119 are fairly standard, and -+ * should probably not be changed - changing might confuse X. -+ * X also interprets scancode 0x5d (KEY_Begin). -+ * -+ * For 1-88 keycode equals scancode. -+ */ -+ -+#define E0_KPENTER 96 -+#define E0_RCTRL 97 -+#define E0_KPSLASH 98 -+#define E0_PRSCR 99 -+#define E0_RALT 100 -+#define E0_BREAK 101 /* (control-pause) */ -+#define E0_HOME 102 -+#define E0_UP 103 -+#define E0_PGUP 104 -+#define E0_LEFT 105 -+#define E0_RIGHT 106 -+#define E0_END 107 -+#define E0_DOWN 108 -+#define E0_PGDN 109 -+#define E0_INS 110 -+#define E0_DEL 111 -+ -+/* for USB 106 keyboard */ -+#define E0_YEN 124 -+#define E0_BACKSLASH 89 -+ -+ -+#define E1_PAUSE 119 -+ -+/* -+ * The keycodes below are randomly located in 89-95,112-118,120-127. -+ * They could be thrown away (and all occurrences below replaced by 0), -+ * but that would force many users to use the `setkeycodes' utility, where -+ * they needed not before. It does not matter that there are duplicates, as -+ * long as no duplication occurs for any single keyboard. -+ */ -+#define SC_LIM 89 -+ -+#define FOCUS_PF1 85 /* actual code! */ -+#define FOCUS_PF2 89 -+#define FOCUS_PF3 90 -+#define FOCUS_PF4 91 -+#define FOCUS_PF5 92 -+#define FOCUS_PF6 93 -+#define FOCUS_PF7 94 -+#define FOCUS_PF8 95 -+#define FOCUS_PF9 120 -+#define FOCUS_PF10 121 -+#define FOCUS_PF11 122 -+#define FOCUS_PF12 123 -+ -+#define JAP_86 124 -+/* tfj@olivia.ping.dk: -+ * The four keys are located over the numeric keypad, and are -+ * labelled A1-A4. It's an rc930 keyboard, from -+ * Regnecentralen/RC International, Now ICL. -+ * Scancodes: 59, 5a, 5b, 5c. -+ */ -+#define RGN1 124 -+#define RGN2 125 -+#define RGN3 126 -+#define RGN4 127 -+ -+static unsigned char high_keys[128 - SC_LIM] = { -+ RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */ -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ -+ 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */ -+ 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */ -+ FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */ -+ FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */ -+}; -+ -+/* BTC */ -+#define E0_MACRO 112 -+/* LK450 */ -+#define E0_F13 113 -+#define E0_F14 114 -+#define E0_HELP 115 -+#define E0_DO 116 -+#define E0_F17 117 -+#define E0_KPMINPLUS 118 -+/* -+ * My OmniKey generates e0 4c for the "OMNI" key and the -+ * right alt key does nada. [kkoller@nyx10.cs.du.edu] -+ */ -+#define E0_OK 124 -+/* -+ * New microsoft keyboard is rumoured to have -+ * e0 5b (left window button), e0 5c (right window button), -+ * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU] -+ * [or: Windows_L, Windows_R, TaskMan] -+ */ -+#define E0_MSLW 125 -+#define E0_MSRW 126 -+#define E0_MSTM 127 -+ -+static unsigned char e0_keys[128] = { -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */ -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */ -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ -+ 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */ -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ -+ 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */ -+ E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */ -+ E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */ -+ E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END, /* 0x48-0x4f */ -+ E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */ -+ 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */ -+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ -+ 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */ -+ //0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ -+ 0, 0, 0, 0, 0, E0_BACKSLASH, 0, 0, /* 0x70-0x77 */ -+ 0, 0, 0, E0_YEN, 0, 0, 0, 0 /* 0x78-0x7f */ -+}; -+ -+int sa1111_setkeycode(unsigned int scancode, unsigned int keycode) -+{ -+ if (scancode < SC_LIM || scancode > 255 || keycode > 127) -+ return -EINVAL; -+ if (scancode < 128) -+ high_keys[scancode - SC_LIM] = keycode; -+ else -+ e0_keys[scancode - 128] = keycode; -+ return 0; -+} -+ -+int sa1111_getkeycode(unsigned int scancode) -+{ -+ return -+ (scancode < SC_LIM || scancode > 255) ? -EINVAL : -+ (scancode < -+ 128) ? high_keys[scancode - SC_LIM] : e0_keys[scancode - 128]; -+} -+ -+static int do_acknowledge(unsigned char scancode) -+{ -+ if (reply_expected) { -+ /* Unfortunately, we must recognise these codes only if we know they -+ * are known to be valid (i.e., after sending a command), because there -+ * are some brain-damaged keyboards (yes, FOCUS 9000 again) which have -+ * keys with such codes :( -+ */ -+ if (scancode == KBD_REPLY_ACK) { -+ acknowledge = 1; -+ reply_expected = 0; -+ return 0; -+ } else if (scancode == KBD_REPLY_RESEND) { -+ resend = 1; -+ reply_expected = 0; -+ return 0; -+ } -+ /* Should not happen... */ -+#if 0 -+ printk(KERN_DEBUG "keyboard reply expected - got %02x\n", -+ scancode); -+#endif -+ } -+ return 1; -+} -+ -+int -+sa1111_translate(unsigned char scancode, unsigned char *keycode, -+ char raw_mode) -+{ -+ static int prev_scancode = 0; -+ -+ /* special prefix scancodes.. */ -+ if (scancode == 0xe0 || scancode == 0xe1) { -+ prev_scancode = scancode; -+ return 0; -+ } -+ -+ /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */ -+ if (scancode == 0x00 || scancode == 0xff) { -+ prev_scancode = 0; -+ return 0; -+ } -+ -+ scancode &= 0x7f; -+ -+ if (prev_scancode) { -+ /* -+ * usually it will be 0xe0, but a Pause key generates -+ * e1 1d 45 e1 9d c5 when pressed, and nothing when released -+ */ -+ if (prev_scancode != 0xe0) { -+ if (prev_scancode == 0xe1 && scancode == 0x1d) { -+ prev_scancode = 0x100; -+ return 0; -+ } -+ else if (prev_scancode == 0x100 -+ && scancode == 0x45) { -+ *keycode = E1_PAUSE; -+ prev_scancode = 0; -+ } else { -+#ifdef KBD_REPORT_UNKN -+ if (!raw_mode) -+ printk(KERN_INFO -+ "keyboard: unknown e1 escape sequence\n"); -+#endif -+ prev_scancode = 0; -+ return 0; -+ } -+ } else { -+ prev_scancode = 0; -+ /* -+ * The keyboard maintains its own internal caps lock and -+ * num lock statuses. In caps lock mode E0 AA precedes make -+ * code and E0 2A follows break code. In num lock mode, -+ * E0 2A precedes make code and E0 AA follows break code. -+ * We do our own book-keeping, so we will just ignore these. -+ */ -+ /* -+ * For my keyboard there is no caps lock mode, but there are -+ * both Shift-L and Shift-R modes. The former mode generates -+ * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs. -+ * So, we should also ignore the latter. - aeb@cwi.nl -+ */ -+ if (scancode == 0x2a || scancode == 0x36) -+ return 0; -+ -+ if (e0_keys[scancode]) -+ *keycode = e0_keys[scancode]; -+ else { -+#ifdef KBD_REPORT_UNKN -+ if (!raw_mode) -+ printk(KERN_INFO -+ "keyboard: unknown scancode e0 %02x\n", -+ scancode); -+#endif -+ return 0; -+ } -+ } -+ } else if (scancode >= SC_LIM) { -+ /* This happens with the FOCUS 9000 keyboard -+ Its keys PF1..PF12 are reported to generate -+ 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f -+ Moreover, unless repeated, they do not generate -+ key-down events, so we have to zero up_flag below */ -+ /* Also, Japanese 86/106 keyboards are reported to -+ generate 0x73 and 0x7d for \ - and \ | respectively. */ -+ /* Also, some Brazilian keyboard is reported to produce -+ 0x73 and 0x7e for \ ? and KP-dot, respectively. */ -+ -+ *keycode = high_keys[scancode - SC_LIM]; -+ -+ if (!*keycode) { -+ if (!raw_mode) { -+#ifdef KBD_REPORT_UNKN -+ printk(KERN_INFO -+ "keyboard: unrecognized scancode (%02x)" -+ " - ignored\n", scancode); -+#endif -+ } -+ return 0; -+ } -+ } else -+ *keycode = scancode; -+ return 1; -+} -+ -+char sa1111_unexpected_up(unsigned char keycode) -+{ -+ /* unexpected, but this can happen: maybe this was a key release for a -+ FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */ -+ if (keycode >= SC_LIM || keycode == 85) -+ return 0; -+ else -+ return 0200; -+} -+ -+static unsigned char kbd_exists = 1; -+ -+static inline void handle_keyboard_event(unsigned char scancode) -+{ -+#ifdef CONFIG_VT -+ kbd_exists = 1; -+ if (do_acknowledge(scancode)) -+ handle_scancode(scancode, !(scancode & 0x80)); -+#endif -+ tasklet_schedule(&keyboard_tasklet); -+} -+ -+/* -+ * This reads the keyboard status port, and does the -+ * appropriate action. -+ * -+ * It requires that we hold the keyboard controller -+ * spinlock. -+ */ -+static void handle_kbd_event(void) -+{ -+ unsigned int status = KBDSTAT; -+ unsigned int work = 10000; -+ unsigned char scancode; -+ -+ while (status & KBD_STAT_RXF) { -+ while (status & KBD_STAT_RXF) { -+ scancode = KBDDATA & 0xff; -+ if (!(status & KBD_STAT_STP)) -+ handle_keyboard_event(scancode); -+ if (!--work) { -+ printk(KERN_ERR -+ "pc_keyb: keyboard controller jammed (0x%02X).\n", -+ status); -+ return; -+ } -+ status = KBDSTAT; -+ } -+ work = 10000; -+ } -+ -+ if (status & KBD_STAT_STP) -+ KBDSTAT = KBD_STAT_STP; -+} -+ -+static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ unsigned long flags; -+ -+#ifdef CONFIG_VT -+ kbd_pt_regs = regs; -+#endif -+ spin_lock_irqsave(&kbd_controller_lock, flags); -+ handle_kbd_event(); -+ spin_unlock_irqrestore(&kbd_controller_lock, flags); -+} -+ -+/* -+ * send_data sends a character to the keyboard and waits -+ * for an acknowledge, possibly retrying if asked to. Returns -+ * the success status. -+ * -+ * Don't use 'jiffies', so that we don't depend on interrupts -+ */ -+static int send_data(unsigned char data) -+{ -+ int retries = 3; -+ -+ do { -+ unsigned long timeout = KBD_TIMEOUT; -+ -+ acknowledge = 0; /* Set by interrupt routine on receipt of ACK. */ -+ resend = 0; -+ reply_expected = 1; -+ kbd_write_output_w(data); -+ for (;;) { -+ if (acknowledge) -+ return 1; -+ if (resend) -+ break; -+ mdelay(1); -+ if (!--timeout) { -+#ifdef KBD_REPORT_TIMEOUTS -+ printk(KERN_WARNING -+ "keyboard: Timeout - AT keyboard not present?\n"); -+#endif -+ return 0; -+ } -+ } -+ } -+ while (retries-- > 0); -+#ifdef KBD_REPORT_TIMEOUTS -+ printk(KERN_WARNING -+ "keyboard: Too many NACKs -- noisy kbd cable?\n"); -+#endif -+ return 0; -+} -+ -+void sa1111_leds(unsigned char leds) -+{ -+ if (kbd_exists -+ && (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds))) { -+ send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */ -+ kbd_exists = 0; -+ } -+} -+ -+#define KBD_NO_DATA (-1) /* No data */ -+#define KBD_BAD_DATA (-2) /* Parity or other error */ -+ -+static int __init kbd_read_data(void) -+{ -+ int retval = KBD_NO_DATA; -+ unsigned int status; -+ -+ status = KBDSTAT; -+ if (status & KBD_STAT_RXF) { -+ unsigned char data = KBDDATA; -+ -+ retval = data; -+ if (status & KBD_STAT_STP) -+ retval = KBD_BAD_DATA; -+ } -+ return retval; -+} -+ -+static void __init kbd_clear_input(void) -+{ -+ int maxread = 100; /* Random number */ -+ -+ do { -+ if (kbd_read_data() == KBD_NO_DATA) -+ break; -+ } -+ while (--maxread); -+} -+ -+static int __init kbd_wait_for_input(void) -+{ -+ long timeout = KBD_INIT_TIMEOUT; -+ -+ do { -+ int retval = kbd_read_data(); -+ if (retval >= 0) -+ return retval; -+ mdelay(1); -+ } -+ while (--timeout); -+ return -1; -+} -+ -+#if 0 -+static void kbd_write_command_w(int data) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbd_controller_lock, flags); -+ kb_wait(); -+ kbd_write_command(data); -+ spin_unlock_irqrestore(&kbd_controller_lock, flags); -+} -+#endif -+ -+static void kbd_write_output_w(int data) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbd_controller_lock, flags); -+ kb_wait(); -+ KBDDATA = data & 0xff; -+ spin_unlock_irqrestore(&kbd_controller_lock, flags); -+} -+ -+/* -+ * Test the keyboard interface. We basically check to make sure that -+ * we can drive each line to the keyboard independently of each other. -+ */ -+static int kbdif_test(void) -+{ -+ int ret = 0; -+ -+ KBDCR = KBDCR_ENA | KBDCR_FKC; -+ udelay(2); -+ if ((KBDSTAT & (KBDSTAT_KBC | KBDSTAT_KBD)) != KBDSTAT_KBD) { -+ printk("Keyboard interface test failed[1]: %02x\n", -+ KBDSTAT); -+ ret = -ENODEV; -+ } -+ -+ KBDCR = KBDCR_ENA; -+ udelay(2); -+ if ((KBDSTAT & (KBDSTAT_KBC | KBDSTAT_KBD)) != (KBDSTAT_KBC | KBDSTAT_KBD)) { -+ printk("Keyboard interface test failed[2]: %02x\n", -+ KBDSTAT); -+ ret = -ENODEV; -+ } -+ -+ KBDCR = KBDCR_ENA | KBDCR_FKD; -+ udelay(2); -+ if ((KBDSTAT & (KBDSTAT_KBC | KBDSTAT_KBD)) != KBDSTAT_KBC) { -+ printk("Keyboard interface test failed[3]: %02x\n", -+ KBDSTAT); -+ ret = -ENODEV; -+ } -+ -+ return ret; -+} -+ -+static char *__init initialize_kbd(void) -+{ -+ int status; -+ -+ /* -+ * Test the keyboard interface. -+ */ -+ kbdif_test(); -+ -+ /* -+ * Ok, drop the force low bits, and wait a while, -+ * and clear the stop bit error flag. -+ */ -+ KBDCR = KBDCR_ENA; -+ udelay(4); -+ KBDSTAT = KBD_STAT_STP; -+ -+ /* -+ * Ok, we're now ready to talk to the keyboard. Reset -+ * it, just to make sure we're starting in a sane state. -+ * -+ * Set up to try again if the keyboard asks for RESEND. -+ */ -+ do { -+ KBDDATA = KBD_CMD_RESET; -+ status = kbd_wait_for_input(); -+ if (status == KBD_REPLY_ACK) -+ break; -+ if (status != KBD_REPLY_RESEND) -+ return "Keyboard reset failed, no ACK"; -+ } while (1); -+ -+ if (kbd_wait_for_input() != KBD_REPLY_POR) -+ return "Keyboard reset failed, no POR"; -+ -+ /* -+ * Set keyboard controller mode. During this, the keyboard should be -+ * in the disabled state. -+ * -+ * Set up to try again if the keyboard asks for RESEND. -+ */ -+ do { -+ kbd_write_output_w(KBD_CMD_DISABLE); -+ status = kbd_wait_for_input(); -+ if (status == KBD_REPLY_ACK) -+ break; -+ if (status != KBD_REPLY_RESEND) -+ return "Disable keyboard: no ACK"; -+ } while (1); -+ -+#if 0 /*@@@ */ -+ kbd_write_command_w(KBD_CCMD_WRITE_MODE); -+ kbd_write_output_w(KBD_MODE_KBD_INT -+ | KBD_MODE_SYS | KBD_MODE_DISABLE_MOUSE | -+ KBD_MODE_KCC); -+ -+ /* ibm powerpc portables need this to use scan-code set 1 -- Cort */ -+ kbd_write_command_w(KBD_CCMD_READ_MODE); -+ if (!(kbd_wait_for_input() & KBD_MODE_KCC)) { -+ /* -+ * If the controller does not support conversion, -+ * Set the keyboard to scan-code set 1. -+ */ -+ kbd_write_output_w(0xF0); -+ kbd_wait_for_input(); -+ kbd_write_output_w(0x01); -+ kbd_wait_for_input(); -+ } -+#else -+ kbd_write_output_w(0xf0); -+ kbd_wait_for_input(); -+ kbd_write_output_w(0x01); -+ kbd_wait_for_input(); -+#endif -+ -+ -+ kbd_write_output_w(KBD_CMD_ENABLE); -+ if (kbd_wait_for_input() != KBD_REPLY_ACK) -+ return "Enable keyboard: no ACK"; -+ -+ /* -+ * Finally, set the typematic rate to maximum. -+ */ -+ kbd_write_output_w(KBD_CMD_SET_RATE); -+ if (kbd_wait_for_input() != KBD_REPLY_ACK) -+ return "Set rate: no ACK"; -+ kbd_write_output_w(0x00); -+ if (kbd_wait_for_input() != KBD_REPLY_ACK) -+ return "Set rate: no ACK"; -+ -+ return NULL; -+} -+ -+int __init sa1111_kbd_init_hw(void) -+{ -+ char *msg; -+ int ret; -+ -+ if (!request_mem_region(_KBDCR, 512, "keyboard")) -+ return -EBUSY; -+ -+ SKPCR |= SKPCR_PTCLKEN; -+ KBDCLKDIV = 0; -+ KBDPRECNT = 127; -+ -+ /* Flush any pending input. */ -+ kbd_clear_input(); -+ -+ msg = initialize_kbd(); -+ if (msg) -+ printk(KERN_WARNING "initialize_kbd: %s\n", msg); -+ -+#if defined CONFIG_PSMOUSE -+ psaux_init(); -+#endif -+ -+ k_setkeycode = sa1111_setkeycode; -+ k_getkeycode = sa1111_getkeycode; -+ k_translate = sa1111_translate; -+ k_unexpected_up = sa1111_unexpected_up; -+ k_leds = sa1111_leds; -+#ifdef CONFIG_MAGIC_SYSRQ -+ k_sysrq_xlate = sa1111_sysrq_xlate; -+ k_sysrq_key = 0x54; -+#endif -+ -+ /* Ok, finally allocate the IRQ, and off we go.. */ -+ ret = request_irq(IRQ_TPRXINT, keyboard_interrupt, 0, "keyboard", NULL); -+ if (ret) -+ release_mem_region(_KBDCR, 512); -+ -+ return ret; -+} -+ -+#if defined CONFIG_PSMOUSE -+ -+static inline void handle_mouse_event(unsigned char scancode) -+{ -+ if (mouse_reply_expected) { -+ if (scancode == AUX_ACK) { -+ mouse_reply_expected--; -+ return; -+ } -+ mouse_reply_expected = 0; -+ } -+ -+ add_mouse_randomness(scancode); -+ if (aux_count) { -+ int head = queue->head; -+ -+ queue->buf[head] = scancode; -+ head = (head + 1) & (AUX_BUF_SIZE - 1); -+ if (head != queue->tail) { -+ queue->head = head; -+ if (queue->fasync) -+ kill_fasync(&queue->fasync, SIGIO, -+ POLL_IN); -+ wake_up_interruptible(&queue->proc_list); -+ } -+ } -+} -+ -+static void handle_mse_event(void) -+{ -+ unsigned int msests = MSESTAT; -+ unsigned int work = 10000; -+ unsigned char scancode; -+ -+ while (msests & MSE_STAT_RXF) { -+ while (msests & MSE_STAT_RXF) { -+ scancode = MSEDATA & 0xff; -+ if (!(msests & MSE_STAT_STP)) -+ handle_mouse_event(scancode); -+ if (!--work) { -+ printk(KERN_ERR -+ "pc_keyb: mouse controller jammed (0x%02X).\n", -+ msests); -+ return; -+ /*XXX*/} -+ msests = MSESTAT; -+ } -+ work = 10000; -+ } -+} -+ -+static void ms_wait(void) -+{ -+ unsigned long timeout = KBC_TIMEOUT; -+ -+ do { -+ /* -+ * "handle_kbd_event()" will handle any incoming events -+ * while we wait - keypresses or mouse movement. -+ */ -+ handle_mse_event(); -+ if (MSESTAT & MSE_STAT_TXE) -+ return; -+ mdelay(1); -+ timeout--; -+ } -+ while (timeout); -+#ifdef KBD_REPORT_TIMEOUTS -+ printk(KERN_WARNING "Mouse timed out[1]\n"); -+#endif -+} -+ -+static void mouse_interrupt(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbd_controller_lock, flags); -+ handle_mse_event(); -+ spin_unlock_irqrestore(&kbd_controller_lock, flags); -+} -+ -+/* -+ * Check if this is a dual port controller. -+ */ -+static int __init detect_auxiliary_port(void) -+{ -+ unsigned long flags; -+ int loops = 10; -+ int retval = 0; -+ -+ /* Check if the BIOS detected a device on the auxiliary port. */ -+ if (aux_device_present == 0xaa) -+ return 1; -+ -+ spin_lock_irqsave(&kbd_controller_lock, flags); -+ -+ /* Put the value 0x5A in the output buffer using the "Write -+ * Auxiliary Device Output Buffer" command (0xD3). Poll the -+ * Status Register for a while to see if the value really -+ * turns up in the Data Register. If the KBD_STAT_MOUSE_OBF -+ * bit is also set to 1 in the Status Register, we assume this -+ * controller has an Auxiliary Port (a.k.a. Mouse Port). -+ */ -+ // kb_wait(); -+ // kbd_write_command(KBD_CCMD_WRITE_AUX_OBUF); -+ -+ SKPCR |= SKPCR_PMCLKEN; -+ -+ MSECLKDIV = 0; -+ MSEPRECNT = 127; -+ MSECR = MSECR_ENA; -+ mdelay(50); -+ MSEDATA = 0xf4; -+ mdelay(50); -+ -+ do { -+ unsigned int msests = MSESTAT; -+ -+ if (msests & MSE_STAT_RXF) { -+ do { -+ msests = MSEDATA; /* dummy read */ -+ mdelay(50); -+ msests = MSESTAT; -+ } -+ while (msests & MSE_STAT_RXF); -+ printk(KERN_INFO "Detected PS/2 Mouse Port.\n"); -+ retval = 1; -+ break; -+ } -+ mdelay(1); -+ } -+ while (--loops); -+ spin_unlock_irqrestore(&kbd_controller_lock, flags); -+ -+ return retval; -+} -+ -+/* -+ * Send a byte to the mouse. -+ */ -+static void aux_write_dev(int val) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbd_controller_lock, flags); -+ // kb_wait(); -+ // kbd_write_command(KBD_CCMD_WRITE_MOUSE); -+ ms_wait(); -+ MSEDATA = val; -+ spin_unlock_irqrestore(&kbd_controller_lock, flags); -+} -+ -+/* -+ * Send a byte to the mouse & handle returned ack -+ */ -+static void aux_write_ack(int val) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbd_controller_lock, flags); -+ // kb_wait(); -+ // kbd_write_command(KBD_CCMD_WRITE_MOUSE); -+ ms_wait(); -+ MSEDATA = val; -+ /* we expect an ACK in response. */ -+ mouse_reply_expected++; -+ ms_wait(); -+ spin_unlock_irqrestore(&kbd_controller_lock, flags); -+} -+ -+static unsigned char get_from_queue(void) -+{ -+ unsigned char result; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&kbd_controller_lock, flags); -+ result = queue->buf[queue->tail]; -+ queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE - 1); -+ spin_unlock_irqrestore(&kbd_controller_lock, flags); -+ return result; -+} -+ -+ -+static inline int queue_empty(void) -+{ -+ return queue->head == queue->tail; -+} -+ -+static int fasync_aux(int fd, struct file *filp, int on) -+{ -+ int retval; -+ -+ retval = fasync_helper(fd, filp, on, &queue->fasync); -+ if (retval < 0) -+ return retval; -+ return 0; -+} -+ -+ -+/* -+ * Random magic cookie for the aux device -+ */ -+#define AUX_DEV ((void *)queue) -+ -+static int release_aux(struct inode *inode, struct file *file) -+{ -+ fasync_aux(-1, file, 0); -+ if (--aux_count) -+ return 0; -+ // kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */ -+ // kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE); -+ aux_write_ack(AUX_DISABLE_DEV); /* Disable aux device */ -+ MSECR &= ~MSECR_ENA; -+ free_irq(IRQ_MSRXINT, AUX_DEV); -+ return 0; -+} -+ -+/* -+ * Install interrupt handler. -+ * Enable auxiliary device. -+ */ -+ -+static int open_aux(struct inode *inode, struct file *file) -+{ -+ if (aux_count++) { -+ return 0; -+ } -+ queue->head = queue->tail = 0; /* Flush input queue */ -+ /* Don't enable the mouse controller until we've registered IRQ handler */ -+ if (request_irq(IRQ_MSRXINT, mouse_interrupt, SA_SHIRQ, "PS/2 Mouse", AUX_DEV)) { -+ aux_count--; -+ return -EBUSY; -+ } -+ MSECLKDIV = 0; -+ MSEPRECNT = 127; -+ MSECR &= ~MSECR_ENA; -+ mdelay(50); -+ MSECR = MSECR_ENA; -+ mdelay(50); -+ MSEDATA = 0xf4; -+ mdelay(50); -+ if (MSESTAT & 0x0100) { -+ MSESTAT = 0x0100; /* clear IRQ status */ -+ } -+/* kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); *//* Enable the -+ auxiliary port on -+ controller. */ -+ aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ -+ // kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */ -+ -+ // send_data(KBD_CMD_ENABLE); /* try to workaround toshiba4030cdt problem */ -+ -+ return 0; -+} -+ -+/* -+ * Put bytes from input queue to buffer. -+ */ -+ -+static ssize_t -+read_aux(struct file *file, char *buffer, size_t count, loff_t * ppos) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ ssize_t i = count; -+ unsigned char c; -+ -+ if (queue_empty()) { -+ if (file->f_flags & O_NONBLOCK) -+ return -EAGAIN; -+ add_wait_queue(&queue->proc_list, &wait); -+ repeat: -+ set_current_state(TASK_INTERRUPTIBLE); -+ if (queue_empty() && !signal_pending(current)) { -+ schedule(); -+ goto repeat; -+ } -+ current->state = TASK_RUNNING; -+ remove_wait_queue(&queue->proc_list, &wait); -+ } -+ while (i > 0 && !queue_empty()) { -+ c = get_from_queue(); -+ put_user(c, buffer++); -+ i--; -+ } -+ if (count - i) { -+ file->f_dentry->d_inode->i_atime = CURRENT_TIME; -+ return count - i; -+ } -+ if (signal_pending(current)) -+ return -ERESTARTSYS; -+ return 0; -+} -+ -+/* -+ * Write to the aux device. -+ */ -+ -+static ssize_t -+write_aux(struct file *file, const char *buffer, size_t count, -+ loff_t * ppos) -+{ -+ ssize_t retval = 0; -+ -+ if (count) { -+ ssize_t written = 0; -+ -+ if (count > 32) -+ count = 32; /* Limit to 32 bytes. */ -+ do { -+ char c; -+ get_user(c, buffer++); -+ aux_write_dev(c); -+ written++; -+ } -+ while (--count); -+ retval = -EIO; -+ if (written) { -+ retval = written; -+ file->f_dentry->d_inode->i_mtime = CURRENT_TIME; -+ } -+ } -+ -+ return retval; -+} -+ -+static unsigned int aux_poll(struct file *file, poll_table * wait) -+{ -+ poll_wait(file, &queue->proc_list, wait); -+ if (!queue_empty()) -+ return POLLIN | POLLRDNORM; -+ return 0; -+} -+ -+struct file_operations psaux_fops = { -+ read: read_aux, -+ write: write_aux, -+ poll: aux_poll, -+ open: open_aux, -+ release: release_aux, -+ fasync: fasync_aux, -+}; -+ -+/* -+ * Initialize driver. -+ */ -+static struct miscdevice psaux_mouse = { -+ PSMOUSE_MINOR, "psaux", &psaux_fops -+}; -+ -+ -+static int __init psaux_init(void) -+{ -+ int ret; -+ -+ if (!request_mem_region(_MSECR, 512, "psaux")) -+ return -EBUSY; -+ -+ if (!detect_auxiliary_port()) { -+ ret = -EIO; -+ goto out; -+ } -+ -+ misc_register(&psaux_mouse); -+ queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); -+ memset(queue, 0, sizeof(*queue)); -+ queue->head = queue->tail = 0; -+ init_waitqueue_head(&queue->proc_list); -+ -+#ifdef CONFIG_PSMOUSE -+ aux_write_ack(AUX_SET_SAMPLE); -+ aux_write_ack(100); /* 100 samples/sec */ -+ aux_write_ack(AUX_SET_RES); -+ aux_write_ack(3); /* 8 counts per mm */ -+ aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */ -+#endif -+ ret = 0; -+ -+ out: -+ if (ret) -+ release_mem_region(_MSECR, 512); -+ return ret; -+} -+ -+#endif /* CONFIG_PSMOUSE */ -diff -urN linux-2.4.26/drivers/char/serial.c linux-2.4.26-vrs1/drivers/char/serial.c ---- linux-2.4.26/drivers/char/serial.c 2004-02-27 20:03:25.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/char/serial.c 2004-02-23 13:36:30.000000000 +0000 -@@ -4527,6 +4527,14 @@ - } - - /* -+ * If there is exactly one port of 8 bytes, use it. -+ */ -+ if (num_port == 1 && pci_resource_len(dev, first_port) == 8) { -+ board->flags = first_port; -+ return 0; -+ } -+ -+ /* - * If there is 1 or 0 iomem regions, and exactly one port, use - * it. - */ -diff -urN linux-2.4.26/drivers/char/serial_21285.c linux-2.4.26-vrs1/drivers/char/serial_21285.c ---- linux-2.4.26/drivers/char/serial_21285.c 2002-08-03 01:39:43.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/serial_21285.c 1970-01-01 01:00:00.000000000 +0100 -@@ -1,498 +0,0 @@ --/* -- * linux/drivers/char/serial_21285.c -- * -- * Driver for the serial port on the 21285 StrongArm-110 core logic chip. -- * -- * Based on drivers/char/serial.c -- */ -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#include --#include --#include --#include --#include -- --#define BAUD_BASE (mem_fclk_21285/64) -- --#define SERIAL_21285_NAME "ttyFB" --#define SERIAL_21285_MAJOR 204 --#define SERIAL_21285_MINOR 4 -- --#define SERIAL_21285_AUXNAME "cuafb" --#define SERIAL_21285_AUXMAJOR 205 --#define SERIAL_21285_AUXMINOR 4 -- --static struct tty_driver rs285_driver, callout_driver; --static int rs285_refcount; --static struct tty_struct *rs285_table[1]; -- --static struct termios *rs285_termios[1]; --static struct termios *rs285_termios_locked[1]; -- --static char wbuf[1000], *putp = wbuf, *getp = wbuf, x_char; --static struct tty_struct *rs285_tty; --static int rs285_use_count; -- --static int rs285_write_room(struct tty_struct *tty) --{ -- return putp >= getp ? (sizeof(wbuf) - (long) putp + (long) getp) : ((long) getp - (long) putp - 1); --} -- --static void rs285_rx_int(int irq, void *dev_id, struct pt_regs *regs) --{ -- if (!rs285_tty) { -- disable_irq(IRQ_CONRX); -- return; -- } -- while (!(*CSR_UARTFLG & 0x10)) { -- int ch, flag; -- ch = *CSR_UARTDR; -- flag = *CSR_RXSTAT; -- if (flag & 4) -- tty_insert_flip_char(rs285_tty, 0, TTY_OVERRUN); -- if (flag & 2) -- flag = TTY_PARITY; -- else if (flag & 1) -- flag = TTY_FRAME; -- tty_insert_flip_char(rs285_tty, ch, flag); -- } -- tty_flip_buffer_push(rs285_tty); --} -- --static void rs285_send_xchar(struct tty_struct *tty, char ch) --{ -- x_char = ch; -- enable_irq(IRQ_CONTX); --} -- --static void rs285_throttle(struct tty_struct *tty) --{ -- if (I_IXOFF(tty)) -- rs285_send_xchar(tty, STOP_CHAR(tty)); --} -- --static void rs285_unthrottle(struct tty_struct *tty) --{ -- if (I_IXOFF(tty)) { -- if (x_char) -- x_char = 0; -- else -- rs285_send_xchar(tty, START_CHAR(tty)); -- } --} -- --static void rs285_tx_int(int irq, void *dev_id, struct pt_regs *regs) --{ -- while (!(*CSR_UARTFLG & 0x20)) { -- if (x_char) { -- *CSR_UARTDR = x_char; -- x_char = 0; -- continue; -- } -- if (putp == getp) { -- disable_irq(IRQ_CONTX); -- break; -- } -- *CSR_UARTDR = *getp; -- if (++getp >= wbuf + sizeof(wbuf)) -- getp = wbuf; -- } -- if (rs285_tty) -- wake_up_interruptible(&rs285_tty->write_wait); --} -- --static inline int rs285_xmit(int ch) --{ -- if (putp + 1 == getp || (putp + 1 == wbuf + sizeof(wbuf) && getp == wbuf)) -- return 0; -- *putp = ch; -- if (++putp >= wbuf + sizeof(wbuf)) -- putp = wbuf; -- enable_irq(IRQ_CONTX); -- return 1; --} -- --static int rs285_write(struct tty_struct *tty, int from_user, -- const u_char * buf, int count) --{ -- int i; -- -- if (from_user && verify_area(VERIFY_READ, buf, count)) -- return -EINVAL; -- -- for (i = 0; i < count; i++) { -- char ch; -- if (from_user) -- __get_user(ch, buf + i); -- else -- ch = buf[i]; -- if (!rs285_xmit(ch)) -- break; -- } -- return i; --} -- --static void rs285_put_char(struct tty_struct *tty, u_char ch) --{ -- rs285_xmit(ch); --} -- --static int rs285_chars_in_buffer(struct tty_struct *tty) --{ -- return sizeof(wbuf) - rs285_write_room(tty); --} -- --static void rs285_flush_buffer(struct tty_struct *tty) --{ -- disable_irq(IRQ_CONTX); -- putp = getp = wbuf; -- if (x_char) -- enable_irq(IRQ_CONTX); --} -- --static inline void rs285_set_cflag(int cflag) --{ -- int h_lcr, baud, quot; -- -- switch (cflag & CSIZE) { -- case CS5: -- h_lcr = 0x10; -- break; -- case CS6: -- h_lcr = 0x30; -- break; -- case CS7: -- h_lcr = 0x50; -- break; -- default: /* CS8 */ -- h_lcr = 0x70; -- break; -- -- } -- if (cflag & CSTOPB) -- h_lcr |= 0x08; -- if (cflag & PARENB) -- h_lcr |= 0x02; -- if (!(cflag & PARODD)) -- h_lcr |= 0x04; -- -- switch (cflag & CBAUD) { -- case B200: baud = 200; break; -- case B300: baud = 300; break; -- case B1200: baud = 1200; break; -- case B1800: baud = 1800; break; -- case B2400: baud = 2400; break; -- case B4800: baud = 4800; break; -- default: -- case B9600: baud = 9600; break; -- case B19200: baud = 19200; break; -- case B38400: baud = 38400; break; -- case B57600: baud = 57600; break; -- case B115200: baud = 115200; break; -- } -- -- /* -- * The documented expression for selecting the divisor is: -- * BAUD_BASE / baud - 1 -- * However, typically BAUD_BASE is not divisible by baud, so -- * we want to select the divisor that gives us the minimum -- * error. Therefore, we want: -- * int(BAUD_BASE / baud - 0.5) -> -- * int(BAUD_BASE / baud - (baud >> 1) / baud) -> -- * int((BAUD_BASE - (baud >> 1)) / baud) -- */ -- quot = (BAUD_BASE - (baud >> 1)) / baud; -- -- *CSR_UARTCON = 0; -- *CSR_L_UBRLCR = quot & 0xff; -- *CSR_M_UBRLCR = (quot >> 8) & 0x0f; -- *CSR_H_UBRLCR = h_lcr; -- *CSR_UARTCON = 1; --} -- --static void rs285_set_termios(struct tty_struct *tty, struct termios *old) --{ -- if (old && tty->termios->c_cflag == old->c_cflag) -- return; -- rs285_set_cflag(tty->termios->c_cflag); --} -- -- --static void rs285_stop(struct tty_struct *tty) --{ -- disable_irq(IRQ_CONTX); --} -- --static void rs285_start(struct tty_struct *tty) --{ -- enable_irq(IRQ_CONTX); --} -- --static void rs285_wait_until_sent(struct tty_struct *tty, int timeout) --{ -- int orig_jiffies = jiffies; -- while (*CSR_UARTFLG & 8) { -- current->state = TASK_INTERRUPTIBLE; -- schedule_timeout(1); -- if (signal_pending(current)) -- break; -- if (timeout && time_after(jiffies, orig_jiffies + timeout)) -- break; -- } -- current->state = TASK_RUNNING; --} -- --static int rs285_open(struct tty_struct *tty, struct file *filp) --{ -- int line; -- -- MOD_INC_USE_COUNT; -- line = MINOR(tty->device) - tty->driver.minor_start; -- if (line) { -- MOD_DEC_USE_COUNT; -- return -ENODEV; -- } -- -- tty->driver_data = NULL; -- if (!rs285_tty) -- rs285_tty = tty; -- -- enable_irq(IRQ_CONRX); -- rs285_use_count++; -- return 0; --} -- --static void rs285_close(struct tty_struct *tty, struct file *filp) --{ -- if (!--rs285_use_count) { -- rs285_wait_until_sent(tty, 0); -- disable_irq(IRQ_CONRX); -- disable_irq(IRQ_CONTX); -- rs285_tty = NULL; -- } -- MOD_DEC_USE_COUNT; --} -- --static int __init rs285_init(void) --{ -- int baud = B9600; -- -- if (machine_is_personal_server()) -- baud = B57600; -- -- rs285_driver.magic = TTY_DRIVER_MAGIC; -- rs285_driver.driver_name = "serial_21285"; -- rs285_driver.name = SERIAL_21285_NAME; -- rs285_driver.major = SERIAL_21285_MAJOR; -- rs285_driver.minor_start = SERIAL_21285_MINOR; -- rs285_driver.num = 1; -- rs285_driver.type = TTY_DRIVER_TYPE_SERIAL; -- rs285_driver.subtype = SERIAL_TYPE_NORMAL; -- rs285_driver.init_termios = tty_std_termios; -- rs285_driver.init_termios.c_cflag = baud | CS8 | CREAD | HUPCL | CLOCAL; -- rs285_driver.flags = TTY_DRIVER_REAL_RAW; -- rs285_driver.refcount = &rs285_refcount; -- rs285_driver.table = rs285_table; -- rs285_driver.termios = rs285_termios; -- rs285_driver.termios_locked = rs285_termios_locked; -- -- rs285_driver.open = rs285_open; -- rs285_driver.close = rs285_close; -- rs285_driver.write = rs285_write; -- rs285_driver.put_char = rs285_put_char; -- rs285_driver.write_room = rs285_write_room; -- rs285_driver.chars_in_buffer = rs285_chars_in_buffer; -- rs285_driver.flush_buffer = rs285_flush_buffer; -- rs285_driver.throttle = rs285_throttle; -- rs285_driver.unthrottle = rs285_unthrottle; -- rs285_driver.send_xchar = rs285_send_xchar; -- rs285_driver.set_termios = rs285_set_termios; -- rs285_driver.stop = rs285_stop; -- rs285_driver.start = rs285_start; -- rs285_driver.wait_until_sent = rs285_wait_until_sent; -- -- callout_driver = rs285_driver; -- callout_driver.name = SERIAL_21285_AUXNAME; -- callout_driver.major = SERIAL_21285_AUXMAJOR; -- callout_driver.subtype = SERIAL_TYPE_CALLOUT; -- -- if (request_irq(IRQ_CONRX, rs285_rx_int, 0, "rs285", NULL)) -- panic("Couldn't get rx irq for rs285"); -- -- if (request_irq(IRQ_CONTX, rs285_tx_int, 0, "rs285", NULL)) -- panic("Couldn't get tx irq for rs285"); -- -- if (tty_register_driver(&rs285_driver)) -- printk(KERN_ERR "Couldn't register 21285 serial driver\n"); -- if (tty_register_driver(&callout_driver)) -- printk(KERN_ERR "Couldn't register 21285 callout driver\n"); -- -- return 0; --} -- --static void __exit rs285_fini(void) --{ -- unsigned long flags; -- int ret; -- -- save_flags(flags); -- cli(); -- ret = tty_unregister_driver(&callout_driver); -- if (ret) -- printk(KERN_ERR "Unable to unregister 21285 callout driver " -- "(%d)\n", ret); -- ret = tty_unregister_driver(&rs285_driver); -- if (ret) -- printk(KERN_ERR "Unable to unregister 21285 driver (%d)\n", -- ret); -- free_irq(IRQ_CONTX, NULL); -- free_irq(IRQ_CONRX, NULL); -- restore_flags(flags); --} -- --module_init(rs285_init); --module_exit(rs285_fini); -- --#ifdef CONFIG_SERIAL_21285_CONSOLE --/************** console driver *****************/ -- --static void rs285_console_write(struct console *co, const char *s, u_int count) --{ -- int i; -- -- disable_irq(IRQ_CONTX); -- for (i = 0; i < count; i++) { -- while (*CSR_UARTFLG & 0x20); -- *CSR_UARTDR = s[i]; -- if (s[i] == '\n') { -- while (*CSR_UARTFLG & 0x20); -- *CSR_UARTDR = '\r'; -- } -- } -- enable_irq(IRQ_CONTX); --} -- --static kdev_t rs285_console_device(struct console *c) --{ -- return MKDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR); --} -- --static int __init rs285_console_setup(struct console *co, char *options) --{ -- int baud = 9600; -- int bits = 8; -- int parity = 'n'; -- int cflag = CREAD | HUPCL | CLOCAL; -- -- if (machine_is_personal_server()) -- baud = 57600; -- -- if (options) { -- char *s = options; -- baud = simple_strtoul(options, NULL, 10); -- while (*s >= '0' && *s <= '9') -- s++; -- if (*s) -- parity = *s++; -- if (*s) -- bits = *s - '0'; -- } -- -- /* -- * Now construct a cflag setting. -- */ -- switch (baud) { -- case 1200: -- cflag |= B1200; -- break; -- case 2400: -- cflag |= B2400; -- break; -- case 4800: -- cflag |= B4800; -- break; -- case 9600: -- cflag |= B9600; -- break; -- case 19200: -- cflag |= B19200; -- break; -- case 38400: -- cflag |= B38400; -- break; -- case 57600: -- cflag |= B57600; -- break; -- case 115200: -- cflag |= B115200; -- break; -- default: -- cflag |= B9600; -- break; -- } -- switch (bits) { -- case 7: -- cflag |= CS7; -- break; -- default: -- cflag |= CS8; -- break; -- } -- switch (parity) { -- case 'o': -- case 'O': -- cflag |= PARODD; -- break; -- case 'e': -- case 'E': -- cflag |= PARENB; -- break; -- } -- co->cflag = cflag; -- rs285_set_cflag(cflag); -- rs285_console_write(NULL, "\e[2J\e[Hboot ", 12); -- if (options) -- rs285_console_write(NULL, options, strlen(options)); -- else -- rs285_console_write(NULL, "no options", 10); -- rs285_console_write(NULL, "\n", 1); -- -- return 0; --} -- --static struct console rs285_cons = --{ -- name: SERIAL_21285_NAME, -- write: rs285_console_write, -- device: rs285_console_device, -- setup: rs285_console_setup, -- flags: CON_PRINTBUFFER, -- index: -1, --}; -- --void __init rs285_console_init(void) --{ -- register_console(&rs285_cons); --} -- --#endif /* CONFIG_SERIAL_21285_CONSOLE */ -- --MODULE_LICENSE("GPL"); --EXPORT_NO_SYMBOLS; -diff -urN linux-2.4.26/drivers/char/serial_amba.c linux-2.4.26-vrs1/drivers/char/serial_amba.c ---- linux-2.4.26/drivers/char/serial_amba.c 2002-08-03 01:39:43.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/serial_amba.c 1970-01-01 01:00:00.000000000 +0100 -@@ -1,2015 +0,0 @@ --/* -- * linux/drivers/char/serial_amba.c -- * -- * Driver for AMBA serial ports -- * -- * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. -- * -- * Copyright 1999 ARM Limited -- * Copyright (C) 2000 Deep Blue Solutions Ltd. -- * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License as published by -- * the Free Software Foundation; either version 2 of the License, or -- * (at your option) any later version. -- * -- * This program is distributed in the hope that it will be useful, -- * but WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- * -- * You should have received a copy of the GNU General Public License -- * along with this program; if not, write to the Free Software -- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -- * -- * -- * This is a generic driver for ARM AMBA-type serial ports. They -- * have a lot of 16550-like features, but are not register compatable. -- * Note that although they do have CTS, DCD and DSR inputs, they do -- * not have an RI input, nor do they have DTR or RTS outputs. If -- * required, these have to be supplied via some other means (eg, GPIO) -- * and hooked into this driver. -- * -- * This could very easily become a generic serial driver for dumb UARTs -- * (eg, {82,16x}50, 21285, SA1100). -- */ -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#include --#include --#include --#include --#include -- --#include -- --#define SERIAL_AMBA_NAME "ttyAM" --#define SERIAL_AMBA_MAJOR 204 --#define SERIAL_AMBA_MINOR 16 --#define SERIAL_AMBA_NR 2 -- --#define CALLOUT_AMBA_NAME "cuaam" --#define CALLOUT_AMBA_MAJOR 205 --#define CALLOUT_AMBA_MINOR 16 --#define CALLOUT_AMBA_NR SERIAL_AMBA_NR -- --#ifndef TRUE --#define TRUE 1 --#endif --#ifndef FALSE --#define FALSE 0 --#endif -- --#define DEBUG 0 --#define DEBUG_LEDS 0 -- --#if DEBUG_LEDS --extern int get_leds(void); --extern int set_leds(int); --#endif -- --/* -- * Access routines for the AMBA UARTs -- */ --#define UART_GET_INT_STATUS(p) IO_READ((p)->uart_base + AMBA_UARTIIR) --#define UART_GET_FR(p) IO_READ((p)->uart_base + AMBA_UARTFR) --#define UART_GET_CHAR(p) IO_READ((p)->uart_base + AMBA_UARTDR) --#define UART_PUT_CHAR(p, c) IO_WRITE((p)->uart_base + AMBA_UARTDR, (c)) --#define UART_GET_RSR(p) IO_READ((p)->uart_base + AMBA_UARTRSR) --#define UART_GET_CR(p) IO_READ((p)->uart_base + AMBA_UARTCR) --#define UART_PUT_CR(p,c) IO_WRITE((p)->uart_base + AMBA_UARTCR, (c)) --#define UART_GET_LCRL(p) IO_READ((p)->uart_base + AMBA_UARTLCR_L) --#define UART_PUT_LCRL(p,c) IO_WRITE((p)->uart_base + AMBA_UARTLCR_L, (c)) --#define UART_GET_LCRM(p) IO_READ((p)->uart_base + AMBA_UARTLCR_M) --#define UART_PUT_LCRM(p,c) IO_WRITE((p)->uart_base + AMBA_UARTLCR_M, (c)) --#define UART_GET_LCRH(p) IO_READ((p)->uart_base + AMBA_UARTLCR_H) --#define UART_PUT_LCRH(p,c) IO_WRITE((p)->uart_base + AMBA_UARTLCR_H, (c)) --#define UART_RX_DATA(s) (((s) & AMBA_UARTFR_RXFE) == 0) --#define UART_TX_READY(s) (((s) & AMBA_UARTFR_TXFF) == 0) --#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & AMBA_UARTFR_TMSK) == 0) -- --#define AMBA_UARTRSR_ANY (AMBA_UARTRSR_OE|AMBA_UARTRSR_BE|AMBA_UARTRSR_PE|AMBA_UARTRSR_FE) --#define AMBA_UARTFR_MODEM_ANY (AMBA_UARTFR_DCD|AMBA_UARTFR_DSR|AMBA_UARTFR_CTS) -- --/* -- * Things needed by tty driver -- */ --static struct tty_driver ambanormal_driver, ambacallout_driver; --static int ambauart_refcount; --static struct tty_struct *ambauart_table[SERIAL_AMBA_NR]; --static struct termios *ambauart_termios[SERIAL_AMBA_NR]; --static struct termios *ambauart_termios_locked[SERIAL_AMBA_NR]; -- --#if defined(CONFIG_SERIAL_AMBA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) --#define SUPPORT_SYSRQ --#endif -- --/* -- * Things needed internally to this driver -- */ -- --/* -- * tmp_buf is used as a temporary buffer by serial_write. We need to -- * lock it in case the copy_from_user blocks while swapping in a page, -- * and some other program tries to do a serial write at the same time. -- * Since the lock will only come under contention when the system is -- * swapping and available memory is low, it makes sense to share one -- * buffer across all the serial ports, since it significantly saves -- * memory if large numbers of serial ports are open. -- */ --static u_char *tmp_buf; --static DECLARE_MUTEX(tmp_buf_sem); -- --#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) -- --/* number of characters left in xmit buffer before we ask for more */ --#define WAKEUP_CHARS 256 --#define AMBA_ISR_PASS_LIMIT 256 -- --#define EVT_WRITE_WAKEUP 0 -- --struct amba_icount { -- __u32 cts; -- __u32 dsr; -- __u32 rng; -- __u32 dcd; -- __u32 rx; -- __u32 tx; -- __u32 frame; -- __u32 overrun; -- __u32 parity; -- __u32 brk; -- __u32 buf_overrun; --}; -- --/* -- * Static information about the port -- */ --struct amba_port { -- unsigned int uart_base; -- unsigned int irq; -- unsigned int uartclk; -- unsigned int fifosize; -- unsigned int tiocm_support; -- void (*set_mctrl)(struct amba_port *, u_int mctrl); --}; -- --/* -- * This is the state information which is persistent across opens -- */ --struct amba_state { -- struct amba_icount icount; -- unsigned int line; -- unsigned int close_delay; -- unsigned int closing_wait; -- unsigned int custom_divisor; -- unsigned int flags; -- struct termios normal_termios; -- struct termios callout_termios; -- -- int count; -- struct amba_info *info; --}; -- --#define AMBA_XMIT_SIZE 1024 --/* -- * This is the state information which is only valid when the port is open. -- */ --struct amba_info { -- struct amba_port *port; -- struct amba_state *state; -- struct tty_struct *tty; -- unsigned char x_char; -- unsigned char old_status; -- unsigned char read_status_mask; -- unsigned char ignore_status_mask; -- struct circ_buf xmit; -- unsigned int flags; --#ifdef SUPPORT_SYSRQ -- unsigned long sysrq; --#endif -- -- unsigned int event; -- unsigned int timeout; -- unsigned int lcr_h; -- unsigned int mctrl; -- int blocked_open; -- pid_t session; -- pid_t pgrp; -- -- struct tasklet_struct tlet; -- -- wait_queue_head_t open_wait; -- wait_queue_head_t close_wait; -- wait_queue_head_t delta_msr_wait; --}; -- --#ifdef CONFIG_SERIAL_AMBA_CONSOLE --static struct console ambauart_cons; --#endif --static void ambauart_change_speed(struct amba_info *info, struct termios *old_termios); --static void ambauart_wait_until_sent(struct tty_struct *tty, int timeout); -- --#if 1 //def CONFIG_SERIAL_INTEGRATOR --static void amba_set_mctrl_null(struct amba_port *port, u_int mctrl) --{ --} -- --static struct amba_port amba_ports[SERIAL_AMBA_NR] = { -- { -- uart_base: IO_ADDRESS(INTEGRATOR_UART0_BASE), -- irq: IRQ_UARTINT0, -- uartclk: 14745600, -- fifosize: 8, -- set_mctrl: amba_set_mctrl_null, -- }, -- { -- uart_base: IO_ADDRESS(INTEGRATOR_UART1_BASE), -- irq: IRQ_UARTINT1, -- uartclk: 14745600, -- fifosize: 8, -- set_mctrl: amba_set_mctrl_null, -- } --}; --#endif -- --static struct amba_state amba_state[SERIAL_AMBA_NR]; -- --static void ambauart_enable_rx_interrupt(struct amba_info *info) --{ -- unsigned int cr; -- -- cr = UART_GET_CR(info->port); -- cr |= AMBA_UARTCR_RIE | AMBA_UARTCR_RTIE; -- UART_PUT_CR(info->port, cr); --} -- --static void ambauart_disable_rx_interrupt(struct amba_info *info) --{ -- unsigned int cr; -- -- cr = UART_GET_CR(info->port); -- cr &= ~(AMBA_UARTCR_RIE | AMBA_UARTCR_RTIE); -- UART_PUT_CR(info->port, cr); --} -- --static void ambauart_enable_tx_interrupt(struct amba_info *info) --{ -- unsigned int cr; -- -- cr = UART_GET_CR(info->port); -- cr |= AMBA_UARTCR_TIE; -- UART_PUT_CR(info->port, cr); --} -- --static void ambauart_disable_tx_interrupt(struct amba_info *info) --{ -- unsigned int cr; -- -- cr = UART_GET_CR(info->port); -- cr &= ~AMBA_UARTCR_TIE; -- UART_PUT_CR(info->port, cr); --} -- --static void ambauart_stop(struct tty_struct *tty) --{ -- struct amba_info *info = tty->driver_data; -- unsigned long flags; -- -- save_flags(flags); cli(); -- ambauart_disable_tx_interrupt(info); -- restore_flags(flags); --} -- --static void ambauart_start(struct tty_struct *tty) --{ -- struct amba_info *info = tty->driver_data; -- unsigned long flags; -- -- save_flags(flags); cli(); -- if (info->xmit.head != info->xmit.tail -- && info->xmit.buf) -- ambauart_enable_tx_interrupt(info); -- restore_flags(flags); --} -- -- --/* -- * This routine is used by the interrupt handler to schedule -- * processing in the software interrupt portion of the driver. -- */ --static void ambauart_event(struct amba_info *info, int event) --{ -- info->event |= 1 << event; -- tasklet_schedule(&info->tlet); --} -- --static void --#ifdef SUPPORT_SYSRQ --ambauart_rx_chars(struct amba_info *info, struct pt_regs *regs) --#else --ambauart_rx_chars(struct amba_info *info) --#endif --{ -- struct tty_struct *tty = info->tty; -- unsigned int status, ch, rsr, flg, ignored = 0; -- struct amba_icount *icount = &info->state->icount; -- struct amba_port *port = info->port; -- -- status = UART_GET_FR(port); -- while (UART_RX_DATA(status)) { -- ch = UART_GET_CHAR(port); -- -- if (tty->flip.count >= TTY_FLIPBUF_SIZE) -- goto ignore_char; -- icount->rx++; -- -- flg = TTY_NORMAL; -- -- /* -- * Note that the error handling code is -- * out of the main execution path -- */ -- rsr = UART_GET_RSR(port); -- if (rsr & AMBA_UARTRSR_ANY) -- goto handle_error; --#ifdef SUPPORT_SYSRQ -- if (info->sysrq) { -- if (ch && time_before(jiffies, info->sysrq)) { -- handle_sysrq(ch, regs, NULL, NULL); -- info->sysrq = 0; -- goto ignore_char; -- } -- info->sysrq = 0; -- } --#endif -- error_return: -- *tty->flip.flag_buf_ptr++ = flg; -- *tty->flip.char_buf_ptr++ = ch; -- tty->flip.count++; -- ignore_char: -- status = UART_GET_FR(port); -- } --out: -- tty_flip_buffer_push(tty); -- return; -- --handle_error: -- if (rsr & AMBA_UARTRSR_BE) { -- rsr &= ~(AMBA_UARTRSR_FE | AMBA_UARTRSR_PE); -- icount->brk++; -- --#ifdef SUPPORT_SYSRQ -- if (info->state->line == ambauart_cons.index) { -- if (!info->sysrq) { -- info->sysrq = jiffies + HZ*5; -- goto ignore_char; -- } -- } --#endif -- } else if (rsr & AMBA_UARTRSR_PE) -- icount->parity++; -- else if (rsr & AMBA_UARTRSR_FE) -- icount->frame++; -- if (rsr & AMBA_UARTRSR_OE) -- icount->overrun++; -- -- if (rsr & info->ignore_status_mask) { -- if (++ignored > 100) -- goto out; -- goto ignore_char; -- } -- rsr &= info->read_status_mask; -- -- if (rsr & AMBA_UARTRSR_BE) -- flg = TTY_BREAK; -- else if (rsr & AMBA_UARTRSR_PE) -- flg = TTY_PARITY; -- else if (rsr & AMBA_UARTRSR_FE) -- flg = TTY_FRAME; -- -- if (rsr & AMBA_UARTRSR_OE) { -- /* -- * CHECK: does overrun affect the current character? -- * ASSUMPTION: it does not. -- */ -- *tty->flip.flag_buf_ptr++ = flg; -- *tty->flip.char_buf_ptr++ = ch; -- tty->flip.count++; -- if (tty->flip.count >= TTY_FLIPBUF_SIZE) -- goto ignore_char; -- ch = 0; -- flg = TTY_OVERRUN; -- } --#ifdef SUPPORT_SYSRQ -- info->sysrq = 0; --#endif -- goto error_return; --} -- --static void ambauart_tx_chars(struct amba_info *info) --{ -- struct amba_port *port = info->port; -- int count; -- -- if (info->x_char) { -- UART_PUT_CHAR(port, info->x_char); -- info->state->icount.tx++; -- info->x_char = 0; -- return; -- } -- if (info->xmit.head == info->xmit.tail -- || info->tty->stopped -- || info->tty->hw_stopped) { -- ambauart_disable_tx_interrupt(info); -- return; -- } -- -- count = port->fifosize; -- do { -- UART_PUT_CHAR(port, info->xmit.buf[info->xmit.tail]); -- info->xmit.tail = (info->xmit.tail + 1) & (AMBA_XMIT_SIZE - 1); -- info->state->icount.tx++; -- if (info->xmit.head == info->xmit.tail) -- break; -- } while (--count > 0); -- -- if (CIRC_CNT(info->xmit.head, -- info->xmit.tail, -- AMBA_XMIT_SIZE) < WAKEUP_CHARS) -- ambauart_event(info, EVT_WRITE_WAKEUP); -- -- if (info->xmit.head == info->xmit.tail) { -- ambauart_disable_tx_interrupt(info); -- } --} -- --static void ambauart_modem_status(struct amba_info *info) --{ -- unsigned int status, delta; -- struct amba_icount *icount = &info->state->icount; -- -- status = UART_GET_FR(info->port) & AMBA_UARTFR_MODEM_ANY; -- -- delta = status ^ info->old_status; -- info->old_status = status; -- -- if (!delta) -- return; -- -- if (delta & AMBA_UARTFR_DCD) { -- icount->dcd++; --#ifdef CONFIG_HARD_PPS -- if ((info->flags & ASYNC_HARDPPS_CD) && -- (status & AMBA_UARTFR_DCD) -- hardpps(); --#endif -- if (info->flags & ASYNC_CHECK_CD) { -- if (status & AMBA_UARTFR_DCD) -- wake_up_interruptible(&info->open_wait); -- else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && -- (info->flags & ASYNC_CALLOUT_NOHUP))) { -- if (info->tty) -- tty_hangup(info->tty); -- } -- } -- } -- -- if (delta & AMBA_UARTFR_DSR) -- icount->dsr++; -- -- if (delta & AMBA_UARTFR_CTS) { -- icount->cts++; -- -- if (info->flags & ASYNC_CTS_FLOW) { -- status &= AMBA_UARTFR_CTS; -- -- if (info->tty->hw_stopped) { -- if (status) { -- info->tty->hw_stopped = 0; -- ambauart_enable_tx_interrupt(info); -- ambauart_event(info, EVT_WRITE_WAKEUP); -- } -- } else { -- if (!status) { -- info->tty->hw_stopped = 1; -- ambauart_disable_tx_interrupt(info); -- } -- } -- } -- } -- wake_up_interruptible(&info->delta_msr_wait); -- --} -- --static void ambauart_int(int irq, void *dev_id, struct pt_regs *regs) --{ -- struct amba_info *info = dev_id; -- unsigned int status, pass_counter = 0; -- --#if DEBUG_LEDS -- // tell the world -- set_leds(get_leds() | RED_LED); --#endif -- -- status = UART_GET_INT_STATUS(info->port); -- do { -- /* -- * FIXME: what about clearing the interrupts? -- */ -- -- if (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS)) --#ifdef SUPPORT_SYSRQ -- ambauart_rx_chars(info, regs); --#else -- ambauart_rx_chars(info); --#endif -- if (status & AMBA_UARTIIR_TIS) -- ambauart_tx_chars(info); -- if (status & AMBA_UARTIIR_MIS) -- ambauart_modem_status(info); -- if (pass_counter++ > AMBA_ISR_PASS_LIMIT) -- break; -- -- status = UART_GET_INT_STATUS(info->port); -- } while (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS | AMBA_UARTIIR_TIS)); -- --#if DEBUG_LEDS -- // tell the world -- set_leds(get_leds() & ~RED_LED); --#endif --} -- --static void ambauart_tasklet_action(unsigned long data) --{ -- struct amba_info *info = (struct amba_info *)data; -- struct tty_struct *tty; -- -- tty = info->tty; -- if (!tty || !test_and_clear_bit(EVT_WRITE_WAKEUP, &info->event)) -- return; -- -- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && -- tty->ldisc.write_wakeup) -- (tty->ldisc.write_wakeup)(tty); -- wake_up_interruptible(&tty->write_wait); --} -- --static int ambauart_startup(struct amba_info *info) --{ -- unsigned long flags; -- unsigned long page; -- int retval = 0; -- -- page = get_zeroed_page(GFP_KERNEL); -- if (!page) -- return -ENOMEM; -- -- save_flags(flags); cli(); -- -- if (info->flags & ASYNC_INITIALIZED) { -- free_page(page); -- goto errout; -- } -- -- if (info->xmit.buf) -- free_page(page); -- else -- info->xmit.buf = (unsigned char *) page; -- -- /* -- * Allocate the IRQ -- */ -- retval = request_irq(info->port->irq, ambauart_int, 0, "amba", info); -- if (retval) { -- if (capable(CAP_SYS_ADMIN)) { -- if (info->tty) -- set_bit(TTY_IO_ERROR, &info->tty->flags); -- retval = 0; -- } -- goto errout; -- } -- -- info->mctrl = 0; -- if (info->tty->termios->c_cflag & CBAUD) -- info->mctrl = TIOCM_RTS | TIOCM_DTR; -- info->port->set_mctrl(info->port, info->mctrl); -- -- /* -- * initialise the old status of the modem signals -- */ -- info->old_status = UART_GET_FR(info->port) & AMBA_UARTFR_MODEM_ANY; -- -- /* -- * Finally, enable interrupts -- */ -- ambauart_enable_rx_interrupt(info); -- -- if (info->tty) -- clear_bit(TTY_IO_ERROR, &info->tty->flags); -- info->xmit.head = info->xmit.tail = 0; -- -- /* -- * Set up the tty->alt_speed kludge -- */ -- if (info->tty) { -- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) -- info->tty->alt_speed = 57600; -- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) -- info->tty->alt_speed = 115200; -- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) -- info->tty->alt_speed = 230400; -- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) -- info->tty->alt_speed = 460800; -- } -- -- /* -- * and set the speed of the serial port -- */ -- ambauart_change_speed(info, 0); -- -- info->flags |= ASYNC_INITIALIZED; -- restore_flags(flags); -- return 0; -- --errout: -- restore_flags(flags); -- return retval; --} -- --/* -- * This routine will shutdown a serial port; interrupts are disabled, and -- * DTR is dropped if the hangup on close termio flag is on. -- */ --static void ambauart_shutdown(struct amba_info *info) --{ -- unsigned long flags; -- -- if (!(info->flags & ASYNC_INITIALIZED)) -- return; -- -- save_flags(flags); cli(); /* Disable interrupts */ -- -- /* -- * clear delta_msr_wait queue to avoid mem leaks: we may free the irq -- * here so the queue might never be woken up -- */ -- wake_up_interruptible(&info->delta_msr_wait); -- -- /* -- * Free the IRQ -- */ -- free_irq(info->port->irq, info); -- -- if (info->xmit.buf) { -- unsigned long pg = (unsigned long) info->xmit.buf; -- info->xmit.buf = NULL; -- free_page(pg); -- } -- -- /* -- * disable all interrupts, disable the port -- */ -- UART_PUT_CR(info->port, 0); -- -- /* disable break condition and fifos */ -- UART_PUT_LCRH(info->port, UART_GET_LCRH(info->port) & -- ~(AMBA_UARTLCR_H_BRK | AMBA_UARTLCR_H_FEN)); -- -- if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) -- info->mctrl &= ~(TIOCM_DTR|TIOCM_RTS); -- info->port->set_mctrl(info->port, info->mctrl); -- -- /* kill off our tasklet */ -- tasklet_kill(&info->tlet); -- if (info->tty) -- set_bit(TTY_IO_ERROR, &info->tty->flags); -- -- info->flags &= ~ASYNC_INITIALIZED; -- restore_flags(flags); --} -- --static void ambauart_change_speed(struct amba_info *info, struct termios *old_termios) --{ -- unsigned int lcr_h, baud, quot, cflag, old_cr, bits; -- unsigned long flags; -- -- if (!info->tty || !info->tty->termios) -- return; -- -- cflag = info->tty->termios->c_cflag; -- --#if DEBUG -- printk("ambauart_set_cflag(0x%x) called\n", cflag); --#endif -- /* byte size and parity */ -- switch (cflag & CSIZE) { -- case CS5: lcr_h = AMBA_UARTLCR_H_WLEN_5; bits = 7; break; -- case CS6: lcr_h = AMBA_UARTLCR_H_WLEN_6; bits = 8; break; -- case CS7: lcr_h = AMBA_UARTLCR_H_WLEN_7; bits = 9; break; -- default: lcr_h = AMBA_UARTLCR_H_WLEN_8; bits = 10; break; // CS8 -- } -- if (cflag & CSTOPB) { -- lcr_h |= AMBA_UARTLCR_H_STP2; -- bits ++; -- } -- if (cflag & PARENB) { -- lcr_h |= AMBA_UARTLCR_H_PEN; -- bits++; -- if (!(cflag & PARODD)) -- lcr_h |= AMBA_UARTLCR_H_EPS; -- } -- if (info->port->fifosize > 1) -- lcr_h |= AMBA_UARTLCR_H_FEN; -- -- do { -- /* Determine divisor based on baud rate */ -- baud = tty_get_baud_rate(info->tty); -- if (!baud) -- baud = 9600; -- -- if (baud == 38400 && -- ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) -- quot = info->state->custom_divisor; -- else -- quot = (info->port->uartclk / (16 * baud)) - 1; -- -- if (!quot && old_termios) { -- info->tty->termios->c_cflag &= ~CBAUD; -- info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); -- old_termios = NULL; -- } -- } while (quot == 0 && old_termios); -- -- /* As a last resort, if the quotient is zero, default to 9600 bps */ -- if (!quot) -- quot = (info->port->uartclk / (16 * 9600)) - 1; -- -- info->timeout = (info->port->fifosize * HZ * bits * quot) / -- (info->port->uartclk / 16); -- info->timeout += HZ/50; /* Add .02 seconds of slop */ -- -- if (cflag & CRTSCTS) -- info->flags |= ASYNC_CTS_FLOW; -- else -- info->flags &= ~ASYNC_CTS_FLOW; -- if (cflag & CLOCAL) -- info->flags &= ~ASYNC_CHECK_CD; -- else -- info->flags |= ASYNC_CHECK_CD; -- -- /* -- * Set up parity check flag -- */ --#define RELEVENT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) -- -- info->read_status_mask = AMBA_UARTRSR_OE; -- if (I_INPCK(info->tty)) -- info->read_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE; -- if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) -- info->read_status_mask |= AMBA_UARTRSR_BE; -- -- /* -- * Characters to ignore -- */ -- info->ignore_status_mask = 0; -- if (I_IGNPAR(info->tty)) -- info->ignore_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE; -- if (I_IGNBRK(info->tty)) { -- info->ignore_status_mask |= AMBA_UARTRSR_BE; -- /* -- * If we're ignoring parity and break indicators, -- * ignore overruns to (for real raw support). -- */ -- if (I_IGNPAR(info->tty)) -- info->ignore_status_mask |= AMBA_UARTRSR_OE; -- } -- -- /* first, disable everything */ -- save_flags(flags); cli(); -- old_cr = UART_GET_CR(info->port) &= ~AMBA_UARTCR_MSIE; -- -- if ((info->flags & ASYNC_HARDPPS_CD) || -- (cflag & CRTSCTS) || -- !(cflag & CLOCAL)) -- old_cr |= AMBA_UARTCR_MSIE; -- -- UART_PUT_CR(info->port, 0); -- restore_flags(flags); -- -- /* Set baud rate */ -- UART_PUT_LCRM(info->port, ((quot & 0xf00) >> 8)); -- UART_PUT_LCRL(info->port, (quot & 0xff)); -- -- /* -- * ----------v----------v----------v----------v----- -- * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L -- * ----------^----------^----------^----------^----- -- */ -- UART_PUT_LCRH(info->port, lcr_h); -- UART_PUT_CR(info->port, old_cr); --} -- --static void ambauart_put_char(struct tty_struct *tty, u_char ch) --{ -- struct amba_info *info = tty->driver_data; -- unsigned long flags; -- -- if (!tty || !info->xmit.buf) -- return; -- -- save_flags(flags); cli(); -- if (CIRC_SPACE(info->xmit.head, info->xmit.tail, AMBA_XMIT_SIZE) != 0) { -- info->xmit.buf[info->xmit.head] = ch; -- info->xmit.head = (info->xmit.head + 1) & (AMBA_XMIT_SIZE - 1); -- } -- restore_flags(flags); --} -- --static void ambauart_flush_chars(struct tty_struct *tty) --{ -- struct amba_info *info = tty->driver_data; -- unsigned long flags; -- -- if (info->xmit.head == info->xmit.tail -- || tty->stopped -- || tty->hw_stopped -- || !info->xmit.buf) -- return; -- -- save_flags(flags); cli(); -- ambauart_enable_tx_interrupt(info); -- restore_flags(flags); --} -- --static int ambauart_write(struct tty_struct *tty, int from_user, -- const u_char * buf, int count) --{ -- struct amba_info *info = tty->driver_data; -- unsigned long flags; -- int c, ret = 0; -- -- if (!tty || !info->xmit.buf || !tmp_buf) -- return 0; -- -- save_flags(flags); -- if (from_user) { -- down(&tmp_buf_sem); -- while (1) { -- int c1; -- c = CIRC_SPACE_TO_END(info->xmit.head, -- info->xmit.tail, -- AMBA_XMIT_SIZE); -- if (count < c) -- c = count; -- if (c <= 0) -- break; -- -- c -= copy_from_user(tmp_buf, buf, c); -- if (!c) { -- if (!ret) -- ret = -EFAULT; -- break; -- } -- cli(); -- c1 = CIRC_SPACE_TO_END(info->xmit.head, -- info->xmit.tail, -- AMBA_XMIT_SIZE); -- if (c1 < c) -- c = c1; -- memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c); -- info->xmit.head = (info->xmit.head + c) & -- (AMBA_XMIT_SIZE - 1); -- restore_flags(flags); -- buf += c; -- count -= c; -- ret += c; -- } -- up(&tmp_buf_sem); -- } else { -- cli(); -- while (1) { -- c = CIRC_SPACE_TO_END(info->xmit.head, -- info->xmit.tail, -- AMBA_XMIT_SIZE); -- if (count < c) -- c = count; -- if (c <= 0) -- break; -- memcpy(info->xmit.buf + info->xmit.head, buf, c); -- info->xmit.head = (info->xmit.head + c) & -- (AMBA_XMIT_SIZE - 1); -- buf += c; -- count -= c; -- ret += c; -- } -- restore_flags(flags); -- } -- if (info->xmit.head != info->xmit.tail -- && !tty->stopped -- && !tty->hw_stopped) -- ambauart_enable_tx_interrupt(info); -- return ret; --} -- --static int ambauart_write_room(struct tty_struct *tty) --{ -- struct amba_info *info = tty->driver_data; -- -- return CIRC_SPACE(info->xmit.head, info->xmit.tail, AMBA_XMIT_SIZE); --} -- --static int ambauart_chars_in_buffer(struct tty_struct *tty) --{ -- struct amba_info *info = tty->driver_data; -- -- return CIRC_CNT(info->xmit.head, info->xmit.tail, AMBA_XMIT_SIZE); --} -- --static void ambauart_flush_buffer(struct tty_struct *tty) --{ -- struct amba_info *info = tty->driver_data; -- unsigned long flags; -- --#if DEBUG -- printk("ambauart_flush_buffer(%d) called\n", -- MINOR(tty->device) - tty->driver.minor_start); --#endif -- save_flags(flags); cli(); -- info->xmit.head = info->xmit.tail = 0; -- restore_flags(flags); -- wake_up_interruptible(&tty->write_wait); -- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && -- tty->ldisc.write_wakeup) -- (tty->ldisc.write_wakeup)(tty); --} -- --/* -- * This function is used to send a high-priority XON/XOFF character to -- * the device -- */ --static void ambauart_send_xchar(struct tty_struct *tty, char ch) --{ -- struct amba_info *info = tty->driver_data; -- -- info->x_char = ch; -- if (ch) -- ambauart_enable_tx_interrupt(info); --} -- --static void ambauart_throttle(struct tty_struct *tty) --{ -- struct amba_info *info = tty->driver_data; -- unsigned long flags; -- -- if (I_IXOFF(tty)) -- ambauart_send_xchar(tty, STOP_CHAR(tty)); -- -- if (tty->termios->c_cflag & CRTSCTS) { -- save_flags(flags); cli(); -- info->mctrl &= ~TIOCM_RTS; -- info->port->set_mctrl(info->port, info->mctrl); -- restore_flags(flags); -- } --} -- --static void ambauart_unthrottle(struct tty_struct *tty) --{ -- struct amba_info *info = (struct amba_info *) tty->driver_data; -- unsigned long flags; -- -- if (I_IXOFF(tty)) { -- if (info->x_char) -- info->x_char = 0; -- else -- ambauart_send_xchar(tty, START_CHAR(tty)); -- } -- -- if (tty->termios->c_cflag & CRTSCTS) { -- save_flags(flags); cli(); -- info->mctrl |= TIOCM_RTS; -- info->port->set_mctrl(info->port, info->mctrl); -- restore_flags(flags); -- } --} -- --static int get_serial_info(struct amba_info *info, struct serial_struct *retinfo) --{ -- struct amba_state *state = info->state; -- struct amba_port *port = info->port; -- struct serial_struct tmp; -- -- memset(&tmp, 0, sizeof(tmp)); -- tmp.type = 0; -- tmp.line = state->line; -- tmp.port = port->uart_base; -- if (HIGH_BITS_OFFSET) -- tmp.port_high = port->uart_base >> HIGH_BITS_OFFSET; -- tmp.irq = port->irq; -- tmp.flags = 0; -- tmp.xmit_fifo_size = port->fifosize; -- tmp.baud_base = port->uartclk / 16; -- tmp.close_delay = state->close_delay; -- tmp.closing_wait = state->closing_wait; -- tmp.custom_divisor = state->custom_divisor; -- -- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) -- return -EFAULT; -- return 0; --} -- --static int set_serial_info(struct amba_info *info, -- struct serial_struct *newinfo) --{ -- struct serial_struct new_serial; -- struct amba_state *state, old_state; -- struct amba_port *port; -- unsigned long new_port; -- unsigned int i, change_irq, change_port; -- int retval = 0; -- -- if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) -- return -EFAULT; -- -- state = info->state; -- old_state = *state; -- port = info->port; -- -- new_port = new_serial.port; -- if (HIGH_BITS_OFFSET) -- new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; -- -- change_irq = new_serial.irq != port->irq; -- change_port = new_port != port->uart_base; -- -- if (!capable(CAP_SYS_ADMIN)) { -- if (change_irq || change_port || -- (new_serial.baud_base != port->uartclk / 16) || -- (new_serial.close_delay != state->close_delay) || -- (new_serial.xmit_fifo_size != port->fifosize) || -- ((new_serial.flags & ~ASYNC_USR_MASK) != -- (state->flags & ~ASYNC_USR_MASK))) -- return -EPERM; -- state->flags = ((state->flags & ~ASYNC_USR_MASK) | -- (new_serial.flags & ASYNC_USR_MASK)); -- info->flags = ((info->flags & ~ASYNC_USR_MASK) | -- (new_serial.flags & ASYNC_USR_MASK)); -- state->custom_divisor = new_serial.custom_divisor; -- goto check_and_exit; -- } -- -- if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) || -- (new_serial.baud_base < 9600)) -- return -EINVAL; -- -- if (new_serial.type && change_port) { -- for (i = 0; i < SERIAL_AMBA_NR; i++) -- if ((port != amba_ports + i) && -- amba_ports[i].uart_base != new_port) -- return -EADDRINUSE; -- } -- -- if ((change_port || change_irq) && (state->count > 1)) -- return -EBUSY; -- -- /* -- * OK, past this point, all the error checking has been done. -- * At this point, we start making changes..... -- */ -- port->uartclk = new_serial.baud_base * 16; -- state->flags = ((state->flags & ~ASYNC_FLAGS) | -- (new_serial.flags & ASYNC_FLAGS)); -- info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) | -- (info->flags & ASYNC_INTERNAL_FLAGS)); -- state->custom_divisor = new_serial.custom_divisor; -- state->close_delay = new_serial.close_delay * HZ / 100; -- state->closing_wait = new_serial.closing_wait * HZ / 100; -- info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; -- port->fifosize = new_serial.xmit_fifo_size; -- -- if (change_port || change_irq) { -- /* -- * We need to shutdown the serial port at the old -- * port/irq combination. -- */ -- ambauart_shutdown(info); -- port->irq = new_serial.irq; -- port->uart_base = new_port; -- } -- --check_and_exit: -- if (!port->uart_base) -- return 0; -- if (info->flags & ASYNC_INITIALIZED) { -- if ((old_state.flags & ASYNC_SPD_MASK) != -- (state->flags & ASYNC_SPD_MASK) || -- (old_state.custom_divisor != state->custom_divisor)) { -- if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) -- info->tty->alt_speed = 57600; -- if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) -- info->tty->alt_speed = 115200; -- if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) -- info->tty->alt_speed = 230400; -- if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) -- info->tty->alt_speed = 460800; -- ambauart_change_speed(info, NULL); -- } -- } else -- retval = ambauart_startup(info); -- return retval; --} -- -- --/* -- * get_lsr_info - get line status register info -- */ --static int get_lsr_info(struct amba_info *info, unsigned int *value) --{ -- unsigned int result, status; -- unsigned long flags; -- -- save_flags(flags); cli(); -- status = UART_GET_FR(info->port); -- restore_flags(flags); -- result = status & AMBA_UARTFR_BUSY ? TIOCSER_TEMT : 0; -- -- /* -- * If we're about to load something into the transmit -- * register, we'll pretend the transmitter isn't empty to -- * avoid a race condition (depending on when the transmit -- * interrupt happens). -- */ -- if (info->x_char || -- ((CIRC_CNT(info->xmit.head, info->xmit.tail, -- AMBA_XMIT_SIZE) > 0) && -- !info->tty->stopped && !info->tty->hw_stopped)) -- result &= TIOCSER_TEMT; -- -- return put_user(result, value); --} -- --static int get_modem_info(struct amba_info *info, unsigned int *value) --{ -- unsigned int result = info->mctrl; -- unsigned int status; -- -- status = UART_GET_FR(info->port); -- if (status & AMBA_UARTFR_DCD) -- result |= TIOCM_CAR; -- if (status & AMBA_UARTFR_DSR) -- result |= TIOCM_DSR; -- if (status & AMBA_UARTFR_CTS) -- result |= TIOCM_CTS; -- -- return put_user(result, value); --} -- --static int set_modem_info(struct amba_info *info, unsigned int cmd, -- unsigned int *value) --{ -- unsigned int arg, old; -- unsigned long flags; -- -- if (get_user(arg, value)) -- return -EFAULT; -- -- old = info->mctrl; -- switch (cmd) { -- case TIOCMBIS: -- info->mctrl |= arg; -- break; -- -- case TIOCMBIC: -- info->mctrl &= ~arg; -- break; -- -- case TIOCMSET: -- info->mctrl = arg; -- break; -- -- default: -- return -EINVAL; -- } -- save_flags(flags); cli(); -- if (old != info->mctrl) -- info->port->set_mctrl(info->port, info->mctrl); -- restore_flags(flags); -- return 0; --} -- --static void ambauart_break_ctl(struct tty_struct *tty, int break_state) --{ -- struct amba_info *info = tty->driver_data; -- unsigned long flags; -- unsigned int lcr_h; -- -- save_flags(flags); cli(); -- lcr_h = UART_GET_LCRH(info->port); -- if (break_state == -1) -- lcr_h |= AMBA_UARTLCR_H_BRK; -- else -- lcr_h &= ~AMBA_UARTLCR_H_BRK; -- UART_PUT_LCRH(info->port, lcr_h); -- restore_flags(flags); --} -- --static int ambauart_ioctl(struct tty_struct *tty, struct file *file, -- unsigned int cmd, unsigned long arg) --{ -- struct amba_info *info = tty->driver_data; -- struct amba_icount cprev, cnow; -- struct serial_icounter_struct icount; -- unsigned long flags; -- -- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && -- (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && -- (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { -- if (tty->flags & (1 << TTY_IO_ERROR)) -- return -EIO; -- } -- -- switch (cmd) { -- case TIOCMGET: -- return get_modem_info(info, (unsigned int *)arg); -- case TIOCMBIS: -- case TIOCMBIC: -- case TIOCMSET: -- return set_modem_info(info, cmd, (unsigned int *)arg); -- case TIOCGSERIAL: -- return get_serial_info(info, -- (struct serial_struct *)arg); -- case TIOCSSERIAL: -- return set_serial_info(info, -- (struct serial_struct *)arg); -- case TIOCSERGETLSR: /* Get line status register */ -- return get_lsr_info(info, (unsigned int *)arg); -- /* -- * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change -- * - mask passed in arg for lines of interest -- * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) -- * Caller should use TIOCGICOUNT to see which one it was -- */ -- case TIOCMIWAIT: -- save_flags(flags); cli(); -- /* note the counters on entry */ -- cprev = info->state->icount; -- /* Force modem status interrupts on */ -- UART_PUT_CR(info->port, UART_GET_CR(info->port) | AMBA_UARTCR_MSIE); -- restore_flags(flags); -- while (1) { -- interruptible_sleep_on(&info->delta_msr_wait); -- /* see if a signal did it */ -- if (signal_pending(current)) -- return -ERESTARTSYS; -- save_flags(flags); cli(); -- cnow = info->state->icount; /* atomic copy */ -- restore_flags(flags); -- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && -- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) -- return -EIO; /* no change => error */ -- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || -- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || -- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || -- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { -- return 0; -- } -- cprev = cnow; -- } -- /* NOTREACHED */ -- -- /* -- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) -- * Return: write counters to the user passed counter struct -- * NB: both 1->0 and 0->1 transitions are counted except for -- * RI where only 0->1 is counted. -- */ -- case TIOCGICOUNT: -- save_flags(flags); cli(); -- cnow = info->state->icount; -- restore_flags(flags); -- icount.cts = cnow.cts; -- icount.dsr = cnow.dsr; -- icount.rng = cnow.rng; -- icount.dcd = cnow.dcd; -- icount.rx = cnow.rx; -- icount.tx = cnow.tx; -- icount.frame = cnow.frame; -- icount.overrun = cnow.overrun; -- icount.parity = cnow.parity; -- icount.brk = cnow.brk; -- icount.buf_overrun = cnow.buf_overrun; -- -- return copy_to_user((void *)arg, &icount, sizeof(icount)) -- ? -EFAULT : 0; -- -- default: -- return -ENOIOCTLCMD; -- } -- return 0; --} -- --static void ambauart_set_termios(struct tty_struct *tty, struct termios *old_termios) --{ -- struct amba_info *info = tty->driver_data; -- unsigned long flags; -- unsigned int cflag = tty->termios->c_cflag; -- -- if ((cflag ^ old_termios->c_cflag) == 0 && -- RELEVENT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) -- return; -- -- ambauart_change_speed(info, old_termios); -- -- /* Handle transition to B0 status */ -- if ((old_termios->c_cflag & CBAUD) && -- !(cflag & CBAUD)) { -- save_flags(flags); cli(); -- info->mctrl &= ~(TIOCM_RTS | TIOCM_DTR); -- info->port->set_mctrl(info->port, info->mctrl); -- restore_flags(flags); -- } -- -- /* Handle transition away from B0 status */ -- if (!(old_termios->c_cflag & CBAUD) && -- (cflag & CBAUD)) { -- save_flags(flags); cli(); -- info->mctrl |= TIOCM_DTR; -- if (!(cflag & CRTSCTS) || -- !test_bit(TTY_THROTTLED, &tty->flags)) -- info->mctrl |= TIOCM_RTS; -- info->port->set_mctrl(info->port, info->mctrl); -- restore_flags(flags); -- } -- -- /* Handle turning off CRTSCTS */ -- if ((old_termios->c_cflag & CRTSCTS) && -- !(cflag & CRTSCTS)) { -- tty->hw_stopped = 0; -- ambauart_start(tty); -- } -- --#if 0 -- /* -- * No need to wake up processes in open wait, since they -- * sample the CLOCAL flag once, and don't recheck it. -- * XXX It's not clear whether the current behavior is correct -- * or not. Hence, this may change..... -- */ -- if (!(old_termios->c_cflag & CLOCAL) && -- (tty->termios->c_cflag & CLOCAL)) -- wake_up_interruptible(&info->open_wait); --#endif --} -- --static void ambauart_close(struct tty_struct *tty, struct file *filp) --{ -- struct amba_info *info = tty->driver_data; -- struct amba_state *state; -- unsigned long flags; -- -- if (!info) -- return; -- -- state = info->state; -- --#if DEBUG -- printk("ambauart_close() called\n"); --#endif -- -- save_flags(flags); cli(); -- -- if (tty_hung_up_p(filp)) { -- MOD_DEC_USE_COUNT; -- restore_flags(flags); -- return; -- } -- -- if ((tty->count == 1) && (state->count != 1)) { -- /* -- * Uh, oh. tty->count is 1, which means that the tty -- * structure will be freed. state->count should always -- * be one in these conditions. If it's greater than -- * one, we've got real problems, since it means the -- * serial port won't be shutdown. -- */ -- printk("ambauart_close: bad serial port count; tty->count is 1, " -- "state->count is %d\n", state->count); -- state->count = 1; -- } -- if (--state->count < 0) { -- printk("rs_close: bad serial port count for %s%d: %d\n", -- tty->driver.name, info->state->line, state->count); -- state->count = 0; -- } -- if (state->count) { -- MOD_DEC_USE_COUNT; -- restore_flags(flags); -- return; -- } -- info->flags |= ASYNC_CLOSING; -- restore_flags(flags); -- /* -- * Save the termios structure, since this port may have -- * separate termios for callout and dialin. -- */ -- if (info->flags & ASYNC_NORMAL_ACTIVE) -- info->state->normal_termios = *tty->termios; -- if (info->flags & ASYNC_CALLOUT_ACTIVE) -- info->state->callout_termios = *tty->termios; -- /* -- * Now we wait for the transmit buffer to clear; and we notify -- * the line discipline to only process XON/XOFF characters. -- */ -- tty->closing = 1; -- if (info->state->closing_wait != ASYNC_CLOSING_WAIT_NONE) -- tty_wait_until_sent(tty, info->state->closing_wait); -- /* -- * At this point, we stop accepting input. To do this, we -- * disable the receive line status interrupts. -- */ -- if (info->flags & ASYNC_INITIALIZED) { -- ambauart_disable_rx_interrupt(info); -- /* -- * Before we drop DTR, make sure the UART transmitter -- * has completely drained; this is especially -- * important if there is a transmit FIFO! -- */ -- ambauart_wait_until_sent(tty, info->timeout); -- } -- ambauart_shutdown(info); -- if (tty->driver.flush_buffer) -- tty->driver.flush_buffer(tty); -- if (tty->ldisc.flush_buffer) -- tty->ldisc.flush_buffer(tty); -- tty->closing = 0; -- info->event = 0; -- info->tty = NULL; -- if (info->blocked_open) { -- if (info->state->close_delay) { -- set_current_state(TASK_INTERRUPTIBLE); -- schedule_timeout(info->state->close_delay); -- } -- wake_up_interruptible(&info->open_wait); -- } -- info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| -- ASYNC_CLOSING); -- wake_up_interruptible(&info->close_wait); -- MOD_DEC_USE_COUNT; --} -- --static void ambauart_wait_until_sent(struct tty_struct *tty, int timeout) --{ -- struct amba_info *info = (struct amba_info *) tty->driver_data; -- unsigned long char_time, expire; -- unsigned int status; -- -- if (info->port->fifosize == 0) -- return; -- -- /* -- * Set the check interval to be 1/5 of the estimated time to -- * send a single character, and make it at least 1. The check -- * interval should also be less than the timeout. -- * -- * Note: we have to use pretty tight timings here to satisfy -- * the NIST-PCTS. -- */ -- char_time = (info->timeout - HZ/50) / info->port->fifosize; -- char_time = char_time / 5; -- if (char_time == 0) -- char_time = 1; -- if (timeout && timeout < char_time) -- char_time = timeout; -- /* -- * If the transmitter hasn't cleared in twice the approximate -- * amount of time to send the entire FIFO, it probably won't -- * ever clear. This assumes the UART isn't doing flow -- * control, which is currently the case. Hence, if it ever -- * takes longer than info->timeout, this is probably due to a -- * UART bug of some kind. So, we clamp the timeout parameter at -- * 2*info->timeout. -- */ -- if (!timeout || timeout > 2 * info->timeout) -- timeout = 2 * info->timeout; -- -- expire = jiffies + timeout; --#if DEBUG -- printk("ambauart_wait_until_sent(%d), jiff=%lu, expire=%lu...\n", -- MINOR(tty->device) - tty->driver.minor_start, jiffies, -- expire); --#endif -- while (UART_GET_FR(info->port) & AMBA_UARTFR_BUSY) { -- set_current_state(TASK_INTERRUPTIBLE); -- schedule_timeout(char_time); -- if (signal_pending(current)) -- break; -- if (timeout && time_after(jiffies, expire)) -- break; -- status = UART_GET_FR(info->port); -- } -- set_current_state(TASK_RUNNING); --} -- --static void ambauart_hangup(struct tty_struct *tty) --{ -- struct amba_info *info = tty->driver_data; -- struct amba_state *state = info->state; -- -- ambauart_flush_buffer(tty); -- if (info->flags & ASYNC_CLOSING) -- return; -- ambauart_shutdown(info); -- info->event = 0; -- state->count = 0; -- info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); -- info->tty = NULL; -- wake_up_interruptible(&info->open_wait); --} -- --static int block_til_ready(struct tty_struct *tty, struct file *filp, -- struct amba_info *info) --{ -- DECLARE_WAITQUEUE(wait, current); -- struct amba_state *state = info->state; -- unsigned long flags; -- int do_clocal = 0, extra_count = 0, retval; -- -- /* -- * If the device is in the middle of being closed, then block -- * until it's done, and then try again. -- */ -- if (tty_hung_up_p(filp) || -- (info->flags & ASYNC_CLOSING)) { -- if (info->flags & ASYNC_CLOSING) -- interruptible_sleep_on(&info->close_wait); -- return (info->flags & ASYNC_HUP_NOTIFY) ? -- -EAGAIN : -ERESTARTSYS; -- } -- -- /* -- * If this is a callout device, then just make sure the normal -- * device isn't being used. -- */ -- if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { -- if (info->flags & ASYNC_NORMAL_ACTIVE) -- return -EBUSY; -- if ((info->flags & ASYNC_CALLOUT_ACTIVE) && -- (info->flags & ASYNC_SESSION_LOCKOUT) && -- (info->session != current->session)) -- return -EBUSY; -- if ((info->flags & ASYNC_CALLOUT_ACTIVE) && -- (info->flags & ASYNC_PGRP_LOCKOUT) && -- (info->pgrp != current->pgrp)) -- return -EBUSY; -- info->flags |= ASYNC_CALLOUT_ACTIVE; -- return 0; -- } -- -- /* -- * If non-blocking mode is set, or the port is not enabled, -- * then make the check up front and then exit. -- */ -- if ((filp->f_flags & O_NONBLOCK) || -- (tty->flags & (1 << TTY_IO_ERROR))) { -- if (info->flags & ASYNC_CALLOUT_ACTIVE) -- return -EBUSY; -- info->flags |= ASYNC_NORMAL_ACTIVE; -- return 0; -- } -- -- if (info->flags & ASYNC_CALLOUT_ACTIVE) { -- if (state->normal_termios.c_cflag & CLOCAL) -- do_clocal = 1; -- } else { -- if (tty->termios->c_cflag & CLOCAL) -- do_clocal = 1; -- } -- -- /* -- * Block waiting for the carrier detect and the line to become -- * free (i.e., not in use by the callout). While we are in -- * this loop, state->count is dropped by one, so that -- * rs_close() knows when to free things. We restore it upon -- * exit, either normal or abnormal. -- */ -- retval = 0; -- add_wait_queue(&info->open_wait, &wait); -- save_flags(flags); cli(); -- if (!tty_hung_up_p(filp)) { -- extra_count = 1; -- state->count--; -- } -- restore_flags(flags); -- info->blocked_open++; -- while (1) { -- save_flags(flags); cli(); -- if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && -- (tty->termios->c_cflag & CBAUD)) { -- info->mctrl = TIOCM_DTR | TIOCM_RTS; -- info->port->set_mctrl(info->port, info->mctrl); -- } -- restore_flags(flags); -- set_current_state(TASK_INTERRUPTIBLE); -- if (tty_hung_up_p(filp) || -- !(info->flags & ASYNC_INITIALIZED)) { -- if (info->flags & ASYNC_HUP_NOTIFY) -- retval = -EAGAIN; -- else -- retval = -ERESTARTSYS; -- break; -- } -- if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && -- !(info->flags & ASYNC_CLOSING) && -- (do_clocal || (UART_GET_FR(info->port) & AMBA_UARTFR_DCD))) -- break; -- if (signal_pending(current)) { -- retval = -ERESTARTSYS; -- break; -- } -- schedule(); -- } -- set_current_state(TASK_RUNNING); -- remove_wait_queue(&info->open_wait, &wait); -- if (extra_count) -- state->count++; -- info->blocked_open--; -- if (retval) -- return retval; -- info->flags |= ASYNC_NORMAL_ACTIVE; -- return 0; --} -- --static struct amba_info *ambauart_get(int line) --{ -- struct amba_info *info; -- struct amba_state *state = amba_state + line; -- -- state->count++; -- if (state->info) -- return state->info; -- info = kmalloc(sizeof(struct amba_info), GFP_KERNEL); -- if (info) { -- memset(info, 0, sizeof(struct amba_info)); -- init_waitqueue_head(&info->open_wait); -- init_waitqueue_head(&info->close_wait); -- init_waitqueue_head(&info->delta_msr_wait); -- info->flags = state->flags; -- info->state = state; -- info->port = amba_ports + line; -- tasklet_init(&info->tlet, ambauart_tasklet_action, -- (unsigned long)info); -- } -- if (state->info) { -- kfree(info); -- return state->info; -- } -- state->info = info; -- return info; --} -- --static int ambauart_open(struct tty_struct *tty, struct file *filp) --{ -- struct amba_info *info; -- int retval, line = MINOR(tty->device) - tty->driver.minor_start; -- --#if DEBUG -- printk("ambauart_open(%d) called\n", line); --#endif -- -- // is this a line that we've got? -- MOD_INC_USE_COUNT; -- if (line >= SERIAL_AMBA_NR) { -- MOD_DEC_USE_COUNT; -- return -ENODEV; -- } -- -- info = ambauart_get(line); -- if (!info) -- return -ENOMEM; -- -- tty->driver_data = info; -- info->tty = tty; -- info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; -- -- /* -- * Make sure we have the temporary buffer allocated -- */ -- if (!tmp_buf) { -- unsigned long page = get_zeroed_page(GFP_KERNEL); -- if (tmp_buf) -- free_page(page); -- else if (!page) { -- MOD_DEC_USE_COUNT; -- return -ENOMEM; -- } -- tmp_buf = (u_char *)page; -- } -- -- /* -- * If the port is in the middle of closing, bail out now. -- */ -- if (tty_hung_up_p(filp) || -- (info->flags & ASYNC_CLOSING)) { -- if (info->flags & ASYNC_CLOSING) -- interruptible_sleep_on(&info->close_wait); -- MOD_DEC_USE_COUNT; -- return -EAGAIN; -- } -- -- /* -- * Start up the serial port -- */ -- retval = ambauart_startup(info); -- if (retval) { -- MOD_DEC_USE_COUNT; -- return retval; -- } -- -- retval = block_til_ready(tty, filp, info); -- if (retval) { -- MOD_DEC_USE_COUNT; -- return retval; -- } -- -- if ((info->state->count == 1) && -- (info->flags & ASYNC_SPLIT_TERMIOS)) { -- if (tty->driver.subtype == SERIAL_TYPE_NORMAL) -- *tty->termios = info->state->normal_termios; -- else -- *tty->termios = info->state->callout_termios; -- } --#ifdef CONFIG_SERIAL_AMBA_CONSOLE -- if (ambauart_cons.cflag && ambauart_cons.index == line) { -- tty->termios->c_cflag = ambauart_cons.cflag; -- ambauart_cons.cflag = 0; -- } --#endif -- ambauart_change_speed(info, NULL); -- info->session = current->session; -- info->pgrp = current->pgrp; -- return 0; --} -- --int __init ambauart_init(void) --{ -- int i; -- -- ambanormal_driver.magic = TTY_DRIVER_MAGIC; -- ambanormal_driver.driver_name = "serial_amba"; -- ambanormal_driver.name = SERIAL_AMBA_NAME; -- ambanormal_driver.major = SERIAL_AMBA_MAJOR; -- ambanormal_driver.minor_start = SERIAL_AMBA_MINOR; -- ambanormal_driver.num = SERIAL_AMBA_NR; -- ambanormal_driver.type = TTY_DRIVER_TYPE_SERIAL; -- ambanormal_driver.subtype = SERIAL_TYPE_NORMAL; -- ambanormal_driver.init_termios = tty_std_termios; -- ambanormal_driver.init_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; -- ambanormal_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; -- ambanormal_driver.refcount = &ambauart_refcount; -- ambanormal_driver.table = ambauart_table; -- ambanormal_driver.termios = ambauart_termios; -- ambanormal_driver.termios_locked = ambauart_termios_locked; -- -- ambanormal_driver.open = ambauart_open; -- ambanormal_driver.close = ambauart_close; -- ambanormal_driver.write = ambauart_write; -- ambanormal_driver.put_char = ambauart_put_char; -- ambanormal_driver.flush_chars = ambauart_flush_chars; -- ambanormal_driver.write_room = ambauart_write_room; -- ambanormal_driver.chars_in_buffer = ambauart_chars_in_buffer; -- ambanormal_driver.flush_buffer = ambauart_flush_buffer; -- ambanormal_driver.ioctl = ambauart_ioctl; -- ambanormal_driver.throttle = ambauart_throttle; -- ambanormal_driver.unthrottle = ambauart_unthrottle; -- ambanormal_driver.send_xchar = ambauart_send_xchar; -- ambanormal_driver.set_termios = ambauart_set_termios; -- ambanormal_driver.stop = ambauart_stop; -- ambanormal_driver.start = ambauart_start; -- ambanormal_driver.hangup = ambauart_hangup; -- ambanormal_driver.break_ctl = ambauart_break_ctl; -- ambanormal_driver.wait_until_sent = ambauart_wait_until_sent; -- ambanormal_driver.read_proc = NULL; -- -- /* -- * The callout device is just like the normal device except for -- * the major number and the subtype code. -- */ -- ambacallout_driver = ambanormal_driver; -- ambacallout_driver.name = CALLOUT_AMBA_NAME; -- ambacallout_driver.major = CALLOUT_AMBA_MAJOR; -- ambacallout_driver.subtype = SERIAL_TYPE_CALLOUT; -- ambacallout_driver.read_proc = NULL; -- ambacallout_driver.proc_entry = NULL; -- -- if (tty_register_driver(&ambanormal_driver)) -- panic("Couldn't register AMBA serial driver\n"); -- if (tty_register_driver(&ambacallout_driver)) -- panic("Couldn't register AMBA callout driver\n"); -- -- for (i = 0; i < SERIAL_AMBA_NR; i++) { -- struct amba_state *state = amba_state + i; -- state->line = i; -- state->close_delay = 5 * HZ / 10; -- state->closing_wait = 30 * HZ; -- state->callout_termios = ambacallout_driver.init_termios; -- state->normal_termios = ambanormal_driver.init_termios; -- } -- -- return 0; --} -- --__initcall(ambauart_init); -- --#ifdef CONFIG_SERIAL_AMBA_CONSOLE --/************** console driver *****************/ -- --/* -- * This code is currently never used; console->read is never called. -- * Therefore, although we have an implementation, we don't use it. -- * FIXME: the "const char *s" should be fixed to "char *s" some day. -- * (when the definition in include/linux/console.h is also fixed) -- */ --#ifdef used_and_not_const_char_pointer --static int ambauart_console_read(struct console *co, const char *s, u_int count) --{ -- struct amba_port *port = &amba_ports[co->index]; -- unsigned int status; -- char *w; -- int c; --#if DEBUG -- printk("ambauart_console_read() called\n"); --#endif -- -- c = 0; -- w = s; -- while (c < count) { -- status = UART_GET_FR(port); -- if (UART_RX_DATA(status)) { -- *w++ = UART_GET_CHAR(port); -- c++; -- } else { -- // nothing more to get, return -- return c; -- } -- } -- // return the count -- return c; --} --#endif -- --/* -- * Print a string to the serial port trying not to disturb -- * any possible real use of the port... -- * -- * The console must be locked when we get here. -- */ --static void ambauart_console_write(struct console *co, const char *s, u_int count) --{ -- struct amba_port *port = &amba_ports[co->index]; -- unsigned int status, old_cr; -- int i; -- -- /* -- * First save the CR then disable the interrupts -- */ -- old_cr = UART_GET_CR(port); -- UART_PUT_CR(port, AMBA_UARTCR_UARTEN); -- -- /* -- * Now, do each character -- */ -- for (i = 0; i < count; i++) { -- do { -- status = UART_GET_FR(port); -- } while (!UART_TX_READY(status)); -- UART_PUT_CHAR(port, s[i]); -- if (s[i] == '\n') { -- do { -- status = UART_GET_FR(port); -- } while (!UART_TX_READY(status)); -- UART_PUT_CHAR(port, '\r'); -- } -- } -- -- /* -- * Finally, wait for transmitter to become empty -- * and restore the TCR -- */ -- do { -- status = UART_GET_FR(port); -- } while (status & AMBA_UARTFR_BUSY); -- UART_PUT_CR(port, old_cr); --} -- --static kdev_t ambauart_console_device(struct console *c) --{ -- return MKDEV(SERIAL_AMBA_MAJOR, SERIAL_AMBA_MINOR + c->index); --} -- --static int __init ambauart_console_setup(struct console *co, char *options) --{ -- struct amba_port *port; -- int baud = 38400; -- int bits = 8; -- int parity = 'n'; -- u_int cflag = CREAD | HUPCL | CLOCAL; -- u_int lcr_h, quot; -- -- if (co->index >= SERIAL_AMBA_NR) -- co->index = 0; -- -- port = &amba_ports[co->index]; -- -- if (options) { -- char *s = options; -- baud = simple_strtoul(s, NULL, 10); -- while (*s >= '0' && *s <= '9') -- s++; -- if (*s) parity = *s++; -- if (*s) bits = *s - '0'; -- } -- -- /* -- * Now construct a cflag setting. -- */ -- switch (baud) { -- case 1200: cflag |= B1200; break; -- case 2400: cflag |= B2400; break; -- case 4800: cflag |= B4800; break; -- default: cflag |= B9600; baud = 9600; break; -- case 19200: cflag |= B19200; break; -- case 38400: cflag |= B38400; break; -- case 57600: cflag |= B57600; break; -- case 115200: cflag |= B115200; break; -- } -- switch (bits) { -- case 7: cflag |= CS7; lcr_h = AMBA_UARTLCR_H_WLEN_7; break; -- default: cflag |= CS8; lcr_h = AMBA_UARTLCR_H_WLEN_8; break; -- } -- switch (parity) { -- case 'o': -- case 'O': cflag |= PARODD; lcr_h |= AMBA_UARTLCR_H_PEN; break; -- case 'e': -- case 'E': cflag |= PARENB; lcr_h |= AMBA_UARTLCR_H_PEN | -- AMBA_UARTLCR_H_EPS; break; -- } -- -- co->cflag = cflag; -- -- if (port->fifosize > 1) -- lcr_h |= AMBA_UARTLCR_H_FEN; -- -- quot = (port->uartclk / (16 * baud)) - 1; -- -- UART_PUT_LCRL(port, (quot & 0xff)); -- UART_PUT_LCRM(port, (quot >> 8)); -- UART_PUT_LCRH(port, lcr_h); -- -- /* we will enable the port as we need it */ -- UART_PUT_CR(port, 0); -- -- return 0; --} -- --static struct console ambauart_cons = --{ -- name: SERIAL_AMBA_NAME, -- write: ambauart_console_write, --#ifdef used_and_not_const_char_pointer -- read: ambauart_console_read, --#endif -- device: ambauart_console_device, -- setup: ambauart_console_setup, -- flags: CON_PRINTBUFFER, -- index: -1, --}; -- --void __init ambauart_console_init(void) --{ -- register_console(&ambauart_cons); --} -- --#endif /* CONFIG_SERIAL_AMBA_CONSOLE */ -- --MODULE_LICENSE("GPL"); --EXPORT_NO_SYMBOLS; -diff -urN linux-2.4.26/drivers/char/tty_io.c linux-2.4.26-vrs1/drivers/char/tty_io.c ---- linux-2.4.26/drivers/char/tty_io.c 2004-04-19 11:44:16.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/tty_io.c 2004-04-18 21:47:50.000000000 +0100 -@@ -19,7 +19,7 @@ - * Also restructured routines so that there is more of a separation - * between the high-level tty routines (tty_io.c and tty_ioctl.c) and - * the low-level tty routines (serial.c, pty.c, console.c). This -- * makes for cleaner and more compact code. -TYT, 9/17/92 -+ * makes for cleaner and more compact code. -TYT, 9/17/92 - * - * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines - * which can be dynamically activated and de-activated by the line -@@ -41,7 +41,7 @@ - * - * New TIOCLINUX variants added. - * -- mj@k332.feld.cvut.cz, 19-Nov-95 -- * -+ * - * Restrict vt switching via ioctl() - * -- grif@cs.ucr.edu, 5-Dec-95 - * -@@ -151,8 +151,7 @@ - extern void tty3215_init(void); - extern void tub3270_con_init(void); - extern void tub3270_init(void); --extern void rs285_console_init(void); --extern void sa1100_rs_console_init(void); -+extern void uart_console_init(void); - extern void sgi_serial_console_init(void); - extern void sn_sal_serial_console_init(void); - extern void sci_console_init(void); -@@ -164,6 +163,7 @@ - extern void txx9_serial_console_init(void); - extern void sb1250_serial_console_init(void); - extern void arc_console_init(void); -+extern void rs285_console_init(void); - extern int hvc_console_init(void); - - #ifndef MIN -@@ -201,7 +201,7 @@ - else - sprintf(buf, name, - idx + tty->driver.name_base); -- -+ - return buf; - } - -@@ -239,7 +239,7 @@ - #ifdef CHECK_TTY_COUNT - struct list_head *p; - int count = 0; -- -+ - file_list_lock(); - for(p = tty->tty_files.next; p != &tty->tty_files; p = p->next) { - if(list_entry(p, struct file, f_list)->private_data == tty) -@@ -255,7 +255,7 @@ - "!= #fd's(%d) in %s\n", - kdevname(tty->device), tty->count, count, routine); - return count; -- } -+ } - #endif - return 0; - } -@@ -264,14 +264,14 @@ - { - if (disc < N_TTY || disc >= NR_LDISCS) - return -EINVAL; -- -+ - if (new_ldisc) { - ldiscs[disc] = *new_ldisc; - ldiscs[disc].flags |= LDISC_FLAG_DEFINED; - ldiscs[disc].num = disc; - } else - memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc)); -- -+ - return 0; - } - -@@ -301,7 +301,7 @@ - o_ldisc = tty->ldisc; - - tty_wait_until_sent(tty, 0); -- -+ - /* Shutdown the current discipline. */ - if (tty->ldisc.close) - (tty->ldisc.close)(tty); -@@ -339,7 +339,7 @@ - { - int major, minor; - struct tty_driver *p; -- -+ - minor = MINOR(device); - major = MAJOR(device); - -@@ -456,7 +456,7 @@ - redirect = NULL; - } - spin_unlock(&redirect_lock); -- -+ - check_tty_count(tty, "do_tty_hangup"); - file_list_lock(); - for (l = tty->tty_files.next; l != &tty->tty_files; l = l->next) { -@@ -473,7 +473,7 @@ - filp->f_op = &hung_up_tty_fops; - } - file_list_unlock(); -- -+ - /* FIXME! What are the locking issues here? This may me overdoing things.. */ - { - unsigned long flags; -@@ -510,7 +510,7 @@ - "error %d\n", -i); - } - } -- -+ - read_lock(&tasklist_lock); - for_each_task(p) { - if ((tty->session > 0) && (p->session == tty->session) && -@@ -550,7 +550,7 @@ - { - #ifdef TTY_DEBUG_HANGUP - char buf[64]; -- -+ - printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf)); - #endif - schedule_task(&tty->tq_hangup); -@@ -650,7 +650,7 @@ - wake_up_interruptible(&tty->write_wait); - } - --static ssize_t tty_read(struct file * file, char * buf, size_t count, -+static ssize_t tty_read(struct file * file, char * buf, size_t count, - loff_t *ppos) - { - int i; -@@ -707,7 +707,7 @@ - size_t count) - { - ssize_t ret = 0, written = 0; -- -+ - if (file->f_flags & O_NONBLOCK) { - if (down_trylock(&tty->atomic_write)) - return -EAGAIN; -@@ -835,7 +835,7 @@ - struct tty_struct *tty, *o_tty; - struct termios *tp, **tp_loc, *o_tp, **o_tp_loc; - struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc; -- struct tty_driver *driver; -+ struct tty_driver *driver; - int retval=0; - int idx; - -@@ -845,7 +845,7 @@ - - idx = MINOR(device) - driver->minor_start; - -- /* -+ /* - * Check whether we need to acquire the tty semaphore to avoid - * race conditions. For now, play it safe. - */ -@@ -859,7 +859,7 @@ - * First time open is complex, especially for PTY devices. - * This code guarantees that either everything succeeds and the - * TTY is ready for operation, or else the table slots are vacated -- * and the allocated memory released. (Except that the termios -+ * and the allocated memory released. (Except that the termios - * and locked termios may be retained.) - */ - -@@ -938,13 +938,13 @@ - o_tty->link = tty; - } - -- /* -+ /* - * All structures have been allocated, so now we install them. -- * Failures after this point use release_mem to clean up, so -+ * Failures after this point use release_mem to clean up, so - * there's no need to null out the local pointers. - */ - driver->table[idx] = tty; -- -+ - if (!*tp_loc) - *tp_loc = tp; - if (!*ltp_loc) -@@ -954,7 +954,7 @@ - (*driver->refcount)++; - tty->count++; - -- /* -+ /* - * Structures all installed ... call the ldisc open routines. - * If we fail here just call release_mem to clean up. No need - * to decrement the use counts, as release_mem doesn't care. -@@ -988,7 +988,7 @@ - if (driver->type == TTY_DRIVER_TYPE_PTY && - driver->subtype == PTY_TYPE_MASTER) { - /* -- * special case for PTY masters: only one open permitted, -+ * special case for PTY masters: only one open permitted, - * and the slave side open count is incremented as well. - */ - if (tty->count) { -@@ -1002,7 +1002,7 @@ - - success: - *ret_tty = tty; -- -+ - /* All paths come through here to release the semaphore */ - end_init: - up_tty_sem(idx); -@@ -1080,7 +1080,7 @@ - int pty_master, tty_closing, o_tty_closing, do_sleep; - int idx; - char buf[64]; -- -+ - tty = (struct tty_struct *)filp->private_data; - if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "release_dev")) - return; -@@ -1138,7 +1138,7 @@ - idx, kdevname(tty->device)); - return; - } -- if (o_tty->termios_locked != -+ if (o_tty->termios_locked != - tty->driver.other->termios_locked[idx]) { - printk(KERN_DEBUG "release_dev: other->termios_locked[" - "%d] not o_termios_locked for (%s)\n", -@@ -1204,11 +1204,11 @@ - printk(KERN_WARNING "release_dev: %s: read/write wait queue " - "active!\n", tty_name(tty, buf)); - schedule(); -- } -+ } - - /* -- * The closing flags are now consistent with the open counts on -- * both sides, and we've completed the last operation that could -+ * The closing flags are now consistent with the open counts on -+ * both sides, and we've completed the last operation that could - * block, so it's safe to proceed with closing. - */ - if (pty_master) { -@@ -1266,7 +1266,7 @@ - /* check whether both sides are closing ... */ - if (!tty_closing || (o_tty && !o_tty_closing)) - return; -- -+ - #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "freeing tty structure..."); - #endif -@@ -1284,14 +1284,14 @@ - (o_tty->ldisc.close)(o_tty); - o_tty->ldisc = ldiscs[N_TTY]; - } -- -+ - /* -- * Make sure that the tty's task queue isn't activated. -+ * Make sure that the tty's task queue isn't activated. - */ - run_task_queue(&tq_timer); - flush_scheduled_tasks(); - -- /* -+ /* - * The release_mem function takes care of the details of clearing - * the slots and preserving the termios structure. - */ -@@ -1482,7 +1482,7 @@ - tty = (struct tty_struct *)filp->private_data; - if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "tty_fasync")) - return 0; -- -+ - retval = fasync_helper(fd, filp, on, &tty->fasync); - if (retval <= 0) - return retval; -@@ -1697,7 +1697,7 @@ - - static int tty_generic_brk(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) - { -- if (cmd == TCSBRK && arg) -+ if (cmd == TCSBRK && arg) - { - /* tcdrain case */ - int retval = tty_check_change(tty); -@@ -1718,7 +1718,7 @@ - { - struct tty_struct *tty, *real_tty; - int retval; -- -+ - tty = (struct tty_struct *)file->private_data; - if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl")) - return -EINVAL; -@@ -1738,7 +1738,7 @@ - if (tty->driver.ioctl) - return tty->driver.ioctl(tty, file, cmd, arg); - return -EINVAL; -- -+ - /* These two ioctl's always return success; even if */ - /* the driver doesn't support them. */ - case TCSBRK: -@@ -1761,7 +1761,7 @@ - case TIOCSBRK: - case TIOCCBRK: - case TCSBRK: -- case TCSBRKP: -+ case TCSBRKP: - retval = tty_check_change(tty); - if (retval) - return retval; -@@ -1824,7 +1824,7 @@ - case TIOCSBRK: /* Turn break on, unconditionally */ - tty->driver.break_ctl(tty, -1); - return 0; -- -+ - case TIOCCBRK: /* Turn break off, unconditionally */ - tty->driver.break_ctl(tty, 0); - return 0; -@@ -1837,7 +1837,7 @@ - if (!arg) - return send_break(tty, HZ/4); - return 0; -- case TCSBRKP: /* support for POSIX tcsendbreak() */ -+ case TCSBRKP: /* support for POSIX tcsendbreak() */ - return send_break(tty, arg ? arg*(HZ/10) : HZ/4); - } - if (tty->driver.ioctl) { -@@ -1859,7 +1859,7 @@ - * prevent trojan horses by killing all processes associated with this - * tty when the user hits the "Secure Attention Key". Required for - * super-paranoid applications --- see the Orange Book for more details. -- * -+ * - * This code could be nicer; ideally it should send a HUP, wait a few - * seconds, then send a INT, and then a KILL signal. But you then - * have to coordinate with the init process, since all processes associated -@@ -1883,7 +1883,7 @@ - int session; - int i; - struct file *filp; -- -+ - if (!tty) - return; - session = tty->session; -@@ -1968,7 +1968,7 @@ - count = tty->flip.count; - tty->flip.count = 0; - restore_flags(flags); -- -+ - tty->ldisc.receive_buf(tty, cp, fp, count); - } - -@@ -2000,7 +2000,7 @@ - i = cflag & CBAUD; - if (i & CBAUDEX) { - i &= ~CBAUDEX; -- if (i < 1 || i+15 >= n_baud_table) -+ if (i < 1 || i+15 >= n_baud_table) - tty->termios->c_cflag &= ~CBAUDEX; - else - i += 15; -@@ -2013,7 +2013,7 @@ - } - return(tty->alt_speed); - } -- -+ - return baud_table[i]; - } - -@@ -2079,7 +2079,7 @@ - mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; - break; - } -- if ( (minor < driver->minor_start) || -+ if ( (minor < driver->minor_start) || - (minor >= driver->minor_start + driver->num) ) { - printk(KERN_ERR "Attempt to register invalid minor number " - "with devfs (%d:%d).\n", (int)driver->major,(int)minor); -@@ -2132,12 +2132,12 @@ - - if (!driver->put_char) - driver->put_char = tty_default_put_char; -- -+ - driver->prev = 0; - driver->next = tty_drivers; - if (tty_drivers) tty_drivers->prev = driver; - tty_drivers = driver; -- -+ - if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) { - for(i = 0; i < driver->num; i++) - tty_register_devfs(driver, 0, driver->minor_start + i); -@@ -2156,7 +2156,7 @@ - int i, found = 0; - struct termios *tp; - const char *othername = NULL; -- -+ - if (*driver->refcount) - return -EBUSY; - -@@ -2166,7 +2166,7 @@ - else if (p->major == driver->major) - othername = p->name; - } -- -+ - if (!found) - return -ENOENT; - -@@ -2181,7 +2181,7 @@ - driver->prev->next = driver->next; - else - tty_drivers = driver->next; -- -+ - if (driver->next) - driver->next->prev = driver->prev; - -@@ -2221,7 +2221,7 @@ - (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); - - /* -- * Set up the standard termios. Individual tty drivers may -+ * Set up the standard termios. Individual tty drivers may - * deviate from this; this is used as a template. - */ - memset(&tty_std_termios, 0, sizeof(struct termios)); -@@ -2233,11 +2233,11 @@ - ECHOCTL | ECHOKE | IEXTEN; - - /* -- * set up the console device so that later boot sequences can -+ * set up the console device so that later boot sequences can - * inform about problems etc.. - */ - #ifdef CONFIG_EARLY_PRINTK -- disable_early_printk(); -+ disable_early_printk(); - #endif - #ifdef CONFIG_HVC_CONSOLE - hvc_console_init(); -@@ -2288,18 +2288,12 @@ - #ifdef CONFIG_STDIO_CONSOLE - stdio_console_init(); - #endif --#ifdef CONFIG_SERIAL_21285_CONSOLE -- rs285_console_init(); --#endif --#ifdef CONFIG_SERIAL_SA1100_CONSOLE -- sa1100_rs_console_init(); -+#ifdef CONFIG_SERIAL_CORE_CONSOLE -+ uart_console_init(); - #endif - #ifdef CONFIG_ARC_CONSOLE - arc_console_init(); - #endif --#ifdef CONFIG_SERIAL_AMBA_CONSOLE -- ambauart_console_init(); --#endif - #ifdef CONFIG_SERIAL_TX3912_CONSOLE - tx3912_console_init(); - #endif -@@ -2315,6 +2309,9 @@ - #ifdef CONFIG_IP22_SERIAL - sgi_serial_console_init(); - #endif -+#ifdef CONFIG_SERIAL_21285_CONSOLE -+ rs285_console_init(); -+#endif - } - - static struct tty_driver dev_tty_driver, dev_syscons_driver; -@@ -2347,7 +2344,7 @@ - dev_tty_driver.num = 1; - dev_tty_driver.type = TTY_DRIVER_TYPE_SYSTEM; - dev_tty_driver.subtype = SYSTEM_TYPE_TTY; -- -+ - if (tty_register_driver(&dev_tty_driver)) - panic("Couldn't register /dev/tty driver\n"); - -@@ -2363,7 +2360,7 @@ - panic("Couldn't register /dev/console driver\n"); - - /* console calls tty_register_driver() before kmalloc() works. -- * Thus, we can't devfs_register() then. Do so now, instead. -+ * Thus, we can't devfs_register() then. Do so now, instead. - */ - #ifdef CONFIG_VT - con_init_devfs(); -@@ -2381,7 +2378,7 @@ - if (tty_register_driver(&dev_ptmx_driver)) - panic("Couldn't register /dev/ptmx driver\n"); - #endif -- -+ - #ifdef CONFIG_VT - dev_console_driver = dev_tty_driver; - dev_console_driver.driver_name = "/dev/vc/0"; -@@ -2441,10 +2438,10 @@ - pty_init(); - #ifdef CONFIG_MOXA_SMARTIO - mxser_init(); --#endif -+#endif - #ifdef CONFIG_MOXA_INTELLIO - moxa_init(); --#endif -+#endif - #ifdef CONFIG_VT - vcs_init(); - #endif -diff -urN linux-2.4.26/drivers/char/wdt285.c linux-2.4.26-vrs1/drivers/char/wdt285.c ---- linux-2.4.26/drivers/char/wdt285.c 2003-06-13 15:51:33.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/char/wdt285.c 2004-01-14 21:32:25.000000000 +0000 -@@ -151,7 +151,7 @@ - if (get_user(new_margin, (int *)arg)) - return -EFAULT; - /* Arbitrary, can't find the card's limits */ -- if ((new_marg < 0) || (new_margin > 60)) -+ if ((new_margin < 0) || (new_margin > 60)) - return -EINVAL; - soft_margin = new_margin; - watchdog_ping(); -diff -urN linux-2.4.26/drivers/char/wdt977.c linux-2.4.26-vrs1/drivers/char/wdt977.c ---- linux-2.4.26/drivers/char/wdt977.c 2002-11-28 23:53:12.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/char/wdt977.c 2004-01-14 21:32:25.000000000 +0000 -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - - #define WATCHDOG_MINOR 130 - -diff -urN linux-2.4.26/drivers/cpufreq/Kconfig linux-2.4.26-vrs1/drivers/cpufreq/Kconfig ---- linux-2.4.26/drivers/cpufreq/Kconfig 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/cpufreq/Kconfig 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,38 @@ -+config CPU_FREQ_PROC_INTF -+ tristate "/proc/cpufreq interface (deprecated)" -+ depends on CPU_FREQ && PROC_FS -+ help -+ This enables the /proc/cpufreq interface for controlling -+ CPUFreq. Please note that it is recommended to use the sysfs -+ interface instead (which is built automatically). -+ -+ For details, take a look at linux/Documentation/cpufreq. -+ -+ If in doubt, say N. -+ -+config CPU_FREQ_GOV_USERSPACE -+ tristate "'userspace' governor for userspace frequency scaling" -+ depends on CPU_FREQ -+ help -+ Enable this cpufreq governor when you either want to set the -+ CPU frequency manually or when an userspace programm shall -+ be able to set the CPU dynamically, like on LART -+ ( http://www.lart.tudelft.nl/ ) -+ -+ For details, take a look at linux/Documentation/cpufreq. -+ -+ If in doubt, say Y. -+ -+config CPU_FREQ_24_API -+ bool "/proc/sys/cpu/ interface (2.4. / OLD)" -+ depends on CPU_FREQ && SYSCTL && CPU_FREQ_GOV_USERSPACE -+ help -+ This enables the /proc/sys/cpu/ sysctl interface for controlling -+ the CPUFreq,"userspace" governor. This is the same interface -+ as known from the.4.-kernel patches for CPUFreq, and offers -+ the same functionality as long as "userspace" is the -+ selected governor for the specified CPU. -+ -+ For details, take a look at linux/Documentation/cpufreq. -+ -+ If in doubt, say N. -diff -urN linux-2.4.26/drivers/cpufreq/Makefile linux-2.4.26-vrs1/drivers/cpufreq/Makefile ---- linux-2.4.26/drivers/cpufreq/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/cpufreq/Makefile 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,4 @@ -+#CPUfreq governors and cross-arch helpers -+obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o -+obj-$(CONFIG_CPU_FREQ_PROC_INTF) += proc_intf.o -+obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += userspace.o -diff -urN linux-2.4.26/drivers/cpufreq/cpufreq.c linux-2.4.26-vrs1/drivers/cpufreq/cpufreq.c ---- linux-2.4.26/drivers/cpufreq/cpufreq.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/cpufreq/cpufreq.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,720 @@ -+/* -+ * linux/kernel/cpufreq.c -+ * -+ * Copyright (C) 2001 Russell King -+ * (C) 2002 - 2003 Dominik Brodowski -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+/** -+ * The "cpufreq driver" - the arch- or hardware-dependend low -+ * level driver of CPUFreq support, and its spinlock. This lock -+ * also protects the cpufreq_cpu_data array. -+ */ -+static struct cpufreq_driver *cpufreq_driver; -+static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS]; -+static spinlock_t cpufreq_driver_lock = SPIN_LOCK_UNLOCKED; -+ -+/* internal prototype */ -+static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event); -+ -+ -+/** -+ * Two notifier lists: the "policy" list is involved in the -+ * validation process for a new CPU frequency policy; the -+ * "transition" list for kernel code that needs to handle -+ * changes to devices when the CPU clock speed changes. -+ * The mutex locks both lists. -+ */ -+static struct notifier_block *cpufreq_policy_notifier_list; -+static struct notifier_block *cpufreq_transition_notifier_list; -+static DECLARE_RWSEM (cpufreq_notifier_rwsem); -+ -+ -+static LIST_HEAD(cpufreq_governor_list); -+static DECLARE_MUTEX (cpufreq_governor_sem); -+ -+/* -+ * backport info: -+ * we don't have a kobj we can use for ref-counting, so use a -+ * "unsigned int policy->use_count" and an "unload_sem" [idea from -+ * Pat Mochel's struct driver unload_sem] for proper reference counting. -+ */ -+ -+static struct cpufreq_policy * cpufreq_cpu_get(unsigned int cpu) -+{ -+ struct cpufreq_policy *data; -+ unsigned long flags; -+ -+ if (cpu >= NR_CPUS) -+ goto err_out; -+ -+ /* get the cpufreq driver */ -+ spin_lock_irqsave(&cpufreq_driver_lock, flags); -+ -+ if (!cpufreq_driver) -+ goto err_out_unlock; -+ -+ /* get the CPU */ -+ data = cpufreq_cpu_data[cpu]; -+ -+ if (!data) -+ goto err_out_unlock; -+ -+ if (!data->use_count) -+ goto err_out_unlock; -+ -+ data->use_count += 1; -+ -+ spin_unlock_irqrestore(&cpufreq_driver_lock, flags); -+ -+ return data; -+ -+ err_out_unlock: -+ spin_unlock_irqrestore(&cpufreq_driver_lock, flags); -+ err_out: -+ return NULL; -+} -+ -+static void cpufreq_cpu_put(struct cpufreq_policy *data) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&cpufreq_driver_lock, flags); -+ data->use_count -= 1; -+ if (!data->use_count) { -+ spin_unlock_irqrestore(&cpufreq_driver_lock, flags); -+ up(&data->unload_sem); -+ return; -+ } -+ spin_unlock_irqrestore(&cpufreq_driver_lock, flags); -+} -+ -+/********************************************************************* -+ * SYSFS INTERFACE * -+ *********************************************************************/ -+ -+/** -+ * cpufreq_parse_governor - parse a governor string -+ */ -+int cpufreq_parse_governor (char *str_governor, unsigned int *policy, -+ struct cpufreq_governor **governor) -+{ -+ if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { -+ *policy = CPUFREQ_POLICY_PERFORMANCE; -+ return 0; -+ } else if (!strnicmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) { -+ *policy = CPUFREQ_POLICY_POWERSAVE; -+ return 0; -+ } else { -+ struct cpufreq_governor *t; -+ down(&cpufreq_governor_sem); -+ if (!cpufreq_driver || !cpufreq_driver->target) -+ goto out; -+ list_for_each_entry(t, &cpufreq_governor_list, governor_list) { -+ if (!strnicmp(str_governor,t->name,CPUFREQ_NAME_LEN)) { -+ *governor = t; -+ *policy = CPUFREQ_POLICY_GOVERNOR; -+ up(&cpufreq_governor_sem); -+ return 0; -+ } -+ } -+ out: -+ up(&cpufreq_governor_sem); -+ } -+ return -EINVAL; -+} -+EXPORT_SYMBOL_GPL(cpufreq_parse_governor); -+ -+ -+/* backport info: -+ * all the sysfs stuff is missing -- of course -+ */ -+ -+/** -+ * cpufreq_add_dev - add a CPU device -+ * -+ * Adds the cpufreq interface for a CPU device. -+ */ -+static int cpufreq_add_dev (unsigned int cpu) -+{ -+ int ret = 0; -+ struct cpufreq_policy new_policy; -+ struct cpufreq_policy *policy; -+ unsigned long flags; -+ -+ policy = kmalloc(sizeof(struct cpufreq_policy), GFP_KERNEL); -+ if (!policy) -+ return -ENOMEM; -+ memset(policy, 0, sizeof(struct cpufreq_policy)); -+ -+ policy->cpu = cpu; -+ policy->use_count = 1; -+ init_MUTEX_LOCKED(&policy->lock); -+ init_MUTEX_LOCKED(&policy->unload_sem); -+ -+ /* call driver. From then on the cpufreq must be able -+ * to accept all calls to ->verify and ->setpolicy for this CPU -+ */ -+ ret = cpufreq_driver->init(policy); -+ if (ret) -+ goto err_out; -+ -+ memcpy(&new_policy, policy, sizeof(struct cpufreq_policy)); -+ -+ spin_lock_irqsave(&cpufreq_driver_lock, flags); -+ cpufreq_cpu_data[cpu] = policy; -+ spin_unlock_irqrestore(&cpufreq_driver_lock, flags); -+ -+ up(&policy->lock); -+ -+ /* set default policy */ -+ ret = cpufreq_set_policy(&new_policy); -+ if (ret) -+ goto err_out_unregister; -+ -+ return 0; -+ -+ -+ err_out_unregister: -+ spin_lock_irqsave(&cpufreq_driver_lock, flags); -+ cpufreq_cpu_data[cpu] = NULL; -+ spin_unlock_irqrestore(&cpufreq_driver_lock, flags); -+ -+ err_out: -+ kfree(policy); -+ return ret; -+} -+ -+ -+/** -+ * cpufreq_remove_dev - remove a CPU device -+ * -+ * Removes the cpufreq interface for a CPU device. -+ */ -+static int cpufreq_remove_dev (unsigned int cpu) -+{ -+ unsigned long flags; -+ struct cpufreq_policy *data; -+ -+ spin_lock_irqsave(&cpufreq_driver_lock, flags); -+ data = cpufreq_cpu_data[cpu]; -+ if (!data) { -+ spin_unlock_irqrestore(&cpufreq_driver_lock, flags); -+ return -EINVAL; -+ } -+ cpufreq_cpu_data[cpu] = NULL; -+ -+ data->use_count -= 1; -+ if (!data->use_count) { -+ spin_unlock_irqrestore(&cpufreq_driver_lock, flags); -+ up(&data->unload_sem); -+ } else { -+ spin_unlock_irqrestore(&cpufreq_driver_lock, flags); -+ /* this will sleep until data->use_count gets to zero */ -+ down(&data->unload_sem); -+ up(&data->unload_sem); -+ } -+ -+ if (cpufreq_driver->target) -+ __cpufreq_governor(data, CPUFREQ_GOV_STOP); -+ -+ if (cpufreq_driver->exit) -+ cpufreq_driver->exit(data); -+ -+ kfree(data); -+ -+ return 0; -+} -+ -+ -+/********************************************************************* -+ * NOTIFIER LISTS INTERFACE * -+ *********************************************************************/ -+ -+/** -+ * cpufreq_register_notifier - register a driver with cpufreq -+ * @nb: notifier function to register -+ * @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER -+ * -+ * Add a driver to one of two lists: either a list of drivers that -+ * are notified about clock rate changes (once before and once after -+ * the transition), or a list of drivers that are notified about -+ * changes in cpufreq policy. -+ * -+ * This function may sleep, and has the same return conditions as -+ * notifier_chain_register. -+ */ -+int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list) -+{ -+ int ret; -+ -+ down_write(&cpufreq_notifier_rwsem); -+ switch (list) { -+ case CPUFREQ_TRANSITION_NOTIFIER: -+ ret = notifier_chain_register(&cpufreq_transition_notifier_list, nb); -+ break; -+ case CPUFREQ_POLICY_NOTIFIER: -+ ret = notifier_chain_register(&cpufreq_policy_notifier_list, nb); -+ break; -+ default: -+ ret = -EINVAL; -+ } -+ up_write(&cpufreq_notifier_rwsem); -+ -+ return ret; -+} -+EXPORT_SYMBOL(cpufreq_register_notifier); -+ -+ -+/** -+ * cpufreq_unregister_notifier - unregister a driver with cpufreq -+ * @nb: notifier block to be unregistered -+ * @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER -+ * -+ * Remove a driver from the CPU frequency notifier list. -+ * -+ * This function may sleep, and has the same return conditions as -+ * notifier_chain_unregister. -+ */ -+int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list) -+{ -+ int ret; -+ -+ down_write(&cpufreq_notifier_rwsem); -+ switch (list) { -+ case CPUFREQ_TRANSITION_NOTIFIER: -+ ret = notifier_chain_unregister(&cpufreq_transition_notifier_list, nb); -+ break; -+ case CPUFREQ_POLICY_NOTIFIER: -+ ret = notifier_chain_unregister(&cpufreq_policy_notifier_list, nb); -+ break; -+ default: -+ ret = -EINVAL; -+ } -+ up_write(&cpufreq_notifier_rwsem); -+ -+ return ret; -+} -+EXPORT_SYMBOL(cpufreq_unregister_notifier); -+ -+ -+/********************************************************************* -+ * GOVERNORS * -+ *********************************************************************/ -+ -+ -+int __cpufreq_driver_target(struct cpufreq_policy *policy, -+ unsigned int target_freq, -+ unsigned int relation) -+{ -+ return cpufreq_driver->target(policy, target_freq, relation); -+} -+EXPORT_SYMBOL_GPL(__cpufreq_driver_target); -+ -+ -+int cpufreq_driver_target(struct cpufreq_policy *policy, -+ unsigned int target_freq, -+ unsigned int relation) -+{ -+ unsigned int ret; -+ -+ policy = cpufreq_cpu_get(policy->cpu); -+ if (!policy) -+ return -EINVAL; -+ -+ down(&policy->lock); -+ -+ ret = __cpufreq_driver_target(policy, target_freq, relation); -+ -+ up(&policy->lock); -+ -+ cpufreq_cpu_put(policy); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(cpufreq_driver_target); -+ -+ -+static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event) -+{ -+ int ret = 0; -+ -+ switch (policy->policy) { -+ case CPUFREQ_POLICY_POWERSAVE: -+ if ((event == CPUFREQ_GOV_LIMITS) || (event == CPUFREQ_GOV_START)) { -+ ret = __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L); -+ } -+ break; -+ case CPUFREQ_POLICY_PERFORMANCE: -+ if ((event == CPUFREQ_GOV_LIMITS) || (event == CPUFREQ_GOV_START)) { -+ ret = __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); -+ } -+ break; -+ case CPUFREQ_POLICY_GOVERNOR: -+ ret = policy->governor->governor(policy, event); -+ break; -+ default: -+ ret = -EINVAL; -+ } -+ -+ return ret; -+} -+ -+ -+int cpufreq_governor(unsigned int cpu, unsigned int event) -+{ -+ int ret = 0; -+ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); -+ -+ if (!policy) -+ return -EINVAL; -+ -+ down(&policy->lock); -+ ret = __cpufreq_governor(policy, event); -+ up(&policy->lock); -+ -+ cpufreq_cpu_put(policy); -+ -+ return ret; -+} -+EXPORT_SYMBOL_GPL(cpufreq_governor); -+ -+ -+int cpufreq_register_governor(struct cpufreq_governor *governor) -+{ -+ struct cpufreq_governor *t; -+ -+ if (!governor) -+ return -EINVAL; -+ -+ if (!strnicmp(governor->name,"powersave",CPUFREQ_NAME_LEN)) -+ return -EBUSY; -+ if (!strnicmp(governor->name,"performance",CPUFREQ_NAME_LEN)) -+ return -EBUSY; -+ -+ down(&cpufreq_governor_sem); -+ -+ list_for_each_entry(t, &cpufreq_governor_list, governor_list) { -+ if (!strnicmp(governor->name,t->name,CPUFREQ_NAME_LEN)) { -+ up(&cpufreq_governor_sem); -+ return -EBUSY; -+ } -+ } -+ list_add(&governor->governor_list, &cpufreq_governor_list); -+ -+ up(&cpufreq_governor_sem); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(cpufreq_register_governor); -+ -+ -+void cpufreq_unregister_governor(struct cpufreq_governor *governor) -+{ -+ /* backport info: -+ * As the module usage count isn't assured in 2.4., check for removal -+ * of running cpufreq governor -+ */ -+ unsigned int i; -+ -+ if (!governor) -+ return; -+ -+ down(&cpufreq_governor_sem); -+ -+ for (i=0; ilock); -+ -+ if (policy->policy != CPUFREQ_POLICY_GOVERNOR) -+ goto unlock_done; -+ if (policy->governor != governor) -+ goto unlock_done; -+ -+ /* stop old one, start performance [always present] */ -+ __cpufreq_governor(policy, CPUFREQ_GOV_STOP); -+ policy->policy = CPUFREQ_POLICY_PERFORMANCE; -+ __cpufreq_governor(policy, CPUFREQ_GOV_START); -+ -+ unlock_done: -+ up(&policy->lock); -+ done: -+ cpufreq_cpu_put(policy); -+ } -+ list_del(&governor->governor_list); -+ up(&cpufreq_governor_sem); -+ return; -+} -+EXPORT_SYMBOL_GPL(cpufreq_unregister_governor); -+ -+ -+ -+/********************************************************************* -+ * POLICY INTERFACE * -+ *********************************************************************/ -+ -+/** -+ * cpufreq_get_policy - get the current cpufreq_policy -+ * @policy: struct cpufreq_policy into which the current cpufreq_policy is written -+ * -+ * Reads the current cpufreq policy. -+ */ -+int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu) -+{ -+ struct cpufreq_policy *cpu_policy; -+ if (!policy) -+ return -EINVAL; -+ -+ cpu_policy = cpufreq_cpu_get(cpu); -+ if (!cpu_policy) -+ return -EINVAL; -+ -+ down(&cpu_policy->lock); -+ memcpy(policy, cpu_policy, sizeof(struct cpufreq_policy)); -+ up(&cpu_policy->lock); -+ -+ cpufreq_cpu_put(cpu_policy); -+ -+ return 0; -+} -+EXPORT_SYMBOL(cpufreq_get_policy); -+ -+ -+/** -+ * cpufreq_set_policy - set a new CPUFreq policy -+ * @policy: policy to be set. -+ * -+ * Sets a new CPU frequency and voltage scaling policy. -+ */ -+int cpufreq_set_policy(struct cpufreq_policy *policy) -+{ -+ int ret = 0; -+ struct cpufreq_policy *data; -+ -+ if (!policy) -+ return -EINVAL; -+ -+ data = cpufreq_cpu_get(policy->cpu); -+ if (!data) -+ return -EINVAL; -+ -+ /* lock this CPU */ -+ down(&data->lock); -+ -+ memcpy(&policy->cpuinfo, -+ &data->cpuinfo, -+ sizeof(struct cpufreq_cpuinfo)); -+ -+ /* verify the cpu speed can be set within this limit */ -+ ret = cpufreq_driver->verify(policy); -+ if (ret) -+ goto error_out; -+ -+ down_read(&cpufreq_notifier_rwsem); -+ -+ /* adjust if necessary - all reasons */ -+ notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_ADJUST, -+ policy); -+ -+ /* adjust if necessary - hardware incompatibility*/ -+ notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_INCOMPATIBLE, -+ policy); -+ -+ /* verify the cpu speed can be set within this limit, -+ which might be different to the first one */ -+ ret = cpufreq_driver->verify(policy); -+ if (ret) { -+ up_read(&cpufreq_notifier_rwsem); -+ goto error_out; -+ } -+ -+ /* notification of the new policy */ -+ notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_NOTIFY, -+ policy); -+ -+ up_read(&cpufreq_notifier_rwsem); -+ -+ data->min = policy->min; -+ data->max = policy->max; -+ -+ if (cpufreq_driver->setpolicy) { -+ data->policy = policy->policy; -+ ret = cpufreq_driver->setpolicy(policy); -+ } else { -+ if ((policy->policy != data->policy) || -+ ((policy->policy == CPUFREQ_POLICY_GOVERNOR) && (policy->governor != data->governor))) { -+ /* save old, working values */ -+ unsigned int old_pol = data->policy; -+ struct cpufreq_governor *old_gov = data->governor; -+ -+ /* end old governor */ -+ __cpufreq_governor(data, CPUFREQ_GOV_STOP); -+ -+ /* start new governor */ -+ data->policy = policy->policy; -+ data->governor = policy->governor; -+ if (__cpufreq_governor(data, CPUFREQ_GOV_START)) { -+ /* new governor failed, so re-start old one */ -+ data->policy = old_pol; -+ data->governor = old_gov; -+ __cpufreq_governor(data, CPUFREQ_GOV_START); -+ } -+ /* might be a policy change, too, so fall through */ -+ } -+ __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); -+ } -+ -+ error_out: -+ up(&data->lock); -+ cpufreq_cpu_put(data); -+ -+ return ret; -+} -+EXPORT_SYMBOL(cpufreq_set_policy); -+ -+ -+ -+/********************************************************************* -+ * EXTERNALLY AFFECTING FREQUENCY CHANGES * -+ *********************************************************************/ -+ -+/** -+ * adjust_jiffies - adjust the system "loops_per_jiffy" -+ * -+ * This function alters the system "loops_per_jiffy" for the clock -+ * speed change. Note that loops_per_jiffy cannot be updated on SMP -+ * systems as each CPU might be scaled differently. So, use the arch -+ * per-CPU loops_per_jiffy value wherever possible. -+ */ -+#ifndef CONFIG_SMP -+static unsigned long l_p_j_ref = 0; -+static unsigned int l_p_j_ref_freq = 0; -+ -+static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) -+{ -+ if (!l_p_j_ref_freq) { -+ l_p_j_ref = loops_per_jiffy; -+ l_p_j_ref_freq = ci->old; -+ } -+ if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) || -+ (val == CPUFREQ_POSTCHANGE && ci->old > ci->new)) -+ loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new); -+} -+#else -+#define adjust_jiffies(x...) do {} while (0) -+#endif -+ -+ -+/** -+ * cpufreq_notify_transition - call notifier chain and adjust_jiffies on frequency transition -+ * -+ * This function calls the transition notifiers and the "adjust_jiffies" function. It is called -+ * twice on all CPU frequency changes that have external effects. -+ */ -+void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) -+{ -+ down_read(&cpufreq_notifier_rwsem); -+ switch (state) { -+ case CPUFREQ_PRECHANGE: -+ notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs); -+ adjust_jiffies(CPUFREQ_PRECHANGE, freqs); -+ break; -+ case CPUFREQ_POSTCHANGE: -+ adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); -+ notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs); -+ cpufreq_cpu_data[freqs->cpu]->cur = freqs->new; -+ break; -+ } -+ up_read(&cpufreq_notifier_rwsem); -+} -+EXPORT_SYMBOL_GPL(cpufreq_notify_transition); -+ -+ -+ -+/********************************************************************* -+ * REGISTER / UNREGISTER CPUFREQ DRIVER * -+ *********************************************************************/ -+ -+/** -+ * cpufreq_register_driver - register a CPU Frequency driver -+ * @driver_data: A struct cpufreq_driver containing the values# -+ * submitted by the CPU Frequency driver. -+ * -+ * Registers a CPU Frequency driver to this core code. This code -+ * returns zero on success, -EBUSY when another driver got here first -+ * (and isn't unregistered in the meantime). -+ * -+ */ -+int cpufreq_register_driver(struct cpufreq_driver *driver_data) -+{ -+ unsigned long flags; -+ unsigned int i; -+ -+ if (!driver_data || !driver_data->verify || !driver_data->init || -+ ((!driver_data->setpolicy) && (!driver_data->target))) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&cpufreq_driver_lock, flags); -+ if (cpufreq_driver) { -+ spin_unlock_irqrestore(&cpufreq_driver_lock, flags); -+ return -EBUSY; -+ } -+ cpufreq_driver = driver_data; -+ spin_unlock_irqrestore(&cpufreq_driver_lock, flags); -+ -+ for (i=0; i -+#include -+#include -+#include -+ -+/********************************************************************* -+ * FREQUENCY TABLE HELPERS * -+ *********************************************************************/ -+ -+int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, -+ struct cpufreq_frequency_table *table) -+{ -+ unsigned int min_freq = ~0; -+ unsigned int max_freq = 0; -+ unsigned int i = 0; -+ -+ for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { -+ unsigned int freq = table[i].frequency; -+ if (freq == CPUFREQ_ENTRY_INVALID) -+ continue; -+ if (freq < min_freq) -+ min_freq = freq; -+ if (freq > max_freq) -+ max_freq = freq; -+ } -+ -+ policy->min = policy->cpuinfo.min_freq = min_freq; -+ policy->max = policy->cpuinfo.max_freq = max_freq; -+ -+ if (policy->min == ~0) -+ return -EINVAL; -+ else -+ return 0; -+} -+EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo); -+ -+ -+int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, -+ struct cpufreq_frequency_table *table) -+{ -+ unsigned int next_larger = ~0; -+ unsigned int i = 0; -+ unsigned int count = 0; -+ -+ if (!cpu_online(policy->cpu)) -+ return -EINVAL; -+ -+ cpufreq_verify_within_limits(policy, -+ policy->cpuinfo.min_freq, -+ policy->cpuinfo.max_freq); -+ -+ for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { -+ unsigned int freq = table[i].frequency; -+ if (freq == CPUFREQ_ENTRY_INVALID) -+ continue; -+ if ((freq >= policy->min) && (freq <= policy->max)) -+ count++; -+ else if ((next_larger > freq) && (freq > policy->max)) -+ next_larger = freq; -+ } -+ -+ if (!count) -+ policy->max = next_larger; -+ -+ cpufreq_verify_within_limits(policy, -+ policy->cpuinfo.min_freq, -+ policy->cpuinfo.max_freq); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify); -+ -+ -+int cpufreq_frequency_table_target(struct cpufreq_policy *policy, -+ struct cpufreq_frequency_table *table, -+ unsigned int target_freq, -+ unsigned int relation, -+ unsigned int *index) -+{ -+ struct cpufreq_frequency_table optimal = { .index = ~0, }; -+ struct cpufreq_frequency_table suboptimal = { .index = ~0, }; -+ unsigned int i; -+ -+ switch (relation) { -+ case CPUFREQ_RELATION_H: -+ optimal.frequency = 0; -+ suboptimal.frequency = ~0; -+ break; -+ case CPUFREQ_RELATION_L: -+ optimal.frequency = ~0; -+ suboptimal.frequency = 0; -+ break; -+ } -+ -+ if (!cpu_online(policy->cpu)) -+ return -EINVAL; -+ -+ for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { -+ unsigned int freq = table[i].frequency; -+ if (freq == CPUFREQ_ENTRY_INVALID) -+ continue; -+ if ((freq < policy->min) || (freq > policy->max)) -+ continue; -+ switch(relation) { -+ case CPUFREQ_RELATION_H: -+ if (freq <= target_freq) { -+ if (freq >= optimal.frequency) { -+ optimal.frequency = freq; -+ optimal.index = i; -+ } -+ } else { -+ if (freq <= suboptimal.frequency) { -+ suboptimal.frequency = freq; -+ suboptimal.index = i; -+ } -+ } -+ break; -+ case CPUFREQ_RELATION_L: -+ if (freq >= target_freq) { -+ if (freq <= optimal.frequency) { -+ optimal.frequency = freq; -+ optimal.index = i; -+ } -+ } else { -+ if (freq >= suboptimal.frequency) { -+ suboptimal.frequency = freq; -+ suboptimal.index = i; -+ } -+ } -+ break; -+ } -+ } -+ if (optimal.index > i) { -+ if (suboptimal.index > i) -+ return -EINVAL; -+ *index = suboptimal.index; -+ } else -+ *index = optimal.index; -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); -+ -+static struct cpufreq_frequency_table *show_table[NR_CPUS]; -+/** -+ * show_scaling_governor - show the current policy for the specified CPU -+ */ -+static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf) -+{ -+ unsigned int i = 0; -+ unsigned int cpu = policy->cpu; -+ ssize_t count = 0; -+ struct cpufreq_frequency_table *table; -+ -+ if (!show_table[cpu]) -+ return -ENODEV; -+ -+ table = show_table[cpu]; -+ -+ for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { -+ if (table[i].frequency == CPUFREQ_ENTRY_INVALID) -+ continue; -+ count += sprintf(&buf[count], "%d ", table[i].frequency); -+ } -+ count += sprintf(&buf[count], "\n"); -+ -+ return count; -+ -+} -+ -+struct freq_attr cpufreq_freq_attr_scaling_available_freqs = { -+ .attr = { .name = "scaling_available_frequencies", .mode = 0444 }, -+ .show = show_available_freqs, -+}; -+EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs); -+ -+/* -+ * if you use these, you must assure that the frequency table is valid -+ * all the time between get_attr and put_attr! -+ */ -+void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, -+ unsigned int cpu) -+{ -+ show_table[cpu] = table; -+} -+EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr); -+ -+void cpufreq_frequency_table_put_attr(unsigned int cpu) -+{ -+ show_table[cpu] = NULL; -+} -+EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr); -+ -+ -+MODULE_AUTHOR ("Dominik Brodowski "); -+MODULE_DESCRIPTION ("CPUfreq frequency table helpers"); -+MODULE_LICENSE ("GPL"); -diff -urN linux-2.4.26/drivers/cpufreq/proc_intf.c linux-2.4.26-vrs1/drivers/cpufreq/proc_intf.c ---- linux-2.4.26/drivers/cpufreq/proc_intf.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/cpufreq/proc_intf.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,244 @@ -+/* -+ * linux/drivers/cpufreq/proc_intf.c -+ * -+ * Copyright (C) 2002 - 2003 Dominik Brodowski -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+/** -+ * cpufreq_parse_policy - parse a policy string -+ * @input_string: the string to parse. -+ * @policy: the policy written inside input_string -+ * -+ * This function parses a "policy string" - something the user echo'es into -+ * /proc/cpufreq or gives as boot parameter - into a struct cpufreq_policy. -+ * If there are invalid/missing entries, they are replaced with current -+ * cpufreq policy. -+ */ -+static int cpufreq_parse_policy(char input_string[42], struct cpufreq_policy *policy) -+{ -+ unsigned int min = 0; -+ unsigned int max = 0; -+ unsigned int cpu = 0; -+ char str_governor[16]; -+ struct cpufreq_policy current_policy; -+ unsigned int result = -EFAULT; -+ -+ if (!policy) -+ return -EINVAL; -+ -+ policy->min = 0; -+ policy->max = 0; -+ policy->policy = 0; -+ policy->cpu = CPUFREQ_ALL_CPUS; -+ -+ if (sscanf(input_string, "%d:%d:%d:%15s", &cpu, &min, &max, str_governor) == 4) -+ { -+ policy->min = min; -+ policy->max = max; -+ policy->cpu = cpu; -+ result = 0; -+ goto scan_policy; -+ } -+ if (sscanf(input_string, "%d%%%d%%%d%%%15s", &cpu, &min, &max, str_governor) == 4) -+ { -+ if (!cpufreq_get_policy(¤t_policy, cpu)) { -+ policy->min = (min * current_policy.cpuinfo.max_freq) / 100; -+ policy->max = (max * current_policy.cpuinfo.max_freq) / 100; -+ policy->cpu = cpu; -+ result = 0; -+ goto scan_policy; -+ } -+ } -+ -+ if (sscanf(input_string, "%d:%d:%15s", &min, &max, str_governor) == 3) -+ { -+ policy->min = min; -+ policy->max = max; -+ result = 0; -+ goto scan_policy; -+ } -+ -+ if (sscanf(input_string, "%d%%%d%%%15s", &min, &max, str_governor) == 3) -+ { -+ if (!cpufreq_get_policy(¤t_policy, cpu)) { -+ policy->min = (min * current_policy.cpuinfo.max_freq) / 100; -+ policy->max = (max * current_policy.cpuinfo.max_freq) / 100; -+ result = 0; -+ goto scan_policy; -+ } -+ } -+ -+ return -EINVAL; -+ -+scan_policy: -+ result = cpufreq_parse_governor(str_governor, &policy->policy, &policy->governor); -+ -+ return result; -+} -+ -+/** -+ * cpufreq_proc_read - read /proc/cpufreq -+ * -+ * This function prints out the current cpufreq policy. -+ */ -+static int cpufreq_proc_read ( -+ char *page, -+ char **start, -+ off_t off, -+ int count, -+ int *eof, -+ void *data) -+{ -+ char *p = page; -+ int len = 0; -+ struct cpufreq_policy policy; -+ unsigned int min_pctg = 0; -+ unsigned int max_pctg = 0; -+ unsigned int i = 0; -+ -+ if (off != 0) -+ goto end; -+ -+ p += sprintf(p, " minimum CPU frequency - maximum CPU frequency - policy\n"); -+ for (i=0;iname); -+ break; -+ default: -+ p += sprintf(p, "INVALID\n"); -+ break; -+ } -+ } -+end: -+ len = (p - page); -+ if (len <= off+count) -+ *eof = 1; -+ *start = page + off; -+ len -= off; -+ if (len>count) -+ len = count; -+ if (len<0) -+ len = 0; -+ -+ return len; -+} -+ -+ -+/** -+ * cpufreq_proc_write - handles writing into /proc/cpufreq -+ * -+ * This function calls the parsing script and then sets the policy -+ * accordingly. -+ */ -+static int cpufreq_proc_write ( -+ struct file *file, -+ const char *buffer, -+ unsigned long count, -+ void *data) -+{ -+ int result = 0; -+ char proc_string[42] = {'\0'}; -+ struct cpufreq_policy policy; -+ unsigned int i = 0; -+ -+ -+ if ((count > sizeof(proc_string) - 1)) -+ return -EINVAL; -+ -+ if (copy_from_user(proc_string, buffer, count)) -+ return -EFAULT; -+ -+ proc_string[count] = '\0'; -+ -+ result = cpufreq_parse_policy(proc_string, &policy); -+ if (result) -+ return -EFAULT; -+ -+ if (policy.cpu == CPUFREQ_ALL_CPUS) -+ { -+ for (i=0; iread_proc = cpufreq_proc_read; -+ entry->write_proc = cpufreq_proc_write; -+ } -+ -+ return 0; -+} -+ -+ -+/** -+ * cpufreq_proc_exit - removes "cpufreq" from the /proc root directory. -+ * -+ * This function removes "cpufreq" from the /proc root directory. -+ */ -+static void __exit cpufreq_proc_exit (void) -+{ -+ remove_proc_entry("cpufreq", &proc_root); -+ return; -+} -+ -+MODULE_AUTHOR ("Dominik Brodowski "); -+MODULE_DESCRIPTION ("CPUfreq /proc/cpufreq interface"); -+MODULE_LICENSE ("GPL"); -+ -+module_init(cpufreq_proc_init); -+module_exit(cpufreq_proc_exit); -diff -urN linux-2.4.26/drivers/cpufreq/userspace.c linux-2.4.26-vrs1/drivers/cpufreq/userspace.c ---- linux-2.4.26/drivers/cpufreq/userspace.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/cpufreq/userspace.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,591 @@ -+/* -+ * drivers/cpufreq/userspace.c -+ * -+ * Copyright (C) 2001 Russell King -+ * (C) 2002 - 2003 Dominik Brodowski -+ * -+ * $Id: userspace.c,v 1.4 2003/03/07 10:30:20 db Exp $ -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define CTL_CPU_VARS_SPEED_MAX(cpunr) { \ -+ .ctl_name = CPU_NR_FREQ_MAX, \ -+ .data = &cpu_max_freq[cpunr], \ -+ .procname = "speed-max", \ -+ .maxlen = sizeof(cpu_max_freq[cpunr]),\ -+ .mode = 0444, \ -+ .proc_handler = proc_dointvec, } -+ -+#define CTL_CPU_VARS_SPEED_MIN(cpunr) { \ -+ .ctl_name = CPU_NR_FREQ_MIN, \ -+ .data = &cpu_min_freq[cpunr], \ -+ .procname = "speed-min", \ -+ .maxlen = sizeof(cpu_min_freq[cpunr]),\ -+ .mode = 0444, \ -+ .proc_handler = proc_dointvec, } -+ -+#define CTL_CPU_VARS_SPEED(cpunr) { \ -+ .ctl_name = CPU_NR_FREQ, \ -+ .procname = "speed", \ -+ .mode = 0644, \ -+ .proc_handler = cpufreq_procctl, \ -+ .strategy = cpufreq_sysctl, \ -+ .extra1 = (void*) (cpunr), } -+ -+#define CTL_TABLE_CPU_VARS(cpunr) static ctl_table ctl_cpu_vars_##cpunr[] = {\ -+ CTL_CPU_VARS_SPEED_MAX(cpunr), \ -+ CTL_CPU_VARS_SPEED_MIN(cpunr), \ -+ CTL_CPU_VARS_SPEED(cpunr), \ -+ { .ctl_name = 0, }, } -+ -+/* the ctl_table entry for each CPU */ -+#define CPU_ENUM(s) { \ -+ .ctl_name = (CPU_NR + s), \ -+ .procname = #s, \ -+ .mode = 0555, \ -+ .child = ctl_cpu_vars_##s } -+ -+/** -+ * A few values needed by the userspace governor -+ */ -+static unsigned int cpu_max_freq[NR_CPUS]; -+static unsigned int cpu_min_freq[NR_CPUS]; -+static unsigned int cpu_cur_freq[NR_CPUS]; -+static unsigned int cpu_is_managed[NR_CPUS]; -+static struct cpufreq_policy current_policy[NR_CPUS]; -+ -+static DECLARE_MUTEX (userspace_sem); -+ -+ -+/* keep track of frequency transitions */ -+static int -+userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val, -+ void *data) -+{ -+ struct cpufreq_freqs *freq = data; -+ -+ cpu_cur_freq[freq->cpu] = freq->new; -+ -+ return 0; -+} -+ -+static struct notifier_block userspace_cpufreq_notifier_block = { -+ .notifier_call = userspace_cpufreq_notifier -+}; -+ -+ -+/** -+ * cpufreq_set - set the CPU frequency -+ * @freq: target frequency in kHz -+ * @cpu: CPU for which the frequency is to be set -+ * -+ * Sets the CPU frequency to freq. -+ */ -+int cpufreq_set(unsigned int freq, unsigned int cpu) -+{ -+ int ret = -EINVAL; -+ -+ down(&userspace_sem); -+ if (!cpu_is_managed[cpu]) -+ goto err; -+ -+ if (freq < cpu_min_freq[cpu]) -+ freq = cpu_min_freq[cpu]; -+ if (freq > cpu_max_freq[cpu]) -+ freq = cpu_max_freq[cpu]; -+ -+ ret = cpufreq_driver_target(¤t_policy[cpu], freq, -+ CPUFREQ_RELATION_L); -+ -+ err: -+ up(&userspace_sem); -+ return ret; -+} -+EXPORT_SYMBOL_GPL(cpufreq_set); -+ -+ -+/** -+ * cpufreq_setmax - set the CPU to the maximum frequency -+ * @cpu - affected cpu; -+ * -+ * Sets the CPU frequency to the maximum frequency supported by -+ * this CPU. -+ */ -+int cpufreq_setmax(unsigned int cpu) -+{ -+ if (!cpu_is_managed[cpu] || !cpu_online(cpu)) -+ return -EINVAL; -+ return cpufreq_set(cpu_max_freq[cpu], cpu); -+} -+EXPORT_SYMBOL_GPL(cpufreq_setmax); -+ -+ -+/** -+ * cpufreq_get - get the current CPU frequency (in kHz) -+ * @cpu: CPU number -+ * -+ * Get the CPU current (static) CPU frequency -+ */ -+unsigned int cpufreq_get(unsigned int cpu) -+{ -+ return cpu_cur_freq[cpu]; -+} -+EXPORT_SYMBOL(cpufreq_get); -+ -+ -+#ifdef CONFIG_CPU_FREQ_24_API -+ -+ -+/*********************** cpufreq_sysctl interface ********************/ -+static int -+cpufreq_procctl(ctl_table *ctl, int write, struct file *filp, -+ void *buffer, size_t *lenp) -+{ -+ char buf[16], *p; -+ int cpu = (int) ctl->extra1; -+ int len, left = *lenp; -+ -+ if (!left || (filp->f_pos && !write) || !cpu_online(cpu)) { -+ *lenp = 0; -+ return 0; -+ } -+ -+ if (write) { -+ unsigned int freq; -+ -+ len = left; -+ if (left > sizeof(buf)) -+ left = sizeof(buf); -+ if (copy_from_user(buf, buffer, left)) -+ return -EFAULT; -+ buf[sizeof(buf) - 1] = '\0'; -+ -+ freq = simple_strtoul(buf, &p, 0); -+ cpufreq_set(freq, cpu); -+ } else { -+ len = sprintf(buf, "%d\n", cpufreq_get(cpu)); -+ if (len > left) -+ len = left; -+ if (copy_to_user(buffer, buf, len)) -+ return -EFAULT; -+ } -+ -+ *lenp = len; -+ filp->f_pos += len; -+ return 0; -+} -+ -+static int -+cpufreq_sysctl(ctl_table *table, int *name, int nlen, -+ void *oldval, size_t *oldlenp, -+ void *newval, size_t newlen, void **context) -+{ -+ int cpu = (int) table->extra1; -+ -+ if (!cpu_online(cpu)) -+ return -EINVAL; -+ -+ if (oldval && oldlenp) { -+ size_t oldlen; -+ -+ if (get_user(oldlen, oldlenp)) -+ return -EFAULT; -+ -+ if (oldlen != sizeof(unsigned int)) -+ return -EINVAL; -+ -+ if (put_user(cpufreq_get(cpu), (unsigned int *)oldval) || -+ put_user(sizeof(unsigned int), oldlenp)) -+ return -EFAULT; -+ } -+ if (newval && newlen) { -+ unsigned int freq; -+ -+ if (newlen != sizeof(unsigned int)) -+ return -EINVAL; -+ -+ if (get_user(freq, (unsigned int *)newval)) -+ return -EFAULT; -+ -+ cpufreq_set(freq, cpu); -+ } -+ return 1; -+} -+ -+/* ctl_table ctl_cpu_vars_{0,1,...,(NR_CPUS-1)} */ -+/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */ -+ CTL_TABLE_CPU_VARS(0); -+#if NR_CPUS > 1 -+ CTL_TABLE_CPU_VARS(1); -+#endif -+#if NR_CPUS > 2 -+ CTL_TABLE_CPU_VARS(2); -+#endif -+#if NR_CPUS > 3 -+ CTL_TABLE_CPU_VARS(3); -+#endif -+#if NR_CPUS > 4 -+ CTL_TABLE_CPU_VARS(4); -+#endif -+#if NR_CPUS > 5 -+ CTL_TABLE_CPU_VARS(5); -+#endif -+#if NR_CPUS > 6 -+ CTL_TABLE_CPU_VARS(6); -+#endif -+#if NR_CPUS > 7 -+ CTL_TABLE_CPU_VARS(7); -+#endif -+#if NR_CPUS > 8 -+ CTL_TABLE_CPU_VARS(8); -+#endif -+#if NR_CPUS > 9 -+ CTL_TABLE_CPU_VARS(9); -+#endif -+#if NR_CPUS > 10 -+ CTL_TABLE_CPU_VARS(10); -+#endif -+#if NR_CPUS > 11 -+ CTL_TABLE_CPU_VARS(11); -+#endif -+#if NR_CPUS > 12 -+ CTL_TABLE_CPU_VARS(12); -+#endif -+#if NR_CPUS > 13 -+ CTL_TABLE_CPU_VARS(13); -+#endif -+#if NR_CPUS > 14 -+ CTL_TABLE_CPU_VARS(14); -+#endif -+#if NR_CPUS > 15 -+ CTL_TABLE_CPU_VARS(15); -+#endif -+#if NR_CPUS > 16 -+ CTL_TABLE_CPU_VARS(16); -+#endif -+#if NR_CPUS > 17 -+ CTL_TABLE_CPU_VARS(17); -+#endif -+#if NR_CPUS > 18 -+ CTL_TABLE_CPU_VARS(18); -+#endif -+#if NR_CPUS > 19 -+ CTL_TABLE_CPU_VARS(19); -+#endif -+#if NR_CPUS > 20 -+ CTL_TABLE_CPU_VARS(20); -+#endif -+#if NR_CPUS > 21 -+ CTL_TABLE_CPU_VARS(21); -+#endif -+#if NR_CPUS > 22 -+ CTL_TABLE_CPU_VARS(22); -+#endif -+#if NR_CPUS > 23 -+ CTL_TABLE_CPU_VARS(23); -+#endif -+#if NR_CPUS > 24 -+ CTL_TABLE_CPU_VARS(24); -+#endif -+#if NR_CPUS > 25 -+ CTL_TABLE_CPU_VARS(25); -+#endif -+#if NR_CPUS > 26 -+ CTL_TABLE_CPU_VARS(26); -+#endif -+#if NR_CPUS > 27 -+ CTL_TABLE_CPU_VARS(27); -+#endif -+#if NR_CPUS > 28 -+ CTL_TABLE_CPU_VARS(28); -+#endif -+#if NR_CPUS > 29 -+ CTL_TABLE_CPU_VARS(29); -+#endif -+#if NR_CPUS > 30 -+ CTL_TABLE_CPU_VARS(30); -+#endif -+#if NR_CPUS > 31 -+ CTL_TABLE_CPU_VARS(31); -+#endif -+#if NR_CPUS > 32 -+#error please extend CPU enumeration -+#endif -+ -+/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */ -+static ctl_table ctl_cpu_table[NR_CPUS + 1] = { -+ CPU_ENUM(0), -+#if NR_CPUS > 1 -+ CPU_ENUM(1), -+#endif -+#if NR_CPUS > 2 -+ CPU_ENUM(2), -+#endif -+#if NR_CPUS > 3 -+ CPU_ENUM(3), -+#endif -+#if NR_CPUS > 4 -+ CPU_ENUM(4), -+#endif -+#if NR_CPUS > 5 -+ CPU_ENUM(5), -+#endif -+#if NR_CPUS > 6 -+ CPU_ENUM(6), -+#endif -+#if NR_CPUS > 7 -+ CPU_ENUM(7), -+#endif -+#if NR_CPUS > 8 -+ CPU_ENUM(8), -+#endif -+#if NR_CPUS > 9 -+ CPU_ENUM(9), -+#endif -+#if NR_CPUS > 10 -+ CPU_ENUM(10), -+#endif -+#if NR_CPUS > 11 -+ CPU_ENUM(11), -+#endif -+#if NR_CPUS > 12 -+ CPU_ENUM(12), -+#endif -+#if NR_CPUS > 13 -+ CPU_ENUM(13), -+#endif -+#if NR_CPUS > 14 -+ CPU_ENUM(14), -+#endif -+#if NR_CPUS > 15 -+ CPU_ENUM(15), -+#endif -+#if NR_CPUS > 16 -+ CPU_ENUM(16), -+#endif -+#if NR_CPUS > 17 -+ CPU_ENUM(17), -+#endif -+#if NR_CPUS > 18 -+ CPU_ENUM(18), -+#endif -+#if NR_CPUS > 19 -+ CPU_ENUM(19), -+#endif -+#if NR_CPUS > 20 -+ CPU_ENUM(20), -+#endif -+#if NR_CPUS > 21 -+ CPU_ENUM(21), -+#endif -+#if NR_CPUS > 22 -+ CPU_ENUM(22), -+#endif -+#if NR_CPUS > 23 -+ CPU_ENUM(23), -+#endif -+#if NR_CPUS > 24 -+ CPU_ENUM(24), -+#endif -+#if NR_CPUS > 25 -+ CPU_ENUM(25), -+#endif -+#if NR_CPUS > 26 -+ CPU_ENUM(26), -+#endif -+#if NR_CPUS > 27 -+ CPU_ENUM(27), -+#endif -+#if NR_CPUS > 28 -+ CPU_ENUM(28), -+#endif -+#if NR_CPUS > 29 -+ CPU_ENUM(29), -+#endif -+#if NR_CPUS > 30 -+ CPU_ENUM(30), -+#endif -+#if NR_CPUS > 31 -+ CPU_ENUM(31), -+#endif -+#if NR_CPUS > 32 -+#error please extend CPU enumeration -+#endif -+ { -+ .ctl_name = 0, -+ } -+}; -+ -+static ctl_table ctl_cpu[2] = { -+ { -+ .ctl_name = CTL_CPU, -+ .procname = "cpu", -+ .mode = 0555, -+ .child = ctl_cpu_table, -+ }, -+ { -+ .ctl_name = 0, -+ } -+}; -+ -+struct ctl_table_header *cpufreq_sysctl_table; -+ -+static inline void cpufreq_sysctl_init(void) -+{ -+ cpufreq_sysctl_table = register_sysctl_table(ctl_cpu, 0); -+} -+ -+static inline void cpufreq_sysctl_exit(void) -+{ -+ unregister_sysctl_table(cpufreq_sysctl_table); -+} -+ -+#else -+#define cpufreq_sysctl_init() do {} while(0) -+#define cpufreq_sysctl_exit() do {} while(0) -+#endif /* CONFIG_CPU_FREQ_24API */ -+ -+ -+/************************** sysfs interface ************************/ -+static ssize_t show_speed (struct cpufreq_policy *policy, char *buf) -+{ -+ return sprintf (buf, "%u\n", cpu_cur_freq[policy->cpu]); -+} -+ -+static ssize_t -+store_speed (struct cpufreq_policy *policy, const char *buf, size_t count) -+{ -+ unsigned int freq = 0; -+ unsigned int ret; -+ -+ ret = sscanf (buf, "%u", &freq); -+ if (ret != 1) -+ return -EINVAL; -+ -+ cpufreq_set(freq, policy->cpu); -+ -+ return count; -+} -+ -+static struct freq_attr freq_attr_scaling_setspeed = { -+ .attr = { .name = "scaling_setspeed", .mode = 0644 }, -+ .show = show_speed, -+ .store = store_speed, -+}; -+ -+static int cpufreq_governor_userspace(struct cpufreq_policy *policy, -+ unsigned int event) -+{ -+ unsigned int cpu = policy->cpu; -+ switch (event) { -+ case CPUFREQ_GOV_START: -+ if ((!cpu_online(cpu)) || (!try_module_get(THIS_MODULE)) || -+ !policy->cur) -+ return -EINVAL; -+ down(&userspace_sem); -+ cpu_is_managed[cpu] = 1; -+ cpu_min_freq[cpu] = policy->min; -+ cpu_max_freq[cpu] = policy->max; -+ cpu_cur_freq[cpu] = policy->cur; -+ sysfs_create_file (&policy->kobj, &freq_attr_scaling_setspeed.attr); -+ memcpy (¤t_policy[cpu], policy, sizeof(struct cpufreq_policy)); -+ up(&userspace_sem); -+ break; -+ case CPUFREQ_GOV_STOP: -+ down(&userspace_sem); -+ cpu_is_managed[cpu] = 0; -+ cpu_min_freq[cpu] = 0; -+ cpu_max_freq[cpu] = 0; -+ sysfs_remove_file (&policy->kobj, &freq_attr_scaling_setspeed.attr); -+ up(&userspace_sem); -+ module_put(THIS_MODULE); -+ break; -+ case CPUFREQ_GOV_LIMITS: -+ down(&userspace_sem); -+ cpu_min_freq[cpu] = policy->min; -+ cpu_max_freq[cpu] = policy->max; -+ if (policy->max < cpu_cur_freq[cpu]) -+ cpufreq_driver_target(¤t_policy[cpu], policy->max, -+ CPUFREQ_RELATION_H); -+ else if (policy->min > cpu_cur_freq[cpu]) -+ cpufreq_driver_target(¤t_policy[cpu], policy->min, -+ CPUFREQ_RELATION_L); -+ memcpy (¤t_policy[cpu], policy, sizeof(struct cpufreq_policy)); -+ up(&userspace_sem); -+ break; -+ } -+ return 0; -+} -+ -+/* on ARM SA1100 we need to rely on the values of cpufreq_get() - because -+ * of this, cpu_cur_freq[] needs to be set early. -+ */ -+#if defined(CONFIG_ARM) && defined(CONFIG_ARCH_SA1100) -+extern unsigned int sa11x0_getspeed(void); -+ -+static void cpufreq_sa11x0_compat(void) -+{ -+ cpu_cur_freq[0] = sa11x0_getspeed(); -+} -+#else -+#define cpufreq_sa11x0_compat() do {} while(0) -+#endif -+ -+ -+static struct cpufreq_governor cpufreq_gov_userspace = { -+ .name = "userspace", -+ .governor = cpufreq_governor_userspace, -+ .owner = THIS_MODULE, -+}; -+EXPORT_SYMBOL(cpufreq_gov_userspace); -+ -+static int already_init = 0; -+ -+int cpufreq_gov_userspace_init(void) -+{ -+ if (!already_init) { -+ down(&userspace_sem); -+ cpufreq_sa11x0_compat(); -+ cpufreq_sysctl_init(); -+ cpufreq_register_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); -+ already_init = 1; -+ up(&userspace_sem); -+ } -+ return cpufreq_register_governor(&cpufreq_gov_userspace); -+} -+EXPORT_SYMBOL(cpufreq_gov_userspace_init); -+ -+ -+static void __exit cpufreq_gov_userspace_exit(void) -+{ -+ cpufreq_unregister_governor(&cpufreq_gov_userspace); -+ cpufreq_unregister_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); -+ cpufreq_sysctl_exit(); -+} -+ -+ -+MODULE_AUTHOR ("Dominik Brodowski , Russell King "); -+MODULE_DESCRIPTION ("CPUfreq policy governor 'userspace'"); -+MODULE_LICENSE ("GPL"); -+ -+module_init(cpufreq_gov_userspace_init); -+module_exit(cpufreq_gov_userspace_exit); -diff -urN linux-2.4.26/drivers/i2c/Config.in linux-2.4.26-vrs1/drivers/i2c/Config.in ---- linux-2.4.26/drivers/i2c/Config.in 2004-04-19 11:44:16.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/i2c/Config.in 2004-04-18 21:47:50.000000000 +0100 -@@ -17,6 +17,15 @@ - int ' GPIO pin used for SCL' CONFIG_SCx200_I2C_SCL 12 - int ' GPIO pin used for SDA' CONFIG_SCx200_I2C_SDA 13 - fi -+ -+ dep_tristate ' Guide GPIO adapter' CONFIG_I2C_GUIDE $CONFIG_I2C_ALGOBIT -+ if [ "$CONFIG_ARCH_OMAHA" = "y" ]; then -+ dep_tristate ' Omaha I2C interface' CONFIG_I2C_OMAHA $CONFIG_I2C -+ fi -+ if [ "$CONFIG_ARCH_SA1100" = "y" ]; then -+ dep_tristate ' Frodo I2C adapter' CONFIG_I2C_FRODO $CONFIG_I2C_ALGOBIT -+ dep_tristate ' SA1100 I2C GPIO adapter' CONFIG_I2C_BIT_SA1100_GPIO $CONFIG_I2C_ALGOBIT -+ fi - fi - - dep_tristate 'NatSemi SCx200 ACCESS.bus' CONFIG_SCx200_ACB $CONFIG_I2C -@@ -49,6 +58,10 @@ - dep_tristate 'Keywest I2C interface in Apple Core99 machines' CONFIG_I2C_KEYWEST $CONFIG_I2C - fi - -+ if [ "$CONFIG_ARCH_AT91RM9200" = "y" ] ; then -+ dep_tristate 'Atmel AT91RM9200 I2C Two-Wire interface (TWI)' CONFIG_I2C_AT91 $CONFIG_I2C -+ fi -+ - if [ "$CONFIG_SIBYTE_SB1xxx_SOC" = "y" ]; then - dep_tristate 'SiByte SMBus interface' CONFIG_I2C_ALGO_SIBYTE $CONFIG_I2C - dep_tristate ' MAX1617 Temperature Sensor' CONFIG_I2C_MAX1617 $CONFIG_I2C_ALGO_SIBYTE -diff -urN linux-2.4.26/drivers/i2c/Makefile linux-2.4.26-vrs1/drivers/i2c/Makefile ---- linux-2.4.26/drivers/i2c/Makefile 2004-02-27 20:03:25.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/i2c/Makefile 2004-02-23 22:59:17.000000000 +0000 -@@ -8,12 +8,21 @@ - i2c-algo-ite.o i2c-algo-sibyte.o i2c-algo-sgi.o \ - i2c-proc.o - -+# Init order: core, chardev, bit adapters, pcf adapters -+ - obj-$(CONFIG_I2C) += i2c-core.o - obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o -+ -+# Bit adapters - obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o - obj-$(CONFIG_I2C_PHILIPSPAR) += i2c-philips-par.o - obj-$(CONFIG_I2C_ELV) += i2c-elv.o - obj-$(CONFIG_I2C_VELLEMAN) += i2c-velleman.o -+obj-$(CONFIG_I2C_GUIDE) += i2c-guide.o -+obj-$(CONFIG_I2C_FRODO) += i2c-frodo.o -+obj-$(CONFIG_I2C_OMAHA) += i2c-omaha.o -+ -+# PCF adapters - obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o - obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o - obj-$(CONFIG_ITE_I2C_ALGO) += i2c-algo-ite.o -@@ -30,4 +39,3 @@ - # This is needed for automatic patch generation: sensors code ends here - - include $(TOPDIR)/Rules.make -- -diff -urN linux-2.4.26/drivers/i2c/i2c-algo-bit.c linux-2.4.26-vrs1/drivers/i2c/i2c-algo-bit.c ---- linux-2.4.26/drivers/i2c/i2c-algo-bit.c 2004-02-27 20:03:25.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/i2c/i2c-algo-bit.c 2004-02-23 13:36:30.000000000 +0000 -@@ -169,7 +169,14 @@ - * 1 if the device acknowledged - * 0 if the device did not ack - * -ETIMEDOUT if an error occurred (while raising the scl line) -- */ -+ -+ * tsong@iders.ca: an instruction to disable any timeconsuming interrupt -+ here except the heart beat of timer2 should be added before setsda(adap, sb). -+ because when interrupt occurs during -+ scl is set high, the interrupt service routine is served and may take long, -+ after the interrupt returns, sda could be sampled by the device(slave) -+ more than once, and this cause error problem. -+*/ - static int i2c_outb(struct i2c_adapter *i2c_adap, char c) - { - int i; -@@ -582,9 +589,7 @@ - printk("\n"); - } - --#ifdef MODULE - MOD_INC_USE_COUNT; --#endif - i2c_add_adapter(adap); - - return 0; -@@ -600,15 +605,13 @@ - - DEB2(printk("i2c-algo-bit.o: adapter unregistered: %s\n",adap->name)); - --#ifdef MODULE - MOD_DEC_USE_COUNT; --#endif - return 0; - } - --int __init i2c_algo_bit_init (void) -+static int __init i2c_algo_bit_init (void) - { -- printk(KERN_INFO "i2c-algo-bit.o: i2c bit algorithm module\n"); -+ printk(KERN_DEBUG "i2c-algo-bit.o: i2c bit algorithm module\n"); - return 0; - } - -@@ -617,7 +620,6 @@ - EXPORT_SYMBOL(i2c_bit_add_bus); - EXPORT_SYMBOL(i2c_bit_del_bus); - --#ifdef MODULE - MODULE_AUTHOR("Simon G. Vogl "); - MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm"); - MODULE_LICENSE("GPL"); -@@ -631,12 +633,4 @@ - MODULE_PARM_DESC(i2c_debug, - "debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol"); - --int init_module(void) --{ -- return i2c_algo_bit_init(); --} -- --void cleanup_module(void) --{ --} --#endif -+module_init(i2c_algo_bit_init); -diff -urN linux-2.4.26/drivers/i2c/i2c-algo-pcf.c linux-2.4.26-vrs1/drivers/i2c/i2c-algo-pcf.c ---- linux-2.4.26/drivers/i2c/i2c-algo-pcf.c 2004-02-27 20:03:25.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/i2c/i2c-algo-pcf.c 2004-02-23 13:36:30.000000000 +0000 -@@ -475,9 +475,7 @@ - return i; - } - --#ifdef MODULE - MOD_INC_USE_COUNT; --#endif - - i2c_add_adapter(adap); - -@@ -515,13 +513,11 @@ - return res; - DEB2(printk("i2c-algo-pcf.o: adapter unregistered: %s\n",adap->name)); - --#ifdef MODULE - MOD_DEC_USE_COUNT; --#endif - return 0; - } - --int __init i2c_algo_pcf_init (void) -+static int __init i2c_algo_pcf_init (void) - { - printk("i2c-algo-pcf.o: i2c pcf8584 algorithm module\n"); - return 0; -@@ -531,7 +527,6 @@ - EXPORT_SYMBOL(i2c_pcf_add_bus); - EXPORT_SYMBOL(i2c_pcf_del_bus); - --#ifdef MODULE - MODULE_AUTHOR("Hans Berglund "); - MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm"); - MODULE_LICENSE("GPL"); -@@ -543,13 +538,4 @@ - MODULE_PARM_DESC(i2c_debug, - "debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol"); - -- --int init_module(void) --{ -- return i2c_algo_pcf_init(); --} -- --void cleanup_module(void) --{ --} --#endif -+module_init(i2c_algo_pcf_init); -diff -urN linux-2.4.26/drivers/i2c/i2c-core.c linux-2.4.26-vrs1/drivers/i2c/i2c-core.c ---- linux-2.4.26/drivers/i2c/i2c-core.c 2004-02-27 20:03:25.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/i2c/i2c-core.c 2004-02-27 22:54:22.000000000 +0000 -@@ -41,7 +41,7 @@ - - /* exclusive access to the bus */ - #define I2C_LOCK(adap) down(&adap->lock) --#define I2C_UNLOCK(adap) up(&adap->lock) -+#define I2C_UNLOCK(adap) up(&adap->lock) - - #define ADAP_LOCK() down(&adap_lock) - #define ADAP_UNLOCK() up(&adap_lock) -@@ -67,7 +67,7 @@ - static int driver_count; - - /**** debug level */ --static int i2c_debug=1; -+static int i2c_debug = 0; - - /* --------------------------------------------------- - * /proc entry declarations -@@ -77,14 +77,14 @@ - #ifdef CONFIG_PROC_FS - - static int i2cproc_init(void); --static int i2cproc_cleanup(void); -+static void i2cproc_cleanup(void); - --static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, -+static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, - loff_t *ppos); - static int read_bus_i2c(char *buf, char **start, off_t offset, int len, - int *eof , void *private); - --/* To implement the dynamic /proc/bus/i2c-? files, we need our own -+/* To implement the dynamic /proc/bus/i2c-? files, we need our own - implementation of the read hook */ - static struct file_operations i2cproc_operations = { - read: i2cproc_bus_read, -@@ -101,8 +101,8 @@ - - - /* --------------------------------------------------- -- * registering functions -- * --------------------------------------------------- -+ * registering functions -+ * --------------------------------------------------- - */ - - /* ----- -@@ -119,7 +119,7 @@ - if (NULL == adapters[i]) - break; - if (I2C_ADAP_MAX == i) { -- printk(KERN_WARNING -+ printk(KERN_WARNING - " i2c-core.o: register_adapter(%s) - enlarge I2C_ADAP_MAX.\n", - adap->name); - res = -ENOMEM; -@@ -129,7 +129,7 @@ - adapters[i] = adap; - adap_count++; - ADAP_UNLOCK(); -- -+ - /* init data types */ - init_MUTEX(&adap->lock); - -@@ -157,18 +157,18 @@ - #endif /* def CONFIG_PROC_FS */ - - /* inform drivers of new adapters */ -- DRV_LOCK(); -+ DRV_LOCK(); - for (j=0;jflags&(I2C_DF_NOTIFY|I2C_DF_DUMMY))) - /* We ignore the return code; if it fails, too bad */ - drivers[j]->attach_adapter(adap); - DRV_UNLOCK(); -- -+ - DEB(printk(KERN_DEBUG "i2c-core.o: adapter %s registered as adapter %d.\n", - adap->name,i)); - -- return 0; -+ return 0; - - - ERROR1: -@@ -203,13 +203,13 @@ - * this or hell will break loose... - */ - DRV_LOCK(); -- for (j = 0; j < I2C_DRIVER_MAX; j++) -+ for (j = 0; j < I2C_DRIVER_MAX; j++) - if (drivers[j] && (drivers[j]->flags & I2C_DF_DUMMY)) - if ((res = drivers[j]->attach_adapter(adap))) { - printk(KERN_WARNING "i2c-core.o: can't detach adapter %s " - "while detaching driver %s: driver not " - "detached!",adap->name,drivers[j]->name); -- goto ERROR1; -+ goto ERROR1; - } - DRV_UNLOCK(); - -@@ -241,8 +241,8 @@ - - adapters[i] = NULL; - adap_count--; -- -- ADAP_UNLOCK(); -+ -+ ADAP_UNLOCK(); - DEB(printk(KERN_DEBUG "i2c-core.o: adapter unregistered: %s\n",adap->name)); - return 0; - -@@ -269,7 +269,7 @@ - if (NULL == drivers[i]) - break; - if (I2C_DRIVER_MAX == i) { -- printk(KERN_WARNING -+ printk(KERN_WARNING - " i2c-core.o: register_driver(%s) " - "- enlarge I2C_DRIVER_MAX.\n", - driver->name); -@@ -279,11 +279,11 @@ - - drivers[i] = driver; - driver_count++; -- -+ - DRV_UNLOCK(); /* driver was successfully added */ -- -+ - DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name)); -- -+ - ADAP_LOCK(); - - /* now look for instances of driver on our adapters -@@ -314,11 +314,11 @@ - return -ENODEV; - } - /* Have a look at each adapter, if clients of this driver are still -- * attached. If so, detach them to be able to kill the driver -+ * attached. If so, detach them to be able to kill the driver - * afterwards. - */ - DEB2(printk(KERN_DEBUG "i2c-core.o: unregister_driver - looking for clients.\n")); -- /* removing clients does not depend on the notify flag, else -+ /* removing clients does not depend on the notify flag, else - * invalid operation might (will!) result, when using stale client - * pointers. - */ -@@ -333,7 +333,7 @@ - /* DUMMY drivers do not register their clients, so we have to - * use a trick here: we call driver->attach_adapter to - * *detach* it! Of course, each dummy driver should know about -- * this or hell will break loose... -+ * this or hell will break loose... - */ - if ((res = driver->attach_adapter(adap))) { - printk(KERN_WARNING "i2c-core.o: while unregistering " -@@ -345,9 +345,9 @@ - return res; - } - } else { -- for (j=0;jclients[j]; -- if (client != NULL && -+ if (client != NULL && - client->driver == driver) { - DEB2(printk(KERN_DEBUG "i2c-core.o: " - "detaching client %s:\n", -@@ -376,7 +376,7 @@ - drivers[i] = NULL; - driver_count--; - DRV_UNLOCK(); -- -+ - DEB(printk(KERN_DEBUG "i2c-core.o: driver unregistered: %s\n",driver->name)); - return 0; - } -@@ -384,7 +384,7 @@ - int i2c_check_addr (struct i2c_adapter *adapter, int addr) - { - int i; -- for (i = 0; i < I2C_CLIENT_MAX ; i++) -+ for (i = 0; i < I2C_CLIENT_MAX ; i++) - if (adapter->clients[i] && (adapter->clients[i]->addr == addr)) - return -EBUSY; - return 0; -@@ -402,7 +402,7 @@ - if (NULL == adapter->clients[i]) - break; - if (I2C_CLIENT_MAX == i) { -- printk(KERN_WARNING -+ printk(KERN_WARNING - " i2c-core.o: attach_client(%s) - enlarge I2C_CLIENT_MAX.\n", - client->name); - return -ENOMEM; -@@ -410,9 +410,9 @@ - - adapter->clients[i] = client; - adapter->client_count++; -- -- if (adapter->client_register) -- if (adapter->client_register(client)) -+ -+ if (adapter->client_register) -+ if (adapter->client_register(client)) - printk(KERN_DEBUG "i2c-core.o: warning: client_register seems " - "to have failed for client %02x at adapter %s\n", - client->addr,adapter->name); -@@ -421,7 +421,7 @@ - - if(client->flags & I2C_CLIENT_ALLOW_USE) - client->usage_count = 0; -- -+ - return 0; - } - -@@ -440,12 +440,12 @@ - client->name); - return -ENODEV; - } -- -- if( (client->flags & I2C_CLIENT_ALLOW_USE) && -+ -+ if( (client->flags & I2C_CLIENT_ALLOW_USE) && - (client->usage_count>0)) - return -EBUSY; -- -- if (adapter->client_unregister != NULL) -+ -+ if (adapter->client_unregister != NULL) - if ((res = adapter->client_unregister(client))) { - printk(KERN_ERR "i2c-core.o: client_unregister [%s] failed, " - "client not detached",client->name); -@@ -471,7 +471,7 @@ - - void i2c_dec_use_client(struct i2c_client *client) - { -- -+ - if (client->driver->dec_use != NULL) - client->driver->dec_use(client); - -@@ -479,65 +479,65 @@ - client->adapter->dec_use(client->adapter); - } - --struct i2c_client *i2c_get_client(int driver_id, int adapter_id, -+struct i2c_client *i2c_get_client(int driver_id, int adapter_id, - struct i2c_client *prev) - { - int i,j; -- -+ - /* Will iterate through the list of clients in each adapter of adapters-list -- in search for a client that matches the search criteria. driver_id or -- adapter_id are ignored if set to 0. If both are ignored this returns -+ in search for a client that matches the search criteria. driver_id or -+ adapter_id are ignored if set to 0. If both are ignored this returns - first client found. */ -- -- i = j = 0; -- -- /* set starting point */ -+ -+ i = j = 0; -+ -+ /* set starting point */ - if(prev) - { - if(!(prev->adapter)) - return (struct i2c_client *) -EINVAL; -- -+ - for(j=0; j < I2C_ADAP_MAX; j++) - if(prev->adapter == adapters[j]) - break; -- -+ - /* invalid starting point? */ - if (I2C_ADAP_MAX == j) { - printk(KERN_WARNING " i2c-core.o: get_client adapter for client:[%s] not found\n", - prev->name); - return (struct i2c_client *) -ENODEV; -- } -- -+ } -+ - for(i=0; i < I2C_CLIENT_MAX; i++) - if(prev == adapters[j]->clients[i]) - break; -- -+ - /* invalid starting point? */ - if (I2C_CLIENT_MAX == i) { - printk(KERN_WARNING " i2c-core.o: get_client client:[%s] not found\n", - prev->name); - return (struct i2c_client *) -ENODEV; -- } -- -+ } -+ - i++; /* start from one after prev */ - } -- -+ - for(; j < I2C_ADAP_MAX; j++) - { - if(!adapters[j]) - continue; -- -+ - if(adapter_id && (adapters[j]->id != adapter_id)) - continue; -- -+ - for(; i < I2C_CLIENT_MAX; i++) - { - if(!adapters[j]->clients[i]) - continue; -- -+ - if(driver_id && (adapters[j]->clients[i]->driver->id != driver_id)) - continue; -- if(adapters[j]->clients[i]->flags & I2C_CLIENT_ALLOW_USE) -+ if(adapters[j]->clients[i]->flags & I2C_CLIENT_ALLOW_USE) - return adapters[j]->clients[i]; - } - i = 0; -@@ -549,12 +549,12 @@ - int i2c_use_client(struct i2c_client *client) - { - if(client->flags & I2C_CLIENT_ALLOW_USE) { -- if (client->flags & I2C_CLIENT_ALLOW_MULTIPLE_USE) -+ if (client->flags & I2C_CLIENT_ALLOW_MULTIPLE_USE) - client->usage_count++; - else { -- if(client->usage_count > 0) -+ if(client->usage_count > 0) - return -EBUSY; -- else -+ else - client->usage_count++; - } - } -@@ -575,9 +575,9 @@ - return -EPERM; - } - } -- -+ - i2c_dec_use_client(client); -- -+ - return 0; - } - -@@ -589,7 +589,7 @@ - #ifdef CONFIG_PROC_FS - - /* This function generates the output for /proc/bus/i2c */ --int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof, -+int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof, - void *private) - { - int i; -@@ -615,7 +615,7 @@ - } - - /* This function generates the output for /proc/bus/i2c-? */ --ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, -+ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, - loff_t *ppos) - { - struct inode * inode = file->f_dentry->d_inode; -@@ -626,7 +626,7 @@ - int order[I2C_CLIENT_MAX]; - - if (count > 4000) -- return -EINVAL; -+ return -EINVAL; - len_total = file->f_pos + count; - /* Too bad if this gets longer (unlikely) */ - if (len_total > 4000) -@@ -641,12 +641,12 @@ - sorted by address */ - order_nr=0; - for (j = 0; j < I2C_CLIENT_MAX; j++) { -- if ((client = adapters[i]->clients[j]) && -+ if ((client = adapters[i]->clients[j]) && - (client->driver->id != I2C_DRIVERID_I2CDEV)) { -- for(k = order_nr; -- (k > 0) && -+ for(k = order_nr; -+ (k > 0) && - adapters[i]->clients[order[k-1]]-> -- addr > client->addr; -+ addr > client->addr; - k--) - order[k] = order[k-1]; - order[k] = j; -@@ -665,7 +665,7 @@ - len = len - file->f_pos; - if (len > count) - len = count; -- if (len < 0) -+ if (len < 0) - len = 0; - if (copy_to_user (buf,kbuf+file->f_pos, len)) { - kfree(kbuf); -@@ -689,7 +689,7 @@ - printk("i2c-core.o: /proc/bus/ does not exist"); - i2cproc_cleanup(); - return -ENOENT; -- } -+ } - proc_bus_i2c = create_proc_entry("i2c",0,proc_bus); - if (!proc_bus_i2c) { - printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/i2c"); -@@ -702,14 +702,13 @@ - return 0; - } - --int i2cproc_cleanup(void) -+static void i2cproc_cleanup(void) - { - - if (i2cproc_initialized >= 1) { - remove_proc_entry("i2c",proc_bus); - i2cproc_initialized -= 2; - } -- return 0; - } - - -@@ -751,10 +750,10 @@ - msg.flags = client->flags & I2C_M_TEN; - msg.len = count; - (const char *)msg.buf = buf; -- -+ - DEB2(printk(KERN_DEBUG "i2c-core.o: master_send: writing %d bytes on %s.\n", - count,client->adapter->name)); -- -+ - I2C_LOCK(adap); - ret = adap->algo->master_xfer(adap,&msg,1); - I2C_UNLOCK(adap); -@@ -784,14 +783,14 @@ - - DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: reading %d bytes on %s.\n", - count,client->adapter->name)); -- -+ - I2C_LOCK(adap); - ret = adap->algo->master_xfer(adap,&msg,1); - I2C_UNLOCK(adap); -- -+ - DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n", - ret, count, client->addr)); -- -+ - /* if everything went ok (i.e. 1 msg transmitted), return #bytes - * transmitted, else error code. - */ -@@ -852,7 +851,7 @@ - found = 0; - - for (i = 0; !found && (address_data->force[i] != I2C_CLIENT_END); i += 3) { -- if (((adap_id == address_data->force[i]) || -+ if (((adap_id == address_data->force[i]) || - (address_data->force[i] == ANY_I2C_BUS)) && - (addr == address_data->force[i+1])) { - DEB2(printk(KERN_DEBUG "i2c-core.o: found force parameter for adapter %d, addr %04x\n", -@@ -862,7 +861,7 @@ - found = 1; - } - } -- if (found) -+ if (found) - continue; - - /* If this address is in one of the ignores, we can forget about -@@ -870,7 +869,7 @@ - for (i = 0; - !found && (address_data->ignore[i] != I2C_CLIENT_END); - i += 2) { -- if (((adap_id == address_data->ignore[i]) || -+ if (((adap_id == address_data->ignore[i]) || - ((address_data->ignore[i] == ANY_I2C_BUS))) && - (addr == address_data->ignore[i+1])) { - DEB2(printk(KERN_DEBUG "i2c-core.o: found ignore parameter for adapter %d, " -@@ -890,11 +889,11 @@ - found = 1; - } - } -- if (found) -+ if (found) - continue; - -- /* Now, we will do a detection, but only if it is in the normal or -- probe entries */ -+ /* Now, we will do a detection, but only if it is in the normal or -+ probe entries */ - for (i = 0; - !found && (address_data->normal_i2c[i] != I2C_CLIENT_END); - i += 1) { -@@ -939,7 +938,7 @@ - "addr %04x\n", adap_id,addr)); - } - } -- if (!found) -+ if (!found) - continue; - - /* OK, so we really should examine this address. First check -@@ -1087,11 +1086,11 @@ - I2C_SMBUS_I2C_BLOCK_DATA,&data); - } - --/* Simulate a SMBus command using the i2c protocol -+/* Simulate a SMBus command using the i2c protocol - No checking of parameters is done! */ --static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, -+static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, - unsigned short flags, -- char read_write, u8 command, int size, -+ char read_write, u8 command, int size, - union i2c_smbus_data * data) - { - /* So we need to generate a series of msgs. In the case of writing, we -@@ -1101,7 +1100,7 @@ - unsigned char msgbuf0[34]; - unsigned char msgbuf1[34]; - int num = read_write == I2C_SMBUS_READ?2:1; -- struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, -+ struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, - { addr, flags | I2C_M_RD, 0, msgbuf1 } - }; - int i; -@@ -1179,7 +1178,7 @@ - case I2C_SMBUS_BYTE_DATA: - data->byte = msgbuf1[0]; - break; -- case I2C_SMBUS_WORD_DATA: -+ case I2C_SMBUS_WORD_DATA: - case I2C_SMBUS_PROC_CALL: - data->word = msgbuf1[0] | (msgbuf1[1] << 8); - break; -@@ -1189,7 +1188,7 @@ - - - s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, -- char read_write, u8 command, int size, -+ char read_write, u8 command, int size, - union i2c_smbus_data * data) - { - s32 res; -@@ -1207,7 +1206,7 @@ - - - /* You should always define `functionality'; the 'else' is just for -- backward compatibility. */ -+ backward compatibility. */ - u32 i2c_get_functionality (struct i2c_adapter *adap) - { - if (adap->algo->functionality) -@@ -1233,122 +1232,12 @@ - - init_MUTEX(&adap_lock); - init_MUTEX(&driver_lock); -- -- i2cproc_init(); -- -- return 0; --} - --#ifndef MODULE --#ifdef CONFIG_I2C_CHARDEV -- extern int i2c_dev_init(void); --#endif --#ifdef CONFIG_I2C_ALGOBIT -- extern int i2c_algo_bit_init(void); --#endif --#ifdef CONFIG_I2C_PHILIPSPAR -- extern int i2c_bitlp_init(void); --#endif --#ifdef CONFIG_I2C_ELV -- extern int i2c_bitelv_init(void); --#endif --#ifdef CONFIG_I2C_VELLEMAN -- extern int i2c_bitvelle_init(void); --#endif --#ifdef CONFIG_I2C_BITVIA -- extern int i2c_bitvia_init(void); --#endif -- --#ifdef CONFIG_I2C_ALGOPCF -- extern int i2c_algo_pcf_init(void); --#endif --#ifdef CONFIG_I2C_ELEKTOR -- extern int i2c_pcfisa_init(void); --#endif -- --#ifdef CONFIG_I2C_ALGO8XX -- extern int i2c_algo_8xx_init(void); --#endif --#ifdef CONFIG_I2C_RPXLITE -- extern int i2c_rpx_init(void); --#endif -- --#ifdef CONFIG_I2C_ALGO_SIBYTE -- extern int i2c_algo_sibyte_init(void); -- extern int i2c_sibyte_init(void); --#endif --#ifdef CONFIG_I2C_MAX1617 -- extern int i2c_max1617_init(void); --#endif -- --#ifdef CONFIG_I2C_PROC -- extern int sensors_init(void); --#endif -- --/* This is needed for automatic patch generation: sensors code starts here */ --/* This is needed for automatic patch generation: sensors code ends here */ -- --int __init i2c_init_all(void) --{ -- /* --------------------- global ----- */ -- i2c_init(); -- --#ifdef CONFIG_I2C_CHARDEV -- i2c_dev_init(); --#endif -- /* --------------------- bit -------- */ --#ifdef CONFIG_I2C_ALGOBIT -- i2c_algo_bit_init(); --#endif --#ifdef CONFIG_I2C_PHILIPSPAR -- i2c_bitlp_init(); --#endif --#ifdef CONFIG_I2C_ELV -- i2c_bitelv_init(); --#endif --#ifdef CONFIG_I2C_VELLEMAN -- i2c_bitvelle_init(); --#endif -- -- /* --------------------- pcf -------- */ --#ifdef CONFIG_I2C_ALGOPCF -- i2c_algo_pcf_init(); --#endif --#ifdef CONFIG_I2C_ELEKTOR -- i2c_pcfisa_init(); --#endif -- -- /* --------------------- 8xx -------- */ --#ifdef CONFIG_I2C_ALGO8XX -- i2c_algo_8xx_init(); --#endif --#ifdef CONFIG_I2C_RPXLITE -- i2c_rpx_init(); --#endif -- -- /* --------------------- SiByte -------- */ --#ifdef CONFIG_I2C_ALGO_SIBYTE -- i2c_algo_sibyte_init(); -- i2c_sibyte_init(); --#endif --#ifdef CONFIG_I2C_MAX1617 -- i2c_max1617_init(); --#endif -- -- /* -------------- proc interface ---- */ --#ifdef CONFIG_I2C_PROC -- sensors_init(); --#endif --/* This is needed for automatic patch generation: sensors code starts here */ --/* This is needed for automatic patch generation: sensors code ends here */ -+ i2cproc_init(); - - return 0; - } - --#endif -- -- -- - EXPORT_SYMBOL(i2c_add_adapter); - EXPORT_SYMBOL(i2c_del_adapter); - EXPORT_SYMBOL(i2c_add_driver); -@@ -1385,7 +1274,6 @@ - EXPORT_SYMBOL(i2c_get_functionality); - EXPORT_SYMBOL(i2c_check_functionality); - --#ifdef MODULE - MODULE_AUTHOR("Simon G. Vogl "); - MODULE_DESCRIPTION("I2C-Bus main module"); - MODULE_LICENSE("GPL"); -@@ -1393,13 +1281,5 @@ - MODULE_PARM(i2c_debug, "i"); - MODULE_PARM_DESC(i2c_debug,"debug level"); - --int init_module(void) --{ -- return i2c_init(); --} -- --void cleanup_module(void) --{ -- i2cproc_cleanup(); --} --#endif -+module_init(i2c_init); -+module_exit(i2cproc_cleanup); -diff -urN linux-2.4.26/drivers/i2c/i2c-dev.c linux-2.4.26-vrs1/drivers/i2c/i2c-dev.c ---- linux-2.4.26/drivers/i2c/i2c-dev.c 2004-02-27 20:03:25.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/i2c/i2c-dev.c 2004-02-27 23:54:13.000000000 +0000 -@@ -1,5 +1,5 @@ - /* -- i2c-dev.c - i2c-bus driver, char device interface -+ i2c-dev.c - i2c-bus driver, char device interface - - Copyright (C) 1995-97 Simon G. Vogl - Copyright (C) 1998-99 Frodo Looijaard -@@ -25,7 +25,7 @@ - - /* The I2C_RDWR ioctl code is written by Kolja Waschk */ - --/* The devfs code is contributed by Philipp Matthias Hahn -+/* The devfs code is contributed by Philipp Matthias Hahn - */ - - /* $Id: i2c-dev.c,v 1.40 2001/08/25 01:28:01 mds Exp $ */ -@@ -50,19 +50,14 @@ - #include - #include - --#ifdef MODULE --extern int init_module(void); --extern int cleanup_module(void); --#endif /* def MODULE */ -- - /* struct file_operations changed too often in the 2.1 series for nice code */ - --static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, -+static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, - loff_t *offset); --static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count, -+static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count, - loff_t *offset); - --static int i2cdev_ioctl (struct inode *inode, struct file *file, -+static int i2cdev_ioctl (struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); - static int i2cdev_open (struct inode *inode, struct file *file); - -@@ -73,13 +68,8 @@ - static int i2cdev_command(struct i2c_client *client, unsigned int cmd, - void *arg); - --#ifdef MODULE --static --#else --extern --#endif -- int __init i2c_dev_init(void); --static int i2cdev_cleanup(void); -+static int __init i2c_dev_init(void); -+static void i2cdev_cleanup(void); - - static struct file_operations i2cdev_fops = { - owner: THIS_MODULE, -@@ -185,7 +175,7 @@ - return ret; - } - --int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, -+int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) - { - struct i2c_client *client = (struct i2c_client *)file->private_data; -@@ -198,14 +188,14 @@ - unsigned long funcs; - - #ifdef DEBUG -- printk(KERN_DEBUG "i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", -+ printk(KERN_DEBUG "i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", - MINOR(inode->i_rdev),cmd, arg); - #endif /* DEBUG */ - - switch ( cmd ) { - case I2C_SLAVE: - case I2C_SLAVE_FORCE: -- if ((arg > 0x3ff) || -+ if ((arg > 0x3ff) || - (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f)) - return -EINVAL; - if ((cmd == I2C_SLAVE) && i2c_check_addr(client->adapter,arg)) -@@ -224,8 +214,8 @@ - sizeof(unsigned long)))?-EFAULT:0; - - case I2C_RDWR: -- if (copy_from_user(&rdwr_arg, -- (struct i2c_rdwr_ioctl_data *)arg, -+ if (copy_from_user(&rdwr_arg, -+ (struct i2c_rdwr_ioctl_data *)arg, - sizeof(rdwr_arg))) - return -EFAULT; - -@@ -233,9 +223,9 @@ - * be sent at once */ - if (rdwr_arg.nmsgs > 42) - return -EINVAL; -- -+ - rdwr_pa = (struct i2c_msg *) -- kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), -+ kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), - GFP_KERNEL); - - if (rdwr_pa == NULL) return -ENOMEM; -@@ -312,9 +302,9 @@ - (struct i2c_smbus_ioctl_data *) arg, - sizeof(struct i2c_smbus_ioctl_data))) - return -EFAULT; -- if ((data_arg.size != I2C_SMBUS_BYTE) && -+ if ((data_arg.size != I2C_SMBUS_BYTE) && - (data_arg.size != I2C_SMBUS_QUICK) && -- (data_arg.size != I2C_SMBUS_BYTE_DATA) && -+ (data_arg.size != I2C_SMBUS_BYTE_DATA) && - (data_arg.size != I2C_SMBUS_WORD_DATA) && - (data_arg.size != I2C_SMBUS_PROC_CALL) && - (data_arg.size != I2C_SMBUS_BLOCK_DATA) && -@@ -325,9 +315,9 @@ - #endif - return -EINVAL; - } -- /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, -+ /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, - so the check is valid if size==I2C_SMBUS_QUICK too. */ -- if ((data_arg.read_write != I2C_SMBUS_READ) && -+ if ((data_arg.read_write != I2C_SMBUS_READ) && - (data_arg.read_write != I2C_SMBUS_WRITE)) { - #ifdef DEBUG - printk(KERN_DEBUG "i2c-dev.o: read_write out of range (%x) in ioctl I2C_SMBUS.\n", -@@ -339,7 +329,7 @@ - /* Note that command values are always valid! */ - - if ((data_arg.size == I2C_SMBUS_QUICK) || -- ((data_arg.size == I2C_SMBUS_BYTE) && -+ ((data_arg.size == I2C_SMBUS_BYTE) && - (data_arg.read_write == I2C_SMBUS_WRITE))) - /* These are special: we do not use data */ - return i2c_smbus_xfer(client->adapter, client->addr, -@@ -358,13 +348,13 @@ - if ((data_arg.size == I2C_SMBUS_BYTE_DATA) || - (data_arg.size == I2C_SMBUS_BYTE)) - datasize = sizeof(data_arg.data->byte); -- else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || -+ else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || - (data_arg.size == I2C_SMBUS_PROC_CALL)) - datasize = sizeof(data_arg.data->word); - else /* size == I2C_SMBUS_BLOCK_DATA */ - datasize = sizeof(data_arg.data->block); - -- if ((data_arg.size == I2C_SMBUS_PROC_CALL) || -+ if ((data_arg.size == I2C_SMBUS_PROC_CALL) || - (data_arg.read_write == I2C_SMBUS_WRITE)) { - if (copy_from_user(&temp, data_arg.data, datasize)) - return -EFAULT; -@@ -372,7 +362,7 @@ - res = i2c_smbus_xfer(client->adapter,client->addr,client->flags, - data_arg.read_write, - data_arg.command,data_arg.size,&temp); -- if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || -+ if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || - (data_arg.read_write == I2C_SMBUS_READ))) { - if (copy_to_user(data_arg.data, &temp, datasize)) - return -EFAULT; -@@ -479,7 +469,7 @@ - return -1; - } - --int __init i2c_dev_init(void) -+static int __init i2c_dev_init(void) - { - int res; - -@@ -509,7 +499,7 @@ - return 0; - } - --int i2cdev_cleanup(void) -+static void i2cdev_cleanup(void) - { - int res; - -@@ -517,9 +507,9 @@ - if ((res = i2c_del_driver(&i2cdev_driver))) { - printk("i2c-dev.o: Driver deregistration failed, " - "module not removed.\n"); -- return res; -+ return; - } -- i2cdev_initialized --; -+ i2cdev_initialized --; - } - - if (i2cdev_initialized >= 1) { -@@ -531,30 +521,17 @@ - #endif - printk("i2c-dev.o: unable to release major %d for i2c bus\n", - I2C_MAJOR); -- return res; -+ return; - } - i2cdev_initialized --; - } -- return 0; - } - - EXPORT_NO_SYMBOLS; - --#ifdef MODULE -- - MODULE_AUTHOR("Frodo Looijaard and Simon G. Vogl "); - MODULE_DESCRIPTION("I2C /dev entries driver"); - MODULE_LICENSE("GPL"); - --int init_module(void) --{ -- return i2c_dev_init(); --} -- --int cleanup_module(void) --{ -- return i2cdev_cleanup(); --} -- --#endif /* def MODULE */ -- -+module_init(i2c_dev_init); -+module_exit(i2cdev_cleanup); -diff -urN linux-2.4.26/drivers/i2c/i2c-elektor.c linux-2.4.26-vrs1/drivers/i2c/i2c-elektor.c ---- linux-2.4.26/drivers/i2c/i2c-elektor.c 2004-02-27 20:03:25.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/i2c/i2c-elektor.c 2004-02-23 13:36:30.000000000 +0000 -@@ -181,16 +181,12 @@ - - static void pcf_isa_inc_use(struct i2c_adapter *adap) - { --#ifdef MODULE - MOD_INC_USE_COUNT; --#endif - } - - static void pcf_isa_dec_use(struct i2c_adapter *adap) - { --#ifdef MODULE - MOD_DEC_USE_COUNT; --#endif - } - - -@@ -219,7 +215,7 @@ - pcf_isa_unreg, - }; - --int __init i2c_pcfisa_init(void) -+static int __init i2c_pcfisa_init(void) - { - #ifdef __alpha__ - /* check to see we have memory mapped PCF8584 connected to the -@@ -289,10 +285,14 @@ - return 0; - } - -+static void i2c_pcfisa_exit(void) -+{ -+ i2c_pcf_del_bus(&pcf_isa_ops); -+ pcf_isa_exit(); -+} - - EXPORT_NO_SYMBOLS; - --#ifdef MODULE - MODULE_AUTHOR("Hans Berglund "); - MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter"); - MODULE_LICENSE("GPL"); -@@ -304,15 +304,5 @@ - MODULE_PARM(mmapped, "i"); - MODULE_PARM(i2c_debug, "i"); - --int init_module(void) --{ -- return i2c_pcfisa_init(); --} -- --void cleanup_module(void) --{ -- i2c_pcf_del_bus(&pcf_isa_ops); -- pcf_isa_exit(); --} -- --#endif -+module_init(i2c_pcfisa_init); -+module_exit(i2c_pcfisa_exit); -diff -urN linux-2.4.26/drivers/i2c/i2c-elv.c linux-2.4.26-vrs1/drivers/i2c/i2c-elv.c ---- linux-2.4.26/drivers/i2c/i2c-elv.c 2004-02-27 20:03:25.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/i2c/i2c-elv.c 2004-02-27 23:52:23.000000000 +0000 -@@ -75,7 +75,7 @@ - PortData |=2; - } - outb(PortData, DATA); --} -+} - - static int bit_elv_getscl(void *data) - { -@@ -90,7 +90,7 @@ - static int bit_elv_init(void) - { - if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) { -- return -ENODEV; -+ return -ENODEV; - } else { - /* test for ELV adap. */ - if (inb(base+1) & 0x80) { /* BUSY should be high */ -@@ -131,16 +131,12 @@ - - static void bit_elv_inc_use(struct i2c_adapter *adap) - { --#ifdef MODULE - MOD_INC_USE_COUNT; --#endif - } - - static void bit_elv_dec_use(struct i2c_adapter *adap) - { --#ifdef MODULE - MOD_DEC_USE_COUNT; --#endif - } - - /* ------------------------------------------------------------------------ -@@ -164,10 +160,10 @@ - bit_elv_inc_use, - bit_elv_dec_use, - bit_elv_reg, -- bit_elv_unreg, -+ bit_elv_unreg, - }; - --int __init i2c_bitelv_init(void) -+static int __init i2c_bitelv_init(void) - { - printk(KERN_INFO "i2c-elv.o: i2c ELV parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); - if (base==0) { -@@ -194,24 +190,19 @@ - } - - -+static void __exit i2c_bitelv_exit(void) -+{ -+ i2c_bit_del_bus(&bit_elv_ops); -+ bit_elv_exit(); -+} -+ - EXPORT_NO_SYMBOLS; - --#ifdef MODULE - MODULE_AUTHOR("Simon G. Vogl "); - MODULE_DESCRIPTION("I2C-Bus adapter routines for ELV parallel port adapter"); - MODULE_LICENSE("GPL"); - - MODULE_PARM(base, "i"); - --int init_module(void) --{ -- return i2c_bitelv_init(); --} -- --void cleanup_module(void) --{ -- i2c_bit_del_bus(&bit_elv_ops); -- bit_elv_exit(); --} -- --#endif -+module_init(i2c_bitelv_init); -+module_exit(i2c_bitelv_exit); -diff -urN linux-2.4.26/drivers/i2c/i2c-frodo.c linux-2.4.26-vrs1/drivers/i2c/i2c-frodo.c ---- linux-2.4.26/drivers/i2c/i2c-frodo.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/i2c/i2c-frodo.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,114 @@ -+ -+/* -+ * linux/drivers/i2c/i2c-frodo.c -+ * -+ * Author: Abraham van der Merwe -+ * -+ * An I2C adapter driver for the 2d3D, Inc. StrongARM SA-1110 -+ * Development board (Frodo). -+ * -+ * This source code 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 -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+ -+#include -+#include -+ -+static void frodo_setsda (void *data,int state) -+{ -+ if (state) -+ frodo_cpld_set (FRODO_CPLD_I2C,FRODO_I2C_SDA_OUT); -+ else -+ frodo_cpld_clear (FRODO_CPLD_I2C,FRODO_I2C_SDA_OUT); -+} -+ -+static void frodo_setscl (void *data,int state) -+{ -+ if (state) -+ frodo_cpld_set (FRODO_CPLD_I2C,FRODO_I2C_SCL_OUT); -+ else -+ frodo_cpld_clear (FRODO_CPLD_I2C,FRODO_I2C_SCL_OUT); -+} -+ -+static int frodo_getsda (void *data) -+{ -+ return ((frodo_cpld_read (FRODO_CPLD_I2C) & FRODO_I2C_SDA_IN) != 0); -+} -+ -+static int frodo_getscl (void *data) -+{ -+ return ((frodo_cpld_read (FRODO_CPLD_I2C) & FRODO_I2C_SCL_IN) != 0); -+} -+ -+static struct i2c_algo_bit_data bit_frodo_data = { -+ setsda: frodo_setsda, -+ setscl: frodo_setscl, -+ getsda: frodo_getsda, -+ getscl: frodo_getscl, -+ udelay: 80, -+ mdelay: 80, -+ timeout: 100 -+}; -+ -+static int frodo_client_register (struct i2c_client *client) -+{ -+ return (0); -+} -+ -+static int frodo_client_unregister (struct i2c_client *client) -+{ -+ return (0); -+} -+ -+static void frodo_inc_use (struct i2c_adapter *adapter) -+{ -+ MOD_INC_USE_COUNT; -+} -+ -+static void frodo_dec_use (struct i2c_adapter *adapter) -+{ -+ MOD_DEC_USE_COUNT; -+} -+ -+static struct i2c_adapter frodo_ops = { -+ name: "Frodo adapter driver", -+ id: I2C_HW_B_FRODO, -+ algo: NULL, -+ algo_data: &bit_frodo_data, -+ inc_use: frodo_inc_use, -+ dec_use: frodo_dec_use, -+ client_register: frodo_client_register, -+ client_unregister: frodo_client_unregister -+}; -+ -+static int __init i2c_frodo_init (void) -+{ -+ return (i2c_bit_add_bus (&frodo_ops)); -+} -+ -+EXPORT_NO_SYMBOLS; -+ -+static void __exit i2c_frodo_exit (void) -+{ -+ i2c_bit_del_bus (&frodo_ops); -+} -+ -+MODULE_AUTHOR ("Abraham van der Merwe "); -+MODULE_DESCRIPTION ("I2C-Bus adapter routines for Frodo"); -+MODULE_LICENSE ("GPL"); -+EXPORT_NO_SYMBOLS; -+ -+module_init (i2c_frodo_init); -+module_exit (i2c_frodo_exit); -+ -diff -urN linux-2.4.26/drivers/i2c/i2c-guide.c linux-2.4.26-vrs1/drivers/i2c/i2c-guide.c ---- linux-2.4.26/drivers/i2c/i2c-guide.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/i2c/i2c-guide.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,199 @@ -+/************************************************************************************\ -+Copyright : Copyright (C) 1995-2000 Simon G. Vogl -+ Copyright 2002 IDERs Incorporated -+File Name : i2c-guide.c -+Description : this i2c driver uses the GPIO port B pin 0 and pin 1 on the cs89712. -+Notes : To change the bit rate, change the structure i2c_algo_bit_data -+ : to 10 10 100 -+Contact : tsong@iders.ca -+License : This source code 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 -+#include -+#include -+#include -+#include /* for 2.0 kernels to get NULL */ -+#include /* for 2.0 kernels to get ENODEV */ -+#include -+ -+#include // io operation ep_writel() -+#include // io operation clps_writel() -+#include // io operation clps_writel() -+ -+#include -+#include -+ -+/* ----- global defines ----------------------------------------------- */ -+ -+#define DEB(x) /* should be reasonable open, close &c. */ -+#define DEB2(x) /* low level debugging - very slow */ -+#define DEBE(x) x /* error messages */ -+ /* Pin Port Inverted name */ -+#define I2C_SDA 0x08 /* port B ctrl pin 3 (inv) */ -+#define I2C_SCL 0x04 /* port B ctrl pin 2 (inv) */ -+ -+#define I2C_SDAIN 0x08 /* use the same pin with output */ -+#define I2C_SCLIN 0x04 /* use the same pin with output */ -+ -+#define I2C_DMASK 0xf7 /* inverse of I2C_SDA */ -+#define I2C_CMASK 0xfb /* inverse of I2c_SCL */ -+ -+#define PORTB_PIN0_SDA_OUTPUT 0x08 /* pin 3 direction of port B output */ -+#define PORTB_PIN0_SDA_INPUT 0xf7 /* pin 3 direction of port B input */ -+ -+#define PORTB_PIN1_SCL_OUTPUT 0x04 /* pin 2 direction of port B output */ -+#define PORTB_PIN1_SCL_INPUT 0xfb /* pin 2 direction of port B input */ -+ -+int base = 0; -+#define DEFAULT_BASE PBDR -+ -+/* ----- local functions --------------------------------------------------- */ -+ -+static void bit_guide_setscl(void* data, int state) -+{ -+ if (state) { -+ // set port B pin2 input -+ clps_writeb((clps_readb(PBDDR)) & PORTB_PIN1_SCL_INPUT, PBDDR); -+ } -+ else { -+ // clear -+ clps_writeb((clps_readb(PBDR)) & I2C_CMASK, PBDR); -+ // set port B pin2 output -+ clps_writeb((clps_readb(PBDDR)) | PORTB_PIN1_SCL_OUTPUT, PBDDR); -+ } -+} -+ -+static void bit_guide_setsda(void* data, int state) -+{ -+ if (state) { -+ clps_writeb((clps_readb(PBDDR)) & PORTB_PIN0_SDA_INPUT, PBDDR); -+ // float pin 0 (actually drive high by pull up resistor) -+ // clps_writeb((clps_readb(PBDR)) | I2C_SDA, PBDR); // set Jan4 ori: eff -+ // printk("set sda high, state=%i\n",state); -+ } -+ else { -+ // clear -+ clps_writeb((clps_readb(PBDR)) & I2C_DMASK, PBDR); -+ // set port B pin 0 output -+ clps_writeb((clps_readb(PBDDR)) | PORTB_PIN0_SDA_OUTPUT, PBDDR); -+ } -+} -+ -+static int bit_guide_getscl(void *data) -+{ -+ return ( 0 != ( (clps_readb(PBDR)) & I2C_SCLIN ) ); -+} -+ -+static int bit_guide_getsda(void *data) -+{ -+ // set port B pin 0 input Jan4 ori eff -+ clps_writeb((clps_readb(PBDDR)) & PORTB_PIN0_SDA_INPUT, PBDDR); -+ return ( 0 != ( (clps_readb(PBDR) ) & I2C_SDAIN ) ); -+} -+ -+static int bit_guide_init(void) -+{ -+ bit_guide_setsda((void*)base,1); -+ bit_guide_setscl((void*)base,1); -+ return 0; -+} -+ -+static int bit_guide_reg(struct i2c_client *client) -+{ -+ return 0; -+} -+ -+static int bit_guide_unreg(struct i2c_client *client) -+{ -+ return 0; -+} -+ -+static void bit_guide_inc_use(struct i2c_adapter *adap) -+{ -+#ifdef MODULE -+ MOD_INC_USE_COUNT; -+#endif -+} -+ -+static void bit_guide_dec_use(struct i2c_adapter *adap) -+{ -+#ifdef MODULE -+ MOD_DEC_USE_COUNT; -+#endif -+} -+ -+/* ------------------------------------------------------------------------ -+ * Encapsulate the above functions in the correct operations structure. -+ * This is only done when more than one hardware adapter is supported. -+ */ -+ -+/* last line (us, ms, timout) -+ * us dominates the bit rate: 10us means: 100Kbit/sec(25 means 40kbps) -+ * 10ms not known -+ * 100ms timeout -+ */ -+static struct i2c_algo_bit_data bit_guide_data = { -+ NULL, -+ bit_guide_setsda, -+ bit_guide_setscl, -+ bit_guide_getsda, -+ bit_guide_getscl, -+ 50, 10, 100, /* orginal (non-guide) value 10, 10, 100 */ -+}; -+ -+static struct i2c_adapter bit_guide_ops = { -+ "Guide Port B: PIN2-SCL/PIN3-SDA", -+ I2C_HW_B_GUIDE, -+ NULL, -+ &bit_guide_data, -+ bit_guide_inc_use, -+ bit_guide_dec_use, -+ bit_guide_reg, -+ bit_guide_unreg, -+}; -+ -+static int __init i2c_bitguide_init(void) -+{ -+ printk("i2c-guide.o: Guide i2c port B adapter module.\n"); -+ clps_writeb((clps_readb(PBDDR)) & 0xfd, PBDDR); // set service reuest pb1 as input -+ if (base==0) { -+ /* probe some values */ -+ base=DEFAULT_BASE; -+ bit_guide_data.data=(void*)DEFAULT_BASE; -+ if (bit_guide_init()==0) { -+ if(i2c_bit_add_bus(&bit_guide_ops) < 0) -+ return -ENODEV; -+ } else { -+ return -ENODEV; -+ } -+ } else { -+ bit_guide_data.data=(void*)base; -+ if (bit_guide_init()==0) { -+ if(i2c_bit_add_bus(&bit_guide_ops) < 0) -+ return -ENODEV; -+ } else { -+ return -ENODEV; -+ } -+ } -+ printk("i2c-guide.o: found device at %#x.\n",base); -+ return 0; -+} -+ -+EXPORT_NO_SYMBOLS; -+ -+MODULE_AUTHOR("T. C. Song "); -+MODULE_DESCRIPTION("I2C-Bus adapter routines for Guide (cs89712) GPIO port B"); -+MODULE_LICENSE("GPL"); -+ -+MODULE_PARM(base, "i"); -+ -+module_init(i2c_bitguide_init); -+/* for completeness, we should have a module_exit() function, but the -+ GUIDE requires this to always be loaded. If it is unloaded, the -+ operation of the GUIDE is undefined. -+ Nobody has written the i2c_bitguide_exit() routine yet, so it is not included. -+module_exit(i2c_bitguide_exit); -+*/ -diff -urN linux-2.4.26/drivers/i2c/i2c-omaha.c linux-2.4.26-vrs1/drivers/i2c/i2c-omaha.c ---- linux-2.4.26/drivers/i2c/i2c-omaha.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/i2c/i2c-omaha.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,276 @@ -+/* ------------------------------------------------------------------------- * -+ Copyright ARM Limited 2002. All rights reserved. -+ -+ i2c driver for Omaha -+ -+ Notes:Based on i2c-elv.c -+ -+ The S3C2400X01 has better support for I2C, but bit oriented operations -+ are directly supported by the other I2C layers, so we use that method -+ of performing I2C operations. -+ -+ Copyright (C) 1995-2000 Simon G. Vogl -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -+/* ------------------------------------------------------------------------- */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+ -+/* ----- global defines ----------------------------------------------- */ -+#define DEB(x) if (i2c_debug>=1) x; -+#define DEB2(x) if (i2c_debug>=2) x; -+#define DEB3(x) if (i2c_debug>=3) x -+#define DEBE(x) x // error messages -+#define DEBSTAT(x) if (i2c_debug>=3) x; /* print several statistical values*/ -+#define DEBPROTO(x) if (i2c_debug>=9) { x; } -+ /* debug the protocol by showing transferred bits */ -+ -+/* Register and bitdefs for Omaha */ -+ -+// Port G control registers -+static volatile unsigned int pgcon = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_PGCON); -+static volatile unsigned int pgdat = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_PGDAT); -+ -+static volatile unsigned int opencr = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_OPENCR); -+ -+static int base = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_PGCON); -+ -+// Open drain control registers -+#define OPC_CMD BIT2 -+#define OPC_DAT BIT3 -+ -+// data bits in GPIO Port G data register -+#define OMAHA_SDA BIT5 -+#define OMAHA_SCL BIT6 -+#define IIC_WP BIT3 // Write Protect for EEPROM -+ -+// input/out select bits in GPIO G control register -+#define IIC_BITS (BIT12|BIT10|BIT6); -+ -+ -+/* ----- local functions ---------------------------------------------- */ -+ -+ -+static void bit_omaha_setscl(void *data, int state) -+{ -+ unsigned int tmp; -+ -+ if (state) -+ { -+ tmp = __raw_readl(pgdat); -+ tmp |= OMAHA_SCL; -+ __raw_writel(tmp,pgdat); -+ } -+ else -+ { -+ tmp = __raw_readl(pgdat); -+ tmp &= ~OMAHA_SCL; -+ __raw_writel(tmp,pgdat); -+ } -+} -+ -+static void bit_omaha_setsda(void *data, int state) -+{ -+ unsigned int tmp; -+ -+ // ensure that sda is an output at the moment -+ tmp = __raw_readl(pgcon); -+ tmp = tmp | BIT10; -+ __raw_writel(tmp,pgcon); -+ -+ if (state) -+ { -+ tmp = __raw_readl(pgdat); -+ tmp |= OMAHA_SDA; -+ __raw_writel(tmp,pgdat); -+ } -+ else -+ { -+ tmp = __raw_readl(pgdat); -+ tmp &= ~OMAHA_SDA; -+ __raw_writel(tmp,pgdat); -+ } -+} -+ -+static int bit_omaha_getscl(void *data) -+{ -+ if (__raw_readl(pgdat) & OMAHA_SCL) -+ return 1; -+ else -+ return 0; -+} -+ -+static int bit_omaha_getsda(void *data) -+{ -+ unsigned int tmp; -+ -+ // ensure that sda is an output at the moment -+ tmp = __raw_readl(pgcon); -+ tmp = tmp & ~BIT10; -+ __raw_writel(tmp,pgcon); -+ -+ if (__raw_readl(pgdat) & OMAHA_SDA) -+ return 1; -+ else -+ return 0; -+} -+ -+static int bit_omaha_init(void) -+{ -+ // Have we got some mmapped space? -+ if (request_region(base, 0x100, "i2c (omaha bus adapter)") < 0 ) -+ { -+ printk("i2c-omaha.o: requested I/O region (0x%08x) is in use.\n", base); -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+ -+static int bit_omaha_reg(struct i2c_client *client) -+{ -+ return 0; -+} -+ -+ -+static int bit_omaha_unreg(struct i2c_client *client) -+{ -+ return 0; -+} -+ -+static void bit_omaha_inc_use(struct i2c_adapter *adap) -+{ -+ MOD_INC_USE_COUNT; -+} -+ -+static void bit_omaha_dec_use(struct i2c_adapter *adap) -+{ -+ MOD_DEC_USE_COUNT; -+} -+ -+ -+ -+/* ------------------------------------------------------------------------ -+ * Encapsulate the above functions in the correct operations structure. -+ * This is only done when more than one hardware adapter is supported. -+ */ -+static struct i2c_algo_bit_data bit_omaha_data = { -+ NULL, -+ bit_omaha_setsda, -+ bit_omaha_setscl, -+ bit_omaha_getsda, -+ bit_omaha_getscl, -+ 10, 10, 20, /* waits, timeout */ -+}; -+ -+static struct i2c_adapter bit_omaha_ops = { -+ "BIT-Type Omaha I2C adapter", -+ I2C_HW_B_OMAHA, -+ NULL, -+ &bit_omaha_data, -+ bit_omaha_inc_use, -+ bit_omaha_dec_use, -+ bit_omaha_reg, -+ bit_omaha_unreg, -+}; -+ -+static int __init i2c_omaha_init (void) -+{ -+ unsigned int tmp; -+ -+ printk("i2c-omaha.o: i2c omaha adapter module\n"); -+ -+ if (bit_omaha_init() == 0) { -+ if(i2c_bit_add_bus(&bit_omaha_ops) < 0) -+ { -+ printk("Could not add bus!\n"); -+ return -ENODEV; -+ } -+ } else { -+ printk("Could not pcf_omaha_init\n"); -+ return -ENODEV; -+ } -+ -+ // Program Port G bits to output function -+ tmp = __raw_readl(pgcon); -+ tmp |= IIC_BITS; -+ __raw_writel(tmp,pgcon); -+ -+ // Ensure SDA and SCL are open-drain -+ tmp = __raw_readl(opencr); -+ tmp = tmp | OPC_CMD | OPC_DAT; -+ __raw_writel(tmp,opencr); -+ -+ bit_omaha_setsda((void*)base,1); -+ bit_omaha_setscl((void*)base,1); -+ -+ // Disable WP -+ tmp = __raw_readl(pgdat); -+ tmp = tmp & ~IIC_WP; -+ __raw_writel(tmp,pgdat); -+ -+ return 0; -+} -+ -+static void bit_omaha_exit(void) -+{ -+ release_region(base , 2); -+} -+ -+static void i2c_omaha_exit(void) -+{ -+ -+ i2c_bit_del_bus(&bit_omaha_ops); -+ -+ bit_omaha_exit(); -+ -+} -+ -+EXPORT_NO_SYMBOLS; -+ -+MODULE_AUTHOR("ARM Limited "); -+MODULE_DESCRIPTION("I2C-Bus adapter routines for Omaha"); -+MODULE_LICENSE("GPL"); -+ -+MODULE_PARM(base, "i"); -+MODULE_PARM(irq, "i"); -+MODULE_PARM(clock, "i"); -+MODULE_PARM(own, "i"); -+MODULE_PARM(mmapped, "i"); -+MODULE_PARM(i2c_debug, "i"); -+ -+ -+module_init(i2c_omaha_init); -+module_exit(i2c_omaha_exit); -+ -+ -diff -urN linux-2.4.26/drivers/i2c/i2c-philips-par.c linux-2.4.26-vrs1/drivers/i2c/i2c-philips-par.c ---- linux-2.4.26/drivers/i2c/i2c-philips-par.c 2004-02-27 20:03:25.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/i2c/i2c-philips-par.c 2004-02-27 23:50:14.000000000 +0000 -@@ -16,7 +16,7 @@ - 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. */ --/* ------------------------------------------------------------------------- */ -+/* ------------------------------------------------------------------------- */ - - /* With some changes from Kyƶsti MƤlkki and even - Frodo Looijaard */ -@@ -72,7 +72,7 @@ - - static void bit_lp_setscl(void *data, int state) - { -- /*be cautious about state of the control register - -+ /*be cautious about state of the control register - - touch only the one bit needed*/ - if (state) { - parport_write_control((struct parport *) data, -@@ -126,7 +126,7 @@ - - static int bit_lp_getsda2(void *data) - { -- return (parport_read_status((struct parport *) data) & -+ return (parport_read_status((struct parport *) data) & - PARPORT_STATUS_BUSY) ? 0 : 1; - } - -@@ -154,7 +154,7 @@ - * Encapsulate the above functions in the correct operations structure. - * This is only done when more than one hardware adapter is supported. - */ -- -+ - static struct i2c_algo_bit_data bit_lp_data = { - NULL, - bit_lp_setsda, -@@ -162,7 +162,7 @@ - bit_lp_getsda, - bit_lp_getscl, - 80, 80, 100, /* waits, timeout */ --}; -+}; - - static struct i2c_algo_bit_data bit_lp_data2 = { - NULL, -@@ -171,7 +171,7 @@ - bit_lp_getsda2, - NULL, - 80, 80, 100, /* waits, timeout */ --}; -+}; - - static struct i2c_adapter bit_lp_ops = { - "Philips Parallel port adapter", -@@ -197,7 +197,7 @@ - printk(KERN_DEBUG "i2c-philips-par.o: attaching to %s\n", port->name); - - adapter->pdev = parport_register_device(port, "i2c-philips-par", -- NULL, NULL, NULL, -+ NULL, NULL, NULL, - PARPORT_FLAG_EXCL, - NULL); - if (!adapter->pdev) { -@@ -257,16 +257,16 @@ - NULL - }; - --int __init i2c_bitlp_init(void) -+static int __init i2c_bitlp_init(void) - { - printk(KERN_INFO "i2c-philips-par.o: i2c Philips parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); - - parport_register_driver(&i2c_driver); -- -+ - return 0; - } - --void __exit i2c_bitlp_exit(void) -+static void __exit i2c_bitlp_exit(void) - { - parport_unregister_driver(&i2c_driver); - } -@@ -279,14 +279,5 @@ - - MODULE_PARM(type, "i"); - --#ifdef MODULE --int init_module(void) --{ -- return i2c_bitlp_init(); --} -- --void cleanup_module(void) --{ -- i2c_bitlp_exit(); --} --#endif -+module_init(i2c_bitlp_init); -+module_exit(i2c_bitlp_exit); -diff -urN linux-2.4.26/drivers/i2c/i2c-velleman.c linux-2.4.26-vrs1/drivers/i2c/i2c-velleman.c ---- linux-2.4.26/drivers/i2c/i2c-velleman.c 2004-02-27 20:03:25.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/i2c/i2c-velleman.c 2004-02-27 23:46:12.000000000 +0000 -@@ -65,7 +65,7 @@ - } else { - outb(inb(CTRL) | I2C_SCL, CTRL); - } -- -+ - } - - static void bit_velle_setsda(void *data, int state) -@@ -75,8 +75,8 @@ - } else { - outb(inb(CTRL) | I2C_SDA, CTRL); - } -- --} -+ -+} - - static int bit_velle_getscl(void *data) - { -@@ -95,7 +95,7 @@ - base)); - return -ENODEV; - } else { -- request_region(base, (base == 0x3bc)? 3 : 8, -+ request_region(base, (base == 0x3bc)? 3 : 8, - "i2c (Vellemann adapter)"); - bit_velle_setsda((void*)base,1); - bit_velle_setscl((void*)base,1); -@@ -104,7 +104,7 @@ - } - - static void __exit bit_velle_exit(void) --{ -+{ - release_region( base , (base == 0x3bc)? 3 : 8 ); - } - -@@ -121,16 +121,12 @@ - - static void bit_velle_inc_use(struct i2c_adapter *adap) - { --#ifdef MODULE - MOD_INC_USE_COUNT; --#endif - } - - static void bit_velle_dec_use(struct i2c_adapter *adap) - { --#ifdef MODULE - MOD_DEC_USE_COUNT; --#endif - } - - /* ------------------------------------------------------------------------ -@@ -158,7 +154,7 @@ - bit_velle_unreg, - }; - --int __init i2c_bitvelle_init(void) -+static int __init i2c_bitvelle_init(void) - { - printk(KERN_INFO "i2c-velleman.o: i2c Velleman K8000 adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE); - if (base==0) { -@@ -184,24 +180,19 @@ - return 0; - } - -+static void __exit i2c_bitvelle_exit(void) -+{ -+ i2c_bit_del_bus(&bit_velle_ops); -+ bit_velle_exit(); -+} -+ - EXPORT_NO_SYMBOLS; - --#ifdef MODULE - MODULE_AUTHOR("Simon G. Vogl "); - MODULE_DESCRIPTION("I2C-Bus adapter routines for Velleman K8000 adapter"); - MODULE_LICENSE("GPL"); - - MODULE_PARM(base, "i"); - --int init_module(void) --{ -- return i2c_bitvelle_init(); --} -- --void cleanup_module(void) --{ -- i2c_bit_del_bus(&bit_velle_ops); -- bit_velle_exit(); --} -- --#endif -+module_init(i2c_bitvelle_init); -+module_exit(i2c_bitvelle_exit); -diff -urN linux-2.4.26/drivers/ide/Config.in linux-2.4.26-vrs1/drivers/ide/Config.in ---- linux-2.4.26/drivers/ide/Config.in 2004-04-19 11:44:16.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/ide/Config.in 2004-04-18 21:47:50.000000000 +0100 -@@ -107,6 +107,9 @@ - define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_ICS - dep_bool ' RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE $CONFIG_ARCH_ACORN - fi -+ if [ "$CONFIG_ARCH_RISCSTATION" = "y" ]; then -+ dep_bool ' RiscStation IDE' CONFIG_BLK_DEV_IDE_RISCSTATION $CONFIG_ARCH_RISCSTATION -+ fi - if [ "$CONFIG_AMIGA" = "y" ]; then - dep_bool ' Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE $CONFIG_AMIGA - dep_mbool ' Amiga IDE Doubler support (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE $CONFIG_EXPERIMENTAL -diff -urN linux-2.4.26/drivers/ide/arm/Makefile linux-2.4.26-vrs1/drivers/ide/arm/Makefile ---- linux-2.4.26/drivers/ide/arm/Makefile 2003-06-13 15:51:33.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/ide/arm/Makefile 2004-01-14 21:32:25.000000000 +0000 -@@ -6,6 +6,7 @@ - - obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o - obj-$(CONFIG_BLK_DEV_IDE_RAPIDE) += rapide.o -+obj-$(CONFIG_BLK_DEV_IDE_RISCSTATION) += rstation-ide.o - - EXTRA_CFLAGS := -I../ - -diff -urN linux-2.4.26/drivers/ide/arm/icside.c linux-2.4.26-vrs1/drivers/ide/arm/icside.c ---- linux-2.4.26/drivers/ide/arm/icside.c 2003-06-13 15:51:33.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/ide/arm/icside.c 2004-01-14 21:32:25.000000000 +0000 -@@ -1,7 +1,7 @@ - /* - * linux/drivers/ide/arm/icside.c - * -- * Copyright (c) 1996,1997 Russell King. -+ * Copyright (c) 1996-2003 Russell King. - * - * Changelog: - * 08-Jun-1996 RMK Created -@@ -26,24 +26,6 @@ - #include - #include - --#include "ide-noise.h" -- --/* -- * FIXME: We want to drop the the MACRO CRAP! -- * -- * ec->iops->in{b/w/l} -- * ec->iops->in{b/w/l}_p -- * ec->iops->out{b/w/l} -- * ec->iops->out{b/w/l}_p -- * -- * the new core supports clean MMIO calls and other goodies -- */ -- --/* -- * Maximum number of interfaces per card -- */ --#define MAX_IFS 2 -- - #define ICS_IDENT_OFFSET 0x8a0 - - #define ICS_ARCIN_V5_INTRSTAT 0x000 -@@ -86,17 +68,20 @@ - ICS_ARCIN_V6_IDESTEPPING - }; - --static const card_ids icside_cids[] = { -- { MANU_ICS, PROD_ICS_IDE }, -- { MANU_ICS2, PROD_ICS2_IDE }, -- { 0xffff, 0xffff } -+struct icside_state { -+ unsigned int channel; -+ unsigned int enabled; -+ unsigned long irq_port; -+ unsigned long slot_port; -+ unsigned int type; -+ ide_hwif_t *hwif[2]; - }; - --typedef enum { -- ics_if_unknown, -- ics_if_arcin_v5, -- ics_if_arcin_v6 --} iftype_t; -+#define ICS_TYPE_A3IN 0 -+#define ICS_TYPE_A3USER 1 -+#define ICS_TYPE_V6 3 -+#define ICS_TYPE_V5 15 -+#define ICS_TYPE_NOTYPE ((unsigned int)-1) - - /* ---------------- Version 5 PCB Support Functions --------------------- */ - /* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr) -@@ -104,8 +89,10 @@ - */ - static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr) - { -- unsigned int memc_port = (unsigned int)ec->irq_data; -- outb(0, memc_port + ICS_ARCIN_V5_INTROFFSET); -+ struct icside_state *state = ec->irq_data; -+ unsigned int base = state->irq_port; -+ -+ outb(0, base + ICS_ARCIN_V5_INTROFFSET); - } - - /* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr) -@@ -113,17 +100,15 @@ - */ - static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr) - { -- unsigned int memc_port = (unsigned int)ec->irq_data; -- inb(memc_port + ICS_ARCIN_V5_INTROFFSET); -+ struct icside_state *state = ec->irq_data; -+ unsigned int base = state->irq_port; -+ -+ inb(base + ICS_ARCIN_V5_INTROFFSET); - } - - static const expansioncard_ops_t icside_ops_arcin_v5 = { -- icside_irqenable_arcin_v5, -- icside_irqdisable_arcin_v5, -- NULL, -- NULL, -- NULL, -- NULL -+ .irqenable = icside_irqenable_arcin_v5, -+ .irqdisable = icside_irqdisable_arcin_v5, - }; - - -@@ -133,10 +118,21 @@ - */ - static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr) - { -- unsigned int ide_base_port = (unsigned int)ec->irq_data; -+ struct icside_state *state = ec->irq_data; -+ unsigned int base = state->irq_port; -+ -+ state->enabled = 1; - -- outb(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1); -- outb(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2); -+ switch (state->channel) { -+ case 0: -+ outb(0, base + ICS_ARCIN_V6_INTROFFSET_1); -+ inb(base + ICS_ARCIN_V6_INTROFFSET_2); -+ break; -+ case 1: -+ outb(0, base + ICS_ARCIN_V6_INTROFFSET_2); -+ inb(base + ICS_ARCIN_V6_INTROFFSET_1); -+ break; -+ } - } - - /* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) -@@ -144,10 +140,12 @@ - */ - static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) - { -- unsigned int ide_base_port = (unsigned int)ec->irq_data; -+ struct icside_state *state = ec->irq_data; -+ -+ state->enabled = 0; - -- inb(ide_base_port + ICS_ARCIN_V6_INTROFFSET_1); -- inb(ide_base_port + ICS_ARCIN_V6_INTROFFSET_2); -+ inb (state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); -+ inb (state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); - } - - /* Prototype: icside_irqprobe(struct expansion_card *ec) -@@ -155,70 +153,49 @@ - */ - static int icside_irqpending_arcin_v6(struct expansion_card *ec) - { -- unsigned int ide_base_port = (unsigned int)ec->irq_data; -+ struct icside_state *state = ec->irq_data; - -- return inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 || -- inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1; -+ return inb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 || -+ inb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1; - } - - static const expansioncard_ops_t icside_ops_arcin_v6 = { -- icside_irqenable_arcin_v6, -- icside_irqdisable_arcin_v6, -- icside_irqpending_arcin_v6, -- NULL, -- NULL, -- NULL -+ .irqenable = icside_irqenable_arcin_v6, -+ .irqdisable = icside_irqdisable_arcin_v6, -+ .irqpending = icside_irqpending_arcin_v6, - }; - --/* Prototype: icside_identifyif (struct expansion_card *ec) -- * Purpose : identify IDE interface type -- * Notes : checks the description string -+/* -+ * Handle routing of interrupts. This is called before -+ * we write the command to the drive. - */ --static iftype_t __init icside_identifyif (struct expansion_card *ec) -+static void icside_maskproc(ide_drive_t *drive, int mask) - { -- unsigned int addr; -- iftype_t iftype; -- int id = 0; -- -- iftype = ics_if_unknown; -- -- addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET; -- -- id = inb(addr) & 1; -- id |= (inb(addr + 1) & 1) << 1; -- id |= (inb(addr + 2) & 1) << 2; -- id |= (inb(addr + 3) & 1) << 3; -- -- switch (id) { -- case 0: /* A3IN */ -- printk("icside: A3IN unsupported\n"); -- break; -- -- case 1: /* A3USER */ -- printk("icside: A3USER unsupported\n"); -- break; -+ ide_hwif_t *hwif = HWIF(drive); -+ struct icside_state *state = hwif->hwif_data; -+ unsigned long flags; - -- case 3: /* ARCIN V6 */ -- printk(KERN_DEBUG "icside: detected ARCIN V6 in slot %d\n", ec->slot_no); -- iftype = ics_if_arcin_v6; -- break; -+ local_irq_save(flags); - -- case 15:/* ARCIN V5 (no id) */ -- printk(KERN_DEBUG "icside: detected ARCIN V5 in slot %d\n", ec->slot_no); -- iftype = ics_if_arcin_v5; -- break; -+ state->channel = hwif->channel; - -- default:/* we don't know - complain very loudly */ -- printk("icside: ***********************************\n"); -- printk("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id); -- printk("icside: ***********************************\n"); -- printk("icside: please report this to linux@arm.linux.org.uk\n"); -- printk("icside: defaulting to ARCIN V5\n"); -- iftype = ics_if_arcin_v5; -- break; -+ if (state->enabled && !mask) { -+ switch (hwif->channel) { -+ case 0: -+ outb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); -+ inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); -+ break; -+ case 1: -+ outb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); -+ inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); -+ break; -+ } -+ } else { -+ inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); -+ inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); - } - -- return iftype; -+ local_irq_restore(flags); - } - - #ifdef CONFIG_BLK_DEV_IDEDMA_ICS -@@ -234,125 +211,138 @@ - #define NR_ENTRIES 256 - #define TABLE_SIZE (NR_ENTRIES * 8) - --static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq) -+static void ide_build_sglist(ide_drive_t *drive, struct request *rq) - { -- struct buffer_head *bh; -+ ide_hwif_t *hwif = HWIF(drive); - struct scatterlist *sg = hwif->sg_table; -+ struct buffer_head *bh; - int nents = 0; - -- if (rq->cmd == READ) -- hwif->sg_dma_direction = PCI_DMA_FROMDEVICE; -- else -- hwif->sg_dma_direction = PCI_DMA_TODEVICE; -- bh = rq->bh; -- do { -- unsigned char *virt_addr = bh->b_data; -- unsigned int size = bh->b_size; -- -- while ((bh = bh->b_reqnext) != NULL) { -- if ((virt_addr + size) != (unsigned char *)bh->b_data) -- break; -- size += bh->b_size; -- } -- memset(&sg[nents], 0, sizeof(*sg)); -- sg[nents].address = virt_addr; -- sg[nents].length = size; -- nents++; -- } while (bh != NULL); -+ BUG_ON(hwif->sg_dma_active); - -- return pci_map_sg(NULL, sg, nents, hwif->sg_dma_direction); --} -+ if (rq->cmd == IDE_DRIVE_TASKFILE) { -+ ide_task_t *args = rq->special; - --static int --icside_build_dmatable(ide_drive_t *drive, int ddir) --{ -- return HWIF(drive)->sg_nents = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq, ddir); --} -+ if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE) -+ hwif->sg_dma_direction = PCI_DMA_FROMDEVICE; -+ else -+ hwif->sg_dma_direction = PCI_DMA_TODEVICE; -+ -+ memset(sg, 0, sizeof(*sg)); -+ sg->address = rq->buffer; -+ sg->length = rq->nr_sectors * SECTOR_SIZE; -+ nents = 1; -+ } else { -+ if (rq->cmd == READ) -+ hwif->sg_dma_direction = PCI_DMA_FROMDEVICE; -+ else -+ hwif->sg_dma_direction = PCI_DMA_TODEVICE; -+ -+ bh = rq->bh; -+ do { -+ unsigned long lastend; -+ -+ memset(sg, 0, sizeof(*sg)); -+ sg->page = bh->b_page; -+ lastend = bh_phys(bh); -+ -+ do { -+ lastend += bh->b_size; -+ sg->length += bh->b_size; -+ -+ bh = bh->b_reqnext; -+ if (bh == NULL) -+ break; -+ } while (lastend == bh_phys(bh)); -+ -+ sg++; -+ nents++; -+ } while (bh != NULL); -+ } - --/* Teardown mappings after DMA has completed. */ --static void icside_destroy_dmatable(ide_drive_t *drive) --{ -- struct scatterlist *sg = HWIF(drive)->sg_table; -- int nents = HWIF(drive)->sg_nents; -+ nents = pci_map_sg(NULL, sg, nents, hwif->sg_dma_direction); - -- pci_unmap_sg(NULL, sg, nents, HWIF(drive)->sg_dma_direction); -+ hwif->sg_nents = nents; - } - --static int --icside_config_if(ide_drive_t *drive, int xfer_mode) -+ -+/* -+ * Configure the IOMD to give the appropriate timings for the transfer -+ * mode being requested. We take the advice of the ATA standards, and -+ * calculate the cycle time based on the transfer mode, and the EIDE -+ * MW DMA specs that the drive provides in the IDENTIFY command. -+ * -+ * We have the following IOMD DMA modes to choose from: -+ * -+ * Type Active Recovery Cycle -+ * A 250 (250) 312 (550) 562 (800) -+ * B 187 250 437 -+ * C 125 (125) 125 (375) 250 (500) -+ * D 62 125 187 -+ * -+ * (figures in brackets are actual measured timings) -+ * -+ * However, we also need to take care of the read/write active and -+ * recovery timings: -+ * -+ * Read Write -+ * Mode Active -- Recovery -- Cycle IOMD type -+ * MW0 215 50 215 480 A -+ * MW1 80 50 50 150 C -+ * MW2 70 25 25 120 C -+ */ -+static int icside_set_speed(ide_drive_t *drive, u8 xfer_mode) - { -- int func = ide_dma_off; -+ int on = 0, cycle_time = 0, use_dma_info = 0; -+ -+ /* -+ * Limit the transfer speed to MW_DMA_2. -+ */ -+ if (xfer_mode > XFER_MW_DMA_2) -+ xfer_mode = XFER_MW_DMA_2; - - switch (xfer_mode) { - case XFER_MW_DMA_2: -- /* -- * The cycle time is limited to 250ns by the r/w -- * pulse width (90ns), however we should still -- * have a maximum burst transfer rate of 8MB/s. -- */ -- drive->drive_data = 250; -+ cycle_time = 250; -+ use_dma_info = 1; - break; - - case XFER_MW_DMA_1: -- drive->drive_data = 250; -+ cycle_time = 250; -+ use_dma_info = 1; - break; - - case XFER_MW_DMA_0: -- drive->drive_data = 480; -+ cycle_time = 480; - break; - -- default: -- drive->drive_data = 0; -+ case XFER_SW_DMA_2: -+ case XFER_SW_DMA_1: -+ case XFER_SW_DMA_0: -+ cycle_time = 480; - break; - } - -- if (!drive->init_speed) -- drive->init_speed = (u8) xfer_mode; -+ /* -+ * If we're going to be doing MW_DMA_1 or MW_DMA_2, we should -+ * take care to note the values in the ID... -+ */ -+ if (use_dma_info && drive->id->eide_dma_time > cycle_time) -+ cycle_time = drive->id->eide_dma_time; -+ -+ drive->drive_data = cycle_time; - -- if (drive->drive_data && -- ide_config_drive_speed(drive, (u8) xfer_mode) == 0) -- func = ide_dma_on; -+ if (cycle_time && ide_config_drive_speed(drive, xfer_mode) == 0) -+ on = 1; - else - drive->drive_data = 480; - - printk("%s: %s selected (peak %dMB/s)\n", drive->name, - ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data); - -- drive->current_speed = (u8) xfer_mode; -- -- return func; --} -- --static int --icside_set_speed(ide_drive_t *drive, u8 speed) --{ -- return icside_config_if(drive, speed); --} -- --/* -- * dma_intr() is the handler for disk read/write DMA interrupts -- */ --static ide_startstop_t icside_dmaintr(ide_drive_t *drive) --{ -- u8 dma_stat = HWIF(drive)->ide_dma_end(drive); -- /* get drive status */ -- u8 stat = HWIF(drive)->INB(IDE_STATUS_REG); -- int i; -+ drive->current_speed = xfer_mode; - -- if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) { -- if (!dma_stat) { -- struct request *rq = HWGROUP(drive)->rq; -- rq = HWGROUP(drive)->rq; -- for (i = rq->nr_sectors; i > 0;) { -- i -= rq->current_nr_sectors; -- DRIVER(drive)->end_request(drive, 1); -- } -- return ide_stopped; -- } -- printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", -- drive->name, dma_stat); -- } -- return DRIVER(drive)->error(drive, "dma_intr", stat); -+ return on; - } - - /* -@@ -361,19 +351,19 @@ - * This should be defined in one place only. - */ - struct drive_list_entry { -- char * id_model; -- char * id_firmware; -+ const char * id_model; -+ const char * id_firmware; - }; - --static struct drive_list_entry drive_whitelist [] = { -+static const struct drive_list_entry drive_whitelist [] = { - { "Micropolis 2112A", "ALL" }, - { "CONNER CTMA 4000", "ALL" }, - { "CONNER CTT8000-A", "ALL" }, - { "ST34342A", "ALL" }, -- { NULL, 0 } -+ { NULL, NULL } - }; - --static struct drive_list_entry drive_blacklist [] = { -+static const struct drive_list_entry drive_blacklist [] = { - { "WDC AC11000H", "ALL" }, - { "WDC AC22100H", "ALL" }, - { "WDC AC32500H", "ALL" }, -@@ -407,10 +397,11 @@ - { "PLEXTOR CD-R PX-W8432T", "ALL" }, - { "ATAPI CD-ROM DRIVE 40X MAXIMUM", "ALL" }, - { "_NEC DV5800A", "ALL" }, -- { NULL, 0 } -+ { NULL, NULL } - }; - --static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table) -+static int -+in_drive_list(struct hd_driveid *id, const struct drive_list_entry *drive_table) - { - for ( ; drive_table->id_model ; drive_table++) - if ((!strcmp(drive_table->id_model, id->model)) && -@@ -420,41 +411,52 @@ - return 0; - } - --/* -- * For both Blacklisted and Whitelisted drives. -- * This is setup to be called as an extern for future support -- * to other special driver code. -- */ --int check_drive_good_lists (ide_drive_t *drive) -+static int icside_dma_host_off(ide_drive_t *drive) - { -- struct hd_driveid *id = drive->id; -- return in_drive_list(id, drive_whitelist); -+ return 0; - } - --int check_drive_bad_lists (ide_drive_t *drive) -+static int icside_dma_off_quietly(ide_drive_t *drive) - { -- struct hd_driveid *id = drive->id; -- int blacklist = in_drive_list(id, drive_blacklist); -- if (blacklist) -- printk("%s: Disabling DMA for %s\n", drive->name, id->model); -- return(blacklist); -+ drive->using_dma = 0; -+ return icside_dma_host_off(drive); -+} -+ -+static int icside_dma_off(ide_drive_t *drive) -+{ -+ printk("%s: DMA disabled\n", drive->name); -+ return icside_dma_off_quietly(drive); -+} -+ -+static int icside_dma_host_on(ide_drive_t *drive) -+{ -+ return 0; - } - --int icside_dma_check(ide_drive_t *drive) -+static int icside_dma_on(ide_drive_t *drive) -+{ -+ drive->using_dma = 1; -+ return icside_dma_host_on(drive); -+} -+ -+static int icside_dma_check(ide_drive_t *drive) - { - struct hd_driveid *id = drive->id; - ide_hwif_t *hwif = HWIF(drive); -- int autodma = hwif->autodma; - int xfer_mode = XFER_PIO_2; -+ int on; - -- if (!id || !(id->capability & 1) || !autodma) -- return hwif->ide_dma_off_quietly(drive); -+ if (!id || !(id->capability & 1) || !hwif->autodma) -+ goto out; - - /* - * Consult the list of known "bad" drives - */ -- if (check_drive_bad_lists(drive)) -- return hwif->ide_dma_off(drive); -+ if (in_drive_list(id, drive_blacklist)) { -+ printk("%s: Disabling DMA for %s (blacklisted)\n", -+ drive->name, id->model); -+ goto out; -+ } - - /* - * Enable DMA on any drive that has multiword DMA -@@ -473,192 +475,241 @@ - /* - * Consult the list of known "good" drives - */ -- if (check_drive_good_lists(drive)) { -+ if (in_drive_list(id, drive_whitelist)) { - if (id->eide_dma_time > 150) - goto out; - xfer_mode = XFER_MW_DMA_1; - } - - out: -- if (icside_config_if(drive, xfer_mode)) -- return hwif->ide_dma_on(drive); -- return hwif->ide_dma_off(drive); --} -+ on = icside_set_speed(drive, xfer_mode); - --int icside_dma_verbose(ide_drive_t *drive) --{ -- printk(", DMA"); -- return 1; -+ if (on) -+ return icside_dma_on(drive); -+ else -+ return icside_dma_off(drive); - } - --int icside_dma_test_irq(ide_drive_t *drive) -+static int icside_dma_end(ide_drive_t *drive) - { - ide_hwif_t *hwif = HWIF(drive); -- return inb((unsigned long)hwif->hw.priv) & 1; --} - --int icside_dma_host_off(ide_drive_t *drive) --{ -- return 0; --} -+ drive->waiting_for_dma = 0; - --int icside_dma_off_quietly(ide_drive_t *drive) --{ -- drive->using_dma = 0; -- return icside_dma_host_off(drive); --} -+ disable_dma(hwif->hw.dma); - --int icside_dma_off(ide_drive_t *drive) --{ -- printk("%s: DMA disabled\n", drive->name); -- return icside_dma_off_quietly(drive); --} -+ /* Teardown mappings after DMA has completed. */ -+ pci_unmap_sg(NULL, hwif->sg_table, hwif->sg_nents, -+ hwif->sg_dma_direction); - --int icside_dma_host_on(ide_drive_t *drive) --{ -- return 0; --} -+ hwif->sg_dma_active = 0; - --int icside_dma_on(ide_drive_t *drive) --{ -- drive->using_dma = 1; -- return icside_dma_host_on(drive); -+ return get_dma_residue(hwif->hw.dma) != 0; - } - --int icside_dma_begin(ide_drive_t *drive) -+static int icside_dma_begin(ide_drive_t *drive) - { - ide_hwif_t *hwif = HWIF(drive); - -+ /* We can not enable DMA on both channels simultaneously. */ -+ BUG_ON(dma_channel_active(hwif->hw.dma)); - enable_dma(hwif->hw.dma); - return 0; - } - --int icside_dma_end(ide_drive_t *drive) -+static int icside_dma_count(ide_drive_t *drive) - { -- ide_hwif_t *hwif = HWIF(drive); -- -- drive->waiting_for_dma = 0; -- disable_dma(hwif->hw.dma); -- icside_destroy_dmatable(drive); -- return get_dma_residue(hwif->hw.dma) != 0; -+ return icside_dma_begin(drive); - } - --int icside_dma_count (ide_drive_t *drive) -+/* -+ * dma_intr() is the handler for disk read/write DMA interrupts -+ */ -+static ide_startstop_t icside_dmaintr(ide_drive_t *drive) - { -- return icside_dma_begin(drive); -+ unsigned int stat; -+ int dma_stat; -+ -+ dma_stat = icside_dma_end(drive); -+ stat = HWIF(drive)->INB(IDE_STATUS_REG); -+ if (OK_STAT(stat, DRIVE_READY, drive->bad_wstat | DRQ_STAT)) { -+ if (!dma_stat) { -+ struct request *rq = HWGROUP(drive)->rq; -+ int i; -+ -+ for (i = rq->nr_sectors; i > 0; ) { -+ i -= rq->current_nr_sectors; -+ DRIVER(drive)->end_request(drive, 1); -+ } -+ -+ return ide_stopped; -+ } -+ printk(KERN_ERR "%s: bad DMA status (dma_stat=%x)\n", -+ drive->name, dma_stat); -+ } -+ -+ return DRIVER(drive)->error(drive, __FUNCTION__, stat); - } - --int icside_dma_read(ide_drive_t *drive) -+static int -+icside_dma_common(ide_drive_t *drive, struct request *rq, -+ unsigned int dma_mode) - { -- ide_hwif_t *hwif = HWIF(drive); --// ide_task_t *args = HWGROUP(drive)->rq->special; -- int count = 0; -- u8 lba48 = (drive->addressing == 1) ? 1 : 0; -- task_ioreg_t command = WIN_NOP; -+ ide_hwif_t *hwif = HWIF(drive); - -- count = icside_build_dmatable(drive, PCI_DMA_FROMDEVICE); -- if (!count) -- return 1; -- disable_dma(hwif->hw.dma); -+ /* -+ * We can not enable DMA on both channels. -+ */ -+ BUG_ON(hwif->sg_dma_active); -+ BUG_ON(dma_channel_active(hwif->hw.dma)); -+ -+ ide_build_sglist(drive, rq); - -- /* Route the DMA signals to -- * to the correct interface. -+ /* -+ * Ensure that we have the right interrupt routed. - */ -- HWIF(drive)->OUTB(hwif->select_data, hwif->config_data); -+ icside_maskproc(drive, 0); - -- /* Select the correct timing -- * for this drive -+ /* -+ * Route the DMA signals to the correct interface. -+ */ -+ outb(hwif->select_data, hwif->config_data); -+ -+ /* -+ * Select the correct timing for this drive. - */ - set_dma_speed(hwif->hw.dma, drive->drive_data); - -- set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count); -- set_dma_mode(hwif->hw.dma, DMA_MODE_READ); -+ /* -+ * Tell the DMA engine about the SG table and -+ * data direction. -+ */ -+ set_dma_sg(hwif->hw.dma, hwif->sg_table, hwif->sg_nents); -+ set_dma_mode(hwif->hw.dma, dma_mode); -+ -+ return 0; -+} -+ -+static int icside_dma_read(ide_drive_t *drive) -+{ -+ struct request *rq = HWGROUP(drive)->rq; -+ task_ioreg_t cmd; -+ -+ if (icside_dma_common(drive, rq, DMA_MODE_READ)) -+ return 1; - - drive->waiting_for_dma = 1; -+ - if (drive->media != ide_disk) - return 0; - -- if (HWGROUP(drive)->handler != NULL) /* paranoia check */ -- BUG(); -- ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL); - /* - * FIX ME to use only ACB ide_task_t args Struct - */ - #if 0 - { -- ide_task_t *args = HWGROUP(drive)->rq->special; -- command = args->tfRegister[IDE_COMMAND_OFFSET]; -+ ide_task_t *args = rq->special; -+ cmd = args->tfRegister[IDE_COMMAND_OFFSET]; - } - #else -- command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA; -- if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) { -- ide_task_t *args = HWGROUP(drive)->rq->special; -- command = args->tfRegister[IDE_COMMAND_OFFSET]; -+ if (rq->cmd == IDE_DRIVE_TASKFILE) { -+ ide_task_t *args = rq->special; -+ cmd = args->tfRegister[IDE_COMMAND_OFFSET]; -+ } else if (drive->addressing == 1) { -+ cmd = WIN_READDMA_EXT; -+ } else { -+ cmd = WIN_READDMA; - } - #endif -- /* issue cmd to drive */ -- HWIF(drive)->OUTB(command, IDE_COMMAND_REG); - -- return icside_dma_count(drive); -+ ide_execute_command(drive, cmd, icside_dmaintr, 2*WAIT_CMD, NULL); -+ -+ return icside_dma_begin(drive); - } - --int icside_dma_write(ide_drive_t *drive) -+static int icside_dma_write(ide_drive_t *drive) - { -- ide_hwif_t *hwif = HWIF(drive); --// ide_task_t *args = HWGROUP(drive)->rq->special; -- int count = 0; -- u8 lba48 = (drive->addressing == 1) ? 1 : 0; -- task_ioreg_t command = WIN_NOP; -+ struct request *rq = HWGROUP(drive)->rq; -+ task_ioreg_t cmd; - -- count = icside_build_dmatable(drive, PCI_DMA_TODEVICE); -- if (!count) -+ if (icside_dma_common(drive, rq, DMA_MODE_WRITE)) - return 1; -- disable_dma(hwif->hw.dma); -- -- /* Route the DMA signals to -- * to the correct interface. -- */ -- HWIF(drive)->OUTB(hwif->select_data, hwif->config_data); -- -- /* Select the correct timing -- * for this drive -- */ -- set_dma_speed(hwif->hw.dma, drive->drive_data); -- -- set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count); -- set_dma_mode(hwif->hw.dma, DMA_MODE_WRITE); - - drive->waiting_for_dma = 1; -+ - if (drive->media != ide_disk) - return 0; - -- if (HWGROUP(drive)->handler != NULL) -- BUG(); -- ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL); - /* - * FIX ME to use only ACB ide_task_t args Struct - */ - #if 0 - { -- ide_task_t *args = HWGROUP(drive)->rq->special; -- command = args->tfRegister[IDE_COMMAND_OFFSET]; -+ ide_task_t *args = rq->special; -+ cmd = args->tfRegister[IDE_COMMAND_OFFSET]; - } - #else -- command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA; -- if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) { -- ide_task_t *args = HWGROUP(drive)->rq->special; -- command = args->tfRegister[IDE_COMMAND_OFFSET]; -+ if (rq->cmd == IDE_DRIVE_TASKFILE) { -+ ide_task_t *args = rq->special; -+ cmd = args->tfRegister[IDE_COMMAND_OFFSET]; -+ } else if (drive->addressing == 1) { -+ cmd = WIN_WRITEDMA_EXT; -+ } else { -+ cmd = WIN_WRITEDMA; - } - #endif -- /* issue cmd to drive */ -- HWIF(drive)->OUTB(command, IDE_COMMAND_REG); - -- return icside_dma_count(drive); -+ ide_execute_command(drive, cmd, icside_dmaintr, 2*WAIT_CMD, NULL); -+ -+ return icside_dma_begin(drive); - } - --static int --icside_setup_dma(ide_hwif_t *hwif, int autodma) -+static int icside_dma_test_irq(ide_drive_t *drive) -+{ -+ ide_hwif_t *hwif = HWIF(drive); -+ struct icside_state *state = hwif->hwif_data; -+ -+ return inb(state->irq_port + -+ (hwif->channel ? -+ ICS_ARCIN_V6_INTRSTAT_2 : -+ ICS_ARCIN_V6_INTRSTAT_1)) & 1; -+} -+ -+static int icside_dma_verbose(ide_drive_t *drive) -+{ -+ printk(", %s (peak %dMB/s)", -+ ide_xfer_verbose(drive->current_speed), -+ 2000 / drive->drive_data); -+ return 1; -+} -+ -+static int icside_dma_timeout(ide_drive_t *drive) -+{ -+ printk(KERN_ERR "%s: DMA timeout occurred: ", drive->name); -+ -+ if (icside_dma_test_irq(drive)) -+ return 0; -+ -+ ide_dump_status(drive, "DMA timeout", -+ HWIF(drive)->INB(IDE_STATUS_REG)); -+ -+ return icside_dma_end(drive); -+} -+ -+static int icside_dma_lostirq(ide_drive_t *drive) -+{ -+ printk(KERN_ERR "%s: IRQ lost\n", drive->name); -+ return 1; -+} -+ -+static int icside_dma_init(ide_hwif_t *hwif) - { -+ int autodma = 0; -+ -+#ifdef CONFIG_IDEDMA_ICS_AUTO -+ autodma = 1; -+#endif -+ - printk(" %s: SG-DMA", hwif->name); - - hwif->sg_table = kmalloc(sizeof(struct scatterlist) * NR_ENTRIES, -@@ -666,40 +717,53 @@ - if (!hwif->sg_table) - goto failed; - -- hwif->dmatable_cpu = NULL; -- hwif->dmatable_dma = 0; -- hwif->speedproc = icside_set_speed; -- hwif->autodma = autodma; -+ hwif->atapi_dma = 1; -+ hwif->mwdma_mask = 7; /* MW0..2 */ -+ hwif->swdma_mask = 7; /* SW0..2 */ -+ -+ hwif->dmatable_cpu = NULL; -+ hwif->dmatable_dma = 0; -+ hwif->speedproc = icside_set_speed; -+ hwif->autodma = autodma; - -- hwif->ide_dma_check = icside_dma_check; -- hwif->ide_dma_host_off = icside_dma_host_off; -+ hwif->ide_dma_check = icside_dma_check; -+ hwif->ide_dma_host_off = icside_dma_host_off; - hwif->ide_dma_off_quietly = icside_dma_off_quietly; -- hwif->ide_dma_off = icside_dma_off; -- hwif->ide_dma_host_on = icside_dma_host_on; -- hwif->ide_dma_on = icside_dma_on; -- hwif->ide_dma_read = icside_dma_read; -- hwif->ide_dma_write = icside_dma_write; -- hwif->ide_dma_count = icside_dma_count; -- hwif->ide_dma_begin = icside_dma_begin; -- hwif->ide_dma_end = icside_dma_end; -- hwif->ide_dma_verbose = icside_dma_verbose; -- hwif->ide_dma_bad_drive = check_drive_bad_lists; -- hwif->ide_dma_good_drive = check_drive_good_lists; -- hwif->ide_dma_test_irq = icside_dma_test_irq; -+ hwif->ide_dma_off = icside_dma_off; -+ hwif->ide_dma_host_on = icside_dma_host_on; -+ hwif->ide_dma_on = icside_dma_on; -+ hwif->ide_dma_read = icside_dma_read; -+ hwif->ide_dma_write = icside_dma_write; -+ hwif->ide_dma_count = icside_dma_count; -+ hwif->ide_dma_begin = icside_dma_begin; -+ hwif->ide_dma_end = icside_dma_end; -+ hwif->ide_dma_test_irq = icside_dma_test_irq; -+ hwif->ide_dma_verbose = icside_dma_verbose; -+ hwif->ide_dma_timeout = icside_dma_timeout; -+ hwif->ide_dma_lostirq = icside_dma_lostirq; - -- printk(" capable%s\n", autodma ? -- ", auto-enable" : ""); -+ printk(" capable%s\n", hwif->autodma ? ", auto-enable" : ""); - - return 1; - - failed: -- printk(" -- ERROR, unable to allocate DMA table\n"); -+ printk(" disabled, unable to allocate DMA table\n"); - return 0; - } -+ -+static void icside_dma_exit(ide_hwif_t *hwif) -+{ -+ if (hwif->sg_table) { -+ kfree(hwif->sg_table); -+ hwif->sg_table = NULL; -+ } -+} -+#else -+#define icside_dma_init(hwif) (0) -+#define icside_dma_exit(hwif) do { } while (0) - #endif - --static ide_hwif_t * --icside_find_hwif(unsigned long dataport) -+static ide_hwif_t *icside_find_hwif(unsigned long dataport) - { - ide_hwif_t *hwif; - int index; -@@ -716,13 +780,13 @@ - goto found; - } - -- return NULL; -+ hwif = NULL; - found: - return hwif; - } - - static ide_hwif_t * --icside_setup(unsigned long base, struct cardinfo *info, int irq) -+icside_setup(unsigned long base, struct cardinfo *info, struct expansion_card *ec) - { - unsigned long port = base + info->dataoffset; - ide_hwif_t *hwif; -@@ -740,8 +804,8 @@ - } - hwif->hw.io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset; - hwif->io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset; -- hwif->hw.irq = irq; -- hwif->irq = irq; -+ hwif->hw.irq = ec->irq; -+ hwif->irq = ec->irq; - hwif->hw.dma = NO_DMA; - hwif->noprobe = 0; - hwif->chipset = ide_acorn; -@@ -750,33 +814,39 @@ - return hwif; - } - --static int __init icside_register_v5(struct expansion_card *ec, int autodma) -+static int __init -+icside_register_v5(struct icside_state *state, struct expansion_card *ec) - { - unsigned long slot_port; - ide_hwif_t *hwif; - - slot_port = ecard_address(ec, ECARD_MEMC, 0); - -+ state->irq_port = slot_port; -+ - ec->irqaddr = (unsigned char *)ioaddr(slot_port + ICS_ARCIN_V5_INTRSTAT); - ec->irqmask = 1; -- ec->irq_data = (void *)slot_port; -- ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v5; -+ ec->irq_data = state; -+ ec->ops = &icside_ops_arcin_v5; - - /* - * Be on the safe side - disable interrupts - */ - inb(slot_port + ICS_ARCIN_V5_INTROFFSET); - -- hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec->irq); -+ hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec); - -- return hwif ? 0 : -1; -+ state->hwif[0] = hwif; -+ -+ return hwif ? 0 : -ENODEV; - } - --static int __init icside_register_v6(struct expansion_card *ec, int autodma) -+static int __init -+icside_register_v6(struct icside_state *state, struct expansion_card *ec) - { - unsigned long slot_port, port; - ide_hwif_t *hwif, *mate; -- int sel = 0; -+ unsigned int sel = 0; - - slot_port = ecard_address(ec, ECARD_IOC, ECARD_FAST); - port = ecard_address(ec, ECARD_EASI, ECARD_FAST); -@@ -788,88 +858,185 @@ - - outb(sel, slot_port); - -- ec->irq_data = (void *)port; -- ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v6; -- - /* - * Be on the safe side - disable interrupts - */ - inb(port + ICS_ARCIN_V6_INTROFFSET_1); - inb(port + ICS_ARCIN_V6_INTROFFSET_2); - -- hwif = icside_setup(port, &icside_cardinfo_v6_1, ec->irq); -- mate = icside_setup(port, &icside_cardinfo_v6_2, ec->irq); -+ /* -+ * Find and register the interfaces. -+ */ -+ hwif = icside_setup(port, &icside_cardinfo_v6_1, ec); -+ mate = icside_setup(port, &icside_cardinfo_v6_2, ec); -+ -+ if (!hwif || !mate) -+ return -ENODEV; - --#ifdef CONFIG_BLK_DEV_IDEDMA_ICS -- if (ec->dma != NO_DMA) { -- if (request_dma(ec->dma, hwif->name)) -- goto no_dma; -- -- if (hwif) { -- hwif->config_data = slot_port; -- hwif->select_data = sel; -- hwif->hw.dma = ec->dma; -- hwif->hw.priv = (void *) -- (port + ICS_ARCIN_V6_INTRSTAT_1); -- hwif->channel = 0; -- icside_setup_dma(hwif, autodma); -- hwif->drives[0].autodma = autodma; -- hwif->drives[1].autodma = autodma; -- } -- if (mate) { -- mate->config_data = slot_port; -- mate->select_data = sel | 1; -- mate->hw.dma = ec->dma; -- mate->hw.priv = (void *) -- (port + ICS_ARCIN_V6_INTRSTAT_2); -- mate->channel = 1; -- icside_setup_dma(mate, autodma); -- mate->drives[0].autodma = autodma; -- mate->drives[1].autodma = autodma; -- } -+ state->irq_port = port; -+ state->slot_port = slot_port; -+ state->hwif[0] = hwif; -+ state->hwif[1] = mate; -+ -+ ec->irq_data = state; -+ ec->ops = &icside_ops_arcin_v6; -+ -+ hwif->maskproc = icside_maskproc; -+ hwif->channel = 0; -+ hwif->hwif_data = state; -+ hwif->mate = mate; -+ hwif->serialized = 1; -+ hwif->config_data = slot_port; -+ hwif->select_data = sel; -+ hwif->hw.dma = ec->dma; -+ -+ mate->maskproc = icside_maskproc; -+ mate->channel = 1; -+ mate->hwif_data = state; -+ mate->mate = hwif; -+ mate->serialized = 1; -+ mate->config_data = slot_port; -+ mate->select_data = sel | 1; -+ mate->hw.dma = ec->dma; -+ -+ if (ec->dma != NO_DMA && !request_dma(ec->dma, hwif->name)) { -+ icside_dma_init(hwif); -+ icside_dma_init(mate); - } --no_dma: --#endif -- return hwif || mate ? 0 : -1; -+ return 0; - } - --int __init icside_init(void) -+static int __init icside_probe(struct expansion_card *ec, const struct ecard_id *id) - { -- int autodma = 0; -+ struct icside_state *state; -+ int ret; - --#ifdef CONFIG_IDEDMA_ICS_AUTO -- autodma = 1; --#endif -+ state = kmalloc(sizeof(struct icside_state), GFP_KERNEL); -+ if (!state) { -+ ret = -ENOMEM; -+ goto out; -+ } - -- ecard_startfind (); -+ memset(state, 0, sizeof(struct icside_state)); -+ state->type = ICS_TYPE_NOTYPE; - -- do { -- struct expansion_card *ec; -- int result; -+ { -+ unsigned int addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET; -+ unsigned int type; - -- ec = ecard_find(0, icside_cids); -- if (ec == NULL) -- break; -+ type = inb(addr) & 1; -+ type |= (inb(addr + 1) & 1) << 1; -+ type |= (inb(addr + 2) & 1) << 2; -+ type |= (inb(addr + 3) & 1) << 3; - -- ecard_claim(ec); -+ state->type = type; -+ } - -- switch (icside_identifyif(ec)) { -- case ics_if_arcin_v5: -- result = icside_register_v5(ec, autodma); -- break; -+ switch (state->type) { -+ case ICS_TYPE_A3IN: -+ printk(KERN_WARNING "icside: A3IN unsupported\n"); -+ ret = -ENODEV; -+ break; - -- case ics_if_arcin_v6: -- result = icside_register_v6(ec, autodma); -- break; -+ case ICS_TYPE_A3USER: -+ printk(KERN_WARNING "icside: A3USER unsupported\n"); -+ ret = -ENODEV; -+ break; - -- default: -- result = -1; -- break; -- } -+ case ICS_TYPE_V5: -+ ret = icside_register_v5(state, ec); -+ break; - -- if (result) -- ecard_release(ec); -- } while (1); -+ case ICS_TYPE_V6: -+ ret = icside_register_v6(state, ec); -+ break; - -- return 0; -+ default: -+ printk(KERN_WARNING "icside: unknown interface type\n"); -+ ret = -ENODEV; -+ break; -+ } -+ -+ if (ret == 0) { -+ ecard_set_drvdata(ec, state); -+ } else { -+ kfree(state); -+ } -+ out: -+ return ret; -+} -+ -+static void __devexit icside_remove(struct expansion_card *ec) -+{ -+ struct icside_state *state = ecard_get_drvdata(ec); -+ -+ switch (state->type) { -+ case ICS_TYPE_V5: -+ /* FIXME: tell IDE to stop using the interface */ -+ -+ /* Disable interrupts */ -+ inb(state->slot_port + ICS_ARCIN_V5_INTROFFSET); -+ break; -+ -+ case ICS_TYPE_V6: -+ /* FIXME: tell IDE to stop using the interface */ -+ icside_dma_exit(state->hwif[1]); -+ icside_dma_exit(state->hwif[0]); -+ -+ if (ec->dma != NO_DMA) -+ free_dma(ec->dma); -+ -+ /* Disable interrupts */ -+ inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); -+ inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); -+ -+ /* Reset the ROM pointer/EASI selection */ -+ outb(0, state->slot_port); -+ break; -+ } -+ -+ ecard_set_drvdata(ec, NULL); -+ ec->ops = NULL; -+ ec->irq_data = NULL; -+ -+ kfree(state); -+} -+ -+static void icside_shutdown(struct expansion_card *ec) -+{ -+ struct icside_state *state = ecard_get_drvdata(ec); -+ -+ switch (state->type) { -+ case ICS_TYPE_V5: -+ /* Disable interrupts */ -+ inb(state->slot_port + ICS_ARCIN_V5_INTROFFSET); -+ break; -+ -+ case ICS_TYPE_V6: -+ /* Disable interrupts */ -+ inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); -+ inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); -+ -+ /* Reset the ROM pointer/EASI selection */ -+ outb(0, state->slot_port); -+ break; -+ } -+} -+ -+static const struct ecard_id icside_ids[] = { -+ { MANU_ICS, PROD_ICS_IDE }, -+ { MANU_ICS2, PROD_ICS2_IDE }, -+ { 0xffff, 0xffff } -+}; -+ -+static struct ecard_driver icside_driver = { -+ .probe = icside_probe, -+ .remove = __devexit_p(icside_remove), -+ .shutdown = icside_shutdown, -+ .id_table = icside_ids, -+}; -+ -+int __init icside_init(void) -+{ -+ return ecard_register_driver(&icside_driver); - } -diff -urN linux-2.4.26/drivers/ide/arm/rstation-ide.c linux-2.4.26-vrs1/drivers/ide/arm/rstation-ide.c ---- linux-2.4.26/drivers/ide/arm/rstation-ide.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/ide/arm/rstation-ide.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,78 @@ -+/* -+ * linux/drivers/ide/rs-ide.c -+ * -+ * Copyright (c) 2002 Ben Dooks -+ * Copyright (c) 2002 Simtec Electronics -+ * -+ * Simple RiscStation IDE support -+*/ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#ifndef CONFIG_ARCH_RISCSTATION -+#error "compiling this code for non-riscstation hardware is dangerous!" -+#endif -+ -+#define DRV_PREFIX "ide-rs" -+ -+#define IRQ_PRI (40+3) -+#define IRQ_SEC (40+4) -+ -+#define PORT_BASE ((0x2b800 - 0x10000) >> 2) -+#define SEC_OFF (0x400 >> 2) -+ -+int __init rside_reg(unsigned long base, unsigned int irq); -+ -+int __init rside_init(void) -+{ -+ int iotcr; -+ -+ if (!machine_is_riscstation()) { -+ printk(DRV_PREFIX ": hardware is not a RiscStation!\n"); -+ return 0; -+ } -+ -+ /* select correct area cycle time */ -+ -+ iotcr = inb(IOMD_IOTCR); -+ outb((iotcr & ~3) | 1, IOMD_IOTCR); -+ -+ /* register h/w */ -+ -+ rside_reg(PORT_BASE, IRQ_PRI); -+ rside_reg(PORT_BASE + SEC_OFF, IRQ_SEC); -+ -+ return 0; -+} -+ -+ -+int __init rside_reg(unsigned long port, unsigned int irq) -+{ -+ unsigned long addr, i; -+ hw_regs_t hw; -+ -+ hw.irq = irq; -+ -+ addr = port; -+ -+ for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { -+ hw.io_ports[i] = (ide_ioreg_t)addr; -+ addr += 0x40 >> 2; -+ } -+ -+ hw.io_ports[IDE_CONTROL_OFFSET] = port + ((0xb80 - 0x800) >> 2); -+ -+ printk(DRV_PREFIX ": registering channel at %08lx, %08lx, irq %d\n", -+ port, hw.io_ports[IDE_CONTROL_OFFSET], irq); -+ -+ return ide_register_hw(&hw, NULL); -+} -diff -urN linux-2.4.26/drivers/ide/ide-probe.c linux-2.4.26-vrs1/drivers/ide/ide-probe.c ---- linux-2.4.26/drivers/ide/ide-probe.c 2004-04-19 11:44:16.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/ide/ide-probe.c 2004-04-18 21:47:50.000000000 +0100 -@@ -1297,11 +1297,11 @@ - hwif->name, hwif->major); - return (hwif->present = 0); - } -- -+ - if (init_irq(hwif)) { - int i = hwif->irq; - /* -- * It failed to initialise. Find the default IRQ for -+ * It failed to initialise. Find the default IRQ for - * this port and try that. - */ - if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) { -@@ -1319,7 +1319,7 @@ - printk("%s: probed IRQ %d failed, using default.\n", - hwif->name, hwif->irq); - } -- -+ - init_gendisk(hwif); - blk_dev[hwif->major].data = hwif; - blk_dev[hwif->major].queue = ide_get_queue; -diff -urN linux-2.4.26/drivers/ide/ide-proc.c linux-2.4.26-vrs1/drivers/ide/ide-proc.c ---- linux-2.4.26/drivers/ide/ide-proc.c 2004-04-19 11:44:16.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/ide/ide-proc.c 2004-04-18 21:47:50.000000000 +0100 -@@ -425,6 +425,7 @@ - case ide_cy82c693: name = "cy82c693"; break; - case ide_4drives: name = "4drives"; break; - case ide_pmac: name = "pmac"; break; -+ case ide_acorn: name = "acorn"; break; - default: name = "(unknown)"; break; - } - len = sprintf(page, "%s\n", name); -diff -urN linux-2.4.26/drivers/ide/ide.c linux-2.4.26-vrs1/drivers/ide/ide.c ---- linux-2.4.26/drivers/ide/ide.c 2004-02-27 20:03:25.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/ide/ide.c 2004-02-23 13:36:30.000000000 +0000 -@@ -218,23 +218,14 @@ - static void init_hwif_data (unsigned int index) - { - unsigned int unit; -- hw_regs_t hw; - ide_hwif_t *hwif = &ide_hwifs[index]; - - /* bulk initialize hwif & drive info with zeros */ - memset(hwif, 0, sizeof(ide_hwif_t)); -- memset(&hw, 0, sizeof(hw_regs_t)); - - /* fill in any non-zero initial values */ - hwif->index = index; -- ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, &hwif->irq); -- memcpy(&hwif->hw, &hw, sizeof(hw)); -- memcpy(hwif->io_ports, hw.io_ports, sizeof(hw.io_ports)); -- hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; --#ifdef CONFIG_BLK_DEV_HD -- if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) -- hwif->noprobe = 1; /* may be overridden by ide_setup() */ --#endif /* CONFIG_BLK_DEV_HD */ -+ hwif->noprobe = 1; - hwif->major = ide_hwif_to_major[index]; - hwif->name[0] = 'i'; - hwif->name[1] = 'd'; -@@ -276,6 +267,28 @@ - } - - /* -+ * Old compatability function - initialise ports using ide_default_io_base -+ */ -+static void ide_old_init_default_hwifs(void) -+{ -+ unsigned int index; -+ ide_ioreg_t base; -+ ide_hwif_t *hwif; -+ -+ for (index = 0; index < MAX_HWIFS; index++) { -+ hwif = &ide_hwifs[index]; -+ -+ base = ide_default_io_base(index); -+ -+ if (base) { -+ ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->hw.irq); -+ memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports)); -+ hwif->noprobe = 0; -+ } -+ } -+} -+ -+/* - * init_ide_data() sets reasonable default values into all fields - * of all instances of the hwifs and drives, but only on the first call. - * Subsequent calls have no effect (they don't wipe out anything). -@@ -307,6 +320,7 @@ - init_hwif_data(index); - - /* Add default hw interfaces */ -+ ide_old_init_default_hwifs(); - ide_init_default_hwifs(); - - idebus_parameter = 0; -@@ -2530,6 +2544,12 @@ - rapide_init(); - } - #endif /* CONFIG_BLK_DEV_IDE_RAPIDE */ -+#ifdef CONFIG_BLK_DEV_IDE_RISCSTATION -+ { -+ extern void rside_init(void); -+ rside_init(); -+ } -+#endif /* CONFIG_BLK_DEV_IDE_RISCSTATION */ - #ifdef CONFIG_BLK_DEV_GAYLE - { - extern void gayle_init(void); -diff -urN linux-2.4.26/drivers/ide/pci/Makefile linux-2.4.26-vrs1/drivers/ide/pci/Makefile ---- linux-2.4.26/drivers/ide/pci/Makefile 2004-04-19 11:44:16.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/ide/pci/Makefile 2004-04-18 21:47:50.000000000 +0100 -@@ -16,7 +16,6 @@ - obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o - obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o - #obj-$(CONFIG_BLK_DEV_HPT37X) += hpt37x.o --obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o - obj-$(CONFIG_BLK_DEV_IT8172) += it8172.o - obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o - obj-$(CONFIG_BLK_DEV_OPTI621) += opti621.o -diff -urN linux-2.4.26/drivers/ide/pci/sl82c105.c linux-2.4.26-vrs1/drivers/ide/pci/sl82c105.c ---- linux-2.4.26/drivers/ide/pci/sl82c105.c 2003-06-13 15:51:33.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/ide/pci/sl82c105.c 2004-01-14 21:32:25.000000000 +0000 -@@ -37,7 +37,7 @@ - #ifdef DEBUG - #define DBG(arg) printk arg - #else --#define DBG(fmt,...) -+#define DBG(fmt...) - #endif - /* - * SL82C105 PCI config register 0x40 bits. -diff -urN linux-2.4.26/drivers/ide/pci/sl82c105.c.2419 linux-2.4.26-vrs1/drivers/ide/pci/sl82c105.c.2419 ---- linux-2.4.26/drivers/ide/pci/sl82c105.c.2419 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/ide/pci/sl82c105.c.2419 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,380 @@ -+/* -+ * linux/drivers/ide/sl82c105.c -+ * -+ * SL82C105/Winbond 553 IDE driver -+ * -+ * Maintainer unknown. -+ * -+ * Changelog: -+ * -+ * 15/11/1998 RMK Drive tuning added from Rebel.com's kernel -+ * sources -+ * 30/03/2002 RMK Add fixes specified in W83C553F errata. -+ * (with special thanks to Todd Inglett) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "ide_modes.h" -+ -+extern char *ide_xfer_verbose (byte xfer_rate); -+ -+/* -+ * SL82C105 PCI config register 0x40 bits. -+ */ -+#define CTRL_IDE_IRQB (1 << 30) -+#define CTRL_IDE_IRQA (1 << 28) -+#define CTRL_LEGIRQ (1 << 11) -+#define CTRL_P1F16 (1 << 5) -+#define CTRL_P1EN (1 << 4) -+#define CTRL_P0F16 (1 << 1) -+#define CTRL_P0EN (1 << 0) -+ -+/* -+ * Convert a PIO mode and cycle time to the required on/off -+ * times for the interface. This has protection against run-away -+ * timings. -+ */ -+static unsigned int get_timing_sl82c105(ide_pio_data_t *p) -+{ -+ unsigned int cmd_on; -+ unsigned int cmd_off; -+ -+ cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30; -+ cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30; -+ -+ if (cmd_on > 32) -+ cmd_on = 32; -+ if (cmd_on == 0) -+ cmd_on = 1; -+ -+ if (cmd_off > 32) -+ cmd_off = 32; -+ if (cmd_off == 0) -+ cmd_off = 1; -+ -+ return (cmd_on - 1) << 8 | (cmd_off - 1) | (p->use_iordy ? 0x40 : 0x00); -+} -+ -+/* -+ * Configure the drive and chipset for PIO -+ */ -+static void config_for_pio(ide_drive_t *drive, int pio, int report) -+{ -+ ide_hwif_t *hwif = HWIF(drive); -+ struct pci_dev *dev = hwif->pci_dev; -+ ide_pio_data_t p; -+ unsigned short drv_ctrl = 0x909; -+ unsigned int xfer_mode, reg; -+ -+ reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0); -+ -+ pio = ide_get_best_pio_mode(drive, pio, 5, &p); -+ -+ switch (pio) { -+ default: -+ case 0: xfer_mode = XFER_PIO_0; break; -+ case 1: xfer_mode = XFER_PIO_1; break; -+ case 2: xfer_mode = XFER_PIO_2; break; -+ case 3: xfer_mode = XFER_PIO_3; break; -+ case 4: xfer_mode = XFER_PIO_4; break; -+ } -+ -+ if (ide_config_drive_speed(drive, xfer_mode) == 0) -+ drv_ctrl = get_timing_sl82c105(&p); -+ -+ if (drive->using_dma == 0) { -+ /* -+ * If we are actually using MW DMA, then we can not -+ * reprogram the interface drive control register. -+ */ -+ pci_write_config_word(dev, reg, drv_ctrl); -+ pci_read_config_word(dev, reg, &drv_ctrl); -+ -+ if (report) { -+ printk("%s: selected %s (%dns) (%04X)\n", drive->name, -+ ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl); -+ } -+ } -+} -+ -+/* -+ * Configure the drive and the chipset for DMA -+ */ -+static int config_for_dma(ide_drive_t *drive) -+{ -+ ide_hwif_t *hwif = HWIF(drive); -+ struct pci_dev *dev = hwif->pci_dev; -+ unsigned short drv_ctrl = 0x909; -+ unsigned int reg; -+ -+ reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0); -+ -+ if (ide_config_drive_speed(drive, XFER_MW_DMA_2) == 0) -+ drv_ctrl = 0x0240; -+ -+ pci_write_config_word(dev, reg, drv_ctrl); -+ -+ return 0; -+} -+ -+ -+/* -+ * Check to see if the drive and -+ * chipset is capable of DMA mode -+ */ -+static int sl82c105_check_drive(ide_drive_t *drive) -+{ -+ ide_dma_action_t dma_func = ide_dma_off_quietly; -+ -+ do { -+ struct hd_driveid *id = drive->id; -+ ide_hwif_t *hwif = HWIF(drive); -+ -+ if (!hwif->autodma) -+ break; -+ -+ if (!id || !(id->capability & 1)) -+ break; -+ -+ /* Consult the list of known "bad" drives */ -+ if (ide_dmaproc(ide_dma_bad_drive, drive)) { -+ dma_func = ide_dma_off; -+ break; -+ } -+ -+ if (id->field_valid & 2) { -+ if (id->dma_mword & 7 || id->dma_1word & 7) -+ dma_func = ide_dma_on; -+ break; -+ } -+ -+ if (ide_dmaproc(ide_dma_good_drive, drive)) { -+ dma_func = ide_dma_on; -+ break; -+ } -+ } while (0); -+ -+ return HWIF(drive)->dmaproc(dma_func, drive); -+} -+ -+/* -+ * The SL82C105 holds off all IDE interrupts while in DMA mode until -+ * all DMA activity is completed. Sometimes this causes problems (eg, -+ * when the drive wants to report an error condition). -+ * -+ * 0x7e is a "chip testing" register. Bit 2 resets the DMA controller -+ * state machine. We need to kick this to work around various bugs. -+ */ -+static inline void sl82c105_reset_host(struct pci_dev *dev) -+{ -+ u16 val; -+ -+ pci_read_config_word(dev, 0x7e, &val); -+ pci_write_config_word(dev, 0x7e, val | (1 << 2)); -+ pci_write_config_word(dev, 0x7e, val & ~(1 << 2)); -+} -+ -+/* -+ * If we get an IRQ timeout, it might be that the DMA state machine -+ * got confused. Fix from Todd Inglett. Details from Winbond. -+ * -+ * This function is called when the IDE timer expires, the drive -+ * indicates that it is READY, and we were waiting for DMA to complete. -+ */ -+static int sl82c105_lostirq(ide_drive_t *drive) -+{ -+ ide_hwif_t *hwif = HWIF(drive); -+ struct pci_dev *dev = hwif->pci_dev; -+ u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA; -+ unsigned long dma_base = hwif->dma_base; -+ -+ printk("sl82c105: lost IRQ: resetting host\n"); -+ -+ /* -+ * Check the raw interrupt from the drive. -+ */ -+ pci_read_config_dword(dev, 0x40, &val); -+ if (val & mask) -+ printk("sl82c105: drive was requesting IRQ, but host lost it\n"); -+ -+ /* -+ * Was DMA enabled? If so, disable it - we're resetting the -+ * host. The IDE layer will be handling the drive for us. -+ */ -+ val = inb(dma_base); -+ if (val & 1) { -+ outb(val & ~1, dma_base); -+ printk("sl82c105: DMA was enabled\n"); -+ } -+ -+ sl82c105_reset_host(dev); -+ -+ /* ide_dmaproc would return 1, so we do as well */ -+ return 1; -+} -+ -+/* -+ * ATAPI devices can cause the SL82C105 DMA state machine to go gaga. -+ * Winbond recommend that the DMA state machine is reset prior to -+ * setting the bus master DMA enable bit. -+ * -+ * The generic IDE core will have disabled the BMEN bit before this -+ * function is called. -+ */ -+static void sl82c105_before_bm_enable(ide_drive_t *drive) -+{ -+ ide_hwif_t *hwif = HWIF(drive); -+ struct pci_dev *dev = hwif->pci_dev; -+ -+ sl82c105_reset_host(dev); -+} -+ -+/* -+ * Our very own dmaproc. We need to intercept various calls -+ * to fix up the SL82C105 specific behaviour. -+ */ -+static int sl82c105_dmaproc(ide_dma_action_t func, ide_drive_t *drive) -+{ -+ switch (func) { -+ case ide_dma_check: -+ return sl82c105_check_drive(drive); -+ -+ case ide_dma_on: -+ if (config_for_dma(drive)) -+ func = ide_dma_off; -+ /* fall through */ -+ -+ case ide_dma_off_quietly: -+ case ide_dma_off: -+ config_for_pio(drive, 4, 0); -+ break; -+ -+ case ide_dma_read: -+ case ide_dma_write: -+ case ide_dma_begin: -+ case ide_dma_timeout: -+ sl82c105_before_bm_enable(drive); -+ break; -+ -+ case ide_dma_lostirq: -+ return sl82c105_lostirq(drive); -+ -+ default: -+ break; -+ } -+ return ide_dmaproc(func, drive); -+} -+ -+/* -+ * We only deal with PIO mode here - DMA mode 'using_dma' is not -+ * initialised at the point that this function is called. -+ */ -+static void tune_sl82c105(ide_drive_t *drive, byte pio) -+{ -+ config_for_pio(drive, pio, 1); -+ -+ /* -+ * We support 32-bit I/O on this interface, and it -+ * doesn't have problems with interrupts. -+ */ -+ drive->io_32bit = 1; -+ drive->unmask = 1; -+} -+ -+/* -+ * Return the revision of the Winbond bridge -+ * which this function is part of. -+ */ -+static unsigned int sl82c105_bridge_revision(struct pci_dev *dev) -+{ -+ struct pci_dev *bridge; -+ unsigned char rev; -+ -+ /* -+ * The bridge should be part of the same device, but function 0. -+ */ -+ bridge = pci_find_slot(dev->bus->number, -+ PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); -+ if (!bridge) -+ return -1; -+ -+ /* -+ * Make sure it is a Winbond 553 and is an ISA bridge. -+ */ -+ if (bridge->vendor != PCI_VENDOR_ID_WINBOND || -+ bridge->device != PCI_DEVICE_ID_WINBOND_83C553 || -+ bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA) -+ return -1; -+ -+ /* -+ * We need to find function 0's revision, not function 1 -+ */ -+ pci_read_config_byte(bridge, PCI_REVISION_ID, &rev); -+ -+ return rev; -+} -+ -+/* -+ * Enable the PCI device -+ */ -+unsigned int __init pci_init_sl82c105(struct pci_dev *dev, const char *msg) -+{ -+ u32 val; -+ -+ pci_read_config_dword(dev, 0x40, &val); -+ val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1EN | CTRL_P1F16; -+ pci_write_config_dword(dev, 0x40, val); -+ -+ return dev->irq; -+} -+ -+void __init dma_init_sl82c105(ide_hwif_t *hwif, unsigned long dma_base) -+{ -+ unsigned int bridge_rev; -+ byte dma_state; -+ -+ dma_state = inb(dma_base + 2); -+ bridge_rev = sl82c105_bridge_revision(hwif->pci_dev); -+ if (bridge_rev <= 5) { -+ hwif->autodma = 0; -+ hwif->drives[0].autotune = 1; -+ hwif->drives[1].autotune = 1; -+ printk(" %s: Winbond 553 bridge revision %d, BM-DMA disabled\n", -+ hwif->name, bridge_rev); -+ dma_state &= ~0x60; -+ } else { -+ dma_state |= 0x60; -+ hwif->autodma = 1; -+ } -+ outb(dma_state, dma_base + 2); -+ -+ ide_setup_dma(hwif, dma_base, 8); -+ -+ if (bridge_rev <= 5) -+ hwif->dmaproc = NULL; -+ else -+ hwif->dmaproc = sl82c105_dmaproc; -+} -+ -+/* -+ * Initialise the chip -+ */ -+void __init ide_init_sl82c105(ide_hwif_t *hwif) -+{ -+ hwif->tuneproc = tune_sl82c105; -+} -+ -diff -urN linux-2.4.26/drivers/input/Config.in linux-2.4.26-vrs1/drivers/input/Config.in ---- linux-2.4.26/drivers/input/Config.in 2004-02-27 20:03:25.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/input/Config.in 2004-02-23 22:53:55.000000000 +0000 -@@ -15,5 +15,6 @@ - dep_tristate ' Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_INPUT - dep_tristate ' Event interface support' CONFIG_INPUT_EVDEV $CONFIG_INPUT - dep_tristate ' User level driver support' CONFIG_INPUT_UINPUT $CONFIG_INPUT -+dep_tristate ' MX1 touchscreen support' CONFIG_INPUT_MX1TS $CONFIG_INPUT_MOUSEDEV $CONFIG_ARCH_MX1ADS - - endmenu -diff -urN linux-2.4.26/drivers/input/Makefile linux-2.4.26-vrs1/drivers/input/Makefile ---- linux-2.4.26/drivers/input/Makefile 2004-02-27 20:03:25.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/input/Makefile 2004-02-23 22:53:03.000000000 +0000 -@@ -24,6 +24,7 @@ - obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o - obj-$(CONFIG_INPUT_JOYDEV) += joydev.o - obj-$(CONFIG_INPUT_EVDEV) += evdev.o -+obj-$(CONFIG_INPUT_MX1TS) += mx1ts.o - obj-$(CONFIG_INPUT_UINPUT) += uinput.o - - # The global Rules.make. -diff -urN linux-2.4.26/drivers/input/mx1ts.c linux-2.4.26-vrs1/drivers/input/mx1ts.c ---- linux-2.4.26/drivers/input/mx1ts.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/input/mx1ts.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,508 @@ -+/* -+ * linux/drivers/misc/mx1ts.c -+ * -+ * Copyright (C) 2003 Blue Mug, Inc. for Motorola, Inc. -+ * -+ * Cloned from ucb1x00_ts.c -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include -+ -+#include "mx1ts.h" -+ -+#define DEV_IRQ_ID "mx1-ts" -+ -+struct mx1_ts { -+ struct input_dev idev; -+#ifdef CONFIG_PM -+ struct pm_dev *pmdev; -+#endif -+ -+ wait_queue_head_t irq_wait; -+ struct completion init_exit; -+ int use_count; -+ u16 x_res; -+ u16 y_res; -+ -+ int restart:1; -+}; -+ -+static struct mx1_ts mx1ts; -+static u8 mx1_performing_auto_calibration = 0; -+static u16 mx1_cal_auto_zero = 0; -+static u16 mx1_cal_range_x = 0; -+static u16 mx1_cal_range_y = 0; -+ -+static int mx1_ts_startup(struct mx1_ts *ts); -+static void mx1_ts_shutdown(struct mx1_ts *ts); -+ -+static void mx1_ts_pendata_int(int irq, void *dev_id, struct pt_regs *regs); -+static void mx1_ts_touch_int(int irq, void *dev_id, struct pt_regs *regs); -+static void mx1_ts_compare_int(int irq, void *dev_id, struct pt_regs *regs); -+ -+static void mx1_ts_enable_pen_touch_interrupt(void); -+static void mx1_ts_disable_pen_touch_interrupt(void); -+static void mx1_ts_enable_pen_up_interrupt(void); -+static void mx1_ts_disable_pen_up_interrupt(void); -+static void mx1_ts_enable_auto_sample(void); -+static void mx1_ts_disable_auto_sample(void); -+static void mx1_ts_start_auto_calibration(void); -+ -+static inline void mx1_reg_write(unsigned int reg, unsigned int val) -+{ -+ *((volatile unsigned int *)reg) = val; -+} -+ -+static inline unsigned int mx1_reg_read(unsigned int reg) -+{ -+ return *((volatile unsigned int *)reg); -+} -+ -+static inline void mx1_reg_clear_bit(unsigned int reg, unsigned int bit) -+{ -+ *((volatile unsigned int *)reg) &= ~bit; -+} -+ -+static inline void mx1_reg_set_bit(unsigned int reg, unsigned int bit) -+{ -+ *((volatile unsigned int *)reg) |= bit; -+} -+ -+static inline void mx1_ts_evt_add(struct mx1_ts *ts, u16 pressure, u16 x, u16 y) -+{ -+ input_report_abs(&ts->idev, ABS_X, (int)x - 32768); -+ input_report_abs(&ts->idev, ABS_Y, (int)y - 32768); -+ input_report_abs(&ts->idev, ABS_PRESSURE, (int)pressure); -+} -+ -+static inline void mx1_ts_flush_fifo(void) -+{ -+ int i; -+ for (i = 0; i < 12; i++) -+ if (mx1_reg_read(ASP_ISTATR) & (ASP_PFF | ASP_PDR)) -+ mx1_reg_read(ASP_PADFIFO); -+} -+ -+static int mx1_ts_open(struct input_dev *idev) -+{ -+ struct mx1_ts *ts = (struct mx1_ts *)idev; -+ -+ mx1_performing_auto_calibration = 0; -+ return mx1_ts_startup(ts); -+} -+ -+static void mx1_ts_close(struct input_dev *idev) -+{ -+ struct mx1_ts *ts = (struct mx1_ts *)idev; -+ -+ mx1_ts_shutdown(ts); -+} -+ -+static inline int mx1_ts_enable_irqs(void) -+{ -+ int result; -+ -+ result = request_irq(ASP_PENDATA_IRQ, -+ mx1_ts_pendata_int, -+ SA_INTERRUPT, -+ DEV_IRQ_ID, -+ DEV_IRQ_ID); -+ if (result) { -+ printk("Couldn't request pen data IRQ.\n"); -+ return result; -+ } -+ -+ result = request_irq(ASP_TOUCH_IRQ, -+ mx1_ts_touch_int, -+ SA_INTERRUPT, -+ DEV_IRQ_ID, -+ DEV_IRQ_ID); -+ if (result) { -+ printk("Couldn't request pen touch IRQ.\n"); -+ free_irq(ASP_PENDATA_IRQ, DEV_IRQ_ID); -+ return result; -+ } -+ -+ return result; -+} -+ -+static inline int mx1_ts_disable_irqs(void) -+{ -+ free_irq(ASP_PENDATA_IRQ, DEV_IRQ_ID); -+ free_irq(ASP_TOUCH_IRQ, DEV_IRQ_ID); -+ -+ return 0; -+} -+ -+static inline int mx1_ts_register(struct mx1_ts *ts) -+{ -+ ts->idev.name = "Touchscreen panel"; -+ ts->idev.open = mx1_ts_open; -+ ts->idev.close = mx1_ts_close; -+ -+ __set_bit(EV_ABS, ts->idev.evbit); -+ __set_bit(ABS_X, ts->idev.absbit); -+ __set_bit(ABS_Y, ts->idev.absbit); -+ __set_bit(ABS_PRESSURE, ts->idev.absbit); -+ -+ ts->idev.absmin[ABS_X] = 0; -+ ts->idev.absmax[ABS_X] = (u32)0x0000FFFF; -+ ts->idev.absfuzz[ABS_X] = 50; -+ ts->idev.absflat[ABS_X] = 0; -+ -+ ts->idev.absmin[ABS_Y] = 0; -+ ts->idev.absmax[ABS_Y] = (u32)0x0000FFFF; -+ ts->idev.absfuzz[ABS_Y] = 50; -+ ts->idev.absflat[ABS_Y] = 0; -+ -+ input_register_device(&ts->idev); -+ -+ return 0; -+} -+ -+static inline void mx1_ts_deregister(struct mx1_ts *ts) -+{ -+ input_unregister_device(&ts->idev); -+} -+ -+/* -+ * Handle the touch interrupt, generated when the pen is pressed/ -+ * released. -+ */ -+static void mx1_ts_touch_int(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ /* Clear the interrupt. */ -+ mx1_reg_set_bit(ASP_ISTATR, ASP_PEN); -+ -+ mx1_ts_disable_pen_touch_interrupt(); -+ mx1_ts_start_auto_calibration(); -+ mx1_ts_enable_pen_up_interrupt(); -+} -+ -+/* -+ * Handle the pen data ready interrupt, generated when pen data is -+ * in the FIFO. -+ */ -+static void mx1_ts_pendata_int(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ static unsigned int auto_zero, pen_x, pen_y, pen_u; -+ -+ if (mx1_reg_read(ASP_ISTATR) & 0x400) { -+ mx1_reg_set_bit(ASP_ISTATR, 0x400); -+ -+ mx1_ts_disable_auto_sample(); -+ mx1_ts_disable_pen_up_interrupt(); -+ mx1_ts_enable_pen_touch_interrupt(); -+ -+ mx1_ts_evt_add(&mx1ts, 0, pen_x, pen_y); -+ -+ mx1_ts_flush_fifo(); -+ -+ return; -+ } -+ -+ if (mx1_performing_auto_calibration) { -+ unsigned int value; -+ -+ mx1_cal_auto_zero = mx1_reg_read(ASP_PADFIFO) & 0xFFFF; -+ mx1_cal_range_x = mx1_reg_read(ASP_PADFIFO) & 0xFFFF; -+ mx1_cal_range_y = mx1_reg_read(ASP_PADFIFO) & 0xFFFF; -+ -+ if ((mx1_cal_auto_zero >= mx1_cal_range_x) || -+ (mx1_cal_auto_zero >= mx1_cal_range_y)) { -+ /* Invalid data. */ -+ mx1_ts_start_auto_calibration(); -+ return; -+ } -+ -+ mx1_cal_range_x -= mx1_cal_auto_zero; -+ mx1_cal_range_y -= mx1_cal_auto_zero; -+ -+ value = mx1_reg_read(ASP_ACNTLCR); -+ value &= ~0x04000000; /* XXX Undocumented. */ -+ mx1_reg_write(ASP_ACNTLCR, value); -+ -+ mx1_performing_auto_calibration = 0; -+ -+ mx1_ts_enable_auto_sample(); -+ } else { -+ /* There could be more than one sample in the FIFO, but we're -+ * only going to read one per call. The interrupt will be -+ * generated as long as there is data in the FIFO. */ -+ -+ if ((mx1_reg_read(ASP_ISTATR) & ASP_PDR) != ASP_PDR) { -+ return; -+ } -+ -+ auto_zero = mx1_reg_read(ASP_PADFIFO); -+ if (auto_zero > (mx1_cal_auto_zero + 0x200)) { -+ return; -+ } -+ -+ pen_x = mx1_reg_read(ASP_PADFIFO); -+ pen_y = mx1_reg_read(ASP_PADFIFO); -+ pen_u = mx1_reg_read(ASP_PADFIFO); -+ -+ pen_x = (u32)(((pen_x - mx1_cal_auto_zero) << 16) / -+ mx1_cal_range_x); -+ pen_y = (u32)(((pen_y - mx1_cal_auto_zero) << 16) / -+ mx1_cal_range_y); -+ -+ mx1_ts_evt_add(&mx1ts, pen_u, pen_x, pen_y); -+ } -+} -+ -+static void mx1_ts_reset_asp(void) -+{ -+ unsigned int value; -+ -+ mx1_ts_flush_fifo(); -+ -+ /* Soft reset the ASP module */ -+ mx1_reg_write(ASP_ACNTLCR, ASP_SWRST); -+ -+ /* Read back the reset value of the control register */ -+ value = mx1_reg_read(ASP_ACNTLCR); -+ -+ /* Enable the clock and wait for a short while */ -+ value |= ASP_CLKEN; -+ mx1_reg_write(ASP_ACNTLCR, value); -+ udelay(100); -+ -+ /* Set the value of the conrtol register. */ -+ value = ASP_CLKEN | ASP_NM | ASP_SW6 | ASP_BGE; -+ mx1_reg_write(ASP_ACNTLCR, value); -+ -+ /* Set the clock divide ratio to 2. */ -+ mx1_reg_write(ASP_CLKDIV, 0x01); -+ -+ /* Set the sample rate control register. These values should yield -+ * about 150 samples per second, which seems to give good smooth -+ * lines. */ -+ value = (0x2 << ASP_DMCNT_SCALE) | /* Decimation ratio is 3 */ -+ (0x1 << ASP_IDLECNT_SCALE) | /* Idle count is 1 clock */ -+ (0x2 << ASP_DSCNT_SCALE); /* Data setup is 2 clocks */ -+ mx1_reg_write(ASP_PSMPLRG, value); -+ -+ /* Disable the compare function. */ -+ mx1_reg_write(ASP_CMPCNTL, 0); -+} -+ -+static void mx1_ts_enable_auto_sample(void) -+{ -+ unsigned int value; -+ -+ mx1_ts_flush_fifo(); -+ -+ value = mx1_reg_read(ASP_ACNTLCR); -+ -+ /* Set the mode to X then Y */ -+ value &= ~ASP_MODE_MASK; -+ value |= ASP_MODE_ONLY_Y; -+ -+ /* Enable auto zero. */ -+ value |= ASP_AZE; -+ -+ /* Enable auto sample. */ -+ value |= ASP_AUTO; -+ -+ /* Enable pen A/D. */ -+ value |= ASP_PADE; -+ mx1_reg_write(ASP_ACNTLCR, value); -+ -+ /* Enable pen data ready and full interrupt. */ -+ value = mx1_reg_read(ASP_ICNTLR); -+ value |= ASP_PFFE | ASP_PDRE; -+ mx1_reg_write(ASP_ICNTLR, value); -+} -+ -+static void mx1_ts_disable_auto_sample(void) -+{ -+ unsigned int value; -+ -+ value = mx1_reg_read(ASP_ACNTLCR); -+ -+ /* Set the mode to none */ -+ value &= ~ASP_MODE_MASK; -+ -+ /* Disable auto zero. */ -+ value &= ~ASP_AZE; -+ -+ /* Disable auto sample. */ -+ value &= ~ASP_AUTO; -+ -+ /* Disable pen A/D. */ -+ value &= ~ASP_PADE; -+ mx1_reg_write(ASP_ACNTLCR, value); -+ -+ /* Disable pen data ready and full interrupt. */ -+ value = mx1_reg_read(ASP_ICNTLR); -+ value &= ~(ASP_PFFE | ASP_PDRE); -+ mx1_reg_write(ASP_ICNTLR, value); -+} -+ -+static void mx1_ts_enable_pen_touch_interrupt(void) -+{ -+ unsigned int value; -+ -+ /* Enable pen touch interrupt. */ -+ value = mx1_reg_read(ASP_ICNTLR); -+ value |= ASP_EDGE | ASP_PIRQE; -+ mx1_reg_write(ASP_ICNTLR, value); -+} -+ -+static void mx1_ts_disable_pen_touch_interrupt(void) -+{ -+ unsigned int value; -+ -+ /* Enable pen touch interrupt. */ -+ value = mx1_reg_read(ASP_ICNTLR); -+ value &= ~ASP_PIRQE; -+ mx1_reg_write(ASP_ICNTLR, value); -+} -+ -+static void mx1_ts_enable_pen_up_interrupt(void) -+{ -+ unsigned int value; -+ -+ /* Enable pen up interrupt. XXX: This feature is undocumented. */ -+ value = mx1_reg_read(ASP_ICNTLR); -+ value |= ASP_PUPE; -+ mx1_reg_write(ASP_ICNTLR, value); -+} -+ -+static void mx1_ts_disable_pen_up_interrupt(void) -+{ -+ unsigned int value; -+ -+ /* Enable pen up interrupt. XXX: This feature is undocumented. */ -+ value = mx1_reg_read(ASP_ICNTLR); -+ value &= ~ASP_PUPE; -+ mx1_reg_write(ASP_ICNTLR, value); -+} -+ -+static void mx1_ts_start_auto_calibration(void) -+{ -+ unsigned int value; -+ -+ mx1_performing_auto_calibration = 1; -+ -+ value = mx1_reg_read(ASP_ACNTLCR); -+ -+ /* Set the mode to X then Y */ -+ value &= ~ASP_MODE_MASK; -+ value |= ASP_MODE_ONLY_X; -+ -+ /* Enable auto zero. */ -+ value |= ASP_AZE; -+ -+ /* Enable auto calibrate. XXX: Undocumented bitfield. */ -+ value |= 0x04000000; -+ -+ /* Enable auto sample. */ -+ value |= ASP_AUTO; -+ -+ /* Enable pen A/D. */ -+ value |= ASP_PADE; -+ mx1_reg_write(ASP_ACNTLCR, value); -+ -+ /* Enable pen data ready and full interrupt. */ -+ value = mx1_reg_read(ASP_ICNTLR); -+ value |= ASP_PFFE | ASP_PDRE | ASP_PUPE; -+ mx1_reg_write(ASP_ICNTLR, value); -+} -+ -+static int mx1_ts_startup(struct mx1_ts *ts) -+{ -+ int ret = 0; -+ -+ if (ts->use_count++ != 0) -+ goto out; -+ -+ /* -+ * Reset the ASP. -+ */ -+ mx1_ts_reset_asp(); -+ -+ -+ /* -+ * XXX: Figure out if we need this... -+ * If we do this at all, we should allow the user to -+ * measure and read the X and Y resistance at any time. -+ */ -+ //ts->x_res = mx1_ts_read_xres(ts); -+ //ts->y_res = mx1_ts_read_yres(ts); -+ -+ mx1_ts_enable_pen_touch_interrupt(); -+ -+ out: -+ if (ret) -+ ts->use_count--; -+ return ret; -+} -+ -+/* -+ * Release touchscreen resources. Disable IRQs. -+ */ -+static void mx1_ts_shutdown(struct mx1_ts *ts) -+{ -+ if (--ts->use_count == 0) { -+ unsigned int value; -+ -+ /* Turn off the ADC and associated circuitry. */ -+ value = mx1_reg_read(ASP_ACNTLCR); -+ value &= !(ASP_CLKEN | ASP_PADE | ASP_BGE); -+ mx1_reg_write(ASP_ACNTLCR, value); -+ } -+} -+ -+/* -+ * Initialization. -+ */ -+static int __init mx1_ts_init(void) -+{ -+ int ret = 0; -+ struct mx1_ts *ts = &mx1ts; -+ -+ mx1_ts_reset_asp(); -+ -+ /* -+ * Enable the IRQ's -+ */ -+ if ((ret = mx1_ts_enable_irqs())) -+ return ret; -+ -+ return mx1_ts_register(ts); -+} -+ -+static void __exit mx1_ts_exit(void) -+{ -+ struct mx1_ts *ts = &mx1ts; -+ -+ mx1_ts_disable_irqs(); -+ mx1_ts_deregister(ts); -+} -+ -+module_init(mx1_ts_init); -+module_exit(mx1_ts_exit); -+ -+MODULE_AUTHOR("Jon McClintock "); -+MODULE_DESCRIPTION("MX1 touchscreen driver"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.4.26/drivers/input/mx1ts.h linux-2.4.26-vrs1/drivers/input/mx1ts.h ---- linux-2.4.26/drivers/input/mx1ts.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/input/mx1ts.h 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,108 @@ -+/* -+ * linux/drivers/misc/mx1ts.h -+ * -+ * Copyright (C) 2003 Blue Mug, Inc. for Motorola, Inc. -+ * -+ * 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. -+ * -+ */ -+ -+/* Interrupt numbers */ -+#define ASP_COMPARE_IRQ 5 -+#define ASP_PENDATA_IRQ 33 -+#define ASP_TOUCH_IRQ 46 -+ -+/* Analog signal processor (ASP) control registers */ -+#define ASP_ACNTLCR 0xF0215010 /* Control register */ -+#define ASP_PSMPLRG 0xF0215014 /* Pen A/D sampe rate control */ -+#define ASP_CMPCNTL 0xF0215030 /* Compare control register */ -+#define ASP_ICNTLR 0xF0215018 /* Interrupt control register */ -+#define ASP_ISTATR 0xF021501C /* Interrupt status register */ -+#define ASP_PADFIFO 0xF0215000 /* Pen sample FIFO */ -+#define ASP_CLKDIV 0xF021502C /* Clock divide register */ -+ -+/* ASP control register bits */ -+#define ASP_CLKEN (1 << 25) /* Clock enable */ -+#define ASP_SWRST (1 << 23) /* Software reset */ -+#define ASP_U_SEL (1 << 21) /* U-channel resistor select */ -+#define ASP_AZ_SEL (1 << 20) /* Auto-zero position select */ -+#define ASP_LVM (1 << 19) /* Low voltage output */ -+#define ASP_NM (1 << 18) /* Normal voltage output */ -+#define ASP_HPM (1 << 17) /* High voltage output */ -+#define ASP_GLO (1 << 16) /* Low gain enable */ -+#define ASP_AZE (1 << 15) /* Auto-zero enable */ -+#define ASP_AUTO (1 << 14) /* Auto sampling */ -+#define ASP_SW8 (1 << 11) /* Switch control 8 */ -+#define ASP_SW7 (1 << 10) -+#define ASP_SW6 (1 << 9) -+#define ASP_SW5 (1 << 8) -+#define ASP_SW4 (1 << 7) -+#define ASP_SW3 (1 << 6) -+#define ASP_SW2 (1 << 5) -+#define ASP_SW1 (1 << 4) /* Switch control 1 */ -+#define ASP_VDAE (1 << 3) /* Voice D/A enable */ -+#define ASP_VADE (1 << 2) /* Voice A/D enable */ -+#define ASP_PADE (1 << 1) /* Pen A/D enable */ -+#define ASP_BGE (1 << 0) /* Bandgap enable */ -+ -+#define ASP_MODE_MASK 0x00003000 -+#define ASP_MODE_NONE 0x00000000 -+#define ASP_MODE_ONLY_X 0x00001000 -+#define ASP_MODE_ONLY_Y 0x00002000 -+#define ASP_MODE_ONLY_U 0x00003000 -+ -+/* ASP Pen A/D sample rate control register */ -+#define ASP_DMCNT_MASK (0x00007000) /* Decimation ratio count */ -+#define ASP_DMCNT_SCALE (12) -+#define ASP_BIT_SELECT_MASK (0x00000C00) /* Bit select */ -+#define ASP_BIT_SELECT_SCALE (10) -+#define ASP_IDLECNT_MASK (0x000003F0) /* Idle count */ -+#define ASP_IDLECNT_SCALE (4) -+#define ASP_DSCNT_MASK (0x0000000F) /* Data setup count */ -+#define ASP_DSCNT_SCALE (0) -+ -+/* ASP compare control register */ -+#define ASP_INT (1 << 19) /* Interrupt status */ -+#define ASP_CC (1 << 18) /* Trigger on greater than */ -+#define ASP_INSEL_MASK (0x00030000) -+#define ASP_INSEL_DISABLE (0x00000000) -+#define ASP_INSEL_X (0x00010000) -+#define ASP_INSEL_Y (0x00020000) -+#define ASP_INSEL_U (0x00030000) -+#define ASP_COMPARE_VAL_MASK (0x0000FFFF) -+#define ASP_COMPARE_VAL_SCALE (0) -+ -+/* ASP interrupt control register bits */ -+#define ASP_PUPE (1 << 10) /* Pen up XXX undocumented */ -+#define ASP_VDDMAE (1 << 8) /* VDAC FIFO empty DMA */ -+#define ASP_VADMAE (1 << 7) /* VADC FIFO full DMA */ -+#define ASP_POL (1 << 6) /* Pen interrupt polarity */ -+#define ASP_EDGE (1 << 5) /* Edge trigger enable */ -+#define ASP_PIRQE (1 << 4) /* Pen interrupt enable */ -+#define ASP_VDAFEE (1 << 3) /* VDAC FIFO empty interrupt */ -+#define ASP_VADFFE (1 << 2) /* VADC FIFO full interrupt */ -+#define ASP_PFFE (1 << 1) /* Pen FIFO full interrupt */ -+#define ASP_PDRE (1 << 0) /* Pen data ready interrupt */ -+ -+/* ASP interrupt/error status register bits */ -+#define ASP_PUP (1 << 10) /* Pen up XXX undocumented */ -+#define ASP_BGR (1 << 9) /* Bandgap ready */ -+#define ASP_VOV (1 << 8) /* Voice sample data overflow */ -+#define ASP_POV (1 << 7) /* Pen sample data overflow */ -+#define ASP_PEN (1 << 6) /* Pen interrupt */ -+#define ASP_VDAFF (1 << 5) /* VDAC FIFO full */ -+#define ASP_VDAFE (1 << 4) /* VDAC FIFO empty */ -+#define ASP_VADFF (1 << 3) /* VADC FIFO full */ -+#define ASP_VADDR (1 << 2) /* VADC data ready */ -+#define ASP_PFF (1 << 1) /* Pen sample FIFO full */ -+#define ASP_PDR (1 << 0) /* Pen data ready */ -+ -+/* ASP Clock divide register */ -+#define ASP_PADC_CLK_MASK (0x0000001F) -+#define ASP_PADC_CLK_SCALE (0) -+#define ASP_VADC_CLK_MASK (0x000003E0) -+#define ASP_VADC_CLK_SCALE (5) -+#define ASP_VDAC_CLK_MASK (0x00003C00) -+#define ASP_VDAC_CLK_SCALE (10) -diff -urN linux-2.4.26/drivers/l3/Config.in linux-2.4.26-vrs1/drivers/l3/Config.in ---- linux-2.4.26/drivers/l3/Config.in 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/l3/Config.in 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,21 @@ -+# -+# L3 bus configuration -+# -+mainmenu_option next_comment -+comment 'L3 serial bus support' -+ -+tristate 'L3 support' CONFIG_L3 -+dep_bool ' L3 bit-banging interfaces' CONFIG_L3_ALGOBIT $CONFIG_L3 -+dep_bool ' SA11x0 GPIO adapter' CONFIG_L3_BIT_SA1100_GPIO $CONFIG_L3_ALGOBIT $CONFIG_ARCH_SA1100 -+ -+comment 'Other L3 adapters' -+dep_bool ' SA1111 adapter' CONFIG_L3_SA1111 $CONFIG_L3 -+endmenu -+ -+# i2c must come before this -+if [ "$CONFIG_L3_BIT_SA1100_GPIO" = "y" -o \ -+ "$CONFIG_I2C_BIT_SA1100_GPIO" = "y" ]; then -+ define_bool CONFIG_BIT_SA1100_GPIO y -+else -+ define_bool CONFIG_BIT_SA1100_GPIO n -+fi -diff -urN linux-2.4.26/drivers/l3/Makefile linux-2.4.26-vrs1/drivers/l3/Makefile ---- linux-2.4.26/drivers/l3/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/l3/Makefile 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,23 @@ -+# -+# Makefile for the L3 bus driver. -+# -+ -+O_TARGET := l3.o -+ -+export-objs := l3-core.o l3-algo-bit.o -+l3-y := -+l3-n := -+l3-drv-y := -+l3-drv-n := -+ -+# Link order: -+# (core, adapters, algorithms, drivers) then clients -+ -+l3-$(CONFIG_L3_ALGOBIT) += l3-algo-bit.o -+l3-$(CONFIG_BIT_SA1100_GPIO) += l3-bit-sa1100.o -+l3-$(CONFIG_L3_SA1111) += l3-sa1111.o -+ -+obj-$(CONFIG_L3) += l3-core.o $(l3-y) $(l3-drv-y) -+ -+include $(TOPDIR)/Rules.make -+ -diff -urN linux-2.4.26/drivers/l3/l3-algo-bit.c linux-2.4.26-vrs1/drivers/l3/l3-algo-bit.c ---- linux-2.4.26/drivers/l3/l3-algo-bit.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/l3/l3-algo-bit.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,175 @@ -+/* -+ * L3 bus algorithm module. -+ * -+ * Copyright (C) 2001 Russell King, All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Note that L3 buses can share the same pins as I2C buses, so we must -+ * _not_ generate an I2C start condition. An I2C start condition is -+ * defined as a high-to-low transition of the data line while the clock -+ * is high. Therefore, we must only change the data line while the -+ * clock is low. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define setdat(adap,val) adap->setdat(adap->data, val) -+#define setclk(adap,val) adap->setclk(adap->data, val) -+#define setmode(adap,val) adap->setmode(adap->data, val) -+#define setdatin(adap) adap->setdir(adap->data, 1) -+#define setdatout(adap) adap->setdir(adap->data, 0) -+#define getdat(adap) adap->getdat(adap->data) -+ -+/* -+ * Send one byte of data to the chip. Data is latched into the chip on -+ * the rising edge of the clock. -+ */ -+static void sendbyte(struct l3_algo_bit_data *adap, unsigned int byte) -+{ -+ int i; -+ -+ for (i = 0; i < 8; i++) { -+ setclk(adap, 0); -+ udelay(adap->data_hold); -+ setdat(adap, byte & 1); -+ udelay(adap->data_setup); -+ setclk(adap, 1); -+ udelay(adap->clock_high); -+ byte >>= 1; -+ } -+} -+ -+/* -+ * Send a set of bytes to the chip. We need to pulse the MODE line -+ * between each byte, but never at the start nor at the end of the -+ * transfer. -+ */ -+static void sendbytes(struct l3_algo_bit_data *adap, const char *buf, int len) -+{ -+ int i; -+ -+ for (i = 0; i < len; i++) { -+ if (i) { -+ udelay(adap->mode_hold); -+ setmode(adap, 0); -+ udelay(adap->mode); -+ } -+ setmode(adap, 1); -+ udelay(adap->mode_setup); -+ sendbyte(adap, buf[i]); -+ } -+} -+ -+/* -+ * Read one byte of data from the chip. Data is latched into the chip on -+ * the rising edge of the clock. -+ */ -+static unsigned int readbyte(struct l3_algo_bit_data *adap) -+{ -+ unsigned int byte = 0; -+ int i; -+ -+ for (i = 0; i < 8; i++) { -+ setclk(adap, 0); -+ udelay(adap->data_hold + adap->data_setup); -+ setclk(adap, 1); -+ if (getdat(adap)) -+ byte |= 1 << i; -+ udelay(adap->clock_high); -+ } -+ -+ return byte; -+} -+ -+/* -+ * Read a set of bytes from the chip. We need to pulse the MODE line -+ * between each byte, but never at the start nor at the end of the -+ * transfer. -+ */ -+static void readbytes(struct l3_algo_bit_data *adap, char *buf, int len) -+{ -+ int i; -+ -+ for (i = 0; i < len; i++) { -+ if (i) { -+ udelay(adap->mode_hold); -+ setmode(adap, 0); -+ } -+ setmode(adap, 1); -+ udelay(adap->mode_setup); -+ buf[i] = readbyte(adap); -+ } -+} -+ -+static int l3_xfer(struct l3_adapter *l3_adap, struct l3_msg msgs[], int num) -+{ -+ struct l3_algo_bit_data *adap = l3_adap->algo_data; -+ int i; -+ -+ /* -+ * If we share an I2C bus, ensure that it is in STOP mode -+ */ -+ setclk(adap, 1); -+ setdat(adap, 1); -+ setmode(adap, 1); -+ setdatout(adap); -+ udelay(adap->mode); -+ -+ for (i = 0; i < num; i++) { -+ struct l3_msg *pmsg = &msgs[i]; -+ -+ if (!(pmsg->flags & L3_M_NOADDR)) { -+ setmode(adap, 0); -+ udelay(adap->mode_setup); -+ sendbyte(adap, pmsg->addr); -+ udelay(adap->mode_hold); -+ } -+ -+ if (pmsg->flags & L3_M_RD) { -+ setdatin(adap); -+ readbytes(adap, pmsg->buf, pmsg->len); -+ } else { -+ setdatout(adap); -+ sendbytes(adap, pmsg->buf, pmsg->len); -+ } -+ } -+ -+ /* -+ * Ensure that we leave the bus in I2C stop mode. -+ */ -+ setclk(adap, 1); -+ setdat(adap, 1); -+ setmode(adap, 0); -+ setdatin(adap); -+ -+ return num; -+} -+ -+static struct l3_algorithm l3_bit_algo = { -+ name: "L3 bit-shift algorithm", -+ xfer: l3_xfer, -+}; -+ -+int l3_bit_add_bus(struct l3_adapter *adap) -+{ -+ adap->algo = &l3_bit_algo; -+ return l3_add_adapter(adap); -+} -+ -+int l3_bit_del_bus(struct l3_adapter *adap) -+{ -+ return l3_del_adapter(adap); -+} -+ -+EXPORT_SYMBOL(l3_bit_add_bus); -+EXPORT_SYMBOL(l3_bit_del_bus); -diff -urN linux-2.4.26/drivers/l3/l3-bit-sa1100.c linux-2.4.26-vrs1/drivers/l3/l3-bit-sa1100.c ---- linux-2.4.26/drivers/l3/l3-bit-sa1100.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/l3/l3-bit-sa1100.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,277 @@ -+/* -+ * linux/drivers/l3/l3-bit-sa1100.c -+ * -+ * Copyright (C) 2001 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 is a combined I2C and L3 bus driver. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#define NAME "l3-bit-sa1100-gpio" -+ -+struct bit_data { -+ unsigned int sda; -+ unsigned int scl; -+ unsigned int l3_mode; -+}; -+ -+static int getsda(void *data) -+{ -+ struct bit_data *bits = data; -+ -+ return GPLR & bits->sda; -+} -+ -+#ifdef CONFIG_I2C_BIT_SA1100_GPIO -+static void i2c_setsda(void *data, int state) -+{ -+ struct bit_data *bits = data; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ if (state) -+ GPDR &= ~bits->sda; -+ else { -+ GPCR = bits->sda; -+ GPDR |= bits->sda; -+ } -+ local_irq_restore(flags); -+} -+ -+static void i2c_setscl(void *data, int state) -+{ -+ struct bit_data *bits = data; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ if (state) -+ GPDR &= ~bits->scl; -+ else { -+ GPCR = bits->scl; -+ GPDR |= bits->scl; -+ } -+ local_irq_restore(flags); -+} -+ -+static int i2c_getscl(void *data) -+{ -+ struct bit_data *bits = data; -+ -+ return GPLR & bits->scl; -+} -+ -+static struct i2c_algo_bit_data i2c_bit_data = { -+ setsda: i2c_setsda, -+ setscl: i2c_setscl, -+ getsda: getsda, -+ getscl: i2c_getscl, -+ udelay: 10, -+ mdelay: 10, -+ timeout: 100, -+}; -+ -+static struct i2c_adapter i2c_adapter = { -+ name: NAME, -+ algo_data: &i2c_bit_data, -+// inc_use: i2c_inc_use, -+// dec_use: i2c_dec_use, -+}; -+ -+#define LOCK &i2c_adapter.lock -+ -+static int __init i2c_init(struct bit_data *bits) -+{ -+ i2c_bit_data.data = bits; -+ return i2c_bit_add_bus(&i2c_adapter); -+} -+ -+static void i2c_exit(void) -+{ -+ i2c_bit_del_bus(&i2c_adapter); -+} -+ -+#else -+static DECLARE_MUTEX(l3_lock); -+#define LOCK &l3_lock -+#define i2c_init(bits) (0) -+#define i2c_exit() do { } while (0) -+#endif -+ -+#ifdef CONFIG_L3_BIT_SA1100_GPIO -+/* -+ * iPAQs need the clock line driven hard high and low. -+ */ -+static void l3_setscl(void *data, int state) -+{ -+ struct bit_data *bits = data; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ if (state) -+ GPSR = bits->scl; -+ else -+ GPCR = bits->scl; -+ GPDR |= bits->scl; -+ local_irq_restore(flags); -+} -+ -+static void l3_setsda(void *data, int state) -+{ -+ struct bit_data *bits = data; -+ -+ if (state) -+ GPSR = bits->sda; -+ else -+ GPCR = bits->sda; -+} -+ -+static void l3_setdir(void *data, int in) -+{ -+ struct bit_data *bits = data; -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ if (in) -+ GPDR &= ~bits->sda; -+ else -+ GPDR |= bits->sda; -+ local_irq_restore(flags); -+} -+ -+static void l3_setmode(void *data, int state) -+{ -+ struct bit_data *bits = data; -+ -+ if (state) -+ GPSR = bits->l3_mode; -+ else -+ GPCR = bits->l3_mode; -+} -+ -+static struct l3_algo_bit_data l3_bit_data = { -+ data: NULL, -+ setdat: l3_setsda, -+ setclk: l3_setscl, -+ setmode: l3_setmode, -+ setdir: l3_setdir, -+ getdat: getsda, -+ data_hold: 1, -+ data_setup: 1, -+ clock_high: 1, -+ mode_hold: 1, -+ mode_setup: 1, -+}; -+ -+static struct l3_adapter l3_adapter = { -+ owner: THIS_MODULE, -+ name: NAME, -+ algo_data: &l3_bit_data, -+ lock: LOCK, -+}; -+ -+static int __init l3_init(struct bit_data *bits) -+{ -+ l3_bit_data.data = bits; -+ return l3_bit_add_bus(&l3_adapter); -+} -+ -+static void __exit l3_exit(void) -+{ -+ l3_bit_del_bus(&l3_adapter); -+} -+#else -+#define l3_init(bits) (0) -+#define l3_exit() do { } while (0) -+#endif -+ -+static struct bit_data bit_data; -+ -+static int __init bus_init(void) -+{ -+ struct bit_data *bit = &bit_data; -+ unsigned long flags; -+ int ret; -+ -+ if (machine_is_assabet() || machine_is_pangolin()) { -+ bit->sda = GPIO_GPIO15; -+ bit->scl = GPIO_GPIO18; -+ bit->l3_mode = GPIO_GPIO17; -+ } -+ -+#if defined(CONFIG_SA1100_H3600) || defined(CONFIG_SA1100_H3100) -+ if (machine_is_h3600() || machine_is_h3100()) { -+ bit->sda = GPIO_H3600_L3_DATA; -+ bit->scl = GPIO_H3600_L3_CLOCK; -+ bit->l3_mode = GPIO_H3600_L3_MODE; -+ } -+#endif -+ -+#ifdef CONFIG_SA1100_STORK -+ if (machine_is_stork()) { -+ bit->sda = GPIO_STORK_L3_I2C_SDA; -+ bit->scl = GPIO_STORK_L3_I2C_SCL; -+ bit->l3_mode = GPIO_STORK_L3_MODE; -+ } -+#endif -+ -+ if (!bit->sda) -+ return -ENODEV; -+ -+ /* -+ * Default level for L3 mode is low. -+ * We set SCL and SDA high (i2c idle state). -+ */ -+ local_irq_save(flags); -+ GPDR &= ~(bit->scl | bit->sda); -+ GPCR = bit->l3_mode | bit->scl | bit->sda; -+ GPDR |= bit->l3_mode; -+ local_irq_restore(flags); -+ -+ if (machine_is_assabet()) { -+ /* -+ * Release reset on UCB1300, ADI7171 and UDA1341. We -+ * need to do this here so that we can communicate on -+ * the I2C/L3 buses. -+ */ -+ ASSABET_BCR_set(ASSABET_BCR_CODEC_RST); -+ mdelay(1); -+ ASSABET_BCR_clear(ASSABET_BCR_CODEC_RST); -+ mdelay(1); -+ ASSABET_BCR_set(ASSABET_BCR_CODEC_RST); -+ } -+ -+ ret = i2c_init(bit); -+ if (ret == 0 && bit->l3_mode) { -+ ret = l3_init(bit); -+ if (ret) -+ i2c_exit(); -+ } -+ -+ return ret; -+} -+ -+static void __exit bus_exit(void) -+{ -+ l3_exit(); -+ i2c_exit(); -+} -+ -+module_init(bus_init); -+module_exit(bus_exit); -diff -urN linux-2.4.26/drivers/l3/l3-core.c linux-2.4.26-vrs1/drivers/l3/l3-core.c ---- linux-2.4.26/drivers/l3/l3-core.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/l3/l3-core.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,377 @@ -+/* -+ * linux/drivers/l3/l3-core.c -+ * -+ * Copyright (C) 2001 Russell King -+ * -+ * General structure taken from i2c-core.c by Simon G. Vogl -+ * -+ * 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. -+ * -+ * See linux/Documentation/l3 for further documentation. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static DECLARE_MUTEX(adapter_lock); -+static LIST_HEAD(adapter_list); -+ -+static DECLARE_MUTEX(driver_lock); -+static LIST_HEAD(driver_list); -+ -+/** -+ * l3_add_adapter - register a new L3 bus adapter -+ * @adap: l3_adapter structure for the registering adapter -+ * -+ * Make the adapter available for use by clients using name adap->name. -+ * The adap->adapters list is initialised by this function. -+ * -+ * Returns 0; -+ */ -+int l3_add_adapter(struct l3_adapter *adap) -+{ -+ INIT_LIST_HEAD(&adap->clients); -+ down(&adapter_lock); -+ list_add(&adap->adapters, &adapter_list); -+ up(&adapter_lock); -+ return 0; -+} -+ -+/** -+ * l3_del_adapter - unregister a L3 bus adapter -+ * @adap: l3_adapter structure to unregister -+ * -+ * Remove an adapter from the list of available L3 Bus adapters. -+ * -+ * Returns 0; -+ */ -+int l3_del_adapter(struct l3_adapter *adap) -+{ -+ down(&adapter_lock); -+ list_del(&adap->adapters); -+ up(&adapter_lock); -+ return 0; -+} -+ -+static struct l3_adapter *__l3_get_adapter(const char *name) -+{ -+ struct list_head *l; -+ -+ list_for_each(l, &adapter_list) { -+ struct l3_adapter *adap = list_entry(l, struct l3_adapter, adapters); -+ -+ if (strcmp(adap->name, name) == 0) -+ return adap; -+ } -+ -+ return NULL; -+} -+ -+/** -+ * l3_get_adapter - get a reference to an adapter -+ * @name: driver name -+ * -+ * Obtain a l3_adapter structure for the specified adapter. If the adapter -+ * is not currently load, then load it. The adapter will be locked in core -+ * until all references are released via l3_put_adapter. -+ */ -+struct l3_adapter *l3_get_adapter(const char *name) -+{ -+ struct l3_adapter *adap; -+ int try; -+ -+ for (try = 0; try < 2; try ++) { -+ down(&adapter_lock); -+ adap = __l3_get_adapter(name); -+ if (adap && !try_inc_mod_count(adap->owner)) -+ adap = NULL; -+ up(&adapter_lock); -+ -+ if (adap) -+ break; -+ -+ if (try == 0) -+ request_module(name); -+ } -+ -+ return adap; -+} -+ -+/** -+ * l3_put_adapter - release a reference to an adapter -+ * @adap: driver to release reference -+ * -+ * Indicate to the L3 core that you no longer require the adapter reference. -+ * The adapter module may be unloaded when there are no references to its -+ * data structure. -+ * -+ * You must not use the reference after calling this function. -+ */ -+void l3_put_adapter(struct l3_adapter *adap) -+{ -+ if (adap && adap->owner) -+ __MOD_DEC_USE_COUNT(adap->owner); -+} -+ -+/** -+ * l3_add_driver - register a new L3 device driver -+ * @driver - driver structure to make available -+ * -+ * Make the driver available for use by clients using name driver->name. -+ * The driver->drivers list is initialised by this function. -+ * -+ * Returns 0; -+ */ -+int l3_add_driver(struct l3_driver *driver) -+{ -+ down(&driver_lock); -+ list_add(&driver->drivers, &driver_list); -+ up(&driver_lock); -+ return 0; -+} -+ -+/** -+ * l3_del_driver - unregister a L3 device driver -+ * @driver: driver to remove -+ * -+ * Remove an driver from the list of available L3 Bus device drivers. -+ * -+ * Returns 0; -+ */ -+int l3_del_driver(struct l3_driver *driver) -+{ -+ down(&driver_lock); -+ list_del(&driver->drivers); -+ up(&driver_lock); -+ return 0; -+} -+ -+static struct l3_driver *__l3_get_driver(const char *name) -+{ -+ struct list_head *l; -+ -+ list_for_each(l, &driver_list) { -+ struct l3_driver *drv = list_entry(l, struct l3_driver, drivers); -+ -+ if (strcmp(drv->name, name) == 0) -+ return drv; -+ } -+ -+ return NULL; -+} -+ -+/** -+ * l3_get_driver - get a reference to a driver -+ * @name: driver name -+ * -+ * Obtain a l3_driver structure for the specified driver. If the driver is -+ * not currently load, then load it. The driver will be locked in core -+ * until all references are released via l3_put_driver. -+ */ -+struct l3_driver *l3_get_driver(const char *name) -+{ -+ struct l3_driver *drv; -+ int try; -+ -+ for (try = 0; try < 2; try ++) { -+ down(&adapter_lock); -+ drv = __l3_get_driver(name); -+ if (drv && !try_inc_mod_count(drv->owner)) -+ drv = NULL; -+ up(&adapter_lock); -+ -+ if (drv) -+ break; -+ -+ if (try == 0) -+ request_module(name); -+ } -+ -+ return drv; -+} -+ -+/** -+ * l3_put_driver - release a reference to a driver -+ * @drv: driver to release reference -+ * -+ * Indicate to the L3 core that you no longer require the driver reference. -+ * The driver module may be unloaded when there are no references to its -+ * data structure. -+ * -+ * You must not use the reference after calling this function. -+ */ -+void l3_put_driver(struct l3_driver *drv) -+{ -+ if (drv && drv->owner) -+ __MOD_DEC_USE_COUNT(drv->owner); -+} -+ -+/** -+ * l3_attach_client - attach a client to an adapter and driver -+ * @client: client structure to attach -+ * @adap: adapter (module) name -+ * @drv: driver (module) name -+ * -+ * Attempt to attach a client (a user of a device driver) to a particular -+ * driver and adapter. If the specified driver or adapter aren't registered, -+ * request_module is used to load the relevant modules. -+ * -+ * Returns 0 on success, or negative error code. -+ */ -+int l3_attach_client(struct l3_client *client, const char *adap, const char *drv) -+{ -+ struct l3_adapter *adapter = l3_get_adapter(adap); -+ struct l3_driver *driver = l3_get_driver(drv); -+ int ret = -ENOENT; -+ -+ if (!adapter) -+ printk(KERN_ERR "%s: unable to get adapter: %s\n", -+ __FUNCTION__, adap); -+ if (!driver) -+ printk(KERN_ERR "%s: unable to get driver: %s\n", -+ __FUNCTION__, drv); -+ -+ if (adapter && driver) { -+ ret = 0; -+ -+ client->adapter = adapter; -+ client->driver = driver; -+ -+ list_add(&client->__adap, &adapter->clients); -+ -+ if (driver->attach_client) -+ ret = driver->attach_client(client); -+ } -+ -+ if (ret) { -+ l3_put_driver(driver); -+ l3_put_adapter(adapter); -+ } -+ return ret; -+} -+ -+/** -+ * l3_detach_client - detach a client from an adapter and driver -+ * @client: client structure to detach -+ * -+ * Detach the client from the adapter and driver. -+ */ -+int l3_detach_client(struct l3_client *client) -+{ -+ struct l3_adapter *adapter = client->adapter; -+ struct l3_driver *driver = client->driver; -+ -+ driver->detach_client(client); -+ -+ client->adapter = NULL; -+ client->driver = NULL; -+ -+ l3_put_driver(driver); -+ l3_put_adapter(adapter); -+ -+ list_del(&client->__adap); -+ -+ return 0; -+} -+ -+/** -+ * l3_transfer - transfer information on an L3 bus -+ * @adap: adapter structure to perform transfer on -+ * @msgs: array of l3_msg structures describing transfer -+ * @num: number of l3_msg structures -+ * -+ * Transfer the specified messages to/from a device on the L3 bus. -+ * -+ * Returns number of messages successfully transferred, otherwise negative -+ * error code. -+ */ -+int l3_transfer(struct l3_adapter *adap, struct l3_msg msgs[], int num) -+{ -+ int ret = -ENOSYS; -+ -+ if (adap->algo->xfer) { -+ down(adap->lock); -+ ret = adap->algo->xfer(adap, msgs, num); -+ up(adap->lock); -+ } -+ return ret; -+} -+ -+/** -+ * l3_write - send data to a device on an L3 bus -+ * @client: registered client structure -+ * @addr: L3 bus address -+ * @buf: buffer for bytes to send -+ * @len: number of bytes to send -+ * -+ * Send len bytes pointed to by buf to device address addr on the L3 bus -+ * described by client. -+ * -+ * Returns the number of bytes transferred, or negative error code. -+ */ -+int l3_write(struct l3_client *client, int addr, const char *buf, int len) -+{ -+ struct l3_adapter *adap = client->adapter; -+ struct l3_msg msg; -+ int ret; -+ -+ msg.addr = addr; -+ msg.flags = 0; -+ msg.buf = (char *)buf; -+ msg.len = len; -+ -+ ret = l3_transfer(adap, &msg, 1); -+ return ret == 1 ? len : ret; -+} -+ -+/** -+ * l3_read - receive data from a device on an L3 bus -+ * @client: registered client structure -+ * @addr: L3 bus address -+ * @buf: buffer for bytes to receive -+ * @len: number of bytes to receive -+ * -+ * Receive len bytes from device address addr on the L3 bus described by -+ * client to a buffer pointed to by buf. -+ * -+ * Returns the number of bytes transferred, or negative error code. -+ */ -+int l3_read(struct l3_client *client, int addr, char *buf, int len) -+{ -+ struct l3_adapter *adap = client->adapter; -+ struct l3_msg msg; -+ int ret; -+ -+ msg.addr = addr; -+ msg.flags = L3_M_RD; -+ msg.buf = buf; -+ msg.len = len; -+ -+ ret = l3_transfer(adap, &msg, 1); -+ return ret == 1 ? len : ret; -+} -+ -+EXPORT_SYMBOL(l3_add_adapter); -+EXPORT_SYMBOL(l3_del_adapter); -+EXPORT_SYMBOL(l3_get_adapter); -+EXPORT_SYMBOL(l3_put_adapter); -+ -+EXPORT_SYMBOL(l3_add_driver); -+EXPORT_SYMBOL(l3_del_driver); -+EXPORT_SYMBOL(l3_get_driver); -+EXPORT_SYMBOL(l3_put_driver); -+ -+EXPORT_SYMBOL(l3_attach_client); -+EXPORT_SYMBOL(l3_detach_client); -+ -+EXPORT_SYMBOL(l3_transfer); -+EXPORT_SYMBOL(l3_write); -+EXPORT_SYMBOL(l3_read); -diff -urN linux-2.4.26/drivers/l3/l3-sa1111.c linux-2.4.26-vrs1/drivers/l3/l3-sa1111.c ---- linux-2.4.26/drivers/l3/l3-sa1111.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/l3/l3-sa1111.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,118 @@ -+/* -+ * L3 SA1111 algorithm/adapter module. -+ * -+ * By Russell King, -+ * gratuitously ripped from sa1111-uda1341.c by John Dorsey. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+static inline unsigned char l3_sa1111_recv_byte(unsigned char addr) -+{ -+ unsigned char dat; -+ -+ L3_CAR = addr; -+ while ((SASR0 & SASR0_L3RD) == 0) -+ mdelay(1); -+ dat = L3_CDR; -+ SASCR = SASCR_RDD; -+ return dat; -+} -+ -+static void l3_sa1111_recv_msg(struct l3_msg *msg) -+{ -+ int len = msg->len; -+ char *p = msg->buf; -+ -+ if (len > 1) { -+ SACR1 |= SACR1_L3MB; -+ while ((len--) > 1) -+ *p++ = l3_sa1111_recv_byte(msg->addr); -+ } -+ SACR1 &= ~SACR1_L3MB; -+ *p = l3_sa1111_recv_byte(msg->addr); -+} -+ -+static inline void l3_sa1111_send_byte(unsigned char addr, unsigned char dat) -+{ -+ L3_CAR = addr; -+ L3_CDR = dat; -+ while ((SASR0 & SASR0_L3WD) == 0) -+ mdelay(1); -+ SASCR = SASCR_DTS; -+} -+ -+static void l3_sa1111_send_msg(struct l3_msg *msg) -+{ -+ int len = msg->len; -+ char *p = msg->buf; -+ -+ if (len > 1) { -+ SACR1 |= SACR1_L3MB; -+ while ((len--) > 1) -+ l3_sa1111_send_byte(msg->addr, *p++); -+ } -+ SACR1 &= ~SACR1_L3MB; -+ l3_sa1111_send_byte(msg->addr, *p); -+} -+ -+static int l3_sa1111_xfer(struct l3_adapter *adap, struct l3_msg msgs[], int num) -+{ -+ int i; -+ -+ for (i = 0; i < num; i++) { -+ struct l3_msg *pmsg = &msgs[i]; -+ -+ if (pmsg->flags & L3_M_RD) -+ l3_sa1111_recv_msg(pmsg); -+ else -+ l3_sa1111_send_msg(pmsg); -+ } -+ -+ return num; -+} -+ -+static struct l3_algorithm l3_sa1111_algo = { -+ name: "L3 SA1111 algorithm", -+ xfer: l3_sa1111_xfer, -+}; -+ -+static DECLARE_MUTEX(sa1111_lock); -+ -+static struct l3_adapter l3_sa1111_adapter = { -+ owner: THIS_MODULE, -+ name: "l3-sa1111", -+ algo: &l3_sa1111_algo, -+ lock: &sa1111_lock, -+}; -+ -+static int __init l3_sa1111_init(void) -+{ -+ int ret = -ENODEV; -+ if ((machine_is_assabet() && machine_has_neponset()) || -+ machine_is_jornada720() || machine_is_accelent_sa() || -+ machine_is_badge4()) -+ ret = l3_add_adapter(&l3_sa1111_adapter); -+ return ret; -+} -+ -+static void __exit l3_sa1111_exit(void) -+{ -+ l3_del_adapter(&l3_sa1111_adapter); -+} -+ -+module_init(l3_sa1111_init); -+module_exit(l3_sa1111_exit); -diff -urN linux-2.4.26/drivers/media/video/Config.in linux-2.4.26-vrs1/drivers/media/video/Config.in ---- linux-2.4.26/drivers/media/video/Config.in 2004-04-19 11:44:16.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/media/video/Config.in 2004-04-19 10:36:42.000000000 +0100 -@@ -52,5 +52,8 @@ - if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_HIGHMEM64G" != "y" ]; then - dep_tristate ' Sony Vaio Picturebook Motion Eye Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_MEYE $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_SONYPI - fi -+# unfortunately, this depends on having CONFIG_FB_CYBER2000 -+# set as well - we hook off of the VGA driver -+dep_tristate ' NetWinder Video for Linux (EXPERIMENTAL)' CONFIG_VIDEO_CYBERPRO $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL $CONFIG_ARCH_NETWINDER - - endmenu -diff -urN linux-2.4.26/drivers/media/video/Makefile linux-2.4.26-vrs1/drivers/media/video/Makefile ---- linux-2.4.26/drivers/media/video/Makefile 2004-02-27 20:03:25.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/media/video/Makefile 2004-02-23 22:56:20.000000000 +0000 -@@ -16,7 +16,7 @@ - obj-n := - obj- := - --SUB_DIRS := -+SUB_DIRS := - MOD_SUB_DIRS := $(SUB_DIRS) - ALL_SUB_DIRS := $(SUB_DIRS) - -@@ -47,7 +47,8 @@ - obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o i2c-old.o - obj-$(CONFIG_VIDEO_ZORAN_BUZ) += saa7111.o saa7185.o - obj-$(CONFIG_VIDEO_ZORAN_DC10) += saa7110.o adv7175.o --obj-$(CONFIG_VIDEO_ZORAN_LML33) += bt819.o bt856.o -+obj-$(CONFIG_VIDEO_CYBERPRO) += cyberpro.o i2c-old.o saa7111.o -+obj-$(CONFIG_VIDEO_LML33) += bt856.o bt819.o - obj-$(CONFIG_VIDEO_PMS) += pms.o - obj-$(CONFIG_VIDEO_PLANB) += planb.o - obj-$(CONFIG_VIDEO_VINO) += saa7191.o indycam.o vino.o -diff -urN linux-2.4.26/drivers/media/video/cyberpro.c linux-2.4.26-vrs1/drivers/media/video/cyberpro.c ---- linux-2.4.26/drivers/media/video/cyberpro.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/media/video/cyberpro.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,2091 @@ -+/* -+ * CyberPro 2000 video capture driver for the Rebel.com NetWinder -+ * -+ * (C) 1999-2000 Russell King -+ * -+ * Re-written from Rebel.com's vidcap driver. -+ * -+ * Architecture -+ * ------------ -+ * The NetWinder video capture consists of a SAA7111 video decoder chip -+ * connected to the CyberPro feature bus. The video data is captured to -+ * the VGA memory, where the CyberPro can overlay (by chromakeying) the -+ * data onto the VGA display. -+ * -+ * The CyberPro also has some nifty features, including a second overlay -+ * and picture in picture mode. We do not currently use these features. -+ * -+ * Power Saving -+ * ------------ -+ * Please note that rev.5 NetWinders have the ability to hold the SAA7111 -+ * decoder chip into reset, which saves power. The only time at which -+ * this is done is when the driver is unloaded, which implies that this -+ * is compiled as a module. -+ * -+ * In this case, you will want the kernel to automatically load this -+ * driver when required. Place the following line in /etc/modules.conf -+ * to enable this: -+ * -+ * alias char-major-81-0 cyberpro -+ * -+ * The relevant modules will be automatically loaded by modprobe on a -+ * as and when needed basis. -+ * -+ * Capture resolution -+ * ------------------ -+ * The maximum useful capture resolution is: -+ * 625-line UK: 716x576 -+ * 525-line US: ? -+ * -+ * Bugs -+ * ---- -+ * 1. The CyberPro chip seems to be prone to randomly scribbling over VGA -+ * memory [hopefully fixed with new capture enable/freeze stuff] -+ * 2. read()ing pauses video capture, and sometimes triggers bug 1. -+ * 3. mmap() is not supported (requires BM-DMA - see bug 4) -+ * 4. Really, we want to do scatter BM-DMA. Is the CyberPro capable of this? -+ * The Cyberpro seems to randomly scribble to various PCI addresses if you -+ * transfer >16 words. -+ * 5. We shouldn't ignore O_NONBLOCK when reading a frame. -+ * 6. The incoming stream on the NetWinder is CCIR656, which is YUV422. -+ * CyberPro docs also call the format we capture and overlay "YUV422", -+ * but we actually seem to have Y, U, Y, V bytes (is this YUYV format?) -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+MODULE_AUTHOR("Russell King "); -+MODULE_DESCRIPTION("CyberPro v4l video grabber"); -+MODULE_LICENSE("GPL"); -+ -+#include "../../video/cyber2000fb.h" -+ -+/* -+ * These enable various experimental features. Most of these -+ * are just plain broken or just don't work at the moment. -+ */ -+/* -+ * Enable this if you want mmap() access. (see bug 4) -+ */ -+#undef USE_MMAP -+ -+/* -+ * Enable this if you want mmio access. (slow) -+ */ -+#define USE_MMIO -+ -+/* -+ * The V4L API is unclear whether VIDIOCSCAPTURE call is allowed while -+ * capture is running. The default is to disallow the call. -+ * -+ * Define this if you do want to allow the call while capture is active. -+ */ -+#undef ALLOW_SCAPTURE_WHILE_CAP -+ -+/* -+ * We capture two frames -+ */ -+#define NR_FRAMES 2 -+ -+/* -+ * One frame of video is 202 pages, assuming YUV422 format, 716x576 -+ */ -+#define NR_PAGES 202 -+ -+struct src_info { -+ unsigned int offset; /* offset of source data */ -+ unsigned int x; /* source x */ -+ unsigned int y; /* source y */ -+ unsigned int width; /* source width */ -+ unsigned int height; /* source height */ -+ unsigned int format; /* source format */ -+}; -+ -+struct dst_info { -+ unsigned int x; /* destination x */ -+ unsigned int y; /* destination y */ -+ unsigned int width; /* destination width */ -+ unsigned int height; /* destination height */ -+ unsigned int chromakey; /* chromakey */ -+ unsigned int flags; /* flags (eg, chromakey enable) */ -+}; -+ -+struct cyberpro_vidinfo; -+ -+struct win_info { -+ void (*init)(struct cyberpro_vidinfo *dp, struct win_info *wi); -+ void (*set_src)(struct cyberpro_vidinfo *dp, struct win_info *wi); -+ void (*set_win)(struct cyberpro_vidinfo *dp, struct win_info *wi); -+ void (*ctl)(struct cyberpro_vidinfo *dp, struct win_info *wi, int on_off); -+ -+ /* public */ -+ struct src_info src; -+ struct dst_info dst; -+ -+ /* private */ -+ unsigned short vid_fifo_ctl; -+ unsigned char vid_fmt; -+ unsigned char vid_disp_ctl1; -+ unsigned char vid_fifo_ctl1; -+ unsigned char vid_misc_ctl1; -+}; -+ -+struct framebuf { -+ unsigned int offset; /* mmap offset for this frame */ -+ unsigned int status; -+#define FRAME_FREE 0 -+#define FRAME_DONE 1 -+#define FRAME_WAITING 2 -+#define FRAME_GRABBING 3 -+ -+ /* -+ * Bus-Master DMA stuff. Note that we should -+ * probably use the kiovec stuff instead. -+ */ -+ unsigned long bus_addr[NR_PAGES]; /* list of pages */ -+ struct page *pages[NR_PAGES]; -+ void *buffer; -+ int dbg; -+}; -+ -+struct cyberpro_vidinfo { -+ struct video_device *dev; -+ struct i2c_bus *bus; -+ struct cyberpro_info info; /* host information */ -+ unsigned char *regs; -+ unsigned int irq; /* PCI interrupt number */ -+ -+ /* hardware configuration */ -+ unsigned int stream_fmt; /* format of stream from decoder*/ -+ -+ /* software settings */ -+ unsigned int decoder:1; /* decoder loaded */ -+ unsigned int interlace:1; /* interlace */ -+ unsigned int buf_set:1; /* VIDIOCSFBUF has been issued */ -+ unsigned int win_set:1; /* VIDIOCSWIN has been issued */ -+ unsigned int cap_active:1; /* capture is active */ -+ unsigned int ovl_active:1; /* overlay is active */ -+ unsigned int mmaped:1; /* buffer is mmap()d */ -+ unsigned int unused:25; -+ -+ unsigned int users; /* number of users */ -+ unsigned long cap_mem_offset; /* capture framebuffer offset */ -+ void * buffer; /* kernel capture buffer */ -+ unsigned int norm; /* video standard */ -+ -+ struct video_capability cap; /* capabilities */ -+ struct video_picture pic; /* current picture settings */ -+ struct video_buffer buf; /* display parameters */ -+ struct video_capture capt; /* video capture params */ -+ -+ struct win_info *ovl; /* overlay window set */ -+ struct win_info ext; /* "Extended" window info */ -+ struct win_info v2; /* "V2" window info */ -+ struct win_info x2; /* "X2" window info */ -+ -+ unsigned int bm_offset; /* Cap memory bus master offset */ -+ unsigned int bm_index; /* Cap page index */ -+ -+#ifdef USE_MMAP -+ unsigned int frame_idx; /* currently grabbing frame */ -+ unsigned int frame_size; -+ struct framebuf frame[NR_FRAMES]; -+ wait_queue_head_t frame_wait; -+#endif -+ -+ wait_queue_head_t vbl_wait; -+ -+ /* -+ * cyberpro registers -+ */ -+ unsigned char cap_mode1; -+ unsigned char cap_mode2; -+ unsigned char cap_miscctl; -+ unsigned char vfac1; -+ unsigned char vfac3; -+}; -+ -+/* -+ * Our access methods. -+ */ -+#define cyberpro_writel(val,reg,dp) writel(val, (dp)->regs + (reg)) -+#define cyberpro_writew(val,reg,dp) writew(val, (dp)->regs + (reg)) -+#define cyberpro_writeb(val,reg,dp) writeb(val, (dp)->regs + (reg)) -+ -+#define cyberpro_readb(reg,dp) readb((dp)->regs + (reg)) -+ -+static inline void -+cyberpro_grphw(unsigned int reg, unsigned int val, struct cyberpro_vidinfo *dp) -+{ -+ cyberpro_writew((reg & 255) | val << 8, 0x3ce, dp); -+} -+ -+static void cyberpro_grphw8(unsigned int reg, unsigned int val, struct cyberpro_vidinfo *dp) -+{ -+ cyberpro_grphw(reg, val, dp); -+} -+ -+static unsigned char cyberpro_grphr8(int reg, struct cyberpro_vidinfo *dp) -+{ -+ cyberpro_writeb(reg, 0x3ce, dp); -+ return cyberpro_readb(0x3cf, dp); -+} -+ -+static void cyberpro_grphw16(int reg, unsigned int val, struct cyberpro_vidinfo *dp) -+{ -+ cyberpro_grphw(reg, val, dp); -+ cyberpro_grphw(reg + 1, val >> 8, dp); -+} -+ -+static void cyberpro_grphw24(int reg, unsigned int val, struct cyberpro_vidinfo *dp) -+{ -+ cyberpro_grphw(reg, val, dp); -+ cyberpro_grphw(reg + 1, val >> 8, dp); -+ cyberpro_grphw(reg + 2, val >> 16, dp); -+} -+ -+#if 0 -+static void -+cyberpro_dbg_dump(void) -+{ -+ int i; -+ unsigned char idx[] = -+ { 0x30, 0x3e, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, -+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad }; -+ printk(KERN_DEBUG); -+ for (i = 0; i < sizeof(idx); i++) -+ printk("%02x ", idx[i]); -+ printk("\n" KERN_DEBUG); -+ for (i = 0; i < sizeof(idx); i++) -+ printk("%02x ", cyberpro_grphr8(idx[i])); -+ printk("\n"); -+} -+#endif -+ -+/* -+ * On the NetWinder, we can put the SAA7111 to sleep by holding -+ * it in reset. -+ * -+ * Note: once we have initialised the SAA7111, we can't put it back to -+ * sleep and expect it to keep its settings. Maybe a better solution -+ * is to register/de-register the i2c bus in open/release? -+ */ -+static void -+decoder_sleep(int sleep) -+{ -+#ifdef CONFIG_ARCH_NETWINDER -+ extern spinlock_t gpio_lock; -+ -+ spin_lock_irq(&gpio_lock); -+ cpld_modify(CPLD_7111_DISABLE, sleep ? CPLD_7111_DISABLE : 0); -+ spin_unlock_irq(&gpio_lock); -+ -+ if (!sleep) { -+ /* -+ * wait 20ms for device to wake up -+ */ -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ schedule_timeout(HZ / 50); -+ } -+#endif -+} -+ -+/* -------------------------------- I2C support ---------------------------- */ -+ -+#define I2C_DELAY 100 -+ -+static void -+cyberpro_i2c_setlines(struct i2c_bus *bus, int ctrl, int data) -+{ -+ struct cyberpro_vidinfo *dp = bus->data; -+ int v; -+ -+ v = (ctrl ? EXT_LATCH2_I2C_CLKEN : 0x00) | (data ? EXT_LATCH2_I2C_DATEN : 0x00); -+ cyberpro_grphw8(EXT_LATCH2, v, dp); -+ -+ udelay(I2C_DELAY); -+} -+ -+static int -+cyberpro_i2c_getdataline(struct i2c_bus *bus) -+{ -+ struct cyberpro_vidinfo *dp = bus->data; -+ unsigned long flags; -+ int v; -+ -+ save_flags(flags); -+ cli(); -+ -+ v = cyberpro_grphr8(EXT_LATCH2, dp); -+ -+ restore_flags(flags); -+ -+ return v & EXT_LATCH2_I2C_DAT ? 1 : 0; -+} -+ -+static void -+cyberpro_i2c_attach(struct i2c_bus *bus, int id) -+{ -+ struct cyberpro_vidinfo *dp = bus->data; -+ int zero = 0; -+ -+ if (id == I2C_DRIVERID_VIDEODECODER) { -+ __u16 norm = dp->norm; -+ i2c_control_device(bus, id, DECODER_SET_NORM, &norm); -+ i2c_control_device(bus, id, DECODER_SET_PICTURE, &dp->pic); -+ i2c_control_device(bus, id, DECODER_ENABLE_OUTPUT, &zero); -+ -+ dp->decoder = 1; -+ } -+} -+ -+static void -+cyberpro_i2c_detach(struct i2c_bus *bus, int id) -+{ -+ struct cyberpro_vidinfo *dp = bus->data; -+ -+ if (id == I2C_DRIVERID_VIDEODECODER) -+ dp->decoder = 0; -+} -+ -+static struct i2c_bus cyberpro_i2c_bus = { -+ name: "", -+ id: I2C_BUSID_CYBER2000, -+ bus_lock: SPIN_LOCK_UNLOCKED, -+ attach_inform: cyberpro_i2c_attach, -+ detach_inform: cyberpro_i2c_detach, -+ i2c_setlines: cyberpro_i2c_setlines, -+ i2c_getdataline: cyberpro_i2c_getdataline, -+}; -+ -+/*------------------------- Extended Overlay Window ------------------------- -+ * Initialise 1st overlay window (works) -+ */ -+static void -+cyberpro_ext_init(struct cyberpro_vidinfo *dp, struct win_info *wi) -+{ -+ wi->vid_fifo_ctl = 0xf87c; -+ wi->vid_fmt = EXT_VID_FMT_YUV422; -+ wi->vid_disp_ctl1 = EXT_VID_DISP_CTL1_VINTERPOL_OFF | -+ EXT_VID_DISP_CTL1_NOCLIP; -+ wi->vid_fifo_ctl1 = EXT_VID_FIFO_CTL1_INTERLEAVE | -+ EXT_VID_FIFO_CTL1_OE_HIGH; -+ wi->vid_misc_ctl1 = 0; -+ -+ cyberpro_grphw8 (EXT_VID_DISP_CTL1, wi->vid_disp_ctl1, dp); -+ cyberpro_grphw16(EXT_DDA_X_INIT, 0x0800, dp); -+ cyberpro_grphw16(EXT_DDA_Y_INIT, 0x0800, dp); -+ cyberpro_grphw16(EXT_VID_FIFO_CTL, wi->vid_fifo_ctl, dp); -+ cyberpro_grphw8 (EXT_VID_FIFO_CTL1, wi->vid_fifo_ctl1, dp); -+} -+ -+/* -+ * Set the source parameters for the extended window -+ */ -+static void -+cyberpro_ext_set_src(struct cyberpro_vidinfo *dp, struct win_info *wi) -+{ -+ unsigned int phase, pitch; -+ -+ pitch = (wi->src.width >> 2) & 0x0fff; -+ phase = (wi->src.width + 3) >> 2; -+ -+ wi->vid_fmt &= ~7; -+ switch (wi->src.format) { -+ case VIDEO_PALETTE_RGB565: wi->vid_fmt |= EXT_VID_FMT_RGB565; break; -+ case VIDEO_PALETTE_RGB24: wi->vid_fmt |= EXT_VID_FMT_RGB888_24; break; -+ case VIDEO_PALETTE_RGB32: wi->vid_fmt |= EXT_VID_FMT_RGB888_32; break; -+ case VIDEO_PALETTE_RGB555: wi->vid_fmt |= EXT_VID_FMT_RGB555; break; -+ case VIDEO_PALETTE_YUV422: wi->vid_fmt |= EXT_VID_FMT_YUV422; break; -+ } -+ -+ cyberpro_grphw24(EXT_MEM_START, wi->src.offset, dp); -+ cyberpro_grphw16(EXT_SRC_WIDTH, pitch | ((phase << 4) & 0xf000), dp); -+ cyberpro_grphw8 (EXT_SRC_WIN_WIDTH, phase, dp); -+ cyberpro_grphw8 (EXT_VID_FMT, wi->vid_fmt, dp); -+} -+ -+/* -+ * Set overlay1 window -+ */ -+static void -+cyberpro_ext_set_win(struct cyberpro_vidinfo *dp, struct win_info *wi) -+{ -+ unsigned int xscale, yscale; -+ unsigned int xoff, yoff; -+ -+ /* -+ * Note: the offset does not appear to be influenced by -+ * hardware scrolling. -+ */ -+ xoff = yoff = 0; -+ -+ xoff += wi->dst.x; -+ yoff += wi->dst.y; -+ -+ xscale = wi->src.width; -+ -+ if (wi->dst.width >= wi->src.width * 2) { -+ wi->vid_fmt |= EXT_VID_FMT_DBL_H_PIX; -+ xscale *= 2; -+ } else { -+ wi->vid_fmt &= ~EXT_VID_FMT_DBL_H_PIX; -+ } -+ -+ xscale = ((xscale - /*2*/0) * 4096) / wi->dst.width; -+ yscale = ((wi->src.height - /*2*/0) * 4096) / wi->dst.height; -+ -+ cyberpro_grphw16(EXT_X_START, xoff, dp); -+ cyberpro_grphw16(EXT_X_END, xoff + wi->dst.width, dp); -+ cyberpro_grphw16(EXT_Y_START, yoff, dp); -+ cyberpro_grphw16(EXT_Y_END, yoff + wi->dst.height, dp); -+ cyberpro_grphw24(EXT_COLOUR_COMPARE, wi->dst.chromakey, dp); -+ cyberpro_grphw16(EXT_DDA_X_INC, xscale, dp); -+ cyberpro_grphw16(EXT_DDA_Y_INC, yscale, dp); -+ cyberpro_grphw8(EXT_VID_FMT, wi->vid_fmt, dp); -+ -+ if (wi->dst.flags & VIDEO_WINDOW_CHROMAKEY) -+ wi->vid_disp_ctl1 &= ~EXT_VID_DISP_CTL1_IGNORE_CCOMP; -+ else -+ wi->vid_disp_ctl1 |= EXT_VID_DISP_CTL1_IGNORE_CCOMP; -+} -+ -+/* -+ * Enable or disable the 1st overlay window. Note that for anything -+ * useful to be displayed, we must have capture enabled. -+ */ -+static void -+cyberpro_ext_ctl(struct cyberpro_vidinfo *dp, struct win_info *wi, int on) -+{ -+ if (on) -+ wi->vid_disp_ctl1 |= EXT_VID_DISP_CTL1_ENABLE_WINDOW; -+ else -+ wi->vid_disp_ctl1 &= ~EXT_VID_DISP_CTL1_ENABLE_WINDOW; -+ -+ cyberpro_grphw8(EXT_VID_DISP_CTL1, wi->vid_disp_ctl1, dp); -+} -+ -+/*------------------------------- V2 Overlay Window ------------------------- -+ * Initialise 2nd overlay window (guesswork) -+ */ -+static void -+cyberpro_v2_init(struct cyberpro_vidinfo *dp, struct win_info *wi) -+{ -+ wi->vid_fifo_ctl = 0xf87c; -+ wi->vid_fmt = EXT_VID_FMT_YUV422; -+ wi->vid_disp_ctl1 = EXT_VID_DISP_CTL1_VINTERPOL_OFF | -+ EXT_VID_DISP_CTL1_NOCLIP; -+ wi->vid_fifo_ctl1 = 0x06; -+ wi->vid_misc_ctl1 = 0; -+ -+ cyberpro_grphw8(REG_BANK, REG_BANK_Y, dp); -+ cyberpro_grphw8 (Y_V2_VID_DISP_CTL1, wi->vid_disp_ctl1, dp); -+ /* No DDA init values */ -+ cyberpro_grphw16(Y_V2_VID_FIFO_CTL, wi->vid_fifo_ctl, dp); -+ cyberpro_grphw8 (Y_V2_VID_FIFO_CTL1, wi->vid_fifo_ctl1, dp); -+} -+ -+/* -+ * Set the source parameters for the v2 window -+ */ -+static void -+cyberpro_v2_set_src(struct cyberpro_vidinfo *dp, struct win_info *wi) -+{ -+ unsigned int phase, pitch; -+ -+ pitch = (wi->src.width >> 2) & 0x0fff; -+ phase = (wi->src.width + 3) >> 2; -+ -+ wi->vid_fmt &= ~7; -+ switch (wi->src.format) { -+ case VIDEO_PALETTE_RGB565: wi->vid_fmt |= EXT_VID_FMT_RGB565; break; -+ case VIDEO_PALETTE_RGB24: wi->vid_fmt |= EXT_VID_FMT_RGB888_24; break; -+ case VIDEO_PALETTE_RGB32: wi->vid_fmt |= EXT_VID_FMT_RGB888_32; break; -+ case VIDEO_PALETTE_RGB555: wi->vid_fmt |= EXT_VID_FMT_RGB555; break; -+ case VIDEO_PALETTE_YUV422: wi->vid_fmt |= EXT_VID_FMT_YUV422; break; -+ } -+ -+ cyberpro_grphw8(REG_BANK, REG_BANK_X, dp); -+ cyberpro_grphw24(X_V2_VID_MEM_START, wi->src.offset, dp); -+ cyberpro_grphw16(X_V2_VID_SRC_WIDTH, pitch | ((phase << 4) & 0xf000), dp); -+ cyberpro_grphw8 (X_V2_VID_SRC_WIN_WIDTH, phase, dp); -+ -+ cyberpro_grphw8(REG_BANK, REG_BANK_Y, dp); -+ cyberpro_grphw8(Y_V2_VID_FMT, wi->vid_fmt, dp); -+} -+ -+/* -+ * Set v2 window -+ */ -+static void -+cyberpro_v2_set_win(struct cyberpro_vidinfo *dp, struct win_info *wi) -+{ -+ unsigned int xscale, yscale; -+ unsigned int xoff, yoff; -+ -+ /* -+ * Note: the offset does not appear to be influenced by -+ * hardware scrolling. -+ */ -+ xoff = yoff = 0; -+ -+ xoff += wi->dst.x; -+ yoff += wi->dst.y; -+ -+ xscale = (wi->src.width * 4096) / wi->dst.width; -+ yscale = (wi->src.height * 4096) / wi->dst.height; -+ -+ cyberpro_grphw8(REG_BANK, REG_BANK_X, dp); -+ cyberpro_grphw16(X_V2_X_START, xoff, dp); -+ cyberpro_grphw16(X_V2_X_END, xoff + wi->dst.width, dp); -+ cyberpro_grphw16(X_V2_Y_START, yoff, dp); -+ cyberpro_grphw16(X_V2_Y_END, yoff + wi->dst.height, dp); -+ -+ cyberpro_grphw8(REG_BANK, REG_BANK_Y, dp); -+ cyberpro_grphw16(Y_V2_DDA_X_INC, xscale, dp); -+ cyberpro_grphw16(Y_V2_DDA_Y_INC, yscale, dp); -+} -+ -+/* -+ * Enable or disable the 2nd overlay window. Note that for anything -+ * useful to be displayed, we must have capture enabled. -+ */ -+static void -+cyberpro_v2_ctl(struct cyberpro_vidinfo *dp, struct win_info *wi, int on) -+{ -+ if (on) -+ wi->vid_disp_ctl1 |= EXT_VID_DISP_CTL1_ENABLE_WINDOW; -+ else -+ wi->vid_disp_ctl1 &= ~EXT_VID_DISP_CTL1_ENABLE_WINDOW; -+ -+ cyberpro_grphw8(REG_BANK, REG_BANK_Y, dp); -+ cyberpro_grphw8(Y_V2_VID_DISP_CTL1, wi->vid_disp_ctl1, dp); -+} -+ -+/*--------------------------- X2 Overlay Window ----------------------------- -+ * Initialise 3rd overlay window (guesswork) -+ */ -+static void -+cyberpro_x2_init(struct cyberpro_vidinfo *dp, struct win_info *wi) -+{ -+ wi->vid_fmt = EXT_VID_FMT_YUV422; -+ wi->vid_disp_ctl1 = 0x40; -+ wi->vid_misc_ctl1 = 0; -+ -+ cyberpro_grphw8(REG_BANK, REG_BANK_K, dp); -+ cyberpro_grphw8 (K_X2_VID_DISP_CTL1, wi->vid_disp_ctl1, dp); -+ cyberpro_grphw16(K_X2_DDA_X_INIT, 0x0800, dp); -+ cyberpro_grphw16(K_X2_DDA_Y_INIT, 0x0800, dp); -+} -+ -+/* -+ * Set the source parameters for the x2 window -+ */ -+static void -+cyberpro_x2_set_src(struct cyberpro_vidinfo *dp, struct win_info *wi) -+{ -+ unsigned int phase, pitch; -+ -+ pitch = (wi->src.width >> 2) & 0x0fff; -+ phase = (wi->src.width + 3) >> 2; -+ -+ wi->vid_fmt &= ~7; -+ switch (wi->src.format) { -+ case VIDEO_PALETTE_RGB565: wi->vid_fmt |= EXT_VID_FMT_RGB565; break; -+ case VIDEO_PALETTE_RGB24: wi->vid_fmt |= EXT_VID_FMT_RGB888_24; break; -+ case VIDEO_PALETTE_RGB32: wi->vid_fmt |= EXT_VID_FMT_RGB888_32; break; -+ case VIDEO_PALETTE_RGB555: wi->vid_fmt |= EXT_VID_FMT_RGB555; break; -+ case VIDEO_PALETTE_YUV422: wi->vid_fmt |= EXT_VID_FMT_YUV422; break; -+ } -+ -+ cyberpro_grphw8(REG_BANK, REG_BANK_J, dp); -+ cyberpro_grphw24(J_X2_VID_MEM_START, wi->src.offset, dp); -+ cyberpro_grphw16(J_X2_VID_SRC_WIDTH, pitch | ((phase << 4) & 0xf000), dp); -+ cyberpro_grphw8 (J_X2_VID_SRC_WIN_WIDTH, phase, dp); -+ -+ cyberpro_grphw8(REG_BANK, REG_BANK_K, dp); -+ cyberpro_grphw8(K_X2_VID_FMT, wi->vid_fmt, dp); -+} -+ -+/* -+ * Set x2 window -+ */ -+static void -+cyberpro_x2_set_win(struct cyberpro_vidinfo *dp, struct win_info *wi) -+{ -+ unsigned int xscale, yscale; -+ unsigned int xoff, yoff; -+ -+ /* -+ * Note: the offset does not appear to be influenced by -+ * hardware scrolling. -+ */ -+ xoff = yoff = 0; -+ -+ xoff += wi->dst.x; -+ yoff += wi->dst.y; -+ -+ xscale = (wi->src.width * 4096) / wi->dst.width; -+ yscale = (wi->src.height * 4096) / wi->dst.height; -+ -+ cyberpro_grphw8(REG_BANK, REG_BANK_J, dp); -+ cyberpro_grphw16(J_X2_X_START, xoff, dp); -+ cyberpro_grphw16(J_X2_X_END, xoff + wi->dst.width, dp); -+ cyberpro_grphw16(J_X2_Y_START, yoff, dp); -+ cyberpro_grphw16(J_X2_Y_END, yoff + wi->dst.height, dp); -+ -+ cyberpro_grphw8(REG_BANK, REG_BANK_K, dp); -+ cyberpro_grphw16(K_X2_DDA_X_INC, xscale, dp); -+ cyberpro_grphw16(K_X2_DDA_Y_INC, yscale, dp); -+} -+ -+/* -+ * Enable or disable the 3rd overlay window. Note that for anything -+ * useful to be displayed, we must have capture enabled. -+ */ -+static void -+cyberpro_x2_ctl(struct cyberpro_vidinfo *dp, struct win_info *wi, int on) -+{ -+ if (on) -+ wi->vid_disp_ctl1 |= EXT_VID_DISP_CTL1_ENABLE_WINDOW; -+ else -+ wi->vid_disp_ctl1 &= ~EXT_VID_DISP_CTL1_ENABLE_WINDOW; -+ -+ cyberpro_grphw8(REG_BANK, REG_BANK_K, dp); -+ cyberpro_grphw8(K_X2_VID_DISP_CTL1, wi->vid_disp_ctl1, dp); -+} -+ -+/* ------------------------------------------------------------------------- */ -+ -+#if 0 -+static void reset_seq(struct cyberpro_vidinfo *dp) -+{ -+ unsigned char ext_mem_ctl = cyberpro_grphr8(0x70, dp); -+ -+ cyberpro_grphw8(ext_mem_ctl | 0x80, 0x70, dp); -+ cyberpro_grphw8(ext_mem_ctl, 0x70, dp); -+} -+#endif -+ -+#ifdef USE_MMAP -+/* -+ * Buffer support -+ */ -+static int -+cyberpro_alloc_frame_buffer(struct cyberpro_vidinfo *dp, -+ struct framebuf *frame) -+{ -+ unsigned long addr; -+ void *buffer; -+ int pgidx; -+ -+ if (frame->buffer) -+ return 0; -+ -+ /* -+ * Allocate frame buffer -+ */ -+ buffer = vmalloc(NR_PAGES * PAGE_SIZE); -+ -+ if (frame->buffer) { -+ vfree(buffer); -+ return 0; -+ } -+ -+ if (!buffer) -+ return -ENOMEM; -+ -+ printk("Buffer allocated @ %p [", buffer); -+ -+ frame->buffer = buffer; -+ frame->dbg = 1; -+ -+ /* -+ * Don't leak information from the kernel. -+ */ -+ memset(buffer, 0x5a, NR_PAGES * PAGE_SIZE); -+ -+ /* -+ * Now, reserve all the pages, and calculate -+ * each pages' bus address. -+ */ -+ addr = (unsigned long)buffer; -+ for (pgidx = 0; pgidx < NR_PAGES; pgidx++, addr += PAGE_SIZE) { -+ struct page *page; -+ pgd_t *pgd; -+ pmd_t *pmd; -+ pte_t *pte; -+ -+ /* -+ * The page should be present. If not, -+ * vmalloc has gone nuts. -+ */ -+ pgd = pgd_offset_k(addr); -+ if (pgd_none(*pgd)) -+ BUG(); -+ pmd = pmd_offset(pgd, addr); -+ if (pmd_none(*pmd)) -+ BUG(); -+ pte = pte_offset(pmd, addr); -+ if (!pte_present(*pte)) -+ BUG(); -+ -+ page = pte_page(*pte); -+ -+ frame->bus_addr[pgidx] = virt_to_bus((void *)page_address(page)); -+ frame->pages[pgidx] = page; -+ SetPageReserved(page); -+ -+ printk("%08lx (%08lx) ", page_address(page), frame->bus_addr[pgidx]); -+ } -+ printk("\n"); -+ -+ return 0; -+} -+ -+static void -+cyberpro_frames_free_one(struct cyberpro_vidinfo *dp, struct framebuf *frame) -+{ -+ void *buffer; -+ int pgidx; -+ -+ frame->status = FRAME_FREE; -+ buffer = frame->buffer; -+ frame->buffer = NULL; -+ -+ if (buffer) { -+ for (pgidx = 0; pgidx < NR_PAGES; pgidx++) { -+ frame->bus_addr[pgidx] = 0; -+ ClearPageReserved(frame->pages[pgidx]); -+ frame->pages[pgidx] = NULL; -+ } -+ vfree(buffer); -+ } -+} -+ -+static void -+cyberpro_busmaster_frame(struct cyberpro_vidinfo *dp, struct framebuf *frame) -+{ -+ unsigned long bus_addr; -+ -+ bus_addr = frame->bus_addr[dp->bm_index]; -+ -+ if (frame->dbg) { -+ printk("Frame%d: %06x -> %08lx\n", -+ dp->frame_idx, -+ dp->bm_offset, -+ bus_addr); -+ } -+ -+ cyber2000_outw(dp->bm_offset, BM_VID_ADDR_LOW); -+ cyber2000_outw(dp->bm_offset >> 16, BM_VID_ADDR_HIGH); -+ -+ cyber2000_outw(bus_addr, BM_ADDRESS_LOW); -+ cyber2000_outw(bus_addr >> 16, BM_ADDRESS_HIGH); -+ -+ /* -+ * One page-full only -+ */ -+ cyber2000_outw(1023, BM_LENGTH); -+ -+ /* -+ * Load length -+ */ -+ cyber2000_outw(BM_CONTROL_INIT, BM_CONTROL); -+ -+ /* -+ * Enable transfer -+ */ -+ cyber2000_outw(BM_CONTROL_ENABLE|BM_CONTROL_IRQEN, BM_CONTROL); -+ -+ dp->bm_offset += 1024; -+ dp->bm_index += 1; -+} -+ -+static void cyberpro_busmaster_interrupt(struct cyberpro_vidinfo *dp) -+{ -+ struct framebuf *frame = dp->frame + dp->frame_idx; -+ -+ /* -+ * Disable Busmaster operations -+ */ -+ cyber2000_outw(0, BM_CONTROL); -+ -+ if (frame->status == FRAME_GRABBING) { -+ /* -+ * We are still grabbing this frame to system -+ * memory. Transfer next page if there are -+ * more, or else flag this frame as complete. -+ */ -+ if (dp->bm_index < NR_PAGES) -+ cyberpro_busmaster_frame(dp); -+ else { -+ unsigned int idx; -+ -+ frame->status = FRAME_DONE; -+ frame->dbg = 0; -+ -+ idx = dp->frame_idx + 1; -+ if (idx >= NR_FRAMES) -+ idx = 0; -+ -+ dp->frame_idx = idx; -+ -+ wake_up(&dp->frame_wait); -+ } -+ } -+} -+ -+static void cyberpro_frames_vbl(struct cyberpro_vidinfo *dp, unsigned int stat) -+{ -+ struct framebuf *frame = dp->frame + dp->frame_idx; -+ -+ /* -+ * No point capturing frames if the grabber isn't active. -+ */ -+ if (stat & EXT_ROM_UCB4GH_FREEZE) -+ return; -+ -+ /* -+ * If the next buffer is ready for grabbing, -+ * set up the bus master registers for the -+ * transfer. -+ */ -+ if (frame->status == FRAME_WAITING) { -+ frame->status = FRAME_GRABBING; -+ -+ dp->bm_offset = dp->cap_mem_offset; -+ dp->bm_index = 0; -+ -+ cyberpro_busmaster_frame(dp, frame); -+ } -+} -+ -+static void __init cyberpro_frames_init(struct cyberpro_vidinfo *dp) -+{ -+ unsigned int offset, maxsize; -+ int i; -+ -+ init_waitqueue_head(&dp->frame_wait); -+ -+ maxsize = 2 * dp->cap.maxwidth * dp->cap.maxheight; -+ dp->frame_size = PAGE_ALIGN(maxsize); -+ dp->frame_idx = 0; -+ -+ for (i = offset = 0; i < NR_FRAMES; i++) { -+ dp->frame[i].offset = offset; -+ dp->frame[i].status = FRAME_FREE; -+ offset += dp->frame_size; -+ } -+} -+ -+static void cyberpro_frames_free(struct cyberpro_vidinfo *dp) -+{ -+ int i; -+ -+ dp->mmaped = 0; -+ -+ /* -+ * Free all frame buffers -+ */ -+ for (i = 0; i < NR_FRAMES; i++) -+ cyberpro_frames_free_one(dp, dp->frame + i); -+} -+ -+#else -+#define cyberpro_frames_vbl(dp,stat) do { } while (0) -+#define cyberpro_frames_init(dp) do { } while (0) -+#define cyberpro_frames_free(dp) do { } while (0) -+#endif -+ -+/* -+ * CyberPro Interrupts -+ * ------------------- -+ * -+ * We don't really know how to signal an IRQ clear to the chip. However, -+ * disabling and re-enabling the capture interrupt enable seems to do what -+ * we want. -+ */ -+static void cyberpro_interrupt(int nr, void *dev_id, struct pt_regs *regs) -+{ -+ struct cyberpro_vidinfo *dp = dev_id; -+ unsigned char old_grphidx; -+ unsigned int status; -+ -+ /* -+ * Save old graphics index register -+ */ -+ old_grphidx = cyberpro_readb(0x3ce, dp); -+ -+ status = cyberpro_grphr8(EXT_ROM_UCB4GH, dp); -+ -+ /* -+ * Was it due to the Capture VSYNC? -+ */ -+ if (status & EXT_ROM_UCB4GH_INTSTAT) { -+ /* -+ * Frob the IRQ enable bit to drop the request. -+ */ -+ cyberpro_grphw8(VFAC_CTL3, dp->vfac3 & ~VFAC_CTL3_CAP_IRQ, dp); -+ cyberpro_grphw8(VFAC_CTL3, dp->vfac3, dp); -+ -+ cyberpro_frames_vbl(dp, status); -+ wake_up(&dp->vbl_wait); -+ } -+ -+ /* -+ * Restore graphics controller index -+ */ -+ cyberpro_writeb(old_grphidx, 0x3ce, dp); -+ -+#ifdef USE_MMAP -+ /* -+ * Do Bus-Master IRQ stuff -+ */ -+ if (cyber2000_inb(BM_CONTROL) & (1 << 7)) -+ cyberpro_busmaster_interrupt(dp); -+#endif -+} -+ -+static void cyberpro_capture(struct cyberpro_vidinfo *dp, int on) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ unsigned int status; -+ -+ status = cyberpro_grphr8(EXT_ROM_UCB4GH, dp); -+ -+ add_wait_queue(&dp->vbl_wait, &wait); -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ -+ if (!!on ^ !(status & EXT_ROM_UCB4GH_FREEZE)) { -+ if (on) { -+ schedule_timeout(40 * HZ / 1000); -+ dp->vfac1 &= ~(VFAC_CTL1_FREEZE_CAPTURE|VFAC_CTL1_FREEZE_CAPTURE_SYNC); -+ cyberpro_grphw8(VFAC_CTL1, dp->vfac1, dp); -+ -+ status = cyberpro_grphr8(EXT_ROM_UCB4GH, dp); -+ } else { -+ dp->vfac1 |= VFAC_CTL1_FREEZE_CAPTURE_SYNC; -+ cyberpro_grphw8(VFAC_CTL1, dp->vfac1, dp); -+ -+ status = cyberpro_grphr8(EXT_ROM_UCB4GH, dp); -+ if (!(status & EXT_ROM_UCB4GH_FREEZE)) -+ schedule_timeout(40 * HZ / 1000); -+ } -+ } -+ -+ current->state = TASK_RUNNING; -+ remove_wait_queue(&dp->vbl_wait, &wait); -+} -+ -+static void cyberpro_capture_one(struct cyberpro_vidinfo *dp) -+{ -+ struct task_struct *tsk = current; -+ DECLARE_WAITQUEUE(wait, tsk); -+ unsigned int status; -+ unsigned long policy, rt_priority; -+ -+ policy = tsk->policy; -+ rt_priority = tsk->rt_priority; -+ -+ tsk->policy = SCHED_FIFO; -+ tsk->rt_priority = 1; -+ -+ status = cyberpro_grphr8(EXT_ROM_UCB4GH, dp); -+ -+ add_wait_queue(&dp->vbl_wait, &wait); -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ -+ schedule_timeout(40 * HZ / 1000); -+ dp->vfac1 &= ~(VFAC_CTL1_FREEZE_CAPTURE|VFAC_CTL1_FREEZE_CAPTURE_SYNC); -+ cyberpro_grphw8(VFAC_CTL1, dp->vfac1, dp); -+ -+ status = cyberpro_grphr8(EXT_ROM_UCB4GH, dp); -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ schedule_timeout(40 * HZ / 1000); -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ schedule_timeout(40 * HZ / 1000); -+ -+ dp->vfac1 |= VFAC_CTL1_FREEZE_CAPTURE_SYNC; -+ cyberpro_grphw8(VFAC_CTL1, dp->vfac1, dp); -+ -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ status = cyberpro_grphr8(EXT_ROM_UCB4GH, dp); -+ -+ current->state = TASK_RUNNING; -+ remove_wait_queue(&dp->vbl_wait, &wait); -+ -+ tsk->policy = policy; -+ tsk->rt_priority = rt_priority; -+} -+ -+static void cyberpro_capture_set_win(struct cyberpro_vidinfo *dp) -+{ -+ unsigned int xstart, xend, ystart, yend; -+ -+ xstart = 4 + dp->capt.x; -+ xend = xstart + dp->capt.width; -+ -+ if (dp->cap_mode1 & EXT_CAP_MODE1_8BIT) { -+ /* 8-bit capture */ -+ xstart *= 2; -+ xend *= 2; -+ } -+ -+ xstart -= 1; -+ xend -= 1; -+ -+ ystart = 18 + dp->capt.y; -+ yend = ystart + dp->capt.height / 2; -+ -+ cyberpro_grphw16(CAP_X_START, xstart, dp); -+ cyberpro_grphw16(CAP_X_END, xend + 1, dp); -+ cyberpro_grphw16(CAP_Y_START, ystart, dp); -+ cyberpro_grphw16(CAP_Y_END, yend + 2, dp); -+ -+ /* -+ * This should take account of capt.decimation -+ */ -+ cyberpro_grphw16(CAP_DDA_X_INIT, 0x0800, dp); -+ cyberpro_grphw16(CAP_DDA_X_INC, 0x1000, dp); -+ cyberpro_grphw16(CAP_DDA_Y_INIT, 0x0800, dp); -+ cyberpro_grphw16(CAP_DDA_Y_INC, 0x1000, dp); -+ -+ cyberpro_grphw8(CAP_PITCH, dp->capt.width >> 2, dp); -+} -+ -+static void cyberpro_set_interlace(struct cyberpro_vidinfo *dp) -+{ -+ /* -+ * set interlace mode -+ */ -+ if (dp->interlace) { -+ dp->vfac3 |= VFAC_CTL3_CAP_INTERLACE; -+ dp->cap_miscctl &= ~CAP_CTL_MISC_ODDEVEN; -+ dp->ovl->src.height = dp->capt.height; -+ } else { -+ dp->vfac3 &= ~VFAC_CTL3_CAP_INTERLACE; -+ dp->cap_miscctl |= CAP_CTL_MISC_ODDEVEN; -+ dp->ovl->src.height = dp->capt.height / 2; -+ } -+ -+ cyberpro_grphw8(VFAC_CTL3, dp->vfac3, dp); -+ cyberpro_grphw8(CAP_CTL_MISC, dp->cap_miscctl, dp); -+ -+ dp->ovl->set_src(dp, dp->ovl); -+ -+ if (dp->win_set) -+ dp->ovl->set_win(dp, dp->ovl); -+} -+ -+/* -+ * Calculate and set the address of the capture buffer. Note we -+ * also update the extended memory buffer for the overlay window. -+ * -+ * base: phys base address of display -+ * width: pixel width of display -+ * height: height of display -+ * depth: depth of display (8/16/24) -+ * bytesperline: number of bytes on a line -+ * -+ * We place the capture buffer 16K after the screen. -+ */ -+static int -+cyberpro_set_buffer(struct cyberpro_vidinfo *dp, struct video_buffer *b) -+{ -+ unsigned long screensize, maxbufsz; -+ -+ if (b->height <= 0 || b->width <= 0 || b->bytesperline <= 0) -+ return -EINVAL; -+ -+ maxbufsz = dp->cap.maxwidth * dp->cap.maxheight * 2; -+ screensize = b->height * b->bytesperline + 16384; -+ -+ if ((screensize + maxbufsz) >= dp->info.fb_size) -+ return -EINVAL; -+ -+ dp->buf.base = b->base; -+ dp->buf.width = b->width; -+ dp->buf.height = b->height; -+ dp->buf.depth = b->depth; -+ dp->buf.bytesperline = b->bytesperline; -+ dp->cap_mem_offset = screensize >> 2; -+ -+ cyberpro_grphw24(CAP_MEM_START, dp->cap_mem_offset, dp); -+ -+ /* -+ * Setup the overlay source information. -+ */ -+ dp->ovl->src.offset = dp->cap_mem_offset; -+ dp->ovl->set_src(dp, dp->ovl); -+ -+ return 0; -+} -+ -+static void cyberpro_hw_init(struct cyberpro_vidinfo *dp) -+{ -+ unsigned char old; -+ -+ /* -+ * Enable access to bus-master registers -+ */ -+ dp->info.enable_extregs(dp->info.info); -+ -+ dp->vfac1 = VFAC_CTL1_PHILIPS | -+ VFAC_CTL1_FREEZE_CAPTURE | -+ VFAC_CTL1_FREEZE_CAPTURE_SYNC; -+ dp->vfac3 = VFAC_CTL3_CAP_IRQ; -+ -+ dp->cap_miscctl = CAP_CTL_MISC_DISPUSED | -+ CAP_CTL_MISC_SYNCTZOR | -+ CAP_CTL_MISC_SYNCTZHIGH; -+ -+ /* -+ * Setup bus-master mode -+ */ -+ cyberpro_grphw8(BM_CTRL1, 0x88, dp); -+ cyberpro_grphw8(PCI_BM_CTL, PCI_BM_CTL_ENABLE, dp); -+ cyberpro_grphw8(BM_CTRL0, 0x44, dp); -+ cyberpro_grphw8(BM_CTRL1, 0x84, dp); -+ -+ cyberpro_grphw24(CAP_MEM_START, 0, dp); -+ -+ cyberpro_grphw8(VFAC_CTL1, dp->vfac1, dp); -+ cyberpro_grphw8(VFAC_CTL3, dp->vfac3, dp); -+ cyberpro_grphw8(VFAC_CTL2, 0, dp); -+ -+ cyberpro_grphw8(REG_BANK, REG_BANK_Y, dp); -+ cyberpro_grphw8(EXT_TV_CTL, 0x80, dp); -+ -+ cyberpro_grphw8(EXT_CAP_CTL1, 0x3f, dp); /* disable PIP */ -+ cyberpro_grphw8(EXT_CAP_CTL2, 0xc0 | EXT_CAP_CTL2_ODDFRAMEIRQ, dp); -+ -+ /* -+ * Configure capture mode to match the -+ * external video processor format -+ */ -+ cyberpro_grphw8(EXT_CAP_MODE1, dp->cap_mode1, dp); -+ cyberpro_grphw8(EXT_CAP_MODE2, dp->cap_mode2, dp); -+ -+ /* setup overlay */ -+ cyberpro_grphw16(EXT_FIFO_CTL, 0x1010, dp); -+// cyberpro_grphw16(EXT_FIFO_CTL, 0x1b0f, dp); -+ -+ /* -+ * Always reset the capture parameters on each open. -+ */ -+ dp->capt.x = 0; -+ dp->capt.y = 0; -+ dp->capt.width = dp->cap.maxwidth; -+ dp->capt.height = dp->cap.maxheight; -+ dp->capt.decimation = 0; -+ dp->capt.flags = 0; -+ -+ cyberpro_capture_set_win(dp); -+ -+ /* -+ * Enable VAFC -+ */ -+ old = cyberpro_grphr8(EXT_LATCH1, dp); -+ cyberpro_grphw8(EXT_LATCH1, old | EXT_LATCH1_VAFC_EN, dp); -+ -+ /* -+ * Enable capture (we hope that VSYNC=1) -+ */ -+ dp->vfac1 |= VFAC_CTL1_CAPTURE; -+ cyberpro_grphw8(VFAC_CTL1, dp->vfac1, dp); -+ -+ /* -+ * The overlay source format is always the -+ * same as the capture stream format. -+ */ -+ dp->ovl->src.width = dp->capt.width; -+ dp->ovl->src.height = dp->capt.height; -+ dp->ovl->src.format = dp->stream_fmt; -+ -+ /* -+ * Initialise the overlay windows -+ */ -+ dp->ext.init(dp, &dp->ext); -+ dp->v2.init(dp, &dp->v2); -+ dp->x2.init(dp, &dp->x2); -+} -+ -+static void cyberpro_deinit(struct cyberpro_vidinfo *dp) -+{ -+ unsigned char old; -+ -+ /* -+ * Stop any bus-master activity -+ */ -+ cyberpro_writew(0, BM_CONTROL, dp); -+ -+ /* -+ * Shut down overlay -+ */ -+ if (dp->ovl_active) -+ dp->ovl->ctl(dp, dp->ovl, 0); -+ dp->ovl_active = 0; -+ -+ /* -+ * Shut down capture -+ */ -+ if (dp->cap_active) -+ cyberpro_capture(dp, 0); -+ dp->cap_active = 0; -+ -+ /* -+ * Disable all capture -+ */ -+ cyberpro_grphw8(VFAC_CTL1, 0, dp); -+ -+ /* -+ * Disable VAFC -+ */ -+ old = cyberpro_grphr8(EXT_LATCH1, dp); -+ cyberpro_grphw8(EXT_LATCH1, old & ~EXT_LATCH1_VAFC_EN, dp); -+ -+ /* -+ * Disable interrupt (this allows it to float) -+ */ -+ dp->vfac3 &= ~VFAC_CTL3_CAP_IRQ; -+ cyberpro_grphw8(VFAC_CTL3, dp->vfac3, dp); -+ -+ /* -+ * Switch off bus-master mode -+ */ -+ cyberpro_grphw8(PCI_BM_CTL, 0, dp); -+ -+ /* -+ * Disable access to bus-master registers -+ */ -+ dp->info.disable_extregs(dp->info.info); -+} -+ -+static int cyberpro_grabber_open(struct video_device *dev, int flags) -+{ -+ struct cyberpro_vidinfo *dp = dev->priv; -+ int ret, one = 1; -+ -+ MOD_INC_USE_COUNT; -+ -+ ret = -EBUSY; -+ if (flags || dp->users) -+ goto out; -+ -+ dp->users += 1; -+ -+ if (dp->users == 1) { -+ ret = request_irq(dp->irq, cyberpro_interrupt, SA_SHIRQ, -+ dp->info.dev_name, dp); -+ -+ if (ret) { -+ dp->users -= 1; -+ goto out; -+ } -+ -+ /* -+ * Initialise the VGA chip -+ */ -+ cyberpro_hw_init(dp); -+ -+ /* -+ * Enable the IRQ. This allows the IRQ to work as expected -+ * even if the IRQ line is missing the pull-up resistor. -+ */ -+ enable_irq(dp->irq); -+ -+ i2c_control_device(dp->bus, I2C_DRIVERID_VIDEODECODER, -+ DECODER_ENABLE_OUTPUT, &one); -+ } -+ -+ ret = 0; -+out: -+ if (ret) -+ MOD_DEC_USE_COUNT; -+ return ret; -+} -+ -+static void cyberpro_grabber_close(struct video_device *dev) -+{ -+ struct cyberpro_vidinfo *dp = dev->priv; -+ -+ if (dp->users == 1) { -+ int zero = 0; -+ -+ /* -+ * Disable the IRQ. This prevents problems with missing -+ * pull-up resistors on the PCI interrupt line. -+ */ -+ disable_irq(dp->irq); -+ -+ cyberpro_frames_free(dp); -+ -+ /* -+ * Turn off the SAA7111 decoder -+ */ -+ i2c_control_device(dp->bus, I2C_DRIVERID_VIDEODECODER, -+ DECODER_ENABLE_OUTPUT, &zero); -+ -+ /* -+ * Disable grabber -+ */ -+ cyberpro_deinit(dp); -+ -+ free_irq(dp->irq, dp); -+ } -+ -+ dp->users -= 1; -+ -+ MOD_DEC_USE_COUNT; -+} -+ -+/* -+ * Our general plan here is: -+ * 1. Set the CyberPro to perform a BM-DMA of one frame to this memory -+ * 2. Copy the frame to the userspace -+ * -+ * However, BM-DMA seems to be unreliable at the moment, especially on -+ * rev. 4 NetWinders. -+ */ -+static long -+cyberpro_grabber_read(struct video_device *dev, char *buf, -+ unsigned long count, int noblock) -+{ -+ struct cyberpro_vidinfo *dp = dev->priv; -+ int ret = -EINVAL; -+ -+#ifdef USE_MMIO -+ unsigned long maxbufsz = dp->capt.width * dp->capt.height * 2; -+ char *disp = dp->info.fb + (dp->cap_mem_offset << 2); -+ -+ /* -+ * If the buffer is mmap()'d, we shouldn't be using read() -+ */ -+ if (dp->mmaped) -+ return -EINVAL; -+ -+ if (count > maxbufsz) -+ count = maxbufsz; -+ -+ if (dp->cap_active) -+ cyberpro_capture(dp, 0); -+ else -+ cyberpro_capture_one(dp); -+ -+ ret = (int)count; -+ if (copy_to_user(buf, disp, count)) -+ ret = -EFAULT; -+ -+ /* -+ * unfreeze capture -+ */ -+ if (dp->cap_active) -+ cyberpro_capture(dp, 1); -+#endif -+ -+ return ret; -+} -+ -+/* -+ * We don't support writing to the grabber -+ * (In theory, we could allow writing to a separate region of VGA memory, -+ * and display this using the second overlay window. This would allow us -+ * to do video conferencing for example). -+ */ -+static long -+cyberpro_grabber_write(struct video_device *dev, const char *buf, -+ unsigned long count, int noblock) -+{ -+ return -EINVAL; -+} -+ -+static int -+cyberpro_grabber_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -+{ -+ struct cyberpro_vidinfo *dp = dev->priv; -+ -+ switch (cmd) { -+ case VIDIOCGCAP: -+ return copy_to_user(arg, &dp->cap, sizeof(dp->cap)) -+ ? -EFAULT : 0; -+ -+ case VIDIOCGCHAN: -+ { -+ struct video_channel chan; -+ -+ chan.channel = 0; -+ strcpy(chan.name, "Composite"); -+ chan.tuners = 0; -+ chan.flags = 0; -+ chan.type = VIDEO_TYPE_CAMERA; -+ chan.norm = dp->norm; -+ -+ return copy_to_user(arg, &chan, sizeof(chan)) ? -EFAULT : 0; -+ } -+ -+ case VIDIOCGPICT: -+ return copy_to_user(arg, &dp->pic, sizeof(dp->pic)) -+ ? -EINVAL : 0; -+ -+ case VIDIOCGWIN: -+ { -+ struct video_window win; -+ -+ win.x = dp->ovl->dst.x; -+ win.y = dp->ovl->dst.y; -+ win.width = dp->ovl->dst.width; -+ win.height = dp->ovl->dst.height; -+ win.chromakey = dp->ovl->dst.chromakey; -+ win.flags = VIDEO_WINDOW_CHROMAKEY | -+ (dp->interlace ? VIDEO_WINDOW_INTERLACE : 0); -+ win.clips = NULL; -+ win.clipcount = 0; -+ -+ return copy_to_user(arg, &win, sizeof(win)) -+ ? -EINVAL : 0; -+ } -+ -+ case VIDIOCGFBUF: -+ return copy_to_user(arg, &dp->buf, sizeof(dp->buf)) -+ ? -EINVAL : 0; -+ -+ case VIDIOCGUNIT: -+ { -+ struct video_unit unit; -+ -+ unit.video = dev->minor; -+ unit.vbi = VIDEO_NO_UNIT; -+ unit.radio = VIDEO_NO_UNIT; -+ unit.audio = VIDEO_NO_UNIT; -+ unit.teletext = VIDEO_NO_UNIT; -+ -+ return copy_to_user(arg, &unit, sizeof(unit)) -+ ? -EINVAL : 0; -+ } -+ -+ case VIDIOCGCAPTURE: -+ return copy_to_user(arg, &dp->capt, sizeof(dp->capt)) -+ ? -EFAULT : 0; -+ -+ case VIDIOCSCHAN: -+ { -+ struct video_decoder_capability vdc; -+ struct video_channel v; -+ int ok; -+ -+ if (copy_from_user(&v, arg, sizeof(v))) -+ return -EFAULT; -+ -+ if (v.channel != 0) -+ return -EINVAL; -+ -+ i2c_control_device(dp->bus, I2C_DRIVERID_VIDEODECODER, -+ DECODER_GET_CAPABILITIES, &vdc); -+ -+ switch (v.norm) { -+ case VIDEO_MODE_PAL: -+ ok = vdc.flags & VIDEO_DECODER_PAL; -+ break; -+ case VIDEO_MODE_NTSC: -+ ok = vdc.flags & VIDEO_DECODER_NTSC; -+ break; -+ case VIDEO_MODE_AUTO: -+ ok = vdc.flags & VIDEO_DECODER_AUTO; -+ break; -+ default: -+ ok = 0; -+ } -+ if (!ok) -+ return -EINVAL; -+ -+ dp->norm = v.norm; -+ -+ i2c_control_device(dp->bus, I2C_DRIVERID_VIDEODECODER, -+ DECODER_SET_NORM, &v.norm); -+ -+ return 0; -+ } -+ -+ case VIDIOCSPICT: -+ { -+ struct video_picture p; -+ -+ if (copy_from_user(&p, arg, sizeof(p))) -+ return -EFAULT; -+ -+ if (p.palette != dp->stream_fmt || -+ p.depth != 8) -+ return -EINVAL; -+ -+ dp->pic = p; -+ -+ /* p.depth sets the capture depth */ -+ /* p.palette sets the capture palette */ -+ -+ i2c_control_device(dp->bus, I2C_DRIVERID_VIDEODECODER, -+ DECODER_SET_PICTURE, &p); -+ -+ return 0; -+ } -+ -+ case VIDIOCSWIN: /* set the size & position of the overlay window */ -+ { -+ struct video_window w; -+ int diff; -+ -+ if (!dp->buf_set) -+ return -EINVAL; -+ -+ if (copy_from_user(&w, arg, sizeof(w))) -+ return -EFAULT; -+ -+ if (w.clipcount) -+ return -EINVAL; -+ -+ /* -+ * Bound the overlay window by the size of the screen -+ */ -+ if (w.x < 0) -+ w.x = 0; -+ if (w.y < 0) -+ w.y = 0; -+ -+ if (w.x > dp->buf.width) -+ w.x = dp->buf.width; -+ if (w.y > dp->buf.height) -+ w.y = dp->buf.height; -+ -+ if (w.width < dp->capt.width) -+ w.width = dp->capt.width; -+ if (w.height < dp->capt.height) -+ w.height = dp->capt.height; -+ -+ if (w.x + w.width > dp->buf.width) -+ w.width = dp->buf.width - w.x; -+ if (w.y + w.height > dp->buf.height) -+ w.height = dp->buf.height - w.y; -+ -+ /* -+ * We've tried to make the values fit, but -+ * they just won't. -+ */ -+ if (w.width < dp->capt.width || w.height < dp->capt.height) -+ return -EINVAL; -+ -+ diff = dp->ovl->dst.x != w.x || -+ dp->ovl->dst.y != w.y || -+ dp->ovl->dst.width != w.width || -+ dp->ovl->dst.height != w.height || -+ dp->ovl->dst.chromakey != w.chromakey || -+ dp->ovl->dst.flags != w.flags; -+ -+ if (!dp->win_set || diff) { -+ dp->ovl->dst.x = w.x; -+ dp->ovl->dst.y = w.y; -+ dp->ovl->dst.width = w.width; -+ dp->ovl->dst.height = w.height; -+ dp->ovl->dst.chromakey = w.chromakey; -+ dp->ovl->dst.flags = w.flags; -+ -+ if (dp->ovl_active) -+ dp->ovl->ctl(dp, dp->ovl, 0); -+ -+ dp->ovl->set_win(dp, dp->ovl); -+ -+ if (dp->ovl_active) -+ dp->ovl->ctl(dp, dp->ovl, 1); -+ -+ diff = w.flags & VIDEO_WINDOW_INTERLACE ? 1 : 0; -+ if (!dp->win_set || dp->interlace != diff) { -+ dp->interlace = diff; -+ cyberpro_set_interlace(dp); -+ } -+ } -+ -+ dp->win_set = 1; -+ -+ return 0; -+ } -+ -+ case VIDIOCSFBUF: /* set frame buffer info */ -+ { -+ struct video_buffer b; -+ int ret; -+ -+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) -+ return -EPERM; -+ -+ if (dp->cap_active) -+ return -EINVAL; -+ -+ if (copy_from_user(&b, arg, sizeof(b))) -+ return -EFAULT; -+ -+ ret = cyberpro_set_buffer(dp, &b); -+ if (ret == 0) { -+ dp->buf_set = 1; -+ dp->win_set = 0; -+ } -+ -+ return ret; -+ } -+ -+ case VIDIOCCAPTURE: -+ { -+ int on; -+ -+ if (get_user(on, (int *)arg)) -+ return -EFAULT; -+ -+ if (( on && dp->ovl_active) || -+ (!on && !dp->ovl_active)) -+ return 0; -+ -+ if (on && (!dp->buf_set || !dp->win_set)) -+ return -EINVAL; -+ -+ cyberpro_capture(dp, on); -+ dp->cap_active = on; -+ dp->ovl->ctl(dp, dp->ovl, on); -+ dp->ovl_active = on; -+ -+ return 0; -+ } -+ -+#ifdef USE_MMAP -+ case VIDIOCSYNC: -+ { -+ DECLARE_WAITQUEUE(wait, current); -+ int buf; -+ -+ /* -+ * The buffer must have been mmaped -+ * for this call to work. -+ */ -+ if (!dp->mmaped) -+ return -EINVAL; -+ -+ if (get_user(buf, (int *)arg)) -+ return -EFAULT; -+ -+ if (buf < 0 || buf >= NR_FRAMES) -+ return -EINVAL; -+ -+ switch (dp->frame[buf].status) { -+ case FRAME_FREE: -+ return -EINVAL; -+ -+ case FRAME_WAITING: -+ case FRAME_GRABBING: -+ add_wait_queue(&dp->frame_wait, &wait); -+ while (1) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ if (signal_pending(current)) -+ break; -+ if (dp->frame[buf].status == FRAME_DONE) -+ break; -+ schedule(); -+ } -+ set_current_state(TASK_RUNNING); -+ remove_wait_queue(&dp->frame_wait, &wait); -+ if (signal_pending(current)) -+ return -EINTR; -+ /*FALLTHROUGH*/ -+ case FRAME_DONE: -+ dp->frame[buf].status = FRAME_FREE; -+ break; -+ } -+ return 0; -+ } -+ -+ case VIDIOCMCAPTURE: -+ { -+ struct video_mmap vmap; -+ -+ /* -+ * The buffer must have been mmaped -+ * for this call to work. -+ */ -+ if (!dp->mmaped) -+ return -EINVAL; -+ -+ if (copy_from_user(&vmap, arg, sizeof(vmap))) -+ return -EFAULT; -+ -+ /* -+ * We can only capture in our source format/size. -+ */ -+ if (vmap.frame >= NR_FRAMES || -+ vmap.format != dp->stream_fmt || -+ vmap.width != dp->capt.width || -+ vmap.height != dp->capt.height) -+ return -EINVAL; -+ -+ if (dp->frame[vmap.frame].status == FRAME_WAITING || -+ dp->frame[vmap.frame].status == FRAME_GRABBING) -+ return -EBUSY; -+ -+ dp->frame[vmap.frame].status = FRAME_WAITING; -+ return 0; -+ } -+ -+ case VIDIOCGMBUF: -+ { -+ struct video_mbuf vmb; -+ unsigned int i; -+ -+ vmb.frames = NR_FRAMES; -+ vmb.size = dp->frame_size * NR_FRAMES; -+ -+ for (i = 0; i < NR_FRAMES; i++) -+ vmb.offsets[i] = dp->frame[i].offset; -+ -+ return copy_to_user(arg, &vmb, sizeof(vmb)) ? -EFAULT : 0; -+ } -+#endif -+ -+ case VIDIOCSCAPTURE: -+ { -+ struct video_capture capt; -+ -+#ifndef ALLOW_SCAPTURE_WHILE_CAP -+ if (dp->cap_active) -+ return -EINVAL; -+#endif -+ -+ if (copy_from_user(&capt, arg, sizeof(capt))) -+ return -EFAULT; -+ -+ if (capt.x < 0 || capt.width < 0 || -+ capt.y < 0 || capt.height < 0 || -+ capt.x + capt.width > dp->cap.maxwidth || -+ capt.y + capt.height > dp->cap.maxheight) -+ return -EINVAL; -+ -+ /* -+ * The capture width must be a multiple of 4 -+ */ -+ if (dp->capt.width & 3) -+ return -EINVAL; -+ -+ dp->capt.x = capt.x; -+ dp->capt.y = capt.y; -+ dp->capt.width = capt.width; -+ dp->capt.height = capt.height; -+#ifdef ALLOW_SCAPTURE_WHILE_CAP -+ if (dp->ovl_active) -+ dp->ovl->ctl(dp, dp->ovl, 0); -+ if (dp->cap_active) -+ cyberpro_capture(dp, 0); -+#endif -+ cyberpro_capture_set_win(dp); -+ -+ /* -+ * Update the overlay window information -+ */ -+ dp->ovl->src.width = capt.width; -+ dp->ovl->src.height = capt.height; -+ -+ dp->ovl->set_src(dp, dp->ovl); -+ if (dp->win_set) -+ dp->ovl->set_win(dp, dp->ovl); -+ -+#ifdef ALLOW_SCAPTURE_WHILE_CAP -+ if (dp->cap_active) -+ cyberpro_capture(dp, 1); -+ if (dp->ovl_active) -+ dp->ovl->ctl(dp, dp->ovl, 1); -+#endif -+ return 0; -+ } -+ -+ case VIDIOCGTUNER: /* no tuner */ -+ case VIDIOCSTUNER: -+ return -EINVAL; -+ } -+ -+ return -EINVAL; -+} -+ -+#ifdef USE_MMAP -+static int -+cyberpro_grabber_mmap(struct video_device *dev, const char *addr, unsigned long size) -+{ -+ struct cyberpro_vidinfo *dp = dev->priv; -+ unsigned long vaddr = (unsigned long)addr; -+ pgprot_t prot; -+ int frame_idx, ret = -EINVAL; -+ -+#if defined(__arm__) -+ prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_USER | L_PTE_WRITE | L_PTE_DIRTY); -+#elif defined(__i386__) -+ prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED); -+ if (boot_cpu_data.x86 > 3) -+ pgprot_val(prot) |= _PAGE_PCD; -+#else -+#error "Unsupported architecture" -+#endif -+ -+ /* -+ * The mmap() request must have the correct size. -+ */ -+ if (size != NR_FRAMES * dp->frame_size) -+ goto out; -+ -+ /* -+ * If it's already mapped, don't re-do -+ */ -+ if (dp->mmaped) -+ goto out; -+ dp->mmaped = 1; -+ -+ /* -+ * Map in each frame -+ */ -+ for (frame_idx = 0; frame_idx < NR_FRAMES; frame_idx++) { -+ struct framebuf *frame; -+ int pgidx; -+ -+ frame = dp->frame + frame_idx; -+ -+ ret = cyberpro_alloc_frame_buffer(dp, frame); -+ -+ /* -+ * If an error occurs, we can be lazy and leave what we've -+ * been able to do. Our release function will free any -+ * allocated buffers, and do_mmap_pgoff() will zap any -+ * inserted mappings. -+ */ -+ if (ret) -+ goto out2; -+ -+ /* -+ * Map in each page on a page by page basis. This is just -+ * a little on the inefficient side, but it's only run once. -+ */ -+ for (pgidx = 0; pgidx < NR_PAGES; pgidx++) { -+ unsigned long virt; -+ -+ virt = page_address(frame->pages[pgidx]); -+ -+ ret = remap_page_range(vaddr, virt_to_phys((void *)virt), -+ PAGE_SIZE, prot); -+ -+ if (ret) -+ goto out2; -+ -+ vaddr += PAGE_SIZE; -+ } -+ } -+ -+ out2: -+ if (ret) -+ dp->mmaped = 0; -+ out: -+ return ret; -+} -+#endif -+ -+static int __init cyberpro_grabber_init_done(struct video_device *dev) -+{ -+ struct cyberpro_vidinfo *dp; -+ struct cyberpro_info *info = dev->priv; -+ int ret; -+ -+ dp = kmalloc(sizeof(*dp), GFP_KERNEL); -+ if (!dp) -+ return -ENOMEM; -+ -+ memset(dp, 0, sizeof(*dp)); -+ -+ dev->priv = dp; -+ dp->info = *info; -+ dp->dev = dev; -+ dp->bus = &cyberpro_i2c_bus; -+ dp->regs = info->regs; -+ dp->irq = info->dev->irq; -+ -+ strcpy(dp->cap.name, dev->name); -+ dp->cap.type = dev->type; -+ dp->cap.channels = 1; -+ dp->cap.audios = 0; -+ dp->cap.minwidth = 32; -+ dp->cap.maxwidth = 716; -+ dp->cap.minheight = 32; -+ dp->cap.maxheight = 576; -+ -+ dp->pic.brightness = 32768; -+ dp->pic.hue = 32768; -+ dp->pic.colour = 32768; -+ dp->pic.contrast = 32768; -+ dp->pic.whiteness = 0; -+ dp->pic.depth = 8; -+ dp->pic.palette = VIDEO_PALETTE_YUV422; -+ -+ /* dp->buf is setup by the user */ -+ /* dp->cap_mem_offset setup by dp->buf */ -+ -+ dp->norm = VIDEO_MODE_AUTO; -+ -+ /* -+ * The extended overlay window -+ */ -+ dp->ext.init = cyberpro_ext_init; -+ dp->ext.set_src = cyberpro_ext_set_src; -+ dp->ext.set_win = cyberpro_ext_set_win; -+ dp->ext.ctl = cyberpro_ext_ctl; -+ -+ /* -+ * The V2 overlay window -+ */ -+ dp->v2.init = cyberpro_v2_init; -+ dp->v2.set_src = cyberpro_v2_set_src; -+ dp->v2.set_win = cyberpro_v2_set_win; -+ dp->v2.ctl = cyberpro_v2_ctl; -+ -+ /* -+ * The X2 overlay window -+ */ -+ dp->x2.init = cyberpro_x2_init; -+ dp->x2.set_src = cyberpro_x2_set_src; -+ dp->x2.set_win = cyberpro_x2_set_win; -+ dp->x2.ctl = cyberpro_x2_ctl; -+ -+ /* -+ * Set the overlay window which we shall be using -+ */ -+ dp->ovl = &dp->ext; -+ -+ dp->cap_mode1 = EXT_CAP_MODE1_ALTFIFO; -+ -+ /* -+ * Initialise hardware specific values. -+ * - CCIR656 8bit mode (YUV422 data) -+ * - Ignore Hgood signal -+ * - Invert Odd/Even field signal -+ */ -+ dp->cap_mode1 |= EXT_CAP_MODE1_CCIR656 | EXT_CAP_MODE1_8BIT; -+ dp->cap_mode2 = EXT_CAP_MODE2_FIXSONY | EXT_CAP_MODE2_DATEND | -+ EXT_CAP_MODE2_CCIRINVOE; -+ dp->stream_fmt = VIDEO_PALETTE_YUV422; -+ -+ -+ init_waitqueue_head(&dp->vbl_wait); -+ cyberpro_frames_init(dp); -+ -+ /* -+ * wake up the decoder -+ */ -+ decoder_sleep(0); -+ -+ dp->bus->data = dp; -+ strncpy(dp->bus->name, dev->name, sizeof(dp->bus->name)); -+ -+ pci_set_master(dp->info.dev); -+ -+ ret = i2c_register_bus(dp->bus); -+ -+ /* -+ * If we successfully registered the bus, but didn't initialise -+ * the decoder (because its driver is not present), request -+ * that it is loaded. -+ */ -+ if (ret == 0 && !dp->decoder) -+ request_module("saa7111"); -+ -+ /* -+ * If that didn't work, then we're out of luck. -+ */ -+ if (ret == 0 && !dp->decoder) { -+ i2c_unregister_bus(dp->bus); -+ ret = -ENXIO; -+ } -+ -+ if (ret) { -+ kfree(dp); -+ -+ /* -+ * put the decoder back to sleep -+ */ -+ decoder_sleep(1); -+ } -+ -+ return ret; -+} -+ -+static struct video_device cyberpro_grabber = { -+ name: "", -+ type: VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | -+ VID_TYPE_CHROMAKEY | VID_TYPE_SCALES | -+ VID_TYPE_SUBCAPTURE, -+ hardware: 0, -+ open: cyberpro_grabber_open, -+ close: cyberpro_grabber_close, -+ read: cyberpro_grabber_read, -+ write: cyberpro_grabber_write, -+ ioctl: cyberpro_grabber_ioctl, -+#ifdef USE_MMAP -+ mmap: cyberpro_grabber_mmap, -+#endif -+ initialize: cyberpro_grabber_init_done, -+}; -+ -+int init_cyber2000fb_viddev(void) -+{ -+ struct cyberpro_info info; -+ -+ if (!cyber2000fb_attach(&info, 0)) -+ return -ENXIO; -+ -+ strncpy(cyberpro_grabber.name, info.dev_name, sizeof(cyberpro_grabber.name)); -+ -+ cyberpro_grabber.priv = &info; -+ -+ return video_register_device(&cyberpro_grabber, VFL_TYPE_GRABBER, -1); -+} -+ -+/* -+ * This can be cleaned up when the SAA7111 code is fixed. -+ */ -+#ifdef MODULE -+static int __init cyberpro_init(void) -+{ -+ disable_irq(35); -+ return init_cyber2000fb_viddev(); -+} -+ -+static void __exit cyberpro_exit(void) -+{ -+ video_unregister_device(&cyberpro_grabber); -+ kfree(cyberpro_grabber.priv); -+ i2c_unregister_bus(&cyberpro_i2c_bus); -+ -+ /* -+ * put the decoder back to sleep -+ */ -+ decoder_sleep(1); -+ -+ cyber2000fb_detach(0); -+} -+ -+module_init(cyberpro_init); -+module_exit(cyberpro_exit); -+#endif -diff -urN linux-2.4.26/drivers/media/video/i2c-old.c linux-2.4.26-vrs1/drivers/media/video/i2c-old.c ---- linux-2.4.26/drivers/media/video/i2c-old.c 2004-02-27 20:03:26.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/media/video/i2c-old.c 2004-02-27 23:41:21.000000000 +0000 -@@ -36,11 +36,20 @@ - static struct i2c_driver *drivers[I2C_DRIVER_MAX]; - static int bus_count = 0, driver_count = 0; - -+extern int saa7111_init(void); -+extern int saa7185_init(void); -+extern int bt819_init(void); -+extern int bt856_init(void); -+ - int i2c_init(void) - { - printk(KERN_INFO "i2c: initialized%s\n", - scan ? " (i2c bus scan enabled)" : ""); - -+#if defined(CONFIG_VIDEO_CYBERPRO) -+ saa7111_init(); -+#endif -+ - return 0; - } - -@@ -52,10 +61,10 @@ - int i,j,ack=1; - unsigned char addr; - LOCK_FLAGS; -- -+ - /* probe for device */ - LOCK_I2C_BUS(bus); -- for (addr = driver->addr_l; addr <= driver->addr_h; addr += 2) -+ for (addr = driver->addr_l; addr <= driver->addr_h; addr += 2) - { - i2c_start(bus); - ack = i2c_sendbyte(bus,addr,0); -@@ -87,8 +96,8 @@ - device->addr = addr; - - /* Attach */ -- -- if (driver->attach(device)!=0) -+ -+ if (driver->attach(device)!=0) - { - kfree(device); - return; -@@ -114,7 +123,7 @@ - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (device == device->driver->devices[i]) - break; -- if (I2C_DEVICE_MAX == i) -+ if (I2C_DEVICE_MAX == i) - { - printk(KERN_WARNING "i2c: detach_device #1: device not found: %s\n", - device->name); -@@ -126,7 +135,7 @@ - for (i = 0; i < I2C_DEVICE_MAX; i++) - if (device == device->bus->devices[i]) - break; -- if (I2C_DEVICE_MAX == i) -+ if (I2C_DEVICE_MAX == i) - { - printk(KERN_WARNING "i2c: detach_device #2: device not found: %s\n", - device->name); -@@ -158,19 +167,19 @@ - busses[i] = bus; - bus_count++; - REGPRINT(printk("i2c: bus registered: %s\n",bus->name)); -- -+ - MOD_INC_USE_COUNT; - -- if (scan) -+ if (scan) - { - /* scan whole i2c bus */ - LOCK_I2C_BUS(bus); -- for (i = 0; i < 256; i+=2) -+ for (i = 0; i < 256; i+=2) - { - i2c_start(bus); - ack = i2c_sendbyte(bus,i,0); - i2c_stop(bus); -- if (!ack) -+ if (!ack) - { - printk(KERN_INFO "i2c: scanning bus %s: found device at addr=0x%02x\n", - bus->name,i); -@@ -198,20 +207,20 @@ - for (i = 0; i < I2C_BUS_MAX; i++) - if (bus == busses[i]) - break; -- if (I2C_BUS_MAX == i) -+ if (I2C_BUS_MAX == i) - { - printk(KERN_WARNING "i2c: unregister_bus #1: bus not found: %s\n", - bus->name); - return -ENODEV; - } -- -+ - MOD_DEC_USE_COUNT; -- -+ - busses[i] = NULL; - bus_count--; - REGPRINT(printk("i2c: bus unregistered: %s\n",bus->name)); - -- return 0; -+ return 0; - } - - /* ----------------------------------------------------------------------- */ -@@ -231,9 +240,9 @@ - - drivers[i] = driver; - driver_count++; -- -+ - MOD_INC_USE_COUNT; -- -+ - REGPRINT(printk("i2c: driver registered: %s\n",driver->name)); - - /* Probe available busses */ -@@ -256,7 +265,7 @@ - for (i = 0; i < I2C_DRIVER_MAX; i++) - if (driver == drivers[i]) - break; -- if (I2C_DRIVER_MAX == i) -+ if (I2C_DRIVER_MAX == i) - { - printk(KERN_WARNING "i2c: unregister_driver: driver not found: %s\n", - driver->name); -@@ -264,7 +273,7 @@ - } - - MOD_DEC_USE_COUNT; -- -+ - drivers[i] = NULL; - driver_count--; - REGPRINT(printk("i2c: driver unregistered: %s\n",driver->name)); -@@ -328,7 +337,7 @@ - int i2c_ack(struct i2c_bus *bus) - { - int ack; -- -+ - I2C_SET(bus,0,1); - I2C_SET(bus,1,1); - ack = I2C_GET(bus); -@@ -339,7 +348,7 @@ - int i2c_sendbyte(struct i2c_bus *bus,unsigned char data,int wait_for_ack) - { - int i, ack; -- -+ - I2C_SET(bus,0,0); - for (i=7; i>=0; i--) - (data&(1<=0; i--) -+ for (i=7; i>=0; i--) - { - I2C_SET(bus,1,1); - if (I2C_GET(bus)) -@@ -373,7 +382,7 @@ - int i2c_read(struct i2c_bus *bus, unsigned char addr) - { - int ret; -- -+ - if (bus->i2c_read) - return bus->i2c_read(bus, addr); - -diff -urN linux-2.4.26/drivers/media/video/saa7111.c linux-2.4.26-vrs1/drivers/media/video/saa7111.c ---- linux-2.4.26/drivers/media/video/saa7111.c 2001-09-30 20:26:06.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/media/video/saa7111.c 2004-01-14 21:32:25.000000000 +0000 -@@ -20,9 +20,9 @@ - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -- --#include -+#include - #include -+#include - #include - #include - #include -@@ -149,7 +149,11 @@ - 0x0d, 0x00, /* 0d - HUE=0 */ - 0x0e, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */ - 0x0f, 0x00, /* 0f - reserved */ -+#ifndef CONFIG_ARCH_NETWINDER - 0x10, 0x48, /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */ -+#else -+ 0x10, 0xc8, /* 10 - OFTS=YUV-CCIR656, HDEL=0, VLRN=1, YDEL=0 */ -+#endif - 0x11, 0x1c, /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1, OEYC=1, OEHV=1, VIPB=0, COLO=0 */ - 0x12, 0x00, /* 12 - output control 2 */ - 0x13, 0x00, /* 13 - output control 3 */ -diff -urN linux-2.4.26/drivers/message/i2o/i2o_core.c linux-2.4.26-vrs1/drivers/message/i2o/i2o_core.c ---- linux-2.4.26/drivers/message/i2o/i2o_core.c 2003-06-13 15:51:34.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/message/i2o/i2o_core.c 2004-01-14 21:32:25.000000000 +0000 -@@ -1665,14 +1665,14 @@ - } - memset(status, 0, 4); - -- msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0; -- msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID; -- msg[2]=core_context; -- msg[3]=0; -- msg[4]=0; -- msg[5]=0; -- msg[6]=virt_to_bus(status); -- msg[7]=0; /* 64bit host FIXME */ -+ writel(EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0, msg + 0); -+ writel(I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID, msg + 1); -+ writel(core_context, msg + 2); -+ writel(0, msg + 3); -+ writel(0, msg + 4); -+ writel(0, msg + 5); -+ writel(virt_to_bus(status), msg + 6); -+ writel(0, msg + 7); /* 64bit host FIXME */ - - i2o_post_message(c,m); - -@@ -1781,15 +1781,15 @@ - return -ETIMEDOUT; - msg=(u32 *)(c->mem_offset+m); - -- msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0; -- msg[1]=I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID; -- msg[2]=core_context; -- msg[3]=0; -- msg[4]=0; -- msg[5]=0; -- msg[6]=virt_to_bus(c->status_block); -- msg[7]=0; /* 64bit host FIXME */ -- msg[8]=sizeof(i2o_status_block); /* always 88 bytes */ -+ writel(NINE_WORD_MSG_SIZE|SGL_OFFSET_0, msg + 0); -+ writel(I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID, msg + 1); -+ writel(core_context, msg + 2); -+ writel(0, msg + 3); -+ writel(0, msg + 4); -+ writel(0, msg + 5); -+ writel(virt_to_bus(c->status_block), msg + 6); -+ writel(0, msg + 7); /* 64bit host FIXME */ -+ writel(sizeof(i2o_status_block), msg + 8); /* always 88 bytes */ - - i2o_post_message(c,m); - -@@ -2193,15 +2193,15 @@ - } - memset(status, 0, 4); - -- msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6; -- msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID; -- msg[2]= core_context; -- msg[3]= 0x0106; /* Transaction context */ -- msg[4]= 4096; /* Host page frame size */ -+ writel(EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6, msg + 0); -+ writel(I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID, msg + 1); -+ writel(core_context, msg + 2); -+ writel(0x0106, msg + 3); /* Transaction context */ -+ writel(PAGE_SIZE, msg + 4); /* Host page frame size */ - /* Frame size is in words. 256 bytes a frame for now */ -- msg[5]= MSG_FRAME_SIZE<<16|0x80; /* Outbound msg frame size in words and Initcode */ -- msg[6]= 0xD0000004; /* Simple SG LE, EOB */ -- msg[7]= virt_to_bus(status); -+ writel(MSG_FRAME_SIZE<<16|0x80, msg + 5);/* Outbound msg frame size in words and Initcode */ -+ writel(0xD0000004, msg + 6); /* Simple SG LE, EOB */ -+ writel(virt_to_bus(status), msg + 7); - - i2o_post_message(c,m); - -diff -urN linux-2.4.26/drivers/message/i2o/i2o_pci.c linux-2.4.26-vrs1/drivers/message/i2o/i2o_pci.c ---- linux-2.4.26/drivers/message/i2o/i2o_pci.c 2002-11-28 23:53:13.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/message/i2o/i2o_pci.c 2004-01-14 21:32:25.000000000 +0000 -@@ -390,4 +390,4 @@ - MODULE_PARM_DESC(dpt, "Set this if you want to drive DPT cards normally handled by dpt_i2o"); - module_init(i2o_pci_core_attach); - module_exit(i2o_pci_core_detach); -- -\ No newline at end of file -+ -diff -urN linux-2.4.26/drivers/misc/Config.in linux-2.4.26-vrs1/drivers/misc/Config.in ---- linux-2.4.26/drivers/misc/Config.in 1999-12-25 23:04:56.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/misc/Config.in 2004-01-14 21:32:25.000000000 +0000 -@@ -1,7 +1,17 @@ - # --# Misc strange devices -+# MCP drivers - # - mainmenu_option next_comment --comment 'Misc devices' -+comment 'Multimedia Capabilities Port drivers' -+ -+bool 'Multimedia drivers' CONFIG_MCP -+ -+# Interface drivers -+dep_bool 'Support SA1100 MCP interface' CONFIG_MCP_SA1100 $CONFIG_MCP $CONFIG_ARCH_SA1100 -+ -+# Chip drivers -+dep_tristate 'Support for UCB1200 / UCB1300' CONFIG_MCP_UCB1200 $CONFIG_MCP -+dep_tristate ' Audio / Telephony interface support' CONFIG_MCP_UCB1200_AUDIO $CONFIG_MCP_UCB1200 $CONFIG_SOUND -+dep_tristate ' Touchscreen interface support' CONFIG_MCP_UCB1200_TS $CONFIG_MCP_UCB1200 - - endmenu -diff -urN linux-2.4.26/drivers/misc/Makefile linux-2.4.26-vrs1/drivers/misc/Makefile ---- linux-2.4.26/drivers/misc/Makefile 2000-12-29 22:07:22.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/misc/Makefile 2004-01-14 21:32:25.000000000 +0000 -@@ -11,6 +11,14 @@ - - O_TARGET := misc.o - -+export-objs := mcp-core.o mcp-sa1100.o ucb1x00-core.o -+ -+obj-$(CONFIG_MCP) += mcp-core.o -+obj-$(CONFIG_MCP_SA1100) += mcp-sa1100.o -+obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o -+obj-$(CONFIG_MCP_UCB1200_AUDIO) += ucb1x00-audio.o -+obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o -+ - include $(TOPDIR)/Rules.make - - fastdep: -diff -urN linux-2.4.26/drivers/misc/mcp-core.c linux-2.4.26-vrs1/drivers/misc/mcp-core.c ---- linux-2.4.26/drivers/misc/mcp-core.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/misc/mcp-core.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,155 @@ -+/* -+ * linux/drivers/misc/mcp-core.c -+ * -+ * Copyright (C) 2001 Russell King -+ * -+ * 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. -+ * -+ * Generic MCP (Multimedia Communications Port) layer. All MCP locking -+ * is solely held within this file. -+ */ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "mcp.h" -+ -+/** -+ * mcp_set_telecom_divisor - set the telecom divisor -+ * @mcp: MCP interface structure -+ * @div: SIB clock divisor -+ * -+ * Set the telecom divisor on the MCP interface. The resulting -+ * sample rate is SIBCLOCK/div. -+ */ -+void mcp_set_telecom_divisor(struct mcp *mcp, unsigned int div) -+{ -+ spin_lock_irq(&mcp->lock); -+ mcp->set_telecom_divisor(mcp, div); -+ spin_unlock_irq(&mcp->lock); -+} -+ -+/** -+ * mcp_set_audio_divisor - set the audio divisor -+ * @mcp: MCP interface structure -+ * @div: SIB clock divisor -+ * -+ * Set the audio divisor on the MCP interface. -+ */ -+void mcp_set_audio_divisor(struct mcp *mcp, unsigned int div) -+{ -+ spin_lock_irq(&mcp->lock); -+ mcp->set_audio_divisor(mcp, div); -+ spin_unlock_irq(&mcp->lock); -+} -+ -+/** -+ * mcp_reg_write - write a device register -+ * @mcp: MCP interface structure -+ * @reg: 4-bit register index -+ * @val: 16-bit data value -+ * -+ * Write a device register. The MCP interface must be enabled -+ * to prevent this function hanging. -+ */ -+void mcp_reg_write(struct mcp *mcp, unsigned int reg, unsigned int val) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&mcp->lock, flags); -+ mcp->reg_write(mcp, reg, val); -+ spin_unlock_irqrestore(&mcp->lock, flags); -+} -+ -+/** -+ * mcp_reg_read - read a device register -+ * @mcp: MCP interface structure -+ * @reg: 4-bit register index -+ * -+ * Read a device register and return its value. The MCP interface -+ * must be enabled to prevent this function hanging. -+ */ -+unsigned int mcp_reg_read(struct mcp *mcp, unsigned int reg) -+{ -+ unsigned long flags; -+ unsigned int val; -+ -+ spin_lock_irqsave(&mcp->lock, flags); -+ val = mcp->reg_read(mcp, reg); -+ spin_unlock_irqrestore(&mcp->lock, flags); -+ -+ return val; -+} -+ -+/** -+ * mcp_enable - enable the MCP interface -+ * @mcp: MCP interface to enable -+ * -+ * Enable the MCP interface. Each call to mcp_enable will need -+ * a corresponding call to mcp_disable to disable the interface. -+ */ -+void mcp_enable(struct mcp *mcp) -+{ -+ spin_lock_irq(&mcp->lock); -+ if (mcp->use_count++ == 0) -+ mcp->enable(mcp); -+ spin_unlock_irq(&mcp->lock); -+} -+ -+/** -+ * mcp_disable - disable the MCP interface -+ * @mcp: MCP interface to disable -+ * -+ * Disable the MCP interface. The MCP interface will only be -+ * disabled once the number of calls to mcp_enable matches the -+ * number of calls to mcp_disable. -+ */ -+void mcp_disable(struct mcp *mcp) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&mcp->lock, flags); -+ if (--mcp->use_count == 0) -+ mcp->disable(mcp); -+ spin_unlock_irqrestore(&mcp->lock, flags); -+} -+ -+ -+/* -+ * This needs re-working -+ */ -+static struct mcp *mcp_if; -+ -+struct mcp *mcp_get(void) -+{ -+ return mcp_if; -+} -+ -+int mcp_register(struct mcp *mcp) -+{ -+ if (mcp_if) -+ return -EBUSY; -+ if (mcp->owner) -+ __MOD_INC_USE_COUNT(mcp->owner); -+ mcp_if = mcp; -+ return 0; -+} -+ -+EXPORT_SYMBOL(mcp_set_telecom_divisor); -+EXPORT_SYMBOL(mcp_set_audio_divisor); -+EXPORT_SYMBOL(mcp_reg_write); -+EXPORT_SYMBOL(mcp_reg_read); -+EXPORT_SYMBOL(mcp_enable); -+EXPORT_SYMBOL(mcp_disable); -+EXPORT_SYMBOL(mcp_get); -+EXPORT_SYMBOL(mcp_register); -+ -+MODULE_AUTHOR("Russell King "); -+MODULE_DESCRIPTION("Core multimedia communications port driver"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.4.26/drivers/misc/mcp-sa1100.c linux-2.4.26-vrs1/drivers/misc/mcp-sa1100.c ---- linux-2.4.26/drivers/misc/mcp-sa1100.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/misc/mcp-sa1100.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,180 @@ -+/* -+ * linux/drivers/misc/mcp-sa1100.c -+ * -+ * Copyright (C) 2001 Russell King -+ * -+ * 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. -+ * -+ * SA1100 MCP (Multimedia Communications Port) driver. -+ * -+ * MCP read/write timeouts from Jordi Colomer, rehacked by rmk. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "mcp.h" -+ -+static void -+mcp_sa1100_set_telecom_divisor(struct mcp *mcp, unsigned int divisor) -+{ -+ unsigned int mccr0; -+ -+ divisor /= 32; -+ -+ mccr0 = Ser4MCCR0 & ~0x00007f00; -+ mccr0 |= divisor << 8; -+ Ser4MCCR0 = mccr0; -+} -+ -+static void -+mcp_sa1100_set_audio_divisor(struct mcp *mcp, unsigned int divisor) -+{ -+ unsigned int mccr0; -+ -+ divisor /= 32; -+ -+ mccr0 = Ser4MCCR0 & ~0x0000007f; -+ mccr0 |= divisor; -+ Ser4MCCR0 = mccr0; -+} -+ -+/* -+ * Write data to the device. The bit should be set after 3 subframe -+ * times (each frame is 64 clocks). We wait a maximum of 6 subframes. -+ * We really should try doing something more productive while we -+ * wait. -+ */ -+static void -+mcp_sa1100_write(struct mcp *mcp, unsigned int reg, unsigned int val) -+{ -+ int ret = -ETIME; -+ int i; -+ -+ Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff); -+ -+ for (i = 0; i < 2; i++) { -+ udelay(mcp->rw_timeout); -+ if (Ser4MCSR & MCSR_CWC) { -+ ret = 0; -+ break; -+ } -+ } -+ -+ if (ret < 0) -+ printk(KERN_WARNING "mcp: write timed out\n"); -+} -+ -+/* -+ * Read data from the device. The bit should be set after 3 subframe -+ * times (each frame is 64 clocks). We wait a maximum of 6 subframes. -+ * We really should try doing something more productive while we -+ * wait. -+ */ -+static unsigned int -+mcp_sa1100_read(struct mcp *mcp, unsigned int reg) -+{ -+ int ret = -ETIME; -+ int i; -+ -+ Ser4MCDR2 = reg << 17 | MCDR2_Rd; -+ -+ for (i = 0; i < 2; i++) { -+ udelay(mcp->rw_timeout); -+ if (Ser4MCSR & MCSR_CRC) { -+ ret = Ser4MCDR2 & 0xffff; -+ break; -+ } -+ } -+ -+ if (ret < 0) -+ printk(KERN_WARNING "mcp: read timed out\n"); -+ -+ return ret; -+} -+ -+static void mcp_sa1100_enable(struct mcp *mcp) -+{ -+ Ser4MCSR = -1; -+ Ser4MCCR0 |= MCCR0_MCE; -+} -+ -+static void mcp_sa1100_disable(struct mcp *mcp) -+{ -+ Ser4MCCR0 &= ~MCCR0_MCE; -+} -+ -+struct mcp mcp_sa1100 = { -+ owner: THIS_MODULE, -+ lock: SPIN_LOCK_UNLOCKED, -+ sclk_rate: 11981000, -+ dma_audio_rd: DMA_Ser4MCP0Rd, -+ dma_audio_wr: DMA_Ser4MCP0Wr, -+ dma_telco_rd: DMA_Ser4MCP1Rd, -+ dma_telco_wr: DMA_Ser4MCP1Wr, -+ set_telecom_divisor: mcp_sa1100_set_telecom_divisor, -+ set_audio_divisor: mcp_sa1100_set_audio_divisor, -+ reg_write: mcp_sa1100_write, -+ reg_read: mcp_sa1100_read, -+ enable: mcp_sa1100_enable, -+ disable: mcp_sa1100_disable, -+}; -+ -+/* -+ * This needs re-working -+ */ -+static int mcp_sa1100_init(void) -+{ -+ struct mcp *mcp = &mcp_sa1100; -+ int ret = -ENODEV; -+ -+ if (machine_is_accelent_sa() || -+ machine_is_adsbitsy() || machine_is_assabet() || -+ machine_is_cerf() || machine_is_flexanet() || -+ machine_is_freebird() || machine_is_graphicsclient() || -+ machine_is_graphicsmaster() || machine_is_lart() || -+ machine_is_omnimeter() || machine_is_pfs168() || -+ machine_is_shannon() || machine_is_simpad() || -+ machine_is_simputer() || machine_is_yopy()) { -+ /* -+ * Setup the PPC unit correctly. -+ */ -+ PPDR &= ~PPC_RXD4; -+ PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM; -+ PSDR |= PPC_RXD4; -+ PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); -+ PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); -+ -+ Ser4MCSR = -1; -+ Ser4MCCR1 = 0; -+ Ser4MCCR0 = 0x00007f7f | MCCR0_ADM; -+ -+ /* -+ * Calculate the read/write timeout (us) from the bit clock -+ * rate. This is the period for 3 64-bit frames. Always -+ * round this time up. -+ */ -+ mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) / -+ mcp->sclk_rate; -+ -+ ret = mcp_register(mcp); -+ } -+ -+ return ret; -+} -+ -+module_init(mcp_sa1100_init); -+EXPORT_SYMBOL(mcp_sa1100_init); -+ -+MODULE_AUTHOR("Russell King "); -+MODULE_DESCRIPTION("SA11x0 multimedia communications port driver"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.4.26/drivers/misc/mcp.h linux-2.4.26-vrs1/drivers/misc/mcp.h ---- linux-2.4.26/drivers/misc/mcp.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/misc/mcp.h 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,44 @@ -+/* -+ * linux/drivers/misc/mcp.h -+ * -+ * Copyright (C) 2001 Russell King, All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License. -+ */ -+#ifndef MCP_H -+#define MCP_H -+ -+struct mcp { -+ struct module *owner; -+ spinlock_t lock; -+ int use_count; -+ unsigned int sclk_rate; -+ unsigned int rw_timeout; -+ dma_device_t dma_audio_rd; -+ dma_device_t dma_audio_wr; -+ dma_device_t dma_telco_rd; -+ dma_device_t dma_telco_wr; -+ void (*set_telecom_divisor)(struct mcp *, unsigned int); -+ void (*set_audio_divisor)(struct mcp *, unsigned int); -+ void (*reg_write)(struct mcp *, unsigned int, unsigned int); -+ unsigned int (*reg_read)(struct mcp *, unsigned int); -+ void (*enable)(struct mcp *); -+ void (*disable)(struct mcp *); -+}; -+ -+void mcp_set_telecom_divisor(struct mcp *, unsigned int); -+void mcp_set_audio_divisor(struct mcp *, unsigned int); -+void mcp_reg_write(struct mcp *, unsigned int, unsigned int); -+unsigned int mcp_reg_read(struct mcp *, unsigned int); -+void mcp_enable(struct mcp *); -+void mcp_disable(struct mcp *); -+ -+/* noddy implementation alert! */ -+struct mcp *mcp_get(void); -+int mcp_register(struct mcp *); -+ -+#define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate) -+ -+#endif -diff -urN linux-2.4.26/drivers/misc/ucb1x00-audio.c linux-2.4.26-vrs1/drivers/misc/ucb1x00-audio.c ---- linux-2.4.26/drivers/misc/ucb1x00-audio.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/misc/ucb1x00-audio.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,378 @@ -+/* -+ * linux/drivers/misc/ucb1x00-audio.c -+ * -+ * Copyright (C) 2001 Russell King, All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "ucb1x00.h" -+ -+#include "../drivers/sound/sa1100-audio.h" -+ -+#define MAGIC 0x41544154 -+ -+struct ucb1x00_audio { -+ struct file_operations fops; -+ struct file_operations mops; -+ struct ucb1x00 *ucb; -+ audio_stream_t output_stream; -+ audio_stream_t input_stream; -+ audio_state_t state; -+ unsigned int rate; -+ int dev_id; -+ int mix_id; -+ unsigned int daa_oh_bit; -+ unsigned int telecom; -+ unsigned int magic; -+ unsigned int ctrl_a; -+ unsigned int ctrl_b; -+ -+ /* mixer info */ -+ unsigned int mod_cnt; -+ unsigned short output_level; -+ unsigned short input_level; -+}; -+ -+#define REC_MASK (SOUND_MASK_VOLUME | SOUND_MASK_MIC) -+#define DEV_MASK REC_MASK -+ -+static int -+ucb1x00_mixer_ioctl(struct inode *ino, struct file *filp, uint cmd, ulong arg) -+{ -+ struct ucb1x00_audio *ucba; -+ unsigned int val, gain; -+ int ret = 0; -+ -+ ucba = list_entry(filp->f_op, struct ucb1x00_audio, mops); -+ -+ if (_IOC_TYPE(cmd) != 'M') -+ return -EINVAL; -+ -+ if (cmd == SOUND_MIXER_INFO) { -+ struct mixer_info mi; -+ -+ strncpy(mi.id, "UCB1x00", sizeof(mi.id)); -+ strncpy(mi.name, "Philips UCB1x00", sizeof(mi.name)); -+ mi.modify_counter = ucba->mod_cnt; -+ return copy_to_user((void *)arg, &mi, sizeof(mi)) ? -EFAULT : 0; -+ } -+ -+ if (_IOC_DIR(cmd) & _IOC_WRITE) { -+ unsigned int left, right; -+ -+ ret = get_user(val, (unsigned int *)arg); -+ if (ret) -+ goto out; -+ -+ left = val & 255; -+ right = val >> 8; -+ -+ if (left > 100) -+ left = 100; -+ if (right > 100) -+ right = 100; -+ -+ gain = (left + right) / 2; -+ -+ ret = -EINVAL; -+ if (!ucba->telecom) { -+ switch(_IOC_NR(cmd)) { -+ case SOUND_MIXER_VOLUME: -+ ucba->output_level = gain | gain << 8; -+ ucba->mod_cnt++; -+ ucba->ctrl_b = (ucba->ctrl_b & 0xff00) | -+ ((gain * 31) / 100); -+ ucb1x00_reg_write(ucba->ucb, UCB_AC_B, -+ ucba->ctrl_b); -+ ret = 0; -+ break; -+ -+ case SOUND_MIXER_MIC: -+ ucba->input_level = gain | gain << 8; -+ ucba->mod_cnt++; -+ ucba->ctrl_a = (ucba->ctrl_a & 0x7f) | -+ (((gain * 31) / 100) << 7); -+ ucb1x00_reg_write(ucba->ucb, UCB_AC_A, -+ ucba->ctrl_a); -+ ret = 0; -+ break; -+ } -+ } -+ } -+ -+ if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) { -+ switch (_IOC_NR(cmd)) { -+ case SOUND_MIXER_VOLUME: -+ val = ucba->output_level; -+ break; -+ -+ case SOUND_MIXER_MIC: -+ val = ucba->input_level; -+ break; -+ -+ case SOUND_MIXER_RECSRC: -+ case SOUND_MIXER_RECMASK: -+ val = ucba->telecom ? 0 : REC_MASK; -+ break; -+ -+ case SOUND_MIXER_DEVMASK: -+ val = ucba->telecom ? 0 : DEV_MASK; -+ break; -+ -+ case SOUND_MIXER_CAPS: -+ case SOUND_MIXER_STEREODEVS: -+ val = 0; -+ break; -+ -+ default: -+ val = 0; -+ ret = -EINVAL; -+ break; -+ } -+ -+ if (ret == 0) -+ ret = put_user(val, (int *)arg); -+ } -+ out: -+ return ret; -+} -+ -+static int ucb1x00_audio_setrate(struct ucb1x00_audio *ucba, int rate) -+{ -+ unsigned int div_rate = ucb1x00_clkrate(ucba->ucb) / 32; -+ unsigned int div; -+ -+ div = (div_rate + (rate / 2)) / rate; -+ if (div < 6) -+ div = 6; -+ if (div > 127) -+ div = 127; -+ -+ ucba->ctrl_a = (ucba->ctrl_a & ~0x7f) | div; -+ -+ if (ucba->telecom) { -+ ucb1x00_reg_write(ucba->ucb, UCB_TC_B, 0); -+ ucb1x00_set_telecom_divisor(ucba->ucb, div * 32); -+ ucb1x00_reg_write(ucba->ucb, UCB_TC_A, ucba->ctrl_a); -+ ucb1x00_reg_write(ucba->ucb, UCB_TC_B, ucba->ctrl_b); -+ } else { -+ ucb1x00_reg_write(ucba->ucb, UCB_AC_B, 0); -+ ucb1x00_set_audio_divisor(ucba->ucb, div * 32); -+ ucb1x00_reg_write(ucba->ucb, UCB_AC_A, ucba->ctrl_a); -+ ucb1x00_reg_write(ucba->ucb, UCB_AC_B, ucba->ctrl_b); -+ } -+ -+ ucba->rate = div_rate / div; -+ -+ return ucba->rate; -+} -+ -+static int ucb1x00_audio_getrate(struct ucb1x00_audio *ucba) -+{ -+ return ucba->rate; -+} -+ -+static void ucb1x00_audio_startup(void *data) -+{ -+ struct ucb1x00_audio *ucba = data; -+ -+ ucb1x00_enable(ucba->ucb); -+ ucb1x00_audio_setrate(ucba, ucba->rate); -+ -+ ucb1x00_reg_write(ucba->ucb, UCB_MODE, UCB_MODE_DYN_VFLAG_ENA); -+ -+ /* -+ * Take off-hook -+ */ -+ if (ucba->daa_oh_bit) -+ ucb1x00_io_write(ucba->ucb, 0, ucba->daa_oh_bit); -+} -+ -+static void ucb1x00_audio_shutdown(void *data) -+{ -+ struct ucb1x00_audio *ucba = data; -+ -+ /* -+ * Place on-hook -+ */ -+ if (ucba->daa_oh_bit) -+ ucb1x00_io_write(ucba->ucb, ucba->daa_oh_bit, 0); -+ -+ ucb1x00_reg_write(ucba->ucb, ucba->telecom ? UCB_TC_B : UCB_AC_B, 0); -+ ucb1x00_disable(ucba->ucb); -+} -+ -+static int -+ucb1x00_audio_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) -+{ -+ struct ucb1x00_audio *ucba; -+ int val, ret = 0; -+ -+ ucba = list_entry(file->f_op, struct ucb1x00_audio, fops); -+ -+ /* -+ * Make sure we have our magic number -+ */ -+ if (ucba->magic != MAGIC) -+ return -ENODEV; -+ -+ switch (cmd) { -+ case SNDCTL_DSP_STEREO: -+ ret = get_user(val, (int *)arg); -+ if (ret) -+ return ret; -+ if (val != 0) -+ return -EINVAL; -+ val = 0; -+ break; -+ -+ case SNDCTL_DSP_CHANNELS: -+ case SOUND_PCM_READ_CHANNELS: -+ val = 1; -+ break; -+ -+ case SNDCTL_DSP_SPEED: -+ ret = get_user(val, (int *)arg); -+ if (ret) -+ return ret; -+ val = ucb1x00_audio_setrate(ucba, val); -+ break; -+ -+ case SOUND_PCM_READ_RATE: -+ val = ucb1x00_audio_getrate(ucba); -+ break; -+ -+ case SNDCTL_DSP_SETFMT: -+ case SNDCTL_DSP_GETFMTS: -+ val = AFMT_S16_LE; -+ break; -+ -+ default: -+ return ucb1x00_mixer_ioctl(inode, file, cmd, arg); -+ } -+ -+ return put_user(val, (int *)arg); -+} -+ -+static int ucb1x00_audio_open(struct inode *inode, struct file *file) -+{ -+ struct ucb1x00_audio *ucba; -+ -+ ucba = list_entry(file->f_op, struct ucb1x00_audio, fops); -+ -+ return sa1100_audio_attach(inode, file, &ucba->state); -+} -+ -+static struct ucb1x00_audio *ucb1x00_audio_alloc(struct ucb1x00 *ucb) -+{ -+ struct ucb1x00_audio *ucba; -+ -+ ucba = kmalloc(sizeof(*ucba), GFP_KERNEL); -+ if (ucba) { -+ memset(ucba, 0, sizeof(*ucba)); -+ -+ ucba->magic = MAGIC; -+ ucba->ucb = ucb; -+ ucba->fops.owner = THIS_MODULE; -+ ucba->fops.open = ucb1x00_audio_open; -+ ucba->mops.owner = THIS_MODULE; -+ ucba->mops.ioctl = ucb1x00_mixer_ioctl; -+ ucba->state.output_stream = &ucba->output_stream; -+ ucba->state.input_stream = &ucba->input_stream; -+ ucba->state.data = ucba; -+ ucba->state.hw_init = ucb1x00_audio_startup; -+ ucba->state.hw_shutdown = ucb1x00_audio_shutdown; -+ ucba->state.client_ioctl = ucb1x00_audio_ioctl; -+ -+ /* There is a bug in the StrongARM causes corrupt MCP data to be sent to -+ * the codec when the FIFOs are empty and writes are made to the OS timer -+ * match register 0. To avoid this we must make sure that data is always -+ * sent to the codec. -+ */ -+ ucba->state.need_tx_for_rx = 1; -+ -+ init_MUTEX(&ucba->state.sem); -+ ucba->rate = 8000; -+ } -+ return ucba; -+} -+ -+static struct ucb1x00_audio *audio, *telecom; -+ -+static int __init ucb1x00_audio_init(void) -+{ -+ struct ucb1x00 *ucb = ucb1x00_get(); -+ struct ucb1x00_audio *a; -+ -+ if (!ucb) -+ return -ENODEV; -+ -+ a = ucb1x00_audio_alloc(ucb); -+ if (a) { -+ a->state.input_dma = ucb->mcp->dma_audio_rd; -+ a->state.input_id = "UCB1x00 audio in"; -+ a->state.output_dma = ucb->mcp->dma_audio_wr; -+ a->state.output_id = "UCB1x00 audio out"; -+ a->dev_id = register_sound_dsp(&a->fops, -1); -+ a->mix_id = register_sound_mixer(&a->mops, -1); -+ a->ctrl_a = 0; -+ a->ctrl_b = UCB_AC_B_IN_ENA|UCB_AC_B_OUT_ENA; -+ audio = a; -+ } -+ -+ a = ucb1x00_audio_alloc(ucb); -+ if (a) { -+#if 0 -+ a->daa_oh_bit = UCB_IO_8; -+ -+ ucb1x00_enable(ucb); -+ ucb1x00_io_write(ucb, a->daa_oh_bit, 0); -+ ucb1x00_io_set_dir(ucb, UCB_IO_7 | UCB_IO_6, a->daa_oh_bit); -+ ucb1x00_disable(ucb); -+#endif -+ -+ a->telecom = 1; -+ a->state.input_dma = ucb->mcp->dma_telco_rd; -+ a->state.input_id = "UCB1x00 telco in"; -+ a->state.output_dma = ucb->mcp->dma_telco_wr; -+ a->state.output_id = "UCB1x00 telco out"; -+ a->dev_id = register_sound_dsp(&a->fops, -1); -+ a->mix_id = register_sound_mixer(&a->mops, -1); -+ a->ctrl_a = 0; -+ a->ctrl_b = UCB_TC_B_IN_ENA|UCB_TC_B_OUT_ENA; -+ telecom = a; -+ } -+ -+ return 0; -+} -+ -+static void __exit ucb1x00_audio_exit(void) -+{ -+ unregister_sound_dsp(telecom->dev_id); -+ unregister_sound_dsp(audio->dev_id); -+ unregister_sound_mixer(telecom->mix_id); -+ unregister_sound_mixer(audio->mix_id); -+} -+ -+module_init(ucb1x00_audio_init); -+module_exit(ucb1x00_audio_exit); -+ -+MODULE_AUTHOR("Russell King "); -+MODULE_DESCRIPTION("UCB1x00 telecom/audio driver"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.4.26/drivers/misc/ucb1x00-core.c linux-2.4.26-vrs1/drivers/misc/ucb1x00-core.c ---- linux-2.4.26/drivers/misc/ucb1x00-core.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/misc/ucb1x00-core.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,651 @@ -+/* -+ * linux/drivers/misc/ucb1x00-core.c -+ * -+ * Copyright (C) 2001 Russell King, All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License. -+ * -+ * The UCB1x00 core driver provides basic services for handling IO, -+ * the ADC, interrupts, and accessing registers. It is designed -+ * such that everything goes through this layer, thereby providing -+ * a consistent locking methodology, as well as allowing the drivers -+ * to be used on other non-MCP-enabled hardware platforms. -+ * -+ * Note that all locks are private to this file. Nothing else may -+ * touch them. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "ucb1x00.h" -+ -+/** -+ * ucb1x00_io_set_dir - set IO direction -+ * @ucb: UCB1x00 structure describing chip -+ * @in: bitfield of IO pins to be set as inputs -+ * @out: bitfield of IO pins to be set as outputs -+ * -+ * Set the IO direction of the ten general purpose IO pins on -+ * the UCB1x00 chip. The @in bitfield has priority over the -+ * @out bitfield, in that if you specify a pin as both input -+ * and output, it will end up as an input. -+ * -+ * ucb1x00_enable must have been called to enable the comms -+ * before using this function. -+ * -+ * This function takes a spinlock, disabling interrupts. -+ */ -+void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int in, unsigned int out) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ucb->io_lock, flags); -+ ucb->io_dir |= out; -+ ucb->io_dir &= ~in; -+ -+ ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); -+ spin_unlock_irqrestore(&ucb->io_lock, flags); -+} -+ -+/** -+ * ucb1x00_io_write - set or clear IO outputs -+ * @ucb: UCB1x00 structure describing chip -+ * @set: bitfield of IO pins to set to logic '1' -+ * @clear: bitfield of IO pins to set to logic '0' -+ * -+ * Set the IO output state of the specified IO pins. The value -+ * is retained if the pins are subsequently configured as inputs. -+ * The @clear bitfield has priority over the @set bitfield - -+ * outputs will be cleared. -+ * -+ * ucb1x00_enable must have been called to enable the comms -+ * before using this function. -+ * -+ * This function takes a spinlock, disabling interrupts. -+ */ -+void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int set, unsigned int clear) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ucb->io_lock, flags); -+ ucb->io_out |= set; -+ ucb->io_out &= ~clear; -+ -+ ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); -+ spin_unlock_irqrestore(&ucb->io_lock, flags); -+} -+ -+/** -+ * ucb1x00_io_read - read the current state of the IO pins -+ * @ucb: UCB1x00 structure describing chip -+ * -+ * Return a bitfield describing the logic state of the ten -+ * general purpose IO pins. -+ * -+ * ucb1x00_enable must have been called to enable the comms -+ * before using this function. -+ * -+ * This function does not take any semaphores or spinlocks. -+ */ -+unsigned int ucb1x00_io_read(struct ucb1x00 *ucb) -+{ -+ return ucb1x00_reg_read(ucb, UCB_IO_DATA); -+} -+ -+/* -+ * UCB1300 data sheet says we must: -+ * 1. enable ADC => 5us (including reference startup time) -+ * 2. select input => 51*tsibclk => 4.3us -+ * 3. start conversion => 102*tsibclk => 8.5us -+ * (tsibclk = 1/11981000) -+ * Period between SIB 128-bit frames = 10.7us -+ */ -+ -+/** -+ * ucb1x00_adc_enable - enable the ADC converter -+ * @ucb: UCB1x00 structure describing chip -+ * -+ * Enable the ucb1x00 and ADC converter on the UCB1x00 for use. -+ * Any code wishing to use the ADC converter must call this -+ * function prior to using it. -+ * -+ * This function takes the ADC semaphore to prevent two or more -+ * concurrent uses, and therefore may sleep. As a result, it -+ * can only be called from process context, not interrupt -+ * context. -+ * -+ * You should release the ADC as soon as possible using -+ * ucb1x00_adc_disable. -+ */ -+void ucb1x00_adc_enable(struct ucb1x00 *ucb) -+{ -+ down(&ucb->adc_sem); -+ -+ ucb->adc_cr |= UCB_ADC_ENA; -+ -+ ucb1x00_enable(ucb); -+ ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr); -+} -+ -+/** -+ * ucb1x00_adc_read - read the specified ADC channel -+ * @ucb: UCB1x00 structure describing chip -+ * @adc_channel: ADC channel mask -+ * @sync: wait for syncronisation pulse. -+ * -+ * Start an ADC conversion and wait for the result. Note that -+ * synchronised ADC conversions (via the ADCSYNC pin) must wait -+ * until the trigger is asserted and the conversion is finished. -+ * -+ * This function currently spins waiting for the conversion to -+ * complete (2 frames max without sync). -+ * -+ * If called for a synchronised ADC conversion, it may sleep -+ * with the ADC semaphore held. -+ */ -+unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync) -+{ -+ unsigned int val; -+ -+ if (sync) -+ adc_channel |= UCB_ADC_SYNC_ENA; -+ -+ ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel); -+ ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel | UCB_ADC_START); -+ -+ for (;;) { -+ val = ucb1x00_reg_read(ucb, UCB_ADC_DATA); -+ if (val & UCB_ADC_DAT_VAL) -+ break; -+ /* yield to other processes */ -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(1); -+ } -+ -+ return UCB_ADC_DAT(val); -+} -+ -+/** -+ * ucb1x00_adc_disable - disable the ADC converter -+ * @ucb: UCB1x00 structure describing chip -+ * -+ * Disable the ADC converter and release the ADC semaphore. -+ */ -+void ucb1x00_adc_disable(struct ucb1x00 *ucb) -+{ -+ ucb->adc_cr &= ~UCB_ADC_ENA; -+ ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr); -+ ucb1x00_disable(ucb); -+ -+ up(&ucb->adc_sem); -+} -+ -+#ifdef CONFIG_PM -+static int ucb1x00_pm (struct pm_dev *dev, pm_request_t rqst, void *data) -+{ -+ struct ucb1x00 *ucb = (struct ucb1x00 *)dev->data; -+ unsigned int isr; -+ -+ if (rqst == PM_RESUME) { -+ ucb1x00_enable(ucb); -+ isr = ucb1x00_reg_read(ucb, UCB_IE_STATUS); -+ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr); -+ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); -+ ucb1x00_disable(ucb); -+ } -+ -+ return 0; -+} -+#endif -+ -+/* -+ * UCB1x00 Interrupt handling. -+ * -+ * The UCB1x00 can generate interrupts when the SIBCLK is stopped. -+ * Since we need to read an internal register, we must re-enable -+ * SIBCLK to talk to the chip. We leave the clock running until -+ * we have finished processing all interrupts from the chip. -+ */ -+static void ucb1x00_irq(int irqnr, void *devid, struct pt_regs *regs) -+{ -+ struct ucb1x00 *ucb = devid; -+ struct ucb1x00_irq *irq; -+ unsigned int isr, i; -+ -+ ucb1x00_enable(ucb); -+ isr = ucb1x00_reg_read(ucb, UCB_IE_STATUS); -+ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr); -+ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); -+ -+ for (i = 0, irq = ucb->irq_handler; i < 16 && isr; i++, isr >>= 1, irq++) -+ if (isr & 1 && irq->fn) -+ irq->fn(i, irq->devid); -+ ucb1x00_disable(ucb); -+} -+ -+/** -+ * ucb1x00_hook_irq - hook a UCB1x00 interrupt -+ * @ucb: UCB1x00 structure describing chip -+ * @idx: interrupt index -+ * @fn: function to call when interrupt is triggered -+ * @devid: device id to pass to interrupt handler -+ * -+ * Hook the specified interrupt. You can only register one handler -+ * for each interrupt source. The interrupt source is not enabled -+ * by this function; use ucb1x00_enable_irq instead. -+ * -+ * Interrupt handlers will be called with other interrupts enabled. -+ * -+ * Returns zero on success, or one of the following errors: -+ * -EINVAL if the interrupt index is invalid -+ * -EBUSY if the interrupt has already been hooked -+ */ -+int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid) -+{ -+ struct ucb1x00_irq *irq; -+ int ret = -EINVAL; -+ -+ if (idx < 16) { -+ irq = ucb->irq_handler + idx; -+ ret = -EBUSY; -+ -+ spin_lock_irq(&ucb->lock); -+ if (irq->fn == NULL) { -+ irq->devid = devid; -+ irq->fn = fn; -+ ret = 0; -+ } -+ spin_unlock_irq(&ucb->lock); -+ } -+ return ret; -+} -+ -+/** -+ * ucb1x00_enable_irq - enable an UCB1x00 interrupt source -+ * @ucb: UCB1x00 structure describing chip -+ * @idx: interrupt index -+ * @edges: interrupt edges to enable -+ * -+ * Enable the specified interrupt to trigger on %UCB_RISING, -+ * %UCB_FALLING or both edges. The interrupt should have been -+ * hooked by ucb1x00_hook_irq. -+ */ -+void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges) -+{ -+ unsigned long flags; -+ -+ if (idx < 16) { -+ spin_lock_irqsave(&ucb->lock, flags); -+ -+ ucb1x00_enable(ucb); -+ if (edges & UCB_RISING) { -+ ucb->irq_ris_enbl |= 1 << idx; -+ ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl); -+ } -+ if (edges & UCB_FALLING) { -+ ucb->irq_fal_enbl |= 1 << idx; -+ ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl); -+ } -+ ucb1x00_disable(ucb); -+ spin_unlock_irqrestore(&ucb->lock, flags); -+ } -+} -+ -+/** -+ * ucb1x00_disable_irq - disable an UCB1x00 interrupt source -+ * @ucb: UCB1x00 structure describing chip -+ * @edges: interrupt edges to disable -+ * -+ * Disable the specified interrupt triggering on the specified -+ * (%UCB_RISING, %UCB_FALLING or both) edges. -+ */ -+void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges) -+{ -+ unsigned long flags; -+ -+ if (idx < 16) { -+ spin_lock_irqsave(&ucb->lock, flags); -+ -+ ucb1x00_enable(ucb); -+ if (edges & UCB_RISING) { -+ ucb->irq_ris_enbl &= ~(1 << idx); -+ ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl); -+ } -+ if (edges & UCB_FALLING) { -+ ucb->irq_fal_enbl &= ~(1 << idx); -+ ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl); -+ } -+ ucb1x00_disable(ucb); -+ spin_unlock_irqrestore(&ucb->lock, flags); -+ } -+} -+ -+/** -+ * ucb1x00_free_irq - disable and free the specified UCB1x00 interrupt -+ * @ucb: UCB1x00 structure describing chip -+ * @idx: interrupt index -+ * @devid: device id. -+ * -+ * Disable the interrupt source and remove the handler. devid must -+ * match the devid passed when hooking the interrupt. -+ * -+ * Returns zero on success, or one of the following errors: -+ * -EINVAL if the interrupt index is invalid -+ * -ENOENT if devid does not match -+ */ -+int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid) -+{ -+ struct ucb1x00_irq *irq; -+ int ret; -+ -+ if (idx >= 16) -+ goto bad; -+ -+ irq = ucb->irq_handler + idx; -+ ret = -ENOENT; -+ -+ spin_lock_irq(&ucb->lock); -+ if (irq->devid == devid) { -+ ucb->irq_ris_enbl &= ~(1 << idx); -+ ucb->irq_fal_enbl &= ~(1 << idx); -+ -+ ucb1x00_enable(ucb); -+ ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl); -+ ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl); -+ ucb1x00_disable(ucb); -+ -+ irq->fn = NULL; -+ irq->devid = NULL; -+ ret = 0; -+ } -+ spin_unlock_irq(&ucb->lock); -+ return ret; -+ -+bad: -+ printk(KERN_ERR "%s: freeing bad irq %d\n", __FUNCTION__, idx); -+ return -EINVAL; -+} -+ -+/* -+ * Try to probe our interrupt, rather than relying on lots of -+ * hard-coded machine dependencies. For reference, the expected -+ * IRQ mappings are: -+ * -+ * Machine Default IRQ -+ * adsbitsy IRQ_GPCIN4 -+ * cerf IRQ_GPIO_UCB1200_IRQ -+ * flexanet IRQ_GPIO_GUI -+ * freebird IRQ_GPIO_FREEBIRD_UCB1300_IRQ -+ * graphicsclient IRQ_GRAPHICSCLIENT_UCB1200 -+ * graphicsmaster IRQ_GRAPHICSMASTER_UCB1200 -+ * lart LART_IRQ_UCB1200 -+ * omnimeter IRQ_GPIO23 -+ * pfs168 IRQ_GPIO_UCB1300_IRQ -+ * simpad IRQ_GPIO_UCB1300_IRQ -+ * shannon SHANNON_IRQ_GPIO_IRQ_CODEC -+ * yopy IRQ_GPIO_UCB1200_IRQ -+ */ -+static int __init ucb1x00_detect_irq(struct ucb1x00 *ucb) -+{ -+ unsigned long mask; -+ -+ mask = probe_irq_on(); -+ if (!mask) -+ return NO_IRQ; -+ -+ /* -+ * Enable the ADC interrupt. -+ */ -+ ucb1x00_reg_write(ucb, UCB_IE_RIS, UCB_IE_ADC); -+ ucb1x00_reg_write(ucb, UCB_IE_FAL, UCB_IE_ADC); -+ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff); -+ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); -+ -+ /* -+ * Cause an ADC interrupt. -+ */ -+ ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA); -+ ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START); -+ -+ /* -+ * Wait for the conversion to complete. -+ */ -+ while ((ucb1x00_reg_read(ucb, UCB_ADC_DATA) & UCB_ADC_DAT_VAL) == 0); -+ ucb1x00_reg_write(ucb, UCB_ADC_CR, 0); -+ -+ /* -+ * Disable and clear interrupt. -+ */ -+ ucb1x00_reg_write(ucb, UCB_IE_RIS, 0); -+ ucb1x00_reg_write(ucb, UCB_IE_FAL, 0); -+ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff); -+ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); -+ -+ /* -+ * Read triggered interrupt. -+ */ -+ return probe_irq_off(mask); -+} -+ -+/* -+ * This configures the UCB1x00 layer depending on the machine type -+ * we're running on. The UCB1x00 drivers should not contain any -+ * machine dependencies. -+ * -+ * We can get rid of some of these dependencies by using existing -+ * facilities provided by the kernel - namely IRQ probing. The -+ * machine specific files are expected to setup the IRQ levels on -+ * initialisation. With any luck, we'll get rid of all the -+ * machine dependencies here. -+ */ -+static int __init ucb1x00_configure(struct ucb1x00 *ucb) -+{ -+ unsigned int irq_gpio_pin = 0; -+ int irq, default_irq = NO_IRQ; -+ -+ if (machine_is_adsbitsy()) -+ default_irq = IRQ_GPCIN4; -+ -+// if (machine_is_assabet()) -+// default_irq = IRQ_GPIO23; -+ -+#ifdef CONFIG_SA1100_CERF -+ if (machine_is_cerf()) -+ default_irq = IRQ_GPIO_UCB1200_IRQ; -+#endif -+#ifdef CONFIG_SA1100_FREEBIRD -+ if (machine_is_freebird()) -+ default_irq = IRQ_GPIO_FREEBIRD_UCB1300_IRQ; -+#endif -+#if defined(CONFIG_SA1100_GRAPHICSCLIENT) -+// if (machine_is_graphicsclient()) -+// default_irq = IRQ_GRAPHICSCLIENT_UCB1200; -+#endif -+#if defined(CONFIG_SA1100_GRAPICSMASTER) -+ if (machine_is_graphicsmaster()) -+ default_irq = IRQ_GRAPHICSMASTER_UCB1200; -+#endif -+#ifdef CONFIG_SA1100_LART -+ if (machine_is_lart()) { -+ default_irq = LART_IRQ_UCB1200; -+ irq_gpio_pin = LART_GPIO_UCB1200; -+ } -+#endif -+ if (machine_is_omnimeter()) -+ default_irq = IRQ_GPIO23; -+ -+#ifdef CONFIG_SA1100_PFS168 -+ if (machine_is_pfs168()) -+ default_irq = IRQ_GPIO_UCB1300_IRQ; -+#endif -+#ifdef CONFIG_SA1100_SIMPAD -+ if (machine_is_simpad()) -+ default_irq = IRQ_GPIO_UCB1300_IRQ; -+#endif -+#ifdef CONFIG_SA1100_SIMPUTER -+ if (machine_is_simputer()) { -+ default_irq = IRQ_GPIO_UCB1300_IRQ; -+ irq_gpio_pin = GPIO_UCB1300_IRQ; -+ } -+#endif -+ if (machine_is_shannon()) -+ default_irq = SHANNON_IRQ_GPIO_IRQ_CODEC; -+#ifdef CONFIG_SA1100_YOPY -+ if (machine_is_yopy()) -+ default_irq = IRQ_GPIO_UCB1200_IRQ; -+#endif -+#ifdef CONFIG_SA1100_ACCELENT -+ if (machine_is_accelent_sa()) { -+ ucb->irq = IRQ_GPIO_UCB1200_IRQ; -+ irq_gpio_pin = GPIO_UCB1200_IRQ; -+ } -+#endif -+ -+ /* -+ * Eventually, this will disappear. -+ */ -+ if (irq_gpio_pin) -+ set_GPIO_IRQ_edge(irq_gpio_pin, GPIO_RISING_EDGE); -+ -+ irq = ucb1x00_detect_irq(ucb); -+ if (irq != NO_IRQ) { -+ if (default_irq != NO_IRQ && irq != default_irq) -+ printk(KERN_ERR "UCB1x00: probed IRQ%d != default IRQ%d\n", -+ irq, default_irq); -+ if (irq == default_irq) -+ printk(KERN_ERR "UCB1x00: probed IRQ%d correctly. " -+ "Please remove machine dependencies from " -+ "ucb1x00-core.c\n", irq); -+ ucb->irq = irq; -+ } else { -+ printk(KERN_ERR "UCB1x00: IRQ probe failed, using IRQ%d\n", -+ default_irq); -+ ucb->irq = default_irq; -+ } -+ -+ return ucb->irq == NO_IRQ ? -ENODEV : 0; -+} -+ -+struct ucb1x00 *my_ucb; -+ -+/** -+ * ucb1x00_get - get the UCB1x00 structure describing a chip -+ * @ucb: UCB1x00 structure describing chip -+ * -+ * Return the UCB1x00 structure describing a chip. -+ * -+ * FIXME: Currently very noddy indeed, which currently doesn't -+ * matter since we only support one chip. -+ */ -+struct ucb1x00 *ucb1x00_get(void) -+{ -+ return my_ucb; -+} -+ -+static int __init ucb1x00_init(void) -+{ -+ struct mcp *mcp; -+ unsigned int id; -+ int ret = -ENODEV; -+ -+ mcp = mcp_get(); -+ if (!mcp) -+ goto no_mcp; -+ -+ mcp_enable(mcp); -+ id = mcp_reg_read(mcp, UCB_ID); -+ -+ if (id != UCB_ID_1200 && id != UCB_ID_1300) { -+ printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id); -+ goto out; -+ } -+ -+ my_ucb = kmalloc(sizeof(struct ucb1x00), GFP_KERNEL); -+ ret = -ENOMEM; -+ if (!my_ucb) -+ goto out; -+ -+ if (machine_is_shannon()) { -+ /* reset the codec */ -+ GPDR |= SHANNON_GPIO_CODEC_RESET; -+ GPCR = SHANNON_GPIO_CODEC_RESET; -+ GPSR = SHANNON_GPIO_CODEC_RESET; -+ -+ } -+ -+ memset(my_ucb, 0, sizeof(struct ucb1x00)); -+ -+ spin_lock_init(&my_ucb->lock); -+ spin_lock_init(&my_ucb->io_lock); -+ sema_init(&my_ucb->adc_sem, 1); -+ -+ my_ucb->id = id; -+ my_ucb->mcp = mcp; -+ -+ ret = ucb1x00_configure(my_ucb); -+ if (ret) -+ goto out; -+ -+ ret = request_irq(my_ucb->irq, ucb1x00_irq, 0, "UCB1x00", my_ucb); -+ if (ret) { -+ printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n", -+ my_ucb->irq, ret); -+ kfree(my_ucb); -+ my_ucb = NULL; -+ goto out; -+ } -+ -+#ifdef CONFIG_PM -+ my_ucb->pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ucb1x00_pm); -+ if (my_ucb->pmdev == NULL) -+ printk("ucb1x00: unable to register in PM.\n"); -+ else -+ my_ucb->pmdev->data = my_ucb; -+#endif -+ -+out: -+ mcp_disable(mcp); -+no_mcp: -+ return ret; -+} -+ -+static void __exit ucb1x00_exit(void) -+{ -+ free_irq(my_ucb->irq, my_ucb); -+ kfree(my_ucb); -+} -+ -+module_init(ucb1x00_init); -+module_exit(ucb1x00_exit); -+ -+EXPORT_SYMBOL(ucb1x00_get); -+ -+EXPORT_SYMBOL(ucb1x00_io_set_dir); -+EXPORT_SYMBOL(ucb1x00_io_write); -+EXPORT_SYMBOL(ucb1x00_io_read); -+ -+EXPORT_SYMBOL(ucb1x00_adc_enable); -+EXPORT_SYMBOL(ucb1x00_adc_read); -+EXPORT_SYMBOL(ucb1x00_adc_disable); -+ -+EXPORT_SYMBOL(ucb1x00_hook_irq); -+EXPORT_SYMBOL(ucb1x00_free_irq); -+EXPORT_SYMBOL(ucb1x00_enable_irq); -+EXPORT_SYMBOL(ucb1x00_disable_irq); -+ -+MODULE_AUTHOR("Russell King "); -+MODULE_DESCRIPTION("UCB1x00 core driver"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.4.26/drivers/misc/ucb1x00-ts.c linux-2.4.26-vrs1/drivers/misc/ucb1x00-ts.c ---- linux-2.4.26/drivers/misc/ucb1x00-ts.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/misc/ucb1x00-ts.c 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,664 @@ -+/* -+ * linux/drivers/misc/ucb1x00-ts.c -+ * -+ * Copyright (C) 2001 Russell King, All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * 21-Jan-2002 : -+ * -+ * Added support for synchronous A/D mode. This mode is useful to -+ * avoid noise induced in the touchpanel by the LCD, provided that -+ * the UCB1x00 has a valid LCD sync signal routed to its ADCSYNC pin. -+ * It is important to note that the signal connected to the ADCSYNC -+ * pin should provide pulses even when the LCD is blanked, otherwise -+ * a pen touch needed to unblank the LCD will never be read. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "ucb1x00.h" -+ -+/* -+ * Define this if you want the UCB1x00 stuff to talk to the input layer -+ */ -+#undef USE_INPUT -+ -+#ifndef USE_INPUT -+ -+#include -+#include -+#include -+ -+/* -+ * This structure is nonsense - millisecs is not very useful -+ * since the field size is too small. Also, we SHOULD NOT -+ * be exposing jiffies to user space directly. -+ */ -+struct ts_event { -+ u16 pressure; -+ u16 x; -+ u16 y; -+ u16 pad; -+ struct timeval stamp; -+}; -+ -+#define NR_EVENTS 16 -+ -+#else -+ -+#include -+ -+#endif -+ -+struct ucb1x00_ts { -+#ifdef USE_INPUT -+ struct input_dev idev; -+#endif -+ struct ucb1x00 *ucb; -+#ifdef CONFIG_PM -+ struct pm_dev *pmdev; -+#endif -+ -+ wait_queue_head_t irq_wait; -+ struct semaphore sem; -+ struct completion init_exit; -+ struct task_struct *rtask; -+ int use_count; -+ u16 x_res; -+ u16 y_res; -+ -+#ifndef USE_INPUT -+ struct fasync_struct *fasync; -+ wait_queue_head_t read_wait; -+ u8 evt_head; -+ u8 evt_tail; -+ struct ts_event events[NR_EVENTS]; -+#endif -+ int restart:1; -+ int adcsync:1; -+}; -+ -+static struct ucb1x00_ts ucbts; -+static int adcsync = UCB_NOSYNC; -+ -+static int ucb1x00_ts_startup(struct ucb1x00_ts *ts); -+static void ucb1x00_ts_shutdown(struct ucb1x00_ts *ts); -+ -+#ifndef USE_INPUT -+ -+#define ucb1x00_ts_evt_pending(ts) ((volatile u8)(ts)->evt_head != (ts)->evt_tail) -+#define ucb1x00_ts_evt_get(ts) ((ts)->events + (ts)->evt_tail) -+#define ucb1x00_ts_evt_pull(ts) ((ts)->evt_tail = ((ts)->evt_tail + 1) & (NR_EVENTS - 1)) -+#define ucb1x00_ts_evt_clear(ts) ((ts)->evt_head = (ts)->evt_tail = 0) -+ -+static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y) -+{ -+ int next_head; -+ -+ next_head = (ts->evt_head + 1) & (NR_EVENTS - 1); -+ if (next_head != ts->evt_tail) { -+ ts->events[ts->evt_head].pressure = pressure; -+ ts->events[ts->evt_head].x = x; -+ ts->events[ts->evt_head].y = y; -+ do_gettimeofday(&ts->events[ts->evt_head].stamp); -+ ts->evt_head = next_head; -+ -+ if (ts->fasync) -+ kill_fasync(&ts->fasync, SIGIO, POLL_IN); -+ wake_up_interruptible(&ts->read_wait); -+ } -+} -+ -+static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts) -+{ -+ ucb1x00_ts_evt_add(ts, 0, 0, 0); -+} -+ -+/* -+ * User space driver interface. -+ */ -+static ssize_t -+ucb1x00_ts_read(struct file *filp, char *buffer, size_t count, loff_t *ppos) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ struct ucb1x00_ts *ts = filp->private_data; -+ char *ptr = buffer; -+ int err = 0; -+ -+ add_wait_queue(&ts->read_wait, &wait); -+ while (count >= sizeof(struct ts_event)) { -+ err = -ERESTARTSYS; -+ if (signal_pending(current)) -+ break; -+ -+ if (ucb1x00_ts_evt_pending(ts)) { -+ struct ts_event *evt = ucb1x00_ts_evt_get(ts); -+ -+ err = copy_to_user(ptr, evt, sizeof(struct ts_event)); -+ ucb1x00_ts_evt_pull(ts); -+ -+ if (err) -+ break; -+ -+ ptr += sizeof(struct ts_event); -+ count -= sizeof(struct ts_event); -+ continue; -+ } -+ -+ set_current_state(TASK_INTERRUPTIBLE); -+ err = -EAGAIN; -+ if (filp->f_flags & O_NONBLOCK) -+ break; -+ schedule(); -+ } -+ current->state = TASK_RUNNING; -+ remove_wait_queue(&ts->read_wait, &wait); -+ -+ return ptr == buffer ? err : ptr - buffer; -+} -+ -+static unsigned int ucb1x00_ts_poll(struct file *filp, poll_table *wait) -+{ -+ struct ucb1x00_ts *ts = filp->private_data; -+ int ret = 0; -+ -+ poll_wait(filp, &ts->read_wait, wait); -+ if (ucb1x00_ts_evt_pending(ts)) -+ ret = POLLIN | POLLRDNORM; -+ -+ return ret; -+} -+ -+static int ucb1x00_ts_fasync(int fd, struct file *filp, int on) -+{ -+ struct ucb1x00_ts *ts = filp->private_data; -+ -+ return fasync_helper(fd, filp, on, &ts->fasync); -+} -+ -+static int ucb1x00_ts_open(struct inode *inode, struct file *filp) -+{ -+ struct ucb1x00_ts *ts = &ucbts; -+ int ret = 0; -+ -+ ret = ucb1x00_ts_startup(ts); -+ if (ret == 0) -+ filp->private_data = ts; -+ -+ return ret; -+} -+ -+/* -+ * Release touchscreen resources. Disable IRQs. -+ */ -+static int ucb1x00_ts_release(struct inode *inode, struct file *filp) -+{ -+ struct ucb1x00_ts *ts = filp->private_data; -+ -+ down(&ts->sem); -+ ucb1x00_ts_fasync(-1, filp, 0); -+ ucb1x00_ts_shutdown(ts); -+ up(&ts->sem); -+ -+ return 0; -+} -+ -+static struct file_operations ucb1x00_fops = { -+ owner: THIS_MODULE, -+ read: ucb1x00_ts_read, -+ poll: ucb1x00_ts_poll, -+ open: ucb1x00_ts_open, -+ release: ucb1x00_ts_release, -+ fasync: ucb1x00_ts_fasync, -+}; -+ -+/* -+ * The official UCB1x00 touchscreen is a miscdevice: -+ * 10 char Non-serial mice, misc features -+ * 14 = /dev/touchscreen/ucb1x00 UCB 1x00 touchscreen -+ */ -+static struct miscdevice ucb1x00_ts_dev = { -+ minor: 14, -+ name: "touchscreen/ucb1x00", -+ fops: &ucb1x00_fops, -+}; -+ -+static inline int ucb1x00_ts_register(struct ucb1x00_ts *ts) -+{ -+ init_waitqueue_head(&ts->read_wait); -+ return misc_register(&ucb1x00_ts_dev); -+} -+ -+static inline void ucb1x00_ts_deregister(struct ucb1x00_ts *ts) -+{ -+ misc_deregister(&ucb1x00_ts_dev); -+} -+ -+#else -+ -+#define ucb1x00_ts_evt_clear(ts) do { } while (0) -+ -+static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y) -+{ -+ input_report_abs(&ts->idev, ABS_X, x); -+ input_report_abs(&ts->idev, ABS_Y, y); -+ input_report_abs(&ts->idev, ABS_PRESSURE, pressure); -+} -+ -+static int ucb1x00_ts_open(struct input_dev *idev) -+{ -+ struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev; -+ -+ return ucb1x00_ts_startup(ts); -+} -+ -+static void ucb1x00_ts_close(struct input_dev *idev) -+{ -+ struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev; -+ -+ down(&ts->sem); -+ ucb1x00_ts_shutdown(ts); -+ up(&ts->sem); -+} -+ -+static inline int ucb1x00_ts_register(struct ucb1x00_ts *ts) -+{ -+ ts->idev.name = "Touchscreen panel"; -+ ts->idev.idproduct = ts->ucb->id; -+ ts->idev.open = ucb1x00_ts_open; -+ ts->idev.close = ucb1x00_ts_close; -+ -+ __set_bit(EV_ABS, ts->idev.evbit); -+ __set_bit(ABS_X, ts->idev.absbit); -+ __set_bit(ABS_Y, ts->idev.absbit); -+ __set_bit(ABS_PRESSURE, ts->idev.absbit); -+ -+ input_register_device(&ts->idev); -+ -+ return 0; -+} -+ -+static inline void ucb1x00_ts_deregister(struct ucb1x00_ts *ts) -+{ -+ input_unregister_device(&ts->idev); -+} -+ -+#endif -+ -+/* -+ * Switch to interrupt mode. -+ */ -+static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts) -+{ -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | -+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | -+ UCB_TS_CR_MODE_INT); -+} -+ -+/* -+ * Switch to pressure mode, and read pressure. We don't need to wait -+ * here, since both plates are being driven. -+ */ -+static inline unsigned int ucb1x00_ts_read_pressure(struct ucb1x00_ts *ts) -+{ -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | -+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | -+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -+ -+ return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); -+} -+ -+/* -+ * Switch to X position mode and measure Y plate. We switch the plate -+ * configuration in pressure mode, then switch to position mode. This -+ * gives a faster response time. Even so, we need to wait about 55us -+ * for things to stabilise. -+ */ -+static inline unsigned int ucb1x00_ts_read_xpos(struct ucb1x00_ts *ts) -+{ -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | -+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | -+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | -+ UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); -+ -+ udelay(55); -+ -+ return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); -+} -+ -+/* -+ * Switch to Y position mode and measure X plate. We switch the plate -+ * configuration in pressure mode, then switch to position mode. This -+ * gives a faster response time. Even so, we need to wait about 55us -+ * for things to stabilise. -+ */ -+static inline unsigned int ucb1x00_ts_read_ypos(struct ucb1x00_ts *ts) -+{ -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | -+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | -+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | -+ UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); -+ -+ udelay(55); -+ -+ return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync); -+} -+ -+/* -+ * Switch to X plate resistance mode. Set MX to ground, PX to -+ * supply. Measure current. -+ */ -+static inline unsigned int ucb1x00_ts_read_xres(struct ucb1x00_ts *ts) -+{ -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | -+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -+ return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync); -+} -+ -+/* -+ * Switch to Y plate resistance mode. Set MY to ground, PY to -+ * supply. Measure current. -+ */ -+static inline unsigned int ucb1x00_ts_read_yres(struct ucb1x00_ts *ts) -+{ -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | -+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -+ return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync); -+} -+ -+/* -+ * This is a RT kernel thread that handles the ADC accesses -+ * (mainly so we can use semaphores in the UCB1200 core code -+ * to serialise accesses to the ADC). -+ */ -+static int ucb1x00_thread(void *_ts) -+{ -+ struct ucb1x00_ts *ts = _ts; -+ struct task_struct *tsk = current; -+ DECLARE_WAITQUEUE(wait, tsk); -+ int valid; -+ -+ ts->rtask = tsk; -+ -+ daemonize(); -+ reparent_to_init(); -+ strcpy(tsk->comm, "ktsd"); -+ tsk->tty = NULL; -+ /* -+ * We could run as a real-time thread. However, thus far -+ * this doesn't seem to be necessary. -+ */ -+// tsk->policy = SCHED_FIFO; -+// tsk->rt_priority = 1; -+ -+ /* only want to receive SIGKILL */ -+ spin_lock_irq(&tsk->sigmask_lock); -+ siginitsetinv(&tsk->blocked, sigmask(SIGKILL)); -+ recalc_sigpending(tsk); -+ spin_unlock_irq(&tsk->sigmask_lock); -+ -+ complete(&ts->init_exit); -+ -+ valid = 0; -+ -+ add_wait_queue(&ts->irq_wait, &wait); -+ for (;;) { -+ unsigned int x, y, p, val; -+ signed long timeout; -+ -+ ts->restart = 0; -+ -+ ucb1x00_adc_enable(ts->ucb); -+ -+ x = ucb1x00_ts_read_xpos(ts); -+ y = ucb1x00_ts_read_ypos(ts); -+ p = ucb1x00_ts_read_pressure(ts); -+ -+ /* -+ * Switch back to interrupt mode. -+ */ -+ ucb1x00_ts_mode_int(ts); -+ ucb1x00_adc_disable(ts->ucb); -+ -+ set_task_state(tsk, TASK_UNINTERRUPTIBLE); -+ schedule_timeout(HZ / 100); -+ if (signal_pending(tsk)) -+ break; -+ -+ ucb1x00_enable(ts->ucb); -+ val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR); -+ -+ if (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW)) { -+ set_task_state(tsk, TASK_INTERRUPTIBLE); -+ -+ ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING); -+ ucb1x00_disable(ts->ucb); -+ -+ /* -+ * If we spat out a valid sample set last time, -+ * spit out a "pen off" sample here. -+ */ -+ if (valid) { -+ ucb1x00_ts_event_release(ts); -+ valid = 0; -+ } -+ -+ timeout = MAX_SCHEDULE_TIMEOUT; -+ } else { -+ ucb1x00_disable(ts->ucb); -+ -+ /* -+ * Filtering is policy. Policy belongs in user -+ * space. We therefore leave it to user space -+ * to do any filtering they please. -+ */ -+ if (!ts->restart) { -+ ucb1x00_ts_evt_add(ts, p, x, y); -+ valid = 1; -+ } -+ -+ set_task_state(tsk, TASK_INTERRUPTIBLE); -+ timeout = HZ / 100; -+ } -+ -+ schedule_timeout(timeout); -+ if (signal_pending(tsk)) -+ break; -+ } -+ -+ remove_wait_queue(&ts->irq_wait, &wait); -+ -+ ts->rtask = NULL; -+ ucb1x00_ts_evt_clear(ts); -+ complete_and_exit(&ts->init_exit, 0); -+} -+ -+/* -+ * We only detect touch screen _touches_ with this interrupt -+ * handler, and even then we just schedule our task. -+ */ -+static void ucb1x00_ts_irq(int idx, void *id) -+{ -+ struct ucb1x00_ts *ts = id; -+ ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING); -+ wake_up(&ts->irq_wait); -+} -+ -+static int ucb1x00_ts_startup(struct ucb1x00_ts *ts) -+{ -+ int ret = 0; -+ -+ if (down_interruptible(&ts->sem)) -+ return -EINTR; -+ -+ if (ts->use_count++ != 0) -+ goto out; -+ -+ if (ts->rtask) -+ panic("ucb1x00: rtask running?"); -+ -+ init_waitqueue_head(&ts->irq_wait); -+ ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts); -+ if (ret < 0) -+ goto out; -+ -+ /* -+ * If we do this at all, we should allow the user to -+ * measure and read the X and Y resistance at any time. -+ */ -+ ucb1x00_adc_enable(ts->ucb); -+ ts->x_res = ucb1x00_ts_read_xres(ts); -+ ts->y_res = ucb1x00_ts_read_yres(ts); -+ ucb1x00_adc_disable(ts->ucb); -+ -+ init_completion(&ts->init_exit); -+ ret = kernel_thread(ucb1x00_thread, ts, 0); -+ if (ret >= 0) { -+ wait_for_completion(&ts->init_exit); -+ ret = 0; -+ } else { -+ ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); -+ } -+ -+ out: -+ if (ret) -+ ts->use_count--; -+ up(&ts->sem); -+ return ret; -+} -+ -+/* -+ * Release touchscreen resources. Disable IRQs. -+ */ -+static void ucb1x00_ts_shutdown(struct ucb1x00_ts *ts) -+{ -+ if (--ts->use_count == 0) { -+ if (ts->rtask) { -+ send_sig(SIGKILL, ts->rtask, 1); -+ wait_for_completion(&ts->init_exit); -+ } -+ -+ ucb1x00_enable(ts->ucb); -+ ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0); -+ ucb1x00_disable(ts->ucb); -+ } -+} -+ -+#ifdef CONFIG_PM -+static int ucb1x00_ts_pm (struct pm_dev *dev, pm_request_t rqst, void *data) -+{ -+ struct ucb1x00_ts *ts = (struct ucb1x00_ts *) (dev->data); -+ -+ if (rqst == PM_RESUME && ts->rtask != NULL) { -+ /* -+ * Restart the TS thread to ensure the -+ * TS interrupt mode is set up again -+ * after sleep. -+ */ -+ ts->restart = 1; -+ wake_up(&ts->irq_wait); -+ } -+ return 0; -+} -+#endif -+ -+ -+/* -+ * Initialisation. -+ */ -+static int __init ucb1x00_ts_init(void) -+{ -+ struct ucb1x00_ts *ts = &ucbts; -+ -+ ts->ucb = ucb1x00_get(); -+ if (!ts->ucb) -+ return -ENODEV; -+ -+ ts->adcsync = adcsync; -+ init_MUTEX(&ts->sem); -+ -+#ifdef CONFIG_PM -+ ts->pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ucb1x00_ts_pm); -+ if (ts->pmdev == NULL) -+ printk("ucb1x00_ts: unable to register in PM.\n"); -+ else -+ ts->pmdev->data = ts; -+#endif -+ return ucb1x00_ts_register(ts); -+} -+ -+static void __exit ucb1x00_ts_exit(void) -+{ -+ struct ucb1x00_ts *ts = &ucbts; -+ -+ ucb1x00_ts_deregister(ts); -+ -+#ifdef CONFIG_PM -+ if (ts->pmdev) -+ pm_unregister(ts->pmdev); -+#endif -+} -+ -+#ifndef MODULE -+ -+/* -+ * Parse kernel command-line options. -+ * -+ * syntax : ucbts=[sync|nosync],... -+ */ -+static int __init ucb1x00_ts_setup(char *str) -+{ -+ char *p; -+ -+ while ((p = strsep(&str, ",")) != NULL) { -+ if (strcmp(p, "sync") == 0) -+ adcsync = UCB_SYNC; -+ } -+ -+ return 1; -+} -+ -+__setup("ucbts=", ucb1x00_ts_setup); -+ -+#else -+ -+MODULE_PARM(adcsync, "i"); -+MODULE_PARM_DESC(adcsync, "Enable use of ADCSYNC signal"); -+ -+#endif -+ -+module_init(ucb1x00_ts_init); -+module_exit(ucb1x00_ts_exit); -+ -+MODULE_AUTHOR("Russell King "); -+MODULE_DESCRIPTION("UCB1x00 touchscreen driver"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.4.26/drivers/misc/ucb1x00.h linux-2.4.26-vrs1/drivers/misc/ucb1x00.h ---- linux-2.4.26/drivers/misc/ucb1x00.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/misc/ucb1x00.h 2004-01-14 21:32:25.000000000 +0000 -@@ -0,0 +1,232 @@ -+/* -+ * linux/drivers/misc/ucb1x00.h -+ * -+ * Copyright (C) 2001 Russell King, All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License. -+ */ -+#ifndef UCB1200_H -+#define UCB1200_H -+ -+#define UCB_IO_DATA 0x00 -+#define UCB_IO_DIR 0x01 -+ -+#define UCB_IO_0 (1 << 0) -+#define UCB_IO_1 (1 << 1) -+#define UCB_IO_2 (1 << 2) -+#define UCB_IO_3 (1 << 3) -+#define UCB_IO_4 (1 << 4) -+#define UCB_IO_5 (1 << 5) -+#define UCB_IO_6 (1 << 6) -+#define UCB_IO_7 (1 << 7) -+#define UCB_IO_8 (1 << 8) -+#define UCB_IO_9 (1 << 9) -+ -+#define UCB_IE_RIS 0x02 -+#define UCB_IE_FAL 0x03 -+#define UCB_IE_STATUS 0x04 -+#define UCB_IE_CLEAR 0x04 -+#define UCB_IE_ADC (1 << 11) -+#define UCB_IE_TSPX (1 << 12) -+#define UCB_IE_TSMX (1 << 13) -+#define UCB_IE_TCLIP (1 << 14) -+#define UCB_IE_ACLIP (1 << 15) -+ -+#define UCB_IRQ_TSPX 12 -+ -+#define UCB_TC_A 0x05 -+#define UCB_TC_A_LOOP (1 << 7) /* UCB1200 */ -+#define UCB_TC_A_AMPL (1 << 7) /* UCB1300 */ -+ -+#define UCB_TC_B 0x06 -+#define UCB_TC_B_VOICE_ENA (1 << 3) -+#define UCB_TC_B_CLIP (1 << 4) -+#define UCB_TC_B_ATT (1 << 6) -+#define UCB_TC_B_SIDE_ENA (1 << 11) -+#define UCB_TC_B_MUTE (1 << 13) -+#define UCB_TC_B_IN_ENA (1 << 14) -+#define UCB_TC_B_OUT_ENA (1 << 15) -+ -+#define UCB_AC_A 0x07 -+#define UCB_AC_B 0x08 -+#define UCB_AC_B_LOOP (1 << 8) -+#define UCB_AC_B_MUTE (1 << 13) -+#define UCB_AC_B_IN_ENA (1 << 14) -+#define UCB_AC_B_OUT_ENA (1 << 15) -+ -+#define UCB_TS_CR 0x09 -+#define UCB_TS_CR_TSMX_POW (1 << 0) -+#define UCB_TS_CR_TSPX_POW (1 << 1) -+#define UCB_TS_CR_TSMY_POW (1 << 2) -+#define UCB_TS_CR_TSPY_POW (1 << 3) -+#define UCB_TS_CR_TSMX_GND (1 << 4) -+#define UCB_TS_CR_TSPX_GND (1 << 5) -+#define UCB_TS_CR_TSMY_GND (1 << 6) -+#define UCB_TS_CR_TSPY_GND (1 << 7) -+#define UCB_TS_CR_MODE_INT (0 << 8) -+#define UCB_TS_CR_MODE_PRES (1 << 8) -+#define UCB_TS_CR_MODE_POS (2 << 8) -+#define UCB_TS_CR_BIAS_ENA (1 << 11) -+#define UCB_TS_CR_TSPX_LOW (1 << 12) -+#define UCB_TS_CR_TSMX_LOW (1 << 13) -+ -+#define UCB_ADC_CR 0x0a -+#define UCB_ADC_SYNC_ENA (1 << 0) -+#define UCB_ADC_VREFBYP_CON (1 << 1) -+#define UCB_ADC_INP_TSPX (0 << 2) -+#define UCB_ADC_INP_TSMX (1 << 2) -+#define UCB_ADC_INP_TSPY (2 << 2) -+#define UCB_ADC_INP_TSMY (3 << 2) -+#define UCB_ADC_INP_AD0 (4 << 2) -+#define UCB_ADC_INP_AD1 (5 << 2) -+#define UCB_ADC_INP_AD2 (6 << 2) -+#define UCB_ADC_INP_AD3 (7 << 2) -+#define UCB_ADC_EXT_REF (1 << 5) -+#define UCB_ADC_START (1 << 7) -+#define UCB_ADC_ENA (1 << 15) -+ -+#define UCB_ADC_DATA 0x0b -+#define UCB_ADC_DAT_VAL (1 << 15) -+#define UCB_ADC_DAT(x) (((x) & 0x7fe0) >> 5) -+ -+#define UCB_ID 0x0c -+#define UCB_ID_1200 0x1004 -+#define UCB_ID_1300 0x1005 -+ -+#define UCB_MODE 0x0d -+#define UCB_MODE_DYN_VFLAG_ENA (1 << 12) -+#define UCB_MODE_AUD_OFF_CAN (1 << 13) -+ -+#include "mcp.h" -+ -+struct ucb1x00; -+ -+struct ucb1x00_irq { -+ void *devid; -+ void (*fn)(int, void *); -+}; -+ -+struct ucb1x00 { -+ spinlock_t lock; -+ struct mcp *mcp; -+ struct pm_dev *pmdev; -+ unsigned int irq; -+ struct semaphore adc_sem; -+ spinlock_t io_lock; -+ u16 id; -+ u16 io_dir; -+ u16 io_out; -+ u16 adc_cr; -+ u16 irq_fal_enbl; -+ u16 irq_ris_enbl; -+ struct ucb1x00_irq irq_handler[16]; -+}; -+ -+/** -+ * ucb1x00_clkrate - return the UCB1x00 SIB clock rate -+ * @ucb: UCB1x00 structure describing chip -+ * -+ * Return the SIB clock rate in Hz. -+ */ -+static inline unsigned int ucb1x00_clkrate(struct ucb1x00 *ucb) -+{ -+ return mcp_get_sclk_rate(ucb->mcp); -+} -+ -+/** -+ * ucb1x00_enable - enable the UCB1x00 SIB clock -+ * @ucb: UCB1x00 structure describing chip -+ * -+ * Enable the SIB clock. This can be called multiple times. -+ */ -+static inline void ucb1x00_enable(struct ucb1x00 *ucb) -+{ -+ mcp_enable(ucb->mcp); -+} -+ -+/** -+ * ucb1x00_disable - disable the UCB1x00 SIB clock -+ * @ucb: UCB1x00 structure describing chip -+ * -+ * Disable the SIB clock. The SIB clock will only be disabled -+ * when the number of ucb1x00_enable calls match the number of -+ * ucb1x00_disable calls. -+ */ -+static inline void ucb1x00_disable(struct ucb1x00 *ucb) -+{ -+ mcp_disable(ucb->mcp); -+} -+ -+/** -+ * ucb1x00_reg_write - write a UCB1x00 register -+ * @ucb: UCB1x00 structure describing chip -+ * @reg: UCB1x00 4-bit register index to write -+ * @val: UCB1x00 16-bit value to write -+ * -+ * Write the UCB1x00 register @reg with value @val. The SIB -+ * clock must be running for this function to return. -+ */ -+static inline void ucb1x00_reg_write(struct ucb1x00 *ucb, unsigned int reg, unsigned int val) -+{ -+ mcp_reg_write(ucb->mcp, reg, val); -+} -+ -+/** -+ * ucb1x00_reg_read - read a UCB1x00 register -+ * @ucb: UCB1x00 structure describing chip -+ * @reg: UCB1x00 4-bit register index to write -+ * -+ * Read the UCB1x00 register @reg and return its value. The SIB -+ * clock must be running for this function to return. -+ */ -+static inline unsigned int ucb1x00_reg_read(struct ucb1x00 *ucb, unsigned int reg) -+{ -+ return mcp_reg_read(ucb->mcp, reg); -+} -+/** -+ * ucb1x00_set_audio_divisor - -+ * @ucb: UCB1x00 structure describing chip -+ * @div: SIB clock divisor -+ */ -+static inline void ucb1x00_set_audio_divisor(struct ucb1x00 *ucb, unsigned int div) -+{ -+ mcp_set_audio_divisor(ucb->mcp, div); -+} -+ -+/** -+ * ucb1x00_set_telecom_divisor - -+ * @ucb: UCB1x00 structure describing chip -+ * @div: SIB clock divisor -+ */ -+static inline void ucb1x00_set_telecom_divisor(struct ucb1x00 *ucb, unsigned int div) -+{ -+ mcp_set_telecom_divisor(ucb->mcp, div); -+} -+ -+struct ucb1x00 *ucb1x00_get(void); -+ -+void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int, unsigned int); -+void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int, unsigned int); -+unsigned int ucb1x00_io_read(struct ucb1x00 *ucb); -+ -+#define UCB_NOSYNC (0) -+#define UCB_SYNC (1) -+ -+unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync); -+void ucb1x00_adc_enable(struct ucb1x00 *ucb); -+void ucb1x00_adc_disable(struct ucb1x00 *ucb); -+ -+/* -+ * Which edges of the IRQ do you want to control today? -+ */ -+#define UCB_RISING (1 << 0) -+#define UCB_FALLING (1 << 1) -+ -+int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid); -+void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges); -+void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges); -+int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid); -+ -+#endif -diff -urN linux-2.4.26/drivers/mtd/chips/cfi_probe.c linux-2.4.26-vrs1/drivers/mtd/chips/cfi_probe.c ---- linux-2.4.26/drivers/mtd/chips/cfi_probe.c 2003-06-13 15:51:34.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/mtd/chips/cfi_probe.c 2004-01-14 21:32:25.000000000 +0000 -@@ -65,6 +65,10 @@ - return 0; - } - cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); -+ -+ /* some devices don't respond to 0xF0, so send 0xFF to be sure */ -+ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); -+ - cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); - - if (!qry_present(map,base,cfi)) -@@ -84,6 +88,8 @@ - /* Eep. This chip also had the QRY marker. - * Is it an alias for the new one? */ - cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, cfi->device_type, NULL); -+ /* some devices don't respond to 0xF0, so send 0xFF to be sure */ -+ cfi_send_gen_cmd(0xFF, 0, chips[i].start, map, cfi, cfi->device_type, NULL); - - /* If the QRY marker goes away, it's an alias */ - if (!qry_present(map, chips[i].start, cfi)) { -@@ -96,7 +102,8 @@ - * too and if it's the same, assume it's an alias. */ - /* FIXME: Use other modes to do a proper check */ - cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); -- -+ /* some devices don't respond to 0xF0, so send 0xFF to be sure */ -+ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); - if (qry_present(map, base, cfi)) { - printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", - map->name, base, chips[i].start); -@@ -119,6 +126,10 @@ - /* Put it back into Read Mode */ - cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); - -+ /* some devices don't respond to 0xF0, so send 0xFF to be sure */ -+ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); -+ -+ - printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n", - map->name, cfi->interleave, cfi->device_type*8, base, - map->buswidth*8); -@@ -165,6 +176,20 @@ - cfi->cfiq->InterfaceDesc = le16_to_cpu(cfi->cfiq->InterfaceDesc); - cfi->cfiq->MaxBufWriteSize = le16_to_cpu(cfi->cfiq->MaxBufWriteSize); - -+ /* -+ * ST screwed up the CFI interface for buffer writes on their parts, -+ * so this needs to be fixed up by hand here. -+ * -+ * A possible enhancment is that instead of just reverting back -+ * to word write (as this does), we could use the ST specific double -+ * word write instead. -+ */ -+ -+ if (cfi_read_query(map,base) == 0x20){ -+ cfi->cfiq->BufWriteTimeoutTyp = 0; -+ cfi->cfiq->BufWriteTimeoutMax = 0; -+ } -+ - #ifdef DEBUG_CFI - /* Dump the information therein */ - print_cfi_ident(cfi->cfiq); -@@ -182,6 +207,9 @@ - /* Put it back into Read Mode */ - cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); - -+ /* some devices don't respond to 0xF0, so send 0xFF to be sure */ -+ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); -+ - return 1; - } - -diff -urN linux-2.4.26/drivers/mtd/chips/jedec_probe.c linux-2.4.26-vrs1/drivers/mtd/chips/jedec_probe.c ---- linux-2.4.26/drivers/mtd/chips/jedec_probe.c 2003-06-13 15:51:34.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/mtd/chips/jedec_probe.c 2004-04-18 21:33:04.000000000 +0100 -@@ -100,6 +100,8 @@ - #define M29W040B 0x00E3 - - /* SST */ -+#define SST29EE020 0x0010 -+#define SST29LE020 0x0012 - #define SST29EE512 0x005d - #define SST29LE512 0x003d - #define SST39LF800 0x2781 -@@ -839,6 +841,24 @@ - } - }, { - mfr_id: MANUFACTURER_SST, -+ dev_id: SST29EE020, -+ name: "SST 29EE020", -+ DevSize: SIZE_256KiB, -+ CmdSet: P_ID_SST_PAGE, -+ NumEraseRegions: 1, -+ regions: {ERASEINFO(0x01000,64), -+ } -+ }, { -+ mfr_id: MANUFACTURER_SST, -+ dev_id: SST29LE020, -+ name: "SST 29LE020", -+ DevSize: SIZE_256KiB, -+ CmdSet: P_ID_SST_PAGE, -+ NumEraseRegions: 1, -+ regions: {ERASEINFO(0x01000,64), -+ } -+ }, { -+ mfr_id: MANUFACTURER_SST, - dev_id: SST39LF020, - name: "SST 39LF020", - DevSize: SIZE_256KiB, -@@ -937,7 +957,20 @@ - struct cfi_private *cfi) - { - /* Reset */ -- cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); -+ -+ /* after checking the datasheets for SST, MACRONIX and ATMEL -+ * (oh and incidentaly the jedec spec - 3.5.3.3) the reset -+ * sequence is *supposed* to be 0xaa at 0x5555, 0x55 at -+ * 0x2aaa, 0xF0 at 0x5555 this will not affect the AMD chips -+ * as they will ignore the writes and dont care what address -+ * the F0 is written to */ -+ if(cfi->addr_unlock1) { -+ /*printk("reset unlock called %x %x \n",cfi->addr_unlock1,cfi->addr_unlock2);*/ -+ cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL); -+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL); -+ } -+ -+ cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); - /* Some misdesigned intel chips do not respond for 0xF0 for a reset, - * so ensure we're in read mode. Send both the Intel and the AMD command - * for this. Intel uses 0xff for this, AMD uses 0xff for NOP, so -diff -urN linux-2.4.26/drivers/mtd/devices/Config.in linux-2.4.26-vrs1/drivers/mtd/devices/Config.in ---- linux-2.4.26/drivers/mtd/devices/Config.in 2003-06-13 15:51:34.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/mtd/devices/Config.in 2004-01-14 21:32:25.000000000 +0000 -@@ -17,6 +17,15 @@ - if [ "$CONFIG_SA1100_LART" = "y" ]; then - dep_tristate ' 28F160xx flash driver for LART' CONFIG_MTD_LART $CONFIG_MTD - fi -+if [ "$CONFIG_ARCH_MX1ADS" = "y" ]; then -+ dep_tristate ' SyncFlash driver for MX1ADS' CONFIG_MTD_SYNCFLASH $CONFIG_MTD -+fi -+if [ "$CONFIG_ARCH_AT91RM9200" = "y" ]; then -+ dep_tristate ' AT91RM9200 DataFlash support' CONFIG_MTD_AT91_DATAFLASH $CONFIG_MTD -+ if [ "$CONFIG_MTD_AT91_DATAFLASH" = "y" -o "$CONFIG_MTD_AT91_DATAFLASH" = "m" ]; then -+ bool ' Enable DataFlash card? ' CONFIG_MTD_AT91_DATAFLASH_CARD -+ fi -+fi - dep_tristate ' Test driver using RAM' CONFIG_MTD_MTDRAM $CONFIG_MTD - if [ "$CONFIG_MTD_MTDRAM" = "y" -o "$CONFIG_MTD_MTDRAM" = "m" ]; then - int 'MTDRAM device size in KiB' CONFIG_MTDRAM_TOTAL_SIZE 4096 -diff -urN linux-2.4.26/drivers/mtd/devices/Makefile linux-2.4.26-vrs1/drivers/mtd/devices/Makefile ---- linux-2.4.26/drivers/mtd/devices/Makefile 2002-11-28 23:53:13.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/mtd/devices/Makefile 2004-01-14 21:32:25.000000000 +0000 -@@ -21,6 +21,7 @@ - obj-$(CONFIG_MTD_MS02NV) += ms02-nv.o - obj-$(CONFIG_MTD_MTDRAM) += mtdram.o - obj-$(CONFIG_MTD_LART) += lart.o -+obj-$(CONFIG_MTD_SYNCFLASH) += syncflash.o - obj-$(CONFIG_MTD_BLKMTD) += blkmtd.o - - include $(TOPDIR)/Rules.make -diff -urN linux-2.4.26/drivers/mtd/devices/syncflash.c linux-2.4.26-vrs1/drivers/mtd/devices/syncflash.c ---- linux-2.4.26/drivers/mtd/devices/syncflash.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/mtd/devices/syncflash.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,615 @@ -+/* -+ * MTD driver for Micron SyncFlash flash memory. -+ * -+ * Author: Jon McClintock -+ * -+ * Based loosely upon the LART flash driver, authored by Abraham vd Merwe -+ * . -+ * -+ * Copyright 2003, Blue Mug, Inc. for Motorola, Inc. -+ * -+ * This code 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. -+ * -+ * References: -+ * -+ * [1] Micron SyncFlash homepage -+ * - http://www.syncflash.com/ -+ * -+ * [2] MT28S4M16LC -- 4Mx16 SyncFlash memory datasheet -+ * - http://syncflash.com/pdfs/datasheets/mt28s4m16lc_6.pdf -+ * -+ * [3] MTD internal API documentation -+ * - http://www.linux-mtd.infradead.org/tech/ -+ * -+ * Limitations: -+ * -+ * Even though this driver is written for Micron SyncFlash, it is quite -+ * specific to the Motorola MX1 ADS development board. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* partition support */ -+#define HAVE_PARTITIONS -+#ifdef HAVE_PARTITIONS -+#include -+#endif -+ -+#ifndef CONFIG_ARCH_MX1ADS -+#error The SyncFlash driver currently only supports the MX1 ADS platform. -+#endif -+ -+/* -+ * General flash configuration parameters. -+ */ -+#define BUSWIDTH 4 -+#define FLASH_BLOCKSIZE (256 * 1024 * BUSWIDTH) -+#define FLASH_NUMBLOCKS 16 -+ -+#define BUSWIDTH 4 -+#define FLASH_ADDRESS IO_ADDRESS(MX1ADS_FLASH_BASE) -+ -+#define FLASH_MANUFACTURER 0x002C002C -+#define FLASH_DEVICE_ID 0x00D300D3 -+ -+/* -+ * The size and extent of the bootloader in flash. -+ */ -+#define NUM_BOOTLOADER_BLOCKS 1 -+#define BOOTLOADER_START 0x00000000 -+#define BOOTLOADER_LEN (NUM_BOOTLOADER_BLOCKS * FLASH_BLOCKSIZE) -+ -+/* -+ * The size and extent of the kernel in flash. -+ */ -+#define NUM_KERNEL_BLOCKS 1 -+#define KERNEL_START (BOOTLOADER_START + BOOTLOADER_LEN) -+#define KERNEL_LEN (NUM_KERNEL_BLOCKS * FLASH_BLOCKSIZE) -+ -+/* File system */ -+#define NUM_FILESYSTEM_BLOCKS 14 -+#define FILESYSTEM_START (KERNEL_START + KERNEL_LEN) -+#define FILESYSTEM_LEN (NUM_FILESYSTEM_BLOCKS * FLASH_BLOCKSIZE) -+ -+ -+/* -+ * SDRAM controller register location and values. These are very specific -+ * to the MX1. -+ */ -+#define SDRAMC_REGISTER IO_ADDRESS(0x00221004) -+ -+/* -+ * This the mask we use to get the start of a block from a given address. -+ */ -+#define BLOCK_MASK (0xFFF00000) -+ -+/* -+ * This is the A10 address line of the SyncFlash; it's used to initiate -+ * a precharge command. -+ */ -+#define SYNCFLASH_A10 (0x00100000) -+ -+/* -+ * SDRAM controller MODE settings. -+ */ -+#define CMD_NORMAL (0x81020300) /* Normal Mode */ -+#define CMD_PREC (CMD_NORMAL + 0x10000000) /* Precharge command */ -+#define CMD_AUTO (CMD_NORMAL + 0x20000000) /* Auto refresh */ -+#define CMD_LMR (CMD_NORMAL + 0x30000000) /* Load Mode Register */ -+#define CMD_LCR (CMD_NORMAL + 0x60000000) /* LCR Command */ -+#define CMD_PROGRAM (CMD_NORMAL + 0x70000000) /* SyncFlash Program */ -+ -+/* -+ * SyncFlash LCR Commands adjusted for the DBMX1 AHB internal address bus . -+ */ -+#define LCR_READ_STATUS (0x0001C000) /* 0x70 */ -+#define LCR_READ_CONFIG (0x00024000) /* 0x90 */ -+#define LCR_ERASE_CONFIRM (0x00008000) /* 0x20 */ -+#define LCR_ERASE_NVMODE (0x0000C000) /* 0x30 */ -+#define LCR_PROG_NVMODE (0x00028000) /* 0xA0 */ -+#define LCR_SR_CLEAR (0x00014000) /* 0x50 */ -+ -+/* -+ * Status register bits -+ */ -+#define SR_VPS_ERROR (1 << 8) /* Power-Up status error */ -+#define SR_ISM_READY (1 << 7) /* State machine isn't busy */ -+#define SR_ERASE_ERROR (1 << 5) /* Erase/Unprotect error */ -+#define SR_PROGRAM_ERROR (1 << 4) /* Program/Protect error */ -+#define SR_DEVICE_PROTECTED (1 << 3) /* Device is protected */ -+#define SR_ISM_STATUS_H (1 << 2) /* Bank ISM status, high bit */ -+#define SR_ISM_STATUS_L (1 << 1) /* Bank ISM status, low bit */ -+#define SR_DEVICE_ISM_STATUS (1 << 0) /* ISM is device-level */ -+ -+#define SR_ERROR (SR_VPS_ERROR|SR_ERASE_ERROR|SR_PROGRAM_ERROR|SR_DEVICE_PROTECTED) -+ -+#define STATUS_VALUE(a) ((a) | ((a) << 16)) -+ -+/* -+ * Device configuration register offsets -+ */ -+#define DC_MANUFACTURER (0 * BUSWIDTH) -+#define DC_DEVICE_ID (1 * BUSWIDTH) -+#define DC_BLOCK_PROTECT (2 * BUSWIDTH) -+#define DC_DEVICE_PROTECT (3 * BUSWIDTH) -+ -+#define FL_WORD(addr) (*(volatile unsigned long*)(addr)) -+ -+static char module_name[] = "syncflash"; -+ -+inline __u8 read8 (__u32 offset) -+{ -+ return *(volatile __u8 *) (FLASH_ADDRESS + offset); -+} -+ -+inline __u32 read32 (__u32 offset) -+{ -+ return *(volatile __u32 *) (FLASH_ADDRESS + offset); -+} -+ -+inline void write32 (__u32 x,__u32 offset) -+{ -+ *(volatile __u32 *) (FLASH_ADDRESS + offset) = x; -+} -+ -+static __u32 read_device_configuration_register(__u32 reg_number) -+{ -+ __u32 tmp; -+ -+ /* Setup the SDRAM controller to issue an LCR command. */ -+ FL_WORD(SDRAMC_REGISTER) = CMD_LCR; -+ -+ /* Perform a read to issue the Read Device Configuration Command. */ -+ tmp = read32(LCR_READ_CONFIG); -+ -+ /* Return the SDRAM controller to normal mode. */ -+ FL_WORD(SDRAMC_REGISTER) = CMD_NORMAL; -+ -+ /* Return the value of the specified register. */ -+ tmp = read32(reg_number); -+ -+ return tmp; -+} -+ -+/* -+ * Get the status of the flash devices. -+ */ -+static __u32 flash_read_status() -+{ -+ __u32 status, tmp; -+ -+ /* Enter the SyncFlash Program READ/WRITE mode. */ -+ FL_WORD(SDRAMC_REGISTER) = CMD_PROGRAM; -+ -+ /* Read the status register. */ -+ status = read32(LCR_READ_STATUS); -+ -+ /* Clear the status register. */ -+ FL_WORD(SDRAMC_REGISTER) = CMD_LCR; -+ tmp = read32(LCR_SR_CLEAR); -+ -+ /* Return to Normal mode. */ -+ FL_WORD(SDRAMC_REGISTER) = CMD_NORMAL; -+ -+ return status; -+} -+ -+/* -+ * Loop until both write state machines are ready. -+ */ -+static __u32 flash_status_wait() -+{ -+ __u32 status; -+ do { -+ status = flash_read_status(); -+ } while ((status & STATUS_VALUE(SR_ISM_READY)) != -+ STATUS_VALUE(SR_ISM_READY)); -+ return status; -+} -+ -+/* -+ * Loop until the Write State machine is ready, then do a full error -+ * check. Clear status and leave the flash in Read Array mode; return -+ * 0 for no error, -1 for error. -+ */ -+static int flash_status_full_check() -+{ -+ __u32 status; -+ -+ status = flash_status_wait() & STATUS_VALUE(SR_ERROR); -+ return status ? -EIO : 0; -+} -+ -+/* -+ * Return the flash to the normal mode. -+ */ -+static void flash_normal_mode() -+{ -+ __u32 tmp; -+ -+ /* First issue a precharge all command. */ -+ FL_WORD(SDRAMC_REGISTER) = CMD_PREC; -+ tmp = read32(SYNCFLASH_A10); -+ -+ /* Now place the SDRAM controller in Normal mode. */ -+ FL_WORD(SDRAMC_REGISTER) = CMD_NORMAL; -+} -+ -+/* -+ * Probe for SyncFlash memory on MX1ADS board. -+ * -+ * Returns 1 if we found SyncFlash memory, 0 otherwise. -+ */ -+static int flash_probe (void) -+{ -+ __u32 manufacturer, device_id; -+ -+ /* For some reason, the first read doesn't work, so we do it -+ * twice. */ -+ manufacturer = read_device_configuration_register(DC_MANUFACTURER); -+ manufacturer = read_device_configuration_register(DC_MANUFACTURER); -+ device_id = read_device_configuration_register(DC_DEVICE_ID); -+ -+ printk("SyncFlash probe: manufacturer 0x%08lx, device_id 0x%08lx\n", -+ manufacturer, device_id); -+ return (manufacturer == FLASH_MANUFACTURER && -+ device_id == FLASH_DEVICE_ID); -+} -+ -+/* -+ * Erase one block of flash memory at offset ``offset'' which is any -+ * address within the block which should be erased. -+ * -+ * Returns 0 if successful, -1 otherwise. -+ */ -+static inline int erase_block (__u32 offset) -+{ -+ __u32 tmp; -+ -+ /* Mask off the lower bits of the address to get the first address -+ * in the flash block. */ -+ offset &= (__u32)BLOCK_MASK; -+ -+ /* Perform a read and precharge of the bank before the LCR|ACT|WRIT -+ * sequence to avoid the inadvertent precharge command occurring -+ * during the LCR_ACT_WRIT sequence. */ -+ FL_WORD(SDRAMC_REGISTER) = CMD_NORMAL; -+ tmp = read32(offset); -+ FL_WORD(SDRAMC_REGISTER) = CMD_PREC; -+ tmp = read32(offset); -+ -+ /* Now start the actual erase. */ -+ -+ /* LCR|ACT|WRIT sequence */ -+ FL_WORD(SDRAMC_REGISTER) = CMD_LCR; -+ write32(0, offset + LCR_ERASE_CONFIRM); -+ -+ /* Return to normal mode to issue the erase confirm. */ -+ FL_WORD(SDRAMC_REGISTER) = CMD_NORMAL; -+ write32(0xD0D0D0D0, offset); -+ -+ if (flash_status_full_check()) { -+ printk (KERN_WARNING "%s: erase error at address 0x%.8x.\n", -+ module_name, offset); -+ return (-1); -+ } -+ -+ flash_normal_mode(); -+ -+ return 0; -+} -+ -+static int flash_erase (struct mtd_info *mtd,struct erase_info *instr) -+{ -+ __u32 addr,len; -+ int i,first; -+ -+ /* sanity checks */ -+ if (instr->addr + instr->len > mtd->size) return (-EINVAL); -+ -+ /* -+ * check that both start and end of the requested erase are -+ * aligned with the erasesize at the appropriate addresses. -+ * -+ * skip all erase regions which are ended before the start of -+ * the requested erase. Actually, to save on the calculations, -+ * we skip to the first erase region which starts after the -+ * start of the requested erase, and then go back one. -+ */ -+ for (i = 0; (i < mtd->numeraseregions) && -+ (instr->addr >= mtd->eraseregions[i].offset); i++) ; -+ i--; -+ -+ /* -+ * ok, now i is pointing at the erase region in which this -+ * erase request starts. Check the start of the requested -+ * erase range is aligned with the erase size which is in -+ * effect here. -+ */ -+ if (instr->addr & (mtd->eraseregions[i].erasesize - 1)) -+ return (-EINVAL); -+ -+ /* Remember the erase region we start on */ -+ first = i; -+ -+ /* -+ * next, check that the end of the requested erase is aligned -+ * with the erase region at that address. -+ * -+ * as before, drop back one to point at the region in which -+ * the address actually falls -+ */ -+ for (; -+ (i < mtd->numeraseregions) && -+ ((instr->addr + instr->len) >= mtd->eraseregions[i].offset) ; -+ i++) ; -+ i--; -+ -+ /* is the end aligned on a block boundary? */ -+ if ((instr->addr + instr->len) & (mtd->eraseregions[i].erasesize - 1)) -+ return (-EINVAL); -+ -+ addr = instr->addr; -+ len = instr->len; -+ -+ i = first; -+ -+ /* now erase those blocks */ -+ while (len) -+ { -+ if (erase_block (addr)) -+ { -+ instr->state = MTD_ERASE_FAILED; -+ return (-EIO); -+ } -+ -+ addr += mtd->eraseregions[i].erasesize; -+ len -= mtd->eraseregions[i].erasesize; -+ -+ if (addr == (mtd->eraseregions[i].offset + -+ (mtd->eraseregions[i].erasesize * -+ mtd->eraseregions[i].numblocks))) -+ i++; -+ } -+ -+ instr->state = MTD_ERASE_DONE; -+ if (instr->callback) instr->callback (instr); -+ -+ return (0); -+} -+ -+static int flash_read (struct mtd_info *mtd, loff_t from, -+ size_t len, size_t *retlen, u_char *buf) -+{ -+ /* Sanity checks. */ -+ if (!len) return (0); -+ if (from + len > mtd->size) return (-EINVAL); -+ -+ /* Ensure that we are in normal mode. */ -+ flash_normal_mode(); -+ -+ /* We always read len bytes. */ -+ *retlen = len; -+ -+ /* first, we read bytes until we reach a dword boundary */ -+ if (from & (BUSWIDTH - 1)) -+ { -+ int gap = BUSWIDTH - (from & (BUSWIDTH - 1)); -+ while (len && gap--) *buf++ = read8(from++), len--; -+ } -+ -+ /* now we read dwords until we reach a non-dword boundary */ -+ while (len >= BUSWIDTH) -+ { -+ *((__u32 *) buf) = read32(from); -+ -+ buf += BUSWIDTH; -+ from += BUSWIDTH; -+ len -= BUSWIDTH; -+ } -+ -+ /* top up the last unaligned bytes */ -+ if (len & (BUSWIDTH - 1)) -+ while (len--) *buf++ = read8(from++); -+ -+ return (0); -+} -+ -+/* -+ * Write one dword ``x'' to flash memory at offset ``offset''. ``offset'' -+ * must be 32 bits, i.e. it must be on a dword boundary. -+ * -+ * Returns 0 if successful, -1 otherwise. -+ */ -+static int flash_write_dword(__u32 offset, __u32 x) -+{ -+ __u32 tmp; -+ -+ /* First issue a precharge all command. */ -+ FL_WORD(SDRAMC_REGISTER) = CMD_PREC; -+ tmp = read32(SYNCFLASH_A10); -+ -+ /* Enter the SyncFlash programming mode. */ -+ FL_WORD(SDRAMC_REGISTER) = CMD_PROGRAM; -+ write32(x, offset); -+ -+ /* Wait for the write to complete. */ -+ flash_status_wait(); -+ -+ /* Return to normal mode. */ -+ flash_normal_mode(); -+ -+ return 0; -+} -+ -+static int flash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen,const u_char *buf) -+{ -+ __u8 tmp[4]; -+ int i,n; -+ -+ *retlen = 0; -+ -+ /* Sanity checks */ -+ if (!len) return (0); -+ if (to + len > mtd->size) return (-EINVAL); -+ -+ /* First, we write a 0xFF.... padded byte until we reach a -+ * dword boundary. */ -+ if (to & (BUSWIDTH - 1)) -+ { -+ __u32 aligned = to & ~(BUSWIDTH - 1); -+ int gap = to - aligned; -+ -+ i = n = 0; -+ -+ while (gap--) tmp[i++] = 0xFF; -+ while (len && i < BUSWIDTH) tmp[i++] = buf[n++], len--; -+ while (i < BUSWIDTH) tmp[i++] = 0xFF; -+ -+ if (flash_write_dword(aligned, *((__u32 *) tmp))) -+ return (-EIO); -+ -+ to += n; -+ buf += n; -+ *retlen += n; -+ } -+ -+ /* Now we write dwords until we reach a non-dword boundary. */ -+ while (len >= BUSWIDTH) -+ { -+ if (flash_write_dword (to,*((__u32 *) buf))) return (-EIO); -+ -+ to += BUSWIDTH; -+ buf += BUSWIDTH; -+ *retlen += BUSWIDTH; -+ len -= BUSWIDTH; -+ } -+ -+ /* Top up the last unaligned bytes, padded with 0xFF.... */ -+ if (len & (BUSWIDTH - 1)) -+ { -+ i = n = 0; -+ -+ while (len--) tmp[i++] = buf[n++]; -+ while (i < BUSWIDTH) tmp[i++] = 0xFF; -+ -+ if (flash_write_dword (to,*((__u32 *) tmp))) return (-EIO); -+ -+ *retlen += n; -+ } -+ -+ return flash_status_full_check(); -+} -+ -+ -+ -+#define NB_OF(x) (sizeof (x) / sizeof (x[0])) -+ -+static struct mtd_info mtd; -+ -+static struct mtd_erase_region_info erase_regions[] = -+{ -+ /* flash blocks */ -+ { -+ offset: 0x00000000, -+ erasesize: FLASH_BLOCKSIZE, -+ numblocks: FLASH_NUMBLOCKS -+ }, -+}; -+ -+#ifdef HAVE_PARTITIONS -+static struct mtd_partition syncflash_partitions[] = -+{ -+ /* bootloader */ -+ { -+ name: "bootloader", -+ offset: BOOTLOADER_START, -+ size: BOOTLOADER_LEN, -+ mask_flags: 0 -+ }, -+ /* Kernel */ -+ { -+ name: "kernel", -+ offset: KERNEL_START, /* MTDPART_OFS_APPEND */ -+ size: KERNEL_LEN, -+ mask_flags: 0 -+ }, -+ /* file system */ -+ { -+ name: "file system", -+ offset: FILESYSTEM_START, /* MTDPART_OFS_APPEND */ -+ size: FILESYSTEM_LEN, /* MTDPART_SIZ_FULL */ -+ mask_flags: 0 -+ } -+}; -+#endif -+ -+int __init syncflash_init (void) -+{ -+ int result; -+ -+ memset (&mtd,0,sizeof (mtd)); -+ -+ printk ("MTD driver for Micron SyncFlash.\n"); -+ printk ("%s: Probing for SyncFlash on MX1ADS...\n",module_name); -+ -+ if (!flash_probe ()) -+ { -+ printk (KERN_WARNING "%s: Found no SyncFlash devices\n", -+ module_name); -+ return (-ENXIO); -+ } -+ -+ printk ("%s: Found a SyncFlash device.\n",module_name); -+ -+ mtd.name = module_name; -+ mtd.type = MTD_NORFLASH; -+ mtd.flags = MTD_CAP_NORFLASH; -+ mtd.size = FLASH_BLOCKSIZE * FLASH_NUMBLOCKS; -+ -+ mtd.erasesize = FLASH_BLOCKSIZE; -+ mtd.numeraseregions = NB_OF(erase_regions); -+ mtd.eraseregions = erase_regions; -+ -+ mtd.module = THIS_MODULE; -+ -+ mtd.erase = flash_erase; -+ mtd.read = flash_read; -+ mtd.write = flash_write; -+ -+#ifndef HAVE_PARTITIONS -+ result = add_mtd_device(&mtd); -+#else -+ result = add_mtd_partitions(&mtd, -+ syncflash_partitions, -+ NB_OF(syncflash_partitions)); -+#endif -+ -+ return (result); -+} -+ -+void __exit syncflash_exit (void) -+{ -+#ifndef HAVE_PARTITIONS -+ del_mtd_device (&mtd); -+#else -+ del_mtd_partitions (&mtd); -+#endif -+} -+ -+module_init (syncflash_init); -+module_exit (syncflash_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jon McClintock "); -+MODULE_DESCRIPTION("MTD driver for Micron MT28S4M16LC SyncFlash on MX1ADS board"); -+ -+ -diff -urN linux-2.4.26/drivers/mtd/maps/Config.in linux-2.4.26-vrs1/drivers/mtd/maps/Config.in ---- linux-2.4.26/drivers/mtd/maps/Config.in 2003-06-13 15:51:34.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/mtd/maps/Config.in 2004-01-14 21:32:26.000000000 +0000 -@@ -81,10 +81,10 @@ - dep_tristate ' CFI Flash device mapped on StrongARM SA11x0' CONFIG_MTD_SA1100 $CONFIG_MTD_CFI $CONFIG_ARCH_SA1100 $CONFIG_MTD_PARTITIONS - dep_tristate ' CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE - dep_tristate ' CFI Flash device mapped on the XScale IQ80310 board' CONFIG_MTD_IQ80310 $CONFIG_MTD_CFI $CONFIG_ARCH_IQ80310 -- dep_tristate ' CFI Flash device mapped on Epxa10db' CONFIG_MTD_EPXA10DB $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT -- dep_tristate ' CFI Flash device mapped on the FortuNet board' CONFIG_MTD_FORTUNET $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_SA1100_FORTUNET -+ dep_tristate ' CFI Flash device mapped on the FortuNet board' CONFIG_MTD_FORTUNET $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_FORTUNET -+ dep_tristate ' CFI Flash device mapped on Epxa' CONFIG_MTD_EPXA $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT - dep_tristate ' NV-RAM mapping AUTCPU12 board' CONFIG_MTD_AUTCPU12 $CONFIG_ARCH_AUTCPU12 -- dep_tristate ' CFI Flash device mapped on EDB7312' CONFIG_MTD_EDB7312 $CONFIG_MTD_CFI -+ dep_tristate ' CFI Flash device mapped on EDB7312' CONFIG_MTD_EDB7312 $CONFIG_ARCH_EDB7212 $CONFIG_MTD_CFI - dep_tristate ' JEDEC Flash device mapped on impA7' CONFIG_MTD_IMPA7 $CONFIG_MTD_JEDECPROBE - dep_tristate ' JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame' CONFIG_MTD_CEIVA $CONFIG_MTD_JEDECPROBE $CONFIG_ARCH_CEIVA - fi -diff -urN linux-2.4.26/drivers/mtd/maps/Makefile linux-2.4.26-vrs1/drivers/mtd/maps/Makefile ---- linux-2.4.26/drivers/mtd/maps/Makefile 2003-06-13 15:51:34.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/mtd/maps/Makefile 2004-01-14 21:32:26.000000000 +0000 -@@ -3,11 +3,7 @@ - # - # $Id: Makefile,v 1.37 2003/01/24 14:26:38 dwmw2 Exp $ - --BELOW25 := $(shell echo $(PATCHLEVEL) | sed s/[1234]/y/) -- --ifeq ($(BELOW25),y) - O_TARGET := mapslink.o --endif - - # Chip mappings - obj-$(CONFIG_MTD_CDB89712) += cdb89712.o -@@ -17,7 +13,7 @@ - obj-$(CONFIG_MTD_DC21285) += dc21285.o - obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o - obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o --obj-$(CONFIG_MTD_EPXA10DB) += epxa10db-flash.o -+obj-$(CONFIG_MTD_EPXA) += epxa-flash.o - obj-$(CONFIG_MTD_IQ80310) += iq80310.o - obj-$(CONFIG_MTD_L440GX) += l440gx.o - obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o -@@ -29,9 +25,9 @@ - obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o - ifneq ($(CONFIG_MTD_PHYSMAP),n) - ifeq ($(CONFIG_MTD_PHYSMAP_BUSWIDTH),8) -- obj-$(CONFIG_MTD_PHYSMAP) += physmap64.o -+ obj-$(CONFIG_MTD_PHYSMAP) += physmap64.o - else -- obj-$(CONFIG_MTD_PHYSMAP) += physmap.o -+ obj-$(CONFIG_MTD_PHYSMAP) += physmap.o - endif - endif - obj-$(CONFIG_MTD_PNC2000) += pnc2000.o -@@ -39,6 +35,9 @@ - obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o - obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o - obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o -+ifeq ($(CONFIG_ASSABET_NEPONSET),y) -+ obj-$(CONFIG_MTD_SA1100) += neponset-flash.o -+endif - obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o - obj-$(CONFIG_MTD_SC520CDP) += sc520cdp.o - obj-$(CONFIG_MTD_NETSC520) += netsc520.o -diff -urN linux-2.4.26/drivers/mtd/maps/dc21285.c linux-2.4.26-vrs1/drivers/mtd/maps/dc21285.c ---- linux-2.4.26/drivers/mtd/maps/dc21285.c 2003-06-13 15:51:34.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/mtd/maps/dc21285.c 2004-04-18 21:33:22.000000000 +0100 -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -18,9 +19,9 @@ - - #include - #include -+#include - -- --static struct mtd_info *mymtd; -+static struct mtd_info *dc21285_mtd; - - __u8 dc21285_read8(struct map_info *map, unsigned long ofs) - { -@@ -44,6 +45,9 @@ - - void dc21285_write8(struct map_info *map, __u8 d, unsigned long adr) - { -+ if(machine_is_netwinder()) { -+ nw_en_write(); -+ } - *CSR_ROMWRITEREG = adr & 3; - adr &= ~3; - *(__u8*)(map->map_priv_1 + adr) = d; -@@ -51,6 +55,9 @@ - - void dc21285_write16(struct map_info *map, __u16 d, unsigned long adr) - { -+ if(machine_is_netwinder()) { -+ nw_en_write(); -+ } - *CSR_ROMWRITEREG = adr & 3; - adr &= ~3; - *(__u16*)(map->map_priv_1 + adr) = d; -@@ -58,6 +65,9 @@ - - void dc21285_write32(struct map_info *map, __u32 d, unsigned long adr) - { -+ if(machine_is_netwinder()) { -+ nw_en_write(); -+ } - *(__u32*)(map->map_priv_1 + adr) = d; - } - -@@ -105,6 +115,27 @@ - }; - - -+static void -+nw_en_write(void) { -+#ifdef CONFIG_ARCH_NETWINDER -+ extern spinlock_t gpio_lock; -+ unsigned long flags; -+ -+ /* -+ * we want to write a bit pattern XXX1 to Xilinx to enable -+ * the write gate, which will be open for about the next 2ms. -+ */ -+ spin_lock_irqsave(&gpio_lock, flags); -+ cpld_modify(1, 1); -+ spin_unlock_irqrestore(&gpio_lock, flags); -+ -+ /* -+ * let the ISA bus to catch on... -+ */ -+ udelay(25); -+#endif -+} -+ - /* Partition stuff */ - static struct mtd_partition *dc21285_parts; - -@@ -112,6 +143,9 @@ - - int __init init_dc21285(void) - { -+ int nr_parts = 0; -+ char *part_type = "none"; -+ - /* Determine buswidth */ - switch (*CSR_SA110_CNTL & (3<<14)) { - case SA110_CNTL_ROMWIDTH_8: -@@ -137,24 +171,64 @@ - return -EIO; - } - -- mymtd = do_map_probe("cfi_probe", &dc21285_map); -- if (mymtd) { -- int nrparts = 0; -+ if(machine_is_ebsa285()) { -+ dc21285_mtd = do_map_probe("cfi_probe", &dc21285_map); -+ } else { -+ dc21285_mtd = do_map_probe("jedec_probe", &dc21285_map); -+ } - -- mymtd->module = THIS_MODULE; -+ if (!dc21285_mtd) { -+ /* no recognised device so unmap and exit */ -+ iounmap((void *)dc21285_map.map_priv_1); -+ return -ENXIO; -+ } - -- /* partition fixup */ -+ dc21285_mtd->module = THIS_MODULE; - -+ /* -+ * Dynamic partition selection stuff (might override the static ones) -+ */ - #ifdef CONFIG_MTD_REDBOOT_PARTS -- nrparts = parse_redboot_partitions(mymtd, &dc21285_parts); -+ if (nr_parts == 0) { -+ int ret = parse_redboot_partitions(dc21285_mtd, &dc21285_parts); -+ -+ if (ret > 0) { -+ part_type = "RedBoot"; -+ nr_parts = ret; -+ } -+ else -+ { -+ dc21285_parts=NULL; /* ensure partition table remains clear */ -+ } -+ } - #endif -- if (nrparts > 0) { -- add_mtd_partitions(mymtd, dc21285_parts, nrparts); -- } else if (nrparts == 0) { -- printk(KERN_NOTICE "RedBoot partition table failed\n"); -- add_mtd_device(mymtd); -+#ifdef CONFIG_MTD_CMDLINE_PARTS -+ if (nr_parts == 0) { -+ int ret = parse_cmdline_partitions(dc21285_mtd, &dc21285_parts, "sa1100"); -+ if (ret > 0) { -+ part_type = "Command Line"; -+ nr_parts = ret; - } -+ else -+ { -+ dc21285_parts=NULL; /* ensure partition table remains clear */ -+ } -+ } -+#endif - -+ if (nr_parts == 0) { -+ printk(KERN_NOTICE "DC21285 Flash: no partition info available, registering whole flash at once\n"); -+ add_mtd_device(dc21285_mtd); -+ } -+#ifdef CONFIG_MTD_PARTITIONS -+ else -+ { -+ printk(KERN_NOTICE "DC21285 Flash: Using %s partition definition\n", part_type); -+ add_mtd_partitions(dc21285_mtd, &dc21285_parts, nr_parts); -+ } -+#endif -+ -+ if(machine_is_ebsa285()) { - /* - * Flash timing is determined with bits 19-16 of the - * CSR_SA110_CNTL. The value is the number of wait cycles, or -@@ -167,20 +241,15 @@ - *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20)); - /* tristate time */ - *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24)); -- -- return 0; - } -- -- iounmap((void *)dc21285_map.map_priv_1); -- return -ENXIO; - } - - static void __exit cleanup_dc21285(void) - { -- if (mymtd) { -- del_mtd_device(mymtd); -- map_destroy(mymtd); -- mymtd = NULL; -+ if (dc21285_mtd) { -+ del_mtd_device(dc21285_mtd); -+ map_destroy(dc21285_mtd); -+ dc21285_mtd = NULL; - } - if (dc21285_map.map_priv_1) { - iounmap((void *)dc21285_map.map_priv_1); -diff -urN linux-2.4.26/drivers/mtd/maps/epxa-flash.c linux-2.4.26-vrs1/drivers/mtd/maps/epxa-flash.c ---- linux-2.4.26/drivers/mtd/maps/epxa-flash.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/mtd/maps/epxa-flash.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,234 @@ -+/* -+ * Flash memory access on EPXA based devices -+ * -+ * (C) 2000 Nicolas Pitre -+ * Copyright (C) 2001 Altera Corporation -+ * Copyright (C) 2001 Red Hat, Inc. -+ * -+ * $Id: epxa10db-flash.c,v 1.4 2002/08/22 10:46:19 cdavies Exp $ -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#ifdef CONFIG_EPXA10DB -+#define BOARD_NAME "EPXA10DB" -+#else -+#define BOARD_NAME "EPXA1DB" -+#endif -+ -+static int nr_parts = 0; -+static struct mtd_partition *parts; -+ -+static struct mtd_info *mymtd; -+ -+extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **); -+static int epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts); -+ -+static __u8 epxa_read8(struct map_info *map, unsigned long ofs) -+{ -+ return __raw_readb(map->map_priv_1 + ofs); -+} -+ -+static __u16 epxa_read16(struct map_info *map, unsigned long ofs) -+{ -+ return __raw_readw(map->map_priv_1 + ofs); -+} -+ -+static __u32 epxa_read32(struct map_info *map, unsigned long ofs) -+{ -+ return __raw_readl(map->map_priv_1 + ofs); -+} -+ -+static void epxa_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -+{ -+ memcpy_fromio(to, map->map_priv_1 + from, len); -+} -+ -+static void epxa_write8(struct map_info *map, __u8 d, unsigned long adr) -+{ -+ __raw_writeb(d, map->map_priv_1 + adr); -+ mb(); -+} -+ -+static void epxa_write16(struct map_info *map, __u16 d, unsigned long adr) -+{ -+ __raw_writew(d, map->map_priv_1 + adr); -+ mb(); -+} -+ -+static void epxa_write32(struct map_info *map, __u32 d, unsigned long adr) -+{ -+ __raw_writel(d, map->map_priv_1 + adr); -+ mb(); -+} -+ -+static void epxa_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -+{ -+ memcpy_toio(map->map_priv_1 + to, from, len); -+} -+ -+static struct map_info epxa_map = { -+ .name = "EPXA flash", -+ .size = FLASH_SIZE, -+ .buswidth = 2, -+ .read8 = epxa_read8, -+ .read16 = epxa_read16, -+ .read32 = epxa_read32, -+ .copy_from = epxa_copy_from, -+ .write8 = epxa_write8, -+ .write16 = epxa_write16, -+ .write32 = epxa_write32, -+ .copy_to = epxa_copy_to -+}; -+ -+static int __init epxa_mtd_init(void) -+{ -+ int i; -+ -+ printk(KERN_NOTICE "%s flash device: %x at %x\n", BOARD_NAME, FLASH_SIZE, FLASH_START); -+ epxa_map.map_priv_1 = (unsigned long)ioremap_nocache(FLASH_START, FLASH_SIZE); -+ if (!epxa_map.map_priv_1) { -+ printk("Failed to ioremap %s flash\n",BOARD_NAME); -+ return -EIO; -+ } -+ -+ mymtd = do_map_probe("cfi_probe", &epxa_map); -+ if (!mymtd) { -+ iounmap((void *)epxa_map.map_priv_1); -+ return -ENXIO; -+ } -+ -+ mymtd->module = THIS_MODULE; -+ -+ /* Unlock the flash device. */ -+ if(mymtd->unlock){ -+ for (i=0; inumeraseregions;i++){ -+ int j; -+ for(j=0;jeraseregions[i].numblocks;j++){ -+ mymtd->unlock(mymtd,mymtd->eraseregions[i].offset + j * mymtd->eraseregions[i].erasesize,mymtd->eraseregions[i].erasesize); -+ } -+ } -+ } -+ -+#ifdef CONFIG_MTD_REDBOOT_PARTS -+ nr_parts = parse_redboot_partitions(mymtd, &parts); -+ -+ if (nr_parts > 0) { -+ add_mtd_partitions(mymtd, parts, nr_parts); -+ return 0; -+ } -+#endif -+#ifdef CONFIG_MTD_AFS_PARTS -+ nr_parts = parse_afs_partitions(mymtd, &parts); -+ -+ if (nr_parts > 0) { -+ add_mtd_partitions(mymtd, parts, nr_parts); -+ return 0; -+ } -+#endif -+ -+ /* No recognised partitioning schemes found - use defaults */ -+ nr_parts = epxa_default_partitions(mymtd, &parts); -+ if (nr_parts > 0) { -+ add_mtd_partitions(mymtd, parts, nr_parts); -+ return 0; -+ } -+ -+ /* If all else fails... */ -+ add_mtd_device(mymtd); -+ return 0; -+} -+ -+static void __exit epxa_mtd_cleanup(void) -+{ -+ if (mymtd) { -+ if (nr_parts) -+ del_mtd_partitions(mymtd); -+ else -+ del_mtd_device(mymtd); -+ map_destroy(mymtd); -+ } -+ if (epxa_map.map_priv_1) { -+ iounmap((void *)epxa_map.map_priv_1); -+ epxa_map.map_priv_1 = 0; -+ } -+} -+ -+ -+/* -+ * This will do for now, once we decide which bootldr we're finally -+ * going to use then we'll remove this function and do it properly -+ * -+ * Partions are currently (as offsets from base of flash): -+ * 0x00000000 - 0x003FFFFF - bootloader (!) -+ * 0x00400000 - 0x00FFFFFF - Flashdisk -+ */ -+ -+static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts) -+{ -+ struct mtd_partition *parts; -+ int ret; -+ int npartitions = 0; -+ char *names; -+ const char *name = "jffs"; -+ -+ printk("Using default partitions for %s\n",BOARD_NAME); -+ npartitions=1; -+ parts = kmalloc(npartitions*sizeof(*parts)+strlen(name)+1, GFP_KERNEL); -+ if (!parts) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ memzero(parts,npartitions*sizeof(*parts)+strlen(name)); -+ -+ names = (char *)&parts[npartitions]; -+ parts[0].name = names; -+ names += strlen(name) + 1; -+ strcpy(parts[0].name, name); -+ -+#ifdef CONFIG_EPXA10DB_R2 -+ parts[0].size = FLASH_SIZE-0x00400000; -+ parts[0].offset = 0x00400000; -+#elif defined CONFIG_EPXA10DB_R3 -+ parts[0].size = 0x00800000; -+ parts[0].offset = 0x00800000; -+#else -+ parts[0].size = FLASH_SIZE-0x00180000; -+ parts[0].offset = 0x00180000; -+#endif -+ ret = npartitions; -+ -+ out: -+ *pparts = parts; -+ return ret; -+} -+ -+ -+module_init(epxa_mtd_init); -+module_exit(epxa_mtd_cleanup); -+ -+MODULE_AUTHOR("Clive Davies"); -+MODULE_DESCRIPTION("Altera epxa mtd flash map"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.4.26/drivers/mtd/maps/epxa10db-flash.c linux-2.4.26-vrs1/drivers/mtd/maps/epxa10db-flash.c ---- linux-2.4.26/drivers/mtd/maps/epxa10db-flash.c 2003-06-13 15:51:34.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/mtd/maps/epxa10db-flash.c 1970-01-01 01:00:00.000000000 +0100 -@@ -1,233 +0,0 @@ --/* -- * Flash memory access on EPXA based devices -- * -- * (C) 2000 Nicolas Pitre -- * Copyright (C) 2001 Altera Corporation -- * Copyright (C) 2001 Red Hat, Inc. -- * -- * $Id: epxa10db-flash.c,v 1.4 2002/08/22 10:46:19 cdavies Exp $ -- * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License as published by -- * the Free Software Foundation; either version 2 of the License, or -- * (at your option) any later version. -- * -- * This program is distributed in the hope that it will be useful, -- * but WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- * -- * You should have received a copy of the GNU General Public License -- * along with this program; if not, write to the Free Software -- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -- */ -- --#include --#include --#include --#include --#include --#include --#include --#include -- --#include --#ifdef CONFIG_EPXA10DB --#define BOARD_NAME "EPXA10DB" --#else --#define BOARD_NAME "EPXA1DB" --#endif -- --static int nr_parts = 0; --static struct mtd_partition *parts; -- --static struct mtd_info *mymtd; -- --extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **); --static int epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts); -- --static __u8 epxa_read8(struct map_info *map, unsigned long ofs) --{ -- return __raw_readb(map->map_priv_1 + ofs); --} -- --static __u16 epxa_read16(struct map_info *map, unsigned long ofs) --{ -- return __raw_readw(map->map_priv_1 + ofs); --} -- --static __u32 epxa_read32(struct map_info *map, unsigned long ofs) --{ -- return __raw_readl(map->map_priv_1 + ofs); --} -- --static void epxa_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); --} -- --static void epxa_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- __raw_writeb(d, map->map_priv_1 + adr); -- mb(); --} -- --static void epxa_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- __raw_writew(d, map->map_priv_1 + adr); -- mb(); --} -- --static void epxa_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- __raw_writel(d, map->map_priv_1 + adr); -- mb(); --} -- --static void epxa_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy_toio((void *)(map->map_priv_1 + to), from, len); --} -- -- -- --static struct map_info epxa_map = { -- name: "EPXA flash", -- size: FLASH_SIZE, -- buswidth: 2, -- read8: epxa_read8, -- read16: epxa_read16, -- read32: epxa_read32, -- copy_from: epxa_copy_from, -- write8: epxa_write8, -- write16: epxa_write16, -- write32: epxa_write32, -- copy_to: epxa_copy_to --}; -- -- --static int __init epxa_mtd_init(void) --{ -- int i; -- -- printk(KERN_NOTICE "%s flash device: %x at %x\n", BOARD_NAME, FLASH_SIZE, FLASH_START); -- epxa_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE); -- if (!epxa_map.map_priv_1) { -- printk("Failed to ioremap %s flash\n",BOARD_NAME); -- return -EIO; -- } -- -- mymtd = do_map_probe("cfi_probe", &epxa_map); -- if (!mymtd) { -- iounmap((void *)epxa_map.map_priv_1); -- return -ENXIO; -- } -- -- mymtd->module = THIS_MODULE; -- -- /* Unlock the flash device. */ -- if(mymtd->unlock){ -- for (i=0; inumeraseregions;i++){ -- int j; -- for(j=0;jeraseregions[i].numblocks;j++){ -- mymtd->unlock(mymtd,mymtd->eraseregions[i].offset + j * mymtd->eraseregions[i].erasesize,mymtd->eraseregions[i].erasesize); -- } -- } -- } -- --#ifdef CONFIG_MTD_REDBOOT_PARTS -- nr_parts = parse_redboot_partitions(mymtd, &parts); -- -- if (nr_parts > 0) { -- add_mtd_partitions(mymtd, parts, nr_parts); -- return 0; -- } --#endif --#ifdef CONFIG_MTD_AFS_PARTS -- nr_parts = parse_afs_partitions(mymtd, &parts); -- -- if (nr_parts > 0) { -- add_mtd_partitions(mymtd, parts, nr_parts); -- return 0; -- } --#endif -- -- /* No recognised partitioning schemes found - use defaults */ -- nr_parts = epxa_default_partitions(mymtd, &parts); -- if (nr_parts > 0) { -- add_mtd_partitions(mymtd, parts, nr_parts); -- return 0; -- } -- -- /* If all else fails... */ -- add_mtd_device(mymtd); -- return 0; --} -- --static void __exit epxa_mtd_cleanup(void) --{ -- if (mymtd) { -- if (nr_parts) -- del_mtd_partitions(mymtd); -- else -- del_mtd_device(mymtd); -- map_destroy(mymtd); -- } -- if (epxa_map.map_priv_1) { -- iounmap((void *)epxa_map.map_priv_1); -- epxa_map.map_priv_1 = 0; -- } --} -- -- --/* -- * This will do for now, once we decide which bootldr we're finally -- * going to use then we'll remove this function and do it properly -- * -- * Partions are currently (as offsets from base of flash): -- * 0x00000000 - 0x003FFFFF - bootloader (!) -- * 0x00400000 - 0x00FFFFFF - Flashdisk -- */ -- --static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts) --{ -- struct mtd_partition *parts; -- int ret, i; -- int npartitions = 0; -- char *names; -- const char *name = "jffs"; -- -- printk("Using default partitions for %s\n",BOARD_NAME); -- npartitions=1; -- parts = kmalloc(npartitions*sizeof(*parts)+strlen(name), GFP_KERNEL); -- memzero(parts,npartitions*sizeof(*parts)+strlen(name)); -- if (!parts) { -- ret = -ENOMEM; -- goto out; -- } -- i=0; -- names = (char *)&parts[npartitions]; -- parts[i].name = names; -- names += strlen(name) + 1; -- strcpy(parts[i].name, name); -- --#ifdef CONFIG_EPXA10DB -- parts[i].size = FLASH_SIZE-0x00400000; -- parts[i].offset = 0x00400000; --#else -- parts[i].size = FLASH_SIZE-0x00180000; -- parts[i].offset = 0x00180000; --#endif -- -- out: -- *pparts = parts; -- return npartitions; --} -- -- --module_init(epxa_mtd_init); --module_exit(epxa_mtd_cleanup); -- --MODULE_AUTHOR("Clive Davies"); --MODULE_DESCRIPTION("Altera epxa mtd flash map"); --MODULE_LICENSE("GPL"); -diff -urN linux-2.4.26/drivers/mtd/maps/neponset-flash.c linux-2.4.26-vrs1/drivers/mtd/maps/neponset-flash.c ---- linux-2.4.26/drivers/mtd/maps/neponset-flash.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/mtd/maps/neponset-flash.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,109 @@ -+/* -+ * Flash memory access on SA11x0 based devices -+ * -+ * (C) 2000 Nicolas Pitre -+ * -+ * $Id: neponset-flash.c,v 1.18 2001/07/14 00:59:17 thockin Exp $ -+ */ -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+static __u8 read8(struct map_info *map, unsigned long ofs) -+{ -+ return readb(map->map_priv_1 + ofs); -+} -+ -+static __u16 read16(struct map_info *map, unsigned long ofs) -+{ -+ return readw(map->map_priv_1 + ofs); -+} -+ -+static __u32 read32(struct map_info *map, unsigned long ofs) -+{ -+ return readl(map->map_priv_1 + ofs); -+} -+ -+static void copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -+{ -+ memcpy_fromio(to, map->map_priv_1 + from, len); -+} -+ -+static void write8(struct map_info *map, __u8 d, unsigned long adr) -+{ -+ writeb(d, map->map_priv_1 + adr); -+} -+ -+static void write16(struct map_info *map, __u16 d, unsigned long adr) -+{ -+ writew(d, map->map_priv_1 + adr); -+} -+ -+static void write32(struct map_info *map, __u32 d, unsigned long adr) -+{ -+ writel(d, map->map_priv_1 + adr); -+} -+ -+static void copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -+{ -+ memcpy_toio(map->map_priv_1 + to, from, len); -+} -+ -+#define MAX_SZ (32 * 1024 * 1024) -+ -+static struct map_info neponset_map = { -+ name: "Neponset", -+ size: MAX_SZ, -+ buswidth: 4, -+ read8: read8, -+ read16: read16, -+ read32: read32, -+ copy_from: copy_from, -+ write8: write8, -+ write16: write16, -+ write32: write32, -+ copy_to: copy_to, -+}; -+ -+extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); -+extern int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts); -+ -+static struct mtd_info *neponset_mtd; -+ -+int __init neponset_mtd_init(void) -+{ -+ if (!machine_is_assabet() || !machine_has_neponset()) -+ return -ENODEV; -+ -+ neponset_map.map_priv_1 = (unsigned int)ioremap(0x08000000, MAX_SZ); -+ if (!neponset_map.map_priv_1) -+ return -ENOMEM; -+ -+ neponset_mtd = do_map_probe("cfi_probe", &neponset_map); -+ if (!neponset_mtd) -+ return -ENXIO; -+ neponset_mtd->module = THIS_MODULE; -+ add_mtd_device(neponset_mtd); -+ return 0; -+} -+ -+static void __exit neponset_mtd_cleanup(void) -+{ -+ if (neponset_mtd) -+ map_destroy(neponset_mtd); -+ if (neponset_map.map_priv_1) -+ iounmap((void *)neponset_map.map_priv_1); -+} -+ -+module_init(neponset_mtd_init); -+module_exit(neponset_mtd_cleanup); -diff -urN linux-2.4.26/drivers/mtd/maps/sa1100-flash.c linux-2.4.26-vrs1/drivers/mtd/maps/sa1100-flash.c ---- linux-2.4.26/drivers/mtd/maps/sa1100-flash.c 2003-06-13 15:51:34.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/mtd/maps/sa1100-flash.c 2004-01-14 21:32:26.000000000 +0000 -@@ -97,6 +97,32 @@ - * entries. Thanks. - */ - -+#ifdef CONFIG_SA1100_ADSAGC -+#define ADSAGC_FLASH_SIZE 0x02000000 -+static struct mtd_partition adsagc_partitions[] = { -+ { -+ name: "bootROM", -+ size: 0x80000, -+ offset: 0, -+ mask_flags: MTD_WRITEABLE, /* force read-only */ -+ }, { -+ name: "zImage", -+ size: 0x100000, -+ offset: MTDPART_OFS_APPEND, -+ mask_flags: MTD_WRITEABLE, /* force read-only */ -+ }, { -+ name: "ramdisk.gz", -+ size: 0x300000, -+ offset: MTDPART_OFS_APPEND, -+ mask_flags: MTD_WRITEABLE, /* force read-only */ -+ }, { -+ name: "User FS", -+ size: MTDPART_SIZ_FULL, -+ offset: MTDPART_OFS_APPEND, -+ } -+}; -+#endif -+ - #ifdef CONFIG_SA1100_ADSBITSY - #define ADSBITSY_FLASH_SIZE 0x02000000 - static struct mtd_partition adsbitsy_partitions[] = { -@@ -123,6 +149,32 @@ - }; - #endif - -+#ifdef CONFIG_SA1100_ADSBITSYPLUS -+#define ADSBITSYPLUS_FLASH_SIZE 0x02000000 -+static struct mtd_partition adsbitsyplus_partitions[] = { -+ { -+ name: "bootROM", -+ size: 0x80000, -+ offset: 0, -+ mask_flags: MTD_WRITEABLE, /* force read-only */ -+ }, { -+ name: "zImage", -+ size: 0x100000, -+ offset: MTDPART_OFS_APPEND, -+ mask_flags: MTD_WRITEABLE, /* force read-only */ -+ }, { -+ name: "ramdisk.gz", -+ size: 0x300000, -+ offset: MTDPART_OFS_APPEND, -+ mask_flags: MTD_WRITEABLE, /* force read-only */ -+ }, { -+ name: "User FS", -+ size: MTDPART_SIZ_FULL, -+ offset: MTDPART_OFS_APPEND, -+ } -+}; -+#endif -+ - #ifdef CONFIG_SA1100_ASSABET - /* Phase 4 Assabet has two 28F160B3 flash parts in bank 0: */ - #define ASSABET4_FLASH_SIZE 0x00400000 -@@ -438,7 +490,7 @@ - #endif - - #ifdef CONFIG_SA1100_GRAPHICSMASTER --#define GRAPHICSMASTER_FLASH_SIZE 0x01000000 -+#define GRAPHICSMASTER_FLASH_SIZE 0x02000000 - static struct mtd_partition graphicsmaster_partitions[] = { - { - name: "zImage", -@@ -507,6 +559,38 @@ - } - #endif - -+#ifdef CONFIG_SA1100_HACKKIT -+#define HACKKIT_FLASH_SIZE 0x01000000 -+static struct mtd_partition hackkit_partitions[] = { -+ { -+ name: "BLOB", -+ size: 0x00040000, -+ offset: 0x00000000, -+ mask_flags: MTD_WRITEABLE, /* force read-only */ -+ }, { -+ name: "config", -+ size: 0x00040000, -+ offset: MTDPART_OFS_APPEND, -+ }, { -+ name: "kernel", -+ size: 0x00100000, -+ offset: MTDPART_OFS_APPEND, -+ }, { -+ name: "initrd", -+ size: 0x00180000, -+ offset: MTDPART_OFS_APPEND, -+ }, { -+ name: "rootfs", -+ size: 0x700000, -+ offset: MTDPART_OFS_APPEND, -+ }, { -+ name: "data", -+ size: MTDPART_SIZ_FULL, -+ offset: MTDPART_OFS_APPEND, -+ } -+}; -+#endif -+ - #ifdef CONFIG_SA1100_HUW_WEBPANEL - #define HUW_WEBPANEL_FLASH_SIZE 0x01000000 - static struct mtd_partition huw_webpanel_partitions[] = { -@@ -555,12 +639,12 @@ - offset: 0x00540000, - }, { - name: "JORNADA720 usr local", -- size: 0 /* will expand to the end of the flash */ -+ size: 0, /* will expand to the end of the flash */ - offset: 0x00d00000, - } - }; - --static void jornada720_set_vpp(int vpp) -+static void jornada720_set_vpp(struct map_info *map, int vpp) - { - if (vpp) - PPSR |= 0x80; -@@ -571,6 +655,27 @@ - - #endif - -+#ifdef CONFIG_SA1100_NANOENGINE -+/* nanoEngine has one 28F320B3B Flash part in bank 0: */ -+#define NANOENGINE_FLASH_SIZE 0x00400000 -+static struct mtd_partition nanoengine_partitions[] = { -+ { -+ name: "nanoEngine boot firmware and parameter table", -+ size: 0x00010000, /* 32K */ -+ offset: 0x00000000, -+ mask_flags: MTD_WRITEABLE, /* force read-only */ -+ },{ -+ name: "kernel/initrd reserved", -+ size: 0x002f0000, -+ offset: 0x00010000, -+ },{ -+ name: "experimental filesystem allocation", -+ size: 0x00100000, -+ offset: 0x00300000, -+ } -+}; -+#endif -+ - #ifdef CONFIG_SA1100_PANGOLIN - #define PANGOLIN_FLASH_SIZE 0x04000000 - static struct mtd_partition pangolin_partitions[] = { -@@ -699,6 +804,32 @@ - }; - #endif /* CONFIG_SA1100_SIMPAD */ - -+#ifdef CONFIG_SA1100_SIMPUTER -+#define SIMPUTER_FLASH_SIZE 0x02000000 -+static struct mtd_partition simputer_partitions[] = { -+ { -+ name: "blob+logo", -+ offset: 0, -+ size: 0x00040000 -+ }, -+ { -+ name: "kernel", -+ offset: MTDPART_OFS_APPEND, -+ size: 0x000C0000 -+ }, -+ { -+ name: "/(cramfs)", -+ offset: MTDPART_OFS_APPEND, -+ size: 0x00200000 -+ }, -+ { -+ name: "/usr/local(jffs2)", -+ offset: MTDPART_OFS_APPEND, -+ size: MTDPART_SIZ_FULL /* expand till the end */ -+ } -+}; -+#endif -+ - #ifdef CONFIG_SA1100_STORK - #define STORK_FLASH_SIZE 0x02000000 - static struct mtd_partition stork_partitions[] = { -@@ -766,7 +897,7 @@ - #endif - - extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); --extern int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts); -+extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *); - - static struct mtd_partition *parsed_parts; - static struct mtd_info *mymtd; -@@ -787,6 +918,14 @@ - */ - part_type = "static"; - -+#ifdef CONFIG_SA1100_ADSAGC -+ if (machine_is_adsagc()) { -+ parts = adsagc_partitions; -+ nb_parts = ARRAY_SIZE(adsagc_partitions); -+ sa1100_map.size = ADSAGC_FLASH_SIZE; -+ sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2 : 4; -+ } -+#endif - #ifdef CONFIG_SA1100_ADSBITSY - if (machine_is_adsbitsy()) { - parts = adsbitsy_partitions; -@@ -795,6 +934,14 @@ - sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2 : 4; - } - #endif -+#ifdef CONFIG_SA1100_ADSBITSYPLUS -+ if (machine_is_adsbitsyplus()) { -+ parts = adsbitsyplus_partitions; -+ nb_parts = ARRAY_SIZE(adsbitsyplus_partitions); -+ sa1100_map.size = ADSBITSYPLUS_FLASH_SIZE; -+ sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2 : 4; -+ } -+#endif - #ifdef CONFIG_SA1100_ASSABET - if (machine_is_assabet()) { - parts = assabet_partitions; -@@ -869,6 +1016,13 @@ - sa1100_map.set_vpp = h3600_set_vpp; - } - #endif -+#ifdef CONFIG_SA1100_HACKKIT -+ if (machine_is_hackkit()) { -+ parts = hackkit_partitions; -+ nb_parts = ARRAY_SIZE(hackkit_partitions); -+ sa1100_map.size = HACKKIT_FLASH_SIZE; -+ } -+#endif - #ifdef CONFIG_SA1100_HUW_WEBPANEL - if (machine_is_huw_webpanel()) { - parts = huw_webpanel_partitions; -@@ -884,6 +1038,13 @@ - sa1100_map.set_vpp = jornada720_set_vpp; - } - #endif -+#ifdef CONFIG_SA1100_NANOENGINE -+ if (machine_is_nanoengine()) { -+ parts = nanoengine_partitions; -+ nb_parts = ARRAY_SIZE(nanoengine_partitions); -+ sa1100_map.size = NANOENGINE_FLASH_SIZE; -+ } -+#endif - #ifdef CONFIG_SA1100_PANGOLIN - if (machine_is_pangolin()) { - parts = pangolin_partitions; -@@ -919,6 +1080,13 @@ - sa1100_map.size = SIMPAD_FLASH_SIZE; - } - #endif -+#ifdef CONFIG_SA1100_SIMPUTER -+ if (machine_is_simputer()) { -+ parts = simputer_partitions; -+ nb_parts = ARRAY_SIZE(simputer_partitions); -+ sa1100_map.size = SIMPUTER_FLASH_SIZE; -+ } -+#endif - #ifdef CONFIG_SA1100_STORK - if (machine_is_stork()) { - parts = stork_partitions; -@@ -953,7 +1121,9 @@ - * specific machine settings might have been set above. - */ - printk(KERN_NOTICE "SA1100 flash: probing %d-bit flash bus\n", sa1100_map.buswidth*8); -- mymtd = do_map_probe("cfi_probe", &sa1100_map); -+ mymtd = do_map_probe("jedec_probe", &sa1100_map); -+ if (!mymtd) -+ mymtd = do_map_probe("cfi_probe", &sa1100_map); - ret = -ENXIO; - if (!mymtd) - goto out_err; -diff -urN linux-2.4.26/drivers/mtd/nand/Config.in linux-2.4.26-vrs1/drivers/mtd/nand/Config.in ---- linux-2.4.26/drivers/mtd/nand/Config.in 2003-06-13 15:51:34.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/mtd/nand/Config.in 2004-04-10 12:50:22.000000000 +0100 -@@ -33,4 +33,8 @@ - fi - fi - -+if [ "$CONFIG_ARCH_AT91RM9200" = "y" ]; then -+ dep_tristate ' SmartMedia Card on Atmel AT91RM9200' CONFIG_MTD_AT91_SMARTMEDIA $CONFIG_MTD_NAND -+fi -+ - endmenu -diff -urN linux-2.4.26/drivers/net/Config.in linux-2.4.26-vrs1/drivers/net/Config.in ---- linux-2.4.26/drivers/net/Config.in 2004-04-19 11:44:16.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/net/Config.in 2004-04-18 21:47:50.000000000 +0100 -@@ -30,9 +30,15 @@ - if [ "$CONFIG_ARCH_ACORN" = "y" ]; then - source drivers/acorn/net/Config.in - fi -+ if [ "$CONFIG_ARCH_AT91RM9200" = "y" ]; then -+ tristate ' AT91RM9200 Ethernet support' CONFIG_AT91_ETHER -+ if [ "$CONFIG_AT91_ETHER" = "y" -o "$CONFIG_AT91_ETHER" = "m" ]; then -+ bool ' RMII interface? ' CONFIG_AT91_ETHER_RMII -+ fi -+ fi - fi - if [ "$CONFIG_ARCH_CAMELOT" = "y" ]; then -- tristate ' Altera Ether00 support' CONFIG_ETHER00 -+ tristate ' Altera Ether00 support' CONFIG_ETHER00 - fi - if [ "$CONFIG_PPC" = "y" ]; then - dep_tristate ' MACE (Power Mac ethernet) support' CONFIG_MACE $CONFIG_ALL_PPC -diff -urN linux-2.4.26/drivers/net/Makefile linux-2.4.26-vrs1/drivers/net/Makefile ---- linux-2.4.26/drivers/net/Makefile 2004-04-19 11:44:16.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/net/Makefile 2004-04-18 21:47:50.000000000 +0100 -@@ -244,6 +244,7 @@ - # non-drivers/net drivers who want mii lib - obj-$(CONFIG_PCMCIA_SMC91C92) += mii.o - obj-$(CONFIG_USB_USBNET) += mii.o -+obj-$(CONFIG_AT91_ETHER) += mii.o - - ifeq ($(CONFIG_ARCH_ACORN),y) - mod-subdirs += ../acorn/net -@@ -268,4 +269,3 @@ - - rcpci.o: $(rcpci-objs) - $(LD) -r -o $@ $(rcpci-objs) -- -diff -urN linux-2.4.26/drivers/net/am79c961a.c linux-2.4.26-vrs1/drivers/net/am79c961a.c ---- linux-2.4.26/drivers/net/am79c961a.c 2003-06-13 15:51:34.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/net/am79c961a.c 2004-01-14 21:32:26.000000000 +0000 -@@ -54,25 +54,36 @@ - #ifdef __arm__ - static void write_rreg(u_long base, u_int reg, u_int val) - { -- __asm__("str%?h %1, [%2] @ NET_RAP -- str%?h %0, [%2, #-4] @ NET_RDP -- " : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464)); -+ __asm__("str%?h %1, [%2] @ NET_RAP\n\t" -+ "str%?h %0, [%2, #-4] @ NET_RDP" -+ : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464)); - } - - static inline unsigned short read_rreg(u_long base_addr, u_int reg) - { - unsigned short v; -- __asm__("str%?h %1, [%2] @ NET_RAP -- ldr%?h %0, [%2, #-4] @ NET_RDP -- " : "=r" (v): "r" (reg), "r" (ISAIO_BASE + 0x0464)); -+ __asm__("str%?h %1, [%2] @ NET_RAP\n\t" -+ "ldr%?h %0, [%2, #-4] @ NET_RDP" -+ : "=r" (v): "r" (reg), "r" (ISAIO_BASE + 0x0464)); - return v; - } - - static inline void write_ireg(u_long base, u_int reg, u_int val) - { -- __asm__("str%?h %1, [%2] @ NET_RAP -- str%?h %0, [%2, #8] @ NET_IDP -- " : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464)); -+ __asm__("str%?h %1, [%2] @ NET_RAP\n\t" -+ "str%?h %0, [%2, #8] @ NET_IDP" -+ : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464)); -+} -+ -+static inline unsigned short read_ireg(u_long base_addr, u_int reg) -+{ -+ u_short v; -+ __asm__( -+ "str%?h %1, [%2] @ NAT_RAP\n\t" -+ "str%?h %0, [%2, #8] @ NET_IDP\n\t" -+ : "=r" (v) -+ : "r" (reg), "r" (ISAIO_BASE + 0x0464)); -+ return v; - } - - #define am_writeword(dev,off,val) __raw_writew(val, ISAMEM_BASE + ((off) << 1)) -@@ -91,16 +102,16 @@ - } - while (length > 8) { - unsigned int tmp, tmp2; -- __asm__ __volatile__(" -- ldm%?ia %1!, {%2, %3} -- str%?h %2, [%0], #4 -- mov%? %2, %2, lsr #16 -- str%?h %2, [%0], #4 -- str%?h %3, [%0], #4 -- mov%? %3, %3, lsr #16 -- str%?h %3, [%0], #4 -- " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2) -- : "0" (offset), "1" (buf)); -+ __asm__ __volatile__( -+ "ldm%?ia %1!, {%2, %3}\n\t" -+ "str%?h %2, [%0], #4\n\t" -+ "mov%? %2, %2, lsr #16\n\t" -+ "str%?h %2, [%0], #4\n\t" -+ "str%?h %3, [%0], #4\n\t" -+ "mov%? %3, %3, lsr #16\n\t" -+ "str%?h %3, [%0], #4" -+ : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2) -+ : "0" (offset), "1" (buf)); - length -= 8; - } - while (length > 0) { -@@ -118,36 +129,36 @@ - length = (length + 1) & ~1; - if ((int)buf & 2) { - unsigned int tmp; -- __asm__ __volatile__(" -- ldr%?h %2, [%0], #4 -- str%?b %2, [%1], #1 -- mov%? %2, %2, lsr #8 -- str%?b %2, [%1], #1 -- " : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf)); -+ __asm__ __volatile__( -+ "ldr%?h %2, [%0], #4\n\t" -+ "str%?b %2, [%1], #1\n\t" -+ "mov%? %2, %2, lsr #8\n\t" -+ "str%?b %2, [%1], #1" -+ : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf)); - length -= 2; - } - while (length > 8) { - unsigned int tmp, tmp2, tmp3; -- __asm__ __volatile__(" -- ldr%?h %2, [%0], #4 -- ldr%?h %3, [%0], #4 -- orr%? %2, %2, %3, lsl #16 -- ldr%?h %3, [%0], #4 -- ldr%?h %4, [%0], #4 -- orr%? %3, %3, %4, lsl #16 -- stm%?ia %1!, {%2, %3} -- " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3) -- : "0" (offset), "1" (buf)); -+ __asm__ __volatile__( -+ "ldr%?h %2, [%0], #4\n\t" -+ "ldr%?h %3, [%0], #4\n\t" -+ "orr%? %2, %2, %3, lsl #16\n\t" -+ "ldr%?h %3, [%0], #4\n\t" -+ "ldr%?h %4, [%0], #4\n\t" -+ "orr%? %3, %3, %4, lsl #16\n\t" -+ "stm%?ia %1!, {%2, %3}" -+ : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3) -+ : "0" (offset), "1" (buf)); - length -= 8; - } - while (length > 0) { - unsigned int tmp; -- __asm__ __volatile__(" -- ldr%?h %2, [%0], #4 -- str%?b %2, [%1], #1 -- mov%? %2, %2, lsr #8 -- str%?b %2, [%1], #1 -- " : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf)); -+ __asm__ __volatile__( -+ "ldr%?h %2, [%0], #4\n\t" -+ "str%?b %2, [%1], #1\n\t" -+ "mov%? %2, %2, lsr #8\n\t" -+ "str%?b %2, [%1], #1" -+ : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf)); - length -= 2; - } - } -@@ -254,9 +265,27 @@ - write_rreg (dev->base_addr, BASERXH, 0); - write_rreg (dev->base_addr, CSR0, CSR0_STOP); - write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM|CSR3_DXSUFLO); -+ write_rreg (dev->base_addr, CSR4, CSR4_APAD_XMIT|CSR4_MFCOM|CSR4_RCVCCOM|CSR4_TXSTRTM|CSR4_JABM); - write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT); - } - -+static void am79c961_timer(unsigned long data) -+{ -+ struct net_device *dev = (struct net_device *)data; -+ struct dev_priv *priv = (struct dev_priv *)dev->priv; -+ unsigned int lnkstat, carrier; -+ -+ lnkstat = read_ireg(dev->base_addr, ISALED0) & ISALED0_LNKST; -+ carrier = netif_carrier_ok(dev); -+ -+ if (lnkstat && !carrier) -+ netif_carrier_on(dev); -+ else if (!lnkstat && carrier) -+ netif_carrier_off(dev); -+ -+ mod_timer(&priv->timer, jiffies + 5*HZ); -+} -+ - /* - * Open/initialize the board. - */ -@@ -274,6 +303,11 @@ - - am79c961_init_for_open(dev); - -+ netif_carrier_off(dev); -+ -+ priv->timer.expires = jiffies; -+ add_timer(&priv->timer); -+ - netif_start_queue(dev); - - return 0; -@@ -288,7 +322,10 @@ - struct dev_priv *priv = (struct dev_priv *)dev->priv; - unsigned long flags; - -+ del_timer_sync(&priv->timer); -+ - netif_stop_queue(dev); -+ netif_carrier_off(dev); - - spin_lock_irqsave(priv->chip_lock, flags); - write_rreg (dev->base_addr, CSR0, CSR0_STOP); -@@ -413,15 +450,6 @@ - unsigned int hdraddr, bufaddr; - unsigned int head; - unsigned long flags; -- -- /* FIXME: I thought the 79c961 could do padding - RMK ??? */ -- if(length < ETH_ZLEN) -- { -- skb = skb_padto(skb, ETH_ZLEN); -- if(skb == NULL) -- return 0; -- length = ETH_ZLEN; -- } - - head = priv->txhead; - hdraddr = priv->txhdr + (head << 3); -@@ -431,7 +459,7 @@ - head = 0; - - am_writebuffer (dev, bufaddr, skb->data, length); -- am_writeword (dev, hdraddr + 4, -length); -+ am_writeword (dev, hdraddr + 4, -skb->len); - am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP); - priv->txhead = head; - -@@ -448,6 +476,8 @@ - if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN) - netif_stop_queue(dev); - -+ priv->stats.tx_bytes += skb->len; -+ - dev_kfree_skb(skb); - - return 0; -@@ -520,6 +550,7 @@ - am79c961_tx(struct net_device *dev, struct dev_priv *priv) - { - do { -+ signed short len; - u_int hdraddr; - u_int status; - -@@ -555,6 +586,8 @@ - continue; - } - priv->stats.tx_packets ++; -+ len = am_readword (dev, hdraddr + 4); -+ priv->stats.tx_bytes += -len; - } while (priv->txtail != priv->txhead); - - netif_wake_queue(dev); -@@ -565,17 +598,23 @@ - { - struct net_device *dev = (struct net_device *)dev_id; - struct dev_priv *priv = (struct dev_priv *)dev->priv; -- u_int status; -+ u_int status, n = 100; - -- status = read_rreg(dev->base_addr, CSR0); -- write_rreg(dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA)); -- -- if (status & CSR0_RINT) -- am79c961_rx(dev, priv); -- if (status & CSR0_TINT) -- am79c961_tx(dev, priv); -- if (status & CSR0_MISS) -- priv->stats.rx_dropped ++; -+ do { -+ status = read_rreg(dev->base_addr, CSR0); -+ write_rreg(dev->base_addr, CSR0, status & -+ (CSR0_IENA|CSR0_TINT|CSR0_RINT| -+ CSR0_MERR|CSR0_MISS|CSR0_CERR|CSR0_BABL)); -+ -+ if (status & CSR0_RINT) -+ am79c961_rx(dev, priv); -+ if (status & CSR0_TINT) -+ am79c961_tx(dev, priv); -+ if (status & CSR0_MISS) -+ priv->stats.rx_dropped ++; -+ if (status & CSR0_CERR) -+ mod_timer(&priv->timer, jiffies); -+ } while (--n && status & (CSR0_RINT | CSR0_TINT)); - } - - /* -@@ -587,10 +626,10 @@ - { - struct dev_priv *priv = (struct dev_priv *)dev->priv; - -- spin_lock_irq(priv->chip_lock); -+ spin_lock_irq(&priv->chip_lock); - write_rreg (dev->base_addr, CSR0, CSR0_STOP); - write_rreg (dev->base_addr, CSR3, CSR3_MASKALL); -- spin_unlock_irq(priv->chip_lock); -+ spin_unlock_irq(&priv->chip_lock); - - am79c961_ramtest(dev, 0x66); - am79c961_ramtest(dev, 0x99); -@@ -655,6 +694,11 @@ - printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]); - } - -+ spin_lock_init(&priv->chip_lock); -+ init_timer(&priv->timer); -+ priv->timer.data = (unsigned long)dev; -+ priv->timer.function = am79c961_timer; -+ - if (am79c961_hw_init(dev)) - goto release; - -diff -urN linux-2.4.26/drivers/net/am79c961a.h linux-2.4.26-vrs1/drivers/net/am79c961a.h ---- linux-2.4.26/drivers/net/am79c961a.h 2000-09-18 23:15:22.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/net/am79c961a.h 2004-01-14 21:32:26.000000000 +0000 -@@ -58,6 +58,18 @@ - #define CSR3_BABLM 0x4000 - #define CSR3_MASKALL 0x5F00 - -+#define CSR4 4 -+#define CSR4_JABM 0x0001 -+#define CSR4_JAB 0x0002 -+#define CSR4_TXSTRTM 0x0004 -+#define CSR4_TXSTRT 0x0008 -+#define CSR4_RCVCCOM 0x0010 -+#define CSR4_RCVCCO 0x0020 -+#define CSR4_MFCOM 0x0100 -+#define CSR4_MFCO 0x0200 -+#define CSR4_ASTRP_RCV 0x0400 -+#define CSR4_APAD_XMIT 0x0800 -+ - #define CTRL1 5 - #define CTRL1_SPND 0x0001 - -@@ -93,6 +105,8 @@ - #define SIZERXR 76 - #define SIZETXR 78 - -+#define CSR_MFC 112 -+ - #define RMD_ENP 0x0100 - #define RMD_STP 0x0200 - #define RMD_CRC 0x0800 -@@ -112,6 +126,9 @@ - #define TST_UFLO 0x4000 - #define TST_BUFF 0x8000 - -+#define ISALED0 0x0004 -+#define ISALED0_LNKST 0x8000 -+ - struct dev_priv { - struct net_device_stats stats; - unsigned long rxbuffer[RX_BUFFERS]; -@@ -123,6 +140,7 @@ - unsigned long rxhdr; - unsigned long txhdr; - spinlock_t chip_lock; -+ struct timer_list timer; - }; - - extern int am79c961_probe (struct net_device *dev); -diff -urN linux-2.4.26/drivers/net/cirrus.c linux-2.4.26-vrs1/drivers/net/cirrus.c ---- linux-2.4.26/drivers/net/cirrus.c 2003-06-13 15:51:34.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/net/cirrus.c 2004-01-14 21:32:26.000000000 +0000 -@@ -75,6 +75,7 @@ - typedef struct { - struct net_device_stats stats; - u16 txlen; -+ u16 txafter; /* Default is After5 (0) */ - } cirrus_t; - - typedef struct { -@@ -230,13 +231,19 @@ - cirrus_t *priv = (cirrus_t *) dev->priv; - u16 status; - -+ /* Tx start must be done with irq disabled -+ * else status can be wrong */ -+ disable_irq (dev->irq); -+ - netif_stop_queue (dev); - -- cirrus_write (dev,PP_TxCMD,TxStart (After5)); -+ cirrus_write (dev,PP_TxCMD,TxStart (priv->txafter)); - cirrus_write (dev,PP_TxLength,skb->len); - - status = cirrus_read (dev,PP_BusST); - -+ enable_irq (dev->irq); -+ - if ((status & TxBidErr)) { - printk (KERN_WARNING "%s: Invalid frame size %d!\n",dev->name,skb->len); - priv->stats.tx_errors++; -@@ -249,7 +256,6 @@ - printk (KERN_WARNING "%s: Transmit buffer not free!\n",dev->name); - priv->stats.tx_errors++; - priv->txlen = 0; -- /* FIXME: store skb and send it in interrupt handler */ - return (1); - } - -@@ -310,11 +316,18 @@ - } - if ((RegContent (status) & TxUnderrun)) { - priv->stats.tx_errors++; -- priv->stats.tx_fifo_errors++; -+ /* Shift start tx, if underruns come too often */ -+ switch (priv->stats.tx_fifo_errors++) { -+ case 3: priv->txafter = After381; break; -+ case 6: priv->txafter = After1021; break; -+ case 9: priv->txafter = AfterAll; break; -+ } -+ } -+ /* Wakeup only for tx events ! */ -+ if ((RegContent (status) & (TxUnderrun | Rdy4Tx))) { -+ priv->txlen = 0; -+ netif_wake_queue (dev); - } -- /* FIXME: if Rdy4Tx, transmit last sent packet (if any) */ -- priv->txlen = 0; -- netif_wake_queue (dev); - break; - - case TxCOL: -@@ -428,7 +441,7 @@ - else - cirrus_clear (dev,PP_RxCTL,PromiscuousA); - -- if ((dev->flags & IFF_ALLMULTI) && dev->mc_list) -+ if ((dev->flags & IFF_ALLMULTI) || dev->mc_list) - cirrus_set (dev,PP_RxCTL,MulticastA); - else - cirrus_clear (dev,PP_RxCTL,MulticastA); -diff -urN linux-2.4.26/drivers/net/cs89x0.c linux-2.4.26-vrs1/drivers/net/cs89x0.c ---- linux-2.4.26/drivers/net/cs89x0.c 2003-08-25 12:44:42.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/net/cs89x0.c 2004-01-14 21:39:05.000000000 +0000 -@@ -115,6 +115,7 @@ - - */ - -+#include - #include - #include - #include -@@ -427,18 +428,18 @@ - /* if they give us an odd I/O address, then do ONE write to - the address port, to get it back to address zero, where we - expect to find the EISA signature word. An IO with a base of 0x3 -- will skip the test for the ADD_PORT. */ -+ will skip the test for the ADD_PORT. */ - if (ioaddr & 1) { - if (net_debug > 1) - printk(KERN_INFO "%s: odd ioaddr 0x%x\n", dev->name, ioaddr); -- if ((ioaddr & 2) != 2) -+ if ((ioaddr & 2) != 2) - if ((inw((ioaddr & ~3)+ ADD_PORT) & ADD_MASK) != ADD_SIG) { - printk(KERN_ERR "%s: bad signature 0x%x\n", - dev->name, inw((ioaddr & ~3)+ ADD_PORT)); - retval = -ENODEV; - goto out2; - } -- ioaddr &= ~3; -+ ioaddr &= ~3; - outw(PP_ChipID, ioaddr + ADD_PORT); - } - printk("PP_addr=0x%x\n", inw(ioaddr + ADD_PORT)); -@@ -446,7 +447,7 @@ - if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG) { - printk(KERN_ERR "%s: incorrect signature 0x%x\n", - dev->name, inw(ioaddr + DATA_PORT)); -- retval = -ENODEV; -+ retval = -ENODEV; - goto out2; - } - -@@ -477,7 +478,7 @@ - dev->base_addr); - - reset_chip(dev); -- -+ - /* Here we read the current configuration of the chip. If there - is no Extended EEPROM then the idea is to not disturb the chip - configuration, it should have been correctly setup by automatic -diff -urN linux-2.4.26/drivers/net/ether00.c linux-2.4.26-vrs1/drivers/net/ether00.c ---- linux-2.4.26/drivers/net/ether00.c 2003-06-13 15:51:34.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/net/ether00.c 2004-01-14 21:32:26.000000000 +0000 -@@ -38,6 +38,7 @@ - #include - #include - -+static int ether00_get_ethernet_address(struct net_device* dev); - - MODULE_AUTHOR("Clive Davies"); - MODULE_DESCRIPTION("Altera Ether00 IP core driver"); -@@ -734,8 +735,11 @@ - int result,tmp; - struct net_priv* priv; - -- if (!is_valid_ether_addr(dev->dev_addr)) -- return -EINVAL; -+ if (!ether00_get_ethernet_address(dev)){ -+ printk("%s: Invalid ethernet MAC address. Please set using " -+ "ifconfig\n", dev->name); -+ return -EINVAL; -+ } - - dev->base_addr=(unsigned int)ioremap_nocache(base,SZ_4K); - -@@ -906,10 +910,9 @@ - } - - --static void ether00_get_ethernet_address(struct net_device* dev) -+static int ether00_get_ethernet_address(struct net_device* dev) - { - struct mtd_info *mymtd=NULL; -- int i; - size_t retlen; - - /* -@@ -926,11 +929,7 @@ - #ifdef CONFIG_ARCH_CAMELOT - #ifdef CONFIG_MTD - /* get the mtd_info structure for the first mtd device*/ -- for(i=0;iname,"EPXA10DB flash")) -- break; -- } -+ mymtd=get_mtd_device(NULL,0); - - if(!mymtd || !mymtd->read_user_prot_reg){ - printk(KERN_WARNING "%s: Failed to read MAC address from flash\n",dev->name); -@@ -947,9 +946,7 @@ - #endif - #endif - -- if (!is_valid_ether_addr(dev->dev_addr)) -- printk("%s: Invalid ethernet MAC address. Please set using " -- "ifconfig\n", dev->name); -+ return (is_valid_ether_addr(dev->dev_addr)); - - } - -@@ -966,8 +963,6 @@ - dev->tx_timeout=ether00_tx_timeout; - dev->watchdog_timeo=TX_TIMEOUT; - -- ether00_get_ethernet_address(dev); -- - SET_MODULE_OWNER(dev); - return 0; - } -diff -urN linux-2.4.26/drivers/net/irda/Config.in linux-2.4.26-vrs1/drivers/net/irda/Config.in ---- linux-2.4.26/drivers/net/irda/Config.in 2004-02-27 20:03:26.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/net/irda/Config.in 2004-02-23 23:21:17.000000000 +0000 -@@ -40,7 +40,7 @@ - dep_tristate 'VIA IrCC (Experimental)' CONFIG_VIA_IRCC_FIR $CONFIG_IRDA - fi - if [ "$CONFIG_ARCH_SA1100" = "y" ]; then -- dep_tristate 'SA1100 Internal IR' CONFIG_SA1100_FIR $CONFIG_IRDA -+ dep_tristate 'SA1100 Internal IR' CONFIG_SA1100_FIR $CONFIG_IRDA $CONFIG_EXPERIMENTAL - fi - - endmenu -diff -urN linux-2.4.26/drivers/net/irda/sa1100_ir.c linux-2.4.26-vrs1/drivers/net/irda/sa1100_ir.c ---- linux-2.4.26/drivers/net/irda/sa1100_ir.c 2002-08-03 01:39:44.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/net/irda/sa1100_ir.c 2004-01-14 21:32:26.000000000 +0000 -@@ -38,11 +38,7 @@ - - #include - --#ifndef CONFIG_SA1100_H3600 --#define clr_h3600_egpio(x) do { } while (0) --#define set_h3600_egpio(x) do { } while (0) --#endif -- -+/* Yopy wants fixing */ - #ifndef GPIO_IRDA_FIR - #define GPIO_IRDA_FIR (0) - #endif -@@ -174,8 +170,8 @@ - - if (machine_is_assabet()) - ASSABET_BCR_clear(ASSABET_BCR_IRDA_FSEL); -- if (machine_is_h3600()) -- clr_h3600_egpio(EGPIO_H3600_IR_FSEL); -+ if (machine_is_h3xxx()) -+ clr_h3600_egpio(IPAQ_EGPIO_IR_FSEL); - if (machine_is_yopy()) - PPSR &= ~GPIO_IRDA_FIR; - -@@ -199,8 +195,8 @@ - - if (machine_is_assabet()) - ASSABET_BCR_set(ASSABET_BCR_IRDA_FSEL); -- if (machine_is_h3600()) -- set_h3600_egpio(EGPIO_H3600_IR_FSEL); -+ if (machine_is_h3xxx()) -+ set_h3600_egpio(IPAQ_EGPIO_IR_FSEL); - if (machine_is_yopy()) - PPSR |= GPIO_IRDA_FIR; - -@@ -246,10 +242,7 @@ - static inline int - sa1100_irda_set_power_h3600(struct sa1100_irda *si, unsigned int state) - { -- if (state) -- set_h3600_egpio(EGPIO_H3600_IR_ON); -- else -- clr_h3600_egpio(EGPIO_H3600_IR_ON); -+ assign_h3600_egpio( IPAQ_EGPIO_IR_ON, state ); - return 0; - } - -@@ -283,7 +276,7 @@ - - if (machine_is_assabet()) - ret = sa1100_irda_set_power_assabet(si, state); -- if (machine_is_h3600()) -+ if (machine_is_h3xxx()) - ret = sa1100_irda_set_power_h3600(si, state); - if (machine_is_yopy()) - ret = sa1100_irda_set_power_yopy(si, state); -@@ -727,11 +720,6 @@ - netif_wake_queue(dev); - } - --/* -- * Note that we will never build up a backlog of frames; the protocol is a -- * half duplex protocol which basically means we transmit a frame, we -- * receive a frame, we transmit the next frame etc. -- */ - static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) - { - struct sa1100_irda *si = dev->priv; -@@ -758,6 +746,8 @@ - } - - if (!IS_FIR(si)) { -+ netif_stop_queue(dev); -+ - si->tx_buff.data = si->tx_buff.head; - si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, - si->tx_buff.truesize); -diff -urN linux-2.4.26/drivers/net/irda/w83977af_ir.c linux-2.4.26-vrs1/drivers/net/irda/w83977af_ir.c ---- linux-2.4.26/drivers/net/irda/w83977af_ir.c 2002-11-28 23:53:13.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/net/irda/w83977af_ir.c 2004-01-14 21:32:26.000000000 +0000 -@@ -205,7 +205,7 @@ - - /* FIXME: The HP HDLS-1100 does not support 1152000! */ - self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| -- IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8); -+ IR_115200/*|IR_576000|IR_1152000|(IR_4000000 << 8)*/; - - /* The HP HDLS-1100 needs 1 ms according to the specs */ - self->qos.min_turn_time.bits = qos_mtt_bits; -@@ -1341,7 +1341,7 @@ - case SIOCSBANDWIDTH: /* Set bandwidth */ - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; -- goto out; -+ break; - } - w83977af_change_speed(self, irq->ifr_baudrate); - break; -diff -urN linux-2.4.26/drivers/net/smc9194.c linux-2.4.26-vrs1/drivers/net/smc9194.c ---- linux-2.4.26/drivers/net/smc9194.c 2003-06-13 15:51:35.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/net/smc9194.c 2004-01-14 21:32:26.000000000 +0000 -@@ -12,8 +12,8 @@ - . AUI/TP selection ( mine has 10Base2/10BaseT select ) - . - . Arguments: -- . io = for the base address -- . irq = for the IRQ -+ . io = for the base address -+ . irq = for the IRQ - . ifport = 0 for autodetect, 1 for TP, 2 for AUI ( or 10base2 ) - . - . author: -@@ -51,12 +51,21 @@ - . allocation - . 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet - . 12/15/00 Christian Jullien fix "Warning: kfree_skb on hard IRQ" -+ . 06/23/01 Russell King Separate out IO functions for different bus -+ . types. -+ . Use dev->name instead of CARDNAME for printk -+ . Add ethtool support, full duplex support -+ . Add LAN91C96 support. - . 11/08/01 Matt Domsch Use common crc32 function - ----------------------------------------------------------------------------*/ - -+#define DRV_NAME "smc9194" -+#define DRV_VERSION "0.15" -+ - static const char version[] = -- "smc9194.c:v0.14 12/15/00 by Erik Stahlman (erik@vt.edu)\n"; -+ DRV_NAME ".c:v" DRV_VERSION " 12/15/00 by Erik Stahlman (erik@vt.edu)\n"; - -+#include - #include - #include - #include -@@ -69,16 +78,26 @@ - #include - #include - #include -+#include - #include - #include --#include --#include - #include -+#include - - #include - #include - #include - -+#include -+#include -+#include -+#include -+ -+#ifdef CONFIG_ARCH_SA1100 -+#include -+#include -+#endif -+ - #include "smc9194.h" - /*------------------------------------------------------------------------ - . -@@ -152,29 +171,27 @@ - -------------------------------------------------------------------------*/ - #define CARDNAME "SMC9194" - -+static const char *chip_ids[15] = { -+ NULL, -+ NULL, -+ NULL, -+ "SMC91C90/91C92", /* 3 */ -+ "SMC91C94/91C96", /* 4 */ -+ "SMC91C95", /* 5 */ -+ NULL, -+ "SMC91C100", /* 7 */ -+ "SMC91C100FD", /* 8 */ -+ NULL, -+ NULL, -+ NULL, -+ NULL, -+ NULL, -+ NULL -+}; - --/* store this information for the driver.. */ --struct smc_local { -- /* -- these are things that the kernel wants me to keep, so users -- can find out semi-useless statistics of how well the card is -- performing -- */ -- struct net_device_stats stats; -- -- /* -- If I have to wait until memory is available to send -- a packet, I will store the skbuff here, until I get the -- desired memory. Then, I'll send it out and free it. -- */ -- struct sk_buff * saved_skb; -- -- /* -- . This keeps track of how many packets that I have -- . sent out. When an TX_EMPTY interrupt comes, I know -- . that all of these have been sent. -- */ -- int packets_waiting; -+static const char * interfaces[2] = { -+ "TP", -+ "AUI" - }; - - -@@ -202,6 +219,11 @@ - static int smc_open(struct net_device *dev); - - /* -+ . This handles the ethtool interface -+*/ -+static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -+ -+/* - . Our watchdog timed out. Called by the networking layer - */ - static void smc_timeout(struct net_device *dev); -@@ -217,11 +239,11 @@ - . This routine allows the proc file system to query the driver's - . statistics. - */ --static struct net_device_stats * smc_query_statistics( struct net_device *dev); -+static struct net_device_stats * smc_query_statistics(struct net_device *dev); - - /* -- . Finally, a call to set promiscuous mode ( for TCPDUMP and related -- . programs ) and multicast modes. -+ . Finally, a call to set promiscuous mode (for TCPDUMP and related -+ . programs) and multicast modes. - */ - static void smc_set_multicast_list(struct net_device *dev); - -@@ -240,12 +262,12 @@ - . This is a separate procedure to handle the receipt of a packet, to - . leave the interrupt code looking slightly cleaner - */ --static inline void smc_rcv( struct net_device *dev ); -+static inline void smc_rcv(struct net_device *dev); - /* - . This handles a TX interrupt, which is only called when an error - . relating to a packet is sent. - */ --static inline void smc_tx( struct net_device * dev ); -+static inline void smc_tx(struct net_device * dev); - - /* - ------------------------------------------------------------ -@@ -261,39 +283,287 @@ - */ - static int smc_probe(struct net_device *dev, int ioaddr); - --/* -- . A rather simple routine to print out a packet for debugging purposes. --*/ --#if SMC_DEBUG > 2 --static void print_packet( byte *, int ); --#endif -- --#define tx_done(dev) 1 -- - /* this is called to actually send the packet to the chip */ --static void smc_hardware_send_packet( struct net_device * dev ); -+static void smc_hardware_send_packet(struct net_device * dev); - - /* Since I am not sure if I will have enough room in the chip's ram - . to store the packet, I call this routine, which either sends it - . now, or generates an interrupt when the card is ready for the - . packet */ --static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device *dev ); -+static int smc_wait_to_send_packet(struct sk_buff * skb, struct net_device *dev); - - /* this does a soft reset on the device */ --static void smc_reset( int ioaddr ); -+static void smc_reset(struct net_device *dev); - - /* Enable Interrupts, Receive, and Transmit */ --static void smc_enable( int ioaddr ); -+static void smc_enable(struct net_device *dev); - - /* this puts the device in an inactive state */ --static void smc_shutdown( int ioaddr ); -+static void smc_shutdown(struct net_device *dev); - - /* This routine will find the IRQ of the driver if one is not - . specified in the input to the device. */ --static int smc_findirq( int ioaddr ); -+static int smc_findirq(struct net_device *dev); -+ -+#ifndef CONFIG_ASSABET_NEPONSET -+/* -+ * These functions allow us to handle IO addressing as we wish - this -+ * ethernet controller can be connected to a variety of busses. Some -+ * busses do not support 16 bit or 32 bit transfers. --rmk -+ */ -+static inline u8 smc_inb(u_int base, u_int reg) -+{ -+ return inb(base + reg); -+} -+ -+static inline u16 smc_inw(u_int base, u_int reg) -+{ -+ return inw(base + reg); -+} -+ -+static inline void smc_ins(u_int base, u_int reg, u8 *data, u_int len) -+{ -+ u_int port = base + reg; -+#ifdef USE_32_BIT -+ /* QUESTION: Like in the TX routine, do I want -+ to send the DWORDs or the bytes first, or some -+ mixture. A mixture might improve already slow PIO -+ performance */ -+ PRINTK3((" Reading %d dwords (and %d bytes) \n", -+ len >> 2, len & 3)); -+ insl(port, data, len >> 2); -+ /* read the left over bytes */ -+ insb(port, data + (len & ~3), len & 3); -+#else -+ PRINTK3((" Reading %d words and %d byte(s) \n", -+ len >> 1, len & 1)); -+ insw(port, data, len >> 1); -+ if (len & 1) { -+ data += len & ~1; -+ *data = inb(port); -+ } -+#endif -+} -+ -+static inline void smc_outb(u8 val, u_int base, u_int reg) -+{ -+ outb(val, base + reg); -+} -+ -+static inline void smc_outw(u16 val, u_int base, u_int reg) -+{ -+ outw(val, base + reg); -+} -+ -+static inline void smc_outl(u32 val, u_int base, u_int reg) -+{ -+ u_int port = base + reg; -+#ifdef USE_32_BIT -+ outl(val, port); -+#else -+ outw(val, port); -+ outw(val >> 16, port); -+#endif -+} -+ -+static inline void smc_outs(u_int base, u_int reg, u8 *data, u_int len) -+{ -+ u_int port = base + reg; -+#ifdef USE_32_BIT -+ if (len & 2) { -+ outsl(port, data, len >> 2); -+ outw(*((word *)(data + (len & ~3))), port); -+ } -+ else -+ outsl(port, data, len >> 2); -+#else -+ outsw(port, data, len >> 1); -+#endif -+} -+ -+ -+/*------------------------------------------------------------------------- -+ . I define some macros to make it easier to do somewhat common -+ . or slightly complicated, repeated tasks. -+ --------------------------------------------------------------------------*/ -+ -+/* select a register bank, 0 to 3 */ -+ -+#define SMC_SELECT_BANK(x) \ -+ { \ -+ smc_outw(x, ioaddr, BANK_SELECT); \ -+ } -+ -+/* define a small delay for the reset */ -+#define SMC_DELAY() \ -+ { \ -+ smc_inw(ioaddr, RCR); \ -+ smc_inw(ioaddr, RCR); \ -+ smc_inw(ioaddr, RCR); \ -+ } -+ -+/* this enables an interrupt in the interrupt mask register */ -+#define SMC_ENABLE_INT(x) \ -+ { \ -+ byte mask; \ -+ mask = smc_inb(ioaddr, INT_MASK); \ -+ mask |= (x); \ -+ smc_outb(mask, ioaddr, INT_MASK); \ -+ } -+ -+/* this sets the absolutel interrupt mask */ -+#define SMC_SET_INT(x) \ -+ { \ -+ smc_outw((x), INT_MASK); \ -+ } -+ -+#else -+ -+#undef SMC_IO_EXTENT -+#define SMC_IO_EXTENT (16 << 2) -+ -+/* -+ * These functions allow us to handle IO addressing as we wish - this -+ * ethernet controller can be connected to a variety of busses. Some -+ * busses do not support 16 bit or 32 bit transfers. --rmk -+ */ -+static inline u8 smc_inb(u_int base, u_int reg) -+{ -+ u_int port = base + reg * 4; -+ -+ return readb(port); -+} -+ -+static inline u16 smc_inw(u_int base, u_int reg) -+{ -+ u_int port = base + reg * 4; -+ -+ return readb(port) | readb(port + 4) << 8; -+} -+ -+static inline void smc_ins(u_int base, u_int reg, u8 *data, u_int len) -+{ -+ u_int port = base + reg * 4; -+ -+ insb(port, data, len); -+} -+ -+static inline void smc_outb(u8 val, u_int base, u_int reg) -+{ -+ u_int port = base + reg * 4; -+ -+ writeb(val, port); -+} -+ -+static inline void smc_outw(u16 val, u_int base, u_int reg) -+{ -+ u_int port = base + reg * 4; -+ -+ writeb(val, port); -+ writeb(val >> 8, port + 4); -+} -+ -+static inline void smc_outl(u32 val, u_int base, u_int reg) -+{ -+ u_int port = base + reg * 4; -+ -+ writeb(val, port); -+ writeb(val >> 8, port + 4); -+ writeb(val >> 16, port + 8); -+ writeb(val >> 24, port + 12); -+} -+ -+static inline void smc_outs(u_int base, u_int reg, u8 *data, u_int len) -+{ -+ u_int port = base + reg * 4; -+ -+ outsb(port, data, len & ~1); -+} -+ -+/*------------------------------------------------------------------------- -+ . I define some macros to make it easier to do somewhat common -+ . or slightly complicated, repeated tasks. -+ --------------------------------------------------------------------------*/ -+ -+/* select a register bank, 0 to 3 */ -+ -+#define SMC_SELECT_BANK(x) \ -+ { \ -+ smc_outb(x, ioaddr, BANK_SELECT); \ -+ } -+ -+/* define a small delay for the reset */ -+#define SMC_DELAY() \ -+ { \ -+ smc_inb(ioaddr, RCR); \ -+ smc_inb(ioaddr, RCR); \ -+ smc_inb(ioaddr, RCR); \ -+ } -+ -+/* this enables an interrupt in the interrupt mask register */ -+#define SMC_ENABLE_INT(x) \ -+ { \ -+ byte mask; \ -+ mask = smc_inb(ioaddr, INT_MASK); \ -+ mask |= (x); \ -+ smc_outb(mask, ioaddr, INT_MASK); \ -+ } -+ -+/* this sets the absolutel interrupt mask */ -+#define SMC_SET_INT(x) \ -+ { \ -+ smc_outb((x), ioaddr, INT_MASK); \ -+ } -+ -+#endif - - /* -- . Function: smc_reset( int ioaddr ) -+ . A rather simple routine to print out a packet for debugging purposes. -+*/ -+#if SMC_DEBUG > 2 -+static void print_packet(byte * buf, int length) -+{ -+ int i; -+ int remainder; -+ int lines; -+ -+ printk("Packet of length %d \n", length); -+ lines = length / 16; -+ remainder = length % 16; -+ -+ for (i = 0; i < lines ; i ++) { -+ int cur; -+ -+ for (cur = 0; cur < 8; cur ++) { -+ byte a, b; -+ -+ a = *(buf ++); -+ b = *(buf ++); -+ printk("%02x%02x ", a, b); -+ } -+ printk("\n"); -+ } -+ for (i = 0; i < remainder/2 ; i++) { -+ byte a, b; -+ -+ a = *(buf ++); -+ b = *(buf ++); -+ printk("%02x%02x ", a, b); -+ } -+ if (remainder & 1) { -+ byte a; -+ -+ a = *buf++; -+ printk("%02x", a); -+ } -+ printk("\n"); -+} -+#else -+#define print_packet(buf,len) do { } while (0) -+#endif -+ -+/* -+ . Function: smc_reset(struct net_device *dev) - . Purpose: - . This sets the SMC91xx chip to its normal state, hopefully from whatever - . mess that any other DOS driver has put it in. -@@ -309,36 +579,37 @@ - . 5. clear all interrupts - . - */ --static void smc_reset( int ioaddr ) -+static void smc_reset(struct net_device *dev) - { -+ u_int ioaddr = dev->base_addr; -+ - /* This resets the registers mostly to defaults, but doesn't - affect EEPROM. That seems unnecessary */ -- SMC_SELECT_BANK( 0 ); -- outw( RCR_SOFTRESET, ioaddr + RCR ); -+ SMC_SELECT_BANK(0); -+ smc_outw(RCR_SOFTRESET, ioaddr, RCR); - - /* this should pause enough for the chip to be happy */ -- SMC_DELAY( ); -+ SMC_DELAY(); - - /* Set the transmit and receive configuration registers to - default values */ -- outw( RCR_CLEAR, ioaddr + RCR ); -- outw( TCR_CLEAR, ioaddr + TCR ); -+ smc_outw(RCR_CLEAR, ioaddr, RCR); -+ smc_outw(TCR_CLEAR, ioaddr, TCR); - - /* set the control register to automatically - release successfully transmitted packets, to make the best - use out of our limited memory */ -- SMC_SELECT_BANK( 1 ); -- outw( inw( ioaddr + CONTROL ) | CTL_AUTO_RELEASE , ioaddr + CONTROL ); -+ SMC_SELECT_BANK(1); -+ smc_outw(smc_inw(ioaddr, CONTROL) | CTL_AUTO_RELEASE, ioaddr, CONTROL); - - /* Reset the MMU */ -- SMC_SELECT_BANK( 2 ); -- outw( MC_RESET, ioaddr + MMU_CMD ); -+ SMC_SELECT_BANK(2); -+ smc_outw(MC_RESET, ioaddr, MMU_CMD); - - /* Note: It doesn't seem that waiting for the MMU busy is needed here, - but this is a place where future chipsets _COULD_ break. Be wary - of issuing another MMU command right after this */ -- -- outb( 0, ioaddr + INT_MASK ); -+ SMC_SET_INT(0); - } - - /* -@@ -349,20 +620,21 @@ - . 2. Enable the receiver - . 3. Enable interrupts - */ --static void smc_enable( int ioaddr ) -+static void smc_enable(struct net_device *dev) - { -- SMC_SELECT_BANK( 0 ); -+ u_int ioaddr = dev->base_addr; -+ SMC_SELECT_BANK(0); - /* see the header file for options in TCR/RCR NORMAL*/ -- outw( TCR_NORMAL, ioaddr + TCR ); -- outw( RCR_NORMAL, ioaddr + RCR ); -+ smc_outw(TCR_NORMAL, ioaddr, TCR); -+ smc_outw(RCR_NORMAL, ioaddr, RCR); - - /* now, enable interrupts */ -- SMC_SELECT_BANK( 2 ); -- outb( SMC_INTERRUPT_MASK, ioaddr + INT_MASK ); -+ SMC_SELECT_BANK(2); -+ SMC_SET_INT(SMC_INTERRUPT_MASK); - } - - /* -- . Function: smc_shutdown -+ . Function: smc_shutdown(struct net_device *dev) - . Purpose: closes down the SMC91xxx chip. - . Method: - . 1. zero the interrupt mask -@@ -375,26 +647,28 @@ - . the manual says that it will wake up in response to any I/O requests - . in the register space. Empirical results do not show this working. - */ --static void smc_shutdown( int ioaddr ) -+static void smc_shutdown(struct net_device *dev) - { -+ u_int ioaddr = dev->base_addr; -+ - /* no more interrupts for me */ -- SMC_SELECT_BANK( 2 ); -- outb( 0, ioaddr + INT_MASK ); -+ SMC_SELECT_BANK(2); -+ SMC_SET_INT(0); - - /* and tell the card to stay away from that nasty outside world */ -- SMC_SELECT_BANK( 0 ); -- outb( RCR_CLEAR, ioaddr + RCR ); -- outb( TCR_CLEAR, ioaddr + TCR ); -+ SMC_SELECT_BANK(0); -+ smc_outb(RCR_CLEAR, ioaddr, RCR); -+ smc_outb(TCR_CLEAR, ioaddr, TCR); - #if 0 - /* finally, shut the chip down */ -- SMC_SELECT_BANK( 1 ); -- outw( inw( ioaddr + CONTROL ), CTL_POWERDOWN, ioaddr + CONTROL ); -+ SMC_SELECT_BANK(1); -+ smc_outw(smc_inw(ioaddr, CONTROL), CTL_POWERDOWN, ioaddr, CONTROL); - #endif - } - - - /* -- . Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds ) -+ . Function: smc_setmulticast(int ioaddr, int count, dev_mc_list * adds) - . Purpose: - . This sets the internal hardware table to filter out unwanted multicast - . packets before they take up memory. -@@ -411,26 +685,28 @@ - */ - - --static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs ) { -+static void smc_setmulticast(struct net_device *dev, int count, struct dev_mc_list * addrs) -+{ -+ u_int ioaddr = dev->base_addr; - int i; -- unsigned char multicast_table[ 8 ]; -+ unsigned char multicast_table[8]; - struct dev_mc_list * cur_addr; - /* table for flipping the order of 3 bits */ - unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; - - /* start with a table of all zeros: reject all */ -- memset( multicast_table, 0, sizeof( multicast_table ) ); -+ memset(multicast_table, 0, sizeof(multicast_table)); - - cur_addr = addrs; -- for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next ) { -+ for (i = 0; i < count ; i ++, cur_addr = cur_addr->next) { - int position; - - /* do we have a pointer here? */ -- if ( !cur_addr ) -+ if (!cur_addr) - break; - /* make sure this is a multicast address - shouldn't this - be a given if we have it here ? */ -- if ( !( *cur_addr->dmi_addr & 1 ) ) -+ if (!(*cur_addr->dmi_addr & 1)) - continue; - - /* only use the low order bits */ -@@ -442,15 +718,15 @@ - - } - /* now, the table can be loaded into the chipset */ -- SMC_SELECT_BANK( 3 ); -+ SMC_SELECT_BANK(3); - -- for ( i = 0; i < 8 ; i++ ) { -- outb( multicast_table[i], ioaddr + MULTICAST1 + i ); -+ for (i = 0; i < 8 ; i++) { -+ smc_outb(multicast_table[i], ioaddr, MULTICAST1 + i); - } - } - - /* -- . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * ) -+ . Function: smc_wait_to_send_packet(struct sk_buff * skb, struct net_device *) - . Purpose: - . Attempt to allocate memory for a packet, if chip-memory is not - . available, then tell the card to generate an interrupt when it -@@ -465,10 +741,10 @@ - . o (NO): Enable interrupts and let the interrupt handler deal with it. - . o (YES):Send it now. - */ --static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * dev ) -+static int smc_wait_to_send_packet(struct sk_buff * skb, struct net_device * dev) - { - struct smc_local *lp = (struct smc_local *)dev->priv; -- unsigned short ioaddr = dev->base_addr; -+ u_int ioaddr = dev->base_addr; - word length; - unsigned short numPages; - word time_out; -@@ -477,15 +753,16 @@ - /* Well, I want to send the packet.. but I don't know - if I can send it right now... */ - -- if ( lp->saved_skb) { -+ if (lp->saved_skb) { - /* THIS SHOULD NEVER HAPPEN. */ - lp->stats.tx_aborted_errors++; -- printk(CARDNAME": Bad Craziness - sent packet while busy.\n" ); -+ printk("%s: Bad Craziness - sent packet while busy.\n", -+ dev->name); - return 1; - } - - length = skb->len; -- -+ - if(length < ETH_ZLEN) - { - skb = skb_padto(skb, ETH_ZLEN); -@@ -497,18 +774,18 @@ - length = ETH_ZLEN; - } - lp->saved_skb = skb; -- -+ - /* - ** The MMU wants the number of pages to be the number of 256 bytes -- ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) ) -+ ** 'pages', minus 1 (since a packet can't ever have 0 pages :)) - ** - ** Pkt size for allocating is data length +6 (for additional status words, - ** length and ctl!) If odd size last byte is included in this header. - */ -- numPages = ((length & 0xfffe) + 6) / 256; -+ numPages = ((length & 0xfffe) + 6) / 256; - -- if (numPages > 7 ) { -- printk(CARDNAME": Far too big packet error. \n"); -+ if (numPages > 7) { -+ printk("%s: Far too big packet error.\n", dev->name); - /* freeing the packet is a good thing here... but should - . any packets of this size get down here? */ - dev_kfree_skb (skb); -@@ -517,12 +794,13 @@ - netif_wake_queue(dev); - return 0; - } -+ - /* either way, a packet is waiting now */ - lp->packets_waiting++; - - /* now, try to allocate the memory */ -- SMC_SELECT_BANK( 2 ); -- outw( MC_ALLOC | numPages, ioaddr + MMU_CMD ); -+ SMC_SELECT_BANK(2); -+ smc_outw(MC_ALLOC | numPages, ioaddr, MMU_CMD); - /* - . Performance Hack - . -@@ -539,21 +817,21 @@ - do { - word status; - -- status = inb( ioaddr + INTERRUPT ); -- if ( status & IM_ALLOC_INT ) { -+ status = smc_inb(ioaddr, INTERRUPT); -+ if (status & IM_ALLOC_INT) { - /* acknowledge the interrupt */ -- outb( IM_ALLOC_INT, ioaddr + INTERRUPT ); -- break; -+ smc_outb(IM_ALLOC_INT, ioaddr, INTERRUPT); -+ break; - } -- } while ( -- time_out ); -+ } while (-- time_out); - -- if ( !time_out ) { -+ if (!time_out) { - /* oh well, wait until the chip finds memory later */ -- SMC_ENABLE_INT( IM_ALLOC_INT ); -- PRINTK2((CARDNAME": memory allocation deferred. \n")); -+ SMC_ENABLE_INT(IM_ALLOC_INT); -+ PRINTK2(("%s: memory allocation deferred.\n", dev->name)); - /* it's deferred, but I'll handle it later */ -- return 0; -- } -+ return 0; -+ } - /* or YES! I can send the packet now.. */ - smc_hardware_send_packet(dev); - netif_wake_queue(dev); -@@ -561,46 +839,46 @@ - } - - /* -- . Function: smc_hardware_send_packet(struct net_device * ) -+ . Function: smc_hardware_send_packet(struct net_device *) - . Purpose: - . This sends the actual packet to the SMC9xxx chip. - . - . Algorithm: - . First, see if a saved_skb is available. -- . ( this should NOT be called if there is no 'saved_skb' -+ . (this should NOT be called if there is no 'saved_skb' - . Now, find the packet number that the chip allocated - . Point the data pointers at it in memory - . Set the length word in the chip's memory - . Dump the packet to chip memory -- . Check if a last byte is needed ( odd length packet ) -+ . Check if a last byte is needed (odd length packet) - . if so, set the control flag right - . Tell the card to send it - . Enable the transmit interrupt, so I know if it failed - . Free the kernel data if I actually sent it. - */ --static void smc_hardware_send_packet( struct net_device * dev ) -+static void smc_hardware_send_packet(struct net_device *dev) - { - struct smc_local *lp = (struct smc_local *)dev->priv; -- byte packet_no; -- struct sk_buff * skb = lp->saved_skb; -- word length; -- unsigned short ioaddr; -- byte * buf; -- -- ioaddr = dev->base_addr; -+ struct sk_buff *skb = lp->saved_skb; -+ word length, lastword; -+ u_int ioaddr = dev->base_addr; -+ byte packet_no; -+ byte *buf; - -- if ( !skb ) { -- PRINTK((CARDNAME": In XMIT with no packet to send \n")); -+ if (!skb) { -+ PRINTK(("%s: In XMIT with no packet to send\n", dev->name)); - return; - } -+ - length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - buf = skb->data; - - /* If I get here, I _know_ there is a packet slot waiting for me */ -- packet_no = inb( ioaddr + PNR_ARR + 1 ); -- if ( packet_no & 0x80 ) { -+ packet_no = smc_inb(ioaddr, PNR_ARR + 1); -+ if (packet_no & 0x80) { - /* or isn't there? BAD CHIP! */ -- printk(KERN_DEBUG CARDNAME": Memory allocation failed. \n"); -+ printk(KERN_DEBUG "%s: Memory allocation failed.\n", -+ dev->name); - dev_kfree_skb_any(skb); - lp->saved_skb = NULL; - netif_wake_queue(dev); -@@ -608,26 +886,19 @@ - } - - /* we have a packet address, so tell the card to use it */ -- outb( packet_no, ioaddr + PNR_ARR ); -+ smc_outb(packet_no, ioaddr, PNR_ARR); - - /* point to the beginning of the packet */ -- outw( PTR_AUTOINC , ioaddr + POINTER ); -+ smc_outw(PTR_AUTOINC, ioaddr, POINTER); - -- PRINTK3((CARDNAME": Trying to xmit packet of length %x\n", length )); --#if SMC_DEBUG > 2 -- print_packet( buf, length ); --#endif -+ PRINTK3(("%s: Trying to xmit packet of length %x\n", -+ dev->name, length)); - -- /* send the packet length ( +6 for status, length and ctl byte ) -- and the status word ( set to zeros ) */ --#ifdef USE_32_BIT -- outl( (length +6 ) << 16 , ioaddr + DATA_1 ); --#else -- outw( 0, ioaddr + DATA_1 ); -- /* send the packet length ( +6 for status words, length, and ctl*/ -- outb( (length+6) & 0xFF,ioaddr + DATA_1 ); -- outb( (length+6) >> 8 , ioaddr + DATA_1 ); --#endif -+ print_packet(buf, length); -+ -+ /* send the packet length (+6 for status, length and ctl byte) -+ and the status word (set to zeros) */ -+ smc_outl((length + 6) << 16, ioaddr, DATA_1); - - /* send the actual data - . I _think_ it's faster to send the longs first, and then -@@ -636,32 +907,22 @@ - . a good idea to check which is optimal? But that could take - . almost as much time as is saved? - */ --#ifdef USE_32_BIT -- if ( length & 0x2 ) { -- outsl(ioaddr + DATA_1, buf, length >> 2 ); -- outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1); -- } -- else -- outsl(ioaddr + DATA_1, buf, length >> 2 ); --#else -- outsw(ioaddr + DATA_1 , buf, (length ) >> 1); --#endif -- /* Send the last byte, if there is one. */ -+ smc_outs(ioaddr, DATA_1, buf, length); - -- if ( (length & 1) == 0 ) { -- outw( 0, ioaddr + DATA_1 ); -- } else { -- outb( buf[length -1 ], ioaddr + DATA_1 ); -- outb( 0x20, ioaddr + DATA_1); -- } -+ /* Send the last byte, if there is one. */ -+ if ((length & 1) == 0) -+ lastword = 0; -+ else -+ lastword = 0x2000 | buf[length - 1]; -+ smc_outw(lastword, ioaddr, DATA_1); - - /* enable the interrupts */ -- SMC_ENABLE_INT( (IM_TX_INT | IM_TX_EMPTY_INT) ); -+ SMC_ENABLE_INT(IM_TX_INT | IM_TX_EMPTY_INT); - - /* and let the chipset deal with it */ -- outw( MC_ENQUEUE , ioaddr + MMU_CMD ); -+ smc_outw(MC_ENQUEUE, ioaddr, MMU_CMD); - -- PRINTK2((CARDNAME": Sent packet of length %d \n",length)); -+ PRINTK2(("%s: Sent packet of length %d\n", dev->name, length)); - - lp->saved_skb = NULL; - dev_kfree_skb_any (skb); -@@ -676,7 +937,7 @@ - - /*------------------------------------------------------------------------- - | -- | smc_init( struct net_device * dev ) -+ | smc_init(struct net_device * dev) - | Input parameters: - | dev->base_addr == 0, try to find all possible locations - | dev->base_addr == 1, return failure code -@@ -691,6 +952,65 @@ - */ - int __init smc_init(struct net_device *dev) - { -+ int ret = -ENODEV; -+#if defined(CONFIG_ASSABET_NEPONSET) -+ if (machine_is_assabet() && machine_has_neponset()) { -+ unsigned int *addr; -+ unsigned char ecor; -+ unsigned long flags; -+ -+ NCR_0 |= NCR_ENET_OSC_EN; -+ dev->irq = IRQ_NEPONSET_SMC9196; -+ -+ /* -+ * Map the attribute space. This is overkill, but clean. -+ */ -+ addr = ioremap(0x18000000 + (1 << 25), 64 * 1024 * 4); -+ if (!addr) -+ return -ENOMEM; -+ -+ /* -+ * Reset the device. We must disable IRQs around this. -+ */ -+ local_irq_save(flags); -+ ecor = readl(addr + ECOR) & ~ECOR_RESET; -+ writel(ecor | ECOR_RESET, addr + ECOR); -+ udelay(100); -+ -+ /* -+ * The device will ignore all writes to the enable bit while -+ * reset is asserted, even if the reset bit is cleared in the -+ * same write. Must clear reset first, then enable the device. -+ */ -+ writel(ecor, addr + ECOR); -+ writel(ecor | ECOR_ENABLE, addr + ECOR); -+ -+ /* -+ * Force byte mode. -+ */ -+ writel(readl(addr + ECSR) | ECSR_IOIS8, addr + ECSR); -+ local_irq_restore(flags); -+ -+ iounmap(addr); -+ -+ /* -+ * Wait for the chip to wake up. -+ */ -+ mdelay(1); -+ -+ /* -+ * Map the real registers. -+ */ -+ addr = ioremap(0x18000000, 8 * 1024); -+ if (!addr) -+ return -ENOMEM; -+ -+ ret = smc_probe(dev, (int)addr); -+ if (ret) -+ iounmap(addr); -+ } -+ -+#elif defined(CONFIG_ISA) - int i; - int base_addr = dev->base_addr; - -@@ -708,7 +1028,8 @@ - return 0; - - /* couldn't find anything */ -- return -ENODEV; -+#endif -+ return ret; - } - - /*---------------------------------------------------------------------- -@@ -718,10 +1039,11 @@ - . interrupt, so an auto-detect routine can detect it, and find the IRQ, - ------------------------------------------------------------------------ - */ --int __init smc_findirq( int ioaddr ) -+int __init smc_findirq(struct net_device *dev) - { - int timeout = 20; - unsigned long cookie; -+ u_int ioaddr = dev->base_addr; - - - /* I have to do a STI() here, because this is called from -@@ -737,26 +1059,25 @@ - * when done. - */ - -- -+ /* enable ALLOCation interrupts ONLY. */ - SMC_SELECT_BANK(2); -- /* enable ALLOCation interrupts ONLY */ -- outb( IM_ALLOC_INT, ioaddr + INT_MASK ); -+ SMC_SET_INT(IM_ALLOC_INT); - - /* - . Allocate 512 bytes of memory. Note that the chip was just - . reset so all the memory is available - */ -- outw( MC_ALLOC | 1, ioaddr + MMU_CMD ); -+ smc_outw(MC_ALLOC | 1, ioaddr, MMU_CMD); - - /* - . Wait until positive that the interrupt has been generated - */ -- while ( timeout ) { -+ while (timeout) { - byte int_status; - -- int_status = inb( ioaddr + INTERRUPT ); -+ int_status = smc_inb(ioaddr, INTERRUPT); - -- if ( int_status & IM_ALLOC_INT ) -+ if (int_status & IM_ALLOC_INT) - break; /* got the interrupt */ - timeout--; - } -@@ -775,7 +1096,7 @@ - SMC_DELAY(); - - /* and disable all interrupts again */ -- outb( 0, ioaddr + INT_MASK ); -+ SMC_SET_INT(0); - - /* clear hardware interrupts again, because that's how it - was when I was called... */ -@@ -785,8 +1106,87 @@ - return probe_irq_off(cookie); - } - -+static int __init smc_probe_chip(struct net_device *dev, int ioaddr) -+{ -+ unsigned int temp; -+ -+ /* First, see if the high byte is 0x33 */ -+ temp = smc_inw(ioaddr, BANK_SELECT); -+ if ((temp & 0xFF00) != 0x3300) -+ return -ENODEV; -+ -+ /* The above MIGHT indicate a device, but I need to write to further -+ test this. */ -+ smc_outw(0, ioaddr, BANK_SELECT); -+ temp = smc_inw(ioaddr, BANK_SELECT); -+ if ((temp & 0xFF00) != 0x3300) -+ return -ENODEV; -+ -+#ifndef CONFIG_ASSABET_NEPONSET -+ /* well, we've already written once, so hopefully another time won't -+ hurt. This time, I need to switch the bank register to bank 1, -+ so I can access the base address register */ -+ SMC_SELECT_BANK(1); -+ temp = smc_inw(ioaddr, BASE); -+ if (ioaddr != (temp >> 3 & 0x3E0)) { -+ printk("%s: IOADDR %x doesn't match configuration (%x)." -+ "Probably not a SMC chip\n", dev->name, -+ ioaddr, (base_address_register >> 3) & 0x3E0); -+ /* well, the base address register didn't match. Must not have -+ been a SMC chip after all. */ -+ return -ENODEV; -+ } -+#endif -+ -+ return 0; -+} -+ -+/* -+ . If dev->irq is 0, then the device has to be banged on to see -+ . what the IRQ is. -+ . -+ . This banging doesn't always detect the IRQ, for unknown reasons. -+ . a workaround is to reset the chip and try again. -+ . -+ . Interestingly, the DOS packet driver *SETS* the IRQ on the card to -+ . be what is requested on the command line. I don't do that, mostly -+ . because the card that I have uses a non-standard method of accessing -+ . the IRQs, and because this _should_ work in most configurations. -+ . -+ . Specifying an IRQ is done with the assumption that the user knows -+ . what (s)he is doing. No checking is done!!!! -+ . -+*/ -+static int __init smc_probe_irq(struct net_device *dev) -+{ -+ if (dev->irq < 2) { -+ int trials; -+ -+ trials = 3; -+ while (trials--) { -+ dev->irq = smc_findirq(dev); -+ if (dev->irq) -+ break; -+ /* kick the card and try again */ -+ smc_reset(dev); -+ } -+ } -+ if (dev->irq == 0) { -+ printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n", -+ dev->name); -+ return -ENODEV; -+ } -+ -+ /* -+ * Some machines (eg, PCs) need to cannonicalize their IRQs. -+ */ -+ dev->irq = irq_cannonicalize(dev->irq); -+ -+ return 0; -+} -+ - /*---------------------------------------------------------------------- -- . Function: smc_probe( int ioaddr ) -+ . Function: smc_probe(struct net_device *dev, int ioaddr) - . - . Purpose: - . Tests to see if a given ioaddr points to an SMC9xxx chip. -@@ -816,16 +1216,14 @@ - */ - static int __init smc_probe(struct net_device *dev, int ioaddr) - { -+ struct smc_local *smc; - int i, memory, retval; - static unsigned version_printed; -- unsigned int bank; - - const char *version_string; -- const char *if_string; - - /* registers */ - word revision_register; -- word base_address_register; - word configuration_register; - word memory_info_register; - word memory_cfg_register; -@@ -834,44 +1232,24 @@ - if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name)) - return -EBUSY; - -- /* First, see if the high byte is 0x33 */ -- bank = inw( ioaddr + BANK_SELECT ); -- if ( (bank & 0xFF00) != 0x3300 ) { -- retval = -ENODEV; -- goto err_out; -- } -- /* The above MIGHT indicate a device, but I need to write to further -- test this. */ -- outw( 0x0, ioaddr + BANK_SELECT ); -- bank = inw( ioaddr + BANK_SELECT ); -- if ( (bank & 0xFF00 ) != 0x3300 ) { -- retval = -ENODEV; -- goto err_out; -- } -- /* well, we've already written once, so hopefully another time won't -- hurt. This time, I need to switch the bank register to bank 1, -- so I can access the base address register */ -- SMC_SELECT_BANK(1); -- base_address_register = inw( ioaddr + BASE ); -- if ( ioaddr != ( base_address_register >> 3 & 0x3E0 ) ) { -- printk(CARDNAME ": IOADDR %x doesn't match configuration (%x)." -- "Probably not a SMC chip\n", -- ioaddr, base_address_register >> 3 & 0x3E0 ); -- /* well, the base address register didn't match. Must not have -- been a SMC chip after all. */ -- retval = -ENODEV; -+ /* -+ * Do the basic probes. -+ */ -+ retval = smc_probe_chip(dev, ioaddr); -+ if (retval) - goto err_out; -- } - - /* check if the revision register is something that I recognize. - These might need to be added to later, as future revisions - could be added. */ - SMC_SELECT_BANK(3); -- revision_register = inw( ioaddr + REVISION ); -- if ( !chip_ids[ ( revision_register >> 4 ) & 0xF ] ) { -+ revision_register = smc_inw(ioaddr, REVISION); -+ version_string = chip_ids[(revision_register >> 4) & 15]; -+ if (!version_string) { - /* I don't recognize this chip, so... */ -- printk(CARDNAME ": IO %x: Unrecognized revision register:" -- " %x, Contact author. \n", ioaddr, revision_register ); -+ printk("%s: IO %x: unrecognized revision register: %x, " -+ "contact author.\n", dev->name, ioaddr, -+ revision_register); - - retval = -ENODEV; - goto err_out; -@@ -882,138 +1260,122 @@ - against the hardware address, or do some other tests. */ - - if (version_printed++ == 0) -- printk("%s", version); -+ printk(KERN_INFO "%s", version); - - /* fill in some of the fields */ - dev->base_addr = ioaddr; - - /* -- . Get the MAC address ( bank 1, regs 4 - 9 ) -+ . Get the MAC address (bank 1, regs 4 - 9) - */ -- SMC_SELECT_BANK( 1 ); -- for ( i = 0; i < 6; i += 2 ) { -+ SMC_SELECT_BANK(1); -+ for (i = 0; i < 6; i += 2) { - word address; - -- address = inw( ioaddr + ADDR0 + i ); -- dev->dev_addr[ i + 1] = address >> 8; -- dev->dev_addr[ i ] = address & 0xFF; -+ address = smc_inw(ioaddr, ADDR0 + i); -+ dev->dev_addr[i + 1] = address >> 8; -+ dev->dev_addr[i] = address & 0xFF; - } - -+ if (!is_valid_ether_addr(dev->dev_addr)) -+ printk("%s: Invalid ethernet MAC address. Please set using " -+ "ifconfig\n", dev->name); -+ - /* get the memory information */ - -- SMC_SELECT_BANK( 0 ); -- memory_info_register = inw( ioaddr + MIR ); -- memory_cfg_register = inw( ioaddr + MCR ); -- memory = ( memory_cfg_register >> 9 ) & 0x7; /* multiplier */ -- memory *= 256 * ( memory_info_register & 0xFF ); -+ SMC_SELECT_BANK(0); -+ memory_info_register = smc_inw(ioaddr, MIR); -+ memory_cfg_register = smc_inw(ioaddr, MCR); -+ memory = (memory_cfg_register >> 9) & 0x7; /* multiplier */ -+ memory *= 256 * (memory_info_register & 0xFF); -+ -+ /* now, reset the chip, and put it into a known state */ -+ smc_reset(dev); - - /* -- Now, I want to find out more about the chip. This is sort of -- redundant, but it's cleaner to have it in both, rather than having -- one VERY long probe procedure. -- */ -- SMC_SELECT_BANK(3); -- revision_register = inw( ioaddr + REVISION ); -- version_string = chip_ids[ ( revision_register >> 4 ) & 0xF ]; -- if ( !version_string ) { -- /* I shouldn't get here because this call was done before.... */ -- retval = -ENODEV; -+ * Ok, now that we have everything in a -+ * sane state, probe for the interrupt. -+ */ -+ retval = smc_probe_irq(dev); -+ if (retval) - goto err_out; -- } - -- /* is it using AUI or 10BaseT ? */ -- if ( dev->if_port == 0 ) { -- SMC_SELECT_BANK(1); -- configuration_register = inw( ioaddr + CONFIG ); -- if ( configuration_register & CFG_AUI_SELECT ) -- dev->if_port = 2; -- else -- dev->if_port = 1; -+ /* Initialize the private structure. */ -+ if (dev->priv == NULL) { -+ dev->priv = kmalloc(sizeof(struct smc_local), GFP_KERNEL); -+ if (dev->priv == NULL) { -+ retval = -ENOMEM; -+ goto err_out; -+ } - } -- if_string = interfaces[ dev->if_port - 1 ]; - -- /* now, reset the chip, and put it into a known state */ -- smc_reset( ioaddr ); -+ smc = dev->priv; -+ -+ /* set the private data to zero by default */ -+ memset(smc, 0, sizeof(struct smc_local)); - - /* -- . If dev->irq is 0, then the device has to be banged on to see -- . what the IRQ is. -- . -- . This banging doesn't always detect the IRQ, for unknown reasons. -- . a workaround is to reset the chip and try again. -- . -- . Interestingly, the DOS packet driver *SETS* the IRQ on the card to -- . be what is requested on the command line. I don't do that, mostly -- . because the card that I have uses a non-standard method of accessing -- . the IRQs, and because this _should_ work in most configurations. -- . -- . Specifying an IRQ is done with the assumption that the user knows -- . what (s)he is doing. No checking is done!!!! -- . -- */ -- if ( dev->irq < 2 ) { -- int trials; -+ * Get the interface characteristics. -+ * is it using AUI or 10BaseT ? -+ */ -+ switch (dev->if_port) { -+ case IF_PORT_10BASET: -+ smc->port = PORT_TP; -+ break; -+ -+ case IF_PORT_AUI: -+ smc->port = PORT_AUI; -+ break; - -- trials = 3; -- while ( trials-- ) { -- dev->irq = smc_findirq( ioaddr ); -- if ( dev->irq ) -- break; -- /* kick the card and try again */ -- smc_reset( ioaddr ); -+ default: -+ SMC_SELECT_BANK(1); -+ configuration_register = smc_inw(ioaddr, CONFIG); -+ if (configuration_register & CFG_AUI_SELECT) { -+ dev->if_port = IF_PORT_AUI; -+ smc->port = PORT_AUI; -+ } else { -+ dev->if_port = IF_PORT_10BASET; -+ smc->port = PORT_TP; - } -- } -- if (dev->irq == 0 ) { -- printk(CARDNAME": Couldn't autodetect your IRQ. Use irq=xx.\n"); -- retval = -ENODEV; -- goto err_out; -+ break; - } - -- /* now, print out the card info, in a short format.. */ -+ /* all interfaces are half-duplex by default */ -+ smc->duplex = DUPLEX_HALF; - -- printk("%s: %s(r:%d) at %#3x IRQ:%d INTF:%s MEM:%db ", dev->name, -- version_string, revision_register & 0xF, ioaddr, dev->irq, -- if_string, memory ); -+ /* now, print out the card info, in a short format.. */ -+ printk("%s: %s (rev %d) at %#3x IRQ:%d INTF:%s MEM:%db ", dev->name, -+ version_string, revision_register & 15, ioaddr, dev->irq, -+ interfaces[smc->port], memory); - /* - . Print the Ethernet address - */ - printk("ADDR: "); - for (i = 0; i < 5; i++) -- printk("%2.2x:", dev->dev_addr[i] ); -- printk("%2.2x \n", dev->dev_addr[5] ); -- -- -- /* Initialize the private structure. */ -- if (dev->priv == NULL) { -- dev->priv = kmalloc(sizeof(struct smc_local), GFP_KERNEL); -- if (dev->priv == NULL) { -- retval = -ENOMEM; -- goto err_out; -- } -- } -- /* set the private data to zero by default */ -- memset(dev->priv, 0, sizeof(struct smc_local)); -+ printk("%2.2x:", dev->dev_addr[i]); -+ printk("%2.2x\n", dev->dev_addr[5]); - - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - - /* Grab the IRQ */ -- retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev); -- if (retval) { -+ retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev); -+ if (retval) { - printk("%s: unable to get IRQ %d (irqval=%d).\n", dev->name, - dev->irq, retval); - kfree(dev->priv); - dev->priv = NULL; -- goto err_out; -- } -+ goto err_out; -+ } - -- dev->open = smc_open; -- dev->stop = smc_close; -- dev->hard_start_xmit = smc_wait_to_send_packet; -- dev->tx_timeout = smc_timeout; -- dev->watchdog_timeo = HZ/20; -- dev->get_stats = smc_query_statistics; -- dev->set_multicast_list = smc_set_multicast_list; -+ dev->open = smc_open; -+ dev->stop = smc_close; -+ dev->hard_start_xmit = smc_wait_to_send_packet; -+ dev->tx_timeout = smc_timeout; -+ dev->watchdog_timeo = HZ/20; -+ dev->get_stats = smc_query_statistics; -+ dev->set_multicast_list = smc_set_multicast_list; -+ dev->do_ioctl = smc_ioctl; - - return 0; - -@@ -1022,42 +1384,43 @@ - return retval; - } - --#if SMC_DEBUG > 2 --static void print_packet( byte * buf, int length ) -+/* -+ * This is responsible for setting the chip appropriately -+ * for the interface type. This should only be called while -+ * the interface is up and running. -+ */ -+static void smc_set_port(struct net_device *dev) - { --#if 0 -- int i; -- int remainder; -- int lines; -- -- printk("Packet of length %d \n", length ); -- lines = length / 16; -- remainder = length % 16; -+ struct smc_local *smc = dev->priv; -+ u_int ioaddr = dev->base_addr; -+ u_int val; - -- for ( i = 0; i < lines ; i ++ ) { -- int cur; -- -- for ( cur = 0; cur < 8; cur ++ ) { -- byte a, b; -- -- a = *(buf ++ ); -- b = *(buf ++ ); -- printk("%02x%02x ", a, b ); -- } -- printk("\n"); -+ SMC_SELECT_BANK(1); -+ val = smc_inw(ioaddr, CONFIG); -+ switch (smc->port) { -+ case PORT_TP: -+ val &= ~CFG_AUI_SELECT; -+ break; -+ -+ case PORT_AUI: -+ val |= CFG_AUI_SELECT; -+ break; - } -- for ( i = 0; i < remainder/2 ; i++ ) { -- byte a, b; -+ smc_outw(val, ioaddr, CONFIG); - -- a = *(buf ++ ); -- b = *(buf ++ ); -- printk("%02x%02x ", a, b ); -+ SMC_SELECT_BANK(0); -+ val = smc_inw(ioaddr, TCR); -+ switch (smc->duplex) { -+ case DUPLEX_HALF: -+ val &= ~TCR_FDSE; -+ break; -+ -+ case DUPLEX_FULL: -+ val |= TCR_FDSE; -+ break; - } -- printk("\n"); --#endif -+ smc_outw(val, ioaddr, TCR); - } --#endif -- - - /* - * Open and Initialize the board -@@ -1067,48 +1430,141 @@ - */ - static int smc_open(struct net_device *dev) - { -- int ioaddr = dev->base_addr; -+ struct smc_local *smc = dev->priv; -+ u_int ioaddr = dev->base_addr; -+ int i; - -- int i; /* used to set hw ethernet address */ -+ /* -+ * Check that the address is valid. If its not, refuse -+ * to bring the device up. The user must specify an -+ * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx -+ */ -+ if (!is_valid_ether_addr(dev->dev_addr)) -+ return -EINVAL; - - /* clear out all the junk that was put here before... */ -- memset(dev->priv, 0, sizeof(struct smc_local)); -+ smc->saved_skb = NULL; -+ smc->packets_waiting = 0; - - /* reset the hardware */ -- -- smc_reset( ioaddr ); -- smc_enable( ioaddr ); -+ smc_reset(dev); -+ smc_enable(dev); - - /* Select which interface to use */ -- -- SMC_SELECT_BANK( 1 ); -- if ( dev->if_port == 1 ) { -- outw( inw( ioaddr + CONFIG ) & ~CFG_AUI_SELECT, -- ioaddr + CONFIG ); -- } -- else if ( dev->if_port == 2 ) { -- outw( inw( ioaddr + CONFIG ) | CFG_AUI_SELECT, -- ioaddr + CONFIG ); -- } -+ smc_set_port(dev); - - /* -- According to Becker, I have to set the hardware address -+ According to Becker, I have to set the hardware address - at this point, because the (l)user can set it with an - ioctl. Easily done... - */ -- SMC_SELECT_BANK( 1 ); -- for ( i = 0; i < 6; i += 2 ) { -+ SMC_SELECT_BANK(1); -+ for (i = 0; i < 6; i += 2) { - word address; - -- address = dev->dev_addr[ i + 1 ] << 8 ; -- address |= dev->dev_addr[ i ]; -- outw( address, ioaddr + ADDR0 + i ); -+ address = dev->dev_addr[i + 1] << 8 ; -+ address |= dev->dev_addr[i]; -+ smc_outw(address, ioaddr, ADDR0 + i); - } - - netif_start_queue(dev); - return 0; - } - -+/* -+ * This is our template. Fill the rest in at run-time -+ */ -+static const struct ethtool_cmd ecmd_template = { -+ supported: SUPPORTED_10baseT_Half | -+ SUPPORTED_10baseT_Full | -+ SUPPORTED_TP | -+ SUPPORTED_AUI, -+ speed: SPEED_10, -+ autoneg: AUTONEG_DISABLE, -+ maxtxpkt: 1, -+ maxrxpkt: 1, -+ transceiver: XCVR_INTERNAL, -+}; -+ -+static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -+{ -+ struct smc_local *smc = dev->priv; -+ u32 etcmd; -+ int ret = -EINVAL; -+ -+ if (cmd != SIOCETHTOOL) -+ return -EOPNOTSUPP; -+ -+ if (get_user(etcmd, (u32 *)rq->ifr_data)) -+ return -EFAULT; -+ -+ switch (etcmd) { -+ case ETHTOOL_GSET: { -+ struct ethtool_cmd ecmd = ecmd_template; -+ -+ ecmd.cmd = etcmd; -+ ecmd.port = smc->port; -+ ecmd.duplex = smc->duplex; -+ -+ ret = copy_to_user(rq->ifr_data, &ecmd, sizeof(ecmd)) -+ ? -EFAULT : 0; -+ break; -+ } -+ -+ case ETHTOOL_SSET: { -+ struct ethtool_cmd ecmd; -+ -+ ret = -EPERM; -+ if (!capable(CAP_NET_ADMIN)) -+ break; -+ -+ ret = -EFAULT; -+ if (copy_from_user(&ecmd, rq->ifr_data, sizeof(ecmd))) -+ break; -+ -+ /* -+ * Sanity-check the arguments. -+ */ -+ ret = -EINVAL; -+ if (ecmd.autoneg != AUTONEG_DISABLE) -+ break; -+ if (ecmd.speed != SPEED_10) -+ break; -+ if (ecmd.duplex != DUPLEX_HALF && ecmd.duplex != DUPLEX_FULL) -+ break; -+ if (ecmd.port != PORT_TP && ecmd.port != PORT_AUI) -+ break; -+ -+ smc->port = ecmd.port; -+ smc->duplex = ecmd.duplex; -+ -+ if (netif_running(dev)) -+ smc_set_port(dev); -+ -+ ret = 0; -+ break; -+ } -+ -+ case ETHTOOL_GDRVINFO: { -+ struct ethtool_drvinfo edrv; -+ -+ memset(&edrv, 0, sizeof(edrv)); -+ -+ edrv.cmd = etcmd; -+ strcpy(edrv.driver, DRV_NAME); -+ strcpy(edrv.version, DRV_VERSION); -+ sprintf(edrv.bus_info, "ISA:%8.8lx:%d", -+ dev->base_addr, dev->irq); -+ -+ ret = copy_to_user(rq->ifr_data, &edrv, sizeof(edrv)) -+ ? -EFAULT : 0; -+ break; -+ } -+ } -+ -+ return ret; -+} -+ - /*-------------------------------------------------------- - . Called by the kernel to send a packet out into the void - . of the net. This routine is largely based on -@@ -1120,12 +1576,10 @@ - { - /* If we get here, some higher level has decided we are broken. - There should really be a "kick me" function call instead. */ -- printk(KERN_WARNING CARDNAME": transmit timed out, %s?\n", -- tx_done(dev) ? "IRQ conflict" : -- "network cable problem"); -+ printk(KERN_WARNING "%s: transmit timed out\n", dev->name); - /* "kick" the adaptor */ -- smc_reset( dev->base_addr ); -- smc_enable( dev->base_addr ); -+ smc_reset(dev); -+ smc_enable(dev); - dev->trans_start = jiffies; - /* clear anything saved */ - ((struct smc_local *)dev->priv)->saved_skb = NULL; -@@ -1145,10 +1599,10 @@ - . - ---------------------------------------------------------------------*/ - --static void smc_interrupt(int irq, void * dev_id, struct pt_regs * regs) -+static void smc_interrupt(int irq, void * dev_id, struct pt_regs * regs) - { - struct net_device *dev = dev_id; -- int ioaddr = dev->base_addr; -+ u_int ioaddr = dev->base_addr; - struct smc_local *lp = (struct smc_local *)dev->priv; - - byte status; -@@ -1161,45 +1615,45 @@ - - - -- PRINTK3((CARDNAME": SMC interrupt started \n")); -+ PRINTK3(("%s: SMC interrupt started\n", dev->name)); - -- saved_bank = inw( ioaddr + BANK_SELECT ); -+ saved_bank = smc_inw(ioaddr, BANK_SELECT); - - SMC_SELECT_BANK(2); -- saved_pointer = inw( ioaddr + POINTER ); -+ saved_pointer = smc_inw(ioaddr, POINTER); - -- mask = inb( ioaddr + INT_MASK ); -+ mask = smc_inb(ioaddr, INT_MASK); - /* clear all interrupts */ -- outb( 0, ioaddr + INT_MASK ); -+ SMC_SET_INT(0); - - - /* set a timeout value, so I don't stay here forever */ - timeout = 4; - -- PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x \n", mask )); -+ PRINTK2((KERN_WARNING "%s: MASK IS %x\n", dev->name, mask)); - do { - /* read the status flag, and mask it */ -- status = inb( ioaddr + INTERRUPT ) & mask; -- if (!status ) -+ status = smc_inb(ioaddr, INTERRUPT) & mask; -+ if (!status) - break; - -- PRINTK3((KERN_WARNING CARDNAME -- ": Handling interrupt status %x \n", status )); -+ PRINTK3((KERN_WARNING "%s: handling interrupt status %x\n", -+ dev->name, status)); - - if (status & IM_RCV_INT) { - /* Got a packet(s). */ -- PRINTK2((KERN_WARNING CARDNAME -- ": Receive Interrupt\n")); -+ PRINTK2((KERN_WARNING "%s: receive interrupt\n", -+ dev->name)); - smc_rcv(dev); -- } else if (status & IM_TX_INT ) { -- PRINTK2((KERN_WARNING CARDNAME -- ": TX ERROR handled\n")); -+ } else if (status & IM_TX_INT) { -+ PRINTK2((KERN_WARNING "%s: TX ERROR handled\n", -+ dev->name)); - smc_tx(dev); -- outb(IM_TX_INT, ioaddr + INTERRUPT ); -- } else if (status & IM_TX_EMPTY_INT ) { -+ smc_outb(IM_TX_INT, ioaddr, INTERRUPT); -+ } else if (status & IM_TX_EMPTY_INT) { - /* update stats */ -- SMC_SELECT_BANK( 0 ); -- card_stats = inw( ioaddr + COUNTER ); -+ SMC_SELECT_BANK(0); -+ card_stats = smc_inw(ioaddr, COUNTER); - /* single collisions */ - lp->stats.collisions += card_stats & 0xF; - card_stats >>= 4; -@@ -1208,60 +1662,63 @@ - - /* these are for when linux supports these statistics */ - -- SMC_SELECT_BANK( 2 ); -- PRINTK2((KERN_WARNING CARDNAME -- ": TX_BUFFER_EMPTY handled\n")); -- outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT ); -+ SMC_SELECT_BANK(2); -+ PRINTK2((KERN_WARNING "%s: TX_BUFFER_EMPTY handled\n", -+ dev->name)); -+ smc_outb(IM_TX_EMPTY_INT, ioaddr, INTERRUPT); - mask &= ~IM_TX_EMPTY_INT; - lp->stats.tx_packets += lp->packets_waiting; - lp->packets_waiting = 0; - -- } else if (status & IM_ALLOC_INT ) { -- PRINTK2((KERN_DEBUG CARDNAME -- ": Allocation interrupt \n")); -+ } else if (status & IM_ALLOC_INT) { -+ PRINTK2((KERN_DEBUG "%s: Allocation interrupt\n", -+ dev->name)); - /* clear this interrupt so it doesn't happen again */ - mask &= ~IM_ALLOC_INT; - -- smc_hardware_send_packet( dev ); -+ smc_hardware_send_packet(dev); - - /* enable xmit interrupts based on this */ -- mask |= ( IM_TX_EMPTY_INT | IM_TX_INT ); -+ mask |= (IM_TX_EMPTY_INT | IM_TX_INT); - - /* and let the card send more packets to me */ - netif_wake_queue(dev); - -- PRINTK2((CARDNAME": Handoff done successfully.\n")); -- } else if (status & IM_RX_OVRN_INT ) { -+ PRINTK2(("%s: Handoff done successfully.\n", -+ dev->name)); -+ } else if (status & IM_RX_OVRN_INT) { - lp->stats.rx_errors++; - lp->stats.rx_fifo_errors++; -- outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT ); -- } else if (status & IM_EPH_INT ) { -- PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT \n")); -- } else if (status & IM_ERCV_INT ) { -- PRINTK((CARDNAME ": UNSUPPORTED: ERCV INTERRUPT \n")); -- outb( IM_ERCV_INT, ioaddr + INTERRUPT ); -+ smc_outb(IM_RX_OVRN_INT, ioaddr, INTERRUPT); -+ } else if (status & IM_EPH_INT) { -+ PRINTK(("%s: UNSUPPORTED: EPH INTERRUPT\n", -+ dev->name)); -+ } else if (status & IM_ERCV_INT) { -+ PRINTK(("%s: UNSUPPORTED: ERCV INTERRUPT\n", -+ dev->name)); -+ smc_outb(IM_ERCV_INT, ioaddr, INTERRUPT); - } -- } while ( timeout -- ); -+ } while (timeout --); - - - /* restore state register */ -- SMC_SELECT_BANK( 2 ); -- outb( mask, ioaddr + INT_MASK ); -+ SMC_SELECT_BANK(2); -+ SMC_SET_INT(mask); - -- PRINTK3(( KERN_WARNING CARDNAME ": MASK is now %x \n", mask )); -- outw( saved_pointer, ioaddr + POINTER ); -+ PRINTK3((KERN_WARNING "%s: MASK is now %x\n", dev->name, mask)); -+ smc_outw(saved_pointer, ioaddr, POINTER); - -- SMC_SELECT_BANK( saved_bank ); -+ SMC_SELECT_BANK(saved_bank); - -- PRINTK3((CARDNAME ": Interrupt done\n")); -+ PRINTK3(("%s: Interrupt done\n", dev->name)); - return; - } - - /*------------------------------------------------------------- - . -- . smc_rcv - receive a packet from the card -+ . smc_rcv - receive a packet from the card - . -- . There is ( at least ) a packet waiting to be read from -+ . There is (at least) a packet waiting to be read from - . chip-memory. - . - . o Read the status -@@ -1272,55 +1729,57 @@ - static void smc_rcv(struct net_device *dev) - { - struct smc_local *lp = (struct smc_local *)dev->priv; -- int ioaddr = dev->base_addr; -+ u_int ioaddr = dev->base_addr; - int packet_number; - word status; - word packet_length; - - /* assume bank 2 */ - -- packet_number = inw( ioaddr + FIFO_PORTS ); -+ packet_number = smc_inw(ioaddr, FIFO_PORTS); - -- if ( packet_number & FP_RXEMPTY ) { -+ if (packet_number & FP_RXEMPTY) { - /* we got called , but nothing was on the FIFO */ -- PRINTK((CARDNAME ": WARNING: smc_rcv with nothing on FIFO. \n")); -+ PRINTK(("%s: WARNING: smc_rcv with nothing on FIFO.\n", -+ dev->name)); - /* don't need to restore anything */ - return; - } - - /* start reading from the start of the packet */ -- outw( PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER ); -+ smc_outw(PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr, POINTER); - - /* First two words are status and packet_length */ -- status = inw( ioaddr + DATA_1 ); -- packet_length = inw( ioaddr + DATA_1 ); -+ status = smc_inw(ioaddr, DATA_1); -+ packet_length = smc_inw(ioaddr, DATA_1); - - packet_length &= 0x07ff; /* mask off top bits */ - -- PRINTK2(("RCV: STATUS %4x LENGTH %4x\n", status, packet_length )); -+ PRINTK2(("RCV: STATUS %4x LENGTH %4x\n", status, packet_length)); - /* - . the packet length contains 3 extra words : - . status, length, and an extra word with an odd byte . - */ - packet_length -= 6; - -- if ( !(status & RS_ERRORS ) ){ -+ if (!(status & RS_ERRORS)){ - /* do stuff to make a new packet */ - struct sk_buff * skb; - byte * data; - - /* read one extra byte */ -- if ( status & RS_ODDFRAME ) -+ if (status & RS_ODDFRAME) - packet_length++; - - /* set multicast stats */ -- if ( status & RS_MULTICAST ) -+ if (status & RS_MULTICAST) - lp->stats.multicast++; - -- skb = dev_alloc_skb( packet_length + 5); -+ skb = dev_alloc_skb(packet_length + 5); - -- if ( skb == NULL ) { -- printk(KERN_NOTICE CARDNAME ": Low memory, packet dropped.\n"); -+ if (skb == NULL) { -+ printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", -+ dev->name); - lp->stats.rx_dropped++; - goto done; - } -@@ -1330,36 +1789,15 @@ - ! in the worse case - */ - -- skb_reserve( skb, 2 ); /* 16 bit alignment */ -+ skb_reserve(skb, 2); /* 16 bit alignment */ - - skb->dev = dev; -- data = skb_put( skb, packet_length); -+ data = skb_put(skb, packet_length); - --#ifdef USE_32_BIT -- /* QUESTION: Like in the TX routine, do I want -- to send the DWORDs or the bytes first, or some -- mixture. A mixture might improve already slow PIO -- performance */ -- PRINTK3((" Reading %d dwords (and %d bytes) \n", -- packet_length >> 2, packet_length & 3 )); -- insl(ioaddr + DATA_1 , data, packet_length >> 2 ); -- /* read the left over bytes */ -- insb( ioaddr + DATA_1, data + (packet_length & 0xFFFFFC), -- packet_length & 0x3 ); --#else -- PRINTK3((" Reading %d words and %d byte(s) \n", -- (packet_length >> 1 ), packet_length & 1 )); -- insw(ioaddr + DATA_1 , data, packet_length >> 1); -- if ( packet_length & 1 ) { -- data += packet_length & ~1; -- *(data++) = inb( ioaddr + DATA_1 ); -- } --#endif --#if SMC_DEBUG > 2 -- print_packet( data, packet_length ); --#endif -+ smc_ins(ioaddr, DATA_1, data, packet_length); -+ print_packet(data, packet_length); - -- skb->protocol = eth_type_trans(skb, dev ); -+ skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->last_rx = jiffies; - lp->stats.rx_packets++; -@@ -1368,15 +1806,17 @@ - /* error ... */ - lp->stats.rx_errors++; - -- if ( status & RS_ALGNERR ) lp->stats.rx_frame_errors++; -- if ( status & (RS_TOOSHORT | RS_TOOLONG ) ) -+ if (status & RS_ALGNERR) -+ lp->stats.rx_frame_errors++; -+ if (status & (RS_TOOSHORT | RS_TOOLONG)) - lp->stats.rx_length_errors++; -- if ( status & RS_BADCRC) lp->stats.rx_crc_errors++; -+ if (status & RS_BADCRC) -+ lp->stats.rx_crc_errors++; - } - - done: - /* error or good, tell the card to get rid of this packet */ -- outw( MC_RELEASE, ioaddr + MMU_CMD ); -+ smc_outw(MC_RELEASE, ioaddr, MMU_CMD); - } - - -@@ -1389,62 +1829,64 @@ - . Algorithm: - . Save pointer and packet no - . Get the packet no from the top of the queue -- . check if it's valid ( if not, is this an error??? ) -+ . check if it's valid (if not, is this an error???) - . read the status word - . record the error -- . ( resend? Not really, since we don't want old packets around ) -+ . (resend? Not really, since we don't want old packets around) - . Restore saved values - ************************************************************************/ --static void smc_tx( struct net_device * dev ) -+static void smc_tx(struct net_device * dev) - { -- int ioaddr = dev->base_addr; -+ u_int ioaddr = dev->base_addr; - struct smc_local *lp = (struct smc_local *)dev->priv; - byte saved_packet; - byte packet_no; - word tx_status; - - -- /* assume bank 2 */ -+ /* assume bank 2 */ - -- saved_packet = inb( ioaddr + PNR_ARR ); -- packet_no = inw( ioaddr + FIFO_PORTS ); -+ saved_packet = smc_inb(ioaddr, PNR_ARR); -+ packet_no = smc_inw(ioaddr, FIFO_PORTS); - packet_no &= 0x7F; - - /* select this as the packet to read from */ -- outb( packet_no, ioaddr + PNR_ARR ); -+ smc_outb(packet_no, ioaddr, PNR_ARR); - - /* read the first word from this packet */ -- outw( PTR_AUTOINC | PTR_READ, ioaddr + POINTER ); -+ smc_outw(PTR_AUTOINC | PTR_READ, ioaddr, POINTER); - -- tx_status = inw( ioaddr + DATA_1 ); -- PRINTK3((CARDNAME": TX DONE STATUS: %4x \n", tx_status )); -+ tx_status = smc_inw(ioaddr, DATA_1); -+ PRINTK3(("%s: TX DONE STATUS: %4x\n", dev->name, tx_status)); - - lp->stats.tx_errors++; -- if ( tx_status & TS_LOSTCAR ) lp->stats.tx_carrier_errors++; -- if ( tx_status & TS_LATCOL ) { -- printk(KERN_DEBUG CARDNAME -- ": Late collision occurred on last xmit.\n"); -+ if (tx_status & TS_LOSTCAR) -+ lp->stats.tx_carrier_errors++; -+ if (tx_status & TS_LATCOL) { -+ printk(KERN_DEBUG "%s: Late collision occurred on " -+ "last xmit.\n", dev->name); - lp->stats.tx_window_errors++; - } - #if 0 -- if ( tx_status & TS_16COL ) { ... } -+ if (tx_status & TS_16COL) { ... } - #endif - -- if ( tx_status & TS_SUCCESS ) { -- printk(CARDNAME": Successful packet caused interrupt \n"); -+ if (tx_status & TS_SUCCESS) { -+ printk("%s: Successful packet caused interrupt\n", -+ dev->name); - } - /* re-enable transmit */ -- SMC_SELECT_BANK( 0 ); -- outw( inw( ioaddr + TCR ) | TCR_ENABLE, ioaddr + TCR ); -+ SMC_SELECT_BANK(0); -+ smc_outw(smc_inw(ioaddr, TCR) | TCR_ENABLE, ioaddr, TCR); - - /* kill the packet */ -- SMC_SELECT_BANK( 2 ); -- outw( MC_FREEPKT, ioaddr + MMU_CMD ); -+ SMC_SELECT_BANK(2); -+ smc_outw(MC_FREEPKT, ioaddr, MMU_CMD); - - /* one less packet waiting for me */ - lp->packets_waiting--; - -- outb( saved_packet, ioaddr + PNR_ARR ); -+ smc_outb(saved_packet, ioaddr, PNR_ARR); - return; - } - -@@ -1460,7 +1902,7 @@ - { - netif_stop_queue(dev); - /* clear everything */ -- smc_shutdown( dev->base_addr ); -+ smc_shutdown(dev); - - /* Update the statistics here. */ - return 0; -@@ -1481,16 +1923,16 @@ - . - . This routine will, depending on the values passed to it, - . either make it accept multicast packets, go into -- . promiscuous mode ( for TCPDUMP and cousins ) or accept -+ . promiscuous mode (for TCPDUMP and cousins) or accept - . a select set of multicast packets - */ - static void smc_set_multicast_list(struct net_device *dev) - { -- short ioaddr = dev->base_addr; -+ u_int ioaddr = dev->base_addr; - - SMC_SELECT_BANK(0); -- if ( dev->flags & IFF_PROMISC ) -- outw( inw(ioaddr + RCR ) | RCR_PROMISC, ioaddr + RCR ); -+ if (dev->flags & IFF_PROMISC) -+ smc_outw(smc_inw(ioaddr, RCR) | RCR_PROMISC, ioaddr, RCR); - - /* BUG? I never disable promiscuous mode if multicasting was turned on. - Now, I turn off promiscuous mode, but I don't do anything to multicasting -@@ -1502,34 +1944,34 @@ - checked before the table is - */ - else if (dev->flags & IFF_ALLMULTI) -- outw( inw(ioaddr + RCR ) | RCR_ALMUL, ioaddr + RCR ); -+ smc_outw(smc_inw(ioaddr, RCR) | RCR_ALMUL, ioaddr, RCR); - - /* We just get all multicast packets even if we only want them - . from one source. This will be changed at some future - . point. */ -- else if (dev->mc_count ) { -+ else if (dev->mc_count) { - /* support hardware multicasting */ - - /* be sure I get rid of flags I might have set */ -- outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL), -- ioaddr + RCR ); -+ smc_outw(smc_inw(ioaddr, RCR) & ~(RCR_PROMISC | RCR_ALMUL), -+ ioaddr, RCR); - /* NOTE: this has to set the bank, so make sure it is the - last thing called. The bank is set to zero at the top */ -- smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list ); -+ smc_setmulticast(dev, dev->mc_count, dev->mc_list); - } -- else { -- outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL), -- ioaddr + RCR ); -+ else { -+ smc_outw(smc_inw(ioaddr, RCR) & ~(RCR_PROMISC | RCR_ALMUL), -+ ioaddr, RCR); - - /* - since I'm disabling all multicast entirely, I need to - clear the multicast list - */ -- SMC_SELECT_BANK( 3 ); -- outw( 0, ioaddr + MULTICAST1 ); -- outw( 0, ioaddr + MULTICAST2 ); -- outw( 0, ioaddr + MULTICAST3 ); -- outw( 0, ioaddr + MULTICAST4 ); -+ SMC_SELECT_BANK(3); -+ smc_outw(0, ioaddr, MULTICAST1); -+ smc_outw(0, ioaddr, MULTICAST2); -+ smc_outw(0, ioaddr, MULTICAST3); -+ smc_outw(0, ioaddr, MULTICAST4); - } - } - -@@ -1550,21 +1992,26 @@ - - int init_module(void) - { -- int result; -- - if (io == 0) -- printk(KERN_WARNING -- CARDNAME": You shouldn't use auto-probing with insmod!\n" ); -+ printk(KERN_WARNING CARDNAME -+ ": You shouldn't use auto-probing with insmod!\n"); -+ -+ /* -+ * Note: dev->if_port has changed to be 2.4 compliant. -+ * We keep the ifport insmod parameter the same though. -+ */ -+ switch (ifport) { -+ case 1: devSMC9194.if_port = IF_PORT_10BASET; break; -+ case 2: devSMC9194.if_port = IF_PORT_AUI; break; -+ default: devSMC9194.if_port = 0; break; -+ } - - /* copy the parameters from insmod into the device structure */ - devSMC9194.base_addr = io; - devSMC9194.irq = irq; -- devSMC9194.if_port = ifport; -- devSMC9194.init = smc_init; -- if ((result = register_netdev(&devSMC9194)) != 0) -- return result; -+ devSMC9194.init = smc_init; - -- return 0; -+ return register_netdev(&devSMC9194); - } - - void cleanup_module(void) -diff -urN linux-2.4.26/drivers/net/smc9194.h linux-2.4.26-vrs1/drivers/net/smc9194.h ---- linux-2.4.26/drivers/net/smc9194.h 2001-09-08 20:13:55.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/net/smc9194.h 2004-01-14 21:32:26.000000000 +0000 -@@ -63,10 +63,11 @@ - - #define TCR 0 /* transmit control register */ - #define TCR_ENABLE 0x0001 /* if this is 1, we can transmit */ -+#define TCR_PAD_ENABLE 0x0080 /* pads short packets to 64 bytes */ -+#define TCR_MON_CNS 0x0400 /* monitors the carrier status */ - #define TCR_FDUPLX 0x0800 /* receive packets sent out */ - #define TCR_STP_SQET 0x1000 /* stop transmitting if Signal quality error */ --#define TCR_MON_CNS 0x0400 /* monitors the carrier status */ --#define TCR_PAD_ENABLE 0x0080 /* pads short packets to 64 bytes */ -+#define TCR_FDSE 0x8000 /* full duplex, switched ethernet */ - - #define TCR_CLEAR 0 /* do NOTHING */ - /* the normal settings for the TCR register : */ -@@ -107,7 +108,10 @@ - #define CTL_CR_ENABLE 0x40 - #define CTL_TE_ENABLE 0x0020 - #define CTL_AUTO_RELEASE 0x0800 --#define CTL_EPROM_ACCESS 0x0003 /* high if Eprom is being read */ -+#define CTL_EPROM_SELECT 0x0004 -+#define CTL_EPROM_RELOAD 0x0002 -+#define CTL_EPROM_STORE 0x0001 -+#define CTL_EPROM_ACCESS (CTL_EPROM_RELOAD | CTL_EPROM_STORE) /* high if Eprom is being read */ - - /* BANK 2 */ - #define MMU_CMD 0 -@@ -130,7 +134,6 @@ - #define PTR_READ 0x2000 - #define PTR_RCV 0x8000 - #define PTR_AUTOINC 0x4000 --#define PTR_AUTO_INC 0x0040 - - #define DATA_1 8 - #define DATA_2 10 -@@ -162,17 +165,6 @@ - #define CHIP_9195 5 - #define CHIP_91100 7 - --static const char * chip_ids[ 15 ] = { -- NULL, NULL, NULL, -- /* 3 */ "SMC91C90/91C92", -- /* 4 */ "SMC91C94", -- /* 5 */ "SMC91C95", -- NULL, -- /* 7 */ "SMC91C100", -- /* 8 */ "SMC91C100FD", -- NULL, NULL, NULL, -- NULL, NULL, NULL}; -- - /* - . Transmit status bits - */ -@@ -192,40 +184,20 @@ - #define RS_MULTICAST 0x0001 - #define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT) - --static const char * interfaces[ 2 ] = { "TP", "AUI" }; -- --/*------------------------------------------------------------------------- -- . I define some macros to make it easier to do somewhat common -- . or slightly complicated, repeated tasks. -- --------------------------------------------------------------------------*/ -- --/* select a register bank, 0 to 3 */ -- --#define SMC_SELECT_BANK(x) { outw( x, ioaddr + BANK_SELECT ); } -- --/* define a small delay for the reset */ --#define SMC_DELAY() { inw( ioaddr + RCR );\ -- inw( ioaddr + RCR );\ -- inw( ioaddr + RCR ); } -- --/* this enables an interrupt in the interrupt mask register */ --#define SMC_ENABLE_INT(x) {\ -- unsigned char mask;\ -- SMC_SELECT_BANK(2);\ -- mask = inb( ioaddr + INT_MASK );\ -- mask |= (x);\ -- outb( mask, ioaddr + INT_MASK ); \ --} -- --/* this disables an interrupt from the interrupt mask register */ -- --#define SMC_DISABLE_INT(x) {\ -- unsigned char mask;\ -- SMC_SELECT_BANK(2);\ -- mask = inb( ioaddr + INT_MASK );\ -- mask &= ~(x);\ -- outb( mask, ioaddr + INT_MASK ); \ --} -+/* -+ * SMC91C96 ethernet config and status registers. -+ * These are in the "attribute" space. -+ */ -+#define ECOR 0x8000 -+#define ECOR_RESET 0x80 -+#define ECOR_LEVEL_IRQ 0x40 -+#define ECOR_WR_ATTRIB 0x04 -+#define ECOR_ENABLE 0x01 -+ -+#define ECSR 0x8002 -+#define ECSR_IOIS8 0x20 -+#define ECSR_PWRDWN 0x04 -+#define ECSR_INT 0x02 - - /*---------------------------------------------------------------------- - . Define the interrupts that I want to receive from the card -@@ -237,5 +209,36 @@ - --------------------------------------------------------------------------*/ - #define SMC_INTERRUPT_MASK (IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT) - -+/* store this information for the driver.. */ -+struct smc_local { -+ /* -+ these are things that the kernel wants me to keep, so users -+ can find out semi-useless statistics of how well the card is -+ performing -+ */ -+ struct net_device_stats stats; -+ -+ /* -+ If I have to wait until memory is available to send -+ a packet, I will store the skbuff here, until I get the -+ desired memory. Then, I'll send it out and free it. -+ */ -+ struct sk_buff * saved_skb; -+ -+ /* -+ . This keeps track of how many packets that I have -+ . sent out. When an TX_EMPTY interrupt comes, I know -+ . that all of these have been sent. -+ */ -+ int packets_waiting; -+ -+ /* -+ . Interface status. These correspond to the parameters -+ . in the ethtool_cmd structure. -+ */ -+ u8 duplex; -+ u8 port; -+}; -+ - #endif /* _SMC_9194_H_ */ - -diff -urN linux-2.4.26/drivers/parport/Config.in linux-2.4.26-vrs1/drivers/parport/Config.in ---- linux-2.4.26/drivers/parport/Config.in 2004-02-27 20:03:27.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/parport/Config.in 2004-02-23 23:33:11.000000000 +0000 -@@ -27,7 +27,8 @@ - dep_tristate ' Support for PCMCIA management for PC-style ports' CONFIG_PARPORT_PC_PCMCIA $CONFIG_PCMCIA $CONFIG_PARPORT_PC $CONFIG_HOTPLUG - fi - if [ "$CONFIG_ARM" = "y" ]; then -- dep_tristate ' Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT -+ dep_tristate ' Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT $CONFIG_ARCH_ARC -+ dep_tristate ' Accelent SA1110 IDP' CONFIG_PARPORT_IDP $CONFIG_PARPORT $CONFIG_SA1100_ACCELENT - fi - if [ "$CONFIG_AMIGA" = "y" ]; then - dep_tristate ' Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT -diff -urN linux-2.4.26/drivers/parport/Makefile linux-2.4.26-vrs1/drivers/parport/Makefile ---- linux-2.4.26/drivers/parport/Makefile 2004-02-27 20:03:27.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/parport/Makefile 2004-02-23 23:17:13.000000000 +0000 -@@ -29,6 +29,7 @@ - obj-$(CONFIG_PARPORT_ATARI) += parport_atari.o - obj-$(CONFIG_PARPORT_SUNBPP) += parport_sunbpp.o - obj-$(CONFIG_PARPORT_GSC) += parport_gsc.o -+obj-$(CONFIG_PARPORT_IDP) += parport_idp.o - obj-$(CONFIG_PARPORT_IP22) += parport_ip22.o - - include $(TOPDIR)/Rules.make -diff -urN linux-2.4.26/drivers/parport/init.c linux-2.4.26-vrs1/drivers/parport/init.c ---- linux-2.4.26/drivers/parport/init.c 2002-11-28 23:53:14.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/parport/init.c 2004-01-14 21:32:26.000000000 +0000 -@@ -164,6 +164,9 @@ - #ifdef CONFIG_PARPORT_SUNBPP - parport_sunbpp_init(); - #endif -+#ifdef CONFIG_PARPORT_IDP -+ parport_idp_init(); -+#endif - return 0; - } - -diff -urN linux-2.4.26/drivers/parport/parport_idp.c linux-2.4.26-vrs1/drivers/parport/parport_idp.c ---- linux-2.4.26/drivers/parport/parport_idp.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/parport/parport_idp.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,247 @@ -+/* Low-level polled-mode parallel port routines for the Accelent IDP -+ * -+ * Author: Rich Dulabahn -+ * -+ * Inspiration taken from parport_amiga.c and parport_atari.c. -+ * -+ * To use, under menuconfig: -+ * 1) Turn on <*> Accelent IDP under Parallel port setup -+ * 2) Turn on <*> Parallel printer support under Character devices -+ * -+ * This will give you parport0 configured as /dev/lp0 -+ * -+ * To make the correct /dev/lp* entries, enter /dev and type this: -+ * -+ * mknod lp0 c 6 0 -+ * mknod lp1 c 6 1 -+ * mknod lp2 c 6 2 -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+ -+/* -+ * Parallel data port is port H, data -+ * Parallel data direction is port H, direction -+ * Control port is port I, data, lowest 4 bits -+ * Status port is port G, data, upper 5 bits -+ */ -+ -+#define INPUTPOWERHANDLER 0 -+/* masks */ -+#define CONTROL_MASK 0x0f -+#define STATUS_MASK 0xf8 -+ -+#undef DEBUG -+ -+#ifdef DEBUG -+#define DPRINTK printk -+#else -+#define DPRINTK(stuff...) -+#endif -+ -+static struct parport *this_port = NULL; -+ -+static unsigned char -+parport_idp_read_data(struct parport *p) -+{ -+ unsigned char c; -+ -+ c = IDP_FPGA_PORTH_DATA; -+ DPRINTK("read_data:0x%x\n",c); -+ return c; -+} -+ -+static void -+parport_idp_write_data(struct parport *p, unsigned char data) -+{ -+ IDP_FPGA_PORTH_DATA = data; -+ DPRINTK("write_data:0x%x\n",data); -+} -+ -+static unsigned char -+parport_idp_read_control(struct parport *p) -+{ -+ unsigned char c; -+ -+ c = IDP_FPGA_PORTI_DATA & CONTROL_MASK; -+ DPRINTK("read_control:0x%x\n",c); -+ return c; -+} -+ -+static void -+parport_idp_write_control(struct parport *p, unsigned char control) -+{ -+ unsigned int temp; -+ -+ temp = IDP_FPGA_PORTH_DATA; -+ temp &= ~CONTROL_MASK; -+ IDP_FPGA_PORTI_DATA = (temp | (control & CONTROL_MASK)); -+DPRINTK("write_control:0x%x\n",control); -+} -+ -+static unsigned char -+parport_idp_frob_control(struct parport *p, unsigned char mask, -+ unsigned char val) -+{ -+ unsigned char c; -+ -+/* From the parport-lowlevel.txt file...*/ -+/* This is equivalent to reading from the control register, masking out -+the bits in mask, exclusive-or'ing with the bits in val, and writing -+the result to the control register. */ -+ -+/* Easy enough, right? */ -+ -+ c = parport_idp_read_control(p); -+ parport_idp_write_control(p, (c & ~mask) ^ val); -+ DPRINTK("frob_control:0x%x\n",c); -+ return c; -+} -+ -+static unsigned char -+parport_idp_read_status(struct parport *p) -+{ -+ unsigned char c; -+ -+ c = IDP_FPGA_PORTG_DATA & STATUS_MASK; -+ c ^= 0x80; /* toggle S7 bit, active low */ -+ DPRINTK("read_status:0x%x\n",c); -+ return c; -+} -+ -+static void -+parport_idp_init_state(struct pardevice *d, struct parport_state *s) -+{ -+} -+ -+static void -+parport_idp_save_state(struct parport *p, struct parport_state *s) -+{ -+} -+ -+static void -+parport_idp_restore_state(struct parport *p, struct parport_state *s) -+{ -+} -+ -+static void -+parport_idp_interrupt(int irq, void *dev_id, struct pt_regs *regs) -+{ -+} -+ -+static void -+parport_idp_enable_irq(struct parport *p) -+{ -+} -+ -+static void -+parport_idp_disable_irq(struct parport *p) -+{ -+} -+ -+static void -+parport_idp_data_forward(struct parport *p) -+{ -+ IDP_FPGA_PORTH_DIR = 0x00; /* 0 sets to output */ -+ DPRINTK("data_forward:0x%x\n",0); -+} -+ -+static void -+parport_idp_data_reverse(struct parport *p) -+{ -+ IDP_FPGA_PORTH_DIR = 0xff; /* and 1 sets to input */ -+ DPRINTK("data_reverse:0x%x\n",0xff); -+} -+ -+static void -+parport_idp_inc_use_count(void) -+{ -+ MOD_INC_USE_COUNT; -+} -+ -+static void -+parport_idp_dec_use_count(void) -+{ -+ MOD_DEC_USE_COUNT; -+} -+ -+static struct parport_operations parport_idp_ops = { -+ parport_idp_write_data, -+ parport_idp_read_data, -+ -+ parport_idp_write_control, -+ parport_idp_read_control, -+ parport_idp_frob_control, -+ -+ parport_idp_read_status, -+ -+ parport_idp_enable_irq, -+ parport_idp_disable_irq, -+ -+ parport_idp_data_forward, -+ parport_idp_data_reverse, -+ -+ parport_idp_init_state, -+ parport_idp_save_state, -+ parport_idp_restore_state, -+ -+ parport_idp_inc_use_count, -+ parport_idp_dec_use_count, -+ -+ parport_ieee1284_epp_write_data, -+ parport_ieee1284_epp_read_data, -+ parport_ieee1284_epp_write_addr, -+ parport_ieee1284_epp_read_addr, -+ -+ parport_ieee1284_ecp_write_data, -+ parport_ieee1284_ecp_read_data, -+ parport_ieee1284_ecp_write_addr, -+ -+ parport_ieee1284_write_compat, -+ parport_ieee1284_read_nibble, -+ parport_ieee1284_read_byte, -+}; -+ -+ -+int __init -+parport_idp_init(void) -+{ -+ struct parport *p; -+ -+ p = parport_register_port((unsigned long)0,PARPORT_IRQ_NONE,PARPORT_DMA_NONE,&parport_idp_ops); -+ -+ if (!p) return 0; /* return 0 on failure */ -+ -+ this_port=p; -+ printk("%s: Accelent IDP parallel port registered.\n", p->name); -+ parport_proc_register(p); -+ parport_announce_port(p); -+ -+ return 1; -+} -+ -+#ifdef MODULE -+ -+MODULE_AUTHOR("Rich Dulabahn"); -+MODULE_DESCRIPTION("Parport Driver for Accelent IDP"); -+MODULE_SUPPORTED_DEVICE("Accelent IDP builtin Parallel Port"); -+MODULE_LICENSE("GPL"); -+ -+int -+init_module(void) -+{ -+ return parport_idp_init() ? 0 : -ENODEV; -+} -+ -+void -+cleanup_module(void) -+{ -+ parport_proc_unregister(this_port); -+ parport_unregister_port(this_port); -+} -+#endif -+ -diff -urN linux-2.4.26/drivers/pci/Makefile linux-2.4.26-vrs1/drivers/pci/Makefile ---- linux-2.4.26/drivers/pci/Makefile 2003-08-25 12:44:42.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pci/Makefile 2004-01-14 21:39:07.000000000 +0000 -@@ -13,7 +13,7 @@ - - export-objs := pci.o - --obj-$(CONFIG_PCI) += pci.o quirks.o compat.o names.o -+obj-$(CONFIG_PCI) += pci.o quirks.o compat.o names.o bridge.o - obj-$(CONFIG_PROC_FS) += proc.o - - ifndef CONFIG_SPARC64 -diff -urN linux-2.4.26/drivers/pci/bridge.c linux-2.4.26-vrs1/drivers/pci/bridge.c ---- linux-2.4.26/drivers/pci/bridge.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pci/bridge.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,149 @@ -+ -+/* -+ * Copyright (c) 2001 Red Hat, Inc. All rights reserved. -+ * -+ * This software may be freely redistributed under the terms -+ * of the GNU public license. -+ * -+ * 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. -+ * -+ * Author: Arjan van de Ven -+ * -+ */ -+ -+ -+/* -+ * Generic PCI driver for PCI bridges for powermanagement purposes -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+static struct pci_device_id bridge_pci_table[] __devinitdata = { -+ {/* handle all PCI bridges */ -+ class: ((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), -+ class_mask: ~0, -+ vendor: PCI_ANY_ID, -+ device: PCI_ANY_ID, -+ subvendor: PCI_ANY_ID, -+ subdevice: PCI_ANY_ID, -+ }, -+ {0,}, -+}; -+ -+static int bridge_probe(struct pci_dev *pdev, const struct pci_device_id *id); -+static int pci_bridge_save_state_bus(struct pci_bus *bus, int force); -+int pci_generic_resume_compare(struct pci_dev *pdev); -+ -+int pci_bridge_force_restore = 0; -+ -+ -+ -+ -+static int __init bridge_setup(char *str) -+{ -+ if (!strcmp(str,"force")) -+ pci_bridge_force_restore = 1; -+ else if (!strcmp(str,"noforce")) -+ pci_bridge_force_restore = 0; -+ return 0; -+} -+ -+__setup("resume=",bridge_setup); -+ -+ -+static int pci_bridge_save_state_bus(struct pci_bus *bus, int force) -+{ -+ struct list_head *list; -+ int error = 0; -+ -+ list_for_each(list, &bus->children) { -+ error = pci_bridge_save_state_bus(pci_bus_b(list),force); -+ if (error) return error; -+ } -+ list_for_each(list, &bus->devices) { -+ pci_generic_suspend_save(pci_dev_b(list),0); -+ } -+ return 0; -+} -+ -+ -+static int pci_bridge_restore_state_bus(struct pci_bus *bus, int force) -+{ -+ struct list_head *list; -+ int error = 0; -+ static int printed_warning=0; -+ -+ list_for_each(list, &bus->children) { -+ error = pci_bridge_restore_state_bus(pci_bus_b(list),force); -+ if (error) return error; -+ } -+ list_for_each(list, &bus->devices) { -+ if (force) -+ pci_generic_resume_restore(pci_dev_b(list)); -+ else { -+ error = pci_generic_resume_compare(pci_dev_b(list)); -+ if (error && !printed_warning++) { -+ printk(KERN_WARNING "resume warning: bios doesn't restore PCI state properly\n"); -+ printk(KERN_WARNING "resume warning: if resume failed, try booting with resume=force\n"); -+ } -+ if (error) -+ return error; -+ } -+ } -+ return 0; -+} -+ -+static int bridge_suspend(struct pci_dev *dev, u32 force) -+{ -+ pci_generic_suspend_save(dev,force); -+ if (dev->subordinate) -+ pci_bridge_save_state_bus(dev->subordinate,force); -+ return 0; -+} -+ -+static int bridge_resume(struct pci_dev *dev) -+{ -+ -+ pci_generic_resume_restore(dev); -+ if (dev->subordinate) -+ pci_bridge_restore_state_bus(dev->subordinate,pci_bridge_force_restore); -+ return 0; -+} -+ -+ -+MODULE_DEVICE_TABLE(pci, bridge_pci_table); -+static struct pci_driver bridge_ops = { -+ name: "PCI Bridge", -+ id_table: bridge_pci_table, -+ probe: bridge_probe, -+ suspend: bridge_suspend, -+ resume: bridge_resume -+}; -+ -+static int __devinit bridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) -+{ -+ return 0; -+} -+ -+static int __init bridge_init(void) -+{ -+ pci_register_driver(&bridge_ops); -+ return 0; -+} -+ -+static void __exit bridge_exit(void) -+{ -+ pci_unregister_driver(&bridge_ops); -+} -+ -+ -+module_init(bridge_init) -+module_exit(bridge_exit) -+ -diff -urN linux-2.4.26/drivers/pci/pci.c linux-2.4.26-vrs1/drivers/pci/pci.c ---- linux-2.4.26/drivers/pci/pci.c 2003-11-28 18:26:20.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/pci/pci.c 2004-01-14 21:39:08.000000000 +0000 -@@ -359,6 +359,48 @@ - return 0; - } - -+int -+pci_compare_state(struct pci_dev *dev, u32 *buffer) -+{ -+ int i; -+ unsigned int temp; -+ -+ if (buffer) { -+ for (i = 0; i < 16; i++) { -+ pci_read_config_dword(dev,i*4,&temp); -+ if (temp!=buffer[i]) -+ return 1; -+ } -+ } -+ return 0; -+} -+ -+int pci_generic_suspend_save(struct pci_dev *pdev, u32 state) -+{ -+ if (pdev) -+ pci_save_state(pdev,pdev->saved_state); -+ return 0; -+} -+ -+int pci_generic_resume_restore(struct pci_dev *pdev) -+{ -+ if (pdev) -+ pci_restore_state(pdev,pdev->saved_state); -+ return 0; -+} -+ -+int pci_generic_resume_compare(struct pci_dev *pdev) -+{ -+ int retval=0; -+ if (pdev) -+ retval = pci_compare_state(pdev,pdev->saved_state); -+ return retval; -+} -+ -+EXPORT_SYMBOL(pci_generic_suspend_save); -+EXPORT_SYMBOL(pci_generic_resume_restore); -+EXPORT_SYMBOL(pci_generic_resume_compare); -+ - /** - * pci_enable_device_bars - Initialize some of a device for use - * @dev: PCI device to be initialized -diff -urN linux-2.4.26/drivers/pci/setup-bus.c linux-2.4.26-vrs1/drivers/pci/setup-bus.c ---- linux-2.4.26/drivers/pci/setup-bus.c 2003-06-13 15:51:35.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pci/setup-bus.c 2004-01-14 21:32:26.000000000 +0000 -@@ -12,6 +12,8 @@ - /* - * Nov 2000, Ivan Kokshaysky - * PCI-PCI bridges cleanup, sorted resource allocation. -+ * May 2001, Russell King -+ * Allocate prefetchable memory regions where available. - * Feb 2002, Ivan Kokshaysky - * Converted to allocation in 3 passes, which gives - * tighter packing. Prefetchable range support. -@@ -160,8 +162,10 @@ - pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); - - /* Check if we have VGA behind the bridge. -- Enable ISA in either case (FIXME!). */ -- l = (bus->resource[0]->flags & IORESOURCE_BUS_HAS_VGA) ? 0x0c : 0x04; -+ Enable ISA in either case. */ -+ l = (bus->resource[0]->flags & IORESOURCE_BUS_HAS_VGA) ? -+ PCI_BRIDGE_CTL_VGA | PCI_BRIDGE_CTL_NO_ISA : -+ PCI_BRIDGE_CTL_NO_ISA; - pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, l); - } - -diff -urN linux-2.4.26/drivers/pcmcia/Config.in linux-2.4.26-vrs1/drivers/pcmcia/Config.in ---- linux-2.4.26/drivers/pcmcia/Config.in 2004-02-27 20:03:27.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/pcmcia/Config.in 2004-02-23 23:29:38.000000000 +0000 -@@ -14,21 +14,19 @@ - - tristate 'PCMCIA/CardBus support' CONFIG_PCMCIA - if [ "$CONFIG_PCMCIA" != "n" ]; then -+ # yes, I really mean the following... -+ if [ "$CONFIG_ISA" = "y" -o "$CONFIG_ARCH_SA1100" = "y" ]; then -+ define_bool CONFIG_PCMCIA_PROBE y -+ fi - if [ "$CONFIG_PCI" != "n" ]; then - bool ' CardBus support' CONFIG_CARDBUS - fi -+ dep_bool ' i82092 compatible bridge support' CONFIG_I82092 $CONFIG_PCI -+ bool ' i82365 compatible bridge support' CONFIG_I82365 - bool ' Databook TCIC host bridge support' CONFIG_TCIC - if [ "$CONFIG_HD64465" = "y" ]; then - dep_tristate ' HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA - fi -- dep_bool ' i82092 compatible bridge support' CONFIG_I82092 $CONFIG_PCI -- bool ' i82365 compatible bridge support' CONFIG_I82365 -- if [ "$CONFIG_ARCH_SA1100" = "y" ]; then -- dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_PCMCIA -- fi -- if [ "$CONFIG_8xx" = "y" ]; then -- dep_tristate ' M8xx support' CONFIG_PCMCIA_M8XX $CONFIG_PCMCIA -- fi - if [ "$CONFIG_SOC_AU1X00" = "y" ]; then - dep_tristate ' Au1x00 PCMCIA support' CONFIG_PCMCIA_AU1X00 $CONFIG_PCMCIA - if [ "$CONFIG_PCMCIA_AU1X00" != "n" ]; then -@@ -44,5 +42,9 @@ - dep_tristate ' NEC VRC4173 CARDU support' CONFIG_PCMCIA_VRC4173 $CONFIG_PCMCIA - fi - fi -+if [ "$CONFIG_ARM" = "y" ]; then -+ dep_tristate ' CLPS6700 support' CONFIG_PCMCIA_CLPS6700 $CONFIG_ARCH_CLPS711X $CONFIG_PCMCIA -+ dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA -+fi - - endmenu -diff -urN linux-2.4.26/drivers/pcmcia/Makefile linux-2.4.26-vrs1/drivers/pcmcia/Makefile ---- linux-2.4.26/drivers/pcmcia/Makefile 2004-02-27 20:03:27.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/pcmcia/Makefile 2004-02-23 23:19:09.000000000 +0000 -@@ -65,15 +65,18 @@ - au1000_ss-objs-$(CONFIG_PCMCIA_DB1X00) += au1000_db1x00.o - au1000_ss-objs-$(CONFIG_PCMCIA_XXS1500) += au1000_xxs1500.o - -+obj-$(CONFIG_PCMCIA_CLPS6700) += clps6700.o - obj-$(CONFIG_PCMCIA_SA1100) += sa1100_cs.o --obj-$(CONFIG_PCMCIA_M8XX) += m8xx_pcmcia.o - obj-$(CONFIG_PCMCIA_SIBYTE) += sibyte_generic.o - - sa1100_cs-objs-y := sa1100_generic.o -+sa1100_cs-objs-$(CONFIG_SA1100_ADSAGC) += sa1100_graphicsmaster.o sa1111_generic.o - sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY) += sa1100_adsbitsy.o sa1111_generic.o -+sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSYPLUS) += sa1100_adsbitsyplus.o sa1111_generic.o - sa1100_cs-objs-$(CONFIG_SA1100_ASSABET) += sa1100_assabet.o - sa1100_cs-objs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o sa1111_generic.o - sa1100_cs-objs-$(CONFIG_SA1100_BADGE4) += sa1100_badge4.o sa1111_generic.o -+sa1100_cs-objs-$(CONFIG_SA1100_CONSUS) += sa1100_neponset.o sa1111_generic.o - sa1100_cs-objs-$(CONFIG_SA1100_CERF) += sa1100_cerf.o - sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET) += sa1100_flexanet.o - sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD) += sa1100_freebird.o -diff -urN linux-2.4.26/drivers/pcmcia/cistpl.c linux-2.4.26-vrs1/drivers/pcmcia/cistpl.c ---- linux-2.4.26/drivers/pcmcia/cistpl.c 2004-02-27 20:03:27.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/pcmcia/cistpl.c 2004-02-23 13:36:32.000000000 +0000 -@@ -286,7 +286,7 @@ - s->cis_mem.flags &= ~MAP_ACTIVE; - s->ss_entry->set_mem_map(s->sock, &s->cis_mem); - if (!(s->cap.features & SS_CAP_STATIC_MAP)) -- release_mem_region(s->cis_mem.sys_start, s->cap.map_size); -+ release_mem_resource(s->cis_mem.sys_start, s->cap.map_size); - bus_iounmap(s->cap.bus, s->cis_virt); - s->cis_mem.sys_start = 0; - s->cis_virt = NULL; -diff -urN linux-2.4.26/drivers/pcmcia/clps6700.c linux-2.4.26-vrs1/drivers/pcmcia/clps6700.c ---- linux-2.4.26/drivers/pcmcia/clps6700.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pcmcia/clps6700.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,498 @@ -+/* -+ * linux/drivers/pcmcia/clps6700.c -+ * -+ * Copyright (C) 2000 Deep Blue Solutions Ltd -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "clps6700.h" -+ -+#define DEBUG -+ -+MODULE_AUTHOR("Russell King"); -+MODULE_DESCRIPTION("CL-PS6700 PCMCIA socket driver"); -+ -+#define NR_CLPS6700 2 -+ -+struct clps6700_skt { -+ u_int nr; -+ u_int physbase; -+ u_int regbase; -+ u_int pmr; -+ u_int cpcr; -+ u_int cpcr_3v3; -+ u_int cpcr_5v0; -+ u_int cur_pmr; -+ u_int cur_cicr; -+ u_int cur_pcimr; -+ u_int cur_cpcr; -+ void (*handler)(void *, u_int); -+ void *handler_info; -+ -+ u_int ev_pending; -+ spinlock_t ev_lock; -+}; -+ -+static struct clps6700_skt *skts[NR_CLPS6700]; -+ -+static int clps6700_sock_init(u_int sock) -+{ -+ struct clps6700_skt *skt = skts[sock]; -+ -+ skt->cur_cicr = 0; -+ skt->cur_pmr = skt->pmr; -+ skt->cur_pcimr = 0; -+ skt->cur_cpcr = skt->cpcr; -+ -+#ifdef DEBUG -+ printk("skt%d: sock_init()\n", sock); -+#endif -+ -+ __raw_writel(skt->cur_pmr, skt->regbase + PMR); -+ __raw_writel(skt->cur_cpcr, skt->regbase + CPCR); -+ __raw_writel(0x01f8, skt->regbase + SICR); -+ __raw_writel(0x0000, skt->regbase + DMACR); -+ __raw_writel(skt->cur_cicr, skt->regbase + CICR); -+ __raw_writel(0x1f00, skt->regbase + CITR0A); -+ __raw_writel(0x0000, skt->regbase + CITR0B); -+ __raw_writel(0x1f00, skt->regbase + CITR1A); -+ __raw_writel(0x0000, skt->regbase + CITR1B); -+ __raw_writel(skt->cur_pcimr, skt->regbase + PCIMR); -+ -+ /* -+ * Enable Auto Idle Mode in PM register -+ */ -+ __raw_writel(-1, skt->regbase + PCIRR1); -+ __raw_writel(-1, skt->regbase + PCIRR2); -+ __raw_writel(-1, skt->regbase + PCIRR3); -+ -+ return 0; -+} -+ -+static int clps6700_suspend(u_int sock) -+{ -+ return 0; -+} -+ -+static int clps6700_register_callback(u_int sock, void (*handler)(void *, u_int), void *info) -+{ -+ struct clps6700_skt *skt = skts[sock]; -+ -+#ifdef DEBUG -+ printk("skt%d: register_callback: %p (%p)\n", sock, handler, info); -+#endif -+ -+ skt->handler_info = info; -+ skt->handler = handler; -+ -+ return 0; -+} -+ -+static int clps6700_inquire_socket(u_int sock, socket_cap_t *cap) -+{ -+ cap->features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP | SS_CAP_MEM_ALIGN; -+ cap->irq_mask = 0; /* available IRQs for this socket */ -+ cap->map_size = PAGE_SIZE; /* minimum mapping size */ -+ cap->pci_irq = 0; /* PCI interrupt number */ -+ cap->cb_dev = NULL; -+ cap->bus = NULL; -+ return 0; -+} -+ -+static int __clps6700_get_status(struct clps6700_skt *skt) -+{ -+ unsigned int v, val; -+ -+ v = __raw_readl(skt->regbase + PCIILR); -+ val = 0; -+ if ((v & (PCM_CD1 | PCM_CD2)) == 0) -+ val |= SS_DETECT; -+ if ((v & (PCM_BVD2 | PCM_BVD1)) == PCM_BVD1) -+ val |= SS_BATWARN; -+ if ((v & PCM_BVD2) == 0) -+ val |= SS_BATDEAD; -+ -+ if (v & PCM_RDYL) -+ val |= SS_READY; -+ if (v & PCM_VS1) -+ val |= SS_3VCARD; -+ if (v & PCM_VS2) -+ val |= SS_XVCARD; -+ -+#ifdef DEBUG -+ printk("skt%d: PCIILR: %08x -> (%s %s %s %s %s %s)\n", -+ skt->nr, v, -+ val & SS_READY ? "rdy" : "---", -+ val & SS_DETECT ? "det" : "---", -+ val & SS_BATWARN ? "bw" : "--", -+ val & SS_BATDEAD ? "bd" : "--", -+ val & SS_3VCARD ? "3v" : "--", -+ val & SS_XVCARD ? "xv" : "--"); -+#endif -+ return val; -+} -+ -+static int clps6700_get_status(u_int sock, u_int *valp) -+{ -+ struct clps6700_skt *skt = skts[sock]; -+ -+ *valp = __clps6700_get_status(skt); -+ -+ return 0; /* not used! */ -+} -+ -+static int clps6700_get_socket(u_int sock, socket_state_t *state) -+{ -+ return -EINVAL; -+} -+ -+static int clps6700_set_socket(u_int sock, socket_state_t *state) -+{ -+ struct clps6700_skt *skt = skts[sock]; -+ unsigned long flags; -+ u_int cpcr = skt->cur_cpcr, pmr = skt->cur_pmr, cicr = skt->cur_cicr; -+ u_int pcimr = 0; -+ -+ cicr &= ~(CICR_ENABLE | CICR_RESET | CICR_IOMODE); -+ -+ if (state->flags & SS_PWR_AUTO) -+ pmr |= PMR_DCAR | PMR_PDCR; -+ -+ /* -+ * Note! We must NOT assert the Card Enable bit until reset has -+ * been de-asserted. Some cards indicate not ready, which then -+ * hangs our next access. (Bug in CLPS6700?) -+ */ -+ if (state->flags & SS_RESET) -+ cicr |= CICR_RESET | CICR_RESETOE; -+ else if (state->flags & SS_OUTPUT_ENA) -+ cicr |= CICR_ENABLE; -+ -+ if (state->flags & SS_IOCARD) { -+ cicr |= CICR_IOMODE; -+ -+/* if (state->csc_mask & SS_STSCHG)*/ -+ } else { -+ if (state->csc_mask & SS_BATDEAD) -+ pcimr |= PCM_BVD2; -+ if (state->csc_mask & SS_BATWARN) -+ pcimr |= PCM_BVD1; -+ if (state->csc_mask & SS_READY) -+ pcimr |= PCM_RDYL; -+ } -+ -+ if (state->csc_mask & SS_DETECT) -+ pcimr |= PCM_CD1 | PCM_CD2; -+ -+ switch (state->Vcc) { -+ case 0: break; -+ case 33: cpcr |= skt->cpcr_3v3; pmr |= PMR_CPE; break; -+ case 50: cpcr |= skt->cpcr_5v0; pmr |= PMR_CPE; break; -+ default: return -EINVAL; -+ } -+ -+#ifdef DEBUG -+ printk("skt%d: PMR: %04x, CPCR: %04x, CICR: %04x PCIMR: %04x " -+ "(Vcc = %d, flags = %c%c%c%c, csc = %c%c%c%c%c)\n", -+ sock, pmr, cpcr, cicr, pcimr, state->Vcc, -+ state->flags & SS_RESET ? 'r' : '-', -+ state->flags & SS_PWR_AUTO ? 'p' : '-', -+ state->flags & SS_IOCARD ? 'i' : '-', -+ state->flags & SS_OUTPUT_ENA ? 'o' : '-', -+ state->csc_mask & SS_STSCHG ? 's' : '-', -+ state->csc_mask & SS_BATDEAD ? 'd' : '-', -+ state->csc_mask & SS_BATWARN ? 'w' : '-', -+ state->csc_mask & SS_READY ? 'r' : '-', -+ state->csc_mask & SS_DETECT ? 'c' : '-'); -+#endif -+ -+ save_flags_cli(flags); -+ -+ if (skt->cur_cpcr != cpcr) { -+ skt->cur_cpcr = cpcr; -+ __raw_writel(skt->cur_cpcr, skt->regbase + CPCR); -+ } -+ -+ if (skt->cur_pmr != pmr) { -+ skt->cur_pmr = pmr; -+ __raw_writel(skt->cur_pmr, skt->regbase + PMR); -+ } -+ if (skt->cur_pcimr != pcimr) { -+ skt->cur_pcimr = pcimr; -+ __raw_writel(skt->cur_pcimr, skt->regbase + PCIMR); -+ } -+ if (skt->cur_cicr != cicr) { -+ skt->cur_cicr = cicr; -+ __raw_writel(skt->cur_cicr, skt->regbase + CICR); -+ } -+ -+ restore_flags(flags); -+ -+ return 0; -+} -+ -+static int clps6700_get_io_map(u_int sock, struct pccard_io_map *io) -+{ -+ return -EINVAL; -+} -+ -+static int clps6700_set_io_map(u_int sock, struct pccard_io_map *io) -+{ -+ printk("skt%d: iomap: %d: speed %d, flags %X start %X stop %X\n", -+ sock, io->map, io->speed, io->flags, io->start, io->stop); -+ return 0; -+} -+ -+static int clps6700_get_mem_map(u_int sock, struct pccard_mem_map *mem) -+{ -+ return -EINVAL; -+} -+ -+/* -+ * Set the memory map attributes for this socket. (ie, mem->speed) -+ * Note that since we have SS_CAP_STATIC_MAP set, we don't need to do -+ * any mapping here at all; we just need to return the address (suitable -+ * for ioremap) to map the requested space in mem->sys_start. -+ * -+ * flags & MAP_ATTRIB indicates whether we want attribute space. -+ */ -+static int clps6700_set_mem_map(u_int sock, struct pccard_mem_map *mem) -+{ -+ struct clps6700_skt *skt = skts[sock]; -+ u_int off; -+ -+ printk("skt%d: memmap: %d: speed %d, flags %X start %lX stop %lX card %X\n", -+ sock, mem->map, mem->speed, mem->flags, mem->sys_start, -+ mem->sys_stop, mem->card_start); -+ -+ if (mem->flags & MAP_ATTRIB) -+ off = CLPS6700_ATTRIB_BASE; -+ else -+ off = CLPS6700_MEM_BASE; -+ -+ mem->sys_start = skt->physbase + off; -+ mem->sys_start += mem->card_start; -+ -+ return 0; -+} -+ -+static void clps6700_proc_setup(u_int sock, struct proc_dir_entry *base) -+{ -+} -+ -+static struct pccard_operations clps6700_operations = { -+ init: clps6700_sock_init, -+ suspend: clps6700_suspend, -+ register_callback: clps6700_register_callback, -+ inquire_socket: clps6700_inquire_socket, -+ get_status: clps6700_get_status, -+ get_socket: clps6700_get_socket, -+ set_socket: clps6700_set_socket, -+ get_io_map: clps6700_get_io_map, -+ set_io_map: clps6700_set_io_map, -+ get_mem_map: clps6700_get_mem_map, -+ set_mem_map: clps6700_set_mem_map, -+ proc_setup: clps6700_proc_setup -+}; -+ -+static void clps6700_bh(void *dummy) -+{ -+ int i; -+ -+ for (i = 0; i < NR_CLPS6700; i++) { -+ struct clps6700_skt *skt = skts[i]; -+ unsigned long flags; -+ u_int events; -+ -+ if (!skt) -+ continue; -+ -+ /* -+ * Note! We must read the pending event state -+ * with interrupts disabled, otherwise we race -+ * with our own interrupt routine! -+ */ -+ spin_lock_irqsave(&skt->ev_lock, flags); -+ events = skt->ev_pending; -+ skt->ev_pending = 0; -+ spin_unlock_irqrestore(&skt->ev_lock, flags); -+ -+ if (skt->handler && events) -+ skt->handler(skt->handler_info, events); -+ } -+} -+ -+static struct tq_struct clps6700_task = { -+ routine: clps6700_bh -+}; -+ -+static void clps6700_interrupt(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ struct clps6700_skt *skt = dev_id; -+ u_int val, events; -+ -+ val = __raw_readl(skt->regbase + PCISR); -+ if (!val) -+ return; -+ -+ __raw_writel(val, skt->regbase + PCICR); -+ -+ events = 0; -+ if (val & (PCM_CD1 | PCM_CD2)) -+ events |= SS_DETECT; -+ if (val & PCM_BVD1) -+ events |= SS_BATWARN; -+ if (val & PCM_BVD2) -+ events |= SS_BATDEAD; -+ if (val & PCM_RDYL) -+ events |= SS_READY; -+ -+ spin_lock(&skt->ev_lock); -+ skt->ev_pending |= events; -+ spin_unlock(&skt->ev_lock); -+ schedule_task(&clps6700_task); -+} -+ -+static int __init clps6700_init_skt(int nr) -+{ -+ struct clps6700_skt *skt; -+ int ret; -+ -+ skt = kmalloc(sizeof(struct clps6700_skt), GFP_KERNEL); -+ if (!skt) -+ return -ENOMEM; -+ -+ memset(skt, 0, sizeof(struct clps6700_skt)); -+ -+ spin_lock_init(&skt->ev_lock); -+ -+ skt->nr = nr; -+ skt->physbase = nr ? CS5_PHYS_BASE : CS4_PHYS_BASE; -+ skt->pmr = PMR_AUTOIDLE | PMR_MCPE | PMR_CDWEAK; -+ skt->cpcr = CPCR_PDIR(PCTL1|PCTL0); -+ skt->cpcr_3v3 = CPCR_PON(PCTL0); -+ skt->cpcr_5v0 = CPCR_PON(PCTL0); /* we only do 3v3 */ -+ -+ skt->cur_pmr = skt->pmr; -+ -+ skt->regbase = (u_int)ioremap(skt->physbase + CLPS6700_REG_BASE, -+ CLPS6700_REG_SIZE); -+ ret = -ENOMEM; -+ if (!skt->regbase) -+ goto err_free; -+ -+ skts[nr] = skt; -+ -+ ret = request_irq(IRQ_EINT3, clps6700_interrupt, -+ SA_SHIRQ, "pcmcia", skt); -+ -+ if (ret) { -+ printk(KERN_ERR "clps6700: unable to grab irq%d (%d)\n", -+ IRQ_EINT3, ret); -+ goto err_unmap; -+ } -+ return 0; -+ -+err_unmap: -+ iounmap((void *)skt->regbase); -+err_free: -+ kfree(skt); -+ skts[nr] = NULL; -+ return ret; -+} -+ -+static void clps6700_free_resources(void) -+{ -+ int i; -+ -+ for (i = NR_CLPS6700; i >= 0; i--) { -+ struct clps6700_skt *skt = skts[i]; -+ -+ skts[i] = NULL; -+ if (skt == NULL) -+ continue; -+ -+ free_irq(IRQ_EINT3, skt); -+ if (skt->regbase) { -+ __raw_writel(skt->pmr, skt->regbase + PMR); -+ __raw_writel(skt->cpcr, skt->regbase + CPCR); -+ __raw_writel(0, skt->regbase + CICR); -+ __raw_writel(0, skt->regbase + PCIMR); -+ } -+ iounmap((void *)skt->regbase); -+ kfree(skt); -+ } -+} -+ -+static int __init clps6700_init(void) -+{ -+ unsigned int v; -+ int err, nr; -+ -+ PLD_CF = 0; -+ v = clps_readl(SYSCON2) | SYSCON2_PCCARD1 | SYSCON2_PCCARD2; -+ clps_writel(v, SYSCON2); -+ v = clps_readl(SYSCON1) | SYSCON1_EXCKEN; -+ clps_writel(v, SYSCON1); -+ -+ for (nr = 0; nr < NR_CLPS6700; nr++) { -+ err = clps6700_init_skt(nr); -+ if (err) -+ goto free; -+ } -+ -+ err = register_ss_entry(nr, &clps6700_operations); -+ if (err) -+ goto free; -+ -+ return 0; -+ -+free: -+ clps6700_free_resources(); -+ /* -+ * An error occurred. Unmap and free all CLPS6700 -+ */ -+ return err; -+} -+ -+static void __exit clps6700_exit(void) -+{ -+ unregister_ss_entry(&clps6700_operations); -+ clps6700_free_resources(); -+} -+ -+module_init(clps6700_init); -+module_exit(clps6700_exit); -diff -urN linux-2.4.26/drivers/pcmcia/clps6700.h linux-2.4.26-vrs1/drivers/pcmcia/clps6700.h ---- linux-2.4.26/drivers/pcmcia/clps6700.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pcmcia/clps6700.h 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,85 @@ -+#define PCISR 0x0000 /* PC Card Interrupt Status Register */ -+#define PCIMR 0x0400 /* PC Card Interrupt Mask Register */ -+#define PCICR 0x0800 /* PC Card Interrupt Clear Register */ -+#define PCIOSR 0x0c00 /* PC Card Interrupt Output Select Regsiter */ -+#define PCIRR1 0x1000 /* PC Card Interrupt Reserved Register 1 */ -+#define PCIRR2 0x1400 /* PC Card Interrupt Reserved Register 2 */ -+#define PCIRR3 0x1800 /* PC Card Interrupt Reserved Register 3 */ -+#define PCIILR 0x1c00 /* PC Card Interrupt Input Level Register */ -+#define SICR 0x2000 /* System Interface Configuration Register */ -+#define CICR 0x2400 /* Card Interface Configuration Register */ -+#define PMR 0x2800 /* Power Management Register */ -+#define CPCR 0x2c00 /* Card Power Control Register */ -+#define CITR0A 0x3000 /* Card Interface Timing Register 0A */ -+#define CITR0B 0x3400 /* Card Interface Timing Register 0B */ -+#define CITR1A 0x3800 /* Card Interface Timing Register 1A */ -+#define CITR1B 0x3c00 /* Card Interface Timing Register 1B */ -+#define DMACR 0x4000 /* DMA Control Register */ -+#define DIR 0x4400 /* Device Information Register */ -+ -+#define CLPS6700_ATTRIB_BASE 0x00000000 -+#define CLPS6700_IO_BASE 0x04000000 -+#define CLPS6700_MEM_BASE 0x08000000 -+#define CLPS6700_REG_BASE 0x0c000000 -+#define CLPS6700_REG_SIZE 0x00005000 -+ -+ -+#define PMR_AUTOIDLE (1 << 0) /* auto idle mode */ -+#define PMR_FORCEIDLE (1 << 1) /* force idle mode */ -+#define PMR_PDCS (1 << 2) /* Power down card on standby */ -+#define PMR_PDCR (1 << 3) /* Power down card on removal */ -+#define PMR_DCAR (1 << 4) /* Disable card access on removal */ -+#define PMR_CPE (1 << 5) /* Card power enable */ -+#define PMR_MCPE (1 << 6) /* Monitor card power enable */ -+#define PMR_PDREQLSEL (1 << 7) /* If set, PDREQL is a GPIO pin */ -+#define PMR_DISSTBY (1 << 8) /* Disable standby */ -+#define PMR_ACCSTBY (1 << 9) /* Complete card accesses before standby*/ -+#define PMR_CDUNPROT (0 << 10) /* Card detect inputs unprotected */ -+#define PMR_CDPROT (1 << 10) /* Card detect inputs protected */ -+#define PMR_CDWEAK (2 << 10) /* Weak pullup except in standby */ -+#define PMR_CDWEAKAL (3 << 10) /* Weak pullup */ -+ -+#define CPCR_PON(x) ((x)&7) /* PCTL[2:0] value when PMR_CPE = 1 */ -+#define CPCR_POFF(x) (((x)&7)<<3) /* PCTL[2:0] value when PMR_CPE = 0 */ -+#define CPCR_PDIR(x) (((x)&7)<<6) /* PCTL[2:0] direction */ -+#define CPCR_CON(x) (((x)&1)<<9) /* GPIO value when PMR_CPE = 1 */ -+#define CPCR_COFF(x) (((x)&1)<<10) /* GPIO value when PMR_CPE = 0 */ -+#define CPCR_CDIR(x) (((x)&1)<<11) /* GPIO direction (PMR_PDREQLSEL = 1) */ -+#define CPCR_VS(x) (((x)&3)<<12) /* VS[2:1] output value */ -+#define CPCR_VSDIR(x) (((x)&3)<<14) /* VS[2:1] direction */ -+ -+#define PCTL0 (1 << 0) -+#define PCTL1 (1 << 1) -+#define PCTL2 (1 << 2) -+ -+#define CICR_ASRTMR1 (1 << 0) /* Timer 1 select for attribute read */ -+#define CICR_ASWTMR1 (1 << 1) /* Timer 1 select for attribute write */ -+#define CICR_IOSRTMR1 (1 << 2) /* Timer 1 select for IO read */ -+#define CICR_IOSWTMR1 (1 << 3) /* Timer 1 select for IO write */ -+#define CICR_MEMSRTMR1 (1 << 4) /* Timer 1 select for memory read */ -+#define CICR_MEMSWTMR1 (1 << 5) /* Timer 1 select for memory write */ -+#define CICR_AUTOIOSZ (1 << 6) /* Auto size I/O accesses */ -+#define CICR_CAW (1 << 7) /* Card access width */ -+#define CICR_IOMODE (1 << 8) /* IO mode select */ -+#define CICR_ENABLE (1 << 10) /* Card enable */ -+#define CICR_RESETOE (1 << 11) /* Card reset output enable */ -+#define CICR_RESET (1 << 12) /* Card reset */ -+ -+ -+#define RD_FAIL (1 << 14) -+#define WR_FAIL (1 << 13) -+#define IDLE (1 << 12) -+ -+#define FFOTHLD (1 << 11) -+#define PCM_RDYL (1 << 10) -+#define PCM_WP (1 << 9) -+#define PCTL (1 << 8) -+ -+#define PDREQ_L (1 << 6) -+#define PCM_VS2 (1 << 5) -+#define PCM_VS1 (1 << 4) -+ -+#define PCM_CD2 (1 << 3) -+#define PCM_CD1 (1 << 2) -+#define PCM_BVD2 (1 << 1) -+#define PCM_BVD1 (1 << 0) -diff -urN linux-2.4.26/drivers/pcmcia/cs.c linux-2.4.26-vrs1/drivers/pcmcia/cs.c ---- linux-2.4.26/drivers/pcmcia/cs.c 2004-02-27 20:03:27.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/pcmcia/cs.c 2004-02-27 23:44:12.000000000 +0000 -@@ -3,7 +3,7 @@ - Kernel Card Services -- core services - - cs.c 1.271 2000/10/02 20:27:49 -- -+ - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of -@@ -28,7 +28,7 @@ - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. -- -+ - ======================================================================*/ - - #include -@@ -92,7 +92,7 @@ - MODULE_AUTHOR("David Hinds "); - MODULE_DESCRIPTION("Linux Kernel Card Services " CS_RELEASE - "\n options:" OPTIONS); --MODULE_LICENSE("Dual MPL/GPL"); -+MODULE_LICENSE("Dual MPL/GPL"); - - #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") - -@@ -123,7 +123,7 @@ - static const char *version = - "cs.c 1.279 2001/10/13 00:08:28 (David Hinds)"; - #endif -- -+ - /*====================================================================*/ - - socket_state_t dead_socket = { -@@ -299,7 +299,7 @@ - - Low-level PC Card interface drivers need to register with Card - Services using these calls. -- -+ - ======================================================================*/ - - static int setup_socket(socket_info_t *); -@@ -331,7 +331,7 @@ - s->use_bus_pm = use_bus_pm; - s->erase_busy.next = s->erase_busy.prev = &s->erase_busy; - spin_lock_init(&s->lock); -- -+ - for (i = 0; i < sockets; i++) - if (socket_table[i] == NULL) break; - socket_table[i] = s; -@@ -365,7 +365,7 @@ - for (ns = 0; ns < nsock; ns++) { - pcmcia_register_socket (ns, ss_entry, 0); - } -- -+ - return 0; - } /* register_ss_entry */ - -@@ -457,7 +457,7 @@ - static void shutdown_socket(socket_info_t *s) - { - client_t **c; -- -+ - DEBUG(1, "cs: shutdown_socket(%p)\n", s); - - /* Blank out the socket state */ -@@ -561,7 +561,7 @@ - have several causes: card insertion, a call to reset_socket, or - recovery from a suspend/resume cycle. Unreset_socket() sends - a CS event that matches the cause of the reset. -- -+ - ======================================================================*/ - - static void reset_socket(socket_info_t *s) -@@ -616,7 +616,7 @@ - s->state &= ~SOCKET_SETUP_PENDING; - } else { - send_event(s, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW); -- if (s->reset_handle) { -+ if (s->reset_handle) { - s->reset_handle->event_callback_args.info = NULL; - EVENT(s->reset_handle, CS_EVENT_RESET_COMPLETE, - CS_EVENT_PRI_LOW); -@@ -631,7 +631,7 @@ - valid clients. Parse_events() interprets the event bits from - a card status change report. Do_shutdown() handles the high - priority stuff associated with a card removal. -- -+ - ======================================================================*/ - - static int send_event(socket_info_t *s, event_t event, int priority) -@@ -641,7 +641,7 @@ - DEBUG(1, "cs: send_event(sock %d, event %d, pri %d)\n", - s->sock, event, priority); - ret = 0; -- for (; client; client = client->next) { -+ for (; client; client = client->next) { - if (client->state & (CLIENT_UNBOUND|CLIENT_STALE)) - continue; - if (client->EventMask & event) { -@@ -675,10 +675,17 @@ - static void parse_events(void *info, u_int events) - { - socket_info_t *s = info; -+ - if (events & SS_DETECT) { - int status; - - get_socket_status(s, &status); -+ -+ /* -+ * If our socket state indicates that a card is present and -+ * either the socket has not been suspended (for some reason) -+ * or the card has been removed, shut down the socket first. -+ */ - if ((s->state & SOCKET_PRESENT) && - (!(s->state & SOCKET_SUSPEND) || - !(status & SS_DETECT))) -@@ -716,7 +723,7 @@ - - This does not comply with the latest PC Card spec for handling - power management events. -- -+ - ======================================================================*/ - - void pcmcia_suspend_socket (socket_info_t *s) -@@ -773,7 +780,7 @@ - /*====================================================================== - - Special stuff for managing IO windows, because they are scarce. -- -+ - ======================================================================*/ - - static int alloc_io_space(socket_info_t *s, u_int attr, ioaddr_t *base, -@@ -862,7 +869,7 @@ - Access_configuration_register() reads and writes configuration - registers in attribute memory. Memory window 0 is reserved for - this and the tuple reading services. -- -+ - ======================================================================*/ - - int pcmcia_access_configuration_register(client_handle_t handle, -@@ -872,7 +879,7 @@ - config_t *c; - int addr; - u_char val; -- -+ - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - s = SOCKET(handle); -@@ -890,7 +897,7 @@ - return CS_CONFIGURATION_LOCKED; - - addr = (c->ConfigBase + reg->Offset) >> 1; -- -+ - switch (reg->Action) { - case CS_READ: - read_cis_mem(s, 1, addr, 1, &val); -@@ -913,7 +920,7 @@ - It is normally called by Driver Services after it has identified - a newly inserted card. An instance of that driver will then be - eligible to register as a client of this socket. -- -+ - ======================================================================*/ - - int pcmcia_bind_device(bind_req_t *req) -@@ -949,23 +956,23 @@ - region. It is normally called by Driver Services after it has - identified a memory device type. An instance of the corresponding - driver will then be able to register to control this region. -- -+ - ======================================================================*/ - - int pcmcia_bind_mtd(mtd_bind_t *req) - { - socket_info_t *s; - memory_handle_t region; -- -+ - if (CHECK_SOCKET(req->Socket)) - return CS_BAD_SOCKET; - s = SOCKET(req); -- -+ - if (req->Attributes & REGION_TYPE_AM) - region = s->a_region; - else - region = s->c_region; -- -+ - while (region) { - if (region->info.CardOffset == req->CardOffset) break; - region = region->info.next; -@@ -973,7 +980,7 @@ - if (!region || (region->mtd != NULL)) - return CS_BAD_OFFSET; - strncpy(region->dev_info, (char *)req->dev_info, DEV_NAME_LEN); -- -+ - DEBUG(1, "cs: bind_mtd(): attr 0x%x, offset 0x%x, dev %s\n", - req->Attributes, req->CardOffset, (char *)req->dev_info); - return CS_SUCCESS; -@@ -988,7 +995,7 @@ - memory_handle_t region; - u_long flags; - int i, sn; -- -+ - DEBUG(1, "cs: deregister_client(%p)\n", handle); - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; -@@ -1007,7 +1014,7 @@ - for (region = s->c_region; region; region = region->info.next) - if (region->mtd == handle) region->mtd = NULL; - } -- -+ - sn = handle->Socket; s = socket_table[sn]; - - if ((handle->state & CLIENT_STALE) || -@@ -1032,7 +1039,7 @@ - - if (--s->real_clients == 0) - register_callback(s, NULL, NULL); -- -+ - return CS_SUCCESS; - } /* deregister_client */ - -@@ -1043,7 +1050,7 @@ - { - socket_info_t *s; - config_t *c; -- -+ - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - s = SOCKET(handle); -@@ -1055,7 +1062,7 @@ - return CS_BAD_ARGS; - } else - config->Function = handle->Function; -- -+ - #ifdef CONFIG_CARDBUS - if (s->state & SOCKET_CARDBUS) { - u_char fn = config->Function; -@@ -1076,16 +1083,16 @@ - return CS_SUCCESS; - } - #endif -- -+ - c = (s->config != NULL) ? &s->config[config->Function] : NULL; -- -+ - if ((c == NULL) || !(c->state & CONFIG_LOCKED)) { - config->Attributes = 0; - config->Vcc = s->socket.Vcc; - config->Vpp1 = config->Vpp2 = s->socket.Vpp; - return CS_SUCCESS; - } -- -+ - /* !!! This is a hack !!! */ - memcpy(&config->Attributes, &c->Attributes, sizeof(config_t)); - config->Attributes |= CONF_VALID_CLIENT; -@@ -1099,14 +1106,14 @@ - config->NumPorts2 = c->io.NumPorts2; - config->Attributes2 = c->io.Attributes2; - config->IOAddrLines = c->io.IOAddrLines; -- -+ - return CS_SUCCESS; - } /* get_configuration_info */ - - /*====================================================================== - - Return information about this version of Card Services. -- -+ - ======================================================================*/ - - int pcmcia_get_card_services_info(servinfo_t *info) -@@ -1124,7 +1131,7 @@ - - Note that get_first_client() *does* recognize the Socket field - in the request structure. -- -+ - ======================================================================*/ - - int pcmcia_get_first_client(client_handle_t *handle, client_req_t *req) -@@ -1239,7 +1246,7 @@ - - Get the current socket state bits. We don't support the latched - SocketState yet: I haven't seen any point for it. -- -+ - ======================================================================*/ - - int pcmcia_get_status(client_handle_t handle, cs_status_t *status) -@@ -1247,7 +1254,7 @@ - socket_info_t *s; - config_t *c; - int val; -- -+ - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - s = SOCKET(handle); -@@ -1263,7 +1270,7 @@ - return CS_NO_CARD; - if (s->state & SOCKET_SETUP_PENDING) - status->CardState |= CS_EVENT_CARD_INSERTION; -- -+ - /* Get info from the PRR, if necessary */ - if (handle->Function == BIND_FN_ALL) { - if (status->Function && (status->Function >= s->functions)) -@@ -1309,7 +1316,7 @@ - /*====================================================================== - - Change the card address of an already open memory window. -- -+ - ======================================================================*/ - - int pcmcia_get_mem_page(window_handle_t win, memreq_t *req) -@@ -1338,7 +1345,7 @@ - /*====================================================================== - - Modify a locked socket configuration -- -+ - ======================================================================*/ - - int pcmcia_modify_configuration(client_handle_t handle, -@@ -1346,7 +1353,7 @@ - { - socket_info_t *s; - config_t *c; -- -+ - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - s = SOCKET(handle); c = CONFIG(handle); -@@ -1354,7 +1361,7 @@ - return CS_NO_CARD; - if (!(c->state & CONFIG_LOCKED)) - return CS_CONFIGURATION_LOCKED; -- -+ - if (mod->Attributes & CONF_IRQ_CHANGE_VALID) { - if (mod->Attributes & CONF_ENABLE_IRQ) { - c->Attributes |= CONF_ENABLE_IRQ; -@@ -1406,7 +1413,7 @@ - win->ctl.flags |= MAP_USE_WAIT; - win->ctl.speed = req->AccessSpeed; - set_mem_map(win->sock, &win->ctl); -- -+ - return CS_SUCCESS; - } /* modify_window */ - -@@ -1416,7 +1423,7 @@ - caller with a socket. The driver must have already been bound - to a socket with bind_device() -- in fact, bind_device() - allocates the client structure that will be used. -- -+ - ======================================================================*/ - - int pcmcia_register_client(client_handle_t *handle, client_reg_t *req) -@@ -1424,7 +1431,7 @@ - client_t *client; - socket_info_t *s; - socket_t ns; -- -+ - /* Look for unbound client with matching dev_info */ - client = NULL; - for (ns = 0; ns < sockets; ns++) { -@@ -1464,7 +1471,7 @@ - - if (s->state & SOCKET_CARDBUS) - client->state |= CLIENT_CARDBUS; -- -+ - if ((!(s->state & SOCKET_CARDBUS)) && (s->functions == 0) && - (client->Function != BIND_FN_ALL)) { - cistpl_longlink_mfc_t mfc; -@@ -1479,7 +1486,7 @@ - return CS_OUT_OF_RESOURCE; - memset(s->config, 0, sizeof(config_t) * s->functions); - } -- -+ - DEBUG(1, "cs: register_client(): client 0x%p, sock %d, dev %s\n", - client, client->Socket, client->dev_info); - if (client->EventMask & CS_EVENT_REGISTRATION_COMPLETE) -@@ -1501,13 +1508,13 @@ - pccard_io_map io = { 0, 0, 0, 0, 1 }; - socket_info_t *s; - int i; -- -+ - if (CHECK_HANDLE(handle) || - !(handle->state & CLIENT_CONFIG_LOCKED)) - return CS_BAD_HANDLE; - handle->state &= ~CLIENT_CONFIG_LOCKED; - s = SOCKET(handle); -- -+ - #ifdef CONFIG_CARDBUS - if (handle->state & CLIENT_CARDBUS) { - cb_disable(s); -@@ -1515,7 +1522,7 @@ - return CS_SUCCESS; - } - #endif -- -+ - if (!(handle->state & CLIENT_STALE)) { - config_t *c = CONFIG(handle); - if (--(s->lock_count) == 0) { -@@ -1536,7 +1543,7 @@ - } - c->state &= ~CONFIG_LOCKED; - } -- -+ - return CS_SUCCESS; - } /* release_configuration */ - -@@ -1547,25 +1554,25 @@ - the actual socket configuration, so if the client is "stale", we - don't bother checking the port ranges against the current socket - values. -- -+ - ======================================================================*/ - - int pcmcia_release_io(client_handle_t handle, io_req_t *req) - { - socket_info_t *s; -- -+ - if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IO_REQ)) - return CS_BAD_HANDLE; - handle->state &= ~CLIENT_IO_REQ; - s = SOCKET(handle); -- -+ - #ifdef CONFIG_CARDBUS - if (handle->state & CLIENT_CARDBUS) { - cb_release(s); - return CS_SUCCESS; - } - #endif -- -+ - if (!(handle->state & CLIENT_STALE)) { - config_t *c = CONFIG(handle); - if (c->state & CONFIG_LOCKED) -@@ -1581,7 +1588,7 @@ - release_io_space(s, req->BasePort1, req->NumPorts1); - if (req->NumPorts2) - release_io_space(s, req->BasePort2, req->NumPorts2); -- -+ - return CS_SUCCESS; - } /* release_io */ - -@@ -1594,7 +1601,7 @@ - return CS_BAD_HANDLE; - handle->state &= ~CLIENT_IRQ_REQ; - s = SOCKET(handle); -- -+ - if (!(handle->state & CLIENT_STALE)) { - config_t *c = CONFIG(handle); - if (c->state & CONFIG_LOCKED) -@@ -1608,16 +1615,16 @@ - s->irq.AssignedIRQ = 0; - } - } -- -+ - if (req->Attributes & IRQ_HANDLE_PRESENT) { - bus_free_irq(s->cap.bus, req->AssignedIRQ, req->Instance); - } - --#ifdef CONFIG_ISA -+#ifdef CONFIG_PCMCIA_PROBE - if (req->AssignedIRQ != s->cap.pci_irq) - undo_irq(req->Attributes, req->AssignedIRQ); - #endif -- -+ - return CS_SUCCESS; - } /* cs_release_irq */ - -@@ -1626,7 +1633,7 @@ - int pcmcia_release_window(window_handle_t win) - { - socket_info_t *s; -- -+ - if ((win == NULL) || (win->magic != WINDOW_MAGIC)) - return CS_BAD_HANDLE; - s = win->sock; -@@ -1640,11 +1647,11 @@ - - /* Release system memory */ - if(!(s->cap.features & SS_CAP_STATIC_MAP)) -- release_mem_region(win->base, win->size); -+ release_mem_resource(win->base, win->size); - win->handle->state &= ~CLIENT_WIN_REQ(win->index); - - win->magic = 0; -- -+ - return CS_SUCCESS; - } /* release_window */ - -@@ -1658,13 +1665,13 @@ - socket_info_t *s; - config_t *c; - pccard_io_map iomap; -- -+ - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - i = handle->Socket; s = socket_table[i]; - if (!(s->state & SOCKET_PRESENT)) - return CS_NO_CARD; -- -+ - #ifdef CONFIG_CARDBUS - if (handle->state & CLIENT_CARDBUS) { - if (!(req->IntType & INT_CARDBUS)) -@@ -1677,7 +1684,7 @@ - return CS_SUCCESS; - } - #endif -- -+ - if (req->IntType & INT_CARDBUS) - return CS_UNSUPPORTED_MODE; - c = CONFIG(handle); -@@ -1692,9 +1699,9 @@ - s->socket.Vpp = req->Vpp1; - if (set_socket(s, &s->socket)) - return CS_BAD_VPP; -- -+ - c->Vcc = req->Vcc; c->Vpp1 = c->Vpp2 = req->Vpp1; -- -+ - /* Pick memory or I/O card, DMA mode, interrupt */ - c->IntType = req->IntType; - c->Attributes = req->Attributes; -@@ -1712,7 +1719,7 @@ - s->socket.io_irq = 0; - set_socket(s, &s->socket); - s->lock_count++; -- -+ - /* Set up CIS configuration registers */ - base = c->ConfigBase = req->ConfigBase; - c->Present = c->CardValues = req->Present; -@@ -1757,7 +1764,7 @@ - u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1; - write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b); - } -- -+ - /* Configure I/O windows */ - if (c->state & CONFIG_IO_REQ) { - iomap.speed = io_speed; -@@ -1779,24 +1786,24 @@ - s->io[i].Config++; - } - } -- -+ - c->state |= CONFIG_LOCKED; - handle->state |= CLIENT_CONFIG_LOCKED; - return CS_SUCCESS; - } /* request_configuration */ - - /*====================================================================== -- -+ - Request_io() reserves ranges of port addresses for a socket. - I have not implemented range sharing or alias addressing. -- -+ - ======================================================================*/ - - int pcmcia_request_io(client_handle_t handle, io_req_t *req) - { - socket_info_t *s; - config_t *c; -- -+ - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - s = SOCKET(handle); -@@ -1855,7 +1862,7 @@ - hooked, we don't guarantee that an irq will still be available - when the configuration is locked. Now that I think about it, - there might be a way to fix this using a dummy handler. -- -+ - ======================================================================*/ - - int pcmcia_request_irq(client_handle_t handle, irq_req_t *req) -@@ -1863,7 +1870,7 @@ - socket_info_t *s; - config_t *c; - int ret = CS_IN_USE, irq = 0; -- -+ - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - s = SOCKET(handle); -@@ -1875,7 +1882,7 @@ - if (c->state & CONFIG_IRQ_REQ) - return CS_IN_USE; - --#ifdef CONFIG_ISA -+#ifdef CONFIG_PCMCIA_PROBE - if (s->irq.AssignedIRQ != 0) { - /* If the interrupt is already assigned, it must match */ - irq = s->irq.AssignedIRQ; -@@ -1909,7 +1916,7 @@ - - if (req->Attributes & IRQ_HANDLE_PRESENT) { - if (bus_request_irq(s->cap.bus, irq, req->Handler, -- ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || -+ ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || - (s->functions > 1) || - (irq == s->cap.pci_irq)) ? SA_SHIRQ : 0, - handle->dev_info, req->Instance)) -@@ -1919,7 +1926,7 @@ - c->irq.Attributes = req->Attributes; - s->irq.AssignedIRQ = req->AssignedIRQ = irq; - s->irq.Config++; -- -+ - c->state |= CONFIG_IRQ_REQ; - handle->state |= CLIENT_IRQ_REQ; - return CS_SUCCESS; -@@ -1938,7 +1945,7 @@ - window_t *win; - u_long align; - int w; -- -+ - if (CHECK_HANDLE(*handle)) - return CS_BAD_HANDLE; - s = SOCKET(*handle); -@@ -2005,7 +2012,7 @@ - /* Return window handle */ - req->Base = win->ctl.sys_start; - *wh = win; -- -+ - return CS_SUCCESS; - } /* request_window */ - -@@ -2014,14 +2021,14 @@ - I'm not sure which "reset" function this is supposed to use, - but for now, it uses the low-level interface's reset, not the - CIS register. -- -+ - ======================================================================*/ - - int pcmcia_reset_card(client_handle_t handle, client_req_t *req) - { - int i, ret; - socket_info_t *s; -- -+ - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - i = handle->Socket; s = socket_table[i]; -@@ -2049,14 +2056,14 @@ - - These shut down or wake up a socket. They are sort of user - initiated versions of the APM suspend and resume actions. -- -+ - ======================================================================*/ - - int pcmcia_suspend_card(client_handle_t handle, client_req_t *req) - { - int i; - socket_info_t *s; -- -+ - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - i = handle->Socket; s = socket_table[i]; -@@ -2077,7 +2084,7 @@ - { - int i; - socket_info_t *s; -- -+ - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - i = handle->Socket; s = socket_table[i]; -@@ -2095,7 +2102,7 @@ - /*====================================================================== - - These handle user requests to eject or insert a card. -- -+ - ======================================================================*/ - - int pcmcia_eject_card(client_handle_t handle, client_req_t *req) -@@ -2103,7 +2110,7 @@ - int i, ret; - socket_info_t *s; - u_long flags; -- -+ - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - i = handle->Socket; s = socket_table[i]; -@@ -2119,9 +2126,9 @@ - spin_lock_irqsave(&s->lock, flags); - do_shutdown(s); - spin_unlock_irqrestore(&s->lock, flags); -- -+ - return CS_SUCCESS; -- -+ - } /* eject_card */ - - int pcmcia_insert_card(client_handle_t handle, client_req_t *req) -@@ -2129,7 +2136,7 @@ - int i, status; - socket_info_t *s; - u_long flags; -- -+ - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; - i = handle->Socket; s = socket_table[i]; -@@ -2157,7 +2164,7 @@ - - Maybe this should send a CS_EVENT_CARD_INSERTION event if we - haven't sent one to this client yet? -- -+ - ======================================================================*/ - - int pcmcia_set_event_mask(client_handle_t handle, eventmask_t *mask) -@@ -2189,7 +2196,7 @@ - printk(KERN_NOTICE); - else - printk(KERN_NOTICE "%s: ", handle->dev_info); -- -+ - for (i = 0; i < SERVICE_COUNT; i++) - if (service_table[i].key == err->func) break; - if (i < SERVICE_COUNT) -@@ -2347,13 +2354,13 @@ - default: - return CS_UNSUPPORTED_FUNCTION; break; - } -- -+ - } /* CardServices */ - - /*====================================================================== - - OS-specific module glue goes here -- -+ - ======================================================================*/ - /* in alpha order */ - EXPORT_SYMBOL(pcmcia_access_configuration_register); -@@ -2450,4 +2457,3 @@ - module_exit(exit_pcmcia_cs); - - /*====================================================================*/ -- -diff -urN linux-2.4.26/drivers/pcmcia/ds.c linux-2.4.26-vrs1/drivers/pcmcia/ds.c ---- linux-2.4.26/drivers/pcmcia/ds.c 2001-11-12 17:39:01.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/pcmcia/ds.c 2004-01-14 21:32:26.000000000 +0000 -@@ -55,6 +55,7 @@ - #include - #include - #include -+#include - - /*====================================================================*/ - -@@ -880,6 +881,8 @@ - EXPORT_SYMBOL(register_pccard_driver); - EXPORT_SYMBOL(unregister_pccard_driver); - -+static devfs_handle_t devfs_handle; -+ - /*====================================================================*/ - - int __init init_pcmcia_ds(void) -@@ -957,8 +960,13 @@ - if (i == -EBUSY) - printk(KERN_NOTICE "unable to find a free device # for " - "Driver Services\n"); -- else -+ else { - major_dev = i; -+ devfs_handle = devfs_register(NULL, "pcmcia", DEVFS_FL_DEFAULT, -+ major_dev, 0, -+ S_IFCHR | S_IRUSR | S_IWUSR, -+ &ds_fops, NULL); -+ } - - #ifdef CONFIG_PROC_FS - if (proc_pccard) -@@ -983,7 +991,9 @@ - remove_proc_entry("drivers", proc_pccard); - #endif - if (major_dev != -1) -- unregister_chrdev(major_dev, "pcmcia"); -+ devfs_unregister_chrdev(major_dev, "pcmcia"); -+ devfs_unregister(devfs_handle); -+ - for (i = 0; i < sockets; i++) - pcmcia_deregister_client(socket_table[i].handle); - sockets = 0; -diff -urN linux-2.4.26/drivers/pcmcia/i82365.c linux-2.4.26-vrs1/drivers/pcmcia/i82365.c ---- linux-2.4.26/drivers/pcmcia/i82365.c 2003-11-28 18:26:20.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/pcmcia/i82365.c 2004-02-22 14:44:10.000000000 +0000 -@@ -28,7 +28,7 @@ - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. -- -+ - ======================================================================*/ - - #include -@@ -65,6 +65,15 @@ - #include "ricoh.h" - #include "o2micro.h" - -+#ifdef CONFIG_ARCH_EBSA110 -+#define I365_MASK (1 << 6) -+#define SOCKIRQ2REG(sock,irq) ((irq) ? ((sock) ? 3 : 4) : 0) -+#define REG2SOCKIRQ(sock,reg) (6) -+#else -+#define SOCKIRQ2REG(sock,irq) (irq) -+#define REG2SOCKIRQ(sock,reg) (reg) -+#endif -+ - #ifdef PCMCIA_DEBUG - static int pc_debug = PCMCIA_DEBUG; - MODULE_PARM(pc_debug, "i"); -@@ -173,13 +182,15 @@ - } socket_info_t; - - /* Where we keep track of our sockets... */ --static int sockets = 0; --static socket_info_t socket[8] = { -- { 0, }, /* ... */ --}; -+static int sockets /* = 0 */; -+static socket_info_t socket[8] /* = { -+ { 0, }, -+} */; - - /* Default ISA interrupt mask */ -+#ifndef I365_MASK - #define I365_MASK 0xdeb8 /* irq 15,14,12,11,10,9,7,5,4,3 */ -+#endif - - static int grab_irq; - static spinlock_t isa_lock = SPIN_LOCK_UNLOCKED; -@@ -303,7 +314,7 @@ - - The VIA controllers also use these routines, as they are mostly - Cirrus lookalikes, without the timing registers. -- -+ - ======================================================================*/ - - #define flip(v,b,f) (v = ((f)<0) ? v : ((f) ? ((v)|(b)) : ((v)&(~b)))) -@@ -389,7 +400,7 @@ - Code to save and restore global state information for Vadem VG468 - and VG469 controllers, and to set and report global configuration - options. -- -+ - ======================================================================*/ - - static void vg46x_get_state(u_short s) -@@ -411,7 +422,7 @@ - static u_int __init vg46x_set_opts(u_short s, char *buf) - { - vg46x_state_t *p = &socket[s].state.vg46x; -- -+ - flip(p->ctl, VG468_CTL_ASYNC, async_clock); - flip(p->ema, VG469_MODE_CABLE, cable_mode); - if (p->ctl & VG468_CTL_ASYNC) -@@ -436,7 +447,7 @@ - /*====================================================================== - - Generic routines to get and set controller options -- -+ - ======================================================================*/ - - static void get_bridge_state(u_short s) -@@ -489,7 +500,7 @@ - /*====================================================================== - - Interrupt testing code, for ISA and PCI interrupts -- -+ - ======================================================================*/ - - static volatile u_int irq_hits; -@@ -517,7 +528,7 @@ - } - - /* Generate one interrupt */ -- i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (irq << 4)); -+ i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (SOCKIRQ2REG(sock, irq) << 4)); - i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ); - udelay(1000); - -@@ -526,7 +537,7 @@ - /* mask all interrupts */ - i365_set(sock, I365_CSCINT, 0); - DEBUG(2, " hits = %d\n", irq_hits); -- -+ - return (irq_hits != 1); - } - -@@ -540,7 +551,7 @@ - /* Don't probe level-triggered interrupts -- reserved for PCI */ - mask0 &= ~(inb(PIC) | (inb(PIC+1) << 8)); - #endif -- -+ - if (do_scan) { - set_bridge_state(sock); - i365_set(sock, I365_CSCINT, 0); -@@ -551,7 +562,7 @@ - if ((mask1 & (1 << i)) && (test_irq(sock, i) != 0)) - mask1 ^= (1 << i); - } -- -+ - printk(KERN_INFO " ISA irqs ("); - if (mask1) { - printk("scanned"); -@@ -565,12 +576,12 @@ - if (!cs_irq && (poll_interval == 0)) poll_interval = HZ; - } - printk(") = "); -- -+ - for (i = 0; i < 16; i++) - if (mask1 & (1<ioaddr > 0) request_region(t->ioaddr, 2, "i82365"); -- -+ - if (base == 0) printk("\n"); - printk(KERN_INFO " %s", pcic[type].name); - printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x", -@@ -713,7 +724,7 @@ - mask &= I365_MASK & set_bridge_opts(base, ns); - /* Scan for ISA interrupts */ - mask = isa_scan(base, mask); -- -+ - /* Poll if only two interrupts available */ - if (!poll_interval) { - u_int tmp = (mask & 0xff20); -@@ -735,15 +746,15 @@ - printk(" status change on irq %d\n", cs_irq); - } - } -- -+ - if (!isa_irq) { - if (poll_interval == 0) - poll_interval = HZ; - printk(" polling interval = %d ms\n", - poll_interval * 1000 / HZ); -- -+ - } -- -+ - /* Update socket interrupt information, capabilities */ - for (i = 0; i < ns; i++) { - t[i].cap.features |= SS_CAP_PCCARD; -@@ -866,12 +877,12 @@ - events = pending_events[i]; - pending_events[i] = 0; - spin_unlock_irq(&pending_event_lock); -- /* -- SS_DETECT events need a small delay here. The reason for this is that -+ /* -+ SS_DETECT events need a small delay here. The reason for this is that - the "is there a card" electronics need time to see the card after the -- "we have a card coming in" electronics have seen it. -+ "we have a card coming in" electronics have seen it. - */ -- if (events & SS_DETECT) -+ if (events & SS_DETECT) - mdelay(4); - if (socket[i].handler) - socket[i].handler(socket[i].info, events); -@@ -890,7 +901,7 @@ - int i, j, csc; - u_int events, active; - u_long flags = 0; -- -+ - DEBUG(4, "i82365: pcic_interrupt(%d)\n", irq); - - for (j = 0; j < 20; j++) { -@@ -906,20 +917,20 @@ - continue; - } - events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0; -- -- -+ -+ - /* Several sockets will send multiple "new card detected" -- events in rapid succession. However, the rest of the pcmcia expects -+ events in rapid succession. However, the rest of the pcmcia expects - only one such event. We just ignore these events by having a - timeout */ - - if (events) { -- if ((jiffies - last_detect_jiffies)<(HZ/20)) -+ if ((jiffies - last_detect_jiffies)<(HZ/20)) - events = 0; - last_detect_jiffies = jiffies; -- -+ - } -- -+ - if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD) - events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0; - else { -@@ -980,11 +991,11 @@ - static int i365_get_status(u_short sock, u_int *value) - { - u_int status; -- -+ - status = i365_get(sock, I365_STATUS); - *value = ((status & I365_CS_DETECT) == I365_CS_DETECT) - ? SS_DETECT : 0; -- -+ - if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) - *value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG; - else { -@@ -1005,7 +1016,7 @@ - *value |= (status & VG469_VSENSE_A_VS2) ? 0 : SS_XVCARD; - } - } -- -+ - DEBUG(1, "i82365: GetStatus(%d) = %#4.4x\n", sock, *value); - return 0; - } /* i365_get_status */ -@@ -1016,7 +1027,7 @@ - { - socket_info_t *t = &socket[sock]; - u_char reg, vcc, vpp; -- -+ - reg = i365_get(sock, I365_POWER); - state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0; - state->flags |= (reg & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0; -@@ -1057,14 +1068,14 @@ - reg = i365_get(sock, I365_INTCTL); - state->flags |= (reg & I365_PC_RESET) ? 0 : SS_RESET; - if (reg & I365_PC_IOCARD) state->flags |= SS_IOCARD; -- state->io_irq = reg & I365_IRQ_MASK; -- -+ state->io_irq = REG2SOCKIRQ(sock, reg & I365_IRQ_MASK); -+ - /* speaker control */ - if (t->flags & IS_CIRRUS) { - if (i365_get(sock, PD67_MISC_CTL_1) & PD67_MC1_SPKR_ENA) - state->flags |= SS_SPKR_ENA; - } -- -+ - /* Card status change mask */ - reg = i365_get(sock, I365_CSCINT); - state->csc_mask = (reg & I365_CSC_DETECT) ? SS_DETECT : 0; -@@ -1075,7 +1086,7 @@ - state->csc_mask |= (reg & I365_CSC_BVD2) ? SS_BATWARN : 0; - state->csc_mask |= (reg & I365_CSC_READY) ? SS_READY : 0; - } -- -+ - DEBUG(1, "i82365: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " - "io_irq %d, csc_mask %#2.2x\n", sock, state->flags, - state->Vcc, state->Vpp, state->io_irq, state->csc_mask); -@@ -1088,21 +1099,21 @@ - { - socket_info_t *t = &socket[sock]; - u_char reg; -- -+ - DEBUG(1, "i82365: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " - "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags, - state->Vcc, state->Vpp, state->io_irq, state->csc_mask); -- -+ - /* First set global controller options */ - set_bridge_state(sock); -- -+ - /* IO card, RESET flag, IO interrupt */ - reg = t->intr; -- reg |= state->io_irq; -+ reg |= SOCKIRQ2REG(sock, state->io_irq); - reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET; - reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0; - i365_set(sock, I365_INTCTL, reg); -- -+ - reg = I365_PWR_NORESET; - if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO; - if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT; -@@ -1165,7 +1176,7 @@ - default: return -EINVAL; - } - } -- -+ - if (reg != i365_get(sock, I365_POWER)) - i365_set(sock, I365_POWER, reg); - -@@ -1175,9 +1186,9 @@ - i365_bflip(sock, PD67_MISC_CTL_1, PD67_MC1_SPKR_ENA, - state->flags & SS_SPKR_ENA); - } -- -+ - /* Card status change interrupt mask */ -- reg = t->cs_irq << 4; -+ reg = SOCKIRQ2REG(sock, t->cs_irq) << 4; - if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT; - if (state->flags & SS_IOCARD) { - if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG; -@@ -1188,7 +1199,7 @@ - } - i365_set(sock, I365_CSCINT, reg); - i365_get(sock, I365_CSC); -- -+ - return 0; - } /* i365_set_socket */ - -@@ -1197,7 +1208,7 @@ - static int i365_get_io_map(u_short sock, struct pccard_io_map *io) - { - u_char map, ioctl, addr; -- -+ - map = io->map; - if (map > 1) return -EINVAL; - io->start = i365_get_pair(sock, I365_IO(map)+I365_W_START); -@@ -1220,7 +1231,7 @@ - static int i365_set_io_map(u_short sock, struct pccard_io_map *io) - { - u_char map, ioctl; -- -+ - DEBUG(1, "i82365: SetIOMap(%d, %d, %#2.2x, %d ns, " - "%#4.4x-%#4.4x)\n", sock, io->map, io->flags, - io->speed, io->start, io->stop); -@@ -1250,30 +1261,30 @@ - { - u_short base, i; - u_char map, addr; -- -+ - map = mem->map; - if (map > 4) return -EINVAL; - addr = i365_get(sock, I365_ADDRWIN); - mem->flags = (addr & I365_ENA_MEM(map)) ? MAP_ACTIVE : 0; - base = I365_MEM(map); -- -+ - i = i365_get_pair(sock, base+I365_W_START); - mem->flags |= (i & I365_MEM_16BIT) ? MAP_16BIT : 0; - mem->flags |= (i & I365_MEM_0WS) ? MAP_0WS : 0; - mem->sys_start = ((u_long)(i & 0x0fff) << 12); -- -+ - i = i365_get_pair(sock, base+I365_W_STOP); - mem->speed = (i & I365_MEM_WS0) ? 1 : 0; - mem->speed += (i & I365_MEM_WS1) ? 2 : 0; - mem->speed = to_ns(mem->speed); - mem->sys_stop = ((u_long)(i & 0x0fff) << 12) + 0x0fff; -- -+ - i = i365_get_pair(sock, base+I365_W_OFF); - mem->flags |= (i & I365_MEM_WRPROT) ? MAP_WRPROT : 0; - mem->flags |= (i & I365_MEM_REG) ? MAP_ATTRIB : 0; - mem->card_start = ((u_int)(i & 0x3fff) << 12) + mem->sys_start; - mem->card_start &= 0x3ffffff; -- -+ - DEBUG(1, "i82365: GetMemMap(%d, %d) = %#2.2x, %d ns, %#5.5lx-%#5." - "5lx, %#5.5x\n", sock, mem->map, mem->flags, mem->speed, - mem->sys_start, mem->sys_stop, mem->card_start); -@@ -1281,12 +1292,12 @@ - } /* i365_get_mem_map */ - - /*====================================================================*/ -- -+ - static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem) - { - u_short base, i; - u_char map; -- -+ - DEBUG(1, "i82365: SetMemMap(%d, %d, %#2.2x, %d ns, %#5.5lx-%#5.5" - "lx, %#5.5x)\n", sock, mem->map, mem->flags, mem->speed, - mem->sys_start, mem->sys_stop, mem->card_start); -@@ -1297,17 +1308,17 @@ - return -EINVAL; - if ((mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff)) - return -EINVAL; -- -+ - /* Turn off the window before changing anything */ - if (i365_get(sock, I365_ADDRWIN) & I365_ENA_MEM(map)) - i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map)); -- -+ - base = I365_MEM(map); - i = (mem->sys_start >> 12) & 0x0fff; - if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT; - if (mem->flags & MAP_0WS) i |= I365_MEM_0WS; - i365_set_pair(sock, base+I365_W_START, i); -- -+ - i = (mem->sys_stop >> 12) & 0x0fff; - switch (to_cycles(mem->speed)) { - case 0: break; -@@ -1316,12 +1327,12 @@ - default: i |= I365_MEM_WS1 | I365_MEM_WS0; break; - } - i365_set_pair(sock, base+I365_W_STOP, i); -- -+ - i = ((mem->card_start - mem->sys_start) >> 12) & 0x3fff; - if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT; - if (mem->flags & MAP_ATTRIB) i |= I365_MEM_REG; - i365_set_pair(sock, base+I365_W_OFF, i); -- -+ - /* Turn on the window if necessary */ - if (mem->flags & MAP_ACTIVE) - i365_bset(sock, I365_ADDRWIN, I365_ENA_MEM(map)); -@@ -1332,7 +1343,7 @@ - - Routines for accessing socket information and register dumps via - /proc/bus/pccard/... -- -+ - ======================================================================*/ - - #ifdef CONFIG_PROC_FS -@@ -1353,7 +1364,7 @@ - u_short sock = (socket_info_t *)data - socket; - char *p = buf; - int i, top; -- -+ - u_long flags = 0; - ISA_LOCK(sock, flags); - top = 0x40; -@@ -1399,7 +1410,7 @@ - - /*====================================================================*/ - --/* this is horribly ugly... proper locking needs to be done here at -+/* this is horribly ugly... proper locking needs to be done here at - * some time... */ - #define LOCKED(x) do { \ - int retval; \ -@@ -1532,7 +1543,7 @@ - /* Set up interrupt handler(s) */ - if (grab_irq != 0) - request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt); -- -+ - if (register_ss_entry(sockets, &pcic_operations) != 0) - printk(KERN_NOTICE "i82365: register_ss_entry() failed\n"); - -@@ -1544,9 +1555,9 @@ - poll_timer.expires = jiffies + poll_interval; - add_timer(&poll_timer); - } -- -+ - return 0; -- -+ - } /* init_i82365 */ - - static void __exit exit_i82365(void) -diff -urN linux-2.4.26/drivers/pcmcia/rsrc_mgr.c linux-2.4.26-vrs1/drivers/pcmcia/rsrc_mgr.c ---- linux-2.4.26/drivers/pcmcia/rsrc_mgr.c 2004-02-27 20:03:27.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/pcmcia/rsrc_mgr.c 2004-02-23 13:36:32.000000000 +0000 -@@ -28,7 +28,7 @@ - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. -- -+ - ======================================================================*/ - - #define __NO_VERSION__ -@@ -55,6 +55,10 @@ - #include - #include "cs_internal.h" - -+#ifndef ISAMEM_PHYS -+#define ISAMEM_PHYS 0 -+#endif -+ - /*====================================================================*/ - - /* Parameters that can be set with 'insmod' */ -@@ -62,7 +66,7 @@ - #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") - - INT_MODULE_PARM(probe_mem, 1); /* memory probe? */ --#ifdef CONFIG_ISA -+#ifdef CONFIG_PCMCIA_PROBE - INT_MODULE_PARM(probe_io, 1); /* IO port probe? */ - INT_MODULE_PARM(mem_limit, 0x10000); - #endif -@@ -85,7 +89,7 @@ - /* IO port resource database */ - static resource_map_t io_db = { 0, 0, &io_db }; - --#ifdef CONFIG_ISA -+#ifdef CONFIG_PCMCIA_PROBE - - typedef struct irq_info_t { - u_int Attributes; -@@ -133,6 +137,7 @@ - static inline int check_mem_resource(unsigned long b, unsigned long n, - struct pci_dev *dev) - { -+ b += ISAMEM_PHYS; - return check_resource(resource_parent(b, n, IORESOURCE_MEM, dev), b, n); - } - -@@ -169,10 +174,15 @@ - static int request_mem_resource(unsigned long b, unsigned long n, - char *name, struct pci_dev *dev) - { -- struct resource *res = make_resource(b, n, IORESOURCE_MEM, name); -- struct resource *pr = resource_parent(b, n, IORESOURCE_MEM, dev); -+ struct resource *res; -+ struct resource *pr; - int err = -ENOMEM; - -+ b += ISAMEM_PHYS; -+ -+ res = make_resource(b, n, IORESOURCE_MEM, name); -+ pr = resource_parent(b, n, IORESOURCE_MEM, dev); -+ - if (res) { - err = request_resource(pr, res); - if (err) -@@ -181,10 +191,16 @@ - return err; - } - -+void release_mem_resource(unsigned long b, unsigned long n) -+{ -+ b += ISAMEM_PHYS; -+ release_mem_region(b, n); -+} -+ - /*====================================================================== - - These manage the internal databases of available resources. -- -+ - ======================================================================*/ - - static int add_interval(resource_map_t *map, u_long base, u_long num) -@@ -248,25 +264,25 @@ - - These routines examine a region of IO or memory addresses to - determine what ranges might be genuinely available. -- -+ - ======================================================================*/ - --#ifdef CONFIG_ISA -+#ifdef CONFIG_PCMCIA_PROBE - static void do_io_probe(ioaddr_t base, ioaddr_t num) - { -- -+ - ioaddr_t i, j, bad, any; - u_char *b, hole, most; -- -+ - printk(KERN_INFO "cs: IO port probe 0x%04x-0x%04x:", - base, base+num-1); -- -+ - /* First, what does a floating port look like? */ - b = kmalloc(256, GFP_KERNEL); - if (!b) { - printk(KERN_ERR "do_io_probe: unable to kmalloc 256 bytes"); - return; -- } -+ } - memset(b, 0, 256); - for (i = base, most = 0; i < base+num; i += 8) { - if (check_io_resource(i, 8, NULL)) -@@ -308,7 +324,7 @@ - printk(" %#04x-%#04x", bad, i-1); - } - } -- -+ - printk(any ? "\n" : " clean.\n"); - } - #endif -@@ -318,7 +334,7 @@ - The memory probe. If the memory list includes a 64K-aligned block - below 1MB, we probe in 64K chunks, and as soon as we accumulate at - least mem_limit free space, we quit. -- -+ - ======================================================================*/ - - static int do_mem_probe(u_long base, u_long num, -@@ -332,7 +348,7 @@ - bad = fail = 0; - step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff); - for (i = j = base; i < base+num; i = j + step) { -- if (!fail) { -+ if (!fail) { - for (j = i; j < base+num; j += step) - if ((check_mem_resource(j, step, s->cap.cb_dev) == 0) && - is_valid(j)) -@@ -356,7 +372,7 @@ - return (num - bad); - } - --#ifdef CONFIG_ISA -+#ifdef CONFIG_PCMCIA_PROBE - - static u_long inv_probe(int (*is_valid)(u_long), - int (*do_cksum)(u_long), -@@ -383,7 +399,7 @@ - static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 }; - static int hi = 0, lo = 0; - u_long b, i, ok = 0; -- -+ - if (!probe_mem) return; - /* We do up to four passes through the list */ - if (!force_low) { -@@ -414,14 +430,14 @@ - } - } - --#else /* CONFIG_ISA */ -+#else /* CONFIG_PCMCIA_PROBE */ - - void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), - int force_low, socket_info_t *s) - { - resource_map_t *m, *n; - static int done = 0; -- -+ - if (!probe_mem || done++) - return; - -@@ -432,7 +448,7 @@ - } - } - --#endif /* CONFIG_ISA */ -+#endif /* CONFIG_PCMCIA_PROBE */ - - /*====================================================================== - -@@ -444,7 +460,7 @@ - should be a power of two, greater than or equal to 'num'. A value - of 0 means that all bits of *base are significant. *base should - also be strictly less than 'align'. -- -+ - ======================================================================*/ - - int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align, -@@ -452,7 +468,7 @@ - { - ioaddr_t try; - resource_map_t *m; -- -+ - for (m = io_db.next; m != &io_db; m = m->next) { - try = (m->base & ~(align-1)) + *base; - for (try = (try >= m->base) ? try : try+align; -@@ -500,10 +516,10 @@ - This checks to see if an interrupt is available, with support - for interrupt sharing. We don't support reserving interrupts - yet. If the interrupt is available, we allocate it. -- -+ - ======================================================================*/ - --#ifdef CONFIG_ISA -+#ifdef CONFIG_PCMCIA_PROBE - - static void fake_irq(int i, void *d, struct pt_regs *r) { } - static inline int check_irq(int irq) -@@ -570,7 +586,7 @@ - - /*====================================================================*/ - --#ifdef CONFIG_ISA -+#ifdef CONFIG_PCMCIA_PROBE - - void undo_irq(u_int Attributes, int irq) - { -@@ -600,7 +616,7 @@ - - The various adjust_* calls form the external interface to the - resource database. -- -+ - ======================================================================*/ - - static int adjust_memory(adjust_t *adj) -@@ -632,7 +648,7 @@ - default: - ret = CS_UNSUPPORTED_FUNCTION; - } -- -+ - return ret; - } - -@@ -641,7 +657,7 @@ - static int adjust_io(adjust_t *adj) - { - int base, num; -- -+ - base = adj->resource.io.BasePort; - num = adj->resource.io.NumPorts; - if ((base < 0) || (base > 0xffff)) -@@ -653,7 +669,7 @@ - case ADD_MANAGED_RESOURCE: - if (add_interval(&io_db, base, num) != 0) - return CS_IN_USE; --#ifdef CONFIG_ISA -+#ifdef CONFIG_PCMCIA_PROBE - if (probe_io) - do_io_probe(base, num); - #endif -@@ -673,15 +689,15 @@ - - static int adjust_irq(adjust_t *adj) - { --#ifdef CONFIG_ISA -+#ifdef CONFIG_PCMCIA_PROBE - int irq; - irq_info_t *info; -- -+ - irq = adj->resource.irq.IRQ; - if ((irq < 0) || (irq > 15)) - return CS_BAD_IRQ; - info = &irq_table[irq]; -- -+ - switch (adj->Action) { - case ADD_MANAGED_RESOURCE: - if (info->Attributes & RES_REMOVED) -@@ -716,7 +732,7 @@ - { - if (CHECK_HANDLE(handle)) - return CS_BAD_HANDLE; -- -+ - switch (adj->Resource) { - case RES_MEMORY_RANGE: - return adjust_memory(adj); -@@ -736,7 +752,7 @@ - void release_resource_db(void) - { - resource_map_t *p, *q; -- -+ - for (p = mem_db.next; p != &mem_db; p = q) { - q = p->next; - kfree(p); -diff -urN linux-2.4.26/drivers/pcmcia/sa1100.h linux-2.4.26-vrs1/drivers/pcmcia/sa1100.h ---- linux-2.4.26/drivers/pcmcia/sa1100.h 2002-08-03 01:39:44.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pcmcia/sa1100.h 2004-01-14 21:32:26.000000000 +0000 -@@ -204,7 +204,9 @@ - extern struct pcmcia_low_level flexanet_pcmcia_ops; - extern struct pcmcia_low_level simpad_pcmcia_ops; - extern struct pcmcia_low_level graphicsmaster_pcmcia_ops; -+extern struct pcmcia_low_level adsagc_pcmcia_ops; - extern struct pcmcia_low_level adsbitsy_pcmcia_ops; -+extern struct pcmcia_low_level adsbitsyplus_pcmcia_ops; - extern struct pcmcia_low_level stork_pcmcia_ops; - extern struct pcmcia_low_level badge4_pcmcia_ops; - -diff -urN linux-2.4.26/drivers/pcmcia/sa1100_adsbitsy.c linux-2.4.26-vrs1/drivers/pcmcia/sa1100_adsbitsy.c ---- linux-2.4.26/drivers/pcmcia/sa1100_adsbitsy.c 2002-08-03 01:39:44.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pcmcia/sa1100_adsbitsy.c 2004-01-14 21:32:26.000000000 +0000 -@@ -11,28 +11,156 @@ - */ - #include - #include -+#include - - #include -+#include -+#include - - #include "sa1100_generic.h" - #include "sa1111_generic.h" - -+int adsbitsy_smc91111_present(void); -+ -+#ifndef CONFIG_SMC91111 -+#define adsbitsy_smc91111_present() 0 -+#endif -+ -+static struct irqs { -+ int irq; -+ const char *str; -+} irqs[] = { -+ { S0_CD_VALID, "SA1111 PCMCIA card detect" }, -+ { S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1" }, -+ { S1_CD_VALID, "SA1111 CF card detect" }, -+ { S1_BVD1_STSCHG, "SA1111 CF BVD1" }, -+}; -+ - static int adsbitsy_pcmcia_init(struct pcmcia_init *init) - { -- /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */ -- PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); -+ int ret=0; -+ int nirq = 0; -+ int slots = 0; -+ int i; -+ -+ /* Set GPIO_A<1:0> to be outputs for PCMCIA power controller: */ -+ PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1); -+ -+ /* Disable Power 3.3V/5V for PCMCIA */ -+ PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1; -+ -+ if (!request_mem_region(_PCCR, 512, "PCMCIA")) -+ return -1; -+ -+ -+ INTPOL1 |= SA1111_IRQMASK_HI(S0_READY_NINT) | -+ SA1111_IRQMASK_HI(S0_CD_VALID) | -+ SA1111_IRQMASK_HI(S0_BVD1_STSCHG); - -- /* Disable Power 3.3V/5V for PCMCIA/CF */ -- PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3; -+ nirq = 2; -+ slots = 1; -+ -+ if (!adsbitsy_smc91111_present()) { -+ /* If the SMC91111 is used CF cannot be used */ -+ /* Set GPIO_A<3:2> to be outputs for CF power controller: */ -+ PA_DDR &= ~(GPIO_GPIO2 | GPIO_GPIO3); -+ -+ /* Disable Power 3.3V/5V for CF */ -+ PA_DWR |= GPIO_GPIO2 | GPIO_GPIO3; -+ -+ INTPOL1 |= SA1111_IRQMASK_HI(S1_READY_NINT) | -+ SA1111_IRQMASK_HI(S1_CD_VALID) | -+ SA1111_IRQMASK_HI(S1_BVD1_STSCHG); -+ -+ nirq = 4; -+ slots = 2; -+ } -+ -+ for (i = ret = 0; i < nirq; i++) { -+ ret = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, -+ irqs[i].str, NULL); -+ if (ret) -+ break; -+ } - -- /* Why? */ -- MECR = 0x09430943; -+ if (i < nirq) { -+ printk(KERN_ERR "sa1111_pcmcia: unable to grab IRQ%d (%d)\n", -+ irqs[i].irq, ret); -+ while (i--) -+ free_irq(irqs[i].irq, NULL); - -- return sa1111_pcmcia_init(init); -+ release_mem_region(_PCCR, 16); -+ } -+ -+ return ret ? -1 : slots; -+} -+ -+static int adsbitsy_pcmcia_shutdown(void) -+{ -+ -+ free_irq(S0_CD_VALID, NULL); -+ free_irq(S0_BVD1_STSCHG, NULL); -+ INTPOL1 &= ~(SA1111_IRQMASK_HI(S0_CD_VALID) | SA1111_IRQMASK_HI(S0_BVD1_STSCHG)); -+ -+ if (!adsbitsy_smc91111_present()) { -+ free_irq(S1_CD_VALID, NULL); -+ free_irq(S1_BVD1_STSCHG, NULL); -+ INTPOL1 &= ~(SA1111_IRQMASK_HI(S1_CD_VALID) | SA1111_IRQMASK_HI(S1_BVD1_STSCHG)); -+ } -+ -+ return 0; - } - --static int --adsbitsy_pcmcia_configure_socket(const struct pcmcia_configure *conf) -+ -+static int adsbitsy_pcmcia_socket_state(struct pcmcia_state_array *state) -+{ -+ unsigned long status; -+ -+ if (adsbitsy_smc91111_present()) { -+ if(state->size<1) return -1; -+ } -+ else -+ if(state->size<2) return -1; -+ -+ memset(state->state, 0, -+ (state->size)*sizeof(struct pcmcia_state)); -+ -+ status = PCSR; -+ -+ state->state[0].detect = status & PCSR_S0_DETECT ? 0 : 1; -+ state->state[0].ready = status & PCSR_S0_READY ? 1 : 0; -+ state->state[0].bvd1 = status & PCSR_S0_BVD1 ? 1 : 0; -+ state->state[0].bvd2 = status & PCSR_S0_BVD2 ? 1 : 0; -+ state->state[0].wrprot = status & PCSR_S0_WP ? 1 : 0; -+ state->state[0].vs_3v = status & PCSR_S0_VS1 ? 0 : 1; -+ state->state[0].vs_Xv = status & PCSR_S0_VS2 ? 0 : 1; -+ -+ if (state->size > 1) { -+ if (adsbitsy_smc91111_present()) { -+ // If there is SMC91111 on ADS Bitsy connector board -+ // it returns not detect/ready/... -+ state->state[1].detect = 0; -+ state->state[1].ready = 0; -+ state->state[1].bvd1 = 0; -+ state->state[1].bvd2 = 0; -+ state->state[1].wrprot = 0; -+ state->state[1].vs_3v = 0; -+ state->state[1].vs_Xv = 0; -+ } -+ else { -+ state->state[1].detect = status & PCSR_S1_DETECT ? 0 : 1; -+ state->state[1].ready = status & PCSR_S1_READY ? 1 : 0; -+ state->state[1].bvd1 = status & PCSR_S1_BVD1 ? 1 : 0; -+ state->state[1].bvd2 = status & PCSR_S1_BVD2 ? 1 : 0; -+ state->state[1].wrprot = status & PCSR_S1_WP ? 1 : 0; -+ state->state[1].vs_3v = status & PCSR_S1_VS1 ? 0 : 1; -+ state->state[1].vs_Xv = status & PCSR_S1_VS2 ? 0 : 1; -+ } -+ } -+ return 1; -+} -+ -+static int adsbitsy_pcmcia_configure_socket(const struct pcmcia_configure *conf) - { - unsigned int pa_dwr_mask, pa_dwr_set; - int ret; -@@ -54,10 +182,11 @@ - - switch (conf->vcc) { - default: -- case 0: pa_dwr_set = 0; break; -+ case 0: pa_dwr_set = GPIO_GPIO2 | GPIO_GPIO3; break; - case 33: pa_dwr_set = GPIO_GPIO2; break; - case 50: pa_dwr_set = GPIO_GPIO3; break; - } -+ break; - - default: - return -1; -@@ -83,8 +212,8 @@ - - struct pcmcia_low_level adsbitsy_pcmcia_ops = { - init: adsbitsy_pcmcia_init, -- shutdown: sa1111_pcmcia_shutdown, -- socket_state: sa1111_pcmcia_socket_state, -+ shutdown: adsbitsy_pcmcia_shutdown, -+ socket_state: adsbitsy_pcmcia_socket_state, - get_irq_info: sa1111_pcmcia_get_irq_info, - configure_socket: adsbitsy_pcmcia_configure_socket, - -diff -urN linux-2.4.26/drivers/pcmcia/sa1100_adsbitsyplus.c linux-2.4.26-vrs1/drivers/pcmcia/sa1100_adsbitsyplus.c ---- linux-2.4.26/drivers/pcmcia/sa1100_adsbitsyplus.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pcmcia/sa1100_adsbitsyplus.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,236 @@ -+/* -+ * drivers/pcmcia/sa1100_adsbitsyplus.c -+ * -+ * PCMCIA implementation routines for ADS Bitsy Plus -+ * -+ * Created Feb 7, 2003 by Robert Whaley -+ * -+ * This file comes from sa1100_adsbitsy.c of Woojung Huh -+ * -+ */ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "sa1100_generic.h" -+#include "sa1111_generic.h" -+ -+int adsbitsy_smc91111_present(void); -+ -+#ifndef CONFIG_SMC91111 -+#define adsbitsy_smc91111_present() 0 -+#endif -+ -+static struct irqs { -+ int irq; -+ const char *str; -+} irqs[] = { -+ { S0_CD_VALID, "SA1111 PCMCIA card detect" }, -+ { S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1" }, -+ { S1_CD_VALID, "SA1111 CF card detect" }, -+ { S1_BVD1_STSCHG, "SA1111 CF BVD1" }, -+}; -+ -+#define sock0_3_3_reverse_logic() ((ADS_CPLD_IO2 & ADS_IO2_CPLD_REV_MASK) >= ADS_IO2_CPLD_REV_5_MAGIC) -+ -+static int adsbitsyplus_pcmcia_init(struct pcmcia_init *init) -+{ -+ int ret=0; -+ int nirq = 0; -+ int slots = 0; -+ int i; -+ -+ /* Set GPIO_A<1:0> to be outputs for PCMCIA power controller: */ -+ PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1); -+ -+ /* Disable Power 3.3V/5V for PCMCIA */ -+ if (sock0_3_3_reverse_logic()) -+ PA_DWR = (PA_DWR & ~GPIO_GPIO0) | GPIO_GPIO1; -+ else -+ PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1; -+ -+ if (!request_mem_region(_PCCR, 512, "PCMCIA")) -+ return -1; -+ -+ -+ INTPOL1 |= SA1111_IRQMASK_HI(S0_READY_NINT) | -+ SA1111_IRQMASK_HI(S0_CD_VALID) | -+ SA1111_IRQMASK_HI(S0_BVD1_STSCHG); -+ -+ nirq = 2; -+ slots = 1; -+ -+ if (!adsbitsy_smc91111_present()) { -+ /* If the SMC91111 is used CF cannot be used */ -+ /* Set GPIO_A<3:2> to be outputs for CF power controller: */ -+ PA_DDR &= ~(GPIO_GPIO2 | GPIO_GPIO3); -+ -+ /* Disable Power 3.3V/5V for CF */ -+ PA_DWR |= GPIO_GPIO2 | GPIO_GPIO3; -+ -+ INTPOL1 |= SA1111_IRQMASK_HI(S1_READY_NINT) | -+ SA1111_IRQMASK_HI(S1_CD_VALID) | -+ SA1111_IRQMASK_HI(S1_BVD1_STSCHG); -+ -+ nirq = 4; -+ slots = 2; -+ } -+ -+ for (i = ret = 0; i < nirq; i++) { -+ ret = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, -+ irqs[i].str, NULL); -+ if (ret) -+ break; -+ } -+ -+ if (i < nirq) { -+ printk(KERN_ERR "sa1111_pcmcia: unable to grab IRQ%d (%d)\n", -+ irqs[i].irq, ret); -+ while (i--) -+ free_irq(irqs[i].irq, NULL); -+ -+ release_mem_region(_PCCR, 16); -+ } -+ -+ return ret ? -1 : slots; -+} -+ -+static int adsbitsyplus_pcmcia_shutdown(void) -+{ -+ -+ free_irq(S0_CD_VALID, NULL); -+ free_irq(S0_BVD1_STSCHG, NULL); -+ INTPOL1 &= ~(SA1111_IRQMASK_HI(S0_CD_VALID) | SA1111_IRQMASK_HI(S0_BVD1_STSCHG)); -+ -+ if (!adsbitsy_smc91111_present()) { -+ free_irq(S1_CD_VALID, NULL); -+ free_irq(S1_BVD1_STSCHG, NULL); -+ INTPOL1 &= ~(SA1111_IRQMASK_HI(S1_CD_VALID) | SA1111_IRQMASK_HI(S1_BVD1_STSCHG)); -+ } -+ -+ return 0; -+} -+ -+ -+static int adsbitsyplus_pcmcia_socket_state(struct pcmcia_state_array *state) -+{ -+ unsigned long status; -+ -+ if (adsbitsy_smc91111_present()) { -+ if(state->size<1) return -1; -+ } -+ else -+ if(state->size<2) return -1; -+ -+ memset(state->state, 0, -+ (state->size)*sizeof(struct pcmcia_state)); -+ -+ status = PCSR; -+ -+ state->state[0].detect = status & PCSR_S0_DETECT ? 0 : 1; -+ state->state[0].ready = status & PCSR_S0_READY ? 1 : 0; -+ state->state[0].bvd1 = status & PCSR_S0_BVD1 ? 1 : 0; -+ state->state[0].bvd2 = status & PCSR_S0_BVD2 ? 1 : 0; -+ state->state[0].wrprot = status & PCSR_S0_WP ? 1 : 0; -+ state->state[0].vs_3v = status & PCSR_S0_VS1 ? 0 : 1; -+ state->state[0].vs_Xv = status & PCSR_S0_VS2 ? 0 : 1; -+ -+ if (state->size > 1) { -+ if (adsbitsy_smc91111_present()) { -+ // If there is SMC91111 on ADS Bitsy connector board -+ // it returns not detect/ready/... -+ state->state[1].detect = 0; -+ state->state[1].ready = 0; -+ state->state[1].bvd1 = 0; -+ state->state[1].bvd2 = 0; -+ state->state[1].wrprot = 0; -+ state->state[1].vs_3v = 0; -+ state->state[1].vs_Xv = 0; -+ } -+ else { -+ state->state[1].detect = status & PCSR_S1_DETECT ? 0 : 1; -+ state->state[1].ready = status & PCSR_S1_READY ? 1 : 0; -+ state->state[1].bvd1 = status & PCSR_S1_BVD1 ? 1 : 0; -+ state->state[1].bvd2 = status & PCSR_S1_BVD2 ? 1 : 0; -+ state->state[1].wrprot = status & PCSR_S1_WP ? 1 : 0; -+ state->state[1].vs_3v = status & PCSR_S1_VS1 ? 0 : 1; -+ state->state[1].vs_Xv = status & PCSR_S1_VS2 ? 0 : 1; -+ } -+ } -+ return 1; -+} -+ -+static int adsbitsyplus_pcmcia_configure_socket(const struct pcmcia_configure *conf) -+{ -+ unsigned int pa_dwr_mask, pa_dwr_set; -+ int ret; -+ -+ switch (conf->sock) { -+ case 0: -+ pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; -+ -+ if (sock0_3_3_reverse_logic()) { -+ switch (conf->vcc) { -+ default: -+ case 0: pa_dwr_set = GPIO_GPIO1; break; -+ case 33: pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1; break; -+ case 50: pa_dwr_set = 0; break; -+ } -+ } else { -+ switch (conf->vcc) { -+ default: -+ case 0: pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1; break; -+ case 33: pa_dwr_set = GPIO_GPIO1; break; -+ case 50: pa_dwr_set = GPIO_GPIO0; break; -+ } -+ } -+ break; -+ -+ case 1: -+ pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3; -+ -+ switch (conf->vcc) { -+ default: -+ case 0: pa_dwr_set = GPIO_GPIO2 | GPIO_GPIO3; break; -+ case 33: pa_dwr_set = GPIO_GPIO2; break; -+ case 50: pa_dwr_set = GPIO_GPIO3; break; -+ } -+ break; -+ -+ default: -+ return -1; -+ } -+ -+ if (conf->vpp != conf->vcc && conf->vpp != 0) { -+ printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n", -+ __FUNCTION__, conf->vpp); -+ return -1; -+ } -+ -+ ret = sa1111_pcmcia_configure_socket(conf); -+ if (ret == 0) { -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; -+ local_irq_restore(flags); -+ } -+ -+ return ret; -+} -+ -+struct pcmcia_low_level adsbitsyplus_pcmcia_ops = { -+ init: adsbitsyplus_pcmcia_init, -+ shutdown: adsbitsyplus_pcmcia_shutdown, -+ socket_state: adsbitsyplus_pcmcia_socket_state, -+ get_irq_info: sa1111_pcmcia_get_irq_info, -+ configure_socket: adsbitsyplus_pcmcia_configure_socket, -+ -+ socket_init: sa1111_pcmcia_socket_init, -+ socket_suspend: sa1111_pcmcia_socket_suspend, -+}; -+ -diff -urN linux-2.4.26/drivers/pcmcia/sa1100_freebird.c linux-2.4.26-vrs1/drivers/pcmcia/sa1100_freebird.c ---- linux-2.4.26/drivers/pcmcia/sa1100_freebird.c 2002-08-03 01:39:44.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pcmcia/sa1100_freebird.c 2004-01-14 21:32:26.000000000 +0000 -@@ -67,9 +67,6 @@ - - if(state_array->size<2) return -1; - -- memset(state_array->state, 0, -- (state_array->size)*sizeof(struct pcmcia_state)); -- - levels = LINKUP_PRS; - //printk("LINKUP_PRS=%x \n",levels); - -diff -urN linux-2.4.26/drivers/pcmcia/sa1100_generic.c linux-2.4.26-vrs1/drivers/pcmcia/sa1100_generic.c ---- linux-2.4.26/drivers/pcmcia/sa1100_generic.c 2003-06-13 15:51:35.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pcmcia/sa1100_generic.c 2004-01-14 21:32:26.000000000 +0000 -@@ -992,10 +992,18 @@ - if(machine_is_graphicsmaster()) - pcmcia_low_level = &graphicsmaster_pcmcia_ops; - #endif -+#ifdef CONFIG_SA1100_ADSAGC -+ if(machine_is_adsagc()) -+ pcmcia_low_level = &graphicsmaster_pcmcia_ops; -+#endif - #ifdef CONFIG_SA1100_ADSBITSY - if(machine_is_adsbitsy()) - pcmcia_low_level = &adsbitsy_pcmcia_ops; - #endif -+#ifdef CONFIG_SA1100_ADSBITSYPLUS -+ if(machine_is_adsbitsyplus()) -+ pcmcia_low_level = &adsbitsyplus_pcmcia_ops; -+#endif - #ifdef CONFIG_SA1100_STORK - if(machine_is_stork()) - pcmcia_low_level = &stork_pcmcia_ops; -@@ -1067,7 +1075,7 @@ - * We initialize the MECR to default values here, because we are - * not guaranteed to see a SetIOMap operation at runtime. - */ -- mecr = 0; -+ mecr = MECR; - - clock = cpufreq_get(0); - -diff -urN linux-2.4.26/drivers/pcmcia/sa1100_graphicsclient.c linux-2.4.26-vrs1/drivers/pcmcia/sa1100_graphicsclient.c ---- linux-2.4.26/drivers/pcmcia/sa1100_graphicsclient.c 2002-08-03 01:39:44.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pcmcia/sa1100_graphicsclient.c 2004-01-14 21:32:26.000000000 +0000 -@@ -3,6 +3,8 @@ - * - * PCMCIA implementation routines for Graphics Client Plus - * -+ * Nov/14/01 Woojung -+ * Set MECR at initializing time - * 9/12/01 Woojung - * Turn power OFF at startup - * 1/31/2001 Woojung Huh -@@ -19,11 +21,6 @@ - #include - #include "sa1100_generic.h" - --#error This is broken! -- --#define S0_CD_IRQ 60 // Socket 0 Card Detect IRQ --#define S0_STS_IRQ 55 // Socket 0 PCMCIA IRQ -- - static volatile unsigned long *PCMCIA_Status = - ((volatile unsigned long *) ADS_p2v(_ADS_CS_STATUS)); - -@@ -46,20 +43,23 @@ - *PCMCIA_Power &= ~0x03; - - /* Register interrupts */ -- irq = S0_CD_IRQ; -+ irq = IRQ_GRAPHICSCLIENT_S0_CD; - res = request_irq(irq, init->handler, SA_INTERRUPT, "PCMCIA 0 CD", NULL); - if (res < 0) { -- printk(KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq); -+ printk(KERN_ERR "%s: Request for IRQ %u failed\n", __FUNCTION__, irq); - return -1; - } - -+ // Nov/14/01 WH -+ MECR = 0x00000943; -+ - return 1; // 1 PCMCIA Slot - } - - static int gcplus_pcmcia_shutdown(void) - { - /* disable IRQs */ -- free_irq( S0_CD_IRQ, NULL); -+ free_irq( IRQ_GRAPHICSCLIENT_S0_CD, NULL); - - /* Shutdown PCMCIA power */ - mdelay(2); // 2msec -@@ -74,9 +74,6 @@ - - if(state_array->size<1) return -1; - -- memset(state_array->state, 0, -- (state_array->size)*sizeof(struct pcmcia_state)); -- - levels=*PCMCIA_Status; - - state_array->state[0].detect=(levels & ADS_CS_ST_A_CD)?1:0; -@@ -96,7 +93,7 @@ - return -1; - - if (info->sock == 0) -- info->irq = S0_STS_IRQ; -+ info->irq = IRQ_GRAPHICSCLIENT_S0_STS; - - return 0; - } -@@ -143,6 +140,11 @@ - - restore_flags(flags); - -+ if (configure->irq) -+ enable_irq(IRQ_GRAPHICSCLIENT_S0_STS); -+ else -+ disable_irq(IRQ_GRAPHICSCLIENT_S0_STS); -+ - return 0; - } - -diff -urN linux-2.4.26/drivers/pcmcia/sa1100_graphicsmaster.c linux-2.4.26-vrs1/drivers/pcmcia/sa1100_graphicsmaster.c ---- linux-2.4.26/drivers/pcmcia/sa1100_graphicsmaster.c 2002-08-03 01:39:44.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pcmcia/sa1100_graphicsmaster.c 2004-01-14 21:32:26.000000000 +0000 -@@ -12,13 +12,13 @@ - #include - - #include -+#include - - #include "sa1100_generic.h" - #include "sa1111_generic.h" - - static int graphicsmaster_pcmcia_init(struct pcmcia_init *init) - { -- int return_val=0; - - /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */ - PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); -@@ -26,9 +26,6 @@ - /* Disable Power 3.3V/5V for PCMCIA/CF */ - PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3; - -- /* why? */ -- MECR = 0x09430943; -- - return sa1111_pcmcia_init(init); - } - -@@ -59,6 +56,10 @@ - case 33: pa_dwr_set = GPIO_GPIO3; break; - case 50: pa_dwr_set = GPIO_GPIO2; break; - } -+ break; -+ -+ default: -+ return -1; - } - - if (conf->vpp != conf->vcc && conf->vpp != 0) { -diff -urN linux-2.4.26/drivers/pcmcia/sa1100_h3600.c linux-2.4.26-vrs1/drivers/pcmcia/sa1100_h3600.c ---- linux-2.4.26/drivers/pcmcia/sa1100_h3600.c 2002-08-03 01:39:44.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pcmcia/sa1100_h3600.c 2004-01-14 21:32:26.000000000 +0000 -@@ -29,6 +29,9 @@ - set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_IRQ0 | GPIO_H3600_PCMCIA_IRQ1, - GPIO_FALLING_EDGE); - -+ set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1, -+ GPIO_NO_EDGES); -+ - /* - * Register interrupts - */ -diff -urN linux-2.4.26/drivers/pcmcia/sa1100_jornada720.c linux-2.4.26-vrs1/drivers/pcmcia/sa1100_jornada720.c ---- linux-2.4.26/drivers/pcmcia/sa1100_jornada720.c 2002-08-03 01:39:44.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pcmcia/sa1100_jornada720.c 2004-01-14 21:32:26.000000000 +0000 -@@ -8,6 +8,7 @@ - #include - - #include -+#include - - #include "sa1100_generic.h" - #include "sa1111_generic.h" -@@ -88,7 +89,7 @@ - - local_irq_save(flags); - PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; -- locla_irq_restore(flags); -+ local_irq_restore(flags); - } - - return ret; -diff -urN linux-2.4.26/drivers/pcmcia/sa1100_pangolin.c linux-2.4.26-vrs1/drivers/pcmcia/sa1100_pangolin.c ---- linux-2.4.26/drivers/pcmcia/sa1100_pangolin.c 2002-08-03 01:39:44.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pcmcia/sa1100_pangolin.c 2004-01-14 21:32:26.000000000 +0000 -@@ -53,9 +53,6 @@ - - if(state_array->size<2) return -1; - -- memset(state_array->state, 0, -- (state_array->size)*sizeof(struct pcmcia_state)); -- - levels=GPLR; - #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE - state_array->state[1].detect=((levels & GPIO_PCMCIA_CD)==0)?1:0; -diff -urN linux-2.4.26/drivers/pcmcia/sa1100_shannon.c linux-2.4.26-vrs1/drivers/pcmcia/sa1100_shannon.c ---- linux-2.4.26/drivers/pcmcia/sa1100_shannon.c 2002-08-03 01:39:44.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pcmcia/sa1100_shannon.c 2004-01-14 21:32:26.000000000 +0000 -@@ -53,9 +53,6 @@ - { - unsigned long levels; - -- memset(state_array->state, 0, -- state_array->size * sizeof(struct pcmcia_state)); -- - levels = GPLR; - - state_array->state[0].detect = (levels & SHANNON_GPIO_EJECT_0) ? 0 : 1; -diff -urN linux-2.4.26/drivers/pcmcia/sa1100_simpad.c linux-2.4.26-vrs1/drivers/pcmcia/sa1100_simpad.c ---- linux-2.4.26/drivers/pcmcia/sa1100_simpad.c 2002-08-03 01:39:44.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pcmcia/sa1100_simpad.c 2004-01-14 21:32:26.000000000 +0000 -@@ -63,9 +63,6 @@ - - if(state_array->size<2) return -1; - -- memset(state_array->state, 0, -- (state_array->size)*sizeof(struct pcmcia_state)); -- - levels=GPLR; - - state_array->state[1].detect=((levels & GPIO_CF_CD)==0)?1:0; -diff -urN linux-2.4.26/drivers/pcmcia/sa1100_stork.c linux-2.4.26-vrs1/drivers/pcmcia/sa1100_stork.c ---- linux-2.4.26/drivers/pcmcia/sa1100_stork.c 2004-02-27 20:03:27.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/pcmcia/sa1100_stork.c 2004-02-23 13:36:32.000000000 +0000 -@@ -79,9 +79,6 @@ - - if(state_array->size<2) return -1; - -- memset(state_array->state, 0, -- (state_array->size)*sizeof(struct pcmcia_state)); -- - levels=GPLR; - - if (debug > 1) -diff -urN linux-2.4.26/drivers/pcmcia/sa1100_yopy.c linux-2.4.26-vrs1/drivers/pcmcia/sa1100_yopy.c ---- linux-2.4.26/drivers/pcmcia/sa1100_yopy.c 2002-08-03 01:39:44.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pcmcia/sa1100_yopy.c 2004-01-14 21:32:26.000000000 +0000 -@@ -73,9 +73,6 @@ - if (state_array->size != 1) - return -1; - -- memset(state_array->state, 0, -- state_array->size * sizeof(struct pcmcia_state)); -- - levels = GPLR; - - state_array->state[0].detect = (levels & GPIO_CF_CD) ? 0 : 1; -diff -urN linux-2.4.26/drivers/pld/Makefile linux-2.4.26-vrs1/drivers/pld/Makefile ---- linux-2.4.26/drivers/pld/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pld/Makefile 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,28 @@ -+# -+# Makefile for the kernel pld device drivers. -+# -+# Note! Dependencies are done automagically by 'make dep', which also -+# removes any old dependencies. DON'T put your own dependencies here -+# unless it's something special (ie not a .c file). -+# -+# Note 2! The CFLAGS definitions are now inherited from the -+# parent makes.. -+# -+# $Id: $ -+# -+ -+O_TARGET := pld.o -+ -+export-objs := pld_hotswap.o -+obj-y := -+obj-m := -+obj-n := -+obj- := -+ -+obj-$(CONFIG_PLD) += pld_epxa.o -+obj-$(CONFIG_PLD_HOTSWAP) += pld_hotswap.o -+ -+include $(TOPDIR)/Rules.make -+ -+fastdep: -+ -diff -urN linux-2.4.26/drivers/pld/pld_epxa.c linux-2.4.26-vrs1/drivers/pld/pld_epxa.c ---- linux-2.4.26/drivers/pld/pld_epxa.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pld/pld_epxa.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,375 @@ -+ -+/* -+ * drivers/char/epxapld.c -+ * -+ * Copyright (C) 2001 Altera Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#define PLD_CONF00_TYPE (volatile unsigned int *) -+#define MODE_CTRL00_TYPE (volatile unsigned int *) -+//#define DEBUG(x) x -+#define DEBUG(x) -+ -+#include -+#include -+#ifdef CONFIG_PLD_HOTSWAP -+#include -+#endif -+#include -+ -+/* -+ * Macros -+ */ -+ -+ -+#define PLD_BASE (IO_ADDRESS(EXC_PLD_CONFIG00_BASE)) -+#define CLOCK_DIV_RATIO ((1 + EXC_AHB2_CLK_FREQUENCY/32000000) & CONFIG_CONTROL_CLOCK_RATIO_MSK) -+/* -+ * STRUCTURES -+ */ -+ -+ -+struct pld_sbihdr{ -+ unsigned int fpos; -+ unsigned int temp; -+}; -+ -+static DECLARE_MUTEX(pld_sem); -+ -+ -+static void lock_pld (void) -+{ -+ /* Lock the pld i/f */ -+ unsigned int tmp; -+ -+ tmp = readl(CONFIG_CONTROL(PLD_BASE)); -+ tmp |= CONFIG_CONTROL_LK_MSK; -+ -+ writel(tmp,CONFIG_CONTROL(PLD_BASE)); -+} -+ -+static void unlock_excalibur_pld (void) -+{ -+ /* Unlock the pld i/f */ -+ -+ if (readl(CONFIG_CONTROL(PLD_BASE)) & CONFIG_CONTROL_LK_MSK ){ -+ writel(CONFIG_UNLOCK_MAGIC, CONFIG_UNLOCK(PLD_BASE)); -+ while (readl(CONFIG_CONTROL(PLD_BASE)) & CONFIG_CONTROL_LK_MSK); -+ } -+} -+ -+ -+static int place_pld_into_configure_mode (void) -+{ -+ unsigned int tmp; -+ -+ -+ if( readl(CONFIG_CONTROL(PLD_BASE)) & CONFIG_CONTROL_CO_MSK ){ -+ /* -+ * Already being configured!!! -+ */ -+ printk(KERN_WARNING "pld0: Device already being configured!\n"); -+ return -EBUSY; -+ } -+ -+ /* Set up the config clock */ -+ -+ writel(CLOCK_DIV_RATIO,CONFIG_CONTROL_CLOCK(PLD_BASE)); -+ while(readl(CONFIG_CONTROL_CLOCK(PLD_BASE)) -+ !=CLOCK_DIV_RATIO); -+ /* Tell the device we wish to configure it */ -+ tmp = readl(CONFIG_CONTROL(PLD_BASE)); -+ tmp |= CONFIG_CONTROL_CO_MSK; -+ writel(tmp,CONFIG_CONTROL(PLD_BASE)); -+ -+ -+ /* -+ * Wait for the busy bit to clear then check for errors. -+ */ -+ -+ while((tmp=readl(CONFIG_CONTROL(PLD_BASE))&CONFIG_CONTROL_B_MSK )); -+ -+ if ( tmp & CONFIG_CONTROL_E_MSK ){ -+ if ( tmp & CONFIG_CONTROL_ES_0_MSK ){ -+ /* Already being programmed via JTAG */ -+ printk(KERN_WARNING "pld0:JTAG configuration alreay in progress\n"); -+ return -EBUSY; -+ -+ } -+ if ( tmp & CONFIG_CONTROL_ES_1_MSK ){ -+ /* No config clock configured */ -+ printk(KERN_ERR "pld0:No config clock!\n"); -+ BUG(); -+ return -EBUSY; -+ } -+ if ( tmp & CONFIG_CONTROL_ES_2_MSK ){ -+ /* Already being programmed via External device */ -+ printk(KERN_WARNING "pld0:JTAG configuration alreay in progress\n"); -+ return -EBUSY; -+ } -+ } -+ -+ return 0; -+} -+ -+ -+static int write_pld_data_word(unsigned int config_data) -+{ -+ unsigned int tmp; -+ -+ do{ -+ tmp = readl(CONFIG_CONTROL(PLD_BASE)); -+ } -+ while ( ( tmp & CONFIG_CONTROL_B_MSK ) && -+ !( tmp & CONFIG_CONTROL_E_MSK )); -+ -+ if ( tmp & CONFIG_CONTROL_E_MSK ){ -+ printk("pld0: Error writing pld data, CONFIG_CONTROL=%#x\n",tmp); -+ -+ return -EILSEQ; -+ } -+ -+ writel(config_data,CONFIG_CONTROL_DATA(PLD_BASE)); -+ return 0; -+ -+} -+ -+ -+static int wait_for_device_to_configure (void) -+{ -+ int i=0x10000; -+ -+ while(readl(CONFIG_CONTROL(PLD_BASE)) & CONFIG_CONTROL_B_MSK); -+ -+ /* -+ * Wait for the config bit (CO) to go low, indicating that everything -+ * is Ok. If it doesn't, assume that is screwed up somehow and -+ * clear the CO bit to abort the configuration. -+ */ -+ -+ while(readl(CONFIG_CONTROL(PLD_BASE)) & CONFIG_CONTROL_B_MSK); -+ -+ while (i&&(readl(CONFIG_CONTROL(PLD_BASE)) & CONFIG_CONTROL_CO_MSK)){ -+ i--; -+ } -+ -+ if (!i){ -+ writel(0,CONFIG_CONTROL(PLD_BASE)); -+ printk(KERN_WARNING "pld0: Invalid PLD config data\n"); -+ return -EILSEQ; -+ } -+ -+ return 0; -+} -+ -+ -+ -+static int pld_open(struct inode* inode, struct file *filep) -+{ -+ -+ struct pld_sbihdr* sbihdr; -+ -+ /* Check the device minor number */ -+ if(minor(inode->i_rdev)){ -+ DEBUG(printk("pld0: minor=%d",minor(inode->i_rdev));) -+ return -ENODEV; -+ } -+ -+ /* Create our private data and link it to the file structure */ -+ sbihdr=kmalloc(sizeof(struct pld_sbihdr),GFP_KERNEL); -+ -+ if(!sbihdr) -+ return -ENOMEM; -+ -+ filep->private_data=sbihdr; -+ -+ sbihdr->fpos=0; -+ sbihdr->temp=0; -+ return 0; -+} -+ -+static int pld_release(struct inode* inode, struct file *filep){ -+ int ret_code; -+ -+ kfree(filep->private_data); -+ ret_code=wait_for_device_to_configure(); -+ lock_pld(); -+ return ret_code; -+} -+ -+static ssize_t pld_write(struct file* filep, const char* data, size_t count, loff_t* ppos){ -+ -+ struct pld_sbihdr* sbihdr=filep->private_data; -+ int bytes_left=count; -+ int result; -+ DEBUG(int i=0); -+ -+ -+ /* Can't seek (pwrite) on pld. */ -+ if (ppos != &filep->f_pos) -+ return -ESPIPE; -+ -+ -+ /* Check access to the whole are in one go */ -+ if(!access_ok(VERIFY_READ,(const void*)data, count)){ -+ return -EFAULT; -+ } -+ -+ /* -+ * We now lock against writes. -+ */ -+ if (down_interruptible(&pld_sem)) -+ return -ERESTARTSYS; -+ -+ if(!sbihdr->fpos){ -+ /* -+ * unlock the pld and place in configure mode -+ */ -+ unlock_excalibur_pld(); -+ result=place_pld_into_configure_mode(); -+ if(result) -+ return result; -+ } -+ DEBUG(printk("data= %#x count=%#x 0ffset=%#x\n",*data, count, *ppos)); -+ -+ while(bytes_left){ -+ char tmp; -+ __get_user(tmp,data); -+ /* read our header ! */ -+ sbihdr->temp|=tmp << (8*(sbihdr->fpos&3)); -+ if((sbihdr->fpos&3)==3){ -+ if(write_pld_data_word(sbihdr->temp)) -+ { -+ DEBUG(printk("pos=%d\n",sbihdr->fpos);) -+ return -EILSEQ; -+ } -+ DEBUG(if(i<10){) -+ DEBUG(printk("fpos2 :%#x data=%#x\n",sbihdr->fpos,sbihdr->temp)); -+ DEBUG(i++); -+ DEBUG(}); -+ sbihdr->temp=0; -+ DEBUG(words_written++); -+ } -+ sbihdr->fpos++; -+ data++; -+ bytes_left--; -+ } -+ -+ up(&pld_sem); -+ return (count); -+} -+ -+int pld_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg) -+{ -+ -+ switch(cmd){ -+ -+#ifdef CONFIG_PLD_HOTSWAP -+ case PLD_IOC_ADD_PLD_DEV: -+ { -+ struct pldhs_dev_desc desc; -+ struct pldhs_dev_info info; -+ char *name; -+ void *data; -+ int result=0; -+ -+ result=copy_from_user(&desc,(const void*)arg,sizeof(struct pldhs_dev_desc)); -+ if(result) -+ return -EFAULT; -+ result=copy_from_user(&info,(const void*)desc.info,sizeof(struct pldhs_dev_info)); -+ if(result) -+ return -EFAULT; -+ name=kmalloc(info.nsize,GFP_KERNEL); -+ if(!name) -+ return -ENOMEM; -+ -+ result=copy_from_user(name,(const void*)desc.name,info.nsize); -+ if(result){ -+ result=-EFAULT; -+ goto ioctl_out; -+ } -+ -+ data=kmalloc(info.pssize,GFP_KERNEL); -+ if(!data){ -+ result=-ENOMEM; -+ goto ioctl_out; -+ } -+ -+ result=copy_from_user(data,(const void*)desc.data,info.pssize); -+ if(result){ -+ result=-EFAULT; -+ goto ioctl_out1; -+ } -+ result=pldhs_add_device(&info,name,data); -+ -+ ioctl_out1: -+ kfree(data); -+ ioctl_out: -+ kfree(name); -+ return result; -+ -+ } -+ -+ case PLD_IOC_REMOVE_PLD_DEVS: -+ pldhs_remove_devices(); -+ return 0; -+ -+ case PLD_IOC_SET_INT_MODE: -+ if(cmd==3){ -+ printk(KERN_INFO "Interrupt mode set to 3 (Six individual interrupts)\n"); -+ return 0; -+ }else{ -+ printk(KERN_INFO "There is no interrupt handler available for this mode (%d). You will need to add one\n to implement whatever scheme you require\n"); -+ return -EACCES; -+ } -+#endif -+ default: -+ return -ENOTTY; -+ } -+} -+ -+ -+static struct file_operations pld_fops={ -+ write: pld_write, -+ ioctl: pld_ioctl, -+ open: pld_open, -+ release: pld_release -+}; -+ -+static int __init pld_init(void){ -+ int major; -+ major=register_chrdev(0,"pld",&pld_fops); -+ printk(KERN_INFO "Using PLD major num=%d\n",major); -+ if (major<0){ -+ return major; -+ } -+ return 0; -+} -+ -+__initcall(pld_init); -diff -urN linux-2.4.26/drivers/pld/pld_hotswap.c linux-2.4.26-vrs1/drivers/pld/pld_hotswap.c ---- linux-2.4.26/drivers/pld/pld_hotswap.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/pld/pld_hotswap.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,188 @@ -+/* -+ * linux/drivers/pld/pld_hotswap.c -+ * -+ * Pld driver for Altera EPXA Excalibur devices -+ * -+ * -+ * Copyright 2001 Altera Corporation (cdavies@altera.com) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * $Id: $ -+ * -+ */ -+ -+/* -+ * pld_hotswap ops contains the basic operation required for adding -+ * and removing devices from the system. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+static struct pld_hotswap_ops pldhs_driver_list={ -+ list: LIST_HEAD_INIT(pldhs_driver_list.list), -+ name: "", -+}; -+ -+static spinlock_t list_lock=SPIN_LOCK_UNLOCKED; -+ -+ -+ -+static struct pld_hotswap_ops * pldhs_find_driver(char* name) -+{ -+ struct pld_hotswap_ops * ptr; -+ struct list_head *list_pos; -+ -+ spin_lock(&list_lock); -+ list_for_each(list_pos,&pldhs_driver_list.list){ -+ ptr=(struct pld_hotswap_ops *)list_pos; -+ if(!strcmp(name, ptr->name)){ -+ spin_unlock(&list_lock); -+ return ptr; -+ -+ } -+ } -+ spin_unlock(&list_lock); -+ return 0; -+} -+ -+ -+ -+int pldhs_register_driver(struct pld_hotswap_ops *drv) -+{ -+ -+ /* Check that the device is not already on the list -+ * if so, do nothing */ -+ if(pldhs_find_driver(drv->name)){ -+ return 0; -+ } -+ -+ printk(KERN_INFO "PLD: Registering hotswap driver %s\n",drv->name); -+ /* Add this at the start of the list */ -+ spin_lock(&list_lock); -+ list_add((struct list_head*)drv,&pldhs_driver_list.list); -+ spin_unlock(&list_lock); -+ -+ return 0; -+} -+ -+int pldhs_unregister_driver(char *name) -+{ -+ struct pld_hotswap_ops *ptr; -+ -+ ptr=pldhs_find_driver(name); -+ if(!ptr){ -+ return -ENODEV; -+ } -+ -+ printk(KERN_INFO "PLD: Unregistering hotswap driver%s\n",name); -+ spin_lock(&list_lock); -+ list_del((struct list_head*)ptr); -+ spin_unlock(&list_lock); -+ -+ return 0; -+} -+ -+int pldhs_add_device(struct pldhs_dev_info* dev_info,char *drv_name, void* dev_ps_data) -+{ -+ struct pld_hotswap_ops * ptr; -+ -+ ptr=pldhs_find_driver(drv_name); -+ -+ if(!ptr){ -+ /* try requesting this module*/ -+ request_module(drv_name); -+ /* is the driver there now? */ -+ ptr=pldhs_find_driver(drv_name); -+ if(!ptr){ -+ printk("pld hotswap: Failed to load a driver for %s\n",drv_name); -+ return -ENODEV; -+ } -+ } -+ -+ if(!ptr->add_device){ -+ printk(KERN_WARNING "pldhs: no add_device() function for driver %s\n",drv_name); -+ return 0; -+ } -+ -+ return ptr->add_device(dev_info,dev_ps_data); -+} -+ -+int pldhs_remove_devices(void) -+{ -+ struct list_head *list_pos; -+ struct pld_hotswap_ops * ptr; -+ -+ -+ spin_lock(&list_lock); -+ list_for_each(list_pos,&pldhs_driver_list.list){ -+ ptr=(struct pld_hotswap_ops *)list_pos; -+ if(ptr->remove_devices) -+ ptr->remove_devices(); -+ -+ } -+ spin_unlock(&list_lock); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PROC_FS -+int pldhs_read_proc(char* buf,char** start,off_t offset,int count,int *eof,void *data){ -+ -+ -+ struct list_head *list_pos; -+ struct pld_hotswap_ops * ptr; -+ int i,len=0; -+ -+ *start=buf; -+ spin_lock(&list_lock); -+ list_for_each(list_pos,&pldhs_driver_list.list){ -+ ptr=(struct pld_hotswap_ops *)list_pos; -+ if(ptr->proc_read){ -+ i=ptr->proc_read(buf,start,offset,count,eof,data); -+ count-=i; -+ len+=i; -+ *start+=i; -+ } -+ } -+ spin_unlock(&list_lock); -+ -+ *start=NULL; -+ *eof=1; -+ return len; -+} -+ -+void __init pldhs_init(void){ -+ create_proc_read_entry("pld",0,NULL,pldhs_read_proc,NULL); -+} -+ -+__initcall(pldhs_init); -+#endif -+ -+EXPORT_SYMBOL(pldhs_register_driver); -+EXPORT_SYMBOL(pldhs_unregister_driver); -diff -urN linux-2.4.26/drivers/scsi/Makefile linux-2.4.26-vrs1/drivers/scsi/Makefile ---- linux-2.4.26/drivers/scsi/Makefile 2004-02-27 20:03:27.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/scsi/Makefile 2004-02-23 13:36:33.000000000 +0000 -@@ -21,7 +21,7 @@ - - O_TARGET := scsidrv.o - --export-objs := scsi_syms.o 53c700.o -+export-objs := scsi_syms.o 53c700.o scsi_error.o - mod-subdirs := pcmcia ../acorn/scsi - - -diff -urN linux-2.4.26/drivers/scsi/scsi.c linux-2.4.26-vrs1/drivers/scsi/scsi.c ---- linux-2.4.26/drivers/scsi/scsi.c 2003-08-25 12:44:42.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/scsi/scsi.c 2004-01-14 21:39:12.000000000 +0000 -@@ -1334,14 +1334,10 @@ - */ - int scsi_retry_command(Scsi_Cmnd * SCpnt) - { -- memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd, -- sizeof(SCpnt->data_cmnd)); -- SCpnt->request_buffer = SCpnt->buffer; -- SCpnt->request_bufflen = SCpnt->bufflen; -- SCpnt->use_sg = SCpnt->old_use_sg; -- SCpnt->cmd_len = SCpnt->old_cmd_len; -- SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; -- SCpnt->underflow = SCpnt->old_underflow; -+ /* -+ * Restore the SCSI command state. -+ */ -+ scsi_setup_cmd_retry(SCpnt); - - /* - * Zero the sense information from the last time we tried -diff -urN linux-2.4.26/drivers/scsi/scsi.h linux-2.4.26-vrs1/drivers/scsi/scsi.h ---- linux-2.4.26/drivers/scsi/scsi.h 2003-08-25 12:44:42.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/scsi/scsi.h 2004-04-19 18:46:03.000000000 +0100 -@@ -465,6 +465,7 @@ - int sectors); - extern struct Scsi_Device_Template *scsi_get_request_dev(struct request *); - extern int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt); -+extern void scsi_setup_cmd_retry(Scsi_Cmnd *SCpnt); - extern int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int); - extern void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, - int block_sectors); -@@ -588,6 +589,7 @@ - unsigned changed:1; /* Data invalid due to media change */ - unsigned busy:1; /* Used to prevent races */ - unsigned lockable:1; /* Able to prevent media removal */ -+ unsigned locked:1; /* Media removal disabled */ - unsigned borken:1; /* Tell the Seagate driver to be - * painfully slow on this device */ - unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */ -diff -urN linux-2.4.26/drivers/scsi/scsi_dma.c linux-2.4.26-vrs1/drivers/scsi/scsi_dma.c ---- linux-2.4.26/drivers/scsi/scsi_dma.c 2002-02-25 19:38:04.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/scsi/scsi_dma.c 2004-01-14 21:32:26.000000000 +0000 -@@ -30,6 +30,15 @@ - typedef unsigned char FreeSectorBitmap; - #elif SECTORS_PER_PAGE <= 32 - typedef unsigned int FreeSectorBitmap; -+#elif SECTORS_PER_PAGE <= 64 -+#if 0 -+typedef unsigned long long FreeSectorBitmap; -+#else -+typedef struct { -+ unsigned long l,h; -+} FreeSectorBitmap; -+#define LARGE_MALLOC -+#endif - #else - #error You lose. - #endif -@@ -69,6 +78,7 @@ - * to allocate more memory in order to be able to write the - * data to disk, you would wedge the system. - */ -+#ifndef LARGE_MALLOC - void *scsi_malloc(unsigned int len) - { - unsigned int nbits, mask; -@@ -167,6 +177,97 @@ - panic("scsi_free:Bad offset"); - } - -+#else -+ -+void *scsi_malloc(unsigned int len) -+{ -+ unsigned int nbits; -+ unsigned long maskl, maskh, flags; -+ FreeSectorBitmap *fsb; -+ int i; -+ -+ if (len % SECTOR_SIZE != 0 || len > PAGE_SIZE) -+ return NULL; -+ -+ save_flags_cli (flags); -+ nbits = len >> 9; -+ if (nbits < 32) { -+ maskl = (1 << nbits) - 1; -+ maskh = 0; -+ } else { -+ maskl = (unsigned long)-1; -+ maskh = (1 << (nbits - 32)) - 1; -+ } -+ -+ fsb = dma_malloc_freelist; -+ -+ for (i = 0; i < dma_sectors / SECTORS_PER_PAGE; i++) { -+ unsigned long mml, mmh; -+ int j; -+ mml = maskl; -+ mmh = maskh; -+ j = 0; -+ do { -+ if ((fsb->l & mml) == 0 && (fsb->h & mmh) == 0) { -+ fsb->h |= mmh; -+ fsb->l |= mml; -+ restore_flags (flags); -+ scsi_dma_free_sectors -= nbits; -+#ifdef DEBUG -+ printk("SMalloc: %d %p\n",len, dma_malloc_pages[i] + (j << 9)); -+#endif -+ return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9)); -+ } -+ mmh = (mmh << 1) | (mml >> 31); -+ mml <<= 1; -+ j++; -+ } while (!(mmh & (1 << 31))); -+ fsb ++; -+ } -+ return NULL; /* Nope. No more */ -+} -+ -+int scsi_free(void *obj, unsigned int len) -+{ -+ unsigned int page, sector, nbits; -+ unsigned long maskl, maskh, flags; -+ -+#ifdef DEBUG -+ printk("scsi_free %p %d\n",obj, len); -+#endif -+ -+ for (page = 0; page < dma_sectors / SECTORS_PER_PAGE; page++) { -+ unsigned long page_addr = (unsigned long) dma_malloc_pages[page]; -+ if ((unsigned long) obj >= page_addr && -+ (unsigned long) obj < page_addr + PAGE_SIZE) { -+ sector = (((unsigned long) obj) - page_addr) >> 9; -+ nbits = len >> 9; -+ if (nbits < 32) { -+ maskl = (1 << nbits) - 1; -+ maskh = 0; -+ } else { -+ maskl = (unsigned long)-1; -+ maskh = (1 << (nbits - 32)) - 1; -+ } -+ if ((sector + nbits) > SECTORS_PER_PAGE) -+ panic ("scsi_free:Bad memory alignment"); -+ maskh = (maskh << sector) | (maskl >> (32 - sector)); -+ maskl = maskl << sector; -+ save_flags_cli(flags); -+ if (((dma_malloc_freelist[page].l & maskl) != maskl) || -+ ((dma_malloc_freelist[page].h & maskh) != maskh)) -+ panic("scsi_free:Trying to free unused memory"); -+ scsi_dma_free_sectors += nbits; -+ dma_malloc_freelist[page].l &= ~maskl; -+ dma_malloc_freelist[page].h &= ~maskh; -+ restore_flags(flags); -+ return 0; -+ } -+ } -+ panic("scsi_free:Bad offset"); -+} -+#endif -+ - - /* - * Function: scsi_resize_dma_pool -diff -urN linux-2.4.26/drivers/scsi/scsi_error.c linux-2.4.26-vrs1/drivers/scsi/scsi_error.c ---- linux-2.4.26/drivers/scsi/scsi_error.c 2004-04-19 11:44:16.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/scsi/scsi_error.c 2004-04-18 21:47:51.000000000 +0100 -@@ -35,6 +35,8 @@ - #include "hosts.h" - #include "constants.h" - -+#include /* grr */ -+ - /* - * We must always allow SHUTDOWN_SIGS. Even if we are not a module, - * the host drivers that we are using may be loaded as modules, and -@@ -49,6 +51,13 @@ - */ - #define SHUTDOWN_SIGS (sigmask(SIGHUP)) - -+/* -+ * The number of times we retry a REQUEST SENSE and TEST UNIT READY -+ * respectively. This is arbitary. -+ */ -+#define SENSE_RETRIES 5 -+#define TUR_RETRIES 5 -+ - #ifdef DEBUG - #define SENSE_TIMEOUT SCSI_TIMEOUT - #define ABORT_TIMEOUT SCSI_TIMEOUT -@@ -373,16 +382,12 @@ - */ - STATIC int scsi_eh_retry_command(Scsi_Cmnd * SCpnt) - { -- memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd, -- sizeof(SCpnt->data_cmnd)); -- SCpnt->request_buffer = SCpnt->buffer; -- SCpnt->request_bufflen = SCpnt->bufflen; -- SCpnt->use_sg = SCpnt->old_use_sg; -- SCpnt->cmd_len = SCpnt->old_cmd_len; -- SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; -- SCpnt->underflow = SCpnt->old_underflow; -+ int tries = 0; - -- scsi_send_eh_cmnd(SCpnt, SCpnt->timeout_per_command); -+ do { -+ scsi_setup_cmd_retry(SCpnt); -+ scsi_send_eh_cmnd(SCpnt, SCpnt->timeout_per_command); -+ } while (SCpnt->eh_state == NEEDS_RETRY && tries++ < SCpnt->allowed); - - /* - * Hey, we are done. Let's look to see what happened. -@@ -409,16 +414,10 @@ - static unsigned char generic_sense[6] = - {REQUEST_SENSE, 0, 0, 0, 255, 0}; - unsigned char scsi_result0[256], *scsi_result = NULL; -- int saved_result; -+ int saved_result, tries; - - ASSERT_LOCK(&io_request_lock, 0); - -- memcpy((void *) SCpnt->cmnd, (void *) generic_sense, -- sizeof(generic_sense)); -- -- if (SCpnt->device->scsi_level <= SCSI_2) -- SCpnt->cmnd[1] = SCpnt->lun << 5; -- - scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma) - ? &scsi_result0[0] : kmalloc(512, GFP_ATOMIC | GFP_DMA); - -@@ -426,24 +425,41 @@ - printk("cannot allocate scsi_result in scsi_request_sense.\n"); - return FAILED; - } -- /* -- * Zero the sense buffer. Some host adapters automatically always request -- * sense, so it is not a good idea that SCpnt->request_buffer and -- * SCpnt->sense_buffer point to the same address (DB). -- * 0 is not a valid sense code. -- */ -- memset((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); -- memset((void *) scsi_result, 0, 256); - - saved_result = SCpnt->result; -- SCpnt->request_buffer = scsi_result; -- SCpnt->request_bufflen = 256; -- SCpnt->use_sg = 0; -- SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); -- SCpnt->sc_data_direction = SCSI_DATA_READ; -- SCpnt->underflow = 0; - -- scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT); -+ tries = 0; -+ do { -+ memcpy((void *) SCpnt->cmnd, (void *) generic_sense, -+ sizeof(generic_sense)); -+ -+ if (SCpnt->device->scsi_level <= SCSI_2) -+ SCpnt->cmnd[1] = SCpnt->lun << 5; -+ -+ /* -+ * Zero the sense buffer. Some host adapters automatically -+ * always request sense, so it is not a good idea that -+ * SCpnt->request_buffer and SCpnt->sense_buffer point to -+ * the same address (DB). 0 is not a valid sense code. -+ */ -+ memset((void *) SCpnt->sense_buffer, 0, -+ sizeof(SCpnt->sense_buffer)); -+ memset((void *) scsi_result, 0, 256); -+ -+ SCpnt->request_buffer = scsi_result; -+ SCpnt->request_bufflen = 256; -+ SCpnt->use_sg = 0; -+ SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); -+ SCpnt->sc_data_direction = SCSI_DATA_READ; -+ SCpnt->underflow = 0; -+ -+ scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT); -+ /* -+ * If the SCSI device responded with "logical unit -+ * is in process of becoming ready", we need to -+ * retry this command. -+ */ -+ } while (SCpnt->eh_state == NEEDS_RETRY && tries++ < SENSE_RETRIES); - - /* Last chance to have valid sense data */ - if (!scsi_sense_valid(SCpnt)) -@@ -458,15 +474,8 @@ - * When we eventually call scsi_finish, we really wish to complete - * the original request, so let's restore the original data. (DB) - */ -- memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd, -- sizeof(SCpnt->data_cmnd)); - SCpnt->result = saved_result; -- SCpnt->request_buffer = SCpnt->buffer; -- SCpnt->request_bufflen = SCpnt->bufflen; -- SCpnt->use_sg = SCpnt->old_use_sg; -- SCpnt->cmd_len = SCpnt->old_cmd_len; -- SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; -- SCpnt->underflow = SCpnt->old_underflow; -+ scsi_setup_cmd_retry(SCpnt); - - /* - * Hey, we are done. Let's look to see what happened. -@@ -484,40 +493,42 @@ - { - static unsigned char tur_command[6] = - {TEST_UNIT_READY, 0, 0, 0, 0, 0}; -+ int tries = 0; - -- memcpy((void *) SCpnt->cmnd, (void *) tur_command, -- sizeof(tur_command)); -+ do { -+ memcpy((void *) SCpnt->cmnd, (void *) tur_command, -+ sizeof(tur_command)); - -- if (SCpnt->device->scsi_level <= SCSI_2) -- SCpnt->cmnd[1] = SCpnt->lun << 5; -+ if (SCpnt->device->scsi_level <= SCSI_2) -+ SCpnt->cmnd[1] = SCpnt->lun << 5; - -- /* -- * Zero the sense buffer. The SCSI spec mandates that any -- * untransferred sense data should be interpreted as being zero. -- */ -- memset((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); -+ /* -+ * Zero the sense buffer. The SCSI spec mandates that any -+ * untransferred sense data should be interpreted as being zero. -+ */ -+ memset((void *) SCpnt->sense_buffer, 0, -+ sizeof(SCpnt->sense_buffer)); - -- SCpnt->request_buffer = NULL; -- SCpnt->request_bufflen = 0; -- SCpnt->use_sg = 0; -- SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); -- SCpnt->underflow = 0; -- SCpnt->sc_data_direction = SCSI_DATA_NONE; -+ SCpnt->request_buffer = NULL; -+ SCpnt->request_bufflen = 0; -+ SCpnt->use_sg = 0; -+ SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); -+ SCpnt->underflow = 0; -+ SCpnt->sc_data_direction = SCSI_DATA_NONE; - -- scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT); -+ scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT); -+ /* -+ * If the SCSI device responded with "logical unit -+ * is in process of becoming ready", we need to -+ * retry this command. -+ */ -+ } while (SCpnt->eh_state == NEEDS_RETRY && tries++ < TUR_RETRIES); - - /* - * When we eventually call scsi_finish, we really wish to complete - * the original request, so let's restore the original data. (DB) - */ -- memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd, -- sizeof(SCpnt->data_cmnd)); -- SCpnt->request_buffer = SCpnt->buffer; -- SCpnt->request_bufflen = SCpnt->bufflen; -- SCpnt->use_sg = SCpnt->old_use_sg; -- SCpnt->cmd_len = SCpnt->old_cmd_len; -- SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; -- SCpnt->underflow = SCpnt->old_underflow; -+ scsi_setup_cmd_retry(SCpnt); - - /* - * Hey, we are done. Let's look to see what happened. -@@ -577,7 +588,6 @@ - - host = SCpnt->host; - -- retry: - /* - * We will use a queued command if possible, otherwise we will emulate the - * queuing and calling of completion function ourselves. -@@ -660,14 +670,13 @@ - SCSI_LOG_ERROR_RECOVERY(3, - printk("scsi_send_eh_cmnd: scsi_eh_completed_normally %x\n", ret)); - switch (ret) { -- case SUCCESS: -- SCpnt->eh_state = SUCCESS; -- break; -- case NEEDS_RETRY: -- goto retry; -- case FAILED: - default: -- SCpnt->eh_state = FAILED; -+ ret = FAILED; -+ /*FALLTHROUGH*/ -+ case FAILED: -+ case NEEDS_RETRY: -+ case SUCCESS: -+ SCpnt->eh_state = ret; - break; - } - } else { -@@ -1208,6 +1217,82 @@ - - - /* -+ * Function: scsi_eh_lock_done -+ * -+ * Purpose: free the command and request structures associated -+ * with the error handlers door lock request -+ * -+ * Arguments: SCpnt - the SCSI command block for the door lock request. -+ * -+ * Returns: Nothing -+ * -+ * Notes: We completed the asynchronous door lock request, and -+ * it has either locked the door or failed. We must free -+ * the command structures associated with this request. -+ */ -+static void scsi_eh_lock_done(struct scsi_cmnd *SCpnt) -+{ -+ struct scsi_request *SRpnt = SCpnt->sc_request; -+ -+ SCpnt->sc_request = NULL; -+ SRpnt->sr_command = NULL; -+ -+ scsi_release_command(SCpnt); -+ scsi_release_request(SRpnt); -+} -+ -+ -+/* -+ * Function: scsi_eh_lock_door -+ * -+ * Purpose: Prevent medium removal for the specified device -+ * -+ * Arguments: dev - SCSI device to prevent medium removal -+ * -+ * Locking: We must be called from process context; -+ * scsi_allocate_request() may sleep. -+ * -+ * Returns: Nothing -+ * -+ * Notes: We queue up an asynchronous "ALLOW MEDIUM REMOVAL" request -+ * on the head of the devices request queue, and continue. -+ * -+ * Bugs: scsi_allocate_request() may sleep waiting for existing -+ * requests to be processed. However, since we haven't -+ * kicked off any request processing for this host, this -+ * may deadlock. -+ * -+ * If scsi_allocate_request() fails for what ever reason, -+ * we completely forget to lock the door. -+ */ -+STATIC void scsi_eh_lock_door(struct scsi_device *dev) -+{ -+ struct scsi_request *SRpnt = scsi_allocate_request(dev); -+ -+ if (SRpnt == NULL) { -+ /* what now? */ -+ return; -+ } -+ -+ SRpnt->sr_cmnd[0] = ALLOW_MEDIUM_REMOVAL; -+ SRpnt->sr_cmnd[1] = (dev->scsi_level <= SCSI_2) ? (dev->lun << 5) : 0; -+ SRpnt->sr_cmnd[2] = 0; -+ SRpnt->sr_cmnd[3] = 0; -+ SRpnt->sr_cmnd[4] = SCSI_REMOVAL_PREVENT; -+ SRpnt->sr_cmnd[5] = 0; -+ SRpnt->sr_data_direction = SCSI_DATA_NONE; -+ SRpnt->sr_bufflen = 0; -+ SRpnt->sr_buffer = NULL; -+ SRpnt->sr_allowed = 5; -+ SRpnt->sr_done = scsi_eh_lock_done; -+ SRpnt->sr_timeout_per_command = 10 * HZ; -+ SRpnt->sr_cmd_len = COMMAND_SIZE(SRpnt->sr_cmnd[0]); -+ -+ scsi_insert_special_req(SRpnt, 1); -+} -+ -+ -+/* - * Function: scsi_restart_operations - * - * Purpose: Restart IO operations to the specified host. -@@ -1229,6 +1314,15 @@ - ASSERT_LOCK(&io_request_lock, 0); - - /* -+ * If the door was locked, we need to insert a door lock request -+ * onto the head of the SCSI request queue for the device. There -+ * is no point trying to lock the door of an off-line device. -+ */ -+ for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) -+ if (SDpnt->online && SDpnt->locked) -+ scsi_eh_lock_door(SDpnt); -+ -+ /* - * Next free up anything directly waiting upon the host. This will be - * requests for character device operations, and also for ioctls to queued - * block devices. -@@ -1248,8 +1342,7 @@ - request_queue_t *q; - if ((host->can_queue > 0 && (host->host_busy >= host->can_queue)) - || (host->host_blocked) -- || (host->host_self_blocked) -- || (SDpnt->device_blocked)) { -+ || (host->host_self_blocked)) { - break; - } - q = &SDpnt->request_queue; -@@ -1259,136 +1352,202 @@ - } - - /* -- * Function: scsi_unjam_host -+ * Function: scsi_eh_find_failed_command - * -- * Purpose: Attempt to fix a host which has a command that failed for -- * some reason. -+ * Purpose: Find a failed Scsi_Cmnd structure on a device. - * -- * Arguments: host - host that needs unjamming. -- * -- * Returns: Nothing -+ * Arguments: SDpnt - Scsi_Device structure - * -- * Notes: When we come in here, we *know* that all commands on the -- * bus have either completed, failed or timed out. We also -- * know that no further commands are being sent to the host, -- * so things are relatively quiet and we have freedom to -- * fiddle with things as we wish. -+ * Returns: Pointer to Scsi_Cmnd structure, or NULL on failure -+ */ -+STATIC Scsi_Cmnd *scsi_eh_find_failed_command(Scsi_Device *SDpnt) -+{ -+ Scsi_Cmnd *SCpnt; -+ -+ for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) -+ if (SCpnt->state == SCSI_STATE_FAILED || -+ SCpnt->state == SCSI_STATE_TIMEOUT) -+ return SCpnt; -+ -+ return NULL; -+} -+ -+ -+/* -+ * Function: scsi_eh_test_and_retry - * -- * Additional note: This is only the *default* implementation. It is possible -- * for individual drivers to supply their own version of this -- * function, and if the maintainer wishes to do this, it is -- * strongly suggested that this function be taken as a template -- * and modified. This function was designed to correctly handle -- * problems for about 95% of the different cases out there, and -- * it should always provide at least a reasonable amount of error -- * recovery. -+ * Purpose: Try to retry a failed command. - * -- * Note3: Any command marked 'FAILED' or 'TIMEOUT' must eventually -- * have scsi_finish_command() called for it. We do all of -- * the retry stuff here, so when we restart the host after we -- * return it should have an empty queue. -+ * Arguments: SCpnt - scsi command structure -+ * done - list of commands that have been successfully -+ * completed. -+ * -+ * Returns: SUCCESS or FAILED -+ * -+ * Note: If the TEST UNIT READY command successfully executes, -+ * but returns some form of "device not ready", we wait -+ * a while, and retry 3 times. The device could be still -+ * re-initialising. - */ --STATIC int scsi_unjam_host(struct Scsi_Host *host) -+STATIC int scsi_eh_test_and_retry(Scsi_Cmnd *SCpnt, Scsi_Cmnd **done) - { -- int devices_failed; -- int numfailed; -- int ourrtn; -- int rtn = FALSE; -- int result; -- Scsi_Cmnd *SCloop; -- Scsi_Cmnd *SCpnt; -- Scsi_Device *SDpnt; -- Scsi_Device *SDloop; -- Scsi_Cmnd *SCdone; -- int timed_out; -+ int rtn, tries = 3; - -- ASSERT_LOCK(&io_request_lock, 0); -+ do { -+ rtn = scsi_test_unit_ready(SCpnt); -+ if (rtn != SUCCESS) -+ return rtn; - -- SCdone = NULL; -+ if (scsi_unit_is_ready(SCpnt)) -+ break; -+ -+ if (tries-- == 0) -+ return FAILED; -+ -+ scsi_sleep(5 * HZ); -+ } while (1); -+ -+ rtn = scsi_eh_retry_command(SCpnt); -+ if (rtn == SUCCESS) { -+ SCpnt->host->host_failed--; -+ scsi_eh_finish_command(done, SCpnt); -+ } -+ -+ return rtn; -+} - -- /* -- * First, protect against any sort of race condition. If any of the outstanding -- * commands are in states that indicate that we are not yet blocked (i.e. we are -- * not in a quiet state) then we got woken up in error. If we ever end up here, -- * we need to re-examine some of the assumptions. -- */ -- for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { -- for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) { -- if (SCpnt->state == SCSI_STATE_FAILED -- || SCpnt->state == SCSI_STATE_TIMEOUT -- || SCpnt->state == SCSI_STATE_INITIALIZING -- || SCpnt->state == SCSI_STATE_UNUSED) { -- continue; -- } -- /* -- * Rats. Something is still floating around out there. This could -- * be the result of the fact that the upper level drivers are still frobbing -- * commands that might have succeeded. There are two outcomes. One is that -- * the command block will eventually be freed, and the other one is that -- * the command will be queued and will be finished along the way. -- */ -- SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler prematurely woken - commands still active (%p %x %d)\n", SCpnt, SCpnt->state, SCpnt->target)); - - /* -- * panic("SCSI Error handler woken too early\n"); -+ * Function: scsi_eh_restart_device - * -- * This is no longer a problem, since now the code cares only about -- * SCSI_STATE_TIMEOUT and SCSI_STATE_FAILED. -- * Other states are useful only to release active commands when devices are -- * set offline. If (host->host_active == host->host_busy) we can safely assume -- * that there are no commands in state other then TIMEOUT od FAILED. (DB) -+ * Purpose: Retry all failed or timed out commands for a device - * -- * FIXME: -- * It is not easy to release correctly commands according to their state when -- * devices are set offline, when the state is neither TIMEOUT nor FAILED. -- * When a device is set offline, we can have some command with -- * rq_status=RQ_SCSY_BUSY, owner=SCSI_STATE_HIGHLEVEL, -- * state=SCSI_STATE_INITIALIZING and the driver module cannot be released. -- * (DB, 17 May 1998) -+ * Arguments: SDpnt - SCSI device to retry -+ * done - list of commands that have been successfully -+ * completed. -+ * -+ * Returns: SUCCESS or failure code -+ */ -+STATIC int scsi_eh_restart_device(Scsi_Device *SDpnt, Scsi_Cmnd **done) -+{ -+ Scsi_Cmnd *SCpnt, *SCnext; -+ int rtn = SUCCESS; -+ -+ for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCnext) { -+ SCnext = SCpnt->next; -+ -+ if (SCpnt->state == SCSI_STATE_FAILED || -+ SCpnt->state == SCSI_STATE_TIMEOUT) { -+ rtn = scsi_eh_test_and_retry(SCpnt, done); -+ if (rtn != SUCCESS) -+ break; -+ } -+ } -+ -+ return rtn; -+} -+ -+/* -+ * Function: scsi_eh_set_device_offline -+ * -+ * Purpose: set a device off line -+ * -+ * Arguments: SDpnt - SCSI device to take off line -+ * done - list of commands that have been successfully -+ * completed. -+ * reason - text string describing why the device is off-line -+ * -+ * Returns: Nothing -+ * -+ * Notes: In addition, we complete each failed or timed out command -+ * attached to this device. - */ -+STATIC void scsi_eh_set_device_offline(Scsi_Device *SDpnt, Scsi_Cmnd **done, -+ const char *reason) -+{ -+ Scsi_Cmnd *SCpnt, *SCnext; -+ -+ printk(KERN_ERR "scsi: device set offline - %s: " -+ "host %d channel %d id %d lun %d\n", -+ reason, SDpnt->host->host_no, SDpnt->channel, -+ SDpnt->id, SDpnt->lun); -+ -+ SDpnt->online = FALSE; -+ -+ for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCnext) { -+ SCnext = SCpnt->next; -+ -+ switch (SCpnt->state) { -+ case SCSI_STATE_TIMEOUT: -+ SCpnt->result |= DRIVER_TIMEOUT; -+ /*FALLTHROUGH*/ -+ -+ case SCSI_STATE_FAILED: -+ SCSI_LOG_ERROR_RECOVERY(3, -+ printk("Finishing command for device %d %x\n", -+ SDpnt->id, SCpnt->result)); -+ -+ SDpnt->host->host_failed--; -+ scsi_eh_finish_command(done, SCpnt); -+ break; -+ -+ default: -+ break; - } - } -+} -+ -+static void scsi_unjam_request_sense(struct Scsi_Host *host, Scsi_Cmnd **done) -+{ -+ int rtn; -+ int result; -+ Scsi_Cmnd *SCpnt; -+ Scsi_Device *SDpnt; - - /* - * Next, see if we need to request sense information. if so, - * then get it now, so we have a better idea of what to do. -- * FIXME(eric) this has the unfortunate side effect that if a host -- * adapter does not automatically request sense information, that we end -- * up shutting it down before we request it. All hosts should be doing this -- * anyways, so for now all I have to say is tough noogies if you end up in here. -- * On second thought, this is probably a good idea. We *really* want to give -- * authors an incentive to automatically request this. -+ * FIXME(eric) this has the unfortunate side effect that if a -+ * host adapter does not automatically request sense information, -+ * that we end up shutting it down before we request it. All -+ * hosts should be doing this anyways, so for now all I have -+ * to say is tough noogies if you end up in here. On second -+ * thought, this is probably a good idea. We *really* want -+ * to give authors an incentive to automatically request this. - */ -- SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Checking to see if we need to request sense\n")); -+ SCSI_LOG_ERROR_RECOVERY(3, -+ printk("scsi_unjam_host: Checking to see if we need to request sense\n")); - - for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { - for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) { -- if (SCpnt->state != SCSI_STATE_FAILED || scsi_sense_valid(SCpnt)) { -+ if (SCpnt->state != SCSI_STATE_FAILED || scsi_sense_valid(SCpnt)) - continue; -- } -- SCSI_LOG_ERROR_RECOVERY(2, printk("scsi_unjam_host: Requesting sense for %d\n", -- SCpnt->target)); -+ -+ SCSI_LOG_ERROR_RECOVERY(2, -+ printk("scsi_unjam_host: Requesting sense for %d\n", -+ SCpnt->target)); - rtn = scsi_request_sense(SCpnt); -- if (rtn != SUCCESS) { -+ if (rtn != SUCCESS) - continue; -- } -- SCSI_LOG_ERROR_RECOVERY(3, printk("Sense requested for %p - result %x\n", -- SCpnt, SCpnt->result)); -+ -+ SCSI_LOG_ERROR_RECOVERY(3, -+ printk("Sense requested for %p - result %x\n", -+ SCpnt, SCpnt->result)); - SCSI_LOG_ERROR_RECOVERY(3, print_sense("bh", SCpnt)); - - result = scsi_decide_disposition(SCpnt); - - /* -- * If the result was normal, then just pass it along to the -- * upper level. -+ * If the result was normal, then just pass -+ * it along to the upper level. - */ - if (result == SUCCESS) { - SCpnt->host->host_failed--; -- scsi_eh_finish_command(&SCdone, SCpnt); -+ scsi_eh_finish_command(done, SCpnt); - } -- if (result != NEEDS_RETRY) { -+ if (result != NEEDS_RETRY) - continue; -- } -+ - /* - * We only come in here if we want to retry a - * command. The test to see whether the command -@@ -1398,20 +1557,29 @@ - */ - SCpnt->state = NEEDS_RETRY; - rtn = scsi_eh_retry_command(SCpnt); -- if (rtn != SUCCESS) { -+ if (rtn != SUCCESS) - continue; -- } -+ - /* - * We eventually hand this one back to the top level. - */ - SCpnt->host->host_failed--; -- scsi_eh_finish_command(&SCdone, SCpnt); -+ scsi_eh_finish_command(done, SCpnt); - } - } -+} -+ -+static void scsi_unjam_count(struct Scsi_Host *host, Scsi_Cmnd **done) -+{ -+ Scsi_Device *SDpnt; -+ Scsi_Cmnd *SCpnt; -+ int devices_failed; -+ int numfailed; -+ int timed_out; - - /* -- * Go through the list of commands and figure out where we stand and how bad things -- * really are. -+ * Go through the list of commands and figure out where we -+ * stand and how bad things really are. - */ - numfailed = 0; - timed_out = 0; -@@ -1421,359 +1589,478 @@ - - for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) { - if (SCpnt->state == SCSI_STATE_FAILED) { -- SCSI_LOG_ERROR_RECOVERY(5, printk("Command to ID %d failed\n", -- SCpnt->target)); -+ SCSI_LOG_ERROR_RECOVERY(5, -+ printk("Command to ID %d failed\n", -+ SCpnt->target)); - numfailed++; - device_error++; - } - if (SCpnt->state == SCSI_STATE_TIMEOUT) { -- SCSI_LOG_ERROR_RECOVERY(5, printk("Command to ID %d timedout\n", -- SCpnt->target)); -+ SCSI_LOG_ERROR_RECOVERY(5, -+ printk("Command to ID %d timedout\n", -+ SCpnt->target)); - timed_out++; - device_error++; - } - } -- if (device_error > 0) { -+ if (device_error > 0) - devices_failed++; -- } - } - -- SCSI_LOG_ERROR_RECOVERY(2, printk("Total of %d+%d commands on %d devices require eh work\n", -- numfailed, timed_out, devices_failed)); -+ SCSI_LOG_ERROR_RECOVERY(2, -+ printk("Total of %d+%d commands on %d devices require eh work\n", -+ numfailed, timed_out, devices_failed)); -+} -+ -+static void scsi_unjam_abort(struct Scsi_Host *host, Scsi_Cmnd **done) -+{ -+ Scsi_Device *SDpnt; -+ Scsi_Cmnd *SCpnt; -+ int rtn; - -- if (host->host_failed == 0) { -- ourrtn = TRUE; -- goto leave; -- } - /* -- * Next, try and see whether or not it makes sense to try and abort -- * the running command. This only works out to be the case if we have -- * one command that has timed out. If the command simply failed, it -- * makes no sense to try and abort the command, since as far as the -- * host adapter is concerned, it isn't running. -+ * Next, try and see whether or not it makes sense to try and -+ * abort the running command. This only works out to be the -+ * case if we have one command that has timed out. If the -+ * command simply failed, it makes no sense to try and abort -+ * the command, since as far as the host adapter is concerned, -+ * it isn't running. - */ - -- SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Checking to see if we want to try abort\n")); -+ SCSI_LOG_ERROR_RECOVERY(3, -+ printk("scsi_unjam_host: Checking to see if we want to try abort\n")); - - for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { -- for (SCloop = SDpnt->device_queue; SCloop; SCloop = SCloop->next) { -- if (SCloop->state != SCSI_STATE_TIMEOUT) { -+ for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) { -+ if (SCpnt->state != SCSI_STATE_TIMEOUT) - continue; -- } -- rtn = scsi_try_to_abort_command(SCloop, ABORT_TIMEOUT); -- if (rtn == SUCCESS) { -- rtn = scsi_test_unit_ready(SCloop); -- -- if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) { -- rtn = scsi_eh_retry_command(SCloop); -- -- if (rtn == SUCCESS) { -- SCloop->host->host_failed--; -- scsi_eh_finish_command(&SCdone, SCloop); -- } -- } -- } -+ -+ rtn = scsi_try_to_abort_command(SCpnt, ABORT_TIMEOUT); -+ if (rtn == SUCCESS) -+ scsi_eh_test_and_retry(SCpnt, done); - } - } -+} -+ -+static void scsi_unjam_device_reset(struct Scsi_Host *host, Scsi_Cmnd **done) -+{ -+ Scsi_Device *SDpnt; -+ Scsi_Cmnd *SCpnt; -+ int rtn; - -- /* -- * If we have corrected all of the problems, then we are done. -- */ -- if (host->host_failed == 0) { -- ourrtn = TRUE; -- goto leave; -- } - /* - * Either the abort wasn't appropriate, or it didn't succeed. -- * Now try a bus device reset. Still, look to see whether we have -- * multiple devices that are jammed or not - if we have multiple devices, -- * it makes no sense to try BUS_DEVICE_RESET - we really would need -- * to try a BUS_RESET instead. -+ * Now try a bus device reset. Still, look to see whether we -+ * have multiple devices that are jammed or not - if we have -+ * multiple devices, it makes no sense to try BUS_DEVICE_RESET -+ * - we really would need to try a BUS_RESET instead. - * -- * Does this make sense - should we try BDR on each device individually? -- * Yes, definitely. -+ * Does this make sense - should we try BDR on each device -+ * individually? Yes, definitely. - */ -- SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Checking to see if we want to try BDR\n")); -+ SCSI_LOG_ERROR_RECOVERY(3, -+ printk("scsi_unjam_host: Checking to see if we want to try BDR\n")); - - for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { -- for (SCloop = SDpnt->device_queue; SCloop; SCloop = SCloop->next) { -- if (SCloop->state == SCSI_STATE_FAILED -- || SCloop->state == SCSI_STATE_TIMEOUT) { -- break; -- } -- } -- -- if (SCloop == NULL) { -+ SCpnt = scsi_eh_find_failed_command(SDpnt); -+ if (SCpnt == NULL) - continue; -- } -+ - /* -- * OK, we have a device that is having problems. Try and send -- * a bus device reset to it. -+ * OK, we have a device that is having problems. -+ * Try and send a bus device reset to it. -+ */ -+ rtn = scsi_try_bus_device_reset(SCpnt, RESET_TIMEOUT); -+ -+ /* -+ * A successful bus device reset causes all commands -+ * currently executing on the device to terminate. -+ * We expect the HBA driver to "forget" all commands -+ * associated with this device. - * -- * FIXME(eric) - make sure we handle the case where multiple -- * commands to the same device have failed. They all must -- * get properly restarted. -- */ -- rtn = scsi_try_bus_device_reset(SCloop, RESET_TIMEOUT); -- -- if (rtn == SUCCESS) { -- rtn = scsi_test_unit_ready(SCloop); -- -- if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) { -- rtn = scsi_eh_retry_command(SCloop); -- -- if (rtn == SUCCESS) { -- SCloop->host->host_failed--; -- scsi_eh_finish_command(&SCdone, SCloop); -- } -- } -- } -+ * Retry each failed or timed out command currently -+ * outstanding for this device. -+ * -+ * If any command fails, bail out. We will try a -+ * bus reset instead. -+ */ -+ if (rtn == SUCCESS) -+ scsi_eh_restart_device(SDpnt, done); - } -+} -+ -+static void scsi_unjam_bus_reset(struct Scsi_Host *host, Scsi_Cmnd **done) -+{ -+ Scsi_Device *SDpnt; -+ Scsi_Cmnd *SCpnt; -+ int rtn, channel, max_channel = 0; - -- if (host->host_failed == 0) { -- ourrtn = TRUE; -- goto leave; -- } - /* -- * If we ended up here, we have serious problems. The only thing left -- * to try is a full bus reset. If someone has grabbed the bus and isn't -- * letting go, then perhaps this will help. -+ * If we ended up here, we have serious problems. The only thing -+ * left to try is a full bus reset. If someone has grabbed the -+ * bus and isn't letting go, then perhaps this will help. - */ -- SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Try hard bus reset\n")); -+ SCSI_LOG_ERROR_RECOVERY(3, -+ printk("scsi_unjam_host: Try hard bus reset\n")); - -- /* -- * We really want to loop over the various channels, and do this on -- * a channel by channel basis. We should also check to see if any -- * of the failed commands are on soft_reset devices, and if so, skip -- * the reset. -+ /* -+ * Find the maximum channel number for this host. - */ -- for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { -- next_device: -- for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) { -- if (SCpnt->state != SCSI_STATE_FAILED -- && SCpnt->state != SCSI_STATE_TIMEOUT) { -+ for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) -+ if (SDpnt->channel > max_channel) -+ max_channel = SDpnt->channel; -+ -+ /* -+ * Loop over each channel, and see if it any device on -+ * each channel has failed. -+ */ -+ for (channel = 0; channel <= max_channel; channel++) { -+ Scsi_Cmnd *failed_command; -+ int soft_reset; -+ -+ try_again: -+ failed_command = NULL; -+ soft_reset = 0; -+ -+ /* -+ * Loop over each device on this channel locating any -+ * failed command. We need a Scsi_Cmnd structure to -+ * call the bus reset function. -+ * -+ * We also need to check if any of the failed commands -+ * are on soft_reset devices, and if so, skip the reset. -+ */ -+ for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { -+ if (SDpnt->channel != channel) - continue; -- } -- /* -- * We have a failed command. Make sure there are no other failed -- * commands on the same channel that are timed out and implement a -- * soft reset. -- */ -- for (SDloop = host->host_queue; SDloop; SDloop = SDloop->next) { -- for (SCloop = SDloop->device_queue; SCloop; SCloop = SCloop->next) { -- if (SCloop->channel != SCpnt->channel) { -- continue; -- } -- if (SCloop->state != SCSI_STATE_FAILED -- && SCloop->state != SCSI_STATE_TIMEOUT) { -- continue; -- } -- if (SDloop->soft_reset && SCloop->state == SCSI_STATE_TIMEOUT) { -- /* -- * If this device uses the soft reset option, and this -- * is one of the devices acting up, then our only -- * option is to wait a bit, since the command is -- * supposedly still running. -- * -- * FIXME(eric) - right now we will just end up falling -- * through to the 'take device offline' case. -- * -- * FIXME(eric) - It is possible that the command completed -- * *after* the error recovery procedure started, and if this -- * is the case, we are worrying about nothing here. -- */ -- -- scsi_sleep(1 * HZ); -- goto next_device; -- } -- } -- } -+ -+ SCpnt = scsi_eh_find_failed_command(SDpnt); -+ if (SCpnt) -+ failed_command = SCpnt; - - /* -- * We now know that we are able to perform a reset for the -- * bus that SCpnt points to. There are no soft-reset devices -- * with outstanding timed out commands. -+ * If this device has timed out or failed commands, -+ * and uses the soft_reset option. - */ -- rtn = scsi_try_bus_reset(SCpnt); -- if (rtn == SUCCESS) { -- for (SDloop = host->host_queue; SDloop; SDloop = SDloop->next) { -- for (SCloop = SDloop->device_queue; SCloop; SCloop = SCloop->next) { -- if (SCloop->channel != SCpnt->channel) { -- continue; -- } -- if (SCloop->state != SCSI_STATE_FAILED -- && SCloop->state != SCSI_STATE_TIMEOUT) { -- continue; -- } -- rtn = scsi_test_unit_ready(SCloop); -- -- if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) { -- rtn = scsi_eh_retry_command(SCloop); -- -- if (rtn == SUCCESS) { -- SCpnt->host->host_failed--; -- scsi_eh_finish_command(&SCdone, SCloop); -- } -- } -- /* -- * If the bus reset worked, but we are still unable to -- * talk to the device, take it offline. -- * FIXME(eric) - is this really the correct thing to do? -- */ -- if (rtn != SUCCESS) { -- printk(KERN_INFO "scsi: device set offline - not ready or command retry failed after bus reset: host %d channel %d id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun); -- -- SDloop->online = FALSE; -- SDloop->host->host_failed--; -- scsi_eh_finish_command(&SCdone, SCloop); -- } -- } -- } -+ if (SCpnt && SDpnt->soft_reset) -+ soft_reset = 1; -+ } -+ -+ /* -+ * If this channel hasn't failed, we -+ * don't need to reset it. -+ */ -+ if (!failed_command) -+ continue; -+ -+ /* -+ * If this device uses the soft reset option, and this -+ * is one of the devices acting up, then our only -+ * option is to wait a bit, since the command is -+ * supposedly still running. -+ * -+ * FIXME(eric) - right now we will just end up falling -+ * through to the 'take device offline' case. -+ * -+ * FIXME(eric) - It is possible that the command completed -+ * *after* the error recovery procedure started, and if -+ * this is the case, we are worrying about nothing here. -+ * -+ * FIXME(rmk) - This should be bounded; we shouldn't wait -+ * for an infinite amount of time for any device. -+ */ -+ if (soft_reset) { -+ SCSI_LOG_ERROR_RECOVERY(3, -+ printk("scsi_unjam_host: unable to try bus " -+ "reset for host %d channel %d\n", -+ host->host_no, channel)); -+ scsi_sleep(1 * HZ); -+ goto try_again; -+ } -+ -+ /* -+ * We now know that we are able to perform a reset for the -+ * bus that SCpnt points to. There are no soft-reset devices -+ * with outstanding timed out commands. -+ */ -+ rtn = scsi_try_bus_reset(failed_command); -+ -+ /* -+ * If we failed to reset the bus, move on to the next bus. -+ */ -+ if (rtn != SUCCESS) -+ continue; -+ -+ /* -+ * We succeeded. Retry each failed command. -+ */ -+ for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { -+ if (SDpnt->channel != channel) -+ continue; -+ -+ rtn = scsi_eh_restart_device(SDpnt, done); -+ -+ if (rtn != SUCCESS) { -+ SCpnt = scsi_eh_find_failed_command(SDpnt); -+ -+ /* -+ * This device failed again. Since a bus -+ * reset freed it up, chances are we've -+ * hit the same problem, so try the same -+ * solution. We also need to ensure that -+ * the SCSI bus is in the BUS FREE state -+ * so we can try to talk to other devices. -+ */ -+ scsi_try_bus_reset(SCpnt); -+ scsi_eh_set_device_offline(SDpnt, done, -+ "not ready or command retry " -+ "failed after bus reset"); - } - } - } -+} -+ -+static void scsi_unjam_host_reset(struct Scsi_Host *host, Scsi_Cmnd **done) -+{ -+ Scsi_Device *SDpnt; -+ Scsi_Cmnd *SCpnt; -+ Scsi_Cmnd *failed_command = NULL; -+ int rtn, soft_reset; - -- if (host->host_failed == 0) { -- ourrtn = TRUE; -- goto leave; -- } - /* -- * If we ended up here, we have serious problems. The only thing left -- * to try is a full host reset - perhaps the firmware on the device -- * crashed, or something like that. -+ * If we ended up here, we have serious problems. The only thing -+ * left to try is a full host reset - perhaps the firmware on the -+ * device crashed, or something like that. - * -- * It is assumed that a succesful host reset will cause *all* information -- * about the command to be flushed from both the host adapter *and* the -- * device. -+ * It is assumed that a succesful host reset will cause *all* -+ * information about the command to be flushed from both the host -+ * adapter *and* the device. - * -- * FIXME(eric) - it isn't clear that devices that implement the soft reset -- * option can ever be cleared except via cycling the power. The problem is -- * that sending the host reset command will cause the host to forget -- * about the pending command, but the device won't forget. For now, we -- * skip the host reset option if any of the failed devices are configured -- * to use the soft reset option. -+ * FIXME(eric) - it isn't clear that devices that implement the -+ * soft reset option can ever be cleared except via cycling the -+ * power. The problem is that sending the host reset command will -+ * cause the host to forget about the pending command, but the -+ * device won't forget. For now, we skip the host reset option -+ * if any of the failed devices are configured to use the soft -+ * reset option. - */ -+ SCSI_LOG_ERROR_RECOVERY(3, -+ printk("scsi_unjam_host: Try host reset\n")); -+ -+ try_again: -+ failed_command = NULL; -+ soft_reset = 0; -+ - for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { -- next_device2: -- for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) { -- if (SCpnt->state != SCSI_STATE_FAILED -- && SCpnt->state != SCSI_STATE_TIMEOUT) { -- continue; -- } -- if (SDpnt->soft_reset && SCpnt->state == SCSI_STATE_TIMEOUT) { -- /* -- * If this device uses the soft reset option, and this -- * is one of the devices acting up, then our only -- * option is to wait a bit, since the command is -- * supposedly still running. -- * -- * FIXME(eric) - right now we will just end up falling -- * through to the 'take device offline' case. -- */ -- SCSI_LOG_ERROR_RECOVERY(3, -- printk("scsi_unjam_host: Unable to try hard host reset\n")); -+ /* -+ * Locate any failed commands for this device. -+ */ -+ SCpnt = scsi_eh_find_failed_command(SDpnt); -+ if (SCpnt) -+ failed_command = SCpnt; - -- /* -- * Due to the spinlock, we will never get out of this -- * loop without a proper wait. (DB) -- */ -- scsi_sleep(1 * HZ); -+ /* -+ * If this device has timed out or failed commands, -+ * and uses the soft_reset option. -+ */ -+ if (SCpnt && SDpnt->soft_reset) -+ soft_reset = 1; -+ } - -- goto next_device2; -- } -- SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Try hard host reset\n")); -+ /* -+ * If this device uses the soft reset option, and this -+ * is one of the devices acting up, then our only -+ * option is to wait a bit, since the command is -+ * supposedly still running. -+ * -+ * FIXME(eric) - right now we will just end up falling -+ * through to the 'take device offline' case. -+ * -+ * FIXME(rmk) - This should be bounded; we shouldn't wait -+ * for an infinite amount of time for any device. -+ */ -+ if (soft_reset) { -+ SCSI_LOG_ERROR_RECOVERY(3, -+ printk("scsi_unjam_host: unable to try " -+ "hard host reset\n")); - - /* -- * FIXME(eric) - we need to obtain a valid SCpnt to perform this call. -+ * Due to the spinlock, we will never get out of this -+ * loop without a proper wait. (DB) - */ -- rtn = scsi_try_host_reset(SCpnt); -- if (rtn == SUCCESS) { -- /* -- * FIXME(eric) we assume that all commands are flushed from the -- * controller. We should get a DID_RESET for all of the commands -- * that were pending. We should ignore these so that we can -- * guarantee that we are in a consistent state. -- * -- * I believe this to be the case right now, but this needs to be -- * tested. -- */ -- for (SDloop = host->host_queue; SDloop; SDloop = SDloop->next) { -- for (SCloop = SDloop->device_queue; SCloop; SCloop = SCloop->next) { -- if (SCloop->state != SCSI_STATE_FAILED -- && SCloop->state != SCSI_STATE_TIMEOUT) { -- continue; -- } -- rtn = scsi_test_unit_ready(SCloop); -- -- if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) { -- rtn = scsi_eh_retry_command(SCloop); -- -- if (rtn == SUCCESS) { -- SCpnt->host->host_failed--; -- scsi_eh_finish_command(&SCdone, SCloop); -- } -- } -- if (rtn != SUCCESS) { -- printk(KERN_INFO "scsi: device set offline - not ready or command retry failed after host reset: host %d channel %d id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun); -- SDloop->online = FALSE; -- SDloop->host->host_failed--; -- scsi_eh_finish_command(&SCdone, SCloop); -- } -- } -- } -- } -- } -- } -+ scsi_sleep(1 * HZ); - -- /* -- * If we solved all of the problems, then let's rev up the engines again. -- */ -- if (host->host_failed == 0) { -- ourrtn = TRUE; -- goto leave; -+ goto try_again; - } -+ -+ SCSI_LOG_ERROR_RECOVERY(3, -+ printk("scsi_unjam_host: Try hard host reset\n")); -+ - /* -- * If the HOST RESET failed, then for now we assume that the entire host -- * adapter is too hosed to be of any use. For our purposes, however, it is -- * easier to simply take the devices offline that correspond to commands -- * that failed. -+ * FIXME(eric) - we need to obtain a valid SCpnt to perform this call. - */ -- SCSI_LOG_ERROR_RECOVERY(1, printk("scsi_unjam_host: Take device offline\n")); -+ rtn = scsi_try_host_reset(failed_command); -+ if (rtn == SUCCESS) { -+ /* -+ * FIXME(eric) we assume that all commands are flushed from -+ * the controller. We should get a DID_RESET for all of the -+ * commands that were pending. We should ignore these so -+ * that we can guarantee that we are in a consistent state. -+ * -+ * I believe this to be the case right now, but this needs -+ * to be tested. -+ */ -+ for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { -+ rtn = scsi_eh_restart_device(SDpnt, done); - -- for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { -- for (SCloop = SDpnt->device_queue; SCloop; SCloop = SCloop->next) { -- if (SCloop->state == SCSI_STATE_FAILED || SCloop->state == SCSI_STATE_TIMEOUT) { -- SDloop = SCloop->device; -- if (SDloop->online == TRUE) { -- printk(KERN_INFO "scsi: device set offline - command error recover failed: host %d channel %d id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun); -- SDloop->online = FALSE; -- } -+ if (rtn != SUCCESS) { -+ SCpnt = scsi_eh_find_failed_command(SDpnt); - - /* -- * This should pass the failure up to the top level driver, and -- * it will have to try and do something intelligent with it. -+ * This device failed again. Since a host -+ * reset freed it up, chances are we've -+ * hit the same problem, so try the same -+ * solution. We also need to ensure that -+ * the SCSI bus is in the BUS FREE state -+ * so we can try to talk to other devices. - */ -- SCloop->host->host_failed--; -- -- if (SCloop->state == SCSI_STATE_TIMEOUT) { -- SCloop->result |= (DRIVER_TIMEOUT << 24); -- } -- SCSI_LOG_ERROR_RECOVERY(3, printk("Finishing command for device %d %x\n", -- SDloop->id, SCloop->result)); -- -- scsi_eh_finish_command(&SCdone, SCloop); -+ scsi_try_host_reset(SCpnt); -+ scsi_eh_set_device_offline(SDpnt, done, -+ "not ready or command retry " -+ "failed after host reset"); - } - } - } -+} -+ -+static void scsi_unjam_failure(struct Scsi_Host *host, Scsi_Cmnd **done) -+{ -+ Scsi_Device *SDpnt; - -- if (host->host_failed != 0) { -+ /* -+ * If the HOST RESET failed, then for now we assume that the -+ * entire host adapter is too hosed to be of any use. For our -+ * purposes, however, it is easier to simply take the devices -+ * offline that correspond to commands that failed. -+ */ -+ SCSI_LOG_ERROR_RECOVERY(1, -+ printk("scsi_unjam_host: Take device offline\n")); -+ -+ for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) -+ scsi_eh_set_device_offline(SDpnt, done, -+ "command error recover failed"); -+ -+ if (host->host_failed != 0) - panic("scsi_unjam_host: Miscount of number of failed commands.\n"); -- } -+ - SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Returning\n")); -+} -+ -+static void (*unjam_method[])(struct Scsi_Host *, Scsi_Cmnd **) = { -+ scsi_unjam_request_sense, -+ scsi_unjam_count, -+ scsi_unjam_abort, -+ scsi_unjam_device_reset, -+ scsi_unjam_bus_reset, -+ scsi_unjam_host_reset, -+ scsi_unjam_failure, -+}; -+ -+/* -+ * Function: scsi_unjam_host -+ * -+ * Purpose: Attempt to fix a host which has a command that failed for -+ * some reason. -+ * -+ * Arguments: host - host that needs unjamming. -+ * -+ * Returns: Nothing -+ * -+ * Notes: When we come in here, we *know* that all commands on the -+ * bus have either completed, failed or timed out. We also -+ * know that no further commands are being sent to the host, -+ * so things are relatively quiet and we have freedom to -+ * fiddle with things as we wish. -+ * -+ * Additional note: This is only the *default* implementation. It is possible -+ * for individual drivers to supply their own version of this -+ * function, and if the maintainer wishes to do this, it is -+ * strongly suggested that this function be taken as a template -+ * and modified. This function was designed to correctly handle -+ * problems for about 95% of the different cases out there, and -+ * it should always provide at least a reasonable amount of error -+ * recovery. -+ * -+ * Note3: Any command marked 'FAILED' or 'TIMEOUT' must eventually -+ * have scsi_finish_command() called for it. We do all of -+ * the retry stuff here, so when we restart the host after we -+ * return it should have an empty queue. -+ */ -+STATIC int scsi_unjam_host(struct Scsi_Host *host) -+{ -+ Scsi_Cmnd *SCdone = NULL; -+ Scsi_Cmnd *SCpnt; -+ Scsi_Device *SDpnt; -+ int ourrtn = FALSE; -+ int i; - -- ourrtn = FALSE; -+ ASSERT_LOCK(&io_request_lock, 0); - -- leave: -+ /* -+ * First, protect against any sort of race condition. If any of the outstanding -+ * commands are in states that indicate that we are not yet blocked (i.e. we are -+ * not in a quiet state) then we got woken up in error. If we ever end up here, -+ * we need to re-examine some of the assumptions. -+ */ -+ for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { -+ for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) { -+ if (SCpnt->state == SCSI_STATE_FAILED -+ || SCpnt->state == SCSI_STATE_TIMEOUT -+ || SCpnt->state == SCSI_STATE_INITIALIZING -+ || SCpnt->state == SCSI_STATE_UNUSED) { -+ continue; -+ } -+ /* -+ * Rats. Something is still floating around out there. This could -+ * be the result of the fact that the upper level drivers are still frobbing -+ * commands that might have succeeded. There are two outcomes. One is that -+ * the command block will eventually be freed, and the other one is that -+ * the command will be queued and will be finished along the way. -+ */ -+ SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler prematurely woken - commands still active (%p %x %d)\n", SCpnt, SCpnt->state, SCpnt->target)); -+ -+/* -+ * panic("SCSI Error handler woken too early\n"); -+ * -+ * This is no longer a problem, since now the code cares only about -+ * SCSI_STATE_TIMEOUT and SCSI_STATE_FAILED. -+ * Other states are useful only to release active commands when devices are -+ * set offline. If (host->host_active == host->host_busy) we can safely assume -+ * that there are no commands in state other then TIMEOUT od FAILED. (DB) -+ * -+ * FIXME: -+ * It is not easy to release correctly commands according to their state when -+ * devices are set offline, when the state is neither TIMEOUT nor FAILED. -+ * When a device is set offline, we can have some command with -+ * rq_status=RQ_SCSY_BUSY, owner=SCSI_STATE_HIGHLEVEL, -+ * state=SCSI_STATE_INITIALIZING and the driver module cannot be released. -+ * (DB, 17 May 1998) -+ */ -+ } -+ } -+ -+ for (i = 0; i < ARRAY_SIZE(unjam_method); i++) { -+ unjam_method[i](host, &SCdone); -+ -+ /* -+ * If we solved all of the problems, then -+ * let's rev up the engines again. -+ */ -+ if (host->host_failed == 0) { -+ ourrtn = TRUE; -+ break; -+ } -+ } - - /* - * We should have a list of commands that we 'finished' during the course of -@@ -2013,3 +2300,17 @@ - * tab-width: 8 - * End: - */ -+ -+EXPORT_SYMBOL(scsi_eh_times_out); -+EXPORT_SYMBOL(scsi_eh_retry_command); -+EXPORT_SYMBOL(scsi_request_sense); -+EXPORT_SYMBOL(scsi_test_unit_ready); -+EXPORT_SYMBOL(scsi_unit_is_ready); -+EXPORT_SYMBOL(scsi_eh_finish_command); -+EXPORT_SYMBOL(scsi_try_to_abort_command); -+EXPORT_SYMBOL(scsi_try_bus_device_reset); -+EXPORT_SYMBOL(scsi_try_bus_reset); -+EXPORT_SYMBOL(scsi_try_host_reset); -+EXPORT_SYMBOL(scsi_sense_valid); -+EXPORT_SYMBOL(scsi_done); -+EXPORT_SYMBOL(scsi_decide_disposition); -diff -urN linux-2.4.26/drivers/scsi/scsi_ioctl.c linux-2.4.26-vrs1/drivers/scsi/scsi_ioctl.c ---- linux-2.4.26/drivers/scsi/scsi_ioctl.c 2003-08-25 12:44:42.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/scsi/scsi_ioctl.c 2004-01-14 21:39:12.000000000 +0000 -@@ -153,6 +153,29 @@ - return result; - } - -+int scsi_set_medium_removal(Scsi_Device *dev, char state) -+{ -+ char scsi_cmd[MAX_COMMAND_SIZE]; -+ int ret; -+ -+ if (!dev->removable || !dev->lockable) -+ return 0; -+ -+ scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; -+ scsi_cmd[1] = (dev->scsi_level <= SCSI_2) ? (dev->lun << 5) : 0; -+ scsi_cmd[2] = 0; -+ scsi_cmd[3] = 0; -+ scsi_cmd[4] = state; -+ scsi_cmd[5] = 0; -+ -+ ret = ioctl_internal_command(dev, scsi_cmd, IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES); -+ -+ if (ret == 0) -+ dev->locked = state == SCSI_REMOVAL_PREVENT; -+ -+ return ret; -+} -+ - /* - * This interface is depreciated - users should use the scsi generic (sg) - * interface instead, as this is a more flexible approach to performing -@@ -450,24 +473,9 @@ - return scsi_ioctl_send_command((Scsi_Device *) dev, - (Scsi_Ioctl_Command *) arg); - case SCSI_IOCTL_DOORLOCK: -- if (!dev->removable || !dev->lockable) -- return 0; -- scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; -- scsi_cmd[1] = cmd_byte1; -- scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; -- scsi_cmd[4] = SCSI_REMOVAL_PREVENT; -- return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, -- IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES); -- break; -+ return scsi_set_medium_removal(dev, SCSI_REMOVAL_PREVENT); - case SCSI_IOCTL_DOORUNLOCK: -- if (!dev->removable || !dev->lockable) -- return 0; -- scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; -- scsi_cmd[1] = cmd_byte1; -- scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; -- scsi_cmd[4] = SCSI_REMOVAL_ALLOW; -- return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, -- IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES); -+ return scsi_set_medium_removal(dev, SCSI_REMOVAL_ALLOW); - case SCSI_IOCTL_TEST_UNIT_READY: - scsi_cmd[0] = TEST_UNIT_READY; - scsi_cmd[1] = cmd_byte1; -diff -urN linux-2.4.26/drivers/scsi/scsi_lib.c linux-2.4.26-vrs1/drivers/scsi/scsi_lib.c ---- linux-2.4.26/drivers/scsi/scsi_lib.c 2004-04-19 11:44:16.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/scsi/scsi_lib.c 2004-04-18 21:47:51.000000000 +0100 -@@ -208,6 +208,30 @@ - } - - /* -+ * Function: scsi_setup_cmd_retry() -+ * -+ * Purpose: Restore the command state for a retry -+ * -+ * Arguments: SCpnt - command to be restored -+ * -+ * Returns: Nothing -+ * -+ * Notes: Immediately prior to retrying a command, we need -+ * to restore certain fields that we saved above. -+ */ -+void scsi_setup_cmd_retry(Scsi_Cmnd *SCpnt) -+{ -+ memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd, -+ sizeof(SCpnt->data_cmnd)); -+ SCpnt->request_buffer = SCpnt->buffer; -+ SCpnt->request_bufflen = SCpnt->bufflen; -+ SCpnt->use_sg = SCpnt->old_use_sg; -+ SCpnt->cmd_len = SCpnt->old_cmd_len; -+ SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; -+ SCpnt->underflow = SCpnt->old_underflow; -+} -+ -+/* - * Function: scsi_queue_next_request() - * - * Purpose: Handle post-processing of completed commands. -@@ -731,7 +755,7 @@ - printk("scsi%d: ERROR on channel %d, id %d, lun %d, CDB: ", - SCpnt->host->host_no, (int) SCpnt->channel, - (int) SCpnt->target, (int) SCpnt->lun); -- print_command(SCpnt->cmnd); -+ print_command(SCpnt->data_cmnd); - print_sense("sd", SCpnt); - SCpnt = scsi_end_request(SCpnt, 0, block_sectors); - return; -@@ -906,8 +930,17 @@ - * space. Technically the error handling thread should be - * doing this crap, but the error handler isn't used by - * most hosts. -+ * -+ * (rmk) -+ * Trying to lock the door can cause deadlocks. We therefore -+ * only use this for old hosts; our door locking is now done -+ * by the error handler in scsi_restart_operations for new -+ * eh hosts. -+ * -+ * Note that we don't clear was_reset here; this is used by -+ * st.c, and either one or other has to die. - */ -- if (SDpnt->was_reset) { -+ if (SHpnt->hostt->use_new_eh_code == 0 && SDpnt->was_reset) { - /* - * We need to relock the door, but we might - * be in an interrupt handler. Only do this -@@ -918,7 +951,7 @@ - * this work. - */ - SDpnt->was_reset = 0; -- if (SDpnt->removable && !in_interrupt()) { -+ if (SDpnt->removable && SDpnt->locked && !in_interrupt()) { - spin_unlock_irq(&io_request_lock); - scsi_ioctl(SDpnt, SCSI_IOCTL_DOORLOCK, 0); - spin_lock_irq(&io_request_lock); -diff -urN linux-2.4.26/drivers/scsi/scsi_syms.c linux-2.4.26-vrs1/drivers/scsi/scsi_syms.c ---- linux-2.4.26/drivers/scsi/scsi_syms.c 2004-04-19 11:44:16.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/scsi/scsi_syms.c 2004-04-18 21:47:51.000000000 +0100 -@@ -104,3 +104,6 @@ - extern int scsi_delete_timer(Scsi_Cmnd *); - EXPORT_SYMBOL(scsi_add_timer); - EXPORT_SYMBOL(scsi_delete_timer); -+ -+extern int scsi_set_medium_removal(Scsi_Device *dev, char state); -+EXPORT_SYMBOL(scsi_set_medium_removal); -diff -urN linux-2.4.26/drivers/scsi/sd.c linux-2.4.26-vrs1/drivers/scsi/sd.c ---- linux-2.4.26/drivers/scsi/sd.c 2003-08-25 12:44:42.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/scsi/sd.c 2004-01-14 21:39:12.000000000 +0000 -@@ -399,6 +399,7 @@ - this_count = 0xffff; - - SCpnt->cmnd[0] += READ_10 - READ_6; -+ SCpnt->cmnd[1] |= 1 << 3; /* Set FUA --rmk */ - SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff; - SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff; - SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff; -@@ -524,7 +525,7 @@ - if (SDev->removable) - if (SDev->access_count==1) - if (scsi_block_when_processing_errors(SDev)) -- scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, NULL); -+ scsi_set_medium_removal(SDev, SCSI_REMOVAL_PREVENT); - - - return 0; -@@ -553,7 +554,7 @@ - if (SDev->removable) { - if (!SDev->access_count) - if (scsi_block_when_processing_errors(SDev)) -- scsi_ioctl(SDev, SCSI_IOCTL_DOORUNLOCK, NULL); -+ scsi_set_medium_removal(SDev, SCSI_REMOVAL_ALLOW); - } - if (SDev->host->hostt->module) - __MOD_DEC_USE_COUNT(SDev->host->hostt->module); -diff -urN linux-2.4.26/drivers/scsi/sr_ioctl.c linux-2.4.26-vrs1/drivers/scsi/sr_ioctl.c ---- linux-2.4.26/drivers/scsi/sr_ioctl.c 2002-11-28 23:53:14.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/scsi/sr_ioctl.c 2004-01-14 21:32:26.000000000 +0000 -@@ -214,9 +214,8 @@ - - int sr_lock_door(struct cdrom_device_info *cdi, int lock) - { -- return scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device, -- lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK, -- 0); -+ return scsi_set_medium_removal(scsi_CDs[MINOR(cdi->dev)].device, -+ lock ? SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW); - } - - int sr_drive_status(struct cdrom_device_info *cdi, int slot) -diff -urN linux-2.4.26/drivers/serial/21285.c linux-2.4.26-vrs1/drivers/serial/21285.c ---- linux-2.4.26/drivers/serial/21285.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/serial/21285.c 2004-04-04 23:11:12.000000000 +0100 -@@ -0,0 +1,599 @@ -+/* -+ * linux/drivers/char/serial_21285.c -+ * -+ * Driver for the serial port on the 21285 StrongArm-110 core logic chip. -+ * -+ * Based on drivers/char/serial.c -+ * -+ * $Id: 21285.c,v 1.4.2.1 2002/10/24 09:53:23 rmk Exp $ -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#define BAUD_BASE (mem_fclk_21285/64) -+ -+#ifdef CONFIG_DEVFS_FS -+#define SERIAL_21285_NAME "tts/FB%d" -+#define SERIAL_21285_AUXNAME "cua/FB%d" -+#else -+#define SERIAL_21285_NAME "ttyFB" -+#define SERIAL_21285_AUXNAME "cuafb" -+#endif -+ -+#define SERIAL_21285_MAJOR 204 -+#define SERIAL_21285_MINOR 4 -+ -+#define SERIAL_21285_AUXMAJOR 205 -+#define SERIAL_21285_AUXMINOR 4 -+ -+#ifdef CONFIG_SERIAL_21285_OLD -+#include -+/* -+ * Compatability with a mistake made a long time ago. -+ * Note - the use of "ttyI", "/dev/ttyS0" and major/minor 5,64 -+ * is HIGHLY DEPRECIATED, and will be removed in the 2.5 -+ * kernel series. -+ * -- rmk 15/04/2000 -+ */ -+#define SERIAL_21285_OLD_NAME "ttyI" -+#define SERIAL_21285_OLD_MAJOR TTY_MAJOR -+#define SERIAL_21285_OLD_MINOR 64 -+ -+static struct tty_driver rs285_old_driver; -+#endif -+ -+static struct tty_driver rs285_driver, callout_driver; -+static int rs285_refcount; -+static struct tty_struct *rs285_table[1]; -+ -+static struct termios *rs285_termios[1]; -+static struct termios *rs285_termios_locked[1]; -+ -+static char wbuf[1000], *putp = wbuf, *getp = wbuf, x_char; -+static struct tty_struct *rs285_tty; -+static DECLARE_MUTEX(rs285_sem); -+static int rs285_use_count; -+static unsigned long rs285_irq_enabled; -+ -+#define TX_IRQ_BIT (0) -+#define RX_IRQ_BIT (1) -+ -+static void rs285_stop_tx(void) -+{ -+ if (test_and_clear_bit(TX_IRQ_BIT, &rs285_irq_enabled)) -+ disable_irq(IRQ_CONTX); -+} -+ -+static void rs285_start_tx(void) -+{ -+ if (!test_and_set_bit(TX_IRQ_BIT, &rs285_irq_enabled)) -+ enable_irq(IRQ_CONTX); -+} -+ -+static void rs285_stop_rx(void) -+{ -+ if (test_and_clear_bit(RX_IRQ_BIT, &rs285_irq_enabled)) -+ disable_irq(IRQ_CONRX); -+} -+ -+static void rs285_start_rx(void) -+{ -+ if (!test_and_set_bit(RX_IRQ_BIT, &rs285_irq_enabled)) -+ enable_irq(IRQ_CONRX); -+} -+ -+static int rs285_write_room(struct tty_struct *tty) -+{ -+ return putp >= getp ? (sizeof(wbuf) - (long) putp + (long) getp) : ((long) getp - (long) putp - 1); -+} -+ -+static void rs285_rx_int(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ if (!rs285_tty) { -+ rs285_stop_rx(); -+ return; -+ } -+ while (!(*CSR_UARTFLG & 0x10)) { -+ int ch, flag; -+ ch = *CSR_UARTDR; -+ flag = *CSR_RXSTAT; -+ if (flag & 4) -+ tty_insert_flip_char(rs285_tty, 0, TTY_OVERRUN); -+ if (flag & 2) -+ flag = TTY_PARITY; -+ else if (flag & 1) -+ flag = TTY_FRAME; -+ tty_insert_flip_char(rs285_tty, ch, flag); -+ } -+ tty_flip_buffer_push(rs285_tty); -+} -+ -+static void rs285_send_xchar(struct tty_struct *tty, char ch) -+{ -+ x_char = ch; -+ rs285_start_tx(); -+} -+ -+static void rs285_throttle(struct tty_struct *tty) -+{ -+ if (I_IXOFF(tty)) -+ rs285_send_xchar(tty, STOP_CHAR(tty)); -+} -+ -+static void rs285_unthrottle(struct tty_struct *tty) -+{ -+ if (I_IXOFF(tty)) { -+ if (x_char) -+ x_char = 0; -+ else -+ rs285_send_xchar(tty, START_CHAR(tty)); -+ } -+} -+ -+static void rs285_tx_int(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ while (!(*CSR_UARTFLG & 0x20)) { -+ if (x_char) { -+ *CSR_UARTDR = x_char; -+ x_char = 0; -+ continue; -+ } -+ if (putp == getp) { -+ rs285_stop_tx(); -+ break; -+ } -+ *CSR_UARTDR = *getp; -+ if (++getp >= wbuf + sizeof(wbuf)) -+ getp = wbuf; -+ } -+ if (rs285_tty) -+ wake_up_interruptible(&rs285_tty->write_wait); -+} -+ -+static inline int rs285_xmit(int ch) -+{ -+ if (putp + 1 == getp || (putp + 1 == wbuf + sizeof(wbuf) && getp == wbuf)) -+ return 0; -+ *putp = ch; -+ if (++putp >= wbuf + sizeof(wbuf)) -+ putp = wbuf; -+ rs285_start_tx(); -+ return 1; -+} -+ -+static int rs285_write(struct tty_struct *tty, int from_user, -+ const u_char * buf, int count) -+{ -+ int i; -+ -+ if (from_user && verify_area(VERIFY_READ, buf, count)) -+ return -EINVAL; -+ -+ for (i = 0; i < count; i++) { -+ char ch; -+ if (from_user) -+ __get_user(ch, buf + i); -+ else -+ ch = buf[i]; -+ if (!rs285_xmit(ch)) -+ break; -+ } -+ return i; -+} -+ -+static void rs285_put_char(struct tty_struct *tty, u_char ch) -+{ -+ rs285_xmit(ch); -+} -+ -+static int rs285_chars_in_buffer(struct tty_struct *tty) -+{ -+ return sizeof(wbuf) - rs285_write_room(tty); -+} -+ -+static void rs285_flush_buffer(struct tty_struct *tty) -+{ -+ rs285_stop_tx(); -+ putp = getp = wbuf; -+ if (x_char) -+ rs285_start_tx(); -+} -+ -+static inline void rs285_set_cflag(int cflag) -+{ -+ int h_lcr, baud, quot; -+ -+ switch (cflag & CSIZE) { -+ case CS5: -+ h_lcr = 0x10; -+ break; -+ case CS6: -+ h_lcr = 0x30; -+ break; -+ case CS7: -+ h_lcr = 0x50; -+ break; -+ default: /* CS8 */ -+ h_lcr = 0x70; -+ break; -+ -+ } -+ if (cflag & CSTOPB) -+ h_lcr |= 0x08; -+ if (cflag & PARENB) -+ h_lcr |= 0x02; -+ if (!(cflag & PARODD)) -+ h_lcr |= 0x04; -+ -+ switch (cflag & CBAUD) { -+ case B200: baud = 200; break; -+ case B300: baud = 300; break; -+ case B1200: baud = 1200; break; -+ case B1800: baud = 1800; break; -+ case B2400: baud = 2400; break; -+ case B4800: baud = 4800; break; -+ default: -+ case B9600: baud = 9600; break; -+ case B19200: baud = 19200; break; -+ case B38400: baud = 38400; break; -+ case B57600: baud = 57600; break; -+ case B115200: baud = 115200; break; -+ } -+ -+ /* -+ * The documented expression for selecting the divisor is: -+ * BAUD_BASE / baud - 1 -+ * However, typically BAUD_BASE is not divisible by baud, so -+ * we want to select the divisor that gives us the minimum -+ * error. Therefore, we want: -+ * int(BAUD_BASE / baud - 0.5) -> -+ * int(BAUD_BASE / baud - (baud >> 1) / baud) -> -+ * int((BAUD_BASE - (baud >> 1)) / baud) -+ */ -+ quot = (BAUD_BASE - (baud >> 1)) / baud; -+ -+ *CSR_UARTCON = 0; -+ *CSR_L_UBRLCR = quot & 0xff; -+ *CSR_M_UBRLCR = (quot >> 8) & 0x0f; -+ *CSR_H_UBRLCR = h_lcr; -+ *CSR_UARTCON = 1; -+} -+ -+static void rs285_set_termios(struct tty_struct *tty, struct termios *old) -+{ -+ if (old && tty->termios->c_cflag == old->c_cflag) -+ return; -+ rs285_set_cflag(tty->termios->c_cflag); -+} -+ -+ -+static void rs285_stop(struct tty_struct *tty) -+{ -+ rs285_stop_tx(); -+} -+ -+static void rs285_start(struct tty_struct *tty) -+{ -+ rs285_start_tx(); -+} -+ -+static void rs285_wait_until_sent(struct tty_struct *tty, int timeout) -+{ -+ int orig_jiffies = jiffies; -+ while (*CSR_UARTFLG & 8) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(1); -+ if (signal_pending(current)) -+ break; -+ if (timeout && time_after(jiffies, orig_jiffies + timeout)) -+ break; -+ } -+ set_current_state(TASK_RUNNING); -+} -+ -+static int rs285_open(struct tty_struct *tty, struct file *filp) -+{ -+ int line, ret; -+ -+ MOD_INC_USE_COUNT; -+ -+ line = MINOR(tty->device) - tty->driver.minor_start; -+ if (line) -+ return -ENODEV; -+ -+ ret = down_interruptible(&rs285_sem); -+ if (ret) -+ return ret; -+ -+ tty->driver_data = NULL; -+ rs285_tty = tty; -+ -+ if (rs285_use_count == 0) { -+ rs285_irq_enabled = 3; -+ ret = request_irq(IRQ_CONRX, rs285_rx_int, 0, "rs285", NULL); -+ if (ret == 0) { -+ ret = request_irq(IRQ_CONTX, rs285_tx_int, 0, "rs285", -+ NULL); -+ if (ret) -+ free_irq(IRQ_CONRX, NULL); -+ } -+ } -+ -+ if (ret == 0) -+ rs285_use_count++; -+ -+ up(&rs285_sem); -+ -+ return ret; -+} -+ -+static void rs285_close(struct tty_struct *tty, struct file *filp) -+{ -+ down(&rs285_sem); -+ if (!--rs285_use_count) { -+ rs285_wait_until_sent(tty, 0); -+ rs285_stop_rx(); -+ rs285_stop_tx(); -+ rs285_tty = NULL; -+ free_irq(IRQ_CONTX, NULL); -+ free_irq(IRQ_CONRX, NULL); -+ } -+ up(&rs285_sem); -+ MOD_DEC_USE_COUNT; -+} -+ -+static int __init rs285_init(void) -+{ -+ int baud = B9600; -+ -+ if (machine_is_personal_server()) -+ baud = B57600; -+ -+ rs285_driver.magic = TTY_DRIVER_MAGIC; -+ rs285_driver.driver_name = "serial_21285"; -+ rs285_driver.name = SERIAL_21285_NAME; -+ rs285_driver.major = SERIAL_21285_MAJOR; -+ rs285_driver.minor_start = SERIAL_21285_MINOR; -+ rs285_driver.num = 1; -+ rs285_driver.type = TTY_DRIVER_TYPE_SERIAL; -+ rs285_driver.subtype = SERIAL_TYPE_NORMAL; -+ rs285_driver.init_termios = tty_std_termios; -+ rs285_driver.init_termios.c_cflag = baud | CS8 | CREAD | HUPCL | CLOCAL; -+ rs285_driver.flags = TTY_DRIVER_REAL_RAW; -+ rs285_driver.refcount = &rs285_refcount; -+ rs285_driver.table = rs285_table; -+ rs285_driver.termios = rs285_termios; -+ rs285_driver.termios_locked = rs285_termios_locked; -+ -+ rs285_driver.open = rs285_open; -+ rs285_driver.close = rs285_close; -+ rs285_driver.write = rs285_write; -+ rs285_driver.put_char = rs285_put_char; -+ rs285_driver.write_room = rs285_write_room; -+ rs285_driver.chars_in_buffer = rs285_chars_in_buffer; -+ rs285_driver.flush_buffer = rs285_flush_buffer; -+ rs285_driver.throttle = rs285_throttle; -+ rs285_driver.unthrottle = rs285_unthrottle; -+ rs285_driver.send_xchar = rs285_send_xchar; -+ rs285_driver.set_termios = rs285_set_termios; -+ rs285_driver.stop = rs285_stop; -+ rs285_driver.start = rs285_start; -+ rs285_driver.wait_until_sent = rs285_wait_until_sent; -+ -+ callout_driver = rs285_driver; -+ callout_driver.name = SERIAL_21285_AUXNAME; -+ callout_driver.major = SERIAL_21285_AUXMAJOR; -+ callout_driver.subtype = SERIAL_TYPE_CALLOUT; -+ -+#ifdef CONFIG_SERIAL_21285_OLD -+ if (!machine_is_ebsa285() && !machine_is_netwinder()) { -+ rs285_old_driver = rs285_driver; -+ rs285_old_driver.name = SERIAL_21285_OLD_NAME; -+ rs285_old_driver.major = SERIAL_21285_OLD_MAJOR; -+ rs285_old_driver.minor_start = SERIAL_21285_OLD_MINOR; -+ -+ if (tty_register_driver(&rs285_old_driver)) -+ printk(KERN_ERR "Couldn't register old 21285 serial driver\n"); -+ } -+#endif -+ -+ if (tty_register_driver(&rs285_driver)) -+ printk(KERN_ERR "Couldn't register 21285 serial driver\n"); -+ if (tty_register_driver(&callout_driver)) -+ printk(KERN_ERR "Couldn't register 21285 callout driver\n"); -+ -+ return 0; -+} -+ -+static void __exit rs285_fini(void) -+{ -+ unsigned long flags; -+ int ret; -+ -+ save_flags(flags); -+ cli(); -+ ret = tty_unregister_driver(&callout_driver); -+ if (ret) -+ printk(KERN_ERR "Unable to unregister 21285 callout driver " -+ "(%d)\n", ret); -+ ret = tty_unregister_driver(&rs285_driver); -+ if (ret) -+ printk(KERN_ERR "Unable to unregister 21285 driver (%d)\n", -+ ret); -+#ifdef CONFIG_SERIAL_21285_OLD -+ if (!machine_is_ebsa285() && !machine_is_netwinder()) { -+ ret = tty_unregister_driver(&rs285_old_driver); -+ if (ret) -+ printk(KERN_ERR "Unable to unregister old 21285 " -+ "driver (%d)\n", ret); -+ } -+#endif -+ free_irq(IRQ_CONTX, NULL); -+ free_irq(IRQ_CONRX, NULL); -+ restore_flags(flags); -+} -+ -+module_init(rs285_init); -+module_exit(rs285_fini); -+ -+#ifdef CONFIG_SERIAL_21285_CONSOLE -+/************** console driver *****************/ -+ -+static void rs285_console_write(struct console *co, const char *s, u_int count) -+{ -+ int i; -+ -+ rs285_stop_tx(); -+ for (i = 0; i < count; i++) { -+ while (*CSR_UARTFLG & 0x20); -+ *CSR_UARTDR = s[i]; -+ if (s[i] == '\n') { -+ while (*CSR_UARTFLG & 0x20); -+ *CSR_UARTDR = '\r'; -+ } -+ } -+ rs285_start_tx(); -+} -+ -+static kdev_t rs285_console_device(struct console *c) -+{ -+ return MKDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR); -+} -+ -+static int __init rs285_console_setup(struct console *co, char *options) -+{ -+ int baud = 9600; -+ int bits = 8; -+ int parity = 'n'; -+ int flow; -+ int cflag = CREAD | HUPCL | CLOCAL; -+ -+ if (machine_is_personal_server()) -+ baud = 57600; -+ -+ if (options) -+ uart_parse_options(options, &baud, &parity, &bits, &flow); -+ -+ /* -+ * Now construct a cflag setting. -+ */ -+ switch (baud) { -+ case 1200: -+ cflag |= B1200; -+ break; -+ case 2400: -+ cflag |= B2400; -+ break; -+ case 4800: -+ cflag |= B4800; -+ break; -+ case 9600: -+ cflag |= B9600; -+ break; -+ case 19200: -+ cflag |= B19200; -+ break; -+ case 38400: -+ cflag |= B38400; -+ break; -+ case 57600: -+ cflag |= B57600; -+ break; -+ case 115200: -+ cflag |= B115200; -+ break; -+ default: -+ cflag |= B9600; -+ break; -+ } -+ switch (bits) { -+ case 7: -+ cflag |= CS7; -+ break; -+ default: -+ cflag |= CS8; -+ break; -+ } -+ switch (parity) { -+ case 'o': -+ case 'O': -+ cflag |= PARODD; -+ break; -+ case 'e': -+ case 'E': -+ cflag |= PARENB; -+ break; -+ } -+ co->cflag = cflag; -+ rs285_set_cflag(cflag); -+ rs285_console_write(NULL, "\e[2J\e[Hboot ", 12); -+ if (options) -+ rs285_console_write(NULL, options, strlen(options)); -+ else -+ rs285_console_write(NULL, "no options", 10); -+ rs285_console_write(NULL, "\n", 1); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_SERIAL_21285_OLD -+static struct console rs285_old_cons = -+{ -+ SERIAL_21285_OLD_NAME, -+ rs285_console_write, -+ NULL, -+ rs285_console_device, -+ NULL, -+ rs285_console_setup, -+ CON_PRINTBUFFER, -+ -1, -+ 0, -+ NULL -+}; -+#endif -+ -+static struct console rs285_cons = -+{ -+ name: SERIAL_21285_NAME, -+ write: rs285_console_write, -+ device: rs285_console_device, -+ setup: rs285_console_setup, -+ flags: CON_PRINTBUFFER, -+ index: -1, -+}; -+ -+void __init rs285_console_init(void) -+{ -+#ifdef CONFIG_SERIAL_21285_OLD -+ if (!machine_is_ebsa285() && !machine_is_netwinder()) -+ register_console(&rs285_old_cons); -+#endif -+ register_console(&rs285_cons); -+} -+ -+#endif /* CONFIG_SERIAL_21285_CONSOLE */ -+ -+EXPORT_NO_SYMBOLS; -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver"); -diff -urN linux-2.4.26/drivers/serial/8250.c linux-2.4.26-vrs1/drivers/serial/8250.c ---- linux-2.4.26/drivers/serial/8250.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/serial/8250.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,2170 @@ -+/* -+ * linux/drivers/serial/8250.c -+ * -+ * Driver for 8250/16550-type serial ports -+ * -+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. -+ * -+ * Copyright (C) 2001 Russell King. -+ * -+ * 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. -+ * -+ * $Id: 8250.c,v 1.14.2.8 2002/10/24 14:31:31 rmk Exp $ -+ * -+ * A note about mapbase / membase -+ * -+ * mapbase is the physical address of the IO port. Currently, we don't -+ * support this very well, and it may well be dropped from this driver -+ * in future. As such, mapbase should be NULL. -+ * -+ * membase is an 'ioremapped' cookie. This is compatible with the old -+ * serial.c driver, and is currently the preferred form. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "8250.h" -+ -+/* -+ * Configuration: -+ * share_irqs - whether we pass SA_SHIRQ to request_irq(). This option -+ * is unsafe when used on edge-triggered interrupts. -+ */ -+unsigned int share_irqs = SERIAL8250_SHARE_IRQS; -+ -+/* -+ * Debugging. -+ */ -+#if 0 -+#define DEBUG_AUTOCONF(fmt...) printk(fmt) -+#else -+#define DEBUG_AUTOCONF(fmt...) do { } while (0) -+#endif -+ -+#if 0 -+#define DEBUG_INTR(fmt...) printk(fmt) -+#else -+#define DEBUG_INTR(fmt...) do { } while (0) -+#endif -+ -+#define PASS_LIMIT 256 -+ -+/* -+ * We default to IRQ0 for the "no irq" hack. Some -+ * machine types want others as well - they're free -+ * to redefine this in their header file. -+ */ -+#define is_real_interrupt(irq) ((irq) != 0) -+ -+/* -+ * This converts from our new CONFIG_ symbols to the symbols -+ * that asm/serial.h expects. You _NEED_ to comment out the -+ * linux/config.h include contained inside asm/serial.h for -+ * this to work. -+ */ -+#undef CONFIG_SERIAL_MANY_PORTS -+#undef CONFIG_SERIAL_DETECT_IRQ -+#undef CONFIG_SERIAL_MULTIPORT -+#undef CONFIG_HUB6 -+ -+#ifdef CONFIG_SERIAL_8250_DETECT_IRQ -+#define CONFIG_SERIAL_DETECT_IRQ 1 -+#endif -+#ifdef CONFIG_SERIAL_8250_MULTIPORT -+#define CONFIG_SERIAL_MULTIPORT 1 -+#endif -+#ifdef CONFIG_SERIAL_8250_HUB6 -+#define CONFIG_HUB6 1 -+#endif -+#ifdef CONFIG_SERIAL_8250_MANY_PORTS -+#define CONFIG_SERIAL_MANY_PORTS 1 -+#endif -+ -+#include -+ -+static struct old_serial_port old_serial_port[] = { -+ SERIAL_PORT_DFNS /* defined in asm/serial.h */ -+}; -+ -+#define UART_NR ARRAY_SIZE(old_serial_port) -+ -+static struct tty_driver normal, callout; -+static struct tty_struct *serial8250_table[UART_NR]; -+static struct termios *serial8250_termios[UART_NR], *serial8250_termios_locked[UART_NR]; -+ -+#if defined(CONFIG_SERIAL_8250_RSA) && defined(MODULE) -+ -+#define PORT_RSA_MAX 4 -+static int probe_rsa[PORT_RSA_MAX]; -+static int force_rsa[PORT_RSA_MAX]; -+#endif /* CONFIG_SERIAL_8250_RSA */ -+ -+struct uart_8250_port { -+ struct uart_port port; -+ struct timer_list timer; /* "no irq" timer */ -+ struct list_head list; /* ports on this IRQ */ -+ unsigned int capabilities; /* port capabilities */ -+ unsigned char acr; -+ unsigned char ier; -+ unsigned short rev; -+ unsigned char lcr; -+ unsigned char mcr; -+ unsigned char mcr_mask; /* mask of user bits */ -+ unsigned char mcr_force; /* mask of forced bits */ -+ unsigned char efr; -+ unsigned int lsr_break_flag; -+ -+ /* -+ * We provide a per-port pm hook. -+ */ -+ void (*pm)(struct uart_port *port, -+ unsigned int state, unsigned int old); -+}; -+ -+struct irq_info { -+ spinlock_t lock; -+ struct list_head *head; -+}; -+ -+static struct irq_info irq_lists[NR_IRQS]; -+ -+/* -+ * Here we define the default xmit fifo size used for each type of UART. -+ */ -+static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = { -+ { "unknown", 1, 0 }, -+ { "8250", 1, 0 }, -+ { "16450", 1, 0 }, -+ { "16550", 1, 0 }, -+ { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, -+ { "Cirrus", 1, 0 }, -+ { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, -+ { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, -+ { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO }, -+ { "Startech", 1, 0 }, -+ { "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO }, -+ { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, -+ { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, -+ { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO } -+}; -+ -+static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset) -+{ -+ offset <<= up->port.regshift; -+ -+ switch (up->port.iotype) { -+#ifdef CONFIG_SERIAL_8250_HUB6 -+ case SERIAL_IO_HUB6: -+ outb(up->port.hub6 - 1 + offset, up->port.iobase); -+ return inb(up->port.iobase + 1); -+#endif -+ -+ case SERIAL_IO_MEM: -+ return readb(up->port.membase + offset); -+ -+ default: -+ return inb(up->port.iobase + offset); -+ } -+} -+ -+static _INLINE_ void -+serial_out(struct uart_8250_port *up, int offset, int value) -+{ -+ offset <<= up->port.regshift; -+ -+ switch (up->port.iotype) { -+#ifdef CONFIG_SERIAL_8250_HUB6 -+ case SERIAL_IO_HUB6: -+ outb(up->port.hub6 - 1 + offset, up->port.iobase); -+ outb(value, up->port.iobase + 1); -+ break; -+#endif -+ -+ case SERIAL_IO_MEM: -+ writeb(value, up->port.membase + offset); -+ break; -+ -+ default: -+ outb(value, up->port.iobase + offset); -+ } -+} -+ -+/* -+ * We used to support using pause I/O for certain machines. We -+ * haven't supported this for a while, but just in case it's badly -+ * needed for certain old 386 machines, I've left these #define's -+ * in.... -+ */ -+#define serial_inp(up, offset) serial_in(up, offset) -+#define serial_outp(up, offset, value) serial_out(up, offset, value) -+ -+ -+/* -+ * For the 16C950 -+ */ -+static void serial_icr_write(struct uart_8250_port *up, int offset, int value) -+{ -+ serial_out(up, UART_SCR, offset); -+ serial_out(up, UART_ICR, value); -+} -+ -+static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) -+{ -+ unsigned int value; -+ -+ serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD); -+ serial_out(up, UART_SCR, offset); -+ value = serial_in(up, UART_ICR); -+ serial_icr_write(up, UART_ACR, up->acr); -+ -+ return value; -+} -+ -+#ifdef CONFIG_SERIAL_8250_RSA -+/* -+ * Attempts to turn on the RSA FIFO. Returns zero on failure. -+ * We set the port uart clock rate if we succeed. -+ */ -+static int __enable_rsa(struct uart_8250_port *up) -+{ -+ unsigned char mode; -+ int result; -+ -+ mode = serial_inp(up, UART_RSA_MSR); -+ result = mode & UART_RSA_MSR_FIFO; -+ -+ if (!result) { -+ serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); -+ mode = serial_inp(up, UART_RSA_MSR); -+ result = mode & UART_RSA_MSR_FIFO; -+ } -+ -+ if (result) -+ up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16; -+ -+ return result; -+} -+ -+static void enable_rsa(struct uart_8250_port *up) -+{ -+ if (up->port.type == PORT_RSA) { -+ if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { -+ spin_lock_irq(&up->port.lock); -+ __enable_rsa(up); -+ spin_unlock_irq(&up->port.lock); -+ } -+ if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) -+ serial_outp(up, UART_RSA_FRR, 0); -+ } -+} -+ -+/* -+ * Attempts to turn off the RSA FIFO. Returns zero on failure. -+ * It is unknown why interrupts were disabled in here. However, -+ * the caller is expected to preserve this behaviour by grabbing -+ * the spinlock before calling this function. -+ */ -+static void disable_rsa(struct uart_8250_port *up) -+{ -+ unsigned char mode; -+ int result; -+ -+ if (up->port.type == PORT_RSA && -+ up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { -+ spin_lock_irq(&up->port.lock); -+ -+ mode = serial_inp(up, UART_RSA_MSR); -+ result = !(mode & UART_RSA_MSR_FIFO); -+ -+ if (!result) { -+ serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); -+ mode = serial_inp(up, UART_RSA_MSR); -+ result = !(mode & UART_RSA_MSR_FIFO); -+ } -+ -+ if (result) -+ up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; -+ spin_unlock_irq(&up->port.lock); -+ } -+} -+#endif /* CONFIG_SERIAL_8250_RSA */ -+ -+/* -+ * This is a quickie test to see how big the FIFO is. -+ * It doesn't work at all the time, more's the pity. -+ */ -+static int size_fifo(struct uart_8250_port *up) -+{ -+ unsigned char old_fcr, old_mcr, old_dll, old_dlm; -+ int count; -+ -+ old_fcr = serial_inp(up, UART_FCR); -+ old_mcr = serial_inp(up, UART_MCR); -+ serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | -+ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); -+ serial_outp(up, UART_MCR, UART_MCR_LOOP); -+ serial_outp(up, UART_LCR, UART_LCR_DLAB); -+ old_dll = serial_inp(up, UART_DLL); -+ old_dlm = serial_inp(up, UART_DLM); -+ serial_outp(up, UART_DLL, 0x01); -+ serial_outp(up, UART_DLM, 0x00); -+ serial_outp(up, UART_LCR, 0x03); -+ for (count = 0; count < 256; count++) -+ serial_outp(up, UART_TX, count); -+ mdelay(20);/* FIXME - schedule_timeout */ -+ for (count = 0; (serial_inp(up, UART_LSR) & UART_LSR_DR) && -+ (count < 256); count++) -+ serial_inp(up, UART_RX); -+ serial_outp(up, UART_FCR, old_fcr); -+ serial_outp(up, UART_MCR, old_mcr); -+ serial_outp(up, UART_LCR, UART_LCR_DLAB); -+ serial_outp(up, UART_DLL, old_dll); -+ serial_outp(up, UART_DLM, old_dlm); -+ -+ return count; -+} -+ -+/* -+ * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's. -+ * When this function is called we know it is at least a StarTech -+ * 16650 V2, but it might be one of several StarTech UARTs, or one of -+ * its clones. (We treat the broken original StarTech 16650 V1 as a -+ * 16550, and why not? Startech doesn't seem to even acknowledge its -+ * existence.) -+ * -+ * What evil have men's minds wrought... -+ */ -+static void autoconfig_has_efr(struct uart_8250_port *up) -+{ -+ unsigned char id1, id2, id3, rev, saved_dll, saved_dlm; -+ -+ /* -+ * First we check to see if it's an Oxford Semiconductor UART. -+ * -+ * If we have to do this here because some non-National -+ * Semiconductor clone chips lock up if you try writing to the -+ * LSR register (which serial_icr_read does) -+ */ -+ -+ /* -+ * Check for Oxford Semiconductor 16C950. -+ * -+ * EFR [4] must be set else this test fails. -+ * -+ * This shouldn't be necessary, but Mike Hudson (Exoray@isys.ca) -+ * claims that it's needed for 952 dual UART's (which are not -+ * recommended for new designs). -+ */ -+ up->acr = 0; -+ serial_out(up, UART_LCR, 0xBF); -+ serial_out(up, UART_EFR, 0x10); -+ serial_out(up, UART_LCR, 0x00); -+ id1 = serial_icr_read(up, UART_ID1); -+ id2 = serial_icr_read(up, UART_ID2); -+ id3 = serial_icr_read(up, UART_ID3); -+ rev = serial_icr_read(up, UART_REV); -+ -+ DEBUG_AUTOCONF("950id=%02x:%02x:%02x:%02x ", id1, id2, id3, rev); -+ -+ if (id1 == 0x16 && id2 == 0xC9 && -+ (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) { -+ up->port.type = PORT_16C950; -+ up->rev = rev | (id3 << 8); -+ return; -+ } -+ -+ /* -+ * We check for a XR16C850 by setting DLL and DLM to 0, and then -+ * reading back DLL and DLM. The chip type depends on the DLM -+ * value read back: -+ * 0x10 - XR16C850 and the DLL contains the chip revision. -+ * 0x12 - XR16C2850. -+ * 0x14 - XR16C854. -+ */ -+ serial_outp(up, UART_LCR, UART_LCR_DLAB); -+ saved_dll = serial_inp(up, UART_DLL); -+ saved_dlm = serial_inp(up, UART_DLM); -+ serial_outp(up, UART_DLL, 0); -+ serial_outp(up, UART_DLM, 0); -+ id2 = serial_inp(up, UART_DLL); -+ id1 = serial_inp(up, UART_DLM); -+ serial_outp(up, UART_DLL, saved_dll); -+ serial_outp(up, UART_DLM, saved_dlm); -+ -+ DEBUG_AUTOCONF("850id=%02x:%02x ", id1, id2); -+ -+ if (id1 == 0x10 || id1 == 0x12 || id1 == 0x14) { -+ if (id1 == 0x10) -+ up->rev = id2; -+ up->port.type = PORT_16850; -+ return; -+ } -+ -+ /* -+ * It wasn't an XR16C850. -+ * -+ * We distinguish between the '654 and the '650 by counting -+ * how many bytes are in the FIFO. I'm using this for now, -+ * since that's the technique that was sent to me in the -+ * serial driver update, but I'm not convinced this works. -+ * I've had problems doing this in the past. -TYT -+ */ -+ if (size_fifo(up) == 64) -+ up->port.type = PORT_16654; -+ else -+ up->port.type = PORT_16650V2; -+} -+ -+/* -+ * We detected a chip without a FIFO. Only two fall into -+ * this category - the original 8250 and the 16450. The -+ * 16450 has a scratch register (accessible with LCR=0) -+ */ -+static void autoconfig_8250(struct uart_8250_port *up) -+{ -+ unsigned char scratch, status1, status2; -+ -+ up->port.type = PORT_8250; -+ -+ scratch = serial_in(up, UART_SCR); -+ serial_outp(up, UART_SCR, 0xa5); -+ status1 = serial_in(up, UART_SCR); -+ serial_outp(up, UART_SCR, 0x5a); -+ status2 = serial_in(up, UART_SCR); -+ serial_outp(up, UART_SCR, scratch); -+ -+ if (status1 == 0xa5 && status2 == 0x5a) -+ up->port.type = PORT_16450; -+} -+ -+/* -+ * We know that the chip has FIFOs. Does it have an EFR? The -+ * EFR is located in the same register position as the IIR and -+ * we know the top two bits of the IIR are currently set. The -+ * EFR should contain zero. Try to read the EFR. -+ */ -+static void autoconfig_16550a(struct uart_8250_port *up) -+{ -+ unsigned char status1, status2; -+ -+ up->port.type = PORT_16550A; -+ -+ /* -+ * Check for presence of the EFR when DLAB is set. -+ * Only ST16C650V1 UARTs pass this test. -+ */ -+ serial_outp(up, UART_LCR, UART_LCR_DLAB); -+ if (serial_in(up, UART_EFR) == 0) { -+ DEBUG_AUTOCONF("EFRv1 "); -+ up->port.type = PORT_16650; -+ return; -+ } -+ -+ /* -+ * Maybe it requires 0xbf to be written to the LCR. -+ * (other ST16C650V2 UARTs, TI16C752A, etc) -+ */ -+ serial_outp(up, UART_LCR, 0xBF); -+ if (serial_in(up, UART_EFR) == 0) { -+ DEBUG_AUTOCONF("EFRv2 "); -+ autoconfig_has_efr(up); -+ return; -+ } -+ -+ /* -+ * Check for a National Semiconductor SuperIO chip. -+ * Attempt to switch to bank 2, read the value of the LOOP bit -+ * from EXCR1. Switch back to bank 0, change it in MCR. Then -+ * switch back to bank 2, read it from EXCR1 again and check -+ * it's changed. If so, set baud_base in EXCR2 to 921600. -+ */ -+ serial_outp(up, UART_LCR, 0); -+ status1 = serial_in(up, UART_MCR); -+ serial_outp(up, UART_LCR, 0xE0); -+ status2 = serial_in(up, 0x02); /* EXCR1 */ -+ -+ if (!((status2 ^ status1) & UART_MCR_LOOP)) { -+ serial_outp(up, UART_LCR, 0); -+ serial_outp(up, UART_MCR, status1 ^ UART_MCR_LOOP); -+ serial_outp(up, UART_LCR, 0xE0); -+ status2 = serial_in(up, 0x02); /* EXCR1 */ -+ serial_outp(up, UART_LCR, 0); -+ serial_outp(up, UART_MCR, status1); -+ -+ if ((status2 ^ status1) & UART_MCR_LOOP) { -+ serial_outp(up, UART_LCR, 0xE0); -+ status1 = serial_in(up, 0x04); /* EXCR1 */ -+ status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ -+ status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ -+ serial_outp(up, 0x04, status1); -+ serial_outp(up, UART_LCR, 0); -+ -+ up->port.type = PORT_NS16550A; -+ up->port.uartclk = 921600*16; -+ return; -+ } -+ } -+ -+ /* -+ * No EFR. Try to detect a TI16750, which only sets bit 5 of -+ * the IIR when 64 byte FIFO mode is enabled when DLAB is set. -+ * Try setting it with and without DLAB set. Cheap clones -+ * set bit 5 without DLAB set. -+ */ -+ serial_outp(up, UART_LCR, 0); -+ serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); -+ status1 = serial_in(up, UART_IIR) >> 5; -+ serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); -+ serial_outp(up, UART_LCR, UART_LCR_DLAB); -+ serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); -+ status2 = serial_in(up, UART_IIR) >> 5; -+ serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); -+ -+ DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2); -+ -+ if (status1 == 6 && status2 == 7) { -+ up->port.type = PORT_16750; -+ return; -+ } -+} -+ -+/* -+ * This routine is called by rs_init() to initialize a specific serial -+ * port. It determines what type of UART chip this serial port is -+ * using: 8250, 16450, 16550, 16550A. The important question is -+ * whether or not this UART is a 16550A or not, since this will -+ * determine whether or not we can use its FIFO features or not. -+ */ -+static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) -+{ -+ unsigned char status1, scratch, scratch2, scratch3; -+ unsigned char save_lcr, save_mcr; -+ unsigned long flags; -+ -+ if (!up->port.iobase && !up->port.mapbase && !up->port.membase) -+ return; -+ -+ DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%p): ", -+ up->port.line, up->port.iobase, up->port.membase); -+ -+ /* -+ * We really do need global IRQs disabled here - we're going to -+ * be frobbing the chips IRQ enable register to see if it exists. -+ */ -+ spin_lock_irqsave(&up->port.lock, flags); -+ -+ if (!(up->port.flags & UPF_BUGGY_UART)) { -+ /* -+ * Do a simple existence test first; if we fail this, -+ * there's no point trying anything else. -+ * -+ * 0x80 is used as a nonsense port to prevent against -+ * false positives due to ISA bus float. The -+ * assumption is that 0x80 is a non-existent port; -+ * which should be safe since include/asm/io.h also -+ * makes this assumption. -+ * -+ * Note: this is safe as long as MCR bit 4 is clear -+ * and the device is in "PC" mode. -+ */ -+ scratch = serial_inp(up, UART_IER); -+ serial_outp(up, UART_IER, 0); -+#ifdef __i386__ -+ outb(0xff, 0x080); -+#endif -+ scratch2 = serial_inp(up, UART_IER); -+ serial_outp(up, UART_IER, 0x0F); -+#ifdef __i386__ -+ outb(0, 0x080); -+#endif -+ scratch3 = serial_inp(up, UART_IER); -+ serial_outp(up, UART_IER, scratch); -+ if (scratch2 != 0 || scratch3 != 0x0F) { -+ /* -+ * We failed; there's nothing here -+ */ -+ DEBUG_AUTOCONF("IER test failed (%02x, %02x) ", -+ scratch2, scratch3); -+ goto out; -+ } -+ } -+ -+ save_mcr = serial_in(up, UART_MCR); -+ save_lcr = serial_in(up, UART_LCR); -+ -+ /* -+ * Check to see if a UART is really there. Certain broken -+ * internal modems based on the Rockwell chipset fail this -+ * test, because they apparently don't implement the loopback -+ * test mode. So this test is skipped on the COM 1 through -+ * COM 4 ports. This *should* be safe, since no board -+ * manufacturer would be stupid enough to design a board -+ * that conflicts with COM 1-4 --- we hope! -+ */ -+ if (!(up->port.flags & UPF_SKIP_TEST)) { -+ serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A); -+ status1 = serial_inp(up, UART_MSR) & 0xF0; -+ serial_outp(up, UART_MCR, save_mcr); -+ if (status1 != 0x90) { -+ DEBUG_AUTOCONF("LOOP test failed (%02x) ", -+ status1); -+ goto out; -+ } -+ } -+ -+ /* -+ * We're pretty sure there's a port here. Lets find out what -+ * type of port it is. The IIR top two bits allows us to find -+ * out if its 8250 or 16450, 16550, 16550A or later. This -+ * determines what we test for next. -+ * -+ * We also initialise the EFR (if any) to zero for later. The -+ * EFR occupies the same register location as the FCR and IIR. -+ */ -+ serial_outp(up, UART_LCR, 0xBF); -+ serial_outp(up, UART_EFR, 0); -+ serial_outp(up, UART_LCR, 0); -+ -+ serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); -+ scratch = serial_in(up, UART_IIR) >> 6; -+ -+ DEBUG_AUTOCONF("iir=%d ", scratch); -+ -+ switch (scratch) { -+ case 0: -+ autoconfig_8250(up); -+ break; -+ case 1: -+ up->port.type = PORT_UNKNOWN; -+ break; -+ case 2: -+ up->port.type = PORT_16550; -+ break; -+ case 3: -+ autoconfig_16550a(up); -+ break; -+ } -+ -+#if defined(CONFIG_SERIAL_8250_RSA) && defined(MODULE) -+ /* -+ * Only probe for RSA ports if we got the region. -+ */ -+ if (up->port.type == PORT_16550A && probeflags & PROBE_RSA) { -+ int i; -+ -+ for (i = 0 ; i < PORT_RSA_MAX ; ++i) { -+ if (!probe_rsa[i] && !force_rsa[i]) -+ break; -+ if (((probe_rsa[i] != up->port.iobase) || -+ check_region(up->port.iobase + UART_RSA_BASE, 16)) && -+ (force_rsa[i] != up->port.iobase)) -+ continue; -+ if (__enable_rsa(up)) { -+ up->port.type = PORT_RSA; -+ break; -+ } -+ } -+ } -+#endif -+ serial_outp(up, UART_LCR, save_lcr); -+ -+ up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size; -+ up->capabilities = uart_config[up->port.type].flags; -+ -+ if (up->port.type == PORT_UNKNOWN) -+ goto out; -+ -+ /* -+ * Reset the UART. -+ */ -+#ifdef CONFIG_SERIAL_8250_RSA -+ if (up->port.type == PORT_RSA) -+ serial_outp(up, UART_RSA_FRR, 0); -+#endif -+ serial_outp(up, UART_MCR, save_mcr); -+ serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO | -+ UART_FCR_CLEAR_RCVR | -+ UART_FCR_CLEAR_XMIT)); -+ serial_outp(up, UART_FCR, 0); -+ (void)serial_in(up, UART_RX); -+ serial_outp(up, UART_IER, 0); -+ -+ out: -+ spin_unlock_irqrestore(&up->port.lock, flags); -+ -+#ifdef CONFIG_SERIAL_8250_RSA -+ if (up->port.iobase && up->port.type == PORT_RSA) { -+ release_region(up->port.iobase, 8); -+ request_region(up->port.iobase + UART_RSA_BASE, 16, -+ "serial_rsa"); -+ } -+#endif -+ DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name); -+} -+ -+static void autoconfig_irq(struct uart_8250_port *up) -+{ -+ unsigned char save_mcr, save_ier; -+ unsigned char save_ICP = 0; -+ unsigned int ICP = 0; -+ unsigned long irqs; -+ int irq; -+ -+ if (up->port.flags & UPF_FOURPORT) { -+ ICP = (up->port.iobase & 0xfe0) | 0x1f; -+ save_ICP = inb_p(ICP); -+ outb_p(0x80, ICP); -+ (void) inb_p(ICP); -+ } -+ -+ /* forget possible initially masked and pending IRQ */ -+ probe_irq_off(probe_irq_on()); -+ save_mcr = serial_inp(up, UART_MCR); -+ save_ier = serial_inp(up, UART_IER); -+ serial_outp(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); -+ -+ irqs = probe_irq_on(); -+ serial_outp(up, UART_MCR, 0); -+ udelay (10); -+ if (up->port.flags & UPF_FOURPORT) { -+ serial_outp(up, UART_MCR, -+ UART_MCR_DTR | UART_MCR_RTS); -+ } else { -+ serial_outp(up, UART_MCR, -+ UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); -+ } -+ serial_outp(up, UART_IER, 0x0f); /* enable all intrs */ -+ (void)serial_inp(up, UART_LSR); -+ (void)serial_inp(up, UART_RX); -+ (void)serial_inp(up, UART_IIR); -+ (void)serial_inp(up, UART_MSR); -+ serial_outp(up, UART_TX, 0xFF); -+ udelay (20); -+ irq = probe_irq_off(irqs); -+ -+ serial_outp(up, UART_MCR, save_mcr); -+ serial_outp(up, UART_IER, save_ier); -+ -+ if (up->port.flags & UPF_FOURPORT) -+ outb_p(save_ICP, ICP); -+ -+ up->port.irq = (irq > 0) ? irq : 0; -+} -+ -+static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop) -+{ -+ struct uart_8250_port *up = (struct uart_8250_port *)port; -+ -+ if (up->ier & UART_IER_THRI) { -+ up->ier &= ~UART_IER_THRI; -+ serial_out(up, UART_IER, up->ier); -+ } -+ if (up->port.type == PORT_16C950 && tty_stop) { -+ up->acr |= UART_ACR_TXDIS; -+ serial_icr_write(up, UART_ACR, up->acr); -+ } -+} -+ -+static void serial8250_start_tx(struct uart_port *port, unsigned int tty_start) -+{ -+ struct uart_8250_port *up = (struct uart_8250_port *)port; -+ -+ if (!(up->ier & UART_IER_THRI)) { -+ up->ier |= UART_IER_THRI; -+ serial_out(up, UART_IER, up->ier); -+ } -+ /* -+ * We only do this from uart_start -+ */ -+ if (tty_start && up->port.type == PORT_16C950) { -+ up->acr &= ~UART_ACR_TXDIS; -+ serial_icr_write(up, UART_ACR, up->acr); -+ } -+} -+ -+static void serial8250_stop_rx(struct uart_port *port) -+{ -+ struct uart_8250_port *up = (struct uart_8250_port *)port; -+ -+ up->ier &= ~UART_IER_RLSI; -+ up->port.read_status_mask &= ~UART_LSR_DR; -+ serial_out(up, UART_IER, up->ier); -+} -+ -+static void serial8250_enable_ms(struct uart_port *port) -+{ -+ struct uart_8250_port *up = (struct uart_8250_port *)port; -+ -+ up->ier |= UART_IER_MSI; -+ serial_out(up, UART_IER, up->ier); -+} -+ -+static _INLINE_ void -+receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) -+{ -+ struct tty_struct *tty = up->port.info->tty; -+ unsigned char ch; -+ int max_count = 256; -+ -+ do { -+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) { -+ /* -+ * FIXME: Deadlock can happen here if we're a -+ * low-latency port. We're holding the per-port -+ * spinlock, and we call flush_to_ldisc-> -+ * n_tty_receive_buf->n_tty_receive_char-> -+ * opost->uart_put_char. -+ */ -+ tty->flip.tqueue.routine((void *)tty); -+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) -+ return; // if TTY_DONT_FLIP is set -+ } -+ ch = serial_inp(up, UART_RX); -+ *tty->flip.char_buf_ptr = ch; -+ *tty->flip.flag_buf_ptr = TTY_NORMAL; -+ up->port.icount.rx++; -+ -+ if (*status & (UART_LSR_BI | UART_LSR_PE | -+ UART_LSR_FE | UART_LSR_OE)) { -+ /* -+ * For statistics only -+ */ -+ if (*status & UART_LSR_BI) { -+ *status &= ~(UART_LSR_FE | UART_LSR_PE); -+ up->port.icount.brk++; -+ /* -+ * We do the SysRQ and SAK checking -+ * here because otherwise the break -+ * may get masked by ignore_status_mask -+ * or read_status_mask. -+ */ -+ if (uart_handle_break(&up->port)) -+ goto ignore_char; -+ } else if (*status & UART_LSR_PE) -+ up->port.icount.parity++; -+ else if (*status & UART_LSR_FE) -+ up->port.icount.frame++; -+ if (*status & UART_LSR_OE) -+ up->port.icount.overrun++; -+ -+ /* -+ * Mask off conditions which should be ingored. -+ */ -+ *status &= up->port.read_status_mask; -+ -+#ifdef CONFIG_SERIAL_8250_CONSOLE -+ if (up->port.line == up->port.cons->index) { -+ /* Recover the break flag from console xmit */ -+ *status |= up->lsr_break_flag; -+ up->lsr_break_flag = 0; -+ } -+#endif -+ if (*status & UART_LSR_BI) { -+ DEBUG_INTR("handling break...."); -+ *tty->flip.flag_buf_ptr = TTY_BREAK; -+ } else if (*status & UART_LSR_PE) -+ *tty->flip.flag_buf_ptr = TTY_PARITY; -+ else if (*status & UART_LSR_FE) -+ *tty->flip.flag_buf_ptr = TTY_FRAME; -+ } -+ if (uart_handle_sysrq_char(&up->port, ch, regs)) -+ goto ignore_char; -+ if ((*status & up->port.ignore_status_mask) == 0) { -+ tty->flip.flag_buf_ptr++; -+ tty->flip.char_buf_ptr++; -+ tty->flip.count++; -+ } -+ if ((*status & UART_LSR_OE) && -+ tty->flip.count < TTY_FLIPBUF_SIZE) { -+ /* -+ * Overrun is special, since it's reported -+ * immediately, and doesn't affect the current -+ * character. -+ */ -+ *tty->flip.flag_buf_ptr = TTY_OVERRUN; -+ tty->flip.flag_buf_ptr++; -+ tty->flip.char_buf_ptr++; -+ tty->flip.count++; -+ } -+ ignore_char: -+ *status = serial_inp(up, UART_LSR); -+ } while ((*status & UART_LSR_DR) && (max_count-- > 0)); -+ tty_flip_buffer_push(tty); -+} -+ -+static _INLINE_ void transmit_chars(struct uart_8250_port *up) -+{ -+ struct circ_buf *xmit = &up->port.info->xmit; -+ int count; -+ -+ if (up->port.x_char) { -+ serial_outp(up, UART_TX, up->port.x_char); -+ up->port.icount.tx++; -+ up->port.x_char = 0; -+ return; -+ } -+ if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { -+ serial8250_stop_tx(&up->port, 0); -+ return; -+ } -+ -+ count = up->port.fifosize; -+ do { -+ serial_out(up, UART_TX, xmit->buf[xmit->tail]); -+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); -+ up->port.icount.tx++; -+ if (uart_circ_empty(xmit)) -+ break; -+ } while (--count > 0); -+ -+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) -+ uart_write_wakeup(&up->port); -+ -+ DEBUG_INTR("THRE..."); -+ -+ if (uart_circ_empty(xmit)) -+ serial8250_stop_tx(&up->port, 0); -+} -+ -+static _INLINE_ void check_modem_status(struct uart_8250_port *up) -+{ -+ int status; -+ -+ status = serial_in(up, UART_MSR); -+ -+ if ((status & UART_MSR_ANY_DELTA) == 0) -+ return; -+ -+ if (status & UART_MSR_TERI) -+ up->port.icount.rng++; -+ if (status & UART_MSR_DDSR) -+ up->port.icount.dsr++; -+ if (status & UART_MSR_DDCD) -+ uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); -+ if (status & UART_MSR_DCTS) -+ uart_handle_cts_change(&up->port, status & UART_MSR_CTS); -+ -+ wake_up_interruptible(&up->port.info->delta_msr_wait); -+} -+ -+/* -+ * This handles the interrupt from one port. -+ */ -+static inline void -+serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs) -+{ -+ unsigned int status = serial_inp(up, UART_LSR); -+ -+ DEBUG_INTR("status = %x...", status); -+ -+ if (status & UART_LSR_DR) -+ receive_chars(up, &status, regs); -+ check_modem_status(up); -+ if (status & UART_LSR_THRE) -+ transmit_chars(up); -+} -+ -+/* -+ * This is the serial driver's interrupt routine. -+ * -+ * Arjan thinks the old way was overly complex, so it got simplified. -+ * Alan disagrees, saying that need the complexity to handle the weird -+ * nature of ISA shared interrupts. (This is a special exception.) -+ * -+ * In order to handle ISA shared interrupts properly, we need to check -+ * that all ports have been serviced, and therefore the ISA interrupt -+ * line has been de-asserted. -+ * -+ * This means we need to loop through all ports. checking that they -+ * don't have an interrupt pending. -+ */ -+static void serial8250_interrupt(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ struct irq_info *i = dev_id; -+ struct list_head *l, *end = NULL; -+ int pass_counter = 0; -+ -+ DEBUG_INTR("serial8250_interrupt(%d)...", irq); -+ -+ spin_lock(&i->lock); -+ -+ l = i->head; -+ do { -+ struct uart_8250_port *up; -+ unsigned int iir; -+ -+ up = list_entry(l, struct uart_8250_port, list); -+ -+ iir = serial_in(up, UART_IIR); -+ if (!(iir & UART_IIR_NO_INT)) { -+ spin_lock(&up->port.lock); -+ serial8250_handle_port(up, regs); -+ spin_unlock(&up->port.lock); -+ -+ end = NULL; -+ } else if (end == NULL) -+ end = l; -+ -+ l = l->next; -+ -+ if (l == i->head && pass_counter++ > PASS_LIMIT) { -+ /* If we hit this, we're dead. */ -+ printk(KERN_ERR "serial8250: too much work for " -+ "irq%d\n", irq); -+ break; -+ } -+ } while (l != end); -+ -+ spin_unlock(&i->lock); -+ -+ DEBUG_INTR("end.\n"); -+} -+ -+/* -+ * To support ISA shared interrupts, we need to have one interrupt -+ * handler that ensures that the IRQ line has been deasserted -+ * before returning. Failing to do this will result in the IRQ -+ * line being stuck active, and, since ISA irqs are edge triggered, -+ * no more IRQs will be seen. -+ */ -+static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up) -+{ -+ spin_lock_irq(&i->lock); -+ -+ if (!list_empty(i->head)) { -+ if (i->head == &up->list) -+ i->head = i->head->next; -+ list_del(&up->list); -+ } else { -+ BUG_ON(i->head != &up->list); -+ i->head = NULL; -+ } -+ -+ spin_unlock_irq(&i->lock); -+} -+ -+static int serial_link_irq_chain(struct uart_8250_port *up) -+{ -+ struct irq_info *i = irq_lists + up->port.irq; -+ int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? SA_SHIRQ : 0; -+ -+ spin_lock_irq(&i->lock); -+ -+ if (i->head) { -+ list_add(&up->list, i->head); -+ spin_unlock_irq(&i->lock); -+ -+ ret = 0; -+ } else { -+ INIT_LIST_HEAD(&up->list); -+ i->head = &up->list; -+ spin_unlock_irq(&i->lock); -+ -+ ret = request_irq(up->port.irq, serial8250_interrupt, -+ irq_flags, "serial", i); -+ if (ret < 0) -+ serial_do_unlink(i, up); -+ } -+ -+ return ret; -+} -+ -+static void serial_unlink_irq_chain(struct uart_8250_port *up) -+{ -+ struct irq_info *i = irq_lists + up->port.irq; -+ -+ BUG_ON(i->head == NULL); -+ -+ if (list_empty(i->head)) -+ free_irq(up->port.irq, i); -+ -+ serial_do_unlink(i, up); -+} -+ -+/* -+ * This function is used to handle ports that do not have an -+ * interrupt. This doesn't work very well for 16450's, but gives -+ * barely passable results for a 16550A. (Although at the expense -+ * of much CPU overhead). -+ */ -+static void serial8250_timeout(unsigned long data) -+{ -+ struct uart_8250_port *up = (struct uart_8250_port *)data; -+ unsigned int timeout; -+ unsigned int iir; -+ -+ iir = serial_in(up, UART_IIR); -+ if (!(iir & UART_IIR_NO_INT)) { -+ spin_lock(&up->port.lock); -+ serial8250_handle_port(up, NULL); -+ spin_unlock(&up->port.lock); -+ } -+ -+ timeout = up->port.timeout; -+ timeout = timeout > 6 ? (timeout / 2 - 2) : 1; -+ mod_timer(&up->timer, jiffies + timeout); -+} -+ -+static unsigned int serial8250_tx_empty(struct uart_port *port) -+{ -+ struct uart_8250_port *up = (struct uart_8250_port *)port; -+ unsigned long flags; -+ unsigned int ret; -+ -+ spin_lock_irqsave(&up->port.lock, flags); -+ ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; -+ spin_unlock_irqrestore(&up->port.lock, flags); -+ -+ return ret; -+} -+ -+static unsigned int serial8250_get_mctrl(struct uart_port *port) -+{ -+ struct uart_8250_port *up = (struct uart_8250_port *)port; -+ unsigned long flags; -+ unsigned char status; -+ unsigned int ret; -+ -+ spin_lock_irqsave(&up->port.lock, flags); -+ status = serial_in(up, UART_MSR); -+ spin_unlock_irqrestore(&up->port.lock, flags); -+ -+ ret = 0; -+ if (status & UART_MSR_DCD) -+ ret |= TIOCM_CAR; -+ if (status & UART_MSR_RI) -+ ret |= TIOCM_RNG; -+ if (status & UART_MSR_DSR) -+ ret |= TIOCM_DSR; -+ if (status & UART_MSR_CTS) -+ ret |= TIOCM_CTS; -+ return ret; -+} -+ -+static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) -+{ -+ struct uart_8250_port *up = (struct uart_8250_port *)port; -+ unsigned char mcr = 0; -+ -+ if (mctrl & TIOCM_RTS) -+ mcr |= UART_MCR_RTS; -+ if (mctrl & TIOCM_DTR) -+ mcr |= UART_MCR_DTR; -+ if (mctrl & TIOCM_OUT1) -+ mcr |= UART_MCR_OUT1; -+ if (mctrl & TIOCM_OUT2) -+ mcr |= UART_MCR_OUT2; -+ if (mctrl & TIOCM_LOOP) -+ mcr |= UART_MCR_LOOP; -+ -+ mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; -+ -+ serial_out(up, UART_MCR, mcr); -+} -+ -+static void serial8250_break_ctl(struct uart_port *port, int break_state) -+{ -+ struct uart_8250_port *up = (struct uart_8250_port *)port; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&up->port.lock, flags); -+ if (break_state == -1) -+ up->lcr |= UART_LCR_SBC; -+ else -+ up->lcr &= ~UART_LCR_SBC; -+ serial_out(up, UART_LCR, up->lcr); -+ spin_unlock_irqrestore(&up->port.lock, flags); -+} -+ -+static int serial8250_startup(struct uart_port *port) -+{ -+ struct uart_8250_port *up = (struct uart_8250_port *)port; -+ unsigned long flags; -+ unsigned char lsr, iir; -+ int retval; -+ -+ up->capabilities = uart_config[up->port.type].flags; -+ up->mcr = 0; -+ up->efr = 0; -+ up->ier = 0; -+ -+ if (up->port.type == PORT_16C950) { -+ /* Wake up and initialize UART */ -+ up->acr = 0; -+ serial_outp(up, UART_LCR, 0xBF); -+ serial_outp(up, UART_EFR, UART_EFR_ECB); -+ serial_outp(up, UART_IER, 0); -+ serial_outp(up, UART_LCR, 0); -+ serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ -+ serial_outp(up, UART_LCR, 0xBF); -+ serial_outp(up, UART_EFR, UART_EFR_ECB); -+ serial_outp(up, UART_LCR, 0); -+ } -+ -+#ifdef CONFIG_SERIAL_8250_RSA -+ /* -+ * If this is an RSA port, see if we can kick it up to the -+ * higher speed clock. -+ */ -+ enable_rsa(up); -+#endif -+ -+ /* -+ * Clear the FIFO buffers and disable them. -+ * (they will be reeanbled in change_speed()) -+ */ -+ if (up->capabilities & UART_CLEAR_FIFO) { -+ serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); -+ serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | -+ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); -+ serial_outp(up, UART_FCR, 0); -+ } -+ -+ /* -+ * Clear the interrupt registers. -+ */ -+ (void) serial_inp(up, UART_LSR); -+ (void) serial_inp(up, UART_RX); -+ (void) serial_inp(up, UART_IIR); -+ (void) serial_inp(up, UART_MSR); -+ -+ /* -+ * At this point, there's no way the LSR could still be 0xff; -+ * if it is, then bail out, because there's likely no UART -+ * here. -+ */ -+ if (!(up->port.flags & UPF_BUGGY_UART) && -+ (serial_inp(up, UART_LSR) == 0xff)) { -+ printk("ttyS%d: LSR safety check engaged!\n", up->port.line); -+ return -ENODEV; -+ } -+ -+ /* -+ * If the "interrupt" for this port doesn't correspond with any -+ * hardware interrupt, we use a timer-based system. The original -+ * driver used to do this with IRQ0. -+ */ -+ if (!is_real_interrupt(up->port.irq)) { -+ unsigned int timeout = up->port.timeout; -+ -+ timeout = timeout > 6 ? (timeout / 2 - 2) : 1; -+ -+ up->timer.data = (unsigned long)up; -+ mod_timer(&up->timer, jiffies + timeout); -+ } else { -+ retval = serial_link_irq_chain(up); -+ if (retval) -+ return retval; -+ } -+ -+ /* -+ * Now, initialize the UART -+ */ -+ serial_outp(up, UART_LCR, UART_LCR_WLEN8); -+ -+ spin_lock_irqsave(&up->port.lock, flags); -+ if (up->port.flags & UPF_FOURPORT) { -+ if (!is_real_interrupt(up->port.irq)) -+ up->port.mctrl |= TIOCM_OUT1; -+ } else -+ /* -+ * Most PC uarts need OUT2 raised to enable interrupts. -+ */ -+ if (is_real_interrupt(up->port.irq)) -+ up->port.mctrl |= TIOCM_OUT2; -+ -+ serial8250_set_mctrl(&up->port, up->port.mctrl); -+ -+ /* -+ * Do a quick test to see if we receive an -+ * interrupt when we enable the TX irq. -+ */ -+ serial_outp(up, UART_IER, UART_IER_THRI); -+ lsr = serial_in(up, UART_LSR); -+ iir = serial_in(up, UART_IIR); -+ serial_outp(up, UART_IER, 0); -+ -+ if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { -+ up->capabilities |= UART_BAD_TX_ENABLE; -+ printk("ttyS%d - enabling bad tx status workarounds\n", -+ port->line); -+ } -+ -+ spin_unlock_irqrestore(&up->port.lock, flags); -+ -+ /* -+ * Finally, enable interrupts. Note: Modem status interrupts -+ * are set via change_speed(), which will be occuring imminently -+ * anyway, so we don't enable them here. -+ */ -+ up->ier = UART_IER_RLSI | UART_IER_RDI; -+ serial_outp(up, UART_IER, up->ier); -+ -+ if (up->port.flags & UPF_FOURPORT) { -+ unsigned int icp; -+ /* -+ * Enable interrupts on the AST Fourport board -+ */ -+ icp = (up->port.iobase & 0xfe0) | 0x01f; -+ outb_p(0x80, icp); -+ (void) inb_p(icp); -+ } -+ -+ /* -+ * And clear the interrupt registers again for luck. -+ */ -+ (void) serial_inp(up, UART_LSR); -+ (void) serial_inp(up, UART_RX); -+ (void) serial_inp(up, UART_IIR); -+ (void) serial_inp(up, UART_MSR); -+ -+ return 0; -+} -+ -+static void serial8250_shutdown(struct uart_port *port) -+{ -+ struct uart_8250_port *up = (struct uart_8250_port *)port; -+ unsigned long flags; -+ -+ /* -+ * Disable interrupts from this port -+ */ -+ up->ier = 0; -+ serial_outp(up, UART_IER, 0); -+ -+ spin_lock_irqsave(&up->port.lock, flags); -+ if (up->port.flags & UPF_FOURPORT) { -+ /* reset interrupts on the AST Fourport board */ -+ inb((up->port.iobase & 0xfe0) | 0x1f); -+ up->port.mctrl |= TIOCM_OUT1; -+ } else -+ up->port.mctrl &= ~TIOCM_OUT2; -+ -+ serial8250_set_mctrl(&up->port, up->port.mctrl); -+ spin_unlock_irqrestore(&up->port.lock, flags); -+ -+ /* -+ * Disable break condition and FIFOs -+ */ -+ serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC); -+ serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | -+ UART_FCR_CLEAR_RCVR | -+ UART_FCR_CLEAR_XMIT); -+ serial_outp(up, UART_FCR, 0); -+ -+#ifdef CONFIG_SERIAL_8250_RSA -+ /* -+ * Reset the RSA board back to 115kbps compat mode. -+ */ -+ disable_rsa(up); -+#endif -+ -+ /* -+ * Read data port to reset things, and then unlink from -+ * the IRQ chain. -+ */ -+ (void) serial_in(up, UART_RX); -+ -+ if (!is_real_interrupt(up->port.irq)) -+ del_timer_sync(&up->timer); -+ else -+ serial_unlink_irq_chain(up); -+} -+ -+static void serial8250_change_speed(struct uart_port *port, unsigned int cflag, unsigned int iflag, unsigned int quot) -+{ -+ struct uart_8250_port *up = (struct uart_8250_port *)port; -+ unsigned char cval, fcr = 0; -+ unsigned long flags; -+ -+ switch (cflag & CSIZE) { -+ case CS5: -+ cval = 0x00; -+ break; -+ case CS6: -+ cval = 0x01; -+ break; -+ case CS7: -+ cval = 0x02; -+ break; -+ default: -+ case CS8: -+ cval = 0x03; -+ break; -+ } -+ -+ if (cflag & CSTOPB) -+ cval |= 0x04; -+ if (cflag & PARENB) -+ cval |= UART_LCR_PARITY; -+ if (!(cflag & PARODD)) -+ cval |= UART_LCR_EPAR; -+#ifdef CMSPAR -+ if (cflag & CMSPAR) -+ cval |= UART_LCR_SPAR; -+#endif -+ -+ /* -+ * Work around a bug in the Oxford Semiconductor 952 rev B -+ * chip which causes it to seriously miscalculate baud rates -+ * when DLL is 0. -+ */ -+ if ((quot & 0xff) == 0 && up->port.type == PORT_16C950 && -+ up->rev == 0x5201) -+ quot ++; -+ -+ if (up->capabilities & UART_USE_FIFO) { -+ if ((up->port.uartclk / quot) < (2400 * 16)) -+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; -+#ifdef CONFIG_SERIAL_8250_RSA -+ else if (up->port.type == PORT_RSA) -+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14; -+#endif -+ else -+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; -+ } -+ if (up->port.type == PORT_16750) -+ fcr |= UART_FCR7_64BYTE; -+ -+ /* -+ * Ok, we're now changing the port state. Do it with -+ * interrupts disabled. -+ */ -+ spin_lock_irqsave(&up->port.lock, flags); -+ -+ up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; -+ if (iflag & IGNPAR) -+ up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; -+ if (iflag & (BRKINT | PARMRK)) -+ up->port.read_status_mask |= UART_LSR_BI; -+ -+ /* -+ * Characteres to ignore -+ */ -+ up->port.ignore_status_mask = 0; -+ if (iflag & IGNPAR) -+ up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; -+ if (iflag & IGNBRK) { -+ up->port.ignore_status_mask |= UART_LSR_BI; -+ /* -+ * If we're ignoring parity and break indicators, -+ * ignore overruns too (for real raw support). -+ */ -+ if (iflag & IGNPAR) -+ up->port.ignore_status_mask |= UART_LSR_OE; -+ } -+ -+ /* -+ * ignore all characters if CREAD is not set -+ */ -+ if ((cflag & CREAD) == 0) -+ up->port.ignore_status_mask |= UART_LSR_DR; -+ -+ /* -+ * CTS flow control flag and modem status interrupts -+ */ -+ up->ier &= ~UART_IER_MSI; -+ if (UART_ENABLE_MS(&up->port, cflag)) -+ up->ier |= UART_IER_MSI; -+ -+ serial_out(up, UART_IER, up->ier); -+ -+ if (up->capabilities & UART_MCRAFE) { -+ /* -+ * TI16C750 hardware flow control -+ */ -+ up->mcr &= ~UART_MCR_AFE; -+ if (cflag & CRTSCTS) -+ up->mcr |= UART_MCR_AFE; -+ } -+ if (up->capabilities & UART_EFRAFE) { -+ /* -+ * TI16C752/Startech hardware flow control -+ * FIXME: -+ * - TI16C752 requires control thresholds -+ * to be set for auto-RTS. -+ * - We only enable auto-CTS here. -+ * Note: ST16C654 does not allow MCR bit 1 -+ * to override RTS when UART_EFR_RTS is set. -+ */ -+ up->efr &= ~UART_EFR_CTS; -+ if (cflag & CRTSCTS) -+ up->efr |= UART_EFR_CTS; -+ serial_outp(up, UART_LCR, 0xBF); -+ serial_outp(up, UART_EFR, up->efr); -+ } -+ -+ if (up->capabilities & UART_NATSEMI) { -+ /* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */ -+ serial_outp(up, UART_LCR, 0xe0); -+ } else { -+ serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ -+ } -+ serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */ -+ serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */ -+ if (up->port.type == PORT_16750) -+ serial_outp(up, UART_FCR, fcr); /* set fcr */ -+ serial_outp(up, UART_LCR, cval); /* reset DLAB */ -+ up->lcr = cval; /* Save LCR */ -+ if (up->port.type != PORT_16750) { -+ if (fcr & UART_FCR_ENABLE_FIFO) { -+ /* emulated UARTs (Lucent Venus 167x) need two steps */ -+ serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); -+ } -+ serial_outp(up, UART_FCR, fcr); /* set fcr */ -+ } -+ serial8250_set_mctrl(&up->port, up->port.mctrl); -+ spin_unlock_irqrestore(&up->port.lock, flags); -+} -+ -+static void -+serial8250_pm(struct uart_port *port, unsigned int state, -+ unsigned int oldstate) -+{ -+ struct uart_8250_port *up = (struct uart_8250_port *)port; -+ if (state) { -+ /* sleep */ -+ if (up->capabilities & UART_STARTECH) { -+ /* Arrange to enter sleep mode */ -+ serial_outp(up, UART_LCR, 0xBF); -+ serial_outp(up, UART_EFR, UART_EFR_ECB); -+ serial_outp(up, UART_LCR, 0); -+ serial_outp(up, UART_IER, UART_IERX_SLEEP); -+ serial_outp(up, UART_LCR, 0xBF); -+ serial_outp(up, UART_EFR, 0); -+ serial_outp(up, UART_LCR, 0); -+ } -+ if (up->port.type == PORT_16750) { -+ /* Arrange to enter sleep mode */ -+ serial_outp(up, UART_IER, UART_IERX_SLEEP); -+ } -+ } else { -+ /* wake */ -+ if (up->capabilities & UART_STARTECH) { -+ /* Wake up UART */ -+ serial_outp(up, UART_LCR, 0xBF); -+ serial_outp(up, UART_EFR, UART_EFR_ECB); -+ /* -+ * Turn off LCR == 0xBF so we actually set the IER -+ * register on the XR16C850 -+ */ -+ serial_outp(up, UART_LCR, 0); -+ serial_outp(up, UART_IER, 0); -+ /* -+ * Now reset LCR so we can turn off the ECB bit -+ */ -+ serial_outp(up, UART_LCR, 0xBF); -+ serial_outp(up, UART_EFR, 0); -+ /* -+ * For a XR16C850, we need to set the trigger levels -+ */ -+ if (up->port.type == PORT_16850) { -+ unsigned char fctr; -+ -+ fctr = serial_inp(up, UART_FCTR) & -+ ~(UART_FCTR_RX | UART_FCTR_TX); -+ serial_outp(up, UART_FCTR, fctr | -+ UART_FCTR_TRGD | -+ UART_FCTR_RX); -+ serial_outp(up, UART_TRG, UART_TRG_96); -+ serial_outp(up, UART_FCTR, fctr | -+ UART_FCTR_TRGD | -+ UART_FCTR_TX); -+ serial_outp(up, UART_TRG, UART_TRG_96); -+ } -+ serial_outp(up, UART_LCR, 0); -+ } -+ -+ if (up->port.type == PORT_16750) { -+ /* Wake up UART */ -+ serial_outp(up, UART_IER, 0); -+ } -+ } -+} -+ -+/* -+ * Resource handling. This is complicated by the fact that resources -+ * depend on the port type. Maybe we should be claiming the standard -+ * 8250 ports, and then trying to get other resources as necessary? -+ */ -+static int -+serial8250_request_std_resource(struct uart_8250_port *up, struct resource **res) -+{ -+ unsigned int size = 8 << up->port.regshift; -+ int ret = 0; -+ -+ switch (up->port.iotype) { -+ case SERIAL_IO_MEM: -+ if (up->port.mapbase) { -+ *res = request_mem_region(up->port.mapbase, size, "serial"); -+ if (!*res) -+ ret = -EBUSY; -+ } -+ break; -+ -+ case SERIAL_IO_HUB6: -+ case SERIAL_IO_PORT: -+ *res = request_region(up->port.iobase, size, "serial"); -+ if (!*res) -+ ret = -EBUSY; -+ break; -+ } -+ return ret; -+} -+ -+static int -+serial8250_request_rsa_resource(struct uart_8250_port *up, struct resource **res) -+{ -+ unsigned int size = 8 << up->port.regshift; -+ unsigned long start; -+ int ret = 0; -+ -+ switch (up->port.iotype) { -+ case SERIAL_IO_MEM: -+ if (up->port.mapbase) { -+ start = up->port.mapbase; -+ start += UART_RSA_BASE << up->port.regshift; -+ *res = request_mem_region(start, size, "serial-rsa"); -+ if (!*res) -+ ret = -EBUSY; -+ } -+ break; -+ -+ case SERIAL_IO_HUB6: -+ case SERIAL_IO_PORT: -+ start = up->port.iobase; -+ start += UART_RSA_BASE << up->port.regshift; -+ *res = request_region(start, size, "serial-rsa"); -+ if (!*res) -+ ret = -EBUSY; -+ break; -+ } -+ -+ return ret; -+} -+ -+static void serial8250_release_port(struct uart_port *port) -+{ -+ struct uart_8250_port *up = (struct uart_8250_port *)port; -+ unsigned long start, offset = 0, size = 0; -+ -+ if (up->port.type == PORT_RSA) { -+ offset = UART_RSA_BASE << up->port.regshift; -+ size = 8; -+ } -+ -+ size <<= up->port.regshift; -+ -+ switch (up->port.iotype) { -+ case SERIAL_IO_MEM: -+ if (up->port.mapbase) { -+ /* -+ * Unmap the area. -+ */ -+ if (up->port.flags & UPF_IOREMAP) { -+ iounmap(up->port.membase); -+ up->port.membase = NULL; -+ } -+ -+ start = up->port.mapbase; -+ -+ if (size) -+ release_mem_region(start + offset, size); -+ release_mem_region(start, 8 << up->port.regshift); -+ } -+ break; -+ -+ case SERIAL_IO_HUB6: -+ case SERIAL_IO_PORT: -+ start = up->port.iobase; -+ -+ if (size) -+ release_region(start + offset, size); -+ release_region(start + offset, 8 << up->port.regshift); -+ break; -+ -+ default: -+ break; -+ } -+} -+ -+static int serial8250_request_port(struct uart_port *port) -+{ -+ struct uart_8250_port *up = (struct uart_8250_port *)port; -+ struct resource *res = NULL, *res_rsa = NULL; -+ int ret = 0; -+ -+ if (up->port.flags & UPF_RESOURCES) { -+ if (up->port.type == PORT_RSA) { -+ ret = serial8250_request_rsa_resource(up, &res_rsa); -+ if (ret < 0) -+ return ret; -+ } -+ -+ ret = serial8250_request_std_resource(up, &res); -+ } -+ -+ /* -+ * If we have a mapbase, then request that as well. -+ */ -+ if (ret == 0 && up->port.flags & UPF_IOREMAP) { -+ int size = res->end - res->start + 1; -+ -+ up->port.membase = ioremap(up->port.mapbase, size); -+ if (!up->port.membase) -+ ret = -ENOMEM; -+ } -+ -+ if (ret < 0) { -+ if (res_rsa) -+ release_resource(res_rsa); -+ if (res) -+ release_resource(res); -+ } -+ return ret; -+} -+ -+static void serial8250_config_port(struct uart_port *port, int flags) -+{ -+ struct uart_8250_port *up = (struct uart_8250_port *)port; -+ struct resource *res_std = NULL, *res_rsa = NULL; -+ int probeflags = PROBE_ANY; -+ int ret; -+ -+#ifdef CONFIG_MCA -+ /* -+ * Don't probe for MCA ports on non-MCA machines. -+ */ -+ if (up->port.flags & UPF_BOOT_ONLYMCA && !MCA_bus) -+ return; -+#endif -+ -+ /* -+ * Find the region that we can probe for. This in turn -+ * tells us whether we can probe for the type of port. -+ */ -+ if (up->port.flags & UPF_RESOURCES) { -+ ret = serial8250_request_std_resource(up, &res_std); -+ if (ret < 0) -+ return; -+ -+ ret = serial8250_request_rsa_resource(up, &res_rsa); -+ if (ret < 0) -+ probeflags &= ~PROBE_RSA; -+ } else { -+ probeflags &= ~PROBE_RSA; -+ } -+ -+ if (flags & UART_CONFIG_TYPE) -+ autoconfig(up, probeflags); -+ if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) -+ autoconfig_irq(up); -+ -+ /* -+ * If the port wasn't an RSA port, release the resource. -+ */ -+ if (up->port.type != PORT_RSA && res_rsa) -+ release_resource(res_rsa); -+ -+ if (up->port.type == PORT_UNKNOWN && res_std) -+ release_resource(res_std); -+} -+ -+static int -+serial8250_verify_port(struct uart_port *port, struct serial_struct *ser) -+{ -+ if (ser->irq >= NR_IRQS || ser->irq < 0 || -+ ser->baud_base < 9600 || ser->type < PORT_UNKNOWN || -+ ser->type > PORT_MAX_8250 || ser->type == PORT_CIRRUS || -+ ser->type == PORT_STARTECH) -+ return -EINVAL; -+ return 0; -+} -+ -+static const char * -+serial8250_type(struct uart_port *port) -+{ -+ int type = port->type; -+ -+ if (type >= ARRAY_SIZE(uart_config)) -+ type = 0; -+ return uart_config[type].name; -+} -+ -+static struct uart_ops serial8250_pops = { -+ .tx_empty = serial8250_tx_empty, -+ .set_mctrl = serial8250_set_mctrl, -+ .get_mctrl = serial8250_get_mctrl, -+ .stop_tx = serial8250_stop_tx, -+ .start_tx = serial8250_start_tx, -+ .stop_rx = serial8250_stop_rx, -+ .enable_ms = serial8250_enable_ms, -+ .break_ctl = serial8250_break_ctl, -+ .startup = serial8250_startup, -+ .shutdown = serial8250_shutdown, -+ .change_speed = serial8250_change_speed, -+ .pm = serial8250_pm, -+ .type = serial8250_type, -+ .release_port = serial8250_release_port, -+ .request_port = serial8250_request_port, -+ .config_port = serial8250_config_port, -+ .verify_port = serial8250_verify_port, -+}; -+ -+static struct uart_8250_port serial8250_ports[UART_NR]; -+ -+static void __init serial8250_isa_init_ports(void) -+{ -+ struct uart_8250_port *up; -+ static int first = 1; -+ int i; -+ -+ if (!first) -+ return; -+ first = 0; -+ -+ for (i = 0, up = serial8250_ports; i < ARRAY_SIZE(old_serial_port); -+ i++, up++) { -+ up->port.iobase = old_serial_port[i].port; -+ up->port.irq = irq_cannonicalize(old_serial_port[i].irq); -+ up->port.uartclk = old_serial_port[i].baud_base * 16; -+ up->port.flags = old_serial_port[i].flags | -+ UPF_RESOURCES; -+ up->port.hub6 = old_serial_port[i].hub6; -+ up->port.membase = old_serial_port[i].iomem_base; -+ up->port.iotype = old_serial_port[i].io_type; -+ up->port.regshift = old_serial_port[i].iomem_reg_shift; -+ up->port.ops = &serial8250_pops; -+ -+ if (up->port.iotype == UPIO_MEM && up->port.mapbase) -+ up->port.flags |= UPF_IOREMAP; -+ -+ if (share_irqs) -+ up->port.flags |= UPF_SHARE_IRQ; -+ } -+} -+ -+static void __init serial8250_register_ports(struct uart_driver *drv) -+{ -+ int i; -+ -+ serial8250_isa_init_ports(); -+ -+ for (i = 0; i < UART_NR; i++) { -+ struct uart_8250_port *up = &serial8250_ports[i]; -+ -+ up->port.line = i; -+ up->port.ops = &serial8250_pops; -+ init_timer(&up->timer); -+ up->timer.function = serial8250_timeout; -+ -+ /* -+ * ALPHA_KLUDGE_MCR needs to be killed. -+ */ -+ up->mcr_mask = ~ALPHA_KLUDGE_MCR; -+ up->mcr_force = ALPHA_KLUDGE_MCR; -+ -+ uart_add_one_port(drv, &up->port); -+ } -+} -+ -+#ifdef CONFIG_SERIAL_8250_CONSOLE -+ -+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) -+ -+/* -+ * Wait for transmitter & holding register to empty -+ */ -+static inline void wait_for_xmitr(struct uart_8250_port *up) -+{ -+ unsigned int status, tmout = 10000; -+ -+ /* Wait up to 10ms for the character(s) to be sent. */ -+ do { -+ status = serial_in(up, UART_LSR); -+ -+ if (status & UART_LSR_BI) -+ up->lsr_break_flag = UART_LSR_BI; -+ -+ if (--tmout == 0) -+ break; -+ udelay(1); -+ } while ((status & BOTH_EMPTY) != BOTH_EMPTY); -+ -+ /* Wait up to 1s for flow control if necessary */ -+ if (up->port.flags & UPF_CONS_FLOW) { -+ tmout = 1000000; -+ while (--tmout && -+ ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0)) -+ udelay(1); -+ } -+} -+ -+/* -+ * Print a string to the serial port trying not to disturb -+ * any possible real use of the port... -+ * -+ * The console_lock must be held when we get here. -+ */ -+static void -+serial8250_console_write(struct console *co, const char *s, unsigned int count) -+{ -+ struct uart_8250_port *up = &serial8250_ports[co->index]; -+ unsigned int ier; -+ int i; -+ -+ /* -+ * First save the UER then disable the interrupts -+ */ -+ ier = serial_in(up, UART_IER); -+ serial_out(up, UART_IER, 0); -+ -+ /* -+ * Now, do each character -+ */ -+ for (i = 0; i < count; i++, s++) { -+ wait_for_xmitr(up); -+ -+ /* -+ * Send the character out. -+ * If a LF, also do CR... -+ */ -+ serial_out(up, UART_TX, *s); -+ if (*s == 10) { -+ wait_for_xmitr(up); -+ serial_out(up, UART_TX, 13); -+ } -+ } -+ -+ /* -+ * Finally, wait for transmitter to become empty -+ * and restore the IER -+ */ -+ wait_for_xmitr(up); -+ serial_out(up, UART_IER, ier); -+} -+ -+static kdev_t serial8250_console_device(struct console *co) -+{ -+ return MKDEV(TTY_MAJOR, 64 + co->index); -+} -+ -+static int __init serial8250_console_setup(struct console *co, char *options) -+{ -+ struct uart_port *port; -+ int baud = 9600; -+ int bits = 8; -+ int parity = 'n'; -+ int flow = 'n'; -+ -+ /* -+ * Check whether an invalid uart number has been specified, and -+ * if so, search for the first available port that does have -+ * console support. -+ */ -+ if (co->index >= UART_NR) -+ co->index = 0; -+ port = &serial8250_ports[co->index].port; -+ -+ /* -+ * Temporary fix. -+ */ -+ spin_lock_init(&port->lock); -+ -+ if (options) -+ uart_parse_options(options, &baud, &parity, &bits, &flow); -+ -+ return uart_set_options(port, co, baud, parity, bits, flow); -+} -+ -+static struct console serial8250_console = { -+ .name = "ttyS", -+ .write = serial8250_console_write, -+ .device = serial8250_console_device, -+ .setup = serial8250_console_setup, -+ .flags = CON_PRINTBUFFER, -+ .index = -1, -+}; -+ -+void __init serial8250_console_init(void) -+{ -+ serial8250_isa_init_ports(); -+ register_console(&serial8250_console); -+} -+ -+#define SERIAL8250_CONSOLE &serial8250_console -+#else -+#define SERIAL8250_CONSOLE NULL -+#endif -+ -+static struct uart_driver serial8250_reg = { -+ .owner = THIS_MODULE, -+#ifdef CONFIG_DEVFS_FS -+ .normal_name = "tts/%d", -+ .callout_name = "cua/%d", -+#else -+ .normal_name = "ttyS", -+ .callout_name = "cua", -+#endif -+ .normal_major = TTY_MAJOR, -+ .callout_major = TTYAUX_MAJOR, -+ .normal_driver = &normal, -+ .callout_driver = &callout, -+ .table = serial8250_table, -+ .termios = serial8250_termios, -+ .termios_locked = serial8250_termios_locked, -+ .minor = 64, -+ .nr = UART_NR, -+ .cons = SERIAL8250_CONSOLE, -+}; -+ -+/* -+ * register_serial and unregister_serial allows for 16x50 serial ports to be -+ * configured at run-time, to support PCMCIA modems. -+ */ -+ -+static int __register_serial(struct serial_struct *req, int line) -+{ -+ struct uart_port port; -+ -+ port.iobase = req->port; -+ port.membase = req->iomem_base; -+ port.irq = req->irq; -+ port.uartclk = req->baud_base * 16; -+ port.fifosize = req->xmit_fifo_size; -+ port.regshift = req->iomem_reg_shift; -+ port.iotype = req->io_type; -+ port.flags = req->flags | UPF_BOOT_AUTOCONF; -+ port.mapbase = req->iomap_base; -+ port.line = line; -+ -+ if (share_irqs) -+ port.flags |= UPF_SHARE_IRQ; -+ -+ if (HIGH_BITS_OFFSET) -+ port.iobase |= (long) req->port_high << HIGH_BITS_OFFSET; -+ -+ /* -+ * If a clock rate wasn't specified by the low level -+ * driver, then default to the standard clock rate. -+ */ -+ if (port.uartclk == 0) -+ port.uartclk = BASE_BAUD * 16; -+ -+ return uart_register_port(&serial8250_reg, &port); -+} -+ -+/** -+ * register_serial - configure a 16x50 serial port at runtime -+ * @req: request structure -+ * -+ * Configure the serial port specified by the request. If the -+ * port exists and is in use an error is returned. If the port -+ * is not currently in the table it is added. -+ * -+ * The port is then probed and if necessary the IRQ is autodetected -+ * If this fails an error is returned. -+ * -+ * On success the port is ready to use and the line number is returned. -+ */ -+int register_serial(struct serial_struct *req) -+{ -+ return __register_serial(req, -1); -+} -+ -+/** -+ * unregister_serial - remove a 16x50 serial port at runtime -+ * @line: serial line number -+ * -+ * Remove one serial port. This may be called from interrupt -+ * context. -+ */ -+void unregister_serial(int line) -+{ -+ uart_unregister_port(&serial8250_reg, line); -+} -+ -+/* -+ * This is for ISAPNP only. -+ */ -+void serial8250_get_irq_map(unsigned int *map) -+{ -+ int i; -+ -+ for (i = 0; i < UART_NR; i++) { -+ if (serial8250_ports[i].port.type != PORT_UNKNOWN && -+ serial8250_ports[i].port.irq < 16) -+ *map |= 1 << serial8250_ports[i].port.irq; -+ } -+} -+ -+static int __init serial8250_init(void) -+{ -+ int ret, i; -+ -+ for (i = 0; i < NR_IRQS; i++) -+ spin_lock_init(&irq_lists[i].lock); -+ -+ ret = uart_register_driver(&serial8250_reg); -+ if (ret >= 0) -+ serial8250_register_ports(&serial8250_reg); -+ -+ return ret; -+} -+ -+static void __exit serial8250_exit(void) -+{ -+ int i; -+ -+ for (i = 0; i < UART_NR; i++) -+ uart_remove_one_port(&serial8250_reg, &serial8250_ports[i].port); -+ -+ uart_unregister_driver(&serial8250_reg); -+} -+ -+module_init(serial8250_init); -+module_exit(serial8250_exit); -+ -+EXPORT_SYMBOL(register_serial); -+EXPORT_SYMBOL(unregister_serial); -+EXPORT_SYMBOL(serial8250_get_irq_map); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("Generic 8250/16x50 serial driver"); -+ -+MODULE_PARM(share_irqs, "i"); -+MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices" -+ " (unsafe)"); -+ -+#if defined(CONFIG_SERIAL_8250_RSA) && defined(MODULE) -+MODULE_PARM(probe_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i"); -+MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA"); -+MODULE_PARM(force_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i"); -+MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA"); -+#endif /* CONFIG_SERIAL_8250_RSA */ -+ -diff -urN linux-2.4.26/drivers/serial/8250.h linux-2.4.26-vrs1/drivers/serial/8250.h ---- linux-2.4.26/drivers/serial/8250.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/serial/8250.h 2004-04-19 16:49:20.000000000 +0100 -@@ -0,0 +1,88 @@ -+/* -+ * linux/drivers/serial/8250.h -+ * -+ * Driver for 8250/16550-type serial ports -+ * -+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. -+ * -+ * Copyright (C) 2001 Russell King. -+ * -+ * 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. -+ * -+ * $Id: 8250.h,v 1.1.1.1.2.1 2002/10/24 09:53:24 rmk Exp $ -+ */ -+ -+#include -+ -+struct serial8250_probe { -+ struct module *owner; -+ int (*pci_init_one)(struct pci_dev *dev); -+ void (*pci_remove_one)(struct pci_dev *dev); -+ void (*pnp_init)(void); -+}; -+ -+int serial8250_register_probe(struct serial8250_probe *probe); -+void serial8250_unregister_probe(struct serial8250_probe *probe); -+void serial8250_get_irq_map(unsigned int *map); -+ -+struct old_serial_port { -+ unsigned int uart; -+ unsigned int baud_base; -+ unsigned int port; -+ unsigned int irq; -+ unsigned int flags; -+ unsigned char hub6; -+ unsigned char io_type; -+ unsigned char *iomem_base; -+ unsigned short iomem_reg_shift; -+}; -+ -+struct serial8250_config { -+ const char *name; -+ unsigned int dfl_xmit_fifo_size; -+ unsigned int flags; -+}; -+ -+#define UART_CLEAR_FIFO 0x01 -+#define UART_USE_FIFO 0x02 -+#define UART_STARTECH 0x04 -+#define UART_NATSEMI 0x08 -+#define UART_MCRAFE 0x10 /* TI16C750-style auto-flow */ -+#define UART_EFRAFE 0x20 /* TI16C752/startech auto-flow */ -+ -+#define UART_BAD_TX_ENABLE 0x80000000 -+ -+#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486)) -+#define SERIAL_INLINE -+#endif -+ -+#ifdef SERIAL_INLINE -+#define _INLINE_ inline -+#else -+#define _INLINE_ -+#endif -+ -+#define PROBE_RSA (1 << 0) -+#define PROBE_ANY (~0) -+ -+#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) -+ -+#ifdef CONFIG_SERIAL_8250_SHARE_IRQ -+#define SERIAL8250_SHARE_IRQS 1 -+#else -+#define SERIAL8250_SHARE_IRQS 0 -+#endif -+ -+#if defined(__alpha__) && !defined(CONFIG_PCI) -+/* -+ * Digital did something really horribly wrong with the OUT1 and OUT2 -+ * lines on at least some ALPHA's. The failure mode is that if either -+ * is cleared, the machine locks up with endless interrupts. -+ */ -+#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2 | UART_MCR_OUT1) -+#else -+#define ALPHA_KLUDGE_MCR 0 -+#endif -diff -urN linux-2.4.26/drivers/serial/8250_pci.c linux-2.4.26-vrs1/drivers/serial/8250_pci.c ---- linux-2.4.26/drivers/serial/8250_pci.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/serial/8250_pci.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,1080 @@ -+/* -+ * linux/drivers/char/serial_8250_pci.c -+ * -+ * Probe module for 8250/16550-type PCI serial ports. -+ * -+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. -+ * -+ * Copyright (C) 2001 Russell King, All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License. -+ * -+ * $Id: 8250_pci.c,v 1.8.2.1 2002/10/24 09:53:24 rmk Exp $ -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* 2.4.6 compatibility cruft ;( */ -+#define pci_board __pci_board -+#include -+#undef pci_board -+ -+#include -+#include -+#include -+ -+#include "8250.h" -+ -+#ifndef IS_PCI_REGION_IOPORT -+#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \ -+ IORESOURCE_IO) -+#endif -+#ifndef IS_PCI_REGION_IOMEM -+#define IS_PCI_REGION_IOMEM(dev, r) (pci_resource_flags((dev), (r)) & \ -+ IORESOURCE_MEM) -+#endif -+#ifndef PCI_IRQ_RESOURCE -+#define PCI_IRQ_RESOURCE(dev, r) ((dev)->irq_resource[r].start) -+#endif -+ -+#ifndef pci_get_subvendor -+#define pci_get_subvendor(dev) ((dev)->subsystem_vendor) -+#define pci_get_subdevice(dev) ((dev)->subsystem_device) -+#endif -+ -+struct serial_private { -+ unsigned int nr; -+ struct pci_board *board; -+ int line[0]; -+}; -+ -+struct pci_board { -+ int flags; -+ int num_ports; -+ int base_baud; -+ int uart_offset; -+ int reg_shift; -+ int (*init_fn)(struct pci_dev *dev, struct pci_board *board, -+ int enable); -+ int first_uart_offset; -+}; -+ -+static int -+get_pci_port(struct pci_dev *dev, struct pci_board *board, -+ struct serial_struct *req, int idx) -+{ -+ unsigned long port; -+ int base_idx; -+ int max_port; -+ int offset; -+ -+ base_idx = SPCI_FL_GET_BASE(board->flags); -+ if (board->flags & SPCI_FL_BASE_TABLE) -+ base_idx += idx; -+ -+ if (board->flags & SPCI_FL_REGION_SZ_CAP) { -+ max_port = pci_resource_len(dev, base_idx) / 8; -+ if (idx >= max_port) -+ return 1; -+ } -+ -+ offset = board->first_uart_offset; -+ -+ /* Timedia/SUNIX uses a mixture of BARs and offsets */ -+ /* Ugh, this is ugly as all hell --- TYT */ -+ if(dev->vendor == PCI_VENDOR_ID_TIMEDIA ) /* 0x1409 */ -+ switch(idx) { -+ case 0: base_idx=0; -+ break; -+ case 1: base_idx=0; offset=8; -+ break; -+ case 2: base_idx=1; -+ break; -+ case 3: base_idx=1; offset=8; -+ break; -+ case 4: /* BAR 2*/ -+ case 5: /* BAR 3 */ -+ case 6: /* BAR 4*/ -+ case 7: base_idx=idx-2; /* BAR 5*/ -+ } -+ -+ /* Some Titan cards are also a little weird */ -+ if (dev->vendor == PCI_VENDOR_ID_TITAN && -+ (dev->device == PCI_DEVICE_ID_TITAN_400L || -+ dev->device == PCI_DEVICE_ID_TITAN_800L)) { -+ switch (idx) { -+ case 0: base_idx = 1; -+ break; -+ case 1: base_idx = 2; -+ break; -+ default: -+ base_idx = 4; -+ offset = 8 * (idx - 2); -+ } -+ } -+ -+ port = pci_resource_start(dev, base_idx) + offset; -+ -+ if ((board->flags & SPCI_FL_BASE_TABLE) == 0) -+ port += idx * (board->uart_offset ? board->uart_offset : 8); -+ -+ if (IS_PCI_REGION_IOPORT(dev, base_idx)) { -+ req->port = port; -+ if (HIGH_BITS_OFFSET) -+ req->port_high = port >> HIGH_BITS_OFFSET; -+ else -+ req->port_high = 0; -+ return 0; -+ } -+ req->io_type = SERIAL_IO_MEM; -+ req->iomem_base = ioremap(port, board->uart_offset); -+ req->iomem_reg_shift = board->reg_shift; -+ req->port = 0; -+ return 0; -+} -+ -+static _INLINE_ int get_pci_irq(struct pci_dev *dev, -+ struct pci_board *board, -+ int idx) -+{ -+ int base_idx; -+ -+ if ((board->flags & SPCI_FL_IRQRESOURCE) == 0) -+ return dev->irq; -+ -+ base_idx = SPCI_FL_GET_IRQBASE(board->flags); -+ if (board->flags & SPCI_FL_IRQ_TABLE) -+ base_idx += idx; -+ -+ return PCI_IRQ_RESOURCE(dev, base_idx); -+} -+ -+/* -+ * Some PCI serial cards using the PLX 9050 PCI interface chip require -+ * that the card interrupt be explicitly enabled or disabled. This -+ * seems to be mainly needed on card using the PLX which also use I/O -+ * mapped memory. -+ */ -+static int __devinit -+pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable) -+{ -+ u8 data, *p, irq_config; -+ int pci_config; -+ -+ irq_config = 0x41; -+ pci_config = PCI_COMMAND_MEMORY; -+ if (dev->vendor == PCI_VENDOR_ID_PANACOM) -+ irq_config = 0x43; -+ if ((dev->vendor == PCI_VENDOR_ID_PLX) && -+ (dev->device == PCI_DEVICE_ID_PLX_ROMULUS)) { -+ /* -+ * As the megawolf cards have the int pins active -+ * high, and have 2 UART chips, both ints must be -+ * enabled on the 9050. Also, the UARTS are set in -+ * 16450 mode by default, so we have to enable the -+ * 16C950 'enhanced' mode so that we can use the deep -+ * FIFOs -+ */ -+ irq_config = 0x5b; -+ pci_config = PCI_COMMAND_MEMORY | PCI_COMMAND_IO; -+ } -+ -+ pci_read_config_byte(dev, PCI_COMMAND, &data); -+ -+ if (enable) -+ pci_write_config_byte(dev, PCI_COMMAND, -+ data | pci_config); -+ -+ /* enable/disable interrupts */ -+ p = ioremap(pci_resource_start(dev, 0), 0x80); -+ writel(enable ? irq_config : 0x00, (unsigned long)p + 0x4c); -+ iounmap(p); -+ -+ if (!enable) -+ pci_write_config_byte(dev, PCI_COMMAND, -+ data & ~pci_config); -+ return 0; -+} -+ -+ -+/* -+ * SIIG serial cards have an PCI interface chip which also controls -+ * the UART clocking frequency. Each UART can be clocked independently -+ * (except cards equiped with 4 UARTs) and initial clocking settings -+ * are stored in the EEPROM chip. It can cause problems because this -+ * version of serial driver doesn't support differently clocked UART's -+ * on single PCI card. To prevent this, initialization functions set -+ * high frequency clocking for all UART's on given card. It is safe (I -+ * hope) because it doesn't touch EEPROM settings to prevent conflicts -+ * with other OSes (like M$ DOS). -+ * -+ * SIIG support added by Andrey Panin , 10/1999 -+ * -+ * There is two family of SIIG serial cards with different PCI -+ * interface chip and different configuration methods: -+ * - 10x cards have control registers in IO and/or memory space; -+ * - 20x cards have control registers in standard PCI configuration space. -+ */ -+ -+#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc) -+#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8) -+ -+static int __devinit -+pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable) -+{ -+ u16 data, *p; -+ -+ if (!enable) return 0; -+ -+ p = ioremap(pci_resource_start(dev, 0), 0x80); -+ -+ switch (dev->device & 0xfff8) { -+ case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */ -+ data = 0xffdf; -+ break; -+ case PCI_DEVICE_ID_SIIG_2S_10x: /* 2S, 2S1P */ -+ data = 0xf7ff; -+ break; -+ default: /* 1S1P, 4S */ -+ data = 0xfffb; -+ break; -+ } -+ -+ writew(readw((unsigned long) p + 0x28) & data, (unsigned long) p + 0x28); -+ iounmap(p); -+ return 0; -+} -+ -+#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc) -+#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc) -+ -+static int __devinit -+pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable) -+{ -+ u8 data; -+ -+ if (!enable) return 0; -+ -+ /* Change clock frequency for the first UART. */ -+ pci_read_config_byte(dev, 0x6f, &data); -+ pci_write_config_byte(dev, 0x6f, data & 0xef); -+ -+ /* If this card has 2 UART, we have to do the same with second UART. */ -+ if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) || -+ ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) { -+ pci_read_config_byte(dev, 0x73, &data); -+ pci_write_config_byte(dev, 0x73, data & 0xef); -+ } -+ return 0; -+} -+ -+/* Added for EKF Intel i960 serial boards */ -+static int __devinit -+pci_inteli960ni_fn(struct pci_dev *dev, -+ struct pci_board *board, -+ int enable) -+{ -+ unsigned long oldval; -+ -+ if (!(pci_get_subdevice(dev) & 0x1000)) -+ return(-1); -+ -+ if (!enable) /* is there something to deinit? */ -+ return(0); -+ -+ /* is firmware started? */ -+ pci_read_config_dword(dev, 0x44, (void*) &oldval); -+ if (oldval == 0x00001000L) { /* RESET value */ -+ printk(KERN_DEBUG "Local i960 firmware missing"); -+ return(-1); -+ } -+ return(0); -+} -+ -+/* -+ * Timedia has an explosion of boards, and to avoid the PCI table from -+ * growing *huge*, we use this function to collapse some 70 entries -+ * in the PCI table into one, for sanity's and compactness's sake. -+ */ -+static unsigned short timedia_single_port[] = { -+ 0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0 }; -+static unsigned short timedia_dual_port[] = { -+ 0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085, -+ 0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079, -+ 0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079, -+ 0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079, -+ 0xD079, 0 }; -+static unsigned short timedia_quad_port[] = { -+ 0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157, -+ 0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159, -+ 0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056, -+ 0xB157, 0 }; -+static unsigned short timedia_eight_port[] = { -+ 0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166, -+ 0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0 }; -+static struct timedia_struct { -+ int num; -+ unsigned short *ids; -+} timedia_data[] = { -+ { 1, timedia_single_port }, -+ { 2, timedia_dual_port }, -+ { 4, timedia_quad_port }, -+ { 8, timedia_eight_port }, -+ { 0, 0 } -+}; -+ -+static int __devinit -+pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable) -+{ -+ int i, j; -+ unsigned short *ids; -+ -+ if (!enable) -+ return 0; -+ -+ for (i=0; timedia_data[i].num; i++) { -+ ids = timedia_data[i].ids; -+ for (j=0; ids[j]; j++) { -+ if (pci_get_subdevice(dev) == ids[j]) { -+ board->num_ports = timedia_data[i].num; -+ return 0; -+ } -+ } -+ } -+ return 0; -+} -+ -+static int __devinit -+pci_xircom_fn(struct pci_dev *dev, struct pci_board *board, int enable) -+{ -+ __set_current_state(TASK_UNINTERRUPTIBLE); -+ schedule_timeout(HZ/10); -+ return 0; -+} -+ -+/* -+ * This is the configuration table for all of the PCI serial boards -+ * which we support. It is directly indexed by the pci_board_num_t enum -+ * value, which is encoded in the pci_device_id PCI probe table's -+ * driver_data member. -+ */ -+enum pci_board_num_t { -+ pbn_b0_1_115200, -+ pbn_default = 0, -+ -+ pbn_b0_2_115200, -+ pbn_b0_4_115200, -+ -+ pbn_b0_1_921600, -+ pbn_b0_2_921600, -+ pbn_b0_4_921600, -+ -+ pbn_b0_bt_1_115200, -+ pbn_b0_bt_2_115200, -+ pbn_b0_bt_1_460800, -+ pbn_b0_bt_2_460800, -+ -+ pbn_b1_1_115200, -+ pbn_b1_2_115200, -+ pbn_b1_4_115200, -+ pbn_b1_8_115200, -+ -+ pbn_b1_2_921600, -+ pbn_b1_4_921600, -+ pbn_b1_8_921600, -+ -+ pbn_b1_2_1382400, -+ pbn_b1_4_1382400, -+ pbn_b1_8_1382400, -+ -+ pbn_b2_8_115200, -+ pbn_b2_4_460800, -+ pbn_b2_8_460800, -+ pbn_b2_16_460800, -+ pbn_b2_4_921600, -+ pbn_b2_8_921600, -+ -+ pbn_b2_bt_1_115200, -+ pbn_b2_bt_2_115200, -+ pbn_b2_bt_4_115200, -+ pbn_b2_bt_2_921600, -+ -+ pbn_panacom, -+ pbn_panacom2, -+ pbn_panacom4, -+ pbn_plx_romulus, -+ pbn_oxsemi, -+ pbn_timedia, -+ pbn_intel_i960, -+ pbn_sgi_ioc3, -+#ifdef CONFIG_DDB5074 -+ pbn_nec_nile4, -+#endif -+#if 0 -+ pbn_dci_pccom8, -+#endif -+ pbn_xircom_combo, -+ -+ pbn_siig10x_0, -+ pbn_siig10x_1, -+ pbn_siig10x_2, -+ pbn_siig10x_4, -+ pbn_siig20x_0, -+ pbn_siig20x_2, -+ pbn_siig20x_4, -+ -+ pbn_computone_4, -+ pbn_computone_6, -+ pbn_computone_8, -+}; -+ -+static struct pci_board pci_boards[] __devinitdata = { -+ /* -+ * PCI Flags, Number of Ports, Base (Maximum) Baud Rate, -+ * Offset to get to next UART's registers, -+ * Register shift to use for memory-mapped I/O, -+ * Initialization function, first UART offset -+ */ -+ -+ /* Generic serial board, pbn_b0_1_115200, pbn_default */ -+ { SPCI_FL_BASE0, 1, 115200 }, /* pbn_b0_1_115200, -+ pbn_default */ -+ -+ { SPCI_FL_BASE0, 2, 115200 }, /* pbn_b0_2_115200 */ -+ { SPCI_FL_BASE0, 4, 115200 }, /* pbn_b0_4_115200 */ -+ -+ { SPCI_FL_BASE0, 1, 921600 }, /* pbn_b0_1_921600 */ -+ { SPCI_FL_BASE0, 2, 921600 }, /* pbn_b0_2_921600 */ -+ { SPCI_FL_BASE0, 4, 921600 }, /* pbn_b0_4_921600 */ -+ -+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b0_bt_1_115200 */ -+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */ -+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */ -+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */ -+ -+ { SPCI_FL_BASE1, 1, 115200 }, /* pbn_b1_1_115200 */ -+ { SPCI_FL_BASE1, 2, 115200 }, /* pbn_b1_2_115200 */ -+ { SPCI_FL_BASE1, 4, 115200 }, /* pbn_b1_4_115200 */ -+ { SPCI_FL_BASE1, 8, 115200 }, /* pbn_b1_8_115200 */ -+ -+ { SPCI_FL_BASE1, 2, 921600 }, /* pbn_b1_2_921600 */ -+ { SPCI_FL_BASE1, 4, 921600 }, /* pbn_b1_4_921600 */ -+ { SPCI_FL_BASE1, 8, 921600 }, /* pbn_b1_8_921600 */ -+ -+ { SPCI_FL_BASE1, 2, 1382400 }, /* pbn_b1_2_1382400 */ -+ { SPCI_FL_BASE1, 4, 1382400 }, /* pbn_b1_4_1382400 */ -+ { SPCI_FL_BASE1, 8, 1382400 }, /* pbn_b1_8_1382400 */ -+ -+ { SPCI_FL_BASE2, 8, 115200 }, /* pbn_b2_8_115200 */ -+ { SPCI_FL_BASE2, 4, 460800 }, /* pbn_b2_4_460800 */ -+ { SPCI_FL_BASE2, 8, 460800 }, /* pbn_b2_8_460800 */ -+ { SPCI_FL_BASE2, 16, 460800 }, /* pbn_b2_16_460800 */ -+ { SPCI_FL_BASE2, 4, 921600 }, /* pbn_b2_4_921600 */ -+ { SPCI_FL_BASE2, 8, 921600 }, /* pbn_b2_8_921600 */ -+ -+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b2_bt_1_115200 */ -+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b2_bt_2_115200 */ -+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, /* pbn_b2_bt_4_115200 */ -+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b2_bt_2_921600 */ -+ -+ { SPCI_FL_BASE2, 2, 921600, /* IOMEM */ /* pbn_panacom */ -+ 0x400, 7, pci_plx9050_fn }, -+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_panacom2 */ -+ 0x400, 7, pci_plx9050_fn }, -+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_panacom4 */ -+ 0x400, 7, pci_plx9050_fn }, -+ { SPCI_FL_BASE2, 4, 921600, /* pbn_plx_romulus */ -+ 0x20, 2, pci_plx9050_fn, 0x03 }, -+ /* This board uses the size of PCI Base region 0 to -+ * signal now many ports are available */ -+ { SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 }, /* pbn_oxsemi */ -+ { SPCI_FL_BASE_TABLE, 1, 921600, /* pbn_timedia */ -+ 0, 0, pci_timedia_fn }, -+ /* EKF addition for i960 Boards form EKF with serial port */ -+ { SPCI_FL_BASE0, 32, 921600, /* max 256 ports */ /* pbn_intel_i960 */ -+ 8<<2, 2, pci_inteli960ni_fn, 0x10000}, -+ { SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE, /* pbn_sgi_ioc3 */ -+ 1, 458333, 0, 0, 0, 0x20178 }, -+#ifdef CONFIG_DDB5074 -+ /* -+ * NEC Vrc-5074 (Nile 4) builtin UART. -+ * Conditionally compiled in since this is a motherboard device. -+ */ -+ { SPCI_FL_BASE0, 1, 520833, /* pbn_nec_nile4 */ -+ 64, 3, NULL, 0x300 }, -+#endif -+#if 0 /* PCI_DEVICE_ID_DCI_PCCOM8 ? */ /* pbn_dci_pccom8 */ -+ { SPCI_FL_BASE3, 8, 115200, 8 }, -+#endif -+ { SPCI_FL_BASE0, 1, 115200, /* pbn_xircom_combo */ -+ 0, 0, pci_xircom_fn }, -+ -+ { SPCI_FL_BASE2, 1, 460800, /* pbn_siig10x_0 */ -+ 0, 0, pci_siig10x_fn }, -+ { SPCI_FL_BASE2, 1, 921600, /* pbn_siig10x_1 */ -+ 0, 0, pci_siig10x_fn }, -+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_siig10x_2 */ -+ 0, 0, pci_siig10x_fn }, -+ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_siig10x_4 */ -+ 0, 0, pci_siig10x_fn }, -+ { SPCI_FL_BASE0, 1, 921600, /* pbn_siix20x_0 */ -+ 0, 0, pci_siig20x_fn }, -+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_siix20x_2 */ -+ 0, 0, pci_siig20x_fn }, -+ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_siix20x_4 */ -+ 0, 0, pci_siig20x_fn }, -+ -+ { SPCI_FL_BASE0, 4, 921600, /* IOMEM */ /* pbn_computone_4 */ -+ 0x40, 2, NULL, 0x200 }, -+ { SPCI_FL_BASE0, 6, 921600, /* IOMEM */ /* pbn_computone_6 */ -+ 0x40, 2, NULL, 0x200 }, -+ { SPCI_FL_BASE0, 8, 921600, /* IOMEM */ /* pbn_computone_8 */ -+ 0x40, 2, NULL, 0x200 }, -+}; -+ -+/* -+ * Given a complete unknown PCI device, try to use some heuristics to -+ * guess what the configuration might be, based on the pitiful PCI -+ * serial specs. Returns 0 on success, 1 on failure. -+ */ -+static int __devinit serial_pci_guess_board(struct pci_dev *dev, -+ struct pci_board *board) -+{ -+ int num_iomem = 0, num_port = 0, first_port = -1; -+ int i; -+ -+ /* -+ * If it is not a communications device or the programming -+ * interface is greater than 6, give up. -+ * -+ * (Should we try to make guesses for multiport serial devices -+ * later?) -+ */ -+ if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) && -+ ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) || -+ (dev->class & 0xff) > 6) -+ return 1; -+ -+ for (i=0; i < 6; i++) { -+ if (IS_PCI_REGION_IOPORT(dev, i)) { -+ num_port++; -+ if (first_port == -1) -+ first_port = i; -+ } -+ if (IS_PCI_REGION_IOMEM(dev, i)) -+ num_iomem++; -+ } -+ -+ /* -+ * If there is 1 or 0 iomem regions, and exactly one port, use -+ * it. -+ */ -+ if (num_iomem <= 1 && num_port == 1) { -+ board->flags = first_port; -+ return 0; -+ } -+ return 1; -+} -+ -+/* -+ * return -1 to refuse -+ */ -+static int pci_init_one(struct pci_dev *dev, const struct pci_device_id *ent) -+{ -+ struct serial_private *priv; -+ struct pci_board *board, tmp; -+ struct serial_struct serial_req; -+ int base_baud, rc, k; -+ -+ board = &pci_boards[ent->driver_data]; -+ -+ rc = pci_enable_device(dev); -+ if (rc) -+ return rc; -+ -+ if (ent->driver_data == pbn_default && -+ serial_pci_guess_board(dev, board)) -+ return -ENODEV; -+ else if (serial_pci_guess_board(dev, &tmp) == 0) { -+ printk(KERN_INFO "Redundant entry in serial pci_table. " -+ "Please send the output of\n" -+ "lspci -vv, this message (%d,%d,%d,%d)\n" -+ "and the manufacturer and name of " -+ "serial board or modem board\n" -+ "to serial-pci-info@lists.sourceforge.net.\n", -+ dev->vendor, dev->device, -+ pci_get_subvendor(dev), pci_get_subdevice(dev)); -+ } -+ -+ -+ priv = kmalloc(sizeof(struct serial_private) + -+ sizeof(unsigned int) * board->num_ports, -+ GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ /* -+ * Run the initialization function, if any -+ */ -+ if (board->init_fn && ((board->init_fn)(dev, board, 1) != 0)) { -+ kfree(priv); -+ return -ENODEV; -+ } -+ -+ base_baud = board->base_baud; -+ if (!base_baud) -+ base_baud = BASE_BAUD; -+ memset(&serial_req, 0, sizeof(serial_req)); -+ for (k=0; k < board->num_ports; k++) { -+ serial_req.irq = get_pci_irq(dev, board, k); -+ if (get_pci_port(dev, board, &serial_req, k)) -+ break; -+#ifdef SERIAL_DEBUG_PCI -+ printk("Setup PCI/PNP port: port %x, irq %d, type %d\n", -+ serial_req.port, serial_req.irq, serial_req.io_type); -+#endif -+ serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE; -+ serial_req.baud_base = base_baud; -+ priv->line[k] = register_serial(&serial_req); -+ if (priv->line[k] < 0) -+ break; -+ } -+ -+ priv->board = board; -+ priv->nr = k; -+ -+ pci_set_drvdata(dev, priv); -+ -+ return 0; -+} -+ -+static void pci_remove_one(struct pci_dev *dev) -+{ -+ struct serial_private *priv = pci_get_drvdata(dev); -+ int i; -+ -+ pci_set_drvdata(dev, NULL); -+ -+ for (i = 0; i < priv->nr; i++) -+ unregister_serial(priv->line[i]); -+ -+ priv->board->init_fn(dev, priv->board, 0); -+ -+ kfree(priv); -+} -+ -+static struct pci_device_id serial_pci_tbl[] __devinitdata = { -+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, -+ PCI_SUBVENDOR_ID_CONNECT_TECH, -+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0, -+ pbn_b1_8_1382400 }, -+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, -+ PCI_SUBVENDOR_ID_CONNECT_TECH, -+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0, -+ pbn_b1_4_1382400 }, -+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, -+ PCI_SUBVENDOR_ID_CONNECT_TECH, -+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0, -+ pbn_b1_2_1382400 }, -+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, -+ PCI_SUBVENDOR_ID_CONNECT_TECH, -+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0, -+ pbn_b1_8_1382400 }, -+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, -+ PCI_SUBVENDOR_ID_CONNECT_TECH, -+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0, -+ pbn_b1_4_1382400 }, -+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, -+ PCI_SUBVENDOR_ID_CONNECT_TECH, -+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0, -+ pbn_b1_2_1382400 }, -+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, -+ PCI_SUBVENDOR_ID_CONNECT_TECH, -+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0, -+ pbn_b1_8_921600 }, -+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, -+ PCI_SUBVENDOR_ID_CONNECT_TECH, -+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0, -+ pbn_b1_8_921600 }, -+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, -+ PCI_SUBVENDOR_ID_CONNECT_TECH, -+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0, -+ pbn_b1_4_921600 }, -+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, -+ PCI_SUBVENDOR_ID_CONNECT_TECH, -+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0, -+ pbn_b1_4_921600 }, -+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, -+ PCI_SUBVENDOR_ID_CONNECT_TECH, -+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0, -+ pbn_b1_2_921600 }, -+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, -+ PCI_SUBVENDOR_ID_CONNECT_TECH, -+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0, -+ pbn_b1_8_921600 }, -+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, -+ PCI_SUBVENDOR_ID_CONNECT_TECH, -+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0, -+ pbn_b1_8_921600 }, -+ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, -+ PCI_SUBVENDOR_ID_CONNECT_TECH, -+ PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0, -+ pbn_b1_4_921600 }, -+ -+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b2_bt_1_115200 }, -+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b2_bt_2_115200 }, -+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b2_bt_4_115200 }, -+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b2_bt_2_115200 }, -+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b2_bt_4_115200 }, -+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b2_8_115200 }, -+ -+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b2_bt_2_115200 }, -+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b2_bt_2_921600 }, -+ /* VScom SPCOM800, from sl@s.pl */ -+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b2_8_921600 }, -+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b2_4_921600 }, -+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, -+ PCI_SUBVENDOR_ID_KEYSPAN, -+ PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0, -+ pbn_panacom }, -+ { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_panacom4 }, -+ { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_panacom2 }, -+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, -+ PCI_SUBVENDOR_ID_CHASE_PCIFAST, -+ PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0, -+ pbn_b2_4_460800 }, -+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, -+ PCI_SUBVENDOR_ID_CHASE_PCIFAST, -+ PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0, -+ pbn_b2_8_460800 }, -+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, -+ PCI_SUBVENDOR_ID_CHASE_PCIFAST, -+ PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0, -+ pbn_b2_16_460800 }, -+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, -+ PCI_SUBVENDOR_ID_CHASE_PCIFAST, -+ PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0, -+ pbn_b2_16_460800 }, -+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, -+ PCI_SUBVENDOR_ID_CHASE_PCIRAS, -+ PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0, -+ pbn_b2_4_460800 }, -+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, -+ PCI_SUBVENDOR_ID_CHASE_PCIRAS, -+ PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0, -+ pbn_b2_8_460800 }, -+ /* Megawolf Romulus PCI Serial Card, from Mike Hudson */ -+ /* (Exoray@isys.ca) */ -+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS, -+ 0x10b5, 0x106a, 0, 0, -+ pbn_plx_romulus }, -+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b1_4_115200 }, -+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b1_2_115200 }, -+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b1_8_115200 }, -+ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b1_8_115200 }, -+ { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954, -+ PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, 0, 0, -+ pbn_b0_4_921600 }, -+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b0_4_115200 }, -+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b0_2_115200 }, -+ -+ /* Digitan DS560-558, from jimd@esoft.com */ -+ { PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b1_1_115200 }, -+ -+ /* 3Com US Robotics 56k Voice Internal PCI model 5610 */ -+ { PCI_VENDOR_ID_USR, 0x1008, -+ PCI_ANY_ID, PCI_ANY_ID, }, -+ -+ /* Titan Electronic cards */ -+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b0_1_921600 }, -+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b0_2_921600 }, -+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b0_4_921600 }, -+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b0_4_921600 }, -+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L, -+ PCI_ANY_ID, PCI_ANY_ID, -+ SPCI_FL_BASE1, 1, 921600 }, -+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L, -+ PCI_ANY_ID, PCI_ANY_ID, -+ SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 }, -+ /* The 400L and 800L have a custom hack in get_pci_port */ -+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L, -+ PCI_ANY_ID, PCI_ANY_ID, -+ SPCI_FL_BASE_TABLE, 4, 921600 }, -+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L, -+ PCI_ANY_ID, PCI_ANY_ID, -+ SPCI_FL_BASE_TABLE, 8, 921600 }, -+ -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig10x_0 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig10x_0 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig10x_0 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig10x_1 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig10x_1 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig10x_1 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig10x_2 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig10x_2 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig10x_2 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig10x_2 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig10x_2 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig10x_2 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig10x_4 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig10x_4 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig10x_4 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig20x_0 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig20x_0 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig20x_0 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig20x_0 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig20x_0 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig20x_0 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig20x_0 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig20x_0 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig20x_0 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig20x_2 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig20x_2 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig20x_2 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig20x_2 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig20x_2 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig20x_2 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig20x_4 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig20x_4 }, -+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_siig20x_4 }, -+ -+ /* Computone devices submitted by Doug McNash dmcnash@computone.com */ -+ { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, -+ PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4, -+ 0, 0, pbn_computone_4 }, -+ { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, -+ PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8, -+ 0, 0, pbn_computone_8 }, -+ { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, -+ PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6, -+ 0, 0, pbn_computone_6 }, -+ -+ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_oxsemi }, -+ { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, -+ PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0, pbn_timedia }, -+ -+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b0_bt_2_115200 }, -+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b0_bt_2_115200 }, -+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b0_bt_2_115200 }, -+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b0_bt_2_460800 }, -+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b0_bt_2_460800 }, -+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b0_bt_2_460800 }, -+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b0_bt_1_115200 }, -+ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b0_bt_1_460800 }, -+ -+ /* RAStel 2 port modem, gerg@moreton.com.au */ -+ { PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_b2_bt_2_115200 }, -+ -+ /* EKF addition for i960 Boards form EKF with serial port */ -+ { PCI_VENDOR_ID_INTEL, 0x1960, -+ 0xE4BF, PCI_ANY_ID, 0, 0, -+ pbn_intel_i960 }, -+ -+ /* Xircom Cardbus/Ethernet combos */ -+ { PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_xircom_combo }, -+ -+ /* -+ * Untested PCI modems, sent in from various folks... -+ */ -+ -+ /* Elsa Model 56K PCI Modem, from Andreas Rath */ -+ { PCI_VENDOR_ID_ROCKWELL, 0x1004, -+ 0x1048, 0x1500, 0, 0, -+ pbn_b1_1_115200 }, -+ -+ { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, -+ 0xFF00, 0, 0, 0, -+ pbn_sgi_ioc3 }, -+ -+#ifdef CONFIG_DDB5074 -+ /* -+ * NEC Vrc-5074 (Nile 4) builtin UART. -+ * Conditionally compiled in since this is a motherboard device. -+ */ -+ { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_nec_nile4 }, -+#endif -+ -+#if 0 /* PCI_DEVICE_ID_DCI_PCCOM8 ? */ -+ { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8, -+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, -+ pbn_dci_pccom8 }, -+#endif -+ -+ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, -+ PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, }, -+ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, -+ PCI_CLASS_COMMUNICATION_MODEM << 8, 0xffff00, }, -+ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, -+ PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00, }, -+ { 0, } -+}; -+ -+static struct pci_driver serial_pci_driver = { -+ name: "serial", -+ probe: pci_init_one, -+ remove: pci_remove_one, -+ id_table: serial_pci_tbl, -+}; -+ -+static int __init serial8250_pci_init(void) -+{ -+ return pci_module_init(&serial_pci_driver); -+} -+ -+static void __exit serial8250_pci_exit(void) -+{ -+ pci_unregister_driver(&serial_pci_driver); -+} -+ -+module_init(serial8250_pci_init); -+module_exit(serial8250_pci_exit); -+ -+EXPORT_NO_SYMBOLS; -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module"); -+MODULE_GENERIC_TABLE(pci, serial_pci_tbl); -diff -urN linux-2.4.26/drivers/serial/8250_pnp.c linux-2.4.26-vrs1/drivers/serial/8250_pnp.c ---- linux-2.4.26/drivers/serial/8250_pnp.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/serial/8250_pnp.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,553 @@ -+/* -+ * linux/drivers/char/serial_8250_pnp.c -+ * -+ * Probe module for 8250/16550-type ISAPNP serial ports. -+ * -+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. -+ * -+ * Copyright (C) 2001 Russell King, All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License. -+ * -+ * $Id: 8250_pnp.c,v 1.3.2.1 2002/10/24 09:53:25 rmk Exp $ -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "8250.h" -+ -+static struct serial_state rs_table[] = { }; -+#define NR_PORTS 0 -+ -+struct pnpbios_device_id -+{ -+ char id[8]; -+ unsigned long driver_data; -+}; -+ -+static const struct pnpbios_device_id pnp_dev_table[] = { -+ /* Archtek America Corp. */ -+ /* Archtek SmartLink Modem 3334BT Plug & Play */ -+ { "AAC000F", 0 }, -+ /* Anchor Datacomm BV */ -+ /* SXPro 144 External Data Fax Modem Plug & Play */ -+ { "ADC0001", 0 }, -+ /* SXPro 288 External Data Fax Modem Plug & Play */ -+ { "ADC0002", 0 }, -+ /* Rockwell 56K ACF II Fax+Data+Voice Modem */ -+ { "AKY1021", SPCI_FL_NO_SHIRQ }, -+ /* AZT3005 PnP SOUND DEVICE */ -+ { "AZT4001", 0 }, -+ /* Best Data Products Inc. Smart One 336F PnP Modem */ -+ { "BDP3336", 0 }, -+ /* Boca Research */ -+ /* Boca Complete Ofc Communicator 14.4 Data-FAX */ -+ { "BRI0A49", 0 }, -+ /* Boca Research 33,600 ACF Modem */ -+ { "BRI1400", 0 }, -+ /* Boca 33.6 Kbps Internal FD34FSVD */ -+ { "BRI3400", 0 }, -+ /* Boca 33.6 Kbps Internal FD34FSVD */ -+ { "BRI0A49", 0 }, -+ /* Best Data Products Inc. Smart One 336F PnP Modem */ -+ { "BDP3336", 0 }, -+ /* Computer Peripherals Inc */ -+ /* EuroViVa CommCenter-33.6 SP PnP */ -+ { "CPI4050", 0 }, -+ /* Creative Labs */ -+ /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */ -+ { "CTL3001", 0 }, -+ /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */ -+ { "CTL3011", 0 }, -+ /* Creative */ -+ /* Creative Modem Blaster Flash56 DI5601-1 */ -+ { "DMB1032", 0 }, -+ /* Creative Modem Blaster V.90 DI5660 */ -+ { "DMB2001", 0 }, -+ /* FUJITSU */ -+ /* Fujitsu 33600 PnP-I2 R Plug & Play */ -+ { "FUJ0202", 0 }, -+ /* Fujitsu FMV-FX431 Plug & Play */ -+ { "FUJ0205", 0 }, -+ /* Fujitsu 33600 PnP-I4 R Plug & Play */ -+ { "FUJ0206", 0 }, -+ /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */ -+ { "FUJ0209", 0 }, -+ /* Archtek America Corp. */ -+ /* Archtek SmartLink Modem 3334BT Plug & Play */ -+ { "GVC000F", 0 }, -+ /* Hayes */ -+ /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */ -+ { "HAY0001", 0 }, -+ /* Hayes Optima 336 V.34 + FAX + Voice PnP */ -+ { "HAY000C", 0 }, -+ /* Hayes Optima 336B V.34 + FAX + Voice PnP */ -+ { "HAY000D", 0 }, -+ /* Hayes Accura 56K Ext Fax Modem PnP */ -+ { "HAY5670", 0 }, -+ /* Hayes Accura 56K Ext Fax Modem PnP */ -+ { "HAY5674", 0 }, -+ /* Hayes Accura 56K Fax Modem PnP */ -+ { "HAY5675", 0 }, -+ /* Hayes 288, V.34 + FAX */ -+ { "HAYF000", 0 }, -+ /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */ -+ { "HAYF001", 0 }, -+ /* IBM */ -+ /* IBM Thinkpad 701 Internal Modem Voice */ -+ { "IBM0033", 0 }, -+ /* Intertex */ -+ /* Intertex 28k8 33k6 Voice EXT PnP */ -+ { "IXDC801", 0 }, -+ /* Intertex 33k6 56k Voice EXT PnP */ -+ { "IXDC901", 0 }, -+ /* Intertex 28k8 33k6 Voice SP EXT PnP */ -+ { "IXDD801", 0 }, -+ /* Intertex 33k6 56k Voice SP EXT PnP */ -+ { "IXDD901", 0 }, -+ /* Intertex 28k8 33k6 Voice SP INT PnP */ -+ { "IXDF401", 0 }, -+ /* Intertex 28k8 33k6 Voice SP EXT PnP */ -+ { "IXDF801", 0 }, -+ /* Intertex 33k6 56k Voice SP EXT PnP */ -+ { "IXDF901", 0 }, -+ /* Kortex International */ -+ /* KORTEX 28800 Externe PnP */ -+ { "KOR4522", 0 }, -+ /* KXPro 33.6 Vocal ASVD PnP */ -+ { "KORF661", 0 }, -+ /* Lasat */ -+ /* LASAT Internet 33600 PnP */ -+ { "LAS4040", 0 }, -+ /* Lasat Safire 560 PnP */ -+ { "LAS4540", 0 }, -+ /* Lasat Safire 336 PnP */ -+ { "LAS5440", 0 }, -+ /* Microcom, Inc. */ -+ /* Microcom TravelPorte FAST V.34 Plug & Play */ -+ { "MNP0281", 0 }, -+ /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */ -+ { "MNP0336", 0 }, -+ /* Microcom DeskPorte FAST EP 28.8 Plug & Play */ -+ { "MNP0339", 0 }, -+ /* Microcom DeskPorte 28.8P Plug & Play */ -+ { "MNP0342", 0 }, -+ /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ -+ { "MNP0500", 0 }, -+ /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ -+ { "MNP0501", 0 }, -+ /* Microcom DeskPorte 28.8S Internal Plug & Play */ -+ { "MNP0502", 0 }, -+ /* Motorola */ -+ /* Motorola BitSURFR Plug & Play */ -+ { "MOT1105", 0 }, -+ /* Motorola TA210 Plug & Play */ -+ { "MOT1111", 0 }, -+ /* Motorola HMTA 200 (ISDN) Plug & Play */ -+ { "MOT1114", 0 }, -+ /* Motorola BitSURFR Plug & Play */ -+ { "MOT1115", 0 }, -+ /* Motorola Lifestyle 28.8 Internal */ -+ { "MOT1190", 0 }, -+ /* Motorola V.3400 Plug & Play */ -+ { "MOT1501", 0 }, -+ /* Motorola Lifestyle 28.8 V.34 Plug & Play */ -+ { "MOT1502", 0 }, -+ /* Motorola Power 28.8 V.34 Plug & Play */ -+ { "MOT1505", 0 }, -+ /* Motorola ModemSURFR External 28.8 Plug & Play */ -+ { "MOT1509", 0 }, -+ /* Motorola Premier 33.6 Desktop Plug & Play */ -+ { "MOT150A", 0 }, -+ /* Motorola VoiceSURFR 56K External PnP */ -+ { "MOT150F", 0 }, -+ /* Motorola ModemSURFR 56K External PnP */ -+ { "MOT1510", 0 }, -+ /* Motorola ModemSURFR 56K Internal PnP */ -+ { "MOT1550", 0 }, -+ /* Motorola ModemSURFR Internal 28.8 Plug & Play */ -+ { "MOT1560", 0 }, -+ /* Motorola Premier 33.6 Internal Plug & Play */ -+ { "MOT1580", 0 }, -+ /* Motorola OnlineSURFR 28.8 Internal Plug & Play */ -+ { "MOT15B0", 0 }, -+ /* Motorola VoiceSURFR 56K Internal PnP */ -+ { "MOT15F0", 0 }, -+ /* Com 1 */ -+ /* Deskline K56 Phone System PnP */ -+ { "MVX00A1", 0 }, -+ /* PC Rider K56 Phone System PnP */ -+ { "MVX00F2", 0 }, -+ /* Pace 56 Voice Internal Plug & Play Modem */ -+ { "PMC2430", 0 }, -+ /* Generic */ -+ /* Generic standard PC COM port */ -+ { "PNP0500", 0 }, -+ /* Generic 16550A-compatible COM port */ -+ { "PNP0501", 0 }, -+ /* Compaq 14400 Modem */ -+ { "PNPC000", 0 }, -+ /* Compaq 2400/9600 Modem */ -+ { "PNPC001", 0 }, -+ /* Dial-Up Networking Serial Cable between 2 PCs */ -+ { "PNPC031", 0 }, -+ /* Dial-Up Networking Parallel Cable between 2 PCs */ -+ { "PNPC032", 0 }, -+ /* Standard 9600 bps Modem */ -+ { "PNPC100", 0 }, -+ /* Standard 14400 bps Modem */ -+ { "PNPC101", 0 }, -+ /* Standard 28800 bps Modem*/ -+ { "PNPC102", 0 }, -+ /* Standard Modem*/ -+ { "PNPC103", 0 }, -+ /* Standard 9600 bps Modem*/ -+ { "PNPC104", 0 }, -+ /* Standard 14400 bps Modem*/ -+ { "PNPC105", 0 }, -+ /* Standard 28800 bps Modem*/ -+ { "PNPC106", 0 }, -+ /* Standard Modem */ -+ { "PNPC107", 0 }, -+ /* Standard 9600 bps Modem */ -+ { "PNPC108", 0 }, -+ /* Standard 14400 bps Modem */ -+ { "PNPC109", 0 }, -+ /* Standard 28800 bps Modem */ -+ { "PNPC10A", 0 }, -+ /* Standard Modem */ -+ { "PNPC10B", 0 }, -+ /* Standard 9600 bps Modem */ -+ { "PNPC10C", 0 }, -+ /* Standard 14400 bps Modem */ -+ { "PNPC10D", 0 }, -+ /* Standard 28800 bps Modem */ -+ { "PNPC10E", 0 }, -+ /* Standard Modem */ -+ { "PNPC10F", 0 }, -+ /* Standard PCMCIA Card Modem */ -+ { "PNP2000", 0 }, -+ /* Rockwell */ -+ /* Modular Technology */ -+ /* Rockwell 33.6 DPF Internal PnP */ -+ /* Modular Technology 33.6 Internal PnP */ -+ { "ROK0030", 0 }, -+ /* Kortex International */ -+ /* KORTEX 14400 Externe PnP */ -+ { "ROK0100", 0 }, -+ /* Viking Components, Inc */ -+ /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */ -+ { "ROK4920", 0 }, -+ /* Rockwell */ -+ /* British Telecom */ -+ /* Modular Technology */ -+ /* Rockwell 33.6 DPF External PnP */ -+ /* BT Prologue 33.6 External PnP */ -+ /* Modular Technology 33.6 External PnP */ -+ { "RSS00A0", 0 }, -+ /* Viking 56K FAX INT */ -+ { "RSS0262", 0 }, -+ /* SupraExpress 28.8 Data/Fax PnP modem */ -+ { "SUP1310", 0 }, -+ /* SupraExpress 33.6 Data/Fax PnP modem */ -+ { "SUP1421", 0 }, -+ /* SupraExpress 33.6 Data/Fax PnP modem */ -+ { "SUP1590", 0 }, -+ /* SupraExpress 33.6 Data/Fax PnP modem */ -+ { "SUP1760", 0 }, -+ /* Phoebe Micro */ -+ /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */ -+ { "TEX0011", 0 }, -+ /* Archtek America Corp. */ -+ /* Archtek SmartLink Modem 3334BT Plug & Play */ -+ { "UAC000F", 0 }, -+ /* 3Com Corp. */ -+ /* Gateway Telepath IIvi 33.6 */ -+ { "USR0000", 0 }, -+ /* Sportster Vi 14.4 PnP FAX Voicemail */ -+ { "USR0004", 0 }, -+ /* U.S. Robotics 33.6K Voice INT PnP */ -+ { "USR0006", 0 }, -+ /* U.S. Robotics 33.6K Voice EXT PnP */ -+ { "USR0007", 0 }, -+ /* U.S. Robotics 33.6K Voice INT PnP */ -+ { "USR2002", 0 }, -+ /* U.S. Robotics 56K Voice INT PnP */ -+ { "USR2070", 0 }, -+ /* U.S. Robotics 56K Voice EXT PnP */ -+ { "USR2080", 0 }, -+ /* U.S. Robotics 56K FAX INT */ -+ { "USR3031", 0 }, -+ /* U.S. Robotics 56K Voice INT PnP */ -+ { "USR3070", 0 }, -+ /* U.S. Robotics 56K Voice EXT PnP */ -+ { "USR3080", 0 }, -+ /* U.S. Robotics 56K Voice INT PnP */ -+ { "USR3090", 0 }, -+ /* U.S. Robotics 56K Message */ -+ { "USR9100", 0 }, -+ /* U.S. Robotics 56K FAX EXT PnP*/ -+ { "USR9160", 0 }, -+ /* U.S. Robotics 56K FAX INT PnP*/ -+ { "USR9170", 0 }, -+ /* U.S. Robotics 56K Voice EXT PnP*/ -+ { "USR9180", 0 }, -+ /* U.S. Robotics 56K Voice INT PnP*/ -+ { "USR9190", 0 }, -+ { "", 0 } -+}; -+ -+static void inline avoid_irq_share(struct pci_dev *dev) -+{ -+ int i, map = 0x1FF8; -+ struct serial_state *state = rs_table; -+ struct isapnp_irq *irq; -+ struct isapnp_resources *res = dev->sysdata; -+ -+ for (i = 0; i < NR_PORTS; i++) { -+ if (state->type != PORT_UNKNOWN) -+ clear_bit(state->irq, &map); -+ state++; -+ } -+ -+ for ( ; res; res = res->alt) -+ for(irq = res->irq; irq; irq = irq->next) -+ irq->map = map; -+} -+ -+static char *modem_names[] __devinitdata = { -+ "MODEM", "Modem", "modem", "FAX", "Fax", "fax", -+ "56K", "56k", "K56", "33.6", "28.8", "14.4", -+ "33,600", "28,800", "14,400", "33.600", "28.800", "14.400", -+ "33600", "28800", "14400", "V.90", "V.34", "V.32", 0 -+}; -+ -+static int __devinit check_name(char *name) -+{ -+ char **tmp; -+ -+ for (tmp = modem_names; *tmp; tmp++) -+ if (strstr(name, *tmp)) -+ return 1; -+ -+ return 0; -+} -+ -+static int inline check_compatible_id(struct pci_dev *dev) -+{ -+ int i; -+ for (i = 0; i < DEVICE_COUNT_COMPATIBLE; i++) -+ if ((dev->vendor_compatible[i] == -+ ISAPNP_VENDOR('P', 'N', 'P')) && -+ (swab16(dev->device_compatible[i]) >= 0xc000) && -+ (swab16(dev->device_compatible[i]) <= 0xdfff)) -+ return 0; -+ return 1; -+} -+ -+/* -+ * Given a complete unknown ISA PnP device, try to use some heuristics to -+ * detect modems. Currently use such heuristic set: -+ * - dev->name or dev->bus->name must contain "modem" substring; -+ * - device must have only one IO region (8 byte long) with base adress -+ * 0x2e8, 0x3e8, 0x2f8 or 0x3f8. -+ * -+ * Such detection looks very ugly, but can detect at least some of numerous -+ * ISA PnP modems, alternatively we must hardcode all modems in pnp_devices[] -+ * table. -+ */ -+static int serial_pnp_guess_board(struct pci_dev *dev, int *flags) -+{ -+ struct isapnp_resources *res = (struct isapnp_resources *)dev->sysdata; -+ struct isapnp_resources *resa; -+ -+ if (!(check_name(dev->name) || check_name(dev->bus->name)) && -+ !(check_compatible_id(dev))) -+ return -ENODEV; -+ -+ if (!res || res->next) -+ return -ENODEV; -+ -+ for (resa = res->alt; resa; resa = resa->alt) { -+ struct isapnp_port *port; -+ for (port = res->port; port; port = port->next) -+ if ((port->size == 8) && -+ ((port->min == 0x2f8) || -+ (port->min == 0x3f8) || -+ (port->min == 0x2e8) || -+ (port->min == 0x3e8))) -+ return 0; -+ } -+ -+ return -ENODEV; -+} -+ -+static int -+pnp_init_one(struct pci_dev *dev, const struct pnpbios_device_id *ent, -+ char *slot_name) -+{ -+ struct serial_struct serial_req; -+ int ret, line, flags = ent ? ent->driver_data : 0; -+ -+ if (!ent) { -+ ret = serial_pnp_guess_board(dev, &flags); -+ if (ret) -+ return ret; -+ } -+ -+ if (dev->prepare(dev) < 0) { -+ printk("serial: PNP device '%s' prepare failed\n", -+ slot_name); -+ return -ENODEV; -+ } -+ -+ if (dev->active) -+ return -ENODEV; -+ -+ if (flags & SPCI_FL_NO_SHIRQ) -+ avoid_irq_share(dev); -+ -+ if (dev->activate(dev) < 0) { -+ printk("serial: PNP device '%s' activate failed\n", -+ slot_name); -+ return -ENODEV; -+ } -+ -+ memset(&serial_req, 0, sizeof(serial_req)); -+ serial_req.irq = dev->irq_resource[0].start; -+ serial_req.port = pci_resource_start(dev, 0); -+ if (HIGH_BITS_OFFSET) -+ serial_req.port = pci_resource_start(dev, 0) >> HIGH_BITS_OFFSET; -+ -+#ifdef SERIAL_DEBUG_PCI -+ printk("Setup PCI/PNP port: port %x, irq %d, type %d\n", -+ serial_req.port, serial_req.irq, serial_req.io_type); -+#endif -+ -+ serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE; -+ serial_req.baud_base = 115200; -+ line = register_serial(&serial_req); -+ -+ if (line >= 0) { -+ pci_set_drvdata(dev, (void *)(line + 1)); -+ -+ /* -+ * Public health warning: remove this once the 2.5 -+ * pnpbios_module_init() stuff is incorporated. -+ */ -+ dev->driver = (void *)pnp_dev_table; -+ } else -+ dev->deactivate(dev); -+ -+ return line >= 0 ? 0 : -ENODEV; -+} -+ -+static void pnp_remove_one(struct pci_dev *dev) -+{ -+ int line = (int)pci_get_drvdata(dev); -+ -+ if (line) { -+ pci_set_drvdata(dev, NULL); -+ -+ unregister_serial(line - 1); -+ -+ dev->deactivate(dev); -+ } -+} -+ -+static char hex[] = "0123456789ABCDEF"; -+ -+/* -+ * This function should vanish when 2.5 comes around and -+ * we have pnpbios_module_init() -+ */ -+static void pnp_init(void) -+{ -+ const struct pnpbios_device_id *id; -+ struct pci_dev *dev = NULL; -+ -+#ifdef SERIAL_DEBUG_PNP -+ printk("Entered probe_serial_pnp()\n"); -+#endif -+ -+ isapnp_for_each_dev(dev) { -+ char slot_name[8]; -+ u32 pnpid; -+ -+ if (dev->active) -+ continue; -+ -+ pnpid = dev->vendor << 16 | dev->device; -+ pnpid = cpu_to_le32(pnpid); -+ -+#define HEX(id,a) hex[((id)>>a) & 15] -+#define CHAR(id,a) (0x40 + (((id)>>a) & 31)) -+ slot_name[0] = CHAR(pnpid, 26); -+ slot_name[1] = CHAR(pnpid, 21); -+ slot_name[2] = CHAR(pnpid, 16); -+ slot_name[3] = HEX(pnpid, 12); -+ slot_name[4] = HEX(pnpid, 8); -+ slot_name[5] = HEX(pnpid, 4); -+ slot_name[6] = HEX(pnpid, 0); -+ slot_name[7] = '\0'; -+ -+ for (id = pnp_dev_table; id->id[0]; id++) -+ if (memcmp(id->id, slot_name, 7) == 0) -+ break; -+ -+ if (id->id[0]) -+ pnp_init_one(dev, id, slot_name); -+ else -+ pnp_init_one(dev, NULL, slot_name); -+ } -+ -+#ifdef SERIAL_DEBUG_PNP -+ printk("Leaving probe_serial_pnp() (probe finished)\n"); -+#endif -+} -+ -+static int __init serial8250_pnp_init(void) -+{ -+ if (!isapnp_present()) { -+#ifdef SERIAL_DEBUG_PNP -+ printk("Leaving probe_serial_pnp() (no isapnp)\n"); -+#endif -+ return -ENODEV; -+ } -+ pnp_init(); -+ return 0; -+} -+ -+static void __exit serial8250_pnp_exit(void) -+{ -+ struct pci_dev *dev = NULL; -+ -+ isapnp_for_each_dev(dev) { -+ if (dev->driver != (void *)pnp_dev_table) -+ continue; -+ pnp_remove_one(dev); -+ } -+} -+ -+module_init(serial8250_pnp_init); -+module_exit(serial8250_pnp_exit); -+ -+EXPORT_NO_SYMBOLS; -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("Generic 8250/16x50 PNPBIOS serial probe module"); -+MODULE_GENERIC_TABLE(pnp, pnp_dev_table); -+ -diff -urN linux-2.4.26/drivers/serial/Config.in linux-2.4.26-vrs1/drivers/serial/Config.in ---- linux-2.4.26/drivers/serial/Config.in 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/serial/Config.in 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,91 @@ -+# -+# Serial device configuration -+# -+# $Id: Config.in,v 1.4 2001/10/12 15:46:58 rmk Exp $ -+# -+mainmenu_option next_comment -+comment 'Serial drivers' -+ -+if [ "$CONFIG_ARM" = "y" ]; then -+ # I don't have this in my tree yet. -+ 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 -+ int ' Default Anakin serial baudrate' CONFIG_ANAKIN_DEFAULT_BAUDRATE 9600 -+ fi -+ -+ dep_tristate 'ARM AMBA serial port support' CONFIG_SERIAL_AMBA $CONFIG_ARCH_INTEGRATOR -+ dep_bool ' Support for console on AMBA serial port' CONFIG_SERIAL_AMBA_CONSOLE $CONFIG_SERIAL_AMBA -+ if [ "$CONFIG_SERIAL_AMBA" = "y" ]; then -+ define_bool CONFIG_SERIAL_INTEGRATOR y -+ fi -+ -+ dep_tristate 'CLPS711X serial port support' CONFIG_SERIAL_CLPS711X $CONFIG_ARCH_CLPS711X -+ dep_bool ' Support for console on CLPS711X serial port' CONFIG_SERIAL_CLPS711X_CONSOLE $CONFIG_SERIAL_CLPS711X -+ -+ dep_bool 'DC21285 serial port support' CONFIG_SERIAL_21285 $CONFIG_FOOTBRIDGE -+ dep_bool ' Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD $CONFIG_SERIAL_21285 $CONFIG_OBSOLETE -+ dep_bool ' Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE $CONFIG_SERIAL_21285 -+ -+ dep_bool 'Excalibur serial port (uart00) support' CONFIG_SERIAL_UART00 $CONFIG_ARCH_CAMELOT -+ dep_bool ' Support for console on Excalibur serial port' CONFIG_SERIAL_UART00_CONSOLE $CONFIG_SERIAL_UART00 -+ -+ -+ dep_bool 'SA1100 serial port support' CONFIG_SERIAL_SA1100 $CONFIG_ARCH_SA1100 -+ dep_bool ' Console on SA1100 serial port' CONFIG_SERIAL_SA1100_CONSOLE $CONFIG_SERIAL_SA1100 -+ if [ "$CONFIG_SERIAL_SA1100" = "y" ]; then -+ int ' Default SA1100 serial baudrate' CONFIG_SA1100_DEFAULT_BAUDRATE 9600 -+ fi -+ -+ dep_tristate 'ARM Omaha serial port support' CONFIG_SERIAL_OMAHA $CONFIG_ARCH_OMAHA -+ dep_bool ' Support for console on Omaha serial port' CONFIG_SERIAL_OMAHA_CONSOLE $CONFIG_SERIAL_OMAHA -+ -+ dep_tristate 'AT91RM9200 serial port support' CONFIG_SERIAL_AT91 $CONFIG_ARCH_AT91RM9200 -+ dep_bool ' Console on AT91RM9200 serial port' CONFIG_SERIAL_AT91_CONSOLE $CONFIG_SERIAL_AT91 -+ -+fi -+# -+# The new 8250/16550 serial drivers -+dep_tristate '8250/16550 and compatible serial support (EXPERIMENTAL)' CONFIG_SERIAL_8250 $CONFIG_EXPERIMENTAL -+dep_bool ' Console on 8250/16550 and compatible serial port (EXPERIMENTAL)' CONFIG_SERIAL_8250_CONSOLE $CONFIG_SERIAL_8250 $CONFIG_EXPERIMENTAL -+ -+dep_mbool 'Extended 8250/16550 serial driver options' CONFIG_SERIAL_8250_EXTENDED $CONFIG_SERIAL_8250 -+dep_bool ' Support more than 4 serial ports' CONFIG_SERIAL_8250_MANY_PORTS $CONFIG_SERIAL_8250_EXTENDED -+dep_bool ' Support for sharing serial interrupts' CONFIG_SERIAL_8250_SHARE_IRQ $CONFIG_SERIAL_8250_EXTENDED -+dep_bool ' Autodetect IRQ on standard ports (unsafe)' CONFIG_SERIAL_8250_DETECT_IRQ $CONFIG_SERIAL_8250_EXTENDED -+dep_bool ' Support special multiport boards' CONFIG_SERIAL_8250_MULTIPORT $CONFIG_SERIAL_8250_EXTENDED -+dep_bool ' Support Bell Technologies HUB6 card' CONFIG_SERIAL_8250_HUB6 $CONFIG_SERIAL_8250_EXTENDED -+ -+if [ "$CONFIG_SERIAL_AMBA" = "y" -o \ -+ "$CONFIG_SERIAL_CLPS711X" = "y" -o \ -+ "$CONFIG_SERIAL_SA1100" = "y" -o \ -+ "$CONFIG_SERIAL_ANAKIN" = "y" -o \ -+ "$CONFIG_SERIAL_UART00" = "y" -o \ -+ "$CONFIG_SERIAL_8250" = "y" -o \ -+ "$CONFIG_SERIAL_OMAHA" = "y" -o \ -+ "$CONFIG_SERIAL_AT91" = "y" ]; then -+ define_bool CONFIG_SERIAL_CORE y -+else -+ if [ "$CONFIG_SERIAL_AMBA" = "m" -o \ -+ "$CONFIG_SERIAL_CLPS711X" = "m" -o \ -+ "$CONFIG_SERIAL_SA1100" = "m" -o \ -+ "$CONFIG_SERIAL_ANAKIN" = "m" -o \ -+ "$CONFIG_SERIAL_UART00" = "m" -o \ -+ "$CONFIG_SERIAL_8250" = "m" -o \ -+ "$CONFIG_SERIAL_OMAHA" = "m" -o \ -+ "$CONFIG_SERIAL_AT91" = "m" ]; then -+ define_bool CONFIG_SERIAL_CORE m -+ fi -+fi -+if [ "$CONFIG_SERIAL_AMBA_CONSOLE" = "y" -o \ -+ "$CONFIG_SERIAL_CLPS711X_CONSOLE" = "y" -o \ -+ "$CONFIG_SERIAL_SA1100_CONSOLE" = "y" -o \ -+ "$CONFIG_SERIAL_ANAKIN_CONSOLE" = "y" -o \ -+ "$CONFIG_SERIAL_UART00_CONSOLE" = "y" -o \ -+ "$CONFIG_SERIAL_8250_CONSOLE" = "y" -o \ -+ "$CONFIG_SERIAL_OMAHA" = "y" -o \ -+ "$CONFIG_SERIAL_AT91_CONSOLE" = "y" ]; then -+ define_bool CONFIG_SERIAL_CORE_CONSOLE y -+fi -+ -+endmenu -diff -urN linux-2.4.26/drivers/serial/Makefile linux-2.4.26-vrs1/drivers/serial/Makefile ---- linux-2.4.26/drivers/serial/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/serial/Makefile 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,39 @@ -+# -+# Makefile for the kernel serial device drivers. -+# -+# Note! Dependencies are done automagically by 'make dep', which also -+# removes any old dependencies. DON'T put your own dependencies here -+# unless it's something special (ie not a .c file). -+# -+# Note 2! The CFLAGS definitions are now inherited from the -+# parent makes.. -+# -+# $Id: Makefile,v 1.2 2001/10/12 15:46:58 rmk Exp $ -+# -+ -+O_TARGET := serial.o -+ -+export-objs := core.o 8250.o -+obj-y := -+obj-m := -+obj-n := -+obj- := -+ -+serial-8250-y := -+serial-8250-$(CONFIG_PCI) += 8250_pci.o -+serial-8250-$(CONFIG_ISAPNP) += 8250_pnp.o -+obj-$(CONFIG_SERIAL_CORE) += core.o -+obj-$(CONFIG_SERIAL_21285) += 21285.o -+obj-$(CONFIG_SERIAL_8250) += 8250.o $(serial-8250-y) -+obj-$(CONFIG_SERIAL_ANAKIN) += anakin.o -+obj-$(CONFIG_SERIAL_AMBA) += amba.o -+obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o -+obj-$(CONFIG_SERIAL_SA1100) += sa1100.o -+obj-$(CONFIG_SERIAL_UART00) += uart00.o -+obj-$(CONFIG_SERIAL_OMAHA) += omaha.o -+obj-$(CONFIG_SERIAL_AT91US3) += at91us3.o -+ -+include $(TOPDIR)/Rules.make -+ -+fastdep: -+ -diff -urN linux-2.4.26/drivers/serial/amba.c linux-2.4.26-vrs1/drivers/serial/amba.c ---- linux-2.4.26/drivers/serial/amba.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/serial/amba.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,770 @@ -+/* -+ * linux/drivers/char/serial_amba.c -+ * -+ * Driver for AMBA serial ports -+ * -+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. -+ * -+ * Copyright 1999 ARM Limited -+ * Copyright (C) 2000 Deep Blue Solutions Ltd. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * $Id: amba.c,v 1.9.2.2 2002/10/24 09:53:25 rmk Exp $ -+ * -+ * This is a generic driver for ARM AMBA-type serial ports. They -+ * have a lot of 16550-like features, but are not register compatable. -+ * Note that although they do have CTS, DCD and DSR inputs, they do -+ * not have an RI input, nor do they have DTR or RTS outputs. If -+ * required, these have to be supplied via some other means (eg, GPIO) -+ * and hooked into this driver. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#if defined(CONFIG_SERIAL_AMBA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -+#define SUPPORT_SYSRQ -+#endif -+ -+#include -+ -+#include -+ -+#define UART_NR 2 -+ -+#define SERIAL_AMBA_MAJOR 204 -+#define SERIAL_AMBA_MINOR 16 -+#define SERIAL_AMBA_NR UART_NR -+ -+#define CALLOUT_AMBA_NAME "cuaam" -+#define CALLOUT_AMBA_MAJOR 205 -+#define CALLOUT_AMBA_MINOR 16 -+#define CALLOUT_AMBA_NR UART_NR -+ -+static struct tty_driver normal, callout; -+static struct tty_struct *amba_table[UART_NR]; -+static struct termios *amba_termios[UART_NR], *amba_termios_locked[UART_NR]; -+#ifdef SUPPORT_SYSRQ -+static struct console amba_console; -+#endif -+ -+#define AMBA_ISR_PASS_LIMIT 256 -+ -+/* -+ * Access macros for the AMBA UARTs -+ */ -+#define UART_GET_INT_STATUS(p) readb((p)->membase + AMBA_UARTIIR) -+#define UART_PUT_ICR(p, c) writel((c), (p)->membase + AMBA_UARTICR) -+#define UART_GET_FR(p) readb((p)->membase + AMBA_UARTFR) -+#define UART_GET_CHAR(p) readb((p)->membase + AMBA_UARTDR) -+#define UART_PUT_CHAR(p, c) writel((c), (p)->membase + AMBA_UARTDR) -+#define UART_GET_RSR(p) readb((p)->membase + AMBA_UARTRSR) -+#define UART_GET_CR(p) readb((p)->membase + AMBA_UARTCR) -+#define UART_PUT_CR(p,c) writel((c), (p)->membase + AMBA_UARTCR) -+#define UART_GET_LCRL(p) readb((p)->membase + AMBA_UARTLCR_L) -+#define UART_PUT_LCRL(p,c) writel((c), (p)->membase + AMBA_UARTLCR_L) -+#define UART_GET_LCRM(p) readb((p)->membase + AMBA_UARTLCR_M) -+#define UART_PUT_LCRM(p,c) writel((c), (p)->membase + AMBA_UARTLCR_M) -+#define UART_GET_LCRH(p) readb((p)->membase + AMBA_UARTLCR_H) -+#define UART_PUT_LCRH(p,c) writel((c), (p)->membase + AMBA_UARTLCR_H) -+#define UART_RX_DATA(s) (((s) & AMBA_UARTFR_RXFE) == 0) -+#define UART_TX_READY(s) (((s) & AMBA_UARTFR_TXFF) == 0) -+#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & AMBA_UARTFR_TMSK) == 0) -+ -+#define UART_DUMMY_RSR_RX 256 -+#define UART_PORT_SIZE 64 -+ -+/* -+ * On the Integrator platform, the port RTS and DTR are provided by -+ * bits in the following SC_CTRLS register bits: -+ * RTS DTR -+ * UART0 7 6 -+ * UART1 5 4 -+ */ -+#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET) -+#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET) -+ -+/* -+ * We wrap our port structure around the generic uart_port. -+ */ -+struct uart_amba_port { -+ struct uart_port port; -+ unsigned int dtr_mask; -+ unsigned int rts_mask; -+ unsigned int old_status; -+}; -+ -+static void ambauart_stop_tx(struct uart_port *port, unsigned int tty_stop) -+{ -+ unsigned int cr; -+ -+ cr = UART_GET_CR(port); -+ cr &= ~AMBA_UARTCR_TIE; -+ UART_PUT_CR(port, cr); -+} -+ -+static void ambauart_start_tx(struct uart_port *port, unsigned int tty_start) -+{ -+ unsigned int cr; -+ -+ cr = UART_GET_CR(port); -+ cr |= AMBA_UARTCR_TIE; -+ UART_PUT_CR(port, cr); -+} -+ -+static void ambauart_stop_rx(struct uart_port *port) -+{ -+ unsigned int cr; -+ -+ cr = UART_GET_CR(port); -+ cr &= ~(AMBA_UARTCR_RIE | AMBA_UARTCR_RTIE); -+ UART_PUT_CR(port, cr); -+} -+ -+static void ambauart_enable_ms(struct uart_port *port) -+{ -+ unsigned int cr; -+ -+ cr = UART_GET_CR(port); -+ cr |= AMBA_UARTCR_MSIE; -+ UART_PUT_CR(port, cr); -+} -+ -+static void -+#ifdef SUPPORT_SYSRQ -+ambauart_rx_chars(struct uart_port *port, struct pt_regs *regs) -+#else -+ambauart_rx_chars(struct uart_port *port) -+#endif -+{ -+ struct tty_struct *tty = port->info->tty; -+ unsigned int status, ch, rsr, max_count = 256; -+ -+ status = UART_GET_FR(port); -+ while (UART_RX_DATA(status) && max_count--) { -+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) { -+ tty->flip.tqueue.routine((void *)tty); -+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) { -+ printk(KERN_WARNING "TTY_DONT_FLIP set\n"); -+ return; -+ } -+ } -+ -+ ch = UART_GET_CHAR(port); -+ -+ *tty->flip.char_buf_ptr = ch; -+ *tty->flip.flag_buf_ptr = TTY_NORMAL; -+ port->icount.rx++; -+ -+ /* -+ * Note that the error handling code is -+ * out of the main execution path -+ */ -+ rsr = UART_GET_RSR(port) | UART_DUMMY_RSR_RX; -+ if (rsr & AMBA_UARTRSR_ANY) { -+ if (rsr & AMBA_UARTRSR_BE) { -+ rsr &= ~(AMBA_UARTRSR_FE | AMBA_UARTRSR_PE); -+ port->icount.brk++; -+ if (uart_handle_break(port)) -+ goto ignore_char; -+ } else if (rsr & AMBA_UARTRSR_PE) -+ port->icount.parity++; -+ else if (rsr & AMBA_UARTRSR_FE) -+ port->icount.frame++; -+ if (rsr & AMBA_UARTRSR_OE) -+ port->icount.overrun++; -+ -+ rsr &= port->read_status_mask; -+ -+ if (rsr & AMBA_UARTRSR_BE) -+ *tty->flip.flag_buf_ptr = TTY_BREAK; -+ else if (rsr & AMBA_UARTRSR_PE) -+ *tty->flip.flag_buf_ptr = TTY_PARITY; -+ else if (rsr & AMBA_UARTRSR_FE) -+ *tty->flip.flag_buf_ptr = TTY_FRAME; -+ } -+ -+ if (uart_handle_sysrq_char(port, ch, regs)) -+ goto ignore_char; -+ -+ if ((rsr & port->ignore_status_mask) == 0) { -+ tty->flip.flag_buf_ptr++; -+ tty->flip.char_buf_ptr++; -+ tty->flip.count++; -+ } -+ if ((rsr & AMBA_UARTRSR_OE) && -+ tty->flip.count < TTY_FLIPBUF_SIZE) { -+ /* -+ * Overrun is special, since it's reported -+ * immediately, and doesn't affect the current -+ * character -+ */ -+ *tty->flip.char_buf_ptr++ = 0; -+ *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; -+ tty->flip.count++; -+ } -+ ignore_char: -+ status = UART_GET_FR(port); -+ } -+ tty_flip_buffer_push(tty); -+ return; -+} -+ -+static void ambauart_tx_chars(struct uart_port *port) -+{ -+ struct circ_buf *xmit = &port->info->xmit; -+ int count; -+ -+ if (port->x_char) { -+ UART_PUT_CHAR(port, port->x_char); -+ port->icount.tx++; -+ port->x_char = 0; -+ return; -+ } -+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { -+ ambauart_stop_tx(port, 0); -+ return; -+ } -+ -+ count = port->fifosize >> 1; -+ do { -+ UART_PUT_CHAR(port, xmit->buf[xmit->tail]); -+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); -+ port->icount.tx++; -+ if (uart_circ_empty(xmit)) -+ break; -+ } while (--count > 0); -+ -+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) -+ uart_write_wakeup(port); -+ -+ if (uart_circ_empty(xmit)) -+ ambauart_stop_tx(port, 0); -+} -+ -+static void ambauart_modem_status(struct uart_port *port) -+{ -+ struct uart_amba_port *uap = (struct uart_amba_port *)port; -+ unsigned int status, delta; -+ -+ UART_PUT_ICR(&uap->port, 0); -+ -+ status = UART_GET_FR(&uap->port) & AMBA_UARTFR_MODEM_ANY; -+ -+ delta = status ^ uap->old_status; -+ uap->old_status = status; -+ -+ if (!delta) -+ return; -+ -+ if (delta & AMBA_UARTFR_DCD) -+ uart_handle_dcd_change(&uap->port, status & AMBA_UARTFR_DCD); -+ -+ if (delta & AMBA_UARTFR_DSR) -+ uap->port.icount.dsr++; -+ -+ if (delta & AMBA_UARTFR_CTS) -+ uart_handle_cts_change(&uap->port, status & AMBA_UARTFR_CTS); -+ -+ wake_up_interruptible(&uap->port.info->delta_msr_wait); -+} -+ -+static void ambauart_int(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ struct uart_port *port = dev_id; -+ unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; -+ -+ status = UART_GET_INT_STATUS(port); -+ do { -+ if (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS)) -+#ifdef SUPPORT_SYSRQ -+ ambauart_rx_chars(port, regs); -+#else -+ ambauart_rx_chars(port); -+#endif -+ if (status & AMBA_UARTIIR_TIS) -+ ambauart_tx_chars(port); -+ if (status & AMBA_UARTIIR_MIS) -+ ambauart_modem_status(port); -+ -+ if (pass_counter-- == 0) -+ break; -+ -+ status = UART_GET_INT_STATUS(port); -+ } while (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS | -+ AMBA_UARTIIR_TIS)); -+} -+ -+static unsigned int ambauart_tx_empty(struct uart_port *port) -+{ -+ return UART_GET_FR(port) & AMBA_UARTFR_BUSY ? 0 : TIOCSER_TEMT; -+} -+ -+static unsigned int ambauart_get_mctrl(struct uart_port *port) -+{ -+ unsigned int result = 0; -+ unsigned int status; -+ -+ status = UART_GET_FR(port); -+ if (status & AMBA_UARTFR_DCD) -+ result |= TIOCM_CAR; -+ if (status & AMBA_UARTFR_DSR) -+ result |= TIOCM_DSR; -+ if (status & AMBA_UARTFR_CTS) -+ result |= TIOCM_CTS; -+ -+ return result; -+} -+ -+static void ambauart_set_mctrl(struct uart_port *port, unsigned int mctrl) -+{ -+ struct uart_amba_port *uap = (struct uart_amba_port *)port; -+ unsigned int ctrls = 0, ctrlc = 0; -+ -+ if (mctrl & TIOCM_RTS) -+ ctrlc |= uap->rts_mask; -+ else -+ ctrls |= uap->rts_mask; -+ -+ if (mctrl & TIOCM_DTR) -+ ctrlc |= uap->dtr_mask; -+ else -+ ctrls |= uap->dtr_mask; -+ -+ __raw_writel(ctrls, SC_CTRLS); -+ __raw_writel(ctrlc, SC_CTRLC); -+} -+ -+static void ambauart_break_ctl(struct uart_port *port, int break_state) -+{ -+ unsigned long flags; -+ unsigned int lcr_h; -+ -+ spin_lock_irqsave(&port->lock, flags); -+ lcr_h = UART_GET_LCRH(port); -+ if (break_state == -1) -+ lcr_h |= AMBA_UARTLCR_H_BRK; -+ else -+ lcr_h &= ~AMBA_UARTLCR_H_BRK; -+ UART_PUT_LCRH(port, lcr_h); -+ spin_unlock_irqrestore(&port->lock, flags); -+} -+ -+static int ambauart_startup(struct uart_port *port) -+{ -+ struct uart_amba_port *uap = (struct uart_amba_port *)port; -+ int retval; -+ -+ /* -+ * Allocate the IRQ -+ */ -+ retval = request_irq(port->irq, ambauart_int, 0, "amba", port); -+ if (retval) -+ return retval; -+ -+ /* -+ * initialise the old status of the modem signals -+ */ -+ uap->old_status = UART_GET_FR(port) & AMBA_UARTFR_MODEM_ANY; -+ -+ /* -+ * Finally, enable interrupts -+ */ -+ UART_PUT_CR(port, AMBA_UARTCR_UARTEN | AMBA_UARTCR_RIE | -+ AMBA_UARTCR_RTIE); -+ -+ return 0; -+} -+ -+static void ambauart_shutdown(struct uart_port *port) -+{ -+ /* -+ * Free the interrupt -+ */ -+ free_irq(port->irq, port); -+ -+ /* -+ * disable all interrupts, disable the port -+ */ -+ UART_PUT_CR(port, 0); -+ -+ /* disable break condition and fifos */ -+ UART_PUT_LCRH(port, UART_GET_LCRH(port) & -+ ~(AMBA_UARTLCR_H_BRK | AMBA_UARTLCR_H_FEN)); -+} -+ -+static void ambauart_change_speed(struct uart_port *port, unsigned int cflag, unsigned int iflag, unsigned int quot) -+{ -+ unsigned int lcr_h, old_cr; -+ unsigned long flags; -+ -+#if DEBUG -+ printk("ambauart_set_cflag(0x%x) called\n", cflag); -+#endif -+ /* byte size and parity */ -+ switch (cflag & CSIZE) { -+ case CS5: -+ lcr_h = AMBA_UARTLCR_H_WLEN_5; -+ break; -+ case CS6: -+ lcr_h = AMBA_UARTLCR_H_WLEN_6; -+ break; -+ case CS7: -+ lcr_h = AMBA_UARTLCR_H_WLEN_7; -+ break; -+ default: // CS8 -+ lcr_h = AMBA_UARTLCR_H_WLEN_8; -+ break; -+ } -+ if (cflag & CSTOPB) -+ lcr_h |= AMBA_UARTLCR_H_STP2; -+ if (cflag & PARENB) { -+ lcr_h |= AMBA_UARTLCR_H_PEN; -+ if (!(cflag & PARODD)) -+ lcr_h |= AMBA_UARTLCR_H_EPS; -+ } -+ if (port->fifosize > 1) -+ lcr_h |= AMBA_UARTLCR_H_FEN; -+ -+ spin_lock_irqsave(&port->lock, flags); -+ -+ port->read_status_mask = AMBA_UARTRSR_OE; -+ if (iflag & INPCK) -+ port->read_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE; -+ if (iflag & (BRKINT | PARMRK)) -+ port->read_status_mask |= AMBA_UARTRSR_BE; -+ -+ /* -+ * Characters to ignore -+ */ -+ port->ignore_status_mask = 0; -+ if (iflag & IGNPAR) -+ port->ignore_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE; -+ if (iflag & IGNBRK) { -+ port->ignore_status_mask |= AMBA_UARTRSR_BE; -+ /* -+ * If we're ignoring parity and break indicators, -+ * ignore overruns too (for real raw support). -+ */ -+ if (iflag & IGNPAR) -+ port->ignore_status_mask |= AMBA_UARTRSR_OE; -+ } -+ -+ /* -+ * Ignore all characters if CREAD is not set. -+ */ -+ if ((cflag & CREAD) == 0) -+ port->ignore_status_mask |= UART_DUMMY_RSR_RX; -+ -+ old_cr = UART_GET_CR(port) & ~AMBA_UARTCR_MSIE; -+ -+ if (UART_ENABLE_MS(port, cflag)) -+ old_cr |= AMBA_UARTCR_MSIE; -+ -+ UART_PUT_CR(port, 0); -+ -+ /* Set baud rate */ -+ quot -= 1; -+ UART_PUT_LCRM(port, ((quot & 0xf00) >> 8)); -+ UART_PUT_LCRL(port, (quot & 0xff)); -+ -+ /* -+ * ----------v----------v----------v----------v----- -+ * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L -+ * ----------^----------^----------^----------^----- -+ */ -+ UART_PUT_LCRH(port, lcr_h); -+ UART_PUT_CR(port, old_cr); -+ -+ spin_unlock_irqrestore(&port->lock, flags); -+} -+ -+static const char *ambauart_type(struct uart_port *port) -+{ -+ return port->type == PORT_AMBA ? "AMBA" : NULL; -+} -+ -+/* -+ * Release the memory region(s) being used by 'port' -+ */ -+static void ambauart_release_port(struct uart_port *port) -+{ -+ release_mem_region(port->mapbase, UART_PORT_SIZE); -+} -+ -+/* -+ * Request the memory region(s) being used by 'port' -+ */ -+static int ambauart_request_port(struct uart_port *port) -+{ -+ return request_mem_region(port->mapbase, UART_PORT_SIZE, "serial_amba") -+ != NULL ? 0 : -EBUSY; -+} -+ -+/* -+ * Configure/autoconfigure the port. -+ */ -+static void ambauart_config_port(struct uart_port *port, int flags) -+{ -+ if (flags & UART_CONFIG_TYPE) { -+ port->type = PORT_AMBA; -+ ambauart_request_port(port); -+ } -+} -+ -+/* -+ * verify the new serial_struct (for TIOCSSERIAL). -+ */ -+static int ambauart_verify_port(struct uart_port *port, struct serial_struct *ser) -+{ -+ int ret = 0; -+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA) -+ ret = -EINVAL; -+ if (ser->irq < 0 || ser->irq >= NR_IRQS) -+ ret = -EINVAL; -+ if (ser->baud_base < 9600) -+ ret = -EINVAL; -+ return ret; -+} -+ -+static struct uart_ops amba_pops = { -+ .tx_empty = ambauart_tx_empty, -+ .set_mctrl = ambauart_set_mctrl, -+ .get_mctrl = ambauart_get_mctrl, -+ .stop_tx = ambauart_stop_tx, -+ .start_tx = ambauart_start_tx, -+ .stop_rx = ambauart_stop_rx, -+ .enable_ms = ambauart_enable_ms, -+ .break_ctl = ambauart_break_ctl, -+ .startup = ambauart_startup, -+ .shutdown = ambauart_shutdown, -+ .change_speed = ambauart_change_speed, -+ .type = ambauart_type, -+ .release_port = ambauart_release_port, -+ .request_port = ambauart_request_port, -+ .config_port = ambauart_config_port, -+ .verify_port = ambauart_verify_port, -+}; -+ -+static struct uart_amba_port amba_ports[UART_NR] = { -+ { -+ .port = { -+ .membase = (void *)IO_ADDRESS(INTEGRATOR_UART0_BASE), -+ .mapbase = INTEGRATOR_UART0_BASE, -+ .iotype = SERIAL_IO_MEM, -+ .irq = IRQ_UARTINT0, -+ .uartclk = 14745600, -+ .fifosize = 16, -+ .ops = &amba_pops, -+ .flags = ASYNC_BOOT_AUTOCONF, -+ .line = 0, -+ }, -+ .dtr_mask = 1 << 5, -+ .rts_mask = 1 << 4, -+ }, -+ { -+ .port = { -+ .membase = (void *)IO_ADDRESS(INTEGRATOR_UART1_BASE), -+ .mapbase = INTEGRATOR_UART1_BASE, -+ .iotype = SERIAL_IO_MEM, -+ .irq = IRQ_UARTINT1, -+ .uartclk = 14745600, -+ .fifosize = 16, -+ .ops = &amba_pops, -+ .flags = ASYNC_BOOT_AUTOCONF, -+ .line = 1, -+ }, -+ .dtr_mask = 1 << 7, -+ .rts_mask = 1 << 6, -+ } -+}; -+ -+#ifdef CONFIG_SERIAL_AMBA_CONSOLE -+ -+static void ambauart_console_write(struct console *co, const char *s, unsigned int count) -+{ -+ struct uart_port *port = &amba_ports[co->index].port; -+ unsigned int status, old_cr; -+ int i; -+ -+ /* -+ * First save the CR then disable the interrupts -+ */ -+ old_cr = UART_GET_CR(port); -+ UART_PUT_CR(port, AMBA_UARTCR_UARTEN); -+ -+ /* -+ * Now, do each character -+ */ -+ for (i = 0; i < count; i++) { -+ do { -+ status = UART_GET_FR(port); -+ } while (!UART_TX_READY(status)); -+ UART_PUT_CHAR(port, s[i]); -+ if (s[i] == '\n') { -+ do { -+ status = UART_GET_FR(port); -+ } while (!UART_TX_READY(status)); -+ UART_PUT_CHAR(port, '\r'); -+ } -+ } -+ -+ /* -+ * Finally, wait for transmitter to become empty -+ * and restore the TCR -+ */ -+ do { -+ status = UART_GET_FR(port); -+ } while (status & AMBA_UARTFR_BUSY); -+ UART_PUT_CR(port, old_cr); -+} -+ -+static kdev_t ambauart_console_device(struct console *co) -+{ -+ return MKDEV(SERIAL_AMBA_MAJOR, SERIAL_AMBA_MINOR + co->index); -+} -+ -+static void __init -+ambauart_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) -+{ -+ if (UART_GET_CR(port) & AMBA_UARTCR_UARTEN) { -+ unsigned int lcr_h, quot; -+ lcr_h = UART_GET_LCRH(port); -+ -+ *parity = 'n'; -+ if (lcr_h & AMBA_UARTLCR_H_PEN) { -+ if (lcr_h & AMBA_UARTLCR_H_EPS) -+ *parity = 'e'; -+ else -+ *parity = 'o'; -+ } -+ -+ if ((lcr_h & 0x60) == AMBA_UARTLCR_H_WLEN_7) -+ *bits = 7; -+ else -+ *bits = 8; -+ -+ quot = UART_GET_LCRL(port) | UART_GET_LCRM(port) << 8; -+ *baud = port->uartclk / (16 * (quot + 1)); -+ } -+} -+ -+static int __init ambauart_console_setup(struct console *co, char *options) -+{ -+ struct uart_port *port; -+ int baud = 38400; -+ int bits = 8; -+ int parity = 'n'; -+ int flow = 'n'; -+ -+ /* -+ * Check whether an invalid uart number has been specified, and -+ * if so, search for the first available port that does have -+ * console support. -+ */ -+ if (co->index >= UART_NR) -+ co->index = 0; -+ port = &amba_ports[co->index].port; -+ -+ if (options) -+ uart_parse_options(options, &baud, &parity, &bits, &flow); -+ else -+ ambauart_console_get_options(port, &baud, &parity, &bits); -+ -+ return uart_set_options(port, co, baud, parity, bits, flow); -+} -+ -+static struct console amba_console = { -+ .name = "ttyAM", -+ .write = ambauart_console_write, -+ .device = ambauart_console_device, -+ .setup = ambauart_console_setup, -+ .flags = CON_PRINTBUFFER, -+ .index = -1, -+}; -+ -+void __init ambauart_console_init(void) -+{ -+ register_console(&amba_console); -+} -+ -+#define AMBA_CONSOLE &amba_console -+#else -+#define AMBA_CONSOLE NULL -+#endif -+ -+static struct uart_driver amba_reg = { -+ .owner = THIS_MODULE, -+ .normal_major = SERIAL_AMBA_MAJOR, -+#ifdef CONFIG_DEVFS_FS -+ .normal_name = "ttyAM%d", -+ .callout_name = "cuaam%d", -+#else -+ .normal_name = "ttyAM", -+ .callout_name = "cuaam", -+#endif -+ .normal_driver = &normal, -+ .callout_major = CALLOUT_AMBA_MAJOR, -+ .callout_driver = &callout, -+ .table = amba_table, -+ .termios = amba_termios, -+ .termios_locked = amba_termios_locked, -+ .minor = SERIAL_AMBA_MINOR, -+ .nr = UART_NR, -+ .cons = AMBA_CONSOLE, -+}; -+ -+static int __init ambauart_init(void) -+{ -+ int ret; -+ -+ ret = uart_register_driver(&amba_reg); -+ if (ret == 0) { -+ int i; -+ -+ for (i = 0; i < UART_NR; i++) -+ uart_add_one_port(&amba_reg, &amba_ports[i].port); -+ } -+ return ret; -+} -+ -+static void __exit ambauart_exit(void) -+{ -+ int i; -+ -+ for (i = 0; i < UART_NR; i++) -+ uart_remove_one_port(&amba_reg, &amba_ports[i].port); -+ -+ uart_unregister_driver(&amba_reg); -+} -+ -+module_init(ambauart_init); -+module_exit(ambauart_exit); -+ -+EXPORT_NO_SYMBOLS; -+ -+MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd"); -+MODULE_DESCRIPTION("ARM AMBA serial port driver"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.4.26/drivers/serial/anakin.c linux-2.4.26-vrs1/drivers/serial/anakin.c ---- linux-2.4.26/drivers/serial/anakin.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/serial/anakin.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,545 @@ -+/* -+ * linux/drivers/char/serial_anakin.c -+ * -+ * Based on driver for AMBA serial ports, by ARM Limited, -+ * Deep Blue Solutions Ltd., Linus Torvalds and Theodore Ts'o. -+ * -+ * Copyright (C) 2001 Aleph One Ltd. for Acunia N.V. -+ * -+ * Copyright (C) 2001 Blue Mug, Inc. for Acunia N.V. -+ * -+ * 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: -+ * 20-Apr-2001 TTC Created -+ * 05-May-2001 W/TTC Updated for serial_core.c -+ * 27-Jun-2001 jonm Minor changes; add mctrl support, switch to -+ * SA_INTERRUPT. Works reliably now. No longer requires -+ * changes to the serial_core API. -+ * -+ * $Id: anakin.c,v 1.5.2.2 2002/10/24 09:53:25 rmk Exp $ -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include -+ -+#define UART_NR 5 -+ -+#define SERIAL_ANAKIN_NAME "ttyAN" -+#define SERIAL_ANAKIN_MAJOR 204 -+#define SERIAL_ANAKIN_MINOR 32 -+ -+#define CALLOUT_ANAKIN_NAME "cuaan" -+#define CALLOUT_ANAKIN_MAJOR 205 -+#define CALLOUT_ANAKIN_MINOR 32 -+ -+static struct tty_driver normal, callout; -+static struct tty_struct *anakin_table[UART_NR]; -+static struct termios *anakin_termios[UART_NR], *anakin_termios_locked[UART_NR]; -+static struct uart_state anakin_state[UART_NR]; -+static u_int txenable[NR_IRQS]; /* Software interrupt register */ -+ -+static inline unsigned int -+anakin_in(struct uart_port *port, u_int offset) -+{ -+ return __raw_readl(port->base + offset); -+} -+ -+static inline void -+anakin_out(struct uart_port *port, u_int offset, unsigned int value) -+{ -+ __raw_writel(value, port->base + offset); -+} -+ -+static void -+anakin_stop_tx(struct uart_port *port, u_int from_tty) -+{ -+ txenable[port->irq] = 0; -+} -+ -+static inline void -+anakin_transmit_buffer(struct uart_info *info) -+{ -+ struct uart_port *port = info->port; -+ -+ while (!(anakin_in(port, 0x10) & TXEMPTY)); -+ anakin_out(port, 0x14, info->xmit.buf[info->xmit.tail]); -+ anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST); -+ info->xmit.tail = (info->xmit.tail + 1) & (UART_XMIT_SIZE-1); -+ info->state->icount.tx++; -+ -+ if (info->xmit.head == info->xmit.tail) -+ anakin_stop_tx(port, 0); -+} -+ -+static inline void -+anakin_transmit_x_char(struct uart_info *info) -+{ -+ struct uart_port *port = info->port; -+ -+ anakin_out(port, 0x14, info->x_char); -+ anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST); -+ info->state->icount.tx++; -+ info->x_char = 0; -+} -+ -+static void -+anakin_start_tx(struct uart_port *port, u_int nonempty, u_int from_tty) -+{ -+ unsigned int flags; -+ -+ save_flags_cli(flags); -+ -+ // is it this... or below: if (nonempty -+ if (!txenable[port->irq]) { -+ txenable[port->irq] = TXENABLE; -+ -+ if ((anakin_in(port, 0x10) & TXEMPTY) && nonempty) { -+ anakin_transmit_buffer((struct uart_info*)port->unused); -+ } -+ } -+ -+ restore_flags(flags); -+} -+ -+static void -+anakin_stop_rx(struct uart_port *port) -+{ -+ unsigned long flags; -+ -+ save_flags_cli(flags); -+ while (anakin_in(port, 0x10) & RXRELEASE) -+ anakin_in(port, 0x14); -+ anakin_out(port, 0x18, anakin_in(port, 0x18) | BLOCKRX); -+ restore_flags(flags); -+} -+ -+static void -+anakin_enable_ms(struct uart_port *port) -+{ -+} -+ -+static inline void -+anakin_rx_chars(struct uart_info *info) -+{ -+ unsigned int ch; -+ struct tty_struct *tty = info->tty; -+ -+ if (!(anakin_in(info->port, 0x10) & RXRELEASE)) -+ return; -+ -+ ch = anakin_in(info->port, 0x14) & 0xff; -+ -+ if (tty->flip.count < TTY_FLIPBUF_SIZE) { -+ *tty->flip.char_buf_ptr++ = ch; -+ *tty->flip.flag_buf_ptr++ = TTY_NORMAL; -+ info->state->icount.rx++; -+ tty->flip.count++; -+ } -+ tty_flip_buffer_push(tty); -+} -+ -+static inline void -+anakin_overrun_chars(struct uart_info *info) -+{ -+ unsigned int ch; -+ -+ ch = anakin_in(info->port, 0x14); -+ info->state->icount.overrun++; -+} -+ -+static inline void -+anakin_tx_chars(struct uart_info *info) -+{ -+ if (info->x_char) { -+ anakin_transmit_x_char(info); -+ return; -+ } -+ -+ if (info->xmit.head == info->xmit.tail -+ || info->tty->stopped -+ || info->tty->hw_stopped) { -+ anakin_stop_tx(info->port, 0); -+ return; -+ } -+ -+ anakin_transmit_buffer(info); -+ -+ if (CIRC_CNT(info->xmit.head, -+ info->xmit.tail, -+ UART_XMIT_SIZE) < WAKEUP_CHARS) -+ uart_event(info, EVT_WRITE_WAKEUP); -+} -+ -+static void -+anakin_int(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ unsigned int status; -+ struct uart_info *info = dev_id; -+ -+ status = anakin_in(info->port, 0x1c); -+ -+ if (status & RX) -+ anakin_rx_chars(info); -+ -+ if (status & OVERRUN) -+ anakin_overrun_chars(info); -+ -+ if (txenable[info->port->irq] && (status & TX)) -+ anakin_tx_chars(info); -+} -+ -+static u_int -+anakin_tx_empty(struct uart_port *port) -+{ -+ return anakin_in(port, 0x10) & TXEMPTY ? TIOCSER_TEMT : 0; -+} -+ -+static u_int -+anakin_get_mctrl(struct uart_port *port) -+{ -+ unsigned int status = 0; -+ -+ status |= (anakin_in(port, 0x10) & CTS ? TIOCM_CTS : 0); -+ status |= (anakin_in(port, 0x18) & DCD ? TIOCM_CAR : 0); -+ status |= (anakin_in(port, 0x18) & DTR ? TIOCM_DTR : 0); -+ status |= (anakin_in(port, 0x18) & RTS ? TIOCM_RTS : 0); -+ -+ return status; -+} -+ -+static void -+anakin_set_mctrl(struct uart_port *port, u_int mctrl) -+{ -+ unsigned int status; -+ -+ status = anakin_in(port, 0x18); -+ -+ if (mctrl & TIOCM_RTS) -+ status |= RTS; -+ else -+ status &= ~RTS; -+ -+ if (mctrl & TIOCM_CAR) -+ status |= DCD; -+ else -+ status &= ~DCD; -+ -+ anakin_out(port, 0x18, status); -+} -+ -+static void -+anakin_break_ctl(struct uart_port *port, int break_state) -+{ -+ unsigned int status; -+ -+ status = anakin_in(port, 0x20); -+ -+ if (break_state == -1) -+ status |= SETBREAK; -+ else -+ status &= ~SETBREAK; -+ -+ anakin_out(port, 0x20, status); -+} -+ -+static int -+anakin_startup(struct uart_port *port, struct uart_info *info) -+{ -+ int retval; -+ unsigned int read,write; -+ -+ /* -+ * Allocate the IRQ -+ */ -+ retval = request_irq(port->irq, anakin_int, SA_INTERRUPT, "serial_anakin", info); -+ if (retval) -+ return retval; -+ -+ port->ops->set_mctrl(port, info->mctrl); -+ -+ /* -+ * initialise the old status of the modem signals -+ */ -+ port->old_status = 0; -+ -+ /* -+ * Finally, disable IRQ and softIRQs for first byte) -+ */ -+ txenable[port->irq] = 0; -+ read = anakin_in(port, 0x18); -+ write = (read & ~(RTS | DTR | BLOCKRX)) | IRQENABLE; -+ anakin_out(port, 0x18, write); -+ -+ /* Store the uart_info pointer so we can reference it in -+ * anakin_start_tx() */ -+ port->unused = (u_int)info; -+ -+ return 0; -+} -+ -+static void -+anakin_shutdown(struct uart_port *port, struct uart_info *info) -+{ -+ /* -+ * Free the interrupt -+ */ -+ free_irq(port->irq, info); -+ -+ /* -+ * disable all interrupts, disable the port -+ */ -+ anakin_out(port, 0x18, anakin_in(port, 0x18) & ~IRQENABLE); -+} -+ -+static void -+anakin_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot) -+{ -+ unsigned int flags; -+ -+ save_flags_cli(flags); -+ while (!(anakin_in(port, 0x10) & TXEMPTY)); -+ anakin_out(port, 0x10, (anakin_in(port, 0x10) & ~PRESCALER) -+ | (quot << 3)); -+ -+ //parity always set to none -+ anakin_out(port, 0x18, anakin_in(port, 0x18) & ~PARITY); -+ restore_flags(flags); -+} -+ -+static const char *anakin_type(struct port *port) -+{ -+ return port->type == PORT_ANAKIN ? "ANAKIN" : NULL; -+} -+ -+static struct uart_ops anakin_pops = { -+ tx_empty: anakin_tx_empty, -+ set_mctrl: anakin_set_mctrl, -+ get_mctrl: anakin_get_mctrl, -+ stop_tx: anakin_stop_tx, -+ start_tx: anakin_start_tx, -+ stop_rx: anakin_stop_rx, -+ enable_ms: anakin_enable_ms, -+ break_ctl: anakin_break_ctl, -+ startup: anakin_startup, -+ shutdown: anakin_shutdown, -+ change_speed: anakin_change_speed, -+ type: anakin_type, -+}; -+ -+static struct uart_port anakin_ports[UART_NR] = { -+ { -+ base: IO_BASE + UART0, -+ irq: IRQ_UART0, -+ uartclk: 3686400, -+ fifosize: 0, -+ ops: &anakin_pops, -+ }, -+ { -+ base: IO_BASE + UART1, -+ irq: IRQ_UART1, -+ uartclk: 3686400, -+ fifosize: 0, -+ ops: &anakin_pops, -+ }, -+ { -+ base: IO_BASE + UART2, -+ irq: IRQ_UART2, -+ uartclk: 3686400, -+ fifosize: 0, -+ ops: &anakin_pops, -+ }, -+ { -+ base: IO_BASE + UART3, -+ irq: IRQ_UART3, -+ uartclk: 3686400, -+ fifosize: 0, -+ ops: &anakin_pops, -+ }, -+ { -+ base: IO_BASE + UART4, -+ irq: IRQ_UART4, -+ uartclk: 3686400, -+ fifosize: 0, -+ ops: &anakin_pops, -+ }, -+}; -+ -+ -+#ifdef CONFIG_SERIAL_ANAKIN_CONSOLE -+ -+static void -+anakin_console_write(struct console *co, const char *s, u_int count) -+{ -+ struct uart_port *port = anakin_ports + co->index; -+ unsigned int flags, status, i; -+ -+ /* -+ * First save the status then disable the interrupts -+ */ -+ save_flags_cli(flags); -+ status = anakin_in(port, 0x18); -+ anakin_out(port, 0x18, status & ~IRQENABLE); -+ restore_flags(flags); -+ -+ /* -+ * Now, do each character -+ */ -+ for (i = 0; i < count; i++, s++) { -+ while (!(anakin_in(port, 0x10) & TXEMPTY)); -+ -+ /* -+ * Send the character out. -+ * If a LF, also do CR... -+ */ -+ anakin_out(port, 0x14, *s); -+ anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST); -+ -+ if (*s == 10) { -+ while (!(anakin_in(port, 0x10) & TXEMPTY)); -+ anakin_out(port, 0x14, 13); -+ anakin_out(port, 0x18, anakin_in(port, 0x18) -+ | SENDREQUEST); -+ } -+ } -+ -+ /* -+ * Finally, wait for transmitter to become empty -+ * and restore the interrupts -+ */ -+ while (!(anakin_in(port, 0x10) & TXEMPTY)); -+ -+ if (status & IRQENABLE) -+ save_flags_cli(flags); -+ anakin_out(port, 0x18, anakin_in(port, 0x18) | IRQENABLE); -+ restore_flags(flags); -+} -+ -+static kdev_t -+anakin_console_device(struct console *co) -+{ -+ return MKDEV(SERIAL_ANAKIN_MAJOR, SERIAL_ANAKIN_MINOR + co->index); -+} -+ -+/* -+ * Read the current UART setup. -+ */ -+static void __init -+anakin_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) -+{ -+ int paritycode; -+ -+ *baud = GETBAUD (anakin_in(port, 0x10) & PRESCALER); -+ paritycode = GETPARITY(anakin_in(port, 0x18) & PARITY); -+ switch (paritycode) { -+ case NONEPARITY: *parity = 'n'; break; -+ case ODDPARITY: *parity = 'o'; break; -+ case EVENPARITY: *parity = 'e'; break; -+ } -+ *bits = 8; -+} -+ -+static int __init -+anakin_console_setup(struct console *co, char *options) -+{ -+ struct uart_port *port; -+ int baud = CONFIG_ANAKIN_DEFAULT_BAUDRATE; -+ int bits = 8; -+ int parity = 'n'; -+ -+ /* -+ * Check whether an invalid uart number has been specified, and -+ * if so, search for the first available port that does have -+ * console support. -+ */ -+ port = uart_get_console(anakin_ports, UART_NR, co); -+ -+ if (options) -+ uart_parse_options(options, &baud, &parity, &bits); -+ else -+ anakin_console_get_options(port, &baud, &parity, &bits); -+ -+ return uart_set_options(port, co, baud, parity, bits); -+} -+ -+static struct console anakin_console = { -+ name: SERIAL_ANAKIN_NAME, -+ write: anakin_console_write, -+ device: anakin_console_device, -+ setup: anakin_console_setup, -+ flags: CON_PRINTBUFFER, -+ index: -1, -+}; -+ -+void __init -+anakin_console_init(void) -+{ -+ register_console(&anakin_console); -+} -+ -+#define ANAKIN_CONSOLE &anakin_console -+#else -+#define ANAKIN_CONSOLE NULL -+#endif -+ -+static struct uart_register anakin_reg = { -+ normal_major: SERIAL_ANAKIN_MAJOR, -+ normal_name: SERIAL_ANAKIN_NAME, -+ normal_driver: &normal, -+ callout_major: CALLOUT_ANAKIN_MAJOR, -+ callout_name: CALLOUT_ANAKIN_NAME, -+ callout_driver: &callout, -+ table: anakin_table, -+ termios: anakin_termios, -+ termios_locked: anakin_termios_locked, -+ minor: SERIAL_ANAKIN_MINOR, -+ nr: UART_NR, -+ state: anakin_state, -+ port: anakin_ports, -+ cons: ANAKIN_CONSOLE, -+}; -+ -+static int __init -+anakin_init(void) -+{ -+ return uart_register_port(&anakin_reg); -+} -+ -+__initcall(anakin_init); -+ -+MODULE_DESCRIPTION("Anakin serial driver"); -+MODULE_AUTHOR("Tak-Shing Chan "); -+MODULE_SUPPORTED_DEVICE("ttyAN"); -+MODULE_LICENSE("GPL"); -+ -+EXPORT_NO_SYMBOLS; -diff -urN linux-2.4.26/drivers/serial/clps711x.c linux-2.4.26-vrs1/drivers/serial/clps711x.c ---- linux-2.4.26/drivers/serial/clps711x.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/serial/clps711x.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,635 @@ -+/* -+ * linux/drivers/char/serial_clps711x.c -+ * -+ * Driver for CLPS711x serial ports -+ * -+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. -+ * -+ * Copyright 1999 ARM Limited -+ * Copyright (C) 2000 Deep Blue Solutions Ltd. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * $Id: clps711x.c,v 1.12.2.2 2002/10/24 09:53:25 rmk Exp $ -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include -+ -+#define UART_NR 2 -+ -+#define SERIAL_CLPS711X_NAME "ttyAM" -+#define SERIAL_CLPS711X_MAJOR 204 -+#define SERIAL_CLPS711X_MINOR 16 -+#define SERIAL_CLPS711X_NR UART_NR -+ -+#define CALLOUT_CLPS711X_NAME "cuaam" -+#define CALLOUT_CLPS711X_MAJOR 205 -+#define CALLOUT_CLPS711X_MINOR 16 -+#define CALLOUT_CLPS711X_NR UART_NR -+ -+static struct tty_driver normal, callout; -+static struct tty_struct *clps711x_table[UART_NR]; -+static struct termios *clps711x_termios[UART_NR], *clps711x_termios_locked[UART_NR]; -+ -+/* -+ * We use the relevant SYSCON register as a base address for these ports. -+ */ -+#define UBRLCR(port) ((port)->iobase + UBRLCR1 - SYSCON1) -+#define UARTDR(port) ((port)->iobase + UARTDR1 - SYSCON1) -+#define SYSFLG(port) ((port)->iobase + SYSFLG1 - SYSCON1) -+#define SYSCON(port) ((port)->iobase + SYSCON1 - SYSCON1) -+ -+#define TX_IRQ(port) ((port)->irq) -+#define RX_IRQ(port) ((port)->irq + 1) -+ -+#define UART_ANY_ERR (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR) -+ -+#define tx_enabled(port) ((port)->unused[0]) -+ -+static void -+clps711xuart_stop_tx(struct uart_port *port, unsigned int tty_stop) -+{ -+ if (tx_enabled(port)) { -+ disable_irq(TX_IRQ(port)); -+ tx_enabled(port) = 0; -+ } -+} -+ -+static void -+clps711xuart_start_tx(struct uart_port *port, unsigned int tty_start) -+{ -+ if (!tx_enabled(port)) { -+ enable_irq(TX_IRQ(port)); -+ tx_enabled(port) = 1; -+ } -+} -+ -+static void clps711xuart_stop_rx(struct uart_port *port) -+{ -+ disable_irq(RX_IRQ(port)); -+} -+ -+static void clps711xuart_enable_ms(struct uart_port *port) -+{ -+} -+ -+static void clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ struct uart_port *port = dev_id; -+ struct tty_struct *tty = port->info->tty; -+ unsigned int status, ch, flg, ignored = 0; -+ -+ status = clps_readl(SYSFLG(port)); -+ while (!(status & SYSFLG_URXFE)) { -+ ch = clps_readl(UARTDR(port)); -+ -+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) -+ goto ignore_char; -+ port->icount.rx++; -+ -+ flg = TTY_NORMAL; -+ -+ /* -+ * Note that the error handling code is -+ * out of the main execution path -+ */ -+ if (ch & UART_ANY_ERR) -+ goto handle_error; -+ -+ if (uart_handle_sysrq_char(port, ch, regs)) -+ goto ignore_char; -+ -+ error_return: -+ *tty->flip.flag_buf_ptr++ = flg; -+ *tty->flip.char_buf_ptr++ = ch; -+ tty->flip.count++; -+ ignore_char: -+ status = clps_readl(SYSFLG(port)); -+ } -+ out: -+ tty_flip_buffer_push(tty); -+ return; -+ -+ handle_error: -+ if (ch & UARTDR_PARERR) -+ port->icount.parity++; -+ else if (ch & UARTDR_FRMERR) -+ port->icount.frame++; -+ if (ch & UARTDR_OVERR) -+ port->icount.overrun++; -+ -+ if (ch & port->ignore_status_mask) { -+ if (++ignored > 100) -+ goto out; -+ goto ignore_char; -+ } -+ ch &= port->read_status_mask; -+ -+ if (ch & UARTDR_PARERR) -+ flg = TTY_PARITY; -+ else if (ch & UARTDR_FRMERR) -+ flg = TTY_FRAME; -+ -+ if (ch & UARTDR_OVERR) { -+ /* -+ * CHECK: does overrun affect the current character? -+ * ASSUMPTION: it does not. -+ */ -+ *tty->flip.flag_buf_ptr++ = flg; -+ *tty->flip.char_buf_ptr++ = ch; -+ tty->flip.count++; -+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) -+ goto ignore_char; -+ ch = 0; -+ flg = TTY_OVERRUN; -+ } -+#ifdef SUPPORT_SYSRQ -+ port->sysrq = 0; -+#endif -+ goto error_return; -+} -+ -+static void clps711xuart_int_tx(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ struct uart_port *port = dev_id; -+ struct circ_buf *xmit = &port->info->xmit; -+ int count; -+ -+ if (port->x_char) { -+ clps_writel(port->x_char, UARTDR(port)); -+ port->icount.tx++; -+ port->x_char = 0; -+ return; -+ } -+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { -+ clps711xuart_stop_tx(port, 0); -+ return; -+ } -+ -+ count = port->fifosize >> 1; -+ do { -+ clps_writel(xmit->buf[xmit->tail], UARTDR(port)); -+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); -+ port->icount.tx++; -+ if (uart_circ_empty(xmit)) -+ break; -+ } while (--count > 0); -+ -+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) -+ uart_write_wakeup(port); -+ -+ if (uart_circ_empty(xmit)) -+ clps711xuart_stop_tx(port, 0); -+} -+ -+static unsigned int clps711xuart_tx_empty(struct uart_port *port) -+{ -+ unsigned int status = clps_readl(SYSFLG(port)); -+ return status & SYSFLG_UBUSY ? 0 : TIOCSER_TEMT; -+} -+ -+static unsigned int clps711xuart_get_mctrl(struct uart_port *port) -+{ -+ unsigned int port_addr; -+ unsigned int result = 0; -+ unsigned int status; -+ -+ port_addr = SYSFLG(port); -+ if (port_addr == SYSFLG1) { -+ status = clps_readl(SYSFLG1); -+ if (status & SYSFLG1_DCD) -+ result |= TIOCM_CAR; -+ if (status & SYSFLG1_DSR) -+ result |= TIOCM_DSR; -+ if (status & SYSFLG1_CTS) -+ result |= TIOCM_CTS; -+ } -+ -+ return result; -+} -+ -+static void -+clps711xuart_set_mctrl_null(struct uart_port *port, unsigned int mctrl) -+{ -+} -+ -+static void clps711xuart_break_ctl(struct uart_port *port, int break_state) -+{ -+ unsigned long flags; -+ unsigned int ubrlcr; -+ -+ spin_lock_irqsave(&port->lock, flags); -+ ubrlcr = clps_readl(UBRLCR(port)); -+ if (break_state == -1) -+ ubrlcr |= UBRLCR_BREAK; -+ else -+ ubrlcr &= ~UBRLCR_BREAK; -+ clps_writel(ubrlcr, UBRLCR(port)); -+ spin_unlock_irqrestore(&port->lock, flags); -+} -+ -+static int clps711xuart_startup(struct uart_port *port) -+{ -+ unsigned int syscon; -+ int retval; -+ -+ tx_enabled(port) = 1; -+ -+ /* -+ * Allocate the IRQs -+ */ -+ retval = request_irq(TX_IRQ(port), clps711xuart_int_tx, 0, -+ "clps711xuart_tx", port); -+ if (retval) -+ return retval; -+ -+ retval = request_irq(RX_IRQ(port), clps711xuart_int_rx, 0, -+ "clps711xuart_rx", port); -+ if (retval) { -+ free_irq(TX_IRQ(port), port); -+ return retval; -+ } -+ -+ /* -+ * enable the port -+ */ -+ syscon = clps_readl(SYSCON(port)); -+ syscon |= SYSCON_UARTEN; -+ clps_writel(syscon, SYSCON(port)); -+ -+ return 0; -+} -+ -+static void clps711xuart_shutdown(struct uart_port *port) -+{ -+ unsigned int ubrlcr, syscon; -+ -+ /* -+ * Free the interrupt -+ */ -+ free_irq(TX_IRQ(port), port); /* TX interrupt */ -+ free_irq(RX_IRQ(port), port); /* RX interrupt */ -+ -+ /* -+ * disable the port -+ */ -+ syscon = clps_readl(SYSCON(port)); -+ syscon &= ~SYSCON_UARTEN; -+ clps_writel(syscon, SYSCON(port)); -+ -+ /* -+ * disable break condition and fifos -+ */ -+ ubrlcr = clps_readl(UBRLCR(port)); -+ ubrlcr &= ~(UBRLCR_FIFOEN | UBRLCR_BREAK); -+ clps_writel(ubrlcr, UBRLCR(port)); -+} -+ -+static void clps711xuart_change_speed(struct uart_port *port, unsigned int cflag, unsigned int iflag, unsigned int quot) -+{ -+ unsigned int ubrlcr; -+ unsigned long flags; -+ -+#if DEBUG -+ printk("clps711xuart_change_speed(cflag=0x%x, iflag=0x%x, quot=%d) called\n", -+ cflag, iflag, quot); -+#endif -+ /* byte size and parity */ -+ switch (cflag & CSIZE) { -+ case CS5: -+ ubrlcr = UBRLCR_WRDLEN5; -+ break; -+ case CS6: -+ ubrlcr = UBRLCR_WRDLEN6; -+ break; -+ case CS7: -+ ubrlcr = UBRLCR_WRDLEN7; -+ break; -+ default: // CS8 -+ ubrlcr = UBRLCR_WRDLEN8; -+ break; -+ } -+ if (cflag & CSTOPB) -+ ubrlcr |= UBRLCR_XSTOP; -+ if (cflag & PARENB) { -+ ubrlcr |= UBRLCR_PRTEN; -+ if (!(cflag & PARODD)) -+ ubrlcr |= UBRLCR_EVENPRT; -+ } -+ if (port->fifosize > 1) -+ ubrlcr |= UBRLCR_FIFOEN; -+ -+ spin_lock_irqsave(&port->lock, flags); -+ -+ port->read_status_mask = UARTDR_OVERR; -+ if (iflag & INPCK) -+ port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR; -+ -+ /* -+ * Characters to ignore -+ */ -+ port->ignore_status_mask = 0; -+ if (iflag & IGNPAR) -+ port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR; -+ if (iflag & IGNBRK) { -+ /* -+ * If we're ignoring parity and break indicators, -+ * ignore overruns to (for real raw support). -+ */ -+ if (iflag & IGNPAR) -+ port->ignore_status_mask |= UARTDR_OVERR; -+ } -+ -+ quot -= 1; -+ -+ clps_writel(ubrlcr | quot, UBRLCR(port)); -+ -+ spin_unlock_irqrestore(&port->lock, flags); -+} -+ -+static const char *clps711xuart_type(struct uart_port *port) -+{ -+ return port->type == PORT_CLPS711X ? "CLPS711x" : NULL; -+} -+ -+/* -+ * Configure/autoconfigure the port. -+ */ -+static void clps711xuart_config_port(struct uart_port *port, int flags) -+{ -+ if (flags & UART_CONFIG_TYPE) -+ port->type = PORT_CLPS711X; -+} -+ -+static void clps711xuart_release_port(struct uart_port *port) -+{ -+} -+ -+static int clps711xuart_request_port(struct uart_port *port) -+{ -+ return 0; -+} -+ -+static struct uart_ops clps711x_pops = { -+ .tx_empty = clps711xuart_tx_empty, -+ .set_mctrl = clps711xuart_set_mctrl_null, -+ .get_mctrl = clps711xuart_get_mctrl, -+ .stop_tx = clps711xuart_stop_tx, -+ .start_tx = clps711xuart_start_tx, -+ .stop_rx = clps711xuart_stop_rx, -+ .enable_ms = clps711xuart_enable_ms, -+ .break_ctl = clps711xuart_break_ctl, -+ .startup = clps711xuart_startup, -+ .shutdown = clps711xuart_shutdown, -+ .change_speed = clps711xuart_change_speed, -+ .type = clps711xuart_type, -+ .config_port = clps711xuart_config_port, -+ .release_port = clps711xuart_release_port, -+ .request_port = clps711xuart_request_port, -+}; -+ -+static struct uart_port clps711x_ports[UART_NR] = { -+ { -+ .iobase = SYSCON1, -+ .irq = IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */ -+ .uartclk = 3686400, -+ .fifosize = 16, -+ .ops = &clps711x_pops, -+ .line = 0, -+ .flags = ASYNC_BOOT_AUTOCONF, -+ }, -+ { -+ .iobase = SYSCON2, -+ .irq = IRQ_UTXINT2, /* IRQ_URXINT2 */ -+ .uartclk = 3686400, -+ .fifosize = 16, -+ .ops = &clps711x_pops, -+ .line = 1, -+ .flags = ASYNC_BOOT_AUTOCONF, -+ } -+}; -+ -+#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE -+/* -+ * Print a string to the serial port trying not to disturb -+ * any possible real use of the port... -+ * -+ * The console_lock must be held when we get here. -+ * -+ * Note that this is called with interrupts already disabled -+ */ -+static void -+clps711xuart_console_write(struct console *co, const char *s, -+ unsigned int count) -+{ -+ struct uart_port *port = clps711x_ports + co->index; -+ unsigned int status, syscon; -+ int i; -+ -+ /* -+ * Ensure that the port is enabled. -+ */ -+ syscon = clps_readl(SYSCON(port)); -+ clps_writel(syscon | SYSCON_UARTEN, SYSCON(port)); -+ -+ /* -+ * Now, do each character -+ */ -+ for (i = 0; i < count; i++) { -+ do { -+ status = clps_readl(SYSFLG(port)); -+ } while (status & SYSFLG_UTXFF); -+ clps_writel(s[i], UARTDR(port)); -+ if (s[i] == '\n') { -+ do { -+ status = clps_readl(SYSFLG(port)); -+ } while (status & SYSFLG_UTXFF); -+ clps_writel('\r', UARTDR(port)); -+ } -+ } -+ -+ /* -+ * Finally, wait for transmitter to become empty -+ * and restore the uart state. -+ */ -+ do { -+ status = clps_readl(SYSFLG(port)); -+ } while (status & SYSFLG_UBUSY); -+ -+ clps_writel(syscon, SYSCON(port)); -+} -+ -+static kdev_t clps711xuart_console_device(struct console *co) -+{ -+ return MKDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR + co->index); -+} -+ -+static void __init -+clps711xuart_console_get_options(struct uart_port *port, int *baud, -+ int *parity, int *bits) -+{ -+ if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) { -+ unsigned int ubrlcr, quot; -+ -+ ubrlcr = clps_readl(UBRLCR(port)); -+ -+ *parity = 'n'; -+ if (ubrlcr & UBRLCR_PRTEN) { -+ if (ubrlcr & UBRLCR_EVENPRT) -+ *parity = 'e'; -+ else -+ *parity = 'o'; -+ } -+ -+ if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7) -+ *bits = 7; -+ else -+ *bits = 8; -+ -+ quot = ubrlcr & UBRLCR_BAUD_MASK; -+ *baud = port->uartclk / (16 * (quot + 1)); -+ } -+} -+ -+static int __init clps711xuart_console_setup(struct console *co, char *options) -+{ -+ struct uart_port *port; -+ int baud = 38400; -+ int bits = 8; -+ int parity = 'n'; -+ int flow = 'n'; -+ -+ /* -+ * Check whether an invalid uart number has been specified, and -+ * if so, search for the first available port that does have -+ * console support. -+ */ -+ port = uart_get_console(clps711x_ports, UART_NR, co); -+ -+ if (options) -+ uart_parse_options(options, &baud, &parity, &bits, &flow); -+ else -+ clps711xuart_console_get_options(port, &baud, &parity, &bits); -+ -+ return uart_set_options(port, co, baud, parity, bits, flow); -+} -+ -+static struct console clps711x_console = { -+ .name = SERIAL_CLPS711X_NAME, -+ .write = clps711xuart_console_write, -+ .device = clps711xuart_console_device, -+ .setup = clps711xuart_console_setup, -+ .flags = CON_PRINTBUFFER, -+ .index = -1, -+}; -+ -+void __init clps711xuart_console_init(void) -+{ -+ register_console(&clps711x_console); -+} -+ -+#define CLPS711X_CONSOLE &clps711x_console -+#else -+#define CLPS711X_CONSOLE NULL -+#endif -+ -+static struct uart_driver clps711x_reg = { -+#ifdef CONFIG_DEVFS_FS -+ .normal_name = SERIAL_CLPS711X_NAME, -+ .callout_name = CALLOUT_CLPS711X_NAME, -+#else -+ .normal_name = SERIAL_CLPS711X_NAME, -+ .callout_name = CALLOUT_CLPS711X_NAME, -+#endif -+ -+ .normal_major = SERIAL_CLPS711X_MAJOR, -+ .normal_driver = &normal, -+ .callout_major = CALLOUT_CLPS711X_MAJOR, -+ .callout_driver = &callout, -+ -+ .table = clps711x_table, -+ .termios = clps711x_termios, -+ .termios_locked = clps711x_termios_locked, -+ -+ .minor = SERIAL_CLPS711X_MINOR, -+ .nr = UART_NR, -+ -+ .cons = CLPS711X_CONSOLE, -+}; -+ -+static int __init clps711xuart_init(void) -+{ -+ int ret, i; -+ -+ printk(KERN_INFO "Serial: CLPS711x driver\n"); -+ -+ ret = uart_register_driver(&clps711x_reg); -+ if (ret) -+ return ret; -+ -+ for (i = 0; i < UART_NR; i++) -+ uart_add_one_port(&clps711x_reg, &clps711x_ports[i]); -+ -+ return 0; -+} -+ -+static void __exit clps711xuart_exit(void) -+{ -+ int i; -+ -+ for (i = 0; i < UART_NR; i++) -+ uart_remove_one_port(&clps711x_reg, &clps711x_ports[i]); -+ -+ uart_unregister_driver(&clps711x_reg); -+} -+ -+module_init(clps711xuart_init); -+module_exit(clps711xuart_exit); -+ -+EXPORT_NO_SYMBOLS; -+ -+MODULE_AUTHOR("Deep Blue Solutions Ltd"); -+MODULE_DESCRIPTION("CLPS-711x generic serial driver"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.4.26/drivers/serial/core.c linux-2.4.26-vrs1/drivers/serial/core.c ---- linux-2.4.26/drivers/serial/core.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/serial/core.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,2584 @@ -+/* -+ * linux/drivers/serial/core.c -+ * -+ * Driver core for serial ports -+ * -+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. -+ * -+ * Copyright 1999 ARM Limited -+ * Copyright (C) 2000-2001 Deep Blue Solutions Ltd. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * $Id: core.c,v 1.20.2.5 2002/03/13 15:22:26 rmk Exp $ -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#undef DEBUG -+#ifdef DEBUG -+#define DPRINTK(x...) printk(x) -+#else -+#define DPRINTK(x...) do { } while (0) -+#endif -+ -+#ifndef CONFIG_PM -+#define pm_access(pm) do { } while (0) -+#define pm_unregister(pm) do { } while (0) -+#endif -+ -+/* -+ * This is used to lock changes in serial line configuration. -+ */ -+static DECLARE_MUTEX(port_sem); -+ -+#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) -+ -+#define uart_users(state) ((state)->count + ((state)->info ? (state)->info->blocked_open : 0)) -+ -+#ifdef CONFIG_SERIAL_CORE_CONSOLE -+#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line) -+#else -+#define uart_console(port) (0) -+#endif -+ -+static void uart_change_speed(struct uart_state *state, struct termios *old_termios); -+static void uart_wait_until_sent(struct tty_struct *tty, int timeout); -+static void uart_change_pm(struct uart_state *state, int pm_state); -+ -+/* -+ * This routine is used by the interrupt handler to schedule processing in -+ * the software interrupt portion of the driver. -+ */ -+void uart_write_wakeup(struct uart_port *port) -+{ -+ struct uart_info *info = port->info; -+ tasklet_schedule(&info->tlet); -+} -+ -+static void uart_stop(struct tty_struct *tty) -+{ -+ struct uart_state *state = tty->driver_data; -+ struct uart_port *port = state->port; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&port->lock, flags); -+ port->ops->stop_tx(port, 1); -+ spin_unlock_irqrestore(&port->lock, flags); -+} -+ -+static void __uart_start(struct tty_struct *tty) -+{ -+ struct uart_state *state = tty->driver_data; -+ struct uart_port *port = state->port; -+ -+ if (!uart_circ_empty(&state->info->xmit) && state->info->xmit.buf && -+ !tty->stopped && !tty->hw_stopped) -+ port->ops->start_tx(port, 1); -+} -+ -+static void uart_start(struct tty_struct *tty) -+{ -+ struct uart_state *state = tty->driver_data; -+ struct uart_port *port = state->port; -+ unsigned long flags; -+ -+ pm_access(state->pm); -+ -+ spin_lock_irqsave(&port->lock, flags); -+ __uart_start(tty); -+ spin_unlock_irqrestore(&port->lock, flags); -+} -+ -+static void uart_tasklet_action(unsigned long data) -+{ -+ struct uart_state *state = (struct uart_state *)data; -+ struct tty_struct *tty; -+ -+ tty = state->info->tty; -+ if (tty) { -+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && -+ tty->ldisc.write_wakeup) -+ tty->ldisc.write_wakeup(tty); -+ wake_up_interruptible(&tty->write_wait); -+ } -+} -+ -+static inline void -+uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) -+{ -+ unsigned long flags; -+ unsigned int old; -+ -+ spin_lock_irqsave(&port->lock, flags); -+ old = port->mctrl; -+ port->mctrl = (old & ~clear) | set; -+ if (old != port->mctrl) -+ port->ops->set_mctrl(port, port->mctrl); -+ spin_unlock_irqrestore(&port->lock, flags); -+} -+ -+#define uart_set_mctrl(port,set) uart_update_mctrl(port,set,0) -+#define uart_clear_mctrl(port,clear) uart_update_mctrl(port,0,clear) -+ -+static inline unsigned int uart_get_altspeed(struct uart_port *port) -+{ -+ unsigned int flags = port->flags & UPF_SPD_MASK; -+ unsigned int altbaud = 0; -+ -+ if (flags == ASYNC_SPD_HI) -+ altbaud = 57600; -+ if (flags == ASYNC_SPD_VHI) -+ altbaud = 115200; -+ if (flags == ASYNC_SPD_SHI) -+ altbaud = 230400; -+ if (flags == ASYNC_SPD_WARP) -+ altbaud = 460800; -+ -+ return altbaud; -+} -+ -+/* -+ * Startup the port. This will be called once per open. All calls -+ * will be serialised by the per-port semaphore. -+ */ -+static int uart_startup(struct uart_state *state, int init_hw) -+{ -+ struct uart_info *info = state->info; -+ struct uart_port *port = state->port; -+ unsigned long page; -+ int retval = 0; -+ -+ if (info->flags & UIF_INITIALIZED) -+ return 0; -+ -+ /* -+ * Set the TTY IO error marker - we will only clear this -+ * once we have successfully opened the port. Also set -+ * up the tty->alt_speed kludge -+ */ -+ if (info->tty) -+ set_bit(TTY_IO_ERROR, &info->tty->flags); -+ -+ if (port->type == PORT_UNKNOWN) -+ return 0; -+ -+ /* -+ * Initialise and allocate the transmit and temporary -+ * buffer. -+ */ -+ if (!info->xmit.buf) { -+ page = get_zeroed_page(GFP_KERNEL); -+ if (!page) -+ return -ENOMEM; -+ -+ info->xmit.buf = (unsigned char *) page; -+ info->tmpbuf = info->xmit.buf + UART_XMIT_SIZE; -+ init_MUTEX(&info->tmpbuf_sem); -+ uart_circ_clear(&info->xmit); -+ } -+ -+ port->mctrl = 0; -+ -+ retval = port->ops->startup(port); -+ if (retval == 0) { -+ if (init_hw) { -+ /* -+ * Initialise the hardware port settings. -+ */ -+ uart_change_speed(state, NULL); -+ -+ /* -+ * Setup the RTS and DTR signals once the -+ * port is open and ready to respond. -+ */ -+ if (info->tty->termios->c_cflag & CBAUD) -+ uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); -+ } -+ -+ info->flags |= UIF_INITIALIZED; -+ -+ clear_bit(TTY_IO_ERROR, &info->tty->flags); -+ } -+ -+ if (retval && capable(CAP_SYS_ADMIN)) -+ retval = 0; -+ -+ return retval; -+} -+ -+/* -+ * This routine will shutdown a serial port; interrupts are disabled, and -+ * DTR is dropped if the hangup on close termio flag is on. Calls to -+ * uart_shutdown are serialised by the per-port semaphore. -+ */ -+static void uart_shutdown(struct uart_state *state) -+{ -+ struct uart_info *info = state->info; -+ struct uart_port *port = state->port; -+ -+ if (!(info->flags & UIF_INITIALIZED)) -+ return; -+ -+ /* -+ * Turn off DTR and RTS early. -+ */ -+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) -+ uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); -+ -+ /* -+ * clear delta_msr_wait queue to avoid mem leaks: we may free -+ * the irq here so the queue might never be woken up. Note -+ * that we won't end up waiting on delta_msr_wait again since -+ * any outstanding file descriptors should be pointing at -+ * hung_up_tty_fops now. -+ */ -+ wake_up_interruptible(&info->delta_msr_wait); -+ -+ /* -+ * Free the IRQ and disable the port. -+ */ -+ port->ops->shutdown(port); -+ -+ /* -+ * Free the transmit buffer page. -+ */ -+ if (info->xmit.buf) { -+ free_page((unsigned long)info->xmit.buf); -+ info->xmit.buf = NULL; -+ info->tmpbuf = NULL; -+ } -+ -+ /* -+ * kill off our tasklet -+ */ -+ tasklet_kill(&info->tlet); -+ if (info->tty) -+ set_bit(TTY_IO_ERROR, &info->tty->flags); -+ -+ info->flags &= ~UIF_INITIALIZED; -+} -+ -+/** -+ * uart_update_timeout - update per-port FIFO timeout. -+ * @port: uart_port structure describing the port. -+ * @cflag: termios cflag value -+ * @quot: uart clock divisor quotient -+ * -+ * Set the port FIFO timeout value. The @cflag value should -+ * reflect the actual hardware settings. -+ */ -+void -+uart_update_timeout(struct uart_port *port, unsigned int cflag, -+ unsigned int baud) -+{ -+ unsigned int bits; -+ -+ /* byte size and parity */ -+ switch (cflag & CSIZE) { -+ case CS5: -+ bits = 7; -+ break; -+ case CS6: -+ bits = 8; -+ break; -+ case CS7: -+ bits = 9; -+ break; -+ default: -+ bits = 10; -+ break; // CS8 -+ } -+ -+ if (cflag & CSTOPB) -+ bits++; -+ if (cflag & PARENB) -+ bits++; -+ -+ /* -+ * The total number of bits to be transmitted in the fifo. -+ */ -+ bits = bits * port->fifosize; -+ -+ /* -+ * Figure the timeout to send the above number of bits. -+ * Add .02 seconds of slop -+ */ -+ port->timeout = (HZ * bits) / baud + HZ/50; -+} -+ -+EXPORT_SYMBOL(uart_update_timeout); -+ -+static inline u_int uart_calculate_quot(struct uart_port *port, u_int baud) -+{ -+ u_int quot; -+ -+ /* Special case: B0 rate */ -+ if (!baud) -+ baud = 9600; -+ -+ /* Old HI/VHI/custom speed handling */ -+ if (baud == 38400 && -+ ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) -+ quot = port->custom_divisor; -+ else -+ quot = port->uartclk / (16 * baud); -+ -+ return quot; -+} -+ -+static void -+uart_change_speed(struct uart_state *state, struct termios *old_termios) -+{ -+ struct tty_struct *tty = state->info->tty; -+ struct uart_port *port = state->port; -+ struct termios *termios; -+ unsigned int quot, baud, cflag, try; -+ -+ /* -+ * If we have no tty, termios, or the port does not exist, -+ * then we can't set the parameters for this port. -+ */ -+ if (!tty || !tty->termios || port->type == PORT_UNKNOWN) -+ return; -+ -+ termios = tty->termios; -+ -+ cflag = termios->c_cflag; -+ -+ for (try = 0; try < 2; try ++) { -+ /* Determine divisor based on baud rate */ -+ baud = tty_get_baud_rate(tty); -+ quot = uart_calculate_quot(port, baud); -+ if (quot) -+ break; -+ -+ /* -+ * Oops, the quotient was zero. Try again with -+ * the old baud rate if possible. -+ */ -+ termios->c_cflag &= ~CBAUD; -+ if (old_termios) { -+ termios->c_cflag |= -+ (old_termios->c_cflag & CBAUD); -+ old_termios = NULL; -+ continue; -+ } -+ -+ /* -+ * As a last resort, if the quotient is zero, -+ * default to 9600 bps -+ */ -+ termios->c_cflag |= B9600; -+ } -+ -+ uart_update_timeout(port, cflag, port->uartclk / (16 * quot)); -+ -+ if (termios->c_cflag & CRTSCTS) -+ state->info->flags |= UIF_CTS_FLOW; -+ else -+ state->info->flags &= ~UIF_CTS_FLOW; -+ if (termios->c_cflag & CLOCAL) -+ state->info->flags &= ~UIF_CHECK_CD; -+ else -+ state->info->flags |= UIF_CHECK_CD; -+ -+ /* -+ * Set up parity check flag -+ */ -+ pm_access(state->pm); -+ -+ port->ops->change_speed(port, cflag, termios->c_iflag, quot); -+} -+ -+static inline void -+__uart_put_char(struct uart_port *port, struct circ_buf *circ, unsigned char c) -+{ -+ unsigned long flags; -+ -+ if (!circ->buf) -+ return; -+ -+ spin_lock_irqsave(&port->lock, flags); -+ if (uart_circ_chars_free(circ) != 0) { -+ circ->buf[circ->head] = c; -+ circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1); -+ } -+ spin_unlock_irqrestore(&port->lock, flags); -+} -+ -+static inline int -+__uart_user_write(struct uart_port *port, struct circ_buf *circ, -+ const unsigned char *buf, int count) -+{ -+ unsigned long flags; -+ int c, ret = 0; -+ -+ if (down_interruptible(&port->info->tmpbuf_sem)) -+ return -EINTR; -+ -+ while (1) { -+ int c1; -+ c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); -+ if (count < c) -+ c = count; -+ if (c <= 0) -+ break; -+ -+ c -= copy_from_user(port->info->tmpbuf, buf, c); -+ if (!c) { -+ if (!ret) -+ ret = -EFAULT; -+ break; -+ } -+ spin_lock_irqsave(&port->lock, flags); -+ c1 = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); -+ if (c1 < c) -+ c = c1; -+ memcpy(circ->buf + circ->head, port->info->tmpbuf, c); -+ circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); -+ spin_unlock_irqrestore(&port->lock, flags); -+ buf += c; -+ count -= c; -+ ret += c; -+ } -+ up(&port->info->tmpbuf_sem); -+ -+ return ret; -+} -+ -+static inline int -+__uart_kern_write(struct uart_port *port, struct circ_buf *circ, -+ const unsigned char *buf, int count) -+{ -+ unsigned long flags; -+ int c, ret = 0; -+ -+ spin_lock_irqsave(&port->lock, flags); -+ while (1) { -+ c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); -+ if (count < c) -+ c = count; -+ if (c <= 0) -+ break; -+ memcpy(circ->buf + circ->head, buf, c); -+ circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); -+ buf += c; -+ count -= c; -+ ret += c; -+ } -+ spin_unlock_irqrestore(&port->lock, flags); -+ -+ return ret; -+} -+ -+static void uart_put_char(struct tty_struct *tty, unsigned char ch) -+{ -+ struct uart_state *state = tty->driver_data; -+ -+ __uart_put_char(state->port, &state->info->xmit, ch); -+} -+ -+static void uart_flush_chars(struct tty_struct *tty) -+{ -+ uart_start(tty); -+} -+ -+static int -+uart_write(struct tty_struct *tty, int from_user, const unsigned char * buf, -+ int count) -+{ -+ struct uart_state *state = tty->driver_data; -+ int ret; -+ -+ if (!state->info->xmit.buf) -+ return 0; -+ -+ if (from_user) -+ ret = __uart_user_write(state->port, &state->info->xmit, buf, count); -+ else -+ ret = __uart_kern_write(state->port, &state->info->xmit, buf, count); -+ -+ uart_start(tty); -+ return ret; -+} -+ -+static int uart_write_room(struct tty_struct *tty) -+{ -+ struct uart_state *state = tty->driver_data; -+ -+ return uart_circ_chars_free(&state->info->xmit); -+} -+ -+static int uart_chars_in_buffer(struct tty_struct *tty) -+{ -+ struct uart_state *state = tty->driver_data; -+ -+ return uart_circ_chars_pending(&state->info->xmit); -+} -+ -+static void uart_flush_buffer(struct tty_struct *tty) -+{ -+ struct uart_state *state = tty->driver_data; -+ struct uart_port *port = state->port; -+ unsigned long flags; -+ -+ DPRINTK("uart_flush_buffer(%d) called\n", -+ MINOR(tty->device) - tty->driver.minor_start); -+ -+ spin_lock_irqsave(&port->lock, flags); -+ uart_circ_clear(&state->info->xmit); -+ spin_unlock_irqrestore(&port->lock, flags); -+ wake_up_interruptible(&tty->write_wait); -+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && -+ tty->ldisc.write_wakeup) -+ (tty->ldisc.write_wakeup)(tty); -+} -+ -+/* -+ * This function is used to send a high-priority XON/XOFF character to -+ * the device -+ */ -+static void uart_send_xchar(struct tty_struct *tty, char ch) -+{ -+ struct uart_state *state = tty->driver_data; -+ struct uart_port *port = state->port; -+ unsigned long flags; -+ -+ if (port->ops->send_xchar) -+ port->ops->send_xchar(port, ch); -+ else { -+ port->x_char = ch; -+ if (ch) { -+ spin_lock_irqsave(&port->lock, flags); -+ port->ops->start_tx(port, 0); -+ spin_unlock_irqrestore(&port->lock, flags); -+ } -+ } -+} -+ -+static void uart_throttle(struct tty_struct *tty) -+{ -+ struct uart_state *state = tty->driver_data; -+ -+ if (I_IXOFF(tty)) -+ uart_send_xchar(tty, STOP_CHAR(tty)); -+ -+ if (tty->termios->c_cflag & CRTSCTS) -+ uart_clear_mctrl(state->port, TIOCM_RTS); -+} -+ -+static void uart_unthrottle(struct tty_struct *tty) -+{ -+ struct uart_state *state = tty->driver_data; -+ struct uart_port *port = state->port; -+ -+ if (I_IXOFF(tty)) { -+ if (port->x_char) -+ port->x_char = 0; -+ else -+ uart_send_xchar(tty, START_CHAR(tty)); -+ } -+ -+ if (tty->termios->c_cflag & CRTSCTS) -+ uart_set_mctrl(port, TIOCM_RTS); -+} -+ -+static int uart_get_info(struct uart_state *state, struct serial_struct *retinfo) -+{ -+ struct uart_port *port = state->port; -+ struct serial_struct tmp; -+ -+ memset(&tmp, 0, sizeof(tmp)); -+ tmp.type = port->type; -+ tmp.line = port->line; -+ tmp.port = port->iobase; -+ if (HIGH_BITS_OFFSET) -+ tmp.port_high = (long) port->iobase >> HIGH_BITS_OFFSET; -+ tmp.irq = port->irq; -+ tmp.flags = port->flags; -+ tmp.xmit_fifo_size = port->fifosize; -+ tmp.baud_base = port->uartclk / 16; -+ tmp.close_delay = state->close_delay; -+ tmp.closing_wait = state->closing_wait; -+ tmp.custom_divisor = port->custom_divisor; -+ tmp.hub6 = port->hub6; -+ tmp.io_type = port->iotype; -+ tmp.iomem_reg_shift = port->regshift; -+ tmp.iomem_base = (void *)port->mapbase; -+ -+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) -+ return -EFAULT; -+ return 0; -+} -+ -+static int -+uart_set_info(struct uart_state *state, struct serial_struct *newinfo) -+{ -+ struct serial_struct new_serial; -+ struct uart_port *port = state->port; -+ unsigned long new_port; -+ unsigned int change_irq, change_port, old_flags; -+ unsigned int old_custom_divisor; -+ int retval = 0; -+ -+ if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) -+ return -EFAULT; -+ -+ new_port = new_serial.port; -+ if (HIGH_BITS_OFFSET) -+ new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; -+ -+ new_serial.irq = irq_cannonicalize(new_serial.irq); -+ -+ /* -+ * This semaphore protects state->count. It is also -+ * very useful to prevent opens. Also, take the -+ * port configuration semaphore to make sure that a -+ * module insertion/removal doesn't change anything -+ * under us. -+ */ -+ down(&state->sem); -+ -+ change_irq = new_serial.irq != port->irq; -+ -+ /* -+ * Since changing the 'type' of the port changes its resource -+ * allocations, we should treat type changes the same as -+ * IO port changes. -+ */ -+ change_port = new_port != port->iobase || -+ (unsigned long)new_serial.iomem_base != port->mapbase || -+ new_serial.hub6 != port->hub6 || -+ new_serial.io_type != port->iotype || -+ new_serial.iomem_reg_shift != port->regshift || -+ new_serial.type != port->type; -+ -+ old_flags = port->flags; -+ old_custom_divisor = port->custom_divisor; -+ -+ if (!capable(CAP_SYS_ADMIN)) { -+ retval = -EPERM; -+ if (change_irq || change_port || -+ (new_serial.baud_base != port->uartclk / 16) || -+ (new_serial.close_delay != state->close_delay) || -+ (new_serial.closing_wait != state->closing_wait) || -+ (new_serial.xmit_fifo_size != port->fifosize) || -+ (((new_serial.flags ^ old_flags) & ~UPF_USR_MASK) != 0)) -+ goto exit; -+ port->flags = ((port->flags & ~UPF_USR_MASK) | -+ (new_serial.flags & UPF_USR_MASK)); -+ port->custom_divisor = new_serial.custom_divisor; -+ goto check_and_exit; -+ } -+ -+ /* -+ * Ask the low level driver to verify the settings. -+ */ -+ if (port->ops->verify_port) -+ retval = port->ops->verify_port(port, &new_serial); -+ -+ if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) || -+ (new_serial.baud_base < 9600)) -+ retval = -EINVAL; -+ -+ if (retval) -+ goto exit; -+ -+ if (change_port || change_irq) { -+ retval = -EBUSY; -+ -+ /* -+ * Make sure that we are the sole user of this port. -+ */ -+ if (uart_users(state) > 1) -+ goto exit; -+ -+ /* -+ * We need to shutdown the serial port at the old -+ * port/type/irq combination. -+ */ -+ uart_shutdown(state); -+ } -+ -+ if (change_port) { -+ unsigned long old_iobase, old_mapbase; -+ unsigned int old_type, old_iotype, old_hub6, old_shift; -+ -+ old_iobase = port->iobase; -+ old_mapbase = port->mapbase; -+ old_type = port->type; -+ old_hub6 = port->hub6; -+ old_iotype = port->iotype; -+ old_shift = port->regshift; -+ -+ /* -+ * Free and release old regions -+ */ -+ if (old_type != PORT_UNKNOWN) -+ port->ops->release_port(port); -+ -+ port->iobase = new_port; -+ port->type = new_serial.type; -+ port->hub6 = new_serial.hub6; -+ port->iotype = new_serial.io_type; -+ port->regshift = new_serial.iomem_reg_shift; -+ port->mapbase = (unsigned long)new_serial.iomem_base; -+ -+ /* -+ * Claim and map the new regions -+ */ -+ if (port->type != PORT_UNKNOWN) { -+ retval = port->ops->request_port(port); -+ } else { -+ /* Always success - Jean II */ -+ retval = 0; -+ } -+ -+ /* -+ * If we fail to request resources for the -+ * new port, try to restore the old settings. -+ */ -+ if (retval && old_type != PORT_UNKNOWN) { -+ port->iobase = old_iobase; -+ port->type = old_type; -+ port->hub6 = old_hub6; -+ port->iotype = old_iotype; -+ port->regshift = old_shift; -+ port->mapbase = old_mapbase; -+ retval = port->ops->request_port(port); -+ /* -+ * If we failed to restore the old settings, -+ * we fail like this. -+ */ -+ if (retval) -+ port->type = PORT_UNKNOWN; -+ -+ /* -+ * We failed anyway. -+ */ -+ retval = -EBUSY; -+ } -+ } -+ -+ port->irq = new_serial.irq; -+ port->uartclk = new_serial.baud_base * 16; -+ port->flags = (port->flags & ~UPF_CHANGE_MASK) | -+ (new_serial.flags & UPF_CHANGE_MASK); -+ port->custom_divisor = new_serial.custom_divisor; -+ state->close_delay = new_serial.close_delay * HZ / 100; -+ state->closing_wait = new_serial.closing_wait * HZ / 100; -+ port->fifosize = new_serial.xmit_fifo_size; -+ if (state->info->tty) -+ state->info->tty->low_latency = -+ (port->flags & UPF_LOW_LATENCY) ? 1 : 0; -+ -+ check_and_exit: -+ retval = 0; -+ if (port->type == PORT_UNKNOWN) -+ goto exit; -+ if (state->info->flags & UIF_INITIALIZED) { -+ if (((old_flags ^ port->flags) & UPF_SPD_MASK) || -+ old_custom_divisor != port->custom_divisor) { -+ state->info->tty->alt_speed = uart_get_altspeed(port); -+ uart_change_speed(state, NULL); -+ } -+ } else -+ retval = uart_startup(state, 1); -+ exit: -+ up(&state->sem); -+ return retval; -+} -+ -+ -+/* -+ * uart_get_lsr_info - get line status register info. -+ * Note: uart_ioctl protects us against hangups. -+ */ -+static int uart_get_lsr_info(struct uart_state *state, unsigned int *value) -+{ -+ struct uart_port *port = state->port; -+ unsigned int result; -+ -+ result = port->ops->tx_empty(port); -+ -+ /* -+ * If we're about to load something into the transmit -+ * register, we'll pretend the transmitter isn't empty to -+ * avoid a race condition (depending on when the transmit -+ * interrupt happens). -+ */ -+ if (port->x_char || -+ ((uart_circ_chars_pending(&state->info->xmit) > 0) && -+ !state->info->tty->stopped && !state->info->tty->hw_stopped)) -+ result &= ~TIOCSER_TEMT; -+ -+ return put_user(result, value); -+} -+ -+static int uart_tiocmget(struct tty_struct *tty, struct file *file) -+{ -+ struct uart_state *state = tty->driver_data; -+ struct uart_port *port = state->port; -+ int result = -EIO; -+ -+ down(&state->sem); -+ if ((!file || !tty_hung_up_p(file)) && -+ !(tty->flags & (1 << TTY_IO_ERROR))) { -+ result = port->mctrl; -+ result |= port->ops->get_mctrl(port); -+ } -+ up(&state->sem); -+ -+ return result; -+} -+ -+static int -+uart_tiocmset(struct tty_struct *tty, struct file *file, -+ unsigned int set, unsigned int clear) -+{ -+ struct uart_state *state = tty->driver_data; -+ struct uart_port *port = state->port; -+ int ret = -EIO; -+ -+ down(&state->sem); -+ if ((!file || !tty_hung_up_p(file)) && -+ !(tty->flags & (1 << TTY_IO_ERROR))) { -+ uart_update_mctrl(port, set, clear); -+ ret = 0; -+ } -+ up(&state->sem); -+ return ret; -+} -+ -+static void uart_break_ctl(struct tty_struct *tty, int break_state) -+{ -+ struct uart_state *state = tty->driver_data; -+ struct uart_port *port = state->port; -+ -+ BUG_ON(!kernel_locked()); -+ -+ down(&state->sem); -+ -+ if (port->type != PORT_UNKNOWN) -+ port->ops->break_ctl(port, break_state); -+ -+ up(&state->sem); -+} -+ -+static int uart_do_autoconfig(struct uart_state *state) -+{ -+ struct uart_port *port = state->port; -+ int flags, ret; -+ -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EPERM; -+ -+ /* -+ * Take the per-port semaphore. This prevents count from -+ * changing, and hence any extra opens of the port while -+ * we're auto-configuring. -+ */ -+ if (down_interruptible(&state->sem)) -+ return -ERESTARTSYS; -+ -+ ret = -EBUSY; -+ if (uart_users(state) == 1) { -+ uart_shutdown(state); -+ -+ /* -+ * If we already have a port type configured, -+ * we must release its resources. -+ */ -+ if (port->type != PORT_UNKNOWN) -+ port->ops->release_port(port); -+ -+ flags = UART_CONFIG_TYPE; -+ if (port->flags & UPF_AUTO_IRQ) -+ flags |= UART_CONFIG_IRQ; -+ -+ /* -+ * This will claim the ports resources if -+ * a port is found. -+ */ -+ port->ops->config_port(port, flags); -+ -+ ret = uart_startup(state, 1); -+ } -+ up(&state->sem); -+ return ret; -+} -+ -+/* -+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change -+ * - mask passed in arg for lines of interest -+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) -+ * Caller should use TIOCGICOUNT to see which one it was -+ */ -+static int -+uart_wait_modem_status(struct uart_state *state, unsigned long arg) -+{ -+ struct uart_port *port = state->port; -+ DECLARE_WAITQUEUE(wait, current); -+ struct uart_icount cprev, cnow; -+ int ret; -+ -+ /* -+ * note the counters on entry -+ */ -+ spin_lock_irq(&port->lock); -+ memcpy(&cprev, &port->icount, sizeof(struct uart_icount)); -+ -+ /* -+ * Force modem status interrupts on -+ */ -+ port->ops->enable_ms(port); -+ spin_unlock_irq(&port->lock); -+ -+ add_wait_queue(&state->info->delta_msr_wait, &wait); -+ for (;;) { -+ spin_lock_irq(&port->lock); -+ memcpy(&cnow, &port->icount, sizeof(struct uart_icount)); -+ spin_unlock_irq(&port->lock); -+ -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || -+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || -+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || -+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { -+ ret = 0; -+ break; -+ } -+ -+ schedule(); -+ -+ /* see if a signal did it */ -+ if (signal_pending(current)) { -+ ret = -ERESTARTSYS; -+ break; -+ } -+ -+ cprev = cnow; -+ } -+ -+ current->state = TASK_RUNNING; -+ remove_wait_queue(&state->info->delta_msr_wait, &wait); -+ -+ return ret; -+} -+ -+/* -+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) -+ * Return: write counters to the user passed counter struct -+ * NB: both 1->0 and 0->1 transitions are counted except for -+ * RI where only 0->1 is counted. -+ */ -+static int -+uart_get_count(struct uart_state *state, struct serial_icounter_struct *icnt) -+{ -+ struct serial_icounter_struct icount; -+ struct uart_icount cnow; -+ struct uart_port *port = state->port; -+ -+ spin_lock_irq(&port->lock); -+ memcpy(&cnow, &port->icount, sizeof(struct uart_icount)); -+ spin_unlock_irq(&port->lock); -+ -+ icount.cts = cnow.cts; -+ icount.dsr = cnow.dsr; -+ icount.rng = cnow.rng; -+ icount.dcd = cnow.dcd; -+ icount.rx = cnow.rx; -+ icount.tx = cnow.tx; -+ icount.frame = cnow.frame; -+ icount.overrun = cnow.overrun; -+ icount.parity = cnow.parity; -+ icount.brk = cnow.brk; -+ icount.buf_overrun = cnow.buf_overrun; -+ -+ return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0; -+} -+ -+/* -+ * Called via sys_ioctl under the BKL. We can use spin_lock_irq() here. -+ */ -+static int -+uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, -+ unsigned long arg) -+{ -+ struct uart_state *state = tty->driver_data; -+ int ret = -ENOIOCTLCMD; -+ -+ BUG_ON(!kernel_locked()); -+ -+ /* -+ * These ioctls don't rely on the hardware to be present. -+ */ -+ switch (cmd) { -+ case TIOCGSERIAL: -+ ret = uart_get_info(state, (struct serial_struct *)arg); -+ break; -+ -+ case TIOCSSERIAL: -+ ret = uart_set_info(state, (struct serial_struct *)arg); -+ break; -+ -+ case TIOCSERCONFIG: -+ ret = uart_do_autoconfig(state); -+ break; -+ -+ case TIOCSERGWILD: /* obsolete */ -+ case TIOCSERSWILD: /* obsolete */ -+ ret = 0; -+ break; -+ } -+ -+ if (ret != -ENOIOCTLCMD) -+ goto out; -+ -+ if (tty->flags & (1 << TTY_IO_ERROR)) { -+ ret = -EIO; -+ goto out; -+ } -+ -+ /* -+ * The following should only be used when hardware is present. -+ */ -+ switch (cmd) { -+ case TIOCMIWAIT: -+ ret = uart_wait_modem_status(state, arg); -+ break; -+ -+ case TIOCGICOUNT: -+ ret = uart_get_count(state, (struct serial_icounter_struct *)arg); -+ break; -+ -+ case TIOCMGET: -+ { -+ int val; -+ val = uart_tiocmget(tty, filp); -+ if (val >= 0) { -+ ret = put_user(val, (int *)arg); -+ } else { -+ ret = val; -+ } -+ } -+ break; -+ -+ case TIOCMBIS: -+ case TIOCMBIC: -+ case TIOCMSET: -+ { -+ int val, set = 0, clear = 0; -+ ret = get_user(val, (int *)arg); -+ if (ret) -+ break; -+ -+ switch (cmd) { -+ case TIOCMBIS: -+ set = val; -+ break; -+ case TIOCMBIC: -+ clear = val; -+ break; -+ case TIOCMSET: -+ set = val; -+ clear = ~val; -+ break; -+ } -+ -+ set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; -+ clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; -+ -+ ret = uart_tiocmset(tty, filp, set, clear); -+ } -+ break; -+ } -+ -+ if (ret != -ENOIOCTLCMD) -+ goto out; -+ -+ down(&state->sem); -+ -+ if (tty_hung_up_p(filp)) { -+ ret = -EIO; -+ goto out_up; -+ } -+ -+ /* -+ * All these rely on hardware being present and need to be -+ * protected against the tty being hung up. -+ */ -+ switch (cmd) { -+ case TIOCSERGETLSR: /* Get line status register */ -+ ret = uart_get_lsr_info(state, (unsigned int *)arg); -+ break; -+ -+ default: { -+ struct uart_port *port = state->port; -+ if (port->ops->ioctl) -+ ret = port->ops->ioctl(port, cmd, arg); -+ break; -+ } -+ } -+ out_up: -+ up(&state->sem); -+ out: -+ return ret; -+} -+ -+static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios) -+{ -+ struct uart_state *state = tty->driver_data; -+ unsigned long flags; -+ unsigned int cflag = tty->termios->c_cflag; -+ -+ BUG_ON(!kernel_locked()); -+ -+ /* -+ * These are the bits that are used to setup various -+ * flags in the low level driver. -+ */ -+#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) -+ -+ if ((cflag ^ old_termios->c_cflag) == 0 && -+ RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) -+ return; -+ -+ uart_change_speed(state, old_termios); -+ -+ /* Handle transition to B0 status */ -+ if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) -+ uart_clear_mctrl(state->port, TIOCM_RTS | TIOCM_DTR); -+ -+ /* Handle transition away from B0 status */ -+ if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { -+ unsigned int mask = TIOCM_DTR; -+ if (!(cflag & CRTSCTS) || -+ !test_bit(TTY_THROTTLED, &tty->flags)) -+ mask |= TIOCM_RTS; -+ uart_set_mctrl(state->port, mask); -+ } -+ -+ /* Handle turning off CRTSCTS */ -+ if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) { -+ spin_lock_irqsave(&state->port->lock, flags); -+ tty->hw_stopped = 0; -+ __uart_start(tty); -+ spin_unlock_irqrestore(&state->port->lock, flags); -+ } -+ -+#if 0 -+ /* -+ * No need to wake up processes in open wait, since they -+ * sample the CLOCAL flag once, and don't recheck it. -+ * XXX It's not clear whether the current behavior is correct -+ * or not. Hence, this may change..... -+ */ -+ if (!(old_termios->c_cflag & CLOCAL) && -+ (tty->termios->c_cflag & CLOCAL)) -+ wake_up_interruptible(&state->info->open_wait); -+#endif -+} -+ -+/* -+ * In 2.4.5, calls to this will be serialized via the BKL in -+ * linux/drivers/char/tty_io.c:tty_release() -+ * linux/drivers/char/tty_io.c:do_tty_handup() -+ */ -+static void uart_close(struct tty_struct *tty, struct file *filp) -+{ -+ struct uart_driver *drv = (struct uart_driver *)tty->driver.driver_state; -+ struct uart_state *state = tty->driver_data; -+ struct uart_port *port; -+ -+ BUG_ON(!kernel_locked()); -+ -+ if (!state || !state->port) -+ return; -+ -+ port = state->port; -+ -+ DPRINTK("uart_close(%d) called\n", port->line); -+ -+ down(&state->sem); -+ -+ if (tty_hung_up_p(filp)) -+ goto done; -+ -+ if ((tty->count == 1) && (state->count != 1)) { -+ /* -+ * Uh, oh. tty->count is 1, which means that the tty -+ * structure will be freed. state->count should always -+ * be one in these conditions. If it's greater than -+ * one, we've got real problems, since it means the -+ * serial port won't be shutdown. -+ */ -+ printk("uart_close: bad serial port count; tty->count is 1, " -+ "state->count is %d\n", state->count); -+ state->count = 1; -+ } -+ if (--state->count < 0) { -+ printk("rs_close: bad serial port count for %s%d: %d\n", -+ tty->driver.name, port->line, state->count); -+ state->count = 0; -+ } -+ if (state->count) -+ goto done; -+ -+ /* -+ * Save the termios structure, since this port may have -+ * separate termios for callout and dialin. -+ */ -+ if (state->info->flags & UIF_NORMAL_ACTIVE) -+ state->normal_termios = *tty->termios; -+ if (state->info->flags & UIF_CALLOUT_ACTIVE) -+ state->callout_termios = *tty->termios; -+ -+ /* -+ * Now we wait for the transmit buffer to clear; and we notify -+ * the line discipline to only process XON/XOFF characters by -+ * setting tty->closing. -+ */ -+ tty->closing = 1; -+ -+ if (state->closing_wait != USF_CLOSING_WAIT_NONE) -+ tty_wait_until_sent(tty, state->closing_wait); -+ -+ /* -+ * At this point, we stop accepting input. To do this, we -+ * disable the receive line status interrupts. -+ */ -+ if (state->info->flags & UIF_INITIALIZED) { -+ unsigned long flags; -+ spin_lock_irqsave(&port->lock, flags); -+ port->ops->stop_rx(port); -+ spin_unlock_irqrestore(&port->lock, flags); -+ /* -+ * Before we drop DTR, make sure the UART transmitter -+ * has completely drained; this is especially -+ * important if there is a transmit FIFO! -+ */ -+ uart_wait_until_sent(tty, port->timeout); -+ } -+ -+ uart_shutdown(state); -+ uart_flush_buffer(tty); -+ if (tty->ldisc.flush_buffer) -+ tty->ldisc.flush_buffer(tty); -+ tty->closing = 0; -+ state->info->tty = NULL; -+ -+ if (state->info->blocked_open) { -+ if (state->close_delay) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(state->close_delay); -+ set_current_state(TASK_RUNNING); -+ } -+ } else if (!uart_console(port)) { -+ uart_change_pm(state, 3); -+ } -+ -+ /* -+ * Wake up anyone trying to open this port. -+ */ -+ state->info->flags &= ~(UIF_NORMAL_ACTIVE|UIF_CALLOUT_ACTIVE); -+ wake_up_interruptible(&state->info->open_wait); -+ -+ done: -+ up(&state->sem); -+ if (drv->owner) -+ __MOD_DEC_USE_COUNT(drv->owner); -+} -+ -+static void uart_wait_until_sent(struct tty_struct *tty, int timeout) -+{ -+ struct uart_state *state = tty->driver_data; -+ struct uart_port *port = state->port; -+ unsigned long char_time, expire; -+ -+ BUG_ON(!kernel_locked()); -+ -+ if (port->type == PORT_UNKNOWN || port->fifosize == 0) -+ return; -+ -+ /* -+ * Set the check interval to be 1/5 of the estimated time to -+ * send a single character, and make it at least 1. The check -+ * interval should also be less than the timeout. -+ * -+ * Note: we have to use pretty tight timings here to satisfy -+ * the NIST-PCTS. -+ */ -+ char_time = (port->timeout - HZ/50) / port->fifosize; -+ char_time = char_time / 5; -+ if (char_time == 0) -+ char_time = 1; -+ if (timeout && timeout < char_time) -+ char_time = timeout; -+ -+ /* -+ * If the transmitter hasn't cleared in twice the approximate -+ * amount of time to send the entire FIFO, it probably won't -+ * ever clear. This assumes the UART isn't doing flow -+ * control, which is currently the case. Hence, if it ever -+ * takes longer than port->timeout, this is probably due to a -+ * UART bug of some kind. So, we clamp the timeout parameter at -+ * 2*port->timeout. -+ */ -+ if (timeout == 0 || timeout > 2 * port->timeout) -+ timeout = 2 * port->timeout; -+ -+ expire = jiffies + timeout; -+ -+ DPRINTK("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n", -+ port->line, jiffies, expire); -+ -+ /* -+ * Check whether the transmitter is empty every 'char_time'. -+ * 'timeout' / 'expire' give us the maximum amount of time -+ * we wait. -+ */ -+ while (!port->ops->tx_empty(port)) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ schedule_timeout(char_time); -+ if (signal_pending(current)) -+ break; -+ if (time_after(jiffies, expire)) -+ break; -+ } -+ set_current_state(TASK_RUNNING); /* might not be needed */ -+} -+ -+/* -+ * This is called with the BKL held in -+ * linux/drivers/char/tty_io.c:do_tty_hangup() -+ * We're called from the eventd thread, so we can sleep for -+ * a _short_ time only. -+ */ -+static void uart_hangup(struct tty_struct *tty) -+{ -+ struct uart_state *state = tty->driver_data; -+ -+ BUG_ON(!kernel_locked()); -+ DPRINTK("uart_hangup(%d)\n", state->port->line); -+ -+ down(&state->sem); -+ if (state->info && state->info->flags & (UIF_NORMAL_ACTIVE|UIF_CALLOUT_ACTIVE)) { -+ uart_flush_buffer(tty); -+ uart_shutdown(state); -+ state->count = 0; -+ state->info->flags &= ~(UIF_NORMAL_ACTIVE|UIF_CALLOUT_ACTIVE); -+ state->info->tty = NULL; -+ wake_up_interruptible(&state->info->open_wait); -+ wake_up_interruptible(&state->info->delta_msr_wait); -+ } -+ up(&state->sem); -+} -+ -+/* -+ * Copy across the serial console cflag setting into the termios settings -+ * for the initial open of the port. This allows continuity between the -+ * kernel settings, and the settings init adopts when it opens the port -+ * for the first time. -+ */ -+static void uart_update_termios(struct uart_state *state) -+{ -+ struct tty_struct *tty = state->info->tty; -+ struct uart_port *port = state->port; -+ -+ if (uart_console(port) && port->cons->cflag) { -+ tty->termios->c_cflag = port->cons->cflag; -+ port->cons->cflag = 0; -+ } -+ -+ /* -+ * If the device failed to grab its irq resources, -+ * or some other error occurred, don't try to talk -+ * to the port hardware. -+ */ -+ if (!(tty->flags & (1 << TTY_IO_ERROR))) { -+ /* -+ * Make termios settings take effect. -+ */ -+ uart_change_speed(state, NULL); -+ -+ /* -+ * And finally enable the RTS and DTR signals. -+ */ -+ if (tty->termios->c_cflag & CBAUD) -+ uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS); -+ } -+} -+ -+/* -+ * Block the open until the port is ready. We must be called with -+ * the per-port semaphore held. -+ */ -+static int -+uart_block_til_ready(struct file *filp, struct uart_state *state) -+{ -+ DECLARE_WAITQUEUE(wait, current); -+ struct uart_info *info = state->info; -+ struct uart_port *port = state->port; -+ struct termios *termios; -+ -+ /* -+ * If this is a callout device, then just make sure the normal -+ * device isn't being used. -+ */ -+ if (info->tty->driver.subtype == SERIAL_TYPE_CALLOUT) { -+ if (info->flags & UIF_NORMAL_ACTIVE) -+ return -EBUSY; -+ if ((info->flags & UIF_CALLOUT_ACTIVE) && -+ (info->flags & ASYNC_SESSION_LOCKOUT) && -+ (info->session != current->session)) -+ return -EBUSY; -+ if ((info->flags & UIF_CALLOUT_ACTIVE) && -+ (info->flags & ASYNC_PGRP_LOCKOUT) && -+ (info->pgrp != current->pgrp)) -+ return -EBUSY; -+ info->flags |= UIF_CALLOUT_ACTIVE; -+ return 0; -+ } -+ -+ if (info->flags & UIF_CALLOUT_ACTIVE) { -+ termios = &state->normal_termios; -+ } else { -+ termios = state->info->tty->termios; -+ } -+ -+ info->blocked_open++; -+ state->count--; -+ -+ add_wait_queue(&info->open_wait, &wait); -+ while (1) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ /* -+ * If we have been hung up, tell userspace/restart open. -+ */ -+ if (tty_hung_up_p(filp) || info->tty == NULL) -+ break; -+ -+ /* -+ * If the port has been closed, tell userspace/restart open. -+ */ -+ if (!(info->flags & UIF_INITIALIZED)) -+ break; -+ -+ /* -+ * If non-blocking mode is set, or CLOCAL mode is set, -+ * we don't want to wait for the modem status lines to -+ * indicate that the port is ready. -+ * -+ * Also, if the port is not enabled/configured, we want -+ * to allow the open to succeed here. Note that we will -+ * have set TTY_IO_ERROR for a non-existant port. -+ */ -+ if ((filp->f_flags & O_NONBLOCK) || -+ (termios->c_cflag & CLOCAL) || -+ (info->tty->flags & (1 << TTY_IO_ERROR))) { -+ break; -+ } -+ -+ if (!(info->flags & UIF_CALLOUT_ACTIVE)) { -+ /* -+ * Set DTR to allow modem to know we're waiting. Do -+ * not set RTS here - we want to make sure we catch -+ * the data from the modem. -+ */ -+ if (info->tty->termios->c_cflag & CBAUD) -+ uart_set_mctrl(port, TIOCM_DTR); -+ -+ /* -+ * and wait for the carrier to indicate that the -+ * modem is ready for us. -+ */ -+ if (port->ops->get_mctrl(port) & TIOCM_CAR) -+ break; -+ } -+ -+ up(&state->sem); -+ schedule(); -+ down(&state->sem); -+ -+ if (signal_pending(current)) -+ break; -+ } -+ set_current_state(TASK_RUNNING); -+ remove_wait_queue(&info->open_wait, &wait); -+ -+ state->count++; -+ info->blocked_open--; -+ -+ info->flags |= UIF_NORMAL_ACTIVE; -+ -+ if (signal_pending(current)) -+ return -ERESTARTSYS; -+ -+ if (!info->tty || tty_hung_up_p(filp)) -+ return -EAGAIN; -+ -+ return 0; -+} -+ -+static struct uart_state *uart_get(struct uart_driver *drv, int line) -+{ -+ struct uart_state *state; -+ -+ down(&port_sem); -+ state = drv->state + line; -+ if (down_interruptible(&state->sem)) { -+ state = ERR_PTR(-ERESTARTSYS); -+ goto out; -+ } -+ -+ state->count++; -+ if (!state->port) { -+ state->count--; -+ up(&state->sem); -+ state = ERR_PTR(-ENXIO); -+ goto out; -+ } -+ -+ if (!state->info) { -+ state->info = kmalloc(sizeof(struct uart_info), GFP_KERNEL); -+ if (state->info) { -+ memset(state->info, 0, sizeof(struct uart_info)); -+ init_waitqueue_head(&state->info->open_wait); -+ init_waitqueue_head(&state->info->delta_msr_wait); -+ -+ /* -+ * Link the info into the other structures. -+ */ -+ state->port->info = state->info; -+ -+ tasklet_init(&state->info->tlet, uart_tasklet_action, -+ (unsigned long)state); -+ } else { -+ state->count--; -+ up(&state->sem); -+ state = ERR_PTR(-ENOMEM); -+ } -+ } -+ -+ out: -+ up(&port_sem); -+ return state; -+} -+ -+/* -+ * In 2.4.5, calls to uart_open are serialised by the BKL in -+ * linux/fs/devices.c:chrdev_open() -+ * Note that if this fails, then uart_close() _will_ be called. -+ */ -+static int uart_open(struct tty_struct *tty, struct file *filp) -+{ -+ struct uart_driver *drv = (struct uart_driver *)tty->driver.driver_state; -+ struct uart_state *state; -+ int retval, line = MINOR(tty->device) - tty->driver.minor_start; -+ -+ BUG_ON(!kernel_locked()); -+ DPRINTK("uart_open(%d) called\n", line); -+ -+ /* -+ * tty->driver->num won't change, so we won't fail here with -+ * tty->driver_data set to something non-NULL (and therefore -+ * we won't get caught by uart_close()). -+ */ -+ retval = -ENODEV; -+ if (line >= tty->driver.num) -+ goto fail; -+ -+ if (!try_inc_mod_count(drv->owner)) -+ goto fail; -+ -+ /* -+ * We take the semaphore inside uart_get to guarantee that we won't -+ * be re-entered while allocating the info structure, or while we -+ * request any IRQs that the driver may need. This also has the nice -+ * side-effect that it delays the action of uart_hangup, so we can -+ * guarantee that info->tty will always contain something reasonable. -+ */ -+ state = uart_get(drv, line); -+ if (IS_ERR(state)) { -+ retval = PTR_ERR(state); -+ if (!tty->driver_data) -+ goto out; -+ else -+ goto fail; -+ } -+ -+ /* -+ * Once we set tty->driver_data here, we are guaranteed that -+ * uart_close() will decrement the driver module use count. -+ * Any failures from here onwards should not touch the count. -+ */ -+ tty->driver_data = state; -+ tty->low_latency = (state->port->flags & UPF_LOW_LATENCY) ? 1 : 0; -+ tty->alt_speed = uart_get_altspeed(state->port); -+ state->info->tty = tty; -+ -+ /* -+ * If the port is in the middle of closing, bail out now. -+ */ -+ if (tty_hung_up_p(filp)) { -+ retval = -EAGAIN; -+ state->count--; -+ up(&state->sem); -+ goto fail; -+ } -+ -+ /* -+ * Make sure the device is in D0 state. -+ */ -+ if (state->count == 1) -+ uart_change_pm(state, 0); -+ -+ /* -+ * Start up the serial port. -+ */ -+ retval = uart_startup(state, 0); -+ -+ /* -+ * If we succeeded, wait until the port is ready. -+ */ -+ if (retval == 0) -+ retval = uart_block_til_ready(filp, state); -+ -+ /* -+ * If this is the first open to succeed, adjust things to suit. -+ */ -+ if (retval == 0 && state->count == 1) { -+ if (state->port->flags & UPF_SPLIT_TERMIOS) { -+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL) -+ *tty->termios = state->normal_termios; -+ else -+ *tty->termios = state->callout_termios; -+ } -+ -+ uart_update_termios(state); -+ -+ state->info->session = current->session; -+ state->info->pgrp = current->pgrp; -+ } -+ up(&state->sem); -+ -+ return 0; -+ -+ out: -+ if (drv->owner) -+ __MOD_DEC_USE_COUNT(drv->owner); -+ fail: -+ return retval; -+} -+ -+static const char *uart_type(struct uart_port *port) -+{ -+ const char *str = NULL; -+ -+ if (port->ops->type) -+ str = port->ops->type(port); -+ -+ if (!str) -+ str = "unknown"; -+ -+ return str; -+} -+ -+#ifdef CONFIG_PROC_FS -+ -+static int uart_line_info(char *buf, struct uart_driver *drv, int i) -+{ -+ struct uart_state *state = drv->state + i; -+ struct uart_port *port = state->port; -+ char stat_buf[32]; -+ unsigned int status; -+ int ret; -+ -+ if (!port) -+ return 0; -+ -+ ret = sprintf(buf, "%d: uart:%s port:%08X irq:%d", -+ port->line, uart_type(port), -+ port->iobase, port->irq); -+ -+ if (port->type == PORT_UNKNOWN) { -+ strcat(buf, "\n"); -+ return ret + 1; -+ } -+ -+ status = port->ops->get_mctrl(port); -+ -+ ret += sprintf(buf + ret, " tx:%d rx:%d", -+ port->icount.tx, port->icount.rx); -+ if (port->icount.frame) -+ ret += sprintf(buf + ret, " fe:%d", -+ port->icount.frame); -+ if (port->icount.parity) -+ ret += sprintf(buf + ret, " pe:%d", -+ port->icount.parity); -+ if (port->icount.brk) -+ ret += sprintf(buf + ret, " brk:%d", -+ port->icount.brk); -+ if (port->icount.overrun) -+ ret += sprintf(buf + ret, " oe:%d", -+ port->icount.overrun); -+ -+#define INFOBIT(bit,str) \ -+ if (port->mctrl & (bit)) \ -+ strcat(stat_buf, (str)) -+#define STATBIT(bit,str) \ -+ if (status & (bit)) \ -+ strcat(stat_buf, (str)) -+ -+ stat_buf[0] = '\0'; -+ stat_buf[1] = '\0'; -+ INFOBIT(TIOCM_RTS, "|RTS"); -+ STATBIT(TIOCM_CTS, "|CTS"); -+ INFOBIT(TIOCM_DTR, "|DTR"); -+ STATBIT(TIOCM_DSR, "|DSR"); -+ STATBIT(TIOCM_CAR, "|CD"); -+ STATBIT(TIOCM_RNG, "|RI"); -+ if (stat_buf[0]) -+ stat_buf[0] = ' '; -+ strcat(stat_buf, "\n"); -+ -+ ret += sprintf(buf + ret, stat_buf); -+ return ret; -+} -+ -+static int uart_read_proc(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ struct tty_driver *ttydrv = data; -+ struct uart_driver *drv = ttydrv->driver_state; -+ int i, len = 0, l; -+ off_t begin = 0; -+ -+ len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n", -+ "", "", ""); -+ for (i = 0; i < drv->nr && len < PAGE_SIZE - 96; i++) { -+ l = uart_line_info(page + len, drv, i); -+ len += l; -+ if (len + begin > off + count) -+ goto done; -+ if (len + begin < off) { -+ begin += len; -+ len = 0; -+ } -+ } -+ *eof = 1; -+ done: -+ if (off >= len + begin) -+ return 0; -+ *start = page + (off - begin); -+ return (count < begin + len - off) ? count : (begin + len - off); -+} -+#endif -+ -+#ifdef CONFIG_SERIAL_CORE_CONSOLE -+/* -+ * Check whether an invalid uart number has been specified, and -+ * if so, search for the first available port that does have -+ * console support. -+ */ -+struct uart_port * __init -+uart_get_console(struct uart_port *ports, int nr, struct console *co) -+{ -+ int idx = co->index; -+ -+ if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 && -+ ports[idx].membase == NULL)) -+ for (idx = 0; idx < nr; idx++) -+ if (ports[idx].iobase != 0 || -+ ports[idx].membase != NULL) -+ break; -+ -+ co->index = idx; -+ -+ return ports + idx; -+} -+ -+/** -+ * uart_parse_options - Parse serial port baud/parity/bits/flow contro. -+ * @options: pointer to option string -+ * @baud: pointer to an 'int' variable for the baud rate. -+ * @parity: pointer to an 'int' variable for the parity. -+ * @bits: pointer to an 'int' variable for the number of data bits. -+ * @flow: pointer to an 'int' variable for the flow control character. -+ * -+ * uart_parse_options decodes a string containing the serial console -+ * options. The format of the string is , -+ * eg: 115200n8r -+ */ -+void __init -+uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow) -+{ -+ char *s = options; -+ -+ *baud = simple_strtoul(s, NULL, 10); -+ while (*s >= '0' && *s <= '9') -+ s++; -+ if (*s) -+ *parity = *s++; -+ if (*s) -+ *bits = *s++ - '0'; -+ if (*s) -+ *flow = *s; -+} -+ -+struct baud_rates { -+ unsigned int rate; -+ unsigned int cflag; -+}; -+ -+static struct baud_rates baud_rates[] = { -+ { 921600, B921600 }, -+ { 460800, B460800 }, -+ { 230400, B230400 }, -+ { 115200, B115200 }, -+ { 57600, B57600 }, -+ { 38400, B38400 }, -+ { 19200, B19200 }, -+ { 9600, B9600 }, -+ { 4800, B4800 }, -+ { 2400, B2400 }, -+ { 1200, B1200 }, -+ { 0, B38400 } -+}; -+ -+/** -+ * uart_set_options - setup the serial console parameters -+ * @port: pointer to the serial ports uart_port structure -+ * @co: console pointer -+ * @baud: baud rate -+ * @parity: parity character - 'n' (none), 'o' (odd), 'e' (even) -+ * @bits: number of data bits -+ * @flow: flow control character - 'r' (rts) -+ */ -+int __init -+uart_set_options(struct uart_port *port, struct console *co, -+ int baud, int parity, int bits, int flow) -+{ -+ struct termios termios; -+ unsigned int quot; -+ int i; -+ -+ memset(&termios, 0, sizeof(struct termios)); -+ -+ termios.c_cflag = CREAD | HUPCL | CLOCAL; -+ -+ /* -+ * Construct a cflag setting. -+ */ -+ for (i = 0; baud_rates[i].rate; i++) -+ if (baud_rates[i].rate <= baud) -+ break; -+ -+ termios.c_cflag |= baud_rates[i].cflag; -+ baud = baud_rates[i].rate; -+ if (baud == 0) -+ baud = 38400; -+ -+ if (bits == 7) -+ termios.c_cflag |= CS7; -+ else -+ termios.c_cflag |= CS8; -+ -+ switch (parity) { -+ case 'o': case 'O': -+ termios.c_cflag |= PARODD; -+ /*fall through*/ -+ case 'e': case 'E': -+ termios.c_cflag |= PARENB; -+ break; -+ } -+ -+ if (flow == 'r') -+ termios.c_cflag |= CRTSCTS; -+ -+ quot = (port->uartclk / (16 * baud)); -+ port->ops->change_speed(port, termios.c_cflag, 0, quot); -+ co->cflag = termios.c_cflag; -+ -+ return 0; -+} -+ -+extern void ambauart_console_init(void); -+extern void anakin_console_init(void); -+extern void clps711xuart_console_init(void); -+extern void sa1100_rs_console_init(void); -+extern void serial8250_console_init(void); -+extern void at91_console_init(void); -+ -+/* -+ * Central "initialise all serial consoles" container. Needs to be killed. -+ */ -+void __init uart_console_init(void) -+{ -+#ifdef CONFIG_SERIAL_AMBA_CONSOLE -+ ambauart_console_init(); -+#endif -+#ifdef CONFIG_SERIAL_ANAKIN_CONSOLE -+ anakin_console_init(); -+#endif -+#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE -+ clps711xuart_console_init(); -+#endif -+#ifdef CONFIG_SERIAL_SA1100_CONSOLE -+ sa1100_rs_console_init(); -+#endif -+#ifdef CONFIG_SERIAL_AT91_CONSOLE -+ at91_console_init(); -+#endif -+#ifdef CONFIG_SERIAL_8250_CONSOLE -+ serial8250_console_init(); -+#endif -+#ifdef CONFIG_SERIAL_UART00_CONSOLE -+ uart00_console_init(); -+#endif -+} -+#endif /* CONFIG_SERIAL_CORE_CONSOLE */ -+ -+static void uart_change_pm(struct uart_state *state, int pm_state) -+{ -+ struct uart_port *port = state->port; -+ if (port->ops->pm) -+ port->ops->pm(port, pm_state, 0); -+} -+ -+#ifdef CONFIG_PM -+int uart_suspend_port(struct uart_state *state) -+{ -+ struct uart_port *port = state->port; -+ -+ down(&state->sem); -+ if (port) { -+ /* -+ * Disable the console device before suspending. -+ */ -+ if (uart_console(port)) -+ port->cons->flags &= ~CON_ENABLED; -+ -+ if (state->info && state->info->flags & UIF_INITIALIZED) { -+ struct uart_ops *ops = port->ops; -+ -+ spin_lock_irq(&port->lock); -+ ops->stop_tx(port, 0); -+ ops->set_mctrl(port, 0); -+ ops->stop_rx(port); -+ spin_unlock_irq(&port->lock); -+ -+ /* -+ * Wait for the transmitter to empty. -+ */ -+ while (!ops->tx_empty(port)) { -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ schedule_timeout(10*HZ/1000); -+ } -+ set_current_state(TASK_RUNNING); -+ -+ ops->shutdown(port); -+ } -+ -+ uart_change_pm(state, 3); -+ } -+ -+ up(&state->sem); -+ -+ return 0; -+} -+ -+int uart_resume_port(struct uart_state *state) -+{ -+ struct uart_port *port = state->port; -+ -+ down(&state->sem); -+ if (port) { -+ uart_change_pm(state, 0); -+ -+ /* -+ * Re-enable the console device after suspending. -+ */ -+ if (uart_console(port)) { -+ uart_change_speed(state, NULL); -+ port->cons->flags |= CON_ENABLED; -+ } -+ -+ if (state->info && state->info->flags & UIF_INITIALIZED) { -+ struct uart_ops *ops = port->ops; -+ -+ ops->set_mctrl(port, 0); -+ ops->startup(port); -+ uart_change_speed(state, NULL); -+ spin_lock_irq(&port->lock); -+ ops->set_mctrl(port, port->mctrl); -+ ops->start_tx(port, 0); -+ spin_unlock_irq(&port->lock); -+ } -+ } -+ -+ up(&state->sem); -+ -+ return 0; -+} -+ -+/* -+ * Wakeup support. -+ */ -+static int uart_pm_set_wakeup(struct uart_state *state, int data) -+{ -+ int err = 0; -+ -+ if (state->port->ops->set_wake) -+ err = state->port->ops->set_wake(state->port, data); -+ -+ return err; -+} -+ -+static int uart_pm(struct pm_dev *dev, pm_request_t rqst, void *data) -+{ -+ struct uart_state *state = dev->data; -+ int err = 0; -+ -+ if (state->port && state->port->type == PORT_UNKNOWN) -+ return 0; -+ -+ switch (rqst) { -+ case PM_SUSPEND: -+ err = uart_suspend_port(state); -+ break; -+ -+ case PM_RESUME: -+ err = uart_resume_port(state); -+ break; -+ -+ case PM_SET_WAKEUP: -+ err = uart_pm_set_wakeup(state, (int)data); -+ break; -+ } -+ return err; -+} -+#endif -+ -+static inline void -+uart_report_port(struct uart_driver *drv, struct uart_port *port) -+{ -+ printk("%s%d at ", drv->normal_name, port->line); -+ switch (port->iotype) { -+ case UPIO_PORT: -+ printk("I/O 0x%x", port->iobase); -+ break; -+ case UPIO_HUB6: -+ printk("I/O 0x%x offset 0x%x", port->iobase, port->hub6); -+ break; -+ case UPIO_MEM: -+ printk("MMIO 0x%lx", port->mapbase); -+ break; -+ } -+ printk(" (irq = %d) is a %s\n", port->irq, uart_type(port)); -+} -+ -+static void -+uart_configure_port(struct uart_driver *drv, struct uart_state *state, -+ struct uart_port *port) -+{ -+ unsigned int flags; -+ -+ /* -+ * If there isn't a port here, don't do anything further. -+ */ -+ if (!port->iobase && !port->mapbase && !port->membase) -+ return; -+ -+ /* -+ * Now do the auto configuration stuff. Note that config_port -+ * is expected to claim the resources and map the port for us. -+ */ -+ flags = UART_CONFIG_TYPE; -+ if (port->flags & UPF_AUTO_IRQ) -+ flags |= UART_CONFIG_IRQ; -+ if (port->flags & UPF_BOOT_AUTOCONF) { -+ port->type = PORT_UNKNOWN; -+ port->ops->config_port(port, flags); -+ } -+ -+ if (port->type != PORT_UNKNOWN) { -+ unsigned long flags; -+ -+ uart_report_port(drv, port); -+ -+ /* -+ * Ensure that the modem control lines are de-activated. -+ * We probably don't need a spinlock around this, but -+ */ -+ spin_lock_irqsave(&port->lock, flags); -+ port->ops->set_mctrl(port, 0); -+ spin_unlock_irqrestore(&port->lock, flags); -+ -+ /* -+ * Power down all ports by default, except the -+ * console if we have one. -+ */ -+ if (!uart_console(port)) -+ uart_change_pm(state, 3); -+ } -+} -+ -+/* -+ * This reverses the effects of uart_configure_port, hanging up the -+ * port before removal. -+ */ -+static void -+uart_unconfigure_port(struct uart_driver *drv, struct uart_state *state) -+{ -+ struct uart_port *port = state->port; -+ struct uart_info *info = state->info; -+ -+ if (info && info->tty) -+ tty_vhangup(info->tty); -+ -+ down(&state->sem); -+ -+ state->info = NULL; -+ -+ /* -+ * Free the port IO and memory resources, if any. -+ */ -+ if (port->type != PORT_UNKNOWN) -+ port->ops->release_port(port); -+ -+ /* -+ * Indicate that there isn't a port here anymore. -+ */ -+ port->type = PORT_UNKNOWN; -+ -+ /* -+ * Kill the tasklet, and free resources. -+ */ -+ if (info) { -+ tasklet_kill(&info->tlet); -+ kfree(info); -+ } -+ -+ up(&state->sem); -+} -+ -+/** -+ * uart_register_driver - register a driver with the uart core layer -+ * @drv: low level driver structure -+ * -+ * Register a uart driver with the core driver. We in turn register -+ * with the tty layer, and initialise the core driver per-port state. -+ * -+ * We have a proc file in /proc/tty/driver which is named after the -+ * normal driver. -+ * -+ * drv->port should be NULL, and the per-port structures should be -+ * registered using uart_add_one_port after this call has succeeded. -+ */ -+int uart_register_driver(struct uart_driver *drv) -+{ -+ struct tty_driver *normal, *callout; -+ int i, retval; -+ -+ BUG_ON(drv->state); -+ -+ /* -+ * Maybe we should be using a slab cache for this, especially if -+ * we have a large number of ports to handle. Note that we also -+ * allocate space for an integer for reference counting. -+ */ -+ drv->state = kmalloc(sizeof(struct uart_state) * drv->nr + -+ sizeof(int), GFP_KERNEL); -+ retval = -ENOMEM; -+ if (!drv->state) -+ goto out; -+ -+ memset(drv->state, 0, sizeof(struct uart_state) * drv->nr + -+ sizeof(int)); -+ -+ normal = drv->normal_driver; -+ callout = drv->callout_driver; -+ -+ normal->magic = TTY_DRIVER_MAGIC; -+ normal->driver_name = drv->normal_name; -+ normal->name = drv->normal_name; -+ normal->major = drv->normal_major; -+ normal->minor_start = drv->minor; -+ normal->num = drv->nr; -+ normal->type = TTY_DRIVER_TYPE_SERIAL; -+ normal->subtype = SERIAL_TYPE_NORMAL; -+ normal->init_termios = tty_std_termios; -+ normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; -+ normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; -+ normal->refcount = (int *)(drv->state + drv->nr); -+ normal->table = drv->table; -+ normal->termios = drv->termios; -+ normal->termios_locked = drv->termios_locked; -+ normal->driver_state = drv; -+ -+ normal->open = uart_open; -+ normal->close = uart_close; -+ normal->write = uart_write; -+ normal->put_char = uart_put_char; -+ normal->flush_chars = uart_flush_chars; -+ normal->write_room = uart_write_room; -+ normal->chars_in_buffer = uart_chars_in_buffer; -+ normal->flush_buffer = uart_flush_buffer; -+ normal->ioctl = uart_ioctl; -+ normal->throttle = uart_throttle; -+ normal->unthrottle = uart_unthrottle; -+ normal->send_xchar = uart_send_xchar; -+ normal->set_termios = uart_set_termios; -+ normal->stop = uart_stop; -+ normal->start = uart_start; -+ normal->hangup = uart_hangup; -+ normal->break_ctl = uart_break_ctl; -+ normal->wait_until_sent = uart_wait_until_sent; -+#ifdef CONFIG_PROC_FS -+ normal->read_proc = uart_read_proc; -+#endif -+ -+ /* -+ * The callout device is just like the normal device except for -+ * the major number and the subtype code. -+ */ -+ *callout = *normal; -+ callout->name = drv->callout_name; -+ callout->major = drv->callout_major; -+ callout->subtype = SERIAL_TYPE_CALLOUT; -+ callout->read_proc = NULL; -+ callout->proc_entry = NULL; -+ -+ /* -+ * Initialise the UART state(s). -+ */ -+ for (i = 0; i < drv->nr; i++) { -+ struct uart_state *state = drv->state + i; -+ -+ state->callout_termios = callout->init_termios; -+ state->normal_termios = normal->init_termios; -+ state->close_delay = 5 * HZ / 10; -+ state->closing_wait = 30 * HZ; -+ -+ init_MUTEX(&state->sem); -+ } -+ -+ retval = tty_register_driver(normal); -+ if (retval) -+ goto out; -+ -+ retval = tty_register_driver(callout); -+ if (retval) -+ tty_unregister_driver(normal); -+ -+ out: -+ if (retval < 0) { -+ kfree(drv->state); -+ } -+ return retval; -+} -+ -+/** -+ * uart_unregister_driver - remove a driver from the uart core layer -+ * @drv: low level driver structure -+ * -+ * Remove all references to a driver from the core driver. The low -+ * level driver must have removed all its ports via the -+ * uart_remove_one_port() if it registered them with uart_add_one_port(). -+ * (ie, drv->port == NULL) -+ */ -+void uart_unregister_driver(struct uart_driver *drv) -+{ -+ tty_unregister_driver(drv->normal_driver); -+ tty_unregister_driver(drv->callout_driver); -+ -+ kfree(drv->state); -+ drv->state = NULL; -+} -+ -+/** -+ * uart_add_one_port - attach a driver-defined port structure -+ * @drv: pointer to the uart low level driver structure for this port -+ * @port: uart port structure to use for this port. -+ * -+ * This allows the driver to register its own uart_port structure -+ * with the core driver. The main purpose is to allow the low -+ * level uart drivers to expand uart_port, rather than having yet -+ * more levels of structures. -+ */ -+int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) -+{ -+ struct uart_state *state; -+ int ret = 0; -+ -+ BUG_ON(in_interrupt()); -+ -+ if (port->line >= drv->nr) -+ return -EINVAL; -+ -+ state = drv->state + port->line; -+ -+ down(&port_sem); -+ if (state->port) { -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ state->port = port; -+ -+ spin_lock_init(&port->lock); -+ port->cons = drv->cons; -+ port->info = state->info; -+ -+ uart_configure_port(drv, state, port); -+ -+ /* -+ * Register the port whether it's detected or not. This allows -+ * setserial to be used to alter this ports parameters. -+ */ -+ tty_register_devfs(drv->normal_driver, 0, drv->minor + port->line); -+ tty_register_devfs(drv->callout_driver, 0, drv->minor + port->line); -+ -+#ifdef CONFIG_PM -+ port->cons = drv->cons; -+ state->pm = pm_register(PM_SYS_DEV, PM_SYS_COM, uart_pm); -+ if (state->pm) -+ state->pm->data = state; -+#endif -+ -+ out: -+ up(&port_sem); -+ -+ return ret; -+} -+ -+/** -+ * uart_remove_one_port - detach a driver defined port structure -+ * @drv: pointer to the uart low level driver structure for this port -+ * @port: uart port structure for this port -+ * -+ * This unhooks (and hangs up) the specified port structure from the -+ * core driver. No further calls will be made to the low-level code -+ * for this port. -+ */ -+int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) -+{ -+ struct uart_state *state = drv->state + port->line; -+ -+ BUG_ON(in_interrupt()); -+ -+ if (state->port != port) -+ printk(KERN_ALERT "Removing wrong port: %p != %p\n", -+ state->port, port); -+ -+ down(&port_sem); -+ -+ pm_unregister(state->pm); -+ -+ /* -+ * Remove the devices from devfs -+ */ -+ tty_unregister_devfs(drv->normal_driver, drv->minor + port->line); -+ tty_unregister_devfs(drv->callout_driver, drv->minor + port->line); -+ -+ uart_unconfigure_port(drv, state); -+ state->port = NULL; -+ up(&port_sem); -+ -+ return 0; -+} -+ -+/* -+ * Are the two ports equivalent? -+ */ -+static int uart_match_port(struct uart_port *port1, struct uart_port *port2) -+{ -+ if (port1->iotype != port2->iotype) -+ return 0; -+ -+ switch (port1->iotype) { -+ case UPIO_PORT: -+ return (port1->iobase == port2->iobase); -+ case UPIO_HUB6: -+ return (port1->iobase == port2->iobase) && -+ (port1->hub6 == port2->hub6); -+ case UPIO_MEM: -+ return (port1->membase == port2->membase); -+ } -+ return 0; -+} -+ -+/* -+ * Try to find an unused uart_state slot for a port. -+ */ -+static struct uart_state * -+uart_find_match_or_unused(struct uart_driver *drv, struct uart_port *port) -+{ -+ int i; -+ -+ /* -+ * First, find a port entry which matches. Note: if we do -+ * find a matching entry, and it has a non-zero use count, -+ * then we can't register the port. -+ */ -+ for (i = 0; i < drv->nr; i++) -+ if (uart_match_port(drv->state[i].port, port)) -+ return &drv->state[i]; -+ -+ /* -+ * We didn't find a matching entry, so look for the first -+ * free entry. We look for one which hasn't been previously -+ * used (indicated by zero iobase). -+ */ -+ for (i = 0; i < drv->nr; i++) -+ if (drv->state[i].port->type == PORT_UNKNOWN && -+ drv->state[i].port->iobase == 0 && -+ drv->state[i].count == 0) -+ return &drv->state[i]; -+ -+ /* -+ * That also failed. Last resort is to find any currently -+ * entry which doesn't have a real port associated with it. -+ */ -+ for (i = 0; i < drv->nr; i++) -+ if (drv->state[i].port->type == PORT_UNKNOWN && -+ drv->state[i].count == 0) -+ return &drv->state[i]; -+ -+ return NULL; -+} -+ -+/** -+ * uart_register_port: register uart settings with a port -+ * @drv: pointer to the uart low level driver structure for this port -+ * @port: uart port structure describing the port -+ * -+ * Register UART settings with the specified low level driver. Detect -+ * the type of the port if UPF_BOOT_AUTOCONF is set, and detect the -+ * IRQ if UPF_AUTO_IRQ is set. -+ * -+ * We try to pick the same port for the same IO base address, so that -+ * when a modem is plugged in, unplugged and plugged back in, it gets -+ * allocated the same port. -+ * -+ * Returns negative error, or positive line number. -+ */ -+int uart_register_port(struct uart_driver *drv, struct uart_port *port) -+{ -+ struct uart_state *state; -+ int ret; -+ -+ down(&port_sem); -+ -+ state = uart_find_match_or_unused(drv, port); -+ -+ if (state) { -+ /* -+ * Ok, we've found a line that we can use. -+ * -+ * If we find a port that matches this one, and it appears -+ * to be in-use (even if it doesn't have a type) we shouldn't -+ * alter it underneath itself - the port may be open and -+ * trying to do useful work. -+ */ -+ if (uart_users(state) != 0) { -+ ret = -EBUSY; -+ goto out; -+ } -+ -+ /* -+ * If the port is already initialised, don't touch it. -+ */ -+ if (state->port->type == PORT_UNKNOWN) { -+ state->port->iobase = port->iobase; -+ state->port->membase = port->membase; -+ state->port->irq = port->irq; -+ state->port->uartclk = port->uartclk; -+ state->port->fifosize = port->fifosize; -+ state->port->regshift = port->regshift; -+ state->port->iotype = port->iotype; -+ state->port->flags = port->flags; -+ state->port->line = state - drv->state; -+ state->port->mapbase = port->mapbase; -+ -+ uart_configure_port(drv, state, state->port); -+ } -+ -+ ret = state->port->line; -+ } else -+ ret = -ENOSPC; -+ out: -+ up(&port_sem); -+ return ret; -+} -+ -+/** -+ * uart_unregister_port - de-allocate a port -+ * @drv: pointer to the uart low level driver structure for this port -+ * @line: line index previously returned from uart_register_port() -+ * -+ * Hang up the specified line associated with the low level driver, -+ * and mark the port as unused. -+ */ -+void uart_unregister_port(struct uart_driver *drv, int line) -+{ -+ struct uart_state *state; -+ -+ if (line < 0 || line >= drv->nr) { -+ printk(KERN_ERR "Attempt to unregister %s%d\n", -+ drv->normal_name, line); -+ return; -+ } -+ -+ state = drv->state + line; -+ -+ down(&port_sem); -+ uart_unconfigure_port(drv, state); -+ up(&port_sem); -+} -+ -+EXPORT_SYMBOL(uart_write_wakeup); -+EXPORT_SYMBOL(uart_register_driver); -+EXPORT_SYMBOL(uart_unregister_driver); -+EXPORT_SYMBOL(uart_register_port); -+EXPORT_SYMBOL(uart_unregister_port); -+EXPORT_SYMBOL(uart_add_one_port); -+EXPORT_SYMBOL(uart_remove_one_port); -+ -+MODULE_DESCRIPTION("Serial driver core"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.4.26/drivers/serial/omaha.c linux-2.4.26-vrs1/drivers/serial/omaha.c ---- linux-2.4.26/drivers/serial/omaha.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/serial/omaha.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,584 @@ -+/* -+ * linux/drivers/char/omaha.c -+ * -+ * Driver for Omaha serial port -+ * -+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. -+ * -+ * Copyright 1999-2002 ARM Limited -+ * Copyright (C) 2000 Deep Blue Solutions Ltd. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * $Id: serial_amba.c,v 1.4 2001/07/17 20:34:27 rmk Exp $ -+ * -+ * This is a generic driver for ARM AMBA-type serial ports. They -+ * have a lot of 16550-like features, but are not register compatable. -+ * Note that although they do have CTS, DCD and DSR inputs, they do -+ * not have an RI input, nor do they have DTR or RTS outputs. If -+ * required, these have to be supplied via some other means (eg, GPIO) -+ * and hooked into this driver. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#if defined(CONFIG_SERIAL_OMAHA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -+#define SUPPORT_SYSRQ -+#endif -+ -+#include -+ -+#include -+ -+#define UART_NR 1 -+ -+#define SERIAL_OMAHA_MAJOR 204 -+#define SERIAL_OMAHA_MINOR 32 -+#define SERIAL_OMAHA_NR UART_NR -+ -+#define CALLOUT_OMAHA_NAME "cuaom" -+#define CALLOUT_OMAHA_MAJOR 205 -+#define CALLOUT_OMAHA_MINOR 32 -+#define CALLOUT_OMAHA_NR UART_NR -+ -+static struct tty_driver normal, callout; -+static struct tty_struct *omaha_table[UART_NR]; -+static struct termios *omaha_termios[UART_NR], *omaha_termios_locked[UART_NR]; -+#ifdef SUPPORT_SYSRQ -+static struct console omaha_console; -+#endif -+ -+#define OMAHA_ISR_PASS_LIMIT 256 -+ -+/* -+ * Access macros for the Omaha UARTs -+ */ -+ -+#define UART_GET_FR(p) readb((p)->membase + OMAHA_UTRSTAT) -+#define UART_GET_CHAR(p) readb((p)->membase + OMAHA_URXH) -+#define UART_PUT_CHAR(p, c) writel((c), (p)->membase + OMAHA_UTXH) -+#define UART_GET_RSR(p) readb((p)->membase + OMAHA_UERSTAT) -+#define UART_FIFO_STATUS(p) (readl((p)->membase + OMAHA_UFSTAT)) -+#define UART_RX_DATA(s) (((s) & OMAHA_RXFF_CNT) != 0) -+#define UART_TX_DATA(s) (!((s) & OMAHA_TXFF)) -+#define UART_TX_READY(s) (((s) & OMAHA_UTX_EMPTY)) -+#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & OMAHA_UTXEMPTY) != 0) -+ -+#define UART_DUMMY_RSR_RX 256 -+#define UART_PORT_SIZE 64 -+ -+#define RX_IRQ(port) ((port)->irq) -+#define TX_IRQ(port) ((port)->irq + 5) -+ -+/* -+ * Our private driver data mappings. -+ */ -+#define drv_old_status driver_priv -+ -+static void omahauart_stop_tx(struct uart_port *port, u_int from_tty) -+{ -+ disable_irq(TX_IRQ(port)); -+} -+ -+static void omahauart_start_tx(struct uart_port *port, u_int nonempty, u_int from_tty) -+{ -+ if (nonempty) -+ enable_irq(TX_IRQ(port)); -+} -+ -+static void omahauart_stop_rx(struct uart_port *port) -+{ -+ disable_irq(RX_IRQ(port)); -+} -+ -+static void omahauart_enable_ms(struct uart_port *port) -+{ -+ // Do nothing... -+} -+ -+static void -+#ifdef SUPPORT_SYSRQ -+omahauart_rx_chars(struct uart_info *info, struct pt_regs *regs) -+#else -+omahauart_rx_chars(struct uart_info *info) -+#endif -+{ -+ struct tty_struct *tty = info->tty; -+ volatile unsigned int status, data, ch, rsr, max_count = 256; -+ struct uart_port *port = info->port; -+ -+ status = UART_FIFO_STATUS(port); -+ while (UART_RX_DATA(status) && max_count--) { -+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) { -+ tty->flip.tqueue.routine((void *)tty); -+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) { -+ printk(KERN_WARNING "TTY_DONT_FLIP set\n"); -+ return; -+ } -+ } -+ -+ ch = UART_GET_CHAR(port); -+ -+ *tty->flip.char_buf_ptr = ch; -+ *tty->flip.flag_buf_ptr = TTY_NORMAL; -+ port->icount.rx++; -+ -+ /* -+ * Note that the error handling code is -+ * out of the main execution path -+ */ -+ rsr = UART_GET_RSR(port) | UART_DUMMY_RSR_RX; -+ if (rsr & 0xf) { -+ if (rsr & OMAHA_UART_BREAK) { -+ rsr &= ~(OMAHA_UART_FRAME | OMAHA_UART_PARITY); -+ port->icount.brk++; -+ if (uart_handle_break(info, &omaha_console)) -+ goto ignore_char; -+ } else if (rsr & OMAHA_UART_PARITY) -+ port->icount.parity++; -+ else if (rsr & OMAHA_UART_FRAME) -+ port->icount.frame++; -+ if (rsr & OMAHA_UART_OVERRUN) -+ port->icount.overrun++; -+ -+ rsr &= port->read_status_mask; -+ -+ if (rsr & OMAHA_UART_BREAK) -+ *tty->flip.flag_buf_ptr = TTY_BREAK; -+ else if (rsr & OMAHA_UART_PARITY) -+ *tty->flip.flag_buf_ptr = TTY_PARITY; -+ else if (rsr & OMAHA_UART_FRAME) -+ *tty->flip.flag_buf_ptr = TTY_FRAME; -+ } -+ -+ if (uart_handle_sysrq_char(info, ch, regs)) -+ goto ignore_char; -+ -+ if ((rsr & port->ignore_status_mask) == 0) { -+ tty->flip.flag_buf_ptr++; -+ tty->flip.char_buf_ptr++; -+ tty->flip.count++; -+ } -+ if ((rsr & OMAHA_UART_OVERRUN) && -+ tty->flip.count < TTY_FLIPBUF_SIZE) { -+ /* -+ * Overrun is special, since it's reported -+ * immediately, and doesn't affect the current -+ * character -+ */ -+ *tty->flip.char_buf_ptr++ = 0; -+ *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; -+ tty->flip.count++; -+ } -+ ignore_char: -+ status = UART_FIFO_STATUS(port); -+ } -+ tty_flip_buffer_push(tty); -+ return; -+} -+ -+static void omahauart_tx_chars(struct uart_info *info) -+{ -+ struct uart_port *port = info->port; -+ volatile unsigned int status; -+ -+ if (port->x_char) { -+ UART_PUT_CHAR(port, port->x_char); -+ port->icount.tx++; -+ port->x_char = 0; -+ return; -+ } -+ if (info->xmit.head == info->xmit.tail -+ || info->tty->stopped -+ || info->tty->hw_stopped) { -+ omahauart_stop_tx(port, 0); -+ return; -+ } -+ -+ status = UART_FIFO_STATUS(info->port); -+ -+ // FIll FIFO as far as possible -+ while(UART_TX_DATA(UART_FIFO_STATUS(info->port))) -+ { -+ UART_PUT_CHAR(port, info->xmit.buf[info->xmit.tail]); -+ info->xmit.tail = (info->xmit.tail + 1) & (UART_XMIT_SIZE - 1); -+ port->icount.tx++; -+ if (info->xmit.head == info->xmit.tail) -+ break; -+ } -+ -+ if (CIRC_CNT(info->xmit.head, info->xmit.tail, UART_XMIT_SIZE) < -+ WAKEUP_CHARS) -+ uart_event(info, EVT_WRITE_WAKEUP); -+ -+ if (info->xmit.head == info->xmit.tail) -+ omahauart_stop_tx(info->port, 0); -+} -+ -+static void omahauart_int_tx(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ struct uart_info *info = dev_id; -+ volatile unsigned int status, pass_counter = OMAHA_ISR_PASS_LIMIT; -+ -+ status = UART_FIFO_STATUS(info->port); -+ do { -+ // TX if FIFO not full -+ if (UART_TX_DATA(status)) -+ omahauart_tx_chars(info); -+ -+ if (pass_counter-- == 0) -+ break; -+ -+ status = UART_FIFO_STATUS(info->port); -+ } while (UART_TX_DATA(status)); -+} -+ -+static void omahauart_int_rx(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ struct uart_info *info = dev_id; -+ volatile unsigned int status, pass_counter = OMAHA_ISR_PASS_LIMIT; -+ -+ status = UART_FIFO_STATUS(info->port); -+ do { -+ if (UART_RX_DATA(status)) -+#ifdef SUPPORT_SYSRQ -+ omahauart_rx_chars(info, regs); -+#else -+ omahauart_rx_chars(info); -+#endif -+ -+ if (pass_counter-- == 0) -+ break; -+ -+ status = UART_FIFO_STATUS(info->port); -+ } while (UART_RX_DATA(status)); -+} -+ -+static u_int omahauart_tx_empty(struct uart_port *port) -+{ -+ return UART_FIFO_STATUS(port) ? 0 : TIOCSER_TEMT; -+} -+ -+static int omahauart_get_mctrl(struct uart_port *port) -+{ -+ // Report no errors. -+ -+ return 0; -+} -+ -+static void omahauart_set_mctrl(struct uart_port *port, u_int mctrl) -+{ -+ // Do nothing. -+} -+ -+static void omahauart_break_ctl(struct uart_port *port, int break_state) -+{ -+ // Do nothing. -+} -+ -+static int omahauart_startup(struct uart_port *port, struct uart_info *info) -+{ -+ unsigned int tmp; -+ int retval; -+ -+ /* -+ * Allocate the IRQs -+ */ -+ retval = request_irq(TX_IRQ(port), omahauart_int_tx, 0, "omaha_uart_tx", info); -+ if (retval) -+ return retval; -+ -+ retval = request_irq(RX_IRQ(port), omahauart_int_rx, 0, "omaha_uart_rx", info); -+ -+ if (retval) -+ { -+ free_irq(TX_IRQ(port), info); -+ return retval; -+ } -+ -+ /* -+ * initialise the old status of the modem signals -+ */ -+ info->drv_old_status = 0; -+ -+ // Clear all errors -+ writel(0, port->membase + OMAHA_UERSTAT); -+ -+ // Enable FIFO, 16-byte watermark, also do reset (auto-clearing) -+ writel(0xF7, port->membase + OMAHA_UFCON); -+ -+ // Level driven TX/RX ints, with rx timeout enabled -+ tmp = readl(port->membase + OMAHA_UCON); -+ tmp |= 0x280; // rx is pulse driven... -+ writel(tmp, port->membase + OMAHA_UCON); -+ -+ return 0; -+} -+ -+static void omahauart_shutdown(struct uart_port *port, struct uart_info *info) -+{ -+ /* -+ * Free the interrupt -+ */ -+ free_irq(TX_IRQ(port), info); /* TX interrupt */ -+ free_irq(RX_IRQ(port), info); /* RX interrupt */ -+ -+} -+ -+static void omahauart_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot) -+{ -+ // Do nothing. -+} -+ -+static const char *omahauart_type(struct uart_port *port) -+{ -+ return port->type == PORT_OMAHA ? "OMAHA" : NULL; -+} -+ -+/* -+ * Release the memory region(s) being used by 'port' -+ */ -+static void omahauart_release_port(struct uart_port *port) -+{ -+ release_mem_region(port->mapbase, UART_PORT_SIZE); -+} -+ -+/* -+ * Request the memory region(s) being used by 'port' -+ */ -+static int omahauart_request_port(struct uart_port *port) -+{ -+ return request_mem_region(port->mapbase, UART_PORT_SIZE, "serial_omaha") -+ != NULL ? 0 : -EBUSY; -+} -+ -+/* -+ * Configure/autoconfigure the port. -+ */ -+static void omahauart_config_port(struct uart_port *port, int flags) -+{ -+ if (flags & UART_CONFIG_TYPE) { -+ port->type = PORT_OMAHA; -+ omahauart_request_port(port); -+ } -+} -+ -+/* -+ * verify the new serial_struct (for TIOCSSERIAL). -+ */ -+static int omahauart_verify_port(struct uart_port *port, struct serial_struct *ser) -+{ -+ int ret = 0; -+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_OMAHA) -+ ret = -EINVAL; -+ if (ser->irq < 0 || ser->irq >= NR_IRQS) -+ ret = -EINVAL; -+ if (ser->baud_base < 9600) -+ ret = -EINVAL; -+ return ret; -+} -+ -+static struct uart_ops omaha_pops = { -+ .tx_empty = omahauart_tx_empty, -+ .set_mctrl = omahauart_set_mctrl, -+ .get_mctrl = omahauart_get_mctrl, -+ .stop_tx = omahauart_stop_tx, -+ .start_tx = omahauart_start_tx, -+ .stop_rx = omahauart_stop_rx, -+ .enable_ms = omahauart_enable_ms, -+ .break_ctl = omahauart_break_ctl, -+ .startup = omahauart_startup, -+ .shutdown = omahauart_shutdown, -+ .change_speed = omahauart_change_speed, -+ .type = omahauart_type, -+ .release_port = omahauart_release_port, -+ .request_port = omahauart_request_port, -+ .config_port = omahauart_config_port, -+ .verify_port = omahauart_verify_port, -+}; -+ -+static struct uart_port omaha_ports[UART_NR] = { -+ { -+ .membase = (void *)IO_ADDRESS(OMAHA_UART0_BASE), -+ .mapbase = OMAHA_UART0_BASE, -+ .iotype = SERIAL_IO_MEM, -+ .irq = OMAHA_INT_URXD0, -+ .uartclk = 10000000, -+ .fifosize = 8, -+ .unused = { 4, 5 }, /*Udriver_priv: PORT_CTRLS(5, 4), */ -+ .ops = &omaha_pops, -+ .flags = ASYNC_BOOT_AUTOCONF, -+ } -+}; -+ -+#ifdef CONFIG_SERIAL_OMAHA_CONSOLE -+static void omahauart_console_write(struct console *co, const char *s, u_int count) -+{ -+ struct uart_port *port = omaha_ports + co->index; -+ unsigned int status; -+ int i; -+ -+ /* -+ * First save the CR then disable the interrupts -+ */ -+ -+ /* -+ * Now, do each character -+ */ -+ for (i = 0; i < count; i++) { -+ do { -+ status = UART_GET_FR(port); -+ } while ((status & OMAHA_UTX_EMPTY) == 0); -+ UART_PUT_CHAR(port, s[i]); -+ if (s[i] == '\n') { -+ do { -+ status = UART_GET_FR(port); -+ } while ((status & OMAHA_UTX_EMPTY) == 0); -+ UART_PUT_CHAR(port, '\r'); -+ } -+ } -+ -+ /* -+ * Finally, wait for transmitter to become empty -+ * and restore the TCR -+ */ -+ do { -+ status = UART_GET_FR(port); -+ } while ((status & OMAHA_UTX_EMPTY) == 0); -+} -+ -+static kdev_t omahauart_console_device(struct console *co) -+{ -+ return MKDEV(SERIAL_OMAHA_MAJOR, SERIAL_OMAHA_MINOR + co->index); -+} -+ -+static int omahauart_console_wait_key(struct console *co) -+{ -+ struct uart_port *port = omaha_ports + co->index; -+ unsigned int status; -+ -+ do { -+ status = UART_FIFO_STATUS(port); -+ } while (!UART_RX_DATA(status)); -+ return UART_GET_CHAR(port); -+} -+ -+static void __init -+omahauart_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) -+{ -+ // Do nothing. -+} -+ -+static int __init omahauart_console_setup(struct console *co, char *options) -+{ -+ struct uart_port *port; -+ int baud = 38400; -+ int bits = 8; -+ int parity = 'n'; -+ int flow = 'n'; -+ -+ /* -+ * Check whether an invalid uart number has been specified, and -+ * if so, search for the first available port that does have -+ * console support. -+ */ -+ port = uart_get_console(omaha_ports, UART_NR, co); -+ -+ if (options) -+ uart_parse_options(options, &baud, &parity, &bits, &flow); -+ else -+ omahauart_console_get_options(port, &baud, &parity, &bits); -+ -+ return uart_set_options(port, co, baud, parity, bits, flow); -+} -+ -+static struct console omaha_console = { -+ .write = omahauart_console_write, -+ .device = omahauart_console_device, -+ .wait_key = omahauart_console_wait_key, -+ .setup = omahauart_console_setup, -+ .flags = CON_PRINTBUFFER, -+ .index = -1, -+}; -+ -+void __init omahauart_console_init(void) -+{ -+ register_console(&omaha_console); -+} -+ -+#define OMAHA_CONSOLE &omaha_console -+#else -+#define OMAHA_CONSOLE NULL -+#endif -+ -+static struct uart_driver omaha_reg = { -+ .owner = THIS_MODULE, -+ .normal_major = SERIAL_OMAHA_MAJOR, -+#ifdef CONFIG_DEVFS_FS -+ .normal_name = "ttyOM%d", -+ .callout_name = "cuaom%d", -+#else -+ .normal_name = "ttyOM", -+ .callout_name = "cuaom", -+#endif -+ .normal_driver = &normal, -+ .callout_major = CALLOUT_OMAHA_MAJOR, -+ .callout_driver = &callout, -+ .table = omaha_table, -+ .termios = omaha_termios, -+ .termios_locked = omaha_termios_locked, -+ .minor = SERIAL_OMAHA_MINOR, -+ .nr = UART_NR, -+ .port = omaha_ports, -+ .cons = OMAHA_CONSOLE, -+}; -+ -+static int __init omahauart_init(void) -+{ -+ return uart_register_driver(&omaha_reg); -+} -+ -+static void __exit omahauart_exit(void) -+{ -+ uart_unregister_driver(&omaha_reg); -+} -+ -+module_init(omahauart_init); -+module_exit(omahauart_exit); -diff -urN linux-2.4.26/drivers/serial/sa1100.c linux-2.4.26-vrs1/drivers/serial/sa1100.c ---- linux-2.4.26/drivers/serial/sa1100.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/serial/sa1100.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,904 @@ -+/* -+ * linux/drivers/char/serial_sa1100.c -+ * -+ * Driver for SA11x0 serial ports -+ * -+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. -+ * -+ * Copyright (C) 2000 Deep Blue Solutions Ltd. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * $Id: sa1100.c,v 1.14.2.4 2002/10/24 09:53:25 rmk Exp $ -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#if defined(CONFIG_SERIAL_SA1100_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -+#define SUPPORT_SYSRQ -+#endif -+ -+#include -+ -+/* We've been assigned a range on the "Low-density serial ports" major */ -+#define SERIAL_SA1100_MAJOR 204 -+#define CALLOUT_SA1100_MAJOR 205 -+#define MINOR_START 5 -+ -+#define NR_PORTS 3 -+ -+#define SA1100_ISR_PASS_LIMIT 256 -+ -+/* -+ * Convert from ignore_status_mask or read_status_mask to UTSR[01] -+ */ -+#define SM_TO_UTSR0(x) ((x) & 0xff) -+#define SM_TO_UTSR1(x) ((x) >> 8) -+#define UTSR0_TO_SM(x) ((x)) -+#define UTSR1_TO_SM(x) ((x) << 8) -+ -+#define UART_GET_UTCR0(sport) __raw_readl((sport)->port.membase + UTCR0) -+#define UART_GET_UTCR1(sport) __raw_readl((sport)->port.membase + UTCR1) -+#define UART_GET_UTCR2(sport) __raw_readl((sport)->port.membase + UTCR2) -+#define UART_GET_UTCR3(sport) __raw_readl((sport)->port.membase + UTCR3) -+#define UART_GET_UTSR0(sport) __raw_readl((sport)->port.membase + UTSR0) -+#define UART_GET_UTSR1(sport) __raw_readl((sport)->port.membase + UTSR1) -+#define UART_GET_CHAR(sport) __raw_readl((sport)->port.membase + UTDR) -+ -+#define UART_PUT_UTCR0(sport,v) __raw_writel((v),(sport)->port.membase + UTCR0) -+#define UART_PUT_UTCR1(sport,v) __raw_writel((v),(sport)->port.membase + UTCR1) -+#define UART_PUT_UTCR2(sport,v) __raw_writel((v),(sport)->port.membase + UTCR2) -+#define UART_PUT_UTCR3(sport,v) __raw_writel((v),(sport)->port.membase + UTCR3) -+#define UART_PUT_UTSR0(sport,v) __raw_writel((v),(sport)->port.membase + UTSR0) -+#define UART_PUT_UTSR1(sport,v) __raw_writel((v),(sport)->port.membase + UTSR1) -+#define UART_PUT_CHAR(sport,v) __raw_writel((v),(sport)->port.membase + UTDR) -+ -+/* -+ * This is the size of our serial port register set. -+ */ -+#define UART_PORT_SIZE 0x24 -+ -+static struct tty_driver normal, callout; -+static struct tty_struct *sa1100_table[NR_PORTS]; -+static struct termios *sa1100_termios[NR_PORTS], *sa1100_termios_locked[NR_PORTS]; -+static int (*sa1100_open)(struct uart_port *); -+static void (*sa1100_close)(struct uart_port *); -+#ifdef SUPPORT_SYSRQ -+static struct console sa1100_console; -+#endif -+ -+/* -+ * This determines how often we check the modem status signals -+ * for any change. They generally aren't connected to an IRQ -+ * so we have to poll them. We also check immediately before -+ * filling the TX fifo incase CTS has been dropped. -+ */ -+#define MCTRL_TIMEOUT (250*HZ/1000) -+ -+struct sa1100_port { -+ struct uart_port port; -+ struct timer_list timer; -+ unsigned int old_status; -+}; -+ -+/* -+ * Handle any change of modem status signal since we were last called. -+ */ -+static void sa1100_mctrl_check(struct sa1100_port *sport) -+{ -+ unsigned int status, changed; -+ -+ status = sport->port.ops->get_mctrl(&sport->port); -+ changed = status ^ sport->old_status; -+ -+ if (changed == 0) -+ return; -+ -+ sport->old_status = status; -+ -+ if (changed & TIOCM_RI) -+ sport->port.icount.rng++; -+ if (changed & TIOCM_DSR) -+ sport->port.icount.dsr++; -+ if (changed & TIOCM_CAR) -+ uart_handle_dcd_change(&sport->port, status & TIOCM_CAR); -+ if (changed & TIOCM_CTS) -+ uart_handle_cts_change(&sport->port, status & TIOCM_CTS); -+ -+ wake_up_interruptible(&sport->port.info->delta_msr_wait); -+} -+ -+/* -+ * This is our per-port timeout handler, for checking the -+ * modem status signals. -+ */ -+static void sa1100_timeout(unsigned long data) -+{ -+ struct sa1100_port *sport = (struct sa1100_port *)data; -+ unsigned long flags; -+ -+ if (sport->port.info) { -+ spin_lock_irqsave(&sport->port.lock, flags); -+ sa1100_mctrl_check(sport); -+ spin_unlock_irqrestore(&sport->port.lock, flags); -+ -+ mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT); -+ } -+} -+ -+/* -+ * interrupts disabled on entry -+ */ -+static void sa1100_stop_tx(struct uart_port *port, unsigned int tty_stop) -+{ -+ struct sa1100_port *sport = (struct sa1100_port *)port; -+ u32 utcr3; -+ -+ utcr3 = UART_GET_UTCR3(sport); -+ UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_TIE); -+ sport->port.read_status_mask &= ~UTSR0_TO_SM(UTSR0_TFS); -+} -+ -+/* -+ * interrupts may not be disabled on entry -+ */ -+static void sa1100_start_tx(struct uart_port *port, unsigned int tty_start) -+{ -+ struct sa1100_port *sport = (struct sa1100_port *)port; -+ unsigned long flags; -+ u32 utcr3; -+ -+ spin_lock_irqsave(&sport->port.lock, flags); -+ utcr3 = UART_GET_UTCR3(sport); -+ sport->port.read_status_mask |= UTSR0_TO_SM(UTSR0_TFS); -+ UART_PUT_UTCR3(sport, utcr3 | UTCR3_TIE); -+ spin_unlock_irqrestore(&sport->port.lock, flags); -+} -+ -+/* -+ * Interrupts enabled -+ */ -+static void sa1100_stop_rx(struct uart_port *port) -+{ -+ struct sa1100_port *sport = (struct sa1100_port *)port; -+ u32 utcr3; -+ -+ utcr3 = UART_GET_UTCR3(sport); -+ UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_RIE); -+} -+ -+/* -+ * Set the modem control timer to fire immediately. -+ */ -+static void sa1100_enable_ms(struct uart_port *port) -+{ -+ struct sa1100_port *sport = (struct sa1100_port *)port; -+ -+ mod_timer(&sport->timer, jiffies); -+} -+ -+static void -+sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs) -+{ -+ struct tty_struct *tty = sport->port.info->tty; -+ unsigned int status, ch, flg, ignored = 0; -+ -+ status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | -+ UTSR0_TO_SM(UART_GET_UTSR0(sport)); -+ while (status & UTSR1_TO_SM(UTSR1_RNE)) { -+ ch = UART_GET_CHAR(sport); -+ -+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) -+ goto ignore_char; -+ sport->port.icount.rx++; -+ -+ flg = TTY_NORMAL; -+ -+ /* -+ * note that the error handling code is -+ * out of the main execution path -+ */ -+ if (status & UTSR1_TO_SM(UTSR1_PRE | UTSR1_FRE | UTSR1_ROR)) -+ goto handle_error; -+ -+ if (uart_handle_sysrq_char(&sport->port, ch, regs)) -+ goto ignore_char; -+ -+ error_return: -+ *tty->flip.flag_buf_ptr++ = flg; -+ *tty->flip.char_buf_ptr++ = ch; -+ tty->flip.count++; -+ ignore_char: -+ status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | -+ UTSR0_TO_SM(UART_GET_UTSR0(sport)); -+ } -+ out: -+ tty_flip_buffer_push(tty); -+ return; -+ -+ handle_error: -+ if (status & UTSR1_TO_SM(UTSR1_PRE)) -+ sport->port.icount.parity++; -+ else if (status & UTSR1_TO_SM(UTSR1_FRE)) -+ sport->port.icount.frame++; -+ if (status & UTSR1_TO_SM(UTSR1_ROR)) -+ sport->port.icount.overrun++; -+ -+ if (status & sport->port.ignore_status_mask) { -+ if (++ignored > 100) -+ goto out; -+ goto ignore_char; -+ } -+ -+ status &= sport->port.read_status_mask; -+ -+ if (status & UTSR1_TO_SM(UTSR1_PRE)) -+ flg = TTY_PARITY; -+ else if (status & UTSR1_TO_SM(UTSR1_FRE)) -+ flg = TTY_FRAME; -+ -+ if (status & UTSR1_TO_SM(UTSR1_ROR)) { -+ /* -+ * overrun does *not* affect the character -+ * we read from the FIFO -+ */ -+ *tty->flip.flag_buf_ptr++ = flg; -+ *tty->flip.char_buf_ptr++ = ch; -+ tty->flip.count++; -+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) -+ goto ignore_char; -+ ch = 0; -+ flg = TTY_OVERRUN; -+ } -+#ifdef SUPPORT_SYSRQ -+ sport->port.sysrq = 0; -+#endif -+ goto error_return; -+} -+ -+static void sa1100_tx_chars(struct sa1100_port *sport) -+{ -+ struct circ_buf *xmit = &sport->port.info->xmit; -+ -+ if (sport->port.x_char) { -+ UART_PUT_CHAR(sport, sport->port.x_char); -+ sport->port.icount.tx++; -+ sport->port.x_char = 0; -+ return; -+ } -+ -+ /* -+ * Check the modem control lines before -+ * transmitting anything. -+ */ -+ sa1100_mctrl_check(sport); -+ -+ if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { -+ sa1100_stop_tx(&sport->port, 0); -+ return; -+ } -+ -+ /* -+ * Tried using FIFO (not checking TNF) for fifo fill: -+ * still had the '4 bytes repeated' problem. -+ */ -+ while (UART_GET_UTSR1(sport) & UTSR1_TNF) { -+ UART_PUT_CHAR(sport, xmit->buf[xmit->tail]); -+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); -+ sport->port.icount.tx++; -+ if (uart_circ_empty(xmit)) -+ break; -+ } -+ -+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) -+ uart_write_wakeup(&sport->port); -+ -+ if (uart_circ_empty(xmit)) -+ sa1100_stop_tx(&sport->port, 0); -+} -+ -+static void sa1100_int(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ struct sa1100_port *sport = dev_id; -+ unsigned int status, pass_counter = 0; -+ -+ spin_lock(&sport->port.lock); -+ status = UART_GET_UTSR0(sport); -+ status &= SM_TO_UTSR0(sport->port.read_status_mask) | ~UTSR0_TFS; -+ do { -+ if (status & (UTSR0_RFS | UTSR0_RID)) { -+ /* Clear the receiver idle bit, if set */ -+ if (status & UTSR0_RID) -+ UART_PUT_UTSR0(sport, UTSR0_RID); -+ sa1100_rx_chars(sport, regs); -+ } -+ -+ /* Clear the relevant break bits */ -+ if (status & (UTSR0_RBB | UTSR0_REB)) -+ UART_PUT_UTSR0(sport, status & (UTSR0_RBB | UTSR0_REB)); -+ -+ if (status & UTSR0_RBB) -+ sport->port.icount.brk++; -+ -+ if (status & UTSR0_REB) -+ uart_handle_break(&sport->port); -+ -+ if (status & UTSR0_TFS) -+ sa1100_tx_chars(sport); -+ if (pass_counter++ > SA1100_ISR_PASS_LIMIT) -+ break; -+ status = UART_GET_UTSR0(sport); -+ status &= SM_TO_UTSR0(sport->port.read_status_mask) | -+ ~UTSR0_TFS; -+ } while (status & (UTSR0_TFS | UTSR0_RFS | UTSR0_RID)); -+ spin_unlock(&sport->port.lock); -+} -+ -+/* -+ * Return TIOCSER_TEMT when transmitter is not busy. -+ */ -+static unsigned int sa1100_tx_empty(struct uart_port *port) -+{ -+ struct sa1100_port *sport = (struct sa1100_port *)port; -+ -+ return UART_GET_UTSR1(sport) & UTSR1_TBY ? 0 : TIOCSER_TEMT; -+} -+ -+static unsigned int sa1100_get_mctrl(struct uart_port *port) -+{ -+ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; -+} -+ -+static void sa1100_set_mctrl(struct uart_port *port, unsigned int mctrl) -+{ -+} -+ -+/* -+ * Interrupts always disabled. -+ */ -+static void sa1100_break_ctl(struct uart_port *port, int break_state) -+{ -+ struct sa1100_port *sport = (struct sa1100_port *)port; -+ unsigned long flags; -+ unsigned int utcr3; -+ -+ spin_lock_irqsave(&sport->port.lock, flags); -+ utcr3 = UART_GET_UTCR3(sport); -+ if (break_state == -1) -+ utcr3 |= UTCR3_BRK; -+ else -+ utcr3 &= ~UTCR3_BRK; -+ UART_PUT_UTCR3(sport, utcr3); -+ spin_unlock_irqrestore(&sport->port.lock, flags); -+} -+ -+static int sa1100_startup(struct uart_port *port) -+{ -+ struct sa1100_port *sport = (struct sa1100_port *)port; -+ int retval; -+ -+ /* -+ * Allocate the IRQ -+ */ -+ retval = request_irq(sport->port.irq, sa1100_int, 0, -+ "sa11x0-uart", sport); -+ if (retval) -+ return retval; -+ -+ /* -+ * If there is a specific "open" function -+ * (to register control line interrupts) -+ */ -+ if (sa1100_open) { -+ retval = sa1100_open(port); -+ if (retval) { -+ free_irq(sport->port.irq, sport); -+ return retval; -+ } -+ } -+ -+ /* -+ * Finally, clear and enable interrupts -+ */ -+ UART_PUT_UTSR0(sport, -1); -+ UART_PUT_UTCR3(sport, UTCR3_RXE | UTCR3_TXE | UTCR3_RIE); -+ -+ return 0; -+} -+ -+static void sa1100_shutdown(struct uart_port *port) -+{ -+ struct sa1100_port *sport = (struct sa1100_port *)port; -+ -+ /* -+ * Stop our timer. -+ */ -+ del_timer_sync(&sport->timer); -+ -+ /* -+ * Free the interrupt -+ */ -+ free_irq(sport->port.irq, sport); -+ -+ /* -+ * If there is a specific "close" function (to unregister -+ * control line interrupts) -+ */ -+ if (sa1100_close) -+ sa1100_close(port); -+ -+ /* -+ * Disable all interrupts, port and break condition. -+ */ -+ UART_PUT_UTCR3(sport, 0); -+} -+ -+static void sa1100_change_speed(struct uart_port *port, unsigned int cflag, unsigned int iflag, unsigned int quot) -+{ -+ struct sa1100_port *sport = (struct sa1100_port *)port; -+ unsigned long flags; -+ unsigned int utcr0, old_utcr3; -+ -+ if ((cflag & CSIZE) == CS8) -+ utcr0 = UTCR0_DSS; -+ else -+ utcr0 = 0; -+ -+ if (cflag & CSTOPB) -+ utcr0 |= UTCR0_SBS; -+ if (cflag & PARENB) { -+ utcr0 |= UTCR0_PE; -+ if (!(cflag & PARODD)) -+ utcr0 |= UTCR0_OES; -+ } -+ -+ spin_lock_irqsave(&sport->port.lock, flags); -+ -+ sport->port.read_status_mask &= UTSR0_TO_SM(UTSR0_TFS); -+ sport->port.read_status_mask |= UTSR1_TO_SM(UTSR1_ROR); -+ if (iflag & INPCK) -+ sport->port.read_status_mask |= -+ UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE); -+ if (iflag & (BRKINT | PARMRK)) -+ sport->port.read_status_mask |= -+ UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB); -+ -+ /* -+ * Characters to ignore -+ */ -+ sport->port.ignore_status_mask = 0; -+ if (iflag & IGNPAR) -+ sport->port.ignore_status_mask |= -+ UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE); -+ if (iflag & IGNBRK) { -+ sport->port.ignore_status_mask |= -+ UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB); -+ /* -+ * If we're ignoring parity and break indicators, -+ * ignore overruns too (for real raw support). -+ */ -+ if (iflag & IGNPAR) -+ sport->port.ignore_status_mask |= -+ UTSR1_TO_SM(UTSR1_ROR); -+ } -+ -+ del_timer_sync(&sport->timer); -+ -+ /* -+ * disable interrupts and drain transmitter -+ */ -+ old_utcr3 = UART_GET_UTCR3(sport); -+ UART_PUT_UTCR3(sport, old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE)); -+ -+ while (UART_GET_UTSR1(sport) & UTSR1_TBY) -+ barrier(); -+ -+ /* then, disable everything */ -+ UART_PUT_UTCR3(sport, 0); -+ -+ /* set the parity, stop bits and data size */ -+ UART_PUT_UTCR0(sport, utcr0); -+ -+ /* set the baud rate */ -+ quot -= 1; -+ UART_PUT_UTCR1(sport, ((quot & 0xf00) >> 8)); -+ UART_PUT_UTCR2(sport, (quot & 0xff)); -+ -+ UART_PUT_UTSR0(sport, -1); -+ -+ UART_PUT_UTCR3(sport, old_utcr3); -+ -+ if (UART_ENABLE_MS(&sport->port, cflag)) -+ sa1100_enable_ms(&sport->port); -+ -+ spin_unlock_irqrestore(&sport->port.lock, flags); -+} -+ -+static const char *sa1100_type(struct uart_port *port) -+{ -+ struct sa1100_port *sport = (struct sa1100_port *)port; -+ -+ return sport->port.type == PORT_SA1100 ? "SA1100" : NULL; -+} -+ -+/* -+ * Release the memory region(s) being used by 'port'. -+ */ -+static void sa1100_release_port(struct uart_port *port) -+{ -+ struct sa1100_port *sport = (struct sa1100_port *)port; -+ -+ release_mem_region(sport->port.mapbase, UART_PORT_SIZE); -+} -+ -+/* -+ * Request the memory region(s) being used by 'port'. -+ */ -+static int sa1100_request_port(struct uart_port *port) -+{ -+ struct sa1100_port *sport = (struct sa1100_port *)port; -+ -+ return request_mem_region(sport->port.mapbase, UART_PORT_SIZE, -+ "sa11x0-uart") != NULL ? 0 : -EBUSY; -+} -+ -+/* -+ * Configure/autoconfigure the port. -+ */ -+static void sa1100_config_port(struct uart_port *port, int flags) -+{ -+ struct sa1100_port *sport = (struct sa1100_port *)port; -+ -+ if (flags & UART_CONFIG_TYPE && -+ sa1100_request_port(&sport->port) == 0) -+ sport->port.type = PORT_SA1100; -+} -+ -+/* -+ * Verify the new serial_struct (for TIOCSSERIAL). -+ * The only change we allow are to the flags and type, and -+ * even then only between PORT_SA1100 and PORT_UNKNOWN -+ */ -+static int sa1100_verify_port(struct uart_port *port, struct serial_struct *ser) -+{ -+ struct sa1100_port *sport = (struct sa1100_port *)port; -+ int ret = 0; -+ -+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_SA1100) -+ ret = -EINVAL; -+ if (sport->port.irq != ser->irq) -+ ret = -EINVAL; -+ if (ser->io_type != SERIAL_IO_MEM) -+ ret = -EINVAL; -+ if (sport->port.uartclk / 16 != ser->baud_base) -+ ret = -EINVAL; -+ if ((void *)sport->port.mapbase != ser->iomem_base) -+ ret = -EINVAL; -+ if (sport->port.iobase != ser->port) -+ ret = -EINVAL; -+ if (ser->hub6 != 0) -+ ret = -EINVAL; -+ return ret; -+} -+ -+static struct uart_ops sa1100_pops = { -+ .tx_empty = sa1100_tx_empty, -+ .set_mctrl = sa1100_set_mctrl, -+ .get_mctrl = sa1100_get_mctrl, -+ .stop_tx = sa1100_stop_tx, -+ .start_tx = sa1100_start_tx, -+ .stop_rx = sa1100_stop_rx, -+ .enable_ms = sa1100_enable_ms, -+ .break_ctl = sa1100_break_ctl, -+ .startup = sa1100_startup, -+ .shutdown = sa1100_shutdown, -+ .change_speed = sa1100_change_speed, -+ .type = sa1100_type, -+ .release_port = sa1100_release_port, -+ .request_port = sa1100_request_port, -+ .config_port = sa1100_config_port, -+ .verify_port = sa1100_verify_port, -+}; -+ -+static struct sa1100_port sa1100_ports[NR_PORTS]; -+ -+/* -+ * Setup the SA1100 serial ports. Note that we don't include the IrDA -+ * port here since we have our own SIR/FIR driver (see drivers/net/irda) -+ * -+ * Note also that we support "console=ttySAx" where "x" is either 0 or 1. -+ * Which serial port this ends up being depends on the machine you're -+ * running this kernel on. I'm not convinced that this is a good idea, -+ * but that's the way it traditionally works. -+ * -+ * Note that NanoEngine UART3 becomes UART2, and UART2 is no longer -+ * used here. -+ */ -+static void __init sa1100_init_ports(void) -+{ -+ static int first = 1; -+ int i; -+ -+ if (!first) -+ return; -+ first = 0; -+ -+ for (i = 0; i < NR_PORTS; i++) { -+ sa1100_ports[i].port.uartclk = 3686400; -+ sa1100_ports[i].port.ops = &sa1100_pops; -+ sa1100_ports[i].port.fifosize = 8; -+ sa1100_ports[i].port.line = i; -+ sa1100_ports[i].port.iotype = SERIAL_IO_MEM; -+ init_timer(&sa1100_ports[i].timer); -+ sa1100_ports[i].timer.function = sa1100_timeout; -+ sa1100_ports[i].timer.data = (unsigned long)&sa1100_ports[i]; -+ } -+ -+ /* -+ * make transmit lines outputs, so that when the port -+ * is closed, the output is in the MARK state. -+ */ -+ PPDR |= PPC_TXD1 | PPC_TXD3; -+ PPSR |= PPC_TXD1 | PPC_TXD3; -+} -+ -+void __init sa1100_register_uart_fns(struct sa1100_port_fns *fns) -+{ -+ if (fns->enable_ms) -+ sa1100_pops.enable_ms = fns->enable_ms; -+ if (fns->get_mctrl) -+ sa1100_pops.get_mctrl = fns->get_mctrl; -+ if (fns->set_mctrl) -+ sa1100_pops.set_mctrl = fns->set_mctrl; -+ sa1100_open = fns->open; -+ sa1100_close = fns->close; -+ sa1100_pops.pm = fns->pm; -+ sa1100_pops.set_wake = fns->set_wake; -+} -+ -+void __init sa1100_register_uart(int idx, int port) -+{ -+ if (idx >= NR_PORTS) { -+ printk(KERN_ERR "%s: bad index number %d\n", __FUNCTION__, idx); -+ return; -+ } -+ -+ switch (port) { -+ case 1: -+ sa1100_ports[idx].port.membase = (void *)&Ser1UTCR0; -+ sa1100_ports[idx].port.mapbase = _Ser1UTCR0; -+ sa1100_ports[idx].port.irq = IRQ_Ser1UART; -+ sa1100_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF; -+ break; -+ -+ case 2: -+ sa1100_ports[idx].port.membase = (void *)&Ser2UTCR0; -+ sa1100_ports[idx].port.mapbase = _Ser2UTCR0; -+ sa1100_ports[idx].port.irq = IRQ_Ser2ICP; -+ sa1100_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF; -+ break; -+ -+ case 3: -+ sa1100_ports[idx].port.membase = (void *)&Ser3UTCR0; -+ sa1100_ports[idx].port.mapbase = _Ser3UTCR0; -+ sa1100_ports[idx].port.irq = IRQ_Ser3UART; -+ sa1100_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF; -+ break; -+ -+ default: -+ printk(KERN_ERR "%s: bad port number %d\n", __FUNCTION__, port); -+ } -+} -+ -+ -+#ifdef CONFIG_SERIAL_SA1100_CONSOLE -+ -+/* -+ * Interrupts are disabled on entering -+ */ -+static void -+sa1100_console_write(struct console *co, const char *s, unsigned int count) -+{ -+ struct sa1100_port *sport = &sa1100_ports[co->index]; -+ unsigned int old_utcr3, status, i; -+ -+ /* -+ * First, save UTCR3 and then disable interrupts -+ */ -+ old_utcr3 = UART_GET_UTCR3(sport); -+ UART_PUT_UTCR3(sport, (old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE)) | -+ UTCR3_TXE); -+ -+ /* -+ * Now, do each character -+ */ -+ for (i = 0; i < count; i++) { -+ do { -+ status = UART_GET_UTSR1(sport); -+ } while (!(status & UTSR1_TNF)); -+ UART_PUT_CHAR(sport, s[i]); -+ if (s[i] == '\n') { -+ do { -+ status = UART_GET_UTSR1(sport); -+ } while (!(status & UTSR1_TNF)); -+ UART_PUT_CHAR(sport, '\r'); -+ } -+ } -+ -+ /* -+ * Finally, wait for transmitter to become empty -+ * and restore UTCR3 -+ */ -+ do { -+ status = UART_GET_UTSR1(sport); -+ } while (status & UTSR1_TBY); -+ UART_PUT_UTCR3(sport, old_utcr3); -+} -+ -+static kdev_t sa1100_console_device(struct console *co) -+{ -+ return MKDEV(SERIAL_SA1100_MAJOR, MINOR_START + co->index); -+} -+ -+/* -+ * If the port was already initialised (eg, by a boot loader), try to determine -+ * the current setup. -+ */ -+static void __init -+sa1100_console_get_options(struct sa1100_port *sport, int *baud, -+ int *parity, int *bits) -+{ -+ unsigned int utcr3; -+ -+ utcr3 = UART_GET_UTCR3(sport) & (UTCR3_RXE | UTCR3_TXE); -+ if (utcr3 == (UTCR3_RXE | UTCR3_TXE)) { -+ /* ok, the port was enabled */ -+ unsigned int utcr0, quot; -+ -+ utcr0 = UART_GET_UTCR0(sport); -+ -+ *parity = 'n'; -+ if (utcr0 & UTCR0_PE) { -+ if (utcr0 & UTCR0_OES) -+ *parity = 'e'; -+ else -+ *parity = 'o'; -+ } -+ -+ if (utcr0 & UTCR0_DSS) -+ *bits = 8; -+ else -+ *bits = 7; -+ -+ quot = UART_GET_UTCR2(sport) | UART_GET_UTCR1(sport) << 8; -+ quot &= 0xfff; -+ *baud = sport->port.uartclk / (16 * (quot + 1)); -+ } -+} -+ -+static int __init -+sa1100_console_setup(struct console *co, char *options) -+{ -+ struct sa1100_port *sport; -+ int baud = CONFIG_SA1100_DEFAULT_BAUDRATE; -+ int bits = 8; -+ int parity = 'n'; -+ int flow = 'n'; -+ -+ /* -+ * Check whether an invalid uart number has been specified, and -+ * if so, search for the first available port that does have -+ * console support. -+ */ -+ if (co->index == -1 || co->index >= NR_PORTS) -+ co->index = 0; -+ sport = &sa1100_ports[co->index]; -+ -+ if (options) -+ uart_parse_options(options, &baud, &parity, &bits, &flow); -+ else -+ sa1100_console_get_options(sport, &baud, &parity, &bits); -+ -+ return uart_set_options(&sport->port, co, baud, parity, bits, flow); -+} -+ -+static struct console sa1100_console = { -+ .name = "ttySA", -+ .write = sa1100_console_write, -+ .device = sa1100_console_device, -+ .setup = sa1100_console_setup, -+ .flags = CON_PRINTBUFFER, -+ .index = -1, -+}; -+ -+void __init sa1100_rs_console_init(void) -+{ -+ sa1100_init_ports(); -+ register_console(&sa1100_console); -+} -+ -+#define SA1100_CONSOLE &sa1100_console -+#else -+#define SA1100_CONSOLE NULL -+#endif -+ -+static struct uart_driver sa1100_reg = { -+ .owner = THIS_MODULE, -+ .normal_major = SERIAL_SA1100_MAJOR, -+#ifdef CONFIG_DEVFS_FS -+ .normal_name = "ttySA%d", -+ .callout_name = "cusa%d", -+#else -+ .normal_name = "ttySA", -+ .callout_name = "cusa", -+#endif -+ .normal_driver = &normal, -+ .callout_major = CALLOUT_SA1100_MAJOR, -+ .callout_driver = &callout, -+ .table = sa1100_table, -+ .termios = sa1100_termios, -+ .termios_locked = sa1100_termios_locked, -+ .minor = MINOR_START, -+ .nr = NR_PORTS, -+ .cons = SA1100_CONSOLE, -+}; -+ -+static int __init sa1100_serial_init(void) -+{ -+ int i, ret; -+ -+ sa1100_init_ports(); -+ -+ ret = uart_register_driver(&sa1100_reg); -+ if (ret) -+ return ret; -+ -+ for (i = 0; i < NR_PORTS; i++) -+ uart_add_one_port(&sa1100_reg, &sa1100_ports[i].port); -+ -+ return 0; -+} -+ -+static void __exit sa1100_serial_exit(void) -+{ -+ int i; -+ -+ for (i = 0; i < NR_PORTS; i++) -+ uart_remove_one_port(&sa1100_reg, &sa1100_ports[i].port); -+ -+ uart_unregister_driver(&sa1100_reg); -+} -+ -+module_init(sa1100_serial_init); -+module_exit(sa1100_serial_exit); -+ -+EXPORT_NO_SYMBOLS; -+ -+MODULE_AUTHOR("Deep Blue Solutions Ltd"); -+MODULE_DESCRIPTION("SA1100 generic serial port driver"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.4.26/drivers/serial/uart00.c linux-2.4.26-vrs1/drivers/serial/uart00.c ---- linux-2.4.26/drivers/serial/uart00.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/serial/uart00.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,903 @@ -+/* -+ * linux/drivers/serial/uart00.c -+ * -+ * Driver for UART00 serial ports -+ * -+ * Based on drivers/char/serial_amba.c, by ARM Limited & -+ * Deep Blue Solutions Ltd. -+ * Copyright 2001 Altera Corporation -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * $Id: uart00.c,v 1.3.2.5 2002/10/24 09:53:26 rmk Exp $ -+ * -+ */ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#if defined(CONFIG_SERIAL_UART00_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -+#define SUPPORT_SYSRQ -+#endif -+ -+#include -+#include -+#define UART00_TYPE (volatile unsigned int*) -+#include -+#include -+ -+#undef DEBUG -+#define UART_NR 2 -+ -+#define SERIAL_UART00_NAME "ttyUA" -+#define SERIAL_UART00_MAJOR 204 -+#define SERIAL_UART00_MINOR 16 /* Temporary - will change in future */ -+#define SERIAL_UART00_NR UART_NR -+#define UART_PORT_SIZE 0x50 -+ -+#define CALLOUT_UART00_NAME "cuaua" -+#define CALLOUT_UART00_MAJOR 205 -+#define CALLOUT_UART00_MINOR 16 /* Temporary - will change in future */ -+#define CALLOUT_UART00_NR UART_NR -+ -+static struct tty_driver normal, callout; -+static struct tty_struct *uart00_table[UART_NR]; -+static struct termios *uart00_termios[UART_NR], *uart00_termios_locked[UART_NR]; -+static struct console uart00_console; -+static struct uart_driver uart00_reg; -+ -+ -+#define UART00_ISR_PASS_LIMIT 256 -+ -+/* -+ * Access macros for the UART00 UARTs -+ */ -+#define UART_GET_INT_STATUS(p) inl(UART_ISR((p)->membase)) -+#define UART_PUT_IES(p, c) outl(c,UART_IES((p)->membase)) -+#define UART_GET_IES(p) inl(UART_IES((p)->membase)) -+#define UART_PUT_IEC(p, c) outl(c,UART_IEC((p)->membase)) -+#define UART_GET_IEC(p) inl(UART_IEC((p)->membase)) -+#define UART_PUT_CHAR(p, c) outl(c,UART_TD((p)->membase)) -+#define UART_GET_CHAR(p) inl(UART_RD((p)->membase)) -+#define UART_GET_RSR(p) inl(UART_RSR((p)->membase)) -+#define UART_GET_RDS(p) inl(UART_RDS((p)->membase)) -+#define UART_GET_MSR(p) inl(UART_MSR((p)->membase)) -+#define UART_GET_MCR(p) inl(UART_MCR((p)->membase)) -+#define UART_PUT_MCR(p, c) outl(c,UART_MCR((p)->membase)) -+#define UART_GET_MC(p) inl(UART_MC((p)->membase)) -+#define UART_PUT_MC(p, c) outl(c,UART_MC((p)->membase)) -+#define UART_GET_TSR(p) inl(UART_TSR((p)->membase)) -+#define UART_GET_DIV_HI(p) inl(UART_DIV_HI((p)->membase)) -+#define UART_PUT_DIV_HI(p,c) outl(c,UART_DIV_HI((p)->membase)) -+#define UART_GET_DIV_LO(p) inl(UART_DIV_LO((p)->membase)) -+#define UART_PUT_DIV_LO(p,c) outl(c,UART_DIV_LO((p)->membase)) -+#define UART_RX_DATA(s) ((s) & UART_RSR_RX_LEVEL_MSK) -+#define UART_TX_READY(s) (((s) & UART_TSR_TX_LEVEL_MSK) < 15) -+//#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & UART00_UARTFR_TMSK) == 0) -+ -+static void uart00_stop_tx(struct uart_port *port, u_int from_tty) -+{ -+ -+ UART_PUT_IEC(port, UART_IEC_TIE_MSK); -+} -+ -+static void uart00_stop_rx(struct uart_port *port) -+{ -+ -+ UART_PUT_IEC(port, UART_IEC_RE_MSK); -+} -+ -+static void uart00_enable_ms(struct uart_port *port) -+{ -+ -+ UART_PUT_IES(port, UART_IES_ME_MSK); -+} -+ -+static void -+uart00_rx_chars(struct uart_port *port, struct pt_regs *regs) -+{ -+ struct uart_info *info = port->info; -+ struct tty_struct *tty = info->tty; -+ unsigned int status, ch, rds, flg, ignored = 0; -+ -+ -+ status = UART_GET_RSR(port); -+ while (UART_RX_DATA(status)) { -+ -+ /* -+ * We need to read rds before reading the -+ * character from the fifo -+ */ -+ rds = UART_GET_RDS(port); -+ ch = UART_GET_CHAR(port); -+ port->icount.rx++; -+ -+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) -+ goto ignore_char; -+ -+ flg = TTY_NORMAL; -+ -+ /* -+ * Note that the error handling code is -+ * out of the main execution path -+ */ -+ if (rds & (UART_RDS_BI_MSK |UART_RDS_FE_MSK|UART_RDS_PE_MSK)) -+ goto handle_error; -+ if (uart_handle_sysrq_char(port, ch, regs)) -+ goto ignore_char; -+ -+ error_return: -+ *tty->flip.flag_buf_ptr++ = flg; -+ *tty->flip.char_buf_ptr++ = ch; -+ tty->flip.count++; -+ ignore_char: -+ status = UART_GET_RSR(port); -+ } -+out: -+ tty_flip_buffer_push(tty); -+ return; -+ -+handle_error: -+ if (rds & UART_RDS_BI_MSK) { -+ status &= ~(UART_RDS_FE_MSK | UART_RDS_PE_MSK); -+ port->icount.brk++; -+ -+#ifdef SUPPORT_SYSRQ -+ if (uart_handle_break(port)) -+ goto ignore_char; -+#endif -+ } else if (rds & UART_RDS_PE_MSK) -+ port->icount.parity++; -+ else if (rds & UART_RDS_FE_MSK) -+ port->icount.frame++; -+ if (rds & UART_RDS_OE_MSK) -+ port->icount.overrun++; -+ -+ if (rds & port->ignore_status_mask) { -+ if (++ignored > 100) -+ goto out; -+ goto ignore_char; -+ } -+ rds &= port->read_status_mask; -+ -+ if (rds & UART_RDS_BI_MSK) -+ flg = TTY_BREAK; -+ else if (rds & UART_RDS_PE_MSK) -+ flg = TTY_PARITY; -+ else if (rds & UART_RDS_FE_MSK) -+ flg = TTY_FRAME; -+ -+ if (rds & UART_RDS_OE_MSK) { -+ /* -+ * CHECK: does overrun affect the current character? -+ * ASSUMPTION: it does not. -+ */ -+ *tty->flip.flag_buf_ptr++ = flg; -+ *tty->flip.char_buf_ptr++ = ch; -+ tty->flip.count++; -+ if (tty->flip.count >= TTY_FLIPBUF_SIZE) -+ goto ignore_char; -+ ch = 0; -+ flg = TTY_OVERRUN; -+ } -+#ifdef SUPPORT_SYSRQ -+ port->sysrq = 0; -+#endif -+ goto error_return; -+} -+ -+static void uart00_tx_chars(struct uart_port *port) -+{ -+ int count; -+ struct uart_info *info = port->info; -+ -+ if (port->x_char) { -+ while((UART_GET_TSR(port)& UART_TSR_TX_LEVEL_MSK)==15); -+ UART_PUT_CHAR(port, port->x_char); -+ port->icount.tx++; -+ port->x_char = 0; -+ -+ return; -+ } -+ if (info->xmit.head == info->xmit.tail -+ || info->tty->stopped -+ || info->tty->hw_stopped) { -+ uart00_stop_tx(port, 0); -+ return; -+ } -+ -+ count = port->fifosize >> 1; -+ do { -+ while((UART_GET_TSR(port)& UART_TSR_TX_LEVEL_MSK)==15); -+ UART_PUT_CHAR(port, info->xmit.buf[info->xmit.tail]); -+ info->xmit.tail = (info->xmit.tail + 1) & (UART_XMIT_SIZE - 1); -+ port->icount.tx++; -+ if (info->xmit.head == info->xmit.tail) -+ break; -+ } while (--count > 0); -+ -+ if (CIRC_CNT(info->xmit.head, -+ info->xmit.tail, -+ UART_XMIT_SIZE) < WAKEUP_CHARS) -+ uart_write_wakeup(port); -+ -+ if (info->xmit.head == info->xmit.tail) -+ uart00_stop_tx(port, 0); -+} -+ -+static void uart00_start_tx(struct uart_port *port, u_int from_tty) -+{ -+ UART_PUT_IES(port,UART_IES_TIE_MSK ); -+ uart00_tx_chars(port); -+} -+ -+static void uart00_modem_status(struct uart_port *port) -+{ -+ unsigned int status; -+ struct uart_icount *icount = &port->icount; -+ struct uart_info *info = port->info; -+ -+ status = UART_GET_MSR(port); -+ -+ if (!status & (UART_MSR_DCTS_MSK | UART_MSR_DDSR_MSK | -+ UART_MSR_TERI_MSK | UART_MSR_DDCD_MSK)) -+ return; -+ -+ if (status & UART_MSR_DDCD_MSK) { -+ icount->dcd++; -+#ifdef CONFIG_HARD_PPS -+ if ((port->flags & ASYNC_HARDPPS_CD) && -+ (status & UART_MSR_DCD_MSK)) -+ hardpps(); -+#endif -+ if (info->flags & ASYNC_CHECK_CD) { -+ if (status & UART_MSR_DCD_MSK) -+ wake_up_interruptible(&info->open_wait); -+ else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && -+ (port->flags & ASYNC_CALLOUT_NOHUP))) { -+ if (info->tty) -+ tty_hangup(info->tty); -+ } -+ } -+ } -+ -+ if (status & UART_MSR_DDSR_MSK) -+ icount->dsr++; -+ -+ if (status & UART_MSR_DCTS_MSK) { -+ icount->cts++; -+ -+ if (info->flags & ASYNC_CTS_FLOW) { -+ status &= UART_MSR_CTS_MSK; -+ -+ if (info->tty->hw_stopped) { -+ if (status) { -+ info->tty->hw_stopped = 0; -+ port->ops->start_tx(port, 0); -+ uart_write_wakeup(port); -+ } -+ } else { -+ if (!status) { -+ info->tty->hw_stopped = 1; -+ port->ops->stop_tx(port, 0); -+ } -+ } -+ } -+ } -+ wake_up_interruptible(&info->delta_msr_wait); -+ -+} -+ -+static void uart00_int(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ struct uart_port *port = dev_id; -+ unsigned int status, pass_counter = 0; -+ -+ status = UART_GET_INT_STATUS(port); -+ do { -+ -+ if (status & UART_ISR_RI_MSK) -+ uart00_rx_chars(port, regs); -+ if (status & (UART_ISR_TI_MSK | UART_ISR_TII_MSK)) -+ uart00_tx_chars(port); -+ if (status & UART_ISR_MI_MSK) -+ uart00_modem_status(port); -+ if (pass_counter++ > UART00_ISR_PASS_LIMIT) -+ break; -+ -+ status = UART_GET_INT_STATUS(port); -+ } while (status); -+} -+ -+static u_int uart00_tx_empty(struct uart_port *port) -+{ -+ return UART_GET_TSR(port) & UART_TSR_TX_LEVEL_MSK? 0 : TIOCSER_TEMT; -+} -+ -+static u_int uart00_get_mctrl(struct uart_port *port) -+{ -+ unsigned int result = 0; -+ unsigned int status; -+ -+ status = UART_GET_MSR(port); -+ if (status & UART_MSR_DCD_MSK) -+ result |= TIOCM_CAR; -+ if (status & UART_MSR_DSR_MSK) -+ result |= TIOCM_DSR; -+ if (status & UART_MSR_CTS_MSK) -+ result |= TIOCM_CTS; -+ if (status & UART_MCR_RI_MSK) -+ result |= TIOCM_RNG; -+ -+ return result; -+} -+ -+static void uart00_set_mctrl(struct uart_port *port, u_int mctrl) -+{ -+ unsigned char mcr = 0; -+ -+ if (mctrl & TIOCM_RTS) -+ mcr |= UART_MCR_RTS_MSK; -+ if (mctrl & TIOCM_DTR) -+ mcr |= UART_MCR_DTR_MSK; -+ if (mctrl & TIOCM_LOOP) -+ mcr |= UART_MCR_LB_MSK; -+ -+ UART_PUT_MCR(port, mcr); -+} -+ -+static void uart00_break_ctl(struct uart_port *port, int break_state) -+{ -+ unsigned int mcr; -+ -+ mcr = UART_GET_MCR(port); -+ if (break_state == -1) -+ mcr |= UART_MCR_BR_MSK; -+ else -+ mcr &= ~UART_MCR_BR_MSK; -+ UART_PUT_MCR(port, mcr); -+} -+ -+static inline u_int uart_calculate_quot(struct uart_port *port, u_int baud) -+{ -+ u_int quot; -+ -+ /* Special case: B0 rate */ -+ if (!baud) -+ baud = 9600; -+ -+ quot = (port->uartclk / (16 * baud)-1) ; -+ -+ return quot; -+} -+static void uart00_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot) -+{ -+ u_int uart_mc=0, old_ies; -+ unsigned long flags; -+ -+#ifdef DEBUG -+ printk("uart00_set_cflag(0x%x) called\n", cflag); -+#endif -+ /* byte size and parity */ -+ switch (cflag & CSIZE) { -+ case CS5: uart_mc = UART_MC_CLS_CHARLEN_5; break; -+ case CS6: uart_mc = UART_MC_CLS_CHARLEN_6; break; -+ case CS7: uart_mc = UART_MC_CLS_CHARLEN_7; break; -+ default: uart_mc = UART_MC_CLS_CHARLEN_8; break; // CS8 -+ } -+ if (cflag & CSTOPB) -+ uart_mc|= UART_MC_ST_TWO; -+ if (cflag & PARENB) { -+ uart_mc |= UART_MC_PE_MSK; -+ if (!(cflag & PARODD)) -+ uart_mc |= UART_MC_EP_MSK; -+ } -+ -+ port->read_status_mask = UART_RDS_OE_MSK; -+ if (iflag & INPCK) -+ port->read_status_mask |= UART_RDS_FE_MSK | UART_RDS_PE_MSK; -+ if (iflag & (BRKINT | PARMRK)) -+ port->read_status_mask |= UART_RDS_BI_MSK; -+ -+ /* -+ * Characters to ignore -+ */ -+ port->ignore_status_mask = 0; -+ if (iflag & IGNPAR) -+ port->ignore_status_mask |= UART_RDS_FE_MSK | UART_RDS_PE_MSK; -+ if (iflag & IGNBRK) { -+ port->ignore_status_mask |= UART_RDS_BI_MSK; -+ /* -+ * If we're ignoring parity and break indicators, -+ * ignore overruns to (for real raw support). -+ */ -+ if (iflag & IGNPAR) -+ port->ignore_status_mask |= UART_RDS_OE_MSK; -+ } -+ -+ /* first, disable everything */ -+ save_flags(flags); cli(); -+ old_ies = UART_GET_IES(port); -+ -+ if ((port->flags & ASYNC_HARDPPS_CD) || -+ (cflag & CRTSCTS) || !(cflag & CLOCAL)) -+ old_ies |= UART_IES_ME_MSK; -+ -+ -+ /* Set baud rate */ -+ UART_PUT_DIV_LO(port, (quot & 0xff)); -+ UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8)); -+ -+ -+ UART_PUT_MC(port, uart_mc); -+ UART_PUT_IES(port, old_ies); -+ -+ restore_flags(flags); -+} -+ -+static int uart00_startup(struct uart_port *port) -+{ -+ int retval; -+ -+ /* -+ * Allocate the IRQ -+ */ -+ retval = request_irq(port->irq, uart00_int, 0, "uart00", port); -+ if (retval) -+ return retval; -+ -+ /* -+ * Finally, enable interrupts. Use the TII interrupt to minimise -+ * the number of interrupts generated. If higher performance is -+ * needed, consider using the TI interrupt with a suitable FIFO -+ * threshold -+ */ -+ UART_PUT_IES(port, UART_IES_RE_MSK | UART_IES_TIE_MSK); -+ -+ return 0; -+} -+ -+static void uart00_shutdown(struct uart_port *port) -+{ -+ /* -+ * disable all interrupts, disable the port -+ */ -+ UART_PUT_IEC(port, 0xff); -+ -+ /* disable break condition and fifos */ -+ UART_PUT_MCR(port, UART_GET_MCR(port) &~UART_MCR_BR_MSK); -+ -+ /* -+ * Free the interrupt -+ */ -+ free_irq(port->irq, port); -+} -+ -+static const char *uart00_type(struct uart_port *port) -+{ -+ return port->type == PORT_UART00 ? "Altera UART00" : NULL; -+} -+ -+/* -+ * Release the memory region(s) being used by 'port' -+ */ -+static void uart00_release_port(struct uart_port *port) -+{ -+ release_mem_region(port->mapbase, UART_PORT_SIZE); -+ -+#ifdef CONFIG_ARCH_CAMELOT -+ if(port->membase!=(void*)IO_ADDRESS(EXC_UART00_BASE)){ -+ iounmap(port->membase); -+ } -+#endif -+} -+ -+/* -+ * Request the memory region(s) being used by 'port' -+ */ -+static int uart00_request_port(struct uart_port *port) -+{ -+ int result; -+ -+ result = request_mem_region(port->mapbase, UART_PORT_SIZE, -+ "serial_uart00") != NULL ? 0 : -EBUSY; -+ if (result) -+ return result; -+ -+ port->membase = ioremap(port->mapbase, SZ_4K); -+ if (!port->membase) { -+ printk(KERN_ERR "serial00: cannot map io memory\n"); -+ release_mem_region(port->mapbase, UART_PORT_SIZE); -+ } -+ -+ return port->membase ? 0 : -ENOMEM; -+} -+ -+/* -+ * Configure/autoconfigure the port. -+ */ -+static void uart00_config_port(struct uart_port *port, int flags) -+{ -+ if (flags & UART_CONFIG_TYPE) { -+ if (uart00_request_port(port) == 0) -+ port->type = PORT_UART00; -+ } -+} -+ -+/* -+ * verify the new serial_struct (for TIOCSSERIAL). -+ */ -+static int uart00_verify_port(struct uart_port *port, struct serial_struct *ser) -+{ -+ int ret = 0; -+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_UART00) -+ ret = -EINVAL; -+ if (ser->irq < 0 || ser->irq >= NR_IRQS) -+ ret = -EINVAL; -+ if (ser->baud_base < 9600) -+ ret = -EINVAL; -+ return ret; -+} -+ -+static struct uart_ops uart00_pops = { -+ tx_empty: uart00_tx_empty, -+ set_mctrl: uart00_set_mctrl, -+ get_mctrl: uart00_get_mctrl, -+ stop_tx: uart00_stop_tx, -+ start_tx: uart00_start_tx, -+ stop_rx: uart00_stop_rx, -+ enable_ms: uart00_enable_ms, -+ break_ctl: uart00_break_ctl, -+ startup: uart00_startup, -+ shutdown: uart00_shutdown, -+ change_speed: uart00_change_speed, -+ type: uart00_type, -+ release_port: uart00_release_port, -+ request_port: uart00_request_port, -+ config_port: uart00_config_port, -+ verify_port: uart00_verify_port, -+}; -+ -+static struct uart_port uart00_ports[UART_NR] = { -+ -+#ifdef CONFIG_ARCH_CAMELOT -+{ -+ .membase = (void*)IO_ADDRESS(EXC_UART00_BASE), -+ .mapbase = EXC_UART00_BASE, -+ .iotype = SERIAL_IO_MEM, -+ .irq = IRQ_UART, -+ .uartclk = EXC_AHB2_CLK_FREQUENCY, -+ .fifosize = 16, -+ .ops = &uart00_pops, -+ .flags = ASYNC_BOOT_AUTOCONF, -+} -+#endif -+}; -+ -+#ifdef CONFIG_SERIAL_UART00_CONSOLE -+static void uart00_console_write(struct console *co, const char *s, unsigned count) -+{ -+#ifdef CONFIG_ARCH_CAMELOT -+ struct uart_port *port = &uart00_ports[0]; -+ unsigned int status, old_ies; -+ int i; -+ -+ /* -+ * First save the CR then disable the interrupts -+ */ -+ old_ies = UART_GET_IES(port); -+ UART_PUT_IEC(port,0xff); -+ -+ /* -+ * Now, do each character -+ */ -+ for (i = 0; i < count; i++) { -+ do { -+ status = UART_GET_TSR(port); -+ } while (!UART_TX_READY(status)); -+ UART_PUT_CHAR(port, s[i]); -+ if (s[i] == '\n') { -+ do { -+ status = UART_GET_TSR(port); -+ } while (!UART_TX_READY(status)); -+ UART_PUT_CHAR(port, '\r'); -+ } -+ } -+ -+ /* -+ * Finally, wait for transmitter to become empty -+ * and restore the IES -+ */ -+ do { -+ status = UART_GET_TSR(port); -+ } while (status & UART_TSR_TX_LEVEL_MSK); -+ UART_PUT_IES(port, old_ies); -+#endif -+} -+ -+static kdev_t uart00_console_device(struct console *co) -+{ -+ return MKDEV(SERIAL_UART00_MAJOR, SERIAL_UART00_MINOR + co->index); -+} -+ -+static void /*__init*/ uart00_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) -+{ -+ u_int uart_mc, quot; -+ uart_mc= UART_GET_MC(port); -+ -+ *parity = 'n'; -+ if (uart_mc & UART_MC_PE_MSK) { -+ if (uart_mc & UART_MC_EP_MSK) -+ *parity = 'e'; -+ else -+ *parity = 'o'; -+ } -+ -+ switch (uart_mc & UART_MC_CLS_MSK){ -+ -+ case UART_MC_CLS_CHARLEN_5: -+ *bits = 5; -+ break; -+ case UART_MC_CLS_CHARLEN_6: -+ *bits = 6; -+ break; -+ case UART_MC_CLS_CHARLEN_7: -+ *bits = 7; -+ break; -+ case UART_MC_CLS_CHARLEN_8: -+ *bits = 8; -+ break; -+ } -+ quot = UART_GET_DIV_LO(port) | (UART_GET_DIV_HI(port) << 8); -+ *baud = port->uartclk / (16 *quot ); -+} -+ -+static int __init uart00_console_setup(struct console *co, char *options) -+{ -+ struct uart_port *port; -+ int baud = 38400; -+ int bits = 8; -+ int parity = 'n'; -+ int flow= 'n'; -+ -+#ifdef CONFIG_ARCH_CAMELOT -+ /* -+ * Check whether an invalid uart number has been specified, and -+ * if so, search for the first available port that does have -+ * console support. -+ */ -+ port = &uart00_ports[0]; -+ co->index = 0; -+#else -+ return -ENODEV; -+#endif -+ -+ if (options) -+ uart_parse_options(options, &baud, &parity, &bits, &flow); -+ else -+ uart00_console_get_options(port, &baud, &parity, &bits); -+ -+ return uart_set_options(port, co, baud, parity, bits, flow); -+} -+ -+static struct console uart00_console = { -+ .name = SERIAL_UART00_NAME, -+ .write = uart00_console_write, -+ .device = uart00_console_device, -+ .setup = uart00_console_setup, -+ .flags = CON_PRINTBUFFER, -+ .index = 0, -+}; -+ -+void __init uart00_console_init(void) -+{ -+ register_console(&uart00_console); -+} -+ -+#define UART00_CONSOLE &uart00_console -+#else -+#define UART00_CONSOLE NULL -+#endif -+ -+static struct uart_driver uart00_reg = { -+ .owner = NULL, -+ .normal_major = SERIAL_UART00_MAJOR, -+ .normal_name = SERIAL_UART00_NAME, -+ .normal_driver = &normal, -+ .callout_major = CALLOUT_UART00_MAJOR, -+ .callout_name = CALLOUT_UART00_NAME, -+ .callout_driver = &callout, -+ .table = uart00_table, -+ .termios = uart00_termios, -+ .termios_locked = uart00_termios_locked, -+ .minor = SERIAL_UART00_MINOR, -+ .nr = UART_NR, -+ .state = NULL, -+ .cons = UART00_CONSOLE, -+}; -+ -+struct dev_port_entry{ -+ struct uart_port *port; -+}; -+ -+static struct dev_port_entry dev_port_map[UART_NR]; -+ -+#ifdef CONFIG_PLD_HOTSWAP -+/* -+ * Keep a mapping of dev_info addresses -> port lines to use when -+ * removing ports dev==NULL indicates unused entry -+ */ -+ -+struct uart00_ps_data{ -+ unsigned int clk; -+ unsigned int fifosize; -+}; -+ -+int uart00_add_device(struct pldhs_dev_info* dev_info, void* dev_ps_data) -+{ -+ struct uart00_ps_data* dev_ps=dev_ps_data; -+ struct uart_port * port; -+ int i,result; -+ -+ i=0; -+ while(dev_port_map[i].port) -+ i++; -+ -+ if(i==UART_NR){ -+ printk(KERN_WARNING "uart00: Maximum number of ports reached\n"); -+ return 0; -+ } -+ -+ port=&uart00_ports[i]; -+ -+ printk("clk=%d fifo=%d\n",dev_ps->clk,dev_ps->fifosize); -+ port->membase=0; -+ port->mapbase=dev_info->base_addr; -+ port->iotype=SERIAL_IO_MEM; -+ port->irq=dev_info->irq; -+ port->uartclk=dev_ps->clk; -+ port->fifosize=dev_ps->fifosize; -+ port->ops=&uart00_pops; -+ port->line=i; -+ port->flags=ASYNC_BOOT_AUTOCONF; -+ -+ result=uart_register_port(&uart00_reg, port); -+ if(result<0){ -+ printk("uart_register_port returned %d\n",result); -+ return result; -+ } -+ dev_port_map[i].port=port; -+ printk("uart00: added device at %lx as ttyUA%d\n",dev_port_map[i].port->mapbase,i); -+ return 0; -+ -+} -+ -+int uart00_remove_devices(void) -+{ -+ int i,result; -+ -+ -+ result=0; -+ for(i=1;iuartclk,port->fifosize); -+ len+=PLDHS_READ_PROC_DATA(buf+len,"uart00",i, -+ port->mapbase,port->irq,ps_data); -+ -+ } -+ } -+ *eof=1; -+ return len; -+} -+ -+ -+ -+#endif -+struct pld_hotswap_ops uart00_pldhs_ops={ -+ .name = "uart00", -+ .add_device = uart00_add_device, -+ .remove_devices = uart00_remove_devices, -+ .proc_read = uart00_proc_read -+}; -+ -+#endif -+ -+static int __init uart00_init(void) -+{ -+ int ret; -+ int i; -+ -+ ret = uart_register_driver(&uart00_reg); -+ if (ret) { -+ printk(KERN_ERR "uart00: Couldn't register driver\n"); -+ return ret; -+ } -+ -+ unregister_console(&uart00_console); -+ -+ for(i=0;i -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License. -+ * -+ * This is the machine specific part of the Assabet/UDA1341 support. -+ * This driver makes use of the UDA1341 and the sa1100-audio modules. -+ * -+ * History: -+ * -+ * 2000-05-21 Nicolas Pitre Initial release. -+ * -+ * 2001-06-03 Nicolas Pitre Made this file a separate module, based on -+ * the former sa1100-uda1341.c driver. -+ * -+ * 2001-07-17 Nicolas Pitre Supports 44100Hz and 22050Hz samplerate now. -+ * -+ * 2001-08-03 Russell King Fix left/right channel swap. -+ * Attempt to reduce power consumption when idle. -+ * -+ * 2001-09-23 Russell King Remove old L3 bus driver. -+ * -+ * Please note that fiddling too much with MDREFR results in oopses, so we don't -+ * touch MDREFR unnecessarily, which means we don't touch it on close. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "sa1100-audio.h" -+ -+/* -+ * Define this to fix the power drain on early Assabets -+ */ -+#define FIX_POWER_DRAIN -+ -+/* -+ * Debugging? -+ */ -+#undef DEBUG -+ -+ -+#ifdef DEBUG -+#define DPRINTK( x... ) printk( ##x ) -+#else -+#define DPRINTK( x... ) -+#endif -+ -+ -+#define AUDIO_RATE_DEFAULT 44100 -+ -+/* -+ * Mixer (UDA1341) interface -+ */ -+ -+static struct l3_client uda1341; -+ -+static int -+mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) -+{ -+ /* -+ * We only accept mixer (type 'M') ioctls. -+ */ -+ if (_IOC_TYPE(cmd) != 'M') -+ return -EINVAL; -+ -+ return l3_command(&uda1341, cmd, (void *)arg); -+} -+ -+static struct file_operations assabet_mixer_fops = { -+ ioctl: mixer_ioctl, -+ owner: THIS_MODULE -+}; -+ -+ -+/* -+ * Audio interface -+ */ -+static long audio_samplerate = AUDIO_RATE_DEFAULT; -+ -+/* -+ * FIXME: what about SFRM going high when SSP is disabled? -+ */ -+static void assabet_set_samplerate(long val) -+{ -+ struct uda1341_cfg cfg; -+ u_int clk_ref, clk_div; -+ -+ /* We don't want to mess with clocks when frames are in flight */ -+ Ser4SSCR0 &= ~SSCR0_SSE; -+ /* wait for any frame to complete */ -+ udelay(125); -+ -+ /* -+ * Our clock source is derived from the CPLD on which we don't have -+ * much control unfortunately. This was intended for a fixed 48000 Hz -+ * samplerate assuming a core clock of 221.2 MHz. The CPLD appears -+ * to divide the memory clock so there is a ratio of 4608 between -+ * the core clock and the resulting samplerate (obtained by -+ * measurements, the CPLD equations should confirm that). -+ * -+ * Still we can play with the SA1110's clock divisor for the SSP port -+ * to get half the samplerate as well. -+ * -+ * Apparently the clock sent to the SA1110 for the SSP port is further -+ * more divided from the clock sent to the UDA1341 (some people tried -+ * to be too clever in their design, or simply failed to read the -+ * SA1110 manual). If it was the same clock we would have been able -+ * to support a third samplerate with the UDA1341's 384FS mode. -+ * -+ * At least it would have been a minimum acceptable solution to be -+ * able to set the CPLD divisor by software. The iPAQ design is -+ * certainly a better example to follow for a new design. -+ */ -+ clk_ref = cpufreq_get(0) * 1000 / 4608; -+ if (val > clk_ref*4/7) { -+ audio_samplerate = clk_ref; -+ cfg.fs = 256; -+ clk_div = SSCR0_SerClkDiv(2); -+ } else { -+ audio_samplerate = clk_ref/2; -+ cfg.fs = 512; -+ clk_div = SSCR0_SerClkDiv(4); -+ } -+ -+ cfg.format = FMT_LSB16; -+ l3_command(&uda1341, L3_UDA1341_CONFIGURE, &cfg); -+ -+ Ser4SSCR0 = (Ser4SSCR0 & ~0xff00) + clk_div + SSCR0_SSE; -+} -+ -+/* -+ * Initialise the Assabet audio driver. -+ * -+ * Note that we have to be careful with the order that we do things here; -+ * there is a D-type flip flop which is clocked from the SFRM line which -+ * indicates whether the same is for the left or right channel to the -+ * UDA1341. -+ * -+ * When you disable the SSP (by clearing SSCR0_SSE) it appears that the -+ * SFRM signal can float high. When you re-enable the SSP, you clock the -+ * flip flop once, and end up swapping the left and right channels. -+ * -+ * The ASSABET_BCR_CODEC_RST line will force this flip flop into a known -+ * state, but this line resets other devices as well! -+ * -+ * In addition to the above, it appears that powering down the UDA1341 on -+ * early Assabets leaves the UDA_WS actively driving a logic '1' into the -+ * chip, wasting power! (you can tell this by D11 being half-on). We -+ * attempt to correct this by kicking the flip flop on init/open/close. -+ * We should probably do this on PM resume as well. -+ * -+ * (Note the ordering of ASSABET_BCR_AUDIO_ON, SFRM and ASSABET_BCR_CODEC_RST -+ * is important). -+ */ -+static void assabet_audio_init(void *dummy) -+{ -+ unsigned long flags; -+ unsigned int mdrefr; -+ -+ local_irq_save(flags); -+ -+ /* -+ * Enable the power for the UDA1341 before driving any signals. -+ * We leave the audio amp (LM4880) disabled for now. -+ */ -+ ASSABET_BCR_set(ASSABET_BCR_AUDIO_ON); -+ -+#ifdef FIX_POWER_DRAIN -+ GPSR = GPIO_SSP_SFRM; -+ GPCR = GPIO_SSP_SFRM; -+#endif -+ -+ ASSABET_BCR_set(ASSABET_BCR_CODEC_RST); -+ ASSABET_BCR_clear(ASSABET_BCR_STEREO_LB); -+ -+ /* -+ * Setup the SSP uart. -+ */ -+ PPAR |= PPAR_SPR; -+ Ser4SSCR0 = SSCR0_DataSize(16) + SSCR0_TI + SSCR0_SerClkDiv(2); -+ Ser4SSCR1 = SSCR1_SClkIactL + SSCR1_SClk1P + SSCR1_ExtClk; -+ GAFR |= GPIO_SSP_TXD | GPIO_SSP_RXD | GPIO_SSP_SCLK | GPIO_SSP_CLK; -+ GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM; -+ GPDR &= ~(GPIO_SSP_RXD | GPIO_SSP_CLK); -+ Ser4SSCR0 |= SSCR0_SSE; -+ -+ /* -+ * Only give SFRM to the SSP after it has been enabled. -+ */ -+ GAFR |= GPIO_SSP_SFRM; -+ -+ /* -+ * The assabet board uses the SDRAM clock as the source clock for -+ * audio. This is supplied to the SA11x0 from the CPLD on pin 19. -+ * At 206MHz we need to run the audio clock (SDRAM bank 2) -+ * at half speed. This clock will scale with core frequency so -+ * the audio sample rate will also scale. The CPLD on Assabet -+ * will need to be programmed to match the core frequency. -+ */ -+ mdrefr = MDREFR; -+ if ((mdrefr & (MDREFR_K2DB2 | MDREFR_K2RUN | MDREFR_EAPD | -+ MDREFR_KAPD)) != (MDREFR_K2DB2 | MDREFR_K2RUN)) { -+ mdrefr |= MDREFR_K2DB2 | MDREFR_K2RUN; -+ mdrefr &= ~(MDREFR_EAPD | MDREFR_KAPD); -+ MDREFR = mdrefr; -+ (void) MDREFR; -+ } -+ local_irq_restore(flags); -+ -+ /* Wait for the UDA1341 to wake up */ -+ mdelay(1); -+ -+ l3_open(&uda1341); -+ -+ assabet_set_samplerate(audio_samplerate); -+ -+ /* Enable the audio power */ -+ ASSABET_BCR_clear(ASSABET_BCR_QMUTE | ASSABET_BCR_SPK_OFF); -+} -+ -+/* -+ * Shutdown the Assabet audio driver. -+ * -+ * We have to be careful about the SFRM line here for the same reasons -+ * described in the initialisation comments above. This basically means -+ * that we must hand the SSP pins back to the GPIO module before disabling -+ * the SSP. -+ * -+ * In addition, to reduce power drain, we toggle the SFRM line once so -+ * that the UDA_WS line is at logic 0. -+ * -+ * We can't clear ASSABET_BCR_CODEC_RST without knowing if the UCB1300 or -+ * ADV7171 driver is still active. If it is, then we still need to play -+ * games, so we might as well leave ASSABET_BCR_CODEC_RST set. -+ */ -+static void assabet_audio_shutdown(void *dummy) -+{ -+ ASSABET_BCR_set(ASSABET_BCR_STEREO_LB | ASSABET_BCR_QMUTE | -+ ASSABET_BCR_SPK_OFF); -+ -+ l3_close(&uda1341); -+ -+ GAFR &= ~(GPIO_SSP_TXD | GPIO_SSP_RXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM); -+ Ser4SSCR0 = 0; -+ -+#ifdef FIX_POWER_DRAIN -+ GPSR = GPIO_SSP_SFRM; -+ GPCR = GPIO_SSP_SFRM; -+#endif -+ -+ /* disable the audio power */ -+ ASSABET_BCR_clear(ASSABET_BCR_AUDIO_ON); -+} -+ -+static int assabet_audio_ioctl( struct inode *inode, struct file *file, -+ uint cmd, ulong arg) -+{ -+ long val; -+ int ret = 0; -+ -+ /* -+ * These are platform dependent ioctls which are not handled by the -+ * generic sa1100-audio module. -+ */ -+ switch (cmd) { -+ case SNDCTL_DSP_STEREO: -+ ret = get_user(val, (int *) arg); -+ if (ret) -+ return ret; -+ /* the UDA1341 is stereo only */ -+ ret = (val == 0) ? -EINVAL : 1; -+ return put_user(ret, (int *) arg); -+ -+ case SNDCTL_DSP_CHANNELS: -+ case SOUND_PCM_READ_CHANNELS: -+ /* the UDA1341 is stereo only */ -+ return put_user(2, (long *) arg); -+ -+ case SNDCTL_DSP_SPEED: -+ ret = get_user(val, (long *) arg); -+ if (ret) break; -+ assabet_set_samplerate(val); -+ /* fall through */ -+ -+ case SOUND_PCM_READ_RATE: -+ return put_user(audio_samplerate, (long *) arg); -+ -+ case SNDCTL_DSP_SETFMT: -+ case SNDCTL_DSP_GETFMTS: -+ /* we can do signed 16-bit only */ -+ return put_user(AFMT_S16_LE, (long *) arg); -+ -+ default: -+ /* Maybe this is meant for the mixer (As per OSS Docs) */ -+ return mixer_ioctl(inode, file, cmd, arg); -+ } -+ -+ return ret; -+} -+ -+static audio_stream_t output_stream, input_stream; -+ -+static audio_state_t audio_state = { -+ output_stream: &output_stream, -+ output_dma: DMA_Ser4SSPWr, -+ output_id: "Assabet UDA1341 out", -+ input_stream: &input_stream, -+ input_dma: DMA_Ser4SSPRd, -+ input_id: "Assabet UDA1341 in", -+ need_tx_for_rx: 1, -+ hw_init: assabet_audio_init, -+ hw_shutdown: assabet_audio_shutdown, -+ client_ioctl: assabet_audio_ioctl, -+ sem: __MUTEX_INITIALIZER(audio_state.sem), -+}; -+ -+static int assabet_audio_open(struct inode *inode, struct file *file) -+{ -+ return sa1100_audio_attach(inode, file, &audio_state); -+} -+ -+/* -+ * Missing fields of this structure will be patched with the call -+ * to sa1100_audio_attach(). -+ */ -+static struct file_operations assabet_audio_fops = { -+ open: assabet_audio_open, -+ owner: THIS_MODULE -+}; -+ -+ -+static int audio_dev_id, mixer_dev_id; -+ -+static int __init assabet_uda1341_init(void) -+{ -+ int ret; -+ -+ if (!machine_is_assabet()) -+ return -ENODEV; -+ -+ ret = l3_attach_client(&uda1341, "l3-bit-sa1100-gpio", "uda1341"); -+ if (ret) -+ goto out; -+ -+ /* register devices */ -+ audio_dev_id = register_sound_dsp(&assabet_audio_fops, -1); -+ mixer_dev_id = register_sound_mixer(&assabet_mixer_fops, -1); -+ -+#ifdef FIX_POWER_DRAIN -+ { -+ unsigned long flags; -+ local_irq_save(flags); -+ ASSABET_BCR_set(ASSABET_BCR_CODEC_RST); -+ GPSR = GPIO_SSP_SFRM; -+ GPDR |= GPIO_SSP_SFRM; -+ GPCR = GPIO_SSP_SFRM; -+ local_irq_restore(flags); -+ } -+#endif -+ -+ printk(KERN_INFO "Sound: Assabet UDA1341: dsp id %d mixer id %d\n", -+ audio_dev_id, mixer_dev_id); -+ return 0; -+ -+release_l3: -+ l3_detach_client(&uda1341); -+out: -+ return ret; -+} -+ -+static void __exit assabet_uda1341_exit(void) -+{ -+ unregister_sound_dsp(audio_dev_id); -+ unregister_sound_mixer(mixer_dev_id); -+ l3_detach_client(&uda1341); -+} -+ -+module_init(assabet_uda1341_init); -+module_exit(assabet_uda1341_exit); -+ -+MODULE_AUTHOR("Nicolas Pitre"); -+MODULE_DESCRIPTION("Glue audio driver for the SA1110 Assabet board & Philips UDA1341 codec."); -+ -+EXPORT_NO_SYMBOLS; -diff -urN linux-2.4.26/drivers/sound/h3600-uda1341.c linux-2.4.26-vrs1/drivers/sound/h3600-uda1341.c ---- linux-2.4.26/drivers/sound/h3600-uda1341.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/sound/h3600-uda1341.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,352 @@ -+/* -+ * Glue audio driver for the Compaq iPAQ H3600 & Philips UDA1341 codec. -+ * -+ * Copyright (c) 2000 Nicolas Pitre -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License. -+ * -+ * This is the machine specific part of the Compaq iPAQ (aka Bitsy) support. -+ * This driver makes use of the UDA1341 and the sa1100-audio modules. -+ * -+ * History: -+ * -+ * 2000-05-21 Nicolas Pitre Initial UDA1341 driver release. -+ * -+ * 2000-07-?? George France Bitsy support. -+ * -+ * 2000-12-13 Deborah Wallach Fixed power handling for iPAQ/h3600 -+ * -+ * 2001-06-03 Nicolas Pitre Made this file a separate module, based on -+ * the former sa1100-uda1341.c driver. -+ * -+ * 2001-07-13 Nicolas Pitre Fixes for all supported samplerates. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+//#include -+ -+#include "sa1100-audio.h" -+ -+ -+#undef DEBUG -+#ifdef DEBUG -+#define DPRINTK( x... ) printk( ##x ) -+#else -+#define DPRINTK( x... ) -+#endif -+ -+ -+#define AUDIO_NAME "Bitsy_UDA1341" -+ -+#define AUDIO_RATE_DEFAULT 44100 -+ -+ -+static struct l3_client uda1341; -+ -+static int -+mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) -+{ -+ /* -+ * We only accept mixer (type 'M') ioctls. -+ */ -+ if (_IOC_TYPE(cmd) != 'M') -+ return -EINVAL; -+ -+ return l3_command(&uda1341, cmd, (void *)arg); -+} -+ -+static struct file_operations h3600_mixer_fops = { -+ ioctl: mixer_ioctl, -+ owner: THIS_MODULE -+}; -+ -+ -+/* -+ * Audio interface -+ */ -+ -+static long audio_samplerate = AUDIO_RATE_DEFAULT; -+ -+/* -+ * Stop-gap solution until rest of hh.org HAL stuff is merged. -+ */ -+#define GPIO_H3600_CLK_SET0 GPIO_GPIO (12) -+#define GPIO_H3600_CLK_SET1 GPIO_GPIO (13) -+static void h3600_set_audio_clock(long val) -+{ -+ switch (val) { -+ case 24000: case 32000: case 48000: /* 00: 12.288 MHz */ -+ GPCR = GPIO_H3600_CLK_SET0 | GPIO_H3600_CLK_SET1; -+ break; -+ -+ case 22050: case 29400: case 44100: /* 01: 11.2896 MHz */ -+ GPSR = GPIO_H3600_CLK_SET0; -+ GPCR = GPIO_H3600_CLK_SET1; -+ break; -+ -+ case 8000: case 10666: case 16000: /* 10: 4.096 MHz */ -+ GPCR = GPIO_H3600_CLK_SET0; -+ GPSR = GPIO_H3600_CLK_SET1; -+ break; -+ -+ case 10985: case 14647: case 21970: /* 11: 5.6245 MHz */ -+ GPSR = GPIO_H3600_CLK_SET0 | GPIO_H3600_CLK_SET1; -+ break; -+ } -+} -+ -+static void h3600_set_samplerate(long val) -+{ -+ struct uda1341_cfg cfg; -+ int clk_div = 0; -+ -+ /* We don't want to mess with clocks when frames are in flight */ -+ Ser4SSCR0 &= ~SSCR0_SSE; -+ /* wait for any frame to complete */ -+ udelay(125); -+ -+ /* -+ * We have the following clock sources: -+ * 4.096 MHz, 5.6245 MHz, 11.2896 MHz, 12.288 MHz -+ * Those can be divided either by 256, 384 or 512. -+ * This makes up 12 combinations for the following samplerates... -+ */ -+ if (val >= 48000) -+ val = 48000; -+ else if (val >= 44100) -+ val = 44100; -+ else if (val >= 32000) -+ val = 32000; -+ else if (val >= 29400) -+ val = 29400; -+ else if (val >= 24000) -+ val = 24000; -+ else if (val >= 22050) -+ val = 22050; -+ else if (val >= 21970) -+ val = 21970; -+ else if (val >= 16000) -+ val = 16000; -+ else if (val >= 14647) -+ val = 14647; -+ else if (val >= 10985) -+ val = 10985; -+ else if (val >= 10666) -+ val = 10666; -+ else -+ val = 8000; -+ -+ /* Set the external clock generator */ -+ h3600_set_audio_clock(val); -+ -+ /* Select the clock divisor */ -+ switch (val) { -+ case 8000: -+ case 10985: -+ case 22050: -+ case 24000: -+ cfg.fs = 512; -+ clk_div = SSCR0_SerClkDiv(16); -+ break; -+ case 16000: -+ case 21970: -+ case 44100: -+ case 48000: -+ cfg.fs = 256; -+ clk_div = SSCR0_SerClkDiv(8); -+ break; -+ case 10666: -+ case 14647: -+ case 29400: -+ case 32000: -+ cfg.fs = 384; -+ clk_div = SSCR0_SerClkDiv(12); -+ break; -+ } -+ -+ cfg.format = FMT_LSB16; -+ l3_command(&uda1341, L3_UDA1341_CONFIGURE, &cfg); -+ Ser4SSCR0 = (Ser4SSCR0 & ~0xff00) + clk_div + SSCR0_SSE; -+ audio_samplerate = val; -+} -+ -+static void h3600_audio_init(void *dummy) -+{ -+ unsigned long flags; -+ -+ /* Setup the uarts */ -+ local_irq_save(flags); -+ GAFR |= (GPIO_SSP_CLK); -+ GPDR &= ~(GPIO_SSP_CLK); -+ Ser4SSCR0 = 0; -+ Ser4SSCR0 = SSCR0_DataSize(16) + SSCR0_TI + SSCR0_SerClkDiv(8); -+ Ser4SSCR1 = SSCR1_SClkIactL + SSCR1_SClk1P + SSCR1_ExtClk; -+ Ser4SSCR0 |= SSCR0_SSE; -+ -+ /* Enable the audio power */ -+ -+ clr_h3600_egpio(IPAQ_EGPIO_CODEC_NRESET); -+ set_h3600_egpio(IPAQ_EGPIO_AUDIO_ON); -+ set_h3600_egpio(IPAQ_EGPIO_QMUTE); -+ local_irq_restore(flags); -+ -+ /* external clock configuration */ -+ h3600_set_samplerate(audio_samplerate); -+ -+ /* Wait for the UDA1341 to wake up */ -+ set_h3600_egpio(IPAQ_EGPIO_CODEC_NRESET); -+ mdelay(1); -+ -+ /* make the left and right channels unswapped (flip the WS latch ) */ -+ Ser4SSDR = 0; -+ -+ /* Initialize the UDA1341 internal state */ -+ l3_open(&uda1341); -+ -+ clr_h3600_egpio(IPAQ_EGPIO_QMUTE); -+} -+ -+static void h3600_audio_shutdown(void *dummy) -+{ -+ /* disable the audio power and all signals leading to the audio chip */ -+ l3_close(&uda1341); -+ Ser4SSCR0 = 0; -+ clr_h3600_egpio(IPAQ_EGPIO_CODEC_NRESET); -+ clr_h3600_egpio(IPAQ_EGPIO_AUDIO_ON); -+ clr_h3600_egpio(IPAQ_EGPIO_QMUTE); -+} -+ -+static int h3600_audio_ioctl(struct inode *inode, struct file *file, -+ uint cmd, ulong arg) -+{ -+ long val; -+ int ret = 0; -+ -+ /* -+ * These are platform dependent ioctls which are not handled by the -+ * generic sa1100-audio module. -+ */ -+ switch (cmd) { -+ case SNDCTL_DSP_STEREO: -+ ret = get_user(val, (int *) arg); -+ if (ret) -+ return ret; -+ /* the UDA1341 is stereo only */ -+ ret = (val == 0) ? -EINVAL : 1; -+ return put_user(ret, (int *) arg); -+ -+ case SNDCTL_DSP_CHANNELS: -+ case SOUND_PCM_READ_CHANNELS: -+ /* the UDA1341 is stereo only */ -+ return put_user(2, (long *) arg); -+ -+ case SNDCTL_DSP_SPEED: -+ ret = get_user(val, (long *) arg); -+ if (ret) break; -+ h3600_set_samplerate(val); -+ /* fall through */ -+ -+ case SOUND_PCM_READ_RATE: -+ return put_user(audio_samplerate, (long *) arg); -+ -+ case SNDCTL_DSP_SETFMT: -+ case SNDCTL_DSP_GETFMTS: -+ /* we can do 16-bit only */ -+ return put_user(AFMT_S16_LE, (long *) arg); -+ -+ default: -+ /* Maybe this is meant for the mixer (As per OSS Docs) */ -+ return mixer_ioctl(inode, file, cmd, arg); -+ } -+ -+ return ret; -+} -+ -+static audio_stream_t output_stream, input_stream; -+ -+static audio_state_t audio_state = { -+ output_stream: &output_stream, -+ output_dma: DMA_Ser4SSPWr, -+ output_id: "UDA1341 out", -+ input_stream: &input_stream, -+ input_dma: DMA_Ser4SSPRd, -+ input_id: "UDA1341 in", -+ need_tx_for_rx: 1, -+ hw_init: h3600_audio_init, -+ hw_shutdown: h3600_audio_shutdown, -+ client_ioctl: h3600_audio_ioctl, -+ sem: __MUTEX_INITIALIZER(audio_state.sem), -+}; -+ -+static int h3600_audio_open(struct inode *inode, struct file *file) -+{ -+ return sa1100_audio_attach(inode, file, &audio_state); -+} -+ -+/* -+ * Missing fields of this structure will be patched with the call -+ * to sa1100_audio_attach(). -+ */ -+static struct file_operations h3600_audio_fops = { -+ open: h3600_audio_open, -+ owner: THIS_MODULE -+}; -+ -+ -+static int audio_dev_id, mixer_dev_id; -+ -+static int __init h3600_uda1341_init(void) -+{ -+ int ret; -+ -+ if (!machine_is_h3xxx()) -+ return -ENODEV; -+ -+ ret = l3_attach_client(&uda1341, "l3-bit-sa1100-gpio", "uda1341"); -+ if (ret) -+ goto out; -+ -+ /* register devices */ -+ audio_dev_id = register_sound_dsp(&h3600_audio_fops, -1); -+ mixer_dev_id = register_sound_mixer(&h3600_mixer_fops, -1); -+ -+ printk( KERN_INFO "iPAQ audio support initialized\n" ); -+ return 0; -+ -+release_l3: -+ l3_detach_client(&uda1341); -+out: -+ return ret; -+} -+ -+static void __exit h3600_uda1341_exit(void) -+{ -+ unregister_sound_dsp(audio_dev_id); -+ unregister_sound_mixer(mixer_dev_id); -+ l3_detach_client(&uda1341); -+} -+ -+module_init(h3600_uda1341_init); -+module_exit(h3600_uda1341_exit); -+ -+MODULE_AUTHOR("Nicolas Pitre, George France"); -+MODULE_DESCRIPTION("Glue audio driver for the Compaq iPAQ H3600 & Philips UDA1341 codec."); -+ -+EXPORT_NO_SYMBOLS; -diff -urN linux-2.4.26/drivers/sound/pangolin-uda1341.c linux-2.4.26-vrs1/drivers/sound/pangolin-uda1341.c ---- linux-2.4.26/drivers/sound/pangolin-uda1341.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/sound/pangolin-uda1341.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,322 @@ -+/* -+ * Glue audio driver for the SA1110 Pangolin board & Philips UDA1341 codec. -+ * -+ * Copyright (c) 2000 Nicolas Pitre -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License. -+ * -+ * This is the machine specific part of the Pangolin/UDA1341 support. -+ * This driver makes use of the UDA1341 and the sa1100-audio modules. -+ * -+ * History: -+ * -+ * 2000-05-21 Nicolas Pitre Initial release. -+ * -+ * 2001-06-03 Nicolas Pitre Made this file a separate module, based on -+ * the former sa1100-uda1341.c driver. -+ * -+ * 2001-07-17 Nicolas Pitre Supports 44100Hz and 22050Hz samplerate now. -+ * -+ * 2001-08-06 Richard Fan Pangolin Support -+ * -+ * 2001-09-23 Russell King Update inline with Assabet driver -+ * Remove old L3 bus driver -+ * -+ * Note: this should probably be merged with the Assabet audio driver, -+ * and become the "SDRAM-clock driven" SA1100 audio driver. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "sa1100-audio.h" -+ -+/* -+ * Debugging? -+ */ -+#undef DEBUG -+ -+ -+#ifdef DEBUG -+#define DPRINTK( x... ) printk( ##x ) -+#else -+#define DPRINTK( x... ) -+#endif -+ -+ -+#define AUDIO_RATE_DEFAULT 44100 -+ -+#define QmutePin GPIO_GPIO(4) -+#define SpeakerOffPin GPIO_GPIO(5) -+ -+/* -+ * Mixer (UDA1341) interface -+ */ -+ -+static struct l3_client uda1341; -+ -+static int -+mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) -+{ -+ /* -+ * We only accept mixer (type 'M') ioctls. -+ */ -+ if (_IOC_TYPE(cmd) != 'M') -+ return -EINVAL; -+ -+ return l3_command(&uda1341, cmd, (void *)arg); -+} -+ -+static struct file_operations pangolin_mixer_fops = { -+ ioctl: mixer_ioctl, -+ owner: THIS_MODULE -+}; -+ -+ -+/* -+ * Audio interface -+ */ -+static long audio_samplerate = AUDIO_RATE_DEFAULT; -+ -+static void pangolin_set_samplerate(long val) -+{ -+ struct uda1341_cfg cfg; -+ int clk_div; -+ -+ /* We don't want to mess with clocks when frames are in flight */ -+ Ser4SSCR0 &= ~SSCR0_SSE; -+ /* wait for any frame to complete */ -+ udelay(125); -+ -+ /* -+ * Our clock source is derived from the CPLD on which we don't have -+ * much control unfortunately. This was intended for a fixed 44100Hz -+ * samplerate assuming a core clock of 206 MHz. Still we can play -+ * with the SA1110's clock divisor for the SSP port to get a 22050Hz -+ * samplerate. -+ * -+ * Apparently the clock sent to the SA1110 for the SSP port is -+ * divided from the clock sent to the UDA1341 (some people tried to -+ * be too clever in their design, or simply failed to read the SA1110 -+ * manual). If it was the same source we would have been able to -+ * support a third samplerate. -+ * -+ * At least it would have been a minimum acceptable solution to be -+ * able to set the CPLD divisor by software. The iPAQ design is -+ * certainly a better example to follow for a new design. -+ */ -+ if (val >= 44100) { -+ audio_samplerate = 44100; -+ cfg.fs = 256; -+ clk_div = SSCR0_SerClkDiv(2); -+ } else { -+ audio_samplerate = 22050; -+ cfg.fs = 512; -+ clk_div = SSCR0_SerClkDiv(4); -+ } -+ -+ cfg.format = FMT_LSB16; -+ l3_command(&uda1341, L3_UDA1341_CONFIGURE, &cfg); -+ -+ Ser4SSCR0 = (Ser4SSCR0 & ~0xff00) + clk_div + SSCR0_SSE; -+} -+ -+static void pangolin_audio_init(void *dummy) -+{ -+ unsigned long flags; -+ unsigned int mdrefr; -+ -+ local_irq_save(flags); -+ -+ /* -+ * Setup the SSP uart. -+ */ -+ PPAR |= PPAR_SPR; -+ Ser4SSCR0 = SSCR0_DataSize(16) + SSCR0_TI + SSCR0_SerClkDiv(2); -+ Ser4SSCR1 = SSCR1_SClkIactL + SSCR1_SClk1P + SSCR1_ExtClk; -+ GAFR |= GPIO_SSP_TXD | GPIO_SSP_RXD | GPIO_SSP_SCLK | GPIO_SSP_CLK | -+ GPIO_SSP_SFRM; -+ GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM; -+ GPDR &= ~(GPIO_SSP_RXD | GPIO_SSP_CLK); -+ Ser4SSCR0 |= SSCR0_SSE; -+ -+ GAFR &= ~(SpeakerOffPin | QmutePin); -+ GPDR |= (SpeakerOffPin | QmutePin); -+ GPCR = SpeakerOffPin; -+ -+ /* -+ * The assabet board uses the SDRAM clock as the source clock for -+ * audio. This is supplied to the SA11x0 from the CPLD on pin 19. -+ * At 206MHz we need to run the audio clock (SDRAM bank 2) -+ * at half speed. This clock will scale with core frequency so -+ * the audio sample rate will also scale. The CPLD on Assabet -+ * will need to be programmed to match the core frequency. -+ */ -+ mdrefr = MDREFR; -+ if ((mdrefr & (MDREFR_K2DB2 | MDREFR_K2RUN | MDREFR_EAPD | -+ MDREFR_KAPD)) != (MDREFR_K2DB2 | MDREFR_K2RUN)) { -+ mdrefr |= MDREFR_K2DB2 | MDREFR_K2RUN; -+ mdrefr &= ~(MDREFR_EAPD | MDREFR_KAPD); -+ MDREFR = mdrefr; -+ (void) MDREFR; -+ } -+ local_irq_restore(flags); -+ -+ /* Wait for the UDA1341 to wake up */ -+ mdelay(100); -+ -+ l3_open(&uda1341); -+ -+ pangolin_set_samplerate(audio_samplerate); -+ -+ GPCR = QmutePin; -+} -+ -+static void pangolin_audio_shutdown(void *dummy) -+{ -+ GPSR = QmutePin; -+ -+ l3_close(&uda1341); -+ -+ Ser4SSCR0 = 0; -+ MDREFR &= ~(MDREFR_K2DB2 | MDREFR_K2RUN); -+} -+ -+static int pangolin_audio_ioctl( struct inode *inode, struct file *file, -+ uint cmd, ulong arg) -+{ -+ long val; -+ int ret = 0; -+ -+ /* -+ * These are platform dependent ioctls which are not handled by the -+ * generic sa1100-audio module. -+ */ -+ switch (cmd) { -+ case SNDCTL_DSP_STEREO: -+ ret = get_user(val, (int *) arg); -+ if (ret) -+ return ret; -+ /* the UDA1341 is stereo only */ -+ ret = (val == 0) ? -EINVAL : 1; -+ return put_user(ret, (int *) arg); -+ -+ case SNDCTL_DSP_CHANNELS: -+ case SOUND_PCM_READ_CHANNELS: -+ /* the UDA1341 is stereo only */ -+ return put_user(2, (long *) arg); -+ -+ case SNDCTL_DSP_SPEED: -+ ret = get_user(val, (long *) arg); -+ if (ret) break; -+ pangolin_set_samplerate(val); -+ /* fall through */ -+ -+ case SOUND_PCM_READ_RATE: -+ return put_user(audio_samplerate, (long *) arg); -+ -+ case SNDCTL_DSP_SETFMT: -+ case SNDCTL_DSP_GETFMTS: -+ /* we can do signed 16-bit only */ -+ return put_user(AFMT_S16_LE, (long *) arg); -+ -+ default: -+ /* Maybe this is meant for the mixer (As per OSS Docs) */ -+ return mixer_ioctl(inode, file, cmd, arg); -+ } -+ -+ return ret; -+} -+ -+static audio_stream_t output_stream, input_stream; -+ -+static audio_state_t audio_state = { -+ output_stream: &output_stream, -+ output_dma: DMA_Ser4SSPWr, -+ output_id: "Pangolin UDA1341 out", -+ input_stream: &input_stream, -+ input_dma: DMA_Ser4SSPRd, -+ input_id: "Pangolin UDA1341 in", -+ need_tx_for_rx: 1, -+ hw_init: pangolin_audio_init, -+ hw_shutdown: pangolin_audio_shutdown, -+ client_ioctl: pangolin_audio_ioctl, -+ sem: __MUTEX_INITIALIZER(audio_state.sem), -+}; -+ -+static int pangolin_audio_open(struct inode *inode, struct file *file) -+{ -+ return sa1100_audio_attach(inode, file, &audio_state); -+} -+ -+/* -+ * Missing fields of this structure will be patched with the call -+ * to sa1100_audio_attach(). -+ */ -+static struct file_operations pangolin_audio_fops = { -+ open: pangolin_audio_open, -+ owner: THIS_MODULE -+}; -+ -+ -+static int audio_dev_id, mixer_dev_id; -+ -+static int __init pangolin_uda1341_init(void) -+{ -+ unsigned long flags; -+ int ret; -+ -+ if (!machine_is_pangolin()) -+ return -ENODEV; -+ -+ ret = l3_attach_client(&uda1341, "l3-bit-sa1100-gpio", "uda1341"); -+ if (ret) -+ goto out; -+ -+ /* register devices */ -+ audio_dev_id = register_sound_dsp(&pangolin_audio_fops, -1); -+ mixer_dev_id = register_sound_mixer(&pangolin_mixer_fops, -1); -+ -+ local_irq_save(flags); -+ GAFR &= ~(SpeakerOffPin | QmutePin); -+ GPDR |= (SpeakerOffPin | QmutePin); -+ local_irq_restore(flags); -+ -+ printk(KERN_INFO "Pangolin UDA1341 audio driver initialized\n"); -+ return 0; -+ -+release_l3: -+ l3_detach_client(&uda1341); -+out: -+ return ret; -+} -+ -+static void __exit pangolin_uda1341_exit(void) -+{ -+ unregister_sound_dsp(audio_dev_id); -+ unregister_sound_mixer(mixer_dev_id); -+ l3_detach_client(&uda1341); -+} -+ -+module_init(pangolin_uda1341_init); -+module_exit(pangolin_uda1341_exit); -+ -+MODULE_AUTHOR("Nicolas Pitre"); -+MODULE_DESCRIPTION("Glue audio driver for the SA1110 Pangolin board & Philips UDA1341 codec."); -+ -+EXPORT_NO_SYMBOLS; -diff -urN linux-2.4.26/drivers/sound/sa1100-audio.c linux-2.4.26-vrs1/drivers/sound/sa1100-audio.c ---- linux-2.4.26/drivers/sound/sa1100-audio.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/sound/sa1100-audio.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,976 @@ -+/* -+ * Common audio handling for the SA11x0 processor -+ * -+ * Copyright (C) 2000, 2001 Nicolas Pitre -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License. -+ * -+ * -+ * This module handles the generic buffering/DMA/mmap audio interface for -+ * codecs connected to the SA1100 chip. All features depending on specific -+ * hardware implementations like supported audio formats or samplerates are -+ * relegated to separate specific modules. -+ * -+ * -+ * History: -+ * -+ * 2000-05-21 Nicolas Pitre Initial release. -+ * -+ * 2000-06-10 Erik Bunce Add initial poll support. -+ * -+ * 2000-08-22 Nicolas Pitre Removed all DMA stuff. Now using the -+ * generic SA1100 DMA interface. -+ * -+ * 2000-11-30 Nicolas Pitre - Validation of opened instances; -+ * - Power handling at open/release time instead -+ * of driver load/unload; -+ * -+ * 2001-06-03 Nicolas Pitre Made this file a separate module, based on -+ * the former sa1100-uda1341.c driver. -+ * -+ * 2001-07-22 Nicolas Pitre - added mmap() and realtime support -+ * - corrected many details to better comply -+ * with the OSS API -+ * -+ * 2001-10-19 Nicolas Pitre - brought DMA registration processing -+ * into this module for better ressource -+ * management. This also fixes a bug -+ * with the suspend/resume logic. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "sa1100-audio.h" -+ -+ -+#undef DEBUG -+/* #define DEBUG 1 */ -+#ifdef DEBUG -+#define DPRINTK( x... ) printk( ##x ) -+#else -+#define DPRINTK( x... ) -+#endif -+ -+ -+#define AUDIO_NAME "sa1100-audio" -+#define AUDIO_NBFRAGS_DEFAULT 8 -+#define AUDIO_FRAGSIZE_DEFAULT 8192 -+ -+#define NEXT_BUF(_s_,_b_) { \ -+ (_s_)->_b_##_idx++; \ -+ (_s_)->_b_##_idx %= (_s_)->nbfrags; \ -+ (_s_)->_b_ = (_s_)->buffers + (_s_)->_b_##_idx; } -+ -+#define AUDIO_ACTIVE(state) ((state)->rd_ref || (state)->wr_ref) -+ -+/* -+ * This function frees all buffers -+ */ -+ -+static void audio_clear_buf(audio_stream_t * s) -+{ -+ DPRINTK("audio_clear_buf\n"); -+ -+ /* ensure DMA won't run anymore */ -+ s->active = 0; -+ s->stopped = 0; -+ sa1100_dma_flush_all(s->dma_ch); -+ -+ if (s->buffers) { -+ int frag; -+ for (frag = 0; frag < s->nbfrags; frag++) { -+ if (!s->buffers[frag].master) -+ continue; -+ consistent_free(s->buffers[frag].start, -+ s->buffers[frag].master, -+ s->buffers[frag].dma_addr); -+ } -+ kfree(s->buffers); -+ s->buffers = NULL; -+ } -+ -+ s->buf_idx = 0; -+ s->buf = NULL; -+} -+ -+ -+/* -+ * This function allocates the buffer structure array and buffer data space -+ * according to the current number of fragments and fragment size. -+ */ -+ -+static int audio_setup_buf(audio_stream_t * s) -+{ -+ int frag; -+ int dmasize = 0; -+ char *dmabuf = NULL; -+ dma_addr_t dmaphys = 0; -+ -+ if (s->buffers) -+ return -EBUSY; -+ -+ s->buffers = (audio_buf_t *) -+ kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL); -+ if (!s->buffers) -+ goto err; -+ memset(s->buffers, 0, sizeof(audio_buf_t) * s->nbfrags); -+ -+ for (frag = 0; frag < s->nbfrags; frag++) { -+ audio_buf_t *b = &s->buffers[frag]; -+ -+ /* -+ * Let's allocate non-cached memory for DMA buffers. -+ * We try to allocate all memory at once. -+ * If this fails (a common reason is memory fragmentation), -+ * then we allocate more smaller buffers. -+ */ -+ if (!dmasize) { -+ dmasize = (s->nbfrags - frag) * s->fragsize; -+ do { -+ dmabuf = consistent_alloc(GFP_KERNEL|GFP_DMA, -+ dmasize, -+ &dmaphys); -+ if (!dmabuf) -+ dmasize -= s->fragsize; -+ } while (!dmabuf && dmasize); -+ if (!dmabuf) -+ goto err; -+ b->master = dmasize; -+ memzero(dmabuf, dmasize); -+ } -+ -+ b->start = dmabuf; -+ b->dma_addr = dmaphys; -+ b->stream = s; -+ sema_init(&b->sem, 1); -+ DPRINTK("buf %d: start %p dma %p\n", frag, b->start, -+ b->dma_addr); -+ -+ dmabuf += s->fragsize; -+ dmaphys += s->fragsize; -+ dmasize -= s->fragsize; -+ } -+ -+ s->buf_idx = 0; -+ s->buf = &s->buffers[0]; -+ s->bytecount = 0; -+ s->getptrCount = 0; -+ s->fragcount = 0; -+ -+ return 0; -+ -+err: -+ printk(AUDIO_NAME ": unable to allocate audio memory\n "); -+ audio_clear_buf(s); -+ return -ENOMEM; -+} -+ -+ -+/* -+ * This function yanks all buffers from the DMA code's control and -+ * resets them ready to be used again. -+ */ -+ -+static void audio_reset_buf(audio_stream_t * s) -+{ -+ int frag; -+ -+ s->active = 0; -+ s->stopped = 0; -+ sa1100_dma_flush_all(s->dma_ch); -+ if (s->buffers) { -+ for (frag = 0; frag < s->nbfrags; frag++) { -+ audio_buf_t *b = &s->buffers[frag]; -+ b->size = 0; -+ sema_init(&b->sem, 1); -+ } -+ } -+ s->bytecount = 0; -+ s->getptrCount = 0; -+ s->fragcount = 0; -+} -+ -+ -+/* -+ * DMA callback functions -+ */ -+ -+static void audio_dmaout_done_callback(void *buf_id, int size) -+{ -+ audio_buf_t *b = (audio_buf_t *) buf_id; -+ audio_stream_t *s = b->stream; -+ -+ /* Accounting */ -+ s->bytecount += size; -+ s->fragcount++; -+ -+ /* Recycle buffer */ -+ if (s->mapped) -+ sa1100_dma_queue_buffer(s->dma_ch, buf_id, -+ b->dma_addr, s->fragsize); -+ else -+ up(&b->sem); -+ -+ /* And any process polling on write. */ -+ wake_up(&s->wq); -+} -+ -+static void audio_dmain_done_callback(void *buf_id, int size) -+{ -+ audio_buf_t *b = (audio_buf_t *) buf_id; -+ audio_stream_t *s = b->stream; -+ -+ /* Accounting */ -+ s->bytecount += size; -+ s->fragcount++; -+ -+ /* Recycle buffer */ -+ if (s->mapped) { -+ sa1100_dma_queue_buffer(s->dma_ch, buf_id, -+ b->dma_addr, s->fragsize); -+ } else { -+ b->size = size; -+ up(&b->sem); -+ } -+ -+ /* And any process polling on write. */ -+ wake_up(&s->wq); -+} -+ -+static int audio_sync(struct file *file) -+{ -+ audio_state_t *state = (audio_state_t *)file->private_data; -+ audio_stream_t *s = state->output_stream; -+ audio_buf_t *b; -+ -+ DPRINTK("audio_sync\n"); -+ -+ if (!(file->f_mode & FMODE_WRITE) || !s->buffers || s->mapped) -+ return 0; -+ -+ /* -+ * Send current buffer if it contains data. Be sure to send -+ * a full sample count. -+ */ -+ b = s->buf; -+ if (b->size &= ~3) { -+ down(&b->sem); -+ sa1100_dma_queue_buffer(s->dma_ch, (void *) b, -+ b->dma_addr, b->size); -+ b->size = 0; -+ NEXT_BUF(s, buf); -+ } -+ -+ /* -+ * Let's wait for the last buffer we sent i.e. the one before the -+ * current buf_idx. When we acquire the semaphore, this means either: -+ * - DMA on the buffer completed or -+ * - the buffer was already free thus nothing else to sync. -+ */ -+ b = s->buffers + ((s->nbfrags + s->buf_idx - 1) % s->nbfrags); -+ if (down_interruptible(&b->sem)) -+ return -EINTR; -+ up(&b->sem); -+ return 0; -+} -+ -+ -+static int audio_write(struct file *file, const char *buffer, -+ size_t count, loff_t * ppos) -+{ -+ const char *buffer0 = buffer; -+ audio_state_t *state = (audio_state_t *)file->private_data; -+ audio_stream_t *s = state->output_stream; -+ int chunksize, ret = 0; -+ -+ DPRINTK("audio_write: count=%d\n", count); -+ -+ if (ppos != &file->f_pos) -+ return -ESPIPE; -+ if (s->mapped) -+ return -ENXIO; -+ if (!s->buffers && audio_setup_buf(s)) -+ return -ENOMEM; -+ -+ while (count > 0) { -+ audio_buf_t *b = s->buf; -+ -+ /* Wait for a buffer to become free */ -+ if (file->f_flags & O_NONBLOCK) { -+ ret = -EAGAIN; -+ if (down_trylock(&b->sem)) -+ break; -+ } else { -+ ret = -ERESTARTSYS; -+ if (down_interruptible(&b->sem)) -+ break; -+ } -+ -+ /* Feed the current buffer */ -+ chunksize = s->fragsize - b->size; -+ if (chunksize > count) -+ chunksize = count; -+ DPRINTK("write %d to %d\n", chunksize, s->buf_idx); -+ if (copy_from_user(b->start + b->size, buffer, chunksize)) { -+ up(&b->sem); -+ return -EFAULT; -+ } -+ b->size += chunksize; -+ buffer += chunksize; -+ count -= chunksize; -+ if (b->size < s->fragsize) { -+ up(&b->sem); -+ break; -+ } -+ -+ /* Send current buffer to dma */ -+ s->active = 1; -+ sa1100_dma_queue_buffer(s->dma_ch, (void *) b, -+ b->dma_addr, b->size); -+ b->size = 0; /* indicate that the buffer has been sent */ -+ NEXT_BUF(s, buf); -+ } -+ -+ if ((buffer - buffer0)) -+ ret = buffer - buffer0; -+ DPRINTK("audio_write: return=%d\n", ret); -+ return ret; -+} -+ -+ -+static inline void audio_check_tx_spin(audio_state_t *state) -+{ -+ /* -+ * With some codecs like the Philips UDA1341 we must ensure -+ * there is an output stream at any time while recording since -+ * this is how the UDA1341 gets its clock from the SA1100. -+ * So while there is no playback data to send, the output DMA -+ * will spin with all zeroes. We use the cache flush special -+ * area for that. -+ */ -+ if (state->need_tx_for_rx && !state->tx_spinning) { -+ sa1100_dma_set_spin(state->output_stream->dma_ch, -+ (dma_addr_t)FLUSH_BASE_PHYS, 2048); -+ state->tx_spinning = 1; -+ } -+} -+ -+ -+static void audio_prime_dma(audio_stream_t *s) -+{ -+ int i; -+ -+ s->active = 1; -+ for (i = 0; i < s->nbfrags; i++) { -+ audio_buf_t *b = s->buf; -+ down(&b->sem); -+ sa1100_dma_queue_buffer(s->dma_ch, (void *) b, -+ b->dma_addr, s->fragsize); -+ NEXT_BUF(s, buf); -+ } -+} -+ -+ -+static int audio_read(struct file *file, char *buffer, -+ size_t count, loff_t * ppos) -+{ -+ char *buffer0 = buffer; -+ audio_state_t *state = (audio_state_t *)file->private_data; -+ audio_stream_t *s = state->input_stream; -+ int chunksize, ret = 0; -+ -+ DPRINTK("audio_read: count=%d\n", count); -+ -+ if (ppos != &file->f_pos) -+ return -ESPIPE; -+ if (s->mapped) -+ return -ENXIO; -+ -+ if (!s->active) { -+ if (!s->buffers && audio_setup_buf(s)) -+ return -ENOMEM; -+ audio_check_tx_spin(state); -+ audio_prime_dma(s); -+ } -+ -+ while (count > 0) { -+ audio_buf_t *b = s->buf; -+ -+ /* Wait for a buffer to become full */ -+ if (file->f_flags & O_NONBLOCK) { -+ ret = -EAGAIN; -+ if (down_trylock(&b->sem)) -+ break; -+ } else { -+ ret = -ERESTARTSYS; -+ if (down_interruptible(&b->sem)) -+ break; -+ } -+ -+ /* Grab data from the current buffer */ -+ chunksize = b->size; -+ if (chunksize > count) -+ chunksize = count; -+ DPRINTK("read %d from %d\n", chunksize, s->buf_idx); -+ if (copy_to_user(buffer, -+ b->start + s->fragsize - b->size, -+ chunksize)) { -+ up(&b->sem); -+ return -EFAULT; -+ } -+ b->size -= chunksize; -+ buffer += chunksize; -+ count -= chunksize; -+ if (b->size > 0) { -+ up(&b->sem); -+ break; -+ } -+ -+ /* Make current buffer available for DMA again */ -+ sa1100_dma_queue_buffer(s->dma_ch, (void *) b, -+ b->dma_addr, s->fragsize); -+ NEXT_BUF(s, buf); -+ } -+ -+ if ((buffer - buffer0)) -+ ret = buffer - buffer0; -+ DPRINTK("audio_read: return=%d\n", ret); -+ return ret; -+} -+ -+ -+static int audio_mmap(struct file *file, struct vm_area_struct *vma) -+{ -+ audio_state_t *state = (audio_state_t *)file->private_data; -+ audio_stream_t *s; -+ unsigned long size, vma_addr; -+ int i, ret; -+ -+ if (vma->vm_pgoff != 0) -+ return -EINVAL; -+ -+ if (vma->vm_flags & VM_WRITE) { -+ if (!state->wr_ref) -+ return -EINVAL;; -+ s = state->output_stream; -+ } else if (vma->vm_flags & VM_READ) { -+ if (!state->rd_ref) -+ return -EINVAL; -+ s = state->input_stream; -+ } else return -EINVAL; -+ -+ if (s->mapped) -+ return -EINVAL; -+ size = vma->vm_end - vma->vm_start; -+ if (size != s->fragsize * s->nbfrags) -+ return -EINVAL; -+ if (!s->buffers && audio_setup_buf(s)) -+ return -ENOMEM; -+ vma_addr = vma->vm_start; -+ for (i = 0; i < s->nbfrags; i++) { -+ audio_buf_t *buf = &s->buffers[i]; -+ if (!buf->master) -+ continue; -+ ret = remap_page_range(vma_addr, buf->dma_addr, buf->master, vma->vm_page_prot); -+ if (ret) -+ return ret; -+ vma_addr += buf->master; -+ } -+ s->mapped = 1; -+ -+ return 0; -+} -+ -+ -+static unsigned int audio_poll(struct file *file, -+ struct poll_table_struct *wait) -+{ -+ audio_state_t *state = (audio_state_t *)file->private_data; -+ audio_stream_t *is = state->input_stream; -+ audio_stream_t *os = state->output_stream; -+ unsigned int mask = 0; -+ int i; -+ -+ DPRINTK("audio_poll(): mode=%s%s\n", -+ (file->f_mode & FMODE_READ) ? "r" : "", -+ (file->f_mode & FMODE_WRITE) ? "w" : ""); -+ -+ if (file->f_mode & FMODE_READ) { -+ /* Start audio input if not already active */ -+ if (!is->active) { -+ if (!is->buffers && audio_setup_buf(is)) -+ return -ENOMEM; -+ audio_check_tx_spin(state); -+ audio_prime_dma(is); -+ } -+ poll_wait(file, &is->wq, wait); -+ } -+ -+ if (file->f_mode & FMODE_WRITE) { -+ if (!os->buffers && audio_setup_buf(os)) -+ return -ENOMEM; -+ poll_wait(file, &os->wq, wait); -+ } -+ -+ if (file->f_mode & FMODE_READ) { -+ if (is->mapped) { -+/* if the buffer is mapped assume we care that there are more bytes available than -+ when we last asked using SNDCTL_DSP_GETxPTR */ -+ if (is->bytecount != is->getptrCount) -+ mask |= POLLIN | POLLRDNORM; -+ } else { -+ for (i = 0; i < is->nbfrags; i++) { -+ if (atomic_read(&is->buffers[i].sem.count) > 0) { -+ mask |= POLLIN | POLLRDNORM; -+ break; -+ } -+ } -+ } -+ } -+ if (file->f_mode & FMODE_WRITE) { -+ if (os->mapped) { -+ if (os->bytecount != os->getptrCount) -+ mask |= POLLOUT | POLLWRNORM; -+ } else { -+ for (i = 0; i < os->nbfrags; i++) { -+ if (atomic_read(&os->buffers[i].sem.count) > 0) { -+ mask |= POLLOUT | POLLWRNORM; -+ break; -+ } -+ } -+ } -+ } -+ -+ DPRINTK("audio_poll() returned mask of %s%s\n", -+ (mask & POLLIN) ? "r" : "", -+ (mask & POLLOUT) ? "w" : ""); -+ -+ return mask; -+} -+ -+ -+static loff_t audio_llseek(struct file *file, loff_t offset, int origin) -+{ -+ return -ESPIPE; -+} -+ -+ -+static int audio_set_fragments(audio_stream_t *s, int val) -+{ -+ if (s->active) -+ return -EBUSY; -+ if (s->buffers) -+ audio_clear_buf(s); -+ s->nbfrags = (val >> 16) & 0x7FFF; -+ val &= 0xffff; -+ if (val < 4) -+ val = 4; -+ if (val > 15) -+ val = 15; -+ s->fragsize = 1 << val; -+ if (s->nbfrags < 2) -+ s->nbfrags = 2; -+ if (s->nbfrags * s->fragsize > 128 * 1024) -+ s->nbfrags = 128 * 1024 / s->fragsize; -+ if (audio_setup_buf(s)) -+ return -ENOMEM; -+ return val|(s->nbfrags << 16); -+} -+ -+static int audio_ioctl(struct inode *inode, struct file *file, -+ uint cmd, ulong arg) -+{ -+ audio_state_t *state = (audio_state_t *)file->private_data; -+ audio_stream_t *os = state->output_stream; -+ audio_stream_t *is = state->input_stream; -+ long val; -+ -+ /* dispatch based on command */ -+ switch (cmd) { -+ case OSS_GETVERSION: -+ return put_user(SOUND_VERSION, (int *)arg); -+ -+ case SNDCTL_DSP_GETBLKSIZE: -+ if (file->f_mode & FMODE_WRITE) -+ return put_user(os->fragsize, (int *)arg); -+ else -+ return put_user(is->fragsize, (int *)arg); -+ -+ case SNDCTL_DSP_GETCAPS: -+ val = DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP; -+ if (is && os) -+ val |= DSP_CAP_DUPLEX; -+ return put_user(val, (int *)arg); -+ -+ case SNDCTL_DSP_SETFRAGMENT: -+ if (get_user(val, (long *) arg)) -+ return -EFAULT; -+ if (file->f_mode & FMODE_READ) { -+ int ret = audio_set_fragments(is, val); -+ if (ret < 0) -+ return ret; -+ ret = put_user(ret, (int *)arg); -+ if (ret) -+ return ret; -+ } -+ if (file->f_mode & FMODE_WRITE) { -+ int ret = audio_set_fragments(os, val); -+ if (ret < 0) -+ return ret; -+ ret = put_user(ret, (int *)arg); -+ if (ret) -+ return ret; -+ } -+ return 0; -+ -+ case SNDCTL_DSP_SYNC: -+ return audio_sync(file); -+ -+ case SNDCTL_DSP_SETDUPLEX: -+ return 0; -+ -+ case SNDCTL_DSP_POST: -+ return 0; -+ -+ case SNDCTL_DSP_GETTRIGGER: -+ val = 0; -+ if (file->f_mode & FMODE_READ && is->active && !is->stopped) -+ val |= PCM_ENABLE_INPUT; -+ if (file->f_mode & FMODE_WRITE && os->active && !os->stopped) -+ val |= PCM_ENABLE_OUTPUT; -+ return put_user(val, (int *)arg); -+ -+ case SNDCTL_DSP_SETTRIGGER: -+ if (get_user(val, (int *)arg)) -+ return -EFAULT; -+ if (file->f_mode & FMODE_READ) { -+ if (val & PCM_ENABLE_INPUT) { -+ if (!is->active) { -+ if (!is->buffers && audio_setup_buf(is)) -+ return -ENOMEM; -+ audio_prime_dma(is); -+ } -+ audio_check_tx_spin(state); -+ if (is->stopped) { -+ is->stopped = 0; -+ sa1100_dma_resume(is->dma_ch); -+ } -+ } else { -+ sa1100_dma_stop(is->dma_ch); -+ is->stopped = 1; -+ } -+ } -+ if (file->f_mode & FMODE_WRITE) { -+ if (val & PCM_ENABLE_OUTPUT) { -+ if (!os->active) { -+ if (!os->buffers && audio_setup_buf(os)) -+ return -ENOMEM; -+ if (os->mapped) -+ audio_prime_dma(os); -+ } -+ if (os->stopped) { -+ os->stopped = 0; -+ sa1100_dma_resume(os->dma_ch); -+ } -+ } else { -+ sa1100_dma_stop(os->dma_ch); -+ os->stopped = 1; -+ } -+ } -+ return 0; -+ -+ case SNDCTL_DSP_GETOPTR: -+ case SNDCTL_DSP_GETIPTR: -+ { -+ count_info inf = { 0, }; -+ audio_stream_t *s = (cmd == SNDCTL_DSP_GETOPTR) ? os : is; -+ audio_buf_t *b; -+ dma_addr_t ptr; -+ int bytecount, offset, flags; -+ -+ if ((s == is && !(file->f_mode & FMODE_READ)) || -+ (s == os && !(file->f_mode & FMODE_WRITE))) -+ return -EINVAL; -+ if (s->active) { -+ save_flags_cli(flags); -+ if (sa1100_dma_get_current(s->dma_ch, (void *)&b, &ptr) == 0) { -+ offset = ptr - b->dma_addr; -+ inf.ptr = (b - s->buffers) * s->fragsize + offset; -+ } else offset = 0; -+ bytecount = s->bytecount + offset; -+ s->getptrCount = s->bytecount; /* so poll can tell if it changes */ -+ inf.blocks = s->fragcount; -+ s->fragcount = 0; -+ restore_flags(flags); -+ if (bytecount < 0) -+ bytecount = 0; -+ inf.bytes = bytecount; -+ } -+ return copy_to_user((void *)arg, &inf, sizeof(inf)); -+ } -+ -+ case SNDCTL_DSP_GETOSPACE: -+ { -+ audio_buf_info inf = { 0, }; -+ int i; -+ -+ if (!(file->f_mode & FMODE_WRITE)) -+ return -EINVAL; -+ if (!os->buffers && audio_setup_buf(os)) -+ return -ENOMEM; -+ for (i = 0; i < os->nbfrags; i++) { -+ if (atomic_read(&os->buffers[i].sem.count) > 0) { -+ if (os->buffers[i].size == 0) -+ inf.fragments++; -+ inf.bytes += os->fragsize - os->buffers[i].size; -+ } -+ } -+ inf.fragstotal = os->nbfrags; -+ inf.fragsize = os->fragsize; -+ return copy_to_user((void *)arg, &inf, sizeof(inf)); -+ } -+ -+ case SNDCTL_DSP_GETISPACE: -+ { -+ audio_buf_info inf = { 0, }; -+ int i; -+ -+ if (!(file->f_mode & FMODE_READ)) -+ return -EINVAL; -+ if (!is->buffers && audio_setup_buf(is)) -+ return -ENOMEM; -+ for (i = 0; i < is->nbfrags; i++) { -+ if (atomic_read(&is->buffers[i].sem.count) > 0) { -+ if (is->buffers[i].size == is->fragsize) -+ inf.fragments++; -+ inf.bytes += is->buffers[i].size; -+ } -+ } -+ inf.fragstotal = is->nbfrags; -+ inf.fragsize = is->fragsize; -+ return copy_to_user((void *)arg, &inf, sizeof(inf)); -+ } -+ -+ case SNDCTL_DSP_NONBLOCK: -+ file->f_flags |= O_NONBLOCK; -+ return 0; -+ -+ case SNDCTL_DSP_RESET: -+ if (file->f_mode & FMODE_READ) { -+ if (state->tx_spinning) { -+ sa1100_dma_set_spin(os->dma_ch, 0, 0); -+ state->tx_spinning = 0; -+ } -+ audio_reset_buf(is); -+ } -+ if (file->f_mode & FMODE_WRITE) { -+ audio_reset_buf(os); -+ } -+ return 0; -+ -+ default: -+ /* -+ * Let the client of this module handle the -+ * non generic ioctls -+ */ -+ return state->client_ioctl(inode, file, cmd, arg); -+ } -+ -+ return 0; -+} -+ -+ -+static int audio_release(struct inode *inode, struct file *file) -+{ -+ audio_state_t *state = (audio_state_t *)file->private_data; -+ DPRINTK("audio_release\n"); -+ -+ down(&state->sem); -+ -+ if (file->f_mode & FMODE_READ) { -+ if (state->tx_spinning) { -+ sa1100_dma_set_spin(state->output_stream->dma_ch, 0, 0); -+ state->tx_spinning = 0; -+ } -+ audio_clear_buf(state->input_stream); -+ if (!state->skip_dma_init) { -+ sa1100_free_dma(state->input_stream->dma_ch); -+ if (state->need_tx_for_rx && !state->wr_ref) -+ sa1100_free_dma(state->output_stream->dma_ch); -+ } -+ state->rd_ref = 0; -+ } -+ -+ if (file->f_mode & FMODE_WRITE) { -+ audio_sync(file); -+ audio_clear_buf(state->output_stream); -+ if (!state->skip_dma_init) -+ if (!state->need_tx_for_rx || !state->rd_ref) -+ sa1100_free_dma(state->output_stream->dma_ch); -+ state->wr_ref = 0; -+ } -+ -+ if (!AUDIO_ACTIVE(state)) { -+ if (state->hw_shutdown) -+ state->hw_shutdown(state->data); -+#ifdef CONFIG_PM -+ pm_unregister(state->pm_dev); -+#endif -+ } -+ -+ up(&state->sem); -+ return 0; -+} -+ -+ -+#ifdef CONFIG_PM -+ -+static int audio_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) -+{ -+ audio_state_t *state = (audio_state_t *)pm_dev->data; -+ -+ switch (req) { -+ case PM_SUSPEND: /* enter D1-D3 */ -+ if (state->output_stream) -+ sa1100_dma_sleep(state->output_stream->dma_ch); -+ if (state->input_stream) -+ sa1100_dma_sleep(state->input_stream->dma_ch); -+ if (AUDIO_ACTIVE(state) && state->hw_shutdown) -+ state->hw_shutdown(state->data); -+ break; -+ case PM_RESUME: /* enter D0 */ -+ if (AUDIO_ACTIVE(state) && state->hw_init) -+ state->hw_init(state->data); -+ if (state->input_stream) -+ sa1100_dma_wakeup(state->input_stream->dma_ch); -+ if (state->output_stream) -+ sa1100_dma_wakeup(state->output_stream->dma_ch); -+ break; -+ } -+ return 0; -+} -+ -+#endif -+ -+ -+int sa1100_audio_attach(struct inode *inode, struct file *file, -+ audio_state_t *state) -+{ -+ int err, need_tx_dma; -+ -+ DPRINTK("audio_open\n"); -+ -+ down(&state->sem); -+ -+ /* access control */ -+ err = -ENODEV; -+ if ((file->f_mode & FMODE_WRITE) && !state->output_stream) -+ goto out; -+ if ((file->f_mode & FMODE_READ) && !state->input_stream) -+ goto out; -+ err = -EBUSY; -+ if ((file->f_mode & FMODE_WRITE) && state->wr_ref) -+ goto out; -+ if ((file->f_mode & FMODE_READ) && state->rd_ref) -+ goto out; -+ err = -EINVAL; -+ if ((file->f_mode & FMODE_READ) && state->need_tx_for_rx && !state->output_stream) -+ goto out; -+ -+ /* request DMA channels */ -+ if (state->skip_dma_init) -+ goto skip_dma; -+ need_tx_dma = ((file->f_mode & FMODE_WRITE) || -+ ((file->f_mode & FMODE_READ) && state->need_tx_for_rx)); -+ if (state->wr_ref || (state->rd_ref && state->need_tx_for_rx)) -+ need_tx_dma = 0; -+ if (need_tx_dma) { -+ err = sa1100_request_dma(&state->output_stream->dma_ch, -+ state->output_id, -+ state->output_dma); -+ if (err) -+ goto out; -+ } -+ if (file->f_mode & FMODE_READ) { -+ err = sa1100_request_dma(&state->input_stream->dma_ch, -+ state->input_id, -+ state->input_dma); -+ if (err) { -+ if (need_tx_dma) -+ sa1100_free_dma(state->output_stream->dma_ch); -+ goto out; -+ } -+ } -+skip_dma: -+ -+ /* now complete initialisation */ -+ if (!AUDIO_ACTIVE(state)) { -+ if (state->hw_init) -+ state->hw_init(state->data); -+#ifdef CONFIG_PM -+ state->pm_dev = pm_register(PM_SYS_DEV, 0, audio_pm_callback); -+ if (state->pm_dev) -+ state->pm_dev->data = state; -+#endif -+ } -+ -+ if ((file->f_mode & FMODE_WRITE)) { -+ state->wr_ref = 1; -+ audio_clear_buf(state->output_stream); -+ state->output_stream->fragsize = AUDIO_FRAGSIZE_DEFAULT; -+ state->output_stream->nbfrags = AUDIO_NBFRAGS_DEFAULT; -+ state->output_stream->mapped = 0; -+ sa1100_dma_set_callback(state->output_stream->dma_ch, -+ audio_dmaout_done_callback); -+ init_waitqueue_head(&state->output_stream->wq); -+ } -+ if (file->f_mode & FMODE_READ) { -+ state->rd_ref = 1; -+ audio_clear_buf(state->input_stream); -+ state->input_stream->fragsize = AUDIO_FRAGSIZE_DEFAULT; -+ state->input_stream->nbfrags = AUDIO_NBFRAGS_DEFAULT; -+ state->input_stream->mapped = 0; -+ sa1100_dma_set_callback(state->input_stream->dma_ch, -+ audio_dmain_done_callback); -+ init_waitqueue_head(&state->input_stream->wq); -+ } -+ -+ file->private_data = state; -+ file->f_op->release = audio_release; -+ file->f_op->write = audio_write; -+ file->f_op->read = audio_read; -+ file->f_op->mmap = audio_mmap; -+ file->f_op->poll = audio_poll; -+ file->f_op->ioctl = audio_ioctl; -+ file->f_op->llseek = audio_llseek; -+ err = 0; -+ -+out: -+ up(&state->sem); -+ return err; -+} -+ -+EXPORT_SYMBOL(sa1100_audio_attach); -+ -+MODULE_AUTHOR("Nicolas Pitre"); -+MODULE_DESCRIPTION("Common audio handling for the SA11x0 processor"); -+MODULE_LICENSE("GPL"); -diff -urN linux-2.4.26/drivers/sound/sa1100-audio.h linux-2.4.26-vrs1/drivers/sound/sa1100-audio.h ---- linux-2.4.26/drivers/sound/sa1100-audio.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/sound/sa1100-audio.h 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,68 @@ -+/* -+ * Common audio handling for the SA11x0 -+ * -+ * Copyright (c) 2000 Nicolas Pitre -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License. -+ */ -+ -+ -+/* -+ * Buffer Management -+ */ -+ -+typedef struct { -+ int size; /* buffer size */ -+ char *start; /* points to actual buffer */ -+ dma_addr_t dma_addr; /* physical buffer address */ -+ struct semaphore sem; /* down before touching the buffer */ -+ int master; /* owner for buffer allocation, contain size when true */ -+ struct audio_stream_s *stream; /* owning stream */ -+} audio_buf_t; -+ -+typedef struct audio_stream_s { -+ audio_buf_t *buffers; /* pointer to audio buffer structures */ -+ audio_buf_t *buf; /* current buffer used by read/write */ -+ u_int buf_idx; /* index for the pointer above... */ -+ u_int fragsize; /* fragment i.e. buffer size */ -+ u_int nbfrags; /* nbr of fragments i.e. buffers */ -+ int bytecount; /* nbr of processed bytes */ -+ int getptrCount; /* value of bytecount last time anyone asked via GETxPTR */ -+ int fragcount; /* nbr of fragment transitions */ -+ dmach_t dma_ch; /* DMA channel ID */ -+ wait_queue_head_t wq; /* for poll */ -+ int mapped:1; /* mmap()'ed buffers */ -+ int active:1; /* actually in progress */ -+ int stopped:1; /* might be active but stopped */ -+} audio_stream_t; -+ -+/* -+ * State structure for one instance -+ */ -+ -+typedef struct { -+ audio_stream_t *output_stream; -+ audio_stream_t *input_stream; -+ dma_device_t output_dma; -+ dma_device_t input_dma; -+ char *output_id; -+ char *input_id; -+ int rd_ref:1; /* open reference for recording */ -+ int wr_ref:1; /* open reference for playback */ -+ int need_tx_for_rx:1; /* if data must be sent while receiving */ -+ int tx_spinning:1; /* tx spinning active */ -+ int skip_dma_init:1; /* hack for the SA1111 */ -+ void *data; -+ void (*hw_init)(void *); -+ void (*hw_shutdown)(void *); -+ int (*client_ioctl)(struct inode *, struct file *, uint, ulong); -+ struct pm_dev *pm_dev; -+ struct semaphore sem; /* to protect against races in attach() */ -+} audio_state_t; -+ -+/* -+ * Functions exported by this module -+ */ -+extern int sa1100_audio_attach( struct inode *inode, struct file *file, -+ audio_state_t *state); -diff -urN linux-2.4.26/drivers/sound/sa1100ssp.c linux-2.4.26-vrs1/drivers/sound/sa1100ssp.c ---- linux-2.4.26/drivers/sound/sa1100ssp.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/sound/sa1100ssp.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,182 @@ -+/* -+ * Glue audio driver for a simple DAC on the SA1100's SSP port -+ * -+ * Copyright (c) 2001 Nicolas Pitre -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License. -+ * -+ * History: -+ * -+ * 2001-06-04 Nicolas Pitre Initial release. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "sa1100-audio.h" -+ -+ -+#undef DEBUG -+#ifdef DEBUG -+#define DPRINTK( x... ) printk( ##x ) -+#else -+#define DPRINTK( x... ) -+#endif -+ -+ -+#define AUDIO_NAME "SA1100 SSP audio" -+ -+#define AUDIO_FMT AFMT_S16_LE -+#define AUDIO_CHANNELS 2 -+ -+static int sample_rate = 44100; -+ -+ -+static void ssp_audio_init(void) -+{ -+ if (machine_is_lart()) { -+ unsigned long flags; -+ local_irq_save(flags); -+ -+ /* LART has the SSP port rewired to GPIO 10-13, 19 */ -+ /* alternate functions for the GPIOs */ -+ GAFR |= ( GPIO_SSP_TXD | GPIO_SSP_RXD | GPIO_SSP_SCLK | -+ GPIO_SSP_SFRM | GPIO_SSP_CLK ); -+ -+ /* Set the direction: 10, 12, 13 output; 11, 19 input */ -+ GPDR |= ( GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM ); -+ GPDR &= ~( GPIO_SSP_RXD | GPIO_SSP_CLK ); -+ -+ /* enable SSP pin swap */ -+ PPAR |= PPAR_SPR; -+ -+ local_irq_restore(flags); -+ } -+ -+ /* turn on the SSP */ -+ Ser4SSCR0 = 0; -+ Ser4SSCR0 = (SSCR0_DataSize(16) | SSCR0_TI | SSCR0_SerClkDiv(2) | -+ SSCR0_SSE); -+ Ser4SSCR1 = (SSCR1_SClkIactL | SSCR1_SClk1P | SSCR1_ExtClk); -+} -+ -+static void ssp_audio_shutdown(void) -+{ -+ Ser4SSCR0 = 0; -+} -+ -+static int ssp_audio_ioctl( struct inode *inode, struct file *file, -+ uint cmd, ulong arg) -+{ -+ long val; -+ int ret = 0; -+ -+ /* -+ * These are platform dependent ioctls which are not handled by the -+ * generic sa1100-audio module. -+ */ -+ switch (cmd) { -+ case SNDCTL_DSP_STEREO: -+ ret = get_user(val, (int *) arg); -+ if (ret) -+ return ret; -+ /* Simple standard DACs are stereo only */ -+ ret = (val == 0) ? -EINVAL : 1; -+ return put_user(ret, (int *) arg); -+ -+ case SNDCTL_DSP_CHANNELS: -+ case SOUND_PCM_READ_CHANNELS: -+ /* Simple standard DACs are stereo only */ -+ return put_user(AUDIO_CHANNELS, (long *) arg); -+ -+ case SNDCTL_DSP_SPEED: -+ case SOUND_PCM_READ_RATE: -+ /* We assume the clock doesn't change */ -+ return put_user(sample_rate, (long *) arg); -+ -+ case SNDCTL_DSP_SETFMT: -+ case SNDCTL_DSP_GETFMTS: -+ /* Simple standard DACs are 16-bit only */ -+ return put_user(AUDIO_FMT, (long *) arg); -+ -+ default: -+ return -EINVAL; -+ } -+ -+ return ret; -+} -+ -+static audio_stream_t output_stream; -+ -+static audio_state_t audio_state = { -+ output_stream: &output_stream, -+ output_dma: DMA_Ser4SSPWr, -+ output_id: "Generic SSP sound", -+ hw_init: ssp_audio_init, -+ hw_shutdown: ssp_audio_shutdown, -+ client_ioctl: ssp_audio_ioctl, -+ sem: __MUTEX_INITIALIZER(audio_state.sem), -+}; -+ -+static int ssp_audio_open(struct inode *inode, struct file *file) -+{ -+ return sa1100_audio_attach(inode, file, &audio_state); -+} -+ -+/* -+ * Missing fields of this structure will be patched with the call -+ * to sa1100_audio_attach(). -+ */ -+static struct file_operations ssp_audio_fops = { -+ open: ssp_audio_open, -+ owner: THIS_MODULE -+}; -+ -+static int audio_dev_id; -+ -+static int __init sa1100ssp_audio_init(void) -+{ -+ int ret; -+ -+ if (!machine_is_lart()) { -+ printk(KERN_ERR AUDIO_NAME ": no support for this SA-1100 design!\n"); -+ /* look at ssp_audio_init() for specific initialisations */ -+ return -ENODEV; -+ } -+ -+ /* register devices */ -+ audio_dev_id = register_sound_dsp(&ssp_audio_fops, -1); -+ -+ printk( KERN_INFO AUDIO_NAME " initialized\n" ); -+ return 0; -+} -+ -+static void __exit sa1100ssp_audio_exit(void) -+{ -+ unregister_sound_dsp(audio_dev_id); -+} -+ -+module_init(sa1100ssp_audio_init); -+module_exit(sa1100ssp_audio_exit); -+ -+MODULE_AUTHOR("Nicolas Pitre"); -+MODULE_DESCRIPTION("Glue audio driver for a simple DAC on the SA1100's SSP port"); -+ -+MODULE_PARM(sample_rate, "i"); -+MODULE_PARM_DESC(sample_rate, "Sample rate of the audio DAC, default is 44100"); -+ -+EXPORT_NO_SYMBOLS; -diff -urN linux-2.4.26/drivers/sound/sa1111-ac97.c linux-2.4.26-vrs1/drivers/sound/sa1111-ac97.c ---- linux-2.4.26/drivers/sound/sa1111-ac97.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/sound/sa1111-ac97.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,518 @@ -+/* -+ * Glue audio driver for the CS4205 and CS4201 AC'97 codecs. -+ * largely based on the framework provided by sa1111-uda1341.c. -+ * -+ * Copyright (c) 2002 Bertrik Sikken (bertrik.sikken@technolution.nl) -+ * Copyright (c) 2002 Robert Whaley (rwhaley@applieddata.net) -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License. -+ * -+ * This driver makes use of the ac97_codec module (for mixer registers) -+ * and the sa1100-audio module (for DMA). -+ * -+ * History: -+ * -+ * 2002-04-04 Initial version. -+ * 2002-04-10 Updated mtd_audio_init to improve choppy sound -+ * and hanging sound issue. -+ * 2002-05-16 Updated for ADS Bitsy+ Robert Whaley -+ * 2002-06-28 Cleanup and added retry for read register timeouts -+ * 2002-08-14 Updated for ADS AGC Robert Whaley -+ * 2002-12-26 Cleanup, remove CONFIG_PM (it's handled by sa1100-audio.c) -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "sa1100-audio.h" -+ -+/* SAC FIFO depth, low nibble is transmit fifo, high nibble is receive FIFO */ -+#define SAC_FIFO_DEPTH 0x77 -+ -+// #define DEBUG -+ -+#ifdef DEBUG -+#define DPRINTK( x... ) printk( ##x ) -+#else -+#define DPRINTK( x... ) -+#endif -+ -+/* -+ Our codec data -+*/ -+static struct ac97_codec ac97codec; -+static int audio_dev_id, mixer_dev_id; -+static audio_stream_t output_stream, input_stream; -+ -+/* proc info */ -+ -+struct proc_dir_entry *ac97_ps; -+ -+static int sa1111_ac97_set_adc_rate(long rate); -+static void sa1111_ac97_write_reg(struct ac97_codec *dev, u8 reg, u16 val); -+static u16 sa1111_ac97_read_reg(struct ac97_codec *dev, u8 reg); -+ -+static int -+mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) -+{ -+ /* -+ * We only accept mixer (type 'M') ioctls. -+ */ -+ if (_IOC_TYPE(cmd) != 'M') { -+ return -EINVAL; -+ } -+ -+ /* pass the ioctl to the ac97 mixer */ -+ return ac97codec.mixer_ioctl(&ac97codec, cmd, arg); -+} -+ -+ -+static struct file_operations sa1111_ac97_mixer_fops = { -+ ioctl: mixer_ioctl, -+ owner: THIS_MODULE -+}; -+ -+static void sa1111_ac97_power_off(void *dummy) -+{ -+#ifdef CONFIG_SA1100_ADSBITSYPLUS -+ /* turn off audio and audio amp */ -+ ADS_CPLD_PCON |= (ADS_PCON_AUDIO_ON | ADS_PCON_AUDIOPA_ON); -+ -+ /* make GPIO11 high impeadence */ -+ GPDR &= ~GPIO_GPIO11; -+ -+ /* disable SACR0 so we can make these pins high impeadence */ -+ SACR0 &= ~SACR0_ENB; -+ -+ /* make BIT_CLK, SDATA_OUT, and SYNC high impeadence */ -+ PC_DDR |= (GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); -+ -+#endif -+ -+#ifdef CONFIG_SA1100_ADSAGC -+ /* turn off audio and audio amp */ -+ ADS_CR1 &= ~(ADS_CR1_CODEC | ADS_CR1_AMP); -+ -+ /* disable SACR0 so we can make these pins high impeadence */ -+ SACR0 &= ~SACR0_ENB; -+ -+ /* make BIT_CLK, SDATA_OUT, and SYNC high impeadence */ -+ PC_DDR |= (GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); -+ -+#endif -+} -+ -+ -+static void sa1111_ac97_power_on(void *dummy) -+{ -+ int ret, i; -+ -+ /* disable L3 */ -+ SACR1 = 0; -+ -+ SKPCR |= (SKPCR_ACCLKEN); /* enable ac97 clock */ -+ udelay(50); -+ -+ /* BIT_CLK is input to SA1111, DMA thresholds 9 (both dirs) */ -+ SACR0 |= SACR0_BCKD | (SAC_FIFO_DEPTH << 8); -+ -+ /* reset SAC registers */ -+ SACR0 &= ~SACR0_RST; -+ udelay(50); -+ SACR0 |= SACR0_RST; -+ udelay(50); -+ SACR0 &= ~SACR0_RST; -+ -+ /* setup SA1111 to use AC'97 */ -+ SBI_SKCR |= SKCR_SELAC; /* select ac97 */ -+ udelay(50); -+ -+ /* issue a cold AC97 reset */ -+#ifdef CONFIG_SA1100_ADSBITSYPLUS -+ -+ /* initialize reset line */ -+ GAFR &= ~GPIO_GPIO11; -+ GPDR |= GPIO_GPIO11; -+ GPSR = GPIO_GPIO11; -+ -+ /* turn on audio and audio amp */ -+ ADS_CPLD_PCON &= ~(ADS_PCON_AUDIO_ON | ADS_PCON_AUDIOPA_ON); -+ mdelay(5); -+ -+ /* reset by lowering the reset pin momentarily */ -+ DPRINTK("reseting codec via GPIO11\n"); -+ GPCR = GPIO_GPIO11; -+ udelay(5); -+ GPSR = GPIO_GPIO11; -+ udelay(10); -+ -+#endif -+#ifdef CONFIG_SA1100_ADSAGC -+ -+ /* turn on audio and audio amp */ -+ DPRINTK("before turning on power. ADS_CR1: %x\n", ADS_CR1); -+ ADS_CR1 |= (ADS_CR1_AMP | ADS_CR1_CODEC); -+ DPRINTK("after turnning on power. ADS_CR1: %x\n", ADS_CR1); -+ mdelay(5); -+ -+ /* reset by lowering the reset pin momentarily */ -+ DPRINTK("reseting codec via CPLD\n"); -+ ADS_CR1 |= ADS_CR1_AUDIO_RST; -+ DPRINTK("after reset1. ADS_CR1: %x\n", ADS_CR1); -+ udelay(5); -+ ADS_CR1 &= ~ADS_CR1_AUDIO_RST; -+ DPRINTK("after reset2. ADS_CR1: %x\n", ADS_CR1); -+ udelay(10); -+ -+#endif -+ SACR2 = 0; -+ udelay(50); -+ -+ DPRINTK("before SW reset: SACR2: %x\n", SACR2); -+ SACR2 = SACR2_RESET; -+ DPRINTK("after SW reset: SACR2: %x\n", SACR2); -+ udelay(50); -+ -+ /* set AC97 slot 3 and 4 (PCM out) to valid */ -+ SACR2 = (SACR2_RESET | SACR2_TS3V | SACR2_TS4V); -+ -+ /* enable SAC */ -+ SACR0 |= SACR0_ENB; -+ -+ i = 100; -+ while (!(SASR1 & SASR1_CRDY)) { -+ if (!i--) { -+ printk("Didn't get CRDY. SASR1=%x SKID=%x\n", SASR1, SBI_SKID); -+ break; -+ } -+ udelay(50); -+ } -+ -+ if (!(ret = ac97_probe_codec(&ac97codec))) { -+ printk("ac97_probe_codec failed (%d)\n", ret); -+ return; -+ } -+ -+ /* mic ADC on, disable VRA, disable VRM */ -+ sa1111_ac97_write_reg(&ac97codec, AC97_EXTENDED_STATUS, 0x0200); -+} -+ -+ -+/* -+ * Audio interface -+ */ -+ -+ -+static int sa1111_ac97_audio_ioctl(struct inode *inode, struct file *file, -+ uint cmd, ulong arg) -+{ -+ long val; -+ int ret = 0; -+ -+ DPRINTK("sa1111_ac97_audio_ioctl\n"); -+ -+ /* -+ * These are platform dependent ioctls which are not handled by the -+ * generic sa1100-audio module. -+ */ -+ switch (cmd) { -+ case SNDCTL_DSP_STEREO: -+ ret = get_user(val, (int *) arg); -+ if (ret) { -+ return ret; -+ } -+ /* the cs42xx is stereo only */ -+ ret = (val == 0) ? -EINVAL : 1; -+ return put_user(ret, (int *) arg); -+ -+ case SNDCTL_DSP_CHANNELS: -+ case SOUND_PCM_READ_CHANNELS: -+ /* the cs42xx is stereo only */ -+ return put_user(2, (long *) arg); -+ -+#define SA1100_AC97_IOCTL_EXTRAS -+ -+#ifdef SA1100_AC97_IOCTL_EXTRAS -+ -+#define SNDCTL_DSP_AC97_CMD _SIOWR('P', 99, int) -+#define SNDCTL_DSP_INPUT_SPEED _SIOWR('P', 98, int) -+#define SOUND_PCM_READ_INPUT_RATE _SIOWR('P', 97, int) -+ -+ case SNDCTL_DSP_AC97_CMD: -+ -+ ret = get_user(val, (long *) arg); -+ if (ret) { -+ break; -+ } -+ sa1111_ac97_write_reg(&ac97codec, (u8) ((val & 0xff000000) >> 24), (u16) (val & 0xffff)); -+ return 0; -+ -+ -+ case SNDCTL_DSP_INPUT_SPEED: -+ ret = get_user(val, (long *) arg); -+ // acc code here to set the speed -+ if (ret) { -+ break; -+ } -+ // note that this only changes the ADC rate, not the -+ // rate of the DAC. -+ ret = sa1111_ac97_set_adc_rate(val); -+ if (ret) -+ break; -+ return put_user(val, (long *) arg); -+ -+ case SOUND_PCM_READ_INPUT_RATE: -+ -+ return put_user((long) sa1111_ac97_read_reg(&ac97codec, 0x32), (long *) arg); -+ -+ -+#endif -+ -+ case SNDCTL_DSP_SPEED: -+ ret = get_user(val, (long *) arg); -+ if (ret) { -+ break; -+ } -+ -+ case SOUND_PCM_READ_RATE: -+ /* only 48 kHz playback is supported by the SA1111 */ -+ return put_user(48000L, (long *) arg); -+ -+ case SNDCTL_DSP_SETFMT: -+ case SNDCTL_DSP_GETFMTS: -+ /* we can do 16-bit only */ -+ return put_user(AFMT_S16_LE, (long *) arg); -+ -+ default: -+ /* Maybe this is meant for the mixer (As per OSS Docs) */ -+ return mixer_ioctl(inode, file, cmd, arg); -+ } -+ -+ return ret; -+} -+ -+ -+static audio_state_t audio_state = { -+ output_stream: &output_stream, -+ input_stream: &input_stream, -+ skip_dma_init: 1, /* done locally */ -+ hw_init: sa1111_ac97_power_on, -+ hw_shutdown: sa1111_ac97_power_off, -+ client_ioctl: sa1111_ac97_audio_ioctl, -+ sem: __MUTEX_INITIALIZER(audio_state.sem), -+}; -+ -+ -+static int sa1111_ac97_audio_open(struct inode *inode, struct file *file) -+{ -+ return sa1100_audio_attach(inode, file, &audio_state); -+} -+ -+ -+/* -+ * Missing fields of this structure will be patched with the call -+ * to sa1100_audio_attach(). -+ */ -+static struct file_operations sa1111_ac97_audio_fops = { -+ open: sa1111_ac97_audio_open, -+ owner: THIS_MODULE -+}; -+ -+ -+static void sa1111_ac97_write_reg(struct ac97_codec *dev, u8 reg, u16 val) -+{ -+ int i; -+ -+ /* reset status bits */ -+ SASCR = SASCR_DTS; -+ -+ /* write command and data registers */ -+ ACCAR = reg << 12; -+ ACCDR = val << 4; -+ -+ /* wait for data to be transmitted */ -+ i = 0; -+ while ((SASR1 & SASR1_CADT) == 0) { -+ udelay(50); -+ if (++i > 10) { -+ DPRINTK("sa1111_ac97_write_reg failed (data not transmitted. SASR1: %x)\n", SASR1); -+ break; -+ } -+ } -+ -+ DPRINTK("<%03d> sa1111_ac97_write_reg, [%02X]=%04X\n", i, reg, val); -+} -+ -+ -+static u16 sa1111_ac97_read_reg(struct ac97_codec *dev, u8 reg) -+{ -+ u16 val; -+ int i; -+ int retry = 10; -+ -+ do { -+ /* reset status bits */ -+ SASCR = SASCR_RDD | SASCR_STO; -+ -+ /* write command register */ -+ ACCAR = (reg | 0x80) << 12; -+ ACCDR = 0; -+ -+ /* wait for SADR bit in SASR1 */ -+ i = 0; -+ while ((SASR1 & SASR1_SADR) == 0) { -+ udelay(50); -+ if (++i > 10) { -+ DPRINTK("<---> sa1111_ac97_read_reg failed\n"); -+ retry--; -+ break; -+ } -+ if ((SASR1 & SASR1_RSTO) != 0) { -+ DPRINTK("sa1111_ac97_read_reg *timeout*\n"); -+ retry--; -+ break; -+ } -+ } -+ -+ } while ((SASR1 & SASR1_SADR) == 0 && retry > 0); -+ -+ val = ACSDR >> 4; -+ -+ DPRINTK("<%03d> sa1111_ac97_read_reg, [%02X]=%04X\n", i, reg, val); -+ return val; -+} -+ -+ -+/* wait for codec ready */ -+static void sa1111_ac97_ready(struct ac97_codec *dev) -+{ -+ int i; -+ u16 val; -+ -+ i = 0; -+ while ((SASR1 & SASR1_CRDY) == 0) { -+ udelay(50); -+ if (++i > 10) { -+ DPRINTK("sa1111_ac97_ready failed\n"); -+ return; -+ } -+ } -+ DPRINTK("codec_ready bit took %d cycles\n", i); -+ -+ /* Wait for analog parts of codec to initialise */ -+ i = 0; -+ do { -+ val = sa1111_ac97_read_reg(&ac97codec, AC97_POWER_CONTROL); -+ if (++i > 100) { -+ break; -+ } -+ mdelay(10); -+ } while ((val & 0xF) != 0xF || val == 0xFFFF); -+ -+ /* the cs42xx typically takes 150 ms to initialise */ -+ -+ DPRINTK("analog init took %d cycles\n", i); -+} -+ -+ -+static int __init sa1111_ac97_init(void) -+{ -+ int ret; -+ -+ // SBI_SKCR |= SKCR_RCLKEN; -+ -+ DPRINTK("sa1111_ac97_init\n"); -+ -+ /* install the ac97 mixer module */ -+ ac97codec.codec_read = sa1111_ac97_read_reg; -+ ac97codec.codec_write = sa1111_ac97_write_reg; -+ ac97codec.codec_wait = sa1111_ac97_ready; -+ -+ /* Acquire and initialize DMA */ -+ ret = sa1111_sac_request_dma(&output_stream.dma_ch, "SA1111 audio out", -+ SA1111_SAC_XMT_CHANNEL); -+ if (ret < 0) { -+ printk("DMA request for SAC output failed\n"); -+ return ret; -+ } -+ -+ ret = sa1111_sac_request_dma(&input_stream.dma_ch, "SA1111 audio in", -+ SA1111_SAC_RCV_CHANNEL); -+ if (ret < 0) { -+ printk("DMA request for SAC input failed\n"); -+ sa1100_free_dma(output_stream.dma_ch); -+ return ret; -+ } -+ /* register devices */ -+ audio_dev_id = register_sound_dsp(&sa1111_ac97_audio_fops, -1); -+ mixer_dev_id = register_sound_mixer(&sa1111_ac97_mixer_fops, -1); -+ -+ -+ /* setup proc entry */ -+ ac97_ps = create_proc_read_entry ("driver/sa1111-ac97", 0, NULL, -+ ac97_read_proc, &ac97codec); -+ -+ return 0; -+} -+ -+ -+static void __exit sa1111_ac97_exit(void) -+{ -+ SKPCR &= ~SKPCR_ACCLKEN; /* disable ac97 clock */ -+ SBI_SKCR &= ~SKCR_SELAC; /* deselect ac97 */ -+ -+ unregister_sound_dsp(audio_dev_id); -+ unregister_sound_mixer(mixer_dev_id); -+ sa1100_free_dma(output_stream.dma_ch); -+ sa1100_free_dma(input_stream.dma_ch); -+} -+ -+static int sa1111_ac97_set_adc_rate(long rate) -+{ -+ -+ // note this only changes the rate of the ADC, the DAC is fixed at 48K. -+ // this is due to limitations of the SA1111 chip -+ -+ u16 code = rate; -+ -+ switch (rate) { -+ case 8000: -+ case 11025: -+ case 16000: -+ case 22050: -+ case 32000: -+ case 44100: -+ case 48000: -+ break; -+ default: -+ return -1; -+ } -+ sa1111_ac97_write_reg(&ac97codec, 0x2A, 0x0001); -+ sa1111_ac97_write_reg(&ac97codec, 0x32, code); -+ return 0; -+} -+ -+module_init(sa1111_ac97_init); -+module_exit(sa1111_ac97_exit); -+ -+MODULE_AUTHOR("Bertrik Sikken, Technolution B.V., Netherlands"); -+MODULE_DESCRIPTION("Glue audio driver for AC'97 codec"); -+MODULE_LICENSE("GPL"); -+ -+EXPORT_NO_SYMBOLS; -diff -urN linux-2.4.26/drivers/sound/sa1111-uda1341.c linux-2.4.26-vrs1/drivers/sound/sa1111-uda1341.c ---- linux-2.4.26/drivers/sound/sa1111-uda1341.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/sound/sa1111-uda1341.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,282 @@ -+/* -+ * Glue audio driver for the SA1111 compagnon chip & Philips UDA1341 codec. -+ * -+ * Copyright (c) 2000 John Dorsey -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License. -+ * -+ * History: -+ * -+ * 2000-09-04 John Dorsey SA-1111 Serial Audio Controller support -+ * was initially added to the sa1100-uda1341.c -+ * driver. -+ * -+ * 2001-06-03 Nicolas Pitre Made this file a separate module, based on -+ * the former sa1100-uda1341.c driver. -+ * -+ * 2001-09-23 Russell King Remove old L3 bus driver. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "sa1100-audio.h" -+ -+#undef DEBUG -+#ifdef DEBUG -+#define DPRINTK( x... ) printk( ##x ) -+#else -+#define DPRINTK( x... ) -+#endif -+ -+ -+/* -+ * Definitions -+ */ -+ -+#define AUDIO_RATE_DEFAULT 22050 -+ -+#define AUDIO_CLK_BASE 561600 -+ -+ -+ -+/* -+ * Mixer interface -+ */ -+ -+static struct l3_client uda1341; -+ -+static int -+mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) -+{ -+ /* -+ * We only accept mixer (type 'M') ioctls. -+ */ -+ if (_IOC_TYPE(cmd) != 'M') -+ return -EINVAL; -+ -+ return l3_command(&uda1341, cmd, (void *)arg); -+} -+ -+static struct file_operations uda1341_mixer_fops = { -+ ioctl: mixer_ioctl, -+ owner: THIS_MODULE -+}; -+ -+ -+/* -+ * Audio interface -+ */ -+ -+static int audio_clk_div = (AUDIO_CLK_BASE + AUDIO_RATE_DEFAULT/2)/AUDIO_RATE_DEFAULT; -+ -+static void sa1111_audio_init(void *dummy) -+{ -+#ifdef CONFIG_ASSABET_NEPONSET -+ if (machine_is_assabet()) { -+ /* Select I2S audio (instead of AC-Link) */ -+ AUD_CTL = AUD_SEL_1341; -+ } -+#endif -+#ifdef CONFIG_SA1100_JORNADA720 -+ if (machine_is_jornada720()) { -+ /* LDD4 is speaker, LDD3 is microphone */ -+ PPSR &= ~(PPC_LDD3 | PPC_LDD4); -+ PPDR |= PPC_LDD3 | PPC_LDD4; -+ PPSR |= PPC_LDD4; /* enable speaker */ -+ PPSR |= PPC_LDD3; /* enable microphone */ -+ } -+#endif -+ -+ SBI_SKCR &= ~SKCR_SELAC; -+ -+ /* Enable the I2S clock and L3 bus clock: */ -+ SKPCR |= (SKPCR_I2SCLKEN | SKPCR_L3CLKEN); -+ -+ /* Activate and reset the Serial Audio Controller */ -+ SACR0 |= (SACR0_ENB | SACR0_RST); -+ mdelay(5); -+ SACR0 &= ~SACR0_RST; -+ -+ /* For I2S, BIT_CLK is supplied internally. The "SA-1111 -+ * Specification Update" mentions that the BCKD bit should -+ * be interpreted as "0 = output". Default clock divider -+ * is 22.05kHz. -+ * -+ * Select I2S, L3 bus. "Recording" and "Replaying" -+ * (receive and transmit) are enabled. -+ */ -+ SACR1 = SACR1_L3EN; -+ SKAUD = audio_clk_div - 1; -+ -+ /* Initialize the UDA1341 internal state */ -+ l3_open(&uda1341); -+} -+ -+static void sa1111_audio_shutdown(void *dummy) -+{ -+ l3_close(&uda1341); -+ SACR0 &= ~SACR0_ENB; -+} -+ -+static int sa1111_audio_ioctl( struct inode *inode, struct file *file, -+ uint cmd, ulong arg) -+{ -+ long val; -+ int ret = 0; -+ -+ switch (cmd) { -+ case SNDCTL_DSP_STEREO: -+ ret = get_user(val, (int *) arg); -+ if (ret) -+ return ret; -+ /* the UDA1341 is stereo only */ -+ ret = (val == 0) ? -EINVAL : 1; -+ return put_user(ret, (int *) arg); -+ -+ case SNDCTL_DSP_CHANNELS: -+ case SOUND_PCM_READ_CHANNELS: -+ /* the UDA1341 is stereo only */ -+ return put_user(2, (long *) arg); -+ -+ case SNDCTL_DSP_SPEED: -+ ret = get_user(val, (long *) arg); -+ if (ret) break; -+ if (val < 8000) val = 8000; -+ if (val > 48000) val = 48000; -+ audio_clk_div = (AUDIO_CLK_BASE + val/2)/val; -+ SKAUD = audio_clk_div - 1; -+ /* fall through */ -+ -+ case SOUND_PCM_READ_RATE: -+ return put_user(AUDIO_CLK_BASE/audio_clk_div, (long *) arg); -+ -+ case SNDCTL_DSP_SETFMT: -+ case SNDCTL_DSP_GETFMTS: -+ /* we can do 16-bit only */ -+ return put_user(AFMT_S16_LE, (long *) arg); -+ -+ default: -+ /* Maybe this is meant for the mixer (as per OSS Docs) */ -+ return mixer_ioctl(inode, file, cmd, arg); -+ } -+ -+ return ret; -+} -+ -+static audio_stream_t output_stream, input_stream; -+ -+static audio_state_t audio_state = { -+ output_stream: &output_stream, -+ input_stream: &input_stream, -+ skip_dma_init: 1, /* done locally */ -+ hw_init: sa1111_audio_init, -+ hw_shutdown: sa1111_audio_shutdown, -+ client_ioctl: sa1111_audio_ioctl, -+ sem: __MUTEX_INITIALIZER(audio_state.sem), -+}; -+ -+static int sa1111_audio_open(struct inode *inode, struct file *file) -+{ -+ return sa1100_audio_attach(inode, file, &audio_state); -+} -+ -+/* -+ * Missing fields of this structure will be patched with the call -+ * to sa1100_audio_attach(). -+ */ -+static struct file_operations sa1111_audio_fops = { -+ open: sa1111_audio_open, -+ owner: THIS_MODULE -+}; -+ -+static int audio_dev_id, mixer_dev_id; -+ -+static int __init sa1111_uda1341_init(void) -+{ -+ struct uda1341_cfg cfg; -+ int ret; -+ -+ if ( !( (machine_is_assabet() && machine_has_neponset()) || -+ machine_is_jornada720() || -+ machine_is_badge4() )) -+ return -ENODEV; -+ -+ if (!request_mem_region(_SACR0, 512, "sound")) -+ return -EBUSY; -+ -+ ret = l3_attach_client(&uda1341, "l3-sa1111", "uda1341"); -+ if (ret) -+ goto out; -+ -+ /* Acquire and initialize DMA */ -+ ret = sa1111_sac_request_dma(&output_stream.dma_ch, "SA1111 audio out", -+ SA1111_SAC_XMT_CHANNEL); -+ if (ret < 0) -+ goto release_l3; -+ -+ ret = sa1111_sac_request_dma(&input_stream.dma_ch, "SA1111 audio in", -+ SA1111_SAC_RCV_CHANNEL); -+ if (ret < 0) -+ goto release_dma; -+ -+ cfg.fs = 256; -+ cfg.format = FMT_I2S; -+ l3_command(&uda1341, L3_UDA1341_CONFIGURE, &cfg); -+ -+ /* register devices */ -+ audio_dev_id = register_sound_dsp(&sa1111_audio_fops, -1); -+ mixer_dev_id = register_sound_mixer(&uda1341_mixer_fops, -1); -+ -+ printk(KERN_INFO "Sound: SA1111 UDA1341: dsp id %d mixer id %d\n", -+ audio_dev_id, mixer_dev_id); -+ return 0; -+ -+release_dma: -+ sa1100_free_dma(output_stream.dma_ch); -+release_l3: -+ l3_detach_client(&uda1341); -+out: -+ release_mem_region(_SACR0, 512); -+ return ret; -+} -+ -+static void __exit sa1111_uda1341_exit(void) -+{ -+ unregister_sound_dsp(audio_dev_id); -+ unregister_sound_mixer(mixer_dev_id); -+ sa1100_free_dma(output_stream.dma_ch); -+ sa1100_free_dma(input_stream.dma_ch); -+ l3_detach_client(&uda1341); -+ -+ release_mem_region(_SACR0, 512); -+} -+ -+module_init(sa1111_uda1341_init); -+module_exit(sa1111_uda1341_exit); -+ -+MODULE_AUTHOR("John Dorsey, Nicolas Pitre"); -+MODULE_DESCRIPTION("Glue audio driver for the SA1111 compagnon chip & Philips UDA1341 codec."); -+ -+EXPORT_NO_SYMBOLS; -diff -urN linux-2.4.26/drivers/sound/uda1341.c linux-2.4.26-vrs1/drivers/sound/uda1341.c ---- linux-2.4.26/drivers/sound/uda1341.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/sound/uda1341.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,511 @@ -+/* -+ * Philips UDA1341 mixer device driver -+ * -+ * Copyright (c) 2000 Nicolas Pitre -+ * -+ * Portions are Copyright (C) 2000 Lernout & Hauspie Speech Products, N.V. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License. -+ * -+ * History: -+ * -+ * 2000-05-21 Nicolas Pitre Initial release. -+ * -+ * 2000-08-19 Erik Bunce More inline w/ OSS API and UDA1341 docs -+ * including fixed AGC and audio source handling -+ * -+ * 2000-11-30 Nicolas Pitre - More mixer functionalities. -+ * -+ * 2001-06-03 Nicolas Pitre Made this file a separate module, based on -+ * the former sa1100-uda1341.c driver. -+ * -+ * 2001-08-13 Russell King Re-written as part of the L3 interface -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define DEF_VOLUME 65 -+ -+/* -+ * UDA1341 L3 address and command types -+ */ -+#define UDA1341_L3ADDR 5 -+#define UDA1341_DATA0 (UDA1341_L3ADDR << 2 | 0) -+#define UDA1341_DATA1 (UDA1341_L3ADDR << 2 | 1) -+#define UDA1341_STATUS (UDA1341_L3ADDR << 2 | 2) -+ -+struct uda1341_regs { -+ unsigned char stat0; -+#define STAT0 0x00 -+#define STAT0_RST (1 << 6) -+#define STAT0_SC_MASK (3 << 4) -+#define STAT0_SC_512FS (0 << 4) -+#define STAT0_SC_384FS (1 << 4) -+#define STAT0_SC_256FS (2 << 4) -+#define STAT0_IF_MASK (7 << 1) -+#define STAT0_IF_I2S (0 << 1) -+#define STAT0_IF_LSB16 (1 << 1) -+#define STAT0_IF_LSB18 (2 << 1) -+#define STAT0_IF_LSB20 (3 << 1) -+#define STAT0_IF_MSB (4 << 1) -+#define STAT0_IF_LSB16MSB (5 << 1) -+#define STAT0_IF_LSB18MSB (6 << 1) -+#define STAT0_IF_LSB20MSB (7 << 1) -+#define STAT0_DC_FILTER (1 << 0) -+ -+ unsigned char stat1; -+#define STAT1 0x80 -+#define STAT1_DAC_GAIN (1 << 6) /* gain of DAC */ -+#define STAT1_ADC_GAIN (1 << 5) /* gain of ADC */ -+#define STAT1_ADC_POL (1 << 4) /* polarity of ADC */ -+#define STAT1_DAC_POL (1 << 3) /* polarity of DAC */ -+#define STAT1_DBL_SPD (1 << 2) /* double speed playback */ -+#define STAT1_ADC_ON (1 << 1) /* ADC powered */ -+#define STAT1_DAC_ON (1 << 0) /* DAC powered */ -+ -+ unsigned char data0_0; -+#define DATA0 0x00 -+#define DATA0_VOLUME_MASK 0x3f -+#define DATA0_VOLUME(x) (x) -+ -+ unsigned char data0_1; -+#define DATA1 0x40 -+#define DATA1_BASS(x) ((x) << 2) -+#define DATA1_BASS_MASK (15 << 2) -+#define DATA1_TREBLE(x) ((x)) -+#define DATA1_TREBLE_MASK (3) -+ -+ unsigned char data0_2; -+#define DATA2 0x80 -+#define DATA2_PEAKAFTER (1 << 5) -+#define DATA2_DEEMP_NONE (0 << 3) -+#define DATA2_DEEMP_32KHz (1 << 3) -+#define DATA2_DEEMP_44KHz (2 << 3) -+#define DATA2_DEEMP_48KHz (3 << 3) -+#define DATA2_MUTE (1 << 2) -+#define DATA2_FILTER_FLAT (0 << 0) -+#define DATA2_FILTER_MIN (1 << 0) -+#define DATA2_FILTER_MAX (3 << 0) -+ -+#define EXTADDR(n) (0xc0 | (n)) -+#define EXTDATA(d) (0xe0 | (d)) -+ -+ unsigned char ext0; -+#define EXT0 0 -+#define EXT0_CH1_GAIN(x) (x) -+ -+ unsigned char ext1; -+#define EXT1 1 -+#define EXT1_CH2_GAIN(x) (x) -+ -+ unsigned char ext2; -+#define EXT2 2 -+#define EXT2_MIC_GAIN_MASK (7 << 2) -+#define EXT2_MIC_GAIN(x) ((x) << 2) -+#define EXT2_MIXMODE_DOUBLEDIFF (0) -+#define EXT2_MIXMODE_CH1 (1) -+#define EXT2_MIXMODE_CH2 (2) -+#define EXT2_MIXMODE_MIX (3) -+ -+ unsigned char ext4; -+#define EXT4 4 -+#define EXT4_AGC_ENABLE (1 << 4) -+#define EXT4_INPUT_GAIN_MASK (3) -+#define EXT4_INPUT_GAIN(x) ((x) & 3) -+ -+ unsigned char ext5; -+#define EXT5 5 -+#define EXT5_INPUT_GAIN(x) ((x) >> 2) -+ -+ unsigned char ext6; -+#define EXT6 6 -+#define EXT6_AGC_CONSTANT_MASK (7 << 2) -+#define EXT6_AGC_CONSTANT(x) ((x) << 2) -+#define EXT6_AGC_LEVEL_MASK (3) -+#define EXT6_AGC_LEVEL(x) (x) -+}; -+ -+#define REC_MASK (SOUND_MASK_LINE | SOUND_MASK_MIC) -+#define DEV_MASK (REC_MASK | SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE) -+ -+struct uda1341 { -+ struct uda1341_regs regs; -+ int active; -+ unsigned short volume; -+ unsigned short bass; -+ unsigned short treble; -+ unsigned short line; -+ unsigned short mic; -+ int mod_cnt; -+}; -+ -+#define ADD_FIELD(reg,field) \ -+ *p++ = reg | uda->regs.field -+ -+#define ADD_EXTFIELD(reg,field) \ -+ *p++ = EXTADDR(reg); \ -+ *p++ = EXTDATA(uda->regs.field); -+ -+static void uda1341_sync(struct l3_client *clnt) -+{ -+ struct uda1341 *uda = clnt->driver_data; -+ char buf[24], *p = buf; -+ -+ ADD_FIELD(STAT0, stat0); -+ ADD_FIELD(STAT1, stat1); -+ -+ if (p != buf) -+ l3_write(clnt, UDA1341_STATUS, buf, p - buf); -+ -+ p = buf; -+ ADD_FIELD(DATA0, data0_0); -+ ADD_FIELD(DATA1, data0_1); -+ ADD_FIELD(DATA2, data0_2); -+ ADD_EXTFIELD(EXT0, ext0); -+ ADD_EXTFIELD(EXT1, ext1); -+ ADD_EXTFIELD(EXT2, ext2); -+ ADD_EXTFIELD(EXT4, ext4); -+ ADD_EXTFIELD(EXT5, ext5); -+ ADD_EXTFIELD(EXT6, ext6); -+ -+ if (p != buf) -+ l3_write(clnt, UDA1341_DATA0, buf, p - buf); -+} -+ -+static void uda1341_cmd_init(struct l3_client *clnt) -+{ -+ struct uda1341 *uda = clnt->driver_data; -+ char buf[2]; -+ -+ uda->active = 1; -+ -+ buf[0] = uda->regs.stat0 | STAT0_RST; -+ buf[1] = uda->regs.stat0; -+ -+ l3_write(clnt, UDA1341_STATUS, buf, 2); -+ -+ /* resend all parameters */ -+ uda1341_sync(clnt); -+} -+ -+static int uda1341_configure(struct l3_client *clnt, struct uda1341_cfg *conf) -+{ -+ struct uda1341 *uda = clnt->driver_data; -+ int ret = 0; -+ -+ uda->regs.stat0 &= ~(STAT0_SC_MASK | STAT0_IF_MASK); -+ -+ switch (conf->fs) { -+ case 512: uda->regs.stat0 |= STAT0_SC_512FS; break; -+ case 384: uda->regs.stat0 |= STAT0_SC_384FS; break; -+ case 256: uda->regs.stat0 |= STAT0_SC_256FS; break; -+ default: ret = -EINVAL; break; -+ } -+ -+ switch (conf->format) { -+ case FMT_I2S: uda->regs.stat0 |= STAT0_IF_I2S; break; -+ case FMT_LSB16: uda->regs.stat0 |= STAT0_IF_LSB16; break; -+ case FMT_LSB18: uda->regs.stat0 |= STAT0_IF_LSB18; break; -+ case FMT_LSB20: uda->regs.stat0 |= STAT0_IF_LSB20; break; -+ case FMT_MSB: uda->regs.stat0 |= STAT0_IF_MSB; break; -+ case FMT_LSB16MSB: uda->regs.stat0 |= STAT0_IF_LSB16MSB; break; -+ case FMT_LSB18MSB: uda->regs.stat0 |= STAT0_IF_LSB18MSB; break; -+ case FMT_LSB20MSB: uda->regs.stat0 |= STAT0_IF_LSB20MSB; break; -+ } -+ -+ if (ret == 0 && uda->active) { -+ char buf = uda->regs.stat0 | STAT0; -+ l3_write(clnt, UDA1341_STATUS, &buf, 1); -+ } -+ return ret; -+} -+ -+static int uda1341_update_direct(struct l3_client *clnt, int cmd, void *arg) -+{ -+ struct uda1341 *uda = clnt->driver_data; -+ struct l3_gain *v = arg; -+ char newreg; -+ int val; -+ -+ switch (cmd) { -+ case L3_SET_VOLUME: /* set volume. val = 0 to 100 => 62 to 1 */ -+ uda->regs.data0_0 = DATA0_VOLUME(62 - ((v->left * 61) / 100)); -+ newreg = uda->regs.data0_0 | DATA0; -+ break; -+ -+ case L3_SET_BASS: /* set bass. val = 50 to 100 => 0 to 12 */ -+ val = v->left - 50; -+ if (val < 0) -+ val = 0; -+ uda->regs.data0_1 &= ~DATA1_BASS_MASK; -+ uda->regs.data0_1 |= DATA1_BASS((val * 12) / 50); -+ newreg = uda->regs.data0_1 | DATA1; -+ break; -+ -+ case L3_SET_TREBLE: /* set treble. val = 50 to 100 => 0 to 3 */ -+ val = v->left - 50; -+ if (val < 0) -+ val = 0; -+ uda->regs.data0_1 &= ~DATA1_TREBLE_MASK; -+ uda->regs.data0_1 |= DATA1_TREBLE((val * 3) / 50); -+ newreg = uda->regs.data0_1 | DATA1; -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ -+ if (uda->active) -+ l3_write(clnt, UDA1341_DATA0, &newreg, 1); -+ return 0; -+} -+ -+static int uda1341_update_indirect(struct l3_client *clnt, int cmd, void *arg) -+{ -+ struct uda1341 *uda = clnt->driver_data; -+ struct l3_gain *gain = arg; -+ struct l3_agc *agc = arg; -+ char buf[8], *p = buf; -+ int val, ret = 0; -+ -+ switch (cmd) { -+ case L3_SET_GAIN: -+ val = 31 - (gain->left * 31 / 100); -+ switch (gain->channel) { -+ case 1: -+ uda->regs.ext0 = EXT0_CH1_GAIN(val); -+ ADD_EXTFIELD(EXT0, ext0); -+ break; -+ -+ case 2: -+ uda->regs.ext1 = EXT1_CH2_GAIN(val); -+ ADD_EXTFIELD(EXT1, ext1); -+ break; -+ -+ default: -+ ret = -EINVAL; -+ } -+ break; -+ -+ case L3_INPUT_AGC: -+ if (agc->channel == 2) { -+ if (agc->enable) -+ uda->regs.ext4 |= EXT4_AGC_ENABLE; -+ else -+ uda->regs.ext4 &= ~EXT4_AGC_ENABLE; -+#if 0 -+ agc->level -+ agc->attack -+ agc->decay -+#endif -+ ADD_EXTFIELD(EXT4, ext4); -+ } else -+ ret = -EINVAL; -+ break; -+ -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+ if (ret == 0 && uda->active) -+ l3_write(clnt, UDA1341_DATA0, buf, p - buf); -+ -+ return ret; -+} -+ -+static int uda1341_mixer_ioctl(struct l3_client *clnt, int cmd, void *arg) -+{ -+ struct uda1341 *uda = clnt->driver_data; -+ struct l3_gain gain; -+ int val, nr = _IOC_NR(cmd), ret = 0; -+ -+ if (cmd == SOUND_MIXER_INFO) { -+ struct mixer_info mi; -+ -+ strncpy(mi.id, "UDA1341", sizeof(mi.id)); -+ strncpy(mi.name, "Philips UDA1341", sizeof(mi.name)); -+ mi.modify_counter = uda->mod_cnt; -+ return copy_to_user(arg, &mi, sizeof(mi)); -+ } -+ -+ if (_IOC_DIR(cmd) & _IOC_WRITE) { -+ ret = get_user(val, (int *)arg); -+ if (ret) -+ goto out; -+ -+ gain.left = val & 255; -+ gain.right = val >> 8; -+ gain.channel = 0; -+ -+ switch (nr) { -+ case SOUND_MIXER_VOLUME: -+ uda->volume = val; -+ uda->mod_cnt++; -+ uda1341_update_direct(clnt, L3_SET_VOLUME, &gain); -+ break; -+ -+ case SOUND_MIXER_BASS: -+ uda->bass = val; -+ uda->mod_cnt++; -+ uda1341_update_direct(clnt, L3_SET_BASS, &gain); -+ break; -+ -+ case SOUND_MIXER_TREBLE: -+ uda->treble = val; -+ uda->mod_cnt++; -+ uda1341_update_direct(clnt, L3_SET_TREBLE, &gain); -+ break; -+ -+ case SOUND_MIXER_LINE: -+ uda->line = val; -+ gain.channel = 1; -+ uda->mod_cnt++; -+ uda1341_update_indirect(clnt, L3_SET_GAIN, &gain); -+ break; -+ -+ case SOUND_MIXER_MIC: -+ uda->mic = val; -+ gain.channel = 2; -+ uda->mod_cnt++; -+ uda1341_update_indirect(clnt, L3_SET_GAIN, &gain); -+ break; -+ -+ case SOUND_MIXER_RECSRC: -+ break; -+ -+ default: -+ ret = -EINVAL; -+ } -+ } -+ -+ if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) { -+ int nr = _IOC_NR(cmd); -+ ret = 0; -+ -+ switch (nr) { -+ case SOUND_MIXER_VOLUME: val = uda->volume; break; -+ case SOUND_MIXER_BASS: val = uda->bass; break; -+ case SOUND_MIXER_TREBLE: val = uda->treble; break; -+ case SOUND_MIXER_LINE: val = uda->line; break; -+ case SOUND_MIXER_MIC: val = uda->mic; break; -+ case SOUND_MIXER_RECSRC: val = REC_MASK; break; -+ case SOUND_MIXER_RECMASK: val = REC_MASK; break; -+ case SOUND_MIXER_DEVMASK: val = DEV_MASK; break; -+ case SOUND_MIXER_CAPS: val = 0; break; -+ case SOUND_MIXER_STEREODEVS: val = 0; break; -+ default: val = 0; ret = -EINVAL; break; -+ } -+ -+ if (ret == 0) -+ ret = put_user(val, (int *)arg); -+ } -+out: -+ return ret; -+} -+ -+static int uda1341_attach(struct l3_client *clnt) -+{ -+ struct uda1341 *uda; -+ -+ uda = kmalloc(sizeof(*uda), GFP_KERNEL); -+ if (!uda) -+ return -ENOMEM; -+ -+ memset(uda, 0, sizeof(*uda)); -+ -+ uda->volume = DEF_VOLUME | DEF_VOLUME << 8; -+ uda->bass = 50 | 50 << 8; -+ uda->treble = 50 | 50 << 8; -+ uda->line = 88 | 88 << 8; -+ uda->mic = 88 | 88 << 8; -+ -+ uda->regs.stat0 = STAT0_SC_256FS | STAT0_IF_LSB16; -+ uda->regs.stat1 = STAT1_DAC_GAIN | STAT1_ADC_GAIN | -+ STAT1_ADC_ON | STAT1_DAC_ON; -+ uda->regs.data0_0 = DATA0_VOLUME(62 - ((DEF_VOLUME * 61) / 100)); -+ uda->regs.data0_1 = DATA1_BASS(0) | DATA1_TREBLE(0); -+ uda->regs.data0_2 = DATA2_PEAKAFTER | DATA2_DEEMP_NONE | -+ DATA2_FILTER_MAX; -+ uda->regs.ext0 = EXT0_CH1_GAIN(4); -+ uda->regs.ext1 = EXT1_CH2_GAIN(4); -+ uda->regs.ext2 = EXT2_MIXMODE_MIX | EXT2_MIC_GAIN(4); -+ uda->regs.ext4 = EXT4_AGC_ENABLE | EXT4_INPUT_GAIN(0); -+ uda->regs.ext5 = EXT5_INPUT_GAIN(0); -+ uda->regs.ext6 = EXT6_AGC_CONSTANT(3) | EXT6_AGC_LEVEL(0); -+ -+ clnt->driver_data = uda; -+ -+ return 0; -+} -+ -+static void uda1341_detach(struct l3_client *clnt) -+{ -+ kfree(clnt->driver_data); -+} -+ -+static int -+uda1341_command(struct l3_client *clnt, int cmd, void *arg) -+{ -+ int ret = -EINVAL; -+ -+ if (_IOC_TYPE(cmd) == 'M') -+ ret = uda1341_mixer_ioctl(clnt, cmd, arg); -+ else if (cmd == L3_UDA1341_CONFIGURE) -+ ret = uda1341_configure(clnt, arg); -+ -+ return ret; -+} -+ -+static int uda1341_open(struct l3_client *clnt) -+{ -+ uda1341_cmd_init(clnt); -+ return 0; -+} -+ -+static void uda1341_close(struct l3_client *clnt) -+{ -+ struct uda1341 *uda = clnt->driver_data; -+ uda->active = 0; -+} -+ -+static struct l3_ops uda1341_ops = { -+ open: uda1341_open, -+ command: uda1341_command, -+ close: uda1341_close, -+}; -+ -+static struct l3_driver uda1341 = { -+ name: UDA1341_NAME, -+ attach_client: uda1341_attach, -+ detach_client: uda1341_detach, -+ ops: &uda1341_ops, -+ owner: THIS_MODULE, -+}; -+ -+static int __init uda1341_init(void) -+{ -+ return l3_add_driver(&uda1341); -+} -+ -+static void __exit uda1341_exit(void) -+{ -+ l3_del_driver(&uda1341); -+} -+ -+module_init(uda1341_init); -+module_exit(uda1341_exit); -+ -+MODULE_AUTHOR("Nicolas Pitre"); -+MODULE_DESCRIPTION("Philips UDA1341 CODEC driver"); -diff -urN linux-2.4.26/drivers/sound/vidc.c linux-2.4.26-vrs1/drivers/sound/vidc.c ---- linux-2.4.26/drivers/sound/vidc.c 2001-10-11 17:43:30.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/sound/vidc.c 2004-01-14 21:32:26.000000000 +0000 -@@ -40,6 +40,7 @@ - #endif - - #define VIDC_SOUND_CLOCK (250000) -+#define VIDC_SOUND_CLOCK_EXT (176400) - - /* - * When using SERIAL SOUND mode (external DAC), the number of physical -@@ -192,28 +193,43 @@ - return vidc_audio_format; - } - -+#define my_abs(i) ((i)<0 ? -(i) : (i)) -+ - static int vidc_audio_set_speed(int dev, int rate) - { - if (rate) { -- unsigned int hwctrl, hwrate; -+ unsigned int hwctrl, hwrate, hwrate_ext, rate_int, rate_ext; - unsigned int newsize, new2size; - -- /* -- * If we have selected 44.1kHz, use the DAC clock. -- */ -- if (0 && rate == 44100) { -- hwctrl = 0x00000002; -- hwrate = 3; -- } else { -- hwctrl = 0x00000003; -+ hwctrl = 0x00000003; - -- hwrate = (((VIDC_SOUND_CLOCK * 2) / rate) + 1) >> 1; -- if (hwrate < 3) -- hwrate = 3; -- if (hwrate > 255) -- hwrate = 255; -+ /* Using internal clock */ -+ hwrate = (((VIDC_SOUND_CLOCK * 2) / rate) + 1) >> 1; -+ if (hwrate < 3) -+ hwrate = 3; -+ if (hwrate > 255) -+ hwrate = 255; - -- rate = VIDC_SOUND_CLOCK / hwrate; -+ /* Using exernal clock */ -+ hwrate_ext = (((VIDC_SOUND_CLOCK_EXT * 2) / rate) + 1) >> 1; -+ if (hwrate_ext < 3) -+ hwrate_ext = 3; -+ if (hwrate_ext > 255) -+ hwrate_ext = 255; -+ -+ rate_int = VIDC_SOUND_CLOCK / hwrate; -+ rate_ext = VIDC_SOUND_CLOCK_EXT / hwrate_ext; -+ -+ /* Chose between external and internal clock */ -+ if (my_abs(rate_ext-rate) < my_abs(rate_int-rate)) { -+ /*printk("VIDC: external %d %d %d\n", rate, rate_ext, hwrate_ext);*/ -+ hwrate=hwrate_ext; -+ hwctrl=0x00000002; -+ rate=rate_ext; -+ } else { -+ /*printk("VIDC: internal %d %d %d\n", rate, rate_int, hwrate);*/ -+ hwctrl=0x00000003; -+ rate=rate_int; - } - - vidc_writel(0xb0000000 | (hwrate - 2)); -@@ -225,13 +241,14 @@ - if (newsize > 4096) - newsize = 4096; - for (new2size = 128; new2size < newsize; new2size <<= 1); -- if (new2size - newsize > newsize - (new2size >> 1)) -- new2size >>= 1; -+ if (new2size - newsize > newsize - (new2size >> 1)) -+ new2size >>= 1; - if (new2size > 4096) { - printk(KERN_ERR "VIDC: error: dma buffer (%d) %d > 4K\n", - newsize, new2size); - new2size = 4096; - } -+ /*printk("VIDC: dma size %d\n", new2size);*/ - dma_bufsize = new2size; - vidc_audio_rate = rate; - } -diff -urN linux-2.4.26/drivers/sound/waveartist.c linux-2.4.26-vrs1/drivers/sound/waveartist.c ---- linux-2.4.26/drivers/sound/waveartist.c 2001-10-25 21:53:52.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/sound/waveartist.c 2004-01-14 21:32:26.000000000 +0000 -@@ -247,17 +247,15 @@ - printk("\n"); - } - -- if (inb(io_base + STATR) & CMD_RF) { -- int old_data; -- -- /* flush the port -- */ -+ /* -+ * flush any stale command data from the port. -+ */ -+ while (inb(io_base + STATR) & CMD_RF) { -+ unsigned int old_data; - - old_data = inw(io_base + CMDR); -- -- if (debug_flg & DEBUG_CMD) -- printk("flushed %04X...", old_data); -- -+ printk("waveartist: flushing stale command data: 0x%04x pc=%p\n", -+ old_data, __builtin_return_address(0)); - udelay(10); - } - -@@ -287,16 +285,19 @@ - resp[i] = inw(io_base + CMDR); - } - -- if (debug_flg & DEBUG_CMD) { -- if (!timed_out) { -- printk("waveartist_cmd: resp="); -- -- for (i = 0; i < nr_resp; i++) -- printk("%04X ", resp[i]); -- -- printk("\n"); -- } else -- printk("waveartist_cmd: timed out\n"); -+ if (debug_flg & DEBUG_CMD && !timed_out) { -+ printk("waveartist_cmd: resp="); -+ -+ for (i = 0; i < nr_resp; i++) -+ printk("%04X ", resp[i]); -+ printk("\n"); -+ } -+ -+ if (timed_out) { -+ printk(KERN_ERR "waveartist_cmd: command timed out:"); -+ for (i = 0; i < nr_cmd; i++) -+ printk(" %04x", cmd[i]); -+ printk("\n"); - } - - return timed_out ? 1 : 0; -@@ -495,7 +496,6 @@ - audio_devs[dev]->flags & DMA_AUTOMODE && - intrflag && - count == devc->xfer_count) { -- devc->audio_mode |= PCM_ENABLE_INPUT; - return; /* - * Auto DMA mode on. No need to react - */ -@@ -571,9 +571,6 @@ - wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc; - unsigned int speed, bits; - -- if (devc->audio_mode) -- return 0; -- - speed = waveartist_get_speed(portc); - bits = waveartist_get_bits(portc); - -diff -urN linux-2.4.26/drivers/ssi/Config.in linux-2.4.26-vrs1/drivers/ssi/Config.in ---- linux-2.4.26/drivers/ssi/Config.in 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/ssi/Config.in 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,11 @@ -+ -+mainmenu_option next_comment -+comment 'Synchronous Serial Interface' -+tristate 'Synchronous Serial Interface Support' CONFIG_SSI -+ -+comment 'SSI Bus Drivers' -+dep_tristate ' CLPS711X SSI support' CONFIG_SSI_CLPS711X $CONFIG_SSI $CONFIG_ARCH_CLPS711X -+ -+comment 'SSI Device Drivers' -+dep_tristate ' JUNO keyboard support' CONFIG_SSI_JUNO $CONFIG_SSI -+endmenu -diff -urN linux-2.4.26/drivers/ssi/Makefile linux-2.4.26-vrs1/drivers/ssi/Makefile ---- linux-2.4.26/drivers/ssi/Makefile 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/ssi/Makefile 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,50 @@ -+# -+# Makefile for the SSI drivers -+# -+# Note! Dependencies are done automagically by 'make dep', which also -+# removes any old dependencies. DON'T put your own dependencies here -+# unless it's something special (ie not a .c file). -+# -+# Note 2! The CFLAGS definition is now inherited from the -+# parent makefile. -+# -+ -+O_TARGET := ssi.o -+ -+obj-y := -+obj-m := -+obj-n := -+obj- := -+ -+export-objs := -+list-multi := -+ -+obj-$(CONFIG_SSI) += ssi_core.o -+obj-$(CONFIG_SSI_CLPS711X) += clps711x_ssi1.o -+obj-y += juno.o -+ -+# Extract lists of the multi-part drivers. -+# The 'int-*' lists are intermediate files used to build the multi's. -+ -+multi-y := $(filter $(list-multi), $(obj-y)) -+multi-m := $(filter $(list-multi), $(obj-m)) -+int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs))) -+int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) -+ -+# Files that are both resident and modular; remove from modular. -+ -+obj-m := $(filter-out $(obj-y), $(obj-m)) -+int-m := $(filter-out $(int-y), $(int-m)) -+ -+# Take multi-part drivers out of obj-y and put components in. -+ -+obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) -+ -+# Translate to Rules.make lists. -+ -+O_OBJS := $(filter-out $(export-objs), $(obj-y)) -+OX_OBJS := $(filter $(export-objs), $(obj-y)) -+M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) -+MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) -+ -+include $(TOPDIR)/Rules.make -diff -urN linux-2.4.26/drivers/ssi/README linux-2.4.26-vrs1/drivers/ssi/README ---- linux-2.4.26/drivers/ssi/README 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/ssi/README 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,86 @@ -+ Synchronous Serial Interface bus driver -+ --------------------------------------- -+ -+ EEEEE X X PPPP EEEEE RRRR IIIII M M EEEEE N N TTTTT AAA L -+ E X X P P E R R I MM MM E NN N T A A L -+ EEEE X PPPP EEEE RRRR I M M M EEEE N N N T AAAAA L -+ E X X P E R R I M M E N NN T A A L -+ EEEEE X X P EEEEE R R IIIII M M EEEEE N N T A A LLLLL -+ -+This directory holds the SSI bus drivers. Basically, a SSI bus consists -+of the following signals: -+ -+ stxd Transmit data -+ srxd Receive data -+ sclk Clock -+ sfrm Frame -+ Chip selects (1 - n) -+ -+There may be more than one device on a SSI bus, and each device can -+have different timing requirements. There are several frame formats: -+ -+1. Texas Instruments Synchronous Serial Frame format -+ -+ sclk ____~_~_~_~_~_~_~_~____ -+ sfrm ____~~_________________ -+ stxd ------bn..........b0--- -+ srxd ------bn..........b0--- -+ -+ - data latched in on the falling edge of the clock -+ - data shifted out on the rising edge of the clock -+ -+2. Motorola SPI frame format -+ -+ sclk ______~_~_~_~_~_~_~____ -+ sfrm ~~~~________________~~~ -+ stxd -----bn..........b0---- -+ srxd ----.bn..........b0---- -+ -+ - data latched in on the rising edge of the clock -+ - data shifted out on the falling edge of the clock, or falling edge -+ of sfrm -+ -+3. National Microwire format -+ -+ sclk ______~_~_~_~_~_~_~_~_~_~_~_~_~_____ -+ sfrm ~~~~_____________________________~~~ -+ stxd -----bn......b0--------------------- -+ srxd -----------------bn..........b0.---- -+ -+ - data latched in on the rising edge of the clock -+ - data shifted out on the falling edge of the clock -+ - half duplex, one clock between transmission and reception -+ -+Types of devices -+---------------- -+ -+The following types of devices can be found on a SSP bus: -+ -+ Sound chips -+ Keyboard devices -+ Touch screen devices -+ -+Keyboard -+-------- -+ -+TX: -+0. Format: cfglen = 8, framelen = 8, clkpol = 1, clk < 250kHz -+1. select device -+2. keyboard responds asserting key_atn -+3. wait 0.1ms to 5ms -+4. transmit data byte -+5. wait >= 150us -+6. repeat step 4 until all data sent -+7. deselect device -+8. keyboard responds de-asserting key_atn -+9. wait >= 120us -+ -+RX: -+0. Format: cfglen = 8, framelen = 8, clkpol = 1, clk < 250kHz -+1. keyboard asserts key_atn -+2. select device after 0.1ms < 5ms -+3. read data byte -+4. wait 150us -+5. if key_atn still asserted, goto 3 -+6. deselect device -+7. wait >= 120us -diff -urN linux-2.4.26/drivers/ssi/clps711x_ssi1.c linux-2.4.26-vrs1/drivers/ssi/clps711x_ssi1.c ---- linux-2.4.26/drivers/ssi/clps711x_ssi1.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/ssi/clps711x_ssi1.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,237 @@ -+/* -+ * linux/drivers/ssi/clps711x_ssi1.c -+ * -+ * SSI bus driver for the CLPS711x SSI1 bus. We support EP7212 -+ * extensions as well. -+ * -+ * Frame sizes can be between 4 and 24 bits. -+ * Config sizes can be between 4 and 16 bits. -+ */ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+ -+#include "ssi_bus.h" -+#include "ssi_dev.h" -+ -+#define EP7212 -+ -+/* -+ * Port E on the P720T is used for the SPI bus chip selects -+ * 0 - Keyboard -+ * 1 - Touch screen -+ * 2 - CS4224 ADC/DAC -+ * 7 - idle -+ */ -+ -+#if 0 -+/* -+ * we place in the transmit buffer: -+ * -+ * received data (binary): -+ * 0xxxxxxxxxxxx000 -+ * where 'x' is the value -+ */ -+struct ssi_dev ads7846_dev = { -+ name: "ADS7846", -+ id: 1, -+ proto: SSI_SPI, -+ cfglen: 8, -+ framelen: 24, -+ clkpol: 0, -+ clkfreq: 2500000, -+}; -+ -+/* -+ * we place in the transmit buffer: -+ * write: <20> ... -+ * received data discarded -+ */ -+struct ssi_dev cs4224_dev = { -+ name: "CS4224", -+ id: 2, -+ proto: SSI_SPI, -+ cfglen: 8, -+ framelen: 8, -+ clkpol: 0, -+ clkfreq: 6000000, -+}; -+#endif -+ -+/* -+ * Supplement with whatever method your board requires -+ */ -+static void ssi1_select_id(int id) -+{ -+ if (machine_is_p720t()) { -+ clps_writel(7, PEDDR); -+ clps_writel(id, PEDR); -+ } -+} -+ -+/* -+ * Select the specified device. The upper layers will have already -+ * checked that the bus transmit queue is idle. We need to make sure -+ * that the interface itself is idle. -+ */ -+static int ssi1_select(struct ssi_bus *bus, struct ssi_dev *dev) -+{ -+ u_int id = dev ? dev->id : 7; -+ u_int val; -+ -+ /* -+ * Make sure that the interface is idle -+ */ -+ do { -+ val = clps_readl(SYSFLG1); -+ } while (val & SYSFLG1_SSIBUSY); -+ -+ ssi1_select_id(7); -+ -+ if (dev) { -+ /* -+ * Select clock frequency. This is very rough, -+ * and assumes that we're operating in PLL mode. -+ */ -+ val = clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK; -+// if (dev->clkfreq <= 16000) /* <16kHz */ -+// val |= SYSCON1_ADCKSEL(0); -+// else if (dev->clkfreq < 64000) /* <64kHz */ -+// val |= SYSCON1_ADCKSEL(1); -+// else if (dev->clkfreq < 128000) /* <128kHz */ -+ val |= SYSCON1_ADCKSEL(2); -+// else /* >= 128kHz */ -+// val |= SYSCON1_ADCKSEL(3); -+ clps_writel(val, SYSCON1); -+ -+ bus->cfglen = dev->cfglen; -+ bus->framelen = dev->framelen; -+ bus->clkpol = dev->clkpol; -+ bus->proto = dev->proto; -+ -+#ifdef EP7212 -+ /* -+ * Set the clock edge according to the device. -+ * (set clkpol if the device reads data on the -+ * falling edge of the clock signal). -+ */ -+ val = ep_readl(SYSCON3) & ~SYSCON3_ADCCKNSEN; -+ if (bus->clkpol && dev->proto != SSI_USAR) -+ val |= SYSCON3_ADCCKNSEN; -+ ep_writel(val, SYSCON3); -+#endif -+ -+ /* -+ * Select the device -+ */ -+ ssi1_select_id(id); -+ -+#ifdef EP7212 -+ /* -+ * If we are doing USAR, wait 30us, then set -+ * the clock line low. -+ */ -+ if (dev->proto == SSI_USAR) { -+ udelay(150); -+ -+ val |= SYSCON3_ADCCKNSEN; -+ ep_writel(val, SYSCON3); -+ } -+#endif -+ } -+ -+ return 0; -+} -+ -+static void ssi1_int(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ struct ssi_bus *bus = (struct ssi_bus *)dev_id; -+ -+ /* -+ * Read the data word and queue it. -+ */ -+ ssi_core_rcv(bus, clps_readl(SYNCIO)); -+} -+ -+/* -+ * Enable transmission and/or of some bytes -+ */ -+static int ssi1_trans(struct ssi_bus *bus, u_int data) -+{ -+ u_int syncio; -+ -+#ifdef EP7212 -+ data <<= 32 - bus->cfglen; -+ syncio = bus->cfglen | bus->framelen << 7 | data; -+#else -+ syncio = data | bus->framelen << 8; -+#endif -+ -+ clps_writel(syncio, SYNCIO); -+ clps_writel(syncio | SYNCIO_TXFRMEN, SYNCIO); -+ return 0; -+} -+ -+/* -+ * Initialise the SSI bus. -+ */ -+static int ssi1_bus_init(struct ssi_bus *bus) -+{ -+ int retval, val; -+ -+ retval = request_irq(IRQ_SSEOTI, ssi1_int, 0, "ssi1", bus); -+ if (retval) -+ return retval; -+ -+#ifdef EP7212 -+ /* -+ * EP7212 only! Set the configuration command length. -+ * On the CLPS711x chips, it is fixed at 8 bits. -+ */ -+ val = ep_readl(SYSCON3); -+ val |= SYSCON3_ADCCON; -+ ep_writel(val, SYSCON3); -+#endif -+ -+ ssi1_select(bus, NULL); -+ -+ PLD_SPI |= PLD_SPI_EN; -+ -+ return 0; -+} -+ -+static void ssi1_bus_exit(struct ssi_bus *bus) -+{ -+ ssi1_select(bus, NULL); -+ -+ PLD_SPI &= ~PLD_SPI_EN; -+ -+ free_irq(IRQ_SSEOTI, bus); -+} -+ -+struct ssi_bus clps711x_ssi1_bus = { -+ name: "clps711x_ssi1", -+ init: ssi1_bus_init, -+ exit: ssi1_bus_exit, -+ select: ssi1_select, -+ trans: ssi1_trans, -+}; -+ -+static int __init clps711x_ssi1_init(void) -+{ -+ return ssi_register_bus(&clps711x_ssi1_bus); -+} -+ -+static void __exit clps711x_ssi1_exit(void) -+{ -+ ssi_unregister_bus(&clps711x_ssi1_bus); -+} -+ -+module_init(clps711x_ssi1_init); -+module_exit(clps711x_ssi1_exit); -diff -urN linux-2.4.26/drivers/ssi/juno.c linux-2.4.26-vrs1/drivers/ssi/juno.c ---- linux-2.4.26/drivers/ssi/juno.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/ssi/juno.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,131 @@ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include -+ -+#include "ssi_bus.h" -+#include "ssi_dev.h" -+ -+extern struct ssi_bus clps711x_ssi1_bus; -+ -+static u_int recvbuf[16]; -+static volatile u_int ptr, rxed; -+ -+static inline void juno_enable_irq(void) -+{ -+ enable_irq(IRQ_EINT1); -+} -+ -+static inline void juno_disable_irq(void) -+{ -+ disable_irq(IRQ_EINT1); -+} -+ -+static void juno_rcv(struct ssi_dev *dev, u_int data) -+{ -+ if (ptr < 16) { -+ recvbuf[ptr] = data; -+ ptr++; -+ } else -+ printk("juno_rcv: %04x\n", data); -+ rxed = 1; -+} -+ -+static void juno_irq(int irq, void *dev_id, struct pt_regs *regs) -+{ -+ struct ssi_dev *dev = dev_id; -+ -+ printk("juno_irq\n"); -+ -+ ssi_select_device(dev->bus, dev); -+ -+ ptr = 0; -+ do { -+ rxed = 0; -+ ssi_transmit_data(dev, 0xff); -+ while (rxed == 0); -+ udelay(150); -+ } while (PLD_INT & PLD_INT_KBD_ATN); -+ -+ ssi_select_device(dev->bus, NULL); -+ -+ { int i; -+ printk("juno_rcv: "); -+ for (i = 0; i < ptr; i++) -+ printk("%04x ", recvbuf[i]); -+ printk("\n"); -+ } -+} -+ -+static void juno_command(struct ssi_dev *dev, int cmd, int data) -+{ -+ ssi_transmit_data(dev, cmd); -+ mdelay(1); -+ ssi_transmit_data(dev, data); -+ mdelay(1); -+ ssi_transmit_data(dev, 0xa0 ^ 0xc0); -+ mdelay(1); -+} -+ -+static int juno_dev_init(struct ssi_dev *dev) -+{ -+ int retval; -+ -+ PLD_KBD |= PLD_KBD_EN; -+ ptr = 16; -+ -+ mdelay(20); -+ -+ retval = request_irq(IRQ_EINT1, juno_irq, 0, dev->name, dev); -+ if (retval) -+ return retval; -+ -+ juno_disable_irq(); -+ -+ if (ssi_select_device(dev->bus, dev) != 0) { -+ printk("juno: ssi_select_dev failed\n"); -+ return -EBUSY; -+ } -+ -+ mdelay(1); -+ -+ juno_command(dev, 0x80, 0x20); -+ -+ ssi_select_device(dev->bus, NULL); -+ -+ juno_enable_irq(); -+ -+ return 0; -+} -+ -+static struct ssi_dev juno_dev = { -+ name: "Juno", -+ id: 0, -+ proto: SSI_USAR, -+ cfglen: 8, -+ framelen: 8, -+ clkpol: 1, -+ clkfreq: 250000, -+ rcv: juno_rcv, -+ init: juno_dev_init, -+}; -+ -+static int __init juno_init(void) -+{ -+ return ssi_register_device(&clps711x_ssi1_bus, &juno_dev); -+} -+ -+static void __exit juno_exit(void) -+{ -+ ssi_unregister_device(&juno_dev); -+} -+ -+module_init(juno_init); -+module_exit(juno_exit); -+ -diff -urN linux-2.4.26/drivers/ssi/ssi_bus.h linux-2.4.26-vrs1/drivers/ssi/ssi_bus.h ---- linux-2.4.26/drivers/ssi/ssi_bus.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/ssi/ssi_bus.h 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,21 @@ -+#include -+ -+struct ssi_dev; -+ -+struct ssi_bus { -+ u_char cfglen; -+ u_char framelen; -+ u_char clkpol; -+ u_char proto; -+ struct ssi_dev *dev; /* current device */ -+ int (*select)(struct ssi_bus *, struct ssi_dev *); -+ int (*trans)(struct ssi_bus *, u_int data); -+ int (*init)(struct ssi_bus *); -+ void (*exit)(struct ssi_bus *); -+ char *name; -+ u_int devices; -+}; -+ -+extern int ssi_core_rcv(struct ssi_bus *bus, u_int data); -+extern int ssi_register_bus(struct ssi_bus *bus); -+extern int ssi_unregister_bus(struct ssi_bus *bus); -diff -urN linux-2.4.26/drivers/ssi/ssi_core.c linux-2.4.26-vrs1/drivers/ssi/ssi_core.c ---- linux-2.4.26/drivers/ssi/ssi_core.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/ssi/ssi_core.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,175 @@ -+/* -+ * linux/drivers/ssi/ssi_core.c -+ * -+ * This file provides a common framework to allow multiple SSI devices -+ * to work together on a single SSI bus. -+ * -+ * You can use this in two ways: -+ * 1. select the device, queue up data, flush the data to the device, -+ * (optionally) purge the received data, deselect the device. -+ * 2. select the device, queue up one data word, flush to the device -+ * read data word, queue up next data word, flush to the device... -+ * deselect the device. -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include "ssi_bus.h" -+#include "ssi_dev.h" -+ -+#define DEBUG -+ -+/** -+ * ssi_core_rcv - pass received SSI data to the device -+ * @bus: the bus that the data was received from -+ * @data: the data word that was received -+ * -+ * This function is intended to be called by SSI bus device -+ * drivers to pass received data to the device driver. -+ */ -+int ssi_core_rcv(struct ssi_bus *bus, u_int data) -+{ -+ struct ssi_dev *dev = bus->dev; -+ -+ if (dev && dev->rcv) -+ dev->rcv(dev, data); -+ -+ return 0; -+} -+ -+/** -+ * ssi_transmit_data - queue SSI data for later transmission -+ * @dev: device requesting data to be transmitted -+ * @data: data word to be transmitted. -+ * -+ * Queue one data word of SSI data for later transmission. -+ */ -+int ssi_transmit_data(struct ssi_dev *dev, u_int data) -+{ -+ struct ssi_bus *bus = dev->bus; -+ -+ /* -+ * Make sure that we currently own the bus -+ */ -+ if (bus->dev != dev) -+ BUG(); -+ -+ bus->trans(bus, data); -+ return 0; -+} -+ -+/** -+ * ssi_select_device - select a SSI device for later transactions -+ * @dev: device to be selected -+ */ -+int ssi_select_device(struct ssi_bus *bus, struct ssi_dev *dev) -+{ -+ int retval; -+ -+#ifdef DEBUG -+ printk("SSI: selecting device %s on bus %s\n", -+ dev ? dev->name : "", bus->name); -+#endif -+ -+ /* -+ * Select the device if it wasn't already selected. -+ */ -+ retval = 0; -+ if (bus->dev != dev) { -+ retval = bus->select(bus, dev); -+ bus->dev = dev; -+ } -+ -+ return retval; -+} -+ -+/** -+ * ssi_register_device - register a SSI device with a SSI bus -+ * @bus: bus -+ * @dev: SSI device -+ */ -+int ssi_register_device(struct ssi_bus *bus, struct ssi_dev *dev) -+{ -+ int retval; -+ -+ dev->bus = bus; -+ bus->devices++; -+ retval = dev->init(dev); -+ if (retval != 0) { -+ dev->bus = NULL; -+ bus->devices--; -+ } else { -+#ifdef DEBUG -+ printk("SSI: registered new device %s on bus %s\n", dev->name, bus->name); -+#endif -+ } -+ return retval; -+} -+ -+/** -+ * ssi_unregister_device - unregister a SSI device from a SSI bus -+ * @dev: SSI device -+ */ -+int ssi_unregister_device(struct ssi_dev *dev) -+{ -+ struct ssi_bus *bus = dev->bus; -+ -+ if (bus->dev == dev) -+ bus->dev = NULL; -+ -+ dev->bus = NULL; -+ bus->devices--; -+#ifdef DEBUG -+ printk("SSI: unregistered device %s on bus %s\n", dev->name, bus->name); -+#endif -+ return 0; -+} -+ -+/** -+ * ssi_register_bus - register a SSI bus driver -+ * @bus: bus -+ */ -+int ssi_register_bus(struct ssi_bus *bus) -+{ -+ int retval; -+ -+ retval = bus->init(bus); -+ if (retval == 0) { -+ bus->devices = 0; -+#ifdef DEBUG -+ printk("SSI: registered new bus %s\n", bus->name); -+#endif -+ } -+ -+ return retval; -+} -+ -+/** -+ * ssi_unregister_bus - unregister a SSI bus driver -+ * @bus: bus -+ */ -+int ssi_unregister_bus(struct ssi_bus *bus) -+{ -+ int retval = -EBUSY; -+ if (bus->devices == 0) { -+ retval = 0; -+ } -+ return retval; -+} -+ -+static int __init ssi_init(void) -+{ -+ return 0; -+} -+ -+static void __exit ssi_exit(void) -+{ -+} -+ -+module_init(ssi_init); -+module_exit(ssi_exit); -diff -urN linux-2.4.26/drivers/ssi/ssi_dev.h linux-2.4.26-vrs1/drivers/ssi/ssi_dev.h ---- linux-2.4.26/drivers/ssi/ssi_dev.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/ssi/ssi_dev.h 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,21 @@ -+struct ssi_bus; -+ -+#define SSI_SPI 1 -+#define SSI_MICROWIRE 2 -+#define SSI_TISSF 3 -+#define SSI_USAR 4 -+ -+struct ssi_dev { -+ char *name; -+ u_int id; -+ u_int clkfreq; -+ u_char cfglen; -+ u_char framelen; -+ u_char clkpol; -+ u_char proto; -+ void (*rcv)(struct ssi_dev *, u_int); -+ int (*init)(struct ssi_dev *); -+ struct ssi_bus *bus; -+}; -+ -+ -diff -urN linux-2.4.26/drivers/usb/Config.in linux-2.4.26-vrs1/drivers/usb/Config.in ---- linux-2.4.26/drivers/usb/Config.in 2004-02-27 20:03:27.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/usb/Config.in 2004-02-23 13:36:33.000000000 +0000 -@@ -4,7 +4,13 @@ - mainmenu_option next_comment - comment 'USB support' - --dep_tristate 'Support for USB' CONFIG_USB $CONFIG_PCI -+# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. -+if [ "$CONFIG_PCI" = "y" -o "$CONFIG_SA1111" = "y" -o "$CONFIG_ARCH_AT91RM9200" = "y" ]; then -+ tristate 'Support for USB' CONFIG_USB -+else -+ define_bool CONFIG_USB n -+fi -+ - if [ "$CONFIG_USB" = "y" -o "$CONFIG_USB" = "m" ]; then - bool ' USB verbose debug messages' CONFIG_USB_DEBUG - -diff -urN linux-2.4.26/drivers/usb/Makefile linux-2.4.26-vrs1/drivers/usb/Makefile ---- linux-2.4.26/drivers/usb/Makefile 2004-02-27 20:03:27.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/usb/Makefile 2004-02-23 13:36:33.000000000 +0000 -@@ -74,6 +74,14 @@ - - subdir-$(CONFIG_USB_OHCI) += host - ifeq ($(CONFIG_USB_OHCI),y) -+ obj-y += host/usb-ohci.o host/usb-ohci-pci.o -+endif -+subdir-$(CONFIG_USB_OHCI_SA1111)+= host -+ifeq ($(CONFIG_USB_OHCI),y) -+ obj-y += host/usb-ohci.o host/usb-ohci-sa1111.o -+endif -+subdir-$(CONFIG_USB_OHCI_AT91) += host -+ifeq ($(CONFIG_USB_OHCI_AT91),y) - obj-y += host/usb-ohci.o - endif - -@@ -85,8 +93,6 @@ - obj-$(CONFIG_USB_KBD) += usbkbd.o - obj-$(CONFIG_USB_AIPTEK) += aiptek.o - obj-$(CONFIG_USB_WACOM) += wacom.o --obj-$(CONFIG_USB_KBTAB) += kbtab.o --obj-$(CONFIG_USB_POWERMATE) += powermate.o - - obj-$(CONFIG_USB_SCANNER) += scanner.o - obj-$(CONFIG_USB_ACM) += acm.o -diff -urN linux-2.4.26/drivers/usb/hcd.c linux-2.4.26-vrs1/drivers/usb/hcd.c ---- linux-2.4.26/drivers/usb/hcd.c 2004-04-19 11:44:27.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/usb/hcd.c 2004-04-19 10:22:01.000000000 +0100 -@@ -96,7 +96,7 @@ - /* used when updating hcd data */ - static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED; - --static struct usb_operations hcd_operations; -+/*static*/ struct usb_operations hcd_operations; - - /*-------------------------------------------------------------------------*/ - -@@ -1208,13 +1208,21 @@ - } else { - if (usb_pipecontrol (urb->pipe)) - urb->setup_dma = pci_map_single ( -+#ifdef CONFIG_PCI - hcd->pdev, -+#else -+ NULL, -+#endif - urb->setup_packet, - sizeof (struct usb_ctrlrequest), - PCI_DMA_TODEVICE); - if (urb->transfer_buffer_length != 0) - urb->transfer_dma = pci_map_single ( -+#ifdef CONFIG_PCI - hcd->pdev, -+#else -+ NULL, -+#endif - urb->transfer_buffer, - urb->transfer_buffer_length, - usb_pipein (urb->pipe) -@@ -1424,7 +1432,7 @@ - return 0; - } - --static struct usb_operations hcd_operations = { -+/*static*/ struct usb_operations hcd_operations = { - allocate: hcd_alloc_dev, - get_frame_number: hcd_get_frame_number, - submit_urb: hcd_submit_urb, -@@ -1434,7 +1442,7 @@ - - /*-------------------------------------------------------------------------*/ - --static void hcd_irq (int irq, void *__hcd, struct pt_regs * r) -+/*static*/ void hcd_irq (int irq, void *__hcd, struct pt_regs * r) - { - struct usb_hcd *hcd = __hcd; - int start = hcd->state; -@@ -1490,12 +1498,24 @@ - - /* For 2.4, don't unmap bounce buffer if it's a root hub operation. */ - if (usb_pipecontrol (urb->pipe) && !is_root_hub_operation) -- pci_unmap_single (hcd->pdev, urb->setup_dma, -+ pci_unmap_single ( -+#ifdef CONFIG_PCI -+ hcd->pdev, -+#else -+ NULL, -+#endif -+ urb->setup_dma, - sizeof (struct usb_ctrlrequest), - PCI_DMA_TODEVICE); - - if ((urb->transfer_buffer_length != 0) && !is_root_hub_operation) -- pci_unmap_single (hcd->pdev, urb->transfer_dma, -+ pci_unmap_single ( -+#ifdef CONFIG_PCI -+ hcd->pdev, -+#else -+ NULL, -+#endif -+ urb->transfer_dma, - urb->transfer_buffer_length, - usb_pipein (urb->pipe) - ? PCI_DMA_FROMDEVICE -diff -urN linux-2.4.26/drivers/usb/host/Config.in linux-2.4.26-vrs1/drivers/usb/host/Config.in ---- linux-2.4.26/drivers/usb/host/Config.in 2003-11-28 18:26:20.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/usb/host/Config.in 2004-02-11 01:35:27.000000000 +0000 -@@ -12,8 +12,13 @@ - define_bool CONFIG_USB_UHCI_ALT n - fi - dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB -+dep_tristate ' SA1111 OHCI-compatible host interface support' CONFIG_USB_OHCI_SA1111 $CONFIG_USB - if [ "$CONFIG_ARM" = "y" -o "$CONFIG_X86" = "y" -a "$CONFIG_X86_64" != "y" ]; then - # Cypress embedded USB controller on StrongARM or on x86 in PC/104 - dep_tristate ' SL811HS Alternate (x86, StrongARM, isosynchronous mode)' CONFIG_USB_SL811HS_ALT $CONFIG_USB $CONFIG_EXPERIMENTAL - dep_tristate ' SL811HS (x86, StrongARM) support, old driver' CONFIG_USB_SL811HS $CONFIG_USB $CONFIG_EXPERIMENTAL - fi -+if [ "$CONFIG_ARCH_AT91RM9200" = "y" ]; then -+ dep_tristate ' AT91RM9200 OHCI-compatible host interface support' CONFIG_USB_OHCI_AT91 $CONFIG_USB -+fi -+ -diff -urN linux-2.4.26/drivers/usb/host/Makefile linux-2.4.26-vrs1/drivers/usb/host/Makefile ---- linux-2.4.26/drivers/usb/host/Makefile 2003-11-28 18:26:20.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/usb/host/Makefile 2004-02-11 01:29:25.000000000 +0000 -@@ -8,9 +8,11 @@ - obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o - obj-$(CONFIG_USB_UHCI_ALT) += uhci.o - obj-$(CONFIG_USB_UHCI) += usb-uhci.o --obj-$(CONFIG_USB_OHCI) += usb-ohci.o -+obj-$(CONFIG_USB_OHCI) += usb-ohci.o usb-ohci-pci.o - obj-$(CONFIG_USB_SL811HS_ALT) += sl811.o - obj-$(CONFIG_USB_SL811HS) += hc_sl811.o -+obj-$(CONFIG_USB_OHCI_SA1111) += usb-ohci.o usb-ohci-sa1111.o -+obj-$(CONFIG_USB_OHCI_AT91) += usb-ohci.o - - # Extract lists of the multi-part drivers. - # The 'int-*' lists are the intermediate files used to build the multi's. -diff -urN linux-2.4.26/drivers/usb/host/usb-ohci-pci.c linux-2.4.26-vrs1/drivers/usb/host/usb-ohci-pci.c ---- linux-2.4.26/drivers/usb/host/usb-ohci-pci.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/usb/host/usb-ohci-pci.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,436 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include /* for in_interrupt() */ -+#undef DEBUG -+#include -+ -+#include "usb-ohci.h" -+ -+#ifdef CONFIG_PMAC_PBOOK -+#include -+#include -+#include -+#ifndef CONFIG_PM -+#define CONFIG_PM -+#endif -+#endif -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* Increment the module usage count, start the control thread and -+ * return success. */ -+ -+static struct pci_driver ohci_pci_driver; -+extern spinlock_t usb_ed_lock; -+int __devinit -+hc_add_ohci(struct pci_dev *dev, int irq, void *membase, unsigned long flags, -+ const char *name, const char *slot_name); -+extern void hc_remove_ohci(ohci_t *ohci); -+ -+static int __devinit -+hc_found_ohci (struct pci_dev *dev, int irq, -+ void *mem_base, const struct pci_device_id *id) -+{ -+ unsigned long flags = id->driver_data; -+ -+ printk(KERN_INFO __FILE__ ": usb-%s, %s\n", dev->slot_name, dev->name); -+ -+ /* Check for NSC87560. We have to look at the bridge (fn1) to identify -+ the USB (fn2). This quirk might apply to more or even all NSC stuff -+ I don't know.. */ -+ -+ if(dev->vendor == PCI_VENDOR_ID_NS) -+ { -+ struct pci_dev *fn1 = pci_find_slot(dev->bus->number, PCI_DEVFN(PCI_SLOT(dev->devfn), 1)); -+ if(fn1 && fn1->vendor == PCI_VENDOR_ID_NS && fn1->device == PCI_DEVICE_ID_NS_87560_LIO) -+ flags |= OHCI_QUIRK_SUCKYIO; -+ -+ } -+ -+ if (flags & OHCI_QUIRK_SUCKYIO) -+ printk (KERN_INFO __FILE__ ": Using NSC SuperIO setup\n"); -+ if (flags & OHCI_QUIRK_AMD756) -+ printk (KERN_INFO __FILE__ ": AMD756 erratum 4 workaround\n"); -+ -+ return hc_add_ohci(dev, irq, mem_base, flags, -+ ohci_pci_driver.name, dev->slot_name); -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+#ifdef CONFIG_PM -+ -+/* controller died; cleanup debris, then restart */ -+/* must not be called from interrupt context */ -+ -+static void hc_restart (ohci_t *ohci) -+{ -+ int temp; -+ int i; -+ -+ if (ohci->pci_latency) -+ pci_write_config_byte (ohci->ohci_dev, PCI_LATENCY_TIMER, ohci->pci_latency); -+ -+ ohci->disabled = 1; -+ ohci->sleeping = 0; -+ if (ohci->bus->root_hub) -+ usb_disconnect (&ohci->bus->root_hub); -+ -+ /* empty the interrupt branches */ -+ for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0; -+ for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table[i] = 0; -+ -+ /* no EDs to remove */ -+ ohci->ed_rm_list [0] = NULL; -+ ohci->ed_rm_list [1] = NULL; -+ -+ /* empty control and bulk lists */ -+ ohci->ed_isotail = NULL; -+ ohci->ed_controltail = NULL; -+ ohci->ed_bulktail = NULL; -+ -+ if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) { -+ err ("can't restart usb-%s, %d", ohci->ohci_dev->slot_name, temp); -+ } else -+ dbg ("restart usb-%s completed", ohci->ohci_dev->slot_name); -+} -+ -+#endif /* CONFIG_PM */ -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* configured so that an OHCI device is always provided */ -+/* always called with process context; sleeping is OK */ -+ -+static int __devinit -+ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) -+{ -+ unsigned long mem_resource, mem_len; -+ void *mem_base; -+ int status; -+ -+ if (pci_enable_device(dev) < 0) -+ return -ENODEV; -+ -+ if (!dev->irq) { -+ err("found OHCI device with no IRQ assigned. check BIOS settings!"); -+ pci_disable_device (dev); -+ return -ENODEV; -+ } -+ -+ /* we read its hardware registers as memory */ -+ mem_resource = pci_resource_start(dev, 0); -+ mem_len = pci_resource_len(dev, 0); -+ if (!request_mem_region (mem_resource, mem_len, ohci_pci_driver.name)) { -+ dbg ("controller already in use"); -+ pci_disable_device (dev); -+ return -EBUSY; -+ } -+ -+ mem_base = ioremap_nocache (mem_resource, mem_len); -+ if (!mem_base) { -+ err("Error mapping OHCI memory"); -+ release_mem_region (mem_resource, mem_len); -+ pci_disable_device (dev); -+ return -EFAULT; -+ } -+ -+ /* controller writes into our memory */ -+ pci_set_master (dev); -+ -+ status = hc_found_ohci (dev, dev->irq, mem_base, id); -+ if (status < 0) { -+ iounmap (mem_base); -+ release_mem_region (mem_resource, mem_len); -+ pci_disable_device (dev); -+ } -+ return status; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* may be called from interrupt context [interface spec] */ -+/* may be called without controller present */ -+/* may be called with controller, bus, and devices active */ -+ -+static void __devexit -+ohci_pci_remove (struct pci_dev *dev) -+{ -+ ohci_t *ohci = (ohci_t *) pci_get_drvdata(dev); -+ -+ dbg ("remove %s controller usb-%s%s%s", -+ hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS), -+ dev->slot_name, -+ ohci->disabled ? " (disabled)" : "", -+ in_interrupt () ? " in interrupt" : "" -+ ); -+ -+ hc_remove_ohci(ohci); -+ -+ release_mem_region (pci_resource_start (dev, 0), pci_resource_len (dev, 0)); -+ pci_disable_device (dev); -+} -+ -+ -+#ifdef CONFIG_PM -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int -+ohci_pci_suspend (struct pci_dev *dev, u32 state) -+{ -+ ohci_t *ohci = (ohci_t *) pci_get_drvdata(dev); -+ unsigned long flags; -+ u16 cmd; -+ -+ if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) { -+ dbg ("can't suspend usb-%s (state is %s)", dev->slot_name, -+ hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS)); -+ return -EIO; -+ } -+ -+ /* act as if usb suspend can always be used */ -+ info ("USB suspend: usb-%s", dev->slot_name); -+ ohci->sleeping = 1; -+ -+ /* First stop processing */ -+ spin_lock_irqsave (&usb_ed_lock, flags); -+ ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE); -+ writel (ohci->hc_control, &ohci->regs->control); -+ writel (OHCI_INTR_SF, &ohci->regs->intrstatus); -+ (void) readl (&ohci->regs->intrstatus); -+ spin_unlock_irqrestore (&usb_ed_lock, flags); -+ -+ /* Wait a frame or two */ -+ mdelay(1); -+ if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF) -+ mdelay (1); -+ -+#ifdef CONFIG_PMAC_PBOOK -+ if (_machine == _MACH_Pmac) -+ disable_irq (ohci->irq); -+ /* else, 2.4 assumes shared irqs -- don't disable */ -+#endif -+ /* Enable remote wakeup */ -+ writel (readl(&ohci->regs->intrenable) | OHCI_INTR_RD, &ohci->regs->intrenable); -+ -+ /* Suspend chip and let things settle down a bit */ -+ ohci->hc_control = OHCI_USB_SUSPEND; -+ writel (ohci->hc_control, &ohci->regs->control); -+ (void) readl (&ohci->regs->control); -+ mdelay (500); /* No schedule here ! */ -+ switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) { -+ case OHCI_USB_RESET: -+ dbg("Bus in reset phase ???"); -+ break; -+ case OHCI_USB_RESUME: -+ dbg("Bus in resume phase ???"); -+ break; -+ case OHCI_USB_OPER: -+ dbg("Bus in operational phase ???"); -+ break; -+ case OHCI_USB_SUSPEND: -+ dbg("Bus suspended"); -+ break; -+ } -+ /* In some rare situations, Apple's OHCI have happily trashed -+ * memory during sleep. We disable it's bus master bit during -+ * suspend -+ */ -+ pci_read_config_word (dev, PCI_COMMAND, &cmd); -+ cmd &= ~PCI_COMMAND_MASTER; -+ pci_write_config_word (dev, PCI_COMMAND, cmd); -+#ifdef CONFIG_PMAC_PBOOK -+ { -+ struct device_node *of_node; -+ -+ /* Disable USB PAD & cell clock */ -+ of_node = pci_device_to_OF_node (ohci->ohci_dev); -+ if (of_node) -+ pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0); -+ } -+#endif -+ return 0; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int -+ohci_pci_resume (struct pci_dev *dev) -+{ -+ ohci_t *ohci = (ohci_t *) pci_get_drvdata(dev); -+ int temp; -+ unsigned long flags; -+ -+ /* guard against multiple resumes */ -+ atomic_inc (&ohci->resume_count); -+ if (atomic_read (&ohci->resume_count) != 1) { -+ err ("concurrent PCI resumes for usb-%s", dev->slot_name); -+ atomic_dec (&ohci->resume_count); -+ return 0; -+ } -+ -+#ifdef CONFIG_PMAC_PBOOK -+ { -+ struct device_node *of_node; -+ -+ /* Re-enable USB PAD & cell clock */ -+ of_node = pci_device_to_OF_node (ohci->ohci_dev); -+ if (of_node) -+ pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 1); -+ } -+#endif -+ -+ /* did we suspend, or were we powered off? */ -+ ohci->hc_control = readl (&ohci->regs->control); -+ temp = ohci->hc_control & OHCI_CTRL_HCFS; -+ -+#ifdef DEBUG -+ /* the registers may look crazy here */ -+ ohci_dump_status (ohci); -+#endif -+ -+ /* Re-enable bus mastering */ -+ pci_set_master(ohci->ohci_dev); -+ -+ switch (temp) { -+ -+ case OHCI_USB_RESET: // lost power -+ info ("USB restart: usb-%s", dev->slot_name); -+ hc_restart (ohci); -+ break; -+ -+ case OHCI_USB_SUSPEND: // host wakeup -+ case OHCI_USB_RESUME: // remote wakeup -+ info ("USB continue: usb-%s from %s wakeup", dev->slot_name, -+ (temp == OHCI_USB_SUSPEND) -+ ? "host" : "remote"); -+ ohci->hc_control = OHCI_USB_RESUME; -+ writel (ohci->hc_control, &ohci->regs->control); -+ (void) readl (&ohci->regs->control); -+ mdelay (20); /* no schedule here ! */ -+ /* Some controllers (lucent) need a longer delay here */ -+ mdelay (15); -+ temp = readl (&ohci->regs->control); -+ temp = ohci->hc_control & OHCI_CTRL_HCFS; -+ if (temp != OHCI_USB_RESUME) { -+ err ("controller usb-%s won't resume", dev->slot_name); -+ ohci->disabled = 1; -+ return -EIO; -+ } -+ -+ /* Some chips likes being resumed first */ -+ writel (OHCI_USB_OPER, &ohci->regs->control); -+ (void) readl (&ohci->regs->control); -+ mdelay (3); -+ -+ /* Then re-enable operations */ -+ spin_lock_irqsave (&usb_ed_lock, flags); -+ ohci->disabled = 0; -+ ohci->sleeping = 0; -+ ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; -+ if (!ohci->ed_rm_list[0] && !ohci->ed_rm_list[1]) { -+ if (ohci->ed_controltail) -+ ohci->hc_control |= OHCI_CTRL_CLE; -+ if (ohci->ed_bulktail) -+ ohci->hc_control |= OHCI_CTRL_BLE; -+ } -+ writel (ohci->hc_control, &ohci->regs->control); -+ writel (OHCI_INTR_SF, &ohci->regs->intrstatus); -+ writel (OHCI_INTR_SF, &ohci->regs->intrenable); -+ /* Check for a pending done list */ -+ writel (OHCI_INTR_WDH, &ohci->regs->intrdisable); -+ (void) readl (&ohci->regs->intrdisable); -+ spin_unlock_irqrestore (&usb_ed_lock, flags); -+#ifdef CONFIG_PMAC_PBOOK -+ if (_machine == _MACH_Pmac) -+ enable_irq (ohci->irq); -+#endif -+ if (ohci->hcca->done_head) -+ dl_done_list (ohci, dl_reverse_done_list (ohci)); -+ writel (OHCI_INTR_WDH, &ohci->regs->intrenable); -+ writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */ -+ writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */ -+ break; -+ -+ default: -+ warn ("odd PCI resume for usb-%s", dev->slot_name); -+ } -+ -+ /* controller is operational, extra resumes are harmless */ -+ atomic_dec (&ohci->resume_count); -+ -+ return 0; -+} -+ -+#endif /* CONFIG_PM */ -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+static const struct pci_device_id __devinitdata ohci_pci_ids [] = { { -+ -+ /* -+ * AMD-756 [Viper] USB has a serious erratum when used with -+ * lowspeed devices like mice. -+ */ -+ vendor: 0x1022, -+ device: 0x740c, -+ subvendor: PCI_ANY_ID, -+ subdevice: PCI_ANY_ID, -+ -+ driver_data: OHCI_QUIRK_AMD756, -+ -+} , { -+ -+ /* handle any USB OHCI controller */ -+ class: ((PCI_CLASS_SERIAL_USB << 8) | 0x10), -+ class_mask: ~0, -+ -+ /* no matter who makes it */ -+ vendor: PCI_ANY_ID, -+ device: PCI_ANY_ID, -+ subvendor: PCI_ANY_ID, -+ subdevice: PCI_ANY_ID, -+ -+ }, { /* end: all zeroes */ } -+}; -+ -+MODULE_DEVICE_TABLE (pci, ohci_pci_ids); -+ -+static struct pci_driver ohci_pci_driver = { -+ name: "usb-ohci", -+ id_table: &ohci_pci_ids [0], -+ -+ probe: ohci_pci_probe, -+ remove: __devexit_p(ohci_pci_remove), -+ -+#ifdef CONFIG_PM -+ suspend: ohci_pci_suspend, -+ resume: ohci_pci_resume, -+#endif /* PM */ -+}; -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int __init ohci_hcd_init (void) -+{ -+ return pci_module_init (&ohci_pci_driver); -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static void __exit ohci_hcd_cleanup (void) -+{ -+ pci_unregister_driver (&ohci_pci_driver); -+} -+ -+module_init (ohci_hcd_init); -+module_exit (ohci_hcd_cleanup); -+ -diff -urN linux-2.4.26/drivers/usb/host/usb-ohci-sa1111.c linux-2.4.26-vrs1/drivers/usb/host/usb-ohci-sa1111.c ---- linux-2.4.26/drivers/usb/host/usb-ohci-sa1111.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/usb/host/usb-ohci-sa1111.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,118 @@ -+/* -+ * linux/drivers/usb/usb-ohci-sa1111.c -+ * -+ * The outline of this code was taken from Brad Parkers -+ * original OHCI driver modifications, and reworked into a cleaner form -+ * by Russell King . -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "usb-ohci.h" -+ -+int __devinit -+hc_add_ohci(struct pci_dev *dev, int irq, void *membase, unsigned long flags, -+ const char *name, const char *slot_name); -+extern void hc_remove_ohci(ohci_t *ohci); -+ -+static ohci_t *sa1111_ohci; -+ -+static void __init sa1111_ohci_configure(void) -+{ -+ unsigned int usb_rst = 0; -+ -+ if (machine_is_xp860() || -+ machine_has_neponset() || -+ machine_is_accelent_sa() || -+ machine_is_pfs168() || -+ machine_is_badge4()) -+ usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW; -+ -+ /* -+ * Configure the power sense and control lines. Place the USB -+ * host controller in reset. -+ */ -+ USB_RESET = usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET; -+ -+ /* -+ * Now, carefully enable the USB clock, and take -+ * the USB host controller out of reset. -+ */ -+ SKPCR |= SKPCR_UCLKEN; -+ udelay(11); -+ USB_RESET = usb_rst; -+} -+ -+static int __init sa1111_ohci_init(void) -+{ -+ int ret; -+ -+ /* -+ * Request memory resources. -+ */ -+// if (!request_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT, "usb-ohci")) -+// return -EBUSY; -+ -+ sa1111_ohci_configure(); -+ -+ /* -+ * Initialise the generic OHCI driver. -+ */ -+ ret = hc_add_ohci(SA1111_FAKE_PCIDEV, NIRQHCIM, -+ (void *)&USB_OHCI_OP_BASE, 0, &sa1111_ohci, -+ "usb-ohci", "sa1111"); -+ -+// if (ret) -+// release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT); -+ -+#ifdef CONFIG_SA1100_BADGE4 -+ if (machine_is_badge4() && (!ret)) { -+ /* found the controller, so now power the bus */ -+ badge4_set_5V(BADGE4_5V_USB, 1); -+ } -+#endif -+ -+ return ret; -+} -+ -+static void __exit sa1111_ohci_exit(void) -+{ -+ hc_remove_ohci(sa1111_ohci); -+ -+ /* -+ * Put the USB host controller into reset. -+ */ -+ USB_RESET |= USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET; -+ -+ /* -+ * Stop the USB clock. -+ */ -+ SKPCR &= ~SKPCR_UCLKEN; -+ -+ /* -+ * Release memory resources. -+ */ -+// release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT); -+ -+#ifdef CONFIG_SA1100_BADGE4 -+ if (machine_is_badge4()) { -+ badge4_set_5V(BADGE4_5V_USB, 0); -+ } -+#endif -+} -+ -+module_init(sa1111_ohci_init); -+module_exit(sa1111_ohci_exit); -diff -urN linux-2.4.26/drivers/usb/host/usb-ohci.c linux-2.4.26-vrs1/drivers/usb/host/usb-ohci.c ---- linux-2.4.26/drivers/usb/host/usb-ohci.c 2004-04-19 11:44:27.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/usb/host/usb-ohci.c 2004-04-19 15:27:57.000000000 +0100 -@@ -12,7 +12,6 @@ - * - * History: - * -- * 2002/10/22 OHCI_USB_OPER for ALi lockup in IBM i1200 (ALEX ) - * 2002/03/08 interrupt unlink fix (Matt Hughes), better cleanup on - * load failure (Matthew Frederickson) - * 2002/01/20 async unlink fixes: return -EINPROGRESS (per spec) and -@@ -81,16 +80,6 @@ - - #include "../hcd.h" - --#ifdef CONFIG_PMAC_PBOOK --#include --#include --#include --#ifndef CONFIG_PM --#define CONFIG_PM --#endif --#endif -- -- - /* - * Version Information - */ -@@ -98,12 +87,12 @@ - #define DRIVER_AUTHOR "Roman Weissgaerber , David Brownell" - #define DRIVER_DESC "USB OHCI Host Controller Driver" - --/* For initializing controller (mask in an HCFS mode too) */ --#define OHCI_CONTROL_INIT \ -- (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE -- - #define OHCI_UNLINK_TIMEOUT (HZ / 10) - -+static LIST_HEAD (ohci_hcd_list); -+spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED; -+ -+ - /*-------------------------------------------------------------------------*/ - - /* AMD-756 (D2 rev) reports corrupt register contents in some cases. -@@ -130,57 +119,6 @@ - /*-------------------------------------------------------------------------* - * URB support functions - *-------------------------------------------------------------------------*/ -- --static void ohci_complete_add(struct ohci *ohci, struct urb *urb) --{ -- -- if (urb->hcpriv != NULL) { -- printk("completing with non-null priv!\n"); -- return; -- } -- -- if (ohci->complete_tail == NULL) { -- ohci->complete_head = urb; -- ohci->complete_tail = urb; -- } else { -- ohci->complete_head->hcpriv = urb; -- ohci->complete_tail = urb; -- } --} -- --static inline struct urb *ohci_complete_get(struct ohci *ohci) --{ -- struct urb *urb; -- -- if ((urb = ohci->complete_head) == NULL) -- return NULL; -- if (urb == ohci->complete_tail) { -- ohci->complete_tail = NULL; -- ohci->complete_head = NULL; -- } else { -- ohci->complete_head = urb->hcpriv; -- } -- urb->hcpriv = NULL; -- return urb; --} -- --static inline void ohci_complete(struct ohci *ohci) --{ -- struct urb *urb; -- -- spin_lock(&ohci->ohci_lock); -- while ((urb = ohci_complete_get(ohci)) != NULL) { -- spin_unlock(&ohci->ohci_lock); -- if (urb->dev) { -- usb_dec_dev_use (urb->dev); -- urb->dev = NULL; -- } -- if (urb->complete) -- (*urb->complete)(urb); -- spin_lock(&ohci->ohci_lock); -- } -- spin_unlock(&ohci->ohci_lock); --} - - /* free HCD-private data associated with this URB */ - -@@ -256,14 +194,20 @@ - } - - urb_free_priv ((struct ohci *)urb->dev->bus->hcpriv, urb_priv); -- } else { -- if (urb->dev != NULL) { -- err ("Non-null dev at rm_priv time"); -- // urb->dev = NULL; -- } -+ usb_dec_dev_use (urb->dev); -+ urb->dev = NULL; - } - } - -+static void urb_rm_priv (struct urb * urb) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave (&usb_ed_lock, flags); -+ urb_rm_priv_locked (urb); -+ spin_unlock_irqrestore (&usb_ed_lock, flags); -+} -+ - /*-------------------------------------------------------------------------*/ - - #ifdef DEBUG -@@ -484,7 +428,7 @@ - - static void ohci_dump (ohci_t *controller, int verbose) - { -- dbg ("OHCI controller usb-%s state", controller->ohci_dev->slot_name); -+ dbg ("OHCI controller usb-%s state", controller->slot_name); - - // dumps some of the state we know about - ohci_dump_status (controller); -@@ -507,6 +451,7 @@ - { - urb_priv_t * urb_priv = urb->hcpriv; - struct urb * urbt; -+ unsigned long flags; - int i; - - if (!urb_priv) -@@ -514,8 +459,7 @@ - - /* just to be sure */ - if (!urb->complete) { -- urb_rm_priv_locked (urb); -- ohci_complete_add(hc, urb); /* Just usb_dec_dev_use */ -+ urb_rm_priv (urb); - return -1; - } - -@@ -531,18 +475,20 @@ - usb_pipeout (urb->pipe) - ? PCI_DMA_TODEVICE - : PCI_DMA_FROMDEVICE); -+ - if (urb->interval) { - urb->complete (urb); -- -+ - /* implicitly requeued */ - urb->actual_length = 0; - urb->status = -EINPROGRESS; - td_submit_urb (urb); - } else { -- urb_rm_priv_locked (urb); -- ohci_complete_add(hc, urb); -+ urb_rm_priv(urb); -+ urb->complete (urb); - } -- break; -+ break; -+ - - case PIPE_ISOCHRONOUS: - for (urbt = urb->next; urbt && (urbt != urb); urbt = urbt->next); -@@ -554,6 +500,7 @@ - ? PCI_DMA_TODEVICE - : PCI_DMA_FROMDEVICE); - urb->complete (urb); -+ spin_lock_irqsave (&usb_ed_lock, flags); - urb->actual_length = 0; - urb->status = USB_ST_URB_PENDING; - urb->start_frame = urb_priv->ed->last_iso + 1; -@@ -564,17 +511,18 @@ - } - td_submit_urb (urb); - } -- -+ spin_unlock_irqrestore (&usb_ed_lock, flags); -+ - } else { /* unlink URB, call complete */ -- urb_rm_priv_locked (urb); -- ohci_complete_add(hc, urb); -+ urb_rm_priv (urb); -+ urb->complete (urb); - } - break; - - case PIPE_BULK: - case PIPE_CONTROL: /* unlink URB, call complete */ -- urb_rm_priv_locked (urb); -- ohci_complete_add(hc, urb); -+ urb_rm_priv (urb); -+ urb->complete (urb); - break; - } - return 0; -@@ -594,7 +542,7 @@ - int i, size = 0; - unsigned long flags; - int bustime = 0; -- int mem_flags = GFP_ATOMIC; -+ int mem_flags = ALLOC_FLAGS; - - if (!urb->dev || !urb->dev->bus) - return -ENODEV; -@@ -611,24 +559,20 @@ - #ifdef DEBUG - urb_print (urb, "SUB", usb_pipein (pipe)); - #endif -- -+ - /* handle a request to the virtual root hub */ - if (usb_pipedevice (pipe) == ohci->rh.devnum) - return rh_submit_urb (urb); -- -- spin_lock_irqsave(&ohci->ohci_lock, flags); -- -+ - /* when controller's hung, permit only roothub cleanup attempts - * such as powering down ports */ - if (ohci->disabled) { -- spin_unlock_irqrestore(&ohci->ohci_lock, flags); - usb_dec_dev_use (urb->dev); - return -ESHUTDOWN; - } - - /* every endpoint has a ed, locate and fill it */ - if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags))) { -- spin_unlock_irqrestore(&ohci->ohci_lock, flags); - usb_dec_dev_use (urb->dev); - return -ENOMEM; - } -@@ -650,7 +594,6 @@ - case PIPE_ISOCHRONOUS: /* number of packets from URB */ - size = urb->number_of_packets; - if (size <= 0) { -- spin_unlock_irqrestore(&ohci->ohci_lock, flags); - usb_dec_dev_use (urb->dev); - return -EINVAL; - } -@@ -670,9 +613,8 @@ - - /* allocate the private part of the URB */ - urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (td_t *), -- GFP_ATOMIC); -+ in_interrupt() ? GFP_ATOMIC : GFP_NOIO); - if (!urb_priv) { -- spin_unlock_irqrestore(&ohci->ohci_lock, flags); - usb_dec_dev_use (urb->dev); - return -ENOMEM; - } -@@ -683,12 +625,13 @@ - urb_priv->ed = ed; - - /* allocate the TDs (updating hash chains) */ -+ spin_lock_irqsave (&usb_ed_lock, flags); - for (i = 0; i < size; i++) { - urb_priv->td[i] = td_alloc (ohci, SLAB_ATOMIC); - if (!urb_priv->td[i]) { - urb_priv->length = i; - urb_free_priv (ohci, urb_priv); -- spin_unlock_irqrestore(&ohci->ohci_lock, flags); -+ spin_unlock_irqrestore (&usb_ed_lock, flags); - usb_dec_dev_use (urb->dev); - return -ENOMEM; - } -@@ -696,7 +639,7 @@ - - if (ed->state == ED_NEW || (ed->state & ED_DEL)) { - urb_free_priv (ohci, urb_priv); -- spin_unlock_irqrestore(&ohci->ohci_lock, flags); -+ spin_unlock_irqrestore (&usb_ed_lock, flags); - usb_dec_dev_use (urb->dev); - return -EINVAL; - } -@@ -718,7 +661,7 @@ - } - if (bustime < 0) { - urb_free_priv (ohci, urb_priv); -- spin_unlock_irqrestore(&ohci->ohci_lock, flags); -+ spin_unlock_irqrestore (&usb_ed_lock, flags); - usb_dec_dev_use (urb->dev); - return bustime; - } -@@ -744,6 +687,9 @@ - if (urb->timeout) { - struct list_head *entry; - -+ // FIXME: usb-uhci uses relative timeouts (like this), -+ // while uhci uses absolute ones (probably better). -+ // Pick one solution and change the affected drivers. - urb->timeout += jiffies; - - list_for_each (entry, &ohci->timeout_list) { -@@ -757,11 +703,10 @@ - - /* drive timeouts by SF (messy, but works) */ - writel (OHCI_INTR_SF, &ohci->regs->intrenable); -- (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */ - } - #endif - -- spin_unlock_irqrestore(&ohci->ohci_lock, flags); -+ spin_unlock_irqrestore (&usb_ed_lock, flags); - - return 0; - } -@@ -792,7 +737,6 @@ - if (usb_pipedevice (urb->pipe) == ohci->rh.devnum) - return rh_unlink_urb (urb); - -- spin_lock_irqsave(&ohci->ohci_lock, flags); - if (urb->hcpriv && (urb->status == USB_ST_URB_PENDING)) { - if (!ohci->disabled) { - urb_priv_t * urb_priv; -@@ -802,7 +746,6 @@ - */ - if (!(urb->transfer_flags & USB_ASYNC_UNLINK) - && in_interrupt ()) { -- spin_unlock_irqrestore(&ohci->ohci_lock, flags); - err ("bug in call from %p; use async!", - __builtin_return_address(0)); - return -EWOULDBLOCK; -@@ -811,10 +754,11 @@ - /* flag the urb and its TDs for deletion in some - * upcoming SF interrupt delete list processing - */ -+ spin_lock_irqsave (&usb_ed_lock, flags); - urb_priv = urb->hcpriv; - - if (!urb_priv || (urb_priv->state == URB_DEL)) { -- spin_unlock_irqrestore(&ohci->ohci_lock, flags); -+ spin_unlock_irqrestore (&usb_ed_lock, flags); - return 0; - } - -@@ -829,36 +773,26 @@ - - add_wait_queue (&unlink_wakeup, &wait); - urb_priv->wait = &unlink_wakeup; -- spin_unlock_irqrestore(&ohci->ohci_lock, flags); -+ spin_unlock_irqrestore (&usb_ed_lock, flags); - - /* wait until all TDs are deleted */ - set_current_state(TASK_UNINTERRUPTIBLE); -- while (timeout && (urb->status == USB_ST_URB_PENDING)) { -+ while (timeout && (urb->status == USB_ST_URB_PENDING)) - timeout = schedule_timeout (timeout); -- set_current_state(TASK_UNINTERRUPTIBLE); -- } - set_current_state(TASK_RUNNING); - remove_wait_queue (&unlink_wakeup, &wait); - if (urb->status == USB_ST_URB_PENDING) { - err ("unlink URB timeout"); - return -ETIMEDOUT; - } -- -- usb_dec_dev_use (urb->dev); -- urb->dev = NULL; -- if (urb->complete) -- urb->complete (urb); - } else { - /* usb_dec_dev_use done in dl_del_list() */ - urb->status = -EINPROGRESS; -- spin_unlock_irqrestore(&ohci->ohci_lock, flags); -+ spin_unlock_irqrestore (&usb_ed_lock, flags); - return -EINPROGRESS; - } - } else { -- urb_rm_priv_locked (urb); -- spin_unlock_irqrestore(&ohci->ohci_lock, flags); -- usb_dec_dev_use (urb->dev); -- urb->dev = NULL; -+ urb_rm_priv (urb); - if (urb->transfer_flags & USB_ASYNC_UNLINK) { - urb->status = -ECONNRESET; - if (urb->complete) -@@ -866,8 +800,6 @@ - } else - urb->status = -ENOENT; - } -- } else { -- spin_unlock_irqrestore(&ohci->ohci_lock, flags); - } - return 0; - } -@@ -910,14 +842,14 @@ - * (freeing all the TDs, unlinking EDs) but we need - * to defend against bugs that prevent that. - */ -- spin_lock_irqsave(&ohci->ohci_lock, flags); -+ spin_lock_irqsave (&usb_ed_lock, flags); - for(i = 0; i < NUM_EDS; i++) { - ed = &(dev->ed[i]); - if (ed->state != ED_NEW) { - if (ed->state == ED_OPER) { - /* driver on that interface didn't unlink an urb */ - dbg ("driver usb-%s dev %d ed 0x%x unfreed URB", -- ohci->ohci_dev->slot_name, usb_dev->devnum, i); -+ ohci->slot_name, usb_dev->devnum, i); - ep_unlink (ohci, ed); - } - ep_rm_ed (usb_dev, ed); -@@ -925,7 +857,7 @@ - cnt++; - } - } -- spin_unlock_irqrestore(&ohci->ohci_lock, flags); -+ spin_unlock_irqrestore (&usb_ed_lock, flags); - - /* if the controller is running, tds for those unlinked - * urbs get freed by dl_del_list at the next SF interrupt -@@ -962,7 +894,7 @@ - } else { - /* likely some interface's driver has a refcount bug */ - err ("bus %s devnum %d deletion in interrupt", -- ohci->ohci_dev->slot_name, usb_dev->devnum); -+ ohci->slot_name, usb_dev->devnum); - BUG (); - } - } -@@ -1259,12 +1191,17 @@ - td_t * td; - ed_t * ed_ret; - volatile ed_t * ed; -+ unsigned long flags; -+ -+ -+ spin_lock_irqsave (&usb_ed_lock, flags); - - ed = ed_ret = &(usb_to_ohci (usb_dev)->ed[(usb_pipeendpoint (pipe) << 1) | - (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))]); - - if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) { - /* pending delete request */ -+ spin_unlock_irqrestore (&usb_ed_lock, flags); - return NULL; - } - -@@ -1277,6 +1214,7 @@ - /* out of memory */ - if (td) - td_free(ohci, td); -+ spin_unlock_irqrestore (&usb_ed_lock, flags); - return NULL; - } - ed->hwTailP = cpu_to_le32 (td->td_dma); -@@ -1299,7 +1237,8 @@ - ed->int_period = interval; - ed->int_load = load; - } -- -+ -+ spin_unlock_irqrestore (&usb_ed_lock, flags); - return ed_ret; - } - -@@ -1340,7 +1279,6 @@ - /* enable SOF interrupt */ - writel (OHCI_INTR_SF, &ohci->regs->intrstatus); - writel (OHCI_INTR_SF, &ohci->regs->intrenable); -- (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */ - } - } - -@@ -1362,7 +1300,11 @@ - err("internal OHCI error: TD index > length"); - return; - } -- -+#ifdef CONFIG_SA1111 -+ if (data & (1 << 20)) -+ panic("td_fill: A20 = 1: %08x\n", data); -+#endif -+ - /* use this td as the next dummy */ - td_pt = urb_priv->td [index]; - td_pt->hwNextTD = 0; -@@ -1461,7 +1403,6 @@ - if (!ohci->sleeping) { - wmb(); - writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */ -- (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */ - } - break; - -@@ -1490,7 +1431,6 @@ - if (!ohci->sleeping) { - wmb(); - writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */ -- (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */ - } - break; - -@@ -1558,7 +1498,7 @@ - - /* handle an urb that is being unlinked */ - --static void dl_del_urb (ohci_t *ohci, struct urb * urb) -+static void dl_del_urb (struct urb * urb) - { - wait_queue_head_t * wait_head = ((urb_priv_t *)(urb->hcpriv))->wait; - -@@ -1566,9 +1506,12 @@ - - if (urb->transfer_flags & USB_ASYNC_UNLINK) { - urb->status = -ECONNRESET; -- ohci_complete_add(ohci, urb); -+ if (urb->complete) -+ urb->complete (urb); - } else { - urb->status = -ENOENT; -+ if (urb->complete) -+ urb->complete (urb); - - /* unblock sohci_unlink_urb */ - if (wait_head) -@@ -1587,7 +1530,10 @@ - td_t * td_rev = NULL; - td_t * td_list = NULL; - urb_priv_t * urb_priv = NULL; -- -+ unsigned long flags; -+ -+ spin_lock_irqsave (&usb_ed_lock, flags); -+ - td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0; - ohci->hcca->done_head = 0; - -@@ -1613,6 +1559,7 @@ - td_rev = td_list; - td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0; - } -+ spin_unlock_irqrestore (&usb_ed_lock, flags); - return td_list; - } - -@@ -1624,6 +1571,7 @@ - - static void dl_del_list (ohci_t * ohci, unsigned int frame) - { -+ unsigned long flags; - ed_t * ed; - __u32 edINFO; - __u32 tdINFO; -@@ -1631,6 +1579,8 @@ - __u32 * td_p; - int ctrl = 0, bulk = 0; - -+ spin_lock_irqsave (&usb_ed_lock, flags); -+ - for (ed = ohci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) { - - tdTailP = dma_to_td (ohci, le32_to_cpup (&ed->hwTailP) & 0xfffffff0); -@@ -1651,7 +1601,7 @@ - - /* URB is done; clean up */ - if (++(urb_priv->td_cnt) == urb_priv->length) -- dl_del_urb (ohci, urb); -+ dl_del_urb (urb); - } else { - td_p = &td->hwNextTD; - } -@@ -1708,6 +1658,7 @@ - } - - ohci->ed_rm_list[frame] = NULL; -+ spin_unlock_irqrestore (&usb_ed_lock, flags); - } - - -@@ -1724,7 +1675,9 @@ - struct urb * urb; - urb_priv_t * urb_priv; - __u32 tdINFO, edHeadP, edTailP; -- -+ -+ unsigned long flags; -+ - while (td_list) { - td_list_next = td_list->next_dl_td; - -@@ -1753,10 +1706,13 @@ - urb->status = cc_to_error[cc]; - sohci_return_urb (ohci, urb); - } else { -- dl_del_urb (ohci, urb); -+ spin_lock_irqsave (&usb_ed_lock, flags); -+ dl_del_urb (urb); -+ spin_unlock_irqrestore (&usb_ed_lock, flags); - } - } - -+ spin_lock_irqsave (&usb_ed_lock, flags); - if (ed->state != ED_NEW) { - edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0; - edTailP = le32_to_cpup (&ed->hwTailP); -@@ -1765,6 +1721,7 @@ - if ((edHeadP == edTailP) && (ed->state == ED_OPER)) - ep_unlink (ohci, ed); - } -+ spin_unlock_irqrestore (&usb_ed_lock, flags); - - td_list = td_list_next; - } -@@ -1855,7 +1812,7 @@ - num_ports = roothub_a (ohci) & RH_A_NDP; - if (num_ports > MAX_ROOT_PORTS) { - err ("bogus NDP=%d for OHCI usb-%s", num_ports, -- ohci->ohci_dev->slot_name); -+ ohci->slot_name); - err ("rereads as NDP=%d", - readl (&ohci->regs->roothub.a) & RH_A_NDP); - /* retry later; "should not happen" */ -@@ -1955,8 +1912,7 @@ - int leni = urb->transfer_buffer_length; - int len = 0; - int status = TD_CC_NOERROR; -- unsigned long flags; -- -+ - __u32 datab[4]; - __u8 * data_buf = (__u8 *) datab; - -@@ -1965,16 +1921,13 @@ - __u16 wIndex; - __u16 wLength; - -- spin_lock_irqsave(&ohci->ohci_lock, flags); -- - if (usb_pipeint(pipe)) { - ohci->rh.urb = urb; - ohci->rh.send = 1; - ohci->rh.interval = urb->interval; - rh_init_int_timer(urb); - urb->status = cc_to_error [TD_CC_NOERROR]; -- -- spin_unlock_irqrestore(&ohci->ohci_lock, flags); -+ - return 0; - } - -@@ -2146,7 +2099,6 @@ - #endif - - urb->hcpriv = NULL; -- spin_unlock_irqrestore(&ohci->ohci_lock, flags); - usb_dec_dev_use (usb_dev); - urb->dev = NULL; - if (urb->complete) -@@ -2159,16 +2111,13 @@ - static int rh_unlink_urb (struct urb * urb) - { - ohci_t * ohci = urb->dev->bus->hcpriv; -- unsigned int flags; - -- spin_lock_irqsave(&ohci->ohci_lock, flags); - if (ohci->rh.urb == urb) { - ohci->rh.send = 0; - del_timer (&ohci->rh.rh_int_timer); - ohci->rh.urb = NULL; - - urb->hcpriv = NULL; -- spin_unlock_irqrestore(&ohci->ohci_lock, flags); - usb_dec_dev_use(urb->dev); - urb->dev = NULL; - if (urb->transfer_flags & USB_ASYNC_UNLINK) { -@@ -2177,8 +2126,6 @@ - urb->complete (urb); - } else - urb->status = -ENOENT; -- } else { -- spin_unlock_irqrestore(&ohci->ohci_lock, flags); - } - return 0; - } -@@ -2213,16 +2160,12 @@ - writel (OHCI_INTR_MIE, &ohci->regs->intrdisable); - - dbg("USB HC reset_hc usb-%s: ctrl = 0x%x ;", -- ohci->ohci_dev->slot_name, -+ ohci->slot_name, - readl (&ohci->regs->control)); - - /* Reset USB (needed by some controllers) */ - writel (0, &ohci->regs->control); -- -- /* Force a state change from USBRESET to USBOPERATIONAL for ALi */ -- (void) readl (&ohci->regs->control); /* PCI posting */ -- writel (ohci->hc_control = OHCI_USB_OPER, &ohci->regs->control); -- -+ - /* HC Reset requires max 10 ms delay */ - writel (OHCI_HCR, &ohci->regs->cmdstatus); - while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) { -@@ -2291,8 +2234,6 @@ - writel (RH_HS_LPSC, &ohci->regs->roothub.status); - #endif /* OHCI_USE_NPS */ - -- (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */ -- - // POTPGT delay is bits 24-31, in 2 ms units. - mdelay ((roothub_a (ohci) >> 23) & 0x1fe); - -@@ -2322,7 +2263,7 @@ - - static void check_timeouts (struct ohci *ohci) - { -- spin_lock (&ohci->ohci_lock); -+ spin_lock (&usb_ed_lock); - while (!list_empty (&ohci->timeout_list)) { - struct urb *urb; - -@@ -2335,15 +2276,15 @@ - continue; - - urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK; -- spin_unlock (&ohci->ohci_lock); -+ spin_unlock (&usb_ed_lock); - - // outside the interrupt handler (in a timer...) - // this reference would race interrupts - sohci_unlink_urb (urb); - -- spin_lock (&ohci->ohci_lock); -+ spin_lock (&usb_ed_lock); - } -- spin_unlock (&ohci->ohci_lock); -+ spin_unlock (&usb_ed_lock); - } - - -@@ -2357,8 +2298,6 @@ - struct ohci_regs * regs = ohci->regs; - int ints; - -- spin_lock (&ohci->ohci_lock); -- - /* avoid (slow) readl if only WDH happened */ - if ((ohci->hcca->done_head != 0) - && !(le32_to_cpup (&ohci->hcca->done_head) & 0x01)) { -@@ -2367,22 +2306,20 @@ - /* cardbus/... hardware gone before remove() */ - } else if ((ints = readl (®s->intrstatus)) == ~(u32)0) { - ohci->disabled++; -- spin_unlock (&ohci->ohci_lock); - err ("%s device removed!", ohci->ohci_dev->slot_name); - return; - - /* interrupt for some other device? */ - } else if ((ints &= readl (®s->intrenable)) == 0) { -- spin_unlock (&ohci->ohci_lock); - return; -- } -+ } - - // dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); - - if (ints & OHCI_INTR_UE) { - ohci->disabled++; - err ("OHCI Unrecoverable Error, controller usb-%s disabled", -- ohci->ohci_dev->slot_name); -+ ohci->slot_name); - // e.g. due to PCI Master/Target Abort - - #ifdef DEBUG -@@ -2398,39 +2335,26 @@ - - if (ints & OHCI_INTR_WDH) { - writel (OHCI_INTR_WDH, ®s->intrdisable); -- (void)readl (®s->intrdisable); /* PCI posting flush */ - dl_done_list (ohci, dl_reverse_done_list (ohci)); - writel (OHCI_INTR_WDH, ®s->intrenable); -- (void)readl (®s->intrdisable); /* PCI posting flush */ - } - - if (ints & OHCI_INTR_SO) { - dbg("USB Schedule overrun"); - writel (OHCI_INTR_SO, ®s->intrenable); -- (void)readl (®s->intrdisable); /* PCI posting flush */ - } - - // FIXME: this assumes SOF (1/ms) interrupts don't get lost... - if (ints & OHCI_INTR_SF) { - unsigned int frame = le16_to_cpu (ohci->hcca->frame_no) & 1; - writel (OHCI_INTR_SF, ®s->intrdisable); -- (void)readl (®s->intrdisable); /* PCI posting flush */ - if (ohci->ed_rm_list[!frame] != NULL) { - dl_del_list (ohci, !frame); - } -- if (ohci->ed_rm_list[frame] != NULL) { -+ if (ohci->ed_rm_list[frame] != NULL) - writel (OHCI_INTR_SF, ®s->intrenable); -- (void)readl (®s->intrdisable); /* PCI posting flush */ -- } - } - -- /* -- * Finally, we are done with trashing about our hardware lists -- * and other CPUs are allowed in. The festive flipping of the lock -- * ensues as we struggle with the check_timeouts disaster. -- */ -- spin_unlock (&ohci->ohci_lock); -- - if (!list_empty (&ohci->timeout_list)) { - check_timeouts (ohci); - // FIXME: enable SF as needed in a timer; -@@ -2442,9 +2366,6 @@ - - writel (ints, ®s->intrstatus); - writel (OHCI_INTR_MIE, ®s->intrenable); -- (void)readl (®s->intrdisable); /* PCI posting flush */ -- -- ohci_complete(ohci); - } - - /*-------------------------------------------------------------------------*/ -@@ -2475,10 +2396,14 @@ - ohci->regs = mem_base; - - ohci->ohci_dev = dev; -+#ifdef CONFIG_PCI - pci_set_drvdata(dev, ohci); -+#endif - -+ INIT_LIST_HEAD (&ohci->ohci_hcd_list); -+ list_add (&ohci->ohci_hcd_list, &ohci_hcd_list); -+ - INIT_LIST_HEAD (&ohci->timeout_list); -- spin_lock_init(&ohci->ohci_lock); - - ohci->bus = usb_alloc_bus (&sohci_device_operations); - if (!ohci->bus) { -@@ -2501,7 +2426,7 @@ - - static void hc_release_ohci (ohci_t * ohci) - { -- dbg ("USB HC release ohci usb-%s", ohci->ohci_dev->slot_name); -+ dbg ("USB HC release ohci usb-%s", ohci->slot_name); - - /* disconnect all devices */ - if (ohci->bus->root_hub) -@@ -2514,7 +2439,9 @@ - free_irq (ohci->irq, ohci); - ohci->irq = -1; - } -- pci_set_drvdata(ohci->ohci_dev, NULL); -+#ifdef CONFIG_PCI -+ pci_set_drvdata(ohci->ohci_dev, 0); -+#endif - if (ohci->bus) { - if (ohci->bus->busnum != -1) - usb_deregister_bus (ohci->bus); -@@ -2522,6 +2449,9 @@ - usb_free_bus (ohci->bus); - } - -+ list_del (&ohci->ohci_hcd_list); -+ INIT_LIST_HEAD (&ohci->ohci_hcd_list); -+ - ohci_mem_cleanup (ohci); - - /* unmap the IO address space */ -@@ -2534,17 +2464,15 @@ - - /*-------------------------------------------------------------------------*/ - --/* Increment the module usage count, start the control thread and -- * return success. */ -- --static struct pci_driver ohci_pci_driver; -- --static int __devinit --hc_found_ohci (struct pci_dev *dev, int irq, -- void *mem_base, const struct pci_device_id *id) -+/* -+ * Host bus independent add one OHCI host controller. -+ */ -+int __devinit -+hc_add_ohci(struct pci_dev *dev, int irq, void *mem_base, unsigned long flags, -+ const char *name, const char *slot_name) - { -- ohci_t * ohci; - char buf[8], *bufp = buf; -+ ohci_t * ohci; - int ret; - - #ifndef __sparc__ -@@ -2554,34 +2482,17 @@ - #endif - printk(KERN_INFO __FILE__ ": USB OHCI at membase 0x%lx, IRQ %s\n", - (unsigned long) mem_base, bufp); -- printk(KERN_INFO __FILE__ ": usb-%s, %s\n", dev->slot_name, dev->name); -- -+ - ohci = hc_alloc_ohci (dev, mem_base); - if (!ohci) { - return -ENOMEM; - } -+ ohci->slot_name = slot_name; - if ((ret = ohci_mem_init (ohci)) < 0) { - hc_release_ohci (ohci); - return ret; - } -- ohci->flags = id->driver_data; -- -- /* Check for NSC87560. We have to look at the bridge (fn1) to identify -- the USB (fn2). This quirk might apply to more or even all NSC stuff -- I don't know.. */ -- -- if(dev->vendor == PCI_VENDOR_ID_NS) -- { -- struct pci_dev *fn1 = pci_find_slot(dev->bus->number, PCI_DEVFN(PCI_SLOT(dev->devfn), 1)); -- if(fn1 && fn1->vendor == PCI_VENDOR_ID_NS && fn1->device == PCI_DEVICE_ID_NS_87560_LIO) -- ohci->flags |= OHCI_QUIRK_SUCKYIO; -- -- } -- -- if (ohci->flags & OHCI_QUIRK_SUCKYIO) -- printk (KERN_INFO __FILE__ ": Using NSC SuperIO setup\n"); -- if (ohci->flags & OHCI_QUIRK_AMD756) -- printk (KERN_INFO __FILE__ ": AMD756 erratum 4 workaround\n"); -+ ohci->flags = flags; - - if (hc_reset (ohci) < 0) { - hc_release_ohci (ohci); -@@ -2590,13 +2501,11 @@ - - /* FIXME this is a second HC reset; why?? */ - writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control); -- (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */ - wait_ms (10); - - usb_register_bus (ohci->bus); - -- if (request_irq (irq, hc_interrupt, SA_SHIRQ, -- ohci_pci_driver.name, ohci) != 0) { -+ if (request_irq (irq, hc_interrupt, SA_SHIRQ, name, ohci) != 0) { - err ("request interrupt %s failed", bufp); - hc_release_ohci (ohci); - return -EBUSY; -@@ -2604,7 +2513,7 @@ - ohci->irq = irq; - - if (hc_start (ohci) < 0) { -- err ("can't start usb-%s", dev->slot_name); -+ err ("can't start usb-%s", ohci->slot_name); - hc_release_ohci (ohci); - return -EBUSY; - } -@@ -2615,114 +2524,11 @@ - return 0; - } - --/*-------------------------------------------------------------------------*/ -- --#ifdef CONFIG_PM -- --/* controller died; cleanup debris, then restart */ --/* must not be called from interrupt context */ -- --static void hc_restart (ohci_t *ohci) --{ -- int temp; -- int i; -- -- if (ohci->pci_latency) -- pci_write_config_byte (ohci->ohci_dev, PCI_LATENCY_TIMER, ohci->pci_latency); -- -- ohci->disabled = 1; -- ohci->sleeping = 0; -- if (ohci->bus->root_hub) -- usb_disconnect (&ohci->bus->root_hub); -- -- /* empty the interrupt branches */ -- for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0; -- for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table[i] = 0; -- -- /* no EDs to remove */ -- ohci->ed_rm_list [0] = NULL; -- ohci->ed_rm_list [1] = NULL; -- -- /* empty control and bulk lists */ -- ohci->ed_isotail = NULL; -- ohci->ed_controltail = NULL; -- ohci->ed_bulktail = NULL; -- -- if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) { -- err ("can't restart usb-%s, %d", ohci->ohci_dev->slot_name, temp); -- } else -- dbg ("restart usb-%s completed", ohci->ohci_dev->slot_name); --} -- --#endif /* CONFIG_PM */ -- --/*-------------------------------------------------------------------------*/ -- --/* configured so that an OHCI device is always provided */ --/* always called with process context; sleeping is OK */ -- --static int __devinit --ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) -+/* -+ * Host bus independent remove one OHCI host controller. -+ */ -+void __devexit hc_remove_ohci(ohci_t *ohci) - { -- unsigned long mem_resource, mem_len; -- void *mem_base; -- int status; -- -- if (pci_enable_device(dev) < 0) -- return -ENODEV; -- -- if (!dev->irq) { -- err("found OHCI device with no IRQ assigned. check BIOS settings!"); -- pci_disable_device (dev); -- return -ENODEV; -- } -- -- /* we read its hardware registers as memory */ -- mem_resource = pci_resource_start(dev, 0); -- mem_len = pci_resource_len(dev, 0); -- if (!request_mem_region (mem_resource, mem_len, ohci_pci_driver.name)) { -- dbg ("controller already in use"); -- pci_disable_device (dev); -- return -EBUSY; -- } -- -- mem_base = ioremap_nocache (mem_resource, mem_len); -- if (!mem_base) { -- err("Error mapping OHCI memory"); -- release_mem_region (mem_resource, mem_len); -- pci_disable_device (dev); -- return -EFAULT; -- } -- -- /* controller writes into our memory */ -- pci_set_master (dev); -- -- status = hc_found_ohci (dev, dev->irq, mem_base, id); -- if (status < 0) { -- iounmap (mem_base); -- release_mem_region (mem_resource, mem_len); -- pci_disable_device (dev); -- } -- return status; --} -- --/*-------------------------------------------------------------------------*/ -- --/* may be called from interrupt context [interface spec] */ --/* may be called without controller present */ --/* may be called with controller, bus, and devices active */ -- --static void __devexit --ohci_pci_remove (struct pci_dev *dev) --{ -- ohci_t *ohci = pci_get_drvdata(dev); -- -- dbg ("remove %s controller usb-%s%s%s", -- hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS), -- dev->slot_name, -- ohci->disabled ? " (disabled)" : "", -- in_interrupt () ? " in interrupt" : "" -- ); - #ifdef DEBUG - ohci_dump (ohci, 1); - #endif -@@ -2739,270 +2545,8 @@ - &ohci->regs->control); - - hc_release_ohci (ohci); -- -- release_mem_region (pci_resource_start (dev, 0), pci_resource_len (dev, 0)); -- pci_disable_device (dev); --} -- -- --#ifdef CONFIG_PM -- --/*-------------------------------------------------------------------------*/ -- --static int --ohci_pci_suspend (struct pci_dev *dev, u32 state) --{ -- ohci_t *ohci = pci_get_drvdata(dev); -- unsigned long flags; -- u16 cmd; -- -- if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) { -- dbg ("can't suspend usb-%s (state is %s)", dev->slot_name, -- hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS)); -- return -EIO; -- } -- -- /* act as if usb suspend can always be used */ -- info ("USB suspend: usb-%s", dev->slot_name); -- ohci->sleeping = 1; -- -- /* First stop processing */ -- spin_lock_irqsave (&ohci->ohci_lock, flags); -- ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE); -- writel (ohci->hc_control, &ohci->regs->control); -- writel (OHCI_INTR_SF, &ohci->regs->intrstatus); -- (void) readl (&ohci->regs->intrstatus); -- spin_unlock_irqrestore (&ohci->ohci_lock, flags); -- -- /* Wait a frame or two */ -- mdelay(1); -- if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF) -- mdelay (1); -- --#ifdef CONFIG_PMAC_PBOOK -- if (_machine == _MACH_Pmac) -- disable_irq (ohci->irq); -- /* else, 2.4 assumes shared irqs -- don't disable */ --#endif -- /* Enable remote wakeup */ -- writel (readl(&ohci->regs->intrenable) | OHCI_INTR_RD, &ohci->regs->intrenable); -- -- /* Suspend chip and let things settle down a bit */ -- ohci->hc_control = OHCI_USB_SUSPEND; -- writel (ohci->hc_control, &ohci->regs->control); -- (void) readl (&ohci->regs->control); -- mdelay (500); /* No schedule here ! */ -- switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) { -- case OHCI_USB_RESET: -- dbg("Bus in reset phase ???"); -- break; -- case OHCI_USB_RESUME: -- dbg("Bus in resume phase ???"); -- break; -- case OHCI_USB_OPER: -- dbg("Bus in operational phase ???"); -- break; -- case OHCI_USB_SUSPEND: -- dbg("Bus suspended"); -- break; -- } -- /* In some rare situations, Apple's OHCI have happily trashed -- * memory during sleep. We disable it's bus master bit during -- * suspend -- */ -- pci_read_config_word (dev, PCI_COMMAND, &cmd); -- cmd &= ~PCI_COMMAND_MASTER; -- pci_write_config_word (dev, PCI_COMMAND, cmd); --#ifdef CONFIG_PMAC_PBOOK -- { -- struct device_node *of_node; -- -- /* Disable USB PAD & cell clock */ -- of_node = pci_device_to_OF_node (ohci->ohci_dev); -- if (of_node) -- pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0); -- } --#endif -- return 0; --} -- --/*-------------------------------------------------------------------------*/ -- --static int --ohci_pci_resume (struct pci_dev *dev) --{ -- ohci_t *ohci = pci_get_drvdata(dev); -- int temp; -- unsigned long flags; -- -- /* guard against multiple resumes */ -- atomic_inc (&ohci->resume_count); -- if (atomic_read (&ohci->resume_count) != 1) { -- err ("concurrent PCI resumes for usb-%s", dev->slot_name); -- atomic_dec (&ohci->resume_count); -- return 0; -- } -- --#ifdef CONFIG_PMAC_PBOOK -- { -- struct device_node *of_node; -- -- /* Re-enable USB PAD & cell clock */ -- of_node = pci_device_to_OF_node (ohci->ohci_dev); -- if (of_node) -- pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 1); -- } --#endif -- -- /* did we suspend, or were we powered off? */ -- ohci->hc_control = readl (&ohci->regs->control); -- temp = ohci->hc_control & OHCI_CTRL_HCFS; -- --#ifdef DEBUG -- /* the registers may look crazy here */ -- ohci_dump_status (ohci); --#endif -- -- /* Re-enable bus mastering */ -- pci_set_master(ohci->ohci_dev); -- -- switch (temp) { -- -- case OHCI_USB_RESET: // lost power -- info ("USB restart: usb-%s", dev->slot_name); -- hc_restart (ohci); -- break; -- -- case OHCI_USB_SUSPEND: // host wakeup -- case OHCI_USB_RESUME: // remote wakeup -- info ("USB continue: usb-%s from %s wakeup", dev->slot_name, -- (temp == OHCI_USB_SUSPEND) -- ? "host" : "remote"); -- ohci->hc_control = OHCI_USB_RESUME; -- writel (ohci->hc_control, &ohci->regs->control); -- (void) readl (&ohci->regs->control); -- mdelay (20); /* no schedule here ! */ -- /* Some controllers (lucent) need a longer delay here */ -- mdelay (15); -- temp = readl (&ohci->regs->control); -- temp = ohci->hc_control & OHCI_CTRL_HCFS; -- if (temp != OHCI_USB_RESUME) { -- err ("controller usb-%s won't resume", dev->slot_name); -- ohci->disabled = 1; -- return -EIO; -- } -- -- /* Some chips likes being resumed first */ -- writel (OHCI_USB_OPER, &ohci->regs->control); -- (void) readl (&ohci->regs->control); -- mdelay (3); -- -- /* Then re-enable operations */ -- spin_lock_irqsave (&ohci->ohci_lock, flags); -- ohci->disabled = 0; -- ohci->sleeping = 0; -- ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; -- if (!ohci->ed_rm_list[0] && !ohci->ed_rm_list[1]) { -- if (ohci->ed_controltail) -- ohci->hc_control |= OHCI_CTRL_CLE; -- if (ohci->ed_bulktail) -- ohci->hc_control |= OHCI_CTRL_BLE; -- } -- writel (ohci->hc_control, &ohci->regs->control); -- writel (OHCI_INTR_SF, &ohci->regs->intrstatus); -- writel (OHCI_INTR_SF, &ohci->regs->intrenable); -- /* Check for a pending done list */ -- writel (OHCI_INTR_WDH, &ohci->regs->intrdisable); -- (void) readl (&ohci->regs->intrdisable); --#ifdef CONFIG_PMAC_PBOOK -- if (_machine == _MACH_Pmac) -- enable_irq (ohci->irq); --#endif -- if (ohci->hcca->done_head) -- dl_done_list (ohci, dl_reverse_done_list (ohci)); -- writel (OHCI_INTR_WDH, &ohci->regs->intrenable); -- writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */ -- writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */ -- spin_unlock_irqrestore (&ohci->ohci_lock, flags); -- break; -- -- default: -- warn ("odd PCI resume for usb-%s", dev->slot_name); -- } -- -- /* controller is operational, extra resumes are harmless */ -- atomic_dec (&ohci->resume_count); -- -- return 0; --} -- --#endif /* CONFIG_PM */ -- -- --/*-------------------------------------------------------------------------*/ -- --static const struct pci_device_id __devinitdata ohci_pci_ids [] = { { -- -- /* -- * AMD-756 [Viper] USB has a serious erratum when used with -- * lowspeed devices like mice. -- */ -- vendor: 0x1022, -- device: 0x740c, -- subvendor: PCI_ANY_ID, -- subdevice: PCI_ANY_ID, -- -- driver_data: OHCI_QUIRK_AMD756, -- --} , { -- -- /* handle any USB OHCI controller */ -- class: ((PCI_CLASS_SERIAL_USB << 8) | 0x10), -- class_mask: ~0, -- -- /* no matter who makes it */ -- vendor: PCI_ANY_ID, -- device: PCI_ANY_ID, -- subvendor: PCI_ANY_ID, -- subdevice: PCI_ANY_ID, -- -- }, { /* end: all zeroes */ } --}; -- --MODULE_DEVICE_TABLE (pci, ohci_pci_ids); -- --static struct pci_driver ohci_pci_driver = { -- name: "usb-ohci", -- id_table: &ohci_pci_ids [0], -- -- probe: ohci_pci_probe, -- remove: __devexit_p(ohci_pci_remove), -- --#ifdef CONFIG_PM -- suspend: ohci_pci_suspend, -- resume: ohci_pci_resume, --#endif /* PM */ --}; -- -- --/*-------------------------------------------------------------------------*/ -- --static int __init ohci_hcd_init (void) --{ -- return pci_module_init (&ohci_pci_driver); - } - --/*-------------------------------------------------------------------------*/ -- --static void __exit ohci_hcd_cleanup (void) --{ -- pci_unregister_driver (&ohci_pci_driver); --} -- --module_init (ohci_hcd_init); --module_exit (ohci_hcd_cleanup); -- -- - MODULE_AUTHOR( DRIVER_AUTHOR ); - MODULE_DESCRIPTION( DRIVER_DESC ); - MODULE_LICENSE("GPL"); -diff -urN linux-2.4.26/drivers/usb/host/usb-ohci.h linux-2.4.26-vrs1/drivers/usb/host/usb-ohci.h ---- linux-2.4.26/drivers/usb/host/usb-ohci.h 2004-04-19 11:44:27.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/usb/host/usb-ohci.h 2004-04-19 17:13:29.000000000 +0100 -@@ -384,12 +384,13 @@ - #define OHCI_QUIRK_SUCKYIO 0x02 /* NSC superio */ - - struct ohci_regs * regs; /* OHCI controller's memory */ -+ struct list_head ohci_hcd_list; /* list of all ohci_hcd */ - -+ struct ohci * next; // chain of ohci device contexts - struct list_head timeout_list; - // struct list_head urb_list; // list of all pending urbs -- spinlock_t ohci_lock; /* Covers all fields up & down */ -- struct urb *complete_head, *complete_tail; -- -+ // spinlock_t urb_list_lock; // lock to keep consistency -+ - int ohci_int_load[32]; /* load of the 32 Interrupt Chains (for load balancing)*/ - ed_t * ed_rm_list[2]; /* lists of all endpoints to be removed */ - ed_t * ed_bulktail; /* last endpoint of bulk list */ -@@ -403,6 +404,7 @@ - - /* PCI device handle, settings, ... */ - struct pci_dev *ohci_dev; -+ const char *slot_name; - u8 pci_latency; - struct pci_pool *td_cache; - struct pci_pool *dev_cache; -@@ -448,7 +450,7 @@ - #endif - - #ifndef CONFIG_PCI --# error "usb-ohci currently requires PCI-based controllers" -+//# error "usb-ohci currently requires PCI-based controllers" - /* to support non-PCI OHCIs, you need custom bus/mem/... glue */ - #endif - -@@ -641,3 +643,6 @@ - pci_pool_free (hc->dev_cache, dev, dev->dma); - } - -+/* For initializing controller (mask in an HCFS mode too) */ -+#define OHCI_CONTROL_INIT \ -+ (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE -diff -urN linux-2.4.26/drivers/video/Config.in linux-2.4.26-vrs1/drivers/video/Config.in ---- linux-2.4.26/drivers/video/Config.in 2004-02-27 20:03:27.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/video/Config.in 2004-02-23 23:25:16.000000000 +0000 -@@ -30,13 +30,28 @@ - tristate ' Permedia3 support (EXPERIMENTAL)' CONFIG_FB_PM3 - fi - fi -- if [ "$CONFIG_ARCH_ACORN" = "y" ]; then -- bool ' Acorn VIDC support' CONFIG_FB_ACORN -- fi -- dep_tristate ' Cyber2000 support' CONFIG_FB_CYBER2000 $CONFIG_PCI -- if [ "$CONFIG_ARCH_SA1100" = "y" ]; then -- bool ' SA-1100 LCD support' CONFIG_FB_SA1100 -+ if [ "$CONFIG_ARM" = "y" ]; then -+ if [ "$CONFIG_ARCH_ACORN" -o "$CONFIG_ARCH_RISCSTATION" ]; then -+ bool ' Acorn VIDC support' CONFIG_FB_ACORN -+ else -+ define_bool CONFIG_FB_ACORN n -+ fi -+ dep_bool ' Anakin LCD support' CONFIG_FB_ANAKIN $CONFIG_ARCH_ANAKIN -+ dep_bool ' CLPS711X LCD support' CONFIG_FB_CLPS711X $CONFIG_ARCH_CLPS711X -+ dep_bool ' SA-1100 LCD support' CONFIG_FB_SA1100 $CONFIG_ARCH_SA1100 -+ dep_bool ' MX1ADS LCD support' CONFIG_FB_DBMX1 $CONFIG_ARCH_MX1ADS -+ if [ "$CONFIG_FB_SA1100" = "y" -a "$CONFIG_SA1100_CERF" = "y" ]; then -+ choice 'CerfBoard LCD Display Size' \ -+ "3.8_Color CONFIG_CERF_LCD_38_A \ -+ 3.8_Mono CONFIG_CERF_LCD_38_B \ -+ 5.7 CONFIG_CERF_LCD_57_A \ -+ 7.2 CONFIG_CERF_LCD_72_A" 5.7 -+ fi -+ if [ "$CONFIG_FB_SA1100" = "y" -a "$CONFIG_SA1100_CERF_CPLD" = "y" ]; then -+ bool 'Cerfboard Backlight (CerfPDA)' CONFIG_SA1100_CERF_LCD_BACKLIGHT -+ fi - fi -+ dep_tristate ' CyberPro 2000/2010/5000 support' CONFIG_FB_CYBER2000 $CONFIG_PCI - if [ "$CONFIG_APOLLO" = "y" ]; then - define_bool CONFIG_FB_APOLLO y - fi -@@ -265,7 +280,7 @@ - "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_RETINAZ3" = "y" -o \ - "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ - "$CONFIG_FB_BWTWO" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ -- "$CONFIG_FB_TX3912" = "y" ]; then -+ "$CONFIG_FB_TX3912" = "y" -o "$CONFIG_FB_CLPS711X" = "y" ]; then - define_tristate CONFIG_FBCON_MFB y - else - if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_AMIGA" = "m" -o \ -@@ -273,19 +288,20 @@ - "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_RETINAZ3" = "m" -o \ - "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ - "$CONFIG_FB_BWTWO" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ -- "$CONFIG_FB_TX3912" = "m" ]; then -+ "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_CLPS711X" = "m" ]; then - define_tristate CONFIG_FBCON_MFB m - fi - fi - if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_MAC" = "y" -o \ - "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ -- "$CONFIG_FB_TX3912" = "y" ]; then -+ "$CONFIG_FB_TX3912" = "y" -o "$CONFIG_FB_CLPS711X" = "y" -o \ -+ "$CONFIG_FB_DBMX1" = "y" ]; then - define_tristate CONFIG_FBCON_CFB2 y - define_tristate CONFIG_FBCON_CFB4 y - else - if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_MAC" = "m" -o \ - "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ -- "$CONFIG_FB_TX3912" = "m" ]; then -+ "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_CLPS711X" = "m" ]; then - define_tristate CONFIG_FBCON_CFB2 m - define_tristate CONFIG_FBCON_CFB4 m - fi -@@ -312,7 +328,8 @@ - "$CONFIG_FB_TX3912" = "y" -o \ - "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" -o \ - "$CONFIG_FB_STI" = "y" -o "$CONFIG_FB_HP300" = "y" -o \ -- "$CONFIG_FB_INTEL" = "y" ]; then -+ "$CONFIG_FB_INTEL" = "y" -o \ -+ "$CONFIG_FB_DBMX1" = "y" ]; then - define_tristate CONFIG_FBCON_CFB8 y - else - if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \ -@@ -354,7 +371,9 @@ - "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \ - "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \ - "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \ -- "$CONFIG_FB_NEOMAGIC" = "y" -o "$CONFIG_FB_INTEL" = "y" ]; then -+ "$CONFIG_FB_NEOMAGIC" = "y" -o "$CONFIG_FB_INTEL" = "y" -o \ -+ "$CONFIG_FB_ANAKIN" = "y" -o \ -+ "$CONFIG_FB_DBMX1" = "y" ]; then - define_tristate CONFIG_FBCON_CFB16 y - else - if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ -@@ -509,6 +528,9 @@ - if [ "$CONFIG_AMIGA" = "y" ]; then - define_bool CONFIG_FONT_PEARL_8x8 y - fi -+ if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_RISCSTATION" = "y" ]; then -+ define_bool CONFIG_FONT_ACORN_8x8 y -+ fi - if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_ACORN" = "y" ]; then - define_bool CONFIG_FONT_ACORN_8x8 y - fi -diff -urN linux-2.4.26/drivers/video/Makefile linux-2.4.26-vrs1/drivers/video/Makefile ---- linux-2.4.26/drivers/video/Makefile 2004-02-27 20:03:27.000000000 +0000 -+++ linux-2.4.26-vrs1/drivers/video/Makefile 2004-02-23 13:36:35.000000000 +0000 -@@ -55,6 +55,7 @@ - obj-$(CONFIG_FB_PLATINUM) += platinumfb.o - obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o - obj-$(CONFIG_FB_CT65550) += chipsfb.o -+obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o - obj-$(CONFIG_FB_CYBER) += cyberfb.o - obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o - obj-$(CONFIG_FB_SGIVW) += sgivwfb.o -@@ -68,7 +69,7 @@ - obj-$(CONFIG_FB_TRIDENT) += tridentfb.o fbgen.o - obj-$(CONFIG_FB_S3TRIO) += S3triofb.o - obj-$(CONFIG_FB_TGA) += tgafb.o fbgen.o --obj-$(CONFIG_FB_VESA) += vesafb.o -+obj-$(CONFIG_FB_VESA) += vesafb.o - obj-$(CONFIG_FB_VGA16) += vga16fb.o fbcon-vga-planes.o - obj-$(CONFIG_FB_VIRGE) += virgefb.o - obj-$(CONFIG_FB_G364) += g364fb.o -@@ -126,14 +127,16 @@ - - obj-$(CONFIG_FB_SUN3) += sun3fb.o - obj-$(CONFIG_FB_BWTWO) += bwtwofb.o --obj-$(CONFIG_FB_HGA) += hgafb.o -+obj-$(CONFIG_FB_HGA) += hgafb.o - obj-$(CONFIG_FB_SA1100) += sa1100fb.o --obj-$(CONFIG_FB_VIRTUAL) += vfb.o -+obj-$(CONFIG_FB_DBMX1) += dbmx1fb.o -+obj-$(CONFIG_FB_VIRTUAL) += vfb.o - obj-$(CONFIG_FB_HIT) += hitfb.o fbgen.o - obj-$(CONFIG_FB_E1355) += epson1355fb.o fbgen.o - obj-$(CONFIG_FB_E1356) += epson1356fb.o - obj-$(CONFIG_FB_PVR2) += pvr2fb.o - obj-$(CONFIG_FB_VOODOO1) += sstfb.o -+obj-$(CONFIG_FB_ANAKIN) += anakinfb.o - - # Generic Low Level Drivers - -@@ -169,4 +172,3 @@ - -e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > promcon_tbl.c - - promcon_tbl.o: promcon_tbl.c $(TOPDIR)/include/linux/types.h -- -diff -urN linux-2.4.26/drivers/video/acornfb.c linux-2.4.26-vrs1/drivers/video/acornfb.c ---- linux-2.4.26/drivers/video/acornfb.c 2002-08-03 01:39:45.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/video/acornfb.c 2004-01-14 21:32:26.000000000 +0000 -@@ -752,11 +752,12 @@ - } - #endif - #ifdef FBCON_HAS_CFB16 -- if (bpp == 16 && regno < 16) { -+ if (bpp == 16) { - int i; - -- current_par.cmap.cfb16[regno] = -- regno | regno << 5 | regno << 10; -+ if (regno < 16) -+ current_par.cmap.cfb16[regno] = -+ regno | regno << 5 | regno << 10; - - pal.p = 0; - vidc_writel(0x10000000); -@@ -1215,7 +1216,7 @@ - p.vidc20.green = current_par.palette[(i >> 1) & 31].vidc20.green; - p.vidc20.blue = current_par.palette[(i >> 2) & 31].vidc20.blue; - } -- acornfb_palette_write(i, current_par.palette[i]); -+ acornfb_palette_write(i, p); - } - } else - #endif -diff -urN linux-2.4.26/drivers/video/anakinfb.c linux-2.4.26-vrs1/drivers/video/anakinfb.c ---- linux-2.4.26/drivers/video/anakinfb.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.26-vrs1/drivers/video/anakinfb.c 2004-01-14 21:32:26.000000000 +0000 -@@ -0,0 +1,221 @@ -+/* -+ * linux/drivers/video/anakinfb.c -+ * -+ * Copyright (C) 2001 Aleph One Ltd. for Acunia N.V. -+ * -+ * 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: -+ * 23-Apr-2001 TTC Created -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include