From f96441b9faf769c9ecdd4d338b605ea3d0cc4010 Mon Sep 17 00:00:00 2001 From: Chris Larson <clarson@kergoth.com> Date: Tue, 9 Nov 2004 00:36:47 +0000 Subject: Disable bk EOLN_NATIVE conversions on all files in packages FILESPATHs, to prevent it screwing up patches. BKrev: 4190111fA4MuVozAqwE7xOSL9fr-TA --- linux/files/linux-2.4-cpufreq.patch | 20 + linux/files/linux-2.4-no-short-loads.patch | 18 + linux/files/linux-2.4.18-list_move.patch | 32 + linux/gumstix-2.6.5-gnalm1-gum0/defconfig | 777 + .../linux-2.6.5-gnalm1.patch | 20991 +++++ .../defconfig-ipaqpxa | 1575 + .../defconfig-ipaqpxa | 1577 + .../defconfig-ipaqpxa | 1578 + .../defconfig-ipaqpxa | 1578 + linux/handhelds-pxa-2.6/defconfig-ipaq-pxa-2.6 | 1304 + .../defconfig-ipaq-pxa-2.6_2.6.8.1-hh0 | 1382 + .../defconfig-ipaqsa | 1505 + .../disable-pcmcia-probe.patch | 17 + .../ipsec.patch | 1446 + .../mkdep.patch | 16 + .../defconfig-ipaqsa | 1508 + linux/handhelds-sa-2.6/defconfig-jornada56x | 877 + linux/linux-bast-2.4.25-vrs1-bast1/defconfig | 1115 + linux/linux-bast-2.4.25-vrs1-bast1/mkdep.patch | 16 + linux/linux-mtx-1-2.4.24/defconfig-mtx-1 | 1265 + linux/linux-mtx-1-2.4.27/defconfig-mtx-1 | 1183 + linux/linux-mtx-1-2.4.27/mtx-1-board-reset.diff | 15 + linux/linux-mtx-1-2.4.27/zimage-flash-bin.patch | 11 + .../omap1610h2/defconfig | 840 + .../schedstats-arm.patch | 26 + linux/linux-sun4cdm-2.4.26/defconfig | 473 + linux/linux-sun4cdm-2.6.8.1/sun4c_defconfig | 689 + linux/linux-xxs1500-2.4.21/Makefile | 756 + linux/linux-xxs1500-2.4.21/defconfig-xxs1500 | 1199 + .../linux-xxs1500-2.4.21/zboot-Makefile-flags.diff | 11 + .../montavista-sa-2.4.17-mvl21/apm-hh-merge.patch | 561 + .../montavista-sa-2.4.17-mvl21/beagle-sound.patch | 57 + .../disable-pcmcia-probe.patch | 17 + linux/montavista-sa-2.4.17-mvl21/iw240_we15-6.diff | 399 + .../iw_handlers.w13-5.diff | 1513 + .../iw_handlers.w14-5.diff | 838 + .../montavista-sa-2.4.17-mvl21/machine_name.patch | 19 + linux/montavista-sa-2.4.17-mvl21/mkdep.patch | 16 + .../remove-montavista-init-stupidity.patch | 23 + .../ucb1x_kill-zombie.patch | 15 + .../gcc-registerparanoia.patch | 57 + linux/nslu2-linksys-2.4.22/gcc3-userfuncs.patch | 134 + linux/nslu2-linksys-2.4.22/gl811e.patch | 43 + .../nslu2-linksys-2.4.22/linksys_can_bite_me.patch | 34 + .../linux-2.4.24-attribute-used.patch | 140 + linux/nslu2-linksys-2.4.22/nofpu.patch | 18 + linux/nslu2-linksys-2.4.22/short_loadbytes.patch | 18 + linux/nslu2-openslug-2.6.7/arm-Makefile.patch | 13 + linux/nslu2-openslug-2.6.7/arm-timer.patch | 17 + linux/nslu2-openslug-2.6.7/ipx4xx-pci.patch | 9 + linux/nslu2-openslug-2.6.7/x1205-rtc.patch | 142 + linux/nslu2-unslung-kernel-2.3r25/able/defconfig | 973 + .../able/missing_usb_ioctls.patch | 11 + .../unslung-kernel-ext3flash.patch | 28 + .../unslung-kernel-vfatdisk2.patch | 45 + .../unslung-kernel.patch | 11 + .../2.4.25-vrs2-pxa1.patch | 39937 +++++++++ .../2.4.25-vrs2.patch | 86979 +++++++++++++++++++ .../disable-pcmcia-probe.patch | 17 + linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/mkdep.patch | 16 + .../mppe-20040216.patch | 1225 + .../scrolling-area.patch | 18 + .../simpad-apm.diff | 799 + .../simpad-backlight-if.diff | 97 + .../simpad-pm-updates.patch | 47 + .../simpad-switches-input.diff | 126 + .../simpad-ts-noninput.diff | 11 + .../sound-volume-reversed.patch | 16 + .../collie-config-2.6.7-jl2 | 769 + .../husky-config-2.6.7-jl2 | 855 + .../openzaurus-2.6.10-rc1-jl1/patch-2.6.5-rp1.diff | 881 + .../poodle-config-2.6.7-jl2 | 708 + .../bluecard_cs.patch | 11 + .../bluetooth-2.4.18-mh11.patch | 31393 +++++++ .../bt950_cs.patch | 1174 + .../buffered-fbmem.patch | 19 + .../compile.patch | 14 + .../deviceinfo.patch | 26 + .../disable-pcmcia-probe.patch | 17 + .../enable-sysrq.patch | 45 + .../idecs.patch | 77 + .../initsh.patch | 14 + .../irda-qos.patch | 108 + .../iw240_we15-6.diff | 399 + .../iw_handlers.w13-5.diff | 1513 + .../iw_handlers.w14-5.diff | 838 + .../keyboard-ctrl+alt.patch | 79 + .../keymap-more-sane.patch | 23 + .../logo.patch | 2598 + .../mkdep.patch | 16 + .../swap-performance.patch | 19 + .../usb-storage.patch | 3433 + .../battery.patch | 326 + .../bluetooth-patch-2.4.18-mh9.diff | 30831 +++++++ .../disable-pcmcia-probe.patch | 17 + .../idecs.patch | 77 + .../initsh.patch | 14 + .../iw240_we15-6.diff | 399 + .../iw_handlers.w13-5.diff | 1513 + .../iw_handlers.w14-5.diff | 838 + .../keymap-more-sane.patch | 19 + .../logo.patch | 2598 + .../mkdep.patch | 16 + .../sound-2.4.18r2.patch | 5602 ++ 104 files changed, 265518 insertions(+) (limited to 'linux') diff --git a/linux/files/linux-2.4-cpufreq.patch b/linux/files/linux-2.4-cpufreq.patch index e69de29bb2..c3526bb30d 100644 --- a/linux/files/linux-2.4-cpufreq.patch +++ b/linux/files/linux-2.4-cpufreq.patch @@ -0,0 +1,20 @@ +Index: include/linux/cpufreq.h +=================================================================== +RCS file: /cvs/linux/kernel/include/linux/cpufreq.h,v +retrieving revision 1.4 +diff -u -r1.4 cpufreq.h +--- linux/include/linux/cpufreq.h 23 Aug 2002 22:18:47 -0000 1.4 ++++ linux/include/linux/cpufreq.h 29 Apr 2004 08:44:18 -0000 +@@ -16,9 +16,9 @@ + #include <linux/notifier.h> + + #ifndef CONFIG_SMP +-#define cpufreq_current(cpu) ((void)(cpu), __cpufreq_cur) +-#define cpufreq_max(cpu) ((void)(cpu), __cpufreq_max) +-#define cpufreq_min(cpu) ((void)(cpu), __cpufreq_min) ++#define cpufreq_current(cpu) (__cpufreq_cur) ++#define cpufreq_max(cpu) (__cpufreq_max) ++#define cpufreq_min(cpu) (__cpufreq_min) + #else + /* + * Should be something like: diff --git a/linux/files/linux-2.4-no-short-loads.patch b/linux/files/linux-2.4-no-short-loads.patch index e69de29bb2..f2d6c74224 100644 --- a/linux/files/linux-2.4-no-short-loads.patch +++ b/linux/files/linux-2.4-no-short-loads.patch @@ -0,0 +1,18 @@ +Index: arch/arm/Makefile +=================================================================== +RCS file: /cvs/linux/kernel/arch/arm/Makefile,v +retrieving revision 1.47 +diff -u -r1.47 Makefile +--- linux/arch/arm/Makefile 9 Jul 2003 14:10:56 -0000 1.47 ++++ linux/arch/arm/Makefile 28 Apr 2004 21:11:04 -0000 +@@ -60,8 +60,8 @@ + tune-$(CONFIG_CPU_XSCALE) :=-mtune=xscale + #tune-$(CONFIG_CPU_XSCALE) :=-mtune=strongarm + +-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 ++CFLAGS_BOOT :=$(apcs-y) $(arch-y) $(tune-y) -msoft-float -Uarm ++CFLAGS +=$(apcs-y) $(arch-y) $(tune-y) -msoft-float -Uarm + AFLAGS +=$(apcs-y) $(arch-y) -msoft-float + + ifeq ($(CONFIG_CPU_26),y) diff --git a/linux/files/linux-2.4.18-list_move.patch b/linux/files/linux-2.4.18-list_move.patch index e69de29bb2..faec56330b 100644 --- a/linux/files/linux-2.4.18-list_move.patch +++ b/linux/files/linux-2.4.18-list_move.patch @@ -0,0 +1,32 @@ +--- linux/include/linux/list.h~ 2001-12-21 17:42:03.000000000 +0000 ++++ linux/include/linux/list.h 2004-06-14 23:41:33.000000000 +0100 +@@ -105,6 +105,29 @@ + } + + /** ++ * list_move - delete from one list and add as another's head ++ * @list: the entry to move ++ * @head: the head that will precede our entry ++ */ ++static inline void list_move(struct list_head *list, struct list_head *head) ++{ ++ __list_del(list->prev, list->next); ++ list_add(list, head); ++} ++ ++/** ++ * list_move_tail - delete from one list and add as another's tail ++ * @list: the entry to move ++ * @head: the head that will follow our entry ++ */ ++static inline void list_move_tail(struct list_head *list, ++ struct list_head *head) ++{ ++ __list_del(list->prev, list->next); ++ list_add_tail(list, head); ++} ++ ++/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ diff --git a/linux/gumstix-2.6.5-gnalm1-gum0/defconfig b/linux/gumstix-2.6.5-gnalm1-gum0/defconfig index e69de29bb2..64020e2cbe 100644 --- a/linux/gumstix-2.6.5-gnalm1-gum0/defconfig +++ b/linux/gumstix-2.6.5-gnalm1-gum0/defconfig @@ -0,0 +1,777 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +CONFIG_ARCH_PXA=y +# 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_IOP3XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set + +# +# CLPS711X/EP721X Implementations +# + +# +# Epxa10db +# + +# +# Footbridge Implementations +# + +# +# IOP3xx Implementation Options +# +# CONFIG_ARCH_IOP310 is not set +# CONFIG_ARCH_IOP321 is not set + +# +# IOP3xx Chipset Features +# + +# +# Intel PXA250/210 Implementations +# +CONFIG_ARCH_GUMSTIK=y +# CONFIG_ARCH_LUBBOCK is not set +# CONFIG_ARCH_PXA_IDP is not set + +# +# SA11x0 Implementations +# + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_XSCALE=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5T=y +CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_MINICACHE=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +CONFIG_XSCALE_PMU=y + +# +# General setup +# +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CPU_FREQ=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +CONFIG_FPE_FASTFPE=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_AOUT=y +# CONFIG_BINFMT_MISC is not set + +# +# Generic Driver Options +# +CONFIG_PM=y +# CONFIG_PREEMPT is not set +# CONFIG_APM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="root=/dev/ram0 console=tty0,115200n8" +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=y +CONFIG_MTD_CONCAT=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +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 is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +CONFIG_MTD_COMPLEX_MAPPINGS=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_START=0x00180000 +CONFIG_MTD_PHYSMAP_LEN=0x00280000 +CONFIG_MTD_PHYSMAP_BUSWIDTH=2 +CONFIG_MTD_GUMSTIK=y +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_EDB7312 is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +CONFIG_MTD_BLKMTD=y + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=36000 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP 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_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_IPV6 is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_NETFILTER 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_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB 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 +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set +CONFIG_SLIP=y +# CONFIG_SLIP_COMPRESSED is not set +# CONFIG_SLIP_SMART is not set +# CONFIG_SLIP_MODE_SLIP6 is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE 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 + +# +# Bluetooth support +# +CONFIG_BT=y +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +# CONFIG_BT_BNEP_MC_FILTER is not set +# CONFIG_BT_BNEP_PROTO_FILTER is not set + +# +# Bluetooth device drivers +# +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_BCSP is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_TSLIBDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +# CONFIG_SERIO is not set +# CONFIG_SERIO_I8042 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_PXA=y +CONFIG_SERIAL_PXA_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +CONFIG_SA1100_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 +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_ALGOPXA=y + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ISA is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +CONFIG_I2C_PXA2XX=y +# CONFIG_SCx200_ACB is not set + +# +# Hardware Sensors Chip support +# +# CONFIG_I2C_SENSOR is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# MMC/SD Card support +# +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_BLOCK=y +CONFIG_MMC_PXA=y + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS_XATTR=y +# CONFIG_DEVPTS_FS_SECURITY is not set +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS 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_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +CONFIG_LDM_PARTITION=y +# CONFIG_LDM_DEBUG is not set +# CONFIG_NEC98_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y + +# +# Misc devices +# + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set + +# +# Console Switches +# +# CONFIG_SWITCHES is not set + +# +# USB support +# + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_NET2280 is not set +CONFIG_USB_GADGET_PXA2XX=y +CONFIG_USB_PXA2XX=y +CONFIG_USB_PXA2XX_SMALL=y +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_SA1100 is not set +# CONFIG_USB_GADGET_DUALSPEED is not set +# CONFIG_USB_ZERO is not set +CONFIG_USB_ETH=y +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_KERNEL is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC32=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/linux/gumstix-2.6.5-gnalm1-gum0/linux-2.6.5-gnalm1.patch b/linux/gumstix-2.6.5-gnalm1-gum0/linux-2.6.5-gnalm1.patch index e69de29bb2..e8ed5c9d44 100644 --- a/linux/gumstix-2.6.5-gnalm1-gum0/linux-2.6.5-gnalm1.patch +++ b/linux/gumstix-2.6.5-gnalm1-gum0/linux-2.6.5-gnalm1.patch @@ -0,0 +1,20991 @@ +--- linux-2.6.5/kernel/printk.c~heh 2004-04-03 22:38:24.000000000 -0500 ++++ linux-2.6.5/kernel/printk.c 2004-04-30 20:57:36.000000000 -0400 +@@ -832,3 +832,25 @@ + printk_ratelimit_burst); + } + EXPORT_SYMBOL(printk_ratelimit); ++ ++#include <linux/sysrq.h> ++ ++static void ++show_msg_info(int key, struct pt_regs *regs, struct tty_struct *tty) ++{ ++ call_console_drivers(log_end - logged_chars, log_end); ++} ++ ++static struct sysrq_key_op msg_info_op = { ++ .handler = show_msg_info, ++ .help_msg = "Dumpmsgs", ++ .action_msg = "Kernel Messages", ++}; ++ ++static int __init dbg_init(void) ++{ ++ register_sysrq_key('d', &msg_info_op); ++ return 0; ++} ++ ++__initcall(dbg_init); +--- linux-2.6.5/kernel/resource.c~heh 2004-04-03 22:37:36.000000000 -0500 ++++ linux-2.6.5/kernel/resource.c 2004-04-30 20:57:36.000000000 -0400 +@@ -179,6 +179,8 @@ + { + struct resource *tmp, **p; + ++ BUG_ON(old->child); ++ + p = &old->parent->child; + for (;;) { + tmp = *p; +@@ -409,6 +411,47 @@ + EXPORT_SYMBOL(adjust_resource); + + /* ++ * Given an existing resource, change its start and size to match the ++ * arguments. Returns -EBUSY if it can't fit. Existing children of ++ * the resource are assumed to be immutable. ++ */ ++int reallocate_resource(struct resource *res, unsigned long start, unsigned long size) ++{ ++ struct resource *tmp, *parent = res->parent; ++ unsigned long end = start + size - 1; ++ int result = -EBUSY; ++ ++ write_lock(&resource_lock); ++ ++ if ((start < parent->start) || (end > parent->end)) ++ goto out; ++ ++ for (tmp = res->child; tmp; tmp = tmp->sibling) { ++ if ((tmp->start < start) || (tmp->end > end)) ++ goto out; ++ } ++ ++ if (res->sibling && (res->sibling->start <= end)) ++ goto out; ++ ++ tmp = parent->child; ++ if (tmp != res) { ++ while (tmp->sibling != res) ++ tmp = tmp->sibling; ++ if (start <= tmp->end) ++ goto out; ++ } ++ ++ res->start = start; ++ res->end = end; ++ result = 0; ++ ++ out: ++ write_unlock(&resource_lock); ++ return result; ++} ++ ++/* + * This is compatibility stuff for IO resources. + * + * Note how this, unlike the above, knows about +--- linux-2.6.5/include/asm-arm/mach/irq.h~heh 2004-04-03 22:36:54.000000000 -0500 ++++ linux-2.6.5/include/asm-arm/mach/irq.h 2004-04-30 20:57:36.000000000 -0400 +@@ -14,6 +14,19 @@ + struct pt_regs; + struct seq_file; + ++/* ++ * Architectures are expected to define NR_IRQ_DEVICES and ++ * NR_IRQ_DEVICE_SHIFT if they wish to use dynamic IRQs. ++ */ ++#ifndef NR_IRQ_DEVICES ++#define NR_IRQ_DEVICES 1 ++#endif ++#define NR_IRQ_PER_DEVICE (1 << (NR_IRQ_DEVICE_SHIFT - 1)) ++ ++#define IRQ_DEVICE(i) ((i) >> NR_IRQ_DEVICE_SHIFT) ++#define IRQ_INDEX(i) ((i) & (NR_IRQ_PER_GROUP - 1)) ++#define TO_IRQ(g,i) (((g) << NR_IRQ_DEVICE_SHIFT) + (i)) ++ + typedef void (*irq_handler_t)(unsigned int, struct irqdesc *, struct pt_regs *); + typedef void (*irq_control_t)(unsigned int); + +--- linux-2.6.5/include/asm-arm/arch-pxa/uncompress.h~heh 2004-04-03 22:36:17.000000000 -0500 ++++ linux-2.6.5/include/asm-arm/arch-pxa/uncompress.h 2004-04-30 20:57:36.000000000 -0400 +@@ -12,6 +12,7 @@ + #define FFUART ((volatile unsigned long *)0x40100000) + #define BTUART ((volatile unsigned long *)0x40200000) + #define STUART ((volatile unsigned long *)0x40700000) ++#define HWUART ((volatile unsigned long *)0x41600000) + + #define UART FFUART + +--- linux-2.6.5/include/asm-arm/arch-pxa/dma.h~heh 2004-04-03 22:38:18.000000000 -0500 ++++ linux-2.6.5/include/asm-arm/arch-pxa/dma.h 2004-04-30 20:57:36.000000000 -0400 +@@ -22,11 +22,11 @@ + * Note: this structure must always be aligned to a 16-byte boundary. + */ + +-typedef struct { +- volatile u32 ddadr; /* Points to the next descriptor + flags */ +- volatile u32 dsadr; /* DSADR value for the current transfer */ +- volatile u32 dtadr; /* DTADR value for the current transfer */ +- volatile u32 dcmd; /* DCMD value for the current transfer */ ++typedef struct pxa_dma_desc { ++ u32 ddadr; /* Points to the next descriptor + flags */ ++ u32 dsadr; /* DSADR value for the current transfer */ ++ u32 dtadr; /* DTADR value for the current transfer */ ++ u32 dcmd; /* DCMD value for the current transfer */ + } pxa_dma_desc; + + /* +--- linux-2.6.5/include/asm-arm/arch-pxa/serial.h~heh 2004-04-03 22:37:06.000000000 -0500 ++++ linux-2.6.5/include/asm-arm/arch-pxa/serial.h 2004-04-30 20:57:36.000000000 -0400 +@@ -43,6 +43,15 @@ + io_type: SERIAL_IO_MEM, \ + irq: IRQ_BTUART, \ + flags: STD_COM_FLAGS, \ ++ }, { \ ++ type: PORT_PXA, \ ++ xmit_fifo_size: 64, \ ++ baud_base: BAUD_BASE, \ ++ iomem_base: &HWUART, \ ++ iomem_reg_shift: 2, \ ++ io_type: SERIAL_IO_MEM, \ ++ irq: IRQ_HWUART, \ ++ flags: STD_COM_FLAGS, \ + } + + #define EXTRA_SERIAL_PORT_DEFNS +--- linux-2.6.5/include/asm-arm/arch-pxa/pxa-regs.h~heh 2004-04-03 22:37:36.000000000 -0500 ++++ linux-2.6.5/include/asm-arm/arch-pxa/pxa-regs.h 2004-04-30 20:57:36.000000000 -0400 +@@ -124,26 +124,26 @@ + #define DRCMR12 __REG(0x40000130) /* Request to Channel Map Register for AC97 audio transmit Request */ + #define DRCMR13 __REG(0x40000134) /* Request to Channel Map Register for SSP receive Request */ + #define DRCMR14 __REG(0x40000138) /* Request to Channel Map Register for SSP transmit Request */ +-#define DRCMR15 __REG(0x4000013c) /* Reserved */ +-#define DRCMR16 __REG(0x40000140) /* Reserved */ ++#define DRCMR15 __REG(0x4000013c) /* Request to Channel Map Register for NSSP receive Request */ ++#define DRCMR16 __REG(0x40000140) /* Request to Channel Map Register for NSSP transmit Request */ + #define DRCMR17 __REG(0x40000144) /* Request to Channel Map Register for ICP receive Request */ + #define DRCMR18 __REG(0x40000148) /* Request to Channel Map Register for ICP transmit Request */ + #define DRCMR19 __REG(0x4000014c) /* Request to Channel Map Register for STUART receive Request */ + #define DRCMR20 __REG(0x40000150) /* Request to Channel Map Register for STUART transmit Request */ + #define DRCMR21 __REG(0x40000154) /* Request to Channel Map Register for MMC receive Request */ + #define DRCMR22 __REG(0x40000158) /* Request to Channel Map Register for MMC transmit Request */ +-#define DRCMR23 __REG(0x4000015c) /* Reserved */ +-#define DRCMR24 __REG(0x40000160) /* Reserved */ ++#define DRCMR23 __REG(0x4000015c) /* Request to Channel Map Register for ASSP receive Request */ ++#define DRCMR24 __REG(0x40000160) /* Request to Channel Map Register for ASSP transmit Request */ + #define DRCMR25 __REG(0x40000164) /* Request to Channel Map Register for USB endpoint 1 Request */ + #define DRCMR26 __REG(0x40000168) /* Request to Channel Map Register for USB endpoint 2 Request */ + #define DRCMR27 __REG(0x4000016C) /* Request to Channel Map Register for USB endpoint 3 Request */ + #define DRCMR28 __REG(0x40000170) /* Request to Channel Map Register for USB endpoint 4 Request */ +-#define DRCMR29 __REG(0x40000174) /* Reserved */ ++#define DRCMR29 __REG(0x40000174) /* Request to Channel Map Register for HWUART receive Request */ + #define DRCMR30 __REG(0x40000178) /* Request to Channel Map Register for USB endpoint 6 Request */ + #define DRCMR31 __REG(0x4000017C) /* Request to Channel Map Register for USB endpoint 7 Request */ + #define DRCMR32 __REG(0x40000180) /* Request to Channel Map Register for USB endpoint 8 Request */ + #define DRCMR33 __REG(0x40000184) /* Request to Channel Map Register for USB endpoint 9 Request */ +-#define DRCMR34 __REG(0x40000188) /* Reserved */ ++#define DRCMR34 __REG(0x40000188) /* Request to Channel Map Register for HWUART transmit Request */ + #define DRCMR35 __REG(0x4000018C) /* Request to Channel Map Register for USB endpoint 11 Request */ + #define DRCMR36 __REG(0x40000190) /* Request to Channel Map Register for USB endpoint 12 Request */ + #define DRCMR37 __REG(0x40000194) /* Request to Channel Map Register for USB endpoint 13 Request */ +@@ -163,12 +163,16 @@ + #define DRCMRTXPCDR DRCMR12 + #define DRCMRRXSSDR DRCMR13 + #define DRCMRTXSSDR DRCMR14 ++#define DRCMRRXNSSPDR DRCMR15 ++#define DRCMRTXNSSPDR DRCMR16 + #define DRCMRRXICDR DRCMR17 + #define DRCMRTXICDR DRCMR18 + #define DRCMRRXSTRBR DRCMR19 + #define DRCMRTXSTTHR DRCMR20 + #define DRCMRRXMMC DRCMR21 + #define DRCMRTXMMC DRCMR22 ++#define DRCMRRXASSPDR DRCMR23 ++#define DRCMRTXASSPDR DRCMR24 + + #define DRCMR_MAPVLD (1 << 7) /* Map Valid (read / write) */ + #define DRCMR_CHLNUM 0x0f /* mask for Channel Number (read / write) */ +@@ -303,6 +307,22 @@ + #define BTDLL __REG(0x40200000) /* Divisor Latch Low Register (DLAB = 1) (read/write) */ + #define BTDLH __REG(0x40200004) /* Divisor Latch High Register (DLAB = 1) (read/write) */ + ++/* Hardware UART (HWUART) */ ++#define HWUART HWRBR ++#define HWRBR __REG(0x41600000) /* Receive Buffer Register (read only) */ ++#define HWTHR __REG(0x41600000) /* Transmit Holding Register (write only) */ ++#define HWIER __REG(0x41600004) /* Interrupt Enable Register (read/write) */ ++#define HWIIR __REG(0x41600008) /* Interrupt ID Register (read only) */ ++#define HWFCR __REG(0x41600008) /* FIFO Control Register (write only) */ ++#define HWLCR __REG(0x4160000C) /* Line Control Register (read/write) */ ++#define HWMCR __REG(0x41600010) /* Modem Control Register (read/write) */ ++#define HWLSR __REG(0x41600014) /* Line Status Register (read only) */ ++#define HWMSR __REG(0x41600018) /* Reserved */ ++#define HWSPR __REG(0x4160001C) /* Scratch Pad Register (read/write) */ ++#define HWISR __REG(0x41600020) /* Infrared Selection Register (read/write) */ ++#define HWDLL __REG(0x41600000) /* Divisor Latch Low Register (DLAB = 1) (read/write) */ ++#define HWDLH __REG(0x41600004) /* Divisor Latch High Register (DLAB = 1) (read/write) */ ++ + /* Standard UART (STUART) */ + #define STUART STRBR + #define STRBR __REG(0x40700000) /* Receive Buffer Register (read only) */ +@@ -1078,6 +1098,111 @@ + + + /* ++ * NSSP Serial Port Registers (Network SSP) ++ */ ++ ++#define NSSCR0 __REG(0x41400000) /* NSSP Control Register 0 */ ++#define NSSCR1 __REG(0x41400004) /* NSSP Control Register 1 */ ++#define NSSSR __REG(0x41400008) /* NSSP Status Register */ ++#define NSSITR __REG(0x4140000C) /* NSSP Interrupt Test Register */ ++#define NSSDR __REG(0x41400010) /* (Write / Read) NSSP Data Write Register/NSSP Data Read Register */ ++#define NSSTO __REG(0x41400028) /* NSSP Time Out Register */ ++#define NSSPSP __REG(0x4140002C) /* NSSP Programable Serial Port Register*/ ++ ++ ++/* ++ * ASSP Serial Port Registers (Audio SSP) ++ */ ++ ++#define ASSCR0 __REG(0x41500000) /* ASSP Control Register 0 */ ++#define ASSCR1 __REG(0x41500004) /* ASSP Control Register 1 */ ++#define ASSSR __REG(0x41500008) /* ASSP Status Register */ ++#define ASSITR __REG(0x4150000C) /* ASSP Interrupt Test Register */ ++#define ASSDR __REG(0x41500010) /* (Write / Read) ASSP Data Write Register/ASSP Data Read Register */ ++#define ASSTO __REG(0x41500028) /* ASSP Time Out Register */ ++#define ASSPSP __REG(0x4150002C) /* ASSP Programable Serial Port Register*/ ++ ++ ++/* ++ * Bit definitions for SSP, NSSP and ASSP registers ++ * - note that some bits are only available on the NSSP and ASSP ++ */ ++ ++#define SSCR0_EDSS (1 << 20) /* ext. data size select */ ++#define SSCR0_SCR_MASK 0x000fff00 /* [19:8] secrial clock rate */ ++#define SSCR0_SCR(x) (((x)<<8) & XSSCR0_SCR_MASK) ++#define SSCR0_SSE (1 << 7) /* sync ser port enable */ ++#define SSCR0_FRF_MASK 0x00000030 /* [5:4] frame format */ ++#define SSCR0_FRF(x) (((x)<<4) & XSSCR0_FRF_MASK) ++#define SSCR0_FRF_SPI 0x00000000 /* ser peripheral i/f */ ++#define SSCR0_FRF_TISSP 0x00000010 /* TI sync ser port */ ++#define SSCR0_FRF_MICROWAVE 0x00000020 /* microwire */ ++#define SSCR0_FRF_PSP 0x00000030 /* prog ser protocol */ ++#define SSCR0_DSS_MASK 0x0000000f /* data size select */ ++#define SSCR0_DSS(x) ((x) & XSSCR0_DSS_MASK) ++ ++#define SSCR1_TTELP (1 << 31) /* tx hi-z later phase */ ++#define SSCR1_TTE (1 << 30) /* tx hi-z enable */ ++#define SSCR1_EBCEI (1 << 29) /* bit count error int mask */ ++#define SSCR1_SCFR (1 << 28) /* slave clock free running */ ++#define SSCR1_SCLKDIR (1 << 25) /* ssp clock direction */ ++#define SSCR1_SFRMDIR (1 << 24) /* ssp frame direction */ ++#define SSCR1_RWOT (1 << 23) /* rx without transmit */ ++#define SSCR1_TSRE (1 << 21) /* tx req enable */ ++#define SSCR1_RSRE (1 << 20) /* rx req enable */ ++#define SSCR1_TINTE (1 << 19) /* timeout int enable */ ++#define SSCR1_STRF (1 << 15) /* select fifo for efwr */ ++#define SSCR1_EFWR (1 << 14) /* fifo write/read enable */ ++#define SSCR1_RFT_MASK 0x00003c00 /* [13:10] rx fifo threshold */ ++#define SSCR1_RFT(x) (((x)<<10) & XSSCR1_RFT_MASK) ++#define SSCR1_TFT_MASK 0x000003c0 /* [9:6] tx fifo threshold */ ++#define SSCR1_TFT(x) (((x)<<6) & XSSCR1_TFT_MASK) ++#define SSCR1_MWDS (1 << 5) /* microwire tx data size */ ++#define SSCR1_SPH (1 << 4) /* SPI SSPSCLK phase */ ++#define SSCR1_SPO (1 << 3) /* motorolla SPI polarity */ ++#define SSCR1_LBM (1 << 2) /* loop-back mode */ ++#define SSCR1_TIE (1 << 1) /* tx fifo int enable */ ++#define SSCR1_RIE (1 << 0) /* rx fifo int enable */ ++ ++#define SSPSP_DMYSTOP_MASK 0x01800000 /* [24:23] dummy stop */ ++#define SSPSP_DMYSTOP(x) (((x)<<23) & XSSPSP_DMYSTOP_MASK) ++#define SSPSP_SFRMWDTH_MASK 0x007f0000 /* [22:16] serial frame width */ ++#define SSPSP_SFRMWDTH(x) (((x)<<16) & XSSPSP_SFRMWDTH_MASK) ++#define SSPSP_SFRMDLY_MASK 0x0000fe00 /* [15:9] serial frame delay */ ++#define SSPSP_SFRMDLY(x) (((x)<<9) & XSSPSP_SFRMDLY_MASK) ++#define SSPSP_DMYSTRT_MASK 0x00000180 /* [8:7] dummy start */ ++#define SSPSP_DMYSTRT(x) (((x)<<7) & XSSPSP_DMYSTRT_MASK) ++#define SSPSP_STRTDLY_MASK 0x00000070 /* [6:4] three-bit start delay */ ++#define SSPSP_STRTDLY(x) (((x)<<4) & XSSPSP_STRTDLY_MASK) ++#define SSPSP_ETDS (1 << 3) /* end of tx data state */ ++#define SSPSP_SFRMP (1 << 2) /* serial frame polarity */ ++#define SSPSP_SCMODE_MASK 0x00000003 /* bit-rate clock mode */ ++#define SSPSP_SCMODE(x) ((x) & XSSPSP_SCMODE_MASK) ++ ++#define SSTO_TIMEOUT_MASK 0x00ffffff /* [23:0] timeout */ ++#define SSTO_TIMEOUT(x) ((x) & XSSTO_TIMEOUT_MASK) ++ ++#define SSITR_TROR (1 << 7) /* test rx fifo overrun */ ++#define SSITR_TRFS (1 << 6) /* test rx fifo serv req */ ++#define SSITR_TTFS (1 << 5) /* test tx fifo serv req */ ++ ++#define SSSR_BCE (1 << 23) /* bit count error */ ++#define SSSR_CSS (1 << 22) /* clock sync stat */ ++#define SSSR_TUR (1 << 21) /* tx fifo underrun */ ++#define SSSR_TINT (1 << 19) /* rx timeout int */ ++#define SSSR_RFL_MASK 0x0000f000 /* rx fifo level */ ++#define SSSR_RFL(x) (((x)<<16) & XSSSR_RFL_MASK) ++#define SSSR_TFL_MASK 0x00000f00 /* tx fifo level */ ++#define SSSR_TFL(x) (((x)<<8) & XSSSR_TFL_MASK) ++#define SSSR_ROR (1 << 7) /* rx fifo overrun */ ++#define SSSR_RFS (1 << 6) /* rx fifo serv request */ ++#define SSSR_TFS (1 << 5) /* tx fifo serv req */ ++#define SSSR_BSY (1 << 4) /* SSP busy */ ++#define SSSR_RNE (1 << 3) /* rx fifo not empty */ ++#define SSSR_TNF (1 << 2) /* tx fifo not full */ ++ ++ ++/* + * MultiMediaCard (MMC) controller + */ + +@@ -1122,6 +1247,7 @@ + #define CKEN7_BTUART (1 << 7) /* BTUART Unit Clock Enable */ + #define CKEN6_FFUART (1 << 6) /* FFUART Unit Clock Enable */ + #define CKEN5_STUART (1 << 5) /* STUART Unit Clock Enable */ ++#define CKEN4_HWUART (1 << 4) /* HWUART Unit Clock Enable */ + #define CKEN3_SSP (1 << 3) /* SSP Unit Clock Enable */ + #define CKEN2_AC97 (1 << 2) /* AC97 Unit Clock Enable */ + #define CKEN1_PWM1 (1 << 1) /* PWM1 Clock Enable */ +--- linux-2.6.5/include/asm-arm/page.h~heh 2004-04-03 22:36:25.000000000 -0500 ++++ linux-2.6.5/include/asm-arm/page.h 2004-04-30 20:57:36.000000000 -0400 +@@ -92,6 +92,14 @@ + # endif + #endif + ++#ifdef CONFIG_CPU_COPY_V6 ++# ifdef _USER ++# define MULTI_USER 1 ++# else ++# define _USER v6 ++# endif ++#endif ++ + #ifndef _USER + #error Unknown user operations model + #endif +--- linux-2.6.5/include/asm-arm/thread_info.h~heh 2004-04-03 22:37:06.000000000 -0500 ++++ linux-2.6.5/include/asm-arm/thread_info.h 2004-04-30 20:57:36.000000000 -0400 +@@ -108,8 +108,8 @@ + #define TI_CPU 20 + #define TI_CPU_DOMAIN 24 + #define TI_CPU_SAVE 28 +-#define TI_USED_MATH 76 +-#define TI_FPSTATE (TI_USED_MATH+16) ++#define TI_USED_CP 76 ++#define TI_FPSTATE (TI_USED_CP+16) + + #endif + +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/include/asm-arm/rtc.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,45 @@ ++/* ++ * linux/include/asm-arm/rtc.h ++ * ++ * Copyright (C) 2003 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 version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef ASMARM_RTC_H ++#define ASMARM_RTC_H ++ ++struct module; ++ ++struct rtc_ops { ++ struct module *owner; ++ int (*open)(void); ++ void (*release)(void); ++ int (*ioctl)(unsigned int, unsigned long); ++ ++ void (*read_time)(struct rtc_time *); ++ int (*set_time)(struct rtc_time *); ++ void (*read_alarm)(struct rtc_wkalrm *); ++ int (*set_alarm)(struct rtc_wkalrm *); ++ int (*proc)(char *buf); ++}; ++ ++void rtc_time_to_tm(unsigned long, struct rtc_time *); ++int rtc_tm_to_time(struct rtc_time *, unsigned long *); ++void rtc_next_alarm_time(struct rtc_time *, struct rtc_time *, struct rtc_time *); ++void rtc_update(unsigned long, unsigned long); ++int register_rtc(struct rtc_ops *); ++void unregister_rtc(struct rtc_ops *); ++ ++static inline int rtc_periodic_alarm(struct rtc_time *tm) ++{ ++ return (tm->tm_year == -1) || ++ ((unsigned)tm->tm_mon >= 12) || ++ ((unsigned)(tm->tm_mday - 1) >= 31) || ++ ((unsigned)tm->tm_hour > 23) || ++ ((unsigned)tm->tm_min > 59) || ++ ((unsigned)tm->tm_sec > 59); ++} ++ ++#endif +--- linux-2.6.5/include/linux/serial.h~heh 2004-04-03 22:36:26.000000000 -0500 ++++ linux-2.6.5/include/linux/serial.h 2004-04-30 20:57:36.000000000 -0400 +@@ -81,17 +81,6 @@ + #define SERIAL_IO_HUB6 1 + #define SERIAL_IO_MEM 2 + +-struct serial_uart_config { +- char *name; +- int dfl_xmit_fifo_size; +- int flags; +-}; +- +-#define UART_CLEAR_FIFO 0x01 +-#define UART_USE_FIFO 0x02 +-#define UART_STARTECH 0x04 +-#define UART_NATSEMI 0x08 +- + /* + * Definitions for async_struct (and serial_struct) flags field + */ +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/include/linux/i2c-pxa.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,76 @@ ++/* ++ * i2c_pxa.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 _I2C_PXA_H_ ++#define _I2C_PXA_H_ ++ ++struct i2c_algo_pxa_data ++{ ++ void (*write_byte) (u8 value); ++ u8 (*read_byte) (void); ++ void (*start) (void); ++ void (*repeat_start) (void); ++ void (*stop) (void); ++ void (*abort) (void); ++ int (*wait_bus_not_busy) (void); ++ int (*wait_for_interrupt) (int wait_type); ++ void (*transfer) (int lastbyte, int receive, int midbyte); ++ void (*reset) (void); ++ ++ int udelay; ++ int timeout; ++}; ++ ++#define DEF_TIMEOUT 3 ++#define BUS_ERROR (-EREMOTEIO) ++#define ACK_DELAY 0 /* time to delay before checking bus error */ ++#define MAX_MESSAGES 65536 /* maximum number of messages to send */ ++ ++#define I2C_SLEEP_TIMEOUT 2 /* time to sleep for on i2c transactions */ ++#define I2C_RETRY (-2000) /* an error has occurred retry transmit */ ++#define I2C_TRANSMIT 1 ++#define I2C_RECEIVE 0 ++#define I2C_PXA_SLAVE_ADDR 0x1 /* slave pxa unit address */ ++#define I2C_ICR_INIT (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE) /* ICR initialization value */ ++/* ICR initialize bit values ++* ++* 15. FM 0 (100 Khz operation) ++* 14. UR 0 (No unit reset) ++* 13. SADIE 0 (Disables the unit from interrupting on slave addresses ++* matching its slave address) ++* 12. ALDIE 0 (Disables the unit from interrupt when it loses arbitration ++* in master mode) ++* 11. SSDIE 0 (Disables interrupts from a slave stop detected, in slave mode) ++* 10. BEIE 1 (Enable interrupts from detected bus errors, no ACK sent) ++* 9. IRFIE 1 (Enable interrupts from full buffer received) ++* 8. ITEIE 1 (Enables the I2C unit to interrupt when transmit buffer empty) ++* 7. GCD 1 (Disables i2c unit response to general call messages as a slave) ++* 6. IUE 0 (Disable unit until we change settings) ++* 5. SCLE 1 (Enables the i2c clock output for master mode (drives SCL) ++* 4. MA 0 (Only send stop with the ICR stop bit) ++* 3. TB 0 (We are not transmitting a byte initially) ++* 2. ACKNAK 0 (Send an ACK after the unit receives a byte) ++* 1. STOP 0 (Do not send a STOP) ++* 0. START 0 (Do not send a START) ++* ++*/ ++ ++#define I2C_ISR_INIT 0x7FF /* status register init */ ++/* I2C status register init values ++ * ++ * 10. BED 1 (Clear bus error detected) ++ * 9. SAD 1 (Clear slave address detected) ++ * 7. IRF 1 (Clear IDBR Receive Full) ++ * 6. ITE 1 (Clear IDBR Transmit Empty) ++ * 5. ALD 1 (Clear Arbitration Loss Detected) ++ * 4. SSD 1 (Clear Slave Stop Detected) ++ */ ++ ++#endif +--- linux-2.6.5/include/linux/ioport.h~heh 2004-04-03 22:36:26.000000000 -0500 ++++ linux-2.6.5/include/linux/ioport.h 2004-04-30 20:57:36.000000000 -0400 +@@ -99,6 +99,7 @@ + void (*alignf)(void *, struct resource *, + unsigned long, unsigned long), + void *alignf_data); ++extern int reallocate_resource(struct resource *res, unsigned long start, unsigned long size); + int adjust_resource(struct resource *res, unsigned long start, + unsigned long size); + +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/include/linux/switches.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,74 @@ ++/* ++ * linux/include/linux/switches.h ++ * ++ * 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 version 2 as ++ * published by the Free Software Foundation. ++ * ++ * 23 October 2000 - created. ++ */ ++ ++#if !defined(_LINUX_SWITCHES_H) ++#define _LINUX_SWITCHES_H ++ ++#define SWITCHES_MASK_SIZE (128) ++ ++typedef unsigned long switches_bitfield; ++ ++#define SWITCHES_BITS (sizeof(switches_bitfield) * 8) ++#define SWITCHES_NUM_FIELDS (SWITCHES_MASK_SIZE / SWITCHES_BITS) ++#define SWITCHES_FIELD_SELECT(i) ((i) / SWITCHES_BITS) ++#define SWITCHES_FIELD_MASK(i) ((switches_bitfield)(1 << (i) % \ ++ SWITCHES_BITS)) ++ ++typedef struct switches_mask_t { ++ unsigned int count; ++ switches_bitfield events[SWITCHES_NUM_FIELDS]; ++ switches_bitfield states[SWITCHES_NUM_FIELDS]; ++} switches_mask_t; ++ ++#define SWITCHES_ZERO(m) \ ++do { \ ++ unsigned int sz_i; \ ++ (m)->count = 0; \ ++ for(sz_i = 0; sz_i < SWITCHES_NUM_FIELDS; ++sz_i) \ ++ (m)->events[sz_i] = (m)->states[sz_i] = 0; \ ++} while (0) ++ ++/* `s' is the state of the switch, either 0 or non-zero: */ ++#define SWITCHES_SET(m, i, s) \ ++do { \ ++ ((m)->events[SWITCHES_FIELD_SELECT((i))] |= \ ++ SWITCHES_FIELD_MASK((i))); \ ++ if(s) \ ++ ((m)->states[SWITCHES_FIELD_SELECT((i))] |= \ ++ SWITCHES_FIELD_MASK((i))); \ ++ else \ ++ ((m)->states[SWITCHES_FIELD_SELECT((i))] &= \ ++ ~SWITCHES_FIELD_MASK((i))); \ ++ ++((m)->count); \ ++} while (0) ++ ++/* Should only use to clear an event set by SWITCHES_SET(): */ ++#define SWITCHES_CLEAR(m, i) \ ++do { \ ++ ((m)->events[SWITCHES_FIELD_SELECT((i))] &= \ ++ ~SWITCHES_FIELD_MASK((i))); \ ++ ((m)->states[SWITCHES_FIELD_SELECT((i))] &= \ ++ ~SWITCHES_FIELD_MASK((i))); \ ++ --((m)->count); \ ++} ++ ++#define SWITCHES_COUNT(m) ((m)->count) ++ ++/* Returns 0 or non-zero: */ ++#define SWITCHES_EVENT(m, i) \ ++((m)->events[SWITCHES_FIELD_SELECT((i))] & SWITCHES_FIELD_MASK((i))) ++ ++/* Returns 0 or non-zero: */ ++#define SWITCHES_STATE(m, i) \ ++((m)->states[SWITCHES_FIELD_SELECT((i))] & SWITCHES_FIELD_MASK((i))) ++ ++#endif /* !defined(_LINUX_SWITCHES_H) */ +--- linux-2.6.5/include/linux/serial_reg.h~heh 2004-04-03 22:37:38.000000000 -0500 ++++ linux-2.6.5/include/linux/serial_reg.h 2004-04-30 20:57:36.000000000 -0400 +@@ -121,6 +121,7 @@ + /* + * These are the definitions for the Modem Control Register + */ ++#define UART_MCR_AFE 0x20 /* Enable auto-RTS/CTS (TI16C750) */ + #define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ + #define UART_MCR_OUT2 0x08 /* Out2 complement */ + #define UART_MCR_OUT1 0x04 /* Out1 complement */ +@@ -156,6 +157,21 @@ + #define UART_FCR_PXAR32 0xc0 /* receive FIFO treshold = 32 */ + + /* ++ * The Intel PXA2xx chip defines those bits ++ */ ++#define UART_IER_DMAE 0x80 /* DMA Requests Enable */ ++#define UART_IER_UUE 0x40 /* UART Unit Enable */ ++#define UART_IER_NRZE 0x20 /* NRZ coding Enable */ ++#define UART_IER_RTOIE 0x10 /* Receiver Time Out Interrupt Enable */ ++ ++#define UART_IIR_TOD 0x08 /* Character Timeout Indication Detected */ ++ ++#define UART_FCR_PXAR1 0x00 /* receive FIFO treshold = 1 */ ++#define UART_FCR_PXAR8 0x40 /* receive FIFO treshold = 8 */ ++#define UART_FCR_PXAR16 0x80 /* receive FIFO treshold = 16 */ ++#define UART_FCR_PXAR32 0xc0 /* receive FIFO treshold = 32 */ ++ ++/* + * These are the definitions for the Extended Features Register + * (StarTech 16C660 only, when DLAB=1) + */ +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/include/linux/mmc/card.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,83 @@ ++/* ++ * linux/include/linux/mmc/card.h ++ * ++ * 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. ++ * ++ * Card driver specific definitions. ++ */ ++#ifndef LINUX_MMC_CARD_H ++#define LINUX_MMC_CARD_H ++ ++#include <linux/mmc/mmc.h> ++ ++struct mmc_cid { ++ unsigned int manfid; ++ unsigned int serial; ++ char prod_name[8]; ++ unsigned char hwrev; ++ unsigned char fwrev; ++ unsigned char month; ++ unsigned char year; ++}; ++ ++struct mmc_csd { ++ unsigned char mmc_prot; ++ unsigned short cmdclass; ++ unsigned short tacc_clks; ++ unsigned int tacc_ns; ++ unsigned int max_dtr; ++ unsigned int read_blkbits; ++ unsigned int capacity; ++}; ++ ++struct mmc_host; ++ ++/* ++ * MMC device ++ */ ++struct mmc_card { ++ struct list_head node; /* node in hosts devices list */ ++ struct mmc_host *host; /* the host this device belongs to */ ++ struct device dev; /* the device */ ++ unsigned int rca; /* relative card address of device */ ++ unsigned int state; /* (our) card state */ ++#define MMC_STATE_PRESENT (1<<0) ++#define MMC_STATE_DEAD (1<<1) ++ struct mmc_cid cid; /* card identification */ ++ struct mmc_csd csd; /* card specific */ ++}; ++ ++#define mmc_card_dead(c) ((c)->state & MMC_STATE_DEAD) ++#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT) ++ ++#define mmc_card_name(c) ((c)->cid.prod_name) ++#define mmc_card_id(c) ((c)->dev.bus_id) ++ ++#define mmc_list_to_card(l) container_of(l, struct mmc_card, node) ++#define mmc_get_drvdata(c) dev_get_drvdata(&(c)->dev) ++#define mmc_set_drvdata(c,d) dev_set_drvdata(&(c)->dev, d) ++ ++/* ++ * MMC device driver (e.g., Flash card, I/O card...) ++ */ ++struct mmc_driver { ++ struct device_driver drv; ++ int (*probe)(struct mmc_card *); ++ void (*remove)(struct mmc_card *); ++ int (*suspend)(struct mmc_card *, u32); ++ int (*resume)(struct mmc_card *); ++}; ++ ++extern int mmc_register_driver(struct mmc_driver *); ++extern void mmc_unregister_driver(struct mmc_driver *); ++ ++static inline int mmc_card_claim_host(struct mmc_card *card) ++{ ++ return __mmc_claim_host(card->host, card); ++} ++ ++#define mmc_card_release_host(c) mmc_release_host((c)->host) ++ ++#endif +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/include/linux/mmc/mmc.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,88 @@ ++/* ++ * linux/include/linux/mmc/mmc.h ++ * ++ * 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 MMC_H ++#define MMC_H ++ ++#include <linux/list.h> ++#include <linux/interrupt.h> ++#include <linux/device.h> ++ ++struct request; ++struct mmc_data; ++struct mmc_request; ++ ++struct mmc_command { ++ u32 opcode; ++ u32 arg; ++ u32 resp[4]; ++ unsigned int flags; /* expected response type */ ++#define MMC_RSP_NONE (0 << 0) ++#define MMC_RSP_SHORT (1 << 0) ++#define MMC_RSP_LONG (2 << 0) ++#define MMC_RSP_MASK (3 << 0) ++#define MMC_RSP_CRC (1 << 3) /* expect valid crc */ ++#define MMC_RSP_BUSY (1 << 4) /* card may send busy */ ++ ++ unsigned int retries; /* max number of retries */ ++ unsigned int error; /* command error */ ++ ++#define MMC_ERR_NONE 0 ++#define MMC_ERR_TIMEOUT 1 ++#define MMC_ERR_BADCRC 2 ++#define MMC_ERR_FIFO 3 ++#define MMC_ERR_FAILED 4 ++#define MMC_ERR_INVALID 5 ++ ++ struct mmc_data *data; /* data segment associated with cmd */ ++ struct mmc_request *req; /* assoicated request */ ++}; ++ ++struct mmc_data { ++ unsigned int timeout_ns; /* data timeout (in ns, max 80ms) */ ++ unsigned int timeout_clks; /* data timeout (in clocks) */ ++ unsigned int blksz_bits; /* data block size */ ++ unsigned int blocks; /* number of blocks */ ++ struct request *rq; /* request structure */ ++ unsigned int error; /* data error */ ++ unsigned int flags; ++ ++#define MMC_DATA_WRITE (1 << 8) ++#define MMC_DATA_READ (1 << 9) ++#define MMC_DATA_STREAM (1 << 10) ++ ++ unsigned int bytes_xfered; ++ ++ struct mmc_command *stop; /* stop command */ ++ struct mmc_request *req; /* assoicated request */ ++}; ++ ++struct mmc_request { ++ struct mmc_command *cmd; ++ struct mmc_data *data; ++ struct mmc_command *stop; ++ ++ void *done_data; /* completion data */ ++ void (*done)(struct mmc_request *);/* completion function */ ++}; ++ ++struct mmc_host; ++struct mmc_card; ++ ++extern int mmc_wait_for_req(struct mmc_host *, struct mmc_request *); ++extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int); ++ ++extern int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card); ++ ++static inline void mmc_claim_host(struct mmc_host *host) ++{ ++ __mmc_claim_host(host, (struct mmc_card *)-1); ++} ++ ++extern void mmc_release_host(struct mmc_host *host); ++ ++#endif +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/include/linux/mmc/host.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,67 @@ ++/* ++ * linux/include/linux/mmc/host.h ++ * ++ * 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. ++ * ++ * Host driver specific definitions. ++ */ ++#ifndef LINUX_MMC_HOST_H ++#define LINUX_MMC_HOST_H ++ ++#include <linux/mmc/mmc.h> ++ ++struct mmc_ios { ++ unsigned int clock; /* clock rate */ ++ unsigned short vdd; /* supply (units of 10mV) */ ++ unsigned char bus_mode; /* command output mode */ ++ ++#define MMC_BUSMODE_OPENDRAIN 1 ++#define MMC_BUSMODE_PUSHPULL 2 ++ ++ unsigned char power_mode; /* power supply mode */ ++ ++#define MMC_POWER_OFF 0 ++#define MMC_POWER_UP 1 ++#define MMC_POWER_ON 2 ++}; ++ ++struct mmc_host_ops { ++ void (*request)(struct mmc_host *host, struct mmc_request *req); ++ void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios); ++}; ++ ++struct mmc_card; ++ ++struct mmc_host { ++ struct device *dev; ++ struct mmc_host_ops *ops; ++ unsigned int f_min; ++ unsigned int f_max; ++ u32 ocr_avail; ++ ++ /* private data */ ++ unsigned int host_num; /* host number */ ++ struct mmc_ios ios; /* current io bus settings */ ++ u32 ocr; /* the current OCR setting */ ++ ++ struct list_head cards; /* devices attached to this host */ ++ ++ wait_queue_head_t wq; ++ spinlock_t lock; /* card_busy lock */ ++ struct mmc_card *card_busy; /* the MMC card claiming host */ ++ struct mmc_card *card_selected; /* the selected MMC card */ ++}; ++ ++extern int mmc_init_host(struct mmc_host *); ++extern int mmc_add_host(struct mmc_host *); ++extern void mmc_remove_host(struct mmc_host *); ++extern int mmc_suspend_host(struct mmc_host *, u32); ++extern int mmc_resume_host(struct mmc_host *); ++ ++extern void mmc_detect_change(struct mmc_host *); ++extern void mmc_request_done(struct mmc_host *, struct mmc_request *); ++ ++#endif ++ +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/include/linux/mmc/protocol.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,203 @@ ++/* ++ * Header for MultiMediaCard (MMC) ++ * ++ * Copyright 2002 Hewlett-Packard Company ++ * ++ * Use consistent with the GNU GPL is permitted, ++ * provided that this copyright notice is ++ * preserved in its entirety in all copies and derived works. ++ * ++ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, ++ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS ++ * FITNESS FOR ANY PARTICULAR PURPOSE. ++ * ++ * Many thanks to Alessandro Rubini and Jonathan Corbet! ++ * ++ * Based strongly on code by: ++ * ++ * Author: Yong-iL Joh <tolkien@mizi.com> ++ * Date : $Date$ ++ * ++ * Author: Andrew Christian ++ * 15 May 2002 ++ */ ++ ++#ifndef MMC_MMC_PROTOCOL_H ++#define MMC_MMC_PROTOCOL_H ++ ++/* Standard MMC commands (3.1) type argument response */ ++ /* class 1 */ ++#define MMC_GO_IDLE_STATE 0 /* bc */ ++#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */ ++#define MMC_ALL_SEND_CID 2 /* bcr R2 */ ++#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ ++#define MMC_SET_DSR 4 /* bc [31:16] RCA */ ++#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */ ++#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */ ++#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */ ++#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ ++#define MMC_STOP_TRANSMISSION 12 /* ac R1b */ ++#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ ++#define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */ ++ ++ /* class 2 */ ++#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ ++#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */ ++#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ ++ ++ /* class 3 */ ++#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */ ++ ++ /* class 4 */ ++#define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */ ++#define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */ ++#define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */ ++#define MMC_PROGRAM_CID 26 /* adtc R1 */ ++#define MMC_PROGRAM_CSD 27 /* adtc R1 */ ++ ++ /* class 6 */ ++#define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */ ++#define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */ ++#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */ ++ ++ /* class 5 */ ++#define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */ ++#define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */ ++#define MMC_ERASE 37 /* ac R1b */ ++ ++ /* class 9 */ ++#define MMC_FAST_IO 39 /* ac <Complex> R4 */ ++#define MMC_GO_IRQ_STATE 40 /* bcr R5 */ ++ ++ /* class 7 */ ++#define MMC_LOCK_UNLOCK 42 /* adtc R1b */ ++ ++ /* class 8 */ ++#define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */ ++#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1b */ ++ ++/* ++ MMC status in R1 ++ Type ++ e : error bit ++ s : status bit ++ r : detected and set for the actual command response ++ x : detected and set during command execution. the host must poll ++ the card by sending status command in order to read these bits. ++ Clear condition ++ a : according to the card state ++ b : always related to the previous command. Reception of ++ a valid command will clear it (with a delay of one command) ++ c : clear by read ++ */ ++ ++#define R1_OUT_OF_RANGE (1 << 31) /* er, c */ ++#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */ ++#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */ ++#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */ ++#define R1_ERASE_PARAM (1 << 27) /* ex, c */ ++#define R1_WP_VIOLATION (1 << 26) /* erx, c */ ++#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */ ++#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */ ++#define R1_COM_CRC_ERROR (1 << 23) /* er, b */ ++#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */ ++#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */ ++#define R1_CC_ERROR (1 << 20) /* erx, c */ ++#define R1_ERROR (1 << 19) /* erx, c */ ++#define R1_UNDERRUN (1 << 18) /* ex, c */ ++#define R1_OVERRUN (1 << 17) /* ex, c */ ++#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */ ++#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */ ++#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */ ++#define R1_ERASE_RESET (1 << 13) /* sr, c */ ++#define R1_STATUS(x) (x & 0xFFFFE000) ++#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ ++#define R1_READY_FOR_DATA (1 << 8) /* sx, a */ ++#define R1_APP_CMD (1 << 7) /* sr, c */ ++ ++/* These are unpacked versions of the actual responses */ ++ ++struct _mmc_csd { ++ u8 csd_structure; ++ u8 spec_vers; ++ u8 taac; ++ u8 nsac; ++ u8 tran_speed; ++ u16 ccc; ++ u8 read_bl_len; ++ u8 read_bl_partial; ++ u8 write_blk_misalign; ++ u8 read_blk_misalign; ++ u8 dsr_imp; ++ u16 c_size; ++ u8 vdd_r_curr_min; ++ u8 vdd_r_curr_max; ++ u8 vdd_w_curr_min; ++ u8 vdd_w_curr_max; ++ u8 c_size_mult; ++ union { ++ struct { /* MMC system specification version 3.1 */ ++ u8 erase_grp_size; ++ u8 erase_grp_mult; ++ } v31; ++ struct { /* MMC system specification version 2.2 */ ++ u8 sector_size; ++ u8 erase_grp_size; ++ } v22; ++ } erase; ++ u8 wp_grp_size; ++ u8 wp_grp_enable; ++ u8 default_ecc; ++ u8 r2w_factor; ++ u8 write_bl_len; ++ u8 write_bl_partial; ++ u8 file_format_grp; ++ u8 copy; ++ u8 perm_write_protect; ++ u8 tmp_write_protect; ++ u8 file_format; ++ u8 ecc; ++}; ++ ++#define MMC_VDD_145_150 0x00000001 /* VDD voltage 1.45 - 1.50 */ ++#define MMC_VDD_150_155 0x00000002 /* VDD voltage 1.50 - 1.55 */ ++#define MMC_VDD_155_160 0x00000004 /* VDD voltage 1.55 - 1.60 */ ++#define MMC_VDD_160_165 0x00000008 /* VDD voltage 1.60 - 1.65 */ ++#define MMC_VDD_165_170 0x00000010 /* VDD voltage 1.65 - 1.70 */ ++#define MMC_VDD_17_18 0x00000020 /* VDD voltage 1.7 - 1.8 */ ++#define MMC_VDD_18_19 0x00000040 /* VDD voltage 1.8 - 1.9 */ ++#define MMC_VDD_19_20 0x00000080 /* VDD voltage 1.9 - 2.0 */ ++#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */ ++#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */ ++#define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */ ++#define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */ ++#define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */ ++#define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */ ++#define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */ ++#define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */ ++#define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */ ++#define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */ ++#define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */ ++#define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */ ++#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */ ++#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */ ++#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */ ++#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */ ++#define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */ ++ ++ ++/* ++ * CSD field definitions ++ */ ++ ++#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */ ++#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */ ++#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 */ ++ ++#define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */ ++#define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */ ++#define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */ ++#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 */ ++ ++#endif /* MMC_MMC_PROTOCOL_H */ ++ +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/include/linux/l3/algo-bit.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,39 @@ ++/* ++ * linux/include/linux/l3/algo-bit.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. ++ * ++ * L3 Bus bit-banging algorithm. Derived from i2c-algo-bit.h by ++ * Simon G. Vogl. ++ */ ++#ifndef L3_ALGO_BIT_H ++#define L3_ALGO_BIT_H 1 ++ ++#include <linux/l3/l3.h> ++ ++struct l3_algo_bit_data { ++ void (*setdat) (void *data, int state); ++ void (*setclk) (void *data, int state); ++ void (*setmode)(void *data, int state); ++ void (*setdir) (void *data, int in); /* set data direction */ ++ int (*getdat) (void *data); ++ ++ void *data; ++ ++ /* bus timings (us) */ ++ int data_hold; ++ int data_setup; ++ int clock_high; ++ int mode_hold; ++ int mode_setup; ++ int mode; ++}; ++ ++int l3_bit_add_bus(struct l3_adapter *); ++int l3_bit_del_bus(struct l3_adapter *); ++ ++#endif +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/include/linux/l3/l3.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,95 @@ ++/* ++ * linux/include/linux/l3/l3.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. ++ * ++ * Derived from i2c.h by Simon G. Vogl ++ */ ++#ifndef L3_H ++#define L3_H ++ ++struct l3_msg { ++ unsigned char addr; /* slave address */ ++ unsigned char flags; ++#define L3_M_RD 0x01 ++#define L3_M_NOADDR 0x02 ++ unsigned short len; /* msg length */ ++ unsigned char *buf; /* pointer to msg data */ ++}; ++ ++#ifdef __KERNEL__ ++ ++#include <linux/types.h> ++#include <linux/list.h> ++ ++struct l3_adapter; ++ ++struct l3_algorithm { ++ /* textual description */ ++ char name[32]; ++ ++ /* perform bus transactions */ ++ int (*xfer)(struct l3_adapter *, struct l3_msg msgs[], int num); ++}; ++ ++struct semaphore; ++ ++/* ++ * l3_adapter is the structure used to identify a physical L3 bus along ++ * with the access algorithms necessary to access it. ++ */ ++struct l3_adapter { ++ /* ++ * This name is used to uniquely identify the adapter. ++ * It should be the same as the module name. ++ */ ++ char name[32]; ++ ++ /* ++ * the algorithm to access the bus ++ */ ++ struct l3_algorithm *algo; ++ ++ /* ++ * Algorithm specific data ++ */ ++ void *algo_data; ++ ++ /* ++ * This may be NULL, or should point to the module struct ++ */ ++ struct module *owner; ++ ++ /* ++ * private data for the adapter ++ */ ++ void *data; ++ ++ /* ++ * Our lock. Unlike the i2c layer, we allow this to be used for ++ * other stuff, like the i2c layer lock. Some people implement ++ * i2c stuff using the same signals as the l3 bus. ++ */ ++ struct semaphore *lock; ++ ++ /* ++ * List of all adapters. ++ */ ++ struct list_head adapters; ++}; ++ ++extern int l3_add_adapter(struct l3_adapter *); ++extern int l3_del_adapter(struct l3_adapter *); ++extern void l3_put_adapter(struct l3_adapter *); ++extern struct l3_adapter *l3_get_adapter(const char *name); ++ ++extern int l3_write(struct l3_adapter *, int, const char *, int); ++extern int l3_read(struct l3_adapter *, int, char *, int); ++ ++#endif ++ ++#endif /* L3_H */ +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/include/linux/l3/uda1341.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,61 @@ ++/* ++ * linux/include/linux/l3/uda1341.h ++ * ++ * Philips UDA1341 mixer device driver ++ * ++ * Copyright (c) 2000 Nicolas Pitre <nico@cam.org> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License. ++ */ ++ ++#define UDA1341_NAME "uda1341" ++ ++struct uda1341_cfg { ++ unsigned int fs:16; ++ unsigned int format:3; ++}; ++ ++#define FMT_I2S 0 ++#define FMT_LSB16 1 ++#define FMT_LSB18 2 ++#define FMT_LSB20 3 ++#define FMT_MSB 4 ++#define FMT_LSB16MSB 5 ++#define FMT_LSB18MSB 6 ++#define FMT_LSB20MSB 7 ++ ++#define L3_UDA1341_CONFIGURE 0x13410001 ++ ++struct l3_gain { ++ unsigned int left:8; ++ unsigned int right:8; ++ unsigned int unused:8; ++ unsigned int channel:8; ++}; ++ ++#define L3_SET_VOLUME 0x13410002 ++#define L3_SET_TREBLE 0x13410003 ++#define L3_SET_BASS 0x13410004 ++#define L3_SET_GAIN 0x13410005 ++ ++struct l3_agc { ++ unsigned int level:8; ++ unsigned int enable:1; ++ unsigned int attack:7; ++ unsigned int decay:8; ++ unsigned int channel:8; ++}; ++ ++#define L3_INPUT_AGC 0x13410006 ++ ++struct uda1341; ++ ++int uda1341_configure(struct uda1341 *uda, struct uda1341_cfg *conf); ++int uda1341_mixer_ctl(struct uda1341 *uda, int cmd, void *arg); ++int uda1341_open(struct uda1341 *uda); ++void uda1341_close(struct uda1341 *uda); ++ ++struct uda1341 *uda1341_attach(const char *adapter); ++void uda1341_detach(struct uda1341 *uda); ++ +--- linux-2.6.5/include/linux/i2c-id.h~heh 2004-04-03 22:36:16.000000000 -0500 ++++ linux-2.6.5/include/linux/i2c-id.h 2004-04-30 20:57:36.000000000 -0400 +@@ -187,6 +187,7 @@ + #define I2C_ALGO_BITHS 0x130000 /* enhanced bit style adapters */ + #define I2C_ALGO_OCP_IOP3XX 0x140000 /* XSCALE IOP3XX On-chip I2C alg */ + ++#define I2C_ALGO_PXA 0x200000 /* Intel PXA I2C algorithm */ + #define I2C_ALGO_EXP 0x800000 /* experimental */ + + #define I2C_ALGO_MASK 0xff0000 /* Mask for algorithms */ +--- linux-2.6.5/include/linux/serial_core.h~heh 2004-04-03 22:36:18.000000000 -0500 ++++ linux-2.6.5/include/linux/serial_core.h 2004-04-30 20:57:36.000000000 -0400 +@@ -17,7 +17,7 @@ + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * +- * $Id$ ++ * $Id$ + */ + + /* +@@ -159,8 +159,6 @@ + spinlock_t lock; /* port lock */ + unsigned int iobase; /* in/out[bwl] */ + char *membase; /* read/write[bwl] */ +- unsigned int irq; /* irq number */ +- unsigned int uartclk; /* base uart clock */ + unsigned char fifosize; /* tx fifo size */ + unsigned char x_char; /* xon/xoff char */ + unsigned char regshift; /* reg offset shift */ +@@ -172,6 +170,7 @@ + + unsigned int read_status_mask; /* driver specific */ + unsigned int ignore_status_mask; /* driver specific */ ++ + struct uart_info *info; /* pointer to parent info */ + struct uart_icount icount; /* statistics */ + +@@ -182,7 +181,6 @@ + + unsigned int flags; + +-#define UPF_HUP_NOTIFY (1 << 0) + #define UPF_FOURPORT (1 << 1) + #define UPF_SAK (1 << 2) + #define UPF_SPD_MASK (0x1030) +@@ -212,9 +210,12 @@ + unsigned int timeout; /* character-based timeout */ + unsigned int type; /* port type */ + struct uart_ops *ops; ++ unsigned int uartclk; /* base uart clock */ + unsigned int custom_divisor; ++ unsigned int irq; /* irq number */ + unsigned int line; /* port index */ + unsigned long mapbase; /* for ioremap */ ++ struct device *dev; /* parent device */ + unsigned char hub6; /* this should be in the 8250 driver */ + unsigned char unused[3]; + }; +--- linux-2.6.5/include/linux/vmalloc.h~heh 2004-04-03 22:38:23.000000000 -0500 ++++ linux-2.6.5/include/linux/vmalloc.h 2004-04-30 20:57:36.000000000 -0400 +@@ -35,6 +35,8 @@ + * Lowlevel-APIs (not for driver use!) + */ + extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags); ++extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, ++ unsigned long start, unsigned long end); + extern struct vm_struct *remove_vm_area(void *addr); + extern int map_vm_area(struct vm_struct *area, pgprot_t prot, + struct page ***pages); +--- linux-2.6.5/include/linux/mm.h~heh 2004-04-03 22:36:15.000000000 -0500 ++++ linux-2.6.5/include/linux/mm.h 2004-04-30 20:57:36.000000000 -0400 +@@ -655,5 +655,12 @@ + int in_gate_area(struct task_struct *task, unsigned long addr); + #endif + ++#ifndef __arm__ ++#define memc_update_addr(x,y,z) ++#define memc_update_mm(x) ++#define memc_clear(x,y) ++#endif ++ + #endif /* __KERNEL__ */ + #endif /* _LINUX_MM_H */ ++ +--- linux-2.6.5/init/do_mounts.c~heh 2004-04-03 22:36:56.000000000 -0500 ++++ linux-2.6.5/init/do_mounts.c 2004-04-30 20:57:36.000000000 -0400 +@@ -391,7 +391,7 @@ + root_device_name += 5; + } + +- is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR; ++ is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR || MAJOR(ROOT_DEV) == 31; + + if (initrd_load()) + goto out; +--- linux-2.6.5/fs/binfmt_aout.c~heh 2004-04-03 22:36:26.000000000 -0500 ++++ linux-2.6.5/fs/binfmt_aout.c 2004-04-30 20:57:36.000000000 -0400 +@@ -432,7 +432,11 @@ + else + send_sig(SIGTRAP, current, 0); + } ++#ifndef __arm__ + return 0; ++#else ++ return regs->ARM_r0; ++#endif + } + + static int load_aout_library(struct file *file) +@@ -462,8 +466,11 @@ + + /* For QMAGIC, the starting address is 0x20 into the page. We mask + this off to get the starting address for the page */ +- +- start_addr = ex.a_entry & 0xfffff000; ++#ifndef __arm__ ++ start_addr = ex.a_entry & 0xfffff000; ++#else ++ start_addr = ex.a_entry & 0xffff8000; ++#endif + + if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) { + static unsigned long error_time; +--- linux-2.6.5/mm/slab.c~heh 2004-04-03 22:37:41.000000000 -0500 ++++ linux-2.6.5/mm/slab.c 2004-04-30 20:57:36.000000000 -0400 +@@ -2115,12 +2115,12 @@ + * + * Called with disabled ints. + */ +-static inline void __cache_free (kmem_cache_t *cachep, void* objp) ++static inline void __cache_free (kmem_cache_t *cachep, void* objp, void *caller) + { + struct array_cache *ac = ac_data(cachep); + + check_irq_off(); +- objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0)); ++ objp = cache_free_debugcheck(cachep, objp, caller /*__builtin_return_address(0)*/); + + if (likely(ac->avail < ac->limit)) { + STATS_INC_FREEHIT(cachep); +@@ -2289,7 +2289,7 @@ + unsigned long flags; + + local_irq_save(flags); +- __cache_free(cachep, objp); ++ __cache_free(cachep, objp, __builtin_return_address(0)); + local_irq_restore(flags); + } + +@@ -2312,7 +2312,7 @@ + local_irq_save(flags); + kfree_debugcheck(objp); + c = GET_PAGE_CACHE(virt_to_page(objp)); +- __cache_free(c, (void*)objp); ++ __cache_free(c, (void*)objp, __builtin_return_address(0)); + local_irq_restore(flags); + } + +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/Documentation/l3/structure 2004-04-30 20:57:36.000000000 -0400 +@@ -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. +--- linux-2.6.5/arch/arm/kernel/debug.S~heh 2004-04-03 22:36:55.000000000 -0500 ++++ linux-2.6.5/arch/arm/kernel/debug.S 2004-04-30 20:57:36.000000000 -0400 +@@ -192,6 +192,20 @@ + + @ if all ports are inactive, then there is nothing we can do + moveq pc, lr ++ ldr r1, [\rx, #UTCR2] ++ teq r1, #5 ++ movne r1, #0 ++ strne r1, [\rx, #UTCR3] ++ movne r1, #8 ++ strne r1, [\rx, #UTCR0] ++ movne r1, #5 ++ strne r1, [\rx, #UTCR2] ++ movne r1, #0 ++ strne r1, [\rx, #UTCR1] ++ movne r1, #3 ++ strne r1, [\rx, #UTCR3] ++ movne r1, #255 ++ strne r1, [\rx, #UTSR0] + .endm + + .macro senduart,rd,rx +@@ -287,7 +301,7 @@ + + #elif defined(CONFIG_ARCH_INTEGRATOR) + +-#include <asm/hardware/serial_amba.h> ++#include <asm/hardware/amba_serial.h> + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 +@@ -298,7 +312,7 @@ + .endm + + .macro senduart,rd,rx +- strb \rd, [\rx, #AMBA_UARTDR] ++ strb \rd, [\rx, #UART01x_DR] + .endm + + .macro waituart,rd,rx +--- linux-2.6.5/arch/arm/kernel/entry-armv.S~heh 2004-04-03 22:36:54.000000000 -0500 ++++ linux-2.6.5/arch/arm/kernel/entry-armv.S 2004-04-30 20:57:36.000000000 -0400 +@@ -1181,6 +1181,9 @@ + * get out of that mode without clobbering one register. + */ + vector_FIQ: disable_fiq ++ mrs r13, spsr ++ orr r13, r13, #PSR_F_BIT ++ msr spsr, r13 + subs pc, lr, #4 + + /*============================================================================= +--- linux-2.6.5/arch/arm/kernel/irq.c~heh 2004-04-03 22:36:12.000000000 -0500 ++++ linux-2.6.5/arch/arm/kernel/irq.c 2004-04-30 20:57:36.000000000 -0400 +@@ -47,12 +47,36 @@ + #define MAX_IRQ_CNT 100000 + + static volatile unsigned long irq_err_count; +-static spinlock_t irq_controller_lock; + static LIST_HEAD(irq_pending); + + struct irqdesc irq_desc[NR_IRQS]; + void (*init_arch_irq)(void) __initdata = NULL; + ++#if NR_IRQ_DEVICES > 1 ++struct irq_device { ++ spinlock_t lock; ++ int nr_irqs; ++ struct irq_desc *irqs; ++}; ++ ++static struct irq_device irq_devices[NR_IRQ_DEVICES] = { ++ [0] = { ++ .lock = SPIN_LOCK_UNLOCKED, ++ .nr_irqs = NR_IRQS, ++ .irqs = irq_desc, ++ }, ++}; ++#define IRQ_LOCK(irq) (&irq_devices[IRQ_DEVICE(irq)].lock) ++#define IRQ_DESC(irq) (&irq_devices[IRQ_DEVICE(irq)].irqs[IRQ_INDEX(irq)]) ++#define IRQ_VALID(irq) (IRQ_DEVICE(irq) < NR_IRQ_DEVICES && \ ++ IRQ_INDEX(irq) < irq_devices[IRQ_DEVICE(irq)].nr_irqs) ++#else ++static spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED; ++#define IRQ_LOCK(irq) (&irq_controller_lock) ++#define IRQ_DESC(irq) (&irq_desc[irq]) ++#define IRQ_VALID(irq) ((irq) < NR_IRQS) ++#endif ++ + /* + * Dummy mask/unmask handler + */ +@@ -95,13 +119,13 @@ + */ + void disable_irq(unsigned int irq) + { +- struct irqdesc *desc = irq_desc + irq; ++ struct irqdesc *desc = IRQ_DESC(irq); + unsigned long flags; + +- spin_lock_irqsave(&irq_controller_lock, flags); ++ spin_lock_irqsave(IRQ_LOCK(irq), flags); + desc->disable_depth++; + list_del_init(&desc->pend); +- spin_unlock_irqrestore(&irq_controller_lock, flags); ++ spin_unlock_irqrestore(IRQ_LOCK(irq), flags); + } + + /** +@@ -116,10 +140,10 @@ + */ + void enable_irq(unsigned int irq) + { +- struct irqdesc *desc = irq_desc + irq; ++ struct irqdesc *desc = IRQ_DESC(irq); + unsigned long flags; + +- spin_lock_irqsave(&irq_controller_lock, flags); ++ spin_lock_irqsave(IRQ_LOCK(irq), flags); + if (unlikely(!desc->disable_depth)) { + printk("enable_irq(%u) unbalanced from %p\n", irq, + __builtin_return_address(0)); +@@ -140,7 +164,7 @@ + list_add(&desc->pend, &irq_pending); + } + } +- spin_unlock_irqrestore(&irq_controller_lock, flags); ++ spin_unlock_irqrestore(IRQ_LOCK(irq), flags); + } + + /* +@@ -148,24 +172,24 @@ + */ + void enable_irq_wake(unsigned int irq) + { +- struct irqdesc *desc = irq_desc + irq; ++ struct irqdesc *desc = IRQ_DESC(irq); + unsigned long flags; + +- spin_lock_irqsave(&irq_controller_lock, flags); ++ spin_lock_irqsave(IRQ_LOCK(irq), flags); + if (desc->chip->wake) + desc->chip->wake(irq, 1); +- spin_unlock_irqrestore(&irq_controller_lock, flags); ++ spin_unlock_irqrestore(IRQ_LOCK(irq), flags); + } + + void disable_irq_wake(unsigned int irq) + { +- struct irqdesc *desc = irq_desc + irq; ++ struct irqdesc *desc = IRQ_DESC(irq); + unsigned long flags; + +- spin_lock_irqsave(&irq_controller_lock, flags); ++ spin_lock_irqsave(IRQ_LOCK(irq), flags); + if (desc->chip->wake) + desc->chip->wake(irq, 0); +- spin_unlock_irqrestore(&irq_controller_lock, flags); ++ spin_unlock_irqrestore(IRQ_LOCK(irq), flags); + } + + int show_interrupts(struct seq_file *p, void *v) +@@ -175,8 +199,8 @@ + unsigned long flags; + + if (i < NR_IRQS) { +- spin_lock_irqsave(&irq_controller_lock, flags); +- action = irq_desc[i].action; ++ spin_lock_irqsave(IRQ_LOCK(irq), flags); ++ action = IRQ_DESC(i)->action; + if (!action) + goto unlock; + +@@ -187,7 +211,7 @@ + + seq_putc(p, '\n'); + unlock: +- spin_unlock_irqrestore(&irq_controller_lock, flags); ++ spin_unlock_irqrestore(IRQ_LOCK(irq), flags); + } else if (i == NR_IRQS) { + #ifdef CONFIG_ARCH_ACORN + show_fiq_list(p, v); +@@ -259,7 +283,7 @@ + unsigned int status; + int retval = 0; + +- spin_unlock(&irq_controller_lock); ++ spin_unlock(IRQ_LOCK(irq)); + + if (!(action->flags & SA_INTERRUPT)) + local_irq_enable(); +@@ -274,7 +298,7 @@ + if (status & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + +- spin_lock_irq(&irq_controller_lock); ++ spin_lock_irq(IRQ_LOCK(irq)); + + return retval; + } +@@ -455,7 +479,7 @@ + desc = &bad_irq_desc; + + irq_enter(); +- spin_lock(&irq_controller_lock); ++ spin_lock(IRQ_LOCK(irq)); + desc->handle(irq, desc, regs); + + /* +@@ -464,7 +488,7 @@ + if (!list_empty(&irq_pending)) + do_pending_irqs(regs); + +- spin_unlock(&irq_controller_lock); ++ spin_unlock(IRQ_LOCK(irq)); + irq_exit(); + } + +@@ -473,7 +497,7 @@ + struct irqdesc *desc; + unsigned long flags; + +- if (irq >= NR_IRQS) { ++ if (!IRQ_VALID(irq)) { + printk(KERN_ERR "Trying to install handler for IRQ%d\n", irq); + return; + } +@@ -481,12 +505,12 @@ + if (handle == NULL) + handle = do_bad_IRQ; + +- desc = irq_desc + irq; ++ desc = IRQ_DESC(irq); + + if (is_chained && desc->chip == &bad_chip) + printk(KERN_WARNING "Trying to install chained handler for IRQ%d\n", irq); + +- spin_lock_irqsave(&irq_controller_lock, flags); ++ spin_lock_irqsave(IRQ_LOCK(irq), flags); + if (handle == do_bad_IRQ) { + desc->chip->mask(irq); + desc->chip->ack(irq); +@@ -499,7 +523,7 @@ + desc->disable_depth = 0; + desc->chip->unmask(irq); + } +- spin_unlock_irqrestore(&irq_controller_lock, flags); ++ spin_unlock_irqrestore(IRQ_LOCK(irq), flags); + } + + void set_irq_chip(unsigned int irq, struct irqchip *chip) +@@ -507,7 +531,7 @@ + struct irqdesc *desc; + unsigned long flags; + +- if (irq >= NR_IRQS) { ++ if (!IRQ_VALID(irq)) { + printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq); + return; + } +@@ -515,10 +539,10 @@ + if (chip == NULL) + chip = &bad_chip; + +- desc = irq_desc + irq; +- spin_lock_irqsave(&irq_controller_lock, flags); ++ desc = IRQ_DESC(irq); ++ spin_lock_irqsave(IRQ_LOCK(irq), flags); + desc->chip = chip; +- spin_unlock_irqrestore(&irq_controller_lock, flags); ++ spin_unlock_irqrestore(IRQ_LOCK(irq), flags); + } + + int set_irq_type(unsigned int irq, unsigned int type) +@@ -527,16 +551,21 @@ + unsigned long flags; + int ret = -ENXIO; + +- if (irq >= NR_IRQS) { ++ if (!IRQ_VALID(irq)) { + printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq); + return -ENODEV; + } + +- desc = irq_desc + irq; ++ desc = IRQ_DESC(irq); ++ if (!desc->action && desc->handle != do_bad_IRQ) { ++ printk(KERN_ERR "Setting type of unclaimed IRQ%d from ", irq); ++ print_symbol("%s\n", (unsigned long)__builtin_return_address(0)); ++ } ++ + if (desc->chip->type) { +- spin_lock_irqsave(&irq_controller_lock, flags); ++ spin_lock_irqsave(IRQ_LOCK(irq), flags); + ret = desc->chip->type(irq, type); +- spin_unlock_irqrestore(&irq_controller_lock, flags); ++ spin_unlock_irqrestore(IRQ_LOCK(irq), flags); + } + + return ret; +@@ -547,17 +576,17 @@ + struct irqdesc *desc; + unsigned long flags; + +- if (irq >= NR_IRQS) { ++ if (!IRQ_VALID(irq)) { + printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq); + return; + } + +- desc = irq_desc + irq; +- spin_lock_irqsave(&irq_controller_lock, flags); ++ desc = IRQ_DESC(irq); ++ spin_lock_irqsave(IRQ_LOCK(irq), flags); + desc->valid = (iflags & IRQF_VALID) != 0; + desc->probe_ok = (iflags & IRQF_PROBE) != 0; + desc->noautoenable = (iflags & IRQF_NOAUTOEN) != 0; +- spin_unlock_irqrestore(&irq_controller_lock, flags); ++ spin_unlock_irqrestore(IRQ_LOCK(irq), flags); + } + + int setup_irq(unsigned int irq, struct irqaction *new) +@@ -587,13 +616,13 @@ + /* + * The following block of code has to be executed atomically + */ +- desc = irq_desc + irq; +- spin_lock_irqsave(&irq_controller_lock, flags); ++ desc = IRQ_DESC(irq); ++ spin_lock_irqsave(IRQ_LOCK(irq), flags); + p = &desc->action; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) { +- spin_unlock_irqrestore(&irq_controller_lock, flags); ++ spin_unlock_irqrestore(IRQ_LOCK(irq), flags); + return -EBUSY; + } + +@@ -618,7 +647,7 @@ + } + } + +- spin_unlock_irqrestore(&irq_controller_lock, flags); ++ spin_unlock_irqrestore(IRQ_LOCK(irq), flags); + return 0; + } + +@@ -659,7 +688,7 @@ + unsigned long retval; + struct irqaction *action; + +- if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler || ++ if (!IRQ_VALID(irq) || !IRQ_DESC(irq)->valid || !handler || + (irq_flags & SA_SHIRQ && !dev_id)) + return -EINVAL; + +@@ -700,14 +729,14 @@ + struct irqaction * action, **p; + unsigned long flags; + +- if (irq >= NR_IRQS || !irq_desc[irq].valid) { ++ if (!IRQ_VALID(irq) || !IRQ_DESC(irq)->valid) { + printk(KERN_ERR "Trying to free IRQ%d\n",irq); + dump_stack(); + return; + } + +- spin_lock_irqsave(&irq_controller_lock, flags); +- for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) { ++ spin_lock_irqsave(IRQ_LOCK(irq), flags); ++ for (p = &IRQ_DESC(irq)->action; (action = *p) != NULL; p = &action->next) { + if (action->dev_id != dev_id) + continue; + +@@ -715,7 +744,7 @@ + *p = action->next; + break; + } +- spin_unlock_irqrestore(&irq_controller_lock, flags); ++ spin_unlock_irqrestore(IRQ_LOCK(irq), flags); + + if (!action) { + printk(KERN_ERR "Trying to free free IRQ%d\n",irq); +@@ -747,19 +776,18 @@ + * first snaffle up any unassigned but + * probe-able interrupts + */ +- spin_lock_irq(&irq_controller_lock); + for (i = 0; i < NR_IRQS; i++) { +- if (!irq_desc[i].probe_ok || irq_desc[i].action) +- continue; +- +- irq_desc[i].probing = 1; +- irq_desc[i].triggered = 0; +- if (irq_desc[i].chip->type) +- irq_desc[i].chip->type(i, IRQT_PROBE); +- irq_desc[i].chip->unmask(i); +- irqs += 1; ++ spin_lock_irq(IRQ_LOCK(i)); ++ if (irq_desc[i].probe_ok && !irq_desc[i].action) { ++ irq_desc[i].probing = 1; ++ irq_desc[i].triggered = 0; ++ if (irq_desc[i].chip->type) ++ irq_desc[i].chip->type(i, IRQT_PROBE); ++ irq_desc[i].chip->unmask(i); ++ irqs += 1; ++ } ++ spin_unlock_irq(IRQ_LOCK(i)); + } +- spin_unlock_irq(&irq_controller_lock); + + /* + * wait for spurious interrupts to mask themselves out again +@@ -770,14 +798,14 @@ + /* + * now filter out any obviously spurious interrupts + */ +- spin_lock_irq(&irq_controller_lock); + for (i = 0; i < NR_IRQS; i++) { ++ spin_lock_irq(IRQ_LOCK(i)); + if (irq_desc[i].probing && irq_desc[i].triggered) { + irq_desc[i].probing = 0; + irqs -= 1; + } ++ spin_unlock_irq(IRQ_LOCK(i)); + } +- spin_unlock_irq(&irq_controller_lock); + + return irqs; + } +@@ -788,11 +816,13 @@ + { + unsigned int mask = 0, i; + +- spin_lock_irq(&irq_controller_lock); +- for (i = 0; i < 16 && i < NR_IRQS; i++) +- if (irq_desc[i].probing && irq_desc[i].triggered) ++ for (i = 0; i < 16 && i < NR_IRQS; i++) { ++ struct irqdesc *desc = IRQ_DESC(i); ++ spin_lock_irq(IRQ_LOCK(i)); ++ if (desc->probing && desc->triggered) + mask |= 1 << i; +- spin_unlock_irq(&irq_controller_lock); ++ spin_unlock_irq(IRQ_LOCK(i)); ++ } + + up(&probe_sem); + +@@ -813,23 +843,21 @@ + * look at the interrupts, and find exactly one + * that we were probing has been triggered + */ +- spin_lock_irq(&irq_controller_lock); + for (i = 0; i < NR_IRQS; i++) { +- if (irq_desc[i].probing && +- irq_desc[i].triggered) { ++ struct irqdesc *desc = IRQ_DESC(i); ++ ++ spin_lock_irq(IRQ_LOCK(i)); ++ if (desc->probing && desc->triggered) { + if (irq_found != NO_IRQ) { ++ spin_unlock_irq(IRQ_LOCK(i)); + irq_found = NO_IRQ; +- goto out; ++ break; + } + irq_found = i; + } ++ spin_unlock_irq(IRQ_LOCK(i)); + } + +- if (irq_found == -1) +- irq_found = NO_IRQ; +-out: +- spin_unlock_irq(&irq_controller_lock); +- + up(&probe_sem); + + return irq_found; +--- linux-2.6.5/arch/arm/kernel/bios32.c~heh 2004-04-03 22:36:56.000000000 -0500 ++++ linux-2.6.5/arch/arm/kernel/bios32.c 2004-04-30 20:57:36.000000000 -0400 +@@ -565,8 +565,6 @@ + if (hw->postinit) + hw->postinit(); + +- pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq); +- + list_for_each_entry(sys, &hw->buses, node) { + struct pci_bus *bus = sys->bus; + +@@ -581,6 +579,11 @@ + pci_bus_assign_resources(bus); + + /* ++ * Fixup IRQs. ++ */ ++ pci_bus_fixup_irqs(bus, pcibios_swizzle, pcibios_map_irq); ++ ++ /* + * Tell drivers about devices found. + */ + pci_bus_add_devices(bus); +--- linux-2.6.5/arch/arm/kernel/traps.c~heh 2004-04-03 22:36:57.000000000 -0500 ++++ linux-2.6.5/arch/arm/kernel/traps.c 2004-04-30 20:57:36.000000000 -0400 +@@ -206,33 +206,43 @@ + c_backtrace(fp, 0x10); + } + +-spinlock_t die_lock = SPIN_LOCK_UNLOCKED; +- +-/* +- * This function is protected against re-entrancy. +- */ +-NORET_TYPE void die(const char *str, struct pt_regs *regs, int err) ++static void __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs) + { +- struct task_struct *tsk = current; ++ struct task_struct *tsk = thread->task; + static int die_counter; + +- console_verbose(); +- spin_lock_irq(&die_lock); +- bust_spinlocks(1); +- + printk("Internal error: %s: %x [#%d]\n", str, err, ++die_counter); + print_modules(); + printk("CPU: %d\n", smp_processor_id()); + show_regs(regs); + printk("Process %s (pid: %d, stack limit = 0x%p)\n", +- tsk->comm, tsk->pid, tsk->thread_info + 1); ++ tsk->comm, tsk->pid, thread + 1); + + if (!user_mode(regs) || in_interrupt()) { + dump_mem("Stack: ", regs->ARM_sp, 8192+(unsigned long)tsk->thread_info); + dump_backtrace(regs, tsk); + dump_instr(regs); + } ++} ++ ++void nmi_watchdog(struct thread_info *thread, struct pt_regs *regs) ++{ ++ __die("NMI watchdog", 0, thread, regs); ++} + ++spinlock_t die_lock = SPIN_LOCK_UNLOCKED; ++ ++/* ++ * This function is protected against re-entrancy. ++ */ ++NORET_TYPE void die(const char *str, struct pt_regs *regs, int err) ++{ ++ struct thread_info *thread = current_thread_info(); ++ ++ console_verbose(); ++ spin_lock_irq(&die_lock); ++ bust_spinlocks(1); ++ __die(str, err, thread, regs); + bust_spinlocks(0); + spin_unlock_irq(&die_lock); + do_exit(SIGSEGV); +--- linux-2.6.5/arch/arm/Kconfig~heh 2004-04-03 22:37:07.000000000 -0500 ++++ linux-2.6.5/arch/arm/Kconfig 2004-04-30 20:57:36.000000000 -0400 +@@ -297,7 +297,7 @@ + + config CPU_FREQ + bool "Support CPU clock change (EXPERIMENTAL)" +- depends on (ARCH_SA1100 || ARCH_INTEGRATOR) && EXPERIMENTAL ++ depends on (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_PXA) && EXPERIMENTAL + help + CPU clock scaling allows you to change the clock speed of the + running CPU on the fly. This is a nice method to save battery power, +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/fastfpe/entry.S 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,294 @@ ++/* ++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 ++ mov r4, r0 @ 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 ++ ++/*---------------------------------------------------------------------------*/ +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/fastfpe/module.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,62 @@ ++/* ++ Fast Floating Point Emulator ++ (c) Peter Teichmann <mail@peter-teichmann.de> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/signal.h> ++#include <linux/sched.h> ++#include <linux/init.h> ++#include <linux/errno.h> ++ ++#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 */ ++ ++static int __init fpe_init(void) ++{ ++ if (fpe_type[0] && strcmp(fpe_type, "fastfpe")) ++ return 0; ++ ++ 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 <mail@peter-teichmann.de>"); ++MODULE_DESCRIPTION("Fast floating point emulator with full precision"); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/fastfpe/CPDO.S 2004-04-30 20:57:36.000000000 -0400 +@@ -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 ++ ++/*---------------------------------------------------------------------------*/ +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/fastfpe/CPRT.S 2004-04-30 20:57:36.000000000 -0400 +@@ -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 ++ ++/*---------------------------------------------------------------------------*/ +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/fastfpe/CPDT.S 2004-04-30 20:57:36.000000000 -0400 +@@ -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 ++ ++/*---------------------------------------------------------------------------*/ +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/fastfpe/Makefile 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,14 @@ ++# ++# linux/arch/arm/fastfpe/Makefile ++# ++# Copyright (C) Peter Teichmann ++# ++ ++obj-y := ++obj-m := ++obj-n := ++obj- := ++ ++fastfpe-objs := module.o entry.o CPDO.o CPRT.o CPDT.o ++ ++obj-$(CONFIG_FPE_FASTFPE) += fastfpe.o +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/common/rtctime.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,482 @@ ++/* ++ * linux/arch/arm/common/rtctime.c ++ * ++ * Copyright (C) 2003 Deep Blue Solutions Ltd. ++ * Based on sa1100-rtc.c, Nils Faerber, CIH, Nicolas Pitre. ++ * Based on rtc.c by Paul Gortmaker ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/time.h> ++#include <linux/rtc.h> ++#include <linux/poll.h> ++#include <linux/proc_fs.h> ++#include <linux/miscdevice.h> ++#include <linux/spinlock.h> ++#include <linux/device.h> ++ ++#include <asm/rtc.h> ++#include <asm/semaphore.h> ++ ++static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); ++static struct fasync_struct *rtc_async_queue; ++ ++/* ++ * rtc_lock protects rtc_irq_data ++ */ ++static spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; ++static unsigned long rtc_irq_data; ++ ++/* ++ * rtc_sem protects rtc_inuse and rtc_ops ++ */ ++static DECLARE_MUTEX(rtc_sem); ++static unsigned long rtc_inuse; ++static struct rtc_ops *rtc_ops; ++ ++#define rtc_epoch 1900UL ++ ++static const unsigned char days_in_month[] = { ++ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ++}; ++ ++#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) ++#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400)) ++ ++static int month_days(unsigned int month, unsigned int year) ++{ ++ return days_in_month[month] + (LEAP_YEAR(year) && month == 1); ++} ++ ++/* ++ * Convert seconds since 01-01-1970 00:00:00 to Gregorian date. ++ */ ++void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) ++{ ++ int days, month, year; ++ ++ days = time / 86400; ++ time -= days * 86400; ++ ++ tm->tm_wday = (days + 4) % 7; ++ ++ 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 + LEAP_YEAR(year); ++ } ++ tm->tm_year = year - 1900; ++ tm->tm_yday = days + 1; ++ ++ for (month = 0; month < 11; month++) { ++ int newdays; ++ ++ newdays = days - month_days(month, year); ++ if (newdays < 0) ++ break; ++ days = newdays; ++ } ++ tm->tm_mon = month; ++ tm->tm_mday = days + 1; ++ ++ tm->tm_hour = time / 3600; ++ time -= tm->tm_hour * 3600; ++ tm->tm_min = time / 60; ++ tm->tm_sec = time - tm->tm_min * 60; ++} ++ ++/* ++ * Convert Gregorian date to seconds since 01-01-1970 00:00:00. ++ */ ++int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time) ++{ ++ unsigned int yrs = tm->tm_year + 1900; ++ ++ *time = 0; ++ ++ if (yrs < 1970 || ++ tm->tm_mon >= 12 || ++ tm->tm_mday < 1 || ++ tm->tm_mday > month_days(tm->tm_mon, yrs) || ++ tm->tm_hour >= 24 || ++ tm->tm_min >= 60 || ++ tm->tm_sec >= 60) ++ return -EINVAL; ++ ++ *time = mktime(yrs, tm->tm_mon + 1, tm->tm_mday, ++ tm->tm_hour, tm->tm_min, tm->tm_sec); ++ ++ return 0; ++} ++ ++/* ++ * Calculate the next alarm time given the requested alarm time mask ++ * and the current time. ++ * ++ * FIXME: for now, we just copy the alarm time because we're lazy (and ++ * is therefore buggy - setting a 10am alarm at 8pm will not result in ++ * the alarm triggering.) ++ */ ++void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, struct rtc_time *alrm) ++{ ++ next->tm_year = now->tm_year; ++ next->tm_mon = now->tm_mon; ++ next->tm_mday = now->tm_mday; ++ next->tm_hour = alrm->tm_hour; ++ next->tm_min = alrm->tm_min; ++ next->tm_sec = alrm->tm_sec; ++} ++ ++static inline void rtc_read_time(struct rtc_ops *ops, struct rtc_time *tm) ++{ ++ memset(tm, 0, sizeof(struct rtc_time)); ++ ops->read_time(tm); ++} ++ ++static inline int rtc_set_time(struct rtc_ops *ops, struct rtc_time *tm) ++{ ++ return ops->set_time(tm); ++} ++ ++static inline void rtc_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) ++{ ++ memset(alrm, 0, sizeof(struct rtc_wkalrm)); ++ ops->read_alarm(alrm); ++} ++ ++static inline int rtc_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) ++{ ++ return ops->set_alarm(alrm); ++} ++ ++void rtc_update(unsigned long num, unsigned long events) ++{ ++ spin_lock(&rtc_lock); ++ rtc_irq_data = (rtc_irq_data + (num << 8)) | events; ++ spin_unlock(&rtc_lock); ++ ++ wake_up_interruptible(&rtc_wait); ++ kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); ++} ++ ++ ++static ssize_t ++rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long data; ++ ssize_t ret; ++ ++ if (count < sizeof(unsigned long)) ++ return -EINVAL; ++ ++ add_wait_queue(&rtc_wait, &wait); ++ do { ++ __set_current_state(TASK_INTERRUPTIBLE); ++ ++ spin_lock_irq(&rtc_lock); ++ data = rtc_irq_data; ++ rtc_irq_data = 0; ++ spin_unlock_irq(&rtc_lock); ++ ++ if (data != 0) { ++ ret = 0; ++ break; ++ } ++ if (file->f_flags & O_NONBLOCK) { ++ ret = -EAGAIN; ++ break; ++ } ++ if (signal_pending(current)) { ++ ret = -ERESTARTSYS; ++ break; ++ } ++ schedule(); ++ } while (1); ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&rtc_wait, &wait); ++ ++ if (ret == 0) { ++ ret = put_user(data, (unsigned long *)buf); ++ if (ret == 0) ++ ret = sizeof(unsigned long); ++ } ++ return ret; ++} ++ ++static unsigned int rtc_poll(struct file *file, poll_table *wait) ++{ ++ unsigned long data; ++ ++ poll_wait(file, &rtc_wait, wait); ++ ++ spin_lock_irq(&rtc_lock); ++ data = rtc_irq_data; ++ spin_unlock_irq(&rtc_lock); ++ ++ return data != 0 ? POLLIN | POLLRDNORM : 0; ++} ++ ++static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ struct rtc_ops *ops = file->private_data; ++ struct rtc_time tm; ++ struct rtc_wkalrm alrm; ++ int ret; ++ ++ switch (cmd) { ++ case RTC_ALM_READ: ++ rtc_read_alarm(ops, &alrm); ++ ret = copy_to_user((void *)arg, &alrm.time, sizeof(tm)); ++ if (ret) ++ ret = -EFAULT; ++ break; ++ ++ case RTC_ALM_SET: ++ ret = copy_from_user(&alrm.time, (void *)arg, sizeof(tm)); ++ alrm.enabled = 0; ++ alrm.pending = 0; ++ alrm.time.tm_mday = -1; ++ alrm.time.tm_mon = -1; ++ alrm.time.tm_year = -1; ++ alrm.time.tm_wday = -1; ++ alrm.time.tm_yday = -1; ++ alrm.time.tm_isdst = -1; ++ if (ret == 0) ++ ret = rtc_set_alarm(ops, &alrm); ++ else ++ ret = -EFAULT; ++ break; ++ ++ case RTC_RD_TIME: ++ rtc_read_time(ops, &tm); ++ ret = copy_to_user((void *)arg, &tm, sizeof(tm)); ++ if (ret) ++ ret = -EFAULT; ++ break; ++ ++ case RTC_SET_TIME: ++ if (!capable(CAP_SYS_TIME)) { ++ ret = -EACCES; ++ break; ++ } ++ ret = copy_from_user(&tm, (void *)arg, sizeof(tm)); ++ if (ret == 0) ++ ret = rtc_set_time(ops, &tm); ++ else ++ ret = -EFAULT; ++ break; ++ ++#ifndef rtc_epoch ++ case RTC_EPOCH_SET: ++ /* ++ * There were no RTC clocks before 1900. ++ */ ++ if (arg < 1900) { ++ ret = -EINVAL; ++ break; ++ } ++ if (!capable(CAP_SYS_TIME)) { ++ ret = -EACCES; ++ break; ++ } ++ rtc_epoch = arg; ++ ret = 0; ++ break; ++#endif ++ ++ case RTC_EPOCH_READ: ++ ret = put_user(rtc_epoch, (unsigned long *)arg); ++ break; ++ ++ case RTC_WKALM_SET: ++ ret = copy_from_user(&alrm, (void *)arg, sizeof(alrm)); ++ if (ret == 0) ++ ret = rtc_set_alarm(ops, &alrm); ++ else ++ ret = -EFAULT; ++ break; ++ ++ case RTC_WKALM_RD: ++ rtc_read_alarm(ops, &alrm); ++ ret = copy_to_user((void *)arg, &alrm, sizeof(alrm)); ++ if (ret) ++ ret = -EFAULT; ++ break; ++ ++ default: ++ ret = ops->ioctl(cmd, arg); ++ } ++ return ret; ++} ++ ++static int rtc_open(struct inode *inode, struct file *file) ++{ ++ int ret; ++ ++ down(&rtc_sem); ++ ++ if (rtc_inuse) { ++ ret = -EBUSY; ++ } else if (!rtc_ops || !try_module_get(rtc_ops->owner)) { ++ ret = -ENODEV; ++ } else { ++ file->private_data = rtc_ops; ++ ++ ret = rtc_ops->open ? rtc_ops->open() : 0; ++ if (ret == 0) { ++ spin_lock_irq(&rtc_lock); ++ rtc_irq_data = 0; ++ spin_unlock_irq(&rtc_lock); ++ ++ rtc_inuse = 1; ++ } ++ } ++ up(&rtc_sem); ++ ++ return ret; ++} ++ ++static int rtc_release(struct inode *inode, struct file *file) ++{ ++ struct rtc_ops *ops = file->private_data; ++ ++ if (ops->release) ++ ops->release(); ++ ++ spin_lock_irq(&rtc_lock); ++ rtc_irq_data = 0; ++ spin_unlock_irq(&rtc_lock); ++ ++ module_put(rtc_ops->owner); ++ rtc_inuse = 0; ++ ++ return 0; ++} ++ ++static int rtc_fasync(int fd, struct file *file, int on) ++{ ++ return fasync_helper(fd, file, on, &rtc_async_queue); ++} ++ ++static struct file_operations rtc_fops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .read = rtc_read, ++ .poll = rtc_poll, ++ .ioctl = rtc_ioctl, ++ .open = rtc_open, ++ .release = rtc_release, ++ .fasync = rtc_fasync, ++}; ++ ++static struct miscdevice rtc_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) ++{ ++ struct rtc_ops *ops = data; ++ struct rtc_wkalrm alrm; ++ struct rtc_time tm; ++ char *p = page; ++ int len; ++ ++ rtc_read_time(ops, &tm); ++ ++ p += sprintf(p, ++ "rtc_time\t: %02d:%02d:%02d\n" ++ "rtc_date\t: %04d-%02d-%02d\n" ++ "rtc_epoch\t: %04lu\n", ++ tm.tm_hour, tm.tm_min, tm.tm_sec, ++ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, ++ rtc_epoch); ++ ++ rtc_read_alarm(ops, &alrm); ++ p += sprintf(p, "alrm_time\t: "); ++ if ((unsigned int)alrm.time.tm_hour <= 24) ++ p += sprintf(p, "%02d:", alrm.time.tm_hour); ++ else ++ p += sprintf(p, "**:"); ++ if ((unsigned int)alrm.time.tm_min <= 59) ++ p += sprintf(p, "%02d:", alrm.time.tm_min); ++ else ++ p += sprintf(p, "**:"); ++ if ((unsigned int)alrm.time.tm_sec <= 59) ++ p += sprintf(p, "%02d\n", alrm.time.tm_sec); ++ else ++ p += sprintf(p, "**\n"); ++ ++ p += sprintf(p, "alrm_date\t: "); ++ if ((unsigned int)alrm.time.tm_year <= 200) ++ p += sprintf(p, "%04d-", alrm.time.tm_year + 1900); ++ else ++ p += sprintf(p, "****-"); ++ if ((unsigned int)alrm.time.tm_mon <= 11) ++ p += sprintf(p, "%02d-", alrm.time.tm_mon + 1); ++ else ++ p += sprintf(p, "**-"); ++ if ((unsigned int)alrm.time.tm_mday <= 31) ++ p += sprintf(p, "%02d\n", alrm.time.tm_mday); ++ else ++ p += sprintf(p, "**\n"); ++ p += sprintf(p, "alrm_wakeup\t: %s\n", alrm.enabled ? "yes" : "no"); ++ p += sprintf(p, "alrm_pending\t: %s\n", alrm.pending ? "yes" : "no"); ++ ++ if (ops->proc) ++ p += ops->proc(p); ++ ++ len = (p - page) - off; ++ if (len < 0) ++ len = 0; ++ *eof = len <= count; ++ *start = page + off; ++ ++ return len; ++} ++ ++int register_rtc(struct rtc_ops *ops) ++{ ++ int ret = -EBUSY; ++ ++ down(&rtc_sem); ++ if (rtc_ops == NULL) { ++ rtc_ops = ops; ++ ++ ret = misc_register(&rtc_miscdev); ++ if (ret == 0) ++ create_proc_read_entry("driver/rtc", 0, 0, ++ rtc_read_proc, ops); ++ } ++ up(&rtc_sem); ++ ++ return ret; ++} ++ ++void unregister_rtc(struct rtc_ops *rtc) ++{ ++ down(&rtc_sem); ++ if (rtc == rtc_ops) { ++ remove_proc_entry("driver/rtc", NULL); ++ misc_deregister(&rtc_miscdev); ++ rtc_ops = NULL; ++ } ++ up(&rtc_sem); ++} ++ ++EXPORT_SYMBOL(rtc_time_to_tm); ++EXPORT_SYMBOL(rtc_tm_to_time); ++EXPORT_SYMBOL(rtc_update); ++EXPORT_SYMBOL(register_rtc); ++EXPORT_SYMBOL(unregister_rtc); +--- linux-2.6.5/arch/arm/common/Makefile~heh 2004-04-03 22:36:57.000000000 -0500 ++++ linux-2.6.5/arch/arm/common/Makefile 2004-04-30 20:57:36.000000000 -0400 +@@ -2,7 +2,7 @@ + # Makefile for the linux kernel. + # + +-obj-y += platform.o ++obj-y += platform.o rtctime.o + obj-$(CONFIG_ARM_AMBA) += amba.o + obj-$(CONFIG_ICST525) += icst525.o + obj-$(CONFIG_SA1111) += sa1111.o sa1111-pcibuf.o +--- linux-2.6.5/arch/arm/mach-pxa/generic.c~heh 2004-04-03 22:36:53.000000000 -0500 ++++ linux-2.6.5/arch/arm/mach-pxa/generic.c 2004-04-30 20:57:36.000000000 -0400 +@@ -132,7 +132,7 @@ + /* virtual physical length type */ + { 0xf6000000, 0x20000000, 0x01000000, MT_DEVICE }, /* PCMCIA0 IO */ + { 0xf7000000, 0x30000000, 0x01000000, MT_DEVICE }, /* PCMCIA1 IO */ +- { 0xf8000000, 0x40000000, 0x01400000, MT_DEVICE }, /* Devs */ ++ { 0xf8000000, 0x40000000, 0x01800000, MT_DEVICE }, /* Devs */ + { 0xfa000000, 0x44000000, 0x00100000, MT_DEVICE }, /* LCD */ + { 0xfc000000, 0x48000000, 0x00100000, MT_DEVICE }, /* Mem Ctl */ + { 0xff000000, 0x00000000, 0x00100000, MT_DEVICE } /* UNCACHED_PHYS_0 */ +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-pxa/cpu-pxa.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,322 @@ ++/* ++ * linux/arch/arm/mach-pxa/cpu-pxa.c ++ * ++ * Copyright (C) 2002,2003 Intrinsyc Software ++ * ++ * 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 ++ * ++ * History: ++ * 31-Jul-2002 : Initial version [FB] ++ * 29-Jan-2003 : added PXA255 support [FB] ++ * 20-Apr-2003 : ported to v2.5 (Dustin McIntire, Sensoria Corp.) ++ * ++ * Note: ++ * This driver may change the memory bus clock rate, but will not do any ++ * platform specific access timing changes... for example if you have flash ++ * memory connected to CS0, you will need to register a platform specific ++ * notifier which will adjust the memory access strobes to maintain a ++ * minimum strobe width. ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/sched.h> ++#include <linux/init.h> ++#include <linux/cpufreq.h> ++ ++#include <asm/hardware.h> ++ ++#define DEBUG 0 ++ ++#ifdef DEBUG ++ static unsigned int freq_debug = DEBUG; ++ MODULE_PARM(freq_debug, "i"); ++ MODULE_PARM_DESC(freq_debug, "Set the debug messages to on=1/off=0"); ++#else ++ #define freq_debug 0 ++#endif ++ ++typedef struct ++{ ++ unsigned int khz; ++ unsigned int membus; ++ unsigned int cccr; ++ unsigned int div2; ++} pxa_freqs_t; ++ ++/* Define the refresh period in mSec for the SDRAM and the number of rows */ ++#define SDRAM_TREF 64 /* standard 64ms SDRAM */ ++#define SDRAM_ROWS 4096 /* 64MB=8192 32MB=4096 */ ++#define MDREFR_DRI(x) ((x*SDRAM_TREF)/(SDRAM_ROWS*32)) ++ ++#define CCLKCFG_TURBO 0x1 ++#define CCLKCFG_FCS 0x2 ++#define PXA25x_MIN_FREQ 99500 ++#define PXA25x_MAX_FREQ 398100 ++#define MDREFR_DB2_MASK (MDREFR_K2DB2 | MDREFR_K1DB2) ++#define MDREFR_DRI_MASK 0xFFF ++ ++ ++/* Use the run mode frequencies for the CPUFREQ_POLICY_PERFORMANCE policy */ ++static pxa_freqs_t pxa255_run_freqs[] = ++{ ++ /* CPU MEMBUS CCCR DIV2*/ ++ { 99500, 99500, 0x121, 1}, /* run= 99, turbo= 99, PXbus=50, SDRAM=50 */ ++ {132700, 132700, 0x123, 1}, /* run=133, turbo=133, PXbus=66, SDRAM=66 */ ++ {199100, 99500, 0x141, 0}, /* run=199, turbo=199, PXbus=99, SDRAM=99 */ ++ {265400, 132700, 0x143, 1}, /* run=265, turbo=265, PXbus=133, SDRAM=66 */ ++ {331800, 165900, 0x145, 1}, /* run=331, turbo=331, PXbus=166, SDRAM=83 */ ++ {398100, 99500, 0x161, 0}, /* run=398, turbo=398, PXbus=196, SDRAM=99 */ ++ {0,} ++}; ++#define NUM_RUN_FREQS (sizeof(pxa255_run_freqs)/sizeof(pxa_freqs_t)) ++ ++static struct cpufreq_frequency_table pxa255_run_freq_table[NUM_RUN_FREQS+1]; ++ ++/* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */ ++static pxa_freqs_t pxa255_turbo_freqs[] = ++{ ++ /* CPU MEMBUS CCCR DIV2*/ ++ { 99500, 99500, 0x121, 1}, /* run=99, turbo= 99, PXbus=50, SDRAM=50 */ ++ {199100, 99500, 0x221, 0}, /* run=99, turbo=199, PXbus=50, SDRAM=99 */ ++ {298500, 99500, 0x321, 0}, /* run=99, turbo=287, PXbus=50, SDRAM=99 */ ++ {298600, 99500, 0x1c1, 0}, /* run=199, turbo=287, PXbus=99, SDRAM=99 */ ++ {398100, 99500, 0x241, 0}, /* run=199, turbo=398, PXbus=99, SDRAM=99 */ ++ {0,} ++}; ++#define NUM_TURBO_FREQS (sizeof(pxa255_turbo_freqs)/sizeof(pxa_freqs_t)) ++ ++static struct cpufreq_frequency_table pxa255_turbo_freq_table[NUM_TURBO_FREQS+1]; ++ ++/* find a valid frequency point */ ++static int pxa_verify_policy(struct cpufreq_policy *policy) ++{ ++ int ret; ++ struct cpufreq_frequency_table *pxa_freqs_table; ++ ++ if(policy->policy == CPUFREQ_POLICY_PERFORMANCE) { ++ pxa_freqs_table = pxa255_run_freq_table; ++ } else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) { ++ pxa_freqs_table = pxa255_turbo_freq_table; ++ } else if (policy->policy == CPUFREQ_POLICY_GOVERNOR) { ++ pxa_freqs_table = pxa255_run_freq_table; ++ } else { ++ printk("CPU PXA: Unknown policy found. " ++ "Using CPUFREQ_POLICY_PERFORMANCE\n"); ++ pxa_freqs_table = pxa255_run_freq_table; ++ } ++ ret=cpufreq_frequency_table_verify(policy, pxa_freqs_table); ++ ++ if(freq_debug) { ++ printk("Verified CPU policy: %dKhz min to %dKhz max\n", ++ policy->min, policy->max); ++ } ++ ++ return ret; ++} ++ ++static int pxa_set_target(struct cpufreq_policy *policy, ++ unsigned int target_freq, ++ unsigned int relation) ++{ ++ int idx; ++ unsigned long cpus_allowed; ++ int cpu = policy->cpu; ++ struct cpufreq_freqs freqs; ++ pxa_freqs_t *pxa_freq_settings; ++ struct cpufreq_frequency_table *pxa_freqs_table; ++ unsigned long flags; ++ unsigned int unused; ++ unsigned int preset_mdrefr, postset_mdrefr; ++ ++ /* ++ * Save this threads cpus_allowed mask. ++ */ ++ cpus_allowed = current->cpus_allowed; ++ ++ /* ++ * Bind to the specified CPU. When this call returns, ++ * we should be running on the right CPU. ++ */ ++ set_cpus_allowed(current, 1 << cpu); ++ BUG_ON(cpu != smp_processor_id()); ++ ++ /* Get the current policy */ ++ if(policy->policy == CPUFREQ_POLICY_PERFORMANCE) { ++ pxa_freq_settings = pxa255_run_freqs; ++ pxa_freqs_table = pxa255_run_freq_table; ++ }else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) { ++ pxa_freq_settings = pxa255_turbo_freqs; ++ pxa_freqs_table = pxa255_turbo_freq_table; ++ }else if (policy->policy == CPUFREQ_POLICY_GOVERNOR) { ++ pxa_freq_settings = pxa255_run_freqs; ++ pxa_freqs_table = pxa255_run_freq_table; ++ }else { ++ printk("CPU PXA: Unknown policy found. " ++ "Using CPUFREQ_POLICY_PERFORMANCE\n"); ++ pxa_freq_settings = pxa255_run_freqs; ++ pxa_freqs_table = pxa255_run_freq_table; ++ } ++ ++ /* Lookup the next frequency */ ++ if (cpufreq_frequency_table_target(policy, pxa_freqs_table, ++ target_freq, relation, &idx)) { ++ return -EINVAL; ++ } ++ ++ freqs.old = policy->cur; ++ freqs.new = pxa_freq_settings[idx].khz; ++ freqs.cpu = policy->cpu; ++ if(freq_debug) { ++ printk(KERN_INFO "Changing CPU frequency to %d Mhz, (SDRAM %d Mhz)\n", ++ freqs.new/1000, (pxa_freq_settings[idx].div2) ? ++ (pxa_freq_settings[idx].membus/2000) : ++ (pxa_freq_settings[idx].membus/1000)); ++ } ++ ++ void *ramstart = phys_to_virt(0xa0000000); ++ ++ /* ++ * Tell everyone what we're about to do... ++ * you should add a notify client with any platform specific ++ * Vcc changing capability ++ */ ++ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); ++ ++ /* Calculate the next MDREFR. If we're slowing down the SDRAM clock ++ * we need to preset the smaller DRI before the change. If we're speeding ++ * up we need to set the larger DRI value after the change. ++ */ ++ preset_mdrefr = postset_mdrefr = MDREFR; ++ if((MDREFR & MDREFR_DRI_MASK) > MDREFR_DRI(pxa_freq_settings[idx].membus)) { ++ preset_mdrefr = (preset_mdrefr & ~MDREFR_DRI_MASK) | ++ MDREFR_DRI(pxa_freq_settings[idx].membus); ++ } ++ postset_mdrefr = (postset_mdrefr & ~MDREFR_DRI_MASK) | ++ MDREFR_DRI(pxa_freq_settings[idx].membus); ++ ++ /* If we're dividing the memory clock by two for the SDRAM clock, this ++ * must be set prior to the change. Clearing the divide must be done ++ * after the change. ++ */ ++ if(pxa_freq_settings[idx].div2) { ++ preset_mdrefr |= MDREFR_DB2_MASK; ++ postset_mdrefr |= MDREFR_DB2_MASK; ++ } else { ++ postset_mdrefr &= ~MDREFR_DB2_MASK; ++ } ++ ++ local_irq_save(flags); ++ ++ /* Set new the CCCR */ ++ CCCR = pxa_freq_settings[idx].cccr; ++ ++ __asm__ __volatile__(" \ ++ ldr r4, [%1] ; /* load MDREFR */ \ ++ b 2f ; \ ++ .align 5 ; \ ++1: \ ++ str %4, [%1] ; /* preset the MDREFR */ \ ++ mcr p14, 0, %2, c6, c0, 0 ; /* set CCLKCFG[FCS] */ \ ++ str %5, [%1] ; /* postset the MDREFR */ \ ++ \ ++ b 3f ; \ ++2: b 1b ; \ ++3: nop ; \ ++ " ++ : "=&r" (unused) ++ : "r" (&MDREFR), "r" (CCLKCFG_TURBO|CCLKCFG_FCS), "r" (ramstart), \ ++ "r" (preset_mdrefr), "r" (postset_mdrefr) ++ : "r4", "r5"); ++ local_irq_restore(flags); ++ ++ /* ++ * Restore the CPUs allowed mask. ++ */ ++ set_cpus_allowed(current, cpus_allowed); ++ ++ /* ++ * Tell everyone what we've just done... ++ * you should add a notify client with any platform specific ++ * SDRAM refresh timer adjustments ++ */ ++ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); ++ ++ return 0; ++} ++ ++static int pxa_cpufreq_init(struct cpufreq_policy *policy) ++{ ++ unsigned long cpus_allowed; ++ unsigned int cpu = policy->cpu; ++ int i; ++ ++ cpus_allowed = current->cpus_allowed; ++ ++ set_cpus_allowed(current, 1 << cpu); ++ BUG_ON(cpu != smp_processor_id()); ++ ++ /* set default policy and cpuinfo */ ++ policy->policy = CPUFREQ_POLICY_PERFORMANCE; ++ policy->cpuinfo.max_freq = PXA25x_MAX_FREQ; ++ policy->cpuinfo.min_freq = PXA25x_MIN_FREQ; ++ policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */ ++ policy->cur = get_clk_frequency_khz(0); /* current freq */ ++ policy->min = policy->max = policy->cur; ++ ++ /* Generate the run cpufreq_frequency_table struct */ ++ for(i=0;i<NUM_RUN_FREQS;i++) { ++ pxa255_run_freq_table[i].frequency = pxa255_run_freqs[i].khz; ++ pxa255_run_freq_table[i].index = i; ++ } ++ pxa255_run_freq_table[i].frequency = CPUFREQ_TABLE_END; ++ /* Generate the turbo cpufreq_frequency_table struct */ ++ for(i=0;i<NUM_TURBO_FREQS;i++) { ++ pxa255_turbo_freq_table[i].frequency = pxa255_turbo_freqs[i].khz; ++ pxa255_turbo_freq_table[i].index = i; ++ } ++ pxa255_turbo_freq_table[i].frequency = CPUFREQ_TABLE_END; ++ ++ set_cpus_allowed(current, cpus_allowed); ++ printk(KERN_INFO "PXA CPU frequency change support initialized\n"); ++ ++ return 0; ++} ++ ++static struct cpufreq_driver pxa_cpufreq_driver = { ++ .verify = pxa_verify_policy, ++ .target = pxa_set_target, ++ .init = pxa_cpufreq_init, ++ .name = "PXA25x", ++}; ++ ++static int __init pxa_cpu_init(void) ++{ ++ return cpufreq_register_driver(&pxa_cpufreq_driver); ++} ++ ++static void __exit pxa_cpu_exit(void) ++{ ++ cpufreq_unregister_driver(&pxa_cpufreq_driver); ++} ++ ++ ++MODULE_AUTHOR ("Intrinsyc Software Inc."); ++MODULE_DESCRIPTION ("CPU frequency changing driver for the PXA architecture"); ++MODULE_LICENSE("GPL"); ++module_init(pxa_cpu_init); ++module_exit(pxa_cpu_exit); ++ +--- linux-2.6.5/arch/arm/boot/compressed/misc.c~heh 2004-04-03 22:37:37.000000000 -0500 ++++ linux-2.6.5/arch/arm/boot/compressed/misc.c 2004-04-30 20:57:36.000000000 -0400 +@@ -113,7 +113,7 @@ + * gzip delarations + */ + #define OF(args) args +-#define STATIC static ++#define STATIC + + typedef unsigned char uch; + typedef unsigned short ush; +@@ -122,12 +122,12 @@ + #define WSIZE 0x8000 /* Window size must be at least 32k, */ + /* and a power of two */ + +-static uch *inbuf; /* input buffer */ +-static uch window[WSIZE]; /* Sliding window buffer */ ++unsigned char *inbuf; /* input buffer */ ++unsigned char window[WSIZE]; /* Sliding window buffer */ + +-static unsigned insize; /* valid bytes in inbuf */ +-static unsigned inptr; /* index of next byte to be processed in inbuf */ +-static unsigned outcnt; /* bytes in output buffer */ ++unsigned int insize; /* valid bytes in inbuf */ ++unsigned int inptr; /* index of next byte to be processed in inbuf */ ++unsigned int outcnt; /* bytes in output buffer */ + + /* gzip flag byte */ + #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +@@ -166,9 +166,9 @@ + extern char input_data[]; + extern char input_data_end[]; + +-static uch *output_data; +-static ulg output_ptr; +-static ulg bytes_out; ++unsigned char *output_data; ++unsigned long output_ptr; ++unsigned long bytes_out; + + static void *malloc(int size); + static void free(void *where); +@@ -179,8 +179,8 @@ + static void puts(const char *); + + extern int end; +-static ulg free_mem_ptr; +-static ulg free_mem_ptr_end; ++unsigned long free_mem_ptr; ++unsigned long free_mem_ptr_end; + + #define HEAP_SIZE 0x2000 + +--- linux-2.6.5/arch/arm/mm/ioremap.c~heh 2004-04-03 22:37:36.000000000 -0500 ++++ linux-2.6.5/arch/arm/mm/ioremap.c 2004-04-30 20:57:36.000000000 -0400 +@@ -13,15 +13,18 @@ + * virtual space. One should *only* use readl, writel, memcpy_toio and + * so on with such remapped areas. + * +- * Because the ARM only has a 32-bit address space we can't address the +- * whole of the (physical) PCI space at once. PCI huge-mode addressing +- * allows us to circumvent this restriction by splitting PCI space into +- * two 2GB chunks and mapping only one at a time into processor memory. +- * We use MMU protection domains to trap any attempt to access the bank +- * that is not currently mapped. (This isn't fully implemented yet.) ++ * ioremap support tweaked to allow support for large page mappings. We ++ * have several issues that needs to be resolved first however: ++ * ++ * 1. We need set_pte, or something like set_pte to understand large ++ * page mappings. ++ * ++ * 2. we need the unmap_* functions to likewise understand large page ++ * mappings. + */ + #include <linux/errno.h> + #include <linux/mm.h> ++#include <linux/slab.h> + #include <linux/vmalloc.h> + + #include <asm/page.h> +@@ -29,31 +32,162 @@ + #include <asm/io.h> + #include <asm/tlbflush.h> + +-static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, +- unsigned long phys_addr, pgprot_t pgprot) ++extern rwlock_t vmlist_lock; ++extern struct vm_struct *vmlist; ++ ++static struct vm_struct * ++get_io_vm_area(unsigned long size, unsigned long align, unsigned long flags) + { ++ struct vm_struct **p, *tmp, *area; ++ unsigned long addr; ++ ++ area = (struct vm_struct *)kmalloc(sizeof(*area), GFP_KERNEL); ++ if (!area) ++ return NULL; ++ ++ align -= 1; ++ ++ size += PAGE_SIZE; ++ addr = VMALLOC_START; ++ write_lock(&vmlist_lock); ++ for (p = &vmlist; (tmp = *p); p = &tmp->next) { ++ if ((unsigned long)tmp->addr < addr) ++ continue; ++ if ((size + addr) < addr) ++ goto out; ++ if (size + addr <= (unsigned long) tmp->addr) ++ break; ++ addr = tmp->size + (unsigned long) tmp->addr; ++ if ((addr + align) < addr) ++ goto out; ++ addr = (addr + align) & ~align; ++ if (addr > VMALLOC_END - size) ++ goto out; ++ } ++ area->flags = flags; ++ area->addr = (void *)addr; ++ area->size = size; ++ area->next = *p; ++ *p = area; ++ write_unlock(&vmlist_lock); ++ return area; ++ ++out: ++ write_unlock(&vmlist_lock); ++ kfree(area); ++ return NULL; ++} ++ ++static inline void unmap_area_pte(pmd_t *pmd, unsigned long address, unsigned long size) ++{ ++ pte_t *ptep; + unsigned long end; + ++ if (pmd_none(*pmd)) ++ return; ++ if (pmd_bad(*pmd)) { ++ pmd_ERROR(*pmd); ++ pmd_clear(pmd); ++ return; ++ } ++ ptep = pte_offset_kernel(pmd, address); + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; +- if (address >= end) +- BUG(); + do { +- if (!pte_none(*pte)) { +- printk("remap_area_pte: page already exists\n"); +- BUG(); ++ pte_t pte; ++ pte = ptep_get_and_clear(ptep); ++ address += PAGE_SIZE; ++ ptep++; ++ if (pte_none(pte)) ++ continue; ++ if (pte_present(pte)) { ++ unsigned long pfn = pte_pfn(pte); ++ struct page *page; ++ ++ if (!pfn_valid(pfn)) ++ continue; ++ page = pfn_to_page(pfn); ++ if (!PageReserved(page)) ++ __free_page(page); ++ continue; + } +- set_pte(pte, pfn_pte(phys_addr >> PAGE_SHIFT, pgprot)); ++ printk(KERN_CRIT "Whee.. Swapped out page in kernel page table\n"); ++ } while (address < end); ++} ++ ++static inline void unmap_area_pmd(pgd_t *dir, unsigned long address, unsigned long size) ++{ ++ pmd_t *pmd; ++ unsigned long end; ++ ++ if (pgd_none(*dir)) ++ return; ++ if (pgd_bad(*dir)) { ++ pgd_ERROR(*dir); ++ pgd_clear(dir); ++ return; ++ } ++ pmd = pmd_offset(dir, address); ++ address &= ~PGDIR_MASK; ++ end = address + size; ++ if (end > PGDIR_SIZE) ++ end = PGDIR_SIZE; ++ do { ++ unmap_area_pte(pmd, address, end - address); ++ address = (address + PMD_SIZE) & PMD_MASK; ++ pmd++; ++ } while (address < end); ++} ++ ++static void ++unmap_area_pages(unsigned long address, unsigned long size) ++{ ++ unsigned long start = address; ++ unsigned long end = address + size; ++ pgd_t *dir; ++ ++ dir = pgd_offset_k(address); ++ flush_cache_vunmap(start, end); ++ do { ++ unmap_area_pmd(dir, address, end - address); ++ address = (address + PGDIR_SIZE) & PGDIR_MASK; ++ dir++; ++ } while (address && (address < end)); ++ flush_tlb_kernel_range(start, end); ++} ++ ++static inline void ++remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, ++ unsigned long pfn, pgprot_t pgprot) ++{ ++ unsigned long end; ++ ++ address &= ~PMD_MASK; ++ end = address + size; ++ if (end > PMD_SIZE) ++ end = PMD_SIZE; ++ BUG_ON(address >= end); ++ do { ++ if (!pte_none(*pte)) ++ goto bad; ++ ++ set_pte(pte, pfn_pte(pfn, pgprot)); + address += PAGE_SIZE; +- phys_addr += PAGE_SIZE; ++ pfn++; + pte++; + } while (address && (address < end)); ++ return; ++ ++ bad: ++ printk("remap_area_pte: page already exists\n"); ++ BUG(); + } + +-static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, +- unsigned long phys_addr, unsigned long flags) ++static inline int ++remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, ++ unsigned long pfn, unsigned long flags) + { + unsigned long end; + pgprot_t pgprot; +@@ -64,51 +198,53 @@ + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + +- phys_addr -= address; +- if (address >= end) +- BUG(); ++ pfn -= address >> PAGE_SHIFT; ++ BUG_ON(address >= end); + + pgprot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE | flags); + do { + pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address); + if (!pte) + return -ENOMEM; +- remap_area_pte(pte, address, end - address, address + phys_addr, pgprot); ++ remap_area_pte(pte, address, end - address, pfn + (address >> PAGE_SHIFT), pgprot); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address && (address < end)); + return 0; + } + +-static int remap_area_pages(unsigned long address, unsigned long phys_addr, +- unsigned long size, unsigned long flags) ++static int ++remap_area_pages(unsigned long start, unsigned long pfn, ++ unsigned long size, unsigned long flags) + { +- int error; ++ unsigned long address = start; ++ unsigned long end = start + size; ++ int err = 0; + pgd_t * dir; +- unsigned long end = address + size; + +- phys_addr -= address; ++ pfn -= address >> PAGE_SHIFT; + dir = pgd_offset(&init_mm, address); +- flush_cache_all(); +- if (address >= end) +- BUG(); ++ BUG_ON(address >= end); + spin_lock(&init_mm.page_table_lock); + do { +- pmd_t *pmd; +- pmd = pmd_alloc(&init_mm, dir, address); +- error = -ENOMEM; +- if (!pmd) ++ pmd_t *pmd = pmd_alloc(&init_mm, dir, address); ++ if (!pmd) { ++ err = -ENOMEM; + break; ++ } + if (remap_area_pmd(pmd, address, end - address, +- phys_addr + address, flags)) ++ pfn + (address >> PAGE_SHIFT), flags)) { ++ err = -ENOMEM; + break; +- error = 0; ++ } ++ + address = (address + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } while (address && (address < end)); ++ + spin_unlock(&init_mm.page_table_lock); +- flush_tlb_all(); +- return error; ++ flush_cache_vmap(start, end); ++ return err; + } + + /* +@@ -146,11 +282,11 @@ + /* + * Ok, go for it.. + */ +- area = get_vm_area(size, VM_IOREMAP); ++ area = get_io_vm_area(size, align, VM_IOREMAP); + if (!area) + return NULL; + addr = area->addr; +- if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) { ++ if (remap_area_pages((unsigned long) addr, phys_addr >> PAGE_SHIFT, size, flags)) { + vfree(addr); + return NULL; + } +@@ -159,5 +295,26 @@ + + void __iounmap(void *addr) + { +- vfree((void *) (PAGE_MASK & (unsigned long) addr)); ++ struct vm_struct **p, *tmp; ++ ++ if (!addr) ++ return; ++ ++ if ((PAGE_SIZE - 1) & (unsigned long)addr) { ++ printk(KERN_ERR "Trying to iounmap() bad address (%p)\n", addr); ++ return; ++ } ++ ++ write_lock(&vmlist_lock); ++ for (p = &vmlist; (tmp = *p); p = &tmp->next) { ++ if (tmp->addr == addr) { ++ *p = tmp->next; ++ unmap_area_pages((unsigned long) tmp->addr, tmp->size); ++ write_unlock(&vmlist_lock); ++ kfree(tmp); ++ return; ++ } ++ } ++ write_unlock(&vmlist_lock); ++ printk(KERN_ERR "Trying to iounmap nonexistent area (%p)\n", addr); + } +--- linux-2.6.5/arch/arm/mm/proc-xscale.S~heh 2004-04-03 22:38:05.000000000 -0500 ++++ linux-2.6.5/arch/arm/mm/proc-xscale.S 2004-04-30 20:57:36.000000000 -0400 +@@ -563,11 +563,62 @@ + movne r2, #0 @ no -> fault + + str r2, [r0] @ hardware version ++ ++ @ We try to map 64K page entries when possible. ++ @ We do that for kernel space only since the usage pattern from ++ @ the setting of VM area is quite simple. User space is not worth ++ @ the implied complexity because of ever randomly changing PTEs ++ @ (page aging, swapout, etc) requiring constant coherency checks. ++ @ Since PTEs are usually set in increasing order, we test the ++ @ possibility for a large page only when given the last PTE of a ++ @ 64K boundary. ++ tsteq r1, #L_PTE_USER ++ andeq r1, r0, #(15 << 2) ++ teqeq r1, #(15 << 2) ++ beq 1f ++ + mov ip, #0 + mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line + mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer + mov pc, lr + ++ @ See if we have 16 identical PTEs but with consecutive base addresses ++1: bic r3, r2, #0x0000f000 ++ mov r1, #0x0000f000 ++2: eor r2, r2, r3 ++ teq r2, r1 ++ bne 4f ++ subs r1, r1, #0x00001000 ++ ldr r2, [r0, #-4]! ++ bne 2b ++ eors r2, r2, r3 ++ bne 4f ++ ++ @ Now create our LARGE PTE from the current EXT one. ++ bic r3, r3, #PTE_TYPE_MASK ++ orr r3, r3, #PTE_TYPE_LARGE ++ and r2, r3, #0x30 @ EXT_AP --> LARGE_AP0 ++ orr r2, r2, r2, lsl #2 @ add LARGE_AP1 ++ orr r2, r2, r2, lsl #4 @ add LARGE_AP3 + LARGE_AP2 ++ and r1, r3, #0x3c0 @ EXT_TEX ++ bic r3, r3, #0x3c0 ++ orr r2, r2, r1, lsl #(12 - 6) @ --> LARGE_TEX ++ orr r2, r2, r3 @ add remaining bits ++ ++ @ then put it in the pagetable ++ mov r3, r2 ++3: strd r2, [r0], #8 ++ tst r0, #(15 << 2) ++ bne 3b ++ ++ @ Then sync the 2 corresponding cache lines ++ sub r0, r0, #(16 << 2) ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++4: orr r0, r0, #(15 << 2) ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ mov ip, #0 ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov pc, lr + + .ltorg + +--- linux-2.6.5/arch/arm/mach-sa1100/Makefile~heh 2004-04-03 22:38:26.000000000 -0500 ++++ linux-2.6.5/arch/arm/mach-sa1100/Makefile 2004-04-30 20:57:36.000000000 -0400 +@@ -3,7 +3,7 @@ + # + + # Common support +-obj-y := generic.o irq.o dma.o ++obj-y := generic.o irq.o dma.o nmi-oopser.o + obj-m := + obj-n := + obj- := +@@ -88,7 +88,7 @@ + obj-$(CONFIG_LEDS) += $(led-y) + + # SA1110 USB client support +-#obj-$(CONFIG_SA1100_USB) += usb/ ++obj-$(CONFIG_SA1100_USB) += usb/ + + # Miscelaneous functions + obj-$(CONFIG_PM) += pm.o sleep.o +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-sa1100/usb/strings.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,43 @@ ++/* ++ * usb/strings.h ++ * ++ * Copyright (C) 2002 Russell King. ++ * ++ * USB device string handling, built upon usb buffers. ++ */ ++#ifndef USBDEV_STRINGS_H ++#define USBDEV_STRINGS_H ++ ++#include <linux/spinlock.h> ++ ++struct usb_buf; ++ ++#define NR_STRINGS 8 ++ ++struct usb_string_descriptor; ++ ++struct usbc_strs { ++ spinlock_t lock; ++ struct usb_buf *buf[NR_STRINGS]; ++}; ++ ++#define usbc_string_desc(buf) ((struct usb_string_descriptor *)(buf)->data) ++ ++void usbc_string_from_cstr(struct usb_buf *buf, const char *str); ++struct usb_buf *usbc_string_alloc(int len); ++void usbc_string_free(struct usb_buf *buf); ++ ++int usbc_string_add(struct usbc_strs *table, struct usb_buf *buf); ++void usbc_string_del(struct usbc_strs *table, int nr); ++ ++/* ++ * Note: usbc_string_find() increments the buffer use count. ++ * You must call usbb_put() after use. ++ */ ++struct usb_buf * ++usbc_string_find(struct usbc_strs *table, unsigned int lang, unsigned int idx); ++ ++void usbc_string_free_all(struct usbc_strs *table); ++void usbc_string_init(struct usbc_strs *table); ++ ++#endif +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb_ctl.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,114 @@ ++/* ++ * 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 <asm/dma.h> /* dmach_t */ ++ ++struct usb_client; ++ ++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 ++{ ++ struct usb_client *client; ++ dma_regs_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 */ ++int ep1_recv(void); ++int ep1_init(dma_regs_t *dma); ++void ep1_int_hndlr(int status); ++void ep1_reset(void); ++void ep1_stall(void); ++ ++/* xmitter */ ++void ep2_reset(void); ++int ep2_init(dma_regs_t *dma); ++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 */ +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb_send.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,302 @@ ++/* ++ * 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 <linux/module.h> ++#include <linux/pci.h> ++#include <linux/errno.h> ++#include <linux/delay.h> // for the massive_attack hack 28Feb01ww ++#include <linux/usb_ch9.h> ++ ++#include <asm/dma.h> ++ ++#include "usbdev.h" ++#include "sa1100_usb.h" ++#include "sa1100usb.h" ++ ++static unsigned int ep2_curdmalen; ++static unsigned int ep2_remain; ++ ++static struct sausb_dev *ep2_dev; ++ ++static void udc_set_cs2(u32 val, u32 mask, u32 check) ++{ ++ int i = 0; ++ ++ do { ++ Ser0UDCCS2 = val; ++ udelay(1); ++ if ((Ser0UDCCS2 & mask) == check) ++ return; ++ } while (i++ < 10000); ++ ++ printk("UDC: UDCCS2 write timed out: val=0x%08x\n", val); ++} ++ ++/* set feature stall executing, async */ ++static void ep2_start(struct sausb_dev *usb) ++{ ++ ep2_curdmalen = min(ep2_remain, usb->ep[1].maxpktsize); ++ if (ep2_curdmalen == 0) ++ return; ++ ++ /* ++ * must do this _before_ queue buffer.. ++ * stop NAKing IN tokens ++ */ ++ udc_set_cs2(usb->ep[1].udccs | UDCCS2_TPC, UDCCS2_TPC, 0); ++ ++ 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 */ ++ ++ /* ++ * fight stupid silicon bug ++ */ ++ Ser0UDCAR = usb->ctl->address; ++ ++ sa1100_start_dma(usb->ep[1].dmach, usb->ep[1].pktdma, ep2_curdmalen); ++} ++ ++static void udc_ep2_done(struct sausb_dev *usb, int flag) ++{ ++ int size = usb->ep[1].buflen - ep2_remain; ++ ++ if (!usb->ep[1].buflen) ++ return; ++ ++ dma_unmap_single(usb->dev, usb->ep[1].bufdma, usb->ep[1].buflen, ++ DMA_TO_DEVICE); ++ ++ usb->ep[1].bufdma = 0; ++ usb->ep[1].buflen = 0; ++ usb->ep[1].pktdma = 0; ++ ++ if (usb->ep[1].cb_func) ++ usb->ep[1].cb_func(usb->ep[1].cb_data, flag, size); ++} ++ ++/* ++ * Initialisation. Clear out the status. ++ */ ++void udc_ep2_init(struct sausb_dev *usb) ++{ ++ ep2_dev = usb; ++ ++ usb->ep[1].udccs = UDCCS2_FST; ++ ++ BUG_ON(usb->ep[1].buflen); ++ BUG_ON(usb->ep[1].pktlen); ++ ++ sa1100_reset_dma(usb->ep[1].dmach); ++} ++ ++/* ++ * Note: rev A0-B2 chips don't like FST ++ */ ++void udc_ep2_halt(struct sausb_dev *usb, int halt) ++{ ++ usb->ep[1].host_halt = halt; ++ ++ if (halt) { ++ usb->ep[1].udccs |= UDCCS2_FST; ++ udc_set_cs2(UDCCS2_FST, UDCCS2_FST, UDCCS2_FST); ++ } else { ++ sa1100_clear_dma(usb->ep[1].dmach); ++ ++ udc_set_cs2(UDCCS2_FST, UDCCS2_FST, UDCCS2_FST); ++ udc_set_cs2(0, UDCCS2_FST, 0); ++ udc_set_cs2(UDCCS2_SST, UDCCS2_SST, 0); ++ ++ usb->ep[1].udccs &= ~UDCCS2_FST; ++ ++ udc_ep2_done(usb, -EINTR); ++ } ++} ++ ++/* ++ * This gets called when we receive a SET_CONFIGURATION packet to EP0. ++ * We were configured. We can now send packets to the host. ++ */ ++void udc_ep2_config(struct sausb_dev *usb, unsigned int maxpktsize) ++{ ++ /* ++ * We shouldn't be transmitting anything... ++ */ ++ BUG_ON(usb->ep[1].buflen); ++ BUG_ON(usb->ep[1].pktlen); ++ ++ /* ++ * Set our configuration. ++ */ ++ usb->ep[1].maxpktsize = maxpktsize; ++ usb->ep[1].configured = 1; ++ ++ /* ++ * Clear any pending TPC status. ++ */ ++ udc_set_cs2(UDCCS2_TPC, UDCCS2_TPC, 0); ++ ++ /* ++ * Enable EP2 interrupts. ++ */ ++ usb->udccr &= ~UDCCR_TIM; ++ UDC_write(Ser0UDCCR, usb->udccr); ++ ++ usb->ep[1].udccs = 0; ++} ++ ++/* ++ * We saw a reset from the attached hub, or were deconfigured. ++ * This means we are no longer configured. ++ */ ++void udc_ep2_reset(struct sausb_dev *usb) ++{ ++ /* ++ * Disable EP2 interrupts. ++ */ ++ usb->udccr |= UDCCR_TIM; ++ UDC_write(Ser0UDCCR, usb->udccr); ++ ++ usb->ep[1].configured = 0; ++ usb->ep[1].maxpktsize = 0; ++ ++ sa1100_reset_dma(usb->ep[1].dmach); ++ udc_ep2_done(usb, -EINTR); ++} ++ ++void udc_ep2_int_hndlr(struct sausb_dev *usb) ++{ ++ u32 status = Ser0UDCCS2; ++ ++ // check for stupid silicon bug. ++ if (Ser0UDCAR != usb->ctl->address) ++ Ser0UDCAR = usb->ctl->address; ++ ++ udc_set_cs2(usb->ep[1].udccs | UDCCS2_SST, UDCCS2_SST, 0); ++ ++ if (!(status & UDCCS2_TPC)) { ++ printk("usb_send: Not TPC: UDCCS2 = %x\n", status); ++ return; ++ } ++ ++ sa1100_stop_dma(usb->ep[1].dmach); ++ ++ if (status & (UDCCS2_TPE | UDCCS2_TUR)) { ++ printk("usb_send: transmit error %x\n", status); ++ usb->ep[1].fifo_errs ++; ++ udc_ep2_done(usb, -EIO); ++ } else { ++ unsigned int imp; ++#if 1 // 22Feb01ww/Oleg ++ imp = ep2_curdmalen; ++#else ++ // this is workaround for case when setting ++ // of Ser0UDCIMP was failed ++ imp = Ser0UDCIMP + 1; ++#endif ++ usb->ep[1].pktdma += imp; ++ ep2_remain -= imp; ++ ++ usb->ep[1].bytes += imp; ++ usb->ep[1].packets++; ++ ++ sa1100_clear_dma(usb->ep[1].dmach); ++ ++ if (ep2_remain != 0) { ++ ep2_start(usb); ++ } else { ++ udc_ep2_done(usb, 0); ++ } ++ } ++} ++ ++int udc_ep2_send(struct sausb_dev *usb, char *buf, int len) ++{ ++ unsigned long flags; ++ dma_addr_t dma; ++ int ret; ++ ++ if (!buf || len == 0) ++ return -EINVAL; ++ ++ dma = dma_map_single(usb->dev, buf, len, DMA_TO_DEVICE); ++ ++ spin_lock_irqsave(&usb->lock, flags); ++ do { ++ if (!usb->ep[1].configured) { ++ ret = -ENODEV; ++ break; ++ } ++ ++ if (usb->ep[1].buflen) { ++ ret = -EBUSY; ++ break; ++ } ++ ++ usb->ep[1].bufdma = dma; ++ usb->ep[1].buflen = len; ++ usb->ep[1].pktdma = dma; ++ ep2_remain = len; ++ ++ sa1100_clear_dma(usb->ep[1].dmach); ++ ++ ep2_start(usb); ++ ret = 0; ++ } while (0); ++ spin_unlock_irqrestore(&usb->lock, flags); ++ ++ if (ret) ++ dma_unmap_single(usb->dev, dma, len, DMA_TO_DEVICE); ++ ++ return ret; ++} ++ ++void udc_ep2_send_reset(struct sausb_dev *usb) ++{ ++ sa1100_reset_dma(usb->ep[1].dmach); ++ udc_ep2_done(usb, -EINTR); ++} ++ ++int udc_ep2_idle(struct sausb_dev *usb) ++{ ++ if (!usb->ep[1].configured) ++ return -ENODEV; ++ ++ if (usb->ep[1].buflen) ++ return -EBUSY; ++ ++ return 0; ++} +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb-char.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,709 @@ ++/* ++ * (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 dma_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 <linux/module.h> ++#include <linux/config.h> ++#include <linux/miscdevice.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/cache.h> ++#include <linux/poll.h> ++#include <linux/circ_buf.h> ++#include <linux/timer.h> ++#include <linux/usb_ch9.h> ++ ++#include <asm/io.h> ++#include <asm/semaphore.h> ++#include <asm/page.h> ++#include <asm/mach-types.h> ++ ++#include "usb-char.h" ++#include "client.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(struct usb_client *client); ++static int usbc_open( struct inode *pInode, struct file *pFile ); ++static void rx_done_callback_packet_buffer(void *data, int flag, int size ); ++ ++static void tx_timeout( unsigned long ); ++static void tx_done_callback(void *data, 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(struct usb_client *client) ++{ ++ struct cdb *cdb = sa1100_usb_get_descriptor_ptr(); ++ ++ cdb->ep1.wMaxPacketSize = cpu_to_le16(RX_PACKET_SIZE); ++ cdb->ep2.wMaxPacketSize = cpu_to_le16(TX_PACKET_SIZE); ++ ++#ifdef CONFIG_SA1100_EXTENEX1 ++ if (machine_is_extenex1()) { ++ int nr; ++ ++ cdb->cfg.bmAttributes = USB_CONFIG_SELFPOWERED; ++ cdb->cfg.MaxPower = 0; ++ ++ nr = sa1100_usb_add_string(client->ctl, "HHT Bulk Transfer"); ++ ++ if (nr > 0) ++ cdb->intf.iInterface = nr; ++ } ++#endif ++} ++ ++////////////////////////////////////////////////////////////////////////////// ++// 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_set_callback(rx_done_callback_packet_buffer, NULL); ++ sa1100_usb_recv( packet_buffer, RX_PACKET_SIZE); ++ } ++ } ++} ++/* ++ * 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(void *data, 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(void *data, 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 ); ++} ++ ++ ++static struct usb_client usbc_client = { ++ .name = "usb-char", ++ ++ /* ++ * USB client identification for host use in CPU endian. ++ */ ++ .vendor = 0, ++ .product = 0, ++ .version = 0, ++ .class = 0xff, ++ .subclass = 0, ++ .protocol = 0, ++}; ++ ++#ifdef CONFIG_SA1100_EXTENEX1 ++#include "../../../drivers/char/ex_gpio.h" ++static void extenex_state_change(void *data, int state, int oldstate) ++{ ++ if (exgpio_play_string( "440,1:698,1") == -EAGAIN) ++ printk( "%sWanted to BEEP but ex_gpio not open\n", pszMe ); ++} ++#endif ++ ++////////////////////////////////////////////////////////////////////////////// ++// Workers ++////////////////////////////////////////////////////////////////////////////// ++ ++static int usbc_open(struct inode *pInode, struct file *pFile) ++{ ++ int retval = 0; ++ ++ PRINTK( KERN_DEBUG "%sopen()\n", pszMe ); ++ ++#ifdef CONFIG_SA1100_EXTENEX1 ++ if (machine_is_extenex1()) { ++ usbc_client.vendor = 0x0c9f; ++ usbc_client.product = 0x0100; ++ usbc_client.version = 0x0001; ++ usbc_client.manufacturer_str = "Extenex"; ++ usbc_client.product_str = "Handheld Theater"; ++ usbc_client.serial_str = "00000000"; ++ usbc_client.state_change = extenex_state_change; ++ } ++#endif ++ ++ /* start usb core */ ++ retval = usbctl_open(&usbc_client); ++ 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(&usbc_client); ++ ++ retval = usbctl_start(&usbc_client); ++ 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; ++ unsigned long 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; ++ sa1100_usb_send_set_callback(tx_done_callback, NULL); ++ retval = sa1100_usb_send( tx_buf, nThisTime); ++ 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 ); ++ usbctl_stop(&usbc_client); ++ free_txrx_buffers(); ++ del_timer( &tx_timer ); ++ usbctl_close(&usbc_client); ++ up(&xmit_sem); ++ } ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++////////////////////////////////////////////////////////////////////////////// ++// 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() ++ */ ++ ++static 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; ++} ++ ++static void __exit usbc_exit( void ) ++{ ++} ++ ++module_init(usbc_init); ++module_exit(usbc_exit); ++ ++// end: usb-char.c ++ ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb-eth.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,535 @@ ++/* ++ * Network 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. ++ * ++ * Issues: ++ * - DMA needs 8 byte aligned buffer, but causes inefficiencies ++ * in the IP code. ++ * - stall endpoint operations appeared to be very unstable. ++ */ ++ ++/* ++ * Define RX_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. ++ * ++ * Since the SA1100 DMA engine is unable to cope with unaligned ++ * buffer addresses, we need to use bounce buffers or suffer the ++ * alignment trap performance hit. ++ */ ++#undef RX_NO_COPY ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> ++#include <linux/random.h> ++#include <linux/usb_ch9.h> ++ ++#include "client.h" ++ ++ ++#define ETHERNET_VENDOR_ID 0x049f ++#define ETHERNET_PRODUCT_ID 0x505A ++#define MAX_PACKET 32768 ++ ++/* ++ * This is our usb "packet size", and must match the host "packet size". ++ */ ++static int usb_rsize = 64; ++static int usb_wsize = 64; ++ ++struct usbe_info { ++ struct net_device dev; ++ struct usb_client client; ++ struct sk_buff *cur_tx_skb; ++ struct sk_buff *next_tx_skb; ++ struct sk_buff *cur_rx_skb; ++ struct sk_buff *next_rx_skb; ++#ifndef RX_NO_COPY ++ char *dmabuf; // dma expects it's buffers to be aligned on 8 bytes boundary ++#endif ++ struct net_device_stats stats; ++}; ++ ++ ++static int usbeth_change_mtu(struct net_device *dev, 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; ++ ++ dev->mtu = new_mtu; ++ return 0; ++} ++ ++static struct sk_buff *usb_new_recv_skb(struct usbe_info *usbe) ++{ ++ struct sk_buff *skb; ++ ++ skb = alloc_skb(2 + sizeof(struct ethhdr) + usbe->dev.mtu, ++ GFP_ATOMIC); ++ ++ if (skb) ++ skb_reserve(skb, 2); ++ ++ return skb; ++} ++ ++static void usbeth_recv_callback(void *data, int flag, int len) ++{ ++ struct usbe_info *usbe = data; ++ struct sk_buff *skb; ++ unsigned int size; ++ char *buf; ++ ++ skb = usbe->cur_rx_skb; ++ ++ /* flag validation */ ++ if (flag != 0) ++ goto error; ++ ++ /* ++ * Make sure we have enough room left in the buffer. ++ */ ++ if (len > skb_tailroom(skb)) { ++ usbe->stats.rx_over_errors++; ++ usbe->stats.rx_errors++; ++ goto oversize; ++ } ++ ++ /* ++ * If the packet is smaller than usb_rsize bytes, the packet ++ * is complete, and we need to use the next receive buffer. ++ */ ++ if (len != usb_rsize) ++ usbe->cur_rx_skb = usbe->next_rx_skb; ++ ++ /* ++ * Put the data onto the socket buffer and resume USB receive. ++ */ ++#ifndef RX_NO_COPY ++ memcpy(skb_put(skb, len), usbe->dmabuf, len); ++ buf = usbe->dmabuf; ++ size = usb_rsize; ++#else ++ skb_put(skb, len); ++ buf = usbe->cur_rx_skb->tail; ++ size = skb_tailroom(usbe->cur_rx_skb); ++#endif ++ usbctl_ep_queue_buffer(usbe->client.ctl, 1, buf, size); ++ ++ if (len == usb_rsize) ++ return; ++ ++ /* ++ * A frame must contain at least an ethernet header. ++ */ ++ if (skb->len < sizeof(struct ethhdr)) { ++ usbe->stats.rx_length_errors++; ++ usbe->stats.rx_errors++; ++ goto recycle; ++ } ++ ++ /* ++ * MAC must match our address or the broadcast address. ++ * Really, we should let any packet through, otherwise ++ * things that rely on multicast won't work. ++ */ ++ if (memcmp(skb->data, usbe->dev.dev_addr, ETH_ALEN) && ++ memcmp(skb->data, usbe->dev.broadcast, ETH_ALEN)) { ++ usbe->stats.rx_frame_errors++; ++ usbe->stats.rx_errors++; ++ goto recycle; ++ } ++ ++ /* ++ * We're going to consume this SKB. Get a new skb to ++ * replace it with. IF this fails, we'd better recycle ++ * the one we have. ++ */ ++ usbe->next_rx_skb = usb_new_recv_skb(usbe); ++ if (!usbe->next_rx_skb) { ++ if (net_ratelimit()) ++ printk(KERN_ERR "%s: can't allocate new rx skb\n", ++ usbe->dev.name); ++ usbe->stats.rx_dropped++; ++ goto recycle; ++ } ++ ++// FIXME: eth_copy_and_csum "small" packets to new SKB (small < ~200 bytes) ? ++ ++ usbe->stats.rx_packets++; ++ usbe->stats.rx_bytes += skb->len; ++ usbe->dev.last_rx = jiffies; ++ ++ skb->dev = &usbe->dev; ++ skb->protocol = eth_type_trans(skb, &usbe->dev); ++ skb->ip_summed = CHECKSUM_NONE; ++ ++ if (netif_rx(skb) == NET_RX_DROP) ++ usbe->stats.rx_dropped++; ++ return; ++ ++ error: ++ /* ++ * Oops, IO error, or stalled. ++ */ ++ switch (flag) { ++ case -EIO: /* aborted transfer */ ++ usbe->stats.rx_errors++; ++ break; ++ ++ case -EPIPE: /* fifo screwed/no data */ ++ usbe->stats.rx_fifo_errors++; ++ usbe->stats.rx_errors++; ++ break; ++ ++ case -EINTR: /* reset */ ++ break; ++ ++ case -EAGAIN: /* initialisation */ ++ break; ++ } ++ ++ oversize: ++ skb_trim(skb, 0); ++ ++#ifndef RX_NO_COPY ++ buf = usbe->dmabuf; ++ size = usb_rsize; ++#else ++ buf = skb->tail; ++ size = skb_tailroom(skb); ++#endif ++ usbctl_ep_queue_buffer(usbe->client.ctl, 1, buf, size); ++ return; ++ ++ recycle: ++ skb_trim(skb, 0); ++ usbe->next_rx_skb = skb; ++ return; ++} ++ ++/* ++ * Send a skb. ++ * ++ * Note that the receiver expects the last packet to be a non-multiple ++ * of its rsize. If the packet length is a muliple of wsize (and ++ * therefore the remote rsize) tweak the length. ++ */ ++static void usbeth_send(struct sk_buff *skb, struct usbe_info *usbe) ++{ ++ unsigned int len = skb->len; ++ int ret; ++ ++ if ((len % usb_wsize) == 0) ++ len++; ++ ++ ret = usbctl_ep_queue_buffer(usbe->client.ctl, 2, skb->data, len); ++ if (ret) { ++ printk(KERN_ERR "%s: tx dropping packet: %d\n", ++ usbe->dev.name, ret); ++ ++ /* ++ * If the USB core can't accept the packet, we drop it. ++ */ ++ dev_kfree_skb_irq(skb); ++ ++ usbe->cur_tx_skb = NULL; ++ usbe->stats.tx_carrier_errors++; ++ } else { ++ usbe->dev.trans_start = jiffies; ++ } ++} ++ ++static void usbeth_send_callback(void *data, int flag, int size) ++{ ++ struct usbe_info *usbe = data; ++ struct sk_buff *skb = usbe->cur_tx_skb; ++ ++ switch (flag) { ++ case 0: ++ usbe->stats.tx_packets++; ++ usbe->stats.tx_bytes += skb->len; ++ break; ++ case -EIO: ++ usbe->stats.tx_errors++; ++ break; ++ default: ++ usbe->stats.tx_dropped++; ++ break; ++ } ++ ++ dev_kfree_skb_irq(skb); ++ ++ skb = usbe->cur_tx_skb = usbe->next_tx_skb; ++ usbe->next_tx_skb = NULL; ++ ++ if (skb) ++ usbeth_send(skb, usbe); ++ ++ netif_wake_queue(&usbe->dev); ++} ++ ++static int usbeth_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct usbe_info *usbe = dev->priv; ++ unsigned long flags; ++ ++ if (usbe->next_tx_skb) { ++ printk(KERN_ERR "%s: called with next_tx_skb != NULL\n", ++ usbe->dev.name); ++ return 1; ++ } ++ ++ local_irq_save(flags); ++ if (usbe->cur_tx_skb) { ++ usbe->next_tx_skb = skb; ++ netif_stop_queue(dev); ++ } else { ++ usbe->cur_tx_skb = skb; ++ ++ usbeth_send(skb, usbe); ++ } ++ local_irq_restore(flags); ++ return 0; ++} ++ ++/* ++ * Transmit timed out. Reset the endpoint, and re-queue the pending ++ * packet. If we have a free transmit slot, wake the transmit queue. ++ */ ++static void usbeth_xmit_timeout(struct net_device *dev) ++{ ++ struct usbe_info *usbe = dev->priv; ++ unsigned long flags; ++ ++ usbctl_ep_reset(usbe->client.ctl, 2); ++ ++ local_irq_save(flags); ++ if (usbe->cur_tx_skb) ++ usbeth_send(usbe->cur_tx_skb, usbe); ++ ++ if (usbe->next_tx_skb == NULL) ++ netif_wake_queue(dev); ++ ++ usbe->stats.tx_errors++; ++ local_irq_restore(flags); ++} ++ ++static int usbeth_open(struct net_device *dev) ++{ ++ struct usbe_info *usbe = dev->priv; ++ unsigned char *buf; ++ unsigned int size; ++ ++ usbctl_ep_set_callback(usbe->client.ctl, 2, usbeth_send_callback, usbe); ++ usbctl_ep_set_callback(usbe->client.ctl, 1, usbeth_recv_callback, usbe); ++ ++ usbe->cur_tx_skb = usbe->next_tx_skb = NULL; ++ usbe->cur_rx_skb = usb_new_recv_skb(usbe); ++ usbe->next_rx_skb = usb_new_recv_skb(usbe); ++ if (!usbe->cur_rx_skb || !usbe->next_rx_skb) { ++ printk(KERN_ERR "%s: can't allocate new skb\n", ++ usbe->dev.name); ++ if (usbe->cur_rx_skb) ++ kfree_skb(usbe->cur_rx_skb); ++ if (usbe->next_rx_skb) ++ kfree_skb(usbe->next_rx_skb); ++ return -ENOMEM;; ++ } ++#ifndef RX_NO_COPY ++ buf = usbe->dmabuf; ++ size = usb_rsize; ++#else ++ buf = usbe->cur_rx_skb->tail; ++ size = skb_tailroom(usbe->cur_rx_skb); ++#endif ++ usbctl_ep_queue_buffer(usbe->client.ctl, 1, buf, size); ++ ++ if (netif_carrier_ok(dev)) ++ netif_start_queue(dev); ++ ++ return 0; ++} ++ ++static int usbeth_close(struct net_device *dev) ++{ ++ struct usbe_info *usbe = dev->priv; ++ ++ netif_stop_queue(dev); ++ ++ usbctl_ep_set_callback(usbe->client.ctl, 2, NULL, NULL); ++ usbctl_ep_set_callback(usbe->client.ctl, 1, NULL, NULL); ++ usbctl_ep_reset(usbe->client.ctl, 2); ++ usbctl_ep_reset(usbe->client.ctl, 1); ++ ++ if (usbe->cur_tx_skb) ++ kfree_skb(usbe->cur_tx_skb); ++ if (usbe->next_tx_skb) ++ kfree_skb(usbe->next_tx_skb); ++ if (usbe->cur_rx_skb) ++ kfree_skb(usbe->cur_rx_skb); ++ if (usbe->next_rx_skb) ++ kfree_skb(usbe->next_rx_skb); ++ ++ return 0; ++} ++ ++static struct net_device_stats *usbeth_stats(struct net_device *dev) ++{ ++ struct usbe_info *usbe = dev->priv; ++ ++ return &usbe->stats; ++} ++ ++static int __init usbeth_probe(struct net_device *dev) ++{ ++ u8 node_id[ETH_ALEN]; ++ ++ SET_MODULE_OWNER(dev); ++ ++ /* ++ * Assign the hardware address of the board: ++ * generate it randomly, as there can be many such ++ * devices on the bus. ++ */ ++ get_random_bytes(node_id, sizeof node_id); ++ node_id[0] &= 0xfe; // clear multicast bit ++ memcpy(dev->dev_addr, node_id, sizeof node_id); ++ ++ ether_setup(dev); ++ dev->flags &= ~IFF_MULTICAST; ++ dev->flags &= ~IFF_BROADCAST; ++ //dev->flags |= IFF_NOARP; ++ ++ return 0; ++} ++ ++/* ++ * This is called when something in the upper usb client layers ++ * changes that affects the endpoint connectivity state (eg, ++ * connection or disconnection from the host.) We probably want ++ * to do some more handling here, like kicking off a pending ++ * transmission if we're running? ++ */ ++static void usbeth_state_change(void *data, int state, int oldstate) ++{ ++ struct usbe_info *usbe = data; ++ ++ if (state == USB_STATE_CONFIGURED) { ++ netif_carrier_on(&usbe->dev); ++ if (netif_running(&usbe->dev)) ++ netif_wake_queue(&usbe->dev); ++ } else { ++ if (netif_running(&usbe->dev)) ++ netif_stop_queue(&usbe->dev); ++ netif_carrier_off(&usbe->dev); ++ } ++} ++ ++static struct usbe_info usbe_info = { ++ .dev = { ++ .name = "usbf", ++ .init = usbeth_probe, ++ .get_stats = usbeth_stats, ++ .watchdog_timeo = 1 * HZ, ++ .open = usbeth_open, ++ .stop = usbeth_close, ++ .hard_start_xmit = usbeth_xmit, ++ .change_mtu = usbeth_change_mtu, ++ .tx_timeout = usbeth_xmit_timeout, ++ .priv = &usbe_info, ++ }, ++ .client = { ++ .name = "usbeth", ++ .priv = &usbe_info, ++ .state_change = usbeth_state_change, ++ ++ /* ++ * USB client identification for host use in CPU endian. ++ */ ++ .vendor = ETHERNET_VENDOR_ID, ++ .product = ETHERNET_PRODUCT_ID, ++ .version = 0, ++ .class = 0xff, /* vendor specific */ ++ .subclass = 0, ++ .protocol = 0, ++ ++ .product_str = "SA1100 USB NIC", ++ }, ++}; ++ ++static int __init usbeth_init(void) ++{ ++ int rc; ++ ++#ifndef RX_NO_COPY ++ usbe_info.dmabuf = kmalloc(usb_rsize, GFP_KERNEL | GFP_DMA); ++ if (!usbe_info.dmabuf) ++ return -ENOMEM; ++#endif ++ ++ if (register_netdev(&usbe_info.dev) != 0) { ++#ifndef RX_NO_COPY ++ kfree(usbe_info.dmabuf); ++#endif ++ return -EIO; ++ } ++ ++ rc = usbctl_open(&usbe_info.client); ++ if (rc == 0) { ++ struct cdb *cdb = sa1100_usb_get_descriptor_ptr(); ++ ++ cdb->ep1.wMaxPacketSize = cpu_to_le16(usb_rsize); ++ cdb->ep2.wMaxPacketSize = cpu_to_le16(usb_wsize); ++ ++ rc = usbctl_start(&usbe_info.client); ++ if (rc) ++ usbctl_close(&usbe_info.client); ++ } ++ ++ if (rc) { ++ unregister_netdev(&usbe_info.dev); ++#ifndef RX_NO_COPY ++ kfree(usbe_info.dmabuf); ++#endif ++ } ++ ++ return rc; ++} ++ ++static void __exit usbeth_cleanup(void) ++{ ++ usbctl_stop(&usbe_info.client); ++ usbctl_close(&usbe_info.client); ++ ++ unregister_netdev(&usbe_info.dev); ++#ifndef RX_NO_COPY ++ kfree(usbe_info.dmabuf); ++#endif ++} ++ ++module_init(usbeth_init); ++module_exit(usbeth_cleanup); ++ ++MODULE_DESCRIPTION("USB client ethernet driver"); ++MODULE_PARM(usb_rsize, "1i"); ++MODULE_PARM_DESC(usb_rsize, "number of bytes in packets from host to sa11x0"); ++MODULE_PARM(usb_wsize, "1i"); ++MODULE_PARM_DESC(usb_wsize, "number of bytes in packets from sa11x0 to host"); ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb_recv.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,318 @@ ++/* ++ * 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 <linux/module.h> ++#include <linux/pci.h> ++#include <linux/errno.h> ++#include <linux/usb_ch9.h> ++ ++#include <asm/byteorder.h> ++#include <asm/dma.h> ++ ++#include "sa1100_usb.h" ++#include "sa1100usb.h" ++ ++static int naking; ++ ++#if 1 ++static void dump_buf(struct sausb_dev *usb, const char *prefix) ++{ ++ printk("%s: buf [dma=%08x len=%3d] pkt [cpu=%08x dma=%08x len=%3d rem=%3d]\n", ++ prefix, ++ usb->ep[0].bufdma, ++ usb->ep[0].buflen, ++ (unsigned int)usb->ep[0].pktcpu, ++ usb->ep[0].pktdma, ++ usb->ep[0].pktlen, ++ usb->ep[0].pktrem); ++} ++#endif ++ ++static void udc_ep1_done(struct sausb_dev *usb, int flag, int size) ++{ ++// printk("UDC: rxd: %3d %3d\n", flag, size); ++ dump_buf(usb, "UDC: rxd"); ++ ++ if (!usb->ep[0].buflen) ++ return; ++ ++ dma_unmap_single(usb->dev, usb->ep[0].bufdma, usb->ep[0].buflen, ++ DMA_FROM_DEVICE); ++ ++ usb->ep[0].bufdma = 0; ++ usb->ep[0].buflen = 0; ++ usb->ep[0].pktcpu = NULL; ++ usb->ep[0].pktdma = 0; ++ usb->ep[0].pktlen = 0; ++ usb->ep[0].pktrem = 0; ++ ++ if (usb->ep[0].cb_func) ++ usb->ep[0].cb_func(usb->ep[0].cb_data, flag, size); ++} ++ ++/* ++ * Initialisation. Clear out the status, and set FST. ++ */ ++void udc_ep1_init(struct sausb_dev *usb) ++{ ++ sa1100_reset_dma(usb->ep[0].dmach); ++ ++ UDC_clear(Ser0UDCCS1, UDCCS1_FST | UDCCS1_RPE | UDCCS1_RPC); ++ ++ BUG_ON(usb->ep[0].buflen); ++ BUG_ON(usb->ep[0].pktlen); ++} ++ ++void udc_ep1_halt(struct sausb_dev *usb, int halt) ++{ ++ if (halt) { ++ /* force stall at UDC */ ++ UDC_set(Ser0UDCCS1, UDCCS1_FST); ++ } else { ++ sa1100_reset_dma(usb->ep[0].dmach); ++ ++ UDC_clear(Ser0UDCCS1, UDCCS1_FST); ++ ++ udc_ep1_done(usb, -EINTR, 0); ++ } ++} ++ ++/* ++ * This gets called when we receive a SET_CONFIGURATION packet to EP0. ++ * We were configured. We can now accept packets from the host. ++ */ ++void udc_ep1_config(struct sausb_dev *usb, unsigned int maxpktsize) ++{ ++ usb->ep[0].maxpktsize = maxpktsize; ++ usb->ep[0].configured = 1; ++ ++ Ser0UDCOMP = maxpktsize - 1; ++ ++ sa1100_reset_dma(usb->ep[0].dmach); ++ udc_ep1_done(usb, -EINTR, 0); ++ ++ /* ++ * Enable EP1 interrupts. ++ */ ++ usb->udccr &= ~UDCCR_RIM; ++ UDC_write(Ser0UDCCR, usb->udccr); ++} ++ ++/* ++ * We saw a reset from the attached hub. This means we are no ++ * longer configured, and as far as the rest of the world is ++ * concerned, we don't exist. ++ */ ++void udc_ep1_reset(struct sausb_dev *usb) ++{ ++ /* ++ * Disable EP1 interrupts. ++ */ ++ usb->udccr |= UDCCR_RIM; ++ UDC_write(Ser0UDCCR, usb->udccr); ++ ++ usb->ep[0].configured = 0; ++ usb->ep[0].maxpktsize = 0; ++ ++ sa1100_reset_dma(usb->ep[0].dmach); ++ udc_ep1_done(usb, -EINTR, 0); ++} ++ ++void udc_ep1_int_hndlr(struct sausb_dev *usb) ++{ ++ dma_addr_t dma_addr; ++ unsigned int len; ++ u32 status = Ser0UDCCS1; ++ ++ dump_buf(usb, "UDC: int"); ++ ++ if (naking) { ++ printk("UDC: usbrx: in ISR but naking [0x%02x]\n", status); ++ return; ++ } ++ ++ if (!(status & UDCCS1_RPC)) ++ /* you can get here if we are holding NAK */ ++ return; ++ ++ if (!usb->ep[0].buflen) { ++ printk("UDC: usb_recv: RPC for non-existent buffer [0x%02x]\n", status); ++ naking = 1; ++ return; ++ } ++ ++ sa1100_stop_dma(usb->ep[0].dmach); ++ ++ dma_addr = sa1100_get_dma_pos(usb->ep[0].dmach); ++ ++ /* ++ * We've finished with the DMA for this packet. ++ */ ++ sa1100_clear_dma(usb->ep[0].dmach); ++ ++ if (status & UDCCS1_SST) { ++ printk("UDC: usb_recv: stall sent\n"); ++ UDC_flip(Ser0UDCCS1, UDCCS1_SST); ++ ++ /* ++ * UDC aborted current transfer, so we do. ++ * ++ * It would be better to re-queue this buffer IMHO. It ++ * hasn't gone anywhere yet. --rmk ++ */ ++ UDC_flip(Ser0UDCCS1, UDCCS1_RPC); ++ udc_ep1_done(usb, -EIO, 0); ++ return; ++ } ++ ++ if (status & UDCCS1_RPE) { ++ printk("UDC: usb_recv: RPError %x\n", status); ++ UDC_flip(Ser0UDCCS1, UDCCS1_RPC); ++ udc_ep1_done(usb, -EIO, 0); ++ return; ++ } ++ ++ len = dma_addr - usb->ep[0].pktdma; ++ if (len < 0) { ++ printk("UDC: usb_recv: dma_addr (%x) < pktdma (%x)\n", ++ dma_addr, usb->ep[0].pktdma); ++ len = 0; ++ } ++ ++ if (len > usb->ep[0].pktlen) ++ len = usb->ep[0].pktlen; ++ ++ /* ++ * If our transfer was smaller, and we have bytes left in ++ * the FIFO, we need to read them out manually. ++ */ ++ if (len < usb->ep[0].pktlen && (Ser0UDCCS1 & UDCCS1_RNE)) { ++ char *buf; ++ ++ dma_sync_single(usb->dev, usb->ep[0].pktdma + len, ++ usb->ep[0].pktlen - len, DMA_FROM_DEVICE); ++ ++ buf = (char *)usb->ep[0].pktcpu + len; ++ ++ do { ++ *buf++ = Ser0UDCDR; ++ len++; ++ } while (len < usb->ep[0].pktlen && (Ser0UDCCS1 & UDCCS1_RNE)); ++ ++ /* ++ * Note: knowing the internals of this macro is BAD, but we ++ * need this to cause the data to be written back to memory. ++ */ ++ dma_sync_single(usb->dev, usb->ep[0].pktdma + len, ++ usb->ep[0].pktlen - len, DMA_TO_DEVICE); ++ } ++ ++ /* ++ * If the FIFO still contains data, something's definitely wrong. ++ */ ++ if (Ser0UDCCS1 & UDCCS1_RNE) { ++ printk("UDC: usb_recv: fifo screwed, shouldn't contain data\n"); ++ usb->ep[0].fifo_errs++; ++ naking = 1; ++ udc_ep1_done(usb, -EPIPE, 0); ++ return; ++ } ++ ++ /* ++ * Do statistics. ++ */ ++ if (len) { ++ usb->ep[0].bytes += len; ++ usb->ep[0].packets ++; ++ } ++ ++ /* ++ * Update remaining byte count for this buffer. ++ */ ++ usb->ep[0].pktrem -= len; ++ ++ /* ++ * If we received a full-sized packet, and there's more ++ * data remaining, th, queue up another receive. ++ */ ++ if (len == usb->ep[0].pktlen && usb->ep[0].pktrem != 0) { ++ usb->ep[0].pktcpu += len; ++ usb->ep[0].pktdma += len; ++ usb->ep[0].pktlen = min(usb->ep[0].pktrem, usb->ep[0].maxpktsize); ++ sa1100_start_dma(usb->ep[0].dmach, usb->ep[0].pktdma, usb->ep[0].pktlen); ++ /* ++ * Clear RPC to receive next packet. ++ */ ++ UDC_flip(Ser0UDCCS1, UDCCS1_RPC); ++ dump_buf(usb, "UDC: req"); ++ return; ++ } ++ ++ naking = 1; ++ udc_ep1_done(usb, 0, usb->ep[0].buflen - usb->ep[0].pktrem); ++} ++ ++int udc_ep1_queue_buffer(struct sausb_dev *usb, char *buf, unsigned int len) ++{ ++ unsigned long flags; ++ dma_addr_t dma; ++ int ret; ++ ++ if (!buf || len == 0) ++ return -EINVAL; ++ ++ dma = dma_map_single(usb->dev, buf, len, DMA_FROM_DEVICE); ++ ++ spin_lock_irqsave(&usb->lock, flags); ++ do { ++ if (usb->ep[0].buflen) { ++ ret = -EBUSY; ++ break; ++ } ++ ++ sa1100_clear_dma(usb->ep[0].dmach); ++ ++ usb->ep[0].bufdma = dma; ++ usb->ep[0].buflen = len; ++ usb->ep[0].pktcpu = buf; ++ usb->ep[0].pktdma = dma; ++ usb->ep[0].pktlen = min(len, usb->ep[0].maxpktsize); ++ usb->ep[0].pktrem = len; ++ ++ sa1100_start_dma(usb->ep[0].dmach, usb->ep[0].bufdma, usb->ep[0].buflen); ++ dump_buf(usb, "UDC: que"); ++ ++ if (naking) { ++ /* turn off NAK of OUT packets, if set */ ++ UDC_flip(Ser0UDCCS1, UDCCS1_RPC); ++ naking = 0; ++ } ++ ++ ret = 0; ++ } while (0); ++ spin_unlock_irqrestore(&usb->lock, flags); ++ ++ if (ret) ++ dma_unmap_single(usb->dev, dma, len, DMA_FROM_DEVICE); ++ ++ return 0; ++} ++ ++void udc_ep1_recv_reset(struct sausb_dev *usb) ++{ ++ sa1100_reset_dma(usb->ep[0].dmach); ++ udc_ep1_done(usb, -EINTR, 0); ++} +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-sa1100/usb/buffer.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,63 @@ ++/* ++ * usb/buffer.c ++ * ++ * Copyright (C) 2002 Russell King. ++ */ ++#include <linux/module.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++ ++#include "buffer.h" ++ ++static LIST_HEAD(buffers); ++ ++struct usb_buf *usbb_alloc(int size, int gfp) ++{ ++ unsigned long flags; ++ struct usb_buf *buf; ++ ++ buf = kmalloc(sizeof(struct usb_buf) + size, gfp); ++ if (buf) { ++ atomic_set(&buf->users, 1); ++ local_irq_save(flags); ++ list_add(&buf->list, &buffers); ++ local_irq_restore(flags); ++ buf->len = 0; ++ buf->data = (unsigned char *) (buf + 1); ++ buf->head = (unsigned char *) (buf + 1); ++ } ++ ++ return buf; ++} ++ ++void __usbb_free(struct usb_buf *buf) ++{ ++ unsigned long flags; ++ local_irq_save(flags); ++ list_del(&buf->list); ++ local_irq_restore(flags); ++ kfree(buf); ++} ++ ++EXPORT_SYMBOL(usbb_alloc); ++EXPORT_SYMBOL(__usbb_free); ++ ++static void __exit usbb_exit(void) ++{ ++ if (!list_empty(&buffers)) { ++ struct list_head *l, *n; ++ printk("usbb: buffers not freed:\n"); ++ ++ list_for_each_safe(l, n, &buffers) { ++ struct usb_buf *b = list_entry(l, struct usb_buf, list); ++ ++ printk(" %p: alloced from %p count %d\n", ++ b, b->alloced_by, atomic_read(&b->users)); ++ ++ __usbb_free(b); ++ } ++ } ++} ++ ++module_exit(usbb_exit); ++ +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb-char.h 2004-04-30 20:57:36.000000000 -0400 +@@ -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 */ ++ +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-sa1100/usb/buffer.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,45 @@ ++/* ++ * usb/buffer.h: USB client buffers ++ * ++ * Copyright (C) 2002 Russell King. ++ * ++ * Loosely based on linux/skbuff.h ++ */ ++#ifndef USBDEV_BUFFER_H ++#define USBDEV_BUFFER_H ++ ++#include <linux/list.h> ++ ++struct usb_buf { ++ atomic_t users; ++ struct list_head list; ++ void *alloced_by; ++ unsigned char *data; ++ unsigned char *head; ++ unsigned int len; ++}; ++ ++extern struct usb_buf *usbb_alloc(int size, int gfp); ++extern void __usbb_free(struct usb_buf *); ++ ++static inline struct usb_buf *usbb_get(struct usb_buf *buf) ++{ ++ atomic_inc(&buf->users); ++ return buf; ++} ++ ++static inline void usbb_put(struct usb_buf *buf) ++{ ++ if (atomic_dec_and_test(&buf->users)) ++ __usbb_free(buf); ++} ++ ++static inline void *usbb_push(struct usb_buf *buf, int len) ++{ ++ unsigned char *b = buf->head; ++ buf->head += len; ++ buf->len += len; ++ return b; ++} ++ ++#endif +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-sa1100/usb/sa1100usb.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,1160 @@ ++#include <linux/module.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/usb_ch9.h> ++#include <linux/init.h> ++#include <linux/proc_fs.h> ++#include <linux/spinlock.h> ++#include <linux/device.h> ++ ++#include <asm/mach-types.h> ++#include <asm/io.h> ++#include <asm/dma.h> ++#include <asm/irq.h> ++ ++#include "buffer.h" ++#include "usbdev.h" ++#include "sa1100_usb.h" ++#include "sa1100usb.h" ++ ++#ifdef DEBUG ++#define DPRINTK(fmt, args...) printk( fmt , ## args) ++#else ++#define DPRINTK(fmt, args...) ++#endif ++ ++static inline void pcs(const char *prefix) ++{ ++#ifdef DEBUG ++ __u32 foo = Ser0UDCCS0; ++ ++ DPRINTK("%s UDCAR: %d\n", prefix, Ser0UDCAR); ++ ++ printk("UDC: %s: %08x [ %s%s%s%s%s%s]\n", prefix, ++ foo, ++ foo & UDCCS0_SE ? "SE " : "", ++ foo & UDCCS0_DE ? "DE " : "", ++ foo & UDCCS0_FST ? "FST " : "", ++ foo & UDCCS0_SST ? "SST " : "", ++ foo & UDCCS0_IPR ? "IPR " : "", ++ foo & UDCCS0_OPR ? "OPR " : ""); ++#endif ++} ++ ++/* ++ * 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 inline 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 inline void udc_disable(struct sausb_dev *usb) ++{ ++ soft_connect_hook(0); ++ ++ usb->udccr = UDCCR_UDD | UDCCR_SUSIM; ++ ++ UDC_write(Ser0UDCCR, usb->udccr); ++} ++ ++/* ++ * Clear any pending write from the EP0 write buffer. ++ */ ++static void ep0_clear_write(struct sausb_dev *usb) ++{ ++ struct usb_buf *buf; ++ ++ buf = usb->wrbuf; ++ usb->wrint = NULL; ++ usb->wrbuf = NULL; ++ usb->wrptr = NULL; ++ usb->wrlen = 0; ++ ++ if (buf) ++ usbb_put(buf); ++} ++ ++static int udc_start(void *priv) ++{ ++ struct sausb_dev *usb = priv; ++ ++ usb->ep[0].maxpktsize = 0; ++ usb->ep[1].maxpktsize = 0; ++ ++ /* ++ * start UDC internal machinery running, but mask interrupts. ++ */ ++ usb->udccr = UDCCR_SUSIM | UDCCR_TIM | UDCCR_RIM | UDCCR_EIM | ++ UDCCR_RESIM; ++ UDC_write(Ser0UDCCR, usb->udccr); ++ ++ udelay(100); ++ ++ /* ++ * clear all interrupt sources ++ */ ++ Ser0UDCSR = UDCSR_RSTIR | UDCSR_RESIR | UDCSR_EIR | ++ UDCSR_RIR | UDCSR_TIR | UDCSR_SUSIR; ++ ++ /* ++ * flush DMA and fire through some -EAGAINs ++ */ ++ udc_ep1_init(usb); ++ udc_ep2_init(usb); ++ ++ /* ++ * enable any platform specific hardware ++ */ ++ soft_connect_hook(1); ++ ++ /* ++ * Enable resume, suspend and endpoint 0 interrupts. Leave ++ * endpoint 1 and 2 interrupts masked. ++ * ++ * 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. ++ */ ++ usb->udccr &= ~(UDCCR_SUSIM | UDCCR_EIM | UDCCR_RESIM); ++ UDC_write(Ser0UDCCR, usb->udccr); ++ ++ return 0; ++} ++ ++static int udc_stop(void *priv) ++{ ++ struct sausb_dev *usb = priv; ++ ++ ep0_clear_write(usb); ++ ++ /* mask everything */ ++ Ser0UDCCR = 0xFC; ++ ++ udc_ep1_reset(usb); ++ udc_ep2_reset(usb); ++ ++ udc_disable(usb); ++ ++ return 0; ++} ++ ++ ++ ++ ++ ++/* ++ * 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_de(void) ++{ ++ int i = 1; ++ ++ while (1) { ++ if (OK_TO_WRITE) { ++ Ser0UDCCS0 |= UDCCS0_DE; ++ } else { ++ DPRINTK("UDC: quitting set DE because SST or SE set\n"); ++ break; ++ } ++ if (Ser0UDCCS0 & UDCCS0_DE) ++ break; ++ udelay(i); ++ if (++i == 50) { ++ printk("UDC: Dangnabbbit! Cannot set DE! (DE=%8.8X CCS0=%8.8X)\n", ++ UDCCS0_DE, Ser0UDCCS0); ++ break; ++ } ++ } ++} ++ ++static void set_ipr(void) ++{ ++ int i = 1; ++ ++ while (1) { ++ if (OK_TO_WRITE) { ++ Ser0UDCCS0 |= UDCCS0_IPR; ++ } else { ++ DPRINTK("UDC: Quitting set IPR because SST or SE set\n"); ++ break; ++ } ++ if (Ser0UDCCS0 & UDCCS0_IPR) ++ break; ++ udelay(i); ++ if (++i == 50) { ++ printk("UDC: Dangnabbbit! Cannot set IPR! (IPR=%8.8X CCS0=%8.8X)\n", ++ UDCCS0_IPR, Ser0UDCCS0); ++ break; ++ } ++ } ++} ++ ++static void set_ipr_and_de(void) ++{ ++ int i = 1; ++ ++ while (1) { ++ if (OK_TO_WRITE) { ++ Ser0UDCCS0 |= BOTH_BITS; ++ } else { ++ DPRINTK("UDC: Quitting set IPR/DE because SST or SE set\n"); ++ break; ++ } ++ if ((Ser0UDCCS0 & BOTH_BITS) == BOTH_BITS) ++ break; ++ udelay(i); ++ if (++i == 50) { ++ printk("UDC: Dangnabbbit! Cannot set DE/IPR! (DE=%8.8X IPR=%8.8X CCS0=%8.8X)\n", ++ UDCCS0_DE, UDCCS0_IPR, Ser0UDCCS0); ++ break; ++ } ++ } ++} ++ ++static inline void set_cs_bits(__u32 bits) ++{ ++ if (bits & (UDCCS0_SO | UDCCS0_SSE | UDCCS0_FST | UDCCS0_SST)) ++ 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(); ++} ++ ++/* ++ * udc_ep0_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 udc_ep0_write_fifo(struct sausb_dev *usb) ++{ ++ unsigned int bytes_this_time = min(usb->wrlen, 8U); ++ int bytes_written = 0; ++ ++ DPRINTK("WF=%d: ", bytes_this_time); ++ ++ while (bytes_this_time--) { ++ unsigned int cwc; ++ int i; ++ ++ DPRINTK("%2.2X ", *usb->wrptr); ++ ++ cwc = Ser0UDCWC & 15; ++ ++ i = 10; ++ do { ++ Ser0UDCD0 = *usb->wrptr; ++ udelay(20); /* voodo 28Feb01ww */ ++ } while ((Ser0UDCWC & 15) == cwc && --i); ++ ++ if (i == 0) { ++ printk("UDC: udc_ep0_write_fifo: write failure\n"); ++ usb->ep0_wr_fifo_errs++; ++ } ++ ++ usb->wrptr++; ++ bytes_written++; ++ } ++ usb->wrlen -= bytes_written; ++ ++ /* following propagation voodo so maybe caller writing IPR in ++ ..a moment might actually get it to stick 28Feb01ww */ ++ udelay(300); ++ ++ usb->ep0_wr_bytes += bytes_written; ++ DPRINTK("L=%d WCR=%8.8X\n", usb->wrlen, 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 ++ * against the count register with an overall timeout. ++ */ ++static int ++udc_ep0_read_fifo(struct sausb_dev *usb, struct usb_ctrlrequest *request, int sz) ++{ ++ unsigned char *pOut = (unsigned char *) request; ++ unsigned int fifo_count, bytes_read = 0; ++ ++ fifo_count = Ser0UDCWC & 15; ++ ++ DPRINTK("RF=%d ", fifo_count); ++ BUG_ON(fifo_count > sz); ++ ++ while (fifo_count--) { ++ unsigned int cwc; ++ int i; ++ ++ cwc = Ser0UDCWC & 15; ++ ++ i = 10; ++ do { ++ *pOut = (unsigned char) Ser0UDCD0; ++ udelay(20); ++ } while ((Ser0UDCWC & 15) == cwc && --i); ++ ++ if (i == 0) { ++ printk(KERN_ERR "UDC: udc_ep0_read_fifo: read failure\n"); ++ usb->ep0_rd_fifo_errs++; ++ break; ++ } ++ pOut++; ++ bytes_read++; ++ } ++ ++ DPRINTK("fc=%d\n", bytes_read); ++ usb->ep0_rd_bytes += bytes_read; ++ usb->ep0_rd_packets ++; ++ return bytes_read; ++} ++ ++static void ep0_sh_write_data(struct sausb_dev *usb) ++{ ++ /* ++ * 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 ++ */ ++ set_cs_bits(UDCCS0_DE); ++} ++ ++static void ep0_sh_write_with_empty_packet(struct sausb_dev *usb) ++{ ++ /* ++ * 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 ++ */ ++ set_cs_bits(UDCCS0_IPR | UDCCS0_DE); ++ DPRINTK("UDC: sh_write_empty: Sent empty packet\n"); ++} ++ ++static int udc_clear_opr(void) ++{ ++ int i = 10000; ++ int is_clear; ++ ++ /*FIXME*/ ++ do { ++ Ser0UDCCS0 = UDCCS0_SO; ++ is_clear = !(Ser0UDCCS0 & UDCCS0_OPR); ++ if (i-- <= 0) ++ break; ++ } while (!is_clear); ++ ++ return is_clear; ++} ++ ++static int udc_ep0_queue(void *priv, struct usb_buf *buf, ++ unsigned int req_len) ++{ ++ struct sausb_dev *usb = priv; ++ __u32 cs_reg_bits = UDCCS0_IPR; ++ ++ DPRINTK("a=%d r=%d\n", buf->len, req_len); ++ ++ /* ++ * thou shalt not enter data phase until ++ * Out Packet Ready is clear ++ */ ++ if (!udc_clear_opr()) { ++ printk("UDC: SO did not clear OPR\n"); ++ set_cs_bits(UDCCS0_DE | UDCCS0_SO); ++ usbb_put(buf); ++ return 1; ++ } ++ ++ usb->ep0_wr_packets++; ++ ++ usb->wrbuf = buf; ++ usb->wrptr = buf->data; ++ usb->wrlen = min(buf->len, req_len); ++ ++ udc_ep0_write_fifo(usb); ++ ++ if (usb->wrlen == 0) { ++ /* ++ * out in one, so data end ++ */ ++ cs_reg_bits |= UDCCS0_DE; ++ ep0_clear_write(usb); ++ } else if (buf->len < req_len) { ++ /* ++ * we are going to short-change host ++ * so need nul to not stall ++ */ ++ usb->wrint = ep0_sh_write_with_empty_packet; ++ } else { ++ /* ++ * we have as much or more than requested ++ */ ++ usb->wrint = ep0_sh_write_data; ++ } ++ ++ /* ++ * note: IPR was set uncondtionally at start of routine ++ */ ++ set_cs_bits(cs_reg_bits); ++ return 0; ++} ++ ++/* ++ * 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 sometimes work! The rest of the time it would never propagate and ++ * we'd spin forever. So now I just set it and pray... ++ */ ++static void udc_set_address(void *priv, unsigned int addr) ++{ ++ Ser0UDCAR = addr; ++} ++ ++static void udc_set_config(void *priv, struct cdb *cdb) ++{ ++ struct sausb_dev *usb = priv; ++ ++ if (cdb) { ++ udc_ep1_config(usb, le16_to_cpu(cdb->ep1.wMaxPacketSize)); ++ udc_ep2_config(usb, le16_to_cpu(cdb->ep2.wMaxPacketSize)); ++ } else { ++ udc_ep1_reset(usb); ++ udc_ep2_reset(usb); ++ } ++} ++ ++static unsigned int udc_ep_get_status(void *priv, unsigned int ep) ++{ ++ unsigned int status; ++ ++ switch (ep) { ++ case 0: ++ status = (Ser0UDCCS0 & UDCCS0_FST) ? 1 : 0; ++ break; ++ ++ case 1: ++ status = (Ser0UDCCS1 & UDCCS1_FST) ? 1 : 0; ++ break; ++ ++ case 2: ++ status = (Ser0UDCCS2 & UDCCS2_FST) ? 1 : 0; ++ break; ++ ++ default: ++ printk(KERN_ERR "UDC: get_status: bad end point %d\n", ep); ++ status = 0; ++ break; ++ } ++ ++ return status; ++} ++ ++static void udc_ep_halt(void *priv, unsigned int ep, int halt) ++{ ++ struct sausb_dev *usb = priv; ++ ++ printk("UDC: ep%d %s halt\n", ep, halt ? "set" : "clear"); ++ ++ switch (ep) { ++ case 1: ++ udc_ep1_halt(usb, halt); ++ break; ++ ++ case 2: ++ udc_ep2_halt(usb, halt); ++ break; ++ } ++} ++ ++static int udc_ep_queue(void *priv, unsigned int ep, char *buf, unsigned int len) ++{ ++ struct sausb_dev *usb = priv; ++ int ret = -EINVAL; ++ ++ switch (ep) { ++ case 1: ++ ret = udc_ep1_queue_buffer(usb, buf, len); ++ break; ++ case 2: ++ ret = udc_ep2_send(usb, buf, len); ++ break; ++ } ++ ++ return ret; ++} ++ ++static void udc_ep_reset(void *priv, unsigned int ep) ++{ ++ struct sausb_dev *usb = priv; ++ ++ switch (ep) { ++ case 1: ++ udc_ep1_recv_reset(usb); ++ break; ++ case 2: ++ udc_ep2_send_reset(usb); ++ break; ++ } ++} ++ ++static void udc_ep_callback(void *priv, unsigned int ep, usb_callback_t cb, void *data) ++{ ++ struct sausb_dev *usb = priv; ++ unsigned long flags; ++ ++ if (ep == 1 || ep == 2) { ++ ep -= 1; ++ ++ spin_lock_irqsave(&usb->lock, flags); ++ usb->ep[ep].cb_func = cb; ++ usb->ep[ep].cb_data = data; ++ spin_unlock_irqrestore(&usb->lock, flags); ++ } ++} ++ ++static int udc_ep_idle(void *priv, unsigned int ep) ++{ ++ struct sausb_dev *usb = priv; ++ int ret = -EINVAL; ++ ++ switch (ep) { ++ case 1: ++ break; ++ case 2: ++ ret = udc_ep2_idle(usb); ++ break; ++ } ++ ++ return ret; ++} ++ ++static struct usbc_driver usb_sa1100_drv = { ++ .owner = THIS_MODULE, ++ .name = "SA1100", ++ .start = udc_start, ++ .stop = udc_stop, ++ .ep0_queue = udc_ep0_queue, ++ .set_address = udc_set_address, ++ .set_config = udc_set_config, ++ .ep_get_status = udc_ep_get_status, ++ .ep_halt = udc_ep_halt, ++ .ep_queue = udc_ep_queue, ++ .ep_reset = udc_ep_reset, ++ .ep_callback = udc_ep_callback, ++ .ep_idle = udc_ep_idle, ++}; ++ ++ ++/* ++ * udc_ep0_read_packet() ++ * ++ * 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, 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 udc_ep0_read_packet(struct sausb_dev *usb, u32 cs_reg_in) ++{ ++ struct usb_ctrlrequest req; ++ int n, ret = RET_NOACTION; ++ ++ /* ++ * A control request has been received by EP0. ++ * Read the request. ++ */ ++ n = udc_ep0_read_fifo(usb, &req, sizeof(req)); ++ ++ if (n == sizeof(req)) { ++ ret = usbctl_parse_request(usb->ctl, &req); ++ } else { ++ /* ++ * The request wasn't fully received. Force a ++ * stall. ++ */ ++ set_cs_bits(UDCCS0_FST | UDCCS0_SO); ++ printk("UDC: fifo read error: wanted %d bytes got %d\n", ++ sizeof(req), n); ++ } ++ ++ switch (ret) { ++ case RET_ERROR: ++ case RET_NOACTION: ++ break; ++ ++ case RET_ACK: ++ set_cs_bits(UDCCS0_DE | UDCCS0_SO); ++ break; ++ ++ case RET_REQERROR: ++ /* ++ * Send stall PID to host. ++ */ ++ set_cs_bits(UDCCS0_DE | UDCCS0_SO | UDCCS0_FST); ++ break; ++ } ++} ++ ++/* ++ * HACK DEBUG 3Mar01ww ++ * Well, maybe not, it really seems to help! 08Mar01ww ++ */ ++static void core_kicker(struct sausb_dev *usb) ++{ ++ __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; ++} ++ ++static void enable_resume_mask_suspend(struct sausb_dev *usb) ++{ ++ int i; ++ ++ usb->udccr |= UDCCR_SUSIM; ++ ++ i = 1; ++ do { ++ Ser0UDCCR = usb->udccr; ++ udelay(i); ++ if (Ser0UDCCR == usb->udccr) ++ break; ++ if (Ser0UDCSR & UDCSR_RSTIR) ++ break; ++ } while (i++ < 50); ++ ++ if (i == 50) ++ printk("UDC: enable_resume: could not set SUSIM 0x%08x\n", ++ Ser0UDCCR); ++ ++ usb->udccr &= ~UDCCR_RESIM; ++ ++ i = 1; ++ do { ++ Ser0UDCCR = usb->udccr; ++ udelay(i); ++ if (Ser0UDCCR == usb->udccr) ++ break; ++ if (Ser0UDCSR & UDCSR_RSTIR) ++ break; ++ } while (i++ < 50); ++ ++ if (i == 50) ++ printk("UDC: enable_resume: could not clear RESIM 0x%08x\n", ++ Ser0UDCCR); ++} ++ ++static void enable_suspend_mask_resume(struct sausb_dev *usb) ++{ ++ int i; ++ ++ usb->udccr |= UDCCR_RESIM; ++ ++ i = 1; ++ do { ++ Ser0UDCCR = usb->udccr; ++ udelay(i); ++ if (Ser0UDCCR == usb->udccr) ++ break; ++ if (Ser0UDCSR & UDCSR_RSTIR) ++ break; ++ } while (i++ < 50); ++ ++ if (i == 50) ++ printk("UDC: enable_resume: could not set RESIM 0x%08x\n", ++ Ser0UDCCR); ++ ++ usb->udccr &= ~UDCCR_SUSIM; ++ ++ i = 1; ++ do { ++ Ser0UDCCR = usb->udccr; ++ udelay(i); ++ if (Ser0UDCCR == usb->udccr) ++ break; ++ if (Ser0UDCSR & UDCSR_RSTIR) ++ break; ++ } while (i++ < 50); ++ ++ if (i == 50) ++ printk("UDC: enable_resume: could not clear SUSIM 0x%08x\n", ++ Ser0UDCCR); ++} ++ ++/* ++ * Reset received from HUB (or controller just went nuts and reset by ++ * itself!) so UDC core has been reset, track this state here ++ */ ++static void udc_reset(struct sausb_dev *usb) ++{ ++ if (usbctl_reset(usb->ctl)) { ++ ep0_clear_write(usb); ++ ++ /* ++ * Clean up endpoints. ++ */ ++ udc_ep1_reset(usb); ++ udc_ep2_reset(usb); ++ } ++ ++ /* ++ * mask reset ints, they flood during sequence, enable ++ * suspend and resume ++ */ ++ usb->udccr = (usb->udccr & ~(UDCCR_SUSIM | UDCCR_RESIM)) | UDCCR_REM; ++ Ser0UDCCR = usb->udccr; ++} ++ ++/* ++ * handle interrupt for endpoint zero ++ */ ++static void udc_ep0_int_hndlr(struct sausb_dev *usb) ++{ ++ u32 cs_reg_in; ++ ++ pcs("-->"); ++ ++ cs_reg_in = Ser0UDCCS0; ++ ++ /* ++ * 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. ++ */ ++ if (cs_reg_in & UDCCS0_SE) { ++ DPRINTK("UDC: early termination of setup\n"); ++ ++ /* ++ * Clear setup end ++ */ ++ set_cs_bits(UDCCS0_SSE); ++ ++ /* ++ * Clear any pending write. ++ */ ++ ep0_clear_write(usb); ++ } ++ ++ /* ++ * UDC sent a stall due to a protocol violation. ++ */ ++ if (cs_reg_in & UDCCS0_SST) { ++ usb->ep0_stall_sent++; ++ ++ DPRINTK("UDC: write_preamble: UDC sent stall\n"); ++ ++ /* ++ * Clear sent stall ++ */ ++ set_cs_bits(UDCCS0_SST); ++ ++ /* ++ * Clear any pending write. ++ */ ++ ep0_clear_write(usb); ++ } ++ ++ switch (cs_reg_in & (UDCCS0_OPR | UDCCS0_IPR)) { ++ case UDCCS0_OPR | UDCCS0_IPR: ++ DPRINTK("UDC: write_preamble: see OPR. Stopping write to " ++ "handle new SETUP\n"); ++ ++ /* ++ * very rarely, you can get OPR and ++ * leftover IPR. Try to clear ++ */ ++ UDC_clear(Ser0UDCCS0, UDCCS0_IPR); ++ ++ /* ++ * Clear any pending write. ++ */ ++ ep0_clear_write(usb); ++ ++ /*FALLTHROUGH*/ ++ case UDCCS0_OPR: ++ /* ++ * A new setup request is pending. Handle ++ * it. Note that we don't try to read a ++ * packet if SE was set and OPR is clear. ++ */ ++ udc_ep0_read_packet(usb, cs_reg_in); ++ break; ++ ++ case 0: ++ if (usb->wrint) { ++ if (usb->wrlen != 0) { ++ /* ++ * More data to go ++ */ ++ udc_ep0_write_fifo(usb); ++ set_ipr(); ++ } ++ ++ if (usb->wrlen == 0) { ++ /* ++ * All data sent. ++ */ ++ usb->wrint(usb); ++ ++ ep0_clear_write(usb); ++ } ++ } ++ break; ++ ++ case UDCCS0_IPR: ++ DPRINTK("UDC: IPR set, not writing\n"); ++ usb->ep0_early_irqs++; ++ break; ++ } ++ ++ pcs("<--"); ++} ++ ++static irqreturn_t udc_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ struct sausb_dev *usb = dev_id; ++ u32 status = Ser0UDCSR; ++ ++ /* ++ * ReSeT Interrupt Request - UDC has been reset ++ */ ++ if (status & UDCSR_RSTIR) { ++ udc_reset(usb); ++ ++ /* ++ * clear all pending sources ++ */ ++ UDC_flip(Ser0UDCSR, status); ++ return IRQ_HANDLED; ++ } ++ ++ /* ++ * else we have done something other than reset, ++ * so be sure reset enabled ++ */ ++ usb->udccr &= ~UDCCR_REM; ++ UDC_write(Ser0UDCCR, usb->udccr); ++ ++ /* ++ * RESume Interrupt Request ++ */ ++ if (status & UDCSR_RESIR) { ++ usbctl_resume(usb->ctl); ++ core_kicker(usb); ++ enable_suspend_mask_resume(usb); ++ } ++ ++ /* ++ * SUSpend Interrupt Request ++ */ ++ if (status & UDCSR_SUSIR) { ++ usbctl_suspend(usb->ctl); ++ enable_resume_mask_suspend(usb); ++ } ++ ++ /* ++ * clear all pending sources ++ */ ++ UDC_flip(Ser0UDCSR, status); ++ ++ if (status & UDCSR_EIR) ++ udc_ep0_int_hndlr(usb); ++ ++ if (status & UDCSR_RIR) ++ udc_ep1_int_hndlr(usb); ++ ++ if (status & UDCSR_TIR) ++ udc_ep2_int_hndlr(usb); ++ ++ return IRQ_HANDLED; ++} ++ ++#ifdef 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 ++udc_read_proc(char *page, char **start, off_t off, int cnt, int *eof, ++ void *data) ++{ ++ struct sausb_dev *usb = data; ++ char *p = page; ++ u32 v; ++ int len, i; ++ ++ p += usbctl_proc_info(usb->ctl, p); ++ p += sprintf(p, "\nUDC:\n"); ++ v = Ser0UDCAR; ++ p += sprintf(p, "Address\t: %d (0x%02x)\n", v, v); ++ v = Ser0UDCIMP; ++ p += sprintf(p, "IN max\t: %d (0x%02x)\n", v + 1, v); ++ v = Ser0UDCOMP; ++ p += sprintf(p, "OUT max\t: %d (0x%02x)\n", v + 1, v); ++ v = Ser0UDCCR; ++ p += sprintf(p, "UDCCR\t: 0x%02x " ++ "[ %cSUSIM %cTIM %cRIM %cEIM %cRESIM %cUDA %cUDD ] " ++ "(0x%02x)\n", ++ v, ++ v & UDCCR_SUSIM ? '+' : '-', v & UDCCR_TIM ? '+' : '-', ++ v & UDCCR_RIM ? '+' : '-', v & UDCCR_EIM ? '+' : '-', ++ v & UDCCR_RESIM ? '+' : '-', v & UDCCR_UDA ? '+' : '-', ++ v & UDCCR_UDD ? '+' : '-', usb->udccr); ++ v = Ser0UDCCS0; ++ p += sprintf(p, "UDCCS0\t: 0x%02x " ++ "[ %cSO %cSE %cDE %cFST %cSST %cIPR %cOPR ]\n", ++ v, ++ v & UDCCS0_SO ? '+' : '-', v & UDCCS0_SE ? '+' : '-', ++ v & UDCCS0_DE ? '+' : '-', v & UDCCS0_FST ? '+' : '-', ++ v & UDCCS0_SST ? '+' : '-', v & UDCCS0_IPR ? '+' : '-', ++ v & UDCCS0_OPR ? '+' : '-'); ++ v = Ser0UDCCS1; ++ p += sprintf(p, "UDCCS1\t: 0x%02x " ++ "[ %cRNE %cFST %cSST %cRPE %cRPC %cRFS ]\n", ++ v, ++ v & UDCCS1_RNE ? '+' : '-', v & UDCCS1_FST ? '+' : '-', ++ v & UDCCS1_SST ? '+' : '-', v & UDCCS1_RPE ? '+' : '-', ++ v & UDCCS1_RPC ? '+' : '-', v & UDCCS1_RFS ? '+' : '-'); ++ v = Ser0UDCCS2; ++ p += sprintf(p, "UDCCS2\t: 0x%02x " ++ "[ %cFST %cSST %cTUR %cTPE %cTPC %cTFS ]\n", ++ v, ++ v & UDCCS2_FST ? '+' : '-', v & UDCCS2_SST ? '+' : '-', ++ v & UDCCS2_TUR ? '+' : '-', v & UDCCS2_TPE ? '+' : '-', ++ v & UDCCS2_TPC ? '+' : '-', v & UDCCS2_TFS ? '+' : '-'); ++ ++ p += sprintf(p, "\n"); ++ p += sprintf(p, " Bytes Packets FIFO errs Max Sz\n"); ++ p += sprintf(p, "EP0 Rd: %10ld %10ld %10ld -\n", ++ usb->ep0_rd_bytes, ++ usb->ep0_rd_packets, ++ usb->ep0_rd_fifo_errs); ++ p += sprintf(p, "EP0 Wr: %10ld %10ld %10ld -\n", ++ usb->ep0_wr_bytes, ++ usb->ep0_wr_packets, ++ usb->ep0_wr_fifo_errs); ++ ++ for (i = 0; i < 2; i++) ++ p += sprintf(p, "EP%d : %10ld %10ld %10ld %6d\n", ++ i + 1, ++ usb->ep[i].bytes, ++ usb->ep[i].packets, ++ usb->ep[i].fifo_errs, ++ usb->ep[i].maxpktsize); ++ ++ p += sprintf(p, "Stalls sent\t: %ld\n", usb->ep0_stall_sent); ++ p += sprintf(p, "Early ints\t: %ld\n", usb->ep0_early_irqs); ++ ++#if 0 ++ 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 ++#endif ++ ++ len = (p - page) - off; ++ if (len < 0) ++ len = 0; ++ *eof = (len <= cnt) ? 1 : 0; ++ *start = page + off; ++ ++ return len; ++} ++ ++#endif ++ ++extern struct usbctl usbctl; ++ ++static int __devinit udc_probe(struct device *dev) ++{ ++ struct sausb_dev *usb; ++ int retval; ++ ++ if (!request_mem_region(0x80000000, 0x10000, "sa11x0-udc")) ++ return -EBUSY; ++ ++ usb = kmalloc(sizeof(struct sausb_dev), GFP_KERNEL); ++ if (!usb) ++ return -ENOMEM; ++ ++ memset(usb, 0, sizeof(struct sausb_dev)); ++ dev_set_drvdata(dev, usb); ++ ++ usb_sa1100_drv.priv = usb; ++ ++ usb->dev = dev; ++ usb->ctl = &usbctl; ++ ++ spin_lock_init(&usb->lock); ++ ++ udc_disable(usb); ++ ++ usbctl_init(usb->ctl, &usb_sa1100_drv); ++ ++#ifdef CONFIG_PROC_FS ++ create_proc_read_entry("sausb", 0, NULL, udc_read_proc, usb); ++#endif ++ ++ /* setup rx dma */ ++ retval = sa1100_request_dma(DMA_Ser0UDCRd, "USB receive", ++ NULL, NULL, &usb->ep[0].dmach); ++ if (retval) { ++ printk("UDC: unable to register for rx dma rc=%d\n", ++ retval); ++ goto err; ++ } ++ ++ /* setup tx dma */ ++ retval = sa1100_request_dma(DMA_Ser0UDCWr, "USB transmit", ++ NULL, NULL, &usb->ep[1].dmach); ++ if (retval) { ++ printk("UDC: unable to register for tx dma rc=%d\n", ++ retval); ++ goto err; ++ } ++ ++ /* now allocate the IRQ. */ ++ retval = request_irq(IRQ_Ser0UDC, udc_interrupt, SA_INTERRUPT, ++ "SA USB core", usb); ++ if (retval) { ++ printk("UDC: couldn't request USB irq rc=%d\n", retval); ++ goto err; ++ } ++ ++ return retval; ++ ++ err: ++ if (usb->ep[2].dmach) { ++ sa1100_free_dma(usb->ep[2].dmach); ++ usb->ep[2].dmach = NULL; ++ } ++ if (usb->ep[1].dmach) { ++ sa1100_free_dma(usb->ep[1].dmach); ++ usb->ep[1].dmach = NULL; ++ } ++#ifdef CONFIG_PROC_FS ++ remove_proc_entry("sausb", NULL); ++#endif ++ release_mem_region(0x80000000, 0x10000); ++ return retval; ++} ++ ++/* ++ * Release DMA and interrupt resources ++ */ ++static int __devexit udc_remove(struct device *dev) ++{ ++ struct sausb_dev *usb = dev_get_drvdata(dev); ++ ++ dev_set_drvdata(dev, NULL); ++ ++#ifdef CONFIG_PROC_FS ++ remove_proc_entry("sausb", NULL); ++#endif ++ ++ udc_disable(usb); ++ ++ free_irq(IRQ_Ser0UDC, usb); ++ sa1100_free_dma(usb->ep[1].dmach); ++ sa1100_free_dma(usb->ep[0].dmach); ++ ++ usbctl_exit(usb->ctl); ++ ++ release_mem_region(0x80000000, 0x10000); ++ ++ return 0; ++} ++ ++static struct device_driver sa11x0usb_driver = { ++ .name = "sa11x0-udc", ++ .bus = &platform_bus_type, ++ .probe = udc_probe, ++ .remove = __devexit_p(udc_remove), ++}; ++ ++static int __init udc_init(void) ++{ ++ return driver_register(&sa11x0usb_driver); ++} ++ ++static void __exit udc_exit(void) ++{ ++ driver_unregister(&sa11x0usb_driver); ++} ++ ++module_init(udc_init); ++module_exit(udc_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("SA1100 USB Gadget driver"); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-sa1100/usb/control.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,933 @@ ++/* ++ * usb/control.c ++ * ++ * This parses and handles all the control messages to/from endpoint 0. ++ */ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/usb_ch9.h> ++#include <linux/gfp.h> ++#include <linux/init.h> ++ ++#include "buffer.h" ++#include "client.h" ++#include "usbdev.h" ++ ++#include "sa1100_usb.h" ++ ++#define USB_ENDPOINT_HALT 0 ++#define USB_DEVICE_REMOTE_WAKEUP 1 ++ ++#undef DEBUG ++ ++#ifdef DEBUG ++#define DPRINTK(fmt, args...) printk(KERN_DEBUG fmt , ## args) ++#else ++#define DPRINTK(fmt, args...) ++#endif ++ ++/* ++ * print string descriptor ++ */ ++static char * __attribute__((unused)) ++psdesc(char *str, int len, struct usb_string_descriptor *desc) ++{ ++ char *start = str; ++ int nchars = (desc->bLength - 2) / sizeof(__u16) + 2; ++ int i; ++ ++ if (nchars >= len) ++ nchars = len - 1; ++ ++ nchars -= 2; ++ ++ *str++ = '"'; ++ for(i = 0; i < nchars; i++) ++ *str++ = le16_to_cpu(desc->wData[i]); ++ *str++ = '"'; ++ *str = '\0'; ++ ++ return start; ++} ++ ++enum { ++ kError = -1, ++ kEvSuspend = 0, ++ kEvReset = 1, ++ kEvResume = 2, ++ kEvAddress = 3, ++ kEvConfig = 4, ++ kEvDeConfig = 5 ++}; ++ ++enum { ++ kStateZombie = 0, ++ kStateZombieSuspend = 1, ++ kStateDefault = 2, ++ kStateDefaultSuspend = 3, ++ kStateAddr = 4, ++ kStateAddrSuspend = 5, ++ kStateConfig = 6, ++ kStateConfigSuspend = 7 ++}; ++ ++#define kE kError ++#define kSZ kStateZombie ++#define kSZS kStateZombieSuspend ++#define kSD kStateDefault ++#define kSDS kStateDefaultSuspend ++#define kSA kStateAddr ++#define kSAS kStateAddrSuspend ++#define kSC kStateConfig ++#define kSCS kStateConfigSuspend ++ ++/* ++ * Fig 9-1 P192 ++ * Zombie == Attached | Powered ++ */ ++static int device_state_machine[8][6] = { ++// suspend reset resume addr config deconfig ++{ kSZS, kSD, kE, kE, kE, kE }, /* zombie */ ++{ kE, kSD, kSZ, kE, kE, kE }, /* zom sus */ ++{ kSDS, kError, kSD, kSA, kE, kE }, /* default */ ++{ kE, kSD, kSD, kE, kE, kE }, /* def sus */ ++{ kSAS, kSD, kE, kE, kSC, kE }, /* addr */ ++{ kE, kSD, kSA, kE, kE, kE }, /* addr sus */ ++{ kSCS, kSD, kE, kE, kE, kSA }, /* config */ ++{ kE, kSD, kSC, kE, kE, kE } /* cfg sus */ ++}; ++ ++/* ++ * "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] = { ++ USB_STATE_POWERED, /* zombie */ ++ USB_STATE_SUSPENDED, /* zombie suspended */ ++ USB_STATE_DEFAULT, /* default */ ++ USB_STATE_SUSPENDED, /* default suspended */ ++ USB_STATE_ADDRESS, /* address */ ++ USB_STATE_SUSPENDED, /* address suspended */ ++ USB_STATE_CONFIGURED, /* config */ ++ USB_STATE_SUSPENDED /* config 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 void usbctl_callbacks(struct usbctl *ctl, int state, int oldstate) ++{ ++ struct usb_client *clnt = ctl->clnt; ++ ++ /* ++ * Inform any clients currently attached ++ * that the connectivity state changed. ++ */ ++ if (clnt && clnt->state_change) ++ clnt->state_change(clnt->priv, state, oldstate); ++} ++ ++/* ++ * called by the interrupt handler here and the two endpoint ++ * files when interesting .."events" happen ++ */ ++static int usbctl_next_state_on_event(struct usbctl *ctl, int event) ++{ ++ int next_state, next_dev_state, old_dev_state; ++ ++ printk(KERN_DEBUG "usbctl: %s --[%s]--> ", state_names[ctl->sm_state], ++ event_names[event]); ++ ++ next_state = device_state_machine[ctl->sm_state][event]; ++ if (next_state != kError) { ++ next_dev_state = sm_state_to_device_state[next_state]; ++ ++ printk("%s. Device in %s state.\n", ++ state_names[next_state], ++ device_state_names[next_dev_state]); ++ ++ old_dev_state = ctl->state; ++ ctl->sm_state = next_state; ++ ctl->state = next_dev_state; ++ ++ if (old_dev_state != next_dev_state) ++ usbctl_callbacks(ctl, next_dev_state, old_dev_state); ++ } else ++ printk("(error)\n"); ++ ++ return next_state; ++} ++ ++/* ++ * Driver detected USB HUB reset. ++ */ ++int usbctl_reset(struct usbctl *ctl) ++{ ++ int ret; ++ ++ ret = usbctl_next_state_on_event(ctl, kEvReset) == kError; ++ ++ if (!ret) { ++ ctl->address = 0; ++ } ++ return ret; ++} ++ ++EXPORT_SYMBOL(usbctl_reset); ++ ++void usbctl_suspend(struct usbctl *ctl) ++{ ++ usbctl_next_state_on_event(ctl, kEvSuspend); ++} ++ ++EXPORT_SYMBOL(usbctl_suspend); ++ ++void usbctl_resume(struct usbctl *ctl) ++{ ++ usbctl_next_state_on_event(ctl, kEvResume); ++} ++ ++EXPORT_SYMBOL(usbctl_resume); ++ ++static struct usb_interface_descriptor * ++usbctl_get_interface_descriptor(struct usbctl *ctl, unsigned int interface) ++{ ++ /*FIXME*/ ++ struct cdb *cdb = sa1100_usb_get_descriptor_ptr(); ++ ++ return (struct usb_interface_descriptor *)&cdb->intf; ++} ++ ++static inline int ++__usbctl_queue(struct usbctl *ctl, struct usb_ctrlrequest *req, ++ struct usb_buf *buf) ++{ ++ unsigned int reqlen = le16_to_cpu(req->wLength); ++ ++ return ctl->driver->ep0_queue(ctl->driver->priv, buf, reqlen) ? ++ RET_ERROR : RET_QUEUED; ++} ++ ++static int ++usbctl_queue(struct usbctl *ctl, struct usb_ctrlrequest *req, ++ void *data, unsigned int len) ++{ ++ struct usb_buf *buf; ++ ++ buf = usbb_alloc(len, GFP_ATOMIC); ++ if (!buf) { ++ printk(KERN_ERR "usb: out of memory\n"); ++ return RET_ERROR; ++ } ++ ++ if (data) ++ memcpy(usbb_push(buf, len), data, len); ++ ++ return __usbctl_queue(ctl, req, buf); ++} ++ ++/* ++ * 9.4.5: Get Status (device) ++ */ ++static int ++usbctl_parse_dev_get_status(struct usbctl *ctl, struct usb_ctrlrequest *req) ++{ ++ u16 status; ++ ++ status = /* self_powered_hook() ? 1 : 0 */1; ++ ++ status = cpu_to_le16(status); ++ ++ return usbctl_queue(ctl, req, &status, 2); ++} ++ ++/* ++ * Send USB device description to the host. ++ */ ++static int ++usbctl_desc_device(struct usbctl *ctl, struct usb_ctrlrequest *req) ++{ ++ return __usbctl_queue(ctl, req, usbb_get(ctl->dev_desc_buf)); ++} ++ ++/* ++ * Send USB configuration information to the host. ++ */ ++static int ++usbctl_desc_config(struct usbctl *ctl, struct usb_ctrlrequest *req) ++{ ++ /*FIXME*/ ++ struct cdb *cdb = sa1100_usb_get_descriptor_ptr(); ++ ++ return usbctl_queue(ctl, req, cdb, sizeof(struct cdb)); ++} ++ ++/* ++ * Send a string to the host from the string table. ++ */ ++static int ++usbctl_desc_string(struct usbctl *ctl, struct usb_ctrlrequest *req, ++ unsigned int idx) ++{ ++ struct usb_buf *buf; ++ unsigned int lang = le16_to_cpu(req->wIndex); ++ char string[32] __attribute__((unused)); ++ int ret; ++ ++ DPRINTK("usbctl: desc_string (index %u, lang 0x%04x): ", idx, lang); ++ ++ buf = usbc_string_find(&ctl->strings, lang, idx); ++ if (buf) { ++ DPRINTK("%s\n", idx == 0 ? "language" : ++ psdesc(string, sizeof(string), usbc_string_desc(buf))); ++ ++ ret = __usbctl_queue(ctl, req, buf); ++ } else { ++ DPRINTK("not found -> stall\n"); ++ ret = RET_REQERROR; ++ } ++ return ret; ++} ++ ++/* ++ * Send an interface description (and endpoints) to the host. ++ */ ++static int ++usbctl_desc_interface(struct usbctl *ctl, struct usb_ctrlrequest *req, ++ unsigned int idx) ++{ ++ struct usb_interface_descriptor *desc; ++ int ret; ++ ++ DPRINTK("usbctl: desc_interface (index %d)\n", idx); ++ ++ desc = usbctl_get_interface_descriptor(ctl, idx); ++ ++ if (desc) { ++ ret = usbctl_queue(ctl, req, desc, desc->bLength); ++ } else { ++ printk("usbctl: unknown interface %d\n", idx); ++ ret = RET_REQERROR; ++ } ++ ++ return ret; ++} ++ ++/* ++ * Send an endpoint (1 .. n) to the host. ++ */ ++static int ++usbctl_desc_endpoint(struct usbctl *ctl, struct usb_ctrlrequest *req, ++ unsigned int idx) ++{ ++ int ret; ++ ++ DPRINTK("usbctl: desc_endpoint (index %d)\n", idx); ++ ++ if (idx >= 1 && idx <= ctl->nr_ep) { ++ struct usb_endpoint_descriptor *ep = ctl->ep_desc[idx - 1]; ++ ++ ret = usbctl_queue(ctl, req, ep, ep->bLength); ++ } else { ++ printk("usbctl: unknown endpoint %d\n", idx); ++ ret = RET_REQERROR; ++ } ++ ++ return ret; ++} ++ ++/* ++ * 9.4.3: Parse a request for a descriptor. ++ * Unspecified conditions: ++ * None ++ * Valid states: default, address, configured. ++ */ ++static int ++usbctl_parse_dev_descriptor(struct usbctl *ctl, struct usb_ctrlrequest *req) ++{ ++ unsigned int idx = le16_to_cpu(req->wValue) & 255; ++ unsigned int type = le16_to_cpu(req->wValue) >> 8; ++ int ret; ++ ++ switch (type) { ++ case USB_DT_DEVICE: /* check if idx matters */ ++ ret = usbctl_desc_device(ctl, req); ++ break; ++ ++ case USB_DT_CONFIG: /* check if idx matters */ ++ ret = usbctl_desc_config(ctl, req); ++ break; ++ ++ case USB_DT_STRING: ++ ret = usbctl_desc_string(ctl, req, idx); ++ break; ++ ++ case USB_DT_INTERFACE: ++ ret = usbctl_desc_interface(ctl, req, idx); ++ break; ++ ++ case USB_DT_ENDPOINT: ++ ret = usbctl_desc_endpoint(ctl, req, idx); ++ break; ++ ++ case USB_DT_DEVICE_QUALIFIER: ++ case USB_DT_OTHER_SPEED_CONFIG: ++ case USB_DT_INTERFACE_POWER: ++ default: ++ printk(KERN_ERR "usbctl: unknown descriptor: " ++ "wValue = 0x%04x wIndex = 0x%04x\n", ++ le16_to_cpu(req->wValue), le16_to_cpu(req->wIndex)); ++ ret = RET_REQERROR; ++ break; ++ } ++ ++ return ret; ++} ++ ++/* ++ * 9.4.6: Set Address ++ * The USB1.1 spec says the response to SetAddress() with value 0 ++ * is undefined. It then goes on to define the response. We ++ * acknowledge addresses of zero, but take no further action. ++ */ ++static int ++usbctl_parse_dev_set_address(struct usbctl *ctl, struct usb_ctrlrequest *req) ++{ ++ unsigned int address = le16_to_cpu(req->wValue) & 0x7f; ++ ++ if (ctl->state == USB_STATE_CONFIGURED) ++ return RET_REQERROR; ++ ++ if (address != 0) { ++ ctl->address = address; ++ ++ usbctl_next_state_on_event(ctl, kEvAddress); ++ ++ ctl->driver->set_address(ctl->driver->priv, address); ++ } ++ ++ return RET_ACK; ++} ++ ++/* ++ * 9.4.2: Get Configuration. ++ * Unspecified conditions: ++ * - non-zero wIndex, wValue or wLength (ignored) ++ * - default state (request error) ++ * Valid states: address, configured. ++ */ ++static int ++usbctl_parse_dev_get_config(struct usbctl *ctl, struct usb_ctrlrequest *req) ++{ ++ u8 status = 0; ++ ++ if (ctl->state == USB_STATE_CONFIGURED) ++ status = 1; ++ ++ return usbctl_queue(ctl, req, &status, 1); ++} ++ ++/* ++ * 9.4.7: Set Configuration. ++ * Unspecified conditions: ++ * - default state (request error) ++ */ ++static int ++usbctl_parse_dev_set_config(struct usbctl *ctl, struct usb_ctrlrequest *req) ++{ ++ unsigned int cfg = le16_to_cpu(req->wValue); ++ int ret = RET_REQERROR; ++ ++ if (ctl->state == USB_STATE_DEFAULT) ++ return ret; ++ ++ if (cfg == 0) { ++ /* enter address state, or remain in address state */ ++ usbctl_next_state_on_event(ctl, kEvDeConfig); ++ ++ ctl->driver->set_config(ctl->driver->priv, NULL); ++ ++ ret = RET_ACK; ++ } else if (cfg == 1) { ++ /* enter configured state, and set configuration */ ++ /*FIXME*/ ++ struct cdb *cdb = sa1100_usb_get_descriptor_ptr(); ++ ++ usbctl_next_state_on_event(ctl, kEvConfig); ++ ++ ctl->driver->set_config(ctl->driver->priv, cdb); ++ ret = RET_ACK; ++ } ++ ++ return ret; ++} ++ ++/* ++ * Interface handling ++ */ ++ ++/* ++ * 9.4.5: Get Status (interface) ++ */ ++static int ++usbctl_parse_int_get_status(struct usbctl *ctl, struct usb_ctrlrequest *req) ++{ ++ unsigned int interface = le16_to_cpu(req->wIndex) & 255; ++ u16 status; ++ ++ switch (ctl->state) { ++ case USB_STATE_DEFAULT: ++ return RET_REQERROR; ++ ++ case USB_STATE_ADDRESS: ++ if (interface != 0) ++ return RET_REQERROR; ++ break; ++ ++ case USB_STATE_CONFIGURED: ++ if (interface != 1) ++ return RET_REQERROR; ++ break; ++ } ++ ++ status = cpu_to_le16(0); ++ ++ return usbctl_queue(ctl, req, &status, 2); ++} ++ ++/* ++ * 9.4.4: Get Interface ++ * Unspecified conditions: ++ * - ++ * States: Default (unspecified), Address (Request Error), Configured (ok) ++ */ ++static int ++usbctl_parse_int_get_interface(struct usbctl *ctl, struct usb_ctrlrequest *req) ++{ ++ unsigned int interface = le16_to_cpu(req->wIndex) & 255; ++ u8 null = 0; ++ ++ if (ctl->state != USB_STATE_CONFIGURED) ++ return RET_REQERROR; ++ ++ /* ++ * If the interface doesn't exist, respond with request error ++ */ ++ if (interface != 1) ++ return RET_REQERROR; ++ ++ printk("usbctl: get interface %d not supported\n", interface); ++ ++ return usbctl_queue(ctl, req, &null, 1); ++} ++ ++static int ++usbctl_parse_int_set_interface(struct usbctl *ctl, struct usb_ctrlrequest *req) ++{ ++ unsigned int interface = le16_to_cpu(req->wIndex) & 255; ++ ++ if (interface != 0) ++ printk("usbctl: set interface %d not supported (ignored)\n", ++ interface); ++ ++ return RET_ACK; ++} ++ ++/* ++ * Endpoint handling ++ */ ++ ++/* ++ * 9.4.5: Get Status (endpoint) ++ */ ++static int ++usbctl_parse_ep_get_status(struct usbctl *ctl, struct usb_ctrlrequest *req) ++{ ++ unsigned int ep = le16_to_cpu(req->wIndex) & 15; ++ u16 status; ++ ++ if ((ep != 0 && ctl->state != USB_STATE_CONFIGURED) || ++ ep <= ctl->nr_ep) ++ return RET_REQERROR; ++ ++ status = ctl->driver->ep_get_status(ctl->driver->priv, ep); ++ status = cpu_to_le16(status); ++ ++ return usbctl_queue(ctl, req, &status, 2); ++} ++ ++/* ++ * 9.4.1: Clear an endpoint feature. We only support ENDPOINT_HALT. ++ * Unspecified conditions: ++ * - non-zero wLength is not specified (ignored) ++ * Valid states: Address, Configured. ++ */ ++static int ++usbctl_parse_ep_clear_feature(struct usbctl *ctl, struct usb_ctrlrequest *req) ++{ ++ unsigned int feature = le16_to_cpu(req->wValue); ++ unsigned int ep = le16_to_cpu(req->wIndex) & 15; ++ int ret; ++ ++ if ((ep != 0 && ctl->state != USB_STATE_CONFIGURED) || ++ ep <= ctl->nr_ep) ++ return RET_REQERROR; ++ ++ if (feature == USB_ENDPOINT_HALT) { ++ ctl->driver->ep_halt(ctl->driver->priv, ep, 0); ++ ret = RET_ACK; ++ } else { ++ printk(KERN_ERR "usbctl: unsupported clear feature: " ++ "wValue = 0x%04x wIndex = 0x%04x\n", ++ feature, ep); ++ ++ ret = RET_REQERROR; ++ } ++ return ret; ++} ++ ++/* ++ * 9.4.9: Set Feature (endpoint) ++ */ ++static int ++usbctl_parse_ep_set_feature(struct usbctl *ctl, struct usb_ctrlrequest *req) ++{ ++ unsigned int feature = le16_to_cpu(req->wValue); ++ unsigned int ep = le16_to_cpu(req->wIndex) & 15; ++ int ret; ++ ++ if ((ep != 0 && ctl->state != USB_STATE_CONFIGURED) || ++ ep <= ctl->nr_ep) ++ return RET_REQERROR; ++ ++ if (feature == USB_ENDPOINT_HALT) { ++ ctl->driver->ep_halt(ctl->driver->priv, ep, 1); ++ ret = RET_ACK; ++ } else { ++ printk(KERN_ERR "usbctl: unsupported set feature " ++ "wValue = 0x%04x wIndex = 0x%04x\n", ++ feature, ep); ++ ++ ret = RET_REQERROR; ++ } ++ return ret; ++} ++ ++/* ++ * This reflects Table 9.3 (p186) in the USB1.1 spec. ++ * ++ * Some notes: ++ * - USB1.1 specifies remote wakeup feature, so we don't implement ++ * USB_RECIP_DEVICE USB_REQ_{SET,CLEAR}_FEATURE ++ * - USB1.1 doesn't actually specify any interface features, so we ++ * don't implement USB_RECIP_INTERFACE USB_REQ_{SET,CLEAR}_FEATURE ++ */ ++static int (*request_fns[4][16])(struct usbctl *, struct usb_ctrlrequest *) = { ++ [USB_RECIP_DEVICE] = { ++ [USB_REQ_GET_STATUS] = usbctl_parse_dev_get_status, ++ [USB_REQ_CLEAR_FEATURE] = NULL, ++ [USB_REQ_SET_FEATURE] = NULL, ++ [USB_REQ_SET_ADDRESS] = usbctl_parse_dev_set_address, ++ [USB_REQ_GET_DESCRIPTOR] = usbctl_parse_dev_descriptor, ++ [USB_REQ_SET_DESCRIPTOR] = NULL, ++ [USB_REQ_GET_CONFIGURATION] = usbctl_parse_dev_get_config, ++ [USB_REQ_SET_CONFIGURATION] = usbctl_parse_dev_set_config, ++ }, ++ ++ [USB_RECIP_INTERFACE] = { ++ [USB_REQ_GET_STATUS] = usbctl_parse_int_get_status, ++ [USB_REQ_CLEAR_FEATURE] = NULL, ++ [USB_REQ_SET_FEATURE] = NULL, ++ [USB_REQ_GET_INTERFACE] = usbctl_parse_int_get_interface, ++ [USB_REQ_SET_INTERFACE] = usbctl_parse_int_set_interface, ++ }, ++ ++ [USB_RECIP_ENDPOINT] = { ++ [USB_REQ_GET_STATUS] = usbctl_parse_ep_get_status, ++ [USB_REQ_CLEAR_FEATURE] = usbctl_parse_ep_clear_feature, ++ [USB_REQ_SET_FEATURE] = usbctl_parse_ep_set_feature, ++ }, ++}; ++ ++static void __attribute__((unused)) ++usbctl_dump_request(const char *prefix, const struct usb_ctrlrequest *req) ++{ ++ printk("%sbRequestType=0x%02x bRequest=0x%02x " ++ "wValue=0x%04x wIndex=0x%04x wLength=0x%04x\n", ++ prefix, req->bRequestType, req->bRequest, ++ le16_to_cpu(req->wValue), le16_to_cpu(req->wIndex), ++ le16_to_cpu(req->wLength)); ++} ++ ++int usbctl_parse_request(struct usbctl *ctl, struct usb_ctrlrequest *req) ++{ ++ unsigned int type; ++ int (*fn)(struct usbctl *, struct usb_ctrlrequest *) = NULL; ++ int ret = RET_REQERROR; ++ ++ //usbctl_dump_request("usbctl: ", req); ++ ++ type = req->bRequestType & USB_TYPE_MASK; ++ if (type == USB_TYPE_STANDARD) { ++ unsigned int recip; ++ ++ recip = req->bRequestType & USB_RECIP_MASK; ++ if (recip < ARRAY_SIZE(request_fns) && ++ req->bRequest < ARRAY_SIZE(request_fns[0])) ++ fn = request_fns[recip][req->bRequest]; ++ } ++ ++ if (fn) ++ ret = fn(ctl, req); ++ else ++ usbctl_dump_request(KERN_ERR "usbctl: unknown request: ", ++ req); ++ ++ /* ++ * Make sure we're doing the right thing. ++ */ ++ if (req->bRequestType & USB_DIR_IN) { ++ if (ret != RET_QUEUED && ret != RET_REQERROR) ++ printk("Error: device to host transfer expected\n"); ++ } else { ++ if (ret == RET_QUEUED) ++ printk("Error: no device to host transfer expected\n"); ++ } ++ ++ return ret; ++} ++ ++EXPORT_SYMBOL(usbctl_parse_request); ++ ++/* Start running. Must have called usb_open (above) first */ ++int usbctl_start(struct usb_client *client) ++{ ++ struct usbctl *ctl = client->ctl; ++ ++ if (ctl == NULL || ctl->clnt != client) { ++ printk("usbctl: start: no client registered\n"); ++ return -EPERM; ++ } ++ ++ ctl->sm_state = kStateZombie; ++ ctl->state = USB_STATE_POWERED; ++ ++ /* ++ * Notify the client as to our state. ++ */ ++ usbctl_callbacks(ctl, USB_STATE_POWERED, USB_STATE_SUSPENDED); ++ ++ return ctl->driver->start(ctl->driver->priv); ++} ++ ++EXPORT_SYMBOL(usbctl_start); ++ ++/* ++ * Stop USB core from running ++ */ ++void usbctl_stop(struct usb_client *client) ++{ ++ struct usbctl *ctl = client->ctl; ++ ++ if (ctl == NULL || ctl->clnt != client) { ++ printk("USBDEV: stop: no client/driver registered\n"); ++ return; ++ } ++ ++ ctl->driver->stop(ctl->driver->priv); ++} ++ ++EXPORT_SYMBOL(usbctl_stop); ++ ++struct usbctl usbctl; ++ ++EXPORT_SYMBOL(usbctl); ++ ++/* Open SA usb core on behalf of a client, but don't start running */ ++ ++int usbctl_open(struct usb_client *client) ++{ ++ struct usbctl *ctl = &usbctl; ++ int ret; ++printk("usbctl_open: ctl %p driver %p\n", ctl, ctl->driver); ++ if (!ctl->driver || !try_module_get(ctl->driver->owner)) ++ return -ENODEV; ++ ++ if (ctl->clnt != NULL) { ++ ret = -EBUSY; ++ goto err; ++ } ++ ++ ctl->clnt = client; ++ ctl->state = USB_STATE_SUSPENDED; ++ ctl->nr_ep = 2; ++ /* start in zombie suspended state */ ++ ctl->sm_state = kStateZombieSuspend; ++ ctl->state = USB_STATE_SUSPENDED; ++ client->ctl = ctl; ++ ++ ctl->dev_desc_buf = usbb_alloc(sizeof(struct usb_device_descriptor), ++ GFP_KERNEL); ++ if (!ctl->dev_desc_buf) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ ctl->dev_desc = usbb_push(ctl->dev_desc_buf, ++ sizeof(struct usb_device_descriptor)); ++ ++ /* create descriptors for enumeration */ ++ initialize_descriptors(ctl); ++ ++ return 0; ++ ++ err: ++ module_put(ctl->driver->owner); ++ return ret; ++} ++ ++EXPORT_SYMBOL(usbctl_open); ++ ++/* Tell SA core client is through using it */ ++void usbctl_close(struct usb_client *client) ++{ ++ struct usbctl *ctl = client->ctl; ++ ++ if (ctl == NULL || ctl->clnt != client) { ++ printk("usbctl: close: no client registered\n"); ++ return; ++ } ++ ++ usbb_put(ctl->dev_desc_buf); ++ ++ client->ctl = NULL; ++ ctl->clnt = NULL; ++ ctl->dev_desc = NULL; ++ ctl->dev_desc_buf = NULL; ++ /* reset to zombie suspended state */ ++ ctl->sm_state = kStateZombieSuspend; ++ ctl->state = USB_STATE_SUSPENDED; ++ ++ usbc_string_free_all(&ctl->strings); ++ ++ if (ctl->driver->owner) ++ module_put(ctl->driver->owner); ++} ++ ++EXPORT_SYMBOL(usbctl_close); ++ ++int usbctl_proc_info(struct usbctl *ctl, char *buf) ++{ ++ char *p = buf; ++ ++ p += sprintf(p, "USB Gadget Core:\n"); ++ p += sprintf(p, "Driver\t: %s\n", ++ ctl->driver ? ctl->driver->name : "none"); ++ p += sprintf(p, "Client\t: %s\n", ++ ctl->clnt ? ctl->clnt->name : "none"); ++ p += sprintf(p, "State\t: %s (%s) %d\n", ++ device_state_names[sm_state_to_device_state[ctl->sm_state]], ++ state_names[ctl->sm_state], ++ ctl->sm_state); ++ p += sprintf(p, "Address\t: %d\n", ctl->address); ++ ++ return p - buf; ++} ++ ++EXPORT_SYMBOL(usbctl_proc_info); ++ ++int ++usbctl_ep_queue_buffer(struct usbctl *ctl, unsigned int ep, ++ char *buf, unsigned int len) ++{ ++ return ctl->driver->ep_queue(ctl->driver->priv, ep, buf, len); ++} ++ ++EXPORT_SYMBOL(usbctl_ep_queue_buffer); ++ ++void usbctl_ep_reset(struct usbctl *ctl, unsigned int ep) ++{ ++ return ctl->driver->ep_reset(ctl->driver->priv, ep); ++} ++ ++EXPORT_SYMBOL(usbctl_ep_reset); ++ ++void ++usbctl_ep_set_callback(struct usbctl *ctl, unsigned int ep, ++ usb_callback_t callback, void *data) ++{ ++ ctl->driver->ep_callback(ctl->driver->priv, ep, callback, data); ++} ++ ++EXPORT_SYMBOL(usbctl_ep_set_callback); ++ ++int usbctl_ep_idle(struct usbctl *ctl, unsigned int ep) ++{ ++ return ctl->driver->ep_idle(ctl->driver->priv, ep); ++} ++ ++EXPORT_SYMBOL(usbctl_ep_idle); ++ ++/* ++ * usbctl_init() ++ * Module load time. Allocate dma and interrupt resources. Setup /proc fs ++ * entry. Leave UDC disabled. ++ */ ++int usbctl_init(struct usbctl *ctl, struct usbc_driver *drv) ++{ ++ usbc_string_init(&ctl->strings); ++printk("usbctl_init: %p %p\n", ctl, drv); ++ /* ++ * start in zombie suspended state ++ */ ++ ctl->sm_state = kStateZombieSuspend; ++ ctl->state = USB_STATE_SUSPENDED; ++ ctl->driver = drv; ++ ++ return 0; ++} ++ ++/* ++ * usbctl_exit() ++ */ ++void usbctl_exit(struct usbctl *ctl) ++{ ++ usbc_string_free_all(&ctl->strings); ++ ++ ctl->driver = NULL; ++} ++ ++EXPORT_SYMBOL(usbctl_init); ++EXPORT_SYMBOL(usbctl_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("USB gadget core"); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-sa1100/usb/client.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,40 @@ ++#ifndef USBDEV_CLIENT_H ++#define USBDEV_CLIENT_H ++ ++#include "sa1100_usb.h" /* grr */ ++ ++struct usbctl; ++ ++struct usb_client { ++ struct usbctl *ctl; ++ const char *name; /* Client name */ ++ void *priv; /* Client-private data */ ++ void (*state_change)(void *priv, int state, int oldstate); ++ __u16 vendor; /* USB vendor ID */ ++ __u16 product; /* USB product ID */ ++ __u16 version; /* USB version ID */ ++ __u8 class; /* USB class */ ++ __u8 subclass; /* USB subclass */ ++ __u8 protocol; /* USB protocol */ ++ __u8 unused1; ++ __u16 unused2; ++ const char *manufacturer_str; ++ const char *product_str; ++ const char *serial_str; ++}; ++ ++int usbctl_start(struct usb_client *client); ++void usbctl_stop(struct usb_client *client); ++int usbctl_open(struct usb_client *client); ++void usbctl_close(struct usb_client *client); ++ ++int ++usbctl_ep_queue_buffer(struct usbctl *ctl, unsigned int ep, ++ char *buf, unsigned int len); ++void usbctl_ep_reset(struct usbctl *ctl, unsigned int ep); ++void ++usbctl_ep_set_callback(struct usbctl *ctl, unsigned int ep, ++ usb_callback_t callback, void *data); ++int usbctl_ep_idle(struct usbctl *ctl, unsigned int ep); ++ ++#endif +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-sa1100/usb/sa1100_usb.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,50 @@ ++/* ++ * 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 ++ ++typedef void (*usb_callback_t)(void *data, int flag, int size); ++ ++/* in usb_send.c */ ++int sa1100_usb_xmitter_avail( void ); ++int sa1100_usb_send(char *buf, int len); ++void sa1100_usb_send_set_callback(usb_callback_t callback, void *data); ++void sa1100_usb_send_reset(void); ++ ++/* in usb_recev.c */ ++int sa1100_usb_recv(char *buf, int len); ++void sa1100_usb_recv_set_callback(usb_callback_t callback, void *data); ++void sa1100_usb_recv_reset(void); ++ ++////////////////////////////////////////////////////////////////////////////// ++// Descriptor Management ++////////////////////////////////////////////////////////////////////////////// ++ ++// MaxPower: ++#define USB_POWER(x) ((x)>>1) /* convert mA to descriptor units of A for MaxPower */ ++ ++/* "config descriptor buffer" - that is, one config, ++ ..one interface and 2 endpoints */ ++struct cdb { ++ struct usb_config_descriptor cfg; ++ struct usb_interface_descriptor intf; ++ struct usb_endpoint_descriptor ep1, ep2; ++} __attribute__ ((packed)); ++ ++ ++/*======================================================= ++ * 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() ++*/ ++struct cdb *sa1100_usb_get_descriptor_ptr(void); ++ ++#endif /* _SA1100_USB_H */ +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-sa1100/usb/sa1100usb.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,136 @@ ++/* ++ * 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 SA1100USB_H ++#define SA1100USB_H ++ ++struct usbctl; ++ ++struct sausb_dev { ++ struct device *dev; ++ struct usbctl *ctl; ++ spinlock_t lock; ++ ++ u32 udccr; ++ ++ /* ++ * EP0 write thread. ++ */ ++ void (*wrint)(struct sausb_dev *); ++ struct usb_buf *wrbuf; ++ unsigned char *wrptr; ++ unsigned int wrlen; ++ ++ /* ++ * EP0 statistics. ++ */ ++ unsigned long ep0_wr_fifo_errs; ++ unsigned long ep0_wr_bytes; ++ unsigned long ep0_wr_packets; ++ unsigned long ep0_rd_fifo_errs; ++ unsigned long ep0_rd_bytes; ++ unsigned long ep0_rd_packets; ++ unsigned long ep0_stall_sent; ++ unsigned long ep0_early_irqs; ++ ++ /* ++ * EP1 .. n ++ */ ++ struct { ++ dma_regs_t *dmach; ++ ++ dma_addr_t bufdma; ++ unsigned int buflen; ++ void *pktcpu; ++ dma_addr_t pktdma; ++ unsigned int pktlen; ++ unsigned int pktrem; ++ ++ void *cb_data; ++ void (*cb_func)(void *data, int flag, int size); ++ ++ u32 udccs; ++ unsigned int maxpktsize; ++ unsigned int configured; ++ unsigned int host_halt; ++ unsigned long fifo_errs; ++ unsigned long bytes; ++ unsigned long packets; ++ } ep[2]; ++}; ++ ++/* receiver */ ++int ep1_recv(void); ++void udc_ep1_init(struct sausb_dev *); ++void udc_ep1_halt(struct sausb_dev *, int); ++void udc_ep1_reset(struct sausb_dev *); ++void udc_ep1_config(struct sausb_dev *, unsigned int); ++void udc_ep1_int_hndlr(struct sausb_dev *); ++ ++/* xmitter */ ++void udc_ep2_init(struct sausb_dev *); ++void udc_ep2_halt(struct sausb_dev *, int); ++void udc_ep2_reset(struct sausb_dev *); ++void udc_ep2_config(struct sausb_dev *, unsigned int); ++void udc_ep2_int_hndlr(struct sausb_dev *); ++ ++#define UDC_write(reg, val) do { \ ++ 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)); \ ++} while (0) ++ ++#define UDC_set(reg, val) do { \ ++ 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))); \ ++} while (0) ++ ++#define UDC_clear(reg, val) do { \ ++ 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)); \ ++} while (0) ++ ++#define UDC_flip(reg, val) do { \ ++ 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))); \ ++} while (0) ++ ++#define CHECK_ADDRESS { if ( Ser0UDCAR == 1 ) { printk("%s:%d I lost my address!!!\n",__FUNCTION__, __LINE__);}} ++ ++#endif +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-sa1100/usb/strings.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,117 @@ ++/* ++ * usb/strings.c ++ * ++ * Copyright (C) 2002 Russell King. ++ */ ++#include <linux/module.h> ++#include <linux/slab.h> ++#include <linux/errno.h> ++#include <linux/spinlock.h> ++#include <linux/string.h> ++#include <linux/usb_ch9.h> ++ ++#include "buffer.h" ++#include "strings.h" ++ ++struct usb_buf *usbc_string_alloc(int len) ++{ ++ struct usb_buf *buf; ++ int tot_len; ++ ++ tot_len = sizeof(struct usb_descriptor_header) + sizeof(u16) * len; ++ ++ buf = usbb_alloc(tot_len, GFP_KERNEL); ++ ++ if (buf) { ++ struct usb_string_descriptor *desc = usbb_push(buf, tot_len); ++ ++ desc->bLength = tot_len; ++ desc->bDescriptorType = USB_DT_STRING; ++ } ++ return buf; ++} ++ ++void usbc_string_free(struct usb_buf *buf) ++{ ++ if (buf) ++ usbb_put(buf); ++} ++ ++void usbc_string_from_cstr(struct usb_buf *buf, const char *str) ++{ ++ struct usb_string_descriptor *desc = usbc_string_desc(buf); ++ int i, len; ++ ++ len = strlen(str); ++ BUG_ON((sizeof(__u16) * len) > desc->bLength - sizeof(struct usb_descriptor_header)); ++ ++ for (i = 0; i < len; i++) ++ desc->wData[i] = cpu_to_le16(str[i]); ++} ++ ++int usbc_string_add(struct usbc_strs *table, struct usb_buf *buf) ++{ ++ int nr, i; ++ ++ nr = -ENOSPC; ++ spin_lock_irq(&table->lock); ++ for (i = 0; i < NR_STRINGS; i++) ++ if (table->buf[i] == NULL) { ++ table->buf[i] = buf; ++ nr = i; ++ break; ++ } ++ spin_unlock_irq(&table->lock); ++ ++ return nr; ++} ++ ++void usbc_string_del(struct usbc_strs *table, int nr) ++{ ++ if (nr < NR_STRINGS) { ++ spin_lock_irq(&table->lock); ++ table->buf[nr] = NULL; ++ spin_unlock_irq(&table->lock); ++ } ++} ++ ++struct usb_buf * ++usbc_string_find(struct usbc_strs *table, unsigned int lang, unsigned int idx) ++{ ++ struct usb_buf *buf = NULL; ++ ++ if (idx < NR_STRINGS) { ++ spin_lock_irq(&table->lock); ++ buf = usbb_get(table->buf[idx]); ++ spin_unlock_irq(&table->lock); ++ } ++ ++ return buf; ++} ++ ++void usbc_string_free_all(struct usbc_strs *table) ++{ ++ int i; ++ ++ spin_lock_irq(&table->lock); ++ for (i = 0; i < NR_STRINGS; i++) { ++ usbc_string_free(table->buf[i]); ++ table->buf[i] = NULL; ++ } ++ spin_unlock_irq(&table->lock); ++} ++ ++void usbc_string_init(struct usbc_strs *table) ++{ ++ memset(table, 0, sizeof(struct usbc_strs)); ++ spin_lock_init(&table->lock); ++} ++ ++EXPORT_SYMBOL(usbc_string_from_cstr); ++EXPORT_SYMBOL(usbc_string_alloc); ++EXPORT_SYMBOL(usbc_string_free); ++EXPORT_SYMBOL(usbc_string_add); ++EXPORT_SYMBOL(usbc_string_del); ++EXPORT_SYMBOL(usbc_string_find); ++EXPORT_SYMBOL(usbc_string_free_all); ++EXPORT_SYMBOL(usbc_string_init); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb_ctl.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,171 @@ ++ /* ++ * 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 <linux/module.h> ++#include <linux/errno.h> ++#include <linux/usb.h> ++ ++#include "buffer.h" ++#include "client.h" ++#include "usbdev.h" ++#include "sa1100_usb.h" ++ ++////////////////////////////////////////////////////////////////////////////// ++// Globals ++////////////////////////////////////////////////////////////////////////////// ++ ++/* device descriptors */ ++static struct cdb cdb; ++ ++////////////////////////////////////////////////////////////////////////////// ++// Private Helpers ++////////////////////////////////////////////////////////////////////////////// ++ ++int sa1100_usb_add_string(struct usbctl *ctl, const char *str) ++{ ++ int nr = 0; ++ ++ if (str) { ++ struct usb_buf *buf; ++ int len; ++ ++ len = strlen(str); ++ ++ nr = -ENOMEM; ++ buf = usbc_string_alloc(len); ++ if (buf) { ++ usbc_string_from_cstr(buf, str); ++ nr = usbc_string_add(&ctl->strings, buf); ++ ++ if (nr < 0) ++ usbc_string_free(buf); ++ } ++ } ++ ++ return nr; ++} ++ ++EXPORT_SYMBOL(sa1100_usb_add_string); ++ ++static int sa1100_usb_add_language(struct usbctl *ctl, unsigned int lang) ++{ ++ struct usb_buf *buf; ++ int nr = -ENOMEM; ++ ++ buf = usbc_string_alloc(1); ++ if (buf) { ++ usbc_string_desc(buf)->wData[0] = cpu_to_le16(lang); /* American English */ ++ nr = usbc_string_add(&ctl->strings, buf); ++ ++ if (nr < 0) ++ usbc_string_free(buf); ++ } ++ ++ return nr; ++} ++ ++/* setup default descriptors */ ++ ++void initialize_descriptors(struct usbctl *ctl) ++{ ++ struct usb_client *clnt = ctl->clnt; ++ int r; ++ ++ ctl->ep_desc[0] = (struct usb_endpoint_descriptor *)&cdb.ep1; ++ ctl->ep_desc[1] = (struct usb_endpoint_descriptor *)&cdb.ep2; ++ ++ cdb.cfg.bLength = USB_DT_CONFIG_SIZE; ++ cdb.cfg.bDescriptorType = USB_DT_CONFIG; ++ cdb.cfg.wTotalLength = cpu_to_le16(sizeof(struct cdb)); ++ cdb.cfg.bNumInterfaces = 1; ++ cdb.cfg.bConfigurationValue = 1; ++ cdb.cfg.iConfiguration = 0; ++ cdb.cfg.bmAttributes = USB_CONFIG_ATT_ONE; ++ cdb.cfg.bMaxPower = USB_POWER( 500 ); ++ ++ cdb.intf.bLength = USB_DT_INTERFACE_SIZE; ++ cdb.intf.bDescriptorType = USB_DT_INTERFACE; ++ cdb.intf.bInterfaceNumber = 0; /* unique intf index*/ ++ cdb.intf.bAlternateSetting = 0; ++ cdb.intf.bNumEndpoints = 2; ++ cdb.intf.bInterfaceClass = 0xff; /* vendor specific */ ++ cdb.intf.bInterfaceSubClass = 0; ++ cdb.intf.bInterfaceProtocol = 0; ++ cdb.intf.iInterface = 0; ++ ++ cdb.ep1.bLength = USB_DT_INTERFACE_SIZE; ++ cdb.ep1.bDescriptorType = USB_DT_ENDPOINT; ++ cdb.ep1.bEndpointAddress = USB_DIR_OUT | 1; ++ cdb.ep1.bmAttributes = USB_ENDPOINT_XFER_BULK; ++ cdb.ep1.wMaxPacketSize = cpu_to_le16(64); ++ cdb.ep1.bInterval = 0; ++ ++ cdb.ep2.bLength = USB_DT_INTERFACE_SIZE; ++ cdb.ep2.bDescriptorType = USB_DT_ENDPOINT; ++ cdb.ep2.bEndpointAddress = USB_DIR_IN | 2; ++ cdb.ep2.bmAttributes = USB_ENDPOINT_XFER_BULK; ++ cdb.ep2.wMaxPacketSize = cpu_to_le16(64); ++ cdb.ep2.bInterval = 0; ++ ++ ctl->dev_desc->bLength = USB_DT_DEVICE_SIZE; ++ ctl->dev_desc->bDescriptorType = USB_DT_DEVICE; ++ ctl->dev_desc->bcdUSB = cpu_to_le16(0x100); /* 1.0 */ ++ ctl->dev_desc->bDeviceClass = clnt->class; ++ ctl->dev_desc->bDeviceSubClass = clnt->subclass; ++ ctl->dev_desc->bDeviceProtocol = clnt->protocol; ++ ctl->dev_desc->bMaxPacketSize0 = 8; /* ep0 max fifo size */ ++ ctl->dev_desc->idVendor = cpu_to_le16(clnt->vendor); ++ ctl->dev_desc->idProduct = cpu_to_le16(clnt->product); ++ ctl->dev_desc->bcdDevice = cpu_to_le16(clnt->version); ++ ctl->dev_desc->bNumConfigurations = 1; ++ ++ /* set language */ ++ /* See: http://www.usb.org/developers/data/USB_LANGIDs.pdf */ ++ r = sa1100_usb_add_language(ctl, 0x409); ++ if (r < 0) ++ printk(KERN_ERR "usbc: couldn't add language\n"); ++ ++ r = sa1100_usb_add_string(ctl, clnt->manufacturer_str); ++ if (r < 0) ++ printk(KERN_ERR "usbc: couldn't add manufacturer string\n"); ++ ++ ctl->dev_desc->iManufacturer = r > 0 ? r : 0; ++ ++ r = sa1100_usb_add_string(ctl, clnt->product_str); ++ if (r < 0) ++ printk(KERN_ERR "usbc: couldn't add product string\n"); ++ ++ ctl->dev_desc->iProduct = r > 0 ? r : 0; ++ ++ r = sa1100_usb_add_string(ctl, clnt->serial_str); ++ if (r < 0) ++ printk(KERN_ERR "usbc: couldn't add serial string\n"); ++ ++ ctl->dev_desc->iSerialNumber = r > 0 ? r : 0; ++} ++ ++ ++/*==================================================== ++ * Descriptor Manipulation. ++ * Use these between open() and start() above to setup ++ * the descriptors for your device. ++ */ ++ ++/* get pointer to static default descriptor */ ++struct cdb *sa1100_usb_get_descriptor_ptr(void) ++{ ++ return &cdb; ++} ++ ++EXPORT_SYMBOL(sa1100_usb_get_descriptor_ptr); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-sa1100/usb/Makefile 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,12 @@ ++# ++# Makefile for the USB client ++# ++ ++usbdevcore-objs := buffer.o control.o strings.o usb_ctl.o ++ ++sa1100-objs := sa1100usb.o usb_recv.o usb_send.o ++ ++obj-$(CONFIG_SA1100_USB) += usbdevcore.o sa1100.o ++obj-$(CONFIG_SA1100_USB_NETLINK) += usb-eth.o ++obj-$(CONFIG_SA1100_USB_CHAR) += usb-char.o ++ +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-sa1100/usb/usbdev.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,91 @@ ++#ifndef USBDEV_H ++#define USBDEV_H ++ ++#include "strings.h" ++ ++struct usb_buf; ++struct module; ++struct cdb; ++struct usb_client; ++ ++struct usbc_driver { ++ struct module *owner; ++ const char *name; ++ void *priv; ++ int (*start)(void *); ++ int (*stop)(void *); ++ ++ int (*ep0_queue)(void *, struct usb_buf *buf, unsigned int req_len); ++ void (*set_address)(void *, unsigned int addr); ++ void (*set_config)(void *, struct cdb *config); ++ ++ /* ++ * Get specified endpoint status, as defined in 9.4.5. ++ */ ++ unsigned int (*ep_get_status)(void *, unsigned int ep); ++ void (*ep_halt)(void *, unsigned int ep, int halt); ++ ++ /* ++ * Client ++ */ ++ int (*ep_queue)(void *, unsigned int, char *, unsigned int); ++ void (*ep_reset)(void *, unsigned int); ++ void (*ep_callback)(void *, unsigned int, void (*)(void *, int, int), void *); ++ int (*ep_idle)(void *, unsigned int); ++}; ++ ++struct usbc_endpoint { ++ struct usb_endpoint_descriptor *desc; ++}; ++ ++struct usbc_interface { ++ struct usb_interface_descriptor *desc; ++ unsigned int nr_ep; ++ struct usbc_endpoint *ep[0]; ++}; ++ ++struct usbc_config { ++ struct usb_config_descriptor *desc; ++ unsigned int nr_interface; ++ struct usbc_interface *interface[0]; ++}; ++ ++struct usbctl { ++ struct usb_client *clnt; ++ const struct usbc_driver *driver; ++ ++ /* Internal state */ ++ unsigned int address; /* host assigned address */ ++ unsigned int state; /* our device state */ ++ unsigned int sm_state; /* state machine state */ ++ ++ struct usbc_config *config; /* active configuration */ ++ struct usbc_strs strings; ++ ++ /* Descriptors */ ++ struct usb_device_descriptor *dev_desc; /* device descriptor */ ++ struct usb_buf *dev_desc_buf; /* device descriptor buffer */ ++ ++ ++ int nr_ep; ++ struct usb_endpoint_descriptor *ep_desc[2]; ++}; ++ ++/* ++ * Function Prototypes ++ */ ++ ++#define RET_ERROR (-1) ++#define RET_NOACTION (0) ++#define RET_QUEUED (1) ++#define RET_ACK (2) ++#define RET_REQERROR (3) ++ ++int usbctl_parse_request(struct usbctl *ctl, struct usb_ctrlrequest *req); ++ ++int usbctl_reset(struct usbctl *ctl); ++void usbctl_suspend(struct usbctl *ctl); ++void usbctl_resume(struct usbctl *ctl); ++ ++#endif ++ +--- linux-2.6.5/arch/arm/mach-sa1100/pm.c~heh 2004-04-03 22:36:27.000000000 -0500 ++++ linux-2.6.5/arch/arm/mach-sa1100/pm.c 2004-04-30 20:57:36.000000000 -0400 +@@ -150,6 +150,7 @@ + */ + static int sa11x0_pm_prepare(u32 state) + { ++ nmi_watchdog_disable(); + return 0; + } + +@@ -158,6 +159,7 @@ + */ + static int sa11x0_pm_finish(u32 state) + { ++ nmi_watchdog_enable(); + return 0; + } + +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/arch/arm/mach-sa1100/nmi-oopser.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,104 @@ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/gfp.h> ++#include <linux/module.h> ++#include <linux/delay.h> ++ ++#include <asm/ptrace.h> ++#include <asm/domain.h> ++#include <asm/hardware.h> ++ ++static void *nmi_stack; ++ ++asm(" \n\ ++nmi_start: \n\ ++ mrs r8, spsr \n\ ++ ldr r9, .Lstack \n\ ++ ldr sp, [r9] \n\ ++ sub sp, sp, #18 * 4 \n\ ++ str r8, [sp, #16 * 4] \n\ ++ str lr, [sp, #15 * 4] \n\ ++ stmia sp, {r0 - r7} \n\ ++ add r0, sp, #8 * 4 \n\ ++ mrs r2, cpsr \n\ ++ bic r1, r2, #0x1f \n\ ++ orr r1, r1, #0x13 \n\ ++ msr cpsr_c, r1 \n\ ++ mov r0, r0 \n\ ++ stmia r0, {r8 - lr} \n\ ++ mov r0, r0 \n\ ++ msr cpsr_c, r2 \n\ ++ mov r0, r0 \n\ ++ mov r0, sp \n\ ++ mov lr, pc \n\ ++ ldr pc, .Lfn \n\ ++ ldmia sp, {r0 - r7} \n\ ++ ldr r8, [sp, #16 * 4] \n\ ++ ldr lr, [sp, #15 * 4] \n\ ++ add sp, sp, #18 * 4 \n\ ++ msr spsr, r8 \n\ ++ movs pc, lr \n\ ++ \n\ ++.Lstack: .long nmi_stack \n\ ++.Lfn: .long nmi_fn \n\ ++nmi_end:"); ++ ++extern unsigned char nmi_start, nmi_end; ++ ++static void __attribute__((unused)) nmi_fn(struct pt_regs *regs) ++{ ++ struct thread_info *thread; ++ unsigned long osmr0, osmr1, oscr, ossr, icmr, icip; ++ ++ oscr = OSCR; ++ osmr0 = OSMR0; ++ osmr1 = OSMR1; ++ ossr = OSSR; ++ icmr = ICMR; ++ icip = ICIP; ++ ++ OSSR = OSSR_M1; ++ ICMR &= ~IC_OST1; ++ ++ thread = (struct thread_info *)(regs->ARM_sp & ~8191); ++ ++ bust_spinlocks(1); ++ printk("OSMR0:%08lx OSMR1:%08lx OSCR:%08lx OSSR:%08lx ICMR:%08lx ICIP:%08lx\n", ++ osmr0, osmr1, oscr, ossr, icmr, icip); ++ nmi_watchdog(thread, regs); ++ bust_spinlocks(0); ++ ++ OSSR = OSSR_M1; ++ OSMR1 = OSSR + 36864000; ++ ICMR |= IC_OST1; ++} ++ ++static int nmi_init(void) ++{ ++ unsigned char *vec_base = (unsigned char *)vectors_base(); ++return 0; ++ nmi_stack = (void *)__get_free_page(GFP_KERNEL); ++ if (!nmi_stack) ++ return -ENOMEM; ++ ++ nmi_stack += PAGE_SIZE; ++ ++ modify_domain(DOMAIN_USER, DOMAIN_MANAGER); ++ memcpy(vec_base + 0x1c, &nmi_start, &nmi_end - &nmi_start); ++ modify_domain(DOMAIN_USER, DOMAIN_CLIENT); ++ ++ /* ++ * Ensure timer 1 is set to FIQ, and enabled. ++ */ ++ OSMR1 = OSCR - 1; ++ OSSR = OSSR_M1; ++ OIER |= OIER_E1; ++ ICLR |= IC_OST1; ++ ICMR |= IC_OST1; ++ ++ return 0; ++} ++ ++__initcall(nmi_init); +--- linux-2.6.5/drivers/media/Kconfig~heh 2004-04-03 22:36:51.000000000 -0500 ++++ linux-2.6.5/drivers/media/Kconfig 2004-04-30 20:57:36.000000000 -0400 +@@ -32,6 +32,8 @@ + + source "drivers/media/common/Kconfig" + ++source "drivers/media/mmc/Kconfig" ++ + config VIDEO_TUNER + tristate + default y if VIDEO_BT848=y || VIDEO_SAA7134=y || VIDEO_MXB=y || VIDEO_CX88=y +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/media/mmc/Kconfig 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,52 @@ ++# ++# MMC subsystem configuration ++# ++ ++menu "MMC/SD Card support" ++ ++config MMC ++ tristate "MMC support" ++ help ++ MMC is the "multi-media card" bus protocol. ++ ++ If you want MMC support, you should say Y here and also ++ to the specific driver for your MMC interface. ++ ++config MMC_DEBUG ++ bool "MMC debugging" ++ depends on MMC != n ++ help ++ This is an option for use by developers; most people should ++ say N here. This enables MMC core and driver debugging. ++ ++config MMC_BLOCK ++ tristate "MMC block device driver" ++ depends on MMC ++ default y ++ help ++ Say Y here to enable the MMC block device driver support. ++ This provides a block device driver, which you can use to ++ mount the filesystem. Almost everyone wishing MMC support ++ should say Y or M here. ++ ++config MMC_ARMMMCI ++ tristate "ARM AMBA Multimedia Card Interface support" ++ depends on ARM_AMBA && MMC ++ help ++ This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card ++ Interface (PL180 and PL181) support. If you have an ARM(R) ++ platform with a Multimedia Card slot, say Y or M here. ++ ++ If unsure, say N. ++ ++config MMC_PXA ++ tristate "Intel PXA255 Multimedia Card Interface support" ++ depends on ARCH_PXA && MMC ++ help ++ This selects the Intel(R) PXA(R) Multimedia card Interface. ++ If you have a PXA(R) platform with a Multimedia Card slot, ++ say Y or M here. ++ ++ If unsure, say N. ++ ++endmenu +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/media/mmc/mmc_queue.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,171 @@ ++/* ++ * linux/drivers/media/mmc/mmc_queue.c ++ * ++ * Copyright (C) 2003 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 <linux/module.h> ++#include <linux/blkdev.h> ++ ++#include <linux/mmc/card.h> ++#include <linux/mmc/host.h> ++#include "mmc_queue.h" ++ ++/* ++ * Prepare a MMC request. Essentially, this means passing the ++ * preparation off to the media driver. The media driver will ++ * create a mmc_io_request in req->special. ++ */ ++static int mmc_prep_request(struct request_queue *q, struct request *req) ++{ ++ struct mmc_queue *mq = q->queuedata; ++ int ret = BLKPREP_KILL; ++ ++ if (req->flags & REQ_SPECIAL) { ++ /* ++ * Special commands already have the command ++ * blocks already setup in req->special. ++ */ ++ BUG_ON(!req->special); ++ ++ ret = BLKPREP_OK; ++ } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { ++ /* ++ * Block I/O requests need translating according ++ * to the protocol. ++ */ ++ ret = mq->prep_fn(mq, req); ++ } else { ++ /* ++ * Everything else is invalid. ++ */ ++ blk_dump_rq_flags(req, "MMC bad request"); ++ } ++ ++ if (ret == BLKPREP_OK) ++ req->flags |= REQ_DONTPREP; ++ ++ return ret; ++} ++ ++static int mmc_queue_thread(void *d) ++{ ++ struct mmc_queue *mq = d; ++ struct request_queue *q = mq->queue; ++ DECLARE_WAITQUEUE(wait, current); ++ int ret; ++ ++ /* ++ * Set iothread to ensure that we aren't put to sleep by ++ * the process freezing. We handle suspension ourselves. ++ */ ++ current->flags |= PF_MEMALLOC|PF_IOTHREAD; ++ ++ daemonize("mmcqd"); ++ ++ spin_lock_irq(¤t->sighand->siglock); ++ sigfillset(¤t->blocked); ++ recalc_sigpending(); ++ spin_unlock_irq(¤t->sighand->siglock); ++ ++ mq->thread = current; ++ complete(&mq->thread_complete); ++ ++ add_wait_queue(&mq->thread_wq, &wait); ++ spin_lock_irq(q->queue_lock); ++ do { ++ struct request *req = NULL; ++ ++ set_current_state(TASK_INTERRUPTIBLE); ++ if (!blk_queue_plugged(q)) ++ mq->req = req = elv_next_request(q); ++ spin_unlock(q->queue_lock); ++ ++ if (!req) { ++ if (!mq->thread) ++ break; ++ schedule(); ++ continue; ++ } ++ set_current_state(TASK_RUNNING); ++ ++ ret = mq->issue_fn(mq, req); ++ ++ spin_lock_irq(q->queue_lock); ++ end_request(req, ret); ++ } while (1); ++ remove_wait_queue(&mq->thread_wq, &wait); ++ ++ complete_and_exit(&mq->thread_complete, 0); ++ return 0; ++} ++ ++/* ++ * Generic MMC request handler. This is called for any queue on a ++ * particular host. When the host is not busy, we look for a request ++ * on any queue on this host, and attempt to issue it. This may ++ * not be the queue we were asked to process. ++ */ ++static void mmc_request(request_queue_t *q) ++{ ++ struct mmc_queue *mq = q->queuedata; ++ ++ if (!mq->req && !blk_queue_plugged(q)) ++ wake_up(&mq->thread_wq); ++} ++ ++/** ++ * mmc_init_queue - initialise a queue structure. ++ * @mq: mmc queue ++ * @card: mmc card to attach this queue ++ * @lock: queue lock ++ * ++ * Initialise a MMC card request queue. ++ */ ++int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock) ++{ ++ u64 limit = BLK_BOUNCE_HIGH; ++ int ret; ++ ++ if (card->host->dev->dma_mask) ++ limit = *card->host->dev->dma_mask; ++ ++ mq->card = card; ++ mq->queue = blk_init_queue(mmc_request, lock); ++ blk_queue_prep_rq(mq->queue, mmc_prep_request); ++ blk_queue_bounce_limit(mq->queue, limit); ++ ++ mq->queue->queuedata = mq; ++ mq->req = NULL; ++ ++ init_completion(&mq->thread_complete); ++ init_waitqueue_head(&mq->thread_wq); ++ ++ ret = kernel_thread(mmc_queue_thread, mq, CLONE_KERNEL); ++ if (ret < 0) { ++ blk_cleanup_queue(mq->queue); ++ } else { ++ wait_for_completion(&mq->thread_complete); ++ init_completion(&mq->thread_complete); ++ } ++ ++ return ret; ++} ++ ++EXPORT_SYMBOL(mmc_init_queue); ++ ++void mmc_cleanup_queue(struct mmc_queue *mq) ++{ ++ mq->thread = NULL; ++ wake_up(&mq->thread_wq); ++ wait_for_completion(&mq->thread_complete); ++ blk_cleanup_queue(mq->queue); ++ ++ mq->card = NULL; ++} ++ ++EXPORT_SYMBOL(mmc_cleanup_queue); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/media/mmc/pxamci.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,587 @@ ++/* ++ * linux/drivers/media/mmc/pxa.c - PXA MMCI driver ++ * ++ * Copyright (C) 2003 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. ++ * ++ * This hardware is really sick. No way to clear interrupts. Have ++ * to turn off the clock whenever we touch the device. Yuck! ++ * ++ * 1 and 3 byte data transfers not supported ++ * max block length up to 1023 ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/ioport.h> ++#include <linux/device.h> ++#include <linux/interrupt.h> ++#include <linux/blkdev.h> ++#include <linux/dma-mapping.h> ++#include <linux/mmc/host.h> ++#include <linux/mmc/protocol.h> ++ ++#include <asm/dma.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/sizes.h> ++ ++#include "pxamci.h" ++ ++#ifdef CONFIG_MMC_DEBUG ++#define DBG(x...) printk(KERN_DEBUG x) ++#else ++#define DBG(x...) do { } while (0) ++#endif ++ ++struct pxamci_host { ++ struct mmc_host mmc; ++ spinlock_t lock; ++ struct resource *res; ++ void *base; ++ int irq; ++ int dma; ++ unsigned int clkrt; ++ unsigned int cmdat; ++ unsigned int imask; ++ unsigned int power_mode; ++ ++ struct mmc_request *req; ++ struct mmc_command *cmd; ++ struct mmc_data *data; ++ ++ dma_addr_t sg_dma; ++ struct pxa_dma_desc *sg_cpu; ++ ++ dma_addr_t dma_buf; ++ unsigned int dma_size; ++ unsigned int dma_dir; ++}; ++ ++#define to_pxamci_host(x) container_of(x, struct pxamci_host, mmc) ++ ++/* ++ * The base MMC clock rate ++ */ ++#define CLOCKRATE 20000000 ++ ++static inline unsigned int ns_to_clocks(unsigned int ns) ++{ ++ return (ns * (CLOCKRATE / 1000000) + 999) / 1000; ++} ++ ++static void pxamci_stop_clock(struct pxamci_host *host) ++{ ++ if (readl(host->base + MMC_STAT) & STAT_CLK_EN) { ++ unsigned long flags; ++ unsigned int v; ++ ++ writel(STOP_CLOCK, host->base + MMC_STRPCL); ++ ++ /* ++ * Wait for the "clock has stopped" interrupt. ++ * We need to unmask the interrupt to receive ++ * the notification. Sigh. ++ */ ++ spin_lock_irqsave(&host->lock, flags); ++ writel(host->imask & ~CLK_IS_OFF, host->base + MMC_I_MASK); ++ do { ++ v = readl(host->base + MMC_I_REG); ++ } while (!(v & CLK_IS_OFF)); ++ writel(host->imask, host->base + MMC_I_MASK); ++ spin_unlock_irqrestore(&host->lock, flags); ++ } ++} ++ ++static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ host->imask &= ~mask; ++ writel(host->imask, host->base + MMC_I_MASK); ++ spin_unlock_irqrestore(&host->lock, flags); ++} ++ ++static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ host->imask |= mask; ++ writel(host->imask, host->base + MMC_I_MASK); ++ spin_unlock_irqrestore(&host->lock, flags); ++} ++ ++static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) ++{ ++ unsigned int nob = data->blocks; ++ unsigned int timeout, size; ++ dma_addr_t dma; ++ u32 dcmd; ++ int i; ++ ++ host->data = data; ++ ++ if (data->flags & MMC_DATA_STREAM) ++ nob = 0xffff; ++ ++ writel(nob, host->base + MMC_NOB); ++ writel(1 << data->blksz_bits, host->base + MMC_BLKLEN); ++ ++ timeout = ns_to_clocks(data->timeout_ns) + data->timeout_clks; ++ writel((timeout + 255) / 256, host->base + MMC_RDTO); ++ ++ if (data->flags & MMC_DATA_READ) { ++ host->dma_dir = DMA_FROM_DEVICE; ++ dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG; ++ DRCMRTXMMC = 0; ++ DRCMRRXMMC = host->dma | DRCMR_MAPVLD; ++ } else { ++ host->dma_dir = DMA_TO_DEVICE; ++ dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC; ++ DRCMRRXMMC = 0; ++ DRCMRTXMMC = host->dma | DRCMR_MAPVLD; ++ } ++ ++ dcmd |= DCMD_BURST32 | DCMD_WIDTH1; ++ ++ host->dma_size = data->blocks << data->blksz_bits; ++ host->dma_buf = dma_map_single(host->mmc.dev, data->rq->buffer, ++ host->dma_size, host->dma_dir); ++ ++ for (i = 0, size = host->dma_size, dma = host->dma_buf; size; i++) { ++ u32 len = size; ++ ++ if (len > DCMD_LENGTH) ++ len = 0x1000; ++ ++ if (data->flags & MMC_DATA_READ) { ++ host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO; ++ host->sg_cpu[i].dtadr = dma; ++ } else { ++ host->sg_cpu[i].dsadr = dma; ++ host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO; ++ } ++ host->sg_cpu[i].dcmd = dcmd | len; ++ ++ dma += len; ++ size -= len; ++ ++ if (size) { ++ host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) * ++ sizeof(struct pxa_dma_desc); ++ } else { ++ host->sg_cpu[i].ddadr = DDADR_STOP; ++ } ++ } ++ wmb(); ++ ++ DDADR(host->dma) = host->sg_dma; ++ DCSR(host->dma) = DCSR_RUN; ++} ++ ++static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat) ++{ ++ WARN_ON(host->cmd != NULL); ++ host->cmd = cmd; ++ ++ if (cmd->flags & MMC_RSP_BUSY) ++ cmdat |= CMDAT_BUSY; ++ ++ switch (cmd->flags & (MMC_RSP_MASK | MMC_RSP_CRC)) { ++ case MMC_RSP_SHORT | MMC_RSP_CRC: ++ cmdat |= CMDAT_RESP_SHORT; ++ break; ++ case MMC_RSP_SHORT: ++ cmdat |= CMDAT_RESP_R3; ++ break; ++ case MMC_RSP_LONG | MMC_RSP_CRC: ++ cmdat |= CMDAT_RESP_R2; ++ break; ++ default: ++ break; ++ } ++ ++ writel(cmd->opcode, host->base + MMC_CMD); ++ writel(cmd->arg >> 16, host->base + MMC_ARGH); ++ writel(cmd->arg & 0xffff, host->base + MMC_ARGL); ++ writel(cmdat, host->base + MMC_CMDAT); ++ writel(host->clkrt, host->base + MMC_CLKRT); ++ ++ writel(START_CLOCK, host->base + MMC_STRPCL); ++ ++ pxamci_enable_irq(host, END_CMD_RES); ++} ++ ++static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *req) ++{ ++ DBG("PXAMCI: request done\n"); ++ host->req = NULL; ++ host->cmd = NULL; ++ host->data = NULL; ++ mmc_request_done(&host->mmc, req); ++} ++ ++static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) ++{ ++ struct mmc_command *cmd = host->cmd; ++ int i; ++ u32 v; ++ ++ if (!cmd) ++ return 0; ++ ++ host->cmd = NULL; ++ ++ /* ++ * Did I mention this is Sick. We always need to ++ * discard the upper 8 bits of the first 16-bit word. ++ */ ++ v = readl(host->base + MMC_RES) & 0xffff; ++ for (i = 0; i < 4; i++) { ++ u32 w1 = readl(host->base + MMC_RES) & 0xffff; ++ u32 w2 = readl(host->base + MMC_RES) & 0xffff; ++ cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8; ++ v = w2; ++ } ++ ++ if (stat & STAT_TIME_OUT_RESPONSE) { ++ cmd->error = MMC_ERR_TIMEOUT; ++ } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) { ++ cmd->error = MMC_ERR_BADCRC; ++ } ++ ++ pxamci_disable_irq(host, END_CMD_RES); ++ if (host->data && cmd->error == MMC_ERR_NONE) { ++ pxamci_enable_irq(host, DATA_TRAN_DONE); ++ } else { ++ pxamci_finish_request(host, host->req); ++ } ++ ++ return 1; ++} ++ ++static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) ++{ ++ struct mmc_data *data = host->data; ++ ++ if (!data) ++ return 0; ++ ++ DCSR(host->dma) = 0; ++ dma_unmap_single(host->mmc.dev, host->dma_buf, host->dma_size, ++ host->dma_dir); ++ ++ if (stat & STAT_READ_TIME_OUT) ++ data->error = MMC_ERR_TIMEOUT; ++ else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR)) ++ data->error = MMC_ERR_BADCRC; ++ ++ data->bytes_xfered = (data->blocks - readl(host->base + MMC_NOB)) ++ << data->blksz_bits; ++ ++ pxamci_disable_irq(host, DATA_TRAN_DONE); ++ ++ host->data = NULL; ++ if (host->req->stop && data->error == MMC_ERR_NONE) { ++ pxamci_stop_clock(host); ++ pxamci_start_cmd(host, host->req->stop, 0); ++ } else { ++ pxamci_finish_request(host, host->req); ++ } ++ ++ return 1; ++} ++ ++static irqreturn_t pxamci_irq(int irq, void *devid, struct pt_regs *regs) ++{ ++ struct pxamci_host *host = devid; ++ unsigned int ireg; ++ int handled = 0; ++ ++ ireg = readl(host->base + MMC_I_REG); ++ ++ DBG("PXAMCI: irq %08x\n", ireg); ++ ++ if (ireg) { ++ unsigned stat = readl(host->base + MMC_STAT); ++ ++ DBG("PXAMCI: stat %08x\n", stat); ++ ++ if (ireg & END_CMD_RES) ++ handled |= pxamci_cmd_done(host, stat); ++ if (ireg & DATA_TRAN_DONE) ++ handled |= pxamci_data_done(host, stat); ++ } ++ ++ return IRQ_RETVAL(handled); ++} ++ ++static void pxamci_request(struct mmc_host *mmc, struct mmc_request *req) ++{ ++ struct pxamci_host *host = to_pxamci_host(mmc); ++ unsigned int cmdat; ++ ++ WARN_ON(host->req != NULL); ++ ++ host->req = req; ++ ++ pxamci_stop_clock(host); ++ ++ cmdat = host->cmdat; ++ host->cmdat &= ~CMDAT_INIT; ++ ++ if (req->data) { ++ pxamci_setup_data(host, req->data); ++ ++ cmdat &= ~CMDAT_BUSY; ++ cmdat |= CMDAT_DATAEN | CMDAT_DMAEN; ++ if (req->data->flags & MMC_DATA_WRITE) ++ cmdat |= CMDAT_WRITE; ++ ++ if (req->data->flags & MMC_DATA_STREAM) ++ cmdat |= CMDAT_STREAM; ++ } ++ ++ pxamci_start_cmd(host, req->cmd, cmdat); ++} ++ ++static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ++{ ++ struct pxamci_host *host = to_pxamci_host(mmc); ++ ++ DBG("pxamci_set_ios: clock %u power %u vdd %u.%02u\n", ++ ios->clock, ios->power_mode, ios->vdd / 100, ++ ios->vdd % 100); ++ ++ if (ios->clock) { ++ unsigned int clk = CLOCKRATE / ios->clock; ++ if (CLOCKRATE / clk > ios->clock) ++ clk <<= 1; ++ host->clkrt = fls(clk) - 1; ++ ++ /* ++ * we write clkrt on the next command ++ */ ++ } else if (readl(host->base + MMC_STAT) & STAT_CLK_EN) { ++ /* ++ * Ensure that the clock is off. ++ */ ++ writel(STOP_CLOCK, host->base + MMC_STRPCL); ++ } ++ ++ if (host->power_mode != ios->power_mode) { ++ host->power_mode = ios->power_mode; ++ ++ /* ++ * power control? none on the lubbock. ++ */ ++ ++ if (ios->power_mode == MMC_POWER_ON) ++ host->cmdat |= CMDAT_INIT; ++ } ++ ++ DBG("pxamci_set_ios: clkrt = %x cmdat = %x\n", ++ host->clkrt, host->cmdat); ++} ++ ++static struct mmc_host_ops pxamci_ops = { ++ .request = pxamci_request, ++ .set_ios = pxamci_set_ios, ++}; ++ ++static struct resource *platform_device_resource(struct platform_device *dev, unsigned int mask, int nr) ++{ ++ int i; ++ ++ for (i = 0; i < dev->num_resources; i++) ++ if (dev->resource[i].flags == mask && nr-- == 0) ++ return &dev->resource[i]; ++ return NULL; ++} ++ ++static int platform_device_irq(struct platform_device *dev, int nr) ++{ ++ int i; ++ ++ for (i = 0; i < dev->num_resources; i++) ++ if (dev->resource[i].flags == IORESOURCE_IRQ && nr-- == 0) ++ return dev->resource[i].start; ++ return NO_IRQ; ++} ++ ++static void pxamci_dma_irq(int dma, void *devid, struct pt_regs *regs) ++{ ++ printk(KERN_ERR "DMA%d: IRQ???\n", dma); ++ DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; ++} ++ ++static int pxamci_probe(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct pxamci_host *host; ++ struct resource *r; ++ int ret, irq; ++ ++ r = platform_device_resource(pdev, IORESOURCE_MEM, 0); ++ irq = platform_device_irq(pdev, 0); ++ if (!r || irq == NO_IRQ) ++ return -ENXIO; ++ ++ r = request_mem_region(r->start, SZ_4K, "PXAMCI"); ++ if (!r) ++ return -EBUSY; ++ ++ host = kmalloc(sizeof(struct pxamci_host), GFP_KERNEL); ++ if (!host) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ memset(host, 0, sizeof(struct pxamci_host)); ++ host->dma = -1; ++ ++ host->sg_cpu = dma_alloc_coherent(dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); ++ if (!host->sg_cpu) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ret = mmc_init_host(&host->mmc); ++ if (ret) ++ goto out; ++ ++ spin_lock_init(&host->lock); ++ host->res = r; ++ host->irq = irq; ++ host->imask = TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD| ++ END_CMD_RES|PRG_DONE|DATA_TRAN_DONE; ++ host->mmc.dev = dev; ++ host->mmc.ops = &pxamci_ops; ++ host->mmc.f_min = 312500; ++ host->mmc.f_max = 20000000; ++ host->mmc.ocr_avail = MMC_VDD_32_33; ++ ++ host->base = ioremap(r->start, SZ_4K); ++ if (!host->base) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ /* ++ * Ensure that the host controller is shut down, and setup ++ * with our defaults. ++ */ ++ pxamci_stop_clock(host); ++ writel(0, host->base + MMC_SPI); ++ writel(64, host->base + MMC_RESTO); ++ ++#ifdef CONFIG_PREEMPT ++#error Not Preempt-safe ++#endif ++ pxa_gpio_mode(GPIO6_MMCCLK_MD); ++ pxa_gpio_mode(GPIO8_MMCCS0_MD); ++ CKEN |= CKEN12_MMC; ++ ++ host->dma = pxa_request_dma("PXAMCI", DMA_PRIO_LOW, pxamci_dma_irq, host); ++ if (host->dma < 0) ++ goto out; ++ ++ ret = request_irq(host->irq, pxamci_irq, 0, "PXAMCI", host); ++ if (ret) ++ goto out; ++ ++ dev_set_drvdata(dev, host); ++ ++ mmc_add_host(&host->mmc); ++ ++ return 0; ++ ++ out: ++ if (host) { ++ if (host->dma >= 0) ++ pxa_free_dma(host->dma); ++ if (host->base) ++ iounmap(host->base); ++ if (host->sg_cpu) ++ dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); ++ kfree(host); ++ } ++ release_resource(r); ++ return ret; ++} ++ ++static int pxamci_remove(struct device *dev) ++{ ++ struct pxamci_host *host = dev_get_drvdata(dev); ++ ++ dev_set_drvdata(dev, NULL); ++ ++ if (host) { ++ mmc_remove_host(&host->mmc); ++ ++ pxamci_stop_clock(host); ++ writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD| ++ END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, ++ host->base + MMC_I_MASK); ++ ++ free_irq(host->irq, host); ++ pxa_free_dma(host->dma); ++ iounmap(host->base); ++ dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); ++ ++ release_resource(host->res); ++ ++ kfree(host); ++ } ++ return 0; ++} ++ ++static int pxamci_suspend(struct device *dev, u32 state, u32 level) ++{ ++ struct pxamci_host *host = dev_get_drvdata(dev); ++ int ret = 0; ++ ++ if (host && level == SUSPEND_DISABLE) ++ ret = mmc_suspend_host(&host->mmc, state); ++ return ret; ++} ++ ++static int pxamci_resume(struct device *dev, u32 level) ++{ ++ struct pxamci_host *host = dev_get_drvdata(dev); ++ int ret = 0; ++ ++ if (host && level == RESUME_ENABLE) ++ ret = mmc_resume_host(&host->mmc); ++ return ret; ++} ++ ++static struct device_driver pxamci_driver = { ++ .name = "pxamci", ++ .bus = &platform_bus_type, ++ .probe = pxamci_probe, ++ .remove = pxamci_remove, ++ .suspend = pxamci_suspend, ++ .resume = pxamci_resume, ++}; ++ ++static int __init pxamci_init(void) ++{ ++ return driver_register(&pxamci_driver); ++} ++ ++static void __exit pxamci_exit(void) ++{ ++ driver_unregister(&pxamci_driver); ++} ++ ++module_init(pxamci_init); ++module_exit(pxamci_exit); ++ ++MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver"); ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/media/mmc/mmc.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,15 @@ ++/* ++ * linux/drivers/media/mmc/mmc.h ++ * ++ * Copyright (C) 2003 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. ++ */ ++#ifndef _MMC_H ++/* core-internal functions */ ++void mmc_init_card(struct mmc_card *card, struct mmc_host *host); ++int mmc_register_card(struct mmc_card *card); ++void mmc_remove_card(struct mmc_card *card); ++#endif +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/media/mmc/mmc_sysfs.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,231 @@ ++/* ++ * linux/drivers/media/mmc/mmc_sysfs.c ++ * ++ * Copyright (C) 2003 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. ++ * ++ * MMC sysfs/driver model support. ++ */ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/device.h> ++ ++#include <linux/mmc/card.h> ++#include <linux/mmc/host.h> ++ ++#include "mmc.h" ++ ++#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) ++#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) ++ ++static void mmc_release_card(struct device *dev) ++{ ++ struct mmc_card *card = dev_to_mmc_card(dev); ++ ++ kfree(card); ++} ++ ++/* ++ * This currently matches any MMC driver to any MMC card - drivers ++ * themselves make the decision whether to drive this card in their ++ * probe method. ++ */ ++static int mmc_bus_match(struct device *dev, struct device_driver *drv) ++{ ++ return 1; ++} ++ ++static int ++mmc_bus_hotplug(struct device *dev, char **envp, int num_envp, char *buf, ++ int buf_size) ++{ ++ struct mmc_card *card = dev_to_mmc_card(dev); ++ char ccc[13]; ++ int i = 0; ++ ++#define add_env(fmt,val) \ ++ ({ \ ++ int len, ret = -ENOMEM; \ ++ if (i < num_envp) { \ ++ envp[i++] = buf; \ ++ len = snprintf(buf, buf_size, fmt, val) + 1; \ ++ buf_size -= len; \ ++ buf += len; \ ++ if (buf_size >= 0) \ ++ ret = 0; \ ++ } \ ++ ret; \ ++ }) ++ ++ for (i = 0; i < 12; i++) ++ ccc[i] = card->csd.cmdclass & (1 << i) ? '1' : '0'; ++ ccc[12] = '\0'; ++ ++ i = 0; ++ add_env("MMC_CCC=%s", ccc); ++ add_env("MMC_MANFID=%03x", card->cid.manfid); ++ add_env("MMC_SLOT_NAME=%s", card->dev.bus_id); ++ ++ return 0; ++} ++ ++static int mmc_bus_suspend(struct device *dev, u32 state) ++{ ++ struct mmc_driver *drv = to_mmc_driver(dev->driver); ++ struct mmc_card *card = dev_to_mmc_card(dev); ++ int ret = 0; ++ ++ if (dev->driver && drv->suspend) ++ ret = drv->suspend(card, state); ++ return ret; ++} ++ ++static int mmc_bus_resume(struct device *dev) ++{ ++ struct mmc_driver *drv = to_mmc_driver(dev->driver); ++ struct mmc_card *card = dev_to_mmc_card(dev); ++ int ret = 0; ++ ++ if (dev->driver && drv->resume) ++ ret = drv->resume(card); ++ return ret; ++} ++ ++static struct bus_type mmc_bus_type = { ++ .name = "mmc", ++ .match = mmc_bus_match, ++ .hotplug = mmc_bus_hotplug, ++ .suspend = mmc_bus_suspend, ++ .resume = mmc_bus_resume, ++}; ++ ++ ++static int mmc_drv_probe(struct device *dev) ++{ ++ struct mmc_driver *drv = to_mmc_driver(dev->driver); ++ struct mmc_card *card = dev_to_mmc_card(dev); ++ ++ return drv->probe(card); ++} ++ ++static int mmc_drv_remove(struct device *dev) ++{ ++ struct mmc_driver *drv = to_mmc_driver(dev->driver); ++ struct mmc_card *card = dev_to_mmc_card(dev); ++ ++ drv->remove(card); ++ ++ return 0; ++} ++ ++ ++/** ++ * mmc_register_driver - register a media driver ++ * @drv: MMC media driver ++ */ ++int mmc_register_driver(struct mmc_driver *drv) ++{ ++ drv->drv.bus = &mmc_bus_type; ++ drv->drv.probe = mmc_drv_probe; ++ drv->drv.remove = mmc_drv_remove; ++ return driver_register(&drv->drv); ++} ++ ++EXPORT_SYMBOL(mmc_register_driver); ++ ++/** ++ * mmc_unregister_driver - unregister a media driver ++ * @drv: MMC media driver ++ */ ++void mmc_unregister_driver(struct mmc_driver *drv) ++{ ++ drv->drv.bus = &mmc_bus_type; ++ driver_unregister(&drv->drv); ++} ++ ++EXPORT_SYMBOL(mmc_unregister_driver); ++ ++ ++#define MMC_ATTR(name, fmt, args...) \ ++static ssize_t mmc_dev_show_##name (struct device *dev, char *buf) \ ++{ \ ++ struct mmc_card *card = dev_to_mmc_card(dev); \ ++ return sprintf(buf, fmt, args); \ ++} \ ++static DEVICE_ATTR(name, S_IRUGO, mmc_dev_show_##name, NULL) ++ ++MMC_ATTR(date, "%02d/%04d\n", card->cid.month, 1997 + card->cid.year); ++MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev); ++MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev); ++MMC_ATTR(manfid, "0x%03x\n", card->cid.manfid); ++MMC_ATTR(serial, "0x%06x\n", card->cid.serial); ++MMC_ATTR(name, "%s\n", card->cid.prod_name); ++ ++static struct device_attribute *mmc_dev_attributes[] = { ++ &dev_attr_date, ++ &dev_attr_fwrev, ++ &dev_attr_hwrev, ++ &dev_attr_manfid, ++ &dev_attr_serial, ++ &dev_attr_name, ++}; ++ ++/* ++ * Internal function. Initialise a MMC card structure. ++ */ ++void mmc_init_card(struct mmc_card *card, struct mmc_host *host) ++{ ++ memset(card, 0, sizeof(struct mmc_card)); ++ card->host = host; ++ device_initialize(&card->dev); ++ card->dev.parent = card->host->dev; ++ card->dev.bus = &mmc_bus_type; ++ card->dev.release = mmc_release_card; ++} ++ ++/* ++ * Internal function. Register a new MMC card with the driver model. ++ */ ++int mmc_register_card(struct mmc_card *card) ++{ ++ int ret, i; ++ ++ snprintf(card->dev.bus_id, sizeof(card->dev.bus_id), ++ "mmc%02x:%04x", card->host->host_num, card->rca); ++ ++ ret = device_add(&card->dev); ++ if (ret == 0) ++ for (i = 0; i < ARRAY_SIZE(mmc_dev_attributes); i++) ++ device_create_file(&card->dev, mmc_dev_attributes[i]); ++ ++ return ret; ++} ++ ++/* ++ * Internal function. Unregister a new MMC card with the ++ * driver model, and (eventually) free it. ++ */ ++void mmc_remove_card(struct mmc_card *card) ++{ ++ if (mmc_card_present(card)) ++ device_del(&card->dev); ++ ++ put_device(&card->dev); ++} ++ ++ ++static int __init mmc_init(void) ++{ ++ return bus_register(&mmc_bus_type); ++} ++ ++static void __exit mmc_exit(void) ++{ ++ bus_unregister(&mmc_bus_type); ++} ++ ++module_init(mmc_init); ++module_exit(mmc_exit); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/media/mmc/mmci.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,445 @@ ++/* ++ * linux/drivers/media/mmc/mmci.c - ARM PrimeCell MMCI PL180/1 driver ++ * ++ * Copyright (C) 2003 Deep Blue Solutions, Ltd, 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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/init.h> ++#include <linux/ioport.h> ++#include <linux/device.h> ++#include <linux/interrupt.h> ++#include <linux/blkdev.h> ++#include <linux/delay.h> ++#include <linux/mmc/host.h> ++#include <linux/mmc/protocol.h> ++ ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/hardware/amba.h> ++ ++#include "mmci.h" ++ ++#define DRIVER_NAME "mmci-pl18x" ++ ++#ifdef CONFIG_MMC_DEBUG ++#define DBG(x...) printk(KERN_DEBUG x) ++#else ++#define DBG(x...) do { } while (0) ++#endif ++ ++static int fmax = 515633; ++ ++static void ++mmci_request_end(struct mmci_host *host, struct mmc_request *req) ++{ ++ writel(0, host->base + MMCICOMMAND); ++ host->req = NULL; ++ host->cmd = NULL; ++ host->data = NULL; ++ ++ if (req->data) ++ req->data->bytes_xfered = host->data_xfered; ++ ++ mmc_request_done(&host->mmc, req); ++} ++ ++static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) ++{ ++ unsigned int datactrl; ++ ++ DBG("MMCI: data: blksz %04x blks %04x flags %08x\n", ++ 1 << data->blksz_bits, data->blocks, data->flags); ++ ++ datactrl = MCI_DPSM_ENABLE | data->blksz_bits << 4; ++ ++ if (data->flags & MMC_DATA_READ) ++ datactrl |= MCI_DPSM_DIRECTION; ++ ++ host->data = data; ++ host->buffer = data->rq->buffer; ++ host->size = data->blocks << data->blksz_bits; ++ host->data_xfered = 0; ++ ++ writel(0x800000, host->base + MMCIDATATIMER); ++ writel(host->size, host->base + MMCIDATALENGTH); ++ writel(datactrl, host->base + MMCIDATACTRL); ++} ++ ++static void ++mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) ++{ ++ DBG("MMCI: cmd: op %02x arg %08x flags %08x\n", ++ cmd->opcode, cmd->arg, cmd->flags); ++ ++ if (readl(host->base + MMCICOMMAND) & MCI_CPSM_ENABLE) { ++ writel(0, host->base + MMCICOMMAND); ++ udelay(1); ++ } ++ ++ c |= cmd->opcode | MCI_CPSM_ENABLE; ++ switch (cmd->flags & MMC_RSP_MASK) { ++ case MMC_RSP_NONE: ++ default: ++ break; ++ case MMC_RSP_LONG: ++ c |= MCI_CPSM_LONGRSP; ++ case MMC_RSP_SHORT: ++ c |= MCI_CPSM_RESPONSE; ++ break; ++ } ++ if (/*interrupt*/0) ++ c |= MCI_CPSM_INTERRUPT; ++ ++ host->cmd = cmd; ++ ++ writel(cmd->arg, host->base + MMCIARGUMENT); ++ writel(c, host->base + MMCICOMMAND); ++} ++ ++static void ++mmci_data_irq(struct mmci_host *host, struct mmc_data *data, ++ unsigned int status) ++{ ++ if (status & MCI_DATABLOCKEND) { ++ host->data_xfered += 1 << data->blksz_bits; ++ } ++ if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { ++ if (status & MCI_DATACRCFAIL) ++ data->error = MMC_ERR_BADCRC; ++ else if (status & MCI_DATATIMEOUT) ++ data->error = MMC_ERR_TIMEOUT; ++ else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) ++ data->error = MMC_ERR_FIFO; ++ status |= MCI_DATAEND; ++ } ++ if (status & MCI_DATAEND) { ++ host->data = NULL; ++ if (!data->stop) { ++ mmci_request_end(host, data->req); ++ } else /*if (readl(host->base + MMCIDATACNT) > 6)*/ { ++ mmci_start_command(host, data->stop, 0); ++ } ++ } ++} ++ ++static void ++mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, ++ unsigned int status) ++{ ++ host->cmd = NULL; ++ ++ cmd->resp[0] = readl(host->base + MMCIRESPONSE0); ++ cmd->resp[1] = readl(host->base + MMCIRESPONSE1); ++ cmd->resp[2] = readl(host->base + MMCIRESPONSE2); ++ cmd->resp[3] = readl(host->base + MMCIRESPONSE3); ++ ++ if (status & MCI_CMDTIMEOUT) { ++ cmd->error = MMC_ERR_TIMEOUT; ++ } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { ++ cmd->error = MMC_ERR_BADCRC; ++ } ++ ++ if (!cmd->data || cmd->error != MMC_ERR_NONE) { ++ mmci_request_end(host, cmd->req); ++ } else if (!(cmd->data->flags & MMC_DATA_READ)) { ++ mmci_start_data(host, cmd->data); ++ } ++} ++ ++static irqreturn_t mmci_irq(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ struct mmci_host *host = dev_id; ++ u32 status; ++ int ret = 0; ++ ++ do { ++ struct mmc_command *cmd; ++ struct mmc_data *data; ++ ++ status = readl(host->base + MMCISTATUS); ++ writel(status, host->base + MMCICLEAR); ++ ++ if (!(status & MCI_IRQMASK)) ++ break; ++ ++ DBG("MMCI: irq %08x\n", status); ++ ++ if (status & (MCI_RXDATAAVLBL|MCI_RXFIFOHALFFULL)) { ++ int count = host->size - (readl(host->base + MMCIFIFOCNT) << 2); ++ if (count < 0) ++ count = 0; ++ if (count && host->buffer) { ++ readsl(host->base + MMCIFIFO, host->buffer, count >> 2); ++ host->buffer += count; ++ host->size -= count; ++ if (host->size == 0) ++ host->buffer = NULL; ++ } else { ++ static int first = 1; ++ if (first) { ++ first = 0; ++ printk(KERN_ERR "MMCI: sinking excessive data\n"); ++ } ++ readl(host->base + MMCIFIFO); ++ } ++ } ++ if (status & (MCI_TXFIFOEMPTY|MCI_TXFIFOHALFEMPTY)) { ++ int count = host->size; ++ if (count > MCI_FIFOHALFSIZE) ++ count = MCI_FIFOHALFSIZE; ++ if (count && host->buffer) { ++ writesl(host->base + MMCIFIFO, host->buffer, count >> 2); ++ host->buffer += count; ++ host->size -= count; ++ if (host->size == 0) ++ host->buffer = NULL; ++ } else { ++ static int first = 1; ++ if (first) { ++ first = 0; ++ printk(KERN_ERR "MMCI: ran out of source data\n"); ++ } ++ } ++ } ++ ++ data = host->data; ++ if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN| ++ MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND)) ++ mmci_data_irq(host, data, status); ++ ++ cmd = host->cmd; ++ if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd) ++ mmci_cmd_irq(host, cmd, status); ++ ++ ret = 1; ++ } while (status); ++ ++ return IRQ_RETVAL(ret); ++} ++ ++static void mmci_request(struct mmc_host *mmc, struct mmc_request *req) ++{ ++ struct mmci_host *host = to_mmci_host(mmc); ++ ++ WARN_ON(host->req != NULL); ++ ++ host->req = req; ++ ++ if (req->data && req->data->flags & MMC_DATA_READ) ++ mmci_start_data(host, req->data); ++ ++ mmci_start_command(host, req->cmd, 0); ++} ++ ++static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ++{ ++ struct mmci_host *host = to_mmci_host(mmc); ++ u32 clk = 0, pwr = 0; ++ ++ DBG("MMCI: set_ios: clock %dHz busmode %d powermode %d Vdd %d.%02d\n", ++ ios->clock, ios->bus_mode, ios->power_mode, ++ ios->vdd / 100, ios->vdd % 100); ++ ++ if (ios->clock) { ++ clk = host->mclk / (2 * ios->clock) - 1; ++ if (clk > 256) ++ clk = 255; ++ clk |= MCI_CLK_ENABLE; ++ } ++ ++ switch (ios->power_mode) { ++ case MMC_POWER_OFF: ++ break; ++ case MMC_POWER_UP: ++ pwr |= MCI_PWR_UP; ++ break; ++ case MMC_POWER_ON: ++ pwr |= MCI_PWR_ON; ++ break; ++ } ++ ++ if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) ++ pwr |= MCI_ROD; ++ ++ writel(clk, host->base + MMCICLOCK); ++ ++ if (host->pwr != pwr) { ++ host->pwr = pwr; ++ writel(pwr, host->base + MMCIPOWER); ++ } ++} ++ ++static struct mmc_host_ops mmci_ops = { ++ .request = mmci_request, ++ .set_ios = mmci_set_ios, ++}; ++ ++static int mmci_probe(struct amba_device *dev, void *id) ++{ ++ struct mmci_host *host; ++ int ret; ++// void *tmp; ++ ++ /* enable the interrupt via the VIC */ ++// tmp = ioremap(0xc3000000, SZ_4K); ++// if (tmp) { ++// u32 val = readl(tmp + 0x10); ++// writel(val | 0x180, tmp + 0x10); ++// iounmap(tmp); ++// } ++ ++ if (!request_mem_region(dev->res.start, SZ_4K, DRIVER_NAME)) ++ return -EBUSY; ++ ++ host = kmalloc(sizeof(struct mmci_host), GFP_KERNEL); ++ if (!host) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ memset(host, 0, sizeof(struct mmci_host)); ++ ++ ret = mmc_init_host(&host->mmc); ++ if (ret) ++ goto out; ++ ++ host->base = ioremap(dev->res.start, SZ_4K); ++ if (!host->base) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ host->irq = dev->irq; ++ host->mclk = 33000000; /* impd1 */ ++ host->mmc.dev = &dev->dev; ++ host->mmc.ops = &mmci_ops; ++ host->mmc.f_min = (host->mclk + 511) / 512; ++ host->mmc.f_max = host->mclk / 2; ++ if (host->mmc.f_max > fmax) ++ host->mmc.f_max = fmax; ++ ++ host->mmc.ocr_avail = MMC_VDD_35_36; ++ ++ writel(0, host->base + MMCIMASK0); ++ writel(0, host->base + MMCIMASK1); ++ writel(0xfff, host->base + MMCICLEAR); ++ ++ ret = request_irq(host->irq, mmci_irq, SA_SHIRQ, DRIVER_NAME, host); ++ if (ret) ++ goto out; ++ ++ writel(MCI_IRQENABLE, host->base + MMCIMASK0); ++ ++ amba_set_drvdata(dev, host); ++ ++ mmc_add_host(&host->mmc); ++ ++ return 0; ++ ++ out: ++ if (host) { ++ if (host->base) ++ iounmap(host->base); ++ kfree(host); ++ } ++ release_mem_region(dev->res.start, SZ_4K); ++ return ret; ++} ++ ++static int mmci_remove(struct amba_device *dev) ++{ ++ struct mmci_host *host = amba_get_drvdata(dev); ++ ++ amba_set_drvdata(dev, NULL); ++ ++ if (host) { ++ mmc_remove_host(&host->mmc); ++ ++ writel(0, host->base + MMCIMASK0); ++ writel(0, host->base + MMCIMASK1); ++ ++ writel(0, host->base + MMCICOMMAND); ++ writel(0, host->base + MMCIDATACTRL); ++ ++ free_irq(host->irq, host); ++ ++ iounmap(host->base); ++ ++ kfree(host); ++ ++ release_mem_region(dev->res.start, SZ_4K); ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int mmci_suspend(struct amba_device *dev, u32 state) ++{ ++ struct mmci_host *host = amba_get_drvdata(dev); ++ ++ return host ? mmc_suspend_host(&host->mmc, state) : 0; ++} ++ ++static int mmci_resume(struct amba_device *dev) ++{ ++ struct mmci_host *host = amba_get_drvdata(dev); ++ int ret = 0; ++ ++ if (host) { ++ writel(MCI_IRQENABLE, host->base + MMCIMASK0); ++ ret = mmc_resume_host(&host->mmc); ++ } ++ ++ return ret; ++} ++#else ++#define mmci_suspend NULL ++#define mmci_resume NULL ++#endif ++ ++static struct amba_id mmci_ids[] = { ++ { ++ .id = 0x00041180, ++ .mask = 0x000fffff, ++ }, ++ { ++ .id = 0x00041181, ++ .mask = 0x000fffff, ++ }, ++ { 0, 0 }, ++}; ++ ++static struct amba_driver mmci_driver = { ++ .drv = { ++ .name = DRIVER_NAME, ++ }, ++ .probe = mmci_probe, ++ .remove = mmci_remove, ++ .suspend = mmci_suspend, ++ .resume = mmci_resume, ++ .id_table = mmci_ids, ++}; ++ ++static int __init mmci_init(void) ++{ ++ return amba_driver_register(&mmci_driver); ++} ++ ++static void __exit mmci_exit(void) ++{ ++ amba_driver_unregister(&mmci_driver); ++} ++ ++module_init(mmci_init); ++module_exit(mmci_exit); ++module_param(fmax, int, 0444); ++ ++MODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver"); ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/media/mmc/mmc_queue.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,29 @@ ++#ifndef MMC_QUEUE_H ++#define MMC_QUEUE_H ++ ++struct request; ++struct task_struct; ++ ++struct mmc_queue { ++ struct mmc_card *card; ++ struct completion thread_complete; ++ wait_queue_head_t thread_wq; ++ struct task_struct *thread; ++ struct request *req; ++ int (*prep_fn)(struct mmc_queue *, struct request *); ++ int (*issue_fn)(struct mmc_queue *, struct request *); ++ void *data; ++ struct request_queue *queue; ++}; ++ ++struct mmc_io_request { ++ struct request *rq; ++ int num; ++ struct mmc_command selcmd; /* mmc_queue private */ ++ struct mmc_command cmd[4]; /* max 4 commands */ ++}; ++ ++extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *); ++extern void mmc_cleanup_queue(struct mmc_queue *); ++ ++#endif +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/media/mmc/mmc_block.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,482 @@ ++/* ++ * Block driver for media (i.e., flash cards) ++ * ++ * Copyright 2002 Hewlett-Packard Company ++ * ++ * Use consistent with the GNU GPL is permitted, ++ * provided that this copyright notice is ++ * preserved in its entirety in all copies and derived works. ++ * ++ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, ++ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS ++ * FITNESS FOR ANY PARTICULAR PURPOSE. ++ * ++ * Many thanks to Alessandro Rubini and Jonathan Corbet! ++ * ++ * Author: Andrew Christian ++ * 28 May 2002 ++ */ ++#include <linux/moduleparam.h> ++#include <linux/module.h> ++#include <linux/init.h> ++ ++#include <linux/sched.h> ++#include <linux/kernel.h> /* printk() */ ++#include <linux/fs.h> /* everything... */ ++#include <linux/errno.h> /* error codes */ ++#include <linux/hdreg.h> /* HDIO_GETGEO */ ++#include <linux/kdev_t.h> ++#include <linux/blkdev.h> ++#include <linux/devfs_fs_kernel.h> ++ ++#include <linux/mmc/card.h> ++#include <linux/mmc/protocol.h> ++ ++#include <asm/system.h> ++#include <asm/uaccess.h> ++ ++#include "mmc_queue.h" ++ ++#define MMC_SHIFT 3 /* max 8 partitions per card */ ++ ++static int mmc_major; ++static int maxsectors = 8; ++ ++/* ++ * There is one mmc_blk_data per slot. ++ */ ++struct mmc_blk_data { ++ spinlock_t lock; ++ struct gendisk *disk; ++ struct mmc_queue queue; ++ ++ unsigned int usage; ++ unsigned int block_bits; ++ unsigned int suspended; ++}; ++ ++static DECLARE_MUTEX(open_lock); ++ ++static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk) ++{ ++ struct mmc_blk_data *md; ++ ++ down(&open_lock); ++ md = disk->private_data; ++ if (md && md->usage == 0) ++ md = NULL; ++ if (md) ++ md->usage++; ++ up(&open_lock); ++ ++ return md; ++} ++ ++static void mmc_blk_put(struct mmc_blk_data *md) ++{ ++ down(&open_lock); ++ md->usage--; ++ if (md->usage == 0) { ++ put_disk(md->disk); ++ mmc_cleanup_queue(&md->queue); ++ kfree(md); ++ } ++ up(&open_lock); ++} ++ ++static int mmc_blk_open(struct inode *inode, struct file *filp) ++{ ++ struct mmc_blk_data *md; ++ int ret = -ENXIO; ++ ++ md = mmc_blk_get(inode->i_bdev->bd_disk); ++ if (md) { ++ if (md->usage == 2) ++ check_disk_change(inode->i_bdev); ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++static int mmc_blk_release(struct inode *inode, struct file *filp) ++{ ++ struct mmc_blk_data *md = inode->i_bdev->bd_disk->private_data; ++ ++ mmc_blk_put(md); ++ return 0; ++} ++ ++static int ++mmc_blk_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ struct block_device *bdev = inode->i_bdev; ++ ++ if (cmd == HDIO_GETGEO) { ++ struct hd_geometry geo; ++ ++ memset(&geo, 0, sizeof(struct hd_geometry)); ++ ++ geo.cylinders = get_capacity(bdev->bd_disk) / (4 * 16); ++ geo.heads = 4; ++ geo.sectors = 16; ++ geo.start = get_start_sect(bdev); ++ ++ return copy_to_user((void *)arg, &geo, sizeof(geo)) ++ ? -EFAULT : 0; ++ } ++ ++ return -ENOTTY; ++} ++ ++static struct block_device_operations mmc_bdops = { ++ .open = mmc_blk_open, ++ .release = mmc_blk_release, ++ .ioctl = mmc_blk_ioctl, ++ .owner = THIS_MODULE, ++}; ++ ++struct mmc_blk_request { ++ struct mmc_request req; ++ struct mmc_command cmd; ++ struct mmc_command stop; ++ struct mmc_data data; ++}; ++ ++static int mmc_blk_prep_rq(struct mmc_queue *mq, struct request *req) ++{ ++ struct mmc_blk_data *md = mq->data; ++ ++ /* ++ * If we have no device, we haven't finished initialising. ++ */ ++ if (!md || !mq->card) { ++ printk("killing request - no device/host\n"); ++ goto kill; ++ } ++ ++ if (md->suspended) { ++ blk_plug_device(md->queue.queue); ++ goto defer; ++ } ++ ++ /* ++ * Check for excessive requests. ++ */ ++ if (req->sector + req->nr_sectors > get_capacity(req->rq_disk)) { ++ printk("bad request size\n"); ++ goto kill; ++ } ++ ++ return BLKPREP_OK; ++ ++ defer: ++ return BLKPREP_DEFER; ++ kill: ++ return BLKPREP_KILL; ++} ++ ++static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ++{ ++ struct mmc_blk_data *md = mq->data; ++ struct mmc_card *card = md->queue.card; ++ int err, sz = 0; ++ ++ err = mmc_card_claim_host(card); ++ if (err) ++ goto cmd_err; ++ ++ do { ++ struct mmc_blk_request rq; ++ struct mmc_command cmd; ++ ++ memset(&rq, 0, sizeof(struct mmc_blk_request)); ++ rq.req.cmd = &rq.cmd; ++ rq.req.data = &rq.data; ++ ++ rq.cmd.arg = req->sector << 9; ++ rq.cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC; ++ rq.data.rq = req; ++ rq.data.timeout_ns = card->csd.tacc_ns * 10; ++ rq.data.timeout_clks = card->csd.tacc_clks * 10; ++ rq.data.blksz_bits = md->block_bits; ++ rq.data.blocks = req->current_nr_sectors >> (md->block_bits - 9); ++ rq.stop.opcode = MMC_STOP_TRANSMISSION; ++ rq.stop.arg = 0; ++ rq.stop.flags = MMC_RSP_SHORT | MMC_RSP_CRC | MMC_RSP_BUSY; ++ ++ if (rq_data_dir(req) == READ) { ++ rq.cmd.opcode = rq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK; ++ rq.data.flags |= MMC_DATA_READ; ++ } else { ++ rq.cmd.opcode = MMC_WRITE_BLOCK; ++ rq.cmd.flags |= MMC_RSP_BUSY; ++ rq.data.flags |= MMC_DATA_WRITE; ++ rq.data.blocks = 1; ++ } ++ rq.req.stop = rq.data.blocks > 1 ? &rq.stop : NULL; ++ ++ mmc_wait_for_req(card->host, &rq.req); ++ if (rq.cmd.error) { ++ err = rq.cmd.error; ++ printk("error %d sending read/write command\n", err); ++ goto cmd_err; ++ } ++ ++ if (rq_data_dir(req) == READ) { ++ sz = rq.data.bytes_xfered; ++ } else { ++ sz = 0; ++ } ++ ++ if (rq.data.error) { ++ err = rq.data.error; ++ printk("error %d transferring data\n", err); ++ goto cmd_err; ++ } ++ ++ if (rq.stop.error) { ++ err = rq.stop.error; ++ printk("error %d sending stop command\n", err); ++ goto cmd_err; ++ } ++ ++ do { ++ cmd.opcode = MMC_SEND_STATUS; ++ cmd.arg = card->rca << 16; ++ cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC; ++ err = mmc_wait_for_cmd(card->host, &cmd, 5); ++ if (err) { ++ printk("error %d requesting status\n", err); ++ goto cmd_err; ++ } ++ } while (!(cmd.resp[0] & R1_READY_FOR_DATA)); ++ ++#if 0 ++ if (cmd.resp[0] & ~0x00000900) ++ printk("status = %08x\n", cmd.resp[0]); ++ err = mmc_decode_status(cmd.resp); ++ if (err) ++ goto cmd_err; ++#endif ++ ++ sz = rq.data.bytes_xfered; ++ } while (end_that_request_chunk(req, 1, sz)); ++ ++ mmc_card_release_host(card); ++ ++ return 1; ++ ++ cmd_err: ++ mmc_card_release_host(card); ++ ++ end_that_request_chunk(req, 1, sz); ++ req->errors = err; ++ ++ return 0; ++} ++ ++#define MMC_NUM_MINORS (256 >> MMC_SHIFT) ++ ++static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))]; ++ ++static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) ++{ ++ struct mmc_blk_data *md; ++ int devidx; ++ ++ devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS); ++ if (devidx >= MMC_NUM_MINORS) ++ return NULL; ++ __set_bit(devidx, dev_use); ++ ++ md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL); ++ if (md) { ++ memset(md, 0, sizeof(struct mmc_blk_data)); ++ ++ md->disk = alloc_disk(1 << MMC_SHIFT); ++ if (md->disk == NULL) { ++ kfree(md); ++ md = NULL; ++ goto out; ++ } ++ ++ spin_lock_init(&md->lock); ++ md->usage = 1; ++ ++ mmc_init_queue(&md->queue, card, &md->lock); ++ md->queue.prep_fn = mmc_blk_prep_rq; ++ md->queue.issue_fn = mmc_blk_issue_rq; ++ md->queue.data = md; ++ ++ md->disk->major = mmc_major; ++ md->disk->first_minor = devidx << MMC_SHIFT; ++ md->disk->fops = &mmc_bdops; ++ md->disk->private_data = md; ++ md->disk->queue = md->queue.queue; ++ md->disk->driverfs_dev = &card->dev; ++ ++ sprintf(md->disk->disk_name, "mmcblk%d", devidx); ++ sprintf(md->disk->devfs_name, "mmc/blk%d", devidx); ++ ++ md->block_bits = md->queue.card->csd.read_blkbits; ++ ++ blk_queue_max_sectors(md->queue.queue, maxsectors); ++ blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits); ++ set_capacity(md->disk, md->queue.card->csd.capacity); ++ } ++ out: ++ return md; ++} ++ ++static int ++mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) ++{ ++ struct mmc_command cmd; ++ int err; ++ ++ mmc_card_claim_host(card); ++ cmd.opcode = MMC_SET_BLOCKLEN; ++ cmd.arg = 1 << card->csd.read_blkbits; ++ cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC; ++ err = mmc_wait_for_cmd(card->host, &cmd, 5); ++ mmc_card_release_host(card); ++ ++ if (err) { ++ printk(KERN_ERR "%s: unable to set block size to %d: %d\n", ++ md->disk->disk_name, cmd.arg, err); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int mmc_blk_probe(struct mmc_card *card) ++{ ++ struct mmc_blk_data *md; ++ int err; ++ ++ if (card->csd.cmdclass & ~0x1ff) ++ return -ENODEV; ++ ++ if (card->csd.read_blkbits < 9) { ++ printk(KERN_WARNING "%s: read blocksize too small (%u)\n", ++ mmc_card_id(card), 1 << card->csd.read_blkbits); ++ return -ENODEV; ++ } ++ ++ md = mmc_blk_alloc(card); ++ if (md == NULL) ++ return -ENOMEM; ++ ++ err = mmc_blk_set_blksize(md, card); ++ if (err) ++ goto out; ++ ++ printk(KERN_INFO "%s: %s %s %dKiB\n", ++ md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), ++ (card->csd.capacity << card->csd.read_blkbits) / 1024); ++ ++ mmc_set_drvdata(card, md); ++ add_disk(md->disk); ++ return 0; ++ ++ out: ++ mmc_blk_put(md); ++ ++ return err; ++} ++ ++static void mmc_blk_remove(struct mmc_card *card) ++{ ++ struct mmc_blk_data *md = mmc_get_drvdata(card); ++ ++ if (md) { ++ int devidx; ++ ++ del_gendisk(md->disk); ++ ++ /* ++ * I think this is needed. ++ */ ++ md->disk->queue = NULL; ++ ++ devidx = md->disk->first_minor >> MMC_SHIFT; ++ __clear_bit(devidx, dev_use); ++ ++ mmc_blk_put(md); ++ } ++ mmc_set_drvdata(card, NULL); ++} ++ ++#ifdef CONFIG_PM ++static int mmc_blk_suspend(struct mmc_card *card, u32 state) ++{ ++ struct mmc_blk_data *md = mmc_get_drvdata(card); ++ ++ if (md) { ++ blk_stop_queue(md->queue.queue); ++ } ++ return 0; ++} ++ ++static int mmc_blk_resume(struct mmc_card *card) ++{ ++ struct mmc_blk_data *md = mmc_get_drvdata(card); ++ ++ if (md) { ++ mmc_blk_set_blksize(md, md->queue.card); ++ blk_start_queue(md->queue.queue); ++ } ++ return 0; ++} ++#else ++#define mmc_blk_suspend NULL ++#define mmc_blk_resume NULL ++#endif ++ ++static struct mmc_driver mmc_driver = { ++ .drv = { ++ .name = "mmcblk", ++ }, ++ .probe = mmc_blk_probe, ++ .remove = mmc_blk_remove, ++ .suspend = mmc_blk_suspend, ++ .resume = mmc_blk_resume, ++}; ++ ++static int __init mmc_blk_init(void) ++{ ++ int res = -ENOMEM; ++ ++ res = register_blkdev(mmc_major, "mmc"); ++ if (res < 0) { ++ printk(KERN_WARNING "Unable to get major %d for MMC media: %d\n", ++ mmc_major, res); ++ goto out; ++ } ++ if (mmc_major == 0) ++ mmc_major = res; ++ ++ devfs_mk_dir("mmc"); ++ return mmc_register_driver(&mmc_driver); ++ ++ out: ++ return res; ++} ++ ++static void __exit mmc_blk_exit(void) ++{ ++ mmc_unregister_driver(&mmc_driver); ++ devfs_remove("mmc"); ++ unregister_blkdev(mmc_major, "mmc"); ++} ++ ++module_init(mmc_blk_init); ++module_exit(mmc_blk_exit); ++module_param(maxsectors, int, 0444); ++ ++MODULE_PARM_DESC(maxsectors, "Maximum number of sectors for a single request"); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver"); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/media/mmc/pxamci.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,94 @@ ++#undef MMC_STRPCL ++#undef MMC_STAT ++#undef MMC_CLKRT ++#undef MMC_SPI ++#undef MMC_CMDAT ++#undef MMC_RESTO ++#undef MMC_RDTO ++#undef MMC_BLKLEN ++#undef MMC_NOB ++#undef MMC_PRTBUF ++#undef MMC_I_MASK ++#undef END_CMD_RES ++#undef PRG_DONE ++#undef DATA_TRAN_DONE ++#undef MMC_I_REG ++#undef MMC_CMD ++#undef MMC_ARGH ++#undef MMC_ARGL ++#undef MMC_RES ++#undef MMC_RXFIFO ++#undef MMC_TXFIFO ++ ++#define MMC_STRPCL 0x0000 ++#define STOP_CLOCK (1 << 0) ++#define START_CLOCK (2 << 0) ++ ++#define MMC_STAT 0x0004 ++#define STAT_END_CMD_RES (1 << 13) ++#define STAT_PRG_DONE (1 << 12) ++#define STAT_DATA_TRAN_DONE (1 << 11) ++#define STAT_CLK_EN (1 << 8) ++#define STAT_RECV_FIFO_FULL (1 << 7) ++#define STAT_XMIT_FIFO_EMPTY (1 << 6) ++#define STAT_RES_CRC_ERR (1 << 5) ++#define STAT_SPI_READ_ERROR_TOKEN (1 << 4) ++#define STAT_CRC_READ_ERROR (1 << 3) ++#define STAT_CRC_WRITE_ERROR (1 << 2) ++#define STAT_TIME_OUT_RESPONSE (1 << 1) ++#define STAT_READ_TIME_OUT (1 << 0) ++ ++#define MMC_CLKRT 0x0008 /* 3 bit */ ++ ++#define MMC_SPI 0x000c ++#define SPI_CS_ADDRESS (1 << 3) ++#define SPI_CS_EN (1 << 2) ++#define CRC_ON (1 << 1) ++#define SPI_EN (1 << 0) ++ ++#define MMC_CMDAT 0x0010 ++#define CMDAT_DMAEN (1 << 7) ++#define CMDAT_INIT (1 << 6) ++#define CMDAT_BUSY (1 << 5) ++#define CMDAT_STREAM (1 << 4) /* 1 = stream */ ++#define CMDAT_WRITE (1 << 3) /* 1 = write */ ++#define CMDAT_DATAEN (1 << 2) ++#define CMDAT_RESP_NONE (0 << 0) ++#define CMDAT_RESP_SHORT (1 << 0) ++#define CMDAT_RESP_R2 (2 << 0) ++#define CMDAT_RESP_R3 (3 << 0) ++ ++#define MMC_RESTO 0x0014 /* 7 bit */ ++ ++#define MMC_RDTO 0x0018 /* 16 bit */ ++ ++#define MMC_BLKLEN 0x001c /* 10 bit */ ++ ++#define MMC_NOB 0x0020 /* 16 bit */ ++ ++#define MMC_PRTBUF 0x0024 ++#define BUF_PART_FULL (1 << 0) ++ ++#define MMC_I_MASK 0x0028 ++#define TXFIFO_WR_REQ (1 << 6) ++#define RXFIFO_RD_REQ (1 << 5) ++#define CLK_IS_OFF (1 << 4) ++#define STOP_CMD (1 << 3) ++#define END_CMD_RES (1 << 2) ++#define PRG_DONE (1 << 1) ++#define DATA_TRAN_DONE (1 << 0) ++ ++#define MMC_I_REG 0x002c ++/* same as MMC_I_MASK */ ++ ++#define MMC_CMD 0x0030 ++ ++#define MMC_ARGH 0x0034 /* 16 bit */ ++ ++#define MMC_ARGL 0x0038 /* 16 bit */ ++ ++#define MMC_RES 0x003c /* 16 bit */ ++ ++#define MMC_RXFIFO 0x0040 /* 8 bit */ ++ ++#define MMC_TXFIFO 0x0044 /* 8 bit */ +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/media/mmc/mmci.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,147 @@ ++/* ++ * linux/drivers/media/mmc/mmci.h - ARM PrimeCell MMCI PL180/1 driver ++ * ++ * Copyright (C) 2003 Deep Blue Solutions, Ltd, 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. ++ */ ++#define MMCIPOWER 0x000 ++#define MCI_PWR_OFF 0x00 ++#define MCI_PWR_UP 0x02 ++#define MCI_PWR_ON 0x03 ++#define MCI_OD (1 << 6) ++#define MCI_ROD (1 << 7) ++ ++#define MMCICLOCK 0x004 ++#define MCI_CLK_ENABLE (1 << 8) ++#define MCI_PWRSAVE (1 << 9) ++#define MCI_BYPASS (1 << 10) ++ ++#define MMCIARGUMENT 0x008 ++#define MMCICOMMAND 0x00c ++#define MCI_CPSM_RESPONSE (1 << 6) ++#define MCI_CPSM_LONGRSP (1 << 7) ++#define MCI_CPSM_INTERRUPT (1 << 8) ++#define MCI_CPSM_PENDING (1 << 9) ++#define MCI_CPSM_ENABLE (1 << 10) ++ ++#define MMCIRESPCMD 0x010 ++#define MMCIRESPONSE0 0x014 ++#define MMCIRESPONSE1 0x018 ++#define MMCIRESPONSE2 0x01c ++#define MMCIRESPONSE3 0x020 ++#define MMCIDATATIMER 0x024 ++#define MMCIDATALENGTH 0x028 ++#define MMCIDATACTRL 0x02c ++#define MCI_DPSM_ENABLE (1 << 0) ++#define MCI_DPSM_DIRECTION (1 << 1) ++#define MCI_DPSM_MODE (1 << 2) ++#define MCI_DPSM_DMAENABLE (1 << 3) ++ ++#define MMCIDATACNT 0x030 ++#define MMCISTATUS 0x034 ++#define MCI_CMDCRCFAIL (1 << 0) ++#define MCI_DATACRCFAIL (1 << 1) ++#define MCI_CMDTIMEOUT (1 << 2) ++#define MCI_DATATIMEOUT (1 << 3) ++#define MCI_TXUNDERRUN (1 << 4) ++#define MCI_RXOVERRUN (1 << 5) ++#define MCI_CMDRESPEND (1 << 6) ++#define MCI_CMDSENT (1 << 7) ++#define MCI_DATAEND (1 << 8) ++#define MCI_DATABLOCKEND (1 << 10) ++#define MCI_CMDACTIVE (1 << 11) ++#define MCI_TXACTIVE (1 << 12) ++#define MCI_RXACTIVE (1 << 13) ++#define MCI_TXFIFOHALFEMPTY (1 << 14) ++#define MCI_RXFIFOHALFFULL (1 << 15) ++#define MCI_TXFIFOFULL (1 << 16) ++#define MCI_RXFIFOFULL (1 << 17) ++#define MCI_TXFIFOEMPTY (1 << 18) ++#define MCI_RXFIFOEMPTY (1 << 19) ++#define MCI_TXDATAAVLBL (1 << 20) ++#define MCI_RXDATAAVLBL (1 << 21) ++ ++#define MMCICLEAR 0x038 ++#define MCI_CMDCRCFAILCLR (1 << 0) ++#define MCI_DATACRCFAILCLR (1 << 1) ++#define MCI_CMDTIMEOUTCLR (1 << 2) ++#define MCI_DATATIMEOUTCLR (1 << 3) ++#define MCI_TXUNDERRUNCLR (1 << 4) ++#define MCI_RXOVERRUNCLR (1 << 5) ++#define MCI_CMDRESPENDCLR (1 << 6) ++#define MCI_CMDSENTCLR (1 << 7) ++#define MCI_DATAENDCLR (1 << 8) ++#define MCI_DATABLOCKENDCLR (1 << 10) ++ ++#define MMCIMASK0 0x03c ++#define MCI_CMDCRCFAILMASK (1 << 0) ++#define MCI_DATACRCFAILMASK (1 << 1) ++#define MCI_CMDTIMEOUTMASK (1 << 2) ++#define MCI_DATATIMEOUTMASK (1 << 3) ++#define MCI_TXUNDERRUNMASK (1 << 4) ++#define MCI_RXOVERRUNMASK (1 << 5) ++#define MCI_CMDRESPENDMASK (1 << 6) ++#define MCI_CMDSENTMASK (1 << 7) ++#define MCI_DATAENDMASK (1 << 8) ++#define MCI_DATABLOCKENDMASK (1 << 10) ++#define MCI_CMDACTIVEMASK (1 << 11) ++#define MCI_TXACTIVEMASK (1 << 12) ++#define MCI_RXACTIVEMASK (1 << 13) ++#define MCI_TXFIFOHALFEMPTYMASK (1 << 14) ++#define MCI_RXFIFOHALFFULLMASK (1 << 15) ++#define MCI_TXFIFOFULLMASK (1 << 16) ++#define MCI_RXFIFOFULLMASK (1 << 17) ++#define MCI_TXFIFOEMPTYMASK (1 << 18) ++#define MCI_RXFIFOEMPTYMASK (1 << 19) ++#define MCI_TXDATAAVLBLMASK (1 << 20) ++#define MCI_RXDATAAVLBLMASK (1 << 21) ++ ++#define MMCIMASK1 0x040 ++#define MMCIFIFOCNT 0x048 ++#define MMCIFIFO 0x080 /* to 0x0bc */ ++ ++#define MCI_IRQMASK \ ++ (MCI_CMDCRCFAIL|MCI_DATACRCFAIL|MCI_CMDTIMEOUT|MCI_DATATIMEOUT| \ ++ MCI_TXUNDERRUN|MCI_RXOVERRUN|MCI_CMDRESPEND|MCI_CMDSENT| \ ++ MCI_DATAEND|MCI_DATABLOCKEND| \ ++ MCI_TXFIFOHALFEMPTY|MCI_RXFIFOHALFFULL| \ ++ MCI_TXFIFOEMPTY|MCI_RXDATAAVLBL) ++ ++#define MCI_IRQENABLE \ ++ (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \ ++ MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ ++ MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATAENDMASK| \ ++ MCI_DATABLOCKENDMASK|MCI_TXFIFOHALFEMPTYMASK| \ ++ MCI_RXFIFOHALFFULLMASK) ++ ++#define MCI_FIFOSIZE 16 ++ ++#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2) ++ ++struct mmci_host { ++ struct mmc_host mmc; ++ void *base; ++ int irq; ++ unsigned int mclk; ++ u32 pwr; ++ ++ struct mmc_request *req; ++ struct mmc_command *cmd; ++ struct mmc_data *data; ++ ++ unsigned int data_xfered; ++ ++ /* pio stuff */ ++ void *buffer; ++ unsigned int size; ++ ++ /* dma stuff */ ++// struct scatterlist *sg_list; ++// int sg_len; ++// int sg_dir; ++}; ++ ++#define to_mmci_host(mmc) container_of(mmc, struct mmci_host, mmc) +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/media/mmc/mmc.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,801 @@ ++/* ++ * linux/drivers/media/mmc/mmc.c ++ * ++ * Copyright (C) 2003 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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/completion.h> ++#include <linux/device.h> ++#include <linux/delay.h> ++#include <linux/err.h> ++ ++#include <linux/mmc/card.h> ++#include <linux/mmc/host.h> ++#include <linux/mmc/protocol.h> ++ ++#include "mmc.h" ++ ++#ifdef CONFIG_MMC_DEBUG ++#define DBG(x...) printk(KERN_DEBUG x) ++#else ++#define DBG(x...) do { } while (0) ++#endif ++ ++#define CMD_RETRIES 3 ++ ++/* ++ * OCR Bit positions to 10s of Vdd mV. ++ */ ++static const unsigned short mmc_ocr_bit_to_vdd[] = { ++ 150, 155, 160, 165, 170, 180, 190, 200, ++ 210, 220, 230, 240, 250, 260, 270, 280, ++ 290, 300, 310, 320, 330, 340, 350, 360 ++}; ++ ++static const unsigned int tran_exp[] = { ++ 10000, 100000, 1000000, 10000000, ++ 0, 0, 0, 0 ++}; ++ ++static const unsigned char tran_mant[] = { ++ 0, 10, 12, 13, 15, 20, 25, 30, ++ 35, 40, 45, 50, 55, 60, 70, 80, ++}; ++ ++static const unsigned int tacc_exp[] = { ++ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, ++}; ++ ++static const unsigned int tacc_mant[] = { ++ 0, 10, 12, 13, 15, 20, 25, 30, ++ 35, 40, 45, 50, 55, 60, 70, 80, ++}; ++ ++ ++/** ++ * mmc_request_done - finish processing an MMC command ++ * @host: MMC host which completed command ++ * @cmd: MMC command which completed ++ * @err: MMC error code ++ * ++ * MMC drivers should call this function when they have completed ++ * their processing of a command. This should be called before the ++ * data part of the command has completed. ++ */ ++void mmc_request_done(struct mmc_host *host, struct mmc_request *req) ++{ ++ struct mmc_command *cmd = req->cmd; ++ int err = req->cmd->error; ++ DBG("MMC: req done (%02x): %d: %08x %08x %08x %08x\n", cmd->opcode, ++ err, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); ++ ++ if (err && cmd->retries) { ++ cmd->retries--; ++ cmd->error = 0; ++ host->ops->request(host, req); ++ } else if (req->done) { ++ req->done(req); ++ } ++} ++ ++EXPORT_SYMBOL(mmc_request_done); ++ ++/** ++ * mmc_start_request - start a command on a host ++ * @host: MMC host to start command on ++ * @cmd: MMC command to start ++ * ++ * Queue a command on the specified host. We expect the ++ * caller to be holding the host lock with interrupts disabled. ++ */ ++void ++mmc_start_request(struct mmc_host *host, struct mmc_request *req) ++{ ++ DBG("MMC: starting cmd %02x arg %08x flags %08x\n", ++ req->cmd->opcode, req->cmd->arg, req->cmd->flags); ++ ++ req->cmd->error = 0; ++ req->cmd->req = req; ++ if (req->data) { ++ req->cmd->data = req->data; ++ req->data->error = 0; ++ req->data->req = req; ++ if (req->stop) { ++ req->data->stop = req->stop; ++ req->stop->error = 0; ++ req->stop->req = req; ++ } ++ } ++ host->ops->request(host, req); ++} ++ ++EXPORT_SYMBOL(mmc_start_request); ++ ++static void mmc_wait_done(struct mmc_request *req) ++{ ++ complete(req->done_data); ++} ++ ++int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *req) ++{ ++ DECLARE_COMPLETION(complete); ++ ++ req->done_data = &complete; ++ req->done = mmc_wait_done; ++ ++ mmc_start_request(host, req); ++ ++ wait_for_completion(&complete); ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL(mmc_wait_for_req); ++ ++/** ++ * mmc_wait_for_cmd - start a command and wait for completion ++ * @host: MMC host to start command ++ * @cmd: MMC command to start ++ * @retries: maximum number of retries ++ * ++ * Start a new MMC command for a host, and wait for the command ++ * to complete. Return any error that occurred while the command ++ * was executing. Do not attempt to parse the response. ++ */ ++int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries) ++{ ++ struct mmc_request req; ++ ++ BUG_ON(host->card_busy == NULL); ++ ++ memset(&req, 0, sizeof(struct mmc_request)); ++ ++ memset(cmd->resp, 0, sizeof(cmd->resp)); ++ cmd->retries = retries; ++ ++ req.cmd = cmd; ++ cmd->data = NULL; ++ ++ mmc_wait_for_req(host, &req); ++ ++ return cmd->error; ++} ++ ++EXPORT_SYMBOL(mmc_wait_for_cmd); ++ ++ ++ ++/** ++ * __mmc_claim_host - exclusively claim a host ++ * @host: mmc host to claim ++ * @card: mmc card to claim host for ++ * ++ * Claim a host for a set of operations. If a valid card ++ * is passed and this wasn't the last card selected, select ++ * the card before returning. ++ * ++ * Note: you should use mmc_card_claim_host or mmc_claim_host. ++ */ ++int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long flags; ++ int err = 0; ++ ++ add_wait_queue(&host->wq, &wait); ++ spin_lock_irqsave(&host->lock, flags); ++ while (1) { ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ if (host->card_busy == NULL) ++ break; ++ spin_unlock_irqrestore(&host->lock, flags); ++ schedule(); ++ spin_lock_irqsave(&host->lock, flags); ++ } ++ set_current_state(TASK_RUNNING); ++ host->card_busy = card; ++ spin_unlock_irqrestore(&host->lock, flags); ++ remove_wait_queue(&host->wq, &wait); ++ ++ if (card != (void *)-1 && host->card_selected != card) { ++ struct mmc_command cmd; ++ ++ host->card_selected = card; ++ ++ cmd.opcode = MMC_SELECT_CARD; ++ cmd.arg = card->rca << 16; ++ cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC; ++ ++ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); ++ } ++ ++ return err; ++} ++ ++EXPORT_SYMBOL(__mmc_claim_host); ++ ++/** ++ * mmc_release_host - release a host ++ * @host: mmc host to release ++ * ++ * Release a MMC host, allowing others to claim the host ++ * for their operations. ++ */ ++void mmc_release_host(struct mmc_host *host) ++{ ++ unsigned long flags; ++ ++ BUG_ON(host->card_busy == NULL); ++ ++ spin_lock_irqsave(&host->lock, flags); ++ host->card_busy = NULL; ++ spin_unlock_irqrestore(&host->lock, flags); ++ ++ wake_up(&host->wq); ++} ++ ++EXPORT_SYMBOL(mmc_release_host); ++ ++static void mmc_deselect_cards(struct mmc_host *host) ++{ ++ struct mmc_command cmd; ++ ++ /* ++ * Ensure that no card is selected. ++ */ ++ if (host->card_selected) { ++ host->card_selected = NULL; ++ ++ cmd.opcode = MMC_SELECT_CARD; ++ cmd.arg = 0; ++ cmd.flags = MMC_RSP_NONE; ++ ++ mmc_wait_for_cmd(host, &cmd, 0); ++ } ++} ++ ++ ++static inline void mmc_delay(unsigned int ms) ++{ ++ if (ms < HZ / 1000) { ++ yield(); ++ mdelay(ms); ++ } else { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(ms * HZ / 1000); ++ } ++} ++ ++static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) ++{ ++ int bit; ++ ++ /* ++ * Mask off any voltages we don't support ++ */ ++ ocr &= host->ocr_avail; ++ ++ /* ++ * Select the lowest voltage ++ */ ++ bit = ffs(ocr); ++ if (bit) { ++ bit -= 1; ++ ++ ocr = 1 << bit; ++ ++ host->ios.vdd = mmc_ocr_bit_to_vdd[bit]; ++ host->ops->set_ios(host, &host->ios); ++ } else { ++ ocr = 0; ++ } ++ ++ return ocr; ++} ++ ++static void mmc_decode_cid(struct mmc_cid *cid, u32 *resp) ++{ ++ memset(cid, 0, sizeof(struct mmc_cid)); ++ ++ cid->manfid = resp[0] >> 8; ++ cid->prod_name[0] = resp[0]; ++ cid->prod_name[1] = resp[1] >> 24; ++ cid->prod_name[2] = resp[1] >> 16; ++ cid->prod_name[3] = resp[1] >> 8; ++ cid->prod_name[4] = resp[1]; ++ cid->prod_name[5] = resp[2] >> 24; ++ cid->prod_name[6] = resp[2] >> 16; ++ cid->prod_name[7] = '\0'; ++ cid->hwrev = (resp[2] >> 12) & 15; ++ cid->fwrev = (resp[2] >> 8) & 15; ++ cid->serial = (resp[2] & 255) << 16 | (resp[3] >> 16); ++ cid->month = (resp[3] >> 12) & 15; ++ cid->year = (resp[3] >> 8) & 15; ++} ++ ++static void mmc_decode_csd(struct mmc_csd *csd, u32 *resp) ++{ ++ unsigned int e, m; ++ ++ csd->mmc_prot = (resp[0] >> 26) & 15; ++ m = (resp[0] >> 19) & 15; ++ e = (resp[0] >> 16) & 7; ++ csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10; ++ csd->tacc_clks = ((resp[0] >> 8) & 255) * 100; ++ ++ m = (resp[0] >> 3) & 15; ++ e = resp[0] & 7; ++ csd->max_dtr = tran_exp[e] * tran_mant[m]; ++ csd->cmdclass = (resp[1] >> 20) & 0xfff; ++ ++ e = (resp[2] >> 15) & 7; ++ m = (resp[1] << 2 | resp[2] >> 30) & 0x3fff; ++ csd->capacity = (1 + m) << (e + 2); ++ ++ csd->read_blkbits = (resp[1] >> 16) & 15; ++} ++ ++/* ++ * Locate a MMC card on this MMC host given a CID. ++ */ ++static struct mmc_card * ++mmc_find_card(struct mmc_host *host, struct mmc_cid *cid) ++{ ++ struct mmc_card *card; ++ ++ list_for_each_entry(card, &host->cards, node) { ++ if (memcmp(&card->cid, cid, sizeof(struct mmc_cid)) == 0) ++ return card; ++ } ++ return NULL; ++} ++ ++/* ++ * Allocate a new MMC card, and assign a unique RCA. ++ */ ++static struct mmc_card * ++mmc_alloc_card(struct mmc_host *host, struct mmc_cid *cid, unsigned int *frca) ++{ ++ struct mmc_card *card, *c; ++ unsigned int rca = *frca; ++ ++ card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL); ++ if (!card) ++ return ERR_PTR(-ENOMEM); ++ ++ mmc_init_card(card, host); ++ memcpy(&card->cid, cid, sizeof(struct mmc_cid)); ++ ++ again: ++ list_for_each_entry(c, &host->cards, node) ++ if (c->rca == rca) { ++ rca++; ++ goto again; ++ } ++ ++ card->rca = rca; ++ ++ *frca = rca; ++ ++ return card; ++} ++ ++/* ++ * Apply power to the MMC stack. ++ */ ++static void mmc_power_up(struct mmc_host *host) ++{ ++ struct mmc_command cmd; ++ int bit = fls(host->ocr_avail) - 1; ++ ++ host->ios.vdd = mmc_ocr_bit_to_vdd[bit]; ++ host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; ++ host->ios.power_mode = MMC_POWER_UP; ++ host->ops->set_ios(host, &host->ios); ++ ++ mmc_delay(1); ++ ++ host->ios.clock = host->f_min; ++ host->ios.power_mode = MMC_POWER_ON; ++ host->ops->set_ios(host, &host->ios); ++ ++ mmc_delay(2); ++ ++ cmd.opcode = MMC_GO_IDLE_STATE; ++ cmd.arg = 0; ++ cmd.flags = MMC_RSP_NONE; ++ ++ mmc_wait_for_cmd(host, &cmd, 0); ++} ++ ++static void mmc_power_off(struct mmc_host *host) ++{ ++ host->ios.clock = 0; ++ host->ios.vdd = 0; ++ host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; ++ host->ios.power_mode = MMC_POWER_OFF; ++ host->ops->set_ios(host, &host->ios); ++} ++ ++static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) ++{ ++ struct mmc_command cmd; ++ int i, err = 0; ++ ++ cmd.opcode = MMC_SEND_OP_COND; ++ cmd.arg = ocr; ++ cmd.flags = MMC_RSP_SHORT; ++ ++ for (i = 100; i; i--) { ++ err = mmc_wait_for_cmd(host, &cmd, 0); ++ if (err != MMC_ERR_NONE) ++ break; ++ ++ if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) ++ break; ++ ++ err = MMC_ERR_TIMEOUT; ++ } ++ ++ if (rocr) ++ *rocr = cmd.resp[0]; ++ ++ return err; ++} ++ ++/* ++ * Discover cards by requesting their CID. If this command ++ * times out, it is not an error; there are no further cards ++ * to be discovered. Add new cards to the list. ++ * ++ * Create a mmc_card entry for each discovered card, assigning ++ * it an RCA, and save the CID. ++ */ ++static void mmc_discover_cards(struct mmc_host *host) ++{ ++ struct mmc_card *card; ++ unsigned int first_rca = 1, err; ++ ++ while (1) { ++ struct mmc_command cmd; ++ struct mmc_cid cid; ++ ++ /* ++ * Read CID ++ */ ++ cmd.opcode = MMC_ALL_SEND_CID; ++ cmd.arg = 0; ++ cmd.flags = MMC_RSP_LONG | MMC_RSP_CRC; ++ ++ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); ++ if (err == MMC_ERR_TIMEOUT) { ++ err = MMC_ERR_NONE; ++ break; ++ } ++ if (err != MMC_ERR_NONE) { ++ printk(KERN_ERR "MMC: mmc%d error requesting CID: %d\n", ++ host->host_num, err); ++ break; ++ } ++ ++ mmc_decode_cid(&cid, cmd.resp); ++ ++ card = mmc_find_card(host, &cid); ++ if (!card) { ++ card = mmc_alloc_card(host, &cid, &first_rca); ++ if (IS_ERR(card)) { ++ err = PTR_ERR(card); ++ break; ++ } ++ list_add(&card->node, &host->cards); ++ } ++ ++ card->state &= ~MMC_STATE_DEAD; ++ ++ cmd.opcode = MMC_SET_RELATIVE_ADDR; ++ cmd.arg = card->rca << 16; ++ cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC; ++ ++ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); ++ if (err != MMC_ERR_NONE) ++ card->state |= MMC_STATE_DEAD; ++ } ++} ++ ++static void mmc_read_csds(struct mmc_host *host) ++{ ++ struct mmc_card *card; ++ ++ list_for_each_entry(card, &host->cards, node) { ++ struct mmc_command cmd; ++ int err; ++ ++ if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) ++ continue; ++ ++ cmd.opcode = MMC_SEND_CSD; ++ cmd.arg = card->rca << 16; ++ cmd.flags = MMC_RSP_LONG | MMC_RSP_CRC; ++ ++ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); ++ if (err != MMC_ERR_NONE) { ++ card->state |= MMC_STATE_DEAD; ++ continue; ++ } ++ ++ mmc_decode_csd(&card->csd, cmd.resp); ++ } ++} ++ ++static unsigned int mmc_calculate_clock(struct mmc_host *host) ++{ ++ struct mmc_card *card; ++ unsigned int max_dtr = host->f_max; ++ ++ list_for_each_entry(card, &host->cards, node) ++ if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr) ++ max_dtr = card->csd.max_dtr; ++ ++ DBG("MMC: selected %d.%03dMHz transfer rate\n", ++ max_dtr / 1000000, (max_dtr / 1000) % 1000); ++ ++ return max_dtr; ++} ++ ++/* ++ * Check whether cards we already know about are still present. ++ * We do this by requesting status, and checking whether a card ++ * responds. ++ * ++ * A request for status does not cause a state change in data ++ * transfer mode. ++ */ ++static void mmc_check_cards(struct mmc_host *host) ++{ ++ struct list_head *l, *n; ++ ++ mmc_deselect_cards(host); ++ ++ list_for_each_safe(l, n, &host->cards) { ++ struct mmc_card *card = mmc_list_to_card(l); ++ struct mmc_command cmd; ++ int err; ++ ++ cmd.opcode = MMC_SEND_STATUS; ++ cmd.arg = card->rca << 16; ++ cmd.flags = MMC_RSP_LONG | MMC_RSP_CRC; ++ ++ err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); ++ if (err == MMC_ERR_NONE) ++ continue; ++ ++ /* ++ * Ok, we believe this card has been removed. ++ */ ++ card->state |= MMC_STATE_DEAD; ++ } ++} ++ ++static void mmc_setup(struct mmc_host *host) ++{ ++ if (host->ios.power_mode != MMC_POWER_ON) { ++ int err; ++ u32 ocr; ++ ++ mmc_power_up(host); ++ ++ err = mmc_send_op_cond(host, 0, &ocr); ++ if (err != MMC_ERR_NONE) ++ return; ++ ++ host->ocr = mmc_select_voltage(host, ocr); ++ } else { ++ host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; ++ host->ios.clock = host->f_min; ++ host->ops->set_ios(host, &host->ios); ++ ++ /* ++ * We should remember the OCR mask from the existing ++ * cards, and detect the new cards OCR mask, combine ++ * the two and re-select the VDD. However, if we do ++ * change VDD, we should do an idle, and then do a ++ * full re-initialisation. We would need to notify ++ * drivers so that they can re-setup the cards as ++ * well, while keeping their queues at bay. ++ * ++ * For the moment, we take the easy way out - if the ++ * new cards don't like our currently selected VDD, ++ * they drop off the bus. ++ */ ++ } ++ ++ if (host->ocr == 0) ++ return; ++ ++ /* ++ * Send the selected OCR multiple times... until the cards ++ * all get the idea that they should be ready for CMD2. ++ * (My SanDisk card seems to need this.) ++ */ ++ mmc_send_op_cond(host, host->ocr, NULL); ++ ++ mmc_discover_cards(host); ++ ++ /* ++ * Ok, now switch to push-pull mode. ++ */ ++ host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; ++ host->ops->set_ios(host, &host->ios); ++ ++ mmc_read_csds(host); ++} ++ ++ ++/** ++ * mmc_detect_change - process change of state on a MMC socket ++ * @host: host which changed state. ++ * ++ * All we know is that card(s) have been inserted or removed ++ * from the socket(s). We don't know which socket or cards. ++ */ ++void mmc_detect_change(struct mmc_host *host) ++{ ++ struct list_head *l, *n; ++ ++ mmc_claim_host(host); ++ ++ if (host->ios.power_mode == MMC_POWER_ON) ++ mmc_check_cards(host); ++ ++ mmc_setup(host); ++ ++ if (!list_empty(&host->cards)) { ++ /* ++ * (Re-)calculate the fastest clock rate which the ++ * attached cards and the host support. ++ */ ++ host->ios.clock = mmc_calculate_clock(host); ++ host->ops->set_ios(host, &host->ios); ++ } ++ ++ mmc_release_host(host); ++ ++ list_for_each_safe(l, n, &host->cards) { ++ struct mmc_card *card = mmc_list_to_card(l); ++ ++ /* ++ * If this is a new and good card, register it. ++ */ ++ if (!mmc_card_present(card) && !mmc_card_dead(card)) { ++ if (mmc_register_card(card)) ++ card->state |= MMC_STATE_DEAD; ++ else ++ card->state |= MMC_STATE_PRESENT; ++ } ++ ++ /* ++ * If this card is dead, destroy it. ++ */ ++ if (mmc_card_dead(card)) { ++ list_del(&card->node); ++ mmc_remove_card(card); ++ } ++ } ++ ++ /* ++ * If we discover that there are no cards on the ++ * bus, turn off the clock and power down. ++ */ ++ if (list_empty(&host->cards)) ++ mmc_power_off(host); ++} ++ ++EXPORT_SYMBOL(mmc_detect_change); ++ ++ ++/** ++ * mmc_init_host - initialise the per-host structure. ++ * @host: mmc host ++ * ++ * Initialise the per-host structure. ++ */ ++int mmc_init_host(struct mmc_host *host) ++{ ++ static unsigned int host_num; ++ ++ memset(host, 0, sizeof(struct mmc_host)); ++ ++ host->host_num = host_num++; ++ ++ spin_lock_init(&host->lock); ++ init_waitqueue_head(&host->wq); ++ INIT_LIST_HEAD(&host->cards); ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL(mmc_init_host); ++ ++/** ++ * mmc_add_host - initialise host hardware ++ * @host: mmc host ++ */ ++int mmc_add_host(struct mmc_host *host) ++{ ++ mmc_power_off(host); ++ mmc_detect_change(host); ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL(mmc_add_host); ++ ++/** ++ * mmc_remove_host - remove host hardware ++ * @host: mmc host ++ * ++ * Unregister and remove all cards associated with this host, ++ * and power down the MMC bus. ++ */ ++void mmc_remove_host(struct mmc_host *host) ++{ ++ struct list_head *l, *n; ++ ++ list_for_each_safe(l, n, &host->cards) { ++ struct mmc_card *card = mmc_list_to_card(l); ++ ++ mmc_remove_card(card); ++ } ++ ++ mmc_power_off(host); ++} ++ ++EXPORT_SYMBOL(mmc_remove_host); ++ ++#ifdef CONFIG_PM ++ ++/** ++ * mmc_suspend_host - suspend a host ++ * @host: mmc host ++ * @state: suspend mode (PM_SUSPEND_xxx) ++ */ ++int mmc_suspend_host(struct mmc_host *host, u32 state) ++{ ++ mmc_claim_host(host); ++ mmc_deselect_cards(host); ++ mmc_power_off(host); ++ mmc_release_host(host); ++ ++ return 0; ++} ++ ++/** ++ * mmc_resume_host - resume a previously suspended host ++ * @host: mmc host ++ */ ++int mmc_resume_host(struct mmc_host *host) ++{ ++ mmc_detect_change(host); ++ ++ return 0; ++} ++ ++ ++#else /* CONFIG_PM is not set */ ++ ++int mmc_suspend_host(struct mmc_host *host, u32 state) { return 0; } ++int mmc_resume_host(struct mmc_host *host) { return 0; } ++ ++#endif ++ ++EXPORT_SYMBOL(mmc_suspend_host); ++EXPORT_SYMBOL(mmc_resume_host); ++ ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/media/mmc/Makefile 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,21 @@ ++# ++# Makefile for the kernel mmc device drivers. ++# ++ ++# ++# Core ++# ++obj-$(CONFIG_MMC) += mmc_core.o ++ ++# ++# Media drivers ++# ++obj-$(CONFIG_MMC_BLOCK) += mmc_block.o ++ ++# ++# Host drivers ++# ++obj-$(CONFIG_MMC_ARMMMCI) += mmci.o ++obj-$(CONFIG_MMC_PXA) += pxamci.o ++ ++mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o +--- linux-2.6.5/drivers/media/Makefile~heh 2004-04-03 22:38:15.000000000 -0500 ++++ linux-2.6.5/drivers/media/Makefile 2004-04-30 20:57:36.000000000 -0400 +@@ -3,3 +3,6 @@ + # + + obj-y := video/ radio/ dvb/ common/ ++ ++obj-$(CONFIG_MMC) += mmc/ ++ +--- linux-2.6.5/drivers/serial/Kconfig~heh 2004-04-03 22:38:15.000000000 -0500 ++++ linux-2.6.5/drivers/serial/Kconfig 2004-04-30 20:57:36.000000000 -0400 +@@ -315,6 +315,29 @@ + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + ++config SERIAL_PXA ++ bool "PXA serial port support" ++ depends on ARM && ARCH_PXA ++ select SERIAL_CORE ++ help ++ If you have a machine based on an Intel XScale PXA2xx CPU you ++ can enable its onboard serial ports by enabling this option. ++ ++config SERIAL_PXA_CONSOLE ++ bool "Console on PXA serial port" ++ depends on SERIAL_PXA ++ select SERIAL_CORE_CONSOLE ++ help ++ If you have enabled the serial port on the Intel XScale PXA ++ CPU you can make it the console by answering Y to this option. ++ ++ Even if you say Y here, the currently visible virtual console ++ (/dev/tty0) will still be used as the system console by default, but ++ you can alter that using a kernel command line option such as ++ "console=ttySA0". (Try "man bootparam" or see the documentation of ++ your boot loader (lilo or loadlin) about how to pass options to the ++ kernel at boot time.) ++ + config SERIAL_SA1100 + bool "SA1100 serial port support" + depends on ARM && ARCH_SA1100 +--- linux-2.6.5/drivers/serial/pxa.c~heh 2004-04-03 22:38:16.000000000 -0500 ++++ linux-2.6.5/drivers/serial/pxa.c 2004-04-30 20:57:36.000000000 -0400 +@@ -294,7 +294,6 @@ + unsigned char status; + unsigned int ret; + +-return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + spin_lock_irqsave(&up->port.lock, flags); + status = serial_in(up, UART_MSR); + spin_unlock_irqrestore(&up->port.lock, flags); +@@ -800,6 +799,21 @@ + .ops = &serial_pxa_pops, + .line = 2, + }, ++ }, { /* HWUART */ ++ .name = "HWUART", ++ .cken = CKEN4_HWUART, ++ .port = { ++ .type = PORT_PXA, ++ .iotype = SERIAL_IO_MEM, ++ .membase = (void *)&HWUART, ++ .mapbase = __PREG(HWUART), ++ .irq = IRQ_HWUART, ++ .uartclk = 921600 * 16, ++ .fifosize = 64, ++ .flags = ASYNC_SKIP_TEST, ++ .ops = &serial_pxa_pops, ++ .line = 3, ++ }, + } + }; + +--- linux-2.6.5/drivers/serial/sa1100.c~heh 2004-04-03 22:36:24.000000000 -0500 ++++ linux-2.6.5/drivers/serial/sa1100.c 2004-04-30 20:57:36.000000000 -0400 +@@ -448,6 +448,15 @@ + unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; + + /* ++ * If we don't support modem control lines, don't allow ++ * these to be set. ++ */ ++ if (0) { ++ termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR); ++ termios->c_cflag |= CLOCAL; ++ } ++ ++ /* + * We only support CS7 and CS8. + */ + while ((termios->c_cflag & CSIZE) != CS7 && +@@ -894,6 +903,7 @@ + if (sa1100_ports[i].port.mapbase != res->start) + continue; + ++ sa1100_ports[i].port.dev = _dev; + uart_add_one_port(&sa1100_reg, &sa1100_ports[i].port); + dev_set_drvdata(_dev, &sa1100_ports[i]); + break; +--- linux-2.6.5/drivers/mtd/mtd_blkdevs.c~heh 2004-04-03 22:36:14.000000000 -0500 ++++ linux-2.6.5/drivers/mtd/mtd_blkdevs.c 2004-04-30 20:57:36.000000000 -0400 +@@ -81,7 +81,7 @@ + struct request_queue *rq = tr->blkcore_priv->rq; + + /* we might get involved when memory gets low, so use PF_MEMALLOC */ +- current->flags |= PF_MEMALLOC; ++ current->flags |= PF_MEMALLOC|PF_IOTHREAD; + + daemonize("%sd", tr->name); + +--- linux-2.6.5/drivers/mtd/devices/doc1000.c~heh 2004-04-03 22:37:36.000000000 -0500 ++++ linux-2.6.5/drivers/mtd/devices/doc1000.c 2004-04-30 20:57:36.000000000 -0400 +@@ -1,6 +1,6 @@ + /*====================================================================== + +- $Id$ ++ $Id$ + + ======================================================================*/ + +@@ -20,6 +20,7 @@ + #include <linux/ioctl.h> + #include <asm/io.h> + #include <asm/system.h> ++#include <asm/segment.h> + #include <stdarg.h> + #include <linux/delay.h> + #include <linux/init.h> +@@ -482,7 +483,7 @@ + else + priv->devstat[erase->dev] = erase->state = MTD_ERASE_PENDING; + } +- else if (erase->time + erase_timeout < jiffies) ++ else if (time_after(jiffies, erase->time + erase_timeout)) + { + printk("Flash erase timed out. The world is broken.\n"); + +--- linux-2.6.5/drivers/mtd/mtdconcat.c~heh 2004-04-03 22:37:37.000000000 -0500 ++++ linux-2.6.5/drivers/mtd/mtdconcat.c 2004-04-30 20:57:36.000000000 -0400 +@@ -7,7 +7,7 @@ + * + * This code is GPL + * +- * $Id$ ++ * $Id$ + */ + + #include <linux/module.h> +@@ -26,7 +26,7 @@ + */ + struct mtd_concat { + struct mtd_info mtd; +- int num_subdev; ++ int num_subdev; + struct mtd_info **subdev; + }; + +@@ -37,21 +37,20 @@ + #define SIZEOF_STRUCT_MTD_CONCAT(num_subdev) \ + ((sizeof(struct mtd_concat) + (num_subdev) * sizeof(struct mtd_info *))) + +- + /* + * Given a pointer to the MTD object in the mtd_concat structure, + * we can retrieve the pointer to that structure with this macro. + */ + #define CONCAT(x) ((struct mtd_concat *)(x)) + +- + /* + * MTD methods which look up the relevant subdevice, translate the + * effective address and pass through to the subdevice. + */ + +-static int concat_read (struct mtd_info *mtd, loff_t from, size_t len, +- size_t *retlen, u_char *buf) ++static int ++concat_read(struct mtd_info *mtd, loff_t from, size_t len, ++ size_t * retlen, u_char * buf) + { + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; +@@ -59,43 +58,43 @@ + + *retlen = 0; + +- for(i = 0; i < concat->num_subdev; i++) +- { ++ for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; + +- if (from >= subdev->size) +- { /* Not destined for this subdev */ +- size = 0; ++ if (from >= subdev->size) { ++ /* Not destined for this subdev */ ++ size = 0; + from -= subdev->size; ++ continue; + } ++ if (from + len > subdev->size) ++ /* First part goes into this subdev */ ++ size = subdev->size - from; + else +- { +- if (from + len > subdev->size) +- size = subdev->size - from; /* First part goes into this subdev */ +- else +- size = len; /* Entire transaction goes into this subdev */ ++ /* Entire transaction goes into this subdev */ ++ size = len; + +- err = subdev->read(subdev, from, size, &retsize, buf); ++ err = subdev->read(subdev, from, size, &retsize, buf); + +- if(err) +- break; ++ if (err) ++ break; + +- *retlen += retsize; +- len -= size; +- if(len == 0) +- break; ++ *retlen += retsize; ++ len -= size; ++ if (len == 0) ++ break; + +- err = -EINVAL; +- buf += size; +- from = 0; +- } ++ err = -EINVAL; ++ buf += size; ++ from = 0; + } + return err; + } + +-static int concat_write (struct mtd_info *mtd, loff_t to, size_t len, +- size_t *retlen, const u_char *buf) ++static int ++concat_write(struct mtd_info *mtd, loff_t to, size_t len, ++ size_t * retlen, const u_char * buf) + { + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; +@@ -106,46 +105,44 @@ + + *retlen = 0; + +- for(i = 0; i < concat->num_subdev; i++) +- { ++ for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; + +- if (to >= subdev->size) +- { +- size = 0; ++ if (to >= subdev->size) { ++ size = 0; + to -= subdev->size; ++ continue; + } ++ if (to + len > subdev->size) ++ size = subdev->size - to; + else +- { +- if (to + len > subdev->size) +- size = subdev->size - to; +- else +- size = len; ++ size = len; + +- if (!(subdev->flags & MTD_WRITEABLE)) +- err = -EROFS; +- else +- err = subdev->write(subdev, to, size, &retsize, buf); ++ if (!(subdev->flags & MTD_WRITEABLE)) ++ err = -EROFS; ++ else ++ err = subdev->write(subdev, to, size, &retsize, buf); + +- if(err) +- break; ++ if (err) ++ break; + +- *retlen += retsize; +- len -= size; +- if(len == 0) +- break; ++ *retlen += retsize; ++ len -= size; ++ if (len == 0) ++ break; + +- err = -EINVAL; +- buf += size; +- to = 0; +- } ++ err = -EINVAL; ++ buf += size; ++ to = 0; + } + return err; + } + +-static int concat_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, +- size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel) ++static int ++concat_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, ++ size_t * retlen, u_char * buf, u_char * eccbuf, ++ struct nand_oobinfo *oobsel) + { + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; +@@ -153,53 +150,56 @@ + + *retlen = 0; + +- for(i = 0; i < concat->num_subdev; i++) +- { ++ for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; +- +- if (from >= subdev->size) +- { /* Not destined for this subdev */ +- size = 0; ++ ++ if (from >= subdev->size) { ++ /* Not destined for this subdev */ ++ size = 0; + from -= subdev->size; ++ continue; + } ++ ++ if (from + len > subdev->size) ++ /* First part goes into this subdev */ ++ size = subdev->size - from; + else +- { +- if (from + len > subdev->size) +- size = subdev->size - from; /* First part goes into this subdev */ +- else +- size = len; /* Entire transaction goes into this subdev */ +- +- if (subdev->read_ecc) +- err = subdev->read_ecc(subdev, from, size, &retsize, buf, eccbuf, oobsel); +- else +- err = -EINVAL; ++ /* Entire transaction goes into this subdev */ ++ size = len; + +- if(err) +- break; ++ if (subdev->read_ecc) ++ err = subdev->read_ecc(subdev, from, size, ++ &retsize, buf, eccbuf, oobsel); ++ else ++ err = -EINVAL; + +- *retlen += retsize; +- len -= size; +- if(len == 0) +- break; ++ if (err) ++ break; + +- err = -EINVAL; +- buf += size; +- if (eccbuf) +- { +- eccbuf += subdev->oobsize; +- /* in nand.c at least, eccbufs are tagged with 2 (int)eccstatus', +- we must account for these */ +- eccbuf += 2 * (sizeof(int)); +- } +- from = 0; ++ *retlen += retsize; ++ len -= size; ++ if (len == 0) ++ break; ++ ++ err = -EINVAL; ++ buf += size; ++ if (eccbuf) { ++ eccbuf += subdev->oobsize; ++ /* in nand.c at least, eccbufs are ++ tagged with 2 (int)eccstatus'; we ++ must account for these */ ++ eccbuf += 2 * (sizeof (int)); + } ++ from = 0; + } + return err; + } + +-static int concat_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, +- size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel) ++static int ++concat_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, ++ size_t * retlen, const u_char * buf, u_char * eccbuf, ++ struct nand_oobinfo *oobsel) + { + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; +@@ -210,50 +210,48 @@ + + *retlen = 0; + +- for(i = 0; i < concat->num_subdev; i++) +- { ++ for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; +- +- if (to >= subdev->size) +- { +- size = 0; ++ ++ if (to >= subdev->size) { ++ size = 0; + to -= subdev->size; ++ continue; + } ++ if (to + len > subdev->size) ++ size = subdev->size - to; + else +- { +- if (to + len > subdev->size) +- size = subdev->size - to; +- else +- size = len; ++ size = len; + +- if (!(subdev->flags & MTD_WRITEABLE)) +- err = -EROFS; +- else if (subdev->write_ecc) +- err = subdev->write_ecc(subdev, to, size, &retsize, buf, eccbuf, oobsel); +- else +- err = -EINVAL; ++ if (!(subdev->flags & MTD_WRITEABLE)) ++ err = -EROFS; ++ else if (subdev->write_ecc) ++ err = subdev->write_ecc(subdev, to, size, ++ &retsize, buf, eccbuf, oobsel); ++ else ++ err = -EINVAL; + +- if(err) +- break; ++ if (err) ++ break; + +- *retlen += retsize; +- len -= size; +- if(len == 0) +- break; ++ *retlen += retsize; ++ len -= size; ++ if (len == 0) ++ break; + +- err = -EINVAL; +- buf += size; +- if (eccbuf) +- eccbuf += subdev->oobsize; +- to = 0; +- } ++ err = -EINVAL; ++ buf += size; ++ if (eccbuf) ++ eccbuf += subdev->oobsize; ++ to = 0; + } + return err; + } + +-static int concat_read_oob (struct mtd_info *mtd, loff_t from, size_t len, +- size_t *retlen, u_char *buf) ++static int ++concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len, ++ size_t * retlen, u_char * buf) + { + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; +@@ -261,46 +259,47 @@ + + *retlen = 0; + +- for(i = 0; i < concat->num_subdev; i++) +- { ++ for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; +- +- if (from >= subdev->size) +- { /* Not destined for this subdev */ +- size = 0; ++ ++ if (from >= subdev->size) { ++ /* Not destined for this subdev */ ++ size = 0; + from -= subdev->size; ++ continue; + } ++ if (from + len > subdev->size) ++ /* First part goes into this subdev */ ++ size = subdev->size - from; + else +- { +- if (from + len > subdev->size) +- size = subdev->size - from; /* First part goes into this subdev */ +- else +- size = len; /* Entire transaction goes into this subdev */ +- +- if (subdev->read_oob) +- err = subdev->read_oob(subdev, from, size, &retsize, buf); +- else +- err = -EINVAL; ++ /* Entire transaction goes into this subdev */ ++ size = len; + +- if(err) +- break; ++ if (subdev->read_oob) ++ err = subdev->read_oob(subdev, from, size, ++ &retsize, buf); ++ else ++ err = -EINVAL; + +- *retlen += retsize; +- len -= size; +- if(len == 0) +- break; ++ if (err) ++ break; + +- err = -EINVAL; +- buf += size; +- from = 0; +- } ++ *retlen += retsize; ++ len -= size; ++ if (len == 0) ++ break; ++ ++ err = -EINVAL; ++ buf += size; ++ from = 0; + } + return err; + } + +-static int concat_write_oob (struct mtd_info *mtd, loff_t to, size_t len, +- size_t *retlen, const u_char *buf) ++static int ++concat_write_oob(struct mtd_info *mtd, loff_t to, size_t len, ++ size_t * retlen, const u_char * buf) + { + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; +@@ -311,50 +310,46 @@ + + *retlen = 0; + +- for(i = 0; i < concat->num_subdev; i++) +- { ++ for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; +- +- if (to >= subdev->size) +- { +- size = 0; ++ ++ if (to >= subdev->size) { ++ size = 0; + to -= subdev->size; ++ continue; + } ++ if (to + len > subdev->size) ++ size = subdev->size - to; + else +- { +- if (to + len > subdev->size) +- size = subdev->size - to; +- else +- size = len; ++ size = len; + +- if (!(subdev->flags & MTD_WRITEABLE)) +- err = -EROFS; +- else if (subdev->write_oob) +- err = subdev->write_oob(subdev, to, size, &retsize, buf); +- else +- err = -EINVAL; ++ if (!(subdev->flags & MTD_WRITEABLE)) ++ err = -EROFS; ++ else if (subdev->write_oob) ++ err = subdev->write_oob(subdev, to, size, &retsize, ++ buf); ++ else ++ err = -EINVAL; + +- if(err) +- break; ++ if (err) ++ break; + +- *retlen += retsize; +- len -= size; +- if(len == 0) +- break; ++ *retlen += retsize; ++ len -= size; ++ if (len == 0) ++ break; + +- err = -EINVAL; +- buf += size; +- to = 0; +- } ++ err = -EINVAL; ++ buf += size; ++ to = 0; + } + return err; + } + +- +-static void concat_erase_callback (struct erase_info *instr) ++static void concat_erase_callback(struct erase_info *instr) + { +- wake_up((wait_queue_head_t *)instr->priv); ++ wake_up((wait_queue_head_t *) instr->priv); + } + + static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase) +@@ -370,18 +365,18 @@ + + erase->mtd = mtd; + erase->callback = concat_erase_callback; +- erase->priv = (unsigned long)&waitq; +- ++ erase->priv = (unsigned long) &waitq; ++ + /* + * FIXME: Allow INTERRUPTIBLE. Which means + * not having the wait_queue head on the stack. + */ + err = mtd->erase(mtd, erase); +- if (!err) +- { ++ if (!err) { + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&waitq, &wait); +- if (erase->state != MTD_ERASE_DONE && erase->state != MTD_ERASE_FAILED) ++ if (erase->state != MTD_ERASE_DONE ++ && erase->state != MTD_ERASE_FAILED) + schedule(); + remove_wait_queue(&waitq, &wait); + set_current_state(TASK_RUNNING); +@@ -391,7 +386,7 @@ + return err; + } + +-static int concat_erase (struct mtd_info *mtd, struct erase_info *instr) ++static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) + { + struct mtd_concat *concat = CONCAT(mtd); + struct mtd_info *subdev; +@@ -402,10 +397,10 @@ + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + +- if(instr->addr > concat->mtd.size) ++ if (instr->addr > concat->mtd.size) + return -EINVAL; + +- if(instr->len + instr->addr > concat->mtd.size) ++ if (instr->len + instr->addr > concat->mtd.size) + return -EINVAL; + + /* +@@ -414,23 +409,22 @@ + * region info rather than looking at each particular sub-device + * in turn. + */ +- if (!concat->mtd.numeraseregions) +- { /* the easy case: device has uniform erase block size */ +- if(instr->addr & (concat->mtd.erasesize - 1)) ++ if (!concat->mtd.numeraseregions) { ++ /* the easy case: device has uniform erase block size */ ++ if (instr->addr & (concat->mtd.erasesize - 1)) + return -EINVAL; +- if(instr->len & (concat->mtd.erasesize - 1)) ++ if (instr->len & (concat->mtd.erasesize - 1)) + return -EINVAL; +- } +- else +- { /* device has variable erase size */ +- struct mtd_erase_region_info *erase_regions = concat->mtd.eraseregions; ++ } else { ++ /* device has variable erase size */ ++ struct mtd_erase_region_info *erase_regions = ++ concat->mtd.eraseregions; + + /* + * Find the erase region where the to-be-erased area begins: + */ +- for(i = 0; i < concat->mtd.numeraseregions && +- instr->addr >= erase_regions[i].offset; i++) +- ; ++ for (i = 0; i < concat->mtd.numeraseregions && ++ instr->addr >= erase_regions[i].offset; i++) ; + --i; + + /* +@@ -438,25 +432,26 @@ + * to-be-erased area begins. Verify that the starting + * offset is aligned to this region's erase size: + */ +- if (instr->addr & (erase_regions[i].erasesize-1)) ++ if (instr->addr & (erase_regions[i].erasesize - 1)) + return -EINVAL; + + /* + * now find the erase region where the to-be-erased area ends: + */ +- for(; i < concat->mtd.numeraseregions && +- (instr->addr + instr->len) >= erase_regions[i].offset ; ++i) +- ; ++ for (; i < concat->mtd.numeraseregions && ++ (instr->addr + instr->len) >= erase_regions[i].offset; ++ ++i) ; + --i; + /* + * check if the ending offset is aligned to this region's erase size + */ +- if ((instr->addr + instr->len) & (erase_regions[i].erasesize-1)) ++ if ((instr->addr + instr->len) & (erase_regions[i].erasesize - ++ 1)) + return -EINVAL; + } + + /* make a local copy of instr to avoid modifying the caller's struct */ +- erase = kmalloc(sizeof(struct erase_info),GFP_KERNEL); ++ erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL); + + if (!erase) + return -ENOMEM; +@@ -468,39 +463,40 @@ + * find the subdevice where the to-be-erased area begins, adjust + * starting offset to be relative to the subdevice start + */ +- for(i = 0; i < concat->num_subdev; i++) +- { ++ for (i = 0; i < concat->num_subdev; i++) { + subdev = concat->subdev[i]; +- if(subdev->size <= erase->addr) ++ if (subdev->size <= erase->addr) + erase->addr -= subdev->size; + else + break; +- } +- if(i >= concat->num_subdev) /* must never happen since size */ +- BUG(); /* limit has been verified above */ ++ } ++ ++ /* must never happen since size limit has been verified above */ ++ if (i >= concat->num_subdev) ++ BUG(); + + /* now do the erase: */ + err = 0; +- for(;length > 0; i++) /* loop for all subevices affected by this request */ +- { +- subdev = concat->subdev[i]; /* get current subdevice */ ++ for (; length > 0; i++) { ++ /* loop for all subdevices affected by this request */ ++ subdev = concat->subdev[i]; /* get current subdevice */ + + /* limit length to subdevice's size: */ +- if(erase->addr + length > subdev->size) ++ if (erase->addr + length > subdev->size) + erase->len = subdev->size - erase->addr; + else + erase->len = length; + +- if (!(subdev->flags & MTD_WRITEABLE)) +- { ++ if (!(subdev->flags & MTD_WRITEABLE)) { + err = -EROFS; + break; + } + length -= erase->len; +- if ((err = concat_dev_erase(subdev, erase))) +- { +- if(err == -EINVAL) /* sanity check: must never happen since */ +- BUG(); /* block alignment has been checked above */ ++ if ((err = concat_dev_erase(subdev, erase))) { ++ /* sanity check: should never happen since ++ * block alignment has been checked above */ ++ if (err == -EINVAL) ++ BUG(); + break; + } + /* +@@ -523,85 +519,79 @@ + return 0; + } + +-static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len) ++static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len) + { + struct mtd_concat *concat = CONCAT(mtd); + int i, err = -EINVAL; + +- if ((len + ofs) > mtd->size) ++ if ((len + ofs) > mtd->size) + return -EINVAL; + +- for(i = 0; i < concat->num_subdev; i++) +- { ++ for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + size_t size; + +- if (ofs >= subdev->size) +- { +- size = 0; ++ if (ofs >= subdev->size) { ++ size = 0; + ofs -= subdev->size; ++ continue; + } ++ if (ofs + len > subdev->size) ++ size = subdev->size - ofs; + else +- { +- if (ofs + len > subdev->size) +- size = subdev->size - ofs; +- else +- size = len; ++ size = len; + +- err = subdev->lock(subdev, ofs, size); ++ err = subdev->lock(subdev, ofs, size); + +- if(err) +- break; ++ if (err) ++ break; + +- len -= size; +- if(len == 0) +- break; ++ len -= size; ++ if (len == 0) ++ break; + +- err = -EINVAL; +- ofs = 0; +- } ++ err = -EINVAL; ++ ofs = 0; + } ++ + return err; + } + +-static int concat_unlock (struct mtd_info *mtd, loff_t ofs, size_t len) ++static int concat_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) + { + struct mtd_concat *concat = CONCAT(mtd); + int i, err = 0; + +- if ((len + ofs) > mtd->size) ++ if ((len + ofs) > mtd->size) + return -EINVAL; + +- for(i = 0; i < concat->num_subdev; i++) +- { ++ for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + size_t size; + +- if (ofs >= subdev->size) +- { +- size = 0; ++ if (ofs >= subdev->size) { ++ size = 0; + ofs -= subdev->size; ++ continue; + } ++ if (ofs + len > subdev->size) ++ size = subdev->size - ofs; + else +- { +- if (ofs + len > subdev->size) +- size = subdev->size - ofs; +- else +- size = len; ++ size = len; + +- err = subdev->unlock(subdev, ofs, size); ++ err = subdev->unlock(subdev, ofs, size); + +- if(err) +- break; ++ if (err) ++ break; + +- len -= size; +- if(len == 0) +- break; ++ len -= size; ++ if (len == 0) ++ break; + +- err = -EINVAL; +- ofs = 0; +- } ++ err = -EINVAL; ++ ofs = 0; + } ++ + return err; + } + +@@ -610,8 +600,7 @@ + struct mtd_concat *concat = CONCAT(mtd); + int i; + +- for(i = 0; i < concat->num_subdev; i++) +- { ++ for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + subdev->sync(subdev); + } +@@ -622,10 +611,9 @@ + struct mtd_concat *concat = CONCAT(mtd); + int i, rc = 0; + +- for(i = 0; i < concat->num_subdev; i++) +- { ++ for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; +- if((rc = subdev->suspend(subdev)) < 0) ++ if ((rc = subdev->suspend(subdev)) < 0) + return rc; + } + return rc; +@@ -636,8 +624,7 @@ + struct mtd_concat *concat = CONCAT(mtd); + int i; + +- for(i = 0; i < concat->num_subdev; i++) +- { ++ for (i = 0; i < concat->num_subdev; i++) { + struct mtd_info *subdev = concat->subdev[i]; + subdev->resume(subdev); + } +@@ -649,11 +636,10 @@ + * stored to *new_dev upon success. This function does _not_ + * register any devices: this is the caller's responsibility. + */ +-struct mtd_info *mtd_concat_create( +- struct mtd_info *subdev[], /* subdevices to concatenate */ +- int num_devs, /* number of subdevices */ +- char *name) /* name for the new device */ +-{ ++struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to concatenate */ ++ int num_devs, /* number of subdevices */ ++ char *name) ++{ /* name for the new device */ + int i; + size_t size; + struct mtd_concat *concat; +@@ -661,94 +647,103 @@ + int num_erase_region; + + printk(KERN_NOTICE "Concatenating MTD devices:\n"); +- for(i = 0; i < num_devs; i++) ++ for (i = 0; i < num_devs; i++) + printk(KERN_NOTICE "(%d): \"%s\"\n", i, subdev[i]->name); + printk(KERN_NOTICE "into device \"%s\"\n", name); + + /* allocate the device structure */ + size = SIZEOF_STRUCT_MTD_CONCAT(num_devs); +- concat = kmalloc (size, GFP_KERNEL); +- if(!concat) +- { +- printk ("memory allocation error while creating concatenated device \"%s\"\n", +- name); +- return NULL; ++ concat = kmalloc(size, GFP_KERNEL); ++ if (!concat) { ++ printk ++ ("memory allocation error while creating concatenated device \"%s\"\n", ++ name); ++ return NULL; + } + memset(concat, 0, size); +- concat->subdev = (struct mtd_info **)(concat + 1); ++ concat->subdev = (struct mtd_info **) (concat + 1); + + /* + * Set up the new "super" device's MTD object structure, check for + * incompatibilites between the subdevices. + */ +- concat->mtd.type = subdev[0]->type; +- concat->mtd.flags = subdev[0]->flags; +- concat->mtd.size = subdev[0]->size; ++ concat->mtd.type = subdev[0]->type; ++ concat->mtd.flags = subdev[0]->flags; ++ concat->mtd.size = subdev[0]->size; + concat->mtd.erasesize = subdev[0]->erasesize; +- concat->mtd.oobblock = subdev[0]->oobblock; +- concat->mtd.oobsize = subdev[0]->oobsize; +- concat->mtd.ecctype = subdev[0]->ecctype; +- concat->mtd.eccsize = subdev[0]->eccsize; ++ concat->mtd.oobblock = subdev[0]->oobblock; ++ concat->mtd.oobsize = subdev[0]->oobsize; ++ concat->mtd.ecctype = subdev[0]->ecctype; ++ concat->mtd.eccsize = subdev[0]->eccsize; ++ if (subdev[0]->read_ecc) ++ concat->mtd.read_ecc = concat_read_ecc; ++ if (subdev[0]->write_ecc) ++ concat->mtd.write_ecc = concat_write_ecc; ++ if (subdev[0]->read_oob) ++ concat->mtd.read_oob = concat_read_oob; ++ if (subdev[0]->write_oob) ++ concat->mtd.write_oob = concat_write_oob; + +- concat->subdev[0] = subdev[0]; ++ concat->subdev[0] = subdev[0]; + +- for(i = 1; i < num_devs; i++) +- { +- if(concat->mtd.type != subdev[i]->type) +- { ++ for (i = 1; i < num_devs; i++) { ++ if (concat->mtd.type != subdev[i]->type) { + kfree(concat); +- printk ("Incompatible device type on \"%s\"\n", subdev[i]->name); ++ printk("Incompatible device type on \"%s\"\n", ++ subdev[i]->name); + return NULL; + } +- if(concat->mtd.flags != subdev[i]->flags) +- { /* +- * Expect all flags except MTD_WRITEABLE to be equal on +- * all subdevices. ++ if (concat->mtd.flags != subdev[i]->flags) { ++ /* ++ * Expect all flags except MTD_WRITEABLE to be ++ * equal on all subdevices. + */ +- if((concat->mtd.flags ^ subdev[i]->flags) & ~MTD_WRITEABLE) +- { ++ if ((concat->mtd.flags ^ subdev[i]-> ++ flags) & ~MTD_WRITEABLE) { + kfree(concat); +- printk ("Incompatible device flags on \"%s\"\n", subdev[i]->name); ++ printk("Incompatible device flags on \"%s\"\n", ++ subdev[i]->name); + return NULL; +- } +- else /* if writeable attribute differs, make super device writeable */ +- concat->mtd.flags |= subdev[i]->flags & MTD_WRITEABLE; ++ } else ++ /* if writeable attribute differs, ++ make super device writeable */ ++ concat->mtd.flags |= ++ subdev[i]->flags & MTD_WRITEABLE; + } + concat->mtd.size += subdev[i]->size; +- if(concat->mtd.oobblock != subdev[i]->oobblock || +- concat->mtd.oobsize != subdev[i]->oobsize || +- concat->mtd.ecctype != subdev[i]->ecctype || +- concat->mtd.eccsize != subdev[i]->eccsize) +- { ++ if (concat->mtd.oobblock != subdev[i]->oobblock || ++ concat->mtd.oobsize != subdev[i]->oobsize || ++ concat->mtd.ecctype != subdev[i]->ecctype || ++ concat->mtd.eccsize != subdev[i]->eccsize || ++ !concat->mtd.read_ecc != !subdev[i]->read_ecc || ++ !concat->mtd.write_ecc != !subdev[i]->write_ecc || ++ !concat->mtd.read_oob != !subdev[i]->read_oob || ++ !concat->mtd.write_oob != !subdev[i]->write_oob) { + kfree(concat); +- printk ("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name); ++ printk("Incompatible OOB or ECC data on \"%s\"\n", ++ subdev[i]->name); + return NULL; + } + concat->subdev[i] = subdev[i]; +- ++ + } + +- concat->num_subdev = num_devs; +- concat->mtd.name = name; ++ concat->num_subdev = num_devs; ++ concat->mtd.name = name; + + /* + * NOTE: for now, we do not provide any readv()/writev() methods + * because they are messy to implement and they are not + * used to a great extent anyway. + */ +- concat->mtd.erase = concat_erase; +- concat->mtd.read = concat_read; +- concat->mtd.write = concat_write; +- concat->mtd.read_ecc = concat_read_ecc; +- concat->mtd.write_ecc = concat_write_ecc; +- concat->mtd.read_oob = concat_read_oob; +- concat->mtd.write_oob = concat_write_oob; +- concat->mtd.sync = concat_sync; +- concat->mtd.lock = concat_lock; +- concat->mtd.unlock = concat_unlock; +- concat->mtd.suspend = concat_suspend; +- concat->mtd.resume = concat_resume; +- ++ concat->mtd.erase = concat_erase; ++ concat->mtd.read = concat_read; ++ concat->mtd.write = concat_write; ++ concat->mtd.sync = concat_sync; ++ concat->mtd.lock = concat_lock; ++ concat->mtd.unlock = concat_unlock; ++ concat->mtd.suspend = concat_suspend; ++ concat->mtd.resume = concat_resume; + + /* + * Combine the erase block size info of the subdevices: +@@ -758,44 +753,44 @@ + */ + max_erasesize = curr_erasesize = subdev[0]->erasesize; + num_erase_region = 1; +- for(i = 0; i < num_devs; i++) +- { +- if(subdev[i]->numeraseregions == 0) +- { /* current subdevice has uniform erase size */ +- if(subdev[i]->erasesize != curr_erasesize) +- { /* if it differs from the last subdevice's erase size, count it */ ++ for (i = 0; i < num_devs; i++) { ++ if (subdev[i]->numeraseregions == 0) { ++ /* current subdevice has uniform erase size */ ++ if (subdev[i]->erasesize != curr_erasesize) { ++ /* if it differs from the last subdevice's erase size, count it */ + ++num_erase_region; + curr_erasesize = subdev[i]->erasesize; +- if(curr_erasesize > max_erasesize) ++ if (curr_erasesize > max_erasesize) + max_erasesize = curr_erasesize; + } +- } +- else +- { /* current subdevice has variable erase size */ ++ } else { ++ /* current subdevice has variable erase size */ + int j; +- for(j = 0; j < subdev[i]->numeraseregions; j++) +- { /* walk the list of erase regions, count any changes */ +- if(subdev[i]->eraseregions[j].erasesize != curr_erasesize) +- { ++ for (j = 0; j < subdev[i]->numeraseregions; j++) { ++ ++ /* walk the list of erase regions, count any changes */ ++ if (subdev[i]->eraseregions[j].erasesize != ++ curr_erasesize) { + ++num_erase_region; +- curr_erasesize = subdev[i]->eraseregions[j].erasesize; +- if(curr_erasesize > max_erasesize) ++ curr_erasesize = ++ subdev[i]->eraseregions[j]. ++ erasesize; ++ if (curr_erasesize > max_erasesize) + max_erasesize = curr_erasesize; + } + } + } + } + +- if(num_erase_region == 1) +- { /* ++ if (num_erase_region == 1) { ++ /* + * All subdevices have the same uniform erase size. + * This is easy: + */ + concat->mtd.erasesize = curr_erasesize; + concat->mtd.numeraseregions = 0; +- } +- else +- { /* ++ } else { ++ /* + * erase block size varies across the subdevices: allocate + * space to store the data describing the variable erase regions + */ +@@ -804,13 +799,14 @@ + + concat->mtd.erasesize = max_erasesize; + concat->mtd.numeraseregions = num_erase_region; +- concat->mtd.eraseregions = erase_region_p = kmalloc ( +- num_erase_region * sizeof(struct mtd_erase_region_info), GFP_KERNEL); +- if(!erase_region_p) +- { ++ concat->mtd.eraseregions = erase_region_p = ++ kmalloc(num_erase_region * ++ sizeof (struct mtd_erase_region_info), GFP_KERNEL); ++ if (!erase_region_p) { + kfree(concat); +- printk ("memory allocation error while creating erase region list" +- " for device \"%s\"\n", name); ++ printk ++ ("memory allocation error while creating erase region list" ++ " for device \"%s\"\n", name); + return NULL; + } + +@@ -820,46 +816,53 @@ + */ + curr_erasesize = subdev[0]->erasesize; + begin = position = 0; +- for(i = 0; i < num_devs; i++) +- { +- if(subdev[i]->numeraseregions == 0) +- { /* current subdevice has uniform erase size */ +- if(subdev[i]->erasesize != curr_erasesize) +- { /* ++ for (i = 0; i < num_devs; i++) { ++ if (subdev[i]->numeraseregions == 0) { ++ /* current subdevice has uniform erase size */ ++ if (subdev[i]->erasesize != curr_erasesize) { ++ /* + * fill in an mtd_erase_region_info structure for the area + * we have walked so far: + */ +- erase_region_p->offset = begin; +- erase_region_p->erasesize = curr_erasesize; +- erase_region_p->numblocks = (position - begin) / curr_erasesize; ++ erase_region_p->offset = begin; ++ erase_region_p->erasesize = ++ curr_erasesize; ++ erase_region_p->numblocks = ++ (position - begin) / curr_erasesize; + begin = position; + + curr_erasesize = subdev[i]->erasesize; + ++erase_region_p; + } + position += subdev[i]->size; +- } +- else +- { /* current subdevice has variable erase size */ ++ } else { ++ /* current subdevice has variable erase size */ + int j; +- for(j = 0; j < subdev[i]->numeraseregions; j++) +- { /* walk the list of erase regions, count any changes */ +- if(subdev[i]->eraseregions[j].erasesize != curr_erasesize) +- { +- erase_region_p->offset = begin; +- erase_region_p->erasesize = curr_erasesize; +- erase_region_p->numblocks = (position - begin) / curr_erasesize; ++ for (j = 0; j < subdev[i]->numeraseregions; j++) { ++ /* walk the list of erase regions, count any changes */ ++ if (subdev[i]->eraseregions[j]. ++ erasesize != curr_erasesize) { ++ erase_region_p->offset = begin; ++ erase_region_p->erasesize = ++ curr_erasesize; ++ erase_region_p->numblocks = ++ (position - ++ begin) / curr_erasesize; + begin = position; + +- curr_erasesize = subdev[i]->eraseregions[j].erasesize; ++ curr_erasesize = ++ subdev[i]->eraseregions[j]. ++ erasesize; + ++erase_region_p; + } +- position += subdev[i]->eraseregions[j].numblocks * curr_erasesize; ++ position += ++ subdev[i]->eraseregions[j]. ++ numblocks * curr_erasesize; + } + } + } + /* Now write the final entry */ +- erase_region_p->offset = begin; ++ erase_region_p->offset = begin; + erase_region_p->erasesize = curr_erasesize; + erase_region_p->numblocks = (position - begin) / curr_erasesize; + } +@@ -874,16 +877,14 @@ + void mtd_concat_destroy(struct mtd_info *mtd) + { + struct mtd_concat *concat = CONCAT(mtd); +- if(concat->mtd.numeraseregions) ++ if (concat->mtd.numeraseregions) + kfree(concat->mtd.eraseregions); + kfree(concat); + } + +- + EXPORT_SYMBOL(mtd_concat_create); + EXPORT_SYMBOL(mtd_concat_destroy); + +- + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Robert Kaiser <rkaiser@sysgo.de>"); + MODULE_DESCRIPTION("Generic support for concatenating of MTD devices"); +--- linux-2.6.5/drivers/mtd/maps/Makefile~heh 2004-04-03 22:36:12.000000000 -0500 ++++ linux-2.6.5/drivers/mtd/maps/Makefile 2004-04-30 20:57:36.000000000 -0400 +@@ -17,12 +17,14 @@ + obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o + obj-$(CONFIG_MTD_EPXA10DB) += epxa10db-flash.o + obj-$(CONFIG_MTD_IQ80310) += iq80310.o ++obj-$(CONFIG_MTD_IQ80321) += iq80321.o + obj-$(CONFIG_MTD_L440GX) += l440gx.o + obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o + obj-$(CONFIG_MTD_ICH2ROM) += ich2rom.o + obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o + obj-$(CONFIG_MTD_LUBBOCK) += lubbock-flash.o + obj-$(CONFIG_MTD_MBX860) += mbx860.o ++obj-$(CONFIG_MTD_NORA) += nora.o + obj-$(CONFIG_MTD_CEIVA) += ceiva.o + obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o + obj-$(CONFIG_MTD_PHYSMAP) += physmap.o +--- linux-2.6.5/drivers/mtd/maps/sa1100-flash.c~heh 2004-04-03 22:36:51.000000000 -0500 ++++ linux-2.6.5/drivers/mtd/maps/sa1100-flash.c 2004-04-30 20:57:36.000000000 -0400 +@@ -14,6 +14,7 @@ + #include <linux/init.h> + #include <linux/errno.h> + #include <linux/slab.h> ++#include <linux/device.h> + + #include <linux/mtd/mtd.h> + #include <linux/mtd/map.h> +@@ -887,6 +888,7 @@ + int width; + void *vbase; + void (*set_vpp)(struct map_info *, int); ++ char name[16]; + struct map_info *map; + struct mtd_info *mtd; + struct resource *res; +@@ -925,6 +927,8 @@ + } + + sa[i].map = maps + i; ++ sa[i].map->name = sa[i].name; ++ sprintf(sa[i].name, "sa1100-%d", i); + + sa[i].vbase = ioremap(sa[i].base, sa[i].size); + if (!sa[i].vbase) { +@@ -986,7 +990,7 @@ + */ + #ifdef CONFIG_MTD_CONCAT + *rmtd = mtd_concat_create(subdev, found, +- "sa1100 flash"); ++ "sa1100"); + if (*rmtd == NULL) + ret = -ENXIO; + #else +@@ -1044,13 +1048,9 @@ + * - Is the MSC setup for flash (no -> failure) + * - Probe for flash + */ +- +-static struct map_info sa1100_probe_map __initdata = { +- .name = "SA1100-flash", +-}; +- +-static void __init sa1100_probe_one_cs(unsigned int msc, unsigned long phys) ++static void sa1100_probe_one_cs(unsigned int msc, unsigned long phys) + { ++ struct map_info map; + struct mtd_info *mtd; + + printk(KERN_INFO "* Probing 0x%08lx: MSC = 0x%04x %d bit ", +@@ -1066,19 +1066,23 @@ + return; + } + +- sa1100_probe_map.buswidth = msc & MSC_RBW ? 2 : 4; +- sa1100_probe_map.size = SZ_1M; +- sa1100_probe_map.phys = phys; +- sa1100_probe_map.virt = (unsigned long)ioremap(phys, SZ_1M); +- if (sa1100_probe_map.virt == 0) ++ memset(&map, 0, sizeof(map)); ++ ++ map.name = "Probe"; ++ map.buswidth = msc & MSC_RBW ? 2 : 4; ++ map.size = SZ_1M; ++ map.phys = NO_XIP; ++ map.virt = (unsigned long)ioremap(phys, SZ_1M); ++ if (map.virt == 0) + goto fail; +- simple_map_init(&sa1100_probe_map); ++ ++ simple_map_init(&map); + + /* Shame cfi_probe blurts out kernel messages... */ +- mtd = do_map_probe("cfi_probe", &sa1100_probe_map); ++ mtd = do_map_probe("cfi_probe", &map); + if (mtd) + map_destroy(mtd); +- iounmap((void *)sa1100_probe_map.virt); ++ iounmap((void *)map.virt); + + if (!mtd) + goto fail; +@@ -1090,7 +1094,7 @@ + printk("failed\n"); + } + +-static void __init sa1100_probe_flash(void) ++static void sa1100_probe_flash(void) + { + printk(KERN_INFO "-- SA11xx Flash probe. Please report results.\n"); + sa1100_probe_one_cs(MSC0, SA1100_CS0_PHYS); +@@ -1321,10 +1325,9 @@ + kfree(parsed_parts); + } + +-static struct mtd_info *mymtd; +- +-static int __init sa1100_mtd_init(void) ++static int __init sa1100_mtd_probe(struct device *dev) + { ++ struct mtd_info *mtd; + int ret; + int nr; + +@@ -1332,21 +1335,74 @@ + if (nr < 0) + return nr; + +- ret = sa1100_setup_mtd(info, nr, &mymtd); +- if (ret == 0) +- sa1100_locate_partitions(mymtd); ++ ret = sa1100_setup_mtd(info, nr, &mtd); ++ if (ret == 0) { ++ sa1100_locate_partitions(mtd); ++ dev_set_drvdata(dev, mtd); ++ } + + return ret; + } + +-static void __exit sa1100_mtd_cleanup(void) ++static int __exit sa1100_mtd_remove(struct device *dev) + { +- sa1100_destroy_mtd(info, mymtd); ++ struct mtd_info *mtd = dev_get_drvdata(dev); ++ sa1100_destroy_mtd(info, mtd); + sa1100_destroy_partitions(); ++ return 0; ++} ++ ++static int sa1100_mtd_suspend(struct device *dev, u32 level, u32 state) ++{ ++ struct mtd_info *mtd = dev_get_drvdata(dev); ++ if (level == SUSPEND_SAVE_STATE) ++ mtd->suspend(mtd); ++ return 0; ++} ++ ++static int sa1100_mtd_resume(struct device *dev, u32 level) ++{ ++ struct mtd_info *mtd = dev_get_drvdata(dev); ++ if (level == RESUME_RESTORE_STATE) ++ mtd->resume(mtd); ++ return 0; ++} ++ ++static struct platform_device sa1100_mtd_device = { ++ .name = "flash", ++ .id = 0, ++}; ++ ++static struct device_driver sa1100_mtd_driver = { ++ .name = "flash", ++ .bus = &platform_bus_type, ++ .probe = sa1100_mtd_probe, ++#ifdef MODULE ++ .remove = sa1100_mtd_remove, ++#endif ++ .suspend = sa1100_mtd_suspend, ++ .resume = sa1100_mtd_resume, ++}; ++ ++static int __init sa1100_mtd_init(void) ++{ ++ int ret = driver_register(&sa1100_mtd_driver); ++ if (ret == 0) { ++ ret = platform_device_register(&sa1100_mtd_device); ++ if (ret) ++ driver_unregister(&sa1100_mtd_driver); ++ } ++ return ret; ++} ++ ++static void __exit sa1100_mtd_exit(void) ++{ ++ platform_device_unregister(&sa1100_mtd_device); ++ driver_unregister(&sa1100_mtd_driver); + } + + module_init(sa1100_mtd_init); +-module_exit(sa1100_mtd_cleanup); ++module_exit(sa1100_mtd_exit); + + MODULE_AUTHOR("Nicolas Pitre"); + MODULE_DESCRIPTION("SA1100 CFI map driver"); +--- linux-2.6.5/drivers/mtd/maps/pcmciamtd.c~heh 2004-04-03 22:36:19.000000000 -0500 ++++ linux-2.6.5/drivers/mtd/maps/pcmciamtd.c 2004-04-30 20:57:36.000000000 -0400 +@@ -25,10 +25,9 @@ + #include <pcmcia/ds.h> + + #include <linux/mtd/map.h> +-#include <linux/mtd/mtd.h> + +-#ifdef CONFIG_MTD_DEBUG +-static int debug = CONFIG_MTD_DEBUG_VERBOSE; ++#if 1 //def CONFIG_MTD_DEBUG ++static int debug = 5; //CONFIG_MTD_DEBUG_VERBOSE; + MODULE_PARM(debug, "i"); + MODULE_PARM_DESC(debug, "Set Debug Level 0=quiet, 5=noisy"); + #undef DEBUG +@@ -88,7 +87,7 @@ + static int setvpp; + + /* Force card to be treated as FLASH, ROM or RAM */ +-static int mem_type; ++static int mem_type = 1; + + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>"); +--- linux-2.6.5/drivers/mtd/maps/pci.c~heh 2004-04-03 22:36:56.000000000 -0500 ++++ linux-2.6.5/drivers/mtd/maps/pci.c 2004-04-30 20:57:36.000000000 -0400 +@@ -22,6 +22,8 @@ + #include <linux/mtd/map.h> + #include <linux/mtd/partitions.h> + ++#include <asm/io.h> ++ + struct map_pci_info; + + struct mtd_pci_info { +--- linux-2.6.5/drivers/input/Kconfig~heh 2004-04-03 22:36:18.000000000 -0500 ++++ linux-2.6.5/drivers/input/Kconfig 2004-04-30 20:57:36.000000000 -0400 +@@ -80,7 +80,7 @@ + module will be called joydev. + + config INPUT_TSDEV +- tristate "Touchscreen interface" ++ tristate "Compaq Touchscreen interface" + depends on INPUT + ---help--- + Say Y here if you have an application that only can understand the +@@ -102,6 +102,10 @@ + depends on INPUT_TSDEV + default "320" + ++config INPUT_TSLIBDEV ++ tristate "TSLIB Touchscreen interface" ++ depends on INPUT ++ + config INPUT_EVDEV + tristate "Event interface" + depends on INPUT +--- linux-2.6.5/drivers/input/serio/Kconfig~heh 2004-04-03 22:37:07.000000000 -0500 ++++ linux-2.6.5/drivers/input/serio/Kconfig 2004-04-30 20:57:36.000000000 -0400 +@@ -80,7 +80,7 @@ + + config SERIO_RPCKBD + tristate "Acorn RiscPC keyboard controller" +- depends on ARCH_ACORN && SERIO ++ depends on (ARCH_ACORN || ARCH_CLPS7500) && SERIO + default y + help + Say Y here if you have the Acorn RiscPC and want to use an AT +@@ -89,6 +89,18 @@ + To compile this driver as a module, choose M here: the + module will be called rpckbd. + ++config SERIO_CLPS7500 ++ tristate "CLPS7500 PS/2 mouse port controller" ++ depends on ARCH_CLPS7500 && SERIO ++ help ++ Say Y here if you have CLPS7500 based hardware and want to use ++ the mouse port. ++ ++ This driver is also available as a module ( = code which can be ++ inserted in and removed from the running kernel whenever you want). ++ The module will be called clps7500ps2. If you want to compile it ++ as a module, say M here and read <file:Documentation/modules.txt>. ++ + config SERIO_AMBAKMI + tristate "AMBA KMI keyboard controller" + depends on ARCH_INTEGRATOR && SERIO +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/input/serio/sa1100ir.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,90 @@ ++/* ++ * linux/drivers/input/serio/sa1100ir.c ++ * ++ * 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. ++ */ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/serio.h> ++ ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/hardware.h> ++ ++ ++ ++struct sa1100_kbd { ++ struct serio io; ++ void *base; ++ int irq; ++}; ++ ++static void sa1100ir_int(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ struct sa1100_kbd *kbd = dev_id; ++ unsigned int status; ++ ++ do { ++ unsigned int flag, data; ++ ++ status = readl(kbd->base + UTSR1); ++ if (!(status & UTSR1_RNE)) ++ break; ++ ++ flag = (status & UTSR1_FRE ? SERIO_FRAME : 0) | ++ (status & UTSR1_PRE ? SERIO_PARITY : 0); ++ ++ data = readl(kbd->base + UTDR); ++ ++ serio_interrupt(&kbd->io, data, flag); ++ } while (1); ++ ++ status = readl(kbd->base + UTSR0) & UTSR0_RID | UTSR0_RBB | UTSR0_REB; ++ if (status) ++ writel(status, kbd->base + UTSR0); ++} ++ ++static int sa1100ir_kbd_open(struct serio *io) ++{ ++ struct sa1100_kbd *kbd = io->driver; ++ int ret; ++ ++ ret = request_irq(kbd->irq, sa1100ir_int, 0, kbd->io.phys, kbd); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static void sa1100ir_kbd_close(struct serio *io) ++{ ++ struct sa1100_kbd *kbd = io->driver; ++ ++ free_irq(kbd->irq, kbd); ++} ++ ++static struct sa1100_kbd sa1100_kbd = { ++ .io = { ++ .type = 0, ++ .open = sa1100ir_kbd_open, ++ .close = sa1100ir_kbd_close, ++ .name = "SA11x0 IR port", ++ .phys = "sa11x0/ir", ++ .driver = &sa1100_kbd, ++ }, ++}; ++ ++static int __init sa1100_kbd_init(void) ++{ ++ serio_register_port(&sa1100_kbd.io); ++} ++ ++static void __exit sa1100_kbd_exit(void) ++{ ++ serio_unregister_port(&sa1100_kbd.io); ++} ++ ++module_init(sa1100_kbd_init); ++module_exit(sa1100_kbd_exit); +--- linux-2.6.5/drivers/input/serio/Makefile~heh 2004-04-03 22:36:16.000000000 -0500 ++++ linux-2.6.5/drivers/input/serio/Makefile 2004-04-30 20:57:36.000000000 -0400 +@@ -10,6 +10,7 @@ + obj-$(CONFIG_SERIO_SERPORT) += serport.o + obj-$(CONFIG_SERIO_CT82C710) += ct82c710.o + obj-$(CONFIG_SERIO_RPCKBD) += rpckbd.o ++obj-$(CONFIG_SERIO_CLPS7500) += clps7500ps2.o + obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o + obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o + obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/input/tslibdev.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,358 @@ ++/* ++ * linux/drivers/input/tslibdev.c ++ * ++ * Copyright (C) 2002 Russell King ++ * ++ * From tsdev.c: ++ * ++ * Copyright (c) 2001 "Crazy" james Simmons ++ * ++ * Input driver to Touchscreen device driver module. ++ * ++ * Sponsored by Transvirtual Technology ++ */ ++ ++/* ++ * 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 ++ * ++ * Should you need to contact me, the author, you can do so either by ++ * e-mail - mail your message to <jsimmons@transvirtual.com>. ++ */ ++ ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/input.h> ++#include <linux/config.h> ++#include <linux/smp_lock.h> ++#include <linux/random.h> ++#include <linux/time.h> ++#include <linux/list.h> ++#include <linux/miscdevice.h> ++ ++struct ucb1x00_dev { ++ int exist; ++ char name[16]; ++ wait_queue_head_t wait; ++ struct list_head list; ++ struct input_handle handle; ++ int x; ++ int y; ++ int pressure; ++}; ++ ++struct ts_event { ++ u16 pressure; ++ u16 x; ++ u16 y; ++ u16 pad; ++ struct timeval stamp; ++}; ++ ++#define TSDEV_BUFFER_SIZE 64 ++ ++struct ucb1x00_list { ++ struct list_head list; ++ struct fasync_struct *fasync; ++ struct ucb1x00_dev *tsdev; ++ unsigned int head; ++ unsigned int tail; ++ struct ts_event event[TSDEV_BUFFER_SIZE]; ++}; ++ ++static struct input_handler ucb1x00_handler; ++static struct ucb1x00_dev *ucb1x00_dev; ++ ++static void ucb1x00_remove(struct ucb1x00_dev *tsdev); ++ ++ ++static int ucb1x00_fasync(int fd, struct file *file, int on) ++{ ++ struct ucb1x00_list *list = file->private_data; ++ int retval; ++ ++ retval = fasync_helper(fd, file, on, &list->fasync); ++ return retval < 0 ? retval : 0; ++} ++ ++static int ucb1x00_open(struct inode *inode, struct file *file) ++{ ++ struct ucb1x00_list *list; ++ int empty; ++ ++ if (!ucb1x00_dev || !ucb1x00_dev->exist) ++ return -ENODEV; ++ ++ printk(KERN_WARNING ++ "tslibdev: process %s (%d) uses obsolete tslib device\n", ++ current->comm, current->pid); ++ ++ list = kmalloc(sizeof(struct ucb1x00_list), GFP_KERNEL); ++ if (!list) ++ return -ENOMEM; ++ ++ memset(list, 0, sizeof(struct ucb1x00_list)); ++ ++ empty = list_empty(&ucb1x00_dev->list); ++ ++ list->tsdev = ucb1x00_dev; ++ list_add(&list->list, &list->tsdev->list); ++ ++ file->private_data = list; ++ ++ if (empty && list->tsdev->exist) ++ input_open_device(&list->tsdev->handle); ++ ++ return 0; ++} ++ ++static int ucb1x00_release(struct inode *inode, struct file *file) ++{ ++ struct ucb1x00_list *list = file->private_data; ++ ++ ucb1x00_fasync(-1, file, 0); ++ ++ list_del(&list->list); ++ ++ ucb1x00_remove(list->tsdev); ++ ++ kfree(list); ++ ++ return 0; ++} ++ ++static ssize_t ++ucb1x00_read(struct file *file, char *buffer, size_t count, loff_t * ppos) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ struct ucb1x00_list *list = file->private_data; ++ int retval = 0; ++ ++ if (list->head == list->tail) { ++ add_wait_queue(&list->tsdev->wait, &wait); ++ ++ while (list->head == list->tail) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ if (!list->tsdev->exist) { ++ retval = -ENODEV; ++ break; ++ } ++ if (file->f_flags & O_NONBLOCK) { ++ retval = -EAGAIN; ++ break; ++ } ++ if (signal_pending(current)) { ++ retval = -ERESTARTSYS; ++ break; ++ } ++ schedule(); ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&list->tsdev->wait, &wait); ++ } ++ ++ if (retval) ++ return retval; ++ ++ while (list->head != list->tail && count >= sizeof(struct ts_event)) { ++ if (copy_to_user(buffer, list->event + list->tail, ++ sizeof(struct ts_event))) ++ return retval ? retval : -EFAULT; ++ list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1); ++ retval += sizeof(struct ts_event); ++ buffer += sizeof(struct ts_event); ++ count -= sizeof(struct ts_event); ++ } ++ return retval; ++} ++ ++/* No kernel lock - fine */ ++static unsigned int ucb1x00_poll(struct file *file, poll_table * wait) ++{ ++ struct ucb1x00_list *list = file->private_data; ++ ++ poll_wait(file, &list->tsdev->wait, wait); ++ if (list->head != list->tail || !list->tsdev->exist) ++ return POLLIN | POLLRDNORM; ++ return 0; ++} ++ ++static int ++ucb1x00_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ return -EINVAL; ++} ++ ++struct file_operations ucb1x00_fops = { ++ .owner = THIS_MODULE, ++ .open = ucb1x00_open, ++ .release = ucb1x00_release, ++ .read = ucb1x00_read, ++ .poll = ucb1x00_poll, ++ .fasync = ucb1x00_fasync, ++ .ioctl = ucb1x00_ioctl, ++}; ++ ++/* ++ * 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, ++ .devfs_name = "touchscreen/ucb1x00", ++}; ++ ++static void ucb1x00_remove(struct ucb1x00_dev *tsdev) ++{ ++ if (list_empty(&tsdev->list)) { ++ if (tsdev->exist) { ++ input_close_device(&tsdev->handle); ++ wake_up_interruptible(&tsdev->wait); ++ } else { ++ misc_deregister(&ucb1x00_ts_dev); ++ ucb1x00_dev = NULL; ++ kfree(tsdev); ++ } ++ } ++} ++ ++ ++static void ++ucb1x00_event(struct input_handle *handle, unsigned int type, unsigned int code, ++ int value) ++{ ++ struct ucb1x00_dev *tsdev = handle->private; ++ struct list_head *l; ++ ++ /* sorry, we only handle absolute stuff */ ++ if (type == EV_ABS) { ++ switch (code) { ++ case ABS_X: ++ tsdev->x = value; ++ break; ++ case ABS_Y: ++ tsdev->y = value; ++ break; ++ case ABS_PRESSURE: ++ tsdev->pressure = value; ++ break; ++ } ++ return; ++ } ++ ++ if (type != EV_SYN || code != SYN_REPORT) ++ return; ++ ++ list_for_each(l, &tsdev->list) { ++ struct ucb1x00_list *list = list_entry(l, struct ucb1x00_list, list); ++ list->event[list->head].pressure = tsdev->pressure; ++ if (tsdev->pressure) { ++ list->event[list->head].x = tsdev->x; ++ list->event[list->head].y = tsdev->y; ++ } else { ++ list->event[list->head].x = 0; ++ list->event[list->head].y = 0; ++ } ++ do_gettimeofday(&list->event[list->head].stamp); ++ list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1); ++ kill_fasync(&list->fasync, SIGIO, POLL_IN); ++ } ++ wake_up_interruptible(&tsdev->wait); ++} ++ ++static struct input_handle * ++ucb1x00_connect(struct input_handler *handler, struct input_dev *dev, ++ struct input_device_id *id) ++{ ++ struct ucb1x00_dev *tsdev; ++ ++ if (ucb1x00_dev) ++ return NULL; ++ ++ tsdev = kmalloc(sizeof(struct ucb1x00_dev), GFP_KERNEL); ++ if (!tsdev) ++ return NULL; ++ ++ memset(tsdev, 0, sizeof(struct ucb1x00_dev)); ++ init_waitqueue_head(&tsdev->wait); ++ INIT_LIST_HEAD(&tsdev->list); ++ ++ ucb1x00_dev = tsdev; ++ ++ strcpy(tsdev->name, ucb1x00_ts_dev.name); ++ ++ tsdev->handle.dev = dev; ++ tsdev->handle.name = tsdev->name; ++ tsdev->handle.handler = handler; ++ tsdev->handle.private = tsdev; ++ ++ misc_register(&ucb1x00_ts_dev); ++ ++ tsdev->exist = 1; ++ ++ return &tsdev->handle; ++} ++ ++static void ucb1x00_disconnect(struct input_handle *handle) ++{ ++ struct ucb1x00_dev *tsdev = handle->private; ++ ++ tsdev->exist = 0; ++ ucb1x00_remove(tsdev); ++} ++ ++static struct input_device_id ucb1x00_ids[] = { ++ { ++ .flags = INPUT_DEVICE_ID_MATCH_ABSBIT, ++ .evbit = { BIT(EV_ABS) }, ++ .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) }, ++ }, ++ ++ {},/* Terminating entry */ ++}; ++ ++MODULE_DEVICE_TABLE(input, ucb1x00_ids); ++ ++static struct input_handler ucb1x00_handler = { ++ .event = ucb1x00_event, ++ .connect = ucb1x00_connect, ++ .disconnect = ucb1x00_disconnect, ++ .name = "touchscreen/ucb1x00", ++ .id_table = ucb1x00_ids, ++}; ++ ++static int __init ucb1x00_init(void) ++{ ++ input_register_handler(&ucb1x00_handler); ++ printk(KERN_INFO "ts: UCB1x00 touchscreen protocol output\n"); ++ return 0; ++} ++ ++static void __exit ucb1x00_exit(void) ++{ ++ input_unregister_handler(&ucb1x00_handler); ++} ++ ++module_init(ucb1x00_init); ++module_exit(ucb1x00_exit); ++ ++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); ++MODULE_DESCRIPTION("Input driver to UCB1x00 touchscreen converter"); +--- linux-2.6.5/drivers/input/Makefile~heh 2004-04-03 22:38:17.000000000 -0500 ++++ linux-2.6.5/drivers/input/Makefile 2004-04-30 20:57:36.000000000 -0400 +@@ -8,6 +8,7 @@ + obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o + obj-$(CONFIG_INPUT_JOYDEV) += joydev.o + obj-$(CONFIG_INPUT_EVDEV) += evdev.o ++obj-$(CONFIG_INPUT_TSLIBDEV) += tslibdev.o + obj-$(CONFIG_INPUT_TSDEV) += tsdev.o + obj-$(CONFIG_INPUT_POWER) += power.o + obj-$(CONFIG_INPUT_EVBUG) += evbug.o +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/char/sa1100-rtc.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,416 @@ ++/* ++ * Real Time Clock interface for Linux on Intel SA11x0/PXA2xx ++ * ++ * 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 <nico@cam.org> ++ * - 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 <cih@coventive.com> ++ * - Modify the bug setups RTC clock. ++ * ++ * 0.02 2001-02-27 Nils Faerber <nils@@kernelconcepts.de> ++ * - removed mktime(), added alarm irq clear ++ * ++ * 0.01 2000-10-01 Nils Faerber <nils@@kernelconcepts.de> ++ * - initial release ++ */ ++ ++#include <linux/module.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/string.h> ++#include <linux/init.h> ++#include <linux/poll.h> ++#include <linux/proc_fs.h> ++#include <linux/interrupt.h> ++#include <linux/rtc.h> ++ ++#include <asm/bitops.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/rtc.h> ++ ++#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_freq = 1024; ++static struct rtc_time rtc_alarm = { ++ .tm_year = 0, ++ .tm_mon = 0, ++ .tm_mday = 0, ++ .tm_hour = 0, ++ .tm_mon = 0, ++ .tm_sec = 0, ++}; ++ ++extern spinlock_t rtc_lock; ++ ++static int rtc_update_alarm(struct rtc_time *alrm) ++{ ++ struct rtc_time alarm_tm, now_tm; ++ unsigned long now, time; ++ int ret; ++ ++ do { ++ now = RCNR; ++ rtc_time_to_tm(now, &now_tm); ++ rtc_next_alarm_time(&alarm_tm, &now_tm, alrm); ++ ret = rtc_tm_to_time(&alarm_tm, &time); ++ if (ret != 0) ++ break; ++ ++ RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL); ++ RTAR = time; ++ } while (now != RCNR); ++ ++ return ret; ++} ++ ++static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ unsigned int rtsr; ++ unsigned long events = 0; ++ ++ spin_lock(&rtc_lock); ++ ++ rtsr = RTSR; ++ /* clear interrupt sources */ ++ RTSR = 0; ++ RTSR = (RTSR_AL|RTSR_HZ) & (rtsr >> 2); ++ ++ /* 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) ++ events |= (RTC_AF|RTC_IRQF); ++ if (rtsr & RTSR_HZ) ++ events |= (RTC_UF|RTC_IRQF); ++ ++ rtc_update(1, events); ++ ++ if (rtsr & RTSR_AL && rtc_periodic_alarm(&rtc_alarm)) ++ rtc_update_alarm(&rtc_alarm); ++ ++ spin_unlock(&rtc_lock); ++ ++ return IRQ_HANDLED; ++} ++ ++#if 0 ++static unsigned long rtc_irq_data; ++ ++static irqreturn_t 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_update(1, RTC_PF | RTC_IRQF); ++ } ++ ++ wake_up_interruptible(&rtc_wait); ++ kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); ++ ++ return IRQ_HANDLED; ++} ++#endif ++ ++static int sa1100_rtc_open(void) ++{ ++ int ret; ++ ++ 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 fail_ui; ++ } ++ 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 fail_ai; ++ } ++#if 0 ++ 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 fail_pi; ++ } ++ rtc_irq_data = 0; ++#endif ++ return 0; ++ ++ fail_pi: ++ free_irq(IRQ_RTCAlrm, NULL); ++ fail_ai: ++ free_irq(IRQ_RTC1Hz, NULL); ++ fail_ui: ++ return ret; ++} ++ ++static void sa1100_rtc_release(void) ++{ ++ spin_lock_irq (&rtc_lock); ++ RTSR = 0; ++ OIER &= ~OIER_E1; ++ OSSR = OSSR_M1; ++ spin_unlock_irq (&rtc_lock); ++ ++// free_irq(IRQ_OST1, NULL); ++ free_irq(IRQ_RTCAlrm, NULL); ++ free_irq(IRQ_RTC1Hz, NULL); ++} ++ ++#if 0 ++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; ++} ++#endif ++ ++static int sa1100_rtc_ioctl(unsigned int cmd, unsigned long arg) ++{ ++ 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; ++#if 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_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; ++#endif ++ } ++ return -EINVAL; ++} ++ ++static void sa1100_rtc_read_time(struct rtc_time *tm) ++{ ++ rtc_time_to_tm(RCNR, tm); ++} ++ ++static int sa1100_rtc_set_time(struct rtc_time *tm) ++{ ++ unsigned long time; ++ int ret; ++ ++ ret = rtc_tm_to_time(tm, &time); ++ if (ret == 0) ++ RCNR = time; ++ return ret; ++} ++ ++static void sa1100_rtc_read_alarm(struct rtc_wkalrm *alrm) ++{ ++ memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time)); ++ alrm->pending = RTSR & RTSR_AL ? 1 : 0; ++} ++ ++static int sa1100_rtc_set_alarm(struct rtc_wkalrm *alrm) ++{ ++ int ret; ++ ++ spin_lock_irq(&rtc_lock); ++ ret = rtc_update_alarm(&alrm->time); ++ if (ret == 0) { ++ memcpy(&rtc_alarm, &alrm->time, sizeof(struct rtc_time)); ++ ++ if (alrm->enabled) ++ enable_irq_wake(IRQ_RTCAlrm); ++ else ++ disable_irq_wake(IRQ_RTCAlrm); ++ } ++ spin_unlock_irq(&rtc_lock); ++ ++ return ret; ++} ++ ++static int sa1100_rtc_proc(char *buf) ++{ ++ char *p = buf; ++ ++ 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); ++ ++ return p - buf; ++} ++ ++static struct rtc_ops sa1100_rtc_ops = { ++ .owner = THIS_MODULE, ++ .open = sa1100_rtc_open, ++ .release = sa1100_rtc_release, ++ .ioctl = sa1100_rtc_ioctl, ++ ++ .read_time = sa1100_rtc_read_time, ++ .set_time = sa1100_rtc_set_time, ++ .read_alarm = sa1100_rtc_read_alarm, ++ .set_alarm = sa1100_rtc_set_alarm, ++ .proc = sa1100_rtc_proc, ++}; ++ ++static int __init rtc_init(void) ++{ ++ /* ++ * 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; ++ } ++ ++ register_rtc(&sa1100_rtc_ops); ++ ++ return 0; ++} ++ ++static void __exit rtc_exit(void) ++{ ++ unregister_rtc(&sa1100_rtc_ops); ++} ++ ++module_init(rtc_init); ++module_exit(rtc_exit); ++ ++MODULE_AUTHOR("Nils Faerber <nils@@kernelconcepts.de>"); ++MODULE_DESCRIPTION("SA11x0/PXA2xx Realtime Clock Driver (RTC)"); ++MODULE_LICENSE("GPL"); /* so says the header */ +--- linux-2.6.5/drivers/char/Kconfig~heh 2004-04-03 22:36:15.000000000 -0500 ++++ linux-2.6.5/drivers/char/Kconfig 2004-04-30 20:57:36.000000000 -0400 +@@ -814,6 +814,10 @@ + + If unsure, say N. + ++config SA1100_RTC ++ tristate "SA1100 or PXA Real Time Clock" ++ depends on ARCH_SA1100 || ARCH_PXA ++ + config DTLK + tristate "Double Talk PC internal speech card support" + help +--- linux-2.6.5/drivers/char/tty_io.c~heh 2004-04-03 22:37:23.000000000 -0500 ++++ linux-2.6.5/drivers/char/tty_io.c 2004-04-30 20:57:36.000000000 -0400 +@@ -1535,10 +1535,17 @@ + return 0; + } + ++/* ++ * In the case of pty's, "tty" is the master side ++ * and "real_tty" is the slave side. ++ */ + static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, + struct winsize * arg) + { + struct winsize tmp_ws; ++ struct task_struct *p; ++ struct list_head *l; ++ struct pid *pid; + + if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) + return -EFAULT; +@@ -1558,8 +1565,21 @@ + #endif + if (tty->pgrp > 0) + kill_pg(tty->pgrp, SIGWINCH, 1); +- if ((real_tty->pgrp != tty->pgrp) && (real_tty->pgrp > 0)) +- kill_pg(real_tty->pgrp, SIGWINCH, 1); ++ ++ /* ++ * Send SIGWINCH to the whole session on the slave tty. ++ * However, in the case of non-master pty's, be careful ++ * not to send two SIGWINCH to the same procress group. ++ */ ++ if (real_tty->session > 0) { ++ read_lock(&tasklist_lock); ++ for_each_task_pid(real_tty->session, PIDTYPE_SID, p, l, pid) { ++ if (process_group(p) != tty->pgrp) ++ group_send_sig_info(SIGWINCH, (void *)1L, p); ++ } ++ read_unlock(&tasklist_lock); ++ } ++ + tty->winsize = tmp_ws; + real_tty->winsize = tmp_ws; + return 0; +--- linux-2.6.5/drivers/Makefile~heh 2004-04-03 22:37:43.000000000 -0500 ++++ linux-2.6.5/drivers/Makefile 2004-04-30 20:57:36.000000000 -0400 +@@ -11,6 +11,8 @@ + # PnP must come after ACPI since it will eventually need to check if acpi + # was used and do nothing if so + obj-$(CONFIG_PNP) += pnp/ ++obj-$(CONFIG_I2C) += i2c/ ++obj-$(CONFIG_L3) += l3/ + + # char/ comes before serial/ etc so that the VT console is the boot-time + # default. +@@ -41,7 +43,6 @@ + obj-$(CONFIG_GAMEPORT) += input/gameport/ + obj-$(CONFIG_SERIO) += input/serio/ + obj-$(CONFIG_I2O) += message/ +-obj-$(CONFIG_I2C) += i2c/ + obj-$(CONFIG_PHONE) += telephony/ + obj-$(CONFIG_MD) += md/ + obj-$(CONFIG_BT) += bluetooth/ +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/l3/Kconfig 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,24 @@ ++# ++# L3 bus configuration ++# ++ ++menu "L3 serial bus support" ++ ++config L3 ++ tristate "L3 support" ++ ++config L3_ALGOBIT ++ bool "L3 bit-banging interfaces" ++ depends on L3=y ++ ++config L3_BIT_SA1100_GPIO ++ bool "SA11x0 GPIO adapter" ++ depends on L3_ALGOBIT && ARCH_SA1100 ++ ++# i2c must come before this ++config BIT_SA1100_GPIO ++ bool ++ depends on L3_BIT_SA1100_GPIO || I2C_BIT_SA1100_GPIO=y ++ default y ++ ++endmenu +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/l3/l3-core.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,203 @@ ++/* ++ * 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 <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/slab.h> ++#include <linux/proc_fs.h> ++#include <linux/kmod.h> ++#include <linux/init.h> ++#include <linux/l3/l3.h> ++ ++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) ++{ ++ 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_module_get(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) ++ module_put(adap->owner); ++} ++ ++/** ++ * 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 ++ * @adap: L3 bus adapter ++ * @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_adapter *adap, int addr, const char *buf, int len) ++{ ++ 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 ++ * @adap: L3 bus adapter ++ * @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_adapter *adap, int addr, char *buf, int len) ++{ ++ 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_transfer); ++EXPORT_SYMBOL(l3_write); ++EXPORT_SYMBOL(l3_read); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/l3/l3-algo-bit.c 2004-04-30 20:57:36.000000000 -0400 +@@ -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 <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/errno.h> ++#include <linux/sched.h> ++#include <linux/l3/l3.h> ++#include <linux/l3/algo-bit.h> ++ ++#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); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/l3/Makefile 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,11 @@ ++# ++# Makefile for the L3 bus driver. ++# ++ ++# 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 ++ ++obj-$(CONFIG_L3) += l3-core.o $(l3-y) $(l3-drv-y) +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/l3/l3-bit-sa1100.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,271 @@ ++/* ++ * 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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/ioport.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/i2c.h> ++#include <linux/i2c-algo-bit.h> ++#include <linux/l3/algo-bit.h> ++ ++#include <asm/system.h> ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++#include <asm/arch/assabet.h> ++ ++#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 = { ++ .algo_data = &i2c_bit_data, ++}; ++ ++#define LOCK &i2c_adapter.bus_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 (machine_is_h3600() || machine_is_h3100()) { ++ bit->sda = GPIO_GPIO14; ++ bit->scl = GPIO_GPIO16; ++ bit->l3_mode = GPIO_GPIO15; ++ } ++ ++ if (machine_is_stork()) { ++ bit->sda = GPIO_GPIO15; ++ bit->scl = GPIO_GPIO18; ++ bit->l3_mode = GPIO_GPIO17; ++ } ++ ++ 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); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/misc/switches.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,22 @@ ++/* ++ * linux/drivers/misc/switches.h ++ * ++ * Copyright (C) 2001 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. ++ * ++ * 19 December 2001 - created. ++ */ ++ ++#if !defined(_SWITCHES_H) ++# define _SWITCHES_H ++ ++#include <linux/switches.h> ++ ++#define SWITCHES_NAME "switches" ++ ++extern int switches_event(switches_mask_t *mask); ++ ++#endif /* !defined(_SWITCHES_H) */ +--- linux-2.6.5/drivers/misc/Kconfig~heh 2004-04-03 22:36:26.000000000 -0500 ++++ linux-2.6.5/drivers/misc/Kconfig 2004-04-30 20:57:36.000000000 -0400 +@@ -21,5 +21,62 @@ + + If unsure, say N. + ++menu "Multimedia Capabilities Port drivers" ++ ++config MCP ++ tristate "Multimedia drivers" ++ ++# Interface drivers ++config MCP_SA1100 ++ tristate "Support SA1100 MCP interface" ++ depends on MCP && ARCH_SA1100 ++ ++# Chip drivers ++config MCP_UCB1200 ++ tristate "Support for UCB1200 / UCB1300" ++ depends on MCP ++ ++config MCP_UCB1200_AUDIO ++ tristate "Audio / Telephony interface support" ++ depends on MCP_UCB1200 && SOUND ++ ++config MCP_UCB1200_TS ++ tristate "Touchscreen interface support" ++ depends on MCP_UCB1200 && INPUT ++ ++endmenu ++ ++ ++menu "Console Switches" ++ ++config SWITCHES ++ tristate "Console Switch Support" ++ help ++ Say Y here to include support for simple console momentary switches. ++ This driver implements a miscellaneous character device (named ++ `switches' in /proc/misc) which can be read by userland programs ++ to respond to switch press events. This mechanism is efficient for ++ systems which may not implement a traditional heavyweight console ++ server. ++ ++ It is also possible to say M to build this driver as a module (named ++ `switches.o'). ++ ++config SWITCHES_SA1100 ++ tristate "SA-1100 switches" ++ depends on SWITCHES && ARCH_SA1100 ++ help ++ Say Y here to include support for switches routed directly to ++ interruptable signals on StrongARM SA-1100 systems. ++ ++config SWITCHES_UCB1X00 ++ tristate "UCB1x00 switches" ++ depends on SWITCHES && MCP_UCB1200 ++ help ++ Say Y here to include support for switches routed through a ++ UCB1x00 modem/audio analog front-end device. ++ ++endmenu ++ + endmenu + +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/misc/ucb1x00-assabet.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,73 @@ ++/* ++ * linux/drivers/misc/ucb1x00-assabet.c ++ * ++ * Copyright (C) 2001-2003 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. ++ * ++ * We handle the machine-specific bits of the UCB1x00 driver here. ++ */ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/fs.h> ++#include <linux/proc_fs.h> ++#include <linux/device.h> ++ ++#include <asm/dma.h> ++ ++#include "ucb1x00.h" ++ ++#define UCB1X00_ATTR(name,input)\ ++static ssize_t name##_show(struct class_device *dev, char *buf) \ ++{ \ ++ struct ucb1x00 *ucb = classdev_to_ucb1x00(dev); \ ++ int val; \ ++ ucb1x00_adc_enable(ucb); \ ++ val = ucb1x00_adc_read(ucb, input, UCB_NOSYNC); \ ++ ucb1x00_adc_disable(ucb); \ ++ return sprintf(buf, "%d\n", val); \ ++} \ ++static CLASS_DEVICE_ATTR(name,0444,name##_show,NULL) ++ ++UCB1X00_ATTR(vbatt, UCB_ADC_INP_AD1); ++UCB1X00_ATTR(vcharger, UCB_ADC_INP_AD0); ++UCB1X00_ATTR(batt_temp, UCB_ADC_INP_AD2); ++ ++static int ucb1x00_assabet_add(struct class_device *dev) ++{ ++ class_device_create_file(dev, &class_device_attr_vbatt); ++ class_device_create_file(dev, &class_device_attr_vcharger); ++ class_device_create_file(dev, &class_device_attr_batt_temp); ++ return 0; ++} ++ ++static void ucb1x00_assabet_remove(struct class_device *dev) ++{ ++ class_device_remove_file(dev, &class_device_attr_batt_temp); ++ class_device_remove_file(dev, &class_device_attr_vcharger); ++ class_device_remove_file(dev, &class_device_attr_vbatt); ++} ++ ++static struct class_interface ucb1x00_assabet_interface = { ++ .add = ucb1x00_assabet_add, ++ .remove = ucb1x00_assabet_remove, ++}; ++ ++static int __init ucb1x00_assabet_init(void) ++{ ++ return ucb1x00_register_interface(&ucb1x00_assabet_interface); ++} ++ ++static void __exit ucb1x00_assabet_exit(void) ++{ ++ ucb1x00_unregister_interface(&ucb1x00_assabet_interface); ++} ++ ++module_init(ucb1x00_assabet_init); ++module_exit(ucb1x00_assabet_exit); ++ ++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); ++MODULE_DESCRIPTION("Assabet noddy testing only example ADC driver"); ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/misc/mcp-pxa.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,57 @@ ++/* ++ * linux/drivers/misc/mcp-pxa.c ++ * ++ * 2002-01-10 Jeff Sutherland <jeffs@accelent.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. ++ * ++ * NOTE: This is a quick hack to gain access to the aclink codec's ++ * touch screen facility. Its audio is handled by a separate ++ * (non-mcp) driver at the present time. ++ */ ++ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/ac97_codec.h> ++ ++#include "mcp.h" ++ ++ ++extern int pxa_ac97_get(struct ac97_codec **codec); ++extern void pxa_ac97_put(void); ++ ++ ++struct mcp *mcp_get(void) ++{ ++ struct ac97_codec *codec; ++ if (pxa_ac97_get(&codec) < 0) ++ return NULL; ++ return (struct mcp *)codec; ++} ++ ++void mcp_reg_write(struct mcp *mcp, unsigned int reg, unsigned int val) ++{ ++ struct ac97_codec *codec = (struct ac97_codec *)mcp; ++ codec->codec_write(codec, reg, val); ++} ++ ++unsigned int mcp_reg_read(struct mcp *mcp, unsigned int reg) ++{ ++ struct ac97_codec *codec = (struct ac97_codec *)mcp; ++ return codec->codec_read(codec, reg); ++} ++ ++void mcp_enable(struct mcp *mcp) ++{ ++ /* ++ * Should we do something here to make sure the aclink ++ * codec is alive??? ++ * A: not for now --NP ++ */ ++} ++ ++void mcp_disable(struct mcp *mcp) ++{ ++} +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/misc/mcp-core.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,235 @@ ++/* ++ * 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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/errno.h> ++#include <linux/smp.h> ++#include <linux/device.h> ++ ++#include <asm/dma.h> ++#include <asm/system.h> ++ ++#include "mcp.h" ++ ++#define to_mcp(d) container_of(d, struct mcp, attached_device) ++#define to_mcp_driver(d) container_of(d, struct mcp_driver, drv) ++ ++static int mcp_bus_match(struct device *dev, struct device_driver *drv) ++{ ++ return 1; ++} ++ ++static int mcp_bus_probe(struct device *dev) ++{ ++ struct mcp *mcp = to_mcp(dev); ++ struct mcp_driver *drv = to_mcp_driver(dev->driver); ++ ++ return drv->probe(mcp); ++} ++ ++static int mcp_bus_remove(struct device *dev) ++{ ++ struct mcp *mcp = to_mcp(dev); ++ struct mcp_driver *drv = to_mcp_driver(dev->driver); ++ ++ drv->remove(mcp); ++ return 0; ++} ++ ++static int mcp_bus_suspend(struct device *dev, u32 state) ++{ ++ struct mcp *mcp = to_mcp(dev); ++ int ret = 0; ++ ++ if (dev->driver) { ++ struct mcp_driver *drv = to_mcp_driver(dev->driver); ++ ++ ret = drv->suspend(mcp, state); ++ } ++ return ret; ++} ++ ++static int mcp_bus_resume(struct device *dev) ++{ ++ struct mcp *mcp = to_mcp(dev); ++ int ret = 0; ++ ++ if (dev->driver) { ++ struct mcp_driver *drv = to_mcp_driver(dev->driver); ++ ++ ret = drv->resume(mcp); ++ } ++ return ret; ++} ++ ++static struct bus_type mcp_bus_type = { ++ .name = "mcp", ++ .match = mcp_bus_match, ++ .suspend = mcp_bus_suspend, ++ .resume = mcp_bus_resume, ++}; ++ ++/** ++ * 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); ++} ++ ++int mcp_host_register(struct mcp *mcp, struct device *parent) ++{ ++ mcp->attached_device.parent = parent; ++ mcp->attached_device.bus = &mcp_bus_type; ++ mcp->attached_device.dma_mask = parent->dma_mask; ++ strcpy(mcp->attached_device.bus_id, "mcp0"); ++ return device_register(&mcp->attached_device); ++} ++ ++void mcp_host_unregister(struct mcp *mcp) ++{ ++ device_unregister_wait(&mcp->attached_device); ++} ++ ++int mcp_driver_register(struct mcp_driver *mcpdrv) ++{ ++ mcpdrv->drv.bus = &mcp_bus_type; ++ mcpdrv->drv.probe = mcp_bus_probe; ++ mcpdrv->drv.remove = mcp_bus_remove; ++ return driver_register(&mcpdrv->drv); ++} ++ ++void mcp_driver_unregister(struct mcp_driver *mcpdrv) ++{ ++ driver_unregister(&mcpdrv->drv); ++} ++ ++static int __init mcp_init(void) ++{ ++ return bus_register(&mcp_bus_type); ++} ++ ++static void __exit mcp_exit(void) ++{ ++ bus_unregister(&mcp_bus_type); ++} ++ ++module_init(mcp_init); ++module_exit(mcp_exit); ++ ++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_host_register); ++EXPORT_SYMBOL(mcp_host_unregister); ++EXPORT_SYMBOL(mcp_driver_register); ++EXPORT_SYMBOL(mcp_driver_unregister); ++ ++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); ++MODULE_DESCRIPTION("Core multimedia communications port driver"); ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/misc/ucb1x00-ts.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,465 @@ ++/* ++ * 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 <jco@ict.es> : ++ * ++ * 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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/smp.h> ++#include <linux/smp_lock.h> ++#include <linux/sched.h> ++#include <linux/completion.h> ++#include <linux/delay.h> ++#include <linux/string.h> ++#include <linux/input.h> ++#include <linux/device.h> ++#include <linux/slab.h> ++ ++#include <asm/dma.h> ++#include <asm/semaphore.h> ++ ++#include "ucb1x00.h" ++ ++ ++struct ucb1x00_ts { ++ struct input_dev idev; ++ struct ucb1x00 *ucb; ++ ++ struct semaphore irq_wait; ++ struct semaphore sem; ++ struct completion init_exit; ++ struct task_struct *rtask; ++ int use_count; ++ u16 x_res; ++ u16 y_res; ++ ++ int restart:1; ++ int adcsync:1; ++}; ++ ++static int adcsync = UCB_NOSYNC; ++ ++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); ++ input_sync(&ts->idev); ++} ++ ++static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts) ++{ ++ input_report_abs(&ts->idev, ABS_PRESSURE, 0); ++ input_sync(&ts->idev); ++} ++ ++/* ++ * Switch to interrupt mode. ++ */ ++static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts) ++{ ++ if (ts->ucb->id == UCB_ID_1400_BUGGY) ++ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, ++ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | ++ UCB_TS_CR_MODE_INT); ++ else ++ 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, and in the UCB1400 case where ++ * any register access may sleep). ++ */ ++static int ucb1x00_thread(void *_ts) ++{ ++ struct ucb1x00_ts *ts = _ts; ++ struct task_struct *tsk = current; ++ int valid; ++ ++ ts->rtask = tsk; ++ ++ daemonize("ktsd"); ++ /* only want to receive SIGKILL */ ++ allow_signal(SIGKILL); ++ ++ /* ++ * 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; ++ ++ complete(&ts->init_exit); ++ ++ valid = 0; ++ ++ for (;;) { ++ unsigned int x, y, p, val; ++ ++ 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)) { ++ 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; ++ } ++ ++ /* ++ * Since ucb1x00_enable_irq() might sleep due ++ * to the way the UCB1400 regs are accessed, we ++ * can't use set_task_state() before that call, ++ * and not changing state before enabling the ++ * interrupt is racy. A semaphore solves all ++ * those issues quite nicely. ++ */ ++ down_interruptible(&ts->irq_wait); ++ } 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); ++ } ++ ++ schedule_timeout(HZ / 100); ++ if (signal_pending(tsk)) ++ break; ++ } ++ ++ ts->rtask = NULL; ++ 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); ++ up(&ts->irq_wait); ++} ++ ++static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts) ++{ ++ input_report_abs(&ts->idev, ABS_PRESSURE, 0); ++} ++ ++static int ucb1x00_ts_open(struct input_dev *idev) ++{ ++ struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev; ++ int ret = 0; ++ ++ if (down_interruptible(&ts->sem)) ++ return -EINTR; ++ ++ if (ts->use_count++ != 0) ++ goto out; ++ ++ if (ts->rtask) ++ panic("ucb1x00: rtask running?"); ++ ++ sema_init(&ts->irq_wait, 0); ++ 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, CLONE_KERNEL); ++ 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_close(struct input_dev *idev) ++{ ++ struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev; ++ ++ down(&ts->sem); ++ 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); ++ } ++ up(&ts->sem); ++} ++ ++#if 0 ++static int ucb1x00_ts_resume(struct device *_dev, u32 level) ++{ ++ struct ucb1x00_device *dev = ucb1x00_dev(_dev); ++ struct ucb1x00_ts *ts = ucb1x00_get_drvdata(dev); ++ ++ if (level == RESUME_ENABLE && ts->rtask != NULL) { ++ /* ++ * Restart the TS thread to ensure the ++ * TS interrupt mode is set up again ++ * after sleep. ++ */ ++ ts->restart = 1; ++ up(&ts->irq_wait); ++ } ++ return 0; ++} ++#endif ++ ++ ++/* ++ * Initialisation. ++ */ ++static int ucb1x00_ts_add(struct class_device *dev) ++{ ++ struct ucb1x00 *ucb = classdev_to_ucb1x00(dev); ++ struct ucb1x00_ts *ts; ++ ++ ts = kmalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL); ++ if (!ts) ++ return -ENOMEM; ++ ++ memset(ts, 0, sizeof(struct ucb1x00_ts)); ++ ++ ts->ucb = ucb; ++ ts->adcsync = adcsync; ++ init_MUTEX(&ts->sem); ++ ++ ts->idev.name = "Touchscreen panel"; ++ ts->idev.id.product = 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); ++ ++ ucb->ts_data = ts; ++ ++ return 0; ++} ++ ++static void ucb1x00_ts_remove(struct class_device *dev) ++{ ++ struct ucb1x00 *ucb = classdev_to_ucb1x00(dev); ++ struct ucb1x00_ts *ts = ucb->ts_data; ++ ++ input_unregister_device(&ts->idev); ++ kfree(ts); ++} ++ ++static struct class_interface ucb1x00_ts_interface = { ++ .add = ucb1x00_ts_add, ++ .remove = ucb1x00_ts_remove, ++}; ++ ++static int __init ucb1x00_ts_init(void) ++{ ++ return ucb1x00_register_interface(&ucb1x00_ts_interface); ++} ++ ++static void __exit ucb1x00_ts_exit(void) ++{ ++ ucb1x00_unregister_interface(&ucb1x00_ts_interface); ++} ++ ++#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 <rmk@arm.linux.org.uk>"); ++MODULE_DESCRIPTION("UCB1x00 touchscreen driver"); ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/misc/ucb1x00-core.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,624 @@ ++/* ++ * 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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/errno.h> ++#include <linux/interrupt.h> ++#include <linux/device.h> ++ ++#include <asm/dma.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#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. ++ * ++ * See ucb1x00.h for definition of the UCB_ADC_DAT macro. It ++ * addresses a bug in the ucb1200/1300 which, of course, Philips ++ * decided to finally fix in the ucb1400 ;-) -jws ++ */ ++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); ++} ++ ++/* ++ * 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. ++ * ++ * A restriction with interrupts exists when using the ucb1400, as ++ * the codec read/write routines may sleep while waiting for codec ++ * access completion and uses semaphores for access control to the ++ * AC97 bus. A complete codec read cycle could take anywhere from ++ * 60 to 100uSec so we *definitely* don't want to spin inside the ++ * interrupt handler waiting for codec access. So, we handle the ++ * interrupt by scheduling a RT kernel thread to run in process ++ * context instead of interrupt context. ++ */ ++ ++static int ucb1x00_thread(void *_ucb) ++{ ++ struct task_struct *tsk = current; ++ DECLARE_WAITQUEUE(wait, tsk); ++ struct ucb1x00 *ucb = _ucb; ++ struct ucb1x00_irq *irq; ++ unsigned int isr, i; ++ ++ ucb->rtask = tsk; ++ ++ daemonize(); ++ reparent_to_init(); ++ tsk->tty = NULL; ++ tsk->policy = SCHED_FIFO; ++ tsk->rt_priority = 1; ++ strcpy(tsk->comm, "kUCB1x00d"); ++ ++ /* only want to receive SIGKILL */ ++ spin_lock_irq(&tsk->sigmask_lock); ++ siginitsetinv(&tsk->blocked, sigmask(SIGKILL)); ++ recalc_sigpending(); ++ spin_unlock_irq(&tsk->sigmask_lock); ++ ++ add_wait_queue(&ucb->irq_wait, &wait); ++ set_task_state(tsk, TASK_INTERRUPTIBLE); ++ complete(&ucb->complete); ++ ++ for (;;) { ++ if (signal_pending(tsk)) ++ break; ++ enable_irq(ucb->irq); ++ schedule(); ++ ++ 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); ++ ++ set_task_state(tsk, TASK_INTERRUPTIBLE); ++ } ++ ++ remove_wait_queue(&ucb->irq_wait, &wait); ++ ucb->rtask = NULL; ++ complete_and_exit(&ucb->complete, 0); ++} ++ ++static irqreturn_t ucb1x00_irq(int irqnr, void *devid, struct pt_regs *regs) ++{ ++ struct ucb1x00 *ucb = devid; ++ disable_irq(irqnr); ++ wake_up(&ucb->irq_wait); ++ return IRQ_HANDLED; ++} ++ ++/** ++ * 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); ++ ++ /* This prevents spurious interrupts on the UCB1400 */ ++ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 1 << idx); ++ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); ++ ++ 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 "Freeing bad UCB1x00 irq %d\n", 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 ADS_EXT_IRQ(8) ++ * graphicsmaster ADS_EXT_IRQ(8) ++ * 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 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); ++} ++ ++static int ucb1x00_probe(struct mcp *mcp) ++{ ++ struct ucb1x00 *ucb; ++ unsigned int id; ++ int ret = -ENODEV; ++ ++ 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 err_disable; ++ } ++ ++ ucb = kmalloc(sizeof(struct ucb1x00), GFP_KERNEL); ++ ret = -ENOMEM; ++ if (!ucb) ++ goto err_disable; ++ ++ memset(ucb, 0, sizeof(struct ucb1x00)); ++ ++ ucb->cdev.class = &ucb1x00_class; ++ ucb->cdev.dev = &mcp->attached_device; ++ strlcpy(ucb->cdev.class_id, "ucb1x00", sizeof(ucb->cdev.class_id)); ++ ++ spin_lock_init(&ucb->lock); ++ spin_lock_init(&ucb->io_lock); ++ sema_init(&ucb->adc_sem, 1); ++ ++ ucb->id = id; ++ ucb->mcp = mcp; ++ ucb->irq = ucb1x00_detect_irq(ucb); ++ if (ucb->irq == NO_IRQ) { ++ printk(KERN_ERR "UCB1x00: IRQ probe failed\n"); ++ ret = -ENODEV; ++ goto err_free; ++ } ++ ++ ret = request_irq(ucb->irq, ucb1x00_irq, 0, "UCB1x00", ucb); ++ if (ret) { ++ printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n", ++ ucb->irq, ret); ++ goto err_free; ++ } ++ ++ set_irq_type(ucb->irq, IRQT_RISING); ++ mcp_set_drvdata(mcp, ucb); ++ ++ ret = class_device_register(&ucb->cdev); ++ if (ret) { ++ free_irq(ucb->irq, ucb); ++ err_free: ++ kfree(ucb); ++ } ++ err_disable: ++ mcp_disable(mcp); ++ return ret; ++} ++ ++static void ucb1x00_remove(struct mcp *mcp) ++{ ++ struct ucb1x00 *ucb = mcp_get_drvdata(mcp); ++ ++ class_device_unregister(&ucb->cdev); ++ free_irq(ucb->irq, ucb); ++} ++ ++static void ucb1x00_release(struct class_device *dev) ++{ ++ struct ucb1x00 *ucb = classdev_to_ucb1x00(dev); ++ kfree(ucb); ++} ++ ++static struct class ucb1x00_class = { ++ .name = "ucb1x00", ++ .release = ucb1x00_release, ++}; ++ ++int ucb1x00_register_interface(struct class_interface *intf) ++{ ++ intf->class = &ucb1x00_class; ++ return class_interface_register(intf); ++} ++ ++void ucb1x00_unregister_interface(struct class_interface *intf) ++{ ++ class_interface_unregister(intf); ++} ++ ++static struct mcp_driver ucb1x00_driver = { ++ .drv = { ++ .name = "ucb1x00", ++ }, ++ .probe = ucb1x00_probe, ++ .remove = ucb1x00_remove, ++}; ++ ++static int __init ucb1x00_init(void) ++{ ++ int ret = class_register(&ucb1x00_class); ++ if (ret == 0) { ++ ret = mcp_driver_register(&ucb1x00_driver); ++ if (ret) ++ class_unregister(&ucb1x00_class); ++ } ++ return ret; ++} ++ ++static void __exit ucb1x00_exit(void) ++{ ++ mcp_driver_unregister(&ucb1x00_driver); ++ class_unregister(&ucb1x00_class); ++} ++ ++module_init(ucb1x00_init); ++module_exit(ucb1x00_exit); ++ ++EXPORT_SYMBOL(ucb1x00_class); ++ ++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); ++ ++EXPORT_SYMBOL(ucb1x00_register_interface); ++EXPORT_SYMBOL(ucb1x00_unregister_interface); ++ ++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); ++MODULE_DESCRIPTION("UCB1x00 core driver"); ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/misc/switches-ucb1x00.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,214 @@ ++/* ++ * linux/drivers/misc/switches-ucb1x00.c ++ * ++ * Copyright (C) 2001 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. ++ * ++ * 19 December 2001 - created from sa1100_switches.c. ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/device.h> ++ ++#include <asm/dma.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/mach-types.h> ++ ++#ifdef CONFIG_SA1100_ASSABET ++#include <asm/arch/assabet.h> ++#endif ++ ++#include "switches.h" ++#include "ucb1x00.h" ++ ++ ++static void switches_ucb1x00_handler(int irq, void *devid); ++ ++ ++#ifdef CONFIG_SA1100_ASSABET ++ ++/* Assabet ++ * ^^^^^^^ ++ * Six switches are routed to GPIO pins on the UCB1300: S3 -- S8. ++ * This code sets bits in the range [3, 8] in the mask that we ++ * return to userland. Note that we transpose signals SW7 and SW8; ++ * see assabet_switches_ucb1x00_handler(). ++ */ ++ ++static int assabet_switches_ucb1x00_init(struct ucb1x00 *ucb) ++{ ++ int i; ++ ++ ucb1x00_enable(ucb); ++ ++ ucb1x00_io_set_dir(ucb, ++ UCB_IO_0 | UCB_IO_1 | UCB_IO_2 | ++ UCB_IO_3 | UCB_IO_4 | UCB_IO_5, 0); ++ ++ for (i = 0; i < 6; ++i) { ++ ucb1x00_enable_irq(ucb, i, UCB_RISING | UCB_FALLING); ++ ++ if (ucb1x00_hook_irq(ucb, i, ++ switches_ucb1x00_handler, ucb) < 0) { ++ printk(KERN_ERR "%s: unable to hook IRQ for " ++ "UCB1300 IO_%d\n", SWITCHES_NAME, i); ++ ++ /* FIXME: BUGGY ERROR HANDLING */ ++ return -EBUSY; ++ } ++ ++ } ++ ++ ucb1x00_disable(ucb); ++ ++ return 0; ++ ++} ++ ++static void assabet_switches_ucb1x00_shutdown(struct ucb1x00 *ucb) ++{ ++ int i; ++ ++ ucb1x00_enable(ucb); ++ ++ for (i = 5; i >= 0; --i) { ++ ucb1x00_disable_irq(ucb, i, UCB_RISING | UCB_FALLING); ++ ++ /* Only error conditions are ENOENT and EINVAL; silently ++ * ignore: ++ */ ++ ucb1x00_free_irq(ucb, i, ucb); ++ } ++ ++ ucb1x00_disable(ucb); ++} ++ ++static void assabet_switches_ucb1x00_handler(struct ucb1x00 *ucb, int irq, switches_mask_t *mask) ++{ ++ unsigned int last, this; ++ static unsigned int states = 0; ++ ++ last = ((states & (1 << irq)) != 0); ++ this = ((ucb1x00_io_read(ucb) & (1 << irq)) != 0); ++ ++ if (last == this) /* debounce */ ++ return; ++ ++ /* Intel StrongARM SA-1110 Development Board ++ * Schematics Figure 5, Sheet 5 of 12 ++ * ++ * See switches S8 and S7. Notice their ++ * relationship to signals SW7 and SW8. Hmmm. ++ */ ++ ++ switch (irq) { ++ ++ case 4: ++ ++ SWITCHES_SET(mask, 8, this); ++ break; ++ ++ case 5: ++ ++ SWITCHES_SET(mask, 7, this); ++ break; ++ ++ default: ++ ++ SWITCHES_SET(mask, irq + 3, this); ++ ++ } ++ ++ states = this ? (states | (1 << irq)) : (states & ~(1 << irq)); ++ ++} ++#endif /* CONFIG_SA1100_ASSABET */ ++ ++ ++/* switches_ucb1x00_handler() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * This routine is a generalized handler for UCB1x00 GPIO switches ++ * which calls a board-specific service routine and passes an event ++ * mask to the core event handler. This routine is appropriate for ++ * systems which use the ucb1x00 framework, and can be registered ++ * using ucb1x00_hook_irq(). ++ */ ++static void switches_ucb1x00_handler(int irq, void *devid) ++{ ++ struct ucb1x00 *ucb = devid; ++ switches_mask_t mask; ++ ++ SWITCHES_ZERO(&mask); ++ ++ /* Porting note: call a board-specific UCB1x00 switch handler here. ++ * The handler can assume that sufficient storage for `mask' has ++ * been allocated, and that the corresponding switches_mask_t ++ * structure has been zeroed. ++ */ ++ ++#ifdef CONFIG_SA1100_ASSABET ++ if (machine_is_assabet()) { ++ assabet_switches_ucb1x00_handler(ucb, irq, &mask); ++ } ++#endif ++ ++ switches_event(&mask); ++} ++ ++static int switches_add(struct class_device *dev) ++{ ++ struct ucb1x00 *ucb = classdev_to_ucb1x00(dev); ++ int ret = -ENODEV; ++ ++#ifdef CONFIG_SA1100_ASSABET ++ if (machine_is_assabet()) { ++ ret = assabet_switches_ucb1x00_init(ucb); ++ } ++#endif ++ /* Porting note: call a board-specific init routine here. */ ++ ++ return ret; ++} ++ ++static void switches_remove(struct class_device *dev) ++{ ++ struct ucb1x00 *ucb = classdev_to_ucb1x00(dev); ++ ++ /* Porting note: call a board-specific shutdown routine here. */ ++ ++#ifdef CONFIG_SA1100_ASSABET ++ if (machine_is_assabet()) { ++ assabet_switches_ucb1x00_shutdown(ucb); ++ } ++#endif ++} ++ ++static struct class_interface ucb1x00_switches_interface = { ++ .add = switches_add, ++ .remove = switches_remove, ++}; ++ ++static int __init switches_ucb1x00_init(void) ++{ ++ return ucb1x00_register_interface(&ucb1x00_switches_interface); ++} ++ ++static void __exit switches_ucb1x00_exit(void) ++{ ++ ucb1x00_unregister_interface(&ucb1x00_switches_interface); ++} ++ ++module_init(switches_ucb1x00_init); ++module_exit(switches_ucb1x00_exit); ++ ++MODULE_DESCRIPTION("ucb1x00 switches driver"); ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/misc/switches-core.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,200 @@ ++/* ++ * linux/drivers/misc/switches-core.c ++ * ++ * Copyright (C) 2000-2001 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. ++ * ++ * 5 October 2000 - created. ++ * ++ * 25 October 2000 - userland file interface added. ++ * ++ * 13 January 2001 - added support for Spot. ++ * ++ * 11 September 2001 - UCB1200 driver framework support added. ++ * ++ * 19 December 2001 - separated out SA-1100 and UCB1x00 code. ++ */ ++ ++#include <linux/config.h> ++#include <linux/init.h> ++#include <linux/fs.h> ++#include <linux/kernel.h> ++#include <linux/miscdevice.h> ++#include <linux/module.h> ++#include <linux/mm.h> ++#include <linux/poll.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/wait.h> ++ ++#include <asm/uaccess.h> ++ ++#include "switches.h" ++ ++ ++MODULE_AUTHOR("John Dorsey"); ++MODULE_DESCRIPTION("Console switch support"); ++MODULE_LICENSE("GPL"); ++ ++ ++struct switches_action { ++ struct list_head list; ++ switches_mask_t mask; ++}; ++ ++ ++static int switches_users = 0; ++ ++static spinlock_t switches_lock = SPIN_LOCK_UNLOCKED; ++ ++DECLARE_WAIT_QUEUE_HEAD(switches_wait); ++LIST_HEAD(switches_event_queue); ++ ++ ++static ssize_t switches_read(struct file *file, char *buffer, ++ size_t count, loff_t *pos) ++{ ++ unsigned long flags; ++ struct list_head *event; ++ struct switches_action *action; ++ ++ if (count < sizeof(struct switches_mask_t)) ++ return -EINVAL; ++ ++ while (list_empty(&switches_event_queue)) { ++ ++ if (file->f_flags & O_NDELAY) ++ return -EAGAIN; ++ ++ interruptible_sleep_on(&switches_wait); ++ ++ if (signal_pending(current)) ++ return -ERESTARTSYS; ++ ++ } ++ ++ if (verify_area(VERIFY_WRITE, buffer, sizeof(struct switches_mask_t))) ++ return -EFAULT; ++ ++ spin_lock_irqsave(&switches_lock, flags); ++ ++ event = switches_event_queue.next; ++ action = list_entry(event, struct switches_action, list); ++ copy_to_user(buffer, &(action->mask), sizeof(struct switches_mask_t)); ++ list_del(event); ++ kfree(action); ++ ++ spin_unlock_irqrestore(&switches_lock, flags); ++ ++ return 0; ++ ++} ++ ++static ssize_t switches_write(struct file *file, const char *buffer, ++ size_t count, loff_t *ppos) ++{ ++ return -EINVAL; ++} ++ ++static unsigned int switches_poll(struct file *file, poll_table *wait) ++{ ++ ++ poll_wait(file, &switches_wait, wait); ++ ++ if (!list_empty(&switches_event_queue)) ++ return POLLIN | POLLRDNORM; ++ ++ return 0; ++ ++} ++ ++static int switches_open(struct inode *inode, struct file *file) ++{ ++ ++ if (switches_users > 0) ++ return -EBUSY; ++ ++ ++switches_users; ++ return 0; ++ ++} ++ ++static int switches_release(struct inode *inode, struct file *file) ++{ ++ ++ --switches_users; ++ return 0; ++ ++} ++ ++static struct file_operations switches_ops = { ++ .owner = THIS_MODULE, ++ .read = switches_read, ++ .write = switches_write, ++ .poll = switches_poll, ++ .open = switches_open, ++ .release = switches_release, ++}; ++ ++static struct miscdevice switches_misc = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = SWITCHES_NAME, ++ .fops = &switches_ops, ++}; ++ ++int switches_event(switches_mask_t *mask) ++{ ++ struct switches_action *action; ++ ++ if ((switches_users > 0) && (SWITCHES_COUNT(mask) > 0)) { ++ ++ if ((action = (struct switches_action *) ++ kmalloc(sizeof(struct switches_action), ++ GFP_KERNEL)) == NULL) { ++ printk(KERN_ERR "%s: unable to allocate action " ++ "descriptor\n", SWITCHES_NAME); ++ return -1; ++ } ++ ++ action->mask = *mask; ++ ++ spin_lock(&switches_lock); ++ list_add_tail(&action->list, &switches_event_queue); ++ spin_unlock(&switches_lock); ++ ++ wake_up_interruptible(&switches_wait); ++ ++ } ++ ++ return 0; ++ ++} ++ ++EXPORT_SYMBOL(switches_event); ++ ++ ++static int __init switches_init(void) ++{ ++ if (misc_register(&switches_misc) < 0) { ++ printk(KERN_ERR "%s: unable to register misc device\n", ++ SWITCHES_NAME); ++ return -EIO; ++ } ++ ++ printk(KERN_INFO "Console switches initialized\n"); ++ ++ return 0; ++} ++ ++static void __exit switches_exit(void) ++{ ++ if (misc_deregister(&switches_misc) < 0) ++ printk(KERN_ERR "%s: unable to deregister misc device\n", ++ SWITCHES_NAME); ++} ++ ++module_init(switches_init); ++module_exit(switches_exit); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/misc/ucb1x00-audio.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,439 @@ ++/* ++ * 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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/fs.h> ++#include <linux/errno.h> ++#include <linux/slab.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++#include <linux/list.h> ++#include <linux/device.h> ++ ++#include <asm/dma.h> ++#include <asm/hardware.h> ++#include <asm/semaphore.h> ++#include <asm/uaccess.h> ++ ++#include "ucb1x00.h" ++ ++#include "../sound/oss/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 *ucb1x00_audio_add_one(struct ucb1x00 *ucb, int telecom) ++{ ++ struct ucb1x00_audio *a; ++ ++ a = ucb1x00_audio_alloc(ucb); ++ if (a) { ++ a->telecom = telecom; ++ ++ a->input_stream.dev = ucb->cdev.dev; ++ a->output_stream.dev = ucb->cdev.dev; ++ a->ctrl_a = 0; ++ ++ if (a->telecom) { ++ a->input_stream.dma_dev = ucb->mcp->dma_telco_rd; ++ a->input_stream.id = "UCB1x00 telco in"; ++ a->output_stream.dma_dev = ucb->mcp->dma_telco_wr; ++ a->output_stream.id = "UCB1x00 telco out"; ++ a->ctrl_b = UCB_TC_B_IN_ENA|UCB_TC_B_OUT_ENA; ++#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 ++ } else { ++ a->input_stream.dma_dev = ucb->mcp->dma_audio_rd; ++ a->input_stream.id = "UCB1x00 audio in"; ++ a->output_stream.dma_dev = ucb->mcp->dma_audio_wr; ++ a->output_stream.id = "UCB1x00 audio out"; ++ a->ctrl_b = UCB_AC_B_IN_ENA|UCB_AC_B_OUT_ENA; ++ } ++ ++ a->dev_id = register_sound_dsp(&a->fops, -1); ++ a->mix_id = register_sound_mixer(&a->mops, -1); ++ ++ printk("Sound: UCB1x00 %s: dsp id %d mixer id %d\n", ++ a->telecom ? "telecom" : "audio", ++ a->dev_id, a->mix_id); ++ } ++ ++ return a; ++} ++ ++static void ucb1x00_audio_remove_one(struct ucb1x00_audio *a) ++{ ++ unregister_sound_dsp(a->dev_id); ++ unregister_sound_mixer(a->mix_id); ++ kfree(a); ++} ++ ++static int ucb1x00_audio_add(struct class_device *cdev) ++{ ++ struct ucb1x00 *ucb = classdev_to_ucb1x00(cdev); ++ ++ if (ucb->cdev.dev == NULL || ucb->cdev.dev->dma_mask == NULL) ++ return -ENXIO; ++ ++ ucb->audio_data = ucb1x00_audio_add_one(ucb, 0); ++ ucb->telecom_data = ucb1x00_audio_add_one(ucb, 1); ++ ++ return 0; ++} ++ ++static void ucb1x00_audio_remove(struct class_device *cdev) ++{ ++ struct ucb1x00 *ucb = classdev_to_ucb1x00(cdev); ++ ++ ucb1x00_audio_remove_one(ucb->audio_data); ++ ucb1x00_audio_remove_one(ucb->telecom_data); ++} ++ ++#if 0 //def CONFIG_PM ++static int ucb1x00_audio_suspend(struct ucb1x00 *ucb, u32 state) ++{ ++ struct ucb1x00_audio *a; ++ ++ a = ucb->audio_data; ++ sa1100_audio_suspend(&a->state, state); ++ a = ucb->telecom_data; ++ sa1100_audio_suspend(&a->state, state); ++ ++ return 0; ++} ++ ++static int ucb1x00_audio_resume(struct ucb1x00 *ucb) ++{ ++ struct ucb1x00_audio *a; ++ ++ a = ucb->audio_data; ++ sa1100_audio_resume(&a->state); ++ a = ucb->telecom_data; ++ sa1100_audio_resume(&a->state); ++ ++ return 0; ++} ++#else ++#define ucb1x00_audio_suspend NULL ++#define ucb1x00_audio_resume NULL ++#endif ++ ++static struct class_interface ucb1x00_audio_interface = { ++ .add = ucb1x00_audio_add, ++ .remove = ucb1x00_audio_remove, ++}; ++ ++static int __init ucb1x00_audio_init(void) ++{ ++ return ucb1x00_register_interface(&ucb1x00_audio_interface); ++} ++ ++static void __exit ucb1x00_audio_exit(void) ++{ ++ ucb1x00_unregister_interface(&ucb1x00_audio_interface); ++} ++ ++module_init(ucb1x00_audio_init); ++module_exit(ucb1x00_audio_exit); ++ ++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); ++MODULE_DESCRIPTION("UCB1x00 telecom/audio driver"); ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/misc/mcp-sa1100.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,275 @@ ++/* ++ * 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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/delay.h> ++#include <linux/spinlock.h> ++#include <linux/slab.h> ++#include <linux/device.h> ++ ++#include <asm/dma.h> ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++#include <asm/system.h> ++ ++#include <asm/arch/assabet.h> ++ ++#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; ++} ++ ++/* ++ * Our methods. ++ */ ++static 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, ++}; ++ ++static int mcp_sa1100_probe(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct mcp *mcp = &mcp_sa1100; ++ int ret; ++ ++ if (!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_yopy()) ++ return -ENODEV; ++ ++ if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp")) ++ return -EBUSY; ++ ++ mcp->me = dev; ++ dev_set_drvdata(dev, mcp); ++ ++ if (machine_is_assabet()) { ++ ASSABET_BCR_set(ASSABET_BCR_CODEC_RST); ++ } ++ ++ /* ++ * 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_host_register(mcp, &pdev->dev); ++ if (ret != 0) { ++ release_mem_region(0x80060000, 0x60); ++ dev_set_drvdata(dev, NULL); ++ } ++ ++ return ret; ++} ++ ++static int mcp_sa1100_remove(struct device *dev) ++{ ++ struct mcp *mcp = dev_get_drvdata(dev); ++ ++ dev_set_drvdata(dev, NULL); ++ ++ mcp_host_unregister(mcp); ++ release_mem_region(0x80060000, 0x60); ++ ++ return 0; ++} ++ ++struct mcp_sa1100_state { ++ u32 mccr0; ++ u32 mccr1; ++}; ++ ++static int mcp_sa1100_suspend(struct device *dev, u32 state, u32 level) ++{ ++ struct mcp_sa1100_state *s = (struct mcp_sa1100_state *)dev->saved_state; ++ ++ if (!s) { ++ s = kmalloc(sizeof(struct mcp_sa1100_state), GFP_KERNEL); ++ dev->saved_state = (unsigned char *)s; ++ } ++ ++ if (s) { ++ s->mccr0 = Ser4MCCR0; ++ s->mccr1 = Ser4MCCR1; ++ } ++ ++ if (level == SUSPEND_DISABLE) ++ Ser4MCCR0 &= ~MCCR0_MCE; ++ return 0; ++} ++ ++static int mcp_sa1100_resume(struct device *dev, u32 level) ++{ ++ struct mcp_sa1100_state *s = (struct mcp_sa1100_state *)dev->saved_state; ++ ++ if (s && level == RESUME_RESTORE_STATE) { ++ Ser4MCCR1 = s->mccr1; ++ Ser4MCCR0 = s->mccr0; ++ ++ dev->saved_state = NULL; ++ kfree(s); ++ } ++ return 0; ++} ++ ++/* ++ * The driver for the SA11x0 MCP port. ++ */ ++static struct device_driver mcp_sa1100_driver = { ++ .name = "sa11x0-mcp", ++ .bus = &platform_bus_type, ++ .probe = mcp_sa1100_probe, ++ .remove = mcp_sa1100_remove, ++ .suspend = mcp_sa1100_suspend, ++ .resume = mcp_sa1100_resume, ++}; ++ ++/* ++ * This needs re-working ++ */ ++static int __init mcp_sa1100_init(void) ++{ ++ return driver_register(&mcp_sa1100_driver); ++} ++ ++static void __exit mcp_sa1100_exit(void) ++{ ++ driver_unregister(&mcp_sa1100_driver); ++} ++ ++module_init(mcp_sa1100_init); ++module_exit(mcp_sa1100_exit); ++ ++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); ++MODULE_DESCRIPTION("SA11x0 multimedia communications port driver"); ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/misc/mcp.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,58 @@ ++/* ++ * 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; ++ struct device *me; ++ 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 *); ++ struct device attached_device; ++}; ++ ++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 *); ++#define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate) ++ ++int mcp_host_register(struct mcp *, struct device *); ++void mcp_host_unregister(struct mcp *); ++ ++struct mcp_driver { ++ struct device_driver drv; ++ int (*probe)(struct mcp *); ++ void (*remove)(struct mcp *); ++ int (*suspend)(struct mcp *, u32); ++ int (*resume)(struct mcp *); ++}; ++ ++int mcp_driver_register(struct mcp_driver *); ++void mcp_driver_unregister(struct mcp_driver *); ++ ++#define mcp_get_drvdata(mcp) dev_get_drvdata(&(mcp)->attached_device) ++#define mcp_set_drvdata(mcp,d) dev_set_drvdata(&(mcp)->attached_device, d) ++ ++#endif +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/misc/ucb1x00-input.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,233 @@ ++/* ++ * 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_ID_1400 0x4304 ++#define UCB_ID_1400_BUGGY 0x4303 /* fake ID */ ++ ++#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; ++ 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 +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/misc/ucb1x00.h 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,271 @@ ++/* ++ * 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 ++ ++#ifdef CONFIG_ARCH_PXA ++ ++/* ucb1400 aclink register mappings: */ ++ ++#define UCB_IO_DATA 0x5a ++#define UCB_IO_DIR 0x5c ++#define UCB_IE_RIS 0x5e ++#define UCB_IE_FAL 0x60 ++#define UCB_IE_STATUS 0x62 ++#define UCB_IE_CLEAR 0x62 ++#define UCB_TS_CR 0x64 ++#define UCB_ADC_CR 0x66 ++#define UCB_ADC_DATA 0x68 ++#define UCB_ID 0x7e /* 7c is mfr id, 7e part id (from aclink spec) */ ++ ++#define UCB_ADC_DAT(x) ((x) & 0x3ff) ++ ++#else ++ ++/* ucb1x00 SIB register mappings: */ ++ ++#define UCB_IO_DATA 0x00 ++#define UCB_IO_DIR 0x01 ++#define UCB_IE_RIS 0x02 ++#define UCB_IE_FAL 0x03 ++#define UCB_IE_STATUS 0x04 ++#define UCB_IE_CLEAR 0x04 ++#define UCB_TC_A 0x05 ++#define UCB_TC_B 0x06 ++#define UCB_AC_A 0x07 ++#define UCB_AC_B 0x08 ++#define UCB_TS_CR 0x09 ++#define UCB_ADC_CR 0x0a ++#define UCB_ADC_DATA 0x0b ++#define UCB_ID 0x0c ++#define UCB_MODE 0x0d ++ ++#define UCB_ADC_DAT(x) (((x) & 0x7fe0) >> 5) ++ ++#endif ++ ++ ++#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_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_LOOP (1 << 7) /* UCB1200 */ ++#define UCB_TC_A_AMPL (1 << 7) /* UCB1300 */ ++ ++#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_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_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_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_DAT_VAL (1 << 15) ++ ++#define UCB_ID_1200 0x1004 ++#define UCB_ID_1300 0x1005 ++#define UCB_ID_1400 0x4304 ++#define UCB_ID_1400_BUGGY 0x4303 /* fake ID */ ++ ++#define UCB_MODE_DYN_VFLAG_ENA (1 << 12) ++#define UCB_MODE_AUD_OFF_CAN (1 << 13) ++ ++#include <linux/completion.h> ++#include "mcp.h" ++ ++struct ucb1x00_irq { ++ void *devid; ++ void (*fn)(int, void *); ++}; ++ ++extern struct class ucb1x00_class; ++ ++struct ucb1x00 { ++ spinlock_t lock; ++ struct mcp *mcp; ++ unsigned int irq; ++ struct semaphore adc_sem; ++ spinlock_t io_lock; ++ wait_queue_head_t irq_wait; ++ struct completion complete; ++ struct task_struct *rtask; ++ 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]; ++ struct class_device cdev; ++ void *audio_data; ++ void *telecom_data; ++ void *ts_data; ++}; ++ ++#define classdev_to_ucb1x00(cd) container_of(cd, struct ucb1x00, cdev) ++ ++int ucb1x00_register_interface(struct class_interface *intf); ++void ucb1x00_unregister_interface(struct class_interface *intf); ++ ++/** ++ * 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); ++} ++ ++#define ucb1x00_get() NULL ++ ++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 +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/misc/switches-sa1100.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,323 @@ ++/* ++ * linux/drivers/misc/switches-sa1100.c ++ * ++ * Copyright (C) 2001 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. ++ * ++ * 19 December 2001 - created from sa1100_switches.c. ++ */ ++ ++#include <linux/config.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/interrupt.h> ++ ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++#include <asm/irq.h> ++ ++#include <asm/arch/assabet.h> ++#include <asm/arch/neponset.h> ++#include <asm/arch/badge4.h> ++ ++#include "switches.h" ++ ++ ++static irqreturn_t switches_sa1100_handler(int irq, void *dev_id, ++ struct pt_regs *regs); ++ ++ ++#ifdef CONFIG_SA1100_ASSABET ++ ++/* Assabet ++ * ^^^^^^^ ++ * We have two general-purpose switches, S1 and S2, available via GPIO ++ * on Assabet. This code sets bits in the range [1, 2] in the mask that ++ * we return to userland. ++ */ ++ ++static int assabet_switches_sa1100_init(void) ++{ ++ ++ if (machine_has_neponset()) ++ NCR_0 |= NCR_GP01_OFF; ++ ++ if (request_irq(IRQ_GPIO0, switches_sa1100_handler, SA_INTERRUPT, ++ SWITCHES_NAME, NULL) < 0) { ++ printk(KERN_ERR "%s: unable to register IRQ for GPIO 0\n", ++ SWITCHES_NAME); ++ return -EIO; ++ } ++ ++ if (request_irq(IRQ_GPIO1, switches_sa1100_handler, SA_INTERRUPT, ++ SWITCHES_NAME, NULL) < 0) { ++ printk(KERN_ERR "%s: unable to register IRQ for GPIO 1\n", ++ SWITCHES_NAME); ++ free_irq(IRQ_GPIO0, NULL); ++ return -EIO; ++ } ++ ++ set_irq_type(IRQ_GPIO0, IRQT_BOTHEDGE); ++ set_irq_type(IRQ_GPIO1, IRQT_BOTHEDGE); ++ ++ return 0; ++ ++} ++ ++static void assabet_switches_sa1100_shutdown(void) ++{ ++ ++ free_irq(IRQ_GPIO1, NULL); ++ free_irq(IRQ_GPIO0, NULL); ++ ++} ++ ++static irqreturn_t assabet_switches_sa1100_handler(int irq, switches_mask_t *mask) ++{ ++ unsigned int s, last, this; ++ static unsigned int states = 0; ++ ++ switch (irq) { ++ ++ case IRQ_GPIO0: s = 0; break; ++ ++ case IRQ_GPIO1: s = 1; break; ++ ++ default: return IRQ_NONE; ++ ++ } ++ ++ last = ((states & (1 << s)) != 0); ++ this = ((GPLR & GPIO_GPIO(s)) != 0); ++ ++ if (last == this) /* debounce */ ++ return IRQ_HANDLED; ++ ++ SWITCHES_SET(mask, s + 1, this); ++ ++ states = this ? (states | (1 << s)) : (states & ~(1 << s)); ++ ++ return IRQ_HANDLED; ++} ++#endif /* CONFIG_SA1100_ASSABET */ ++ ++#ifdef CONFIG_SA1100_BADGE4 ++ ++/* BadgePAD 4 ++ * ^^^^^^^^^^ ++ * ++ * Here we use test point J6 (BADGE4_GPIO_TESTPT_J6 aka GPIO 23) as a ++ * general purpose switch input. We map this to switch #0. ++ */ ++ ++#define BADGE4_SW0_GPIO GPIO_GPIO23 /* aka BADGE4_GPIO_TESTPT_J6 */ ++#define BADGE4_SW0_IRQ IRQ_GPIO23 ++ ++static int badge4_switches_sa1100_init(void) ++{ ++ if (request_irq(BADGE4_SW0_IRQ, switches_sa1100_handler, SA_INTERRUPT, ++ SWITCHES_NAME, NULL) < 0) { ++ printk(KERN_ERR "%s: unable to register IRQ for SW0\n", ++ SWITCHES_NAME); ++ return -EIO; ++ } ++ ++ set_irq_type(BADGE4_SW0_IRQ, IRQT_BOTHEDGE); ++ ++ return 0; ++} ++ ++static void badge4_switches_sa1100_shutdown(void) ++{ ++ free_irq(BADGE4_SW0_IRQ, NULL); ++} ++ ++static irqreturn_t badge4_switches_sa1100_handler(int irq, switches_mask_t *mask) ++{ ++ unsigned int swno, last, this, gpio; ++ static unsigned int states = 0; ++ ++ switch (irq) { ++ case BADGE4_SW0_IRQ: ++ swno = 0; ++ gpio = BADGE4_SW0_GPIO; ++ break; ++ default: ++ return IRQ_NONE; ++ } ++ ++ last = ((states & gpio) != 0); ++ this = ((GPLR & gpio) != 0); ++ ++ if (last == this) /* debounce */ ++ return IRQ_HANDLED; ++ ++ SWITCHES_SET(mask, swno, this); ++ ++ states = this ? (states | gpio) : (states & ~gpio); ++ ++ return IRQ_HANDLED; ++} ++#endif /* CONFIG_SA1100_BADGE4 */ ++ ++ ++#ifdef CONFIG_SA1100_SPOT ++ ++/* Spot ++ * ^^^^ ++ * Spot (R2, R3) has a single general-purpose switch (S1), which is ++ * also the power-on switch. We set bit [1] in the mask we return to ++ * userland. ++ */ ++ ++static int spot_switches_sa1100_init(void) ++{ ++ ++ set_GPIO_IRQ_edge(GPIO_SW1, GPIO_BOTH_EDGES); ++ ++ if (request_irq(IRQ_GPIO_SW1, switches_sa1100_handler, SA_INTERRUPT, ++ SWITCHES_NAME, NULL) < 0) { ++ printk(KERN_ERR "%s: unable to register IRQ for SW1\n", ++ SWITCHES_NAME); ++ return -EIO; ++ } ++ ++ return 0; ++ ++} ++ ++static void spot_switches_sa1100_shutdown(void) ++{ ++ ++ free_irq(IRQ_GPIO_SW1, NULL); ++ ++} ++ ++static irqreturn_t spot_switches_sa1100_handler(int irq, switches_mask_t *mask) ++{ ++ unsigned int s, last, this; ++ static unsigned int states = 0; ++ ++ switch (irq) { ++ ++ case IRQ_GPIO_SW1: s = 0; break; ++ ++ default: return IRQ_NONE; ++ ++ } ++ ++ last = ((states & (1 << s)) != 0); ++ this = ((GPLR & GPIO_GPIO(s)) != 0); ++ ++ if (last == this) /* debounce */ ++ return IRQ_HANDLED; ++ ++ SWITCHES_SET(mask, s + 1, this); ++ ++ states = this ? (states | (1 << s)) : (states & ~(1 << s)); ++ ++ return IRQ_HANDLED; ++ ++} ++#endif /* CONFIG_SA1100_SPOT */ ++ ++ ++/* switches_sa1100_handler() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * This routine is a generalized handler for SA-1100 switches ++ * which manages action descriptors and calls a board-specific ++ * service routine. This routine is appropriate for GPIO switches ++ * or other primary interrupt sources, and can be registered as a ++ * first-class IRQ handler using request_irq(). ++ */ ++static irqreturn_t switches_sa1100_handler(int irq, void *dev_id, ++ struct pt_regs *regs) ++{ ++ switches_mask_t mask; ++ irqreturn_t ret = IRQ_NONE; ++ ++ SWITCHES_ZERO(&mask); ++ ++ /* Porting note: call a board-specific switch interrupt handler ++ * here. The handler can assume that sufficient storage for ++ * `mask' has been allocated, and that the corresponding ++ * switches_mask_t structure has been zeroed. ++ */ ++ ++ if (machine_is_assabet()) { ++#ifdef CONFIG_SA1100_ASSABET ++ ret = assabet_switches_sa1100_handler(irq, &mask); ++#endif ++ } else if (machine_is_badge4()) { ++#ifdef CONFIG_SA1100_BADGE4 ++ ret = badge4_switches_sa1100_handler(irq, &mask); ++#endif ++ } else if (machine_is_spot()) { ++#ifdef CONFIG_SA1100_SPOT ++ ret = spot_switches_sa1100_handler(irq, &mask); ++#endif ++ } ++ ++ switches_event(&mask); ++ ++ return ret; ++} ++ ++int __init switches_sa1100_init(void) ++{ ++ ++ /* Porting note: call a board-specific init routine here. */ ++ ++ if (machine_is_assabet()) { ++#ifdef CONFIG_SA1100_ASSABET ++ if (assabet_switches_sa1100_init() < 0) ++ return -EIO; ++#endif ++ } else if (machine_is_badge4()) { ++#ifdef CONFIG_SA1100_BADGE4 ++ if (badge4_switches_sa1100_init() < 0) ++ return -EIO; ++#endif ++ } else if (machine_is_spot()) { ++#ifdef CONFIG_SA1100_SPOT ++ if (spot_switches_sa1100_init() < 0) ++ return -EIO; ++#endif ++ } ++ ++ return 0; ++ ++} ++ ++void __exit switches_sa1100_exit(void) ++{ ++ ++ /* Porting note: call a board-specific shutdown routine here. */ ++ ++ if (machine_is_assabet()) { ++#ifdef CONFIG_SA1100_ASSABET ++ assabet_switches_sa1100_shutdown(); ++#endif ++ } else if (machine_is_badge4()) { ++#ifdef CONFIG_SA1100_BADGE4 ++ badge4_switches_sa1100_shutdown(); ++#endif ++ } else if (machine_is_spot()) { ++#ifdef CONFIG_SA1100_SPOT ++ spot_switches_sa1100_shutdown(); ++#endif ++ } ++ ++} ++ ++module_init(switches_sa1100_init); ++module_exit(switches_sa1100_exit); ++ ++MODULE_DESCRIPTION("SA-1100 switches driver"); ++MODULE_LICENSE("GPL"); +--- linux-2.6.5/drivers/misc/Makefile~heh 2004-04-03 22:38:17.000000000 -0500 ++++ linux-2.6.5/drivers/misc/Makefile 2004-04-30 20:57:36.000000000 -0400 +@@ -4,3 +4,21 @@ + obj- := misc.o # Dummy rule to force built-in.o to be made + + obj-$(CONFIG_IBM_ASM) += ibmasm/ ++ ++obj-$(CONFIG_MCP) += mcp-core.o ++obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o ++obj-$(CONFIG_MCP_UCB1200_AUDIO) += ucb1x00-audio.o ++obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o ++ ++ifeq ($(CONFIG_SA1100_ASSABET),y) ++obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o ++endif ++ ++obj-$(CONFIG_SWITCHES) += switches-core.o ++obj-$(CONFIG_SWITCHES_SA1100) += switches-sa1100.o ++obj-$(CONFIG_SWITCHES_UCB1X00) += switches-ucb1x00.o ++ ++obj-$(CONFIG_MCP_SA1100) += mcp-sa1100.o ++ ++obj-$(CONFIG_UCB1400_TS) += mcp-pxa.o ucb1x00-core.o ucb1x00-ts.o ++ +--- linux-2.6.5/drivers/i2c/busses/Kconfig~heh 2004-04-03 22:38:10.000000000 -0500 ++++ linux-2.6.5/drivers/i2c/busses/Kconfig 2004-04-30 20:57:36.000000000 -0400 +@@ -70,6 +70,16 @@ + This support is also available as a module. If so, the module + will be called i2c-hydra. + ++config I2C_BIT_SA1100_GPIO ++ bool "SA1100 I2C GPIO adapter" ++ depends on ARCH_SA1100 && I2C_ALGOBIT ++ help ++ This supports I2C on the SA11x0 processor GPIO pins. This ++ shares support with the L3 driver. ++ ++ This support is also available as a module. If so, the module ++ will be called l3-bit-sa1100. ++ + config I2C_I801 + tristate "Intel 801" + depends on I2C && PCI && EXPERIMENTAL +@@ -241,6 +251,18 @@ + This support is also available as a module. If so, the module + will be called i2c-prosavage. + ++config I2C_PXA2XX ++ tristate "PXA I2C Interface" ++ depends on I2C && ARCH_PXA ++ select I2C_ALGOPXA ++ help ++ This supports the use of the PXA I2C interface found on the Intel ++ PXA 25x and PXA 26x systems. Say Y if you have one of these. ++ ++ This support 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-adap-pxa. ++ + config I2C_RPXLITE + tristate "Embedded Planet RPX Lite/Classic support" + depends on (RPXLITE || RPXCLASSIC) && I2C +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/i2c/busses/pxa2xx_i2c.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,388 @@ ++/* ++ * i2c_adap_pxa.c ++ * ++ * I2C adapter for the PXA I2C bus access. ++ * ++ * 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. ++ * ++ * History: ++ * Apr 2002: Initial version [CS] ++ * Jun 2002: Properly seperated algo/adap [FB] ++ * Jan 2003: Fixed several bugs concerning interrupt handling [Kai-Uwe Bloem] ++ * Jan 2003: added limited signal handling [Kai-Uwe Bloem] ++ * Jun 2003: updated for 2.5 [Dustin McIntire] ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++ ++#include <linux/i2c.h> ++#include <linux/i2c-id.h> ++#include <linux/init.h> ++#include <linux/time.h> ++#include <linux/sched.h> ++#include <linux/delay.h> ++#include <linux/errno.h> ++#include <linux/interrupt.h> ++ ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/arch/irqs.h> /* for IRQ_I2C */ ++ ++#include <linux/i2c-pxa.h> ++ ++/* ++ * Set this to zero to remove all debug statements via dead code elimination. ++ */ ++//#define DEBUG 1 ++ ++#if DEBUG ++static unsigned int i2c_debug = DEBUG; ++#else ++#define i2c_debug 0 ++#endif ++ ++static int irq = 0; ++static volatile int i2c_pending = 0; /* interrupt pending when 1 */ ++static volatile int bus_error = 0; ++static volatile int tx_finished = 0; ++static volatile int rx_finished = 0; ++ ++static wait_queue_head_t i2c_wait; ++static void i2c_pxa_transfer( int lastbyte, int receive, int midbyte); ++ ++/* place a byte in the transmit register */ ++static void i2c_pxa_write_byte(u8 value) ++{ ++ IDBR = value; ++} ++ ++/* read byte in the receive register */ ++static u8 i2c_pxa_read_byte(void) ++{ ++ return (u8) (0xff & IDBR); ++} ++ ++static void i2c_pxa_start(void) ++{ ++ unsigned long icr = ICR; ++ icr |= ICR_START; ++ icr &= ~(ICR_STOP | ICR_ALDIE | ICR_ACKNAK); ++ ICR = icr; ++ ++ bus_error=0; /* clear any bus_error from previous txfers */ ++ tx_finished=0; /* clear rx and tx interrupts from previous txfers */ ++ rx_finished=0; ++ i2c_pending = 0; ++} ++ ++static void i2c_pxa_repeat_start(void) ++{ ++ unsigned long icr = ICR; ++ icr |= ICR_START; ++ icr &= ~(ICR_STOP | ICR_ALDIE); ++ ICR = icr; ++ ++ bus_error=0; /* clear any bus_error from previous txfers */ ++ tx_finished=0; /* clear rx and tx interrupts from previous txfers */ ++ rx_finished=0; ++ i2c_pending = 0; ++} ++ ++static void i2c_pxa_stop(void) ++{ ++ unsigned long icr = ICR; ++ icr |= ICR_STOP; ++ icr &= ~(ICR_START); ++ ICR = icr; ++} ++ ++static void i2c_pxa_midbyte(void) ++{ ++ unsigned long icr = ICR; ++ icr &= ~(ICR_START | ICR_STOP); ++ ICR = icr; ++} ++ ++static void i2c_pxa_abort(void) ++{ ++ unsigned long timeout = jiffies + HZ/4; ++ ++#ifdef PXA_ABORT_MA ++ while ((long)(timeout - jiffies) > 0 && (ICR & ICR_TB)) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(1); ++ } ++ ++ ICR |= ICR_MA; ++ udelay(100); ++#else ++ while ((long)(timeout - jiffies) > 0 && (IBMR & 0x1) == 0) { ++ i2c_pxa_transfer( 1, I2C_RECEIVE, 1); ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(1); ++ } ++#endif ++ ICR &= ~(ICR_MA | ICR_START | ICR_STOP); ++} ++ ++static int i2c_pxa_wait_bus_not_busy( void) ++{ ++ int timeout = DEF_TIMEOUT; ++ ++ while (timeout-- && (ISR & ISR_IBB)) { ++ udelay(100); /* wait for 100 us */ ++ } ++ ++ return (timeout<=0); ++} ++ ++spinlock_t i2c_pxa_irqlock = SPIN_LOCK_UNLOCKED; ++ ++static void i2c_pxa_wait_for_ite(void){ ++ unsigned long flags; ++ if (irq > 0) { ++ spin_lock_irqsave(&i2c_pxa_irqlock, flags); ++ if (i2c_pending == 0) { ++ interruptible_sleep_on_timeout(&i2c_wait, I2C_SLEEP_TIMEOUT ); ++ } ++ i2c_pending = 0; ++ spin_unlock_irqrestore(&i2c_pxa_irqlock, flags); ++ } else { ++ udelay(100); ++ } ++} ++ ++static int i2c_pxa_wait_for_int( int wait_type) ++{ ++ int timeout = DEF_TIMEOUT; ++#ifdef DEBUG ++ if (bus_error) ++ printk(KERN_INFO"i2c_pxa_wait_for_int: Bus error on enter\n"); ++ if (rx_finished) ++ printk(KERN_INFO"i2c_pxa_wait_for_int: Receive interrupt on enter\n"); ++ if (tx_finished) ++ printk(KERN_INFO"i2c_pxa_wait_for_int: Transmit interrupt on enter\n"); ++#endif ++ ++ if (wait_type == I2C_RECEIVE){ /* wait on receive */ ++ ++ do { ++ i2c_pxa_wait_for_ite(); ++ } while (!(rx_finished) && timeout-- && !signal_pending(current)); ++ ++#ifdef DEBUG ++ if (timeout<0){ ++ if (tx_finished) ++ printk("Error: i2c-algo-pxa.o: received a tx" ++ " interrupt while waiting on a rx in wait_for_int"); ++ } ++#endif ++ } else { /* wait on transmit */ ++ ++ do { ++ i2c_pxa_wait_for_ite(); ++ } while (!(tx_finished) && timeout-- && !signal_pending(current)); ++ ++#ifdef DEBUG ++ if (timeout<0){ ++ if (rx_finished) ++ printk("Error: i2c-algo-pxa.o: received a rx" ++ " interrupt while waiting on a tx in wait_for_int"); ++ } ++#endif ++ } ++ ++ udelay(ACK_DELAY); /* this is needed for the bus error */ ++ ++ tx_finished=0; ++ rx_finished=0; ++ ++ if (bus_error){ ++ bus_error=0; ++ if( i2c_debug > 2)printk("wait_for_int: error - no ack.\n"); ++ return BUS_ERROR; ++ } ++ ++ if (signal_pending(current)) { ++ return (-ERESTARTSYS); ++ } else if (timeout < 0) { ++ if( i2c_debug > 2)printk("wait_for_int: timeout.\n"); ++ return(-EIO); ++ } else ++ return(0); ++} ++ ++static void i2c_pxa_transfer( int lastbyte, int receive, int midbyte) ++{ ++ if( lastbyte) ++ { ++ if( receive==I2C_RECEIVE) ICR |= ICR_ACKNAK; ++ i2c_pxa_stop(); ++ } ++ else if( midbyte) ++ { ++ i2c_pxa_midbyte(); ++ } ++ ICR |= ICR_TB; ++} ++ ++static void i2c_pxa_reset( void) ++{ ++#ifdef DEBUG ++ printk("Resetting I2C Controller Unit\n"); ++#endif ++ ++ /* abort any transfer currently under way */ ++ i2c_pxa_abort(); ++ ++ /* reset according to 9.8 */ ++ ICR = ICR_UR; ++ ISR = I2C_ISR_INIT; ++ ICR &= ~ICR_UR; ++ ++ /* set the global I2C clock on */ ++ CKEN |= CKEN14_I2C; ++ ++ /* set our slave address */ ++ ISAR = I2C_PXA_SLAVE_ADDR; ++ ++ /* set control register values */ ++ ICR = I2C_ICR_INIT; ++ ++ /* clear any leftover states from prior transmissions */ ++ i2c_pending = rx_finished = tx_finished = bus_error = 0; ++ ++ /* enable unit */ ++ ICR |= ICR_IUE; ++ udelay(100); ++} ++ ++static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id, struct pt_regs *regs) ++{ ++ unsigned long flags; ++ int status, wakeup = 0; ++ status = (ISR); ++ ++ if (status & ISR_BED){ ++ (ISR) |= ISR_BED; ++ bus_error=ISR_BED; ++ wakeup = 1; ++ } ++ if (status & ISR_ITE){ ++ (ISR) |= ISR_ITE; ++ tx_finished=ISR_ITE; ++ wakeup = 1; ++ } ++ if (status & ISR_IRF){ ++ (ISR) |= ISR_IRF; ++ rx_finished=ISR_IRF; ++ wakeup = 1; ++ } ++ if (wakeup) { ++ spin_lock_irqsave(&i2c_pxa_irqlock, flags); ++ i2c_pending = 1; ++ spin_unlock_irqrestore(&i2c_pxa_irqlock, flags); ++ wake_up_interruptible(&i2c_wait); ++ } ++ return IRQ_HANDLED; ++} ++ ++static int i2c_pxa_resource_init( void) ++{ ++ init_waitqueue_head(&i2c_wait); ++ ++ if (request_irq(IRQ_I2C, &i2c_pxa_handler, SA_INTERRUPT, "I2C", 0) < 0) { ++ irq = 0; ++ if(i2c_debug) ++ printk(KERN_INFO "I2C: Failed to register I2C irq %i\n", IRQ_I2C); ++ return -ENODEV; ++ } ++ return 0; ++} ++ ++static void i2c_pxa_resource_release( void) ++{ ++ if( irq > 0) ++ { ++ disable_irq(irq); ++ free_irq(irq,0); ++ irq=0; ++ } ++} ++ ++static int i2c_pxa_client_register(struct i2c_client *client) ++{ ++ return 0; ++} ++ ++static int i2c_pxa_client_unregister(struct i2c_client *client) ++{ ++ return 0; ++} ++ ++static struct i2c_algo_pxa_data i2c_pxa_data = { ++ write_byte: i2c_pxa_write_byte, ++ read_byte: i2c_pxa_read_byte, ++ ++ start: i2c_pxa_start, ++ repeat_start: i2c_pxa_repeat_start, ++ stop: i2c_pxa_stop, ++ abort: i2c_pxa_abort, ++ ++ wait_bus_not_busy: i2c_pxa_wait_bus_not_busy, ++ wait_for_interrupt: i2c_pxa_wait_for_int, ++ transfer: i2c_pxa_transfer, ++ reset: i2c_pxa_reset, ++ ++ udelay: 10, ++ timeout: DEF_TIMEOUT, ++}; ++ ++static struct i2c_adapter i2c_pxa_ops = { ++ .owner = THIS_MODULE, ++ .id = I2C_ALGO_PXA, ++ .algo_data = &i2c_pxa_data, ++ .dev = { ++ .name = "PXA I2C Adapter", ++ }, ++ .client_register = i2c_pxa_client_register, ++ .client_unregister = i2c_pxa_client_unregister, ++ .retries = 2, ++}; ++ ++extern int i2c_pxa_add_bus(struct i2c_adapter *); ++extern int i2c_pxa_del_bus(struct i2c_adapter *); ++ ++static int __init i2c_adap_pxa_init(void) ++{ ++ if( i2c_pxa_resource_init() == 0) { ++ ++ if (i2c_pxa_add_bus(&i2c_pxa_ops) < 0) { ++ i2c_pxa_resource_release(); ++ printk(KERN_INFO "I2C: Failed to add bus\n"); ++ return -ENODEV; ++ } ++ } else { ++ return -ENODEV; ++ } ++ ++ printk(KERN_INFO "I2C: Successfully added bus\n"); ++ ++ return 0; ++} ++ ++static void i2c_adap_pxa_exit(void) ++{ ++ i2c_pxa_del_bus( &i2c_pxa_ops); ++ i2c_pxa_resource_release(); ++ ++ printk(KERN_INFO "I2C: Successfully removed bus\n"); ++} ++ ++module_init(i2c_adap_pxa_init); ++module_exit(i2c_adap_pxa_exit); +--- linux-2.6.5/drivers/i2c/busses/Makefile~heh 2004-04-03 22:36:17.000000000 -0500 ++++ linux-2.6.5/drivers/i2c/busses/Makefile 2004-04-30 20:57:36.000000000 -0400 +@@ -21,6 +21,7 @@ + obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o + obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o + obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o ++obj-$(CONFIG_I2C_PXA) += pxa2xx_i2c.o + obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o + obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o + obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o +--- linux-2.6.5/drivers/i2c/algos/Kconfig~heh 2004-04-03 22:37:59.000000000 -0500 ++++ linux-2.6.5/drivers/i2c/algos/Kconfig 2004-04-30 20:57:36.000000000 -0400 +@@ -38,6 +38,18 @@ + This support is also available as a module. If so, the module + will be called i2c-algo-ite. + ++config I2C_ALGOPXA ++ tristate "PXA I2C Algorithm" ++ depends on ARCH_PXA && I2C ++ help ++ This supports the use of the PXA I2C interface found on the Intel ++ PXA 25x and PXA 26x systems. Say Y if you have one of these. ++ You should also say Y for the PXA I2C peripheral driver support below. ++ ++ This support 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-algo-pxa. ++ + config I2C_ALGO8XX + tristate "MPC8xx CPM I2C interface" + depends on 8xx && I2C +--- /dev/null 2003-09-23 18:19:32.000000000 -0400 ++++ linux-2.6.5/drivers/i2c/algos/i2c-algo-pxa.c 2004-04-30 20:57:36.000000000 -0400 +@@ -0,0 +1,384 @@ ++/* ++ * i2c-algo-pxa.c ++ * ++ * I2C algorithm for the PXA I2C bus access. ++ * Byte driven algorithm similar to pcf. ++ * ++ * 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. ++ * ++ * History: ++ * Apr 2002: Initial version [CS] ++ * Jun 2002: Properly seperated algo/adap [FB] ++ * Jan 2003: added limited signal handling [Kai-Uwe Bloem] ++ * Jan 2003: allow SMBUS_QUICK as valid msg [FB] ++ * Jun 2003: updated for 2.5 [Dustin McIntire] ++ * ++ */ ++#include <linux/kernel.h> ++#include <linux/module.h> ++ ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/errno.h> ++#include <linux/i2c.h> /* struct i2c_msg and others */ ++#include <linux/i2c-id.h> ++ ++#include <linux/i2c-pxa.h> ++ ++/* ++ * Set this to zero to remove all the debug statements via dead code elimination. ++ */ ++//#define DEBUG 1 ++ ++#if DEBUG ++static unsigned int i2c_debug = DEBUG; ++#else ++#define i2c_debug 0 ++#endif ++ ++static int pxa_scan = 1; ++ ++static int i2c_pxa_valid_messages( struct i2c_msg msgs[], int num) ++{ ++ int i; ++ if (num < 1 || num > MAX_MESSAGES){ ++ if( i2c_debug) ++ printk(KERN_INFO "Invalid number of messages (max=%d, num=%d)\n", ++ MAX_MESSAGES, num); ++ return -EINVAL; ++ } ++ ++ /* check consistency of our messages */ ++ for (i=0;i<num;i++){ ++ if (&msgs[i]==NULL){ ++ if( i2c_debug) printk(KERN_INFO "Msgs is NULL\n"); ++ return -EINVAL; ++ } else { ++ if (msgs[i].buf == NULL){ ++ if( i2c_debug)printk(KERN_INFO "Length is less than zero"); ++ return -EINVAL; ++ } ++ } ++ } ++ ++ return 1; ++} ++ ++static int i2c_pxa_readbytes(struct i2c_adapter *i2c_adap, char *buf, ++ int count, int last) ++{ ++ ++ int i, timeout=0; ++ struct i2c_algo_pxa_data *adap = i2c_adap->algo_data; ++ ++ /* increment number of bytes to read by one -- read dummy byte */ ++ for (i = 0; i <= count; i++) { ++ if (i!=0){ ++ /* set ACK to NAK for last received byte ICR[ACKNAK] = 1 ++ only if not a repeated start */ ++ ++ if ((i == count) && last) { ++ adap->transfer( last, I2C_RECEIVE, 0); ++ }else{ ++ adap->transfer( 0, I2C_RECEIVE, 1); ++ } ++ ++ timeout = adap->wait_for_interrupt(I2C_RECEIVE); ++ ++#ifdef DEBUG ++ if (timeout==BUS_ERROR){ ++ printk(KERN_INFO "i2c_pxa_readbytes: bus error -> forcing reset\n"); ++ adap->reset(); ++ return I2C_RETRY; ++ } else ++#endif ++ if (timeout == -ERESTARTSYS) { ++ adap->abort(); ++ return timeout; ++ } else ++ if (timeout){ ++#ifdef DEBUG ++ printk(KERN_INFO "i2c_pxa_readbytes: timeout -> forcing reset\n"); ++#endif ++ adap->reset(); ++ return I2C_RETRY; ++ } ++ ++ } ++ ++ if (i) { ++ buf[i - 1] = adap->read_byte(); ++ } else { ++ adap->read_byte(); /* dummy read */ ++ } ++ } ++ return (i - 1); ++} ++ ++static int i2c_pxa_sendbytes(struct i2c_adapter *i2c_adap, const char *buf, ++ int count, int last) ++{ ++ ++ struct i2c_algo_pxa_data *adap = i2c_adap->algo_data; ++ int wrcount, timeout; ++ ++ for (wrcount=0; wrcount<count; ++wrcount) { ++ ++ adap->write_byte(buf[wrcount]); ++ if ((wrcount==(count-1)) && last) { ++ adap->transfer( last, I2C_TRANSMIT, 0); ++ }else{ ++ adap->transfer( 0, I2C_TRANSMIT, 1); ++ } ++ ++ timeout = adap->wait_for_interrupt(I2C_TRANSMIT); ++ ++#ifdef DEBUG ++ if (timeout==BUS_ERROR) { ++ printk(KERN_INFO "i2c_pxa_sendbytes: bus error -> forcing reset.\n"); ++ adap->reset(); ++ return I2C_RETRY; ++ } else ++#endif ++ if (timeout == -ERESTARTSYS) { ++ adap->abort(); ++ return timeout; ++ } else ++ if (timeout) { ++#ifdef DEBUG ++ printk(KERN_INFO "i2c_pxa_sendbytes: timeout -> forcing reset\n"); ++#endif ++ adap->reset(); ++ return I2C_RETRY; ++ } ++ } ++ return (wrcount); ++} ++ ++ ++static inline int i2c_pxa_set_ctrl_byte(struct i2c_algo_pxa_data * adap, struct i2c_msg *msg) ++{ ++ u16 flags = msg->flags; ++ u8 addr; ++ addr = (u8) ( (0x7f & msg->addr) << 1 ); ++ if (flags & I2C_M_RD ) ++ addr |= 1; ++ if (flags & I2C_M_REV_DIR_ADDR ) ++ addr ^= 1; ++ adap->write_byte(addr); ++ return 0; ++} ++ ++static int i2c_pxa_do_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) ++{ ++ struct i2c_algo_pxa_data * adap; ++ struct i2c_msg *pmsg=NULL; ++ int i; ++ int ret=0, timeout; ++ ++ adap = i2c_adap->algo_data; ++ ++ timeout = adap->wait_bus_not_busy(); ++ ++ if (timeout) { ++ return I2C_RETRY; ++ } ++ ++ for (i = 0;ret >= 0 && i < num; i++) { ++ int last = i + 1 == num; ++ pmsg = &msgs[i]; ++ ++ ret = i2c_pxa_set_ctrl_byte(adap,pmsg); ++ ++ /* Send START */ ++ if (i == 0) { ++ adap->start(); ++ }else{ ++ adap->repeat_start(); ++ } ++ ++ adap->transfer(0, I2C_TRANSMIT, 0); ++ ++ /* Wait for ITE (transmit empty) */ ++ timeout = adap->wait_for_interrupt(I2C_TRANSMIT); ++ ++#ifdef DEBUG ++ /* Check for ACK (bus error) */ ++ if (timeout==BUS_ERROR){ ++ printk(KERN_INFO "i2c_pxa_do_xfer: bus error -> forcing reset\n"); ++ adap->reset(); ++ return I2C_RETRY; ++ } else ++#endif ++ if (timeout == -ERESTARTSYS) { ++ adap->abort(); ++ return timeout; ++ } else ++ if (timeout) { ++#ifdef DEBUG ++ printk(KERN_INFO "i2c_pxa_do_xfer: timeout -> forcing reset\n"); ++#endif ++ adap->reset(); ++ return I2C_RETRY; ++ } ++/* FIXME: handle arbitration... */ ++#if 0 ++ /* Check for bus arbitration loss */ ++ if (adap->arbitration_loss()){ ++ printk("Arbitration loss detected \n"); ++ adap->reset(); ++ return I2C_RETRY; ++ } ++#endif ++ ++ /* Read */ ++ if (pmsg->flags & I2C_M_RD) { ++ /* read bytes into buffer*/ ++ ret = i2c_pxa_readbytes(i2c_adap, pmsg->buf, pmsg->len, last); ++#if DEBUG > 2 ++ if (ret != pmsg->len) { ++ printk(KERN_INFO"i2c_pxa_do_xfer: read %d/%d bytes.\n", ++ ret, pmsg->len); ++ } else { ++ printk(KERN_INFO"i2c_pxa_do_xfer: read %d bytes.\n",ret); ++ } ++#endif ++ } else { /* Write */ ++ ret = i2c_pxa_sendbytes(i2c_adap, pmsg->buf, pmsg->len, last); ++#if DEBUG > 2 ++ if (ret != pmsg->len) { ++ printk(KERN_INFO"i2c_pxa_do_xfer: wrote %d/%d bytes.\n", ++ ret, pmsg->len); ++ } else { ++ printk(KERN_INFO"i2c_pxa_do_xfer: wrote %d bytes.\n",ret); ++ } ++#endif ++ } ++ } ++ ++ if (ret<0){ ++ return ret; ++ }else{ ++ return i; ++ } ++} ++ ++static int i2c_pxa_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) ++{ ++ int retval = i2c_pxa_valid_messages( msgs, num); ++ if( retval > 0) ++ { ++ int i; ++ for (i=i2c_adap->retries; i>=0; i--){ ++ int retval = i2c_pxa_do_xfer(i2c_adap,msgs,num); ++ if (retval!=I2C_RETRY){ ++ return retval; ++ } ++ if( i2c_debug)printk(KERN_INFO"Retrying transmission \n"); ++ udelay(100); ++ } ++ if( i2c_debug)printk(KERN_INFO"Retried %i times\n",i2c_adap->retries); ++ return -EREMOTEIO; ++ ++ } ++ return retval; ++} ++ ++static u32 i2c_pxa_functionality(struct i2c_adapter * adapter) ++{ ++ /* Emulate the SMBUS functions */ ++ return I2C_FUNC_SMBUS_EMUL; ++} ++ ++struct i2c_algorithm i2c_pxa_algorithm = { ++ name: "PXA I2C Algorithm", ++ id: I2C_ALGO_PXA, ++ master_xfer: i2c_pxa_xfer, ++ smbus_xfer: NULL, ++ slave_send: NULL, ++ slave_recv: NULL, ++ algo_control: NULL, ++ functionality: i2c_pxa_functionality, ++}; ++ ++/* ++ * registering functions to load algorithms at runtime ++ */ ++int i2c_pxa_add_bus(struct i2c_adapter *i2c_adap) ++{ ++ struct i2c_algo_pxa_data *adap = i2c_adap->algo_data; ++ ++ printk(KERN_INFO"I2C: Adding %s.\n", i2c_adap->dev.name); ++ ++ i2c_adap->algo = &i2c_pxa_algorithm; ++ ++ MOD_INC_USE_COUNT; ++ ++ /* register new adapter to i2c module... */ ++ i2c_add_adapter(i2c_adap); ++ ++ adap->reset(); ++ ++ /* scan bus */ ++ if (pxa_scan) { ++ int i; ++ printk(KERN_INFO "I2C: Scanning bus "); ++ for (i = 0x02; i < 0xff; i+=2) { ++ if( i==(I2C_PXA_SLAVE_ADDR<<1)) continue; ++ ++ if (adap->wait_bus_not_busy()) { ++ printk(KERN_INFO "I2C: scanning bus %s - TIMEOUT.\n", ++ i2c_adap->dev.name); ++ return -EIO; ++ } ++ adap->write_byte(i); ++ adap->start(); ++ adap->transfer(0, I2C_TRANSMIT, 0); ++ ++ if ((adap->wait_for_interrupt(I2C_TRANSMIT) != BUS_ERROR)) { ++ printk("(%02x)",i>>1); ++ adap->abort(); ++ } else { ++// printk("."); ++ adap->stop(); ++ } ++ udelay(adap->udelay); ++ } ++ printk("\n"); ++ } ++ return 0; ++} ++ ++int i2c_pxa_del_bus(struct i2c_adapter *i2c_adap) ++{ ++ int res; ++ if ((res = i2c_del_adapter(i2c_adap)) < 0) ++ return res; ++ ++ MOD_DEC_USE_COUNT; ++ ++ printk(KERN_INFO "I2C: Removing %s.\n", i2c_adap->dev.name); ++ ++ return 0; ++} ++ ++static int __init i2c_algo_pxa_init (void) ++{ ++ printk(KERN_INFO "I2C: PXA algorithm module loaded.\n"); ++ return 0; ++} ++ ++EXPORT_SYMBOL(i2c_pxa_add_bus); ++EXPORT_SYMBOL(i2c_pxa_del_bus); ++ ++MODULE_PARM(pxa_scan, "i"); ++MODULE_PARM_DESC(pxa_scan, "Scan for active chips on the bus"); ++ ++MODULE_AUTHOR("Intrinsyc Software Inc."); ++MODULE_LICENSE("GPL"); ++ ++module_init(i2c_algo_pxa_init); +--- linux-2.6.5/drivers/i2c/algos/Makefile~heh 2004-04-03 22:37:37.000000000 -0500 ++++ linux-2.6.5/drivers/i2c/algos/Makefile 2004-04-30 20:57:36.000000000 -0400 +@@ -4,6 +4,7 @@ + + obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o + obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o ++obj-$(CONFIG_I2C_ALGOPXA) += i2c-algo-pxa.o + obj-$(CONFIG_I2C_ALGOITE) += i2c-algo-ite.o + + ifeq ($(CONFIG_I2C_DEBUG_ALGO),y) +--- linux-2.6.5/Makefile~heh 2004-04-03 22:37:36.000000000 -0500 ++++ linux-2.6.5/Makefile 2004-04-30 20:57:58.000000000 -0400 +@@ -1,7 +1,7 @@ + VERSION = 2 + PATCHLEVEL = 6 + SUBLEVEL = 5 +-EXTRAVERSION = ++EXTRAVERSION = -gnalm1 + NAME=Zonked Quokka + + # *DOCUMENTATION* diff --git a/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.12/defconfig-ipaqpxa b/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.12/defconfig-ipaqpxa index e69de29bb2..9446168fdb 100644 --- a/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.12/defconfig-ipaqpxa +++ b/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.12/defconfig-ipaqpxa @@ -0,0 +1,1575 @@ +# +# Automatically generated make config: 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_PXA=y +# 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_S3C2410 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_AT91RM9200DK is not set +# CONFIG_MINIMAL_OOPS is not set + +# +# Linux As Bootldr support +# +# CONFIG_LAB is not set +# CONFIG_BIG_KERNEL is not set +# CONFIG_USE_DATE_CODE is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# 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_ADSBITSY 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_CONSUS 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_JORNADA56X 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_REGISTERS is not set + +# +# Intel PXA250/210 Implementations +# +# CONFIG_ARCH_LUBBOCK is not set +# CONFIG_ARCH_PXA_IDP is not set +# CONFIG_ARCH_PXA_CERF is not set +CONFIG_ARCH_H3900=y +CONFIG_ARCH_H1900=y +CONFIG_ARCH_H5400=y +# CONFIG_ARCH_H2200 is not set +CONFIG_ARCH_AXIM=y +CONFIG_PXA_USB=m +CONFIG_PXA_USB_NETLINK=m +CONFIG_PXA_USB_CHAR=m + +# +# 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_P720T is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set + +# +# Processor Type +# +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 is not set +# 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_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +CONFIG_CPU_32v5=y +CONFIG_CPU_XSCALE=y +CONFIG_XSCALE_PXA250=y +# CONFIG_XSCALE_80200_OLD is not set +# CONFIG_CPU_32v3 is not set +# CONFIG_CPU_32v4 is not set +# CONFIG_SA1100_IPAQ is not set +CONFIG_PXA_IPAQ=y +CONFIG_IPAQ_HANDHELD=y + +# +# Compaq iPAQ Handheld +# +CONFIG_IPAQ_HAL=m +# CONFIG_H3600_MICRO is not set +CONFIG_IPAQ_HAS_ROSELLA=y +CONFIG_H3600_ASIC=m +CONFIG_H3900_ASIC_DEBUG=m +CONFIG_H5400_ASIC=m +CONFIG_H1900_ASIC=m +CONFIG_H1900_TS=m +CONFIG_H3600_HARDWARE=y +CONFIG_IPAQ_SLEEVE=m +CONFIG_SLEEVE_DEBUG=y +CONFIG_SLEEVE_DEBUG_VERBOSE=0 +# CONFIG_SLEEVE_IRQ_DEMUX is not set + +# +# Dell Axim X5 +# +CONFIG_AXIM_HAL=m + +# +# Processor Features +# +# 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_CPU_FREQ=y +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +# CONFIG_PCMCIA_CLPS6700 is not set +# CONFIG_PCMCIA_SA1100 is not set +CONFIG_PCMCIA_PXA=m +# CONFIG_MERCURY_BACKPAQ is not set + +# +# MMC/SD Card support +# +CONFIG_MMC=m +CONFIG_MMC_DEBUG=y +CONFIG_MMC_DEBUG_VERBOSE=0 +CONFIG_MMC_SAMSUNG_ASIC=m +# CONFIG_MMC_S3C2410 is not set +CONFIG_MMC_H5400=m +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_XIP_KERNEL is not set + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# 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=y +CONFIG_APM=m +# CONFIG_HWTIMER is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="keepinitrd" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_CML1=m +# CONFIG_PARPORT_SERIAL is not set +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_ARC is not set +# CONFIG_PARPORT_IDP is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_SUNBPP is not set +# CONFIG_PARPORT_OTHER is not set +# CONFIG_PARPORT_1284 is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +CONFIG_MTD_DEBUG=y +CONFIG_MTD_DEBUG_VERBOSE=1 +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_CFI_B1 is not set +CONFIG_MTD_CFI_B2=y +CONFIG_MTD_CFI_B4=y +# CONFIG_MTD_CFI_B8 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# 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 +# 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_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_IPAQ=y +# 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_LUBBOCK is not set +# CONFIG_MTD_EPXA10DB is not set +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_AUTCPU12 is not set +# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_H720X 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_MTDRAM is not set +CONFIG_MTD_BLKMTD=m + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND 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_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +CONFIG_NVRD=m + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +# 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=m +CONFIG_BLK_DEV_DM=m + +# +# Networking options +# +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +# CONFIG_IP_NF_AMANDA is not set +# CONFIG_IP_NF_TFTP is not set +CONFIG_IP_NF_IRC=m +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_MAC=m +# CONFIG_IP_NF_MATCH_PKTTYPE is not set +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +# CONFIG_IP_NF_MATCH_RECENT is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_DSCP is not set +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +# CONFIG_IP_NF_MATCH_HELPER is not set +CONFIG_IP_NF_MATCH_STATE=m +# CONFIG_IP_NF_MATCH_CONNTRACK is not set +# CONFIG_IP_NF_MATCH_UNCLEAN is not set +# CONFIG_IP_NF_MATCH_OWNER is not set +CONFIG_IP_NF_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_MIRROR is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +# CONFIG_IP_NF_NAT_LOCAL is not set +# CONFIG_IP_NF_NAT_SNMP_BASIC is not set +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_DSCP is not set +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_ARPTABLES is not set +CONFIG_IP_NF_COMPAT_IPCHAINS=m +CONFIG_IP_NF_NAT_NEEDED=y +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IPV6=m +CONFIG_IPV6_SUBTREES=y +CONFIG_IPV6_IPV6_TUNNEL=m +CONFIG_IPV6_MOBILITY=m +CONFIG_IPV6_MOBILITY_MN=m +# CONFIG_IPV6_MOBILITY_HA is not set +CONFIG_IPV6_MOBILITY_DEBUG=y + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +CONFIG_IP6_NF_MATCH_MULTIPORT=m +# CONFIG_IP6_NF_MATCH_OWNER is not set +CONFIG_IP6_NF_MATCH_MARK=m +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_AHESP is not set +# CONFIG_IP6_NF_MATCH_LENGTH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +# CONFIG_KHTTPD 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=m +# 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 +CONFIG_IPSEC=m + +# +# IPSec options (FreeS/WAN) +# +CONFIG_IPSEC_IPIP=y +CONFIG_IPSEC_AH=y +CONFIG_IPSEC_AUTH_HMAC_MD5=y +CONFIG_IPSEC_AUTH_HMAC_SHA1=y +CONFIG_IPSEC_ESP=y +CONFIG_IPSEC_ENC_3DES=y +CONFIG_IPSEC_IPCOMP=y +CONFIG_IPSEC_DEBUG=y + +# +# 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=m +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K 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_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=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_MPPE=m +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_HERMES is not set +# CONFIG_SPECTRUM24T is not set + +# +# Wireless Pcmcia cards support +# +# CONFIG_PCMCIA_HERMES is not set +# CONFIG_AIRO_CS is not set +# CONFIG_WVLAN_CS is not set +# CONFIG_MWVLAN_CS is not set +# CONFIG_HOSTAP is not set +# CONFIG_HOSTAP_CS is not set +CONFIG_NET_WIRELESS=y +CONFIG_ATMELWLAN=y +CONFIG_ATMELWLAN_USB_503A_RFMD=m +CONFIG_ATMELWLAN_PCMCIA_502A=m +CONFIG_ATMELWLAN_PCMCIA_3COM=m +CONFIG_ATMELWLAN_PCMCIA_502AD=m +CONFIG_ATMELWLAN_PCMCIA_502AE=m +CONFIG_ATMELWLAN_PCMCIA_504=m + +# +# 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 + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_AXNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +CONFIG_NET_PCMCIA_RADIO=y +CONFIG_PCMCIA_RAYCS=m +CONFIG_PCMCIA_NETWAVE=m +CONFIG_PCMCIA_WAVELAN=m +# CONFIG_AIRONET4500_CS is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +CONFIG_IRDA_ULTRA=y + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_DEBUG=y + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m +CONFIG_IRPORT_SIR=m + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_NSC_FIR is not set +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +CONFIG_PXA_FIR=m + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=m + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=m +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# SCSI support +# +CONFIG_SCSI=m + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_SD_EXTRA_DEVS=40 +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +CONFIG_SCSI_PCMCIA=y +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC 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=m +CONFIG_INPUT_KEYBDEV=m +CONFIG_INPUT_MOUSEDEV=m +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_UINPUT=m + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +CONFIG_SERIAL_EXTENDED=y +# CONFIG_SERIAL_MANY_PORTS is not set +# CONFIG_SERIAL_SHARE_IRQ is not set +# CONFIG_SERIAL_DETECT_IRQ is not set +# CONFIG_SERIAL_MULTIPORT is not set +# CONFIG_HUB6 is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_S3C2410 is not set +# CONFIG_SERIAL_S3C2410_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_SIR_PXA is not set +# 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_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=32 +# CONFIG_PRINTER is not set +# CONFIG_PPDEV is not set +CONFIG_NEWTONKBD=m +# CONFIG_SA1100_PROFILER is not set + +# +# Compaq iPAQ H3600 support +# +CONFIG_TOUCHSCREEN_H3600=m +# CONFIG_H3600_BACKPAQ_FPGA is not set +# CONFIG_H3600_BACKPAQ_ACCEL is not set +# CONFIG_H3600_BACKPAQ_GASGAUGE is not set +# CONFIG_H3600_BACKPAQ_SRAM is not set +# CONFIG_H3600_BACKPAQ_AUDIO is not set +# CONFIG_H3600_STOWAWAY is not set +# CONFIG_H3800_MICROKBD is not set +# CONFIG_SA1100_LIRC is not set +CONFIG_H5400_BUZZER=m +CONFIG_H5400_FSI=m + +# +# I2C support +# +CONFIG_I2C=m +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_PXA_ALGO=m +CONFIG_I2C_PXA_ADAP=m +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_PROC=m +# CONFIG_I2C_DS1307 is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_S3C2410 is not set +# CONFIG_L3_SA1111 is not set +# CONFIG_L3_BACKPAQ is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# SPI support +# +# CONFIG_SPI is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=m +# CONFIG_PSMOUSE is not set +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +CONFIG_INPUT_SERIO=m +CONFIG_INPUT_SERPORT=m + +# +# Joysticks +# +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_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_PXA_WATCHDOG=m +# CONFIG_OMAHA_WATCHDOG is not set +# 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_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_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_PXA_RTC=m +CONFIG_PXA_RTC_HACK=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 +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +CONFIG_PCMCIA_SERIAL_CS=m +CONFIG_PCMCIA_MOBILISCAN_CS=m +# CONFIG_AXIM_TS is not set +CONFIG_AXIM_KEY=m +# CONFIG_AXIM_KEY_FIX is not set + +# +# Multimedia devices +# +CONFIG_MEDIA=m +CONFIG_VIDEO_DEV=m +CONFIG_V4L2_DEV=m + +# +# Video For Linux +# +CONFIG_VIDEO_PROC_FS=y +# CONFIG_I2C_PARPORT is not set + +# +# Video Adapters +# +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_BWQCAM is not set +# CONFIG_VIDEO_CQCAM is not set +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_USB=m +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_STRADIS is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_ZORAN_BUZ is not set +# CONFIG_VIDEO_ZORAN_DC10 is not set +# CONFIG_VIDEO_ZORAN_LML33 is not set +# CONFIG_VIDEO_ZR36120 is not set +# CONFIG_VIDEO_MEYE is not set +# CONFIG_VIDEO_CYBERPRO is not set +# CONFIG_VIDEO_H3600_BACKPAQ is not set +# CONFIG_VIDEO_HAWKEYE is not set + +# +# Video for Linux 2 (V4L2) +# +CONFIG_VIDEO_WINNOV_CS=m + +# +# Radio Adapters +# +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_GEMTEK_PCI is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_MAESTRO is not set +# CONFIG_RADIO_MIROPCM20 is not set +# CONFIG_RADIO_MIROPCM20_RDS is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=m +CONFIG_REISERFS_FS=m +# 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_BFS_FS is not set +CONFIG_EXT3_FS=m +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_UMSDOS_FS=m +CONFIG_VFAT_FS=m +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +CONFIG_CRAMFS=y +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=m +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS 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_DRIVERFS_FS is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=m +# 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 + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT 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=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Console drivers +# +CONFIG_PC_KEYMAP=y +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_ACORN is not set +# CONFIG_FB_ANAKIN is not set +# CONFIG_FB_CLPS711X is not set +# CONFIG_FB_S3C2410 is not set +# CONFIG_FB_SA1100 is not set +# CONFIG_FB_EPSON1356 is not set +# CONFIG_FB_MQ200 is not set +CONFIG_FB_PXA=y +# CONFIG_FB_PXA_8BPP is not set +CONFIG_FB_PXA_16BPP=y +CONFIG_FB_MQ1100=y +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +# CONFIG_FBCON_CFB8 is not set +CONFIG_FBCON_CFB16=y +# CONFIG_FBCON_CFB24 is not set +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +# CONFIG_FBCON_NO_LOGO is not set +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +CONFIG_SOUND_H3900_UDA1380=m +CONFIG_SOUND_H5400=m +CONFIG_SOUND_OSS=m +# CONFIG_SOUND_TRACEINIT is not set +# CONFIG_SOUND_DMAP is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_ADLIB is not set +# CONFIG_SOUND_ACI_MIXER is not set +# CONFIG_SOUND_CS4232 is not set +# CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_NM256 is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_PAS is not set +# CONFIG_PAS_JOYSTICK is not set +# CONFIG_SOUND_PSS is not set +# CONFIG_SOUND_SB is not set +# CONFIG_SOUND_AWE32_SYNTH is not set +# CONFIG_SOUND_WAVEFRONT is not set +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_YM3812 is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_YMFPCI is not set +# CONFIG_SOUND_YMFPCI_LEGACY is not set +# CONFIG_SOUND_UART6850 is not set +# CONFIG_SOUND_AEDSP16 is not set +# CONFIG_SOUND_VIDC is not set +# CONFIG_SOUND_WAVEARTIST is not set +CONFIG_SOUND_PXA_AC97=m +# CONFIG_SOUND_TVMIXER 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 +# CONFIG_MCP_UCB1400_TS is not set + +# +# Console Switches +# +# CONFIG_SWITCHES is not set + +# +# USB support +# +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +CONFIG_USB_OHCI=m +# CONFIG_USB_OHCI_SA1111 is not set +CONFIG_USB_OHCI_H5400=m +# CONFIG_USB_OHCI_S3C2410 is not set +# CONFIG_USB_SL811HS is not set + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=m +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_BLUETOOTH is not set +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +CONFIG_USB_PRINTER=m + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT=y +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_WACOM is not set + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +CONFIG_USB_IBMCAM=m +CONFIG_USB_OV511=m +CONFIG_USB_PWC=m +CONFIG_USB_SE401=m +CONFIG_USB_STV680=m +CONFIG_USB_VICAM=m +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DABUSB is not set + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +CONFIG_USB_CDCETHER=m +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# 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 + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_BRLVGER is not set + +# +# Linux As Bootldr Modules +# +# CONFIG_BIG_KERNEL is not set +# CONFIG_USE_DATE_CODE is not set +# CONFIG_YMODEM is not set +# CONFIG_LAB_DUMMY is not set +# CONFIG_LAB_CRC is not set +# CONFIG_LAB_YMODEM is not set +# CONFIG_LAB_MTD is not set +# CONFIG_LAB_COPY is not set +# CONFIG_LAB_COPY_YMODEM is not set +# CONFIG_LAB_COPY_FLASH is not set +# CONFIG_LAB_COPY_FS is not set +# CONFIG_LAB_COPY_WRAPPER is not set + +# +# Bluetooth support +# +CONFIG_BLUEZ=m +CONFIG_BLUEZ_L2CAP=m +CONFIG_BLUEZ_SCO=m +CONFIG_BLUEZ_RFCOMM=m +CONFIG_BLUEZ_RFCOMM_TTY=y +CONFIG_BLUEZ_BNEP=m +CONFIG_BLUEZ_BNEP_MC_FILTER=y +CONFIG_BLUEZ_BNEP_PROTO_FILTER=y + +# +# Bluetooth device drivers +# +# CONFIG_BLUEZ_HCIUSB is not set +CONFIG_BLUEZ_HCIUART=m +CONFIG_BLUEZ_HCIUART_H4=y +CONFIG_BLUEZ_HCIUART_BCSP=y +# CONFIG_BLUEZ_HCIUART_BCSP_TXCRC is not set +# CONFIG_BLUEZ_HCIBFUSB is not set +CONFIG_BLUEZ_HCIDTL1=m +CONFIG_BLUEZ_HCIBT3C=m +CONFIG_BLUEZ_HCIBLUECARD=m +CONFIG_BLUEZ_HCIBTUART=m +# CONFIG_BLUEZ_HCIVHCI is not set + +# +# Kernel hacking +# +# CONFIG_FRAME_POINTER is not set +# CONFIG_DEBUG_USER is not set +# 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=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +# CONFIG_CRC32 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.13/defconfig-ipaqpxa b/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.13/defconfig-ipaqpxa index e69de29bb2..681818f9ab 100644 --- a/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.13/defconfig-ipaqpxa +++ b/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.13/defconfig-ipaqpxa @@ -0,0 +1,1577 @@ +# +# Automatically generated make config: 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_PXA=y +# 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_S3C2410 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_AT91RM9200DK is not set +# CONFIG_MINIMAL_OOPS is not set + +# +# Linux As Bootldr support +# +# CONFIG_LAB is not set +# CONFIG_BIG_KERNEL is not set +# CONFIG_USE_DATE_CODE is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# 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_ADSBITSY 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_CONSUS 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_JORNADA56X 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_REGISTERS is not set + +# +# Intel PXA250/210 Implementations +# +# CONFIG_ARCH_LUBBOCK is not set +# CONFIG_ARCH_PXA_IDP is not set +# CONFIG_ARCH_PXA_CERF is not set +CONFIG_ARCH_H3900=y +CONFIG_ARCH_H1900=y +CONFIG_ARCH_H5400=y +# CONFIG_ARCH_H2200 is not set +CONFIG_ARCH_AXIM=y +CONFIG_PXA_USB=m +CONFIG_PXA_USB_NETLINK=m +CONFIG_PXA_USB_CHAR=m + +# +# 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_P720T is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set + +# +# Processor Type +# +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 is not set +# 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_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +CONFIG_CPU_32v5=y +CONFIG_CPU_XSCALE=y +CONFIG_XSCALE_PXA250=y +# CONFIG_XSCALE_80200_OLD is not set +# CONFIG_CPU_32v3 is not set +# CONFIG_CPU_32v4 is not set +# CONFIG_SA1100_IPAQ is not set +CONFIG_PXA_IPAQ=y +CONFIG_IPAQ_HANDHELD=y + +# +# Compaq iPAQ Handheld +# +CONFIG_IPAQ_HAL=m +# CONFIG_H3600_MICRO is not set +CONFIG_IPAQ_HAS_ROSELLA=y +CONFIG_IPAQ_HAS_ASIC3=y +CONFIG_H3600_ASIC=m +CONFIG_H3900_ASIC_DEBUG=m +CONFIG_H5400_ASIC=m +CONFIG_H1900_ASIC=m +CONFIG_H1900_TS=m +CONFIG_H3600_HARDWARE=y +CONFIG_IPAQ_SLEEVE=m +CONFIG_SLEEVE_DEBUG=y +CONFIG_SLEEVE_DEBUG_VERBOSE=0 +# CONFIG_SLEEVE_IRQ_DEMUX is not set + +# +# Dell Axim X5 +# +CONFIG_AXIM_HAL=m + +# +# Processor Features +# +# 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_CPU_FREQ=y +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +# CONFIG_PCMCIA_CLPS6700 is not set +# CONFIG_PCMCIA_SA1100 is not set +CONFIG_PCMCIA_PXA=m +# CONFIG_MERCURY_BACKPAQ is not set + +# +# MMC/SD Card support +# +CONFIG_MMC=m +CONFIG_MMC_DEBUG=y +CONFIG_MMC_DEBUG_VERBOSE=0 +CONFIG_MMC_SAMSUNG_ASIC=m +# CONFIG_MMC_S3C2410 is not set +CONFIG_MMC_H5400=m +CONFIG_MMC_ASIC3=m +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_XIP_KERNEL is not set + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# 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=y +CONFIG_APM=m +# CONFIG_HWTIMER is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="keepinitrd" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_CML1=m +# CONFIG_PARPORT_SERIAL is not set +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_ARC is not set +# CONFIG_PARPORT_IDP is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_SUNBPP is not set +# CONFIG_PARPORT_OTHER is not set +# CONFIG_PARPORT_1284 is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +CONFIG_MTD_DEBUG=y +CONFIG_MTD_DEBUG_VERBOSE=1 +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_CFI_B1 is not set +CONFIG_MTD_CFI_B2=y +CONFIG_MTD_CFI_B4=y +# CONFIG_MTD_CFI_B8 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# 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 +# 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_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_IPAQ=y +# 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_LUBBOCK is not set +# CONFIG_MTD_EPXA10DB is not set +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_AUTCPU12 is not set +# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_H720X 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_MTDRAM is not set +CONFIG_MTD_BLKMTD=m + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND 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_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +CONFIG_NVRD=m + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +# 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=m +CONFIG_BLK_DEV_DM=m + +# +# Networking options +# +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +# CONFIG_IP_NF_AMANDA is not set +# CONFIG_IP_NF_TFTP is not set +CONFIG_IP_NF_IRC=m +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_MAC=m +# CONFIG_IP_NF_MATCH_PKTTYPE is not set +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +# CONFIG_IP_NF_MATCH_RECENT is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_DSCP is not set +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +# CONFIG_IP_NF_MATCH_HELPER is not set +CONFIG_IP_NF_MATCH_STATE=m +# CONFIG_IP_NF_MATCH_CONNTRACK is not set +# CONFIG_IP_NF_MATCH_UNCLEAN is not set +# CONFIG_IP_NF_MATCH_OWNER is not set +CONFIG_IP_NF_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_MIRROR is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +# CONFIG_IP_NF_NAT_LOCAL is not set +# CONFIG_IP_NF_NAT_SNMP_BASIC is not set +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_DSCP is not set +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_ARPTABLES is not set +CONFIG_IP_NF_COMPAT_IPCHAINS=m +CONFIG_IP_NF_NAT_NEEDED=y +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IPV6=m +CONFIG_IPV6_SUBTREES=y +CONFIG_IPV6_IPV6_TUNNEL=m +CONFIG_IPV6_MOBILITY=m +CONFIG_IPV6_MOBILITY_MN=m +# CONFIG_IPV6_MOBILITY_HA is not set +CONFIG_IPV6_MOBILITY_DEBUG=y + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +CONFIG_IP6_NF_MATCH_MULTIPORT=m +# CONFIG_IP6_NF_MATCH_OWNER is not set +CONFIG_IP6_NF_MATCH_MARK=m +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_AHESP is not set +# CONFIG_IP6_NF_MATCH_LENGTH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +# CONFIG_KHTTPD 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=m +# 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 +CONFIG_IPSEC=m + +# +# IPSec options (FreeS/WAN) +# +CONFIG_IPSEC_IPIP=y +CONFIG_IPSEC_AH=y +CONFIG_IPSEC_AUTH_HMAC_MD5=y +CONFIG_IPSEC_AUTH_HMAC_SHA1=y +CONFIG_IPSEC_ESP=y +CONFIG_IPSEC_ENC_3DES=y +CONFIG_IPSEC_IPCOMP=y +CONFIG_IPSEC_DEBUG=y + +# +# 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=m +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K 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_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=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_MPPE=m +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_HERMES is not set +# CONFIG_SPECTRUM24T is not set + +# +# Wireless Pcmcia cards support +# +# CONFIG_PCMCIA_HERMES is not set +# CONFIG_AIRO_CS is not set +# CONFIG_WVLAN_CS is not set +# CONFIG_MWVLAN_CS is not set +# CONFIG_HOSTAP is not set +# CONFIG_HOSTAP_CS is not set +CONFIG_NET_WIRELESS=y +CONFIG_ATMELWLAN=y +CONFIG_ATMELWLAN_USB_503A_RFMD=m +CONFIG_ATMELWLAN_PCMCIA_502A=m +CONFIG_ATMELWLAN_PCMCIA_3COM=m +CONFIG_ATMELWLAN_PCMCIA_502AD=m +CONFIG_ATMELWLAN_PCMCIA_502AE=m +CONFIG_ATMELWLAN_PCMCIA_504=m + +# +# 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 + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_AXNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +CONFIG_NET_PCMCIA_RADIO=y +CONFIG_PCMCIA_RAYCS=m +CONFIG_PCMCIA_NETWAVE=m +CONFIG_PCMCIA_WAVELAN=m +# CONFIG_AIRONET4500_CS is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +CONFIG_IRDA_ULTRA=y + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_DEBUG=y + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m +CONFIG_IRPORT_SIR=m + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_NSC_FIR is not set +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +CONFIG_PXA_FIR=m + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=m + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=m +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# SCSI support +# +CONFIG_SCSI=m + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_SD_EXTRA_DEVS=40 +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +CONFIG_SCSI_PCMCIA=y +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC 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=m +CONFIG_INPUT_KEYBDEV=m +CONFIG_INPUT_MOUSEDEV=m +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_UINPUT=m + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +CONFIG_SERIAL_EXTENDED=y +# CONFIG_SERIAL_MANY_PORTS is not set +# CONFIG_SERIAL_SHARE_IRQ is not set +# CONFIG_SERIAL_DETECT_IRQ is not set +# CONFIG_SERIAL_MULTIPORT is not set +# CONFIG_HUB6 is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_S3C2410 is not set +# CONFIG_SERIAL_S3C2410_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_SIR_PXA is not set +# 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_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=32 +# CONFIG_PRINTER is not set +# CONFIG_PPDEV is not set +CONFIG_NEWTONKBD=m +# CONFIG_SA1100_PROFILER is not set + +# +# Compaq iPAQ H3600 support +# +CONFIG_TOUCHSCREEN_H3600=m +# CONFIG_H3600_BACKPAQ_FPGA is not set +# CONFIG_H3600_BACKPAQ_ACCEL is not set +# CONFIG_H3600_BACKPAQ_GASGAUGE is not set +# CONFIG_H3600_BACKPAQ_SRAM is not set +# CONFIG_H3600_BACKPAQ_AUDIO is not set +# CONFIG_H3600_STOWAWAY is not set +# CONFIG_H3800_MICROKBD is not set +# CONFIG_SA1100_LIRC is not set +CONFIG_H5400_BUZZER=m +CONFIG_H5400_FSI=m + +# +# I2C support +# +CONFIG_I2C=m +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_PXA_ALGO=m +CONFIG_I2C_PXA_ADAP=m +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_PROC=m +# CONFIG_I2C_DS1307 is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_S3C2410 is not set +# CONFIG_L3_SA1111 is not set +# CONFIG_L3_BACKPAQ is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# SPI support +# +# CONFIG_SPI is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=m +# CONFIG_PSMOUSE is not set +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +CONFIG_INPUT_SERIO=m +CONFIG_INPUT_SERPORT=m + +# +# Joysticks +# +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_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_PXA_WATCHDOG=m +# CONFIG_OMAHA_WATCHDOG is not set +# 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_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_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_PXA_RTC=m +CONFIG_PXA_RTC_HACK=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 +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +CONFIG_PCMCIA_SERIAL_CS=m +CONFIG_PCMCIA_MOBILISCAN_CS=m +# CONFIG_AXIM_TS is not set +CONFIG_AXIM_KEY=m +# CONFIG_AXIM_KEY_FIX is not set + +# +# Multimedia devices +# +CONFIG_MEDIA=m +CONFIG_VIDEO_DEV=m +CONFIG_V4L2_DEV=m + +# +# Video For Linux +# +CONFIG_VIDEO_PROC_FS=y +# CONFIG_I2C_PARPORT is not set + +# +# Video Adapters +# +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_BWQCAM is not set +# CONFIG_VIDEO_CQCAM is not set +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_USB=m +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_STRADIS is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_ZORAN_BUZ is not set +# CONFIG_VIDEO_ZORAN_DC10 is not set +# CONFIG_VIDEO_ZORAN_LML33 is not set +# CONFIG_VIDEO_ZR36120 is not set +# CONFIG_VIDEO_MEYE is not set +# CONFIG_VIDEO_CYBERPRO is not set +# CONFIG_VIDEO_H3600_BACKPAQ is not set +# CONFIG_VIDEO_HAWKEYE is not set + +# +# Video for Linux 2 (V4L2) +# +CONFIG_VIDEO_WINNOV_CS=m + +# +# Radio Adapters +# +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_GEMTEK_PCI is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_MAESTRO is not set +# CONFIG_RADIO_MIROPCM20 is not set +# CONFIG_RADIO_MIROPCM20_RDS is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=m +CONFIG_REISERFS_FS=m +# 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_BFS_FS is not set +CONFIG_EXT3_FS=m +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_UMSDOS_FS=m +CONFIG_VFAT_FS=m +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +CONFIG_CRAMFS=y +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=m +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS 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_DRIVERFS_FS is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=m +# 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 + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT 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=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Console drivers +# +CONFIG_PC_KEYMAP=y +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_ACORN is not set +# CONFIG_FB_ANAKIN is not set +# CONFIG_FB_CLPS711X is not set +# CONFIG_FB_S3C2410 is not set +# CONFIG_FB_SA1100 is not set +# CONFIG_FB_EPSON1356 is not set +# CONFIG_FB_MQ200 is not set +CONFIG_FB_PXA=y +# CONFIG_FB_PXA_8BPP is not set +CONFIG_FB_PXA_16BPP=y +CONFIG_FB_MQ1100=y +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +# CONFIG_FBCON_CFB8 is not set +CONFIG_FBCON_CFB16=y +# CONFIG_FBCON_CFB24 is not set +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +# CONFIG_FBCON_NO_LOGO is not set +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +CONFIG_SOUND_H3900_UDA1380=m +CONFIG_SOUND_H5400=m +CONFIG_SOUND_OSS=m +# CONFIG_SOUND_TRACEINIT is not set +# CONFIG_SOUND_DMAP is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_ADLIB is not set +# CONFIG_SOUND_ACI_MIXER is not set +# CONFIG_SOUND_CS4232 is not set +# CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_NM256 is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_PAS is not set +# CONFIG_PAS_JOYSTICK is not set +# CONFIG_SOUND_PSS is not set +# CONFIG_SOUND_SB is not set +# CONFIG_SOUND_AWE32_SYNTH is not set +# CONFIG_SOUND_WAVEFRONT is not set +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_YM3812 is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_YMFPCI is not set +# CONFIG_SOUND_YMFPCI_LEGACY is not set +# CONFIG_SOUND_UART6850 is not set +# CONFIG_SOUND_AEDSP16 is not set +# CONFIG_SOUND_VIDC is not set +# CONFIG_SOUND_WAVEARTIST is not set +CONFIG_SOUND_PXA_AC97=m +# CONFIG_SOUND_TVMIXER 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 +# CONFIG_MCP_UCB1400_TS is not set + +# +# Console Switches +# +# CONFIG_SWITCHES is not set + +# +# USB support +# +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +CONFIG_USB_OHCI=m +# CONFIG_USB_OHCI_SA1111 is not set +CONFIG_USB_OHCI_H5400=m +# CONFIG_USB_OHCI_S3C2410 is not set +# CONFIG_USB_SL811HS is not set + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=m +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_BLUETOOTH is not set +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +CONFIG_USB_PRINTER=m + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT=y +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_WACOM is not set + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +CONFIG_USB_IBMCAM=m +CONFIG_USB_OV511=m +CONFIG_USB_PWC=m +CONFIG_USB_SE401=m +CONFIG_USB_STV680=m +CONFIG_USB_VICAM=m +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DABUSB is not set + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +CONFIG_USB_CDCETHER=m +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# 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 + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_BRLVGER is not set + +# +# Linux As Bootldr Modules +# +# CONFIG_BIG_KERNEL is not set +# CONFIG_USE_DATE_CODE is not set +# CONFIG_YMODEM is not set +# CONFIG_LAB_DUMMY is not set +# CONFIG_LAB_CRC is not set +# CONFIG_LAB_YMODEM is not set +# CONFIG_LAB_MTD is not set +# CONFIG_LAB_COPY is not set +# CONFIG_LAB_COPY_YMODEM is not set +# CONFIG_LAB_COPY_FLASH is not set +# CONFIG_LAB_COPY_FS is not set +# CONFIG_LAB_COPY_WRAPPER is not set + +# +# Bluetooth support +# +CONFIG_BLUEZ=m +CONFIG_BLUEZ_L2CAP=m +CONFIG_BLUEZ_SCO=m +CONFIG_BLUEZ_RFCOMM=m +CONFIG_BLUEZ_RFCOMM_TTY=y +CONFIG_BLUEZ_BNEP=m +CONFIG_BLUEZ_BNEP_MC_FILTER=y +CONFIG_BLUEZ_BNEP_PROTO_FILTER=y + +# +# Bluetooth device drivers +# +# CONFIG_BLUEZ_HCIUSB is not set +CONFIG_BLUEZ_HCIUART=m +CONFIG_BLUEZ_HCIUART_H4=y +CONFIG_BLUEZ_HCIUART_BCSP=y +# CONFIG_BLUEZ_HCIUART_BCSP_TXCRC is not set +# CONFIG_BLUEZ_HCIBFUSB is not set +CONFIG_BLUEZ_HCIDTL1=m +CONFIG_BLUEZ_HCIBT3C=m +CONFIG_BLUEZ_HCIBLUECARD=m +CONFIG_BLUEZ_HCIBTUART=m +# CONFIG_BLUEZ_HCIVHCI is not set + +# +# Kernel hacking +# +# CONFIG_FRAME_POINTER is not set +# CONFIG_DEBUG_USER is not set +# 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=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +# CONFIG_CRC32 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.14/defconfig-ipaqpxa b/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.14/defconfig-ipaqpxa index e69de29bb2..fc9682743a 100644 --- a/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.14/defconfig-ipaqpxa +++ b/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.14/defconfig-ipaqpxa @@ -0,0 +1,1578 @@ +# +# Automatically generated make config: 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_PXA=y +# 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_S3C2410 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_AT91RM9200DK is not set +# CONFIG_MINIMAL_OOPS is not set + +# +# Linux As Bootldr support +# +# CONFIG_LAB is not set +# CONFIG_BIG_KERNEL is not set +# CONFIG_USE_DATE_CODE is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# 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_ADSBITSY 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_CONSUS 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_JORNADA56X 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_REGISTERS is not set + +# +# Intel PXA250/210 Implementations +# +# CONFIG_ARCH_LUBBOCK is not set +# CONFIG_ARCH_PXA_IDP is not set +# CONFIG_ARCH_PXA_CERF is not set +CONFIG_ARCH_H3900=y +CONFIG_ARCH_H1900=y +CONFIG_ARCH_H5400=y +# CONFIG_ARCH_H2200 is not set +CONFIG_ARCH_AXIM=y +CONFIG_PXA_USB=m +CONFIG_PXA_USB_NETLINK=m +CONFIG_PXA_USB_CHAR=m + +# +# 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_P720T is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set + +# +# Processor Type +# +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 is not set +# 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_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +CONFIG_CPU_32v5=y +CONFIG_CPU_XSCALE=y +CONFIG_XSCALE_PXA250=y +# CONFIG_XSCALE_80200_OLD is not set +# CONFIG_CPU_32v3 is not set +# CONFIG_CPU_32v4 is not set +# CONFIG_SA1100_IPAQ is not set +CONFIG_PXA_IPAQ=y +CONFIG_IPAQ_HANDHELD=y + +# +# Compaq iPAQ Handheld +# +CONFIG_IPAQ_HAL=m +# CONFIG_H3600_MICRO is not set +CONFIG_IPAQ_HAS_ROSELLA=y +CONFIG_IPAQ_HAS_ASIC3=y +CONFIG_H3600_ASIC=m +CONFIG_H3900_ASIC_DEBUG=m +CONFIG_H5400_ASIC=m +CONFIG_H1900_ASIC=m +CONFIG_H1900_TS=m +CONFIG_H3600_HARDWARE=y +CONFIG_IPAQ_SLEEVE=m +CONFIG_SLEEVE_DEBUG=y +CONFIG_SLEEVE_DEBUG_VERBOSE=0 +# CONFIG_SLEEVE_IRQ_DEMUX is not set + +# +# Dell Axim X5 +# +CONFIG_AXIM_HAL=m + +# +# Processor Features +# +# 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_CPU_FREQ=y +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +# CONFIG_PCMCIA_CLPS6700 is not set +# CONFIG_PCMCIA_SA1100 is not set +CONFIG_PCMCIA_PXA=m +# CONFIG_MERCURY_BACKPAQ is not set + +# +# MMC/SD Card support +# +CONFIG_MMC=m +CONFIG_MMC_DEBUG=y +CONFIG_MMC_DEBUG_VERBOSE=0 +CONFIG_MMC_SAMSUNG_ASIC=m +# CONFIG_MMC_S3C2410 is not set +CONFIG_MMC_H5400=m +CONFIG_MMC_ASIC3=m +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_XIP_KERNEL is not set + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# 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=y +CONFIG_APM=m +# CONFIG_HWTIMER is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="keepinitrd" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_CML1=m +# CONFIG_PARPORT_SERIAL is not set +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_ARC is not set +# CONFIG_PARPORT_IDP is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_SUNBPP is not set +# CONFIG_PARPORT_OTHER is not set +# CONFIG_PARPORT_1284 is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +CONFIG_MTD_DEBUG=y +CONFIG_MTD_DEBUG_VERBOSE=1 +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_CFI_B1 is not set +CONFIG_MTD_CFI_B2=y +CONFIG_MTD_CFI_B4=y +# CONFIG_MTD_CFI_B8 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# 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 +# 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_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_IPAQ=y +# 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_LUBBOCK is not set +# CONFIG_MTD_EPXA10DB is not set +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_AUTCPU12 is not set +# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_H720X 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_MTDRAM is not set +CONFIG_MTD_BLKMTD=m + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND 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_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +CONFIG_NVRD=m + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +# 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=m +CONFIG_BLK_DEV_DM=m + +# +# Networking options +# +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +# CONFIG_IP_NF_AMANDA is not set +# CONFIG_IP_NF_TFTP is not set +CONFIG_IP_NF_IRC=m +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_MAC=m +# CONFIG_IP_NF_MATCH_PKTTYPE is not set +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +# CONFIG_IP_NF_MATCH_RECENT is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_DSCP is not set +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +# CONFIG_IP_NF_MATCH_HELPER is not set +CONFIG_IP_NF_MATCH_STATE=m +# CONFIG_IP_NF_MATCH_CONNTRACK is not set +# CONFIG_IP_NF_MATCH_UNCLEAN is not set +# CONFIG_IP_NF_MATCH_OWNER is not set +CONFIG_IP_NF_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_MIRROR is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +# CONFIG_IP_NF_NAT_LOCAL is not set +# CONFIG_IP_NF_NAT_SNMP_BASIC is not set +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_DSCP is not set +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_ARPTABLES is not set +CONFIG_IP_NF_COMPAT_IPCHAINS=m +CONFIG_IP_NF_NAT_NEEDED=y +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IPV6=m +CONFIG_IPV6_SUBTREES=y +CONFIG_IPV6_IPV6_TUNNEL=m +CONFIG_IPV6_MOBILITY=m +CONFIG_IPV6_MOBILITY_MN=m +# CONFIG_IPV6_MOBILITY_HA is not set +CONFIG_IPV6_MOBILITY_DEBUG=y + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +CONFIG_IP6_NF_MATCH_MULTIPORT=m +# CONFIG_IP6_NF_MATCH_OWNER is not set +CONFIG_IP6_NF_MATCH_MARK=m +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_AHESP is not set +# CONFIG_IP6_NF_MATCH_LENGTH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +# CONFIG_KHTTPD 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=m +# 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 +CONFIG_IPSEC=m + +# +# IPSec options (FreeS/WAN) +# +CONFIG_KLIPS_AUTH_HMAC_MD5=y +CONFIG_KLIPS_AUTH_HMAC_SHA1=y +CONFIG_KLIPS_ENC_3DES=y + +# +# ESP always enabled with tunnel mode +# +CONFIG_KLIPS_IPCOMP=y +CONFIG_KLIPS_DEBUG=y + +# +# 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=m +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K 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_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=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_MPPE=m +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_HERMES is not set +# CONFIG_SPECTRUM24T is not set + +# +# Wireless Pcmcia cards support +# +# CONFIG_PCMCIA_HERMES is not set +# CONFIG_AIRO_CS is not set +# CONFIG_WVLAN_CS is not set +# CONFIG_MWVLAN_CS is not set +# CONFIG_HOSTAP is not set +# CONFIG_HOSTAP_CS is not set +CONFIG_NET_WIRELESS=y +CONFIG_ATMELWLAN=y +CONFIG_ATMELWLAN_USB_503A_RFMD=m +CONFIG_ATMELWLAN_PCMCIA_502A=m +CONFIG_ATMELWLAN_PCMCIA_3COM=m +CONFIG_ATMELWLAN_PCMCIA_502AD=m +CONFIG_ATMELWLAN_PCMCIA_502AE=m +CONFIG_ATMELWLAN_PCMCIA_504=m + +# +# 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 + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_AXNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +CONFIG_NET_PCMCIA_RADIO=y +CONFIG_PCMCIA_RAYCS=m +CONFIG_PCMCIA_NETWAVE=m +CONFIG_PCMCIA_WAVELAN=m +# CONFIG_AIRONET4500_CS is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +CONFIG_IRDA_ULTRA=y + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_DEBUG=y + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m +CONFIG_IRPORT_SIR=m + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_NSC_FIR is not set +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +CONFIG_PXA_FIR=m + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=m + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=m +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# SCSI support +# +CONFIG_SCSI=m + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_SD_EXTRA_DEVS=40 +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +CONFIG_SCSI_PCMCIA=y +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC 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=m +CONFIG_INPUT_KEYBDEV=m +CONFIG_INPUT_MOUSEDEV=m +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_UINPUT=m + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +CONFIG_SERIAL_EXTENDED=y +# CONFIG_SERIAL_MANY_PORTS is not set +# CONFIG_SERIAL_SHARE_IRQ is not set +# CONFIG_SERIAL_DETECT_IRQ is not set +# CONFIG_SERIAL_MULTIPORT is not set +# CONFIG_HUB6 is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_S3C2410 is not set +# CONFIG_SERIAL_S3C2410_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_SIR_PXA is not set +# 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_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=32 +# CONFIG_PRINTER is not set +# CONFIG_PPDEV is not set +CONFIG_NEWTONKBD=m +# CONFIG_SA1100_PROFILER is not set + +# +# Compaq iPAQ H3600 support +# +CONFIG_TOUCHSCREEN_H3600=m +# CONFIG_H3600_BACKPAQ_FPGA is not set +# CONFIG_H3600_BACKPAQ_ACCEL is not set +# CONFIG_H3600_BACKPAQ_GASGAUGE is not set +# CONFIG_H3600_BACKPAQ_SRAM is not set +# CONFIG_H3600_BACKPAQ_AUDIO is not set +# CONFIG_H3600_STOWAWAY is not set +# CONFIG_H3800_MICROKBD is not set +# CONFIG_SA1100_LIRC is not set +CONFIG_H5400_BUZZER=m +CONFIG_H5400_FSI=m + +# +# I2C support +# +CONFIG_I2C=m +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_PXA_ALGO=m +CONFIG_I2C_PXA_ADAP=m +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_PROC=m +# CONFIG_I2C_DS1307 is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_S3C2410 is not set +# CONFIG_L3_SA1111 is not set +# CONFIG_L3_BACKPAQ is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# SPI support +# +# CONFIG_SPI is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=m +# CONFIG_PSMOUSE is not set +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +CONFIG_INPUT_SERIO=m +CONFIG_INPUT_SERPORT=m + +# +# Joysticks +# +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_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_PXA_WATCHDOG=m +# CONFIG_OMAHA_WATCHDOG is not set +# 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_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_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_PXA_RTC=m +CONFIG_PXA_RTC_HACK=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 +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +CONFIG_PCMCIA_SERIAL_CS=m +CONFIG_PCMCIA_MOBILISCAN_CS=m +# CONFIG_AXIM_TS is not set +CONFIG_AXIM_KEY=m +# CONFIG_AXIM_KEY_FIX is not set + +# +# Multimedia devices +# +CONFIG_MEDIA=m +CONFIG_VIDEO_DEV=m +CONFIG_V4L2_DEV=m + +# +# Video For Linux +# +CONFIG_VIDEO_PROC_FS=y +# CONFIG_I2C_PARPORT is not set + +# +# Video Adapters +# +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_BWQCAM is not set +# CONFIG_VIDEO_CQCAM is not set +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_USB=m +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_STRADIS is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_ZORAN_BUZ is not set +# CONFIG_VIDEO_ZORAN_DC10 is not set +# CONFIG_VIDEO_ZORAN_LML33 is not set +# CONFIG_VIDEO_ZR36120 is not set +# CONFIG_VIDEO_MEYE is not set +# CONFIG_VIDEO_CYBERPRO is not set +# CONFIG_VIDEO_H3600_BACKPAQ is not set +# CONFIG_VIDEO_HAWKEYE is not set + +# +# Video for Linux 2 (V4L2) +# +CONFIG_VIDEO_WINNOV_CS=m + +# +# Radio Adapters +# +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_GEMTEK_PCI is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_MAESTRO is not set +# CONFIG_RADIO_MIROPCM20 is not set +# CONFIG_RADIO_MIROPCM20_RDS is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=m +CONFIG_REISERFS_FS=m +# 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_BFS_FS is not set +CONFIG_EXT3_FS=m +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_UMSDOS_FS=m +CONFIG_VFAT_FS=m +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +CONFIG_CRAMFS=y +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=m +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS 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_DRIVERFS_FS is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=m +# 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 + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT 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=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Console drivers +# +CONFIG_PC_KEYMAP=y +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_ACORN is not set +# CONFIG_FB_ANAKIN is not set +# CONFIG_FB_CLPS711X is not set +# CONFIG_FB_S3C2410 is not set +# CONFIG_FB_SA1100 is not set +# CONFIG_FB_EPSON1356 is not set +# CONFIG_FB_MQ200 is not set +CONFIG_FB_PXA=y +# CONFIG_FB_PXA_8BPP is not set +CONFIG_FB_PXA_16BPP=y +CONFIG_FB_MQ1100=y +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +# CONFIG_FBCON_CFB8 is not set +CONFIG_FBCON_CFB16=y +# CONFIG_FBCON_CFB24 is not set +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +# CONFIG_FBCON_NO_LOGO is not set +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +CONFIG_SOUND_H3900_UDA1380=m +CONFIG_SOUND_H5400=m +CONFIG_SOUND_OSS=m +# CONFIG_SOUND_TRACEINIT is not set +# CONFIG_SOUND_DMAP is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_ADLIB is not set +# CONFIG_SOUND_ACI_MIXER is not set +# CONFIG_SOUND_CS4232 is not set +# CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_NM256 is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_PAS is not set +# CONFIG_PAS_JOYSTICK is not set +# CONFIG_SOUND_PSS is not set +# CONFIG_SOUND_SB is not set +# CONFIG_SOUND_AWE32_SYNTH is not set +# CONFIG_SOUND_WAVEFRONT is not set +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_YM3812 is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_YMFPCI is not set +# CONFIG_SOUND_YMFPCI_LEGACY is not set +# CONFIG_SOUND_UART6850 is not set +# CONFIG_SOUND_AEDSP16 is not set +# CONFIG_SOUND_VIDC is not set +# CONFIG_SOUND_WAVEARTIST is not set +CONFIG_SOUND_PXA_AC97=m +# CONFIG_SOUND_TVMIXER 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 +# CONFIG_MCP_UCB1400_TS is not set + +# +# Console Switches +# +# CONFIG_SWITCHES is not set + +# +# USB support +# +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +CONFIG_USB_OHCI=m +# CONFIG_USB_OHCI_SA1111 is not set +CONFIG_USB_OHCI_H5400=m +# CONFIG_USB_OHCI_S3C2410 is not set +# CONFIG_USB_SL811HS is not set + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=m +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_BLUETOOTH is not set +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +CONFIG_USB_PRINTER=m + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT=y +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_WACOM is not set + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +CONFIG_USB_IBMCAM=m +CONFIG_USB_OV511=m +CONFIG_USB_PWC=m +CONFIG_USB_SE401=m +CONFIG_USB_STV680=m +CONFIG_USB_VICAM=m +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DABUSB is not set + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +CONFIG_USB_CDCETHER=m +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# 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 + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_BRLVGER is not set + +# +# Linux As Bootldr Modules +# +# CONFIG_BIG_KERNEL is not set +# CONFIG_USE_DATE_CODE is not set +# CONFIG_YMODEM is not set +# CONFIG_LAB_DUMMY is not set +# CONFIG_LAB_CRC is not set +# CONFIG_LAB_YMODEM is not set +# CONFIG_LAB_MTD is not set +# CONFIG_LAB_COPY is not set +# CONFIG_LAB_COPY_YMODEM is not set +# CONFIG_LAB_COPY_FLASH is not set +# CONFIG_LAB_COPY_FS is not set +# CONFIG_LAB_COPY_WRAPPER is not set + +# +# Bluetooth support +# +CONFIG_BLUEZ=m +CONFIG_BLUEZ_L2CAP=m +CONFIG_BLUEZ_SCO=m +CONFIG_BLUEZ_RFCOMM=m +CONFIG_BLUEZ_RFCOMM_TTY=y +CONFIG_BLUEZ_BNEP=m +CONFIG_BLUEZ_BNEP_MC_FILTER=y +CONFIG_BLUEZ_BNEP_PROTO_FILTER=y + +# +# Bluetooth device drivers +# +# CONFIG_BLUEZ_HCIUSB is not set +CONFIG_BLUEZ_HCIUART=m +CONFIG_BLUEZ_HCIUART_H4=y +CONFIG_BLUEZ_HCIUART_BCSP=y +# CONFIG_BLUEZ_HCIUART_BCSP_TXCRC is not set +# CONFIG_BLUEZ_HCIBFUSB is not set +CONFIG_BLUEZ_HCIDTL1=m +CONFIG_BLUEZ_HCIBT3C=m +CONFIG_BLUEZ_HCIBLUECARD=m +CONFIG_BLUEZ_HCIBTUART=m +# CONFIG_BLUEZ_HCIVHCI is not set + +# +# Kernel hacking +# +# CONFIG_FRAME_POINTER is not set +# CONFIG_DEBUG_USER is not set +# 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=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +# CONFIG_CRC32 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh37.1/defconfig-ipaqpxa b/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh37.1/defconfig-ipaqpxa index e69de29bb2..ee30cf0a42 100644 --- a/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh37.1/defconfig-ipaqpxa +++ b/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh37.1/defconfig-ipaqpxa @@ -0,0 +1,1578 @@ +# +# Automatically generated make config: 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_PXA=y +# 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_S3C2410 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_AT91RM9200DK is not set +# CONFIG_MINIMAL_OOPS is not set + +# +# Linux As Bootldr support +# +# CONFIG_LAB is not set +# CONFIG_BIG_KERNEL is not set +# CONFIG_USE_DATE_CODE is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# 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_ADSBITSY 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_CONSUS 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_JORNADA56X 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_REGISTERS is not set + +# +# Intel PXA250/210 Implementations +# +# CONFIG_ARCH_LUBBOCK is not set +# CONFIG_ARCH_PXA_IDP is not set +# CONFIG_ARCH_PXA_CERF is not set +CONFIG_ARCH_H3900=y +CONFIG_ARCH_H1900=y +CONFIG_ARCH_H5400=y +# CONFIG_ARCH_H2200 is not set +CONFIG_ARCH_AXIM=y +CONFIG_PXA_USB=m +CONFIG_PXA_USB_NETLINK=m +CONFIG_PXA_USB_CHAR=m + +# +# 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_P720T is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set + +# +# Processor Type +# +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 is not set +# 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_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +CONFIG_CPU_32v5=y +CONFIG_CPU_XSCALE=y +CONFIG_XSCALE_PXA250=y +# CONFIG_XSCALE_80200_OLD is not set +# CONFIG_CPU_32v3 is not set +# CONFIG_CPU_32v4 is not set +# CONFIG_SA1100_IPAQ is not set +CONFIG_PXA_IPAQ=y +CONFIG_IPAQ_HANDHELD=y + +# +# Compaq iPAQ Handheld +# +CONFIG_IPAQ_HAL=m +# CONFIG_H3600_MICRO is not set +CONFIG_IPAQ_HAS_ROSELLA=y +CONFIG_IPAQ_HAS_ASIC3=y +CONFIG_H3600_ASIC=m +CONFIG_H3900_ASIC_DEBUG=m +CONFIG_H5400_ASIC=m +CONFIG_H1900_ASIC=m +CONFIG_H1900_TS=m +CONFIG_H3600_HARDWARE=y +CONFIG_IPAQ_SLEEVE=m +CONFIG_SLEEVE_DEBUG=y +CONFIG_SLEEVE_DEBUG_VERBOSE=0 +# CONFIG_SLEEVE_IRQ_DEMUX is not set + +# +# Dell Axim X5 +# +CONFIG_AXIM_HAL=m + +# +# Processor Features +# +# 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_CPU_FREQ=y +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +# CONFIG_PCMCIA_CLPS6700 is not set +# CONFIG_PCMCIA_SA1100 is not set +CONFIG_PCMCIA_PXA=m +# CONFIG_MERCURY_BACKPAQ is not set + +# +# MMC/SD Card support +# +CONFIG_MMC=m +CONFIG_MMC_DEBUG=y +CONFIG_MMC_DEBUG_VERBOSE=0 +CONFIG_MMC_SAMSUNG_ASIC=m +# CONFIG_MMC_S3C2410 is not set +CONFIG_MMC_H5400=m +CONFIG_MMC_ASIC3=m +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_XIP_KERNEL is not set + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# 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=y +CONFIG_APM=m +# CONFIG_HWTIMER is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="keepinitrd" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_CML1=m +# CONFIG_PARPORT_SERIAL is not set +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_PC_PCMCIA=m +# CONFIG_PARPORT_ARC is not set +# CONFIG_PARPORT_IDP is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_SUNBPP is not set +# CONFIG_PARPORT_OTHER is not set +# CONFIG_PARPORT_1284 is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +CONFIG_MTD_DEBUG=y +CONFIG_MTD_DEBUG_VERBOSE=1 +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=m +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_CFI_B1 is not set +CONFIG_MTD_CFI_B2=y +CONFIG_MTD_CFI_B4=y +# CONFIG_MTD_CFI_B8 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# 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 +# 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_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_IPAQ=y +# 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_LUBBOCK is not set +# CONFIG_MTD_EPXA10DB is not set +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_AUTCPU12 is not set +# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_H720X 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_MTDRAM is not set +CONFIG_MTD_BLKMTD=m + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND 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_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +CONFIG_NVRD=m + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +# 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=m +CONFIG_BLK_DEV_DM=m + +# +# Networking options +# +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +# CONFIG_IP_NF_AMANDA is not set +# CONFIG_IP_NF_TFTP is not set +CONFIG_IP_NF_IRC=m +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_MAC=m +# CONFIG_IP_NF_MATCH_PKTTYPE is not set +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +# CONFIG_IP_NF_MATCH_RECENT is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_DSCP is not set +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +# CONFIG_IP_NF_MATCH_HELPER is not set +CONFIG_IP_NF_MATCH_STATE=m +# CONFIG_IP_NF_MATCH_CONNTRACK is not set +# CONFIG_IP_NF_MATCH_UNCLEAN is not set +# CONFIG_IP_NF_MATCH_OWNER is not set +CONFIG_IP_NF_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_MIRROR is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +# CONFIG_IP_NF_NAT_LOCAL is not set +# CONFIG_IP_NF_NAT_SNMP_BASIC is not set +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_DSCP is not set +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_ARPTABLES is not set +CONFIG_IP_NF_COMPAT_IPCHAINS=m +CONFIG_IP_NF_NAT_NEEDED=y +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IPV6=m +CONFIG_IPV6_SUBTREES=y +CONFIG_IPV6_TUNNEL=m +CONFIG_IPV6_MOBILITY=m +CONFIG_IPV6_MOBILITY_MN=m +# CONFIG_IPV6_MOBILITY_HA is not set +CONFIG_IPV6_MOBILITY_DEBUG=y + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +CONFIG_IP6_NF_MATCH_MULTIPORT=m +# CONFIG_IP6_NF_MATCH_OWNER is not set +CONFIG_IP6_NF_MATCH_MARK=m +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_AHESP is not set +# CONFIG_IP6_NF_MATCH_LENGTH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +# CONFIG_KHTTPD 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=m +# 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 +CONFIG_IPSEC=m + +# +# IPSec options (FreeS/WAN) +# +CONFIG_KLIPS_AUTH_HMAC_MD5=y +CONFIG_KLIPS_AUTH_HMAC_SHA1=y +CONFIG_KLIPS_ENC_3DES=y + +# +# ESP always enabled with tunnel mode +# +CONFIG_KLIPS_IPCOMP=y +CONFIG_KLIPS_DEBUG=y + +# +# 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=m +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K 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_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=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_MPPE=m +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_HERMES is not set +# CONFIG_SPECTRUM24T is not set + +# +# Wireless Pcmcia cards support +# +# CONFIG_PCMCIA_HERMES is not set +# CONFIG_AIRO_CS is not set +# CONFIG_WVLAN_CS is not set +# CONFIG_MWVLAN_CS is not set +# CONFIG_HOSTAP is not set +# CONFIG_HOSTAP_CS is not set +CONFIG_NET_WIRELESS=y +CONFIG_ATMELWLAN=y +CONFIG_ATMELWLAN_USB_503A_RFMD=m +CONFIG_ATMELWLAN_PCMCIA_502A=m +CONFIG_ATMELWLAN_PCMCIA_3COM=m +CONFIG_ATMELWLAN_PCMCIA_502AD=m +CONFIG_ATMELWLAN_PCMCIA_502AE=m +CONFIG_ATMELWLAN_PCMCIA_504=m + +# +# 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 + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_AXNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +CONFIG_NET_PCMCIA_RADIO=y +CONFIG_PCMCIA_RAYCS=m +CONFIG_PCMCIA_NETWAVE=m +CONFIG_PCMCIA_WAVELAN=m +# CONFIG_AIRONET4500_CS is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +CONFIG_IRDA_ULTRA=y + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_DEBUG=y + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m +CONFIG_IRPORT_SIR=m + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_NSC_FIR is not set +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +CONFIG_PXA_FIR=m + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=m + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=m +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# SCSI support +# +CONFIG_SCSI=m + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_SD_EXTRA_DEVS=40 +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +CONFIG_SCSI_PCMCIA=y +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC 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=m +CONFIG_INPUT_KEYBDEV=m +CONFIG_INPUT_MOUSEDEV=m +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_UINPUT=m + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +CONFIG_SERIAL_EXTENDED=y +# CONFIG_SERIAL_MANY_PORTS is not set +# CONFIG_SERIAL_SHARE_IRQ is not set +# CONFIG_SERIAL_DETECT_IRQ is not set +# CONFIG_SERIAL_MULTIPORT is not set +# CONFIG_HUB6 is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_S3C2410 is not set +# CONFIG_SERIAL_S3C2410_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_SIR_PXA is not set +# 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_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=32 +# CONFIG_PRINTER is not set +# CONFIG_PPDEV is not set +CONFIG_NEWTONKBD=m +# CONFIG_SA1100_PROFILER is not set + +# +# Compaq iPAQ H3600 support +# +CONFIG_TOUCHSCREEN_H3600=m +# CONFIG_H3600_BACKPAQ_FPGA is not set +# CONFIG_H3600_BACKPAQ_ACCEL is not set +# CONFIG_H3600_BACKPAQ_GASGAUGE is not set +# CONFIG_H3600_BACKPAQ_SRAM is not set +# CONFIG_H3600_BACKPAQ_AUDIO is not set +# CONFIG_H3600_STOWAWAY is not set +# CONFIG_H3800_MICROKBD is not set +# CONFIG_SA1100_LIRC is not set +CONFIG_H5400_BUZZER=m +CONFIG_H5400_FSI=m + +# +# I2C support +# +CONFIG_I2C=m +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_PXA_ALGO=m +CONFIG_I2C_PXA_ADAP=m +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_PROC=m +# CONFIG_I2C_DS1307 is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_S3C2410 is not set +# CONFIG_L3_SA1111 is not set +# CONFIG_L3_BACKPAQ is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# SPI support +# +# CONFIG_SPI is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=m +# CONFIG_PSMOUSE is not set +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +CONFIG_INPUT_SERIO=m +CONFIG_INPUT_SERPORT=m + +# +# Joysticks +# +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_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_PXA_WATCHDOG=m +# CONFIG_OMAHA_WATCHDOG is not set +# 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_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_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_PXA_RTC=m +CONFIG_PXA_RTC_HACK=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 +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +CONFIG_PCMCIA_SERIAL_CS=m +CONFIG_PCMCIA_MOBILISCAN_CS=m +# CONFIG_AXIM_TS is not set +CONFIG_AXIM_KEY=m +# CONFIG_AXIM_KEY_FIX is not set + +# +# Multimedia devices +# +CONFIG_MEDIA=m +CONFIG_VIDEO_DEV=m +CONFIG_V4L2_DEV=m + +# +# Video For Linux +# +CONFIG_VIDEO_PROC_FS=y +# CONFIG_I2C_PARPORT is not set + +# +# Video Adapters +# +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_BWQCAM is not set +# CONFIG_VIDEO_CQCAM is not set +CONFIG_VIDEO_CPIA=m +CONFIG_VIDEO_CPIA_USB=m +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_STRADIS is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_ZORAN_BUZ is not set +# CONFIG_VIDEO_ZORAN_DC10 is not set +# CONFIG_VIDEO_ZORAN_LML33 is not set +# CONFIG_VIDEO_ZR36120 is not set +# CONFIG_VIDEO_MEYE is not set +# CONFIG_VIDEO_CYBERPRO is not set +# CONFIG_VIDEO_H3600_BACKPAQ is not set +# CONFIG_VIDEO_HAWKEYE is not set + +# +# Video for Linux 2 (V4L2) +# +CONFIG_VIDEO_WINNOV_CS=m + +# +# Radio Adapters +# +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_GEMTEK_PCI is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_MAESTRO is not set +# CONFIG_RADIO_MIROPCM20 is not set +# CONFIG_RADIO_MIROPCM20_RDS is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=m +CONFIG_REISERFS_FS=m +# 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_BFS_FS is not set +CONFIG_EXT3_FS=m +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_UMSDOS_FS=m +CONFIG_VFAT_FS=m +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +CONFIG_CRAMFS=y +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=m +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS 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_DRIVERFS_FS is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=m +# 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 + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT 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=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Console drivers +# +CONFIG_PC_KEYMAP=y +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_ACORN is not set +# CONFIG_FB_ANAKIN is not set +# CONFIG_FB_CLPS711X is not set +# CONFIG_FB_S3C2410 is not set +# CONFIG_FB_SA1100 is not set +# CONFIG_FB_EPSON1356 is not set +# CONFIG_FB_MQ200 is not set +CONFIG_FB_PXA=y +# CONFIG_FB_PXA_8BPP is not set +CONFIG_FB_PXA_16BPP=y +CONFIG_FB_MQ1100=y +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +# CONFIG_FBCON_CFB8 is not set +CONFIG_FBCON_CFB16=y +# CONFIG_FBCON_CFB24 is not set +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +# CONFIG_FBCON_NO_LOGO is not set +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +CONFIG_SOUND_H3900_UDA1380=m +CONFIG_SOUND_H5400=m +CONFIG_SOUND_OSS=m +# CONFIG_SOUND_TRACEINIT is not set +# CONFIG_SOUND_DMAP is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_ADLIB is not set +# CONFIG_SOUND_ACI_MIXER is not set +# CONFIG_SOUND_CS4232 is not set +# CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_NM256 is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_PAS is not set +# CONFIG_PAS_JOYSTICK is not set +# CONFIG_SOUND_PSS is not set +# CONFIG_SOUND_SB is not set +# CONFIG_SOUND_AWE32_SYNTH is not set +# CONFIG_SOUND_WAVEFRONT is not set +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_YM3812 is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_YMFPCI is not set +# CONFIG_SOUND_YMFPCI_LEGACY is not set +# CONFIG_SOUND_UART6850 is not set +# CONFIG_SOUND_AEDSP16 is not set +# CONFIG_SOUND_VIDC is not set +# CONFIG_SOUND_WAVEARTIST is not set +CONFIG_SOUND_PXA_AC97=m +# CONFIG_SOUND_TVMIXER 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 +# CONFIG_MCP_UCB1400_TS is not set + +# +# Console Switches +# +# CONFIG_SWITCHES is not set + +# +# USB support +# +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_UHCI is not set +# CONFIG_USB_UHCI_ALT is not set +CONFIG_USB_OHCI=m +# CONFIG_USB_OHCI_SA1111 is not set +CONFIG_USB_OHCI_H5400=m +# CONFIG_USB_OHCI_S3C2410 is not set +# CONFIG_USB_SL811HS is not set + +# +# USB Device Class drivers +# +CONFIG_USB_AUDIO=m +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_BLUETOOTH is not set +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +CONFIG_USB_PRINTER=m + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT=y +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_WACOM is not set + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +CONFIG_USB_IBMCAM=m +CONFIG_USB_OV511=m +CONFIG_USB_PWC=m +CONFIG_USB_SE401=m +CONFIG_USB_STV680=m +CONFIG_USB_VICAM=m +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DABUSB is not set + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +CONFIG_USB_CDCETHER=m +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# 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 + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_BRLVGER is not set + +# +# Linux As Bootldr Modules +# +# CONFIG_BIG_KERNEL is not set +# CONFIG_USE_DATE_CODE is not set +# CONFIG_YMODEM is not set +# CONFIG_LAB_DUMMY is not set +# CONFIG_LAB_CRC is not set +# CONFIG_LAB_YMODEM is not set +# CONFIG_LAB_MTD is not set +# CONFIG_LAB_COPY is not set +# CONFIG_LAB_COPY_YMODEM is not set +# CONFIG_LAB_COPY_FLASH is not set +# CONFIG_LAB_COPY_FS is not set +# CONFIG_LAB_COPY_WRAPPER is not set + +# +# Bluetooth support +# +CONFIG_BLUEZ=m +CONFIG_BLUEZ_L2CAP=m +CONFIG_BLUEZ_SCO=m +CONFIG_BLUEZ_RFCOMM=m +CONFIG_BLUEZ_RFCOMM_TTY=y +CONFIG_BLUEZ_BNEP=m +CONFIG_BLUEZ_BNEP_MC_FILTER=y +CONFIG_BLUEZ_BNEP_PROTO_FILTER=y + +# +# Bluetooth device drivers +# +# CONFIG_BLUEZ_HCIUSB is not set +CONFIG_BLUEZ_HCIUART=m +CONFIG_BLUEZ_HCIUART_H4=y +CONFIG_BLUEZ_HCIUART_BCSP=y +# CONFIG_BLUEZ_HCIUART_BCSP_TXCRC is not set +# CONFIG_BLUEZ_HCIBFUSB is not set +CONFIG_BLUEZ_HCIDTL1=m +CONFIG_BLUEZ_HCIBT3C=m +CONFIG_BLUEZ_HCIBLUECARD=m +CONFIG_BLUEZ_HCIBTUART=m +# CONFIG_BLUEZ_HCIVHCI is not set + +# +# Kernel hacking +# +# CONFIG_FRAME_POINTER is not set +# CONFIG_DEBUG_USER is not set +# 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=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +# CONFIG_CRC32 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/linux/handhelds-pxa-2.6/defconfig-ipaq-pxa-2.6 b/linux/handhelds-pxa-2.6/defconfig-ipaq-pxa-2.6 index e69de29bb2..0a7d4a6694 100644 --- a/linux/handhelds-pxa-2.6/defconfig-ipaq-pxa-2.6 +++ b/linux/handhelds-pxa-2.6/defconfig-ipaq-pxa-2.6 @@ -0,0 +1,1304 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_CLEAN_COMPILE is not set +CONFIG_STANDALONE=y +CONFIG_BROKEN=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_HOTPLUG=y +CONFIG_IKCONFIG=y +# CONFIG_MINIMAL_OOPS is not set +CONFIG_IKCONFIG_PROC=y +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_IOSCHED_CFQ is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +CONFIG_ARCH_PXA=y +# 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_IOP3XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_VERSATILE_PB is not set + +# +# Intel PXA250/210 Implementations +# +# CONFIG_ARCH_LUBBOCK is not set +# CONFIG_ARCH_PXA_IDP is not set +# CONFIG_ARCH_H1900 is not set +CONFIG_ARCH_H2200=y +CONFIG_H2200_PCMCIA=m +CONFIG_H2200_LCD=m +# CONFIG_H2200_BATTERY is not set +CONFIG_H2200_TS=m +CONFIG_ARCH_H3900=y +CONFIG_MACH_H4000=y +CONFIG_ARCH_H5400=y +CONFIG_ARCH_AXIMX5=y +# CONFIG_AXIMX5_MISC is not set +# CONFIG_AXIMX5_LCD is not set +# CONFIG_AXIMX5_PCMCIA is not set +# CONFIG_AXIMX5_BUTTONS is not set +# CONFIG_ARCH_AXIMX3 is not set +CONFIG_MACH_E740=y +CONFIG_MACH_E750=y +CONFIG_MACH_E800=y +CONFIG_ARCH_ESERIES=y +# CONFIG_ARCH_ROVERP5P is not set + +# +# S3C2410 Implementations +# + +# +# Linux As Bootloader +# +# CONFIG_LAB is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_XSCALE=y +CONFIG_CPU_XSCALE_PXA250=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5T=y +CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_MINICACHE=y + +# +# Processor Features +# +# CONFIG_ARM_FASTCALL is not set +CONFIG_ARM_THUMB=y +CONFIG_XSCALE_PMU=y + +# +# Compaq/iPAQ Options +# +CONFIG_PXA_IPAQ=y + +# +# XScale-based iPAQ +# +CONFIG_IPAQ_HANDHELD=y +CONFIG_IPAQ_SLEEVE=m +CONFIG_IPAQ_ASIC2=m +CONFIG_IPAQ_ASIC2_TOUCHSCREEN=m +CONFIG_IPAQ_ASIC3=m +CONFIG_IPAQ_H3900_LCD=m +CONFIG_IPAQ_H4000_LCD=m +CONFIG_IPAQ_SAMCOP=m +CONFIG_IPAQ_SAMCOP_ADC=m +CONFIG_IPAQ_SAMCOP_TOUCHSCREEN=m +CONFIG_IPAQ_SHAMCOP=m +CONFIG_IPAQ_SHAMCOP_ADC=m +CONFIG_IPAQ_SHAMCOP_TOUCHSCREEN=m +CONFIG_IPAQ_SHAMCOP_NAND=m +CONFIG_IPAQ_H5400_LCD=m +CONFIG_IPAQ_H5400_WIFI=m + +# +# General setup +# +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +# CONFIG_CPU_FREQ is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_TCIC is not set +CONFIG_PCMCIA_PXA2XX=m + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set +CONFIG_SOC_DEVICE=m +# CONFIG_DOCKING_HOTPLUG is not set +# CONFIG_DEBUG_DRIVER is not set +CONFIG_PM=y +# CONFIG_PREEMPT is not set +# CONFIG_APM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="keepinitrd" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +CONFIG_MTD_DEBUG=y +CONFIG_MTD_DEBUG_VERBOSE=1 +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_CONCAT=m +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_CFI_B1 is not set +CONFIG_MTD_CFI_B2=y +CONFIG_MTD_CFI_B4=y +# CONFIG_MTD_CFI_B8 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_IPAQ=y +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_EDB7312 is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +CONFIG_MTD_NAND=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_H1900 is not set +CONFIG_MTD_NAND_IDS=m + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=m +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +CONFIG_NET_KEY=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +CONFIG_IPV6=m +# CONFIG_IPV6_PRIVACY is not set +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_TUNNEL=m +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +# CONFIG_IP_NF_TFTP is not set +# CONFIG_IP_NF_AMANDA is not set +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +# CONFIG_IP_NF_MATCH_IPRANGE is not set +CONFIG_IP_NF_MATCH_MAC=m +# CONFIG_IP_NF_MATCH_PKTTYPE is not set +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +# CONFIG_IP_NF_MATCH_RECENT is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_DSCP is not set +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +# CONFIG_IP_NF_MATCH_HELPER is not set +CONFIG_IP_NF_MATCH_STATE=m +# CONFIG_IP_NF_MATCH_CONNTRACK is not set +# CONFIG_IP_NF_MATCH_OWNER is not set +# CONFIG_IP_NF_MATCH_PHYSDEV is not set +CONFIG_IP_NF_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_SAME is not set +# CONFIG_IP_NF_NAT_LOCAL is not set +# CONFIG_IP_NF_NAT_SNMP_BASIC is not set +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_DSCP is not set +CONFIG_IP_NF_TARGET_MARK=m +# CONFIG_IP_NF_TARGET_CLASSIFY is not set +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_ARPTABLES is not set +CONFIG_IP_NF_COMPAT_IPCHAINS=m +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +# CONFIG_IP_NF_RAW is not set + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +CONFIG_IP6_NF_MATCH_MULTIPORT=m +# CONFIG_IP6_NF_MATCH_OWNER is not set +CONFIG_IP6_NF_MATCH_MARK=m +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_AHESP is not set +# CONFIG_IP6_NF_MATCH_LENGTH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +# CONFIG_IP6_NF_RAW is not set + +# +# Bridge: Netfilter Configuration +# +# CONFIG_BRIDGE_NF_EBTABLES is not set +CONFIG_XFRM=y +CONFIG_XFRM_USER=m + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +CONFIG_BRIDGE=m +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB 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 +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +CONFIG_IRDA_ULTRA=y + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_DEBUG=y + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# Old SIR device drivers +# +CONFIG_IRPORT_SIR=m + +# +# Old Serial dongle support +# +# CONFIG_DONGLE_OLD is not set + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_SIGMATEL_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +CONFIG_BT=m +# CONFIG_BT_L2CAP is not set +# CONFIG_BT_SCO is not set + +# +# Bluetooth device drivers +# +# CONFIG_BT_HCIUSB is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIDTL1 is not set +# CONFIG_BT_HCIBT3C is not set +# CONFIG_BT_HCIBLUECARD is not set +# CONFIG_BT_HCIBTUART is not set +# CONFIG_BT_HCIVHCI is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +CONFIG_TUN=m + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set +CONFIG_MII=m +# CONFIG_SMC91X is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y + +# +# Obsolete Wireless cards support (pre-802.11) +# +# CONFIG_STRIP is not set +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_NETWAVE=m + +# +# Wireless 802.11 Frequency Hopping cards support +# +CONFIG_PCMCIA_RAYCS=m + +# +# Wireless 802.11b ISA/PCI cards support +# +CONFIG_HERMES=m +# CONFIG_ATMEL is not set + +# +# Wireless 802.11b Pcmcia/Cardbus cards support +# +CONFIG_PCMCIA_HERMES=m +CONFIG_AIRO_CS=m +# CONFIG_PCMCIA_WL3501 is not set +CONFIG_NET_WIRELESS=y +# CONFIG_HOSTAP is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_AXNET=m + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=m +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=m +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=m +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_REPORT_LUNS=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_TSDEV=m +CONFIG_INPUT_TSDEV_SCREEN_X=240 +CONFIG_INPUT_TSDEV_SCREEN_Y=320 +CONFIG_INPUT_TSLIBDEV=m +CONFIG_INPUT_EVDEV=m +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=m +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=m +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +CONFIG_KEYBOARD_NEWTON=m +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_DZ is not set +CONFIG_SERIAL_PXA=y +CONFIG_SERIAL_PXA_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_PXA_JTAG is not set +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# I2C support +# +CONFIG_I2C=m +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPXA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ELV is not set +# CONFIG_I2C_ISA is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PXA is not set +# CONFIG_SCx200_ACB is not set + +# +# Hardware Sensors Chip support +# +# CONFIG_I2C_SENSOR is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# L3 serial bus support +# +CONFIG_L3=m + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# 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 +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_RAW_DRIVER is not set + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# + +# +# Video Adapters +# +CONFIG_VIDEO_CPIA=m +# CONFIG_VIDEO_CPIA_USB is not set +# CONFIG_VIDEO_SAA5246A is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set + +# +# Radio Adapters +# +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_MAESTRO is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=m +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=m + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS 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_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_NAND=y +CONFIG_CRAMFS=m +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V4 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_SUNRPC=m +# CONFIG_RPCSEC_GSS_KRB5 is not set +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set + +# +# Native Language Support +# +CONFIG_NLS=m +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +CONFIG_FB=y +CONFIG_FB_MODES=y +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_DEVICE=y +CONFIG_BACKLIGHT_CLASS_DEVICE=m +CONFIG_BACKLIGHT_DEVICE=y +# CONFIG_FB_VSFB is not set +CONFIG_FB_MQ1100=m +CONFIG_FB_PXA=m +# CONFIG_FB_PXA_8BPP is not set +CONFIG_FB_PXA_16BPP=y +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=m +CONFIG_PCI_CONSOLE=y +CONFIG_FONTS=y +# CONFIG_FONT_8x8 is not set +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +CONFIG_FONT_MINI_4x6=y +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set + +# +# Logo configuration +# +# CONFIG_LOGO is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Misc devices +# + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set + +# +# Console Switches +# +CONFIG_SWITCHES=m + +# +# SoC drivers +# +CONFIG_SOC_MQ11XX=m +# CONFIG_BATTERY_MONITOR is not set + +# +# USB support +# +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811HS is not set +# CONFIG_USB_SL811HS_ALT is not set + +# +# USB Device Class drivers +# + +# +# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_STORAGE is not set + +# +# USB Human Interface Devices (HID) +# +# CONFIG_USB_HID is not set + +# +# USB HID Boot Protocol drivers +# +# 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_MTOUCH is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set +# CONFIG_USB_VICAM is not set +# CONFIG_USB_DSBR is not set +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_KONICAWC is not set +# CONFIG_USB_OV511 is not set +# CONFIG_USB_PWC is not set +# CONFIG_USB_SE401 is not set +# CONFIG_USB_STV680 is not set +# CONFIG_USB_W9968CF is not set + +# +# USB Network adaptors +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_TIGL is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_TEST is not set + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=y + +# +# USB Device Controller drivers +# +CONFIG_USB_GADGET_PXA2XX=m +CONFIG_USB_PXA2XX=y +CONFIG_USB_PXA2XX_SMALL=y +CONFIG_USB_GADGET_MQ11XX=m +CONFIG_USB_MQ11XX=y +# CONFIG_USB_GADGET_DUMMY_HCD is not set +# CONFIG_USB_GADGET_DUALSPEED is not set + +# +# USB Gadget Drivers +# +CONFIG_USB_ZERO=m +CONFIG_USB_ETH=m +# CONFIG_USB_ETH_RNDIS is not set +# CONFIG_USB_GADGETFS is not set +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_G_CHAR is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_LL_PXA_JTAG is not set +# 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=y +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +# CONFIG_CRYPTO_TEST is not set + +# +# Library routines +# +CONFIG_CRC32=m +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/linux/handhelds-pxa-2.6/defconfig-ipaq-pxa-2.6_2.6.8.1-hh0 b/linux/handhelds-pxa-2.6/defconfig-ipaq-pxa-2.6_2.6.8.1-hh0 index e69de29bb2..8d03220347 100644 --- a/linux/handhelds-pxa-2.6/defconfig-ipaq-pxa-2.6_2.6.8.1-hh0 +++ b/linux/handhelds-pxa-2.6/defconfig-ipaq-pxa-2.6_2.6.8.1-hh0 @@ -0,0 +1,1382 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_CLEAN_COMPILE is not set +CONFIG_BROKEN=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_HOTPLUG=y +CONFIG_IKCONFIG=y +# CONFIG_MINIMAL_OOPS is not set +CONFIG_IKCONFIG_PROC=y +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_IOSCHED_CFQ is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# 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_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_L7200 is not set +CONFIG_ARCH_PXA=y +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE_PB is not set + +# +# Intel PXA2xx Implementations +# +CONFIG_PXA25x=y +# CONFIG_PXA27x is not set +# CONFIG_ARCH_LUBBOCK is not set +# CONFIG_MACH_MAINSTONE is not set +# CONFIG_ARCH_PXA_IDP is not set +CONFIG_ARCH_ESERIES=y +CONFIG_MACH_E740=y +CONFIG_MACH_E750=y +CONFIG_MACH_E800=y +CONFIG_ESERIES_TMIO=y +CONFIG_OHCI_TMIO=y +CONFIG_MTD_NAND_TMIO=y +CONFIG_ESERIES_UDC=y +# CONFIG_E740_PCMCIA is not set +# CONFIG_E750_PCMCIA is not set +# CONFIG_E800_PCMCIA is not set +CONFIG_MACH_A620=y +CONFIG_A620_LCD=m +CONFIG_A620_BUTTONS=m +CONFIG_ARCH_H1900=y +CONFIG_ARCH_H2200=y +CONFIG_H2200_PCMCIA=m +CONFIG_H2200_LCD=m +# CONFIG_H2200_BATTERY is not set +CONFIG_H2200_TS=m +CONFIG_H2200_AUDIO=m +CONFIG_ARCH_H3900=y +CONFIG_MACH_H4000=y +CONFIG_ARCH_H5400=y +# CONFIG_ARCH_AXIMX5 is not set +# CONFIG_ARCH_AXIMX3 is not set +CONFIG_ARCH_ROVERP1=y +CONFIG_ARCH_ROVERP5P=y +CONFIG_ROVERP5P_LCD=m +CONFIG_ROVERP5P_PCMCIA=m + +# +# Linux As Bootloader +# +# CONFIG_LAB is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_XSCALE=y +CONFIG_CPU_XSCALE_PXA250=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5T=y +CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_MINICACHE=y + +# +# Processor Features +# +# CONFIG_ARM_FASTCALL is not set +CONFIG_ARM_THUMB=y +CONFIG_XSCALE_PMU=y + +# +# Compaq/iPAQ Options +# +CONFIG_PXA_IPAQ=y + +# +# XScale-based iPAQ +# +CONFIG_IPAQ_HANDHELD=y +# CONFIG_IPAQ_SLEEVE is not set +CONFIG_IPAQ_ASIC2=m +CONFIG_IPAQ_ASIC2_TOUCHSCREEN=m +CONFIG_IPAQ_ASIC3=m +# CONFIG_IPAQ_H1900_LCD is not set +# CONFIG_IPAQ_H3900_LCD is not set +CONFIG_IPAQ_H4000_LCD=m +CONFIG_IPAQ_SAMCOP=m +CONFIG_IPAQ_SAMCOP_ADC=m +CONFIG_IPAQ_SAMCOP_TOUCHSCREEN=m +CONFIG_IPAQ_SHAMCOP=m +CONFIG_IPAQ_SHAMCOP_ADC=m +CONFIG_IPAQ_SHAMCOP_TOUCHSCREEN=m +CONFIG_IPAQ_SHAMCOP_NAND=m +CONFIG_IPAQ_H5400_LCD=m +CONFIG_IPAQ_H5400_WIFI=m + +# +# General setup +# +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +# CONFIG_CPU_FREQ is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_TCIC is not set +CONFIG_PCMCIA_PXA2XX=m + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +# CONFIG_VFP is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +CONFIG_SOC_DEVICE=m +# CONFIG_DOCKING_HOTPLUG is not set +# CONFIG_DEBUG_DRIVER is not set +CONFIG_PM=y +# CONFIG_PREEMPT is not set +# CONFIG_APM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="keepinitrd" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +CONFIG_MTD_DEBUG=y +CONFIG_MTD_DEBUG_VERBOSE=1 +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_CONCAT=m +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_IPAQ=y +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_EDB7312 is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +CONFIG_MTD_NAND=m +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_H1900 is not set +CONFIG_MTD_NAND_IDS=m +# CONFIG_MTD_NAND_DISKONCHIP is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=m +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +CONFIG_NET_KEY=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +CONFIG_IPV6=m +# CONFIG_IPV6_PRIVACY is not set +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_TUNNEL=m +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_BRIDGE_NETFILTER=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +# CONFIG_IP_NF_TFTP is not set +# CONFIG_IP_NF_AMANDA is not set +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +# CONFIG_IP_NF_MATCH_IPRANGE is not set +CONFIG_IP_NF_MATCH_MAC=m +# CONFIG_IP_NF_MATCH_PKTTYPE is not set +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +# CONFIG_IP_NF_MATCH_RECENT is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_DSCP is not set +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +# CONFIG_IP_NF_MATCH_HELPER is not set +CONFIG_IP_NF_MATCH_STATE=m +# CONFIG_IP_NF_MATCH_CONNTRACK is not set +# CONFIG_IP_NF_MATCH_OWNER is not set +# CONFIG_IP_NF_MATCH_PHYSDEV is not set +CONFIG_IP_NF_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_SAME is not set +# CONFIG_IP_NF_NAT_LOCAL is not set +# CONFIG_IP_NF_NAT_SNMP_BASIC is not set +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_DSCP is not set +CONFIG_IP_NF_TARGET_MARK=m +# CONFIG_IP_NF_TARGET_CLASSIFY is not set +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_ARPTABLES is not set +CONFIG_IP_NF_COMPAT_IPCHAINS=m +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_MATCH_ADDRTYPE is not set +# CONFIG_IP_NF_MATCH_REALM is not set + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +CONFIG_IP6_NF_MATCH_MULTIPORT=m +# CONFIG_IP6_NF_MATCH_OWNER is not set +CONFIG_IP6_NF_MATCH_MARK=m +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_AHESP is not set +# CONFIG_IP6_NF_MATCH_LENGTH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +# CONFIG_IP6_NF_RAW is not set + +# +# Bridge: Netfilter Configuration +# +# CONFIG_BRIDGE_NF_EBTABLES is not set +CONFIG_XFRM=y +CONFIG_XFRM_USER=m + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +CONFIG_BRIDGE=m +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +CONFIG_IRDA_ULTRA=y + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_DEBUG=y + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# Old SIR device drivers +# +CONFIG_IRPORT_SIR=m + +# +# Old Serial dongle support +# +# CONFIG_DONGLE_OLD is not set + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_SIGMATEL_FIR is not set +CONFIG_BT=m +# CONFIG_BT_L2CAP is not set +# CONFIG_BT_SCO is not set + +# +# Bluetooth device drivers +# +# CONFIG_BT_HCIUSB is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIDTL1 is not set +# CONFIG_BT_HCIBT3C is not set +# CONFIG_BT_HCIBLUECARD is not set +# CONFIG_BT_HCIBTUART is not set +# CONFIG_BT_HCIVHCI is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +CONFIG_TUN=m + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set +CONFIG_MII=m + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y + +# +# Obsolete Wireless cards support (pre-802.11) +# +# CONFIG_STRIP is not set +CONFIG_PCMCIA_WAVELAN=m +CONFIG_PCMCIA_NETWAVE=m + +# +# Wireless 802.11 Frequency Hopping cards support +# +CONFIG_PCMCIA_RAYCS=m + +# +# Wireless 802.11b ISA/PCI cards support +# +CONFIG_HERMES=m +# CONFIG_ATMEL is not set + +# +# Wireless 802.11b Pcmcia/Cardbus cards support +# +CONFIG_PCMCIA_HERMES=m +CONFIG_AIRO_CS=m +# CONFIG_PCMCIA_WL3501 is not set +CONFIG_NET_WIRELESS=y +# CONFIG_HOSTAP is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +CONFIG_PCMCIA_AXNET=m + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_PPP=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=m +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=m +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=m +# CONFIG_IDE_ARM is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +CONFIG_SCSI=m +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_SYM53C500 is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_TSDEV=m +CONFIG_INPUT_TSDEV_SCREEN_X=240 +CONFIG_INPUT_TSDEV_SCREEN_Y=320 +CONFIG_INPUT_TSLIBDEV=m +CONFIG_INPUT_EVDEV=m +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=m +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=m +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +CONFIG_KEYBOARD_NEWTON=m +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_DZ is not set +CONFIG_SERIAL_PXA=y +CONFIG_SERIAL_PXA_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# I2C support +# +CONFIG_I2C=m +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_ALGOPXA=m + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ELV is not set +# CONFIG_I2C_ISA is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +CONFIG_I2C_PXA=m +# CONFIG_SCx200_ACB is not set + +# +# Hardware Sensors Chip support +# +# CONFIG_I2C_SENSOR is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +CONFIG_I2C_DEBUG_CORE=y +CONFIG_I2C_DEBUG_ALGO=y +CONFIG_I2C_DEBUG_BUS=y +CONFIG_I2C_DEBUG_CHIP=y + +# +# L3 serial bus support +# +CONFIG_L3=m + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_SA1100_WATCHDOG is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_RAW_DRIVER is not set + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# + +# +# Video Adapters +# +CONFIG_VIDEO_CPIA=m +# CONFIG_VIDEO_CPIA_USB is not set +# CONFIG_VIDEO_SAA5246A is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_OVCAMCHIP is not set + +# +# Radio Adapters +# +# CONFIG_RADIO_MAESTRO is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_REISERFS_FS_XATTR is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=m +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=m + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS 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_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=m +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_JFFS2_FS_NAND=y +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_CRAMFS=m +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V4 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=m +CONFIG_SUNRPC=m +# CONFIG_RPCSEC_GSS_KRB5 is not set +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=m +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +CONFIG_FB=y +CONFIG_FB_MODES=y +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_LCD_DEVICE=y +CONFIG_BACKLIGHT_CLASS_DEVICE=m +CONFIG_BACKLIGHT_DEVICE=y +# CONFIG_FB_VSFB is not set +CONFIG_FB_MQ1100=m +CONFIG_FB_PXA=m +# CONFIG_FB_PXA_PARAMETERS is not set +# CONFIG_FB_PXA_8BPP is not set +CONFIG_FB_PXA_16BPP=y +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=m +CONFIG_FONTS=y +# CONFIG_FONT_8x8 is not set +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +CONFIG_FONT_MINI_4x6=y +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set + +# +# Logo configuration +# +# CONFIG_LOGO is not set + +# +# Sound +# +CONFIG_SOUND=m + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=m +CONFIG_SND_TIMER=m +CONFIG_SND_PCM=m +# CONFIG_SND_SEQUENCER is not set +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_VERBOSE_PRINTK=y +CONFIG_SND_DEBUG=y +CONFIG_SND_DEBUG_MEMORY=y +CONFIG_SND_DEBUG_DETECT=y + +# +# Generic devices +# +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set + +# +# ALSA ARM devices +# +CONFIG_SND_PXA2XX_UDA1380=m +# CONFIG_SND_H5XXX_AK4535 is not set +# CONFIG_SND_PXA_AC97 is not set + +# +# ALSA USB devices +# +# CONFIG_SND_USB_AUDIO is not set + +# +# PCMCIA devices +# + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set +# CONFIG_SOUND_UDA1341 is not set + +# +# Misc devices +# + +# +# SoC drivers +# +CONFIG_SOC_MQ11XX=m +# CONFIG_BATTERY_MONITOR is not set + +# +# USB support +# +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811HS is not set +# CONFIG_USB_SL811HS_ALT is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set + +# +# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem +# +# CONFIG_USB_MIDI is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_STORAGE is not set + +# +# USB Human Interface Devices (HID) +# +# CONFIG_USB_HID is not set + +# +# USB HID Boot Protocol drivers +# +# 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_MTOUCH is not set +# CONFIG_USB_EGALAX is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set +# CONFIG_USB_VICAM is not set +# CONFIG_USB_DSBR is not set +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_KONICAWC is not set +# CONFIG_USB_OV511 is not set +# CONFIG_USB_PWC is not set +# CONFIG_USB_SE401 is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_STV680 is not set + +# +# USB Network adaptors +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_TIGL is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_TEST is not set + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=m +# CONFIG_USB_GADGET_NET2280 is not set +CONFIG_USB_GADGET_PXA2XX=y +CONFIG_USB_PXA2XX=m +# CONFIG_USB_PXA2XX_SMALL is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_SA1100 is not set +# CONFIG_USB_GADGET_MQ11XX is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +# CONFIG_USB_GADGET_DUALSPEED is not set +CONFIG_USB_ZERO=m +CONFIG_USB_ETH=m +# CONFIG_USB_ETH_RNDIS is not set +# CONFIG_USB_GADGETFS is not set +CONFIG_USB_FILE_STORAGE=m +# CONFIG_USB_FILE_STORAGE_TEST is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_G_CHAR is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_LL_PXA_JTAG is not set +# 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=y +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_ARC4=m +# CONFIG_CRYPTO_KHAZAD is not set +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +# CONFIG_CRYPTO_TEST is not set + +# +# Library routines +# +CONFIG_CRC_CCITT=m +CONFIG_CRC32=m +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/defconfig-ipaqsa b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/defconfig-ipaqsa index e69de29bb2..f144aa6c17 100644 --- a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/defconfig-ipaqsa +++ b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/defconfig-ipaqsa @@ -0,0 +1,1505 @@ +# +# Automatically generated make config: 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_PXA 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_S3C2410 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=y +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_AT91RM9200DK is not set +# CONFIG_MINIMAL_OOPS is not set + +# +# Linux As Bootldr support +# +# CONFIG_LAB is not set +# CONFIG_BIG_KERNEL is not set +# CONFIG_USE_DATE_CODE is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# 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_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CEP is not set +# CONFIG_SA1100_CERF is not set +CONFIG_SA1100_H3100=y +CONFIG_SA1100_H3600=y +CONFIG_SA1100_H3800=y +# CONFIG_SA1100_CONSUS 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_JORNADA56X 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=m +CONFIG_SA1100_USB_NETLINK=m +CONFIG_SA1100_USB_CHAR=m +CONFIG_REGISTERS=m + +# +# Intel PXA250/210 Implementations +# +# CONFIG_ARCH_LUBBOCK is not set +# CONFIG_ARCH_PXA_IDP is not set +# CONFIG_ARCH_PXA_CERF is not set +# CONFIG_ARCH_H3900 is not set +# CONFIG_ARCH_H1900 is not set +# CONFIG_ARCH_H5400 is not set +# CONFIG_ARCH_H2200 is not set +# CONFIG_ARCH_AXIM is not set +# CONFIG_PXA_USB is not set +# CONFIG_PXA_USB_NETLINK is not set +# CONFIG_PXA_USB_CHAR is not set + +# +# 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_P720T is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set + +# +# Processor Type +# +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 is not set +# 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_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +CONFIG_CPU_SA1100=y +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y +CONFIG_SA1100_IPAQ=y +# CONFIG_PXA_IPAQ is not set +CONFIG_IPAQ_HANDHELD=y + +# +# Compaq iPAQ Handheld +# +CONFIG_IPAQ_HAL=m +CONFIG_H3600_MICRO=m +CONFIG_IPAQ_HAS_ROSELLA=y +CONFIG_H3600_ASIC=m +CONFIG_H3900_ASIC_DEBUG=y +# CONFIG_H5400_ASIC is not set +# CONFIG_H1900_ASIC is not set +# CONFIG_H1900_TS is not set +CONFIG_H3600_HARDWARE=y +CONFIG_IPAQ_SLEEVE=m +CONFIG_SLEEVE_DEBUG=y +CONFIG_SLEEVE_DEBUG_VERBOSE=0 +# CONFIG_SLEEVE_IRQ_DEMUX is not set + +# +# Processor Features +# +CONFIG_DISCONTIGMEM=y + +# +# General setup +# +# CONFIG_PCI is not set +CONFIG_ISA=y +# CONFIG_ISA_DMA is not set +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_CPU_FREQ=y +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +# CONFIG_PCMCIA_CLPS6700 is not set +CONFIG_PCMCIA_SA1100=m +# CONFIG_PCMCIA_PXA is not set +CONFIG_MERCURY_BACKPAQ=m + +# +# MMC/SD Card support +# +CONFIG_MMC=m +CONFIG_MMC_DEBUG=y +CONFIG_MMC_DEBUG_VERBOSE=0 +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# 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=y +CONFIG_APM=m +CONFIG_HWTIMER=m +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="keepinitrd" +# 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=y +CONFIG_MTD_DEBUG_VERBOSE=1 +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_CFI_B1 is not set +CONFIG_MTD_CFI_B2=y +CONFIG_MTD_CFI_B4=y +# CONFIG_MTD_CFI_B8 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# 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 +# 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_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_IPAQ=y +# 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_LUBBOCK is not set +# CONFIG_MTD_EPXA10DB is not set +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_AUTCPU12 is not set +# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_H720X 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_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTD_BLKMTD=m + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND 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_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +CONFIG_NVRD=m + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +# 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=m +CONFIG_BLK_DEV_DM=m + +# +# Networking options +# +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +# CONFIG_IP_NF_AMANDA is not set +# CONFIG_IP_NF_TFTP is not set +CONFIG_IP_NF_IRC=m +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_MAC=m +# CONFIG_IP_NF_MATCH_PKTTYPE is not set +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +# CONFIG_IP_NF_MATCH_RECENT is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_DSCP is not set +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +# CONFIG_IP_NF_MATCH_HELPER is not set +CONFIG_IP_NF_MATCH_STATE=m +# CONFIG_IP_NF_MATCH_CONNTRACK is not set +# CONFIG_IP_NF_MATCH_UNCLEAN is not set +# CONFIG_IP_NF_MATCH_OWNER is not set +CONFIG_IP_NF_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_MIRROR is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +# CONFIG_IP_NF_NAT_LOCAL is not set +# CONFIG_IP_NF_NAT_SNMP_BASIC is not set +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_DSCP is not set +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_ARPTABLES is not set +CONFIG_IP_NF_COMPAT_IPCHAINS=m +CONFIG_IP_NF_NAT_NEEDED=y +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IPV6=m +CONFIG_IPV6_SUBTREES=y +CONFIG_IPV6_IPV6_TUNNEL=m +CONFIG_IPV6_MOBILITY=m +CONFIG_IPV6_MOBILITY_MN=m +# CONFIG_IPV6_MOBILITY_HA is not set +CONFIG_IPV6_MOBILITY_DEBUG=y + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +CONFIG_IP6_NF_MATCH_MULTIPORT=m +# CONFIG_IP6_NF_MATCH_OWNER is not set +CONFIG_IP6_NF_MATCH_MARK=m +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_AHESP is not set +# CONFIG_IP6_NF_MATCH_LENGTH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +# CONFIG_KHTTPD 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=m +# 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 +CONFIG_IPSEC=m + +# +# IPSec options (FreeS/WAN) +# +CONFIG_IPSEC_IPIP=y +CONFIG_IPSEC_AH=y +CONFIG_IPSEC_AUTH_HMAC_MD5=y +CONFIG_IPSEC_AUTH_HMAC_SHA1=y +CONFIG_IPSEC_ESP=y +CONFIG_IPSEC_ENC_3DES=y +CONFIG_IPSEC_IPCOMP=y +CONFIG_IPSEC_DEBUG=y + +# +# 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=m +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K 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_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=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPP_MPPE is not set +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_HERMES is not set +# CONFIG_SPECTRUM24T is not set + +# +# Wireless Pcmcia cards support +# +# CONFIG_PCMCIA_HERMES is not set +# CONFIG_AIRO_CS is not set +# CONFIG_WVLAN_CS is not set +# CONFIG_MWVLAN_CS is not set +# CONFIG_HOSTAP is not set +# CONFIG_HOSTAP_CS is not set +CONFIG_NET_WIRELESS=y +CONFIG_ATMELWLAN=y +# CONFIG_ATMELWLAN_USB_503A_RFMD is not set +CONFIG_ATMELWLAN_PCMCIA_502A=m +CONFIG_ATMELWLAN_PCMCIA_3COM=m +CONFIG_ATMELWLAN_PCMCIA_502AD=m +CONFIG_ATMELWLAN_PCMCIA_502AE=m +CONFIG_ATMELWLAN_PCMCIA_504=m + +# +# 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 + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_AXNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +CONFIG_NET_PCMCIA_RADIO=y +CONFIG_PCMCIA_RAYCS=m +CONFIG_PCMCIA_NETWAVE=m +CONFIG_PCMCIA_WAVELAN=m +# CONFIG_AIRONET4500_CS is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +CONFIG_IRDA_ULTRA=y + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_DEBUG=y + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m +CONFIG_IRPORT_SIR=m + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_NSC_FIR is not set +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +CONFIG_SA1100_FIR=m + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=m + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=m +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# SCSI support +# +CONFIG_SCSI=m + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_SD_EXTRA_DEVS=40 +CONFIG_CHR_DEV_ST=m +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +CONFIG_SCSI_PCMCIA=y +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC 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=m +CONFIG_INPUT_KEYBDEV=m +CONFIG_INPUT_MOUSEDEV=m +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_UINPUT=m + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=m +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_S3C2410 is not set +# CONFIG_SERIAL_S3C2410_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=y +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_SA1100_DEFAULT_BAUDRATE=115200 +CONFIG_SERIAL_H3800_ASIC=m +# CONFIG_SERIAL_SIR_PXA is not set +# 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=y +CONFIG_UNIX98_PTY_COUNT=32 +CONFIG_NEWTONKBD=m +CONFIG_SA1100_PROFILER=m + +# +# Compaq iPAQ H3600 support +# +CONFIG_TOUCHSCREEN_H3600=m +CONFIG_H3600_BACKPAQ_FPGA=m +CONFIG_H3600_BACKPAQ_ACCEL=m +CONFIG_H3600_BACKPAQ_GASGAUGE=m +CONFIG_H3600_BACKPAQ_SRAM=m +CONFIG_H3600_BACKPAQ_AUDIO=m +CONFIG_H3600_STOWAWAY=m +CONFIG_H3800_MICROKBD=m +CONFIG_SA1100_LIRC=m +# CONFIG_H5400_BUZZER is not set +# CONFIG_H5400_FSI is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +CONFIG_L3=y +CONFIG_L3_ALGOBIT=y +CONFIG_L3_BIT_SA1100_GPIO=y + +# +# Other L3 adapters +# +# CONFIG_L3_S3C2410 is not set +# CONFIG_L3_SA1111 is not set +CONFIG_L3_BACKPAQ=m +CONFIG_BIT_SA1100_GPIO=y + +# +# SPI support +# +# CONFIG_SPI is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=m +# CONFIG_PSMOUSE is not set +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +CONFIG_INPUT_SERIO=m +CONFIG_INPUT_SERPORT=m + +# +# Joysticks +# +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_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=m +# CONFIG_PXA_WATCHDOG is not set +# CONFIG_OMAHA_WATCHDOG is not set +# 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_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_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_SA1100_RTC=m +# CONFIG_PXA_RTC_HACK is not set +# 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 +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +CONFIG_PCMCIA_SERIAL_CS=m +# CONFIG_PCMCIA_MOBILISCAN_CS is not set +# CONFIG_AXIM_KEY_FIX is not set + +# +# Multimedia devices +# +CONFIG_MEDIA=m +CONFIG_VIDEO_DEV=m +CONFIG_V4L2_DEV=m + +# +# Video For Linux +# +CONFIG_VIDEO_PROC_FS=y +# CONFIG_I2C_PARPORT is not set + +# +# Video Adapters +# +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_STRADIS is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_ZORAN_BUZ is not set +# CONFIG_VIDEO_ZORAN_DC10 is not set +# CONFIG_VIDEO_ZORAN_LML33 is not set +# CONFIG_VIDEO_ZR36120 is not set +# CONFIG_VIDEO_MEYE is not set +# CONFIG_VIDEO_CYBERPRO is not set +CONFIG_VIDEO_H3600_BACKPAQ=m +# CONFIG_VIDEO_HAWKEYE is not set + +# +# Video for Linux 2 (V4L2) +# +CONFIG_VIDEO_WINNOV_CS=m + +# +# Radio Adapters +# +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_GEMTEK_PCI is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_MAESTRO is not set +# CONFIG_RADIO_MIROPCM20 is not set +# CONFIG_RADIO_MIROPCM20_RDS is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=m +CONFIG_REISERFS_FS=m +# 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_BFS_FS is not set +CONFIG_EXT3_FS=m +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_UMSDOS_FS=m +CONFIG_VFAT_FS=m +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +CONFIG_CRAMFS=y +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=m +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS 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_DRIVERFS_FS is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=m +# 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 + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT 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=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Console drivers +# +CONFIG_PC_KEYMAP=y +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_ACORN is not set +# CONFIG_FB_ANAKIN is not set +# CONFIG_FB_CLPS711X is not set +# CONFIG_FB_S3C2410 is not set +CONFIG_FB_SA1100=y +# CONFIG_FB_EPSON1356 is not set +# CONFIG_FB_MQ200 is not set +# CONFIG_FB_PXA is not set +# CONFIG_FB_MQ1100 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +CONFIG_FBCON_CFB4=y +# CONFIG_FBCON_CFB8 is not set +CONFIG_FBCON_CFB16=y +# CONFIG_FBCON_CFB24 is not set +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +# CONFIG_FBCON_NO_LOGO is not set +CONFIG_FBCON_FONTWIDTH8_ONLY=y +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +CONFIG_SOUND_SA1100=m +CONFIG_SOUND_UDA1341=m +# CONFIG_SOUND_SA1100_MONO is not set +# CONFIG_SOUND_ASSABET_UDA1341 is not set +CONFIG_SOUND_H3600_UDA1341=m +# CONFIG_SOUND_PANGOLIN_UDA1341 is not set +# CONFIG_SOUND_SA1111_UDA1341 is not set +# CONFIG_SOUND_SA1100SSP is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_VIDC is not set +# CONFIG_SOUND_WAVEARTIST is not set +# CONFIG_SOUND_PXA_AC97 is not set +# CONFIG_SOUND_TVMIXER 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 +# CONFIG_MCP_UCB1400_TS is not set + +# +# Console Switches +# +# CONFIG_SWITCHES is not set + +# +# USB support +# +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set + +# +# USB Host Controller Drivers +# +# 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_OHCI_H5400 is not set +# CONFIG_USB_OHCI_S3C2410 is not set +CONFIG_USB_SL811HS=m + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_BLUETOOTH is not set +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +CONFIG_USB_PRINTER=m + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT=y +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_WACOM is not set + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +CONFIG_USB_IBMCAM=m +CONFIG_USB_OV511=m +CONFIG_USB_PWC=m +CONFIG_USB_SE401=m +CONFIG_USB_STV680=m +CONFIG_USB_VICAM=m +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DABUSB is not set + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +CONFIG_USB_CDCETHER=m +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# 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 + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_BRLVGER is not set + +# +# Linux As Bootldr Modules +# +# CONFIG_BIG_KERNEL is not set +# CONFIG_USE_DATE_CODE is not set +# CONFIG_YMODEM is not set +# CONFIG_LAB_DUMMY is not set +# CONFIG_LAB_CRC is not set +# CONFIG_LAB_YMODEM is not set +# CONFIG_LAB_MTD is not set +# CONFIG_LAB_COPY is not set +# CONFIG_LAB_COPY_YMODEM is not set +# CONFIG_LAB_COPY_FLASH is not set +# CONFIG_LAB_COPY_FS is not set +# CONFIG_LAB_COPY_WRAPPER is not set + +# +# Bluetooth support +# +CONFIG_BLUEZ=m +CONFIG_BLUEZ_L2CAP=m +CONFIG_BLUEZ_SCO=m +CONFIG_BLUEZ_RFCOMM=m +CONFIG_BLUEZ_RFCOMM_TTY=y +CONFIG_BLUEZ_BNEP=m +CONFIG_BLUEZ_BNEP_MC_FILTER=y +CONFIG_BLUEZ_BNEP_PROTO_FILTER=y + +# +# Bluetooth device drivers +# +# CONFIG_BLUEZ_HCIUSB is not set +CONFIG_BLUEZ_HCIUART=m +CONFIG_BLUEZ_HCIUART_H4=y +CONFIG_BLUEZ_HCIUART_BCSP=y +# CONFIG_BLUEZ_HCIUART_BCSP_TXCRC is not set +# CONFIG_BLUEZ_HCIBFUSB is not set +CONFIG_BLUEZ_HCIDTL1=m +CONFIG_BLUEZ_HCIBT3C=m +CONFIG_BLUEZ_HCIBLUECARD=m +CONFIG_BLUEZ_HCIBTUART=m +# CONFIG_BLUEZ_HCIVHCI is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# 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=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +# CONFIG_CRC32 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/disable-pcmcia-probe.patch b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/disable-pcmcia-probe.patch index e69de29bb2..79ba036323 100644 --- a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/disable-pcmcia-probe.patch +++ b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/disable-pcmcia-probe.patch @@ -0,0 +1,17 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux/drivers/pcmcia/Config.in~disable-pcmcia-probe 2003-05-13 11:18:23.000000000 +0200 ++++ linux/drivers/pcmcia/Config.in 2004-05-27 13:59:50.000000000 +0200 +@@ -15,9 +15,6 @@ + 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 diff --git a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/ipsec.patch b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/ipsec.patch index e69de29bb2..4e2efc035b 100644 --- a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/ipsec.patch +++ b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/ipsec.patch @@ -0,0 +1,1446 @@ +--- linux/net/Makefile 3 Dec 2003 19:15:16 -0000 1.25 ++++ linux/net/Makefile 20 Feb 2003 15:50:38 -0000 1.24 +@@ -19,6 +19,7 @@ + subdir-$(CONFIG_NETFILTER) += ipv4/netfilter + subdir-$(CONFIG_UNIX) += unix + subdir-$(CONFIG_IPV6) += ipv6 ++subdir-$(CONFIG_IPSEC) += ipsec + + ifneq ($(CONFIG_IPV6),n) + ifneq ($(CONFIG_IPV6),) +--- /dev/null 2004-02-02 20:32:13.000000000 +0000 ++++ linux/include/zlib/zlib.h 2004-07-05 23:56:59.000000000 +0100 +@@ -0,0 +1,893 @@ ++/* zlib.h -- interface of the 'zlib' general purpose compression library ++ version 1.1.4, March 11th, 2002 ++ ++ Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler ++ ++ This software is provided 'as-is', without any express or implied ++ warranty. In no event will the authors be held liable for any damages ++ arising from the use of this software. ++ ++ Permission is granted to anyone to use this software for any purpose, ++ including commercial applications, and to alter it and redistribute it ++ freely, subject to the following restrictions: ++ ++ 1. The origin of this software must not be misrepresented; you must not ++ claim that you wrote the original software. If you use this software ++ in a product, an acknowledgment in the product documentation would be ++ appreciated but is not required. ++ 2. Altered source versions must be plainly marked as such, and must not be ++ misrepresented as being the original software. ++ 3. This notice may not be removed or altered from any source distribution. ++ ++ Jean-loup Gailly Mark Adler ++ jloup@gzip.org madler@alumni.caltech.edu ++ ++ ++ The data format used by the zlib library is described by RFCs (Request for ++ Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt ++ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). ++*/ ++ ++#ifndef _ZLIB_H ++#define _ZLIB_H ++ ++#include "zconf.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define ZLIB_VERSION "1.1.4" ++ ++/* ++ The 'zlib' compression library provides in-memory compression and ++ decompression functions, including integrity checks of the uncompressed ++ data. This version of the library supports only one compression method ++ (deflation) but other algorithms will be added later and will have the same ++ stream interface. ++ ++ Compression can be done in a single step if the buffers are large ++ enough (for example if an input file is mmap'ed), or can be done by ++ repeated calls of the compression function. In the latter case, the ++ application must provide more input and/or consume the output ++ (providing more output space) before each call. ++ ++ The library also supports reading and writing files in gzip (.gz) format ++ with an interface similar to that of stdio. ++ ++ The library does not install any signal handler. The decoder checks ++ the consistency of the compressed data, so the library should never ++ crash even in case of corrupted input. ++*/ ++ ++typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); ++typedef void (*free_func) OF((voidpf opaque, voidpf address)); ++ ++struct internal_state; ++ ++typedef struct z_stream_s { ++ Bytef *next_in; /* next input byte */ ++ uInt avail_in; /* number of bytes available at next_in */ ++ uLong total_in; /* total nb of input bytes read so far */ ++ ++ Bytef *next_out; /* next output byte should be put there */ ++ uInt avail_out; /* remaining free space at next_out */ ++ uLong total_out; /* total nb of bytes output so far */ ++ ++ const char *msg; /* last error message, NULL if no error */ ++ struct internal_state FAR *state; /* not visible by applications */ ++ ++ alloc_func zalloc; /* used to allocate the internal state */ ++ free_func zfree; /* used to free the internal state */ ++ voidpf opaque; /* private data object passed to zalloc and zfree */ ++ ++ int data_type; /* best guess about the data type: ascii or binary */ ++ uLong adler; /* adler32 value of the uncompressed data */ ++ uLong reserved; /* reserved for future use */ ++} z_stream; ++ ++typedef z_stream FAR *z_streamp; ++ ++/* ++ The application must update next_in and avail_in when avail_in has ++ dropped to zero. It must update next_out and avail_out when avail_out ++ has dropped to zero. The application must initialize zalloc, zfree and ++ opaque before calling the init function. All other fields are set by the ++ compression library and must not be updated by the application. ++ ++ The opaque value provided by the application will be passed as the first ++ parameter for calls of zalloc and zfree. This can be useful for custom ++ memory management. The compression library attaches no meaning to the ++ opaque value. ++ ++ zalloc must return Z_NULL if there is not enough memory for the object. ++ If zlib is used in a multi-threaded application, zalloc and zfree must be ++ thread safe. ++ ++ On 16-bit systems, the functions zalloc and zfree must be able to allocate ++ exactly 65536 bytes, but will not be required to allocate more than this ++ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, ++ pointers returned by zalloc for objects of exactly 65536 bytes *must* ++ have their offset normalized to zero. The default allocation function ++ provided by this library ensures this (see zutil.c). To reduce memory ++ requirements and avoid any allocation of 64K objects, at the expense of ++ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). ++ ++ The fields total_in and total_out can be used for statistics or ++ progress reports. After compression, total_in holds the total size of ++ the uncompressed data and may be saved for use in the decompressor ++ (particularly if the decompressor wants to decompress everything in ++ a single step). ++*/ ++ ++ /* constants */ ++ ++#define Z_NO_FLUSH 0 ++#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ ++#define Z_SYNC_FLUSH 2 ++#define Z_FULL_FLUSH 3 ++#define Z_FINISH 4 ++/* Allowed flush values; see deflate() below for details */ ++ ++#define Z_OK 0 ++#define Z_STREAM_END 1 ++#define Z_NEED_DICT 2 ++#define Z_ERRNO (-1) ++#define Z_STREAM_ERROR (-2) ++#define Z_DATA_ERROR (-3) ++#define Z_MEM_ERROR (-4) ++#define Z_BUF_ERROR (-5) ++#define Z_VERSION_ERROR (-6) ++/* Return codes for the compression/decompression functions. Negative ++ * values are errors, positive values are used for special but normal events. ++ */ ++ ++#define Z_NO_COMPRESSION 0 ++#define Z_BEST_SPEED 1 ++#define Z_BEST_COMPRESSION 9 ++#define Z_DEFAULT_COMPRESSION (-1) ++/* compression levels */ ++ ++#define Z_FILTERED 1 ++#define Z_HUFFMAN_ONLY 2 ++#define Z_DEFAULT_STRATEGY 0 ++/* compression strategy; see deflateInit2() below for details */ ++ ++#define Z_BINARY 0 ++#define Z_ASCII 1 ++#define Z_UNKNOWN 2 ++/* Possible values of the data_type field */ ++ ++#define Z_DEFLATED 8 ++/* The deflate compression method (the only one supported in this version) */ ++ ++#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ ++ ++#define zlib_version zlibVersion() ++/* for compatibility with versions < 1.0.2 */ ++ ++ /* basic functions */ ++ ++ZEXTERN const char * ZEXPORT zlibVersion OF((void)); ++/* The application can compare zlibVersion and ZLIB_VERSION for consistency. ++ If the first character differs, the library code actually used is ++ not compatible with the zlib.h header file used by the application. ++ This check is automatically made by deflateInit and inflateInit. ++ */ ++ ++/* ++ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); ++ ++ Initializes the internal stream state for compression. The fields ++ zalloc, zfree and opaque must be initialized before by the caller. ++ If zalloc and zfree are set to Z_NULL, deflateInit updates them to ++ use default allocation functions. ++ ++ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: ++ 1 gives best speed, 9 gives best compression, 0 gives no compression at ++ all (the input data is simply copied a block at a time). ++ Z_DEFAULT_COMPRESSION requests a default compromise between speed and ++ compression (currently equivalent to level 6). ++ ++ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not ++ enough memory, Z_STREAM_ERROR if level is not a valid compression level, ++ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible ++ with the version assumed by the caller (ZLIB_VERSION). ++ msg is set to null if there is no error message. deflateInit does not ++ perform any compression: this will be done by deflate(). ++*/ ++ ++ ++ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); ++/* ++ deflate compresses as much data as possible, and stops when the input ++ buffer becomes empty or the output buffer becomes full. It may introduce some ++ output latency (reading input without producing any output) except when ++ forced to flush. ++ ++ The detailed semantics are as follows. deflate performs one or both of the ++ following actions: ++ ++ - Compress more input starting at next_in and update next_in and avail_in ++ accordingly. If not all input can be processed (because there is not ++ enough room in the output buffer), next_in and avail_in are updated and ++ processing will resume at this point for the next call of deflate(). ++ ++ - Provide more output starting at next_out and update next_out and avail_out ++ accordingly. This action is forced if the parameter flush is non zero. ++ Forcing flush frequently degrades the compression ratio, so this parameter ++ should be set only when necessary (in interactive applications). ++ Some output may be provided even if flush is not set. ++ ++ Before the call of deflate(), the application should ensure that at least ++ one of the actions is possible, by providing more input and/or consuming ++ more output, and updating avail_in or avail_out accordingly; avail_out ++ should never be zero before the call. The application can consume the ++ compressed output when it wants, for example when the output buffer is full ++ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK ++ and with zero avail_out, it must be called again after making room in the ++ output buffer because there might be more output pending. ++ ++ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is ++ flushed to the output buffer and the output is aligned on a byte boundary, so ++ that the decompressor can get all input data available so far. (In particular ++ avail_in is zero after the call if enough output space has been provided ++ before the call.) Flushing may degrade compression for some compression ++ algorithms and so it should be used only when necessary. ++ ++ If flush is set to Z_FULL_FLUSH, all output is flushed as with ++ Z_SYNC_FLUSH, and the compression state is reset so that decompression can ++ restart from this point if previous compressed data has been damaged or if ++ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade ++ the compression. ++ ++ If deflate returns with avail_out == 0, this function must be called again ++ with the same value of the flush parameter and more output space (updated ++ avail_out), until the flush is complete (deflate returns with non-zero ++ avail_out). ++ ++ If the parameter flush is set to Z_FINISH, pending input is processed, ++ pending output is flushed and deflate returns with Z_STREAM_END if there ++ was enough output space; if deflate returns with Z_OK, this function must be ++ called again with Z_FINISH and more output space (updated avail_out) but no ++ more input data, until it returns with Z_STREAM_END or an error. After ++ deflate has returned Z_STREAM_END, the only possible operations on the ++ stream are deflateReset or deflateEnd. ++ ++ Z_FINISH can be used immediately after deflateInit if all the compression ++ is to be done in a single step. In this case, avail_out must be at least ++ 0.1% larger than avail_in plus 12 bytes. If deflate does not return ++ Z_STREAM_END, then it must be called again as described above. ++ ++ deflate() sets strm->adler to the adler32 checksum of all input read ++ so far (that is, total_in bytes). ++ ++ deflate() may update data_type if it can make a good guess about ++ the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered ++ binary. This field is only for information purposes and does not affect ++ the compression algorithm in any manner. ++ ++ deflate() returns Z_OK if some progress has been made (more input ++ processed or more output produced), Z_STREAM_END if all input has been ++ consumed and all output has been produced (only when flush is set to ++ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example ++ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible ++ (for example avail_in or avail_out was zero). ++*/ ++ ++ ++ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); ++/* ++ All dynamically allocated data structures for this stream are freed. ++ This function discards any unprocessed input and does not flush any ++ pending output. ++ ++ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the ++ stream state was inconsistent, Z_DATA_ERROR if the stream was freed ++ prematurely (some input or output was discarded). In the error case, ++ msg may be set but then points to a static string (which must not be ++ deallocated). ++*/ ++ ++ ++/* ++ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); ++ ++ Initializes the internal stream state for decompression. The fields ++ next_in, avail_in, zalloc, zfree and opaque must be initialized before by ++ the caller. If next_in is not Z_NULL and avail_in is large enough (the exact ++ value depends on the compression method), inflateInit determines the ++ compression method from the zlib header and allocates all data structures ++ accordingly; otherwise the allocation will be deferred to the first call of ++ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to ++ use default allocation functions. ++ ++ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough ++ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the ++ version assumed by the caller. msg is set to null if there is no error ++ message. inflateInit does not perform any decompression apart from reading ++ the zlib header if present: this will be done by inflate(). (So next_in and ++ avail_in may be modified, but next_out and avail_out are unchanged.) ++*/ ++ ++ ++ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); ++/* ++ inflate decompresses as much data as possible, and stops when the input ++ buffer becomes empty or the output buffer becomes full. It may some ++ introduce some output latency (reading input without producing any output) ++ except when forced to flush. ++ ++ The detailed semantics are as follows. inflate performs one or both of the ++ following actions: ++ ++ - Decompress more input starting at next_in and update next_in and avail_in ++ accordingly. If not all input can be processed (because there is not ++ enough room in the output buffer), next_in is updated and processing ++ will resume at this point for the next call of inflate(). ++ ++ - Provide more output starting at next_out and update next_out and avail_out ++ accordingly. inflate() provides as much output as possible, until there ++ is no more input data or no more space in the output buffer (see below ++ about the flush parameter). ++ ++ Before the call of inflate(), the application should ensure that at least ++ one of the actions is possible, by providing more input and/or consuming ++ more output, and updating the next_* and avail_* values accordingly. ++ The application can consume the uncompressed output when it wants, for ++ example when the output buffer is full (avail_out == 0), or after each ++ call of inflate(). If inflate returns Z_OK and with zero avail_out, it ++ must be called again after making room in the output buffer because there ++ might be more output pending. ++ ++ If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much ++ output as possible to the output buffer. The flushing behavior of inflate is ++ not specified for values of the flush parameter other than Z_SYNC_FLUSH ++ and Z_FINISH, but the current implementation actually flushes as much output ++ as possible anyway. ++ ++ inflate() should normally be called until it returns Z_STREAM_END or an ++ error. However if all decompression is to be performed in a single step ++ (a single call of inflate), the parameter flush should be set to ++ Z_FINISH. In this case all pending input is processed and all pending ++ output is flushed; avail_out must be large enough to hold all the ++ uncompressed data. (The size of the uncompressed data may have been saved ++ by the compressor for this purpose.) The next operation on this stream must ++ be inflateEnd to deallocate the decompression state. The use of Z_FINISH ++ is never required, but can be used to inform inflate that a faster routine ++ may be used for the single inflate() call. ++ ++ If a preset dictionary is needed at this point (see inflateSetDictionary ++ below), inflate sets strm-adler to the adler32 checksum of the ++ dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise ++ it sets strm->adler to the adler32 checksum of all output produced ++ so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or ++ an error code as described below. At the end of the stream, inflate() ++ checks that its computed adler32 checksum is equal to that saved by the ++ compressor and returns Z_STREAM_END only if the checksum is correct. ++ ++ inflate() returns Z_OK if some progress has been made (more input processed ++ or more output produced), Z_STREAM_END if the end of the compressed data has ++ been reached and all uncompressed output has been produced, Z_NEED_DICT if a ++ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was ++ corrupted (input stream not conforming to the zlib format or incorrect ++ adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent ++ (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not ++ enough memory, Z_BUF_ERROR if no progress is possible or if there was not ++ enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR ++ case, the application may then call inflateSync to look for a good ++ compression block. ++*/ ++ ++ ++ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); ++/* ++ All dynamically allocated data structures for this stream are freed. ++ This function discards any unprocessed input and does not flush any ++ pending output. ++ ++ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state ++ was inconsistent. In the error case, msg may be set but then points to a ++ static string (which must not be deallocated). ++*/ ++ ++ /* Advanced functions */ ++ ++/* ++ The following functions are needed only in some special applications. ++*/ ++ ++/* ++ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, ++ int level, ++ int method, ++ int windowBits, ++ int memLevel, ++ int strategy)); ++ ++ This is another version of deflateInit with more compression options. The ++ fields next_in, zalloc, zfree and opaque must be initialized before by ++ the caller. ++ ++ The method parameter is the compression method. It must be Z_DEFLATED in ++ this version of the library. ++ ++ The windowBits parameter is the base two logarithm of the window size ++ (the size of the history buffer). It should be in the range 8..15 for this ++ version of the library. Larger values of this parameter result in better ++ compression at the expense of memory usage. The default value is 15 if ++ deflateInit is used instead. ++ ++ The memLevel parameter specifies how much memory should be allocated ++ for the internal compression state. memLevel=1 uses minimum memory but ++ is slow and reduces compression ratio; memLevel=9 uses maximum memory ++ for optimal speed. The default value is 8. See zconf.h for total memory ++ usage as a function of windowBits and memLevel. ++ ++ The strategy parameter is used to tune the compression algorithm. Use the ++ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a ++ filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no ++ string match). Filtered data consists mostly of small values with a ++ somewhat random distribution. In this case, the compression algorithm is ++ tuned to compress them better. The effect of Z_FILTERED is to force more ++ Huffman coding and less string matching; it is somewhat intermediate ++ between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects ++ the compression ratio but not the correctness of the compressed output even ++ if it is not set appropriately. ++ ++ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough ++ memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid ++ method). msg is set to null if there is no error message. deflateInit2 does ++ not perform any compression: this will be done by deflate(). ++*/ ++ ++ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, ++ const Bytef *dictionary, ++ uInt dictLength)); ++/* ++ Initializes the compression dictionary from the given byte sequence ++ without producing any compressed output. This function must be called ++ immediately after deflateInit, deflateInit2 or deflateReset, before any ++ call of deflate. The compressor and decompressor must use exactly the same ++ dictionary (see inflateSetDictionary). ++ ++ The dictionary should consist of strings (byte sequences) that are likely ++ to be encountered later in the data to be compressed, with the most commonly ++ used strings preferably put towards the end of the dictionary. Using a ++ dictionary is most useful when the data to be compressed is short and can be ++ predicted with good accuracy; the data can then be compressed better than ++ with the default empty dictionary. ++ ++ Depending on the size of the compression data structures selected by ++ deflateInit or deflateInit2, a part of the dictionary may in effect be ++ discarded, for example if the dictionary is larger than the window size in ++ deflate or deflate2. Thus the strings most likely to be useful should be ++ put at the end of the dictionary, not at the front. ++ ++ Upon return of this function, strm->adler is set to the Adler32 value ++ of the dictionary; the decompressor may later use this value to determine ++ which dictionary has been used by the compressor. (The Adler32 value ++ applies to the whole dictionary even if only a subset of the dictionary is ++ actually used by the compressor.) ++ ++ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a ++ parameter is invalid (such as NULL dictionary) or the stream state is ++ inconsistent (for example if deflate has already been called for this stream ++ or if the compression method is bsort). deflateSetDictionary does not ++ perform any compression: this will be done by deflate(). ++*/ ++ ++ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, ++ z_streamp source)); ++/* ++ Sets the destination stream as a complete copy of the source stream. ++ ++ This function can be useful when several compression strategies will be ++ tried, for example when there are several ways of pre-processing the input ++ data with a filter. The streams that will be discarded should then be freed ++ by calling deflateEnd. Note that deflateCopy duplicates the internal ++ compression state which can be quite large, so this strategy is slow and ++ can consume lots of memory. ++ ++ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not ++ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent ++ (such as zalloc being NULL). msg is left unchanged in both source and ++ destination. ++*/ ++ ++ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); ++/* ++ This function is equivalent to deflateEnd followed by deflateInit, ++ but does not free and reallocate all the internal compression state. ++ The stream will keep the same compression level and any other attributes ++ that may have been set by deflateInit2. ++ ++ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source ++ stream state was inconsistent (such as zalloc or state being NULL). ++*/ ++ ++ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, ++ int level, ++ int strategy)); ++/* ++ Dynamically update the compression level and compression strategy. The ++ interpretation of level and strategy is as in deflateInit2. This can be ++ used to switch between compression and straight copy of the input data, or ++ to switch to a different kind of input data requiring a different ++ strategy. If the compression level is changed, the input available so far ++ is compressed with the old level (and may be flushed); the new level will ++ take effect only at the next call of deflate(). ++ ++ Before the call of deflateParams, the stream state must be set as for ++ a call of deflate(), since the currently available input may have to ++ be compressed and flushed. In particular, strm->avail_out must be non-zero. ++ ++ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source ++ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR ++ if strm->avail_out was zero. ++*/ ++ ++/* ++ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, ++ int windowBits)); ++ ++ This is another version of inflateInit with an extra parameter. The ++ fields next_in, avail_in, zalloc, zfree and opaque must be initialized ++ before by the caller. ++ ++ The windowBits parameter is the base two logarithm of the maximum window ++ size (the size of the history buffer). It should be in the range 8..15 for ++ this version of the library. The default value is 15 if inflateInit is used ++ instead. If a compressed stream with a larger window size is given as ++ input, inflate() will return with the error code Z_DATA_ERROR instead of ++ trying to allocate a larger window. ++ ++ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough ++ memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative ++ memLevel). msg is set to null if there is no error message. inflateInit2 ++ does not perform any decompression apart from reading the zlib header if ++ present: this will be done by inflate(). (So next_in and avail_in may be ++ modified, but next_out and avail_out are unchanged.) ++*/ ++ ++ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, ++ const Bytef *dictionary, ++ uInt dictLength)); ++/* ++ Initializes the decompression dictionary from the given uncompressed byte ++ sequence. This function must be called immediately after a call of inflate ++ if this call returned Z_NEED_DICT. The dictionary chosen by the compressor ++ can be determined from the Adler32 value returned by this call of ++ inflate. The compressor and decompressor must use exactly the same ++ dictionary (see deflateSetDictionary). ++ ++ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a ++ parameter is invalid (such as NULL dictionary) or the stream state is ++ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the ++ expected one (incorrect Adler32 value). inflateSetDictionary does not ++ perform any decompression: this will be done by subsequent calls of ++ inflate(). ++*/ ++ ++ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); ++/* ++ Skips invalid compressed data until a full flush point (see above the ++ description of deflate with Z_FULL_FLUSH) can be found, or until all ++ available input is skipped. No output is provided. ++ ++ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR ++ if no more input was provided, Z_DATA_ERROR if no flush point has been found, ++ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success ++ case, the application may save the current current value of total_in which ++ indicates where valid compressed data was found. In the error case, the ++ application may repeatedly call inflateSync, providing more input each time, ++ until success or end of the input data. ++*/ ++ ++ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); ++/* ++ This function is equivalent to inflateEnd followed by inflateInit, ++ but does not free and reallocate all the internal decompression state. ++ The stream will keep attributes that may have been set by inflateInit2. ++ ++ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source ++ stream state was inconsistent (such as zalloc or state being NULL). ++*/ ++ ++ ++ /* utility functions */ ++ ++/* ++ The following utility functions are implemented on top of the ++ basic stream-oriented functions. To simplify the interface, some ++ default options are assumed (compression level and memory usage, ++ standard memory allocation functions). The source code of these ++ utility functions can easily be modified if you need special options. ++*/ ++ ++ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, ++ const Bytef *source, uLong sourceLen)); ++/* ++ Compresses the source buffer into the destination buffer. sourceLen is ++ the byte length of the source buffer. Upon entry, destLen is the total ++ size of the destination buffer, which must be at least 0.1% larger than ++ sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the ++ compressed buffer. ++ This function can be used to compress a whole file at once if the ++ input file is mmap'ed. ++ compress returns Z_OK if success, Z_MEM_ERROR if there was not ++ enough memory, Z_BUF_ERROR if there was not enough room in the output ++ buffer. ++*/ ++ ++ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, ++ const Bytef *source, uLong sourceLen, ++ int level)); ++/* ++ Compresses the source buffer into the destination buffer. The level ++ parameter has the same meaning as in deflateInit. sourceLen is the byte ++ length of the source buffer. Upon entry, destLen is the total size of the ++ destination buffer, which must be at least 0.1% larger than sourceLen plus ++ 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. ++ ++ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough ++ memory, Z_BUF_ERROR if there was not enough room in the output buffer, ++ Z_STREAM_ERROR if the level parameter is invalid. ++*/ ++ ++ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, ++ const Bytef *source, uLong sourceLen)); ++/* ++ Decompresses the source buffer into the destination buffer. sourceLen is ++ the byte length of the source buffer. Upon entry, destLen is the total ++ size of the destination buffer, which must be large enough to hold the ++ entire uncompressed data. (The size of the uncompressed data must have ++ been saved previously by the compressor and transmitted to the decompressor ++ by some mechanism outside the scope of this compression library.) ++ Upon exit, destLen is the actual size of the compressed buffer. ++ This function can be used to decompress a whole file at once if the ++ input file is mmap'ed. ++ ++ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not ++ enough memory, Z_BUF_ERROR if there was not enough room in the output ++ buffer, or Z_DATA_ERROR if the input data was corrupted. ++*/ ++ ++ ++typedef voidp gzFile; ++ ++ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); ++/* ++ Opens a gzip (.gz) file for reading or writing. The mode parameter ++ is as in fopen ("rb" or "wb") but can also include a compression level ++ ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for ++ Huffman only compression as in "wb1h". (See the description ++ of deflateInit2 for more information about the strategy parameter.) ++ ++ gzopen can be used to read a file which is not in gzip format; in this ++ case gzread will directly read from the file without decompression. ++ ++ gzopen returns NULL if the file could not be opened or if there was ++ insufficient memory to allocate the (de)compression state; errno ++ can be checked to distinguish the two cases (if errno is zero, the ++ zlib error is Z_MEM_ERROR). */ ++ ++ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); ++/* ++ gzdopen() associates a gzFile with the file descriptor fd. File ++ descriptors are obtained from calls like open, dup, creat, pipe or ++ fileno (in the file has been previously opened with fopen). ++ The mode parameter is as in gzopen. ++ The next call of gzclose on the returned gzFile will also close the ++ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file ++ descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). ++ gzdopen returns NULL if there was insufficient memory to allocate ++ the (de)compression state. ++*/ ++ ++ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); ++/* ++ Dynamically update the compression level or strategy. See the description ++ of deflateInit2 for the meaning of these parameters. ++ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not ++ opened for writing. ++*/ ++ ++ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); ++/* ++ Reads the given number of uncompressed bytes from the compressed file. ++ If the input file was not in gzip format, gzread copies the given number ++ of bytes into the buffer. ++ gzread returns the number of uncompressed bytes actually read (0 for ++ end of file, -1 for error). */ ++ ++ZEXTERN int ZEXPORT gzwrite OF((gzFile file, ++ const voidp buf, unsigned len)); ++/* ++ Writes the given number of uncompressed bytes into the compressed file. ++ gzwrite returns the number of uncompressed bytes actually written ++ (0 in case of error). ++*/ ++ ++ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); ++/* ++ Converts, formats, and writes the args to the compressed file under ++ control of the format string, as in fprintf. gzprintf returns the number of ++ uncompressed bytes actually written (0 in case of error). ++*/ ++ ++ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); ++/* ++ Writes the given null-terminated string to the compressed file, excluding ++ the terminating null character. ++ gzputs returns the number of characters written, or -1 in case of error. ++*/ ++ ++ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); ++/* ++ Reads bytes from the compressed file until len-1 characters are read, or ++ a newline character is read and transferred to buf, or an end-of-file ++ condition is encountered. The string is then terminated with a null ++ character. ++ gzgets returns buf, or Z_NULL in case of error. ++*/ ++ ++ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); ++/* ++ Writes c, converted to an unsigned char, into the compressed file. ++ gzputc returns the value that was written, or -1 in case of error. ++*/ ++ ++ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); ++/* ++ Reads one byte from the compressed file. gzgetc returns this byte ++ or -1 in case of end of file or error. ++*/ ++ ++ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); ++/* ++ Flushes all pending output into the compressed file. The parameter ++ flush is as in the deflate() function. The return value is the zlib ++ error number (see function gzerror below). gzflush returns Z_OK if ++ the flush parameter is Z_FINISH and all output could be flushed. ++ gzflush should be called only when strictly necessary because it can ++ degrade compression. ++*/ ++ ++ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, ++ z_off_t offset, int whence)); ++/* ++ Sets the starting position for the next gzread or gzwrite on the ++ given compressed file. The offset represents a number of bytes in the ++ uncompressed data stream. The whence parameter is defined as in lseek(2); ++ the value SEEK_END is not supported. ++ If the file is opened for reading, this function is emulated but can be ++ extremely slow. If the file is opened for writing, only forward seeks are ++ supported; gzseek then compresses a sequence of zeroes up to the new ++ starting position. ++ ++ gzseek returns the resulting offset location as measured in bytes from ++ the beginning of the uncompressed stream, or -1 in case of error, in ++ particular if the file is opened for writing and the new starting position ++ would be before the current position. ++*/ ++ ++ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); ++/* ++ Rewinds the given file. This function is supported only for reading. ++ ++ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) ++*/ ++ ++ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); ++/* ++ Returns the starting position for the next gzread or gzwrite on the ++ given compressed file. This position represents a number of bytes in the ++ uncompressed data stream. ++ ++ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) ++*/ ++ ++ZEXTERN int ZEXPORT gzeof OF((gzFile file)); ++/* ++ Returns 1 when EOF has previously been detected reading the given ++ input stream, otherwise zero. ++*/ ++ ++ZEXTERN int ZEXPORT gzclose OF((gzFile file)); ++/* ++ Flushes all pending output if necessary, closes the compressed file ++ and deallocates all the (de)compression state. The return value is the zlib ++ error number (see function gzerror below). ++*/ ++ ++ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); ++/* ++ Returns the error message for the last error which occurred on the ++ given compressed file. errnum is set to zlib error number. If an ++ error occurred in the file system and not in the compression library, ++ errnum is set to Z_ERRNO and the application may consult errno ++ to get the exact error code. ++*/ ++ ++ /* checksum functions */ ++ ++/* ++ These functions are not related to compression but are exported ++ anyway because they might be useful in applications using the ++ compression library. ++*/ ++ ++ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); ++ ++/* ++ Update a running Adler-32 checksum with the bytes buf[0..len-1] and ++ return the updated checksum. If buf is NULL, this function returns ++ the required initial value for the checksum. ++ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed ++ much faster. Usage example: ++ ++ uLong adler = adler32(0L, Z_NULL, 0); ++ ++ while (read_buffer(buffer, length) != EOF) { ++ adler = adler32(adler, buffer, length); ++ } ++ if (adler != original_adler) error(); ++*/ ++ ++ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); ++/* ++ Update a running crc with the bytes buf[0..len-1] and return the updated ++ crc. If buf is NULL, this function returns the required initial value ++ for the crc. Pre- and post-conditioning (one's complement) is performed ++ within this function so it shouldn't be done by the application. ++ Usage example: ++ ++ uLong crc = crc32(0L, Z_NULL, 0); ++ ++ while (read_buffer(buffer, length) != EOF) { ++ crc = crc32(crc, buffer, length); ++ } ++ if (crc != original_crc) error(); ++*/ ++ ++ ++ /* various hacks, don't look :) */ ++ ++/* deflateInit and inflateInit are macros to allow checking the zlib version ++ * and the compiler's view of z_stream: ++ */ ++ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, ++ const char *version, int stream_size)); ++ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, ++ const char *version, int stream_size)); ++ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, ++ int windowBits, int memLevel, ++ int strategy, const char *version, ++ int stream_size)); ++ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, ++ const char *version, int stream_size)); ++#define deflateInit(strm, level) \ ++ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) ++#define inflateInit(strm) \ ++ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) ++#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ ++ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ ++ (strategy), ZLIB_VERSION, sizeof(z_stream)) ++#define inflateInit2(strm, windowBits) \ ++ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) ++ ++ ++#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL) ++ struct internal_state {int dummy;}; /* hack for buggy compilers */ ++#endif ++ ++ZEXTERN const char * ZEXPORT zError OF((int err)); ++ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); ++ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _ZLIB_H */ +--- /dev/null 2004-02-02 20:32:13.000000000 +0000 ++++ linux/include/zlib/zutil.h 2004-07-05 23:59:30.000000000 +0100 +@@ -0,0 +1,225 @@ ++/* zutil.h -- internal interface and configuration of the compression library ++ * Copyright (C) 1995-2002 Jean-loup Gailly. ++ * For conditions of distribution and use, see copyright notice in zlib.h ++ */ ++ ++/* WARNING: this file should *not* be used by applications. It is ++ part of the implementation of the compression library and is ++ subject to change. Applications should only use zlib.h. ++ */ ++ ++/* @(#) $Id$ */ ++ ++#ifndef _Z_UTIL_H ++#define _Z_UTIL_H ++ ++#include "zlib.h" ++ ++#include <linux/string.h> ++#define HAVE_MEMCPY ++ ++#if 0 // #ifdef STDC ++# include <stddef.h> ++# include <string.h> ++# include <stdlib.h> ++#endif ++#ifndef __KERNEL__ ++#ifdef NO_ERRNO_H ++ extern int errno; ++#else ++# include <errno.h> ++#endif ++#endif ++ ++#ifndef local ++# define local static ++#endif ++/* compile with -Dlocal if your debugger can't find static symbols */ ++ ++typedef unsigned char uch; ++typedef uch FAR uchf; ++typedef unsigned short ush; ++typedef ush FAR ushf; ++typedef unsigned long ulg; ++ ++extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ ++/* (size given to avoid silly warnings with Visual C++) */ ++ ++#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] ++ ++#define ERR_RETURN(strm,err) \ ++ return (strm->msg = ERR_MSG(err), (err)) ++/* To be used only when the state is known to be valid */ ++ ++ /* common constants */ ++ ++#ifndef DEF_WBITS ++# define DEF_WBITS MAX_WBITS ++#endif ++/* default windowBits for decompression. MAX_WBITS is for compression only */ ++ ++#if MAX_MEM_LEVEL >= 8 ++# define DEF_MEM_LEVEL 8 ++#else ++# define DEF_MEM_LEVEL MAX_MEM_LEVEL ++#endif ++/* default memLevel */ ++ ++#define STORED_BLOCK 0 ++#define STATIC_TREES 1 ++#define DYN_TREES 2 ++/* The three kinds of block type */ ++ ++#define MIN_MATCH 3 ++#define MAX_MATCH 258 ++/* The minimum and maximum match lengths */ ++ ++#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ ++ ++ /* target dependencies */ ++ ++#ifdef MSDOS ++# define OS_CODE 0x00 ++# if defined(__TURBOC__) || defined(__BORLANDC__) ++# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) ++ /* Allow compilation with ANSI keywords only enabled */ ++ void _Cdecl farfree( void *block ); ++ void *_Cdecl farmalloc( unsigned long nbytes ); ++# else ++# include <alloc.h> ++# endif ++# else /* MSC or DJGPP */ ++# include <malloc.h> ++# endif ++#endif ++ ++#ifdef OS2 ++# define OS_CODE 0x06 ++#endif ++ ++#ifdef WIN32 /* Window 95 & Windows NT */ ++# define OS_CODE 0x0b ++#endif ++ ++#if defined(VAXC) || defined(VMS) ++# define OS_CODE 0x02 ++# define F_OPEN(name, mode) \ ++ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") ++#endif ++ ++#ifdef AMIGA ++# define OS_CODE 0x01 ++#endif ++ ++#if defined(ATARI) || defined(atarist) ++# define OS_CODE 0x05 ++#endif ++ ++#if defined(MACOS) || defined(TARGET_OS_MAC) ++# define OS_CODE 0x07 ++# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os ++# include <unix.h> /* for fdopen */ ++# else ++# ifndef fdopen ++# define fdopen(fd,mode) NULL /* No fdopen() */ ++# endif ++# endif ++#endif ++ ++#ifdef __50SERIES /* Prime/PRIMOS */ ++# define OS_CODE 0x0F ++#endif ++ ++#ifdef TOPS20 ++# define OS_CODE 0x0a ++#endif ++ ++#if defined(_BEOS_) || defined(RISCOS) ++# define fdopen(fd,mode) NULL /* No fdopen() */ ++#endif ++ ++#if (defined(_MSC_VER) && (_MSC_VER > 600)) ++# define fdopen(fd,type) _fdopen(fd,type) ++#endif ++ ++ ++ /* Common defaults */ ++ ++#ifndef OS_CODE ++# define OS_CODE 0x03 /* assume Unix */ ++#endif ++ ++#ifndef F_OPEN ++# define F_OPEN(name, mode) fopen((name), (mode)) ++#endif ++ ++ /* functions */ ++ ++#ifdef HAVE_STRERROR ++ extern char *strerror OF((int)); ++# define zstrerror(errnum) strerror(errnum) ++#else ++# define zstrerror(errnum) "" ++#endif ++ ++#if defined(pyr) ++# define NO_MEMCPY ++#endif ++#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) ++ /* Use our own functions for small and medium model with MSC <= 5.0. ++ * You may have to use the same strategy for Borland C (untested). ++ * The __SC__ check is for Symantec. ++ */ ++# define NO_MEMCPY ++#endif ++#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) ++# define HAVE_MEMCPY ++#endif ++#ifdef HAVE_MEMCPY ++# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ ++# define zmemcpy _fmemcpy ++# define zmemcmp _fmemcmp ++# define zmemzero(dest, len) _fmemset(dest, 0, len) ++# else ++# define zmemcpy memcpy ++# define zmemcmp memcmp ++# define zmemzero(dest, len) memset(dest, 0, len) ++# endif ++#else ++ extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); ++ extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); ++ extern void zmemzero OF((Bytef* dest, uInt len)); ++#endif ++ ++/* Diagnostic functions */ ++#ifdef DEBUG ++# include <stdio.h> ++ extern int z_verbose; ++ extern void z_error OF((char *m)); ++# define Assert(cond,msg) {if(!(cond)) z_error(msg);} ++# define Trace(x) {if (z_verbose>=0) fprintf x ;} ++# define Tracev(x) {if (z_verbose>0) fprintf x ;} ++# define Tracevv(x) {if (z_verbose>1) fprintf x ;} ++# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} ++# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} ++#else ++# define Assert(cond,msg) ++# define Trace(x) ++# define Tracev(x) ++# define Tracevv(x) ++# define Tracec(c,x) ++# define Tracecv(c,x) ++#endif ++ ++ ++typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf, ++ uInt len)); ++voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); ++void zcfree OF((voidpf opaque, voidpf ptr)); ++ ++#define ZALLOC(strm, items, size) \ ++ (*((strm)->zalloc))((strm)->opaque, (items), (size)) ++#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) ++#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} ++ ++#endif /* _Z_UTIL_H */ +--- /dev/null 2004-02-02 20:32:13.000000000 +0000 ++++ linux/include/zconf.h 2004-07-04 15:38:31.000000000 +0100 +@@ -0,0 +1,309 @@ ++/* zconf.h -- configuration of the zlib compression library ++ * Copyright (C) 1995-2002 Jean-loup Gailly. ++ * For conditions of distribution and use, see copyright notice in zlib.h ++ */ ++ ++/* @(#) $Id$ */ ++ ++#ifndef _ZCONF_H ++#define _ZCONF_H ++ ++/* ++ * If you *really* need a unique prefix for all types and library functions, ++ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. ++ */ ++#ifdef IPCOMP_PREFIX ++# define deflateInit_ ipcomp_deflateInit_ ++# define deflate ipcomp_deflate ++# define deflateEnd ipcomp_deflateEnd ++# define inflateInit_ ipcomp_inflateInit_ ++# define inflate ipcomp_inflate ++# define inflateEnd ipcomp_inflateEnd ++# define deflateInit2_ ipcomp_deflateInit2_ ++# define deflateSetDictionary ipcomp_deflateSetDictionary ++# define deflateCopy ipcomp_deflateCopy ++# define deflateReset ipcomp_deflateReset ++# define deflateParams ipcomp_deflateParams ++# define inflateInit2_ ipcomp_inflateInit2_ ++# define inflateSetDictionary ipcomp_inflateSetDictionary ++# define inflateSync ipcomp_inflateSync ++# define inflateSyncPoint ipcomp_inflateSyncPoint ++# define inflateReset ipcomp_inflateReset ++# define compress ipcomp_compress ++# define compress2 ipcomp_compress2 ++# define uncompress ipcomp_uncompress ++# define adler32 ipcomp_adler32 ++# define crc32 ipcomp_crc32 ++# define get_crc_table ipcomp_get_crc_table ++/* SSS: these also need to be prefixed to avoid clash with ppp_deflate and ext2compression */ ++# define inflate_blocks ipcomp_deflate_blocks ++# define inflate_blocks_free ipcomp_deflate_blocks_free ++# define inflate_blocks_new ipcomp_inflate_blocks_new ++# define inflate_blocks_reset ipcomp_inflate_blocks_reset ++# define inflate_blocks_sync_point ipcomp_inflate_blocks_sync_point ++# define inflate_set_dictionary ipcomp_inflate_set_dictionary ++# define inflate_codes ipcomp_inflate_codes ++# define inflate_codes_free ipcomp_inflate_codes_free ++# define inflate_codes_new ipcomp_inflate_codes_new ++# define inflate_fast ipcomp_inflate_fast ++# define inflate_trees_bits ipcomp_inflate_trees_bits ++# define inflate_trees_dynamic ipcomp_inflate_trees_dynamic ++# define inflate_trees_fixed ipcomp_inflate_trees_fixed ++# define inflate_flush ipcomp_inflate_flush ++# define inflate_mask ipcomp_inflate_mask ++# define _dist_code _ipcomp_dist_code ++# define _length_code _ipcomp_length_code ++# define _tr_align _ipcomp_tr_align ++# define _tr_flush_block _ipcomp_tr_flush_block ++# define _tr_init _ipcomp_tr_init ++# define _tr_stored_block _ipcomp_tr_stored_block ++# define _tr_tally _ipcomp_tr_tally ++# define zError ipcomp_zError ++# define z_errmsg ipcomp_z_errmsg ++# define zlibVersion ipcomp_zlibVersion ++# define match_init ipcomp_match_init ++# define longest_match ipcomp_longest_match ++#endif ++ ++#ifdef Z_PREFIX ++# define Byte z_Byte ++# define uInt z_uInt ++# define uLong z_uLong ++# define Bytef z_Bytef ++# define charf z_charf ++# define intf z_intf ++# define uIntf z_uIntf ++# define uLongf z_uLongf ++# define voidpf z_voidpf ++# define voidp z_voidp ++#endif ++ ++#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) ++# define WIN32 ++#endif ++#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386) ++# ifndef __32BIT__ ++# define __32BIT__ ++# endif ++#endif ++#if defined(__MSDOS__) && !defined(MSDOS) ++# define MSDOS ++#endif ++ ++/* ++ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more ++ * than 64k bytes at a time (needed on systems with 16-bit int). ++ */ ++#if defined(MSDOS) && !defined(__32BIT__) ++# define MAXSEG_64K ++#endif ++#ifdef MSDOS ++# define UNALIGNED_OK ++#endif ++ ++#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC) ++# define STDC ++#endif ++#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__) ++# ifndef STDC ++# define STDC ++# endif ++#endif ++ ++#ifndef STDC ++# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ ++# define const ++# endif ++#endif ++ ++/* Some Mac compilers merge all .h files incorrectly: */ ++#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__) ++# define NO_DUMMY_DECL ++#endif ++ ++/* Old Borland C incorrectly complains about missing returns: */ ++#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500) ++# define NEED_DUMMY_RETURN ++#endif ++ ++ ++/* Maximum value for memLevel in deflateInit2 */ ++#ifndef MAX_MEM_LEVEL ++# ifdef MAXSEG_64K ++# define MAX_MEM_LEVEL 8 ++# else ++# define MAX_MEM_LEVEL 9 ++# endif ++#endif ++ ++/* Maximum value for windowBits in deflateInit2 and inflateInit2. ++ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files ++ * created by gzip. (Files created by minigzip can still be extracted by ++ * gzip.) ++ */ ++#ifndef MAX_WBITS ++# define MAX_WBITS 15 /* 32K LZ77 window */ ++#endif ++ ++/* The memory requirements for deflate are (in bytes): ++ (1 << (windowBits+2)) + (1 << (memLevel+9)) ++ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) ++ plus a few kilobytes for small objects. For example, if you want to reduce ++ the default memory requirements from 256K to 128K, compile with ++ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" ++ Of course this will generally degrade compression (there's no free lunch). ++ ++ The memory requirements for inflate are (in bytes) 1 << windowBits ++ that is, 32K for windowBits=15 (default value) plus a few kilobytes ++ for small objects. ++*/ ++ ++ /* Type declarations */ ++ ++#ifndef OF /* function prototypes */ ++# ifdef STDC ++# define OF(args) args ++# else ++# define OF(args) () ++# endif ++#endif ++ ++/* The following definitions for FAR are needed only for MSDOS mixed ++ * model programming (small or medium model with some far allocations). ++ * This was tested only with MSC; for other MSDOS compilers you may have ++ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, ++ * just define FAR to be empty. ++ */ ++#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__) ++ /* MSC small or medium model */ ++# define SMALL_MEDIUM ++# ifdef _MSC_VER ++# define FAR _far ++# else ++# define FAR far ++# endif ++#endif ++#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__)) ++# ifndef __32BIT__ ++# define SMALL_MEDIUM ++# define FAR _far ++# endif ++#endif ++ ++/* Compile with -DZLIB_DLL for Windows DLL support */ ++#if defined(ZLIB_DLL) ++# if defined(_WINDOWS) || defined(WINDOWS) ++# ifdef FAR ++# undef FAR ++# endif ++# include <windows.h> ++# define ZEXPORT WINAPI ++# ifdef WIN32 ++# define ZEXPORTVA WINAPIV ++# else ++# define ZEXPORTVA FAR _cdecl _export ++# endif ++# endif ++# if defined (__BORLANDC__) ++# if (__BORLANDC__ >= 0x0500) && defined (WIN32) ++# include <windows.h> ++# define ZEXPORT __declspec(dllexport) WINAPI ++# define ZEXPORTRVA __declspec(dllexport) WINAPIV ++# else ++# if defined (_Windows) && defined (__DLL__) ++# define ZEXPORT _export ++# define ZEXPORTVA _export ++# endif ++# endif ++# endif ++#endif ++ ++#if defined (__BEOS__) ++# if defined (ZLIB_DLL) ++# define ZEXTERN extern __declspec(dllexport) ++# else ++# define ZEXTERN extern __declspec(dllimport) ++# endif ++#endif ++ ++#ifndef ZEXPORT ++# define ZEXPORT ++#endif ++#ifndef ZEXPORTVA ++# define ZEXPORTVA ++#endif ++#ifndef ZEXTERN ++# define ZEXTERN extern ++#endif ++ ++#ifndef FAR ++# define FAR ++#endif ++ ++#if !defined(MACOS) && !defined(TARGET_OS_MAC) ++typedef unsigned char Byte; /* 8 bits */ ++#endif ++typedef unsigned int uInt; /* 16 bits or more */ ++typedef unsigned long uLong; /* 32 bits or more */ ++ ++#ifdef SMALL_MEDIUM ++ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ ++# define Bytef Byte FAR ++#else ++ typedef Byte FAR Bytef; ++#endif ++typedef char FAR charf; ++typedef int FAR intf; ++typedef uInt FAR uIntf; ++typedef uLong FAR uLongf; ++ ++#ifdef STDC ++ typedef void FAR *voidpf; ++ typedef void *voidp; ++#else ++ typedef Byte FAR *voidpf; ++ typedef Byte *voidp; ++#endif ++ ++#ifdef HAVE_UNISTD_H ++# include <sys/types.h> /* for off_t */ ++# include <unistd.h> /* for SEEK_* and off_t */ ++# define z_off_t off_t ++#endif ++#ifndef SEEK_SET ++# define SEEK_SET 0 /* Seek from beginning of file. */ ++# define SEEK_CUR 1 /* Seek from current position. */ ++# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ ++#endif ++#ifndef z_off_t ++# define z_off_t long ++#endif ++ ++/* MVS linker does not support external names larger than 8 bytes */ ++#if defined(__MVS__) ++# pragma map(deflateInit_,"DEIN") ++# pragma map(deflateInit2_,"DEIN2") ++# pragma map(deflateEnd,"DEEND") ++# pragma map(inflateInit_,"ININ") ++# pragma map(inflateInit2_,"ININ2") ++# pragma map(inflateEnd,"INEND") ++# pragma map(inflateSync,"INSY") ++# pragma map(inflateSetDictionary,"INSEDI") ++# pragma map(inflate_blocks,"INBL") ++# pragma map(inflate_blocks_new,"INBLNE") ++# pragma map(inflate_blocks_free,"INBLFR") ++# pragma map(inflate_blocks_reset,"INBLRE") ++# pragma map(inflate_codes_free,"INCOFR") ++# pragma map(inflate_codes,"INCO") ++# pragma map(inflate_fast,"INFA") ++# pragma map(inflate_flush,"INFLU") ++# pragma map(inflate_mask,"INMA") ++# pragma map(inflate_set_dictionary,"INSEDI2") ++# pragma map(ipcomp_inflate_copyright,"INCOPY") ++# pragma map(inflate_trees_bits,"INTRBI") ++# pragma map(inflate_trees_dynamic,"INTRDY") ++# pragma map(inflate_trees_fixed,"INTRFI") ++# pragma map(inflate_trees_free,"INTRFR") ++#endif ++ ++#endif /* _ZCONF_H */ diff --git a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/mkdep.patch b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/mkdep.patch index e69de29bb2..4daeaa11be 100644 --- a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/mkdep.patch +++ b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/mkdep.patch @@ -0,0 +1,16 @@ + +# +# Made by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux/Makefile~mkdep 2003-12-19 09:36:51.000000000 -0800 ++++ linux/Makefile 2003-12-19 09:57:44.000000000 -0800 +@@ -458,7 +458,7 @@ + + dep-files: scripts/mkdep archdep include/linux/version.h + scripts/mkdep -- init/*.c > .depend +- scripts/mkdep -- `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend ++ $(foreach, dir, $(FINDHPATH), scripts/mkdep -- `find $(dir) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` >> .hdepend) + $(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)" + ifdef CONFIG_MODVERSIONS + $(MAKE) update-modverfile diff --git a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh37.1/defconfig-ipaqsa b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh37.1/defconfig-ipaqsa index e69de29bb2..c440fd3d59 100644 --- a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh37.1/defconfig-ipaqsa +++ b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh37.1/defconfig-ipaqsa @@ -0,0 +1,1508 @@ +# +# Automatically generated make config: 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_PXA 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_S3C2410 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=y +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_AT91RM9200DK is not set +# CONFIG_MINIMAL_OOPS is not set + +# +# Linux As Bootldr support +# +# CONFIG_LAB is not set +# CONFIG_BIG_KERNEL is not set +# CONFIG_USE_DATE_CODE is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# 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_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CEP is not set +# CONFIG_SA1100_CERF is not set +CONFIG_SA1100_H3100=y +CONFIG_SA1100_H3600=y +CONFIG_SA1100_H3800=y +# CONFIG_SA1100_CONSUS 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_JORNADA56X 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=m +CONFIG_SA1100_USB_NETLINK=m +CONFIG_SA1100_USB_CHAR=m +CONFIG_REGISTERS=m + +# +# Intel PXA250/210 Implementations +# +# CONFIG_ARCH_LUBBOCK is not set +# CONFIG_ARCH_PXA_IDP is not set +# CONFIG_ARCH_PXA_CERF is not set +# CONFIG_ARCH_H3900 is not set +# CONFIG_ARCH_H1900 is not set +# CONFIG_ARCH_H5400 is not set +# CONFIG_ARCH_H2200 is not set +# CONFIG_ARCH_AXIM is not set +# CONFIG_PXA_USB is not set +# CONFIG_PXA_USB_NETLINK is not set +# CONFIG_PXA_USB_CHAR is not set + +# +# 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_P720T is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set + +# +# Processor Type +# +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 is not set +# 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_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +CONFIG_CPU_SA1100=y +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y +CONFIG_SA1100_IPAQ=y +# CONFIG_PXA_IPAQ is not set +CONFIG_IPAQ_HANDHELD=y + +# +# Compaq iPAQ Handheld +# +CONFIG_IPAQ_HAL=m +CONFIG_H3600_MICRO=m +CONFIG_IPAQ_HAS_ROSELLA=y +# CONFIG_IPAQ_HAS_ASIC3 is not set +CONFIG_H3600_ASIC=m +CONFIG_H3900_ASIC_DEBUG=y +# CONFIG_H5400_ASIC is not set +# CONFIG_H1900_ASIC is not set +# CONFIG_H1900_TS is not set +CONFIG_H3600_HARDWARE=y +CONFIG_IPAQ_SLEEVE=m +CONFIG_SLEEVE_DEBUG=y +CONFIG_SLEEVE_DEBUG_VERBOSE=0 +# CONFIG_SLEEVE_IRQ_DEMUX is not set + +# +# Processor Features +# +CONFIG_DISCONTIGMEM=y + +# +# General setup +# +# CONFIG_PCI is not set +CONFIG_ISA=y +# CONFIG_ISA_DMA is not set +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_CPU_FREQ=y +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +# CONFIG_PCMCIA_CLPS6700 is not set +CONFIG_PCMCIA_SA1100=m +# CONFIG_PCMCIA_PXA is not set +CONFIG_MERCURY_BACKPAQ=m + +# +# MMC/SD Card support +# +CONFIG_MMC=m +CONFIG_MMC_DEBUG=y +CONFIG_MMC_DEBUG_VERBOSE=0 +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# 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=y +CONFIG_APM=m +CONFIG_HWTIMER=m +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="keepinitrd" +# 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=y +CONFIG_MTD_DEBUG_VERBOSE=1 +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_GEOMETRY=y +# CONFIG_MTD_CFI_B1 is not set +CONFIG_MTD_CFI_B2=y +CONFIG_MTD_CFI_B4=y +# CONFIG_MTD_CFI_B8 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# 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 +# 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_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +CONFIG_MTD_IPAQ=y +# 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_LUBBOCK is not set +# CONFIG_MTD_EPXA10DB is not set +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_AUTCPU12 is not set +# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_H720X 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_MTDRAM=m +CONFIG_MTDRAM_TOTAL_SIZE=4096 +CONFIG_MTDRAM_ERASE_SIZE=128 +CONFIG_MTD_BLKMTD=m + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND 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_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +CONFIG_NVRD=m + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +# 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=m +CONFIG_BLK_DEV_DM=m + +# +# Networking options +# +CONFIG_PACKET=m +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +# CONFIG_IP_NF_AMANDA is not set +# CONFIG_IP_NF_TFTP is not set +CONFIG_IP_NF_IRC=m +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_MAC=m +# CONFIG_IP_NF_MATCH_PKTTYPE is not set +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +# CONFIG_IP_NF_MATCH_RECENT is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_DSCP is not set +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +# CONFIG_IP_NF_MATCH_HELPER is not set +CONFIG_IP_NF_MATCH_STATE=m +# CONFIG_IP_NF_MATCH_CONNTRACK is not set +# CONFIG_IP_NF_MATCH_UNCLEAN is not set +# CONFIG_IP_NF_MATCH_OWNER is not set +CONFIG_IP_NF_FILTER=m +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_MIRROR is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +# CONFIG_IP_NF_NAT_LOCAL is not set +# CONFIG_IP_NF_NAT_SNMP_BASIC is not set +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_DSCP is not set +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_ARPTABLES is not set +CONFIG_IP_NF_COMPAT_IPCHAINS=m +CONFIG_IP_NF_NAT_NEEDED=y +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IPV6=m +CONFIG_IPV6_SUBTREES=y +CONFIG_IPV6_TUNNEL=m +CONFIG_IPV6_MOBILITY=m +CONFIG_IPV6_MOBILITY_MN=m +# CONFIG_IPV6_MOBILITY_HA is not set +CONFIG_IPV6_MOBILITY_DEBUG=y + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +CONFIG_IP6_NF_MATCH_MULTIPORT=m +# CONFIG_IP6_NF_MATCH_OWNER is not set +CONFIG_IP6_NF_MATCH_MARK=m +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_AHESP is not set +# CONFIG_IP6_NF_MATCH_LENGTH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +# CONFIG_KHTTPD 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=m +# 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 +CONFIG_IPSEC=m + +# +# IPSec options (FreeS/WAN) +# +CONFIG_KLIPS_AUTH_HMAC_MD5=y +CONFIG_KLIPS_AUTH_HMAC_SHA1=y +CONFIG_KLIPS_ENC_3DES=y + +# +# ESP always enabled with tunnel mode +# +CONFIG_KLIPS_IPCOMP=y +CONFIG_KLIPS_DEBUG=y + +# +# 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=m +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K 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_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=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPP_MPPE is not set +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_AIRO is not set +# CONFIG_HERMES is not set +# CONFIG_SPECTRUM24T is not set + +# +# Wireless Pcmcia cards support +# +# CONFIG_PCMCIA_HERMES is not set +# CONFIG_AIRO_CS is not set +# CONFIG_WVLAN_CS is not set +# CONFIG_MWVLAN_CS is not set +# CONFIG_HOSTAP is not set +# CONFIG_HOSTAP_CS is not set +CONFIG_NET_WIRELESS=y +CONFIG_ATMELWLAN=y +# CONFIG_ATMELWLAN_USB_503A_RFMD is not set +CONFIG_ATMELWLAN_PCMCIA_502A=m +CONFIG_ATMELWLAN_PCMCIA_3COM=m +CONFIG_ATMELWLAN_PCMCIA_502AD=m +CONFIG_ATMELWLAN_PCMCIA_502AE=m +CONFIG_ATMELWLAN_PCMCIA_504=m + +# +# 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 + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_AXNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +CONFIG_NET_PCMCIA_RADIO=y +CONFIG_PCMCIA_RAYCS=m +CONFIG_PCMCIA_NETWAVE=m +CONFIG_PCMCIA_WAVELAN=m +# CONFIG_AIRONET4500_CS is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +CONFIG_IRDA=m + +# +# IrDA protocols +# +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +CONFIG_IRDA_ULTRA=y + +# +# IrDA options +# +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_DEBUG=y + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=m +CONFIG_IRPORT_SIR=m + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_NSC_FIR is not set +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +CONFIG_SA1100_FIR=m + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=m + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=m +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=m +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set + +# +# SCSI support +# +CONFIG_SCSI=m + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_SD_EXTRA_DEVS=40 +CONFIG_CHR_DEV_ST=m +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +CONFIG_SCSI_PCMCIA=y +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_QLOGIC 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=m +CONFIG_INPUT_KEYBDEV=m +CONFIG_INPUT_MOUSEDEV=m +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_UINPUT=m + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=m +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_S3C2410 is not set +# CONFIG_SERIAL_S3C2410_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=y +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_SA1100_DEFAULT_BAUDRATE=115200 +CONFIG_SERIAL_H3800_ASIC=m +# CONFIG_SERIAL_SIR_PXA is not set +# 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=y +CONFIG_UNIX98_PTY_COUNT=32 +CONFIG_NEWTONKBD=m +CONFIG_SA1100_PROFILER=m + +# +# Compaq iPAQ H3600 support +# +CONFIG_TOUCHSCREEN_H3600=m +CONFIG_H3600_BACKPAQ_FPGA=m +CONFIG_H3600_BACKPAQ_ACCEL=m +CONFIG_H3600_BACKPAQ_GASGAUGE=m +CONFIG_H3600_BACKPAQ_SRAM=m +CONFIG_H3600_BACKPAQ_AUDIO=m +CONFIG_H3600_STOWAWAY=m +CONFIG_H3800_MICROKBD=m +CONFIG_SA1100_LIRC=m +# CONFIG_H5400_BUZZER is not set +# CONFIG_H5400_FSI is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +CONFIG_L3=y +CONFIG_L3_ALGOBIT=y +CONFIG_L3_BIT_SA1100_GPIO=y + +# +# Other L3 adapters +# +# CONFIG_L3_S3C2410 is not set +# CONFIG_L3_SA1111 is not set +CONFIG_L3_BACKPAQ=m +CONFIG_BIT_SA1100_GPIO=y + +# +# SPI support +# +# CONFIG_SPI is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=m +# CONFIG_PSMOUSE is not set +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +CONFIG_INPUT_SERIO=m +CONFIG_INPUT_SERPORT=m + +# +# Joysticks +# +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_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=m +# CONFIG_PXA_WATCHDOG is not set +# CONFIG_OMAHA_WATCHDOG is not set +# 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_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_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_SA1100_RTC=m +# CONFIG_PXA_RTC_HACK is not set +# 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 +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +CONFIG_PCMCIA_SERIAL_CS=m +# CONFIG_PCMCIA_MOBILISCAN_CS is not set +# CONFIG_AXIM_KEY_FIX is not set + +# +# Multimedia devices +# +CONFIG_MEDIA=m +CONFIG_VIDEO_DEV=m +CONFIG_V4L2_DEV=m + +# +# Video For Linux +# +CONFIG_VIDEO_PROC_FS=y +# CONFIG_I2C_PARPORT is not set + +# +# Video Adapters +# +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_STRADIS is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_ZORAN_BUZ is not set +# CONFIG_VIDEO_ZORAN_DC10 is not set +# CONFIG_VIDEO_ZORAN_LML33 is not set +# CONFIG_VIDEO_ZR36120 is not set +# CONFIG_VIDEO_MEYE is not set +# CONFIG_VIDEO_CYBERPRO is not set +CONFIG_VIDEO_H3600_BACKPAQ=m +# CONFIG_VIDEO_HAWKEYE is not set + +# +# Video for Linux 2 (V4L2) +# +CONFIG_VIDEO_WINNOV_CS=m + +# +# Radio Adapters +# +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_GEMTEK_PCI is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_MAESTRO is not set +# CONFIG_RADIO_MIROPCM20 is not set +# CONFIG_RADIO_MIROPCM20_RDS is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=m +CONFIG_REISERFS_FS=m +# 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_BFS_FS is not set +CONFIG_EXT3_FS=m +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_UMSDOS_FS=m +CONFIG_VFAT_FS=m +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +CONFIG_CRAMFS=y +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=m +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS 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_DRIVERFS_FS is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=m +# 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 + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +CONFIG_NFSD=m +CONFIG_NFSD_V3=y +CONFIG_SUNRPC=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT 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=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=m +CONFIG_NLS_CODEPAGE_737=m +CONFIG_NLS_CODEPAGE_775=m +CONFIG_NLS_CODEPAGE_850=m +CONFIG_NLS_CODEPAGE_852=m +CONFIG_NLS_CODEPAGE_855=m +CONFIG_NLS_CODEPAGE_857=m +CONFIG_NLS_CODEPAGE_860=m +CONFIG_NLS_CODEPAGE_861=m +CONFIG_NLS_CODEPAGE_862=m +CONFIG_NLS_CODEPAGE_863=m +CONFIG_NLS_CODEPAGE_864=m +CONFIG_NLS_CODEPAGE_865=m +CONFIG_NLS_CODEPAGE_866=m +CONFIG_NLS_CODEPAGE_869=m +CONFIG_NLS_CODEPAGE_936=m +CONFIG_NLS_CODEPAGE_950=m +CONFIG_NLS_CODEPAGE_932=m +CONFIG_NLS_CODEPAGE_949=m +CONFIG_NLS_CODEPAGE_874=m +CONFIG_NLS_ISO8859_8=m +CONFIG_NLS_CODEPAGE_1250=m +CONFIG_NLS_CODEPAGE_1251=m +CONFIG_NLS_ISO8859_1=m +CONFIG_NLS_ISO8859_2=m +CONFIG_NLS_ISO8859_3=m +CONFIG_NLS_ISO8859_4=m +CONFIG_NLS_ISO8859_5=m +CONFIG_NLS_ISO8859_6=m +CONFIG_NLS_ISO8859_7=m +CONFIG_NLS_ISO8859_9=m +CONFIG_NLS_ISO8859_13=m +CONFIG_NLS_ISO8859_14=m +CONFIG_NLS_ISO8859_15=m +CONFIG_NLS_KOI8_R=m +CONFIG_NLS_KOI8_U=m +CONFIG_NLS_UTF8=m + +# +# Console drivers +# +CONFIG_PC_KEYMAP=y +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_ACORN is not set +# CONFIG_FB_ANAKIN is not set +# CONFIG_FB_CLPS711X is not set +# CONFIG_FB_S3C2410 is not set +CONFIG_FB_SA1100=y +# CONFIG_FB_EPSON1356 is not set +# CONFIG_FB_MQ200 is not set +# CONFIG_FB_PXA is not set +# CONFIG_FB_MQ1100 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +CONFIG_FBCON_CFB4=y +# CONFIG_FBCON_CFB8 is not set +CONFIG_FBCON_CFB16=y +# CONFIG_FBCON_CFB24 is not set +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +# CONFIG_FBCON_NO_LOGO is not set +CONFIG_FBCON_FONTWIDTH8_ONLY=y +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +CONFIG_SOUND_SA1100=m +CONFIG_SOUND_UDA1341=m +# CONFIG_SOUND_SA1100_MONO is not set +# CONFIG_SOUND_ASSABET_UDA1341 is not set +CONFIG_SOUND_H3600_UDA1341=m +# CONFIG_SOUND_PANGOLIN_UDA1341 is not set +# CONFIG_SOUND_SA1111_UDA1341 is not set +# CONFIG_SOUND_SA1100SSP is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_VIDC is not set +# CONFIG_SOUND_WAVEARTIST is not set +# CONFIG_SOUND_PXA_AC97 is not set +# CONFIG_SOUND_TVMIXER 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 +# CONFIG_MCP_UCB1400_TS is not set + +# +# Console Switches +# +# CONFIG_SWITCHES is not set + +# +# USB support +# +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_LONG_TIMEOUT is not set + +# +# USB Host Controller Drivers +# +# 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_OHCI_H5400 is not set +# CONFIG_USB_OHCI_S3C2410 is not set +CONFIG_USB_SL811HS=m + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_BLUETOOTH is not set +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_ACM is not set +CONFIG_USB_PRINTER=m + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT=y +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_WACOM is not set + +# +# USB Imaging devices +# +# CONFIG_USB_DC2XX is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +CONFIG_USB_IBMCAM=m +CONFIG_USB_OV511=m +CONFIG_USB_PWC=m +CONFIG_USB_SE401=m +CONFIG_USB_STV680=m +CONFIG_USB_VICAM=m +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DABUSB is not set + +# +# USB Network adaptors +# +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +CONFIG_USB_CDCETHER=m +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# 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 + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_BRLVGER is not set + +# +# Linux As Bootldr Modules +# +# CONFIG_BIG_KERNEL is not set +# CONFIG_USE_DATE_CODE is not set +# CONFIG_YMODEM is not set +# CONFIG_LAB_DUMMY is not set +# CONFIG_LAB_CRC is not set +# CONFIG_LAB_YMODEM is not set +# CONFIG_LAB_MTD is not set +# CONFIG_LAB_COPY is not set +# CONFIG_LAB_COPY_YMODEM is not set +# CONFIG_LAB_COPY_FLASH is not set +# CONFIG_LAB_COPY_FS is not set +# CONFIG_LAB_COPY_WRAPPER is not set + +# +# Bluetooth support +# +CONFIG_BLUEZ=m +CONFIG_BLUEZ_L2CAP=m +CONFIG_BLUEZ_SCO=m +CONFIG_BLUEZ_RFCOMM=m +CONFIG_BLUEZ_RFCOMM_TTY=y +CONFIG_BLUEZ_BNEP=m +CONFIG_BLUEZ_BNEP_MC_FILTER=y +CONFIG_BLUEZ_BNEP_PROTO_FILTER=y + +# +# Bluetooth device drivers +# +# CONFIG_BLUEZ_HCIUSB is not set +CONFIG_BLUEZ_HCIUART=m +CONFIG_BLUEZ_HCIUART_H4=y +CONFIG_BLUEZ_HCIUART_BCSP=y +# CONFIG_BLUEZ_HCIUART_BCSP_TXCRC is not set +# CONFIG_BLUEZ_HCIBFUSB is not set +CONFIG_BLUEZ_HCIDTL1=m +CONFIG_BLUEZ_HCIBT3C=m +CONFIG_BLUEZ_HCIBLUECARD=m +CONFIG_BLUEZ_HCIBTUART=m +# CONFIG_BLUEZ_HCIVHCI is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# 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=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +# CONFIG_CRC32 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/linux/handhelds-sa-2.6/defconfig-jornada56x b/linux/handhelds-sa-2.6/defconfig-jornada56x index e69de29bb2..ebc9a88f2c 100644 --- a/linux/handhelds-sa-2.6/defconfig-jornada56x +++ b/linux/handhelds-sa-2.6/defconfig-jornada56x @@ -0,0 +1,877 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_HOTPLUG=y +# CONFIG_IKCONFIG is not set +# CONFIG_MINIMAL_OOPS is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODULE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# 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_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +CONFIG_ARCH_SA1100=y +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE_PB is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_COLLIE is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_BADGE4 is not set +CONFIG_SA1100_JORNADA56X=y +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HACKKIT 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_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_STORK is not set +# CONFIG_SA1100_SSP is not set +CONFIG_SA1100_USB=y +CONFIG_SA1100_USB_NETLINK=y +# CONFIG_SA1100_USB_CHAR is not set + +# +# Linux As Bootloader +# +# CONFIG_LAB is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_SA1100=y +CONFIG_CPU_32v4=y +CONFIG_CPU_ABRT_EV4=y +CONFIG_CPU_CACHE_V4WB=y +CONFIG_CPU_TLB_V4WB=y +CONFIG_CPU_MINICACHE=y + +# +# Processor Features +# +# CONFIG_ARM_FASTCALL is not set + +# +# Compaq/iPAQ Options +# + +# +# General setup +# +CONFIG_DISCONTIGMEM=y +CONFIG_ISA=y +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +# CONFIG_CPU_FREQ is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +CONFIG_PCMCIA_SA1100=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +# CONFIG_VFP is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_MISC=y + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=m +# CONFIG_SOC_DEVICE is not set +# CONFIG_DOCKING_HOTPLUG is not set +CONFIG_PM=y +CONFIG_PREEMPT=y +CONFIG_APM=y +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="" +# 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=y +CONFIG_MTD_DEBUG_VERBOSE=3 +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=m +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +CONFIG_MTD_SA1100=y +# CONFIG_MTD_EDB7312 is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# Plug and Play support +# +# CONFIG_PNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_RAM is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +# CONFIG_IPV6 is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +CONFIG_BT=m +# CONFIG_BT_L2CAP is not set +# CONFIG_BT_SCO is not set + +# +# Bluetooth device drivers +# +# CONFIG_BT_HCIUART is not set +CONFIG_BT_HCIDTL1=m +CONFIG_BT_HCIBT3C=m +CONFIG_BT_HCIBLUECARD=m +CONFIG_BT_HCIBTUART=m +# CONFIG_BT_HCIVHCI is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set +CONFIG_MII=m + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y + +# +# Obsolete Wireless cards support (pre-802.11) +# +# CONFIG_STRIP is not set +CONFIG_ARLAN=m +CONFIG_WAVELAN=m +CONFIG_PCMCIA_WAVELAN=m +# CONFIG_PCMCIA_NETWAVE is not set + +# +# Wireless 802.11 Frequency Hopping cards support +# +# CONFIG_PCMCIA_RAYCS is not set + +# +# Wireless 802.11b ISA/PCI cards support +# +CONFIG_HERMES=m +# CONFIG_ATMEL is not set + +# +# Wireless 802.11b Pcmcia/Cardbus cards support +# +CONFIG_PCMCIA_HERMES=m +CONFIG_AIRO_CS=m +# CONFIG_PCMCIA_WL3501 is not set +CONFIG_NET_WIRELESS=y +# CONFIG_HOSTAP is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +# CONFIG_PCMCIA_AXNET is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_PPP=m +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=m +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=m +CONFIG_BLK_DEV_IDE=m + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +CONFIG_BLK_DEV_IDECS=m +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=m +# CONFIG_IDE_ARM is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_DEV_IDEDMA is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=640 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=240 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_TSDEV=y +CONFIG_INPUT_TSDEV_SCREEN_X=240 +CONFIG_INPUT_TSDEV_SCREEN_Y=320 +# CONFIG_INPUT_TSLIBDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +# CONFIG_SERIO is not set +# CONFIG_SERIO_I8042 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_DZ is not set +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +CONFIG_SA1100_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_RAW_DRIVER is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# File systems +# +CONFIG_EXT2_FS=m +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=m +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=m +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_REISERFS_FS_XATTR is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS4_FS=y + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +CONFIG_DEVFS_DEBUG=y +# CONFIG_DEVPTS_FS_XATTR is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS 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_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_CRAMFS=m +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=m +# CONFIG_RPCSEC_GSS_KRB5 is not set +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set + +# +# Native Language Support +# +CONFIG_NLS=m +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +CONFIG_FB=y +CONFIG_FB_MODES=y +CONFIG_LCD_CLASS_DEVICE=y +CONFIG_LCD_DEVICE=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_DEVICE=y +CONFIG_FB_SA1100=y +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FONTS=y +# CONFIG_FONT_8x8 is not set +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +CONFIG_FONT_MINI_4x6=y +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Misc devices +# + +# +# SoC drivers +# +# CONFIG_BATTERY_MONITOR is not set + +# +# USB support +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_KERNEL is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC_CCITT=m +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/linux/linux-bast-2.4.25-vrs1-bast1/defconfig b/linux/linux-bast-2.4.25-vrs1-bast1/defconfig index e69de29bb2..1dc6f19154 100644 --- a/linux/linux-bast-2.4.25-vrs1-bast1/defconfig +++ b/linux/linux-bast-2.4.25-vrs1-bast1/defconfig @@ -0,0 +1,1115 @@ +# +# 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 is not set + +# +# 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_BAST=y +# CONFIG_ARCH_AT91RM9200 is not set + +# +# 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 + +# +# 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 is not set +CONFIG_CPU_ARM920T=y +CONFIG_CPU_S3C2410X=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=y +# 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=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="root=/dev/hda1 ro" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +CONFIG_PARPORT=y +CONFIG_PARPORT_PC=y +# CONFIG_PARPORT_PC_FIFO is not set +CONFIG_PARPORT_PC_SUPERIO=y +# CONFIG_PARPORT_PC_PCMCIA is not set +# CONFIG_PARPORT_ARC is not set +# CONFIG_PARPORT_IDP is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_SUNBPP is not set +# CONFIG_PARPORT_IP22 is not set +CONFIG_PARPORT_OTHER=y +CONFIG_PARPORT_1284=y + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +CONFIG_MTD_DEBUG=y +CONFIG_MTD_DEBUG_VERBOSE=1 +CONFIG_MTD_PARTITIONS=y +CONFIG_MTD_CONCAT=y +CONFIG_MTD_REDBOOT_PARTS=y +# CONFIG_MTD_CMDLINE_PARTS is not set +CONFIG_MTD_AFS_PARTS=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +CONFIG_NFTL=y +CONFIG_NFTL_RW=y + +# +# 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=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_RAM=y +CONFIG_MTD_ROM=y +CONFIG_MTD_ABSENT=y +# 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 is not set +# 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_BAST 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_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=y +CONFIG_MTD_NAND_IDS=y + +# +# 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=y +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +# 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=y +CONFIG_NETLINK_DEV=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_DEBUG=y +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# 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=y +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS 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_NE2K_BAST=y +CONFIG_DM9000_BAST=y +# 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_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +CONFIG_NET_ISA=y +# CONFIG_E2100 is not set +# CONFIG_EWRK3 is not set +# CONFIG_EEXPRESS is not set +# CONFIG_EEXPRESS_PRO is not set +# CONFIG_HPLAN_PLUS is not set +# CONFIG_HPLAN is not set +# CONFIG_LP486E is not set +# CONFIG_ETH16I is not set +# CONFIG_NE2000 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=y +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_SMART=y +CONFIG_SLIP_MODE_SLIP6=y + +# +# 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=y +CONFIG_IRLAN=y +# CONFIG_IRNET is not set +CONFIG_IRCOMM=y +CONFIG_IRDA_ULTRA=y +CONFIG_IRDA_CACHE_LAST_LSAP=y +CONFIG_IRDA_FAST_RR=y +CONFIG_IRDA_DEBUG=y + +# +# Infrared-port device drivers +# +# CONFIG_IRTTY_SIR is not set +# CONFIG_IRPORT_SIR is not set +# CONFIG_DONGLE is not set +# CONFIG_USB_IRDA is not set +CONFIG_NSC_FIR=y +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_OLD is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set +# CONFIG_VIA_IRCC_FIR is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +CONFIG_BLK_DEV_IDE_BAST=y +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set +# CONFIG_BLK_DEV_ATARAID_SII 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=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=y +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_MX1TS is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_DUMMY_KEYB=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 is not set +# CONFIG_SERIAL_AT91_CONSOLE is not set +CONFIG_SERIAL_S3C2410X=y +CONFIG_SERIAL_S3C2410X_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=y +CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_PRINTER=y +# CONFIG_LP_CONSOLE is not set +CONFIG_PPDEV=y +# CONFIG_TIPAR is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +CONFIG_I2C_PHILIPSPAR=y +# CONFIG_I2C_ELV is not set +# CONFIG_I2C_VELLEMAN is not set +# CONFIG_SCx200_I2C is not set +# CONFIG_I2C_GUIDE is not set +CONFIG_I2C_S3C2410BIT=y +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_PROC=y +# CONFIG_I2C_DS1307 is not set + +# +# 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=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +# CONFIG_INPUT_SERIO is not set +# CONFIG_INPUT_SERPORT is not set +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX 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 is not set +# 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_S3C2410_WATCHDOG=y +# CONFIG_AT91_WATCHDOG is not set +# 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_BAST_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=y +# 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=y +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +CONFIG_JFFS_FS=y +CONFIG_JFFS_FS_VERBOSE=0 +CONFIG_JFFS_PROC_FS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +CONFIG_CRAMFS=y +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +# 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 is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=y +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=y + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +CONFIG_NLS_CODEPAGE_850=y +CONFIG_NLS_CODEPAGE_852=y +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_ACORN is not set +# CONFIG_FB_ANAKIN is not set +# CONFIG_FB_CLPS711X is not set +# CONFIG_FB_SA1100 is not set +CONFIG_FB_S3C2410=y +# CONFIG_FB_DBMX1 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +CONFIG_FBCON_CFB4=y +CONFIG_FBCON_CFB8=y +# CONFIG_FBCON_CFB16 is not set +# CONFIG_FBCON_CFB24 is not set +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +CONFIG_FONT_ACORN_8x8=y + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_ALI5455 is not set +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_FORTE is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +CONFIG_SOUND_S3C2410=y +CONFIG_SOUND_S3C2410_TLV320AIC23=y +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_VIDC is not set +# CONFIG_SOUND_WAVEARTIST is not set +# CONFIG_SOUND_TVMIXER is not set +# CONFIG_SOUND_AD1980 is not set +# CONFIG_SOUND_WM97XX 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=y +CONFIG_USB_DEBUG=y +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH 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_OHCI_S3C2410=y +# CONFIG_USB_SL811HS_ALT is not set +# CONFIG_USB_SL811HS is not set +# 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 +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# 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=y +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +CONFIG_USB_HIDDEV=y +# 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 +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDCETHER is not set +CONFIG_USB_USBNET=y +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=y +# CONFIG_USB_SERIAL_DEBUG 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=y +# 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_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +CONFIG_USB_SERIAL_PL2303=y +# 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 +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_INFO=y +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_SLAB=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_WAITQ=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set +CONFIG_DEBUG_S3C2410X_UART0=y + +# +# Library routines +# +# CONFIG_CRC32 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/linux/linux-bast-2.4.25-vrs1-bast1/mkdep.patch b/linux/linux-bast-2.4.25-vrs1-bast1/mkdep.patch index e69de29bb2..57218a7d1a 100644 --- a/linux/linux-bast-2.4.25-vrs1-bast1/mkdep.patch +++ b/linux/linux-bast-2.4.25-vrs1-bast1/mkdep.patch @@ -0,0 +1,16 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux-2.4.25/Makefile~mkdep 2004-03-31 17:15:12.000000000 +0200 ++++ linux-2.4.25/Makefile 2004-03-31 17:18:50.000000000 +0200 +@@ -502,7 +502,7 @@ + ifdef CONFIG_MODVERSIONS + $(MAKE) update-modverfile + endif +- scripts/mkdep -- `find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend ++ $(foreach, dir, $(FINDHPATH), scripts/mkdep -- `find $(dir) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` >> .hdepend) + scripts/mkdep -- init/*.c > .depend + + ifdef CONFIG_MODVERSIONS diff --git a/linux/linux-mtx-1-2.4.24/defconfig-mtx-1 b/linux/linux-mtx-1-2.4.24/defconfig-mtx-1 index e69de29bb2..84ab6de3a8 100644 --- a/linux/linux-mtx-1-2.4.24/defconfig-mtx-1 +++ b/linux/linux-mtx-1-2.4.24/defconfig-mtx-1 @@ -0,0 +1,1265 @@ +# +# Automatically generated by make menuconfig: don't edit +# +CONFIG_MIPS=y +CONFIG_MIPS32=y +# CONFIG_MIPS64 is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Machine selection +# +# CONFIG_ACER_PICA_61 is not set +# CONFIG_MIPS_BOSPORUS is not set +# CONFIG_MIPS_MIRAGE is not set +# CONFIG_MIPS_DB1000 is not set +# CONFIG_MIPS_DB1100 is not set +# CONFIG_MIPS_DB1500 is not set +# CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1100 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_MIPS_HYDROGEN3 is not set +# CONFIG_MIPS_PB1550 is not set +# CONFIG_MIPS_XXS1500 is not set +CONFIG_MIPS_MTX1=y +# CONFIG_COGENT_CSB250 is not set +# CONFIG_BAGET_MIPS is not set +# CONFIG_CASIO_E55 is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_DECSTATION is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_IBM_WORKPAD is not set +# CONFIG_LASAT is not set +# CONFIG_MIPS_ITE8172 is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_SEAD is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_MOMENCO_OCELOT_G is not set +# CONFIG_MOMENCO_OCELOT_C is not set +# CONFIG_MOMENCO_JAGUAR_ATX is not set +# CONFIG_PMC_YOSEMITE is not set +# CONFIG_DDB5074 is not set +# CONFIG_DDB5476 is not set +# CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set +# CONFIG_NEC_EAGLE is not set +# CONFIG_OLIVETTI_M700 is not set +# CONFIG_NINO is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SIBYTE_SB1xxx_SOC is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_TANBAC_TB0226 is not set +# CONFIG_TANBAC_TB0229 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_TOSHIBA_RBTX4927 is not set +# CONFIG_VICTOR_MPC30X is not set +# CONFIG_ZAO_CAPCELLA is not set +# CONFIG_HIGHMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_SOC_AU1X00=y +CONFIG_SOC_AU1500=y +CONFIG_NEW_TIME_C=y +CONFIG_PCI=y +CONFIG_NEW_PCI=y +CONFIG_PCI_AUTO=y +# CONFIG_NONCOHERENT_IO is not set +# CONFIG_MIPS_AU1000 is not set + +# +# CPU selection +# +CONFIG_CPU_MIPS32=y +# CONFIG_CPU_MIPS64 is not set +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_RM9000 is not set +# CONFIG_CPU_SB1 is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +CONFIG_CPU_HAS_PREFETCH=y +# CONFIG_VTAG_ICACHE is not set +CONFIG_64BIT_PHYS_ADDR=y +# CONFIG_CPU_ADVANCED is not set +CONFIG_CPU_HAS_LLSC=y +# CONFIG_CPU_HAS_LLDSCD is not set +# CONFIG_CPU_HAS_WB is not set +CONFIG_CPU_HAS_SYNC=y + +# +# General setup +# +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_NET=y +CONFIG_PCI_NAMES=y +# CONFIG_ISA is not set +# CONFIG_TC is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HOTPLUG_PCI_COMPAQ is not set +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_MIPS32_COMPAT is not set +# CONFIG_MIPS32_O32 is not set +# CONFIG_MIPS32_N32 is not set +# CONFIG_BINFMT_ELF32 is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_OOM_KILLER is not set +# CONFIG_PM is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_CFI_AMDSTD_RETRY=y +CONFIG_MTD_CFI_AMDSTD_RETRY_MAX=5 +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# 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_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_DB1X00 is not set +CONFIG_MTD_MTX1=y +# CONFIG_MTD_CSTM_MIPS_IXX is not set +# CONFIG_MTD_OCELOT is not set +# CONFIG_MTD_LASAT 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_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT 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=y +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=m +CONFIG_BLK_DEV_RAM_SIZE=4096 +# 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=y +CONFIG_NETLINK_DEV=m +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_AMANDA=m +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_PKTTYPE=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_DSCP=m +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_HELPER=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +CONFIG_IP_NF_MATCH_UNCLEAN=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_MATCH_PHYSDEV=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_MIRROR=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_NAT_AMANDA=m +# CONFIG_IP_NF_NAT_LOCAL is not set +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_NAT_TFTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_DSCP=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +CONFIG_IPV6=m + +# +# IPv6: Netfilter Configuration +# +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_MULTIPORT=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_MARK=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AHESP=m +CONFIG_IP6_NF_MATCH_LENGTH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +# CONFIG_KHTTPD is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IPV6_SCTP__=m +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +CONFIG_VLAN_8021Q=m +# 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=m +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_IPF=m +CONFIG_BRIDGE_EBT_ARPF=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_VLANF=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_MARKF=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_MARK_T=m +# 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=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +CONFIG_NET_PKTGEN=m +CONFIG_IPSEC=m +CONFIG_IPSEC_IPIP=y +CONFIG_IPSEC_AH=y +CONFIG_IPSEC_AUTH_HMAC_MD5=y +CONFIG_IPSEC_AUTH_HMAC_SHA1=y +CONFIG_IPSEC_ESP=y +CONFIG_IPSEC_ENC_3DES=y +CONFIG_IPSEC_IPCOMP=y +# CONFIG_IPSEC_DEBUG is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 +# CONFIG_CHR_DEV_SG is not set +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_MEGARAID2 is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_BOOT is not set +# CONFIG_FUSION_ISENSE is not set +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LAN is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI 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 + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=m +CONFIG_BONDING=m +# CONFIG_EQUALIZER is not set +CONFIG_TUN=m +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MIPS_AU1X00_ENET=y +# CONFIG_BCM5222_DUAL_PHY is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL 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_HP100 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=m +CONFIG_PPP_MULTILINK=y +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPPOE=m +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +CONFIG_AIRONET4500=m +CONFIG_AIRONET4500_NONCS=m +# CONFIG_AIRONET4500_PNP is not set +CONFIG_AIRONET4500_PCI=y +# CONFIG_AIRONET4500_ISA is not set +# CONFIG_AIRONET4500_I365 is not set +CONFIG_AIRONET4500_PROC=m +CONFIG_AIRO=m +# CONFIG_HERMES is not set +# CONFIG_PLX_HERMES is not set +# CONFIG_TMD_HERMES is not set +# CONFIG_PCI_HERMES is not set +CONFIG_NET_WIRELESS=y + +# +# 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 + +# +# 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 + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_DIGI is not set +# CONFIG_ESPSERIAL is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_ISI is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_N_HDLC is not set +# CONFIG_RISCOM8 is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +# CONFIG_STALDRV is not set +# CONFIG_SERIAL_TX3912 is not set +# CONFIG_SERIAL_TX3912_CONSOLE is not set +# CONFIG_SERIAL_TXX9 is not set +# CONFIG_SERIAL_TXX9_CONSOLE is not set +CONFIG_AU1X00_UART=y +CONFIG_AU1X00_SERIAL_CONSOLE=y +# CONFIG_AU1X00_USB_TTY is not set +# CONFIG_AU1X00_USB_RAW is not set +# CONFIG_TXX927_SERIAL is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C 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 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_MIPS_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 +CONFIG_AU1X00_GPIO=m +# CONFIG_TS_AU1X00_ADS7846 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=m +# 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=m +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=m +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +# 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=m +# 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=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=m +# 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=y +CONFIG_NFSD_V3=y +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT 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=m + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_SMB_NLS=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-15" +CONFIG_NLS_CODEPAGE_437=m +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +CONFIG_NLS_CODEPAGE_850=m +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ISO8859_1=m +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +CONFIG_NLS_ISO8859_15=m +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=m + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# +# CONFIG_VIDEO_PROC_FS is not set +# CONFIG_I2C_PARPORT is not set +# CONFIG_VIDEO_BT848 is not set +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_STRADIS is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_ZORAN_BUZ is not set +# CONFIG_VIDEO_ZORAN_DC10 is not set +# CONFIG_VIDEO_ZORAN_LML33 is not set +# CONFIG_VIDEO_ZR36120 is not set +# CONFIG_VIDEO_MEYE is not set + +# +# Radio Adapters +# +# CONFIG_RADIO_GEMTEK_PCI is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_MAESTRO is not set +# CONFIG_RADIO_MIROPCM20 is not set + +# +# Sound +# +CONFIG_SOUND=m +# CONFIG_SOUND_ALI5455 is not set +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_FORTE is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_AU1X00 is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +CONFIG_SOUND_OSS=m +# CONFIG_SOUND_TRACEINIT is not set +# CONFIG_SOUND_DMAP is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_AD1889 is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_ADLIB is not set +# CONFIG_SOUND_ACI_MIXER is not set +# CONFIG_SOUND_CS4232 is not set +# CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_NM256 is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_PAS is not set +# CONFIG_PAS_JOYSTICK is not set +# CONFIG_SOUND_PSS is not set +# CONFIG_SOUND_SB is not set +# CONFIG_SOUND_AWE32_SYNTH is not set +# CONFIG_SOUND_KAHLUA is not set +# CONFIG_SOUND_WAVEFRONT is not set +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_YM3812 is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_YMFPCI is not set +# CONFIG_SOUND_YMFPCI_LEGACY is not set +# CONFIG_SOUND_UART6850 is not set +# CONFIG_SOUND_AEDSP16 is not set +# CONFIG_SOUND_TVMIXER is not set +# CONFIG_SOUND_AD1980 is not set +# CONFIG_SOUND_WM97XX is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +# CONFIG_USB_DEVICEFS is not set +# CONFIG_USB_BANDWIDTH 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=y +CONFIG_USB_NON_PCI_OHCI=y +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_MIDI is not set +CONFIG_USB_STORAGE=y +CONFIG_USB_STORAGE_DEBUG=y +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +CONFIG_USB_STORAGE_SDDR09=y +# CONFIG_USB_STORAGE_SDDR55 is not set +CONFIG_USB_STORAGE_JUMPSHOT=y +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_HID is not set +# CONFIG_USB_HIDINPUT is not set +# 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=m +CONFIG_USB_MDC800=m +CONFIG_USB_SCANNER=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_HPUSBSCSI=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_KONICAWC=m +CONFIG_USB_OV511=m +CONFIG_USB_PWC=m +CONFIG_USB_SE401=m +CONFIG_USB_STV680=m +# CONFIG_USB_W9968CF is not set +CONFIG_USB_VICAM=m +CONFIG_USB_DSBR=m +CONFIG_USB_DABUSB=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_KAWETH=m +CONFIG_USB_CATC=m +CONFIG_USB_AX8817X=m +CONFIG_USB_CDCETHER=m +CONFIG_USB_USBNET=m +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_DEBUG is not set +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_RIO500=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_TIGL=m +CONFIG_USB_BRLVGER=m +CONFIG_USB_LCD=m + +# +# Support for USB gadgets +# +# CONFIG_USB_GADGET is not set + +# +# USB clients (devices, not hosts) +# +CONFIG_USBD=m +CONFIG_USBD_HIGH_SPEED=y +# CONFIG_USBD_NO_SERIAL_NUMBER is not set +CONFIG_USBD_SERIAL_NUMBER_STR="" +CONFIG_USBD_MAXPOWER=0 +CONFIG_USBD_PROCFS=y +CONFIG_USBD_PROCFSM=m + +# +# Network Function +# +CONFIG_USBD_NETWORK=m +CONFIG_USBD_NETWORK_VENDORID=2001 +CONFIG_USBD_NETWORK_PRODUCTID=1a00 +CONFIG_USBD_NETWORK_BCDDEVICE=0100 +CONFIG_USBD_NETWORK_MANUFACTURER="Belcarra" +CONFIG_USBD_NETWORK_PRODUCT_NAME="Belcarra BLAN Device" +CONFIG_USBD_NETWORK_BLAN=y +CONFIG_USBD_NETWORK_BLAN_DESC="BLAN Net Cfg" +CONFIG_USBD_NETWORK_BLAN_INTF="Comm/Data Intf" +CONFIG_USBD_NETWORK_BLAN_CRC=y +CONFIG_USBD_NETWORK_BLAN_PADBEFORE=y +CONFIG_USBD_NETWORK_BLAN_PADAFTER=y +CONFIG_USBD_NETWORK_BLAN_PADBYTES=8 +CONFIG_USBD_NETWORK_BLAN_FERMAT=y +CONFIG_USBD_NETWORK_BLAN_DO_NOT_SETTIME=y +# CONFIG_USBD_NETWORK_BLAN_HOSTNAME is not set +CONFIG_USBD_NETWORK_BLAN_NONBRIDGED=y +# CONFIG_USBD_NETWORK_SAFE is not set +CONFIG_USBD_NETWORK_CDC=y +CONFIG_USBD_NETWORK_CDC_DESC="SAFE Net Cfg" +CONFIG_USBD_NETWORK_CDC_COMM_INTF="Comm Intf" +CONFIG_USBD_NETWORK_CDC_NODATA_INTF="Data (Disabled) Intf" +CONFIG_USBD_NETWORK_CDC_DATA_INTF="Dat Intf" +# CONFIG_USBD_NETWORK_BASIC is not set +# CONFIG_USBD_NETWORK_BASIC2 is not set +CONFIG_USBD_NETWORK_START_SINGLE=y +CONFIG_USBD_NETWORK_EP0TEST=y + +# +# CDC ACM Function +# +CONFIG_USBD_ACM=m +CONFIG_USBD_ACM_VENDORID=12b9 +CONFIG_USBD_ACM_PRODUCTID=f002 +CONFIG_USBD_ACM_BCDDEVICE=0100 +CONFIG_USBD_ACM_MANUFACTURER="Belcarra" +CONFIG_USBD_ACM_PRODUCT_NAME="Belcarra ACM Device" +CONFIG_USBD_ACM_DESC="Acm Cfg" +CONFIG_USBD_ACM_COMM_INTF="Comm Intf" +CONFIG_USBD_ACM_DATA_INTF="Data Intf" +CONFIG_USBD_ACM_TRACE=y + +# +# Random Mouse Function +# +CONFIG_USBD_MOUSE=m +CONFIG_USBD_MOUSE_VENDORID=12b9 +CONFIG_USBD_MOUSE_PRODUCTID=f003 +CONFIG_USBD_MOUSE_BCDDEVICE=0100 +CONFIG_USBD_MOUSE_MANUFACTURER="Belcarra" +CONFIG_USBD_MOUSE_DESC="Acm Cfg" +CONFIG_USBD_MOUSE_COMM_INTF="Comm Intf" +CONFIG_USBD_MOUSE_BH=y + +# +# AMD AU1X000 Bus Interface +# +CONFIG_USBD_AU1X00_BUS=m +CONFIG_USBD_AU1X00_SCLOCK=400 +CONFIG_AU1000_USB_DEVICE=y +CONFIG_AU1X00_USB_DEVICE=y +CONFIG_USBD_BI_REGISTER_TRACE=y + +# +# Bluetooth support +# +CONFIG_BLUEZ=m +CONFIG_BLUEZ_L2CAP=m +CONFIG_BLUEZ_SCO=m +CONFIG_BLUEZ_RFCOMM=m +CONFIG_BLUEZ_RFCOMM_TTY=y +CONFIG_BLUEZ_BNEP=m +CONFIG_BLUEZ_BNEP_MC_FILTER=y +CONFIG_BLUEZ_BNEP_PROTO_FILTER=y + +# +# Bluetooth device drivers +# +CONFIG_BLUEZ_HCIUSB=m +CONFIG_BLUEZ_HCIUSB_SCO=y +CONFIG_BLUEZ_HCIUART=m +CONFIG_BLUEZ_HCIUART_H4=y +CONFIG_BLUEZ_HCIUART_BCSP=y +CONFIG_BLUEZ_HCIUART_BCSP_TXCRC=y +CONFIG_BLUEZ_HCIBFUSB=m +# CONFIG_BLUEZ_HCIDTL1 is not set +# CONFIG_BLUEZ_HCIBT3C is not set +# CONFIG_BLUEZ_HCIBLUECARD is not set +# CONFIG_BLUEZ_HCIBTUART is not set +CONFIG_BLUEZ_HCIVHCI=m + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_RUNTIME_DEBUG is not set +# CONFIG_KGDB is not set +# CONFIG_GDB_CONSOLE is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set +CONFIG_LOG_BUF_SHIFT=0 + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_TEST=m + +# +# Library routines +# +CONFIG_CRC32=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_FW_LOADER=m diff --git a/linux/linux-mtx-1-2.4.27/defconfig-mtx-1 b/linux/linux-mtx-1-2.4.27/defconfig-mtx-1 index e69de29bb2..03e8dc6dbd 100644 --- a/linux/linux-mtx-1-2.4.27/defconfig-mtx-1 +++ b/linux/linux-mtx-1-2.4.27/defconfig-mtx-1 @@ -0,0 +1,1183 @@ +# +# Automatically generated by make menuconfig: don't edit +# +CONFIG_MIPS=y +CONFIG_MIPS32=y +# CONFIG_MIPS64 is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Machine selection +# +# CONFIG_ACER_PICA_61 is not set +# CONFIG_MIPS_BOSPORUS is not set +# CONFIG_MIPS_MIRAGE is not set +# CONFIG_MIPS_DB1000 is not set +# CONFIG_MIPS_DB1100 is not set +# CONFIG_MIPS_DB1500 is not set +# CONFIG_MIPS_DB1550 is not set +# CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1100 is not set +# CONFIG_MIPS_PB1500 is not set +# CONFIG_MIPS_HYDROGEN3 is not set +# CONFIG_MIPS_PB1550 is not set +# CONFIG_MIPS_XXS1500 is not set +CONFIG_MIPS_MTX1=y +# CONFIG_COGENT_CSB250 is not set +# CONFIG_BAGET_MIPS is not set +# CONFIG_CASIO_E55 is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_DECSTATION is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_IBM_WORKPAD is not set +# CONFIG_LASAT is not set +# CONFIG_MIPS_ITE8172 is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_SEAD is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_MOMENCO_OCELOT_G is not set +# CONFIG_MOMENCO_OCELOT_C is not set +# CONFIG_MOMENCO_JAGUAR_ATX is not set +# CONFIG_PMC_BIG_SUR is not set +# CONFIG_PMC_STRETCH is not set +# CONFIG_PMC_YOSEMITE is not set +# CONFIG_DDB5074 is not set +# CONFIG_DDB5476 is not set +# CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set +# CONFIG_NEC_EAGLE is not set +# CONFIG_OLIVETTI_M700 is not set +# CONFIG_NINO is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SIBYTE_SB1xxx_SOC is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_TANBAC_TB0226 is not set +# CONFIG_TANBAC_TB0229 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_TOSHIBA_RBTX4927 is not set +# CONFIG_VICTOR_MPC30X is not set +# CONFIG_ZAO_CAPCELLA is not set +# CONFIG_HIGHMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_SOC_AU1X00=y +CONFIG_SOC_AU1500=y +CONFIG_NONCOHERENT_IO=y +# CONFIG_MIPS_AU1000 is not set + +# +# CPU selection +# +CONFIG_CPU_MIPS32=y +# CONFIG_CPU_MIPS64 is not set +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_RM9000 is not set +# CONFIG_CPU_SB1 is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +CONFIG_CPU_HAS_PREFETCH=y +# CONFIG_VTAG_ICACHE is not set +CONFIG_64BIT_PHYS_ADDR=y +# CONFIG_CPU_ADVANCED is not set +CONFIG_CPU_HAS_LLSC=y +# CONFIG_CPU_HAS_LLDSCD is not set +# CONFIG_CPU_HAS_WB is not set +CONFIG_CPU_HAS_SYNC=y + +# +# General setup +# +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_NET=y +CONFIG_PCI=y +CONFIG_PCI_NEW=y +CONFIG_PCI_AUTO=y +CONFIG_PCI_NAMES=y +# CONFIG_ISA is not set +# CONFIG_TC is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HOTPLUG_PCI_COMPAQ is not set +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set +# CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE is not set +# CONFIG_HOTPLUG_PCI_PCIE is not set +# CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_MIPS32_COMPAT is not set +# CONFIG_MIPS32_O32 is not set +# CONFIG_MIPS32_N32 is not set +# CONFIG_BINFMT_ELF32 is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_OOM_KILLER is not set +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_PM is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_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 is not set +CONFIG_MTD_GEN_PROBE=y +# 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 +# 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 is not set +# CONFIG_MTD_PB1000 is not set +# CONFIG_MTD_PB1500 is not set +# CONFIG_MTD_PB1100 is not set +# CONFIG_MTD_BOSPORUS is not set +# CONFIG_MTD_XXS1500 is not set +CONFIG_MTD_MTX1=y +# CONFIG_MTD_DB1X00 is not set +# CONFIG_MTD_PB1550 is not set +# CONFIG_MTD_HYDROGEN3 is not set +# CONFIG_MTD_MIRAGE is not set +# CONFIG_MTD_CSTM_MIPS_IXX is not set +# CONFIG_MTD_OCELOT is not set +# CONFIG_MTD_LASAT 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_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 is not set + +# +# Parallel port support +# +# CONFIG_PARPORT 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_SX8 is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=m +CONFIG_BLK_DEV_RAM_SIZE=4096 +# 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=y +# CONFIG_NETLINK_DEV is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_AMANDA=m +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_PKTTYPE=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_RECENT=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_DSCP=m +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_HELPER=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +CONFIG_IP_NF_MATCH_UNCLEAN=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_MIRROR=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_NAT_AMANDA=m +# CONFIG_IP_NF_NAT_LOCAL is not set +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_NAT_TFTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_DSCP=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +CONFIG_IPV6=m + +# +# IPv6: Netfilter Configuration +# +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_MULTIPORT=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_MARK=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AHESP=m +CONFIG_IP6_NF_MATCH_LENGTH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +# CONFIG_KHTTPD is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +CONFIG_VLAN_8021Q=m +# 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=m +# 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=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +CONFIG_NET_PKTGEN=m + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +CONFIG_SCSI=m +CONFIG_BLK_DEV_SD=m +CONFIG_SD_EXTRA_DEVS=40 +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 +# CONFIG_CHR_DEV_SG is not set +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_MEGARAID2 is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_SATA_SVW is not set +# CONFIG_SCSI_SATA_PROMISE is not set +# CONFIG_SCSI_SATA_SX4 is not set +# CONFIG_SCSI_SATA_SIL is not set +# CONFIG_SCSI_SATA_SIS is not set +# CONFIG_SCSI_SATA_VIA is not set +# CONFIG_SCSI_SATA_VITESSE is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set +# CONFIG_FUSION_BOOT is not set +# CONFIG_FUSION_ISENSE is not set +# CONFIG_FUSION_CTL is not set +# CONFIG_FUSION_LAN is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI 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 + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=m +CONFIG_BONDING=m +# CONFIG_EQUALIZER is not set +CONFIG_TUN=m +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MIPS_AU1X00_ENET=y +# CONFIG_BCM5222_DUAL_PHY is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL 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_HP100 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=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPPOE=m +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_AIRO is not set +# CONFIG_HERMES is not set +# CONFIG_PLX_HERMES is not set +# CONFIG_TMD_HERMES is not set +# CONFIG_PCI_HERMES is not set +CONFIG_NET_WIRELESS=y + +# +# 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 + +# +# 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 + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_DIGI is not set +# CONFIG_ESPSERIAL is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_ISI is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_N_HDLC is not set +# CONFIG_RISCOM8 is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +# CONFIG_STALDRV is not set +# CONFIG_SERIAL_TX3912 is not set +# CONFIG_SERIAL_TX3912_CONSOLE is not set +# CONFIG_SERIAL_TXX9 is not set +# CONFIG_SERIAL_TXX9_CONSOLE is not set +CONFIG_AU1X00_UART=y +CONFIG_AU1X00_SERIAL_CONSOLE=y +CONFIG_AU1X00_USB_TTY=m +CONFIG_AU1X00_USB_RAW=m +CONFIG_AU1X00_USB_DEVICE=y +# CONFIG_TXX927_SERIAL is not set +# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +# CONFIG_I2C 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 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_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 +CONFIG_AU1X00_GPIO=m +# CONFIG_TS_AU1X00_ADS7846 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=m +# 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=m +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=m +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +# 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=m +# 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=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=m +# CONFIG_SYSV_FS is not set +CONFIG_UDF_FS=m +# 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=y +CONFIG_NFSD_V3=y +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT is not set +CONFIG_SMB_UNIX=y +# 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=m + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_SMB_NLS=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-15" +CONFIG_NLS_CODEPAGE_437=m +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +CONFIG_NLS_CODEPAGE_850=m +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ISO8859_1=m +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +CONFIG_NLS_ISO8859_15=m +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=m + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# +CONFIG_VIDEO_PROC_FS=y +# CONFIG_I2C_PARPORT is not set +# CONFIG_VIDEO_BT848 is not set +# CONFIG_VIDEO_PMS is not set +CONFIG_VIDEO_CPIA=m +# CONFIG_VIDEO_CPIA_PP is not set +CONFIG_VIDEO_CPIA_USB=m +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_STRADIS is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_ZORAN_BUZ is not set +# CONFIG_VIDEO_ZORAN_DC10 is not set +# CONFIG_VIDEO_ZORAN_LML33 is not set +# CONFIG_VIDEO_ZR36120 is not set +# CONFIG_VIDEO_MEYE is not set + +# +# Radio Adapters +# +# CONFIG_RADIO_GEMTEK_PCI is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_MAESTRO is not set +# CONFIG_RADIO_MIROPCM20 is not set + +# +# Sound +# +CONFIG_SOUND=m +# CONFIG_SOUND_ALI5455 is not set +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_FORTE is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_AU1X00 is not set +# CONFIG_SOUND_AU1550_PSC is not set +# CONFIG_SOUND_AU1550_I2S is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +CONFIG_SOUND_OSS=m +# CONFIG_SOUND_TRACEINIT is not set +# CONFIG_SOUND_DMAP is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_AD1889 is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_ADLIB is not set +# CONFIG_SOUND_ACI_MIXER is not set +# CONFIG_SOUND_CS4232 is not set +# CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_NM256 is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_PAS is not set +# CONFIG_PAS_JOYSTICK is not set +# CONFIG_SOUND_PSS is not set +# CONFIG_SOUND_SB is not set +# CONFIG_SOUND_AWE32_SYNTH is not set +# CONFIG_SOUND_KAHLUA is not set +# CONFIG_SOUND_WAVEFRONT is not set +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_YM3812 is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_YMFPCI is not set +# CONFIG_SOUND_YMFPCI_LEGACY is not set +# CONFIG_SOUND_UART6850 is not set +# CONFIG_SOUND_AEDSP16 is not set +# CONFIG_SOUND_TVMIXER is not set +# CONFIG_SOUND_AD1980 is not set +# CONFIG_SOUND_WM97XX is not set + +# +# USB support +# +CONFIG_USB=y +CONFIG_USB_DEBUG=y +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH 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=y +CONFIG_USB_NON_PCI_OHCI=y +CONFIG_USB_AUDIO=m +CONFIG_USB_EMI26=m +CONFIG_USB_MIDI=m +CONFIG_USB_STORAGE=m +CONFIG_USB_STORAGE_DEBUG=y +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +# CONFIG_USB_STORAGE_ISD200 is not set +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_HP8200e=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y +CONFIG_USB_ACM=m +CONFIG_USB_PRINTER=m +# CONFIG_USB_HID is not set +# CONFIG_USB_HIDINPUT is not set +# 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=m +CONFIG_USB_MDC800=m +CONFIG_USB_SCANNER=m +CONFIG_USB_MICROTEK=m +CONFIG_USB_HPUSBSCSI=m +CONFIG_USB_IBMCAM=m +CONFIG_USB_KONICAWC=m +CONFIG_USB_OV511=m +CONFIG_USB_PWC=m +CONFIG_USB_SE401=m +CONFIG_USB_STV680=m +# CONFIG_USB_W9968CF is not set +CONFIG_USB_VICAM=m +CONFIG_USB_DSBR=m +CONFIG_USB_DABUSB=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_KAWETH=m +CONFIG_USB_CATC=m +CONFIG_USB_CDCETHER=m +CONFIG_USB_USBNET=m +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_DEBUG is not set +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_BELKIN=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_EMPEG=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_VISOR=m +CONFIG_USB_SERIAL_IPAQ=m +CONFIG_USB_SERIAL_IR=m +CONFIG_USB_SERIAL_EDGEPORT=m +CONFIG_USB_SERIAL_EDGEPORT_TI=m +CONFIG_USB_SERIAL_KEYSPAN_PDA=m +CONFIG_USB_SERIAL_KEYSPAN=m +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +CONFIG_USB_SERIAL_MCT_U232=m +CONFIG_USB_SERIAL_KLSI=m +CONFIG_USB_SERIAL_KOBIL_SCT=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_CYBERJACK=m +CONFIG_USB_SERIAL_XIRCOM=m +CONFIG_USB_SERIAL_OMNINET=m +CONFIG_USB_RIO500=m +CONFIG_USB_AUERSWALD=m +CONFIG_USB_TIGL=m +CONFIG_USB_BRLVGER=m +CONFIG_USB_LCD=m + +# +# Support for USB gadgets +# +# CONFIG_USB_GADGET is not set + +# +# Bluetooth support +# +CONFIG_BLUEZ=m +CONFIG_BLUEZ_L2CAP=m +CONFIG_BLUEZ_SCO=m +CONFIG_BLUEZ_RFCOMM=m +CONFIG_BLUEZ_RFCOMM_TTY=y +CONFIG_BLUEZ_BNEP=m +CONFIG_BLUEZ_BNEP_MC_FILTER=y +CONFIG_BLUEZ_BNEP_PROTO_FILTER=y + +# +# Bluetooth device drivers +# +CONFIG_BLUEZ_HCIUSB=m +CONFIG_BLUEZ_HCIUSB_SCO=y +CONFIG_BLUEZ_HCIUART=m +CONFIG_BLUEZ_HCIUART_H4=y +CONFIG_BLUEZ_HCIUART_BCSP=y +CONFIG_BLUEZ_HCIUART_BCSP_TXCRC=y +CONFIG_BLUEZ_HCIBFUSB=m +# CONFIG_BLUEZ_HCIDTL1 is not set +# CONFIG_BLUEZ_HCIBT3C is not set +# CONFIG_BLUEZ_HCIBLUECARD is not set +# CONFIG_BLUEZ_HCIBTUART is not set +CONFIG_BLUEZ_HCIVHCI=m + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_RUNTIME_DEBUG is not set +# CONFIG_KGDB is not set +# CONFIG_GDB_CONSOLE is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set +CONFIG_LOG_BUF_SHIFT=0 + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MD5=m +CONFIG_CRYPTO_SHA1=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_DES=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_DEFLATE=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_TEST=m + +# +# Library routines +# +CONFIG_CRC32=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_FW_LOADER=m diff --git a/linux/linux-mtx-1-2.4.27/mtx-1-board-reset.diff b/linux/linux-mtx-1-2.4.27/mtx-1-board-reset.diff index e69de29bb2..9a13c2a403 100644 --- a/linux/linux-mtx-1-2.4.27/mtx-1-board-reset.diff +++ b/linux/linux-mtx-1-2.4.27/mtx-1-board-reset.diff @@ -0,0 +1,15 @@ +--- linux/arch/mips/au1000/mtx-1/board_setup.c.orig 2004-10-13 19:05:15.340583632 +0200 ++++ linux/arch/mips/au1000/mtx-1/board_setup.c 2004-10-13 19:01:03.402883984 +0200 +@@ -48,6 +48,12 @@ + + extern struct rtc_ops no_rtc_ops; + ++void board_reset (void) ++{ ++ /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */ ++ au_writel(0x00000000, 0xAE00001C); ++} ++ + void __init board_setup(void) + { + rtc_ops = &no_rtc_ops; diff --git a/linux/linux-mtx-1-2.4.27/zimage-flash-bin.patch b/linux/linux-mtx-1-2.4.27/zimage-flash-bin.patch index e69de29bb2..dca79a3000 100644 --- a/linux/linux-mtx-1-2.4.27/zimage-flash-bin.patch +++ b/linux/linux-mtx-1-2.4.27/zimage-flash-bin.patch @@ -0,0 +1,11 @@ +diff -Nurb oe/tmp/work/linux-mtx-1-2.4.27-r0/linux/arch/mips/zboot/pb1xxx/Makefile linux.m/arch/mips/zboot/pb1xxx/Makefile +--- oe/tmp/work/linux-mtx-1-2.4.27-r0/linux/arch/mips/zboot/pb1xxx/Makefile 2004-10-13 21:08:49.840408328 +0200 ++++ linux.m/arch/mips/zboot/pb1xxx/Makefile 2004-10-13 21:08:29.736464592 +0200 +@@ -131,5 +131,7 @@ + zImage.flash: zImage + $(OBJCOPY) -O srec --adjust-vma 0x3ed00000 \ + ../images/zImage.$(BNAME) ../images/$(BNAME).flash.srec ++ $(OBJCOPY) -O binary --adjust-vma 0x3ed00000 \ ++ ../images/zImage.$(BNAME) ../images/$(BNAME).flash.bin + + include $(TOPDIR)/Rules.make diff --git a/linux/linux-omap-2.6-2.6.9-omap1/omap1610h2/defconfig b/linux/linux-omap-2.6-2.6.9-omap1/omap1610h2/defconfig index e69de29bb2..8b4d7f27ce 100644 --- a/linux/linux-omap-2.6-2.6.9-omap1/omap1610h2/defconfig +++ b/linux/linux-omap-2.6-2.6.9-omap1/omap1610h2/defconfig @@ -0,0 +1,840 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc4-omap1 +# Thu Oct 14 16:30:44 2004 +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_IOMAP=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# 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_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +CONFIG_ARCH_OMAP=y +# CONFIG_ARCH_VERSATILE_PB is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_H720X is not set + +# +# TI OMAP Implementations +# + +# +# OMAP Core Type +# +# CONFIG_ARCH_OMAP730 is not set +# CONFIG_ARCH_OMAP1510 is not set +CONFIG_ARCH_OMAP16XX=y +CONFIG_ARCH_OMAP_OTG=y + +# +# OMAP Board Type +# +# CONFIG_MACH_OMAP_INNOVATOR is not set +CONFIG_MACH_OMAP_H2=y +# CONFIG_MACH_OMAP_H3 is not set +# CONFIG_MACH_OMAP_H4 is not set +# CONFIG_MACH_OMAP_OSK is not set +# CONFIG_MACH_OMAP_GENERIC is not set + +# +# OMAP Feature Selections +# +# CONFIG_OMAP_BOOT_TAG is not set +CONFIG_OMAP_MUX=y +# CONFIG_OMAP_MUX_DEBUG is not set +CONFIG_OMAP_MUX_WARNINGS=y +CONFIG_OMAP_LL_DEBUG_UART1=y +# CONFIG_OMAP_LL_DEBUG_UART2 is not set +# CONFIG_OMAP_LL_DEBUG_UART3 is not set +CONFIG_OMAP_ARM_192MHZ=y +# CONFIG_OMAP_ARM_168MHZ is not set +# CONFIG_OMAP_ARM_120MHZ is not set +# CONFIG_OMAP_ARM_60MHZ is not set +# CONFIG_OMAP_ARM_30MHZ is not set +# CONFIG_OMAP_DSP is not set + +# +# h720x Implementations +# + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5TJ=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_CPU_CACHE_ROUND_ROBIN is not set + +# +# General setup +# +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0x10C08000 +CONFIG_ZBOOT_ROM_BSS=0x10200000 + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +# CONFIG_VFP is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_AOUT=y +# CONFIG_BINFMT_MISC is not set + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_PM is not set +CONFIG_PREEMPT=y +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 initrd=0x10A00000,8M root=/dev/ram0 rw ip=dhcp devfs=mount" +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# 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_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_NET_VENDOR_SMC=y +CONFIG_SMC91X=y +# CONFIG_SMC9194 is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set +CONFIG_SLIP=y +CONFIG_SLIP_COMPRESSED=y +# CONFIG_SLIP_SMART is not set +# CONFIG_SLIP_MODE_SLIP6 is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_RAW is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_KEYBOARD_OMAP=y +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_8250_OMAP=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +# CONFIG_OMAP16XX_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_OMAP_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +CONFIG_I2C=y +# CONFIG_I2C_CHARDEV is not set + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ISA is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_PCA_ISA is not set +CONFIG_I2C_OMAP=y + +# +# Hardware Sensors Chip support +# +# CONFIG_I2C_SENSOR is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +CONFIG_ISP1301_OMAP=m +CONFIG_TPS65010=y +# CONFIG_SENSORS_TLV320AIC23 is not set +CONFIG_GPIOEXPANDER_OMAP=y +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=y + +# +# Video For Linux +# + +# +# Video Adapters +# +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_SAA5246A is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_OVCAMCHIP is not set + +# +# Radio Adapters +# +# CONFIG_RADIO_MAESTRO is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS_XATTR is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS 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_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +CONFIG_PROFILING=y +CONFIG_OPROFILE=y + +# +# Graphics support +# +CONFIG_FB=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_OMAP=y +CONFIG_FB_OMAP_INTERNAL_LCDC=y +# CONFIG_FB_OMAP_EXTERNAL_LCDC is not set +# CONFIG_FB_OMAP_DMA_TUNE is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# +CONFIG_SOUND=y + +# +# Advanced Linux Sound Architecture +# +# CONFIG_SND is not set + +# +# Open Sound System +# +CONFIG_SOUND_PRIME=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set +# CONFIG_SOUND_AD1980 is not set + +# +# Misc devices +# + +# +# USB support +# +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811HS is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH_TTY is not set +# CONFIG_USB_MIDI is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_STORAGE is not set + +# +# USB Human Interface Devices (HID) +# +# CONFIG_USB_HID is not set + +# +# USB HID Boot Protocol drivers +# +# 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_MTOUCH is not set +# CONFIG_USB_EGALAX is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set +# CONFIG_USB_VICAM is not set +# CONFIG_USB_DSBR is not set +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_KONICAWC is not set +# CONFIG_USB_OV511 is not set +# CONFIG_USB_SE401 is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_STV680 is not set + +# +# USB Network adaptors +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_TIGL is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# Synchronous Serial Interfaces (SSI) +# +CONFIG_OMAP_UWIRE=y + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_ERRORS=y +CONFIG_SCHEDSTATS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_ICEDCC is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC_CCITT=y +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff --git a/linux/linux-omap-2.6-2.6.9-omap1/schedstats-arm.patch b/linux/linux-omap-2.6-2.6.9-omap1/schedstats-arm.patch index e69de29bb2..f5823a9943 100644 --- a/linux/linux-omap-2.6-2.6.9-omap1/schedstats-arm.patch +++ b/linux/linux-omap-2.6-2.6.9-omap1/schedstats-arm.patch @@ -0,0 +1,26 @@ + +# +# Patch managed by http://www.holgerschurig.de/patcher.html +# + +--- linux-2.6.9-rc4/arch/arm/Kconfig.debug~schedstats-arm ++++ linux-2.6.9-rc4/arch/arm/Kconfig.debug +@@ -57,6 +57,18 @@ + time and disk space needed for compilation of the kernel. If in + doubt say N. + ++config SCHEDSTATS ++ bool "Collect scheduler statistics" ++ depends on DEBUG_KERNEL && PROC_FS ++ help ++ If you say Y here, additional code will be inserted into the ++ scheduler and related routines to collect statistics about ++ scheduler behavior and provide them in /proc/schedstat. These ++ stats may be useful for both tuning and debugging the scheduler ++ If you aren't debugging the scheduler or trying to tune a specific ++ application, you can say N to avoid the very slight overhead ++ this adds. ++ + # These options are only for real kernel hackers who want to get their hands dirty. + config DEBUG_LL + bool "Kernel low-level debugging functions" diff --git a/linux/linux-sun4cdm-2.4.26/defconfig b/linux/linux-sun4cdm-2.4.26/defconfig index e69de29bb2..8704f6307e 100644 --- a/linux/linux-sun4cdm-2.4.26/defconfig +++ b/linux/linux-sun4cdm-2.4.26/defconfig @@ -0,0 +1,473 @@ +# +# Automatically generated by make menuconfig: don't edit +# +CONFIG_UID16=y +CONFIG_HIGHMEM=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SMP is not set +CONFIG_SPARC32=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set +# CONFIG_PCMCIA is not set +CONFIG_SBUS=y +CONFIG_SBUSCHAR=y +CONFIG_BUSMOUSE=y +CONFIG_SUN_MOUSE=y +CONFIG_SERIAL=y +CONFIG_SUN_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +CONFIG_SUN_KEYBOARD=y +CONFIG_SUN_CONSOLE=y +CONFIG_SUN_AUXIO=y +CONFIG_SUN_IO=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_SUN_PM=y +# CONFIG_SUN4 is not set +CONFIG_PCI=y +# CONFIG_PCI_NAMES is not set +CONFIG_SUN_OPENPROMFS=m +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_KCORE_ELF=y +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=m +CONFIG_SUNOS_EMUL=y +# CONFIG_OOM_KILLER is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set +# CONFIG_PRINTER is not set + +# +# Console drivers +# +# CONFIG_PROM_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_RIVA is not set +# CONFIG_FB_CLGEN is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_INTEL is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set +CONFIG_FB_SBUS=y +# CONFIG_FB_CGSIX is not set +CONFIG_FB_BWTWO=y +CONFIG_FB_CGTHREE=y +# CONFIG_FB_TCX is not set +# CONFIG_FB_CGFOURTEEN is not set +# CONFIG_FB_P9100 is not set +# CONFIG_FB_LEO is not set +# CONFIG_FB_PCI is not set +# CONFIG_FB_IT8181 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_MFB=y +CONFIG_FBCON_CFB8=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FONT_SUN8x16=y +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FBCON_FONTS is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Misc Linux/SPARC drivers +# +CONFIG_SUN_OPENPROMIO=m +CONFIG_SUN_MOSTEK_RTC=m +# CONFIG_SUN_BPP is not set +# CONFIG_SUN_VIDEOPIX is not set +# CONFIG_SUN_AURORA is not set +# CONFIG_TADPOLE_TS102_UCTRL is not set +# CONFIG_SUN_JSFLASH is not set +CONFIG_APM_RTC_IS_GMT=y +CONFIG_RTC=y + +# +# Linux/SPARC audio subsystem (EXPERIMENTAL) +# +# CONFIG_SPARCAUDIO is not set +# CONFIG_SPARCAUDIO_AMD7930 is not set +# CONFIG_SPARCAUDIO_DBRI is not set +# CONFIG_SPARCAUDIO_CS4231 is not set +# CONFIG_SPARCAUDIO_DUMMY is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=m +# CONFIG_BLK_DEV_NBD 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 +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK_DEV=y +# 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=y +# 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=y +# CONFIG_KHTTPD is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +CONFIG_SCTP_DBG_OBJCNT=y +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +# 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=m + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_HD is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# SCSI support +# +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 +CONFIG_CHR_DEV_SG=m +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +CONFIG_SCSI_SUNESP=y +CONFIG_SCSI_QLOGICPTI=m + +# +# Fibre Channel support +# +# CONFIG_FC4 is not set +# CONFIG_FC4_SOC is not set +# CONFIG_FC4_SOCAL is not set +# CONFIG_SCSI_PLUTO is not set +# CONFIG_SCSI_FCAL is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +# CONFIG_BONDING is not set +CONFIG_TUN=m +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +CONFIG_SUNLANCE=y +CONFIG_HAPPYMEAL=m +CONFIG_SUNBMAC=m +CONFIG_SUNQE=m +# CONFIG_MYRI_SBUS is not set +# CONFIG_VORTEX is not set + +# +# Unix98 PTY support +# +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_QFMT_V2 is not set +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m +# 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=m +# 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=y +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=m +# 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 is not set +# CONFIG_DEVFS_MOUNT is not set +# 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=m +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=m +CONFIG_XFS_QUOTA=y +CONFIG_XFS_RT=y +# 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_SUN_PARTITION=y +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Watchdog +# +# CONFIG_SOFT_WATCHDOG is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_IOVIRT is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +CONFIG_LOG_BUF_SHIFT=14 + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_TEST is not set + +# +# Library routines +# +CONFIG_CRC32=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/linux/linux-sun4cdm-2.6.8.1/sun4c_defconfig b/linux/linux-sun4cdm-2.6.8.1/sun4c_defconfig index e69de29bb2..49b84791ae 100644 --- a/linux/linux-sun4cdm-2.6.8.1/sun4c_defconfig +++ b/linux/linux-sun4cdm-2.6.8.1/sun4c_defconfig @@ -0,0 +1,689 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_HIGHMEM=y +CONFIG_GENERIC_ISA_DMA=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# General setup +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_SPARC32=y +CONFIG_SBUS=y +CONFIG_SBUSCHAR=y +CONFIG_SERIAL_CONSOLE=y +CONFIG_SUN_AUXIO=y +CONFIG_SUN_IO=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_SUN_PM=y +# CONFIG_SUN4 is not set +CONFIG_PCI=y +# CONFIG_PCI_LEGACY_PROC is not set +# CONFIG_PCI_NAMES is not set +CONFIG_SUN_OPENPROMFS=m +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_MISC=m +CONFIG_SUNOS_EMUL=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_DEBUG_DRIVER is not set + +# +# Graphics support +# +CONFIG_FB=y +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +CONFIG_FB_BW2=y +CONFIG_FB_CG3=y +CONFIG_FB_CG6=y +# CONFIG_FB_RIVA is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON_OLD is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set +CONFIG_FB_SBUS=y +# CONFIG_FB_TCX is not set +# CONFIG_FB_CG14 is not set +# CONFIG_FB_P9100 is not set +# CONFIG_FB_LEO is not set +# CONFIG_FB_PCI is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_MDA_CONSOLE is not set +# CONFIG_PROM_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_SUN8x16=y +# CONFIG_FONT_SUN12x22 is not set + +# +# Logo configuration +# +# CONFIG_LOGO is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_SUNCORE=y +CONFIG_SERIAL_SUNZILOG=y +CONFIG_SERIAL_SUNZILOG_CONSOLE=y +CONFIG_SERIAL_SUNSU=y +CONFIG_SERIAL_SUNSU_CONSOLE=y +# CONFIG_SERIAL_SUNSAB is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y + +# +# Misc Linux/SPARC drivers +# +CONFIG_SUN_OPENPROMIO=m +CONFIG_SUN_MOSTEK_RTC=m +# CONFIG_SUN_BPP is not set +# CONFIG_SUN_VIDEOPIX is not set +# CONFIG_TADPOLE_TS102_UCTRL is not set +# CONFIG_SUN_JSFLASH is not set +CONFIG_APM_RTC_IS_GMT=y +CONFIG_RTC=m + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_CRYPTOLOOP=m +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# SCSI device support +# +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=m +# CONFIG_SCSI_FC_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +CONFIG_SCSI_QLOGICPTI=m +CONFIG_SCSI_QLA2XXX=y +# CONFIG_SCSI_QLA21XX is not set +# CONFIG_SCSI_QLA22XX is not set +# CONFIG_SCSI_QLA2300 is not set +# CONFIG_SCSI_QLA2322 is not set +# CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_QLA6322 is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set +CONFIG_SCSI_SUNESP=y + +# +# Fibre Channel support +# +# CONFIG_FC4 is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK_DEV=y +CONFIG_UNIX=y +CONFIG_NET_KEY=m +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_SYN_COOKIES is not set +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_TUNNEL=m +# CONFIG_NETFILTER is not set +CONFIG_XFRM=y +CONFIG_XFRM_USER=m + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +CONFIG_SCTP_DBG_OBJCNT=y +# CONFIG_SCTP_HMAC_NONE is not set +# CONFIG_SCTP_HMAC_SHA1 is not set +CONFIG_SCTP_HMAC_MD5=y +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +CONFIG_NET_PKTGEN=m +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +CONFIG_TUN=m +# CONFIG_ETHERTAP is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=m +CONFIG_SUNLANCE=y +CONFIG_HAPPYMEAL=m +CONFIG_SUNBMAC=m +CONFIG_SUNQE=m +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +# CONFIG_NET_PCI 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 + +# +# Ethernet (10000 Mbit) +# +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# Unix98 PTY support +# +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=m +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=m +CONFIG_INPUT_EVBUG=m + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=m +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=m +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=m +CONFIG_KEYBOARD_SUNKBD=m +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=m +CONFIG_MOUSE_SERIAL=m +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_XFS_FS=m +CONFIG_XFS_RT=y +CONFIG_XFS_QUOTA=y +CONFIG_XFS_SECURITY=y +CONFIG_XFS_POSIX_ACL=y +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=m +# CONFIG_QUOTA is not set +CONFIG_QUOTACTL=y +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS_XATTR=y +# CONFIG_DEVPTS_FS_SECURITY is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +CONFIG_BEFS_FS=m +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=m +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_SMB_FS is not set +CONFIG_CIFS=m +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_POSIX is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +CONFIG_AFS_FS=m +CONFIG_RXRPC=m + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_SUN_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_DEBUG_BUGVERBOSE is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_TWOFISH=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_CAST5=m +CONFIG_CRYPTO_CAST6=m +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_ARC4=m +# CONFIG_CRYPTO_KHAZAD is not set +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_CRC32C=m +# CONFIG_CRYPTO_TEST is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +CONFIG_LIBCRC32C=m +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/linux/linux-xxs1500-2.4.21/Makefile b/linux/linux-xxs1500-2.4.21/Makefile index e69de29bb2..7ef3faa145 100644 --- a/linux/linux-xxs1500-2.4.21/Makefile +++ b/linux/linux-xxs1500-2.4.21/Makefile @@ -0,0 +1,756 @@ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1994, 1995, 1996 by Ralf Baechle +# DECStation modifications by Paul M. Antoine, 1996 +# Copyright (C) 2002, 2003 Maciej W. Rozycki +# +# This file is included by the global makefile so that you can add your own +# architecture-specific flags and dependencies. Remember to do have actions +# for "archclean" and "archdep" for cleaning up and making dependencies for +# this architecture +# + +# +# Select the object file format to substitute into the linker script. +# +ifdef CONFIG_CPU_LITTLE_ENDIAN +tool-prefix = mipsel-linux- +ld-emul = elf32ltsmip +else +tool-prefix = mips-linux- +ld-emul = elf32btsmip +endif + +ifdef CONFIG_CROSSCOMPILE +CROSS_COMPILE = $(tool-prefix) +endif + +check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi) + +# +# +# GCC uses -G 0 -mabicalls -fpic as default. We don't want PIC in the kernel +# code since it only slows down the whole thing. At some point we might make +# use of global pointer optimizations but their use of $28 conflicts with +# the current pointer optimization. +# +# The DECStation requires an ECOFF kernel for remote booting, other MIPS +# machines may also. Since BFD is incredibly buggy with respect to +# crossformat linking we rely on the elf2ecoff tool for format conversion. +# +GCCFLAGS := -I $(TOPDIR)/include/asm/gcc +GCCFLAGS += -G 0 -mno-abicalls -fno-pic -pipe +GCCFLAGS += $(call check_gcc, -finline-limit=100000,) +LINKFLAGS += -G 0 -static # -N +MODFLAGS += -mlong-calls + +ifdef CONFIG_DEBUG_INFO +GCCFLAGS += -g +ifdef CONFIG_SB1XXX_CORELIS +GCCFLAGS += -mno-sched-prolog -fno-omit-frame-pointer +endif +endif + +# +# Use: $(call set_gccflags,<cpu0>,<isa0>,<cpu1>,<isa1>,<isa2>) +# +# <cpu0>,<isa0> -- preferred CPU and ISA designations (may require +# recent tools) +# <cpu1>,<isa1> -- fallback CPU and ISA designations (have to work +# with up to the oldest supported tools) +# <isa2> -- an ISA designation used as an ABI selector for +# gcc versions that do not support "-mabi=32" +# (depending on the CPU type, either "mips1" or +# "mips2") +# +set_gccflags = $(shell \ +while :; do \ + cpu=$(1); isa=-$(2); \ + for gcc_opt in -march= -mcpu=; do \ + $(CC) $$gcc_opt$$cpu $$isa -S -o /dev/null \ + -xc /dev/null > /dev/null 2>&1 && \ + break 2; \ + done; \ + cpu=$(3); isa=-$(4); \ + for gcc_opt in -march= -mcpu=; do \ + $(CC) $$gcc_opt$$cpu $$isa -S -o /dev/null \ + -xc /dev/null > /dev/null 2>&1 && \ + break 2; \ + done; \ + break; \ +done; \ +gcc_abi=-mabi=32; gcc_cpu=$$cpu; \ +if $(CC) $$gcc_abi -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then \ + gcc_isa=$$isa; \ +else \ + gcc_abi=; gcc_isa=-$(5); \ +fi; \ +gas_abi=-Wa,-32; gas_cpu=$$cpu; gas_isa=-Wa,$$isa; \ +while :; do \ + for gas_opt in -Wa,-march= -Wa,-mcpu=; do \ + $(CC) $$gas_abi $$gas_opt$$cpu $$gas_isa -Wa,-Z -c \ + -o /dev/null -xassembler /dev/null > /dev/null 2>&1 && \ + break 2; \ + done; \ + gas_abi=; gas_opt=; gas_cpu=; gas_isa=; \ + break; \ +done; \ +echo $$gcc_abi $$gcc_opt$$gcc_cpu $$gcc_isa $$gas_abi $$gas_opt$$gas_cpu $$gas_isa) + +# +# CPU-dependent compiler/assembler options for optimization. +# +ifdef CONFIG_CPU_R3000 +GCCFLAGS += $(call set_gccflags,r3000,mips1,r3000,mips1,mips1) +endif +ifdef CONFIG_CPU_TX39XX +GCCFLAGS += $(call set_gccflags,r3900,mips1,r3000,mips1,mips1) +endif +ifdef CONFIG_CPU_R6000 +GCCFLAGS += $(call set_gccflags,r6000,mips2,r6000,mips2,mips2) \ + -Wa,--trap +endif +ifdef CONFIG_CPU_R4300 +GCCFLAGS += $(call set_gccflags,r4300,mips3,r4300,mips3,mips2) \ + -Wa,--trap +endif +ifdef CONFIG_CPU_VR41XX +GCCFLAGS += $(call set_gccflags,r4100,mips3,r4600,mips3,mips2) \ + -Wa,--trap +endif +ifdef CONFIG_CPU_R4X00 +GCCFLAGS += $(call set_gccflags,r4600,mips3,r4600,mips3,mips2) \ + -Wa,--trap +endif +ifdef CONFIG_CPU_TX49XX +GCCFLAGS += $(call set_gccflags,r4600,mips3,r4600,mips3,mips2) \ + -Wa,--trap +endif +ifdef CONFIG_CPU_MIPS32 +GCCFLAGS += $(call set_gccflags,mips32,mips32,r4600,mips3,mips2) \ + -Wa,--trap +endif +ifdef CONFIG_CPU_MIPS64 +GCCFLAGS += $(call set_gccflags,mips64,mips64,r4600,mips3,mips2) \ + -Wa,--trap +endif +ifdef CONFIG_CPU_R5000 +GCCFLAGS += $(call set_gccflags,r5000,mips4,r5000,mips4,mips2) \ + -Wa,--trap +endif +ifdef CONFIG_CPU_R5432 +GCCFLAGS += $(call set_gccflags,r5400,mips4,r5000,mips4,mips2) \ + -Wa,--trap +endif +ifdef CONFIG_CPU_NEVADA +GCCFLAGS += $(call set_gccflags,rm5200,mips4,r5000,mips4,mips2) \ + -Wa,--trap +#GCCFLAGS += $(call check_gcc,-mmad,) +endif +ifdef CONFIG_CPU_RM7000 +GCCFLAGS += $(call set_gccflags,rm7000,mips4,r5000,mips4,mips2) \ + -Wa,--trap +endif +ifdef CONFIG_CPU_RM9000 +GCCFLAGS += $(call set_gccflags,rm9000,mips4,r5000,mips4,mips2) \ + -Wa,--trap +endif +ifdef CONFIG_CPU_SB1 +GCCFLAGS += $(call set_gccflags,sb1,mips64,r5000,mips4,mips2) \ + -Wa,--trap +ifdef CONFIG_SB1_PASS_1_WORKAROUNDS +MODFLAGS += -msb1-pass1-workarounds +endif +endif + +AFLAGS += $(GCCFLAGS) +CFLAGS += $(GCCFLAGS) +LDFLAGS += -m $(ld-emul) + + +# +# We unconditionally build the math emulator +# +CORE_FILES += arch/mips/math-emu/fpu_emulator.o +SUBDIRS += arch/mips/math-emu + +# +# ramdisk/initrd support +# You need a compressed ramdisk image, named ramdisk.gz in +# arch/mips/ramdisk +# +ifdef CONFIG_EMBEDDED_RAMDISK +CORE_FILES += arch/mips/ramdisk/ramdisk.o +SUBDIRS += arch/mips/ramdisk +endif + + +# +# Board-dependent options and extra files +# + +# +# Acer PICA 61, Mips Magnum 4000 and Olivetti M700. +# +ifdef CONFIG_MIPS_JAZZ +CORE_FILES += arch/mips/jazz/jazz.o +SUBDIRS += arch/mips/jazz arch/mips/arc +LIBS += arch/mips/arc/arclib.a +LOADADDR := 0x80080000 +endif + +# +# Au1000 (Alchemy Semi PB1000) eval board +# +ifdef CONFIG_MIPS_PB1000 +LIBS += arch/mips/au1000/pb1000/pb1000.o \ + arch/mips/au1000/common/au1000.o +SUBDIRS += arch/mips/au1000/pb1000 arch/mips/au1000/common +LOADADDR := 0x80100000 +endif + +# +# Au1100 (Alchemy Semi PB1100) eval board +# +ifdef CONFIG_MIPS_PB1100 +LIBS += arch/mips/au1000/pb1100/pb1100.o \ + arch/mips/au1000/common/au1000.o +SUBDIRS += arch/mips/au1000/pb1100 arch/mips/au1000/common +LOADADDR += 0x80100000 +endif + +# +# Au1500 (Alchemy Semi PB1500) eval board +# +ifdef CONFIG_MIPS_PB1500 +LIBS += arch/mips/au1000/pb1500/pb1500.o \ + arch/mips/au1000/common/au1000.o +SUBDIRS += arch/mips/au1000/pb1500 arch/mips/au1000/common +LOADADDR := 0x80100000 +endif + +# +# Au1x00 (AMD/Alchemy) eval boards +# +ifdef CONFIG_MIPS_DB1000 +LIBS += arch/mips/au1000/db1x00/db1x00.o \ + arch/mips/au1000/common/au1000.o +SUBDIRS += arch/mips/au1000/db1x00 arch/mips/au1000/common +LOADADDR += 0x80100000 +endif + +ifdef CONFIG_MIPS_DB1500 +LIBS += arch/mips/au1000/db1x00/db1x00.o \ + arch/mips/au1000/common/au1000.o +SUBDIRS += arch/mips/au1000/db1x00 arch/mips/au1000/common +LOADADDR += 0x80100000 +endif + +ifdef CONFIG_MIPS_DB1100 +LIBS += arch/mips/au1000/db1x00/db1x00.o \ + arch/mips/au1000/common/au1000.o +SUBDIRS += arch/mips/au1000/db1x00 arch/mips/au1000/common +LOADADDR += 0x80100000 +endif + +ifdef CONFIG_MIPS_HYDROGEN3 +LIBS += arch/mips/au1000/hydrogen3/hydrogen3.o \ + arch/mips/au1000/common/au1000.o +SUBDIRS += arch/mips/au1000/hydrogen3 arch/mips/au1000/common +LOADADDR += 0x80100000 +endif + +ifdef CONFIG_MIPS_BOSPORUS +LIBS += arch/mips/au1000/db1x00/db1x00.o \ + arch/mips/au1000/common/au1000.o +SUBDIRS += arch/mips/au1000/db1x00 arch/mips/au1000/common +LOADADDR += 0x80100000 +endif + +ifdef CONFIG_MIPS_MIRAGE +LIBS += arch/mips/au1000/db1x00/db1x00.o \ + arch/mips/au1000/common/au1000.o +SUBDIRS += arch/mips/au1000/db1x00 arch/mips/au1000/common +LOADADDR += 0x80100000 +endif + +ifdef CONFIG_MIPS_XXS1500 +LIBS += arch/mips/au1000/xxs1500/xxs1500.o \ + arch/mips/au1000/common/au1000.o +SUBDIRS += arch/mips/au1000/xxs1500 arch/mips/au1000/common +LOADADDR += 0x80100000 +endif + +ifdef CONFIG_MIPS_MTX1 +LIBS += arch/mips/au1000/mtx-1/mtx-1.o \ + arch/mips/au1000/common/au1000.o +SUBDIRS += arch/mips/au1000/mtx-1 arch/mips/au1000/common +LOADADDR += 0x80100000 +endif + +ifdef CONFIG_MIPS_PB1550 +LIBS += arch/mips/au1000/pb1550/pb1550.o \ + arch/mips/au1000/common/au1000.o +SUBDIRS += arch/mips/au1000/pb1550 arch/mips/au1000/common +LOADADDR += 0x80100000 +endif + + +# +# Cogent CSB250 +# +ifdef CONFIG_COGENT_CSB250 +LIBS += arch/mips/au1000/csb250/csb250.o \ + arch/mips/au1000/common/au1000.o +SUBDIRS += arch/mips/au1000/csb250 arch/mips/au1000/common +LOADADDR := 0x80100000 +endif + +ifdef CONFIG_PCI +CORE_FILES += arch/mips/pci/pci-core.o +SUBDIRS += arch/mips/pci +endif + +# +# Algorithmics P4032 +# +ifdef CONFIG_ALGOR_P4032 +CORE_FILES += arch/mips/algor/algor.o +SUBDIRS += arch/mips/algor +LOADADDR := 0x80000000 +endif + +# +# Baget/MIPS +# +ifdef CONFIG_BAGET_MIPS +SUBDIRS += arch/mips/baget arch/mips/baget/prom +LIBS += arch/mips/baget/baget.a arch/mips/baget/prom/bagetlib.a +LOADADDR := 0x80001000 +endif + +# +# Cobalt Server +# +ifdef CONFIG_MIPS_COBALT +SUBDIRS += arch/mips/cobalt +CORE_FILES += arch/mips/cobalt/cobalt.o +LOADADDR := 0x80080000 +endif + +# +# DECstation family +# +ifdef CONFIG_DECSTATION +CORE_FILES += arch/mips/dec/dec.o +SUBDIRS += arch/mips/dec arch/mips/dec/prom +LIBS += arch/mips/dec/prom/rexlib.a +LOADADDR := 0x80040000 +endif + +# +# Galileo EV64120 Board +# +ifdef CONFIG_MIPS_EV64120 +LIBS += arch/mips/gt64120/common/gt64120.o \ + arch/mips/gt64120/ev64120/ev64120.o +SUBDIRS += arch/mips/gt64120/common arch/mips/gt64120/ev64120 +LOADADDR := 0x80100000 +endif + +# +# Galileo EV96100 Board +# +ifdef CONFIG_MIPS_EV96100 +LIBS += arch/mips/galileo-boards/ev96100/ev96100.o +SUBDIRS += arch/mips/galileo-boards/ev96100 +LOADADDR := 0x80100000 +endif + +# +# Globespan IVR eval board with QED 5231 CPU +# +ifdef CONFIG_MIPS_IVR +LIBS += arch/mips/ite-boards/ivr/ivr.o \ + arch/mips/ite-boards/generic/it8172.o +SUBDIRS += arch/mips/ite-boards/generic arch/mips/ite-boards/ivr +LOADADDR := 0x80100000 +endif + +# +# HP LaserJet +# +ifdef CONFIG_HP_LASERJET +SUBDIRS += arch/mips/hp-lj +LIBS += arch/mips/hp-lj/hp-lj.o +LOADADDR := 0x80030000 +endif + +# +# ITE 8172 eval board with QED 5231 CPU +# +ifdef CONFIG_MIPS_ITE8172 +LIBS += arch/mips/ite-boards/qed-4n-s01b/ite.o \ + arch/mips/ite-boards/generic/it8172.o +SUBDIRS += arch/mips/ite-boards/generic arch/mips/ite-boards/qed-4n-s01b +LOADADDR := 0x80100000 +endif + +# +# MIPS Atlas board +# +ifdef CONFIG_MIPS_ATLAS +LIBS += arch/mips/mips-boards/atlas/atlas.o \ + arch/mips/mips-boards/generic/mipsboards.o +SUBDIRS += arch/mips/mips-boards/generic arch/mips/mips-boards/atlas +LOADADDR := 0x80100000 +endif + +# +# MIPS Malta board +# +ifdef CONFIG_MIPS_MALTA +LIBS += arch/mips/mips-boards/malta/malta.o \ + arch/mips/mips-boards/generic/mipsboards.o +SUBDIRS += arch/mips/mips-boards/malta arch/mips/mips-boards/generic +LOADADDR := 0x80100000 +endif + +# +# MIPS SEAD board +# +ifdef CONFIG_MIPS_SEAD +LIBS += arch/mips/mips-boards/sead/sead.o \ + arch/mips/mips-boards/generic/mipsboards.o +SUBDIRS += arch/mips/mips-boards/generic arch/mips/mips-boards/sead +LOADADDR := 0x80100000 +endif + +# +# Momentum Ocelot board +# +ifdef CONFIG_MOMENCO_OCELOT +# The Ocelot setup.o must be linked early - it does the ioremap() for the +# mips_io_port_base. +CORE_FILES += arch/mips/gt64120/common/gt64120.o \ + arch/mips/gt64120/momenco_ocelot/momenco_ocelot.o +SUBDIRS += arch/mips/gt64120/common arch/mips/gt64120/momenco_ocelot +LOADADDR := 0x80100000 +endif + +# +# Momentum Ocelot-G board +# +ifdef CONFIG_MOMENCO_OCELOT_G +# The Ocelot-G setup.o must be linked early - it does the ioremap() for the +# mips_io_port_base. +CORE_FILES += arch/mips/momentum/ocelot_g/ocelot_g.o +SUBDIRS += arch/mips/momentum/ocelot_g +LOADADDR := 0x80100000 +endif + +# +# Momentum Ocelot-C and -CS boards +# +ifdef CONFIG_MOMENCO_OCELOT_C +# The Ocelot-C[S] setup.o must be linked early - it does the ioremap() for the +# mips_io_port_base. +CORE_FILES += arch/mips/momentum/ocelot_c/ocelot_c.o +SUBDIRS += arch/mips/momentum/ocelot_c +LOADADDR := 0x80100000 +endif + +ifdef CONFIG_MOMENCO_JAGUAR_ATX +LIBS += arch/mips/momentum/jaguar_atx/jaguar_atx.o +SUBDIRS += arch/mips/momentum/jaguar_atx +ifdef CONFIG_JAGUAR_DMALOW +LOADADDR := 0x88000000 +else +LOADADDR := 0x80100000 +endif +endif + +# +# NEC DDB Vrc-5074 +# +ifdef CONFIG_DDB5074 +SUBDIRS += arch/mips/ddb5xxx/common arch/mips/ddb5xxx/ddb5074 +LIBS += arch/mips/ddb5xxx/common/ddb5xxx.o arch/mips/ddb5xxx/ddb5074/ddb5074.o +LOADADDR := 0x80080000 +endif + +# +# NEC DDB Vrc-5476 +# +ifdef CONFIG_DDB5476 +SUBDIRS += arch/mips/ddb5xxx/common arch/mips/ddb5xxx/ddb5476 +LIBS += arch/mips/ddb5xxx/common/ddb5xxx.o \ + arch/mips/ddb5xxx/ddb5476/ddb5476.o +LOADADDR := 0x80080000 +endif + +# +# NEC DDB Vrc-5477 +# +ifdef CONFIG_DDB5477 +SUBDIRS += arch/mips/ddb5xxx/common arch/mips/ddb5xxx/ddb5477 +LIBS += arch/mips/ddb5xxx/common/ddb5xxx.o \ + arch/mips/ddb5xxx/ddb5477/ddb5477.o +LOADADDR := 0x80100000 +endif + +ifdef CONFIG_LASAT +LIBS += arch/mips/lasat/lasatkern.o +SUBDIRS += arch/mips/lasat +LOADADDR += 0x80000000 +endif +# +# NEC Osprey (vr4181) board +# +ifdef CONFIG_NEC_OSPREY +SUBDIRS += arch/mips/vr4181/common arch/mips/vr4181/osprey +LIBS += arch/mips/vr4181/common/vr4181.o \ + arch/mips/vr4181/osprey/osprey.o +LOADADDR := 0x80002000 +endif + +# +# NEC Eagle/Hawk (VR4122/VR4131) board +# +ifdef CONFIG_NEC_EAGLE +SUBDIRS += arch/mips/vr41xx/common \ + arch/mips/vr41xx/nec-eagle +CORE_FILES += arch/mips/vr41xx/common/vr41xx.o \ + arch/mips/vr41xx/nec-eagle/eagle.o +LOADADDR := 0x80000000 +endif + +# +# ZAO Networks Capcella (VR4131) +# +ifdef CONFIG_ZAO_CAPCELLA +SUBDIRS += arch/mips/vr41xx/common \ + arch/mips/vr41xx/zao-capcella +CORE_FILES += arch/mips/vr41xx/common/vr41xx.o \ + arch/mips/vr41xx/zao-capcella/capcella.o +LOADADDR := 0x80000000 +endif + +# +# Victor MP-C303/304 (VR4122) +# +ifdef CONFIG_VICTOR_MPC30X +SUBDIRS += arch/mips/vr41xx/common \ + arch/mips/vr41xx/victor-mpc30x +CORE_FILES += arch/mips/vr41xx/common/vr41xx.o \ + arch/mips/vr41xx/victor-mpc30x/mpc30x.o +LOADADDR := 0x80001000 +endif + +# +# IBM WorkPad z50 (VR4121) +# +ifdef CONFIG_IBM_WORKPAD +SUBDIRS += arch/mips/vr41xx/common \ + arch/mips/vr41xx/ibm-workpad +CORE_FILES += arch/mips/vr41xx/common/vr41xx.o \ + arch/mips/vr41xx/ibm-workpad/workpad.o +LOADADDR += 0x80004000 +endif + +# +# CASIO CASSIPEIA E-55/65 (VR4111) +# +ifdef CONFIG_CASIO_E55 +SUBDIRS += arch/mips/vr41xx/common \ + arch/mips/vr41xx/casio-e55 +CORE_FILES += arch/mips/vr41xx/common/vr41xx.o \ + arch/mips/vr41xx/casio-e55/e55.o +LOADADDR += 0x80004000 +endif + +# +# TANBAC TB0226 Mbase (VR4131) +# +ifdef CONFIG_TANBAC_TB0226 +SUBDIRS += arch/mips/vr41xx/common \ + arch/mips/vr41xx/tanbac-tb0226 +CORE_FILES += arch/mips/vr41xx/common/vr41xx.o \ + arch/mips/vr41xx/tanbac-tb0226/tb0226.o +LOADADDR := 0x80000000 +endif + +# +# TANBAC TB0229 (VR4131DIMM) +# +ifdef CONFIG_TANBAC_TB0229 +SUBDIRS += arch/mips/vr41xx/common \ + arch/mips/vr41xx/tanbac-tb0229 +CORE_FILES += arch/mips/vr41xx/common/vr41xx.o \ + arch/mips/vr41xx/tanbac-tb0229/tb0229.o +LOADADDR := 0x80000000 +endif + +# +# Philips Nino +# +ifdef CONFIG_NINO +CORE_FILES += arch/mips/philips/nino/nino.o +SUBDIRS += arch/mips/philips/nino +LOADADDR := 0x80000000 +endif + +# +# SGI IP22 (Indy/Indigo2) +# +ifdef CONFIG_SGI_IP22 +CORE_FILES += arch/mips/sgi-ip22/ip22-kern.o +LIBS += arch/mips/arc/arclib.a +SUBDIRS += arch/mips/sgi-ip22 arch/mips/arc +# +# Set LOADADDR to >= 0x88069000 if you want to leave space for symmon, +# 0x88002000 for production kernels. Note that the value must be +# 8kb aligned or the handling of the current variable will break. +# +LOADADDR := 0x88002000 +endif + +# +# Sibyte SB1250 SOC and Broadcom (SiByte) BCM112x SOCs +# +ifneq ($(CONFIG_SIBYTE_SB1250)$(CONFIG_SIBYTE_BCM112X),) +# This is a LIB so that it links at the end, and initcalls are later +# the sequence; but it is built as an object so that modules don't get +# removed (as happens, even if they have __initcall/module_init) +LIBS += arch/mips/sibyte/sb1250/sb1250.o +SUBDIRS += arch/mips/sibyte/sb1250 +LOADADDR := 0x80100000 +endif + +# +# Sibyte boards: +# +# BCM91250A (SWARM), +# BCM91250E (Sentosa), +# BCM91120C (CRhine), +# BCM91120x (Carmel), +# BCM91125C (CRhone), +# BCM91125E (Rhone). +# +ifdef CONFIG_SIBYTE_BOARD +LIBS += arch/mips/sibyte/swarm/sbswarm.a +SUBDIRS += arch/mips/sibyte/swarm +endif + +# +# Sibyte CFE firmware +# +ifdef CONFIG_SIBYTE_CFE +LIBS += arch/mips/sibyte/cfe/cfe.a +SUBDIRS += arch/mips/sibyte/cfe +endif + +# +# SNI RM200 PCI +# +ifdef CONFIG_SNI_RM200_PCI +CORE_FILES += arch/mips/sni/sni.o +SUBDIRS += arch/mips/sni arch/mips/arc +LIBS += arch/mips/arc/arclib.a +LOADADDR := 0x80080000 +endif + +# +# Toshiba JMR-TX3927 board +# +ifdef CONFIG_TOSHIBA_JMR3927 +CORE_FILES += arch/mips/jmr3927/rbhma3100/jmr3927.o \ + arch/mips/jmr3927/common/tx3927.o +SUBDIRS += arch/mips/jmr3927/rbhma3100 arch/mips/jmr3927/common +LOADADDR := 0x80050000 +endif + +# +# Toshiba RBTX4927 board or +# Toshiba RBTX4937 board +# +ifdef CONFIG_TOSHIBA_RBTX4927 +MIPS = arch/mips +CEC = tx4927 +COMMON = $(MIPS)/$(CEC)/common +BOARD = $(MIPS)/$(CEC)/toshiba_rbtx4927 +LIBS += $(BOARD)/toshiba_rbtx4927.o $(COMMON)/tx4927.o +SUBDIRS += $(BOARD) $(COMMON) +LOADADDR += 0x80020000 +endif + +# +# Choosing incompatible machines durings configuration will result in +# error messages during linking. Select a default linkscript if +# none has been choosen above. +# +vmlinux: arch/$(ARCH)/ld.script + +arch/$(ARCH)/ld.script: arch/$(ARCH)/ld.script.in arch/$(ARCH)/Makefile + sed -e 's/@@LOADADDR@@/$(LOADADDR)/' <$< >$@ +LINKFLAGS += -T arch/$(ARCH)/ld.script + +HEAD := arch/mips/kernel/head.o arch/mips/kernel/init_task.o + +SUBDIRS := $(addprefix arch/mips/, tools) $(SUBDIRS) $(addprefix arch/mips/, kernel mm lib) +CORE_FILES := arch/mips/kernel/kernel.o arch/mips/mm/mm.o $(CORE_FILES) +LIBS := arch/mips/lib/lib.a $(LIBS) + +ifdef CONFIG_BAGET_MIPS + +BAGETBOOT = $(MAKE) -C arch/$(ARCH)/baget + +balo: vmlinux + $(BAGETBOOT) balo + +endif + +ifdef CONFIG_MIPS_EV64120 +gboot: vmlinux + $(MAKE) -C arch/$(ARCH)/galileo-boards/ev64120/compressed +endif + +ifdef CONFIG_LASAT +rom.bin rom.sw: vmlinux + $(MAKE) -C arch/$(ARCH)/lasat/image $@ +endif + +MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot +MAKEZBOOT = $(MAKE) -C arch/$(ARCH)/zboot +BOOT_TARGETS = zImage zImage.initrd zImage.flash zImage.flash.bin + +vmlinux.ecoff: vmlinux + @$(MAKEBOOT) $@ + + $(BOOT_TARGETS): vmlinux + @$(MAKEZBOOT) $@ + +vmlinux.srec: vmlinux + @$(MAKEBOOT) $@ + +archclean: + @$(MAKEBOOT) clean + @$(MAKEZBOOT) clean + rm -f arch/$(ARCH)/ld.script + $(MAKE) -C arch/$(ARCH)/tools clean + $(MAKE) -C arch/mips/baget clean + $(MAKE) -C arch/mips/lasat clean + +archmrproper: + @$(MAKEBOOT) mrproper + $(RM) $(TOPDIR)/include/asm-$(ARCH)/offset.h + $(MAKE) -C arch/$(ARCH)/tools mrproper + +archdep: + if [ ! -f $(TOPDIR)/include/asm-$(ARCH)/offset.h ]; then \ + touch $(TOPDIR)/include/asm-$(ARCH)/offset.h; \ + fi; + @$(MAKEBOOT) dep diff --git a/linux/linux-xxs1500-2.4.21/defconfig-xxs1500 b/linux/linux-xxs1500-2.4.21/defconfig-xxs1500 index e69de29bb2..0fc84863ca 100644 --- a/linux/linux-xxs1500-2.4.21/defconfig-xxs1500 +++ b/linux/linux-xxs1500-2.4.21/defconfig-xxs1500 @@ -0,0 +1,1199 @@ +# +# Automatically generated by make menuconfig: don't edit +# +CONFIG_MIPS=y +CONFIG_MIPS32=y +# CONFIG_MIPS64 is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# Machine selection +# +# CONFIG_ACER_PICA_61 is not set +# CONFIG_MIPS_BOSPORUS is not set +# CONFIG_MIPS_MIRAGE is not set +# CONFIG_MIPS_DB1000 is not set +# CONFIG_MIPS_DB1100 is not set +# CONFIG_MIPS_DB1500 is not set +# CONFIG_MIPS_PB1000 is not set +# CONFIG_MIPS_PB1100 is not set +# CONFIG_MIPS_PB1500 is not set +CONFIG_MIPS_XXS1500=y +# CONFIG_MIPS_MTX1 is not set +# CONFIG_BAGET_MIPS is not set +# CONFIG_CASIO_E55 is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_DECSTATION is not set +# CONFIG_MIPS_EV64120 is not set +# CONFIG_MIPS_EV96100 is not set +# CONFIG_MIPS_IVR is not set +# CONFIG_HP_LASERJET is not set +# CONFIG_IBM_WORKPAD is not set +# CONFIG_LASAT is not set +# CONFIG_MIPS_ITE8172 is not set +# CONFIG_MIPS_ATLAS is not set +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_SEAD is not set +# CONFIG_MOMENCO_OCELOT is not set +# CONFIG_MOMENCO_OCELOT_G is not set +# CONFIG_MOMENCO_OCELOT_C is not set +# CONFIG_DDB5074 is not set +# CONFIG_DDB5476 is not set +# CONFIG_DDB5477 is not set +# CONFIG_NEC_OSPREY is not set +# CONFIG_NEC_EAGLE is not set +# CONFIG_OLIVETTI_M700 is not set +# CONFIG_NINO is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SIBYTE_SB1xxx_SOC is not set +# CONFIG_SNI_RM200_PCI is not set +# CONFIG_TANBAC_TB0226 is not set +# CONFIG_TANBAC_TB0229 is not set +# CONFIG_TOSHIBA_JMR3927 is not set +# CONFIG_TOSHIBA_RBTX4927 is not set +# CONFIG_VICTOR_MPC30X is not set +# CONFIG_ZAO_CAPCELLA is not set +# CONFIG_HIGHMEM is not set +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +CONFIG_SOC_AU1X00=y +CONFIG_SOC_AU1500=y +CONFIG_PCI=y +CONFIG_NEW_PCI=y +CONFIG_PCI_AUTO=y +CONFIG_NONCOHERENT_IO=y +CONFIG_PC_KEYB=y +# CONFIG_MIPS_AU1000 is not set + +# +# CPU selection +# +CONFIG_CPU_MIPS32=y +# CONFIG_CPU_MIPS64 is not set +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_VR41XX is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_SB1 is not set +CONFIG_CPU_HAS_PREFETCH=y +# CONFIG_VTAG_ICACHE is not set +CONFIG_64BIT_PHYS_ADDR=y +# CONFIG_CPU_ADVANCED is not set +CONFIG_CPU_HAS_LLSC=y +# CONFIG_CPU_HAS_LLDSCD is not set +# CONFIG_CPU_HAS_WB is not set +CONFIG_CPU_HAS_SYNC=y + +# +# General setup +# +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_NET=y +CONFIG_PCI_NAMES=y +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_TC is not set +# CONFIG_MCA is not set +# CONFIG_SBUS is not set +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=m +# CONFIG_CARDBUS is not set +# CONFIG_TCIC is not set +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +CONFIG_PCMCIA_AU1X00=m +# CONFIG_PCMCIA_PB1X00 is not set +# CONFIG_PCMCIA_DB1X00 is not set +CONFIG_PCMCIA_XXS1500=y +# CONFIG_PCMCIA_VRC4173 is not set + +# +# PCI Hotplug Support +# +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HOTPLUG_PCI_COMPAQ is not set +# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set +# CONFIG_HOTPLUG_PCI_ACPI is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_MIPS32_COMPAT is not set +# CONFIG_MIPS32_O32 is not set +# CONFIG_MIPS32_N32 is not set +# CONFIG_BINFMT_ELF32 is not set +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_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 is not set +CONFIG_MTD_GEN_PROBE=y +# 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 +# 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 is not set +# CONFIG_MTD_PB1000 is not set +# CONFIG_MTD_PB1500 is not set +# CONFIG_MTD_PB1100 is not set +# CONFIG_MTD_BOSPORUS is not set +CONFIG_MTD_XXS1500=y +# CONFIG_MTD_MTX1 is not set +# CONFIG_MTD_DB1X00 is not set +# CONFIG_MTD_CSTM_MIPS_IXX is not set +# CONFIG_MTD_OCELOT is not set +# CONFIG_MTD_LASAT 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_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 is not set + +# +# Parallel port support +# +CONFIG_PARPORT=m +CONFIG_PARPORT_PC=m +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +# CONFIG_PARPORT_PC_PCMCIA is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_SUNBPP is not set +# CONFIG_PARPORT_IP22 is not set +# CONFIG_PARPORT_OTHER is not set +CONFIG_PARPORT_1284=y + +# +# 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_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# 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=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_FWMARK=y +CONFIG_IP_ROUTE_NAT=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_TOS=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_ROUTE_LARGE_TABLES=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_INET_ECN=y +CONFIG_SYN_COOKIES=y + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_AMANDA=m +CONFIG_IP_NF_TFTP=m +CONFIG_IP_NF_IRC=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_LIMIT=m +CONFIG_IP_NF_MATCH_MAC=m +CONFIG_IP_NF_MATCH_PKTTYPE=m +CONFIG_IP_NF_MATCH_MARK=m +CONFIG_IP_NF_MATCH_MULTIPORT=m +CONFIG_IP_NF_MATCH_TOS=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_DSCP=m +CONFIG_IP_NF_MATCH_AH_ESP=m +CONFIG_IP_NF_MATCH_LENGTH=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_MATCH_TCPMSS=m +CONFIG_IP_NF_MATCH_HELPER=m +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +CONFIG_IP_NF_MATCH_UNCLEAN=m +CONFIG_IP_NF_MATCH_OWNER=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_MIRROR=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_NAT_AMANDA=m +# CONFIG_IP_NF_NAT_LOCAL is not set +CONFIG_IP_NF_NAT_SNMP_BASIC=m +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_NAT_TFTP=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_TOS=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_DSCP=m +CONFIG_IP_NF_TARGET_MARK=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_IP_NF_TARGET_TCPMSS=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +CONFIG_IPV6=m + +# +# IPv6: Netfilter Configuration +# +CONFIG_IP6_NF_QUEUE=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_LIMIT=m +CONFIG_IP6_NF_MATCH_MAC=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_MULTIPORT=m +CONFIG_IP6_NF_MATCH_OWNER=m +CONFIG_IP6_NF_MATCH_MARK=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_AHESP=m +CONFIG_IP6_NF_MATCH_LENGTH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_LOG=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_TARGET_MARK=m +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +CONFIG_VLAN_8021Q=m +# 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=m +# 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=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_QOS=y +CONFIG_NET_ESTIMATOR=y +CONFIG_NET_CLS=y +CONFIG_NET_CLS_TCINDEX=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_ROUTE=y +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_POLICE=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ is not set +# CONFIG_PHONE_IXJ_PCMCIA is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=m + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=m +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=m +CONFIG_IDEDISK_MULTI_MODE=y +# CONFIG_IDEDISK_STROKE is not set +CONFIG_BLK_DEV_IDECS=m +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +CONFIG_BLK_DEV_IDEPCI=y +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +CONFIG_BLK_DEV_OFFBOARD=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_PCI_WIP is not set +# CONFIG_BLK_DEV_ADMA100 is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_WDC_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_AMD74XX_OVERRIDE is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_HPT34X_AUTODMA is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_PDC202XX_BURST is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_IDE_CHIPSETS is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set +# CONFIG_BLK_DEV_ATARAID_SII is not set + +# +# SCSI support +# +CONFIG_SCSI=m +CONFIG_BLK_DEV_SD=m +CONFIG_SD_EXTRA_DEVS=40 +CONFIG_CHR_DEV_ST=m +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 +# CONFIG_CHR_DEV_SG is not set +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +CONFIG_SCSI_PCMCIA=y +CONFIG_PCMCIA_AHA152X=m +CONFIG_PCMCIA_FDOMAIN=m +CONFIG_PCMCIA_NINJA_SCSI=m +# CONFIG_PCMCIA_QLOGIC is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI 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 + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_EQUALIZER=m +CONFIG_TUN=m +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MIPS_AU1X00_ENET=y +CONFIG_BCM5222_DUAL_PHY=y +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL 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_HP100 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=m +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPPOE=m +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_AIRO is not set +# CONFIG_HERMES is not set +# CONFIG_PLX_HERMES is not set +# CONFIG_PCI_HERMES is not set +# CONFIG_PCMCIA_HERMES is not set +CONFIG_AIRO_CS=m +CONFIG_NET_WIRELESS=y + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +CONFIG_SHAPER=m + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +CONFIG_PCMCIA_3C589=m +CONFIG_PCMCIA_3C574=m +CONFIG_PCMCIA_FMVJ18X=m +CONFIG_PCMCIA_PCNET=m +CONFIG_PCMCIA_AXNET=m +CONFIG_PCMCIA_NMCLAN=m +CONFIG_PCMCIA_SMC91C92=m +CONFIG_PCMCIA_XIRC2PS=m +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +CONFIG_NET_PCMCIA_RADIO=y +# CONFIG_PCMCIA_RAYCS is not set +# CONFIG_PCMCIA_NETWAVE is not set +# CONFIG_PCMCIA_WAVELAN is not set +# CONFIG_AIRONET4500_CS is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA 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 + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_COMPUTONE is not set +# CONFIG_ROCKETPORT is not set +# CONFIG_CYCLADES is not set +# CONFIG_DIGIEPCA is not set +# CONFIG_DIGI is not set +# CONFIG_ESPSERIAL is not set +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_ISI is not set +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_N_HDLC is not set +# CONFIG_RISCOM8 is not set +# CONFIG_SPECIALIX is not set +# CONFIG_SX is not set +# CONFIG_RIO is not set +# CONFIG_STALDRV is not set +# CONFIG_SERIAL_TX3912 is not set +# CONFIG_SERIAL_TX3912_CONSOLE is not set +# CONFIG_SERIAL_TXX9 is not set +# CONFIG_SERIAL_TXX9_CONSOLE is not set +CONFIG_AU1X00_UART=y +CONFIG_AU1X00_SERIAL_CONSOLE=y +# CONFIG_AU1X00_USB_TTY is not set +# CONFIG_AU1X00_USB_RAW is not set +# CONFIG_TXX927_SERIAL is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +# CONFIG_PRINTER is not set +# CONFIG_PPDEV is not set +# CONFIG_TIPAR is not set + +# +# I2C support +# +CONFIG_I2C=m +CONFIG_I2C_ALGOBIT=m +# CONFIG_I2C_PHILIPSPAR is not set +# CONFIG_I2C_ELV is not set +# CONFIG_I2C_VELLEMAN is not set +# CONFIG_SCx200_I2C is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_CHARDEV=m +# CONFIG_I2C_PROC 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 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_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 +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_PCMCIA_SERIAL_CS is not set +# CONFIG_SYNCLINK_CS is not set +# CONFIG_AU1X00_GPIO is not set +# CONFIG_TS_AU1X00_ADS7846 is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=m +CONFIG_AUTOFS4_FS=m +CONFIG_REISERFS_FS=m +# 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_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +CONFIG_EXT3_FS=m +CONFIG_JBD=m +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=m +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=m +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=2 +# CONFIG_CRAMFS is not set +CONFIG_TMPFS=y +CONFIG_RAMFS=y +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +# 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=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=m +# 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 + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_ROOT_NFS=y +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_SMB_FS=m +# CONFIG_SMB_NLS_DEFAULT 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=m + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_SMB_NLS=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# +CONFIG_VIDEO_PROC_FS=y +# CONFIG_I2C_PARPORT is not set +CONFIG_VIDEO_BT848=m +# CONFIG_VIDEO_PMS is not set +CONFIG_VIDEO_BWQCAM=m +CONFIG_VIDEO_CQCAM=m +CONFIG_VIDEO_W9966=m +CONFIG_VIDEO_CPIA=m +# CONFIG_VIDEO_CPIA_PP is not set +CONFIG_VIDEO_CPIA_USB=m +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_STRADIS is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIDEO_ZORAN_BUZ is not set +# CONFIG_VIDEO_ZORAN_DC10 is not set +# CONFIG_VIDEO_ZORAN_LML33 is not set +# CONFIG_VIDEO_ZR36120 is not set +# CONFIG_VIDEO_MEYE is not set + +# +# Radio Adapters +# +# CONFIG_RADIO_GEMTEK_PCI is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_MAESTRO is not set +# CONFIG_RADIO_MIROPCM20 is not set + +# +# Console drivers +# +CONFIG_VGA_CONSOLE=y +# CONFIG_MDA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_RIVA is not set +# CONFIG_FB_CLGEN is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_INTEL is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_E1356 is not set +CONFIG_FB_MB86290=y +CONFIG_FB_LYNX3DM=y +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +# CONFIG_FBCON_CFB8 is not set +CONFIG_FBCON_CFB16=y +# CONFIG_FBCON_CFB24 is not set +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_ALI5455 is not set +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_FORTE is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +CONFIG_SOUND_AU1X00=y +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +# CONFIG_USB_DEVICEFS is not set +# CONFIG_USB_BANDWIDTH 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=y +CONFIG_USB_NON_PCI_OHCI=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=m +CONFIG_USB_STORAGE_DEBUG=y +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +CONFIG_USB_STORAGE_SDDR09=y +# CONFIG_USB_STORAGE_SDDR55 is not set +CONFIG_USB_STORAGE_JUMPSHOT=y +# CONFIG_USB_ACM is not set +CONFIG_USB_PRINTER=m +CONFIG_USB_HID=m +# CONFIG_USB_HIDINPUT is not set +# 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 +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set +CONFIG_USB_IBMCAM=m +CONFIG_USB_KONICAWC=m +CONFIG_USB_OV511=m +CONFIG_USB_PWC=m +CONFIG_USB_SE401=m +CONFIG_USB_STV680=m +CONFIG_USB_VICAM=m +# CONFIG_USB_DSBR is not set +CONFIG_USB_DABUSB=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_KAWETH=m +CONFIG_USB_CATC=m +CONFIG_USB_CDCETHER=m +CONFIG_USB_USBNET=m +CONFIG_USB_USS720=m + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +# CONFIG_USB_SERIAL_DEBUG is not set +CONFIG_USB_SERIAL_GENERIC=y +# 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_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT 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=m + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_RUNTIME_DEBUG is not set +# CONFIG_KGDB is not set +# CONFIG_GDB_CONSOLE is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_MIPS_UNCACHED is not set + +# +# Library routines +# +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/linux/linux-xxs1500-2.4.21/zboot-Makefile-flags.diff b/linux/linux-xxs1500-2.4.21/zboot-Makefile-flags.diff index e69de29bb2..da17a12f38 100644 --- a/linux/linux-xxs1500-2.4.21/zboot-Makefile-flags.diff +++ b/linux/linux-xxs1500-2.4.21/zboot-Makefile-flags.diff @@ -0,0 +1,11 @@ +--- arch/mips/zboot/Makefile.o 2004-10-09 19:44:27.380145288 +0200 ++++ arch/mips/zboot/Makefile 2004-10-09 19:46:17.643382728 +0200 +@@ -27,7 +27,7 @@ + + CFLAGS := $(CPPFLAGS) -O2 -D__BOOTER__ \ + -fomit-frame-pointer -fno-strict-aliasing -fno-common \ +- -G 0 -mno-abicalls -fno-pic -mcpu=r4600 -mips2 \ ++ -G 0 -mno-abicalls -fno-pic -mabi=32 -march=mips32 -mips32 \ + -I$(TOPDIR)/arch/$(ARCH)/zboot/include \ + -I$(TOPDIR)/include/asm + AFLAGS += -D__BOOTER__ diff --git a/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch b/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch index e69de29bb2..f8343f89e1 100644 --- a/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch +++ b/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch @@ -0,0 +1,561 @@ + +# +# Patch managed by http://www.holgerschurig.de/patcher.html +# + +--- linux-2.4.17_mvl21/arch/arm/mach-sa1100/apm.c~apm-hh-merge ++++ linux-2.4.17_mvl21/arch/arm/mach-sa1100/apm.c +@@ -86,6 +86,8 @@ + int magic; + struct apm_user * next; + int suser: 1; ++ int writer : 1; ++ int reader : 1; + int suspend_wait: 1; + int suspend_result; + int suspends_pending; +@@ -105,7 +107,7 @@ + /* + * Local variables + */ +-//static int suspends_pending; ++static int suspends_pending; + //static int standbys_pending; + //static int ignore_normal_resume; + +@@ -123,8 +125,6 @@ + #else + static int power_off = 1; + #endif +-static int exit_kapmd; +-static int kapmd_running; + + static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); + static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); +@@ -192,6 +192,41 @@ + return as->events[as->event_tail]; + } + ++static void queue_event(apm_event_t event, struct apm_user *sender) ++{ ++ struct apm_user * as; ++ if (user_list == NULL) ++ return; ++ for (as = user_list; as != NULL; as = as->next) { ++ if ((as == sender) || (!as->reader)) ++ continue; ++ as->event_head = (as->event_head + 1) % APM_MAX_EVENTS; ++ if (as->event_head == as->event_tail) { ++ static int notified; ++ ++ if (notified++ == 0) ++ printk(KERN_ERR "apm: an event queue overflowed\n"); ++ as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; ++ } ++ as->events[as->event_head] = event; ++ if ((!as->suser) || (!as->writer)) ++ continue; ++ switch (event) { ++ case APM_SYS_SUSPEND: ++ case APM_USER_SUSPEND: ++ as->suspends_pending++; ++ suspends_pending++; ++ break; ++ ++ case APM_SYS_STANDBY: ++ case APM_USER_STANDBY: ++ as->standbys_pending++; ++ break; ++ } ++ } ++ wake_up_interruptible(&apm_waitqueue); ++} ++ + static int check_apm_user(struct apm_user *as, const char *func) + { + if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) { +@@ -270,7 +305,6 @@ + return 0; + } + +-extern int pm_do_suspend(void); + + static int do_ioctl(struct inode * inode, struct file *filp, + u_int cmd, u_long arg) +@@ -284,7 +318,17 @@ + return -EPERM; + switch (cmd) { + case APM_IOC_SUSPEND: +- pm_do_suspend(); ++ if (as->suspends_read > 0) { ++ as->suspends_read--; ++ as->suspends_pending--; ++ suspends_pending--; ++ } else { ++ queue_event(APM_USER_SUSPEND, as); ++ } ++ ++ if (suspends_pending <= 0) ++ wake_up(&apm_suspend_waitqueue); ++ + break; + default: + return -EINVAL; +@@ -301,6 +345,20 @@ + return 0; + filp->private_data = NULL; + lock_kernel(); ++ if (user_list == as) ++ user_list = as->next; ++ else { ++ struct apm_user * as1; ++ ++ for (as1 = user_list; ++ (as1 != NULL) && (as1->next != as); ++ as1 = as1->next) ++ ; ++ if (as1 == NULL) ++ printk(KERN_ERR "apm: filp not in user list\n"); ++ else ++ as1->next = as->next; ++ } + unlock_kernel(); + kfree(as); + return 0; +@@ -328,6 +386,8 @@ + * privileged operation -- cevans + */ + as->suser = capable(CAP_SYS_ADMIN); ++ as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE; ++ as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ; + as->next = user_list; + user_list = as; + filp->private_data = as; +@@ -411,33 +471,7 @@ + return p - buf; + } + +-#ifndef MODULE +-static int __init apm_setup(char *str) +-{ +- int invert; +- +- while ((str != NULL) && (*str != '\0')) { +- if (strncmp(str, "off", 3) == 0) +- apm_disabled = 1; +- if (strncmp(str, "on", 2) == 0) +- apm_disabled = 0; +- invert = (strncmp(str, "no-", 3) == 0); +- if (invert) +- str += 3; +- if (strncmp(str, "debug", 5) == 0) +- debug = !invert; +- if ((strncmp(str, "power-off", 9) == 0) || +- (strncmp(str, "power_off", 9) == 0)) +- power_off = !invert; +- str = strchr(str, ','); +- if (str != NULL) +- str += strspn(str, ", \t"); +- } +- return 1; +-} + +-__setup("apm=", apm_setup); +-#endif + + static struct file_operations apm_bios_fops = { + owner: THIS_MODULE, +@@ -449,13 +483,55 @@ + }; + + static struct miscdevice apm_device = { +- APM_MINOR_DEV, +- "apm_bios", +- &apm_bios_fops ++ minor : APM_MINOR_DEV, ++ name : "apm_bios", ++ fops : &apm_bios_fops + }; + + #define APM_INIT_ERROR_RETURN return -1 + ++static pid_t apmd_pid; ++static DECLARE_COMPLETION(apmd_exited); ++ ++static int apm(void *unused) ++{ ++ unsigned short bx; ++ unsigned short cx; ++ unsigned short dx; ++ int error; ++ char * power_stat; ++ char * bat_stat; ++ DECLARE_WAITQUEUE(wait, current); ++ struct apm_user au, *as; ++ ++ lock_kernel(); ++ ++ daemonize(); ++ ++ strcpy(current->comm, "kapmd"); ++ ++ as = &au; ++ as->magic = APM_BIOS_MAGIC; ++ as->event_tail = as->event_head = 0; ++ as->suspends_pending = as->standbys_pending = 0; ++ as->suspends_read = as->standbys_read = 0; ++ as->suser = 1; ++ as->writer = 1; ++ as->reader = 0; ++ ++ while (!signal_pending (current)) { ++ interruptible_sleep_on(&apm_suspend_waitqueue); ++ ++ pm_suggest_suspend(); ++ ++ queue_event(APM_NORMAL_RESUME, as); ++ } ++ ++ unlock_kernel(); ++ ++ complete_and_exit(&apmd_exited, 0); ++} ++ + /* + * Just start the APM thread. We do NOT want to do APM BIOS + * calls from anything but the APM thread, if for no other reason +@@ -494,18 +570,19 @@ + + misc_register(&apm_device); + ++ apmd_pid = kernel_thread(apm, NULL, 0); ++ + return 0; + } + + static void __exit apm_exit(void) + { + misc_deregister(&apm_device); +- remove_proc_entry("apm", NULL); ++ remove_proc_entry("apm", NULL); ++ kill_proc (apmd_pid, SIGTERM, 1); ++ wait_for_completion(&apmd_exited); + if (power_off) + pm_power_off = NULL; +- exit_kapmd = 1; +- while (kapmd_running) +- schedule(); + pm_active = 0; + } + +@@ -514,6 +591,7 @@ + + MODULE_AUTHOR("Jamey Hicks, pulling bits from original by Stephen Rothwell"); + MODULE_DESCRIPTION("A minimal emulation of APM"); ++MODULE_LICENSE("GPL"); + MODULE_PARM(debug, "i"); + MODULE_PARM_DESC(debug, "Enable debug mode"); + MODULE_PARM(power_off, "i"); +--- linux-2.4.17_mvl21/arch/arm/mach-sa1100/pm.c~apm-hh-merge ++++ linux-2.4.17_mvl21/arch/arm/mach-sa1100/pm.c +@@ -53,6 +53,10 @@ + #include <asm/arch/assabet.h> + #endif + ++#define __KERNEL_SYSCALLS__ ++#include <linux/unistd.h> ++ ++ + /* + * ARGH! Stupid ACPI people. They should define this in linux/sysctl.h, + * NOT linux/acpi.h. +@@ -64,123 +68,6 @@ + #define CTL_ACPI 9999 + #define ACPI_S1_SLP_TYP 19 + +-#ifndef CONFIG_SA1100_BEAGLE +- +-extern void sa1100_cpu_suspend(void); +-extern void sa1100_cpu_resume(void); +- +-extern unsigned long *sleep_save; /* virtual address */ +-extern unsigned long sleep_save_p; /* physical address */ +- +-#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x +-#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] +- +-int sa1110_suspend(void) +-{ +- int retval; +- +- /* set up pointer to sleep parameters */ +- sleep_save = kmalloc (SLEEP_SAVE_SIZE*sizeof(long), GFP_ATOMIC); +- if (!sleep_save) +- return -ENOMEM; +- sleep_save_p = virt_to_phys(sleep_save); +- +- retval = pm_send_all(PM_SUSPEND, (void *)2); +- if (retval) { +- kfree(sleep_save); +- return retval; +- } +- +- cli(); +- +- /* preserve current time */ +- RCNR = xtime.tv_sec; +- +- /* save vital registers */ +- SAVE(OSCR); +- SAVE(OSMR0); +- SAVE(OSMR1); +- SAVE(OSMR2); +- SAVE(OSMR3); +- SAVE(OIER); +- +- SAVE(GPDR); +- SAVE(GRER); +- SAVE(GFER); +- SAVE(GAFR); +- +- SAVE(PPDR); +- SAVE(PPSR); +- SAVE(PPAR); +- SAVE(PSDR); +- +- SAVE(Ser1SDCR0); +- +- SAVE(ICMR); +- +- /* ... maybe a global variable initialized by arch code to set this? */ +- GRER = PWER; +- GFER = 0; +- GEDR = GEDR; +- +- /* Clear previous reset status */ +- RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR; +- +- /* set resume return address */ +- PSPR = virt_to_phys(sa1100_cpu_resume); +- +- /* go zzz */ +- sa1100_cpu_suspend(); +- +- /* ensure not to come back here if it wasn't intended */ +- PSPR = 0; +- +- DPRINTK("*** made it back from resume\n"); +- +- /* restore registers */ +- RESTORE(GPDR); +- RESTORE(GRER); +- RESTORE(GFER); +- RESTORE(GAFR); +- +- /* clear any edge detect bit */ +- GEDR = GEDR; +- +- RESTORE(PPDR); +- RESTORE(PPSR); +- RESTORE(PPAR); +- RESTORE(PSDR); +- +- RESTORE(Ser1SDCR0); +- +- PSSR = PSSR_PH; +- +- RESTORE(OSMR0); +- RESTORE(OSMR1); +- RESTORE(OSMR2); +- RESTORE(OSMR3); +- RESTORE(OSCR); +- RESTORE(OIER); +- +- ICLR = 0; +- ICCR = 1; +- RESTORE(ICMR); +- +- /* restore current time */ +- xtime.tv_sec = RCNR; +- +- sti(); +- +- kfree (sleep_save); +- +-#ifdef CONFIG_CPU_FREQ +- cpufreq_restore(); +-#endif +- +- return pm_send_all(PM_RESUME, (void *)0); +-} +- +-#else //CONFIG_SA1100_BEAGLE + + typedef struct _tag_SLEEP_SAVED_DATA { + uint wakeup_addr; +@@ -363,9 +250,6 @@ + " ); + } + +-extern void h3600_control_egpio( enum ipaq_egpio_type x, int setp ); +-extern unsigned long h3600_read_egpio( void ); +- + static int GPDR_saved; + static int GPLR_saved; + static int GRER_saved; +@@ -742,21 +626,37 @@ + Ser3UTSR1 = 0xff; + } + +-#endif //CONFIG_SA1100_BEAGLE +- ++/* ++ * If pm_suggest_suspend_hook is non-NULL, it is called by pm_suggest_suspend. ++ * ++ * If sysctl_pm_do_suspend_hook is non-NULL, it is called by sysctl_pm_do_suspend. ++ * If it returns a true value, then pm_suspend is not called. ++ * Use this to hook in apmd, for now. ++ * ++ * -not exported just so that the code compiles ++ */ ++int (*pm_suggest_suspend_hook)(int state); ++int (*pm_sysctl_suspend_hook)(int state); ++int pm_use_sbin_pm_helper = 1; + static char pm_helper_path[128] = "/sbin/pm_helper"; ++extern int exec_usermodehelper(char *path, char **argv, char **envp); ++int debug_pm = 0; ++static int pm_helper_veto = 0; + +-static void ++static int + run_sbin_pm_helper( pm_request_t action ) + { + int i; + char *argv[3], *envp[8]; + + if (!pm_helper_path[0]) +- return; ++ return 2; + + if ( action != PM_SUSPEND && action != PM_RESUME ) +- return; ++ return 1; ++ ++ /* Be root */ ++ current->uid = current->gid = 0; + + i = 0; + argv[i++] = pm_helper_path; +@@ -771,14 +671,15 @@ + envp[i] = 0; + + /* other stuff we want to pass to /sbin/hotplug */ +- call_usermodehelper (argv [0], argv, envp); ++ return exec_usermodehelper (argv [0], argv, envp); + } + ++int pm_force_suspend(void); ++ + int pm_do_suspend(void) + { +- DPRINTK("suggest\n"); +- run_sbin_pm_helper(PM_SUSPEND); +- return 0; ++ DPRINTK("suspend now\n"); ++ return pm_force_suspend(); + } + + #ifdef CONFIG_SA1100_BEAGLE +@@ -863,9 +764,91 @@ + } + #endif + ++int pm_suggest_suspend(void) ++{ ++ int retval; ++ ++ if (pm_suggest_suspend_hook) { ++ if (pm_suggest_suspend_hook(PM_SUSPEND)) ++ return 0; ++ } ++ ++ if (pm_use_sbin_pm_helper) { ++ pid_t pid; ++ int res; ++ int status = 0; ++ unsigned int old_fs; ++ ++ pid = kernel_thread ((int (*) (void *)) run_sbin_pm_helper, (void *) PM_SUSPEND, 0 ); ++ if ( pid < 0 ) ++ return pid; ++ ++ if (debug_pm) ++ printk(KERN_CRIT "%s:%d got pid=%d\n", __FUNCTION__, __LINE__, pid); ++ ++ old_fs = get_fs (); ++ set_fs (get_ds ()); ++ res = waitpid(pid, &status, __WCLONE); ++ set_fs (old_fs); ++ ++ if ( pid != res ) { ++ if (debug_pm) ++ printk(KERN_CRIT ": waitpid returned %d (exit_code=%d); not suspending\n", res, status ); ++ ++ return -1; ++ } ++ ++ /*if ( WIFEXITED(status) && ( WIFEXITSTATUS(status) != 0 )) {*/ ++ if (( status & 0xff7f ) != 0 ) { ++ if (pm_helper_veto) { ++ if (debug_pm) ++ printk(KERN_CRIT "%s: SUSPEND WAS CANCELLED BY pm_helper (exit status %d)\n", __FUNCTION__, status >> 8); ++ return -1; ++ } else { ++ if (debug_pm) ++ printk(KERN_CRIT "%s: pm_helper returned %d, but going ahead anyway\n", __FUNCTION__, status >> 8); ++ } ++ } ++ } ++ ++ if (debug_pm) ++ printk(KERN_CRIT "%s: REALLY SUSPENDING NOW\n", __FUNCTION__ ); ++ ++ if (pm_sysctl_suspend_hook) { ++ if (pm_sysctl_suspend_hook(PM_SUSPEND)) ++ return 0; ++ } ++ ++ retval = pm_do_suspend(); ++ if (retval) { ++ if (debug_pm) ++ printk(KERN_CRIT "pm_suspend returned %d\n", retval); ++ return retval; ++ } ++ ++ if (pm_use_sbin_pm_helper) { ++ pid_t pid; ++ ++ if (debug_pm) ++ printk(KERN_CRIT "%s: running pm_helper for wakeup\n", __FUNCTION__); ++ ++ pid = kernel_thread ((int (*) (void *)) run_sbin_pm_helper, (void *) PM_RESUME, 0 ); ++ if ( pid < 0 ) ++ return pid; ++ ++ if ( pid != waitpid ( pid, NULL, __WCLONE )) ++ return -1; ++ } ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL(pm_suggest_suspend); ++ ++ + static struct ctl_table pm_table[] = + { +- {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0644, NULL, (proc_handler *)&pm_force_suspend}, ++/* {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0644, NULL, (proc_handler *)&pm_force_suspend}, */ + {2, "helper", pm_helper_path, sizeof(pm_helper_path), 0644, NULL, (proc_handler *)&proc_dostring}, + #ifdef CONFIG_SA1100_BEAGLE + {3, "wakeup_delayed_time", &wakeup_delayed_time, sizeof(wakeup_delayed_time), 0644, NULL, &proc_dointvec }, diff --git a/linux/montavista-sa-2.4.17-mvl21/beagle-sound.patch b/linux/montavista-sa-2.4.17-mvl21/beagle-sound.patch index e69de29bb2..f4749ca944 100644 --- a/linux/montavista-sa-2.4.17-mvl21/beagle-sound.patch +++ b/linux/montavista-sa-2.4.17-mvl21/beagle-sound.patch @@ -0,0 +1,57 @@ + +# +# Patch managed by http://www.holgerschurig.de/patcher.html +# + +--- linux-2.4.17_mvl21/drivers/sound/assabet-uda1341.c~beagle-sound.patch ++++ linux-2.4.17_mvl21/drivers/sound/assabet-uda1341.c +@@ -49,7 +49,9 @@ + #ifdef CONFIG_SA1100_BEAGLE + #include <linux/timer.h> + #include <linux/sysctl.h> +-#include <asm/io.h> ++ ++#define CCR_ADDR 0xf2000000 ++ + #endif + + #include "sa1100-audio.h" +@@ -142,15 +144,12 @@ + /* MasterIA support full sampling rate in BEAGLE and + provide click from other device */ + +- unsigned int ccr_addr; + unsigned int frg_set; + unsigned int frg_get = -1; + int count; + + audio_samplerate = val; + +- ccr_addr = (unsigned int)__ioremap((unsigned long)0x18000000, 0x00100000, 0); +- + switch(val) { + case 8000: frg_set = 0x01; break; + case 11025: frg_set = 0x02; break; +@@ -165,18 +164,16 @@ + count = 0; + while(frg_set != frg_get) { + /* Ensure CPLD read we gave */ +- *((volatile unsigned int*)(ccr_addr+0x04)) = frg_set; ++ *((volatile unsigned int*)(CCR_ADDR+0x04)) = frg_set; + +- frg_get = *((volatile unsigned int*)(ccr_addr+0x0024)) & 0xFF; ++ frg_get = *((volatile unsigned int*)(CCR_ADDR+0x0024)) & 0xFF; + if ( ++count >= 10 ) { + schedule_timeout( 1 ); + count = 0; + } +-// printk("*** Sound: write %02x[%08x], read %02x[%08x]\n", frg_set, ccr_addr+0x04, +-// frg_get, ccr_addr+0x24); ++// printk("*** Sound: write %02x[%08x], read %02x[%08x]\n", frg_set, CCR_ADDR+0x04, ++// frg_get, CCR_ADDR+0x24); + } +- +- __iounmap((void*)ccr_addr); + #else + struct uda1341_cfg cfg; + u_int clk_ref, clk_div; diff --git a/linux/montavista-sa-2.4.17-mvl21/disable-pcmcia-probe.patch b/linux/montavista-sa-2.4.17-mvl21/disable-pcmcia-probe.patch index e69de29bb2..79ba036323 100644 --- a/linux/montavista-sa-2.4.17-mvl21/disable-pcmcia-probe.patch +++ b/linux/montavista-sa-2.4.17-mvl21/disable-pcmcia-probe.patch @@ -0,0 +1,17 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux/drivers/pcmcia/Config.in~disable-pcmcia-probe 2003-05-13 11:18:23.000000000 +0200 ++++ linux/drivers/pcmcia/Config.in 2004-05-27 13:59:50.000000000 +0200 +@@ -15,9 +15,6 @@ + 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 diff --git a/linux/montavista-sa-2.4.17-mvl21/iw240_we15-6.diff b/linux/montavista-sa-2.4.17-mvl21/iw240_we15-6.diff index e69de29bb2..2ebfd8ec12 100644 --- a/linux/montavista-sa-2.4.17-mvl21/iw240_we15-6.diff +++ b/linux/montavista-sa-2.4.17-mvl21/iw240_we15-6.diff @@ -0,0 +1,399 @@ +diff -u -p linux/include/linux/wireless.14.h linux/include/linux/wireless.h +--- linux/include/linux/wireless.14.h Mon Dec 2 18:51:00 2002 ++++ linux/include/linux/wireless.h Mon Dec 2 18:53:35 2002 +@@ -1,7 +1,7 @@ + /* + * This file define a set of standard wireless extensions + * +- * Version : 14 25.1.02 ++ * Version : 15 12.7.02 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> + * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. +@@ -80,7 +80,7 @@ + * (there is some stuff that will be added in the future...) + * I just plan to increment with each new version. + */ +-#define WIRELESS_EXT 14 ++#define WIRELESS_EXT 15 + + /* + * Changes : +@@ -153,17 +153,32 @@ + * - Define additional specific event numbers + * - Add "addr" and "param" fields in union iwreq_data + * - AP scanning stuff (SIOCSIWSCAN and friends) ++ * ++ * V14 to V15 ++ * ---------- ++ * - Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg ++ * - Make struct iw_freq signed (both m & e), add explicit padding ++ * - Add IWEVCUSTOM for driver specific event/scanning token ++ * - Add IW_MAX_GET_SPY for driver returning a lot of addresses ++ * - Add IW_TXPOW_RANGE for range of Tx Powers ++ * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points ++ * - Add IW_MODE_MONITOR for passive monitor + */ + + /**************************** CONSTANTS ****************************/ + + /* -------------------------- IOCTL LIST -------------------------- */ + +-/* Basic operations */ ++/* Wireless Identification */ + #define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */ + #define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ +-#define SIOCSIWNWID 0x8B02 /* set network id (the cell) */ +-#define SIOCGIWNWID 0x8B03 /* get network id */ ++/* SIOCGIWNAME is used to verify the presence of Wireless Extensions. ++ * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"... ++ * Don't put the name of your driver there, it's useless. */ ++ ++/* Basic operations */ ++#define SIOCSIWNWID 0x8B02 /* set network id (pre-802.11) */ ++#define SIOCGIWNWID 0x8B03 /* get network id (the cell) */ + #define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */ + #define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */ + #define SIOCSIWMODE 0x8B06 /* set operation mode */ +@@ -178,16 +193,18 @@ + #define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */ + #define SIOCSIWSTATS 0x8B0E /* Unused */ + #define SIOCGIWSTATS 0x8B0F /* Get /proc/net/wireless stats */ ++/* SIOCGIWSTATS is strictly used between user space and the kernel, and ++ * is never passed to the driver (i.e. the driver will never see it). */ + +-/* Mobile IP support */ ++/* Mobile IP support (statistics per MAC address) */ + #define SIOCSIWSPY 0x8B10 /* set spy addresses */ + #define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */ + + /* Access Point manipulation */ + #define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ + #define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ +-#define SIOCGIWAPLIST 0x8B17 /* get list of access point in range */ +-#define SIOCSIWSCAN 0x8B18 /* trigger scanning */ ++#define SIOCGIWAPLIST 0x8B17 /* Deprecated in favor of scanning */ ++#define SIOCSIWSCAN 0x8B18 /* trigger scanning (list cells) */ + #define SIOCGIWSCAN 0x8B19 /* get scanning results */ + + /* 802.11 specific support */ +@@ -197,9 +214,7 @@ + #define SIOCGIWNICKN 0x8B1D /* get node name/nickname */ + /* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit + * within the 'iwreq' structure, so we need to use the 'data' member to +- * point to a string in user space, like it is done for RANGE... +- * The "flags" member indicate if the ESSID is active or not (promiscuous). +- */ ++ * point to a string in user space, like it is done for RANGE... */ + + /* Other parameters useful in 802.11 and some other devices */ + #define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */ +@@ -257,7 +272,10 @@ + /* Most events use the same identifier as ioctl requests */ + + #define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ +-#define IWEVQUAL 0x8C01 /* Quality part of statistics */ ++#define IWEVQUAL 0x8C01 /* Quality part of statistics (scan) */ ++#define IWEVCUSTOM 0x8C02 /* Driver specific ascii string */ ++#define IWEVREGISTERED 0x8C03 /* Discovered a new node (AP mode) */ ++#define IWEVEXPIRED 0x8C04 /* Expired a node (AP mode) */ + + #define IWEVFIRST 0x8C00 + +@@ -273,7 +291,8 @@ + #define IW_PRIV_TYPE_BYTE 0x1000 /* Char as number */ + #define IW_PRIV_TYPE_CHAR 0x2000 /* Char as character */ + #define IW_PRIV_TYPE_INT 0x4000 /* 32 bits int */ +-#define IW_PRIV_TYPE_FLOAT 0x5000 ++#define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */ ++#define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */ + + #define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed nuber of args */ + +@@ -297,13 +316,16 @@ + + /* Maximum tx powers in the range struct */ + #define IW_MAX_TXPOWER 8 ++/* Note : if you more than 8 TXPowers, just set the max and min or ++ * a few of them in the struct iw_range. */ + + /* Maximum of address that you may set with SPY */ +-#define IW_MAX_SPY 8 ++#define IW_MAX_SPY 8 /* set */ ++#define IW_MAX_GET_SPY 64 /* get */ + + /* Maximum of address that you may get in the + list of access points in range */ +-#define IW_MAX_AP 8 ++#define IW_MAX_AP 64 + + /* Maximum size of the ESSID and NICKN strings */ + #define IW_ESSID_MAX_SIZE 32 +@@ -315,6 +337,7 @@ + #define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */ + #define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */ + #define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ ++#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */ + + /* Maximum number of size of encoding token available + * they are listed in the range structure */ +@@ -350,8 +373,10 @@ + #define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ + + /* Transmit Power flags available */ ++#define IW_TXPOW_TYPE 0x00FF /* Type of value */ + #define IW_TXPOW_DBM 0x0000 /* Value is in dBm */ + #define IW_TXPOW_MWATT 0x0001 /* Value is in mW */ ++#define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */ + + /* Retry limits and lifetime flags available */ + #define IW_RETRY_ON 0x0000 /* No details... */ +@@ -376,6 +401,9 @@ + /* Maximum size of returned data */ + #define IW_SCAN_MAX_DATA 4096 /* In bytes */ + ++/* Max number of char in custom event - use multiple of them if needed */ ++#define IW_CUSTOM_MAX 256 /* In bytes */ ++ + /****************************** TYPES ******************************/ + + /* --------------------------- SUBTYPES --------------------------- */ +@@ -411,9 +439,10 @@ struct iw_point + */ + struct iw_freq + { +- __u32 m; /* Mantissa */ +- __u16 e; /* Exponent */ ++ __s32 m; /* Mantissa */ ++ __s16 e; /* Exponent */ + __u8 i; /* List index (when in range struct) */ ++ __u8 pad; /* Unused - just for alignement */ + }; + + /* +diff -u -p linux/include/net/iw_handler.14.h linux/include/net/iw_handler.h +--- linux/include/net/iw_handler.14.h Mon Dec 2 18:51:17 2002 ++++ linux/include/net/iw_handler.h Mon Dec 2 18:54:51 2002 +@@ -1,7 +1,7 @@ + /* + * This file define the new driver API for Wireless Extensions + * +- * Version : 3 17.1.02 ++ * Version : 4 21.6.02 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> + * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved. +@@ -206,7 +206,7 @@ + * will be needed... + * I just plan to increment with each new version. + */ +-#define IW_HANDLER_VERSION 3 ++#define IW_HANDLER_VERSION 4 + + /* + * Changes : +@@ -217,6 +217,9 @@ + * - Add Wireless Event support : + * o wireless_send_event() prototype + * o iwe_stream_add_event/point() inline functions ++ * V3 to V4 ++ * -------- ++ * - Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes + */ + + /**************************** CONSTANTS ****************************/ +@@ -233,10 +236,10 @@ + #define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */ + #define IW_HEADER_TYPE_UINT 4 /* __u32 */ + #define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */ +-#define IW_HEADER_TYPE_POINT 6 /* struct iw_point */ +-#define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */ +-#define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */ +-#define IW_HEADER_TYPE_QUAL 9 /* struct iw_quality */ ++#define IW_HEADER_TYPE_ADDR 6 /* struct sockaddr */ ++#define IW_HEADER_TYPE_POINT 8 /* struct iw_point */ ++#define IW_HEADER_TYPE_PARAM 9 /* struct iw_param */ ++#define IW_HEADER_TYPE_QUAL 10 /* struct iw_quality */ + + /* Handling flags */ + /* Most are not implemented. I just use them as a reminder of some +diff -u -p linux/net/core/wireless.14.c linux/net/core/wireless.c +--- linux/net/core/wireless.14.c Mon Dec 2 18:51:35 2002 ++++ linux/net/core/wireless.c Mon Dec 2 18:53:10 2002 +@@ -33,8 +33,16 @@ + * o Propagate events as rtnetlink IFLA_WIRELESS option + * o Generate event on selected SET requests + * +- * v4 - 18.04.01 - Jean II ++ * v4 - 18.04.02 - Jean II + * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1 ++ * ++ * v5 - 21.06.02 - Jean II ++ * o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup) ++ * o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes ++ * o Add IWEVCUSTOM for driver specific event/scanning token ++ * o Turn on WE_STRICT_WRITE by default + kernel warning ++ * o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num) ++ * o Fix off-by-one in test (extra_size <= IFNAMSIZ) + */ + + /***************************** INCLUDES *****************************/ +@@ -50,8 +58,9 @@ + + /**************************** CONSTANTS ****************************/ + +-/* This will be turned on later on... */ +-#undef WE_STRICT_WRITE /* Check write buffer size */ ++/* Enough lenience, let's make sure things are proper... */ ++#define WE_STRICT_WRITE /* Check write buffer size */ ++/* I'll probably drop both the define and kernel message in the next version */ + + /* Debuging stuff */ + #undef WE_IOCTL_DEBUG /* Debug IOCTL API */ +@@ -106,7 +115,7 @@ static const struct iw_ioctl_description + /* SIOCSIWSPY */ + { IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0}, + /* SIOCGIWSPY */ +- { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0}, ++ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_GET_SPY, 0}, + /* -- hole -- */ + { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, + /* -- hole -- */ +@@ -176,25 +185,41 @@ static const struct iw_ioctl_description + { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, + /* IWEVQUAL */ + { IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0}, ++ /* IWEVCUSTOM */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_CUSTOM_MAX, 0}, ++ /* IWEVREGISTERED */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, ++ /* IWEVEXPIRED */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, + }; + static const int standard_event_num = (sizeof(standard_event) / + sizeof(struct iw_ioctl_description)); + + /* Size (in bytes) of the various private data types */ +-static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; ++static const char priv_type_size[] = { ++ 0, /* IW_PRIV_TYPE_NONE */ ++ 1, /* IW_PRIV_TYPE_BYTE */ ++ 1, /* IW_PRIV_TYPE_CHAR */ ++ 0, /* Not defined */ ++ sizeof(__u32), /* IW_PRIV_TYPE_INT */ ++ sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */ ++ sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */ ++ 0, /* Not defined */ ++}; + + /* Size (in bytes) of various events */ + static const int event_type_size[] = { +- IW_EV_LCP_LEN, ++ IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */ ++ 0, ++ IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ + 0, +- IW_EV_CHAR_LEN, ++ IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */ ++ IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ ++ IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ + 0, +- IW_EV_UINT_LEN, +- IW_EV_FREQ_LEN, + IW_EV_POINT_LEN, /* Without variable payload */ +- IW_EV_PARAM_LEN, +- IW_EV_ADDR_LEN, +- IW_EV_QUAL_LEN, ++ IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ ++ IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ + }; + + /************************ COMMON SUBROUTINES ************************/ +@@ -440,8 +465,10 @@ static inline int ioctl_export_private(s + return -EFAULT; + #ifdef WE_STRICT_WRITE + /* Check if there is enough buffer up there */ +- if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1)) ++ if(iwr->u.data.length < dev->wireless_handlers->num_private_args) { ++ printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args); + return -E2BIG; ++ } + #endif /* WE_STRICT_WRITE */ + + /* Set the number of available ioctls. */ +@@ -471,6 +498,7 @@ static inline int ioctl_standard_call(st + const struct iw_ioctl_description * descr; + struct iw_request_info info; + int ret = -EINVAL; ++ int user_size = 0; + + /* Get the description of the IOCTL */ + if((cmd - SIOCIWFIRST) >= standard_ioctl_num) +@@ -518,11 +546,8 @@ static inline int ioctl_standard_call(st + /* Check NULL pointer */ + if(iwr->u.data.pointer == NULL) + return -EFAULT; +-#ifdef WE_STRICT_WRITE +- /* Check if there is enough buffer up there */ +- if(iwr->u.data.length < descr->max_tokens) +- return -E2BIG; +-#endif /* WE_STRICT_WRITE */ ++ /* Save user space buffer size for checking */ ++ user_size = iwr->u.data.length; + } + + #ifdef WE_IOCTL_DEBUG +@@ -559,6 +584,15 @@ static inline int ioctl_standard_call(st + + /* If we have something to return to the user */ + if (!ret && IW_IS_GET(cmd)) { ++#ifdef WE_STRICT_WRITE ++ /* Check if there is enough buffer up there */ ++ if(user_size < iwr->u.data.length) { ++ printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length); ++ kfree(extra); ++ return -E2BIG; ++ } ++#endif /* WE_STRICT_WRITE */ ++ + err = copy_to_user(iwr->u.data.pointer, extra, + iwr->u.data.length * + descr->token_size); +@@ -646,12 +680,18 @@ static inline int ioctl_private_call(str + /* Compute the size of the set/get arguments */ + if(descr != NULL) { + if(IW_IS_SET(cmd)) { ++ int offset = 0; /* For sub-ioctls */ ++ /* Check for sub-ioctl handler */ ++ if(descr->name[0] == '\0') ++ /* Reserve one int for sub-ioctl index */ ++ offset = sizeof(__u32); ++ + /* Size of set arguments */ + extra_size = get_priv_size(descr->set_args); + + /* Does it fits in iwr ? */ + if((descr->set_args & IW_PRIV_SIZE_FIXED) && +- (extra_size < IFNAMSIZ)) ++ ((extra_size + offset) <= IFNAMSIZ)) + extra_size = 0; + } else { + /* Size of set arguments */ +@@ -659,7 +699,7 @@ static inline int ioctl_private_call(str + + /* Does it fits in iwr ? */ + if((descr->get_args & IW_PRIV_SIZE_FIXED) && +- (extra_size < IFNAMSIZ)) ++ (extra_size <= IFNAMSIZ)) + extra_size = 0; + } + } +@@ -925,7 +965,7 @@ void wireless_send_event(struct net_devi + * The best the driver could do is to log an error message. + * We will do it ourselves instead... + */ +- printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n", ++ printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n", + dev->name, cmd); + return; + } diff --git a/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w13-5.diff b/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w13-5.diff index e69de29bb2..a27a7654a9 100644 --- a/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w13-5.diff +++ b/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w13-5.diff @@ -0,0 +1,1513 @@ +diff -u -p -r --new-file linux/include/linux-w12/netdevice.h linux/include/linux/netdevice.h +--- linux/include/linux-w12/netdevice.h Thu Nov 22 11:47:09 2001 ++++ linux/include/linux/netdevice.h Thu Jan 17 12:00:39 2002 +@@ -278,6 +278,10 @@ struct net_device + struct net_device_stats* (*get_stats)(struct net_device *dev); + struct iw_statistics* (*get_wireless_stats)(struct net_device *dev); + ++ /* List of functions to handle Wireless Extensions (instead of ioctl). ++ * See <net/iw_handler.h> for details. Jean II */ ++ struct iw_handler_def * wireless_handlers; ++ + /* + * This marks the end of the "visible" part of the structure. All + * fields hereafter are internal to the system, and may change at +diff -u -p -r --new-file linux/include/linux-w12/wireless.h linux/include/linux/wireless.h +--- linux/include/linux-w12/wireless.h Thu Nov 22 11:47:12 2001 ++++ linux/include/linux/wireless.h Thu Jan 17 12:04:08 2002 +@@ -1,9 +1,10 @@ + /* + * This file define a set of standard wireless extensions + * +- * Version : 12 5.10.01 ++ * Version : 13 6.12.01 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> ++ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. + */ + + #ifndef _LINUX_WIRELESS_H +@@ -11,6 +12,8 @@ + + /************************** DOCUMENTATION **************************/ + /* ++ * Initial APIs (1996 -> onward) : ++ * ----------------------------- + * Basically, the wireless extensions are for now a set of standard ioctl + * call + /proc/net/wireless + * +@@ -27,16 +30,27 @@ + * We have the list of command plus a structure descibing the + * data exchanged... + * Note that to add these ioctl, I was obliged to modify : +- * net/core/dev.c (two place + add include) +- * net/ipv4/af_inet.c (one place + add include) ++ * # net/core/dev.c (two place + add include) ++ * # net/ipv4/af_inet.c (one place + add include) + * + * /proc/net/wireless is a copy of /proc/net/dev. + * We have a structure for data passed from the driver to /proc/net/wireless + * Too add this, I've modified : +- * net/core/dev.c (two other places) +- * include/linux/netdevice.h (one place) +- * include/linux/proc_fs.h (one place) ++ * # net/core/dev.c (two other places) ++ * # include/linux/netdevice.h (one place) ++ * # include/linux/proc_fs.h (one place) ++ * ++ * New driver API (2001 -> onward) : ++ * ------------------------------- ++ * This file is only concerned with the user space API and common definitions. ++ * The new driver API is defined and documented in : ++ * # include/net/iw_handler.h + * ++ * Note as well that /proc/net/wireless implementation has now moved in : ++ * # include/linux/wireless.c ++ * ++ * Other comments : ++ * -------------- + * Do not add here things that are redundant with other mechanisms + * (drivers init, ifconfig, /proc/net/dev, ...) and with are not + * wireless specific. +@@ -54,16 +68,14 @@ + #include <linux/socket.h> /* for "struct sockaddr" et al */ + #include <linux/if.h> /* for IFNAMSIZ and co... */ + +-/**************************** CONSTANTS ****************************/ +- +-/* --------------------------- VERSION --------------------------- */ ++/***************************** VERSION *****************************/ + /* + * This constant is used to know the availability of the wireless + * extensions and to know which version of wireless extensions it is + * (there is some stuff that will be added in the future...) + * I just plan to increment with each new version. + */ +-#define WIRELESS_EXT 12 ++#define WIRELESS_EXT 13 + + /* + * Changes : +@@ -123,12 +135,20 @@ + * - Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space + * - Add new statistics (frag, retry, beacon) + * - Add average quality (for user space calibration) ++ * ++ * V12 to V13 ++ * ---------- ++ * - Document creation of new driver API. ++ * - Extract union iwreq_data from struct iwreq (for new driver API). ++ * - Rename SIOCSIWNAME as SIOCSIWCOMMIT + */ + ++/**************************** CONSTANTS ****************************/ ++ + /* -------------------------- IOCTL LIST -------------------------- */ + + /* Basic operations */ +-#define SIOCSIWNAME 0x8B00 /* Unused */ ++#define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */ + #define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ + #define SIOCSIWNWID 0x8B02 /* set network id (the cell) */ + #define SIOCGIWNWID 0x8B03 /* get network id */ +@@ -414,13 +434,49 @@ struct iw_statistics + + /* ------------------------ IOCTL REQUEST ------------------------ */ + /* ++ * This structure defines the payload of an ioctl, and is used ++ * below. ++ * ++ * Note that this structure should fit on the memory footprint ++ * of iwreq (which is the same as ifreq), which mean a max size of ++ * 16 octets = 128 bits. Warning, pointers might be 64 bits wide... ++ * You should check this when increasing the structures defined ++ * above in this file... ++ */ ++union iwreq_data ++{ ++ /* Config - generic */ ++ char name[IFNAMSIZ]; ++ /* Name : used to verify the presence of wireless extensions. ++ * Name of the protocol/provider... */ ++ ++ struct iw_point essid; /* Extended network name */ ++ struct iw_param nwid; /* network id (or domain - the cell) */ ++ struct iw_freq freq; /* frequency or channel : ++ * 0-1000 = channel ++ * > 1000 = frequency in Hz */ ++ ++ struct iw_param sens; /* signal level threshold */ ++ struct iw_param bitrate; /* default bit rate */ ++ struct iw_param txpower; /* default transmit power */ ++ struct iw_param rts; /* RTS threshold threshold */ ++ struct iw_param frag; /* Fragmentation threshold */ ++ __u32 mode; /* Operation mode */ ++ struct iw_param retry; /* Retry limits & lifetime */ ++ ++ struct iw_point encoding; /* Encoding stuff : tokens */ ++ struct iw_param power; /* PM duration/timeout */ ++ ++ struct sockaddr ap_addr; /* Access point address */ ++ ++ struct iw_point data; /* Other large parameters */ ++}; ++ ++/* + * The structure to exchange data for ioctl. + * This structure is the same as 'struct ifreq', but (re)defined for + * convenience... +- * +- * Note that it should fit on the same memory footprint ! +- * You should check this when increasing the above structures (16 octets) +- * 16 octets = 128 bits. Warning, pointers might be 64 bits wide... ++ * Do I need to remind you about structure size (32 octets) ? + */ + struct iwreq + { +@@ -429,35 +485,8 @@ struct iwreq + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */ + } ifr_ifrn; + +- /* Data part */ +- union +- { +- /* Config - generic */ +- char name[IFNAMSIZ]; +- /* Name : used to verify the presence of wireless extensions. +- * Name of the protocol/provider... */ +- +- struct iw_point essid; /* Extended network name */ +- struct iw_param nwid; /* network id (or domain - the cell) */ +- struct iw_freq freq; /* frequency or channel : +- * 0-1000 = channel +- * > 1000 = frequency in Hz */ +- +- struct iw_param sens; /* signal level threshold */ +- struct iw_param bitrate; /* default bit rate */ +- struct iw_param txpower; /* default transmit power */ +- struct iw_param rts; /* RTS threshold threshold */ +- struct iw_param frag; /* Fragmentation threshold */ +- __u32 mode; /* Operation mode */ +- struct iw_param retry; /* Retry limits & lifetime */ +- +- struct iw_point encoding; /* Encoding stuff : tokens */ +- struct iw_param power; /* PM duration/timeout */ +- +- struct sockaddr ap_addr; /* Access point address */ +- +- struct iw_point data; /* Other large parameters */ +- } u; ++ /* Data part (defined just above) */ ++ union iwreq_data u; + }; + + /* -------------------------- IOCTL DATA -------------------------- */ +diff -u -p -r --new-file linux/include/net-w12/iw_handler.h linux/include/net/iw_handler.h +--- linux/include/net-w12/iw_handler.h Wed Dec 31 16:00:00 1969 ++++ linux/include/net/iw_handler.h Thu Jan 17 12:16:46 2002 +@@ -0,0 +1,374 @@ ++/* ++ * This file define the new driver API for Wireless Extensions ++ * ++ * Version : 2 6.12.01 ++ * ++ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> ++ * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved. ++ */ ++ ++#ifndef _IW_HANDLER_H ++#define _IW_HANDLER_H ++ ++/************************** DOCUMENTATION **************************/ ++/* ++ * Initial driver API (1996 -> onward) : ++ * ----------------------------------- ++ * The initial API just sends the IOCTL request received from user space ++ * to the driver (via the driver ioctl handler). The driver has to ++ * handle all the rest... ++ * ++ * The initial API also defines a specific handler in struct net_device ++ * to handle wireless statistics. ++ * ++ * The initial APIs served us well and has proven a reasonably good design. ++ * However, there is a few shortcommings : ++ * o No events, everything is a request to the driver. ++ * o Large ioctl function in driver with gigantic switch statement ++ * (i.e. spaghetti code). ++ * o Driver has to mess up with copy_to/from_user, and in many cases ++ * does it unproperly. Common mistakes are : ++ * * buffer overflows (no checks or off by one checks) ++ * * call copy_to/from_user with irq disabled ++ * o The user space interface is tied to ioctl because of the use ++ * copy_to/from_user. ++ * ++ * New driver API (2001 -> onward) : ++ * ------------------------------- ++ * The new driver API is just a bunch of standard functions (handlers), ++ * each handling a specific Wireless Extension. The driver just export ++ * the list of handler it supports, and those will be called apropriately. ++ * ++ * I tried to keep the main advantage of the previous API (simplicity, ++ * efficiency and light weight), and also I provide a good dose of backward ++ * compatibility (most structures are the same, driver can use both API ++ * simultaneously, ...). ++ * Hopefully, I've also addressed the shortcomming of the initial API. ++ * ++ * The advantage of the new API are : ++ * o Handling of Extensions in driver broken in small contained functions ++ * o Tighter checks of ioctl before calling the driver ++ * o Flexible commit strategy (at least, the start of it) ++ * o Backward compatibility (can be mixed with old API) ++ * o Driver doesn't have to worry about memory and user-space issues ++ * The last point is important for the following reasons : ++ * o You are now able to call the new driver API from any API you ++ * want (including from within other parts of the kernel). ++ * o Common mistakes are avoided (buffer overflow, user space copy ++ * with irq disabled and so on). ++ * ++ * The Drawback of the new API are : ++ * o bloat (especially kernel) ++ * o need to migrate existing drivers to new API ++ * My initial testing shows that the new API adds around 3kB to the kernel ++ * and save between 0 and 5kB from a typical driver. ++ * Also, as all structures and data types are unchanged, the migration is ++ * quite straightforward (but tedious). ++ * ++ * --- ++ * ++ * The new driver API is defined below in this file. User space should ++ * not be aware of what's happening down there... ++ * ++ * A new kernel wrapper is in charge of validating the IOCTLs and calling ++ * the appropriate driver handler. This is implemented in : ++ * # net/core/wireless.c ++ * ++ * The driver export the list of handlers in : ++ * # include/linux/netdevice.h (one place) ++ * ++ * The new driver API is available for WIRELESS_EXT >= 13. ++ * Good luck with migration to the new API ;-) ++ */ ++ ++/* ---------------------- THE IMPLEMENTATION ---------------------- */ ++/* ++ * Some of the choice I've made are pretty controversials. Defining an ++ * API is very much weighting compromises. This goes into some of the ++ * details and the thinking behind the implementation. ++ * ++ * Implementation goals : ++ * -------------------- ++ * The implementation goals were as follow : ++ * o Obvious : you should not need a PhD to understand what's happening, ++ * the benefit is easier maintainance. ++ * o Flexible : it should accomodate a wide variety of driver ++ * implementations and be as flexible as the old API. ++ * o Lean : it should be efficient memory wise to minimise the impact ++ * on kernel footprint. ++ * o Transparent to user space : the large number of user space ++ * applications that use Wireless Extensions should not need ++ * any modifications. ++ * ++ * Array of functions versus Struct of functions ++ * --------------------------------------------- ++ * 1) Having an array of functions allow the kernel code to access the ++ * handler in a single lookup, which is much more efficient (think hash ++ * table here). ++ * 2) The only drawback is that driver writer may put their handler in ++ * the wrong slot. This is trivial to test (I set the frequency, the ++ * bitrate changes). Once the handler is in the proper slot, it will be ++ * there forever, because the array is only extended at the end. ++ * 3) Backward/forward compatibility : adding new handler just require ++ * extending the array, so you can put newer driver in older kernel ++ * without having to patch the kernel code (and vice versa). ++ * ++ * All handler are of the same generic type ++ * ---------------------------------------- ++ * That's a feature !!! ++ * 1) Having a generic handler allow to have generic code, which is more ++ * efficient. If each of the handler was individually typed I would need ++ * to add a big switch in the kernel (== more bloat). This solution is ++ * more scalable, adding new Wireless Extensions doesn't add new code. ++ * 2) You can use the same handler in different slots of the array. For ++ * hardware, it may be more efficient or logical to handle multiple ++ * Wireless Extensions with a single function, and the API allow you to ++ * do that. (An example would be a single record on the card to control ++ * both bitrate and frequency, the handler would read the old record, ++ * modify it according to info->cmd and rewrite it). ++ * ++ * Functions prototype uses union iwreq_data ++ * ----------------------------------------- ++ * Some would have prefered functions defined this way : ++ * static int mydriver_ioctl_setrate(struct net_device *dev, ++ * long rate, int auto) ++ * 1) The kernel code doesn't "validate" the content of iwreq_data, and ++ * can't do it (different hardware may have different notion of what a ++ * valid frequency is), so we don't pretend that we do it. ++ * 2) The above form is not extendable. If I want to add a flag (for ++ * example to distinguish setting max rate and basic rate), I would ++ * break the prototype. Using iwreq_data is more flexible. ++ * 3) Also, the above form is not generic (see above). ++ * 4) I don't expect driver developper using the wrong field of the ++ * union (Doh !), so static typechecking doesn't add much value. ++ * 5) Lastly, you can skip the union by doing : ++ * static int mydriver_ioctl_setrate(struct net_device *dev, ++ * struct iw_request_info *info, ++ * struct iw_param *rrq, ++ * char *extra) ++ * And then adding the handler in the array like this : ++ * (iw_handler) mydriver_ioctl_setrate, // SIOCSIWRATE ++ * ++ * Using functions and not a registry ++ * ---------------------------------- ++ * Another implementation option would have been for every instance to ++ * define a registry (a struct containing all the Wireless Extensions) ++ * and only have a function to commit the registry to the hardware. ++ * 1) This approach can be emulated by the current code, but not ++ * vice versa. ++ * 2) Some drivers don't keep any configuration in the driver, for them ++ * adding such a registry would be a significant bloat. ++ * 3) The code to translate from Wireless Extension to native format is ++ * needed anyway, so it would not reduce significantely the amount of code. ++ * 4) The current approach only selectively translate Wireless Extensions ++ * to native format and only selectively set, whereas the registry approach ++ * would require to translate all WE and set all parameters for any single ++ * change. ++ * 5) For many Wireless Extensions, the GET operation return the current ++ * dynamic value, not the value that was set. ++ * ++ * This header is <net/iw_handler.h> ++ * --------------------------------- ++ * 1) This header is kernel space only and should not be exported to ++ * user space. Headers in "include/linux/" are exported, headers in ++ * "include/net/" are not. ++ * ++ * Mixed 32/64 bit issues ++ * ---------------------- ++ * The Wireless Extensions are designed to be 64 bit clean, by using only ++ * datatypes with explicit storage size. ++ * There are some issues related to kernel and user space using different ++ * memory model, and in particular 64bit kernel with 32bit user space. ++ * The problem is related to struct iw_point, that contains a pointer ++ * that *may* need to be translated. ++ * This is quite messy. The new API doesn't solve this problem (it can't), ++ * but is a step in the right direction : ++ * 1) Meta data about each ioctl is easily available, so we know what type ++ * of translation is needed. ++ * 2) The move of data between kernel and user space is only done in a single ++ * place in the kernel, so adding specific hooks in there is possible. ++ * 3) In the long term, it allows to move away from using ioctl as the ++ * user space API. ++ * ++ * So many comments and so few code ++ * -------------------------------- ++ * That's a feature. Comments won't bloat the resulting kernel binary. ++ */ ++ ++/***************************** INCLUDES *****************************/ ++ ++#include <linux/wireless.h> /* IOCTL user space API */ ++ ++/***************************** VERSION *****************************/ ++/* ++ * This constant is used to know which version of the driver API is ++ * available. Hopefully, this will be pretty stable and no changes ++ * will be needed... ++ * I just plan to increment with each new version. ++ */ ++#define IW_HANDLER_VERSION 2 ++ ++/**************************** CONSTANTS ****************************/ ++ ++/* Special error message for the driver to indicate that we ++ * should do a commit after return from the iw_handler */ ++#define EIWCOMMIT EINPROGRESS ++ ++/* Flags available in struct iw_request_info */ ++#define IW_REQUEST_FLAG_NONE 0x0000 /* No flag so far */ ++ ++/* Type of headers we know about (basically union iwreq_data) */ ++#define IW_HEADER_TYPE_NULL 0 /* Not available */ ++#define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */ ++#define IW_HEADER_TYPE_UINT 4 /* __u32 */ ++#define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */ ++#define IW_HEADER_TYPE_POINT 6 /* struct iw_point */ ++#define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */ ++#define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */ ++ ++/* Handling flags */ ++/* Most are not implemented. I just use them as a reminder of some ++ * cool features we might need one day ;-) */ ++#define IW_DESCR_FLAG_NONE 0x0000 /* Obvious */ ++/* Wrapper level flags */ ++#define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */ ++#define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */ ++#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET request is ROOT only */ ++/* Driver level flags */ ++#define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */ ++ ++/****************************** TYPES ******************************/ ++ ++/* ----------------------- WIRELESS HANDLER ----------------------- */ ++/* ++ * A wireless handler is just a standard function, that looks like the ++ * ioctl handler. ++ * We also define there how a handler list look like... As the Wireless ++ * Extension space is quite dense, we use a simple array, which is faster ++ * (that's the perfect hash table ;-). ++ */ ++ ++/* ++ * Meta data about the request passed to the iw_handler. ++ * Most handlers can safely ignore what's in there. ++ * The 'cmd' field might come handy if you want to use the same handler ++ * for multiple command... ++ * This struct is also my long term insurance. I can add new fields here ++ * without breaking the prototype of iw_handler... ++ */ ++struct iw_request_info ++{ ++ __u16 cmd; /* Wireless Extension command */ ++ __u16 flags; /* More to come ;-) */ ++}; ++ ++/* ++ * This is how a function handling a Wireless Extension should look ++ * like (both get and set, standard and private). ++ */ ++typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++/* ++ * This define all the handler that the driver export. ++ * As you need only one per driver type, please use a static const ++ * shared by all driver instances... Same for the members... ++ * This will be linked from net_device in <linux/netdevice.h> ++ */ ++struct iw_handler_def ++{ ++ /* Number of handlers defined (more precisely, index of the ++ * last defined handler + 1) */ ++ __u16 num_standard; ++ __u16 num_private; ++ /* Number of private arg description */ ++ __u16 num_private_args; ++ ++ /* Array of handlers for standard ioctls ++ * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME] ++ */ ++ iw_handler * standard; ++ ++ /* Array of handlers for private ioctls ++ * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV] ++ */ ++ iw_handler * private; ++ ++ /* Arguments of private handler. This one is just a list, so you ++ * can put it in any order you want and should not leave holes... ++ * We will automatically export that to user space... */ ++ struct iw_priv_args * private_args; ++ ++ /* In the long term, get_wireless_stats will move from ++ * 'struct net_device' to here, to minimise bloat. */ ++}; ++ ++/* ----------------------- WIRELESS EVENTS ----------------------- */ ++/* ++ * Currently we don't support events, so let's just plan for the ++ * future... ++ */ ++ ++/* ++ * A Wireless Event. ++ */ ++// How do we define short header ? We don't want a flag on length. ++// Probably a flag on event ? Highest bit to zero... ++struct iw_event ++{ ++ __u16 length; /* Lenght of this stuff */ ++ __u16 event; /* Wireless IOCTL */ ++ union iwreq_data header; /* IOCTL fixed payload */ ++ char extra[0]; /* Optional IOCTL data */ ++}; ++ ++/* ---------------------- IOCTL DESCRIPTION ---------------------- */ ++/* ++ * One of the main goal of the new interface is to deal entirely with ++ * user space/kernel space memory move. ++ * For that, we need to know : ++ * o if iwreq is a pointer or contain the full data ++ * o what is the size of the data to copy ++ * ++ * For private IOCTLs, we use the same rules as used by iwpriv and ++ * defined in struct iw_priv_args. ++ * ++ * For standard IOCTLs, things are quite different and we need to ++ * use the stuctures below. Actually, this struct is also more ++ * efficient, but that's another story... ++ */ ++ ++/* ++ * Describe how a standard IOCTL looks like. ++ */ ++struct iw_ioctl_description ++{ ++ __u8 header_type; /* NULL, iw_point or other */ ++ __u8 token_type; /* Future */ ++ __u16 token_size; /* Granularity of payload */ ++ __u16 min_tokens; /* Min acceptable token number */ ++ __u16 max_tokens; /* Max acceptable token number */ ++ __u32 flags; /* Special handling of the request */ ++}; ++ ++/* Need to think of short header translation table. Later. */ ++ ++/**************************** PROTOTYPES ****************************/ ++/* ++ * Functions part of the Wireless Extensions (defined in net/core/wireless.c). ++ * Those may be called only within the kernel. ++ */ ++ ++/* First : function strictly used inside the kernel */ ++ ++/* Handle /proc/net/wireless, called in net/code/dev.c */ ++extern int dev_get_wireless_info(char * buffer, char **start, off_t offset, ++ int length); ++ ++/* Handle IOCTLs, called in net/code/dev.c */ ++extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd); ++ ++/* Second : functions that may be called by driver modules */ ++/* None yet */ ++ ++#endif /* _LINUX_WIRELESS_H */ +diff -u -p -r --new-file linux/net/core-w12/Makefile linux/net/core/Makefile +--- linux/net/core-w12/Makefile Tue Oct 30 15:08:12 2001 ++++ linux/net/core/Makefile Thu Jan 17 11:06:07 2002 +@@ -26,5 +26,8 @@ obj-$(CONFIG_NET) += dev.o dev_mcast.o d + obj-$(CONFIG_NETFILTER) += netfilter.o + obj-$(CONFIG_NET_DIVERT) += dv.o + obj-$(CONFIG_NET_PROFILE) += profile.o ++obj-$(CONFIG_NET_RADIO) += wireless.o ++# Ugly. I wish all wireless drivers were moved in drivers/net/wireless ++obj-$(CONFIG_NET_PCMCIA_RADIO) += wireless.o + + include $(TOPDIR)/Rules.make +diff -u -p -r --new-file linux/net/core-w12/dev.c linux/net/core/dev.c +--- linux/net/core-w12/dev.c Wed Nov 7 14:39:36 2001 ++++ linux/net/core/dev.c Thu Jan 17 11:06:07 2002 +@@ -102,6 +102,7 @@ + #include <linux/module.h> + #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO) + #include <linux/wireless.h> /* Note : will define WIRELESS_EXT */ ++#include <net/iw_handler.h> + #endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ + #ifdef CONFIG_PLIP + extern int plip_init(void); +@@ -1796,122 +1797,6 @@ static int dev_proc_stats(char *buffer, + #endif /* CONFIG_PROC_FS */ + + +-#ifdef WIRELESS_EXT +-#ifdef CONFIG_PROC_FS +- +-/* +- * Print one entry of /proc/net/wireless +- * This is a clone of /proc/net/dev (just above) +- */ +-static int sprintf_wireless_stats(char *buffer, struct net_device *dev) +-{ +- /* Get stats from the driver */ +- struct iw_statistics *stats = (dev->get_wireless_stats ? +- dev->get_wireless_stats(dev) : +- (struct iw_statistics *) NULL); +- int size; +- +- if (stats != (struct iw_statistics *) NULL) { +- size = sprintf(buffer, +- "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d %6d %6d %6d\n", +- dev->name, +- stats->status, +- stats->qual.qual, +- stats->qual.updated & 1 ? '.' : ' ', +- stats->qual.level, +- stats->qual.updated & 2 ? '.' : ' ', +- stats->qual.noise, +- stats->qual.updated & 4 ? '.' : ' ', +- stats->discard.nwid, +- stats->discard.code, +- stats->discard.fragment, +- stats->discard.retries, +- stats->discard.misc, +- stats->miss.beacon); +- stats->qual.updated = 0; +- } +- else +- size = 0; +- +- return size; +-} +- +-/* +- * Print info for /proc/net/wireless (print all entries) +- * This is a clone of /proc/net/dev (just above) +- */ +-static int dev_get_wireless_info(char * buffer, char **start, off_t offset, +- int length) +-{ +- int len = 0; +- off_t begin = 0; +- off_t pos = 0; +- int size; +- +- struct net_device * dev; +- +- size = sprintf(buffer, +- "Inter-| sta-| Quality | Discarded packets | Missed\n" +- " face | tus | link level noise | nwid crypt frag retry misc | beacon\n" +- ); +- +- pos += size; +- len += size; +- +- read_lock(&dev_base_lock); +- for (dev = dev_base; dev != NULL; dev = dev->next) { +- size = sprintf_wireless_stats(buffer + len, dev); +- len += size; +- pos = begin + len; +- +- if (pos < offset) { +- len = 0; +- begin = pos; +- } +- if (pos > offset + length) +- break; +- } +- read_unlock(&dev_base_lock); +- +- *start = buffer + (offset - begin); /* Start of wanted data */ +- len -= (offset - begin); /* Start slop */ +- if (len > length) +- len = length; /* Ending slop */ +- if (len < 0) +- len = 0; +- +- return len; +-} +-#endif /* CONFIG_PROC_FS */ +- +-/* +- * Allow programatic access to /proc/net/wireless even if /proc +- * doesn't exist... Also more efficient... +- */ +-static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr) +-{ +- /* Get stats from the driver */ +- struct iw_statistics *stats = (dev->get_wireless_stats ? +- dev->get_wireless_stats(dev) : +- (struct iw_statistics *) NULL); +- +- if (stats != (struct iw_statistics *) NULL) { +- struct iwreq * wrq = (struct iwreq *)ifr; +- +- /* Copy statistics to the user buffer */ +- if(copy_to_user(wrq->u.data.pointer, stats, +- sizeof(struct iw_statistics))) +- return -EFAULT; +- +- /* Check if we need to clear the update flag */ +- if(wrq->u.data.flags != 0) +- stats->qual.updated = 0; +- return(0); +- } else +- return -EOPNOTSUPP; +-} +-#endif /* WIRELESS_EXT */ +- + /** + * netdev_set_master - set up master/slave pair + * @slave: slave device +@@ -2209,11 +2094,6 @@ static int dev_ifsioc(struct ifreq *ifr, + notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); + return 0; + +-#ifdef WIRELESS_EXT +- case SIOCGIWSTATS: +- return dev_iwstats(dev, ifr); +-#endif /* WIRELESS_EXT */ +- + /* + * Unknown or private ioctl + */ +@@ -2239,17 +2119,6 @@ static int dev_ifsioc(struct ifreq *ifr, + return -EOPNOTSUPP; + } + +-#ifdef WIRELESS_EXT +- if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { +- if (dev->do_ioctl) { +- if (!netif_device_present(dev)) +- return -ENODEV; +- return dev->do_ioctl(dev, ifr, cmd); +- } +- return -EOPNOTSUPP; +- } +-#endif /* WIRELESS_EXT */ +- + } + return -EINVAL; + } +@@ -2431,7 +2300,8 @@ int dev_ioctl(unsigned int cmd, void *ar + } + dev_load(ifr.ifr_name); + rtnl_lock(); +- ret = dev_ifsioc(&ifr, cmd); ++ /* Follow me in net/core/wireless.c */ ++ ret = wireless_process_ioctl(&ifr, cmd); + rtnl_unlock(); + if (!ret && IW_IS_GET(cmd) && + copy_to_user(arg, &ifr, sizeof(struct ifreq))) +@@ -2856,6 +2726,7 @@ int __init net_dev_init(void) + proc_net_create("dev", 0, dev_get_info); + create_proc_read_entry("net/softnet_stat", 0, 0, dev_proc_stats, NULL); + #ifdef WIRELESS_EXT ++ /* Available in net/core/wireless.c */ + proc_net_create("wireless", 0, dev_get_wireless_info); + #endif /* WIRELESS_EXT */ + #endif /* CONFIG_PROC_FS */ +diff -u -p -r --new-file linux/net/core-w12/wireless.c linux/net/core/wireless.c +--- linux/net/core-w12/wireless.c Wed Dec 31 16:00:00 1969 ++++ linux/net/core/wireless.c Mon Jan 21 11:13:23 2002 +@@ -0,0 +1,733 @@ ++/* ++ * This file implement the Wireless Extensions APIs. ++ * ++ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> ++ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. ++ * ++ * (As all part of the Linux kernel, this file is GPL) ++ */ ++ ++/************************** DOCUMENTATION **************************/ ++/* ++ * API definition : ++ * -------------- ++ * See <linux/wireless.h> for details of the APIs and the rest. ++ * ++ * History : ++ * ------- ++ * ++ * v1 - 5.12.01 - Jean II ++ * o Created this file. ++ * ++ * v2 - 13.12.01 - Jean II ++ * o Move /proc/net/wireless stuff from net/core/dev.c to here ++ * o Make Wireless Extension IOCTLs go through here ++ * o Added iw_handler handling ;-) ++ * o Added standard ioctl description ++ * o Initial dumb commit strategy based on orinoco.c ++ */ ++ ++/***************************** INCLUDES *****************************/ ++ ++#include <asm/uaccess.h> /* copy_to_user() */ ++#include <linux/config.h> /* Not needed ??? */ ++#include <linux/types.h> /* off_t */ ++#include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */ ++ ++#include <linux/wireless.h> /* Pretty obvious */ ++#include <net/iw_handler.h> /* New driver API */ ++ ++/**************************** CONSTANTS ****************************/ ++ ++/* This will be turned on later on... */ ++#undef WE_STRICT_WRITE /* Check write buffer size */ ++ ++/* Debuging stuff */ ++#undef WE_IOCTL_DEBUG /* Debug IOCTL API */ ++ ++/************************* GLOBAL VARIABLES *************************/ ++/* ++ * You should not use global variables, because or re-entrancy. ++ * On our case, it's only const, so it's OK... ++ */ ++static const struct iw_ioctl_description standard_ioctl[] = { ++ /* SIOCSIWCOMMIT (internal) */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWNAME */ ++ { IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWNWID */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT}, ++ /* SIOCGIWNWID */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWFREQ */ ++ { IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT}, ++ /* SIOCGIWFREQ */ ++ { IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWMODE */ ++ { IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT}, ++ /* SIOCGIWMODE */ ++ { IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWSENS */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWSENS */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWRANGE */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWRANGE */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_range), IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWPRIV */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWPRIV (handled directly by us) */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWSTATS */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWSTATS (handled directly by us) */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWSPY */ ++ { IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0}, ++ /* SIOCGIWSPY */ ++ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWAP */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, ++ /* SIOCGIWAP */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWAPLIST */ ++ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWESSID */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT}, ++ /* SIOCGIWESSID */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWNICKN */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, ++ /* SIOCGIWNICKN */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWRATE */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWRATE */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWRTS */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWRTS */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWFRAG */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWFRAG */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWTXPOW */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWTXPOW */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWRETRY */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWRETRY */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWENCODE */ ++ { IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT}, ++ /* SIOCGIWENCODE */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT}, ++ /* SIOCSIWPOWER */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWPOWER */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++}; ++ ++/* Size (in bytes) of the various private data types */ ++char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; ++ ++/************************ COMMON SUBROUTINES ************************/ ++/* ++ * Stuff that may be used in various place or doesn't fit in one ++ * of the section below. ++ */ ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Return the driver handler associated with a specific Wireless Extension. ++ * Called from various place, so make sure it remains efficient. ++ */ ++static inline iw_handler get_handler(struct net_device *dev, ++ unsigned int cmd) ++{ ++ unsigned int index; /* MUST be unsigned */ ++ ++ /* Check if we have some wireless handlers defined */ ++ if(dev->wireless_handlers == NULL) ++ return NULL; ++ ++ /* Try as a standard command */ ++ index = cmd - SIOCIWFIRST; ++ if(index < dev->wireless_handlers->num_standard) ++ return dev->wireless_handlers->standard[index]; ++ ++ /* Try as a private command */ ++ index = cmd - SIOCIWFIRSTPRIV; ++ if(index < dev->wireless_handlers->num_private) ++ return dev->wireless_handlers->private[index]; ++ ++ /* Not found */ ++ return NULL; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Get statistics out of the driver ++ */ ++static inline struct iw_statistics *get_wireless_stats(struct net_device *dev) ++{ ++ return (dev->get_wireless_stats ? ++ dev->get_wireless_stats(dev) : ++ (struct iw_statistics *) NULL); ++ /* In the future, get_wireless_stats may move from 'struct net_device' ++ * to 'struct iw_handler_def', to de-bloat struct net_device. ++ * Definitely worse a thought... */ ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Call the commit handler in the driver ++ * (if exist and if conditions are right) ++ * ++ * Note : our current commit strategy is currently pretty dumb, ++ * but we will be able to improve on that... ++ * The goal is to try to agreagate as many changes as possible ++ * before doing the commit. Drivers that will define a commit handler ++ * are usually those that need a reset after changing parameters, so ++ * we want to minimise the number of reset. ++ * A cool idea is to use a timer : at each "set" command, we re-set the ++ * timer, when the timer eventually fires, we call the driver. ++ * Hopefully, more on that later. ++ * ++ * Also, I'm waiting to see how many people will complain about the ++ * netif_running(dev) test. I'm open on that one... ++ * Hopefully, the driver will remember to do a commit in "open()" ;-) ++ */ ++static inline int call_commit_handler(struct net_device * dev) ++{ ++ if((netif_running(dev)) && ++ (dev->wireless_handlers->standard[0] != NULL)) { ++ /* Call the commit handler on the driver */ ++ return dev->wireless_handlers->standard[0](dev, NULL, ++ NULL, NULL); ++ } else ++ return 0; /* Command completed successfully */ ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Number of private arguments ++ */ ++static inline int get_priv_size(__u16 args) ++{ ++ int num = args & IW_PRIV_SIZE_MASK; ++ int type = (args & IW_PRIV_TYPE_MASK) >> 12; ++ ++ return num * priv_type_size[type]; ++} ++ ++ ++/******************** /proc/net/wireless SUPPORT ********************/ ++/* ++ * The /proc/net/wireless file is a human readable user-space interface ++ * exporting various wireless specific statistics from the wireless devices. ++ * This is the most popular part of the Wireless Extensions ;-) ++ * ++ * This interface is a pure clone of /proc/net/dev (in net/core/dev.c). ++ * The content of the file is basically the content of "struct iw_statistics". ++ */ ++ ++#ifdef CONFIG_PROC_FS ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Print one entry (line) of /proc/net/wireless ++ */ ++static inline int sprintf_wireless_stats(char *buffer, struct net_device *dev) ++{ ++ /* Get stats from the driver */ ++ struct iw_statistics *stats; ++ int size; ++ ++ stats = get_wireless_stats(dev); ++ if (stats != (struct iw_statistics *) NULL) { ++ size = sprintf(buffer, ++ "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d %6d %6d %6d\n", ++ dev->name, ++ stats->status, ++ stats->qual.qual, ++ stats->qual.updated & 1 ? '.' : ' ', ++ stats->qual.level, ++ stats->qual.updated & 2 ? '.' : ' ', ++ stats->qual.noise, ++ stats->qual.updated & 4 ? '.' : ' ', ++ stats->discard.nwid, ++ stats->discard.code, ++ stats->discard.fragment, ++ stats->discard.retries, ++ stats->discard.misc, ++ stats->miss.beacon); ++ stats->qual.updated = 0; ++ } ++ else ++ size = 0; ++ ++ return size; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Print info for /proc/net/wireless (print all entries) ++ */ ++int dev_get_wireless_info(char * buffer, char **start, off_t offset, ++ int length) ++{ ++ int len = 0; ++ off_t begin = 0; ++ off_t pos = 0; ++ int size; ++ ++ struct net_device * dev; ++ ++ size = sprintf(buffer, ++ "Inter-| sta-| Quality | Discarded packets | Missed\n" ++ " face | tus | link level noise | nwid crypt frag retry misc | beacon\n" ++ ); ++ ++ pos += size; ++ len += size; ++ ++ read_lock(&dev_base_lock); ++ for (dev = dev_base; dev != NULL; dev = dev->next) { ++ size = sprintf_wireless_stats(buffer + len, dev); ++ len += size; ++ pos = begin + len; ++ ++ if (pos < offset) { ++ len = 0; ++ begin = pos; ++ } ++ if (pos > offset + length) ++ break; ++ } ++ read_unlock(&dev_base_lock); ++ ++ *start = buffer + (offset - begin); /* Start of wanted data */ ++ len -= (offset - begin); /* Start slop */ ++ if (len > length) ++ len = length; /* Ending slop */ ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++#endif /* CONFIG_PROC_FS */ ++ ++/************************** IOCTL SUPPORT **************************/ ++/* ++ * The original user space API to configure all those Wireless Extensions ++ * is through IOCTLs. ++ * In there, we check if we need to call the new driver API (iw_handler) ++ * or just call the driver ioctl handler. ++ */ ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Allow programatic access to /proc/net/wireless even if /proc ++ * doesn't exist... Also more efficient... ++ */ ++static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr) ++{ ++ /* Get stats from the driver */ ++ struct iw_statistics *stats; ++ ++ stats = get_wireless_stats(dev); ++ if (stats != (struct iw_statistics *) NULL) { ++ struct iwreq * wrq = (struct iwreq *)ifr; ++ ++ /* Copy statistics to the user buffer */ ++ if(copy_to_user(wrq->u.data.pointer, stats, ++ sizeof(struct iw_statistics))) ++ return -EFAULT; ++ ++ /* Check if we need to clear the update flag */ ++ if(wrq->u.data.flags != 0) ++ stats->qual.updated = 0; ++ return 0; ++ } else ++ return -EOPNOTSUPP; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Export the driver private handler definition ++ * They will be picked up by tools like iwpriv... ++ */ ++static inline int ioctl_export_private(struct net_device * dev, ++ struct ifreq * ifr) ++{ ++ struct iwreq * iwr = (struct iwreq *) ifr; ++ ++ /* Check if the driver has something to export */ ++ if((dev->wireless_handlers->num_private_args == 0) || ++ (dev->wireless_handlers->private_args == NULL)) ++ return -EOPNOTSUPP; ++ ++ /* Check NULL pointer */ ++ if(iwr->u.data.pointer == NULL) ++ return -EFAULT; ++#ifdef WE_STRICT_WRITE ++ /* Check if there is enough buffer up there */ ++ if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1)) ++ return -E2BIG; ++#endif /* WE_STRICT_WRITE */ ++ ++ /* Set the number of available ioctls. */ ++ iwr->u.data.length = dev->wireless_handlers->num_private_args; ++ ++ /* Copy structure to the user buffer. */ ++ if (copy_to_user(iwr->u.data.pointer, ++ dev->wireless_handlers->private_args, ++ sizeof(struct iw_priv_args) * iwr->u.data.length)) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Wrapper to call a standard Wireless Extension handler. ++ * We do various checks and also take care of moving data between ++ * user space and kernel space. ++ */ ++static inline int ioctl_standard_call(struct net_device * dev, ++ struct ifreq * ifr, ++ unsigned int cmd, ++ iw_handler handler) ++{ ++ struct iwreq * iwr = (struct iwreq *) ifr; ++ const struct iw_ioctl_description * descr; ++ struct iw_request_info info; ++ int ret = -EINVAL; ++ ++ /* Get the description of the IOCTL */ ++ descr = &(standard_ioctl[cmd - SIOCIWFIRST]); ++ ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n", ++ ifr->ifr_name, cmd); ++ printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); ++#endif /* WE_IOCTL_DEBUG */ ++ ++ /* Prepare the call */ ++ info.cmd = cmd; ++ info.flags = 0; ++ ++ /* Check if we have a pointer to user space data or not */ ++ if(descr->header_type != IW_HEADER_TYPE_POINT) { ++ /* No extra arguments. Trivial to handle */ ++ ret = handler(dev, &info, &(iwr->u), NULL); ++ } else { ++ char * extra; ++ int err; ++ ++ /* Check what user space is giving us */ ++ if(IW_IS_SET(cmd)) { ++ /* Check NULL pointer */ ++ if((iwr->u.data.pointer == NULL) && ++ (iwr->u.data.length != 0)) ++ return -EFAULT; ++ /* Check if number of token fits within bounds */ ++ if(iwr->u.data.length > descr->max_tokens) ++ return -E2BIG; ++ if(iwr->u.data.length < descr->min_tokens) ++ return -EINVAL; ++ } else { ++ /* Check NULL pointer */ ++ if(iwr->u.data.pointer == NULL) ++ return -EFAULT; ++#ifdef WE_STRICT_WRITE ++ /* Check if there is enough buffer up there */ ++ if(iwr->u.data.length < descr->max_tokens) ++ return -E2BIG; ++#endif /* WE_STRICT_WRITE */ ++ } ++ ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Malloc %d bytes\n", ++ descr->max_tokens * descr->token_size); ++#endif /* WE_IOCTL_DEBUG */ ++ ++ /* Always allocate for max space. Easier, and won't last ++ * long... */ ++ extra = kmalloc(descr->max_tokens * descr->token_size, ++ GFP_KERNEL); ++ if (extra == NULL) { ++ return -ENOMEM; ++ } ++ ++ /* If it is a SET, get all the extra data in here */ ++ if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { ++ err = copy_from_user(extra, iwr->u.data.pointer, ++ iwr->u.data.length * ++ descr->token_size); ++ if (err) { ++ kfree(extra); ++ return -EFAULT; ++ } ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Got %d bytes\n", ++ iwr->u.data.length * descr->token_size); ++#endif /* WE_IOCTL_DEBUG */ ++ } ++ ++ /* Call the handler */ ++ ret = handler(dev, &info, &(iwr->u), extra); ++ ++ /* If we have something to return to the user */ ++ if (!ret && IW_IS_GET(cmd)) { ++ err = copy_to_user(iwr->u.data.pointer, extra, ++ iwr->u.data.length * ++ descr->token_size); ++ if (err) ++ ret = -EFAULT; ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Wrote %d bytes\n", ++ iwr->u.data.length * descr->token_size); ++#endif /* WE_IOCTL_DEBUG */ ++ } ++ ++ /* Cleanup - I told you it wasn't that long ;-) */ ++ kfree(extra); ++ } ++ ++ /* Call commit handler if needed and defined */ ++ if(ret == -EIWCOMMIT) ++ ret = call_commit_handler(dev); ++ ++ /* Here, we will generate the appropriate event if needed */ ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Wrapper to call a private Wireless Extension handler. ++ * We do various checks and also take care of moving data between ++ * user space and kernel space. ++ * It's not as nice and slimline as the standard wrapper. The cause ++ * is struct iw_priv_args, which was not really designed for the ++ * job we are going here. ++ * ++ * IMPORTANT : This function prevent to set and get data on the same ++ * IOCTL and enforce the SET/GET convention. Not doing it would be ++ * far too hairy... ++ * If you need to set and get data at the same time, please don't use ++ * a iw_handler but process it in your ioctl handler (i.e. use the ++ * old driver API). ++ */ ++static inline int ioctl_private_call(struct net_device * dev, ++ struct ifreq * ifr, ++ unsigned int cmd, ++ iw_handler handler) ++{ ++ struct iwreq * iwr = (struct iwreq *) ifr; ++ struct iw_priv_args * descr = NULL; ++ struct iw_request_info info; ++ int extra_size = 0; ++ int i; ++ int ret = -EINVAL; ++ ++ /* Get the description of the IOCTL */ ++ for(i = 0; i < dev->wireless_handlers->num_private_args; i++) ++ if(cmd == dev->wireless_handlers->private_args[i].cmd) { ++ descr = &(dev->wireless_handlers->private_args[i]); ++ break; ++ } ++ ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n", ++ ifr->ifr_name, cmd); ++ if(descr) { ++ printk(KERN_DEBUG "Name %s, set %X, get %X\n", ++ descr->name, descr->set_args, descr->get_args); ++ } ++#endif /* WE_IOCTL_DEBUG */ ++ ++ /* Compute the size of the set/get arguments */ ++ if(descr != NULL) { ++ if(IW_IS_SET(cmd)) { ++ /* Size of set arguments */ ++ extra_size = get_priv_size(descr->set_args); ++ ++ /* Does it fits in iwr ? */ ++ if((descr->set_args & IW_PRIV_SIZE_FIXED) && ++ (extra_size < IFNAMSIZ)) ++ extra_size = 0; ++ } else { ++ /* Size of set arguments */ ++ extra_size = get_priv_size(descr->get_args); ++ ++ /* Does it fits in iwr ? */ ++ if((descr->get_args & IW_PRIV_SIZE_FIXED) && ++ (extra_size < IFNAMSIZ)) ++ extra_size = 0; ++ } ++ } ++ ++ /* Prepare the call */ ++ info.cmd = cmd; ++ info.flags = 0; ++ ++ /* Check if we have a pointer to user space data or not. */ ++ if(extra_size == 0) { ++ /* No extra arguments. Trivial to handle */ ++ ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u)); ++ } else { ++ char * extra; ++ int err; ++ ++ /* Check what user space is giving us */ ++ if(IW_IS_SET(cmd)) { ++ /* Check NULL pointer */ ++ if((iwr->u.data.pointer == NULL) && ++ (iwr->u.data.length != 0)) ++ return -EFAULT; ++ ++ /* Does it fits within bounds ? */ ++ if(iwr->u.data.length > (descr->set_args & ++ IW_PRIV_SIZE_MASK)) ++ return -E2BIG; ++ } else { ++ /* Check NULL pointer */ ++ if(iwr->u.data.pointer == NULL) ++ return -EFAULT; ++ } ++ ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Malloc %d bytes\n", extra_size); ++#endif /* WE_IOCTL_DEBUG */ ++ ++ /* Always allocate for max space. Easier, and won't last ++ * long... */ ++ extra = kmalloc(extra_size, GFP_KERNEL); ++ if (extra == NULL) { ++ return -ENOMEM; ++ } ++ ++ /* If it is a SET, get all the extra data in here */ ++ if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { ++ err = copy_from_user(extra, iwr->u.data.pointer, ++ extra_size); ++ if (err) { ++ kfree(extra); ++ return -EFAULT; ++ } ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length); ++#endif /* WE_IOCTL_DEBUG */ ++ } ++ ++ /* Call the handler */ ++ ret = handler(dev, &info, &(iwr->u), extra); ++ ++ /* If we have something to return to the user */ ++ if (!ret && IW_IS_GET(cmd)) { ++ err = copy_to_user(iwr->u.data.pointer, extra, ++ extra_size); ++ if (err) ++ ret = -EFAULT; ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Wrote %d elem\n", ++ iwr->u.data.length); ++#endif /* WE_IOCTL_DEBUG */ ++ } ++ ++ /* Cleanup - I told you it wasn't that long ;-) */ ++ kfree(extra); ++ } ++ ++ ++ /* Call commit handler if needed and defined */ ++ if(ret == -EIWCOMMIT) ++ ret = call_commit_handler(dev); ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Main IOCTl dispatcher. Called from the main networking code ++ * (dev_ioctl() in net/core/dev.c). ++ * Check the type of IOCTL and call the appropriate wrapper... ++ */ ++int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd) ++{ ++ struct net_device *dev; ++ iw_handler handler; ++ ++ /* Permissions are already checked in dev_ioctl() before calling us. ++ * The copy_to/from_user() of ifr is also dealt with in there */ ++ ++ /* Make sure the device exist */ ++ if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) ++ return -ENODEV; ++ ++ /* A bunch of special cases, then the generic case... ++ * Note that 'cmd' is already filtered in dev_ioctl() with ++ * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ ++ switch(cmd) ++ { ++ case SIOCGIWSTATS: ++ /* Get Wireless Stats */ ++ return dev_iwstats(dev, ifr); ++ ++ case SIOCGIWPRIV: ++ /* Check if we have some wireless handlers defined */ ++ if(dev->wireless_handlers != NULL) { ++ /* We export to user space the definition of ++ * the private handler ourselves */ ++ return ioctl_export_private(dev, ifr); ++ } ++ // ## Fall-through for old API ## ++ default: ++ /* Generic IOCTL */ ++ /* Basic check */ ++ if (!netif_device_present(dev)) ++ return -ENODEV; ++ /* New driver API : try to find the handler */ ++ handler = get_handler(dev, cmd); ++ if(handler != NULL) { ++ /* Standard and private are not the same */ ++ if(cmd < SIOCIWFIRSTPRIV) ++ return ioctl_standard_call(dev, ++ ifr, ++ cmd, ++ handler); ++ else ++ return ioctl_private_call(dev, ++ ifr, ++ cmd, ++ handler); ++ } ++ /* Old driver API : call driver ioctl handler */ ++ if (dev->do_ioctl) { ++ return dev->do_ioctl(dev, ifr, cmd); ++ } ++ return -EOPNOTSUPP; ++ } ++ /* Not reached */ ++ return -EINVAL; ++} diff --git a/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff b/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff index e69de29bb2..539b160068 100644 --- a/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff +++ b/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff @@ -0,0 +1,838 @@ +diff -u -p -r --new-file linux/include/linux-w13/rtnetlink.h linux/include/linux/rtnetlink.h +--- linux/include/linux-w13/rtnetlink.h Thu Jun 6 14:44:08 2002 ++++ linux/include/linux/rtnetlink.h Thu Jun 6 15:47:44 2002 +@@ -440,12 +440,14 @@ enum + #define IFLA_COST IFLA_COST + IFLA_PRIORITY, + #define IFLA_PRIORITY IFLA_PRIORITY +- IFLA_MASTER ++ IFLA_MASTER, + #define IFLA_MASTER IFLA_MASTER ++ IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */ ++#define IFLA_WIRELESS IFLA_WIRELESS + }; + + +-#define IFLA_MAX IFLA_MASTER ++#define IFLA_MAX IFLA_WIRELESS + + #define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) + #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) +diff -u -p -r --new-file linux/include/linux-w13/wireless.h linux/include/linux/wireless.h +--- linux/include/linux-w13/wireless.h Thu Jun 6 15:00:28 2002 ++++ linux/include/linux/wireless.h Thu Jun 6 15:47:44 2002 +@@ -1,10 +1,10 @@ + /* + * This file define a set of standard wireless extensions + * +- * Version : 13 6.12.01 ++ * Version : 14 25.1.02 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> +- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. ++ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. + */ + + #ifndef _LINUX_WIRELESS_H +@@ -40,7 +40,7 @@ + * # include/linux/netdevice.h (one place) + * # include/linux/proc_fs.h (one place) + * +- * New driver API (2001 -> onward) : ++ * New driver API (2002 -> onward) : + * ------------------------------- + * This file is only concerned with the user space API and common definitions. + * The new driver API is defined and documented in : +@@ -49,6 +49,11 @@ + * Note as well that /proc/net/wireless implementation has now moved in : + * # include/linux/wireless.c + * ++ * Wireless Events (2002 -> onward) : ++ * -------------------------------- ++ * Events are defined at the end of this file, and implemented in : ++ * # include/linux/wireless.c ++ * + * Other comments : + * -------------- + * Do not add here things that are redundant with other mechanisms +@@ -75,7 +80,7 @@ + * (there is some stuff that will be added in the future...) + * I just plan to increment with each new version. + */ +-#define WIRELESS_EXT 13 ++#define WIRELESS_EXT 14 + + /* + * Changes : +@@ -141,6 +146,13 @@ + * - Document creation of new driver API. + * - Extract union iwreq_data from struct iwreq (for new driver API). + * - Rename SIOCSIWNAME as SIOCSIWCOMMIT ++ * ++ * V13 to V14 ++ * ---------- ++ * - Wireless Events support : define struct iw_event ++ * - Define additional specific event numbers ++ * - Add "addr" and "param" fields in union iwreq_data ++ * - AP scanning stuff (SIOCSIWSCAN and friends) + */ + + /**************************** CONSTANTS ****************************/ +@@ -175,6 +187,8 @@ + #define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ + #define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ + #define SIOCGIWAPLIST 0x8B17 /* get list of access point in range */ ++#define SIOCSIWSCAN 0x8B18 /* trigger scanning */ ++#define SIOCGIWSCAN 0x8B19 /* get scanning results */ + + /* 802.11 specific support */ + #define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */ +@@ -238,6 +252,15 @@ + #define IW_IS_SET(cmd) (!((cmd) & 0x1)) + #define IW_IS_GET(cmd) ((cmd) & 0x1) + ++/* ----------------------- WIRELESS EVENTS ----------------------- */ ++/* Those are *NOT* ioctls, do not issue request on them !!! */ ++/* Most events use the same identifier as ioctl requests */ ++ ++#define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ ++#define IWEVQUAL 0x8C01 /* Quality part of statistics */ ++ ++#define IWEVFIRST 0x8C00 ++ + /* ------------------------- PRIVATE INFO ------------------------- */ + /* + * The following is used with SIOCGIWPRIV. It allow a driver to define +@@ -340,6 +363,19 @@ + #define IW_RETRY_MAX 0x0002 /* Value is a maximum */ + #define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ + ++/* Scanning request flags */ ++#define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */ ++#define IW_SCAN_ALL_ESSID 0x0001 /* Scan all ESSIDs */ ++#define IW_SCAN_THIS_ESSID 0x0002 /* Scan only this ESSID */ ++#define IW_SCAN_ALL_FREQ 0x0004 /* Scan all Frequencies */ ++#define IW_SCAN_THIS_FREQ 0x0008 /* Scan only this Frequency */ ++#define IW_SCAN_ALL_MODE 0x0010 /* Scan all Modes */ ++#define IW_SCAN_THIS_MODE 0x0020 /* Scan only this Mode */ ++#define IW_SCAN_ALL_RATE 0x0040 /* Scan all Bit-Rates */ ++#define IW_SCAN_THIS_RATE 0x0080 /* Scan only this Bit-Rate */ ++/* Maximum size of returned data */ ++#define IW_SCAN_MAX_DATA 4096 /* In bytes */ ++ + /****************************** TYPES ******************************/ + + /* --------------------------- SUBTYPES --------------------------- */ +@@ -466,9 +502,12 @@ union iwreq_data + + struct iw_point encoding; /* Encoding stuff : tokens */ + struct iw_param power; /* PM duration/timeout */ ++ struct iw_quality qual; /* Quality part of statistics */ + + struct sockaddr ap_addr; /* Access point address */ ++ struct sockaddr addr; /* Destination address (hw) */ + ++ struct iw_param param; /* Other small parameters */ + struct iw_point data; /* Other large parameters */ + }; + +@@ -595,5 +634,36 @@ struct iw_priv_args + __u16 get_args; /* Type and number of args */ + char name[IFNAMSIZ]; /* Name of the extension */ + }; ++ ++/* ----------------------- WIRELESS EVENTS ----------------------- */ ++/* ++ * Wireless events are carried through the rtnetlink socket to user ++ * space. They are encapsulated in the IFLA_WIRELESS field of ++ * a RTM_NEWLINK message. ++ */ ++ ++/* ++ * A Wireless Event. Contains basically the same data as the ioctl... ++ */ ++struct iw_event ++{ ++ __u16 len; /* Real lenght of this stuff */ ++ __u16 cmd; /* Wireless IOCTL */ ++ union iwreq_data u; /* IOCTL fixed payload */ ++}; ++ ++/* Size of the Event prefix (including padding and alignement junk) */ ++#define IW_EV_LCP_LEN (sizeof(struct iw_event) - sizeof(union iwreq_data)) ++/* Size of the various events */ ++#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ) ++#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32)) ++#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq)) ++#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point)) ++#define IW_EV_PARAM_LEN (IW_EV_LCP_LEN + sizeof(struct iw_param)) ++#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr)) ++#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality)) ++ ++/* Note : in the case of iw_point, the extra data will come at the ++ * end of the event */ + + #endif /* _LINUX_WIRELESS_H */ +diff -u -p -r --new-file linux/include/net-w13/iw_handler.h linux/include/net/iw_handler.h +--- linux/include/net-w13/iw_handler.h Thu Jun 6 15:06:16 2002 ++++ linux/include/net/iw_handler.h Thu Jun 6 15:48:06 2002 +@@ -1,10 +1,10 @@ + /* + * This file define the new driver API for Wireless Extensions + * +- * Version : 2 6.12.01 ++ * Version : 3 17.1.02 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> +- * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved. ++ * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved. + */ + + #ifndef _IW_HANDLER_H +@@ -33,7 +33,7 @@ + * o The user space interface is tied to ioctl because of the use + * copy_to/from_user. + * +- * New driver API (2001 -> onward) : ++ * New driver API (2002 -> onward) : + * ------------------------------- + * The new driver API is just a bunch of standard functions (handlers), + * each handling a specific Wireless Extension. The driver just export +@@ -206,7 +206,18 @@ + * will be needed... + * I just plan to increment with each new version. + */ +-#define IW_HANDLER_VERSION 2 ++#define IW_HANDLER_VERSION 3 ++ ++/* ++ * Changes : ++ * ++ * V2 to V3 ++ * -------- ++ * - Move event definition in <linux/wireless.h> ++ * - Add Wireless Event support : ++ * o wireless_send_event() prototype ++ * o iwe_stream_add_event/point() inline functions ++ */ + + /**************************** CONSTANTS ****************************/ + +@@ -225,6 +236,7 @@ + #define IW_HEADER_TYPE_POINT 6 /* struct iw_point */ + #define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */ + #define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */ ++#define IW_HEADER_TYPE_QUAL 9 /* struct iw_quality */ + + /* Handling flags */ + /* Most are not implemented. I just use them as a reminder of some +@@ -233,7 +245,8 @@ + /* Wrapper level flags */ + #define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */ + #define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */ +-#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET request is ROOT only */ ++#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */ ++ /* SET : Omit payload from generated iwevent */ + /* Driver level flags */ + #define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */ + +@@ -303,25 +316,6 @@ struct iw_handler_def + * 'struct net_device' to here, to minimise bloat. */ + }; + +-/* ----------------------- WIRELESS EVENTS ----------------------- */ +-/* +- * Currently we don't support events, so let's just plan for the +- * future... +- */ +- +-/* +- * A Wireless Event. +- */ +-// How do we define short header ? We don't want a flag on length. +-// Probably a flag on event ? Highest bit to zero... +-struct iw_event +-{ +- __u16 length; /* Lenght of this stuff */ +- __u16 event; /* Wireless IOCTL */ +- union iwreq_data header; /* IOCTL fixed payload */ +- char extra[0]; /* Optional IOCTL data */ +-}; +- + /* ---------------------- IOCTL DESCRIPTION ---------------------- */ + /* + * One of the main goal of the new interface is to deal entirely with +@@ -369,6 +363,88 @@ extern int dev_get_wireless_info(char * + extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd); + + /* Second : functions that may be called by driver modules */ +-/* None yet */ + +-#endif /* _LINUX_WIRELESS_H */ ++/* Send a single event to user space */ ++extern void wireless_send_event(struct net_device * dev, ++ unsigned int cmd, ++ union iwreq_data * wrqu, ++ char * extra); ++ ++/* We may need a function to send a stream of events to user space. ++ * More on that later... */ ++ ++/************************* INLINE FUNTIONS *************************/ ++/* ++ * Function that are so simple that it's more efficient inlining them ++ */ ++ ++/*------------------------------------------------------------------*/ ++/* ++ * Wrapper to add an Wireless Event to a stream of events. ++ */ ++static inline char * ++iwe_stream_add_event(char * stream, /* Stream of events */ ++ char * ends, /* End of stream */ ++ struct iw_event *iwe, /* Payload */ ++ int event_len) /* Real size of payload */ ++{ ++ /* Check if it's possible */ ++ if((stream + event_len) < ends) { ++ iwe->len = event_len; ++ memcpy(stream, (char *) iwe, event_len); ++ stream += event_len; ++ } ++ return stream; ++} ++ ++/*------------------------------------------------------------------*/ ++/* ++ * Wrapper to add an short Wireless Event containing a pointer to a ++ * stream of events. ++ */ ++static inline char * ++iwe_stream_add_point(char * stream, /* Stream of events */ ++ char * ends, /* End of stream */ ++ struct iw_event *iwe, /* Payload */ ++ char * extra) ++{ ++ int event_len = IW_EV_POINT_LEN + iwe->u.data.length; ++ /* Check if it's possible */ ++ if((stream + event_len) < ends) { ++ iwe->len = event_len; ++ memcpy(stream, (char *) iwe, IW_EV_POINT_LEN); ++ memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length); ++ stream += event_len; ++ } ++ return stream; ++} ++ ++/*------------------------------------------------------------------*/ ++/* ++ * Wrapper to add a value to a Wireless Event in a stream of events. ++ * Be careful, this one is tricky to use properly : ++ * At the first run, you need to have (value = event + IW_EV_LCP_LEN). ++ */ ++static inline char * ++iwe_stream_add_value(char * event, /* Event in the stream */ ++ char * value, /* Value in event */ ++ char * ends, /* End of stream */ ++ struct iw_event *iwe, /* Payload */ ++ int event_len) /* Real size of payload */ ++{ ++ /* Don't duplicate LCP */ ++ event_len -= IW_EV_LCP_LEN; ++ ++ /* Check if it's possible */ ++ if((value + event_len) < ends) { ++ /* Add new value */ ++ memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len); ++ value += event_len; ++ /* Patch LCP */ ++ iwe->len = value - event; ++ memcpy(event, (char *) iwe, IW_EV_LCP_LEN); ++ } ++ return value; ++} ++ ++#endif /* _IW_HANDLER_H */ +diff -u -p -r --new-file linux/net/netsyms-w13.c linux/net/netsyms.c +--- linux/net/netsyms-w13.c Thu Jun 6 15:46:34 2002 ++++ linux/net/netsyms.c Thu Jun 6 15:47:44 2002 +@@ -588,4 +588,10 @@ EXPORT_SYMBOL(register_gifconf); + EXPORT_SYMBOL(net_call_rx_atomic); + EXPORT_SYMBOL(softnet_data); + ++#if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO) ++/* Don't include the whole header mess for a single function */ ++extern void wireless_send_event(struct net_device *dev, unsigned int cmd, union iwreq_data *wrqu, char *extra); ++EXPORT_SYMBOL(wireless_send_event); ++#endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ ++ + #endif /* CONFIG_NET */ +diff -u -p -r --new-file linux/net/core/wireless-w13.c linux/net/core/wireless.c +--- linux/net/core/wireless-w13.c Thu Jun 6 15:46:45 2002 ++++ linux/net/core/wireless.c Thu Jun 6 15:48:06 2002 +@@ -2,7 +2,7 @@ + * This file implement the Wireless Extensions APIs. + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> +- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. ++ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. + * + * (As all part of the Linux kernel, this file is GPL) + */ +@@ -25,6 +25,16 @@ + * o Added iw_handler handling ;-) + * o Added standard ioctl description + * o Initial dumb commit strategy based on orinoco.c ++ * ++ * v3 - 19.12.01 - Jean II ++ * o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call ++ * o Add event dispatcher function ++ * o Add event description ++ * o Propagate events as rtnetlink IFLA_WIRELESS option ++ * o Generate event on selected SET requests ++ * ++ * v4 - 18.04.01 - Jean II ++ * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1 + */ + + /***************************** INCLUDES *****************************/ +@@ -33,6 +43,7 @@ + #include <linux/config.h> /* Not needed ??? */ + #include <linux/types.h> /* off_t */ + #include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */ ++#include <linux/rtnetlink.h> /* rtnetlink stuff */ + + #include <linux/wireless.h> /* Pretty obvious */ + #include <net/iw_handler.h> /* New driver API */ +@@ -44,14 +55,23 @@ + + /* Debuging stuff */ + #undef WE_IOCTL_DEBUG /* Debug IOCTL API */ ++#undef WE_EVENT_DEBUG /* Debug Event dispatcher */ ++ ++/* Options */ ++#define WE_EVENT_NETLINK /* Propagate events using rtnetlink */ ++#define WE_SET_EVENT /* Generate an event on some set commands */ + + /************************* GLOBAL VARIABLES *************************/ + /* + * You should not use global variables, because or re-entrancy. + * On our case, it's only const, so it's OK... + */ ++/* ++ * Meta-data about all the standard Wireless Extension request we ++ * know about. ++ */ + static const struct iw_ioctl_description standard_ioctl[] = { +- /* SIOCSIWCOMMIT (internal) */ ++ /* SIOCSIWCOMMIT */ + { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, + /* SIOCGIWNAME */ + { IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, +@@ -99,18 +119,18 @@ static const struct iw_ioctl_description + { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, + /* SIOCGIWAPLIST */ + { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0}, +- /* -- hole -- */ +- { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, +- /* -- hole -- */ +- { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWSCAN */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWSCAN */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, 0}, + /* SIOCSIWESSID */ +- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_EVENT}, + /* SIOCGIWESSID */ +- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_DUMP}, + /* SIOCSIWNICKN */ +- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0}, + /* SIOCGIWNICKN */ +- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0}, + /* -- hole -- */ + { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, + /* -- hole -- */ +@@ -136,7 +156,7 @@ static const struct iw_ioctl_description + /* SIOCGIWRETRY */ + { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, + /* SIOCSIWENCODE */ +- { IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT}, + /* SIOCGIWENCODE */ + { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT}, + /* SIOCSIWPOWER */ +@@ -144,9 +164,38 @@ static const struct iw_ioctl_description + /* SIOCGIWPOWER */ + { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, + }; ++static const int standard_ioctl_num = (sizeof(standard_ioctl) / ++ sizeof(struct iw_ioctl_description)); ++ ++/* ++ * Meta-data about all the additional standard Wireless Extension events ++ * we know about. ++ */ ++static const struct iw_ioctl_description standard_event[] = { ++ /* IWEVTXDROP */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, ++ /* IWEVQUAL */ ++ { IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0}, ++}; ++static const int standard_event_num = (sizeof(standard_event) / ++ sizeof(struct iw_ioctl_description)); + + /* Size (in bytes) of the various private data types */ +-char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; ++static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; ++ ++/* Size (in bytes) of various events */ ++static const int event_type_size[] = { ++ IW_EV_LCP_LEN, ++ 0, ++ IW_EV_CHAR_LEN, ++ 0, ++ IW_EV_UINT_LEN, ++ IW_EV_FREQ_LEN, ++ IW_EV_POINT_LEN, /* Without variable payload */ ++ IW_EV_PARAM_LEN, ++ IW_EV_ADDR_LEN, ++ IW_EV_QUAL_LEN, ++}; + + /************************ COMMON SUBROUTINES ************************/ + /* +@@ -162,7 +211,8 @@ char priv_type_size[] = { 0, 1, 1, 0, 4, + static inline iw_handler get_handler(struct net_device *dev, + unsigned int cmd) + { +- unsigned int index; /* MUST be unsigned */ ++ /* Don't "optimise" the following variable, it will crash */ ++ unsigned int index; /* *MUST* be unsigned */ + + /* Check if we have some wireless handlers defined */ + if(dev->wireless_handlers == NULL) +@@ -269,9 +319,9 @@ static inline int sprintf_wireless_stats + stats->status, + stats->qual.qual, + stats->qual.updated & 1 ? '.' : ' ', +- stats->qual.level, ++ ((__u8) stats->qual.level), + stats->qual.updated & 2 ? '.' : ' ', +- stats->qual.noise, ++ ((__u8) stats->qual.noise), + stats->qual.updated & 4 ? '.' : ' ', + stats->discard.nwid, + stats->discard.code, +@@ -423,12 +473,14 @@ static inline int ioctl_standard_call(st + int ret = -EINVAL; + + /* Get the description of the IOCTL */ ++ if((cmd - SIOCIWFIRST) >= standard_ioctl_num) ++ return -EOPNOTSUPP; + descr = &(standard_ioctl[cmd - SIOCIWFIRST]); + + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n", ++ printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n", + ifr->ifr_name, cmd); +- printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); ++ printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); + #endif /* WE_IOCTL_DEBUG */ + + /* Prepare the call */ +@@ -437,8 +489,16 @@ static inline int ioctl_standard_call(st + + /* Check if we have a pointer to user space data or not */ + if(descr->header_type != IW_HEADER_TYPE_POINT) { ++ + /* No extra arguments. Trivial to handle */ + ret = handler(dev, &info, &(iwr->u), NULL); ++ ++#ifdef WE_SET_EVENT ++ /* Generate an event to notify listeners of the change */ ++ if((descr->flags & IW_DESCR_FLAG_EVENT) && ++ ((ret == 0) || (ret == -EIWCOMMIT))) ++ wireless_send_event(dev, cmd, &(iwr->u), NULL); ++#endif /* WE_SET_EVENT */ + } else { + char * extra; + int err; +@@ -466,8 +526,8 @@ static inline int ioctl_standard_call(st + } + + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Malloc %d bytes\n", +- descr->max_tokens * descr->token_size); ++ printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", ++ dev->name, descr->max_tokens * descr->token_size); + #endif /* WE_IOCTL_DEBUG */ + + /* Always allocate for max space. Easier, and won't last +@@ -488,7 +548,8 @@ static inline int ioctl_standard_call(st + return -EFAULT; + } + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Got %d bytes\n", ++ printk(KERN_DEBUG "%s (WE) : Got %d bytes\n", ++ dev->name, + iwr->u.data.length * descr->token_size); + #endif /* WE_IOCTL_DEBUG */ + } +@@ -504,11 +565,26 @@ static inline int ioctl_standard_call(st + if (err) + ret = -EFAULT; + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Wrote %d bytes\n", ++ printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n", ++ dev->name, + iwr->u.data.length * descr->token_size); + #endif /* WE_IOCTL_DEBUG */ + } + ++#ifdef WE_SET_EVENT ++ /* Generate an event to notify listeners of the change */ ++ if((descr->flags & IW_DESCR_FLAG_EVENT) && ++ ((ret == 0) || (ret == -EIWCOMMIT))) { ++ if(descr->flags & IW_DESCR_FLAG_RESTRICT) ++ /* If the event is restricted, don't ++ * export the payload */ ++ wireless_send_event(dev, cmd, &(iwr->u), NULL); ++ else ++ wireless_send_event(dev, cmd, &(iwr->u), ++ extra); ++ } ++#endif /* WE_SET_EVENT */ ++ + /* Cleanup - I told you it wasn't that long ;-) */ + kfree(extra); + } +@@ -558,11 +634,12 @@ static inline int ioctl_private_call(str + } + + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n", ++ printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n", + ifr->ifr_name, cmd); + if(descr) { +- printk(KERN_DEBUG "Name %s, set %X, get %X\n", +- descr->name, descr->set_args, descr->get_args); ++ printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n", ++ dev->name, descr->name, ++ descr->set_args, descr->get_args); + } + #endif /* WE_IOCTL_DEBUG */ + +@@ -617,7 +694,8 @@ static inline int ioctl_private_call(str + } + + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Malloc %d bytes\n", extra_size); ++ printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", ++ dev->name, extra_size); + #endif /* WE_IOCTL_DEBUG */ + + /* Always allocate for max space. Easier, and won't last +@@ -636,7 +714,8 @@ static inline int ioctl_private_call(str + return -EFAULT; + } + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length); ++ printk(KERN_DEBUG "%s (WE) : Got %d elem\n", ++ dev->name, iwr->u.data.length); + #endif /* WE_IOCTL_DEBUG */ + } + +@@ -650,8 +729,8 @@ static inline int ioctl_private_call(str + if (err) + ret = -EFAULT; + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Wrote %d elem\n", +- iwr->u.data.length); ++ printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n", ++ dev->name, iwr->u.data.length); + #endif /* WE_IOCTL_DEBUG */ + } + +@@ -730,4 +809,178 @@ int wireless_process_ioctl(struct ifreq + } + /* Not reached */ + return -EINVAL; ++} ++ ++/************************* EVENT PROCESSING *************************/ ++/* ++ * Process events generated by the wireless layer or the driver. ++ * Most often, the event will be propagated through rtnetlink ++ */ ++ ++#ifdef WE_EVENT_NETLINK ++/* "rtnl" is defined in net/core/rtnetlink.c, but we need it here. ++ * It is declared in <linux/rtnetlink.h> */ ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Fill a rtnetlink message with our event data. ++ * Note that we propage only the specified event and don't dump the ++ * current wireless config. Dumping the wireless config is far too ++ * expensive (for each parameter, the driver need to query the hardware). ++ */ ++static inline int rtnetlink_fill_iwinfo(struct sk_buff * skb, ++ struct net_device * dev, ++ int type, ++ char * event, ++ int event_len) ++{ ++ struct ifinfomsg *r; ++ struct nlmsghdr *nlh; ++ unsigned char *b = skb->tail; ++ ++ nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r)); ++ r = NLMSG_DATA(nlh); ++ r->ifi_family = AF_UNSPEC; ++ r->ifi_type = dev->type; ++ r->ifi_index = dev->ifindex; ++ r->ifi_flags = dev->flags; ++ r->ifi_change = 0; /* Wireless changes don't affect those flags */ ++ ++ /* Add the wireless events in the netlink packet */ ++ RTA_PUT(skb, IFLA_WIRELESS, ++ event_len, event); ++ ++ nlh->nlmsg_len = skb->tail - b; ++ return skb->len; ++ ++nlmsg_failure: ++rtattr_failure: ++ skb_trim(skb, b - skb->data); ++ return -1; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Create and broadcast and send it on the standard rtnetlink socket ++ * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c ++ * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field ++ * within a RTM_NEWLINK event. ++ */ ++static inline void rtmsg_iwinfo(struct net_device * dev, ++ char * event, ++ int event_len) ++{ ++ struct sk_buff *skb; ++ int size = NLMSG_GOODSIZE; ++ ++ skb = alloc_skb(size, GFP_ATOMIC); ++ if (!skb) ++ return; ++ ++ if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, ++ event, event_len) < 0) { ++ kfree_skb(skb); ++ return; ++ } ++ NETLINK_CB(skb).dst_groups = RTMGRP_LINK; ++ netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC); ++} ++#endif /* WE_EVENT_NETLINK */ ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Main event dispatcher. Called from other parts and drivers. ++ * Send the event on the apropriate channels. ++ * May be called from interrupt context. ++ */ ++void wireless_send_event(struct net_device * dev, ++ unsigned int cmd, ++ union iwreq_data * wrqu, ++ char * extra) ++{ ++ const struct iw_ioctl_description * descr = NULL; ++ int extra_len = 0; ++ struct iw_event *event; /* Mallocated whole event */ ++ int event_len; /* Its size */ ++ int hdr_len; /* Size of the event header */ ++ /* Don't "optimise" the following variable, it will crash */ ++ unsigned cmd_index; /* *MUST* be unsigned */ ++ ++ /* Get the description of the IOCTL */ ++ if(cmd <= SIOCIWLAST) { ++ cmd_index = cmd - SIOCIWFIRST; ++ if(cmd_index < standard_ioctl_num) ++ descr = &(standard_ioctl[cmd_index]); ++ } else { ++ cmd_index = cmd - IWEVFIRST; ++ if(cmd_index < standard_event_num) ++ descr = &(standard_event[cmd_index]); ++ } ++ /* Don't accept unknown events */ ++ if(descr == NULL) { ++ /* Note : we don't return an error to the driver, because ++ * the driver would not know what to do about it. It can't ++ * return an error to the user, because the event is not ++ * initiated by a user request. ++ * The best the driver could do is to log an error message. ++ * We will do it ourselves instead... ++ */ ++ printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n", ++ dev->name, cmd); ++ return; ++ } ++#ifdef WE_EVENT_DEBUG ++ printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n", ++ dev->name, cmd); ++ printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); ++#endif /* WE_EVENT_DEBUG */ ++ ++ /* Check extra parameters and set extra_len */ ++ if(descr->header_type == IW_HEADER_TYPE_POINT) { ++ /* Check if number of token fits within bounds */ ++ if(wrqu->data.length > descr->max_tokens) { ++ printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length); ++ return; ++ } ++ if(wrqu->data.length < descr->min_tokens) { ++ printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length); ++ return; ++ } ++ /* Calculate extra_len - extra is NULL for restricted events */ ++ if(extra != NULL) ++ extra_len = wrqu->data.length * descr->token_size; ++#ifdef WE_EVENT_DEBUG ++ printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len); ++#endif /* WE_EVENT_DEBUG */ ++ } ++ ++ /* Total length of the event */ ++ hdr_len = event_type_size[descr->header_type]; ++ event_len = hdr_len + extra_len; ++ ++#ifdef WE_EVENT_DEBUG ++ printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len); ++#endif /* WE_EVENT_DEBUG */ ++ ++ /* Create temporary buffer to hold the event */ ++ event = kmalloc(event_len, GFP_ATOMIC); ++ if(event == NULL) ++ return; ++ ++ /* Fill event */ ++ event->len = event_len; ++ event->cmd = cmd; ++ memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN); ++ if(extra != NULL) ++ memcpy(((char *) event) + hdr_len, extra, extra_len); ++ ++#ifdef WE_EVENT_NETLINK ++ /* rtnetlink event channel */ ++ rtmsg_iwinfo(dev, (char *) event, event_len); ++#endif /* WE_EVENT_NETLINK */ ++ ++ /* Cleanup */ ++ kfree(event); ++ ++ return; /* Always success, I guess ;-) */ + } diff --git a/linux/montavista-sa-2.4.17-mvl21/machine_name.patch b/linux/montavista-sa-2.4.17-mvl21/machine_name.patch index e69de29bb2..8b7ad2b143 100644 --- a/linux/montavista-sa-2.4.17-mvl21/machine_name.patch +++ b/linux/montavista-sa-2.4.17-mvl21/machine_name.patch @@ -0,0 +1,19 @@ +Change the Name showed by /proc/cpuinfo + + + +# +# Patch managed by http://www.holgerschurig.de/patcher.html +# + +--- linux-2.4.17_mvl21/arch/arm/mach-sa1100/assabet.c~machine_name ++++ linux-2.4.17_mvl21/arch/arm/mach-sa1100/assabet.c +@@ -374,7 +374,7 @@ + } + + +-MACHINE_START(ASSABET, "Intel-Assabet") ++MACHINE_START(ASSABET, "Tradesquare.NL Tuxpad 1") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + BOOT_PARAMS(0xc0000100) + FIXUP(fixup_assabet) diff --git a/linux/montavista-sa-2.4.17-mvl21/mkdep.patch b/linux/montavista-sa-2.4.17-mvl21/mkdep.patch index e69de29bb2..4daeaa11be 100644 --- a/linux/montavista-sa-2.4.17-mvl21/mkdep.patch +++ b/linux/montavista-sa-2.4.17-mvl21/mkdep.patch @@ -0,0 +1,16 @@ + +# +# Made by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux/Makefile~mkdep 2003-12-19 09:36:51.000000000 -0800 ++++ linux/Makefile 2003-12-19 09:57:44.000000000 -0800 +@@ -458,7 +458,7 @@ + + dep-files: scripts/mkdep archdep include/linux/version.h + scripts/mkdep -- init/*.c > .depend +- scripts/mkdep -- `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend ++ $(foreach, dir, $(FINDHPATH), scripts/mkdep -- `find $(dir) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` >> .hdepend) + $(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)" + ifdef CONFIG_MODVERSIONS + $(MAKE) update-modverfile diff --git a/linux/montavista-sa-2.4.17-mvl21/remove-montavista-init-stupidity.patch b/linux/montavista-sa-2.4.17-mvl21/remove-montavista-init-stupidity.patch index e69de29bb2..0fd0a96659 100644 --- a/linux/montavista-sa-2.4.17-mvl21/remove-montavista-init-stupidity.patch +++ b/linux/montavista-sa-2.4.17-mvl21/remove-montavista-init-stupidity.patch @@ -0,0 +1,23 @@ + +# +# Patch managed by http://www.holgerschurig.de/patcher.html +# + +--- linux-2.4.17_mvl21/init/main.c~remove-montavista-init-stupidity ++++ linux-2.4.17_mvl21/init/main.c +@@ -852,15 +852,11 @@ + * trying to recover a really broken machine. + */ + +-#ifndef CONFIG_SA1100_BEAGLE + if (execute_command) + execve(execute_command,argv_init,envp_init); + execve("/sbin/init",argv_init,envp_init); + execve("/etc/init",argv_init,envp_init); + execve("/bin/init",argv_init,envp_init); +-#else +- strcpy( argv_init[0], "--login" ); +-#endif + execve("/bin/sh",argv_init,envp_init); + panic("No init found. Try passing init= option to kernel."); + } diff --git a/linux/montavista-sa-2.4.17-mvl21/ucb1x_kill-zombie.patch b/linux/montavista-sa-2.4.17-mvl21/ucb1x_kill-zombie.patch index e69de29bb2..77fdfa6846 100644 --- a/linux/montavista-sa-2.4.17-mvl21/ucb1x_kill-zombie.patch +++ b/linux/montavista-sa-2.4.17-mvl21/ucb1x_kill-zombie.patch @@ -0,0 +1,15 @@ + +# +# Patch managed by http://www.holgerschurig.de/patcher.html +# + +--- linux-2.4.17_mvl21/drivers/misc/beagle-ts.c~ucb1x_kill_daemon ++++ linux-2.4.17_mvl21/drivers/misc/beagle-ts.c +@@ -372,6 +372,7 @@ + ts->rtask = tsk; + + daemonize(); ++ reparent_to_init(); + tsk->tty = NULL; + //tsk->policy = SCHED_FIFO; + //tsk->rt_priority = 1; diff --git a/linux/nslu2-linksys-2.4.22/gcc-registerparanoia.patch b/linux/nslu2-linksys-2.4.22/gcc-registerparanoia.patch index e69de29bb2..7c3e538e1e 100644 --- a/linux/nslu2-linksys-2.4.22/gcc-registerparanoia.patch +++ b/linux/nslu2-linksys-2.4.22/gcc-registerparanoia.patch @@ -0,0 +1,57 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux-2.4.22/include/asm-arm/system.h~gcc-registerparanoia 2004-09-08 19:45:34.000000000 -0500 ++++ linux-2.4.22/include/asm-arm/system.h 2004-09-08 19:53:01.000000000 -0500 +@@ -3,6 +3,15 @@ + + #ifdef __KERNEL__ + ++/* ++ * This is used to ensure the compiler did actually allocate the register we ++ * asked it for some inline assembly sequences. Apparently we can't trust ++ * the compiler from one version to another so a bit of paranoia won't hurt. ++ * This string is meant to be concatenated with the inline asm string and ++ * will cause compilation to stop on mismatch. ++ */ ++#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t" ++ + #include <linux/config.h> + #include <linux/kernel.h> + +--- linux-2.4.22/include/asm-arm/uaccess.h~gcc-registerparanoia 2004-09-08 19:45:34.000000000 -0500 ++++ linux-2.4.22/include/asm-arm/uaccess.h 2004-09-08 19:59:20.000000000 -0500 +@@ -6,6 +6,7 @@ + */ + #include <linux/sched.h> + #include <asm/errno.h> ++#include <asm/system.h> + + #define VERIFY_READ 0 + #define VERIFY_WRITE 1 +@@ -71,7 +72,9 @@ + extern int __get_user_bad(void); + + #define __get_user_x(__r1,__p,__e,__s,__i...) \ +- __asm__ __volatile__ ("bl __get_user_" #__s \ ++ __asm__ __volatile__ ( \ ++ __asmeq("%0", "r0") __asmeq("%1", "r1") \ ++ "bl __get_user_" #__s \ + : "=&r" (__e), "=r" (__r1) \ + : "0" (__p) \ + : __i) +@@ -110,7 +113,9 @@ + extern int __put_user_bad(void); + + #define __put_user_x(__r1,__p,__e,__s,__i...) \ +- __asm__ __volatile__ ("bl __put_user_" #__s \ ++ __asm__ __volatile__ ( \ ++ __asmeq("%0", "r0") __asmeq("%2", "r1") \ ++ "bl __put_user_" #__s \ + : "=&r" (__e) \ + : "0" (__p), "r" (__r1) \ + : __i) +--- linux-2.4.22/-~gcc-registerparanoia ++++ linux-2.4.22/- diff --git a/linux/nslu2-linksys-2.4.22/gcc3-userfuncs.patch b/linux/nslu2-linksys-2.4.22/gcc3-userfuncs.patch index e69de29bb2..54726bf740 100644 --- a/linux/nslu2-linksys-2.4.22/gcc3-userfuncs.patch +++ b/linux/nslu2-linksys-2.4.22/gcc3-userfuncs.patch @@ -0,0 +1,134 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux-2.4.22/arch/arm/lib/getuser.S~gcc3-userfuncs 2004-09-08 19:14:05.000000000 -0500 ++++ linux-2.4.22/arch/arm/lib/getuser.S 2004-09-08 19:49:27.000000000 -0500 +@@ -42,17 +42,17 @@ + + .global __get_user_2 + __get_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: ldrlsbt r1, [r0], #1 +-3: ldrlsbt r2, [r0] ++3: ldrlsbt ip, [r0] + #ifndef __ARMEB__ +- orrls r1, r1, r2, lsl #8 ++ orrls r1, r1, ip, lsl #8 + #else +- orrls r1, r2, r1, lsl #8 ++ orrls r1, ip, r1, lsl #8 + #endif + movls r0, #0 + movls pc, lr +--- linux-2.4.22/arch/arm/lib/putuser.S~gcc3-userfuncs 2004-09-08 19:14:05.000000000 -0500 ++++ linux-2.4.22/arch/arm/lib/putuser.S 2004-09-08 19:45:00.000000000 -0500 +@@ -18,7 +18,7 @@ + * Inputs: r0 contains the address + * r1, r2 contains the value + * Outputs: r0 is the error code +- * lr corrupted ++ * ip, lr corrupted + * + * No other registers must be altered. (see include/asm-arm/uaccess.h + * for specific ASM register usage). +@@ -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,20 +42,20 @@ + + .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 + #ifndef __ARMEB__ + 2: strlsbt r1, [r0], #1 + movls r1, r1, lsr #8 + 3: strlsbt r1, [r0] + #else +-2: movls r2, r1 ++2: movls ip, r1 + movls r1, r1, lsr #8 + strlsbt r1, [r0], #1 +- movls r1, r2 ++ movls r1, ip + 3: strlsbt r1, [r0] + #endif + movls r0, #0 +@@ -64,11 +64,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 +--- linux-2.4.22/include/asm-arm/uaccess.h~gcc3-userfuncs 2004-09-08 19:36:03.000000000 -0500 ++++ linux-2.4.22/include/asm-arm/uaccess.h 2004-09-08 20:03:34.000000000 -0500 +@@ -86,7 +86,7 @@ + __get_user_x(__r1, __p, __e, 1, "lr"); \ + break; \ + case 2: \ +- __get_user_x(__r1, __p, __e, 2, "r2", "lr"); \ ++ __get_user_x(__r1, __p, __e, 2, "ip", "lr"); \ + break; \ + case 4: \ + __get_user_x(__r1, __p, __e, 4, "lr"); \ +@@ -122,13 +122,13 @@ + register int __e asm("r0"); \ + switch (sizeof(*(p))) { \ + case 1: \ +- __put_user_x(__r1, __p, __e, 1, "r2", "lr"); \ ++ __put_user_x(__r1, __p, __e, 1, "ip", "lr"); \ + break; \ + case 2: \ +- __put_user_x(__r1, __p, __e, 2, "r2", "lr"); \ ++ __put_user_x(__r1, __p, __e, 2, "ip", "lr"); \ + break; \ + case 4: \ +- __put_user_x(__r1, __p, __e, 4, "r2", "lr"); \ ++ __put_user_x(__r1, __p, __e, 4, "ip", "lr"); \ + break; \ + case 8: \ + __put_user_x(__r1, __p, __e, 8, "ip", "lr"); \ diff --git a/linux/nslu2-linksys-2.4.22/gl811e.patch b/linux/nslu2-linksys-2.4.22/gl811e.patch index e69de29bb2..106c329b4c 100644 --- a/linux/nslu2-linksys-2.4.22/gl811e.patch +++ b/linux/nslu2-linksys-2.4.22/gl811e.patch @@ -0,0 +1,43 @@ +--- linux-2.4.22/drivers/usb/storage/transport.c Fri Jul 9 10:56:27 2004 ++++ linux-2.4.22/drivers/usb/storage/transport.c Fri Jul 9 11:51:14 2004 +@@ -1170,6 +1170,12 @@ + + /* if the command transfered well, then we go to the data stage */ + if (result == 0) { ++ ++ /* Genesys Logic interface chips need a 100us delay between ++ * the command phase and the data phase */ ++ if (us->pusb_dev->descriptor.idVendor == USB_VENDOR_ID_GENESYS) ++ udelay(100); ++ + /* send/receive data payload, if there is any */ + if (bcb->DataTransferLength) { + usb_stor_transfer(srb, us); +--- linux-2.4.22/drivers/usb/storage/usb.c Fri Jul 9 11:44:53 2004 ++++ linux-2.4.22/drivers/usb/storage/usb.c Fri Jul 9 11:49:44 2004 +@@ -996,6 +996,15 @@ + */ + (struct us_data *)ss->htmplt.proc_dir = ss; + ++ /* According to the technical support people at Genesys Logic, ++ * devices using their chips have problems transferring more ++ * than 32 KB at a time. In practice people have found that ++ * 64 KB works okay and that's what Windows does. But we'll ++ * be conservative. ++ */ ++ if (ss->pusb_dev->descriptor.idVendor == USB_VENDOR_ID_GENESYS) ++ ss->htmplt.max_sectors = 64; ++ + /* Just before we start our control thread, initialize + * the device if it needs initialization */ + if (unusual_dev && unusual_dev->initFunction) +--- linux-2.4.22/drivers/usb/storage/usb.h Fri Jul 9 10:56:03 2004 ++++ linux-2.4.22/drivers/usb/storage/usb.h Fri Jul 9 11:45:49 2004 +@@ -193,4 +193,7 @@ + /* Function to fill an inquiry response. See usb.c for details */ + extern void fill_inquiry_response(struct us_data *us, + unsigned char *data, unsigned int data_len); ++ ++/* Vendor ID list for devices that require special handling */ ++#define USB_VENDOR_ID_GENESYS 0x05e3 /* Genesys Logic */ + #endif diff --git a/linux/nslu2-linksys-2.4.22/linksys_can_bite_me.patch b/linux/nslu2-linksys-2.4.22/linksys_can_bite_me.patch index e69de29bb2..2afbe66f0a 100644 --- a/linux/nslu2-linksys-2.4.22/linksys_can_bite_me.patch +++ b/linux/nslu2-linksys-2.4.22/linksys_can_bite_me.patch @@ -0,0 +1,34 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux-2.4.22/drivers/usb/Config.in~linksys_can_bite_me 2004-09-08 19:14:15.000000000 -0500 ++++ linux-2.4.22/drivers/usb/Config.in 2004-09-08 19:19:37.000000000 -0500 +@@ -120,6 +120,4 @@ + fi + fi + +-source drivers/usb/gadget/Config.in +- + endmenu +--- linux-2.4.22/drivers/ixp400/Makefile~linksys_can_bite_me 2004-09-08 19:14:08.000000000 -0500 ++++ linux-2.4.22/drivers/ixp400/Makefile 2004-09-08 19:32:55.000000000 -0500 +@@ -78,7 +78,9 @@ + # DAMAGE." + # + # -- End Intel/GPL Copyright Notice -- ++# + ++ifdef CONFIG_IXP425_CSR + include $(ROOTDIR)/IXP400lib/ixp400_xscale_sw/buildUtils/environment.linux + # IX_XSCALE_SW=$(ROOTDIR)/IXP400lib/ixp400_xscale_sw/ + # The kernel makefiles override the value of CFLAGS on the make +@@ -148,6 +150,7 @@ + # directory. Note that they must be filenames in this directory - the + # ramdisk rules cannot handle paths in this list. + obj-m := $(IXP400_MODULES) ++endif + + # Include the generic kernel build system rules + include $(TOPDIR)/Rules.make diff --git a/linux/nslu2-linksys-2.4.22/linux-2.4.24-attribute-used.patch b/linux/nslu2-linksys-2.4.22/linux-2.4.24-attribute-used.patch index e69de29bb2..bcf1c10335 100644 --- a/linux/nslu2-linksys-2.4.22/linux-2.4.24-attribute-used.patch +++ b/linux/nslu2-linksys-2.4.22/linux-2.4.24-attribute-used.patch @@ -0,0 +1,140 @@ +diff -purN linux-2.4.24-uc0.orig/include/asm-arm/setup.h linux-2.4.24-uc0/include/asm-arm/setup.h +--- linux-2.4.24-uc0.orig/include/asm-arm/setup.h 2003-08-25 04:44:43.000000000 -0700 ++++ linux-2.4.24-uc0/include/asm-arm/setup.h 2004-09-09 04:36:03.000000000 -0700 +@@ -236,7 +236,7 @@ struct tagtable { + int (*parse)(const struct tag *); + }; + +-#define __tag __attribute__((unused, __section__(".taglist"))) ++#define __tag __attribute_used__ __attribute__((__section__(".taglist"))) + #define __tagtable(tag, fn) \ + static struct tagtable __tagtable_##fn __tag = { tag, fn } + +diff -purN linux-2.4.24-uc0.orig/include/linux/compiler.h linux-2.4.24-uc0/include/linux/compiler.h +--- linux-2.4.24-uc0.orig/include/linux/compiler.h 2004-03-31 21:52:49.000000000 -0800 ++++ linux-2.4.24-uc0/include/linux/compiler.h 2004-09-09 01:33:29.000000000 -0700 +@@ -13,4 +13,18 @@ + #define likely(x) __builtin_expect((x),1) + #define unlikely(x) __builtin_expect((x),0) + ++#if __GNUC__ > 3 ++#define __attribute_used__ __attribute__((__used__)) ++#elif __GNUC__ == 3 ++#if __GNUC_MINOR__ >= 3 ++# define __attribute_used__ __attribute__((__used__)) ++#else ++# define __attribute_used__ __attribute__((__unused__)) ++#endif /* __GNUC_MINOR__ >= 3 */ ++#elif __GNUC__ == 2 ++#define __attribute_used__ __attribute__((__unused__)) ++#else ++#define __attribute_used__ /* not implemented */ ++#endif /* __GNUC__ */ ++ + #endif /* __LINUX_COMPILER_H */ +diff -purN linux-2.4.24-uc0.orig/include/linux/init.h linux-2.4.24-uc0/include/linux/init.h +--- linux-2.4.24-uc0.orig/include/linux/init.h 2004-03-31 21:52:50.000000000 -0800 ++++ linux-2.4.24-uc0/include/linux/init.h 2004-09-09 01:38:11.000000000 -0700 +@@ -2,6 +2,7 @@ + #define _LINUX_INIT_H + + #include <linux/config.h> ++#include <linux/compiler.h> + + /* These macros are used to mark some functions or + * initialized data (doesn't apply to uninitialized data) +@@ -51,7 +52,7 @@ typedef void (*exitcall_t)(void); + extern initcall_t __initcall_start, __initcall_end; + + #define __initcall(fn) \ +- static initcall_t __initcall_##fn __init_call = fn ++ static initcall_t __initcall_##fn __attribute_used__ __init_call = fn + #define __exitcall(fn) \ + static exitcall_t __exitcall_##fn __exit_call = fn + +@@ -67,7 +68,7 @@ extern struct kernel_param __setup_start + + #define __setup(str, fn) \ + static char __setup_str_##fn[] __initdata = str; \ +- static struct kernel_param __setup_##fn __attribute__((unused)) __initsetup = { __setup_str_##fn, fn } ++ static struct kernel_param __setup_##fn __attribute_used__ __initsetup = { __setup_str_##fn, fn } + + #endif /* __ASSEMBLY__ */ + +@@ -77,16 +78,16 @@ extern struct kernel_param __setup_start + */ + #ifndef NO_TEXT_SECTIONS + #define __init __attribute__ ((__section__ (".text.init"))) +-#define __exit __attribute__ ((unused, __section__(".text.exit"))) ++#define __exit __attribute_used__ __attribute__ ((__section__(".text.exit"))) + #else + #define __init +-#define __exit __attribute__ ((unused)) ++#define __exit __attribute_used__ + #endif + #define __initdata __attribute__ ((__section__ (".data.init"))) +-#define __exitdata __attribute__ ((unused, __section__ (".data.exit"))) +-#define __initsetup __attribute__ ((unused,__section__ (".setup.init"))) +-#define __init_call __attribute__ ((unused,__section__ (".initcall.init"))) +-#define __exit_call __attribute__ ((unused,__section__ (".exitcall.exit"))) ++#define __exitdata __attribute_used__ __attribute__ ((__section__ (".data.exit"))) ++#define __initsetup __attribute_used__ __attribute__ ((__section__ (".setup.init"))) ++#define __init_call __attribute_used__ __attribute__ ((__section__ (".initcall.init"))) ++#define __exit_call __attribute_used__ __attribute__ ((__section__ (".exitcall.exit"))) + + /* For assembly routines */ + #define __INIT .section ".text.init","ax" +diff -purN linux-2.4.24-uc0.orig/include/linux/module.h linux-2.4.24-uc0/include/linux/module.h +--- linux-2.4.24-uc0.orig/include/linux/module.h 2002-08-02 17:39:45.000000000 -0700 ++++ linux-2.4.24-uc0/include/linux/module.h 2004-09-09 03:15:30.000000000 -0700 +@@ -8,6 +8,7 @@ + #define _LINUX_MODULE_H + + #include <linux/config.h> ++#include <linux/compiler.h> + #include <linux/spinlock.h> + #include <linux/list.h> + +@@ -254,9 +255,9 @@ __attribute__((section(".modinfo"))) = + */ + #define MODULE_GENERIC_TABLE(gtype,name) \ + static const unsigned long __module_##gtype##_size \ +- __attribute__ ((unused)) = sizeof(struct gtype##_id); \ ++ __attribute_used__ = sizeof(struct gtype##_id); \ + static const struct gtype##_id * __module_##gtype##_table \ +- __attribute__ ((unused)) = name ++ __attribute_used__ = name + + /* + * The following license idents are currently accepted as indicating free +@@ -284,7 +285,7 @@ static const struct gtype##_id * __modul + */ + + #define MODULE_LICENSE(license) \ +-static const char __module_license[] __attribute__((section(".modinfo"))) = \ ++static const char __module_license[] __attribute_used__ __attribute__((section(".modinfo"))) = \ + "license=" license + + /* Define the module variable, and usage macros. */ +@@ -296,10 +297,10 @@ extern struct module __this_module; + #define MOD_IN_USE __MOD_IN_USE(THIS_MODULE) + + #include <linux/version.h> +-static const char __module_kernel_version[] __attribute__((section(".modinfo"))) = ++static const char __module_kernel_version[] __attribute_used__ __attribute__((section(".modinfo"))) = + "kernel_version=" UTS_RELEASE; + #ifdef MODVERSIONS +-static const char __module_using_checksums[] __attribute__((section(".modinfo"))) = ++static const char __module_using_checksums[] __attribute_used__ __attribute__((section(".modinfo"))) = + "using_checksums=1"; + #endif + +@@ -319,7 +320,7 @@ static const char __module_using_checksu + */ + #define MODULE_GENERIC_TABLE(gtype,name) \ + static const struct gtype##_id * __module_##gtype##_table \ +- __attribute__ ((unused, __section__(".data.exit"))) = name ++ __attribute_used__ __attribute__ ((__section__(".data.exit"))) = name + + #ifndef __GENKSYMS__ + diff --git a/linux/nslu2-linksys-2.4.22/nofpu.patch b/linux/nslu2-linksys-2.4.22/nofpu.patch index e69de29bb2..c23eceb506 100644 --- a/linux/nslu2-linksys-2.4.22/nofpu.patch +++ b/linux/nslu2-linksys-2.4.22/nofpu.patch @@ -0,0 +1,18 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux-2.4.22/arch/arm/Makefile~nofpu 2004-09-08 19:34:11.000000000 -0500 ++++ linux-2.4.22/arch/arm/Makefile 2004-09-08 20:03:34.000000000 -0500 +@@ -76,7 +76,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 +--- linux-2.4.22/-~nofpu ++++ linux-2.4.22/- diff --git a/linux/nslu2-linksys-2.4.22/short_loadbytes.patch b/linux/nslu2-linksys-2.4.22/short_loadbytes.patch index e69de29bb2..f0b514225c 100644 --- a/linux/nslu2-linksys-2.4.22/short_loadbytes.patch +++ b/linux/nslu2-linksys-2.4.22/short_loadbytes.patch @@ -0,0 +1,18 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux-2.4.22/arch/arm/Makefile~short_loadbytes 2004-09-08 19:34:45.000000000 -0500 ++++ linux-2.4.22/arch/arm/Makefile 2004-09-08 19:34:53.000000000 -0500 +@@ -74,8 +74,8 @@ + tune-$(CONFIG_CPU_XSCALE) :=-mtune=strongarm + endif + +-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 ++CFLAGS_BOOT :=$(apcs-y) $(arch-y) $(tune-y) $(call check_gcc,-malignment-traps,-mshort-load-bytes) -msoft-float -Uarm ++CFLAGS +=$(apcs-y) $(arch-y) $(tune-y) $(call check_gcc,-malignment-traps,-mshort-load-bytes) -msoft-float -Uarm + AFLAGS +=$(apcs-y) $(arch-y) -msoft-float + + ifeq ($(CONFIG_CPU_26),y) diff --git a/linux/nslu2-openslug-2.6.7/arm-Makefile.patch b/linux/nslu2-openslug-2.6.7/arm-Makefile.patch index e69de29bb2..fa059f29cd 100644 --- a/linux/nslu2-openslug-2.6.7/arm-Makefile.patch +++ b/linux/nslu2-openslug-2.6.7/arm-Makefile.patch @@ -0,0 +1,13 @@ +--- linux-2.6.7/arch/arm/Makefile.orig 2004-06-15 22:19:13.000000000 -0700 ++++ linux-2.6.7/arch/arm/Makefile 2004-09-19 21:47:58.000000000 -0700 +@@ -55,8 +55,8 @@ + tune-$(CONFIG_CPU_V6) :=-mtune=strongarm + + # Need -Uarm for gcc < 3.x +-CFLAGS +=-mapcs-32 $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Wa,-mno-fpu -Uarm +-AFLAGS +=-mapcs-32 $(arch-y) $(tune-y) -msoft-float -Wa,-mno-fpu ++CFLAGS +=-mapcs-32 $(arch-y) $(tune-y) -msoft-float -Uarm ++AFLAGS +=-mapcs-32 $(arch-y) $(tune-y) -msoft-float + + #Default value + DATAADDR := . diff --git a/linux/nslu2-openslug-2.6.7/arm-timer.patch b/linux/nslu2-openslug-2.6.7/arm-timer.patch index e69de29bb2..b36df4fe7c 100644 --- a/linux/nslu2-openslug-2.6.7/arm-timer.patch +++ b/linux/nslu2-openslug-2.6.7/arm-timer.patch @@ -0,0 +1,17 @@ +--- linux-2.6.7/arch/arm/mach-ixp4xx/common.c.orig 2004-09-26 15:32:52.000000000 -0400 ++++ linux-2.6.7/arch/arm/mach-ixp4xx/common.c 2004-09-26 15:33:34.000000000 -0400 +@@ -223,13 +223,7 @@ static irqreturn_t ixp4xx_timer_interrup + /* Clear Pending Interrupt by writing '1' to it */ + *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND; + +- /* +- * Catch up with the real idea of time +- */ +- do { +- do_timer(regs); +- last_jiffy_time += LATCH; +- } while((*IXP4XX_OSTS - last_jiffy_time) > LATCH); ++ do_timer(regs); + + return IRQ_HANDLED; + } diff --git a/linux/nslu2-openslug-2.6.7/ipx4xx-pci.patch b/linux/nslu2-openslug-2.6.7/ipx4xx-pci.patch index e69de29bb2..31be5fb874 100644 --- a/linux/nslu2-openslug-2.6.7/ipx4xx-pci.patch +++ b/linux/nslu2-openslug-2.6.7/ipx4xx-pci.patch @@ -0,0 +1,9 @@ +--- linux-2.6.7/arch/arm/mach-ixp4xx/common-pci.c.orig 2004-09-25 04:06:48.000000000 -0400 ++++ linux-2.6.7/arch/arm/mach-ixp4xx/common-pci.c 2004-09-25 04:07:31.000000000 -0400 +@@ -540,4 +540,6 @@ + EXPORT_SYMBOL(pci_set_dma_mask); + EXPORT_SYMBOL(pci_dac_set_dma_mask); + EXPORT_SYMBOL(pci_set_consistent_dma_mask); ++EXPORT_SYMBOL(ixp4xx_pci_read); ++EXPORT_SYMBOL(ixp4xx_pci_write); + diff --git a/linux/nslu2-openslug-2.6.7/x1205-rtc.patch b/linux/nslu2-openslug-2.6.7/x1205-rtc.patch index e69de29bb2..72c2bf91b9 100644 --- a/linux/nslu2-openslug-2.6.7/x1205-rtc.patch +++ b/linux/nslu2-openslug-2.6.7/x1205-rtc.patch @@ -0,0 +1,142 @@ +--- drivers/i2c/chips/Kconfig.orig 2004-06-16 01:19:35.000000000 -0400 ++++ drivers/i2c/chips/Kconfig 2004-09-22 18:09:48.454794342 -0400 +@@ -240,6 +240,16 @@ + This driver can also be built as a module. If so, the module + will be called pcf8591. + ++config SENSORS_X1205 ++ tristate "Xicor X1205 RTC chip" ++ depends on I2C && EXPERIMENTAL ++ select I2C_SENSOR ++ help ++ If you say yes here you get support for the Xicor x1205 RTC chip. ++ ++ This driver can also be built as a module. If so, the module ++ will be called x1205-rtc ++ + config SENSORS_RTC8564 + tristate "Epson 8564 RTC chip" + depends on I2C && EXPERIMENTA +--- drivers/i2c/chips/Makefile.old 2004-06-16 01:20:26.000000000 -0400 ++++ drivers/i2c/chips/Makefile 2004-09-22 16:48:06.435580334 -0400 +@@ -25,6 +25,7 @@ + obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o + obj-$(CONFIG_SENSORS_VIA686A) += via686a.o + obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o ++obj-$(CONFIG_SENSORS_X1205) += x1205-rtc.o + + ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) + EXTRA_CFLAGS += -DDEBUG + +--- arch/arm/mach-ixp4xx/ixp425-time.c.old 1969-12-31 19:00:00.000000000 -0500 ++++ arch/arm/mach-ixp4xx/ixp425-time.c 2004-09-22 23:30:54.165988077 -0400 +@@ -0,0 +1,87 @@ ++/* ++ * arch/arm/mach-ixp425/ixp425-time.c ++ * ++ * Timer tick for IXP425 based sytems. We use OS timer1 on the CPU. ++ * ++ * Author: Peter Barry ++ * Copyright: (C) 2001 Intel Corporation. ++ * ++ * Maintainer: Deepak Saxena <dsaxena@mvista.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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/interrupt.h> ++#include <linux/time.h> ++#include <linux/init.h> ++#include <linux/smp.h> ++ ++#include <asm/uaccess.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++ ++#include <linux/timex.h> ++#include <asm/hardware.h> ++ ++ ++extern int setup_arm_irq(int, struct irqaction *); ++ ++/* IRQs are disabled before entering here from do_gettimeofday() */ ++static unsigned long ixp425_gettimeoffset(void) ++{ ++ u32 elapsed, usec, curr, reload; ++ ++ /* ++ * We need elapsed timer ticks since last interrupt ++ * ++ * Read the CCNT value. The returned value is ++ * between -LATCH and 0, 0 corresponding to a full jiffy ++ */ ++ ++ reload = *IXP425_OSRT1 & ~IXP425_OST_RELOAD_MASK; ++ curr = *IXP425_OST1; ++ ++ /* Corner case when rolling over as int disabled ?? */ ++ elapsed = reload - curr; ++ ++ /* Now convert them to usec */ ++ usec = (unsigned long)(elapsed * tick) / LATCH; ++ ++ return usec; ++} ++ ++static void ixp425_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ /* Clear Pending Interrupt by writing '1' to it */ ++ *IXP425_OSST = IXP425_OSST_TIMER_1_PEND; ++ ++ do_timer(regs); ++} ++ ++extern unsigned long (*gettimeoffset)(void); ++ ++static struct irqaction timer_irq = { ++ name: "IXP425 Timer 1", ++}; ++ ++void __init setup_timer(void) ++{ ++ gettimeoffset = ixp425_gettimeoffset; ++ timer_irq.handler = ixp425_timer_interrupt; ++ ++ /* Clear Pending Interrupt by writing '1' to it */ ++ *IXP425_OSST = IXP425_OSST_TIMER_1_PEND; ++ ++ /* Setup the Timer counter value */ ++ *IXP425_OSRT1 = (LATCH & ~IXP425_OST_RELOAD_MASK) | IXP425_OST_ENABLE; ++ ++ /* Connect the interrupt handler and enable the interrupt */ ++ setup_arm_irq(IRQ_IXP425_TIMER1, &ixp4xx_timer_irq); ++} +--- include/linux/i2c-id.h 2004-06-16 01:18:57.000000000 -0400 ++++ include/linux/i2c-id.h.new 2004-09-23 00:56:30.772429217 -0400 +@@ -101,7 +101,7 @@ + #define I2C_DRIVERID_UDA1342 53 /* UDA1342 audio codec */ + #define I2C_DRIVERID_ADV7170 54 /* video encoder */ + #define I2C_DRIVERID_RADEON 55 /* I2C bus on Radeon boards */ +- ++#define I2C_DRIVERID_X1205 0xF0 /* Xicor X1205 RTC */ + + #define I2C_DRIVERID_EXP0 0xF0 /* experimental use id's */ + #define I2C_DRIVERID_EXP1 0xF1 +--- archold/arm/kernel/time.c 2004-06-16 01:19:43.000000000 -0400 ++++ arch/arm/kernel/time.c 2004-10-14 12:28:51.434231567 -0400 +@@ -58,7 +58,7 @@ static int dummy_set_rtc(void) + * hook for setting the RTC's idea of the current time. + */ + int (*set_rtc)(void) = dummy_set_rtc; +- ++EXPORT_SYMBOL(set_rtc); + static unsigned long dummy_gettimeoffset(void) + { + return 0; diff --git a/linux/nslu2-unslung-kernel-2.3r25/able/defconfig b/linux/nslu2-unslung-kernel-2.3r25/able/defconfig index e69de29bb2..57730349d9 100644 --- a/linux/nslu2-unslung-kernel-2.3r25/able/defconfig +++ b/linux/nslu2-unslung-kernel-2.3r25/able/defconfig @@ -0,0 +1,973 @@ +# +# 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_ADVANCED_OPTIONS is not set +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# 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_IOP3XX is not set +# CONFIG_ARCH_IXP1200 is not set +# CONFIG_ARCH_IXP2000 is not set +CONFIG_ARCH_IXP425=y +# 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 is not set + +# +# 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 + +# +# IXP425 Implementation Options +# +CONFIG_ARCH_IXDP425=y +# CONFIG_ARCH_IXCDP1100 is not set +# CONFIG_ARCH_PRPMC1100 is not set +# CONFIG_ARCH_IXP425_COYOTE is not set +# CONFIG_ARCH_SE4000 is not set +CONFIG_IXP425_SDRAM_SIZE=32 +# CONFIG_IXP425_LARGE_SDRAM is not set +CONFIG_IXP425_PCI_ERRATA=y +# CONFIG_IXP425_OS_TIMER1 is not set +# CONFIG_XSCALE_PMU_TIMER is not set +# CONFIG_IXP425_CSR is not set + +# +# AT91RM9200 Implementations +# +# CONFIG_ARCH_AT91RM9200DK is not set + +# +# 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_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 is not set +# 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_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 is not set +CONFIG_CPU_32v5=y +CONFIG_CPU_XSCALE=y +CONFIG_ARM_THUMB=y +# CONFIG_XSCALE_PMU_TIMER is not set +# CONFIG_XSCALE_CACHE_ERRATA is not set +# CONFIG_XSCALE_BDI2000 is not set +# CONFIG_DISCONTIGMEM is not set +CONFIG_CPU_BIG_ENDIAN=y + +# +# General setup +# +CONFIG_PCI=y +CONFIG_PCI_AUTOCONFIG=y +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +CONFIG_KERNEL_START=0xc0000000 +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_PCI_NAMES=y +# 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=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/ram0 initrd=0x01000000,10M mem=32M@0x00000000" +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=y +# 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 +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +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 is not set +# 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 is not set +# CONFIG_MTD_DRAGONIX is not set +# CONFIG_MTD_NETtel is not set +# CONFIG_MTD_SNAPGEODE is not set +# CONFIG_MTD_NETteluC is not set +# CONFIG_MTD_MBVANILLA is not set +# CONFIG_MTD_KeyTechnology is not set +# 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_EPXA10DB is not set +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_AUTCPU12 is not set +CONFIG_MTD_IXP425=y +# CONFIG_MTD_IXP425_COYOTE is not set +# CONFIG_MTD_SE4000 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_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_DOC2001PLUS is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND 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_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=16384 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_RAMDISK_DATA is not set +# CONFIG_BLK_DEV_BLKMEM is not set +# CONFIG_BLK_STATS is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=m +CONFIG_BLK_DEV_MD=m +# CONFIG_MD_LINEAR is not set +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID5=m +# 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=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_FILTER=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_MULTIPLE_TABLES is not set +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_MULTIPATH_SEQUENTIAL is not set +# CONFIG_IP_ROUTE_TOS is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_ARP_LIMIT is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD 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 +# CONFIG_IPSEC 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_IXP425_ETH is not set +# CONFIG_SUNLANCE is not set +# CONFIG_HAPPYMEAL 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_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_APRICOT is not set +# CONFIG_B44 is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_DE4X5 is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_EEPRO100_PIO is not set +# CONFIG_E100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139CP_EXTERNAL_PHY is not set +CONFIG_8139CP_PHY_NUM=32 +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_RTL8139 is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNDANCE_MMIO is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_FET is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set +# CONFIG_FEC is not set +# CONFIG_CS89x0 is not set +# CONFIG_UCCS8900 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_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_SD_EXTRA_DEVS=40 +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_SCSI_DEBUG_QUEUES is not set +CONFIG_SCSI_MULTI_LUN=n +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_PCI 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 + +# +# Character devices +# +# CONFIG_LEDMAN is not set +# CONFIG_DS1302 is not set +# CONFIG_VT is not set +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_PHILIPSPAR is not set +# CONFIG_I2C_ELV is not set +# CONFIG_I2C_VELLEMAN is not set +# CONFIG_I2C_MCF_GPIO is not set +CONFIG_I2C_IXP425=y +# CONFIG_SCx200_I2C is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_ALGOPCF is not set +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_PROC is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_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 + +# +# Controller Area Network Cards/Chips +# +# CONFIG_CAN4LINUX is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG 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_X1226_RTC=m +# 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 +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +CONFIG_QUOTA=y +CONFIG_QFMT_V2=y +# 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=y +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# 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=y +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 is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# 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_POSIX_ACL is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_DMAPI 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 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=y +# CONFIG_SMB_NLS_DEFAULT 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 +# CONFIG_COREDUMP_PRINTK is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +CONFIG_OSF_PARTITION=y +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +CONFIG_MINIX_SUBPARTITION=y +CONFIG_SOLARIS_X86_PARTITION=y +CONFIG_UNIXWARE_DISKLABEL=y +# CONFIG_LDM_PARTITION is not set +CONFIG_SGI_PARTITION=y +# CONFIG_ULTRIX_PARTITION is not set +CONFIG_SUN_PARTITION=y +# CONFIG_EFI_PARTITION is not set +CONFIG_SMB_NLS=y +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Misc devices +# + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_UHCI=y +# CONFIG_USB_UHCI_ALT is not set +CONFIG_USB_OHCI=y +# CONFIG_USB_SL811HS_ALT is not set +# CONFIG_USB_SL811HS is not set +# 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=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_HOTPLUG_SCSIDEV_NUMBER is not set +CONFIG_USB_STORAGE_MAXTOR_ONETOUCH=y +CONFIG_USB_STORAGE_MAXTOR_ONETOUCH_DEBUG=y +# CONFIG_USB_STORAGE_MAXTOR_ONETOUCH_USB_EVENT is not set +CONFIG_USB_STORAGE_MAXTOR_ONETOUCH_PERSO=y +CONFIG_USB_STORAGE_MAXTOR_ONETOUCH_PERSO_APP_PATH="/sbin/onetouch" +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# 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 +# CONFIG_USB_HID is not set +# CONFIG_USB_HIDINPUT is not set +# 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 +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_KAWETH=m +CONFIG_USB_CATC=m +CONFIG_USB_AX8817X=m +CONFIG_USB_CDCETHER=m +CONFIG_USB_USBNET=m +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL 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 + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_NO_PGT_CACHE is not set +# CONFIG_DEBUG_KERNEL is not set +# 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 is not set +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC32=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/linux/nslu2-unslung-kernel-2.3r25/able/missing_usb_ioctls.patch b/linux/nslu2-unslung-kernel-2.3r25/able/missing_usb_ioctls.patch index e69de29bb2..ba4c606d48 100644 --- a/linux/nslu2-unslung-kernel-2.3r25/able/missing_usb_ioctls.patch +++ b/linux/nslu2-unslung-kernel-2.3r25/able/missing_usb_ioctls.patch @@ -0,0 +1,11 @@ +--- linux-2.4.22/include/linux/usbdevice_fs.h.orig 2004-10-31 20:05:45.989296261 +1100 ++++ linux-2.4.22/include/linux/usbdevice_fs.h 2004-10-31 22:55:50.470987905 +1100 +@@ -142,6 +142,8 @@ + #define USBDEVFS_HUB_PORTINFO _IOR('U', 19, struct usbdevfs_hub_portinfo) + #define USBDEVFS_RESET _IO('U', 20) + #define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int) ++#define USBDEVFS_DISCONNECT _IO('U', 22) ++#define USBDEVFS_CONNECT _IO('U', 23) + + /* --------------------------------------------------------------------- */ + diff --git a/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel-ext3flash.patch b/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel-ext3flash.patch index e69de29bb2..b61346c62b 100644 --- a/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel-ext3flash.patch +++ b/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel-ext3flash.patch @@ -0,0 +1,28 @@ +--- linux-2.4.22/drivers/scsi/scsi_scan.c.orig 2004-09-23 22:26:35.000000000 +0930 ++++ linux-2.4.22/drivers/scsi/scsi_scan.c 2004-09-23 22:38:30.000000000 +0930 +@@ -704,6 +704,7 @@ + /* restrict device on certain port grant */ + SDpnt->host->hostt->removable = SDpnt->removable; + ++#if 0 + if ( SDpnt->removable && (USB_DEVPATH_1 == SDpnt->host->hostt->port) ) + { + create_proc_read_entry("usb_err", +@@ -729,6 +730,7 @@ + NULL + ); + }else { ++#endif + printk("%x port connect!!!!!\n",SDpnt->host->hostt->port); + if(0x31 == SDpnt->host->hostt->port){ + *IXP425_GPIO_GPOUTR &= 0xfff7; +@@ -747,7 +749,9 @@ + NULL + ); + } ++#if 0 + } ++#endif + //end + /* + * Check the peripheral qualifier field - this tells us whether LUNS diff --git a/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel-vfatdisk2.patch b/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel-vfatdisk2.patch index e69de29bb2..d424daf26a 100644 --- a/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel-vfatdisk2.patch +++ b/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel-vfatdisk2.patch @@ -0,0 +1,45 @@ +--- linux-2.4.22/drivers/scsi/scsi_scan.c.orig 2004-09-23 22:26:35.000000000 +0930 ++++ linux-2.4.22/drivers/scsi/scsi_scan.c 2004-09-23 22:43:16.000000000 +0930 +@@ -657,7 +657,7 @@ + SDpnt->removable = (0x80 & scsi_result[1]) >> 7; + + +-#if 1 ++#if 0 + if (!SDpnt->removable) + { + unsigned int the_result; +@@ -704,6 +704,7 @@ + /* restrict device on certain port grant */ + SDpnt->host->hostt->removable = SDpnt->removable; + ++#if 0 + if ( SDpnt->removable && (USB_DEVPATH_1 == SDpnt->host->hostt->port) ) + { + create_proc_read_entry("usb_err", +@@ -729,6 +730,7 @@ + NULL + ); + }else { ++#endif + printk("%x port connect!!!!!\n",SDpnt->host->hostt->port); + if(0x31 == SDpnt->host->hostt->port){ + *IXP425_GPIO_GPOUTR &= 0xfff7; +@@ -740,14 +742,16 @@ + ); + }else{ + *IXP425_GPIO_GPOUTR &= 0xfffb; +- create_proc_read_entry("hd2_conn", ++ create_proc_read_entry("usb_conn", + 0, + NULL, + NULL, + NULL + ); + } ++#if 0 + } ++#endif + //end + /* + * Check the peripheral qualifier field - this tells us whether LUNS diff --git a/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel.patch b/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel.patch index e69de29bb2..17f78ef785 100644 --- a/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel.patch +++ b/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel.patch @@ -0,0 +1,11 @@ +--- linux-2.4.22/drivers/scsi/scsi_scan.c.orig 2004-09-23 22:26:35.000000000 +0930 ++++ linux-2.4.22/drivers/scsi/scsi_scan.c 2004-09-23 22:42:09.000000000 +0930 +@@ -694,7 +694,7 @@ + (buffer[2] << 8) | + buffer[3]); + printk("The capacity is %d\n",capacity); +- if(capacity<20000000){ ++ if(capacity<2000000){ + SDpnt->removable = 1; + } + kfree(buffer); diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/2.4.25-vrs2-pxa1.patch b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/2.4.25-vrs2-pxa1.patch index e69de29bb2..df59f13544 100644 --- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/2.4.25-vrs2-pxa1.patch +++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/2.4.25-vrs2-pxa1.patch @@ -0,0 +1,39937 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux-2.4.25/Documentation/Configure.help~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:08.000000000 +0200 ++++ linux-2.4.25/Documentation/Configure.help 2004-03-31 17:15:11.000000000 +0200 +@@ -4526,6 +4526,24 @@ + building a kernel for install/rescue disks or your system is very + limited in memory. + ++Kernel Execute-In-Place from ROM ++CONFIG_XIP_KERNEL ++ Execute-In-Place allows the kernel to run directly from ++ non-volatile storage, such as flash. This saves RAM space since ++ the text section of the kernel is not loaded from flash to ++ RAM. Read-write sections, such as the data section and stack, ++ are still copied to RAM. The XIP kernel is not compressed since it ++ has to run directly from flash, so it will take more space to store ++ it. The flash address where the kernel is linked to run from and ++ is stored is board dependent. Therefore, if you say Y, you must ++ know the proper physical address where to store the kernel image. ++ ++ Also note that the make target becomes "make xipImage" rather than ++ "make zImage" or "make Image". The final kernel binary to put in ++ ROM memory will be arch/arm/boot/xipImage. ++ ++ If unsure, say N. ++ + # Choice: kcore + Kernel core (/proc/kcore) format + CONFIG_KCORE_ELF +@@ -13386,6 +13404,30 @@ + + If you don't know what this all is, saying Y is a safe choice. + ++Workaround for XScale cache errata ++CONFIG_XSCALE_CACHE_ERRATA ++ There are couple errata that say that the cache may get confused ++ whether some cache lines are dirty or not, resulting in some memory ++ corruptions. The workaround (using the cache only in write through ++ mode) is performance impairing, and the bug _might_ just not be ++ that visible or critical to you depending on many esoteric ++ hardware factors. ++ ++ Not using the workaround makes Linux unreliable. If you're used ++ to some other OSes which requires to be rebooted once in a while ++ then this won't look so bad to you. On the other hand you may ++ stress test the system for hours without seeing any effect of this ++ bug. ++ ++ So this is configurable. Let's hope a future core revision will tell ++ this was just a bad dream. But in the mean time the risk and ++ trade-off is yours to decide. ++ ++ This should apply to all PXA250 up to rev B2 (erratum #120) and ++ possibly other current XScale cores as well. ++ ++ If you don't know what to answer, say Y. ++ + Support CD-ROM drives that are not SCSI or IDE/ATAPI + CONFIG_CD_NO_IDESCSI + If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y +@@ -16568,6 +16610,40 @@ + + If unsure, say N. + ++Use linear addressing for cramfs ++CONFIG_CRAMFS_LINEAR ++ This option tells the cramfs driver to load data directly from a linear ++ adressed memory range (usually non volatile memory like flash) instead ++ of going through the block device layer. This saves some memory since ++ no intermediate buffering is necessary. ++ ++ This is also a prerequisite for XIP of binaries stored on the filesystem. ++ ++ The location of the cramfs image in memory is board dependent. Therefore, ++ if you say Y, you must know the proper physical address where to store ++ the cramfs image and specify it using the physaddr=0x******** mount ++ option (for example: "mount -t cramfs -o physaddr=0x100000 none /mnt"). ++ ++ If unsure, say N. ++ ++Support XIP on linear cramfs ++CONFIG_CRAMFS_LINEAR_XIP ++ You must say Y to this option if you want to be able to run applications ++ directly from non-volatile memory. XIP applications are marked by ++ setting the sticky bit (ie, "chmod +t <app name>"). A cramfs file system ++ then needs to be created using mkcramfs (with XIP cramfs support ++ in it). Applications marked for XIP execution will not be compressed ++ since they have to run directly from flash. ++ ++Root file system on linear cramfs ++CONFIG_ROOT_CRAMFS_LINEAR ++ Say Y if you have enabled linear cramfs, and you want to be able to use ++ the linear cramfs image as a root file system. To actually have the ++ kernel mount this cramfs image as a root file system, you must also pass ++ the command line parameter "root=/dev/null rootflags=physaddr=0x********" ++ to the kernel (replace 0x******** with the physical address location ++ of the linear cramfs image to boot with). ++ + CMS file system support + CONFIG_CMS_FS + Read only support for CMS minidisk file systems found on IBM +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/Documentation/arm/XScale/PXA/USB-client 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,38 @@ ++Date: Wed, 05 Jun 2002 13:38:53 -0700 ++From: Frank Becker <fbecker@intrinsyc.com> ++To: Nicolas Pitre <nico@cam.org> ++Subject: [PATCH] PXA-USB ++ ++Hi Nicolas, ++ ++one more patch... ++ ++This patch adds minimal USB client (UDC) support. ++ ++Some notes: ++It adds just enough to get usb-eth working. I.e. ++endpoints 0-2, no dma. Performance isn't stellar ++partially due to UDC bug workarounds... ++(~350K @ 100Mhz, ~550K @ 200Mhz). ++ ++Endpoint 1&2 have changed direction compared to ++the SA, so the host side requires a change to ++usbnet.c to flip endpoints (in:2/out:1 -> in:1/out:2). ++ ++usb-eth and usb-char for PXA are almost identical ++to the SA versions, so they could probably be merged at ++one point. I made some minor changes to the eth driver ++to grab the usb resources at open, rather than at init ++and allow eth&char to be loaded at the same time. ++ ++Stuart Lynne was working on his own USB client driver ++(and he was getting higher throughput than my driver). ++Assuming you guys have something in the oven for USB ++as well, there should be good selection for best of ++breed :) ++ ++Cheers, ++Frank. ++-- ++Frank Becker - Intrinsyc Software, Inc. - http://www.intrinsyc.com/ ++Need a break? http://criticalmass.sf.net/ +--- linux-2.4.25/Makefile~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:08.000000000 +0200 ++++ linux-2.4.25/Makefile 2004-03-31 17:15:11.000000000 +0200 +@@ -1,11 +1,13 @@ + VERSION = 2 + PATCHLEVEL = 4 + SUBLEVEL = 25 +-EXTRAVERSION =-vrs2 ++EXTRAVERSION =-vrs2-pxa1 + + KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) + +-ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) ++#ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) ++ARCH := arm ++ + KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//g") + + CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ +@@ -19,7 +21,7 @@ + HOSTCC = gcc + HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer + +-CROSS_COMPILE = ++CROSS_COMPILE = arm-linux- + + # + # Include the make variables (CC, etc...) +@@ -168,6 +170,7 @@ + DRIVERS-$(CONFIG_SOUND) += drivers/sound/sounddrivers.o + DRIVERS-$(CONFIG_PCI) += drivers/pci/driver.o + DRIVERS-$(CONFIG_MTD) += drivers/mtd/mtdlink.o ++DRIVERS-$(CONFIG_MMC) += drivers/mmc/mmcdrivers.o + DRIVERS-$(CONFIG_PCMCIA) += drivers/pcmcia/pcmcia.o + DRIVERS-$(CONFIG_NET_PCMCIA) += drivers/net/pcmcia/pcmcia_net.o + DRIVERS-$(CONFIG_NET_WIRELESS) += drivers/net/wireless/wireless_net.o +--- linux-2.4.25/arch/arm/Makefile~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:08.000000000 +0200 ++++ linux-2.4.25/arch/arm/Makefile 2004-03-31 17:15:11.000000000 +0200 +@@ -13,10 +13,11 @@ + CFLAGS +=-Uarm -fno-common -pipe + + ifeq ($(CONFIG_FRAME_POINTER),y) +-CFLAGS :=$(CFLAGS:-fomit-frame-pointer=-mapcs -mno-sched-prolog) ++CFLAGS :=$(CFLAGS:-fomit-frame-pointer=) ++CFLAGS +=-fno-omit-frame-pointer -mapcs -mno-sched-prolog + endif + +-CFLAGS :=$(CFLAGS:-O2=-Os) ++#CFLAGS :=$(CFLAGS:-O2=-Os) + + ifeq ($(CONFIG_DEBUG_INFO),y) + CFLAGS +=-g +@@ -38,6 +39,8 @@ + arch-$(CONFIG_CPU_32v3) :=-D__LINUX_ARM_ARCH__=3 -march=armv3 + arch-$(CONFIG_CPU_32v4) :=-D__LINUX_ARM_ARCH__=4 -march=armv4 + arch-$(CONFIG_CPU_32v5) :=-D__LINUX_ARM_ARCH__=5 -march=armv5 ++#arch-$(CONFIG_CPU_XSCALE) :=-D__LINUX_ARM_ARCH__=5 -mcpu=xscale ++arch-$(CONFIG_CPU_XSCALE) :=-D__LINUX_ARM_ARCH__=5 -march=armv4 -Wa,-mcpu=xscale + + # This selects how we optimise for the processor. + tune-y := +@@ -49,6 +52,8 @@ + tune-$(CONFIG_CPU_ARM926T) :=-mtune=arm9tdmi + tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110 + tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100 ++tune-$(CONFIG_CPU_XSCALE) :=-mtune=xscale ++#tune-$(CONFIG_CPU_XSCALE) :=-mtune=strongarm + + 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 +@@ -127,6 +132,10 @@ + MACHINE = sa1100 + endif + ++ifeq ($(CONFIG_ARCH_PXA),y) ++MACHINE = pxa ++endif ++ + ifeq ($(CONFIG_ARCH_L7200),y) + MACHINE = l7200 + endif +@@ -164,6 +173,17 @@ + MACHINE = omaha + endif + ++ifeq ($(CONFIG_XIP_KERNEL),y) ++ DATAADDR := $(TEXTADDR) ++ # Replace phys addr with virt addr while keeping offset from base. ++ # Virt base addr also defined in include/asm-arm/arch-*/hardware.h ++ TEXTADDR = $(shell echo 0x`echo $(CONFIG_XIP_PHYS_ADDR)|sed -e's/^0x//'` |\ ++ awk --non-decimal-data '/[:xdigit:]/ \ ++ {printf("0x%x\n",and($$0,0x001fffff)+0xe8000000)}' ) ++ LDSCRIPT = arch/arm/vmlinux-armv-xip.lds.in ++ export DATAADDR ++endif ++ + export MACHINE PROCESSOR TEXTADDR GZFLAGS CFLAGS_BOOT OBJCOPYFLAGS + + # Only set INCDIR if its not already defined above +@@ -269,7 +289,7 @@ + arch/arm/kernel arch/arm/mm arch/arm/lib: dummy + $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@) + +-bzImage zImage zinstall Image bootpImage install: vmlinux ++bzImage zImage zinstall Image xipImage bootpImage install: vmlinux + @$(MAKEBOOT) $@ + + CLEAN_FILES += \ +--- linux-2.4.25/arch/arm/boot/Makefile~2.4.25-vrs2-pxa1.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/boot/Makefile 2004-03-31 17:15:11.000000000 +0200 +@@ -113,6 +113,10 @@ + endif + endif + ++ifeq ($(CONFIG_ARCH_PXA),y) ++ZRELADDR = 0xa0008000 ++endif ++ + ifeq ($(CONFIG_ARCH_ANAKIN),y) + ZRELADDR = 0x20008000 + endif +@@ -140,6 +144,14 @@ + zImage: compressed/vmlinux + $(OBJCOPY) $(OBJCOPYFLAGS) $< $@ + ++ifeq ($(CONFIG_XIP_KERNEL),y) ++xipImage: $(CONFIGURE) $(SYSTEM) ++ $(OBJCOPY) -S -O binary -R .data $(SYSTEM) vmlinux-text.bin ++ $(OBJCOPY) -S -O binary -R .init -R .text -R __ex_table -R __ksymtab $(SYSTEM) vmlinux-data.bin ++ cat vmlinux-text.bin vmlinux-data.bin > $@ ++ $(RM) -f vmlinux-text.bin vmlinux-data.bin ++endif ++ + bootpImage: bootp/bootp + $(OBJCOPY) $(OBJCOPYFLAGS) $< $@ + +@@ -160,7 +172,7 @@ + sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)" + + clean: +- $(RM) Image zImage bootpImage ++ $(RM) Image xipImage zImage bootpImage + @$(MAKE) -C compressed clean + @$(MAKE) -C bootp clean + +--- linux-2.4.25/arch/arm/boot/compressed/Makefile~2.4.25-vrs2-pxa1.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/boot/compressed/Makefile 2004-03-31 17:15:11.000000000 +0200 +@@ -71,6 +71,10 @@ + OBJS += head-sa1100.o + endif + ++ifeq ($(CONFIG_CPU_XSCALE),y) ++OBJS += head-xscale.o ++endif ++ + SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/;s/BSS_START/$(ZBSSADDR)/ + + LIBGCC := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name) +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/boot/compressed/head-xscale.S 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,50 @@ ++/* ++ * linux/arch/arm/boot/compressed/head-xscale.S ++ * ++ * XScale specific tweaks. This is merged into head.S by the linker. ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/linkage.h> ++#include <asm/mach-types.h> ++ ++ .section ".start", #alloc, #execinstr ++ ++__XScale_start: ++ ++ @ Preserve r8/r7 i.e. kernel entry values ++ ++ @ Data cache might be active. ++ @ Be sure to flush kernel binary out of the cache, ++ @ whatever state it is, before it is turned off. ++ @ This is done by fetching through currently executed ++ @ memory to be sure we hit the same cache. ++ bic r2, pc, #0x1f ++ add r3, r2, #0x10000 @ 64 kb is quite enough... ++1: ldr r0, [r2], #32 ++ teq r2, r3 ++ bne 1b ++ mcr p15, 0, r0, c7, c10, 4 @ drain WB ++ mcr p15, 0, r0, c7, c7, 0 @ flush I & D caches ++ ++ @ disabling MMU and caches ++ mrc p15, 0, r0, c1, c0, 0 @ read control reg ++ bic r0, r0, #0x05 @ clear DC, MMU ++ bic r0, r0, #0x1000 @ clear Icache ++ mcr p15, 0, r0, c1, c0, 0 ++ ++#ifdef CONFIG_ARCH_LUBBOCK ++ mov r7, #MACH_TYPE_LUBBOCK ++#endif ++ ++#ifdef CONFIG_ARCH_PXA_IDP ++ mov r7, #MACH_TYPE_PXA_IDP ++#endif ++ ++#ifdef CONFIG_ARCH_TRIZEPS2 ++ mov r7, #(MACH_TYPE_TRIZEPS2 & 0xFF00) ++ add r7, r7, #(MACH_TYPE_TRIZEPS2 & 0xFF) ++#endif ++ ++ +--- linux-2.4.25/arch/arm/boot/compressed/head.S~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:08.000000000 +0200 ++++ linux-2.4.25/arch/arm/boot/compressed/head.S 2004-03-31 17:15:11.000000000 +0200 +@@ -351,7 +351,11 @@ + orr r1, r1, #3 << 10 + add r2, r3, #16384 + 1: cmp r1, r8 @ if virt > start of RAM ++#ifdef CONFIG_XSCALE_CACHE_ERRATA ++ orrhs r1, r1, #0x08 @ set cacheable, not bufferable ++#else + orrhs r1, r1, #0x0c @ set cacheable, bufferable ++#endif + cmp r1, r9 @ if virt > end of RAM + bichs r1, r1, #0x0c @ clear cacheable, bufferable + str r1, [r0], #4 @ 1:1 mapping +@@ -364,7 +368,11 @@ + * so there is no map overlap problem for up to 1 MB compressed kernel. + * If the execution is in RAM then we would only be duplicating the above. + */ ++#ifdef CONFIG_XSCALE_CACHE_ERRATA ++ mov r1, #0x1a ++#else + mov r1, #0x1e ++#endif + orr r1, r1, #3 << 10 + mov r2, pc, lsr #20 + orr r1, r1, r2, lsl #20 +--- linux-2.4.25/arch/arm/config.in~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:08.000000000 +0200 ++++ linux-2.4.25/arch/arm/config.in 2004-03-31 17:15:11.000000000 +0200 +@@ -38,6 +38,7 @@ + Cirrus-CL-PS7500FE CONFIG_ARCH_CLPS7500 \ + CLPS711x/EP721x-based CONFIG_ARCH_CLPS711X \ + Co-EBSA285 CONFIG_ARCH_CO285 \ ++ PXA250/210-based CONFIG_ARCH_PXA \ + EBSA-110 CONFIG_ARCH_EBSA110 \ + Excalibur-ARM CONFIG_ARCH_CAMELOT \ + FootBridge CONFIG_ARCH_FOOTBRIDGE \ +@@ -148,6 +149,47 @@ + endmenu + + mainmenu_option next_comment ++comment 'Intel PXA250/210 Implementations' ++dep_bool ' Intel DBPXA250 Development Platform' CONFIG_ARCH_LUBBOCK $CONFIG_ARCH_PXA ++dep_bool ' Accelent Xscale IDP' CONFIG_ARCH_PXA_IDP $CONFIG_ARCH_PXA ++dep_bool ' Intrinsyc CerfBoard' CONFIG_ARCH_PXA_CERF $CONFIG_ARCH_PXA ++dep_bool ' Trizeps-II MT6N' CONFIG_ARCH_TRIZEPS2 $CONFIG_ARCH_PXA ++ ++if [ "$CONFIG_ARCH_PXA_CERF" = "y" ]; then ++ define_bool CONFIG_PXA_CERF y ++ ++ choice 'CerfBoard Style' \ ++ "PDA CONFIG_PXA_CERF_PDA \ ++ BOARD CONFIG_PXA_CERF_BOARD" PDA ++ ++ choice 'CerfBoard RAM Available' \ ++ "128MB CONFIG_PXA_CERF_RAM_128MB \ ++ 64MB CONFIG_PXA_CERF_RAM_64MB \ ++ 32MB CONFIG_PXA_CERF_RAM_32MB \ ++ 16MB CONFIG_PXA_CERF_RAM_16MB" 64MB ++ ++ choice 'CerfBoard Flash Available' \ ++ "64MB CONFIG_PXA_CERF_FLASH_64MB \ ++ 32MB CONFIG_PXA_CERF_FLASH_32MB \ ++ 16MB CONFIG_PXA_CERF_FLASH_16MB \ ++ 8MB CONFIG_PXA_CERF_FLASH_8MB" 32MB ++fi ++ ++if [ "$CONFIG_ARCH_LUBBOCK" = "y" ]; then ++ define_bool CONFIG_SA1111 y ++fi ++ ++if [ "$CONFIG_ARCH_TRIZEPS2" = "y" ]; then ++ define_bool CONFIG_TRIZEPS2 y ++fi ++ ++dep_tristate 'PXA USB function support' CONFIG_PXA_USB $CONFIG_ARCH_PXA ++dep_tristate ' Support for PXA USB network link function' CONFIG_PXA_USB_NETLINK $CONFIG_PXA_USB ++dep_tristate ' Support for PXA USB character device emulation' CONFIG_PXA_USB_CHAR $CONFIG_PXA_USB ++ ++endmenu ++ ++mainmenu_option next_comment + comment 'CLPS711X/EP721X Implementations' + dep_bool ' AUTCPU12' CONFIG_ARCH_AUTCPU12 $CONFIG_ARCH_CLPS711X + dep_bool ' CDB89712' CONFIG_ARCH_CDB89712 $CONFIG_ARCH_CLPS711X +@@ -385,6 +427,12 @@ + define_bool CONFIG_CPU_SA1100 n + fi + ++if [ "$CONFIG_ARCH_PXA" = "y" ]; then ++ define_bool CONFIG_CPU_32v5 y ++ define_bool CONFIG_CPU_XSCALE y ++ bool 'Workaround for XScale cache errata (see help)' CONFIG_XSCALE_CACHE_ERRATA ++fi ++ + # Figure out what processor architecture version we should be using. + # This defines the compiler instruction set which depends on the machine type. + +@@ -493,6 +541,7 @@ + hex 'Compressed ROM boot loader BSS address' CONFIG_ZBOOT_ROM_BSS 0 + + if [ "$CONFIG_ARCH_SA1100" = "y" -o \ ++ "$CONFIG_ARCH_PXA" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then + dep_bool 'Support CPU clock change (EXPERIMENTAL)' CONFIG_CPU_FREQ $CONFIG_EXPERIMENTAL + fi +@@ -501,8 +550,10 @@ + bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG + if [ "$CONFIG_HOTPLUG" = "y" ]; then + source drivers/pcmcia/Config.in ++ source drivers/mmc/Config.in + else + define_bool CONFIG_PCMCIA n ++ define_bool CONFIG_MMC n + fi + if [ "$CONFIG_SA1100_ACCELENT" = "y" ]; then + if [ "$CONFIG_PCMCIA" != "n" ]; then +@@ -513,6 +564,14 @@ + bool 'System V IPC' CONFIG_SYSVIPC + bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT + bool 'Sysctl support' CONFIG_SYSCTL ++ ++if [ "$CONFIG_ARCH_PXA" = "y" ]; then ++ dep_bool 'Kernel Execute-In-Place from ROM (EXPERIMENTAL)' CONFIG_XIP_KERNEL $CONFIG_EXPERIMENTAL ++ if [ "$CONFIG_XIP_KERNEL" = "y" ]; then ++ hex ' Kernel .text physical address' CONFIG_XIP_PHYS_ADDR 0 ++ fi ++fi ++ + comment 'At least one math emulation must be selected' + tristate 'NWFPE math emulation' CONFIG_FPE_NWFPE + if [ "$CONFIG_FPE_NWFPE" != "n" ]; then +@@ -538,6 +597,9 @@ + "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_CO285" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" -o \ ++ "$CONFIG_ARCH_LUBBOCK" = "y" -o \ ++ "$CONFIG_ARCH_PXA_IDP" = "y" -o \ ++ "$CONFIG_ARCH_PXA_CERF" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" -o \ + "$CONFIG_ARCH_CDB89712" = "y" -o \ + "$CONFIG_ARCH_P720T" = "y" -o \ +@@ -549,8 +611,12 @@ + "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_CO285" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" -o \ ++ "$CONFIG_ARCH_LUBBOCK" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" -o \ + "$CONFIG_ARCH_P720T" = "y" -o \ ++ "$CONFIG_ARCH_LUBBOCK" = "y" -o \ ++ "$CONFIG_ARCH_PXA_CERF" = "y" -o \ ++ "$CONFIG_ARCH_PXA_IDP" = "y" -o \ + "$CONFIG_ARCH_OMAHA" = "y" ]; then + bool ' Timer LED' CONFIG_LEDS_TIMER + bool ' CPU usage LED' CONFIG_LEDS_CPU +@@ -684,6 +750,7 @@ + if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \ + "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" -o \ ++ "$CONFIG_ARCH_PXA" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" -o \ + "$CONFIG_ARCH_TBOX" = "y" -o \ + "$CONFIG_ARCH_CLPS7500" = "y" -o \ +@@ -705,6 +772,7 @@ + "$CONFIG_ARCH_TBOX" = "y" -o \ + "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" -o \ ++ "$CONFIG_ARCH_PXA" = "y" -o \ + "$CONFIG_PCI" = "y" ]; then + mainmenu_option next_comment + comment 'Sound' +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/def-configs/cerfboard_pxa 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,857 @@ ++# ++# 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_PXA=y ++# 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 ++ ++# ++# 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_ADSBITSY 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_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_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_H3600_SLEEVE is not set ++ ++# ++# Intel PXA250/210 Implementations ++# ++# CONFIG_ARCH_LUBBOCK is not set ++# CONFIG_ARCH_PXA_IDP is not set ++CONFIG_ARCH_PXA_CERF=y ++CONFIG_PXA_CERF=y ++# CONFIG_PXA_CERF_PDA is not set ++CONFIG_PXA_CERF_BOARD=y ++# CONFIG_PXA_CERF_RAM_128MB is not set ++CONFIG_PXA_CERF_RAM_64MB=y ++# CONFIG_PXA_CERF_RAM_32MB is not set ++# CONFIG_PXA_CERF_RAM_16MB is not set ++# CONFIG_PXA_CERF_FLASH_64MB is not set ++CONFIG_PXA_CERF_FLASH_32MB=y ++# CONFIG_PXA_CERF_FLASH_16MB is not set ++# CONFIG_PXA_CERF_FLASH_8MB is not set ++CONFIG_PXA_USB=y ++CONFIG_PXA_USB_NETLINK=y ++CONFIG_PXA_USB_CHAR=m ++ ++# ++# 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_P720T is not set ++# CONFIG_ARCH_FORTUNET is not set ++# CONFIG_ARCH_EP7211 is not set ++# CONFIG_ARCH_EP7212 is not set ++# CONFIG_ARCH_ACORN 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 is not set ++# 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_ARM1026 is not set ++# CONFIG_CPU_SA110 is not set ++# CONFIG_CPU_SA1100 is not set ++CONFIG_CPU_32v5=y ++CONFIG_CPU_XSCALE=y ++CONFIG_XSCALE_CACHE_ERRATA=y ++# CONFIG_CPU_32v3 is not set ++# CONFIG_CPU_32v4 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_CPU_FREQ=y ++CONFIG_HOTPLUG=y ++ ++# ++# PCMCIA/CardBus support ++# ++CONFIG_PCMCIA=y ++# CONFIG_I82092 is not set ++# CONFIG_I82365 is not set ++# CONFIG_TCIC is not set ++# CONFIG_PCMCIA_CLPS6700 is not set ++# CONFIG_PCMCIA_SA1100 is not set ++CONFIG_PCMCIA_PXA=y ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++CONFIG_BSD_PROCESS_ACCT=y ++CONFIG_SYSCTL=y ++CONFIG_FPE_NWFPE=y ++# 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="root=1f03 rw console=tty0 console=ttyS0,38400 init=/linuxrc" ++CONFIG_LEDS=y ++# CONFIG_LEDS_TIMER is not set ++CONFIG_LEDS_CPU=y ++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=y ++# CONFIG_MTD_CONCAT is not set ++CONFIG_MTD_REDBOOT_PARTS=y ++# 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 is not set ++CONFIG_MTD_GEN_PROBE=y ++CONFIG_MTD_CFI_ADV_OPTIONS=y ++CONFIG_MTD_CFI_NOSWAP=y ++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set ++# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set ++CONFIG_MTD_CFI_GEOMETRY=y ++# CONFIG_MTD_CFI_B1 is not set ++# CONFIG_MTD_CFI_B2 is not set ++CONFIG_MTD_CFI_B4=y ++# CONFIG_MTD_CFI_B8 is not set ++# CONFIG_MTD_CFI_I1 is not set ++CONFIG_MTD_CFI_I2=y ++# CONFIG_MTD_CFI_I4 is not set ++# CONFIG_MTD_CFI_I8 is not set ++CONFIG_MTD_CFI_INTELEXT=y ++# CONFIG_MTD_CFI_AMDSTD is not set ++# CONFIG_MTD_RAM is not set ++# CONFIG_MTD_ROM is not set ++# 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 is not set ++# CONFIG_MTD_LUBBOCK is not set ++# 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_PXA_CERF=y ++# CONFIG_MTD_EPXA10DB is not set ++# CONFIG_MTD_AUTCPU12 is not set ++# CONFIG_MTD_EDB7312 is not set ++# CONFIG_MTD_IMPA7 is not set ++# CONFIG_MTD_PCI is not set ++ ++# ++# Self-contained MTD device drivers ++# ++# CONFIG_MTD_PMC551 is not set ++# CONFIG_MTD_SLRAM 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 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_BLK_DEV_DAC960 is not set ++# CONFIG_BLK_DEV_UMEM is not set ++CONFIG_BLK_DEV_LOOP=m ++# CONFIG_BLK_DEV_NBD is not set ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_SIZE=4096 ++CONFIG_BLK_DEV_INITRD=y ++ ++# ++# 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=y ++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=y ++# 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 ++# 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_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=y ++# CONFIG_WD80x3 is not set ++# CONFIG_ULTRAMCA is not set ++# CONFIG_ULTRA is not set ++# CONFIG_ULTRA32 is not set ++# CONFIG_SMC9194 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_MYRI_SBUS is not set ++# CONFIG_NS83820 is not set ++# CONFIG_HAMACHI is not set ++# CONFIG_YELLOWFIN 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=m ++# CONFIG_PPP_MULTILINK is not set ++# CONFIG_PPP_FILTER is not set ++CONFIG_PPP_ASYNC=m ++# CONFIG_PPP_SYNC_TTY is not set ++CONFIG_PPP_DEFLATE=m ++CONFIG_PPP_BSDCOMP=m ++# CONFIG_PPPOE 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 ++ ++# ++# PCMCIA network device support ++# ++CONFIG_NET_PCMCIA=y ++CONFIG_PCMCIA_3C589=m ++CONFIG_PCMCIA_3C574=m ++CONFIG_PCMCIA_FMVJ18X=m ++CONFIG_PCMCIA_PCNET=m ++CONFIG_PCMCIA_AXNET=m ++CONFIG_PCMCIA_NMCLAN=m ++CONFIG_PCMCIA_SMC91C92=m ++CONFIG_PCMCIA_XIRC2PS=m ++# CONFIG_ARCNET_COM20020_CS is not set ++# CONFIG_PCMCIA_IBMTR is not set ++CONFIG_NET_PCMCIA_RADIO=y ++CONFIG_PCMCIA_RAYCS=m ++CONFIG_PCMCIA_NETWAVE=m ++CONFIG_PCMCIA_WAVELAN=m ++CONFIG_AIRONET4500_CS=m ++ ++# ++# Amateur Radio support ++# ++# CONFIG_HAMRADIO is not set ++ ++# ++# IrDA (infrared) support ++# ++# CONFIG_IRDA is not set ++ ++# ++# ATA/ATAPI/MFM/RLL support ++# ++CONFIG_IDE=y ++ ++# ++# IDE, ATA and ATAPI Block devices ++# ++CONFIG_BLK_DEV_IDE=y ++# CONFIG_BLK_DEV_HD_IDE is not set ++# CONFIG_BLK_DEV_HD is not set ++CONFIG_BLK_DEV_IDEDISK=y ++# CONFIG_IDEDISK_MULTI_MODE is not set ++# CONFIG_IDEDISK_STROKE is not set ++# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set ++# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set ++# CONFIG_BLK_DEV_IDEDISK_IBM is not set ++# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set ++# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set ++# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set ++# CONFIG_BLK_DEV_IDEDISK_WD is not set ++# CONFIG_BLK_DEV_COMMERIAL is not set ++# CONFIG_BLK_DEV_TIVO is not set ++CONFIG_BLK_DEV_IDECS=m ++# CONFIG_BLK_DEV_IDECD is not set ++# CONFIG_BLK_DEV_IDETAPE is not set ++# CONFIG_BLK_DEV_IDEFLOPPY is not set ++# CONFIG_BLK_DEV_IDESCSI is not set ++# CONFIG_IDE_TASK_IOCTL is not set ++# CONFIG_BLK_DEV_CMD640 is not set ++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set ++# CONFIG_BLK_DEV_ISAPNP is not set ++# CONFIG_IDE_CHIPSETS is not set ++# CONFIG_IDEDMA_AUTO is not set ++# CONFIG_DMA_NONPCI is not set ++# CONFIG_BLK_DEV_IDE_MODES is not set ++# CONFIG_BLK_DEV_ATARAID is not set ++# CONFIG_BLK_DEV_ATARAID_PDC is not set ++# CONFIG_BLK_DEV_ATARAID_HPT 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 ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++CONFIG_VT_CONSOLE=y ++CONFIG_SERIAL=y ++CONFIG_SERIAL_CONSOLE=y ++# CONFIG_SERIAL_EXTENDED is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++ ++# ++# 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_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_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++ ++# ++# I2C support ++# ++CONFIG_I2C=y ++# CONFIG_I2C_ALGOBIT is not set ++# CONFIG_I2C_ALGOPCF is not set ++CONFIG_I2C_PXA_ALGO=y ++CONFIG_I2C_PXA_ADAP=y ++# CONFIG_I2C_CHARDEV is not set ++# CONFIG_I2C_PROC is not set ++# CONFIG_I2C_DS1307 is not set ++ ++# ++# 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 ++ ++# ++# Watchdog Cards ++# ++CONFIG_WATCHDOG=y ++# CONFIG_WATCHDOG_NOWAYOUT is not set ++# CONFIG_ACQUIRE_WDT is not set ++# CONFIG_ADVANTECH_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_PXA_WATCHDOG=m ++# CONFIG_OMAHA_WATCHDOG is not set ++# 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_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_NVRAM is not set ++# CONFIG_RTC is not set ++# CONFIG_PXA_RTC is not set ++# 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 ++# CONFIG_DRM is not set ++ ++# ++# PCMCIA character devices ++# ++CONFIG_PCMCIA_SERIAL_CS=y ++CONFIG_PCMCIA_CHRDEV=y ++ ++# ++# Multimedia devices ++# ++# CONFIG_VIDEO_DEV is not set ++ ++# ++# File systems ++# ++# CONFIG_QUOTA is not set ++CONFIG_AUTOFS_FS=y ++CONFIG_AUTOFS4_FS=y ++# 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_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=m ++CONFIG_MSDOS_FS=m ++CONFIG_UMSDOS_FS=m ++CONFIG_VFAT_FS=m ++# CONFIG_EFS_FS is not set ++# CONFIG_JFFS_FS is not set ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_FS_DEBUG=0 ++# CONFIG_CRAMFS is not set ++CONFIG_TMPFS=y ++CONFIG_RAMFS=y ++# CONFIG_ISO9660_FS is not set ++# CONFIG_JOLIET is not set ++# CONFIG_ZISOFS 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 is not set ++# CONFIG_DEVFS_MOUNT is not set ++# CONFIG_DEVFS_DEBUG is not set ++CONFIG_DEVPTS_FS=y ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX4FS_RW is not set ++CONFIG_ROMFS_FS=y ++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 ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_ROOT_NFS=y ++# CONFIG_NFSD is not set ++# CONFIG_NFSD_V3 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 ++# CONFIG_ZLIB_FS_INFLATE is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED is not set ++CONFIG_MSDOS_PARTITION=y ++# CONFIG_SMB_NLS is not set ++CONFIG_NLS=y ++ ++# ++# Native Language Support ++# ++CONFIG_NLS_DEFAULT="iso8859-1" ++CONFIG_NLS_CODEPAGE_437=m ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++CONFIG_NLS_CODEPAGE_850=m ++CONFIG_NLS_CODEPAGE_852=m ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++CONFIG_NLS_CODEPAGE_863=m ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++CONFIG_NLS_ISO8859_1=m ++CONFIG_NLS_ISO8859_2=m ++CONFIG_NLS_ISO8859_3=m ++CONFIG_NLS_ISO8859_4=m ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_UTF8 is not set ++ ++# ++# Console drivers ++# ++CONFIG_PC_KEYMAP=y ++# CONFIG_VGA_CONSOLE is not set ++ ++# ++# Frame-buffer support ++# ++# CONFIG_FB is not set ++ ++# ++# Sound ++# ++# CONFIG_SOUND 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 ++# CONFIG_MCP_UCB1400_TS is not set ++ ++# ++# USB support ++# ++# CONFIG_USB 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=y ++# CONFIG_DEBUG_SPINLOCK is not set ++# CONFIG_DEBUG_WAITQ is not set ++CONFIG_DEBUG_BUGVERBOSE=y ++CONFIG_DEBUG_ERRORS=y ++CONFIG_DEBUG_LL=y ++# CONFIG_DEBUG_DC21285_PORT is not set ++# CONFIG_DEBUG_CLPS711X_UART2 is not set +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/def-configs/cerfpda_pxa 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,962 @@ ++# ++# 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_PXA=y ++# 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_L7200 is not set ++# CONFIG_ARCH_MX1ADS is not set ++# CONFIG_ARCH_RPC is not set ++# CONFIG_ARCH_SA1100 is not set ++# CONFIG_ARCH_SHARK is not set ++ ++# ++# 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_ASSABET is not set ++# CONFIG_ASSABET_NEPONSET is not set ++# CONFIG_SA1100_ADSBITSY 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_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_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_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_H3600_SLEEVE is not set ++ ++# ++# Intel PXA250/210 Implementations ++# ++# CONFIG_ARCH_LUBBOCK is not set ++# CONFIG_ARCH_PXA_IDP is not set ++CONFIG_ARCH_PXA_CERF=y ++CONFIG_PXA_CERF=y ++CONFIG_PXA_CERF_PDA=y ++# CONFIG_PXA_CERF_BOARD is not set ++# CONFIG_PXA_CERF_RAM_128MB is not set ++CONFIG_PXA_CERF_RAM_64MB=y ++# CONFIG_PXA_CERF_RAM_32MB is not set ++# CONFIG_PXA_CERF_RAM_16MB is not set ++# CONFIG_PXA_CERF_FLASH_64MB is not set ++CONFIG_PXA_CERF_FLASH_32MB=y ++# CONFIG_PXA_CERF_FLASH_16MB is not set ++# CONFIG_PXA_CERF_FLASH_8MB is not set ++CONFIG_PXA_USB=y ++CONFIG_PXA_USB_NETLINK=y ++CONFIG_PXA_USB_CHAR=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_P720T is not set ++# CONFIG_ARCH_FORTUNET is not set ++# CONFIG_ARCH_EP7211 is not set ++# CONFIG_ARCH_EP7212 is not set ++# CONFIG_ARCH_ACORN 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_32v3 is not set ++# CONFIG_CPU_32v4 is not set ++# CONFIG_CPU_ARM610 is not set ++# CONFIG_CPU_ARM710 is not set ++# CONFIG_CPU_ARM720T is not set ++# CONFIG_CPU_ARM920T is not set ++# 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_SA110 is not set ++# CONFIG_CPU_SA1100 is not set ++CONFIG_CPU_32v5=y ++CONFIG_CPU_XSCALE=y ++# CONFIG_XSCALE_CACHE_ERRATA is not set ++# CONFIG_ARM_THUMB 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=y ++ ++# ++# PCMCIA/CardBus support ++# ++CONFIG_PCMCIA=y ++# CONFIG_I82092 is not set ++# CONFIG_I82365 is not set ++# CONFIG_TCIC is not set ++# CONFIG_PCMCIA_CLPS6700 is not set ++# CONFIG_PCMCIA_SA1100 is not set ++CONFIG_PCMCIA_PXA=y ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++CONFIG_BSD_PROCESS_ACCT=y ++CONFIG_SYSCTL=y ++CONFIG_FPE_NWFPE=y ++# 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="root=1f03 rw console=tty0 console=ttyS0,38400 init=/linuxrc" ++CONFIG_LEDS=y ++# CONFIG_LEDS_TIMER is not set ++CONFIG_LEDS_CPU=y ++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=y ++# CONFIG_MTD_CONCAT is not set ++CONFIG_MTD_REDBOOT_PARTS=y ++# 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 is not set ++CONFIG_MTD_GEN_PROBE=y ++CONFIG_MTD_CFI_ADV_OPTIONS=y ++CONFIG_MTD_CFI_NOSWAP=y ++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set ++# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set ++CONFIG_MTD_CFI_GEOMETRY=y ++# CONFIG_MTD_CFI_B1 is not set ++# CONFIG_MTD_CFI_B2 is not set ++CONFIG_MTD_CFI_B4=y ++# CONFIG_MTD_CFI_B8 is not set ++# CONFIG_MTD_CFI_I1 is not set ++CONFIG_MTD_CFI_I2=y ++# CONFIG_MTD_CFI_I4 is not set ++# CONFIG_MTD_CFI_I8 is not set ++CONFIG_MTD_CFI_INTELEXT=y ++# CONFIG_MTD_CFI_AMDSTD is not set ++# CONFIG_MTD_RAM is not set ++# CONFIG_MTD_ROM is not set ++# 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 is not set ++# CONFIG_MTD_LUBBOCK is not set ++# 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_PXA_CERF=y ++# CONFIG_MTD_EPXA10DB is not set ++# CONFIG_MTD_AUTCPU12 is not set ++# CONFIG_MTD_EDB7312 is not set ++# CONFIG_MTD_IMPA7 is not set ++# CONFIG_MTD_PCI is not set ++ ++# ++# Self-contained MTD device drivers ++# ++# CONFIG_MTD_PMC551 is not set ++# CONFIG_MTD_SLRAM 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 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_BLK_DEV_DAC960 is not set ++CONFIG_BLK_DEV_LOOP=m ++# CONFIG_BLK_DEV_NBD is not set ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_SIZE=4096 ++CONFIG_BLK_DEV_INITRD=y ++ ++# ++# 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=y ++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=y ++# 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 ++# CONFIG_ATM is not set ++# CONFIG_VLAN_8021Q is not set ++# CONFIG_IPX is not set ++# CONFIG_ATALK 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 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_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_MYRI_SBUS is not set ++# CONFIG_NS83820 is not set ++# CONFIG_HAMACHI is not set ++# CONFIG_YELLOWFIN is not set ++# CONFIG_SK98LIN is not set ++# CONFIG_FDDI is not set ++# CONFIG_HIPPI is not set ++# CONFIG_PLIP is not set ++CONFIG_PPP=m ++# CONFIG_PPP_MULTILINK is not set ++# CONFIG_PPP_FILTER is not set ++CONFIG_PPP_ASYNC=m ++# CONFIG_PPP_SYNC_TTY is not set ++CONFIG_PPP_DEFLATE=m ++CONFIG_PPP_BSDCOMP=m ++# CONFIG_PPPOE 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 ++ ++# ++# PCMCIA network device support ++# ++CONFIG_NET_PCMCIA=y ++CONFIG_PCMCIA_3C589=m ++CONFIG_PCMCIA_3C574=m ++CONFIG_PCMCIA_FMVJ18X=m ++CONFIG_PCMCIA_PCNET=m ++CONFIG_PCMCIA_AXNET=m ++CONFIG_PCMCIA_NMCLAN=m ++CONFIG_PCMCIA_SMC91C92=m ++CONFIG_PCMCIA_XIRC2PS=m ++# CONFIG_ARCNET_COM20020_CS is not set ++# CONFIG_PCMCIA_IBMTR is not set ++# CONFIG_NET_PCMCIA_RADIO is not set ++ ++# ++# Amateur Radio support ++# ++# CONFIG_HAMRADIO is not set ++ ++# ++# IrDA (infrared) support ++# ++CONFIG_IRDA=y ++CONFIG_IRLAN=y ++# CONFIG_IRNET is not set ++CONFIG_IRCOMM=y ++CONFIG_IRDA_ULTRA=y ++# CONFIG_IRDA_CACHE_LAST_LSAP is not set ++# CONFIG_IRDA_FAST_RR is not set ++CONFIG_IRDA_DEBUG=y ++ ++# ++# Infrared-port device drivers ++# ++CONFIG_IRTTY_SIR=y ++# CONFIG_IRPORT_SIR is not set ++# CONFIG_DONGLE is not set ++# CONFIG_USB_IRDA is not set ++# CONFIG_NSC_FIR is not set ++# CONFIG_WINBOND_FIR is not set ++# CONFIG_TOSHIBA_FIR is not set ++# CONFIG_SMC_IRCC_FIR is not set ++# CONFIG_ALI_FIR is not set ++# CONFIG_VLSI_FIR is not set ++ ++# ++# ATA/IDE/MFM/RLL support ++# ++CONFIG_IDE=y ++ ++# ++# IDE, ATA and ATAPI Block devices ++# ++CONFIG_BLK_DEV_IDE=y ++# CONFIG_BLK_DEV_HD_IDE is not set ++# CONFIG_BLK_DEV_HD is not set ++CONFIG_BLK_DEV_IDEDISK=y ++# CONFIG_IDEDISK_MULTI_MODE is not set ++# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set ++# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set ++# CONFIG_BLK_DEV_IDEDISK_IBM is not set ++# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set ++# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set ++# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set ++# CONFIG_BLK_DEV_IDEDISK_WD is not set ++# CONFIG_BLK_DEV_COMMERIAL is not set ++# CONFIG_BLK_DEV_TIVO is not set ++CONFIG_BLK_DEV_IDECS=m ++# CONFIG_BLK_DEV_IDECD is not set ++# CONFIG_BLK_DEV_IDETAPE is not set ++# CONFIG_BLK_DEV_IDEFLOPPY is not set ++# CONFIG_BLK_DEV_IDESCSI is not set ++# CONFIG_BLK_DEV_CMD640 is not set ++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set ++# CONFIG_BLK_DEV_ISAPNP is not set ++# CONFIG_IDE_CHIPSETS is not set ++# CONFIG_IDEDMA_AUTO is not set ++# CONFIG_DMA_NONPCI is not set ++# CONFIG_BLK_DEV_IDE_MODES is not set ++# CONFIG_BLK_DEV_ATARAID is not set ++# CONFIG_BLK_DEV_ATARAID_PDC is not set ++# CONFIG_BLK_DEV_ATARAID_HPT 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=y ++# CONFIG_INPUT_KEYBDEV is not set ++# CONFIG_INPUT_MOUSEDEV is not set ++# CONFIG_INPUT_JOYDEV is not set ++CONFIG_INPUT_EVDEV=y ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++CONFIG_VT_CONSOLE=y ++CONFIG_SERIAL=y ++CONFIG_SERIAL_CONSOLE=y ++# CONFIG_SERIAL_EXTENDED is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++ ++# ++# 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_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_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++ ++# ++# I2C support ++# ++# CONFIG_I2C is not set ++ ++# ++# 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_INPUT_NS558 is not set ++# CONFIG_INPUT_LIGHTNING is not set ++# CONFIG_INPUT_PCIGAME is not set ++# CONFIG_INPUT_CS461X is not set ++# CONFIG_INPUT_EMU10K1 is not set ++# CONFIG_INPUT_SERIO is not set ++# CONFIG_INPUT_SERPORT is not set ++# CONFIG_INPUT_ANALOG is not set ++# CONFIG_INPUT_A3D is not set ++# CONFIG_INPUT_ADI is not set ++# CONFIG_INPUT_COBRA is not set ++# CONFIG_INPUT_GF2K is not set ++# CONFIG_INPUT_GRIP is not set ++# CONFIG_INPUT_INTERACT is not set ++# CONFIG_INPUT_TMDC is not set ++# CONFIG_INPUT_SIDEWINDER is not set ++# CONFIG_INPUT_IFORCE_USB is not set ++# CONFIG_INPUT_IFORCE_232 is not set ++# CONFIG_INPUT_WARRIOR is not set ++# CONFIG_INPUT_MAGELLAN is not set ++# CONFIG_INPUT_SPACEORB is not set ++# CONFIG_INPUT_SPACEBALL is not set ++# CONFIG_INPUT_STINGER is not set ++# CONFIG_INPUT_DB9 is not set ++# CONFIG_INPUT_GAMECON is not set ++# CONFIG_INPUT_TURBOGRAFX is not set ++# CONFIG_QIC02_TAPE is not set ++ ++# ++# Watchdog Cards ++# ++# CONFIG_WATCHDOG is not set ++# CONFIG_INTEL_RNG is not set ++# CONFIG_NVRAM is not set ++# CONFIG_RTC is not set ++# 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 ++# CONFIG_DRM is not set ++ ++# ++# PCMCIA character devices ++# ++CONFIG_PCMCIA_SERIAL_CS=y ++CONFIG_PCMCIA_CHRDEV=y ++ ++# ++# Multimedia devices ++# ++# CONFIG_VIDEO_DEV is not set ++ ++# ++# File systems ++# ++# CONFIG_QUOTA is not set ++CONFIG_AUTOFS_FS=y ++CONFIG_AUTOFS4_FS=y ++# 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_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=m ++CONFIG_MSDOS_FS=m ++CONFIG_UMSDOS_FS=m ++CONFIG_VFAT_FS=m ++# CONFIG_EFS_FS is not set ++# CONFIG_JFFS_FS is not set ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_FS_DEBUG=0 ++# CONFIG_CRAMFS is not set ++CONFIG_TMPFS=y ++CONFIG_RAMFS=m ++# CONFIG_ISO9660_FS is not set ++# CONFIG_JOLIET is not set ++# CONFIG_ZISOFS 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 is not set ++# CONFIG_DEVFS_MOUNT is not set ++# CONFIG_DEVFS_DEBUG is not set ++CONFIG_DEVPTS_FS=y ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX4FS_RW is not set ++CONFIG_ROMFS_FS=y ++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 ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_ROOT_NFS=y ++# CONFIG_NFSD is not set ++# CONFIG_NFSD_V3 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 ++# CONFIG_ZLIB_FS_INFLATE is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED is not set ++CONFIG_MSDOS_PARTITION=y ++# CONFIG_SMB_NLS is not set ++CONFIG_NLS=y ++ ++# ++# Native Language Support ++# ++CONFIG_NLS_DEFAULT="iso8859-1" ++CONFIG_NLS_CODEPAGE_437=m ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++CONFIG_NLS_CODEPAGE_850=m ++CONFIG_NLS_CODEPAGE_852=m ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++CONFIG_NLS_CODEPAGE_863=m ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++CONFIG_NLS_ISO8859_1=m ++CONFIG_NLS_ISO8859_2=m ++CONFIG_NLS_ISO8859_3=m ++CONFIG_NLS_ISO8859_4=m ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_UTF8 is not set ++ ++# ++# Console drivers ++# ++CONFIG_PC_KEYMAP=y ++# CONFIG_VGA_CONSOLE is not set ++ ++# ++# Frame-buffer support ++# ++CONFIG_FB=y ++CONFIG_DUMMY_CONSOLE=y ++# CONFIG_FB_ACORN is not set ++# CONFIG_FB_ANAKIN is not set ++# CONFIG_FB_CLPS711X is not set ++# CONFIG_FB_SA1100 is not set ++CONFIG_FB_PXA=y ++# CONFIG_FB_PXA_8BPP is not set ++CONFIG_FB_PXA_16BPP=y ++# CONFIG_FB_CYBER2000 is not set ++# CONFIG_FB_VIRTUAL is not set ++# CONFIG_FBCON_ADVANCED is not set ++CONFIG_FBCON_CFB2=y ++CONFIG_FBCON_CFB4=y ++CONFIG_FBCON_CFB8=y ++CONFIG_FBCON_CFB16=y ++# CONFIG_FBCON_FONTWIDTH8_ONLY is not set ++CONFIG_FBCON_FONTS=y ++# CONFIG_FONT_8x8 is not set ++# CONFIG_FONT_8x16 is not set ++# CONFIG_FONT_SUN8x16 is not set ++# CONFIG_FONT_SUN12x22 is not set ++# CONFIG_FONT_6x11 is not set ++# CONFIG_FONT_PEARL_8x8 is not set ++CONFIG_FONT_ACORN_8x8=y ++ ++# ++# Sound ++# ++CONFIG_SOUND=y ++# CONFIG_SOUND_BT878 is not set ++# CONFIG_SOUND_CMPCI is not set ++# CONFIG_SOUND_EMU10K1 is not set ++# CONFIG_MIDI_EMU10K1 is not set ++# CONFIG_SOUND_FUSION is not set ++# CONFIG_SOUND_CS4281 is not set ++# CONFIG_SOUND_ES1370 is not set ++# CONFIG_SOUND_ES1371 is not set ++# CONFIG_SOUND_ESSSOLO1 is not set ++# CONFIG_SOUND_MAESTRO is not set ++# CONFIG_SOUND_MAESTRO3 is not set ++# CONFIG_SOUND_ICH is not set ++# CONFIG_SOUND_RME96XX is not set ++# CONFIG_SOUND_SONICVIBES is not set ++# CONFIG_SOUND_TRIDENT is not set ++# CONFIG_SOUND_MSNDCLAS is not set ++# CONFIG_SOUND_MSNDPIN is not set ++# CONFIG_SOUND_VIA82CXXX is not set ++# CONFIG_MIDI_VIA82CXXX is not set ++# CONFIG_SOUND_OSS is not set ++# CONFIG_SOUND_WAVEARTIST is not set ++CONFIG_SOUND_PXA_AC97=y ++# CONFIG_SOUND_TVMIXER 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 ++CONFIG_MCP_UCB1400_TS=y ++ ++# ++# USB support ++# ++# CONFIG_USB 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_AUDIO is not set ++# CONFIG_USB_BLUETOOTH is not set ++# CONFIG_USB_STORAGE is not set ++# CONFIG_USB_STORAGE_DEBUG is not set ++# CONFIG_USB_STORAGE_DATAFAB is not set ++# CONFIG_USB_STORAGE_FREECOM is not set ++# CONFIG_USB_STORAGE_ISD200 is not set ++# CONFIG_USB_STORAGE_DPCM is not set ++# CONFIG_USB_STORAGE_HP8200e is not set ++# CONFIG_USB_STORAGE_SDDR09 is not set ++# CONFIG_USB_STORAGE_JUMPSHOT is not set ++# CONFIG_USB_ACM is not set ++# CONFIG_USB_PRINTER is not set ++# CONFIG_USB_HID is not set ++# CONFIG_USB_HIDDEV is not set ++# CONFIG_USB_KBD is not set ++# CONFIG_USB_MOUSE is not set ++# CONFIG_USB_WACOM is not set ++# CONFIG_USB_DC2XX is not set ++# CONFIG_USB_MDC800 is not set ++# CONFIG_USB_SCANNER is not set ++# CONFIG_USB_MICROTEK is not set ++# CONFIG_USB_HPUSBSCSI is not set ++# CONFIG_USB_PEGASUS is not set ++# CONFIG_USB_KAWETH is not set ++# CONFIG_USB_CATC is not set ++# CONFIG_USB_CDCETHER is not set ++# CONFIG_USB_USBNET is not set ++# CONFIG_USB_USS720 is not set ++ ++# ++# 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 ++ ++# ++# Bluetooth support ++# ++CONFIG_BLUEZ=y ++CONFIG_BLUEZ_L2CAP=y ++ ++# ++# Bluetooth device drivers ++# ++# CONFIG_BLUEZ_HCIUSB is not set ++CONFIG_BLUEZ_HCIUART=y ++CONFIG_BLUEZ_HCIVHCI=y ++ ++# ++# Kernel hacking ++# ++CONFIG_FRAME_POINTER=y ++CONFIG_DEBUG_USER=y ++CONFIG_DEBUG_INFO=y ++# CONFIG_NO_PGT_CACHE is not set ++CONFIG_DEBUG_KERNEL=y ++# CONFIG_DEBUG_SLAB is not set ++CONFIG_MAGIC_SYSRQ=y ++# CONFIG_DEBUG_SPINLOCK is not set ++# CONFIG_DEBUG_WAITQ is not set ++CONFIG_DEBUG_BUGVERBOSE=y ++CONFIG_DEBUG_ERRORS=y ++CONFIG_DEBUG_LL=y ++# CONFIG_DEBUG_DC21285_PORT is not set ++# CONFIG_DEBUG_CLPS711X_UART2 is not set +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/def-configs/csb226 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,615 @@ ++# ++# 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_PXA=y ++# 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_AT91RM9200DK is not set ++ ++# ++# 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_ADSBITSY 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_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_H3600_SLEEVE is not set ++ ++# ++# Intel PXA250/210 Board ++# ++# CONFIG_ARCH_PXA_IDP is not set ++# CONFIG_ARCH_INNOKOM is not set ++CONFIG_ARCH_CSB226=y ++# CONFIG_ARCH_LUBBOCK is not set ++# CONFIG_ARCH_PXA_CERF is not set ++# CONFIG_PXA_USB is not set ++# CONFIG_PXA_USB_NETLINK is not set ++# CONFIG_PXA_USB_CHAR is not set ++ ++# ++# 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_P720T is not set ++# CONFIG_ARCH_FORTUNET is not set ++# CONFIG_ARCH_EP7211 is not set ++# CONFIG_ARCH_EP7212 is not set ++# CONFIG_ARCH_ACORN 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 is not set ++# 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_ARM1026 is not set ++# CONFIG_CPU_SA110 is not set ++# CONFIG_CPU_SA1100 is not set ++CONFIG_CPU_32v5=y ++CONFIG_CPU_XSCALE=y ++CONFIG_XSCALE_CACHE_ERRATA=y ++# CONFIG_CPU_32v3 is not set ++# CONFIG_CPU_32v4 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_CPU_FREQ is not set ++# CONFIG_HOTPLUG is not set ++# CONFIG_PCMCIA is not set ++# CONFIG_MMC is not set ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++# CONFIG_BSD_PROCESS_ACCT is not set ++CONFIG_SYSCTL=y ++# CONFIG_XIP_KERNEL is not set ++CONFIG_FPE_NWFPE=y ++# 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="console=ttyS0,19200" ++CONFIG_ALIGNMENT_TRAP=y ++CONFIG_ARM_HWTIMER=y ++ ++# ++# Parallel port support ++# ++# CONFIG_PARPORT is not set ++ ++# ++# Memory Technology Devices (MTD) ++# ++# CONFIG_MTD 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_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 is not set ++# CONFIG_BLK_DEV_INITRD 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 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 is not set ++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 ++# 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=y ++# 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_MYRI_SBUS is not set ++# CONFIG_NS83820 is not set ++# CONFIG_HAMACHI is not set ++# CONFIG_YELLOWFIN 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_IDE_MODES 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 ++ ++# ++# Character devices ++# ++# CONFIG_VT is not set ++CONFIG_SERIAL=y ++CONFIG_SERIAL_CONSOLE=y ++# CONFIG_SERIAL_EXTENDED is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++ ++# ++# 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_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_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++ ++# ++# I2C support ++# ++# CONFIG_I2C is not set ++ ++# ++# 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 ++ ++# ++# Watchdog Cards ++# ++# CONFIG_WATCHDOG is not set ++# CONFIG_NVRAM is not set ++# CONFIG_RTC is not set ++# CONFIG_PXA_RTC is not set ++# 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 ++# CONFIG_DRM is not set ++ ++# ++# Multimedia devices ++# ++# CONFIG_VIDEO_DEV is not set ++ ++# ++# File systems ++# ++# CONFIG_QUOTA 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_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_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 is not set ++# CONFIG_DEVFS_MOUNT is not set ++# CONFIG_DEVFS_DEBUG is not set ++CONFIG_DEVPTS_FS=y ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX4FS_RW is not set ++# CONFIG_ROMFS_FS is not set ++# CONFIG_EXT2_FS is not set ++# 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 ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++CONFIG_NFS_FS=y ++# CONFIG_NFS_V3 is not set ++CONFIG_ROOT_NFS=y ++# CONFIG_NFSD is not set ++# CONFIG_NFSD_V3 is not set ++CONFIG_SUNRPC=y ++CONFIG_LOCKD=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 ++# CONFIG_ZLIB_FS_INFLATE is not set ++ ++# ++# Partition Types ++# ++CONFIG_PARTITION_ADVANCED=y ++# CONFIG_ACORN_PARTITION is not set ++# CONFIG_OSF_PARTITION is not set ++# CONFIG_AMIGA_PARTITION is not set ++# CONFIG_ATARI_PARTITION is not set ++# CONFIG_MAC_PARTITION is not set ++# CONFIG_MSDOS_PARTITION is not set ++# CONFIG_LDM_PARTITION is not set ++# CONFIG_SGI_PARTITION is not set ++# CONFIG_ULTRIX_PARTITION is not set ++# CONFIG_SUN_PARTITION is not set ++# CONFIG_SMB_NLS is not set ++# CONFIG_NLS is not set ++ ++# ++# Sound ++# ++# CONFIG_SOUND 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 ++# CONFIG_MCP_UCB1400_TS is not set ++ ++# ++# USB support ++# ++# CONFIG_USB is not set ++ ++# ++# Bluetooth support ++# ++# CONFIG_BLUEZ is not set ++ ++# ++# Kernel hacking ++# ++CONFIG_FRAME_POINTER=y ++CONFIG_DEBUG_USER=y ++CONFIG_DEBUG_INFO=y ++# CONFIG_NO_PGT_CACHE is not set ++CONFIG_DEBUG_KERNEL=y ++CONFIG_DEBUG_SLAB=y ++CONFIG_MAGIC_SYSRQ=y ++CONFIG_DEBUG_SPINLOCK=y ++CONFIG_DEBUG_WAITQ=y ++CONFIG_DEBUG_BUGVERBOSE=y ++CONFIG_DEBUG_ERRORS=y ++CONFIG_DEBUG_LL=y ++# CONFIG_DEBUG_DC21285_PORT is not set ++# CONFIG_DEBUG_CLPS711X_UART2 is not set +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/def-configs/innokom 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,699 @@ ++# ++# 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_PXA=y ++# 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_AT91RM9200DK is not set ++ ++# ++# 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_ADSBITSY 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_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_H3600_SLEEVE is not set ++ ++# ++# Intel PXA250/210 Board ++# ++# CONFIG_ARCH_PXA_IDP is not set ++CONFIG_ARCH_INNOKOM=y ++# CONFIG_ARCH_CSB226 is not set ++# CONFIG_ARCH_LUBBOCK is not set ++# CONFIG_ARCH_PXA_CERF is not set ++# CONFIG_PXA_USB is not set ++# CONFIG_PXA_USB_NETLINK is not set ++# CONFIG_PXA_USB_CHAR is not set ++ ++# ++# 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_P720T is not set ++# CONFIG_ARCH_FORTUNET is not set ++# CONFIG_ARCH_EP7211 is not set ++# CONFIG_ARCH_EP7212 is not set ++# CONFIG_ARCH_ACORN 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 is not set ++# 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_ARM1026 is not set ++# CONFIG_CPU_SA110 is not set ++# CONFIG_CPU_SA1100 is not set ++CONFIG_CPU_32v5=y ++CONFIG_CPU_XSCALE=y ++CONFIG_XSCALE_CACHE_ERRATA=y ++# CONFIG_CPU_32v3 is not set ++# CONFIG_CPU_32v4 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_CPU_FREQ is not set ++# CONFIG_HOTPLUG is not set ++# CONFIG_PCMCIA is not set ++# CONFIG_MMC is not set ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++# CONFIG_BSD_PROCESS_ACCT is not set ++CONFIG_SYSCTL=y ++# CONFIG_XIP_KERNEL is not set ++CONFIG_FPE_NWFPE=y ++# 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="root=/dev/nfs mem=32M ip=dhcp console=ttyS0,19200" ++CONFIG_ALIGNMENT_TRAP=y ++CONFIG_ARM_HWTIMER=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=y ++# CONFIG_MTD_CONCAT is not set ++# CONFIG_MTD_REDBOOT_PARTS is not set ++CONFIG_MTD_CMDLINE_PARTS=y ++# 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 is not set ++CONFIG_MTD_GEN_PROBE=y ++# CONFIG_MTD_CFI_ADV_OPTIONS is not set ++CONFIG_MTD_CFI_INTELEXT=y ++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 ++# 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 is not set ++# 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_LUBBOCK is not set ++# CONFIG_MTD_EPXA10DB is not set ++# CONFIG_MTD_FORTUNET is not set ++CONFIG_MTD_INNOKOM=y ++CONFIG_MTD_INNOKOM_16MB=y ++# CONFIG_MTD_INNOKOM_64MB 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_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 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_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 is not set ++# CONFIG_BLK_DEV_INITRD 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 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 is not set ++# 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 ++# 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_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=y ++# CONFIG_WD80x3 is not set ++# CONFIG_ULTRAMCA is not set ++# CONFIG_ULTRA is not set ++# CONFIG_ULTRA32 is not set ++# CONFIG_SMC9194 is not set ++CONFIG_SMC91X=y ++# 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_MYRI_SBUS is not set ++# CONFIG_NS83820 is not set ++# CONFIG_HAMACHI is not set ++# CONFIG_YELLOWFIN 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_IDE_MODES 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 ++ ++# ++# Character devices ++# ++# CONFIG_VT is not set ++CONFIG_SERIAL=y ++CONFIG_SERIAL_CONSOLE=y ++# CONFIG_SERIAL_EXTENDED is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++ ++# ++# 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_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_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++ ++# ++# I2C support ++# ++CONFIG_I2C=y ++# CONFIG_I2C_ALGOBIT is not set ++# CONFIG_I2C_ALGOPCF is not set ++CONFIG_I2C_PXA_ALGO=y ++CONFIG_I2C_PXA_ADAP=y ++CONFIG_I2C_CHARDEV=y ++CONFIG_I2C_PROC=y ++# CONFIG_I2C_DS1307 is not set ++ ++# ++# 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 ++ ++# ++# Watchdog Cards ++# ++# CONFIG_WATCHDOG is not set ++# CONFIG_NVRAM is not set ++# CONFIG_RTC is not set ++# CONFIG_PXA_RTC is not set ++# 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 ++# CONFIG_DRM is not set ++ ++# ++# Multimedia devices ++# ++# CONFIG_VIDEO_DEV is not set ++ ++# ++# File systems ++# ++# CONFIG_QUOTA 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_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=y ++CONFIG_JFFS2_FS_DEBUG=0 ++# CONFIG_JFFS2_FS_NAND 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_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=y ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX4FS_RW is not set ++# CONFIG_ROMFS_FS is not set ++# CONFIG_EXT2_FS is not set ++# 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 ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_ROOT_NFS=y ++# CONFIG_NFSD is not set ++# CONFIG_NFSD_V3 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 ++# CONFIG_ZLIB_FS_INFLATE is not set ++ ++# ++# Partition Types ++# ++CONFIG_PARTITION_ADVANCED=y ++# CONFIG_ACORN_PARTITION is not set ++# CONFIG_OSF_PARTITION is not set ++# CONFIG_AMIGA_PARTITION is not set ++# CONFIG_ATARI_PARTITION is not set ++# CONFIG_MAC_PARTITION is not set ++# CONFIG_MSDOS_PARTITION is not set ++# CONFIG_LDM_PARTITION is not set ++# CONFIG_SGI_PARTITION is not set ++# CONFIG_ULTRIX_PARTITION is not set ++# CONFIG_SUN_PARTITION is not set ++# CONFIG_SMB_NLS is not set ++# CONFIG_NLS is not set ++ ++# ++# Sound ++# ++# CONFIG_SOUND 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 ++# CONFIG_MCP_UCB1400_TS is not set ++ ++# ++# USB support ++# ++# CONFIG_USB is not set ++ ++# ++# Bluetooth support ++# ++# CONFIG_BLUEZ is not set ++ ++# ++# Kernel hacking ++# ++CONFIG_FRAME_POINTER=y ++CONFIG_DEBUG_USER=y ++CONFIG_DEBUG_INFO=y ++# CONFIG_NO_PGT_CACHE is not set ++CONFIG_DEBUG_KERNEL=y ++CONFIG_DEBUG_SLAB=y ++CONFIG_MAGIC_SYSRQ=y ++CONFIG_DEBUG_SPINLOCK=y ++CONFIG_DEBUG_WAITQ=y ++CONFIG_DEBUG_BUGVERBOSE=y ++CONFIG_DEBUG_ERRORS=y ++CONFIG_DEBUG_LL=y ++# CONFIG_DEBUG_DC21285_PORT is not set ++# CONFIG_DEBUG_CLPS711X_UART2 is not set +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/def-configs/lubbock 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,971 @@ ++# ++# Automatically generated make config: 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 is not set ++ ++# ++# 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_PXA=y ++# 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 is not set ++ ++# ++# Archimedes/A5000 Implementations ++# ++ ++# ++# Archimedes/A5000 Implementations (select only ONE) ++# ++# 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 ++ ++# ++# Intel PXA250/210 Implementations ++# ++CONFIG_ARCH_LUBBOCK=y ++# CONFIG_ARCH_PXA_IDP is not set ++# CONFIG_ARCH_PXA_CERF is not set ++# CONFIG_ARCH_TRIZEPS2 is not set ++CONFIG_SA1111=y ++# CONFIG_PXA_USB is not set ++# CONFIG_PXA_USB_NETLINK is not set ++# CONFIG_PXA_USB_CHAR is not set ++ ++# ++# 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_FOOTBRIDGE is not set ++# CONFIG_FOOTBRIDGE_HOST is not set ++# CONFIG_FOOTBRIDGE_ADDIN is not set ++ ++# ++# Processor Type ++# ++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 is not set ++# 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_ARM1026 is not set ++# CONFIG_CPU_SA110 is not set ++# CONFIG_CPU_SA1100 is not set ++CONFIG_CPU_32v5=y ++CONFIG_CPU_XSCALE=y ++# CONFIG_XSCALE_CACHE_ERRATA is not set ++# CONFIG_CPU_32v3 is not set ++# CONFIG_CPU_32v4 is not set ++ ++# ++# Processor Features ++# ++# 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_CPU_FREQ=y ++CONFIG_HOTPLUG=y ++ ++# ++# PCMCIA/CardBus support ++# ++CONFIG_PCMCIA=y ++# CONFIG_I82092 is not set ++# CONFIG_I82365 is not set ++# CONFIG_TCIC is not set ++# CONFIG_PCMCIA_CLPS6700 is not set ++# CONFIG_PCMCIA_SA1100 is not set ++CONFIG_PCMCIA_PXA=y ++ ++# ++# MMC device drivers ++# ++CONFIG_MMC=m ++CONFIG_MMC_PXA=m ++CONFIG_MMC_BLOCK=m ++CONFIG_MMC_PARTITIONS=y ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++# CONFIG_BSD_PROCESS_ACCT is not set ++CONFIG_SYSCTL=y ++# CONFIG_XIP_KERNEL is not set ++ ++# ++# At least one math emulation must be selected ++# ++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=y ++# CONFIG_ARTHUR is not set ++CONFIG_CMDLINE="root=/dev/nfs ip=bootp console=ttyS0,115200 mem=32M" ++CONFIG_LEDS=y ++CONFIG_LEDS_TIMER=y ++CONFIG_LEDS_CPU=y ++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=y ++# CONFIG_MTD_CONCAT is not set ++CONFIG_MTD_REDBOOT_PARTS=y ++# CONFIG_MTD_CMDLINE_PARTS is not set ++# CONFIG_MTD_AFS_PARTS is not set ++ ++# ++# User Modules And Translation Layers ++# ++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 is not set ++CONFIG_MTD_GEN_PROBE=y ++CONFIG_MTD_CFI_ADV_OPTIONS=y ++CONFIG_MTD_CFI_NOSWAP=y ++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set ++# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set ++CONFIG_MTD_CFI_GEOMETRY=y ++# CONFIG_MTD_CFI_B1 is not set ++CONFIG_MTD_CFI_B2=y ++CONFIG_MTD_CFI_B4=y ++# CONFIG_MTD_CFI_B8 is not set ++CONFIG_MTD_CFI_I1=y ++CONFIG_MTD_CFI_I2=y ++# CONFIG_MTD_CFI_I4 is not set ++# CONFIG_MTD_CFI_I8 is not set ++CONFIG_MTD_CFI_INTELEXT=y ++# CONFIG_MTD_CFI_AMDSTD is not set ++# 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 ++# 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 is not set ++CONFIG_MTD_LUBBOCK=y ++# 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_MTDRAM is not set ++# CONFIG_MTD_BLKMTD is not set ++ ++# ++# Disk-On-Chip Device Drivers ++# ++# 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 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_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 is not set ++# 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 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 is not set ++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 ++# 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_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=y ++# CONFIG_WD80x3 is not set ++# CONFIG_ULTRAMCA is not set ++# CONFIG_ULTRA is not set ++# CONFIG_ULTRA32 is not set ++# CONFIG_SMC9194 is not set ++CONFIG_SMC91X=y ++# 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 ++ ++# ++# PCMCIA network device support ++# ++CONFIG_NET_PCMCIA=y ++# CONFIG_PCMCIA_3C589 is not set ++# CONFIG_PCMCIA_3C574 is not set ++# CONFIG_PCMCIA_FMVJ18X is not set ++CONFIG_PCMCIA_PCNET=y ++# CONFIG_PCMCIA_AXNET is not set ++# CONFIG_PCMCIA_NMCLAN is not set ++# CONFIG_PCMCIA_SMC91C92 is not set ++# CONFIG_PCMCIA_XIRC2PS is not set ++# CONFIG_ARCNET_COM20020_CS is not set ++# CONFIG_PCMCIA_IBMTR is not set ++# CONFIG_NET_PCMCIA_RADIO 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=y ++ ++# ++# IDE, ATA and ATAPI Block devices ++# ++CONFIG_BLK_DEV_IDE=y ++ ++# ++# Please see Documentation/ide.txt for help/info on IDE drives ++# ++# CONFIG_BLK_DEV_HD_IDE is not set ++# CONFIG_BLK_DEV_HD is not set ++CONFIG_BLK_DEV_IDEDISK=y ++# CONFIG_IDEDISK_MULTI_MODE is not set ++# CONFIG_IDEDISK_STROKE is not set ++CONFIG_BLK_DEV_IDECS=y ++# CONFIG_BLK_DEV_IDECD is not set ++# CONFIG_BLK_DEV_IDETAPE is not set ++# CONFIG_BLK_DEV_IDEFLOPPY is not set ++# CONFIG_BLK_DEV_IDESCSI is not set ++# CONFIG_IDE_TASK_IOCTL is not set ++ ++# ++# IDE chipset support/bugfixes ++# ++# CONFIG_BLK_DEV_CMD640 is not set ++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set ++# CONFIG_BLK_DEV_ISAPNP is not set ++# CONFIG_IDE_CHIPSETS is not set ++# CONFIG_IDEDMA_AUTO is not set ++# CONFIG_DMA_NONPCI is not set ++CONFIG_BLK_DEV_IDE_MODES=y ++# CONFIG_BLK_DEV_ATARAID is not set ++# CONFIG_BLK_DEV_ATARAID_PDC is not set ++# CONFIG_BLK_DEV_ATARAID_HPT is not set ++# CONFIG_BLK_DEV_ATARAID_SII 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=y ++# CONFIG_INPUT_KEYBDEV is not set ++# CONFIG_INPUT_MOUSEDEV is not set ++# CONFIG_INPUT_JOYDEV is not set ++CONFIG_INPUT_EVDEV=y ++# CONFIG_INPUT_MX1TS is not set ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++# CONFIG_VT_CONSOLE is not set ++CONFIG_SERIAL=y ++CONFIG_SERIAL_CONSOLE=y ++# CONFIG_SERIAL_EXTENDED is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++ ++# ++# 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 is not set ++# CONFIG_SERIAL_AT91_CONSOLE is not set ++# 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_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++ ++# ++# I2C support ++# ++# CONFIG_I2C is not set ++ ++# ++# L3 serial bus support ++# ++# CONFIG_L3 is not set ++# CONFIG_L3_ALGOBIT is not set ++# CONFIG_L3_BIT_SA1100_GPIO is not set ++ ++# ++# Other L3 adapters ++# ++# CONFIG_L3_SA1111 is not set ++# CONFIG_BIT_SA1100_GPIO is not set ++ ++# ++# Mice ++# ++CONFIG_BUSMOUSE=y ++# CONFIG_ATIXL_BUSMOUSE is not set ++# CONFIG_LOGIBUSMOUSE is not set ++# CONFIG_MS_BUSMOUSE is not set ++CONFIG_MOUSE=y ++CONFIG_PSMOUSE=y ++# CONFIG_82C710_MOUSE is not set ++# CONFIG_PC110_PAD is not set ++# CONFIG_MK712_MOUSE is not set ++ ++# ++# Joysticks ++# ++# CONFIG_INPUT_GAMEPORT is not set ++# CONFIG_INPUT_NS558 is not set ++# CONFIG_INPUT_LIGHTNING is not set ++# CONFIG_INPUT_PCIGAME is not set ++# CONFIG_INPUT_CS461X is not set ++# CONFIG_INPUT_EMU10K1 is not set ++# CONFIG_INPUT_SERIO is not set ++# CONFIG_INPUT_SERPORT is not set ++ ++# ++# Joysticks ++# ++# CONFIG_INPUT_ANALOG is not set ++# CONFIG_INPUT_A3D is not set ++# CONFIG_INPUT_ADI is not set ++# CONFIG_INPUT_COBRA is not set ++# CONFIG_INPUT_GF2K is not set ++# CONFIG_INPUT_GRIP is not set ++# CONFIG_INPUT_INTERACT is not set ++# CONFIG_INPUT_TMDC is not set ++# CONFIG_INPUT_SIDEWINDER is not set ++# CONFIG_INPUT_IFORCE_USB is not set ++# CONFIG_INPUT_IFORCE_232 is not set ++# CONFIG_INPUT_WARRIOR is not set ++# CONFIG_INPUT_MAGELLAN is not set ++# CONFIG_INPUT_SPACEORB is not set ++# CONFIG_INPUT_SPACEBALL is not set ++# CONFIG_INPUT_STINGER is not set ++# CONFIG_INPUT_DB9 is not set ++# CONFIG_INPUT_GAMECON is not set ++# CONFIG_INPUT_TURBOGRAFX 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 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_PXA_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 ++# CONFIG_DRM is not set ++ ++# ++# PCMCIA character devices ++# ++# CONFIG_PCMCIA_SERIAL_CS is not set ++# CONFIG_SYNCLINK_CS is not set ++ ++# ++# Multimedia devices ++# ++# CONFIG_VIDEO_DEV is not set ++ ++# ++# File systems ++# ++# CONFIG_QUOTA 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_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=y ++CONFIG_MSDOS_FS=y ++# 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=y ++CONFIG_JFFS2_FS_DEBUG=0 ++# CONFIG_CRAMFS is not set ++# CONFIG_CRAMFS_LINEAR is not set ++# CONFIG_CRAMFS_LINEAR_XIP is not set ++# CONFIG_ROOT_CRAMFS_LINEAR 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=y ++# 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 ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++CONFIG_NFS_FS=y ++# CONFIG_NFS_V3 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_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=y ++ ++# ++# Native Language Support ++# ++CONFIG_NLS_DEFAULT="iso8859-1" ++# CONFIG_NLS_CODEPAGE_437 is not set ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++# CONFIG_NLS_CODEPAGE_850 is not set ++# CONFIG_NLS_CODEPAGE_852 is not set ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++# CONFIG_NLS_CODEPAGE_863 is not set ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++CONFIG_NLS_ISO8859_1=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_UTF8 is not set ++ ++# ++# Console drivers ++# ++CONFIG_PC_KEYMAP=y ++# CONFIG_VGA_CONSOLE is not set ++ ++# ++# Frame-buffer support ++# ++CONFIG_FB=y ++CONFIG_DUMMY_CONSOLE=y ++# CONFIG_FB_ACORN is not set ++# CONFIG_FB_ANAKIN is not set ++# CONFIG_FB_CLPS711X is not set ++# CONFIG_FB_SA1100 is not set ++# CONFIG_FB_DBMX1 is not set ++CONFIG_FB_PXA=y ++# CONFIG_FB_PXA_8BPP is not set ++CONFIG_FB_PXA_16BPP=y ++# CONFIG_FB_PXA_QVGA is not set ++# CONFIG_FB_CYBER2000 is not set ++# CONFIG_FB_VIRTUAL is not set ++# CONFIG_FBCON_ADVANCED is not set ++CONFIG_FBCON_CFB2=y ++CONFIG_FBCON_CFB4=y ++CONFIG_FBCON_CFB8=y ++CONFIG_FBCON_CFB16=y ++CONFIG_FBCON_FONTWIDTH8_ONLY=y ++# CONFIG_FBCON_FONTS is not set ++CONFIG_FONT_8x8=y ++CONFIG_FONT_8x16=y ++ ++# ++# Sound ++# ++CONFIG_SOUND=y ++# CONFIG_SOUND_ALI5455 is not set ++# CONFIG_SOUND_BT878 is not set ++# CONFIG_SOUND_CMPCI is not set ++# CONFIG_SOUND_EMU10K1 is not set ++# CONFIG_MIDI_EMU10K1 is not set ++# CONFIG_SOUND_FUSION is not set ++# CONFIG_SOUND_CS4281 is not set ++# CONFIG_SOUND_ES1370 is not set ++# CONFIG_SOUND_ES1371 is not set ++# CONFIG_SOUND_ESSSOLO1 is not set ++# CONFIG_SOUND_MAESTRO is not set ++# CONFIG_SOUND_MAESTRO3 is not set ++# CONFIG_SOUND_FORTE is not set ++# CONFIG_SOUND_ICH is not set ++# CONFIG_SOUND_RME96XX is not set ++# CONFIG_SOUND_SONICVIBES is not set ++# CONFIG_SOUND_TRIDENT is not set ++# CONFIG_SOUND_MSNDCLAS is not set ++# CONFIG_SOUND_MSNDPIN is not set ++# CONFIG_SOUND_VIA82CXXX is not set ++# CONFIG_MIDI_VIA82CXXX is not set ++# CONFIG_SOUND_OSS is not set ++# CONFIG_SOUND_VIDC is not set ++# CONFIG_SOUND_WAVEARTIST is not set ++CONFIG_SOUND_PXA_AC97=y ++# CONFIG_SOUND_TVMIXER 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 ++CONFIG_MCP_UCB1400_TS=y ++ ++# ++# USB support ++# ++# CONFIG_USB is not set ++ ++# ++# Bluetooth support ++# ++# CONFIG_BLUEZ is not set ++ ++# ++# Kernel hacking ++# ++CONFIG_FRAME_POINTER=y ++CONFIG_DEBUG_USER=y ++CONFIG_DEBUG_INFO=y ++# CONFIG_NO_PGT_CACHE is not set ++CONFIG_DEBUG_KERNEL=y ++# CONFIG_DEBUG_SLAB is not set ++CONFIG_MAGIC_SYSRQ=y ++# CONFIG_DEBUG_SPINLOCK is not set ++# CONFIG_DEBUG_WAITQ is not set ++CONFIG_DEBUG_BUGVERBOSE=y ++CONFIG_DEBUG_ERRORS=y ++CONFIG_DEBUG_LL=y ++# CONFIG_DEBUG_DC21285_PORT is not set ++# CONFIG_DEBUG_CLPS711X_UART2 is not set ++ ++# ++# Library routines ++# ++CONFIG_ZLIB_INFLATE=y ++CONFIG_ZLIB_DEFLATE=y +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/def-configs/pxa_idp 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,933 @@ ++# ++# 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_PXA=y ++# 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 ++ ++# ++# 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_ADSBITSY 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_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_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_H3600_SLEEVE is not set ++ ++# ++# Intel PXA250/210 Implementations ++# ++# CONFIG_ARCH_LUBBOCK is not set ++CONFIG_ARCH_PXA_IDP=y ++# CONFIG_ARCH_PXA_CERF is not set ++CONFIG_PXA_USB=m ++CONFIG_PXA_USB_NETLINK=m ++CONFIG_PXA_USB_CHAR=m ++ ++# ++# 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_P720T is not set ++# CONFIG_ARCH_FORTUNET is not set ++# CONFIG_ARCH_EP7211 is not set ++# CONFIG_ARCH_EP7212 is not set ++# CONFIG_ARCH_ACORN 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 is not set ++# 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_ARM1026 is not set ++# CONFIG_CPU_SA110 is not set ++# CONFIG_CPU_SA1100 is not set ++CONFIG_CPU_32v5=y ++CONFIG_CPU_XSCALE=y ++# CONFIG_XSCALE_CACHE_ERRATA is not set ++# CONFIG_CPU_32v3 is not set ++# CONFIG_CPU_32v4 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=y ++ ++# ++# PCMCIA/CardBus support ++# ++CONFIG_PCMCIA=y ++# CONFIG_I82092 is not set ++# CONFIG_I82365 is not set ++# CONFIG_TCIC is not set ++# CONFIG_PCMCIA_CLPS6700 is not set ++# CONFIG_PCMCIA_SA1100 is not set ++CONFIG_PCMCIA_PXA=y ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++# CONFIG_BSD_PROCESS_ACCT is not set ++CONFIG_SYSCTL=y ++CONFIG_FPE_NWFPE=y ++# 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=y ++# CONFIG_ARTHUR is not set ++CONFIG_CMDLINE="root=/dev/mtdblock2 init=/linuxrc console=ttyS0,115200" ++CONFIG_LEDS=y ++CONFIG_LEDS_TIMER=y ++CONFIG_LEDS_CPU=y ++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=y ++# 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 is not set ++CONFIG_MTD_GEN_PROBE=y ++CONFIG_MTD_CFI_ADV_OPTIONS=y ++CONFIG_MTD_CFI_NOSWAP=y ++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set ++# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set ++CONFIG_MTD_CFI_GEOMETRY=y ++# CONFIG_MTD_CFI_B1 is not set ++# CONFIG_MTD_CFI_B2 is not set ++CONFIG_MTD_CFI_B4=y ++# CONFIG_MTD_CFI_B8 is not set ++# CONFIG_MTD_CFI_I1 is not set ++CONFIG_MTD_CFI_I2=y ++# CONFIG_MTD_CFI_I4 is not set ++# CONFIG_MTD_CFI_I8 is not set ++CONFIG_MTD_CFI_INTELEXT=y ++# CONFIG_MTD_CFI_AMDSTD is not set ++# CONFIG_MTD_RAM is not set ++# CONFIG_MTD_ROM is not set ++# 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 is not set ++CONFIG_MTD_LUBBOCK=y ++# 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_PXA_CERF is not set ++# CONFIG_MTD_EPXA10DB is not set ++# CONFIG_MTD_AUTCPU12 is not set ++# CONFIG_MTD_EDB7312 is not set ++# CONFIG_MTD_IMPA7 is not set ++CONFIG_ASI_MTD0_SIZE=40000 ++CONFIG_ASI_MTD1_SIZE=100000 ++CONFIG_ASI_MTD2_SIZE=1e00000 ++# CONFIG_MTD_PCI is not set ++ ++# ++# Self-contained MTD device drivers ++# ++# CONFIG_MTD_PMC551 is not set ++# CONFIG_MTD_SLRAM 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 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_BLK_DEV_DAC960 is not set ++# CONFIG_BLK_DEV_UMEM is not set ++CONFIG_BLK_DEV_LOOP=y ++# CONFIG_BLK_DEV_NBD is not set ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_SIZE=4096 ++CONFIG_BLK_DEV_INITRD=y ++ ++# ++# 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 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 ++# 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_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=y ++# CONFIG_WD80x3 is not set ++# CONFIG_ULTRAMCA is not set ++# CONFIG_ULTRA is not set ++# CONFIG_ULTRA32 is not set ++# CONFIG_SMC9194 is not set ++CONFIG_SMC91111=m ++# CONFIG_NET_VENDOR_RACAL is not set ++# CONFIG_NET_ISA is not set ++# CONFIG_NET_PCI is not set ++CONFIG_NET_POCKET=y ++# CONFIG_DE600 is not set ++# CONFIG_DE620 is not set ++ ++# ++# Ethernet (1000 Mbit) ++# ++# CONFIG_ACENIC is not set ++# CONFIG_DL2K 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_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=y ++# CONFIG_STRIP is not set ++CONFIG_WAVELAN=m ++# CONFIG_ARLAN is not set ++CONFIG_AIRONET4500=y ++# CONFIG_AIRONET4500_NONCS is not set ++# CONFIG_AIRONET4500_PROC is not set ++CONFIG_HERMES=m ++CONFIG_PCMCIA_HERMES=m ++CONFIG_AIRO_CS=m ++CONFIG_NET_WIRELESS=y ++ ++# ++# 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 ++ ++# ++# PCMCIA network device support ++# ++CONFIG_NET_PCMCIA=y ++# CONFIG_PCMCIA_3C589 is not set ++# CONFIG_PCMCIA_3C574 is not set ++# CONFIG_PCMCIA_FMVJ18X is not set ++CONFIG_PCMCIA_PCNET=m ++# CONFIG_PCMCIA_AXNET is not set ++CONFIG_PCMCIA_NMCLAN=m ++CONFIG_PCMCIA_SMC91C92=m ++CONFIG_PCMCIA_XIRC2PS=m ++# CONFIG_ARCNET_COM20020_CS is not set ++# CONFIG_PCMCIA_IBMTR is not set ++CONFIG_NET_PCMCIA_RADIO=y ++CONFIG_PCMCIA_RAYCS=m ++CONFIG_PCMCIA_NETWAVE=m ++CONFIG_PCMCIA_WAVELAN=m ++CONFIG_AIRONET4500_CS=m ++ ++# ++# Amateur Radio support ++# ++# CONFIG_HAMRADIO is not set ++ ++# ++# IrDA (infrared) support ++# ++CONFIG_IRDA=m ++CONFIG_IRLAN=m ++# CONFIG_IRNET is not set ++CONFIG_IRCOMM=m ++CONFIG_IRDA_ULTRA=y ++# CONFIG_IRDA_CACHE_LAST_LSAP is not set ++# CONFIG_IRDA_FAST_RR is not set ++CONFIG_IRDA_DEBUG=y ++ ++# ++# Infrared-port device drivers ++# ++CONFIG_IRTTY_SIR=m ++# CONFIG_IRPORT_SIR is not set ++# CONFIG_DONGLE is not set ++# CONFIG_USB_IRDA is not set ++# CONFIG_NSC_FIR is not set ++# CONFIG_WINBOND_FIR is not set ++# CONFIG_TOSHIBA_FIR is not set ++# CONFIG_SMC_IRCC_FIR is not set ++# CONFIG_ALI_FIR is not set ++# CONFIG_VLSI_FIR is not set ++CONFIG_PXA_FIR=m ++ ++# ++# ATA/ATAPI/MFM/RLL support ++# ++CONFIG_IDE=y ++ ++# ++# IDE, ATA and ATAPI Block devices ++# ++CONFIG_BLK_DEV_IDE=y ++# CONFIG_BLK_DEV_HD_IDE is not set ++# CONFIG_BLK_DEV_HD is not set ++CONFIG_BLK_DEV_IDEDISK=y ++# CONFIG_IDEDISK_MULTI_MODE is not set ++# CONFIG_IDEDISK_STROKE is not set ++# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set ++# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set ++# CONFIG_BLK_DEV_IDEDISK_IBM is not set ++# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set ++# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set ++# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set ++# CONFIG_BLK_DEV_IDEDISK_WD is not set ++# CONFIG_BLK_DEV_COMMERIAL is not set ++# CONFIG_BLK_DEV_TIVO is not set ++CONFIG_BLK_DEV_IDECS=m ++# CONFIG_BLK_DEV_IDECD is not set ++# CONFIG_BLK_DEV_IDETAPE is not set ++# CONFIG_BLK_DEV_IDEFLOPPY is not set ++# CONFIG_BLK_DEV_IDESCSI is not set ++# CONFIG_IDE_TASK_IOCTL is not set ++# CONFIG_BLK_DEV_CMD640 is not set ++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set ++# CONFIG_BLK_DEV_ISAPNP is not set ++# CONFIG_IDE_CHIPSETS is not set ++# CONFIG_IDEDMA_AUTO is not set ++# CONFIG_DMA_NONPCI is not set ++# CONFIG_BLK_DEV_IDE_MODES is not set ++# CONFIG_BLK_DEV_ATARAID is not set ++# CONFIG_BLK_DEV_ATARAID_PDC is not set ++# CONFIG_BLK_DEV_ATARAID_HPT 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=y ++CONFIG_INPUT_KEYBDEV=m ++CONFIG_INPUT_MOUSEDEV=m ++CONFIG_INPUT_MOUSEDEV_SCREEN_X=640 ++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480 ++# CONFIG_INPUT_JOYDEV is not set ++CONFIG_INPUT_EVDEV=y ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++# CONFIG_VT_CONSOLE is not set ++CONFIG_SERIAL=y ++CONFIG_SERIAL_CONSOLE=y ++# CONFIG_SERIAL_EXTENDED is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++ ++# ++# 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_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_IDP_KEYB is not set ++CONFIG_MATRIX_KEYBOARD=y ++# CONFIG_SA1111_PS2_KEYB is not set ++CONFIG_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++ ++# ++# I2C support ++# ++# CONFIG_I2C is not set ++ ++# ++# 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=y ++# CONFIG_ATIXL_BUSMOUSE is not set ++# CONFIG_LOGIBUSMOUSE is not set ++# CONFIG_MS_BUSMOUSE is not set ++CONFIG_MOUSE=y ++CONFIG_PSMOUSE=y ++# CONFIG_82C710_MOUSE is not set ++# CONFIG_PC110_PAD is not set ++# CONFIG_MK712_MOUSE is not set ++ ++# ++# Joysticks ++# ++# CONFIG_INPUT_GAMEPORT is not set ++# CONFIG_INPUT_NS558 is not set ++# CONFIG_INPUT_LIGHTNING is not set ++# CONFIG_INPUT_PCIGAME is not set ++# CONFIG_INPUT_CS461X is not set ++# CONFIG_INPUT_EMU10K1 is not set ++# CONFIG_INPUT_SERIO is not set ++# CONFIG_INPUT_SERPORT is not set ++# CONFIG_INPUT_ANALOG is not set ++# CONFIG_INPUT_A3D is not set ++# CONFIG_INPUT_ADI is not set ++# CONFIG_INPUT_COBRA is not set ++# CONFIG_INPUT_GF2K is not set ++# CONFIG_INPUT_GRIP is not set ++# CONFIG_INPUT_INTERACT is not set ++# CONFIG_INPUT_TMDC is not set ++# CONFIG_INPUT_SIDEWINDER is not set ++# CONFIG_INPUT_IFORCE_USB is not set ++# CONFIG_INPUT_IFORCE_232 is not set ++# CONFIG_INPUT_WARRIOR is not set ++# CONFIG_INPUT_MAGELLAN is not set ++# CONFIG_INPUT_SPACEORB is not set ++# CONFIG_INPUT_SPACEBALL is not set ++# CONFIG_INPUT_STINGER is not set ++# CONFIG_INPUT_DB9 is not set ++# CONFIG_INPUT_GAMECON is not set ++# CONFIG_INPUT_TURBOGRAFX is not set ++# CONFIG_QIC02_TAPE is not set ++ ++# ++# Watchdog Cards ++# ++# CONFIG_WATCHDOG is not set ++# CONFIG_NVRAM is not set ++# CONFIG_RTC is not set ++# CONFIG_PXA_RTC is not set ++# 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 ++# CONFIG_DRM is not set ++ ++# ++# PCMCIA character devices ++# ++CONFIG_PCMCIA_SERIAL_CS=m ++ ++# ++# Multimedia devices ++# ++# CONFIG_VIDEO_DEV is not set ++ ++# ++# File systems ++# ++# CONFIG_QUOTA 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_BFS_FS is not set ++CONFIG_EXT3_FS=m ++CONFIG_JBD=m ++# CONFIG_JBD_DEBUG is not set ++CONFIG_FAT_FS=m ++CONFIG_MSDOS_FS=m ++# CONFIG_UMSDOS_FS is not set ++CONFIG_VFAT_FS=m ++# CONFIG_EFS_FS is not set ++# CONFIG_JFFS_FS is not set ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_FS_DEBUG=0 ++CONFIG_CRAMFS=y ++# 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_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=y ++# 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 ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++# CONFIG_ROOT_NFS is not set ++# CONFIG_NFSD is not set ++# CONFIG_NFSD_V3 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 ++CONFIG_ZLIB_FS_INFLATE=y ++ ++# ++# Partition Types ++# ++CONFIG_PARTITION_ADVANCED=y ++# CONFIG_ACORN_PARTITION is not set ++# CONFIG_OSF_PARTITION is not set ++# CONFIG_AMIGA_PARTITION is not set ++# CONFIG_ATARI_PARTITION is not set ++# CONFIG_MAC_PARTITION is not set ++CONFIG_MSDOS_PARTITION=y ++# CONFIG_BSD_DISKLABEL is not set ++# CONFIG_MINIX_SUBPARTITION is not set ++# CONFIG_SOLARIS_X86_PARTITION is not set ++# CONFIG_UNIXWARE_DISKLABEL is not set ++# CONFIG_LDM_PARTITION is not set ++# CONFIG_SGI_PARTITION is not set ++# CONFIG_ULTRIX_PARTITION is not set ++# CONFIG_SUN_PARTITION is not set ++# CONFIG_SMB_NLS is not set ++CONFIG_NLS=y ++ ++# ++# Native Language Support ++# ++CONFIG_NLS_DEFAULT="iso8859-1" ++CONFIG_NLS_CODEPAGE_437=m ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++# CONFIG_NLS_CODEPAGE_850 is not set ++# CONFIG_NLS_CODEPAGE_852 is not set ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++# CONFIG_NLS_CODEPAGE_863 is not set ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++CONFIG_NLS_ISO8859_1=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_UTF8 is not set ++ ++# ++# Console drivers ++# ++CONFIG_PC_KEYMAP=y ++# CONFIG_VGA_CONSOLE is not set ++ ++# ++# Frame-buffer support ++# ++CONFIG_FB=y ++CONFIG_DUMMY_CONSOLE=y ++# CONFIG_FB_ACORN is not set ++# CONFIG_FB_ANAKIN is not set ++# CONFIG_FB_CLPS711X is not set ++# CONFIG_FB_SA1100 is not set ++CONFIG_FB_PXA=y ++# CONFIG_FB_CYBER2000 is not set ++# CONFIG_FB_VIRTUAL is not set ++# CONFIG_FBCON_ADVANCED is not set ++CONFIG_FBCON_CFB2=y ++CONFIG_FBCON_CFB4=y ++CONFIG_FBCON_CFB8=y ++CONFIG_FBCON_CFB16=y ++# CONFIG_FBCON_FONTWIDTH8_ONLY is not set ++# CONFIG_FBCON_FONTS is not set ++CONFIG_FONT_8x8=y ++CONFIG_FONT_8x16=y ++ ++# ++# Sound ++# ++CONFIG_SOUND=y ++# CONFIG_SOUND_BT878 is not set ++# CONFIG_SOUND_CMPCI is not set ++# CONFIG_SOUND_EMU10K1 is not set ++# CONFIG_MIDI_EMU10K1 is not set ++# CONFIG_SOUND_FUSION is not set ++# CONFIG_SOUND_CS4281 is not set ++# CONFIG_SOUND_ES1370 is not set ++# CONFIG_SOUND_ES1371 is not set ++# CONFIG_SOUND_ESSSOLO1 is not set ++# CONFIG_SOUND_MAESTRO is not set ++# CONFIG_SOUND_MAESTRO3 is not set ++# CONFIG_SOUND_ICH is not set ++# CONFIG_SOUND_RME96XX is not set ++# CONFIG_SOUND_SONICVIBES is not set ++# CONFIG_SOUND_TRIDENT is not set ++# CONFIG_SOUND_MSNDCLAS is not set ++# CONFIG_SOUND_MSNDPIN is not set ++# CONFIG_SOUND_VIA82CXXX is not set ++# CONFIG_MIDI_VIA82CXXX is not set ++# CONFIG_SOUND_OSS is not set ++# CONFIG_SOUND_WAVEARTIST is not set ++CONFIG_SOUND_PXA_AC97=y ++# CONFIG_SOUND_TVMIXER 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 ++CONFIG_MCP_UCB1400_TS=m ++ ++# ++# USB support ++# ++# CONFIG_USB 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=y ++# CONFIG_MAGIC_SYSRQ is not set ++# CONFIG_DEBUG_SPINLOCK is not set ++# CONFIG_DEBUG_WAITQ is not set ++CONFIG_DEBUG_BUGVERBOSE=y ++CONFIG_DEBUG_ERRORS=y ++# CONFIG_DEBUG_LL is not set ++# CONFIG_DEBUG_DC21285_PORT is not set ++# CONFIG_DEBUG_CLPS711X_UART2 is not set +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/def-configs/trizeps2 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,873 @@ ++# ++# 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_PXA=y ++# 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 ++ ++# ++# 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_ADSBITSY 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_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_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_H3600_SLEEVE is not set ++ ++# ++# Intel PXA250/210 Implementations ++# ++# CONFIG_ARCH_LUBBOCK is not set ++# CONFIG_ARCH_PXA_IDP is not set ++# CONFIG_ARCH_PXA_CERF is not set ++CONFIG_ARCH_TRIZEPS2=y ++CONFIG_TRIZEPS2=y ++CONFIG_PXA_USB=y ++# CONFIG_PXA_USB_NETLINK is not set ++# CONFIG_PXA_USB_CHAR is not set ++ ++# ++# 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_P720T is not set ++# CONFIG_ARCH_FORTUNET is not set ++# CONFIG_ARCH_EP7211 is not set ++# CONFIG_ARCH_EP7212 is not set ++# CONFIG_ARCH_ACORN 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 is not set ++# 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_ARM1026 is not set ++# CONFIG_CPU_SA110 is not set ++# CONFIG_CPU_SA1100 is not set ++CONFIG_CPU_32v5=y ++CONFIG_CPU_XSCALE=y ++# CONFIG_XSCALE_CACHE_ERRATA is not set ++# CONFIG_CPU_32v3 is not set ++# CONFIG_CPU_32v4 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=y ++ ++# ++# PCMCIA/CardBus support ++# ++CONFIG_PCMCIA=y ++# CONFIG_I82092 is not set ++# CONFIG_I82365 is not set ++# CONFIG_TCIC is not set ++# CONFIG_PCMCIA_CLPS6700 is not set ++# CONFIG_PCMCIA_SA1100 is not set ++CONFIG_PCMCIA_PXA=y ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++# CONFIG_BSD_PROCESS_ACCT is not set ++CONFIG_SYSCTL=y ++CONFIG_FPE_NWFPE=y ++# 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="root=/dev/mtdblock3 rw console=ttyS0,38400 mem=32M noinitrd init=/linuxrc" ++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=y ++# CONFIG_MTD_CONCAT is not set ++CONFIG_MTD_REDBOOT_PARTS=y ++CONFIG_MTD_CMDLINE_PARTS=y ++# 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 is not set ++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_RAM is not set ++# CONFIG_MTD_ROM is not set ++# 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 is not set ++# CONFIG_MTD_LUBBOCK is not set ++# 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_PXA_CERF is not set ++# CONFIG_MTD_EPXA10DB is not set ++# CONFIG_MTD_AUTCPU12 is not set ++# CONFIG_MTD_EDB7312 is not set ++# CONFIG_MTD_IMPA7 is not set ++CONFIG_MTD_TRIZEPS2=y ++# CONFIG_MTD_PCI is not set ++ ++# ++# Self-contained MTD device drivers ++# ++# CONFIG_MTD_PMC551 is not set ++# CONFIG_MTD_SLRAM 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 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_BLK_DEV_DAC960 is not set ++# CONFIG_BLK_DEV_UMEM is not set ++CONFIG_BLK_DEV_LOOP=y ++# CONFIG_BLK_DEV_NBD is not set ++# CONFIG_BLK_DEV_RAM is not set ++# CONFIG_BLK_DEV_INITRD 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 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 is not set ++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 ++# 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_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=y ++# CONFIG_WD80x3 is not set ++# CONFIG_ULTRAMCA is not set ++# CONFIG_ULTRA is not set ++# CONFIG_ULTRA32 is not set ++CONFIG_SMC9194=y ++# 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_MYRI_SBUS is not set ++# CONFIG_NS83820 is not set ++# CONFIG_HAMACHI is not set ++# CONFIG_YELLOWFIN 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=m ++# CONFIG_PPP_MULTILINK is not set ++# CONFIG_PPP_FILTER is not set ++CONFIG_PPP_ASYNC=m ++CONFIG_PPP_SYNC_TTY=m ++CONFIG_PPP_DEFLATE=m ++CONFIG_PPP_BSDCOMP=m ++# CONFIG_PPPOE is not set ++# CONFIG_SLIP is not set ++ ++# ++# Wireless LAN (non-hamradio) ++# ++CONFIG_NET_RADIO=y ++# CONFIG_STRIP is not set ++# CONFIG_WAVELAN is not set ++# CONFIG_ARLAN is not set ++# CONFIG_AIRONET4500 is not set ++# CONFIG_AIRONET4500_NONCS is not set ++# CONFIG_AIRONET4500_PROC is not set ++# CONFIG_HERMES is not set ++# CONFIG_PCMCIA_HERMES is not set ++CONFIG_AIRO_CS=m ++CONFIG_NET_WIRELESS=y ++ ++# ++# 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 ++ ++# ++# PCMCIA network device support ++# ++CONFIG_NET_PCMCIA=y ++# CONFIG_PCMCIA_3C589 is not set ++CONFIG_PCMCIA_3C574=m ++# CONFIG_PCMCIA_FMVJ18X is not set ++# CONFIG_PCMCIA_PCNET is not set ++# CONFIG_PCMCIA_AXNET is not set ++# CONFIG_PCMCIA_NMCLAN is not set ++# CONFIG_PCMCIA_SMC91C92 is not set ++# CONFIG_PCMCIA_XIRC2PS is not set ++# CONFIG_ARCNET_COM20020_CS is not set ++# CONFIG_PCMCIA_IBMTR is not set ++CONFIG_NET_PCMCIA_RADIO=y ++# CONFIG_PCMCIA_RAYCS is not set ++# CONFIG_PCMCIA_NETWAVE is not set ++# CONFIG_PCMCIA_WAVELAN is not set ++# CONFIG_AIRONET4500_CS 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=m ++ ++# ++# IDE, ATA and ATAPI Block devices ++# ++CONFIG_BLK_DEV_IDE=m ++# CONFIG_BLK_DEV_HD_IDE is not set ++# CONFIG_BLK_DEV_HD is not set ++CONFIG_BLK_DEV_IDEDISK=m ++# CONFIG_IDEDISK_MULTI_MODE is not set ++# CONFIG_IDEDISK_STROKE is not set ++# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set ++# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set ++# CONFIG_BLK_DEV_IDEDISK_IBM is not set ++# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set ++# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set ++# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set ++# CONFIG_BLK_DEV_IDEDISK_WD is not set ++# CONFIG_BLK_DEV_COMMERIAL is not set ++# CONFIG_BLK_DEV_TIVO is not set ++CONFIG_BLK_DEV_IDECS=m ++# CONFIG_BLK_DEV_IDECD is not set ++# CONFIG_BLK_DEV_IDETAPE is not set ++# CONFIG_BLK_DEV_IDEFLOPPY is not set ++# CONFIG_BLK_DEV_IDESCSI is not set ++# CONFIG_IDE_TASK_IOCTL is not set ++# CONFIG_BLK_DEV_CMD640 is not set ++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set ++# CONFIG_BLK_DEV_ISAPNP is not set ++# CONFIG_IDE_CHIPSETS is not set ++# CONFIG_IDEDMA_AUTO is not set ++# CONFIG_DMA_NONPCI is not set ++# CONFIG_BLK_DEV_IDE_MODES is not set ++# CONFIG_BLK_DEV_ATARAID is not set ++# CONFIG_BLK_DEV_ATARAID_PDC is not set ++# CONFIG_BLK_DEV_ATARAID_HPT 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 ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++# CONFIG_VT_CONSOLE is not set ++CONFIG_SERIAL=y ++CONFIG_SERIAL_CONSOLE=y ++# CONFIG_SERIAL_EXTENDED is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++ ++# ++# 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_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_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++ ++# ++# I2C support ++# ++CONFIG_I2C=y ++# CONFIG_I2C_ALGOBIT is not set ++# CONFIG_I2C_ALGOPCF is not set ++CONFIG_I2C_PXA_ALGO=y ++CONFIG_I2C_PXA_ADAP=y ++CONFIG_I2C_CHARDEV=y ++CONFIG_I2C_PROC=y ++# CONFIG_I2C_DS1307 is not set ++ ++# ++# 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 ++ ++# ++# Watchdog Cards ++# ++# CONFIG_WATCHDOG is not set ++# CONFIG_NVRAM is not set ++# CONFIG_RTC is not set ++CONFIG_PXA_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 ++# CONFIG_DRM is not set ++ ++# ++# PCMCIA character devices ++# ++# CONFIG_PCMCIA_SERIAL_CS is not set ++CONFIG_TRIZEPS2_TTLIO=m ++ ++# ++# Multimedia devices ++# ++# CONFIG_VIDEO_DEV is not set ++ ++# ++# File systems ++# ++# CONFIG_QUOTA 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_BFS_FS is not set ++CONFIG_EXT3_FS=y ++CONFIG_JBD=y ++# CONFIG_JBD_DEBUG is not set ++CONFIG_FAT_FS=m ++CONFIG_MSDOS_FS=m ++# CONFIG_UMSDOS_FS is not set ++CONFIG_VFAT_FS=m ++# CONFIG_EFS_FS is not set ++# CONFIG_JFFS_FS is not set ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_FS_DEBUG=0 ++# CONFIG_CRAMFS is not set ++CONFIG_TMPFS=y ++CONFIG_RAMFS=y ++# CONFIG_ISO9660_FS is not set ++# CONFIG_JOLIET is not set ++# CONFIG_ZISOFS 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 is not set ++# CONFIG_DEVFS_MOUNT is not set ++# CONFIG_DEVFS_DEBUG is not set ++CONFIG_DEVPTS_FS=y ++# 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 ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++CONFIG_NFS_FS=m ++# CONFIG_NFS_V3 is not set ++# CONFIG_ROOT_NFS is not set ++# CONFIG_NFSD is not set ++# CONFIG_NFSD_V3 is not set ++CONFIG_SUNRPC=m ++CONFIG_LOCKD=m ++# 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 ++# CONFIG_ZLIB_FS_INFLATE is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED is not set ++CONFIG_MSDOS_PARTITION=y ++# CONFIG_SMB_NLS is not set ++CONFIG_NLS=y ++ ++# ++# Native Language Support ++# ++CONFIG_NLS_DEFAULT="iso8859-1" ++# CONFIG_NLS_CODEPAGE_437 is not set ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++# CONFIG_NLS_CODEPAGE_850 is not set ++# CONFIG_NLS_CODEPAGE_852 is not set ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++# CONFIG_NLS_CODEPAGE_863 is not set ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++CONFIG_NLS_ISO8859_1=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_UTF8 is not set ++ ++# ++# Console drivers ++# ++CONFIG_PC_KEYMAP=y ++# CONFIG_VGA_CONSOLE is not set ++ ++# ++# Frame-buffer support ++# ++CONFIG_FB=y ++CONFIG_DUMMY_CONSOLE=y ++# CONFIG_FB_ACORN is not set ++# CONFIG_FB_ANAKIN is not set ++# CONFIG_FB_CLPS711X is not set ++# CONFIG_FB_SA1100 is not set ++CONFIG_FB_PXA=y ++# CONFIG_FB_CYBER2000 is not set ++# CONFIG_FB_VIRTUAL is not set ++CONFIG_FBCON_ADVANCED=y ++# CONFIG_FBCON_MFB is not set ++# CONFIG_FBCON_CFB2 is not set ++# CONFIG_FBCON_CFB4 is not set ++# CONFIG_FBCON_CFB8 is not set ++CONFIG_FBCON_CFB16=y ++# CONFIG_FBCON_CFB24 is not set ++# CONFIG_FBCON_CFB32 is not set ++# CONFIG_FBCON_AFB is not set ++# CONFIG_FBCON_ILBM is not set ++# CONFIG_FBCON_IPLAN2P2 is not set ++# CONFIG_FBCON_IPLAN2P4 is not set ++# CONFIG_FBCON_IPLAN2P8 is not set ++# CONFIG_FBCON_MAC is not set ++# CONFIG_FBCON_VGA_PLANES is not set ++# CONFIG_FBCON_VGA is not set ++# CONFIG_FBCON_HGA is not set ++CONFIG_FBCON_FONTWIDTH8_ONLY=y ++CONFIG_FBCON_FONTS=y ++# CONFIG_FONT_8x8 is not set ++# CONFIG_FONT_8x16 is not set ++# CONFIG_FONT_SUN8x16 is not set ++# CONFIG_FONT_PEARL_8x8 is not set ++CONFIG_FONT_ACORN_8x8=y ++ ++# ++# Sound ++# ++CONFIG_SOUND=y ++# CONFIG_SOUND_BT878 is not set ++# CONFIG_SOUND_CMPCI is not set ++# CONFIG_SOUND_EMU10K1 is not set ++# CONFIG_MIDI_EMU10K1 is not set ++# CONFIG_SOUND_FUSION is not set ++# CONFIG_SOUND_CS4281 is not set ++# CONFIG_SOUND_ES1370 is not set ++# CONFIG_SOUND_ES1371 is not set ++# CONFIG_SOUND_ESSSOLO1 is not set ++# CONFIG_SOUND_MAESTRO is not set ++# CONFIG_SOUND_MAESTRO3 is not set ++# CONFIG_SOUND_ICH is not set ++# CONFIG_SOUND_RME96XX is not set ++# CONFIG_SOUND_SONICVIBES is not set ++# CONFIG_SOUND_TRIDENT is not set ++# CONFIG_SOUND_MSNDCLAS is not set ++# CONFIG_SOUND_MSNDPIN is not set ++# CONFIG_SOUND_VIA82CXXX is not set ++# CONFIG_MIDI_VIA82CXXX is not set ++# CONFIG_SOUND_OSS is not set ++# CONFIG_SOUND_WAVEARTIST is not set ++CONFIG_SOUND_PXA_AC97=y ++# CONFIG_SOUND_TVMIXER is not set ++ ++# ++# Multimedia Capabilities Port drivers ++# ++CONFIG_MCP=y ++# 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 ++CONFIG_MCP_UCB1400_TS=y ++CONFIG_MCP_UCB1X00_TS_COMPAT=y ++ ++# ++# USB support ++# ++# CONFIG_USB is not set ++ ++# ++# Bluetooth support ++# ++# CONFIG_BLUEZ is not set ++ ++# ++# Kernel hacking ++# ++CONFIG_FRAME_POINTER=y ++CONFIG_DEBUG_USER=y ++CONFIG_DEBUG_INFO=y ++# CONFIG_NO_PGT_CACHE is not set ++CONFIG_DEBUG_KERNEL=y ++# CONFIG_DEBUG_SLAB is not set ++CONFIG_MAGIC_SYSRQ=y ++# CONFIG_DEBUG_SPINLOCK is not set ++# CONFIG_DEBUG_WAITQ is not set ++CONFIG_DEBUG_BUGVERBOSE=y ++CONFIG_DEBUG_ERRORS=y ++CONFIG_DEBUG_LL=y ++# CONFIG_DEBUG_DC21285_PORT is not set ++# CONFIG_DEBUG_CLPS711X_UART2 is not set +--- linux-2.4.25/arch/arm/kernel/Makefile~2.4.25-vrs2-pxa1.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/kernel/Makefile 2004-03-31 17:15:11.000000000 +0200 +@@ -10,7 +10,7 @@ + HEAD_OBJ = head-$(PROCESSOR).o + ENTRY_OBJ = entry-$(PROCESSOR).o + +-AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) ++AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -DDATAADDR=$(DATAADDR) + AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) + + # This is depreciated. +@@ -45,7 +45,7 @@ + $(CONFIG_FOOTBRIDGE) $(CONFIG_ARCH_EBSA110) \ + $(CONFIG_ARCH_SA1100) $(CONFIG_ARCH_CAMELOT) \ + $(CONFIG_ARCH_MX1ADS) $(CONFIG_ARCH_OMAHA) \ +- $(CONFIG_ARCH_AT91RM9200) ++ $(CONFIG_ARCH_AT91RM9200) $(CONFIG_ARCH_PXA) + + ifneq ($(findstring y,$(no-irq-arch)),y) + obj-y += irq-arch.o +--- linux-2.4.25/arch/arm/kernel/debug-armv.S~2.4.25-vrs2-pxa1.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/kernel/debug-armv.S 2004-03-31 17:15:11.000000000 +0200 +@@ -221,6 +221,31 @@ + bne 1001b + .endm + ++#elif defined(CONFIG_ARCH_PXA) ++ ++ .macro addruart,rx ++ mrc p15, 0, \rx, c1, c0 ++ tst \rx, #1 @ MMU enabled? ++ moveq \rx, #0x40000000 @ physical ++ movne \rx, #io_p2v(0x40000000) @ virtual ++ orr \rx, \rx, #0x00100000 @ FFUART ++ .endm ++ ++ .macro senduart,rd,rx ++ str \rd, [\rx, #0] ++ .endm ++ ++ .macro busyuart,rd,rx ++1002: ldr \rd, [\rx, #0x14] ++ tst \rd, #(1 << 6) ++ beq 1002b ++ .endm ++ ++ .macro waituart,rd,rx ++1001: ldr \rd, [\rx, #0x14] ++ tst \rd, #(1 << 5) ++ beq 1001b ++ .endm + #elif defined(CONFIG_ARCH_CLPS7500) + .macro addruart,rx + mov \rx, #0xe0000000 +--- linux-2.4.25/arch/arm/kernel/entry-armv.S~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:08.000000000 +0200 ++++ linux-2.4.25/arch/arm/kernel/entry-armv.S 2004-03-31 17:15:11.000000000 +0200 +@@ -615,6 +615,27 @@ + .text + .endm + ++#elif CONFIG_ARCH_PXA ++ ++ .macro disable_fiq ++ .endm ++ ++ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp ++ mov \base, #io_p2v(0x40000000) @ IIR Ctl = 0x40d00000 ++ add \base, \base, #0x00d00000 ++ ldr \irqstat, [\base, #0] @ ICIP ++ ldr \irqnr, [\base, #4] @ ICMR ++ ands \irqstat, \irqstat, \irqnr ++ beq 1001f ++ rsb \irqnr, \irqstat, #0 ++ and \irqstat, \irqstat, \irqnr ++ clz \irqnr, \irqstat ++ rsb \irqnr, \irqnr, #(31 - PXA_IRQ_SKIP) ++1001: ++ .endm ++ ++ .macro irq_prio_table ++ .endm + #else + #error Unknown architecture + #endif +@@ -891,9 +912,17 @@ + stmfd sp!, {r4 - sl, fp, lr} @ Store most regs on stack + mrs ip, cpsr + str ip, [sp, #-4]! @ Save cpsr_SVC ++#ifdef CONFIG_CPU_XSCALE ++ mra r4, r5, acc0 ++ stmfd sp!, {r4, r5} ++#endif + str sp, [r0, #TSS_SAVE] @ Save sp_SVC + ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC + ldr r2, [r1, #TSS_DOMAIN] ++#ifdef CONFIG_CPU_XSCALE ++ ldmfd sp!, {r4, r5} ++ mar acc0, r4, r5 ++#endif + ldr ip, [sp], #4 + mcr p15, 0, r2, c3, c0 @ Set domain register + msr spsr, ip @ Save tasks CPSR into SPSR for this return +--- linux-2.4.25/arch/arm/kernel/head-armv.S~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:08.000000000 +0200 ++++ linux-2.4.25/arch/arm/kernel/head-armv.S 2004-03-31 17:15:11.000000000 +0200 +@@ -30,6 +30,7 @@ + * + * swapper_pg_dir, pgtbl and krnladr are all closely related. + */ ++#ifndef CONFIG_XIP_KERNEL + #if (TEXTADDR & 0xffff) != 0x8000 + #error TEXTADDR must start at 0xXXXX8000 + #endif +@@ -41,6 +42,26 @@ + adr \reg, stext + sub \reg, \reg, #0x4000 + .endm ++#else ++#if (DATAADDR & 0xffff) != 0x8000 ++#error DATAADDR must start at 0xXXXX8000 ++#endif ++ ++#define PAGE_OFFSET 0xc0000000 ++#ifdef CONFIG_ARCH_LUBBOCK ++#define PHYS_OFFSET 0xa0000000 ++#elif CONFIG_ARCH_OMAP ++#define PHYS_OFFSET 0x10000000 ++#endif ++ ++ .globl SYMBOL_NAME(swapper_pg_dir) ++ .equ SYMBOL_NAME(swapper_pg_dir), DATAADDR - 0x4000 ++ ++ .macro pgtbl, reg, rambase ++ ldr \reg, PGTBL ++ add \reg, \reg, #PHYS_OFFSET - PAGE_OFFSET ++ .endm ++#endif + + /* + * Since the page table is closely related to the kernel start address, we +@@ -131,6 +152,32 @@ + mov r1, #MACH_TYPE_L7200 + #endif + ++#ifdef CONFIG_XIP_KERNEL ++ ++#if defined(CONFIG_ARCH_LUBBOCK) ++ mov r1, #MACH_TYPE_LUBBOCK ++#endif ++ ++ @ Data cache might be active. ++ @ Be sure to flush kernel binary out of the cache, ++ @ whatever state it is, before it is turned off. ++ @ This is done by fetching through currently executed ++ @ memory to be sure we hit the same cache. ++ bic r2, pc, #0x1f ++ add r3, r2, #0x10000 @ 64 kb is quite enough... ++1: ldr r0, [r2], #32 ++ teq r2, r3 ++ bne 1b ++ mcr p15, 0, r0, c7, c10, 4 @ drain WB ++ mcr p15, 0, r0, c7, c7, 0 @ flush I & D caches ++ ++ @ disabling MMU and caches ++ mrc p15, 0, r0, c1, c0, 0 @ read control reg ++ bic r0, r0, #0x05 @ clear DC, MMU ++ bic r0, r0, #0x1000 @ clear Icache ++ mcr p15, 0, r0, c1, c0, 0 ++#endif ++ + mov r0, #F_BIT | I_BIT | MODE_SVC @ make sure svc mode + msr cpsr_c, r0 @ and all irqs disabled + bl __lookup_processor_type +@@ -179,6 +226,17 @@ + */ + .align 5 + __mmap_switched: ++#ifdef CONFIG_XIP_KERNEL ++ ldr r3, ETEXT @ data section copy ++ ldr r4, SDATA ++ ldr r5, EDATA ++1: ++ ldr r6, [r3], #4 ++ str r6, [r4], #4 ++ cmp r4, r5 ++ blo 1b ++#endif ++ + adr r3, __switch_data + 4 + ldmia r3, {r4, r5, r6, r7, r8, sp}@ r2 = compat + @ sp = stack pointer +@@ -233,6 +291,8 @@ + teq r0, r2 + bne 1b + ++#ifndef CONFIG_XIP_KERNEL ++ + /* + * Create identity mapping for first MB of kernel to + * cater for the MMU enable. This identity mapping +@@ -271,6 +331,43 @@ + add r3, r8, r2 @ flags + rambase + str r3, [r0] + ++#else /* CONFIG_XIP_KERNEL */ ++ ++ mov r3, pc, lsr #20 ++ mov r3, r3, lsl #20 @ phys kernel start ++ ++ add r0, r4, r3, lsr #18 ++ orr r3, r3, r8 ++ str r3, [r0] ++ ++ mov r0, #TEXTADDR & 0xff000000 ++ add r0, r0, #TEXTADDR & 0x00f00000 @ virt kernel start ++ add r0, r4, r0, lsr #18 ++ add r2, r3, #4 << 20 @ kernel + 4MB ++ ++1: ++ str r3, [r0], #4 ++ add r3, r3, #1 << 20 ++ cmp r3, r2 ++ bne 1b ++ ++ bic r3, r4, #0x000ff000 @ ram start ++ add r0, r4, r3, lsr #18 ++ orr r3, r3, r8 ++ str r3, [r0], #4 ++ ++ add r0, r3, #PAGE_OFFSET - PHYS_OFFSET ++ add r0, r4, r0, lsr #18 ++ add r2, r3, #4 << 20 @ ram + 4MB ++ ++1: ++ str r3, [r0], #4 ++ add r3, r3, #1 << 20 ++ cmp r3, r2 ++ bne 1b ++ ++#endif /* CONFIG_XIP_KERNEL */ ++ + bic r8, r8, #0x0c @ turn off cacheable + @ and bufferable bits + #ifdef CONFIG_DEBUG_LL +@@ -433,3 +530,13 @@ + mov pc, lr + 2: ldmib r4, {r5, r6, r7} @ found, get results + mov pc, lr ++ ++#ifdef CONFIG_XIP_KERNEL ++ ++PGTBL: .long SYMBOL_NAME(swapper_pg_dir) ++ ++ETEXT: .long SYMBOL_NAME(_endtext) ++SDATA: .long SYMBOL_NAME(_sdata) ++EDATA: .long SYMBOL_NAME(__bss_start) ++ ++#endif +--- linux-2.4.25/arch/arm/kernel/setup.c~2.4.25-vrs2-pxa1.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/kernel/setup.c 2004-03-31 17:15:11.000000000 +0200 +@@ -55,6 +55,10 @@ + extern void reboot_setup(char *str); + extern int root_mountflags; + extern int _stext, _text, _etext, _edata, _end; ++#ifdef CONFIG_XIP_KERNEL ++extern int _endtext, _sdata; ++#endif ++ + + unsigned int processor_id; + unsigned int __machine_arch_type; +@@ -105,6 +109,109 @@ + #define lp1 io_res[1] + #define lp2 io_res[2] + ++#ifdef CONFIG_CPU_32 ++static const char *cache_types[16] = { ++ "write-through", ++ "write-back", ++ "write-back", ++ "undefined 3", ++ "undefined 4", ++ "undefined 5", ++ "write-back", ++ "write-back", ++ "undefined 8", ++ "undefined 9", ++ "undefined 10", ++ "undefined 11", ++ "undefined 12", ++ "undefined 13", ++ "undefined 14", ++ "undefined 15", ++}; ++ ++static const char *cache_clean[16] = { ++ "not required", ++ "read-block", ++ "cp15 c7 ops", ++ "undefined 3", ++ "undefined 4", ++ "undefined 5", ++ "cp15 c7 ops", ++ "cp15 c7 ops", ++ "undefined 8", ++ "undefined 9", ++ "undefined 10", ++ "undefined 11", ++ "undefined 12", ++ "undefined 13", ++ "undefined 14", ++ "undefined 15", ++}; ++ ++static const char *cache_lockdown[16] = { ++ "not supported", ++ "not supported", ++ "not supported", ++ "undefined 3", ++ "undefined 4", ++ "undefined 5", ++ "format A", ++ "format B", ++ "undefined 8", ++ "undefined 9", ++ "undefined 10", ++ "undefined 11", ++ "undefined 12", ++ "undefined 13", ++ "undefined 14", ++ "undefined 15", ++}; ++ ++#define CACHE_TYPE(x) (((x) >> 25) & 15) ++#define CACHE_S(x) ((x) & (1 << 24)) ++#define CACHE_DSIZE(x) (((x) >> 12) & 4095) /* only if S=1 */ ++#define CACHE_ISIZE(x) ((x) & 4095) ++ ++#define CACHE_SIZE(y) (((y) >> 6) & 7) ++#define CACHE_ASSOC(y) (((y) >> 3) & 7) ++#define CACHE_M(y) ((y) & (1 << 2)) ++#define CACHE_LINE(y) ((y) & 3) ++ ++static inline void dump_cache(const char *prefix, unsigned int cache) ++{ ++ unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0); ++ ++ printk("%s size %dK associativity %d line length %d sets %d\n", ++ prefix, ++ mult << (8 + CACHE_SIZE(cache)), ++ (mult << CACHE_ASSOC(cache)) >> 1, ++ 8 << CACHE_LINE(cache), ++ 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) - ++ CACHE_LINE(cache))); ++} ++ ++static inline void dump_cpu_cache_id(void) ++{ ++ unsigned int cache_info; ++ ++ asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (cache_info)); ++ ++ if (cache_info == processor_id) ++ return; ++ ++ printk("CPU: D %s cache\n", cache_types[CACHE_TYPE(cache_info)]); ++ if (CACHE_S(cache_info)) { ++ dump_cache("CPU: I cache", CACHE_ISIZE(cache_info)); ++ dump_cache("CPU: D cache", CACHE_DSIZE(cache_info)); ++ } else { ++ dump_cache("CPU: cache", CACHE_ISIZE(cache_info)); ++ } ++} ++ ++#else ++#define dump_cpu_cache_id() do { } while (0) ++#endif ++ + static void __init setup_processor(void) + { + extern struct proc_info_list __proc_info_begin, __proc_info_end; +@@ -272,7 +379,11 @@ + + kernel_code.start = __virt_to_phys(init_mm.start_code); + kernel_code.end = __virt_to_phys(init_mm.end_code - 1); ++#ifndef CONFIG_XIP_KERNEL + kernel_data.start = __virt_to_phys(init_mm.end_code); ++#else ++ kernel_data.start = __virt_to_phys(init_mm.start_data); ++#endif + kernel_data.end = __virt_to_phys(init_mm.brk - 1); + + for (i = 0; i < mi->nr_banks; i++) { +@@ -531,7 +642,12 @@ + } + + init_mm.start_code = (unsigned long) &_text; ++#ifndef CONFIG_XIP_KERNEL + init_mm.end_code = (unsigned long) &_etext; ++#else ++ init_mm.end_code = (unsigned long) &_endtext; ++ init_mm.start_data = (unsigned long) &_sdata; ++#endif + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) &_end; + +@@ -568,6 +684,41 @@ + NULL + }; + ++static const char *proc_arch[16] = { ++ "undefined 0", ++ "4", ++ "4T", ++ "5", ++ "5T", ++ "5TE", ++ "undefined 6", ++ "undefined 7", ++ "undefined 8", ++ "undefined 9", ++ "undefined 10", ++ "undefined 11", ++ "undefined 12", ++ "undefined 13", ++ "undefined 14", ++ "undefined 15" ++}; ++ ++static void ++c_show_cache(struct seq_file *m, const char *type, unsigned int cache) ++{ ++ unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0); ++ ++ seq_printf(m, "%s size\t\t: %d\n" ++ "%s assoc\t\t: %d\n" ++ "%s line length\t: %d\n" ++ "%s sets\t\t: %d\n", ++ type, mult << (8 + CACHE_SIZE(cache)), ++ type, (mult << CACHE_ASSOC(cache)) >> 1, ++ type, 8 << CACHE_LINE(cache), ++ type, 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) - ++ CACHE_LINE(cache))); ++} ++ + static int c_show(struct seq_file *m, void *v) + { + int i; +@@ -586,7 +737,60 @@ + if (elf_hwcap & (1 << i)) + seq_printf(m, "%s ", hwcap_str[i]); + +- seq_puts(m, "\n\n"); ++ seq_puts(m, "\n"); ++ ++ if ((processor_id & 0x0000f000) == 0x00000000) { ++ /* pre-ARM7 */ ++ seq_printf(m, "CPU part\t\t: %07x\n", processor_id >> 4); ++ } else if ((processor_id & 0x0000f000) == 0x00007000) { ++ /* ARM7 */ ++ seq_printf(m, "CPU implementor\t: 0x%02x\n" ++ "CPU architecture: %s\n" ++ "CPU variant\t: 0x%02x\n" ++ "CPU part\t: 0x%03x\n", ++ processor_id >> 24, ++ processor_id & (1 << 23) ? "4T" : "3", ++ (processor_id >> 16) & 127, ++ (processor_id >> 4) & 0xfff); ++ } else { ++ /* post-ARM7 */ ++ seq_printf(m, "CPU implementor\t: 0x%02x\n" ++ "CPU architecture: %s\n" ++ "CPU variant\t: 0x%x\n" ++ "CPU part\t: 0x%03x\n", ++ processor_id >> 24, ++ proc_arch[(processor_id >> 16) & 15], ++ (processor_id >> 20) & 15, ++ (processor_id >> 4) & 0xfff); ++ } ++ seq_printf(m, "CPU revision\t: %d\n", processor_id & 15); ++ ++#ifdef CONFIG_CPU_32 ++ { ++ unsigned int cache_info; ++ ++ asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (cache_info)); ++ if (cache_info != processor_id) { ++ seq_printf(m, "Cache type\t: %s\n" ++ "Cache clean\t: %s\n" ++ "Cache lockdown\t: %s\n" ++ "Cache unified\t: %s\n", ++ cache_types[CACHE_TYPE(cache_info)], ++ cache_clean[CACHE_TYPE(cache_info)], ++ cache_lockdown[CACHE_TYPE(cache_info)], ++ CACHE_S(cache_info) ? "harvard" : "unified"); ++ ++ if (CACHE_S(cache_info)) { ++ c_show_cache(m, "I", CACHE_ISIZE(cache_info)); ++ c_show_cache(m, "D", CACHE_DSIZE(cache_info)); ++ } else { ++ c_show_cache(m, "Cache", CACHE_ISIZE(cache_info)); ++ } ++ } ++ } ++#endif ++ ++ seq_puts(m, "\n"); + + seq_printf(m, "Hardware\t: %s\n", machine_name); + seq_printf(m, "Revision\t: %04x\n", system_rev); +--- linux-2.4.25/arch/arm/lib/copy_page.S~2.4.25-vrs2-pxa1.patch 2001-03-07 04:44:35.000000000 +0100 ++++ linux-2.4.25/arch/arm/lib/copy_page.S 2004-03-31 17:15:11.000000000 +0200 +@@ -13,6 +13,8 @@ + #include <asm/assembler.h> + #include <asm/constants.h> + ++#define COPY_COUNT (PAGE_SZ/64 PLD( -1 )) ++ + .text + .align 5 + /* +@@ -23,9 +25,13 @@ + */ + ENTRY(copy_page) + stmfd sp!, {r4, lr} @ 2 +- mov r2, #PAGE_SZ/64 @ 1 ++ PLD( pld [r1, #0] ) ++ PLD( pld [r1, #32] ) ++ mov r2, #COPY_COUNT @ 1 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 +-1: stmia r0!, {r3, r4, ip, lr} @ 4 ++1: PLD( pld [r1, #64] ) ++ PLD( pld [r1, #96] ) ++2: stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 +@@ -33,6 +39,8 @@ + ldmia r1!, {r3, r4, ip, lr} @ 4 + subs r2, r2, #1 @ 1 + stmia r0!, {r3, r4, ip, lr} @ 4 +- ldmneia r1!, {r3, r4, ip, lr} @ 4 +- bne 1b @ 1 ++ ldmgtia r1!, {r3, r4, ip, lr} @ 4 ++ bgt 1b @ 1 ++ PLD( ldmeqia r1!, {r3, r4, ip, lr} ) ++ PLD( beq 2b ) + LOADREGS(fd, sp!, {r4, pc}) @ 3 +--- linux-2.4.25/arch/arm/lib/findbit.S~2.4.25-vrs2-pxa1.patch 2000-09-19 00:15:25.000000000 +0200 ++++ linux-2.4.25/arch/arm/lib/findbit.S 2004-03-31 17:15:11.000000000 +0200 +@@ -43,7 +43,15 @@ + /* + * One or more bits in the LSB of r3 are assumed to be set. + */ +-.found: tst r3, #0x0f ++.found: ++#if __LINUX_ARM_ARCH__ >= 5 ++ rsb r1, r3, #0 ++ and r3, r3, r1 ++ clz r3, r3 ++ rsb r3, r3, #31 ++ add r0, r2, r3 ++#else ++ tst r3, #0x0f + addeq r2, r2, #4 + movne r3, r3, lsl #4 + tst r3, #0x30 +@@ -52,5 +60,6 @@ + tst r3, #0x40 + addeq r2, r2, #1 + mov r0, r2 ++#endif + RETINSTR(mov,pc,lr) + +--- linux-2.4.25/arch/arm/lib/getuser.S~2.4.25-vrs2-pxa1.patch 2002-08-03 02:39:42.000000000 +0200 ++++ linux-2.4.25/arch/arm/lib/getuser.S 2004-03-31 17:15:11.000000000 +0200 +@@ -18,7 +18,7 @@ + * Inputs: r0 contains the address + * Outputs: r0 is the error code + * r1, r2 contains the zero-extended value +- * lr corrupted ++ * ip, lr corrupted + * + * No other registers must be altered. (see include/asm-arm/uaccess.h + * for specific ASM register usage). +@@ -42,14 +42,14 @@ + + .global __get_user_2 + __get_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: ldrlsbt r1, [r0], #1 +-3: ldrlsbt r2, [r0] +- orrls r1, r1, r2, lsl #8 ++3: ldrlsbt ip, [r0] ++ orrls r1, r1, ip, lsl #8 + movls r0, #0 + movls pc, lr + b __get_user_bad +--- linux-2.4.25/arch/arm/lib/memcpy.S~2.4.25-vrs2-pxa1.patch 2001-03-07 04:44:35.000000000 +0100 ++++ linux-2.4.25/arch/arm/lib/memcpy.S 2004-03-31 17:15:11.000000000 +0200 +@@ -8,6 +8,9 @@ + * published by the Free Software Foundation. + * + * ASM optimised string functions ++ * ++ * Big Endian, prefetching and code factorization provided by Nicolas Pitre: ++ * Copyright (C) 2002-2003 MontaVista Software, Inc. + */ + #include <linux/linkage.h> + #include <asm/assembler.h> +@@ -27,15 +30,16 @@ + + /* + * Prototype: void memcpy(void *to,const void *from,unsigned long n); +- * ARM3: cant use memcopy here!!! + */ + ENTRY(memcpy) + ENTRY(memmove) + ENTER +- cmp r1, r0 +- bcc 19f ++ subs ip, r0, r1 ++ cmphi r2, ip ++ bhi 18f + subs r2, r2, #4 + blt 6f ++ PLD( pld [r1, #0] ) + ands ip, r0, #3 + bne 7f + ands ip, r1, #3 +@@ -43,29 +47,59 @@ + + 1: subs r2, r2, #8 + blt 5f +- subs r2, r2, #0x14 +- blt 3f +-2: ldmia r1!,{r3 - r9, ip} +- stmia r0!,{r3 - r9, ip} ++ subs r2, r2, #20 ++ blt 4f ++ ++ PLD( subs r2, r2, #65 ) ++ PLD( blt 3f ) ++ PLD( pld [r1, #32] ) ++ ++ PLD( @ cache alignment ) ++ PLD( ands ip, r1, #31 ) ++ PLD( pld [r1, #64] ) ++ PLD( beq 2f ) ++ PLD( rsb ip, ip, #32 ) ++ PLD( cmp r2, ip ) ++ PLD( pld [r1, #96] ) ++ PLD( blt 2f ) ++ PLD( cmp ip, #16 ) ++ PLD( sub r2, r2, ip ) ++ PLD( ldmgeia r1!, {r3 - r6} ) ++ PLD( stmgeia r0!, {r3 - r6} ) ++ PLD( beq 2f ) ++ PLD( and ip, ip, #15 ) ++ PLD( cmp ip, #8 ) ++ PLD( ldr r3, [r1], #4 ) ++ PLD( ldrge r4, [r1], #4 ) ++ PLD( ldrgt r5, [r1], #4 ) ++ PLD( str r3, [r0], #4 ) ++ PLD( strge r4, [r0], #4 ) ++ PLD( strgt r5, [r0], #4 ) ++ ++2: PLD( pld [r1, #96] ) ++3: ldmia r1!, {r3 - r9, ip} + subs r2, r2, #32 ++ stmia r0!, {r3 - r9, ip} + bge 2b +- cmn r2, #16 ++ PLD( cmn r2, #65 ) ++ PLD( bge 3b ) ++ PLD( add r2, r2, #65 ) ++4: cmn r2, #16 + ldmgeia r1!, {r3 - r6} ++ subge r2, r2, #16 + stmgeia r0!, {r3 - r6} +- subge r2, r2, #0x10 +-3: adds r2, r2, #0x14 +-4: ldmgeia r1!, {r3 - r5} ++ adds r2, r2, #20 ++ ldmgeia r1!, {r3 - r5} ++ subge r2, r2, #12 + stmgeia r0!, {r3 - r5} +- subges r2, r2, #12 +- bge 4b + 5: adds r2, r2, #8 + blt 6f + subs r2, r2, #4 + ldrlt r3, [r1], #4 + ldmgeia r1!, {r4, r5} ++ subge r2, r2, #4 + strlt r3, [r0], #4 + stmgeia r0!, {r4, r5} +- subge r2, r2, #4 + + 6: adds r2, r2, #4 + EXITEQ +@@ -92,122 +126,175 @@ + beq 1b + + 8: bic r1, r1, #3 +- ldr r7, [r1], #4 + cmp ip, #2 +- bgt 15f +- beq 11f ++ ldr lr, [r1], #4 ++ bgt 17f ++ beq 16f ++ ++ ++ .macro forward_copy_shift pull push ++ + cmp r2, #12 +- blt 10f +- sub r2, r2, #12 +-9: mov r3, r7, lsr #8 +- ldmia r1!, {r4 - r7} +- orr r3, r3, r4, lsl #24 +- mov r4, r4, lsr #8 +- orr r4, r4, r5, lsl #24 +- mov r5, r5, lsr #8 +- orr r5, r5, r6, lsl #24 +- mov r6, r6, lsr #8 +- orr r6, r6, r7, lsl #24 ++ PLD( pld [r1, #0] ) ++ blt 14f ++ subs r2, r2, #28 ++ blt 12f ++ ++ PLD( subs r2, r2, #97 ) ++ PLD( blt 11f ) ++ PLD( pld [r1, #32] ) ++ ++ PLD( @ cache alignment ) ++ PLD( rsb ip, r1, #36 ) ++ PLD( pld [r1, #64] ) ++ PLD( ands ip, ip, #31 ) ++ PLD( pld [r1, #96] ) ++ PLD( beq 10f ) ++ PLD( cmp r2, ip ) ++ PLD( pld [r1, #128] ) ++ PLD( blt 10f ) ++ PLD( sub r2, r2, ip ) ++9: PLD( mov r3, lr, pull #\pull ) ++ PLD( ldr lr, [r1], #4 ) ++ PLD( subs ip, ip, #4 ) ++ PLD( orr r3, r3, lr, push #\push ) ++ PLD( str r3, [r0], #4 ) ++ PLD( bgt 9b ) ++ ++10: PLD( pld [r1, #128] ) ++11: mov r3, lr, pull #\pull ++ ldmia r1!, {r4 - r9, ip, lr} ++ subs r2, r2, #32 ++ orr r3, r3, r4, push #\push ++ mov r4, r4, pull #\pull ++ orr r4, r4, r5, push #\push ++ mov r5, r5, pull #\pull ++ orr r5, r5, r6, push #\push ++ mov r6, r6, pull #\pull ++ orr r6, r6, r7, push #\push ++ mov r7, r7, pull #\pull ++ orr r7, r7, r8, push #\push ++ mov r8, r8, pull #\pull ++ orr r8, r8, r9, push #\push ++ mov r9, r9, pull #\pull ++ orr r9, r9, ip, push #\push ++ mov ip, ip, pull #\pull ++ orr ip, ip, lr, push #\push ++ stmia r0!, {r3 - r9, ip} ++ bge 10b ++ PLD( cmn r2, #97 ) ++ PLD( bge 11b ) ++ PLD( add r2, r2, #97 ) ++ cmn r2, #16 ++ blt 13f ++12: mov r3, lr, pull #\pull ++ ldmia r1!, {r4 - r6, lr} ++ sub r2, r2, #16 ++ orr r3, r3, r4, push #\push ++ mov r4, r4, pull #\pull ++ orr r4, r4, r5, push #\push ++ mov r5, r5, pull #\pull ++ orr r5, r5, r6, push #\push ++ mov r6, r6, pull #\pull ++ orr r6, r6, lr, push #\push + stmia r0!, {r3 - r6} +- subs r2, r2, #16 +- bge 9b +- adds r2, r2, #12 +- blt 100f +-10: mov r3, r7, lsr #8 +- ldr r7, [r1], #4 ++13: adds r2, r2, #28 ++ blt 15f ++14: mov r3, lr, pull #\pull ++ ldr lr, [r1], #4 + subs r2, r2, #4 +- orr r3, r3, r7, lsl #24 ++ orr r3, r3, lr, push #\push + str r3, [r0], #4 +- bge 10b +-100: sub r1, r1, #3 ++ bge 14b ++15: ++ .endm ++ ++ ++ forward_copy_shift pull=8 push=24 ++ sub r1, r1, #3 + b 6b + +-11: cmp r2, #12 +- blt 13f /* */ +- sub r2, r2, #12 +-12: mov r3, r7, lsr #16 +- ldmia r1!, {r4 - r7} +- orr r3, r3, r4, lsl #16 +- mov r4, r4, lsr #16 +- orr r4, r4, r5, lsl #16 +- mov r5, r5, lsr #16 +- orr r5, r5, r6, lsl #16 +- mov r6, r6, lsr #16 +- orr r6, r6, r7,LSL#16 +- stmia r0!, {r3 - r6} +- subs r2, r2, #16 +- bge 12b +- adds r2, r2, #12 +- blt 14f +-13: mov r3, r7, lsr #16 +- ldr r7, [r1], #4 +- subs r2, r2, #4 +- orr r3, r3, r7, lsl #16 +- str r3, [r0], #4 +- bge 13b +-14: sub r1, r1, #2 ++16: forward_copy_shift pull=16 push=16 ++ sub r1, r1, #2 + b 6b + +-15: cmp r2, #12 +- blt 17f +- sub r2, r2, #12 +-16: mov r3, r7, lsr #24 +- ldmia r1!,{r4 - r7} +- orr r3, r3, r4, lsl #8 +- mov r4, r4, lsr #24 +- orr r4, r4, r5, lsl #8 +- mov r5, r5, lsr #24 +- orr r5, r5, r6, lsl #8 +- mov r6, r6, lsr #24 +- orr r6, r6, r7, lsl #8 +- stmia r0!, {r3 - r6} +- subs r2, r2, #16 +- bge 16b +- adds r2, r2, #12 +- blt 18f +-17: mov r3, r7, lsr #24 +- ldr r7, [r1], #4 +- subs r2, r2, #4 +- orr r3, r3, r7, lsl#8 +- str r3, [r0], #4 +- bge 17b +-18: sub r1, r1, #1 ++17: forward_copy_shift pull=24 push=8 ++ sub r1, r1, #1 + b 6b + + +-19: add r1, r1, r2 ++18: add r1, r1, r2 + add r0, r0, r2 + subs r2, r2, #4 + blt 24f ++ PLD( pld [r1, #-4] ) + ands ip, r0, #3 + bne 25f + ands ip, r1, #3 + bne 26f + +-20: subs r2, r2, #8 ++19: subs r2, r2, #8 + blt 23f +- subs r2, r2, #0x14 ++ subs r2, r2, #20 + blt 22f +-21: ldmdb r1!, {r3 - r9, ip} +- stmdb r0!, {r3 - r9, ip} ++ ++ PLD( subs r2, r2, #96 ) ++ PLD( pld [r1, #-32] ) ++ PLD( blt 21f ) ++ ++ PLD( @ cache alignment ) ++ PLD( ands ip, r1, #31 ) ++ PLD( pld [r1, #-64] ) ++ PLD( beq 20f ) ++ PLD( cmp r2, ip ) ++ PLD( pld [r1, #-96] ) ++ PLD( blt 20f ) ++ PLD( cmp ip, #16 ) ++ PLD( sub r2, r2, ip ) ++ PLD( ldmgedb r1!, {r3 - r6} ) ++ PLD( stmgedb r0!, {r3 - r6} ) ++ PLD( beq 20f ) ++ PLD( and ip, ip, #15 ) ++ PLD( cmp ip, #8 ) ++ PLD( ldr r3, [r1, #-4]! ) ++ PLD( ldrge r4, [r1, #-4]! ) ++ PLD( ldrgt r5, [r1, #-4]! ) ++ PLD( str r3, [r0, #-4]! ) ++ PLD( strge r4, [r0, #-4]! ) ++ PLD( strgt r5, [r0, #-4]! ) ++ ++20: PLD( pld [r1, #-96] ) ++ PLD( pld [r1, #-128] ) ++21: ldmdb r1!, {r3 - r6} + subs r2, r2, #32 +- bge 21b +-22: cmn r2, #16 ++ stmdb r0!, {r3 - r6} ++ ldmdb r1!, {r3 - r6} ++ stmgedb r0!, {r3 - r6} + ldmgedb r1!, {r3 - r6} + stmgedb r0!, {r3 - r6} ++ ldmgedb r1!, {r3 - r6} ++ subges r2, r2, #32 ++ stmdb r0!, {r3 - r6} ++ bge 20b ++ PLD( cmn r2, #96 ) ++ PLD( bge 21b ) ++ PLD( add r2, r2, #96 ) ++22: cmn r2, #16 ++ ldmgedb r1!, {r3 - r6} + subge r2, r2, #16 ++ stmgedb r0!, {r3 - r6} + adds r2, r2, #20 + ldmgedb r1!, {r3 - r5} +- stmgedb r0!, {r3 - r5} + subge r2, r2, #12 ++ stmgedb r0!, {r3 - r5} + 23: adds r2, r2, #8 + blt 24f + subs r2, r2, #4 + ldrlt r3, [r1, #-4]! + ldmgedb r1!, {r4, r5} ++ subge r2, r2, #4 + strlt r3, [r0, #-4]! + stmgedb r0!, {r4, r5} +- subge r2, r2, #4 + + 24: adds r2, r2, #4 + EXITEQ +@@ -230,89 +317,101 @@ + subs r2, r2, ip + blt 24b + ands ip, r1, #3 +- beq 20b ++ beq 19b + + 26: bic r1, r1, #3 +- ldr r3, [r1], #0 + cmp ip, #2 +- blt 34f +- beq 30f +- cmp r2, #12 +- blt 28f +- sub r2, r2, #12 +-27: mov r7, r3, lsl #8 +- ldmdb r1!, {r3, r4, r5, r6} +- orr r7, r7, r6, lsr #24 +- mov r6, r6, lsl #8 +- orr r6, r6, r5, lsr #24 +- mov r5, r5, lsl #8 +- orr r5, r5, r4, lsr #24 +- mov r4, r4, lsl #8 +- orr r4, r4, r3, lsr #24 +- stmdb r0!, {r4, r5, r6, r7} +- subs r2, r2, #16 +- bge 27b +- adds r2, r2, #12 +- blt 29f +-28: mov ip, r3, lsl #8 +- ldr r3, [r1, #-4]! +- subs r2, r2, #4 +- orr ip, ip, r3, lsr #24 +- str ip, [r0, #-4]! +- bge 28b +-29: add r1, r1, #3 +- b 24b ++ ldr r3, [r1], #0 ++ blt 35f ++ beq 34f + +-30: cmp r2, #12 ++ ++ .macro backward_copy_shift push pull ++ ++ cmp r2, #12 ++ PLD( pld [r1, #-4] ) + blt 32f +- sub r2, r2, #12 +-31: mov r7, r3, lsl #16 +- ldmdb r1!, {r3, r4, r5, r6} +- orr r7, r7, r6, lsr #16 +- mov r6, r6, lsl #16 +- orr r6, r6, r5, lsr #16 +- mov r5, r5, lsl #16 +- orr r5, r5, r4, lsr #16 +- mov r4, r4, lsl #16 +- orr r4, r4, r3, lsr #16 +- stmdb r0!, {r4, r5, r6, r7} +- subs r2, r2, #16 +- bge 31b +- adds r2, r2, #12 ++ subs r2, r2, #28 ++ blt 30f ++ ++ PLD( subs r2, r2, #96 ) ++ PLD( pld [r1, #-32] ) ++ PLD( blt 29f ) ++ PLD( pld [r1, #-64] ) ++ ++ PLD( @ cache alignment ) ++ PLD( ands ip, r1, #31 ) ++ PLD( pld [r1, #-96] ) ++ PLD( beq 28f ) ++ PLD( cmp r2, ip ) ++ PLD( pld [r1, #-128] ) ++ PLD( blt 28f ) ++ PLD( sub r2, r2, ip ) ++27: PLD( mov r4, r3, push #\push ) ++ PLD( ldr r3, [r1, #-4]! ) ++ PLD( subs ip, ip, #4 ) ++ PLD( orr r4, r4, r3, pull #\pull ) ++ PLD( str r4, [r0, #-4]! ) ++ PLD( bgt 27b ) ++ ++28: PLD( pld [r1, #-128] ) ++29: mov lr, r3, push #\push ++ ldmdb r1!, {r3 - r9, ip} ++ subs r2, r2, #32 ++ orr lr, lr, ip, pull #\pull ++ mov ip, ip, push #\push ++ orr ip, ip, r9, pull #\pull ++ mov r9, r9, push #\push ++ orr r9, r9, r8, pull #\pull ++ mov r8, r8, push #\push ++ orr r8, r8, r7, pull #\pull ++ mov r7, r7, push #\push ++ orr r7, r7, r6, pull #\pull ++ mov r6, r6, push #\push ++ orr r6, r6, r5, pull #\pull ++ mov r5, r5, push #\push ++ orr r5, r5, r4, pull #\pull ++ mov r4, r4, push #\push ++ orr r4, r4, r3, pull #\pull ++ stmdb r0!, {r4 - r9, ip, lr} ++ bge 28b ++ PLD( cmn r2, #96 ) ++ PLD( bge 29b ) ++ PLD( add r2, r2, #96 ) ++ cmn r2, #16 ++ blt 31f ++30: mov r7, r3, push #\push ++ ldmdb r1!, {r3 - r6} ++ sub r2, r2, #16 ++ orr r7, r7, r6, pull #\pull ++ mov r6, r6, push #\push ++ orr r6, r6, r5, pull #\pull ++ mov r5, r5, push #\push ++ orr r5, r5, r4, pull #\pull ++ mov r4, r4, push #\push ++ orr r4, r4, r3, pull #\pull ++ stmdb r0!, {r4 - r7} ++31: adds r2, r2, #28 + blt 33f +-32: mov ip, r3, lsl #16 ++32: mov r4, r3, push #\push + ldr r3, [r1, #-4]! + subs r2, r2, #4 +- orr ip, ip, r3, lsr #16 +- str ip, [r0, #-4]! ++ orr r4, r4, r3, pull #\pull ++ str r4, [r0, #-4]! + bge 32b +-33: add r1, r1, #2 ++33: ++ .endm ++ ++ ++ backward_copy_shift push=8 pull=24 ++ add r1, r1, #3 + b 24b + +-34: cmp r2, #12 +- blt 36f +- sub r2, r2, #12 +-35: mov r7, r3, lsl #24 +- ldmdb r1!, {r3, r4, r5, r6} +- orr r7, r7, r6, lsr #8 +- mov r6, r6, lsl #24 +- orr r6, r6, r5, lsr #8 +- mov r5, r5, lsl #24 +- orr r5, r5, r4, lsr #8 +- mov r4, r4, lsl #24 +- orr r4, r4, r3, lsr #8 +- stmdb r0!, {r4, r5, r6, r7} +- subs r2, r2, #16 +- bge 35b +- adds r2, r2, #12 +- blt 37f +-36: mov ip, r3, lsl #24 +- ldr r3, [r1, #-4]! +- subs r2, r2, #4 +- orr ip, ip, r3, lsr #8 +- str ip, [r0, #-4]! +- bge 36b +-37: add r1, r1, #1 ++34: backward_copy_shift push=16 pull=16 ++ add r1, r1, #2 ++ b 24b ++ ++35: backward_copy_shift push=24 pull=8 ++ add r1, r1, #1 + b 24b + +- .align +--- linux-2.4.25/arch/arm/lib/uaccess.S~2.4.25-vrs2-pxa1.patch 2000-09-19 00:15:25.000000000 +0200 ++++ linux-2.4.25/arch/arm/lib/uaccess.S 2004-03-31 17:15:11.000000000 +0200 +@@ -43,6 +43,8 @@ + stmfd sp!, {r2, r4 - r7, lr} + cmp r2, #4 + blt .c2u_not_enough ++ PLD( pld [r1, #0] ) ++ PLD( pld [r0, #0] ) + ands ip, r0, #3 + bne .c2u_dest_not_aligned + .c2u_dest_aligned: +@@ -71,13 +73,26 @@ + sub r2, r2, ip + subs ip, ip, #32 + blt .c2u_0rem8lp ++ PLD( pld [r1, #28] ) ++ PLD( pld [r0, #28] ) ++ PLD( subs ip, ip, #64 ) ++ PLD( blt .c2u_0cpynopld ) ++ PLD( pld [r1, #60] ) ++ PLD( pld [r0, #60] ) + +-.c2u_0cpy8lp: ldmia r1!, {r3 - r6} ++.c2u_0cpy8lp: ++ PLD( pld [r1, #92] ) ++ PLD( pld [r0, #92] ) ++.c2u_0cpynopld: ldmia r1!, {r3 - r6} + stmia r0!, {r3 - r6} @ Shouldnt fault + ldmia r1!, {r3 - r6} +- stmia r0!, {r3 - r6} @ Shouldnt fault + subs ip, ip, #32 ++ stmia r0!, {r3 - r6} @ Shouldnt fault + bpl .c2u_0cpy8lp ++ PLD( cmn ip, #64 ) ++ PLD( bge .c2u_0cpynopld ) ++ PLD( add ip, ip, #64 ) ++ + .c2u_0rem8lp: cmn ip, #16 + ldmgeia r1!, {r3 - r6} + stmgeia r0!, {r3 - r6} @ Shouldnt fault +@@ -115,9 +130,9 @@ + .c2u_1fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .c2u_1nowords +- mov r3, r7, lsr #8 ++ mov r3, r7, pull #8 + ldr r7, [r1], #4 +- orr r3, r3, r7, lsl #24 ++ orr r3, r3, r7, push #24 + USER( strt r3, [r0], #4) @ May fault + mov ip, r0, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 +@@ -128,50 +143,63 @@ + sub r2, r2, ip + subs ip, ip, #16 + blt .c2u_1rem8lp ++ PLD( pld [r1, #12] ) ++ PLD( pld [r0, #12] ) ++ PLD( subs ip, ip, #32 ) ++ PLD( blt .c2u_1cpynopld ) ++ PLD( pld [r1, #28] ) ++ PLD( pld [r0, #28] ) + +-.c2u_1cpy8lp: mov r3, r7, lsr #8 ++.c2u_1cpy8lp: ++ PLD( pld [r1, #44] ) ++ PLD( pld [r0, #44] ) ++.c2u_1cpynopld: mov r3, r7, pull #8 + ldmia r1!, {r4 - r7} +- orr r3, r3, r4, lsl #24 +- mov r4, r4, lsr #8 +- orr r4, r4, r5, lsl #24 +- mov r5, r5, lsr #8 +- orr r5, r5, r6, lsl #24 +- mov r6, r6, lsr #8 +- orr r6, r6, r7, lsl #24 +- stmia r0!, {r3 - r6} @ Shouldnt fault + subs ip, ip, #16 ++ orr r3, r3, r4, push #24 ++ mov r4, r4, pull #8 ++ orr r4, r4, r5, push #24 ++ mov r5, r5, pull #8 ++ orr r5, r5, r6, push #24 ++ mov r6, r6, pull #8 ++ orr r6, r6, r7, push #24 ++ stmia r0!, {r3 - r6} @ Shouldnt fault + bpl .c2u_1cpy8lp ++ PLD( cmn ip, #32 ) ++ PLD( bge .c2u_1cpynopld ) ++ PLD( add ip, ip, #32 ) ++ + .c2u_1rem8lp: tst ip, #8 +- movne r3, r7, lsr #8 ++ movne r3, r7, pull #8 + ldmneia r1!, {r4, r7} +- orrne r3, r3, r4, lsl #24 +- movne r4, r4, lsr #8 +- orrne r4, r4, r7, lsl #24 ++ orrne r3, r3, r4, push #24 ++ movne r4, r4, pull #8 ++ orrne r4, r4, r7, push #24 + stmneia r0!, {r3 - r4} @ Shouldnt fault + tst ip, #4 +- movne r3, r7, lsr #8 ++ movne r3, r7, pull #8 + ldrne r7, [r1], #4 +- orrne r3, r3, r7, lsl #24 ++ orrne r3, r3, r7, push #24 + strnet r3, [r0], #4 @ Shouldnt fault + ands ip, ip, #3 + beq .c2u_1fupi +-.c2u_1nowords: mov r3, r7, lsr #8 ++.c2u_1nowords: mov r3, r7, lsr #byte(1) + teq ip, #0 + beq .c2u_finished + cmp ip, #2 + USER( strbt r3, [r0], #1) @ May fault +- movge r3, r3, lsr #8 ++ movge r3, r7, lsr #byte(2) + USER( strgebt r3, [r0], #1) @ May fault +- movgt r3, r3, lsr #8 ++ movgt r3, r7, lsr #byte(3) + USER( strgtbt r3, [r0], #1) @ May fault + b .c2u_finished + + .c2u_2fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .c2u_2nowords +- mov r3, r7, lsr #16 ++ mov r3, r7, pull #16 + ldr r7, [r1], #4 +- orr r3, r3, r7, lsl #16 ++ orr r3, r3, r7, push #16 + USER( strt r3, [r0], #4) @ May fault + mov ip, r0, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 +@@ -182,39 +210,52 @@ + sub r2, r2, ip + subs ip, ip, #16 + blt .c2u_2rem8lp ++ PLD( pld [r1, #12] ) ++ PLD( pld [r0, #12] ) ++ PLD( subs ip, ip, #32 ) ++ PLD( blt .c2u_2cpynopld ) ++ PLD( pld [r1, #28] ) ++ PLD( pld [r0, #28] ) + +-.c2u_2cpy8lp: mov r3, r7, lsr #16 ++.c2u_2cpy8lp: ++ PLD( pld [r1, #44] ) ++ PLD( pld [r0, #44] ) ++.c2u_2cpynopld: mov r3, r7, pull #16 + ldmia r1!, {r4 - r7} +- orr r3, r3, r4, lsl #16 +- mov r4, r4, lsr #16 +- orr r4, r4, r5, lsl #16 +- mov r5, r5, lsr #16 +- orr r5, r5, r6, lsl #16 +- mov r6, r6, lsr #16 +- orr r6, r6, r7, lsl #16 +- stmia r0!, {r3 - r6} @ Shouldnt fault + subs ip, ip, #16 ++ orr r3, r3, r4, push #16 ++ mov r4, r4, pull #16 ++ orr r4, r4, r5, push #16 ++ mov r5, r5, pull #16 ++ orr r5, r5, r6, push #16 ++ mov r6, r6, pull #16 ++ orr r6, r6, r7, push #16 ++ stmia r0!, {r3 - r6} @ Shouldnt fault + bpl .c2u_2cpy8lp ++ PLD( cmn ip, #32 ) ++ PLD( bge .c2u_2cpynopld ) ++ PLD( add ip, ip, #32 ) ++ + .c2u_2rem8lp: tst ip, #8 +- movne r3, r7, lsr #16 ++ movne r3, r7, pull #16 + ldmneia r1!, {r4, r7} +- orrne r3, r3, r4, lsl #16 +- movne r4, r4, lsr #16 +- orrne r4, r4, r7, lsl #16 ++ orrne r3, r3, r4, push #16 ++ movne r4, r4, pull #16 ++ orrne r4, r4, r7, push #16 + stmneia r0!, {r3 - r4} @ Shouldnt fault + tst ip, #4 +- movne r3, r7, lsr #16 ++ movne r3, r7, pull #16 + ldrne r7, [r1], #4 +- orrne r3, r3, r7, lsl #16 ++ orrne r3, r3, r7, push #16 + strnet r3, [r0], #4 @ Shouldnt fault + ands ip, ip, #3 + beq .c2u_2fupi +-.c2u_2nowords: mov r3, r7, lsr #16 ++.c2u_2nowords: mov r3, r7, lsr #byte(2) + teq ip, #0 + beq .c2u_finished + cmp ip, #2 + USER( strbt r3, [r0], #1) @ May fault +- movge r3, r3, lsr #8 ++ movge r3, r7, lsr #byte(3) + USER( strgebt r3, [r0], #1) @ May fault + ldrgtb r3, [r1], #0 + USER( strgtbt r3, [r0], #1) @ May fault +@@ -223,9 +264,9 @@ + .c2u_3fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .c2u_3nowords +- mov r3, r7, lsr #24 ++ mov r3, r7, pull #24 + ldr r7, [r1], #4 +- orr r3, r3, r7, lsl #8 ++ orr r3, r3, r7, push #8 + USER( strt r3, [r0], #4) @ May fault + mov ip, r0, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 +@@ -236,41 +277,54 @@ + sub r2, r2, ip + subs ip, ip, #16 + blt .c2u_3rem8lp ++ PLD( pld [r1, #12] ) ++ PLD( pld [r0, #12] ) ++ PLD( subs ip, ip, #32 ) ++ PLD( blt .c2u_3cpynopld ) ++ PLD( pld [r1, #28] ) ++ PLD( pld [r0, #28] ) + +-.c2u_3cpy8lp: mov r3, r7, lsr #24 ++.c2u_3cpy8lp: ++ PLD( pld [r1, #44] ) ++ PLD( pld [r0, #44] ) ++.c2u_3cpynopld: mov r3, r7, pull #24 + ldmia r1!, {r4 - r7} +- orr r3, r3, r4, lsl #8 +- mov r4, r4, lsr #24 +- orr r4, r4, r5, lsl #8 +- mov r5, r5, lsr #24 +- orr r5, r5, r6, lsl #8 +- mov r6, r6, lsr #24 +- orr r6, r6, r7, lsl #8 +- stmia r0!, {r3 - r6} @ Shouldnt fault + subs ip, ip, #16 ++ orr r3, r3, r4, push #8 ++ mov r4, r4, pull #24 ++ orr r4, r4, r5, push #8 ++ mov r5, r5, pull #24 ++ orr r5, r5, r6, push #8 ++ mov r6, r6, pull #24 ++ orr r6, r6, r7, push #8 ++ stmia r0!, {r3 - r6} @ Shouldnt fault + bpl .c2u_3cpy8lp ++ PLD( cmn ip, #32 ) ++ PLD( bge .c2u_3cpynopld ) ++ PLD( add ip, ip, #32 ) ++ + .c2u_3rem8lp: tst ip, #8 +- movne r3, r7, lsr #24 ++ movne r3, r7, pull #24 + ldmneia r1!, {r4, r7} +- orrne r3, r3, r4, lsl #8 +- movne r4, r4, lsr #24 +- orrne r4, r4, r7, lsl #8 ++ orrne r3, r3, r4, push #8 ++ movne r4, r4, pull #24 ++ orrne r4, r4, r7, push #8 + stmneia r0!, {r3 - r4} @ Shouldnt fault + tst ip, #4 +- movne r3, r7, lsr #24 ++ movne r3, r7, pull #24 + ldrne r7, [r1], #4 +- orrne r3, r3, r7, lsl #8 ++ orrne r3, r3, r7, push #8 + strnet r3, [r0], #4 @ Shouldnt fault + ands ip, ip, #3 + beq .c2u_3fupi +-.c2u_3nowords: mov r3, r7, lsr #24 ++.c2u_3nowords: mov r3, r7, lsr #byte(3) + teq ip, #0 + beq .c2u_finished + cmp ip, #2 + USER( strbt r3, [r0], #1) @ May fault +- ldrge r3, [r1], #0 ++ ldrgeb r3, [r1], #1 + USER( strgebt r3, [r0], #1) @ May fault +- movgt r3, r3, lsr #8 ++ ldrgtb r3, [r1], #0 + USER( strgtbt r3, [r0], #1) @ May fault + b .c2u_finished + +@@ -302,6 +356,8 @@ + stmfd sp!, {r0, r2, r4 - r7, lr} + cmp r2, #4 + blt .cfu_not_enough ++ PLD( pld [r1, #0] ) ++ PLD( pld [r0, #0] ) + ands ip, r0, #3 + bne .cfu_dest_not_aligned + .cfu_dest_aligned: +@@ -329,13 +385,26 @@ + sub r2, r2, ip + subs ip, ip, #32 + blt .cfu_0rem8lp ++ PLD( pld [r1, #28] ) ++ PLD( pld [r0, #28] ) ++ PLD( subs ip, ip, #64 ) ++ PLD( blt .cfu_0cpynopld ) ++ PLD( pld [r1, #60] ) ++ PLD( pld [r0, #60] ) + +-.cfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault ++.cfu_0cpy8lp: ++ PLD( pld [r1, #92] ) ++ PLD( pld [r0, #92] ) ++.cfu_0cpynopld: ldmia r1!, {r3 - r6} @ Shouldnt fault + stmia r0!, {r3 - r6} + ldmia r1!, {r3 - r6} @ Shouldnt fault +- stmia r0!, {r3 - r6} + subs ip, ip, #32 ++ stmia r0!, {r3 - r6} + bpl .cfu_0cpy8lp ++ PLD( cmn ip, #64 ) ++ PLD( bge .cfu_0cpynopld ) ++ PLD( add ip, ip, #64 ) ++ + .cfu_0rem8lp: cmn ip, #16 + ldmgeia r1!, {r3 - r6} @ Shouldnt fault + stmgeia r0!, {r3 - r6} +@@ -374,9 +443,9 @@ + .cfu_1fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .cfu_1nowords +- mov r3, r7, lsr #8 ++ mov r3, r7, pull #8 + USER( ldrt r7, [r1], #4) @ May fault +- orr r3, r3, r7, lsl #24 ++ orr r3, r3, r7, push #24 + str r3, [r0], #4 + mov ip, r1, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 +@@ -387,50 +456,63 @@ + sub r2, r2, ip + subs ip, ip, #16 + blt .cfu_1rem8lp ++ PLD( pld [r1, #12] ) ++ PLD( pld [r0, #12] ) ++ PLD( subs ip, ip, #32 ) ++ PLD( blt .cfu_1cpynopld ) ++ PLD( pld [r1, #28] ) ++ PLD( pld [r0, #28] ) + +-.cfu_1cpy8lp: mov r3, r7, lsr #8 ++.cfu_1cpy8lp: ++ PLD( pld [r1, #44] ) ++ PLD( pld [r0, #44] ) ++.cfu_1cpynopld: mov r3, r7, pull #8 + ldmia r1!, {r4 - r7} @ Shouldnt fault +- orr r3, r3, r4, lsl #24 +- mov r4, r4, lsr #8 +- orr r4, r4, r5, lsl #24 +- mov r5, r5, lsr #8 +- orr r5, r5, r6, lsl #24 +- mov r6, r6, lsr #8 +- orr r6, r6, r7, lsl #24 +- stmia r0!, {r3 - r6} + subs ip, ip, #16 ++ orr r3, r3, r4, push #24 ++ mov r4, r4, pull #8 ++ orr r4, r4, r5, push #24 ++ mov r5, r5, pull #8 ++ orr r5, r5, r6, push #24 ++ mov r6, r6, pull #8 ++ orr r6, r6, r7, push #24 ++ stmia r0!, {r3 - r6} + bpl .cfu_1cpy8lp ++ PLD( cmn ip, #32 ) ++ PLD( bge .cfu_1cpynopld ) ++ PLD( add ip, ip, #32 ) ++ + .cfu_1rem8lp: tst ip, #8 +- movne r3, r7, lsr #8 ++ movne r3, r7, pull #8 + ldmneia r1!, {r4, r7} @ Shouldnt fault +- orrne r3, r3, r4, lsl #24 +- movne r4, r4, lsr #8 +- orrne r4, r4, r7, lsl #24 ++ orrne r3, r3, r4, push #24 ++ movne r4, r4, pull #8 ++ orrne r4, r4, r7, push #24 + stmneia r0!, {r3 - r4} + tst ip, #4 +- movne r3, r7, lsr #8 ++ movne r3, r7, pull #8 + USER( ldrnet r7, [r1], #4) @ May fault +- orrne r3, r3, r7, lsl #24 ++ orrne r3, r3, r7, push #24 + strne r3, [r0], #4 + ands ip, ip, #3 + beq .cfu_1fupi +-.cfu_1nowords: mov r3, r7, lsr #8 ++.cfu_1nowords: mov r3, r7, lsr #byte(1) + teq ip, #0 + beq .cfu_finished + cmp ip, #2 + strb r3, [r0], #1 +- movge r3, r3, lsr #8 ++ movge r3, r7, lsr #byte(2) + strgeb r3, [r0], #1 +- movgt r3, r3, lsr #8 ++ movgt r3, r7, lsr #byte(3) + strgtb r3, [r0], #1 + b .cfu_finished + + .cfu_2fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .cfu_2nowords +- mov r3, r7, lsr #16 ++ mov r3, r7, pull #16 + USER( ldrt r7, [r1], #4) @ May fault +- orr r3, r3, r7, lsl #16 ++ orr r3, r3, r7, push #16 + str r3, [r0], #4 + mov ip, r1, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 +@@ -441,39 +523,52 @@ + sub r2, r2, ip + subs ip, ip, #16 + blt .cfu_2rem8lp ++ PLD( pld [r1, #12] ) ++ PLD( pld [r0, #12] ) ++ PLD( subs ip, ip, #32 ) ++ PLD( blt .cfu_2cpynopld ) ++ PLD( pld [r1, #28] ) ++ PLD( pld [r0, #28] ) + +-.cfu_2cpy8lp: mov r3, r7, lsr #16 ++.cfu_2cpy8lp: ++ PLD( pld [r1, #44] ) ++ PLD( pld [r0, #44] ) ++.cfu_2cpynopld: mov r3, r7, pull #16 + ldmia r1!, {r4 - r7} @ Shouldnt fault +- orr r3, r3, r4, lsl #16 +- mov r4, r4, lsr #16 +- orr r4, r4, r5, lsl #16 +- mov r5, r5, lsr #16 +- orr r5, r5, r6, lsl #16 +- mov r6, r6, lsr #16 +- orr r6, r6, r7, lsl #16 +- stmia r0!, {r3 - r6} + subs ip, ip, #16 ++ orr r3, r3, r4, push #16 ++ mov r4, r4, pull #16 ++ orr r4, r4, r5, push #16 ++ mov r5, r5, pull #16 ++ orr r5, r5, r6, push #16 ++ mov r6, r6, pull #16 ++ orr r6, r6, r7, push #16 ++ stmia r0!, {r3 - r6} + bpl .cfu_2cpy8lp ++ PLD( cmn ip, #32 ) ++ PLD( bge .cfu_2cpynopld ) ++ PLD( add ip, ip, #32 ) ++ + .cfu_2rem8lp: tst ip, #8 +- movne r3, r7, lsr #16 ++ movne r3, r7, pull #16 + ldmneia r1!, {r4, r7} @ Shouldnt fault +- orrne r3, r3, r4, lsl #16 +- movne r4, r4, lsr #16 +- orrne r4, r4, r7, lsl #16 ++ orrne r3, r3, r4, push #16 ++ movne r4, r4, pull #16 ++ orrne r4, r4, r7, push #16 + stmneia r0!, {r3 - r4} + tst ip, #4 +- movne r3, r7, lsr #16 ++ movne r3, r7, pull #16 + USER( ldrnet r7, [r1], #4) @ May fault +- orrne r3, r3, r7, lsl #16 ++ orrne r3, r3, r7, push #16 + strne r3, [r0], #4 + ands ip, ip, #3 + beq .cfu_2fupi +-.cfu_2nowords: mov r3, r7, lsr #16 ++.cfu_2nowords: mov r3, r7, lsr #byte(2) + teq ip, #0 + beq .cfu_finished + cmp ip, #2 + strb r3, [r0], #1 +- movge r3, r3, lsr #8 ++ movge r3, r7, lsr #byte(3) + strgeb r3, [r0], #1 + USER( ldrgtbt r3, [r1], #0) @ May fault + strgtb r3, [r0], #1 +@@ -482,9 +577,9 @@ + .cfu_3fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .cfu_3nowords +- mov r3, r7, lsr #24 ++ mov r3, r7, pull #24 + USER( ldrt r7, [r1], #4) @ May fault +- orr r3, r3, r7, lsl #8 ++ orr r3, r3, r7, push #8 + str r3, [r0], #4 + mov ip, r1, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 +@@ -495,41 +590,54 @@ + sub r2, r2, ip + subs ip, ip, #16 + blt .cfu_3rem8lp ++ PLD( pld [r1, #12] ) ++ PLD( pld [r0, #12] ) ++ PLD( subs ip, ip, #32 ) ++ PLD( blt .cfu_3cpynopld ) ++ PLD( pld [r1, #28] ) ++ PLD( pld [r0, #28] ) + +-.cfu_3cpy8lp: mov r3, r7, lsr #24 ++.cfu_3cpy8lp: ++ PLD( pld [r1, #44] ) ++ PLD( pld [r0, #44] ) ++.cfu_3cpynopld: mov r3, r7, pull #24 + ldmia r1!, {r4 - r7} @ Shouldnt fault +- orr r3, r3, r4, lsl #8 +- mov r4, r4, lsr #24 +- orr r4, r4, r5, lsl #8 +- mov r5, r5, lsr #24 +- orr r5, r5, r6, lsl #8 +- mov r6, r6, lsr #24 +- orr r6, r6, r7, lsl #8 ++ orr r3, r3, r4, push #8 ++ mov r4, r4, pull #24 ++ orr r4, r4, r5, push #8 ++ mov r5, r5, pull #24 ++ orr r5, r5, r6, push #8 ++ mov r6, r6, pull #24 ++ orr r6, r6, r7, push #8 + stmia r0!, {r3 - r6} + subs ip, ip, #16 + bpl .cfu_3cpy8lp ++ PLD( cmn ip, #32 ) ++ PLD( bge .cfu_3cpynopld ) ++ PLD( add ip, ip, #32 ) ++ + .cfu_3rem8lp: tst ip, #8 +- movne r3, r7, lsr #24 ++ movne r3, r7, pull #24 + ldmneia r1!, {r4, r7} @ Shouldnt fault +- orrne r3, r3, r4, lsl #8 +- movne r4, r4, lsr #24 +- orrne r4, r4, r7, lsl #8 ++ orrne r3, r3, r4, push #8 ++ movne r4, r4, pull #24 ++ orrne r4, r4, r7, push #8 + stmneia r0!, {r3 - r4} + tst ip, #4 +- movne r3, r7, lsr #24 ++ movne r3, r7, pull #24 + USER( ldrnet r7, [r1], #4) @ May fault +- orrne r3, r3, r7, lsl #8 ++ orrne r3, r3, r7, push #8 + strne r3, [r0], #4 + ands ip, ip, #3 + beq .cfu_3fupi +-.cfu_3nowords: mov r3, r7, lsr #24 ++.cfu_3nowords: mov r3, r7, lsr #byte(3) + teq ip, #0 + beq .cfu_finished + cmp ip, #2 + strb r3, [r0], #1 +-USER( ldrget r3, [r1], #0) @ May fault ++USER( ldrgebt r3, [r1], #1) @ May fault + strgeb r3, [r0], #1 +- movgt r3, r3, lsr #8 ++USER( ldrgtbt r3, [r1], #1) @ May fault + strgtb r3, [r0], #1 + b .cfu_finished + +@@ -544,7 +652,7 @@ + ldr r1, [sp], #4 @ unsigned long count + subs r4, r1, r2 @ bytes left to copy + movne r1, r4 +- blne SYMBOL_NAME(__memzero) ++ blne __memzero + mov r0, r4 + LOADREGS(fd,sp!, {r4 - r7, pc}) + .previous +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/Makefile 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,56 @@ ++# ++# Makefile for the linux kernel. ++# ++# 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). ++ ++USE_STANDARD_AS_RULE := true ++ ++O_TARGET := pxa.o ++ ++obj-y := ++obj-m := ++obj-n := ++obj- := ++ ++export-objs := generic.o irq.o dma.o sa1111.o \ ++ usb_ctl.o usb_recv.o usb_send.o ++ ++# Common support (must be linked before board specific support) ++obj-y += generic.o irq.o dma.o ++obj-$(CONFIG_SA1111) += sa1111.o ++ ++# Specific board support ++obj-$(CONFIG_ARCH_CSB226) += csb226.o ++obj-$(CONFIG_ARCH_INNOKOM) += innokom.o ++obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o ++obj-$(CONFIG_ARCH_PXA_CERF) += cerf.o ++obj-$(CONFIG_ARCH_PXA_IDP) += idp.o ++obj-$(CONFIG_ARCH_TRIZEPS2) += trizeps2.o ++ ++# Support for blinky lights ++leds-y := leds.o ++leds-$(CONFIG_ARCH_CSB226) += leds-csb226.o ++leds-$(CONFIG_ARCH_INNOKOM) += leds-innokom.o ++leds-$(CONFIG_ARCH_LUBBOCK) += leds-lubbock.o ++leds-$(CONFIG_ARCH_PXA_IDP) += leds-idp.o ++leds-$(CONFIG_ARCH_PXA_CERF) += leds-cerf.o ++ ++obj-$(CONFIG_LEDS) += $(leds-y) ++ ++# PXA USB client support ++list-multi += pxausb_core.o ++pxausb_core-objs := usb_ctl.o usb_ep0.o usb_recv.o usb_send.o ++obj-$(CONFIG_PXA_USB) += pxausb_core.o ++obj-$(CONFIG_PXA_USB_NETLINK) += usb-eth.o ++obj-$(CONFIG_PXA_USB_CHAR) += usb-char.o ++ ++# Misc features ++obj-$(CONFIG_PM) += pm.o sleep.o ++obj-$(CONFIG_CPU_FREQ) += cpu-pxa.o ++ ++include $(TOPDIR)/Rules.make ++ ++pxausb_core.o: $(pxausb_core-objs) ++ $(LD) -r -o $@ $(pxausb_core-objs) +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/cerf.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,266 @@ ++/* ++ * linux/arch/arm/mach-pxa/cerf.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 <linux/init.h> ++#include <linux/major.h> ++#include <linux/fs.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++ ++#include <asm/types.h> ++#include <asm/setup.h> ++#include <asm/memory.h> ++#include <asm/mach-types.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/io.h> ++#include <asm/arch/irq.h> ++ ++#include "generic.h" ++ ++/* ++ * Set this to zero to remove all the debug statements via ++ * dead code elimination. ++ */ ++#define DEBUGGING 1 ++ ++#if DEBUGGING ++static unsigned int cerf_debug = DEBUGGING; ++#else ++#define cerf_debug 0 ++#endif ++ ++static void __init cerf_init_irq(void) ++{ ++ pxa_init_irq(); ++ ++ if( cerf_debug > 1) ++ { ++#if 0 ++ GPDR0 = 0xc05b9130; ++ GPDR1 = 0xfcffab82; ++ GPDR2 = 0x0001ffff; ++#endif ++ ++ printk(KERN_INFO "Pin directions:\n"); ++ printk(KERN_INFO "GPDR0 0x%08x\n", GPDR0); ++ printk(KERN_INFO "GPDR1 0x%08x\n", GPDR1); ++ printk(KERN_INFO "GPDR2 0x%08x\n", GPDR2); ++ ++ printk(KERN_INFO "Pin State:\n"); ++ printk(KERN_INFO "GPLR0 0x%08x\n", GPLR0); ++ printk(KERN_INFO "GPLR1 0x%08x\n", GPLR1); ++ printk(KERN_INFO "GPLR2 0x%08x\n", GPLR2); ++ ++ printk(KERN_INFO "Rising Edge:\n"); ++ printk(KERN_INFO "GRER0 0x%08x\n", GRER0); ++ printk(KERN_INFO "GRER1 0x%08x\n", GRER1); ++ printk(KERN_INFO "GRER2 0x%08x\n", GRER2); ++ ++ printk(KERN_INFO "Falling Edge:\n"); ++ printk(KERN_INFO "GFER0 0x%08x\n", GFER0); ++ printk(KERN_INFO "GFER1 0x%08x\n", GFER1); ++ printk(KERN_INFO "GFER2 0x%08x\n", GFER2); ++ } ++ ++ /* set_GPIO_IRQ_edge has to be called before an irq can be requested */ ++ set_GPIO_IRQ_edge( 0, GPIO_FALLING_EDGE); /* CPLD */ ++#ifdef CONFIG_PXA_CERF_PDA ++ set_GPIO_IRQ_edge( 2, GPIO_RISING_EDGE); /* UART B Interrupt */ ++ set_GPIO_IRQ_edge( 3, GPIO_RISING_EDGE); /* UART A Interrupt */ ++ set_GPIO_IRQ_edge( 32, GPIO_RISING_EDGE); /* UCB1400 Interrupt */ ++#endif ++ set_GPIO_IRQ_edge( 14, GPIO_FALLING_EDGE); /* PCMCIA Card Detect */ ++ set_GPIO_IRQ_edge( 21, GPIO_RISING_EDGE); /* Ethernet Interrupt */ ++} ++ ++static int __init cerf_init(void) ++{ ++ /* ++ * All of the code that was here was SA1111 init code ++ * which we do not have. ++ */ ++ return 0; ++} ++ ++__initcall(cerf_init); ++ ++static void __init ++fixup_cerf(struct machine_desc *desc, struct param_struct *params, ++ char **cmdline, struct meminfo *mi) ++{ ++ SET_BANK (0, CERF_RAM_BASE, CERF_RAM_SIZE); ++ mi->nr_banks = 1; ++ ++#if 0 // Enable this stuff if you plan on not using jffs2 ++ setup_ramdisk (1, 0, 0, 8192); ++ setup_initrd (__phys_to_virt(0xa1000000), 4*1024*1024); ++ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); ++#endif ++} ++ ++/* ++ * IO map for the devices. ++ */ ++static struct map_desc cerf_io_desc[] __initdata = { ++ /* virtual physical length domain r w c b */ ++ { CERF_FLASH_BASE , CERF_FLASH_PHYS , CERF_FLASH_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, ++ { CERF_ETH_BASE , CERF_ETH_PHYS , CERF_ETH_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, ++#ifdef CONFIG_PXA_CERF_PDA ++ { CERF_BT_BASE , CERF_BT_PHYS , CERF_BT_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, ++ { CERF_SERIAL_BASE, CERF_SERIAL_PHYS, CERF_SERIAL_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, ++ { CERF_CPLD_BASE , CERF_CPLD_PHYS , CERF_CPLD_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, ++#endif ++ ++ LAST_DESC ++}; ++ ++static void __init cerf_map_io(void) ++{ ++ pxa_map_io(); ++ iotable_init(cerf_io_desc); ++ ++ if( cerf_debug > 1) ++ { ++ printk(KERN_INFO "origMCS0 = 0x%08x\n", MSC0); ++ printk(KERN_INFO "origMCS1 = 0x%08x\n", MSC1); ++ printk(KERN_INFO "origMCS2 = 0x%08x\n", MSC2); ++ } ++ ++ /* setup memory timing for CS0/1 */ ++ MSC0 = MSC_CS(0, MSC_RBUFF(MSC_RBUFF_SLOW) | ++ MSC_RRR(3) | ++ MSC_RDN(15) | ++ MSC_RDF(13) | ++ MSC_RBW(0) | ++ MSC_RT(0)) | ++#ifdef CONFIG_PXA_CERF_PDA ++ MSC_CS(1, MSC_RBUFF(MSC_RBUFF_SLOW) | ++ MSC_RRR(7) | ++ MSC_RDN(15) | ++ MSC_RDF(15) | ++ MSC_RBW(1) | ++ MSC_RT(0)); ++#elif defined(CONFIG_PXA_CERF_BOARD) ++ MSC_CS(1, MSC_RBUFF(MSC_RBUFF_SLOW) | ++ MSC_RRR(1) | ++ MSC_RDN(2) | ++ MSC_RDF(4) | ++ MSC_RBW(0) | ++ MSC_RT(4)); ++#endif ++ printk(KERN_INFO "MCS0 = 0x%08x\n", MSC0); ++ ++ /* setup memory timing for CS2/3 */ ++ MSC1 = MSC_CS(2, MSC_RBUFF(MSC_RBUFF_SLOW) | ++ MSC_RRR(5) | ++ MSC_RDN(10) | ++ MSC_RDF(10) | ++ MSC_RBW(1) | ++ MSC_RT(0)) | ++ MSC_CS(3, MSC_RBUFF(MSC_RBUFF_SLOW) | ++ MSC_RRR(5) | ++ MSC_RDN(10) | ++ MSC_RDF(10) | ++ MSC_RBW(1) | ++ MSC_RT(0)); ++ printk(KERN_INFO "MCS1 = 0x%08x\n", MSC1); ++ ++ /* setup memory timing for CS4/5 */ ++ MSC2 = MSC_CS(4, MSC_RBUFF(MSC_RBUFF_SLOW) | ++ MSC_RRR(2) | ++ MSC_RDN(4) | ++ MSC_RDF(4) | ++ MSC_RBW(1) | ++ MSC_RT(0)) | ++ MSC_CS(5, MSC_RBUFF(MSC_RBUFF_SLOW) | ++ MSC_RRR(2) | ++ MSC_RDN(4) | ++ MSC_RDF(4) | ++ MSC_RBW(1) | ++ MSC_RT(0)); ++ printk(KERN_INFO "MCS2 = 0x%08x\n", MSC2); ++ ++#ifdef CONFIG_SOUND_PXA_AC97 ++ printk(KERN_INFO "Enabling sound amp for pxa cerf pda.\n"); ++ outw( CERF_PDA_SOUND_ENABLE, CERF_CPLD_BASE+CERF_PDA_CPLD_SOUND_ENA); ++#endif ++ ++#ifdef CONFIG_FB_PXA ++ printk(KERN_INFO "Setting LCD to brightness to %d/15\n", CERF_PDA_DEFAULT_BRIGHTNESS); ++ outw( CERF_PDA_DEFAULT_BRIGHTNESS, CERF_CPLD_BASE+CERF_PDA_CPLD_BRIGHTNESS); ++#endif ++ ++#ifdef CONFIG_IRDA ++ /* Enable IrDA UART (SIR)*/ ++ CKEN |= CKEN5_STUART; ++ ++ /* We want to get our goods from the STUART */ ++ set_GPIO_mode(GPIO46_STRXD_MD); ++ set_GPIO_mode(GPIO47_STTXD_MD); ++ ++ /* make sure FIR ICP is off */ ++ ICCR0 = 0; ++ ++ /* configure STUART to for SIR ++ * NOTE: RCVEIR and XMITIR must not be set at the same time! ++ * Start with receive in IR mode, and switch transmit to IR only ++ * when we need to send something in serial driver. ++ */ ++ STISR = IrSR_IR_RECEIVE_ON; ++#endif ++ ++#if 0 ++ /* Connect FIR ICP to GPIO pins */ ++ CKEN |= CKEN13_FICP; ++ set_GPIO_mode(GPIO46_ICPRXD_MD); ++ set_GPIO_mode(GPIO47_ICPTXD_MD); ++ ICCR0 = 0x1 | 0x18; //ICP unit enable ++#endif ++ ++#if 0 ++ /* Enable BT UART */ ++ CKEN |= CKEN7_BTUART; ++ set_GPIO_mode(GPIO42_BTRXD_MD); ++ set_GPIO_mode(GPIO43_BTTXD_MD); ++ set_GPIO_mode(GPIO44_BTCTS_MD); ++ set_GPIO_mode(GPIO45_BTRTS_MD); ++#endif ++ ++ if( cerf_debug > 1) ++ { ++ printk(KERN_INFO "GPDR0 0x%08x\n", GPDR0); ++ printk(KERN_INFO "GPDR1 0x%08x\n", GPDR1); ++ printk(KERN_INFO "GPDR2 0x%08x\n", GPDR2); ++ printk(KERN_INFO "GPLR0 0x%08x\n", GPLR0); ++ printk(KERN_INFO "GPLR1 0x%08x\n", GPLR1); ++ printk(KERN_INFO "GPLR2 0x%08x\n", GPLR2); ++ printk(KERN_INFO "GAFR0_L 0x%08x\n", GAFR0_L); ++ printk(KERN_INFO "GAFR0_U 0x%08x\n", GAFR0_U); ++ printk(KERN_INFO "GAFR1_L 0x%08x\n", GAFR1_L); ++ printk(KERN_INFO "GAFR1_U 0x%08x\n", GAFR1_U); ++ printk(KERN_INFO "GAFR2_L 0x%08x\n", GAFR2_L); ++ printk(KERN_INFO "GAFR2_U 0x%08x\n", GAFR2_U); ++ printk(KERN_INFO "CKEN = 0x%08x\n", CKEN); ++ printk(KERN_INFO "ICCR0 = 0x%08x\n", ICCR0); ++ printk(KERN_INFO "STISR = 0x%08x\n", STISR); ++ } ++} ++ ++MACHINE_START(PXA_CERF, "CerfBoard PXA Reference Board") ++ MAINTAINER("Intrinsyc Software Inc.") ++ BOOT_MEM(0xa0000000, 0x40000000, 0xfc000000) ++ BOOT_PARAMS(0xa0000100) ++ FIXUP(fixup_cerf) ++ MAPIO(cerf_map_io) ++ INITIRQ(cerf_init_irq) ++MACHINE_END +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/cpu-pxa.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,240 @@ ++/* ++ * linux/arch/arm/mach-pxa/cpu-pxa.c ++ * ++ * Copyright (C) 2002,2003 Intrinsyc Software ++ * ++ * 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. ++ * ++ * History: ++ * 31-Jul-2002 : Initial version [FB] ++ * 29-Jan-2003 : added PXA255 support [FB] ++ * ++ * Note: ++ * ++ * Quote from erratum 134: ++ * ""If the operation of these peripherals would be adversely affected, ++ * then these peripherals would have to be disabled during a frequency ++ * change. (MMC,FFUART,STUART,BTUART,IRDA,SSP,UDC,AC97)"" ++ * ++ * This sounds like they are not sure what the bug is... ++ * If you run into problems with any of these peripherals, the effected ++ * driver should register with cpu freq notification and disable/enable ++ * the peripheral on CPUFREQ_PRECHANGE and CPUFREQ_POSTCHANGE. ++ * ++ * So far I've tested this code only under light load. It works for me. ++ * ++ * TODO: ++ * - determine min/max freq at runtime ++ * - determine pxbus value at runtime ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/sched.h> ++#include <linux/init.h> ++#include <linux/cpufreq.h> ++ ++#include <asm/hardware.h> ++ ++#define DEBUGGING 1 ++ ++#if DEBUGGING ++static unsigned int freq_debug = DEBUGGING; ++#else ++#define freq_debug 0 ++#endif ++ ++typedef struct ++{ ++ unsigned int khz; ++ unsigned int cccr; ++ unsigned int pxbus; ++} pxa_freqs_t; ++ ++#define CCLKCFG_TURBO 0x1 ++#define CCLKCFG_FCS 0x2 ++ ++#define PXA250_REV_A1 0x1 ++#define PXA250_REV_B2 0x4 ++#define PXA25x_MIN_FREQ 99000 ++ ++//#define PXA25x_ALLOW_OVERCLOCK ++ ++#ifdef PXA25x_ALLOW_OVERCLOCK ++#warning *** Overclocking enabled - this may fry your hardware - you have been warned *** ++#define OC(x...) x ++#define PXA25x_MAX_FREQ 471000 ++#else ++#define OC(x...) ++#define PXA25x_MAX_FREQ 400000 ++#endif ++ ++/* If CONFIG_CPU_FREQ is turned on but we find (at runtime) ++ * we can't support scaling, try to handle requests gracefully. ++ */ ++static int supported; ++ ++static pxa_freqs_t pxa250_valid_freqs[] = ++{ ++ {199100, 0x141, 99}, /* mem= 99, run=199, turbo=199, PXbus= 99 */ ++ {298600, 0x1c1, 99}, /* mem= 99, run=199, turbo=298, PXbus= 99 */ ++ {398100, 0x241, 99}, /* mem= 99, run=199, turbo=398, PXbus= 99 */ ++ {0,0} ++}; ++ ++static pxa_freqs_t pxa255_valid_freqs[] = ++{ ++ { 99000, 0x121, 50}, /* mem= 99, run= 99, turbo= 99, PXbus= 50 */ ++OC( {118000, 0x122, 59},)/* mem=118, run=118, turbo=118, PXbus= 59 OC'd mem */ ++ {199100, 0x141, 99}, /* mem= 99, run=199, turbo=199, PXbus= 99 */ ++OC( {236000, 0x142,118},)/* mem=118, run=236, turbo=236, PXbus=118 OC'd mem */ ++ {298600, 0x1c1, 99}, /* mem= 99, run=199, turbo=298, PXbus= 99 */ ++OC( {354000, 0x1c2,118},)/* mem=118, run=236, turbo=354, PXbus=118 OC'd mem */ ++ {398099, 0x241, 99}, /* mem= 99, run=199, turbo=398, PXbus= 99 */ ++ {398100, 0x161,196}, /* mem= 99, run=398, turbo=398, PXbus=196 */ ++OC( {471000, 0x162,236},)/* mem=118, run=471, turbo=471, PXbus=236 OC'd mem/core/bus */ ++ {0,0} ++}; ++ ++static pxa_freqs_t *pxa_valid_freqs; ++ ++/* This should be called with a valid freq point that was ++ * obtained via pxa_validate_speed ++ */ ++static pxa_freqs_t * pxa_get_freq_info( unsigned int khz) ++{ ++ int i=0; ++ while( pxa_valid_freqs[i].khz) ++ { ++ if( pxa_valid_freqs[i].khz == khz) ++ return &pxa_valid_freqs[i]; ++ i++; ++ } ++ ++ /* shouldn't get here */ ++ return 0; ++} ++ ++/* find a valid frequency point */ ++static unsigned int pxa_validate_speed(unsigned int khz) ++{ ++ int i=0; ++ unsigned int vfreq = 0; ++ while( pxa_valid_freqs[i].khz && (khz >= pxa_valid_freqs[i].khz)) ++ { ++ vfreq = pxa_valid_freqs[i].khz; ++ i++; ++ } ++ return vfreq; ++} ++ ++/* This should be called with a valid freq point that was ++ * obtained via pxa_validate_speed ++ */ ++static void pxa_setspeed(unsigned int khz) ++{ ++ unsigned long flags; ++ unsigned int unused; ++ void *ramstart = phys_to_virt(0xa0000000); ++ pxa_freqs_t *freq_info; ++ ++ if( ! supported) return; ++ ++ freq_info = pxa_get_freq_info( khz); ++ ++ if( ! freq_info) return; ++ ++ CCCR = freq_info->cccr; ++ if( freq_debug) ++ printk(KERN_INFO "Changing CPU frequency to %d Mhz (PXbus=%dMhz).\n", ++ khz/1000, freq_info->pxbus); ++ ++ local_irq_save(flags); ++ __asm__ __volatile__("\ ++ ldr r4, [%1] @load MDREFR \n\ ++ b 2f \n\ ++ .align 5 \n\ ++1: \n\ ++ mcr p14, 0, %2, c6, c0, 0 @ set CCLKCFG[FCS] \n\ ++ \n\ ++ @ restart sdcke 0 / 1 \n\ ++ bic r5, r4, #(0x00001000 | 0x00008000) @ MDREFR_E0PIN | MDREFR_E1PIN \n\ ++ str r5, [%1] @clear \n\ ++ str r4, [%1] @restore \n\ ++ \n\ ++ @ Generate refresh cycles for all banks \n\ ++ ldr r4, [%3] \n\ ++ str r4, [%3] \n\ ++ str r4, [%3] \n\ ++ str r4, [%3] \n\ ++ str r4, [%3] \n\ ++ str r4, [%3] \n\ ++ str r4, [%3] \n\ ++ str r4, [%3] \n\ ++ str r4, [%3] \n\ ++ \n\ ++ b 3f \n\ ++2: b 1b \n\ ++3: nop \n\ ++ " ++ : "=&r" (unused) ++ : "r" (&MDREFR), "r" (CCLKCFG_TURBO|CCLKCFG_FCS), "r" (ramstart) ++ : "r4", "r5"); ++ local_irq_restore(flags); ++} ++ ++static int pxa_init_freqs( void) ++{ ++ int cpu_ver; ++ asm("mrc%? p15, 0, %0, c0, c0" : "=r" (cpu_ver)); ++ ++ if( (cpu_ver & 0xf) <= PXA250_REV_A1) ++ { ++ return 0; ++ } ++ ++ if( (cpu_ver & 0xf) <= PXA250_REV_B2) ++ { ++ if( freq_debug) printk(KERN_INFO "Using PXA250 frequency points.\n"); ++ pxa_valid_freqs = pxa250_valid_freqs; ++ } ++ else /* C0 and above */ ++ { ++ if( freq_debug) printk(KERN_INFO "Using PXA255 frequency points.\n"); ++ pxa_valid_freqs = pxa255_valid_freqs; ++ } ++ ++ return 1; ++} ++ ++static int __init pxa_clk_init(void) ++{ ++ if( pxa_init_freqs()) ++ { ++ if( freq_debug) printk(KERN_INFO "Registering CPU frequency change support.\n"); ++ supported = 1; ++ ++ cpufreq_init( get_clk_frequency_khz(0), PXA25x_MIN_FREQ, PXA25x_MAX_FREQ); ++ cpufreq_setfunctions(pxa_validate_speed, pxa_setspeed); ++ } ++ else ++ { ++ if( freq_debug) printk(KERN_INFO "Disabling CPU frequency change support.\n"); ++ /* Note that we have to initialize the generic code in order to ++ * release a lock (cpufreq_sem). Any registration for freq changes ++ * (e.g. lcd driver) will get blocked otherwise. ++ */ ++ cpufreq_init( 0, 0, 0); ++ cpufreq_setfunctions(pxa_validate_speed, pxa_setspeed); ++ } ++ ++ return 0; ++} ++ ++module_init(pxa_clk_init); ++ ++MODULE_AUTHOR ("Intrinsyc Software Inc."); ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/csb226.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,180 @@ ++/* ++ * linux/arch/arm/mach-pxa/csb226.c ++ * ++ * (c) 2003 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix ++ * ++ * 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 <linux/init.h> ++#include <linux/major.h> ++#include <linux/fs.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++ ++#include <asm/types.h> ++#include <asm/setup.h> ++#include <asm/memory.h> ++#include <asm/mach-types.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/irq.h> ++#include <asm/arch/irqs.h> ++#include <asm/hardware/sa1111.h> ++ ++#include "generic.h" ++ ++static unsigned long csb226_irq_en_mask; ++ ++static void csb226_mask_and_ack_irq(unsigned int irq) ++{ ++ int csb226_irq = (irq - CSB226_IRQ(0)); ++ csb226_irq_en_mask &= ~(1 << csb226_irq); ++ CSB226_IRQ_MASK_EN &= ~(1 << csb226_irq); ++ CSB226_IRQ_SET_CLR &= ~(1 << csb226_irq); ++} ++ ++static void csb226_mask_irq(unsigned int irq) ++{ ++ int csb226_irq = (irq - CSB226_IRQ(0)); ++ csb226_irq_en_mask &= ~(1 << csb226_irq); ++ CSB226_IRQ_MASK_EN &= ~(1 << csb226_irq); ++} ++ ++static void csb226_unmask_irq(unsigned int irq) ++{ ++ int csb226_irq = (irq - CSB226_IRQ(0)); ++ csb226_irq_en_mask |= (1 << csb226_irq); ++ CSB226_IRQ_MASK_EN |= (1 << csb226_irq); ++} ++ ++void csb226_irq_demux(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ unsigned long irq_status; ++ int i; ++ ++ while ((irq_status = CSB226_IRQ_SET_CLR & csb226_irq_en_mask)) { ++ for (i = 0; i < 6; i++) { ++ if(irq_status & (1<<i)) ++ do_IRQ(CSB226_IRQ(i), regs); ++ } ++ } ++} ++ ++/* FIXME: this should not be necessary on csb226 */ ++static struct irqaction csb226_irq = { ++ name: "CSB226 FPGA", ++ handler: csb226_irq_demux, ++ flags: SA_INTERRUPT ++}; ++ ++static void __init csb226_init_irq(void) ++{ ++ int irq; ++ ++ pxa_init_irq(); ++ ++ /* setup extra csb226 irqs */ ++/* RS: ??? ++ for(irq = CSB226_IRQ(0); irq <= CSB226_IRQ(5); irq++) ++ { ++ irq_desc[irq].valid = 1; ++ irq_desc[irq].probe_ok = 1; ++ irq_desc[irq].mask_ack = csb226_mask_and_ack_irq; ++ irq_desc[irq].mask = csb226_mask_irq; ++ irq_desc[irq].unmask = csb226_unmask_irq; ++ } ++ ++ set_GPIO_IRQ_edge(GPIO_CSB226_IRQ, GPIO_FALLING_EDGE); ++ setup_arm_irq(IRQ_GPIO_CSB226_IRQ, &csb226_irq); ++*/ ++} ++ ++/* FIXME: not necessary on CSB226? */ ++static int __init csb226_init(void) ++{ ++ int ret; ++ ++ return 0; ++} ++ ++__initcall(csb226_init); ++ ++static void __init ++fixup_csb226(struct machine_desc *desc, struct param_struct *params, ++ char **cmdline, struct meminfo *mi) ++{ ++ SET_BANK (0, 0xa0000000, 64*1024*1024); ++ mi->nr_banks = 1; ++#if 0 ++ setup_ramdisk (1, 0, 0, 8192); ++ setup_initrd (__phys_to_virt(0xa1000000), 4*1024*1024); ++ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); ++#endif ++} ++ ++/* FIXME: shouldn't this be moved to arch/arm/mach-pxa/mm.c? [RS] */ ++static struct map_desc csb226_io_desc[] __initdata = { ++ /* virtual physical length domain r w c b */ ++// { 0xf4000000, 0x04000000, 0x00ffffff, DOMAIN_IO, 1, 1, 0, 0 }, /* HT4562B PS/2 controller */ ++ { 0xf8000000, 0x08000000, 1024*1024, DOMAIN_IO, 0, 1, 0, 0 }, /* CS8900 LAN controller */ ++// { 0xe0000000, 0x20000000, 0x0fffffff, DOMAIN_IO, 1, 1, 0, 0 }, /* CompactFlash */ ++#if 0 ++ { 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */ ++ { 0xf1000000, 0x0c000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 IO */ ++ { 0xf1100000, 0x0e000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 Attr */ ++ { 0xf4000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA1111 */ ++#endif ++ LAST_DESC ++}; ++ ++static void __init csb226_map_io(void) ++{ ++ pxa_map_io(); ++ iotable_init(csb226_io_desc); ++ ++ /* This enables the BTUART */ ++ CKEN |= CKEN7_BTUART; ++ set_GPIO_mode(GPIO42_BTRXD_MD); ++ set_GPIO_mode(GPIO43_BTTXD_MD); ++ set_GPIO_mode(GPIO44_BTCTS_MD); ++ set_GPIO_mode(GPIO45_BTRTS_MD); ++ ++ /* This is for the CS8900 chip select */ ++ set_GPIO_mode(GPIO78_nCS_2_MD); ++ ++ /* setup sleep mode values */ ++ PWER = 0x00000002; ++ PFER = 0x00000000; ++ PRER = 0x00000002; ++ PGSR0 = 0x00008000; ++ PGSR1 = 0x003F0202; ++ PGSR2 = 0x0001C000; ++ PCFR |= PCFR_OPDE; ++} ++ ++MACHINE_START(CSB226, "Cogent CSB226 Development Platform") ++ MAINTAINER("Robert Schwebel, Pengutronix") ++ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) ++ BOOT_PARAMS(0xa0000100) ++ FIXUP(fixup_csb226) ++ MAPIO(csb226_map_io) ++ INITIRQ(csb226_init_irq) ++MACHINE_END +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/dma.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,131 @@ ++/* ++ * linux/arch/arm/mach-pxa/dma.c ++ * ++ * PXA DMA registration and IRQ dispatching ++ * ++ * Author: Nicolas Pitre ++ * Created: Nov 15, 2001 ++ * Copyright: MontaVista 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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++ ++#include <asm/system.h> ++#include <asm/irq.h> ++#include <asm/hardware.h> ++#include <asm/dma.h> ++ ++ ++static struct dma_channel { ++ char *name; ++ void (*irq_handler)(int, void *, struct pt_regs *); ++ void *data; ++} dma_channels[16]; ++ ++ ++int pxa_request_dma (char *name, pxa_dma_prio prio, ++ void (*irq_handler)(int, void *, struct pt_regs *), ++ void *data) ++{ ++ unsigned long flags; ++ int i, found = 0; ++ ++ /* basic sanity checks */ ++ if (!name || !irq_handler) ++ return -EINVAL; ++ ++ local_irq_save(flags); ++ ++ /* try grabbing a DMA channel with the requested priority */ ++ for (i = prio; i < prio + (prio == DMA_PRIO_LOW) ? 8 : 4; i++) { ++ if (!dma_channels[i].name) { ++ found = 1; ++ break; ++ } ++ } ++ ++ if (!found) { ++ /* requested prio group is full, try hier priorities */ ++ for (i = prio-1; i >= 0; i--) { ++ if (!dma_channels[i].name) { ++ found = 1; ++ break; ++ } ++ } ++ } ++ ++ if (found) { ++ DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; ++ dma_channels[i].name = name; ++ dma_channels[i].irq_handler = irq_handler; ++ dma_channels[i].data = data; ++ } else { ++ printk (KERN_WARNING "No more available DMA channels for %s\n", name); ++ i = -ENODEV; ++ } ++ ++ local_irq_restore(flags); ++ return i; ++} ++ ++void pxa_free_dma (int dma_ch) ++{ ++ unsigned long flags; ++ ++ if (!dma_channels[dma_ch].name) { ++ printk (KERN_CRIT __FUNCTION__ ++ ": trying to free channel %d which is already freed\n", ++ dma_ch); ++ return; ++ } ++ ++ local_irq_save(flags); ++ DCSR(dma_ch) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; ++ dma_channels[dma_ch].name = NULL; ++ local_irq_restore(flags); ++} ++ ++static void dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ int i, dint = DINT; ++ ++ for (i = 0; i < 16; i++) { ++ if (dint & (1 << i)) { ++ struct dma_channel *channel = &dma_channels[i]; ++ if (channel->name && channel->irq_handler) { ++ channel->irq_handler(i, channel->data, regs); ++ } else { ++ /* ++ * IRQ for an unregistered DMA channel: ++ * let's clear the interrupts and disable it. ++ */ ++ printk (KERN_WARNING "spurious IRQ for DMA channel %d\n", i); ++ DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; ++ } ++ } ++ } ++} ++ ++static int __init pxa_dma_init (void) ++{ ++ int ret; ++ ++ ret = request_irq (IRQ_DMA, dma_irq_handler, 0, "DMA", NULL); ++ if (ret) ++ printk (KERN_CRIT "Wow! Can't register IRQ for DMA\n"); ++ return ret; ++} ++ ++__initcall(pxa_dma_init); ++ ++EXPORT_SYMBOL(pxa_request_dma); ++EXPORT_SYMBOL(pxa_free_dma); ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/generic.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,142 @@ ++/* ++ * linux/arch/arm/mach-pxa/generic.c ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista Software Inc. ++ * ++ * Code common to all PXA machines. ++ * ++ * 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. ++ * ++ * Since this file should be linked before any other machine specific file, ++ * the __initcall() here will be executed first. This serves as default ++ * initialization stuff for PXA machines which can be overriden later if ++ * need be. ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/pm.h> ++ ++#include <asm/hardware.h> ++#include <asm/system.h> ++#include <asm/pgtable.h> ++#include <asm/mach/map.h> ++ ++#include "generic.h" ++ ++/* ++ * Various clock factors driven by the CCCR register. ++ */ ++ ++/* Crystal Frequency to Memory Frequency Multiplier (L) */ ++static unsigned char L_clk_mult[32] = { 0, 27, 32, 36, 40, 45, 0, }; ++ ++/* Memory Frequency to Run Mode Frequency Multiplier (M) */ ++static unsigned char M_clk_mult[4] = { 0, 1, 2, 4 }; ++ ++/* Run Mode Frequency to Turbo Mode Frequency Multiplier (N) */ ++/* Note: we store the value N * 2 here. */ ++static unsigned char N2_clk_mult[8] = { 0, 0, 2, 3, 4, 0, 6, 0 }; ++ ++/* Crystal clock */ ++#define BASE_CLK 3686400 ++ ++/* ++ * Get the clock frequency as reflected by CCCR and the turbo flag. ++ * We assume these values have been applied via a fcs. ++ * If info is not 0 we also display the current settings. ++ */ ++unsigned int get_clk_frequency_khz( int info) ++{ ++ unsigned long cccr, turbo; ++ unsigned int l, L, m, M, n2, N; ++ ++ cccr = CCCR; ++ asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (turbo) ); ++ ++ l = L_clk_mult[(cccr >> 0) & 0x1f]; ++ m = M_clk_mult[(cccr >> 5) & 0x03]; ++ n2 = N2_clk_mult[(cccr >> 7) & 0x07]; ++ ++ L = l * BASE_CLK; ++ M = m * L; ++ N = n2 * M / 2; ++ ++ if( info) ++ { ++ L += 5000; ++ printk( KERN_INFO "Memory clock: %d.%02dMHz (*%d)\n", ++ L / 1000000, (L % 1000000) / 10000, l ); ++ M += 5000; ++ printk( KERN_INFO "Run Mode clock: %d.%02dMHz (*%d)\n", ++ M / 1000000, (M % 1000000) / 10000, m ); ++ N += 5000; ++ printk( KERN_INFO "Turbo Mode clock: %d.%02dMHz (*%d.%d, %sactive)\n", ++ N / 1000000, (N % 1000000) / 10000, n2 / 2, (n2 % 2) * 5, ++ (turbo & 1) ? "" : "in" ); ++ } ++ ++ return (turbo & 1) ? (N/1000) : (M/1000); ++} ++ ++EXPORT_SYMBOL(get_clk_frequency_khz); ++ ++/* ++ * Return the current lclk requency in units of 10kHz ++ */ ++unsigned int get_lclk_frequency_10khz(void) ++{ ++ return L_clk_mult[(CCCR >> 0) & 0x1f] * BASE_CLK / 10000; ++} ++ ++EXPORT_SYMBOL(get_lclk_frequency_10khz); ++ ++/* ++ * Handy function to set GPIO alternate functions ++ */ ++ ++void set_GPIO_mode(int gpio_mode) ++{ ++ long flags; ++ int gpio = gpio_mode & GPIO_MD_MASK_NR; ++ int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8; ++ int gafr; ++ ++ local_irq_save(flags); ++ if (gpio_mode & GPIO_MD_MASK_DIR) ++ GPDR(gpio) |= GPIO_bit(gpio); ++ else ++ GPDR(gpio) &= ~GPIO_bit(gpio); ++ gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2)); ++ GAFR(gpio) = gafr | (fn << (((gpio) & 0xf)*2)); ++ local_irq_restore(flags); ++} ++ ++EXPORT_SYMBOL(set_GPIO_mode); ++ ++/* ++ * Note that 0xfffe0000-0xffffffff is reserved for the vector table and ++ * cache flush area. ++ */ ++static struct map_desc standard_io_desc[] __initdata = { ++ /* virtual physical length domain r w c b */ ++ { 0xf6000000, 0x20000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 IO */ ++ { 0xf7000000, 0x30000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 IO */ ++ { 0xf8000000, 0x40000000, 0x01800000, DOMAIN_IO, 0, 1, 0, 0 }, /* Devs */ ++ { 0xfa000000, 0x44000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD */ ++ { 0xfc000000, 0x48000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Mem Ctl */ ++ { 0xff000000, 0x00000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* UNCACHED_PHYS_0 */ ++ LAST_DESC ++}; ++ ++void __init pxa_map_io(void) ++{ ++ iotable_init(standard_io_desc); ++ get_clk_frequency_khz( 1); ++} +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/generic.h 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,19 @@ ++/* ++ * linux/arch/arm/mach-pxa/generic.h ++ * ++ * Author: Nicolas Pitre ++ * Copyright: MontaVista 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. ++ */ ++ ++extern void __init pxa_map_io(void); ++extern void __init pxa_init_irq(void); ++ ++#define SET_BANK(__nr,__start,__size) \ ++ mi->bank[__nr].start = (__start), \ ++ mi->bank[__nr].size = (__size), \ ++ mi->bank[__nr].node = (((unsigned)(__start) - PHYS_OFFSET) >> 27) ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/idp.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,142 @@ ++/* ++ * linux/arch/arm/mach-pxa/idp.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. ++ * ++ * Copyright (c) 2001 Cliff Brake, Accelent Systems Inc. ++ * ++ * 2001-09-13: Cliff Brake <cbrake@accelent.com> ++ * Initial code ++ */ ++#include <linux/init.h> ++#include <linux/major.h> ++#include <linux/fs.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++ ++#include <asm/types.h> ++#include <asm/setup.h> ++#include <asm/memory.h> ++#include <asm/mach-types.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/irq.h> ++ ++#include "generic.h" ++ ++#define PXA_IDP_REV02 ++ ++#ifndef PXA_IDP_REV02 ++/* shadow registers for write only registers */ ++unsigned int idp_cpld_led_control_shadow = 0x1; ++unsigned int idp_cpld_periph_pwr_shadow = 0xd; ++unsigned int ipd_cpld_cir_shadow = 0; ++unsigned int idp_cpld_kb_col_high_shadow = 0; ++unsigned int idp_cpld_kb_col_low_shadow = 0; ++unsigned int idp_cpld_pccard_en_shadow = 0xC3; ++unsigned int idp_cpld_gpioh_dir_shadow = 0; ++unsigned int idp_cpld_gpioh_value_shadow = 0; ++unsigned int idp_cpld_gpiol_dir_shadow = 0; ++unsigned int idp_cpld_gpiol_value_shadow = 0; ++ ++/* ++ * enable all LCD signals -- they should still be on ++ * write protect flash ++ * enable all serial port transceivers ++ */ ++ ++unsigned int idp_control_port_shadow = ((0x7 << 21) | /* LCD power */ ++ (0x1 << 19) | /* disable flash write enable */ ++ (0x7 << 9)); /* enable serial port transeivers */ ++ ++#endif ++ ++static int __init idp_init(void) ++{ ++ printk("idp_init()\n"); ++ return 0; ++} ++ ++__initcall(idp_init); ++ ++static void __init idp_init_irq(void) ++{ ++ pxa_init_irq(); ++} ++ ++static void __init ++fixup_idp(struct machine_desc *desc, struct param_struct *params, ++ char **cmdline, struct meminfo *mi) ++{ ++#ifdef PXA_IDP_REV02 ++ SET_BANK (0, 0xa0000000, 64*1024*1024); ++#else ++ SET_BANK (0, 0xa0000000, 32*1024*1024); ++#endif ++ mi->nr_banks = 1; ++#if 0 ++ setup_ramdisk (1, 0, 0, 8192); ++ setup_initrd (__phys_to_virt(0xa1000000), 4*1024*1024); ++ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); ++#endif ++} ++ ++static struct map_desc idp_io_desc[] __initdata = { ++ /* virtual physical length domain r w c b */ ++ ++ ++#ifndef PXA_IDP_REV02 ++ { IDP_CTRL_PORT_BASE, ++ IDP_CTRL_PORT_PHYS, ++ IDP_CTRL_PORT_SIZE, ++ DOMAIN_IO, ++ 0, 1, 0, 0 }, ++#endif ++ ++ { IDP_IDE_BASE, ++ IDP_IDE_PHYS, ++ IDP_IDE_SIZE, ++ DOMAIN_IO, ++ 0, 1, 0, 0 }, ++ { IDP_ETH_BASE, ++ IDP_ETH_PHYS, ++ IDP_ETH_SIZE, ++ DOMAIN_IO, ++ 0, 1, 0, 0 }, ++ { IDP_COREVOLT_BASE, ++ IDP_COREVOLT_PHYS, ++ IDP_COREVOLT_SIZE, ++ DOMAIN_IO, ++ 0, 1, 0, 0 }, ++ { IDP_CPLD_BASE, ++ IDP_CPLD_PHYS, ++ IDP_CPLD_SIZE, ++ DOMAIN_IO, ++ 0, 1, 0, 0 }, ++ ++ LAST_DESC ++}; ++ ++static void __init idp_map_io(void) ++{ ++ pxa_map_io(); ++ iotable_init(idp_io_desc); ++ ++ set_GPIO_IRQ_edge(IRQ_TO_GPIO(TOUCH_PANEL_IRQ), TOUCH_PANEL_IRQ_EDGE); ++ set_GPIO_IRQ_edge(IRQ_TO_GPIO(SMC_IRQ), GPIO_RISING_EDGE); ++} ++ ++MACHINE_START(PXA_IDP, "Accelent Xscale IDP") ++ MAINTAINER("Accelent Systems Inc.") ++ BOOT_MEM(0xa0000000, 0x40000000, 0xfc000000) ++ FIXUP(fixup_idp) ++ MAPIO(idp_map_io) ++ INITIRQ(idp_init_irq) ++MACHINE_END +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/innokom.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,129 @@ ++/* ++ * linux/arch/arm/mach-pxa/innokom.c ++ * ++ * (c) 2003 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix ++ * ++ * 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 <linux/init.h> ++#include <linux/major.h> ++#include <linux/fs.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++ ++#include <asm/types.h> ++#include <asm/setup.h> ++#include <asm/memory.h> ++#include <asm/mach-types.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/irq.h> ++#include <asm/arch/irqs.h> ++#include <asm/hardware/sa1111.h> ++ ++#include "generic.h" ++ ++ ++static void __init innokom_init_irq(void) ++{ ++ pxa_init_irq(); ++} ++ ++ ++void sw_update_handler( int irq, void* dev_id,struct pt_regs* regs) ++{ ++} ++ ++ ++void reset_handler( int irq, void* dev_id,struct pt_regs* regs) ++{ ++} ++ ++ ++static int __init innokom_init(void) ++{ ++ int sw_irq = GPIO_2_80_TO_IRQ(11); /* software update button */ ++ int reset_irq = GPIO_2_80_TO_IRQ(3); /* reset button */ ++ ++ set_GPIO_IRQ_edge(11,GPIO_FALLING_EDGE); ++ if (request_irq(sw_irq,sw_update_handler,SA_INTERRUPT,"software update button",NULL)) ++ printk(KERN_INFO "innokom: can't get assigned irq %i\n",sw_irq); ++ ++ set_GPIO_IRQ_edge(3,GPIO_FALLING_EDGE); ++ if (request_irq(reset_irq,reset_handler,SA_INTERRUPT,"reset button",NULL)) ++ printk(KERN_INFO "innokom: can't get assigned irq %i\n",reset_irq); ++ ++ return 0; ++} ++ ++ ++__initcall(innokom_init); ++ ++ ++static void __init ++fixup_innokom(struct machine_desc *desc, struct param_struct *params, ++ char **cmdline, struct meminfo *mi) ++{ ++ /* we probably want to get this information from the bootloader later */ ++ SET_BANK (0, 0xa0000000, 64*1024*1024); ++ mi->nr_banks = 1; ++} ++ ++ ++/* memory mapping */ ++static struct map_desc innokom_io_desc[] __initdata = { ++/* virtual physical length domain r w c b */ ++ { INNOKOM_ETH_BASE, INNOKOM_ETH_PHYS, INNOKOM_ETH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* ETH SMSC 91111 */ ++ LAST_DESC ++}; ++ ++static void __init innokom_map_io(void) ++{ ++ pxa_map_io(); ++ iotable_init(innokom_io_desc); ++ ++ /* Enable the BTUART */ ++ CKEN |= CKEN7_BTUART; ++ set_GPIO_mode(GPIO42_BTRXD_MD); ++ set_GPIO_mode(GPIO43_BTTXD_MD); ++ set_GPIO_mode(GPIO44_BTCTS_MD); ++ set_GPIO_mode(GPIO45_BTRTS_MD); ++ ++ set_GPIO_mode(GPIO33_nCS_5_MD); /* SMSC network chip */ ++ ++ /* setup sleep mode values */ ++ PWER = 0x00000002; ++ PFER = 0x00000000; ++ PRER = 0x00000002; ++ PGSR0 = 0x00008000; ++ PGSR1 = 0x003F0202; ++ PGSR2 = 0x0001C000; ++ PCFR |= PCFR_OPDE; ++} ++ ++MACHINE_START(INNOKOM, "Auerswald Innokom") ++ MAINTAINER("Robert Schwebel, Pengutronix") ++ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) ++ BOOT_PARAMS(0xa0000100) ++ FIXUP(fixup_innokom) ++ MAPIO(innokom_map_io) ++ INITIRQ(innokom_init_irq) ++MACHINE_END +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/irq.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,282 @@ ++/* ++ * linux/arch/arm/mach-pxa/irq.c ++ * ++ * Generic PXA IRQ handling, GPIO IRQ demultiplexing, etc. ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista 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 <linux/init.h> ++#include <linux/module.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/ptrace.h> ++ ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/mach/irq.h> ++#include <asm/arch/irq.h> ++ ++#include "generic.h" ++ ++ ++/* ++ * PXA GPIO edge detection for IRQs: ++ * IRQs are generated on Falling-Edge, Rising-Edge, or both. ++ * This must be called *before* the appropriate IRQ is registered. ++ * Use this instead of directly setting GRER/GFER. ++ */ ++ ++static int GPIO_IRQ_rising_edge[3]; ++static int GPIO_IRQ_falling_edge[3]; ++ ++void set_GPIO_IRQ_edge (int gpio_nr, int edge) ++{ ++ long flags; ++ local_irq_save(flags); ++ set_GPIO_mode(gpio_nr | GPIO_IN); ++ if (edge & GPIO_FALLING_EDGE) ++ set_bit (gpio_nr, GPIO_IRQ_falling_edge); ++ else ++ clear_bit (gpio_nr, GPIO_IRQ_falling_edge); ++ if (edge & GPIO_RISING_EDGE) ++ set_bit (gpio_nr, GPIO_IRQ_rising_edge); ++ else ++ clear_bit (gpio_nr, GPIO_IRQ_rising_edge); ++ irq_desc[IRQ_GPIO(gpio_nr)].valid = 1; ++ local_irq_restore(flags); ++} ++ ++EXPORT_SYMBOL(set_GPIO_IRQ_edge); ++ ++ ++/* ++ * We don't need to ACK IRQs on the PXA unless they're GPIOs ++ * this is for IRQs known as PXA_IRQ([10...31]). ++ */ ++ ++static void pxa_mask_irq(unsigned int irq) ++{ ++ ICMR &= ~(1 << (irq + PXA_IRQ_SKIP)); ++} ++ ++static void pxa_unmask_irq(unsigned int irq) ++{ ++ ICMR |= (1 << (irq + PXA_IRQ_SKIP)); ++} ++ ++/* ++ * GPIO IRQs must be acknoledged. This is for GPIO 0 and 1. ++ */ ++ ++static void pxa_mask_and_ack_GPIO_0_1_irq(unsigned int irq) ++{ ++ ICMR &= ~(1 << (irq + PXA_IRQ_SKIP)); ++ GEDR0 = (1 << (irq - IRQ_GPIO0)); ++} ++ ++static void pxa_mask_GPIO_0_1_irq(unsigned int irq) ++{ ++ ICMR &= ~(1 << (irq + PXA_IRQ_SKIP)); ++} ++ ++static void pxa_unmask_GPIO_0_1_irq(unsigned int irq) ++{ ++ int gpio = irq - IRQ_GPIO0; ++ GRER0 = (GRER0 & ~(1 << gpio))|(GPIO_IRQ_rising_edge[0] & (1 << gpio)); ++ GFER0 = (GFER0 & ~(1 << gpio))|(GPIO_IRQ_falling_edge[0] & (1 << gpio)); ++ ICMR |= (1 << (irq + PXA_IRQ_SKIP)); ++} ++ ++/* ++ * Demux handler for GPIO 2-80 edge detect interrupts ++ */ ++ ++static int GPIO_2_80_enabled[3]; /* enabled i.e. unmasked GPIO IRQs */ ++static int GPIO_2_80_spurious[3]; /* GPIOs that triggered when masked */ ++ ++static void pxa_GPIO_2_80_demux(int irq, void *dev_id, ++ struct pt_regs *regs) ++{ ++ int i, gedr, spurious; ++ ++ while ((gedr = (GEDR0 & ~3))) { ++ /* ++ * We don't want to clear GRER/GFER when the corresponding ++ * IRQ is masked because we could miss a level transition ++ * i.e. an IRQ which need servicing as soon as it is ++ * unmasked. However, such situation should happen only ++ * during the loop below. Thus all IRQs which aren't ++ * enabled at this point are considered spurious. Those ++ * are cleared but only de-activated if they happen twice. ++ */ ++ spurious = gedr & ~GPIO_2_80_enabled[0]; ++ if (spurious) { ++ GEDR0 = spurious; ++ GRER0 &= ~(spurious & GPIO_2_80_spurious[0]); ++ GFER0 &= ~(spurious & GPIO_2_80_spurious[0]); ++ GPIO_2_80_spurious[0] |= spurious; ++ gedr ^= spurious; ++ if (!gedr) continue; ++ } ++ ++ for (i = 2; i < 32; ++i) { ++ if (gedr & (1<<i)) { ++ do_IRQ (IRQ_GPIO(2) + i - 2, regs); ++ } ++ } ++ } ++ while ((gedr = GEDR1)) { ++ spurious = gedr & ~GPIO_2_80_enabled[1]; ++ if (spurious) { ++ GEDR1 = spurious; ++ GRER1 &= ~(spurious & GPIO_2_80_spurious[1]); ++ GFER1 &= ~(spurious & GPIO_2_80_spurious[1]); ++ GPIO_2_80_spurious[1] |= spurious; ++ gedr ^= spurious; ++ if (!gedr) continue; ++ } ++ ++ for (i = 0; i < 32; ++i) { ++ if (gedr & (1<<i)) { ++ do_IRQ (IRQ_GPIO(32) + i, regs); ++ } ++ } ++ } ++ while ((gedr = (GEDR2 & 0x0001ffff))) { ++ spurious = gedr & ~GPIO_2_80_enabled[2]; ++ if (spurious) { ++ GEDR2 = spurious; ++ GRER2 &= ~(spurious & GPIO_2_80_spurious[2]); ++ GFER2 &= ~(spurious & GPIO_2_80_spurious[2]); ++ GPIO_2_80_spurious[2] |= spurious; ++ gedr ^= spurious; ++ if (!gedr) continue; ++ } ++ ++ for (i = 0; i < 17; ++i) { ++ if (gedr & (1<<i)) { ++ do_IRQ (IRQ_GPIO(64) + i, regs); ++ } ++ } ++ } ++} ++ ++static struct irqaction GPIO_2_80_irqaction = { ++ name: "GPIO 2-80", ++ handler: pxa_GPIO_2_80_demux, ++ flags: SA_INTERRUPT ++}; ++ ++#define GRER_x(i) (*(&GRER0 + (i))) ++#define GFER_x(i) (*(&GFER0 + (i))) ++#define GEDR_x(i) (*(&GEDR0 + (i))) ++#define GPLR_x(i) (*(&GPLR0 + (i))) ++ ++static void pxa_mask_and_ack_GPIO_2_80_irq(unsigned int irq) ++{ ++ int gpio_nr = IRQ_TO_GPIO_2_80(irq); ++ int mask = 1 << (gpio_nr & 0x1f); ++ int index = gpio_nr >> 5; ++ GPIO_2_80_spurious[index] &= ~mask; ++ GPIO_2_80_enabled[index] &= ~mask; ++ GEDR_x(index) = mask; ++} ++ ++static void pxa_mask_GPIO_2_80_irq(unsigned int irq) ++{ ++ int gpio_nr = IRQ_TO_GPIO_2_80(irq); ++ int mask = 1 << (gpio_nr & 0x1f); ++ int index = gpio_nr >> 5; ++ GPIO_2_80_spurious[index] &= ~mask; ++ GPIO_2_80_enabled[index] &= ~mask; ++} ++ ++static void pxa_unmask_GPIO_2_80_irq(unsigned int irq) ++{ ++ int gpio_nr = IRQ_TO_GPIO_2_80(irq); ++ int mask = 1 << (gpio_nr & 0x1f); ++ int index = gpio_nr >> 5; ++ if (GPIO_2_80_spurious[index] & mask) { ++ /* ++ * We don't want to miss an interrupt that would have occurred ++ * while it was masked. Simulate it if it is the case. ++ */ ++ int state = GPLR_x(index); ++ if (((state & GPIO_IRQ_rising_edge[index]) | ++ (~state & GPIO_IRQ_falling_edge[index])) & mask) ++ { ++ /* just in case it gets referenced: */ ++ struct pt_regs dummy; ++ ++ memzero(&dummy, sizeof(dummy)); ++ do_IRQ(irq, &dummy); ++ ++ /* we are being called recursively from do_IRQ() */ ++ return; ++ } ++ } ++ GPIO_2_80_enabled[index] |= mask; ++ GRER_x(index) = ++ (GRER_x(index) & ~mask) | (GPIO_IRQ_rising_edge[index] & mask); ++ GFER_x(index) = ++ (GFER_x(index) & ~mask) | (GPIO_IRQ_falling_edge[index] & mask); ++} ++ ++ ++void __init pxa_init_irq(void) ++{ ++ int irq; ++ ++ /* disable all IRQs */ ++ ICMR = 0; ++ ++ /* all IRQs are IRQ, not FIQ */ ++ ICLR = 0; ++ ++ /* clear all GPIO edge detects */ ++ GFER0 = GFER1 = GFER2 = 0; ++ GRER0 = GRER1 = GRER2 = 0; ++ GEDR0 = GEDR0; ++ GEDR1 = GEDR1; ++ GEDR2 = GEDR2; ++ ++ /* only unmasked interrupts kick us out of idle */ ++ ICCR = 1; ++ ++ for (irq = PXA_IRQ(PXA_IRQ_SKIP); irq <= PXA_IRQ(31); irq++) { ++ irq_desc[irq].valid = 1; ++ irq_desc[irq].probe_ok = 0; ++ irq_desc[irq].mask_ack = pxa_mask_irq; ++ irq_desc[irq].mask = pxa_mask_irq; ++ irq_desc[irq].unmask = pxa_unmask_irq; ++ } ++ ++ /* ++ * Note: GPIO IRQs are initially invalid until set_GPIO_IRQ_edge() ++ * is called at least once. ++ */ ++ ++ for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) { ++ irq_desc[irq].valid = 0; ++ irq_desc[irq].probe_ok = 1; ++ irq_desc[irq].mask_ack = pxa_mask_and_ack_GPIO_0_1_irq; ++ irq_desc[irq].mask = pxa_mask_GPIO_0_1_irq; ++ irq_desc[irq].unmask = pxa_unmask_GPIO_0_1_irq; ++ } ++ ++ for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(80); irq++) { ++ irq_desc[irq].valid = 0; ++ irq_desc[irq].probe_ok = 1; ++ irq_desc[irq].mask_ack = pxa_mask_and_ack_GPIO_2_80_irq; ++ irq_desc[irq].mask = pxa_mask_GPIO_2_80_irq; ++ irq_desc[irq].unmask = pxa_unmask_GPIO_2_80_irq; ++ } ++ setup_arm_irq( IRQ_GPIO_2_80, &GPIO_2_80_irqaction ); ++} +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/leds-cerf.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,135 @@ ++/* ++ * linux/arch/arm/mach-pxa/leds-cerf.c ++ * ++ * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu> ++ * ++ * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com> ++ * ++ * Original (leds-footbridge.c) by Russell King ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++ ++#include <linux/config.h> ++#include <linux/init.h> ++ ++#include <asm/hardware.h> ++#include <asm/leds.h> ++#include <asm/system.h> ++ ++#include "leds.h" ++ ++ ++#define LED_STATE_ENABLED 1 ++#define LED_STATE_CLAIMED 2 ++ ++static unsigned int led_state; ++static unsigned int hw_led_state; ++ ++void pxa_cerf_leds_event(led_event_t evt) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ switch (evt) { ++ case led_start: ++ hw_led_state = CERF_HEARTBEAT_LED; ++ led_state = LED_STATE_ENABLED; ++ break; ++ ++ case led_stop: ++ led_state &= ~LED_STATE_ENABLED; ++ break; ++ ++ case led_claim: ++ led_state |= LED_STATE_CLAIMED; ++ hw_led_state = CERF_HEARTBEAT_LED; ++ break; ++ ++ case led_release: ++ led_state &= ~LED_STATE_CLAIMED; ++ hw_led_state = CERF_HEARTBEAT_LED; ++ break; ++ ++#ifdef CONFIG_LEDS_TIMER ++ case led_timer: ++ if (!(led_state & LED_STATE_CLAIMED)) ++ hw_led_state ^= CERF_HEARTBEAT_LED; ++ break; ++#endif ++ ++#ifdef CONFIG_LEDS_CPU ++ case led_idle_start: ++ if (!(led_state & LED_STATE_CLAIMED)) ++ hw_led_state |= CERF_SYS_BUSY_LED; ++ break; ++ ++ case led_idle_end: ++ if (!(led_state & LED_STATE_CLAIMED)) ++ hw_led_state &= ~CERF_SYS_BUSY_LED; ++ break; ++#endif ++ ++ case led_halted: ++ break; ++ ++ case led_green_on: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state &= ~CERF_HEARTBEAT_LED; ++ break; ++ ++ case led_green_off: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state |= CERF_HEARTBEAT_LED; ++ break; ++ ++ case led_amber_on: ++ break; ++ ++ case led_amber_off: ++ break; ++ ++#ifndef CONFIG_PXA_CERF_PDA ++ case led_red_on: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state &= ~CERF_SYS_BUSY_LED; ++ break; ++ ++ case led_red_off: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state |= CERF_SYS_BUSY_LED; ++ break; ++#endif ++ default: ++ break; ++ } ++ ++ if (led_state & LED_STATE_ENABLED) ++ { ++ switch (hw_led_state) { ++ case 0: // all on ++ CERF_HEARTBEAT_LED_ON; ++ CERF_SYS_BUSY_LED_ON; ++ break; ++ case 1: // turn off heartbeat, status on: ++ CERF_HEARTBEAT_LED_OFF; ++ CERF_SYS_BUSY_LED_ON; ++ break; ++ case 2: // status off, heartbeat on: ++ CERF_HEARTBEAT_LED_ON; ++ CERF_SYS_BUSY_LED_OFF; ++ break; ++ case 3: // turn them both off... ++ CERF_HEARTBEAT_LED_OFF; ++ CERF_SYS_BUSY_LED_OFF; ++ break; ++ default: ++ break; ++ } ++ } ++ local_irq_restore(flags); ++} +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/leds-idp.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,112 @@ ++/* ++ * linux/arch/arm/mach-pxa/leds-idp.c ++ * ++ * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu> ++ * ++ * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com> ++ * ++ * Original (leds-footbridge.c) by Russell King ++ * ++ * Macros for actual LED manipulation should be in machine specific ++ * files in this 'mach' directory. ++ */ ++ ++ ++#include <linux/config.h> ++#include <linux/init.h> ++ ++#include <asm/hardware.h> ++#include <asm/leds.h> ++#include <asm/system.h> ++ ++#include "leds.h" ++ ++#define LED_STATE_ENABLED 1 ++#define LED_STATE_CLAIMED 2 ++ ++static unsigned int led_state; ++static unsigned int hw_led_state; ++ ++void idp_leds_event(led_event_t evt) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ switch (evt) { ++ case led_start: ++ hw_led_state = IDP_HB_LED | IDP_BUSY_LED; ++ led_state = LED_STATE_ENABLED; ++ break; ++ ++ case led_stop: ++ led_state &= ~LED_STATE_ENABLED; ++ break; ++ ++ case led_claim: ++ led_state |= LED_STATE_CLAIMED; ++ hw_led_state = IDP_HB_LED | IDP_BUSY_LED; ++ break; ++ ++ case led_release: ++ led_state &= ~LED_STATE_CLAIMED; ++ hw_led_state = IDP_HB_LED | IDP_BUSY_LED; ++ break; ++ ++#ifdef CONFIG_LEDS_TIMER ++ case led_timer: ++ if (!(led_state & LED_STATE_CLAIMED)) ++ hw_led_state ^= IDP_HB_LED; ++ break; ++#endif ++ ++#ifdef CONFIG_LEDS_CPU ++ case led_idle_start: ++ if (!(led_state & LED_STATE_CLAIMED)) ++ hw_led_state |= IDP_BUSY_LED; ++ break; ++ ++ case led_idle_end: ++ if (!(led_state & LED_STATE_CLAIMED)) ++ hw_led_state &= ~IDP_BUSY_LED; ++ break; ++#endif ++ ++ case led_halted: ++ break; ++ ++ case led_green_on: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state &= ~IDP_HB_LED; ++ break; ++ ++ case led_green_off: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state |= IDP_HB_LED; ++ break; ++ ++ case led_amber_on: ++ break; ++ ++ case led_amber_off: ++ break; ++ ++ case led_red_on: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state &= ~IDP_BUSY_LED; ++ break; ++ ++ case led_red_off: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state |= IDP_BUSY_LED; ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (led_state & LED_STATE_ENABLED) ++ IDP_WRITE_LEDS(hw_led_state); ++ ++ local_irq_restore(flags); ++} +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/leds-lubbock.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,134 @@ ++/* ++ * linux/arch/arm/mach-pxa/leds-lubbock.c ++ * ++ * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu> ++ * ++ * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com> ++ * ++ * Original (leds-footbridge.c) by Russell King ++ * ++ * See leds.h for bit definitions. The first version defines D28 on the ++ * Lubbock dev board as the heartbeat, and D27 as the Sys_busy led. ++ * There's plenty more if you're interested in adding them :) ++ */ ++ ++ ++#include <linux/config.h> ++#include <linux/init.h> ++ ++#include <asm/hardware.h> ++#include <asm/leds.h> ++#include <asm/system.h> ++ ++#include "leds.h" ++ ++ ++#define LED_STATE_ENABLED 1 ++#define LED_STATE_CLAIMED 2 ++ ++static unsigned int led_state; ++static unsigned int hw_led_state; ++ ++void lubbock_leds_event(led_event_t evt) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ switch (evt) { ++ case led_start: ++ hw_led_state = HEARTBEAT_LED | SYS_BUSY_LED; ++ led_state = LED_STATE_ENABLED; ++ break; ++ ++ case led_stop: ++ led_state &= ~LED_STATE_ENABLED; ++ break; ++ ++ case led_claim: ++ led_state |= LED_STATE_CLAIMED; ++ hw_led_state = HEARTBEAT_LED | SYS_BUSY_LED; ++ break; ++ ++ case led_release: ++ led_state &= ~LED_STATE_CLAIMED; ++ hw_led_state = HEARTBEAT_LED | SYS_BUSY_LED; ++ break; ++ ++#ifdef CONFIG_LEDS_TIMER ++ case led_timer: ++ if (!(led_state & LED_STATE_CLAIMED)) ++ hw_led_state ^= HEARTBEAT_LED; ++ break; ++#endif ++ ++#ifdef CONFIG_LEDS_CPU ++ case led_idle_start: ++ if (!(led_state & LED_STATE_CLAIMED)) ++ hw_led_state |= SYS_BUSY_LED; ++ break; ++ ++ case led_idle_end: ++ if (!(led_state & LED_STATE_CLAIMED)) ++ hw_led_state &= ~SYS_BUSY_LED; ++ break; ++#endif ++ ++ case led_halted: ++ break; ++ ++ case led_green_on: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state &= ~HEARTBEAT_LED; ++ break; ++ ++ case led_green_off: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state |= HEARTBEAT_LED; ++ break; ++ ++ case led_amber_on: ++ break; ++ ++ case led_amber_off: ++ break; ++ ++ case led_red_on: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state &= ~SYS_BUSY_LED; ++ break; ++ ++ case led_red_off: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state |= SYS_BUSY_LED; ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (led_state & LED_STATE_ENABLED) ++ { ++ switch (hw_led_state) { ++ case 0: // all on ++ HEARTBEAT_LED_ON; ++ SYS_BUSY_LED_ON; ++ break; ++ case 1: // turn off heartbeat, status on: ++ HEARTBEAT_LED_OFF; ++ SYS_BUSY_LED_ON; ++ break; ++ case 2: // status off, heartbeat on: ++ HEARTBEAT_LED_ON; ++ SYS_BUSY_LED_OFF; ++ break; ++ case 3: // turn them both off... ++ HEARTBEAT_LED_OFF; ++ SYS_BUSY_LED_OFF; ++ break; ++ default: ++ break; ++ } ++ } ++ local_irq_restore(flags); ++} +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/leds.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,32 @@ ++/* ++ * linux/arch/arm/mach-pxa/leds.c ++ * ++ * xscale LEDs dispatcher ++ * ++ * Copyright (C) 2001 Nicolas Pitre ++ * ++ * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc. ++ */ ++#include <linux/config.h> ++#include <linux/init.h> ++ ++#include <asm/leds.h> ++#include <asm/mach-types.h> ++ ++#include "leds.h" ++ ++static int __init ++pxa_leds_init(void) ++{ ++ if (machine_is_lubbock()) ++ leds_event = lubbock_leds_event; ++ if (machine_is_pxa_idp()) ++ leds_event = idp_leds_event; ++ if (machine_is_pxa_cerf()) ++ leds_event = pxa_cerf_leds_event; ++ ++ leds_event(led_start); ++ return 0; ++} ++ ++__initcall(pxa_leds_init); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/leds.h 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,12 @@ ++/* ++ * include/asm-arm/arch-pxa/leds.h ++ * ++ * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc. ++ * ++ * blinky lights for various PXA-based systems: ++ * ++ */ ++ ++extern void lubbock_leds_event(led_event_t evt); ++extern void idp_leds_event(led_event_t evt); ++extern void pxa_cerf_leds_event(led_event_t evt); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/lubbock.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,157 @@ ++/* ++ * linux/arch/arm/mach-pxa/lubbock.c ++ * ++ * Support for the Intel DBPXA250 Development Platform. ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista 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 <linux/init.h> ++#include <linux/major.h> ++#include <linux/fs.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++#include <linux/bitops.h> ++ ++#include <asm/types.h> ++#include <asm/setup.h> ++#include <asm/memory.h> ++#include <asm/mach-types.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/irq.h> ++#include <asm/hardware/sa1111.h> ++ ++#include "generic.h" ++ ++#ifdef CONFIG_SA1111 ++ #include "sa1111.h" ++#endif ++ ++ ++static unsigned long lubbock_irq_enabled; ++ ++static void lubbock_mask_irq(unsigned int irq) ++{ ++ int lubbock_irq = (irq - LUBBOCK_IRQ(0)); ++ LUB_IRQ_MASK_EN = (lubbock_irq_enabled &= ~(1 << lubbock_irq)); ++} ++ ++static void lubbock_unmask_irq(unsigned int irq) ++{ ++ int lubbock_irq = (irq - LUBBOCK_IRQ(0)); ++ /* the irq can be acknowledged only if deasserted, so it's done here */ ++ LUB_IRQ_SET_CLR &= ~(1 << lubbock_irq); ++ LUB_IRQ_MASK_EN = (lubbock_irq_enabled |= (1 << lubbock_irq)); ++} ++ ++void lubbock_irq_demux(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ unsigned long pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled; ++ do { ++ GEDR(0) = GPIO_bit(0); /* clear useless edge notification */ ++ if (likely(pending)) ++ do_IRQ( LUBBOCK_IRQ(0) + __ffs(pending), regs ); ++ pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled; ++ } while (pending); ++} ++ ++static struct irqaction lubbock_irq = { ++ name: "Lubbock FPGA", ++ handler: lubbock_irq_demux, ++ flags: SA_INTERRUPT ++}; ++ ++static void __init lubbock_init_irq(void) ++{ ++ int irq; ++ ++ pxa_init_irq(); ++ ++ /* setup extra lubbock irqs */ ++ for(irq = LUBBOCK_IRQ(0); irq <= LUBBOCK_LAST_IRQ; irq++) { ++ irq_desc[irq].valid = 1; ++ irq_desc[irq].probe_ok = 1; ++ irq_desc[irq].mask_ack = lubbock_mask_irq; ++ irq_desc[irq].mask = lubbock_mask_irq; ++ irq_desc[irq].unmask = lubbock_unmask_irq; ++ } ++ ++ set_GPIO_IRQ_edge(GPIO_LUBBOCK_IRQ, GPIO_FALLING_EDGE); ++ setup_arm_irq(IRQ_GPIO_LUBBOCK_IRQ, &lubbock_irq); ++} ++ ++static int __init lubbock_init(void) ++{ ++ int ret; ++ ++ ret = sa1111_probe(LUBBOCK_SA1111_BASE); ++ if (ret) ++ return ret; ++ sa1111_wake(); ++ sa1111_init_irq(LUBBOCK_SA1111_IRQ); ++ return 0; ++} ++ ++__initcall(lubbock_init); ++ ++static void __init ++fixup_lubbock(struct machine_desc *desc, struct param_struct *params, ++ char **cmdline, struct meminfo *mi) ++{ ++ /* Some boards have 32MB some 64MB. Let's use a safe default */ ++ SET_BANK (0, 0xa0000000, 32*1024*1024); ++ mi->nr_banks = 1; ++} ++ ++static struct map_desc lubbock_io_desc[] __initdata = { ++ /* virtual physical length domain r w c b */ ++ { 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */ ++ { 0xf1000000, 0x0c000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 IO */ ++ { 0xf1100000, 0x0e000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 Attr */ ++ { 0xf4000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA1111 */ ++ LAST_DESC ++}; ++ ++static void __init lubbock_map_io(void) ++{ ++ pxa_map_io(); ++ iotable_init(lubbock_io_desc); ++ ++ /* This enables the BTUART */ ++ CKEN |= CKEN7_BTUART; ++ set_GPIO_mode(GPIO42_BTRXD_MD); ++ set_GPIO_mode(GPIO43_BTTXD_MD); ++ set_GPIO_mode(GPIO44_BTCTS_MD); ++ set_GPIO_mode(GPIO45_BTRTS_MD); ++ ++ /* This is for the SMC chip select */ ++ set_GPIO_mode(GPIO79_nCS_3_MD); ++ ++ /* setup sleep mode values */ ++ PWER = 0x00000002; ++ PFER = 0x00000000; ++ PRER = 0x00000002; ++ PGSR0 = 0x00008000; ++ PGSR1 = 0x003F0202; ++ PGSR2 = 0x0001C000; ++ PCFR |= PCFR_OPDE; ++} ++ ++MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform") ++ MAINTAINER("MontaVista Software Inc.") ++ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) ++ FIXUP(fixup_lubbock) ++ MAPIO(lubbock_map_io) ++ INITIRQ(lubbock_init_irq) ++MACHINE_END +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/pm.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,265 @@ ++/* ++ * PXA250/210 Power Management Routines ++ * ++ * Original code for the SA11x0: ++ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> ++ * ++ * Modified for the PXA250 by Nicolas Pitre: ++ * Copyright (c) 2002 Monta Vista Software, Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License. ++ */ ++ ++#include <linux/config.h> ++#include <linux/init.h> ++#include <linux/pm.h> ++#include <linux/slab.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/sysctl.h> ++#include <linux/errno.h> ++ ++#include <asm/hardware.h> ++#include <asm/memory.h> ++#include <asm/system.h> ++#include <asm/leds.h> ++ ++ ++/* ++ * Debug macros ++ */ ++#undef DEBUG ++ ++extern void pxa_cpu_suspend(void); ++extern void pxa_cpu_resume(void); ++ ++#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x ++#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] ++ ++/* ++ * List of global PXA peripheral registers to preserve. ++ * More ones like CP and general purpose register values are preserved ++ * with the stack pointer in sleep.S. ++ */ ++enum { SLEEP_SAVE_START = 0, ++ ++ SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER, ++ SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3, ++ ++ SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, ++ SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, ++ SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, ++ SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR2_L, ++ SLEEP_SAVE_GAFR0_U, SLEEP_SAVE_GAFR1_U, SLEEP_SAVE_GAFR2_U, ++ ++ SLEEP_SAVE_FFIER, SLEEP_SAVE_FFLCR, SLEEP_SAVE_FFMCR, ++ SLEEP_SAVE_FFSPR, SLEEP_SAVE_FFISR, ++ SLEEP_SAVE_FFDLL, SLEEP_SAVE_FFDLH, ++ ++ SLEEP_SAVE_ICMR, ++ SLEEP_SAVE_CKEN, ++ ++ SLEEP_SAVE_CKSUM, ++ ++ SLEEP_SAVE_SIZE ++}; ++ ++ ++int pm_do_suspend(void) ++{ ++ unsigned long sleep_save[SLEEP_SAVE_SIZE]; ++ unsigned long checksum = 0; ++ int i; ++ ++ cli(); ++ clf(); ++ ++ leds_event(led_stop); ++ ++ /* preserve current time */ ++ RCNR = xtime.tv_sec; ++ ++ /* ++ * Temporary solution. This won't be necessary once ++ * we move pxa support into the serial/* driver ++ * Save the FF UART ++ */ ++ SAVE(FFIER); ++ SAVE(FFLCR); ++ SAVE(FFMCR); ++ SAVE(FFSPR); ++ SAVE(FFISR); ++ FFLCR |= 0x80; ++ SAVE(FFDLL); ++ SAVE(FFDLH); ++ FFLCR &= 0xef; ++ ++ /* save vital registers */ ++ SAVE(OSCR); ++ SAVE(OSMR0); ++ SAVE(OSMR1); ++ SAVE(OSMR2); ++ SAVE(OSMR3); ++ SAVE(OIER); ++ ++ SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); ++ SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); ++ SAVE(GFER0); SAVE(GFER1); SAVE(GFER2); ++ SAVE(GAFR0_L); SAVE(GAFR0_U); ++ SAVE(GAFR1_L); SAVE(GAFR1_U); ++ SAVE(GAFR2_L); SAVE(GAFR2_U); ++ ++ SAVE(ICMR); ++ ICMR = 0; ++ ++ SAVE(CKEN); ++ CKEN = 0; ++ ++ /* Note: wake up source are set up in each machine specific files */ ++ ++ /* clear GPIO transition detect bits */ ++ GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2; ++ ++ /* Clear sleep reset status */ ++ RCSR = RCSR_SMR; ++ ++ /* set resume return address */ ++ PSPR = virt_to_phys(pxa_cpu_resume); ++ ++ /* before sleeping, calculate and save a checksum */ ++ for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++) ++ checksum += sleep_save[i]; ++ sleep_save[SLEEP_SAVE_CKSUM] = checksum; ++ ++ /* *** go zzz *** */ ++ pxa_cpu_suspend(); ++ ++ /* after sleeping, validate the checksum */ ++ checksum = 0; ++ for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++) ++ checksum += sleep_save[i]; ++ ++ /* if invalid, display message and wait for a hardware reset */ ++ if (checksum != sleep_save[SLEEP_SAVE_CKSUM]) { ++#ifdef CONFIG_ARCH_LUBBOCK ++ LUB_HEXLED = 0xbadbadc5; ++#endif ++ while (1); ++ } ++ ++ /* ensure not to come back here if it wasn't intended */ ++ PSPR = 0; ++ ++ /* restore registers */ ++ RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2); ++ RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); ++ RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); ++ RESTORE(GAFR0_L); RESTORE(GAFR0_U); ++ RESTORE(GAFR1_L); RESTORE(GAFR1_U); ++ RESTORE(GAFR2_L); RESTORE(GAFR2_U); ++ ++ PSSR = PSSR_PH; ++ ++ RESTORE(OSMR0); ++ RESTORE(OSMR1); ++ RESTORE(OSMR2); ++ RESTORE(OSMR3); ++ RESTORE(OSCR); ++ RESTORE(OIER); ++ ++ RESTORE(CKEN); ++ ++ ICLR = 0; ++ ICCR = 1; ++ RESTORE(ICMR); ++ ++ /* ++ * Temporary solution. This won't be necessary once ++ * we move pxa support into the serial/* driver. ++ * Restore the FF UART. ++ */ ++ RESTORE(FFMCR); ++ RESTORE(FFSPR); ++ RESTORE(FFLCR); ++ FFLCR |= 0x80; ++ RESTORE(FFDLH); ++ RESTORE(FFDLL); ++ RESTORE(FFLCR); ++ RESTORE(FFISR); ++ FFFCR = 0x07; ++ RESTORE(FFIER); ++ ++ /* restore current time */ ++ xtime.tv_sec = RCNR; ++ ++#ifdef DEBUG ++ printk(KERN_DEBUG "*** made it back from resume\n"); ++#endif ++ ++ leds_event(led_start); ++ ++ sti(); ++ ++ return 0; ++} ++ ++unsigned long sleep_phys_sp(void *sp) ++{ ++ return virt_to_phys(sp); ++} ++ ++#ifdef CONFIG_SYSCTL ++/* ++ * ARGH! ACPI people defined CTL_ACPI in linux/acpi.h rather than ++ * linux/sysctl.h. ++ * ++ * This means our interface here won't survive long - it needs a new ++ * interface. Quick hack to get this working - use sysctl id 9999. ++ */ ++#warning ACPI broke the kernel, this interface needs to be fixed up. ++#define CTL_ACPI 9999 ++#define ACPI_S1_SLP_TYP 19 ++ ++/* ++ * Send us to sleep. ++ */ ++static int sysctl_pm_do_suspend(void) ++{ ++ int retval; ++ ++ retval = pm_send_all(PM_SUSPEND, (void *)3); ++ ++ if (retval == 0) { ++ retval = pm_do_suspend(); ++ ++ pm_send_all(PM_RESUME, (void *)0); ++ } ++ ++ return retval; ++} ++ ++static struct ctl_table pm_table[] = ++{ ++ {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&sysctl_pm_do_suspend}, ++ {0} ++}; ++ ++static struct ctl_table pm_dir_table[] = ++{ ++ {CTL_ACPI, "pm", NULL, 0, 0555, pm_table}, ++ {0} ++}; ++ ++/* ++ * Initialize power interface ++ */ ++static int __init pm_init(void) ++{ ++ register_sysctl_table(pm_dir_table, 1); ++ return 0; ++} ++ ++__initcall(pm_init); ++ ++#endif +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/pxa_usb.h 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,230 @@ ++/* ++ * pxa_usb.h ++ * ++ * Public interface to the pxa USB core. For use by client modules ++ * like usb-eth and usb-char. ++ * ++ * 02-May-2002 ++ * Frank Becker (Intrinsyc) - derived from sa1100_usb.h ++ * ++ */ ++ ++#ifndef _PXA_USB_H ++#define _PXA_USB_H ++#include <asm/byteorder.h> ++ ++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 pxa_usb_open( const char * client_name ); ++ ++// Start UDC running ++int pxa_usb_start( void ); ++ ++// Immediately stop udc, fire off completion routines w/-EINTR ++int pxa_usb_stop( void ) ; ++ ++// Disconnect client from usb core ++int pxa_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 pxa_set_configured_callback( usb_notify_t callback ); ++ ++/* in usb_send.c */ ++int pxa_usb_xmitter_avail( void ); ++int pxa_usb_send(char *buf, int len, usb_callback_t callback); ++void sa110a_usb_send_reset(void); ++ ++/* in usb_recev.c */ ++int pxa_usb_recv(char *buf, int len, usb_callback_t callback); ++void pxa_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, ++ USB_EP_ISO =4 ++}; ++ ++// --- 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 ++ */ ++ ++enum { ++ UNUSED = 0, ++ ++ BULK_IN1 = 1, ++ BULK_OUT1 = 2, ++ ISO_IN1 = 3, ++ ISO_OUT1 = 4, ++ INT_IN1 = 5, ++ ++ BULK_IN2 = 6, ++ BULK_OUT2 = 7, ++ ISO_IN2 = 8, ++ ISO_OUT2 = 9, ++ INT_IN2 = 10, ++ ++ BULK_IN3 = 11, ++ BULK_OUT3 = 12, ++ ISO_IN3 = 13, ++ ISO_OUT3 = 14, ++ INT_IN3 = 15 ++} /*endpoint_type*/; ++ ++/* "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 pxa_usb_open() and pxa_usb_start() ++*/ ++desc_t * ++pxa_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 pxa_usb_set_string_descriptor( int index, string_desc_t * p ); ++ ++/* reverse of above */ ++string_desc_t * ++pxa_usb_get_string_descriptor( int index ); ++ ++/* kmalloc() a string descriptor and convert "p" to unicode in it */ ++string_desc_t * ++pxa_usb_kmalloc_string_descriptor( const char * p ); ++ ++#endif /* _PXA_USB_H */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/sa1111.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,3 @@ ++#include "../mach-sa1100/sa1111.c" ++ ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/sa1111.h 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,2 @@ ++#include "../mach-sa1100/sa1111.h" ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/sleep.S 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,150 @@ ++/* ++ * Low-level PXA250/210 sleep/wakeUp support ++ * ++ * Initial SA1110 code: ++ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> ++ * ++ * Adapted for PXA by Nicolas Pitre: ++ * Copyright (c) 2002 Monta Vista Software, Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License. ++ */ ++ ++#include <linux/config.h> ++#include <linux/linkage.h> ++#include <asm/assembler.h> ++#include <asm/hardware.h> ++ ++ .text ++ ++/* ++ * pxa_cpu_suspend() ++ * ++ * Forces CPU into sleep state ++ */ ++ ++ENTRY(pxa_cpu_suspend) ++ ++ mra r2, r3, acc0 ++ stmfd sp!, {r2 - r12, lr} @ save registers on stack ++ ++ @ get coprocessor registers ++ mrc p15, 0, r4, c15, c1, 0 @ CP access reg ++ mrc p15, 0, r5, c13, c0, 0 @ PID ++ mrc p15, 0, r6, c3, c0, 0 @ domain ID ++ mrc p15, 0, r7, c2, c0, 0 @ translation table base addr ++ mrc p15, 0, r8, c1, c1, 0 @ auxiliary control reg ++ mrc p15, 0, r9, c1, c0, 0 @ control reg ++ ++ @ store them plus current virtual stack ptr on stack ++ mov r10, sp ++ stmfd sp!, {r4 - r10} ++ ++ @ preserve phys address of stack ++ mov r0, sp ++ bl sleep_phys_sp ++ ldr r1, =sleep_save_sp ++ str r0, [r1] ++ ++ @ clean data cache ++ bl cpu_xscale_cache_clean_invalidate_all ++ ++ @ Put the processor to sleep ++ @ (also workaround for sighting 28071) ++ ++ @ prepare value for sleep mode ++ mov r1, #3 @ sleep mode ++ ++ @ prepare to put SDRAM into self-refresh manually ++ ldr r4, =MDREFR ++ ldr r5, [r4] ++ orr r5, r5, #MDREFR_SLFRSH ++ ++ @ prepare pointer to physical address 0 (virtual mapping in generic.c) ++ mov r2, #UNCACHED_PHYS_0 ++ ++ @ align execution to a cache line ++ b 1f ++ ++ .ltorg ++ .align 5 ++1: ++ ++ @ All needed values are now in registers. ++ @ These last instructions should be in cache ++ ++ @ put SDRAM into self-refresh ++ str r5, [r4] ++ ++ @ force address lines low by reading at physical address 0 ++ ldr r3, [r2] ++ ++ @ enter sleep mode ++ mcr p14, 0, r1, c7, c0, 0 ++ ++20: nop ++ b 20b @ loop waiting for sleep ++ ++/* ++ * cpu_pxa_resume() ++ * ++ * entry point from bootloader into kernel during resume ++ * ++ * Note: Yes, part of the following code is located into the .data section. ++ * This is to allow sleep_save_sp to be accessed with a relative load ++ * while we can't rely on any MMU translation. We could have put ++ * sleep_save_sp in the .text section as well, but some setups might ++ * insist on it to be truely read-only. ++ */ ++ ++ .data ++ .align 5 ++ENTRY(pxa_cpu_resume) ++ mov r0, #I_BIT | F_BIT | MODE_SVC @ set SVC, irqs off ++ msr cpsr_c, r0 ++ ++ ldr r0, sleep_save_sp @ stack phys addr ++ ldr r2, =resume_after_mmu @ its absolute virtual address ++ ldmfd r0, {r4 - r9, sp} @ CP regs + virt stack ptr ++ ++ mov r1, #0 ++ mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs ++ mcr p15, 0, r1, c7, c7, 0 @ invalidate I & D caches, BTB ++ ++#ifdef CONFIG_XSCALE_CACHE_ERRATA ++ bic r9, r9, #0x0004 @ see cpu_xscale_proc_init ++#endif ++ ++ mcr p15, 0, r4, c15, c1, 0 @ CP access reg ++ mcr p15, 0, r5, c13, c0, 0 @ PID ++ mcr p15, 0, r6, c3, c0, 0 @ domain ID ++ mcr p15, 0, r7, c2, c0, 0 @ translation table base addr ++ mcr p15, 0, r8, c1, c1, 0 @ auxiliary control reg ++ b resume_turn_on_mmu @ cache align execution ++ ++ .align 5 ++resume_turn_on_mmu: ++ mcr p15, 0, r9, c1, c0, 0 @ turn on MMU, caches, etc. ++ ++ @ Let us ensure we jump to resume_after_mmu only when the mcr above ++ @ actually took effect. They call it the "cpwait" operation. ++ mrc p15, 0, r1, c2, c0, 0 @ queue a dependency on CP15 ++ sub pc, r2, r1, lsr #32 @ jump to virtual addr ++ nop ++ nop ++ nop ++ ++sleep_save_sp: ++ .word 0 @ preserve stack phys ptr here ++ ++ .text ++resume_after_mmu: ++#ifdef CONFIG_XSCALE_CACHE_ERRATA ++ bl cpu_xscale_proc_init ++#endif ++ ldmfd sp!, {r2, r3} ++ mar acc0, r2, r3 ++ ldmfd sp!, {r4 - r12, pc} @ return to caller ++ ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/trizeps2.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,105 @@ ++/* ++ * linux/arch/arm/mach-pxa/trizeps2.c ++ * ++ * Support for the Keith&Koep MT6N Development Platform. ++ * ++ * Author: Luc De Cock ++ * Created: Jan 13, 2003 ++ * Copyright: Teradyne DS, Ltd. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/init.h> ++#include <linux/major.h> ++#include <linux/fs.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++ ++#include <asm/types.h> ++#include <asm/setup.h> ++#include <asm/memory.h> ++#include <asm/mach-types.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/irq.h> ++ ++#include "generic.h" ++ ++static unsigned long trizeps2_irq_en_mask; ++unsigned short trizeps2_bcr_shadow = 0x50; // 0x70 ++ ++ ++static void __init trizeps2_init_irq(void) ++{ ++ int irq; ++ ++ pxa_init_irq(); ++ ++ set_GPIO_IRQ_edge(GPIO_ETHERNET_IRQ, GPIO_RISING_EDGE); ++} ++ ++static int __init trizeps2_init(void) ++{ ++ /* Configure the BCR register */ ++ unsigned short *bcr = (unsigned short *) TRIZEPS2_BCR_BASE; ++ ++ *bcr = trizeps2_bcr_shadow; ++ return 0; ++} ++ ++__initcall(trizeps2_init); ++ ++static void __init ++fixup_trizeps2(struct machine_desc *desc, struct param_struct *params, ++ char **cmdline, struct meminfo *mi) ++{ ++#ifdef TRIZEPS2_MEM_64MB ++ SET_BANK (0, 0xa0000000, 64*1024*1024); ++#else ++ SET_BANK (0, 0xa0000000, 32*1024*1024); ++#endif ++ mi->nr_banks = 1; ++} ++ ++static struct map_desc trizeps2_io_desc[] __initdata = { ++ /* virtual physical length domain r w c b */ ++ { 0xf0000000, 0x0e000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* BCR */ ++ { 0xf0100000, 0x0c000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA STATUS */ ++ { 0xf1000000, 0x0c800000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 IO */ ++ { 0xf1100000, 0x0e000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 Attr */ ++ { 0xf2000000, 0x0d800000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* TTL-IO */ ++ LAST_DESC ++}; ++ ++static void __init trizeps2_map_io(void) ++{ ++ pxa_map_io(); ++ iotable_init(trizeps2_io_desc); ++ ++ /* This is for the SMC chip select */ ++ set_GPIO_mode(GPIO79_nCS_3_MD); ++ ++ /* setup sleep mode values */ ++ PWER = 0x00000002; ++ PFER = 0x00000000; ++ PRER = 0x00000002; ++ PGSR0 = 0x00008000; ++ PGSR1 = 0x003F0202; ++ PGSR2 = 0x0001C000; ++ PCFR |= PCFR_OPDE; ++} ++ ++MACHINE_START(TRIZEPS2, "Keith-n-Koep MT6N Development Platform") ++ MAINTAINER("Luc De Cock") ++ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) ++ FIXUP(fixup_trizeps2) ++ MAPIO(trizeps2_map_io) ++ INITIRQ(trizeps2_init_irq) ++MACHINE_END +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/usb-char.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,719 @@ ++/* ++ * (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 <linux/module.h> ++#include <linux/config.h> ++#include <linux/miscdevice.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/cache.h> ++#include <linux/poll.h> ++#include <linux/circ_buf.h> ++#include <linux/timer.h> ++ ++#include <asm/io.h> ++#include <asm/semaphore.h> ++#include <asm/proc/page.h> ++#include <asm/mach-types.h> ++ ++#include "usb-char.h" ++#include "pxa_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 = pxa_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 = pxa_usb_kmalloc_string_descriptor( "Extenex" ); ++ if ( pString ) { ++ pxa_usb_set_string_descriptor( 1, pString ); ++ pDesc->dev.iManufacturer = 1; ++ } ++ ++ pString = pxa_usb_kmalloc_string_descriptor( "Handheld Theater" ); ++ if ( pString ) { ++ pxa_usb_set_string_descriptor( 2, pString ); ++ pDesc->dev.iProduct = 2; ++ } ++ ++ pString = pxa_usb_kmalloc_string_descriptor( "00000000" ); ++ if ( pString ) { ++ pxa_usb_set_string_descriptor( 3, pString ); ++ pDesc->dev.iSerialNumber = 3; ++ } ++ ++ pString = pxa_usb_kmalloc_string_descriptor( "HHT Bulk Transfer" ); ++ if ( pString ) { ++ pxa_usb_set_string_descriptor( 4, pString ); ++ pDesc->b.intf.iInterface = 4; ++ } ++ pxa_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 = pxa_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 ) { ++ pxa_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 ); ++ pxa_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 = pxa_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 = pxa_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 = pxa_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 ( pxa_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: ++ pxa_usb_recv_reset(); ++ rx_ring.in = rx_ring.out = 0; ++ break; ++ ++ case USBC_IOC_FLUSH_TRANSMITTER: ++ pxa_usb_send_reset(); ++ break; ++ ++ case USBC_IOC_FLUSH_ALL: ++ pxa_usb_recv_reset(); ++ rx_ring.in = rx_ring.out = 0; ++ pxa_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 ); ++ pxa_usb_stop(); ++ free_txrx_buffers(); ++ free_string_descriptors(); ++ del_timer( &tx_timer ); ++ pxa_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 ( (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 ++ ++ ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/usb-char.h 2004-03-31 17:15:11.000000000 +0200 +@@ -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 */ ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/usb-eth.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,479 @@ ++/* ++ * Ethernet driver for the PXA 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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/timer.h> ++ ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> ++#include <linux/random.h> ++ ++#include "pxa_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; ++ } ++ ++ ++ /* ++ * If the real size of the packet is divisible by usb_rsize ++ * an extra byte will be added. Thus size == usb_rsize ++ * should only happen if more data is to come. ++ */ ++ /* 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 ++ pxa_usb_recv(dmabuf, usb_rsize, ++ usb_recv_callback); ++#else ++ pxa_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 0 ++{ ++ int i; ++ ++ for (i = 0; i < skb->len; i++) ++ { ++ printk("%02X ", skb->data[i]); ++ if( (i%8)==7) printk("\n"); ++ } ++ printk("...\n"); ++} ++#endif ++ ++ } ++ ++ 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: ++//printk("ERROR... tailroom=%d size=%d len=%d flag=%d\n", skb_tailroom(skb), size, skb->len, flag); ++ /* ++ * 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 ++ pxa_usb_recv(dmabuf, usb_rsize, usb_recv_callback); ++#else ++ pxa_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 = pxa_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; ++ 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. ++ } ++ ++ save_flags_cli(flags); ++ if (cur_tx_skb) { ++ next_tx_skb = skb; ++ netif_stop_queue(dev); ++ } else { ++ cur_tx_skb = skb; ++ dev->trans_start = jiffies; ++ ret = pxa_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++; ++ } ++ } ++ restore_flags(flags); ++ return 0; ++} ++ ++static void ++usb_xmit_timeout(struct net_device *dev ) ++{ ++ pxa_usb_send_reset(); ++ dev->trans_start = jiffies; ++ netif_wake_queue(dev); ++} ++ ++ ++static int ++usb_eth_open(struct net_device *dev) ++{ ++ int rc; ++ rc = pxa_usb_open( "usb-eth" ); ++ if ( rc == 0 ) { ++ string_desc_t * pstr; ++ desc_t * pd = pxa_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 = pxa_usb_kmalloc_string_descriptor( "PXA USB NIC" ); ++ if ( pstr ) { ++ pxa_usb_set_string_descriptor( 1, pstr ); ++ pd->dev.iProduct = 1; ++ } ++ rc = pxa_usb_start(); ++ } ++ ++ if( rc == 0) ++ { ++ 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); ++ ++ pxa_usb_stop(); ++ pxa_usb_close(); ++ return -ENOMEM;; ++ } ++ ++ MOD_INC_USE_COUNT; ++#ifndef DMA_NO_COPY ++ pxa_usb_recv(dmabuf, usb_rsize, usb_recv_callback); ++#else ++ pxa_usb_recv(cur_rx_skb->tail, MIN(usb_rsize, skb_tailroom (cur_rx_skb)), ++ usb_recv_callback); ++#endif ++ } ++ ++ return rc; ++} ++ ++static int ++usb_eth_release(struct net_device *dev) ++{ ++ string_desc_t * pstr; ++ ++ terminating = 1; ++ pxa_usb_send_reset(); ++ pxa_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); ++ ++ pxa_usb_stop(); ++ pxa_usb_close(); ++ if ( (pstr = pxa_usb_get_string_descriptor(1)) != NULL ) ++ kfree( pstr ); ++ ++ 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 pxa"); ++MODULE_PARM(usb_wsize, "1i"); ++MODULE_PARM_DESC(usb_wsize, "number of bytes in packets from pxa to host"); ++#endif ++ ++static int __init ++usb_eth_init(void) ++{ ++#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; ++ ++ printk( KERN_INFO "USB Function Ethernet Driver Interface\n"); ++ ++ return 0; ++} ++ ++static void __exit ++usb_eth_cleanup(void) ++{ ++#ifndef DMA_NO_COPY ++ kfree(dmabuf); ++#endif ++ unregister_netdev(&usb_eth_device); ++} ++ ++module_init(usb_eth_init); ++module_exit(usb_eth_cleanup); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/usb_ctl.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,769 @@ ++/* ++ * Copyright (C) Compaq Computer Corporation, 1998, 1999 ++ * Copyright (C) Extenex Corporation, 2001 ++ * Copyright (C) Intrinsyc, Inc., 2002 ++ * ++ * PXA USB controller core driver. ++ * ++ * This file provides interrupt routing and overall coordination ++ * of the endpoints. ++ * ++ * Please see: ++ * linux/Documentation/arm/SA1100/SA1100_USB ++ * for more info. ++ * ++ * 02-May-2002 ++ * Frank Becker (Intrinsyc) - derived from sa1100 usb_ctl.c ++ * ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/proc_fs.h> ++#include <linux/tqueue.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <asm/io.h> ++#include <asm/dma.h> ++#include <asm/irq.h> ++#include <asm/mach-types.h> ++ ++#include "pxa_usb.h" ++#include "usb_ctl.h" ++ ++//#define DEBUG 1 ++ ++#if DEBUG ++static unsigned int usb_debug = DEBUG; ++#else ++#define usb_debug 0 /* gcc will remove all the debug code for us */ ++#endif ++ ++////////////////////////////////////////////////////////////////////////////// ++// 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 "driver/pxausb" ++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 ++}; ++ ++/* ++ * FIXME: The PXA UDC handles several host device requests without user ++ * notification/intervention. The table could be collapsed quite a bit... ++ */ ++static int device_state_machine[8][6] = { ++// suspend reset resume adddr config deconfig ++/* zombie */ { kStateZombieSuspend , kStateDefault, kStateZombie , kError , kError , kError }, ++/* zom sus */ { kStateZombieSuspend , kStateDefault, kStateZombie , kError , kError , kError }, ++/* default */ { kStateDefaultSuspend, kStateDefault, kStateDefault, kStateAddr, kStateConfig, kError }, ++/* def sus */ { kStateDefaultSuspend, kStateDefault, kStateDefault, kError , kError , kError }, ++/* addr */ { kStateAddrSuspend , kStateDefault, kStateAddr , kError , kStateConfig, kError }, ++/* addr sus */{ kStateAddrSuspend , kStateDefault, kStateAddr , kError , kError , kError }, ++/* config */ { kStateConfigSuspend , kStateDefault, kStateConfig , kError , kError , kStateDefault }, ++/* cfg sus */ { kStateConfigSuspend , 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 ++USB_STATE_POWERED, USB_STATE_SUSPENDED, ++// default default sus ++USB_STATE_DEFAULT, USB_STATE_SUSPENDED, ++// addr addr sus ++USB_STATE_ADDRESS, USB_STATE_SUSPENDED, ++// config config sus ++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 ++////////////////////////////////////////////////////////////////////////////// ++ ++/* The UDCCR reg contains mask and interrupt status bits, ++ * so using '|=' isn't safe as it may ack an interrupt. ++ */ ++ ++void udc_set_mask_UDCCR( int mask ) ++{ ++ UDCCR = (UDCCR & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS); ++} ++ ++void udc_clear_mask_UDCCR( int mask) ++{ ++ UDCCR = (UDCCR & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS); ++} ++ ++void udc_ack_int_UDCCR( int mask) ++{ ++ /* udccr contains the bits we dont want to change */ ++ __u32 udccr = UDCCR & UDCCR_MASK_BITS; ++ ++ UDCCR = udccr | (mask & ~UDCCR_MASK_BITS); ++} ++ ++static void ++udc_int_hndlr(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ __u32 status = UDCCR; ++ __u32 ir0_status = USIR0; ++ __u32 ir1_status = USIR1; ++ __u32 uicr0 = UICR0; ++ __u32 uicr1 = UICR1; ++ ++ //mask ints ++ udc_set_mask_UDCCR( UDCCR_REM | UDCCR_SRM); ++ UICR0 = 0xff; ++ UICR1 = 0xff; ++ ++ if( usb_debug > 2) ++ { ++ printk("%s--- udc_int_hndlr\n" ++ "UDCCR=0x%08x UDCCS0=0x%08x UDCCS1=0x%08x UDCCS2=0x%08x\n" ++ "USIR0=0x%08x USIR1=0x%08x UICR0=0x%08x UICR1=0x%08x\n", ++ pszMe, status, UDCCS0, UDCCS1, UDCCS2, ir0_status, ir1_status, uicr0, uicr1); ++ } ++ ++ /* SUSpend Interrupt Request */ ++ if ( status & UDCCR_SUSIR ) ++ { ++ udc_ack_int_UDCCR( UDCCR_SUSIR); ++ if( usb_debug) printk("%sSuspend...\n", pszMe); ++ usbctl_next_state_on_event( kEvSuspend ); ++ } ++ ++ /* RESume Interrupt Request */ ++ if ( status & UDCCR_RESIR ) ++ { ++ udc_ack_int_UDCCR( UDCCR_RESIR); ++ if( usb_debug) printk("%sResume...\n", pszMe); ++ usbctl_next_state_on_event( kEvResume ); ++ } ++ ++ /* ReSeT Interrupt Request - UDC has been reset */ ++ if ( status & UDCCR_RSTIR ) ++ { ++ /* clear the reset interrupt */ ++ udc_ack_int_UDCCR( UDCCR_RSTIR); ++ ++ /* check type of reset */ ++ if( (UDCCR & UDCCR_UDA) == 0) ++ { ++ /* reset assertion took place, nothing to do */ ++ if( usb_debug) printk("%sReset assertion...\n", pszMe); ++ } ++ ++ /* ok, it's a reset negation, go on with reset */ ++ else if ( usbctl_next_state_on_event( kEvReset ) != kError ) ++ { ++ /* starting reset sequence now... */ ++ if( usb_debug) printk("%sResetting\n", pszMe); ++ ++ ep0_reset(); ++ ep_bulk_in1_reset(); ++ ep_bulk_out1_reset(); ++ ++ usbctl_next_state_on_event( kEvConfig ); ++ } ++ else ++ { ++ printk("%sUnexpected reset\n", pszMe); ++ } ++ } ++ else ++ { ++ /* ep0 int */ ++ if (ir0_status & USIR0_IR0) ++ ep0_int_hndlr(); ++ ++ /* transmit bulk */ ++ if (ir0_status & USIR0_IR1) ++ ep_bulk_in1_int_hndlr(ir0_status); ++ ++ /* receive bulk */ ++ if ( ir0_status & USIR0_IR2) ++ ep_bulk_out1_int_hndlr(ir0_status); ++ ++ while (UDCCS2 & UDCCS_BO_RNE) ++ { ++ if( usb_debug) printk("More Bulk-out data...\n"); ++ ep_bulk_out1_int_hndlr(ir0_status); ++ } ++ } ++ ++ UICR0 = uicr0; ++ UICR1 = uicr1; ++ udc_clear_mask_UDCCR( UDCCR_SRM | UDCCR_REM); /* enable suspend/resume, reset */ ++ ++ /* clear all endpoint ints */ ++ USIR0 |= 0xff; ++ USIR1 |= 0xff; ++ ++ if( usb_debug > 2) ++ { ++ printk("%sudc_int_hndlr\n" ++ "UDCCR=0x%08x UDCCS0=0x%08x UDCCS1=0x%08x UDCCS2=0x%08x\n" ++ "USIR0=0x%08x USIR1=0x%08x UICR0=0x%08x UICR1=0x%08x\n", ++ pszMe, UDCCR, UDCCS0, UDCCS1, UDCCS2, USIR0, USIR1, UICR0, UICR1); ++ } ++} ++ ++////////////////////////////////////////////////////////////////////////////// ++// Public Interface ++////////////////////////////////////////////////////////////////////////////// ++ ++/* Open PXA usb core on behalf of a client, but don't start running */ ++ ++int ++pxa_usb_open( const char * client ) ++{ ++ if ( usbd_info.client_name != NULL ) ++ { ++ printk( "%sUnable to register %s (%s already registered).\n", ++ pszMe, client, usbd_info.client_name ); ++ 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( "%s%s registered.\n", pszMe, client ); ++ return 0; ++} ++ ++/* Start running. Must have called usb_open (above) first */ ++int ++pxa_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 ); ++ ++ /* flush DMA and fire through some -EAGAINs */ ++ ep_bulk_out1_init( usbd_info.dmach_rx ); ++ ep_bulk_in1_init( usbd_info.dmach_tx ); ++ ++ /* give endpoint notification we are starting */ ++ ep_bulk_out1_state_change_notify( USB_STATE_SUSPENDED ); ++ ep_bulk_in1_state_change_notify( USB_STATE_SUSPENDED ); ++ ++ /* enable any platform specific hardware */ ++ soft_connect_hook( 1 ); ++ ++ /* enable suspend/resume, reset */ ++ udc_clear_mask_UDCCR( UDCCR_SRM | UDCCR_REM); ++ /* enable ep0, ep1, ep2 */ ++ UICR0 &= ~(UICR0_IM0 | UICR0_IM1 | UICR0_IM2); ++ ++ if( usb_debug) printk( "%sStarted %s\n", pszMe, usbd_info.client_name ); ++ return 0; ++} ++ ++/* Stop USB core from running */ ++int ++pxa_usb_stop( void ) ++{ ++ if ( usbd_info.client_name == NULL ) { ++ printk( "%s%s - no client registered\n", ++ pszMe, __FUNCTION__ ); ++ return -EPERM; ++ } ++ /* mask everything */ ++ /* disable suspend/resume, reset */ ++ udc_set_mask_UDCCR( UDCCR_SRM | UDCCR_REM); ++ /* disable ep0, ep1, ep2 */ ++ UICR0 |= (UICR0_IM0 | UICR0_IM1 | UICR0_IM2); ++ ++ ep_bulk_out1_reset(); ++ ep_bulk_in1_reset(); ++ ++ udc_disable(); ++ if( usb_debug) printk( "%sStopped %s\n", pszMe, usbd_info.client_name ); ++ return 0; ++} ++ ++/* Tell PXA core client is through using it */ ++int ++pxa_usb_close( void ) ++{ ++ if ( usbd_info.client_name == NULL ) { ++ printk( "%s%s - no client registered\n", ++ pszMe, __FUNCTION__ ); ++ return -EPERM; ++ } ++ printk( "%s%s closed.\n", pszMe, (char*)usbd_info.client_name ); ++ usbd_info.client_name = NULL; ++ return 0; ++} ++ ++/* set a proc to be called when device is configured */ ++usb_notify_t pxa_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 * ++pxa_usb_get_descriptor_ptr( void ) { return &desc; } ++ ++/* optional: set a string descriptor */ ++int ++pxa_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 * ++pxa_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 * ++pxa_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 ]; ++ if( usb_debug) 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; ++ ++ ep_bulk_out1_state_change_notify( next_device_state ); ++ ep_bulk_in1_state_change_notify( next_device_state ); ++ } ++ } ++#if 1 ++ 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 = 16; /* 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; ++ ++/* ++ * FIXME... ++ * The host usbnet driver expects EP1=out EP2=in. On the PXA UDC EP1=in, EP2=out ++ */ ++ desc.b.ep1.bLength = sizeof( ep_desc_t ); ++ desc.b.ep1.bDescriptorType = USB_DESC_ENDPOINT; ++ desc.b.ep1.bEndpointAddress = USB_EP_ADDRESS( 1, USB_IN ); ++ 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_OUT ); ++ desc.b.ep2.bmAttributes = USB_EP_BULK; ++ desc.b.ep2.wMaxPacketSize = make_word_c( 64 ); ++ desc.b.ep2.bInterval = 0; ++ ++// FIXME: Add support for all endpoint... ++ ++ /* 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 */ ++ pxa_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 ) ++{ ++} ++ ++/* disable the UDC at the source */ ++static void ++udc_disable(void) ++{ ++ soft_connect_hook( 0 ); ++ /* clear UDC-enable */ ++ udc_clear_mask_UDCCR( UDCCR_UDE); ++ ++ /* Disable clock for USB device */ ++ CKEN &= ~CKEN11_USB; ++} ++ ++ ++/* enable the udc at the source */ ++static void ++udc_enable(void) ++{ ++ /* Enable clock for USB device */ ++ CKEN |= CKEN11_USB; ++ ++ /* try to clear these bits before we enable the udc */ ++ udc_ack_int_UDCCR( UDCCR_SUSIR); ++ udc_ack_int_UDCCR( UDCCR_RSTIR); ++ udc_ack_int_UDCCR( UDCCR_RESIR); ++ ++ /* set UDC-enable */ ++ udc_set_mask_UDCCR( UDCCR_UDE); ++ if( (UDCCR & UDCCR_UDA) == 0) ++ { ++ /* There's a reset on the bus, ++ * clear the interrupt bit and keep going ++ */ ++ udc_ack_int_UDCCR( UDCCR_RSTIR); ++ } ++ ++ /* "USB test mode" to work around errata 40-42 (stepping a0, a1) ++ * which could result in missing packets and interrupts. ++ * Supposedly this turns off double buffering for all endpoints. ++ */ ++ if( usb_debug) printk( "USB RES1=%x RES2=%x RES3=%x\n", UDC_RES1, UDC_RES2, UDC_RES3); ++ UDC_RES1 = 0x00; ++ UDC_RES2 = 0x00; ++ if( usb_debug) printk( "USB RES1=%x RES2=%x RES3=%x\n", UDC_RES1, UDC_RES2, UDC_RES3); ++} ++ ++////////////////////////////////////////////////////////////////////////////// ++// 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( "PXA USB Controller Core\n" ); ++ SAY( "Active Client: %s\n", usbd_info.client_name ? usbd_info.client_name : "none"); ++ 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 = UDCCR; ++ SAY( "\nUDC Control Register\n" ); ++ SAYV( v ); ++ SAYC( "UDC Enabled", ( v & UDCCR_UDE ) ? yes : no ); ++ SAYC( "UDC Active", ( v & UDCCR_UDA ) ? yes : no ); ++ SAYC( "Suspend/Resume interrupts masked", ( v & UDCCR_SRM ) ? yes : no ); ++ SAYC( "Reset interrupts masked", ( v & UDCCR_REM ) ? yes : no ); ++ SAYC( "Reset pending", ( v & UDCCR_RSTIR ) ? yes : no ); ++ SAYC( "Suspend pending", ( v & UDCCR_SUSIR ) ? yes : no ); ++ SAYC( "Resume pending", ( v & UDCCR_RESIR ) ? yes : no ); ++ ++ len = ( p - page ) - off; ++ if ( len < 0 ) ++ len = 0; ++ *eof = ( len <=count ) ? 1 : 0; ++ *start = page + off; ++ return len; ++} ++ ++#endif /* CONFIG_PROC_FS */ ++ ++#if 0 ++static void irq_handler(int channel, void *data, struct pt_regs *regs) ++{ ++ if( channel == usbd_info.dmach_rx) ++ { ++ printk( "USB receive DMA\n"); ++ } ++ else if( channel == usbd_info.dmach_tx) ++ { ++ printk( "USB transmit DMA\n"); ++ } ++ else ++ { ++ printk( "USB unknown DMA channel\n"); ++ } ++} ++#endif ++ ++////////////////////////////////////////////////////////////////////////////// ++// 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 ++ ++#if 0 ++ /* setup rx dma */ ++ usbd_info.dmach_rx = pxa_request_dma("USB receive", DMA_PRIO_MEDIUM, irq_handler, 0 /*data; DMA_Ser0UDCRd*/); ++ if (usbd_info.dmach_rx < 0) { ++ printk("%sunable to register for rx dma rc=%d\n", pszMe, usbd_info.dmach_rx ); ++ goto err_rx_dma; ++ } ++ ++ /* setup tx dma */ ++ usbd_info.dmach_tx = pxa_request_dma("USB receive", DMA_PRIO_MEDIUM, irq_handler, 0 /*data; DMA_Ser0UDCRd*/); ++ if (usbd_info.dmach_tx < 0) { ++ printk("%sunable to register for tx dma rc=%d\n",pszMe,usbd_info.dmach_tx); ++ goto err_tx_dma; ++ } ++#endif ++ ++ /* now allocate the IRQ. */ ++ retval = request_irq(IRQ_USB, udc_int_hndlr, SA_INTERRUPT, "PXA USB core", NULL); ++ if (retval) { ++ printk("%sCouldn't request USB irq rc=%d\n",pszMe, retval); ++ goto err_irq; ++ } ++ ++ printk( "PXA USB Controller Core Initialized\n"); ++ return 0; ++ ++err_irq: ++#if 0 ++ pxa_free_dma(usbd_info.dmach_tx); ++ usbd_info.dmach_tx = 0; ++err_tx_dma: ++ pxa_free_dma(usbd_info.dmach_rx); ++ usbd_info.dmach_rx = 0; ++err_rx_dma: ++#endif ++ return retval; ++} ++/* ++ * usbctl_exit() ++ * Release DMA and interrupt resources ++ */ ++void __exit usbctl_exit( void ) ++{ ++ printk("Unloading PXA USB Controller\n"); ++ ++ udc_disable(); ++ ++#if CONFIG_PROC_FS ++ remove_proc_entry ( PROC_NODE_NAME, NULL); ++#endif ++ ++ pxa_free_dma(usbd_info.dmach_rx); ++ pxa_free_dma(usbd_info.dmach_tx); ++ free_irq(IRQ_USB, NULL); ++} ++ ++module_init( usbctl_init ); ++module_exit( usbctl_exit ); ++ ++EXPORT_SYMBOL( pxa_usb_open ); ++EXPORT_SYMBOL( pxa_usb_start ); ++EXPORT_SYMBOL( pxa_usb_stop ); ++EXPORT_SYMBOL( pxa_usb_close ); ++EXPORT_SYMBOL( pxa_usb_get_descriptor_ptr ); ++EXPORT_SYMBOL( pxa_usb_set_string_descriptor ); ++EXPORT_SYMBOL( pxa_usb_get_string_descriptor ); ++EXPORT_SYMBOL( pxa_usb_kmalloc_string_descriptor ); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/usb_ctl.h 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,89 @@ ++/* ++ * Copyright (C) Compaq Computer Corporation, 1998, 1999 ++ * Copyright (C) Extenex Corporation 2001 ++ * Copyright (C) Intrinsyc, Inc., 2002 ++ * ++ * usb_ctl.h ++ * ++ * PRIVATE interface used to share info among components of the PXA USB ++ * core: usb_ctl, usb_ep0, usb_recv and usb_send. Clients of the USB core ++ * should use pxa_usb.h. ++ * ++ * 02-May-2002 ++ * Frank Becker (Intrinsyc) - derived from sa1100 usb_ctl.h ++ * ++ */ ++ ++#ifndef _USB_CTL_H ++#define _USB_CTL_H ++ ++/* Interrupt mask bits and UDC enable bit */ ++#define UDCCR_MASK_BITS (UDCCR_REM | UDCCR_SRM | UDCCR_UDE) ++ ++/* ++ * 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 ep_bulk_out1_state_change_notify( int new_state ); ++int ep_bulk_out1_recv(void); ++int ep_bulk_out1_init(int chn); ++void ep_bulk_out1_int_hndlr(int status); ++void ep_bulk_out1_reset(void); ++void ep_bulk_out1_stall(void); ++ ++/* xmitter */ ++void ep_bulk_in1_state_change_notify( int new_state ); ++void ep_bulk_in1_reset(void); ++int ep_bulk_in1_init(int chn); ++void ep_bulk_in1_int_hndlr(int status); ++void ep_bulk_in1_stall(void); ++ ++#endif /* _USB_CTL_H */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/usb_ep0.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,556 @@ ++/* ++ * Copyright (C) Extenex Corporation 2001 ++ * Copyright (C) Compaq Computer Corporation, 1998, 1999 ++ * Copyright (C) Intrinsyc, Inc., 2002 ++ * ++ * PXA USB controller driver - Endpoint zero management ++ * ++ * Please see: ++ * linux/Documentation/arm/SA1100/SA1100_USB ++ * for more info. ++ * ++ * 02-May-2002 ++ * Frank Becker (Intrinsyc) - derived from sa1100 usb_ctl.c ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/proc_fs.h> ++#include <linux/tqueue.h> ++#include <linux/delay.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <asm/io.h> ++#include <asm/dma.h> ++#include <asm/irq.h> ++ ++#include "pxa_usb.h" /* public interface */ ++#include "usb_ctl.h" /* private stuff */ ++#include "usb_ep0.h" ++ ++ ++// 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 ++ ++static EP0_state ep0_state = EP0_IDLE; ++ ++/*************************************************************************** ++ Prototypes ++ ***************************************************************************/ ++/* "setup handlers" -- the main functions dispatched to by the ++ .. isr. These represent the major "modes" of endpoint 0 operation */ ++static void sh_setup_begin(void); /* setup begin (idle) */ ++static void sh_write( void ); /* writing data */ ++static int read_fifo( usb_dev_request_t * p ); ++static void write_fifo( void ); ++static void get_descriptor( usb_dev_request_t * pReq ); ++static void queue_and_start_write( void * p, int req, int act ); ++ ++/*************************************************************************** ++ Inline Helpers ++ ***************************************************************************/ ++ ++inline int type_code_from_request( __u8 by ) { return (( by >> 4 ) & 3); } ++ ++/* 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 = UDCCS0; ++ printk( "%08x: %s %s %s %s %s %s\n", ++ foo, ++ foo & UDCCS0_SA ? "SA" : "", ++ foo & UDCCS0_OPR ? "OPR" : "", ++ foo & UDCCS0_RNE ? "RNE" : "", ++ foo & UDCCS0_SST ? "SST" : "", ++ foo & UDCCS0_FST ? "FST" : "", ++ foo & UDCCS0_DRWF ? "DRWF" : "" ++ ); ++} ++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; ++ case SYNCH_FRAME: psz = "synch frame"; 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( usb_dev_request_t *x){} ++#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) ++{ ++ PRINTKD( "%sep0_reset\n", pszMe); ++ /* 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( "%sep0_int_hndlr\n", pszMe); ++ pcs(); ++ (*current_handler)(); ++} ++ ++/*************************************************************************** ++ 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. ++ * ++ */ ++static void sh_setup_begin( void ) ++{ ++ usb_dev_request_t req; ++ int request_type; ++ int n; ++ __u32 cs_reg_in = UDCCS0; ++ ++ PRINTKD( "%ssh_setup_begin\n", pszMe); ++ ++ /* 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; ++ } ++ ++ if( ((cs_reg_in & UDCCS0_SA) == 0) && (ep0_state == EP0_IN_DATA_PHASE)) ++ { ++ PRINTKD( "%ssetup begin: premature status\n", pszMe ); ++ ++ /* premature status, reset tx fifo and go back to idle state*/ ++ UDCCS0 = UDCCS0_OPR | UDCCS0_FTF; ++ ++ ep0_state = EP0_IDLE; ++ return; ++ } ++ ++ if( (UDCCS0 & UDCCS0_RNE) == 0) ++ { ++ /* zero-length OUT? */ ++ printk( "%ssetup begin: zero-length OUT?\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 */ ++ UDCCS0 = UDCCS0_FST; ++ 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 ); ++ 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 ) { ++ ++ case SET_ADDRESS: ++ PRINTKD( "%sSET_ADDRESS handled by UDC\n", pszMe); ++ break; ++#if 0 /* NOT_NEEDED */ ++ ++ case SET_FEATURE: ++ PRINTKD( "%sSET_FEATURE handled by UDC\n", pszMe); ++ break; ++ ++ case CLEAR_FEATURE: ++ PRINTKD( "%sCLEAR_FEATURE handled by UDC\n", pszMe); ++ break; ++ ++ case GET_CONFIGURATION: ++ PRINTKD( "%sGET_CONFIGURATION handled by UDC\n", pszMe ); ++ break; ++ ++ case GET_STATUS: ++ PRINTKD( "%s%sGET_STATUS handled by UDC\n", pszMe ); ++ break; ++ ++ case GET_INTERFACE: ++ PRINTKD( "%sGET_INTERFACE handled by UDC\n", pszMe); ++ break; ++ ++ case SYNCH_FRAME: ++ PRINTKD( "%sSYNCH_FRAME handled by UDC\n", pszMe ); ++ break; ++#endif ++ ++ case GET_DESCRIPTOR: ++ PRINTKD( "%sGET_DESCRIPTOR\n", pszMe ); ++ get_descriptor( &req ); ++ break; ++ ++ case SET_INTERFACE: ++ PRINTKD( "%sSET_INTERFACE TODO...\n", pszMe); ++ break; ++ ++ case SET_DESCRIPTOR: ++ PRINTKD( "%sSET_DESCRIPTOR TODO...\n", pszMe ); ++ break; ++ ++ case SET_CONFIGURATION: ++ PRINTKD( "%sSET_CONFIGURATION %d\n", pszMe, req.wValue); ++ ++/* ++ * FIXME: Something is not quite right here... I only ever get a ++ * de-configure from the host. Ignoring it for now, since usb ++ * ethernet won't do anything unless usb is 'configured'. ++ * ++ */ ++#if 0 ++ switch( req.wValue) ++ { ++ case 0: ++ /* configured */ ++ usbctl_next_state_on_event( kEvConfig ); ++ break; ++ case 1: ++ /* de-configured */ ++ usbctl_next_state_on_event( kEvDeConfig ); ++ break; ++ default: ++ PRINTKD( "%sSET_CONFIGURATION: unknown configuration value (%d)\n", pszMe, req.wValue); ++ break; ++ } ++#endif ++ break; ++ default : ++ printk("%sunknown request 0x%x\n", pszMe, req.bRequest); ++ break; ++ } /* switch( bRequest ) */ ++ ++sh_sb_end: ++ return; ++} ++ ++/* ++ * sh_write() ++ * ++ * Due to UDC bugs we push everything into the fifo in one go. ++ * Using interrupts just didn't work right... ++ * This should be ok, since control request are small. ++ */ ++static void sh_write() ++{ ++ PRINTKD( "sh_write\n" ); ++ do ++ { ++ write_fifo(); ++ } while( ep0_state != EP0_END_XFER); ++} ++ ++/*************************************************************************** ++ Other Private Subroutines ++ ***************************************************************************/ ++/* ++ * queue_and_start_write() ++ * data == data to send ++ * req == bytes host requested ++ * act == bytes we actually have ++ * ++ * Sets up the global "wr"-ite structure and load the outbound FIFO ++ * with data. ++ * ++ */ ++static void queue_and_start_write( void * data, int req, int act ) ++{ ++ PRINTKD( "write start: bytes requested=%d actual=%d\n", req, act); ++ ++ wr.p = (unsigned char*) data; ++ wr.bytes_left = MIN( act, req ); ++ ++ ep0_state = EP0_IN_DATA_PHASE; ++ sh_write(); ++ ++ return; ++} ++/* ++ * write_fifo() ++ * Stick bytes in the endpoint zero FIFO. ++ * ++ */ ++static void write_fifo( void ) ++{ ++ int bytes_this_time = MIN( wr.bytes_left, EP0_FIFO_SIZE ); ++ int bytes_written = 0; ++ ++ while( bytes_this_time-- ) { ++// PRINTKD( "%2.2X ", *wr.p ); ++ UDDR0 = *wr.p++; ++ bytes_written++; ++ } ++ wr.bytes_left -= bytes_written; ++ ++ usbd_info.stats.ep0_bytes_written += bytes_written; ++ ++ if( (wr.bytes_left==0)) ++ { ++ wr.p = NULL; /* be anal */ ++ ++ if(bytes_written < EP0_FIFO_SIZE) ++ { ++ int count; ++ int udccs0; ++ ++ /* We always end the transfer with a short or zero length packet */ ++ ep0_state = EP0_END_XFER; ++ current_handler = sh_setup_begin; ++ ++ /* Let the packet go... */ ++ UDCCS0 = UDCCS0_IPR; ++ ++ /* Wait until we get to status-stage, then ack. ++ * ++ * When the UDC sets the UDCCS0[OPR] bit, an interrupt ++ * is supposed to be generated (see 12.5.1 step 14ff, PXA Dev Manual). ++ * That approach didn't work out. Usually a new SETUP command was ++ * already in the fifo. I tried many approaches but was always losing ++ * at least some OPR interrupts. Thus the polling below... ++ */ ++ count = 1000; ++ udccs0 = UDCCS0; ++ do ++ { ++ if( (UDCCS0 & UDCCS0_OPR)) ++ { ++ /* clear OPR, generate ack */ ++ UDCCS0 = UDCCS0_OPR; ++ break; ++ } ++ count--; ++ udelay(1); ++ } while( count); ++ ++ PRINTKD( "write fifo: count=%d UDCCS0=%x UDCCS0=%x\n", count, udccs0, UDCCS0); ++ } ++ } ++ /* something goes poopy if I dont wait here ... */ ++ udelay(500); ++ ++ PRINTKD( "write fifo: bytes sent=%d, bytes left=%d\n", bytes_written, wr.bytes_left); ++} ++ ++/* ++ * read_fifo() ++ * Read 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. ++ * ++ */ ++static int read_fifo( usb_dev_request_t * request ) ++{ ++ int bytes_read = 0; ++ unsigned char * pOut = (unsigned char*) request; ++ ++ int udccs0 = UDCCS0; ++ ++ if( (udccs0 & SETUP_READY) == SETUP_READY) ++ { ++ /* ok it's a setup command */ ++ while( UDCCS0 & UDCCS0_RNE) ++ { ++ if( bytes_read >= sizeof( usb_dev_request_t)) ++ { ++ /* We've already read enought o fill usb_dev_request_t. ++ * Our tummy is full. Go barf... ++ */ ++ printk( "%sread_fifo(): read failure\n", pszMe ); ++ usbd_info.stats.ep0_fifo_read_failures++; ++ break; ++ } ++ ++ *pOut++ = UDDR0; ++ bytes_read++; ++ } ++ } ++ PRINTKD( "read_fifo %d bytes\n", bytes_read ); ++ ++ /* clear SA & OPR */ ++ UDCCS0 = SETUP_READY; ++ ++ usbd_info.stats.ep0_bytes_read += 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 ) ++{ ++ string_desc_t * pString; ++ ep_desc_t * pEndpoint = 0; ++ ++ desc_t * pDesc = pxa_usb_get_descriptor_ptr(); ++ int type = pReq->wValue >> 8; ++ int idx = pReq->wValue & 0xFF; ++ ++// PRINTKD( "%sget_descriptor for %d\n", pszMe, type ); ++ switch( type ) { ++ case USB_DESC_DEVICE: ++ queue_and_start_write( &pDesc->dev, ++ pReq->wLength, ++ pDesc->dev.bLength ); ++ break; ++ ++ // return config descriptor buffer, cfg, intf, 2 ep ++ case USB_DESC_CONFIG: ++ 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 = pxa_usb_get_string_descriptor( idx ); ++ if ( pString ) { ++ if ( idx != 0 ) { // if not language index ++ printk( "%sReturn string %d: ", pszMe, idx ); ++ psdesc( pString ); ++ } ++ queue_and_start_write( pString, ++ pReq->wLength, ++ pString->bLength ); ++ } ++ else { ++ printk("%sunkown string index %d Stall.\n", pszMe, idx ); ++ } ++ break; ++ ++ case USB_DESC_INTERFACE: ++ if ( idx == pDesc->b.intf.bInterfaceNumber ) { ++ 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; //[BULK_IN1]; ++ else if ( idx == 2 ) ++ pEndpoint = &pDesc->b.ep2; //[BULK_OUT1]; ++ else ++ pEndpoint = NULL; ++ if ( pEndpoint ) { ++ queue_and_start_write( pEndpoint, ++ pReq->wLength, ++ pEndpoint->bLength ); ++ } else { ++ printk("%sunkown endpoint index %d Stall.\n", pszMe, idx ); ++ } ++ break; ++ ++ ++ default : ++ printk("%sunknown descriptor type %d. Stall.\n", pszMe, type ); ++ break; ++ ++ } ++} ++ ++/* end usb_ep0.c - who needs this comment? */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/usb_ep0.h 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,66 @@ ++/* ++ * Copyright (C) Intrinsyc, Inc., 2002 ++ * ++ * usb_ep0.h - PXA USB controller driver. ++ * Endpoint zero management ++ * ++ * Please see: ++ * linux/Documentation/arm/SA1100/SA1100_USB ++ * for details. ++ * ++ * 02-May-2002 ++ * Frank Becker (Intrinsyc) - ++ * ++ */ ++ ++#ifndef __USB_EP0_H ++#define __USB_EP0_H ++ ++#define EP0_FIFO_SIZE 16 ++#define SETUP_READY (UDCCS0_SA | UDCCS0_OPR) ++ ++/*================================================ ++ * USB Protocol Stuff ++ */ ++ ++/* Request Codes */ ++enum { ++ GET_STATUS =0, ++ CLEAR_FEATURE =1, ++ /* reserved =2 */ ++ SET_FEATURE =3, ++ /* reserved =4 */ ++ SET_ADDRESS =5, ++ GET_DESCRIPTOR =6, ++ SET_DESCRIPTOR =7, ++ GET_CONFIGURATION =8, ++ SET_CONFIGURATION =9, ++ GET_INTERFACE =10, ++ SET_INTERFACE =11, ++ SYNCH_FRAME =12 ++}; ++ ++typedef enum { ++ EP0_IDLE, ++ EP0_IN_DATA_PHASE, ++ EP0_END_XFER, ++ EP0_OUT_DATA_PHASE ++} EP0_state; ++ ++/* USB Device Requests */ ++typedef struct ++{ ++ __u8 bmRequestType; ++ __u8 bRequest; ++ __u16 wValue; ++ __u16 wIndex; ++ __u16 wLength; ++} usb_dev_request_t __attribute__ ((packed)); ++ ++/* Data extraction from usb_request_t fields */ ++enum { ++ kTargetDevice =0, ++ kTargetInterface=1, ++ kTargetEndpoint =2 ++}; ++#endif +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/usb_recv.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,173 @@ ++/* ++ * Generic receive layer for the PXA USB client function ++ * ++ * This code was loosely inspired by the original version which was ++ * Copyright (c) Compaq Computer Corporation, 1998-1999 ++ * Copyright (c) 2001 by Nicolas Pitre ++ * ++ * 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. ++ * ++ * 02-May-2002 ++ * Frank Becker (Intrinsyc) - derived from sa1100 usb_recv.c ++ * ++ * TODO: Add support for DMA. ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/pci.h> ++#include <linux/errno.h> ++#include <asm/dma.h> ++#include <asm/system.h> ++ ++#include "pxa_usb.h" ++#include "usb_ctl.h" ++ ++#if DEBUG ++static unsigned int usb_debug = DEBUG; ++#else ++#define usb_debug 0 /* gcc will remove all the debug code for us */ ++#endif ++ ++static char *ep_bulk_out1_buf; ++static int ep_bulk_out1_len; ++static int ep_bulk_out1_remain; ++static usb_callback_t ep_bulk_out1_callback; ++static int rx_pktsize; ++ ++static void ++ep_bulk_out1_start(void) ++{ ++ /* disable DMA */ ++ UDCCS2 &= ~UDCCS_BO_DME; ++ ++ /* enable interrupts for endpoint 2 (bulk out) */ ++ UICR0 &= ~UICR0_IM2; ++} ++ ++static void ++ep_bulk_out1_done(int flag) ++{ ++ int size = ep_bulk_out1_len - ep_bulk_out1_remain; ++ ++ if (!ep_bulk_out1_len) ++ return; ++ ++ ep_bulk_out1_len = 0; ++ if (ep_bulk_out1_callback) { ++ ep_bulk_out1_callback(flag, size); ++ } ++} ++ ++void ++ep_bulk_out1_state_change_notify( int new_state ) ++{ ++} ++ ++void ++ep_bulk_out1_stall( void ) ++{ ++ /* SET_FEATURE force stall at UDC */ ++ UDCCS2 |= UDCCS_BO_FST; ++} ++ ++int ++ep_bulk_out1_init(int chn) ++{ ++ desc_t * pd = pxa_usb_get_descriptor_ptr(); ++ rx_pktsize = __le16_to_cpu( pd->b.ep1.wMaxPacketSize ); ++ ep_bulk_out1_done(-EAGAIN); ++ return 0; ++} ++ ++void ++ep_bulk_out1_reset(void) ++{ ++ desc_t * pd = pxa_usb_get_descriptor_ptr(); ++ rx_pktsize = __le16_to_cpu( pd->b.ep1.wMaxPacketSize ); ++ UDCCS2 &= ~UDCCS_BO_FST; ++ ep_bulk_out1_done(-EINTR); ++} ++ ++void ++ep_bulk_out1_int_hndlr(int udcsr) ++{ ++ int status = UDCCS2; ++ if( usb_debug) printk("ep_bulk_out1_int_hndlr: UDCCS2=%x\n", status); ++ ++ if( (status & (UDCCS_BO_RNE | UDCCS_BO_RSP)) == UDCCS_BO_RSP) ++ { ++ /* zero-length packet */ ++ } ++ ++ if( status & UDCCS_BO_RNE) ++ { ++ int len; ++ int i; ++ char *buf = ep_bulk_out1_buf + ep_bulk_out1_len - ep_bulk_out1_remain; ++ ++ /* bytes in FIFO */ ++ len = (UBCR2 & 0xff) +1; ++ ++ if( usb_debug) printk("usb_recv: " ++ "len=%d out1_len=%d out1_remain=%d\n", ++ len,ep_bulk_out1_len,ep_bulk_out1_remain); ++ ++ if( len > ep_bulk_out1_remain) ++ { ++ /* FIXME: if this happens, we need a temporary overflow buffer */ ++ printk("usb_recv: Buffer overwrite warning...\n"); ++ len = ep_bulk_out1_remain; ++ } ++ ++ /* read data out of fifo */ ++ for( i=0; i<len; i++) ++ { ++ *buf++ = UDDR2 & 0xff; ++ } ++ ++ ep_bulk_out1_remain -= len; ++ ep_bulk_out1_done((len) ? 0 : -EPIPE); ++ } ++ ++ /* ack RPC - FIXME: '|=' we may ack SST here, too */ ++ UDCCS2 |= UDCCS_BO_RPC; ++ return; ++} ++ ++int ++pxa_usb_recv(char *buf, int len, usb_callback_t callback) ++{ ++ int flags; ++ ++ if (ep_bulk_out1_len) ++ return -EBUSY; ++ ++ local_irq_save(flags); ++ ep_bulk_out1_buf = buf; ++ ep_bulk_out1_len = len; ++ ep_bulk_out1_callback = callback; ++ ep_bulk_out1_remain = len; ++ ep_bulk_out1_start(); ++ local_irq_restore(flags); ++ ++ return 0; ++} ++ ++void ++pxa_usb_recv_reset(void) ++{ ++ ep_bulk_out1_reset(); ++} ++ ++void ++pxa_usb_recv_stall(void) ++{ ++ ep_bulk_out1_stall(); ++} ++ ++EXPORT_SYMBOL(pxa_usb_recv_stall); ++EXPORT_SYMBOL(pxa_usb_recv); ++EXPORT_SYMBOL(pxa_usb_recv_reset); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-pxa/usb_send.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,190 @@ ++/* ++ * Generic xmit layer for the PXA USB client function ++ * ++ * This code was loosely inspired by the original version which was ++ * Copyright (c) Compaq Computer Corporation, 1998-1999 ++ * Copyright (c) 2001 by Nicolas Pitre ++ * ++ * 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. ++ * ++ * 02-May-2002 ++ * Frank Becker (Intrinsyc) - derived from sa1100 usb_send.c ++ * ++ * TODO: Add support for DMA. ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/pci.h> ++#include <linux/errno.h> ++#include <asm/hardware.h> ++#include <asm/dma.h> ++#include <asm/system.h> ++#include <asm/byteorder.h> ++ ++#include "pxa_usb.h" ++#include "usb_ctl.h" ++ ++#if DEBUG ++static unsigned int usb_debug = DEBUG; ++#else ++#define usb_debug 0 /* gcc will remove all the debug code for us */ ++#endif ++ ++static char *ep_bulk_in1_buf; ++static int ep_bulk_in1_len; ++static int ep_bulk_in1_remain; ++static usb_callback_t ep_bulk_in1_callback; ++static int tx_pktsize; ++ ++/* device state is changing, async */ ++void ++ep_bulk_in1_state_change_notify( int new_state ) ++{ ++} ++ ++/* set feature stall executing, async */ ++void ++ep_bulk_in1_stall( void ) ++{ ++ UDCCS1 |= UDCCS_BI_FST; ++} ++ ++static void ++ep_bulk_in1_send_packet(void) ++{ ++ int i; ++ char *buf = ep_bulk_in1_buf + ep_bulk_in1_len - ep_bulk_in1_remain; ++ int out_size = tx_pktsize; ++ ++ if( usb_debug) printk( "ep_bulk_in1_send_packet: UICR0=%x UDCCS1=%x\n", UICR0, UDCCS1); ++ ++ if( out_size > ep_bulk_in1_remain) ++ { ++ out_size = ep_bulk_in1_remain; ++ } ++ ++ for( i=0; i<out_size; i++) ++ { ++ UDDR1 = *buf++; ++ } ++ ++ UDCCS1 = UDCCS_BI_TPC; ++ if( out_size < tx_pktsize) ++ { ++ /* short packet */ ++ UDCCS1 = UDCCS_BI_TSP; ++ } ++ ep_bulk_in1_remain -= out_size; ++ ++ if( usb_debug) printk( "ep_bulk_in1_send_packet: " ++ "UICR0=%x UDCCS1=%x send bytes=%d left=%d\n", ++ UICR0, UDCCS1, out_size, ep_bulk_in1_remain); ++} ++ ++static void ++ep_bulk_in1_start(void) ++{ ++ if (!ep_bulk_in1_len) ++ return; ++ ++ UICR0 &= ~UICR0_IM1; ++ ++ ep_bulk_in1_send_packet(); ++} ++ ++static void ++ep_bulk_in1_done(int flag) ++{ ++ int size = ep_bulk_in1_len - ep_bulk_in1_remain; ++ if (ep_bulk_in1_len) { ++ ep_bulk_in1_len = 0; ++ if (ep_bulk_in1_callback) ++ ep_bulk_in1_callback(flag, size); ++ } ++} ++ ++int ++ep_bulk_in1_init(int chn) ++{ ++ desc_t * pd = pxa_usb_get_descriptor_ptr(); ++ tx_pktsize = __le16_to_cpu( pd->b.ep2.wMaxPacketSize ); ++ ep_bulk_in1_done(-EAGAIN); ++ return 0; ++} ++ ++void ++ep_bulk_in1_reset(void) ++{ ++ desc_t * pd = pxa_usb_get_descriptor_ptr(); ++ tx_pktsize = __le16_to_cpu( pd->b.ep2.wMaxPacketSize ); ++ UDCCS1 &= ~UDCCS_BI_FST; ++ ep_bulk_in1_done(-EINTR); ++} ++ ++void ++ep_bulk_in1_int_hndlr(int usir0) ++{ ++ int status = UDCCS1; ++ ++ if (ep_bulk_in1_remain != 0) { ++ /* more data to go */ ++ ep_bulk_in1_start(); ++ } else { ++ if( status & UDCCS_BI_TPC) ++ { ++ UDCCS1 = UDCCS_BI_TPC; ++ } ++ ep_bulk_in1_done(0); ++ } ++} ++ ++int ++pxa_usb_send(char *buf, int len, usb_callback_t callback) ++{ ++ int flags; ++ ++ if( usb_debug) printk( "pxa_usb_send: " ++ "data len=%d state=%d blen=%d\n", ++ len, usbd_info.state, ep_bulk_in1_len); ++ ++ if (usbd_info.state != USB_STATE_CONFIGURED) ++ return -ENODEV; ++ ++ if (ep_bulk_in1_len) ++ return -EBUSY; ++ ++ local_irq_save(flags); ++ ep_bulk_in1_buf = buf; ++ ep_bulk_in1_len = len; ++ ep_bulk_in1_callback = callback; ++ ep_bulk_in1_remain = len; ++ ep_bulk_in1_start(); ++ local_irq_restore(flags); ++ ++ return 0; ++} ++ ++ ++void ++pxa_usb_send_reset(void) ++{ ++ ep_bulk_in1_reset(); ++} ++ ++int ++pxa_usb_xmitter_avail( void ) ++{ ++ if (usbd_info.state != USB_STATE_CONFIGURED) ++ return -ENODEV; ++ if (ep_bulk_in1_len) ++ return -EBUSY; ++ return 0; ++} ++ ++ ++EXPORT_SYMBOL(pxa_usb_xmitter_avail); ++EXPORT_SYMBOL(pxa_usb_send); ++EXPORT_SYMBOL(pxa_usb_send_reset); +--- linux-2.4.25/arch/arm/mach-sa1100/sa1111-ohci.c~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-sa1100/sa1111-ohci.c 2004-03-31 17:15:11.000000000 +0200 +@@ -54,7 +54,7 @@ + * 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); ++ vbuf = consistent_alloc(GFP_KERNEL | GFP_DMA, 4, &dma_buf, 0); + + SADTSA = (unsigned long)dma_buf; + SADTCA = 4; +--- linux-2.4.25/arch/arm/mach-sa1100/sa1111.c~2.4.25-vrs2-pxa1.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-sa1100/sa1111.c 2004-03-31 17:15:11.000000000 +0200 +@@ -243,9 +243,15 @@ + * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111: + * (SA-1110 Developer's Manual, section 9.1.2.1) + */ ++#if CONFIG_ARCH_SA1100 + GAFR |= GPIO_32_768kHz; + GPDR |= GPIO_32_768kHz; + TUCR = TUCR_3_6864MHz; ++#elif CONFIG_ARCH_PXA ++ set_GPIO_mode(GPIO11_3_6MHz_MD); ++#else ++#error missing clock setup ++#endif + + /* + * Turn VCO on, and disable PLL Bypass. +@@ -300,6 +306,8 @@ + SBI_SMCR = smcr; + } + ++#ifdef CONFIG_ARCH_SA1100 ++ + /* + * Disable the memory bus request/grant signals on the SA1110 to + * ensure that we don't receive spurious memory requests. We set +@@ -341,5 +349,7 @@ + local_irq_restore(flags); + } + ++#endif ++ + EXPORT_SYMBOL(sa1111_wake); + EXPORT_SYMBOL(sa1111_doze); +--- linux-2.4.25/arch/arm/mm/Makefile~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/Makefile 2004-03-31 17:15:11.000000000 +0200 +@@ -44,6 +44,7 @@ + p-$(CONFIG_CPU_ARM1026) += proc-arm1026.o + p-$(CONFIG_CPU_SA110) += proc-sa110.o + p-$(CONFIG_CPU_SA1100) += proc-sa110.o ++p-$(CONFIG_CPU_XSCALE) += proc-xscale.o + + # Integrator follows "new style" + # Soon, others will do too, and we can get rid of this +--- linux-2.4.25/arch/arm/mm/consistent.c~2.4.25-vrs2-pxa1.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/consistent.c 2004-03-31 17:15:11.000000000 +0200 +@@ -37,7 +37,8 @@ + * + * Note that this does *not* zero the allocated area! + */ +-void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle) ++void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle, ++ unsigned long cache_flags) + { + struct page *page, *end, *free; + unsigned long order; +@@ -55,7 +56,7 @@ + goto no_page; + + *dma_handle = page_to_bus(page); +- ret = __ioremap(page_to_pfn(page) << PAGE_SHIFT, size, 0); ++ ret = __ioremap(page_to_pfn(page) << PAGE_SHIFT, size, cache_flags); + if (!ret) + goto no_remap; + +@@ -106,7 +107,7 @@ + #endif + gfp |= GFP_DMA; + +- return consistent_alloc(gfp, size, handle); ++ return consistent_alloc(gfp, size, handle, 0); + } + + /* +--- linux-2.4.25/arch/arm/mm/init.c~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/init.c 2004-03-31 17:15:11.000000000 +0200 +@@ -49,6 +49,9 @@ + static unsigned long totalram_pages; + extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; + extern char _stext, _text, _etext, _end, __init_begin, __init_end; ++#ifdef CONFIG_XIP_KERNEL ++extern char _endtext, _sdata; ++#endif + extern unsigned long phys_initrd_start; + extern unsigned long phys_initrd_size; + +@@ -347,7 +350,11 @@ + * Register the kernel text and data with bootmem. + * Note that this can only be in node 0. + */ ++#ifdef CONFIG_XIP_KERNEL ++ reserve_bootmem_node(pgdat, __pa(&_sdata), &_end - &_sdata); ++#else + reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext); ++#endif + + #ifdef CONFIG_CPU_32 + /* +@@ -601,8 +608,13 @@ + unsigned int codepages, datapages, initpages; + int i, node; + ++#ifndef CONFIG_XIP_KERNEL + codepages = &_etext - &_text; + datapages = &_end - &_etext; ++#else ++ codepages = &_endtext - &_text; ++ datapages = &_end - &_sdata; ++#endif + initpages = &__init_end - &__init_begin; + + high_memory = (void *)__va(meminfo.end); +@@ -658,11 +670,13 @@ + + void free_initmem(void) + { ++#ifndef CONFIG_XIP_KERNEL + if (!machine_is_integrator()) { + free_area((unsigned long)(&__init_begin), + (unsigned long)(&__init_end), + "init"); + } ++#endif + } + + #ifdef CONFIG_BLK_DEV_INITRD +--- linux-2.4.25/arch/arm/mm/mm-armv.c~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/mm-armv.c 2004-03-31 17:15:11.000000000 +0200 +@@ -356,6 +356,19 @@ + p ++; + #endif + ++#ifdef CONFIG_XIP_KERNEL ++ p->physical = KERNEL_XIP_BASE_PHYS; ++ p->virtual = KERNEL_XIP_BASE_VIRT; ++ p->length = PGDIR_SIZE * 8; ++ p->domain = DOMAIN_KERNEL; ++ p->prot_read = 0; /* r=0, b=0 --> read-only for kernel mode */ ++ p->prot_write = 0; ++ p->cacheable = 1; ++ p->bufferable = 1; ++ ++ p ++; ++#endif ++ + /* + * Go through the initial mappings, but clear out any + * pgdir entries that are not in the description. +@@ -386,7 +399,7 @@ + init_maps->prot_read = 0; + init_maps->prot_write = 0; + init_maps->cacheable = 1; +- init_maps->bufferable = 0; ++ init_maps->bufferable = 1; + + create_mapping(init_maps); + +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/proc-xscale.S 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,1086 @@ ++/* ++ * linux/arch/arm/mm/proc-xscale.S ++ * ++ * Author: Nicolas Pitre ++ * Created: November 2000 ++ * Copyright: (C) 2000, 2001 MontaVista 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. ++ * ++ * MMU functions for the Intel XScale CPUs ++ * ++ * 2001 Aug 21: ++ * some contributions by Brett Gaines <brett.w.gaines@intel.com> ++ * Copyright 2001 by Intel Corp. ++ * ++ * 2001 Sep 08: ++ * Completely revisited, many important fixes ++ * Nicolas Pitre <nico@cam.org> ++ */ ++ ++#include <linux/config.h> ++#include <linux/linkage.h> ++#include <asm/assembler.h> ++#include <asm/constants.h> ++#include <asm/procinfo.h> ++#include <asm/hardware.h> ++#include <asm/proc/pgtable.h> ++ ++/* ++ * Some knobs for cache allocation policy. ++ * Allocate on write may or may not be beneficial depending on the memory ++ * usage pattern of your main application. Write through cache is definitely ++ * a performance loss in most cases, but might be used for special purposes. ++ */ ++#define PMD_CACHE_WRITE_ALLOCATE 1 ++#define PTE_CACHE_WRITE_ALLOCATE 1 ++#define CACHE_WRITE_THROUGH 0 ++ ++/* ++ * There are errata that say that dirty status bits in the cache may get ++ * corrupted. The workaround significantly affects performance, and the bug ++ * _might_ just not be that visible or critical to you, so it is configurable. ++ * Let's hope a future core revision will tell us this was only a bad dream. ++ * But in the mean time the risk and tradeoff is yours to decide.... ++ */ ++#ifdef CONFIG_XSCALE_CACHE_ERRATA ++#undef CACHE_WRITE_THROUGH ++#define CACHE_WRITE_THROUGH 1 ++#endif ++ ++/* ++ * This is the maximum size of an area which will be flushed. If the area ++ * is larger than this, then we flush the whole cache ++ */ ++#define MAX_AREA_SIZE 32768 ++ ++/* ++ * the cache line size of the I and D cache ++ */ ++#define CACHELINESIZE 32 ++ ++/* ++ * the size of the data cache ++ */ ++#define CACHESIZE 32768 ++ ++/* ++ * and the page size ++ */ ++#define PAGESIZE 4096 ++ ++/* ++ * Virtual address used to allocate the cache when flushed ++ * ++ * This must be an address range which is _never_ used. It should ++ * apparently have a mapping in the corresponding page table for ++ * compatibility with future CPUs that _could_ require it. For instance we ++ * don't care. ++ * ++ * This must be aligned on a 2*CACHESIZE boundary. The code selects one of ++ * the 2 areas in alternance each time the clean_d_cache macro is used. ++ * Without this the XScale core exhibits cache eviction problems and no one ++ * knows why. ++ * ++ * Reminder: the vector table is located at 0xffff0000-0xffff0fff. ++ */ ++#define CLEAN_ADDR 0xfffe0000 ++ ++/* ++ * This macro is used to wait for a CP15 write and is needed ++ * when we have to ensure that the last operation to the co-pro ++ * was completed before continuing with operation. ++ */ ++ .macro cpwait, rd ++ mrc p15, 0, \rd, c2, c0, 0 @ arbitrary read of cp15 ++ mov \rd, \rd @ wait for completion ++ sub pc, pc, #4 @ flush instruction pipeline ++ .endm ++ ++ .macro cpwait_ret, lr, rd ++ mrc p15, 0, \rd, c2, c0, 0 @ arbitrary read of cp15 ++ sub pc, \lr, \rd, LSR #32 @ wait for completion and ++ @ flush instruction pipeline ++ .endm ++ ++#if !CACHE_WRITE_THROUGH ++ ++/* ++ * This macro cleans the entire dcache using line allocate. ++ * The main loop has been unrolled to reduce loop overhead. ++ * rd and rs are two scratch registers. ++ */ ++ .macro clean_d_cache, rd, rs ++ ldr \rs, =clean_addr ++ ldr \rd, [\rs] ++ eor \rd, \rd, #CACHESIZE ++ str \rd, [\rs] ++ add \rs, \rd, #CACHESIZE ++1: mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line ++ add \rd, \rd, #CACHELINESIZE ++ mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line ++ add \rd, \rd, #CACHELINESIZE ++ mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line ++ add \rd, \rd, #CACHELINESIZE ++ mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line ++ add \rd, \rd, #CACHELINESIZE ++ teq \rd, \rs ++ bne 1b ++ .endm ++ ++ .macro clean_d_line, rd ++ mcr p15, 0, \rd, c7, c10, 1 ++ .endm ++ ++ .data ++clean_addr: .word CLEAN_ADDR ++ ++#else ++ ++/* ++ * If cache is write-through, there is no need to clean it. ++ * Simply invalidating will do. ++ */ ++ ++ .macro clean_d_cache, rd, rs ++ mcr p15, 0, \rd, c7, c6, 0 ++ .endm ++ ++ /* let's try to skip this needless operations at least within loops */ ++ .macro clean_d_line, rd ++ .endm ++ ++#endif ++ ++ .text ++ ++/* ++ * cpu_xscale_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 = saved SPSR ++ * ++ * Returns: ++ * r0 = address of abort ++ * r1 = FSR, bit 11 = write ++ * r3 = corrupted ++ */ ++ .align 5 ++ENTRY(cpu_xscale_data_abort) ++ mrc p15, 0, r1, c5, c0, 0 @ get FSR ++ mrc p15, 0, r0, c6, c0, 0 @ get FAR ++ ldr r3, [r2] @ read aborted instruction ++ bic r1, r1, #1 << 11 @ clear bits 11 of FSR ++ tst r3, #1 << 20 @ check write ++ orreq r1, r1, #1 << 11 ++ mov pc, lr ++ ++/* ++ * cpu_xscale_check_bugs() ++ */ ++ENTRY(cpu_xscale_check_bugs) ++ mrs ip, cpsr ++ bic ip, ip, #F_BIT ++ msr cpsr, ip ++ mov pc, lr ++ ++#ifndef CONFIG_XSCALE_CACHE_ERRATA ++/* ++ * cpu_xscale_proc_init() ++ * ++ * Nothing too exciting at the moment ++ */ ++ENTRY(cpu_xscale_proc_init) ++ mov pc, lr ++#else ++/* ++ * We enable the cache here, but we make sure all the status bits for dirty ++ * lines are cleared as well (see PXA250 erratum #120). ++ */ ++ENTRY(cpu_xscale_proc_init) ++ @ enable data cache ++ ldr r0, cr_p ++ ldmia r0, {r1, r2} ++ orr r1, r1, #0x4 ++ orr r2, r2, #0x4 ++ stmia r0, {r1, r2} ++ mcr p15, 0, r1, c1, c0, 0 ++ cpwait r0 ++ ++ @ invalidate data cache ++ mcr p15, 0, r0, c7, c6, 0 ++ ++ @ fill main cache with write-through lines ++ bic r0, pc, #0x1f ++ add r1, r0, #CACHESIZE ++1: ldr r2, [r0], #32 ++ cmp r0, r1 ++ bne 1b ++ ++ @ enable test feature to force all fills to the mini-cache ++ mov r1, #0x8 ++ mcr p15, 0, r1, c15, c15, 3 ++ ++ @ fill mini-cache with write-through lines (2kbytes, 64 lines) ++ add r1, r0, #2048 ++2: ldr r2, [r0], #32 ++ cmp r0, r1 ++ bne 2b ++ ++ @ disable test feature to force all fills to the mini-cache ++ mov r1, #0x0 ++ mcr p15, 0, r1, c15, c15, 3 ++ ++ @ invalidate data cache again ++ mcr p15, 0, r1, c7, c6, 0 ++ mov pc, lr ++ ++cr_p: .long SYMBOL_NAME(cr_alignment) ++#endif ++ ++/* ++ * cpu_xscale_proc_fin() ++ */ ++ENTRY(cpu_xscale_proc_fin) ++ str lr, [sp, #-4]! ++ mov r0, #F_BIT|I_BIT|SVC_MODE ++ msr cpsr_c, r0 ++ mrc p15, 0, r0, c1, c0, 0 @ ctrl register ++ bic r0, r0, #0x1800 @ ...IZ........... ++ bic r0, r0, #0x0006 @ .............CA. ++ mcr p15, 0, r0, c1, c0, 0 @ disable caches ++ bl cpu_xscale_cache_clean_invalidate_all @ clean caches ++ ldr pc, [sp], #4 ++ ++/* ++ * cpu_xscale_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_xscale_reset) ++ mov r1, #F_BIT|I_BIT|SVC_MODE ++ msr cpsr_c, r1 @ reset CPSR ++ mrc p15, 0, r1, c1, c0, 0 @ ctrl register ++ bic r1, r1, #0x0086 @ ........B....CA. ++ bic r1, r1, #0x1900 @ ...IZ..S........ ++ mcr p15, 0, r1, c1, c0, 0 @ ctrl register ++ mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches & BTB ++ bic r1, r1, #0x0001 @ ...............M ++ mcr p15, 0, r1, c1, c0, 0 @ ctrl register ++ @ CAUTION: MMU turned off from this point. We count on the pipeline ++ @ already containing those two last instructions to survive. ++ mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs ++ mov pc, r0 ++ ++/* ++ * cpu_xscale_do_idle(type) ++ * ++ * Cause the processor to idle ++ * ++ * type: ++ * 0 = slow idle ++ * 1 = fast idle ++ * 2 = switch to slow processor clock ++ * 3 = switch to fast processor clock ++ * ++ * For now we do nothing but go to idle mode for every case ++ * ++ * XScale supports clock switching, but using idle mode support ++ * allows external hardware to react to system state changes. ++ */ ++ .align 5 ++ ++ENTRY(cpu_xscale_do_idle) ++ mov r0, #1 ++ mcr p14, 0, r0, c7, c0, 0 @ Go to IDLE ++ mov pc, lr ++ ++/* ================================= CACHE ================================ */ ++ ++/* ++ * cpu_xscale_cache_clean_invalidate_all (void) ++ * ++ * clean and invalidate all cache lines ++ * ++ * Note: ++ * 1. We should preserve r0 at all times. ++ * 2. Even if this function implies cache "invalidation" by its name, ++ * we don't need to actually use explicit invalidation operations ++ * since the goal is to discard all valid references from the cache ++ * and the cleaning of it already has that effect. ++ * 3. Because of 2 above and the fact that kernel space memory is always ++ * coherent across task switches there is no need to worry about ++ * inconsistencies due to interrupts, ence no irq disabling. ++ */ ++ .align 5 ++ENTRY(cpu_xscale_cache_clean_invalidate_all) ++ mov r2, #1 ++cpu_xscale_cache_clean_invalidate_all_r2: ++ clean_d_cache r0, r1 ++ teq r2, #0 ++ mcrne p15, 0, ip, c7, c5, 0 @ Invalidate I cache & BTB ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov pc, lr ++ ++/* ++ * cpu_xscale_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_xscale_cache_clean_invalidate_range) ++ bic r0, r0, #CACHELINESIZE - 1 @ round down to cache line ++ sub r3, r1, r0 ++ cmp r3, #MAX_AREA_SIZE ++ bhi cpu_xscale_cache_clean_invalidate_all_r2 ++1: clean_d_line r0 @ Clean D cache line ++ mcr p15, 0, r0, c7, c6, 1 @ Invalidate D cache line ++ add r0, r0, #CACHELINESIZE ++ cmp r0, r1 ++ blo 1b ++ teq r2, #0 ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ moveq pc, lr ++ sub r0, r0, r3 ++1: mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line ++ add r0, r0, #CACHELINESIZE ++ cmp r0, r1 ++ blo 1b ++ mcr p15, 0, ip, c7, c5, 6 @ Invalidate BTB ++ mov pc, lr ++ ++/* ++ * cpu_xscale_flush_ram_page(page) ++ * ++ * clean all cache lines associated with this memory page ++ * ++ * page: page to clean ++ */ ++ .align 5 ++ENTRY(cpu_xscale_flush_ram_page) ++#if !CACHE_WRITE_THROUGH ++ mov r1, #PAGESIZE ++1: mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ add r0, r0, #CACHELINESIZE ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ add r0, r0, #CACHELINESIZE ++ subs r1, r1, #2 * CACHELINESIZE ++ bne 1b ++#endif ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov pc, lr ++ ++/* ================================ D-CACHE =============================== */ ++ ++/* ++ * cpu_xscale_dcache_invalidate_range(start, end) ++ * ++ * throw away all D-cached data in specified region without an obligation ++ * to write them back. Note however that on XScale we must clean all ++ * entries also due to hardware errata (80200 A0 & A1 only). ++ * ++ * start: virtual start address ++ * end: virtual end address ++ */ ++ .align 5 ++ENTRY(cpu_xscale_dcache_invalidate_range) ++ mrc p15, 0, r2, c0, c0, 0 @ Read part no. ++ eor r2, r2, #0x69000000 ++ eor r2, r2, #0x00052000 @ 80200 XX part no. ++ bics r2, r2, #0x1 @ Clear LSB in revision field ++ moveq r2, #0 ++ beq cpu_xscale_cache_clean_invalidate_range @ An 80200 A0 or A1 ++ ++ tst r0, #CACHELINESIZE - 1 ++ mcrne p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ tst r1, #CACHELINESIZE - 1 ++ mcrne p15, 0, r1, c7, c10, 1 @ Clean D cache line ++ bic r0, r0, #CACHELINESIZE - 1 @ round down to cache line ++1: mcr p15, 0, r0, c7, c6, 1 @ Invalidate D cache line ++ add r0, r0, #CACHELINESIZE ++ cmp r0, r1 ++ blo 1b ++ mov pc, lr ++ ++/* ++ * cpu_xscale_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_xscale_dcache_clean_range) ++#if !CACHE_WRITE_THROUGH ++ bic r0, r0, #CACHELINESIZE - 1 ++ sub r2, r1, r0 ++ cmp r2, #MAX_AREA_SIZE ++ movhi r2, #0 ++ bhi cpu_xscale_cache_clean_invalidate_all_r2 ++ ++1: mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ add r0, r0, #CACHELINESIZE ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ add r0, r0, #CACHELINESIZE ++ cmp r0, r1 ++ blo 1b ++#endif ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov pc, lr ++ ++/* ++ * cpu_xscale_clean_dcache_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. ++ * ++ * Note: ++ * 1. we don't need to flush the write buffer in this case. [really? -Nico] ++ * 2. 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_xscale_dcache_clean_page) ++#if !CACHE_WRITE_THROUGH ++ mov r1, #PAGESIZE ++1: mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ add r0, r0, #CACHELINESIZE ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ add r0, r0, #CACHELINESIZE ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ add r0, r0, #CACHELINESIZE ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ add r0, r0, #CACHELINESIZE ++ subs r1, r1, #4 * CACHELINESIZE ++ bne 1b ++#endif ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov pc, lr ++ ++/* ++ * cpu_xscale_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_xscale_dcache_clean_entry) ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov pc, lr ++ ++/* ================================ I-CACHE =============================== */ ++ ++/* ++ * cpu_xscale_icache_invalidate_range(start, end) ++ * ++ * invalidate a range of virtual addresses from the Icache ++ * ++ * start: virtual start address ++ * end: virtual end address ++ * ++ * Note: This is vaguely defined as supposed to bring the dcache and the ++ * icache in sync by the way this function is used. ++ */ ++ .align 5 ++ENTRY(cpu_xscale_icache_invalidate_range) ++ bic r0, r0, #CACHELINESIZE - 1 ++1: clean_d_line r0 @ Clean D cache line ++ mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line ++ add r0, r0, #CACHELINESIZE ++ cmp r0, r1 ++ blo 1b ++ mcr p15, 0, ip, c7, c5, 6 @ Invalidate BTB ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov pc, lr ++ ++/* ++ * cpu_xscale_icache_invalidate_page(page) ++ * ++ * invalidate all Icache lines associated with this area of memory ++ * ++ * page: page to invalidate ++ */ ++ .align 5 ++ENTRY(cpu_xscale_icache_invalidate_page) ++ mov r1, #PAGESIZE ++1: mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line ++ add r0, r0, #CACHELINESIZE ++ mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line ++ add r0, r0, #CACHELINESIZE ++ mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line ++ add r0, r0, #CACHELINESIZE ++ mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line ++ add r0, r0, #CACHELINESIZE ++ subs r1, r1, #4 * CACHELINESIZE ++ bne 1b ++ mcr p15, 0, r0, c7, c5, 6 @ Invalidate BTB ++ mov pc, lr ++ ++/* ================================ CACHE LOCKING============================ ++ * ++ * The XScale MicroArchitecture implements support for locking entries into ++ * the data and instruction cache. The following functions implement the core ++ * low level instructions needed to accomplish the locking. The developer's ++ * manual states that the code that performs the locking must be in non-cached ++ * memory. To accomplish this, the code in xscale-cache-lock.c copies the ++ * following functions from the cache into a non-cached memory region that ++ * is allocated through consistent_alloc(). ++ * ++ */ ++ .align 5 ++/* ++ * xscale_icache_lock ++ * ++ * r0: starting address to lock ++ * r1: end address to lock ++ */ ++ENTRY(xscale_icache_lock) ++ ++iLockLoop: ++ bic r0, r0, #CACHELINESIZE - 1 ++ mcr p15, 0, r0, c9, c1, 0 @ lock into cache ++ cmp r0, r1 @ are we done? ++ add r0, r0, #CACHELINESIZE @ advance to next cache line ++ bls iLockLoop ++ mov pc, lr ++ ++/* ++ * xscale_icache_unlock ++ */ ++ENTRY(xscale_icache_unlock) ++ mcr p15, 0, r0, c9, c1, 1 @ Unlock icache ++ mov pc, lr ++ ++/* ++ * xscale_dcache_lock ++ * ++ * r0: starting address to lock ++ * r1: end address to lock ++ */ ++ENTRY(xscale_dcache_lock) ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov r2, #1 ++ mcr p15, 0, r2, c9, c2, 0 @ Put dcache in lock mode ++ cpwait ip @ Wait for completion ++ ++ mrs r2, cpsr ++ orr r3, r2, #F_BIT | I_BIT ++dLockLoop: ++ msr cpsr_c, r3 ++ mcr p15, 0, r0, c7, c10, 1 @ Write back line if it is dirty ++ mcr p15, 0, r0, c7, c6, 1 @ Flush/invalidate line ++ msr cpsr_c, r2 ++ ldr ip, [r0], #CACHELINESIZE @ Preload 32 bytes into cache from ++ @ location [r0]. Post-increment ++ @ r3 to next cache line ++ cmp r0, r1 @ Are we done? ++ bls dLockLoop ++ ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov r2, #0 ++ mcr p15, 0, r2, c9, c2, 0 @ Get out of lock mode ++ cpwait_ret lr, ip ++ ++/* ++ * xscale_dcache_unlock ++ */ ++ENTRY(xscale_dcache_unlock) ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mcr p15, 0, ip, c9, c2, 1 @ Unlock cache ++ mov pc, lr ++ ++/* ++ * Needed to determine the length of the code that needs to be copied. ++ */ ++ .align 5 ++ENTRY(xscale_cache_dummy) ++ mov pc, lr ++ ++/* ================================== TLB ================================= */ ++ ++/* ++ * cpu_xscale_tlb_invalidate_all() ++ * ++ * Invalidate all TLB entries ++ */ ++ .align 5 ++ENTRY(cpu_xscale_tlb_invalidate_all) ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs ++ cpwait_ret lr, ip ++ ++/* ++ * cpu_xscale_tlb_invalidate_range(start, end) ++ * ++ * invalidate TLB entries covering the specified range ++ * ++ * start: range start address ++ * end: range end address ++ */ ++ .align 5 ++ENTRY(cpu_xscale_tlb_invalidate_range) ++ bic r0, r0, #(PAGESIZE - 1) & 0x00ff ++ bic r0, r0, #(PAGESIZE - 1) & 0xff00 ++ sub r3, r1, r0 ++ cmp r3, #256 * PAGESIZE @ arbitrary, should be tuned ++ bhi cpu_xscale_tlb_invalidate_all ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++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 ++ blo 1b ++ cpwait_ret lr, ip ++ ++/* ++ * cpu_xscale_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_xscale_tlb_invalidate_page) ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ teq r1, #0 ++ mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry ++ mcrne p15, 0, r3, c8, c5, 1 @ invalidate I TLB entry ++ cpwait_ret lr, ip ++ ++/* ================================ TLB LOCKING============================== ++ * ++ * The XScale MicroArchitecture implements support for locking entries into ++ * the Instruction and Data TLBs. The following functions provide the ++ * low level support for supporting these under Linux. xscale-lock.c ++ * implements some higher level management code. Most of the following ++ * is taken straight out of the Developer's Manual. ++ */ ++ ++/* ++ * Lock I-TLB entry ++ * ++ * r0: Virtual address to translate and lock ++ */ ++ .align 5 ++ENTRY(xscale_itlb_lock) ++ mrs r2, cpsr ++ orr r3, r2, #F_BIT | I_BIT ++ msr cpsr_c, r3 @ Disable interrupts ++ mcr p15, 0, r0, c8, c5, 1 @ Invalidate I-TLB entry ++ mcr p15, 0, r0, c10, c4, 0 @ Translate and lock ++ msr cpsr_c, r2 @ Restore interrupts ++ cpwait_ret lr, ip ++ ++/* ++ * Lock D-TLB entry ++ * ++ * r0: Virtual address to translate and lock ++ */ ++ .align 5 ++ENTRY(xscale_dtlb_lock) ++ mrs r2, cpsr ++ orr r3, r2, #F_BIT | I_BIT ++ msr cpsr_c, r3 @ Disable interrupts ++ mcr p15, 0, r0, c8, c6, 1 @ Invalidate D-TLB entry ++ mcr p15, 0, r0, c10, c8, 0 @ Translate and lock ++ msr cpsr_c, r2 @ Restore interrupts ++ cpwait_ret lr, ip ++ ++/* ++ * Unlock all I-TLB entries ++ */ ++ .align 5 ++ENTRY(xscale_itlb_unlock) ++ mcr p15, 0, ip, c10, c4, 1 @ Unlock I-TLB ++ mcr p15, 0, ip, c8, c5, 0 @ Invalidate I-TLB ++ cpwait_ret lr, ip ++ ++/* ++ * Unlock all D-TLB entries ++ */ ++ENTRY(xscale_dtlb_unlock) ++ mcr p15, 0, ip, c10, c8, 1 @ Unlock D-TBL ++ mcr p15, 0, ip, c8, c6, 0 @ Invalidate D-TLB ++ cpwait_ret lr, ip ++ ++/* =============================== PageTable ============================== */ ++ ++/* ++ * cpu_xscale_set_pgd(pgd) ++ * ++ * Set the translation base pointer to be as described by pgd. ++ * ++ * pgd: new page tables ++ */ ++ .align 5 ++ENTRY(cpu_xscale_set_pgd) ++ clean_d_cache r1, r2 ++ mcr p15, 0, ip, c7, c5, 0 @ Invalidate I cache & BTB ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mcr p15, 0, r0, c2, c0, 0 @ load page table pointer ++ mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs ++ cpwait_ret lr, ip ++ ++/* ++ * cpu_xscale_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_xscale_set_pmd) ++#if PMD_CACHE_WRITE_ALLOCATE && !CACHE_WRITE_THROUGH ++ and r2, r1, #PMD_TYPE_MASK|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE ++ cmp r2, #PMD_TYPE_SECT|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE ++ orreq r1, r1, #PMD_SECT_TEX(1) ++#elif CACHE_WRITE_THROUGH ++ and r2, r1, #PMD_TYPE_MASK|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE ++ cmp r2, #PMD_TYPE_SECT|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE ++ biceq r1, r1, #PMD_SECT_BUFFERABLE ++#endif ++ str r1, [r0] ++ mov ip, #0 ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov pc, lr ++ ++/* ++ * cpu_xscale_set_pte(ptep, pte) ++ * ++ * Set a PTE and flush it out ++ * ++ * Errata 40: must set memory to write-through for user read-only pages. ++ */ ++ .align 5 ++ENTRY(cpu_xscale_set_pte) ++ str r1, [r0], #-1024 @ linux version ++ ++ bic r2, r1, #0xff0 ++ orr r2, r2, #PTE_TYPE_EXT @ extended page ++ ++ eor r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY ++ ++ tst r3, #L_PTE_USER | L_PTE_EXEC @ User or Exec? ++ orrne r2, r2, #PTE_EXT_AP_URO_SRW @ yes -> user r/o, system r/w ++ ++ tst r3, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty? ++ orreq r2, r2, #PTE_EXT_AP_UNO_SRW @ yes -> user n/a, system r/w ++ @ combined with user -> user r/w ++ ++ @ ++ @ Handle the X bit. We want to set this bit for the minicache ++ @ (U = E = B = W = 0, C = 1) or when write allocate is enabled, ++ @ and we have a writeable, cacheable region. If we ignore the ++ @ U and E bits, we can allow user space to use the minicache as ++ @ well. ++ @ ++ @ X = C & ~W & ~B ++ @ | C & W & B & write_allocate ++ @ ++ eor ip, r1, #L_PTE_CACHEABLE ++ tst ip, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE ++#if PTE_CACHE_WRITE_ALLOCATE && !CACHE_WRITE_THROUGH ++ eorne ip, r1, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE ++ tstne ip, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE ++#endif ++ orreq r2, r2, #PTE_EXT_TEX(1) ++ ++#if CACHE_WRITE_THROUGH ++ tst r1, #L_PTE_CACHEABLE ++ bicne r2, r2, #L_PTE_BUFFERABLE @ clear B only if C is set ++#else ++ @ ++ @ Errata 40: The B bit must be cleared for a user read-only ++ @ cacheable page. ++ @ ++ @ B = B & ~((U|E) & C & ~W) ++ @ ++ and ip, r1, #L_PTE_USER | L_PTE_EXEC | L_PTE_WRITE | L_PTE_CACHEABLE ++ teq ip, #L_PTE_USER | L_PTE_CACHEABLE ++ teqne ip, #L_PTE_EXEC | L_PTE_CACHEABLE ++ teqne ip, #L_PTE_USER | L_PTE_EXEC | L_PTE_CACHEABLE ++ biceq r2, r2, #PTE_BUFFERABLE ++#endif ++ ++ tst r3, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young? ++ movne r2, #0 @ no -> fault ++ ++ str r2, [r0] @ hardware version ++ ++ @ We try to map 64K page entries when possible. ++ @ We do that for kernel space only since the usage pattern from ++ @ the setting of VM area is quite simple. User space is not worth ++ @ the implied complexity because of ever randomly changing PTEs ++ @ (page aging, swapout, etc) requiring constant coherency checks. ++ @ Since PTEs are usually set in increasing order, we test the ++ @ possibility for a large page only when given the last PTE of a ++ @ 64K boundary. ++ tsteq r1, #L_PTE_USER ++ andeq r1, r0, #(15 << 2) ++ teqeq r1, #(15 << 2) ++ beq 1f ++ ++ mov ip, #0 ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov pc, lr ++ ++ @ See if we have 16 identical PTEs but with consecutive base addresses ++1: bic r3, r2, #0x0000f000 ++ mov r1, #0x0000f000 ++2: eor r2, r2, r3 ++ teq r2, r1 ++ bne 4f ++ subs r1, r1, #0x00001000 ++ ldr r2, [r0, #-4]! ++ bne 2b ++ eors r2, r2, r3 ++ bne 4f ++ ++ @ Now create our LARGE PTE from the current EXT one. ++ bic r3, r3, #PTE_TYPE_MASK ++ orr r3, r3, #PTE_TYPE_LARGE ++ and r2, r3, #0x30 @ EXT_AP --> LARGE_AP0 ++ orr r2, r2, r2, lsl #2 @ add LARGE_AP1 ++ orr r2, r2, r2, lsl #4 @ add LARGE_AP3 + LARGE_AP2 ++ and r1, r3, #0x3c0 @ EXT_TEX ++ bic r3, r3, #0x3c0 ++ orr r2, r2, r1, lsl #(12 - 6) @ --> LARGE_TEX ++ orr r2, r2, r3 @ add remaining bits ++ ++ @ then put it in the pagetable ++ mov r3, r2 ++3: strd r2, [r0], #8 ++ tst r0, #(15 << 2) ++ bne 3b ++ ++ @ Then sync the 2 corresponding cache lines ++ sub r0, r0, #(16 << 2) ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++4: orr r0, r0, #(15 << 2) ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ mov ip, #0 ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov pc, lr ++ ++ .ltorg ++ ++cpu_manu_name: ++ .asciz "Intel" ++ ++cpu_80200_name: ++ .asciz "XScale-80200" ++ ++cpu_pxa210_name: ++ .asciz "XScale-PXA210" ++ ++cpu_pxa250_name: ++ .asciz "XScale-PXA250" ++ ++cpu_pxa255_name: ++ .asciz "XScale-PXA255" ++ ++ .align ++ ++ .section ".text.init", #alloc, #execinstr ++ ++__xscale_setup: ++ mov r0, #F_BIT|I_BIT|SVC_MODE ++ msr cpsr_c, r0 ++ mcr p15, 0, ip, c7, c7, 0 @ invalidate I, D caches & BTB ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mcr p15, 0, ip, c8, c7, 0 @ invalidate I, D TLBs ++ 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 ++ mov r0, #1 @ Allow user space to access ++ mcr p15, 0, r0, c15, c1, 0 @ ... CP 0 only. ++#if CACHE_WRITE_THROUGH ++ mov r0, #0x20 ++#else ++ mov r0, #0x00 ++#endif ++ mcr p15, 0, r0, c1, c1, 0 @ set auxiliary control reg ++ mrc p15, 0, r0, c1, c0, 0 @ get control register ++ bic r0, r0, #0x0200 @ ......R......... ++ bic r0, r0, #0x0082 @ ........B.....A. ++ orr r0, r0, #0x0005 @ .............C.M ++ orr r0, r0, #0x3900 @ ..VIZ..S........ ++#ifdef CONFIG_XSCALE_CACHE_ERRATA ++ bic r0, r0, #0x0004 @ see cpu_xscale_proc_init ++#endif ++ mov pc, lr ++ ++ .text ++ ++/* ++ * Purpose : Function pointers used to access above functions - all calls ++ * come through these ++ */ ++ ++ .type xscale_processor_functions, #object ++ENTRY(xscale_processor_functions) ++ .word cpu_xscale_data_abort ++ .word cpu_xscale_check_bugs ++ .word cpu_xscale_proc_init ++ .word cpu_xscale_proc_fin ++ .word cpu_xscale_reset ++ .word cpu_xscale_do_idle ++ ++ /* cache */ ++ .word cpu_xscale_cache_clean_invalidate_all ++ .word cpu_xscale_cache_clean_invalidate_range ++ .word cpu_xscale_flush_ram_page ++ ++ /* dcache */ ++ .word cpu_xscale_dcache_invalidate_range ++ .word cpu_xscale_dcache_clean_range ++ .word cpu_xscale_dcache_clean_page ++ .word cpu_xscale_dcache_clean_entry ++ ++ /* icache */ ++ .word cpu_xscale_icache_invalidate_range ++ .word cpu_xscale_icache_invalidate_page ++ ++ /* tlb */ ++ .word cpu_xscale_tlb_invalidate_all ++ .word cpu_xscale_tlb_invalidate_range ++ .word cpu_xscale_tlb_invalidate_page ++ ++ /* pgtable */ ++ .word cpu_xscale_set_pgd ++ .word cpu_xscale_set_pmd ++ .word cpu_xscale_set_pte ++ .size xscale_processor_functions, . - xscale_processor_functions ++ ++ .type cpu_80200_info, #object ++cpu_80200_info: ++ .long cpu_manu_name ++ .long cpu_80200_name ++ .size cpu_80200_info, . - cpu_80200_info ++ ++ .type cpu_pxa210_info, #object ++cpu_pxa210_info: ++ .long cpu_manu_name ++ .long cpu_pxa210_name ++ .size cpu_pxa210_info, . - cpu_pxa210_info ++ ++ .type cpu_pxa250_info, #object ++cpu_pxa250_info: ++ .long cpu_manu_name ++ .long cpu_pxa250_name ++ .size cpu_pxa250_info, . - cpu_pxa250_info ++ ++ .type cpu_pxa255_info, #object ++cpu_pxa255_info: ++ .long cpu_manu_name ++ .long cpu_pxa255_name ++ .size cpu_pxa255_info, . - cpu_pxa255_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 __80200_proc_info,#object ++__80200_proc_info: ++ .long 0x69052000 ++ .long 0xfffffff0 ++#if CACHE_WRITE_THROUGH ++ .long 0x00000c0a ++#else ++ .long 0x00000c0e ++#endif ++ b __xscale_setup ++ .long cpu_arch_name ++ .long cpu_elf_name ++ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_XSCALE ++ .long cpu_80200_info ++ .long xscale_processor_functions ++ .size __80200_proc_info, . - __80200_proc_info ++ ++ .type __pxa210_proc_info,#object ++__pxa210_proc_info: ++ .long 0x69052120 ++ .long 0xfffff3f0 ++#if CACHE_WRITE_THROUGH ++ .long 0x00000c0a ++#else ++ .long 0x00000c0e ++#endif ++ b __xscale_setup ++ .long cpu_arch_name ++ .long cpu_elf_name ++ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_XSCALE ++ .long cpu_pxa210_info ++ .long xscale_processor_functions ++ .size __pxa210_proc_info, . - __pxa210_proc_info ++ ++ .type __pxa250_proc_info,#object ++__pxa250_proc_info: ++ .long 0x69052100 ++ .long 0xfffff7f0 ++#if CACHE_WRITE_THROUGH ++ .long 0x00000c0a ++#else ++ .long 0x00000c0e ++#endif ++ b __xscale_setup ++ .long cpu_arch_name ++ .long cpu_elf_name ++ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_XSCALE ++ .long cpu_pxa250_info ++ .long xscale_processor_functions ++ .size __pxa250_proc_info, . - __pxa250_proc_info ++ ++ .type __pxa255_proc_info,#object ++__pxa255_proc_info: ++ .long 0x69052d00 ++ .long 0xfffffff0 ++#if CACHE_WRITE_THROUGH ++ .long 0x00000c0a ++#else ++ .long 0x00000c0e ++#endif ++ b __xscale_setup ++ .long cpu_arch_name ++ .long cpu_elf_name ++ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_XSCALE ++ .long cpu_pxa255_info ++ .long xscale_processor_functions ++ .size __pxa255_proc_info, . - __pxa255_proc_info ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/vmlinux-armv-xip.lds.in 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,125 @@ ++/* ++ * ld script to make ARM Linux kernel ++ * ++ * (C) Copyright 2001 Lineo Japan, Inc. ++ * ++ * May be copied or modified under the terms of the GNU General Public ++ * License. See linux/COPYING for more information. ++ * ++ * Based on arch/arm/vmlinux-armv.lds.in ++ * ++ * taken from the i386 version by Russell King ++ * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz> ++ */ ++OUTPUT_ARCH(arm) ++ENTRY(stext) ++SECTIONS ++{ ++ . = TEXTADDR; ++ .init : { /* Init code and data */ ++ _stext = .; ++ __init_begin = .; ++ *(.text.init) ++ __proc_info_begin = .; ++ *(.proc.info) ++ __proc_info_end = .; ++ __arch_info_begin = .; ++ *(.arch.info) ++ __arch_info_end = .; ++ __tagtable_begin = .; ++ *(.taglist) ++ __tagtable_end = .; ++ . = ALIGN(16); ++ __setup_start = .; ++ *(.setup.init) ++ __setup_end = .; ++ __initcall_start = .; ++ *(.initcall.init) ++ __initcall_end = .; ++ . = ALIGN(4096); ++ __init_end = .; ++ } ++ ++ /DISCARD/ : { /* Exit code and data */ ++ *(.text.exit) ++ *(.data.exit) ++ *(.exitcall.exit) ++ } ++ ++ .text : { /* Real text segment */ ++ _text = .; /* Text and read-only data */ ++ *(.text) ++ *(.fixup) ++ *(.gnu.warning) ++ *(.text.lock) /* out-of-line lock text */ ++ *(.rodata) ++ *(.rodata.*) ++ *(.glue_7) ++ *(.glue_7t) ++ *(.kstrtab) ++ *(.got) /* Global offset table */ ++ *(.got.plt) ++ ++ _etext = .; /* End of text section */ ++ } ++ ++ . = ALIGN(16); ++ __ex_table : { /* Exception table */ ++ __start___ex_table = .; ++ *(__ex_table) ++ __stop___ex_table = .; ++ } ++ ++ __ksymtab : { /* Kernel symbol table */ ++ __start___ksymtab = .; ++ *(__ksymtab) ++ __stop___ksymtab = .; ++ } ++ ++ _endtext = .; ++ ++ . = DATAADDR; ++ ++ _sdata = .; ++ ++ . = ALIGN(8192); ++ ++ .data : { ++ /* ++ * first, the init task union, aligned ++ * to an 8192 byte boundary. ++ */ ++ *(.init.task) ++ ++ /* ++ * then the cacheline aligned data ++ */ ++ . = ALIGN(32); ++ *(.data.cacheline_aligned) ++ ++ /* ++ * and the usual data section ++ */ ++ *(.data) ++ CONSTRUCTORS ++ ++ *(.data.init) ++ ++ _edata = .; ++ } ++ ++ .bss : { ++ __bss_start = .; /* BSS */ ++ *(.bss) ++ *(COMMON) ++ _end = . ; ++ } ++ /* Stabs debugging sections. */ ++ .stab 0 : { *(.stab) } ++ .stabstr 0 : { *(.stabstr) } ++ .stab.excl 0 : { *(.stab.excl) } ++ .stab.exclstr 0 : { *(.stab.exclstr) } ++ .stab.index 0 : { *(.stab.index) } ++ .stab.indexstr 0 : { *(.stab.indexstr) } ++ .comment 0 : { *(.comment) } ++} +--- linux-2.4.25/drivers/Makefile~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/Makefile 2004-03-31 17:15:11.000000000 +0200 +@@ -25,6 +25,7 @@ + subdir-$(CONFIG_NUBUS) += nubus + subdir-$(CONFIG_TC) += tc + subdir-$(CONFIG_VT) += video ++subdir-$(CONFIG_MMC) += mmc + subdir-$(CONFIG_MAC) += macintosh + subdir-$(CONFIG_PPC32) += macintosh + subdir-$(CONFIG_USB) += usb +--- linux-2.4.25/drivers/char/Config.in~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/char/Config.in 2004-03-31 17:15:11.000000000 +0200 +@@ -253,6 +253,7 @@ + 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 ' PXA250/210 watchdog' CONFIG_SA1100_WATCHDOG $CONFIG_ARCH_PXA + 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 +@@ -335,6 +336,9 @@ + if [ "$CONFIG_ARCH_SA1100" = "y" ]; then + tristate 'SA1100 Real Time Clock' CONFIG_SA1100_RTC + fi ++if [ "$CONFIG_ARCH_PXA" = "y" ]; then ++ tristate 'PXA250/210 Real Time Clock' CONFIG_PXA_RTC ++fi + if [ "$CONFIG_ARCH_OMAHA" = "y" ]; then + tristate 'Omaha Real Time Clock' CONFIG_OMAHA_RTC + fi +@@ -417,4 +421,8 @@ + dep_tristate 'HP OB600 C/CT Pop-up mouse support' CONFIG_OBMOUSE $CONFIG_INPUT_MOUSEDEV + fi + ++if [ "$CONFIG_ARCH_TRIZEPS2" = "y" ]; then ++ tristate ' MT6N TTL I/O suport' CONFIG_TRIZEPS2_TTLIO ++fi ++ + endmenu +--- linux-2.4.25/drivers/char/Makefile~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/char/Makefile 2004-03-31 17:15:11.000000000 +0200 +@@ -280,6 +280,7 @@ + obj-$(CONFIG_MIPS_RTC) += mips_rtc.o + obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o + obj-$(CONFIG_SA1100_RTC) += sa1100-rtc.o ++obj-$(CONFIG_PXA_RTC) += sa1100-rtc.o + obj-$(CONFIG_OMAHA_RTC) += omaha-rtc.o + ifeq ($(CONFIG_PPC),) + obj-$(CONFIG_NVRAM) += nvram.o +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/char/mt6n_ttl.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,316 @@ ++/* ++ * Trizeps-2 MT6N development board TTL-IO interface for Linux ++ * ++ * Copyright (C) 2003 Luc De Cock ++ * ++ * This driver allows use of the TTL-IO interface on the MT6N ++ * from user space. It exports the /dev/ttlio interface supporting ++ * some ioctl() and also the /proc/driver/ttlio pseudo-file ++ * for status information. ++ * ++ * The ioctls can be used to set individual TTL output lines. ++ * Only ioctls are supported. ++ * ++ * 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. ++ * ++ * Based on other minimal char device drivers, like Alan's ++ * watchdog, Ted's random, Paul's rtc, etc. etc. ++ * ++ * 1.00 Luc De Cock: initial version. ++ */ ++ ++#define TTLIO_VERSION "1.00" ++ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <linux/miscdevice.h> ++#include <linux/fcntl.h> ++#include <linux/init.h> ++#include <linux/poll.h> ++#include <linux/proc_fs.h> ++ ++#include <asm/io.h> ++#include <asm/uaccess.h> ++#include <asm/system.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++/* Writing to the register sets the output lines ++* Reading from the register returns the status of the input lines ++*/ ++static unsigned short *ttlio_base = (unsigned short *) TRIZEPS2_TTLIO_BASE; ++static unsigned short ttlio_shadow = 0; ++ ++/* interrupt stuff */ ++static struct fasync_struct *ttlio_async_queue; ++static DECLARE_WAIT_QUEUE_HEAD(ttlio_wait); ++static int ttlio_irq_arrived = 0; ++static spinlock_t ttlio_lock; ++static unsigned short ttlio_in = 0; ++static volatile unsigned long teller = 0; ++ ++ ++static int ttlio_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg); ++ ++static int ttlio_read_proc(char *page, char **start, off_t off, ++ int count, int *eof, void *data); ++ ++ ++static void ttlio_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ ttlio_in = *ttlio_base; ++ ++ ttlio_irq_arrived = 1; ++ teller++; ++ ++ /* wake up the waiting process */ ++ wake_up_interruptible(&ttlio_wait); ++ kill_fasync(&ttlio_async_queue, SIGIO, POLL_IN); ++} ++ ++/* ++ * Now all the various file operations that we export. ++ */ ++ ++static int ttlio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ unsigned long ttlio_val; ++ ++ switch (cmd) { ++ case TTLIO_RESET: /* clear all lines */ ++ { ++ *ttlio_base = 0; ++ return 0; ++ } ++ case TTLIO_GET: /* get state of TTL input lines */ ++ { ++ ttlio_val = *ttlio_base; ++ return put_user(ttlio_val, (unsigned long *)arg); ++ } ++ case TTLIO_SET: /* set state of TTL output lines */ ++ { ++ unsigned long user_val; ++ if (copy_from_user(&user_val, arg, sizeof(unsigned long))) ++ return -EFAULT; ++ ttlio_shadow |= (unsigned short) user_val; ++ *ttlio_base = ttlio_shadow; ++ return 0; ++ } ++ case TTLIO_UNSET: /* unset (clear) state of TTL output lines */ ++ { ++ unsigned long user_val; ++ if (copy_from_user(&user_val, arg, sizeof(unsigned long))) ++ return -EFAULT; ++ ttlio_shadow &= ~((unsigned short) user_val); ++ *ttlio_base = ttlio_shadow; ++ return 0; ++ } ++ case 100: /* get counter */ ++ { ++ return put_user(teller, (unsigned long *)arg); ++ } ++ case 101: /* reset counter */ ++ { ++ teller = 0; ++ return 0; ++ } ++ default: ++ return -ENOTTY; ++ } ++ return 0; ++} ++ ++static ssize_t ttlio_read(struct file *file, char *buf, ++ size_t count, loff_t *ppos) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned short data; ++ ssize_t retval; ++ ++ if (count < sizeof(unsigned short)) ++ return -EINVAL; ++ ++ if (file->f_flags & O_NONBLOCK) { ++ spin_lock_irq(&ttlio_lock); ++ data = *ttlio_base; ++ spin_unlock_irq(&ttlio_lock); ++ retval = put_user(data, (unsigned short *) buf); ++ if (!retval) ++ retval = sizeof(unsigned short); ++ return retval; ++ } ++ /* blocking read: wait for interrupt */ ++ add_wait_queue(&ttlio_wait, &wait); ++ set_current_state(TASK_INTERRUPTIBLE); ++ for (;;) { ++ spin_lock_irq(&ttlio_lock); ++ data = *ttlio_base; ++ if (ttlio_irq_arrived) { ++ ttlio_irq_arrived = 0; ++ break; ++ } ++ spin_unlock_irq(&ttlio_lock); ++ ++ if (signal_pending(current)) { ++ retval = -ERESTARTSYS; ++ goto out; ++ } ++ schedule(); ++ } ++ ++ spin_unlock_irq(&ttlio_lock); ++ retval = put_user(data, (unsigned short *)buf); ++ if (!retval) ++ retval = sizeof(unsigned short); ++ ++out: ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&ttlio_wait, &wait); ++ return retval; ++} ++ ++static ssize_t ttlio_write(struct file *file, ++ const char *buf, size_t count, loff_t *ppos) ++{ ++ unsigned short content; ++ ++ if (count < sizeof(unsigned short)) ++ return -EINVAL; ++ ++ if (copy_from_user (&content, buf, sizeof(unsigned short))) ++ return -EFAULT; ++ ++ ttlio_shadow = content; ++ *ttlio_base = ttlio_shadow; ++ ++ *ppos += sizeof(unsigned short); ++ ++ return sizeof(unsigned short); ++} ++ ++static int ttlio_open(struct inode *inode, struct file *file) ++{ ++ ttlio_irq_arrived = 0; ++ return 0; ++} ++ ++static int ttlio_fasync(int fd, struct file *filp, int on) ++{ ++ return fasync_helper(fd, filp, on, &ttlio_async_queue); ++} ++ ++static unsigned int ttlio_poll(struct file *file, poll_table *wait) ++{ ++ poll_wait(file, &ttlio_wait, wait); ++ return ttlio_irq_arrived ? 0 : POLLIN | POLLRDNORM; ++} ++ ++static loff_t ttlio_llseek(struct file *file, loff_t offset, int origin) ++{ ++ return -ESPIPE; ++} ++ ++/* ++ * The various file operations we support. ++ */ ++ ++static struct file_operations ttlio_fops = { ++ owner: THIS_MODULE, ++ llseek: ttlio_llseek, ++ read: ttlio_read, ++ poll: ttlio_poll, ++ write: ttlio_write, ++ ioctl: ttlio_ioctl, ++ open: ttlio_open, ++ fasync: ttlio_fasync, ++}; ++ ++static struct miscdevice ttlio_dev = { ++ TTLIO_MINOR, ++ "ttlio", ++ &ttlio_fops ++}; ++ ++static int __init ttlio_init(void) ++{ ++ printk(KERN_INFO "MT6N TTL-I/O driver (release %s)\n", ++ TTLIO_VERSION); ++ ++ misc_register(&ttlio_dev); ++ create_proc_read_entry ("driver/ttlio", 0, 0, ttlio_read_proc, NULL); ++ ++ set_GPIO_IRQ_edge(GPIO_TTLIO_IRQ, GPIO_FALLING_EDGE); ++ if (request_irq(TTLIO_IRQ, ttlio_interrupt, SA_INTERRUPT, "ttlio irq", NULL)) { ++ printk(KERN_ERR "ttlio: irq %d already in use\n", TTLIO_IRQ); ++ return 1; ++ } ++ return 0; ++} ++ ++static void __exit ttlio_exit(void) ++{ ++ free_irq(TTLIO_IRQ, NULL); ++ remove_proc_entry ("driver/ttlio", NULL); ++ misc_deregister(&ttlio_dev); ++} ++ ++module_init(ttlio_init); ++module_exit(ttlio_exit); ++EXPORT_NO_SYMBOLS; ++ ++/* ++ * Info exported via "/proc/driver/ttlio". ++ */ ++ ++static int ttlio_proc_output(char *buf) ++{ ++ char *p; ++ unsigned short val; ++ int i; ++ ++ p = buf; ++ ++ p += sprintf(p, "input : "); ++ /* write the state of the input lines */ ++ val = *ttlio_base; ++ for (i = 0; i < 8*sizeof(unsigned short); i++) { ++ *p++ = (val & 1) ? '1' : '0'; ++ val >>= 1; ++ } ++ *p = 0; ++ p += sprintf(p, "\noutput: "); ++ /* write the state of the output lines */ ++ val = ttlio_shadow; ++ for (i = 0; i < 8*sizeof(unsigned short); i++) { ++ *p++ = (val & 1) ? '1' : '0'; ++ val >>= 1; ++ } ++ *p = 0; ++ p += sprintf(p, "\n"); ++ ++ return p - buf; ++} ++ ++static int ttlio_read_proc(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len = ttlio_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; ++} ++ ++MODULE_AUTHOR("Luc De Cock"); ++MODULE_DESCRIPTION("MT6N TTL-I/O driver"); ++MODULE_LICENSE("GPL"); +--- linux-2.4.25/drivers/char/sa1100-rtc.c~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/char/sa1100-rtc.c 2004-03-31 17:15:11.000000000 +0200 +@@ -1,5 +1,6 @@ + /* + * Real Time Clock interface for Linux on StrongARM SA1100 ++ * and XScale PXA250/210. + * + * Copyright (c) 2000 Nils Faerber + * +@@ -470,5 +471,5 @@ + module_exit(rtc_exit); + + MODULE_AUTHOR("Nils Faerber <nils@@kernelconcepts.de>"); +-MODULE_DESCRIPTION("SA1100 Realtime Clock Driver (RTC)"); ++MODULE_DESCRIPTION("SA1100/PXA Realtime Clock Driver (RTC)"); + EXPORT_NO_SYMBOLS; +--- linux-2.4.25/drivers/char/sa1100_wdt.c~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/char/sa1100_wdt.c 2004-03-31 17:15:11.000000000 +0200 +@@ -1,5 +1,5 @@ + /* +- * Watchdog driver for the SA11x0 ++ * Watchdog driver for the SA11x0/PXA + * + * (c) Copyright 2000 Oleg Drokin <green@crimea.edu> + * Based on SoftDog driver by Alan Cox <alan@redhat.com> +@@ -35,13 +35,20 @@ + + #define TIMER_MARGIN 60 /* (secs) Default is 1 minute */ + +-static int sa1100_margin = TIMER_MARGIN; /* in seconds */ ++static int timer_margin = TIMER_MARGIN; /* in seconds */ + static int sa1100wdt_users; + static int pre_margin; + #ifdef MODULE +-MODULE_PARM(sa1100_margin,"i"); ++MODULE_PARM(timer_margin,"i"); + #endif + ++static void sa1100dog_ping( void) ++{ ++ /* reload counter with (new) margin */ ++ pre_margin=3686400 * timer_margin; ++ OSMR3 = OSCR + pre_margin; ++} ++ + /* + * Allow only one person to hold it open + */ +@@ -51,9 +58,7 @@ + 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; ++ sa1100dog_ping(); + OSSR = OSSR_M3; + OWER = OWER_WME; + OIER |= OIER_E3; +@@ -93,8 +98,11 @@ + unsigned int cmd, unsigned long arg) + { + static struct watchdog_info ident = { +- identity: "SA1100 Watchdog", ++ identity: "PXA/SA1100 Watchdog", ++ options: WDIOF_SETTIMEOUT, ++ firmware_version: 0, + }; ++ int new_margin; + + switch(cmd){ + default: +@@ -108,6 +116,16 @@ + case WDIOC_KEEPALIVE: + OSMR3 = OSCR + pre_margin; + return 0; ++ case WDIOC_SETTIMEOUT: ++ if (get_user(new_margin, (int *)arg)) ++ return -EFAULT; ++ if (new_margin < 1) ++ return -EINVAL; ++ timer_margin = new_margin; ++ sa1100dog_ping(); ++ /* Fall */ ++ case WDIOC_GETTIMEOUT: ++ return put_user(timer_margin, (int *)arg); + } + } + +@@ -123,7 +141,11 @@ + static struct miscdevice sa1100dog_miscdev= + { + WATCHDOG_MINOR, +- "SA1100 watchdog", ++#if defined(CONFIG_SA1100_WATCHDOG) ++ "SA1100_watchdog", ++#elif defined(CONFIG_PXA_WATCHDOG) ++ "PXA_watchdog", ++#endif + &sa1100dog_fops + }; + +@@ -136,7 +158,7 @@ + if (ret) + return ret; + +- printk("SA1100 Watchdog Timer: timer margin %d sec\n", sa1100_margin); ++ printk("SA1100/PXA Watchdog Timer: timer margin %d sec\n", timer_margin); + + return 0; + } +--- linux-2.4.25/drivers/char/serial.c~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/char/serial.c 2004-03-31 17:15:11.000000000 +0200 +@@ -133,6 +133,16 @@ + #endif + #endif + ++#ifdef CONFIG_ARCH_PXA ++#define pxa_port(x) ((x) == PORT_PXA) ++#define pxa_buggy_port(x) ({ \ ++ int cpu_ver; asm("mrc%? p15, 0, %0, c0, c0" : "=r" (cpu_ver)); \ ++ ((x) == PORT_PXA && (cpu_ver & ~1) == 0x69052100); }) ++#else ++#define pxa_port(x) (0) ++#define pxa_buggy_port(x) (0) ++#endif ++ + /* Set of debugging defines */ + + #undef SERIAL_DEBUG_INTR +@@ -311,6 +321,7 @@ + { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | + UART_STARTECH }, + { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO }, ++ { "PXA UART", 32, UART_CLEAR_FIFO | UART_USE_FIFO }, + { 0, 0} + }; + +@@ -424,6 +435,9 @@ + case SERIAL_IO_MEM: + return readb((unsigned long) info->iomem_base + + (offset<<info->iomem_reg_shift)); ++ case SERIAL_IO_MEM32: ++ return readl((unsigned long) info->iomem_base + ++ (offset<<info->iomem_reg_shift)); + default: + return inb(info->port + offset); + } +@@ -443,6 +457,10 @@ + writeb(value, (unsigned long) info->iomem_base + + (offset<<info->iomem_reg_shift)); + break; ++ case SERIAL_IO_MEM32: ++ writel(value, (unsigned long) info->iomem_base + ++ (offset<<info->iomem_reg_shift)); ++ break; + default: + outb(value, info->port+offset); + } +@@ -1306,6 +1324,16 @@ + } + #endif + ++#ifdef CONFIG_ARCH_PXA ++ if (state->type == PORT_PXA) { ++ switch ((long)state->iomem_base) { ++ case (long)&FFUART: CKEN |= CKEN6_FFUART; break; ++ case (long)&BTUART: CKEN |= CKEN7_BTUART; break; ++ case (long)&STUART: CKEN |= CKEN5_STUART; break; ++ } ++ } ++#endif ++ + /* + * Clear the FIFO buffers and disable them + * (they will be reenabled in change_speed()) +@@ -1403,6 +1431,8 @@ + { + if (state->irq != 0) + info->MCR |= UART_MCR_OUT2; ++ if (pxa_buggy_port(state->type) && state->irq != 0) ++ info->MCR ^= UART_MCR_OUT2; + } + info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */ + serial_outp(info, UART_MCR, info->MCR); +@@ -1411,6 +1441,8 @@ + * Finally, enable interrupts + */ + info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; ++ if (pxa_port(state->type)) ++ info->IER |= UART_IER_UUE | UART_IER_RTOIE; + serial_outp(info, UART_IER, info->IER); /* enable interrupts */ + + #ifdef CONFIG_SERIAL_MANY_PORTS +@@ -1542,6 +1574,8 @@ + } else + #endif + info->MCR &= ~UART_MCR_OUT2; ++ if (pxa_buggy_port(state->type)) ++ info->MCR ^= UART_MCR_OUT2; + info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */ + + /* disable break condition */ +@@ -1567,6 +1601,20 @@ + state->baud_base = SERIAL_RSA_BAUD_BASE_LO; + #endif + ++#ifdef CONFIG_ARCH_PXA ++ if (state->type == PORT_PXA ++#ifdef CONFIG_SERIAL_CONSOLE ++ && sercons.index != info->line ++#endif ++ ) { ++ switch ((long)state->iomem_base) { ++ case (long)&FFUART: CKEN &= ~CKEN6_FFUART; break; ++ case (long)&BTUART: CKEN &= ~CKEN7_BTUART; break; ++ case (long)&STUART: CKEN &= ~CKEN5_STUART; break; ++ } ++ } ++#endif ++ + + (void)serial_in(info, UART_RX); /* read data port to reset things */ + +@@ -1857,6 +1905,8 @@ + save_flags(flags); cli(); + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); ++ if (pxa_buggy_port(info->state->type)) ++ rs_interrupt_single(info->state->irq, NULL, NULL); + restore_flags(flags); + } + +@@ -1933,6 +1983,11 @@ + && !(info->IER & UART_IER_THRI)) { + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); ++ if (pxa_buggy_port(info->state->type)) { ++ save_flags(flags); cli(); ++ rs_interrupt_single(info->state->irq, NULL, NULL); ++ restore_flags(flags); ++ } + } + return ret; + } +@@ -1990,6 +2045,8 @@ + /* Make sure transmit interrupts are on */ + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); ++ if (pxa_buggy_port(info->state->type)) ++ rs_interrupt_single(info->state->irq, NULL, NULL); + } + } + +@@ -5517,7 +5574,6 @@ + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + state->magic = SSTATE_MAGIC; + state->line = i; +- state->type = PORT_UNKNOWN; + state->custom_divisor = 0; + state->close_delay = 5*HZ/10; + state->closing_wait = 30*HZ; +@@ -5531,14 +5587,18 @@ + state->irq = irq_cannonicalize(state->irq); + if (state->hub6) + state->io_type = SERIAL_IO_HUB6; +- if (state->port && check_region(state->port,8)) ++ if (state->port && check_region(state->port,8)) { ++ state->type = PORT_UNKNOWN; + continue; ++ } + #ifdef CONFIG_MCA + if ((state->flags & ASYNC_BOOT_ONLYMCA) && !MCA_bus) + continue; + #endif +- if (state->flags & ASYNC_BOOT_AUTOCONF) ++ if (state->flags & ASYNC_BOOT_AUTOCONF) { ++ state->type = PORT_UNKNOWN; + autoconfig(state); ++ } + } + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + if (state->type == PORT_UNKNOWN) +@@ -5858,6 +5918,8 @@ + */ + ier = serial_in(info, UART_IER); + serial_out(info, UART_IER, 0x00); ++ if (pxa_port(info->state->type)) ++ serial_out(info, UART_IER, UART_IER_UUE); + + /* + * Now, do each character +@@ -6009,6 +6071,8 @@ + serial_out(info, UART_DLM, quot >> 8); /* MS of divisor */ + serial_out(info, UART_LCR, cval); /* reset DLAB */ + serial_out(info, UART_IER, 0); ++ if (pxa_port(info->state->type)) ++ serial_out(info, UART_IER, UART_IER_UUE); + serial_out(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); + + /* +--- linux-2.4.25/drivers/i2c/Config.in~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/i2c/Config.in 2004-03-31 17:15:11.000000000 +0200 +@@ -54,6 +54,11 @@ + fi + fi + ++ if [ "$CONFIG_ARCH_PXA" = "y" ]; then ++ dep_tristate 'PXA I2C Algorithm' CONFIG_I2C_PXA_ALGO $CONFIG_I2C ++ dep_tristate 'PXA I2C Adapter' CONFIG_I2C_PXA_ADAP $CONFIG_I2C_PXA_ALGO ++ fi ++ + if [ "$CONFIG_ALL_PPC" = "y" ] ; then + dep_tristate 'Keywest I2C interface in Apple Core99 machines' CONFIG_I2C_KEYWEST $CONFIG_I2C + fi +--- linux-2.4.25/drivers/i2c/Makefile~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/i2c/Makefile 2004-03-31 17:15:11.000000000 +0200 +@@ -6,7 +6,7 @@ + + export-objs := i2c-core.o i2c-algo-bit.o i2c-algo-pcf.o \ + i2c-algo-ite.o i2c-algo-sibyte.o i2c-algo-sgi.o \ +- i2c-proc.o ++ i2c-algo-pxa.o i2c-proc.o + + # Init order: core, chardev, bit adapters, pcf adapters + +@@ -35,6 +35,10 @@ + obj-$(CONFIG_I2C_MAX1617) += i2c-max1617.o + obj-$(CONFIG_I2C_ALGO_SGI) += i2c-algo-sgi.o + ++# PXA adapters ++obj-$(CONFIG_I2C_PXA_ALGO) += i2c-algo-pxa.o ++obj-$(CONFIG_I2C_PXA_ADAP) += i2c-adap-pxa.o ++ + # This is needed for automatic patch generation: sensors code starts here + # This is needed for automatic patch generation: sensors code ends here + +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/i2c/i2c-adap-pxa.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,396 @@ ++/* ++ * i2c_adap_pxa.c ++ * ++ * I2C adapter for the PXA I2C bus access. ++ * ++ * 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. ++ * ++ * History: ++ * Apr 2002: Initial version [CS] ++ * Jun 2002: Properly seperated algo/adap [FB] ++ * Jan 2003: Fixed several bugs concerning interrupt handling [Kai-Uwe Bloem] ++ * Jan 2003: added limited signal handling [Kai-Uwe Bloem] ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++ ++#include <linux/i2c.h> ++#include <linux/i2c-id.h> ++#include <linux/init.h> ++#include <linux/time.h> ++#include <linux/sched.h> ++#include <linux/delay.h> ++#include <linux/errno.h> ++ ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/arch/irqs.h> /* for IRQ_I2C */ ++ ++#include "i2c-pxa.h" ++ ++/* ++ * Set this to zero to remove all debug statements via dead code elimination. ++ */ ++//#define DEBUG 1 ++ ++#if DEBUG ++static unsigned int i2c_debug = DEBUG; ++#else ++#define i2c_debug 0 ++#endif ++ ++static int irq = 0; ++static volatile int i2c_pending = 0; /* interrupt pending when 1 */ ++static volatile int bus_error = 0; ++static volatile int tx_finished = 0; ++static volatile int rx_finished = 0; ++ ++static wait_queue_head_t i2c_wait; ++static void i2c_pxa_transfer( int lastbyte, int receive, int midbyte); ++ ++/* place a byte in the transmit register */ ++static void i2c_pxa_write_byte(u8 value) ++{ ++ IDBR = value; ++} ++ ++/* read byte in the receive register */ ++static u8 i2c_pxa_read_byte(void) ++{ ++ return (u8) (0xff & IDBR); ++} ++ ++static void i2c_pxa_start(void) ++{ ++ unsigned long icr = ICR; ++ icr |= ICR_START; ++ icr &= ~(ICR_STOP | ICR_ALDIE | ICR_ACKNAK); ++ ICR = icr; ++ ++ bus_error=0; /* clear any bus_error from previous txfers */ ++ tx_finished=0; /* clear rx and tx interrupts from previous txfers */ ++ rx_finished=0; ++ i2c_pending = 0; ++} ++ ++static void i2c_pxa_repeat_start(void) ++{ ++ unsigned long icr = ICR; ++ icr |= ICR_START; ++ icr &= ~(ICR_STOP | ICR_ALDIE); ++ ICR = icr; ++ ++ bus_error=0; /* clear any bus_error from previous txfers */ ++ tx_finished=0; /* clear rx and tx interrupts from previous txfers */ ++ rx_finished=0; ++ i2c_pending = 0; ++} ++ ++static void i2c_pxa_stop(void) ++{ ++ unsigned long icr = ICR; ++ icr |= ICR_STOP; ++ icr &= ~(ICR_START); ++ ICR = icr; ++} ++ ++static void i2c_pxa_midbyte(void) ++{ ++ unsigned long icr = ICR; ++ icr &= ~(ICR_START | ICR_STOP); ++ ICR = icr; ++} ++ ++static void i2c_pxa_abort(void) ++{ ++ unsigned long timeout = jiffies + HZ/4; ++ ++#ifdef PXA_ABORT_MA ++ while ((long)(timeout - jiffies) > 0 && (ICR & ICR_TB)) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(1); ++ } ++ ++ ICR |= ICR_MA; ++ udelay(100); ++#else ++ while ((long)(timeout - jiffies) > 0 && (IBMR & 0x1) == 0) { ++ i2c_pxa_transfer( 1, I2C_RECEIVE, 1); ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(1); ++ } ++#endif ++ ICR &= ~(ICR_MA | ICR_START | ICR_STOP); ++} ++ ++static int i2c_pxa_wait_bus_not_busy( void) ++{ ++ int timeout = DEF_TIMEOUT; ++ ++ while (timeout-- && (ISR & ISR_IBB)) { ++ udelay(100); /* wait for 100 us */ ++ } ++ ++ return (timeout<=0); ++} ++ ++static void i2c_pxa_wait_for_ite(void){ ++ unsigned long flags; ++ if (irq > 0) { ++ save_flags_cli(flags); ++ if (i2c_pending == 0) { ++ interruptible_sleep_on_timeout(&i2c_wait, I2C_SLEEP_TIMEOUT ); ++ } ++ i2c_pending = 0; ++ restore_flags(flags); ++ } else { ++ udelay(100); ++ } ++} ++ ++static int i2c_pxa_wait_for_int( int wait_type) ++{ ++ int timeout = DEF_TIMEOUT; ++#ifdef DEBUG ++ if (bus_error) ++ printk(KERN_INFO"i2c_pxa_wait_for_int: Bus error on enter\n"); ++ if (rx_finished) ++ printk(KERN_INFO"i2c_pxa_wait_for_int: Receive interrupt on enter\n"); ++ if (tx_finished) ++ printk(KERN_INFO"i2c_pxa_wait_for_int: Transmit interrupt on enter\n"); ++#endif ++ ++ if (wait_type == I2C_RECEIVE){ /* wait on receive */ ++ ++ do { ++ i2c_pxa_wait_for_ite(); ++ } while (!(rx_finished) && timeout-- && !signal_pending(current)); ++ ++#ifdef DEBUG ++ if (timeout<0){ ++ if (tx_finished) ++ printk("Error: i2c-algo-pxa.o: received a tx" ++ " interrupt while waiting on a rx in wait_for_int"); ++ } ++#endif ++ } else { /* wait on transmit */ ++ ++ do { ++ i2c_pxa_wait_for_ite(); ++ } while (!(tx_finished) && timeout-- && !signal_pending(current)); ++ ++#ifdef DEBUG ++ if (timeout<0){ ++ if (rx_finished) ++ printk("Error: i2c-algo-pxa.o: received a rx" ++ " interrupt while waiting on a tx in wait_for_int"); ++ } ++#endif ++ } ++ ++ udelay(ACK_DELAY); /* this is needed for the bus error */ ++ ++ tx_finished=0; ++ rx_finished=0; ++ ++ if (bus_error){ ++ bus_error=0; ++ if( i2c_debug > 2)printk("wait_for_int: error - no ack.\n"); ++ return BUS_ERROR; ++ } ++ ++ if (signal_pending(current)) { ++ return (-ERESTARTSYS); ++ } else if (timeout < 0) { ++ if( i2c_debug > 2)printk("wait_for_int: timeout.\n"); ++ return(-EIO); ++ } else ++ return(0); ++} ++ ++static void i2c_pxa_transfer( int lastbyte, int receive, int midbyte) ++{ ++ if( lastbyte) ++ { ++ if( receive==I2C_RECEIVE) ICR |= ICR_ACKNAK; ++ i2c_pxa_stop(); ++ } ++ else if( midbyte) ++ { ++ i2c_pxa_midbyte(); ++ } ++ ICR |= ICR_TB; ++} ++ ++static void i2c_pxa_reset( void) ++{ ++#ifdef DEBUG ++ printk("Resetting I2C Controller Unit\n"); ++#endif ++ ++ /* abort any transfer currently under way */ ++ i2c_pxa_abort(); ++ ++ /* reset according to 9.8 */ ++ ICR = ICR_UR; ++ ISR = I2C_ISR_INIT; ++ ICR &= ~ICR_UR; ++ ++ /* set the global I2C clock on */ ++ CKEN |= CKEN14_I2C; ++ ++ /* set our slave address */ ++ ISAR = I2C_PXA_SLAVE_ADDR; ++ ++ /* set control register values */ ++ ICR = I2C_ICR_INIT; ++ ++ /* clear any leftover states from prior transmissions */ ++ i2c_pending = rx_finished = tx_finished = bus_error = 0; ++ ++ /* enable unit */ ++ ICR |= ICR_IUE; ++ udelay(100); ++} ++ ++static void i2c_pxa_handler(int this_irq, void *dev_id, struct pt_regs *regs) ++{ ++ int status, wakeup = 0; ++ status = (ISR); ++ ++ if (status & ISR_BED){ ++ (ISR) |= ISR_BED; ++ bus_error=ISR_BED; ++ wakeup = 1; ++ } ++ if (status & ISR_ITE){ ++ (ISR) |= ISR_ITE; ++ tx_finished=ISR_ITE; ++ wakeup = 1; ++ } ++ if (status & ISR_IRF){ ++ (ISR) |= ISR_IRF; ++ rx_finished=ISR_IRF; ++ wakeup = 1; ++ } ++ if (wakeup) { ++ i2c_pending = 1; ++ wake_up_interruptible(&i2c_wait); ++ } ++} ++ ++static int i2c_pxa_resource_init( void) ++{ ++ init_waitqueue_head(&i2c_wait); ++ ++ if (request_irq(IRQ_I2C, &i2c_pxa_handler, SA_INTERRUPT, "I2C_PXA", 0) < 0) { ++ irq = 0; ++ if( i2c_debug) ++ printk(KERN_INFO "I2C: Failed to register I2C irq %i\n", IRQ_I2C); ++ return -ENODEV; ++ }else{ ++ irq = IRQ_I2C; ++ enable_irq(irq); ++ } ++ return 0; ++} ++ ++static void i2c_pxa_resource_release( void) ++{ ++ if( irq > 0) ++ { ++ disable_irq(irq); ++ free_irq(irq,0); ++ irq=0; ++ } ++} ++ ++static void i2c_pxa_inc_use(struct i2c_adapter *adap) ++{ ++#ifdef MODULE ++ MOD_INC_USE_COUNT; ++#endif ++} ++ ++static void i2c_pxa_dec_use(struct i2c_adapter *adap) ++{ ++#ifdef MODULE ++ MOD_DEC_USE_COUNT; ++#endif ++} ++ ++static int i2c_pxa_client_register(struct i2c_client *client) ++{ ++ return 0; ++} ++ ++static int i2c_pxa_client_unregister(struct i2c_client *client) ++{ ++ return 0; ++} ++ ++static struct i2c_algo_pxa_data i2c_pxa_data = { ++ write_byte: i2c_pxa_write_byte, ++ read_byte: i2c_pxa_read_byte, ++ ++ start: i2c_pxa_start, ++ repeat_start: i2c_pxa_repeat_start, ++ stop: i2c_pxa_stop, ++ abort: i2c_pxa_abort, ++ ++ wait_bus_not_busy: i2c_pxa_wait_bus_not_busy, ++ wait_for_interrupt: i2c_pxa_wait_for_int, ++ transfer: i2c_pxa_transfer, ++ reset: i2c_pxa_reset, ++ ++ udelay: 10, ++ timeout: DEF_TIMEOUT, ++}; ++ ++static struct i2c_adapter i2c_pxa_ops = { ++ name: "PXA-I2C-Adapter", ++ id: I2C_ALGO_PXA, ++ algo_data: &i2c_pxa_data, ++ inc_use: i2c_pxa_inc_use, ++ dec_use: i2c_pxa_dec_use, ++ client_register: i2c_pxa_client_register, ++ client_unregister: i2c_pxa_client_unregister, ++ retries: 2, ++}; ++ ++extern int i2c_pxa_add_bus(struct i2c_adapter *); ++extern int i2c_pxa_del_bus(struct i2c_adapter *); ++ ++static int __init i2c_adap_pxa_init(void) ++{ ++ if( i2c_pxa_resource_init() == 0) { ++ ++ if (i2c_pxa_add_bus(&i2c_pxa_ops) < 0) { ++ i2c_pxa_resource_release(); ++ printk(KERN_INFO "I2C: Failed to add bus\n"); ++ return -ENODEV; ++ } ++ } else { ++ return -ENODEV; ++ } ++ ++ printk(KERN_INFO "I2C: Successfully added bus\n"); ++ ++ return 0; ++} ++ ++static void i2c_adap_pxa_exit(void) ++{ ++ i2c_pxa_del_bus( &i2c_pxa_ops); ++ i2c_pxa_resource_release(); ++ ++ printk(KERN_INFO "I2C: Successfully removed bus\n"); ++} ++ ++module_init(i2c_adap_pxa_init); ++module_exit(i2c_adap_pxa_exit); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/i2c/i2c-algo-pxa.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,376 @@ ++/* ++ * i2c-algo-pxa.c ++ * ++ * I2C algorithm for the PXA I2C bus access. ++ * Byte driven algorithm similar to pcf. ++ * ++ * 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. ++ * ++ * History: ++ * Apr 2002: Initial version [CS] ++ * Jun 2002: Properly seperated algo/adap [FB] ++ * Jan 2003: added limited signal handling [Kai-Uwe Bloem] ++ * Jan 2003: allow SMBUS_QUICK as valid msg [FB] ++ * ++ */ ++#include <linux/kernel.h> ++#include <linux/module.h> ++ ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/errno.h> ++#include <linux/i2c.h> /* struct i2c_msg and others */ ++#include <linux/i2c-id.h> ++ ++#include "i2c-pxa.h" ++ ++/* ++ * Set this to zero to remove all the debug statements via dead code elimination. ++ */ ++//#define DEBUG 1 ++ ++#if DEBUG ++static unsigned int i2c_debug = DEBUG; ++#else ++#define i2c_debug 0 ++#endif ++ ++static int pxa_scan = 1; ++ ++static int i2c_pxa_valid_messages( struct i2c_msg msgs[], int num) ++{ ++ int i; ++ if (num < 1 || num > MAX_MESSAGES){ ++ if( i2c_debug) ++ printk(KERN_INFO "Invalid number of messages (max=%d, num=%d)\n", ++ MAX_MESSAGES, num); ++ return -EINVAL; ++ } ++ ++ /* check consistency of our messages */ ++ for (i=0;i<num;i++){ ++ if (&msgs[i]==NULL){ ++ if( i2c_debug) printk(KERN_INFO "Msgs is NULL\n"); ++ return -EINVAL; ++ } else { ++ if (msgs[i].len < 0 || msgs[i].buf == NULL){ ++ if( i2c_debug)printk(KERN_INFO "Length is less than zero"); ++ return -EINVAL; ++ } ++ } ++ } ++ ++ return 1; ++} ++ ++static int i2c_pxa_readbytes(struct i2c_adapter *i2c_adap, char *buf, ++ int count, int last) ++{ ++ ++ int i, timeout=0; ++ struct i2c_algo_pxa_data *adap = i2c_adap->algo_data; ++ ++ /* increment number of bytes to read by one -- read dummy byte */ ++ for (i = 0; i <= count; i++) { ++ if (i!=0){ ++ /* set ACK to NAK for last received byte ICR[ACKNAK] = 1 ++ only if not a repeated start */ ++ ++ if ((i == count) && last) { ++ adap->transfer( last, I2C_RECEIVE, 0); ++ }else{ ++ adap->transfer( 0, I2C_RECEIVE, 1); ++ } ++ ++ timeout = adap->wait_for_interrupt(I2C_RECEIVE); ++ ++#ifdef DEBUG ++ if (timeout==BUS_ERROR){ ++ printk(KERN_INFO "i2c_pxa_readbytes: bus error -> forcing reset\n"); ++ adap->reset(); ++ return I2C_RETRY; ++ } else ++#endif ++ if (timeout == -ERESTARTSYS) { ++ adap->abort(); ++ return timeout; ++ } else ++ if (timeout){ ++#ifdef DEBUG ++ printk(KERN_INFO "i2c_pxa_readbytes: timeout -> forcing reset\n"); ++#endif ++ adap->reset(); ++ return I2C_RETRY; ++ } ++ ++ } ++ ++ if (i) { ++ buf[i - 1] = adap->read_byte(); ++ } else { ++ adap->read_byte(); /* dummy read */ ++ } ++ } ++ return (i - 1); ++} ++ ++static int i2c_pxa_sendbytes(struct i2c_adapter *i2c_adap, const char *buf, ++ int count, int last) ++{ ++ ++ struct i2c_algo_pxa_data *adap = i2c_adap->algo_data; ++ int wrcount, timeout; ++ ++ for (wrcount=0; wrcount<count; ++wrcount) { ++ ++ adap->write_byte(buf[wrcount]); ++ if ((wrcount==(count-1)) && last) { ++ adap->transfer( last, I2C_TRANSMIT, 0); ++ }else{ ++ adap->transfer( 0, I2C_TRANSMIT, 1); ++ } ++ ++ timeout = adap->wait_for_interrupt(I2C_TRANSMIT); ++ ++#ifdef DEBUG ++ if (timeout==BUS_ERROR) { ++ printk(KERN_INFO "i2c_pxa_sendbytes: bus error -> forcing reset.\n"); ++ adap->reset(); ++ return I2C_RETRY; ++ } else ++#endif ++ if (timeout == -ERESTARTSYS) { ++ adap->abort(); ++ return timeout; ++ } else ++ if (timeout) { ++#ifdef DEBUG ++ printk(KERN_INFO "i2c_pxa_sendbytes: timeout -> forcing reset\n"); ++#endif ++ adap->reset(); ++ return I2C_RETRY; ++ } ++ } ++ return (wrcount); ++} ++ ++ ++static inline int i2c_pxa_set_ctrl_byte(struct i2c_algo_pxa_data * adap, struct i2c_msg *msg) ++{ ++ u16 flags = msg->flags; ++ u8 addr; ++ addr = (u8) ( (0x7f & msg->addr) << 1 ); ++ if (flags & I2C_M_RD ) ++ addr |= 1; ++ if (flags & I2C_M_REV_DIR_ADDR ) ++ addr ^= 1; ++ adap->write_byte(addr); ++ return 0; ++} ++ ++static int i2c_pxa_do_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) ++{ ++ struct i2c_algo_pxa_data * adap; ++ struct i2c_msg *pmsg=NULL; ++ int i; ++ int ret=0, timeout; ++ ++ adap = i2c_adap->algo_data; ++ ++ timeout = adap->wait_bus_not_busy(); ++ ++ if (timeout) { ++ return I2C_RETRY; ++ } ++ ++ for (i = 0;ret >= 0 && i < num; i++) { ++ int last = i + 1 == num; ++ pmsg = &msgs[i]; ++ ++ ret = i2c_pxa_set_ctrl_byte(adap,pmsg); ++ ++ /* Send START */ ++ if (i == 0) { ++ adap->start(); ++ }else{ ++ adap->repeat_start(); ++ } ++ ++ adap->transfer(0, I2C_TRANSMIT, 0); ++ ++ /* Wait for ITE (transmit empty) */ ++ timeout = adap->wait_for_interrupt(I2C_TRANSMIT); ++ ++#ifdef DEBUG ++ /* Check for ACK (bus error) */ ++ if (timeout==BUS_ERROR){ ++ printk(KERN_INFO "i2c_pxa_do_xfer: bus error -> forcing reset\n"); ++ adap->reset(); ++ return I2C_RETRY; ++ } else ++#endif ++ if (timeout == -ERESTARTSYS) { ++ adap->abort(); ++ return timeout; ++ } else ++ if (timeout) { ++#ifdef DEBUG ++ printk(KERN_INFO "i2c_pxa_do_xfer: timeout -> forcing reset\n"); ++#endif ++ adap->reset(); ++ return I2C_RETRY; ++ } ++/* FIXME: handle arbitration... */ ++#if 0 ++ /* Check for bus arbitration loss */ ++ if (adap->arbitration_loss()){ ++ printk("Arbitration loss detected \n"); ++ adap->reset(); ++ return I2C_RETRY; ++ } ++#endif ++ ++ /* Read */ ++ if (pmsg->flags & I2C_M_RD) { ++ /* read bytes into buffer*/ ++ ret = i2c_pxa_readbytes(i2c_adap, pmsg->buf, pmsg->len, last); ++#if DEBUG > 2 ++ if (ret != pmsg->len) { ++ printk(KERN_INFO"i2c_pxa_do_xfer: read %d/%d bytes.\n", ++ ret, pmsg->len); ++ } else { ++ printk(KERN_INFO"i2c_pxa_do_xfer: read %d bytes.\n",ret); ++ } ++#endif ++ } else { /* Write */ ++ ret = i2c_pxa_sendbytes(i2c_adap, pmsg->buf, pmsg->len, last); ++#if DEBUG > 2 ++ if (ret != pmsg->len) { ++ printk(KERN_INFO"i2c_pxa_do_xfer: wrote %d/%d bytes.\n", ++ ret, pmsg->len); ++ } else { ++ printk(KERN_INFO"i2c_pxa_do_xfer: wrote %d bytes.\n",ret); ++ } ++#endif ++ } ++ } ++ ++ if (ret<0){ ++ return ret; ++ }else{ ++ return i; ++ } ++} ++ ++static int i2c_pxa_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) ++{ ++ int retval = i2c_pxa_valid_messages( msgs, num); ++ if( retval > 0) ++ { ++ int i; ++ for (i=i2c_adap->retries; i>=0; i--){ ++ int retval = i2c_pxa_do_xfer(i2c_adap,msgs,num); ++ if (retval!=I2C_RETRY){ ++ return retval; ++ } ++ if( i2c_debug)printk(KERN_INFO"Retrying transmission \n"); ++ udelay(100); ++ } ++ if( i2c_debug)printk(KERN_INFO"Retried %i times\n",i2c_adap->retries); ++ return -EREMOTEIO; ++ ++ } ++ return retval; ++} ++ ++struct i2c_algorithm i2c_pxa_algorithm = { ++ name: "PXA-I2C-Algorithm", ++ id: I2C_ALGO_PXA, ++ master_xfer: i2c_pxa_xfer, ++ smbus_xfer: NULL, ++ slave_send: NULL, ++ slave_recv: NULL, ++ algo_control: NULL, ++}; ++ ++/* ++ * registering functions to load algorithms at runtime ++ */ ++int i2c_pxa_add_bus(struct i2c_adapter *i2c_adap) ++{ ++ struct i2c_algo_pxa_data *adap = i2c_adap->algo_data; ++ ++ printk(KERN_INFO"I2C: Adding %s.\n", i2c_adap->name); ++ ++ i2c_adap->algo = &i2c_pxa_algorithm; ++ ++ MOD_INC_USE_COUNT; ++ ++ /* register new adapter to i2c module... */ ++ i2c_add_adapter(i2c_adap); ++ ++ adap->reset(); ++ ++ /* scan bus */ ++ if (pxa_scan) { ++ int i; ++ printk(KERN_INFO "I2C: Scanning bus "); ++ for (i = 0x02; i < 0xff; i+=2) { ++ if( i==(I2C_PXA_SLAVE_ADDR<<1)) continue; ++ ++ if (adap->wait_bus_not_busy()) { ++ printk(KERN_INFO "I2C: scanning bus %s - TIMEOUTed.\n", ++ i2c_adap->name); ++ return -EIO; ++ } ++ adap->write_byte(i); ++ adap->start(); ++ adap->transfer(0, I2C_TRANSMIT, 0); ++ ++ if ((adap->wait_for_interrupt(I2C_TRANSMIT) != BUS_ERROR)) { ++ printk("(%02x)",i>>1); ++ adap->abort(); ++ } else { ++// printk("."); ++ adap->stop(); ++ } ++ udelay(adap->udelay); ++ } ++ printk("\n"); ++ } ++ return 0; ++} ++ ++int i2c_pxa_del_bus(struct i2c_adapter *i2c_adap) ++{ ++ int res; ++ if ((res = i2c_del_adapter(i2c_adap)) < 0) ++ return res; ++ ++ MOD_DEC_USE_COUNT; ++ ++ printk(KERN_INFO "I2C: Removing %s.\n", i2c_adap->name); ++ ++ return 0; ++} ++ ++static int __init i2c_algo_pxa_init (void) ++{ ++ printk(KERN_INFO "I2C: PXA algorithm module loaded.\n"); ++ return 0; ++} ++ ++EXPORT_SYMBOL(i2c_pxa_add_bus); ++EXPORT_SYMBOL(i2c_pxa_del_bus); ++ ++MODULE_PARM(pxa_scan, "i"); ++MODULE_PARM_DESC(pxa_scan, "Scan for active chips on the bus"); ++ ++MODULE_AUTHOR("Intrinsyc Software Inc."); ++MODULE_LICENSE("GPL"); ++ ++module_init(i2c_algo_pxa_init); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/i2c/i2c-pxa.h 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,76 @@ ++/* ++ * i2c_pxa.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 _I2C_PXA_H_ ++#define _I2C_PXA_H_ ++ ++struct i2c_algo_pxa_data ++{ ++ void (*write_byte) (u8 value); ++ u8 (*read_byte) (void); ++ void (*start) (void); ++ void (*repeat_start) (void); ++ void (*stop) (void); ++ void (*abort) (void); ++ int (*wait_bus_not_busy) (void); ++ int (*wait_for_interrupt) (int wait_type); ++ void (*transfer) (int lastbyte, int receive, int midbyte); ++ void (*reset) (void); ++ ++ int udelay; ++ int timeout; ++}; ++ ++#define DEF_TIMEOUT 3 ++#define BUS_ERROR (-EREMOTEIO) ++#define ACK_DELAY 0 /* time to delay before checking bus error */ ++#define MAX_MESSAGES 65536 /* maximum number of messages to send */ ++ ++#define I2C_SLEEP_TIMEOUT 2 /* time to sleep for on i2c transactions */ ++#define I2C_RETRY (-2000) /* an error has occurred retry transmit */ ++#define I2C_TRANSMIT 1 ++#define I2C_RECEIVE 0 ++#define I2C_PXA_SLAVE_ADDR 0x1 /* slave pxa unit address */ ++#define I2C_ICR_INIT (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE) /* ICR initialization value */ ++/* ICR initialize bit values ++* ++* 15. FM 0 (100 Khz operation) ++* 14. UR 0 (No unit reset) ++* 13. SADIE 0 (Disables the unit from interrupting on slave addresses ++* matching its slave address) ++* 12. ALDIE 0 (Disables the unit from interrupt when it loses arbitration ++* in master mode) ++* 11. SSDIE 0 (Disables interrupts from a slave stop detected, in slave mode) ++* 10. BEIE 1 (Enable interrupts from detected bus errors, no ACK sent) ++* 9. IRFIE 1 (Enable interrupts from full buffer received) ++* 8. ITEIE 1 (Enables the I2C unit to interrupt when transmit buffer empty) ++* 7. GCD 1 (Disables i2c unit response to general call messages as a slave) ++* 6. IUE 0 (Disable unit until we change settings) ++* 5. SCLE 1 (Enables the i2c clock output for master mode (drives SCL) ++* 4. MA 0 (Only send stop with the ICR stop bit) ++* 3. TB 0 (We are not transmitting a byte initially) ++* 2. ACKNAK 0 (Send an ACK after the unit receives a byte) ++* 1. STOP 0 (Do not send a STOP) ++* 0. START 0 (Do not send a START) ++* ++*/ ++ ++#define I2C_ISR_INIT 0x7FF /* status register init */ ++/* I2C status register init values ++ * ++ * 10. BED 1 (Clear bus error detected) ++ * 9. SAD 1 (Clear slave address detected) ++ * 7. IRF 1 (Clear IDBR Receive Full) ++ * 6. ITE 1 (Clear IDBR Transmit Empty) ++ * 5. ALD 1 (Clear Arbitration Loss Detected) ++ * 4. SSD 1 (Clear Slave Stop Detected) ++ */ ++ ++#endif +--- linux-2.4.25/drivers/misc/Config.in~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/misc/Config.in 2004-03-31 17:15:11.000000000 +0200 +@@ -13,5 +13,6 @@ + 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 ++dep_tristate ' UCB1400 Touchscreen support' CONFIG_MCP_UCB1400_TS $CONFIG_ARCH_PXA $CONFIG_SOUND + + endmenu +--- linux-2.4.25/drivers/misc/Makefile~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/misc/Makefile 2004-03-31 17:15:11.000000000 +0200 +@@ -11,13 +11,15 @@ + + O_TARGET := misc.o + +-export-objs := mcp-core.o mcp-sa1100.o ucb1x00-core.o ++export-objs := mcp-core.o mcp-sa1100.o mcp-pxa.o \ ++ ucb1x00-core.o + +-obj-$(CONFIG_MCP) += mcp-core.o +-obj-$(CONFIG_MCP_SA1100) += mcp-sa1100.o ++obj-$(CONFIG_MCP_SA1100) += mcp-core.o 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 ++obj-$(CONFIG_MCP_UCB1400_TS) += mcp-pxa.o ucb1x00-core.o ucb1x00-ts.o ++obj-$(CONFIG_PXA_CERF_PDA) += cerf_ucb1400gpio.o + + include $(TOPDIR)/Rules.make + +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/misc/cerf_ucb1400gpio.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,189 @@ ++/* ++ * cerf_ucb1400gpio.c ++ * ++ * UCB1400 GPIO control stuff for the cerf. ++ * ++ * 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. ++ * ++ * History: ++ * Mar 2002: Initial version [FB] ++ * Jun 2002: Removed ac97 dependency [FB] ++ * ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/ctype.h> ++#include <linux/mm.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++ ++#include <asm/system.h> ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++ ++#include "ucb1x00.h" ++ ++/* ++ * Set this to zero to remove all the debug statements via ++ * dead code elimination. ++ */ ++#define DEBUGGING 0 ++ ++#if DEBUGGING ++static unsigned int ucb_debug = DEBUGGING; ++#else ++#define ucb_debug 0 ++#endif ++ ++#define UP 1 ++#define DOWN 0 ++ ++/* -- -- */ ++ ++void cerf_ucb1400gpio_lcd_enable( void) ++{ ++ struct ucb1x00 * ucb = ucb1x00_get(); ++ if( ucb_debug > 2) printk( KERN_INFO "Enabling LCD.\n"); ++ /* Enable [not] LCD_RESET to enable the LCD display */ ++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_LCD_RESET); ++ ucb1x00_io_write( ucb, UCB1400_GPIO_LCD_RESET, 0); ++ ++ /* Enable the Contrast circuit */ ++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_CONT_ENA); ++ ucb1x00_io_write( ucb, UCB1400_GPIO_CONT_ENA, 0); ++} ++ ++void cerf_ucb1400gpio_lcd_disable( void) ++{ ++ struct ucb1x00 * ucb = ucb1x00_get(); ++ if( ucb_debug > 2) printk( KERN_INFO "Disabling LCD.\n"); ++ /* Disable the Contrast circuit */ ++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_CONT_ENA); ++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_ENA); ++ ++ /* Disable [not] LCD_RESET to enable the LCD display */ ++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_LCD_RESET); ++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_LCD_RESET); ++} ++ ++void cerf_ucb1400gpio_lcd_contrast_step( int direction) ++{ ++ struct ucb1x00 * ucb = ucb1x00_get(); ++ // Assert the chip select and the up modifier ++ ucb1x00_io_set_dir( ucb, 0, ++ (UCB1400_GPIO_CONT_CS | ++ UCB1400_GPIO_CONT_DOWN | ++ UCB1400_GPIO_CONT_INC)); ++ ++ if( direction == DOWN) ++ { ++ if( ucb_debug > 3) ++ printk(KERN_INFO "cerf_ucb1400gpio_lcd_contrast_step: " ++ "stepping up\n"); ++ //goin' up ++ ucb1x00_io_write( ucb, UCB1400_GPIO_CONT_DOWN, 0); ++ } ++ else ++ { ++ if( ucb_debug > 3) ++ printk(KERN_INFO "cerf_ucb1400gpio_lcd_contrast_step: " ++ "stepping down\n"); ++ //goin' down ++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_DOWN); ++ } ++ ++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_CS); ++ ++ // Assert the line up, down then up again ++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_INC); ++ udelay(1); ++ ucb1x00_io_write( ucb, UCB1400_GPIO_CONT_INC, 0); ++ udelay(1); ++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_INC); ++ ++ // Deassert the chip select and the up modifier ++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_DOWN); ++ ucb1x00_io_write( ucb, UCB1400_GPIO_CONT_CS, 0); ++} ++ ++/* -- -- */ ++ ++void cerf_ucb1400gpio_irda_enable( void) ++{ ++ struct ucb1x00 * ucb = ucb1x00_get(); ++ printk( KERN_INFO "Enabling IRDA.\n"); ++ /* Enable IRDA (active low) */ ++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_IRDA_ENABLE); ++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_IRDA_ENABLE); ++} ++ ++void cerf_ucb1400gpio_irda_disable( void) ++{ ++ struct ucb1x00 * ucb = ucb1x00_get(); ++ printk( KERN_INFO "Disabling IRDA.\n"); ++ /* Disable IRDA (active low) */ ++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_IRDA_ENABLE); ++ ucb1x00_io_write( ucb, UCB1400_GPIO_IRDA_ENABLE, 0); ++} ++ ++/* -- -- */ ++ ++void cerf_ucb1400gpio_bt_enable( void) ++{ ++ struct ucb1x00 * ucb = ucb1x00_get(); ++ printk( KERN_INFO "Enabling Bluetooth.\n"); ++ /* Enable BT (active low) */ ++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_BT_ENABLE); ++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_BT_ENABLE); ++} ++ ++void cerf_ucb1400gpio_bt_disable( void) ++{ ++ struct ucb1x00 * ucb = ucb1x00_get(); ++ printk( KERN_INFO "Disabling Bluetooth.\n"); ++ /* Disable BT (active low) */ ++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_BT_ENABLE); ++ ucb1x00_io_write( ucb, UCB1400_GPIO_BT_ENABLE, 0); ++} ++ ++/* -- -- */ ++ ++/* -- Enable Bluetooth and IRDA automatically via pseudo module -- */ ++#if defined(CONFIG_BLUEZ) || defined(CONFIG_IRDA) ++static int __init cerf_ucb1400gpio_module_init (void) ++{ ++#ifdef CONFIG_BLUEZ ++ cerf_ucb1400gpio_bt_enable(); ++#endif ++ ++#ifdef CONFIG_IRDA ++ cerf_ucb1400gpio_irda_enable(); ++#endif ++ return 0; ++} ++ ++static void __exit cerf_ucb1400gpio_module_exit (void) ++{ ++#ifdef CONFIG_BLUEZ ++ cerf_ucb1400gpio_bt_disable(); ++#endif ++ ++#ifdef CONFIG_IRDA ++ cerf_ucb1400gpio_irda_disable(); ++#endif ++} ++ ++module_init(cerf_ucb1400gpio_module_init); ++module_exit(cerf_ucb1400gpio_module_exit); ++#endif ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/misc/mcp-pxa.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,57 @@ ++/* ++ * linux/drivers/misc/mcp-pxa.c ++ * ++ * 2002-01-10 Jeff Sutherland <jeffs@accelent.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. ++ * ++ * NOTE: This is a quick hack to gain access to the aclink codec's ++ * touch screen facility. Its audio is handled by a separate ++ * (non-mcp) driver at the present time. ++ */ ++ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/ac97_codec.h> ++ ++#include "mcp.h" ++ ++ ++extern int pxa_ac97_get(struct ac97_codec **codec); ++extern void pxa_ac97_put(void); ++ ++ ++struct mcp *mcp_get(void) ++{ ++ struct ac97_codec *codec; ++ if (pxa_ac97_get(&codec) < 0) ++ return NULL; ++ return (struct mcp *)codec; ++} ++ ++void mcp_reg_write(struct mcp *mcp, unsigned int reg, unsigned int val) ++{ ++ struct ac97_codec *codec = (struct ac97_codec *)mcp; ++ codec->codec_write(codec, reg, val); ++} ++ ++unsigned int mcp_reg_read(struct mcp *mcp, unsigned int reg) ++{ ++ struct ac97_codec *codec = (struct ac97_codec *)mcp; ++ return codec->codec_read(codec, reg); ++} ++ ++void mcp_enable(struct mcp *mcp) ++{ ++ /* ++ * Should we do something here to make sure the aclink ++ * codec is alive??? ++ * A: not for now --NP ++ */ ++} ++ ++void mcp_disable(struct mcp *mcp) ++{ ++} +--- linux-2.4.25/drivers/misc/mcp.h~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/misc/mcp.h 2004-03-31 17:15:11.000000000 +0200 +@@ -10,16 +10,22 @@ + #ifndef MCP_H + #define MCP_H + ++#ifdef CONFIG_ARCH_SA1100 ++#include <asm/dma.h> ++#endif ++ + struct mcp { + struct module *owner; + spinlock_t lock; + int use_count; + unsigned int sclk_rate; + unsigned int rw_timeout; ++#ifdef CONFIG_ARCH_SA1100 + dma_device_t dma_audio_rd; + dma_device_t dma_audio_wr; + dma_device_t dma_telco_rd; + dma_device_t dma_telco_wr; ++#endif + 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); +--- linux-2.4.25/drivers/misc/ucb1x00-core.c~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/misc/ucb1x00-core.c 2004-03-31 17:15:11.000000000 +0200 +@@ -23,12 +23,18 @@ + #include <linux/errno.h> + #include <linux/interrupt.h> + #include <linux/pm.h> ++#include <linux/tqueue.h> ++#include <linux/config.h> + +-#include <asm/dma.h> +-#include <asm/hardware.h> + #include <asm/irq.h> + #include <asm/mach-types.h> ++ ++#ifdef CONFIG_ARCH_SA1100 ++#include <asm/arch/assabet.h> + #include <asm/arch/shannon.h> ++#endif ++ ++#include <asm/hardware.h> + + #include "ucb1x00.h" + +@@ -155,6 +161,10 @@ + * + * If called for a synchronised ADC conversion, it may sleep + * with the ADC semaphore held. ++ * ++ * See ucb1x00.h for definition of the UCB_ADC_DAT macro. It ++ * addresses a bug in the ucb1200/1300 which, of course, Philips ++ * decided to finally fix in the ucb1400 ;-) -jws + */ + unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync) + { +@@ -218,22 +228,75 @@ + * 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. ++ * ++ * A restriction with interrupts exists when using the ucb1400, as ++ * the codec read/write routines may sleep while waiting for codec ++ * access completion and uses semaphores for access control to the ++ * AC97 bus. A complete codec read cycle could take anywhere from ++ * 60 to 100uSec so we *definitely* don't want to spin inside the ++ * interrupt handler waiting for codec access. So, we handle the ++ * interrupt by scheduling a RT kernel thread to run in process ++ * context instead of interrupt context. + */ +-static void ucb1x00_irq(int irqnr, void *devid, struct pt_regs *regs) ++ ++static int ucb1x00_thread(void *_ucb) + { +- struct ucb1x00 *ucb = devid; ++ struct task_struct *tsk = current; ++ DECLARE_WAITQUEUE(wait, tsk); ++ struct ucb1x00 *ucb = _ucb; + 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); ++ ucb->rtask = tsk; + +- 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); ++ daemonize(); ++ reparent_to_init(); ++ tsk->tty = NULL; ++ tsk->policy = SCHED_FIFO; ++ tsk->rt_priority = 1; ++ strcpy(tsk->comm, "kUCB1x00d"); ++ ++ /* 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); ++ ++ add_wait_queue(&ucb->irq_wait, &wait); ++ set_task_state(tsk, TASK_INTERRUPTIBLE); ++ complete(&ucb->complete); ++ ++ for (;;) { ++ if (signal_pending(tsk)) ++ break; ++ enable_irq(ucb->irq); ++ schedule(); ++ ++ 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); ++ ++ set_task_state(tsk, TASK_INTERRUPTIBLE); ++ } ++ ++ remove_wait_queue(&ucb->irq_wait, &wait); ++ ucb->rtask = NULL; ++ complete_and_exit(&ucb->complete, 0); ++} ++ ++static void ucb1x00_irq(int irqnr, void *devid, struct pt_regs *regs) ++{ ++ struct ucb1x00 *ucb = devid; ++ disable_irq(irqnr); ++ wake_up(&ucb->irq_wait); + } + + /** +@@ -291,6 +354,11 @@ + spin_lock_irqsave(&ucb->lock, flags); + + ucb1x00_enable(ucb); ++ ++ /* This prevents spurious interrupts on the UCB1400 */ ++ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 1 << idx); ++ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); ++ + if (edges & UCB_RISING) { + ucb->irq_ris_enbl |= 1 << idx; + ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl); +@@ -456,6 +524,7 @@ + unsigned int irq_gpio_pin = 0; + int irq, default_irq = NO_IRQ; + ++#ifdef CONFIG_ARCH_SA1100 + if (machine_is_adsbitsy()) + default_irq = IRQ_GPCIN4; + +@@ -514,12 +583,40 @@ + } + #endif + ++#endif /* CONFIG_ARCH_SA1100 */ ++ ++#ifdef CONFIG_ARCH_PXA_IDP ++ if (machine_is_pxa_idp()) { ++ default_irq = TOUCH_PANEL_IRQ; ++ irq_gpio_pin = IRQ_TO_GPIO_2_80(TOUCH_PANEL_IRQ); ++ GPDR(irq_gpio_pin) &= ~GPIO_bit(irq_gpio_pin); ++ } ++#endif ++ ++#ifdef CONFIG_ARCH_TRIZEPS2 ++ if (machine_is_trizeps2()) { ++ default_irq = TOUCH_PANEL_IRQ; ++ irq_gpio_pin = IRQ_TO_GPIO_2_80(TOUCH_PANEL_IRQ); ++ GPDR(irq_gpio_pin) &= ~GPIO_bit(irq_gpio_pin); ++ } ++#endif ++ ++ ++#ifdef CONFIG_PXA_CERF_PDA ++ if (machine_is_pxa_cerf()) { ++ irq_gpio_pin = CERF_GPIO_UCB1400_IRQ; ++ } ++#endif ++ + /* + * Eventually, this will disappear. + */ + if (irq_gpio_pin) ++#ifdef CONFIG_ARCH_PXA_IDP ++ set_GPIO_IRQ_edge(irq_gpio_pin, GPIO_FALLING_EDGE); ++#else + set_GPIO_IRQ_edge(irq_gpio_pin, GPIO_RISING_EDGE); +- ++#endif + irq = ucb1x00_detect_irq(ucb); + if (irq != NO_IRQ) { + if (default_irq != NO_IRQ && irq != default_irq) +@@ -541,21 +638,7 @@ + + 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) ++static int ucb1x00_init_helper(void) + { + struct mcp *mcp; + unsigned int id; +@@ -568,23 +651,28 @@ + mcp_enable(mcp); + id = mcp_reg_read(mcp, UCB_ID); + +- if (id != UCB_ID_1200 && id != UCB_ID_1300) { ++ if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_1400) { + printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id); + goto out; + } + ++ /* distinguish between UCB1400 revs 1B and 2A */ ++ if (id == UCB_ID_1400 && mcp_reg_read(mcp, 0x00) == 0x002a) ++ id = UCB_ID_1400_BUGGY; ++ + my_ucb = kmalloc(sizeof(struct ucb1x00), GFP_KERNEL); + ret = -ENOMEM; + if (!my_ucb) + goto out; + ++#ifdef CONFIG_ARCH_SA1100 + if (machine_is_shannon()) { + /* reset the codec */ + GPDR |= SHANNON_GPIO_CODEC_RESET; + GPCR = SHANNON_GPIO_CODEC_RESET; + GPSR = SHANNON_GPIO_CODEC_RESET; +- + } ++#endif + + memset(my_ucb, 0, sizeof(struct ucb1x00)); + +@@ -599,13 +687,12 @@ + if (ret) + goto out; + ++ init_waitqueue_head(&my_ucb->irq_wait); + 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; ++ goto irq_err; + } + + #ifdef CONFIG_PM +@@ -616,16 +703,55 @@ + my_ucb->pmdev->data = my_ucb; + #endif + ++ init_completion(&my_ucb->complete); ++ ret = kernel_thread(ucb1x00_thread, my_ucb, CLONE_FS | CLONE_FILES); ++ if (ret >= 0) { ++ wait_for_completion(&my_ucb->complete); ++ ret = 0; ++ goto out; ++ } ++ ++ free_irq(my_ucb->irq, my_ucb); ++irq_err: ++ kfree(my_ucb); ++ my_ucb = NULL; + out: + mcp_disable(mcp); + no_mcp: + return ret; + } + ++/** ++ * 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) ++{ ++ if( !my_ucb) ucb1x00_init_helper(); ++ ++ return my_ucb; ++} ++ ++static int __init ucb1x00_init(void) ++{ ++ /* check if driver is already initialized */ ++ if( my_ucb) return 0; ++ ++ return ucb1x00_init_helper(); ++} ++ + static void __exit ucb1x00_exit(void) + { ++ send_sig(SIGKILL, my_ucb->rtask, 1); ++ wait_for_completion(&my_ucb->complete); + free_irq(my_ucb->irq, my_ucb); + kfree(my_ucb); ++ my_ucb = 0; + } + + module_init(ucb1x00_init); +--- linux-2.4.25/drivers/misc/ucb1x00-ts.c~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/misc/ucb1x00-ts.c 2004-03-31 17:15:11.000000000 +0200 +@@ -35,7 +35,11 @@ + /* + * Define this if you want the UCB1x00 stuff to talk to the input layer + */ ++#ifdef CONFIG_INPUT ++#define USE_INPUT ++#else + #undef USE_INPUT ++#endif + + #ifndef USE_INPUT + +@@ -73,7 +77,7 @@ + struct pm_dev *pmdev; + #endif + +- wait_queue_head_t irq_wait; ++ struct semaphore irq_wait; + struct semaphore sem; + struct completion init_exit; + struct task_struct *rtask; +@@ -259,6 +263,11 @@ + input_report_abs(&ts->idev, ABS_PRESSURE, pressure); + } + ++static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts) ++{ ++ input_report_abs(&ts->idev, ABS_PRESSURE, 0); ++} ++ + static int ucb1x00_ts_open(struct input_dev *idev) + { + struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev; +@@ -304,10 +313,15 @@ + */ + 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); ++ if (ts->ucb->id == UCB_ID_1400_BUGGY) ++ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, ++ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | ++ UCB_TS_CR_MODE_INT); ++ else ++ 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); + } + + /* +@@ -397,13 +411,13 @@ + /* + * 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). ++ * to serialise accesses to the ADC). The UCB1400 access ++ * functions are expected to be able to sleep as well. + */ + 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; +@@ -429,10 +443,8 @@ + + valid = 0; + +- add_wait_queue(&ts->irq_wait, &wait); + for (;;) { + unsigned int x, y, p, val; +- signed long timeout; + + ts->restart = 0; + +@@ -457,8 +469,6 @@ + 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); + +@@ -471,7 +481,15 @@ + valid = 0; + } + +- timeout = MAX_SCHEDULE_TIMEOUT; ++ /* ++ * Since ucb1x00_enable_irq() might sleep due ++ * to the way the UCB1400 regs are accessed, we ++ * can't use set_task_state() before that call, ++ * and not changing state before enabling the ++ * interrupt is racy. A semaphore solves all ++ * those issues quite nicely. ++ */ ++ down_interruptible(&ts->irq_wait); + } else { + ucb1x00_disable(ts->ucb); + +@@ -486,16 +504,13 @@ + } + + set_task_state(tsk, TASK_INTERRUPTIBLE); +- timeout = HZ / 100; ++ schedule_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); +@@ -509,7 +524,7 @@ + { + struct ucb1x00_ts *ts = id; + ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING); +- wake_up(&ts->irq_wait); ++ up(&ts->irq_wait); + } + + static int ucb1x00_ts_startup(struct ucb1x00_ts *ts) +@@ -525,7 +540,7 @@ + if (ts->rtask) + panic("ucb1x00: rtask running?"); + +- init_waitqueue_head(&ts->irq_wait); ++ sema_init(&ts->irq_wait, 0); + ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts); + if (ret < 0) + goto out; +@@ -585,7 +600,7 @@ + * after sleep. + */ + ts->restart = 1; +- wake_up(&ts->irq_wait); ++ up(&ts->irq_wait); + } + return 0; + } +--- linux-2.4.25/drivers/misc/ucb1x00.h~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/misc/ucb1x00.h 2004-03-31 17:15:11.000000000 +0200 +@@ -10,8 +10,47 @@ + #ifndef UCB1200_H + #define UCB1200_H + ++#ifdef CONFIG_ARCH_PXA ++ ++/* ucb1400 aclink register mappings: */ ++ ++#define UCB_IO_DATA 0x5a ++#define UCB_IO_DIR 0x5c ++#define UCB_IE_RIS 0x5e ++#define UCB_IE_FAL 0x60 ++#define UCB_IE_STATUS 0x62 ++#define UCB_IE_CLEAR 0x62 ++#define UCB_TS_CR 0x64 ++#define UCB_ADC_CR 0x66 ++#define UCB_ADC_DATA 0x68 ++#define UCB_ID 0x7e /* 7c is mfr id, 7e part id (from aclink spec) */ ++ ++#define UCB_ADC_DAT(x) ((x) & 0x3ff) ++ ++#else ++ ++/* ucb1x00 SIB register mappings: */ ++ + #define UCB_IO_DATA 0x00 + #define UCB_IO_DIR 0x01 ++#define UCB_IE_RIS 0x02 ++#define UCB_IE_FAL 0x03 ++#define UCB_IE_STATUS 0x04 ++#define UCB_IE_CLEAR 0x04 ++#define UCB_TC_A 0x05 ++#define UCB_TC_B 0x06 ++#define UCB_AC_A 0x07 ++#define UCB_AC_B 0x08 ++#define UCB_TS_CR 0x09 ++#define UCB_ADC_CR 0x0a ++#define UCB_ADC_DATA 0x0b ++#define UCB_ID 0x0c ++#define UCB_MODE 0x0d ++ ++#define UCB_ADC_DAT(x) (((x) & 0x7fe0) >> 5) ++ ++#endif ++ + + #define UCB_IO_0 (1 << 0) + #define UCB_IO_1 (1 << 1) +@@ -24,10 +63,6 @@ + #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) +@@ -36,11 +71,9 @@ + + #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) +@@ -49,14 +82,11 @@ + #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) +@@ -72,7 +102,6 @@ + #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) +@@ -87,15 +116,13 @@ + #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_ID_1400 0x4304 ++#define UCB_ID_1400_BUGGY 0x4303 /* fake ID */ + +-#define UCB_MODE 0x0d + #define UCB_MODE_DYN_VFLAG_ENA (1 << 12) + #define UCB_MODE_AUD_OFF_CAN (1 << 13) + +@@ -115,6 +142,9 @@ + unsigned int irq; + struct semaphore adc_sem; + spinlock_t io_lock; ++ wait_queue_head_t irq_wait; ++ struct completion complete; ++ struct task_struct *rtask; + u16 id; + u16 io_dir; + u16 io_out; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/mmc/Config.in 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,12 @@ ++mainmenu_option next_comment ++comment 'MMC device drivers' ++tristate 'Multi Media Card support' CONFIG_MMC ++if [ "$CONFIG_MMC" = "y" -o "$CONFIG_MMC" = "m" ]; then ++ dep_tristate 'PXA250 MMC driver' CONFIG_MMC_PXA $CONFIG_MMC ++ dep_tristate 'MMC block driver' CONFIG_MMC_BLOCK $CONFIG_MMC ++ if [ "$CONFIG_MMC_BLOCK" = "y" -o "$CONFIG_MMC_BLOCK" = "m" ]; then ++ bool ' MMC partitioning support' CONFIG_MMC_PARTITIONS ++ fi ++fi ++endmenu ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/mmc/Makefile 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,14 @@ ++# ++# Makefile for MMC drivers ++# ++ ++export-objs := mmc_core.o ++ ++obj-$(CONFIG_MMC) += mmc_core.o # mmc_test.o ++obj-$(CONFIG_MMC_BLOCK) += mmc_block.o ++obj-$(CONFIG_MMC_PXA) += mmc_pxa.o ++# EXTRA_CFLAGS += -DCONFIG_MMC_DEBUG -DCONFIG_MMC_DEBUG_VERBOSE=2 ++ ++O_TARGET := mmcdrivers.o ++ ++include $(TOPDIR)/Rules.make +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/mmc/error.h 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,70 @@ ++/* ++ * linux/include/linux/mmc/error.h ++ * ++ * Author: Vladimir Shebordaev ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id$ ++ * ++ * 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 __MMC_ERROR_H__ ++#define __MMC_ERROR_H__ ++ ++/* MMC protocol card error codes */ ++#define MMC_CARD_STATUS_OUT_OF_RANGE (1<<31) ++#define MMC_CARD_STATUS_ADDRESS_ERROR (1<<30) ++#define MMC_CARD_STATUS_BLOCK_LEN_ERROR (1<<29) ++#define MMC_CARD_STATUS_ERASE_SEQ_ERROR (1<<28) ++#define MMC_CARD_STATUS_ERASE_PARAM (1<<27) ++#define MMC_CARD_STATUS_WP_VIOLATION (1<<26) ++#define MMC_CARD_STATUS_CARD_IS_LOCKED (1<<25) ++#define MMC_CARD_STATUS_LOCK_UNLOCK_FAILED (1<<24) ++#define MMC_CARD_STATUS_COM_CRC_ERROR (1<<23) ++#define MMC_CARD_STATUS_ILLEGAL_COMMAND (1<<22) ++#define MMC_CARD_STATUS_CARD_ECC_FAILED (1<<21) ++#define MMC_CARD_STATUS_CC_ERROR (1<<20) ++#define MMC_CARD_STATUS_ERROR (1<<19) ++#define MMC_CARD_STATUS_UNDERRUN (1<<18) ++#define MMC_CARD_STATUS_OVERRUN (1<<17) ++#define MMC_CARD_STATUS_CID_CSD_OVERWRITE (1<<16) ++#define MMC_CARD_STATUS_ERASE_RESET (1<<13) ++ ++#define MMC_ERROR( fmt, args... ) printk( KERN_ERR "%s(): " fmt, __FUNCTION__, ##args ) ++ ++/* ++ * Error codes returned by MMC subsystem functions and ++ * error reporting function prototypes ++ */ ++enum _mmc_error { ++/* controller errors */ ++ MMC_ERROR_GENERIC = -10000, ++ MMC_ERROR_CRC_WRITE_ERROR = -10001, ++ MMC_ERROR_CRC_READ_ERROR = -10002, ++ MMC_ERROR_RES_CRC_ERROR = -10003, ++ MMC_ERROR_READ_TIME_OUT = -10004, ++ MMC_ERROR_TIME_OUT_RESPONSE = -10005, ++ MMC_ERROR_INVAL = -10006, ++/* protocol errors reported in card status (R1 response) */ ++ MMC_ERROR_OUT_OF_RANGE = -10007, ++ MMC_ERROR_ADDRESS_ERROR = -10008, ++ MMC_ERROR_BLOCK_LEN_ERROR = -10009, ++ MMC_ERROR_ERASE_SEQ_ERROR = -10010, ++ MMC_ERROR_ERASE_PARAM = -10011, ++ MMC_ERROR_WP_VIOLATION = -10012, ++ MMC_ERROR_CARD_IS_LOCKED = -10013, ++ MMC_ERROR_LOCK_UNLOCK_FAILED = -10014, ++ MMC_ERROR_COM_CRC_ERROR = -10015, ++ MMC_ERROR_ILLEGAL_COMMAND = -10016, ++ MMC_ERROR_CARD_ECC_FAILED = -10017, ++ MMC_ERROR_CC_ERROR = -10018, ++ MMC_ERROR_ERROR = -10019, ++ MMC_ERROR_UNDERRUN = -10020, ++ MMC_ERROR_OVERRUN = -10021, ++ MMC_ERROR_CID_CSD_OVERWRITE = -10022, ++ /* FIXME: incomplete */ ++ MMC_ERROR_ERASE_RESET = -10025 ++}; ++#endif /* __MMC_ERROR_H__ */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/mmc/mmc.h 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,463 @@ ++/* ++ * linux/drivers/mmc/mmc.h ++ * ++ * Author: Vladimir Shebordaev ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id$ ++ * ++ * 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 __MMC_P_H__ ++#define __MMC_P_H__ ++ ++#ifdef __KERNEL__ ++ ++#include <linux/types.h> ++#include <linux/slab.h> ++ ++#include <linux/spinlock.h> ++ ++#ifdef CONFIG_PROC_FS ++#include <linux/proc_fs.h> ++#endif ++ ++#include <asm/semaphore.h> ++#include <mmc/types.h> ++#include <mmc/mmc.h> ++ ++#include "types.h" ++ ++#include "error.h" ++ ++#define MMC_CONTROLLERS_MAX (4) ++#define MMC_CARDS_MAX (16) ++ ++/* test device */ ++#define MMC_TEST_MAJOR (240) ++#define MMC_TEST_TRANSFER_MODE_DEFAULT MMC_TRANSFER_MODE_BLOCK_SINGLE ++ ++/* block device */ ++#define MMC_BLOCK_MAJOR (241) /* FIXME: MMC_MAJOR */ ++#define MMC_BLOCK_DEVICES_MAX (1<<MINORBITS) /* FIXME */ ++#define MMC_BLOCK_SECT_SIZE (512) /* FIXME */ ++#define MMC_BLOCK_PARTNBITS (3) ++ ++/* Device minor number encoding: ++ * [7:6] - host ++ * [5:3] - card slot number ++ * [2:0] - partition number ++ */ ++#define MMC_MINOR_HOST_SHIFT (6) ++#define MMC_MINOR_CARD_MASK (0x07) ++ ++/* ++ * MMC controller abstraction ++ */ ++enum _mmc_controller_state { ++ MMC_CONTROLLER_ABSENT = 0, ++ MMC_CONTROLLER_FOUND, ++ MMC_CONTROLLER_INITIALIZED, ++ MMC_CONTROLLER_UNPLUGGED ++}; ++ ++enum _mmc_dir { ++ MMC_READ = 1, ++ MMC_WRITE ++}; ++ ++enum _mmc_buftype { ++ MMC_USER = 1, ++ MMC_KERNEL ++}; ++ ++struct _mmc_data_transfer_req_rec { ++ mmc_dir_t cmd; /* read or write operation requested */ ++ mmc_transfer_mode_t mode; /* requested data transfer mode */ ++ mmc_buftype_t type; /* whether supplied buffer resides in user or kernel space */ ++ char *buf; /* poiner to the caller's buffer */ ++ ssize_t cnt; /* number of bytes to transfer */ ++ loff_t addr; /* card address */ ++ ssize_t blksz; /* block size as for CSD[READ_BL_LEN] or CSD[WRITE_BL_LEN] */ ++ ssize_t nob; /* number of blocks to transfer */ ++}; ++ ++struct _mmc_controller_tmpl_rec { ++ struct module *owner; /* driver module */ ++ char name[16]; ++ ++ const ssize_t block_size_max; /* max acceptable block size */ ++ const ssize_t nob_max; /* max blocks per one data transfer */ ++ ++ int (*probe)( mmc_controller_t ); /* hardware probe */ ++ int (*init)( mmc_controller_t ); /* initialize, e.g. request irq, DMA and allocate buffers */ ++ void (*remove)( mmc_controller_t ); /* free resources */ ++#if 0 /* CONFIG_HOTPLUG */ ++ void (*attach)( void ); /|* controller hotplug callbacks *|/ ++ void (*detach)( void ); ++#endif ++#ifdef CONFIG_PM ++ int (*suspend)( mmc_controller_t ); /* power management callbacks */ ++ void (*resume)( mmc_controller_t ); ++#endif ++ ++/* MMC protocol macros, v3.4, p.120 */ ++ int (*init_card_stack)( mmc_controller_t ); ++ int (*update_acq)( mmc_controller_t ); /* update card stack management data */ ++ int (*single_card_acq)( mmc_controller_t ); ++ int (*check_card_stack)( mmc_controller_t ); ++ int (*setup_card)( mmc_controller_t, mmc_card_t ); ++ int (*stream_read)( mmc_controller_t, mmc_data_transfer_req_t ); ++ int (*read_block)( mmc_controller_t, mmc_data_transfer_req_t ); ++ int (*read_mblock)( mmc_controller_t, mmc_data_transfer_req_t ); ++ int (*stream_write)( mmc_controller_t, mmc_data_transfer_req_t ); ++ int (*write_block)( mmc_controller_t, mmc_data_transfer_req_t ); ++ int (*write_mblock)( mmc_controller_t, mmc_data_transfer_req_t ); ++/* TODO: ++ int (*sg_io)( mmc_controller_t, sg_list_t ); ++*/ ++/* TODO: ++ * 1) erase group macros ++ * int (*erase_group)( mmc_controller_t, mmc_erase_group_info_t ); ++ * 2) write protection macros; ++ * int (*set_write_prot)( mmc_controller_t, mmc_write_protection_info_t ) ++ * 3) lock/password management macros; ++ */ ++}; ++ ++#ifndef MMC_CTRLR_BLKSZ_DEFAULT ++#define MMC_CTRLR_BLKSZ_DEFAULT (512) ++#endif ++ ++#ifndef MMC_CTRLR_NOB_DEFAULT ++#define MMC_CTRLR_NOB_DEFAULT (1) ++#endif ++ ++struct _mmc_card_rec { ++/* public card interface */ ++ struct _mmc_card_info_rec info; /* see <linux/mmc/mmc.h> */ ++ ++/* private kernel specific data */ ++ mmc_state_t state; /* card's state as per last operation */ ++ mmc_card_t next; /* link to the stack */ ++ mmc_controller_t ctrlr; /* back reference to the controller */ ++ int usage; /* reference count */ ++ int slot; /* card's number for device reference */ ++/* TODO: async I/O queue */ ++#ifdef CONFIG_PROC_FS ++ proc_dir_entry_t proc; ++ char proc_name[16]; ++#endif ++ unsigned long card_data[0] /* card specific data */ ++ __attribute__((aligned (sizeof(unsigned long)))); ++}; ++ ++struct _mmc_card_stack_rec { ++ mmc_card_t first; /* first card on the stack */ ++ mmc_card_t last; /* last card on the stack */ ++ mmc_card_t selected; /* currently selected card */ ++ int ncards; ++}; ++ ++struct _mmc_controller_rec { ++ mmc_controller_state_t state; /* found, initialized, unplugged... */ ++ int usage; /* reference count */ ++ int slot; /* host's number for device reference */ ++ semaphore_t io_sem; /* I/O serialization */ ++ rwsemaphore_t update_sem; /* card stack check/update serialization */ ++ ++ mmc_controller_tmpl_t tmpl; /* methods provided by the driver */ ++ mmc_card_stack_rec_t stack; /* card stack management data */ ++ ++ u32 rca_next; /* next RCA to assign */ ++ int slot_next; /* next slot number to assign */ ++#ifdef CONFIG_PROC_FS ++ char proc_name[16]; ++ proc_dir_entry_t proc; ++#endif ++ unsigned long host_data[0] /* driver can request some extra space */ ++ __attribute__((aligned (sizeof(unsigned long)))); ++}; ++ ++/* ++ * MMC core interface ++ */ ++enum _mmc_reg_type { ++ MMC_REG_TYPE_USER = 1, ++ MMC_REG_TYPE_HOST, ++ MMC_REG_TYPE_CARD ++}; ++ ++struct _mmc_notifier_rec { ++ struct _mmc_notifier_rec *next; ++ mmc_notifier_fn_t add; ++ mmc_notifier_fn_t remove; ++}; ++ ++enum _mmc_response { ++ MMC_NORESPONSE = 1, ++ MMC_R1, ++ MMC_R2, ++ MMC_R3, ++ MMC_R4, ++ MMC_R5 ++}; ++ ++#undef EXTERN ++#ifndef __MMC_CORE_IMPLEMENTATION__ ++#define EXTERN extern ++#else ++#define EXTERN /* empty */ ++#endif ++ ++EXTERN void *mmc_register( mmc_reg_type_t, void *, size_t ); ++EXTERN void mmc_unregister( mmc_reg_type_t, void * ); ++EXTERN int mmc_update_card_stack( int ); ++ ++EXTERN mmc_card_t mmc_get_card( int, int );/* get reference to the card */ ++EXTERN void mmc_put_card( mmc_card_t ); /* release card reference */ ++ ++EXTERN int mmc_notify_add( mmc_card_t ); /* user notification */ ++EXTERN int mmc_notify_remove( mmc_card_t ); ++ ++EXTERN ssize_t mmc_read( mmc_card_t, mmc_transfer_mode_t, char *, size_t, loff_t * ); /* generic read */ ++EXTERN ssize_t mmc_write( mmc_card_t, mmc_transfer_mode_t, const char *, size_t, loff_t * ); /* generic write */ ++EXTERN int mmc_ioctl( mmc_card_t, unsigned int, unsigned long ); /* generic ioctl */ ++/* ++ * TODO: [?m.b. ioctl()] to erase, lock and write protect ++ * 1) mmc_erase ++ * 2) mmc_write_prot ++ * 3) mmc_lock ++ */ ++#undef EXTERN ++ ++static inline mmc_card_t __mmc_card_alloc( size_t extra ) ++{ ++ mmc_card_t ret = kmalloc( sizeof( mmc_card_rec_t ) + extra, GFP_KERNEL ); ++ ++ if ( ret ) { ++ memset( ret, 0, sizeof( mmc_card_rec_t ) + extra ); ++ } ++ ++ return ret; ++} ++ ++static inline void __mmc_card_free( mmc_card_t card ) ++{ ++ if ( card ) { ++ kfree( card ); ++ } ++} ++ ++static inline mmc_card_stack_t __mmc_card_stack_init( mmc_card_stack_t stack ) ++{ ++ mmc_card_stack_t ret = NULL; ++ if ( stack ) { ++ memset( stack, 0, sizeof( mmc_card_stack_rec_t ) ); ++ ret = stack; ++ } ++ return ret; ++} ++ ++static inline mmc_card_stack_t __mmc_card_stack_add( mmc_card_stack_t stack, mmc_card_t card ) ++{ ++ mmc_card_stack_t ret = NULL; ++ ++ if ( stack && card ) { ++ card->next = NULL; ++ ++ if ( stack->first ) { ++ stack->last->next = card; ++ stack->last = card; ++ } else ++ stack->first = stack->last = card; ++ ++ ++stack->ncards; ++ ret = stack; ++ } ++ return ret; ++} ++ ++static inline mmc_card_stack_t __mmc_card_stack_remove( mmc_card_stack_t stack, mmc_card_t card ) ++{ ++ mmc_card_stack_t ret = NULL; ++ register mmc_card_t prev; ++ int found = FALSE; ++ ++ if ( !stack || !card ) ++ goto error; ++ ++ if ( stack->ncards > 0 ) { ++ if ( stack->first == card ) { ++ stack->first = stack->first->next; ++ if ( stack->last == card ) ++ stack->last = stack->last->next; ++ found = TRUE; ++ } else { ++ for ( prev = stack->first; prev; prev = prev->next ) ++ if ( prev->next == card ) { ++ found = TRUE; ++ break; ++ } ++ if ( found ) { ++ if ( prev->next == stack->last ) ++ stack->last = prev->next; ++ prev->next = prev->next->next; ++ } ++ } ++ if ( found ) { ++ --stack->ncards; ++ ret = stack; ++ } ++ } ++error: ++ return ret; ++} ++ ++static inline void __mmc_card_stack_free( mmc_card_stack_t stack ) ++{ ++ mmc_card_t card, next; ++ ++ if ( stack && (stack->ncards > 0) ) { ++ card = stack->first; ++ while ( card ) { ++ next = card->next; ++ kfree( card ); ++ card = next; ++ } ++ __mmc_card_stack_init( stack ); ++ } ++} ++ ++static inline int __mmc_card_stack_foreach( mmc_card_stack_t stack, mmc_notifier_fn_t fn, int unplugged_also ) ++{ ++ int ret = 0; ++ register mmc_card_t card = NULL; ++ ++ if ( stack && fn ) { ++ for ( card = stack->first; card; card = card->next ) ++ if ( (card->state != MMC_CARD_STATE_UNPLUGGED) ++ || unplugged_also ) ++ if ( fn( card ) ) { ++ ret = -card->slot; ++ break; ++ } ++ } ++ ++ return ret; ++} ++ ++/* ++ * Debugging macros ++ */ ++#ifdef CONFIG_MMC_DEBUG ++ ++#define MMC_DEBUG_LEVEL0 (0) /* major */ ++#define MMC_DEBUG_LEVEL1 (1) ++#define MMC_DEBUG_LEVEL2 (2) /* device */ ++#define MMC_DEBUG_LEVEL3 (3) /* protocol */ ++#define MMC_DEBUG_LEVEL4 (4) /* everything */ ++ ++#define MMC_DEBUG(n, args...) \ ++if (n <= CONFIG_MMC_DEBUG_VERBOSE) { \ ++ printk(KERN_INFO __FUNCTION__ "(): " args); \ ++} ++#define __ENTER0( ) MMC_DEBUG( MMC_DEBUG_LEVEL2, "entry\n" ); ++#define __LEAVE0( ) MMC_DEBUG( MMC_DEBUG_LEVEL2, "exit\n" ); ++#define __ENTER( format, args... ) MMC_DEBUG( MMC_DEBUG_LEVEL2, "entry: " format "\n", args ); ++#define __LEAVE( format, args... ) MMC_DEBUG( MMC_DEBUG_LEVEL2, "exit: " format "\n", args ); ++ ++#define MMC_DUMP_CSD( card ) MMC_DEBUG( MMC_DEBUG_LEVEL3, \ ++"CSD register:\n" \ ++" csd_structure=%u\n" \ ++" spec_vers=%u\n" \ ++" taac=%x\n" \ ++" nsac=%x\n" \ ++" tran_speed=%x\n" \ ++" ccc=%x\n" \ ++" read_bl_len=%u\n" \ ++" read_bl_partial=%u\n" \ ++" write_blk_misalign=%u\n" \ ++" read_blk_misalign=%u\n" \ ++" dsr_imp=%u\n" \ ++" c_size=%u\n" \ ++" vdd_r_curr_min=%u\n" \ ++" vdd_r_curr_max=%u\n" \ ++" vdd_w_curr_min=%u\n" \ ++" vdd_w_curr_max=%u\n" \ ++" c_size_mult=%u\n" \ ++" erase_grp_size=%u\n" \ ++" erase_grp_mult=%u\n" \ ++" wp_grp_size=%u\n" \ ++" wp_grp_enable=%u\n" \ ++" default_ecc=%u\n" \ ++" r2w_factor=%u\n" \ ++" write_bl_len=%u\n" \ ++" write_bl_partial=%u\n" \ ++" content_prot_app=%u\n" \ ++" file_format_grp=%u\n" \ ++" copy=%u\n" \ ++" perm_write_protect=%d\n" \ ++" tmp_write_protect=%d\n" \ ++" file_format=%d\n" \ ++" ecc=%d\n", \ ++card->info.csd.csd_structure, \ ++card->info.csd.spec_vers, \ ++card->info.csd.taac, \ ++card->info.csd.nsac, \ ++card->info.csd.tran_speed, \ ++card->info.csd.ccc, \ ++card->info.csd.read_bl_len, \ ++card->info.csd.read_bl_partial, \ ++card->info.csd.write_blk_misalign, \ ++card->info.csd.read_blk_misalign, \ ++card->info.csd.dsr_imp, \ ++card->info.csd.c_size, \ ++card->info.csd.vdd_r_curr_min, \ ++card->info.csd.vdd_r_curr_max, \ ++card->info.csd.vdd_w_curr_min, \ ++card->info.csd.vdd_w_curr_max, \ ++card->info.csd.c_size_mult, \ ++card->info.csd.erase_grp_size, \ ++card->info.csd.erase_grp_mult, \ ++card->info.csd.wp_grp_size, \ ++card->info.csd.wp_grp_enable, \ ++card->info.csd.default_ecc, \ ++card->info.csd.r2w_factor, \ ++card->info.csd.write_bl_len, \ ++card->info.csd.write_bl_partial, \ ++card->info.csd.content_prot_app, \ ++card->info.csd.file_format_grp, \ ++card->info.csd.copy, \ ++card->info.csd.perm_write_protect, \ ++card->info.csd.tmp_write_protect, \ ++card->info.csd.file_format, \ ++card->info.csd.ecc ); ++ ++#else /* CONFIG_MMC_DEBUG */ ++#define MMC_DEBUG(n, args...) /* empty */ ++#define __ENTER0( ) /* empty */ ++#define __LEAVE0( ) /* empty */ ++#define __ENTER( args... ) /* empty */ ++#define __LEAVE( args... ) /* empty */ ++#define MMC_DUMP_CSD( card ) /* empty */ ++#endif /* CONFIG_MMC_DEBUG */ ++ ++/* ++ * Miscellaneous defines ++ */ ++#ifndef MMC_DUMP_R1 ++#define MMC_DUMP_R1( ctrlr ) /* empty */ ++#endif ++#ifndef MMC_DUMP_R2 ++#define MMC_DUMP_R2( ctrlr ) /* empty */ ++#endif ++#ifndef MMC_DUMP_R3 ++#define MMC_DUMP_R3( ctrlr ) /* empty */ ++#endif ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* __MMC_P_H__ */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/mmc/mmc_block.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,989 @@ ++/* ++ * linux/drivers/mmc/mmc_block.c ++ * driver for the block device on the MMC card ++ * ++ * Author: Vladimir Shebordaev ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id$ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/version.h> ++#include <linux/config.h> ++#include <linux/types.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/devfs_fs_kernel.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/hdreg.h> ++#include <linux/blkpg.h> ++#include <asm/uaccess.h> ++ ++#include <mmc/types.h> ++#include <mmc/mmc.h> ++ ++#include "types.h" ++#include "mmc.h" ++#include "error.h" ++ ++#define MAJOR_NR MMC_BLOCK_MAJOR ++#define MAJOR_NAME "mmc" ++#define DEVICE_NAME "mmc_block" ++#define DEVICE_REQUEST mmc_block_request ++#define DEVICE_NR(device) (device) ++#define DEVICE_ON(device) ++#define DEVICE_OFF(device) ++#define DEVICE_NO_RANDOM ++#include <linux/blk.h> ++/* for old kernels... */ ++#ifndef QUEUE_EMPTY ++#define QUEUE_EMPTY (!CURRENT) ++#endif ++#if LINUX_VERSION_CODE < 0x20300 ++#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].plug_tq.sync) ++#else ++#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].request_queue.plugged) ++#endif ++ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14) ++#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT ++#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT ++#else ++#define BLK_INC_USE_COUNT do {} while(0) ++#define BLK_DEC_USE_COUNT do {} while(0) ++#endif ++ ++#define MMC_BLOCK_RAW_DEVICE( device ) ((device>>MMC_BLOCK_PARTNBITS)<<MMC_BLOCK_PARTNBITS) ++#define MMC_BLOCK_MKDEV( host, slot ) \ ++ MKDEV( MMC_BLOCK_MAJOR, \ ++ (host<<MMC_MINOR_HOST_SHIFT) \ ++ | (slot<<MMC_BLOCK_PARTNBITS) ) ++ ++typedef struct _mmc_block_device mmc_block_device_rec_t; ++typedef struct _mmc_block_device *mmc_block_device_t; ++ ++struct _mmc_block_device { ++ mmc_card_t card; ++ int host; ++ int slot; ++ kdev_t rdev; ++ int usage; ++ semaphore_t sem; ++}; ++ ++static int mmc_block_blk_sizes[1<<MINORBITS]; ++static int mmc_block_blk_blksizes[1<<MINORBITS]; ++static int mmc_block_hardsect_sizes[1<<MINORBITS]; ++static struct hd_struct mmc_block_partitions[1<<MINORBITS]; ++ ++/* Accessed under device table lock */ ++static gendisk_rec_t mmc_block_gendisk = { ++ major: MMC_BLOCK_MAJOR, ++ major_name: MAJOR_NAME, ++ minor_shift: MMC_BLOCK_PARTNBITS, ++ max_p: (1<<MMC_BLOCK_PARTNBITS), ++ sizes: mmc_block_blk_sizes, ++ part: mmc_block_partitions ++}; ++ ++static mmc_block_device_rec_t mmc_block_device[1<<MINORBITS]; ++static rwsemaphore_t mmc_block_device_sem; ++ ++static inline void __mmc_block_rdlock_devices( void ) ++{ ++ down_read( &mmc_block_device_sem ); ++} ++ ++static inline void __mmc_block_rdunlock_devices( void ) ++{ ++ up_read( &mmc_block_device_sem ); ++} ++ ++static inline void __mmc_block_wrlock_devices( void ) ++{ ++ down_write( &mmc_block_device_sem ); ++} ++ ++static inline void __mmc_block_wrunlock_devices( void ) ++{ ++ up_write( &mmc_block_device_sem ); ++} ++ ++static inline void __mmc_block_lock_device( kdev_t rdev ) ++{ ++ __mmc_block_rdlock_devices(); ++ down( &mmc_block_device[MINOR( rdev )].sem ); ++} ++ ++static inline void __mmc_block_unlock_device( kdev_t rdev ) ++{ ++ up( &mmc_block_device[MINOR( rdev )].sem ); ++ __mmc_block_rdunlock_devices(); ++} ++ ++static inline void __mmc_block_device_init( int minor ) ++{ ++ mmc_block_device_t dev = &mmc_block_device[minor]; ++ ++ dev->usage = 0; ++ dev->card = NULL; ++ dev->host = minor >> MMC_MINOR_HOST_SHIFT; ++ dev->slot = (minor & MMC_MINOR_CARD_MASK)>>MMC_BLOCK_PARTNBITS; ++ dev->rdev = MKDEV( MMC_BLOCK_MAJOR, minor ); ++} ++ ++static inline int __mmc_block_validate_device( kdev_t rdev ) ++{ ++ int ret = -1; ++ int minor = MINOR( rdev ); ++ ++ if ( mmc_block_device[minor].card ++ && (mmc_block_gendisk.part[minor].nr_sects > 0) ) ++ ret = 0; ++ ++ return ret; ++} ++ ++static inline int __mmc_block_invalidate_card( mmc_card_t card, int invalidate ) ++{ ++ int ret = 0; ++ kdev_t start; ++ int minor; ++ ++ __ENTER( "card = 0x%p", card ); ++ ++ if ( card && card->ctrlr ) { ++ register int i; ++ ++ start = MMC_BLOCK_MKDEV( card->ctrlr->slot, card->slot ); ++ minor = MINOR( start ); ++ ++ __mmc_block_wrlock_devices(); ++ for ( i = mmc_block_gendisk.max_p - 1; i >= 0; --i ) { ++ if ( invalidate ) ++ invalidate_device( start + i, 0 ); ++ ++ __mmc_block_device_init( minor + i ); ++ ++ mmc_block_gendisk.part[minor + i].nr_sects = 0; ++ mmc_block_gendisk.part[minor + i].start_sect = 0; ++ } ++ __mmc_block_wrunlock_devices(); ++ } ++ ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static inline int mmc_block_invalidate_card( int host, int slot, int invalidate ) ++{ ++ int ret = 0; ++ kdev_t start; ++ int minor; ++ ++ __ENTER( "host=%d slot=%d", host, slot ); ++ ++ if ( (host >= 0) && (slot >= 0) ) { ++ register int i; ++ mmc_card_t card = NULL; ++ ++ start = MMC_BLOCK_MKDEV( host, slot ); ++ minor = MINOR( start ); ++ ++ __mmc_block_wrlock_devices(); ++ for ( i = mmc_block_gendisk.max_p - 1; i >= 0; --i ) { ++ if ( !card ) ++ card = mmc_block_device[minor + i].card; ++ ++ if ( invalidate ) ++ invalidate_device( start + i, 0 ); ++ ++ __mmc_block_device_init( minor + i ); ++ ++ mmc_block_gendisk.part[minor + i].nr_sects = 0; ++ mmc_block_gendisk.part[minor + i].start_sect = 0; ++ } ++ if ( card ) ++ mmc_put_card( card ); ++ __mmc_block_wrunlock_devices(); ++ } ++ ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++/* Get device reference locked for writing */ ++static inline mmc_block_device_t __mmc_block_get_device( kdev_t rdev ) ++{ ++ mmc_block_device_t ret = NULL; ++ u8 minor = MINOR( rdev ); ++ int host_no, card_no; ++ ++ __ENTER( "rdev=%x:%x", MAJOR( rdev ), MINOR( rdev ) ); ++ ++ host_no = minor >> MMC_MINOR_HOST_SHIFT; ++ if ( host_no >= MMC_CONTROLLERS_MAX ) ++ goto error; ++ ++ card_no = (minor & MMC_MINOR_CARD_MASK)>>MMC_BLOCK_PARTNBITS; ++ if ( card_no >= MMC_CARDS_MAX ) ++ goto error; ++ ++ __mmc_block_lock_device( rdev ); ++ if ( __mmc_block_validate_device( rdev ) ) { ++ __mmc_block_unlock_device( rdev ); ++ goto error; ++ } ++ ++ ret = &mmc_block_device[minor]; ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "(%x:%x) card=%p, dusage=%d\n", ++ MAJOR( ret->rdev ), MINOR( ret->rdev ), ++ ret->card, ret->usage ); ++error: ++ __LEAVE( "ret=0x%p", ret ); ++ return ret; ++} ++ ++/* Unlocks the device */ ++static inline void __mmc_block_put_device( mmc_block_device_t dev ) ++{ ++ __ENTER0(); ++ ++ if ( dev ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "(%x:%x) card=%p, dusage=%d\n", ++ MAJOR( dev->rdev ), MINOR( dev->rdev ), ++ dev->card, dev->usage ); ++ __mmc_block_unlock_device( dev->rdev ); ++ } ++ ++ __LEAVE0(); ++} ++ ++/* Atomically increases use count of the valid device */ ++static inline mmc_block_device_t mmc_block_get_device( kdev_t rdev ) ++{ ++ mmc_block_device_t ret = NULL; ++ ++ __ENTER0(); ++ ++ ret = __mmc_block_get_device( rdev ); ++ if ( !ret ) ++ goto error; ++ ++ ret->usage++; ++ __mmc_block_put_device( ret ); ++error: ++ __LEAVE( "ret=0x%p dusage=%d card=0x%p cusage=%d", ++ ret, ret ? ret->usage : -1, ++ ret ? ret->card : NULL, ++ ret ? (ret->card ? ret->card->usage : -1) : -1 ); ++ return ret; ++} ++ ++/* Check is there references to the card */ ++static inline int __mmc_block_check_card( kdev_t rdev ) ++{ ++ int ret = TRUE; ++ int start = MINOR( MMC_BLOCK_RAW_DEVICE( rdev ) ); ++ register int i; ++ ++ for ( i = 0; i < mmc_block_gendisk.max_p; i++ ) ++ if ( mmc_block_device[start + i].usage > 0 ) { ++ ret = FALSE; ++ break; ++ } ++ ++ return ret; ++} ++ ++/* Atomically decreases device use count */ ++static inline void mmc_block_put_device( mmc_block_device_t dev ) ++{ ++ __ENTER0(); ++ ++ if ( dev ) { ++ int invalidate = FALSE; ++ ++ __mmc_block_get_device( dev->rdev ); ++ if ( dev->usage > 0 ) ++ --dev->usage; ++ ++ if ( dev->usage ) { ++ __mmc_block_put_device( dev ); ++ goto out; ++ ++ } else { ++ int host, slot; ++ mmc_card_t card = NULL; ++ ++ invalidate = __mmc_block_check_card( dev->rdev ); ++ if ( invalidate ) { ++ host = dev->card->ctrlr->slot; ++ slot = dev->card->slot; ++ ++ if ( dev->card ) { ++ card = dev->card; ++ mmc_put_card( dev->card ); ++ dev->card = NULL; ++ } ++ } ++ __mmc_block_put_device( dev ); ++ ++ if ( invalidate ) ++ __mmc_block_invalidate_card( card, TRUE ); ++ } ++ ++ } ++out: ++ __LEAVE0(); ++} ++ ++static int mmc_block_open( struct inode *inode, struct file *file ) ++{ ++ int ret = -ENODEV; ++ mmc_block_device_t dev = NULL; ++ ++ __ENTER0(); ++ ++ if ( !inode || !file ) ++ goto error; ++ ++ BLK_INC_USE_COUNT; ++ ++ check_disk_change( inode->i_rdev ); ++ ++ dev = mmc_block_get_device( inode->i_rdev ); ++ if ( !dev ) ++ goto error; ++ ++ dev = __mmc_block_get_device( inode->i_rdev ); ++ if ( !dev ) ++ goto error; ++ ++ if ( file->f_mode & FMODE_WRITE ) { /* FIXME */ ++ if ( dev->usage > 1 ) { ++ ret = -EBUSY; ++ __mmc_block_put_device( dev ); ++ mmc_block_put_device( dev ); ++ goto error; ++ } ++ } ++ ++ __mmc_block_put_device( dev ); ++ ++ if ( file ) ++ file->private_data = dev; ++ ++ ret = 0; ++ goto out; ++error: ++ BLK_DEC_USE_COUNT; ++out: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static int mmc_block_release( struct inode *inode, struct file *file ) ++{ ++ int ret = -EINVAL; ++ mmc_block_device_t dev = NULL; ++ ++ __ENTER( "inode=0x%p file=0x%p rdev=(%x:%x)", inode, file, ++ inode ? MAJOR( inode->i_rdev ) : 0xff, ++ inode ? MINOR( inode->i_rdev ) : 0xff ); ++ ++ if ( !file && !inode ) ++ goto error; ++ ++ if ( file ) ++ dev = file->private_data; ++ else ++ dev = __mmc_block_get_device( inode->i_rdev ); ++ ++ if ( !dev ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "invalid device\n" ); ++ goto error; ++ } ++ ++ if ( file ) { ++ mmc_block_put_device( dev ); ++ file->private_data = NULL; ++ ++ } else { ++ int invalidate = FALSE; ++ ++ if ( dev->usage > 0 ) ++ --dev->usage; ++ ++ if ( dev->usage ) { ++ __mmc_block_put_device( dev ); ++ goto out; ++ ++ } else { ++ int host, slot; ++ mmc_card_t card = NULL; ++ ++ invalidate = __mmc_block_check_card( dev->rdev ); ++ if ( invalidate ) { ++ host = dev->card->ctrlr->slot; ++ slot = dev->card->slot; ++ ++ if ( dev->card ) { ++ card = dev->card; ++ mmc_put_card( dev->card ); ++ dev->card = NULL; ++ } ++ } ++ __mmc_block_put_device( dev ); ++ ++ if ( invalidate ) ++ __mmc_block_invalidate_card( card, TRUE ); ++ ++ } ++ } ++ ++out: ++ BLK_DEC_USE_COUNT; ++ ret = 0; ++error: ++ __LEAVE0(); ++ return ret; ++} ++ ++static int mmc_block_check_disk_change( kdev_t rdev ) ++{ ++ int ret = 0; ++#if 0 ++ mmc_block_device_t dev = &mmc_block_device[MINOR( rdev )]; ++ ++ __mmc_block_lock_device( rdev ); ++ if ( !dev->card ) ++ ret = 1; ++ __mmc_block_unlock_device( rdev ); ++#else ++ ret = 1; ++#endif ++ return ret; ++} ++ ++static int mmc_block_revalidate( kdev_t rdev ) ++{ ++ int ret = 1; ++ mmc_card_t card; ++ mmc_block_device_t dev; ++ kdev_t start = MMC_BLOCK_RAW_DEVICE( rdev ); ++ int minor = MINOR( start ); ++ int host, slot; ++ int i; ++ ++ __ENTER0(); ++ ++ (void)mmc_update_card_stack( MINOR( start )>>MMC_MINOR_HOST_SHIFT ); ++ ++ __mmc_block_wrlock_devices(); ++ ++ dev = &mmc_block_device[minor]; ++ host = dev->host; ++ slot = dev->slot; ++ ++ if ( dev->card ) { /* card has not been changed actually */ ++ __mmc_block_wrunlock_devices(); ++ goto out; ++ ++ } else { ++ card = mmc_get_card( host, slot ); ++ if ( !card ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "failed to get card: " ++ "host=%d, slot=%d\n", host, slot ); ++ __mmc_block_wrunlock_devices(); ++ goto error; ++ } ++ dev->card = card; ++ } ++ __mmc_block_wrunlock_devices(); ++ /* FIXME */ ++ __mmc_block_rdlock_devices(); /* handle the request for sector 0 */ ++ grok_partitions( &mmc_block_gendisk, MINOR( start ), ++ mmc_block_gendisk.max_p, ++ card->info.capacity>>9 /* sectors */ ++ ); ++ __mmc_block_rdunlock_devices(); ++ /* FIXME */ ++ __mmc_block_wrlock_devices(); ++ for ( i = start + mmc_block_gendisk.max_p - 1; i >= 0; --i ) { ++ int minor = MINOR( i ); ++ ++ dev = &mmc_block_device[minor]; ++ if ( mmc_block_gendisk.part[minor].nr_sects > 0 ) ++ dev->card = card; ++ } ++ __mmc_block_wrunlock_devices(); ++out: ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static void mmc_block_handle_request( void ) ++{ ++ struct request *request; ++ mmc_block_device_t dev; ++ mmc_card_t card; ++ char *buf; ++ loff_t pos; ++ unsigned int result = 0; ++ ++ for (;;) { ++ int minor; ++ ++ INIT_REQUEST; ++ request = CURRENT; ++ spin_unlock_irq( &io_request_lock ); ++ ++ minor = MINOR( request->rq_dev ); ++ dev = __mmc_block_get_device( request->rq_dev ); ++ if ( !dev ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "invalid device (%x:%x)\n", ++ MAJOR( request->rq_dev ), minor ); ++ ++ goto end_req; ++ } ++ ++ card = dev->card; ++ (void)__mmc_block_put_device( dev ); ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, ++// printk( KERN_INFO __FUNCTION__"(): " ++ "request %p: cmd %i sec %li (nr. %li)\n", ++ CURRENT, CURRENT->cmd, CURRENT->sector, ++ CURRENT->current_nr_sectors ); ++ ++ if ( request->current_nr_sectors > ++ mmc_block_gendisk.part[minor].nr_sects ) ++ goto end_req; ++ ++ // Handle the request ++ // TODO: handle clusterred requests in multiple block transfer mode ++ buf = request->buffer; ++ pos = (mmc_block_gendisk.part[minor].start_sect + ++ request->sector) * MMC_BLOCK_SECT_SIZE; ++ ++ switch ( request->cmd ) ++ { ++ int i, ret; ++ ++ case READ: ++#if 0 ++ ret = mmc_read( card, ++ (request->current_nr_sectors > 1) ? ++ MMC_TRANSFER_MODE_BLOCK_MULTIPLE : ++ MMC_TRANSFER_MODE_BLOCK_SINGLE, ++ buf, ++ request->current_nr_sectors ++ * MMC_BLOCK_SECT_SIZE, /* FIXME */ ++ &pos ); ++ if ( ret < 0 ) ++ goto end_req; ++ ++#else ++ for ( i = 0; ++ i < request->current_nr_sectors; ++ i++ ) { ++ ret = mmc_read( card, ++ MMC_TRANSFER_MODE_BLOCK_SINGLE, ++ buf, ++ MMC_BLOCK_SECT_SIZE, /* FIXME */ ++ &pos ); ++ if ( ret < 0 ) ++ goto end_req; ++ else ++ buf += ret; ++ } ++#endif ++ result = 1; ++ break; ++ ++ case WRITE: ++ // TODO: Read only device ++#if 0 ++ ret = mmc_write( card, ++ (request->current_nr_sectors > 1) ? ++ MMC_TRANSFER_MODE_BLOCK_MULTIPLE : ++ MMC_TRANSFER_MODE_BLOCK_SINGLE, ++ buf, ++ request->current_nr_sectors ++ * MMC_BLOCK_SECT_SIZE, /* FIXME */ ++ &pos ); ++ if ( ret < 0 ) ++ goto end_req; ++ ++#else ++ for ( i = 0; ++ i < request->current_nr_sectors; ++ i++ ) { ++ ret = mmc_write( card, ++ MMC_TRANSFER_MODE_BLOCK_SINGLE, ++ buf, ++ MMC_BLOCK_SECT_SIZE, /* FIXME */ ++ &pos ); ++ if ( ret < 0 ) ++ goto end_req; ++ else ++ buf += ret; ++ } ++#endif ++ result = 1; ++ break; ++ } ++ ++end_req: ++ __LEAVE( "result=%d", result ); ++ spin_lock_irq( &io_request_lock ); ++ end_request( result ); ++ } ++} ++ ++static volatile int leaving = 0; ++static DECLARE_MUTEX_LOCKED( thread_sem ); ++static DECLARE_WAIT_QUEUE_HEAD( thr_wq ); ++static pid_t thr_id = -1; ++ ++int mmc_block_thread( void *arg ) ++{ ++ struct task_struct *task = current; ++ DECLARE_WAITQUEUE(wait, task); ++ ++ __ENTER0(); ++ ++ task->session = 1; ++ task->pgrp = 1; ++ task->flags |= PF_MEMALLOC; ++ strcpy( task->comm, "mmcblockd" ); ++ task->tty = NULL; ++ spin_lock_irq( &task->sigmask_lock ); ++ sigfillset( &task->blocked ); ++ recalc_sigpending( task ); ++ spin_unlock_irq( &task->sigmask_lock ); ++ exit_mm( task ); ++ exit_files( task ); ++ exit_sighand( task ); ++ exit_fs( task ); ++ ++ while ( !leaving ) { ++ add_wait_queue( &thr_wq, &wait); ++ set_current_state( TASK_INTERRUPTIBLE ); ++ spin_lock_irq( &io_request_lock ); ++ if ( QUEUE_EMPTY || QUEUE_PLUGGED ) { ++ spin_unlock_irq( &io_request_lock ); ++ schedule(); ++ remove_wait_queue( &thr_wq, &wait ); ++ } else { ++ remove_wait_queue( &thr_wq, &wait ); ++ set_current_state( TASK_RUNNING ); ++ mmc_block_handle_request(); /* handle the request */ ++ spin_unlock_irq( &io_request_lock ); ++ } ++ } ++ ++ up( &thread_sem ); ++ ++ __LEAVE0(); ++ return 0; ++} ++ ++#if LINUX_VERSION_CODE < 0x20300 ++#define RQFUNC_ARG void ++#else ++#define RQFUNC_ARG request_queue_t *q ++#endif ++ ++static void mmc_block_request( RQFUNC_ARG ) ++{ ++ wake_up( &thr_wq ); ++} ++ ++static int mmc_block_ioctl( struct inode * inode, struct file * file, ++ unsigned int cmd, unsigned long arg ) ++{ ++ int ret = -ENODEV; ++ mmc_block_device_t dev; ++ mmc_card_t card; ++ int minor; ++ __ENTER0(); ++ ++ if ( !inode || !file ) { ++ ret = -EINVAL; ++ goto error; ++ } ++ minor = MINOR( inode->i_rdev ); ++ ++ dev = __mmc_block_get_device( inode->i_rdev ); ++ if ( !dev ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "invalid device\n" ); ++ goto error; ++ } ++ ++ card = dev->card; ++ __mmc_block_put_device( dev ); ++ ++ switch ( cmd ) { ++ case BLKGETSIZE: /* Return device size */ ++ { ++ unsigned long value; ++ ++ __mmc_block_rdlock_devices(); ++ value = mmc_block_gendisk.part[minor].nr_sects; ++ __mmc_block_rdunlock_devices(); ++ ++ if ( put_user( value, (unsigned long *) arg) ) { ++ ret = -EFAULT; ++ goto error; ++ } ++ } ++ break; ++ ++#ifdef BLKGETSIZE64 ++ case BLKGETSIZE64: ++ { ++ unsigned long value; ++ ++ __mmc_block_rdlock_devices(); ++ value = mmc_block_gendisk.part[minor].nr_sects; ++ __mmc_block_rdunlock_devices(); ++ ++ if ( put_user( (u64)value, (u64 *) arg) ) { ++ ret = -EFAULT; ++ goto error; ++ } ++ } ++ break; ++#endif ++ ++ case HDIO_GETGEO: ++ { ++ struct hd_geometry geo; ++ ++ ret = !access_ok( VERIFY_WRITE, arg, sizeof( geo ) ); ++ if ( ret ) { ++ ret = -EFAULT; ++ goto error; ++ } ++ ++ geo.heads = 1; ++ geo.sectors = 1; ++ ++ __mmc_block_rdlock_devices(); ++ geo.cylinders = mmc_block_gendisk.part[minor].nr_sects; ++ geo.start = mmc_block_gendisk.part[minor].start_sect; ++ __mmc_block_rdunlock_devices(); ++ ++ if ( copy_to_user( (int *)arg, &geo, sizeof( geo ) ) ) { ++ ret = -EFAULT; ++ goto error; ++ } ++ } ++ break; ++ ++ case BLKRRPART: ++ if ( !capable( CAP_SYS_ADMIN ) ) { ++ ret = -EACCES; ++ goto error; ++ } ++ (void)mmc_block_revalidate( inode->i_rdev ); ++ break; ++ ++ default: ++ ret = blk_ioctl( inode->i_rdev, cmd, arg ); ++ goto out; ++ } ++ ++ ret = 0; ++error: ++out: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++#if LINUX_VERSION_CODE < 0x20326 ++static struct file_operations mmc_block_fops = ++{ ++ open: mmc_block_open, ++ ioctl: mmc_block_ioctl, ++ release: mmc_block_release, ++ check_media_change: mmc_block_check_disk_change, ++ revalidate: mmc_block_revalidate, ++ read: block_read, ++ write: block_write ++}; ++#else ++static struct block_device_operations mmc_block_fops = ++{ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14) ++ owner: THIS_MODULE, ++#endif ++ open: mmc_block_open, ++ release: mmc_block_release, ++ ioctl: mmc_block_ioctl, ++ check_media_change: mmc_block_check_disk_change, ++ revalidate: mmc_block_revalidate ++}; ++#endif ++ ++ ++static int mmc_block_notify_add( mmc_card_t card ) ++{ ++ int ret = -1; ++ mmc_block_device_t dev; ++ kdev_t start; ++ int minor; ++ ++ __ENTER0(); ++ ++ if ( !card || !card->ctrlr ) ++ goto error; ++ ++ start = MMC_BLOCK_MKDEV( card->ctrlr->slot, card->slot ); ++ dev = &mmc_block_device[MINOR( start )]; ++ ++ __mmc_block_wrlock_devices(); ++ if ( !dev->card ) { ++ dev->card = card; ++ ret = 0; ++ } ++ __mmc_block_wrunlock_devices(); ++ ++ if ( !ret ) { ++ int i; ++ ++ /* allow to read partition table */ ++ __mmc_block_rdlock_devices(); ++ grok_partitions( &mmc_block_gendisk, MINOR( start ), ++ mmc_block_gendisk.max_p, ++ card->info.capacity>>9 /* sectors */ ++ ); ++ __mmc_block_rdunlock_devices(); ++ ++ __mmc_block_wrlock_devices(); ++ for ( i = start + mmc_block_gendisk.max_p - 1; i >= 0; --i ) { ++ minor = MINOR( i ); ++ dev = &mmc_block_device[minor]; ++ if ( mmc_block_gendisk.part[minor].nr_sects > 0 ) ++ dev->card = card; ++ } ++ __mmc_block_wrunlock_devices(); ++ } ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++ ++static int mmc_block_notify_remove( mmc_card_t card ) ++{ ++ int ret = -1; ++ ++ __ENTER( "card=0x%p", card ); ++ ++ if ( card && card->ctrlr ) ++ ret = __mmc_block_invalidate_card( card, FALSE ); ++ ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static mmc_notifier_rec_t mmc_block_notifier = { ++ add: mmc_block_notify_add, ++ remove: mmc_block_notify_remove ++}; ++ ++static int __init mmc_block_module_init( void ) ++{ ++ int ret = -ENODEV; ++ int i; ++ ++ __ENTER0(); ++ ++ init_rwsem( &mmc_block_device_sem ); ++ ++ if ( devfs_register_blkdev( MAJOR_NR, MAJOR_NAME, &mmc_block_fops ) ) { ++ MMC_ERROR( "Can't allocate major number %d for MMC block devices.\n", MMC_BLOCK_MAJOR ); ++ ret = -EAGAIN; ++ goto error; ++ } ++ ++ for ( i = 0; i < (1<<MINORBITS); i++ ) { ++ __mmc_block_device_init( i ); ++ init_MUTEX( &mmc_block_device[i].sem ); ++ ++ /* We fill it in at open() time. */ ++ mmc_block_blk_sizes[i] = 0; ++ mmc_block_blk_blksizes[i] = BLOCK_SIZE; ++ mmc_block_hardsect_sizes[i] = 0; ++ } ++ ++ init_waitqueue_head( &thr_wq ); ++ /* Allow the block size to default to BLOCK_SIZE. */ ++ blksize_size[MAJOR_NR] = mmc_block_blk_blksizes; ++ hardsect_size[MAJOR_NR] = mmc_block_hardsect_sizes; ++ /* Gendisk stuff */ ++ memset( mmc_block_partitions, 0, sizeof( mmc_block_partitions ) ); ++ add_gendisk( &mmc_block_gendisk ); ++ ++/* FIXME: per controller request queue, I/O and card stack update threads */ ++ blk_init_queue( BLK_DEFAULT_QUEUE( MAJOR_NR ), &mmc_block_request ); ++ thr_id = kernel_thread( mmc_block_thread, NULL, ++ CLONE_FS|CLONE_FILES|CLONE_SIGHAND ); ++ ++ if ( !mmc_register( MMC_REG_TYPE_USER, &mmc_block_notifier, 0 ) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to register with MMC core\n" ); ++ goto error; ++ } ++ ++ ret = 0; ++ goto out; ++error: ++ if ( thr_id != -1 ) { ++/* quit the thread */ ++ leaving = 1; ++ wake_up(&thr_wq); ++ ++ down(&thread_sem); ++ } ++ blksize_size[MAJOR_NR] = NULL; ++ blk_size[MAJOR_NR] = NULL; ++ hardsect_size[MAJOR_NR] = NULL; ++out: ++ __LEAVE0(); ++ return ret; ++} ++ ++static void __exit mmc_block_module_cleanup( void ) ++{ ++/* quit the thread */ ++ leaving = 1; ++ wake_up(&thr_wq); ++ ++ down(&thread_sem); ++ ++ mmc_unregister( MMC_REG_TYPE_USER, &mmc_block_notifier ); ++ del_gendisk( &mmc_block_gendisk ); ++ devfs_unregister_blkdev( MAJOR_NR, MAJOR_NAME ); ++ ++ blk_cleanup_queue( BLK_DEFAULT_QUEUE( MAJOR_NR ) ); ++ blksize_size[MAJOR_NR] = NULL; ++ blk_size[MAJOR_NR] = NULL; ++ hardsect_size[MAJOR_NR] = NULL; ++} ++ ++EXPORT_NO_SYMBOLS; ++ ++module_init( mmc_block_module_init ); ++module_exit( mmc_block_module_cleanup ); ++ ++ ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/mmc/mmc_core.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,1124 @@ ++/* ++ * linux/drivers/mmc/mmc_core.c ++ * MultiMediaCard subsystem core implementation ++ * ++ * Author: Vladimir Shebordaev ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id$ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/version.h> ++#include <linux/config.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++ ++#include <linux/slab.h> ++#include <asm/uaccess.h> ++#include <asm/semaphore.h> ++ ++#ifdef CONFIG_PM ++#include <linux/pm.h> ++#endif ++ ++#include <mmc/types.h> ++#include <mmc/mmc.h> ++#include <mmc/ioctl.h> ++ ++#include "types.h" ++ ++#define __MMC_CORE_IMPLEMENTATION__ ++#include "mmc.h" ++ ++/* MMC controllers registered in the system */ ++static mmc_controller_t mmc_controller[MMC_CONTROLLERS_MAX]; ++static int mmc_ncontrollers = 0; ++static rwsemaphore_t mmc_controller_sem; /* controller table lock */ ++#ifdef CONFIG_PM ++static struct pm_dev *mmc_pm_dev = NULL; ++#endif ++ ++/* users' notification list */ ++static mmc_notifier_t mmc_notifier = NULL; ++static rwsemaphore_t mmc_notifier_sem; /* notifiers' list lock */ ++#ifdef CONFIG_PROC_FS ++static proc_dir_entry_t mmc_proc_dir = NULL; ++#endif ++ ++/************************************************ ++ * service function prototypes and declarations * ++ ************************************************/ ++static inline int mmc_acquire_io( mmc_controller_t ctrlr, mmc_card_t card ) ++{ ++ int ret = -EIO; ++ ++ __ENTER0(); ++ ++ if ( !card || !ctrlr ) { ++ ret = -EINVAL; ++ goto error; ++ } ++#ifdef CONFIG_HOTPLUG ++/* TODO: account for controller removal */ ++#endif ++ down( &ctrlr->io_sem ); ++#if 0 ++ down_read( &ctrlr->update_sem ); /* FIXME */ ++ if ( card->state != MMC_CARD_STATE_UNPLUGGED ) ++ ret = 0; ++ up_read( &ctrlr->update_sem ); ++ ++ if ( ret ) ++ up( &ctrlr->io_sem ); ++#else ++ ret = 0; ++#endif ++ ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static inline void mmc_release_io( mmc_controller_t ctrlr, mmc_card_t card ) ++{ ++ __ENTER0(); ++#ifdef CONFIG_HOTPLUG ++/* TODO: account for controller removal */ ++#endif ++ if ( !card && !ctrlr ) { /* FIXME */ ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "bad card reference\n" ); ++ goto error; ++ } ++ up( &ctrlr->io_sem ); ++error: ++ __LEAVE0(); ++} ++ ++/* TODO: there should be a separate context to be awaken ++ * by the card intertion interrupt; called under ctrlr->update_sem ++ * held down by now */ ++static int __mmc_update_card_stack( mmc_controller_t ctrlr ) ++{ ++ int ret = -1; ++ mmc_card_t card, prev; ++ ++ __ENTER0(); ++ ++ if ( !ctrlr || !ctrlr->tmpl ) ++ goto error; ++ ++ /* check unplugged cards first... */ ++ if ( (ret = ctrlr->tmpl->check_card_stack( ctrlr )) ) ++ goto error; ++ ++ /* unregister unplugged cards and free 'em immediately */ ++ if ( ctrlr->stack.ncards > 0 ) { ++ prev = ctrlr->stack.first; ++ /* process the stack tail first */ ++ if ( prev->next ) { ++ card = prev->next; ++ while ( card ) { ++ if ( card->state == MMC_CARD_STATE_UNPLUGGED ) { ++ if ( ctrlr->stack.selected == card ) ++ ctrlr->stack.selected = NULL; ++#ifdef CONFIG_PROC_FS ++ if ( card->proc ) { ++ remove_proc_entry( card->proc_name, ctrlr->proc ); ++ card->proc = NULL; ++ } ++#endif ++ ctrlr->slot_next = card->slot; /* FIXME */ ++ prev->next = card->next; ++ if ( ctrlr->stack.last == card ) ++ ctrlr->stack.last = prev; ++ /* FIXME: controller use count */ ++ mmc_notify_remove( card ); ++ --ctrlr->stack.ncards; ++ if ( (ctrlr->usage > 0) && ctrlr->tmpl->owner ) { ++ --ctrlr->usage; ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, ++ "'%s' use count " ++ "decreased (%d)\n", ++ ctrlr->tmpl->name, ++ ctrlr->usage ); ++ __MOD_DEC_USE_COUNT( ++ ctrlr->tmpl->owner ); ++ } ++ __mmc_card_free( card ); ++ ++ card = prev->next; ++ } ++ } ++ } ++ /* then the head */ ++ card = ctrlr->stack.first; ++ if ( card && (card->state == MMC_CARD_STATE_UNPLUGGED) ) { ++ if ( ctrlr->stack.selected == card ) ++ ctrlr->stack.selected = NULL; ++#ifdef CONFIG_PROC_FS ++ if ( card->proc ) { ++ remove_proc_entry( card->proc_name, ctrlr->proc ); ++ card->proc = NULL; ++ } ++#endif ++ ctrlr->slot_next = card->slot; /* FIXME */ ++ mmc_notify_remove( card ); /* FIXME: should unregister here */ ++ ctrlr->stack.first = card->next; ++ if ( ctrlr->stack.last == card ) ++ ctrlr->stack.last = NULL; ++ /* FIXME: controller use count */ ++ --ctrlr->stack.ncards; ++ if ( (ctrlr->usage > 0) && ctrlr->tmpl->owner ) { ++ --ctrlr->usage; ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "'%s' use count " ++ "decreased (%d)\n", ctrlr->tmpl->name, ++ ctrlr->usage ); ++ __MOD_DEC_USE_COUNT( ctrlr->tmpl->owner ); ++ } ++ __mmc_card_free( card ); ++ } ++ } ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "after stack check: ncards=%d" ++ " first=0x%x last=0x%x\n", ctrlr->stack.ncards, ++ ctrlr->stack.first, ctrlr->stack.last ); ++ /* ...then add newly inserted ones */ ++ if ( (ret = ctrlr->tmpl->update_acq( ctrlr )) ) ++ goto error; ++ /* ret = 0; */ ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++/* ++ * 1) check error code returned by controller; it's up to ++ * controller to detect error conditions reported by the card ++ * and to abort data transfer requests properly (e.g. send ++ * CMD12(STOP_TRANSMISSION) to abort ADDRESS_ERROR multiple ++ * block transfers) ++ * 2) arrange for card stack update when necessary ++ * (all pending i/o requests must be held pending, ++ * update procedure must start immediately after ++ * error has been detected) ++ */ ++static inline int __mmc_check_error( mmc_card_t card, int err ) ++{ ++ int ret = -EIO; ++ mmc_controller_t ctrlr; ++ ++ __ENTER0(); ++ ++ if ( !card || !card->ctrlr ) ++ goto error; ++ ++ ctrlr = card->ctrlr; ++ ++ if ( err < 0 ) { ++ switch ( err ) { ++ /* bus error occurred */ ++ case MMC_ERROR_CRC_WRITE_ERROR: ++ case MMC_ERROR_CRC_READ_ERROR: ++ case MMC_ERROR_RES_CRC_ERROR: ++ case MMC_ERROR_READ_TIME_OUT: ++ case MMC_ERROR_TIME_OUT_RESPONSE: ++ down_write( &ctrlr->update_sem ); /* FIXME */ ++ if ( !__mmc_update_card_stack( ctrlr ) ) ++ ret = -ENXIO; ++ up_write( &ctrlr->update_sem ); ++ break; ++ } ++ } else ++ ret = err; ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static inline void __mmc_free_controller( mmc_controller_t ctrlr ) ++{ ++ if ( ctrlr ) { ++ if ( ctrlr->stack.ncards > 0 ) ++ __mmc_card_stack_free( &ctrlr->stack ); ++ kfree( ctrlr ); ++ } ++} ++ ++#ifdef CONFIG_PROC_FS ++static int mmc_proc_read_card_info( char *page, char **start, off_t off, int count, int *eof, void *data ) ++{ ++ int ret = -EINVAL; ++ mmc_card_t card = (mmc_card_t)data; ++ char *cp = page; ++ ++ if ( !card ) ++ goto error; ++ ++ down_read( &card->ctrlr->update_sem ); ++/* TODO: proc report ++ * Type: RO, RW or IO (by CCC) ++ * MID: 0x%02x card->info.cid.mid ++ * OID: 0x%04x card->info.cid.oid ++ * PNM: %s card->info.pnm ++ * PRV: %s card->info.prv ++ * PSN: 0x%08x card->info.cid.psn ++ * MDT: %s card->info.mdt ++ * Capacity: card->info.capacity (Bytes) ++ */ ++#if 1 ++ cp += sprintf( cp, "Capacity: %dKb.\n\n", (card->info.capacity>>10) ); ++#else /* TODO */ ++ cp += sprintf( cp, "Type : %s\n", card->info.type ); ++ cp += sprintf( cp, "MID : 0x%02x\n", card->info.cid.mid ); ++ cp += sprintf( cp, "OID : 0x%04x\n", card->info.cid.oid ); ++ cp += sprintf( cp, "PNM : %s\n", card->info.pnm ); ++ cp += sprintf( cp, "PRV : %s\n", card->info.prv ); ++ cp += sprintf( cp, "PSN : 0x%08x\n", card->info.cid.psn ); ++ cp += sprintf( cp, "MDT : %s\n", card->info.mdt ); ++ cp += sprintf( cp, "Capacity: %dKB\n", ++ (card->info.capacity>>10) ); ++#endif ++ up_read( &card->ctrlr->update_sem ); ++ ++ ret = cp - page; ++error: ++ return ret; ++} ++#endif ++ ++/************************************* ++ * MMC core interface implementation * ++ *************************************/ ++int mmc_notify_add( mmc_card_t card ) ++{ ++ int ret = 0; ++ mmc_notifier_t notifier; ++ ++ __ENTER0(); ++ if ( card ) { ++ for ( notifier = mmc_notifier; notifier; ++ notifier = notifier->next ) ++ if ( notifier->add ) ++ if ( (ret = notifier->add( card )) ) ++ break; ++ } ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++EXPORT_SYMBOL( mmc_notify_add ); ++ ++int mmc_notify_remove( mmc_card_t card ) ++{ ++ int ret = 0; ++ mmc_notifier_t notifier; ++ ++ __ENTER0(); ++ if ( card ) { ++ for ( notifier = mmc_notifier; notifier; ++ notifier = notifier->next ) ++ if ( notifier->remove ) ++ if ( (ret = notifier->remove( card )) ) ++ break; ++ } ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++EXPORT_SYMBOL( mmc_notify_remove ); ++ ++int mmc_update_card_stack( int host ) ++{ ++ int ret = -EINVAL; ++ mmc_controller_t ctrlr; ++ ++ __ENTER0(); ++ ++ if ( (host < 0) || (host >= MMC_CONTROLLERS_MAX) ) ++ goto error; ++ ++ down_read( &mmc_controller_sem ); ++ if ( (ctrlr = mmc_controller[host]) ) { ++ down_write( &ctrlr->update_sem ); ++ (void)__mmc_update_card_stack( ctrlr ); ++ up_write( &ctrlr->update_sem ); ++ } ++ up_read( &mmc_controller_sem ); ++ ret = 0; ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++EXPORT_SYMBOL( mmc_update_card_stack ); ++ ++ssize_t mmc_read( mmc_card_t card, mmc_transfer_mode_t mode, char *buf, size_t size, loff_t *paddr ) ++{ ++ ssize_t ret = -EIO; ++ mmc_controller_t ctrlr; ++ mmc_data_transfer_req_rec_t transfer; ++ ++ if ( !paddr ) { ++ ret = -EINVAL; ++ goto error; ++ } ++ ++ if ( !card ) { ++ ret = -ENODEV; ++ goto error; ++ } ++ ++ __ENTER( "card=%p usage=%d mode=%d buf=%p size=%d addr=%x", ++ card, card->usage, mode, buf, size, *paddr ); ++ ++ ctrlr = card->ctrlr; ++ if ( (ret = mmc_acquire_io( ctrlr, card )) ) ++ goto error; ++ ++ memset( &transfer, 0, sizeof( mmc_data_transfer_req_rec_t ) ); ++ transfer.cmd = MMC_READ; ++ transfer.mode = mode; ++ transfer.type = MMC_USER; /* FIXME: buffer cache */ ++ transfer.buf = buf; ++ transfer.addr = *paddr; ++ transfer.cnt = size; ++ ++/* max block size defined by CSD[read_bl_len] */ ++ transfer.blksz = card->info.read_bl_len; ++ transfer.nob = size / transfer.blksz; ++ if ( (size - (transfer.nob * transfer.blksz)) > 0 ) ++ transfer.nob++; ++ ++/* TODO: controller may restrict maximum block size; set block size ++ * and number of blocks that their accumulated length fit to ++ * CSD[READ_BL_LEN] not to bother with block misalignment in multiple ++ * block transfers */ ++ ctrlr = card->ctrlr; ++ if ( transfer.blksz > ctrlr->tmpl->block_size_max ) { ++ ret = -EINVAL; /* FIXME */ ++ goto error; ++ } ++ ++ if ( ctrlr->stack.selected != card ) { ++ if ( (ret = ctrlr->tmpl->setup_card( ctrlr, card )) ) ++ goto err_mmc; ++ ctrlr->stack.selected = card; ++ } ++ ++ switch( mode ) { ++ case MMC_TRANSFER_MODE_STREAM: ++ if ( !ctrlr->tmpl->stream_read ) { ++ ret = -ENXIO; ++ goto err_down; ++ } ++/* TODO: The max clock frequency for stream read operation is given by ++ the following formula: ++ max speed = min ( TRAN_SPEED, 8*2^(READ_BL_LEN) - NSAC/TAAC ) ++ ++ If the card is not able to sustain data transfer it will set the ++ UNDERRUN error bit in the status register, abort the transmission ++ and wait in the Data state for a stop command ++ */ ++ ret = ctrlr->tmpl->stream_read( ctrlr, &transfer ); ++ break; ++ ++ case MMC_TRANSFER_MODE_BLOCK_SINGLE: ++ if ( !ctrlr->tmpl->read_block ) { ++ ret = -ENXIO; ++ goto err_down; ++ } ++/* TODO: buffer size and data alignment (v3.4, p.29): ++ if CSD[READ_BL_PARTIAL] is set, smaller blocks whose starting ++ and ending address are entirely contained within one physical ++ block (as defined by CSD[READ_BL_LEN]) may also be transmitted ++ */ ++ transfer.type = MMC_KERNEL; /* FIXME */ ++ ret = ctrlr->tmpl->read_block( ctrlr, &transfer ); ++ break; ++ ++ case MMC_TRANSFER_MODE_BLOCK_MULTIPLE: ++ if ( !ctrlr->tmpl->read_mblock ) { ++ ret = -ENXIO; ++ goto err_down; ++ } ++ ++ if ( transfer.nob > ctrlr->tmpl->nob_max ) { ++ ret = -EINVAL; ++ goto error; ++ } ++/* TODO: buffer size and data alignment (v3.4, p.29): ++ if the host uses patrial blocks whose accumulated length is ++ not block aligned and block misalignment is not allowed, the ++ card should detect a block misalignment error condition at the ++ beginning of the first misaligned block ++ */ ++ transfer.type = MMC_KERNEL; /* FIXME */ ++ ret = ctrlr->tmpl->read_mblock( card->ctrlr, &transfer ); ++ break; ++ ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "request for unknown transfer type\n" ); ++ ret = -EINVAL; ++ } ++err_mmc: ++ ret = __mmc_check_error( card, ret ); ++ if ( ret >= 0 ) { ++ ret = size - transfer.cnt; ++ *paddr += ret; ++ } ++err_down: ++ mmc_release_io( ctrlr, card ); ++error: ++ __LEAVE("ret=%d", ret); ++ return ret; ++} ++EXPORT_SYMBOL( mmc_read ); ++ ++ssize_t mmc_write( mmc_card_t card, mmc_transfer_mode_t mode, const char *buf, size_t size, loff_t *paddr ) ++{ ++ ssize_t ret = -ESPIPE; ++ mmc_controller_t ctrlr; ++ mmc_data_transfer_req_rec_t transfer; ++ ++ if ( !paddr ) { ++ ret = -EINVAL; ++ goto error; ++ } ++ ++ if ( !card ) { ++ ret = -ENODEV; ++ goto error; ++ } ++ ++ __ENTER( "card=%p usage=%d mode=%d buf=%p size=%d addr=%llx", ++ card, card->usage, mode, buf, size, *paddr ); ++ ++ ctrlr = card->ctrlr; ++ if ( (ret = mmc_acquire_io( ctrlr, card )) ) ++ goto error; ++ ++ memset( &transfer, 0, sizeof( mmc_data_transfer_req_rec_t ) ); ++ transfer.cmd = MMC_WRITE; ++ transfer.mode = mode; ++ transfer.type = MMC_USER; /* FIXME: buffer cache */ ++ transfer.buf = (char *)buf; ++ transfer.addr = *paddr; ++ transfer.cnt = size; ++ ++/* max block size defined by CSD[write_bl_len] */ ++ transfer.blksz = card->info.write_bl_len; ++ transfer.nob = size / transfer.blksz; ++ if ( (size - (transfer.nob * transfer.blksz)) > 0 ) ++ transfer.nob++; ++ ++/* TODO: controller may restrict maximum block size; set block size ++ * and number of blocks that their accumulated length fit to ++ * CSD[WRITE_BL_LEN] not to bother with block misalignment in multiple ++ * block transfers */ ++ ctrlr = card->ctrlr; ++ if ( transfer.blksz > ctrlr->tmpl->block_size_max ) { ++ ret = -EINVAL; /* FIXME */ ++ goto error; ++ } ++ ++ if ( ctrlr->stack.selected != card ) { ++ if ( (ret = ctrlr->tmpl->setup_card( ctrlr, card )) ) ++ goto err_mmc; ++ ctrlr->stack.selected = card; ++ } ++ ++ transfer.cmd = MMC_WRITE; ++ transfer.mode = mode; ++ transfer.type = MMC_USER; ++ switch( mode ) { ++ case MMC_TRANSFER_MODE_STREAM: ++ if ( !ctrlr->tmpl->stream_write ) { ++ ret = -ENXIO; ++ goto err_down; ++ } ++ ret = ctrlr->tmpl->stream_write( ctrlr, &transfer ); ++ break; ++ ++ case MMC_TRANSFER_MODE_BLOCK_SINGLE: ++ if ( !ctrlr->tmpl->write_block ) { ++ ret = -ENXIO; ++ goto err_down; ++ } ++ transfer.type = MMC_KERNEL; /* FIXME */ ++ ret = ctrlr->tmpl->write_block( ctrlr, &transfer ); ++ break; ++ ++ case MMC_TRANSFER_MODE_BLOCK_MULTIPLE: ++ if ( !ctrlr->tmpl->write_mblock ) { ++ ret = -ENXIO; ++ goto err_down; ++ } ++ transfer.type = MMC_KERNEL; /* FIXME */ ++ ret = ctrlr->tmpl->write_mblock( card->ctrlr, &transfer ); ++ break; ++ ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "request for unknown transfer type\n" ); ++ } ++ ++err_mmc: ++ ret = __mmc_check_error( card, ret ); /* FIXME */ ++ if ( ret >= 0 ) { ++ ret = size - transfer.cnt; ++ *paddr += ret; ++ } ++err_down: ++ mmc_release_io( ctrlr, card ); ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++EXPORT_SYMBOL( mmc_write ); ++ ++int mmc_ioctl( mmc_card_t card, unsigned int cmd, unsigned long arg ) ++{ ++ int ret = -EINVAL; ++ mmc_controller_t ctrlr; ++ ++ if ( !card ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "bad card reference\n" ) ++ goto error; ++ } ++ ++ ctrlr = card->ctrlr; ++ if ( mmc_acquire_io( ctrlr, card ) ) { ++ ret = -ENXIO; ++ goto error; ++ } ++ ++ switch ( cmd ) { ++ case IOCMMCGCARDESC: ++ if ( copy_to_user( (void *)arg, &card->info, sizeof( mmc_card_info_rec_t ) ) ) ++ ret = -EFAULT; ++ break; ++/* ++ * 1. TODO: erase region ++ * 2. TODO: set/unset write protection, lock/password ++ */ ++ default: ++ ret = -ENOIOCTLCMD; ++ } ++ ++ mmc_release_io( ctrlr, card ); ++error: ++ return ret; ++} ++EXPORT_SYMBOL( mmc_ioctl ); ++ ++/* ++ * registry stuff ++ */ ++mmc_card_t mmc_get_card( int host, int slot ) ++{ ++ mmc_card_t ret = NULL; ++ mmc_controller_t ctrlr = NULL; ++ int found; ++ ++ __ENTER( "host=%d, card=%d", host, slot ); ++ ++ if ( ((host < 0) || (host >= MMC_CONTROLLERS_MAX)) ++ && ((slot < 0) || (slot >= MMC_CARDS_MAX)) ) ++ goto error; ++ ++ down_read( &mmc_controller_sem ); ++ ++ if ( (ctrlr = mmc_controller[host]) ) { ++ down_write( &ctrlr->update_sem ); ++ if ( ctrlr->stack.ncards > 0 ) { ++ ret = ctrlr->stack.first; ++ found = FALSE; ++ while ( ret ) { ++ if ( (ret->slot == slot) && (ret->state != ++ MMC_CARD_STATE_UNPLUGGED) ) { ++ found = TRUE; ++ break; ++ } ++ ret = ret->next; ++ } ++ ++ if ( found ) { ++ if ( ctrlr->tmpl->owner ) { ++ ++ctrlr->usage; ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, ++ "'%s' use count increased (%d)\n", ++ ctrlr->tmpl->name, ctrlr->usage ); ++ __MOD_INC_USE_COUNT( ctrlr->tmpl->owner ); ++ } ++ ++ret->usage; ++ } else ++ ret = NULL; ++ } ++ up_write( &ctrlr->update_sem ); ++ } ++ up_read( &mmc_controller_sem ); ++error: ++ __LEAVE("ret=0x%p usage=%d", ret, ret ? ret->usage : -1 ); ++ return ret; ++} ++EXPORT_SYMBOL( mmc_get_card ); ++ ++void mmc_put_card( mmc_card_t card ) ++{ ++ mmc_card_t tmp = NULL; ++ mmc_controller_t ctrlr; ++ int found; ++ ++ __ENTER( "card=0x%p", card ); ++ ++ if ( !card ) ++ goto error; ++ ++ ctrlr = card->ctrlr; ++ ++ down_read( &mmc_controller_sem ); ++ if ( !ctrlr || (ctrlr != mmc_controller[ctrlr->slot]) ) { ++ MMC_ERROR( "bad controller reference: ctrlr=0x%p\n", ctrlr ); ++ goto err_down; ++ } ++ ++ down_write( &ctrlr->update_sem ); ++ if ( ctrlr->stack.ncards > 0 ) { ++ tmp = ctrlr->stack.first; ++ found = FALSE; ++ while ( tmp ) { ++ if ( tmp == card ) { ++ found = TRUE; ++ break; ++ } ++ tmp = tmp->next; ++ } ++ ++ if ( found ) { ++ if ( tmp->usage > 0 ) { ++ --tmp->usage; ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "usage=%d" ++ "owner=0x%p\n", tmp->usage, ++ ctrlr->tmpl->owner ); ++ if ( !tmp->usage && (ctrlr->usage > 0) ++ && ctrlr->tmpl->owner ) { ++ --ctrlr->usage; ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, ++ "'%s' use count " ++ "decreased (%d)\n", ++ ctrlr->tmpl->name, ++ ctrlr->usage ); ++ __MOD_DEC_USE_COUNT( ++ ctrlr->tmpl->owner ); ++ } ++ } ++ } else ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "bad card reference\n" ); ++ ++ } ++ up_write( &ctrlr->update_sem ); ++err_down: ++ up_read( &mmc_controller_sem ); ++error: ++ __LEAVE( "found=%d", found ); ++ return; ++} ++EXPORT_SYMBOL( mmc_put_card ); ++ ++static inline void *mmc_register_user( mmc_notifier_t notifier ) ++{ ++ mmc_notifier_t ret = NULL, last = mmc_notifier; ++ ++ MOD_INC_USE_COUNT; ++ if ( notifier ) { ++ down_write( &mmc_notifier_sem ); ++ ++ notifier->next = NULL; ++ if ( !last ) { ++ mmc_notifier = notifier; ++ ret = notifier; ++ } else { ++ while ( last->next ) { ++ if ( last == notifier ) { ++ MOD_DEC_USE_COUNT; ++ break; ++ } ++ last = last->next; ++ } ++ if ( last != notifier ) { ++ last->next = notifier; ++ ret = notifier; ++ } ++ } ++ up_write( &mmc_notifier_sem ); ++ } ++/* notify new user about the cards present in the system */ ++ if ( ret && ret->add ) { ++ int i; ++ ++ down_read( &mmc_controller_sem ); ++ for ( i = 0; i < mmc_ncontrollers; i++ ) { ++ mmc_controller_t ctrlr = mmc_controller[i]; ++ ++ down_read( &ctrlr->update_sem ); /* FIXME */ ++ __mmc_card_stack_foreach( &ctrlr->stack, ++ ret->add, FALSE ); ++ up_read( &ctrlr->update_sem ); /* FIXME */ ++ } ++ up_read( &mmc_controller_sem ); ++ } ++/* error: */ ++ __LEAVE( "mmc_notifier=0x%p, mmc_notifier->next=0x%p", ++ mmc_notifier, mmc_notifier ? mmc_notifier->next : NULL ); ++ return ret; ++} ++ ++static inline mmc_controller_t mmc_register_controller( mmc_controller_tmpl_t tmpl, size_t extra ) ++{ ++ mmc_controller_t ret = NULL; ++ int found; ++ int i; ++ ++ MOD_INC_USE_COUNT; ++ ++ down_write( &mmc_controller_sem ); ++ ++ if ( mmc_ncontrollers >= MMC_CONTROLLERS_MAX ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "there're too many controllers\n" ); ++ goto error; ++ } ++ ++ found = FALSE; ++ for ( i = 0; i < MMC_CONTROLLERS_MAX; i++ ) ++ if ( !mmc_controller[i] ) { ++ found = TRUE; ++ break; ++ } ++ ++ if ( !found ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "there're no empty slots\n" ); ++ goto error; ++ } ++ ++ if ( !tmpl->init ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'init()'\n" ); ++ goto error; ++ } ++ ++ if ( !tmpl->probe ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'probe()'\n" ); ++ goto error; ++ } ++ ++ if ( !tmpl->init_card_stack ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'init_card_stack()'\n" ); ++ goto error; ++ } ++ ++ if ( !tmpl->update_acq ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'update_acq()'\n" ); ++ goto error; ++ } ++ ++ if ( !tmpl->check_card_stack ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'check_card_stack()'\n" ); ++ goto error; ++ } ++ ++ if ( !tmpl->setup_card ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'setup_card()'\n" ); ++ goto error; ++ } ++ ++ ret = kmalloc( sizeof( mmc_controller_rec_t ) + extra, GFP_ATOMIC ); /* FIXME: ISA + GFP_DMA */ ++ if ( !ret ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "out of memory\n" ); ++ goto error; ++ } ++ ++ memset( ret, 0, sizeof( mmc_controller_rec_t ) + extra ); ++ ++ if ( (tmpl->probe( ret ) != 1) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "controller probe failed\n" ); ++ goto err_free; ++ } ++ ++ if ( tmpl->init( ret ) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "controller initialization failure\n" ); ++ goto err_free; ++ } ++ ++ ret->state = MMC_CONTROLLER_FOUND; ++ ret->slot = i; ++ ret->tmpl = tmpl; ++ init_MUTEX( &ret->io_sem ); ++ init_rwsem( &ret->update_sem ); ++#ifdef CONFIG_PROC_FS ++ if ( mmc_proc_dir ) { ++ snprintf( ret->proc_name, sizeof( ret->proc_name ), ++ "host%d", ret->slot ); ++ ret->proc = proc_mkdir( ret->proc_name, mmc_proc_dir ); ++ } ++#endif ++ ++/* initialize card stack */ ++ if ( ret->tmpl->init_card_stack( ret ) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "card stack initialization failure\n" ); ++ if ( ret->tmpl->remove ) ++ ret->tmpl->remove( ret ); /* FIXME */ ++ goto err_free; ++ } ++ ++ mmc_controller[ret->slot] = ret; ++ ++mmc_ncontrollers; ++ ++/* notify users */ ++ if ( ret->stack.ncards > 0 ) { ++ down_read( &mmc_notifier_sem ); ++ if ( (i = __mmc_card_stack_foreach( &ret->stack, mmc_notify_add, FALSE ) ) < 0 ) ++ MMC_ERROR( "device add notification failed at slot %d\n", -i ); ++ up_read( &mmc_notifier_sem ); ++ } ++ goto out; ++ ++err_free: ++#ifdef CONFIG_PROC_FS ++ if ( ret->proc ) ++ remove_proc_entry( ret->proc_name, mmc_proc_dir ); ++#endif ++ kfree( ret ); ++error: ++ ret = NULL; ++ MOD_DEC_USE_COUNT; ++out: ++ up_write( &mmc_controller_sem ); ++ return ret; ++} ++ ++static inline mmc_card_t mmc_register_card( mmc_card_t card ) ++{ ++ mmc_card_t ret = NULL; ++ mmc_controller_t ctrlr; ++ ++ if ( !card || !card->ctrlr ) ++ goto error; ++ ++ ctrlr = card->ctrlr; ++#ifdef CONFIG_PROC_FS ++ if ( ctrlr->proc ) { ++ snprintf( card->proc_name, sizeof( card->proc_name ), ++ "card%d", card->slot ); ++ card->proc = create_proc_read_entry( card->proc_name, ++ 0444, ctrlr->proc, ++ mmc_proc_read_card_info, card ); ++ } ++#endif ++ mmc_notify_add( card ); ++error: ++ return ret; ++} ++ ++void *mmc_register( mmc_reg_type_t reg_type, void *tmpl, size_t extra ) ++{ ++ void *ret = NULL; ++ ++ switch ( reg_type ) { ++ case MMC_REG_TYPE_CARD: ++ ret = mmc_register_card( (mmc_card_t)tmpl ); ++ break; ++ ++ case MMC_REG_TYPE_USER: ++ ret = mmc_register_user( (mmc_notifier_t)tmpl ); ++ break; ++ ++ case MMC_REG_TYPE_HOST: ++ ret = mmc_register_controller( (mmc_controller_tmpl_t)tmpl, extra ); ++ break; ++ ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "register request for unknown type\n" ); ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL( mmc_register ); ++ ++static inline void mmc_unregister_user( mmc_notifier_t notifier ) ++{ ++ mmc_notifier_t prev = mmc_notifier; ++ int found = FALSE; ++ ++ if ( notifier ) { ++ down_write( &mmc_notifier_sem ); ++ ++ if ( mmc_notifier == notifier) { ++ mmc_notifier = prev->next; ++ found = TRUE; ++ ++ } else if ( mmc_notifier ) { ++ while( prev ) { ++ if ( prev->next == notifier ) { ++ found = TRUE; ++ prev->next = prev->next->next; ++ break; ++ } ++ prev = prev->next; ++ } ++ } ++ ++ if ( found ) { ++ if ( notifier->remove ) { ++ int i; ++ ++ down_read( &mmc_controller_sem ); ++ for ( i = 0; i < mmc_ncontrollers; i++ ) { ++ mmc_controller_t ctrlr = ++ mmc_controller[i]; ++ ++ down_read( &ctrlr->update_sem ); ++ __mmc_card_stack_foreach( &ctrlr->stack, notifier->remove, FALSE ); ++ up_read( &ctrlr->update_sem ); ++ } ++ up_read( &mmc_controller_sem ); ++ } ++ } ++ ++ up_write( &mmc_notifier_sem ); ++ } ++ ++ MOD_DEC_USE_COUNT; ++} ++ ++static inline void mmc_unregister_controller( mmc_controller_t ctrlr ) ++{ ++ if ( !ctrlr || (mmc_controller[ctrlr->slot] != ctrlr ) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "bad unregister request\n" ); ++ goto error; ++ } ++ ++ down_write( &mmc_controller_sem ); ++ ++/* notify users */ ++ if ( ctrlr->stack.ncards > 0 ) { ++ int slot; ++ ++ down_read( &mmc_notifier_sem ); ++ if ( (slot = __mmc_card_stack_foreach( &ctrlr->stack, mmc_notify_remove, FALSE ) ) ) ++ MMC_ERROR( "device remove notification failed at slot %d\n", -slot ); ++ up_read( &mmc_notifier_sem ); ++ } ++ ++#ifdef CONFIG_PROC_FS ++ if ( ctrlr->proc ) ++ remove_proc_entry( ctrlr->proc_name, mmc_proc_dir ); ++#endif ++ ++ if ( ctrlr->tmpl && ctrlr->tmpl->remove ) ++ ctrlr->tmpl->remove( ctrlr ); ++ ++ mmc_controller[ctrlr->slot] = NULL; ++ --mmc_ncontrollers; ++ ++ __mmc_free_controller( ctrlr ); ++ ++ up_write( &mmc_controller_sem ); ++ MOD_DEC_USE_COUNT; ++error: ++ return; ++} ++ ++void mmc_unregister( mmc_reg_type_t reg_type, void *tmpl ) ++{ ++ switch ( reg_type ) { ++ case MMC_REG_TYPE_USER: ++ mmc_unregister_user( (mmc_notifier_t)tmpl ); ++ break; ++ ++ case MMC_REG_TYPE_HOST: ++ mmc_unregister_controller( (mmc_controller_t)tmpl ); ++ break; ++ ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "unregister request for unknown type\n" ); ++ } ++} ++EXPORT_SYMBOL( mmc_unregister ); ++ ++#ifdef CONFIG_PM ++/* power management support */ ++static int mmc_pm_callback( struct pm_dev *pmdev, pm_request_t pmreq, void *pmdata ) ++{ ++ int ret = -EINVAL; ++ mmc_controller_t ctrlr; ++ int i; ++ ++ __ENTER( "pmreq=%d", pmreq ); ++ ++ down_read( &mmc_controller_sem ); ++ ++ switch ( pmreq ) { ++ case PM_SUSPEND: ++ for ( ret = 0, i = 0; !ret && (i < mmc_ncontrollers); i++ ) { ++ ctrlr = mmc_controller[i]; ++ if ( ctrlr->tmpl->suspend ) ++ ret = ctrlr->tmpl->suspend( ctrlr ); ++ } ++ if ( !ret ) ++ break; ++ ++ case PM_RESUME: ++ for ( i = mmc_ncontrollers - 1; i >= 0; i-- ) { ++ ctrlr = mmc_controller[i]; ++ if ( ctrlr->tmpl->resume ) ++ ctrlr->tmpl->resume( ctrlr ); ++ } ++ ret = 0; ++ break; ++ ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "unsupported PM request %d\n", ++ pmreq ); ++ } ++ ++ up_read( &mmc_controller_sem ); ++/* error: */ ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++#endif ++ ++/* kernel module stuff */ ++static int __init mmc_core_module_init( void ) ++{ ++ int ret = -ENODEV; ++ ++ memset( &mmc_controller, 0, sizeof( mmc_controller ) ); ++ ++ init_rwsem( &mmc_controller_sem ); ++ init_rwsem( &mmc_notifier_sem ); ++#ifdef CONFIG_PM ++ if ( !(mmc_pm_dev = pm_register( PM_UNKNOWN_DEV, 0, mmc_pm_callback )) ) MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to register PM callback\n" ); ++#endif ++#ifdef CONFIG_PROC_FS ++ mmc_proc_dir = proc_mkdir( "mmc", NULL ); ++#endif ++ ret = 0; ++/* error: */ ++ return ret; ++} ++ ++static void __exit mmc_core_module_cleanup( void ) ++{ ++#ifdef CONFIG_PROC_FS ++ if ( mmc_proc_dir ) ++ remove_proc_entry( "mmc", NULL ); ++#endif ++#ifdef CONFIG_PM ++ pm_unregister( mmc_pm_dev ); ++#endif ++} ++ ++module_init( mmc_core_module_init ); ++module_exit( mmc_core_module_cleanup ); ++ ++MODULE_LICENSE( "GPL" ); ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/mmc/mmc_pxa.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,1902 @@ ++/* ++ * linux/drivers/mmc/mmc_pxa.c ++ * driver for Cotulla MMC controller ++ * ++ * Authors: Vladimir Shebordaev, Igor Oblakov ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id$ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/version.h> ++#include <linux/config.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++ ++#include <linux/slab.h> ++#include <linux/sched.h> ++#include <linux/delay.h> ++ ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/dma.h> ++ ++#include <asm/uaccess.h> ++#include <asm/semaphore.h> ++ ++#include <mmc/types.h> ++#include <mmc/mmc.h> ++#include <mmc/ioctl.h> ++ ++#include "types.h" ++#include "mmc.h" ++#include "mmc_pxa.h" ++ ++static mmc_controller_t host = NULL; ++ ++/* service routines */ ++static inline int pxa_mmc_check_state( mmc_controller_t ctrlr, pxa_mmc_state_t state ) ++{ ++ int ret = -1; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++ if ( hostdata->state != state ) { ++ //MMC_DEBUG( MMC_DEBUG_LEVEL3, "state (%s vs %s)\n", PXA_MMC_STATE_LABEL( hostdata->state ), PXA_MMC_STATE_LABEL( state ) ); ++ goto error; ++ } ++ ret = 0; ++error: ++ return ret; ++} ++ ++static inline void pxa_mmc_set_state( mmc_controller_t ctrlr, pxa_mmc_state_t state ) ++{ ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++ hostdata->state = state; ++} ++ ++static inline int pxa_mmc_init_completion( mmc_controller_t ctrlr, u32 mask ) ++{ ++ int ret = -1; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++ if ( xchg( &hostdata->busy, 1 ) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "another interrupt " ++ "is already been expected\n" ); ++ goto error; ++ } ++ ++#if CONFIG_MMC_DEBUG_IRQ ++ hostdata->irqcnt = 1000; ++#endif ++ init_completion( &hostdata->completion ); ++ ++ MMC_I_MASK = MMC_I_MASK_ALL & ~mask; ++ ret = 0; ++error: ++ return ret; ++} ++ ++#if CONFIG_MMC_DEBUG_IRQ ++static struct timer_list timer; ++static void wait_timeo( unsigned long arg ) { ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)arg; ++ hostdata->timeo = 1; ++ complete( &hostdata->completion ); ++ return; ++} ++#endif ++ ++static inline int pxa_mmc_wait_for_completion( mmc_controller_t ctrlr, u32 mask ) ++{ ++ int ret = -1; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++ if ( !xchg( &hostdata->busy, 1 ) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "there were no " ++ "interrupt awaited for\n" ); ++ goto error; ++ } ++ ++#if CONFIG_MMC_DEBUG_IRQ ++ hostdata->timeo = 0; ++ del_timer( &timer ); ++ timer.function = wait_timeo; ++ timer.expires = jiffies + 1UL*HZ; ++ timer.data = (unsigned long)hostdata; ++ add_timer( &timer ); ++#endif ++ wait_for_completion( &hostdata->completion ); ++#if CONFIG_MMC_DEBUG_IRQ ++ del_timer( &timer ); ++ if ( hostdata->timeo ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "irq timed out: " "mask=%x stat=%x\n", mask, MMC_STAT ); ++ goto error; ++ } ++#endif ++ /* verify interrupt */ ++ if ( (mask == ~0UL) || !( hostdata->mmc_i_reg & ~mask ) ) ++ ret = 0; ++ ++error: ++ xchg( &hostdata->busy, 0 ); ++ return ret; ++} ++ ++static inline int pxa_mmc_stop_bus_clock( mmc_controller_t ctrlr ) ++{ ++ int ret = -1; ++ ++ if ( !pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_CLK_OFF ) ) ++ goto out; ++ ++ if ( !pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_BUFFER_IN_TRANSIT ) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "BUFFER_IN_TRANSIT\n" ); ++ goto error; ++ } ++ ++ if ( pxa_mmc_init_completion( ctrlr, MMC_I_MASK_CLK_IS_OFF ) ) ++ goto error; ++ ++ MMC_STRPCL = MMC_STRPCL_STOP_CLK; ++ ++ if ( pxa_mmc_wait_for_completion( ctrlr, MMC_I_REG_CLK_IS_OFF ) ) ++ goto error; ++ ++ //MMC_DEBUG( MMC_DEBUG_LEVEL3, "clock is off\n" ); ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_CLK_OFF ); ++out: ++ ret = 0; ++error: ++ return ret; ++} ++ ++static inline int pxa_mmc_start_bus_clock( mmc_controller_t ctrlr ) ++{ ++ int ret = -1; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++ if ( (hostdata->state != PXA_MMC_FSM_CLK_OFF) ++ && (hostdata->state != PXA_MMC_FSM_END_IO) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "illegal state %s\n", PXA_MMC_STATE_LABEL( hostdata->state ) ); ++ goto error; ++ } ++ ++ MMC_STRPCL = MMC_STRPCL_START_CLK; ++ wmb(); ++ //MMC_DEBUG( MMC_DEBUG_LEVEL3, "clock is on\n" ); ++ ret = 0; ++error: ++ return ret; ++} ++ ++/* ++int pxa_mmc_complete_cmd( mmc_controller_t ctrlr, mmc_response_fmt_t response ) ++ ++Effects: initializes completion to wait for END_CMD_RES intr, ++ waits for intr to occur, checks controller and card status ++Requiers: controller is in CLK_OFF state ++Modifies: moves controller to the END_CMD state ++Returns: ++*/ ++static mmc_error_t pxa_mmc_complete_cmd( mmc_controller_t ctrlr, mmc_response_fmt_t format, int send_abort ) ++{ ++ mmc_error_t ret = MMC_ERROR_GENERIC; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ int mask, nwords; ++ u32 status; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD%d(0x%04x%04x)\n", MMC_CMD & 0x3f, MMC_ARGH, MMC_ARGL); ++ ++/* FIXME: check arguments */ ++ ++ if ( (hostdata->state != PXA_MMC_FSM_CLK_OFF) ++ && (hostdata->state != PXA_MMC_FSM_END_IO) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "illegal state %s\n", ++ PXA_MMC_STATE_LABEL( hostdata->state ) ); ++ goto error; ++ } ++ ++ mask = MMC_I_MASK_END_CMD_RES; ++ if ( pxa_mmc_init_completion( ctrlr, mask ) ) ++ goto error; ++ ++ MMC_PRTBUF = MMC_PRTBUF_BUF_FULL; ++/* start the clock */ ++ if ( pxa_mmc_start_bus_clock( ctrlr ) ) ++ goto error; ++ ++/* wait for END_CMD_RES intr */ ++ if ( pxa_mmc_wait_for_completion( ctrlr, MMC_I_REG_END_CMD_RES ) ) ++ goto error; ++ ++/* check status */ ++ if ( hostdata->mmc_stat & MMC_STAT_TIME_OUT_RESPONSE ) { ++ // MMC_DEBUG(MMC_DEBUG_LEVEL3, "response timeout\n"); ++ ret = MMC_ERROR_TIME_OUT_RESPONSE; ++ goto error; ++ ++ } else if ( hostdata->mmc_stat & MMC_STAT_READ_TIME_OUT ) { ++ // MMC_DEBUG(MMC_DEBUG_LEVEL3, "read timeout\n"); ++ ret = MMC_ERROR_READ_TIME_OUT; ++ goto error; ++ ++ } else if ( hostdata->mmc_stat & MMC_STAT_RES_CRC_ERROR ) { ++ // MMC_DEBUG(MMC_DEBUG_LEVEL3, "response crc err\n"); ++ ret = MMC_ERROR_RES_CRC_ERROR; ++ goto error; ++ ++ } else if ( hostdata->mmc_stat & MMC_STAT_CRC_READ_ERROR ) { ++ // MMC_DEBUG(MMC_DEBUG_LEVEL3, "read crc err\n"); ++ ret = MMC_ERROR_CRC_READ_ERROR; ++ goto error; ++ ++ } else if ( hostdata->mmc_stat & MMC_STAT_CRC_WRITE_ERROR ) { ++ // MMC_DEBUG(MMC_DEBUG_LEVEL3, "write crc err\n"); ++ ret = MMC_ERROR_CRC_WRITE_ERROR; ++ goto error; ++ } ++ ++ nwords = (format == MMC_NORESPONSE) ? 0 : ++ (format == MMC_R1) ? 3 : ++ (format == MMC_R2) ? 8 : ++ (format == MMC_R3) ? 3 : ++ -1; ++ ret = nwords; ++ if ( nwords > 0 ) { ++ register int i; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "nwords=%d\n", nwords ); ++ for ( i = nwords - 1; i >= 0 ; i-- ) { ++ u32 res = MMC_RES; ++ int ibase = i<<1; ++ ++ hostdata->mmc_res[ibase] = ((u8 *)&res)[0]; ++ hostdata->mmc_res[ibase + 1] = ((u8 *)&res)[1]; ++ --ret; ++ } ++#ifdef CONFIG_MMC_DEBUG ++ switch ( format ) { ++ case MMC_R1: ++ MMC_DUMP_R1( ctrlr ); ++ break; ++ case MMC_R2: ++ MMC_DUMP_R2( ctrlr ); ++ break; ++ case MMC_R3: ++ MMC_DUMP_R3( ctrlr ); ++ break; ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, ++ "unknown response format\n" ); ++ ret = MMC_ERROR_GENERIC; ++ goto error; ++ } ++#endif ++ ++/* check card status for R1(b) commands */ ++ if ( format == MMC_R1 ) { ++ u8 cmd; ++ ++ ((u8 *)&status)[0] = hostdata->mmc_res[1]; ++ ((u8 *)&status)[1] = hostdata->mmc_res[2]; ++ ((u8 *)&status)[2] = hostdata->mmc_res[3]; ++ ((u8 *)&status)[3] = hostdata->mmc_res[4]; ++ cmd = PXA_MMC_RESPONSE( ctrlr, 5 )&0x3f; ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, ++ //printk( KERN_INFO __FUNCTION__"(): " ++ "cmd=%u status: 0x%08x\n", ++ cmd, status ); ++ switch ( cmd ) { ++ case 11: ++ case 18: ++ case 20: ++ case 25: ++ if ( !(status & 0x00000100) ) /* FIXME */ ++ goto mmc_error; ++ default: ++ break; ++ } ++ if ( status & MMC_CARD_STATUS_OUT_OF_RANGE ) { ++ ret = MMC_ERROR_OUT_OF_RANGE; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_ADDRESS_ERROR ) { ++ ret = MMC_ERROR_ADDRESS_ERROR; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_BLOCK_LEN_ERROR ) { ++ ret = MMC_ERROR_ADDRESS_ERROR; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_ERASE_SEQ_ERROR ) { ++ ret = MMC_ERROR_ERASE_SEQ_ERROR; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_ERASE_PARAM ) { ++ ret = MMC_ERROR_ERASE_PARAM; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_WP_VIOLATION ) { ++ ret = MMC_ERROR_WP_VIOLATION; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_CARD_IS_LOCKED ) { ++ ret = MMC_ERROR_CARD_IS_LOCKED; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_LOCK_UNLOCK_FAILED ) { ++ ret = MMC_ERROR_LOCK_UNLOCK_FAILED; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_COM_CRC_ERROR ) { ++ ret = MMC_ERROR_COM_CRC_ERROR; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_ILLEGAL_COMMAND ) { ++ ret = MMC_ERROR_ILLEGAL_COMMAND; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_CARD_ECC_FAILED ) { ++ ret = MMC_ERROR_CARD_ECC_FAILED; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_CC_ERROR ) { ++ ret = MMC_ERROR_CC_ERROR; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_ERROR ) { ++ ret = MMC_ERROR_ERROR; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_UNDERRUN ) { ++ ret = MMC_ERROR_UNDERRUN; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_OVERRUN ) { ++ ret = MMC_ERROR_OVERRUN; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_CID_CSD_OVERWRITE ) { ++ ret = MMC_ERROR_CID_CSD_OVERWRITE; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_ERASE_RESET ) { ++ ret = MMC_ERROR_ERASE_RESET; ++ goto mmc_error; ++ } ++ } ++ } ++ ++ if ( ret >= 0 ) ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_CMD ); ++ goto out; ++mmc_error: ++#if 1 ++ if ( send_abort ) { ++ /* send CMD12 to abort failed transfer */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(12); /* STOP_TRANSMISSION */ ++ MMC_CMDAT = MMC_CMDAT_R1; ++ ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ ++ ret = -EIO; ++ goto error; ++ } ++#endif ++error: ++ /* move controller to the IDLE state */ ++ pxa_mmc_stop_bus_clock( ctrlr ); ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_IDLE ); ++out: ++ return ret; ++} ++ ++/* ++int pxa_mmc_complete_io( mmc_controller_t ctrlr, mmc_dir_t cmd, mmc_dir_t dir, mmc_transfer_mode_t mode ) ++ ++Effects: finilizes data transfer request ++Reqires: controller is in the END_BUFFER state ++Modifies: moves controller to the IDLE state ++Returns: zero upon success or error condition code otherwise ++ */ ++static mmc_error_t pxa_mmc_complete_io( mmc_controller_t ctrlr, mmc_dir_t dir, mmc_transfer_mode_t mode ) ++{ ++ int ret = MMC_ERROR_GENERIC; ++ ++ if ( pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_END_IO ) ) ++ goto error; ++ ++ switch ( mode ) { ++ case MMC_TRANSFER_MODE_STREAM: /* FIXME */ ++ if ( dir == MMC_WRITE ) { ++ /* 1. wait for STOP_CMD intr */ ++ if ( (ret = pxa_mmc_init_completion( ctrlr, ++ MMC_I_MASK_STOP_CMD )) ) ++ goto error; ++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr, ++ MMC_I_REG_STOP_CMD )) ) ++ goto error; ++ } ++ /* 2. send CMD12 */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(12); /* STOP_TRANSMISSION */ ++ MMC_CMDAT = MMC_CMDAT_R1; ++ if ( dir == MMC_WRITE ) ++ MMC_CMDAT |= MMC_CMDAT_BUSY; ++ ++ /* 3. wait for CMD12 to complete */ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "ready for CMD12\n" ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ ++ /* 4. wait for DATA_TRAN_DONE intr */ ++ if ( (ret = pxa_mmc_init_completion( ctrlr, ++ MMC_I_MASK_DATA_TRAN_DONE )) ) ++ goto error; ++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr, ++ MMC_I_REG_DATA_TRAN_DONE )) ) ++ goto error; ++ ++ if ( dir == MMC_WRITE ) { ++ /* 5. wait for PRG_DONE intr */ ++ if ( (ret = pxa_mmc_init_completion( ctrlr, ++ MMC_I_MASK_PRG_DONE )) ) ++ goto error; ++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr, ++ MMC_I_REG_PRG_DONE )) ) ++ goto error; ++ } ++ break; ++ case MMC_TRANSFER_MODE_BLOCK_MULTIPLE: ++ /* 1. wait for DATA_TRAN done intr */ ++ if ( (ret = pxa_mmc_init_completion( ctrlr, ++ MMC_I_MASK_DATA_TRAN_DONE )) ) ++ goto error; ++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr, ++ MMC_I_REG_DATA_TRAN_DONE )) ) ++ goto error; ++ ++ /* 2. send CMD12 */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(12); /* STOP_TRANSMISSION */ ++ MMC_CMDAT = MMC_CMDAT_R1; ++ if ( dir == MMC_WRITE ) ++ MMC_CMDAT |= MMC_CMDAT_BUSY; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD12\n" ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ ++ if ( dir == MMC_WRITE ) { ++ /* 3. wait for PRG_DONE intr */ ++ if ( (ret = pxa_mmc_init_completion( ctrlr, ++ MMC_I_MASK_PRG_DONE )) ) ++ goto error; ++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr, ++ MMC_I_REG_PRG_DONE )) ) ++ goto error; ++ } ++ break; ++ case MMC_TRANSFER_MODE_BLOCK_SINGLE: ++ /* 1. wait for DATA_TRAN_DONE intr */ ++ if ( (ret = pxa_mmc_init_completion( ctrlr, ++ MMC_I_MASK_DATA_TRAN_DONE )) ) ++ goto error; ++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr, ++ MMC_I_REG_DATA_TRAN_DONE )) ) ++ goto error; ++ ++ if ( dir == MMC_WRITE ) { ++ /* 2. wait for PRG_DONE intr */ ++ if ( (ret = pxa_mmc_init_completion( ctrlr, ++ MMC_I_MASK_PRG_DONE )) ) ++ goto error; ++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr, ++ MMC_I_REG_PRG_DONE )) ) ++ goto error; ++ } ++ break; ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "unknown transfer mode\n" ); ++ goto error; ++ } ++/* move the controller to the IDLE state */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_IDLE ); ++ ++ ret = 0; ++error: ++ return ret; ++} ++ ++static inline int pxa_mmc_update_acq( mmc_controller_t ctrlr ) ++{ ++ int ret = -EINVAL; ++ pxa_mmc_hostdata_t hostdata = NULL; ++ mmc_card_t card = NULL; ++ mmc_card_stack_rec_t fake; ++ mmc_card_stack_t stack = &fake; ++ u16 argl = 0U, argh = 0U; ++ int ncards = 0; ++ ++ if ( !ctrlr ) ++ goto error; ++ ++ hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++ __mmc_card_stack_init( stack ); ++ ++ /* max open-drain mode frequency is 400kHZ */ ++ MMC_CLKRT = MMC_CLKRT_0_3125MHZ; ++ MMC_RESTO = MMC_RES_TO_MAX; /* set response timeout */ ++ ++ /* discover and add cards to the stack */ ++ /* I. bus operation condition setup */ ++ /* 1) send CMD1 */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto err_free; ++ ++ argl = 0x0000; ++ argh = 0x0004; ++ ++ MMC_CMD = CMD(1); ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ ++ MMC_CMDAT = MMC_CMDAT_BUSY|MMC_CMDAT_R3; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD1(0x%04x%04x)\n", argh, argl ); ++ ret = pxa_mmc_complete_cmd( ctrlr, MMC_R3, FALSE ); ++ if ( !ret ) { ++ argh = (PXA_MMC_RESPONSE( ctrlr, 4 ) << 8) ++ | PXA_MMC_RESPONSE( ctrlr, 3 ); ++ argl = (PXA_MMC_RESPONSE( ctrlr, 2 ) << 8) ++ | PXA_MMC_RESPONSE( ctrlr, 1 ); ++ ++ } else if ( ret != MMC_ERROR_TIME_OUT_RESPONSE ) ++ goto err_free; ++ ++ if ( !argh && !argl ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, ++ "assuming full voltage range support\n" ); ++ argh = 0x00ff; ++ argl = 0xff00; ++ } ++ ++ /* 2) continuously send CMD1 'till there're busy cards */ ++ for(;;) { ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto err_free; ++ ++ MMC_CMD = CMD(1); ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ ++ MMC_CMDAT = MMC_CMDAT_BUSY|MMC_CMDAT_R3; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD1(0x%04x%04x)\n", argh, argl ); ++ ret = pxa_mmc_complete_cmd( ctrlr, MMC_R3, FALSE ); ++ if ( ret == MMC_ERROR_TIME_OUT_RESPONSE ) ++ break; ++ ++ else if ( !ret ) { ++ /* busy state reported by LOW signal level ++ * (MMC v3.2, p.58) ++ * ++ * Thanks to Alexander Samoutin :) ++ */ ++ if ( !(PXA_MMC_RESPONSE( ctrlr, 4 ) & 0x80) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "busy state reported\n"); ++ udelay( 20 ); ++ continue; ++ } else ++ break; ++ } else ++ goto err_free; ++ } ++ ++/* II. card identification: the cards in Ready state ++ * are the only expected to respond ++ */ ++ for (;;) { ++ argh = 0U; ++ argl = 0U; ++ ++ /* 1) send CMD2 */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto err_free; ++ ++ MMC_CMD = CMD(2); ++ MMC_ARGH = 0x0003; ++ MMC_ARGL = 0xf300; ++ MMC_CMDAT = MMC_CMDAT_R2; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD2(0x%04x%04x)\n", argh, argl ); ++ ret = pxa_mmc_complete_cmd( ctrlr, MMC_R2, FALSE ); ++ if ( ret == MMC_ERROR_TIME_OUT_RESPONSE ) ++ break; ++ ++ else if ( ret ) /* bus error */ ++ goto err_free; ++ ++ /* TODO: store CID for the card */ ++ ++ /* 2) assign RCA */ ++ if ( !++ctrlr->rca_next ) /* overflow */ ++ ++ctrlr->rca_next; ++ argh = ctrlr->rca_next; ++ ++ /* 3) send it to the card last responded (CMD3) */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto err_free; ++ ++ MMC_CMD = CMD(3); ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_R1; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD3(0x%04x%04x)\n", argh, argl ); ++ ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE ); ++ if ( ret ) /* CMD3 failed */ ++ goto err_free; ++ ++ card = __mmc_card_alloc( sizeof( pxa_mmc_card_data_rec_t ) ); ++ if ( !card ) { ++ MMC_ERROR( "out of memory\n" ); ++ goto err_free; ++ } ++ ++ card->info.rca = argh; ++ card->slot = ctrlr->slot_next++; /* FIXME: minor encoding */ ++ card->ctrlr = ctrlr; ++ ++ if ( !__mmc_card_stack_add( stack, card ) ) ++ goto err_free; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "added card: " ++ "slot %d, RCA=0x%04x\n", card->slot, argh ); ++ ++ncards; ++ } ++ ++ if ( ncards ) { ++/* III. read CSD registers of all cards; DSR support also reported there */ ++ for ( card = stack->first; card; card = card->next ) { ++ pxa_mmc_card_data_t card_data = ++ (pxa_mmc_card_data_t)card->card_data; ++ ++ /* 1) send CMD9 */ ++ argh = card->info.rca; ++ argl = 0U; ++ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto err_free; ++ ++ MMC_CMD = CMD(9); ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_R2; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, ++ "CMD9(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R2, FALSE )) ) ++ goto err_free; ++ ++ memcpy( &card->info.csd, hostdata->mmc_res, 15 ); ++ MMC_DUMP_CSD( card ); ++ ++ card->info.read_bl_len = (1<<card->info.csd.read_bl_len); ++ card->info.write_bl_len = (1<<card->info.csd.write_bl_len); ++ card->info.capacity = (card->info.csd.c_size + 1) ++ * (1<<(card->info.csd.c_size_mult + 2)) ++ * card->info.read_bl_len; ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "card capacity=%dMb\n", ++ card->info.capacity>>20 ); ++ card->info.tran_speed = 20*1024; /* FIXME */ ++ card->info.transfer_mode = MMC_TRANSFER_MODE_BLOCK_SINGLE; ++ /* 2) set bus operation freq */ ++ card_data->clkrt = pxa_mmc_clkrt( card->info.tran_speed ); ++ /* 3) register card with MMC core */ ++ mmc_register( MMC_REG_TYPE_CARD, card, 0 ); ++ } ++/* IV. set DSR registers of the cards */ ++#if 0 /* TODO */ ++ if ( card->info.csd.dsr_imp ) { ++ set_dsr = TRUE; ++ /* calculate DSR */ ++ } ++#endif ++ } ++#if 0 /* TODO */ ++ if ( set_dsr ) { ++ /* send CMD4 */ ++ } ++#endif ++/* merge list of the newly inserted cards into controller card stack */ ++ if ( !ctrlr->stack.ncards ) { ++ ctrlr->stack.first = stack->first; ++ ctrlr->stack.last = stack->last; ++ } else ++ ctrlr->stack.last->next = stack->first; ++ ++ ctrlr->stack.ncards += stack->ncards; ++ ++ ret = 0; ++ goto out; ++err_free: ++ __mmc_card_stack_free( stack ); ++error: ++out: ++ return ret; ++} ++ ++/* MMC protocol macros: v3.4, p.120 */ ++static int pxa_mmc_init_card_stack( mmc_controller_t ctrlr ) ++{ ++ int ret = -EIO; ++ u16 argl = 0U, argh = 0U; ++ ++ if ( !ctrlr || ctrlr->stack.ncards ) { ++ ret = -EINVAL; ++ goto error; ++ } ++ ++ /* initialize stack */ ++ /* 1) send CMD0 */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ /* max open-drain mode frequency is 400kHZ */ ++ MMC_CLKRT = MMC_CLKRT_0_3125MHZ; ++ MMC_RESTO = MMC_RES_TO_MAX; /* set response timeout */ ++ MMC_SPI = MMC_SPI_DISABLE; ++ ++ MMC_CMD = CMD(0); /* CMD0 with zero argument */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_INIT; ++ ++ //MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD0(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_NORESPONSE, FALSE )) ) ++ goto error; ++ ++ /* update card stack */ ++ if ( (ret = pxa_mmc_update_acq( ctrlr )) ) ++ goto err_free; ++ ++ /* move the controller to the IDLE state */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto err_free; ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_IDLE ); ++ ++ ret = 0; ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "ncards=%d\n", ctrlr->stack.ncards ); ++ goto out; ++ ++err_free: ++ __mmc_card_stack_free( &ctrlr->stack ); ++error: ++out: ++ return ret; ++} ++ ++static int pxa_mmc_check_card_stack( mmc_controller_t ctrlr ) ++{ ++ int ret = -1; ++ mmc_card_t card; ++ ++ if ( !ctrlr ) ++ goto error; ++ ++ if ( ctrlr->stack.ncards > 0 ) { ++/* for each card in the stack: */ ++ for( card = ctrlr->stack.first; card; card = card->next ) { ++ u16 argh = card->info.rca; ++ u16 argl = 0UL; ++ ++/* 1) send CMD9( card->rca ) */ ++ if ( pxa_mmc_stop_bus_clock( ctrlr ) ) ++ goto error; ++ ++ /* SanDisk's cards do not respond to CMD9 */ ++ MMC_CMD = CMD(13); ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_R1; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD13(0x%04x%04x)\n", ++ argh, argl ); ++ ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE ); ++/* 2) if card responded, it is still there */ ++ if ( ret ) ++ card->state = MMC_CARD_STATE_UNPLUGGED; ++ } ++ } ++ ret = 0; ++error: ++ return ret; ++} ++ ++/* This procedure links the bus master with a single card ++ * 1) cross checks with the internal stack management data if a card still ++ * exists in the slot ++ * 2) send CMD7( card->public.rca ) ++ * 3) setup data path and controller options ++ */ ++static int pxa_mmc_setup_card( mmc_controller_t ctrlr, mmc_card_t card ) ++{ ++ int ret = -ENODEV; ++ pxa_mmc_hostdata_t hostdata; ++ pxa_mmc_card_data_t card_data; ++ u16 argh = 0U; ++#ifdef CONFIG_MMC_DEBUG ++ u16 argl = 0U; ++#endif ++ ++ if ( !ctrlr || !card ) { ++ ret = -EINVAL; ++ goto error; ++ } ++ ++ if ( card->ctrlr != ctrlr ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "card is on another bus\n" ); ++ goto error; ++ } ++ ++ hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ card_data = (pxa_mmc_card_data_t)card->card_data; ++ ++ argh = card->info.rca; ++ ++/* select requested card */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(7); ++ MMC_ARGH = argh; ++ MMC_CMDAT = MMC_CMDAT_R1; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD7(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ ++/* set controller options */ ++#ifndef CONFIG_MMC_DEBUG ++ MMC_CLKRT = card_data->clkrt; ++#endif ++/* move the controller to the IDLE state */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_IDLE ); ++ ++ ret = 0; ++error: ++ return ret; ++} ++ ++static inline int pxa_mmc_iobuf_init( mmc_controller_t ctrlr, ssize_t cnt ) ++{ ++#ifdef PIO ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++#endif ++#ifndef PIO ++/* TODO */ ++#else ++ hostdata->iobuf.buf.pos = hostdata->iobuf.iodata; ++ hostdata->iobuf.buf.cnt = cnt; ++#endif ++ return 0; ++} ++/* TODO: ssize_t pxa_mmc_read_buffer( mmc_controller_t ctrlr, ssize_t cnt ) ++effects: reads at most cnt bytes from the card to the controller I/O buffer; ++ takes care of partial data transfers ++requieres: ++modifies: ctrlr->iobuf ++returns: number of bytes actually transferred or negative error code if there were any errors ++ */ ++ssize_t pxa_mmc_read_buffer( mmc_controller_t ctrlr, ssize_t cnt ) ++{ ++ ssize_t ret = -EIO; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++#ifndef PIO ++ register int ndesc; ++ int chan = hostdata->iobuf.buf.chan; ++ pxa_dma_desc *desc; ++#endif ++ ++ if ( (hostdata->state != PXA_MMC_FSM_END_CMD) && (hostdata->state != PXA_MMC_FSM_END_BUFFER) ) { ++ goto error; ++ } ++ ++ if ( cnt > hostdata->iobuf.bufsz ) ++ cnt = hostdata->iobuf.bufsz; ++ ++ if ( (ret = pxa_mmc_iobuf_init( ctrlr, cnt )) ) ++ goto error; ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_BUFFER_IN_TRANSIT ); ++#ifndef PIO ++ if ( pxa_mmc_init_completion( ctrlr, ~MMC_I_MASK_ALL ) ) /* FIXME */ ++ goto error; ++ ++ if ( (desc = hostdata->iobuf.buf.last_read_desc) ) { ++ desc->ddadr &= ~DDADR_STOP; ++ desc->dcmd &= ~(DCMD_ENDIRQEN|DCMD_LENGTH); ++ desc->dcmd |= (1<<5); ++ } ++/* 1) setup descriptors for DMA transfer from the device */ ++ ndesc = (cnt>>5) - 1; /* FIXME: partial read */ ++ desc = &hostdata->iobuf.buf.read_desc[ndesc]; ++ hostdata->iobuf.buf.last_read_desc = desc; ++ /* TODO: partial read */ ++ desc->ddadr |= DDADR_STOP; ++ desc->dcmd |= DCMD_ENDIRQEN; ++/* 2) start DMA channel */ ++ DDADR( chan ) = hostdata->iobuf.buf.read_desc_phys_addr; ++ DCSR( chan ) |= DCSR_RUN; ++#else ++ if ( pxa_mmc_init_completion( ctrlr, MMC_I_MASK_RXFIFO_RD_REQ ) ) ++ goto error; ++#endif ++ ++ if ( pxa_mmc_wait_for_completion( ctrlr, ~0UL ) ) ++ goto error; ++ ++ if ( pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_END_BUFFER ) ) ++ goto error; ++ ++ if ( !(hostdata->mmc_stat & MMC_STAT_ERRORS) ) /* FIXME */ ++ ret = cnt; ++error: ++ return ret; ++} ++ ++ssize_t pxa_mmc_write_buffer( mmc_controller_t ctrlr, ssize_t cnt ) ++{ ++ ssize_t ret = -EIO; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++#ifndef PIO ++ register int ndesc; ++ int chan = hostdata->iobuf.buf.chan; ++ pxa_dma_desc *desc; ++#endif ++ ++ if ( (hostdata->state != PXA_MMC_FSM_END_CMD) ++ && (hostdata->state != PXA_MMC_FSM_END_BUFFER) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "unexpected state (%s)\n", ++ PXA_MMC_STATE_LABEL( hostdata->state ) ); ++ goto error; ++ } ++ ++ if ( cnt > hostdata->iobuf.bufsz ) ++ cnt = hostdata->iobuf.bufsz; ++ ++ if ( (ret = pxa_mmc_iobuf_init( ctrlr, cnt )) ) ++ goto error; ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_BUFFER_IN_TRANSIT ); ++#ifndef PIO ++ if ( pxa_mmc_init_completion( ctrlr, ~MMC_I_MASK_ALL ) ) /* FIXME */ ++ goto error; ++ if ( (desc = hostdata->iobuf.buf.last_write_desc) ) { ++ desc->ddadr &= ~DDADR_STOP; ++ desc->dcmd &= ~(DCMD_ENDIRQEN|DCMD_LENGTH); ++ desc->dcmd |= (1<<5); ++ } ++/* 1) setup descriptors for DMA transfer to the device */ ++ ndesc = (cnt>>5) - 1; /* FIXME: partial write */ ++ desc = &hostdata->iobuf.buf.write_desc[ndesc]; ++ /* TODO: partial write */ ++ hostdata->iobuf.buf.last_write_desc = desc; ++ desc->ddadr |= DDADR_STOP; ++ desc->dcmd |= DCMD_ENDIRQEN; ++/* 2) start DMA channel */ ++ DDADR( chan ) = hostdata->iobuf.buf.write_desc_phys_addr; ++ DCSR( chan ) |= DCSR_RUN; ++#else ++ if ( pxa_mmc_init_completion( ctrlr, MMC_I_MASK_TXFIFO_WR_REQ ) ) ++ goto error; ++#endif ++ if ( pxa_mmc_wait_for_completion( ctrlr, ~0UL ) ) ++ goto error; ++ ++ if ( pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_END_BUFFER ) ) ++ goto error; ++ ++ if ( !(hostdata->mmc_stat & MMC_STAT_ERRORS) ) /* FIXME */ ++ ret = cnt; ++error: ++ return ret; ++} ++ ++/* TODO: ssize_t pxa_mmc_copy_from_buffer( ctrlr, mmc_buftype_t to, char *buf, ssize_t cnt ) ++effects: copies at most cnt bytes from the controller I/O buffer to the user or kernel buffer ++ pointed by buf ++requiers: ++modifies: ++returns: number of bytes actually transferred or negative error code if there were any errors ++ */ ++ssize_t pxa_mmc_copy_from_buffer( mmc_controller_t ctrlr, mmc_buftype_t to, char *buf, ssize_t cnt ) ++{ ++ ssize_t ret = -EIO; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++#ifndef PIO ++/* TODO: check that DMA channel is not running */ ++#endif ++ switch ( to ) { ++ case MMC_USER: ++ if ( copy_to_user( buf, hostdata->iobuf.iodata, cnt ) ) { ++ ret = -EFAULT; ++ goto error; ++ } ++ break; ++ case MMC_KERNEL: ++ memcpy( buf, hostdata->iobuf.iodata, cnt ); ++ break; ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "unknown buffer type\n" ); ++ goto error; ++ } ++ ret = cnt; ++error: ++ return ret; ++} ++ ++ssize_t pxa_mmc_copy_to_buffer( mmc_controller_t ctrlr, mmc_buftype_t to, char *buf, ssize_t cnt ) ++{ ++ ssize_t ret = -EIO; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++#ifndef PIO ++/* check that DMA channel is not running */ ++#endif ++ switch ( to ) { ++ case MMC_USER: ++ if ( copy_from_user( hostdata->iobuf.iodata, buf, cnt ) ) { ++ ret = -EFAULT; ++ goto error; ++ } ++ break; ++ case MMC_KERNEL: ++ memcpy( hostdata->iobuf.iodata, buf, cnt ); ++ break; ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "unknown buffer type\n" ); ++ goto error; ++ } ++ ret = cnt; ++error: ++ return ret; ++} ++ ++/* This procedure sequentally passes the data from the user buffer to the card */ ++static int pxa_mmc_stream_read( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer ) ++{ ++ int ret = -EIO; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ u16 argh = 0UL, argl = 0UL; ++ ssize_t size = 0; ++ ++ while ( transfer->cnt > 0 ) { ++ size = (transfer->cnt < hostdata->iobuf.blksz) ? ++ transfer->cnt : hostdata->iobuf.blksz; ++ /* 1. send CMD11 */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ argh = transfer->addr >> 16; ++ argl = transfer->addr; ++ /* 2. setup controller registers to start stream data transfer */ ++ MMC_CMD = CMD(11); /* READ_DAT_UNTIL_STOP */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_NOB = 0xffff; ++ MMC_BLKLEN = size; ++ MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_READ|MMC_CMDAT_STREAM|MMC_CMDAT_DATA_EN; ++#ifndef PIO ++ MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; ++#endif ++ /* 3. wait for cmd to complete */ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD11(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, TRUE )) ) ++ goto error; ++ ++ /* 4. transfer the data to the caller supplied buffer */ ++ if ( (ret = pxa_mmc_read_buffer( ctrlr, size )) < 0 ) ++ goto error; ++ ++ if ( (ret = pxa_mmc_copy_from_buffer( ctrlr, transfer->type, transfer->buf, ret )) < 0 ) ++ goto error; ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO ); ++ ++ if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) ) ++ goto error; ++ ++ transfer->buf += ret; ++ transfer->addr += ret; ++ transfer->cnt -= ret; ++ } ++ ret = 0; ++error: ++ return ret; ++} ++ ++/* This procedure reads a data block from a card at a given kernel address */ ++static int pxa_mmc_read_block( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer ) ++{ ++ int ret = -ENODEV; ++ u16 argh = 0UL, argl = 0UL; ++ ++/* send CMD16 (SET_BLOCK_LEN) when requested block size is not the default ++ * for the current card */ ++ if ( transfer->blksz != ctrlr->stack.selected->info.read_bl_len ) { ++ argh = transfer->blksz >> 16; ++ argl = transfer->blksz; ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(16); /* SET_BLOCK_LEN */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_R1; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, ++ "CMD16(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ } ++ ++/* CMD17 (READ_SINGLE_BLOCK) */ ++ argh = transfer->addr >> 16; ++ argl = transfer->addr; ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(17); /* READ_SINGLE_BLOCK */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_READ|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN; ++ MMC_NOB = 1; ++ MMC_BLKLEN = transfer->blksz; ++#ifndef PIO ++ MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; ++#endif ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD17(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ ++/* transfer the data to the caller supplied buffer */ ++ if ( (ret = pxa_mmc_read_buffer( ctrlr, transfer->blksz )) < 0 ) ++ goto error; ++ ++ if ( (ret = pxa_mmc_copy_from_buffer( ctrlr, transfer->type, transfer->buf, ret )) < 0 ) ++ goto error; ++ ++ transfer->buf += ret; ++ transfer->cnt -= ret; ++ transfer->nob -= 1; ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO ); ++ ++ if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) ) ++ goto error; ++ ++ ret = 0; ++error: ++ return ret; ++} ++ ++/* This procedure sequentally reads data blocks from ++ * a card to the user buffer. Controller options and block size ++ * are already set by setup_card(). Data alignment and partial ++ * data accessibility assumed to be checked by mmc_core */ ++static int pxa_mmc_read_mblock( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer ) ++{ ++ int ret = -EIO; ++ u16 argh = 0UL, argl = 0UL; ++ ++/* send CMD16 (SET_BLOCK_LEN) when requested block size is not the default ++ * for the current card */ ++ if ( transfer->blksz != ctrlr->stack.selected->info.read_bl_len ) { ++ argh = transfer->blksz >> 16; ++ argl = transfer->blksz; ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(16); /* SET_BLOCK_LEN */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_R1; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD16(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ } ++ ++ argh = transfer->addr >> 16; ++ argl = transfer->addr; ++/* 1. stop bus clock */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++/* 2. setup controller registers to start multiple block transfer */ ++ MMC_CMD = CMD(18); /* READ_MULTIPLE_BLOCK */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_NOB = transfer->nob; ++ MMC_BLKLEN = transfer->blksz; ++ MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_READ|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN; ++#ifndef PIO ++ MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; ++#endif ++ ++/* 3. start clock */ ++ if ( (ret = pxa_mmc_start_bus_clock( ctrlr )) ) ++ goto error; ++ ++/* 4. wait for cmd to complete */ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD18(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, TRUE )) ) ++ goto error; ++ ++/* 6. transfer the data to the caller supplied buffer */ ++ while ( transfer->cnt > 0 ) { ++ if ( (ret = pxa_mmc_read_buffer( ctrlr, transfer->cnt )) < 0 ) ++ goto error; ++ ++ if ( (ret = pxa_mmc_copy_from_buffer( ctrlr, transfer->type, transfer->buf, ret )) < 0 ) ++ goto error; ++ ++ transfer->buf += ret; ++ transfer->cnt -= ret; ++ } ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO ); ++ ++ if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) ) ++ goto error; ++ ++ ret = 0; ++error: ++ return ret; ++} ++ ++/* Sequentally writes the data from a user buffer to the card */ ++static int pxa_mmc_stream_write( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer ) ++{ ++ int ret = -EIO; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ u16 argh = 0UL, argl = 0UL; ++ ssize_t size = 0; ++ ++ __ENTER( "transfer: cmd=%d mode=%d type=%d blksz=%d " ++ "nob=%d buf=%p cnt=%d addr=%Lx", transfer->cmd, ++ transfer->mode, transfer->type, transfer->blksz, ++ transfer->nob, transfer->buf, transfer->cnt, transfer->addr ); ++ ++ argh = transfer->addr >> 16; ++ argl = transfer->addr; ++/* 1. stop bus clock */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++/* 2. setup controller registers to start stream data transfer */ ++ MMC_CMD = CMD(20); /* WRITE_DAT_UNTIL_STOP */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_NOB = 0xffff; ++ MMC_BLKLEN = hostdata->iobuf.blksz; ++ MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_STREAM|MMC_CMDAT_DATA_EN; ++#ifndef PIO ++ MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; ++#endif ++ ++/* 3. wait for cmd to complete */ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD20(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, TRUE )) ) ++ goto error; ++ ++/* 4. transfer the data to the caller supplied buffer */ ++ while ( transfer->cnt > 0 ) { ++ size = (transfer->cnt < hostdata->iobuf.blksz) ? ++ transfer->cnt : hostdata->iobuf.blksz; ++ if ( (ret = pxa_mmc_copy_to_buffer( ctrlr, ++ transfer->type, transfer->buf, size )) < 0 ) ++ goto error; ++ ++ if ( (ret = pxa_mmc_write_buffer( ctrlr, ret )) < 0 ) ++ goto error; ++ ++ transfer->buf += ret; ++ transfer->cnt -= ret; ++ } ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO ); ++ ++ if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) ) ++ goto error; ++ ++ ret = 0; ++error: ++ return ret; ++} ++ ++/* This procedure writes a data block to a card at a given address */ ++static int pxa_mmc_write_block( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer ) ++{ ++ int ret = -ENODEV; ++ u16 argh = 0UL, argl = 0UL; ++ ++/* send CMD16 (SET_BLOCK_LEN) when requested block size is not the default ++ * for the current card */ ++ if ( transfer->blksz != ctrlr->stack.selected->info.read_bl_len ) { ++ argh = transfer->blksz >> 16; ++ argl = transfer->blksz; ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(16); /* SET_BLOCK_LEN */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_R1; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD16(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ } ++ ++/* CMD17 (READ_SINGLE_BLOCK) */ ++ argh = transfer->addr >> 16; ++ argl = transfer->addr; ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(24); /* WRITE_BLOCK */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN; ++#ifndef PIO ++ MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; ++#endif ++ MMC_NOB = 1; ++ MMC_BLKLEN = transfer->blksz; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD24(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ ++/* transfer the data to the caller supplied buffer */ ++ if ( (ret = pxa_mmc_copy_to_buffer( ctrlr, transfer->type, transfer->buf, transfer->cnt )) < 0 ) ++ goto error; ++ ++ if ( (ret = pxa_mmc_write_buffer( ctrlr, ret )) < 0 ) ++ goto error; ++ ++ transfer->buf += ret; ++ transfer->cnt -= ret; ++ transfer->nob -= 1; ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO ); ++ ++ if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) ) ++ goto error; ++ ++ ret = 0; ++error: ++ return ret; ++} ++ ++/* This procedure sequentally writes data blocks to a card at a given address */ ++static ssize_t pxa_mmc_write_mblock( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer ) ++{ ++ int ret = -EIO; ++ u16 argh = 0UL, argl = 0UL; ++ ++/* send CMD16 (SET_BLOCK_LEN) when requested block size is not the default ++ * for the current card */ ++ if ( transfer->blksz != ctrlr->stack.selected->info.write_bl_len ) { ++ argh = transfer->blksz >> 16; ++ argl = transfer->blksz; ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(16); /* SET_BLOCK_LEN */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_R1; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD16(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ } ++ ++ argh = transfer->addr >> 16; ++ argl = transfer->addr; ++/* 1. stop bus clock */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++/* 2. setup controller registers to start multiple block transfer */ ++ MMC_CMD = CMD(25); /* WRITE_MULTIPLE_BLOCK */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_NOB = transfer->nob; ++ MMC_BLKLEN = transfer->blksz; ++ MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN; ++#ifndef PIO ++ MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; ++#endif ++ ++/* 3. start clock */ ++ if ( (ret = pxa_mmc_start_bus_clock( ctrlr )) ) ++ goto error; ++ ++/* 4. wait for cmd to complete */ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD25(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, TRUE )) ) ++ goto error; ++ ++/* 6. transfer the data to the caller supplied buffer */ ++ while ( transfer->cnt > 0 ) { ++ if ( (ret = pxa_mmc_copy_to_buffer( ctrlr, transfer->type, ++ transfer->buf, transfer->cnt )) < 0 ) ++ goto error; ++ ++ if ( (ret = pxa_mmc_write_buffer( ctrlr, ret )) < 0 ) ++ goto error; ++ ++ transfer->buf += ret; ++ transfer->cnt -= ret; ++ } ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO ); ++ ++ if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) ) ++ goto error; ++ ++ ret = 0; ++error: ++ return ret; ++} ++ ++static void pxa_mmc_irq( int irq, void *dev_id, struct pt_regs *regs ) ++{ ++ mmc_controller_t ctrlr = (mmc_controller_t)dev_id; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++#ifdef PIO ++ register int i, cnt; ++ register char *buf; ++#endif ++ ++ hostdata->mmc_i_reg = MMC_I_REG; ++ hostdata->mmc_stat = MMC_STAT; ++ hostdata->mmc_cmdat = MMC_CMDAT; ++#if 0 ++ if (hostdata->mmc_i_reg != 0x0010) { ++ printk("IREG %08x", hostdata->mmc_i_reg); ++ if (hostdata->mmc_i_reg & 0x0001) printk(" DATA_TRAN_DONE"); ++ if (hostdata->mmc_i_reg & 0x0002) printk(" PRG_DONE"); ++ if (hostdata->mmc_i_reg & 0x0004) printk(" END_CMD"); ++ if (hostdata->mmc_i_reg & 0x0008) printk(" STOP_CMD"); ++ if (hostdata->mmc_i_reg & 0x0010) printk(" CLK_OFF"); ++ if (hostdata->mmc_i_reg & 0x0020) printk(" RX_FIFO"); ++ if (hostdata->mmc_i_reg & 0x0040) printk(" TX_FIFO"); ++ printk("\nSTAT %08x", hostdata->mmc_stat); ++ if (hostdata->mmc_stat & 0x0001) printk(" READ_TO"); ++ if (hostdata->mmc_stat & 0x0002) printk(" RESP_TO"); ++ if (hostdata->mmc_stat & 0x0004) printk(" WR_CRC"); ++ if (hostdata->mmc_stat & 0x0008) printk(" READ_CRC"); ++ if (hostdata->mmc_stat & 0x0010) printk(" SPI_RD_TKN"); ++ if (hostdata->mmc_stat & 0x0020) printk(" RESP_CRC"); ++ if (hostdata->mmc_stat & 0x0040) printk(" TX_FIFO"); ++ if (hostdata->mmc_stat & 0x0080) printk(" RX_FIFO"); ++ if (hostdata->mmc_stat & 0x0100) printk(" CLK"); ++ if (hostdata->mmc_stat & 0x0800) printk(" DATA_TRAN_DONE"); ++ if (hostdata->mmc_stat & 0x1000) printk(" PRG_DONE"); ++ if (hostdata->mmc_stat & 0x2000) printk(" END_CMD"); ++ printk("\n"); ++ } ++#endif ++ ++#if CONFIG_MMC_DEBUG_IRQ ++ if ( --hostdata->irqcnt <= 0 ) { ++ printk( KERN_INFO __FUNCTION__"(): irqcnt exceeded\n" ); ++ goto complete; ++ } ++#endif ++ switch ( hostdata->state ) { ++ case PXA_MMC_FSM_IDLE: ++ case PXA_MMC_FSM_CLK_OFF: ++ case PXA_MMC_FSM_END_IO: ++ case PXA_MMC_FSM_END_BUFFER: ++ case PXA_MMC_FSM_END_CMD: ++ goto complete; ++#ifdef PIO ++ case PXA_MMC_FSM_BUFFER_IN_TRANSIT: ++ if ( hostdata->mmc_stat & MMC_STAT_ERRORS ) ++ goto complete; ++ ++ buf = hostdata->iobuf.buf.pos; ++ cnt = (hostdata->iobuf.buf.cnt < 32) ? ++ hostdata->iobuf.buf.cnt : 32; ++ if ( hostdata->mmc_cmdat & MMC_CMDAT_WRITE ) { ++ if ( !(hostdata->mmc_stat & MMC_STAT_XMIT_FIFO_EMPTY) ) ++ break; ++ for ( i = 0; i < cnt; i++ ) ++ MMC_TXFIFO = *buf++; ++ if ( cnt < 32 ) ++ MMC_PRTBUF = MMC_PRTBUF_BUF_PART_FULL; ++ } else { /* i.e. MMC_CMDAT_READ */ ++ if( !(hostdata->mmc_stat & MMC_STAT_RECV_FIFO_FULL) ) ++ break; ++ for( i = 0; i < cnt; i++ ) ++ *buf++ = MMC_RXFIFO; ++ } ++ ++ hostdata->iobuf.buf.pos = buf; ++ hostdata->iobuf.buf.cnt -= i; ++ if ( hostdata->iobuf.buf.cnt <= 0 ) { ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_BUFFER ); ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "buffer transferred\n" ); ++ goto complete; ++ } ++ break; ++#endif /* PIO */ ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "unexpected state %d\n", ++ hostdata->state ); ++ goto complete; ++ } ++ return; ++complete: ++ MMC_I_MASK = MMC_I_MASK_ALL; ++ complete( &hostdata->completion ); ++ return; ++} ++ ++#ifndef PIO ++static void pxa_mmc_dma_irq( int irq, void *dev_id, struct pt_regs *regs ) ++{ ++ mmc_controller_t ctrlr = (mmc_controller_t)dev_id; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ u32 dcsr; ++ u32 ddadr; ++ int chan = hostdata->iobuf.buf.chan; ++ ++ ddadr = DDADR( chan ); ++ dcsr = DCSR( chan ); ++ DCSR( chan ) = dcsr & ~DCSR_STOPIRQEN; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, ++ "MMC DMA interrupt: chan=%d ddadr=0x%08x " ++ "dcmd=0x%08x dcsr=0x%08x\n", ++ chan, ddadr, DCMD( chan ), dcsr ); ++/* bus error */ ++ if ( dcsr & DCSR_BUSERR ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "bus error on DMA channel %d\n", ++ chan ); ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_ERROR ); ++ goto complete; ++ } ++/* data transfer completed */ ++ if ( dcsr & DCSR_ENDINTR ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "buffer transferred\n" ); ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_BUFFER ); ++ goto complete; ++ } ++ return; ++complete: ++ complete( &hostdata->completion ); ++ return; ++} ++#endif ++ ++ ++static int pxa_mmc_init( mmc_controller_t ctrlr ) ++{ ++ int ret = -ENODEV; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++#ifndef PIO ++ register int i; ++ register pxa_dma_desc *desc; ++#endif ++ ++/* hardware initialization */ ++/* I. prepare to transfer data */ ++/* 1. allocate buffer */ ++#ifndef PIO ++ hostdata->iobuf.buf.read_desc = consistent_alloc( GFP_KERNEL, ++ (PXA_MMC_IODATA_SIZE>>5) ++ * sizeof( pxa_dma_desc ), ++ &hostdata->iobuf.buf.read_desc_phys_addr, 0 ); ++ if ( !hostdata->iobuf.buf.read_desc ) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ hostdata->iobuf.buf.write_desc = consistent_alloc( GFP_KERNEL, ++ (PXA_MMC_IODATA_SIZE>>5) ++ * sizeof( pxa_dma_desc ), ++ &hostdata->iobuf.buf.write_desc_phys_addr, 0 ); ++ if ( !hostdata->iobuf.buf.write_desc ) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ hostdata->iobuf.iodata = consistent_alloc( GFP_ATOMIC, ++ PXA_MMC_IODATA_SIZE, ++ &hostdata->iobuf.buf.phys_addr, 0 ); ++#else ++ hostdata->iobuf.iodata = kmalloc( PXA_MMC_IODATA_SIZE, GFP_ATOMIC ); ++#endif ++ if ( !hostdata->iobuf.iodata ) { ++ ret = -ENOMEM; ++ goto error; ++ } ++/* 2. initialize iobuf */ ++ hostdata->iobuf.blksz = PXA_MMC_BLKSZ_MAX; ++ hostdata->iobuf.bufsz = PXA_MMC_IODATA_SIZE; ++ hostdata->iobuf.nob = PXA_MMC_BLOCKS_PER_BUFFER; ++#ifndef PIO ++ /* request DMA channel */ ++ if ( (hostdata->iobuf.buf.chan = pxa_request_dma( "MMC", DMA_PRIO_LOW, ++ pxa_mmc_dma_irq, ctrlr )) < 0 ) { ++ MMC_ERROR( "failed to request DMA channel\n" ); ++ goto error; ++ } ++ ++ DRCMRRXMMC = hostdata->iobuf.buf.chan | DRCMR_MAPVLD; ++ DRCMRTXMMC = hostdata->iobuf.buf.chan | DRCMR_MAPVLD; ++ ++ for ( i = 0; i < ((PXA_MMC_IODATA_SIZE>>5) - 1); i++ ) { ++ desc = &hostdata->iobuf.buf.read_desc[i]; ++ desc->ddadr = hostdata->iobuf.buf.read_desc_phys_addr ++ + ((i + 1) * sizeof( pxa_dma_desc )); ++ desc->dsadr = MMC_RXFIFO_PHYS_ADDR; ++ desc->dtadr = hostdata->iobuf.buf.phys_addr + (i<<5); ++ desc->dcmd = DCMD_FLOWSRC|DCMD_INCTRGADDR ++ |DCMD_WIDTH1|DCMD_BURST32|(1<<5); ++ ++ desc = &hostdata->iobuf.buf.write_desc[i]; ++ desc->ddadr = hostdata->iobuf.buf.write_desc_phys_addr ++ + ((i + 1) * sizeof( pxa_dma_desc )); ++ desc->dsadr = hostdata->iobuf.buf.phys_addr + (i<<5); ++ desc->dtadr = MMC_TXFIFO_PHYS_ADDR; ++ desc->dcmd = DCMD_FLOWTRG|DCMD_INCSRCADDR ++ |DCMD_WIDTH1|DCMD_BURST32|(1<<5); ++ } ++ desc = &hostdata->iobuf.buf.read_desc[i]; ++ desc->ddadr = (hostdata->iobuf.buf.read_desc_phys_addr + ++ (i + 1) * sizeof( pxa_dma_desc))|DDADR_STOP; ++ desc->dsadr = MMC_RXFIFO_PHYS_ADDR; ++ desc->dtadr = hostdata->iobuf.buf.phys_addr + (i<<5); ++ desc->dcmd = DCMD_FLOWSRC|DCMD_INCTRGADDR ++ |DCMD_WIDTH1|DCMD_BURST32|(1<<5); ++ ++ desc = &hostdata->iobuf.buf.write_desc[i]; ++ desc->ddadr = (hostdata->iobuf.buf.write_desc_phys_addr + ++ (i + 1) * sizeof( pxa_dma_desc))|DDADR_STOP; ++ desc->dsadr = hostdata->iobuf.buf.phys_addr + (i<<5); ++ desc->dtadr = MMC_TXFIFO_PHYS_ADDR; ++ desc->dcmd = DCMD_FLOWTRG|DCMD_INCSRCADDR ++ |DCMD_WIDTH1|DCMD_BURST32|(1<<5); ++#endif ++/* II. MMC */ ++/* 1) request irq */ ++ if ( request_irq( IRQ_MMC, pxa_mmc_irq, 0, "MMC", ctrlr ) ) { ++ MMC_ERROR( "failed to request IRQ_MMC\n" ); ++ goto error; ++ } ++ ++/* 2) initialize h/w and ctrlr */ ++ set_GPIO_mode( GPIO6_MMCCLK_MD ); ++ CKEN |= CKEN12_MMC; /* enable MMC unit clock */ ++ ++ ret = 0; ++ goto out; ++error: ++#ifndef PIO ++/* free DMA resources */ ++ if ( hostdata->iobuf.buf.chan >= 0 ) { ++ DRCMRRXMMC = 0; ++ DRCMRTXMMC = 0; ++ pxa_free_dma( hostdata->iobuf.buf.chan ); ++ } ++ if ( hostdata->iobuf.iodata ) ++ consistent_free( hostdata->iobuf.iodata, ++ PXA_MMC_IODATA_SIZE, ++ hostdata->iobuf.buf.phys_addr ); ++ if ( hostdata->iobuf.buf.read_desc ) ++ consistent_free( hostdata->iobuf.buf.read_desc, ++ (PXA_MMC_IODATA_SIZE>>5) ++ * sizeof( pxa_dma_desc ), ++ hostdata->iobuf.buf.read_desc_phys_addr ); ++ if ( hostdata->iobuf.buf.write_desc ) ++ consistent_free( hostdata->iobuf.buf.write_desc, ++ (PXA_MMC_IODATA_SIZE>>5) ++ * sizeof( pxa_dma_desc ), ++ hostdata->iobuf.buf.write_desc_phys_addr ); ++#else ++ kfree( hostdata->iobuf.iodata ); ++#endif ++out: ++ return ret; ++} ++ ++static void pxa_mmc_remove( mmc_controller_t ctrlr ) ++{ ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++/* 1) free buffer(s) */ ++#ifndef PIO ++ consistent_free( hostdata->iobuf.iodata, PXA_MMC_IODATA_SIZE, ++ hostdata->iobuf.buf.phys_addr ); ++ consistent_free( hostdata->iobuf.buf.read_desc, ++ (PXA_MMC_IODATA_SIZE>>5) ++ * sizeof( pxa_dma_desc ), ++ hostdata->iobuf.buf.read_desc_phys_addr ); ++ consistent_free( hostdata->iobuf.buf.write_desc, ++ (PXA_MMC_IODATA_SIZE>>5) ++ * sizeof( pxa_dma_desc ), ++ hostdata->iobuf.buf.write_desc_phys_addr ); ++/* 2) release DMA channel */ ++ if ( hostdata->iobuf.buf.chan >= 0 ) { ++ DRCMRRXMMC = 0; ++ DRCMRTXMMC = 0; ++ pxa_free_dma( hostdata->iobuf.buf.chan ); ++ } ++#else ++ kfree( hostdata->iobuf.iodata ); ++#endif ++/* II. MMC */ ++/* 1) release irq */ ++ free_irq( IRQ_MMC, ctrlr ); ++ CKEN &= ~CKEN12_MMC; /* disable MMC unit clock */ ++} ++ ++static int pxa_mmc_probe( mmc_controller_t ctrlr ) ++{ ++ return 1; ++} ++ ++#ifdef CONFIG_PM ++static int pxa_mmc_suspend( mmc_controller_t ctrlr ) ++{ ++ int ret = -EBUSY; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "state=%s\n", ++ PXA_MMC_STATE_LABEL( hostdata->state ) ); ++ ++ if ( hostdata->state == PXA_MMC_FSM_IDLE ) { ++ /* save registers */ ++ SAVED_MMC_CLKRT = MMC_CLKRT; ++ SAVED_MMC_RESTO = MMC_RESTO; ++ SAVED_MMC_SPI = MMC_SPI; ++ SAVED_DRCMRRXMMC = DRCMRRXMMC; ++ SAVED_DRCMRTXMMC = DRCMRTXMMC; ++ ++#if 0 /* FIXME */ ++ /* send CMD0 */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(0); /* CMD0 with zero argument */ ++ MMC_ARGH = 0UL; ++ MMC_ARGL = 0UL; ++ MMC_CMDAT = 0UL; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD0(0x%04x%04x)\n", 0UL, 0UL ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_NORESPONSE, ++ FALSE )) ) ++ { ++ ret = -EIO; ++ goto error; ++ } ++#endif ++ ++ set_GPIO_mode( GPIO6_MMCCLK ); ++ CKEN &= ~CKEN12_MMC; /* disable MMC unit clock */ ++ ++ hostdata->suspended = TRUE; ++ ret = 0; ++ } ++error: ++ return ret; ++} ++ ++static void pxa_mmc_resume( mmc_controller_t ctrlr ) ++{ ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++ if ( hostdata->suspended == TRUE ) { ++ set_GPIO_mode( GPIO6_MMCCLK_MD ); ++ CKEN |= CKEN12_MMC; /* enable MMC unit clock */ ++ ++ /* restore registers */ ++ MMC_CLKRT = SAVED_MMC_CLKRT; ++ MMC_RESTO = SAVED_MMC_RESTO; ++ MMC_SPI = SAVED_MMC_SPI; ++ DRCMRRXMMC = SAVED_DRCMRRXMMC; ++ DRCMRTXMMC = SAVED_DRCMRTXMMC; ++ ++ hostdata->suspended = FALSE; ++ ++ mmc_update_card_stack( ctrlr->slot ); /* FIXME */ ++ } ++ ++ return; ++} ++#endif ++ ++static mmc_controller_tmpl_rec_t pxa_mmc_controller_tmpl_rec = { ++ owner: THIS_MODULE, ++ name: "PXA250", ++ block_size_max: PXA_MMC_BLKSZ_MAX, ++ nob_max: PXA_MMC_NOB_MAX, ++ probe: pxa_mmc_probe, ++ init: pxa_mmc_init, ++ remove: __devexit_p( pxa_mmc_remove ), ++#ifdef CONFIG_PM ++ suspend: pxa_mmc_suspend, ++ resume: pxa_mmc_resume, ++#endif /* CONFIG_PM */ ++ update_acq: pxa_mmc_update_acq, ++// single_card_acq: pxa_mmc_single_card_acq, ++ init_card_stack: pxa_mmc_init_card_stack, ++ check_card_stack: pxa_mmc_check_card_stack, ++ setup_card: pxa_mmc_setup_card, ++ stream_read: pxa_mmc_stream_read, ++ read_block: pxa_mmc_read_block, ++ read_mblock: pxa_mmc_read_mblock, ++ stream_write: pxa_mmc_stream_write, ++ write_block: pxa_mmc_write_block, ++ write_mblock: pxa_mmc_write_mblock ++ /* TODO ++ sg_io: pxa_mmc_sg_io ++ */ ++ /* TODO: ++ * erase, ++ * write protection, ++ * lock/password management methods ++ */ ++}; ++ ++static int __devinit mmc_pxa_module_init( void ) ++{ ++ int ret = -ENODEV; ++#ifdef CONFIG_ARCH_RAMSES ++ RAMSES_MMC_ON(); ++ udelay(1000); ++#endif ++ ++ host = mmc_register( MMC_REG_TYPE_HOST, &pxa_mmc_controller_tmpl_rec, ++ sizeof( pxa_mmc_hostdata_rec_t ) ); ++ if ( !host ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, ++ "failed to register with MMC core\n" ); ++ goto error; ++ } ++ ++ ret = 0; ++error: ++ return ret; ++} ++ ++static void __devexit mmc_pxa_module_cleanup( void ) ++{ ++ mmc_unregister( MMC_REG_TYPE_HOST, host ); ++#ifdef CONFIG_ARCH_RAMSES ++ RAMSES_MMC_OFF(); ++#endif ++} ++ ++EXPORT_NO_SYMBOLS; ++ ++MODULE_LICENSE( "GPL" ); ++ ++module_init( mmc_pxa_module_init ); ++module_exit( mmc_pxa_module_cleanup ); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/mmc/mmc_pxa.h 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,278 @@ ++/* ++ * linux/drivers/mmc/mmc_pxa.h ++ * ++ * Author: Vladimir Shebordaev, Igor Oblakov ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id$ ++ * ++ * 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 __MMC_PXA_P_H__ ++#define __MMC_PXA_P_H__ ++ ++#include <linux/completion.h> ++ ++#define PIO ++ ++/* PXA-250 MMC controller registers */ ++ ++/* MMC_STRPCL */ ++#define MMC_STRPCL_STOP_CLK (0x0001UL) ++#define MMC_STRPCL_START_CLK (0x0002UL) ++ ++/* MMC_STAT */ ++#define MMC_STAT_END_CMD_RES (0x0001UL << 13) ++#define MMC_STAT_PRG_DONE (0x0001UL << 12) ++#define MMC_STAT_DATA_TRAN_DONE (0x0001UL << 11) ++#define MMC_STAT_CLK_EN (0x0001UL << 8) ++#define MMC_STAT_RECV_FIFO_FULL (0x0001UL << 7) ++#define MMC_STAT_XMIT_FIFO_EMPTY (0x0001UL << 6) ++#define MMC_STAT_RES_CRC_ERROR (0x0001UL << 5) ++#define MMC_STAT_SPI_READ_ERROR_TOKEN (0x0001UL << 4) ++#define MMC_STAT_CRC_READ_ERROR (0x0001UL << 3) ++#define MMC_STAT_CRC_WRITE_ERROR (0x0001UL << 2) ++#define MMC_STAT_TIME_OUT_RESPONSE (0x0001UL << 1) ++#define MMC_STAT_READ_TIME_OUT (0x0001UL) ++ ++#define MMC_STAT_ERRORS (MMC_STAT_RES_CRC_ERROR|MMC_STAT_SPI_READ_ERROR_TOKEN\ ++ |MMC_STAT_CRC_READ_ERROR|MMC_STAT_TIME_OUT_RESPONSE\ ++ |MMC_STAT_READ_TIME_OUT) ++ ++/* MMC_CLKRT */ ++#define MMC_CLKRT_20MHZ (0x0000UL) ++#define MMC_CLKRT_10MHZ (0x0001UL) ++#define MMC_CLKRT_5MHZ (0x0002UL) ++#define MMC_CLKRT_2_5MHZ (0x0003UL) ++#define MMC_CLKRT_1_25MHZ (0x0004UL) ++#define MMC_CLKRT_0_625MHZ (0x0005UL) ++#define MMC_CLKRT_0_3125MHZ (0x0006UL) ++ ++/* MMC_SPI */ ++#define MMC_SPI_DISABLE (0x00UL) ++#define MMC_SPI_EN (0x01UL) ++#define MMC_SPI_CS_EN (0x01UL << 2) ++#define MMC_SPI_CS_ADDRESS (0x01UL << 3) ++#define MMC_SPI_CRC_ON (0x01UL << 1) ++ ++/* MMC_CMDAT */ ++#define MMC_CMDAT_MMC_DMA_EN (0x0001UL << 7) ++#define MMC_CMDAT_INIT (0x0001UL << 6) ++#define MMC_CMDAT_BUSY (0x0001UL << 5) ++#define MMC_CMDAT_STREAM (0x0001UL << 4) ++#define MMC_CMDAT_BLOCK (0x0000UL << 4) ++#define MMC_CMDAT_WRITE (0x0001UL << 3) ++#define MMC_CMDAT_READ (0x0000UL << 3) ++#define MMC_CMDAT_DATA_EN (0x0001UL << 2) ++#define MMC_CMDAT_R1 (0x0001UL) ++#define MMC_CMDAT_R2 (0x0002UL) ++#define MMC_CMDAT_R3 (0x0003UL) ++ ++/* MMC_RESTO */ ++#define MMC_RES_TO_MAX (0x007fUL) /* [6:0] */ ++ ++/* MMC_RDTO */ ++#define MMC_READ_TO_MAX (0x0ffffUL) /* [15:0] */ ++ ++/* MMC_BLKLEN */ ++#define MMC_BLK_LEN_MAX (0x03ffUL) /* [9:0] */ ++ ++/* MMC_PRTBUF */ ++#define MMC_PRTBUF_BUF_PART_FULL (0x01UL) ++#define MMC_PRTBUF_BUF_FULL (0x00UL ) ++ ++/* MMC_I_MASK */ ++#define MMC_I_MASK_TXFIFO_WR_REQ (0x01UL << 6) ++#define MMC_I_MASK_RXFIFO_RD_REQ (0x01UL << 5) ++#define MMC_I_MASK_CLK_IS_OFF (0x01UL << 4) ++#define MMC_I_MASK_STOP_CMD (0x01UL << 3) ++#define MMC_I_MASK_END_CMD_RES (0x01UL << 2) ++#define MMC_I_MASK_PRG_DONE (0x01UL << 1) ++#define MMC_I_MASK_DATA_TRAN_DONE (0x01UL) ++#define MMC_I_MASK_ALL (0x07fUL) ++ ++ ++/* MMC_I_REG */ ++#define MMC_I_REG_TXFIFO_WR_REQ (0x01UL << 6) ++#define MMC_I_REG_RXFIFO_RD_REQ (0x01UL << 5) ++#define MMC_I_REG_CLK_IS_OFF (0x01UL << 4) ++#define MMC_I_REG_STOP_CMD (0x01UL << 3) ++#define MMC_I_REG_END_CMD_RES (0x01UL << 2) ++#define MMC_I_REG_PRG_DONE (0x01UL << 1) ++#define MMC_I_REG_DATA_TRAN_DONE (0x01UL) ++#define MMC_I_REG_ALL (0x007fUL) ++ ++/* MMC_CMD */ ++#define MMC_CMD_INDEX_MAX (0x006fUL) /* [5:0] */ ++#define CMD(x) (x) ++ ++/* MMC_ARGH */ ++/* MMC_ARGL */ ++/* MMC_RES */ ++/* MMC_RXFIFO */ ++#define MMC_RXFIFO_PHYS_ADDR 0x41100040 //MMC_RXFIFO physical address ++/* MMC_TXFIFO */ ++#define MMC_TXFIFO_PHYS_ADDR 0x41100044 //MMC_TXFIFO physical address ++ ++/* implementation specific declarations */ ++#define PXA_MMC_BLKSZ_MAX (1<<9) /* actually 1023 */ ++#define PXA_MMC_NOB_MAX ((1<<16)-2) ++#define PXA_MMC_BLOCKS_PER_BUFFER (2) ++ ++#define PXA_MMC_IODATA_SIZE (PXA_MMC_BLOCKS_PER_BUFFER*PXA_MMC_BLKSZ_MAX) /* 1K */ ++ ++typedef enum _pxa_mmc_fsm { /* command processing FSM */ ++ PXA_MMC_FSM_IDLE = 1, ++ PXA_MMC_FSM_CLK_OFF, ++ PXA_MMC_FSM_END_CMD, ++ PXA_MMC_FSM_BUFFER_IN_TRANSIT, ++ PXA_MMC_FSM_END_BUFFER, ++ PXA_MMC_FSM_END_IO, ++ PXA_MMC_FSM_END_PRG, ++ PXA_MMC_FSM_ERROR ++} pxa_mmc_state_t; ++ ++#define PXA_MMC_STATE_LABEL( state ) (\ ++ (state == PXA_MMC_FSM_IDLE) ? "IDLE" :\ ++ (state == PXA_MMC_FSM_CLK_OFF) ? "CLK_OFF" :\ ++ (state == PXA_MMC_FSM_END_CMD) ? "END_CMD" :\ ++ (state == PXA_MMC_FSM_BUFFER_IN_TRANSIT) ? "IN_TRANSIT" :\ ++ (state == PXA_MMC_FSM_END_BUFFER) ? "END_BUFFER" :\ ++ (state == PXA_MMC_FSM_END_IO) ? "END_IO" :\ ++ (state == PXA_MMC_FSM_END_PRG) ? "END_PRG" : "UNKNOWN" ) ++ ++typedef enum _pxa_mmc_result { ++ PXA_MMC_NORMAL = 0, ++ PXA_MMC_INVALID_STATE = -1, ++ PXA_MMC_TIMEOUT = -2, ++ PXA_MMC_ERROR = -3 ++} pxa_mmc_result_t; ++ ++typedef u32 pxa_mmc_clkrt_t; ++ ++typedef char *pxa_mmc_iodata_t; ++#ifdef PIO ++typedef struct _pxa_mmc_piobuf_rec { ++ char *pos; /* current buffer position */ ++ int cnt; /* byte counter */ ++} pxa_mmc_piobuf_rec_t, *pxa_mmc_piobuf_t; ++#else /* i.e. DMA */ ++typedef struct _pxa_mmc_dmabuf_rec { /* TODO: buffer ring, DMA irq completion */ ++ int chan; /* dma channel no */ ++ dma_addr_t phys_addr; /* iodata physical address */ ++ pxa_dma_desc *read_desc; /* input descriptor array virtual address */ ++ pxa_dma_desc *write_desc; /* output descriptor array virtual address */ ++ dma_addr_t read_desc_phys_addr; /* descriptor array physical address */ ++ dma_addr_t write_desc_phys_addr; /* descriptor array physical address */ ++ pxa_dma_desc *last_read_desc; /* last input descriptor ++ * used by the previous transfer ++ */ ++ pxa_dma_desc *last_write_desc; /* last output descriptor ++ * used by the previous transfer ++ */ ++} pxa_mmc_dmabuf_rec_t, *pxa_mmc_dmabuf_t; ++#endif ++ ++typedef struct _pxa_mmc_iobuf_rec { ++ ssize_t blksz; /* current block size in bytes */ ++ ssize_t bufsz; /* buffer size for each transfer */ ++ ssize_t nob; /* number of blocks pers buffer */ ++#ifndef PIO ++ pxa_mmc_dmabuf_rec_t buf; /* i.e. DMA buffer ring on the iodata */ ++#else /* i.e. DMA */ ++ pxa_mmc_piobuf_rec_t buf; /* PIO buffer accounting */ ++#endif ++ pxa_mmc_iodata_t iodata; /* I/O data buffer */ ++} pxa_mmc_iobuf_rec_t, *pxa_mmc_iobuf_t; ++ ++typedef struct _pxa_mmc_hostdata_rec { ++ pxa_mmc_state_t state; /* FSM */ ++#ifdef CONFIG_PM ++ int suspended; ++#endif ++ pxa_mmc_iobuf_rec_t iobuf; /* data transfer state */ ++ ++ int busy; /* atomic busy flag */ ++ struct completion completion; /* completion */ ++#if CONFIG_MMC_DEBUG_IRQ ++ int irqcnt; ++ int timeo; ++#endif ++ ++/* cached controller state */ ++ u32 mmc_i_reg; /* interrupt last requested */ ++ u32 mmc_i_mask; /* mask to be set by intr handler */ ++ u32 mmc_stat; /* status register at the last intr */ ++ u32 mmc_cmdat; /* MMC_CMDAT at the last inr */ ++ u8 mmc_res[16]; /* response to the last command in host order */ ++ u32 saved_mmc_clkrt; ++ u32 saved_mmc_resto; ++ u32 saved_mmc_spi; ++ u32 saved_drcmrrxmmc; ++ u32 saved_drcmrtxmmc; ++ ++/* controller options */ ++ pxa_mmc_clkrt_t clkrt; /* current bus clock rate */ ++} pxa_mmc_hostdata_rec_t, *pxa_mmc_hostdata_t; ++ ++#define PXA_MMC_STATUS( ctrlr ) (((pxa_mmc_hostdata_t)ctrlr->host_data)->mmc_stat) ++#define PXA_MMC_RESPONSE( ctrlr, idx ) ((((pxa_mmc_hostdata_t)ctrlr->host_data)->mmc_res)[idx]) ++#define PXA_MMC_CLKRT( ctrlr ) (((pxa_mmc_hostdata_t)ctrlr->host_data)->clkrt) ++ ++#define SAVED_MMC_CLKRT (hostdata->saved_mmc_clkrt) ++#define SAVED_MMC_RESTO (hostdata->saved_mmc_resto) ++#define SAVED_MMC_SPI (hostdata->saved_mmc_spi) ++#define SAVED_DRCMRRXMMC (hostdata->saved_drcmrrxmmc ) ++#define SAVED_DRCMRTXMMC (hostdata->saved_drcmrtxmmc ) ++ ++static inline int pxa_mmc_clkrt( int speed ) ++{ ++ return MMC_CLKRT_20MHZ; /* TODO */ ++} ++ ++/* PXA MMC controller specific card data */ ++typedef struct _pxa_mmc_card_data_rec { ++ pxa_mmc_clkrt_t clkrt; /* clock rate to be set for the card */ ++} pxa_mmc_card_data_rec_t, *pxa_mmc_card_data_t; ++ ++#ifdef CONFIG_MMC_DEBUG ++#undef MMC_DUMP_R1 ++#undef MMC_DUMP_R2 ++#undef MMC_DUMP_R3 ++#define MMC_DUMP_R2( ctrlr ) MMC_DEBUG( MMC_DEBUG_LEVEL3, \ ++"R2 response: %02x %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", \ ++PXA_MMC_RESPONSE( ctrlr, 15 ), \ ++PXA_MMC_RESPONSE( ctrlr, 14 ), \ ++PXA_MMC_RESPONSE( ctrlr, 13 ), \ ++PXA_MMC_RESPONSE( ctrlr, 12 ), \ ++PXA_MMC_RESPONSE( ctrlr, 11 ), \ ++PXA_MMC_RESPONSE( ctrlr, 10 ), \ ++PXA_MMC_RESPONSE( ctrlr, 9 ), \ ++PXA_MMC_RESPONSE( ctrlr, 8 ), \ ++PXA_MMC_RESPONSE( ctrlr, 7 ), \ ++PXA_MMC_RESPONSE( ctrlr, 6 ), \ ++PXA_MMC_RESPONSE( ctrlr, 5 ), \ ++PXA_MMC_RESPONSE( ctrlr, 4 ), \ ++PXA_MMC_RESPONSE( ctrlr, 3 ), \ ++PXA_MMC_RESPONSE( ctrlr, 2 ), \ ++PXA_MMC_RESPONSE( ctrlr, 1 ), \ ++PXA_MMC_RESPONSE( ctrlr, 0 ) ); ++#define MMC_DUMP_R1( ctrlr ) MMC_DEBUG( MMC_DEBUG_LEVEL3, \ ++"R1(b) response: %02x %02x%02x%02x%02x\n", \ ++PXA_MMC_RESPONSE( ctrlr, 5 ), \ ++PXA_MMC_RESPONSE( ctrlr, 4 ), \ ++PXA_MMC_RESPONSE( ctrlr, 3 ), \ ++PXA_MMC_RESPONSE( ctrlr, 2 ), \ ++PXA_MMC_RESPONSE( ctrlr, 1 ) ); ++#define MMC_DUMP_R3( ctrlr ) MMC_DEBUG( MMC_DEBUG_LEVEL3, \ ++"R3 response: %02x %02x%02x%02x%02x\n", \ ++PXA_MMC_RESPONSE( ctrlr, 5 ), \ ++PXA_MMC_RESPONSE( ctrlr, 4 ), \ ++PXA_MMC_RESPONSE( ctrlr, 3 ), \ ++PXA_MMC_RESPONSE( ctrlr, 2 ), \ ++PXA_MMC_RESPONSE( ctrlr, 1 ) ); ++ ++#endif ++#endif /* __MMC_PXA_P_H__ */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/mmc/mmc_test.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,538 @@ ++/* ++ * linux/drivers/mmc/mmc_test.c ++ * ++ * Author: Vladimir Shebordaev ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id$ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/version.h> ++#include <linux/config.h> ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++ ++#include <linux/fs.h> ++#ifdef CONFIG_DEVFS_FS ++#include <linux/devfs_fs_kernel.h> ++#endif ++ ++#include <asm/uaccess.h> ++ ++#include <mmc/types.h> ++#include <mmc/mmc.h> ++#include <mmc/ioctl.h> ++ ++#include "types.h" ++#include "mmc.h" ++ ++typedef struct _mmc_test_device_rec mmc_test_device_rec_t; ++typedef struct _mmc_test_device_rec *mmc_test_device_t; ++ ++struct _mmc_test_device_rec { ++ mmc_card_t card; ++ mmc_transfer_mode_t transfer_mode; ++ int usage; ++#ifdef CONFIG_DEVFS_FS ++ devfs_handle_t devfs_handle; ++#endif ++}; ++ ++/* MMC device table */ ++static mmc_test_device_rec_t mmc_test_device[MMC_CONTROLLERS_MAX][MMC_CARDS_MAX]; ++static DECLARE_MUTEX(mmc_test_device_mutex); ++ ++static inline mmc_test_device_t __mmc_test_get_device( kdev_t rdev ) ++{ ++ mmc_test_device_t ret = NULL; ++ u8 minor = MINOR( rdev ); ++ int host_no, card_no; ++ ++ host_no = minor >> MMC_MINOR_HOST_SHIFT; ++ if ( host_no >= MMC_CONTROLLERS_MAX ) ++ goto error; ++ ++ card_no = minor & MMC_MINOR_CARD_MASK; ++ if ( card_no >= MMC_CARDS_MAX ) ++ goto error; ++ ++ ret = &mmc_test_device[host_no][card_no]; ++ if ( !ret->card ) { ++ ret->card = mmc_get_card( host_no, card_no ); ++ if ( !ret->card ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to get card: host=%d, card=%d\n", host_no, card_no ); ++ ret = NULL; ++ goto error; ++ } ++ ++ } ++ ++ret->usage; ++ ++error: ++ return ret; ++} ++ ++static inline void __mmc_test_put_device( mmc_test_device_t dev ) ++{ ++ mmc_put_card( dev->card ); ++ --dev->usage; ++} ++ ++static inline mmc_test_device_t mmc_test_get_device( kdev_t kdev ) ++{ ++ mmc_test_device_t ret = NULL; ++ ++ down( &mmc_test_device_mutex ); ++ ret = __mmc_test_get_device( kdev ); ++ up( &mmc_test_device_mutex ); ++ ++ return ret; ++} ++ ++static inline void mmc_test_put_device( mmc_test_device_t dev ) ++{ ++ if ( dev ) { ++ down( &mmc_test_device_mutex ); ++ __mmc_test_put_device( dev ); ++ if ( !dev->usage ) { ++ if ( dev->card ) { ++ if ( dev->card->usage ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, ++ "broken card reference\n" ); ++ } ++ memset( dev, 0, sizeof( mmc_test_device_rec_t ) ); ++ } ++ } ++ up( &mmc_test_device_mutex ); ++ } ++} ++ ++static inline int mmc_test_set_transfer_mode( mmc_test_device_t dev, mmc_transfer_mode_t mode ) ++{ ++ int ret = -1; ++ ++ if ( dev ) { ++ down( &mmc_test_device_mutex ); ++ dev->transfer_mode = mode; ++ ret = 0; ++ up( &mmc_test_device_mutex ); ++ } ++ return ret; ++} ++ ++static inline mmc_transfer_mode_t mmc_test_get_transfer_mode( mmc_test_device_t dev ) ++{ ++ mmc_transfer_mode_t ret = MMC_TRANSFER_MODE_UNDEFINED; ++ ++ if ( dev ) { ++ down( &mmc_test_device_mutex ); ++ ret = dev->transfer_mode; ++ up( &mmc_test_device_mutex ); ++ } ++ return ret; ++} ++ ++static int mmc_test_open( struct inode *inode, struct file *file ) ++{ ++ int ret = -ENODEV; ++ mmc_test_device_t dev = NULL; ++ ++ MOD_INC_USE_COUNT; ++ ++ __ENTER0( ); ++ dev = mmc_test_get_device( inode->i_rdev ); ++ if ( !dev || !dev->card ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to acquire device\n" ); ++ goto error; ++ } ++ ++ if ( dev->card->usage > 1 ) { ++ ret = -EBUSY; ++ goto error; ++ } ++ ++ dev->transfer_mode = MMC_TEST_TRANSFER_MODE_DEFAULT; /* FIXME: should check card CCC */ ++ file->private_data = dev; ++ ++ __LEAVE0( ); ++ return 0; ++error: ++ MOD_DEC_USE_COUNT; ++ mmc_test_put_device( dev ); ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static int mmc_test_release( struct inode *inode, struct file *file ) ++{ ++ int ret = -ENODEV; ++ mmc_test_device_t dev = (mmc_test_device_t)file->private_data; ++ ++ if ( !dev ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" ); ++ goto error; ++ } ++ ++ __ENTER( "host=%d, card=%d", dev->card->ctrlr->slot, dev->card->slot ); ++ ++ file->private_data = NULL; ++ ++ mmc_test_put_device( dev ); ++ MOD_DEC_USE_COUNT; ++ ++ ret = 0; ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static ssize_t mmc_test_read( struct file *file, char *buf, size_t size, loff_t *ppos ) ++{ ++ ssize_t ret = -ENODEV; ++ ssize_t retsize = 0; ++ mmc_test_device_t dev = (mmc_test_device_t)file->private_data; ++ ++ __ENTER( "host=%d, card=%d, size=%d", dev->card->ctrlr->slot, dev->card->slot, size ); ++ ++ if ( !dev ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" ); ++ goto error; ++ } ++ ++ switch ( dev->transfer_mode ) { ++ char *mbuf; ++ ++ case MMC_TRANSFER_MODE_BLOCK_SINGLE: ++ mbuf = kmalloc( 512, GFP_ATOMIC ); /* FIXME: actual read_bl_len or ctrlr->block_size_max whichever is less ), GFP_KERNEL */ ++ if ( !mbuf ) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ while( size > 0 ) { ++ int lsize = (size > 512) ? 512 : size; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL4, ++ "before mmc_read mbuf=0x%x " ++ "lsize=%d ppos=0x%x *ppos=%d\n", ++ mbuf, lsize, ppos, *ppos ); ++ ret = mmc_read( dev->card, ++ MMC_TRANSFER_MODE_BLOCK_SINGLE, ++ mbuf, lsize, ppos ); ++ if ( ret <= 0 ) ++ break; ++ ++ /* Copy to user */ ++ if ( copy_to_user( buf, mbuf, ret ) ) { ++ ret = -EFAULT; ++ break; ++ } ++ retsize += ret; ++ buf += ret; ++ size -= ret; ++ } ++ ++ if ( retsize > 0 ) ++ ret = retsize; ++ kfree(mbuf); ++ break; ++ ++ case MMC_TRANSFER_MODE_BLOCK_MULTIPLE: ++ mbuf = kmalloc( 1024, GFP_ATOMIC ); /* FIXME */ ++ if ( !mbuf ) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ while( size > 0 ) { ++ int lsize = (size > 1024) ? 1024 : size; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL4, ++ "before mmc_read mbuf=0x%x " ++ "lsize=%d ppos=0x%x *ppos=%d\n", ++ mbuf, lsize, ppos, *ppos ); ++ ret = mmc_read( dev->card, ++ MMC_TRANSFER_MODE_BLOCK_MULTIPLE, ++ mbuf, lsize, ppos ); ++ if ( ret <= 0 ) ++ break; ++ ++ /* Copy to user */ ++ if ( copy_to_user( buf, mbuf, ret ) ) { ++ ret = -EFAULT; ++ break; ++ } ++ retsize += ret; ++ buf += ret; ++ size -= ret; ++ } ++ ++ if ( retsize > 0 ) ++ ret = retsize; ++ kfree(mbuf); ++ break; ++ ++ case MMC_TRANSFER_MODE_STREAM: ++ ret = mmc_read( dev->card, dev->transfer_mode, ++ buf, size, ppos ); ++ break; ++ ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "invalid transfer mode\n" ); ++ } ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static ssize_t mmc_test_write( struct file *file, const char *buf, size_t size, loff_t *ppos ) ++{ ++ ssize_t ret = -ENODEV; ++ mmc_test_device_t dev = (mmc_test_device_t)file->private_data; ++ int retsize=0; ++ ++ __ENTER( "host=%d, card=%d, size=%d", dev->card->ctrlr->slot, dev->card->slot, size ); ++ ++ if ( !dev ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" ); ++ goto error; ++ } ++ ++ switch ( dev->transfer_mode ) { ++ char *mbuf; ++ ++ case MMC_TRANSFER_MODE_BLOCK_SINGLE: ++ mbuf = kmalloc( 512, GFP_ATOMIC ); /* FIXME: actual write_bl_len or ctrlr->block_size_max whichever is less, GFP_KERNEL */ ++ if ( !mbuf ) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ while ( size > 0 ) { ++ int lsize = ( size > 512 ) ? 512 : size; ++ ++ /* Copy from user */ ++ if ( copy_from_user( mbuf, buf, lsize ) ) { ++ ret = -EFAULT; ++ break; ++ } ++ ++ ret = mmc_write( dev->card, ++ MMC_TRANSFER_MODE_BLOCK_SINGLE, ++ mbuf, lsize, ppos ); ++ if( ret <= 0 ) ++ break; ++ ++ retsize += ret; ++ buf += ret; ++ size -= ret; ++ } ++ ++ if ( retsize > 0 ) ++ ret = retsize; ++ ++ kfree( mbuf ); ++ break; ++ ++ case MMC_TRANSFER_MODE_BLOCK_MULTIPLE: ++ mbuf = kmalloc( 1024, GFP_ATOMIC ); /* FIXME */ ++ if ( !mbuf ) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ while( size > 0 ) { ++ int lsize = (size > 1024) ? 1024 : size; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL4, ++ "before mmc_read mbuf=0x%x " ++ "lsize=%d ppos=0x%x *ppos=%d\n", ++ mbuf, lsize, ppos, *ppos ); ++ ret = mmc_write( dev->card, ++ MMC_TRANSFER_MODE_BLOCK_MULTIPLE, ++ mbuf, lsize, ppos ); ++ if ( ret <= 0 ) ++ break; ++ ++ /* Copy to user */ ++ if ( copy_to_user( (char *)buf, mbuf, ret ) ) { ++ ret = -EFAULT; ++ break; ++ } ++ retsize += ret; ++ buf += ret; ++ size -= ret; ++ } ++ ++ if ( retsize > 0 ) ++ ret = retsize; ++ kfree(mbuf); ++ break; ++ case MMC_TRANSFER_MODE_STREAM: ++ ret = mmc_write( dev->card, dev->transfer_mode, ++ buf, size, ppos ); ++ break; ++ ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "invalid transfer mode\n" ); ++ } ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static loff_t mmc_test_llseek( struct file *file, loff_t offset, int origin ) ++{ ++ loff_t ret = -ESPIPE; ++ mmc_test_device_t dev = (mmc_test_device_t)file->private_data; ++ mmc_card_t card; ++ ++ if ( !dev ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" ); ++ ret = -ENODEV; ++ goto error; ++ } ++ ++ __ENTER( "host=%d, card=%d, off=%ld, orig=%d", dev->card->ctrlr->slot, dev->card->slot, (long)offset, origin ); ++ ++ card = dev->card; ++ ++ switch ( origin ) { ++ case SEEK_CUR: ++ file->f_pos += offset; ++ break; ++ ++ case SEEK_END: ++ file->f_pos = card->info.capacity + offset; ++ break; ++ ++ case SEEK_SET: ++ file->f_pos = offset; ++ break; ++ ++ default: ++ ret = -EINVAL; ++ goto error; ++ } ++ ++ ret = file->f_pos; ++error: ++ __LEAVE( "ret=%ld", (long)ret ); ++ return ret; ++} ++ ++static int mmc_test_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg ) ++{ ++ int ret = -ENODEV; ++ mmc_test_device_t dev = (mmc_test_device_t)file->private_data; ++ ++ if ( !dev ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" ); ++ goto error; ++ } ++ ++ switch ( cmd ) { ++ case IOCMMCSTRNSMODE: ++ if ( get_user( ret, (int *)arg ) ) { ++ ret = -EFAULT; ++ goto error; ++ } ++ ret = mmc_test_set_transfer_mode( dev, ret ); ++ break; ++ ++ case IOCMMCGTRNSMODE: ++ ret = mmc_test_get_transfer_mode( dev ); ++ if ( put_user( ret, (int *)arg ) ) ++ ret = -EFAULT; ++ break; ++ ++ default: ++ ret = mmc_ioctl( dev->card, cmd, arg ); ++ } ++ ++error: ++ return ret; ++} ++ ++struct file_operations mmc_test_fops = { ++ owner: THIS_MODULE, ++ open: mmc_test_open, ++ release: mmc_test_release, ++ read: mmc_test_read, ++ write: mmc_test_write, ++ ioctl: mmc_test_ioctl, ++ llseek: mmc_test_llseek ++}; ++ ++#ifdef CONFIG_DEVFS_FS ++static int mmc_test_add_card( mmc_card_t card ) /* TODO */ ++{ ++ int ret = -1; ++ __ENTER( "host=%d, card=%d", card->ctrlr->slot, card->slot ); ++/* TODO: make kdev; register with devfs */ ++ __LEAVE0( ); ++ return ret; ++} ++ ++static int mmc_test_remove_card( mmc_card_t card ) /* TODO */ ++{ ++ int ret = -1; ++ __ENTER( "host=%d, card=%d", card->ctrlr->slot, card->slot ); ++/* TODO: make kdev; unregister with devfs */ ++ __LEAVE0( ); ++ return ret; ++} ++ ++static mmc_notifier_rec_t mmc_test_notifier = { ++ add: mmc_test_add_card, ++ remove: mmc_test_remove_card ++}; ++#endif /* CONFIG_DEVFS_FS */ ++ ++static int __init mmc_test_module_init( void ) ++{ ++ int ret = -ENODEV; ++ ++#ifdef CONFIG_DEVFS_FS ++ if ( !mmc_register( MMC_REG_TYPE_USER, &mmc_test_notifier, 0 ) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to register with MMC core\n" ); ++ goto error; ++ } ++#else ++ mmc_register( MMC_REG_TYPE_USER, NULL, 0 ); ++ if ( register_chrdev( MMC_TEST_MAJOR, "mmc_test", &mmc_test_fops ) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, ++ "failed to request device major number\n" ); ++ mmc_unregister( MMC_REG_TYPE_USER, NULL ); ++ goto error; ++ } ++#endif ++ ++ memset( mmc_test_device, 0, sizeof( mmc_test_device ) ); ++ ++ ret = 0; ++error: ++ return ret; ++} ++ ++static void __exit mmc_test_module_cleanup( void ) ++{ ++#ifdef CONFIG_DEVFS_FS ++ mmc_unregister( MMC_REG_TYPE_USER, &mmc_test_notifier ); ++#else ++ mmc_unregister( MMC_REG_TYPE_USER, NULL ); ++ unregister_chrdev( MMC_TEST_MAJOR, "mmc_test" ); ++#endif ++} ++ ++EXPORT_NO_SYMBOLS; ++ ++module_init( mmc_test_module_init ); ++module_exit( mmc_test_module_cleanup ); ++ ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/mmc/pm_test.c 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,29 @@ ++/* Power Managment Test Module. RTSoft Co. 2002 */ ++ ++/* The necessary header files */ ++ ++/* Standard in kernel modules */ ++#include <linux/kernel.h> /* We're doing kernel work */ ++#include <linux/module.h> /* Specifically, a module */ ++#define CONFIG_PM ++#include <linux/pm.h> ++ ++ ++static int pmdata = -1; ++ ++/* Initialize the module - register the proc file */ ++ ++int init_module() ++{ ++ pm_send_all(PM_SUSPEND,&pmdata); ++ return(0); ++} ++ ++ ++/* Cleanup - unregister our file from /proc */ ++void cleanup_module() ++{ ++ pm_send_all(PM_RESUME,NULL); ++} ++ ++MODULE_LICENSE( "GPL" ); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/mmc/types.h 2004-03-31 17:15:11.000000000 +0200 +@@ -0,0 +1,59 @@ ++/* ++ * linux/drivers/mmc/types.h ++ * ++ * Author: Vladimir Shebordaev ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id$ ++ * ++ * 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 __MMC_TYPES_P_H__ ++#define __MMC_TYPES_P_H__ ++ ++#ifdef __KERNEL__ ++#include <linux/kdev_t.h> ++ ++typedef enum _mmc_reg_type mmc_reg_type_t; ++typedef enum _mmc_response mmc_response_fmt_t; ++ ++/* MMC card private description */ ++typedef struct _mmc_card_rec mmc_card_rec_t; ++typedef struct _mmc_card_rec *mmc_card_t; ++typedef enum _mmc_dir mmc_dir_t; ++typedef enum _mmc_buftype mmc_buftype_t; ++ ++/* notifier declarations */ ++typedef struct _mmc_notifier_rec mmc_notifier_rec_t; ++typedef struct _mmc_notifier_rec *mmc_notifier_t; ++ ++typedef int (*mmc_notifier_fn_t) ( mmc_card_t ); ++ ++/* MMC card stack */ ++typedef struct _mmc_card_stack_rec mmc_card_stack_rec_t; ++typedef struct _mmc_card_stack_rec *mmc_card_stack_t; ++ ++typedef struct _mmc_data_transfer_req_rec mmc_data_transfer_req_rec_t; ++typedef struct _mmc_data_transfer_req_rec *mmc_data_transfer_req_t; ++ ++/* MMC controller */ ++typedef struct _mmc_controller_tmpl_rec mmc_controller_tmpl_rec_t; ++typedef struct _mmc_controller_tmpl_rec *mmc_controller_tmpl_t; ++ ++typedef enum _mmc_controller_state mmc_controller_state_t; ++typedef struct _mmc_controller_rec mmc_controller_rec_t; ++typedef struct _mmc_controller_rec *mmc_controller_t; ++ ++/* various kernel types */ ++typedef struct semaphore semaphore_t; ++typedef struct rw_semaphore rwsemaphore_t; ++typedef struct proc_dir_entry proc_dir_entry_rec_t; ++typedef struct proc_dir_entry *proc_dir_entry_t; ++typedef struct gendisk gendisk_rec_t; ++typedef struct gendisk *gendisk_t; ++#endif /* __KERNEL__ */ ++ ++#endif /* __MMC_TYPES_P_H__ */ ++ +--- linux-2.4.25/drivers/net/Config.in~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/net/Config.in 2004-03-31 17:15:11.000000000 +0200 +@@ -125,6 +125,7 @@ + dep_tristate ' SMC Ultra support' CONFIG_ULTRA $CONFIG_ISA + dep_tristate ' SMC Ultra32 EISA support' CONFIG_ULTRA32 $CONFIG_EISA + dep_tristate ' SMC 9194 support' CONFIG_SMC9194 $CONFIG_ISA ++ tristate ' SMC 91C9x/91C1xx support' CONFIG_SMC91X + fi + bool ' Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL + if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then +--- linux-2.4.25/drivers/net/Makefile~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/net/Makefile 2004-03-31 17:15:11.000000000 +0200 +@@ -137,6 +137,7 @@ + obj-$(CONFIG_SK_G16) += sk_g16.o + obj-$(CONFIG_HP100) += hp100.o + obj-$(CONFIG_SMC9194) += smc9194.o ++obj-$(CONFIG_SMC91X) += smc91x.o + obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o + obj-$(CONFIG_ARM_ETHERH) += 8390.o + obj-$(CONFIG_WD80x3) += wd.o 8390.o +--- linux-2.4.25/drivers/net/cirrus.c~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/net/cirrus.c 2004-03-31 17:15:11.000000000 +0200 +@@ -67,6 +67,9 @@ + #elif CONFIG_ARCH_CDB89712 + # define CIRRUS_DEFAULT_IO ETHER_BASE + 0x300 + # define CIRRUS_DEFAULT_IRQ IRQ_EINT3 ++#elif CONFIG_ARCH_CSB226 ++# define CIRRUS_DEFAULT_IO 0xF8000000 ++# define CIRRUS_DEFAULT_IRQ IRQ_GPIO(14) + #else + # define CIRRUS_DEFAULT_IO 0 + # define CIRRUS_DEFAULT_IRQ 0 +--- linux-2.4.25/drivers/net/irda/Config.in~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/net/irda/Config.in 2004-03-31 17:15:11.000000000 +0200 +@@ -42,5 +42,7 @@ + if [ "$CONFIG_ARCH_SA1100" = "y" ]; then + dep_tristate 'SA1100 Internal IR' CONFIG_SA1100_FIR $CONFIG_IRDA $CONFIG_EXPERIMENTAL + fi +- ++if [ "$CONFIG_ARCH_PXA" = "y" ]; then ++ dep_tristate 'Intel PXA2xx Internal IR' CONFIG_PXA_FIR $CONFIG_IRDA $CONFIG_EXPERIMENTAL ++fi + endmenu +--- linux-2.4.25/drivers/net/irda/Makefile~2.4.25-vrs2-pxa1.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/net/irda/Makefile 2004-03-31 17:15:12.000000000 +0200 +@@ -16,6 +16,7 @@ + obj-$(CONFIG_USB_IRDA) += irda-usb.o + obj-$(CONFIG_NSC_FIR) += nsc-ircc.o + obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o ++obj-$(CONFIG_PXA_FIR) += pxa_ir.o + obj-$(CONFIG_SA1100_FIR) += sa1100_ir.o + obj-$(CONFIG_TOSHIBA_OLD) += toshoboe.o + obj-$(CONFIG_TOSHIBA_FIR) += donauboe.o +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/net/irda/pxa_ir.c 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,1545 @@ ++/* ++ * linux/drivers/net/irda/pxa_ir.c ++ * ++ * Author: ++ * Alexey Lugovskoy RTSoft. ++ * lugovskoy@rtsoft.msk.ru ++ * ++ * Dmitrij Frasenyak RTSoft. ++ * sed@mipt.sw.ru ++ * ++ * 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. ++ * ++ * Infra-red SIR and FIR driver for the PXA 210/250 embedded microprocessors ++ * Based on linux/drivers/net/irda/sa1100_ir.c ++ * ++ */ ++ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/errno.h> ++#include <linux/netdevice.h> ++#include <linux/slab.h> ++#include <linux/rtnetlink.h> ++#include <linux/interrupt.h> ++#include <linux/delay.h> ++#include <linux/ioport.h> ++#include <linux/delay.h> ++ ++#include <linux/pm.h> ++ ++#include <net/irda/irda.h> ++#include <net/irda/irmod.h> ++#include <net/irda/wrapper.h> ++#include <net/irda/irda_device.h> ++ ++#include <asm/irq.h> ++#include <asm/dma.h> ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++#include <asm/arch/lubbock.h> ++ ++ ++static int rx_count = 0; ++static int tx_count = 0; ++ ++/* ++ * Our netdevice. There is only ever one of these. ++ */ ++ ++static struct net_device *netdev; ++ ++struct pxa250_irda { ++ ++ unsigned char open; ++ ++ int speed; ++ int newspeed; ++ ++ struct sk_buff *txskb; ++ struct sk_buff *rxskb; ++ ++ ++ /* => FIR */ ++ unsigned int fir_irq; ++ int txdma_ch; ++ int rxdma_ch; ++ dma_addr_t txbuf_dma; ++ dma_addr_t rxbuf_dma; ++ void* txbuf_dma_virt; ++ void* rxbuf_dma_virt; ++ /* <= FIR*/ ++ struct net_device_stats stats; ++ struct irlap_cb *irlap; ++ struct pm_dev *pmdev; ++ struct qos_info qos; ++ ++ /* => SIR */ ++ iobuff_t tx_buff; ++ iobuff_t rx_buff; ++ /* <= SIR */ ++}; ++ ++#define IS_FIR(si) ((si)->speed >= 4000000) ++ ++#define HPSIR_MAX_RXLEN 2050 ++#define HPSIR_MAX_TXLEN 2050 ++#define TXBUFF_MAX_SIZE HPSIR_MAX_TXLEN ++#define SET_SIR_MODE STISR = STISR_RCVEIR | STISR_XMITIR | STISR_XMODE ++ ++/* ++ * If you want to disable debug information ++ * please uncomment line bellow ++ */ ++ ++#define PXA_FIR_DUMP_ENABLE ++#undef PXA_FIR_DUMP_ENABLE ++ ++ ++#define PXA_FIR_DEBUG_ENABLE ++#undef PXA_FIR_DEBUG_ENABLE ++ ++#define PXA_FIR_IRQ_DEBUG_ENABLE ++#undef PXA_FIR_IRQ_DEBUG_ENABLE ++ ++#ifdef PXA_FIR_DEBUG_ENABLE ++#define __ECHO_IN printk(KERN_ERR "%s: enter\n",__FUNCTION__); ++#define __ECHO_OUT printk(KERN_ERR "%s: exit\n",__FUNCTION__); ++#define DBG(args...) printk(KERN_ERR __FUNCTION__"():"args); ++#else ++#define __ECHO_IN ++#define __ECHO_OUT ++#define DBG(args...) ++#endif ++ ++#ifdef PXA_FIR_IRQ_DEBUG_ENABLE ++#define DBG_IRQ(args...) printk(KERN_ERR __FUNCTION__"():"args); ++#else ++#define DBG_IRQ(args...) ++#endif ++ ++ ++static int pxa250_irda_set_speed(struct net_device *dev,int speed); ++static void pxa250_start_rx_dma(struct net_device *dev); ++ ++ ++ ++/************************************************************************** ++ * Misc FIR/SIR functions * ++ **************************************************************************/ ++/* ++ * Allocate the receive buffer, unless it is already allocated. ++ */ ++ ++static int pxa250_irda_rx_alloc(struct pxa250_irda *si) ++{ ++ __ECHO_IN; ++ ++ if (si->rxskb) ++ return 0; ++ ++ si->rxskb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC); ++ ++ if (!si->rxskb) { ++ printk(KERN_ERR "pxa250_ir: out of memory for RX SKB\n"); ++ return -ENOMEM; ++ } ++ ++ /* ++ * Align any IP headers that may be contained ++ * within the frame. ++ */ ++ skb_reserve(si->rxskb, 1); ++ ++ __ECHO_OUT; ++ ++ return 0; ++} ++ ++ ++ ++/************************************************************************** ++ * FIR * ++ **************************************************************************/ ++ ++ ++ ++ ++static inline void pxa250_dma_stop(int ch) ++{ ++ __ECHO_IN; ++ ++ DCSR(ch) &= ~DCSR_RUN; ++ ++ __ECHO_OUT; ++ ++} ++ ++ ++static void pxa250_ficp_rx_start(void) ++{ ++ ICCR0 = 0; ++ ICCR2 = 1 << 2 | 0 << 3 ; ++ ICCR0 = ICCR0_ITR ; ++ ICCR0 |= ICCR0_RIE | ICCR0_RXE ; ++} ++ ++/* ++ * Change Alternative Function encoding ++ * Enable ICP unit ++ * Disabe STUART unit ++ * Enable IRQ unit clock; ++ * Configure direction of GPIO used by ICP ++ */ ++ ++ ++static void pxa250_do_fir_GPIO_config(void) ++{ ++ /* ++ * Modify GPIO 46 and 47 Alternate Function ++ */ ++ ++ __ECHO_IN; ++ ++ /*Switch AF*/ ++ set_GPIO_mode (GPIO46_ICPRXD_MD); ++ set_GPIO_mode (GPIO47_ICPTXD_MD); ++ ++ if (machine_is_lubbock()) ++ LUB_MISC_WR |= 1 << 4; ++ ++ /*init clock*/ ++ CKEN |= CKEN13_FICP; ++ ++ __ECHO_OUT; ++} ++ ++/* ++ * Low level hardware configuration and startup. ++ */ ++ ++static int pxa250_fir_irda_startup(struct pxa250_irda *si) ++{ ++ ++ __ECHO_IN; ++ ++ /* ++ * Disable STUART ++ */ ++ ++ STIER &= ~IER_UUE; ++ ++ /*Disable STUART FIFO */ ++ STFCR = 0; ++ ++ /* ++ * Do low level configuration for HW AF and clock ++ */ ++ pxa250_do_fir_GPIO_config(); ++ ++ __ECHO_OUT; ++ return 0; ++} ++ ++ ++/* ++ * Aieeeeee .. we should never get here :( ++ */ ++static void pxa250_irda_rxdma_irq(int ch,void *id, struct pt_regs *regs) ++{ ++ struct net_device *dev=id; ++ struct pxa250_irda *si=dev->priv; ++ u_int dcsr; ++ ++ ++ __ECHO_IN; ++ ++ /* ++ * Make sure that irq is our. ++ */ ++ ++ if ( ch != si->rxdma_ch ) ++ /*just*/ return; ++ ++ /* ++ * Check status ++ */ ++ dcsr = DCSR(ch); ++ ++ DBG("DCSR=%x\n",dcsr); ++ ++ if (dcsr & DCSR_STOPSTATE ) ++ { ++ DBG_IRQ("Chanel %d in stop state\n",ch); ++ } ++ ++ if (dcsr & DCSR_BUSERR ) ++ { ++ /* ++ * BUS Error we must restart reception ++ */ ++ ++ DBG("PXA IrDA: bus error interrupt on channel %d\n", ch); ++ DCSR(ch) |= DCSR_BUSERR; ++ } ++ ++ if (dcsr & DCSR_ENDINTR ) ++ { ++ DBG("PXA IrDA: Normal end of dma channel %d - packet to big\n", ch); ++ DCSR(ch) |= DCSR_ENDINTR; ++ } ++ ++ /* no mater what restart rx*/ ++ pxa250_start_rx_dma(dev); ++ ++ return ; ++ ++} ++ ++ ++static void pxa250_irda_txdma_irq(int ch, void *id , struct pt_regs *regs) ++{ ++ struct net_device *dev=id; ++ struct pxa250_irda *si=dev->priv; ++ struct sk_buff *skb = si->txskb; ++ u_int dcsr; ++ ++ ++ __ECHO_IN; ++ DBG_IRQ("transmit\n"); ++ ++ ++ /* ++ * Make sure that irq is our. ++ */ ++ ++ if ( ch != si->txdma_ch ) ++ /*just*/ return; ++ ++ ++ /* ++ * Check status ++ */ ++ dcsr = DCSR(ch); ++ ++ DBG("DCSR=%x",dcsr); ++ ++ if (dcsr & DCSR_STOPSTATE ) ++ { ++ DBG("Chanel %d in stop state\n",ch); ++ } ++ ++ if (dcsr & DCSR_BUSERR ) ++ { ++ DBG("PXA IrDA: bus error interrupt on channel %d\n", ch); ++ DCSR(ch) |= DCSR_BUSERR; ++ si->txskb = NULL; ++ } ++ ++ if (dcsr & DCSR_ENDINTR ) ++ { ++ DBG("PXA IrDA: Normal end of dma channel %d\n", ch); ++ DCSR(ch) |= DCSR_ENDINTR; ++ si->txskb = NULL; ++ } ++ ++ /* ++ * Account and free the packet. ++ */ ++ if (skb) ++ { ++ si->stats.tx_packets ++; ++ si->stats.tx_bytes += skb->len; ++ dev_kfree_skb_irq(skb); ++ } ++ ++ /*Disable transceiver and enable receiver*/ ++ ++ if (si->newspeed) { ++ pxa250_irda_set_speed(dev, si->newspeed); ++ si->newspeed = 0; ++ } ++ ++ while (ICSR1 & ICSR1_TBY) ++ udelay(1); ++ ++ ICCR0 &= ~ICCR0_TXE; ++ ++ ++ enable_irq(si->fir_irq); ++ ++ ICCR0 |= ICCR0_RXE; ++ ++ /* ++ * Make sure that the TX queue is available for sending ++ * (for retries). TX has priority over RX at all times. ++ */ ++ netif_wake_queue(dev); ++ ++ __ECHO_OUT; ++} ++ ++ ++static void pxa250_start_rx_dma(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ int ch=si->rxdma_ch; ++ ++ if (!si->rxskb) { ++ DBG("rx buffer went missing\n"); ++/* return; */ ++ } ++ ++ DCSR(ch)=0; ++ DCSR(ch)=DCSR_NODESC; ++ DSADR(ch) = __PREG(ICDR); ++ DTADR(ch) = si->rxbuf_dma; /* phisical address */; ++ ++ /* We should never do END_IRQ. !!!*/ ++ DCMD(ch) = DCMD_ENDIRQEN| DCMD_INCTRGADDR | DCMD_FLOWSRC | DCMD_BURST8 | DCMD_WIDTH1 | HPSIR_MAX_RXLEN; ++ ++ /* ++ * All right information will be available as soon as we set RXE flag ++ */ ++ ++ DCSR(ch) = DCSR_ENDINTR | DCSR_BUSERR; ++ DCSR(ch) = DCSR_RUN | DCSR_NODESC ; ++ ++} ++ ++ ++ ++ ++static int pxa250_get_rx_len(struct pxa250_irda *si) ++{ ++ /* ++ * DMA have to be stoped here ++ */ ++ ++ if ( ! (DCSR(si->rxdma_ch) & DCSR_STOPSTATE) ) ++ printk("warning dma have to be stoped befor counting len\n"); ++ ++ return ( HPSIR_MAX_RXLEN - ( DCMD(si->rxdma_ch) & DCMD_LENGTH ) ); ++ ++} ++ ++static void pxa250_irda_fir_error(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ struct sk_buff *skb = si->rxskb; ++ int len; ++ int stat,data; ++ ++ __ECHO_IN; ++ ++ if (!skb) ++ { ++ printk("pxa250 fir_error: SKB is NULL!\n"); ++ return; ++ } ++ ++ /* ++ * Get the current data position. ++ */ ++ ++ len=pxa250_get_rx_len(si); ++ DBG("RXLEN=%d\n",len); ++ memcpy(skb->data, si->rxbuf_dma_virt, len); ++ ++ do { ++ /* ++ * Read Status, and then Data. ++ */ ++ stat = ICSR1; ++ rmb(); ++ data = ICDR; ++ if (stat & (ICSR1_CRE | ICSR1_ROR)) { ++ si->stats.rx_errors++; ++ if (stat & ICSR1_CRE) ++ si->stats.rx_crc_errors++; ++ if (stat & ICSR1_ROR) ++ si->stats.rx_frame_errors++; ++ } else ++ skb->data[len++] = data; ++ ++ /* ++ * If we hit the end of frame, there's ++ * no point in continuing. ++ */ ++ if (stat & ICSR1_EOF) ++ break; ++ } while (ICSR0 & ICSR0_EIF); ++ ++ if (stat & ICSR1_EOF) { ++ si->rxskb = NULL; ++ ++ skb_put(skb, len); ++ skb->dev = dev; ++ skb->mac.raw = skb->data; ++ skb->protocol = htons(ETH_P_IRDA); ++ si->stats.rx_packets++; ++ si->stats.rx_bytes += len; ++ ++ /* ++ * Before we pass the buffer up, allocate a new one. ++ */ ++ ++ si->rxskb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC); ++ ++ if (!si->rxskb) { ++ printk(KERN_ERR "pxa250_ir: out of memory for RX SKB\n"); ++ return; ++ } ++ ++ /* ++ * Align any IP headers that may be contained ++ * within the frame. ++ */ ++ skb_reserve(si->rxskb, 1); ++ ++ netif_rx(skb); ++ } ++} ++ ++/* ++ * FIR format interrupt service routine. We only have to ++ * handle RX events; transmit events go via the TX DMA irq handler. ++ * ++ * No matter what, we disable RX, process, and then restart RX. ++ */ ++ ++static void pxa250_irda_fir_irq(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ struct net_device *dev = dev_id; ++ struct pxa250_irda *si = dev->priv; ++ int status; ++ ++ /* ++ * Stop RX ++ */ ++ ++ __ECHO_IN; ++ ++ pxa250_dma_stop(si->rxdma_ch); ++ ++ ++ /* ++ * Framing error - we throw away the packet completely. ++ * Clearing RXE flushes the error conditions and data ++ * from the fifo. ++ */ ++ status=ICSR0; ++ ++ if (status & (ICSR0_FRE | ICSR0_RAB)) { ++ DBG_IRQ("Framing error or RAB\n"); ++ ++ si->stats.rx_errors++; ++ ++ if (ICSR0 & ICSR0_FRE) ++ si->stats.rx_frame_errors++; ++ ++ /* Clear RX fifo ++ * DMA will be cleared when we restart RX ++ * Should we check RNE after that? ++ */ ++ ++ ICCR0 &= ~ICCR0_RXE; ++ ++ /* ++ * Clear selected status bits now, so we ++ * don't miss them next time around. ++ */ ++ ICSR0 = status & (ICSR0_FRE | ICSR0_RAB); ++ } ++ ++ ++ /* ++ * Deal with any receive errors. The any of the lowest ++ * 8 bytes in the FIFO may contain an error. We must read ++ * them one by one. The "error" could even be the end of ++ * packet! ++ */ ++ if (ICSR0 & ICSR0_EIF) ++ pxa250_irda_fir_error(dev); ++ ++ /* ++ * No matter what happens, we must restart reception. ++ */ ++ ++ ICCR0 = 0; ++ pxa250_start_rx_dma(dev); ++ pxa250_ficp_rx_start(); ++ __ECHO_OUT; ++} ++ ++ ++ ++ ++ ++/************************************************************************** ++ * SIR * ++ **************************************************************************/ ++/* ++ * HP-SIR format interrupt service routines. ++ */ ++static void pxa250_sir_transmit(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ ++ if (si->tx_buff.len) ++ { ++ /* Disable receiver and enable transmiter*/ ++ ++ ++ ++ STISR &= ~STISR_RCVEIR; ++// STISR |= STISR_XMITIR; ++ ++ ++ ++ disable_irq(dev->irq); ++ ++ do ++ { ++ ++ if (STLSR & LSR_TDRQ) ++ { ++ STTHR = *si->tx_buff.data++; ++ si->tx_buff.len -= 1; ++ ++ tx_count++; ++ } ++ ++ ++ } while (si->tx_buff.len); ++ ++ ++ if (si->tx_buff.len == 0) ++ { ++ ++ ++ si->stats.tx_packets++; ++ si->stats.tx_bytes += si->tx_buff.data - ++ si->tx_buff.head; ++ ++ /* ++ * We need to ensure that the transmitter has ++ * finished. ++ */ ++ ++ do ++ { ++ udelay(1); ++ ++ } ++ while ( ! (STLSR & LSR_TEMT) ); ++ ++ ++ /* ++ ++ * Ok, we've finished transmitting. Now enable ++ * the receiver. Sometimes we get a receive IRQ ++ * immediately after a transmit... ++ */ ++ ++ if (si->newspeed) ++ { ++ pxa250_irda_set_speed(dev, si->newspeed); ++ si->newspeed = 0; ++ } ++ ++ /* I'm hungry! */ ++ netif_wake_queue(dev); ++ } ++ ++ enable_irq (dev->irq); ++ STIER = (IER_RAVIE | IER_UUE | IER_RTIOE); ++ ++ STISR |= STISR_RCVEIR; ++// STISR &= ~STISR_XMITIR; ++ } ++} ++ ++static void pxa250_irda_hpsir_irq(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ ++ /* ++ * Deal with any receive errors first. The bytes in error may be ++ * the only bytes in the receive FIFO, so we do this first. ++ */ ++ __ECHO_IN; ++ ++ while (STLSR & LSR_FIFOE) ++ { ++ int stat, data; ++ ++ stat = STLSR; ++ data = STRBR; ++ ++ ++ if (stat & (LSR_FE | LSR_OE | LSR_PE)) ++ ++ { ++ si->stats.rx_errors++; ++ if (stat & LSR_FE) ++ si->stats.rx_frame_errors++; ++ if (stat & LSR_OE) ++ si->stats.rx_fifo_errors++; ++ ++ } else ++ { ++ rx_count++; ++ async_unwrap_char(dev, &si->stats, &si->rx_buff, data); ++ } ++ ++ } ++ ++ /* ++ * We must clear certain bits. ++ */ ++ ++ if (STLSR & (LSR_DR)) ++ { ++ /* ++ * Fifo contains at least 1 character. ++ */ ++ do ++ { ++ int data; ++ ++ data = STRBR; ++ ++ async_unwrap_char(dev, &si->stats, &si->rx_buff, ++ data); /* was Ser2UTDR); Clo */ ++ rx_count++; ++ ++ } while (STLSR & LSR_DR); ++ ++ dev->last_rx = jiffies; ++ } ++ ++ __ECHO_OUT; ++} ++ ++static void pxa250_sir_irda_shutdown(struct pxa250_irda *si) ++{ ++ ++ STIER = 0; ++ STFCR = 0; ++ STISR = 0; ++ CKEN &= ~CKEN5_STUART; ++} ++ ++ ++/************************************************************************************/ ++ ++/*Low level init/uninstall function PM control and IrDA protocol stack registration */ ++ ++/* ++ * Set the IrDA communications speed. ++ * Interrupt have to be disabled here. ++ */ ++ ++static int pxa250_irda_startup(struct net_device *dev) ++{ ++ ++ ++ __ECHO_IN; ++ ++ /* ++ * Ensure that the ports for this device are setup correctly. ++ */ ++ ++ ++ set_GPIO_mode (GPIO46_STRXD_MD); ++ set_GPIO_mode (GPIO47_STTXD_MD); ++ ++ STMCR = MCR_OUT2; ++ STLCR = LCR_WLS1 | LCR_WLS0; ++ ++ SET_SIR_MODE; ++ CKEN |= CKEN5_STUART; ++ /* enable irq from stuart */ ++ ICMR |= ( 1 << 20 ); ++ ++ /*reset FIFO*/ ++ ++/* STFCR = FCR_TRFIFOE | FCR_RESETTF | FCR_RESETRF;// | FCR_ITL_16; ++ ++ STIER = IER_UUE | IER_RAVIE | IER_RTOIE; ++*/ ++ __ECHO_OUT; ++ ++ return 0; ++ ++} ++ ++ ++#ifdef CONFIG_PM ++/* ++ * Suspend the IrDA interface. ++ */ ++ ++static int pxa250_irda_shutdown(struct pxa250_irda *si) ++{ ++ ++ pxa250_sir_irda_shutdown(si); ++ return 0; ++ ++} ++ ++ ++static int pxa250_irda_suspend(struct net_device *dev, int state) ++{ ++ struct pxa250_irda *si = dev->priv; ++ ++ if (si && si->open) { ++ /* ++ * Stop the transmit queue ++ */ ++ if (IS_FIR(si)) ++ return -1; ++ ++ netif_stop_queue(dev); ++ disable_irq(dev->irq); ++ disable_irq(si->fir_irq); ++ pxa250_sir_irda_shutdown(si); ++ } ++ ++ return 0; ++} ++ ++/* ++ * Resume the IrDA interface. ++ */ ++ ++static int pxa250_irda_resume(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ ++ __ECHO_IN; ++ ++ if (si && si->open) { ++ /* ++ * If we missed a speed change, initialise at the new speed ++ * directly. It is debatable whether this is actually ++ * required, but in the interests of continuing from where ++ * we left off it is desireable. The converse argument is ++ * that we should re-negotiate at 9600 baud again. ++ */ ++ if (si->newspeed) { ++ si->speed = si->newspeed; ++ si->newspeed = 0; ++ } ++ ++ pxa250_irda_startup(dev); ++ enable_irq(dev->irq); ++ ++ /* ++ * This automatically wakes up the queue ++ */ ++ netif_wake_queue(dev); ++ pxa250_irda_set_speed(dev,si->speed = 9600); ++ ++ } ++ ++ __ECHO_OUT; ++ return 0; ++} ++ ++static int pxa250_irda_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data) ++{ ++ int ret; ++ ++ ++ if (!dev->data) ++ return -EINVAL; ++ ++ ++ switch (rqst) { ++ case PM_SUSPEND: ++ ret = pxa250_irda_suspend((struct net_device *)dev->data, ++ (int)data); ++ break; ++ ++ case PM_RESUME: ++ ret = pxa250_irda_resume((struct net_device *)dev->data); ++ break; ++ ++ default: ++ ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++#endif ++ ++ ++ ++ ++static void pxa250_irda_irq(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ struct net_device *dev = dev_id; ++ ++ pxa250_irda_hpsir_irq(dev); ++ ++} ++ ++ ++static int pxa250_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ int speed = irda_get_next_speed(skb); ++ int mtt; ++ ++ __ECHO_IN; ++ ++ /* ++ * Does this packet contain a request to change the interface ++ * speed? If so, remember it until we complete the transmission ++ * of this frame. ++ */ ++ if (speed != si->speed && speed != -1) ++ si->newspeed = speed; ++ ++ /* ++ * If this is an empty frame, we can bypass a lot. ++ */ ++ if (skb->len == 0) { ++ if (si->newspeed) { ++ si->newspeed = 0; ++ pxa250_irda_set_speed(dev, speed); ++ } ++ dev_kfree_skb(skb); ++ return 0; ++ } ++ ++ ++ DBG("stop queue\n"); ++ netif_stop_queue(dev); ++ ++ if(!IS_FIR(si)) ++ { ++ ++ si->tx_buff.data = si->tx_buff.head; ++ si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, ++ si->tx_buff.truesize); ++ ++ ++ pxa250_sir_transmit(dev); ++ ++ ++ ++ dev_kfree_skb(skb); ++ ++ dev->trans_start = jiffies; ++ ++ return 0; ++ } ++ else /* FIR */ ++ { ++ DBG("Enter FIR transmit\n"); ++ /* ++ * We must not be transmitting... ++ */ ++ if (si->txskb) ++ BUG(); ++ ++ disable_irq(si->fir_irq); ++ ++ netif_stop_queue(dev); ++ DBG("queue stoped\n"); ++ si->txskb = skb; ++ ++ /* we could not just map so we'll need some triks */ ++ /* skb->data may be not DMA capable -Sed- */ ++ ++ ++ if (skb->len > TXBUFF_MAX_SIZE) ++ { ++ printk (KERN_ERR "skb data too large\n"); ++ printk (KERN_ERR "len=%d",skb->len); ++ BUG(); ++ } ++ ++ ++ DBG("gonna copy %d bytes to txbuf\n",skb->len); ++ ++ memcpy (si->txbuf_dma_virt, skb->data , skb->len); ++ ++ /* Actual sending ;must not be receiving !!! */ ++ /* Write data and source address */ ++ ++ DBG("ICSR1 & RNE =%d\n",(ICSR1 & ICSR1_RNE) ? 1 : 0 ); ++ ++ /*Disable receiver and enable transifer */ ++ ICCR0 &= ~ICCR0_RXE; ++ ++ if (ICSR1 & ICSR1_TBY) ++ BUG(); ++ ++ ICCR0 |= ICCR0_TXE; ++ ++ DBG("FICP status %x\n",ICSR0); ++ ++ if (0){ ++ int i; ++ ++ DBG("sending packet\n"); ++ for (i=0;i<skb->len;i++) ++ (i % 64) ? printk ("%2x ",skb->data[i]) : printk ("%2x \n",skb->data[i]) ; ++ DBG(" done\n"); ++ ++ } ++ /* ++ * If we have a mean turn-around time, impose the specified ++ * specified delay. We could shorten this by timing from ++ * the point we received the packet. ++ */ ++ ++ mtt = irda_get_mtt(skb); ++ if(mtt) ++ udelay(mtt); ++ ++ DCSR(si->txdma_ch)=0; ++ DCSR(si->txdma_ch)=DCSR_NODESC; ++ DSADR(si->txdma_ch) = si->txbuf_dma; /* phisic address */ ++ DTADR(si->txdma_ch) = __PREG(ICDR); ++ ++ DCMD(si->txdma_ch) = DCMD_ENDIRQEN| DCMD_INCSRCADDR | DCMD_FLOWTRG | DCMD_BURST8 | DCMD_WIDTH1 | skb->len; ++ ++ DCSR(si->txdma_ch) = DCSR_ENDINTR | DCSR_BUSERR; ++ DCSR(si->txdma_ch) = DCSR_RUN | DCSR_NODESC ; ++ ++ DBG("FICP status %x\n",ICSR0); ++ ++ return 0; ++ } ++ ++} ++ ++static int ++pxa250_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) ++{ ++ struct if_irda_req *rq = (struct if_irda_req *)ifreq; ++ struct pxa250_irda *si = dev->priv; ++ int ret = -EOPNOTSUPP; ++ ++ __ECHO_IN; ++ ++ switch (cmd) { ++ case SIOCSBANDWIDTH: ++ if (capable(CAP_NET_ADMIN)) { ++ /* ++ * We are unable to set the speed if the ++ * device is not running. ++ */ ++ if (si->open) { ++ ret = pxa250_irda_set_speed(dev, ++ rq->ifr_baudrate); ++ } else { ++ printk("pxa250_irda_ioctl: SIOCSBANDWIDTH: !netif_running\n"); ++ ret = 0; ++ } ++ } ++ break; ++ ++ case SIOCSMEDIABUSY: ++ ret = -EPERM; ++ if (capable(CAP_NET_ADMIN)) { ++ irda_device_set_media_busy(dev, TRUE); ++ ret = 0; ++ } ++ break; ++ ++ case SIOCGRECEIVING: ++ rq->ifr_receiving = IS_FIR(si) ? 0 ++ : si->rx_buff.state != OUTSIDE_FRAME; ++ break; ++ ++ default: ++ break; ++ } ++ ++ __ECHO_OUT; ++ ++ return ret; ++} ++ ++static struct net_device_stats *pxa250_irda_stats(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ return &si->stats; ++} ++ ++static int pxa250_irda_start(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ int err; ++ unsigned int flags; ++ ++ ++ MOD_INC_USE_COUNT; ++ ++ __ECHO_IN; ++ si->speed = 9600; ++ ++ local_irq_save(flags); ++ ++ err = request_irq(si->fir_irq, pxa250_irda_fir_irq, 0, dev->name, dev); ++ if (err) ++ goto err_fir_irq; ++ ++ err = request_irq(dev->irq, pxa250_irda_irq, 0, dev->name, dev); ++ if (err) ++ goto err_irq; ++ ++ /* ++ * The interrupt must remain disabled for now. ++ */ ++ ++ disable_irq(dev->irq); ++ disable_irq(si->fir_irq); ++ ++ local_irq_restore(flags); ++ ++ ++ /* Allocate DMA channel for receiver (not used) */ ++ err = pxa_request_dma("IrDA receive", DMA_PRIO_LOW, pxa250_irda_rxdma_irq, dev); ++ if (err < 0 ) ++ goto err_rx_dma; ++ si->rxdma_ch=err; ++ ++ DRCMRRXICDR = DRCMR_MAPVLD | si->rxdma_ch; ++ ++ ++ /* Allocate DMA channel for transmit */ ++ err = pxa_request_dma("IrDA transmit", DMA_PRIO_LOW, pxa250_irda_txdma_irq , dev); ++ if (err < 0 ) ++ goto err_tx_dma; ++ ++ si->txdma_ch=err; ++ ++ /* ++ * Make sure that ICP will be able ++ * to assert the transmit dma request bit ++ * through the peripherals request bus (PREQ) ++ */ ++ ++ DRCMRTXICDR = DRCMR_MAPVLD | si->txdma_ch; ++ ++ DBG("rx(not used) channel=%d tx channel=%d\n",si->rxdma_ch,si->txdma_ch); ++ ++ /* allocate consistent buffers for dma access ++ * buffers have to be aligned and situated in dma capable memory region; ++ */ ++ si->rxbuf_dma_virt = consistent_alloc(GFP_KERNEL | GFP_DMA ,HPSIR_MAX_RXLEN , &si->rxbuf_dma); ++ if (! si->rxbuf_dma_virt ) ++ goto err_rxbuf_dma; ++ ++ si->txbuf_dma_virt = consistent_alloc(GFP_KERNEL | GFP_DMA, HPSIR_MAX_TXLEN, &si->txbuf_dma); ++ if (! si->txbuf_dma_virt ) ++ goto err_txbuf_dma; ++ ++ /* Alocate skb for receiver */ ++ err=pxa250_irda_rx_alloc(si); ++ if (err) ++ goto err_rx_alloc; ++ ++ /* ++ * Setup the serial port for the specified config. ++ */ ++ err = pxa250_irda_startup(dev); ++ if (err) ++ goto err_startup; ++ ++ pxa250_irda_set_speed(dev,si->speed = 9600); ++ ++ ++ /* ++ * Open a new IrLAP layer instance. ++ */ ++ si->irlap = irlap_open(dev, &si->qos, "pxa250"); ++ err = -ENOMEM; ++ if (!si->irlap) ++ goto err_irlap; ++ ++ /* ++ * Now enable the interrupt and start the queue ++ */ ++ si->open = 1; ++ enable_irq(dev->irq); ++ netif_start_queue(dev); ++ return 0; ++ ++err_irlap: ++ si->open = 0; ++ pxa250_sir_irda_shutdown(si); ++err_startup: ++ dev_kfree_skb(si->rxskb); ++err_rx_alloc: ++ consistent_free (si->txbuf_dma_virt,HPSIR_MAX_TXLEN,si->txbuf_dma); ++err_txbuf_dma: ++ consistent_free (si->rxbuf_dma_virt,HPSIR_MAX_RXLEN,si->rxbuf_dma); ++err_rxbuf_dma: ++ pxa_free_dma(si->txdma_ch); ++err_tx_dma: ++ pxa_free_dma(si->rxdma_ch); ++err_rx_dma: ++ free_irq(dev->irq, dev); ++err_irq: ++ free_irq(si->fir_irq, dev); ++err_fir_irq: ++ MOD_DEC_USE_COUNT; ++ return err; ++} ++ ++static int pxa250_irda_stop(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ ++ printk(KERN_ERR "Irda stop... RX = %d TX = %d\n",rx_count,tx_count); ++ ++ disable_irq(dev->irq); ++ disable_irq(si->fir_irq); ++/* pxa250_irda_shutdown(si); */ ++ ++ /* ++ * If we have been doing DMA receive, make sure we ++ * tidy that up cleanly. ++ */ ++ if (si->rxskb) { ++ dev_kfree_skb(si->rxskb); ++ si->rxskb = NULL; ++ } ++ ++ /* Stop IrLAP */ ++ if (si->irlap) { ++ irlap_close(si->irlap); ++ si->irlap = NULL; ++ } ++ ++ consistent_free (si->txbuf_dma_virt,HPSIR_MAX_TXLEN,si->txbuf_dma); ++ consistent_free (si->rxbuf_dma_virt,HPSIR_MAX_RXLEN,si->rxbuf_dma); ++ pxa_free_dma(si->txdma_ch); ++ pxa_free_dma(si->rxdma_ch); ++ ++ netif_stop_queue(dev); ++ si->open = 0; ++ ++ /* ++ * Free resources ++ */ ++ free_irq(dev->irq, dev); ++ free_irq(si->fir_irq, dev); ++ ++ ++ MOD_DEC_USE_COUNT; ++ ++ return 0; ++} ++ ++static int pxa250_irda_init_iobuf(iobuff_t *io, int size) ++{ ++ io->head = kmalloc(size, GFP_KERNEL | GFP_DMA); ++ if (io->head != NULL) { ++ io->truesize = size; ++ io->in_frame = FALSE; ++ io->state = OUTSIDE_FRAME; ++ io->data = io->head; ++ } ++ return io->head ? 0 : -ENOMEM; ++} ++ ++ ++ ++ ++static int pxa250_stop_fir(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ unsigned int flag; ++ ++ save_flags(flag); ++ cli(); ++ ++ pxa250_dma_stop(si->txdma_ch); ++ pxa250_dma_stop(si->rxdma_ch); ++ ++ if (si->txskb) ++ dev_kfree_skb_irq(si->txskb); ++ ++ ICCR0 &= ~(ICCR0_RXE | ICCR0_TXE ); ++ disable_irq(si->fir_irq); ++ CKEN &= ~CKEN13_FICP; ++ ++ restore_flags(flag); ++ ++ return 0; ++} ++ ++ ++ ++static int pxa250_irda_set_speed(struct net_device *dev, int speed) ++{ ++ struct pxa250_irda *si = dev->priv; ++ int brd, ret = -EINVAL; ++ static int last_fir_speed=0; ++ ++ __ECHO_IN; ++ ++ ++ ++ switch (speed) { ++ case 9600: case 19200: case 38400: ++ case 57600: case 115200: ++ ++ /* Baud rate fixed - Clo */ ++ ++ /* ++ * FIXME ++ */ ++ if (last_fir_speed) ++ { ++ ++ pxa250_stop_fir(dev); ++ set_GPIO_mode (GPIO46_STRXD_MD); ++ set_GPIO_mode (GPIO47_STTXD_MD); ++ ++ enable_irq(dev->irq); ++ netif_wake_queue(dev); ++ last_fir_speed=0; ++ } ++ ++ ++ LUB_MISC_WR &= ~(1 << 4); ++ ++ brd = 14745600 / (16 * speed); ++ ++ STLCR |= LCR_DLAB; ++ ++ STDLH = brd >> 8; /* Clo: set Divisor Latch High */ ++ STDLL = brd & 0xFF; /* Clo: set Devisor Latch Low */ ++ ++ STLCR &= ~LCR_DLAB; /* Clo: clear DLAB bit */ ++ ++ STMCR = MCR_OUT2; ++ ++ CKEN |= CKEN5_STUART; ++ ++ ICMR |= ( 1 << 20 ); ++ ++ STLCR = LCR_WLS1 | LCR_WLS0; ++ ++ SET_SIR_MODE; ++ ++ STFCR = FCR_TRFIFOE | FCR_RESETTF | FCR_RESETRF | FCR_ITL_1 ;// | FCR_ITL_16; ++ ++ STIER = IER_UUE | IER_RAVIE | IER_RTIOE; ++ ++ si->speed = speed; ++ ++ ret = 0; ++ break; ++ ++ case 4000000: ++ ++ if (last_fir_speed) ++ goto speed_out; ++ ++ disable_irq(dev->irq); ++ ++ pxa250_sir_irda_shutdown(si); ++ pxa250_fir_irda_startup(si); ++ pxa250_irda_rx_alloc(si); ++ ICCR0=0; ++ pxa250_start_rx_dma(dev); ++ pxa250_ficp_rx_start(); ++ ++ enable_irq(si->fir_irq); ++ DBG("enable FIR \n"); ++ si->speed = speed; ++ ++ netif_wake_queue(dev); ++ last_fir_speed=1; ++speed_out: ++ ++ ret=0; ++ ++ break; ++ ++ default: ++ break; ++ } ++ __ECHO_OUT; ++ ++ return ret; ++} ++ ++ ++static int pxa250_irda_net_init(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ unsigned int baudrate_mask; ++ int err = -ENOMEM; ++ ++ si = kmalloc(sizeof(struct pxa250_irda), GFP_KERNEL); ++ if (!si) ++ goto out; ++ ++ memset(si, 0, sizeof(*si)); ++ ++ /* ++ * Initialise the HP-SIR buffers ++ */ ++ ++ err = pxa250_irda_init_iobuf(&si->rx_buff, 14384); ++ if (err) ++ goto out; ++ err = pxa250_irda_init_iobuf(&si->tx_buff, 4000); ++ if (err) ++ goto out_free_rx; ++ ++ si->fir_irq = IRQ_ICP; ++ dev->priv = si; ++ dev->hard_start_xmit = pxa250_irda_hard_xmit; ++ dev->open = pxa250_irda_start; ++ dev->stop = pxa250_irda_stop; ++ dev->do_ioctl = pxa250_irda_ioctl; ++ dev->get_stats = pxa250_irda_stats; ++ ++ irda_device_setup(dev); ++ irda_init_max_qos_capabilies(&si->qos); ++ ++ /* ++ * We support original IRDA up to 115k2. (we don't currently ++ * support 4Mbps). Min Turn Time set to 1ms or greater. ++ */ ++ baudrate_mask = IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; ++ baudrate_mask |= IR_4000000 << 8; ++ si->qos.baud_rate.bits &= baudrate_mask; ++ si->qos.min_turn_time.bits = 7; ++ ++ irda_qos_bits_to_value(&si->qos); ++ ++#ifdef CONFIG_PM ++ /* ++ * Power-Management is optional. ++ */ ++ si->pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, pxa250_irda_pmproc); ++ if (si->pmdev) ++ si->pmdev->data = dev; ++#endif ++ ++ return 0; ++ ++ kfree(si->tx_buff.head); ++out_free_rx: ++ kfree(si->rx_buff.head); ++out: ++ kfree(si); ++ ++ return err; ++} ++ ++/* ++ * Remove all traces of this driver module from the kernel, so we can't be ++ * called. Note that the device has already been stopped, so we don't have ++ * to worry about interrupts or dma. ++ */ ++static void pxa250_irda_net_uninit(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ ++ dev->hard_start_xmit = NULL; ++ dev->open = NULL; ++ dev->stop = NULL; ++ dev->do_ioctl = NULL; ++ dev->get_stats = NULL; ++ dev->priv = NULL; ++ ++ pm_unregister(si->pmdev); ++ ++ kfree(si->tx_buff.head); ++ kfree(si->rx_buff.head); ++ kfree(si); ++} ++ ++static int __init pxa250_irda_init(void) ++{ ++ struct net_device *dev; ++ int err; ++ ++ /* STUART */ ++ err = request_mem_region(__PREG(STRBR), 0x24, "IrDA") ? 0 : -EBUSY; ++ if (err) ++ goto err_mem_1; ++ ++ /* FIR */ ++ err = request_mem_region(__PREG(ICCR0), 0x1c, "IrDA") ? 0 : -EBUSY; ++ if (err) ++ goto err_mem_2; ++ ++ ++ rtnl_lock(); ++ dev = dev_alloc("irda%d", &err); ++ if (dev) { ++ dev->irq = IRQ_STUART; ++ dev->init = pxa250_irda_net_init; ++ dev->uninit = pxa250_irda_net_uninit; ++ ++ err = register_netdevice(dev); ++ ++ if (err) ++ kfree(dev); ++ else ++ netdev = dev; ++ } ++ rtnl_unlock(); ++ ++ if (err) { ++ release_mem_region(__PREG(ICCR0), 0x1c); ++err_mem_2: ++ release_mem_region(__PREG(STRBR), 0x24); ++ } ++err_mem_1: ++ return err; ++} ++ ++static void __exit pxa250_irda_exit(void) ++{ ++ struct net_device *dev = netdev; ++ ++ netdev = NULL; ++ if (dev) { ++ rtnl_lock(); ++ unregister_netdevice(dev); ++ rtnl_unlock(); ++ } ++ ++ release_mem_region(__PREG(ICCR0), 0x1c); ++ ++ release_mem_region(__PREG(STRBR), 0x24); ++ ++ /* ++ * We now know that the netdevice is no longer in use, and all ++ * references to our driver have been removed. The only structure ++ * which may still be present is the netdevice, which will get ++ * cleaned up by net/core/dev.c ++ */ ++} ++ ++module_init(pxa250_irda_init); ++module_exit(pxa250_irda_exit); ++ ++MODULE_AUTHOR("Alexey Lugovskoy Frasenyak Dmitrij"); ++MODULE_DESCRIPTION("PXA250 SIR/FIR"); ++MODULE_LICENSE("GPL"); ++EXPORT_NO_SYMBOLS; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/net/smc91x.c 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,2123 @@ ++/*------------------------------------------------------------------------ ++ . smc91x.c ++ . This is a driver for SMSC's 91C9x/91C1xx single-chip Ethernet devices. ++ . ++ . Copyright (C) 1996 by Erik Stahlman ++ . Copyright (C) 2001 Standard Microsystems Corporation ++ . Developed by Simple Network Magic Corporation ++ . Copyright (C) 2003 Monta Vista Software, Inc. ++ . Unified SMC91x driver by Nicolas Pitre ++ . ++ . 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 ++ . ++ . Arguments: ++ . io = for the base address ++ . irq = for the IRQ ++ . nowait = 0 for normal wait states, 1 eliminates additional wait states ++ . ++ . original author: ++ . Erik Stahlman <erik@vt.edu> ++ . ++ . hardware multicast code: ++ . Peter Cammaert <pc@denkart.be> ++ . ++ . contributors: ++ . Daris A Nevil <dnevil@snmc.com> ++ . Nicolas Pitre <nico@cam.org> ++ . ++ . History: ++ . 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" ++ . 03/16/01 Daris A Nevil modified smc9194.c for use with LAN91C111 ++ . 08/22/01 Scott Anderson merge changes from smc9194 to smc91111 ++ . 08/21/01 Pramod B Bhardwaj added support for RevB of LAN91C111 ++ . 12/20/01 Jeff Sutherland initial port to Xscale PXA with DMA support ++ . 04/07/03 Nicolas Pitre unified SMC91x driver, killed irq races, ++ . more bus abstraction, big cleanup, etc. ++ ----------------------------------------------------------------------------*/ ++ ++static const char version[] = ++ "smc91x.c: v1.0, mar 07 2003 by Nicolas Pitre <nico@cam.org>\n"; ++ ++/* Debugging level */ ++#ifndef SMC_DEBUG ++#define SMC_DEBUG 0 ++#endif ++ ++ ++#include <linux/config.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/delay.h> ++#include <linux/timer.h> ++#include <linux/errno.h> ++#include <linux/ioport.h> ++ ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> ++#ifdef CONFIG_PM ++#include <linux/pm.h> ++#endif ++ ++#include <asm/io.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#include "smc91x.h" ++ ++ ++#ifdef CONFIG_ISA ++/* ++ . the LAN91C111 can be at any of the following port addresses. To change, ++ . for a slightly different card, you can add it to the array. Keep in ++ . mind that the array must end in zero. ++*/ ++static unsigned int smc_portlist[] __initdata = { ++ 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, ++ 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0 ++}; ++#endif /* CONFIG_ISA */ ++ ++#ifndef SMC_IOADDR ++# define SMC_IOADDR -1 ++#endif ++static int io = SMC_IOADDR; ++ ++#ifndef SMC_IRQ ++# define SMC_IRQ -1 ++#endif ++static int irq = SMC_IRQ; ++ ++#ifndef SMC_NOWAIT ++# define SMC_NOWAIT 0 ++#endif ++static int nowait = SMC_NOWAIT; ++ ++MODULE_PARM(io, "i"); ++MODULE_PARM(irq, "i"); ++MODULE_PARM(nowait, "i"); ++MODULE_PARM_DESC(io, "I/O base address"); ++MODULE_PARM_DESC(irq, "IRQ number"); ++MODULE_PARM_DESC(nowait, "set to 1 for no wait state"); ++ ++ ++/*------------------------------------------------------------------------ ++ . ++ . The internal workings of the driver. If you are changing anything ++ . here with the SMC stuff, you should have the datasheet and know ++ . what you are doing. ++ . ++ -------------------------------------------------------------------------*/ ++#define CARDNAME "LAN91x" ++ ++// Use power-down feature of the chip ++#define POWER_DOWN 1 ++ ++/* ++ . Wait time for memory to be free. This probably shouldn't be ++ . tuned that much, as waiting for this means nothing else happens ++ . in the system ++*/ ++#define MEMORY_WAIT_TIME 16 ++ ++/* ++ . This selects whether TX packets are sent one by one to the SMC91x internal ++ . memory ans throttled until transmission completes. This may prevent ++ . RX overruns a litle by keeping much of the memory free for RX packets ++ . but to the expense of reduced TX throughput and increased IRQ overhead. ++ . Note this is not a cure for a too slow data bus or too high IRQ latency. ++ */ ++#define THROTTLE_TX_PKTS 0 ++ ++ ++/* store this information for the driver.. */ ++struct smc_local { ++ ++ // 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; ++ ++ // 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; ++ ++ // version/revision of the SMC91x chip ++ int version; ++ ++ // Set to true during the auto-negotiation sequence ++ int autoneg_active; ++ ++ // Address of our PHY port ++ int phyaddr; ++ ++ // Type of PHY ++ int phytype; ++ ++ // Last contents of PHY Register 18 ++ int lastPhy18; ++ ++ // Contains the current active transmission mode ++ int tcr_cur_mode; ++ ++ // Contains the current active receive mode ++ int rcr_cur_mode; ++ ++ // Contains the current active receive/phy mode ++ int rpc_cur_mode; ++ int ctl_autoneg; ++ int ctl_rfduplx; ++ int ctl_rspeed; ++ ++#ifdef CONFIG_PM ++ struct pm_dev* pm; ++#endif ++ ++}; ++ ++ ++#if SMC_DEBUG > 2 ++#define PRINTK3(args...) printk(args) ++#else ++#define PRINTK3(args...) do { } while(0) ++#endif ++ ++#if SMC_DEBUG > 1 ++#define PRINTK2(args...) printk(args) ++#else ++#define PRINTK2(args...) do { } while(0) ++#endif ++ ++#if SMC_DEBUG > 0 ++#define PRINTK1(args...) printk(args) ++#define PRINTK(args...) printk(args) ++#else ++#define PRINTK1(args...) do { } while(0) ++#define PRINTK(args...) printk(KERN_DEBUG args) ++#endif ++ ++#if SMC_DEBUG > 3 ++static void PRINT_PKT(u_char *buf, int length) ++{ ++ int i; ++ int remainder; ++ int lines; ++ ++ lines = length / 16; ++ remainder = length % 16; ++ ++ for (i = 0; i < lines ; i ++) { ++ int cur; ++ for (cur = 0; cur < 8; cur++) { ++ u_char a, b; ++ a = *buf++; ++ b = *buf++; ++ printk("%02x%02x ", a, b); ++ } ++ printk("\n"); ++ } ++ for (i = 0; i < remainder/2 ; i++) { ++ u_char a, b; ++ a = *buf++; ++ b = *buf++; ++ printk("%02x%02x ", a, b ); ++ } ++ printk("\n"); ++} ++#else ++#define PRINT_PKT(x...) do { } while(0) ++#endif ++ ++ ++/* this enables an interrupt in the interrupt mask register */ ++#define SMC_ENABLE_INT(x) do { \ ++ unsigned long flags; \ ++ unsigned char mask; \ ++ local_irq_save(flags); \ ++ mask = SMC_GET_INT_MASK(); \ ++ mask |= (x); \ ++ SMC_SET_INT_MASK(mask); \ ++ local_irq_restore(flags); \ ++} while (0) ++ ++/* this disables an interrupt from the interrupt mask register */ ++#define SMC_DISABLE_INT(x) do { \ ++ unsigned long flags; \ ++ unsigned char mask; \ ++ local_irq_save(flags); \ ++ mask = SMC_GET_INT_MASK(); \ ++ mask &= ~(x); \ ++ SMC_SET_INT_MASK(mask); \ ++ local_irq_restore(flags); \ ++} while (0) ++ ++/* wait while MMU is busy */ ++#define SMC_WAIT_MMU_BUSY() do { \ ++ if (unlikely(SMC_GET_MMU_CMD() & MC_BUSY)) { \ ++ unsigned long timeout = jiffies + 2; \ ++ while (SMC_GET_MMU_CMD() & MC_BUSY) { \ ++ if (time_after(jiffies, timeout)) { \ ++ printk("%s: timeout %s line %d\n", \ ++ dev->name, __FILE__, __LINE__); \ ++ break; \ ++ } \ ++ } \ ++ } \ ++} while (0) ++ ++ ++/* this does a soft reset on the device */ ++static void ++smc_reset(struct net_device *dev) ++{ ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ int phyaddr = lp->phyaddr; ++ int status; ++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__); ++ ++ /* This resets the registers mostly to defaults, but doesn't ++ affect EEPROM. That seems unnecessary */ ++ SMC_SELECT_BANK( 0 ); ++ SMC_SET_RCR( RCR_SOFTRST ); ++ ++ /* Setup the Configuration Register */ ++ /* This is necessary because the CONFIG_REG is not affected */ ++ /* by a soft reset */ ++ SMC_SELECT_BANK( 1 ); ++ SMC_SET_CONFIG( CONFIG_DEFAULT ); ++ ++ /* Setup for fast accesses if requested */ ++ /* If the card/system can't handle it then there will */ ++ /* be no recovery except for a hard reset or power cycle */ ++ if (nowait) ++ SMC_SET_CONFIG( SMC_GET_CONFIG() | CONFIG_NO_WAIT ); ++ ++#ifdef POWER_DOWN ++ /* Release from possible power-down state */ ++ /* Configuration register is not affected by Soft Reset */ ++ SMC_SELECT_BANK( 1 ); ++ SMC_SET_CONFIG( SMC_GET_CONFIG() | CONFIG_EPH_POWER_EN ); ++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG); ++ status &= ~PHY_CNTL_PDN; ++ smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG); ++#endif ++ ++ /* this should pause enough for the chip to be happy */ ++ udelay(1); ++ ++ /* Disable transmit and receive functionality */ ++ SMC_SELECT_BANK( 0 ); ++ SMC_SET_RCR( RCR_CLEAR ); ++ SMC_SET_TCR( TCR_CLEAR ); ++ ++ /* set the control register to automatically ++ release successfully transmitted packets, to make the best ++ use out of our limited memory */ ++ SMC_SELECT_BANK( 1 ); ++#if ! THROTTLE_TX_PKTS ++ SMC_SET_CTL( SMC_GET_CTL() | CTL_AUTO_RELEASE ); ++#else ++ SMC_SET_CTL( SMC_GET_CTL() & ~CTL_AUTO_RELEASE ); ++#endif ++ ++ /* Disable all interrupts */ ++ SMC_SELECT_BANK( 2 ); ++ SMC_SET_INT_MASK( 0 ); ++ ++ /* Reset the MMU */ ++ SMC_SET_MMU_CMD( MC_RESET ); ++ SMC_WAIT_MMU_BUSY(); ++} ++ ++/* Enable Interrupts, Receive, and Transmit */ ++static void ++smc_enable(struct net_device *dev) ++{ ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ int mask; ++ ++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__); ++ ++ /* see the header file for options in TCR/RCR DEFAULT*/ ++ SMC_SELECT_BANK( 0 ); ++ SMC_SET_TCR( lp->tcr_cur_mode ); ++ SMC_SET_RCR( lp->rcr_cur_mode ); ++ ++ /* now, enable interrupts */ ++ mask = IM_EPH_INT|IM_RX_OVRN_INT|IM_RCV_INT; ++ if (lp->version >= 0x70) ++ mask |= IM_MDINT; ++ SMC_SELECT_BANK( 2 ); ++ SMC_SET_INT_MASK( mask ); ++} ++ ++/* this puts the device in an inactive state */ ++static void ++smc_shutdown(struct net_device *dev) ++{ ++ int ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ int phyaddr = lp->phyaddr; ++ int status; ++ ++ PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__); ++ ++ /* no more interrupts for me */ ++ SMC_SELECT_BANK( 2 ); ++ SMC_SET_INT_MASK( 0 ); ++ ++ /* and tell the card to stay away from that nasty outside world */ ++ SMC_SELECT_BANK( 0 ); ++ SMC_SET_RCR( RCR_CLEAR ); ++ SMC_SET_TCR( TCR_CLEAR ); ++ ++#ifdef POWER_DOWN ++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG); ++ status |= PHY_CNTL_PDN; ++ smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG); ++ ++ /* finally, shut the chip down */ ++ SMC_SELECT_BANK( 1 ); ++ SMC_SET_CONFIG( SMC_GET_CONFIG() & ~CONFIG_EPH_POWER_EN ); ++#endif ++} ++ ++/* This is the procedure to handle the receipt of a packet. */ ++static inline void ++smc_rcv(struct net_device *dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ unsigned long ioaddr = dev->base_addr; ++ unsigned int packet_number, status, packet_len; ++ ++ PRINTK3("%s: %s\n", dev->name, __FUNCTION__); ++ ++ packet_number = SMC_GET_RXFIFO(); ++ if (unlikely(packet_number & RXFIFO_REMPTY)) { ++ PRINTK("%s: smc_rcv with nothing on FIFO.\n", dev->name); ++ return; ++ } ++ ++ /* read from start of packet */ ++ SMC_SET_PTR( PTR_READ | PTR_RCV | PTR_AUTOINC ); ++ ++ /* First two words are status and packet length */ ++ SMC_GET_PKT_HDR(status, packet_len); ++ packet_len &= 0x07ff; /* mask off top bits */ ++ PRINTK2("%s: RX PNR 0x%x STATUS 0x%04x LENGTH 0x%04x (%d)\n", ++ dev->name, packet_number, status, ++ packet_len, packet_len); ++ ++ if (unlikely(status & RS_ERRORS)) { ++ lp->stats.rx_errors++; ++ 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++; ++ } else { ++ struct sk_buff *skb; ++ unsigned char *data; ++ unsigned int data_len; ++ ++ /* set multicast stats */ ++ if (status & RS_MULTICAST) ++ lp->stats.multicast++; ++ ++ /* ++ * Actual payload is packet_len - 4 (or 3 if odd byte). ++ * We want skb_reserve(2) and the final ctrl word ++ * (2 bytes, possibly containing the payload odd byte). ++ * Ence packet_len - 4 + 2 + 2. ++ */ ++ skb = dev_alloc_skb(packet_len); ++ if (unlikely(skb == NULL)) { ++ printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", ++ dev->name); ++ lp->stats.rx_dropped++; ++ goto done; ++ } ++ ++ /* Align IP header to 32 bits */ ++ skb_reserve(skb, 2); ++ ++ /* BUG: the LAN91C111 rev A never sets this bit. Force it. */ ++ if (lp->version == 0x90) ++ status |= RS_ODDFRAME; ++ ++ /* ++ * If odd length: packet_len - 3, ++ * otherwise packet_len - 4. ++ */ ++ data_len = packet_len - ((status & RS_ODDFRAME) ? 3 : 4); ++ data = skb_put(skb, data_len); ++ SMC_PULL_DATA(data, packet_len - 2); ++ ++ PRINT_PKT(data, packet_len - 2); ++ ++ dev->last_rx = jiffies; ++ skb->dev = dev; ++ skb->protocol = eth_type_trans(skb, dev); ++ netif_rx(skb); ++ lp->stats.rx_packets++; ++ lp->stats.rx_bytes += data_len; ++ } ++ ++done: ++ SMC_WAIT_MMU_BUSY(); ++ SMC_SET_MMU_CMD( MC_RELEASE ); ++} ++ ++/* ++ * This is called to actually send a packet to the chip. ++ * Returns non-zero when successful. ++ */ ++static void ++smc_hardware_send_packet(struct net_device *dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ unsigned long ioaddr = dev->base_addr; ++ struct sk_buff *skb = lp->saved_skb; ++ unsigned int packet_no, len; ++ unsigned char *buf; ++ ++ PRINTK3("%s: %s\n", dev->name, __FUNCTION__); ++ ++ if (unlikely(!skb)) { ++ printk ("%s: In XMIT with no packet to send\n", dev->name); ++ return; ++ } ++ ++ packet_no = SMC_GET_AR(); ++ if (unlikely(packet_no & AR_FAILED)) { ++ printk("%s: Memory allocation failed.\n", dev->name); ++ lp->saved_skb = NULL; ++ lp->stats.tx_errors++; ++ lp->stats.tx_fifo_errors++; ++ dev_kfree_skb_any(skb); ++ return; ++ } ++ ++ /* point to the beginning of the packet */ ++ SMC_SET_PN( packet_no ); ++ SMC_SET_PTR( PTR_AUTOINC ); ++ ++ buf = skb->data; ++ len = skb->len; ++ PRINTK2("%s: TX PNR 0x%x lENGTH 0x%04x (%d) BUF 9x%p\n", ++ dev->name, packet_no, len, len, buf); ++ PRINT_PKT(buf, len); ++ ++ /* ++ * Send the packet length ( +6 for status words, length, and ctl. ++ * The card will pad to 64 bytes with zeroes if packet is too small. ++ */ ++ SMC_PUT_PKT_HDR(0, len + 6); ++ ++ /* send the actual data */ ++ SMC_PUSH_DATA(buf, len & ~1); ++ ++ /* Send final ctl word with the last byte if there is one */ ++ SMC_outw( ((len & 1) ? (0x2000 | buf[len-1]) : 0), ioaddr, DATA_REG ); ++ ++ /* and let the chipset deal with it */ ++ SMC_SET_MMU_CMD( MC_ENQUEUE ); ++ SMC_ACK_INT( IM_TX_EMPTY_INT ); ++ ++ dev->trans_start = jiffies; ++ dev_kfree_skb_any(skb); ++ lp->saved_skb = NULL; ++ lp->stats.tx_packets++; ++ lp->stats.tx_bytes += len; ++} ++ ++/* ++ . 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 set the card to generates an interrupt when ready ++ . for the packet. ++ */ ++static int ++smc_hard_start_xmit( struct sk_buff * skb, struct net_device * dev ) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ unsigned long ioaddr = dev->base_addr; ++ unsigned int numPages, poll_count, status, saved_bank; ++ ++ PRINTK3("%s: %s\n", dev->name, __FUNCTION__); ++ ++ if (unlikely(lp->saved_skb != NULL)) { ++ /* THIS SHOULD NEVER HAPPEN. */ ++ printk( KERN_CRIT ++ "%s: Bad Craziness - sent packet while busy.\n", ++ dev->name ); ++ lp->stats.tx_errors++; ++ lp->stats.tx_aborted_errors++; ++ return 1; ++ } ++ 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 :) ) ++ ** ++ ** The 91C111 ignores the size bits, but the code is left intact ++ ** for backwards and future compatibility. ++ ** ++ ** Pkt size for allocating is data length +6 (for additional status ++ ** words, length and ctl!) ++ ** ++ ** If odd size then last byte is included in ctl word. ++ */ ++ numPages = ((skb->len & ~1) + (6 - 1)) >> 8; ++ if (unlikely(numPages > 7)) { ++ printk("%s: Far too big packet error.\n", dev->name); ++ lp->saved_skb = NULL; ++ lp->stats.tx_errors++; ++ lp->stats.tx_dropped++; ++ dev_kfree_skb(skb); ++ return 0; ++ } ++ ++ /* now, try to allocate the memory */ ++ saved_bank = SMC_CURRENT_BANK(); ++ SMC_SELECT_BANK( 2 ); ++ SMC_SET_MMU_CMD( MC_ALLOC | numPages ); ++ ++ /* ++ * Poll the chip for a short amount of time in case the ++ * allocation succeeds quickly. ++ */ ++ poll_count = MEMORY_WAIT_TIME; ++ do { ++ status = SMC_GET_INT(); ++ if (status & IM_ALLOC_INT) { ++ SMC_ACK_INT( IM_ALLOC_INT ); ++ break; ++ } ++ } while (--poll_count); ++ ++ if (!poll_count) { ++ /* oh well, wait until the chip finds memory later */ ++ netif_stop_queue(dev); ++ PRINTK2("%s: TX memory allocation deferred.\n", dev->name); ++ SMC_ENABLE_INT( IM_ALLOC_INT ); ++ } else { ++ /* Send current packet immediately.. */ ++#if THROTTLE_TX_PKTS ++ netif_stop_queue(dev); ++#endif ++ smc_hardware_send_packet(dev); ++ SMC_ENABLE_INT( IM_TX_INT | IM_TX_EMPTY_INT ); ++ } ++ ++ SMC_SELECT_BANK( saved_bank ); ++ return 0; ++} ++ ++/* ++ . This handles a TX interrupt, which is only called when an error ++ . relating to a packet is sent or CTL_AUTO_RELEASE is not set. ++*/ ++static void ++smc_tx(struct net_device *dev) ++{ ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ unsigned int saved_packet, packet_no, tx_status, pkt_len; ++ ++ PRINTK3("%s: %s\n", dev->name, __FUNCTION__); ++ ++ /* If the TX FIFO is empty then nothing to do */ ++ packet_no = SMC_GET_TXFIFO(); ++ if (unlikely(packet_no & TXFIFO_TEMPTY)) { ++ PRINTK("%s: smc_tx with nothing on FIFO.\n", dev->name); ++ return; ++ } ++ ++ /* select packet to read from */ ++ saved_packet = SMC_GET_PN(); ++ SMC_SET_PN( packet_no ); ++ ++ /* read the first word (status word) from this packet */ ++ SMC_SET_PTR( PTR_AUTOINC | PTR_READ ); ++ SMC_GET_PKT_HDR(tx_status, pkt_len); ++ PRINTK2("%s: TX STATUS 0x%04x PNR 0x%02x\n", ++ dev->name, tx_status, packet_no); ++ ++ if (!(tx_status & TS_SUCCESS)) ++ lp->stats.tx_errors++; ++ 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++; ++ } ++ ++ /* kill the packet */ ++ SMC_WAIT_MMU_BUSY(); ++ SMC_SET_MMU_CMD( MC_FREEPKT ); ++ ++ /* Don't restore Packet Number Reg until busy bit is cleared */ ++ SMC_WAIT_MMU_BUSY(); ++ SMC_SET_PN( saved_packet ); ++ ++ /* re-enable transmit */ ++ SMC_SELECT_BANK( 0 ); ++ SMC_SET_TCR( lp->tcr_cur_mode ); ++ SMC_SELECT_BANK( 2 ); ++} ++ ++ ++//---PHY CONTROL AND CONFIGURATION----------------------------------------- ++ ++/*------------------------------------------------------------ ++ . Debugging function for viewing MII Management serial bitstream ++ .-------------------------------------------------------------*/ ++#if SMC_DEBUG > 3 ++static void ++PRINT_MII_STREAM(u_char *bits, int size) ++{ ++ int i; ++ ++ printk("BIT#:"); ++ for (i = 0; i < size; ++i) ++ printk("%d", i%10); ++ ++ printk("\nMDOE:"); ++ for (i = 0; i < size; ++i) { ++ if (bits[i] & MII_MDOE) ++ printk("1"); ++ else ++ printk("0"); ++ } ++ ++ printk("\nMDO :"); ++ for (i = 0; i < size; ++i) { ++ if (bits[i] & MII_MDO) ++ printk("1"); ++ else ++ printk("0"); ++ } ++ ++ printk("\nMDI :"); ++ for (i = 0; i < size; ++i) { ++ if (bits[i] & MII_MDI) ++ printk("1"); ++ else ++ printk("0"); ++ } ++ ++ printk("\n"); ++} ++#else ++#define PRINT_MII_STREAM(x...) ++#endif ++ ++/*------------------------------------------------------------ ++ . Reads a register from the MII Management serial interface ++ .-------------------------------------------------------------*/ ++static int ++smc_read_phy_register(unsigned long ioaddr, int phyaddr, int phyreg) ++{ ++ int oldBank; ++ int i, mask, mii_reg; ++ u_char bits[64]; ++ int input_idx, phydata; ++ int clk_idx = 0; ++ ++ // 32 consecutive ones on MDO to establish sync ++ for (i = 0; i < 32; ++i) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ ++ // Start code <01> ++ bits[clk_idx++] = MII_MDOE; ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ ++ // Read command <10> ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ bits[clk_idx++] = MII_MDOE; ++ ++ // Output the PHY address, msb first ++ mask = 0x10; ++ for (i = 0; i < 5; ++i) { ++ if (phyaddr & mask) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ else ++ bits[clk_idx++] = MII_MDOE; ++ ++ // Shift to next lowest bit ++ mask >>= 1; ++ } ++ ++ // Output the phy register number, msb first ++ mask = 0x10; ++ for (i = 0; i < 5; ++i) { ++ if (phyreg & mask) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ else ++ bits[clk_idx++] = MII_MDOE; ++ ++ // Shift to next lowest bit ++ mask >>= 1; ++ } ++ ++ // Tristate and turnaround (2 bit times) ++ bits[clk_idx++] = 0; ++ //bits[clk_idx++] = 0; ++ ++ // Input starts at this bit time ++ input_idx = clk_idx; ++ ++ // Will input 16 bits ++ for (i = 0; i < 16; ++i) ++ bits[clk_idx++] = 0; ++ ++ // Final clock bit ++ bits[clk_idx++] = 0; ++ ++ // Save the current bank ++ oldBank = SMC_CURRENT_BANK(); ++ ++ // Select bank 3 ++ SMC_SELECT_BANK( 3 ); ++ ++ // Get the current MII register value ++ mii_reg = SMC_GET_MII(); ++ ++ // Turn off all MII Interface bits ++ mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO); ++ ++ // Clock all 64 cycles ++ for (i = 0; i < sizeof bits; ++i) { ++ // Clock Low - output data ++ SMC_SET_MII( mii_reg | bits[i] ); ++ udelay(50); ++ ++ // Clock Hi - input data ++ SMC_SET_MII( mii_reg | bits[i] | MII_MCLK ); ++ udelay(50); ++ bits[i] |= SMC_GET_MII() & MII_MDI; ++ } ++ ++ // Return to idle state ++ // Set clock to low, data to low, and output tristated ++ SMC_SET_MII( mii_reg ); ++ udelay(50); ++ ++ // Restore original bank select ++ SMC_SELECT_BANK( oldBank ); ++ ++ // Recover input data ++ phydata = 0; ++ for (i = 0; i < 16; ++i) { ++ phydata <<= 1; ++ ++ if (bits[input_idx++] & MII_MDI) ++ phydata |= 0x0001; ++ } ++ ++ PRINTK3("%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", ++ __FUNCTION__, phyaddr, phyreg, phydata); ++ PRINT_MII_STREAM(bits, sizeof(bits)); ++ ++ return phydata; ++} ++ ++/*------------------------------------------------------------ ++ . Writes a register to the MII Management serial interface ++ .-------------------------------------------------------------*/ ++static void ++smc_write_phy_register( unsigned long ioaddr, int phyaddr, ++ int phyreg, int phydata ) ++{ ++ int oldBank; ++ int i, mask, mii_reg; ++ u_char bits[65]; ++ int clk_idx = 0; ++ ++ // 32 consecutive ones on MDO to establish sync ++ for (i = 0; i < 32; ++i) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ ++ // Start code <01> ++ bits[clk_idx++] = MII_MDOE; ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ ++ // Write command <01> ++ bits[clk_idx++] = MII_MDOE; ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ ++ // Output the PHY address, msb first ++ mask = 0x10; ++ for (i = 0; i < 5; ++i) { ++ if (phyaddr & mask) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ else ++ bits[clk_idx++] = MII_MDOE; ++ ++ // Shift to next lowest bit ++ mask >>= 1; ++ } ++ ++ // Output the phy register number, msb first ++ mask = 0x10; ++ for (i = 0; i < 5; ++i) { ++ if (phyreg & mask) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ else ++ bits[clk_idx++] = MII_MDOE; ++ ++ // Shift to next lowest bit ++ mask >>= 1; ++ } ++ ++ // Tristate and turnaround (2 bit times) ++ bits[clk_idx++] = 0; ++ bits[clk_idx++] = 0; ++ ++ // Write out 16 bits of data, msb first ++ mask = 0x8000; ++ for (i = 0; i < 16; ++i) { ++ if (phydata & mask) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ else ++ bits[clk_idx++] = MII_MDOE; ++ ++ // Shift to next lowest bit ++ mask >>= 1; ++ } ++ ++ // Final clock bit (tristate) ++ bits[clk_idx++] = 0; ++ ++ // Save the current bank ++ oldBank = SMC_CURRENT_BANK(); ++ ++ // Select bank 3 ++ SMC_SELECT_BANK( 3 ); ++ ++ // Get the current MII register value ++ mii_reg = SMC_GET_MII(); ++ ++ // Turn off all MII Interface bits ++ mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO); ++ ++ // Clock all cycles ++ for (i = 0; i < sizeof bits; ++i) { ++ // Clock Low - output data ++ SMC_SET_MII( mii_reg | bits[i] ); ++ udelay(50); ++ ++ // Clock Hi - input data ++ SMC_SET_MII( mii_reg | bits[i] | MII_MCLK ); ++ udelay(50); ++ bits[i] |= SMC_GET_MII() & MII_MDI; ++ } ++ ++ // Return to idle state ++ // Set clock to low, data to low, and output tristated ++ SMC_SET_MII( mii_reg ); ++ udelay(50); ++ ++ // Restore original bank select ++ SMC_SELECT_BANK( oldBank ); ++ ++ PRINTK3("%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", ++ __FUNCTION__, phyaddr, phyreg, phydata); ++ PRINT_MII_STREAM(bits, sizeof(bits)); ++} ++ ++ ++/*------------------------------------------------------------ ++ . Finds and reports the PHY address ++ .-------------------------------------------------------------*/ ++static int smc_detect_phy(struct net_device* dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ unsigned long ioaddr = dev->base_addr; ++ int phy_id1, phy_id2; ++ int phyaddr; ++ int found = 0; ++ ++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__); ++ ++ // Scan all 32 PHY addresses if necessary ++ for (phyaddr = 0; phyaddr < 32; ++phyaddr) { ++ // Read the PHY identifiers ++ phy_id1 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID1_REG); ++ phy_id2 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID2_REG); ++ ++ PRINTK3("%s: phy_id1=0x%x, phy_id2=0x%x\n", ++ dev->name, phy_id1, phy_id2); ++ ++ // Make sure it is a valid identifier ++ if ((phy_id2 > 0x0000) && (phy_id2 < 0xffff) && ++ (phy_id1 > 0x0000) && (phy_id1 < 0xffff)) { ++ if ((phy_id1 != 0x8000) && (phy_id2 != 0x8000)) { ++ // Save the PHY's address ++ lp->phyaddr = phyaddr; ++ found = 1; ++ break; ++ } ++ } ++ } ++ ++ if (!found) { ++ PRINTK("%s: No PHY found\n", dev->name); ++ return(0); ++ } ++ ++ // Set the PHY type ++ if ( (phy_id1 == 0x0016) && ((phy_id2 & 0xFFF0) == 0xF840 ) ) { ++ lp->phytype = PHY_LAN83C183; ++ PRINTK("%s: PHY=LAN83C183 (LAN91C111 Internal)\n", dev->name); ++ } ++ ++ if ( (phy_id1 == 0x0282) && ((phy_id2 & 0xFFF0) == 0x1C50) ) { ++ lp->phytype = PHY_LAN83C180; ++ PRINTK("%s: PHY=LAN83C180\n", dev->name); ++ } ++ ++ return 1; ++} ++ ++/*------------------------------------------------------------ ++ . Waits the specified number of milliseconds - kernel friendly ++ .-------------------------------------------------------------*/ ++static void ++smc_wait_ms(unsigned int ms) ++{ ++ if (!in_interrupt()) { ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ schedule_timeout(1 + ms * HZ / 1000); ++ } else { ++ /* if this happens it must be fixed */ ++ printk( KERN_WARNING "%s: busy wait while in interrupt!\n", ++ __FUNCTION__); ++ mdelay(ms); ++ } ++} ++ ++/*------------------------------------------------------------ ++ . Sets the PHY to a configuration as determined by the user ++ .-------------------------------------------------------------*/ ++static int ++smc_phy_fixed(struct net_device *dev) ++{ ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ int phyaddr = lp->phyaddr; ++ int my_fixed_caps, cfg1; ++ ++ PRINTK3("%s: %s\n", dev->name, __FUNCTION__); ++ ++ // Enter Link Disable state ++ cfg1 = smc_read_phy_register(ioaddr, phyaddr, PHY_CFG1_REG); ++ cfg1 |= PHY_CFG1_LNKDIS; ++ smc_write_phy_register(ioaddr, phyaddr, PHY_CFG1_REG, cfg1); ++ ++ // Set our fixed capabilities ++ // Disable auto-negotiation ++ my_fixed_caps = 0; ++ ++ if (lp->ctl_rfduplx) ++ my_fixed_caps |= PHY_CNTL_DPLX; ++ ++ if (lp->ctl_rspeed == 100) ++ my_fixed_caps |= PHY_CNTL_SPEED; ++ ++ // Write our capabilities to the phy control register ++ smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, my_fixed_caps); ++ ++ // Re-Configure the Receive/Phy Control register ++ SMC_SET_RPC( lp->rpc_cur_mode ); ++ ++ // Success ++ return(1); ++} ++ ++/*------------------------------------------------------------ ++ . Configures the specified PHY through the MII management interface ++ . using Autonegotiation. ++ . Calls smc_phy_fixed() if the user has requested a certain config. ++ .-------------------------------------------------------------*/ ++static void ++smc_phy_configure(struct net_device* dev) ++{ ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ int timeout; ++ int phyaddr; ++ int my_phy_caps; // My PHY capabilities ++ int my_ad_caps; // My Advertised capabilities ++ int status; ++ ++ PRINTK3("%s:smc_program_phy()\n", dev->name); ++ ++ // Set the blocking flag ++ lp->autoneg_active = 1; ++ ++ // Find the address and type of our phy ++ if (!smc_detect_phy(dev)) ++ goto smc_phy_configure_exit; ++ ++ // Get the detected phy address ++ phyaddr = lp->phyaddr; ++ ++ // Reset the PHY, setting all other bits to zero ++ smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, PHY_CNTL_RST); ++ ++ // Wait for the reset to complete, or time out ++ timeout = 6; // Wait up to 3 seconds ++ while (timeout--) { ++ if (!(smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG) ++ & PHY_CNTL_RST)) ++ // reset complete ++ break; ++ smc_wait_ms(500); // wait 500 millisecs ++ if (signal_pending(current)) { // Exit anyway if signaled ++ PRINTK("%s: PHY reset interrupted by signal\n", ++ dev->name); ++ timeout = 0; ++ break; ++ } ++ } ++ ++ if (timeout < 1) { ++ printk("%s: PHY reset timed out\n", dev->name); ++ goto smc_phy_configure_exit; ++ } ++ ++ // Read PHY Register 18, Status Output ++ lp->lastPhy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG); ++ ++ // Enable PHY Interrupts (for register 18) ++ // Interrupts listed here are disabled ++ smc_write_phy_register(ioaddr, phyaddr, PHY_MASK_REG, ++ PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD | ++ PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB | ++ PHY_INT_SPDDET | PHY_INT_DPLXDET); ++ ++ /* Configure the Receive/Phy Control register */ ++ SMC_SELECT_BANK( 0 ); ++ SMC_SET_RPC( lp->rpc_cur_mode ); ++ ++ // Copy our capabilities from PHY_STAT_REG to PHY_AD_REG ++ my_phy_caps = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG); ++ ++ // If the user requested no auto neg, then go set his request ++ if (!(lp->ctl_autoneg)) { ++ smc_phy_fixed(dev); ++ goto smc_phy_configure_exit; ++ } ++ ++ if( !( my_phy_caps & PHY_STAT_CAP_ANEG)) ++ { ++ printk(KERN_INFO "Auto negotiation NOT supported\n"); ++ smc_phy_fixed(dev); ++ goto smc_phy_configure_exit; ++ } ++ ++ my_ad_caps = PHY_AD_CSMA; // I am CSMA capable ++ ++ if (my_phy_caps & PHY_STAT_CAP_T4) ++ my_ad_caps |= PHY_AD_T4; ++ ++ if (my_phy_caps & PHY_STAT_CAP_TXF) ++ my_ad_caps |= PHY_AD_TX_FDX; ++ ++ if (my_phy_caps & PHY_STAT_CAP_TXH) ++ my_ad_caps |= PHY_AD_TX_HDX; ++ ++ if (my_phy_caps & PHY_STAT_CAP_TF) ++ my_ad_caps |= PHY_AD_10_FDX; ++ ++ if (my_phy_caps & PHY_STAT_CAP_TH) ++ my_ad_caps |= PHY_AD_10_HDX; ++ ++ // Disable capabilities not selected by our user ++ if (lp->ctl_rspeed != 100) ++ my_ad_caps &= ~(PHY_AD_T4|PHY_AD_TX_FDX|PHY_AD_TX_HDX); ++ ++ if (!lp->ctl_rfduplx) ++ my_ad_caps &= ~(PHY_AD_TX_FDX|PHY_AD_10_FDX); ++ ++ // Update our Auto-Neg Advertisement Register ++ smc_write_phy_register(ioaddr, phyaddr, PHY_AD_REG, my_ad_caps); ++ ++ // Read the register back. Without this, it appears that when ++ // auto-negotiation is restarted, sometimes it isn't ready and ++ // the link does not come up. ++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_AD_REG); ++ ++ PRINTK2("%s: phy caps=%x\n", dev->name, my_phy_caps); ++ PRINTK2("%s: phy advertised caps=%x\n", dev->name, my_ad_caps); ++ ++ // Restart auto-negotiation process in order to advertise my caps ++ smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG, ++ PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST ); ++ ++ // Wait for the auto-negotiation to complete. This may take from ++ // 2 to 3 seconds. ++ // Wait for the reset to complete, or time out ++ timeout = 20; // Wait up to 10 seconds ++ while (timeout--) { ++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_RMT_REG); ++ if (status & PHY_AD_ACK) ++ // auto-negotiate complete ++ break; ++ ++ smc_wait_ms(500); // wait 500 millisecs ++ if (signal_pending(current)) { // Exit anyway if signaled ++ printk(KERN_DEBUG ++ "%s: PHY auto-negotiate interrupted by signal\n", ++ dev->name); ++ timeout = 0; ++ break; ++ } ++ } ++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG); ++ ++ if (timeout < 1) { ++ PRINTK("%s: PHY auto-negotiate timed out\n", dev->name); ++ } ++ ++ // Fail if we detected an auto-negotiate remote fault ++ if (status & PHY_STAT_REM_FLT) { ++ PRINTK("%s: PHY remote fault detected\n", dev->name); ++ } ++ ++ // Wait for link. Once the link is up, phy18 should be up to date ++ timeout = 200; ++ do ++ { ++ udelay(100); ++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG); ++ } while ( ((status & PHY_STAT_LINK)==0) && --timeout); ++ ++ if (status & PHY_STAT_LINK) ++ { ++ PRINTK("%s: Ethernet Link Detected\n", dev->name); ++ } ++ ++ // The smc_phy_interrupt() routine will be called to update lastPhy18 ++ ++ // Set our sysctl parameters to match auto-negotiation results ++ if ( lp->lastPhy18 & PHY_INT_SPDDET ) { ++ PRINTK("%s: PHY 100BaseT\n", dev->name); ++ lp->rpc_cur_mode |= RPC_SPEED; ++ } else { ++ PRINTK("%s: PHY 10BaseT\n", dev->name); ++ lp->rpc_cur_mode &= ~RPC_SPEED; ++ } ++ ++ if ( lp->lastPhy18 & PHY_INT_DPLXDET ) { ++ PRINTK("%s: PHY Full Duplex\n", dev->name); ++ lp->rpc_cur_mode |= RPC_DPLX; ++ lp->tcr_cur_mode |= TCR_SWFDUP; ++ } else { ++ PRINTK("%s: PHY Half Duplex\n", dev->name); ++ lp->rpc_cur_mode &= ~RPC_DPLX; ++ lp->tcr_cur_mode &= ~TCR_SWFDUP; ++ } ++ ++ // Re-Configure the Receive/Phy Control register and TCR ++ SMC_SET_RPC( lp->rpc_cur_mode ); ++ SMC_SET_TCR( lp->tcr_cur_mode ); ++ ++smc_phy_configure_exit: ++ // Exit auto-negotiation ++ lp->autoneg_active = 0; ++} ++ ++/************************************************************************* ++ . smc_phy_interrupt ++ . ++ . Purpose: Handle interrupts relating to PHY register 18. This is ++ . called from the "hard" interrupt handler. ++ . ++ ************************************************************************/ ++static void ++smc_phy_interrupt(struct net_device* dev) ++{ ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ int phyaddr = lp->phyaddr; ++ int phy18; ++ ++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__); ++ ++ for(;;) { ++ // Read PHY Register 18, Status Output ++ phy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG); ++ ++ // Exit if not more changes ++ if (phy18 == lp->lastPhy18) ++ break; ++ ++#if SMC_DEBUG > 1 ++ PRINTK2("%s: phy18=0x%04x\n", dev->name, phy18); ++ PRINTK2("%s: lastPhy18=0x%04x\n", dev->name, lp->lastPhy18); ++ ++ // Handle events ++ if ((phy18 & PHY_INT_LNKFAIL) != ++ (lp->lastPhy18 & PHY_INT_LNKFAIL)) ++ PRINTK2("%s: PHY Link Fail=%x\n", dev->name, ++ phy18 & PHY_INT_LNKFAIL); ++ ++ if ((phy18 & PHY_INT_LOSSSYNC) != ++ (lp->lastPhy18 & PHY_INT_LOSSSYNC)) ++ PRINTK2("%s: PHY LOSS SYNC=%x\n", dev->name, ++ phy18 & PHY_INT_LOSSSYNC); ++ ++ if ((phy18 & PHY_INT_CWRD) != (lp->lastPhy18 & PHY_INT_CWRD)) ++ PRINTK2("%s: PHY INVALID 4B5B code=%x\n", dev->name, ++ phy18 & PHY_INT_CWRD); ++ ++ if ((phy18 & PHY_INT_SSD) != (lp->lastPhy18 & PHY_INT_SSD)) ++ PRINTK2("%s: PHY No Start Of Stream=%x\n", dev->name, ++ phy18 & PHY_INT_SSD); ++ ++ if ((phy18 & PHY_INT_ESD) != (lp->lastPhy18 & PHY_INT_ESD)) ++ ++ PRINTK2("%s: PHY No End Of Stream=%x\n", dev->name, ++ phy18 & PHY_INT_ESD); ++ ++ if ((phy18 & PHY_INT_RPOL) != (lp->lastPhy18 & PHY_INT_RPOL)) ++ PRINTK2("%s: PHY Reverse Polarity Detected=%x\n", ++ dev->name, phy18 & PHY_INT_RPOL); ++ ++ if ((phy18 & PHY_INT_JAB) != (lp->lastPhy18 & PHY_INT_JAB)) ++ PRINTK2("%s: PHY Jabber Detected=%x\n", dev->name, ++ phy18 & PHY_INT_JAB); ++ ++ if ((phy18 & PHY_INT_SPDDET) != ++ (lp->lastPhy18 & PHY_INT_SPDDET)) ++ PRINTK2("%s: PHY Speed Detect=%x\n", dev->name, ++ phy18 & PHY_INT_SPDDET); ++ ++ if ((phy18 & PHY_INT_DPLXDET) != ++ (lp->lastPhy18 & PHY_INT_DPLXDET)) ++ PRINTK2("%s: PHY Duplex Detect=%x\n", dev->name, ++ phy18 & PHY_INT_DPLXDET); ++#endif ++ // Update the last phy 18 variable ++ lp->lastPhy18 = phy18; ++ } ++} ++ ++//--- END PHY CONTROL AND CONFIGURATION------------------------------------- ++ ++ ++/* ++ * This is the main routine of the driver, to handle the device when ++ * it needs some attention. ++ */ ++static void ++smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ struct net_device *dev = dev_id; ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ int status, mask, timeout, card_stats; ++ int saved_bank, saved_pointer; ++ ++ PRINTK3("%s: %s\n", dev->name, __FUNCTION__); ++ ++ saved_bank = SMC_CURRENT_BANK(); ++ SMC_SELECT_BANK(2); ++ saved_pointer = SMC_GET_PTR(); ++ mask = SMC_GET_INT_MASK(); ++ SMC_SET_INT_MASK( 0 ); ++ ++ /* set a timeout value, so I don't stay here forever */ ++ timeout = 8; ++ ++ do { ++ status = SMC_GET_INT(); ++ ++ PRINTK2("%s: IRQ 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n", ++ dev->name, status, mask, ++ ({ int meminfo; SMC_SELECT_BANK(0); ++ meminfo = SMC_GET_MIR(); ++ SMC_SELECT_BANK(2); meminfo; }), ++ SMC_GET_FIFO()); ++ ++ status &= mask; ++ if (!status) ++ break; ++ ++ if (status & IM_RCV_INT) { ++ PRINTK3("%s: RX irq\n", dev->name); ++ smc_rcv(dev); ++ } else if (status & IM_TX_INT) { ++ PRINTK3("%s: TX int\n", dev->name); ++ smc_tx(dev); ++ SMC_ACK_INT( IM_TX_INT ); ++#if THROTTLE_TX_PKTS ++ netif_wake_queue(dev); ++#endif ++ } else if (status & IM_ALLOC_INT) { ++ PRINTK3("%s: Allocation irq\n", dev->name); ++ smc_hardware_send_packet(dev); ++ mask |= (IM_TX_INT | IM_TX_EMPTY_INT); ++ mask &= ~IM_ALLOC_INT; ++#if ! THROTTLE_TX_PKTS ++ netif_wake_queue(dev); ++#endif ++ } else if (status & IM_TX_EMPTY_INT) { ++ PRINTK3("%s: TX empty\n", dev->name); ++ mask &= ~IM_TX_EMPTY_INT; ++ ++ /* update stats */ ++ SMC_SELECT_BANK( 0 ); ++ card_stats = SMC_GET_COUNTER(); ++ SMC_SELECT_BANK( 2 ); ++ ++ /* single collisions */ ++ lp->stats.collisions += card_stats & 0xF; ++ card_stats >>= 4; ++ ++ /* multiple collisions */ ++ lp->stats.collisions += card_stats & 0xF; ++ } else if (status & IM_RX_OVRN_INT) { ++ PRINTK1( "%s: RX overrun\n", dev->name); ++ SMC_ACK_INT( IM_RX_OVRN_INT ); ++ lp->stats.rx_errors++; ++ lp->stats.rx_fifo_errors++; ++ } else if (status & IM_EPH_INT) { ++ PRINTK("%s: UNSUPPORTED: EPH INTERRUPT\n", dev->name); ++ } else if (status & IM_MDINT) { ++ SMC_ACK_INT( IM_MDINT ); ++ smc_phy_interrupt(dev); ++ } else if (status & IM_ERCV_INT ) { ++ SMC_ACK_INT( IM_ERCV_INT ); ++ PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n", dev->name); ++ } ++ } while (--timeout); ++ ++ /* restore register states */ ++ SMC_SET_INT_MASK( mask ); ++ SMC_SET_PTR( saved_pointer ); ++ SMC_SELECT_BANK( saved_bank ); ++ ++ PRINTK3("%s: Interrupt done\n", dev->name); ++} ++ ++/* Our watchdog timed out. Called by the networking layer */ ++static void ++smc_timeout(struct net_device *dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ ++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__); ++ ++ smc_reset(dev); ++ smc_enable(dev); ++ ++#if 0 ++ /* Reconfiguring the PHY doesn't seem like a bad idea here, but ++ * it introduced a problem. Now that this is a timeout routine, ++ * we are getting called from within an interrupt context. ++ * smc_phy_configure() calls smc_wait_ms() which calls ++ * schedule_timeout() which calls schedule(). When schedule() ++ * is called from an interrupt context, it prints out ++ * "Scheduling in interrupt" and then calls BUG(). This is ++ * obviously not desirable. This was worked around by removing ++ * the call to smc_phy_configure() here because it didn't seem ++ * absolutely necessary. Ultimately, if smc_wait_ms() is ++ * supposed to be usable from an interrupt context (which it ++ * looks like it thinks it should handle), it should be fixed. ++ */ ++ /* Reconfigure the PHY */ ++ smc_phy_configure(dev); ++#endif ++ ++ /* clear anything saved */ ++ if (lp->saved_skb != NULL) { ++ dev_kfree_skb (lp->saved_skb); ++ lp->saved_skb = NULL; ++ lp->stats.tx_errors++; ++ lp->stats.tx_aborted_errors++; ++ } ++ dev->trans_start = jiffies; ++ netif_wake_queue(dev); ++} ++ ++/* ++ * Finds the CRC32 of a set of bytes. ++ * (from Peter Cammaert's code) ++ */ ++static int ++crc32(char *s, int length) ++{ ++ /* indices */ ++ int perByte; ++ int perBit; ++ /* crc polynomial for Ethernet */ ++ const unsigned long poly = 0xedb88320; ++ /* crc value - preinitialized to all 1's */ ++ unsigned long crc_value = 0xffffffff; ++ ++ for ( perByte = 0; perByte < length; perByte ++ ) { ++ unsigned char c; ++ ++ c = *(s++); ++ for ( perBit = 0; perBit < 8; perBit++ ) { ++ crc_value = (crc_value>>1)^ ++ (((crc_value^c)&0x01)?poly:0); ++ c >>= 1; ++ } ++ } ++ return crc_value; ++} ++ ++/* ++ . This sets the internal hardware table to filter out unwanted multicast ++ . packets before they take up memory. ++ . ++ . The SMC chip uses a hash table where the high 6 bits of the CRC of ++ . address are the offset into the table. If that bit is 1, then the ++ . multicast packet is accepted. Otherwise, it's dropped silently. ++ . ++ . To use the 6 bits as an offset into the table, the high 3 bits are the ++ . number of the 8 bit register, while the low 3 bits are the bit within ++ . that register. ++ . ++ . This routine is based very heavily on the one provided by Peter Cammaert. ++*/ ++static void ++smc_setmulticast(unsigned long ioaddr, int count, struct dev_mc_list *addrs) ++{ ++ int i; ++ unsigned char multicast_table[ 8 ]; ++ struct dev_mc_list *cur_addr; ++ ++ /* table for flipping the order of 3 bits */ ++ static 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 ) ); ++ ++ cur_addr = addrs; ++ for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next ) { ++ int position; ++ ++ /* do we have a pointer here? */ ++ 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 ) ) ++ continue; ++ ++ /* only use the low order bits */ ++ position = crc32( cur_addr->dmi_addr, 6 ) & 0x3f; ++ ++ /* do some messy swapping to put the bit in the right spot */ ++ multicast_table[invert3[position&7]] |= ++ (1<<invert3[(position>>3)&7]); ++ ++ } ++ /* now, the table can be loaded into the chipset */ ++ SMC_SELECT_BANK( 3 ); ++ SMC_SET_MCAST( multicast_table ); ++} ++ ++/* ++ . 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 ++ . a select set of multicast packets ++*/ ++static void smc_set_multicast_list(struct net_device *dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ unsigned long ioaddr = dev->base_addr; ++ ++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__); ++ ++ SMC_SELECT_BANK(0); ++ if ( dev->flags & IFF_PROMISC ) { ++ PRINTK2("%s: RCR_PRMS\n", dev->name); ++ lp->rcr_cur_mode |= RCR_PRMS; ++ SMC_SET_RCR( lp->rcr_cur_mode ); ++ } ++ ++/* 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 ++ when promiscuous mode is turned on. ++*/ ++ ++ /* Here, I am setting this to accept all multicast packets. ++ I don't need to zero the multicast table, because the flag is ++ checked before the table is ++ */ ++ else if (dev->flags & IFF_ALLMULTI) { ++ lp->rcr_cur_mode |= RCR_ALMUL; ++ SMC_SET_RCR( lp->rcr_cur_mode ); ++ PRINTK2("%s: RCR_ALMUL\n", dev->name); ++ } ++ ++ /* 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 ) { ++ /* support hardware multicasting */ ++ ++ /* be sure I get rid of flags I might have set */ ++ lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL); ++ SMC_SET_RCR( lp->rcr_cur_mode ); ++ /* 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 ); ++ } else { ++ PRINTK2("%s: ~(RCR_PRMS|RCR_ALMUL)\n", dev->name); ++ lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL); ++ SMC_SET_RCR( lp->rcr_cur_mode ); ++ ++ /* ++ since I'm disabling all multicast entirely, I need to ++ clear the multicast list ++ */ ++ SMC_SELECT_BANK( 3 ); ++ SMC_CLEAR_MCAST(); ++ } ++} ++ ++ ++/* ++ * Open and Initialize the board ++ * ++ * Set up everything, reset the card, etc .. ++ */ ++static int ++smc_open(struct net_device *dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ unsigned long ioaddr = dev->base_addr; ++ ++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__); ++ ++ /* clear out all the junk that was put here before... */ ++ memset(dev->priv, 0, sizeof(struct smc_local)); ++ ++ // Setup the default Register Modes ++ lp->tcr_cur_mode = TCR_DEFAULT; ++ lp->rcr_cur_mode = RCR_DEFAULT; ++ lp->rpc_cur_mode = RPC_DEFAULT; ++ ++ /* Set default parameters */ ++#ifdef CONFIG_ARCH_RAMSES ++ lp->ctl_autoneg = 0; ++ lp->ctl_rfduplx = 0; ++ lp->ctl_rspeed = 10; ++#else ++ lp->ctl_autoneg = 1; ++ lp->ctl_rfduplx = 1; ++ lp->ctl_rspeed = 100; ++#endif ++ ++ SMC_SELECT_BANK(3); ++ lp->version = SMC_GET_REV() & 0xff; ++ ++ /* reset the hardware */ ++ smc_reset(dev); ++ smc_enable(dev); ++ ++ SMC_SELECT_BANK( 1 ); ++ SMC_SET_MAC_ADDR(dev->dev_addr); ++ ++ /* Configure the PHY */ ++ if (lp->version >= 0x70) ++ smc_phy_configure(dev); ++ ++ netif_start_queue(dev); ++ return 0; ++} ++ ++/*---------------------------------------------------- ++ . smc_close ++ . ++ . this makes the board clean up everything that it can ++ . and not talk to the outside world. Caused by ++ . an 'ifconfig ethX down' ++ . ++ -----------------------------------------------------*/ ++static int ++smc_close(struct net_device *dev) ++{ ++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__); ++ ++ netif_stop_queue(dev); ++ ++ /* clear everything */ ++ smc_shutdown(dev); ++ ++ return 0; ++} ++ ++/*------------------------------------------------------------ ++ . Get the current statistics. ++ . This may be called with the card open or closed. ++ .-------------------------------------------------------------*/ ++static struct net_device_stats * ++smc_query_statistics(struct net_device *dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ ++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__); ++ ++ return &lp->stats; ++} ++ ++/*---------------------------------------------------------------------- ++ . smc_findirq ++ . ++ . This routine has a simple purpose -- make the SMC chip generate an ++ . interrupt, so an auto-detect routine can detect it, and find the IRQ, ++ ------------------------------------------------------------------------ ++*/ ++int __init ++smc_findirq( unsigned long ioaddr ) ++{ ++ int timeout = 20; ++ unsigned long cookie; ++ ++ PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__); ++ ++ cookie = probe_irq_on(); ++ ++ /* ++ * What I try to do here is trigger an ALLOC_INT. This is done ++ * by allocating a small chunk of memory, which will give an interrupt ++ * when done. ++ */ ++ ++ /* enable ALLOCation interrupts ONLY */ ++ SMC_SELECT_BANK(2); ++ SMC_SET_INT_MASK( IM_ALLOC_INT ); ++ ++ /* ++ . Allocate 512 bytes of memory. Note that the chip was just ++ . reset so all the memory is available ++ */ ++ SMC_SET_MMU_CMD( MC_ALLOC | 1 ); ++ ++ /* ++ . Wait until positive that the interrupt has been generated ++ */ ++ do { ++ int int_status; ++ udelay(10); ++ int_status = SMC_GET_INT(); ++ if (int_status & IM_ALLOC_INT) ++ break; /* got the interrupt */ ++ } while (--timeout); ++ ++ /* there is really nothing that I can do here if timeout fails, ++ as autoirq_report will return a 0 anyway, which is what I ++ want in this case. Plus, the clean up is needed in both ++ cases. */ ++ ++ /* and disable all interrupts again */ ++ SMC_SET_INT_MASK( 0 ); ++ ++ /* and return what I found */ ++ return probe_irq_off(cookie); ++} ++ ++/*---------------------------------------------------------------------- ++ . Function: smc_probe( unsigned long ioaddr ) ++ . ++ . Purpose: ++ . Tests to see if a given ioaddr points to an SMC91x chip. ++ . Returns a 0 on success ++ . ++ . Algorithm: ++ . (1) see if the high byte of BANK_SELECT is 0x33 ++ . (2) compare the ioaddr with the base register's address ++ . (3) see if I recognize the chip ID in the appropriate register ++ . ++ .--------------------------------------------------------------------- ++ */ ++/*--------------------------------------------------------------- ++ . Here I do typical initialization tasks. ++ . ++ . o Initialize the structure if needed ++ . o print out my vanity message if not done so already ++ . o print out what type of hardware is detected ++ . o print out the ethernet address ++ . o find the IRQ ++ . o set up my private data ++ . o configure the dev structure with my subroutines ++ . o actually GRAB the irq. ++ . o GRAB the region ++ .----------------------------------------------------------------- ++*/ ++static int __init ++smc_probe(struct net_device *dev, unsigned long ioaddr) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ static int version_printed = 0; ++ int i, retval; ++ unsigned int val, revision_register; ++ const char *version_string; ++ ++ PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__); ++ ++ /* Grab the region so that no one else tries to probe our ioports. */ ++ if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name)) ++ return -EBUSY; ++ ++ /* First, see if the high byte is 0x33 */ ++ val = SMC_CURRENT_BANK(); ++ PRINTK2("%s: bank signature probe returned 0x%04x\n", CARDNAME, val); ++ if ( (val & 0xFF00) != 0x3300 ) { ++ if ( (val & 0xFF) == 0x33 ) { ++ printk( KERN_WARNING ++ "%s: Detected possible byte-swapped interface" ++ " at IOADDR 0x%lx\n", CARDNAME, ioaddr); ++ } ++ retval = -ENODEV; ++ goto err_out; ++ } ++ ++ /* The above MIGHT indicate a device, but I need to write to further ++ test this. */ ++ SMC_SELECT_BANK(0); ++ val = SMC_CURRENT_BANK(); ++ if ( (val & 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); ++ val = SMC_GET_BASE(); ++ val = ((val & 0x1F00) >> 3) << SMC_IO_SHIFT; ++ if ( (ioaddr & ((PAGE_SIZE-1)<<SMC_IO_SHIFT)) != val ) { ++ printk( "%s: IOADDR %lx doesn't match configuration (%x).\n", ++ CARDNAME, ioaddr, val ); ++ } ++ ++ /* 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 = SMC_GET_REV(); ++ PRINTK2("%s: revision = 0x%04x\n", CARDNAME, revision_register); ++ version_string = chip_ids[ (revision_register >> 4) & 0xF]; ++ if (!version_string || (revision_register & 0xff00) != 0x3300) { ++ /* I don't recognize this chip, so... */ ++ printk( "%s: IO 0x%lx: Unrecognized revision register 0x%04x" ++ ", Contact author.\n", CARDNAME, ++ ioaddr, revision_register); ++ ++ retval = -ENODEV; ++ goto err_out; ++ } ++ ++ /* At this point I'll assume that the chip is an SMC91x. */ ++ if (version_printed++ == 0) ++ printk("%s", version); ++ ++ /* set the private data to zero by default */ ++ memset(lp, 0, sizeof(struct smc_local)); ++ ++ /* fill in some of the fields */ ++ dev->base_addr = ioaddr; ++ lp->version = revision_register & 0xff; ++ ++ /* Get the MAC address */ ++ SMC_SELECT_BANK( 1 ); ++ SMC_GET_MAC_ADDR(dev->dev_addr); ++ ++ /* now, reset the chip, and put it into a known state */ ++ smc_reset( dev ); ++ ++ /* ++ . 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 < 1 ) { ++ int trials; ++ ++ trials = 3; ++ while ( trials-- ) { ++ dev->irq = smc_findirq( ioaddr ); ++ 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); ++ retval = -ENODEV; ++ goto err_out; ++ } ++ dev->irq = irq_cannonicalize(dev->irq); ++ ++ /* now, print out the card info, in a short format.. */ ++ printk( "%s: %s (rev %d) at %#lx IRQ %d%s%s\n", ++ dev->name, version_string, revision_register & 0x0f, ++ ioaddr, dev->irq, nowait ? " [nowait]" : "", ++ THROTTLE_TX_PKTS ? " [throttle_tx]" : "" ); ++ ++ /* Print the Ethernet address */ ++ printk("%s: Ethernet addr: ", dev->name); ++ for (i = 0; i < 5; i++) ++ 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) { ++ goto err_out; ++ } ++ ++ dev->open = smc_open; ++ dev->stop = smc_close; ++ dev->hard_start_xmit = smc_hard_start_xmit; ++ dev->tx_timeout = smc_timeout; ++ dev->watchdog_timeo = HZ/10; ++ dev->get_stats = smc_query_statistics; ++ dev->set_multicast_list = smc_set_multicast_list; ++ ++ return 0; ++ ++err_out: ++ release_region(ioaddr, SMC_IO_EXTENT); ++ return retval; ++} ++ ++/*------------------------------------------------------------------------- ++ | ++ | smc_init( void ) ++ | Input parameters: ++ | dev->base_addr == 0, try to find all possible locations ++ | dev->base_addr > 0x1ff, this is the address to check ++ | dev->base_addr == <anything else>, return failure code ++ | ++ | Output: ++ | 0 --> there is a device ++ | anything else, error ++ | ++ --------------------------------------------------------------------------- ++*/ ++static struct net_device *global_dev = NULL; /* needs to be fixed */ ++ ++#ifdef CONFIG_PM ++ ++static int smc_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) ++{ ++ unsigned long ioaddr = global_dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)global_dev->priv; ++ ++ switch (rqst) { ++ case PM_SUSPEND: ++ smc_shutdown(global_dev); ++ break; ++ case PM_RESUME: ++ smc_reset(global_dev); ++ smc_enable(global_dev); ++ SMC_SELECT_BANK( 1 ); ++ SMC_SET_MAC_ADDR(global_dev->dev_addr); ++ if (lp->version >= 0x70) ++ smc_phy_configure(global_dev); ++ break; ++ } ++ return 0; ++} ++ ++#endif ++ ++static int __init ++smc_init(void) ++{ ++ int ret; ++ ++ PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__); ++ ++#ifdef MODULE ++ if (io == -1) ++ printk( KERN_WARNING ++ "%s: You shouldn't use auto-probing with insmod!\n", ++ CARDNAME ); ++#endif ++ ++ if (global_dev) { ++ printk("%s: already initialized.\n", CARDNAME); ++ return -EBUSY; ++ } ++ ++ global_dev = init_etherdev(0, sizeof(struct smc_local)); ++ if (!global_dev) { ++ printk("%s: could not allocate device.\n", CARDNAME); ++ return -ENOMEM; ++ } ++ SET_MODULE_OWNER(global_dev); ++ ++ /* copy the parameters from insmod into the device structure */ ++ if (io != -1) ++ global_dev->base_addr = io; ++ if (irq != -1) ++ global_dev->irq = irq; ++ ++#ifdef CONFIG_ISA ++ /* try a specific location */ ++ if (global_dev->base_addr > 0x1ff) ++ ret = smc_probe(global_dev, global_dev->base_addr); ++ else if (global_dev->base_addr != 0) ++ ret = -ENXIO; ++ else { ++ int i; ++ ++ /* check every ethernet address */ ++ for (i = 0; smc_portlist[i]; i++) { ++ ret = smc_probe(global_dev, smc_portlist[i]); ++ if (ret == 0) ++ break; ++ } ++ } ++#elif defined(CONFIG_ARCH_LUBBOCK) ++ { ++ int ioaddr = LUBBOCK_ETH_VIRT + (0x300 << 2); ++ volatile int *attaddr = (int *)(LUBBOCK_ETH_VIRT + 0x100000); ++ unsigned long flags; ++ ++ /* first reset, then enable the device. Sequence is critical */ ++ local_irq_save(flags); ++ attaddr[ECOR] |= ECOR_RESET; ++ udelay(100); ++ attaddr[ECOR] &= ~ECOR_RESET; ++ attaddr[ECOR] |= ECOR_ENABLE; ++ ++ /* force 16-bit mode */ ++ attaddr[ECSR] &= ~ECSR_IOIS8; ++ mdelay(1); ++ local_irq_restore(flags); ++ ++ global_dev->irq = LUBBOCK_ETH_IRQ; ++ ret = smc_probe(global_dev, ioaddr); ++ } ++#elif defined(CONFIG_ARCH_PXA_IDP) ++ { ++ int ioaddr = IDP_ETH_BASE + 0x300; ++ global_dev->irq = SMC_IRQ; ++ ret = smc_probe(global_dev, ioaddr); ++ } ++#elif defined(CONFIG_ARCH_RAMSES) ++ { ++ int ioaddr = RAMSES_ETH_BASE + 0x300; ++ global_dev->irq = SMC_IRQ; ++ ret = smc_probe(global_dev, ioaddr); ++ } ++#else ++ if (global_dev->base_addr == -1) { ++ printk(KERN_WARNING"%s: SMC91X_BASE_ADDR not set!\n", CARDNAME); ++ ret = -ENXIO; ++ } else { ++ void *ioaddr = ioremap(global_dev->base_addr, SMC_IO_EXTENT); ++ ret = smc_probe(global_dev, (unsigned long)ioaddr); ++ if (ret != 0) ++ iounmap(ioaddr); ++ } ++#endif ++ ++#ifdef SMC_USE_PXA_DMA ++ if (ret == 0) { ++ int dma = pxa_request_dma(global_dev->name, DMA_PRIO_LOW, ++ smc_pxa_dma_irq, NULL); ++ if (dma >= 0) { ++ global_dev->dma = dma; ++ PRINTK("%s: using DMA channel %d\n", global_dev->name, dma); ++ } else { ++ global_dev->dma = -1; ++ } ++ } ++#endif ++ ++#ifdef CONFIG_PM ++ if (ret == 0) { ++ struct smc_local *lp = (struct smc_local *)global_dev->priv; ++ lp->pm = pm_register(PM_SYS_UNKNOWN, 0x73393178, smc_pm_callback); ++ } ++#endif ++ ++ if (ret != 0) { ++ printk("%s: not found.\n", CARDNAME); ++ kfree(global_dev->priv); ++ unregister_netdev(global_dev); ++ kfree(global_dev); ++ } ++ ++ return ret; ++} ++ ++static void __exit ++smc_cleanup(void) ++{ ++ unregister_netdev(global_dev); ++#ifdef CONFIG_PM ++ { ++ struct smc_local *lp = (struct smc_local *)global_dev->priv; ++ pm_unregister(lp->pm); ++ } ++#endif ++ free_irq(global_dev->irq, global_dev); ++ release_region(global_dev->base_addr, SMC_IO_EXTENT); ++ ++#ifndef CONFIG_ISA ++ iounmap((void *)global_dev->base_addr); ++#endif ++ ++ kfree(global_dev); ++ global_dev = NULL; ++} ++ ++module_init(smc_init); ++module_exit(smc_cleanup); ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/net/smc91x.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,835 @@ ++/*------------------------------------------------------------------------ ++ . smc91x.h - macros for SMSC's 91C9x/91C1xx single-chip Ethernet device. ++ . ++ . Copyright (C) 1996 by Erik Stahlman ++ . Copyright (C) 2001 Standard Microsystems Corporation ++ . Developed by Simple Network Magic Corporation ++ . Copyright (C) 2003 Monta Vista Software, Inc. ++ . Unified SMC91x driver by Nicolas Pitre ++ . ++ . 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 ++ . ++ . Information contained in this file was obtained from the LAN91C111 ++ . manual from SMC. To get a copy, if you really want one, you can find ++ . information under www.smsc.com. ++ . ++ . Authors ++ . Erik Stahlman <erik@vt.edu> ++ . Daris A Nevil <dnevil@snmc.com> ++ . Nicolas Pitre <nico@cam.org> ++ . ++ ---------------------------------------------------------------------------*/ ++#ifndef _SMC91X_H_ ++#define _SMC91X_H_ ++ ++ ++/* ++ * Define your architecture specific configuration parameters here. ++ */ ++ ++#if defined(CONFIG_SA1100_GRAPHICSCLIENT) || \ ++ defined(CONFIG_SA1100_PFS168) || \ ++ defined(CONFIG_SA1100_FLEXANET) || \ ++ defined(CONFIG_SA1100_GRAPHICSMASTER) || \ ++ defined(CONFIG_ARCH_LUBBOCK) ++ ++/* We can only do 16-bit reads and writes in the static memory space. */ ++#define SMC_CAN_USE_8BIT 0 ++#define SMC_CAN_USE_16BIT 1 ++#define SMC_CAN_USE_32BIT 0 ++#define SMC_NOWAIT 1 ++ ++/* The first two address lines aren't connected... */ ++#define SMC_IO_SHIFT 2 ++ ++#define SMC_inw(a, r) readw((a) + (r)) ++#define SMC_outw(v, a, r) writew(v, (a) + (r)) ++#define SMC_insw(a, r, p, l) insw((a) + (r), p, l) ++#define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l) ++ ++#ifdef CONFIG_ARCH_LUBBOCK ++#define SMC_IOADDR LUBBOCK_ETH_PHYS ++#endif ++ ++#elif defined(CONFIG_ARCH_MAINSTONE) || defined(CONFIG_ARCH_PXA_IDP) || defined(CONFIG_ARCH_RAMSES) ++ ++#ifdef CONFIG_ARCH_MAINSTONE ++#include <asm/arch/mainstone.h> ++#define SMC_IOADDR (MST_ETH_PHYS + 0x300) ++#define SMC_IRQ MAINSTONE_IRQ(3) ++ ++#elif CONFIG_ARCH_PXA_IDP ++#include <asm/arch/idp.h> ++#define SMC_IOADDR (IDP_ETH_PHYS + 0x300) ++#define SMC_IRQ ETHERNET_IRQ ++ ++#elif CONFIG_ARCH_RAMSES ++#include <asm/arch/ramses.h> ++#define SMC_IOADDR (RAMSES_ETH_PHYS + 0x300) ++#define SMC_IRQ ETHERNET_IRQ ++#endif ++ ++#define SMC_CAN_USE_8BIT 1 ++#define SMC_CAN_USE_16BIT 1 ++#define SMC_CAN_USE_32BIT 1 ++#define SMC_IO_SHIFT 0 ++#define SMC_NOWAIT 1 ++#define SMC_USE_PXA_DMA 1 ++ ++#define SMC_inb(a, r) readb((a) + (r)) ++#define SMC_inw(a, r) readw((a) + (r)) ++#define SMC_inl(a, r) readl((a) + (r)) ++#define SMC_outb(v, a, r) writeb(v, (a) + (r)) ++#define SMC_outl(v, a, r) writel(v, (a) + (r)) ++#define SMC_insl(a, r, p, l) insl((a) + (r), p, l) ++#define SMC_outsl(a, r, p, l) outsl((a) + (r), p, l) ++ ++/* We actually can't write halfwords properly if not word aligned */ ++static inline void ++SMC_outw(u16 val, unsigned long ioaddr, int reg) ++{ ++ if (reg & 2) { ++ unsigned int v = val << 16; ++ v |= readl(ioaddr + (reg & ~2)) & 0xffff; ++ writel(v, ioaddr + (reg & ~2)); ++ } else { ++ writew(val, ioaddr + reg); ++ } ++} ++ ++#elif defined(CONFIG_ISA) ++ ++#define SMC_CAN_USE_8BIT 1 ++#define SMC_CAN_USE_16BIT 1 ++#define SMC_CAN_USE_32BIT 0 ++ ++#define SMC_inb(a, r) inb((a) + (r)) ++#define SMC_inw(a, r) inw((a) + (r)) ++#define SMC_outb(v, a, r) outb(v, (a) + (r)) ++#define SMC_outw(v, a, r) outw(v, (a) + (r)) ++#define SMC_insw(a, r, p, l) insw((a) + (r), p, l) ++#define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l) ++ ++#endif ++ ++ ++#ifdef SMC_USE_PXA_DMA ++/* ++ * Let's use the DMA engine on the XScale PXA2xx for RX packets. This is ++ * always happening in irq context so no need to worry about races. TX is ++ * different and probably not worth it for that reason, and not as critical ++ * as RX which can overrun memory and lose packets. ++ */ ++#include <linux/pci.h> ++#include <asm/dma.h> ++ ++#ifdef SMC_insl ++#undef SMC_insl ++#define SMC_insl(a, r, p, l) smc_pxa_dma_insl(a, r, dev->dma, p, l) ++static inline void ++smc_pxa_dma_insl(u_long ioaddr, int reg, int dma, u_char *buf, int len) ++{ ++ dma_addr_t dmabuf; ++ ++ /* fallback if no DMA available */ ++ if (dma == -1) { ++ insl(ioaddr + reg, buf, len); ++ return; ++ } ++ ++ /* 64 bit alignment is required for memory to memory DMA */ ++ if ((long)buf & 4) { ++ *((u32 *)buf)++ = SMC_inl(ioaddr, reg); ++ len--; ++ } ++ ++ len *= 4; ++ dmabuf = pci_map_single(NULL, buf, len, PCI_DMA_FROMDEVICE); ++ DCSR(dma) = DCSR_NODESC; ++ DTADR(dma) = dmabuf; ++ DSADR(dma) = SMC_IOADDR + reg; ++ DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 | ++ DCMD_WIDTH4 | (DCMD_LENGTH & len)); ++ DCSR(dma) = DCSR_NODESC | DCSR_RUN; ++ while (!(DCSR(dma) & DCSR_STOPSTATE)); ++ DCSR(dma) = 0; ++ pci_unmap_single(NULL, dmabuf,len, PCI_DMA_FROMDEVICE); ++} ++#endif ++ ++#ifdef SMC_insw ++#undef SMC_insw ++#define SMC_insw(a, r, p, l) smc_pxa_dma_insw(a, r, dev->dma, p, l) ++static inline void ++smc_pxa_dma_insw(u_long ioaddr, int reg, int dma, u_char *buf, int len) ++{ ++ dma_addr_t dmabuf; ++ ++ /* fallback if no DMA available */ ++ if (dma == -1) { ++ insw(ioaddr + reg, buf, len); ++ return; ++ } ++ ++ /* 64 bit alignment is required for memory to memory DMA */ ++ while ((long)buf & 6) { ++ *((u16 *)buf)++ = SMC_inw(ioaddr, reg); ++ len--; ++ } ++ ++ len *= 2; ++ dmabuf = pci_map_single(NULL, buf, len, PCI_DMA_FROMDEVICE); ++ DCSR(dma) = DCSR_NODESC; ++ DTADR(dma) = dmabuf; ++ DSADR(dma) = SMC_IOADDR + reg; ++ DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 | ++ DCMD_WIDTH2 | (DCMD_LENGTH & len)); ++ DCSR(dma) = DCSR_NODESC | DCSR_RUN; ++ while (!(DCSR(dma) & DCSR_STOPSTATE)); ++ DCSR(dma) = 0; ++ pci_unmap_single(NULL, dmabuf,len, PCI_DMA_FROMDEVICE); ++} ++#endif ++ ++static void ++smc_pxa_dma_irq(int dma, void *dummy, struct pt_regs *regs) ++{ ++ DCSR(dma) = 0; ++} ++#endif /* SMC_USE_PXA_DMA */ ++ ++ ++/* Because of bank switching, the LAN91xxx uses only 16 I/O ports */ ++#ifndef SMC_IO_SHIFT ++#define SMC_IO_SHIFT 0 ++#endif ++#define SMC_IO_EXTENT (16 << SMC_IO_SHIFT) ++ ++ ++/* ++ . Bank Select Register: ++ . ++ . yyyy yyyy 0000 00xx ++ . xx = bank number ++ . yyyy yyyy = 0x33, for identification purposes. ++*/ ++#define BANK_SELECT (14 << SMC_IO_SHIFT) ++ ++ ++// Transmit Control Register ++/* BANK 0 */ ++#define TCR_REG SMC_REG(0x0000, 0) ++#define TCR_ENABLE 0x0001 // When 1 we can transmit ++#define TCR_LOOP 0x0002 // Controls output pin LBK ++#define TCR_FORCOL 0x0004 // When 1 will force a collision ++#define TCR_PAD_EN 0x0080 // When 1 will pad tx frames < 64 bytes w/0 ++#define TCR_NOCRC 0x0100 // When 1 will not append CRC to tx frames ++#define TCR_MON_CSN 0x0400 // When 1 tx monitors carrier ++#define TCR_FDUPLX 0x0800 // When 1 enables full duplex operation ++#define TCR_STP_SQET 0x1000 // When 1 stops tx if Signal Quality Error ++#define TCR_EPH_LOOP 0x2000 // When 1 enables EPH block loopback ++#define TCR_SWFDUP 0x8000 // When 1 enables Switched Full Duplex mode ++ ++#define TCR_CLEAR 0 /* do NOTHING */ ++/* the default settings for the TCR register : */ ++#define TCR_DEFAULT (TCR_ENABLE | TCR_PAD_EN) ++ ++ ++// EPH Status Register ++/* BANK 0 */ ++#define EPH_STATUS_REG SMC_REG(0x0002, 0) ++#define ES_TX_SUC 0x0001 // Last TX was successful ++#define ES_SNGL_COL 0x0002 // Single collision detected for last tx ++#define ES_MUL_COL 0x0004 // Multiple collisions detected for last tx ++#define ES_LTX_MULT 0x0008 // Last tx was a multicast ++#define ES_16COL 0x0010 // 16 Collisions Reached ++#define ES_SQET 0x0020 // Signal Quality Error Test ++#define ES_LTXBRD 0x0040 // Last tx was a broadcast ++#define ES_TXDEFR 0x0080 // Transmit Deferred ++#define ES_LATCOL 0x0200 // Late collision detected on last tx ++#define ES_LOSTCARR 0x0400 // Lost Carrier Sense ++#define ES_EXC_DEF 0x0800 // Excessive Deferral ++#define ES_CTR_ROL 0x1000 // Counter Roll Over indication ++#define ES_LINK_OK 0x4000 // Driven by inverted value of nLNK pin ++#define ES_TXUNRN 0x8000 // Tx Underrun ++ ++ ++// Receive Control Register ++/* BANK 0 */ ++#define RCR_REG SMC_REG(0x0004, 0) ++#define RCR_RX_ABORT 0x0001 // Set if a rx frame was aborted ++#define RCR_PRMS 0x0002 // Enable promiscuous mode ++#define RCR_ALMUL 0x0004 // When set accepts all multicast frames ++#define RCR_RXEN 0x0100 // IFF this is set, we can receive packets ++#define RCR_STRIP_CRC 0x0200 // When set strips CRC from rx packets ++#define RCR_ABORT_ENB 0x0200 // When set will abort rx on collision ++#define RCR_FILT_CAR 0x0400 // When set filters leading 12 bit s of carrier ++#define RCR_SOFTRST 0x8000 // resets the chip ++ ++/* the normal settings for the RCR register : */ ++#define RCR_DEFAULT (RCR_STRIP_CRC | RCR_RXEN) ++#define RCR_CLEAR 0x0 // set it to a base state ++ ++ ++// Counter Register ++/* BANK 0 */ ++#define COUNTER_REG SMC_REG(0x0006, 0) ++ ++ ++// Memory Information Register ++/* BANK 0 */ ++#define MIR_REG SMC_REG(0x0008, 0) ++ ++ ++// Receive/Phy Control Register ++/* BANK 0 */ ++#define RPC_REG SMC_REG(0x000A, 0) ++#define RPC_SPEED 0x2000 // When 1 PHY is in 100Mbps mode. ++#define RPC_DPLX 0x1000 // When 1 PHY is in Full-Duplex Mode ++#define RPC_ANEG 0x0800 // When 1 PHY is in Auto-Negotiate Mode ++#define RPC_LSXA_SHFT 5 // Bits to shift LS2A,LS1A,LS0A to lsb ++#define RPC_LSXB_SHFT 2 // Bits to get LS2B,LS1B,LS0B to lsb ++#define RPC_LED_100_10 (0x00) // LED = 100Mbps OR's with 10Mbps link detect ++#define RPC_LED_RES (0x01) // LED = Reserved ++#define RPC_LED_10 (0x02) // LED = 10Mbps link detect ++#define RPC_LED_FD (0x03) // LED = Full Duplex Mode ++#define RPC_LED_TX_RX (0x04) // LED = TX or RX packet occurred ++#define RPC_LED_100 (0x05) // LED = 100Mbps link dectect ++#define RPC_LED_TX (0x06) // LED = TX packet occurred ++#define RPC_LED_RX (0x07) // LED = RX packet occurred ++#define RPC_DEFAULT (RPC_ANEG | (RPC_LED_100 << RPC_LSXA_SHFT) | (RPC_LED_FD << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX) ++ ++ ++/* Bank 0 0x0C is reserved */ ++ ++// Bank Select Register ++/* All Banks */ ++#define BSR_REG 0x000E ++ ++ ++// Configuration Reg ++/* BANK 1 */ ++#define CONFIG_REG SMC_REG(0x0000, 1) ++#define CONFIG_EXT_PHY 0x0200 // 1=external MII, 0=internal Phy ++#define CONFIG_GPCNTRL 0x0400 // Inverse value drives pin nCNTRL ++#define CONFIG_NO_WAIT 0x1000 // When 1 no extra wait states on ISA bus ++#define CONFIG_EPH_POWER_EN 0x8000 // When 0 EPH is placed into low power mode. ++ ++// Default is powered-up, Internal Phy, Wait States, and pin nCNTRL=low ++#define CONFIG_DEFAULT (CONFIG_EPH_POWER_EN) ++ ++ ++// Base Address Register ++/* BANK 1 */ ++#define BASE_REG SMC_REG(0x0002, 1) ++ ++ ++// Individual Address Registers ++/* BANK 1 */ ++#define ADDR0_REG SMC_REG(0x0004, 1) ++#define ADDR1_REG SMC_REG(0x0006, 1) ++#define ADDR2_REG SMC_REG(0x0008, 1) ++ ++ ++// General Purpose Register ++/* BANK 1 */ ++#define GP_REG SMC_REG(0x000A, 1) ++ ++ ++// Control Register ++/* BANK 1 */ ++#define CTL_REG SMC_REG(0x000C, 1) ++#define CTL_RCV_BAD 0x4000 // When 1 bad CRC packets are received ++#define CTL_AUTO_RELEASE 0x0800 // When 1 tx pages are released automatically ++#define CTL_LE_ENABLE 0x0080 // When 1 enables Link Error interrupt ++#define CTL_CR_ENABLE 0x0040 // When 1 enables Counter Rollover interrupt ++#define CTL_TE_ENABLE 0x0020 // When 1 enables Transmit Error interrupt ++#define CTL_EEPROM_SELECT 0x0004 // Controls EEPROM reload & store ++#define CTL_RELOAD 0x0002 // When set reads EEPROM into registers ++#define CTL_STORE 0x0001 // When set stores registers into EEPROM ++ ++ ++// MMU Command Register ++/* BANK 2 */ ++#define MMU_CMD_REG SMC_REG(0x0000, 2) ++#define MC_BUSY 1 // When 1 the last release has not completed ++#define MC_NOP (0<<5) // No Op ++#define MC_ALLOC (1<<5) // OR with number of 256 byte packets ++#define MC_RESET (2<<5) // Reset MMU to initial state ++#define MC_REMOVE (3<<5) // Remove the current rx packet ++#define MC_RELEASE (4<<5) // Remove and release the current rx packet ++#define MC_FREEPKT (5<<5) // Release packet in PNR register ++#define MC_ENQUEUE (6<<5) // Enqueue the packet for transmit ++#define MC_RSTTXFIFO (7<<5) // Reset the TX FIFOs ++ ++ ++// Packet Number Register ++/* BANK 2 */ ++#define PN_REG SMC_REG(0x0002, 2) ++ ++ ++// Allocation Result Register ++/* BANK 2 */ ++#define AR_REG SMC_REG(0x0003, 2) ++#define AR_FAILED 0x80 // Alocation Failed ++ ++ ++// TX FIFO Ports Register ++/* BANK 2 */ ++#define TXFIFO_REG SMC_REG(0x0004, 2) ++#define TXFIFO_TEMPTY 0x80 // TX FIFO Empty ++ ++// RX FIFO Ports Register ++/* BANK 2 */ ++#define RXFIFO_REG SMC_REG(0x0005, 2) ++#define RXFIFO_REMPTY 0x80 // RX FIFO Empty ++ ++#define FIFO_REG SMC_REG(0x0004, 2) ++ ++// Pointer Register ++/* BANK 2 */ ++#define PTR_REG SMC_REG(0x0006, 2) ++#define PTR_RCV 0x8000 // 1=Receive area, 0=Transmit area ++#define PTR_AUTOINC 0x4000 // Auto increment the pointer on each access ++#define PTR_READ 0x2000 // When 1 the operation is a read ++ ++ ++// Data Register ++/* BANK 2 */ ++#define DATA_REG SMC_REG(0x0008, 2) ++ ++ ++// Interrupt Status/Acknowledge Register ++/* BANK 2 */ ++#define INT_REG SMC_REG(0x000C, 2) ++ ++ ++// Interrupt Mask Register ++/* BANK 2 */ ++#define IM_REG SMC_REG(0x000D, 2) ++#define IM_MDINT 0x80 // PHY MI Register 18 Interrupt ++#define IM_ERCV_INT 0x40 // Early Receive Interrupt ++#define IM_EPH_INT 0x20 // Set by Ethernet Protocol Handler section ++#define IM_RX_OVRN_INT 0x10 // Set by Receiver Overruns ++#define IM_ALLOC_INT 0x08 // Set when allocation request is completed ++#define IM_TX_EMPTY_INT 0x04 // Set if the TX FIFO goes empty ++#define IM_TX_INT 0x02 // Transmit Interrupt ++#define IM_RCV_INT 0x01 // Receive Interrupt ++ ++ ++// Multicast Table Registers ++/* BANK 3 */ ++#define MCAST_REG1 SMC_REG(0x0000, 3) ++#define MCAST_REG2 SMC_REG(0x0002, 3) ++#define MCAST_REG3 SMC_REG(0x0004, 3) ++#define MCAST_REG4 SMC_REG(0x0006, 3) ++ ++ ++// Management Interface Register (MII) ++/* BANK 3 */ ++#define MII_REG SMC_REG(0x0008, 3) ++#define MII_MSK_CRS100 0x4000 // Disables CRS100 detection during tx half dup ++#define MII_MDOE 0x0008 // MII Output Enable ++#define MII_MCLK 0x0004 // MII Clock, pin MDCLK ++#define MII_MDI 0x0002 // MII Input, pin MDI ++#define MII_MDO 0x0001 // MII Output, pin MDO ++ ++ ++// Revision Register ++/* BANK 3 */ ++/* ( hi: chip id low: rev # ) */ ++#define REV_REG SMC_REG(0x000A, 3) ++ ++ ++// Early RCV Register ++/* BANK 3 */ ++/* this is NOT on SMC9192 */ ++#define ERCV_REG SMC_REG(0x000C, 3) ++#define ERCV_RCV_DISCRD 0x0080 // When 1 discards a packet being received ++#define ERCV_THRESHOLD 0x001F // ERCV Threshold Mask ++ ++ ++// External Register ++/* BANK 7 */ ++#define EXT_REG SMC_REG(0x0000, 7) ++ ++ ++#define CHIP_9192 3 ++#define CHIP_9194 4 ++#define CHIP_9195 5 ++#define CHIP_9196 6 ++#define CHIP_91100 7 ++#define CHIP_91100FD 8 ++#define CHIP_91111FD 9 ++ ++static const char * chip_ids[ 16 ] = { ++ NULL, NULL, NULL, ++ /* 3 */ "SMC91C90/91C92", ++ /* 4 */ "SMC91C94", ++ /* 5 */ "SMC91C95", ++ /* 6 */ "SMC91C96", ++ /* 7 */ "SMC91C100", ++ /* 8 */ "SMC91C100FD", ++ /* 9 */ "SMC91C11xFD", ++ NULL, NULL, NULL, ++ NULL, NULL, NULL}; ++ ++ ++/* ++ . Transmit status bits ++*/ ++#define TS_SUCCESS 0x0001 ++#define TS_LOSTCAR 0x0400 ++#define TS_LATCOL 0x0200 ++#define TS_16COL 0x0010 ++ ++/* ++ . Receive status bits ++*/ ++#define RS_ALGNERR 0x8000 ++#define RS_BRODCAST 0x4000 ++#define RS_BADCRC 0x2000 ++#define RS_ODDFRAME 0x1000 ++#define RS_TOOLONG 0x0800 ++#define RS_TOOSHORT 0x0400 ++#define RS_MULTICAST 0x0001 ++#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT) ++ ++ ++// PHY Types ++enum { ++ PHY_LAN83C183 = 1, // LAN91C111 Internal PHY ++ PHY_LAN83C180 ++}; ++ ++ ++// PHY Register Addresses (LAN91C111 Internal PHY) ++ ++// PHY Control Register ++#define PHY_CNTL_REG 0x00 ++#define PHY_CNTL_RST 0x8000 // 1=PHY Reset ++#define PHY_CNTL_LPBK 0x4000 // 1=PHY Loopback ++#define PHY_CNTL_SPEED 0x2000 // 1=100Mbps, 0=10Mpbs ++#define PHY_CNTL_ANEG_EN 0x1000 // 1=Enable Auto negotiation ++#define PHY_CNTL_PDN 0x0800 // 1=PHY Power Down mode ++#define PHY_CNTL_MII_DIS 0x0400 // 1=MII 4 bit interface disabled ++#define PHY_CNTL_ANEG_RST 0x0200 // 1=Reset Auto negotiate ++#define PHY_CNTL_DPLX 0x0100 // 1=Full Duplex, 0=Half Duplex ++#define PHY_CNTL_COLTST 0x0080 // 1= MII Colision Test ++ ++// PHY Status Register ++#define PHY_STAT_REG 0x01 ++#define PHY_STAT_CAP_T4 0x8000 // 1=100Base-T4 capable ++#define PHY_STAT_CAP_TXF 0x4000 // 1=100Base-X full duplex capable ++#define PHY_STAT_CAP_TXH 0x2000 // 1=100Base-X half duplex capable ++#define PHY_STAT_CAP_TF 0x1000 // 1=10Mbps full duplex capable ++#define PHY_STAT_CAP_TH 0x0800 // 1=10Mbps half duplex capable ++#define PHY_STAT_CAP_SUPR 0x0040 // 1=recv mgmt frames with not preamble ++#define PHY_STAT_ANEG_ACK 0x0020 // 1=ANEG has completed ++#define PHY_STAT_REM_FLT 0x0010 // 1=Remote Fault detected ++#define PHY_STAT_CAP_ANEG 0x0008 // 1=Auto negotiate capable ++#define PHY_STAT_LINK 0x0004 // 1=valid link ++#define PHY_STAT_JAB 0x0002 // 1=10Mbps jabber condition ++#define PHY_STAT_EXREG 0x0001 // 1=extended registers implemented ++ ++// PHY Identifier Registers ++#define PHY_ID1_REG 0x02 // PHY Identifier 1 ++#define PHY_ID2_REG 0x03 // PHY Identifier 2 ++ ++// PHY Auto-Negotiation Advertisement Register ++#define PHY_AD_REG 0x04 ++#define PHY_AD_NP 0x8000 // 1=PHY requests exchange of Next Page ++#define PHY_AD_ACK 0x4000 // 1=got link code word from remote ++#define PHY_AD_RF 0x2000 // 1=advertise remote fault ++#define PHY_AD_T4 0x0200 // 1=PHY is capable of 100Base-T4 ++#define PHY_AD_TX_FDX 0x0100 // 1=PHY is capable of 100Base-TX FDPLX ++#define PHY_AD_TX_HDX 0x0080 // 1=PHY is capable of 100Base-TX HDPLX ++#define PHY_AD_10_FDX 0x0040 // 1=PHY is capable of 10Base-T FDPLX ++#define PHY_AD_10_HDX 0x0020 // 1=PHY is capable of 10Base-T HDPLX ++#define PHY_AD_CSMA 0x0001 // 1=PHY is capable of 802.3 CMSA ++ ++// PHY Auto-negotiation Remote End Capability Register ++#define PHY_RMT_REG 0x05 ++// Uses same bit definitions as PHY_AD_REG ++ ++// PHY Configuration Register 1 ++#define PHY_CFG1_REG 0x10 ++#define PHY_CFG1_LNKDIS 0x8000 // 1=Rx Link Detect Function disabled ++#define PHY_CFG1_XMTDIS 0x4000 // 1=TP Transmitter Disabled ++#define PHY_CFG1_XMTPDN 0x2000 // 1=TP Transmitter Powered Down ++#define PHY_CFG1_BYPSCR 0x0400 // 1=Bypass scrambler/descrambler ++#define PHY_CFG1_UNSCDS 0x0200 // 1=Unscramble Idle Reception Disable ++#define PHY_CFG1_EQLZR 0x0100 // 1=Rx Equalizer Disabled ++#define PHY_CFG1_CABLE 0x0080 // 1=STP(150ohm), 0=UTP(100ohm) ++#define PHY_CFG1_RLVL0 0x0040 // 1=Rx Squelch level reduced by 4.5db ++#define PHY_CFG1_TLVL_SHIFT 2 // Transmit Output Level Adjust ++#define PHY_CFG1_TLVL_MASK 0x003C ++#define PHY_CFG1_TRF_MASK 0x0003 // Transmitter Rise/Fall time ++ ++ ++// PHY Configuration Register 2 ++#define PHY_CFG2_REG 0x11 ++#define PHY_CFG2_APOLDIS 0x0020 // 1=Auto Polarity Correction disabled ++#define PHY_CFG2_JABDIS 0x0010 // 1=Jabber disabled ++#define PHY_CFG2_MREG 0x0008 // 1=Multiple register access (MII mgt) ++#define PHY_CFG2_INTMDIO 0x0004 // 1=Interrupt signaled with MDIO pulseo ++ ++// PHY Status Output (and Interrupt status) Register ++#define PHY_INT_REG 0x12 // Status Output (Interrupt Status) ++#define PHY_INT_INT 0x8000 // 1=bits have changed since last read ++#define PHY_INT_LNKFAIL 0x4000 // 1=Link Not detected ++#define PHY_INT_LOSSSYNC 0x2000 // 1=Descrambler has lost sync ++#define PHY_INT_CWRD 0x1000 // 1=Invalid 4B5B code detected on rx ++#define PHY_INT_SSD 0x0800 // 1=No Start Of Stream detected on rx ++#define PHY_INT_ESD 0x0400 // 1=No End Of Stream detected on rx ++#define PHY_INT_RPOL 0x0200 // 1=Reverse Polarity detected ++#define PHY_INT_JAB 0x0100 // 1=Jabber detected ++#define PHY_INT_SPDDET 0x0080 // 1=100Base-TX mode, 0=10Base-T mode ++#define PHY_INT_DPLXDET 0x0040 // 1=Device in Full Duplex ++ ++// PHY Interrupt/Status Mask Register ++#define PHY_MASK_REG 0x13 // Interrupt Mask ++// Uses the same bit definitions as PHY_INT_REG ++ ++ ++/* ++ * 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 ++ ++ ++/* ++ * Macros to abstract register access according to the data bus ++ * capabilities. Please try to use those and not the in/out primitives. ++ * Note: the following macros do *not* select the bank -- this must ++ * be done separately as needed in the main code. The SMC_REG() macro ++ * only uses the bank argument for debugging purposes. ++ */ ++ ++#if SMC_DEBUG > 0 ++#define SMC_REG(reg, bank) \ ++ ({ \ ++ int __b = SMC_CURRENT_BANK(); \ ++ if ((__b & ~0xf0) != (0x3300 | bank)) { \ ++ printk( "%s: bank reg screwed (0x%04x)\n", \ ++ CARDNAME, __b ); \ ++ BUG(); \ ++ } \ ++ reg<<SMC_IO_SHIFT; \ ++ }) ++#else ++#define SMC_REG(reg, bank) (reg<<SMC_IO_SHIFT) ++#endif ++ ++#if SMC_CAN_USE_8BIT ++#define SMC_GET_PN() SMC_inb( ioaddr, PN_REG ) ++#define SMC_SET_PN(x) SMC_outb( x, ioaddr, PN_REG ) ++#define SMC_GET_AR() SMC_inb( ioaddr, AR_REG ) ++#define SMC_GET_TXFIFO() SMC_inb( ioaddr, TXFIFO_REG ) ++#define SMC_GET_RXFIFO() SMC_inb( ioaddr, RXFIFO_REG ) ++#define SMC_GET_INT() SMC_inb( ioaddr, INT_REG ) ++#define SMC_ACK_INT(x) SMC_outb( x, ioaddr, INT_REG ) ++#define SMC_GET_INT_MASK() SMC_inb( ioaddr, IM_REG ) ++#define SMC_SET_INT_MASK(x) SMC_outb( x, ioaddr, IM_REG ) ++#else ++#define SMC_GET_PN() (SMC_inw( ioaddr, PN_REG ) & 0xFF) ++#define SMC_SET_PN(x) SMC_outw( x, ioaddr, PN_REG ) ++#define SMC_GET_AR() (SMC_inw( ioaddr, PN_REG ) >> 8) ++#define SMC_GET_TXFIFO() (SMC_inw( ioaddr, TXFIFO_REG ) & 0xFF) ++#define SMC_GET_RXFIFO() (SMC_inw( ioaddr, TXFIFO_REG ) >> 8) ++#define SMC_GET_INT() (SMC_inw( ioaddr, INT_REG ) & 0xFF) ++#define SMC_ACK_INT(x) \ ++ do { \ ++ unsigned long __flags; \ ++ int __mask; \ ++ local_irq_save(__flags); \ ++ __mask = SMC_inw( ioaddr, INT_REG ) & ~0xff; \ ++ SMC_outw( __mask | (x), ioaddr, INT_REG ); \ ++ local_irq_restore(__flags); \ ++ } while (0) ++#define SMC_GET_INT_MASK() (SMC_inw( ioaddr, INT_REG ) >> 8) ++#define SMC_SET_INT_MASK(x) SMC_outw( (x) << 8, ioaddr, INT_REG ) ++#endif ++ ++#define SMC_CURRENT_BANK() SMC_inw( ioaddr, BANK_SELECT ) ++#define SMC_SELECT_BANK(x) SMC_outw( x, ioaddr, BANK_SELECT ) ++#define SMC_GET_BASE() SMC_inw( ioaddr, BASE_REG ) ++#define SMC_SET_BASE(x) SMC_outw( x, ioaddr, BASE_REG ) ++#define SMC_GET_CONFIG() SMC_inw( ioaddr, CONFIG_REG ) ++#define SMC_SET_CONFIG(x) SMC_outw( x, ioaddr, CONFIG_REG ) ++#define SMC_GET_COUNTER() SMC_inw( ioaddr, COUNTER_REG ) ++#define SMC_GET_CTL() SMC_inw( ioaddr, CTL_REG ) ++#define SMC_SET_CTL(x) SMC_outw( x, ioaddr, CTL_REG ) ++#define SMC_GET_MII() SMC_inw( ioaddr, MII_REG ) ++#define SMC_SET_MII(x) SMC_outw( x, ioaddr, MII_REG ) ++#define SMC_GET_MIR() SMC_inw( ioaddr, MIR_REG ) ++#define SMC_SET_MIR(x) SMC_outw( x, ioaddr, MIR_REG ) ++#define SMC_GET_MMU_CMD() SMC_inw( ioaddr, MMU_CMD_REG ) ++#define SMC_SET_MMU_CMD(x) SMC_outw( x, ioaddr, MMU_CMD_REG ) ++#define SMC_GET_FIFO() SMC_inw( ioaddr, FIFO_REG ) ++#define SMC_GET_PTR() SMC_inw( ioaddr, PTR_REG ) ++#define SMC_SET_PTR(x) SMC_outw( x, ioaddr, PTR_REG ) ++#define SMC_GET_RCR() SMC_inw( ioaddr, RCR_REG ) ++#define SMC_SET_RCR(x) SMC_outw( x, ioaddr, RCR_REG ) ++#define SMC_GET_REV() SMC_inw( ioaddr, REV_REG ) ++#define SMC_GET_RPC() SMC_inw( ioaddr, RPC_REG ) ++#define SMC_SET_RPC(x) SMC_outw( x, ioaddr, RPC_REG ) ++#define SMC_GET_TCR() SMC_inw( ioaddr, TCR_REG ) ++#define SMC_SET_TCR(x) SMC_outw( x, ioaddr, TCR_REG ) ++ ++#ifndef SMC_GET_MAC_ADDR ++#define SMC_GET_MAC_ADDR(addr) \ ++ do { \ ++ unsigned int __v; \ ++ __v = SMC_inw( ioaddr, ADDR0_REG ); \ ++ addr[0] = __v; addr[1] = __v >> 8; \ ++ __v = SMC_inw( ioaddr, ADDR1_REG ); \ ++ addr[2] = __v; addr[3] = __v >> 8; \ ++ __v = SMC_inw( ioaddr, ADDR2_REG ); \ ++ addr[4] = __v; addr[5] = __v >> 8; \ ++ } while (0) ++#endif ++ ++#define SMC_SET_MAC_ADDR(addr) \ ++ do { \ ++ SMC_outw( addr[0]|(addr[1] << 8), ioaddr, ADDR0_REG ); \ ++ SMC_outw( addr[2]|(addr[3] << 8), ioaddr, ADDR1_REG ); \ ++ SMC_outw( addr[4]|(addr[5] << 8), ioaddr, ADDR2_REG ); \ ++ } while (0) ++ ++#define SMC_CLEAR_MCAST() \ ++ do { \ ++ SMC_outw( 0, ioaddr, MCAST_REG1 ); \ ++ SMC_outw( 0, ioaddr, MCAST_REG2 ); \ ++ SMC_outw( 0, ioaddr, MCAST_REG3 ); \ ++ SMC_outw( 0, ioaddr, MCAST_REG4 ); \ ++ } while (0) ++#define SMC_SET_MCAST(x) \ ++ do { \ ++ unsigned char *mt = (x); \ ++ SMC_outw( mt[0] | (mt[1] << 8), ioaddr, MCAST_REG1 ); \ ++ SMC_outw( mt[2] | (mt[3] << 8), ioaddr, MCAST_REG2 ); \ ++ SMC_outw( mt[4] | (mt[5] << 8), ioaddr, MCAST_REG3 ); \ ++ SMC_outw( mt[6] | (mt[7] << 8), ioaddr, MCAST_REG4 ); \ ++ } while (0) ++ ++#if SMC_CAN_USE_32BIT ++/* ++ * Some setups just can't write 8 or 16 bits reliably when not aligned ++ * to a 32 bit boundary. I tell you that exists! ++ * We do the ones that can have their low parts written to 0 here. ++ */ ++#undef SMC_SELECT_BANK ++#define SMC_SELECT_BANK(x) SMC_outl( (x)<<16, ioaddr, 12<<SMC_IO_SHIFT ) ++#undef SMC_SET_RPC ++#define SMC_SET_RPC(x) SMC_outl( (x)<<16, ioaddr, SMC_REG(8, 0) ) ++#undef SMC_SET_PN ++#define SMC_SET_PN(x) SMC_outl( (x)<<16, ioaddr, SMC_REG(0, 2) ) ++#undef SMC_SET_PTR ++#define SMC_SET_PTR(x) SMC_outl( (x)<<16, ioaddr, SMC_REG(4, 2) ) ++#endif ++ ++#if SMC_CAN_USE_32BIT ++#define SMC_PUT_PKT_HDR(status, length) \ ++ SMC_outl( (status) | (length) << 16, ioaddr, DATA_REG ) ++#define SMC_GET_PKT_HDR(status, length) \ ++ do { \ ++ unsigned int __val = SMC_inl( ioaddr, DATA_REG ); \ ++ (status) = __val & 0xffff; \ ++ (length) = __val >> 16; \ ++ } while (0) ++#else ++#define SMC_PUT_PKT_HDR(status, length) \ ++ do { \ ++ SMC_outw( status, ioaddr, DATA_REG ); \ ++ SMC_outw( length, ioaddr, DATA_REG ); \ ++ } while (0) ++#define SMC_GET_PKT_HDR(status, length) \ ++ do { \ ++ (status) = SMC_inw( ioaddr, DATA_REG ); \ ++ (length) = SMC_inw( ioaddr, DATA_REG ); \ ++ } while (0) ++#endif ++ ++#if SMC_CAN_USE_32BIT ++#define SMC_PUSH_DATA(p, l) \ ++ do { \ ++ char *__ptr = (p); \ ++ int __len = (l); \ ++ if (__len >= 2 && (long)__ptr & 2) { \ ++ __len -= 2; \ ++ SMC_outw( *((u16 *)__ptr)++, ioaddr, DATA_REG );\ ++ } \ ++ SMC_outsl( ioaddr, DATA_REG, __ptr, __len >> 2); \ ++ if (__len & 2) { \ ++ __ptr += (__len & ~3); \ ++ SMC_outw( *((u16 *)__ptr), ioaddr, DATA_REG ); \ ++ } \ ++ } while (0) ++#define SMC_PULL_DATA(p, l) \ ++ do { \ ++ char *__ptr = (p); \ ++ int __len = (l); \ ++ if ((long)__ptr & 2) { \ ++ /* \ ++ * We want 32bit alignment here. \ ++ * Since some buses perform a full 32bit \ ++ * fetch even for 16bit data we can't use \ ++ * SMC_inw() here. Back both source (on chip \ ++ * and destination) pointers of 2 bytes. \ ++ */ \ ++ (long)__ptr &= ~2; \ ++ __len += 2; \ ++ SMC_SET_PTR( 2|PTR_READ|PTR_RCV|PTR_AUTOINC ); \ ++ } \ ++ __len += 2; \ ++ SMC_insl( ioaddr, DATA_REG, __ptr, __len >> 2); \ ++ } while (0) ++#elif SMC_CAN_USE_16BIT ++#define SMC_PUSH_DATA(p, l) SMC_outsw( ioaddr, DATA_REG, p, (l) >> 1 ) ++#define SMC_PULL_DATA(p, l) SMC_insw ( ioaddr, DATA_REG, p, (l) >> 1 ) ++#elif SMC_CAN_USE_8BIT ++#define SMC_PUSH_DATA(p, l) SMC_outsb( ioaddr, DATA_REG, p, l ) ++#define SMC_PULL_DATA(p, l) SMC_insb ( ioaddr, DATA_REG, p, l ) ++#endif ++ ++#if ! SMC_CAN_USE_16BIT ++#define SMC_outw(x, ioaddr, reg) \ ++ do { \ ++ unsigned int __val16 = (x); \ ++ SMC_outb( __val16, ioaddr, reg ); \ ++ SMC_outb( __val16 >> 8, ioaddr, reg + 1 ); \ ++ } while (0) ++#define SMC_inw(ioaddr, reg) \ ++ ({ \ ++ unsigned int __val16; \ ++ __val16 = SMC_inb( ioaddr, reg ); \ ++ __val16 |= SMC_inb( ioaddr, reg + 1 ) << 8; \ ++ __val16; \ ++ }) ++#endif ++ ++ ++#endif /* _SMC91X_H_ */ +--- linux-2.4.25/drivers/pcmcia/Config.in~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/Config.in 2004-03-31 17:15:12.000000000 +0200 +@@ -45,6 +45,7 @@ + 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 ++ dep_tristate ' PXA250/210 support' CONFIG_PCMCIA_PXA $CONFIG_ARCH_PXA $CONFIG_PCMCIA + fi + + endmenu +--- linux-2.4.25/drivers/pcmcia/Makefile~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/Makefile 2004-03-31 17:15:12.000000000 +0200 +@@ -94,6 +94,11 @@ + + obj-$(CONFIG_PCMCIA_VRC4173) += vrc4173_cardu.o + ++subdir-$(CONFIG_PCMCIA_PXA) += pxa ++ifeq ($(CONFIG_PCMCIA_PXA),y) ++ obj-y += pxa/pxa_cs.o ++endif ++ + include $(TOPDIR)/Rules.make + + pcmcia_core.o: $(pcmcia_core-objs) +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/pxa/Makefile 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,18 @@ ++# ++# Makefile for the Intel PXA250/210 PCMCIA driver ++# ++# 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). ++ ++O_TARGET := pxa_cs.o ++ ++obj-y := pxa.o ++obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o ++obj-$(CONFIG_ARCH_PXA_IDP) += pxa_idp.o ++obj-$(CONFIG_ARCH_TRIZEPS2) += trizeps2.o ++obj-$(CONFIG_ARCH_PXA_CERF) += ../sa1100_cerf.o ++ ++obj-m := $(O_TARGET) ++ ++include $(TOPDIR)/Rules.make +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/pxa/lubbock.c 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,329 @@ ++/* ++ * linux/drivers/pcmcia/pxa/lubbock.c ++ * ++ * Author: George Davis ++ * Created: Jan 10, 2002 ++ * Copyright: MontaVista 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. ++ * ++ * Originally based upon linux/drivers/pcmcia/sa1100_neponset.c ++ * ++ * Lubbock PCMCIA specific routines. ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/sched.h> ++ ++#include <pcmcia/ss.h> ++ ++#include <asm/delay.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/arch/pcmcia.h> ++#include <asm/hardware/sa1111.h> ++ ++/* ++ * I'd really like to move the INTPOL stuff to arch/arm/mach-sa1100/sa1111.c ++ * ... and maybe even arch/arm/mach-pxa/sa1111.c now too! : ) ++ */ ++#define SA1111_IRQMASK_LO(x) (1 << (x - IRQ_SA1111_START)) ++#define SA1111_IRQMASK_HI(x) (1 << (x - IRQ_SA1111_START - 32)) ++ ++static int lubbock_pcmcia_init(struct pcmcia_init *init){ ++ int return_val=0; ++ ++ /* Set PCMCIA Socket 0 power to standby mode. ++ */ ++ PA_DWR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3)); ++ ++ /* Set GPIO_A<3:0> to be outputs for PCMCIA (socket 0) power controller. ++ * Note that this is done only after first initializing GPIO_A<3:0> ++ * output state above to be certain that we drive signals to the same ++ * state as the pull-downs connected to these lines. The pull-downs are ++ * req'd to make sure PCMCIA power is OFF until we can get around to ++ * setting up the GPIO_A<3:0> state and direction. ++ */ ++ PA_DDR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3)); ++ ++ /* Set CF Socket 1 power to standby mode. */ ++ LUB_MISC_WR &= ~(GPIO_bit(15) | GPIO_bit(14)); ++ ++ INTPOL1 |= SA1111_IRQMASK_HI(S0_READY_NINT) | ++ SA1111_IRQMASK_HI(S1_READY_NINT) | ++ SA1111_IRQMASK_HI(S0_CD_VALID) | ++ SA1111_IRQMASK_HI(S1_CD_VALID) | ++ SA1111_IRQMASK_HI(S0_BVD1_STSCHG) | ++ SA1111_IRQMASK_HI(S1_BVD1_STSCHG); ++ ++#warning what if a request_irq fails? ++ return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT, ++ "Lubbock PCMCIA (0) CD", NULL); ++ return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT, ++ "Lubbock CF (1) CD", NULL); ++ return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT, ++ "Lubbock PCMCIA (0) BVD1", NULL); ++ return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT, ++ "Lubbock CF (1) BVD1", NULL); ++ ++ return (return_val<0) ? -1 : 2; ++} ++ ++static int lubbock_pcmcia_shutdown(void){ ++ ++ free_irq(S0_CD_VALID, NULL); ++ free_irq(S1_CD_VALID, NULL); ++ free_irq(S0_BVD1_STSCHG, NULL); ++ free_irq(S1_BVD1_STSCHG, NULL); ++ ++ INTPOL1 &= ~(SA1111_IRQMASK_HI(S0_CD_VALID) | ++ SA1111_IRQMASK_HI(S1_CD_VALID) | ++ SA1111_IRQMASK_HI(S0_BVD1_STSCHG) | ++ SA1111_IRQMASK_HI(S1_BVD1_STSCHG)); ++ ++ return 0; ++} ++ ++static int lubbock_pcmcia_socket_state(struct pcmcia_state_array ++ *state_array){ ++ unsigned long status; ++ int return_val=1; ++ ++ if(state_array->size<2) return -1; ++ ++ memset(state_array->state, 0, ++ (state_array->size)*sizeof(struct pcmcia_state)); ++ ++ status=PCSR; ++ ++ state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0; ++ ++ state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1; ++ ++ state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1; ++ ++ state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1; ++ ++ state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1; ++ ++ state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0; ++ ++ state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0; ++ ++ state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0; ++ ++ state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1; ++ ++ state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1; ++ ++ state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1; ++ ++ state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1; ++ ++ state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0; ++ ++ state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0; ++ ++ return return_val; ++} ++ ++static int lubbock_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ ++ ++ switch(info->sock){ ++ case 0: ++ info->irq=S0_READY_NINT; ++ break; ++ ++ case 1: ++ info->irq=S1_READY_NINT; ++ break; ++ ++ default: ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int ++lubbock_pcmcia_configure_socket(unsigned int sock, socket_state_t *state) ++{ ++ unsigned long flags, pccr, gpio, misc_wr, status; ++ int ret=1; ++ ++ local_irq_save(flags); ++ ++ pccr=PCCR; ++ gpio=PA_DWR; ++ misc_wr = LUB_MISC_WR; ++ ++ /* Lubbock uses the Maxim MAX1602, with the following connections: ++ * ++ * Socket 0 (PCMCIA): ++ * MAX1602 Lubbock Register ++ * Pin Signal ++ * ----- ------- ---------------------- ++ * A0VPP S0_PWR0 SA-1111 GPIO A<0> ++ * A1VPP S0_PWR1 SA-1111 GPIO A<1> ++ * A0VCC S0_PWR2 SA-1111 GPIO A<2> ++ * A1VCC S0_PWR3 SA-1111 GPIO A<3> ++ * VX VCC ++ * VY +3.3V ++ * 12IN +12V ++ * CODE +3.3V Cirrus Code, CODE = High (VY) ++ * ++ * Socket 1 (CF): ++ * MAX1602 Lubbock Register ++ * Pin Signal ++ * ----- ------- ---------------------- ++ * A0VPP GND VPP is not connected ++ * A1VPP GND VPP is not connected ++ * A0VCC S1_PWR0 MISC_WR<14> ++ * A1VCC S1_PWR0 MISC_WR<15> ++ * VX VCC ++ * VY +3.3V ++ * 12IN GND VPP is not connected ++ * CODE +3.3V Cirrus Code, CODE = High (VY) ++ * ++ */ ++ ++again: ++ switch(sock){ ++ case 0: ++ ++ switch(state->Vcc){ ++ case 0: ++ pccr = (pccr & ~PCCR_S0_FLT); ++ gpio &= ~(GPIO_bit(2) | GPIO_bit(3)); ++ break; ++ ++ case 33: ++ pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN; ++ gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(3); ++ break; ++ ++ case 50: ++ pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN); ++ gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(2); ++ break; ++ ++ default: ++ printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, state->Vcc); ++ ret = -1; ++ break; ++ } ++ ++ switch(state->Vpp){ ++ case 0: ++ gpio &= ~(GPIO_bit(0) | GPIO_bit(1)); ++ break; ++ ++ case 120: ++ gpio = (gpio & ~(GPIO_bit(0) | GPIO_bit(1))) | GPIO_bit(1); ++ break; ++ ++ default: ++ /* REVISIT: I'm not sure about this? Is this correct? ++ Is it always safe or do we have potential problems ++ with bogus combinations of Vcc and Vpp settings? */ ++ if(state->Vpp == state->Vcc) ++ gpio = (gpio & ~(GPIO_bit(0) | GPIO_bit(1))) | GPIO_bit(0); ++ else { ++ printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__, state->Vpp); ++ ret = -1; ++ break; ++ } ++ } ++ ++ pccr = (state->flags&SS_RESET) ? (pccr|PCCR_S0_RST) : (pccr&~PCCR_S0_RST); ++ ++ break; ++ ++ case 1: ++ switch(state->Vcc){ ++ case 0: ++ pccr = (pccr & ~PCCR_S1_FLT); ++ misc_wr &= ~((1 << 15) | (1 << 14)); ++ break; ++ ++ case 33: ++ pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN; ++ misc_wr = (misc_wr & ~(1 << 15)) | (1 << 14); ++ gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(2); ++ break; ++ ++ case 50: ++ pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN); ++ misc_wr = (misc_wr & ~(1 << 15)) | (1 << 14); ++ break; ++ ++ default: ++ printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, state->Vcc); ++ ret = -1; ++ break; ++ } ++ ++ if(state->Vpp!=state->Vcc && state->Vpp!=0){ ++ printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, state->Vpp); ++ ret = -1; ++ break; ++ } ++ ++ pccr = (state->flags&SS_RESET) ? (pccr|PCCR_S1_RST) : (pccr&~PCCR_S1_RST); ++ ++ break; ++ ++ default: ++ ret = -1; ++ } ++ ++ if (ret >= 0) { ++ PCCR = pccr; ++ LUB_MISC_WR = misc_wr; ++ PA_DWR = gpio; ++ } ++ ++ if (ret > 0) { ++ ret = 0; ++ /* ++ * HACK ALERT: ++ * We can't sense the voltage properly on Lubbock before actually ++ * applying some power to the socket (catch 22). ++ * Resense the socket Voltage Sense pins after applying socket power. ++ */ ++ if (sock == 0) ++ status = PCSR & (PCSR_S0_VS1 | PCSR_S0_VS2); ++ else ++ status = PCSR & (PCSR_S1_VS1 | PCSR_S1_VS2); ++ ++ if ((status == (PCSR_S0_VS1 | PCSR_S0_VS2)) && (state->Vcc == 33)) { ++ /* Switch to 5V, Configure socket 0 with 5V voltage */ ++ PA_DWR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3)); ++ PA_DDR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3)); ++ state->Vcc = 50; ++ state->Vpp = 50; ++ goto again; ++ } ++ if ((status == (PCSR_S1_VS1 | PCSR_S1_VS2)) && (state->Vcc == 33)) { ++ /* Switch to 5V, Configure socket 1 with 5V voltage */ ++ LUB_MISC_WR &= ~((1 << 15) | (1 << 14)); ++ state->Vcc = 50; ++ state->Vpp = 50; ++ goto again; ++ } ++ } ++ ++ local_irq_restore(flags); ++ return ret; ++} ++ ++struct pcmcia_low_level lubbock_pcmcia_ops = { ++ lubbock_pcmcia_init, ++ lubbock_pcmcia_shutdown, ++ lubbock_pcmcia_socket_state, ++ lubbock_pcmcia_get_irq_info, ++ lubbock_pcmcia_configure_socket ++}; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/pxa/pxa.c 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,1247 @@ ++/* ++ * linux/drivers/pcmcia/pxa/pxa.c ++ * ++ * Author: George Davis ++ * Created: Jan 10, 2002 ++ * Copyright: MontaVista 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. ++ * ++ * Originally based upon linux/drivers/pcmcia/sa1100_generic.c ++ * ++ */ ++ ++/*====================================================================== ++ ++ Device driver for the PCMCIA control functionality of Intel ++ PXA250/210 microprocessors. ++ ++ The contents of this file are subject to the Mozilla Public ++ License Version 1.1 (the "License"); you may not use this file ++ except in compliance with the License. You may obtain a copy of ++ the License at http://www.mozilla.org/MPL/ ++ ++ Software distributed under the License is distributed on an "AS ++ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++ implied. See the License for the specific language governing ++ rights and limitations under the License. ++ ++ The initial developer of the original code is John G. Dorsey ++ <john+@cs.cmu.edu>. Portions created by John G. Dorsey are ++ Copyright (C) 1999 John G. Dorsey. All Rights Reserved. ++ ++ Alternatively, the contents of this file may be used under the ++ terms of the GNU Public License version 2 (the "GPL"), in which ++ case the provisions of the GPL are applicable instead of the ++ above. If you wish to allow the use of your version of this file ++ only under the terms of the GPL and not to allow others to use ++ your version of this file under the MPL, indicate your decision ++ by deleting the provisions above and replace them with the notice ++ and other provisions required by the GPL. If you do not delete ++ the provisions above, a recipient may use your version of this ++ file under either the MPL or the GPL. ++ ++======================================================================*/ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/config.h> ++#include <linux/cpufreq.h> ++#include <linux/delay.h> ++#include <linux/ioport.h> ++#include <linux/kernel.h> ++#include <linux/tqueue.h> ++#include <linux/timer.h> ++#include <linux/mm.h> ++#include <linux/notifier.h> ++#include <linux/proc_fs.h> ++#include <linux/version.h> ++#include <linux/cpufreq.h> ++ ++#include <pcmcia/version.h> ++#include <pcmcia/cs_types.h> ++#include <pcmcia/cs.h> ++#include <pcmcia/ss.h> ++#include <pcmcia/bus_ops.h> ++ ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/system.h> ++#include <asm/arch/lubbock.h> ++ ++#include "pxa.h" ++ ++#ifdef PCMCIA_DEBUG ++static int pc_debug; ++#endif ++ ++MODULE_AUTHOR("George Davis <davis_g@mvista.com>"); ++MODULE_DESCRIPTION("Linux PCMCIA Card Services: PXA250/210 Socket Controller"); ++ ++/* This structure maintains housekeeping state for each socket, such ++ * as the last known values of the card detect pins, or the Card Services ++ * callback value associated with the socket: ++ */ ++static struct pxa_pcmcia_socket ++pxa_pcmcia_socket[PXA_PCMCIA_MAX_SOCK]; ++ ++static int pxa_pcmcia_socket_count; ++ ++ ++/* Returned by the low-level PCMCIA interface: */ ++static struct pcmcia_low_level *pcmcia_low_level; ++ ++/* Event poll timer structure */ ++static struct timer_list poll_timer; ++ ++ ++/* Prototypes for routines which are used internally: */ ++ ++static int pxa_pcmcia_driver_init(void); ++static void pxa_pcmcia_driver_shutdown(void); ++static void pxa_pcmcia_task_handler(void *data); ++static void pxa_pcmcia_poll_event(unsigned long data); ++static void pxa_pcmcia_interrupt(int irq, void *dev, ++ struct pt_regs *regs); ++static struct tq_struct pxa_pcmcia_task; ++ ++#ifdef CONFIG_PROC_FS ++static int pxa_pcmcia_proc_status(char *buf, char **start, off_t pos, ++ int count, int *eof, void *data); ++#endif ++ ++ ++/* Prototypes for operations which are exported to the ++ * new-and-impr^H^H^H^H^H^H^H^H^H^H in-kernel PCMCIA core: ++ */ ++ ++static int pxa_pcmcia_init(unsigned int sock); ++static int pxa_pcmcia_suspend(unsigned int sock); ++static int pxa_pcmcia_register_callback(unsigned int sock, ++ void (*handler)(void *, ++ unsigned int), ++ void *info); ++static int pxa_pcmcia_inquire_socket(unsigned int sock, ++ socket_cap_t *cap); ++static int pxa_pcmcia_get_status(unsigned int sock, u_int *value); ++static int pxa_pcmcia_get_socket(unsigned int sock, ++ socket_state_t *state); ++static int pxa_pcmcia_set_socket(unsigned int sock, ++ socket_state_t *state); ++static int pxa_pcmcia_get_io_map(unsigned int sock, ++ struct pccard_io_map *io); ++static int pxa_pcmcia_set_io_map(unsigned int sock, ++ struct pccard_io_map *io); ++static int pxa_pcmcia_get_mem_map(unsigned int sock, ++ struct pccard_mem_map *mem); ++static int pxa_pcmcia_set_mem_map(unsigned int sock, ++ struct pccard_mem_map *mem); ++#ifdef CONFIG_PROC_FS ++static void pxa_pcmcia_proc_setup(unsigned int sock, ++ struct proc_dir_entry *base); ++#endif ++ ++static struct pccard_operations pxa_pcmcia_operations = { ++ pxa_pcmcia_init, ++ pxa_pcmcia_suspend, ++ pxa_pcmcia_register_callback, ++ pxa_pcmcia_inquire_socket, ++ pxa_pcmcia_get_status, ++ pxa_pcmcia_get_socket, ++ pxa_pcmcia_set_socket, ++ pxa_pcmcia_get_io_map, ++ pxa_pcmcia_set_io_map, ++ pxa_pcmcia_get_mem_map, ++ pxa_pcmcia_set_mem_map, ++#ifdef CONFIG_PROC_FS ++ pxa_pcmcia_proc_setup ++#endif ++}; ++ ++#ifdef CONFIG_CPU_FREQ ++/* forward declaration */ ++static struct notifier_block pxa_pcmcia_notifier_block; ++#endif ++ ++ ++/* pxa_pcmcia_driver_init() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * ++ * This routine performs a basic sanity check to ensure that this ++ * kernel has been built with the appropriate board-specific low-level ++ * PCMCIA support, performs low-level PCMCIA initialization, registers ++ * this socket driver with Card Services, and then spawns the daemon ++ * thread which is the real workhorse of the socket driver. ++ * ++ * Please see linux/Documentation/arm/SA1100/PCMCIA for more information ++ * on the low-level kernel interface. ++ * ++ * Returns: 0 on success, -1 on error ++ */ ++static int __init pxa_pcmcia_driver_init(void){ ++ servinfo_t info; ++ struct pcmcia_init pcmcia_init; ++ struct pcmcia_state state[PXA_PCMCIA_MAX_SOCK]; ++ struct pcmcia_state_array state_array; ++ unsigned int i, clock; ++ unsigned long mecr; ++ ++ printk(KERN_INFO "Intel PXA250/210 PCMCIA (CS release %s)\n", CS_RELEASE); ++ ++ CardServices(GetCardServicesInfo, &info); ++ ++ if(info.Revision!=CS_RELEASE_CODE){ ++ printk(KERN_ERR "Card Services release codes do not match\n"); ++ return -1; ++ } ++ ++ /* Setup GPIOs for PCMCIA/CF alternate function mode. ++ * ++ * It would be nice if set_GPIO_mode included support ++ * for driving GPIO outputs to default high/low state ++ * before programming GPIOs as outputs. Setting GPIO ++ * outputs to default high/low state via GPSR/GPCR ++ * before defining them as outputs should reduce ++ * the possibility of glitching outputs during GPIO ++ * setup. This of course assumes external terminators ++ * are present to hold GPIOs in a defined state. ++ * ++ * In the meantime, setup default state of GPIO ++ * outputs before we enable them as outputs. ++ */ ++ ++ GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) | ++ GPIO_bit(GPIO49_nPWE) | ++ GPIO_bit(GPIO50_nPIOR) | ++ GPIO_bit(GPIO51_nPIOW) | ++ GPIO_bit(GPIO52_nPCE_1) | ++ GPIO_bit(GPIO53_nPCE_2); ++ ++ set_GPIO_mode(GPIO48_nPOE_MD); ++ set_GPIO_mode(GPIO49_nPWE_MD); ++ set_GPIO_mode(GPIO50_nPIOR_MD); ++ set_GPIO_mode(GPIO51_nPIOW_MD); ++ set_GPIO_mode(GPIO52_nPCE_1_MD); ++ set_GPIO_mode(GPIO53_nPCE_2_MD); ++ set_GPIO_mode(GPIO54_pSKTSEL_MD); /* REVISIT: s/b dependent on num sockets */ ++ set_GPIO_mode(GPIO55_nPREG_MD); ++ set_GPIO_mode(GPIO56_nPWAIT_MD); ++ set_GPIO_mode(GPIO57_nIOIS16_MD); ++ ++ ++ if(machine_is_lubbock()){ ++#if defined(CONFIG_ARCH_LUBBOCK) || defined(CONFIG_ARCH_CSB226) ++ pcmcia_low_level=&lubbock_pcmcia_ops; ++#endif ++ } else if (machine_is_pxa_idp()) { ++ pcmcia_low_level=&pxa_idp_pcmcia_ops; ++ } else if( machine_is_pxa_cerf()){ ++ pcmcia_low_level=&cerf_pcmcia_ops; ++ } else if (machine_is_trizeps2()){ ++#ifdef CONFIG_ARCH_TRIZEPS2 ++ pcmcia_low_level=&trizeps2_pcmcia_ops; ++#endif ++ } ++ ++ if (!pcmcia_low_level) { ++ printk(KERN_ERR "This hardware is not supported by the PXA250/210 Card Service driver\n"); ++ return -ENODEV; ++ } ++ ++ pcmcia_init.handler=pxa_pcmcia_interrupt; ++ ++ if((pxa_pcmcia_socket_count=pcmcia_low_level->init(&pcmcia_init))<0){ ++ printk(KERN_ERR "Unable to initialize kernel PCMCIA service.\n"); ++ return -EIO; ++ } ++ ++ state_array.size=pxa_pcmcia_socket_count; ++ state_array.state=state; ++ ++ /* Configure MECR based on the number of sockets present. */ ++ if (pxa_pcmcia_socket_count == 2) { ++ MECR |= GPIO_bit(0); ++ } else { ++ MECR &= ~GPIO_bit(0); ++ } ++ ++ if(pcmcia_low_level->socket_state(&state_array)<0){ ++ printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n"); ++ return -EIO; ++ } ++ ++ /* Well, it looks good to go. So we can now enable the PCMCIA ++ * controller. ++ */ ++ MECR |= GPIO_bit(1); ++ ++ /* We need to initialize the MCXX registers to default values ++ * here because we're not guaranteed to see a SetIOMap operation ++ * at runtime. ++ */ ++ ++ clock = get_lclk_frequency_10khz(); ++ ++ for(i=0; i<pxa_pcmcia_socket_count; ++i){ ++ pxa_pcmcia_socket[i].k_state=state[i]; ++ ++ /* This is an interim fix. Apparently, SetSocket is no longer ++ * called to initialize each socket (prior to the first detect ++ * event). For now, we'll just manually set up the mask. ++ */ ++ pxa_pcmcia_socket[i].cs_state.csc_mask=SS_DETECT; ++ ++ pxa_pcmcia_socket[i].virt_io=(i==0)?PCMCIA_IO_0_BASE:PCMCIA_IO_1_BASE; ++ pxa_pcmcia_socket[i].phys_attr=_PCMCIAAttr(i); ++ pxa_pcmcia_socket[i].phys_mem=_PCMCIAMem(i); ++ ++ /* REVISIT: cleanup these macros */ ++ //MCIO_SET(i, PXA_PCMCIA_IO_ACCESS, clock); ++ //MCATTR_SET(i, PXA_PCMCIA_5V_MEM_ACCESS, clock); ++ //MCMEM_SET(i, PXA_PCMCIA_5V_MEM_ACCESS, clock); ++ ++ pxa_pcmcia_socket[i].speed_io=PXA_PCMCIA_IO_ACCESS; ++ pxa_pcmcia_socket[i].speed_attr=PXA_PCMCIA_ATTR_MEM_ACCESS; ++ pxa_pcmcia_socket[i].speed_mem=PXA_PCMCIA_5V_MEM_ACCESS; ++ } ++ ++/* REVISIT: cleanup these macros */ ++MCMEM0 = ((pxa_mcxx_setup(PXA_PCMCIA_5V_MEM_ACCESS, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(PXA_PCMCIA_5V_MEM_ACCESS, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(PXA_PCMCIA_5V_MEM_ACCESS, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++MCMEM1 = ((pxa_mcxx_setup(PXA_PCMCIA_5V_MEM_ACCESS, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(PXA_PCMCIA_5V_MEM_ACCESS, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(PXA_PCMCIA_5V_MEM_ACCESS, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++MCATT0 = ((pxa_mcxx_setup(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++MCATT1 = ((pxa_mcxx_setup(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++MCIO0 = ((pxa_mcxx_setup(PXA_PCMCIA_IO_ACCESS, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(PXA_PCMCIA_IO_ACCESS, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(PXA_PCMCIA_IO_ACCESS, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++MCIO1 = ((pxa_mcxx_setup(PXA_PCMCIA_IO_ACCESS, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(PXA_PCMCIA_IO_ACCESS, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(PXA_PCMCIA_IO_ACCESS, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++ ++#ifdef CONFIG_CPU_FREQ ++ if(cpufreq_register_notifier(&pxa_pcmcia_notifier_block) < 0){ ++ printk(KERN_ERR "Unable to register CPU frequency change notifier\n"); ++ return -ENXIO; ++ } ++#endif ++ ++ /* Only advertise as many sockets as we can detect: */ ++ if(register_ss_entry(pxa_pcmcia_socket_count, ++ &pxa_pcmcia_operations)<0){ ++ printk(KERN_ERR "Unable to register socket service routine\n"); ++ return -ENXIO; ++ } ++ ++ /* Start the event poll timer. It will reschedule by itself afterwards. */ ++ pxa_pcmcia_poll_event(0); ++ ++ DEBUG(1, "pxa_cs: initialization complete\n"); ++ ++ return 0; ++ ++} /* pxa_pcmcia_driver_init() */ ++ ++module_init(pxa_pcmcia_driver_init); ++ ++ ++/* pxa_pcmcia_driver_shutdown() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Invokes the low-level kernel service to free IRQs associated with this ++ * socket controller and reset GPIO edge detection. ++ */ ++static void __exit pxa_pcmcia_driver_shutdown(void){ ++ ++ del_timer_sync(&poll_timer); ++ unregister_ss_entry(&pxa_pcmcia_operations); ++#ifdef CONFIG_CPU_FREQ ++ cpufreq_unregister_notifier(&pxa_pcmcia_notifier_block); ++#endif ++ pcmcia_low_level->shutdown(); ++ flush_scheduled_tasks(); ++ ++ DEBUG(1, "pxa_cs: shutdown complete\n"); ++} ++ ++module_exit(pxa_pcmcia_driver_shutdown); ++ ++ ++/* pxa_pcmcia_init() ++ * ^^^^^^^^^^^^^^^^^^^^ ++ * We perform all of the interesting initialization tasks in ++ * pxa_pcmcia_driver_init(). ++ * ++ * Returns: 0 ++ */ ++static int pxa_pcmcia_init(unsigned int sock){ ++ ++ DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, sock); ++ ++ return 0; ++} ++ ++ ++/* pxa_pcmcia_suspend() ++ * ^^^^^^^^^^^^^^^^^^^^^^^ ++ * We don't currently perform any actions on a suspend. ++ * ++ * Returns: 0 ++ */ ++static int pxa_pcmcia_suspend(unsigned int sock) ++{ ++ socket_state_t st; ++ int ret; ++ ++ DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, sock); ++ ++ st.Vcc = 0; ++ st.Vpp = 0; ++ st.flags = SS_RESET; ++ ++ ret = pcmcia_low_level->configure_socket(sock, &st); ++ ++ if (ret == 0) ++ pxa_pcmcia_socket[sock].cs_state = dead_socket; ++ ++ return ret; ++} ++ ++ ++/* pxa_pcmcia_events() ++ * ^^^^^^^^^^^^^^^^^^^^^^ ++ * Helper routine to generate a Card Services event mask based on ++ * state information obtained from the kernel low-level PCMCIA layer ++ * in a recent (and previous) sampling. Updates `prev_state'. ++ * ++ * Returns: an event mask for the given socket state. ++ */ ++static inline unsigned pxa_pcmcia_events(struct pcmcia_state *state, ++ struct pcmcia_state *prev_state, ++ unsigned int mask, ++ unsigned int flags){ ++ unsigned int events=0; ++ ++ if(state->detect!=prev_state->detect){ ++ ++ DEBUG(2, "%s(): card detect value %u\n", __FUNCTION__, state->detect); ++ ++ events|=mask&SS_DETECT; ++ } ++ ++ if(state->ready!=prev_state->ready){ ++ ++ DEBUG(2, "%s(): card ready value %u\n", __FUNCTION__, state->ready); ++ ++ events|=mask&((flags&SS_IOCARD)?0:SS_READY); ++ } ++ ++ if(state->bvd1!=prev_state->bvd1){ ++ ++ DEBUG(2, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1); ++ ++ events|=mask&(flags&SS_IOCARD)?SS_STSCHG:SS_BATDEAD; ++ } ++ ++ if(state->bvd2!=prev_state->bvd2){ ++ ++ DEBUG(2, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2); ++ ++ events|=mask&(flags&SS_IOCARD)?0:SS_BATWARN; ++ } ++ ++ DEBUG(2, "events: %s%s%s%s%s%s\n", ++ (events==0)?"<NONE>":"", ++ (events&SS_DETECT)?"DETECT ":"", ++ (events&SS_READY)?"READY ":"", ++ (events&SS_BATDEAD)?"BATDEAD ":"", ++ (events&SS_BATWARN)?"BATWARN ":"", ++ (events&SS_STSCHG)?"STSCHG ":""); ++ ++ *prev_state=*state; ++ ++ return events; ++ ++} /* pxa_pcmcia_events() */ ++ ++ ++/* pxa_pcmcia_task_handler() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Processes serviceable socket events using the "eventd" thread context. ++ * ++ * Event processing (specifically, the invocation of the Card Services event ++ * callback) occurs in this thread rather than in the actual interrupt ++ * handler due to the use of scheduling operations in the PCMCIA core. ++ */ ++static void pxa_pcmcia_task_handler(void *data) { ++ struct pcmcia_state state[PXA_PCMCIA_MAX_SOCK]; ++ struct pcmcia_state_array state_array; ++ int i, events, all_events, irq_status; ++ ++ DEBUG(2, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__); ++ ++ state_array.size=pxa_pcmcia_socket_count; ++ state_array.state=state; ++ ++ do { ++ ++ DEBUG(3, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__); ++ ++ if((irq_status=pcmcia_low_level->socket_state(&state_array))<0) ++ printk(KERN_ERR "Error in kernel low-level PCMCIA service.\n"); ++ ++ all_events=0; ++ ++ if(irq_status>0){ ++ ++ for(i=0; i<state_array.size; ++i, all_events|=events) ++ if((events= ++ pxa_pcmcia_events(&state[i], ++ &pxa_pcmcia_socket[i].k_state, ++ pxa_pcmcia_socket[i].cs_state.csc_mask, ++ pxa_pcmcia_socket[i].cs_state.flags))) ++ if(pxa_pcmcia_socket[i].handler!=NULL) ++ pxa_pcmcia_socket[i].handler(pxa_pcmcia_socket[i].handler_info, ++ events); ++ } ++ ++ } while(all_events); ++} /* pxa_pcmcia_task_handler() */ ++ ++static struct tq_struct pxa_pcmcia_task = { ++ routine: pxa_pcmcia_task_handler ++}; ++ ++ ++/* pxa_pcmcia_poll_event() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Let's poll for events in addition to IRQs since IRQ only is unreliable... ++ */ ++static void pxa_pcmcia_poll_event(unsigned long dummy) ++{ ++ DEBUG(3, "%s(): polling for events\n", __FUNCTION__); ++ poll_timer.function = pxa_pcmcia_poll_event; ++ poll_timer.expires = jiffies + PXA_PCMCIA_POLL_PERIOD; ++ add_timer(&poll_timer); ++ schedule_task(&pxa_pcmcia_task); ++} ++ ++ ++/* pxa_pcmcia_interrupt() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Service routine for socket driver interrupts (requested by the ++ * low-level PCMCIA init() operation via pxa_pcmcia_thread()). ++ * The actual interrupt-servicing work is performed by ++ * pxa_pcmcia_thread(), largely because the Card Services event- ++ * handling code performs scheduling operations which cannot be ++ * executed from within an interrupt context. ++ */ ++static void pxa_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs){ ++ DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq); ++ schedule_task(&pxa_pcmcia_task); ++} ++ ++ ++/* pxa_pcmcia_register_callback() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the register_callback() operation for the in-kernel ++ * PCMCIA service (formerly SS_RegisterCallback in Card Services). If ++ * the function pointer `handler' is not NULL, remember the callback ++ * location in the state for `sock', and increment the usage counter ++ * for the driver module. (The callback is invoked from the interrupt ++ * service routine, pxa_pcmcia_interrupt(), to notify Card Services ++ * of interesting events.) Otherwise, clear the callback pointer in the ++ * socket state and decrement the module usage count. ++ * ++ * Returns: 0 ++ */ ++static int pxa_pcmcia_register_callback(unsigned int sock, ++ void (*handler)(void *, ++ unsigned int), ++ void *info){ ++ if(handler==NULL){ ++ pxa_pcmcia_socket[sock].handler=NULL; ++ MOD_DEC_USE_COUNT; ++ } else { ++ MOD_INC_USE_COUNT; ++ pxa_pcmcia_socket[sock].handler=handler; ++ pxa_pcmcia_socket[sock].handler_info=info; ++ } ++ ++ return 0; ++} ++ ++ ++/* pxa_pcmcia_inquire_socket() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the inquire_socket() operation for the in-kernel PCMCIA ++ * service (formerly SS_InquireSocket in Card Services). Of note is ++ * the setting of the SS_CAP_PAGE_REGS bit in the `features' field of ++ * `cap' to "trick" Card Services into tolerating large "I/O memory" ++ * addresses. Also set is SS_CAP_STATIC_MAP, which disables the memory ++ * resource database check. (Mapped memory is set up within the socket ++ * driver itself.) ++ * ++ * In conjunction with the STATIC_MAP capability is a new field, ++ * `io_offset', recommended by David Hinds. Rather than go through ++ * the SetIOMap interface (which is not quite suited for communicating ++ * window locations up from the socket driver), we just pass up ++ * an offset which is applied to client-requested base I/O addresses ++ * in alloc_io_space(). ++ * ++ * Returns: 0 on success, -1 if no pin has been configured for `sock' ++ */ ++static int pxa_pcmcia_inquire_socket(unsigned int sock, ++ socket_cap_t *cap){ ++ struct pcmcia_irq_info irq_info; ++ ++ DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ if(sock>=pxa_pcmcia_socket_count){ ++ printk(KERN_ERR "pxa_cs: socket %u not configured\n", sock); ++ return -1; ++ } ++ ++ /* SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the ++ * force_low argument to validate_mem() in rsrc_mgr.c -- since in ++ * general, the mapped * addresses of the PCMCIA memory regions ++ * will not be within 0xffff, setting force_low would be ++ * undesirable. ++ * ++ * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory ++ * resource database; we instead pass up physical address ranges ++ * and allow other parts of Card Services to deal with remapping. ++ * ++ * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but ++ * not 32-bit CardBus devices. ++ */ ++ cap->features=(SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD); ++ ++ irq_info.sock=sock; ++ irq_info.irq=-1; ++ ++ if(pcmcia_low_level->get_irq_info(&irq_info)<0){ ++ printk(KERN_ERR "Error obtaining IRQ info from kernel for socket %u\n", ++ sock); ++ return -1; ++ } ++ ++ cap->irq_mask=0; ++ cap->map_size=PAGE_SIZE; ++ cap->pci_irq=irq_info.irq; ++ cap->io_offset=pxa_pcmcia_socket[sock].virt_io; ++ ++ return 0; ++ ++} /* pxa_pcmcia_inquire_socket() */ ++ ++ ++/* pxa_pcmcia_get_status() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the get_status() operation for the in-kernel PCMCIA ++ * service (formerly SS_GetStatus in Card Services). Essentially just ++ * fills in bits in `status' according to internal driver state or ++ * the value of the voltage detect chipselect register. ++ * ++ * As a debugging note, during card startup, the PCMCIA core issues ++ * three set_socket() commands in a row the first with RESET deasserted, ++ * the second with RESET asserted, and the last with RESET deasserted ++ * again. Following the third set_socket(), a get_status() command will ++ * be issued. The kernel is looking for the SS_READY flag (see ++ * setup_socket(), reset_socket(), and unreset_socket() in cs.c). ++ * ++ * Returns: 0 ++ */ ++static int pxa_pcmcia_get_status(unsigned int sock, ++ unsigned int *status){ ++ struct pcmcia_state state[PXA_PCMCIA_MAX_SOCK]; ++ struct pcmcia_state_array state_array; ++ ++ DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ state_array.size=pxa_pcmcia_socket_count; ++ state_array.state=state; ++ ++ if((pcmcia_low_level->socket_state(&state_array))<0){ ++ printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n"); ++ return -1; ++ } ++ ++ pxa_pcmcia_socket[sock].k_state=state[sock]; ++ ++ *status=state[sock].detect?SS_DETECT:0; ++ ++ *status|=state[sock].ready?SS_READY:0; ++ ++ /* The power status of individual sockets is not available ++ * explicitly from the hardware, so we just remember the state ++ * and regurgitate it upon request: ++ */ ++ *status|=pxa_pcmcia_socket[sock].cs_state.Vcc?SS_POWERON:0; ++ ++ if(pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD) ++ *status|=state[sock].bvd1?SS_STSCHG:0; ++ else { ++ if(state[sock].bvd1==0) ++ *status|=SS_BATDEAD; ++ else if(state[sock].bvd2==0) ++ *status|=SS_BATWARN; ++ } ++ ++ *status|=state[sock].vs_3v?SS_3VCARD:0; ++ ++ *status|=state[sock].vs_Xv?SS_XVCARD:0; ++ ++ DEBUG(3, "\tstatus: %s%s%s%s%s%s%s%s\n", ++ (*status&SS_DETECT)?"DETECT ":"", ++ (*status&SS_READY)?"READY ":"", ++ (*status&SS_BATDEAD)?"BATDEAD ":"", ++ (*status&SS_BATWARN)?"BATWARN ":"", ++ (*status&SS_POWERON)?"POWERON ":"", ++ (*status&SS_STSCHG)?"STSCHG ":"", ++ (*status&SS_3VCARD)?"3VCARD ":"", ++ (*status&SS_XVCARD)?"XVCARD ":""); ++ ++ return 0; ++ ++} /* pxa_pcmcia_get_status() */ ++ ++ ++/* pxa_pcmcia_get_socket() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the get_socket() operation for the in-kernel PCMCIA ++ * service (formerly SS_GetSocket in Card Services). Not a very ++ * exciting routine. ++ * ++ * Returns: 0 ++ */ ++static int pxa_pcmcia_get_socket(unsigned int sock, ++ socket_state_t *state){ ++ ++ DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ /* This information was given to us in an earlier call to set_socket(), ++ * so we're just regurgitating it here: ++ */ ++ *state=pxa_pcmcia_socket[sock].cs_state; ++ ++ return 0; ++} ++ ++ ++/* pxa_pcmcia_set_socket() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the set_socket() operation for the in-kernel PCMCIA ++ * service (formerly SS_SetSocket in Card Services). We more or ++ * less punt all of this work and let the kernel handle the details ++ * of power configuration, reset, &c. We also record the value of ++ * `state' in order to regurgitate it to the PCMCIA core later. ++ * ++ * Returns: 0 ++ */ ++static int pxa_pcmcia_set_socket(unsigned int sock, ++ socket_state_t *state){ ++ ++ DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ DEBUG(3, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n" ++ "\tVcc %d Vpp %d irq %d\n", ++ (state->csc_mask==0)?"<NONE>":"", ++ (state->csc_mask&SS_DETECT)?"DETECT ":"", ++ (state->csc_mask&SS_READY)?"READY ":"", ++ (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", ++ (state->csc_mask&SS_BATWARN)?"BATWARN ":"", ++ (state->csc_mask&SS_STSCHG)?"STSCHG ":"", ++ (state->flags==0)?"<NONE>":"", ++ (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", ++ (state->flags&SS_IOCARD)?"IOCARD ":"", ++ (state->flags&SS_RESET)?"RESET ":"", ++ (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", ++ (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"", ++ state->Vcc, state->Vpp, state->io_irq); ++ ++ if(pcmcia_low_level->configure_socket(sock, state)<0){ ++ printk(KERN_ERR "Unable to configure socket %u\n", sock); ++ return -1; ++ } ++ ++ pxa_pcmcia_socket[sock].cs_state=*state; ++ ++ return 0; ++ ++} /* pxa_pcmcia_set_socket() */ ++ ++ ++/* pxa_pcmcia_get_io_map() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the get_io_map() operation for the in-kernel PCMCIA ++ * service (formerly SS_GetIOMap in Card Services). Just returns an ++ * I/O map descriptor which was assigned earlier by a set_io_map(). ++ * ++ * Returns: 0 on success, -1 if the map index was out of range ++ */ ++static int pxa_pcmcia_get_io_map(unsigned int sock, ++ struct pccard_io_map *map){ ++ ++ DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ if(map->map>=MAX_IO_WIN){ ++ printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, ++ map->map); ++ return -1; ++ } ++ ++ *map=pxa_pcmcia_socket[sock].io_map[map->map]; ++ ++ return 0; ++} ++ ++ ++/* pxa_pcmcia_set_io_map() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the set_io_map() operation for the in-kernel PCMCIA ++ * service (formerly SS_SetIOMap in Card Services). We configure ++ * the map speed as requested, but override the address ranges ++ * supplied by Card Services. ++ * ++ * Returns: 0 on success, -1 on error ++ */ ++static int pxa_pcmcia_set_io_map(unsigned int sock, ++ struct pccard_io_map *map){ ++ unsigned int clock, speed; ++ unsigned long mecr, start; ++ ++ DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ DEBUG(4, "\tmap %u speed %u\n\tstart 0x%08lx stop 0x%08lx\n" ++ "\tflags: %s%s%s%s%s%s%s%s\n", ++ map->map, map->speed, map->start, map->stop, ++ (map->flags==0)?"<NONE>":"", ++ (map->flags&MAP_ACTIVE)?"ACTIVE ":"", ++ (map->flags&MAP_16BIT)?"16BIT ":"", ++ (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", ++ (map->flags&MAP_0WS)?"0WS ":"", ++ (map->flags&MAP_WRPROT)?"WRPROT ":"", ++ (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"", ++ (map->flags&MAP_PREFETCH)?"PREFETCH ":""); ++ ++ if(map->map>=MAX_IO_WIN){ ++ printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, ++ map->map); ++ return -1; ++ } ++ ++ if(map->flags&MAP_ACTIVE){ ++ ++ speed=(map->speed>0)?map->speed:PXA_PCMCIA_IO_ACCESS; ++ ++ clock = get_lclk_frequency_10khz(); ++ ++ pxa_pcmcia_socket[sock].speed_io=speed; ++ ++ if (sock == 0) { ++ MCIO0 = ((pxa_mcxx_setup(speed, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(speed, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(speed, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++ } else { ++ MCIO1 = ((pxa_mcxx_setup(speed, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(speed, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(speed, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++ } ++ ++ DEBUG(4, "%s(): FAST%u %lx BSM%u %lx BSA%u %lx BSIO%u %lx\n", ++ __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock, ++ MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), ++ sock, MECR_BSIO_GET(mecr, sock)); ++ ++ } ++ ++ start=map->start; ++ ++ if(map->stop==1) ++ map->stop=PAGE_SIZE-1; ++ ++ map->start=pxa_pcmcia_socket[sock].virt_io; ++ map->stop=map->start+(map->stop-start); ++ ++ pxa_pcmcia_socket[sock].io_map[map->map]=*map; ++ ++ return 0; ++ ++} /* pxa_pcmcia_set_io_map() */ ++ ++ ++/* pxa_pcmcia_get_mem_map() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the get_mem_map() operation for the in-kernel PCMCIA ++ * service (formerly SS_GetMemMap in Card Services). Just returns a ++ * memory map descriptor which was assigned earlier by a ++ * set_mem_map() request. ++ * ++ * Returns: 0 on success, -1 if the map index was out of range ++ */ ++static int pxa_pcmcia_get_mem_map(unsigned int sock, ++ struct pccard_mem_map *map){ ++ ++ DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ if(map->map>=MAX_WIN){ ++ printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, ++ map->map); ++ return -1; ++ } ++ ++ *map=pxa_pcmcia_socket[sock].mem_map[map->map]; ++ ++ return 0; ++} ++ ++ ++/* pxa_pcmcia_set_mem_map() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the set_mem_map() operation for the in-kernel PCMCIA ++ * service (formerly SS_SetMemMap in Card Services). We configure ++ * the map speed as requested, but override the address ranges ++ * supplied by Card Services. ++ * ++ * Returns: 0 on success, -1 on error ++ */ ++static int pxa_pcmcia_set_mem_map(unsigned int sock, ++ struct pccard_mem_map *map){ ++ unsigned int clock, speed; ++ unsigned long mecr, start; ++ ++ DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ DEBUG(4, "\tmap %u speed %u\n\tsys_start %#lx\n" ++ "\tsys_stop %#lx\n\tcard_start %#x\n" ++ "\tflags: %s%s%s%s%s%s%s%s\n", ++ map->map, map->speed, map->sys_start, map->sys_stop, ++ map->card_start, (map->flags==0)?"<NONE>":"", ++ (map->flags&MAP_ACTIVE)?"ACTIVE ":"", ++ (map->flags&MAP_16BIT)?"16BIT ":"", ++ (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", ++ (map->flags&MAP_0WS)?"0WS ":"", ++ (map->flags&MAP_WRPROT)?"WRPROT ":"", ++ (map->flags&MAP_ATTRIB)?"ATTRIB ":"", ++ (map->flags&MAP_USE_WAIT)?"USE_WAIT ":""); ++ ++ if(map->map>=MAX_WIN){ ++ printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, ++ map->map); ++ return -1; ++ } ++ ++ if(map->flags&MAP_ACTIVE){ ++ /* When clients issue RequestMap, the access speed is not always ++ * properly configured: ++ */ ++ if(map->speed > 0) ++ speed = map->speed; ++ else ++ switch(pxa_pcmcia_socket[sock].cs_state.Vcc){ ++ case 33: ++ speed = PXA_PCMCIA_3V_MEM_ACCESS; ++ break; ++ default: ++ speed = PXA_PCMCIA_5V_MEM_ACCESS; ++ } ++ ++ clock = get_lclk_frequency_10khz(); ++ ++ if(map->flags&MAP_ATTRIB){ ++ if (sock == 0) { ++ MCATT0 = ((pxa_mcxx_setup(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++ } else { ++ MCATT1 = ((pxa_mcxx_setup(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++ } ++ pxa_pcmcia_socket[sock].speed_attr=speed; ++ } else { ++ if (sock == 0) { ++ MCMEM0 = ((pxa_mcxx_setup(speed, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(speed, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(speed, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++ } else { ++ MCMEM1 = ((pxa_mcxx_setup(speed, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(speed, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(speed, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++ } ++ pxa_pcmcia_socket[sock].speed_mem=speed; ++ } ++ DEBUG(4, "%s(): FAST%u %lx BSM%u %lx BSA%u %lx BSIO%u %lx\n", ++ __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock, ++ MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), ++ sock, MECR_BSIO_GET(mecr, sock)); ++ } ++ ++ start=map->sys_start; ++ ++ if(map->sys_stop==0) ++ map->sys_stop=PAGE_SIZE-1; ++ ++ map->sys_start=(map->flags & MAP_ATTRIB)?\ ++ pxa_pcmcia_socket[sock].phys_attr:\ ++ pxa_pcmcia_socket[sock].phys_mem; ++ ++ map->sys_stop=map->sys_start+(map->sys_stop-start); ++ ++ pxa_pcmcia_socket[sock].mem_map[map->map]=*map; ++ ++ return 0; ++ ++} /* pxa_pcmcia_set_mem_map() */ ++ ++ ++#if defined(CONFIG_PROC_FS) ++ ++/* pxa_pcmcia_proc_setup() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the proc_setup() operation for the in-kernel PCMCIA ++ * service (formerly SS_ProcSetup in Card Services). ++ * ++ * Returns: 0 on success, -1 on error ++ */ ++static void pxa_pcmcia_proc_setup(unsigned int sock, ++ struct proc_dir_entry *base){ ++ struct proc_dir_entry *entry; ++ ++ DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ if((entry=create_proc_entry("status", 0, base))==NULL){ ++ printk(KERN_ERR "Unable to install \"status\" procfs entry\n"); ++ return; ++ } ++ ++ entry->read_proc=pxa_pcmcia_proc_status; ++ entry->data=(void *)sock; ++} ++ ++ ++/* pxa_pcmcia_proc_status() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the /proc/bus/pccard/??/status file. ++ * ++ * Returns: the number of characters added to the buffer ++ */ ++static int pxa_pcmcia_proc_status(char *buf, char **start, off_t pos, ++ int count, int *eof, void *data){ ++ char *p=buf; ++ unsigned int sock=(unsigned int)data; ++ unsigned int clock = get_lclk_frequency_10khz(); ++ unsigned long mecr = MECR; ++ ++ p+=sprintf(p, "k_flags : %s%s%s%s%s%s%s\n", ++ pxa_pcmcia_socket[sock].k_state.detect?"detect ":"", ++ pxa_pcmcia_socket[sock].k_state.ready?"ready ":"", ++ pxa_pcmcia_socket[sock].k_state.bvd1?"bvd1 ":"", ++ pxa_pcmcia_socket[sock].k_state.bvd2?"bvd2 ":"", ++ pxa_pcmcia_socket[sock].k_state.wrprot?"wrprot ":"", ++ pxa_pcmcia_socket[sock].k_state.vs_3v?"vs_3v ":"", ++ pxa_pcmcia_socket[sock].k_state.vs_Xv?"vs_Xv ":""); ++ ++ p+=sprintf(p, "status : %s%s%s%s%s%s%s%s%s\n", ++ pxa_pcmcia_socket[sock].k_state.detect?"SS_DETECT ":"", ++ pxa_pcmcia_socket[sock].k_state.ready?"SS_READY ":"", ++ pxa_pcmcia_socket[sock].cs_state.Vcc?"SS_POWERON ":"", ++ pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\ ++ "SS_IOCARD ":"", ++ (pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD && ++ pxa_pcmcia_socket[sock].k_state.bvd1)?"SS_STSCHG ":"", ++ ((pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 && ++ (pxa_pcmcia_socket[sock].k_state.bvd1==0))?"SS_BATDEAD ":"", ++ ((pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 && ++ (pxa_pcmcia_socket[sock].k_state.bvd2==0))?"SS_BATWARN ":"", ++ pxa_pcmcia_socket[sock].k_state.vs_3v?"SS_3VCARD ":"", ++ pxa_pcmcia_socket[sock].k_state.vs_Xv?"SS_XVCARD ":""); ++ ++ p+=sprintf(p, "mask : %s%s%s%s%s\n", ++ pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_DETECT?\ ++ "SS_DETECT ":"", ++ pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_READY?\ ++ "SS_READY ":"", ++ pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_BATDEAD?\ ++ "SS_BATDEAD ":"", ++ pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_BATWARN?\ ++ "SS_BATWARN ":"", ++ pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_STSCHG?\ ++ "SS_STSCHG ":""); ++ ++ p+=sprintf(p, "cs_flags : %s%s%s%s%s\n", ++ pxa_pcmcia_socket[sock].cs_state.flags&SS_PWR_AUTO?\ ++ "SS_PWR_AUTO ":"", ++ pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\ ++ "SS_IOCARD ":"", ++ pxa_pcmcia_socket[sock].cs_state.flags&SS_RESET?\ ++ "SS_RESET ":"", ++ pxa_pcmcia_socket[sock].cs_state.flags&SS_SPKR_ENA?\ ++ "SS_SPKR_ENA ":"", ++ pxa_pcmcia_socket[sock].cs_state.flags&SS_OUTPUT_ENA?\ ++ "SS_OUTPUT_ENA ":""); ++ ++ p+=sprintf(p, "Vcc : %d\n", pxa_pcmcia_socket[sock].cs_state.Vcc); ++ ++ p+=sprintf(p, "Vpp : %d\n", pxa_pcmcia_socket[sock].cs_state.Vpp); ++ ++ p+=sprintf(p, "irq : %d\n", pxa_pcmcia_socket[sock].cs_state.io_irq); ++ ++ p+=sprintf(p, "I/O : %u (%u)\n", pxa_pcmcia_socket[sock].speed_io, ++ sock ? ++ pxa_pcmcia_cmd_time(clock, ++ ((MCIO1 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK)) : ++ pxa_pcmcia_cmd_time(clock, ++ ((MCIO0 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK))); ++ ++ p+=sprintf(p, "attribute: %u (%u)\n", pxa_pcmcia_socket[sock].speed_attr, ++ sock ? ++ pxa_pcmcia_cmd_time(clock, ++ ((MCATT1 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK)) : ++ pxa_pcmcia_cmd_time(clock, ++ ((MCATT0 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK))); ++ ++ p+=sprintf(p, "common : %u (%u)\n", pxa_pcmcia_socket[sock].speed_mem, ++ sock ? ++ pxa_pcmcia_cmd_time(clock, ++ ((MCMEM1 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK)) : ++ pxa_pcmcia_cmd_time(clock, ++ ((MCMEM0 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK))); ++ ++ return p-buf; ++} ++ ++#endif /* defined(CONFIG_PROC_FS) */ ++ ++ ++#ifdef CONFIG_CPU_FREQ ++ ++/* pxa_pcmcia_update_mecr() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * When pxa_pcmcia_notifier() decides that a MECR adjustment (due ++ * to a core clock frequency change) is needed, this routine establishes ++ * new BS_xx values consistent with the clock speed `clock'. ++ */ ++static void pxa_pcmcia_update_mecr(unsigned int clock){ ++ unsigned int sock; ++ ++ for(sock = 0; sock < PXA_PCMCIA_MAX_SOCK; ++sock){ ++ ++ // REVISIT: MCXX macros needed here ++ // MECR_BSIO_SET(mecr, sock, ++// pxa_pcmcia_mecr_bs(pxa_pcmcia_socket[sock].speed_io, ++// clock)); ++ // MECR_BSA_SET(mecr, sock, ++// pxa_pcmcia_mecr_bs(pxa_pcmcia_socket[sock].speed_attr, ++// clock)); ++ // MECR_BSM_SET(mecr, sock, ++// pxa_pcmcia_mecr_bs(pxa_pcmcia_socket[sock].speed_mem, ++// clock)); ++ } ++} ++ ++/* pxa_pcmcia_notifier() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^ ++ * When changing the processor core clock frequency, it is necessary ++ * to adjust the MECR timings accordingly. We've recorded the timings ++ * requested by Card Services, so this is just a matter of finding ++ * out what our current speed is, and then recomputing the new MECR ++ * values. ++ * ++ * Returns: 0 on success, -1 on error ++ */ ++static int pxa_pcmcia_notifier(struct notifier_block *nb, ++ unsigned long val, void *data){ ++ struct cpufreq_info *ci = data; ++ ++ switch(val){ ++ case CPUFREQ_MINMAX: ++ ++ break; ++ ++ case CPUFREQ_PRECHANGE: ++ ++ if(ci->new_freq > ci->old_freq){ ++ DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, pre-updating\n", ++ __FUNCTION__, ++ ci->new_freq / 1000, (ci->new_freq / 100) % 10, ++ ci->old_freq / 1000, (ci->old_freq / 100) % 10); ++ pxa_pcmcia_update_mecr(ci->new_freq); ++ } ++ ++ break; ++ ++ case CPUFREQ_POSTCHANGE: ++ ++ if(ci->new_freq < ci->old_freq){ ++ DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, post-updating\n", ++ __FUNCTION__, ++ ci->new_freq / 1000, (ci->new_freq / 100) % 10, ++ ci->old_freq / 1000, (ci->old_freq / 100) % 10); ++ pxa_pcmcia_update_mecr(ci->new_freq); ++ } ++ ++ break; ++ ++ default: ++ printk(KERN_ERR "%s(): unknown CPU frequency event %lx\n", __FUNCTION__, ++ val); ++ return -1; ++ ++ } ++ ++ return 0; ++ ++} ++ ++static struct notifier_block pxa_pcmcia_notifier_block = { ++ notifier_call: pxa_pcmcia_notifier ++}; ++ ++#endif ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/pxa/pxa.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,233 @@ ++/* ++ * linux/drivers/pcmcia/pxa/pxa.h ++ * ++ * Author: George Davis ++ * Created: Jan 10, 2002 ++ * Copyright: MontaVista 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. ++ * ++ * Originally based upon linux/drivers/pcmcia/sa1100_generic.h ++ * ++ */ ++ ++/*====================================================================== ++ ++ Device driver for the PCMCIA control functionality of Intel ++ PXA250/210 microprocessors. ++ ++ The contents of this file are subject to the Mozilla Public ++ License Version 1.1 (the "License"); you may not use this file ++ except in compliance with the License. You may obtain a copy of ++ the License at http://www.mozilla.org/MPL/ ++ ++ Software distributed under the License is distributed on an "AS ++ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++ implied. See the License for the specific language governing ++ rights and limitations under the License. ++ ++ The initial developer of the original code is John G. Dorsey ++ <john+@cs.cmu.edu>. Portions created by John G. Dorsey are ++ Copyright (C) 1999 John G. Dorsey. All Rights Reserved. ++ ++ Alternatively, the contents of this file may be used under the ++ terms of the GNU Public License version 2 (the "GPL"), in which ++ case the provisions of the GPL are applicable instead of the ++ above. If you wish to allow the use of your version of this file ++ only under the terms of the GPL and not to allow others to use ++ your version of this file under the MPL, indicate your decision ++ by deleting the provisions above and replace them with the notice ++ and other provisions required by the GPL. If you do not delete ++ the provisions above, a recipient may use your version of this ++ file under either the MPL or the GPL. ++ ++======================================================================*/ ++ ++#if !defined(_PCMCIA_PXA_H) ++# define _PCMCIA_PXA_H ++ ++#include <pcmcia/cs_types.h> ++#include <pcmcia/ss.h> ++#include <pcmcia/bulkmem.h> ++#include <pcmcia/cistpl.h> ++#include "../cs_internal.h" ++ ++#include <asm/arch/pcmcia.h> ++ ++ ++/* MECR: Expansion Memory Configuration Register ++ * (SA-1100 Developers Manual, p.10-13; SA-1110 Developers Manual, p.10-24) ++ * ++ * MECR layout is: ++ * ++ * FAST1 BSM1<4:0> BSA1<4:0> BSIO1<4:0> FAST0 BSM0<4:0> BSA0<4:0> BSIO0<4:0> ++ * ++ * (This layout is actually true only for the SA-1110; the FASTn bits are ++ * reserved on the SA-1100.) ++ */ ++ ++#define MCXX_SETUP_MASK (0x7f) ++#define MCXX_ASST_MASK (0x1f) ++#define MCXX_HOLD_MASK (0x3f) ++#define MCXX_SETUP_SHIFT (0) ++#define MCXX_ASST_SHIFT (7) ++#define MCXX_HOLD_SHIFT (14) ++ ++ ++#define MECR_SET(mecr, sock, shift, mask, bs) \ ++((mecr)=((mecr)&~(((mask)<<(shift))<<\ ++ ((sock)==0?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT)))|\ ++ (((bs)<<(shift))<<((sock)==0?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT))) ++ ++#define MECR_GET(mecr, sock, shift, mask) \ ++((((mecr)>>(((sock)==0)?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT))>>\ ++ (shift))&(mask)) ++ ++#define MECR_BSIO_SET(mecr, sock, bs) \ ++MECR_SET((mecr), (sock), MECR_BSIO_SHIFT, MECR_BS_MASK, (bs)) ++ ++#define MECR_BSIO_GET(mecr, sock) \ ++MECR_GET((mecr), (sock), MECR_BSIO_SHIFT, MECR_BS_MASK) ++ ++#define MECR_BSA_SET(mecr, sock, bs) \ ++MECR_SET((mecr), (sock), MECR_BSA_SHIFT, MECR_BS_MASK, (bs)) ++ ++#define MECR_BSA_GET(mecr, sock) \ ++MECR_GET((mecr), (sock), MECR_BSA_SHIFT, MECR_BS_MASK) ++ ++#define MECR_BSM_SET(mecr, sock, bs) \ ++MECR_SET((mecr), (sock), MECR_BSM_SHIFT, MECR_BS_MASK, (bs)) ++ ++#define MECR_BSM_GET(mecr, sock) \ ++MECR_GET((mecr), (sock), MECR_BSM_SHIFT, MECR_BS_MASK) ++ ++#define MECR_FAST_SET(mecr, sock, fast) \ ++MECR_SET((mecr), (sock), MECR_FAST_SHIFT, MECR_FAST_MODE_MASK, (fast)) ++ ++#define MECR_FAST_GET(mecr, sock) \ ++MECR_GET((mecr), (sock), MECR_FAST_SHIFT, MECR_FAST_MODE_MASK) ++ ++ ++/* This function implements the BS value calculation for setting the MECR ++ * using integer arithmetic: ++ */ ++static inline unsigned int pxa_pcmcia_mecr_bs(unsigned int pcmcia_cycle_ns, ++ unsigned int cpu_clock_khz){ ++ unsigned int t = ((pcmcia_cycle_ns * cpu_clock_khz) / 6) - 1000000; ++ return (t / 1000000) + (((t % 1000000) == 0) ? 0 : 1); ++} ++ ++static inline u_int pxa_mcxx_hold(u_int pcmcia_cycle_ns, ++ u_int mem_clk_10khz){ ++ u_int code = pcmcia_cycle_ns * mem_clk_10khz; ++ return (code / 300000) + ((code % 300000) ? 1 : 0); ++} ++ ++static inline u_int pxa_mcxx_asst(u_int pcmcia_cycle_ns, ++ u_int mem_clk_10khz){ ++ u_int code = pcmcia_cycle_ns * mem_clk_10khz; ++ return (code / 300000) + ((code % 300000) ? 1 : 0); ++} ++ ++static inline u_int pxa_mcxx_setup(u_int pcmcia_cycle_ns, ++ u_int mem_clk_10khz){ ++ u_int code = pcmcia_cycle_ns * mem_clk_10khz; ++ return (code / 100000) + ((code % 100000) ? 1 : 0) + 1; ++} ++ ++/* This function returns the (approxmiate) command assertion period, in ++ * nanoseconds, for a given CPU clock frequency and MCXX_ASST value: ++ */ ++ ++static inline u_int pxa_pcmcia_cmd_time(u_int mem_clk_10khz, ++ u_int pcmcia_mcxx_asst){ ++ return (300000 * (pcmcia_mcxx_asst + 1) / mem_clk_10khz); ++} ++ ++ ++/* SA-1100 PCMCIA Memory and I/O timing ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * The SA-1110 Developer's Manual, section 10.2.5, says the following: ++ * ++ * "To calculate the recommended BS_xx value for each address space: ++ * divide the command width time (the greater of twIOWR and twIORD, ++ * or the greater of twWE and twOE) by processor cycle time; divide ++ * by 2; divide again by 3 (number of BCLK's per command assertion); ++ * round up to the next whole number; and subtract 1." ++ * ++ * The PC Card Standard, Release 7, section 4.13.4, says that twIORD ++ * has a minimum value of 165ns. Section 4.13.5 says that twIOWR has ++ * a minimum value of 165ns, as well. Section 4.7.2 (describing ++ * common and attribute memory write timing) says that twWE has a ++ * minimum value of 150ns for a 250ns cycle time (for 5V operation; ++ * see section 4.7.4), or 300ns for a 600ns cycle time (for 3.3V ++ * operation, also section 4.7.4). Section 4.7.3 says that taOE ++ * has a maximum value of 150ns for a 300ns cycle time (for 5V ++ * operation), or 300ns for a 600ns cycle time (for 3.3V operation). ++ * ++ * When configuring memory maps, Card Services appears to adopt the policy ++ * that a memory access time of "0" means "use the default." The default ++ * PCMCIA I/O command width time is 165ns. The default PCMCIA 5V attribute ++ * and memory command width time is 150ns; the PCMCIA 3.3V attribute and ++ * memory command width time is 300ns. ++ */ ++ ++/* The PXA 250 and PXA 210 Application Processors Developer's Manual ++ * was used to determine correct PXA_PCMCIA_IO_ACCES time ++ */ ++ ++#define PXA_PCMCIA_IO_ACCESS (165) ++ ++/* Default PC Card Common Memory timings*/ ++ ++#define PXA_PCMCIA_5V_MEM_ACCESS (250) ++#define PXA_PCMCIA_3V_MEM_ACCESS (250) ++ ++/* Atrribute Memory timing - must be constant via PC Card standart*/ ++ ++#define PXA_PCMCIA_ATTR_MEM_ACCESS (300) ++ ++ ++/* The socket driver actually works nicely in interrupt-driven form, ++ * so the (relatively infrequent) polling is "just to be sure." ++ */ ++#define PXA_PCMCIA_POLL_PERIOD (2*HZ) ++ ++ ++/* This structure encapsulates per-socket state which we might need to ++ * use when responding to a Card Services query of some kind. ++ */ ++struct pxa_pcmcia_socket { ++ socket_state_t cs_state; ++ struct pcmcia_state k_state; ++ unsigned int irq; ++ void (*handler)(void *, unsigned int); ++ void *handler_info; ++ pccard_io_map io_map[MAX_IO_WIN]; ++ pccard_mem_map mem_map[MAX_WIN]; ++ ioaddr_t virt_io, phys_attr, phys_mem; ++ unsigned short speed_io, speed_attr, speed_mem; ++}; ++ ++ ++/* I/O pins replacing memory pins ++ * (PCMCIA System Architecture, 2nd ed., by Don Anderson, p.75) ++ * ++ * These signals change meaning when going from memory-only to ++ * memory-or-I/O interface: ++ */ ++#define iostschg bvd1 ++#define iospkr bvd2 ++ ++ ++/* ++ * Declaration for all implementation specific low_level operations. ++ */ ++extern struct pcmcia_low_level lubbock_pcmcia_ops; ++extern struct pcmcia_low_level pxa_idp_pcmcia_ops; ++extern struct pcmcia_low_level cerf_pcmcia_ops; ++extern struct pcmcia_low_level trizeps2_pcmcia_ops; ++ ++#endif /* !defined(_PCMCIA_PXA_H) */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/pxa/pxa_idp.c 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,297 @@ ++/* ++ * linux/drivers/pcmcia/pxa/pxa_idp.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. ++ * ++ * Copyright (c) 2002 Accelent Systems, Inc. All Rights Reserved ++ * ++ * Platform specific routines for the Accelent PXA250 IDP, based on those ++ * first done for the Lubbock. ++ * ++ * Version 1.0 2002-05-02 Jeff Sutherland <jeffs@accelent.com> ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/sched.h> ++ ++#include <pcmcia/ss.h> ++ ++#include <asm/delay.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/arch/pcmcia.h> ++ ++static int ++pxa_idp_pcmcia_init(struct pcmcia_init *init) ++{ ++ int return_val = 0; ++ ++ /* Set PCMCIA Socket 0 power to standby mode. ++ * PXA IDP has dedicated CPLD pins for all this stuff :-) ++ */ ++ ++ /* both slots disabled, reset NOT active */ ++ IDP_CPLD_PCCARD_EN = PCC0_ENABLE | PCC1_ENABLE; ++ ++ IDP_CPLD_PCCARD_PWR = 0; //all power to both slots off ++ ++ GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S0_CD_VALID)) &= ++ ~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S0_CD_VALID)); ++ GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S1_CD_VALID)) &= ++ ~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S1_CD_VALID)); ++ ++ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S0_CD_VALID), ++ GPIO_BOTH_EDGES); ++ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S1_CD_VALID), ++ GPIO_BOTH_EDGES); ++ ++ /* irq's for slots: */ ++ GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S0_RDYINT)) &= ++ ~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S0_RDYINT)); ++ GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S1_RDYINT)) &= ++ ~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S1_RDYINT)); ++ ++ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S0_RDYINT), ++ GPIO_FALLING_EDGE); ++ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S1_RDYINT), ++ GPIO_FALLING_EDGE); ++ ++ return_val = ++ request_irq(PCMCIA_S0_CD_VALID, init->handler, SA_INTERRUPT, ++ "PXA PCMCIA CD0", NULL); ++ ++ if (return_val < 0) ++ return -1; ++ ++ return_val += ++ request_irq(PCMCIA_S1_CD_VALID, init->handler, SA_INTERRUPT, ++ "PXA PCMCIA CD1", NULL); ++ ++ if (return_val < 0) { ++ free_irq(PCMCIA_S0_CD_VALID, NULL); ++ return -1; ++ } ++ ++ return 2; ++} ++ ++static int ++pxa_idp_pcmcia_shutdown(void) ++{ ++ ++ free_irq(PCMCIA_S0_CD_VALID, NULL); ++ free_irq(PCMCIA_S1_CD_VALID, NULL); ++ ++ IDP_CPLD_PCCARD_EN = 0x03; //disable slots ++ udelay(200); ++ IDP_CPLD_PCCARD_PWR = 0; //shut off all power ++ ++ return 0; ++} ++ ++static int ++pxa_idp_pcmcia_socket_state(struct pcmcia_state_array *state_array) ++{ ++ unsigned long status; ++ int return_val = 1; ++ int i; ++ volatile unsigned long *stat_regs[2] = { &IDP_CPLD_PCCARD0_STATUS, ++ &IDP_CPLD_PCCARD1_STATUS ++ }; ++ ++ if (state_array->size < 2) ++ return -1; ++ ++ memset(state_array->state, 0, ++ (state_array->size) * sizeof (struct pcmcia_state)); ++ ++ for (i = 0; i < 2; i++) { ++ ++ status = *stat_regs[i]; ++ ++ /* this one is a gpio */ ++ state_array->state[i].detect = (PCC_DETECT(i)) ? 0 : 1; ++ ++ state_array->state[i].ready = ++ ((status & _PCC_IRQ) == 0) ? 0 : 1; ++ state_array->state[i].bvd1 = (status & PCC_BVD1) ? 0 : 1; ++ state_array->state[i].bvd2 = (status & PCC_BVD2) ? 0 : 1; ++ state_array->state[i].wrprot = ++ (status & _PCC_WRPROT) ? 1 : 0; ++ state_array->state[i].vs_3v = (status & PCC_VS1) ? 0 : 1; ++ state_array->state[i].vs_Xv = (status & PCC_VS2) ? 0 : 1; ++ } ++ ++ return return_val; ++} ++ ++static int ++pxa_idp_pcmcia_get_irq_info(struct pcmcia_irq_info *info) ++{ ++ switch (info->sock) { ++ case 0: ++ info->irq = PCMCIA_S0_RDYINT; ++ break; ++ ++ case 1: ++ info->irq = PCMCIA_S1_RDYINT; ++ break; ++ ++ default: ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int ++pxa_idp_pcmcia_configure_socket(unsigned int sock, socket_state_t *state) ++{ ++ /* The PXA Idp uses the Maxim MAX1602, with the following connections: ++ * ++ * Socket 0 (PCMCIA): ++ * MAX1602 PXA_IDP Register ++ * Pin Signal IDP_CPLD_PCCARD_PWR: ++ * ----- ------- ---------------------- ++ * A0VPP PCC0_PWR0 bit0 ++ * A1VPP PCC0_PWR1 bit1 ++ * A0VCC PCC0_PWR2 bit2 ++ * A1VCC PCC0_PWR3 bit3 ++ * VX VCC ++ * VY +3.3V ++ * 12IN +12V ++ * CODE +3.3V Cirrus Code, CODE = High (VY) ++ * ++ * Socket 1 (PCMCIA): ++ * MAX1602 PXA_IDP Register ++ * Pin Signal IDP_CPLD_PCCARD_PWR: ++ * ----- ------- ---------------------- ++ * A0VPP PCC1_PWR0 bit4 ++ * A1VPP PCC1_PWR1 bit5 ++ * A0VCC PCC1_PWR2 bit6 ++ * A1VCC PCC1_PWR3 bit7 ++ * VX VCC ++ * VY +3.3V ++ * 12IN +12V ++ * CODE +3.3V Cirrus Code, CODE = High (VY) ++ * ++ */ ++ ++ switch (sock) { ++ case 0: ++ switch (state->Vcc) { ++ case 0: ++ IDP_CPLD_PCCARD_EN |= PCC0_ENABLE; // disable socket ++ udelay(200); ++ IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR2 | PCC0_PWR3); ++ break; ++ ++ case 33: ++ IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR2 | PCC0_PWR3); ++ IDP_CPLD_PCCARD_PWR |= PCC0_PWR3; ++ IDP_CPLD_PCCARD_EN &= ~PCC0_ENABLE; //turn it on ++ break; ++ ++ case 50: ++ IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR2 | PCC0_PWR3); ++ IDP_CPLD_PCCARD_PWR |= PCC0_PWR2; ++ IDP_CPLD_PCCARD_EN &= ~PCC0_ENABLE; ++ break; ++ ++ default: ++ printk(KERN_ERR "%s(): unrecognized Vcc %u\n", ++ __FUNCTION__, state->Vcc); ++ return -1; ++ } ++ ++ switch (state->Vpp) { ++ case 0: ++ IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR0 | PCC0_PWR1); ++ break; ++ ++ case 120: ++ IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR0 | PCC0_PWR1); ++ IDP_CPLD_PCCARD_PWR |= PCC0_PWR1; ++ break; ++ ++ default: ++ if (state->Vpp == state->Vcc) ++ IDP_CPLD_PCCARD_PWR = ++ (IDP_CPLD_PCCARD_PWR & ++ ~(PCC0_PWR0 | PCC0_PWR1)) | PCC0_PWR0; ++ else { ++ printk(KERN_ERR "%s(): unrecognized Vpp %u\n", ++ __FUNCTION__, state->Vpp); ++ return -1; ++ } ++ } ++ ++ IDP_CPLD_PCCARD_EN = ++ (state->flags & SS_RESET) ? (IDP_CPLD_PCCARD_EN | PCC0_RESET) ++ : (IDP_CPLD_PCCARD_EN & ~PCC0_RESET); ++ break; ++ ++ case 1: ++ switch (state->Vcc) { ++ case 0: ++ IDP_CPLD_PCCARD_EN |= PCC1_ENABLE; // disable socket ++ udelay(200); ++ IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3); ++ break; ++ ++ case 33: ++ IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3); ++ IDP_CPLD_PCCARD_PWR |= PCC1_PWR3; ++ IDP_CPLD_PCCARD_EN &= ~PCC1_ENABLE; //turn it on ++ break; ++ ++ case 50: ++ IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3); ++ IDP_CPLD_PCCARD_PWR |= PCC1_PWR2; ++ IDP_CPLD_PCCARD_EN &= ~PCC1_ENABLE; ++ break; ++ ++ default: ++ printk(KERN_ERR "%s(): unrecognized Vcc %u\n", ++ __FUNCTION__, state->Vcc); ++ return -1; ++ } ++ ++ switch (state->Vpp) { ++ case 0: ++ IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR0 | PCC1_PWR1); ++ break; ++ ++ case 120: ++ IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR0 | PCC1_PWR1); ++ IDP_CPLD_PCCARD_PWR |= PCC1_PWR1; ++ break; ++ ++ default: ++ if (state->Vpp == state->Vcc) ++ IDP_CPLD_PCCARD_PWR = ++ (IDP_CPLD_PCCARD_PWR & ++ ~(PCC1_PWR0 | PCC1_PWR1)) | PCC1_PWR0; ++ else { ++ printk(KERN_ERR "%s(): unrecognized Vpp %u\n", ++ __FUNCTION__, state->Vpp); ++ return -1; ++ } ++ } ++ IDP_CPLD_PCCARD_EN = (state->flags & SS_RESET) ? (IDP_CPLD_PCCARD_EN | PCC1_RESET) ++ : (IDP_CPLD_PCCARD_EN & ~PCC1_RESET); ++ break; ++ } ++ return 0; ++} ++ ++struct pcmcia_low_level pxa_idp_pcmcia_ops = { ++ pxa_idp_pcmcia_init, ++ pxa_idp_pcmcia_shutdown, ++ pxa_idp_pcmcia_socket_state, ++ pxa_idp_pcmcia_get_irq_info, ++ pxa_idp_pcmcia_configure_socket ++}; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/pxa/trizeps2.c 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,187 @@ ++/* ++ * linux/drivers/pcmcia/pxa/trizeps2.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. ++ * ++ * Copyright (c) 2002 Accelent Systems, Inc. All Rights Reserved ++ * ++ * Platform specific routines for the Keith-n-Koep Trizeps-II, based on IDP ++ * ++ * Copyright (c) 2003 Teradyne DS, Ltd. ++ * Port to Trizeps-2 MT6N board by Luc De Cock ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/sched.h> ++ ++#include <pcmcia/ss.h> ++ ++#include <asm/delay.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/arch/pcmcia.h> ++ ++static int trizeps2_pcmcia_init(struct pcmcia_init *init) ++{ ++ int return_val = 0; ++ unsigned short *bcr = (unsigned short *) TRIZEPS2_BCR_BASE; ++ unsigned short val; ++ ++ /* reset the PCMCIA controller */ ++ val = trizeps2_bcr_shadow | BCR_PCMCIA_RESET; ++ *bcr = val; ++ udelay(500); ++ /* un-reset it again */ ++ trizeps2_bcr_shadow &= ~BCR_PCMCIA_RESET; ++ /* enable the PCMCIA buffer */ ++ trizeps2_bcr_shadow &= ~(1 << 5); ++ *bcr = trizeps2_bcr_shadow; ++ ++ GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S_CD_VALID)) &= ++ ~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S_CD_VALID)); ++ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S_CD_VALID), ++ PCMCIA_S_CD_VALID_EDGE); ++ GPDR(IRQ_TO_GPIO(PCMCIA_S_RDYINT)) &= ++ ~GPIO_bit(IRQ_TO_GPIO(PCMCIA_S_RDYINT)); ++ set_GPIO_IRQ_edge(IRQ_TO_GPIO(PCMCIA_S_RDYINT), ++ PCMCIA_S_RDYINT_EDGE); ++ ++ return_val = request_irq(PCMCIA_S_CD_VALID, init->handler, SA_INTERRUPT, ++ "PXA PCMCIA CD", NULL); ++ if (return_val < 0) { ++ return -1; ++ } ++ /* only 1 slot */ ++ return 1; ++} ++ ++static int trizeps2_pcmcia_shutdown(void) ++{ ++ free_irq(PCMCIA_S_CD_VALID, NULL); ++ ++ unsigned short *bcr = (unsigned short *) TRIZEPS2_BCR_BASE; ++ trizeps2_bcr_shadow |= (1 << 5); /* pcmcia buffer off */ ++ *bcr = trizeps2_bcr_shadow; ++ trizeps2_bcr_shadow &= 0xFFF0; /* pcmcia control logic grounded */ ++ *bcr = trizeps2_bcr_shadow; ++ ++ return 0; ++} ++ ++static int trizeps2_pcmcia_socket_state(struct pcmcia_state_array *state_array) ++{ ++ unsigned long status; ++ int return_val = 1; ++ volatile unsigned short *stat_regs[1] = { ++ &TRIZEPS2_PCCARD_STATUS ++ }; ++ ++ if (state_array->size < 1) ++ return -1; ++ ++ memset(state_array->state, 0, ++ (state_array->size) * sizeof (struct pcmcia_state)); ++ ++ status = *stat_regs[0]; ++ ++ /* this one is a gpio */ ++ state_array->state[0].detect = (PCC_DETECT) ? 0 : 1; ++ state_array->state[0].ready = (PCC_READY) ? 1 : 0; ++ state_array->state[0].bvd1 = (status & PCC_BVD1) ? 1 : 0; ++ state_array->state[0].bvd2 = (status & PCC_BVD2) ? 1 : 0; ++ state_array->state[0].wrprot = 0; /* r/w all the time */ ++ state_array->state[0].vs_3v = (status & PCC_VS1) ? 0 : 1; ++ state_array->state[0].vs_Xv = (status & PCC_VS2) ? 0 : 1; ++ ++ return return_val; ++} ++ ++static int trizeps2_pcmcia_get_irq_info(struct pcmcia_irq_info *info) ++{ ++ switch (info->sock) { ++ case 0: ++ info->irq = PCMCIA_S_RDYINT; ++ break; ++ ++ default: ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int trizeps2_pcmcia_configure_socket(unsigned int sock, socket_state_t *state) ++{ ++ unsigned short cntr_logic = trizeps2_bcr_shadow & 0xF; ++ unsigned short *bcr = (unsigned short *) TRIZEPS2_BCR_BASE; ++ ++ /* configure Vcc and Vpp */ ++ switch (sock) { ++ case 0: ++ switch (state->Vcc) { ++ case 0: ++ cntr_logic &= ~(PCC_3V | PCC_5V); ++ break; ++ ++ case 33: ++ cntr_logic &= ~(PCC_3V | PCC_5V); ++ cntr_logic |= PCC_3V; ++ break; ++ ++ case 50: ++ cntr_logic &= ~(PCC_3V | PCC_5V); ++ cntr_logic |= PCC_5V; ++ break; ++ ++ default: ++ printk(KERN_ERR "%s(): unrecognized Vcc %u\n", ++ __FUNCTION__, state->Vcc); ++ return -1; ++ } ++ ++ switch (state->Vpp) { ++ case 0: ++ cntr_logic &= ~(PCC_EN0 | PCC_EN1); ++ break; ++ ++ case 120: ++ cntr_logic &= ~(PCC_EN0 | PCC_EN1); ++ cntr_logic |= PCC_EN1; ++ break; ++ ++ default: ++ if (state->Vpp == state->Vcc) { ++ cntr_logic &= ~(PCC_EN0 | PCC_EN1); ++ cntr_logic |= PCC_EN0; ++ } ++ else { ++ printk(KERN_ERR "%s(): unrecognized Vpp %u\n", ++ __FUNCTION__, state->Vpp); ++ return -1; ++ } ++ } ++ trizeps2_bcr_shadow &= ~(PCC_EN0 | PCC_EN1 | PCC_3V | PCC_5V | ++ BCR_PCMCIA_RESET); ++ trizeps2_bcr_shadow |= cntr_logic; ++ *bcr = trizeps2_bcr_shadow; ++ /* reset PCMCIA controller if requested */ ++ trizeps2_bcr_shadow |= ++ (state->flags & SS_RESET) ? BCR_PCMCIA_RESET : 0; ++ *bcr = trizeps2_bcr_shadow; ++ udelay(500); ++ break; ++ } ++ return 0; ++} ++ ++struct pcmcia_low_level trizeps2_pcmcia_ops = { ++ trizeps2_pcmcia_init, ++ trizeps2_pcmcia_shutdown, ++ trizeps2_pcmcia_socket_state, ++ trizeps2_pcmcia_get_irq_info, ++ trizeps2_pcmcia_configure_socket ++}; ++ +--- linux-2.4.25/drivers/pcmcia/sa1100_cerf.c~2.4.25-vrs2-pxa1.patch 2002-08-03 02:39:44.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/sa1100_cerf.c 2004-03-31 17:15:12.000000000 +0200 +@@ -7,15 +7,25 @@ + */ + #include <linux/kernel.h> + #include <linux/sched.h> ++#include <linux/delay.h> + + #include <asm/hardware.h> + #include <asm/irq.h> +-#include "sa1100_generic.h" + +-#ifdef CONFIG_SA1100_CERF_CPLD +-#define CERF_SOCKET 0 ++#include <pcmcia/ss.h> ++#include <asm/arch/pcmcia.h> ++#include "sa1100_cerf.h" ++ ++/* ++ * Set this to zero to remove all the debug statements via ++ * dead code elimination ++ */ ++//#define DEBUGGING 1 ++ ++#if DEBUGGING ++static unsigned int pcmcia_debug = DEBUGGING; + #else +-#define CERF_SOCKET 1 ++#define pcmcia_debug 0 /* gcc will remove all the debug code for us */ + #endif + + static struct irqs { +@@ -23,122 +33,178 @@ + unsigned int gpio; + const char *str; + } irqs[] = { +- { IRQ_GPIO_CF_CD, GPIO_CF_CD, "CF_CD" }, +- { IRQ_GPIO_CF_BVD2, GPIO_CF_BVD2, "CF_BVD2" }, +- { IRQ_GPIO_CF_BVD1, GPIO_CF_BVD1, "CF_BVD1" } ++ { PCMCIA_IRQ_CF_CD, PCMCIA_GPIO_CF_CD_EDGE, "CF_CD" }, ++ { PCMCIA_IRQ_CF_BVD2, PCMCIA_GPIO_CF_BVD2_EDGE, "CF_BVD2" }, ++ { PCMCIA_IRQ_CF_BVD1, PCMCIA_GPIO_CF_BVD1_EDGE, "CF_BVD1" } + }; + ++static void cerf_pcmcia_reset( void) ++{ ++ int i; ++ ++ // Make sure SKTSEL is 0 (single slot) ++ set_GPIO_mode(54 | GPIO_OUT); ++ GPCR1 = GPIO_bit(54); ++ set_GPIO_mode(GPIO54_pSKTSEL_MD); ++ ++ PCMCIA_GPCR = PCMCIA_GPIO_CF_RESET_MASK; ++ mdelay(300); ++ ++ PCMCIA_GPSR = PCMCIA_GPIO_CF_RESET_MASK; ++ udelay(20); ++ ++ PCMCIA_GPCR = PCMCIA_GPIO_CF_RESET_MASK; ++ mdelay(50); ++ ++ for( i=0; i<10; i++) ++ { ++ if( cerf_pcmcia_level_ready()) break; ++ mdelay(100); ++ } ++} ++ + static int cerf_pcmcia_init(struct pcmcia_init *init) + { +- int i, res; ++ int i, res; + +- set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE ); ++ if( pcmcia_debug) ++ printk( KERN_INFO "cerf_pcmcia_init: enter\n"); + +- for (i = 0; i < ARRAY_SIZE(irqs); i++) { +- set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES); +- res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, +- irqs[i].str, NULL); +- if (res) +- goto irq_err; +- } ++ cerf_pcmcia_set_gpio_direction(); + +- return 2; ++ set_GPIO_IRQ_edge( PCMCIA_GPIO_CF_IRQ_EDGE, GPIO_FALLING_EDGE ); + +- irq_err: +- printk(KERN_ERR "%s: Request for IRQ%d failed\n", __FUNCTION__, irqs[i].irq); ++ for (i = 0; i < ARRAY_SIZE(irqs); i++) { + +- while (i--) +- free_irq(irqs[i].irq, NULL); ++ set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_BOTH_EDGES); + +- return -1; ++ res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, ++ irqs[i].str, NULL); ++ if (res) ++ goto irq_err; ++ } ++ ++ printk( KERN_INFO "PCMCIA for Cerf: OK\n"); ++ ++ return CERF_SOCKET+1; /* last socket used +1 */ ++ ++irq_err: ++ printk(KERN_ERR "%s: Request for IRQ%d failed\n", ++ __FUNCTION__, irqs[i].irq); ++ ++ while (i--) ++ free_irq(irqs[i].irq, NULL); ++ ++ return -1; + } + + static int cerf_pcmcia_shutdown(void) + { +- int i; ++ int i; ++ if( pcmcia_debug) ++ printk( KERN_INFO "cerf_pcmcia_shutdown: enter\n"); + +- for (i = 0; i < ARRAY_SIZE(irqs); i++) +- free_irq(irqs[i].irq, NULL); ++ for (i = 0; i < ARRAY_SIZE(irqs); i++) ++ free_irq(irqs[i].irq, NULL); + +- return 0; ++ return 0; + } + +-static int cerf_pcmcia_socket_state(struct pcmcia_state_array +- *state_array){ +- unsigned long levels; +- int i = CERF_SOCKET; ++static int cerf_pcmcia_socket_state(struct pcmcia_state_array *state_array) ++{ ++ int i = CERF_SOCKET; + +- if(state_array->size<2) return -1; ++ if( pcmcia_debug > 3) ++ printk( KERN_INFO "cerf_pcmcia_socket_state: i=%d, size=%d\n", ++ i, state_array->size); + +- levels=GPLR; ++ memset(state_array->state, 0, ++ (state_array->size)*sizeof(struct pcmcia_state)); + +- state_array->state[i].detect=((levels & GPIO_CF_CD)==0)?1:0; +- state_array->state[i].ready=(levels & GPIO_CF_IRQ)?1:0; +- state_array->state[i].bvd1=(levels & GPIO_CF_BVD1)?1:0; +- state_array->state[i].bvd2=(levels & GPIO_CF_BVD2)?1:0; +- state_array->state[i].wrprot=0; +- state_array->state[i].vs_3v=1; +- state_array->state[i].vs_Xv=0; ++ state_array->state[i].detect = cerf_pcmcia_level_detect(); ++ state_array->state[i].ready = cerf_pcmcia_level_ready(); ++ state_array->state[i].bvd1 = cerf_pcmcia_level_bvd1(); ++ state_array->state[i].bvd2 = cerf_pcmcia_level_bvd2(); ++ state_array->state[i].wrprot=0; ++ state_array->state[i].vs_3v=1; ++ state_array->state[i].vs_Xv=0; + +- return 1; ++ if( pcmcia_debug > 3) ++ printk( KERN_INFO "cerf_pcmcia_socket_state: " ++ "detect=%d ready=%d bvd1=%d bvd2=%d\n", ++ state_array->state[i].detect, ++ state_array->state[i].ready, ++ state_array->state[i].bvd1, ++ state_array->state[i].bvd2); ++ ++ return 1; + } + + static int cerf_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ + +- if(info->sock>1) return -1; ++ if( pcmcia_debug) ++ printk( KERN_INFO "cerf_pcmcia_get_irq_info: " ++ "sock=%d\n", info->sock); + +- if (info->sock == CERF_SOCKET) +- info->irq=IRQ_GPIO_CF_IRQ; ++ if(info->sock>1) return -1; + +- return 0; ++ if (info->sock == CERF_SOCKET) ++ info->irq=PCMCIA_IRQ_CF_IRQ; ++ ++ if( pcmcia_debug) ++ printk( KERN_INFO "cerf_pcmcia_get_irq_info: irq=%d\n",info->irq); ++ ++ return 0; + } + +-static int cerf_pcmcia_configure_socket(const struct pcmcia_configure +- *configure) ++static int cerf_pcmcia_configure_socket( unsigned int sock, socket_state_t *state) + { +- if(configure->sock>1) +- return -1; ++ if( pcmcia_debug) ++ printk( KERN_INFO "cerf_pcmcia_configure_socket:" ++ "sock=%d vcc=%d flags=%x\n", ++ sock, state->Vcc, state->flags); + +- if (configure->sock != CERF_SOCKET) +- return 0; ++ if(sock>1) ++ return -1; + +- switch(configure->vcc){ +- case 0: +- break; ++ if (sock != CERF_SOCKET) ++ return 0; + +- case 50: +- case 33: +-#ifdef CONFIG_SA1100_CERF_CPLD +- GPCR = GPIO_PWR_SHUTDOWN; ++ switch(state->Vcc){ ++ case 0: ++ break; ++ ++ case 50: ++ case 33: ++#if defined(CONFIG_SA1100_CERF_CPLD) ++ PCMCIA_GPDR |= PCMCIA_PWR_SHUTDOWN; ++ PCMCIA_GPCR |= PCMCIA_PWR_SHUTDOWN; + #endif +- break; ++ /* voltage selected automatically */ ++ break; + +- default: +- printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, +- configure->vcc); +- return -1; +- } ++ default: ++ printk(KERN_ERR "%s(): unrecognized Vcc %u\n", ++ __FUNCTION__, state->Vcc); ++ return -1; ++ } + +- if(configure->reset) +- { +-#ifdef CONFIG_SA1100_CERF_CPLD +- GPSR = GPIO_CF_RESET; +-#endif +- } +- else +- { +-#ifdef CONFIG_SA1100_CERF_CPLD +- GPCR = GPIO_CF_RESET; +-#endif +- } ++ if(state->flags&SS_RESET) ++ { ++ cerf_pcmcia_reset(); ++ } + +- return 0; ++ return 0; + } + ++#ifdef CONFIG_SA1100_CERF + static int cerf_pcmcia_socket_init(int sock) + { + int i; + ++ if( pcmcia_debug) ++ printk( KERN_INFO "cerf_pcmcia_socket_init: sock=%d\n",sock); ++ + if (sock == CERF_SOCKET) + for (i = 0; i < ARRAY_SIZE(irqs); i++) + set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_BOTH_EDGES); +@@ -150,21 +216,26 @@ + { + int i; + ++ if( pcmcia_debug) ++ printk( KERN_INFO "cerf_pcmcia_socket_suspend: sock=%d\n",sock); ++ + if (sock == CERF_SOCKET) + for (i = 0; i < ARRAY_SIZE(irqs); i++) + set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES); + + return 0; + } ++#endif + + struct pcmcia_low_level cerf_pcmcia_ops = { +- init: cerf_pcmcia_init, +- shutdown: cerf_pcmcia_shutdown, +- socket_state: cerf_pcmcia_socket_state, +- get_irq_info: cerf_pcmcia_get_irq_info, +- configure_socket: cerf_pcmcia_configure_socket, ++init: cerf_pcmcia_init, ++shutdown: cerf_pcmcia_shutdown, ++socket_state: cerf_pcmcia_socket_state, ++get_irq_info: cerf_pcmcia_get_irq_info, ++configure_socket: cerf_pcmcia_configure_socket, + +- socket_init: cerf_pcmcia_socket_init, +- socket_suspend: cerf_pcmcia_socket_suspend, ++#ifdef CONFIG_SA1100_CERF ++socket_init: cerf_pcmcia_socket_init, ++socket_suspend: cerf_pcmcia_socket_suspend, ++#endif + }; +- +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/sa1100_cerf.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,138 @@ ++/* ++ * drivers/pcmcia/cerf.h ++ * ++ * PCMCIA implementation routines for CerfBoard ++ * Based off the Assabet. ++ * ++ */ ++#ifndef _LINUX_PCMCIA_CERF_H ++#define _LINUX_PCMCIA_CERF_H ++ ++#include <linux/config.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/arch/pcmcia.h> ++ ++#ifdef CONFIG_PXA_CERF /* PXA */ ++ ++#define PCMCIA_GPCR GPCR0 ++#define PCMCIA_GPSR GPSR0 ++ ++#define PCMCIA_GPIO_CF_CD 14 ++#define PCMCIA_GPIO_CF_IRQ 13 ++#define PCMCIA_GPIO_CF_RESET 12 ++#ifdef CONFIG_PXA_CERF_PDA ++# define PCMCIA_GPIO_CF_BVD1 11 ++# define PCMCIA_GPIO_CF_BVD2 10 ++#elif defined( CONFIG_PXA_CERF_BOARD) ++# define PCMCIA_GPIO_CF_BVD1 32 ++# define PCMCIA_GPIO_CF_BVD2 10 ++#endif ++ ++#define PCMCIA_GPIO_CF_CD_MASK (GPIO_bit(PCMCIA_GPIO_CF_CD)) ++#define PCMCIA_GPIO_CF_IRQ_MASK (GPIO_bit(PCMCIA_GPIO_CF_IRQ)) ++#define PCMCIA_GPIO_CF_RESET_MASK (GPIO_bit(PCMCIA_GPIO_CF_RESET)) ++#define PCMCIA_GPIO_CF_BVD1_MASK (GPIO_bit(PCMCIA_GPIO_CF_BVD1)) ++#define PCMCIA_GPIO_CF_BVD2_MASK (GPIO_bit(PCMCIA_GPIO_CF_BVD2)) ++ ++#define PCMCIA_GPIO_CF_CD_EDGE PCMCIA_GPIO_CF_CD ++#define PCMCIA_GPIO_CF_IRQ_EDGE PCMCIA_GPIO_CF_IRQ ++#define PCMCIA_GPIO_CF_RESET_EDGE PCMCIA_GPIO_CF_RESET ++#define PCMCIA_GPIO_CF_BVD1_EDGE PCMCIA_GPIO_CF_BVD1 ++#define PCMCIA_GPIO_CF_BVD2_EDGE PCMCIA_GPIO_CF_BVD2 ++ ++#define PCMCIA_IRQ_CF_CD IRQ_GPIO(PCMCIA_GPIO_CF_CD) ++#define PCMCIA_IRQ_CF_IRQ IRQ_GPIO(PCMCIA_GPIO_CF_IRQ) ++#define PCMCIA_IRQ_CF_BVD1 IRQ_GPIO(PCMCIA_GPIO_CF_BVD1) ++#define PCMCIA_IRQ_CF_BVD2 IRQ_GPIO(PCMCIA_GPIO_CF_BVD2) ++ ++#define PCMCIA_PWR_SHUTDOWN 0 /* not needed */ ++#define CERF_SOCKET 0 ++ ++inline void cerf_pcmcia_set_gpio_direction(void) ++{ ++ GPDR(PCMCIA_GPIO_CF_CD) &= ~(PCMCIA_GPIO_CF_CD_MASK); ++ GPDR(PCMCIA_GPIO_CF_BVD1) &= ~(PCMCIA_GPIO_CF_BVD1_MASK); ++ GPDR(PCMCIA_GPIO_CF_BVD2) &= ~(PCMCIA_GPIO_CF_BVD2_MASK); ++ GPDR(PCMCIA_GPIO_CF_IRQ) &= ~(PCMCIA_GPIO_CF_IRQ_MASK); ++ GPDR(PCMCIA_GPIO_CF_RESET)|= (PCMCIA_GPIO_CF_RESET_MASK); ++} ++ ++inline int cerf_pcmcia_level_detect( void) ++{ ++ return ((GPLR(PCMCIA_GPIO_CF_CD)&PCMCIA_GPIO_CF_CD_MASK)==0)?1:0; ++} ++inline int cerf_pcmcia_level_ready( void) ++{ ++ return (GPLR(PCMCIA_GPIO_CF_IRQ)&PCMCIA_GPIO_CF_IRQ_MASK)?1:0; ++} ++inline int cerf_pcmcia_level_bvd1( void) ++{ ++ return (GPLR(PCMCIA_GPIO_CF_BVD1)&PCMCIA_GPIO_CF_BVD1_MASK)?1:0; ++} ++inline int cerf_pcmcia_level_bvd2( void) ++{ ++ return (GPLR(PCMCIA_GPIO_CF_BVD2)&PCMCIA_GPIO_CF_BVD2_MASK)?1:0; ++} ++ ++#elif defined(CONFIG_SA1100_CERF) /* SA1100 */ ++ ++#define PCMCIA_GPDR GPDR ++#define PCMCIA_GPCR GPCR ++#define PCMCIA_GPSR GPSR ++#define PCMCIA_GPLR GPLR ++ ++#define PCMCIA_GPIO_CF_CD_MASK GPIO_CF_CD ++#define PCMCIA_GPIO_CF_IRQ_MASK GPIO_CF_IRQ ++#define PCMCIA_GPIO_CF_RESET_MASK GPIO_CF_RESET ++#define PCMCIA_GPIO_CF_BVD1_MASK GPIO_CF_BVD1 ++#define PCMCIA_GPIO_CF_BVD2_MASK GPIO_CF_BVD2 ++ ++#define PCMCIA_GPIO_CF_CD_EDGE PCMCIA_GPIO_CF_CD_MASK ++#define PCMCIA_GPIO_CF_IRQ_EDGE PCMCIA_GPIO_CF_IRQ_MASK ++#define PCMCIA_GPIO_CF_RESET_EDGE PCMCIA_GPIO_CF_RESET_MASK ++#define PCMCIA_GPIO_CF_BVD1_EDGE PCMCIA_GPIO_CF_BVD1_MASK ++#define PCMCIA_GPIO_CF_BVD2_EDGE PCMCIA_GPIO_CF_BVD2_MASK ++ ++#define PCMCIA_IRQ_CF_CD IRQ_GPIO_CF_CD ++#define PCMCIA_IRQ_CF_IRQ IRQ_GPIO_CF_IRQ ++#define PCMCIA_IRQ_CF_BVD1 IRQ_GPIO_CF_BVD1 ++#define PCMCIA_IRQ_CF_BVD2 IRQ_GPIO_CF_BVD2 ++ ++#define PCMCIA_PWR_SHUTDOWN GPIO_PWR_SHUTDOWN ++ ++#ifdef CONFIG_SA1100_CERF_CPLD ++#define CERF_SOCKET 0 ++#else ++#define CERF_SOCKET 1 ++#endif ++ ++inline void cerf_pcmcia_set_gpio_direction(void) ++{ ++ PCMCIA_GPDR &= ~(PCMCIA_GPIO_CF_CD_MASK | ++ PCMCIA_GPIO_CF_BVD1_MASK | ++ PCMCIA_GPIO_CF_BVD2_MASK | ++ PCMCIA_GPIO_CF_IRQ_MASK); ++ PCMCIA_GPDR |= PCMCIA_GPIO_CF_RESET_MASK; ++} ++ ++inline int cerf_pcmcia_level_detect( void) ++{ ++ return ((PCMCIA_GPLR & PCMCIA_GPIO_CF_CD_MASK)==0)?1:0; ++} ++inline int cerf_pcmcia_level_ready( void) ++{ ++ return (PCMCIA_GPLR & PCMCIA_GPIO_CF_IRQ_MASK)?1:0; ++} ++inline int cerf_pcmcia_level_bvd1( void) ++{ ++ return (PCMCIA_GPLR & PCMCIA_GPIO_CF_BVD1_MASK)?1:0; ++} ++inline int cerf_pcmcia_level_bvd2( void) ++{ ++ return (PCMCIA_GPLR & PCMCIA_GPIO_CF_BVD2_MASK)?1:0; ++} ++ ++#endif ++ ++#endif +--- linux-2.4.25/drivers/sound/Config.in~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/sound/Config.in 2004-03-31 17:15:12.000000000 +0200 +@@ -239,6 +239,7 @@ + dep_tristate ' VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS + fi + dep_tristate ' Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS $CONFIG_ARCH_NETWINDER ++ dep_tristate ' Intel PXA250/210 AC97 audio' CONFIG_SOUND_PXA_AC97 $CONFIG_ARCH_PXA $CONFIG_SOUND + fi + + dep_tristate ' TV card (bt848) mixer support' CONFIG_SOUND_TVMIXER $CONFIG_SOUND $CONFIG_I2C +--- linux-2.4.25/drivers/sound/Makefile~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/sound/Makefile 2004-03-31 17:15:12.000000000 +0200 +@@ -11,7 +11,7 @@ + msnd.o opl3.o sb_common.o sequencer_syms.o \ + sound_core.o sound_syms.o uart401.o \ + nm256_audio.o ac97.o ac97_codec.o aci.o \ +- sa1100-audio.o ++ sa1100-audio.o pxa-audio.o pxa-ac97.o + + # Each configuration option enables a list of files. + +@@ -85,6 +85,7 @@ + obj-$(CONFIG_SOUND_SA1111_UDA1341) += sa1111-uda1341.o + obj-$(CONFIG_SOUND_SA1111_AC97) += sa1111-ac97.o ac97_codec.o + obj-$(CONFIG_SOUND_SA1100SSP) += sa1100ssp.o ++obj-$(CONFIG_SOUND_PXA_AC97)+= pxa-ac97.o pxa-audio.o ac97_codec.o + obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o + obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o + obj-$(CONFIG_SOUND_RME96XX) += rme96xx.o +--- linux-2.4.25/drivers/sound/ac97_codec.c~2.4.25-vrs2-pxa1.patch 2003-11-28 19:26:20.000000000 +0100 ++++ linux-2.4.25/drivers/sound/ac97_codec.c 2004-03-31 17:15:12.000000000 +0200 +@@ -155,6 +155,7 @@ + {0x45838308, "ESS Allegro ES1988", &null_ops}, + {0x49434511, "ICE1232", &null_ops}, /* I hope --jk */ + {0x4e534331, "National Semiconductor LM4549", &null_ops}, ++ {0x50534304, "Philips UCB1400", &default_ops}, + {0x53494c22, "Silicon Laboratory Si3036", &null_ops}, + {0x53494c23, "Silicon Laboratory Si3038", &null_ops}, + {0x545200FF, "TriTech TR?????", &tritech_m_ops}, +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/sound/pxa-ac97.c 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,370 @@ ++/* ++ * linux/drivers/sound/pxa-ac97.c -- AC97 interface for the Cotula chip ++ * ++ * Author: Nicolas Pitre ++ * Created: Aug 15, 2001 ++ * Copyright: MontaVista 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. ++ * ++ * AC97 GPIO Changes:- ++ * In order to read/write codec GPIO bits using AC97 link slot 12, ++ * all IO to AC97_GPIO_STATUS must be via the Xscale modem codec ++ * address space. ++ * Liam Girdwood <liam.girdwood@wolfsonmicro.com> ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/pci.h> ++#include <linux/completion.h> ++#include <linux/delay.h> ++#include <linux/poll.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++#include <linux/ac97_codec.h> ++ ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <asm/semaphore.h> ++#include <asm/dma.h> ++ ++#include "pxa-audio.h" ++ ++static struct completion CAR_completion; ++static int waitingForMask; ++static DECLARE_MUTEX(CAR_mutex); ++ ++static u16 pxa_ac97_read(struct ac97_codec *codec, u8 reg) ++{ ++ u16 val = -1; ++ ++ down(&CAR_mutex); ++ if (!(CAR & CAR_CAIP)) { ++ volatile u32 *reg_addr; ++ ++ // if we are reading the GPIO status then this is cached ++ // in hardware so we don't need to read over the link. ++ if (reg == AC97_GPIO_STATUS) { ++ reg_addr = (u32 *)&PMC_REG_BASE + (reg >> 1); ++ val = *reg_addr; ++ return val; ++ } ++ ++ reg_addr = (u32 *)&PAC_REG_BASE + (reg >> 1); ++ ++ waitingForMask=GSR_SDONE; ++ ++ init_completion(&CAR_completion); ++ (void)*reg_addr; //start read access across the ac97 link ++ wait_for_completion(&CAR_completion); ++ ++ if (GSR & GSR_RDCS) { ++ GSR |= GSR_RDCS; //write a 1 to clear ++ printk(KERN_CRIT __FUNCTION__": read codec register timeout.\n"); ++ } ++ ++ init_completion(&CAR_completion); ++ val = *reg_addr; //valid data now but we've just started another cycle... ++ wait_for_completion(&CAR_completion); ++ ++ } else { ++ printk(KERN_CRIT __FUNCTION__": CAR_CAIP already set\n"); ++ } ++ up(&CAR_mutex); ++ //printk("%s(0x%02x) = 0x%04x\n", __FUNCTION__, reg, val); ++ return val; ++} ++ ++static void pxa_ac97_write(struct ac97_codec *codec, u8 reg, u16 val) ++{ ++ down(&CAR_mutex); ++ if (!(CAR & CAR_CAIP)) { ++ volatile u32 *reg_addr; ++ ++ // if we are writing to the codec GPIO using slot 12 ++ // then we have to write to the modem register space ++ if (reg == AC97_GPIO_STATUS) { ++ reg_addr = (u32 *)&PMC_REG_BASE + (reg >> 1); ++ *reg_addr = val; ++ return; ++ } ++ ++ reg_addr = (u32 *)&PAC_REG_BASE + (reg >> 1); ++ ++ waitingForMask=GSR_CDONE; ++ init_completion(&CAR_completion); ++ *reg_addr = val; ++ wait_for_completion(&CAR_completion); ++ } else { ++ printk(KERN_CRIT __FUNCTION__": CAR_CAIP already set\n"); ++ } ++ up(&CAR_mutex); ++ //printk("%s(0x%02x, 0x%04x)\n", __FUNCTION__, reg, val); ++} ++ ++static void pxa_ac97_irq(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ int gsr = GSR; ++ GSR = gsr & (GSR_SDONE|GSR_CDONE); //write a 1 to clear ++ if (gsr & waitingForMask) ++ { ++ complete(&CAR_completion); ++ } ++} ++ ++static struct ac97_codec pxa_ac97_codec = { ++ codec_read: pxa_ac97_read, ++ codec_write: pxa_ac97_write, ++}; ++ ++static DECLARE_MUTEX(pxa_ac97_mutex); ++static int pxa_ac97_refcount; ++ ++int pxa_ac97_get(struct ac97_codec **codec) ++{ ++ int ret; ++ ++ *codec = NULL; ++ down(&pxa_ac97_mutex); ++ ++ if (!pxa_ac97_refcount) { ++ ret = request_irq(IRQ_AC97, pxa_ac97_irq, 0, "AC97", NULL); ++ if (ret) ++ return ret; ++ ++ CKEN |= CKEN2_AC97; ++ set_GPIO_mode(GPIO31_SYNC_AC97_MD); ++ set_GPIO_mode(GPIO30_SDATA_OUT_AC97_MD); ++ set_GPIO_mode(GPIO28_BITCLK_AC97_MD); ++ set_GPIO_mode(GPIO29_SDATA_IN_AC97_MD); ++ ++ GCR = 0; ++ udelay(10); ++ GCR = GCR_COLD_RST|GCR_CDONE_IE|GCR_SDONE_IE; ++ while (!(GSR & GSR_PCR)) { ++ schedule(); ++ } ++ ++ ret = ac97_probe_codec(&pxa_ac97_codec); ++ if (ret != 1) { ++ free_irq(IRQ_AC97, NULL); ++ GCR = GCR_ACLINK_OFF; ++ CKEN &= ~CKEN2_AC97; ++ return ret; ++ } ++ ++ // need little hack for UCB1400 (should be moved elsewhere) ++ pxa_ac97_write(&pxa_ac97_codec,AC97_EXTENDED_STATUS,1); ++ //pxa_ac97_write(&pxa_ac97_codec, 0x6a, 0x1ff7); ++ pxa_ac97_write(&pxa_ac97_codec, 0x6a, 0x0050); ++ pxa_ac97_write(&pxa_ac97_codec, 0x6c, 0x0030); ++ } ++ ++ pxa_ac97_refcount++; ++ up(&pxa_ac97_mutex); ++ *codec = &pxa_ac97_codec; ++ return 0; ++} ++ ++void pxa_ac97_put(void) ++{ ++ down(&pxa_ac97_mutex); ++ pxa_ac97_refcount--; ++ if (!pxa_ac97_refcount) { ++ GCR = GCR_ACLINK_OFF; ++ CKEN &= ~CKEN2_AC97; ++ free_irq(IRQ_AC97, NULL); ++ } ++ up(&pxa_ac97_mutex); ++} ++ ++EXPORT_SYMBOL(pxa_ac97_get); ++EXPORT_SYMBOL(pxa_ac97_put); ++ ++ ++/* ++ * Audio Mixer stuff ++ */ ++ ++static audio_state_t ac97_audio_state; ++static audio_stream_t ac97_audio_in; ++ ++static int mixer_ioctl( struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ int ret, val; ++ ++ ret = pxa_ac97_codec.mixer_ioctl(&pxa_ac97_codec, cmd, arg); ++ if (ret) ++ return ret; ++ ++ /* We must snoop for some commands to provide our own extra processing */ ++ switch (cmd) { ++ case SOUND_MIXER_WRITE_RECSRC: ++ /* ++ * According to the PXA250 spec, mic-in should use different ++ * DRCMR and different AC97 FIFO. ++ * Unfortunately current UCB1400 versions (up to ver 2A) don't ++ * produce slot 6 for the audio input frame, therefore the PXA ++ * AC97 mic-in FIFO is always starved. ++ */ ++#if 0 ++ ret = get_user(val, (int *)arg); ++ if (ret) ++ return ret; ++ pxa_audio_clear_buf(&ac97_audio_in); ++ *ac97_audio_in.drcmr = 0; ++ if (val & (1 << SOUND_MIXER_MIC)) { ++ ac97_audio_in.dcmd = DCMD_RXMCDR; ++ ac97_audio_in.drcmr = &DRCMRRXMCDR; ++ ac97_audio_in.dev_addr = __PREG(MCDR); ++ } else { ++ ac97_audio_in.dcmd = DCMD_RXPCDR; ++ ac97_audio_in.drcmr = &DRCMRRXPCDR; ++ ac97_audio_in.dev_addr = __PREG(PCDR); ++ } ++ if (ac97_audio_state.rd_ref) ++ *ac97_audio_in.drcmr = ++ ac97_audio_in.dma_ch | DRCMR_MAPVLD; ++#endif ++ break; ++ } ++ return 0; ++} ++ ++static struct file_operations mixer_fops = { ++ ioctl: mixer_ioctl, ++ llseek: no_llseek, ++ owner: THIS_MODULE ++}; ++ ++/* ++ * AC97 codec ioctls ++ */ ++ ++static int codec_adc_rate = 48000; ++static int codec_dac_rate = 48000; ++ ++static int ac97_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ int ret; ++ long val; ++ ++ switch(cmd) { ++ case SNDCTL_DSP_STEREO: ++ ret = get_user(val, (int *) arg); ++ if (ret) ++ return ret; ++ /* FIXME: do we support mono? */ ++ ret = (val == 0) ? -EINVAL : 1; ++ return put_user(ret, (int *) arg); ++ ++ case SNDCTL_DSP_CHANNELS: ++ case SOUND_PCM_READ_CHANNELS: ++ /* FIXME: do we support mono? */ ++ return put_user(2, (long *) arg); ++ ++ case SNDCTL_DSP_SPEED: ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ if (file->f_mode & FMODE_READ) ++ codec_adc_rate = ac97_set_adc_rate(&pxa_ac97_codec, val); ++ if (file->f_mode & FMODE_WRITE) ++ codec_dac_rate = ac97_set_dac_rate(&pxa_ac97_codec, val); ++ /* fall through */ ++ ++ case SOUND_PCM_READ_RATE: ++ if (file->f_mode & FMODE_READ) ++ val = codec_adc_rate; ++ if (file->f_mode & FMODE_WRITE) ++ val = codec_dac_rate; ++ return put_user(val, (long *) arg); ++ ++ case SNDCTL_DSP_SETFMT: ++ case SNDCTL_DSP_GETFMTS: ++ /* FIXME: can we do other fmts? */ ++ 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 0; ++} ++ ++ ++/* ++ * Audio stuff ++ */ ++ ++static audio_stream_t ac97_audio_out = { ++ name: "AC97 audio out", ++ dcmd: DCMD_TXPCDR, ++ drcmr: &DRCMRTXPCDR, ++ dev_addr: __PREG(PCDR), ++}; ++ ++static audio_stream_t ac97_audio_in = { ++ name: "AC97 audio in", ++ dcmd: DCMD_RXPCDR, ++ drcmr: &DRCMRRXPCDR, ++ dev_addr: __PREG(PCDR), ++}; ++ ++static audio_state_t ac97_audio_state = { ++ output_stream: &ac97_audio_out, ++ input_stream: &ac97_audio_in, ++ client_ioctl: ac97_ioctl, ++ sem: __MUTEX_INITIALIZER(ac97_audio_state.sem), ++}; ++ ++static int ac97_audio_open(struct inode *inode, struct file *file) ++{ ++ return pxa_audio_attach(inode, file, &ac97_audio_state); ++} ++ ++/* ++ * Missing fields of this structure will be patched with the call ++ * to pxa_audio_attach(). ++ */ ++ ++static struct file_operations ac97_audio_fops = { ++ open: ac97_audio_open, ++ owner: THIS_MODULE ++}; ++ ++ ++static int __init pxa_ac97_init(void) ++{ ++ int ret; ++ struct ac97_codec *dummy; ++ ++ ret = pxa_ac97_get(&dummy); ++ if (ret) ++ return ret; ++ ++ ac97_audio_state.dev_dsp = register_sound_dsp(&ac97_audio_fops, -1); ++ pxa_ac97_codec.dev_mixer = register_sound_mixer(&mixer_fops, -1); ++ ++ return 0; ++} ++ ++static void __exit pxa_ac97_exit(void) ++{ ++ unregister_sound_dsp(ac97_audio_state.dev_dsp); ++ unregister_sound_mixer(pxa_ac97_codec.dev_mixer); ++ pxa_ac97_put(); ++} ++ ++ ++module_init(pxa_ac97_init); ++module_exit(pxa_ac97_exit); ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/sound/pxa-audio.c 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,853 @@ ++/* ++ * linux/drivers/sound/pxa-audio.c -- audio interface for the Cotula chip ++ * ++ * Author: Nicolas Pitre ++ * Created: Aug 15, 2001 ++ * Copyright: MontaVista 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 <linux/init.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/pci.h> ++#include <linux/poll.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++ ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <asm/semaphore.h> ++#include <asm/dma.h> ++ ++#include "pxa-audio.h" ++ ++ ++#define AUDIO_NBFRAGS_DEFAULT 8 ++#define AUDIO_FRAGSIZE_DEFAULT 8192 ++ ++#define MAX_DMA_SIZE 4096 ++#define DMA_DESC_SIZE sizeof(pxa_dma_desc) ++ ++ ++/* ++ * This function frees all buffers ++ */ ++#define audio_clear_buf pxa_audio_clear_buf ++ ++void pxa_audio_clear_buf(audio_stream_t * s) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ int frag; ++ ++ if (!s->buffers) ++ return; ++ ++ /* Ensure DMA isn't running */ ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ add_wait_queue(&s->stop_wq, &wait); ++ DCSR(s->dma_ch) = DCSR_STOPIRQEN; ++ schedule(); ++ remove_wait_queue(&s->stop_wq, &wait); ++ ++ /* free DMA buffers */ ++ for (frag = 0; frag < s->nbfrags; frag++) { ++ audio_buf_t *b = &s->buffers[frag]; ++ if (!b->master) ++ continue; ++ consistent_free(b->data, b->master, b->dma_desc->dsadr); ++ } ++ ++ /* free descriptor ring */ ++ if (s->buffers->dma_desc) ++ consistent_free(s->buffers->dma_desc, ++ s->nbfrags * s->descs_per_frag * DMA_DESC_SIZE, ++ s->dma_desc_phys); ++ ++ /* free buffer structure array */ ++ kfree(s->buffers); ++ s->buffers = NULL; ++} ++ ++/* ++ * This function allocates the DMA descriptor array and buffer data space ++ * according to the current number of fragments and fragment size. ++ */ ++static int audio_setup_buf(audio_stream_t * s) ++{ ++ pxa_dma_desc *dma_desc; ++ dma_addr_t dma_desc_phys; ++ int nb_desc, frag, i, buf_size = 0; ++ char *dma_buf = NULL; ++ dma_addr_t dma_buf_phys = 0; ++ ++ if (s->buffers) ++ return -EBUSY; ++ ++ /* Our buffer structure array */ ++ s->buffers = kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL); ++ if (!s->buffers) ++ goto err; ++ memzero(s->buffers, sizeof(audio_buf_t) * s->nbfrags); ++ ++ /* ++ * Our DMA descriptor array: ++ * for Each fragment we have one checkpoint descriptor plus one ++ * descriptor per MAX_DMA_SIZE byte data blocks. ++ */ ++ nb_desc = (1 + (s->fragsize + MAX_DMA_SIZE - 1)/MAX_DMA_SIZE) * s->nbfrags; ++ dma_desc = consistent_alloc(GFP_KERNEL, ++ nb_desc * DMA_DESC_SIZE, ++ &dma_desc_phys, ++ 0); ++ if (!dma_desc) ++ goto err; ++ s->descs_per_frag = nb_desc / s->nbfrags; ++ s->buffers->dma_desc = dma_desc; ++ s->dma_desc_phys = dma_desc_phys; ++ for (i = 0; i < nb_desc - 1; i++) ++ dma_desc[i].ddadr = dma_desc_phys + (i + 1) * DMA_DESC_SIZE; ++ dma_desc[i].ddadr = dma_desc_phys; ++ ++ /* Our actual DMA buffers */ ++ 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'll try allocating smaller buffers. ++ */ ++ if (!buf_size) { ++ buf_size = (s->nbfrags - frag) * s->fragsize; ++ do { ++ dma_buf = consistent_alloc(GFP_KERNEL, ++ buf_size, ++ &dma_buf_phys, ++ 0); ++ if (!dma_buf) ++ buf_size -= s->fragsize; ++ } while (!dma_buf && buf_size); ++ if (!dma_buf) ++ goto err; ++ b->master = buf_size; ++ memzero(dma_buf, buf_size); ++ } ++ ++ /* ++ * Set up our checkpoint descriptor. Since the count ++ * is always zero, we'll abuse the dsadr and dtadr fields ++ * just in case this one is picked up by the hardware ++ * while processing SOUND_DSP_GETPTR. ++ */ ++ dma_desc->dsadr = dma_buf_phys; ++ dma_desc->dtadr = dma_buf_phys; ++ dma_desc->dcmd = DCMD_ENDIRQEN; ++ if (s->output && !s->mapped) ++ dma_desc->ddadr |= DDADR_STOP; ++ b->dma_desc = dma_desc++; ++ ++ /* set up the actual data descriptors */ ++ for (i = 0; (i * MAX_DMA_SIZE) < s->fragsize; i++) { ++ dma_desc[i].dsadr = (s->output) ? ++ (dma_buf_phys + i*MAX_DMA_SIZE) : s->dev_addr; ++ dma_desc[i].dtadr = (s->output) ? ++ s->dev_addr : (dma_buf_phys + i*MAX_DMA_SIZE); ++ dma_desc[i].dcmd = s->dcmd | ++ ((s->fragsize < MAX_DMA_SIZE) ? ++ s->fragsize : MAX_DMA_SIZE); ++ } ++ dma_desc += i; ++ ++ /* handle buffer pointers */ ++ b->data = dma_buf; ++ dma_buf += s->fragsize; ++ dma_buf_phys += s->fragsize; ++ buf_size -= s->fragsize; ++ } ++ ++ s->usr_frag = s->dma_frag = 0; ++ s->bytecount = 0; ++ s->fragcount = 0; ++ sema_init(&s->sem, (s->output) ? s->nbfrags : 0); ++ return 0; ++ ++err: ++ printk("pxa-audio: unable to allocate audio memory\n "); ++ audio_clear_buf(s); ++ return -ENOMEM; ++} ++ ++/* ++ * Our DMA interrupt handler ++ */ ++static void audio_dma_irq(int ch, void *dev_id, struct pt_regs *regs) ++{ ++ audio_stream_t *s = dev_id; ++ u_int dcsr; ++ ++ dcsr = DCSR(ch); ++ DCSR(ch) = dcsr & ~DCSR_STOPIRQEN; ++ ++ if (!s->buffers) { ++ printk("AC97 DMA: wow... received IRQ for channel %d but no buffer exists\n", ch); ++ return; ++ } ++ ++ if (dcsr & DCSR_BUSERR) ++ printk("AC97 DMA: bus error interrupt on channel %d\n", ch); ++ ++ if (dcsr & DCSR_ENDINTR) { ++ u_long cur_dma_desc; ++ u_int cur_dma_frag; ++ ++ /* ++ * Find out which DMA desc is current. Note that DDADR ++ * points to the next desc, not the current one. ++ */ ++ cur_dma_desc = DDADR(ch) - s->dma_desc_phys - DMA_DESC_SIZE; ++ ++ /* ++ * Let the compiler nicely optimize constant divisors into ++ * multiplications for the common cases which is much faster. ++ * Common cases: x = 1 + (1 << y) for y = [0..3] ++ */ ++ switch (s->descs_per_frag) { ++ case 2: cur_dma_frag = cur_dma_desc / (2*DMA_DESC_SIZE); break; ++ case 3: cur_dma_frag = cur_dma_desc / (3*DMA_DESC_SIZE); break; ++ case 5: cur_dma_frag = cur_dma_desc / (5*DMA_DESC_SIZE); break; ++ case 9: cur_dma_frag = cur_dma_desc / (9*DMA_DESC_SIZE); break; ++ default: cur_dma_frag = ++ cur_dma_desc / (s->descs_per_frag * DMA_DESC_SIZE); ++ } ++ ++ /* Account for possible wrap back of cur_dma_desc above */ ++ if (cur_dma_frag >= s->nbfrags) ++ cur_dma_frag = s->nbfrags - 1; ++ ++ while (s->dma_frag != cur_dma_frag) { ++ if (!s->mapped) { ++ /* ++ * This fragment is done - set the checkpoint ++ * descriptor to STOP until it is gets ++ * processed by the read or write function. ++ */ ++ s->buffers[s->dma_frag].dma_desc->ddadr |= DDADR_STOP; ++ up(&s->sem); ++ } ++ if (++s->dma_frag >= s->nbfrags) ++ s->dma_frag = 0; ++ ++ /* Accounting */ ++ s->bytecount += s->fragsize; ++ s->fragcount++; ++ } ++ ++ /* ... and for polling processes */ ++ wake_up(&s->frag_wq); ++ } ++ ++ if ((dcsr & DCSR_STOPIRQEN) && (dcsr & DCSR_STOPSTATE)) ++ wake_up(&s->stop_wq); ++} ++ ++/* ++ * Validate and sets up buffer fragments, etc. ++ */ ++static int audio_set_fragments(audio_stream_t *s, int val) ++{ ++ if (s->mapped || DCSR(s->dma_ch) & DCSR_RUN) ++ return -EBUSY; ++ if (s->buffers) ++ audio_clear_buf(s); ++ s->nbfrags = (val >> 16) & 0x7FFF; ++ val &= 0xffff; ++ if (val < 5) ++ val = 5; ++ if (val > 15) ++ val = 15; ++ s->fragsize = 1 << val; ++ if (s->nbfrags < 2) ++ s->nbfrags = 2; ++ if (s->nbfrags * s->fragsize > 256 * 1024) ++ s->nbfrags = 256 * 1024 / s->fragsize; ++ if (audio_setup_buf(s)) ++ return -ENOMEM; ++ return val|(s->nbfrags << 16); ++} ++ ++ ++/* ++ * The fops functions ++ */ ++ ++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; ++ ++ 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->buffers[s->usr_frag]; ++ ++ /* Grab a fragment */ ++ if (file->f_flags & O_NONBLOCK) { ++ ret = -EAGAIN; ++ if (down_trylock(&s->sem)) ++ break; ++ } else { ++ ret = -ERESTARTSYS; ++ if (down_interruptible(&s->sem)) ++ break; ++ } ++ ++ /* Feed the current buffer */ ++ chunksize = s->fragsize - b->offset; ++ if (chunksize > count) ++ chunksize = count; ++ if (copy_from_user(b->data + b->offset, buffer, chunksize)) { ++ up(&s->sem); ++ return -EFAULT; ++ } ++ b->offset += chunksize; ++ buffer += chunksize; ++ count -= chunksize; ++ if (b->offset < s->fragsize) { ++ up(&s->sem); ++ break; ++ } ++ ++ /* ++ * Activate DMA on current buffer. ++ * We unlock this fragment's checkpoint descriptor and ++ * kick DMA if it is idle. Using checkpoint descriptors ++ * allows for control operations without the need for ++ * stopping the DMA channel if it is already running. ++ */ ++ b->offset = 0; ++ b->dma_desc->ddadr &= ~DDADR_STOP; ++ if (DCSR(s->dma_ch) & DCSR_STOPSTATE) { ++ DDADR(s->dma_ch) = b->dma_desc->ddadr; ++ DCSR(s->dma_ch) = DCSR_RUN; ++ } ++ ++ /* move the index to the next fragment */ ++ if (++s->usr_frag >= s->nbfrags) ++ s->usr_frag = 0; ++ } ++ ++ if ((buffer - buffer0)) ++ ret = buffer - buffer0; ++ return ret; ++} ++ ++ ++static int audio_read(struct file *file, char *buffer, ++ size_t count, loff_t * ppos) ++{ ++ char *buffer0 = buffer; ++ audio_state_t *state = file->private_data; ++ audio_stream_t *s = state->input_stream; ++ int chunksize, ret = 0; ++ ++ 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->buffers[s->usr_frag]; ++ ++ /* prime DMA */ ++ if (DCSR(s->dma_ch) & DCSR_STOPSTATE) { ++ DDADR(s->dma_ch) = ++ s->buffers[s->dma_frag].dma_desc->ddadr; ++ DCSR(s->dma_ch) = DCSR_RUN; ++ } ++ ++ /* Wait for a buffer to become full */ ++ if (file->f_flags & O_NONBLOCK) { ++ ret = -EAGAIN; ++ if (down_trylock(&s->sem)) ++ break; ++ } else { ++ ret = -ERESTARTSYS; ++ if (down_interruptible(&s->sem)) ++ break; ++ } ++ ++ /* Grab data from current buffer */ ++ chunksize = s->fragsize - b->offset; ++ if (chunksize > count) ++ chunksize = count; ++ if (copy_to_user(buffer, b->data + b->offset, chunksize)) { ++ up(&s->sem); ++ return -EFAULT; ++ } ++ b->offset += chunksize; ++ buffer += chunksize; ++ count -= chunksize; ++ if (b->offset < s->fragsize) { ++ up(&s->sem); ++ break; ++ } ++ ++ /* ++ * Make this buffer available for DMA again. ++ * We unlock this fragment's checkpoint descriptor and ++ * kick DMA if it is idle. Using checkpoint descriptors ++ * allows for control operations without the need for ++ * stopping the DMA channel if it is already running. ++ */ ++ b->offset = 0; ++ b->dma_desc->ddadr &= ~DDADR_STOP; ++ ++ /* move the index to the next fragment */ ++ if (++s->usr_frag >= s->nbfrags) ++ s->usr_frag = 0; ++ } ++ ++ if ((buffer - buffer0)) ++ ret = buffer - buffer0; ++ return ret; ++} ++ ++ ++static int audio_sync(struct file *file) ++{ ++ audio_state_t *state = file->private_data; ++ audio_stream_t *s = state->output_stream; ++ audio_buf_t *b; ++ pxa_dma_desc *final_desc; ++ u_long dcmd_save = 0; ++ DECLARE_WAITQUEUE(wait, current); ++ ++ 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. ++ */ ++ final_desc = NULL; ++ b = &s->buffers[s->usr_frag]; ++ if (b->offset &= ~3) { ++ final_desc = &b->dma_desc[1 + b->offset/MAX_DMA_SIZE]; ++ b->offset &= (MAX_DMA_SIZE-1); ++ dcmd_save = final_desc->dcmd; ++ final_desc->dcmd = b->offset | s->dcmd | DCMD_ENDIRQEN; ++ final_desc->ddadr |= DDADR_STOP; ++ b->offset = 0; ++ b->dma_desc->ddadr &= ~DDADR_STOP; ++ if (DCSR(s->dma_ch) & DCSR_STOPSTATE) { ++ DDADR(s->dma_ch) = b->dma_desc->ddadr; ++ DCSR(s->dma_ch) = DCSR_RUN; ++ } ++ } ++ ++ /* Wait for DMA to complete. */ ++ set_current_state(TASK_INTERRUPTIBLE); ++#if 0 ++ /* ++ * The STOPSTATE IRQ never seem to occur if DCSR_STOPIRQEN is set ++ * along wotj DCSR_RUN. Silicon bug? ++ */ ++ add_wait_queue(&s->stop_wq, &wait); ++ DCSR(s->dma_ch) |= DCSR_STOPIRQEN; ++ schedule(); ++#else ++ add_wait_queue(&s->frag_wq, &wait); ++ while ((DCSR(s->dma_ch) & DCSR_RUN) && !signal_pending(current)) { ++ schedule(); ++ set_current_state(TASK_INTERRUPTIBLE); ++ } ++#endif ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&s->frag_wq, &wait); ++ ++ /* Restore the descriptor chain. */ ++ if (final_desc) { ++ final_desc->dcmd = dcmd_save; ++ final_desc->ddadr &= ~DDADR_STOP; ++ b->dma_desc->ddadr |= DDADR_STOP; ++ } ++ return 0; ++} ++ ++ ++static unsigned int audio_poll(struct file *file, ++ struct poll_table_struct *wait) ++{ ++ audio_state_t *state = file->private_data; ++ audio_stream_t *is = state->input_stream; ++ audio_stream_t *os = state->output_stream; ++ unsigned int mask = 0; ++ ++ if (file->f_mode & FMODE_READ) { ++ /* Start audio input if not already active */ ++ if (!is->buffers && audio_setup_buf(is)) ++ return -ENOMEM; ++ if (DCSR(is->dma_ch) & DCSR_STOPSTATE) { ++ DDADR(is->dma_ch) = ++ is->buffers[is->dma_frag].dma_desc->ddadr; ++ DCSR(is->dma_ch) = DCSR_RUN; ++ } ++ poll_wait(file, &is->frag_wq, wait); ++ } ++ ++ if (file->f_mode & FMODE_WRITE) { ++ if (!os->buffers && audio_setup_buf(os)) ++ return -ENOMEM; ++ poll_wait(file, &os->frag_wq, wait); ++ } ++ ++ if (file->f_mode & FMODE_READ) ++ if (( is->mapped && is->bytecount > 0) || ++ (!is->mapped && atomic_read(&is->sem.count) > 0)) ++ mask |= POLLIN | POLLRDNORM; ++ ++ if (file->f_mode & FMODE_WRITE) ++ if (( os->mapped && os->bytecount > 0) || ++ (!os->mapped && atomic_read(&os->sem.count) > 0)) ++ mask |= POLLOUT | POLLWRNORM; ++ ++ return mask; ++} ++ ++ ++static int audio_ioctl( struct inode *inode, struct file *file, ++ uint cmd, ulong arg) ++{ ++ audio_state_t *state = file->private_data; ++ audio_stream_t *os = state->output_stream; ++ audio_stream_t *is = state->input_stream; ++ long val; ++ ++ 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 && DCSR(is->dma_ch) & DCSR_RUN) ++ val |= PCM_ENABLE_INPUT; ++ if (file->f_mode & FMODE_WRITE && DCSR(os->dma_ch) & DCSR_RUN) ++ 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->buffers && audio_setup_buf(is)) ++ return -ENOMEM; ++ if (!(DCSR(is->dma_ch) & DCSR_RUN)) { ++ audio_buf_t *b = &is->buffers[is->dma_frag]; ++ DDADR(is->dma_ch) = b->dma_desc->ddadr; ++ DCSR(is->dma_ch) = DCSR_RUN; ++ } ++ } else { ++ DCSR(is->dma_ch) = 0; ++ } ++ } ++ if (file->f_mode & FMODE_WRITE) { ++ if (val & PCM_ENABLE_OUTPUT) { ++ if (!os->buffers && audio_setup_buf(os)) ++ return -ENOMEM; ++ if (!(DCSR(os->dma_ch) & DCSR_RUN)) { ++ audio_buf_t *b = &os->buffers[os->dma_frag]; ++ DDADR(os->dma_ch) = b->dma_desc->ddadr; ++ DCSR(os->dma_ch) = DCSR_RUN; ++ } ++ } else { ++ DCSR(os->dma_ch) = 0; ++ } ++ } ++ return 0; ++ ++ case SNDCTL_DSP_GETOSPACE: ++ case SNDCTL_DSP_GETISPACE: ++ { ++ audio_buf_info inf = { 0, }; ++ audio_stream_t *s = (cmd == SNDCTL_DSP_GETOSPACE) ? os : is; ++ ++ if ((s == is && !(file->f_mode & FMODE_READ)) || ++ (s == os && !(file->f_mode & FMODE_WRITE))) ++ return -EINVAL; ++ if (!s->buffers && audio_setup_buf(s)) ++ return -ENOMEM; ++ inf.bytes = atomic_read(&s->sem.count) * s->fragsize; ++ inf.bytes -= s->buffers[s->usr_frag].offset; ++ inf.fragments = inf.bytes / s->fragsize; ++ inf.fragsize = s->fragsize; ++ inf.fragstotal = s->nbfrags; ++ return copy_to_user((void *)arg, &inf, sizeof(inf)); ++ } ++ ++ case SNDCTL_DSP_GETOPTR: ++ case SNDCTL_DSP_GETIPTR: ++ { ++ count_info inf = { 0, }; ++ audio_stream_t *s = (cmd == SNDCTL_DSP_GETOPTR) ? os : is; ++ 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 (DCSR(s->dma_ch) & DCSR_RUN) { ++ audio_buf_t *b; ++ save_flags_cli(flags); ++ ptr = (s->output) ? DSADR(s->dma_ch) : DTADR(s->dma_ch); ++ b = &s->buffers[s->dma_frag]; ++ offset = ptr - b->dma_desc->dsadr; ++ if (offset >= s->fragsize) ++ offset = s->fragsize - 4; ++ } else { ++ save_flags(flags); ++ offset = 0; ++ } ++ inf.ptr = s->dma_frag * s->fragsize + offset; ++ bytecount = s->bytecount + offset; ++ s->bytecount = -offset; ++ 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_NONBLOCK: ++ file->f_flags |= O_NONBLOCK; ++ return 0; ++ ++ case SNDCTL_DSP_RESET: ++ if (file->f_mode & FMODE_WRITE) ++ audio_clear_buf(os); ++ if (file->f_mode & FMODE_READ) ++ audio_clear_buf(is); ++ return 0; ++ ++ default: ++ return state->client_ioctl(inode, file, cmd, arg); ++ } ++ ++ return 0; ++} ++ ++ ++static int audio_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ audio_state_t *state = 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_desc->dsadr, ++ buf->master, vma->vm_page_prot); ++ if (ret) ++ return ret; ++ vma_addr += buf->master; ++ } ++ for (i = 0; i < s->nbfrags; i++) ++ s->buffers[i].dma_desc->ddadr &= ~DDADR_STOP; ++ s->mapped = 1; ++ return 0; ++} ++ ++ ++static int audio_release(struct inode *inode, struct file *file) ++{ ++ audio_state_t *state = file->private_data; ++ ++ down(&state->sem); ++ ++ if (file->f_mode & FMODE_READ) { ++ audio_clear_buf(state->input_stream); ++ *state->input_stream->drcmr = 0; ++ pxa_free_dma(state->input_stream->dma_ch); ++ state->rd_ref = 0; ++ } ++ ++ if (file->f_mode & FMODE_WRITE) { ++ audio_sync(file); ++ audio_clear_buf(state->output_stream); ++ *state->output_stream->drcmr = 0; ++ pxa_free_dma(state->output_stream->dma_ch); ++ state->wr_ref = 0; ++ } ++ ++ up(&state->sem); ++ return 0; ++} ++ ++ ++int pxa_audio_attach(struct inode *inode, struct file *file, ++ audio_state_t *state) ++{ ++ audio_stream_t *is = state->input_stream; ++ audio_stream_t *os = state->output_stream; ++ int err; ++ ++ down(&state->sem); ++ ++ /* access control */ ++ err = -ENODEV; ++ if ((file->f_mode & FMODE_WRITE) && !os) ++ goto out; ++ if ((file->f_mode & FMODE_READ) && !is) ++ 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; ++ ++ /* request DMA channels */ ++ if (file->f_mode & FMODE_WRITE) { ++ err = pxa_request_dma(os->name, DMA_PRIO_LOW, ++ audio_dma_irq, os); ++ if (err < 0) ++ goto out; ++ os->dma_ch = err; ++ } ++ if (file->f_mode & FMODE_READ) { ++ err = pxa_request_dma(is->name, DMA_PRIO_LOW, ++ audio_dma_irq, is); ++ if (err < 0) { ++ if (file->f_mode & FMODE_WRITE) { ++ *os->drcmr = 0; ++ pxa_free_dma(os->dma_ch); ++ } ++ goto out; ++ } ++ is->dma_ch = err; ++ } ++ ++ 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 = no_llseek; ++ ++ if ((file->f_mode & FMODE_WRITE)) { ++ state->wr_ref = 1; ++ os->fragsize = AUDIO_FRAGSIZE_DEFAULT; ++ os->nbfrags = AUDIO_NBFRAGS_DEFAULT; ++ os->output = 1; ++ os->mapped = 0; ++ init_waitqueue_head(&os->frag_wq); ++ init_waitqueue_head(&os->stop_wq); ++ *os->drcmr = os->dma_ch | DRCMR_MAPVLD; ++ } ++ if (file->f_mode & FMODE_READ) { ++ state->rd_ref = 1; ++ is->fragsize = AUDIO_FRAGSIZE_DEFAULT; ++ is->nbfrags = AUDIO_NBFRAGS_DEFAULT; ++ is->output = 0; ++ is->mapped = 0; ++ init_waitqueue_head(&is->frag_wq); ++ init_waitqueue_head(&is->stop_wq); ++ *is->drcmr = is->dma_ch | DRCMR_MAPVLD; ++ } ++ ++ err = 0; ++ ++out: ++ up(&state->sem); ++ return err; ++} ++ ++EXPORT_SYMBOL(pxa_audio_attach); ++EXPORT_SYMBOL(pxa_audio_clear_buf); ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/sound/pxa-audio.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,55 @@ ++/* ++ * linux/drivers/sound/pxa-audio.h -- audio interface for the Cotula chip ++ * ++ * Author: Nicolas Pitre ++ * Created: Aug 15, 2001 ++ * Copyright: MontaVista 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. ++ */ ++ ++typedef struct { ++ int offset; /* current buffer position */ ++ char *data; /* actual buffer */ ++ pxa_dma_desc *dma_desc; /* pointer to the starting desc */ ++ int master; /* owner for buffer allocation, contain size whn true */ ++} audio_buf_t; ++ ++typedef struct { ++ char *name; /* stream identifier */ ++ audio_buf_t *buffers; /* pointer to audio buffer array */ ++ u_int usr_frag; /* user fragment index */ ++ u_int dma_frag; /* DMA fragment index */ ++ u_int fragsize; /* fragment size */ ++ u_int nbfrags; /* number of fragments */ ++ u_int dma_ch; /* DMA channel number */ ++ dma_addr_t dma_desc_phys; /* phys addr of descriptor ring */ ++ u_int descs_per_frag; /* nbr descriptors per fragment */ ++ int bytecount; /* nbr of processed bytes */ ++ int fragcount; /* nbr of fragment transitions */ ++ struct semaphore sem; /* account for fragment usage */ ++ wait_queue_head_t frag_wq; /* for poll(), etc. */ ++ wait_queue_head_t stop_wq; /* for users of DCSR_STOPIRQEN */ ++ u_long dcmd; /* DMA descriptor dcmd field */ ++ volatile u32 *drcmr; /* the DMA request channel to use */ ++ u_long dev_addr; /* device physical address for DMA */ ++ int mapped:1; /* mmap()'ed buffers */ ++ int output:1; /* 0 for input, 1 for output */ ++} audio_stream_t; ++ ++typedef struct { ++ audio_stream_t *output_stream; ++ audio_stream_t *input_stream; ++ int dev_dsp; /* audio device handle */ ++ int rd_ref:1; /* open reference for recording */ ++ int wr_ref:1; /* open reference for playback */ ++ int (*client_ioctl)(struct inode *, struct file *, uint, ulong); ++ struct semaphore sem; /* prevent races in attach/release */ ++} audio_state_t; ++ ++extern int pxa_audio_attach(struct inode *inode, struct file *file, ++ audio_state_t *state); ++extern void pxa_audio_clear_buf(audio_stream_t *s); ++ +--- linux-2.4.25/drivers/sound/sa1100-audio.c~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/sound/sa1100-audio.c 2004-03-31 17:15:12.000000000 +0200 +@@ -148,7 +148,8 @@ + do { + dmabuf = consistent_alloc(GFP_KERNEL|GFP_DMA, + dmasize, +- &dmaphys); ++ &dmaphys, ++ 0); + if (!dmabuf) + dmasize -= s->fragsize; + } while (!dmabuf && dmasize); +--- linux-2.4.25/drivers/video/Config.in~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/video/Config.in 2004-03-31 17:15:12.000000000 +0200 +@@ -50,6 +50,15 @@ + if [ "$CONFIG_FB_SA1100" = "y" -a "$CONFIG_SA1100_CERF_CPLD" = "y" ]; then + bool 'Cerfboard Backlight (CerfPDA)' CONFIG_SA1100_CERF_LCD_BACKLIGHT + fi ++ tristate ' PXA LCD support' CONFIG_FB_PXA $CONFIG_ARCH_PXA ++ if [ "$CONFIG_FB_PXA" != "n" ]; then ++ choice 'LCD Bit Depth' \ ++ "8-Bpp CONFIG_FB_PXA_8BPP \ ++ 16-Bpp CONFIG_FB_PXA_16BPP" Bit-Depth ++ fi ++ if [ "$CONFIG_FB_PXA" != "n" -a "$CONFIG_ARCH_LUBBOCK" = "y" ]; then ++ bool ' Lubbock QVGA LCD support instead of DSTN' CONFIG_FB_PXA_QVGA ++ fi + fi + dep_tristate ' CyberPro 2000/2010/5000 support' CONFIG_FB_CYBER2000 $CONFIG_PCI + if [ "$CONFIG_APOLLO" = "y" ]; then +@@ -295,7 +304,7 @@ + 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" -o "$CONFIG_FB_CLPS711X" = "y" -o \ +- "$CONFIG_FB_DBMX1" = "y" ]; then ++ "$CONFIG_FB_DBMX1" = "y" -o "$CONFIG_FB_PXA" = "y" ]; then + define_tristate CONFIG_FBCON_CFB2 y + define_tristate CONFIG_FBCON_CFB4 y + else +@@ -329,7 +338,7 @@ + "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" -o \ + "$CONFIG_FB_STI" = "y" -o "$CONFIG_FB_HP300" = "y" -o \ + "$CONFIG_FB_INTEL" = "y" -o \ +- "$CONFIG_FB_DBMX1" = "y" ]; then ++ "$CONFIG_FB_DBMX1" = "y" -o "$CONFIG_FB_PXA" = "y" ]; then + define_tristate CONFIG_FBCON_CFB8 y + else + if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \ +@@ -372,7 +381,7 @@ + "$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" -o \ +- "$CONFIG_FB_ANAKIN" = "y" -o \ ++ "$CONFIG_FB_ANAKIN" = "y" -o "$CONFIG_FB_PXA" = "y" -o \ + "$CONFIG_FB_DBMX1" = "y" ]; then + define_tristate CONFIG_FBCON_CFB16 y + else +--- linux-2.4.25/drivers/video/Makefile~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/video/Makefile 2004-03-31 17:15:12.000000000 +0200 +@@ -14,7 +14,7 @@ + fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o \ + fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \ + fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \ +- fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o \ ++ fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o pxafb.o \ + cyber2000fb.o sa1100fb.o fbcon-hga.o fbgen.o + + # Each configuration option enables a list of files. +@@ -129,6 +129,10 @@ + obj-$(CONFIG_FB_BWTWO) += bwtwofb.o + obj-$(CONFIG_FB_HGA) += hgafb.o + obj-$(CONFIG_FB_SA1100) += sa1100fb.o ++obj-$(CONFIG_FB_PXA) += pxafb.o ++ifeq ($(CONFIG_PXA_CERF_PDA),y) ++ obj-$(CONFIG_FB_PXA) += lcdctrl.o lcdctrl_cerf.o ++endif + obj-$(CONFIG_FB_DBMX1) += dbmx1fb.o + obj-$(CONFIG_FB_VIRTUAL) += vfb.o + obj-$(CONFIG_FB_HIT) += hitfb.o fbgen.o +--- linux-2.4.25/drivers/video/fbmem.c~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/video/fbmem.c 2004-03-31 17:15:12.000000000 +0200 +@@ -109,6 +109,7 @@ + extern int chips_init(void); + extern int g364fb_init(void); + extern int sa1100fb_init(void); ++extern int pxafb_init(void); + extern int fm2fb_init(void); + extern int fm2fb_setup(char*); + extern int q40fb_init(void); +@@ -305,6 +306,9 @@ + #ifdef CONFIG_FB_SA1100 + { "sa1100", sa1100fb_init, NULL }, + #endif ++#ifdef CONFIG_FB_PXA ++ { "pxa", pxafb_init, NULL }, ++#endif + #ifdef CONFIG_FB_SUN3 + { "sun3", sun3fb_init, sun3fb_setup }, + #endif +@@ -675,13 +679,13 @@ + #elif defined(__i386__) || defined(__x86_64__) + if (boot_cpu_data.x86 > 3) + pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; +-#elif defined(__arm__) || defined(__mips__) ++#elif defined(__mips__) + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + #elif defined(__sh__) + pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE; + #elif defined(__hppa__) + pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; +-#elif defined(__ia64__) ++#elif defined(__ia64__) || defined(__arm__) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + #elif defined(__hppa__) + pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/video/lcdctrl.c 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,223 @@ ++/* ++ * lcdctrl.c ++ * ++ * Generic LCD control for brightness, contrast, etc. ++ * Device specific drivers implement a lcdctrl_device and ++ * provides access to it via lcdctrl_device_get_ops(). ++ * ++ * 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. ++ * ++ * History: ++ * Mar 2002: Initial version [FB] ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/ctype.h> ++#include <linux/mm.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++ ++#include <asm/system.h> ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++ ++#include <video/lcdctrl.h> ++ ++/* ++ * Set this to zero to remove all the debug statements via ++ * dead code elimination. ++ */ ++#define DEBUGGING 0 ++ ++#if DEBUGGING ++static unsigned int lcd_debug = DEBUGGING; ++#else ++#define lcd_debug 0 ++#endif ++ ++/* -- prototypes -- */ ++ ++static int lcdctrl_ioctl(struct inode * inode, struct file *filp, ++ unsigned int cmd , unsigned long arg); ++static int lcdctrl_open(struct inode *inode, struct file *filp); ++static int lcdctrl_close(struct inode *inode, struct file *filp); ++ ++/* -- variables -- */ ++ ++struct lcdctrl_device *lcd_device; ++ ++static int intensity; ++static int brightness; ++static int contrast; ++ ++static int enabled; ++static int sync_needed; ++static int chrdev_major; ++ ++static struct file_operations lcdctrl_fops = { ++ ioctl: lcdctrl_ioctl, ++ open: lcdctrl_open, ++ release: lcdctrl_close ++}; ++ ++/* -- ioctl -- */ ++ ++static int lcdctrl_ioctl(struct inode * inode, struct file *filp, ++ unsigned int cmd , unsigned long arg) ++{ ++ int ret; ++ ret = -EINVAL; ++ ++ if( lcd_debug) ++ printk(KERN_INFO "lcdctrl_ioctl: cmd=%d, arg=%ld\n", cmd, arg); ++ ++ switch(cmd) ++ { ++ case _LCDCTRL_IOCTL_ON: ++ ret = lcdctrl_enable(); ++ break; ++ case _LCDCTRL_IOCTL_OFF: ++ ret = lcdctrl_disable(); ++ break; ++ case _LCDCTRL_IOCTL_INTENSITY: ++ if ((arg >=0) && (arg <= 100)) ++ ret = lcdctrl_set_intensity(arg); ++ break; ++ case _LCDCTRL_IOCTL_BRIGHTNESS: ++ if ((arg >=0) && (arg <= 100)) ++ ret = lcdctrl_set_brightness(arg); ++ break; ++ case _LCDCTRL_IOCTL_CONTRAST: ++ if ((arg >=0) && (arg <= 100)) ++ ret = lcdctrl_set_contrast(arg, LCD_NO_SYNC); ++ break; ++ case _LCDCTRL_IOCTL_GET_BRIGHTNESS: ++ ret = brightness; ++ break; ++ case _LCDCTRL_IOCTL_GET_CONTRAST: ++ ret = contrast; ++ break; ++ case _LCDCTRL_IOCTL_GET_INTENSITY: ++ ret = intensity; ++ break; ++ ++ default: ++ printk(KERN_ERR "lcdctrl_ioctl: invalid ioctl\n"); ++ break; ++ } ++ ++ return ret; ++} ++ ++static int lcdctrl_open(struct inode *inode, struct file *filp) ++{ ++// MOD_INC_USE_COUNT; ++ return 0; ++} ++ ++static int lcdctrl_close(struct inode *inode, struct file *filp) ++{ ++// MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++/* -- -- */ ++ ++int lcdctrl_enable( void) ++{ ++ int result; ++ ++ if( enabled) return 0; ++ ++ result = lcd_device->enable(); ++ ++ lcdctrl_set_intensity( intensity); ++ lcdctrl_set_brightness( brightness); ++ lcdctrl_set_contrast( contrast, sync_needed); ++ sync_needed = LCD_NO_SYNC; ++ ++ enabled = 1; ++ return result; ++} ++ ++int lcdctrl_disable( void) ++{ ++ enabled = 0; ++ return lcd_device->disable(); ++} ++ ++int lcdctrl_set_intensity( int i) ++{ ++ intensity = i; ++ return lcd_device->set_intensity( i); ++} ++ ++int lcdctrl_set_brightness( int b) ++{ ++ brightness = b; ++ return lcd_device->set_brightness( b); ++} ++ ++int lcdctrl_set_contrast( int c, int sync) ++{ ++ contrast = c; ++ return lcd_device->set_contrast( c, sync); ++} ++ ++int lcdctrl_get_intensity( void) ++{ ++ return intensity; ++} ++ ++int lcdctrl_get_brightness( void) ++{ ++ return brightness; ++} ++ ++int lcdctrl_get_contrast( void) ++{ ++ return contrast; ++} ++ ++/* -- -- */ ++ ++/* the device specific driver should implement this */ ++struct lcdctrl_device *lcdctrl_device_get_ops(void); ++ ++int lcdctrl_init( void) ++{ ++ int ret; ++ ++ lcd_device = lcdctrl_device_get_ops(); ++ ++ if( !lcd_device) ++ { ++ printk(KERN_ERR "lcdctrl_init: No lcd_device registered.\n"); ++ return -EINVAL; ++ } ++ ++ ret = lcd_device->init( &intensity, &brightness, &contrast); ++ ++ sync_needed = LCD_SYNC_NEEDED; ++ ++ if( ret == 0) ++ { ++ chrdev_major = ++ register_chrdev( 0,_LCD_CONTROL_NAME,&lcdctrl_fops); ++ if( lcd_debug) ++ printk(KERN_INFO "lcdctrl_init: OK\n"); ++ } ++ return ret; ++} +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/video/lcdctrl_cerf.c 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,175 @@ ++/* ++ * lcdctrl_cerf.c ++ * ++ * Cerf LCD control for brightness and contrast. ++ * ++ * 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. ++ * ++ * History: ++ * Mar 2002: Initial version [FB] ++ * ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/ctype.h> ++#include <linux/mm.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++ ++#include <asm/system.h> ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <asm/arch/cerf_ucb1400gpio.h> ++ ++#include <video/lcdctrl.h> ++ ++/* ++ * Set this to zero to remove all the debug statements via ++ * dead code elimination. ++ */ ++#define DEBUGGING 0 ++ ++#if DEBUGGING ++static unsigned int lcd_debug = DEBUGGING; ++#else ++#define lcd_debug 0 ++#endif ++ ++#define LCD_MAX_INTENSITY 0 ++#define LCD_MAX_BRIGHTNESS 15 ++#define LCD_MAX_CONTRAST 100 ++ ++#define LCD_DEFAULT_INTENSITY 0 ++#define LCD_DEFAULT_BRIGHTNESS 14*100/(LCD_MAX_BRIGHTNESS) ++#define LCD_DEFAULT_CONTRAST 90*100/(LCD_MAX_CONTRAST) ++ ++#define UP 1 ++#define DOWN 0 ++ ++/* -- prototypes -- */ ++ ++static int cerf_lcdctrl_init( int *intensity, int *brightness, int *contrast); ++static int cerf_lcdctrl_enable(void); ++static int cerf_lcdctrl_disable(void); ++static int cerf_lcdctrl_set_intensity( int i); ++static int cerf_lcdctrl_set_brightness( int b); ++static int cerf_lcdctrl_set_contrast( int c, int sync); ++ ++static void cerf_lcdctrl_contrast_step( int direction); ++ ++/* -- variables -- */ ++ ++static int dev_contrast; ++ ++/* -- -- */ ++ ++static struct lcdctrl_device cerf_dev = { ++ init: cerf_lcdctrl_init, ++ enable: cerf_lcdctrl_enable, ++ disable: cerf_lcdctrl_disable, ++ set_intensity: cerf_lcdctrl_set_intensity, ++ set_brightness: cerf_lcdctrl_set_brightness, ++ set_contrast: cerf_lcdctrl_set_contrast ++}; ++ ++static int cerf_lcdctrl_enable( void) ++{ ++ cerf_ucb1400gpio_lcd_enable(); ++ ++ return 0; ++} ++ ++static int cerf_lcdctrl_disable( void) ++{ ++ cerf_ucb1400gpio_lcd_disable(); ++ ++ return 0; ++} ++ ++static int cerf_lcdctrl_set_intensity( int i) ++{ ++ int dev_intensity = LCD_MAX_INTENSITY*i/100; ++ if( lcd_debug) ++ printk(KERN_INFO "cerf_lcdctrl_set_intensity: " ++ "dev_intensity = %d\n", dev_intensity); ++ return 0; ++} ++ ++static int cerf_lcdctrl_set_brightness( int b) ++{ ++ int dev_brightness = LCD_MAX_BRIGHTNESS*b/100; ++ outw( dev_brightness, CERF_PDA_CPLD+CERF_PDA_CPLD_BRIGHTNESS); ++ if( lcd_debug) ++ printk(KERN_INFO "cerf_lcdctrl_set_brightness: " ++ "dev_brightness = %d\n", dev_brightness); ++ return 0; ++} ++ ++static int cerf_lcdctrl_set_contrast( int c, int sync) ++{ ++ int new_dev_contrast = LCD_MAX_CONTRAST*c/100; ++ int i; ++ int count; ++ int direction = UP; ++ if( sync == LCD_SYNC_NEEDED) ++ { ++ /* In order to sync we step down to the lowest contrast level */ ++ for( i=0; i<LCD_MAX_CONTRAST; i++) ++ cerf_lcdctrl_contrast_step(DOWN); ++ dev_contrast = 0; ++ } ++ ++ count = new_dev_contrast - dev_contrast; ++ if( count < 0) ++ { ++ /* new contrast is lower then current setting */ ++ direction = DOWN; ++ count = -count; ++ } ++ ++ for( i=0; i<count; i++) ++ cerf_lcdctrl_contrast_step(direction); ++ ++ if( lcd_debug) ++ printk(KERN_INFO "cerf_lcdctrl_set_contrast: " ++ "dev_contrast = %d\n", new_dev_contrast); ++ dev_contrast = new_dev_contrast; ++ ++ return 0; ++} ++ ++/* -- -- */ ++ ++static void cerf_lcdctrl_contrast_step( int direction) ++{ ++ cerf_ucb1400gpio_lcd_contrast_step( direction); ++} ++ ++/* -- -- */ ++ ++static int cerf_lcdctrl_init( int *intensity, int *brightness, int *contrast) ++{ ++ *intensity = LCD_DEFAULT_INTENSITY; ++ *brightness = LCD_DEFAULT_BRIGHTNESS; ++ *contrast = LCD_DEFAULT_CONTRAST; ++ ++ if( lcd_debug) ++ printk(KERN_INFO "cerf_lcdctrl_init: OK\n"); ++ return 0; ++} ++ ++/* this is the hook for lcdctrl to access to the device specifics */ ++struct lcdctrl_device *lcdctrl_device_get_ops(void) ++{ ++ return &cerf_dev; ++} +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/video/pxafb.c 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,1410 @@ ++/* ++ * linux/drivers/video/pxafb.c ++ * ++ * Copyright (C) 1999 Eric A. Thomas ++ * Based on acornfb.c Copyright (C) Russell King. ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ * ++ * Intel PXA250/210 LCD Controller Frame Buffer Driver ++ * ++ * Please direct your questions and comments on this driver to the following ++ * email address: ++ * ++ * linux-arm-kernel@lists.arm.linux.org.uk ++ * ++ * ++ * Code Status: ++ * ++ * 2001/08/03: <cbrake@accelent.com> ++ * - Ported from SA1100 to PXA250 ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/interrupt.h> ++#include <linux/slab.h> ++#include <linux/fb.h> ++#include <linux/delay.h> ++#include <linux/pm.h> ++#include <linux/init.h> ++#include <linux/notifier.h> ++#include <linux/cpufreq.h> ++ ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/mach-types.h> ++#include <asm/uaccess.h> ++ ++#include <video/fbcon.h> ++#include <video/fbcon-mfb.h> ++#include <video/fbcon-cfb4.h> ++#include <video/fbcon-cfb8.h> ++#include <video/fbcon-cfb16.h> ++#include <video/lcdctrl.h> /* brightness, contrast, etc. control */ ++ ++/* ++ * debugging? ++ */ ++#define DEBUG 0 ++/* ++ * Complain if VAR is out of range. ++ */ ++#define DEBUG_VAR 1 ++ ++#undef ASSABET_PAL_VIDEO ++ ++#include "pxafb.h" ++ ++void (*pxafb_blank_helper)(int blank); ++EXPORT_SYMBOL(pxafb_blank_helper); ++ ++/* ++ * IMHO this looks wrong. In 8BPP, length should be 8. ++ */ ++static struct pxafb_rgb rgb_8 = { ++ red: { offset: 0, length: 4, }, ++ green: { offset: 0, length: 4, }, ++ blue: { offset: 0, length: 4, }, ++ transp: { offset: 0, length: 0, }, ++}; ++ ++static struct pxafb_rgb def_rgb_16 = { ++ red: { offset: 11, length: 5, }, ++ green: { offset: 5, length: 6, }, ++ blue: { offset: 0, length: 5, }, ++ transp: { offset: 0, length: 0, }, ++}; ++ ++static struct pxafb_mach_info pxa_fb_info __initdata = { ++ pixclock: LCD_PIXCLOCK, /* clock period in ps */ ++ bpp: LCD_BPP, ++ xres: LCD_XRES, ++ yres: LCD_YRES, ++ hsync_len: LCD_HORIZONTAL_SYNC_PULSE_WIDTH, ++ vsync_len: LCD_VERTICAL_SYNC_PULSE_WIDTH, ++ left_margin: LCD_BEGIN_OF_LINE_WAIT_COUNT, ++ upper_margin: LCD_BEGIN_FRAME_WAIT_COUNT, ++ right_margin: LCD_END_OF_LINE_WAIT_COUNT, ++ lower_margin: LCD_END_OF_FRAME_WAIT_COUNT, ++ sync: LCD_SYNC, ++ lccr0: LCD_LCCR0, ++ lccr3: LCD_LCCR3 ++}; ++ ++static struct pxafb_mach_info * __init ++pxafb_get_machine_info(struct pxafb_info *fbi) ++{ ++ return &pxa_fb_info; ++} ++ ++static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *); ++static void set_ctrlr_state(struct pxafb_info *fbi, u_int state); ++ ++static inline void pxafb_schedule_task(struct pxafb_info *fbi, u_int state) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ /* ++ * We need to handle two requests being made at the same time. ++ * There are two important cases: ++ * 1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE) ++ * We must perform the unblanking, which will do our REENABLE for us. ++ * 2. When we are blanking, but immediately unblank before we have ++ * blanked. We do the "REENABLE" thing here as well, just to be sure. ++ */ ++ if (fbi->task_state == C_ENABLE && state == C_REENABLE) ++ state = (u_int) -1; ++ if (fbi->task_state == C_DISABLE && state == C_ENABLE) ++ state = C_REENABLE; ++ ++ if (state != (u_int)-1) { ++ fbi->task_state = state; ++ schedule_task(&fbi->task); ++ } ++ local_irq_restore(flags); ++} ++ ++/* ++ * Get the VAR structure pointer for the specified console ++ */ ++static inline struct fb_var_screeninfo *get_con_var(struct fb_info *info, int con) ++{ ++ struct pxafb_info *fbi = (struct pxafb_info *)info; ++ return (con == fbi->currcon || con == -1) ? &fbi->fb.var : &fb_display[con].var; ++} ++ ++/* ++ * Get the DISPLAY structure pointer for the specified console ++ */ ++static inline struct display *get_con_display(struct fb_info *info, int con) ++{ ++ struct pxafb_info *fbi = (struct pxafb_info *)info; ++ return (con < 0) ? fbi->fb.disp : &fb_display[con]; ++} ++ ++/* ++ * Get the CMAP pointer for the specified console ++ */ ++static inline struct fb_cmap *get_con_cmap(struct fb_info *info, int con) ++{ ++ struct pxafb_info *fbi = (struct pxafb_info *)info; ++ return (con == fbi->currcon || con == -1) ? &fbi->fb.cmap : &fb_display[con].cmap; ++} ++ ++static inline u_int ++chan_to_field(u_int chan, struct fb_bitfield *bf) ++{ ++ chan &= 0xffff; ++ chan >>= 16 - bf->length; ++ return chan << bf->offset; ++} ++ ++static int ++pxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue, ++ u_int trans, struct fb_info *info) ++{ ++ struct pxafb_info *fbi = (struct pxafb_info *)info; ++ u_int val, ret = 1; ++ ++ if (regno < fbi->palette_size) { ++ val = ((red >> 0) & 0xf800); ++ val |= ((green >> 5) & 0x07e0); ++ val |= ((blue >> 11) & 0x001f); ++ ++ fbi->palette_cpu[regno] = val; ++ ret = 0; ++ } ++ return ret; ++} ++ ++static int ++pxafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ++ u_int trans, struct fb_info *info) ++{ ++ struct pxafb_info *fbi = (struct pxafb_info *)info; ++ u_int val; ++ int ret = 1; ++ ++ /* ++ * If greyscale is true, then we convert the RGB value ++ * to greyscale no mater what visual we are using. ++ */ ++ if (fbi->fb.var.grayscale) ++ red = green = blue = (19595 * red + 38470 * green + ++ 7471 * blue) >> 16; ++ ++ switch (fbi->fb.disp->visual) { ++ case FB_VISUAL_TRUECOLOR: ++ case FB_VISUAL_DIRECTCOLOR: ++ /* ++ * 12 or 16-bit True Colour. We encode the RGB value ++ * according to the RGB bitfield information. ++ */ ++ if (regno <= 16) { ++ u16 *pal = fbi->fb.pseudo_palette; ++ ++ val = chan_to_field(red, &fbi->fb.var.red); ++ val |= chan_to_field(green, &fbi->fb.var.green); ++ val |= chan_to_field(blue, &fbi->fb.var.blue); ++ ++ pal[regno] = val; ++ ret = 0; ++ } ++ break; ++ ++ case FB_VISUAL_PSEUDOCOLOR: ++ ret = pxafb_setpalettereg(regno, red, green, blue, trans, info); ++ break; ++ } ++ ++ return ret; ++} ++ ++/* ++ * pxafb_decode_var(): ++ * Get the video params out of 'var'. If a value doesn't fit, round it up, ++ * if it's too big, return -EINVAL. ++ * ++ * Suggestion: Round up in the following order: bits_per_pixel, xres, ++ * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, ++ * bitfields, horizontal timing, vertical timing. ++ */ ++static int pxafb_validate_var(struct fb_var_screeninfo *var, ++ struct pxafb_info *fbi) ++{ ++ int ret = -EINVAL; ++ ++ if (var->xres < MIN_XRES) ++ var->xres = MIN_XRES; ++ if (var->yres < MIN_YRES) ++ var->yres = MIN_YRES; ++ if (var->xres > fbi->max_xres) ++ var->xres = fbi->max_xres; ++ if (var->yres > fbi->max_yres) ++ var->yres = fbi->max_yres; ++ var->xres_virtual = ++ var->xres_virtual < var->xres ? var->xres : var->xres_virtual; ++ var->yres_virtual = ++ var->yres_virtual < var->yres ? var->yres : var->yres_virtual; ++ ++ DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel); ++ switch (var->bits_per_pixel) { ++#ifdef FBCON_HAS_CFB4 ++ case 4: ret = 0; break; ++#endif ++#ifdef FBCON_HAS_CFB8 ++ case 8: ret = 0; break; ++#endif ++#ifdef FBCON_HAS_CFB16 ++ case 12: ++ /* make sure we are in passive mode */ ++ if (!(fbi->lccr0 & LCCR0_PAS)) ++ ret = 0; ++ break; ++ ++ case 16: ++ /* ++ * 16 bits works apparemtly fine in passive mode for those, ++ * so don't complain ++ */ ++ if (machine_is_lubbock() || ++ machine_is_pxa_cerf()) { ++ ret = 0; ++ } else ++ /* make sure we are in active mode */ ++ if ((fbi->lccr0 & LCCR0_PAS)) ++ ret = 0; ++ break; ++#endif ++ default: ++ break; ++ } ++ ++ return ret; ++} ++ ++static inline void pxafb_set_truecolor(u_int is_true_color) ++{ ++ DPRINTK("true_color = %d\n", is_true_color); ++} ++ ++static void ++pxafb_hw_set_var(struct fb_var_screeninfo *var, struct pxafb_info *fbi) ++{ ++ ++ fb_set_cmap(&fbi->fb.cmap, 1, pxafb_setcolreg, &fbi->fb); ++ ++ /* Set board control register to handle new color depth */ ++ pxafb_set_truecolor(var->bits_per_pixel >= 16); ++ ++ pxafb_activate_var(var, fbi); ++ ++} ++ ++/* ++ * pxafb_set_var(): ++ * Set the user defined part of the display for the specified console ++ */ ++static int ++pxafb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) ++{ ++ struct pxafb_info *fbi = (struct pxafb_info *)info; ++ struct fb_var_screeninfo *dvar = get_con_var(&fbi->fb, con); ++ struct display *display = get_con_display(&fbi->fb, con); ++ int err, chgvar = 0, rgbidx; ++ ++ DPRINTK("set_var\n"); ++ ++ /* ++ * Decode var contents into a par structure, adjusting any ++ * out of range values. ++ */ ++ err = pxafb_validate_var(var, fbi); ++ if (err) ++ return err; ++ ++ if (var->activate & FB_ACTIVATE_TEST) ++ return 0; ++ ++ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) ++ return -EINVAL; ++ ++ if (dvar->xres != var->xres) ++ chgvar = 1; ++ if (dvar->yres != var->yres) ++ chgvar = 1; ++ if (dvar->xres_virtual != var->xres_virtual) ++ chgvar = 1; ++ if (dvar->yres_virtual != var->yres_virtual) ++ chgvar = 1; ++ if (dvar->bits_per_pixel != var->bits_per_pixel) ++ chgvar = 1; ++ if (con < 0) ++ chgvar = 0; ++ ++ switch (var->bits_per_pixel) { ++#ifdef FBCON_HAS_CFB4 ++ case 4: ++ if (fbi->cmap_static) ++ display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR; ++ else ++ display->visual = FB_VISUAL_PSEUDOCOLOR; ++ display->line_length = var->xres / 2; ++ display->dispsw = &fbcon_cfb4; ++ rgbidx = RGB_8; ++ break; ++#endif ++#ifdef FBCON_HAS_CFB8 ++ case 8: ++ if (fbi->cmap_static) ++ display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR; ++ else ++ display->visual = FB_VISUAL_PSEUDOCOLOR; ++ display->line_length = var->xres; ++ display->dispsw = &fbcon_cfb8; ++ rgbidx = RGB_8; ++ break; ++#endif ++#ifdef FBCON_HAS_CFB16 ++ case 12: ++ case 16: ++ display->visual = FB_VISUAL_TRUECOLOR; ++ display->line_length = var->xres * 2; ++ display->dispsw = &fbcon_cfb16; ++ display->dispsw_data = fbi->fb.pseudo_palette; ++ rgbidx = RGB_16; ++ break; ++#endif ++ default: ++ rgbidx = 0; ++ display->dispsw = &fbcon_dummy; ++ break; ++ } ++ ++ display->screen_base = fbi->screen_cpu; ++ display->next_line = display->line_length; ++ display->type = fbi->fb.fix.type; ++ display->type_aux = fbi->fb.fix.type_aux; ++ display->ypanstep = fbi->fb.fix.ypanstep; ++ display->ywrapstep = fbi->fb.fix.ywrapstep; ++ display->can_soft_blank = 1; ++ display->inverse = 0; ++ ++ *dvar = *var; ++ dvar->activate &= ~FB_ACTIVATE_ALL; ++ ++ /* ++ * Copy the RGB parameters for this display ++ * from the machine specific parameters. ++ */ ++ dvar->red = fbi->rgb[rgbidx]->red; ++ dvar->green = fbi->rgb[rgbidx]->green; ++ dvar->blue = fbi->rgb[rgbidx]->blue; ++ dvar->transp = fbi->rgb[rgbidx]->transp; ++ ++ DPRINTK("RGBT length = %d:%d:%d:%d\n", ++ dvar->red.length, dvar->green.length, dvar->blue.length, ++ dvar->transp.length); ++ ++ DPRINTK("RGBT offset = %d:%d:%d:%d\n", ++ dvar->red.offset, dvar->green.offset, dvar->blue.offset, ++ dvar->transp.offset); ++ ++ /* ++ * Update the old var. The fbcon drivers still use this. ++ * Once they are using fbi->fb.var, this can be dropped. ++ */ ++ display->var = *dvar; ++ ++ /* ++ * If we are setting all the virtual consoles, also set the ++ * defaults used to create new consoles. ++ */ ++ if (var->activate & FB_ACTIVATE_ALL) ++ fbi->fb.disp->var = *dvar; ++ ++ /* ++ * If the console has changed and the console has defined ++ * a changevar function, call that function. ++ */ ++ if (chgvar && info && fbi->fb.changevar) ++ fbi->fb.changevar(con); ++ ++ /* If the current console is selected, activate the new var. */ ++ if (con != fbi->currcon) ++ return 0; ++ ++ pxafb_hw_set_var(dvar, fbi); ++ ++ return 0; ++} ++ ++static int ++__do_set_cmap(struct fb_cmap *cmap, int kspc, int con, ++ struct fb_info *info) ++{ ++ struct pxafb_info *fbi = (struct pxafb_info *)info; ++ struct fb_cmap *dcmap = get_con_cmap(info, con); ++ int err = 0; ++ ++ if (con == -1) ++ con = fbi->currcon; ++ ++ /* no colormap allocated? (we always have "this" colour map allocated) */ ++ if (con >= 0) ++ err = fb_alloc_cmap(&fb_display[con].cmap, fbi->palette_size, 0); ++ ++ if (!err && con == fbi->currcon) ++ err = fb_set_cmap(cmap, kspc, pxafb_setcolreg, info); ++ ++ if (!err) ++ fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1); ++ ++ return err; ++} ++ ++static int ++pxafb_set_cmap(struct fb_cmap *cmap, int kspc, int con, ++ struct fb_info *info) ++{ ++ struct display *disp = get_con_display(info, con); ++ ++ if (disp->visual == FB_VISUAL_TRUECOLOR) ++ return -EINVAL; ++ ++ return __do_set_cmap(cmap, kspc, con, info); ++} ++ ++static int ++pxafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) ++{ ++ struct display *display = get_con_display(info, con); ++ ++ *fix = info->fix; ++ ++ fix->line_length = display->line_length; ++ fix->visual = display->visual; ++ return 0; ++} ++ ++static int ++pxafb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) ++{ ++ *var = *get_con_var(info, con); ++ return 0; ++} ++ ++static int ++pxafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) ++{ ++ struct fb_cmap *dcmap = get_con_cmap(info, con); ++ fb_copy_cmap(dcmap, cmap, kspc ? 0 : 2); ++ return 0; ++} ++ ++static struct fb_ops pxafb_ops = { ++ owner: THIS_MODULE, ++ fb_get_fix: pxafb_get_fix, ++ fb_get_var: pxafb_get_var, ++ fb_set_var: pxafb_set_var, ++ fb_get_cmap: pxafb_get_cmap, ++ fb_set_cmap: pxafb_set_cmap, ++}; ++ ++/* ++ * pxafb_switch(): ++ * Change to the specified console. Palette and video mode ++ * are changed to the console's stored parameters. ++ * ++ * Uh oh, this can be called from a tasklet (IRQ) ++ */ ++static int pxafb_switch(int con, struct fb_info *info) ++{ ++ struct pxafb_info *fbi = (struct pxafb_info *)info; ++ struct display *disp; ++ struct fb_cmap *cmap; ++ ++ DPRINTK("con=%d info->modename=%s\n", con, fbi->fb.modename); ++ ++ if (con == fbi->currcon) ++ return 0; ++ ++ if (fbi->currcon >= 0) { ++ disp = fb_display + fbi->currcon; ++ ++ /* ++ * Save the old colormap and video mode. ++ */ ++ disp->var = fbi->fb.var; ++ ++ if (disp->cmap.len) ++ fb_copy_cmap(&fbi->fb.cmap, &disp->cmap, 0); ++ } ++ ++ fbi->currcon = con; ++ disp = fb_display + con; ++ ++ /* ++ * Make sure that our colourmap contains 256 entries. ++ */ ++ fb_alloc_cmap(&fbi->fb.cmap, 256, 0); ++ ++ if (disp->cmap.len) ++ cmap = &disp->cmap; ++ else ++ cmap = fb_default_cmap(1 << disp->var.bits_per_pixel); ++ ++ fb_copy_cmap(cmap, &fbi->fb.cmap, 0); ++ ++ fbi->fb.var = disp->var; ++ fbi->fb.var.activate = FB_ACTIVATE_NOW; ++ ++ pxafb_set_var(&fbi->fb.var, con, info); ++ return 0; ++} ++ ++/* ++ * Formal definition of the VESA spec: ++ * On ++ * This refers to the state of the display when it is in full operation ++ * Stand-By ++ * This defines an optional operating state of minimal power reduction with ++ * the shortest recovery time ++ * Suspend ++ * This refers to a level of power management in which substantial power ++ * reduction is achieved by the display. The display can have a longer ++ * recovery time from this state than from the Stand-by state ++ * Off ++ * This indicates that the display is consuming the lowest level of power ++ * and is non-operational. Recovery from this state may optionally require ++ * the user to manually power on the monitor ++ * ++ * Now, the fbdev driver adds an additional state, (blank), where they ++ * turn off the video (maybe by colormap tricks), but don't mess with the ++ * video itself: think of it semantically between on and Stand-By. ++ * ++ * So here's what we should do in our fbdev blank routine: ++ * ++ * VESA_NO_BLANKING (mode 0) Video on, front/back light on ++ * VESA_VSYNC_SUSPEND (mode 1) Video on, front/back light off ++ * VESA_HSYNC_SUSPEND (mode 2) Video on, front/back light off ++ * VESA_POWERDOWN (mode 3) Video off, front/back light off ++ * ++ * This will match the matrox implementation. ++ */ ++/* ++ * pxafb_blank(): ++ * Blank the display by setting all palette values to zero. Note, the ++ * 12 and 16 bpp modes don't really use the palette, so this will not ++ * blank the display in all modes. ++ */ ++static void pxafb_blank(int blank, struct fb_info *info) ++{ ++ struct pxafb_info *fbi = (struct pxafb_info *)info; ++ int i; ++ ++ DPRINTK("pxafb_blank: blank=%d info->modename=%s\n", blank, ++ fbi->fb.modename); ++ ++ switch (blank) { ++ case VESA_POWERDOWN: ++ case VESA_VSYNC_SUSPEND: ++ case VESA_HSYNC_SUSPEND: ++ if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR || ++ fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR) ++ for (i = 0; i < fbi->palette_size; i++) ++ pxafb_setpalettereg(i, 0, 0, 0, 0, info); ++ pxafb_schedule_task(fbi, C_DISABLE); ++ if (pxafb_blank_helper) ++ pxafb_blank_helper(blank); ++ break; ++ ++ case VESA_NO_BLANKING: ++ if (pxafb_blank_helper) ++ pxafb_blank_helper(blank); ++ if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR || ++ fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR) ++ fb_set_cmap(&fbi->fb.cmap, 1, pxafb_setcolreg, info); ++ pxafb_schedule_task(fbi, C_ENABLE); ++ } ++} ++ ++static int pxafb_updatevar(int con, struct fb_info *info) ++{ ++ DPRINTK("entered\n"); ++ return 0; ++} ++ ++/* ++ * Calculate the PCD value from the clock rate (in picoseconds). ++ * We take account of the PPCR clock setting. ++ */ ++static inline int get_pcd(unsigned int pixclock) ++{ ++ unsigned int pcd; ++ ++ if (pixclock) { ++ pcd = get_lclk_frequency_10khz() * pixclock; ++ pcd /= 100000000; ++ pcd += 1; /* make up for integer math truncations */ ++ } else { ++ printk(KERN_WARNING "Please convert me to use the PCD calculations\n"); ++ pcd = 0; ++ } ++ return pcd; ++} ++ ++/* ++ * pxafb_activate_var(): ++ * Configures LCD Controller based on entries in var parameter. Settings are ++ * only written to the controller if changes were made. ++ */ ++static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *fbi) ++{ ++ struct pxafb_lcd_reg new_regs; ++// u_int pcd = get_pcd(var->pixclock); ++ u_long flags; ++ ++ DPRINTK("Configuring PXA LCD\n"); ++ ++ DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n", ++ var->xres, var->hsync_len, ++ var->left_margin, var->right_margin); ++ DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n", ++ var->yres, var->vsync_len, ++ var->upper_margin, var->lower_margin); ++ ++#if DEBUG_VAR ++ if (var->xres < 16 || var->xres > 1024) ++ printk(KERN_ERR "%s: invalid xres %d\n", ++ fbi->fb.fix.id, var->xres); ++ if (var->hsync_len < 1 || var->hsync_len > 64) ++ printk(KERN_ERR "%s: invalid hsync_len %d\n", ++ fbi->fb.fix.id, var->hsync_len); ++ if (var->left_margin < 1 || var->left_margin > 255) ++ printk(KERN_ERR "%s: invalid left_margin %d\n", ++ fbi->fb.fix.id, var->left_margin); ++ if (var->right_margin < 1 || var->right_margin > 255) ++ printk(KERN_ERR "%s: invalid right_margin %d\n", ++ fbi->fb.fix.id, var->right_margin); ++ if (var->yres < 1 || var->yres > 1024) ++ printk(KERN_ERR "%s: invalid yres %d\n", ++ fbi->fb.fix.id, var->yres); ++ if (var->vsync_len < 1 || var->vsync_len > 64) ++ printk(KERN_ERR "%s: invalid vsync_len %d\n", ++ fbi->fb.fix.id, var->vsync_len); ++ if (var->upper_margin < 0 || var->upper_margin > 255) ++ printk(KERN_ERR "%s: invalid upper_margin %d\n", ++ fbi->fb.fix.id, var->upper_margin); ++ if (var->lower_margin < 0 || var->lower_margin > 255) ++ printk(KERN_ERR "%s: invalid lower_margin %d\n", ++ fbi->fb.fix.id, var->lower_margin); ++#endif ++ ++#if defined (CONFIG_PXA_CERF_PDA) ++ new_regs.lccr0 = fbi->lccr0; ++ new_regs.lccr1 = ++ LCCR1_DisWdth(var->xres) + ++ LCCR1_HorSnchWdth(var->hsync_len) + ++ LCCR1_BegLnDel(var->left_margin) + ++ LCCR1_EndLnDel(var->right_margin); ++ ++ new_regs.lccr2 = ++ LCCR2_DisHght(var->yres) + ++ LCCR2_VrtSnchWdth(var->vsync_len) + ++ LCCR2_BegFrmDel(var->upper_margin) + ++ LCCR2_EndFrmDel(var->lower_margin); ++ ++ new_regs.lccr3 = fbi->lccr3 ++ | ++ (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) | ++ (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL); ++#elif defined (CONFIG_FB_PXA_QVGA) ++ new_regs.lccr0 = fbi->lccr0; ++ new_regs.lccr1 = ++ LCCR1_DisWdth(var->xres) + ++ LCCR1_HorSnchWdth(var->hsync_len) + ++ LCCR1_BegLnDel(var->left_margin) + ++ LCCR1_EndLnDel(var->right_margin); ++ new_regs.lccr2 = ++ LCCR2_DisHght(var->yres) + ++ LCCR2_VrtSnchWdth(var->vsync_len) + ++ LCCR2_BegFrmDel(var->upper_margin) + ++ LCCR2_EndFrmDel(var->lower_margin); ++ new_regs.lccr3 = fbi->lccr3; ++#else ++ // FIXME using hardcoded values for now ++ new_regs.lccr0 = fbi->lccr0; ++// | ++// LCCR0_LEN | LCCR0_LDM | LCCR0_BAM | ++// LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0); ++ ++ new_regs.lccr1 = 0x3030A7F; ++// LCCR1_DisWdth(var->xres) + ++// LCCR1_HorSnchWdth(var->hsync_len) + ++// LCCR1_BegLnDel(var->left_margin) + ++// LCCR1_EndLnDel(var->right_margin); ++ ++ new_regs.lccr2 = 0x4EF; ++// LCCR2_DisHght(var->yres) + ++// LCCR2_VrtSnchWdth(var->vsync_len) + ++// LCCR2_BegFrmDel(var->upper_margin) + ++// LCCR2_EndFrmDel(var->lower_margin); ++ ++ new_regs.lccr3 = fbi->lccr3; ++// | ++// (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) | ++// (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL) | ++// LCCR3_ACBsCntOff; ++#endif ++ ++// if (pcd) ++// new_regs.lccr3 |= LCCR3_PixClkDiv(pcd); ++ ++ DPRINTK("nlccr0 = 0x%08x\n", new_regs.lccr0); ++ DPRINTK("nlccr1 = 0x%08x\n", new_regs.lccr1); ++ DPRINTK("nlccr2 = 0x%08x\n", new_regs.lccr2); ++ DPRINTK("nlccr3 = 0x%08x\n", new_regs.lccr3); ++ ++ /* Update shadow copy atomically */ ++ local_irq_save(flags); ++ ++ /* setup dma descriptors */ ++ fbi->dmadesc_fblow_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 3*16); ++ fbi->dmadesc_fbhigh_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 2*16); ++ fbi->dmadesc_palette_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 1*16); ++ ++ fbi->dmadesc_fblow_dma = fbi->palette_dma - 3*16; ++ fbi->dmadesc_fbhigh_dma = fbi->palette_dma - 2*16; ++ fbi->dmadesc_palette_dma = fbi->palette_dma - 1*16; ++ ++ #define BYTES_PER_PANEL ((fbi->lccr0 & LCCR0_SDS) ? (var->xres * var->yres * var->bits_per_pixel / 8 / 2) : \ ++ (var->xres * var->yres * var->bits_per_pixel / 8)) ++ ++ /* populate descriptors */ ++ fbi->dmadesc_fblow_cpu->fdadr = fbi->dmadesc_fblow_dma; ++ fbi->dmadesc_fblow_cpu->fsadr = fbi->screen_dma + BYTES_PER_PANEL; ++ fbi->dmadesc_fblow_cpu->fidr = 0; ++ fbi->dmadesc_fblow_cpu->ldcmd = BYTES_PER_PANEL; ++ ++ fbi->fdadr1 = fbi->dmadesc_fblow_dma; /* only used in dual-panel mode */ ++ ++ fbi->dmadesc_fbhigh_cpu->fsadr = fbi->screen_dma; ++ fbi->dmadesc_fbhigh_cpu->fidr = 0; ++ fbi->dmadesc_fbhigh_cpu->ldcmd = BYTES_PER_PANEL; ++ ++ fbi->dmadesc_palette_cpu->fsadr = fbi->palette_dma; ++ fbi->dmadesc_palette_cpu->fidr = 0; ++ fbi->dmadesc_palette_cpu->ldcmd = (fbi->palette_size * 2) | LDCMD_PAL; ++ ++ if( var->bits_per_pixel < 12) ++ { ++ /* assume any mode with <12 bpp is palette driven */ ++ fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_fbhigh_dma; ++ fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_palette_dma; ++ fbi->fdadr0 = fbi->dmadesc_palette_dma; /* flips back and forth between pal and fbhigh */ ++ } ++ else ++ { ++ /* palette shouldn't be loaded in true-color mode */ ++ fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_fbhigh_dma; ++ fbi->fdadr0 = fbi->dmadesc_fbhigh_dma; /* no pal just fbhigh */ ++ } ++ ++ DPRINTK("fbi->dmadesc_fblow_cpu = 0x%x\n", fbi->dmadesc_fblow_cpu); ++ DPRINTK("fbi->dmadesc_fbhigh_cpu = 0x%x\n", fbi->dmadesc_fbhigh_cpu); ++ DPRINTK("fbi->dmadesc_palette_cpu = 0x%x\n", fbi->dmadesc_palette_cpu); ++ DPRINTK("fbi->dmadesc_fblow_dma = 0x%x\n", fbi->dmadesc_fblow_dma); ++ DPRINTK("fbi->dmadesc_fbhigh_dma = 0x%x\n", fbi->dmadesc_fbhigh_dma); ++ DPRINTK("fbi->dmadesc_palette_dma = 0x%x\n", fbi->dmadesc_palette_dma); ++ ++ DPRINTK("fbi->dmadesc_fblow_cpu->fdadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fdadr); ++ DPRINTK("fbi->dmadesc_fbhigh_cpu->fdadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fdadr); ++ DPRINTK("fbi->dmadesc_palette_cpu->fdadr = 0x%x\n", fbi->dmadesc_palette_cpu->fdadr); ++ ++ DPRINTK("fbi->dmadesc_fblow_cpu->fsadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fsadr); ++ DPRINTK("fbi->dmadesc_fbhigh_cpu->fsadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fsadr); ++ DPRINTK("fbi->dmadesc_palette_cpu->fsadr = 0x%x\n", fbi->dmadesc_palette_cpu->fsadr); ++ ++ DPRINTK("fbi->dmadesc_fblow_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fblow_cpu->ldcmd); ++ DPRINTK("fbi->dmadesc_fbhigh_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fbhigh_cpu->ldcmd); ++ DPRINTK("fbi->dmadesc_palette_cpu->ldcmd = 0x%x\n", fbi->dmadesc_palette_cpu->ldcmd); ++ ++ fbi->reg_lccr0 = new_regs.lccr0; ++ fbi->reg_lccr1 = new_regs.lccr1; ++ fbi->reg_lccr2 = new_regs.lccr2; ++ fbi->reg_lccr3 = new_regs.lccr3; ++ local_irq_restore(flags); ++ ++ /* ++ * Only update the registers if the controller is enabled ++ * and something has changed. ++ */ ++ if ((LCCR0 != fbi->reg_lccr0) || (LCCR1 != fbi->reg_lccr1) || ++ (LCCR2 != fbi->reg_lccr2) || (LCCR3 != fbi->reg_lccr3) || ++ (FDADR0 != fbi->fdadr0) || (FDADR1 != fbi->fdadr1)) ++ pxafb_schedule_task(fbi, C_REENABLE); ++ ++ return 0; ++} ++ ++/* ++ * NOTE! The following functions are purely helpers for set_ctrlr_state. ++ * Do not call them directly; set_ctrlr_state does the correct serialisation ++ * to ensure that things happen in the right way 100% of time time. ++ * -- rmk ++ */ ++ ++/* ++ * FIXME: move LCD power stuff into pxafb_power_up_lcd() ++ * Also, I'm expecting that the backlight stuff should ++ * be handled differently. ++ */ ++static void pxafb_backlight_on(struct pxafb_info *fbi) ++{ ++ DPRINTK("backlight on\n"); ++ ++#ifdef CONFIG_ARCH_PXA_IDP ++ if(machine_is_pxa_idp()) { ++ FB_BACKLIGHT_ON(); ++ } ++#endif ++} ++ ++/* ++ * FIXME: move LCD power stuf into pxafb_power_down_lcd() ++ * Also, I'm expecting that the backlight stuff should ++ * be handled differently. ++ */ ++static void pxafb_backlight_off(struct pxafb_info *fbi) ++{ ++ DPRINTK("backlight off\n"); ++ ++#ifdef CONFIG_ARCH_PXA_IDP ++ if(machine_is_pxa_idp()) { ++ FB_BACKLIGHT_OFF(); ++ } ++#endif ++ ++} ++ ++static void pxafb_power_up_lcd(struct pxafb_info *fbi) ++{ ++ DPRINTK("LCD power on\n"); ++ CKEN |= CKEN16_LCD; ++ ++ if(machine_is_pxa_cerf()) { ++ lcdctrl_enable(); ++ } ++ ++#if CONFIG_ARCH_PXA_IDP ++ /* set GPIOs, etc */ ++ if(machine_is_pxa_idp()) { ++ // FIXME need to add proper delays ++ FB_PWR_ON(); ++ FB_VLCD_ON(); // FIXME this should be after scanning starts ++ } ++#endif ++} ++ ++static void pxafb_power_down_lcd(struct pxafb_info *fbi) ++{ ++ DPRINTK("LCD power off\n"); ++ CKEN &= ~CKEN16_LCD; ++ ++ if(machine_is_pxa_cerf()) { ++ lcdctrl_disable(); ++ } ++ ++ /* set GPIOs, etc */ ++#if CONFIG_ARCH_PXA_IDP ++ if(machine_is_pxa_idp()) { ++ // FIXME need to add proper delays ++ FB_PWR_OFF(); ++ FB_VLCD_OFF(); // FIXME this should be before scanning stops ++ } ++#endif ++ ++} ++ ++static void pxafb_setup_gpio(struct pxafb_info *fbi) ++{ ++ unsigned int lccr0; ++ ++ /* ++ * setup is based on type of panel supported ++ */ ++ ++ lccr0 = fbi->lccr0; ++ ++ /* 4 bit interface */ ++ if ((lccr0 & LCCR0_CMS) && (lccr0 & LCCR0_SDS) && !(lccr0 & LCCR0_DPD)) ++ { ++ // bits 58-61 ++ GPDR1 |= (0xf << 26); ++ GAFR1_U = (GAFR1_U & ~(0xff << 20)) | (0xaa << 20); ++ ++ // bits 74-77 ++ GPDR2 |= (0xf << 10); ++ GAFR2_L = (GAFR2_L & ~(0xff << 20)) | (0xaa << 20); ++ } ++ ++ /* 8 bit interface */ ++ else if (((lccr0 & LCCR0_CMS) && ((lccr0 & LCCR0_SDS) || (lccr0 & LCCR0_DPD))) || ++ (!(lccr0 & LCCR0_CMS) && !(lccr0 & LCCR0_PAS) && !(lccr0 & LCCR0_SDS))) ++ { ++ // bits 58-65 ++ GPDR1 |= (0x3f << 26); ++ GPDR2 |= (0x3); ++ ++ GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20); ++ GAFR2_L = (GAFR2_L & ~0xf) | (0xa); ++ ++ // bits 74-77 ++ GPDR2 |= (0xf << 10); ++ GAFR2_L = (GAFR2_L & ~(0xff << 20)) | (0xaa << 20); ++ } ++ ++ /* 16 bit interface */ ++ else if (!(lccr0 & LCCR0_CMS) && ((lccr0 & LCCR0_SDS) || (lccr0 & LCCR0_PAS))) ++ { ++ // bits 58-77 ++ GPDR1 |= (0x3f << 26); ++ GPDR2 |= 0x00003fff; ++ ++ GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20); ++ GAFR2_L = (GAFR2_L & 0xf0000000) | 0x0aaaaaaa; ++ } ++ else ++ { ++ printk( KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n"); ++ } ++} ++ ++static void pxafb_enable_controller(struct pxafb_info *fbi) ++{ ++ DPRINTK("Enabling LCD controller\n"); ++ ++ /* Sequence from 11.7.10 */ ++ LCCR3 = fbi->reg_lccr3; ++ LCCR2 = fbi->reg_lccr2; ++ LCCR1 = fbi->reg_lccr1; ++ LCCR0 = fbi->reg_lccr0 & ~LCCR0_ENB; ++ ++ /* FIXME we used to have LCD power control here */ ++ ++ FDADR0 = fbi->fdadr0; ++ FDADR1 = fbi->fdadr1; ++ LCCR0 |= LCCR0_ENB; ++ ++ DPRINTK("FDADR0 = 0x%08x\n", (unsigned int)FDADR0); ++ DPRINTK("FDADR1 = 0x%08x\n", (unsigned int)FDADR1); ++ DPRINTK("LCCR0 = 0x%08x\n", (unsigned int)LCCR0); ++ DPRINTK("LCCR1 = 0x%08x\n", (unsigned int)LCCR1); ++ DPRINTK("LCCR2 = 0x%08x\n", (unsigned int)LCCR2); ++ DPRINTK("LCCR3 = 0x%08x\n", (unsigned int)LCCR3); ++} ++ ++static void pxafb_disable_controller(struct pxafb_info *fbi) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ ++ DPRINTK("Disabling LCD controller\n"); ++ ++ /* FIXME add power down GPIO stuff here */ ++ ++ add_wait_queue(&fbi->ctrlr_wait, &wait); ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ ++ LCSR = 0xffffffff; /* Clear LCD Status Register */ ++ LCCR0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */ ++ LCCR0 &= ~LCCR0_ENB; /* Disable LCD Controller */ ++ ++ schedule_timeout(20 * HZ / 1000); ++ current->state = TASK_RUNNING; ++ remove_wait_queue(&fbi->ctrlr_wait, &wait); ++} ++ ++/* ++ * pxafb_handle_irq: Handle 'LCD DONE' interrupts. ++ */ ++static void pxafb_handle_irq(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ struct pxafb_info *fbi = dev_id; ++ unsigned int lcsr = LCSR; ++ ++ if (lcsr & LCSR_LDD) { ++ LCCR0 |= LCCR0_LDM; ++ wake_up(&fbi->ctrlr_wait); ++ } ++ ++ LCSR = lcsr; ++} ++ ++/* ++ * This function must be called from task context only, since it will ++ * sleep when disabling the LCD controller, or if we get two contending ++ * processes trying to alter state. ++ */ ++static void set_ctrlr_state(struct pxafb_info *fbi, u_int state) ++{ ++ u_int old_state; ++ ++ down(&fbi->ctrlr_sem); ++ ++ old_state = fbi->state; ++ ++ switch (state) { ++ case C_DISABLE_CLKCHANGE: ++ /* ++ * Disable controller for clock change. If the ++ * controller is already disabled, then do nothing. ++ */ ++ if (old_state != C_DISABLE) { ++ fbi->state = state; ++ pxafb_disable_controller(fbi); ++ } ++ break; ++ ++ case C_DISABLE: ++ /* ++ * Disable controller ++ */ ++ if (old_state != C_DISABLE) { ++ fbi->state = state; ++ ++ pxafb_backlight_off(fbi); ++ if (old_state != C_DISABLE_CLKCHANGE) ++ pxafb_disable_controller(fbi); ++ pxafb_power_down_lcd(fbi); ++ } ++ break; ++ ++ case C_ENABLE_CLKCHANGE: ++ /* ++ * Enable the controller after clock change. Only ++ * do this if we were disabled for the clock change. ++ */ ++ if (old_state == C_DISABLE_CLKCHANGE) { ++ fbi->state = C_ENABLE; ++ pxafb_enable_controller(fbi); ++ } ++ break; ++ ++ case C_REENABLE: ++ /* ++ * Re-enable the controller only if it was already ++ * enabled. This is so we reprogram the control ++ * registers. ++ */ ++ if (old_state == C_ENABLE) { ++ pxafb_disable_controller(fbi); ++ pxafb_setup_gpio(fbi); ++ pxafb_enable_controller(fbi); ++ } ++ break; ++ ++ case C_ENABLE: ++ /* ++ * Power up the LCD screen, enable controller, and ++ * turn on the backlight. ++ */ ++ if (old_state != C_ENABLE) { ++ fbi->state = C_ENABLE; ++ pxafb_setup_gpio(fbi); ++ pxafb_power_up_lcd(fbi); ++ pxafb_enable_controller(fbi); ++ pxafb_backlight_on(fbi); ++ } ++ break; ++ } ++ up(&fbi->ctrlr_sem); ++} ++ ++/* ++ * Our LCD controller task (which is called when we blank or unblank) ++ * via keventd. ++ */ ++static void pxafb_task(void *dummy) ++{ ++ struct pxafb_info *fbi = dummy; ++ u_int state = xchg(&fbi->task_state, -1); ++ ++ set_ctrlr_state(fbi, state); ++} ++ ++#ifdef CONFIG_CPU_FREQ ++/* ++ * CPU clock speed change handler. We need to adjust the LCD timing ++ * parameters when the CPU clock is adjusted by the power management ++ * subsystem. ++ */ ++static int ++pxafb_clkchg_notifier(struct notifier_block *nb, unsigned long val, ++ void *data) ++{ ++ struct pxafb_info *fbi = TO_INF(nb, clockchg); ++ u_int pcd; ++ ++ switch (val) { ++ case CPUFREQ_MINMAX: ++ /* todo: fill in min/max values */ ++ break; ++ ++ case CPUFREQ_PRECHANGE: ++ set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE); ++ break; ++ ++ case CPUFREQ_POSTCHANGE: ++ pcd = get_pcd(fbi->fb.var.pixclock); ++ fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd); ++ set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE); ++ break; ++ } ++ return 0; ++} ++#endif ++ ++#ifdef CONFIG_PM ++/* ++ * Power management hook. Note that we won't be called from IRQ context, ++ * unlike the blank functions above, so we may sleep. ++ */ ++static int ++pxafb_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ struct pxafb_info *fbi = pm_dev->data; ++ ++ DPRINTK("pm_callback: %d\n", req); ++ ++ if (req == PM_SUSPEND || req == PM_RESUME) { ++ int state = (int)data; ++ ++ if (state == 0) { ++ /* Enter D0. */ ++ set_ctrlr_state(fbi, C_ENABLE); ++ } else { ++ /* Enter D1-D3. Disable the LCD controller. */ ++ set_ctrlr_state(fbi, C_DISABLE); ++ } ++ } ++ DPRINTK("done\n"); ++ return 0; ++} ++#endif ++ ++/* ++ * pxafb_map_video_memory(): ++ * Allocates the DRAM memory for the frame buffer. This buffer is ++ * remapped into a non-cached, non-buffered, memory region to ++ * allow palette and pixel writes to occur without flushing the ++ * cache. Once this area is remapped, all virtual memory ++ * access to the video memory should occur at the new region. ++ */ ++static int __init pxafb_map_video_memory(struct pxafb_info *fbi) ++{ ++ u_long palette_mem_size; ++ ++ /* ++ * We reserve one page for the palette, plus the size ++ * of the framebuffer. ++ * ++ * layout of stuff in memory ++ * ++ * fblow descriptor ++ * fbhigh descriptor ++ * palette descriptor ++ * palette ++ * page boundary-> ++ * frame buffer ++ */ ++ fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE); ++ fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size, ++ &fbi->map_dma, PTE_BUFFERABLE); ++ ++ if (fbi->map_cpu) { ++ fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE; ++ fbi->screen_dma = fbi->map_dma + PAGE_SIZE; ++ fbi->fb.fix.smem_start = fbi->screen_dma; ++ ++ fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16; ++ ++ palette_mem_size = fbi->palette_size * sizeof(u16); ++ ++ DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size); ++ ++ fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size); ++ fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size; ++ ++ } ++ ++ return fbi->map_cpu ? 0 : -ENOMEM; ++} ++ ++/* Fake monspecs to fill in fbinfo structure */ ++static struct fb_monspecs monspecs __initdata = { ++ 30000, 70000, 50, 65, 0 /* Generic */ ++}; ++ ++ ++static struct pxafb_info * __init pxafb_init_fbinfo(void) ++{ ++ struct pxafb_mach_info *inf; ++ struct pxafb_info *fbi; ++ ++ fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(struct display) + ++ sizeof(u16) * 16, GFP_KERNEL); ++ if (!fbi) ++ return NULL; ++ ++ memset(fbi, 0, sizeof(struct pxafb_info) + sizeof(struct display)); ++ ++ fbi->currcon = -1; ++ ++ strcpy(fbi->fb.fix.id, PXA_NAME); ++ ++ fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS; ++ fbi->fb.fix.type_aux = 0; ++ fbi->fb.fix.xpanstep = 0; ++ fbi->fb.fix.ypanstep = 0; ++ fbi->fb.fix.ywrapstep = 0; ++ fbi->fb.fix.accel = FB_ACCEL_NONE; ++ ++ fbi->fb.var.nonstd = 0; ++ fbi->fb.var.activate = FB_ACTIVATE_NOW; ++ fbi->fb.var.height = -1; ++ fbi->fb.var.width = -1; ++ fbi->fb.var.accel_flags = 0; ++ fbi->fb.var.vmode = FB_VMODE_NONINTERLACED; ++ ++ strcpy(fbi->fb.modename, PXA_NAME); ++ strcpy(fbi->fb.fontname, "Acorn8x8"); ++ ++ fbi->fb.fbops = &pxafb_ops; ++ fbi->fb.changevar = NULL; ++ fbi->fb.switch_con = pxafb_switch; ++ fbi->fb.updatevar = pxafb_updatevar; ++ fbi->fb.blank = pxafb_blank; ++ fbi->fb.flags = FBINFO_FLAG_DEFAULT; ++ fbi->fb.node = -1; ++ fbi->fb.monspecs = monspecs; ++ fbi->fb.disp = (struct display *)(fbi + 1); ++ fbi->fb.pseudo_palette = (void *)(fbi->fb.disp + 1); ++ ++ fbi->rgb[RGB_8] = &rgb_8; ++ fbi->rgb[RGB_16] = &def_rgb_16; ++ ++ inf = pxafb_get_machine_info(fbi); ++ ++ fbi->max_xres = inf->xres; ++ fbi->fb.var.xres = inf->xres; ++ fbi->fb.var.xres_virtual = inf->xres; ++ fbi->max_yres = inf->yres; ++ fbi->fb.var.yres = inf->yres; ++ fbi->fb.var.yres_virtual = inf->yres; ++ fbi->max_bpp = inf->bpp; ++ fbi->fb.var.bits_per_pixel = inf->bpp; ++ fbi->fb.var.pixclock = inf->pixclock; ++ fbi->fb.var.hsync_len = inf->hsync_len; ++ fbi->fb.var.left_margin = inf->left_margin; ++ fbi->fb.var.right_margin = inf->right_margin; ++ fbi->fb.var.vsync_len = inf->vsync_len; ++ fbi->fb.var.upper_margin = inf->upper_margin; ++ fbi->fb.var.lower_margin = inf->lower_margin; ++ fbi->fb.var.sync = inf->sync; ++ fbi->fb.var.grayscale = inf->cmap_greyscale; ++ fbi->cmap_inverse = inf->cmap_inverse; ++ fbi->cmap_static = inf->cmap_static; ++ fbi->lccr0 = inf->lccr0; ++ fbi->lccr3 = inf->lccr3; ++ fbi->state = C_DISABLE; ++ fbi->task_state = (u_char)-1; ++ fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres * ++ fbi->max_bpp / 8; ++ ++ init_waitqueue_head(&fbi->ctrlr_wait); ++ INIT_TQUEUE(&fbi->task, pxafb_task, fbi); ++ init_MUTEX(&fbi->ctrlr_sem); ++ ++ return fbi; ++} ++ ++int __init pxafb_init(void) ++{ ++ struct pxafb_info *fbi; ++ int ret; ++ ++ fbi = pxafb_init_fbinfo(); ++ ret = -ENOMEM; ++ if (!fbi) ++ goto failed; ++ ++ if(machine_is_pxa_cerf()) { ++ // brightness&contrast is handled via lcdctrl. ++ lcdctrl_init(); ++ } ++ ++ /* Initialize video memory */ ++ ret = pxafb_map_video_memory(fbi); ++ if (ret) ++ goto failed; ++ ++ ret = request_irq(IRQ_LCD, pxafb_handle_irq, SA_INTERRUPT, ++ "LCD", fbi); ++ if (ret) { ++ printk(KERN_ERR "pxafb: failed in request_irq: %d\n", ret); ++ goto failed; ++ } ++ ++ pxafb_set_var(&fbi->fb.var, -1, &fbi->fb); ++ ++ ret = register_framebuffer(&fbi->fb); ++ if (ret < 0) ++ goto failed; ++ ++#ifdef CONFIG_PM ++ /* ++ * Note that the console registers this as well, but we want to ++ * power down the display prior to sleeping. ++ */ ++ fbi->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, pxafb_pm_callback); ++ if (fbi->pm) ++ fbi->pm->data = fbi; ++#endif ++#ifdef CONFIG_CPU_FREQ ++ fbi->clockchg.notifier_call = pxafb_clkchg_notifier; ++ cpufreq_register_notifier(&fbi->clockchg); ++#endif ++ ++ /* ++ * Ok, now enable the LCD controller ++ */ ++ set_ctrlr_state(fbi, C_ENABLE); ++ ++ /* This driver cannot be unloaded at the moment */ ++ MOD_INC_USE_COUNT; ++ ++ return 0; ++ ++failed: ++ if (fbi) ++ kfree(fbi); ++ return ret; ++} ++ ++ ++#ifdef MODULE ++module_init(pxafb_init); ++#endif ++ ++MODULE_DESCRIPTION("loadable framebuffer driver for PXA"); ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/video/pxafb.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,238 @@ ++/* ++ * linux/drivers/video/pxafb.h ++ * -- Intel PXA250/210 LCD Controller Frame Buffer Device ++ * ++ * Copyright (C) 1999 Eric A. Thomas ++ * Based on acornfb.c Copyright (C) Russell King. ++ * ++ * 2001-08-03: Cliff Brake <cbrake@acclent.com> ++ * - ported SA1100 code to PXA ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive ++ * for more details. ++ */ ++ ++/* ++ * These are the bitfields for each ++ * display depth that we support. ++ */ ++struct pxafb_rgb { ++ struct fb_bitfield red; ++ struct fb_bitfield green; ++ struct fb_bitfield blue; ++ struct fb_bitfield transp; ++}; ++ ++/* ++ * This structure describes the machine which we are running on. ++ */ ++struct pxafb_mach_info { ++ u_long pixclock; ++ ++ u_short xres; ++ u_short yres; ++ ++ u_char bpp; ++ u_char hsync_len; ++ u_char left_margin; ++ u_char right_margin; ++ ++ u_char vsync_len; ++ u_char upper_margin; ++ u_char lower_margin; ++ u_char sync; ++ ++ u_int cmap_greyscale:1, ++ cmap_inverse:1, ++ cmap_static:1, ++ unused:29; ++ ++ u_int lccr0; ++ u_int lccr3; ++}; ++ ++/* Shadows for LCD controller registers */ ++struct pxafb_lcd_reg { ++ unsigned int lccr0; ++ unsigned int lccr1; ++ unsigned int lccr2; ++ unsigned int lccr3; ++}; ++ ++/* PXA LCD DMA descriptor */ ++struct pxafb_dma_descriptor { ++ unsigned int fdadr; ++ unsigned int fsadr; ++ unsigned int fidr; ++ unsigned int ldcmd; ++}; ++ ++#define RGB_8 (0) ++#define RGB_16 (1) ++#define NR_RGB 2 ++ ++struct pxafb_info { ++ struct fb_info fb; ++ signed int currcon; ++ ++ struct pxafb_rgb *rgb[NR_RGB]; ++ ++ u_int max_bpp; ++ u_int max_xres; ++ u_int max_yres; ++ ++ /* ++ * These are the addresses we mapped ++ * the framebuffer memory region to. ++ */ ++ ++ /* raw memory addresses */ ++ dma_addr_t map_dma; /* physical */ ++ u_char * map_cpu; /* virtual */ ++ u_int map_size; ++ ++ /* addresses of pieces placed in raw buffer */ ++ u_char * screen_cpu; /* virtual address of frame buffer */ ++ dma_addr_t screen_dma; /* physical address of frame buffer */ ++ u16 * palette_cpu; /* virtual address of palette memory */ ++ dma_addr_t palette_dma; /* physical address of palette memory */ ++ u_int palette_size; ++ ++ /* DMA descriptors */ ++ struct pxafb_dma_descriptor * dmadesc_fblow_cpu; ++ dma_addr_t dmadesc_fblow_dma; ++ struct pxafb_dma_descriptor * dmadesc_fbhigh_cpu; ++ dma_addr_t dmadesc_fbhigh_dma; ++ struct pxafb_dma_descriptor * dmadesc_palette_cpu; ++ dma_addr_t dmadesc_palette_dma; ++ ++ dma_addr_t fdadr0; ++ dma_addr_t fdadr1; ++ ++ u_int lccr0; ++ u_int lccr3; ++ u_int cmap_inverse:1, ++ cmap_static:1, ++ unused:30; ++ ++ u_int reg_lccr0; ++ u_int reg_lccr1; ++ u_int reg_lccr2; ++ u_int reg_lccr3; ++ ++ volatile u_char state; ++ volatile u_char task_state; ++ struct semaphore ctrlr_sem; ++ wait_queue_head_t ctrlr_wait; ++ struct tq_struct task; ++ ++#ifdef CONFIG_PM ++ struct pm_dev *pm; ++#endif ++#ifdef CONFIG_CPU_FREQ ++ struct notifier_block clockchg; ++#endif ++}; ++ ++#define __type_entry(ptr,type,member) ((type *)((char *)(ptr)-offsetof(type,member))) ++ ++#define TO_INF(ptr,member) __type_entry(ptr,struct pxafb_info,member) ++ ++/* ++ * These are the actions for set_ctrlr_state ++ */ ++#define C_DISABLE (0) ++#define C_ENABLE (1) ++#define C_DISABLE_CLKCHANGE (2) ++#define C_ENABLE_CLKCHANGE (3) ++#define C_REENABLE (4) ++ ++#define PXA_NAME "PXA" ++ ++/* ++ * Debug macros ++ */ ++#if DEBUG ++# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) ++#else ++# define DPRINTK(fmt, args...) ++#endif ++ ++/* ++ * Minimum X and Y resolutions ++ */ ++#define MIN_XRES 64 ++#define MIN_YRES 64 ++ ++/* ++ * Are we configured for 8 or 16 bits per pixel? ++ */ ++#ifdef CONFIG_FB_PXA_8BPP ++# define PXAFB_BPP 8 ++# define PXAFB_BPP_BITS 0x03 ++#elif CONFIG_FB_PXA_16BPP ++# define PXAFB_BPP 16 ++# define PXAFB_BPP_BITS 0x04 ++#endif ++ ++#if defined(CONFIG_ARCH_LUBBOCK) ++#define LCD_PIXCLOCK 150000 ++#define LCD_BPP PXAFB_BPP ++#ifdef CONFIG_FB_PXA_QVGA ++#define LCD_XRES 320 ++#define LCD_YRES 240 ++#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH 51 ++#define LCD_VERTICAL_SYNC_PULSE_WIDTH 1 ++#define LCD_BEGIN_OF_LINE_WAIT_COUNT 1 ++#define LCD_BEGIN_FRAME_WAIT_COUNT 8 ++#define LCD_END_OF_LINE_WAIT_COUNT 1 ++#define LCD_END_OF_FRAME_WAIT_COUNT 1 ++#define LCD_SYNC (FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT) ++#define LCD_LCCR0 0x003008F8 ++#define LCD_LCCR3 (0x0040FF0C | (PXAFB_BPP_BITS << 24)) ++#else ++#define LCD_XRES 640 ++#define LCD_YRES 480 ++#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH 1 ++#define LCD_VERTICAL_SYNC_PULSE_WIDTH 1 ++#define LCD_BEGIN_OF_LINE_WAIT_COUNT 3 ++#define LCD_BEGIN_FRAME_WAIT_COUNT 0 ++#define LCD_END_OF_LINE_WAIT_COUNT 3 ++#define LCD_END_OF_FRAME_WAIT_COUNT 0 ++#define LCD_SYNC (FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT) ++#define LCD_LCCR0 0x0030087C ++#define LCD_LCCR3 (0x0040FF0C | (PXAFB_BPP_BITS << 24)) ++#endif ++ ++#elif defined (CONFIG_ARCH_PXA_IDP) ++#define LCD_PIXCLOCK 150000 ++#define LCD_BPP PXAFB_BPP ++#define LCD_XRES 640 ++#define LCD_YRES 480 ++#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH 1 ++#define LCD_VERTICAL_SYNC_PULSE_WIDTH 1 ++#define LCD_BEGIN_OF_LINE_WAIT_COUNT 3 ++#define LCD_BEGIN_FRAME_WAIT_COUNT 0 ++#define LCD_END_OF_LINE_WAIT_COUNT 3 ++#define LCD_END_OF_FRAME_WAIT_COUNT 0 ++#define LCD_SYNC (FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT) ++#define LCD_LCCR0 0x0030087C ++#define LCD_LCCR3 (0x0040FF0C | (PXAFB_BPP_BITS << 24)) ++ ++#elif defined CONFIG_PXA_CERF_PDA ++#define LCD_PIXCLOCK 171521 ++#define LCD_BPP PXAFB_BPP ++#define LCD_XRES 240 ++#define LCD_YRES 320 ++#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH 7 ++#define LCD_VERTICAL_SYNC_PULSE_WIDTH 2 ++#define LCD_BEGIN_OF_LINE_WAIT_COUNT 17 ++#define LCD_BEGIN_FRAME_WAIT_COUNT 0 ++#define LCD_END_OF_LINE_WAIT_COUNT 17 ++#define LCD_END_OF_FRAME_WAIT_COUNT 0 ++#define LCD_SYNC (FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT) ++#define LCD_LCCR0 (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_QDM | LCCR0_BM | LCCR0_OUM) ++#define LCD_LCCR3 (LCCR3_PCP | LCCR3_PixClkDiv(0x12) | LCCR3_Bpp(PXAFB_BPP_BITS) | LCCR3_Acb(0x18)) ++ ++#endif +--- linux-2.4.25/drivers/video/sa1100fb.c~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/drivers/video/sa1100fb.c 2004-03-31 17:15:12.000000000 +0200 +@@ -2175,7 +2175,7 @@ + */ + fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE); + fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size, +- &fbi->map_dma); ++ &fbi->map_dma, PTE_BUFFERABLE); + + if (fbi->map_cpu) { + fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE; +--- linux-2.4.25/fs/Config.in~2.4.25-vrs2-pxa1.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/fs/Config.in 2004-03-31 17:15:12.000000000 +0200 +@@ -51,6 +51,9 @@ + int 'JFFS2 debugging verbosity (0 = quiet, 2 = noisy)' CONFIG_JFFS2_FS_DEBUG 0 + fi + tristate 'Compressed ROM file system support' CONFIG_CRAMFS ++dep_mbool ' Use linear addressing for cramfs' CONFIG_CRAMFS_LINEAR $CONFIG_CRAMFS ++dep_bool ' Support XIP on linear cramfs' CONFIG_CRAMFS_LINEAR_XIP $CONFIG_CRAMFS_LINEAR ++dep_bool ' Root file system on linear cramfs' CONFIG_ROOT_CRAMFS_LINEAR $CONFIG_CRAMFS_LINEAR + bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS + define_bool CONFIG_RAMFS y + +--- linux-2.4.25/fs/cramfs/inode.c~2.4.25-vrs2-pxa1.patch 2002-08-03 02:39:45.000000000 +0200 ++++ linux-2.4.25/fs/cramfs/inode.c 2004-03-31 17:15:12.000000000 +0200 +@@ -4,11 +4,29 @@ + * Copyright (C) 1999 Linus Torvalds. + * + * This file is released under the GPL. +- */ +- +-/* ++ * + * These are the VFS interfaces to the compressed rom filesystem. + * The actual compression is based on zlib, see the other files. ++ * ++ * Linear Addressing code ++ * Copyright (C) 2000 Shane Nay. ++ * ++ * Allows you to have a linearly addressed cramfs filesystem. ++ * Saves the need for buffer, and the munging of the buffer. ++ * Savings a bit over 32k with default PAGE_SIZE, BUFFER_SIZE ++ * etc. Usefull on embedded platform with ROM :-). ++ * ++ * Downsides- Currently linear addressed cramfs partitions ++ * don't co-exist with block cramfs partitions. ++ * ++ * 28-Dec-2000: XIP mode for linear cramfs ++ * Copyright (C) 2000 Robert Leslie <rob@mars.org> ++ * ++ * Dynamic allocation of linear cramfs space by Nicolas Pitre ++ * Copyright (C) 2003 Monta Vista Software, Inc. ++ * ++ * Linear cramfs now requires that you pass the physaddr= parameter to ++ * the mount process. Allows for multiple linear cramfs partitions. + */ + + #include <linux/module.h> +@@ -16,10 +34,12 @@ + #include <linux/pagemap.h> + #include <linux/init.h> + #include <linux/string.h> ++#include <linux/kernel.h> + #include <linux/locks.h> + #include <linux/blkdev.h> + #include <linux/cramfs_fs.h> + #include <asm/semaphore.h> ++#include <asm/io.h> + + #include <asm/uaccess.h> + +@@ -28,6 +48,8 @@ + #define CRAMFS_SB_BLOCKS u.cramfs_sb.blocks + #define CRAMFS_SB_FILES u.cramfs_sb.files + #define CRAMFS_SB_FLAGS u.cramfs_sb.flags ++#define CRAMFS_SB_LINEAR_PHYS_ADDR u.cramfs_sb.linear_phys_addr ++#define CRAMFS_SB_LINEAR_VIRT_ADDR u.cramfs_sb.linear_virt_addr + + static struct super_operations cramfs_ops; + static struct inode_operations cramfs_dir_inode_operations; +@@ -42,6 +64,74 @@ + #define CRAMINO(x) ((x)->offset?(x)->offset<<2:1) + #define OFFSET(x) ((x)->i_ino) + ++ ++#ifdef CONFIG_CRAMFS_LINEAR_XIP ++ ++static int cramfs_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ unsigned long address, length; ++ struct inode *inode = file->f_dentry->d_inode; ++ struct super_block *sb = inode->i_sb; ++ ++ /* this is only used in the case of read-only maps for XIP */ ++ ++ if (vma->vm_flags & VM_WRITE) ++ return generic_file_mmap(file, vma); ++ ++ if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) ++ return -EINVAL; ++ ++ address = PAGE_ALIGN(sb->CRAMFS_SB_LINEAR_PHYS_ADDR + OFFSET(inode)); ++ address += vma->vm_pgoff << PAGE_SHIFT; ++ ++ length = vma->vm_end - vma->vm_start; ++ ++ if (length > inode->i_size) ++ length = inode->i_size; ++ ++ length = PAGE_ALIGN(length); ++ ++ ++#if 0 ++ /* Doing the following makes it slower and more broken. bdl */ ++ /* ++ * Accessing memory above the top the kernel knows about or ++ * through a file pointer that was marked O_SYNC will be ++ * done non-cached. ++ */ ++ vma->vm_page_prot = ++ __pgprot((pgprot_val(vma->vm_page_prot) & ~_CACHE_MASK) ++ | _CACHE_UNCACHED); ++#endif ++ ++ /* ++ * Don't dump addresses that are not real memory to a core file. ++ */ ++ vma->vm_flags |= VM_IO; ++ flush_tlb_page(vma, address); ++ if (remap_page_range(vma->vm_start, address, length, ++ vma->vm_page_prot)) ++ return -EAGAIN; ++ ++#ifdef DEBUG_CRAMFS_XIP ++ printk("cramfs_mmap: mapped %s at 0x%08lx, length %lu to vma 0x%08lx" ++ ", page_prot 0x%08lx\n", ++ file->f_dentry->d_name.name, address, length, ++ vma->vm_start, pgprot_val(vma->vm_page_prot)); ++#endif ++ ++ return 0; ++} ++ ++static struct file_operations cramfs_linear_xip_fops = { ++ read: generic_file_read, ++ mmap: cramfs_mmap, ++}; ++ ++#define CRAMFS_INODE_IS_XIP(x) ((x)->i_mode & S_ISVTX) ++ ++#endif ++ + static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inode * cramfs_inode) + { + struct inode * inode = new_inode(sb); +@@ -60,7 +150,11 @@ + without -noleaf option. */ + insert_inode_hash(inode); + if (S_ISREG(inode->i_mode)) { ++#ifdef CONFIG_CRAMFS_LINEAR_XIP ++ inode->i_fop = CRAMFS_INODE_IS_XIP(inode) ? &cramfs_linear_xip_fops : &generic_ro_fops; ++#else + inode->i_fop = &generic_ro_fops; ++#endif + inode->i_data.a_ops = &cramfs_aops; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &cramfs_dir_inode_operations; +@@ -76,6 +170,18 @@ + return inode; + } + ++#ifdef CONFIG_CRAMFS_LINEAR ++/* ++ * Return a pointer to the block in the linearly addressed cramfs image. ++ */ ++static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len) ++{ ++ if (!len) ++ return NULL; ++ return (void*)(sb->CRAMFS_SB_LINEAR_VIRT_ADDR + offset); ++} ++ ++#else /* Not linear addressing - aka regular block mode. */ + /* + * We have our own block cache: don't fill up the buffer cache + * with the rom-image, because the way the filesystem is set +@@ -186,23 +292,65 @@ + } + return read_buffers[buffer] + offset; + } +- ++#endif /* !CONFIG_CRAMFS_LINEAR */ + + static struct super_block * cramfs_read_super(struct super_block *sb, void *data, int silent) + { ++#ifndef CONFIG_CRAMFS_LINEAR + int i; ++#else ++ char *p; ++#endif + struct cramfs_super super; + unsigned long root_offset; + struct super_block * retval = NULL; + +- set_blocksize(sb->s_dev, PAGE_CACHE_SIZE); + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + ++#ifndef CONFIG_CRAMFS_LINEAR ++ ++ set_blocksize(sb->s_dev, PAGE_CACHE_SIZE); ++ + /* Invalidate the read buffers on mount: think disk change.. */ + for (i = 0; i < READ_BUFFERS; i++) + buffer_blocknr[i] = -1; + ++#else ++ ++ /* ++ * The physical location of the cramfs image is specified as ++ * a mount parameter. This parameter is mandatory for obvious ++ * reasons. Some validation is made on the phys address but this ++ * is not exhaustive and we count on the fact that someone using ++ * this feature is supposed to know what he/she's doing. ++ */ ++ if (!data || !(p = strstr((char *)data, "physaddr="))) { ++ printk(KERN_ERR "cramfs: unknown physical address for linear cramfs image\n"); ++ goto out; ++ } ++ sb->CRAMFS_SB_LINEAR_PHYS_ADDR = simple_strtoul(p + 9, NULL, 0); ++ if (sb->CRAMFS_SB_LINEAR_PHYS_ADDR & (PAGE_SIZE-1)) { ++ printk(KERN_ERR "cramfs: physical address 0x%lx for linear cramfs isn't aligned to a page boundary\n", ++ sb->CRAMFS_SB_LINEAR_PHYS_ADDR); ++ goto out; ++ } ++ if (sb->CRAMFS_SB_LINEAR_PHYS_ADDR == 0) { ++ printk(KERN_ERR "cramfs: physical address for linear cramfs image can't be 0\n"); ++ goto out; ++ } ++ printk(KERN_INFO "cramfs: checking physical address 0x%lx for linear cramfs image\n", ++ sb->CRAMFS_SB_LINEAR_PHYS_ADDR); ++ ++ /* Map only one page for now. Will remap it when fs size is known. */ ++ sb->CRAMFS_SB_LINEAR_VIRT_ADDR = ++ ioremap(sb->CRAMFS_SB_LINEAR_PHYS_ADDR, PAGE_SIZE); ++ if (!sb->CRAMFS_SB_LINEAR_VIRT_ADDR) { ++ printk(KERN_ERR "cramfs: ioremap of the linear cramfs image failed\n"); ++ goto out; ++ } ++#endif ++ + down(&read_mutex); + /* Read the first block and get the superblock from it */ + memcpy(&super, cramfs_read(sb, 0, sizeof(super)), sizeof(super)); +@@ -254,8 +402,26 @@ + /* Set it all up.. */ + sb->s_op = &cramfs_ops; + sb->s_root = d_alloc_root(get_cramfs_inode(sb, &super.root)); ++ ++#ifdef CONFIG_CRAMFS_LINEAR ++ /* Remap the whole filesystem now */ ++ iounmap(sb->CRAMFS_SB_LINEAR_VIRT_ADDR); ++ printk(KERN_INFO "cramfs: linear cramfs image appears to be %lu KB in size\n", ++ sb->CRAMFS_SB_SIZE/1024); ++ sb->CRAMFS_SB_LINEAR_VIRT_ADDR = ++ ioremap(sb->CRAMFS_SB_LINEAR_PHYS_ADDR, sb->CRAMFS_SB_SIZE); ++ if (!sb->CRAMFS_SB_LINEAR_VIRT_ADDR) { ++ printk(KERN_ERR "cramfs: ioremap of the linear cramfs image failed\n"); ++ goto out; ++ } ++#endif ++ + retval = sb; + out: ++#ifdef CONFIG_CRAMFS_LINEAR ++ if (!retval && sb->CRAMFS_SB_LINEAR_VIRT_ADDR) ++ iounmap(sb->CRAMFS_SB_LINEAR_VIRT_ADDR); ++#endif + return retval; + } + +@@ -388,6 +554,18 @@ + + maxblock = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + bytes_filled = 0; ++#ifdef CONFIG_CRAMFS_LINEAR_XIP ++ if (page->index < maxblock && CRAMFS_INODE_IS_XIP(inode)) { ++ struct super_block *sb = inode->i_sb; ++ u32 blkptr_offset = PAGE_ALIGN(OFFSET(inode)) + ++ page->index * PAGE_CACHE_SIZE; ++ memcpy( page_address(page), ++ (void*)(sb->CRAMFS_SB_LINEAR_VIRT_ADDR + blkptr_offset), ++ PAGE_CACHE_SIZE ); ++ bytes_filled = PAGE_CACHE_SIZE; ++ pgdata = kmap(page); ++ } else ++#endif + if (page->index < maxblock) { + struct super_block *sb = inode->i_sb; + u32 blkptr_offset = OFFSET(inode) + page->index*4; +@@ -444,7 +622,11 @@ + statfs: cramfs_statfs, + }; + ++#ifndef CONFIG_CRAMFS_LINEAR + static DECLARE_FSTYPE_DEV(cramfs_fs_type, "cramfs", cramfs_read_super); ++#else ++static DECLARE_FSTYPE(cramfs_fs_type, "cramfs", cramfs_read_super, 0); ++#endif + + static int __init init_cramfs_fs(void) + { +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/fs/cramfs/mkcramfs.c 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,821 @@ ++/* ++ * mkcramfs - make a cramfs file system, optionally with XIP files. ++ * ++ * Copyright (C) 1999-2001 Transmeta 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 <sys/types.h> ++#include <stdio.h> ++#include <sys/stat.h> ++#include <unistd.h> ++#include <sys/mman.h> ++#include <sys/fcntl.h> ++#include <dirent.h> ++#include <stdlib.h> ++#include <errno.h> ++#include <string.h> ++#include <assert.h> ++#include <getopt.h> ++#include <linux/cramfs_fs.h> ++#include <zlib.h> ++ ++#define PAD_SIZE 512 /* only 0 and 512 supported by kernel */ ++ ++static const char *progname = "mkcramfs"; ++ ++/* N.B. If you change the disk format of cramfs, please update fs/cramfs/README. */ ++ ++/* Input status of 0 to print help and exit without an error. */ ++static void usage(int status) ++{ ++ FILE *stream = status ? stderr : stdout; ++ ++ fprintf(stream, "usage: %s [-h] [-e edition] [-i file] [-n name] dirname outfile\n" ++ " -h print this help\n" ++ " -E make all warnings errors (non-zero exit status)\n" ++ " -e edition set edition number (part of fsid)\n" ++ " -i file insert a file image into the filesystem (requires >= 2.4.0)\n" ++ " -n name set name of cramfs filesystem\n" ++ " -p pad by %d bytes for boot code\n" ++ " -s sort directory entries (old option, ignored)\n" ++ " -x make marked files eXecute In Place\n" ++ " -z make explicit holes (requires >= 2.3.39)\n" ++ " dirname root of the filesystem to be compressed\n" ++ " outfile output file\n", progname, PAD_SIZE); ++ ++ exit(status); ++} ++ ++#define PAGE_SIZE (4096) ++#define PAGE_ALIGN(x) (((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) ++#define ROM_OFFSET 0 ++#define ROM_ALIGN(x) (PAGE_ALIGN((x) + ROM_OFFSET) - ROM_OFFSET) ++#define PAGE_CACHE_SIZE (4096) ++/* The kernel assumes PAGE_CACHE_SIZE as block size. */ ++static unsigned int blksize = PAGE_CACHE_SIZE; ++static long total_blocks = 0, total_nodes = 1; /* pre-count the root node */ ++static int image_length = 0; ++ ++/* ++ * If opt_holes is set, then mkcramfs can create explicit holes in the ++ * data, which saves 26 bytes per hole (which is a lot smaller a ++ * saving than most most filesystems). ++ * ++ * Note that kernels up to at least 2.3.39 don't support cramfs holes, ++ * which is why this is turned off by default. ++ */ ++static int opt_edition = 0; ++static int opt_errors = 0; ++static int opt_holes = 0; ++static int opt_xip = 0; ++static int opt_pad = 0; ++static char *opt_image = NULL; ++static char *opt_name = NULL; ++ ++static int warn_dev, warn_gid, warn_namelen, warn_skip, warn_size, warn_uid; ++ ++#ifndef MIN ++# define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) ++#endif ++ ++/* In-core version of inode / directory entry. */ ++struct entry { ++ /* stats */ ++ char *name; ++ unsigned int mode, size, uid, gid; ++ ++ /* FS data */ ++ void *uncompressed; ++ /* points to other identical file */ ++ struct entry *same; ++ unsigned int offset; /* pointer to compressed data in archive */ ++ unsigned int dir_offset; /* Where in the archive is the directory entry? */ ++ ++ /* organization */ ++ struct entry *child; /* null for non-directories and empty directories */ ++ struct entry *next; ++}; ++ ++/* ++ * The longest file name component to allow for in the input directory tree. ++ * Ext2fs (and many others) allow up to 255 bytes. A couple of filesystems ++ * allow longer (e.g. smbfs 1024), but there isn't much use in supporting ++ * >255-byte names in the input directory tree given that such names get ++ * truncated to 255 bytes when written to cramfs. ++ */ ++#define MAX_INPUT_NAMELEN 255 ++ ++static int find_identical_file(struct entry *orig,struct entry *newfile) ++{ ++ if(orig==newfile) return 1; ++ if(!orig) return 0; ++ if(orig->size==newfile->size && orig->uncompressed && !memcmp(orig->uncompressed,newfile->uncompressed,orig->size)) { ++ newfile->same=orig; ++ return 1; ++ } ++ return find_identical_file(orig->child,newfile) || ++ find_identical_file(orig->next,newfile); ++} ++ ++static void eliminate_doubles(struct entry *root,struct entry *orig) { ++ if(orig) { ++ if(orig->size && orig->uncompressed) ++ find_identical_file(root,orig); ++ eliminate_doubles(root,orig->child); ++ eliminate_doubles(root,orig->next); ++ } ++} ++ ++/* ++ * We define our own sorting function instead of using alphasort which ++ * uses strcoll and changes ordering based on locale information. ++ */ ++static int cramsort (const void *a, const void *b) ++{ ++ return strcmp ((*(const struct dirent **) a)->d_name, ++ (*(const struct dirent **) b)->d_name); ++} ++ ++static unsigned int parse_directory(struct entry *root_entry, const char *name, struct entry **prev, loff_t *fslen_ub) ++{ ++ struct dirent **dirlist; ++ int totalsize = 0, dircount, dirindex; ++ char *path, *endpath; ++ size_t len = strlen(name); ++ ++ /* Set up the path. */ ++ /* TODO: Reuse the parent's buffer to save memcpy'ing and duplication. */ ++ path = malloc(len + 1 + MAX_INPUT_NAMELEN + 1); ++ if (!path) { ++ perror(NULL); ++ exit(8); ++ } ++ memcpy(path, name, len); ++ endpath = path + len; ++ *endpath = '/'; ++ endpath++; ++ ++ /* read in the directory and sort */ ++ dircount = scandir(name, &dirlist, 0, cramsort); ++ ++ if (dircount < 0) { ++ perror(name); ++ exit(8); ++ } ++ ++ /* process directory */ ++ for (dirindex = 0; dirindex < dircount; dirindex++) { ++ struct dirent *dirent; ++ struct entry *entry; ++ struct stat st; ++ int size; ++ size_t namelen; ++ ++ dirent = dirlist[dirindex]; ++ ++ /* Ignore "." and ".." - we won't be adding them to the archive */ ++ if (dirent->d_name[0] == '.') { ++ if (dirent->d_name[1] == '\0') ++ continue; ++ if (dirent->d_name[1] == '.') { ++ if (dirent->d_name[2] == '\0') ++ continue; ++ } ++ } ++ namelen = strlen(dirent->d_name); ++ if (namelen > MAX_INPUT_NAMELEN) { ++ fprintf(stderr, ++ "Very long (%u bytes) filename `%s' found.\n" ++ " Please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile. Exiting.\n", ++ namelen, dirent->d_name); ++ exit(8); ++ } ++ memcpy(endpath, dirent->d_name, namelen + 1); ++ ++ if (lstat(path, &st) < 0) { ++ perror(endpath); ++ warn_skip = 1; ++ continue; ++ } ++ entry = calloc(1, sizeof(struct entry)); ++ if (!entry) { ++ perror(NULL); ++ exit(8); ++ } ++ entry->name = strdup(dirent->d_name); ++ if (!entry->name) { ++ perror(NULL); ++ exit(8); ++ } ++ if (namelen > 255) { ++ /* Can't happen when reading from ext2fs. */ ++ ++ /* TODO: we ought to avoid chopping in half ++ multi-byte UTF8 characters. */ ++ entry->name[namelen = 255] = '\0'; ++ warn_namelen = 1; ++ } ++ entry->mode = st.st_mode; ++ entry->size = st.st_size; ++ entry->uid = st.st_uid; ++ if (entry->uid >= 1 << CRAMFS_UID_WIDTH) ++ warn_uid = 1; ++ entry->gid = st.st_gid; ++ if (entry->gid >= 1 << CRAMFS_GID_WIDTH) ++ /* TODO: We ought to replace with a default ++ gid instead of truncating; otherwise there ++ are security problems. Maybe mode should ++ be &= ~070. Same goes for uid once Linux ++ supports >16-bit uids. */ ++ warn_gid = 1; ++ size = sizeof(struct cramfs_inode) + ((namelen + 3) & ~3); ++ *fslen_ub += size; ++ if (S_ISDIR(st.st_mode)) { ++ entry->size = parse_directory(root_entry, path, &entry->child, fslen_ub); ++ } else if (S_ISREG(st.st_mode)) { ++ /* TODO: We ought to open files in do_compress, one ++ at a time, instead of amassing all these memory ++ maps during parse_directory (which don't get used ++ until do_compress anyway). As it is, we tend to ++ get EMFILE errors (especially if mkcramfs is run ++ by non-root). ++ ++ While we're at it, do analagously for symlinks ++ (which would just save a little memory). */ ++ int fd = open(path, O_RDONLY); ++ if (fd < 0) { ++ perror(path); ++ warn_skip = 1; ++ continue; ++ } ++ if (entry->size) { ++ if ((entry->size >= 1 << CRAMFS_SIZE_WIDTH)) { ++ warn_size = 1; ++ entry->size = (1 << CRAMFS_SIZE_WIDTH) - 1; ++ } ++ ++ entry->uncompressed = mmap(NULL, entry->size, PROT_READ, MAP_PRIVATE, fd, 0); ++ if (-1 == (int) (long) entry->uncompressed) { ++ perror("mmap"); ++ exit(8); ++ } ++ } ++ close(fd); ++ } else if (S_ISLNK(st.st_mode)) { ++ entry->uncompressed = malloc(entry->size); ++ if (!entry->uncompressed) { ++ perror(NULL); ++ exit(8); ++ } ++ if (readlink(path, entry->uncompressed, entry->size) < 0) { ++ perror(path); ++ warn_skip = 1; ++ continue; ++ } ++ } else if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) { ++ /* maybe we should skip sockets */ ++ entry->size = 0; ++ } else { ++ entry->size = st.st_rdev; ++ if (entry->size & -(1<<CRAMFS_SIZE_WIDTH)) ++ warn_dev = 1; ++ } ++ ++ if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { ++ int blocks = ((entry->size - 1) / blksize + 1); ++ ++ /* block pointers & data expansion allowance + data */ ++ if(entry->size) ++ *fslen_ub += (4+26)*blocks + entry->size + 3; ++ } ++ ++ if (opt_xip && entry->mode & S_ISVTX) { ++ /* worse case, depending on where the offsets falls, ++ * a single XIP entry could expand the sizeof the ++ * file system by 8k, since we're aligning the start ++ * and end on page boundary. ++ */ ++ *fslen_ub += 2*PAGE_CACHE_SIZE; ++ } ++ ++ /* Link it into the list */ ++ *prev = entry; ++ prev = &entry->next; ++ totalsize += size; ++ } ++ free(path); ++ free(dirlist); /* allocated by scandir() with malloc() */ ++ return totalsize; ++} ++ ++/* Returns sizeof(struct cramfs_super), which includes the root inode. */ ++static unsigned int write_superblock(struct entry *root, char *base, int size) ++{ ++ struct cramfs_super *super = (struct cramfs_super *) base; ++ unsigned int offset = sizeof(struct cramfs_super) + image_length; ++ ++ if (opt_pad) { ++ offset += opt_pad; ++ } ++ ++ super->magic = CRAMFS_MAGIC; ++ super->flags = CRAMFS_FLAG_FSID_VERSION_2 | CRAMFS_FLAG_SORTED_DIRS; ++ if (opt_holes) ++ super->flags |= CRAMFS_FLAG_HOLES; ++ if (image_length > 0) ++ super->flags |= CRAMFS_FLAG_SHIFTED_ROOT_OFFSET; ++ super->size = size; ++ memcpy(super->signature, CRAMFS_SIGNATURE, sizeof(super->signature)); ++ ++ super->fsid.crc = crc32(0L, Z_NULL, 0); ++ super->fsid.edition = opt_edition; ++ super->fsid.blocks = total_blocks; ++ super->fsid.files = total_nodes; ++ ++ memset(super->name, 0x00, sizeof(super->name)); ++ if (opt_name) ++ strncpy(super->name, opt_name, sizeof(super->name)); ++ else ++ strncpy(super->name, "Compressed", sizeof(super->name)); ++ ++ super->root.mode = root->mode; ++ super->root.uid = root->uid; ++ super->root.gid = root->gid; ++ super->root.size = root->size; ++ super->root.offset = offset >> 2; ++ ++ return offset; ++} ++ ++static void set_data_offset(struct entry *entry, char *base, unsigned long offset) ++{ ++ struct cramfs_inode *inode = (struct cramfs_inode *) (base + entry->dir_offset); ++#ifdef DEBUG ++ assert ((offset & 3) == 0); ++#endif /* DEBUG */ ++ if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH))) { ++ fprintf(stderr, "filesystem too big. Exiting.\n"); ++ exit(8); ++ } ++ inode->offset = (offset >> 2); ++} ++ ++ ++/* ++ * We do a width-first printout of the directory ++ * entries, using a stack to remember the directories ++ * we've seen. ++ */ ++#define MAXENTRIES (100) ++static unsigned int write_directory_structure(struct entry *entry, char *base, unsigned int offset) ++{ ++ int stack_entries = 0; ++ struct entry *entry_stack[MAXENTRIES]; ++ ++ for (;;) { ++ int dir_start = stack_entries; ++ while (entry) { ++ struct cramfs_inode *inode = (struct cramfs_inode *) (base + offset); ++ size_t len = strlen(entry->name); ++ ++ entry->dir_offset = offset; ++ ++ inode->mode = entry->mode; ++ inode->uid = entry->uid; ++ inode->gid = entry->gid; ++ inode->size = entry->size; ++ inode->offset = 0; ++ /* Non-empty directories, regfiles and symlinks will ++ write over inode->offset later. */ ++ ++ offset += sizeof(struct cramfs_inode); ++ total_nodes++; /* another node */ ++ memcpy(base + offset, entry->name, len); ++ /* Pad up the name to a 4-byte boundary */ ++ while (len & 3) { ++ *(base + offset + len) = '\0'; ++ len++; ++ } ++ inode->namelen = len >> 2; ++ offset += len; ++ ++ /* TODO: this may get it wrong for chars >= 0x80. ++ Most filesystems use UTF8 encoding for filenames, ++ whereas the console is a single-byte character ++ set like iso-latin-1. */ ++ printf(" %s\n", entry->name); ++ if (entry->child) { ++ if (stack_entries >= MAXENTRIES) { ++ fprintf(stderr, "Exceeded MAXENTRIES. Raise this value in mkcramfs.c and recompile. Exiting.\n"); ++ exit(8); ++ } ++ entry_stack[stack_entries] = entry; ++ stack_entries++; ++ } ++ entry = entry->next; ++ } ++ ++ /* ++ * Reverse the order the stack entries pushed during ++ * this directory, for a small optimization of disk ++ * access in the created fs. This change makes things ++ * `ls -UR' order. ++ */ ++ { ++ struct entry **lo = entry_stack + dir_start; ++ struct entry **hi = entry_stack + stack_entries; ++ struct entry *tmp; ++ ++ while (lo < --hi) { ++ tmp = *lo; ++ *lo++ = *hi; ++ *hi = tmp; ++ } ++ } ++ ++ /* Pop a subdirectory entry from the stack, and recurse. */ ++ if (!stack_entries) ++ break; ++ stack_entries--; ++ entry = entry_stack[stack_entries]; ++ ++ set_data_offset(entry, base, offset); ++ printf("'%s':\n", entry->name); ++ entry = entry->child; ++ } ++ return offset; ++} ++ ++static int is_zero(char const *begin, unsigned len) ++{ ++ if (opt_holes) ++ /* Returns non-zero iff the first LEN bytes from BEGIN are ++ all NULs. */ ++ return (len-- == 0 || ++ (begin[0] == '\0' && ++ (len-- == 0 || ++ (begin[1] == '\0' && ++ (len-- == 0 || ++ (begin[2] == '\0' && ++ (len-- == 0 || ++ (begin[3] == '\0' && ++ memcmp(begin, begin + 4, len) == 0)))))))); ++ else ++ /* Never create holes. */ ++ return 0; ++} ++ ++static unsigned int do_xip(char *base, unsigned int offset, ++ char const *name, char *uncompressed, ++ unsigned int size) ++{ ++ unsigned int start, end; ++ ++ /* align to page boundary */ ++ ++ start = ROM_ALIGN(offset); ++ memset(base + offset, 0, start - offset); ++ ++ memcpy(base + start, uncompressed, size); ++ ++ /* pad to page boundary */ ++ ++ end = ROM_ALIGN(start + size); ++ memset(base + start + size, 0, end - (start + size)); ++ ++ printf("XIP (%u+%u bytes)\toffset %u\t%s\n", ++ size, (end - offset) - size, offset, name); ++ ++ return end; ++} ++ ++/* ++ * One 4-byte pointer per block and then the actual blocked ++ * output. The first block does not need an offset pointer, ++ * as it will start immediately after the pointer block; ++ * so the i'th pointer points to the end of the i'th block ++ * (i.e. the start of the (i+1)'th block or past EOF). ++ * ++ * Note that size > 0, as a zero-sized file wouldn't ever ++ * have gotten here in the first place. ++ */ ++static unsigned int do_compress(char *base, unsigned int offset, char const *name, char *uncompressed, unsigned int size) ++{ ++ unsigned long original_size = size; ++ unsigned long original_offset = offset; ++ unsigned long new_size; ++ unsigned long blocks = (size - 1) / blksize + 1; ++ unsigned long curr = offset + 4 * blocks; ++ int change; ++ ++ total_blocks += blocks; ++ ++ do { ++ unsigned long len = 2 * blksize; ++ unsigned int input = size; ++ if (input > blksize) ++ input = blksize; ++ size -= input; ++ if (!is_zero (uncompressed, input)) { ++ compress(base + curr, &len, uncompressed, input); ++ curr += len; ++ } ++ uncompressed += input; ++ ++ if (len > blksize*2) { ++ /* (I don't think this can happen with zlib.) */ ++ printf("AIEEE: block \"compressed\" to > 2*blocklength (%ld)\n", len); ++ exit(8); ++ } ++ ++ *(u32 *) (base + offset) = curr; ++ offset += 4; ++ } while (size); ++ ++ curr = (curr + 3) & ~3; ++ new_size = curr - original_offset; ++ /* TODO: Arguably, original_size in these 2 lines should be ++ st_blocks * 512. But if you say that then perhaps ++ administrative data should also be included in both. */ ++ change = new_size - original_size; ++ printf("%6.2f%% (%+d bytes)\toffset %lu\t%s\n", ++ (change * 100) / (double) original_size, change, original_offset, name); ++ ++ return curr; ++} ++ ++ ++/* ++ * Traverse the entry tree, writing data for every item that has ++ * non-null entry->compressed (i.e. every symlink and non-empty ++ * regfile). ++ */ ++static unsigned int write_data(struct entry *entry, char *base, unsigned int offset) ++{ ++ do { ++ if (entry->uncompressed) { ++ if(entry->same) { ++ set_data_offset(entry, base, entry->same->offset); ++ entry->offset=entry->same->offset; ++ } else { ++ set_data_offset(entry, base, offset); ++ entry->offset=offset; ++ if (opt_xip && entry->mode & S_ISVTX) ++ offset = do_xip(base, offset, entry->name, entry->uncompressed, entry->size); ++ else ++ offset = do_compress(base, offset, entry->name, entry->uncompressed, entry->size); ++ } ++ } ++ else if (entry->child) ++ offset = write_data(entry->child, base, offset); ++ entry=entry->next; ++ } while (entry); ++ return offset; ++} ++ ++static unsigned int write_file(char *file, char *base, unsigned int offset) ++{ ++ int fd; ++ char *buf; ++ ++ fd = open(file, O_RDONLY); ++ if (fd < 0) { ++ perror(file); ++ exit(8); ++ } ++ buf = mmap(NULL, image_length, PROT_READ, MAP_PRIVATE, fd, 0); ++ memcpy(base + offset, buf, image_length); ++ munmap(buf, image_length); ++ close (fd); ++ /* Pad up the image_length to a 4-byte boundary */ ++ while (image_length & 3) { ++ *(base + offset + image_length) = '\0'; ++ image_length++; ++ } ++ return (offset + image_length); ++} ++ ++/* ++ * Maximum size fs you can create is roughly 256MB. (The last file's ++ * data must begin within 256MB boundary but can extend beyond that.) ++ * ++ * Note that if you want it to fit in a ROM then you're limited to what the ++ * hardware and kernel can support (64MB?). ++ */ ++#define MAXFSLEN ((((1 << CRAMFS_OFFSET_WIDTH) - 1) << 2) /* offset */ \ ++ + (1 << CRAMFS_SIZE_WIDTH) - 1 /* filesize */ \ ++ + (1 << CRAMFS_SIZE_WIDTH) * 4 / PAGE_CACHE_SIZE /* block pointers */ ) ++ ++ ++/* ++ * Usage: ++ * ++ * mkcramfs directory-name outfile ++ * ++ * where "directory-name" is simply the root of the directory ++ * tree that we want to generate a compressed filesystem out ++ * of. ++ */ ++int main(int argc, char **argv) ++{ ++ struct stat st; /* used twice... */ ++ struct entry *root_entry; ++ char *rom_image; ++ ssize_t offset, written; ++ int fd; ++ /* initial guess (upper-bound) of required filesystem size */ ++ loff_t fslen_ub = sizeof(struct cramfs_super); ++ char const *dirname, *outfile; ++ u32 crc = crc32(0L, Z_NULL, 0); ++ int c; /* for getopt */ ++ ++ total_blocks = 0; ++ ++ if (argc) ++ progname = argv[0]; ++ ++ /* command line options */ ++ while ((c = getopt(argc, argv, "hEe:i:n:psxz")) != EOF) { ++ switch (c) { ++ case 'h': ++ usage(0); ++ case 'E': ++ opt_errors = 1; ++ break; ++ case 'e': ++ opt_edition = atoi(optarg); ++ break; ++ case 'i': ++ opt_image = optarg; ++ if (lstat(opt_image, &st) < 0) { ++ perror(opt_image); ++ exit(16); ++ } ++ image_length = st.st_size; /* may be padded later */ ++ fslen_ub += (image_length + 3); /* 3 is for padding */ ++ break; ++ case 'n': ++ opt_name = optarg; ++ break; ++ case 'p': ++ opt_pad = PAD_SIZE; ++ fslen_ub += PAD_SIZE; ++ break; ++ case 's': ++ /* old option, ignored */ ++ break; ++ case 'x': ++ opt_xip = 1; ++ break; ++ case 'z': ++ opt_holes = 1; ++ break; ++ } ++ } ++ ++ if ((argc - optind) != 2) ++ usage(16); ++ dirname = argv[optind]; ++ outfile = argv[optind + 1]; ++ ++ if (stat(dirname, &st) < 0) { ++ perror(dirname); ++ exit(16); ++ } ++ fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666); ++ ++ root_entry = calloc(1, sizeof(struct entry)); ++ if (!root_entry) { ++ perror(NULL); ++ exit(8); ++ } ++ root_entry->mode = st.st_mode; ++ root_entry->uid = st.st_uid; ++ root_entry->gid = st.st_gid; ++ ++ root_entry->size = parse_directory(root_entry, dirname, &root_entry->child, &fslen_ub); ++ ++ /* always allocate a multiple of blksize bytes because that's ++ what we're going to write later on */ ++ fslen_ub = ((fslen_ub - 1) | (blksize - 1)) + 1; ++ ++ if (fslen_ub > MAXFSLEN) { ++ fprintf(stderr, ++ "warning: guestimate of required size (upper bound) is %LdMB, but maximum image size is %uMB. We might die prematurely.\n", ++ fslen_ub >> 20, ++ MAXFSLEN >> 20); ++ fslen_ub = MAXFSLEN; ++ } ++ ++ /* find duplicate files. TODO: uses the most inefficient algorithm ++ possible. */ ++ eliminate_doubles(root_entry,root_entry); ++ ++ /* TODO: Why do we use a private/anonymous mapping here ++ followed by a write below, instead of just a shared mapping ++ and a couple of ftruncate calls? Is it just to save us ++ having to deal with removing the file afterwards? If we ++ really need this huge anonymous mapping, we ought to mmap ++ in smaller chunks, so that the user doesn't need nn MB of ++ RAM free. If the reason is to be able to write to ++ un-mmappable block devices, then we could try shared mmap ++ and revert to anonymous mmap if the shared mmap fails. */ ++ rom_image = mmap(NULL, fslen_ub?fslen_ub:1, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ++ ++ if (-1 == (int) (long) rom_image) { ++ perror("ROM image map"); ++ exit(8); ++ } ++ ++ /* Skip the first opt_pad bytes for boot loader code */ ++ offset = opt_pad; ++ memset(rom_image, 0x00, opt_pad); ++ ++ /* Skip the superblock and come back to write it later. */ ++ offset += sizeof(struct cramfs_super); ++ ++ /* Insert a file image. */ ++ if (opt_image) { ++ printf("Including: %s\n", opt_image); ++ offset = write_file(opt_image, rom_image, offset); ++ } ++ ++ offset = write_directory_structure(root_entry->child, rom_image, offset); ++ printf("Directory data: %d bytes\n", offset); ++ ++ offset = write_data(root_entry, rom_image, offset); ++ ++ /* We always write a multiple of blksize bytes, so that ++ losetup works. */ ++ offset = ((offset - 1) | (blksize - 1)) + 1; ++ printf("Everything: %d kilobytes\n", offset >> 10); ++ ++ /* Write the superblock now that we can fill in all of the fields. */ ++ write_superblock(root_entry, rom_image+opt_pad, offset); ++ printf("Super block: %d bytes\n", sizeof(struct cramfs_super)); ++ ++ /* Put the checksum in. */ ++ crc = crc32(crc, (rom_image+opt_pad), (offset-opt_pad)); ++ ((struct cramfs_super *) (rom_image+opt_pad))->fsid.crc = crc; ++ printf("CRC: %x\n", crc); ++ ++ /* Check to make sure we allocated enough space. */ ++ if (fslen_ub < offset) { ++ fprintf(stderr, "not enough space allocated for ROM image (%Ld allocated, %d used)\n", ++ fslen_ub, offset); ++ exit(8); ++ } ++ ++ written = write(fd, rom_image, offset); ++ if (written < 0) { ++ perror("ROM image"); ++ exit(8); ++ } ++ if (offset != written) { ++ fprintf(stderr, "ROM image write failed (%d %d)\n", written, offset); ++ exit(8); ++ } ++ ++ /* (These warnings used to come at the start, but they scroll off the ++ screen too quickly.) */ ++ if (warn_namelen) /* (can't happen when reading from ext2fs) */ ++ fprintf(stderr, /* bytes, not chars: think UTF8. */ ++ "warning: filenames truncated to 255 bytes.\n"); ++ if (warn_skip) ++ fprintf(stderr, "warning: files were skipped due to errors.\n"); ++ if (warn_size) ++ fprintf(stderr, ++ "warning: file sizes truncated to %luMB (minus 1 byte).\n", ++ 1L << (CRAMFS_SIZE_WIDTH - 20)); ++ if (warn_uid) /* (not possible with current Linux versions) */ ++ fprintf(stderr, ++ "warning: uids truncated to %u bits. (This may be a security concern.)\n", ++ CRAMFS_UID_WIDTH); ++ if (warn_gid) ++ fprintf(stderr, ++ "warning: gids truncated to %u bits. (This may be a security concern.)\n", ++ CRAMFS_GID_WIDTH); ++ if (warn_dev) ++ fprintf(stderr, ++ "WARNING: device numbers truncated to %u bits. This almost certainly means\n" ++ "that some device files will be wrong.\n", ++ CRAMFS_OFFSET_WIDTH); ++ if (opt_errors && ++ (warn_namelen||warn_skip||warn_size||warn_uid||warn_gid||warn_dev)) ++ exit(8); ++ return 0; ++} +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/bitfield.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,113 @@ ++/* ++ * FILE bitfield.h ++ * ++ * Version 1.1 ++ * Author Copyright (c) Marc A. Viredaz, 1998 ++ * DEC Western Research Laboratory, Palo Alto, CA ++ * Date April 1998 (April 1997) ++ * System Advanced RISC Machine (ARM) ++ * Language C or ARM Assembly ++ * Purpose Definition of macros to operate on bit fields. ++ */ ++ ++ ++ ++#ifndef __BITFIELD_H ++#define __BITFIELD_H ++ ++#ifndef __ASSEMBLY__ ++#define UData(Data) ((unsigned long) (Data)) ++#else ++#define UData(Data) (Data) ++#endif ++ ++ ++/* ++ * MACRO: Fld ++ * ++ * Purpose ++ * The macro "Fld" encodes a bit field, given its size and its shift value ++ * with respect to bit 0. ++ * ++ * Note ++ * A more intuitive way to encode bit fields would have been to use their ++ * mask. However, extracting size and shift value information from a bit ++ * field's mask is cumbersome and might break the assembler (255-character ++ * line-size limit). ++ * ++ * Input ++ * Size Size of the bit field, in number of bits. ++ * Shft Shift value of the bit field with respect to bit 0. ++ * ++ * Output ++ * Fld Encoded bit field. ++ */ ++ ++#define Fld(Size, Shft) (((Size) << 16) + (Shft)) ++ ++ ++/* ++ * MACROS: FSize, FShft, FMsk, FAlnMsk, F1stBit ++ * ++ * Purpose ++ * The macros "FSize", "FShft", "FMsk", "FAlnMsk", and "F1stBit" return ++ * the size, shift value, mask, aligned mask, and first bit of a ++ * bit field. ++ * ++ * Input ++ * Field Encoded bit field (using the macro "Fld"). ++ * ++ * Output ++ * FSize Size of the bit field, in number of bits. ++ * FShft Shift value of the bit field with respect to bit 0. ++ * FMsk Mask for the bit field. ++ * FAlnMsk Mask for the bit field, aligned on bit 0. ++ * F1stBit First bit of the bit field. ++ */ ++ ++#define FSize(Field) ((Field) >> 16) ++#define FShft(Field) ((Field) & 0x0000FFFF) ++#define FMsk(Field) (((UData (1) << FSize (Field)) - 1) << FShft (Field)) ++#define FAlnMsk(Field) ((UData (1) << FSize (Field)) - 1) ++#define F1stBit(Field) (UData (1) << FShft (Field)) ++ ++ ++/* ++ * MACRO: FInsrt ++ * ++ * Purpose ++ * The macro "FInsrt" inserts a value into a bit field by shifting the ++ * former appropriately. ++ * ++ * Input ++ * Value Bit-field value. ++ * Field Encoded bit field (using the macro "Fld"). ++ * ++ * Output ++ * FInsrt Bit-field value positioned appropriately. ++ */ ++ ++#define FInsrt(Value, Field) \ ++ (UData (Value) << FShft (Field)) ++ ++ ++/* ++ * MACRO: FExtr ++ * ++ * Purpose ++ * The macro "FExtr" extracts the value of a bit field by masking and ++ * shifting it appropriately. ++ * ++ * Input ++ * Data Data containing the bit-field to be extracted. ++ * Field Encoded bit field (using the macro "Fld"). ++ * ++ * Output ++ * FExtr Bit-field value. ++ */ ++ ++#define FExtr(Data, Field) \ ++ ((UData (Data) >> FShft (Field)) & FAlnMsk (Field)) ++ ++ ++#endif /* __BITFIELD_H */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/cerf.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,177 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/cerf.h ++ * ++ * 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. ++ */ ++ ++/* ++ * Add CerfBoard Specifics here... ++ */ ++ ++/* ++ * Memory sizes ++ */ ++ ++#define CERF_RAM_BASE 0xa0000000 ++ ++#ifdef CONFIG_PXA_CERF_RAM_128MB ++#define CERF_RAM_SIZE 128*1024*1024 ++ ++#elif defined (CONFIG_PXA_CERF_RAM_64MB) ++#define CERF_RAM_SIZE 64*1024*1024 ++ ++#elif defined (CONFIG_PXA_CERF_RAM_32MB) ++#define CERF_RAM_SIZE 32*1024*1024 ++ ++#elif defined (CONFIG_PXA_CERF_RAM_16MB) ++#define CERF_RAM_SIZE 16*1024*1024 ++#endif ++ ++/* ++ * CS memory timing via Static Memory Control Register (MSC0-2) ++ */ ++ ++#define MSC_CS(cs,val) ((val)<<((cs&1)<<4)) ++ ++#define MSC_RBUFF_SHIFT 15 ++#define MSC_RBUFF_SLOW (0) ++#define MSC_RBUFF_FAST (1) ++#define MSC_RBUFF(x) ((x)<<MSC_RBUFF_SHIFT) ++ ++#define MSC_RRR_SHIFT 12 ++#define MSC_RRR(x) ((x)<<MSC_RRR_SHIFT) ++ ++#define MSC_RDN_SHIFT 8 ++#define MSC_RDN(x) ((x)<<MSC_RDN_SHIFT) ++ ++#define MSC_RDF_SHIFT 4 ++#define MSC_RDF(x) ((x)<<MSC_RDF_SHIFT) ++ ++#define MSC_RBW_SHIFT 3 ++#define MSC_RBW(x) ((x)<<MSC_RBW_SHIFT) ++ ++#define MSC_RT_SHIFT 0 ++#define MSC_RT(x) ((x)<<MSC_RT_SHIFT) ++ ++/* ++ * IO Pins for devices ++ */ ++ ++#define CERF_FLASH_BASE 0xe8000000 ++#define CERF_FLASH_SIZE 0x02000000 ++#define CERF_FLASH_PHYS PXA_CS0_PHYS ++ ++#define CERF_ETH_BASE 0xf0000000 ++#define CERF_ETH_SIZE 0x00100000 ++#define CERF_ETH_PHYS PXA_CS1_PHYS ++ ++#define CERF_BT_BASE 0xf2000000 ++#define CERF_BT_SIZE 0x00100000 ++#define CERF_BT_PHYS PXA_CS2_PHYS ++ ++#define CERF_SERIAL_BASE 0xf3000000 ++#define CERF_SERIAL_SIZE 0x00100000 ++#define CERF_SERIAL_PHYS PXA_CS3_PHYS ++ ++#define CERF_CPLD_BASE 0xf1000000 ++#define CERF_CPLD_SIZE 0x00100000 ++#define CERF_CPLD_PHYS PXA_CS4_PHYS ++ ++#define CERF_PDA_CPLD_WRCLRINT (0x0) ++#define CERF_PDA_CPLD_BRIGHTNESS (0x2) ++#define CERF_PDA_CPLD_KEYPAD_A (0x6) ++#define CERF_PDA_CPLD_BATTFAULT (0x8) ++#define CERF_PDA_CPLD_KEYPAD_B (0xa) ++#define CERF_PDA_CPLD_SOUND_ENA (0xc) ++ ++#define CERF_PDA_SOUND_ENABLE 0x1 ++#define CERF_PDA_DEFAULT_BRIGHTNESS 0x9 ++ ++/* ++ * Access functions (registers are 4-bit wide) ++ */ ++ ++#define CERF_PDA_CPLD CERF_CPLD_BASE ++ ++#define CERF_PDA_CPLD_Get(x, y) (*((char*)(CERF_PDA_CPLD + (x))) & (y)) ++#define CERF_PDA_CPLD_Set(x, y, z) (*((char*)(CERF_PDA_CPLD + (x))) = (*((char*)(CERF_PDA_CPLD + (x))) & ~(z)) | (y)) ++#define CERF_PDA_CPLD_UnSet(x, y, z) (*((char*)(CERF_PDA_CPLD + (x))) = (*((char*)(CERF_PDA_CPLD + (x))) & ~(z)) & ~(y)) ++ ++/* ++ * IO and IRQ settings for cs8900 ethernet chip ++ */ ++#define CERF_ETH_IO CERF_ETH_BASE ++#define CERF_ETH_IRQ GPIO_2_80_TO_IRQ(21) ++ ++/* ++ * We only have one LED on the XScale CerfPDA so only the ++ * time or idle should ever be selected. ++ */ ++#define CERF_HEARTBEAT_LED 0x1 ++#define CERF_SYS_BUSY_LED 0x2 ++ ++#define CERF_HEARTBEAT_LED_GPIO 16 // GPIO 4 ++#define CERF_SYS_BUSY_LED_GPIO 16 // GPIO 4 ++ ++#define CERF_HEARTBEAT_LED_ON (GPSR0 = CERF_HEARTBEAT_LED_GPIO) ++#define CERF_HEARTBEAT_LED_OFF (GPCR0 = CERF_HEARTBEAT_LED_GPIO) ++#define CERF_SYS_BUSY_LED_ON (GPSR0 = CERF_SYS_BUSY_LED_GPIO) ++#define CERF_SYS_BUSY_LED_OFF (GPCR0 = CERF_SYS_BUSY_LED_GPIO) ++ ++/* ++ * UCB 1400 gpio ++ */ ++ ++#define CERF_GPIO_UCB1400_IRQ 32 ++ ++#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 UCB1400_GPIO_CONT_CS UCB_IO_0 ++#define UCB1400_GPIO_CONT_DOWN UCB_IO_1 ++#define UCB1400_GPIO_CONT_INC UCB_IO_2 ++#define UCB1400_GPIO_CONT_ENA UCB_IO_3 ++#define UCB1400_GPIO_LCD_RESET UCB_IO_4 ++#define UCB1400_GPIO_IRDA_ENABLE UCB_IO_5 ++#define UCB1400_GPIO_BT_ENABLE UCB_IO_6 ++#define UCB1400_GPIO_TEST_P1 UCB_IO_7 ++#define UCB1400_GPIO_TEST_P2 UCB_IO_8 ++#define UCB1400_GPIO_TEST_P3 UCB_IO_9 ++ ++/* ++ * IRQ for devices ++ */ ++#define UCB1400_IRQ(x) (NR_IRQS + 1 + (x)) ++ ++#define IRQ_UCB1400_IO0 UCB1400_IRQ(0) ++#define IRQ_UCB1400_IO1 UCB1400_IRQ(1) ++#define IRQ_UCB1400_IO2 UCB1400_IRQ(2) ++#define IRQ_UCB1400_IO3 UCB1400_IRQ(3) ++#define IRQ_UCB1400_IO4 UCB1400_IRQ(4) ++#define IRQ_UCB1400_IO5 UCB1400_IRQ(5) ++#define IRQ_UCB1400_IO6 UCB1400_IRQ(6) ++#define IRQ_UCB1400_IO7 UCB1400_IRQ(7) ++#define IRQ_UCB1400_IO8 UCB1400_IRQ(8) ++#define IRQ_UCB1400_IO9 UCB1400_IRQ(9) ++ ++#define IRQ_UCB1400_CONT_CS IRQ_UCB1400_IO0 ++#define IRQ_UCB1400_CONT_DOWN IRQ_UCB1400_IO1 ++#define IRQ_UCB1400_CONT_INC IRQ_UCB1400_IO2 ++#define IRQ_UCB1400_CONT_ENA IRQ_UCB1400_IO3 ++#define IRQ_UCB1400_LCD_RESET IRQ_UCB1400_IO4 ++#define IRQ_UCB1400_IRDA_ENABLE IRQ_UCB1400_IO5 ++#define IRQ_UCB1400_BT_ENABLE IRQ_UCB1400_IO6 ++#define IRQ_UCB1400_TEST_P1 IRQ_UCB1400_IO7 ++#define IRQ_UCB1400_TEST_P2 IRQ_UCB1400_IO8 ++#define IRQ_UCB1400_TEST_P3 IRQ_UCB1400_IO9 ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/cerf_ucb1400gpio.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,30 @@ ++/* ++ * cerf_ucb1400gpio.h ++ * ++ * UCB1400 GPIO control stuff for the cerf. ++ * ++ * 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. ++ * ++ * History: ++ * Mar 2002: Initial version [FB] ++ * ++ */ ++/* -- lcd -- */ ++extern void cerf_ucb1400gpio_lcd_enable( void); ++extern void cerf_ucb1400gpio_lcd_disable( void); ++extern void cerf_ucb1400gpio_lcd_contrast_step( int direction); ++ ++/* -- irda -- */ ++extern void cerf_ucb1400gpio_irda_enable( void); ++extern void cerf_ucb1400gpio_irda_disable( void); ++ ++/* -- bt -- */ ++extern void cerf_ucb1400gpio_bt_enable( void); ++extern void cerf_ucb1400gpio_bt_disable( void); ++ ++/* -- init -- */ ++extern int cerf_ucb1400gpio_init(void); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/csb226.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,99 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/csb226.h ++ * ++ * Author: Robert Schwebel (stolen from lubbock.h) ++ * Created: Oct 30, 2002 ++ * Copyright: Pengutronix ++ * ++ * 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. ++ */ ++ ++#define CSB226_FPGA_PHYS PXA_CS2_PHYS ++ ++#define CSB226_FPGA_VIRT (0xf0000000) /* phys 0x08000000 */ ++#define CSB226_ETH_BASE (0xf1000000) /* phys 0x0c000000 */ ++ ++#define CSB226_P2V(x) ((x) - CSB226_FPGA_PHYS + CSB226_FPGA_VIRT) ++#define CSB226_V2P(x) ((x) - CSB226_FPGA_VIRT + CSB226_FPGA_PHYS) ++ ++#ifndef __ASSEMBLY__ ++# define __CSB226_REG(x) (*((volatile unsigned long *)CSB226_P2V(x))) ++#else ++# define __CSB226_REG(x) CSB226_P2V(x) ++#endif ++ ++ ++/* register physical addresses */ ++#define _CSB226_MISC_WR (CSB226_FPGA_PHYS + 0x080) ++#define _CSB226_MISC_RD (CSB226_FPGA_PHYS + 0x090) ++#define _CSB226_IRQ_MASK_EN (CSB226_FPGA_PHYS + 0x0C0) ++#define _CSB226_IRQ_SET_CLR (CSB226_FPGA_PHYS + 0x0D0) ++#define _CSB226_GP (CSB226_FPGA_PHYS + 0x100) ++ ++ ++ ++/* register virtual addresses */ ++ ++#define CSB226_MISC_WR __CSB226_REG(_CSB226_MISC_WR) ++#define CSB226_MISC_RD __CSB226_REG(_CSB226_MISC_RD) ++#define CSB226_IRQ_MASK_EN __CSB226_REG(_CSB226_IRQ_MASK_EN) ++#define CSB226_IRQ_SET_CLR __CSB226_REG(_CSB226_IRQ_SET_CLR) ++#define CSB226_GP __CSB226_REG(_CSB226_GP) ++ ++ ++/* GPIOs */ ++ ++#define GPIO_CSB226_IRQ 0 ++#define IRQ_GPIO_CSB226_IRQ IRQ_GPIO0 ++ ++ ++/* ++ * LED macros ++ */ ++ ++// #define LEDS_BASE LUB_DISC_BLNK_LED ++ ++// 8 discrete leds available for general use: ++ ++/* ++#define D28 0x1 ++#define D27 0x2 ++#define D26 0x4 ++#define D25 0x8 ++#define D24 0x10 ++#define D23 0x20 ++#define D22 0x40 ++#define D21 0x80 ++*/ ++ ++/* Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays so ++* be sure to not monkey with them here. ++*/ ++ ++/* ++#define HEARTBEAT_LED D28 ++#define SYS_BUSY_LED D27 ++#define HEXLEDS_BASE LUB_HEXLED ++ ++#define HEARTBEAT_LED_ON (LEDS_BASE &= ~HEARTBEAT_LED) ++#define HEARTBEAT_LED_OFF (LEDS_BASE |= HEARTBEAT_LED) ++#define SYS_BUSY_LED_OFF (LEDS_BASE |= SYS_BUSY_LED) ++#define SYS_BUSY_LED_ON (LEDS_BASE &= ~SYS_BUSY_LED) ++ ++// use x = D26-D21 for these, please... ++#define DISCRETE_LED_ON(x) (LEDS_BASE &= ~(x)) ++#define DISCRETE_LED_OFF(x) (LEDS_BASE |= (x)) ++*/ ++ ++#ifndef __ASSEMBLY__ ++ ++//extern int hexled_val = 0; ++ ++#endif ++ ++/* ++#define BUMP_COUNTER (HEXLEDS_BASE = hexled_val++) ++#define DEC_COUNTER (HEXLEDS_BASE = hexled_val--) ++*/ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/dma.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,49 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/dma.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista 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 __ASM_ARCH_DMA_H ++#define __ASM_ARCH_DMA_H ++ ++#define MAX_DMA_ADDRESS 0xffffffff ++ ++/* No DMA as the rest of the world see it */ ++#define MAX_DMA_CHANNELS 0 ++ ++/* ++ * Descriptor structure for PXA's DMA engine ++ * Note: this structure must always be aligned to a 16-byte boundary. ++ */ ++ ++typedef struct { ++ volatile u32 ddadr; /* Points to the next descriptor + flags */ ++ volatile u32 dsadr; /* DSADR value for the current transfer */ ++ volatile u32 dtadr; /* DTADR value for the current transfer */ ++ volatile u32 dcmd; /* DCMD value for the current transfer */ ++} pxa_dma_desc; ++ ++/* ++ * DMA registration ++ */ ++ ++typedef enum { ++ DMA_PRIO_HIGH = 0, ++ DMA_PRIO_MEDIUM = 4, ++ DMA_PRIO_LOW = 8 ++} pxa_dma_prio; ++ ++int pxa_request_dma (char *name, ++ pxa_dma_prio prio, ++ void (*irq_handler)(int, void *, struct pt_regs *), ++ void *data); ++ ++void pxa_free_dma (int dma_ch); ++ ++#endif /* _ASM_ARCH_DMA_H */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/hardware.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,142 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/hardware.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista 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 __ASM_ARCH_HARDWARE_H ++#define __ASM_ARCH_HARDWARE_H ++ ++#include <linux/config.h> ++#include <asm/mach-types.h> ++ ++ ++/* ++ * These are statically mapped PCMCIA IO space for designs using it as a ++ * generic IO bus, typically with ISA parts, hardwired IDE interfaces, etc. ++ * The actual PCMCIA code is mapping required IO region at run time. ++ */ ++#define PCMCIA_IO_0_BASE 0xf6000000 ++#define PCMCIA_IO_1_BASE 0xf7000000 ++ ++ ++/* ++ * XIP kernel text mapping. ++ * Note: the exact virtual address is also specified in arch/arm/Makefile. ++ */ ++#ifdef CONFIG_XIP_KERNEL ++#define KERNEL_XIP_BASE_PHYS (CONFIG_XIP_PHYS_ADDR & 0xffe00000) ++#define KERNEL_XIP_BASE_VIRT 0xe8000000 ++#endif ++ ++ ++/* ++ * We requires absolute addresses. ++ */ ++#define PCIO_BASE 0 ++ ++/* ++ * Workarounds for at least 2 errata so far require this. ++ * The mapping is set in mach-pxa/generic.c. ++ */ ++#define UNCACHED_PHYS_0 0xff000000 ++#define UNCACHED_ADDR UNCACHED_PHYS_0 ++ ++/* ++ * Intel PXA internal I/O mappings: ++ * ++ * 0x40000000 - 0x41ffffff <--> 0xf8000000 - 0xf9ffffff ++ * 0x44000000 - 0x45ffffff <--> 0xfa000000 - 0xfbffffff ++ * 0x48000000 - 0x49ffffff <--> 0xfc000000 - 0xfdffffff ++ */ ++ ++#define io_p2v(x) ( ((x) | 0xbe000000) ^ (~((x) >> 1) & 0x06000000) ) ++#define io_v2p( x ) ( ((x) & 0x41ffffff) ^ ( ((x) & 0x06000000) << 1) ) ++ ++#ifndef __ASSEMBLY__ ++ ++#if 0 ++# define __REG(x) (*((volatile u32 *)io_p2v(x))) ++#else ++/* ++ * This __REG() version gives the same results as the one above, except ++ * that we are fooling gcc somehow so it generates far better and smaller ++ * assembly code for access to contigous registers. It's a shame that gcc ++ * doesn't guess this by itself. ++ */ ++#include <asm/types.h> ++typedef struct { volatile u32 offset[4096]; } __regbase; ++# define __REGP(x) ((__regbase *)((x)&~4095))->offset[((x)&4095)>>2] ++# define __REG(x) __REGP(io_p2v(x)) ++#endif ++ ++/* Let's kick gcc's ass again... */ ++# define __REG2(x,y) \ ++ ( __builtin_constant_p(y) ? (__REG((x) + (y))) \ ++ : (*(volatile u32 *)((u32)&__REG(x) + (y))) ) ++ ++# define __PREG(x) (io_v2p((u32)&(x))) ++ ++#else ++ ++# define __REG(x) io_p2v(x) ++# define __PREG(x) io_v2p(x) ++ ++#endif ++ ++#include "pxa-regs.h" ++ ++#ifndef __ASSEMBLY__ ++ ++/* ++ * GPIO edge detection for IRQs: ++ * IRQs are generated on Falling-Edge, Rising-Edge, or both. ++ * This must be called *before* the corresponding IRQ is registered. ++ * Use this instead of directly setting GRER/GFER. ++ */ ++#define GPIO_FALLING_EDGE 1 ++#define GPIO_RISING_EDGE 2 ++#define GPIO_BOTH_EDGES 3 ++extern void set_GPIO_IRQ_edge( int gpio_nr, int edge_mask ); ++ ++/* ++ * Handy routine to set GPIO alternate functions ++ */ ++extern void set_GPIO_mode( int gpio_mode ); ++ ++/* ++ * return current lclk frequency in units of 10kHz ++ */ ++extern unsigned int get_lclk_frequency_10khz(void); ++ ++/* ++ * return current clk frequency in units of 1kHz ++ */ ++extern unsigned int get_clk_frequency_khz( int info); ++ ++#endif ++ ++ ++/* ++ * Implementation specifics ++ */ ++ ++//#ifdef CONFIG_ARCH_LUBBOCK ++#include "lubbock.h" ++//#endif ++ ++//#ifdef CONFIG_ARCH_PXA_IDP ++#include "idp.h" ++//#endif ++ ++//#ifdef CONFIG_ARCH_PXA_CERF ++#include "cerf.h" ++//#endif ++ ++#endif /* _ASM_ARCH_HARDWARE_H */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/ide.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,59 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/ide.h ++ * ++ * Author: George Davis ++ * Created: Jan 10, 2002 ++ * Copyright: MontaVista 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. ++ * ++ * ++ * Originally based upon linux/include/asm-arm/arch-sa1100/ide.h ++ * ++ */ ++ ++#include <linux/config.h> ++#include <asm/irq.h> ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++ ++ ++/* ++ * Set up a hw structure for a specified data port, control port and IRQ. ++ * This should follow whatever the default interface uses. ++ */ ++static __inline__ void ++ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) ++{ ++ ide_ioreg_t reg; ++ ++ memset(hw, 0, sizeof(*hw)); ++ ++ reg = (ide_ioreg_t)data_port; ++ ++ hw->io_ports[IDE_DATA_OFFSET] = reg + 0; ++ hw->io_ports[IDE_ERROR_OFFSET] = reg + 1; ++ hw->io_ports[IDE_NSECTOR_OFFSET] = reg + 2; ++ hw->io_ports[IDE_SECTOR_OFFSET] = reg + 3; ++ hw->io_ports[IDE_LCYL_OFFSET] = reg + 4; ++ hw->io_ports[IDE_HCYL_OFFSET] = reg + 5; ++ hw->io_ports[IDE_SELECT_OFFSET] = reg + 6; ++ hw->io_ports[IDE_STATUS_OFFSET] = reg + 7; ++ ++ hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port; ++ ++ if (irq) ++ *irq = 0; ++} ++ ++ ++/* ++ * Register the standard ports for this architecture with the IDE driver. ++ */ ++static __inline__ void ++ide_init_default_hwifs(void) ++{ ++ /* Nothing to declare... */ ++} +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/idp.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,468 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/idp.h ++ * ++ * 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. ++ * ++ * Copyright (c) 2001 Cliff Brake, Accelent Systems Inc. ++ * ++ * 2001-09-13: Cliff Brake <cbrake@accelent.com> ++ * Initial code ++ * ++ */ ++ ++ ++/* ++ * Note: this file must be safe to include in assembly files ++ */ ++ ++/* comment out following if you have a rev01 board */ ++#define PXA_IDP_REV02 1 ++//#undef PXA_IDP_REV02 ++ ++#ifdef PXA_IDP_REV02 ++ ++//Use this as well for 0017-x004 and greater pcb's: ++#define PXA_IDP_REV04 1 ++ ++#define IDP_FLASH_PHYS (PXA_CS0_PHYS) ++#define IDP_ALT_FLASH_PHYS (PXA_CS1_PHYS) ++#define IDP_MEDIAQ_PHYS (PXA_CS3_PHYS) ++#define IDP_IDE_PHYS (PXA_CS5_PHYS + 0x03000000) ++#define IDP_ETH_PHYS (PXA_CS5_PHYS + 0x03400000) ++#define IDP_COREVOLT_PHYS (PXA_CS5_PHYS + 0x03800000) ++#define IDP_CPLD_PHYS (PXA_CS5_PHYS + 0x03C00000) ++ ++ ++/* ++ * virtual memory map ++ */ ++ ++#define IDP_IDE_BASE (0xf0000000) ++#define IDP_IDE_SIZE (1*1024*1024) ++ ++#define IDP_ETH_BASE (IDP_IDE_BASE + IDP_IDE_SIZE) ++#define IDP_ETH_SIZE (1*1024*1024) ++#define ETH_BASE IDP_ETH_BASE //smc9194 driver compatibility issue ++ ++#define IDP_COREVOLT_BASE (IDP_ETH_BASE + IDP_ETH_SIZE) ++#define IDP_COREVOLT_SIZE (1*1024*1024) ++ ++#define IDP_CPLD_BASE (IDP_COREVOLT_BASE + IDP_COREVOLT_SIZE) ++#define IDP_CPLD_SIZE (1*1024*1024) ++ ++#if (IDP_CPLD_BASE + IDP_CPLD_SIZE) > 0xfc000000 ++#error Your custom IO space is getting a bit large !! ++#endif ++ ++#define CPLD_P2V(x) ((x) - IDP_CPLD_PHYS + IDP_CPLD_BASE) ++#define CPLD_V2P(x) ((x) - IDP_CPLD_BASE + IDP_CPLD_PHYS) ++ ++#ifndef __ASSEMBLY__ ++# define __CPLD_REG(x) (*((volatile unsigned long *)CPLD_P2V(x))) ++#else ++# define __CPLD_REG(x) CPLD_P2V(x) ++#endif ++ ++/* board level registers in the CPLD: (offsets from CPLD_BASE) */ ++ ++#define _IDP_CPLD_REV (IDP_CPLD_PHYS + 0x00) ++#define _IDP_CPLD_PERIPH_PWR (IDP_CPLD_PHYS + 0x04) ++#define _IDP_CPLD_LED_CONTROL (IDP_CPLD_PHYS + 0x08) ++#define _IDP_CPLD_KB_COL_HIGH (IDP_CPLD_PHYS + 0x0C) ++#define _IDP_CPLD_KB_COL_LOW (IDP_CPLD_PHYS + 0x10) ++#define _IDP_CPLD_PCCARD_EN (IDP_CPLD_PHYS + 0x14) ++#define _IDP_CPLD_GPIOH_DIR (IDP_CPLD_PHYS + 0x18) ++#define _IDP_CPLD_GPIOH_VALUE (IDP_CPLD_PHYS + 0x1C) ++#define _IDP_CPLD_GPIOL_DIR (IDP_CPLD_PHYS + 0x20) ++#define _IDP_CPLD_GPIOL_VALUE (IDP_CPLD_PHYS + 0x24) ++#define _IDP_CPLD_PCCARD_PWR (IDP_CPLD_PHYS + 0x28) ++#define _IDP_CPLD_MISC_CTRL (IDP_CPLD_PHYS + 0x2C) ++#define _IDP_CPLD_LCD (IDP_CPLD_PHYS + 0x30) ++#define _IDP_CPLD_FLASH_WE (IDP_CPLD_PHYS + 0x34) ++ ++#define _IDP_CPLD_KB_ROW (IDP_CPLD_PHYS + 0x50) ++#define _IDP_CPLD_PCCARD0_STATUS (IDP_CPLD_PHYS + 0x54) ++#define _IDP_CPLD_PCCARD1_STATUS (IDP_CPLD_PHYS + 0x58) ++#define _IDP_CPLD_MISC_STATUS (IDP_CPLD_PHYS + 0x5C) ++ ++/* FPGA register virtual addresses */ ++ ++#define IDP_CPLD_REV __CPLD_REG(_IDP_CPLD_REV) ++#define IDP_CPLD_PERIPH_PWR __CPLD_REG(_IDP_CPLD_PERIPH_PWR) ++#define IDP_CPLD_LED_CONTROL __CPLD_REG(_IDP_CPLD_LED_CONTROL) ++#define IDP_CPLD_KB_COL_HIGH __CPLD_REG(_IDP_CPLD_KB_COL_HIGH) ++#define IDP_CPLD_KB_COL_LOW __CPLD_REG(_IDP_CPLD_KB_COL_LOW) ++#define IDP_CPLD_PCCARD_EN __CPLD_REG(_IDP_CPLD_PCCARD_EN) ++#define IDP_CPLD_GPIOH_DIR __CPLD_REG(_IDP_CPLD_GPIOH_DIR) ++#define IDP_CPLD_GPIOH_VALUE __CPLD_REG(_IDP_CPLD_GPIOH_VALUE) ++#define IDP_CPLD_GPIOL_DIR __CPLD_REG(_IDP_CPLD_GPIOL_DIR) ++#define IDP_CPLD_GPIOL_VALUE __CPLD_REG(_IDP_CPLD_GPIOL_VALUE) ++#define IDP_CPLD_PCCARD_PWR __CPLD_REG(_IDP_CPLD_PCCARD_PWR) ++#define IDP_CPLD_MISC_CTRL __CPLD_REG(_IDP_CPLD_MISC_CTRL) ++#define IDP_CPLD_LCD __CPLD_REG(_IDP_CPLD_LCD) ++#define IDP_CPLD_FLASH_WE __CPLD_REG(_IDP_CPLD_FLASH_WE) ++ ++#define IDP_CPLD_KB_ROW __CPLD_REG(_IDP_CPLD_KB_ROW) ++#define IDP_CPLD_PCCARD0_STATUS __CPLD_REG(_IDP_CPLD_PCCARD0_STATUS) ++#define IDP_CPLD_PCCARD1_STATUS __CPLD_REG(_IDP_CPLD_PCCARD1_STATUS) ++#define IDP_CPLD_MISC_STATUS __CPLD_REG(_IDP_CPLD_MISC_STATUS) ++ ++ ++/* ++ * Bit masks for various registers ++ */ ++// IDP_CPLD_PCCARD_PWR ++#define PCC0_PWR0 (1 << 0) ++#define PCC0_PWR1 (1 << 1) ++#define PCC0_PWR2 (1 << 2) ++#define PCC0_PWR3 (1 << 3) ++#define PCC1_PWR0 (1 << 4) ++#define PCC1_PWR1 (1 << 5) ++#define PCC1_PWR2 (1 << 6) ++#define PCC1_PWR3 (1 << 7) ++ ++// IDP_CPLD_PCCARD_EN ++#define PCC0_RESET (1 << 6) ++#define PCC1_RESET (1 << 7) ++#define PCC0_ENABLE (1 << 0) ++#define PCC1_ENABLE (1 << 1) ++ ++// IDP_CPLD_PCCARDx_STATUS ++#define _PCC_WRPROT (1 << 7) // 7-4 read as low true ++#define _PCC_RESET (1 << 6) ++#define _PCC_IRQ (1 << 5) ++#define _PCC_INPACK (1 << 4) ++#define PCC_BVD2 (1 << 3) ++#define PCC_BVD1 (1 << 2) ++#define PCC_VS2 (1 << 1) ++#define PCC_VS1 (1 << 0) ++ ++#define PCC_DETECT(x) (GPLR(7 + (x)) & GPIO_bit(7 + (x))) ++ ++/* ++ * Macros for LCD Driver ++ */ ++ ++#ifdef CONFIG_FB_PXA ++ ++#define FB_BACKLIGHT_ON() (IDP_CPLD_LCD |= (1<<1)) ++#define FB_BACKLIGHT_OFF() (IDP_CPLD_LCD &= ~(1<<1)) ++ ++#define FB_PWR_ON() (IDP_CPLD_LCD |= (1<< 0)) ++#define FB_PWR_OFF() (IDP_CPLD_LCD &= ~(1<<0)) ++ ++#define FB_VLCD_ON() (IDP_CPLD_LCD |= (1<<2)) ++#define FB_VLCD_OFF() (IDP_CPLD_LCD &= ~(1<<2)) ++ ++#endif ++ ++/* A listing of interrupts used by external hardware devices */ ++ ++#ifdef PXA_IDP_REV04 ++#define TOUCH_PANEL_IRQ IRQ_GPIO(5) ++#define IDE_IRQ IRQ_GPIO(21) ++#else ++#define TOUCH_PANEL_IRQ IRQ_GPIO(21) ++#define IDE_IRQ IRQ_GPIO(5) ++#endif ++ ++#define TOUCH_PANEL_IRQ_EDGE GPIO_FALLING_EDGE ++ ++#define IDE_IRQ_EDGE GPIO_RISING_EDGE ++ ++#define ETHERNET_IRQ IRQ_GPIO(4) ++#define ETHERNET_IRQ_EDGE GPIO_RISING_EDGE ++ ++#define IDE_IRQ_EDGE GPIO_RISING_EDGE ++ ++#define PCMCIA_S0_CD_VALID IRQ_GPIO(7) ++#define PCMCIA_S0_CD_VALID_EDGE GPIO_BOTH_EDGES ++ ++#define PCMCIA_S1_CD_VALID IRQ_GPIO(8) ++#define PCMCIA_S1_CD_VALID_EDGE GPIO_BOTH_EDGES ++ ++#define PCMCIA_S0_RDYINT IRQ_GPIO(19) ++#define PCMCIA_S1_RDYINT IRQ_GPIO(22) ++ ++/* ++ * Macros for LED Driver ++ */ ++ ++/* leds 0 = ON */ ++#define IDP_HB_LED (1<<5) ++#define IDP_BUSY_LED (1<<6) ++ ++#define IDP_LEDS_MASK (IDP_HB_LED | IDP_BUSY_LED) ++ ++#define IDP_WRITE_LEDS(value) (IDP_CPLD_LED_CONTROL = (IDP_CPLD_LED_CONTROL & (~(IDP_LEDS_MASK)) | value)) ++ ++/* ++ * macros for MTD driver ++ */ ++ ++#define FLASH_WRITE_PROTECT_DISABLE() ((IDP_CPLD_FLASH_WE) &= ~(0x1)) ++#define FLASH_WRITE_PROTECT_ENABLE() ((IDP_CPLD_FLASH_WE) |= (0x1)) ++ ++/* ++ * macros for matrix keyboard driver ++ */ ++ ++#define KEYBD_MATRIX_NUMBER_INPUTS 7 ++#define KEYBD_MATRIX_NUMBER_OUTPUTS 14 ++ ++#define KEYBD_MATRIX_INVERT_OUTPUT_LOGIC FALSE ++#define KEYBD_MATRIX_INVERT_INPUT_LOGIC FALSE ++ ++#define KEYBD_MATRIX_SETTLING_TIME_US 100 ++#define KEYBD_MATRIX_KEYSTATE_DEBOUNCE_CONSTANT 2 ++ ++#define KEYBD_MATRIX_SET_OUTPUTS(outputs) \ ++{\ ++ IDP_CPLD_KB_COL_LOW = outputs;\ ++ IDP_CPLD_KB_COL_HIGH = outputs >> 7;\ ++} ++ ++#define KEYBD_MATRIX_GET_INPUTS(inputs) \ ++{\ ++ inputs = (IDP_CPLD_KB_ROW & 0x7f);\ ++} ++ ++//------------------------------------------------------------------------------ ++ ++#else // must be rev 01 ++ ++/* ----------------------------------------------------------------------------- ++ * following is for rev01 boards only ++ */ ++ ++#define IDP_FLASH_PHYS (PXA_CS0_PHYS) ++#define IDP_ALT_FLASH_PHYS (PXA_CS1_PHYS) ++#define IDP_MEDIAQ_PHYS (PXA_CS3_PHYS) ++#define IDP_CTRL_PORT_PHYS (PXA_CS5_PHYS + 0x02C00000) ++#define IDP_IDE_PHYS (PXA_CS5_PHYS + 0x03000000) ++#define IDP_ETH_PHYS (PXA_CS5_PHYS + 0x03400000) ++#define IDP_COREVOLT_PHYS (PXA_CS5_PHYS + 0x03800000) ++#define IDP_CPLD_PHYS (PXA_CS5_PHYS + 0x03C00000) ++ ++ ++/* ++ * virtual memory map ++ */ ++ ++#define IDP_CTRL_PORT_BASE (0xf0000000) ++#define IDP_CTRL_PORT_SIZE (1*1024*1024) ++ ++#define IDP_IDE_BASE (IDP_CTRL_PORT_BASE + IDP_CTRL_PORT_SIZE) ++#define IDP_IDE_SIZE (1*1024*1024) ++ ++#define IDP_ETH_BASE (IDP_IDE_BASE + IDP_IDE_SIZE) ++#define IDP_ETH_SIZE (1*1024*1024) ++ ++#define IDP_COREVOLT_BASE (IDP_ETH_BASE + IDP_ETH_SIZE) ++#define IDP_COREVOLT_SIZE (1*1024*1024) ++ ++#define IDP_CPLD_BASE (IDP_COREVOLT_BASE + IDP_COREVOLT_SIZE) ++#define IDP_CPLD_SIZE (1*1024*1024) ++ ++#if (IDP_CPLD_BASE + IDP_CPLD_SIZE) > 0xfc000000 ++#error Your custom IO space is getting a bit large !! ++#endif ++ ++#define CPLD_P2V(x) ((x) - IDP_CPLD_PHYS + IDP_CPLD_BASE) ++#define CPLD_V2P(x) ((x) - IDP_CPLD_BASE + IDP_CPLD_PHYS) ++ ++#ifndef __ASSEMBLY__ ++# define __CPLD_REG(x) (*((volatile unsigned long *)CPLD_P2V(x))) ++#else ++# define __CPLD_REG(x) CPLD_P2V(x) ++#endif ++ ++/* board level registers in the CPLD: (offsets from CPLD_BASE) */ ++ ++#define _IDP_CPLD_LED_CONTROL (IDP_CPLD_PHYS + 0x00) ++#define _IDP_CPLD_PERIPH_PWR (IDP_CPLD_PHYS + 0x04) ++#define _IDP_CPLD_CIR (IDP_CPLD_PHYS + 0x08) ++#define _IDP_CPLD_KB_COL_HIGH (IDP_CPLD_PHYS + 0x0C) ++#define _IDP_CPLD_KB_COL_LOW (IDP_CPLD_PHYS + 0x10) ++#define _IDP_CPLD_PCCARD_EN (IDP_CPLD_PHYS + 0x14) ++#define _IDP_CPLD_GPIOH_DIR (IDP_CPLD_PHYS + 0x18) ++#define _IDP_CPLD_GPIOH_VALUE (IDP_CPLD_PHYS + 0x1C) ++#define _IDP_CPLD_GPIOL_DIR (IDP_CPLD_PHYS + 0x20) ++#define _IDP_CPLD_GPIOL_VALUE (IDP_CPLD_PHYS + 0x24) ++#define _IDP_CPLD_MISC (IDP_CPLD_PHYS + 0x28) ++#define _IDP_CPLD_PCCARD0_STATUS (IDP_CPLD_PHYS + 0x2C) ++#define _IDP_CPLD_PCCARD1_STATUS (IDP_CPLD_PHYS + 0x30) ++ ++/* FPGA register virtual addresses */ ++#define IDP_CPLD_LED_CONTROL __CPLD_REG(_IDP_CPLD_LED_CONTROL) /* write only */ ++#define IDP_CPLD_PERIPH_PWR __CPLD_REG(_IDP_CPLD_PERIPH_PWR) /* write only */ ++#define IDP_CPLD_CIR __CPLD_REG(_IDP_CPLD_CIR) /* write only */ ++#define IDP_CPLD_KB_COL_HIGH __CPLD_REG(_IDP_CPLD_KB_COL_HIGH) /* write only */ ++#define IDP_CPLD_KB_COL_LOW __CPLD_REG(_IDP_CPLD_KB_COL_LOW) /* write only */ ++#define IDP_CPLD_PCCARD_EN __CPLD_REG(_IDP_CPLD_PCCARD_EN) /* write only */ ++#define IDP_CPLD_GPIOH_DIR __CPLD_REG(_IDP_CPLD_GPIOH_DIR) /* write only */ ++#define IDP_CPLD_GPIOH_VALUE __CPLD_REG(_IDP_CPLD_GPIOH_VALUE) /* write only */ ++#define IDP_CPLD_GPIOL_DIR __CPLD_REG(_IDP_CPLD_GPIOL_DIR) /* write only */ ++#define IDP_CPLD_GPIOL_VALUE __CPLD_REG(_IDP_CPLD_GPIOL_VALUE) /* write only */ ++#define IDP_CPLD_MISC __CPLD_REG(_IDP_CPLD_MISC) /* read only */ ++#define IDP_CPLD_PCCARD0_STATUS __CPLD_REG(_IDP_CPLD_PCCARD0_STATUS) /* read only */ ++#define IDP_CPLD_PCCARD1_STATUS __CPLD_REG(_IDP_CPLD_PCCARD1_STATUS) /* read only */ ++ ++ ++#ifndef __ASSEMBLY__ ++ ++/* shadow registers for write only registers */ ++extern unsigned int idp_cpld_led_control_shadow; ++extern unsigned int idp_cpld_periph_pwr_shadow; ++extern unsigned int idp_cpld_cir_shadow; ++extern unsigned int idp_cpld_kb_col_high_shadow; ++extern unsigned int idp_cpld_kb_col_low_shadow; ++extern unsigned int idp_cpld_pccard_en_shadow; ++extern unsigned int idp_cpld_gpioh_dir_shadow; ++extern unsigned int idp_cpld_gpioh_value_shadow; ++extern unsigned int idp_cpld_gpiol_dir_shadow; ++extern unsigned int idp_cpld_gpiol_value_shadow; ++ ++extern unsigned int idp_control_port_shadow; ++ ++/* ++ * macros to write to write only register ++ * ++ * none of these macros are protected from ++ * multiple drivers using them in interrupt context. ++ */ ++ ++#define WRITE_IDP_CPLD_LED_CONTROL(value, mask) \ ++{\ ++ idp_cpld_led_control_shadow = ((value & mask) | (idp_cpld_led_control_shadow & ~mask));\ ++ IDP_CPLD_LED_CONTROL = idp_cpld_led_control_shadow;\ ++} ++#define WRITE_IDP_CPLD_PERIPH_PWR(value, mask) \ ++{\ ++ idp_cpld_periph_pwr_shadow = ((value & mask) | (idp_cpld_periph_pwr_shadow & ~mask));\ ++ IDP_CPLD_PERIPH_PWR = idp_cpld_periph_pwr_shadow;\ ++} ++#define WRITE_IDP_CPLD_CIR(value, mask) \ ++{\ ++ idp_cpld_cir_shadow = ((value & mask) | (idp_cpld_cir_shadow & ~mask));\ ++ IDP_CPLD_CIR = idp_cpld_cir_shadow;\ ++} ++#define WRITE_IDP_CPLD_KB_COL_HIGH(value, mask) \ ++{\ ++ idp_cpld_kb_col_high_shadow = ((value & mask) | (idp_cpld_kb_col_high_shadow & ~mask));\ ++ IDP_CPLD_KB_COL_HIGH = idp_cpld_kb_col_high_shadow;\ ++} ++#define WRITE_IDP_CPLD_KB_COL_LOW(value, mask) \ ++{\ ++ idp_cpld_kb_col_low_shadow = ((value & mask) | (idp_cpld_kb_col_low_shadow & ~mask));\ ++ IDP_CPLD_KB_COL_LOW = idp_cpld_kb_col_low_shadow;\ ++} ++#define WRITE_IDP_CPLD_PCCARD_EN(value, mask) \ ++{\ ++ idp_cpld_ = ((value & mask) | (idp_cpld_led_control_shadow & ~mask));\ ++ IDP_CPLD_LED_CONTROL = idp_cpld_led_control_shadow;\ ++} ++#define WRITE_IDP_CPLD_GPIOH_DIR(value, mask) \ ++{\ ++ idp_cpld_gpioh_dir_shadow = ((value & mask) | (idp_cpld_gpioh_dir_shadow & ~mask));\ ++ IDP_CPLD_GPIOH_DIR = idp_cpld_gpioh_dir_shadow;\ ++} ++#define WRITE_IDP_CPLD_GPIOH_VALUE(value, mask) \ ++{\ ++ idp_cpld_gpioh_value_shadow = ((value & mask) | (idp_cpld_gpioh_value_shadow & ~mask));\ ++ IDP_CPLD_GPIOH_VALUE = idp_cpld_gpioh_value_shadow;\ ++} ++#define WRITE_IDP_CPLD_GPIOL_DIR(value, mask) \ ++{\ ++ idp_cpld_gpiol_dir_shadow = ((value & mask) | (idp_cpld_gpiol_dir_shadow & ~mask));\ ++ IDP_CPLD_GPIOL_DIR = idp_cpld_gpiol_dir_shadow;\ ++} ++#define WRITE_IDP_CPLD_GPIOL_VALUE(value, mask) \ ++{\ ++ idp_cpld_gpiol_value_shadow = ((value & mask) | (idp_cpld_gpiol_value_shadow & ~mask));\ ++ IDP_CPLD_GPIOL_VALUE = idp_cpld_gpiol_value_shadow;\ ++} ++ ++#define WRITE_IDP_CONTROL_PORT(value, mask) \ ++{\ ++ idp_control_port_shadow = ((value & mask) | (idp_control_port_shadow & ~mask));\ ++ (*((volatile unsigned long *)IDP_CTRL_PORT_BASE)) = idp_control_port_shadow;\ ++} ++ ++#endif ++ ++/* A listing of interrupts used by external hardware devices */ ++ ++#define TOUCH_PANEL_IRQ IRQ_GPIO(21) ++#define TOUCH_PANEL_IRQ_EGDE GPIO_FALLING_EDGE ++ ++#define ETHERNET_IRQ IRQ_GPIO(4) ++#define ETHERNET_IRQ_EDGE GPIO_RISING_EDGE ++ ++/* ++ * Bit masks for various registers ++ */ ++ ++ ++/* control port */ ++#define IDP_CONTROL_PORT_PCSLOT0_0 (1 << 0) ++#define IDP_CONTROL_PORT_PCSLOT0_1 (1 << 1) ++#define IDP_CONTROL_PORT_PCSLOT0_2 (1 << 2) ++#define IDP_CONTROL_PORT_PCSLOT0_3 (1 << 3) ++#define IDP_CONTROL_PORT_PCSLOT1_1 (1 << 4) ++#define IDP_CONTROL_PORT_PCSLOT1_2 (1 << 5) ++#define IDP_CONTROL_PORT_PCSLOT1_3 (1 << 6) ++#define IDP_CONTROL_PORT_PCSLOT1_4 (1 << 7) ++#define IDP_CONTROL_PORT_SERIAL1_EN (1 << 9) ++#define IDP_CONTROL_PORT_SERIAL2_EN (1 << 10) ++#define IDP_CONTROL_PORT_SERIAL3_EN (1 << 11) ++#define IDP_CONTROL_PORT_IRDA_FIR (1 << 12) ++#define IDP_CONTROL_PORT_IRDA_M0 (1 << 13) ++#define IDP_CONTROL_PORT_IRDA_M1 (1 << 14) ++#define IDP_CONTROL_PORT_I2S_PWR (1 << 15) ++#define IDP_CONTROL_PORT_FLASH_WP (1 << 19) ++#define IDP_CONTROL_PORT_MILL_EN (1 << 20) ++#define IDP_CONTROL_PORT_LCD_PWR (1 << 21) ++#define IDP_CONTROL_PORT_LCD_BKLEN (1 << 22) ++#define IDP_CONTROL_PORT_LCD_ENAVLCD (1 << 23) ++ ++/* ++ * Macros for LCD Driver ++ */ ++ ++#ifdef CONFIG_FB_PXA ++ ++#define FB_BACKLIGHT_ON() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_LCD_BKLEN, IDP_CONTROL_PORT_LCD_BKLEN) ++#define FB_BACKLIGHT_OFF() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_LCD_BKLEN) ++ ++#define FB_PWR_ON() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_LCD_PWR, IDP_CONTROL_PORT_LCD_PWR) ++#define FB_PWR_OFF() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_LCD_PWR) ++ ++#define FB_VLCD_ON() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_LCD_ENAVLCD, IDP_CONTROL_PORT_LCD_ENAVLCD) ++#define FB_VLCD_OFF() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_LCD_ENAVLCD) ++ ++#endif ++ ++ ++/* ++ * Macros for LED Driver ++ */ ++ ++/* leds 0 = ON */ ++#define IDP_HB_LED 0x1 ++#define IDP_BUSY_LED 0x2 ++ ++#define IDP_LEDS_MASK (IDP_HB_LED | IDP_BUSY_LED) ++ ++#define IDP_WRITE_LEDS(value) WRITE_IDP_CPLD_LED_CONTROL(value, IDP_LEDS_MASK) ++ ++/* ++ * macros for MTD driver ++ */ ++ ++#define FLASH_WRITE_PROTECT_DISABLE() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_FLASH_WP) ++#define FLASH_WRITE_PROTECT_ENABLE() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_FLASH_WP, IDP_CONTROL_PORT_FLASH_WP) ++ ++#endif +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/innokom.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,47 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/innokom.h ++ * ++ * (c) 2003 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix ++ * ++ * 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 ++ */ ++ ++/* ++ * GPIOs ++ */ ++#define GPIO_INNOKOM_RESET 3 ++#define GPIO_INNOKOM_SW_UPDATE 11 ++#define GPIO_INNOKOM_ETH 59 ++ ++/* ++ * ethernet chip (SMSC91C111) ++ */ ++#define INNOKOM_ETH_PHYS PXA_CS5_PHYS ++#define INNOKOM_ETH_BASE (0xf0000000) /* phys 0x14000000 */ ++#define INNOKOM_ETH_SIZE (1*1024*1024) ++#define INNOKOM_ETH_IRQ IRQ_GPIO(GPIO_INNOKOM_ETH) ++#define INNOKOM_ETH_IRQ_EDGE GPIO_RISING_EDGE ++ ++/* ++ * virtual to physical conversion macros ++ */ ++#define INNOKOM_P2V(x) ((x) - INNOKOM_FPGA_PHYS + INNOKOM_FPGA_VIRT) ++#define INNOKOM_V2P(x) ((x) - INNOKOM_FPGA_VIRT + INNOKOM_FPGA_PHYS) ++ ++#ifndef __ASSEMBLY__ ++# define __INNOKOM_REG(x) (*((volatile unsigned long *)INNOKOM_P2V(x))) ++#else ++# define __INNOKOM_REG(x) INNOKOM_P2V(x) ++#endif +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/io.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,34 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/io.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista 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 __ASM_ARM_ARCH_IO_H ++#define __ASM_ARM_ARCH_IO_H ++ ++#define IO_SPACE_LIMIT 0xffffffff ++ ++/* ++ * We don't actually have real ISA nor PCI buses, but there is so many ++ * drivers out there that might just work if we fake them... ++ */ ++#define __io(a) (a) ++#define __mem_pci(a) ((unsigned long)(a)) ++#define __mem_isa(a) ((unsigned long)(a)) ++ ++/* ++ * Generic virtual read/write ++ */ ++#define __arch_getw(a) (*(volatile unsigned short *)(a)) ++#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) ++ ++#define iomem_valid_addr(iomem,sz) (1) ++#define iomem_to_phys(iomem) (iomem) ++ ++#endif +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/irq.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,19 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/irq.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista 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. ++ */ ++ ++#define fixup_irq(x) (x) ++ ++/* ++ * This prototype is required for cascading of multiplexed interrupts. ++ * Since it doesn't exist elsewhere, we'll put it here for now. ++ */ ++extern void do_IRQ(int irq, struct pt_regs *regs); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/irqs.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,137 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/irqs.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista 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. ++ */ ++ ++#define PXA_IRQ_SKIP 7 /* The first 7 IRQs are not yet used */ ++#define PXA_IRQ(x) ((x) - PXA_IRQ_SKIP) ++ ++#define IRQ_HWUART PXA_IRQ(7) /* HWUART Transmit/Receive/Error */ ++#define IRQ_GPIO0 PXA_IRQ(8) /* GPIO0 Edge Detect */ ++#define IRQ_GPIO1 PXA_IRQ(9) /* GPIO1 Edge Detect */ ++#define IRQ_GPIO_2_80 PXA_IRQ(10) /* GPIO[2-80] Edge Detect */ ++#define IRQ_USB PXA_IRQ(11) /* USB Service */ ++#define IRQ_PMU PXA_IRQ(12) /* Performance Monitoring Unit */ ++#define IRQ_I2S PXA_IRQ(13) /* I2S Interrupt */ ++#define IRQ_AC97 PXA_IRQ(14) /* AC97 Interrupt */ ++#define IRQ_ASSP PXA_IRQ(15) /* Audio SSP Service Request */ ++#define IRQ_NSSP PXA_IRQ(16) /* Network SSP Service Request */ ++#define IRQ_LCD PXA_IRQ(17) /* LCD Controller Service Request */ ++#define IRQ_I2C PXA_IRQ(18) /* I2C Service Request */ ++#define IRQ_ICP PXA_IRQ(19) /* ICP Transmit/Receive/Error */ ++#define IRQ_STUART PXA_IRQ(20) /* STUART Transmit/Receive/Error */ ++#define IRQ_BTUART PXA_IRQ(21) /* BTUART Transmit/Receive/Error */ ++#define IRQ_FFUART PXA_IRQ(22) /* FFUART Transmit/Receive/Error*/ ++#define IRQ_MMC PXA_IRQ(23) /* MMC Status/Error Detection */ ++#define IRQ_SSP PXA_IRQ(24) /* SSP Service Request */ ++#define IRQ_DMA PXA_IRQ(25) /* DMA Channel Service Request */ ++#define IRQ_OST0 PXA_IRQ(26) /* OS Timer match 0 */ ++#define IRQ_OST1 PXA_IRQ(27) /* OS Timer match 1 */ ++#define IRQ_OST2 PXA_IRQ(28) /* OS Timer match 2 */ ++#define IRQ_OST3 PXA_IRQ(29) /* OS Timer match 3 */ ++#define IRQ_RTC1Hz PXA_IRQ(30) /* RTC HZ Clock Tick */ ++#define IRQ_RTCAlrm PXA_IRQ(31) /* RTC Alarm */ ++ ++#define GPIO_2_80_TO_IRQ(x) \ ++ PXA_IRQ((x) - 2 + 32) ++#define IRQ_GPIO(x) (((x) < 2) ? (IRQ_GPIO0 + (x)) : GPIO_2_80_TO_IRQ(x)) ++ ++#define IRQ_TO_GPIO_2_80(i) \ ++ ((i) - PXA_IRQ(32) + 2) ++#define IRQ_TO_GPIO(i) ((i) - (((i) > IRQ_GPIO1) ? IRQ_GPIO(2) - 2 : IRQ_GPIO(0))) ++ ++#define NR_IRQS (IRQ_GPIO(80) + 1) ++ ++#if defined(CONFIG_SA1111) ++ ++#define IRQ_SA1111_START (IRQ_GPIO(80) + 1) ++#define SA1111_IRQ(x) (IRQ_SA1111_START + (x)) ++ ++#define IRQ_GPAIN0 SA1111_IRQ(0) ++#define IRQ_GPAIN1 SA1111_IRQ(1) ++#define IRQ_GPAIN2 SA1111_IRQ(2) ++#define IRQ_GPAIN3 SA1111_IRQ(3) ++#define IRQ_GPBIN0 SA1111_IRQ(4) ++#define IRQ_GPBIN1 SA1111_IRQ(5) ++#define IRQ_GPBIN2 SA1111_IRQ(6) ++#define IRQ_GPBIN3 SA1111_IRQ(7) ++#define IRQ_GPBIN4 SA1111_IRQ(8) ++#define IRQ_GPBIN5 SA1111_IRQ(9) ++#define IRQ_GPCIN0 SA1111_IRQ(10) ++#define IRQ_GPCIN1 SA1111_IRQ(11) ++#define IRQ_GPCIN2 SA1111_IRQ(12) ++#define IRQ_GPCIN3 SA1111_IRQ(13) ++#define IRQ_GPCIN4 SA1111_IRQ(14) ++#define IRQ_GPCIN5 SA1111_IRQ(15) ++#define IRQ_GPCIN6 SA1111_IRQ(16) ++#define IRQ_GPCIN7 SA1111_IRQ(17) ++#define IRQ_MSTXINT SA1111_IRQ(18) ++#define IRQ_MSRXINT SA1111_IRQ(19) ++#define IRQ_MSSTOPERRINT SA1111_IRQ(20) ++#define IRQ_TPTXINT SA1111_IRQ(21) ++#define IRQ_TPRXINT SA1111_IRQ(22) ++#define IRQ_TPSTOPERRINT SA1111_IRQ(23) ++#define SSPXMTINT SA1111_IRQ(24) ++#define SSPRCVINT SA1111_IRQ(25) ++#define SSPROR SA1111_IRQ(26) ++#define AUDXMTDMADONEA SA1111_IRQ(32) ++#define AUDRCVDMADONEA SA1111_IRQ(33) ++#define AUDXMTDMADONEB SA1111_IRQ(34) ++#define AUDRCVDMADONEB SA1111_IRQ(35) ++#define AUDTFSR SA1111_IRQ(36) ++#define AUDRFSR SA1111_IRQ(37) ++#define AUDTUR SA1111_IRQ(38) ++#define AUDROR SA1111_IRQ(39) ++#define AUDDTS SA1111_IRQ(40) ++#define AUDRDD SA1111_IRQ(41) ++#define AUDSTO SA1111_IRQ(42) ++#define USBPWR SA1111_IRQ(43) ++#define NIRQHCIM SA1111_IRQ(44) ++#define HCIBUFFACC SA1111_IRQ(45) ++#define HCIRMTWKP SA1111_IRQ(46) ++#define NHCIMFCIR SA1111_IRQ(47) ++#define PORT_RESUME SA1111_IRQ(48) ++#define S0_READY_NINT SA1111_IRQ(49) ++#define S1_READY_NINT SA1111_IRQ(50) ++#define S0_CD_VALID SA1111_IRQ(51) ++#define S1_CD_VALID SA1111_IRQ(52) ++#define S0_BVD1_STSCHG SA1111_IRQ(53) ++#define S1_BVD1_STSCHG SA1111_IRQ(54) ++ ++#define SA1111_IRQ_MAX SA1111_IRQ(54) ++ ++#undef NR_IRQS ++#define NR_IRQS (SA1111_IRQ_MAX + 1) ++ ++#endif // defined(CONFIG_SA1111) ++ ++#if defined(CONFIG_ARCH_LUBBOCK) || defined(CONFIG_ARCH_PXA_IDP) ++#if CONFIG_SA1111 ++#define LUBBOCK_IRQ(x) (SA1111_IRQ_MAX + 1 + (x)) ++#else ++#define LUBBOCK_IRQ(x) (IRQ_GPIO(80) + 1 + (x)) ++#endif ++ ++#define LUBBOCK_SD_IRQ LUBBOCK_IRQ(0) ++#define LUBBOCK_SA1111_IRQ LUBBOCK_IRQ(1) ++#define LUBBOCK_USB_IRQ LUBBOCK_IRQ(2) ++#define LUBBOCK_ETH_IRQ LUBBOCK_IRQ(3) ++#define LUBBOCK_UCB1400_IRQ LUBBOCK_IRQ(4) ++#define LUBBOCK_BB_IRQ LUBBOCK_IRQ(5) ++#define LUBBOCK_USB_DISC_IRQ LUBBOCK_IRQ(6) /* usb disconnect */ ++#define LUBBOCK_LAST_IRQ LUBBOCK_IRQ(6) ++ ++#undef NR_IRQS ++#define NR_IRQS (LUBBOCK_LAST_IRQ + 1) ++ ++#endif // CONFIG_ARCH_LUBBOCK ++ ++ ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/keyboard.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,29 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/keyboard.h ++ * ++ * This file contains the architecture specific keyboard definitions ++ */ ++ ++#ifndef _PXA_KEYBOARD_H ++#define _PXA_KEYBOARD_H ++ ++#include <linux/config.h> ++#include <asm/mach-types.h> ++#include <asm/hardware.h> ++ ++extern struct kbd_ops_struct *kbd_ops; ++ ++#define kbd_disable_irq() do { } while(0); ++#define kbd_enable_irq() do { } while(0); ++ ++extern int sa1111_kbd_init_hw(void); ++ ++static inline void kbd_init_hw(void) ++{ ++ if (machine_is_lubbock()) ++ sa1111_kbd_init_hw(); ++} ++ ++ ++#endif /* _PXA_KEYBOARD_H */ ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/lubbock.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,113 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/lubbock.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista 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. ++ */ ++ ++#define LUBBOCK_FPGA_PHYS PXA_CS2_PHYS ++#define LUBBOCK_FPGA_VIRT (0xf0000000) /* phys 0x08000000 */ ++#define LUBBOCK_ETH_PHYS PXA_CS3_PHYS ++#define LUBBOCK_ETH_VIRT (0xf1000000) ++#define LUBBOCK_SA1111_BASE (0xf4000000) /* phys 0x10000000 */ ++ ++#define LUB_P2V(x) ((x) - LUBBOCK_FPGA_PHYS + LUBBOCK_FPGA_VIRT) ++#define LUB_V2P(x) ((x) - LUBBOCK_FPGA_VIRT + LUBBOCK_FPGA_PHYS) ++ ++#ifndef __ASSEMBLY__ ++# define __LUB_REG(x) (*((volatile unsigned long *)LUB_P2V(x))) ++#else ++# define __LUB_REG(x) LUB_P2V(x) ++#endif ++ ++/* board level registers in the CPLD: (offsets from CPLD_BASE) */ ++ ++#define WHOAMI 0 // card ID's (see programmers manual) ++#define HEX_LED 0x10 // R/W access to 8 7 segment displays ++#define DISC_BLNK_LED 0x40 // R/W [15-8] enables for hex leds, [7-0] discrete LEDs ++#define CONF_SWITCHES 0x50 // RO [1] flash wrt prot, [0] 0= boot from rom, 1= flash ++#define USER_SWITCHES 0x60 // RO [15-8] dip switches, [7-0] 2 hex encoding switches ++#define MISC_WR 0x80 // R/W various system controls -see manual ++#define MISC_RD 0x90 // RO various system status bits -see manual ++//#define LUB_IRQ_MASK_EN 0xC0 // R/W 0= mask, 1= enable of TS, codec, ethernet, USB, SA1111, and card det. irq's ++//#define LUB_IRQ_SET_CLR 0xD0 // R/W 1= set, 0 = clear IRQ's from TS, codec, etc... ++//#define LUB_GP 0x100 // R/W [15-0] 16 bits of general purpose I/o for hacking ++ ++ ++/* FPGA register physical addresses */ ++#define _LUB_WHOAMI (LUBBOCK_FPGA_PHYS + 0x000) ++#define _LUB_HEXLED (LUBBOCK_FPGA_PHYS + 0x010) ++#define _LUB_DISC_BLNK_LED (LUBBOCK_FPGA_PHYS + 0x040) ++#define _LUB_CONF_SWITCHES (LUBBOCK_FPGA_PHYS + 0x050) ++#define _LUB_USER_SWITCHES (LUBBOCK_FPGA_PHYS + 0x060) ++#define _LUB_MISC_WR (LUBBOCK_FPGA_PHYS + 0x080) ++#define _LUB_MISC_RD (LUBBOCK_FPGA_PHYS + 0x090) ++#define _LUB_IRQ_MASK_EN (LUBBOCK_FPGA_PHYS + 0x0C0) ++#define _LUB_IRQ_SET_CLR (LUBBOCK_FPGA_PHYS + 0x0D0) ++#define _LUB_GP (LUBBOCK_FPGA_PHYS + 0x100) ++ ++/* FPGA register virtual addresses */ ++#define LUB_WHOAMI __LUB_REG(_LUB_WHOAMI) ++#define LUB_HEXLED __LUB_REG(_LUB_HEXLED) ++#define LUB_DISC_BLNK_LED __LUB_REG(_LUB_DISC_BLNK_LED) ++#define LUB_CONF_SWITCHES __LUB_REG(_LUB_CONF_SWITCHES) ++#define LUB_USER_SWITCHES __LUB_REG(_LUB_USER_SWITCHES) ++#define LUB_MISC_WR __LUB_REG(_LUB_MISC_WR) ++#define LUB_MISC_RD __LUB_REG(_LUB_MISC_RD) ++#define LUB_IRQ_MASK_EN __LUB_REG(_LUB_IRQ_MASK_EN) ++#define LUB_IRQ_SET_CLR __LUB_REG(_LUB_IRQ_SET_CLR) ++#define LUB_GP __LUB_REG(_LUB_GP) ++ ++/* GPIOs */ ++ ++#define GPIO_LUBBOCK_IRQ 0 ++#define IRQ_GPIO_LUBBOCK_IRQ IRQ_GPIO0 ++ ++ ++/* ++ * LED macros ++ */ ++ ++#define LEDS_BASE LUB_DISC_BLNK_LED ++ ++// 8 discrete leds available for general use: ++ ++#define D28 0x1 ++#define D27 0x2 ++#define D26 0x4 ++#define D25 0x8 ++#define D24 0x10 ++#define D23 0x20 ++#define D22 0x40 ++#define D21 0x80 ++ ++/* Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays so ++* be sure to not monkey with them here. ++*/ ++ ++#define HEARTBEAT_LED D28 ++#define SYS_BUSY_LED D27 ++#define HEXLEDS_BASE LUB_HEXLED ++ ++#define HEARTBEAT_LED_ON (LEDS_BASE &= ~HEARTBEAT_LED) ++#define HEARTBEAT_LED_OFF (LEDS_BASE |= HEARTBEAT_LED) ++#define SYS_BUSY_LED_OFF (LEDS_BASE |= SYS_BUSY_LED) ++#define SYS_BUSY_LED_ON (LEDS_BASE &= ~SYS_BUSY_LED) ++ ++// use x = D26-D21 for these, please... ++#define DISCRETE_LED_ON(x) (LEDS_BASE &= ~(x)) ++#define DISCRETE_LED_OFF(x) (LEDS_BASE |= (x)) ++ ++#ifndef __ASSEMBLY__ ++ ++//extern int hexled_val = 0; ++ ++#endif ++ ++#define BUMP_COUNTER (HEXLEDS_BASE = hexled_val++) ++#define DEC_COUNTER (HEXLEDS_BASE = hexled_val--) +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/memory.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,106 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/memory.h ++ * ++ * Author: Nicolas Pitre ++ * Copyright: (C) 2001 MontaVista 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 __ASM_ARCH_MEMORY_H ++#define __ASM_ARCH_MEMORY_H ++ ++ ++/* ++ * Task size: 3GB ++ */ ++#define TASK_SIZE (0xc0000000UL) ++#define TASK_SIZE_26 (0x04000000UL) ++ ++/* ++ * This decides where the kernel will search for a free chunk of vm ++ * space during mmap's. ++ */ ++#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) ++ ++/* ++ * Page offset: 3GB ++ */ ++#define PAGE_OFFSET (0xc0000000UL) ++ ++/* ++ * Physical DRAM offset. ++ */ ++#define PHYS_OFFSET (0xa0000000UL) ++ ++/* ++ * physical vs virtual ram conversion ++ */ ++#define __virt_to_phys__is_a_macro ++#define __phys_to_virt__is_a_macro ++#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET) ++#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET) ++ ++/* ++ * Virtual view <-> DMA view memory address translations ++ * virt_to_bus: Used to translate the virtual address to an ++ * address suitable to be passed to set_dma_addr ++ * bus_to_virt: Used to convert an address for DMA operations ++ * to an address that the kernel can use. ++ */ ++#define __virt_to_bus__is_a_macro ++#define __bus_to_virt__is_a_macro ++#define __virt_to_bus(x) __virt_to_phys(x) ++#define __bus_to_virt(x) __phys_to_virt(x) ++ ++#ifdef CONFIG_DISCONTIGMEM ++/* ++ * The nodes are matched with the physical SDRAM banks as follows: ++ * ++ * node 0: 0xa0000000-0xa3ffffff --> 0xc0000000-0xc3ffffff ++ * node 1: 0xa4000000-0xa7ffffff --> 0xc4000000-0xc7ffffff ++ * node 2: 0xa8000000-0xabffffff --> 0xc8000000-0xcbffffff ++ * node 3: 0xac000000-0xafffffff --> 0xcc000000-0xcfffffff ++ */ ++ ++#define NR_NODES 4 ++ ++/* ++ * Given a kernel address, find the home node of the underlying memory. ++ */ ++#define KVADDR_TO_NID(addr) (((unsigned long)(addr) - PAGE_OFFSET) >> 26) ++ ++/* ++ * Given a page frame number, convert it to a node id. ++ */ ++#define PFN_TO_NID(pfn) (((pfn) - PHYS_PFN_OFFSET) >> (26 - PAGE_SHIFT)) ++ ++/* ++ * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory ++ * and returns the mem_map of that node. ++ */ ++#define ADDR_TO_MAPBASE(kaddr) NODE_MEM_MAP(KVADDR_TO_NID(kaddr)) ++ ++/* ++ * Given a page frame number, find the owning node of the memory ++ * and returns the mem_map of that node. ++ */ ++#define PFN_TO_MAPBASE(pfn) NODE_MEM_MAP(PFN_TO_NID(pfn)) ++ ++/* ++ * Given a kaddr, LOCAL_MEM_MAP finds the owning node of the memory ++ * and returns the index corresponding to the appropriate page in the ++ * node's mem_map. ++ */ ++#define LOCAL_MAP_NR(addr) \ ++ (((unsigned long)(addr) & 0x03ffffff) >> PAGE_SHIFT) ++ ++#else ++ ++#define PFN_TO_NID(addr) (0) ++ ++#endif ++ ++#endif +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/param.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,3 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/param.h ++ */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/pcmcia.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,65 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/pcmcia.h ++ * ++ * Author: George Davis ++ * Created: Jan 10, 2002 ++ * Copyright: MontaVista 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. ++ * ++ * ++ * Originally based upon linux/include/asm-arm/arch-sa1100/pcmcia.h ++ * ++ */ ++ ++#ifndef _ASM_ARCH_PCMCIA ++#define _ASM_ARCH_PCMCIA ++ ++ ++/* Ideally, we'd support up to MAX_SOCK sockets, but PXA250 only ++ * provides support for a maximum of two. ++ */ ++#define PXA_PCMCIA_MAX_SOCK (2) ++ ++ ++#ifndef __ASSEMBLY__ ++ ++struct pcmcia_init { ++ void (*handler)(int irq, void *dev, struct pt_regs *regs); ++}; ++ ++struct pcmcia_state { ++ unsigned detect: 1, ++ ready: 1, ++ bvd1: 1, ++ bvd2: 1, ++ wrprot: 1, ++ vs_3v: 1, ++ vs_Xv: 1; ++}; ++ ++struct pcmcia_state_array { ++ unsigned int size; ++ struct pcmcia_state *state; ++}; ++ ++struct pcmcia_irq_info { ++ unsigned int sock; ++ unsigned int irq; ++}; ++ ++struct pcmcia_low_level { ++ int (*init)(struct pcmcia_init *); ++ int (*shutdown)(void); ++ int (*socket_state)(struct pcmcia_state_array *); ++ int (*get_irq_info)(struct pcmcia_irq_info *); ++ int (*configure_socket)(unsigned int, socket_state_t *); ++}; ++ ++extern struct pcmcia_low_level *pcmcia_low_level; ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/pxa-regs.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,1327 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/pxa-regs.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista 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 _PXA_REGS_H_ ++#define _PXA_REGS_H_ ++ ++#include "bitfield.h" ++ ++ ++// FIXME hack so that SA-1111.h will work [cb] ++ ++#ifndef __ASSEMBLY__ ++typedef unsigned short Word16 ; ++typedef unsigned int Word32 ; ++typedef Word32 Word ; ++typedef Word Quad [4] ; ++typedef void *Address ; ++typedef void (*ExcpHndlr) (void) ; ++#endif ++ ++/* ++ * PXA Chip selects ++ */ ++ ++#define PXA_CS0_PHYS 0x00000000 ++#define PXA_CS1_PHYS 0x04000000 ++#define PXA_CS2_PHYS 0x08000000 ++#define PXA_CS3_PHYS 0x0C000000 ++#define PXA_CS4_PHYS 0x10000000 ++#define PXA_CS5_PHYS 0x14000000 ++ ++ ++/* ++ * Personal Computer Memory Card International Association (PCMCIA) sockets ++ */ ++ ++#define PCMCIAPrtSp 0x04000000 /* PCMCIA Partition Space [byte] */ ++#define PCMCIASp (4*PCMCIAPrtSp) /* PCMCIA Space [byte] */ ++#define PCMCIAIOSp PCMCIAPrtSp /* PCMCIA I/O Space [byte] */ ++#define PCMCIAAttrSp PCMCIAPrtSp /* PCMCIA Attribute Space [byte] */ ++#define PCMCIAMemSp PCMCIAPrtSp /* PCMCIA Memory Space [byte] */ ++ ++#define PCMCIA0Sp PCMCIASp /* PCMCIA 0 Space [byte] */ ++#define PCMCIA0IOSp PCMCIAIOSp /* PCMCIA 0 I/O Space [byte] */ ++#define PCMCIA0AttrSp PCMCIAAttrSp /* PCMCIA 0 Attribute Space [byte] */ ++#define PCMCIA0MemSp PCMCIAMemSp /* PCMCIA 0 Memory Space [byte] */ ++ ++#define PCMCIA1Sp PCMCIASp /* PCMCIA 1 Space [byte] */ ++#define PCMCIA1IOSp PCMCIAIOSp /* PCMCIA 1 I/O Space [byte] */ ++#define PCMCIA1AttrSp PCMCIAAttrSp /* PCMCIA 1 Attribute Space [byte] */ ++#define PCMCIA1MemSp PCMCIAMemSp /* PCMCIA 1 Memory Space [byte] */ ++ ++#define _PCMCIA(Nb) /* PCMCIA [0..1] */ \ ++ (0x20000000 + (Nb)*PCMCIASp) ++#define _PCMCIAIO(Nb) _PCMCIA (Nb) /* PCMCIA I/O [0..1] */ ++#define _PCMCIAAttr(Nb) /* PCMCIA Attribute [0..1] */ \ ++ (_PCMCIA (Nb) + 2*PCMCIAPrtSp) ++#define _PCMCIAMem(Nb) /* PCMCIA Memory [0..1] */ \ ++ (_PCMCIA (Nb) + 3*PCMCIAPrtSp) ++ ++#define _PCMCIA0 _PCMCIA (0) /* PCMCIA 0 */ ++#define _PCMCIA0IO _PCMCIAIO (0) /* PCMCIA 0 I/O */ ++#define _PCMCIA0Attr _PCMCIAAttr (0) /* PCMCIA 0 Attribute */ ++#define _PCMCIA0Mem _PCMCIAMem (0) /* PCMCIA 0 Memory */ ++ ++#define _PCMCIA1 _PCMCIA (1) /* PCMCIA 1 */ ++#define _PCMCIA1IO _PCMCIAIO (1) /* PCMCIA 1 I/O */ ++#define _PCMCIA1Attr _PCMCIAAttr (1) /* PCMCIA 1 Attribute */ ++#define _PCMCIA1Mem _PCMCIAMem (1) /* PCMCIA 1 Memory */ ++ ++ ++ ++/* ++ * DMA Controller ++ */ ++ ++#define DCSR0 __REG(0x40000000) /* DMA Control / Status Register for Channel 0 */ ++#define DCSR1 __REG(0x40000004) /* DMA Control / Status Register for Channel 1 */ ++#define DCSR2 __REG(0x40000008) /* DMA Control / Status Register for Channel 2 */ ++#define DCSR3 __REG(0x4000000c) /* DMA Control / Status Register for Channel 3 */ ++#define DCSR4 __REG(0x40000010) /* DMA Control / Status Register for Channel 4 */ ++#define DCSR5 __REG(0x40000014) /* DMA Control / Status Register for Channel 5 */ ++#define DCSR6 __REG(0x40000018) /* DMA Control / Status Register for Channel 6 */ ++#define DCSR7 __REG(0x4000001c) /* DMA Control / Status Register for Channel 7 */ ++#define DCSR8 __REG(0x40000020) /* DMA Control / Status Register for Channel 8 */ ++#define DCSR9 __REG(0x40000024) /* DMA Control / Status Register for Channel 9 */ ++#define DCSR10 __REG(0x40000028) /* DMA Control / Status Register for Channel 10 */ ++#define DCSR11 __REG(0x4000002c) /* DMA Control / Status Register for Channel 11 */ ++#define DCSR12 __REG(0x40000030) /* DMA Control / Status Register for Channel 12 */ ++#define DCSR13 __REG(0x40000034) /* DMA Control / Status Register for Channel 13 */ ++#define DCSR14 __REG(0x40000038) /* DMA Control / Status Register for Channel 14 */ ++#define DCSR15 __REG(0x4000003c) /* DMA Control / Status Register for Channel 15 */ ++ ++#define DCSR(x) __REG2(0x40000000, (x) << 2) ++ ++#define DCSR_RUN (1 << 31) /* Run Bit (read / write) */ ++#define DCSR_NODESC (1 << 30) /* No-Descriptor Fetch (read / write) */ ++#define DCSR_STOPIRQEN (1 << 29) /* Stop Interrupt Enable (read / write) */ ++#define DCSR_REQPEND (1 << 8) /* Request Pending (read-only) */ ++#define DCSR_STOPSTATE (1 << 3) /* Stop State (read-only) */ ++#define DCSR_ENDINTR (1 << 2) /* End Interrupt (read / write) */ ++#define DCSR_STARTINTR (1 << 1) /* Start Interrupt (read / write) */ ++#define DCSR_BUSERR (1 << 0) /* Bus Error Interrupt (read / write) */ ++ ++#define DINT __REG(0x400000f0) /* DMA Interrupt Register */ ++ ++#define DRCMR0 __REG(0x40000100) /* Request to Channel Map Register for DREQ 0 */ ++#define DRCMR1 __REG(0x40000104) /* Request to Channel Map Register for DREQ 1 */ ++#define DRCMR2 __REG(0x40000108) /* Request to Channel Map Register for I2S receive Request */ ++#define DRCMR3 __REG(0x4000010c) /* Request to Channel Map Register for I2S transmit Request */ ++#define DRCMR4 __REG(0x40000110) /* Request to Channel Map Register for BTUART receive Request */ ++#define DRCMR5 __REG(0x40000114) /* Request to Channel Map Register for BTUART transmit Request. */ ++#define DRCMR6 __REG(0x40000118) /* Request to Channel Map Register for FFUART receive Request */ ++#define DRCMR7 __REG(0x4000011c) /* Request to Channel Map Register for FFUART transmit Request */ ++#define DRCMR8 __REG(0x40000120) /* Request to Channel Map Register for AC97 microphone Request */ ++#define DRCMR9 __REG(0x40000124) /* Request to Channel Map Register for AC97 modem receive Request */ ++#define DRCMR10 __REG(0x40000128) /* Request to Channel Map Register for AC97 modem transmit Request */ ++#define DRCMR11 __REG(0x4000012c) /* Request to Channel Map Register for AC97 audio receive Request */ ++#define DRCMR12 __REG(0x40000130) /* Request to Channel Map Register for AC97 audio transmit Request */ ++#define DRCMR13 __REG(0x40000134) /* Request to Channel Map Register for SSP receive Request */ ++#define DRCMR14 __REG(0x40000138) /* Request to Channel Map Register for SSP transmit Request */ ++#define DRCMR15 __REG(0x4000013c) /* Reserved */ ++#define DRCMR16 __REG(0x40000140) /* Reserved */ ++#define DRCMR17 __REG(0x40000144) /* Request to Channel Map Register for ICP receive Request */ ++#define DRCMR18 __REG(0x40000148) /* Request to Channel Map Register for ICP transmit Request */ ++#define DRCMR19 __REG(0x4000014c) /* Request to Channel Map Register for STUART receive Request */ ++#define DRCMR20 __REG(0x40000150) /* Request to Channel Map Register for STUART transmit Request */ ++#define DRCMR21 __REG(0x40000154) /* Request to Channel Map Register for MMC receive Request */ ++#define DRCMR22 __REG(0x40000158) /* Request to Channel Map Register for MMC transmit Request */ ++#define DRCMR23 __REG(0x4000015c) /* Reserved */ ++#define DRCMR24 __REG(0x40000160) /* Reserved */ ++#define DRCMR25 __REG(0x40000164) /* Request to Channel Map Register for USB endpoint 1 Request */ ++#define DRCMR26 __REG(0x40000168) /* Request to Channel Map Register for USB endpoint 2 Request */ ++#define DRCMR27 __REG(0x4000016C) /* Request to Channel Map Register for USB endpoint 3 Request */ ++#define DRCMR28 __REG(0x40000170) /* Request to Channel Map Register for USB endpoint 4 Request */ ++#define DRCMR29 __REG(0x40000174) /* Reserved */ ++#define DRCMR30 __REG(0x40000178) /* Request to Channel Map Register for USB endpoint 6 Request */ ++#define DRCMR31 __REG(0x4000017C) /* Request to Channel Map Register for USB endpoint 7 Request */ ++#define DRCMR32 __REG(0x40000180) /* Request to Channel Map Register for USB endpoint 8 Request */ ++#define DRCMR33 __REG(0x40000184) /* Request to Channel Map Register for USB endpoint 9 Request */ ++#define DRCMR34 __REG(0x40000188) /* Reserved */ ++#define DRCMR35 __REG(0x4000018C) /* Request to Channel Map Register for USB endpoint 11 Request */ ++#define DRCMR36 __REG(0x40000190) /* Request to Channel Map Register for USB endpoint 12 Request */ ++#define DRCMR37 __REG(0x40000194) /* Request to Channel Map Register for USB endpoint 13 Request */ ++#define DRCMR38 __REG(0x40000198) /* Request to Channel Map Register for USB endpoint 14 Request */ ++#define DRCMR39 __REG(0x4000019C) /* Reserved */ ++ ++#define DRCMRRXSADR DRCMR2 ++#define DRCMRTXSADR DRCMR3 ++#define DRCMRRXBTRBR DRCMR4 ++#define DRCMRTXBTTHR DRCMR5 ++#define DRCMRRXFFRBR DRCMR6 ++#define DRCMRTXFFTHR DRCMR7 ++#define DRCMRRXMCDR DRCMR8 ++#define DRCMRRXMODR DRCMR9 ++#define DRCMRTXMODR DRCMR10 ++#define DRCMRRXPCDR DRCMR11 ++#define DRCMRTXPCDR DRCMR12 ++#define DRCMRRXSSDR DRCMR13 ++#define DRCMRTXSSDR DRCMR14 ++#define DRCMRRXICDR DRCMR17 ++#define DRCMRTXICDR DRCMR18 ++#define DRCMRRXSTRBR DRCMR19 ++#define DRCMRTXSTTHR DRCMR20 ++#define DRCMRRXMMC DRCMR21 ++#define DRCMRTXMMC DRCMR22 ++ ++#define DRCMR_MAPVLD (1 << 7) /* Map Valid (read / write) */ ++#define DRCMR_CHLNUM 0x0f /* mask for Channel Number (read / write) */ ++ ++#define DDADR0 __REG(0x40000200) /* DMA Descriptor Address Register Channel 0 */ ++#define DSADR0 __REG(0x40000204) /* DMA Source Address Register Channel 0 */ ++#define DTADR0 __REG(0x40000208) /* DMA Target Address Register Channel 0 */ ++#define DCMD0 __REG(0x4000020c) /* DMA Command Address Register Channel 0 */ ++#define DDADR1 __REG(0x40000210) /* DMA Descriptor Address Register Channel 1 */ ++#define DSADR1 __REG(0x40000214) /* DMA Source Address Register Channel 1 */ ++#define DTADR1 __REG(0x40000218) /* DMA Target Address Register Channel 1 */ ++#define DCMD1 __REG(0x4000021c) /* DMA Command Address Register Channel 1 */ ++#define DDADR2 __REG(0x40000220) /* DMA Descriptor Address Register Channel 2 */ ++#define DSADR2 __REG(0x40000224) /* DMA Source Address Register Channel 2 */ ++#define DTADR2 __REG(0x40000228) /* DMA Target Address Register Channel 2 */ ++#define DCMD2 __REG(0x4000022c) /* DMA Command Address Register Channel 2 */ ++#define DDADR3 __REG(0x40000230) /* DMA Descriptor Address Register Channel 3 */ ++#define DSADR3 __REG(0x40000234) /* DMA Source Address Register Channel 3 */ ++#define DTADR3 __REG(0x40000238) /* DMA Target Address Register Channel 3 */ ++#define DCMD3 __REG(0x4000023c) /* DMA Command Address Register Channel 3 */ ++#define DDADR4 __REG(0x40000240) /* DMA Descriptor Address Register Channel 4 */ ++#define DSADR4 __REG(0x40000244) /* DMA Source Address Register Channel 4 */ ++#define DTADR4 __REG(0x40000248) /* DMA Target Address Register Channel 4 */ ++#define DCMD4 __REG(0x4000024c) /* DMA Command Address Register Channel 4 */ ++#define DDADR5 __REG(0x40000250) /* DMA Descriptor Address Register Channel 5 */ ++#define DSADR5 __REG(0x40000254) /* DMA Source Address Register Channel 5 */ ++#define DTADR5 __REG(0x40000258) /* DMA Target Address Register Channel 5 */ ++#define DCMD5 __REG(0x4000025c) /* DMA Command Address Register Channel 5 */ ++#define DDADR6 __REG(0x40000260) /* DMA Descriptor Address Register Channel 6 */ ++#define DSADR6 __REG(0x40000264) /* DMA Source Address Register Channel 6 */ ++#define DTADR6 __REG(0x40000268) /* DMA Target Address Register Channel 6 */ ++#define DCMD6 __REG(0x4000026c) /* DMA Command Address Register Channel 6 */ ++#define DDADR7 __REG(0x40000270) /* DMA Descriptor Address Register Channel 7 */ ++#define DSADR7 __REG(0x40000274) /* DMA Source Address Register Channel 7 */ ++#define DTADR7 __REG(0x40000278) /* DMA Target Address Register Channel 7 */ ++#define DCMD7 __REG(0x4000027c) /* DMA Command Address Register Channel 7 */ ++#define DDADR8 __REG(0x40000280) /* DMA Descriptor Address Register Channel 8 */ ++#define DSADR8 __REG(0x40000284) /* DMA Source Address Register Channel 8 */ ++#define DTADR8 __REG(0x40000288) /* DMA Target Address Register Channel 8 */ ++#define DCMD8 __REG(0x4000028c) /* DMA Command Address Register Channel 8 */ ++#define DDADR9 __REG(0x40000290) /* DMA Descriptor Address Register Channel 9 */ ++#define DSADR9 __REG(0x40000294) /* DMA Source Address Register Channel 9 */ ++#define DTADR9 __REG(0x40000298) /* DMA Target Address Register Channel 9 */ ++#define DCMD9 __REG(0x4000029c) /* DMA Command Address Register Channel 9 */ ++#define DDADR10 __REG(0x400002a0) /* DMA Descriptor Address Register Channel 10 */ ++#define DSADR10 __REG(0x400002a4) /* DMA Source Address Register Channel 10 */ ++#define DTADR10 __REG(0x400002a8) /* DMA Target Address Register Channel 10 */ ++#define DCMD10 __REG(0x400002ac) /* DMA Command Address Register Channel 10 */ ++#define DDADR11 __REG(0x400002b0) /* DMA Descriptor Address Register Channel 11 */ ++#define DSADR11 __REG(0x400002b4) /* DMA Source Address Register Channel 11 */ ++#define DTADR11 __REG(0x400002b8) /* DMA Target Address Register Channel 11 */ ++#define DCMD11 __REG(0x400002bc) /* DMA Command Address Register Channel 11 */ ++#define DDADR12 __REG(0x400002c0) /* DMA Descriptor Address Register Channel 12 */ ++#define DSADR12 __REG(0x400002c4) /* DMA Source Address Register Channel 12 */ ++#define DTADR12 __REG(0x400002c8) /* DMA Target Address Register Channel 12 */ ++#define DCMD12 __REG(0x400002cc) /* DMA Command Address Register Channel 12 */ ++#define DDADR13 __REG(0x400002d0) /* DMA Descriptor Address Register Channel 13 */ ++#define DSADR13 __REG(0x400002d4) /* DMA Source Address Register Channel 13 */ ++#define DTADR13 __REG(0x400002d8) /* DMA Target Address Register Channel 13 */ ++#define DCMD13 __REG(0x400002dc) /* DMA Command Address Register Channel 13 */ ++#define DDADR14 __REG(0x400002e0) /* DMA Descriptor Address Register Channel 14 */ ++#define DSADR14 __REG(0x400002e4) /* DMA Source Address Register Channel 14 */ ++#define DTADR14 __REG(0x400002e8) /* DMA Target Address Register Channel 14 */ ++#define DCMD14 __REG(0x400002ec) /* DMA Command Address Register Channel 14 */ ++#define DDADR15 __REG(0x400002f0) /* DMA Descriptor Address Register Channel 15 */ ++#define DSADR15 __REG(0x400002f4) /* DMA Source Address Register Channel 15 */ ++#define DTADR15 __REG(0x400002f8) /* DMA Target Address Register Channel 15 */ ++#define DCMD15 __REG(0x400002fc) /* DMA Command Address Register Channel 15 */ ++ ++#define DDADR(x) __REG2(0x40000200, (x) << 4) ++#define DSADR(x) __REG2(0x40000204, (x) << 4) ++#define DTADR(x) __REG2(0x40000208, (x) << 4) ++#define DCMD(x) __REG2(0x4000020c, (x) << 4) ++ ++#define DDADR_DESCADDR 0xfffffff0 /* Address of next descriptor (mask) */ ++#define DDADR_STOP (1 << 0) /* Stop (read / write) */ ++ ++#define DCMD_INCSRCADDR (1 << 31) /* Source Address Increment Setting. */ ++#define DCMD_INCTRGADDR (1 << 30) /* Target Address Increment Setting. */ ++#define DCMD_FLOWSRC (1 << 29) /* Flow Control by the source. */ ++#define DCMD_FLOWTRG (1 << 28) /* Flow Control by the target. */ ++#define DCMD_STARTIRQEN (1 << 22) /* Start Interrupt Enable */ ++#define DCMD_ENDIRQEN (1 << 21) /* End Interrupt Enable */ ++#define DCMD_ENDIAN (1 << 18) /* Device Endian-ness. */ ++#define DCMD_BURST8 (1 << 16) /* 8 byte burst */ ++#define DCMD_BURST16 (2 << 16) /* 16 byte burst */ ++#define DCMD_BURST32 (3 << 16) /* 32 byte burst */ ++#define DCMD_WIDTH1 (1 << 14) /* 1 byte width */ ++#define DCMD_WIDTH2 (2 << 14) /* 2 byte width (HalfWord) */ ++#define DCMD_WIDTH4 (3 << 14) /* 4 byte width (Word) */ ++#define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */ ++ ++/* default combinations */ ++#define DCMD_RXPCDR (DCMD_INCTRGADDR|DCMD_FLOWSRC|DCMD_BURST32|DCMD_WIDTH4) ++#define DCMD_RXMCDR (DCMD_INCTRGADDR|DCMD_FLOWSRC|DCMD_BURST32|DCMD_WIDTH4) ++#define DCMD_TXPCDR (DCMD_INCSRCADDR|DCMD_FLOWTRG|DCMD_BURST32|DCMD_WIDTH4) ++ ++ ++/* ++ * UARTs ++ */ ++ ++/* Full Function UART (FFUART) */ ++#define FFUART FFRBR ++#define FFRBR __REG(0x40100000) /* Receive Buffer Register (read only) */ ++#define FFTHR __REG(0x40100000) /* Transmit Holding Register (write only) */ ++#define FFIER __REG(0x40100004) /* Interrupt Enable Register (read/write) */ ++#define FFIIR __REG(0x40100008) /* Interrupt ID Register (read only) */ ++#define FFFCR __REG(0x40100008) /* FIFO Control Register (write only) */ ++#define FFLCR __REG(0x4010000C) /* Line Control Register (read/write) */ ++#define FFMCR __REG(0x40100010) /* Modem Control Register (read/write) */ ++#define FFLSR __REG(0x40100014) /* Line Status Register (read only) */ ++#define FFMSR __REG(0x40100018) /* Modem Status Register (read only) */ ++#define FFSPR __REG(0x4010001C) /* Scratch Pad Register (read/write) */ ++#define FFISR __REG(0x40100020) /* Infrared Selection Register (read/write) */ ++#define FFDLL __REG(0x40100000) /* Divisor Latch Low Register (DLAB = 1) (read/write) */ ++#define FFDLH __REG(0x40100004) /* Divisor Latch High Register (DLAB = 1) (read/write) */ ++ ++/* Bluetooth UART (BTUART) */ ++#define BTUART BTRBR ++#define BTRBR __REG(0x40200000) /* Receive Buffer Register (read only) */ ++#define BTTHR __REG(0x40200000) /* Transmit Holding Register (write only) */ ++#define BTIER __REG(0x40200004) /* Interrupt Enable Register (read/write) */ ++#define BTIIR __REG(0x40200008) /* Interrupt ID Register (read only) */ ++#define BTFCR __REG(0x40200008) /* FIFO Control Register (write only) */ ++#define BTLCR __REG(0x4020000C) /* Line Control Register (read/write) */ ++#define BTMCR __REG(0x40200010) /* Modem Control Register (read/write) */ ++#define BTLSR __REG(0x40200014) /* Line Status Register (read only) */ ++#define BTMSR __REG(0x40200018) /* Modem Status Register (read only) */ ++#define BTSPR __REG(0x4020001C) /* Scratch Pad Register (read/write) */ ++#define BTISR __REG(0x40200020) /* Infrared Selection Register (read/write) */ ++#define BTDLL __REG(0x40200000) /* Divisor Latch Low Register (DLAB = 1) (read/write) */ ++#define BTDLH __REG(0x40200004) /* Divisor Latch High Register (DLAB = 1) (read/write) */ ++ ++/* Standard UART (STUART) */ ++#define STUART STRBR ++#define STRBR __REG(0x40700000) /* Receive Buffer Register (read only) */ ++#define STTHR __REG(0x40700000) /* Transmit Holding Register (write only) */ ++#define STIER __REG(0x40700004) /* Interrupt Enable Register (read/write) */ ++#define STIIR __REG(0x40700008) /* Interrupt ID Register (read only) */ ++#define STFCR __REG(0x40700008) /* FIFO Control Register (write only) */ ++#define STLCR __REG(0x4070000C) /* Line Control Register (read/write) */ ++#define STMCR __REG(0x40700010) /* Modem Control Register (read/write) */ ++#define STLSR __REG(0x40700014) /* Line Status Register (read only) */ ++#define STMSR __REG(0x40700018) /* Reserved */ ++#define STSPR __REG(0x4070001C) /* Scratch Pad Register (read/write) */ ++#define STISR __REG(0x40700020) /* Infrared Selection Register (read/write) */ ++#define STDLL __REG(0x40700000) /* Divisor Latch Low Register (DLAB = 1) (read/write) */ ++#define STDLH __REG(0x40700004) /* Divisor Latch High Register (DLAB = 1) (read/write) */ ++ ++#define IER_DMAE (1 << 7) /* DMA Requests Enable */ ++#define IER_UUE (1 << 6) /* UART Unit Enable */ ++#define IER_NRZE (1 << 5) /* NRZ coding Enable */ ++#define IER_RTIOE (1 << 4) /* Receiver Time Out Interrupt Enable */ ++#define IER_MIE (1 << 3) /* Modem Interrupt Enable */ ++#define IER_RLSE (1 << 2) /* Receiver Line Status Interrupt Enable */ ++#define IER_TIE (1 << 1) /* Transmit Data request Interrupt Enable */ ++#define IER_RAVIE (1 << 0) /* Receiver Data Available Interrupt Enable */ ++ ++#define IIR_FIFOES1 (1 << 7) /* FIFO Mode Enable Status */ ++#define IIR_FIFOES0 (1 << 6) /* FIFO Mode Enable Status */ ++#define IIR_TOD (1 << 3) /* Time Out Detected */ ++#define IIR_IID2 (1 << 2) /* Interrupt Source Encoded */ ++#define IIR_IID1 (1 << 1) /* Interrupt Source Encoded */ ++#define IIR_IP (1 << 0) /* Interrupt Pending (active low) */ ++ ++#define FCR_ITL2 (1 << 7) /* Interrupt Trigger Level */ ++#define FCR_ITL1 (1 << 6) /* Interrupt Trigger Level */ ++#define FCR_RESETTF (1 << 2) /* Reset Transmitter FIFO */ ++#define FCR_RESETRF (1 << 1) /* Reset Receiver FIFO */ ++#define FCR_TRFIFOE (1 << 0) /* Transmit and Receive FIFO Enable */ ++#define FCR_ITL_1 (0) ++#define FCR_ITL_8 (FCR_ITL1) ++#define FCR_ITL_16 (FCR_ITL2) ++#define FCR_ITL_32 (FCR_ITL2|FCR_ITL1) ++ ++#define LCR_DLAB (1 << 7) /* Divisor Latch Access Bit */ ++#define LCR_SB (1 << 6) /* Set Break */ ++#define LCR_STKYP (1 << 5) /* Sticky Parity */ ++#define LCR_EPS (1 << 4) /* Even Parity Select */ ++#define LCR_PEN (1 << 3) /* Parity Enable */ ++#define LCR_STB (1 << 2) /* Stop Bit */ ++#define LCR_WLS1 (1 << 1) /* Word Length Select */ ++#define LCR_WLS0 (1 << 0) /* Word Length Select */ ++ ++#define LSR_FIFOE (1 << 7) /* FIFO Error Status */ ++#define LSR_TEMT (1 << 6) /* Transmitter Empty */ ++#define LSR_TDRQ (1 << 5) /* Transmit Data Request */ ++#define LSR_BI (1 << 4) /* Break Interrupt */ ++#define LSR_FE (1 << 3) /* Framing Error */ ++#define LSR_PE (1 << 2) /* Parity Error */ ++#define LSR_OE (1 << 1) /* Overrun Error */ ++#define LSR_DR (1 << 0) /* Data Ready */ ++ ++#define MCR_LOOP (1 << 4) */ ++#define MCR_OUT2 (1 << 3) /* force MSR_DCD in loopback mode */ ++#define MCR_OUT1 (1 << 2) /* force MSR_RI in loopback mode */ ++#define MCR_RTS (1 << 1) /* Request to Send */ ++#define MCR_DTR (1 << 0) /* Data Terminal Ready */ ++ ++#define MSR_DCD (1 << 7) /* Data Carrier Detect */ ++#define MSR_RI (1 << 6) /* Ring Indicator */ ++#define MSR_DSR (1 << 5) /* Data Set Ready */ ++#define MSR_CTS (1 << 4) /* Clear To Send */ ++#define MSR_DDCD (1 << 3) /* Delta Data Carrier Detect */ ++#define MSR_TERI (1 << 2) /* Trailing Edge Ring Indicator */ ++#define MSR_DDSR (1 << 1) /* Delta Data Set Ready */ ++#define MSR_DCTS (1 << 0) /* Delta Clear To Send */ ++ ++/* ++ * IrSR (Infrared Selection Register) ++ */ ++#define STISR_RXPL (1 << 4) /* Receive Data Polarity */ ++#define STISR_TXPL (1 << 3) /* Transmit Data Polarity */ ++#define STISR_XMODE (1 << 2) /* Transmit Pulse Width Select */ ++#define STISR_RCVEIR (1 << 1) /* Receiver SIR Enable */ ++#define STISR_XMITIR (1 << 0) /* Transmitter SIR Enable */ ++ ++ ++/* ++ * I2C registers ++ */ ++ ++#define IBMR __REG(0x40301680) /* I2C Bus Monitor Register - IBMR */ ++#define IDBR __REG(0x40301688) /* I2C Data Buffer Register - IDBR */ ++#define ICR __REG(0x40301690) /* I2C Control Register - ICR */ ++#define ISR __REG(0x40301698) /* I2C Status Register - ISR */ ++#define ISAR __REG(0x403016A0) /* I2C Slave Address Register - ISAR */ ++ ++#define ICR_START (1 << 0) /* start bit */ ++#define ICR_STOP (1 << 1) /* stop bit */ ++#define ICR_ACKNAK (1 << 2) /* send ACK(0) or NAK(1) */ ++#define ICR_TB (1 << 3) /* transfer byte bit */ ++#define ICR_MA (1 << 4) /* master abort */ ++#define ICR_SCLE (1 << 5) /* master clock enable */ ++#define ICR_IUE (1 << 6) /* unit enable */ ++#define ICR_GCD (1 << 7) /* general call disable */ ++#define ICR_ITEIE (1 << 8) /* enable tx interrupts */ ++#define ICR_IRFIE (1 << 9) /* enable rx interrupts */ ++#define ICR_BEIE (1 << 10) /* enable bus error ints */ ++#define ICR_SSDIE (1 << 11) /* slave STOP detected int enable */ ++#define ICR_ALDIE (1 << 12) /* enable arbitration interrupt */ ++#define ICR_SADIE (1 << 13) /* slave address detected int enable */ ++#define ICR_UR (1 << 14) /* unit reset */ ++ ++#define ISR_RWM (1 << 0) /* read/write mode */ ++#define ISR_ACKNAK (1 << 1) /* ack/nak status */ ++#define ISR_UB (1 << 2) /* unit busy */ ++#define ISR_IBB (1 << 3) /* bus busy */ ++#define ISR_SSD (1 << 4) /* slave stop detected */ ++#define ISR_ALD (1 << 5) /* arbitration loss detected */ ++#define ISR_ITE (1 << 6) /* tx buffer empty */ ++#define ISR_IRF (1 << 7) /* rx buffer full */ ++#define ISR_GCAD (1 << 8) /* general call address detected */ ++#define ISR_SAD (1 << 9) /* slave address detected */ ++#define ISR_BED (1 << 10) /* bus error no ACK/NAK */ ++ ++ ++/* ++ * Serial Audio Controller ++ */ ++ ++/* FIXME: This clash with SA1111 defines */ ++#ifndef CONFIG_SA1111 ++#define SACR0 __REG(0x40400000) /* Global Control Register */ ++#define SACR1 __REG(0x40400004) /* Serial Audio I 2 S/MSB-Justified Control Register */ ++#define SASR0 __REG(0x4040000C) /* Serial Audio I 2 S/MSB-Justified Interface and FIFO Status Register */ ++#define SAIMR __REG(0x40400014) /* Serial Audio Interrupt Mask Register */ ++#define SAICR __REG(0x40400018) /* Serial Audio Interrupt Clear Register */ ++#define SADIV __REG(0x40400060) /* Audio Clock Divider Register. */ ++#define SADR __REG(0x40400080) /* Serial Audio Data Register (TX and RX FIFO access Register). */ ++#endif ++ ++ ++/* ++ * AC97 Controller registers ++ */ ++ ++#define POCR __REG(0x40500000) /* PCM Out Control Register */ ++#define POCR_FEIE (1 << 3) /* FIFO Error Interrupt Enable */ ++ ++#define PICR __REG(0x40500004) /* PCM In Control Register */ ++#define PICR_FEIE (1 << 3) /* FIFO Error Interrupt Enable */ ++ ++#define MCCR __REG(0x40500008) /* Mic In Control Register */ ++#define MCCR_FEIE (1 << 3) /* FIFO Error Interrupt Enable */ ++ ++#define GCR __REG(0x4050000C) /* Global Control Register */ ++#define GCR_CDONE_IE (1 << 19) /* Command Done Interrupt Enable */ ++#define GCR_SDONE_IE (1 << 18) /* Status Done Interrupt Enable */ ++#define GCR_SECRDY_IEN (1 << 9) /* Secondary Ready Interrupt Enable */ ++#define GCR_PRIRDY_IEN (1 << 8) /* Primary Ready Interrupt Enable */ ++#define GCR_SECRES_IEN (1 << 5) /* Secondary Resume Interrupt Enable */ ++#define GCR_PRIRES_IEN (1 << 4) /* Primary Resume Interrupt Enable */ ++#define GCR_ACLINK_OFF (1 << 3) /* AC-link Shut Off */ ++#define GCR_WARM_RST (1 << 2) /* AC97 Warm Reset */ ++#define GCR_COLD_RST (1 << 1) /* AC'97 Cold Reset (0 = active) */ ++#define GCR_GIE (1 << 0) /* Codec GPI Interrupt Enable */ ++ ++#define POSR __REG(0x40500010) /* PCM Out Status Register */ ++#define POSR_FIFOE (1 << 4) /* FIFO error */ ++ ++#define PISR __REG(0x40500014) /* PCM In Status Register */ ++#define PISR_FIFOE (1 << 4) /* FIFO error */ ++ ++#define MCSR __REG(0x40500018) /* Mic In Status Register */ ++#define MCSR_FIFOE (1 << 4) /* FIFO error */ ++ ++#define GSR __REG(0x4050001C) /* Global Status Register */ ++#define GSR_CDONE (1 << 19) /* Command Done */ ++#define GSR_SDONE (1 << 18) /* Status Done */ ++#define GSR_RDCS (1 << 15) /* Read Completion Status */ ++#define GSR_BIT3SLT12 (1 << 14) /* Bit 3 of slot 12 */ ++#define GSR_BIT2SLT12 (1 << 13) /* Bit 2 of slot 12 */ ++#define GSR_BIT1SLT12 (1 << 12) /* Bit 1 of slot 12 */ ++#define GSR_SECRES (1 << 11) /* Secondary Resume Interrupt */ ++#define GSR_PRIRES (1 << 10) /* Primary Resume Interrupt */ ++#define GSR_SCR (1 << 9) /* Secondary Codec Ready */ ++#define GSR_PCR (1 << 8) /* Primary Codec Ready */ ++#define GSR_MINT (1 << 7) /* Mic In Interrupt */ ++#define GSR_POINT (1 << 6) /* PCM Out Interrupt */ ++#define GSR_PIINT (1 << 5) /* PCM In Interrupt */ ++#define GSR_MOINT (1 << 2) /* Modem Out Interrupt */ ++#define GSR_MIINT (1 << 1) /* Modem In Interrupt */ ++#define GSR_GSCI (1 << 0) /* Codec GPI Status Change Interrupt */ ++ ++#define CAR __REG(0x40500020) /* CODEC Access Register */ ++#define CAR_CAIP (1 << 0) /* Codec Access In Progress */ ++ ++#define PCDR __REG(0x40500040) /* PCM FIFO Data Register */ ++#define MCDR __REG(0x40500060) /* Mic-in FIFO Data Register */ ++ ++#define MOCR __REG(0x40500100) /* Modem Out Control Register */ ++#define MOCR_FEIE (1 << 3) /* FIFO Error */ ++ ++#define MICR __REG(0x40500108) /* Modem In Control Register */ ++#define MICR_FEIE (1 << 3) /* FIFO Error */ ++ ++#define MOSR __REG(0x40500110) /* Modem Out Status Register */ ++#define MOSR_FIFOE (1 << 4) /* FIFO error */ ++ ++#define MISR __REG(0x40500118) /* Modem In Status Register */ ++#define MISR_FIFOE (1 << 4) /* FIFO error */ ++ ++#define MODR __REG(0x40500140) /* Modem FIFO Data Register */ ++ ++#define PAC_REG_BASE __REG(0x40500200) /* Primary Audio Codec */ ++#define SAC_REG_BASE __REG(0x40500300) /* Secondary Audio Codec */ ++#define PMC_REG_BASE __REG(0x40500400) /* Primary Modem Codec */ ++#define SMC_REG_BASE __REG(0x40500500) /* Secondary Modem Codec */ ++ ++ ++/* ++ * USB Device Controller ++ */ ++#define UDC_RES1 __REG(0x40600004) /* UDC Undocumented - Reserved1 */ ++#define UDC_RES2 __REG(0x40600008) /* UDC Undocumented - Reserved2 */ ++#define UDC_RES3 __REG(0x4060000C) /* UDC Undocumented - Reserved3 */ ++ ++#define UDCCR __REG(0x40600000) /* UDC Control Register */ ++#define UDCCR_UDE (1 << 0) /* UDC enable */ ++#define UDCCR_UDA (1 << 1) /* UDC active */ ++#define UDCCR_RSM (1 << 2) /* Device resume */ ++#define UDCCR_RESIR (1 << 3) /* Resume interrupt request */ ++#define UDCCR_SUSIR (1 << 4) /* Suspend interrupt request */ ++#define UDCCR_SRM (1 << 5) /* Suspend/resume interrupt mask */ ++#define UDCCR_RSTIR (1 << 6) /* Reset interrupt request */ ++#define UDCCR_REM (1 << 7) /* Reset interrupt mask */ ++ ++#define UDCCS0 __REG(0x40600010) /* UDC Endpoint 0 Control/Status Register */ ++#define UDCCS0_OPR (1 << 0) /* OUT packet ready */ ++#define UDCCS0_IPR (1 << 1) /* IN packet ready */ ++#define UDCCS0_FTF (1 << 2) /* Flush Tx FIFO */ ++#define UDCCS0_DRWF (1 << 3) /* Device remote wakeup feature */ ++#define UDCCS0_SST (1 << 4) /* Sent stall */ ++#define UDCCS0_FST (1 << 5) /* Force stall */ ++#define UDCCS0_RNE (1 << 6) /* Receive FIFO no empty */ ++#define UDCCS0_SA (1 << 7) /* Setup active */ ++ ++/* Bulk IN - Endpoint 1,6,11 */ ++#define UDCCS1 __REG(0x40600014) /* UDC Endpoint 1 (IN) Control/Status Register */ ++#define UDCCS6 __REG(0x40600028) /* UDC Endpoint 6 (IN) Control/Status Register */ ++#define UDCCS11 __REG(0x4060003C) /* UDC Endpoint 11 (IN) Control/Status Register */ ++ ++#define UDCCS_BI_TFS (1 << 0) /* Transmit FIFO service */ ++#define UDCCS_BI_TPC (1 << 1) /* Transmit packet complete */ ++#define UDCCS_BI_FTF (1 << 2) /* Flush Tx FIFO */ ++#define UDCCS_BI_TUR (1 << 3) /* Transmit FIFO underrun */ ++#define UDCCS_BI_SST (1 << 4) /* Sent stall */ ++#define UDCCS_BI_FST (1 << 5) /* Force stall */ ++#define UDCCS_BI_TSP (1 << 7) /* Transmit short packet */ ++ ++/* Bulk OUT - Endpoint 2,7,12 */ ++#define UDCCS2 __REG(0x40600018) /* UDC Endpoint 2 (OUT) Control/Status Register */ ++#define UDCCS7 __REG(0x4060002C) /* UDC Endpoint 7 (OUT) Control/Status Register */ ++#define UDCCS12 __REG(0x40600040) /* UDC Endpoint 12 (OUT) Control/Status Register */ ++ ++#define UDCCS_BO_RFS (1 << 0) /* Receive FIFO service */ ++#define UDCCS_BO_RPC (1 << 1) /* Receive packet complete */ ++#define UDCCS_BO_DME (1 << 3) /* DMA enable */ ++#define UDCCS_BO_SST (1 << 4) /* Sent stall */ ++#define UDCCS_BO_FST (1 << 5) /* Force stall */ ++#define UDCCS_BO_RNE (1 << 6) /* Receive FIFO not empty */ ++#define UDCCS_BO_RSP (1 << 7) /* Receive short packet */ ++ ++/* Isochronous IN - Endpoint 3,8,13 */ ++#define UDCCS3 __REG(0x4060001C) /* UDC Endpoint 3 (IN) Control/Status Register */ ++#define UDCCS8 __REG(0x40600030) /* UDC Endpoint 8 (IN) Control/Status Register */ ++#define UDCCS13 __REG(0x40600044) /* UDC Endpoint 13 (IN) Control/Status Register */ ++ ++#define UDCCS_II_TFS (1 << 0) /* Transmit FIFO service */ ++#define UDCCS_II_TPC (1 << 1) /* Transmit packet complete */ ++#define UDCCS_II_FTF (1 << 2) /* Flush Tx FIFO */ ++#define UDCCS_II_TUR (1 << 3) /* Transmit FIFO underrun */ ++#define UDCCS_II_TSP (1 << 7) /* Transmit short packet */ ++ ++/* Isochronous OUT - Endpoint 4,9,14 */ ++#define UDCCS4 __REG(0x40600020) /* UDC Endpoint 4 (OUT) Control/Status Register */ ++#define UDCCS9 __REG(0x40600034) /* UDC Endpoint 9 (OUT) Control/Status Register */ ++#define UDCCS14 __REG(0x40600048) /* UDC Endpoint 14 (OUT) Control/Status Register */ ++ ++#define UDCCS_IO_RFS (1 << 0) /* Receive FIFO service */ ++#define UDCCS_IO_RPC (1 << 1) /* Receive packet complete */ ++#define UDCCS_IO_ROF (1 << 3) /* Receive overflow */ ++#define UDCCS_IO_DME (1 << 3) /* DMA enable */ ++#define UDCCS_IO_RNE (1 << 6) /* Receive FIFO not empty */ ++#define UDCCS_IO_RSP (1 << 7) /* Receive short packet */ ++ ++/* Interrupt IN - Endpoint 5,10,15 */ ++#define UDCCS5 __REG(0x40600024) /* UDC Endpoint 5 (Interrupt) Control/Status Register */ ++#define UDCCS10 __REG(0x40600038) /* UDC Endpoint 10 (Interrupt) Control/Status Register */ ++#define UDCCS15 __REG(0x4060004C) /* UDC Endpoint 15 (Interrupt) Control/Status Register */ ++ ++#define UDCCS_INT_TFS (1 << 0) /* Transmit FIFO service */ ++#define UDCCS_INT_TPC (1 << 1) /* Transmit packet complete */ ++#define UDCCS_INT_FTF (1 << 2) /* Flush Tx FIFO */ ++#define UDCCS_INT_TUR (1 << 3) /* Transmit FIFO underrun */ ++#define UDCCS_INT_SST (1 << 4) /* Sent stall */ ++#define UDCCS_INT_FST (1 << 5) /* Force stall */ ++#define UDCCS_INT_TSP (1 << 7) /* Transmit short packet */ ++ ++#define UFNRH __REG(0x40600060) /* UDC Frame Number Register High */ ++#define UFNRL __REG(0x40600064) /* UDC Frame Number Register Low */ ++#define UBCR2 __REG(0x40600068) /* UDC Byte Count Reg 2 */ ++#define UBCR4 __REG(0x4060006c) /* UDC Byte Count Reg 4 */ ++#define UBCR7 __REG(0x40600070) /* UDC Byte Count Reg 7 */ ++#define UBCR9 __REG(0x40600074) /* UDC Byte Count Reg 9 */ ++#define UBCR12 __REG(0x40600078) /* UDC Byte Count Reg 12 */ ++#define UBCR14 __REG(0x4060007c) /* UDC Byte Count Reg 14 */ ++#define UDDR0 __REG(0x40600080) /* UDC Endpoint 0 Data Register */ ++#define UDDR1 __REG(0x40600100) /* UDC Endpoint 1 Data Register */ ++#define UDDR2 __REG(0x40600180) /* UDC Endpoint 2 Data Register */ ++#define UDDR3 __REG(0x40600200) /* UDC Endpoint 3 Data Register */ ++#define UDDR4 __REG(0x40600400) /* UDC Endpoint 4 Data Register */ ++#define UDDR5 __REG(0x406000A0) /* UDC Endpoint 5 Data Register */ ++#define UDDR6 __REG(0x40600600) /* UDC Endpoint 6 Data Register */ ++#define UDDR7 __REG(0x40600680) /* UDC Endpoint 7 Data Register */ ++#define UDDR8 __REG(0x40600700) /* UDC Endpoint 8 Data Register */ ++#define UDDR9 __REG(0x40600900) /* UDC Endpoint 9 Data Register */ ++#define UDDR10 __REG(0x406000C0) /* UDC Endpoint 10 Data Register */ ++#define UDDR11 __REG(0x40600B00) /* UDC Endpoint 11 Data Register */ ++#define UDDR12 __REG(0x40600B80) /* UDC Endpoint 12 Data Register */ ++#define UDDR13 __REG(0x40600C00) /* UDC Endpoint 13 Data Register */ ++#define UDDR14 __REG(0x40600E00) /* UDC Endpoint 14 Data Register */ ++#define UDDR15 __REG(0x406000E0) /* UDC Endpoint 15 Data Register */ ++ ++#define UICR0 __REG(0x40600050) /* UDC Interrupt Control Register 0 */ ++ ++#define UICR0_IM0 (1 << 0) /* Interrupt mask ep 0 */ ++#define UICR0_IM1 (1 << 1) /* Interrupt mask ep 1 */ ++#define UICR0_IM2 (1 << 2) /* Interrupt mask ep 2 */ ++#define UICR0_IM3 (1 << 3) /* Interrupt mask ep 3 */ ++#define UICR0_IM4 (1 << 4) /* Interrupt mask ep 4 */ ++#define UICR0_IM5 (1 << 5) /* Interrupt mask ep 5 */ ++#define UICR0_IM6 (1 << 6) /* Interrupt mask ep 6 */ ++#define UICR0_IM7 (1 << 7) /* Interrupt mask ep 7 */ ++ ++#define UICR1 __REG(0x40600054) /* UDC Interrupt Control Register 1 */ ++ ++#define UICR1_IM8 (1 << 0) /* Interrupt mask ep 8 */ ++#define UICR1_IM9 (1 << 1) /* Interrupt mask ep 9 */ ++#define UICR1_IM10 (1 << 2) /* Interrupt mask ep 10 */ ++#define UICR1_IM11 (1 << 3) /* Interrupt mask ep 11 */ ++#define UICR1_IM12 (1 << 4) /* Interrupt mask ep 12 */ ++#define UICR1_IM13 (1 << 5) /* Interrupt mask ep 13 */ ++#define UICR1_IM14 (1 << 6) /* Interrupt mask ep 14 */ ++#define UICR1_IM15 (1 << 7) /* Interrupt mask ep 15 */ ++ ++#define USIR0 __REG(0x40600058) /* UDC Status Interrupt Register 0 */ ++ ++#define USIR0_IR0 (1 << 0) /* Interrup request ep 0 */ ++#define USIR0_IR1 (1 << 1) /* Interrup request ep 1 */ ++#define USIR0_IR2 (1 << 2) /* Interrup request ep 2 */ ++#define USIR0_IR3 (1 << 3) /* Interrup request ep 3 */ ++#define USIR0_IR4 (1 << 4) /* Interrup request ep 4 */ ++#define USIR0_IR5 (1 << 5) /* Interrup request ep 5 */ ++#define USIR0_IR6 (1 << 6) /* Interrup request ep 6 */ ++#define USIR0_IR7 (1 << 7) /* Interrup request ep 7 */ ++ ++#define USIR1 __REG(0x4060005C) /* UDC Status Interrupt Register 1 */ ++ ++#define USIR1_IR8 (1 << 0) /* Interrup request ep 8 */ ++#define USIR1_IR9 (1 << 1) /* Interrup request ep 9 */ ++#define USIR1_IR10 (1 << 2) /* Interrup request ep 10 */ ++#define USIR1_IR11 (1 << 3) /* Interrup request ep 11 */ ++#define USIR1_IR12 (1 << 4) /* Interrup request ep 12 */ ++#define USIR1_IR13 (1 << 5) /* Interrup request ep 13 */ ++#define USIR1_IR14 (1 << 6) /* Interrup request ep 14 */ ++#define USIR1_IR15 (1 << 7) /* Interrup request ep 15 */ ++ ++ ++/* ++ * Fast Infrared Communication Port ++ */ ++ ++#define ICCR0 __REG(0x40800000) /* ICP Control Register 0 */ ++#define ICCR1 __REG(0x40800004) /* ICP Control Register 1 */ ++#define ICCR2 __REG(0x40800008) /* ICP Control Register 2 */ ++#define ICDR __REG(0x4080000c) /* ICP Data Register */ ++#define ICSR0 __REG(0x40800014) /* ICP Status Register 0 */ ++#define ICSR1 __REG(0x40800018) /* ICP Status Register 1 */ ++ ++#define ICCR0_AME (1 << 7) /* Adress match enable */ ++#define ICCR0_TIE (1 << 6) /* Transmit FIFO interrupt enable */ ++#define ICCR0_RIE (1 << 5) /* Recieve FIFO interrupt enable */ ++#define ICCR0_RXE (1 << 4) /* Receive enable */ ++#define ICCR0_TXE (1 << 3) /* Transmit enable */ ++#define ICCR0_TUS (1 << 2) /* Transmit FIFO underrun select */ ++#define ICCR0_LBM (1 << 1) /* Loopback mode */ ++#define ICCR0_ITR (1 << 0) /* IrDA transmission */ ++ ++#define ICSR0_FRE (1 << 5) /* Framing error */ ++#define ICSR0_RFS (1 << 4) /* Receive FIFO service request */ ++#define ICSR0_TFS (1 << 3) /* Transnit FIFO service request */ ++#define ICSR0_RAB (1 << 2) /* Receiver abort */ ++#define ICSR0_TUR (1 << 1) /* Trunsmit FIFO underun */ ++#define ICSR0_EIF (1 << 0) /* End/Error in FIFO */ ++ ++#define ICSR1_ROR (1 << 6) /* Receiver FIFO underrun */ ++#define ICSR1_CRE (1 << 5) /* CRC error */ ++#define ICSR1_EOF (1 << 4) /* End of frame */ ++#define ICSR1_TNF (1 << 3) /* Transmit FIFO not full */ ++#define ICSR1_RNE (1 << 2) /* Receive FIFO not empty */ ++#define ICSR1_TBY (1 << 1) /* Tramsmiter busy flag */ ++#define ICSR1_RSY (1 << 0) /* Recevier synchronized flag */ ++ ++ ++/* ++ * Real Time Clock ++ */ ++ ++#define RCNR __REG(0x40900000) /* RTC Count Register */ ++#define RTAR __REG(0x40900004) /* RTC Alarm Register */ ++#define RTSR __REG(0x40900008) /* RTC Status Register */ ++#define RTTR __REG(0x4090000C) /* RTC Timer Trim Register */ ++ ++#define RTSR_HZE (1 << 3) /* HZ interrupt enable */ ++#define RTSR_ALE (1 << 2) /* RTC alarm interrupt enable */ ++#define RTSR_HZ (1 << 1) /* HZ rising-edge detected */ ++#define RTSR_AL (1 << 0) /* RTC alarm detected */ ++ ++ ++/* ++ * OS Timer & Match Registers ++ */ ++ ++#define OSMR0 __REG(0x40A00000) /* */ ++#define OSMR1 __REG(0x40A00004) /* */ ++#define OSMR2 __REG(0x40A00008) /* */ ++#define OSMR3 __REG(0x40A0000C) /* */ ++#define OSCR __REG(0x40A00010) /* OS Timer Counter Register */ ++#define OSSR __REG(0x40A00014) /* OS Timer Status Register */ ++#define OWER __REG(0x40A00018) /* OS Timer Watchdog Enable Register */ ++#define OIER __REG(0x40A0001C) /* OS Timer Interrupt Enable Register */ ++ ++#define OSSR_M3 (1 << 3) /* Match status channel 3 */ ++#define OSSR_M2 (1 << 2) /* Match status channel 2 */ ++#define OSSR_M1 (1 << 1) /* Match status channel 1 */ ++#define OSSR_M0 (1 << 0) /* Match status channel 0 */ ++ ++#define OWER_WME (1 << 0) /* Watchdog Match Enable */ ++ ++#define OIER_E3 (1 << 3) /* Interrupt enable channel 3 */ ++#define OIER_E2 (1 << 2) /* Interrupt enable channel 2 */ ++#define OIER_E1 (1 << 1) /* Interrupt enable channel 1 */ ++#define OIER_E0 (1 << 0) /* Interrupt enable channel 0 */ ++ ++ ++/* ++ * Pulse Width Modulator ++ */ ++ ++#define PWM_CTRL0 __REG(0x40B00000) /* PWM 0 Control Register */ ++#define PWM_PWDUTY0 __REG(0x40B00004) /* PWM 0 Duty Cycle Register */ ++#define PWM_PERVAL0 __REG(0x40B00008) /* PWM 0 Period Control Register */ ++ ++#define PWM_CTRL1 __REG(0x40C00000) /* PWM 1Control Register */ ++#define PWM_PWDUTY1 __REG(0x40C00004) /* PWM 1 Duty Cycle Register */ ++#define PWM_PERVAL1 __REG(0x40C00008) /* PWM 1 Period Control Register */ ++ ++ ++/* ++ * Interrupt Controller ++ */ ++ ++#define ICIP __REG(0x40D00000) /* Interrupt Controller IRQ Pending Register */ ++#define ICMR __REG(0x40D00004) /* Interrupt Controller Mask Register */ ++#define ICLR __REG(0x40D00008) /* Interrupt Controller Level Register */ ++#define ICFP __REG(0x40D0000C) /* Interrupt Controller FIQ Pending Register */ ++#define ICPR __REG(0x40D00010) /* Interrupt Controller Pending Register */ ++#define ICCR __REG(0x40D00014) /* Interrupt Controller Control Register */ ++ ++ ++/* ++ * General Purpose I/O ++ */ ++ ++#define GPLR0 __REG(0x40E00000) /* GPIO Pin-Level Register GPIO<31:0> */ ++#define GPLR1 __REG(0x40E00004) /* GPIO Pin-Level Register GPIO<63:32> */ ++#define GPLR2 __REG(0x40E00008) /* GPIO Pin-Level Register GPIO<80:64> */ ++ ++#define GPDR0 __REG(0x40E0000C) /* GPIO Pin Direction Register GPIO<31:0> */ ++#define GPDR1 __REG(0x40E00010) /* GPIO Pin Direction Register GPIO<63:32> */ ++#define GPDR2 __REG(0x40E00014) /* GPIO Pin Direction Register GPIO<80:64> */ ++ ++#define GPSR0 __REG(0x40E00018) /* GPIO Pin Output Set Register GPIO<31:0> */ ++#define GPSR1 __REG(0x40E0001C) /* GPIO Pin Output Set Register GPIO<63:32> */ ++#define GPSR2 __REG(0x40E00020) /* GPIO Pin Output Set Register GPIO<80:64> */ ++ ++#define GPCR0 __REG(0x40E00024) /* GPIO Pin Output Clear Register GPIO<31:0> */ ++#define GPCR1 __REG(0x40E00028) /* GPIO Pin Output Clear Register GPIO <63:32> */ ++#define GPCR2 __REG(0x40E0002C) /* GPIO Pin Output Clear Register GPIO <80:64> */ ++ ++#define GRER0 __REG(0x40E00030) /* GPIO Rising-Edge Detect Register GPIO<31:0> */ ++#define GRER1 __REG(0x40E00034) /* GPIO Rising-Edge Detect Register GPIO<63:32> */ ++#define GRER2 __REG(0x40E00038) /* GPIO Rising-Edge Detect Register GPIO<80:64> */ ++ ++#define GFER0 __REG(0x40E0003C) /* GPIO Falling-Edge Detect Register GPIO<31:0> */ ++#define GFER1 __REG(0x40E00040) /* GPIO Falling-Edge Detect Register GPIO<63:32> */ ++#define GFER2 __REG(0x40E00044) /* GPIO Falling-Edge Detect Register GPIO<80:64> */ ++ ++#define GEDR0 __REG(0x40E00048) /* GPIO Edge Detect Status Register GPIO<31:0> */ ++#define GEDR1 __REG(0x40E0004C) /* GPIO Edge Detect Status Register GPIO<63:32> */ ++#define GEDR2 __REG(0x40E00050) /* GPIO Edge Detect Status Register GPIO<80:64> */ ++ ++#define GAFR0_L __REG(0x40E00054) /* GPIO Alternate Function Select Register GPIO<15:0> */ ++#define GAFR0_U __REG(0x40E00058) /* GPIO Alternate Function Select Register GPIO<31:16> */ ++#define GAFR1_L __REG(0x40E0005C) /* GPIO Alternate Function Select Register GPIO<47:32> */ ++#define GAFR1_U __REG(0x40E00060) /* GPIO Alternate Function Select Register GPIO<63:48> */ ++#define GAFR2_L __REG(0x40E00064) /* GPIO Alternate Function Select Register GPIO<79:64> */ ++#define GAFR2_U __REG(0x40E00068) /* GPIO Alternate Function Select Register GPIO 80 */ ++ ++/* More handy macros. The argument is a literal GPIO number. */ ++ ++#define GPIO_bit(x) (1 << ((x) & 0x1f)) ++#define GPLR(x) __REG2(0x40E00000, ((x) & 0x60) >> 3) ++#define GPDR(x) __REG2(0x40E0000C, ((x) & 0x60) >> 3) ++#define GPSR(x) __REG2(0x40E00018, ((x) & 0x60) >> 3) ++#define GPCR(x) __REG2(0x40E00024, ((x) & 0x60) >> 3) ++#define GRER(x) __REG2(0x40E00030, ((x) & 0x60) >> 3) ++#define GFER(x) __REG2(0x40E0003C, ((x) & 0x60) >> 3) ++#define GEDR(x) __REG2(0x40E00048, ((x) & 0x60) >> 3) ++#define GAFR(x) __REG2(0x40E00054, ((x) & 0x70) >> 2) ++ ++/* GPIO alternate function assignments */ ++ ++#define GPIO1_RST 1 /* reset */ ++#define GPIO6_MMCCLK 6 /* MMC Clock */ ++#define GPIO8_48MHz 7 /* 48 MHz clock output */ ++#define GPIO8_MMCCS0 8 /* MMC Chip Select 0 */ ++#define GPIO9_MMCCS1 9 /* MMC Chip Select 1 */ ++#define GPIO10_RTCCLK 10 /* real time clock (1 Hz) */ ++#define GPIO11_3_6MHz 11 /* 3.6 MHz oscillator out */ ++#define GPIO12_32KHz 12 /* 32 kHz out */ ++#define GPIO13_MBGNT 13 /* memory controller grant */ ++#define GPIO14_MBREQ 14 /* alternate bus master request */ ++#define GPIO15_nCS_1 15 /* chip select 1 */ ++#define GPIO16_PWM0 16 /* PWM0 output */ ++#define GPIO17_PWM1 17 /* PWM1 output */ ++#define GPIO18_RDY 18 /* Ext. Bus Ready */ ++#define GPIO19_DREQ1 19 /* External DMA Request */ ++#define GPIO20_DREQ0 20 /* External DMA Request */ ++#define GPIO23_SCLK 23 /* SSP clock */ ++#define GPIO24_SFRM 24 /* SSP Frame */ ++#define GPIO25_STXD 25 /* SSP transmit */ ++#define GPIO26_SRXD 26 /* SSP receive */ ++#define GPIO27_SEXTCLK 27 /* SSP ext_clk */ ++#define GPIO28_BITCLK 28 /* AC97/I2S bit_clk */ ++#define GPIO29_SDATA_IN 29 /* AC97 Sdata_in0 / I2S Sdata_in */ ++#define GPIO30_SDATA_OUT 30 /* AC97/I2S Sdata_out */ ++#define GPIO31_SYNC 31 /* AC97/I2S sync */ ++#define GPIO32_SDATA_IN1 32 /* AC97 Sdata_in1 */ ++#define GPIO33_nCS_5 33 /* chip select 5 */ ++#define GPIO34_FFRXD 34 /* FFUART receive */ ++#define GPIO34_MMCCS0 34 /* MMC Chip Select 0 */ ++#define GPIO35_FFCTS 35 /* FFUART Clear to send */ ++#define GPIO36_FFDCD 36 /* FFUART Data carrier detect */ ++#define GPIO37_FFDSR 37 /* FFUART data set ready */ ++#define GPIO38_FFRI 38 /* FFUART Ring Indicator */ ++#define GPIO39_MMCCS1 39 /* MMC Chip Select 1 */ ++#define GPIO39_FFTXD 39 /* FFUART transmit data */ ++#define GPIO40_FFDTR 40 /* FFUART data terminal Ready */ ++#define GPIO41_FFRTS 41 /* FFUART request to send */ ++#define GPIO42_BTRXD 42 /* BTUART receive data */ ++#define GPIO43_BTTXD 43 /* BTUART transmit data */ ++#define GPIO44_BTCTS 44 /* BTUART clear to send */ ++#define GPIO45_BTRTS 45 /* BTUART request to send */ ++#define GPIO46_ICPRXD 46 /* ICP receive data */ ++#define GPIO46_STRXD 46 /* STD_UART receive data */ ++#define GPIO47_ICPTXD 47 /* ICP transmit data */ ++#define GPIO47_STTXD 47 /* STD_UART transmit data */ ++#define GPIO48_nPOE 48 /* Output Enable for Card Space */ ++#define GPIO49_nPWE 49 /* Write Enable for Card Space */ ++#define GPIO50_nPIOR 50 /* I/O Read for Card Space */ ++#define GPIO51_nPIOW 51 /* I/O Write for Card Space */ ++#define GPIO52_nPCE_1 52 /* Card Enable for Card Space */ ++#define GPIO53_nPCE_2 53 /* Card Enable for Card Space */ ++#define GPIO53_MMCCLK 53 /* MMC Clock */ ++#define GPIO54_MMCCLK 54 /* MMC Clock */ ++#define GPIO54_pSKTSEL 54 /* Socket Select for Card Space */ ++#define GPIO55_nPREG 55 /* Card Address bit 26 */ ++#define GPIO56_nPWAIT 56 /* Wait signal for Card Space */ ++#define GPIO57_nIOIS16 57 /* Bus Width select for I/O Card Space */ ++#define GPIO58_LDD_0 58 /* LCD data pin 0 */ ++#define GPIO59_LDD_1 59 /* LCD data pin 1 */ ++#define GPIO60_LDD_2 60 /* LCD data pin 2 */ ++#define GPIO61_LDD_3 61 /* LCD data pin 3 */ ++#define GPIO62_LDD_4 62 /* LCD data pin 4 */ ++#define GPIO63_LDD_5 63 /* LCD data pin 5 */ ++#define GPIO64_LDD_6 64 /* LCD data pin 6 */ ++#define GPIO65_LDD_7 65 /* LCD data pin 7 */ ++#define GPIO66_LDD_8 66 /* LCD data pin 8 */ ++#define GPIO66_MBREQ 66 /* alternate bus master req */ ++#define GPIO67_LDD_9 67 /* LCD data pin 9 */ ++#define GPIO67_MMCCS0 67 /* MMC Chip Select 0 */ ++#define GPIO68_LDD_10 68 /* LCD data pin 10 */ ++#define GPIO68_MMCCS1 68 /* MMC Chip Select 1 */ ++#define GPIO69_LDD_11 69 /* LCD data pin 11 */ ++#define GPIO69_MMCCLK 69 /* MMC_CLK */ ++#define GPIO70_LDD_12 70 /* LCD data pin 12 */ ++#define GPIO70_RTCCLK 70 /* Real Time clock (1 Hz) */ ++#define GPIO71_LDD_13 71 /* LCD data pin 13 */ ++#define GPIO71_3_6MHz 71 /* 3.6 MHz Oscillator clock */ ++#define GPIO72_LDD_14 72 /* LCD data pin 14 */ ++#define GPIO72_32kHz 72 /* 32 kHz clock */ ++#define GPIO73_LDD_15 73 /* LCD data pin 15 */ ++#define GPIO73_MBGNT 73 /* Memory controller grant */ ++#define GPIO74_LCD_FCLK 74 /* LCD Frame clock */ ++#define GPIO75_LCD_LCLK 75 /* LCD line clock */ ++#define GPIO76_LCD_PCLK 76 /* LCD Pixel clock */ ++#define GPIO77_LCD_ACBIAS 77 /* LCD AC Bias */ ++#define GPIO78_nCS_2 78 /* chip select 2 */ ++#define GPIO79_nCS_3 79 /* chip select 3 */ ++#define GPIO80_nCS_4 80 /* chip select 4 */ ++ ++/* GPIO alternate function mode & direction */ ++ ++#define GPIO_IN 0x000 ++#define GPIO_OUT 0x080 ++#define GPIO_ALT_FN_1_IN 0x100 ++#define GPIO_ALT_FN_1_OUT 0x180 ++#define GPIO_ALT_FN_2_IN 0x200 ++#define GPIO_ALT_FN_2_OUT 0x280 ++#define GPIO_ALT_FN_3_IN 0x300 ++#define GPIO_ALT_FN_3_OUT 0x380 ++#define GPIO_MD_MASK_NR 0x07f ++#define GPIO_MD_MASK_DIR 0x080 ++#define GPIO_MD_MASK_FN 0x300 ++ ++#define GPIO1_RTS_MD ( 1 | GPIO_ALT_FN_1_IN) ++#define GPIO6_MMCCLK_MD ( 6 | GPIO_ALT_FN_1_OUT) ++#define GPIO8_48MHz_MD ( 8 | GPIO_ALT_FN_1_OUT) ++#define GPIO8_MMCCS0_MD ( 8 | GPIO_ALT_FN_1_OUT) ++#define GPIO9_MMCCS1_MD ( 9 | GPIO_ALT_FN_1_OUT) ++#define GPIO10_RTCCLK_MD (10 | GPIO_ALT_FN_1_OUT) ++#define GPIO11_3_6MHz_MD (11 | GPIO_ALT_FN_1_OUT) ++#define GPIO12_32KHz_MD (12 | GPIO_ALT_FN_1_OUT) ++#define GPIO13_MBGNT_MD (13 | GPIO_ALT_FN_2_OUT) ++#define GPIO14_MBREQ_MD (14 | GPIO_ALT_FN_1_IN) ++#define GPIO15_nCS_1_MD (15 | GPIO_ALT_FN_2_OUT) ++#define GPIO16_PWM0_MD (16 | GPIO_ALT_FN_2_OUT) ++#define GPIO17_PWM1_MD (17 | GPIO_ALT_FN_2_OUT) ++#define GPIO18_RDY_MD (18 | GPIO_ALT_FN_1_IN) ++#define GPIO19_DREQ1_MD (19 | GPIO_ALT_FN_1_IN) ++#define GPIO20_DREQ0_MD (20 | GPIO_ALT_FN_1_IN) ++#define GPIO23_SCLK_md (23 | GPIO_ALT_FN_2_OUT) ++#define GPIO24_SFRM_MD (24 | GPIO_ALT_FN_2_OUT) ++#define GPIO25_STXD_MD (25 | GPIO_ALT_FN_2_OUT) ++#define GPIO26_SRXD_MD (26 | GPIO_ALT_FN_1_IN) ++#define GPIO27_SEXTCLK_MD (27 | GPIO_ALT_FN_1_IN) ++#define GPIO28_BITCLK_AC97_MD (28 | GPIO_ALT_FN_1_IN) ++#define GPIO28_BITCLK_I2S_MD (28 | GPIO_ALT_FN_2_IN) ++#define GPIO29_SDATA_IN_AC97_MD (29 | GPIO_ALT_FN_1_IN) ++#define GPIO29_SDATA_IN_I2S_MD (29 | GPIO_ALT_FN_2_IN) ++#define GPIO30_SDATA_OUT_AC97_MD (30 | GPIO_ALT_FN_2_OUT) ++#define GPIO30_SDATA_OUT_I2S_MD (30 | GPIO_ALT_FN_1_OUT) ++#define GPIO31_SYNC_AC97_MD (31 | GPIO_ALT_FN_2_OUT) ++#define GPIO31_SYNC_I2S_MD (31 | GPIO_ALT_FN_1_OUT) ++#define GPIO32_SDATA_IN1_AC97_MD (32 | GPIO_ALT_FN_1_IN) ++#define GPIO33_nCS_5_MD (33 | GPIO_ALT_FN_2_OUT) ++#define GPIO34_FFRXD_MD (34 | GPIO_ALT_FN_1_IN) ++#define GPIO34_MMCCS0_MD (34 | GPIO_ALT_FN_2_OUT) ++#define GPIO35_FFCTS_MD (35 | GPIO_ALT_FN_1_IN) ++#define GPIO36_FFDCD_MD (36 | GPIO_ALT_FN_1_IN) ++#define GPIO37_FFDSR_MD (37 | GPIO_ALT_FN_1_IN) ++#define GPIO38_FFRI_MD (38 | GPIO_ALT_FN_1_IN) ++#define GPIO39_MMCCS1_MD (39 | GPIO_ALT_FN_1_OUT) ++#define GPIO39_FFTXD_MD (39 | GPIO_ALT_FN_2_OUT) ++#define GPIO40_FFDTR_MD (40 | GPIO_ALT_FN_2_OUT) ++#define GPIO41_FFRTS_MD (41 | GPIO_ALT_FN_2_OUT) ++#define GPIO42_BTRXD_MD (42 | GPIO_ALT_FN_1_IN) ++#define GPIO43_BTTXD_MD (43 | GPIO_ALT_FN_2_OUT) ++#define GPIO44_BTCTS_MD (44 | GPIO_ALT_FN_1_IN) ++#define GPIO45_BTRTS_MD (45 | GPIO_ALT_FN_2_OUT) ++#define GPIO46_ICPRXD_MD (46 | GPIO_ALT_FN_1_IN) ++#define GPIO46_STRXD_MD (46 | GPIO_ALT_FN_2_IN) ++#define GPIO47_ICPTXD_MD (47 | GPIO_ALT_FN_2_OUT) ++#define GPIO47_STTXD_MD (47 | GPIO_ALT_FN_1_OUT) ++#define GPIO48_nPOE_MD (48 | GPIO_ALT_FN_2_OUT) ++#define GPIO49_nPWE_MD (49 | GPIO_ALT_FN_2_OUT) ++#define GPIO50_nPIOR_MD (50 | GPIO_ALT_FN_2_OUT) ++#define GPIO51_nPIOW_MD (51 | GPIO_ALT_FN_2_OUT) ++#define GPIO52_nPCE_1_MD (52 | GPIO_ALT_FN_2_OUT) ++#define GPIO53_nPCE_2_MD (53 | GPIO_ALT_FN_2_OUT) ++#define GPIO53_MMCCLK_MD (53 | GPIO_ALT_FN_1_OUT) ++#define GPIO54_MMCCLK_MD (54 | GPIO_ALT_FN_1_OUT) ++#define GPIO54_pSKTSEL_MD (54 | GPIO_ALT_FN_2_OUT) ++#define GPIO55_nPREG_MD (55 | GPIO_ALT_FN_2_OUT) ++#define GPIO56_nPWAIT_MD (56 | GPIO_ALT_FN_1_IN) ++#define GPIO57_nIOIS16_MD (57 | GPIO_ALT_FN_1_IN) ++#define GPIO58_LDD_0_MD (58 | GPIO_ALT_FN_2_OUT) ++#define GPIO59_LDD_1_MD (59 | GPIO_ALT_FN_2_OUT) ++#define GPIO60_LDD_2_MD (60 | GPIO_ALT_FN_2_OUT) ++#define GPIO61_LDD_3_MD (61 | GPIO_ALT_FN_2_OUT) ++#define GPIO62_LDD_4_MD (62 | GPIO_ALT_FN_2_OUT) ++#define GPIO63_LDD_5_MD (63 | GPIO_ALT_FN_2_OUT) ++#define GPIO64_LDD_6_MD (64 | GPIO_ALT_FN_2_OUT) ++#define GPIO65_LDD_7_MD (65 | GPIO_ALT_FN_2_OUT) ++#define GPIO66_LDD_8_MD (66 | GPIO_ALT_FN_2_OUT) ++#define GPIO66_MBREQ_MD (66 | GPIO_ALT_FN_1_IN) ++#define GPIO67_LDD_9_MD (67 | GPIO_ALT_FN_2_OUT) ++#define GPIO67_MMCCS0_MD (67 | GPIO_ALT_FN_1_OUT) ++#define GPIO68_LDD_10_MD (68 | GPIO_ALT_FN_2_OUT) ++#define GPIO68_MMCCS1_MD (68 | GPIO_ALT_FN_1_OUT) ++#define GPIO69_LDD_11_MD (69 | GPIO_ALT_FN_2_OUT) ++#define GPIO69_MMCCLK_MD (69 | GPIO_ALT_FN_1_OUT) ++#define GPIO70_LDD_12_MD (70 | GPIO_ALT_FN_2_OUT) ++#define GPIO70_RTCCLK_MD (70 | GPIO_ALT_FN_1_OUT) ++#define GPIO71_LDD_13_MD (71 | GPIO_ALT_FN_2_OUT) ++#define GPIO71_3_6MHz_MD (71 | GPIO_ALT_FN_1_OUT) ++#define GPIO72_LDD_14_MD (72 | GPIO_ALT_FN_2_OUT) ++#define GPIO72_32kHz_MD (72 | GPIO_ALT_FN_1_OUT) ++#define GPIO73_LDD_15_MD (73 | GPIO_ALT_FN_2_OUT) ++#define GPIO73_MBGNT_MD (73 | GPIO_ALT_FN_1_OUT) ++#define GPIO74_LCD_FCLK_MD (74 | GPIO_ALT_FN_2_OUT) ++#define GPIO75_LCD_LCLK_MD (75 | GPIO_ALT_FN_2_OUT) ++#define GPIO76_LCD_PCLK_MD (76 | GPIO_ALT_FN_2_OUT) ++#define GPIO77_LCD_ACBIAS_MD (77 | GPIO_ALT_FN_2_OUT) ++#define GPIO78_nCS_2_MD (78 | GPIO_ALT_FN_2_OUT) ++#define GPIO79_nCS_3_MD (79 | GPIO_ALT_FN_2_OUT) ++#define GPIO80_nCS_4_MD (80 | GPIO_ALT_FN_2_OUT) ++ ++ ++/* ++ * Power Manager ++ */ ++ ++#define PMCR __REG(0x40F00000) /* Power Manager Control Register */ ++#define PSSR __REG(0x40F00004) /* Power Manager Sleep Status Register */ ++#define PSPR __REG(0x40F00008) /* Power Manager Scratch Pad Register */ ++#define PWER __REG(0x40F0000C) /* Power Manager Wake-up Enable Register */ ++#define PRER __REG(0x40F00010) /* Power Manager GPIO Rising-Edge Detect Enable Register */ ++#define PFER __REG(0x40F00014) /* Power Manager GPIO Falling-Edge Detect Enable Register */ ++#define PEDR __REG(0x40F00018) /* Power Manager GPIO Edge Detect Status Register */ ++#define PCFR __REG(0x40F0001C) /* Power Manager General Configuration Register */ ++#define PGSR0 __REG(0x40F00020) /* Power Manager GPIO Sleep State Register for GP[31-0] */ ++#define PGSR1 __REG(0x40F00024) /* Power Manager GPIO Sleep State Register for GP[63-32] */ ++#define PGSR2 __REG(0x40F00028) /* Power Manager GPIO Sleep State Register for GP[84-64] */ ++#define RCSR __REG(0x40F00030) /* Reset Controller Status Register */ ++ ++#define PSSR_RDH (1 << 5) /* Read Disable Hold */ ++#define PSSR_PH (1 << 4) /* Peripheral Control Hold */ ++#define PSSR_VFS (1 << 2) /* VDD Fault Status */ ++#define PSSR_BFS (1 << 1) /* Battery Fault Status */ ++#define PSSR_SSS (1 << 0) /* Software Sleep Status */ ++ ++#define PCFR_DS (1 << 3) /* Deep Sleep Mode */ ++#define PCFR_FS (1 << 2) /* Float Static Chip Selects */ ++#define PCFR_FP (1 << 1) /* Float PCMCIA controls */ ++#define PCFR_OPDE (1 << 0) /* 3.6864 MHz oscillator power-down enable */ ++ ++#define RCSR_GPR (1 << 3) /* GPIO Reset */ ++#define RCSR_SMR (1 << 2) /* Sleep Mode */ ++#define RCSR_WDR (1 << 1) /* Watchdog Reset */ ++#define RCSR_HWR (1 << 0) /* Hardware Reset */ ++ ++ ++/* ++ * SSP Serial Port Registers ++ */ ++ ++#define SSCR0 __REG(0x41000000) /* SSP Control Register 0 */ ++#define SSCR1 __REG(0x41000004) /* SSP Control Register 1 */ ++#define SSSR __REG(0x41000008) /* SSP Status Register */ ++#define SSITR __REG(0x4100000C) /* SSP Interrupt Test Register */ ++#define SSDR __REG(0x41000010) /* (Write / Read) SSP Data Write Register/SSP Data Read Register */ ++ ++ ++/* ++ * MultiMediaCard (MMC) controller ++ */ ++ ++#define MMC_STRPCL __REG(0x41100000) /* Control to start and stop MMC clock */ ++#define MMC_STAT __REG(0x41100004) /* MMC Status Register (read only) */ ++#define MMC_CLKRT __REG(0x41100008) /* MMC clock rate */ ++#define MMC_SPI __REG(0x4110000c) /* SPI mode control bits */ ++#define MMC_CMDAT __REG(0x41100010) /* Command/response/data sequence control */ ++#define MMC_RESTO __REG(0x41100014) /* Expected response time out */ ++#define MMC_RDTO __REG(0x41100018) /* Expected data read time out */ ++#define MMC_BLKLEN __REG(0x4110001c) /* Block length of data transaction */ ++#define MMC_NOB __REG(0x41100020) /* Number of blocks, for block mode */ ++#define MMC_PRTBUF __REG(0x41100024) /* Partial MMC_TXFIFO FIFO written */ ++#define MMC_I_MASK __REG(0x41100028) /* Interrupt Mask */ ++#define MMC_I_REG __REG(0x4110002c) /* Interrupt Register (read only) */ ++#define MMC_CMD __REG(0x41100030) /* Index of current command */ ++#define MMC_ARGH __REG(0x41100034) /* MSW part of the current command argument */ ++#define MMC_ARGL __REG(0x41100038) /* LSW part of the current command argument */ ++#define MMC_RES __REG(0x4110003c) /* Response FIFO (read only) */ ++#define MMC_RXFIFO __REG(0x41100040) /* Receive FIFO (read only) */ ++#define MMC_TXFIFO __REG(0x41100044) /* Transmit FIFO (write only) */ ++ ++ ++/* ++ * Core Clock ++ */ ++ ++#define CCCR __REG(0x41300000) /* Core Clock Configuration Register */ ++#define CKEN __REG(0x41300004) /* Clock Enable Register */ ++#define OSCC __REG(0x41300008) /* Oscillator Configuration Register */ ++ ++#define CCCR_N_MASK 0x0380 /* Run Mode Frequency to Turbo Mode Frequency Multiplier */ ++#define CCCR_M_MASK 0x0060 /* Memory Frequency to Run Mode Frequency Multiplier */ ++#define CCCR_L_MASK 0x001f /* Crystal Frequency to Memory Frequency Multiplier */ ++ ++#define CKEN16_LCD (1 << 16) /* LCD Unit Clock Enable */ ++#define CKEN14_I2C (1 << 14) /* I2C Unit Clock Enable */ ++#define CKEN13_FICP (1 << 13) /* FICP Unit Clock Enable */ ++#define CKEN12_MMC (1 << 12) /* MMC Unit Clock Enable */ ++#define CKEN11_USB (1 << 11) /* USB Unit Clock Enable */ ++#define CKEN8_I2S (1 << 8) /* I2S Unit Clock Enable */ ++#define CKEN7_BTUART (1 << 7) /* BTUART Unit Clock Enable */ ++#define CKEN6_FFUART (1 << 6) /* FFUART Unit Clock Enable */ ++#define CKEN5_STUART (1 << 5) /* STUART Unit Clock Enable */ ++#define CKEN3_SSP (1 << 3) /* SSP Unit Clock Enable */ ++#define CKEN2_AC97 (1 << 2) /* AC97 Unit Clock Enable */ ++#define CKEN1_PWM1 (1 << 1) /* PWM1 Clock Enable */ ++#define CKEN0_PWM0 (1 << 0) /* PWM0 Clock Enable */ ++ ++#define OSCC_OON (1 << 1) /* 32.768kHz OON (write-once only bit) */ ++#define OSCC_OOK (1 << 0) /* 32.768kHz OOK (read-only bit) */ ++ ++ ++/* ++ * LCD ++ */ ++ ++#define LCCR0 __REG(0x44000000) /* LCD Controller Control Register 0 */ ++#define LCCR1 __REG(0x44000004) /* LCD Controller Control Register 1 */ ++#define LCCR2 __REG(0x44000008) /* LCD Controller Control Register 2 */ ++#define LCCR3 __REG(0x4400000C) /* LCD Controller Control Register 3 */ ++#define DFBR0 __REG(0x44000020) /* DMA Channel 0 Frame Branch Register */ ++#define DFBR1 __REG(0x44000024) /* DMA Channel 1 Frame Branch Register */ ++#define LCSR __REG(0x44000038) /* LCD Controller Status Register */ ++#define LIIDR __REG(0x4400003C) /* LCD Controller Interrupt ID Register */ ++#define TMEDRGBR __REG(0x44000040) /* TMED RGB Seed Register */ ++#define TMEDCR __REG(0x44000044) /* TMED Control Register */ ++ ++#define FDADR0 __REG(0x44000200) /* DMA Channel 0 Frame Descriptor Address Register */ ++#define FSADR0 __REG(0x44000204) /* DMA Channel 0 Frame Source Address Register */ ++#define FIDR0 __REG(0x44000208) /* DMA Channel 0 Frame ID Register */ ++#define LDCMD0 __REG(0x4400020C) /* DMA Channel 0 Command Register */ ++#define FDADR1 __REG(0x44000210) /* DMA Channel 1 Frame Descriptor Address Register */ ++#define FSADR1 __REG(0x44000214) /* DMA Channel 1 Frame Source Address Register */ ++#define FIDR1 __REG(0x44000218) /* DMA Channel 1 Frame ID Register */ ++#define LDCMD1 __REG(0x4400021C) /* DMA Channel 1 Command Register */ ++ ++#define LCCR0_ENB (1 << 0) /* LCD Controller enable */ ++#define LCCR0_CMS (1 << 1) /* Color = 0, Monochrome = 1 */ ++#define LCCR0_SDS (1 << 2) /* Single Panel = 0, Dual Panel = 1 */ ++#define LCCR0_LDM (1 << 3) /* LCD Disable Done Mask */ ++#define LCCR0_SFM (1 << 4) /* Start of frame mask */ ++#define LCCR0_IUM (1 << 5) /* Input FIFO underrun mask */ ++#define LCCR0_EFM (1 << 6) /* End of Frame mask */ ++#define LCCR0_PAS (1 << 7) /* Passive = 0, Active = 1 */ ++#define LCCR0_BLE (1 << 8) /* Little Endian = 0, Big Endian = 1 */ ++#define LCCR0_DPD (1 << 9) /* Double Pixel mode, 4 pixel value = 0, 8 pixle values = 1 */ ++#define LCCR0_DIS (1 << 10) /* LCD Disable */ ++#define LCCR0_QDM (1 << 11) /* LCD Quick Disable mask */ ++#define LCCR0_PDD (0xff << 12) /* Palette DMA request delay */ ++#define LCCR0_PDD_S 12 ++#define LCCR0_BM (1 << 20) /* Branch mask */ ++#define LCCR0_OUM (1 << 21) /* Output FIFO underrun mask */ ++ ++#define LCCR1_PPL Fld (10, 0) /* Pixels Per Line - 1 */ ++#define LCCR1_DisWdth(Pixel) /* Display Width [1..800 pix.] */ \ ++ (((Pixel) - 1) << FShft (LCCR1_PPL)) ++ ++#define LCCR1_HSW Fld (6, 10) /* Horizontal Synchronization */ ++#define LCCR1_HorSnchWdth(Tpix) /* Horizontal Synchronization */ \ ++ /* pulse Width [1..64 Tpix] */ \ ++ (((Tpix) - 1) << FShft (LCCR1_HSW)) ++ ++#define LCCR1_ELW Fld (8, 16) /* End-of-Line pixel clock Wait */ ++ /* count - 1 [Tpix] */ ++#define LCCR1_EndLnDel(Tpix) /* End-of-Line Delay */ \ ++ /* [1..256 Tpix] */ \ ++ (((Tpix) - 1) << FShft (LCCR1_ELW)) ++ ++#define LCCR1_BLW Fld (8, 24) /* Beginning-of-Line pixel clock */ ++ /* Wait count - 1 [Tpix] */ ++#define LCCR1_BegLnDel(Tpix) /* Beginning-of-Line Delay */ \ ++ /* [1..256 Tpix] */ \ ++ (((Tpix) - 1) << FShft (LCCR1_BLW)) ++ ++ ++#define LCCR2_LPP Fld (10, 0) /* Line Per Panel - 1 */ ++#define LCCR2_DisHght(Line) /* Display Height [1..1024 lines] */ \ ++ (((Line) - 1) << FShft (LCCR2_LPP)) ++ ++#define LCCR2_VSW Fld (6, 10) /* Vertical Synchronization pulse */ ++ /* Width - 1 [Tln] (L_FCLK) */ ++#define LCCR2_VrtSnchWdth(Tln) /* Vertical Synchronization pulse */ \ ++ /* Width [1..64 Tln] */ \ ++ (((Tln) - 1) << FShft (LCCR2_VSW)) ++ ++#define LCCR2_EFW Fld (8, 16) /* End-of-Frame line clock Wait */ ++ /* count [Tln] */ ++#define LCCR2_EndFrmDel(Tln) /* End-of-Frame Delay */ \ ++ /* [0..255 Tln] */ \ ++ ((Tln) << FShft (LCCR2_EFW)) ++ ++#define LCCR2_BFW Fld (8, 24) /* Beginning-of-Frame line clock */ ++ /* Wait count [Tln] */ ++#define LCCR2_BegFrmDel(Tln) /* Beginning-of-Frame Delay */ \ ++ /* [0..255 Tln] */ \ ++ ((Tln) << FShft (LCCR2_BFW)) ++ ++#if 0 ++#define LCCR3_PCD (0xff) /* Pixel clock divisor */ ++#define LCCR3_ACB (0xff << 8) /* AC Bias pin frequency */ ++#define LCCR3_ACB_S 8 ++#endif ++ ++#define LCCR3_API (0xf << 16) /* AC Bias pin trasitions per interrupt */ ++#define LCCR3_API_S 16 ++#define LCCR3_VSP (1 << 20) /* vertical sync polarity */ ++#define LCCR3_HSP (1 << 21) /* horizontal sync polarity */ ++#define LCCR3_PCP (1 << 22) /* pixel clock polarity */ ++#define LCCR3_OEP (1 << 23) /* output enable polarity */ ++#if 0 ++#define LCCR3_BPP (7 << 24) /* bits per pixel */ ++#define LCCR3_BPP_S 24 ++#endif ++#define LCCR3_DPC (1 << 27) /* double pixel clock mode */ ++ ++ ++#define LCCR3_PCD Fld (8, 0) /* Pixel Clock Divisor */ ++#define LCCR3_PixClkDiv(Div) /* Pixel Clock Divisor */ \ ++ (((Div) << FShft (LCCR3_PCD))) ++ ++ ++#define LCCR3_BPP Fld (3, 24) /* Bit Per Pixel */ ++#define LCCR3_Bpp(Bpp) /* Bit Per Pixel */ \ ++ (((Bpp) << FShft (LCCR3_BPP))) ++ ++#define LCCR3_ACB Fld (8, 8) /* AC Bias */ ++#define LCCR3_Acb(Acb) /* BAC Bias */ \ ++ (((Acb) << FShft (LCCR3_ACB))) ++ ++#define LCCR3_HorSnchH (LCCR3_HSP*0) /* Horizontal Synchronization */ ++ /* pulse active High */ ++#define LCCR3_HorSnchL (LCCR3_HSP*1) /* Horizontal Synchronization */ ++ ++#define LCCR3_VrtSnchH (LCCR3_VSP*0) /* Vertical Synchronization pulse */ ++ /* active High */ ++#define LCCR3_VrtSnchL (LCCR3_VSP*1) /* Vertical Synchronization pulse */ ++ /* active Low */ ++ ++#define LCSR_LDD (1 << 0) /* LCD Disable Done */ ++#define LCSR_SOF (1 << 1) /* Start of frame */ ++#define LCSR_BER (1 << 2) /* Bus error */ ++#define LCSR_ABC (1 << 3) /* AC Bias count */ ++#define LCSR_IUL (1 << 4) /* input FIFO underrun Lower panel */ ++#define LCSR_IUU (1 << 5) /* input FIFO underrun Upper panel */ ++#define LCSR_OU (1 << 6) /* output FIFO underrun */ ++#define LCSR_QD (1 << 7) /* quick disable */ ++#define LCSR_EOF (1 << 8) /* end of frame */ ++#define LCSR_BS (1 << 9) /* branch status */ ++#define LCSR_SINT (1 << 10) /* subsequent interrupt */ ++ ++#define LDCMD_PAL (1 << 26) /* instructs DMA to load palette buffer */ ++ ++#define LCSR_LDD (1 << 0) /* LCD Disable Done */ ++#define LCSR_SOF (1 << 1) /* Start of frame */ ++#define LCSR_BER (1 << 2) /* Bus error */ ++#define LCSR_ABC (1 << 3) /* AC Bias count */ ++#define LCSR_IUL (1 << 4) /* input FIFO underrun Lower panel */ ++#define LCSR_IUU (1 << 5) /* input FIFO underrun Upper panel */ ++#define LCSR_OU (1 << 6) /* output FIFO underrun */ ++#define LCSR_QD (1 << 7) /* quick disable */ ++#define LCSR_EOF (1 << 8) /* end of frame */ ++#define LCSR_BS (1 << 9) /* branch status */ ++#define LCSR_SINT (1 << 10) /* subsequent interrupt */ ++ ++#define LDCMD_PAL (1 << 26) /* instructs DMA to load palette buffer */ ++ ++/* ++ * Memory controller ++ */ ++ ++#define MDCNFG __REG(0x48000000) /* SDRAM Configuration Register 0 */ ++#define MDREFR __REG(0x48000004) /* SDRAM Refresh Control Register */ ++#define MSC0 __REG(0x48000008) /* Static Memory Control Register 0 */ ++#define MSC1 __REG(0x4800000C) /* Static Memory Control Register 1 */ ++#define MSC2 __REG(0x48000010) /* Static Memory Control Register 2 */ ++#define MECR __REG(0x48000014) /* Expansion Memory (PCMCIA/Compact Flash) Bus Configuration */ ++#define SXLCR __REG(0x48000018) /* LCR value to be written to SDRAM-Timing Synchronous Flash */ ++#define SXCNFG __REG(0x4800001C) /* Synchronous Static Memory Control Register */ ++#define SXMRS __REG(0x48000024) /* MRS value to be written to Synchronous Flash or SMROM */ ++#define MCMEM0 __REG(0x48000028) /* Card interface Common Memory Space Socket 0 Timing */ ++#define MCMEM1 __REG(0x4800002C) /* Card interface Common Memory Space Socket 1 Timing */ ++#define MCATT0 __REG(0x48000030) /* Card interface Attribute Space Socket 0 Timing Configuration */ ++#define MCATT1 __REG(0x48000034) /* Card interface Attribute Space Socket 1 Timing Configuration */ ++#define MCIO0 __REG(0x48000038) /* Card interface I/O Space Socket 0 Timing Configuration */ ++#define MCIO1 __REG(0x4800003C) /* Card interface I/O Space Socket 1 Timing Configuration */ ++#define MDMRS __REG(0x48000040) /* MRS value to be written to SDRAM */ ++#define BOOT_DEF __REG(0x48000044) /* Read-Only Boot-Time Register. Contains BOOT_SEL and PKG_SEL */ ++ ++#define MDREFR_K2FREE (1 << 25) /* SDRAM Free-Running Control */ ++#define MDREFR_K1FREE (1 << 24) /* SDRAM Free-Running Control */ ++#define MDREFR_K0FREE (1 << 23) /* SDRAM Free-Running Control */ ++#define MDREFR_SLFRSH (1 << 22) /* SDRAM Self-Refresh Control/Status */ ++#define MDREFR_APD (1 << 20) /* SDRAM/SSRAM Auto-Power-Down Enable */ ++#define MDREFR_K2DB2 (1 << 19) /* SDCLK2 Divide by 2 Control/Status */ ++#define MDREFR_K2RUN (1 << 18) /* SDCLK2 Run Control/Status */ ++#define MDREFR_K1DB2 (1 << 17) /* SDCLK1 Divide by 2 Control/Status */ ++#define MDREFR_K1RUN (1 << 16) /* SDCLK1 Run Control/Status */ ++#define MDREFR_E1PIN (1 << 15) /* SDCKE1 Level Control/Status */ ++#define MDREFR_K0DB2 (1 << 14) /* SDCLK0 Divide by 2 Control/Status */ ++#define MDREFR_K0RUN (1 << 13) /* SDCLK0 Run Control/Status */ ++#define MDREFR_E0PIN (1 << 12) /* SDCKE0 Level Control/Status */ ++ ++#endif +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/serial.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,51 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/serial.h ++ * ++ * Author: Nicolas Pitre ++ * Copyright: (C) 2001 MontaVista 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. ++ */ ++ ++ ++#define BAUD_BASE 921600 ++ ++/* Standard COM flags */ ++#define STD_COM_FLAGS (ASYNC_SKIP_TEST) ++ ++#define STD_SERIAL_PORT_DEFNS \ ++ { \ ++ type: PORT_PXA, \ ++ xmit_fifo_size: 32, \ ++ baud_base: BAUD_BASE, \ ++ iomem_base: (void *)&FFUART,\ ++ iomem_reg_shift: 2, \ ++ io_type: SERIAL_IO_MEM32,\ ++ irq: IRQ_FFUART, \ ++ flags: STD_COM_FLAGS, \ ++ }, { \ ++ type: PORT_PXA, \ ++ xmit_fifo_size: 32, \ ++ baud_base: BAUD_BASE, \ ++ iomem_base: (void *)&BTUART,\ ++ iomem_reg_shift: 2, \ ++ io_type: SERIAL_IO_MEM32,\ ++ irq: IRQ_BTUART, \ ++ flags: STD_COM_FLAGS, \ ++ }, { \ ++ type: PORT_PXA, \ ++ xmit_fifo_size: 32, \ ++ baud_base: BAUD_BASE, \ ++ iomem_base: (void *)&STUART,\ ++ iomem_reg_shift: 2, \ ++ io_type: SERIAL_IO_MEM32,\ ++ irq: IRQ_STUART, \ ++ flags: STD_COM_FLAGS, \ ++ } ++ ++#define RS_TABLE_SIZE 8 ++ ++#define EXTRA_SERIAL_PORT_DEFNS ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/system.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,32 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/system.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista 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 "hardware.h" ++ ++static inline void arch_idle(void) ++{ ++ cpu_do_idle(); ++} ++ ++static inline void arch_reset(char mode) ++{ ++ if (mode == 's') { ++ /* Jump into ROM at address 0 */ ++ cpu_reset(0); ++ } else { ++ /* Initialize the watchdog and let it fire */ ++ OWER = OWER_WME; ++ OSSR = OSSR_M3; ++ OSMR3 = OSCR + 368640; /* ... in 100 ms */ ++ } ++} ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/time.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,86 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/time.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista 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. ++ */ ++ ++ ++static inline unsigned long pxa_get_rtc_time(void) ++{ ++ return RCNR; ++} ++ ++static int pxa_set_rtc(void) ++{ ++ unsigned long current_time = xtime.tv_sec; ++ ++ if (RTSR & RTSR_ALE) { ++ /* make sure not to forward the clock over an alarm */ ++ unsigned long alarm = RTAR; ++ if (current_time >= alarm && alarm >= RCNR) ++ return -ERESTARTSYS; ++ } ++ RCNR = current_time; ++ return 0; ++} ++ ++/* IRQs are disabled before entering here from do_gettimeofday() */ ++static unsigned long pxa_gettimeoffset (void) ++{ ++ unsigned long ticks_to_match, elapsed, usec; ++ ++ /* Get ticks before next timer match */ ++ ticks_to_match = OSMR0 - OSCR; ++ ++ /* We need elapsed ticks since last match */ ++ elapsed = LATCH - ticks_to_match; ++ ++ /* Now convert them to usec */ ++ usec = (unsigned long)(elapsed*tick)/LATCH; ++ ++ return usec; ++} ++ ++static void pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ long flags; ++ int next_match; ++ ++ do_profile(regs); ++ ++ /* Loop until we get ahead of the free running timer. ++ * This ensures an exact clock tick count and time acuracy. ++ * IRQs are disabled inside the loop to ensure coherence between ++ * lost_ticks (updated in do_timer()) and the match reg value, so we ++ * can use do_gettimeofday() from interrupt handlers. ++ */ ++ do { ++ do_leds(); ++ do_set_rtc(); ++ save_flags_cli( flags ); ++ do_timer(regs); ++ OSSR = OSSR_M0; /* Clear match on timer 0 */ ++ next_match = (OSMR0 += LATCH); ++ restore_flags( flags ); ++ } while( (signed long)(next_match - OSCR) <= 0 ); ++} ++ ++extern inline void setup_timer (void) ++{ ++ gettimeoffset = pxa_gettimeoffset; ++ set_rtc = pxa_set_rtc; ++ xtime.tv_sec = pxa_get_rtc_time(); ++ timer_irq.handler = pxa_timer_interrupt; ++ OSMR0 = 0; /* set initial match at 0 */ ++ OSSR = 0xf; /* clear status on all timers */ ++ setup_arm_irq(IRQ_OST0, &timer_irq); ++ OIER |= OIER_E0; /* enable match on timer 0 to cause interrupts */ ++ OSCR = 0; /* initialize free-running timer, force first match */ ++} ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/timex.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,17 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/timex.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista 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. ++ */ ++ ++/* ++ * PXA250/210 timer ++ */ ++#define CLOCK_TICK_RATE 3686400 ++#define CLOCK_TICK_FACTOR 80 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/trizeps2.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,206 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/trizeps2.h ++ * ++ * 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. ++ * ++ * Copyright (c) 2002 Luc De Cock, Teradyne DS, Ltd. ++ * ++ * 2002-10-10: Initial code started from idp.h ++ */ ++ ++ ++/* ++ * Note: this file must be safe to include in assembly files ++ */ ++ ++/* comment out following if you have a board with 32MB RAM */ ++//#define PXA_TRIZEPS2_64MB 1 ++#undef PXA_TRIZEPS2_64MB ++ ++#define TRIZEPS2_FLASH_PHYS (PXA_CS0_PHYS) ++#define TRIZEPS2_ALT_FLASH_PHYS (PXA_CS1_PHYS) ++#define TRIZEPS2_MEDIAQ_PHYS (PXA_CS3_PHYS) ++#define TRIZEPS2_IDE_PHYS (PXA_CS5_PHYS + 0x03000000) ++#define TRIZEPS2_ETH_PHYS (0x0C800000) ++#define TRIZEPS2_COREVOLT_PHYS (PXA_CS5_PHYS + 0x03800000) ++#define TRIZEPS2_BCR_PHYS (0x0E000000) ++#define TRIZEPS2_CPLD_PHYS (0x0C000000) ++ ++/* ++ * virtual memory map ++ */ ++ ++#define TRIZEPS2_IDE_BASE (0xf0000000) ++#define TRIZEPS2_IDE_SIZE (1*1024*1024) ++ ++#define TRIZEPS2_ETH_BASE (0xf1000000) ++#define TRIZEPS2_ETH_SIZE (1*1024*1024) ++#define ETH_BASE TRIZEPS2_ETH_BASE //smc9194 driver compatibility issue ++ ++#define TRIZEPS2_COREVOLT_BASE (TRIZEPS2_ETH_BASE + TRIZEPS2_ETH_SIZE) ++#define TRIZEPS2_COREVOLT_SIZE (1*1024*1024) ++ ++#define TRIZEPS2_BCR_BASE (0xf0000000) ++#define TRIZEPS2_BCR_SIZE (1*1024*1024) ++ ++#define BCR_P2V(x) ((x) - TRIZEPS2_BCR_PHYS + TRIZEPS2_BCR_BASE) ++#define BCR_V2P(x) ((x) - TRIZEPS2_BCR_BASE + TRIZEPS2_BCR_PHYS) ++ ++#ifndef __ASSEMBLY__ ++# define __BCR_REG(x) (*((volatile unsigned short *)BCR_P2V(x))) ++#else ++# define __BCR_REG(x) BCR_P2V(x) ++#endif ++ ++/* board level registers */ ++#define TRIZEPS2_CPLD_BASE (0xf0100000) ++#define CPLD_P2V(x) ((x) - TRIZEPS2_CPLD_PHYS + TRIZEPS2_CPLD_BASE) ++#define CPLD_V2P(x) ((x) - TRIZEPS2_CPLD_BASE + TRIZEPS2_CPLD_PHYS) ++ ++#ifndef __ASSEMBLY__ ++# define __CPLD_REG(x) (*((volatile unsigned short *)CPLD_P2V(x))) ++#else ++# define __CPLD_REG(x) CPLD_P2V(x) ++#endif ++ ++#define _TRIZEPS2_PCCARD_STATUS (0x0c000000) ++#define TRIZEPS2_PCCARD_STATUS __CPLD_REG(_TRIZEPS2_PCCARD_STATUS) ++ ++/* ++ * CS memory timing via Static Memory Control Register (MSC0-2) ++ */ ++ ++#define MSC_CS(cs,val) ((val)<<((cs&1)<<4)) ++ ++#define MSC_RBUFF_SHIFT 15 ++#define MSC_RBUFF(x) ((x)<<MSC_RBUFF_SHIFT) ++#define MSC_RBUFF_SLOW MSC_RBUFF(0) ++#define MSC_RBUFF_FAST MSC_RBUFF(1) ++ ++#define MSC_RRR_SHIFT 12 ++#define MSC_RRR(x) ((x)<<MSC_RRR_SHIFT) ++ ++#define MSC_RDN_SHIFT 8 ++#define MSC_RDN(x) ((x)<<MSC_RDN_SHIFT) ++ ++#define MSC_RDF_SHIFT 4 ++#define MSC_RDF(x) ((x)<<MSC_RDF_SHIFT) ++ ++#define MSC_RBW_SHIFT 3 ++#define MSC_RBW(x) ((x)<<MSC_RBW_SHIFT) ++#define MSC_RBW_16 MSC_RBW(1) ++#define MSC_RBW_32 MSC_RBW(0) ++ ++#define MSC_RT_SHIFT 0 ++#define MSC_RT(x) ((x)<<MSC_RT_SHIFT) ++ ++ ++/* ++ * Bit masks for various registers ++ */ ++// TRIZEPS2_BCR_PCCARD_PWR ++#define PCC_3V (1 << 0) ++#define PCC_5V (1 << 1) ++#define PCC_EN1 (1 << 2) ++#define PCC_EN0 (1 << 3) ++ ++// TRIZEPS2_BCR_PCCARD_EN ++#define PCC_RESET (1 << 6) ++#define PCC_ENABLE (1 << 0) ++ ++// TRIZEPS2_BSR_PCCARDx_STATUS ++#define _PCC_WRPROT (1 << 7) // 7-4 read as low true ++#define _PCC_RESET (1 << 6) ++#define _PCC_IRQ (1 << 5) ++#define _PCC_INPACK (1 << 4) ++#define PCC_BVD1 (1 << 0) ++#define PCC_BVD2 (1 << 1) ++#define PCC_VS1 (1 << 2) ++#define PCC_VS2 (1 << 3) ++ ++// TRIZEPS2_BCR_CONTROL bits ++#define BCR_LCD_ON (1 << 4) ++#define BCR_LCD_OFF (0) ++#define BCR_LCD_MASK (1 << 4) ++#define BCR_PCMCIA_RESET (1 << 7) ++#define BCR_PCMCIA_NORMAL (0) ++ ++#define PCC_DETECT (GPLR(24) & GPIO_bit(24)) ++#define PCC_READY (GPLR(1) & GPIO_bit(1)) ++ ++// Board Control Register ++#define _TRIZEPS2_BCR_CONTROL (TRIZEPS2_BCR_PHYS) ++#define TRIZEPS2_BCR_CONTROL __BCR_REG(_TRIZEPS2_BCR_CONTROL) ++ ++// Board TTL-IO register ++#define TRIZEPS2_TTLIO_PHYS (0x0d800000) ++#define TRIZEPS2_TTLIO_BASE (0xf2000000) ++// various ioctl cmds ++#define TTLIO_RESET 0 ++#define TTLIO_GET 1 ++#define TTLIO_SET 2 ++#define TTLIO_UNSET 3 ++ ++/* ++ * Macros for LCD Driver ++ */ ++ ++#ifdef CONFIG_FB_PXA ++ ++#define FB_BACKLIGHT_ON() ++#define FB_BACKLIGHT_OFF() ++ ++#define FB_PWR_ON() ++#define FB_PWR_OFF() ++ ++#define FB_VLCD_ON() WRITE_TRIZEPS2_BCR(BCR_LCD_ON,BCR_LCD_MASK); ++#define FB_VLCD_OFF() WRITE_TRIZEPS2_BCR(BCR_LCD_OFF,BCR_LCD_MASK); ++ ++#endif ++ ++/* A listing of interrupts used by external hardware devices */ ++ ++#define GPIO_TOUCH_PANEL_IRQ 2 ++#define TOUCH_PANEL_IRQ IRQ_GPIO(GPIO_TOUCH_PANEL_IRQ) ++#define GPIO_ETHERNET_IRQ 19 ++#define ETHERNET_IRQ IRQ_GPIO(GPIO_ETHERNET_IRQ) ++#define GPIO_TTLIO_IRQ 23 ++#define TTLIO_IRQ IRQ_GPIO(GPIO_TTLIO_IRQ) ++ ++#define TOUCH_PANEL_IRQ_EDGE GPIO_FALLING_EDGE ++#define IDE_IRQ_EDGE GPIO_RISING_EDGE ++#define ETHERNET_IRQ_EDGE GPIO_RISING_EDGE ++ ++#define PCMCIA_S_CD_VALID IRQ_GPIO(24) ++#define PCMCIA_S_CD_VALID_EDGE GPIO_BOTH_EDGES ++ ++#define PCMCIA_S_RDYINT IRQ_GPIO(1) ++#define PCMCIA_S_RDYINT_EDGE GPIO_FALLING_EDGE ++ ++/* ++ * macros for MTD driver ++ */ ++ ++#define FLASH_WRITE_PROTECT_DISABLE() // ((TRIZEPS2_CPLD_FLASH_WE) &= ~(0x1)) ++#define FLASH_WRITE_PROTECT_ENABLE() // ((TRIZEPS2_CPLD_FLASH_WE) |= (0x1)) ++ ++/* shadow registers for write only registers */ ++#ifndef __ASSEMBLY__ ++extern unsigned short trizeps2_bcr_shadow; ++#endif ++ ++/* ++ * macros to write to write only register ++ * ++ * none of these macros are protected from ++ * multiple drivers using them in interrupt context. ++ */ ++ ++#define WRITE_TRIZEPS2_BCR(value, mask) \ ++{\ ++ trizeps2_bcr_shadow = ((value & mask) | (trizeps2_bcr_shadow & ~mask));\ ++ TRIZEPS2_BCR_CONTROL = trizeps2_bcr_shadow;\ ++} ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/uncompress.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,42 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/uncompress.h ++ * ++ * Author: Nicolas Pitre ++ * Copyright: (C) 2001 MontaVista 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. ++ */ ++ ++#define FFUART ((volatile unsigned long *)0x40100000) ++#define BTUART ((volatile unsigned long *)0x40200000) ++#define STUART ((volatile unsigned long *)0x40700000) ++ ++#define UART FFUART ++ ++ ++static __inline__ void putc(char c) ++{ ++ while (!(UART[5] & 0x20)); ++ UART[0] = c; ++} ++ ++/* ++ * This does not append a newline ++ */ ++static void puts(const char *s) ++{ ++ while (*s) { ++ putc(*s); ++ if (*s == '\n') ++ putc('\r'); ++ s++; ++ } ++} ++ ++/* ++ * nothing to do ++ */ ++#define arch_decomp_setup() ++#define arch_decomp_wdog() +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-pxa/vmalloc.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,23 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/vmalloc.h ++ * ++ * Author: Nicolas Pitre ++ * Copyright: (C) 2001 MontaVista 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. ++ */ ++ ++/* ++ * Just any arbitrary offset to the start of the vmalloc VM area: the ++ * current 8MB value just means that there will be a 8MB "hole" after the ++ * physical memory until the kernel virtual memory starts. That means that ++ * any out-of-bounds memory accesses will hopefully be caught. ++ * The vmalloc() routines leaves a hole of 4kB between each vmalloced ++ * area for the same reason. ;) ++ */ ++#define VMALLOC_OFFSET (8*1024*1024) ++#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) ++#define VMALLOC_VMADDR(x) ((unsigned long)(x)) ++#define VMALLOC_END (0xe8000000) +--- linux-2.4.25/include/asm-arm/assembler.h~2.4.25-vrs2-pxa1.patch 2000-08-13 18:54:15.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/assembler.h 2004-03-31 17:15:12.000000000 +0200 +@@ -13,3 +13,26 @@ + + #include <asm/proc/ptrace.h> + #include <asm/proc/assembler.h> ++ ++/* ++ * Endian independent macros for shifting bytes within registers. ++ */ ++#ifndef __ARMEB__ ++#define pull lsr ++#define push lsl ++#define byte(x) (x*8) ++#else ++#define pull lsl ++#define push lsr ++#define byte(x) ((3-x)*8) ++#endif ++ ++/* ++ * Data preload for architectures that support it ++ */ ++#if __LINUX_ARM_ARCH__ >= 5 ++#define PLD(code...) code ++#else ++#define PLD(code...) ++#endif ++ +--- linux-2.4.25/include/asm-arm/bitops.h~2.4.25-vrs2-pxa1.patch 2003-08-25 13:44:43.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/bitops.h 2004-03-31 17:15:12.000000000 +0200 +@@ -91,6 +91,8 @@ + return (((unsigned char *) addr)[nr >> 3] >> (nr & 7)) & 1; + } + ++#if __LINUX_ARM_ARCH__ < 5 ++ + /* + * ffz = Find First Zero in word. Undefined if no zero exists, + * so code should check against ~0UL first.. +@@ -117,6 +119,23 @@ + + #define ffs(x) generic_ffs(x) + ++#else ++ ++/* ++ * On ARMv5 and above those functions can be implemented around ++ * the clz instruction for much better code efficiency. ++ */ ++ ++extern __inline__ int generic_fls(int x); ++#define fls(x) \ ++ ( __builtin_constant_p(x) ? generic_fls(x) : \ ++ ({ int __r; asm("clz%?\t%0, %1" : "=r"(__r) : "r"(x)); 32-__r; }) ) ++#define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); }) ++#define __ffs(x) (ffs(x) - 1) ++#define ffz(x) __ffs( ~(x) ) ++ ++#endif ++ + /* + * hweightN: returns the hamming weight (i.e. the number + * of bits set) of a N-bit word +--- linux-2.4.25/include/asm-arm/io.h~2.4.25-vrs2-pxa1.patch 2003-08-25 13:44:43.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/io.h 2004-03-31 17:15:12.000000000 +0200 +@@ -168,7 +168,7 @@ + * devices. This is the "generic" version. The PCI specific version + * is in pci.h + */ +-extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle); ++extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle, unsigned long flags); + extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle); + extern void consistent_sync(void *vaddr, size_t size, int rw); + +--- linux-2.4.25/include/asm-arm/memory.h~2.4.25-vrs2-pxa1.patch 2003-08-25 13:44:43.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/memory.h 2004-03-31 17:15:12.000000000 +0200 +@@ -123,6 +123,9 @@ + ((unsigned)((page) - NODE_MEM_MAP(node)) < NODE_DATA(node)->node_size)); \ + }) + ++/* We want large page mapping possible */ ++#define VMALLOC_ALIGN 0x10000 ++ + #endif + + /* +--- linux-2.4.25/include/asm-arm/proc-armv/pgtable.h~2.4.25-vrs2-pxa1.patch 2001-08-12 20:14:00.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/proc-armv/pgtable.h 2004-03-31 17:15:12.000000000 +0200 +@@ -15,9 +15,6 @@ + #ifndef __ASM_PROC_PGTABLE_H + #define __ASM_PROC_PGTABLE_H + +-#include <asm/proc/domain.h> +-#include <asm/arch/vmalloc.h> +- + /* + * entries per page directory level: they are two-level, so + * we don't really have any PMD directory. +@@ -26,27 +23,92 @@ + #define PTRS_PER_PMD 1 + #define PTRS_PER_PGD 4096 + +-/**************** +-* PMD functions * +-****************/ +- +-/* PMD types (actually level 1 descriptor) */ +-#define PMD_TYPE_MASK 0x0003 +-#define PMD_TYPE_FAULT 0x0000 +-#define PMD_TYPE_TABLE 0x0001 +-#define PMD_TYPE_SECT 0x0002 +-#define PMD_UPDATABLE 0x0010 +-#define PMD_SECT_CACHEABLE 0x0008 +-#define PMD_SECT_BUFFERABLE 0x0004 +-#define PMD_SECT_AP_WRITE 0x0400 +-#define PMD_SECT_AP_READ 0x0800 ++/* ++ * Hardware page table definitions. ++ * ++ * + Level 1 descriptor (PMD) ++ * - common ++ */ ++#define PMD_TYPE_MASK (3 << 0) ++#define PMD_TYPE_FAULT (0 << 0) ++#define PMD_TYPE_TABLE (1 << 0) ++#define PMD_TYPE_SECT (2 << 0) ++#define PMD_UPDATABLE (1 << 4) + #define PMD_DOMAIN(x) ((x) << 5) ++#define PMD_PROTECTION (1 << 9) /* v5 */ ++/* ++ * - section ++ */ ++#define PMD_SECT_BUFFERABLE (1 << 2) ++#define PMD_SECT_CACHEABLE (1 << 3) ++#define PMD_SECT_AP_WRITE (1 << 10) ++#define PMD_SECT_AP_READ (1 << 11) ++#define PMD_SECT_TEX(x) ((x) << 12) /* v5 */ ++/* ++ * - coarse table ++ */ ++ ++/* ++ * + Level 2 descriptor (PTE) ++ * - common ++ */ ++#define PTE_TYPE_MASK (3 << 0) ++#define PTE_TYPE_FAULT (0 << 0) ++#define PTE_TYPE_LARGE (1 << 0) ++#define PTE_TYPE_SMALL (2 << 0) ++#define PTE_TYPE_EXT (3 << 0) /* v5 */ ++#define PTE_BUFFERABLE (1 << 2) ++#define PTE_CACHEABLE (1 << 3) ++ ++/* ++ * - extended small page/tiny page ++ */ ++#define PTE_EXT_AP_UNO_SRO (0 << 4) ++#define PTE_EXT_AP_UNO_SRW (1 << 4) ++#define PTE_EXT_AP_URO_SRW (2 << 4) ++#define PTE_EXT_AP_URW_SRW (3 << 4) ++#define PTE_EXT_TEX(x) ((x) << 6) /* v5 */ ++ ++/* ++ * - small page ++ */ ++#define PTE_SMALL_AP_UNO_SRO (0x00 << 4) ++#define PTE_SMALL_AP_UNO_SRW (0x55 << 4) ++#define PTE_SMALL_AP_URO_SRW (0xaa << 4) ++#define PTE_SMALL_AP_URW_SRW (0xff << 4) ++#define PTE_AP_READ PTE_SMALL_AP_URO_SRW ++#define PTE_AP_WRITE PTE_SMALL_AP_UNO_SRW ++ ++/* ++ * "Linux" PTE definitions. ++ * ++ * We keep two sets of PTEs - the hardware and the linux version. ++ * This allows greater flexibility in the way we map the Linux bits ++ * onto the hardware tables, and allows us to have YOUNG and DIRTY ++ * bits. ++ * ++ * The PTE table pointer refers to the hardware entries; the "Linux" ++ * entries are stored 1024 bytes below. ++ */ ++#define L_PTE_PRESENT (1 << 0) ++#define L_PTE_YOUNG (1 << 1) ++#define L_PTE_BUFFERABLE (1 << 2) /* matches PTE */ ++#define L_PTE_CACHEABLE (1 << 3) /* matches PTE */ ++#define L_PTE_USER (1 << 4) ++#define L_PTE_WRITE (1 << 5) ++#define L_PTE_EXEC (1 << 6) ++#define L_PTE_DIRTY (1 << 7) ++ ++#ifndef __ASSEMBLY__ ++ ++#include <asm/proc/domain.h> ++#include <asm/arch/vmalloc.h> + + #define _PAGE_USER_TABLE (PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_USER)) + #define _PAGE_KERNEL_TABLE (PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL)) + + #define pmd_bad(pmd) (pmd_val(pmd) & 2) +-#define set_pmd(pmdp,pmd) cpu_set_pmd(pmdp,pmd) ++#define set_pmd(pmdp,pmd) cpu_set_pmd(pmdp, pmd) + + static inline pmd_t __mk_pmd(pte_t *ptep, unsigned long prot) + { +@@ -75,49 +137,8 @@ + return __phys_to_virt(ptr); + } + +-/**************** +-* PTE functions * +-****************/ +- +-/* PTE types (actually level 2 descriptor) */ +-#define PTE_TYPE_MASK 0x0003 +-#define PTE_TYPE_FAULT 0x0000 +-#define PTE_TYPE_LARGE 0x0001 +-#define PTE_TYPE_SMALL 0x0002 +-#define PTE_AP_READ 0x0aa0 +-#define PTE_AP_WRITE 0x0550 +-#define PTE_CACHEABLE 0x0008 +-#define PTE_BUFFERABLE 0x0004 +- + #define set_pte(ptep, pte) cpu_set_pte(ptep,pte) + +-/* We now keep two sets of ptes - the physical and the linux version. +- * This gives us many advantages, and allows us greater flexibility. +- * +- * The Linux pte's contain: +- * bit meaning +- * 0 page present +- * 1 young +- * 2 bufferable - matches physical pte +- * 3 cacheable - matches physical pte +- * 4 user +- * 5 write +- * 6 execute +- * 7 dirty +- * 8-11 unused +- * 12-31 virtual page address +- * +- * These are stored at the pte pointer; the physical PTE is at -1024bytes +- */ +-#define L_PTE_PRESENT (1 << 0) +-#define L_PTE_YOUNG (1 << 1) +-#define L_PTE_BUFFERABLE (1 << 2) +-#define L_PTE_CACHEABLE (1 << 3) +-#define L_PTE_USER (1 << 4) +-#define L_PTE_WRITE (1 << 5) +-#define L_PTE_EXEC (1 << 6) +-#define L_PTE_DIRTY (1 << 7) +- + /* + * The following macros handle the cache and bufferable bits... + */ +@@ -162,5 +183,8 @@ + * Mark the prot value as uncacheable and unbufferable. + */ + #define pgprot_noncached(prot) __pgprot(pgprot_val(prot) & ~(L_PTE_CACHEABLE | L_PTE_BUFFERABLE)) ++#define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~L_PTE_CACHEABLE) ++ ++#endif /* __ASSEMBLY__ */ + + #endif /* __ASM_PROC_PGTABLE_H */ +--- linux-2.4.25/include/asm-arm/proc-armv/processor.h~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/proc-armv/processor.h 2004-03-31 17:15:12.000000000 +0200 +@@ -23,6 +23,9 @@ + #define KERNEL_STACK_SIZE PAGE_SIZE + + struct context_save_struct { ++#ifdef CONFIG_CPU_XSCALE ++ long long acc0; ++#endif + unsigned long cpsr; + unsigned long r4; + unsigned long r5; +@@ -35,7 +38,11 @@ + unsigned long pc; + }; + ++#ifdef CONFIG_CPU_XSCALE ++#define INIT_CSS (struct context_save_struct){ 0, SVC_MODE, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ++#else + #define INIT_CSS (struct context_save_struct){ SVC_MODE, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ++#endif + + #define EXTRA_THREAD_STRUCT \ + unsigned int domain; +--- linux-2.4.25/include/asm-arm/proc-fns.h~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/proc-fns.h 2004-03-31 17:15:12.000000000 +0200 +@@ -124,6 +124,14 @@ + # define CPU_NAME sa1100 + # endif + # endif ++# ifdef CONFIG_CPU_XSCALE ++# ifdef CPU_NAME ++# undef MULTI_CPU ++# define MULTI_CPU ++# else ++# define CPU_NAME xscale ++# endif ++# endif + #endif + + #ifndef MULTI_CPU +--- linux-2.4.25/include/asm-arm/procinfo.h~2.4.25-vrs2-pxa1.patch 2003-08-25 13:44:43.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/procinfo.h 2004-03-31 17:15:12.000000000 +0200 +@@ -55,7 +55,8 @@ + #define HWCAP_FAST_MULT 16 + #define HWCAP_FPA 32 + #define HWCAP_VFP 64 +-#define HWCAP_EDSP 128 ++#define HWCAP_EDSP 128 /* El Segundo */ + #define HWCAP_JAVA 256 ++#define HWCAP_XSCALE 512 /* XScale DSP co-processor */ + + #endif +--- linux-2.4.25/include/asm-arm/uaccess.h~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/uaccess.h 2004-03-31 17:15:12.000000000 +0200 +@@ -86,7 +86,7 @@ + __get_user_x(__r1, __p, __e, 1, "lr"); \ + break; \ + case 2: \ +- __get_user_x(__r1, __p, __e, 2, "r2", "lr"); \ ++ __get_user_x(__r1, __p, __e, 2, "ip", "lr"); \ + break; \ + case 4: \ + __get_user_x(__r1, __p, __e, 4, "lr"); \ +--- linux-2.4.25/include/linux/cramfs_fs_sb.h~2.4.25-vrs2-pxa1.patch 2001-07-20 01:14:53.000000000 +0200 ++++ linux-2.4.25/include/linux/cramfs_fs_sb.h 2004-03-31 17:15:12.000000000 +0200 +@@ -10,6 +10,10 @@ + unsigned long blocks; + unsigned long files; + unsigned long flags; ++#ifdef CONFIG_CRAMFS_LINEAR ++ unsigned long linear_phys_addr; ++ char * linear_virt_addr; ++#endif + }; + + #endif +--- linux-2.4.25/include/linux/i2c-id.h~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/include/linux/i2c-id.h 2004-03-31 17:15:12.000000000 +0200 +@@ -100,6 +100,10 @@ + #define I2C_DRIVERID_SAA7191 57 /* video decoder */ + #define I2C_DRIVERID_INDYCAM 58 /* SGI IndyCam */ + ++#define I2C_DRIVERID_DS1307 46 /* real time clock: DS1307 */ ++#define I2C_DRIVERID_24LC64 47 /* EEprom 24LC64 */ ++#define I2C_DRIVERID_FM24CLB4 48 /* EEprom FM24CLB4 */ ++ + #define I2C_DRIVERID_EXP0 0xF0 /* experimental use id's */ + #define I2C_DRIVERID_EXP1 0xF1 + #define I2C_DRIVERID_EXP2 0xF2 +@@ -172,6 +176,8 @@ + + #define I2C_ALGO_OCP 0x120000 /* IBM or otherwise On-chip I2C algorithm */ + ++#define I2C_ALGO_PXA 0x400000 /* Intel PXA I2C algorithm */ ++ + #define I2C_ALGO_EXP 0x800000 /* experimental */ + + #define I2C_ALGO_MASK 0xff0000 /* Mask for algorithms */ +--- linux-2.4.25/include/linux/serial.h~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/include/linux/serial.h 2004-03-31 17:15:12.000000000 +0200 +@@ -75,11 +75,13 @@ + #define PORT_16654 11 + #define PORT_16850 12 + #define PORT_RSA 13 /* RSA-DV II/S card */ +-#define PORT_MAX 13 ++#define PORT_PXA 14 ++#define PORT_MAX 14 + + #define SERIAL_IO_PORT 0 + #define SERIAL_IO_HUB6 1 + #define SERIAL_IO_MEM 2 ++#define SERIAL_IO_MEM32 3 + + struct serial_uart_config { + char *name; +--- linux-2.4.25/include/linux/serial_reg.h~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/include/linux/serial_reg.h 2004-03-31 17:15:12.000000000 +0200 +@@ -119,6 +119,14 @@ + #define UART_IERX_SLEEP 0x10 /* Enable sleep mode */ + + /* ++ * The Intel PXA250/210 chip defines those bits ++ */ ++#define UART_IER_DMAE 0x80 /* DMA Requests Enable */ ++#define UART_IER_UUE 0x40 /* UART Unit Enable */ ++#define UART_IER_NRZE 0x20 /* NRZ coding Enable */ ++#define UART_IER_RTOIE 0x10 /* Receiver Time Out Interrupt Enable */ ++ ++/* + * These are the definitions for the Modem Control Register + */ + #define UART_MCR_AFE 0x20 /* Enable auto-RTS/CTS (TI16C750) */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/mmc/ioctl.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,25 @@ ++/* ++ * linux/include/linux/mmc/ioctl.h ++ * ++ * Author: Vladimir Shebordaev ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id$ ++ * ++ * 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 __MMC_IOCTL_H__ ++#define __MMC_IOCTL_H__ ++ ++#include <asm/ioctl.h> ++ ++/* IOCTL commands provided by MMC subsystem */ ++#define IOCMMCSTRNSMODE _IOW('I',0x0f01,int) ++#define IOCMMCGTRNSMODE _IOR('I',0x0f02,int) ++#define IOCMMCGCARDESC _IOR('I',0x0f03,int) /* FIXME */ ++#define IOCMMCGBLKSZMAX _IOR('I',0x0f04,ssize_t) ++#define IOCMMCGNOBMAX _IOR('I',0x0f05,ssize_t) ++ ++#endif /* __MMC_IOCTL_H__ */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/mmc/mmc.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,143 @@ ++/* ++ * linux/include/linux/mmc/mmc.h ++ * ++ * Author: Vladimir Shebordaev ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id$ ++ * ++ * 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 __MMC_H__ ++#define __MMC_H__ ++ ++#include <linux/types.h> ++#include <mmc/types.h> ++ ++/* ++ * MMC card type ++ */ ++enum _mmc_type { ++ MMC_CARD_TYPE_RO = 1, ++ MMC_CARD_TYPE_RW, ++ MMC_CARD_TYPE_IO ++}; ++ ++/* ++ * MMC card state ++ */ ++enum _mmc_state { ++ MMC_CARD_STATE_IDLE = 1, ++ MMC_CARD_STATE_READY, ++ MMC_CARD_STATE_IDENT, ++ MMC_CARD_STATE_STNBY, ++ MMC_CARD_STATE_TRAN, ++ MMC_CARD_STATE_DATA, ++ MMC_CARD_STATE_RCV, ++ MMC_CARD_STATE_DIS, ++ MMC_CARD_STATE_UNPLUGGED=0xff ++}; ++ ++/* ++ * Data transfer mode ++ */ ++enum _mmc_transfer_mode { ++ MMC_TRANSFER_MODE_STREAM = 1, ++ MMC_TRANSFER_MODE_BLOCK_SINGLE, ++ MMC_TRANSFER_MODE_BLOCK_MULTIPLE, ++ MMC_TRANSFER_MODE_UNDEFINED = -1 ++}; ++ ++struct _mmc_card_csd_rec { /* CSD register contents */ ++/* FIXME: BYTE_ORDER */ ++ u8 ecc:2, ++ file_format:2, ++ tmp_write_protect:1, ++ perm_write_protect:1, ++ copy:1, ++ file_format_grp:1; ++ u64 content_prot_app:1, ++ rsvd3:4, ++ write_bl_partial:1, ++ write_bl_len:4, ++ r2w_factor:3, ++ default_ecc:2, ++ wp_grp_enable:1, ++ wp_grp_size:5, ++ erase_grp_mult:5, ++ erase_grp_size:5, ++ c_size_mult:3, ++ vdd_w_curr_max:3, ++ vdd_w_curr_min:3, ++ vdd_r_curr_max:3, ++ vdd_r_curr_min:3, ++ c_size:12, ++ rsvd2:2, ++ dsr_imp:1, ++ read_blk_misalign:1, ++ write_blk_misalign:1, ++ read_bl_partial:1; ++ ++ u16 read_bl_len:4, ++ ccc:12; ++ u8 tran_speed; ++ u8 nsac; ++ u8 taac; ++ u8 rsvd1:2, ++ spec_vers:4, ++ csd_structure:2; ++}; ++ ++struct _mmc_card_cid_rec { /* CID register contents */ ++/* FIXME: BYTE_ORDER */ ++ u8 mdt_year:4, ++ mdt_mon:4; ++ u32 psn; ++ u8 prv_minor:4, ++ prv_major:4; ++ u8 pnm[6]; ++ u16 oid; ++ u8 mid; ++}; ++ ++/* ++ * Public card description ++ */ ++struct _mmc_card_info_rec { ++ mmc_type_t type; ++ mmc_transfer_mode_t transfer_mode; /* current data transfer mode */ ++ __u16 rca; /* card's RCA assigned during initialization */ ++ struct _mmc_card_csd_rec csd; ++ struct _mmc_card_cid_rec cid; ++ __u32 tran_speed; /* kbits */ ++ __u16 read_bl_len; ++ __u16 write_bl_len; ++ size_t capacity; /* card's capacity in bytes */ ++}; ++ ++/* ++ * Micsellaneous defines ++ */ ++#ifndef SEEK_SET ++#define SEEK_SET (0) ++#endif ++ ++#ifndef SEEK_CUR ++#define SEEK_CUR (1) ++#endif ++ ++#ifndef SEEK_END ++#define SEEK_END (2) ++#endif ++ ++#ifndef TRUE ++#define TRUE (1) ++#endif ++ ++#ifndef FALSE ++#define FALSE (0) ++#endif ++ ++#endif /* __MMC_H__ */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/mmc/types.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,29 @@ ++/* ++ * linux/include/linux/mmc/types.h ++ * ++ * Author: Vladimir Shebordaev ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id$ ++ * ++ * 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 __MMC_TYPES_H__ ++#define __MMC_TYPES_H__ ++ ++/* MMC card */ ++typedef enum _mmc_type mmc_type_t; ++typedef enum _mmc_state mmc_state_t; ++typedef enum _mmc_transfer_mode mmc_transfer_mode_t; ++ ++typedef struct _mmc_card_csd_rec mmc_card_csd_rec_t; ++typedef struct _mmc_card_cid_rec mmc_card_cid_rec_t; ++ ++typedef struct _mmc_card_info_rec mmc_card_info_rec_t; ++typedef struct _mmc_card_info_rec *mmc_card_info_t; ++ ++typedef enum _mmc_error mmc_error_t; ++ ++#endif /* __MMC_TYPES_H__ */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/video/lcdctrl.h 2004-03-31 17:15:12.000000000 +0200 +@@ -0,0 +1,61 @@ ++/* ++ * lcdctrl.h ++ * ++ * Generic LCD control for brightness, contrast, etc. ++ * Device specific drivers implement a lcdctrl_device and ++ * provides access to it via lcdctrl_device_get_ops(). ++ * ++ * 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. ++ * ++ * History: ++ * Mar 2002: Initial version [FB] ++ * ++ */ ++#ifndef __LCD_CONTROL_H ++#define __LCD_CONTROL_H ++ ++#define _LCDCTRL_IOCTL_ON 1 ++#define _LCDCTRL_IOCTL_OFF 2 ++#define _LCDCTRL_IOCTL_INTENSITY 3 ++#define _LCDCTRL_IOCTL_BRIGHTNESS 4 ++#define _LCDCTRL_IOCTL_CONTRAST 5 ++#define _LCDCTRL_IOCTL_GET_BRIGHTNESS 6 ++#define _LCDCTRL_IOCTL_GET_CONTRAST 7 ++#define _LCDCTRL_IOCTL_GET_INTENSITY 8 ++ ++#define _LCD_CONTROL_NAME "lcdctrl" ++ ++#define LCD_NO_SYNC 0 ++#define LCD_SYNC_NEEDED 1 ++ ++int lcdctrl_enable( void); ++int lcdctrl_disable( void); ++ ++/* intensity, contrast, and brightness take values ++ * between 0..100. ++ */ ++int lcdctrl_set_intensity( int intensity); ++int lcdctrl_set_contrast( int contrast, int sync); ++int lcdctrl_set_brightness( int brightness); ++ ++int lcdctrl_get_intensity( void); ++int lcdctrl_get_contrast( void); ++int lcdctrl_get_brightness( void); ++ ++struct lcdctrl_device ++{ ++ int (*init)( int*, int*, int*); ++ int (*enable)(void); ++ int (*disable)(void); ++ int (*set_intensity)( int i); ++ int (*set_brightness)( int b); ++ int (*set_contrast)( int c, int sync); ++}; ++ ++int lcdctrl_init( void); ++ ++#endif +--- linux-2.4.25/init/do_mounts.c~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/init/do_mounts.c 2004-03-31 17:15:12.000000000 +0200 +@@ -394,6 +394,16 @@ + } + #endif + ++#ifdef CONFIG_ROOT_CRAMFS_LINEAR ++static int __init mount_linear_cramfs_root(void) ++{ ++ void *data = root_mount_data; ++ if (sys_mount("/dev/root","/root","cramfs",root_mountflags,data) == 0) ++ return 1; ++ return 0; ++} ++#endif ++ + static int __init create_dev(char *name, kdev_t dev, char *devfs_name) + { + void *handle; +@@ -759,6 +769,16 @@ + + static void __init mount_root(void) + { ++#ifdef CONFIG_ROOT_CRAMFS_LINEAR ++ if (ROOT_DEV == MKDEV(0, 0)) { ++ if (mount_linear_cramfs_root()) { ++ sys_chdir("/root"); ++ ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev; ++ printk("VFS: Mounted root (linear cramfs filesystem).\n"); ++ return; ++ } ++ } ++#endif + #ifdef CONFIG_ROOT_NFS + if (MAJOR(ROOT_DEV) == NFS_MAJOR + && MINOR(ROOT_DEV) == NFS_MINOR) { +--- linux-2.4.25/mm/memory.c~2.4.25-vrs2-pxa1.patch 2004-03-31 17:15:09.000000000 +0200 ++++ linux-2.4.25/mm/memory.c 2004-03-31 17:15:12.000000000 +0200 +@@ -1018,6 +1018,41 @@ + return 1; /* Minor fault */ + + bad_wp_page: ++ if (pte_present(pte) && pte_read(pte)) { ++ /* ++ * Handle COW of XIP memory. ++ * Note that the source memory actually isn't a ram page so ++ * no struct page is associated to the source pte. ++ */ ++ char *dst; ++ int ret; ++ ++ spin_unlock(&mm->page_table_lock); ++ new_page = alloc_page(GFP_HIGHUSER); ++ if (!new_page) ++ return -1; ++ ++ /* copy XIP data to memory */ ++ dst = kmap_atomic(new_page, KM_USER0); ++ ret = copy_from_user(dst, (void*)address, PAGE_SIZE); ++ kunmap_atomic(dst, KM_USER0); ++ ++ /* make sure pte didn't change while we dropped the lock */ ++ spin_lock(&mm->page_table_lock); ++ if (!ret && pte_same(*page_table, pte)) { ++ ++mm->rss; ++ break_cow(vma, new_page, address, page_table); ++ lru_cache_add(new_page); ++ spin_unlock(&mm->page_table_lock); ++ return 1; /* Minor fault */ ++ } ++ ++ /* pte changed: back off */ ++ spin_unlock(&mm->page_table_lock); ++ page_cache_release(new_page); ++ return ret ? -1 : 1; ++ } ++ + spin_unlock(&mm->page_table_lock); + printk("do_wp_page: bogus page at address %08lx\n", address); + return -1; diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/2.4.25-vrs2.patch b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/2.4.25-vrs2.patch index e69de29bb2..c5f370aee3 100644 --- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/2.4.25-vrs2.patch +++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/2.4.25-vrs2.patch @@ -0,0 +1,86979 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux-2.4.25/Documentation/Configure.help~2.4.25-vrs2.patch 2004-02-18 14:36:30.000000000 +0100 ++++ linux-2.4.25/Documentation/Configure.help 2004-03-31 17:15:08.000000000 +0200 +@@ -4837,6 +4837,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 +@@ -13125,6 +13132,17 @@ + The module will be called tmspci.o. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + ++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. +@@ -15069,6 +15087,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 +@@ -19085,6 +19113,20 @@ + <file:Documentation/modules.txt>. + 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. +@@ -20230,6 +20272,17 @@ + <file:Documentation/modules.txt>. 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. +@@ -21891,6 +21944,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 +@@ -25594,6 +25671,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) +@@ -25601,6 +25692,14 @@ + <http://www.visuaide.com/pagevictor.en.html> 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 +@@ -25668,37 +25767,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. + +-Round robin I and D cache replacement algorithm ++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. ++ ++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 +@@ -25745,6 +25872,11 @@ + Say Y here if you are using the inhand electronics OmniMeter. See + <http://www.inhandelectronics.com/html/omni1.html> 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 +@@ -25757,6 +25889,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 +@@ -25785,19 +25926,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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/Documentation/arm/Porting 2004-03-31 17:15:08.000000000 +0200 +@@ -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. ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/Documentation/arm/mem_alignment 2004-03-31 17:15:08.000000000 +0200 +@@ -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/sys/debug/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/sys/debug/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. +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/Documentation/arm/memory.txt 2004-03-31 17:15:08.000000000 +0200 +@@ -0,0 +1,74 @@ ++ Kernel Memory Layout on ARM Linux ++ ++ Russell King <rmk@arm.linux.org.uk> ++ 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(). +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/Documentation/cpufreq/core.txt 2004-03-31 17:15:08.000000000 +0200 +@@ -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 <linux@brodo.de> ++ David Kimdon <dwhedon@debian.org> ++ ++ ++ ++ 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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/Documentation/cpufreq/cpu-drivers.txt 2004-03-31 17:15:08.000000000 +0200 +@@ -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 <linux@brodo.de> ++ ++ ++ ++ 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. ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/Documentation/cpufreq/governors.txt 2004-03-31 17:15:08.000000000 +0200 +@@ -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 <linux@brodo.de> ++ ++ ++ ++ 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. ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/Documentation/cpufreq/index.txt 2004-03-31 17:15:08.000000000 +0200 +@@ -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 <linux@brodo.de> ++ ++ ++ ++ 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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/Documentation/cpufreq/user-guide.txt 2004-03-31 17:15:08.000000000 +0200 +@@ -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 <linux@brodo.de> ++ ++ ++ ++ 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. ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/Documentation/cpufreq-old 2004-03-31 17:15:08.000000000 +0200 +@@ -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 <devel@brodo.de> ++ ++ ++ ++ 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 <mike@ossmann.com> 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 seperately (seperate 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/ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/Documentation/l3/structure 2004-03-31 17:15:08.000000000 +0200 +@@ -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. +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/Documentation/serial/driver 2004-03-31 17:15:08.000000000 +0200 +@@ -0,0 +1,208 @@ ++ ++ Low Level Serial API ++ -------------------- ++ ++ ++ $Id$ ++ ++ ++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 ++<rmk@arm.linux.org.uk> ++ ++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 <asm/ioctl.h> ++ ++ ++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; ++ }; ++ +--- linux-2.4.25/Makefile~2.4.25-vrs2.patch 2004-02-18 14:36:32.000000000 +0100 ++++ linux-2.4.25/Makefile 2004-03-31 17:15:08.000000000 +0200 +@@ -1,7 +1,7 @@ + VERSION = 2 + PATCHLEVEL = 4 + SUBLEVEL = 25 +-EXTRAVERSION = ++EXTRAVERSION =-vrs2 + + 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) + +@@ -273,11 +278,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 + +--- linux-2.4.25/Rules.make~2.4.25-vrs2.patch 2004-02-18 14:36:30.000000000 +0100 ++++ linux-2.4.25/Rules.make 2004-03-31 17:15:08.000000000 +0200 +@@ -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)))' ; \ +--- linux-2.4.25/arch/alpha/config.in~2.4.25-vrs2.patch 2004-02-18 14:36:30.000000000 +0100 ++++ linux-2.4.25/arch/alpha/config.in 2004-03-31 17:15:08.000000000 +0200 +@@ -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" + +--- linux-2.4.25/arch/arm/Makefile~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/Makefile 2004-03-31 17:15:08.000000000 +0200 +@@ -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 +--- linux-2.4.25/arch/arm/boot/compressed/head.S~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/boot/compressed/head.S 2004-03-31 17:15:08.000000000 +0200 +@@ -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 +--- linux-2.4.25/arch/arm/config.in~2.4.25-vrs2.patch 2004-02-18 14:36:30.000000000 +0100 ++++ linux-2.4.25/arch/arm/config.in 2004-03-31 17:15:08.000000000 +0200 +@@ -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 + +@@ -729,10 +756,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 ++ +--- linux-2.4.25/arch/arm/def-configs/at91rm9200dk~2.4.25-vrs2.patch 2004-02-18 14:36:30.000000000 +0100 ++++ linux-2.4.25/arch/arm/def-configs/at91rm9200dk 2004-03-31 17:15:08.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/def-configs/csb337 2004-03-31 17:15:08.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/fastfpe/CPDO.S 2004-03-31 17:15:08.000000000 +0200 +@@ -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 ++ ++/*---------------------------------------------------------------------------*/ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/fastfpe/CPDT.S 2004-03-31 17:15:08.000000000 +0200 +@@ -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 ++ ++/*---------------------------------------------------------------------------*/ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/fastfpe/CPRT.S 2004-03-31 17:15:08.000000000 +0200 +@@ -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 ++ ++/*---------------------------------------------------------------------------*/ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/fastfpe/Makefile 2004-03-31 17:15:08.000000000 +0200 +@@ -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) +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/fastfpe/entry.S 2004-03-31 17:15:08.000000000 +0200 +@@ -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 ++ ++/*---------------------------------------------------------------------------*/ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/fastfpe/module.c 2004-03-31 17:15:08.000000000 +0200 +@@ -0,0 +1,78 @@ ++/* ++ Fast Floating Point Emulator ++ (c) Peter Teichmann <mail@peter-teichmann.de> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/signal.h> ++#include <linux/sched.h> ++#include <linux/init.h> ++ ++#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 <mail@peter-teichmann.de>"); ++MODULE_DESCRIPTION("Fast floating point emulator with full precision"); +--- linux-2.4.25/arch/arm/kernel/calls.S~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/kernel/calls.S 2004-03-31 17:15:08.000000000 +0200 +@@ -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) +--- linux-2.4.25/arch/arm/kernel/dma-rpc.c~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/kernel/dma-rpc.c 2004-03-31 17:15:08.000000000 +0200 +@@ -26,19 +26,6 @@ + #include <asm/mach/dma.h> + #include <asm/hardware/iomd.h> + +-#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); + } + +--- linux-2.4.25/arch/arm/kernel/entry-armv.S~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/kernel/entry-armv.S 2004-03-31 17:15:08.000000000 +0200 +@@ -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 +--- linux-2.4.25/arch/arm/kernel/head-armv.S~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/kernel/head-armv.S 2004-03-31 17:15:08.000000000 +0200 +@@ -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 +--- linux-2.4.25/arch/arm/kernel/irq.c~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/kernel/irq.c 2004-03-31 17:15:08.000000000 +0200 +@@ -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 +--- linux-2.4.25/arch/arm/kernel/ptrace.c~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/kernel/ptrace.c 2004-03-31 17:15:08.000000000 +0200 +@@ -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); +--- linux-2.4.25/arch/arm/kernel/semaphore.c~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/kernel/semaphore.c 2004-03-31 17:15:08.000000000 +0200 +@@ -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\ +--- linux-2.4.25/arch/arm/kernel/signal.c~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/kernel/signal.c 2004-03-31 17:15:08.000000000 +0200 +@@ -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 */ + } + } +--- linux-2.4.25/arch/arm/lib/Makefile~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/lib/Makefile 2004-03-31 17:15:08.000000000 +0200 +@@ -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 := + +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/lib/div64.S 2004-03-31 17:15:08.000000000 +0200 +@@ -0,0 +1,59 @@ ++#include <linux/linkage.h> ++ ++#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} +--- linux-2.4.25/arch/arm/lib/putuser.S~2.4.25-vrs2.patch 2001-10-11 18:04:57.000000000 +0200 ++++ linux-2.4.25/arch/arm/lib/putuser.S 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/arch/arm/mach-integrator/pci_v3.c~2.4.25-vrs2.patch 2003-06-13 16:51:29.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-integrator/pci_v3.c 2004-03-31 17:15:09.000000000 +0200 +@@ -21,7 +21,6 @@ + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + #include <linux/config.h> +-#include <linux/sched.h> + #include <linux/kernel.h> + #include <linux/pci.h> + #include <linux/ptrace.h> +@@ -32,6 +31,7 @@ + #include <linux/init.h> + + #include <asm/hardware.h> ++#include <asm/io.h> + #include <asm/irq.h> + #include <asm/system.h> + #include <asm/mach/pci.h> +@@ -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 + } +--- linux-2.4.25/arch/arm/mach-sa1100/pm.c~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-sa1100/pm.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <jcorrall@mac.com> ++ * Saved the GPIO levels for resume after sleep. + */ + #include <linux/config.h> + #include <linux/init.h> +@@ -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); + +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-sa1100/sa1100_usb.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <asm/byteorder.h> ++ ++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 */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-sa1100/sa1111-ohci.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,140 @@ ++#include <linux/config.h> ++#include <linux/sched.h> ++#include <linux/pci.h> ++#include <linux/mm.h> ++ ++#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 */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-sa1100/usb-char.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/config.h> ++#include <linux/miscdevice.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/cache.h> ++#include <linux/poll.h> ++#include <linux/circ_buf.h> ++#include <linux/timer.h> ++ ++#include <asm/io.h> ++#include <asm/semaphore.h> ++#include <asm/proc/page.h> ++#include <asm/mach-types.h> ++ ++#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 ++ ++ ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-sa1100/usb-char.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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 */ ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-sa1100/usb-eth.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/timer.h> ++ ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> ++#include <linux/random.h> ++ ++#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); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-sa1100/usb_ctl.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/proc_fs.h> ++#include <linux/tqueue.h> ++#include <linux/delay.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <asm/io.h> ++#include <asm/dma.h> ++#include <asm/irq.h> ++#include <asm/mach-types.h> ++ ++#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 ); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-sa1100/usb_ctl.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <asm/dma.h> /* 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 */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-sa1100/usb_ep0.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/delay.h> ++#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 */ ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-sa1100/usb_recv.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/pci.h> ++#include <linux/errno.h> ++#include <asm/dma.h> ++#include <asm/system.h> ++ ++#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); ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mach-sa1100/usb_send.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/pci.h> ++#include <linux/errno.h> ++#include <linux/delay.h> // for the massive_attack hack 28Feb01ww ++#include <asm/hardware.h> ++#include <asm/dma.h> ++#include <asm/system.h> ++#include <asm/byteorder.h> ++ ++#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); +--- linux-2.4.25/arch/arm/mm/Makefile~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/arch/arm/mm/alignment.c~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/alignment.c 2004-03-31 17:15:09.000000000 +0200 +@@ -11,7 +11,6 @@ + #include <linux/config.h> + #include <linux/compiler.h> + #include <linux/signal.h> +-#include <linux/sched.h> + #include <linux/kernel.h> + #include <linux/errno.h> + #include <linux/string.h> +@@ -19,7 +18,6 @@ + #include <linux/ptrace.h> + #include <linux/mman.h> + #include <linux/mm.h> +-#include <linux/interrupt.h> + #include <linux/proc_fs.h> + #include <linux/bitops.h> + #include <linux/init.h> +@@ -30,9 +28,7 @@ + #include <asm/pgtable.h> + #include <asm/unaligned.h> + +-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 +@@ -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); +--- linux-2.4.25/arch/arm/mm/fault-armv.c~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/fault-armv.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/config.h> +-#include <linux/signal.h> + #include <linux/sched.h> + #include <linux/kernel.h> +-#include <linux/errno.h> +-#include <linux/string.h> + #include <linux/types.h> + #include <linux/ptrace.h> +-#include <linux/mman.h> + #include <linux/mm.h> +-#include <linux/interrupt.h> +-#include <linux/proc_fs.h> + #include <linux/bitops.h> + #include <linux/init.h> + +-#include <asm/system.h> +-#include <asm/uaccess.h> + #include <asm/pgalloc.h> + #include <asm/pgtable.h> ++#include <asm/io.h> + +-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,27 +133,30 @@ + * 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; +@@ -210,14 +190,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 +225,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"); + } + } +--- linux-2.4.25/arch/arm/mm/fault-common.c~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/fault-common.c 2004-03-31 17:15:09.000000000 +0200 +@@ -11,21 +11,17 @@ + #include <linux/config.h> + #include <linux/signal.h> + #include <linux/sched.h> +-#include <linux/kernel.h> +-#include <linux/errno.h> + #include <linux/string.h> +-#include <linux/types.h> + #include <linux/ptrace.h> +-#include <linux/mman.h> + #include <linux/mm.h> + #include <linux/interrupt.h> +-#include <linux/proc_fs.h> + #include <linux/init.h> + + #include <asm/system.h> +-#include <asm/uaccess.h> + #include <asm/pgtable.h> +-#include <asm/unaligned.h> ++#include <asm/uaccess.h> ++ ++#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; + } +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/fault.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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); ++ +--- linux-2.4.25/arch/arm/mm/init.c~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/init.c 2004-03-31 17:15:09.000000000 +0200 +@@ -9,7 +9,6 @@ + */ + #include <linux/config.h> + #include <linux/signal.h> +-#include <linux/sched.h> + #include <linux/kernel.h> + #include <linux/errno.h> + #include <linux/string.h> +@@ -18,7 +17,6 @@ + #include <linux/mman.h> + #include <linux/mm.h> + #include <linux/swap.h> +-#include <linux/swapctl.h> + #include <linux/smp.h> + #include <linux/init.h> + #include <linux/bootmem.h> +--- linux-2.4.25/arch/arm/mm/ioremap.c~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/ioremap.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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.. +--- linux-2.4.25/arch/arm/mm/mm-armv.c~2.4.25-vrs2.patch 2003-11-28 19:26:19.000000000 +0100 ++++ linux-2.4.25/arch/arm/mm/mm-armv.c 2004-03-31 17:15:09.000000000 +0200 +@@ -9,7 +9,6 @@ + * + * Page table sludge for ARM v3 and v4 processor architectures. + */ +-#include <linux/sched.h> + #include <linux/mm.h> + #include <linux/init.h> + #include <linux/bootmem.h> +@@ -390,6 +389,9 @@ + init_maps->bufferable = 0; + + create_mapping(init_maps); ++ ++ flush_cache_all(); ++ flush_tlb_all(); + } + + /* +--- linux-2.4.25/arch/arm/mm/proc-arm1020.S~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/proc-arm1020.S 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/proc-arm1020E.S 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/linkage.h> ++#include <linux/config.h> ++#include <asm/assembler.h> ++#include <asm/constants.h> ++#include <asm/procinfo.h> ++#include <asm/hardware.h> ++ ++/* ++ * 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 ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/proc-arm1022.S 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/linkage.h> ++#include <linux/config.h> ++#include <asm/assembler.h> ++#include <asm/constants.h> ++#include <asm/procinfo.h> ++#include <asm/hardware.h> ++ ++/* ++ * 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 +--- linux-2.4.25/arch/arm/mm/proc-arm1026.S~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/proc-arm1026.S 2004-03-31 17:15:09.000000000 +0200 +@@ -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 + +--- linux-2.4.25/arch/arm/mm/proc-arm6,7.S~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/proc-arm6,7.S 2004-03-31 17:15:09.000000000 +0200 +@@ -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? +--- linux-2.4.25/arch/arm/mm/proc-arm720.S~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/proc-arm720.S 2004-03-31 17:15:09.000000000 +0200 +@@ -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? +--- linux-2.4.25/arch/arm/mm/proc-arm920.S~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/proc-arm920.S 2004-03-31 17:15:09.000000000 +0200 +@@ -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? +--- linux-2.4.25/arch/arm/mm/proc-arm922.S~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/proc-arm922.S 2004-03-31 17:15:09.000000000 +0200 +@@ -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? +--- linux-2.4.25/arch/arm/mm/proc-arm925.S~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/proc-arm925.S 2004-03-31 17:15:09.000000000 +0200 +@@ -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? +--- linux-2.4.25/arch/arm/mm/proc-arm926.S~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/proc-arm926.S 2004-03-31 17:15:09.000000000 +0200 +@@ -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? +--- linux-2.4.25/arch/arm/mm/proc-sa110.S~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/mm/proc-sa110.S 2004-03-31 17:15:09.000000000 +0200 +@@ -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? +--- linux-2.4.25/arch/arm/tools/mach-types~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/arm/tools/mach-types 2004-03-31 17:15:09.000000000 +0200 +@@ -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: Tue Feb 10 17:10:34 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 +@@ -300,7 +300,7 @@ + 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,111 @@ + 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 ++omap1610 ARCH_OMAP1610 OMAP1610 382 ++pelee ARCH_PELEE PELEE 383 ++e7xx ARCH_E7XX E7XX 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 +--- linux-2.4.25/arch/i386/config.in~2.4.25-vrs2.patch 2004-02-18 14:36:30.000000000 +0100 ++++ linux-2.4.25/arch/i386/config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/arch/i386/kernel/Makefile~2.4.25-vrs2.patch 2003-11-28 19:26:19.000000000 +0100 ++++ linux-2.4.25/arch/i386/kernel/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 + +--- linux-2.4.25/arch/i386/kernel/apm.c~2.4.25-vrs2.patch 2003-08-25 13:44:39.000000000 +0200 ++++ linux-2.4.25/arch/i386/kernel/apm.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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: +--- linux-2.4.25/arch/i386/lib/Makefile~2.4.25-vrs2.patch 2001-09-10 16:31:30.000000000 +0200 ++++ linux-2.4.25/arch/i386/lib/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 + +--- linux-2.4.25/arch/i386/math-emu/Makefile~2.4.25-vrs2.patch 2000-12-29 23:07:20.000000000 +0100 ++++ linux-2.4.25/arch/i386/math-emu/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 \ +--- linux-2.4.25/arch/ia64/config.in~2.4.25-vrs2.patch 2004-02-18 14:36:30.000000000 +0100 ++++ linux-2.4.25/arch/ia64/config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 \ +--- linux-2.4.25/arch/m68k/config.in~2.4.25-vrs2.patch 2004-02-18 14:36:30.000000000 +0100 ++++ linux-2.4.25/arch/m68k/config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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" + +--- linux-2.4.25/arch/mips/config.in~2.4.25-vrs2.patch 2002-11-29 00:53:09.000000000 +0100 ++++ linux-2.4.25/arch/mips/config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/arch/parisc/config.in~2.4.25-vrs2.patch 2004-02-18 14:36:30.000000000 +0100 ++++ linux-2.4.25/arch/parisc/config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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' +--- linux-2.4.25/arch/ppc/config.in~2.4.25-vrs2.patch 2004-02-18 14:36:30.000000000 +0100 ++++ linux-2.4.25/arch/ppc/config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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" + +--- linux-2.4.25/arch/sh/config.in~2.4.25-vrs2.patch 2004-02-18 14:36:30.000000000 +0100 ++++ linux-2.4.25/arch/sh/config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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' +--- linux-2.4.25/arch/sparc/config.in~2.4.25-vrs2.patch 2004-02-18 14:36:30.000000000 +0100 ++++ linux-2.4.25/arch/sparc/config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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' +--- linux-2.4.25/arch/sparc64/config.in~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/arch/sparc64/config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/Makefile~2.4.25-vrs2.patch 2003-11-28 19:26:19.000000000 +0100 ++++ linux-2.4.25/drivers/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/acorn/char/i2c.c~2.4.25-vrs2.patch 2004-01-05 14:53:56.000000000 +0100 ++++ linux-2.4.25/drivers/acorn/char/i2c.c 2004-03-31 17:15:09.000000000 +0200 +@@ -166,7 +166,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; +--- linux-2.4.25/drivers/acorn/net/ether1.c~2.4.25-vrs2.patch 2003-08-25 13:44:40.000000000 +0200 ++++ linux-2.4.25/drivers/acorn/net/ether1.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 } + }; +--- linux-2.4.25/drivers/acorn/net/ether3.c~2.4.25-vrs2.patch 2003-08-25 13:44:40.000000000 +0200 ++++ linux-2.4.25/drivers/acorn/net/ether3.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 }, +--- linux-2.4.25/drivers/acorn/net/etherh.c~2.4.25-vrs2.patch 2003-08-25 13:44:40.000000000 +0200 ++++ linux-2.4.25/drivers/acorn/net/etherh.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 }, +--- linux-2.4.25/drivers/acorn/scsi/cumana_1.c~2.4.25-vrs2.patch 2001-09-14 00:21:32.000000000 +0200 ++++ linux-2.4.25/drivers/acorn/scsi/cumana_1.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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); +--- linux-2.4.25/drivers/acorn/scsi/ecoscsi.c~2.4.25-vrs2.patch 2002-08-03 02:39:43.000000000 +0200 ++++ linux-2.4.25/drivers/acorn/scsi/ecoscsi.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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); +--- linux-2.4.25/drivers/acorn/scsi/oak.c~2.4.25-vrs2.patch 2001-10-11 18:04:57.000000000 +0200 ++++ linux-2.4.25/drivers/acorn/scsi/oak.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/i2c/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/i2c/at91_i2c.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <phil@stimpy.netroedge.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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ ++*/ ++ ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/pci.h> ++#include <linux/types.h> ++#include <linux/delay.h> ++#include <linux/i2c.h> ++#include <linux/init.h> ++ ++#include <asm/arch/AT91RM9200_TWI.h> ++#include <asm/arch/pio.h> ++#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; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/i2c/at91_i2c.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/mtd/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/mtd/at91_dataflash.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,495 @@ ++/* ++ * 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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/slab.h> ++#include <linux/pci.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/partitions.h> ++ ++#include <asm/arch/AT91RM9200_SPI.h> ++#include <asm/arch/pio.h> ++#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 a block 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) || (instr->len != priv->page_size)) ++ return -EINVAL; ++ if ((instr->addr % priv->page_size) != 0) ++ return -EINVAL; ++ ++ command = kmalloc(4, GFP_KERNEL); ++ if (!command) ++ return -ENOMEM; ++ ++ /* 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); ++ ++ 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; ++ char *writebuf; ++ unsigned short status; ++ int res = 0; ++ char* command; ++ ++#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; ++ ++ /* 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, writebuf, 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(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") +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/mtd/at91_dataflash.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/mtd/at91_nand.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/slab.h> ++#include <linux/module.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/nand.h> ++#include <linux/mtd/partitions.h> ++#include <asm/io.h> ++#include <asm/arch/hardware.h> ++#include <asm/sizes.h> ++ ++#include <asm/arch/pio.h> ++#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"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/mtd/at91_nand.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/net/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/net/at91_ether.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/config.h> ++#include <linux/mii.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> ++#include <asm/io.h> ++#include <linux/pci.h> ++#include <linux/crc32.h> ++#include <asm/uaccess.h> ++#include <linux/ethtool.h> ++ ++#include <asm/arch/AT91RM9200_EMAC.h> ++#include <asm/arch/pio.h> ++#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"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/net/at91_ether.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/rtc/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/rtc/at91_rtc.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/string.h> ++#include <linux/init.h> ++#include <linux/poll.h> ++#include <linux/proc_fs.h> ++#include <asm/bitops.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <linux/rtc.h> ++ ++#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; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/serial/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/serial/at91_serial.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/tty.h> ++#include <linux/ioport.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/serial.h> ++#include <linux/console.h> ++#include <linux/sysrq.h> ++ ++#include <asm/arch/AT91RM9200_USART.h> ++#include <asm/mach/serial_at91rm9200.h> ++#include <asm/arch/pio.h> ++ ++ ++#if defined(CONFIG_SERIAL_AT91_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) ++#define SUPPORT_SYSRQ ++#endif ++ ++#include <linux/serial_core.h> ++ ++#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(uart, cflag)) ++ at91_pops.enable_ms(uart); ++} ++ ++/* ++ * 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"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/spi/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/spi/at91_spi.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/init.h> ++#include <linux/module.h> ++#include <asm/semaphore.h> ++#include <linux/pci.h> ++#include <linux/sched.h> ++#include <linux/completion.h> ++ ++#include <asm/arch/AT91RM9200_SPI.h> ++#include <asm/arch/pio.h> ++#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 */ ++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. ++ */ ++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") +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/spi/at91_spi.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/spi/at91_spidev.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/config.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/iobuf.h> ++#include <linux/highmem.h> ++ ++#ifdef CONFIG_DEVFS_FS ++#include <linux/devfs_fs_kernel.h> ++#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; ++} ++ ++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 ++ */ ++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 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") +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/usb/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/usb/at91_usb-ohci.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,81 @@ ++/* ++ * linux/drivers/at91/usb/at91_usb_ohci-at91.c ++ * ++ * (c) Rick Bronson ++ * ++ * The outline of this code was taken from Brad Parkers <brad@heeltoe.com> ++ * original OHCI driver modifications, and reworked into a cleaner form ++ * by Russell King <rmk@arm.linux.org.uk>. ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/sched.h> ++#include <linux/ioport.h> ++#include <linux/interrupt.h> ++#include <linux/slab.h> ++#include <linux/usb.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/io.h> ++ ++#include <asm/arch/AT91RM9200_UHP.h> ++ ++/* ++ 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; ++ } ++ ++ /* 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); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/watchdog/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/at91/watchdog/at91_wdt.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/config.h> ++#include <linux/miscdevice.h> ++#include <linux/watchdog.h> ++#include <asm/uaccess.h> ++#include <linux/init.h> ++ ++#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. ++ */ ++void at91_wdt_stop(void) ++{ ++ AT91_SYS->ST_WDMR = AT91C_ST_EXTEN; ++} ++ ++/* ++ * Enable and reset the watchdog. ++ */ ++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") +--- linux-2.4.25/drivers/block/Makefile~2.4.25-vrs2.patch 2003-06-13 16:51:32.000000000 +0200 ++++ linux-2.4.25/drivers/block/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/block/ll_rw_blk.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/block/ll_rw_blk.c 2004-03-31 17:15:09.000000000 +0200 +@@ -32,6 +32,19 @@ + #include <linux/slab.h> + #include <linux/module.h> + ++/* 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; +@@ -1540,7 +1553,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(); +@@ -1554,12 +1567,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(); +@@ -1617,7 +1632,7 @@ + jsfd_init(); + #endif + return 0; +-}; ++} + + EXPORT_SYMBOL(io_request_lock); + EXPORT_SYMBOL(end_that_request_first); +--- linux-2.4.25/drivers/cdrom/cdrom.c~2.4.25-vrs2.patch 2003-11-28 19:26:20.000000000 +0100 ++++ linux-2.4.25/drivers/cdrom/cdrom.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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) */ + +--- linux-2.4.25/drivers/char/Config.in~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/char/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/char/Makefile~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/char/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/char/amba_kmi_keyb.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/config.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> /* for in_interrupt */ ++#include <linux/timer.h> ++#include <linux/init.h> ++#include <linux/delay.h> /* for udelay */ ++#include <linux/kbd_kern.h> /* for keyboard_tasklet */ ++#include <linux/kbd_ll.h> ++ ++#include <asm/io.h> ++#include <asm/hardware/amba_kmi.h> ++#include <asm/mach/amba_kmi.h> ++#include <asm/keyboard.h> ++ ++//#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 <linux/fs.h> /* for struct file_ops */ ++#include <linux/poll.h> /* for poll_table */ ++#include <linux/miscdevice.h> /* for struct miscdev */ ++#include <linux/random.h> /* for add_mouse_randomness */ ++#include <linux/slab.h> /* for kmalloc */ ++#include <linux/smp_lock.h> /* for {un,}lock_kernel */ ++#include <linux/spinlock.h> ++ ++#include <asm/uaccess.h> ++ ++#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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/char/anakin_ts.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/types.h> ++#include <linux/wait.h> ++#include <linux/fs.h> ++#include <linux/sched.h> ++#include <linux/poll.h> ++#include <linux/miscdevice.h> ++#include <linux/init.h> ++#include <linux/compiler.h> ++#include <linux/interrupt.h> ++ ++#include <asm/io.h> ++#include <asm/uaccess.h> ++#include <asm/irq.h> ++ ++/* ++ * 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 <chan@aleph1.co.uk>"); ++MODULE_DESCRIPTION("Anakin touchscreen driver"); ++MODULE_SUPPORTED_DEVICE("touchscreen/anakin"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/char/cerf_keyb.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,380 @@ ++/* ++ cerf_keyb.c: This is the end. Daniel is writing a device driver!!! ++*/ ++#include <linux/config.h> ++ ++#include <linux/spinlock.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/tty.h> ++#include <linux/mm.h> ++#include <linux/signal.h> ++#include <linux/init.h> ++#include <linux/kbd_ll.h> ++#include <linux/delay.h> ++#include <linux/random.h> ++#include <linux/poll.h> ++#include <linux/miscdevice.h> ++#include <linux/slab.h> ++#include <linux/kbd_kern.h> ++#include <linux/smp_lock.h> ++#include <linux/timer.h> ++ ++#include <asm/keyboard.h> ++#include <asm/bitops.h> ++#include <asm/uaccess.h> ++#include <asm/irq.h> ++#include <asm/system.h> ++ ++#include <asm/io.h> ++ ++#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"); ++} +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/char/clps711x_keyb.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,547 @@ ++/* ++ * drivers/char/clps711x_keyb.c ++ * ++ * Copyright (C) 2001 Thomas Gleixner <gleixner@autronix.de> ++ * ++ * 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 seperate 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 seperate 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 <linux/config.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/tty.h> ++#include <linux/tty_flip.h> ++#include <linux/mm.h> ++#include <linux/slab.h> ++#include <linux/ptrace.h> ++#include <linux/signal.h> ++#include <linux/timer.h> ++#include <linux/tqueue.h> ++#include <linux/random.h> ++#include <linux/ctype.h> ++#include <linux/init.h> ++#include <linux/kbd_ll.h> ++#include <linux/kbd_kern.h> ++#include <linux/delay.h> ++#include <linux/proc_fs.h> ++ ++#include <asm/bitops.h> ++#include <asm/keyboard.h> ++#include <asm/irq.h> ++#include <asm/hardware.h> ++#include <asm/uaccess.h> ++ ++#include <asm/io.h> ++#include <asm/system.h> ++ ++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"); ++ ++} +--- linux-2.4.25/drivers/char/console.c~2.4.25-vrs2.patch 2003-11-28 19:26:20.000000000 +0100 ++++ linux-2.4.25/drivers/char/console.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <rmk@arm.linux.org.uk>, July 1998 + */ + ++#define CONSOLE_WIP ++ + #include <linux/module.h> + #include <linux/sched.h> + #include <linux/tty.h> +@@ -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<NPAR; npar++) +- par[npar] = 0 ; +- npar = 0 ; +- vc_state = ESpalette; +- return; +- } else if (c=='R') { /* reset palette */ +- reset_palette(currcons); +- vc_state = ESnormal; +- } else +- vc_state = ESnormal; +- return; +- case ESpalette: +- if ( (c>='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<NPAR; npar++) ++ par[npar] = 0 ; ++ npar = 0 ; ++ vc_state = con_write_ctrl_ESpalette; ++ break; ++ case 'R': /* reset palette */ ++ reset_palette (currcons); ++ default: ++ vc_state = con_write_ctrl_ESnormal; ++ } ++ return 0; ++} ++ ++static int con_write_ctrl_ESpalette(int currcons, struct tty_struct *tty, unsigned int c) ++{ ++ if ( (c>='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<NPAR-1) { +- npar++; +- return; +- } else if (c>='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<NPAR-1) { ++ npar++; ++ return 0; ++ } else if (c>='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)) +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/char/ds1307.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/version.h> ++ ++#include <linux/kernel.h> ++#include <linux/poll.h> ++#include <linux/i2c.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/rtc.h> ++#include <linux/string.h> ++#include <linux/miscdevice.h> ++#include <linux/proc_fs.h> ++ ++#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; i<DS1307_RAM_SIZE; i++) ++ { ++ printk ("%02X ", buf[i]); ++ if( (i%8) == 7) printk ("\n"); ++ } ++ printk ("\n"); ++ } ++} ++ ++static void ++ds1307_enable_clock( int enable) ++{ ++ unsigned char buf[2], ad[1] = { 0 }; ++ struct i2c_msg msgs[2] = { ++ { ds1307_i2c_client->addr , 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; i<DS1307_RAM_SIZE; i++) ++ { ++ p += sprintf(p, "%02X ", ram[i]); ++ ++ if( (ram[i] < 32) || (ram[i]>126)) 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"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/char/ds1307.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/char/edb7211_keyb.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/config.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/tty.h> ++#include <linux/tty_flip.h> ++#include <linux/mm.h> ++#include <linux/slab.h> ++#include <linux/ptrace.h> ++#include <linux/signal.h> ++#include <linux/timer.h> ++#include <linux/tqueue.h> ++#include <linux/random.h> ++#include <linux/ctype.h> ++#include <linux/init.h> ++#include <linux/kbd_ll.h> ++#include <linux/kbd_kern.h> ++#include <linux/delay.h> ++ ++#include <asm/bitops.h> ++#include <asm/keyboard.h> ++#include <asm/irq.h> ++#include <asm/hardware.h> ++ ++#include <asm/io.h> ++#include <asm/system.h> ++ ++ ++/* ++ * 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); ++} ++ ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/char/epxa_wdt.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,178 @@ ++/* ++ * Watchdog driver for the Altera Excalibur EPXA1DB ++ * ++ * (c) Copyright 2003 Krzysztof Marianski <kmarian@konin.lm.pl> ++ * Based on SA11x0 Watchdog driver by Oleg Drokin <green@crimea.edu> ++ * ++ * 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 <kmarian@konin.lm.pl> ++ * ++ * 1/08/2003 Initial release ++ */ ++ ++#include <linux/module.h> ++#include <linux/config.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/fs.h> ++#include <linux/mm.h> ++#include <linux/miscdevice.h> ++#include <linux/watchdog.h> ++#include <linux/reboot.h> ++#include <linux/smp_lock.h> ++#include <linux/init.h> ++#include <asm/uaccess.h> ++#include <asm/hardware.h> ++ ++#define WATCHDOG00_TYPE (volatile unsigned int*) ++#include <asm/arch/watchdog00.h> ++#include <asm/bitops.h> ++ ++#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 <kmarian@konin.lm.pl>"); ++MODULE_DESCRIPTION("EPXA Watchdog Timer"); ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/char/gc_kbmap.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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}; ++ ++ ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/char/gc_keyb.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <tthaele@papenmeier.de> ++ * - Added Keyboard Sniffer on /dev/sio12 <minor = 12> ++ * - 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 ++ * <tthaele@papenmeier.de> 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 <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/kbd_ll.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/kbd_kern.h> ++ ++#include <asm/irq.h> ++#include <asm/hardware.h> ++#include <asm/keyboard.h> ++#include <linux/tqueue.h> ++#include <linux/proc_fs.h> ++#include <linux/pm.h> ++ ++#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 <tthaele@papenmeier.de>"; ++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<num;i++) { ++ while ((Ser4SSSR & SSSR_TNF) == 0); ++ tmp = pBuf[i]; ++ Ser4SSDR = (tmp << 8); ++ } ++ ++ // Throw away Echo ++ for (i=0;i<num;i++) { ++ while ((Ser4SSSR & SSSR_RNE) == 0); ++ tmp = Ser4SSDR; ++ } ++} ++ ++static unchar ReadSSPByte(void) ++{ ++ if (Ser4SSSR & SSSR_ROR) { ++ printk("%s() : Overrun\n", __FUNCTION__); ++ return 0; ++ } ++ ++ Ser4SSDR = 0x00; ++ ++ while ((Ser4SSSR & SSSR_RNE) == 0); ++ ++ return ((unchar) Ser4SSDR); ++} ++ ++static ulong read_SSP_response(int num) ++{ ++ int i; ++ ulong ret; ++ ++ // discard leading 0x00 and command echo 0 (command group value) ++ while (ReadSSPByte() == 0); ++ // discard command echo 1 (command code value) ++ ReadSSPByte(); ++ ++ // data from SMARTIO ++ // It assumes LSB first. ++ // NOTE:Some command uses MSB first order ++ ret = 0; ++ for (i=0;i<num;i++) { ++ ret |= ReadSSPByte() << (8*i); ++ } ++ ++ return ret; ++} ++ ++typedef struct t_SMARTIO_CMD { ++ unchar Group; ++ unchar Code; ++ unchar Opt[2]; ++} SMARTIO_CMD; ++ ++static SMARTIO_CMD RD_INT_CMD = { 0x83, 0x01, { 0x00, 0x00 } }; ++static SMARTIO_CMD RD_KBD_CMD = { 0x83, 0x02, { 0x00, 0x00 } }; ++static SMARTIO_CMD RD_ADC_CMD = { 0x83, 0x28, { 0x00, 0x00 } }; ++static SMARTIO_CMD RD_KPD_CMD = { 0x83, 0x04, { 0x00, 0x00 } }; ++ ++static volatile ushort adc_value; ++static volatile unchar kpd_value; ++static unsigned int kpd_timeout = 10000; // 10000 msec ++ ++static ulong kbd_int, kpd_int, adc_int; ++ ++static void smartio_interrupt_task(void *data); ++ ++static struct tq_struct tq_smartio = { ++ { NULL, NULL }, // struct list_head ++ 0, // unsigned long sync ++ smartio_interrupt_task, // void (*routine)(void *) ++ NULL, // void *data ++}; ++ ++DECLARE_WAIT_QUEUE_HEAD(smartio_queue); ++DECLARE_WAIT_QUEUE_HEAD(smartio_adc_queue); ++DECLARE_WAIT_QUEUE_HEAD(smartio_kpd_queue); ++DECLARE_WAIT_QUEUE_HEAD(keyboard_done_queue); ++DECLARE_WAIT_QUEUE_HEAD(sniffer_queue); ++ ++static spinlock_t smartio_busy_lock = SPIN_LOCK_UNLOCKED; ++static atomic_t smartio_busy = ATOMIC_INIT(0); ++ ++static int f_five_pressed = 0; ++static int f_seven_pressed = 0; ++//static int e_null_counter = 0; ++//static int f_null_counter = 0; ++//static int keydown = 0; ++static unchar previous_code = 0; ++//static int e0 = 0; ++ ++static void smartio_interrupt_task(void *arg) ++{ ++ unchar code; ++ unsigned long flags; ++ unchar dummy; ++ ++ spin_lock_irqsave(&smartio_busy_lock, flags); ++ if (atomic_read(&smartio_busy) == 1) { ++ spin_unlock_irqrestore(&smartio_busy_lock, flags); ++ queue_task(&tq_smartio, &tq_timer); ++ } ++ else { ++ atomic_set(&smartio_busy, 1); ++ spin_unlock_irqrestore(&smartio_busy_lock, flags); ++ } ++ ++ /* Read SMARTIO Interrupt Status to check which Interrupt is occurred ++ * and Clear SMARTIO Interrupt */ ++ send_SSP_msg((unchar *) &RD_INT_CMD, 2); ++ code = (unchar) (read_SSP_response(1) & 0xFF); ++ ++#ifdef CONFIG_VT ++ if (code & 0x04) { // Keyboard Interrupt ++ kbd_int++; ++ /* Read Scan code */ ++ send_SSP_msg((unchar *) &RD_KBD_CMD, 2); ++ code = (unchar) (read_SSP_response(1) & 0xFF); ++ dummy = code & 0x80; ++ if ((code == 0xE0) || (code == 0xE1) || (code == 0xF0)) { // combined code ++ if (code == 0xF0) { ++ if (!previous_code) { ++ code = 0xE0; ++ previous_code = 0xF0; ++ } else { ++ code = mf_two_kbdmap[code & 0x7F] | dummy; ++ previous_code = 0; ++ } ++ } else if (code == 0xE0) { ++ if (previous_code != 0) { ++ code = mf_two_kbdmap[code & 0x7F] | dummy; ++ previous_code = 0; ++ } else previous_code = code; ++ } else { // 0xE1 ++ if (!previous_code) { ++ code = mf_two_kbdmap[code &0x7F] | dummy; ++ previous_code = 0; ++ } else { ++ previous_code = code; ++ } ++ } ++ } else { ++ if (code == 0x03) { ++ f_five_pressed = 1; ++ } else if (code == 0x83) { ++ if (f_five_pressed != 0) { ++ f_five_pressed = 0; ++ code = 0x03; ++ } else if (f_seven_pressed == 0) { ++ f_seven_pressed = 1; ++ code = 2; ++ dummy = 0; ++ } else { ++ f_seven_pressed = 0; ++ code = 2; ++ } ++ } ++ previous_code = 0; ++ code &= 0x7F; ++ code = mf_two_kbdmap[code] | dummy; ++ } ++ sniffed_value = (ushort)code; ++ if (SNIFFER) wake_up_interruptible(&sniffer_queue); ++ if (SNIFFMODE == PASSIVE) { ++ handle_scancode( code, (code & 0x80) ? 0 : 1 ); ++ if (code & 0x80) { ++ wake_up_interruptible(&keyboard_done_queue); ++ mdelay(10); // this makes the whole thing a bit more stable ++ // keyboard handling can be corrupted when hitting ++ // thousands of keys like crazy. kbd_translate might catch up ++ // with irq routine? or there is simply a buffer overflow on ++ // the serial device? somehow it looses some key sequences. ++ // if a break code is lost or coruppted the keyboard starts ++ // to autorepeat like crazy and appears to hang. ++ // this needs further investigations! Thomas ++ kbd_press_flag = 0; ++ } ++ else ++ kbd_press_flag = 1; ++ } ++ code = 0; // prevent furthermore if ... then to react! ++ } ++#endif ++ // ADC resolution is 10bit (0x000 ~ 0x3FF) ++ if (code & 0x02) { // ADC Complete Interrupt ++ adc_int++; ++ send_SSP_msg((unchar *) &RD_ADC_CMD, 2); ++ adc_value = (ushort) (read_SSP_response(2) & 0x3FF); ++ wake_up_interruptible(&smartio_adc_queue); ++ } ++ ++ if (code & 0x08) { // Keypad interrupt ++ kpd_int++; ++ send_SSP_msg((unchar *) &RD_KPD_CMD, 2); ++ kpd_value = (unchar) (read_SSP_response(1) & 0xFF); ++ wake_up_interruptible(&smartio_kpd_queue); ++ } ++ ++ spin_lock_irqsave(&smartio_busy_lock, flags); ++ atomic_set(&smartio_busy, 0); ++ spin_unlock_irqrestore(&smartio_busy_lock, flags); ++ ++ enable_irq(ADS_AVR_IRQ); ++ ++ wake_up_interruptible(&smartio_queue); ++} ++ ++static void gc_sio_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++{ ++#ifdef CONFIG_VT ++ kbd_pt_regs = regs; ++#endif ++ ++ // *NOTE* ++ // ADS SMARTIO interrupt is cleared after reading interrupt status ++ // from smartio. ++ // disable SMARTIO IRQ here and re-enable at samrtio_bh. ++ // 11/13/00 Woojung ++ disable_irq(ADS_AVR_IRQ); ++ ++ queue_task(&tq_smartio, &tq_immediate); ++ mark_bh(IMMEDIATE_BH); ++} ++ ++char gc_kbd_unexpected_up(unsigned char keycode) ++{ ++ return 0; ++} ++ ++static inline void gc_sio_init(void) ++{ ++ GPDR |= (GPIO_GPIO10 | GPIO_GPIO12 | GPIO_GPIO13); // Output ++ GPDR &= ~GPIO_GPIO11; ++ ++ // Alternative Function ++ GAFR |= (GPIO_GPIO10 | GPIO_GPIO11 | GPIO_GPIO12 | GPIO_GPIO13); ++ ++ Ser4SSCR0 = 0xA707; ++ Ser4SSSR = SSSR_ROR; ++ Ser4SSCR1 = 0x0010; ++ Ser4SSCR0 = 0xA787; ++ ++ // Reset SMARTIO ++ ADS_AVR_REG &= 0xFE; ++ mdelay(300); // 10 mSec ++ ADS_AVR_REG |= 0x01; ++ mdelay(10); // 10 mSec ++ ++} ++ ++void __init gc_kbd_init_hw(void) ++{ ++ printk (KERN_INFO "Graphics Client keyboard driver v1.0\n"); ++ ++ k_setkeycode = gc_kbd_setkeycode; ++ k_getkeycode = gc_kbd_getkeycode; ++ k_translate = gc_kbd_translate; ++ k_unexpected_up = gc_kbd_unexpected_up; ++#ifdef CONFIG_MAGIC_SYSRQ ++ k_sysrq_key = 0x54; ++ /* sysrq table??? --rmk */ ++#endif ++ ++ gc_sio_init(); ++ ++ if (request_irq(ADS_AVR_IRQ,gc_sio_interrupt,0,"smartio", NULL) != 0) ++ printk("Could not allocate SMARTIO IRQ!\n"); ++ ++ sio_reset_flag = 1; ++} ++ ++/* SMARTIO ADC Interface */ ++#define SMARTIO_VERSION 0 ++#define SMARTIO_PORT_A 1 ++#define SMARTIO_PORT_B 2 ++#define SMARTIO_PORT_C 3 ++#define SMARTIO_PORT_D 4 ++#define SMARTIO_SELECT_OPTION 5 ++#define SMARTIO_BACKLITE 6 ++#define SMARTIO_KEYPAD 7 ++#define SMARTIO_ADC 8 ++#define SMARTIO_VEE_PWM 9 ++#define SMARTIO_SLEEP 11 ++#define SMARTIO_KBD_SNIFFER 12 ++ ++static SMARTIO_CMD CONV_ADC_CMD = { 0x80, 0x28, { 0x00, 0x00 } }; ++static SMARTIO_CMD READ_PORT_CMD = { 0x82, 0x00, { 0x00, 0x00 } }; ++ ++static SMARTIO_CMD READ_DEVVER_CMD = { 0x82, 0x05, { 0x00, 0x00 } }; ++static SMARTIO_CMD READ_DEVTYPE_CMD = { 0x82, 0x06, { 0x00, 0x00 } }; ++static SMARTIO_CMD READ_FWLEVEL_CMD = { 0x82, 0x07, { 0x00, 0x00 } }; ++ ++static int lock_smartio(unsigned long *flags) ++{ ++ spin_lock_irqsave(&smartio_busy_lock, *flags); ++ if (atomic_read(&smartio_busy) == 1) { ++ spin_unlock_irqrestore(&smartio_busy_lock, *flags); ++ interruptible_sleep_on(&smartio_queue); ++ } ++ else { ++ atomic_set(&smartio_busy, 1); ++ spin_unlock_irqrestore(&smartio_busy_lock, *flags); ++ } ++ ++ return 1; ++} ++ ++static int unlock_smartio(unsigned long *flags) ++{ ++ spin_lock_irqsave(&smartio_busy_lock, *flags); ++ atomic_set(&smartio_busy, 0); ++ spin_unlock_irqrestore(&smartio_busy_lock, *flags); ++ ++ return 1; ++} ++ ++static ushort read_sio_adc(int channel) ++{ ++ unsigned long flags; ++ ++ if ((channel < 0) || (channel > 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 ++ } ++ } ++} +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/char/gckeymap.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,262 @@ ++/* Do not edit this file! It was automatically generated by */ ++/* loadkeys --mktable defkeymap.map > defkeymap.c */ ++ ++#include <linux/types.h> ++#include <linux/keyboard.h> ++#include <linux/kd.h> ++ ++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; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/char/gckeymap.map 2004-03-31 17:15:09.000000000 +0200 +@@ -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 '�' +--- linux-2.4.25/drivers/char/generic_serial.c~2.4.25-vrs2.patch 2002-11-29 00:53:12.000000000 +0100 ++++ linux-2.4.25/drivers/char/generic_serial.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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) || +--- linux-2.4.25/drivers/char/keyboard.c~2.4.25-vrs2.patch 2003-11-28 19:26:20.000000000 +0100 ++++ linux-2.4.25/drivers/char/keyboard.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/config.h> +@@ -30,6 +34,7 @@ + #include <linux/tty_flip.h> + #include <linux/mm.h> + #include <linux/string.h> ++#include <linux/timer.h> + #include <linux/random.h> + #include <linux/init.h> + +@@ -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; +--- linux-2.4.25/drivers/char/mem.c~2.4.25-vrs2.patch 2003-11-28 19:26:20.000000000 +0100 ++++ linux-2.4.25/drivers/char/mem.c 2004-03-31 17:15:09.000000000 +0200 +@@ -27,9 +27,6 @@ + #include <asm/io.h> + #include <asm/pgalloc.h> + +-#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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/char/omaha-rtc.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <nico@cam.org> ++ * - 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 <cih@coventive.com> ++ * - Modify the bug setups RTC clock. ++ * ++ * 0.02 2001-02-27 Nils Faerber <nils@@kernelconcepts.de> ++ * - removed mktime(), added alarm irq clear ++ * ++ * 0.01 2000-10-01 Nils Faerber <nils@@kernelconcepts.de> ++ * - initial release ++ */ ++ ++#include <linux/module.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/string.h> ++#include <linux/init.h> ++#include <linux/poll.h> ++#include <linux/proc_fs.h> ++#include <asm/bitops.h> ++#include <asm/io.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <linux/rtc.h> ++#include <linux/mc146818rtc.h> ++ ++#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 <support@arm.com>"); ++MODULE_DESCRIPTION("Omaha Realtime Clock Driver (RTC)"); ++EXPORT_NO_SYMBOLS; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/char/omaha_wdt.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,193 @@ ++/* ++ * Watchdog driver for the Omaha ++ * (C) ARM Limited 2002. ++ * ++ * Based on sa1100_wdt.c ++ * ++ * (c) Copyright 2000 Oleg Drokin <green@crimea.edu> ++ * Based on SoftDog driver by Alan Cox <alan@redhat.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. ++ * ++ * 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 <green@crimea.edu> ++ * ++ * 27/11/2000 Initial release ++ */ ++ ++#include <linux/module.h> ++#include <linux/config.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/fs.h> ++#include <linux/mm.h> ++#include <linux/miscdevice.h> ++#include <linux/watchdog.h> ++#include <linux/reboot.h> ++#include <linux/smp_lock.h> ++#include <linux/init.h> ++#include <asm/uaccess.h> ++#include <asm/io.h> ++#include <asm/hardware.h> ++#include <asm/bitops.h> ++ ++#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); +--- linux-2.4.25/drivers/char/pcmcia/Config.in~2.4.25-vrs2.patch 2002-11-29 00:53:12.000000000 +0100 ++++ linux-2.4.25/drivers/char/pcmcia/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/char/pcmcia/memory_cs.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,214 @@ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/mtd.h> ++ ++#include <pcmcia/version.h> ++#include <pcmcia/cs_types.h> ++#include <pcmcia/cs.h> ++#include <pcmcia/cistpl.h> ++#include <pcmcia/ciscode.h> ++#include <pcmcia/ds.h> ++#include <pcmcia/cisreg.h> ++ ++#include <linux/mtd/map.h> ++#include <linux/mtd/mtd.h> ++ ++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"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/char/sa1100-rtc.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <nico@cam.org> ++ * - 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 <cih@coventive.com> ++ * - Modify the bug setups RTC clock. ++ * ++ * 0.02 2001-02-27 Nils Faerber <nils@@kernelconcepts.de> ++ * - removed mktime(), added alarm irq clear ++ * ++ * 0.01 2000-10-01 Nils Faerber <nils@@kernelconcepts.de> ++ * - initial release ++ */ ++ ++#include <linux/module.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/string.h> ++#include <linux/init.h> ++#include <linux/poll.h> ++#include <linux/proc_fs.h> ++#include <asm/bitops.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <linux/rtc.h> ++ ++#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 <nils@@kernelconcepts.de>"); ++MODULE_DESCRIPTION("SA1100 Realtime Clock Driver (RTC)"); ++EXPORT_NO_SYMBOLS; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/char/sa1100_wdt.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,150 @@ ++/* ++ * Watchdog driver for the SA11x0 ++ * ++ * (c) Copyright 2000 Oleg Drokin <green@crimea.edu> ++ * Based on SoftDog driver by Alan Cox <alan@redhat.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. ++ * ++ * 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 <green@crimea.edu> ++ * ++ * 27/11/2000 Initial release ++ */ ++ ++#include <linux/module.h> ++#include <linux/config.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/fs.h> ++#include <linux/mm.h> ++#include <linux/miscdevice.h> ++#include <linux/watchdog.h> ++#include <linux/reboot.h> ++#include <linux/smp_lock.h> ++#include <linux/init.h> ++#include <asm/uaccess.h> ++#include <asm/hardware.h> ++#include <asm/bitops.h> ++ ++#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); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/char/sa1111_keyb.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,1153 @@ ++/* ++ * SA1111 PS/2 keyboard/mouse driver ++ * ++ * 2000 by VASARA RESEARCH INC. ++ * ++ * Changelog: ++ * Jun.xx,2000: Kunihiko IMAI <imai@vasara.co.jp> ++ * Port to 2.4.0test1-ac19-rmk1-np1 ++ * Apr.17,2000: Takafumi Kawana <kawana@pro.or.jp> ++ * 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 <jem@iki.fi> 1998-10-08. ++ * ++ * Code fixes to handle mouse ACKs properly. ++ * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29. ++ * ++ */ ++#include <linux/config.h> ++#include <linux/spinlock.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/tty.h> ++#include <linux/mm.h> ++#include <linux/signal.h> ++#include <linux/init.h> ++#include <linux/kbd_ll.h> ++#include <linux/delay.h> ++#include <linux/random.h> ++#include <linux/poll.h> ++#include <linux/miscdevice.h> ++#include <linux/slab.h> ++#include <linux/kbd_kern.h> ++#include <linux/ioport.h> ++ ++#include <asm/hardware.h> ++#include <asm/bitops.h> ++#include <asm/uaccess.h> ++#include <asm/irq.h> ++#include <asm/system.h> ++ ++#include <asm/io.h> ++ ++/* Some configuration switches are present in the include file... */ ++ ++#include <linux/pc_keyb.h> ++#include <asm/keyboard.h> ++#include <asm/hardware/sa1111.h> ++ ++#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 */ +--- linux-2.4.25/drivers/char/serial.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/char/serial.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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. + */ +--- linux-2.4.25/drivers/char/serial_21285.c~2.4.25-vrs2.patch ++++ linux-2.4.25/drivers/char/serial_21285.c +-/* +- * 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 <linux/config.h> +-#include <linux/module.h> +-#include <linux/errno.h> +-#include <linux/signal.h> +-#include <linux/sched.h> +-#include <linux/interrupt.h> +-#include <linux/tty.h> +-#include <linux/tty_flip.h> +-#include <linux/serial.h> +-#include <linux/major.h> +-#include <linux/ptrace.h> +-#include <linux/ioport.h> +-#include <linux/mm.h> +-#include <linux/slab.h> +-#include <linux/init.h> +-#include <linux/console.h> +- +-#include <asm/io.h> +-#include <asm/irq.h> +-#include <asm/uaccess.h> +-#include <asm/dec21285.h> +-#include <asm/hardware.h> +- +-#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; +--- linux-2.4.25/drivers/char/serial_amba.c~2.4.25-vrs2.patch ++++ linux-2.4.25/drivers/char/serial_amba.c +-/* +- * 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 <linux/config.h> +-#include <linux/module.h> +-#include <linux/errno.h> +-#include <linux/signal.h> +-#include <linux/sched.h> +-#include <linux/interrupt.h> +-#include <linux/tty.h> +-#include <linux/tty_flip.h> +-#include <linux/major.h> +-#include <linux/string.h> +-#include <linux/fcntl.h> +-#include <linux/ptrace.h> +-#include <linux/ioport.h> +-#include <linux/mm.h> +-#include <linux/slab.h> +-#include <linux/init.h> +-#include <linux/circ_buf.h> +-#include <linux/serial.h> +-#include <linux/console.h> +-#include <linux/sysrq.h> +- +-#include <asm/system.h> +-#include <asm/io.h> +-#include <asm/irq.h> +-#include <asm/uaccess.h> +-#include <asm/bitops.h> +- +-#include <asm/hardware/serial_amba.h> +- +-#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; +--- linux-2.4.25/drivers/char/tty_io.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/char/tty_io.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/char/wdt285.c~2.4.25-vrs2.patch 2003-06-13 16:51:33.000000000 +0200 ++++ linux-2.4.25/drivers/char/wdt285.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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(); +--- linux-2.4.25/drivers/char/wdt977.c~2.4.25-vrs2.patch 2002-11-29 00:53:12.000000000 +0100 ++++ linux-2.4.25/drivers/char/wdt977.c 2004-03-31 17:15:09.000000000 +0200 +@@ -27,6 +27,7 @@ + #include <asm/io.h> + #include <asm/system.h> + #include <asm/mach-types.h> ++#include <asm/uaccess.h> + + #define WATCHDOG_MINOR 130 + +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/cpufreq/Kconfig 2004-03-31 17:15:09.000000000 +0200 +@@ -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. +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/cpufreq/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/cpufreq/cpufreq.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,720 @@ ++/* ++ * linux/kernel/cpufreq.c ++ * ++ * Copyright (C) 2001 Russell King ++ * (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/notifier.h> ++#include <linux/cpufreq.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/spinlock.h> ++#include <linux/slab.h> ++ ++#include <asm/semaphore.h> ++/** ++ * 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; i<NR_CPUS; i++) { ++ struct cpufreq_policy *policy = cpufreq_cpu_get(i); ++ if (!policy) ++ goto done; ++ down(&policy->lock); ++ ++ 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<NR_CPUS; i++) { ++ if (cpu_online(i)) ++ cpufreq_add_dev(i); ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(cpufreq_register_driver); ++ ++ ++/** ++ * cpufreq_unregister_driver - unregister the current CPUFreq driver ++ * ++ * Unregister the current CPUFreq driver. Only call this if you have ++ * the right to do so, i.e. if you have succeeded in initialising before! ++ * Returns zero if successful, and -EINVAL if the cpufreq_driver is ++ * currently not initialised. ++ */ ++int cpufreq_unregister_driver(struct cpufreq_driver *driver) ++{ ++ unsigned long flags; ++ unsigned int i; ++ ++ if (!cpufreq_driver || (driver != cpufreq_driver)) ++ return -EINVAL; ++ ++ for (i=0; i<NR_CPUS; i++) { ++ if (cpu_online(i)) ++ cpufreq_remove_dev(i); ++ } ++ ++ spin_lock_irqsave(&cpufreq_driver_lock, flags); ++ cpufreq_driver = NULL; ++ spin_unlock_irqrestore(&cpufreq_driver_lock, flags); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(cpufreq_unregister_driver); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/cpufreq/freq_table.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,203 @@ ++/* ++ * linux/drivers/cpufreq/freq_table.c ++ * ++ * Copyright (C) 2002 - 2003 Dominik Brodowski ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/cpufreq.h> ++ ++/********************************************************************* ++ * 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 <linux@brodo.de>"); ++MODULE_DESCRIPTION ("CPUfreq frequency table helpers"); ++MODULE_LICENSE ("GPL"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/cpufreq/proc_intf.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,244 @@ ++/* ++ * linux/drivers/cpufreq/proc_intf.c ++ * ++ * Copyright (C) 2002 - 2003 Dominik Brodowski ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/cpufreq.h> ++#include <linux/ctype.h> ++#include <linux/proc_fs.h> ++#include <asm/uaccess.h> ++ ++ ++/** ++ * 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;i<NR_CPUS;i++) { ++ if (!cpu_online(i)) ++ continue; ++ ++ if (cpufreq_get_policy(&policy, i)) ++ continue; ++ ++ if (!policy.cpuinfo.max_freq) ++ continue; ++ ++ min_pctg = (policy.min * 100) / policy.cpuinfo.max_freq; ++ max_pctg = (policy.max * 100) / policy.cpuinfo.max_freq; ++ ++ p += sprintf(p, "CPU%3d %9d kHz (%3d %%) - %9d kHz (%3d %%) - ", ++ i , policy.min, min_pctg, policy.max, max_pctg); ++ switch (policy.policy) { ++ case CPUFREQ_POLICY_POWERSAVE: ++ p += sprintf(p, "powersave\n"); ++ break; ++ case CPUFREQ_POLICY_PERFORMANCE: ++ p += sprintf(p, "performance\n"); ++ break; ++ case CPUFREQ_POLICY_GOVERNOR: ++ p += snprintf(p, CPUFREQ_NAME_LEN, "%s\n", policy.governor->name); ++ 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; i<NR_CPUS; i++) ++ { ++ policy.cpu = i; ++ if (cpu_online(i)) ++ cpufreq_set_policy(&policy); ++ } ++ } ++ else ++ cpufreq_set_policy(&policy); ++ ++ return count; ++} ++ ++ ++/** ++ * cpufreq_proc_init - add "cpufreq" to the /proc root directory ++ * ++ * This function adds "cpufreq" to the /proc root directory. ++ */ ++static int __init cpufreq_proc_init (void) ++{ ++ struct proc_dir_entry *entry = NULL; ++ ++ /* are these acceptable values? */ ++ entry = create_proc_entry("cpufreq", S_IFREG|S_IRUGO|S_IWUSR, ++ &proc_root); ++ ++ if (!entry) { ++ printk(KERN_ERR "unable to create /proc/cpufreq entry\n"); ++ return -EIO; ++ } else { ++ entry->read_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 <linux@brodo.de>"); ++MODULE_DESCRIPTION ("CPUfreq /proc/cpufreq interface"); ++MODULE_LICENSE ("GPL"); ++ ++module_init(cpufreq_proc_init); ++module_exit(cpufreq_proc_exit); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/cpufreq/userspace.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,591 @@ ++/* ++ * drivers/cpufreq/userspace.c ++ * ++ * Copyright (C) 2001 Russell King ++ * (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de> ++ * ++ * $Id$ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/smp.h> ++#include <linux/init.h> ++#include <linux/spinlock.h> ++#include <linux/interrupt.h> ++#include <linux/ctype.h> ++#include <linux/cpufreq.h> ++#include <linux/sysctl.h> ++#include <linux/types.h> ++#include <linux/fs.h> ++#include <linux/sysfs.h> ++ ++#include <asm/uaccess.h> ++ ++#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 <linux@brodo.de>, Russell King <rmk@arm.linux.org.uk>"); ++MODULE_DESCRIPTION ("CPUfreq policy governor 'userspace'"); ++MODULE_LICENSE ("GPL"); ++ ++module_init(cpufreq_gov_userspace_init); ++module_exit(cpufreq_gov_userspace_exit); +--- linux-2.4.25/drivers/i2c/Config.in~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/i2c/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/i2c/Makefile~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/i2c/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +- +--- linux-2.4.25/drivers/i2c/i2c-algo-bit.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/i2c/i2c-algo-bit.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <simon@tk.uni-linz.ac.at>"); + 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); +--- linux-2.4.25/drivers/i2c/i2c-algo-pcf.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/i2c/i2c-algo-pcf.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <hb@spacetec.no>"); + 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); +--- linux-2.4.25/drivers/i2c/i2c-core.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/i2c/i2c-core.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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;j<I2C_DRIVER_MAX;j++) +- if (drivers[j]!=NULL && ++ if (drivers[j]!=NULL && + (drivers[j]->flags&(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;j<I2C_CLIENT_MAX;j++) { ++ for (j=0;j<I2C_CLIENT_MAX;j++) { + struct i2c_client *client = adap->clients[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 <simon@tk.uni-linz.ac.at>"); + 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); +--- linux-2.4.25/drivers/i2c/i2c-dev.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/i2c/i2c-dev.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <frodol@dds.nl> +@@ -25,7 +25,7 @@ + + /* The I2C_RDWR ioctl code is written by Kolja Waschk <waschk@telos.de> */ + +-/* The devfs code is contributed by Philipp Matthias Hahn ++/* The devfs code is contributed by Philipp Matthias Hahn + <pmhahn@titan.lahn.de> */ + + /* $Id$ */ +@@ -50,19 +50,14 @@ + #include <linux/i2c.h> + #include <linux/i2c-dev.h> + +-#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 <frodol@dds.nl> and Simon G. Vogl <simon@tk.uni-linz.ac.at>"); + 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); +--- linux-2.4.25/drivers/i2c/i2c-elektor.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/i2c/i2c-elektor.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <hb@spacetec.no>"); + 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); +--- linux-2.4.25/drivers/i2c/i2c-elv.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/i2c/i2c-elv.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <simon@tk.uni-linz.ac.at>"); + 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); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/i2c/i2c-frodo.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,114 @@ ++ ++/* ++ * linux/drivers/i2c/i2c-frodo.c ++ * ++ * Author: Abraham van der Merwe <abraham@2d3d.co.za> ++ * ++ * 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 <linux/config.h> ++#include <linux/version.h> ++#include <linux/module.h> ++ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++ ++#include <asm/hardware.h> ++ ++#include <linux/i2c.h> ++#include <linux/i2c-algo-bit.h> ++ ++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 <abraham@2d3d.co.za>"); ++MODULE_DESCRIPTION ("I2C-Bus adapter routines for Frodo"); ++MODULE_LICENSE ("GPL"); ++EXPORT_NO_SYMBOLS; ++ ++module_init (i2c_frodo_init); ++module_exit (i2c_frodo_exit); ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/i2c/i2c-guide.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/kernel.h> ++#include <linux/ioport.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/string.h> /* for 2.0 kernels to get NULL */ ++#include <asm/errno.h> /* for 2.0 kernels to get ENODEV */ ++#include <asm/io.h> ++ ++#include <asm/hardware/cs89712.h> // io operation ep_writel() ++#include <asm/hardware/clps7111.h> // io operation clps_writel() ++#include <asm/arch-clps711x/hardware.h> // io operation clps_writel() ++ ++#include <linux/i2c.h> ++#include <linux/i2c-algo-bit.h> ++ ++/* ----- 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 <tsong@iders.ca>"); ++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); ++*/ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/i2c/i2c-omaha.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <linux/version.h> ++#include <linux/init.h> ++#include <asm/irq.h> ++#include <asm/io.h> ++#include <asm/uaccess.h> ++#include <linux/ioport.h> ++#include <linux/errno.h> ++#include <linux/sched.h> ++ ++#include <linux/i2c.h> ++#include <linux/i2c-algo-bit.h> ++ ++#include <asm/io.h> ++#include <asm/hardware.h> ++ ++/* ----- 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 <support@arm.com>"); ++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); ++ ++ +--- linux-2.4.25/drivers/i2c/i2c-philips-par.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/i2c/i2c-philips-par.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <kmalkki@cc.hut.fi> and even + Frodo Looijaard <frodol@dds.nl> */ +@@ -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); +--- linux-2.4.25/drivers/i2c/i2c-velleman.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/i2c/i2c-velleman.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <simon@tk.uni-linz.ac.at>"); + 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); +--- linux-2.4.25/drivers/ide/Config.in~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/ide/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -106,6 +106,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 +--- linux-2.4.25/drivers/ide/arm/Makefile~2.4.25-vrs2.patch 2003-06-13 16:51:33.000000000 +0200 ++++ linux-2.4.25/drivers/ide/arm/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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../ + +--- linux-2.4.25/drivers/ide/arm/icside.c~2.4.25-vrs2.patch 2003-06-13 16:51:33.000000000 +0200 ++++ linux-2.4.25/drivers/ide/arm/icside.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <asm/ecard.h> + #include <asm/io.h> + +-#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; + +- outb(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1); +- outb(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2); ++ state->enabled = 1; ++ ++ 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; + +- inb(ide_base_port + ICS_ARCIN_V6_INTROFFSET_1); +- inb(ide_base_port + ICS_ARCIN_V6_INTROFFSET_2); ++ state->enabled = 0; ++ ++ 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; ++ BUG_ON(hwif->sg_dma_active); + +- 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); ++ if (rq->cmd == IDE_DRIVE_TASKFILE) { ++ ide_task_t *args = rq->special; + +- return pci_map_sg(NULL, sg, nents, hwif->sg_dma_direction); +-} ++ if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE) ++ hwif->sg_dma_direction = PCI_DMA_FROMDEVICE; ++ else ++ hwif->sg_dma_direction = PCI_DMA_TODEVICE; + +-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); +-} ++ 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; + +-/* 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; ++ bh = rq->bh; ++ do { ++ unsigned long lastend; + +- pci_unmap_sg(NULL, sg, nents, HWIF(drive)->sg_dma_direction); ++ 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); ++ } ++ ++ nents = pci_map_sg(NULL, sg, nents, hwif->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; + +- if (drive->drive_data && +- ide_config_drive_speed(drive, (u8) xfer_mode) == 0) +- func = ide_dma_on; ++ drive->drive_data = cycle_time; ++ ++ 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); + } + +-int icside_dma_check(ide_drive_t *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; ++} ++ ++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)); + +- /* Route the DMA signals to +- * to the correct interface. ++ ide_build_sglist(drive, rq); ++ ++ /* ++ * 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->ide_dma_check = icside_dma_check; +- hwif->ide_dma_host_off = icside_dma_host_off; ++ 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_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); + +-#ifdef CONFIG_BLK_DEV_IDEDMA_ICS +- if (ec->dma != NO_DMA) { +- if (request_dma(ec->dma, hwif->name)) +- goto no_dma; ++ if (!hwif || !mate) ++ return -ENODEV; + +- 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); + } +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/ide/arm/rstation-ide.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/slab.h> ++#include <linux/blkdev.h> ++#include <linux/errno.h> ++#include <linux/ide.h> ++#include <linux/init.h> ++ ++#include <asm/hardware/iomd.h> ++#include <asm/mach-types.h> ++#include <asm/io.h> ++ ++#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); ++} +--- linux-2.4.25/drivers/ide/ide-probe.c~2.4.25-vrs2.patch 2003-11-28 19:26:20.000000000 +0100 ++++ linux-2.4.25/drivers/ide/ide-probe.c 2004-03-31 17:15:09.000000000 +0200 +@@ -1296,11 +1296,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]))) { +@@ -1318,7 +1318,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; +--- linux-2.4.25/drivers/ide/ide-proc.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/ide/ide-proc.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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); +--- linux-2.4.25/drivers/ide/ide.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/ide/ide.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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); +--- linux-2.4.25/drivers/ide/pci/Makefile~2.4.25-vrs2.patch 2003-11-28 19:26:20.000000000 +0100 ++++ linux-2.4.25/drivers/ide/pci/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -15,7 +15,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 +--- linux-2.4.25/drivers/ide/pci/sl82c105.c~2.4.25-vrs2.patch 2003-06-13 16:51:33.000000000 +0200 ++++ linux-2.4.25/drivers/ide/pci/sl82c105.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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. +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/ide/pci/sl82c105.c.2419 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/config.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/timer.h> ++#include <linux/mm.h> ++#include <linux/ioport.h> ++#include <linux/interrupt.h> ++#include <linux/blkdev.h> ++#include <linux/hdreg.h> ++#include <linux/pci.h> ++#include <linux/ide.h> ++ ++#include <asm/io.h> ++#include <asm/dma.h> ++ ++#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; ++} ++ +--- linux-2.4.25/drivers/input/Config.in~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/input/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/input/Makefile~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/input/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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. +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/input/mx1ts.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/smp.h> ++#include <linux/smp_lock.h> ++#include <linux/sched.h> ++#include <linux/completion.h> ++#include <linux/delay.h> ++#include <linux/string.h> ++#include <linux/pm.h> ++ ++#include <asm/dma.h> ++ ++#include <linux/input.h> ++ ++#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 <jonm@bluemug.com>"); ++MODULE_DESCRIPTION("MX1 touchscreen driver"); ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/input/mx1ts.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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) +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/l3/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/l3/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/l3/l3-algo-bit.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/errno.h> ++#include <linux/sched.h> ++#include <linux/l3/l3.h> ++#include <linux/l3/algo-bit.h> ++ ++#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); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/l3/l3-bit-sa1100.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/ioport.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/i2c-algo-bit.h> ++#include <linux/l3/algo-bit.h> ++ ++#include <asm/system.h> ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++#include <asm/arch/assabet.h> ++ ++#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); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/l3/l3-core.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/config.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/slab.h> ++#include <linux/proc_fs.h> ++#include <linux/kmod.h> ++#include <linux/init.h> ++#include <linux/l3/l3.h> ++ ++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); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/l3/l3-sa1111.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/errno.h> ++#include <linux/l3/l3.h> ++ ++#include <asm/hardware.h> ++#include <asm/semaphore.h> ++#include <asm/mach-types.h> ++#include <asm/arch/assabet.h> ++#include <asm/hardware/sa1111.h> ++ ++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); +--- linux-2.4.25/drivers/media/video/Config.in~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/media/video/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -52,5 +52,8 @@ + if [ "$CONFIG_EXPERIMENTAL" = "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 +--- linux-2.4.25/drivers/media/video/Makefile~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/media/video/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/media/video/cyberpro.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/videodev.h> ++#include <linux/video_decoder.h> ++#include <linux/mm.h> ++#include <linux/i2c-old.h> ++#include <linux/spinlock.h> ++#include <linux/slab.h> ++#include <linux/vmalloc.h> ++#include <linux/delay.h> ++#include <linux/sched.h> ++#include <linux/kmod.h> ++#include <linux/pci.h> ++#include <linux/init.h> ++ ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/pgtable.h> ++#include <asm/pgalloc.h> ++ ++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); ++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 +--- linux-2.4.25/drivers/media/video/i2c-old.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/media/video/i2c-old.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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<<i)) ? i2c_one(bus) : i2c_zero(bus); +@@ -354,9 +363,9 @@ + { + int i; + unsigned char data=0; +- ++ + I2C_SET(bus,0,1); +- for (i=7; i>=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); + +--- linux-2.4.25/drivers/media/video/saa7111.c~2.4.25-vrs2.patch 2001-09-30 21:26:06.000000000 +0200 ++++ linux-2.4.25/drivers/media/video/saa7111.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/config.h> + #include <linux/init.h> ++#include <linux/module.h> + #include <linux/delay.h> + #include <linux/errno.h> + #include <linux/fs.h> +@@ -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 */ +--- linux-2.4.25/drivers/message/i2o/i2o_core.c~2.4.25-vrs2.patch 2003-06-13 16:51:34.000000000 +0200 ++++ linux-2.4.25/drivers/message/i2o/i2o_core.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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); + +--- linux-2.4.25/drivers/message/i2o/i2o_pci.c~2.4.25-vrs2.patch 2002-11-29 00:53:13.000000000 +0100 ++++ linux-2.4.25/drivers/message/i2o/i2o_pci.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 ++ +--- linux-2.4.25/drivers/misc/Config.in~2.4.25-vrs2.patch 1999-12-26 00:04:56.000000000 +0100 ++++ linux-2.4.25/drivers/misc/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/misc/Makefile~2.4.25-vrs2.patch 2000-12-29 23:07:22.000000000 +0100 ++++ linux-2.4.25/drivers/misc/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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: +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/misc/mcp-core.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/errno.h> ++#include <linux/smp.h> ++ ++#include <asm/dma.h> ++#include <asm/system.h> ++ ++#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 <rmk@arm.linux.org.uk>"); ++MODULE_DESCRIPTION("Core multimedia communications port driver"); ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/misc/mcp-sa1100.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/delay.h> ++#include <linux/spinlock.h> ++ ++#include <asm/dma.h> ++#include <asm/hardware.h> ++#include <asm/system.h> ++ ++#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 <rmk@arm.linux.org.uk>"); ++MODULE_DESCRIPTION("SA11x0 multimedia communications port driver"); ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/misc/mcp.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/misc/ucb1x00-audio.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/fs.h> ++#include <linux/errno.h> ++#include <linux/slab.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++#include <linux/list.h> ++ ++#include <asm/dma.h> ++#include <asm/hardware.h> ++#include <asm/semaphore.h> ++#include <asm/uaccess.h> ++ ++#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 <rmk@arm.linux.org.uk>"); ++MODULE_DESCRIPTION("UCB1x00 telecom/audio driver"); ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/misc/ucb1x00-core.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/errno.h> ++#include <linux/interrupt.h> ++#include <linux/pm.h> ++ ++#include <asm/dma.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/mach-types.h> ++#include <asm/arch/shannon.h> ++ ++#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 <rmk@arm.linux.org.uk>"); ++MODULE_DESCRIPTION("UCB1x00 core driver"); ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/misc/ucb1x00-ts.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <jco@ict.es> : ++ * ++ * 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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/smp.h> ++#include <linux/smp_lock.h> ++#include <linux/sched.h> ++#include <linux/completion.h> ++#include <linux/delay.h> ++#include <linux/string.h> ++#include <linux/pm.h> ++ ++#include <asm/dma.h> ++#include <asm/semaphore.h> ++ ++#include "ucb1x00.h" ++ ++/* ++ * Define this if you want the UCB1x00 stuff to talk to the input layer ++ */ ++#undef USE_INPUT ++ ++#ifndef USE_INPUT ++ ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/poll.h> ++ ++/* ++ * 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 <linux/input.h> ++ ++#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 <rmk@arm.linux.org.uk>"); ++MODULE_DESCRIPTION("UCB1x00 touchscreen driver"); ++MODULE_LICENSE("GPL"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/misc/ucb1x00.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/mtd/chips/cfi_probe.c~2.4.25-vrs2.patch 2003-06-13 16:51:34.000000000 +0200 ++++ linux-2.4.25/drivers/mtd/chips/cfi_probe.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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; + } + +--- linux-2.4.25/drivers/mtd/devices/Config.in~2.4.25-vrs2.patch 2003-06-13 16:51:34.000000000 +0200 ++++ linux-2.4.25/drivers/mtd/devices/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/mtd/devices/Makefile~2.4.25-vrs2.patch 2002-11-29 00:53:13.000000000 +0100 ++++ linux-2.4.25/drivers/mtd/devices/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/mtd/devices/syncflash.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,615 @@ ++/* ++ * MTD driver for Micron SyncFlash flash memory. ++ * ++ * Author: Jon McClintock <jonm@bluemug.com> ++ * ++ * Based loosely upon the LART flash driver, authored by Abraham vd Merwe ++ * <abraham@2d3d.co.za>. ++ * ++ * 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 <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/version.h> ++#include <linux/errno.h> ++#include <linux/mtd/mtd.h> ++#include <asm/io.h> ++ ++/* partition support */ ++#define HAVE_PARTITIONS ++#ifdef HAVE_PARTITIONS ++#include <linux/mtd/partitions.h> ++#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 <jonm@bluemug.com>"); ++MODULE_DESCRIPTION("MTD driver for Micron MT28S4M16LC SyncFlash on MX1ADS board"); ++ ++ +--- linux-2.4.25/drivers/mtd/maps/Config.in~2.4.25-vrs2.patch 2003-06-13 16:51:34.000000000 +0200 ++++ linux-2.4.25/drivers/mtd/maps/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/mtd/maps/Makefile~2.4.25-vrs2.patch 2003-06-13 16:51:34.000000000 +0200 ++++ linux-2.4.25/drivers/mtd/maps/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -3,11 +3,7 @@ + # + # $Id$ + +-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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/mtd/maps/epxa-flash.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,234 @@ ++/* ++ * Flash memory access on EPXA based devices ++ * ++ * (C) 2000 Nicolas Pitre <nico@cam.org> ++ * Copyright (C) 2001 Altera Corporation ++ * Copyright (C) 2001 Red Hat, Inc. ++ * ++ * $Id$ ++ * ++ * 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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <asm/io.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/map.h> ++#include <linux/mtd/partitions.h> ++ ++#include <asm/hardware.h> ++#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; i<mymtd->numeraseregions;i++){ ++ int j; ++ for(j=0;j<mymtd->eraseregions[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"); +--- linux-2.4.25/drivers/mtd/maps/epxa10db-flash.c~2.4.25-vrs2.patch ++++ linux-2.4.25/drivers/mtd/maps/epxa10db-flash.c +-/* +- * Flash memory access on EPXA based devices +- * +- * (C) 2000 Nicolas Pitre <nico@cam.org> +- * Copyright (C) 2001 Altera Corporation +- * Copyright (C) 2001 Red Hat, Inc. +- * +- * $Id$ +- * +- * 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 <linux/config.h> +-#include <linux/module.h> +-#include <linux/types.h> +-#include <linux/kernel.h> +-#include <asm/io.h> +-#include <linux/mtd/mtd.h> +-#include <linux/mtd/map.h> +-#include <linux/mtd/partitions.h> +- +-#include <asm/hardware.h> +-#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; i<mymtd->numeraseregions;i++){ +- int j; +- for(j=0;j<mymtd->eraseregions[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"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/mtd/maps/neponset-flash.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,109 @@ ++/* ++ * Flash memory access on SA11x0 based devices ++ * ++ * (C) 2000 Nicolas Pitre <nico@cam.org> ++ * ++ * $Id$ ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++ ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/map.h> ++#include <linux/mtd/partitions.h> ++ ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/arch/assabet.h> ++ ++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); +--- linux-2.4.25/drivers/mtd/maps/sa1100-flash.c~2.4.25-vrs2.patch 2003-06-13 16:51:34.000000000 +0200 ++++ linux-2.4.25/drivers/mtd/maps/sa1100-flash.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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; +--- linux-2.4.25/drivers/net/Config.in~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/net/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/net/Makefile~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/net/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -243,6 +243,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 +@@ -267,4 +268,3 @@ + + rcpci.o: $(rcpci-objs) + $(LD) -r -o $@ $(rcpci-objs) +- +--- linux-2.4.25/drivers/net/am79c961a.c~2.4.25-vrs2.patch 2003-06-13 16:51:34.000000000 +0200 ++++ linux-2.4.25/drivers/net/am79c961a.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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)); ++ 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_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; + +--- linux-2.4.25/drivers/net/am79c961a.h~2.4.25-vrs2.patch 2000-09-19 00:15:22.000000000 +0200 ++++ linux-2.4.25/drivers/net/am79c961a.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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); +--- linux-2.4.25/drivers/net/cirrus.c~2.4.25-vrs2.patch 2003-06-13 16:51:34.000000000 +0200 ++++ linux-2.4.25/drivers/net/cirrus.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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); +--- linux-2.4.25/drivers/net/cs89x0.c~2.4.25-vrs2.patch 2003-08-25 13:44:42.000000000 +0200 ++++ linux-2.4.25/drivers/net/cs89x0.c 2004-03-31 17:15:09.000000000 +0200 +@@ -115,6 +115,7 @@ + + */ + ++#include <linux/config.h> + #include <linux/kernel.h> + #include <linux/sched.h> + #include <linux/types.h> +@@ -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 +--- linux-2.4.25/drivers/net/ether00.c~2.4.25-vrs2.patch 2003-06-13 16:51:34.000000000 +0200 ++++ linux-2.4.25/drivers/net/ether00.c 2004-03-31 17:15:09.000000000 +0200 +@@ -38,6 +38,7 @@ + #include <asm/arch/ether00.h> + #include <asm/arch/tdkphy.h> + ++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;i<MAX_MTD_DEVICES;i++){ +- mymtd=get_mtd_device(NULL,i); +- if(!mymtd||!strcmp(mymtd->name,"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; + } +--- linux-2.4.25/drivers/net/irda/Config.in~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/net/irda/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/net/irda/sa1100_ir.c~2.4.25-vrs2.patch 2002-08-03 02:39:44.000000000 +0200 ++++ linux-2.4.25/drivers/net/irda/sa1100_ir.c 2004-03-31 17:15:09.000000000 +0200 +@@ -38,11 +38,7 @@ + + #include <asm/arch/assabet.h> + +-#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); +--- linux-2.4.25/drivers/net/irda/w83977af_ir.c~2.4.25-vrs2.patch 2002-11-29 00:53:13.000000000 +0100 ++++ linux-2.4.25/drivers/net/irda/w83977af_ir.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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; +--- linux-2.4.25/drivers/net/smc9194.c~2.4.25-vrs2.patch 2003-06-13 16:51:35.000000000 +0200 ++++ linux-2.4.25/drivers/net/smc9194.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/config.h> + #include <linux/module.h> + #include <linux/version.h> + #include <linux/kernel.h> +@@ -69,16 +78,26 @@ + #include <linux/in.h> + #include <linux/slab.h> + #include <linux/string.h> ++#include <linux/delay.h> + #include <linux/init.h> + #include <linux/crc32.h> +-#include <asm/bitops.h> +-#include <asm/io.h> + #include <linux/errno.h> ++#include <linux/ethtool.h> + + #include <linux/netdevice.h> + #include <linux/etherdevice.h> + #include <linux/skbuff.h> + ++#include <asm/bitops.h> ++#include <asm/irq.h> ++#include <asm/io.h> ++#include <asm/uaccess.h> ++ ++#ifdef CONFIG_ARCH_SA1100 ++#include <asm/hardware.h> ++#include <asm/arch/assabet.h> ++#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 + /* +- . Function: smc_reset( int ioaddr ) ++ * 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 ++ ++/* ++ . 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; + +- trials = 3; +- while ( trials-- ) { +- dev->irq = smc_findirq( ioaddr ); +- if ( dev->irq ) +- break; +- /* kick the card and try again */ +- smc_reset( ioaddr ); ++ case IF_PORT_AUI: ++ smc->port = PORT_AUI; ++ break; ++ ++ 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; +- +- for ( i = 0; i < lines ; i ++ ) { +- int cur; ++ struct smc_local *smc = dev->priv; ++ u_int ioaddr = dev->base_addr; ++ u_int val; + +- for ( cur = 0; cur < 8; cur ++ ) { +- byte a, b; ++ SMC_SELECT_BANK(1); ++ val = smc_inw(ioaddr, CONFIG); ++ switch (smc->port) { ++ case PORT_TP: ++ val &= ~CFG_AUI_SELECT; ++ break; + +- a = *(buf ++ ); +- b = *(buf ++ ); +- printk("%02x%02x ", a, b ); +- } +- printk("\n"); ++ 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) +--- linux-2.4.25/drivers/net/smc9194.h~2.4.25-vrs2.patch 2001-09-08 21:13:55.000000000 +0200 ++++ linux-2.4.25/drivers/net/smc9194.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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 */ ++/* ++ * 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 SMC_DISABLE_INT(x) {\ +- unsigned char mask;\ +- SMC_SELECT_BANK(2);\ +- mask = inb( ioaddr + INT_MASK );\ +- mask &= ~(x);\ +- outb( mask, ioaddr + INT_MASK ); \ +-} ++#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_ */ + +--- linux-2.4.25/drivers/parport/Config.in~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/parport/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/parport/Makefile~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/parport/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/parport/init.c~2.4.25-vrs2.patch 2002-11-29 00:53:14.000000000 +0100 ++++ linux-2.4.25/drivers/parport/init.c 2004-03-31 17:15:09.000000000 +0200 +@@ -164,6 +164,9 @@ + #ifdef CONFIG_PARPORT_SUNBPP + parport_sunbpp_init(); + #endif ++#ifdef CONFIG_PARPORT_IDP ++ parport_idp_init(); ++#endif + return 0; + } + +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/parport/parport_idp.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,247 @@ ++/* Low-level polled-mode parallel port routines for the Accelent IDP ++ * ++ * Author: Rich Dulabahn <rich@accelent.com> ++ * ++ * 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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/parport.h> ++#include <asm/hardware.h> ++ ++/* ++ * 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 ++ +--- linux-2.4.25/drivers/pci/Makefile~2.4.25-vrs2.patch 2003-08-25 13:44:42.000000000 +0200 ++++ linux-2.4.25/drivers/pci/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/pci/bridge.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <arjanv@redhat.com> ++ * ++ */ ++ ++ ++/* ++ * Generic PCI driver for PCI bridges for powermanagement purposes ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/pci.h> ++#include <linux/init.h> ++ ++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) ++ +--- linux-2.4.25/drivers/pci/pci.c~2.4.25-vrs2.patch 2003-11-28 19:26:20.000000000 +0100 ++++ linux-2.4.25/drivers/pci/pci.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/pci/setup-bus.c~2.4.25-vrs2.patch 2003-06-13 16:51:35.000000000 +0200 ++++ linux-2.4.25/drivers/pci/setup-bus.c 2004-03-31 17:15:09.000000000 +0200 +@@ -12,6 +12,8 @@ + /* + * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru> + * PCI-PCI bridges cleanup, sorted resource allocation. ++ * May 2001, Russell King <rmk@arm.linux.org.uk> ++ * Allocate prefetchable memory regions where available. + * Feb 2002, Ivan Kokshaysky <ink@jurassic.park.msu.ru> + * 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); + } + +--- linux-2.4.25/drivers/pcmcia/Config.in~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/pcmcia/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/pcmcia/Makefile~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/pcmcia/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/pcmcia/cistpl.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/pcmcia/cistpl.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/clps6700.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/errno.h> ++#include <linux/sched.h> ++#include <linux/proc_fs.h> ++#include <linux/spinlock.h> ++#include <linux/init.h> ++ ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/hardware.h> ++#include <asm/page.h> ++ ++#include <asm/arch/syspld.h> ++#include <asm/hardware/clps7111.h> ++ ++#include <pcmcia/version.h> ++#include <pcmcia/cs_types.h> ++#include <pcmcia/ss.h> ++ ++#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); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/clps6700.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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) +--- linux-2.4.25/drivers/pcmcia/cs.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/pcmcia/cs.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> +@@ -92,7 +92,7 @@ + MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); + 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); + + /*====================================================================*/ +- +--- linux-2.4.25/drivers/pcmcia/ds.c~2.4.25-vrs2.patch 2001-11-12 18:39:01.000000000 +0100 ++++ linux-2.4.25/drivers/pcmcia/ds.c 2004-03-31 17:15:09.000000000 +0200 +@@ -55,6 +55,7 @@ + #include <pcmcia/bulkmem.h> + #include <pcmcia/cistpl.h> + #include <pcmcia/ds.h> ++#include <linux/devfs_fs_kernel.h> + + /*====================================================================*/ + +@@ -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; +--- linux-2.4.25/drivers/pcmcia/i82365.c~2.4.25-vrs2.patch 2003-11-28 19:26:20.000000000 +0100 ++++ linux-2.4.25/drivers/pcmcia/i82365.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> +@@ -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<<i)) + printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i); + if (mask1 == 0) printk("none!"); +- ++ + return mask1; + } + +@@ -598,14 +609,14 @@ + /* Use the next free entry in the socket table */ + socket[sockets].ioaddr = port; + socket[sockets].psock = sock; +- ++ + /* Wake up a sleepy Cirrus controller */ + if (wakeup) { + i365_bclr(sockets, PD67_MISC_CTL_2, PD67_MC2_SUSPEND); + /* Pause at least 50 ms */ + mdelay(50); + } +- ++ + if ((val = i365_get(sockets, I365_IDENT)) & 0x70) + return -1; + switch (val) { +@@ -618,7 +629,7 @@ + case 0x88: case 0x89: case 0x8a: + type = IS_IBM; break; + } +- ++ + /* Check for Vadem VG-468 chips */ + outb(0x0e, port); + outb(0x37, port); +@@ -633,7 +644,7 @@ + val = i365_get(sockets, RF5C_CHIP_ID); + if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396)) + type = IS_RF5Cx96; +- ++ + /* Check for Cirrus CL-PD67xx chips */ + i365_set(sockets, PD67_CHIP_INFO, 0); + val = i365_get(sockets, PD67_CHIP_INFO); +@@ -655,14 +666,14 @@ + bound to a (non PC Card) Linux driver. We leave these alone. + + We make an exception for cards that seem to be serial devices. +- ++ + ======================================================================*/ + + static int __init is_alive(u_short sock) + { + u_char stat; + u_short start, stop; +- ++ + stat = i365_get(sock, I365_STATUS); + start = i365_get_pair(sock, I365_IO(0)+I365_W_START); + stop = i365_get_pair(sock, I365_IO(0)+I365_W_STOP); +@@ -697,7 +708,7 @@ + + base = sockets-ns; + if (t->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) +--- linux-2.4.25/drivers/pcmcia/rsrc_mgr.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/pcmcia/rsrc_mgr.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <pcmcia/cistpl.h> + #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); +--- linux-2.4.25/drivers/pcmcia/sa1100.h~2.4.25-vrs2.patch 2002-08-03 02:39:44.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/sa1100.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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; + +--- linux-2.4.25/drivers/pcmcia/sa1100_adsbitsy.c~2.4.25-vrs2.patch 2002-08-03 02:39:44.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/sa1100_adsbitsy.c 2004-03-31 17:15:09.000000000 +0200 +@@ -11,28 +11,156 @@ + */ + #include <linux/kernel.h> + #include <linux/sched.h> ++#include <linux/ioport.h> + + #include <asm/hardware.h> ++#include <asm/hardware/sa1111.h> ++#include <asm/irq.h> + + #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; + +- /* Disable Power 3.3V/5V for PCMCIA/CF */ +- PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3; ++ /* Set GPIO_A<1:0> to be outputs for PCMCIA power controller: */ ++ PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1); + +- /* Why? */ +- MECR = 0x09430943; ++ /* Disable Power 3.3V/5V for PCMCIA */ ++ PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1; + +- return sa1111_pcmcia_init(init); ++ 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 +-adsbitsy_pcmcia_configure_socket(const struct pcmcia_configure *conf) ++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_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, + +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/sa1100_adsbitsyplus.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,236 @@ ++/* ++ * drivers/pcmcia/sa1100_adsbitsyplus.c ++ * ++ * PCMCIA implementation routines for ADS Bitsy Plus ++ * ++ * Created Feb 7, 2003 by Robert Whaley <rwhaley@applieddata.net> ++ * ++ * This file comes from sa1100_adsbitsy.c of Woojung Huh <whuh@applieddata.net> ++ * ++ */ ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/ioport.h> ++ ++#include <asm/hardware.h> ++#include <asm/hardware/sa1111.h> ++#include <asm/irq.h> ++ ++#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, ++}; ++ +--- linux-2.4.25/drivers/pcmcia/sa1100_freebird.c~2.4.25-vrs2.patch 2002-08-03 02:39:44.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/sa1100_freebird.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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); + +--- linux-2.4.25/drivers/pcmcia/sa1100_generic.c~2.4.25-vrs2.patch 2003-06-13 16:51:35.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/sa1100_generic.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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); + +--- linux-2.4.25/drivers/pcmcia/sa1100_graphicsclient.c~2.4.25-vrs2.patch 2002-08-03 02:39:44.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/sa1100_graphicsclient.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <asm/irq.h> + #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; + } + +--- linux-2.4.25/drivers/pcmcia/sa1100_graphicsmaster.c~2.4.25-vrs2.patch 2002-08-03 02:39:44.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/sa1100_graphicsmaster.c 2004-03-31 17:15:09.000000000 +0200 +@@ -12,13 +12,13 @@ + #include <linux/sched.h> + + #include <asm/hardware.h> ++#include <asm/hardware/sa1111.h> + + #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) { +--- linux-2.4.25/drivers/pcmcia/sa1100_h3600.c~2.4.25-vrs2.patch 2002-08-03 02:39:44.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/sa1100_h3600.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 + */ +--- linux-2.4.25/drivers/pcmcia/sa1100_jornada720.c~2.4.25-vrs2.patch 2002-08-03 02:39:44.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/sa1100_jornada720.c 2004-03-31 17:15:09.000000000 +0200 +@@ -8,6 +8,7 @@ + #include <linux/sched.h> + + #include <asm/hardware.h> ++#include <asm/hardware/sa1111.h> + + #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; +--- linux-2.4.25/drivers/pcmcia/sa1100_pangolin.c~2.4.25-vrs2.patch 2002-08-03 02:39:44.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/sa1100_pangolin.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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; +--- linux-2.4.25/drivers/pcmcia/sa1100_shannon.c~2.4.25-vrs2.patch 2002-08-03 02:39:44.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/sa1100_shannon.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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; +--- linux-2.4.25/drivers/pcmcia/sa1100_simpad.c~2.4.25-vrs2.patch 2002-08-03 02:39:44.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/sa1100_simpad.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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; +--- linux-2.4.25/drivers/pcmcia/sa1100_stork.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/pcmcia/sa1100_stork.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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) +--- linux-2.4.25/drivers/pcmcia/sa1100_yopy.c~2.4.25-vrs2.patch 2002-08-03 02:39:44.000000000 +0200 ++++ linux-2.4.25/drivers/pcmcia/sa1100_yopy.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/pld/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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: ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/pld/pld_epxa.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/config.h> ++#include <linux/errno.h> ++#include <linux/fs.h> ++#include <linux/slab.h> ++#include <linux/ioport.h> ++#include <linux/init.h> ++#include <linux/errno.h> ++#include <linux/module.h> ++#include <asm/io.h> ++#include <asm/uaccess.h> ++#include <asm/arch/excalibur.h> ++#include <asm/arch/hardware.h> ++#define PLD_CONF00_TYPE (volatile unsigned int *) ++#define MODE_CTRL00_TYPE (volatile unsigned int *) ++//#define DEBUG(x) x ++#define DEBUG(x) ++ ++#include <asm/arch/mode_ctrl00.h> ++#include <asm/arch/pld_conf00.h> ++#ifdef CONFIG_PLD_HOTSWAP ++#include <linux/pld/pld_hotswap.h> ++#endif ++#include <linux/pld/pld_epxa.h> ++ ++/* ++ * 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); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/pld/pld_hotswap.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <linux/pagemap.h> ++#include <linux/slab.h> ++#include <linux/smp_lock.h> ++#include <linux/init.h> ++#include <linux/kmod.h> ++#include <linux/proc_fs.h> ++#include <linux/list.h> ++#include <asm/uaccess.h> ++#include <linux/pld/pld_hotswap.h> ++ ++ ++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); +--- linux-2.4.25/drivers/scsi/Makefile~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/scsi/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 + + +--- linux-2.4.25/drivers/scsi/scsi.c~2.4.25-vrs2.patch 2003-08-25 13:44:42.000000000 +0200 ++++ linux-2.4.25/drivers/scsi/scsi.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/scsi/scsi.h~2.4.25-vrs2.patch 2003-08-25 13:44:42.000000000 +0200 ++++ linux-2.4.25/drivers/scsi/scsi.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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 */ +--- linux-2.4.25/drivers/scsi/scsi_dma.c~2.4.25-vrs2.patch 2002-02-25 20:38:04.000000000 +0100 ++++ linux-2.4.25/drivers/scsi/scsi_dma.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/scsi/scsi_error.c~2.4.25-vrs2.patch 2002-11-29 00:53:14.000000000 +0100 ++++ linux-2.4.25/drivers/scsi/scsi_error.c 2004-03-31 17:15:09.000000000 +0200 +@@ -35,6 +35,8 @@ + #include "hosts.h" + #include "constants.h" + ++#include <scsi/scsi_ioctl.h> /* 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 +@@ -385,16 +394,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. +@@ -421,16 +426,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); + +@@ -438,24 +437,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)) +@@ -470,15 +486,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. +@@ -496,40 +505,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. +@@ -589,7 +600,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. +@@ -672,14 +682,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 { +@@ -1220,6 +1229,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. +@@ -1241,6 +1326,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. +@@ -1260,8 +1354,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; +@@ -1271,136 +1364,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 +@@ -1410,20 +1569,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; +@@ -1433,359 +1601,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. +- * +- * FIXME(eric) - make sure we handle the case where multiple +- * commands to the same device have failed. They all must +- * get properly restarted. ++ * OK, we have a device that is having problems. ++ * Try and send a bus device reset to it. + */ +- rtn = scsi_try_bus_device_reset(SCloop, RESET_TIMEOUT); ++ rtn = scsi_try_bus_device_reset(SCpnt, RESET_TIMEOUT); + +- if (rtn == SUCCESS) { +- rtn = scsi_test_unit_ready(SCloop); ++ /* ++ * 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. ++ * ++ * 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); ++ } ++} + +- if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) { +- rtn = scsi_eh_retry_command(SCloop); ++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 (rtn == SUCCESS) { +- SCloop->host->host_failed--; +- scsi_eh_finish_command(&SCdone, SCloop); +- } +- } +- } +- } ++ /* ++ * 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")); + +- 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. ++ * Find the maximum channel number for this host. + */ +- SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Try hard bus reset\n")); ++ for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) ++ if (SDpnt->channel > max_channel) ++ max_channel = SDpnt->channel; + +- /* +- * 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. ++ /* ++ * Loop over each channel, and see if it any device on ++ * each channel has failed. + */ +- 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 (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 (SCpnt && SDpnt->soft_reset) ++ soft_reset = 1; ++ } + +- if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) { +- rtn = scsi_eh_retry_command(SCloop); ++ /* ++ * If this channel hasn't failed, we ++ * don't need to reset it. ++ */ ++ if (!failed_command) ++ continue; + +- 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); ++ /* ++ * 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; ++ } + +- SDloop->online = FALSE; +- SDloop->host->host_failed--; +- scsi_eh_finish_command(&SCdone, SCloop); +- } +- } +- } ++ /* ++ * 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); ++ scsi_sleep(1 * HZ); + +- 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); +- } +- } +- } +- } +- } ++ goto try_again; + } + ++ SCSI_LOG_ERROR_RECOVERY(3, ++ printk("scsi_unjam_host: Try hard host reset\n")); ++ + /* +- * If we solved all of the problems, then let's rev up the engines again. +- */ +- if (host->host_failed == 0) { +- ourrtn = TRUE; +- goto leave; +- } +- /* +- * 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"); + } + } + } ++} + +- if (host->host_failed != 0) { ++static void scsi_unjam_failure(struct Scsi_Host *host, Scsi_Cmnd **done) ++{ ++ Scsi_Device *SDpnt; ++ ++ /* ++ * 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")); ++} + +- ourrtn = FALSE; ++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, ++}; + +- leave: ++/* ++ * 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; ++ ++ ASSERT_LOCK(&io_request_lock, 0); ++ ++ /* ++ * 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 +@@ -2025,3 +2312,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); +--- linux-2.4.25/drivers/scsi/scsi_ioctl.c~2.4.25-vrs2.patch 2003-08-25 13:44:42.000000000 +0200 ++++ linux-2.4.25/drivers/scsi/scsi_ioctl.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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; +--- linux-2.4.25/drivers/scsi/scsi_lib.c~2.4.25-vrs2.patch 2003-08-25 13:44:42.000000000 +0200 ++++ linux-2.4.25/drivers/scsi/scsi_lib.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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. +@@ -723,7 +747,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; +@@ -898,8 +922,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 +@@ -910,7 +943,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); +--- linux-2.4.25/drivers/scsi/scsi_syms.c~2.4.25-vrs2.patch 2002-08-03 02:39:44.000000000 +0200 ++++ linux-2.4.25/drivers/scsi/scsi_syms.c 2004-03-31 17:15:09.000000000 +0200 +@@ -103,3 +103,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); +--- linux-2.4.25/drivers/scsi/sd.c~2.4.25-vrs2.patch 2003-08-25 13:44:42.000000000 +0200 ++++ linux-2.4.25/drivers/scsi/sd.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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); +--- linux-2.4.25/drivers/scsi/sr_ioctl.c~2.4.25-vrs2.patch 2002-11-29 00:53:14.000000000 +0100 ++++ linux-2.4.25/drivers/scsi/sr_ioctl.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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) +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/serial/21285.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,600 @@ ++/* ++ * 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$ ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++#include <linux/signal.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/tty.h> ++#include <linux/tty_flip.h> ++#include <linux/serial.h> ++#include <linux/major.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/mm.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/console.h> ++ ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <asm/hardware/dec21285.h> ++#include <asm/hardware.h> ++ ++#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 ++ ++#ifdef CONFIG_SERIAL_21285_OLD ++#include <asm/mach-types.h> ++/* ++ * 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 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; ++} ++ ++#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"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/serial/8250.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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$ ++ * ++ * 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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++#include <linux/sched.h> ++#include <linux/tty.h> ++#include <linux/tty_flip.h> ++#include <linux/major.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/init.h> ++#include <linux/serial.h> ++#include <linux/console.h> ++#include <linux/sysrq.h> ++#include <linux/serial_reg.h> ++#include <linux/serialP.h> ++#include <linux/delay.h> ++#include <linux/serial_core.h> ++#include <linux/kmod.h> ++ ++#include <asm/system.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <asm/bitops.h> ++ ++#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 <asm/serial.h> ++ ++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 */ ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/serial/8250.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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$ ++ */ ++ ++#include <linux/config.h> ++ ++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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/serial/8250_pci.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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$ ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/pci.h> ++#include <linux/sched.h> ++#include <linux/string.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/serial.h> ++ ++/* 2.4.6 compatibility cruft ;( */ ++#define pci_board __pci_board ++#include <linux/serialP.h> ++#undef pci_board ++ ++#include <asm/bitops.h> ++#include <asm/byteorder.h> ++#include <asm/serial.h> ++ ++#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 <pazke@mail.tp.ru>, 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 <arh@01019freenet.de> */ ++ { 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); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/serial/8250_pnp.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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$ ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/pci.h> ++#include <linux/isapnp.h> ++#include <linux/string.h> ++#include <linux/kernel.h> ++#include <linux/serial.h> ++#include <linux/serialP.h> ++ ++#include <asm/bitops.h> ++#include <asm/byteorder.h> ++#include <asm/serial.h> ++ ++#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); ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/serial/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,91 @@ ++# ++# Serial device configuration ++# ++# $Id$ ++# ++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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/serial/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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$ ++# ++ ++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: ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/serial/amba.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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$ ++ * ++ * 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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/tty.h> ++#include <linux/ioport.h> ++#include <linux/init.h> ++#include <linux/sched.h> ++#include <linux/serial.h> ++#include <linux/console.h> ++#include <linux/sysrq.h> ++ ++#include <asm/io.h> ++#include <asm/irq.h> ++ ++#if defined(CONFIG_SERIAL_AMBA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) ++#define SUPPORT_SYSRQ ++#endif ++ ++#include <linux/serial_core.h> ++ ++#include <asm/hardware/serial_amba.h> ++ ++#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"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/serial/anakin.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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$ ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++#include <linux/signal.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/tty.h> ++#include <linux/tty_flip.h> ++#include <linux/major.h> ++#include <linux/string.h> ++#include <linux/fcntl.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/mm.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/circ_buf.h> ++#include <linux/serial.h> ++#include <linux/console.h> ++#include <linux/sysrq.h> ++ ++#include <asm/system.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <asm/bitops.h> ++ ++#include <linux/serial_core.h> ++ ++#include <asm/arch/serial_reg.h> ++ ++#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 <chan@aleph1.co.uk>"); ++MODULE_SUPPORTED_DEVICE("ttyAN"); ++MODULE_LICENSE("GPL"); ++ ++EXPORT_NO_SYMBOLS; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/serial/clps711x.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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$ ++ * ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++#include <linux/signal.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/tty.h> ++#include <linux/tty_flip.h> ++#include <linux/major.h> ++#include <linux/string.h> ++#include <linux/fcntl.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/mm.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/circ_buf.h> ++#include <linux/serial.h> ++#include <linux/console.h> ++#include <linux/sysrq.h> ++ ++#include <asm/bitops.h> ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/system.h> ++#include <asm/uaccess.h> ++ ++#include <linux/serial_core.h> ++ ++#include <asm/hardware/clps7111.h> ++ ++#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"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/serial/core.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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$ ++ * ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++#include <linux/tty.h> ++#include <linux/string.h> ++#include <linux/fcntl.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/mm.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/console.h> ++#include <linux/sysrq.h> ++#include <linux/pm.h> ++#include <linux/serial_core.h> ++#include <linux/smp_lock.h> ++ ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++ ++#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 <baud><parity><bits><flow>, ++ * 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"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/serial/omaha.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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$ ++ * ++ * 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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++#include <linux/signal.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/tty.h> ++#include <linux/tty_flip.h> ++#include <linux/major.h> ++#include <linux/string.h> ++#include <linux/fcntl.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/mm.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/circ_buf.h> ++#include <linux/serial.h> ++#include <linux/console.h> ++#include <linux/sysrq.h> ++ ++#include <asm/system.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <asm/bitops.h> ++ ++#if defined(CONFIG_SERIAL_OMAHA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) ++#define SUPPORT_SYSRQ ++#endif ++ ++#include <linux/serial_core.h> ++ ++#include <asm/hardware/serial_omaha.h> ++ ++#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); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/serial/sa1100.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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$ ++ * ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/tty.h> ++#include <linux/ioport.h> ++#include <linux/init.h> ++#include <linux/sched.h> ++#include <linux/serial.h> ++#include <linux/console.h> ++#include <linux/sysrq.h> ++ ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/hardware.h> ++#include <asm/mach/serial_sa1100.h> ++ ++#if defined(CONFIG_SERIAL_SA1100_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) ++#define SUPPORT_SYSRQ ++#endif ++ ++#include <linux/serial_core.h> ++ ++/* 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"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/serial/uart00.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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$ ++ * ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/errno.h> ++#include <linux/signal.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/tty.h> ++#include <linux/tty_flip.h> ++#include <linux/major.h> ++#include <linux/string.h> ++#include <linux/fcntl.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/mm.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/circ_buf.h> ++#include <linux/serial.h> ++#include <linux/console.h> ++#include <linux/sysrq.h> ++#include <linux/pld/pld_hotswap.h> ++#include <linux/proc_fs.h> ++ ++#include <asm/system.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <asm/bitops.h> ++#include <asm/sizes.h> ++ ++#if defined(CONFIG_SERIAL_UART00_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) ++#define SUPPORT_SYSRQ ++#endif ++ ++#include <linux/serial_core.h> ++#include <asm/arch/excalibur.h> ++#define UART00_TYPE (volatile unsigned int*) ++#include <asm/arch/uart00.h> ++#include <asm/arch/int_ctrl00.h> ++ ++#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;i<UART_NR;i++){ ++ if(dev_port_map[i].port){ ++ uart_unregister_port(&uart00_reg,i); ++ dev_port_map[i].port=NULL; ++ } ++ } ++ return 0; ++ ++} ++ ++#ifdef CONFIG_PROC_FS ++ ++ ++int uart00_proc_read(char* buf,char** start,off_t offset,int count,int *eof,void *data){ ++ ++ int i,len=0; ++ struct uart_port *port; ++ int limit = count - 80; ++ char ps_data[80]; ++ if(*start) ++ buf=*start; ++ for(i=0;(i<UART_NR)&&(len<limit);i++){ ++ if(dev_port_map[i].port){ ++ port=dev_port_map[i].port; ++ sprintf(ps_data,"clk, %dHz, fifo size, %dbytes", ++ port->uartclk,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<UART_NR;i++){ ++ uart00_ports[i].ops=&uart00_pops; ++ } ++ ++ printk(KERN_WARNING "uart00:Using temporary major/minor pairs - these WILL change in the future\n"); ++ ++#ifdef CONFIG_PLD_HOTSWAP ++ pldhs_register_driver(&uart00_pldhs_ops); ++#endif ++ for (i=0; i<UART_NR; i++) ++ uart_add_one_port(&uart00_reg,&uart00_ports[i]); ++ ++ uart00_console.flags = 0; ++ register_console(&uart00_console); ++#ifdef CONFIG_ARCH_CAMELOT ++ dev_port_map[0].port=uart00_ports; ++#endif ++ return ret; ++} ++ ++ ++__initcall(uart00_init); ++ ++ +--- linux-2.4.25/drivers/sound/.version~2.4.25-vrs2.patch ++++ linux-2.4.25/drivers/sound/.version +-3.8s +-0x030804 +--- linux-2.4.25/drivers/sound/Config.in~2.4.25-vrs2.patch 2003-11-28 19:26:20.000000000 +0100 ++++ linux-2.4.25/drivers/sound/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -131,6 +131,17 @@ + dep_tristate ' VIA 82C686 Audio Codec' CONFIG_SOUND_VIA82CXXX $CONFIG_PCI + dep_mbool ' VIA 82C686 MIDI' CONFIG_MIDI_VIA82CXXX $CONFIG_SOUND_VIA82CXXX + ++if [ "$CONFIG_ARCH_SA1100" = "y" ]; then ++ dep_tristate ' StrongARM-11x0 Sound Drivers' CONFIG_SOUND_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_SOUND ++ dep_tristate ' UDA1341 Stereo Codec' CONFIG_SOUND_UDA1341 $CONFIG_L3 $CONFIG_SOUND_SA1100 $CONFIG_SOUND ++ dep_tristate ' Assabet audio support' CONFIG_SOUND_ASSABET_UDA1341 $CONFIG_SA1100_ASSABET $CONFIG_SOUND_UDA1341 ++ dep_tristate ' Compaq iPAQ audio support' CONFIG_SOUND_H3600_UDA1341 $CONFIG_SA1100_H3600 $CONFIG_SOUND_UDA1341 ++ dep_tristate ' Pangolin audio support' CONFIG_SOUND_PANGOLIN_UDA1341 $CONFIG_SA1100_PANGOLIN $CONFIG_SOUND_UDA1341 ++ dep_tristate ' SA1111 audio support' CONFIG_SOUND_SA1111_UDA1341 $CONFIG_SA1111 $CONFIG_SOUND_UDA1341 ++ dep_tristate ' SA1111 AC97 Sound' CONFIG_SOUND_SA1111_AC97 $CONFIG_SA1111 $CONFIG_SOUND_SA1100 ++ dep_tristate ' Generic DAC on the SA11x0 SSP port' CONFIG_SOUND_SA1100SSP $CONFIG_SOUND_SA1100 ++fi ++ + dep_tristate ' OSS sound modules' CONFIG_SOUND_OSS $CONFIG_SOUND + + if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then +@@ -220,14 +231,14 @@ + bool ' Audio Excel DSP 16 (MPU401 emulation)' CONFIG_AEDSP16_MPU401 + fi + fi ++ ++fi + +- if [ "$CONFIG_ARM" = "y" ]; then +- if [ "$CONFIG_ARCH_ACORN" = "y" -o "$CONFIG_ARCH_CLPS7500" = "y" ]; then +- dep_tristate ' VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS +- fi +- dep_tristate ' Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS $CONFIG_ARCH_NETWINDER ++if [ "$CONFIG_ARM" = "y" ]; then ++ if [ "$CONFIG_ARCH_ACORN" = "y" -o "$CONFIG_ARCH_CLPS7500" = "y" -o "$CONFIG_ARCH_RISCSTATION" ]; then ++ dep_tristate ' VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS + fi +- ++ dep_tristate ' Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS $CONFIG_ARCH_NETWINDER + fi + + dep_tristate ' TV card (bt848) mixer support' CONFIG_SOUND_TVMIXER $CONFIG_SOUND $CONFIG_I2C +--- linux-2.4.25/drivers/sound/Makefile~2.4.25-vrs2.patch 2003-11-28 19:26:20.000000000 +0100 ++++ linux-2.4.25/drivers/sound/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -10,7 +10,8 @@ + export-objs := ad1848.o audio_syms.o midi_syms.o mpu401.o \ + msnd.o opl3.o sb_common.o sequencer_syms.o \ + sound_core.o sound_syms.o uart401.o \ +- nm256_audio.o ac97.o ac97_codec.o aci.o ++ nm256_audio.o ac97.o ac97_codec.o aci.o \ ++ sa1100-audio.o + + # Each configuration option enables a list of files. + +@@ -76,6 +77,14 @@ + obj-$(CONFIG_SOUND_FORTE) += forte.o ac97_codec.o + obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o + obj-$(CONFIG_SOUND_HARMONY) += harmony.o ++obj-$(CONFIG_SOUND_SA1100) += sa1100-audio.o ++obj-$(CONFIG_SOUND_UDA1341) += uda1341.o ++obj-$(CONFIG_SOUND_ASSABET_UDA1341) += assabet-uda1341.o ++obj-$(CONFIG_SOUND_PANGOLIN_UDA1341) += pangolin-uda1341.o ++obj-$(CONFIG_SOUND_H3600_UDA1341) += h3600-uda1341.o ++obj-$(CONFIG_SOUND_SA1111_UDA1341) += sa1111-uda1341.o ++obj-$(CONFIG_SOUND_SA1111_AC97) += sa1111-ac97.o ac97_codec.o ++obj-$(CONFIG_SOUND_SA1100SSP) += sa1100ssp.o + obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o + obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o + obj-$(CONFIG_SOUND_RME96XX) += rme96xx.o +@@ -105,7 +114,6 @@ + obj-y += dmasound/dmasound.o + endif + +- + # Declare multi-part drivers. + + list-multi := sound.o gus.o pas2.o sb.o sb_lib.o vidc_mod.o \ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/sound/assabet-uda1341.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,404 @@ ++/* ++ * Glue audio driver for the SA1110 Assabet board & Philips UDA1341 codec. ++ * ++ * Copyright (c) 2000 Nicolas Pitre <nico@cam.org> ++ * ++ * 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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/types.h> ++#include <linux/fs.h> ++#include <linux/delay.h> ++#include <linux/pm.h> ++#include <linux/errno.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++#include <linux/cpufreq.h> ++#include <linux/l3/l3.h> ++#include <linux/l3/uda1341.h> ++ ++#include <asm/semaphore.h> ++#include <asm/uaccess.h> ++#include <asm/hardware.h> ++#include <asm/dma.h> ++#include <asm/arch/assabet.h> ++ ++#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; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/sound/h3600-uda1341.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,352 @@ ++/* ++ * Glue audio driver for the Compaq iPAQ H3600 & Philips UDA1341 codec. ++ * ++ * Copyright (c) 2000 Nicolas Pitre <nico@cam.org> ++ * ++ * 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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/types.h> ++#include <linux/fs.h> ++#include <linux/delay.h> ++#include <linux/pm.h> ++#include <linux/errno.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++#include <linux/l3/l3.h> ++#include <linux/l3/uda1341.h> ++ ++#include <asm/semaphore.h> ++#include <asm/uaccess.h> ++#include <asm/hardware.h> ++#include <asm/dma.h> ++//#include <asm/arch/h3600_hal.h> ++ ++#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; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/sound/pangolin-uda1341.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,322 @@ ++/* ++ * Glue audio driver for the SA1110 Pangolin board & Philips UDA1341 codec. ++ * ++ * Copyright (c) 2000 Nicolas Pitre <nico@cam.org> ++ * ++ * 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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/types.h> ++#include <linux/fs.h> ++#include <linux/delay.h> ++#include <linux/pm.h> ++#include <linux/errno.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++#include <linux/l3/l3.h> ++#include <linux/l3/uda1341.h> ++ ++#include <asm/semaphore.h> ++#include <asm/uaccess.h> ++#include <asm/hardware.h> ++#include <asm/dma.h> ++ ++#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; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/sound/sa1100-audio.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,976 @@ ++/* ++ * Common audio handling for the SA11x0 processor ++ * ++ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org> ++ * ++ * 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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/types.h> ++#include <linux/fs.h> ++#include <linux/mm.h> ++#include <linux/slab.h> ++#include <linux/sched.h> ++#include <linux/poll.h> ++#include <linux/pm.h> ++#include <linux/errno.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++#include <linux/sysrq.h> ++ ++#include <asm/uaccess.h> ++#include <asm/io.h> ++#include <asm/hardware.h> ++#include <asm/semaphore.h> ++#include <asm/dma.h> ++ ++#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"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/sound/sa1100-audio.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,68 @@ ++/* ++ * Common audio handling for the SA11x0 ++ * ++ * Copyright (c) 2000 Nicolas Pitre <nico@cam.org> ++ * ++ * 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); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/sound/sa1100ssp.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,182 @@ ++/* ++ * Glue audio driver for a simple DAC on the SA1100's SSP port ++ * ++ * Copyright (c) 2001 Nicolas Pitre <nico@cam.org> ++ * ++ * 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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/types.h> ++#include <linux/fs.h> ++#include <linux/delay.h> ++#include <linux/pm.h> ++#include <linux/errno.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++ ++#include <asm/semaphore.h> ++#include <asm/uaccess.h> ++#include <asm/hardware.h> ++#include <asm/dma.h> ++ ++#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; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/sound/sa1111-ac97.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/types.h> ++#include <linux/fs.h> ++#include <linux/delay.h> ++#include <linux/pm.h> ++#include <linux/errno.h> ++#include <linux/proc_fs.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++#include <linux/ac97_codec.h> ++ ++#include <asm/semaphore.h> ++#include <asm/uaccess.h> ++#include <asm/dma.h> ++#include <asm/hardware/sa1111.h> ++ ++#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; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/sound/sa1111-uda1341.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/config.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/types.h> ++#include <linux/fs.h> ++#include <linux/delay.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++#include <linux/ioport.h> ++#include <linux/pm.h> ++#include <linux/l3/l3.h> ++#include <linux/l3/uda1341.h> ++ ++#include <asm/semaphore.h> ++#include <asm/mach-types.h> ++#include <asm/uaccess.h> ++#include <asm/hardware.h> ++#include <asm/dma.h> ++#include <asm/arch/assabet.h> ++#include <asm/hardware/sa1111.h> ++ ++#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; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/sound/uda1341.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,511 @@ ++/* ++ * Philips UDA1341 mixer device driver ++ * ++ * Copyright (c) 2000 Nicolas Pitre <nico@cam.org> ++ * ++ * 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 <linux/module.h> ++#include <linux/init.h> ++#include <linux/types.h> ++#include <linux/slab.h> ++#include <linux/errno.h> ++#include <linux/ioctl.h> ++#include <linux/soundcard.h> ++#include <linux/l3/l3.h> ++#include <linux/l3/uda1341.h> ++ ++#include <asm/uaccess.h> ++ ++#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"); +--- linux-2.4.25/drivers/sound/vidc.c~2.4.25-vrs2.patch 2001-10-11 18:43:30.000000000 +0200 ++++ linux-2.4.25/drivers/sound/vidc.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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; ++ hwctrl = 0x00000003; ++ ++ /* Using internal clock */ ++ hwrate = (((VIDC_SOUND_CLOCK * 2) / rate) + 1) >> 1; ++ if (hwrate < 3) + hwrate = 3; +- } else { +- hwctrl = 0x00000003; ++ if (hwrate > 255) ++ hwrate = 255; + +- hwrate = (((VIDC_SOUND_CLOCK * 2) / rate) + 1) >> 1; +- if (hwrate < 3) +- hwrate = 3; +- if (hwrate > 255) +- hwrate = 255; ++ /* 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 = VIDC_SOUND_CLOCK / hwrate; ++ 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; + } +--- linux-2.4.25/drivers/sound/waveartist.c~2.4.25-vrs2.patch 2001-10-25 22:53:52.000000000 +0200 ++++ linux-2.4.25/drivers/sound/waveartist.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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="); ++ if (debug_flg & DEBUG_CMD && !timed_out) { ++ printk("waveartist_cmd: resp="); + +- for (i = 0; i < nr_resp; i++) +- printk("%04X ", resp[i]); ++ for (i = 0; i < nr_resp; i++) ++ printk("%04X ", resp[i]); ++ printk("\n"); ++ } + +- printk("\n"); +- } else +- printk("waveartist_cmd: timed out\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); + +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/ssi/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/ssi/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/ssi/README 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/ssi/clps711x_ssi1.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/init.h> ++#include <linux/sched.h> ++#include <linux/delay.h> ++ ++#include <asm/mach-types.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++ ++#include <asm/hardware/ep7212.h> ++ ++#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: ++ * <control> ++ * 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> <map> <data>... ++ * 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); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/ssi/juno.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,131 @@ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/sched.h> ++#include <linux/delay.h> ++ ++#include <asm/io.h> ++#include <asm/irq.h> ++ ++#include <asm/arch/syspld.h> ++ ++#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); ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/ssi/ssi_bus.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,21 @@ ++#include <linux/circ_buf.h> ++ ++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); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/ssi/ssi_core.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/module.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/malloc.h> ++#include <linux/init.h> ++ ++#include <asm/errno.h> ++ ++#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 : "<none>", 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); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/ssi/ssi_dev.h 2004-03-31 17:15:09.000000000 +0200 +@@ -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; ++}; ++ ++ +--- linux-2.4.25/drivers/usb/Config.in~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/usb/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 + +--- linux-2.4.25/drivers/usb/Makefile~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/usb/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/usb/hcd.c~2.4.25-vrs2.patch 2003-06-13 16:51:36.000000000 +0200 ++++ linux-2.4.25/drivers/usb/hcd.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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; + + /*-------------------------------------------------------------------------*/ + +@@ -1203,13 +1203,21 @@ + // NOTE: 2.5 does this if !URB_NO_DMA_MAP transfer flag + 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) +@@ -1422,7 +1430,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, +@@ -1432,7 +1440,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; +@@ -1481,11 +1489,23 @@ + + // NOTE: 2.5 does this if !URB_NO_DMA_MAP transfer flag + if (usb_pipecontrol (urb->pipe)) +- 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) +- 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 +--- linux-2.4.25/drivers/usb/host/Config.in~2.4.25-vrs2.patch 2003-11-28 19:26:20.000000000 +0100 ++++ linux-2.4.25/drivers/usb/host/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 ++ +--- linux-2.4.25/drivers/usb/host/Makefile~2.4.25-vrs2.patch 2003-11-28 19:26:20.000000000 +0100 ++++ linux-2.4.25/drivers/usb/host/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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. +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/usb/host/usb-ohci-pci.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,436 @@ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/pci.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> /* for in_interrupt() */ ++#undef DEBUG ++#include <linux/usb.h> ++ ++#include "usb-ohci.h" ++ ++#ifdef CONFIG_PMAC_PBOOK ++#include <asm/machdep.h> ++#include <asm/pmac_feature.h> ++#include <asm/pci-bridge.h> ++#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); ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/usb/host/usb-ohci-sa1111.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,118 @@ ++/* ++ * linux/drivers/usb/usb-ohci-sa1111.c ++ * ++ * The outline of this code was taken from Brad Parkers <brad@heeltoe.com> ++ * original OHCI driver modifications, and reworked into a cleaner form ++ * by Russell King <rmk@arm.linux.org.uk>. ++ */ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/sched.h> ++#include <linux/ioport.h> ++#include <linux/interrupt.h> ++#include <linux/slab.h> ++#include <linux/usb.h> ++ ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/io.h> ++#include <asm/pci.h> ++#include <asm/arch/assabet.h> ++#include <asm/arch/badge4.h> ++#include <asm/hardware/sa1111.h> ++ ++#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); +--- linux-2.4.25/drivers/usb/host/usb-ohci.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/usb/host/usb-ohci.c 2004-03-31 17:15:09.000000000 +0200 +@@ -12,7 +12,6 @@ + * + * History: + * +- * 2002/10/22 OHCI_USB_OPER for ALi lockup in IBM i1200 (ALEX <thchou@ali>) + * 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 <asm/machdep.h> +-#include <asm/pmac_feature.h> +-#include <asm/pci-bridge.h> +-#ifndef CONFIG_PM +-#define CONFIG_PM +-#endif +-#endif +- +- + /* + * Version Information + */ +@@ -98,14 +87,10 @@ + #define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, 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); +-static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED; ++spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED; + + + /*-------------------------------------------------------------------------*/ +@@ -443,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); +@@ -557,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; +@@ -702,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) { +@@ -715,7 +703,6 @@ + + /* drive timeouts by SF (messy, but works) */ + writel (OHCI_INTR_SF, &ohci->regs->intrenable); +- (void)readl (&ohci->regs->intrdisable); /* PCI posting flush */ + } + #endif + +@@ -790,10 +777,8 @@ + + /* 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) { +@@ -864,7 +849,7 @@ + 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); +@@ -909,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 (); + } + } +@@ -1294,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 */ + } + } + +@@ -1316,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; +@@ -1415,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; + +@@ -1444,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; + +@@ -1826,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" */ +@@ -2174,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) { +@@ -2252,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); + +@@ -2332,14 +2312,14 @@ + /* interrupt for some other device? */ + } else if ((ints &= readl (®s->intrenable)) == 0) { + 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 +@@ -2355,30 +2335,24 @@ + + 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 */ +- } + } + + if (!list_empty (&ohci->timeout_list)) { +@@ -2392,7 +2366,6 @@ + + writel (ints, ®s->intrstatus); + writel (OHCI_INTR_MIE, ®s->intrenable); +- (void)readl (®s->intrdisable); /* PCI posting flush */ + } + + /*-------------------------------------------------------------------------*/ +@@ -2423,7 +2396,9 @@ + 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); +@@ -2451,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) +@@ -2464,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); +@@ -2487,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__ +@@ -2507,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); +@@ -2543,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; +@@ -2557,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; + } +@@ -2568,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) +-{ +- 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) ++/* ++ * Host bus independent remove one OHCI host controller. ++ */ ++void __devexit hc_remove_ohci(ohci_t *ohci) + { +- 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 +@@ -2692,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 (&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 = 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); +- +- + MODULE_AUTHOR( DRIVER_AUTHOR ); + MODULE_DESCRIPTION( DRIVER_DESC ); + MODULE_LICENSE("GPL"); +--- linux-2.4.25/drivers/usb/host/usb-ohci.h~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/usb/host/usb-ohci.h 2004-03-31 17:15:09.000000000 +0200 +@@ -386,6 +386,7 @@ + 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 urb_list_lock; // lock to keep consistency +@@ -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 +--- linux-2.4.25/drivers/video/Config.in~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/video/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- linux-2.4.25/drivers/video/Makefile~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/video/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +- +--- linux-2.4.25/drivers/video/acornfb.c~2.4.25-vrs2.patch 2002-08-03 02:39:45.000000000 +0200 ++++ linux-2.4.25/drivers/video/acornfb.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/video/anakinfb.c 2004-03-31 17:15:09.000000000 +0200 +@@ -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 <linux/types.h> ++#include <linux/fb.h> ++#include <linux/string.h> ++#include <linux/errno.h> ++#include <linux/init.h> ++#include <linux/module.h> ++ ++#include <asm/io.h> ++ ++#include <video/fbcon.h> ++#include <video/fbcon-cfb16.h> ++ ++static u16 colreg[16]; ++static int currcon = 0; ++static struct fb_info fb_info; ++static struct display display; ++ ++static int ++anakinfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, ++ u_int *transp, struct fb_info *info) ++{ ++ if (regno > 15) ++ return 1; ++ ++ *red = colreg[regno] & 0xf800; ++ *green = colreg[regno] & 0x7e0 << 5; ++ *blue = colreg[regno] & 0x1f << 11; ++ *transp = 0; ++ return 0; ++} ++ ++static int ++anakinfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ++ u_int transp, struct fb_info *info) ++{ ++ if (regno > 15) ++ return 1; ++ ++ colreg[regno] = (red & 0xf800) | (green & 0xfc00 >> 5) | ++ (blue & 0xf800 >> 11); ++ return 0; ++} ++ ++static int ++anakinfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) ++{ ++ memset(fix, 0, sizeof(struct fb_fix_screeninfo)); ++ strcpy(fix->id, "AnakinFB"); ++ fix->smem_start = VGA_START; ++ fix->smem_len = VGA_SIZE; ++ fix->type = FB_TYPE_PACKED_PIXELS; ++ fix->type_aux = 0; ++ fix->visual = FB_VISUAL_TRUECOLOR; ++ fix->xpanstep = 0; ++ fix->ypanstep = 0; ++ fix->ywrapstep = 0; ++ fix->line_length = 400 * 2; ++ fix->accel = FB_ACCEL_NONE; ++ return 0; ++} ++ ++static int ++anakinfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) ++{ ++ memset(var, 0, sizeof(struct fb_var_screeninfo)); ++ var->xres = 400; ++ var->yres = 234; ++ var->xres_virtual = 400; ++ var->yres_virtual = 234; ++ var->xoffset = 0; ++ var->yoffset = 0; ++ var->bits_per_pixel = 16; ++ var->grayscale = 0; ++ var->red.offset = 11; ++ var->red.length = 5; ++ var->green.offset = 5; ++ var->green.length = 6; ++ var->blue.offset = 0; ++ var->blue.length = 5; ++ var->transp.offset = 0; ++ var->transp.length = 0; ++ var->nonstd = 0; ++ var->activate = FB_ACTIVATE_NOW; ++ var->height = -1; ++ var->width = -1; ++ var->pixclock = 0; ++ var->left_margin = 0; ++ var->right_margin = 0; ++ var->upper_margin = 0; ++ var->lower_margin = 0; ++ var->hsync_len = 0; ++ var->vsync_len = 0; ++ var->sync = 0; ++ var->vmode = FB_VMODE_NONINTERLACED; ++ return 0; ++} ++ ++static int ++anakinfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) ++{ ++ return -EINVAL; ++} ++ ++static int ++anakinfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, ++ struct fb_info *info) ++{ ++ if (con == currcon) ++ return fb_get_cmap(cmap, kspc, anakinfb_getcolreg, info); ++ else if (fb_display[con].cmap.len) ++ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); ++ else ++ fb_copy_cmap(fb_default_cmap(16), cmap, kspc ? 0 : 2); ++ return 0; ++} ++ ++static int ++anakinfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, ++ struct fb_info *info) ++{ ++ int err; ++ ++ if (!fb_display[con].cmap.len) { ++ if ((err = fb_alloc_cmap(&fb_display[con].cmap, 16, 0))) ++ return err; ++ } ++ if (con == currcon) ++ return fb_set_cmap(cmap, kspc, anakinfb_setcolreg, info); ++ else ++ fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); ++ return 0; ++} ++ ++static int ++anakinfb_switch_con(int con, struct fb_info *info) ++{ ++ currcon = con; ++ return 0; ++ ++} ++ ++static int ++anakinfb_updatevar(int con, struct fb_info *info) ++{ ++ return 0; ++} ++ ++static void ++anakinfb_blank(int blank, struct fb_info *info) ++{ ++ /* ++ * TODO: use I2C to blank/unblank the screen ++ */ ++} ++ ++static struct fb_ops anakinfb_ops = { ++ owner: THIS_MODULE, ++ fb_get_fix: anakinfb_get_fix, ++ fb_get_var: anakinfb_get_var, ++ fb_set_var: anakinfb_set_var, ++ fb_get_cmap: anakinfb_get_cmap, ++ fb_set_cmap: anakinfb_set_cmap, ++}; ++ ++int __init ++anakinfb_init(void) ++{ ++ memset(&fb_info, 0, sizeof(struct fb_info)); ++ strcpy(fb_info.modename, "AnakinFB"); ++ fb_info.node = -1; ++ fb_info.flags = FBINFO_FLAG_DEFAULT; ++ fb_info.fbops = &anakinfb_ops; ++ fb_info.disp = &display; ++ strcpy(fb_info.fontname, "VGA8x16"); ++ fb_info.changevar = NULL; ++ fb_info.switch_con = &anakinfb_switch_con; ++ fb_info.updatevar = &anakinfb_updatevar; ++ fb_info.blank = &anakinfb_blank; ++ ++ memset(&display, 0, sizeof(struct display)); ++ anakinfb_get_var(&display.var, 0, &fb_info); ++ display.screen_base = ioremap(VGA_START, VGA_SIZE); ++ display.visual = FB_VISUAL_TRUECOLOR; ++ display.type = FB_TYPE_PACKED_PIXELS; ++ display.type_aux = 0; ++ display.ypanstep = 0; ++ display.ywrapstep = 0; ++ display.line_length = 400 * 2; ++ display.can_soft_blank = 1; ++ display.inverse = 0; ++ ++#ifdef FBCON_HAS_CFB16 ++ display.dispsw = &fbcon_cfb16; ++ display.dispsw_data = colreg; ++#else ++ display.dispsw = &fbcon_dummy; ++#endif ++ ++ if (register_framebuffer(&fb_info) < 0) ++ return -EINVAL; ++ ++ MOD_INC_USE_COUNT; ++ return 0; ++} ++ ++MODULE_AUTHOR("Tak-Shing Chan <chan@aleph1.co.uk>"); ++MODULE_DESCRIPTION("Anakin framebuffer driver"); ++MODULE_SUPPORTED_DEVICE("fb"); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/video/clps711xfb.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,677 @@ ++/* ++ * linux/drivers/video/clps711xfb.c ++ * ++ * 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 ++ * ++ * Framebuffer driver for the CLPS7111 and EP7212 processors. ++ */ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/fb.h> ++#include <linux/init.h> ++#include <linux/proc_fs.h> ++#include <linux/delay.h> ++ ++#include <video/fbcon.h> ++#include <video/fbcon-cfb4.h> ++#include <video/fbcon-cfb2.h> ++#include <video/fbcon-mfb.h> ++ ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++#include <asm/uaccess.h> ++ ++#include <asm/hardware/clps7111.h> ++#include <asm/arch/syspld.h> ++ ++static struct clps7111fb_info { ++ struct fb_info fb; ++ int currcon; ++} *cfb; ++ ++#define CMAP_MAX_SIZE 16 ++ ++/* The /proc entry for the backlight. */ ++static struct proc_dir_entry *clps7111fb_backlight_proc_entry = NULL; ++ ++static int clps7111fb_proc_backlight_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data); ++static int clps7111fb_proc_backlight_write(struct file *file, ++ const char *buffer, unsigned long count, void *data); ++ ++/* ++ * LCD AC Prescale. This comes from the LCD panel manufacturers specifications. ++ * This determines how many clocks + 1 of CL1 before the M signal toggles. ++ * The number of lines on the display must not be divisible by this number. ++ */ ++static unsigned int lcd_ac_prescale = 13; ++ ++/* ++ * Set a single color register. Return != 0 for invalid regno. ++ */ ++static int ++clps7111fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ++ u_int transp, struct fb_info *info) ++{ ++ unsigned int level, mask, shift, pal; ++ ++ if (regno >= (1 << info->var.bits_per_pixel)) ++ return 1; ++ ++ /* gray = 0.30*R + 0.58*G + 0.11*B */ ++ level = (red * 77 + green * 151 + blue * 28) >> 20; ++ ++ /* ++ * On an LCD, a high value is dark, while a low value is light. ++ * So we invert the level. ++ * ++ * This isn't true on all machines, so we only do it on EDB7211. ++ * --rmk ++ */ ++ if (machine_is_edb7211() || machine_is_guidea07()) { ++ level = 15 - level; ++ } ++ ++ shift = 4 * (regno & 7); ++ level <<= shift; ++ mask = 15 << shift; ++ level &= mask; ++ ++ regno = regno < 8 ? PALLSW : PALMSW; ++ ++ pal = clps_readl(regno); ++ pal = (pal & ~mask) | level; ++ clps_writel(pal, regno); ++ ++ return 0; ++} ++ ++/* ++ * Set the colormap ++ */ ++static int ++clps7111fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, ++ struct fb_info *info) ++{ ++ struct clps7111fb_info *cfb = (struct clps7111fb_info *)info; ++ struct fb_cmap *dcmap = &fb_display[con].cmap; ++ int err = 0; ++ ++ /* no colormap allocated? */ ++ if (!dcmap->len) ++ err = fb_alloc_cmap(dcmap, CMAP_MAX_SIZE, 0); ++ ++ if (!err && con == cfb->currcon) { ++ err = fb_set_cmap(cmap, kspc, clps7111fb_setcolreg, &cfb->fb); ++ dcmap = &cfb->fb.cmap; ++ } ++ ++ if (!err) ++ fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1); ++ ++ return err; ++} ++ ++/* ++ * Set the User Defined Part of the Display ++ */ ++static int ++clps7111fb_set_var(struct fb_var_screeninfo *var, int con, ++ struct fb_info *info) ++{ ++ struct display *display; ++ unsigned int lcdcon, syscon, pixclock; ++ int chgvar = 0; ++ ++ if (var->activate & FB_ACTIVATE_TEST) ++ return 0; ++ ++ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) ++ return -EINVAL; ++ ++ if (cfb->fb.var.xres != var->xres) ++ chgvar = 1; ++ if (cfb->fb.var.yres != var->yres) ++ chgvar = 1; ++ if (cfb->fb.var.xres_virtual != var->xres_virtual) ++ chgvar = 1; ++ if (cfb->fb.var.yres_virtual != var->yres_virtual) ++ chgvar = 1; ++ if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel) ++ chgvar = 1; ++ ++ if (con < 0) { ++ display = cfb->fb.disp; ++ chgvar = 0; ++ } else { ++ display = fb_display + con; ++ } ++ ++ var->transp.msb_right = 0; ++ var->transp.offset = 0; ++ var->transp.length = 0; ++ var->red.msb_right = 0; ++ var->red.offset = 0; ++ var->red.length = var->bits_per_pixel; ++ var->green = var->red; ++ var->blue = var->red; ++ ++ switch (var->bits_per_pixel) { ++#ifdef FBCON_HAS_MFB ++ case 1: ++ cfb->fb.fix.visual = FB_VISUAL_MONO01; ++ display->dispsw = &fbcon_mfb; ++ display->dispsw_data = NULL; ++ break; ++#endif ++#ifdef FBCON_HAS_CFB2 ++ case 2: ++ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ display->dispsw = &fbcon_cfb2; ++ display->dispsw_data = NULL; ++ break; ++#endif ++#ifdef FBCON_HAS_CFB4 ++ case 4: ++ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ display->dispsw = &fbcon_cfb4; ++ display->dispsw_data = NULL; ++ break; ++#endif ++ default: ++ return -EINVAL; ++ } ++ ++ display->next_line = var->xres_virtual * var->bits_per_pixel / 8; ++ ++ cfb->fb.fix.line_length = display->next_line; ++ ++ display->screen_base = cfb->fb.screen_base; ++ display->line_length = cfb->fb.fix.line_length; ++ display->visual = cfb->fb.fix.visual; ++ display->type = cfb->fb.fix.type; ++ display->type_aux = cfb->fb.fix.type_aux; ++ display->ypanstep = cfb->fb.fix.ypanstep; ++ display->ywrapstep = cfb->fb.fix.ywrapstep; ++ display->can_soft_blank = 1; ++ display->inverse = 0; ++ ++ cfb->fb.var = *var; ++ cfb->fb.var.activate &= ~FB_ACTIVATE_ALL; ++ ++ /* ++ * Update the old var. The fbcon drivers still use this. ++ * Once they are using cfb->fb.var, this can be dropped. ++ * --rmk ++ */ ++ display->var = cfb->fb.var; ++ ++ /* ++ * If we are setting all the virtual consoles, also set the ++ * defaults used to create new consoles. ++ */ ++ if (var->activate & FB_ACTIVATE_ALL) ++ cfb->fb.disp->var = cfb->fb.var; ++ ++ if (chgvar && info && cfb->fb.changevar) ++ cfb->fb.changevar(con); ++ ++ lcdcon = (var->xres_virtual * var->yres_virtual * var->bits_per_pixel) / 128 - 1; ++ lcdcon |= ((var->xres_virtual / 16) - 1) << 13; ++ lcdcon |= lcd_ac_prescale << 25; ++ ++ /* ++ * Calculate pixel prescale value from the pixclock. This is: ++ * 36.864MHz / pixclock_mhz - 1. ++ * However, pixclock is in picoseconds, so this ends up being: ++ * 36864000 * pixclock_ps / 10^12 - 1 ++ * and this will overflow the 32-bit math. We perform this as ++ * (9 * 4096000 == 36864000): ++ * pixclock_ps * 9 * (4096000 / 10^12) - 1 ++ */ ++ pixclock = 9 * info->var.pixclock / 244140 - 1; ++ lcdcon |= pixclock << 19; ++ ++ if (info->var.bits_per_pixel == 4) ++ lcdcon |= LCDCON_GSMD; ++ if (info->var.bits_per_pixel >= 2) ++ lcdcon |= LCDCON_GSEN; ++ ++ /* ++ * LCDCON must only be changed while the LCD is disabled ++ */ ++ syscon = clps_readl(SYSCON1); ++ clps_writel(syscon & ~SYSCON1_LCDEN, SYSCON1); ++ clps_writel(lcdcon, LCDCON); ++ clps_writel(syscon | SYSCON1_LCDEN, SYSCON1); ++ ++ fb_set_cmap(&cfb->fb.cmap, 1, clps7111fb_setcolreg, &cfb->fb); ++ ++ return 0; ++} ++ ++/* ++ * Get the currently displayed virtual consoles colormap. ++ */ ++static int ++gen_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) ++{ ++ fb_copy_cmap(&info->cmap, cmap, kspc ? 0 : 2); ++ return 0; ++} ++ ++/* ++ * Get the currently displayed virtual consoles fixed part of the display. ++ */ ++static int ++gen_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) ++{ ++ *fix = info->fix; ++ return 0; ++} ++ ++/* ++ * Get the current user defined part of the display. ++ */ ++static int ++gen_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) ++{ ++ *var = info->var; ++ return 0; ++} ++ ++static struct fb_ops clps7111fb_ops = { ++ owner: THIS_MODULE, ++ fb_set_var: clps7111fb_set_var, ++ fb_set_cmap: clps7111fb_set_cmap, ++ fb_get_fix: gen_get_fix, ++ fb_get_var: gen_get_var, ++ fb_get_cmap: gen_get_cmap, ++}; ++ ++static int clps7111fb_switch(int con, struct fb_info *info) ++{ ++ struct clps7111fb_info *cfb = (struct clps7111fb_info *)info; ++ struct display *disp; ++ struct fb_cmap *cmap; ++ ++ if (cfb->currcon >= 0) { ++ disp = fb_display + cfb->currcon; ++ ++ /* ++ * Save the old colormap and video mode. ++ */ ++ disp->var = cfb->fb.var; ++ if (disp->cmap.len) ++ fb_copy_cmap(&cfb->fb.cmap, &disp->cmap, 0); ++ } ++ ++ cfb->currcon = con; ++ disp = fb_display + con; ++ ++ /* ++ * Install the new colormap and change the video mode. By default, ++ * fbcon sets all the colormaps and video modes to the default ++ * values at bootup. ++ */ ++ if (disp->cmap.len) ++ cmap = &disp->cmap; ++ else ++ cmap = fb_default_cmap(CMAP_MAX_SIZE); ++ ++ fb_copy_cmap(cmap, &cfb->fb.cmap, 0); ++ ++ cfb->fb.var = disp->var; ++ cfb->fb.var.activate = FB_ACTIVATE_NOW; ++ ++ clps7111fb_set_var(&cfb->fb.var, con, &cfb->fb); ++ ++ return 0; ++} ++ ++static int clps7111fb_updatevar(int con, struct fb_info *info) ++{ ++ return -EINVAL; ++} ++ ++static void clps7111fb_blank(int blank, struct fb_info *info) ++{ ++ if (blank) { ++ if (machine_is_edb7211()) { ++ /* Turn off the LCD backlight. */ ++ clps_writeb(clps_readb(PDDR) & ~EDB_PD3_LCDBL, PDDR); ++ ++ /* Power off the LCD DC-DC converter. */ ++ clps_writeb(clps_readb(PDDR) & ~EDB_PD1_LCD_DC_DC_EN, PDDR); ++ ++ /* Delay for a little while (half a second). */ ++ udelay(100); ++ ++ /* Power off the LCD panel. */ ++ clps_writeb(clps_readb(PDDR) & ~EDB_PD2_LCDEN, PDDR); ++ ++ /* Power off the LCD controller. */ ++ clps_writel(clps_readl(SYSCON1) & ~SYSCON1_LCDEN, ++ SYSCON1); ++ } ++ } else { ++ if (machine_is_edb7211()) { ++ /* Power up the LCD controller. */ ++ clps_writel(clps_readl(SYSCON1) | SYSCON1_LCDEN, ++ SYSCON1); ++ ++ /* Power up the LCD panel. */ ++ clps_writeb(clps_readb(PDDR) | EDB_PD2_LCDEN, PDDR); ++ ++ /* Delay for a little while. */ ++ udelay(100); ++ ++ /* Power up the LCD DC-DC converter. */ ++ clps_writeb(clps_readb(PDDR) | EDB_PD1_LCD_DC_DC_EN, ++ PDDR); ++ ++ /* Turn on the LCD backlight. */ ++ clps_writeb(clps_readb(PDDR) | EDB_PD3_LCDBL, PDDR); ++ } ++ } ++} ++ ++static int ++clps7111fb_proc_backlight_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ /* We need at least two characters, one for the digit, and one for ++ * the terminating NULL. */ ++ if (count < 2) ++ return -EINVAL; ++ ++ if (machine_is_edb7211()) { ++ return sprintf(page, "%d\n", ++ (clps_readb(PDDR) & EDB_PD3_LCDBL) ? 1 : 0); ++ } ++ ++ return 0; ++} ++ ++static int ++clps7111fb_proc_backlight_write(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ unsigned char char_value; ++ int value; ++ ++ if (count < 1) { ++ return -EINVAL; ++ } ++ ++ if (copy_from_user(&char_value, buffer, 1)) ++ return -EFAULT; ++ ++ value = char_value - '0'; ++ ++ if (machine_is_edb7211()) { ++ unsigned char port_d; ++ ++ port_d = clps_readb(PDDR); ++ ++ if (value) { ++ port_d |= EDB_PD3_LCDBL; ++ } else { ++ port_d &= ~EDB_PD3_LCDBL; ++ } ++ ++ clps_writeb(port_d, PDDR); ++ } ++ ++ return count; ++} ++ ++static void __init clps711x_guess_lcd_params(struct fb_info *info) ++{ ++ unsigned int lcdcon, syscon, size; ++ unsigned long phys_base = PHYS_OFFSET; ++ void *virt_base = (void *)PAGE_OFFSET; ++ ++ info->var.xres_virtual = 640; ++ info->var.yres_virtual = 240; ++ info->var.bits_per_pixel = 4; ++ info->var.activate = FB_ACTIVATE_NOW; ++ info->var.height = -1; ++ info->var.width = -1; ++ info->var.pixclock = 93006; /* 10.752MHz pixel clock */ ++ ++ /* ++ * If the LCD controller is already running, decode the values ++ * in LCDCON to xres/yres/bpp/pixclock/acprescale ++ */ ++ syscon = clps_readl(SYSCON1); ++ if (syscon & SYSCON1_LCDEN) { ++ lcdcon = clps_readl(LCDCON); ++ ++ /* ++ * Decode GSMD and GSEN bits to bits per pixel ++ * (in cs89712 docs, GSEN is GSMD1, GSMD is GSMD2) ++ */ ++ switch (lcdcon & (LCDCON_GSMD | LCDCON_GSEN)) { ++ case LCDCON_GSMD | LCDCON_GSEN: ++ info->var.bits_per_pixel = 4; ++ break; ++ ++ case LCDCON_GSEN: ++ info->var.bits_per_pixel = 2; ++ break; ++ ++ default: ++ info->var.bits_per_pixel = 1; ++ break; ++ } ++ ++ /* ++ * Decode xres/yres ++ */ ++ info->var.xres_virtual = (((lcdcon >> 13) & 0x3f) + 1) * 16; ++ info->var.yres_virtual = (((lcdcon & 0x1fff) + 1) * 128) / ++ (info->var.xres_virtual * ++ info->var.bits_per_pixel); ++ ++ /* ++ * Calculate pixclock ++ */ ++ info->var.pixclock = (((lcdcon >> 19) & 0x3f) + 1) * 244140 / 9; ++ ++ /* ++ * Grab AC prescale ++ */ ++ lcd_ac_prescale = (lcdcon >> 25) & 0x1f; ++ } ++ ++ info->var.xres = info->var.xres_virtual; ++ info->var.yres = info->var.yres_virtual; ++ info->var.grayscale = info->var.bits_per_pixel > 1; ++ ++ size = info->var.xres * info->var.yres * info->var.bits_per_pixel / 8; ++ ++ /* ++ * Might be worth checking to see if we can use the on-board ++ * RAM if size here... ++ * CLPS7110 - no on-board SRAM ++ * EP7212 - 38400 bytes ++ */ ++ if (size <= 38400) { ++ printk(KERN_INFO "CLPS711xFB: could use on-board SRAM?\n"); ++ } ++ ++ if ((syscon & SYSCON1_LCDEN) == 0) { ++ /* ++ * The display isn't running. Ensure that ++ * the display memory is empty. ++ */ ++ memset(virt_base, 0, size); ++ } ++ ++ info->screen_base = virt_base; ++ info->fix.smem_start = phys_base; ++ info->fix.smem_len = PAGE_ALIGN(size); ++ info->fix.type = FB_TYPE_PACKED_PIXELS; ++} ++ ++/* this function initializes the LCD registers as required by the Guide A07 ++*/ ++int __init clps711xfb_guidea07_init(void) ++{ ++ unsigned long videomem, videosize; ++ unsigned int lcdcon, syscon; ++ ++ //LCDCON must only be changed while the LCD is disabled ++ syscon = clps_readl(SYSCON1); ++ clps_writel(syscon & ~SYSCON1_LCDEN, SYSCON1); ++ ++ printk(KERN_INFO "CLPS711xFB: setting up cs89712 SRAM as QVGA video framebuffer\n"); ++ clps_writel(0x6, FBADDR); //internal SRAM location ++ videomem = (unsigned long)ioremap(SRAM_START, SRAM_SIZE); ++ if (!videomem) { ++ printk("ioremap failed!\n"); ++ kfree(cfb); ++ return -EIO; ++ } ++ ++ videosize = (320*240 * 4 / 8); //ie. 38400 or 0x9600 ++ memset((void *)videomem, 0, videosize); //clear the vid memory ++ ++ cfb->fb.screen_base = (void *)videomem; ++ cfb->fb.fix.smem_start = SRAM_START; //must be physical address ++ cfb->fb.fix.smem_len = videosize; ++ ++ cfb->fb.var.grayscale = 1; ++ cfb->fb.var.bits_per_pixel = 4; ++ cfb->fb.var.xres_virtual = 320; ++ cfb->fb.var.activate = FB_ACTIVATE_NOW; ++ ++ // change to 4bpp mode ++ lcdcon = clps_readl(LCDCON); ++ lcdcon |= LCDCON_GSMD | LCDCON_GSEN; //4bpp ++ //lcdcon |= 5 << 19; //pixel prescale value (pixclock) ++ //lcdcon |= 13 << 25; //AC prescale value ++ clps_writel(lcdcon, LCDCON); ++ ++ //reenable LCD ++ clps_writel(syscon | SYSCON1_LCDEN, SYSCON1); ++ ++ return 0; ++} ++ ++int __init clps711xfb_init(void) ++{ ++ int err = -ENOMEM; ++ ++ cfb = kmalloc(sizeof(*cfb) + sizeof(struct display), GFP_KERNEL); ++ if (!cfb) ++ goto out; ++ ++ memset(cfb, 0, sizeof(*cfb) + sizeof(struct display)); ++ strcpy(cfb->fb.fix.id, "clps7111"); ++ ++ cfb->currcon = -1; ++ cfb->fb.screen_base = (void *)PAGE_OFFSET; ++ cfb->fb.fix.smem_start = PAGE_OFFSET; ++ cfb->fb.fix.smem_len = 0x14000; ++ cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS; ++ ++ cfb->fb.fbops = &clps7111fb_ops; ++ cfb->fb.changevar = NULL; ++ cfb->fb.switch_con = clps7111fb_switch; ++ cfb->fb.updatevar = clps7111fb_updatevar; ++ cfb->fb.blank = clps7111fb_blank; ++ cfb->fb.flags = FBINFO_FLAG_DEFAULT; ++ cfb->fb.disp = (struct display *)(cfb + 1); ++ ++ clps711x_guess_lcd_params(&cfb->fb); ++ ++ if (machine_is_guidea07()) { ++ clps711xfb_guidea07_init(); ++ } ++ ++ if (machine_is_fortunet()) { ++ cfb->fb.fix.smem_len = 0x20000; ++ } ++ ++ fb_alloc_cmap(&cfb->fb.cmap, CMAP_MAX_SIZE, 0); ++ ++ /* Register the /proc entries. */ ++ clps7111fb_backlight_proc_entry = create_proc_entry("backlight", 0444, ++ &proc_root); ++ if (clps7111fb_backlight_proc_entry == NULL) { ++ printk("Couldn't create the /proc entry for the backlight.\n"); ++ return -EINVAL; ++ } ++ ++ clps7111fb_backlight_proc_entry->read_proc = ++ &clps7111fb_proc_backlight_read; ++ clps7111fb_backlight_proc_entry->write_proc = ++ &clps7111fb_proc_backlight_write; ++ ++ /* ++ * Power up the LCD ++ */ ++ if (machine_is_p720t()) { ++ PLD_LCDEN = PLD_LCDEN_EN; ++ PLD_PWR |= (PLD_S4_ON|PLD_S3_ON|PLD_S2_ON|PLD_S1_ON); ++ } ++ ++ if (machine_is_edb7211()) { ++ /* Power up the LCD panel. */ ++ clps_writeb(clps_readb(PDDR) | EDB_PD2_LCDEN, PDDR); ++ ++ /* Delay for a little while. */ ++ udelay(100); ++ ++ /* Power up the LCD DC-DC converter. */ ++ clps_writeb(clps_readb(PDDR) | EDB_PD1_LCD_DC_DC_EN, PDDR); ++ ++ /* Turn on the LCD backlight. */ ++ clps_writeb(clps_readb(PDDR) | EDB_PD3_LCDBL, PDDR); ++ } ++ ++ clps7111fb_set_var(&cfb->fb.var, -1, &cfb->fb); ++ err = register_framebuffer(&cfb->fb); ++ ++out: return err; ++} ++ ++static void __exit clps711xfb_exit(void) ++{ ++ unregister_framebuffer(&cfb->fb); ++ kfree(cfb); ++ ++ /* ++ * Power down the LCD ++ */ ++ if (machine_is_p720t()) { ++ PLD_LCDEN = 0; ++ PLD_PWR &= ~(PLD_S4_ON|PLD_S3_ON|PLD_S2_ON|PLD_S1_ON); ++ } ++} ++ ++#ifdef MODULE ++module_init(clps711xfb_init); ++#endif ++module_exit(clps711xfb_exit); ++ ++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); ++MODULE_DESCRIPTION("CLPS711x framebuffer driver"); ++MODULE_LICENSE("GPL"); +--- linux-2.4.25/drivers/video/cyber2000fb.c~2.4.25-vrs2.patch 2002-08-03 02:39:45.000000000 +0200 ++++ linux-2.4.25/drivers/video/cyber2000fb.c 2004-03-31 17:15:09.000000000 +0200 +@@ -1,7 +1,7 @@ + /* + * linux/drivers/video/cyber2000fb.c + * +- * Copyright (C) 1998-2000 Russell King ++ * Copyright (C) 1998-2002 Russell King + * + * MIPS and 50xx clock support + * Copyright (C) 2001 Bradley D. LaRonde <brad@ltc.com> +@@ -13,22 +13,28 @@ + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * +- * Intergraphics CyberPro 2000, 2010 and 5000 frame buffer device ++ * Integraphics CyberPro 2000, 2010 and 5000 frame buffer device + * + * Based on cyberfb.c. + * +- * Note that we now use the new fbcon fix, var and cmap scheme. We do still +- * have to check which console is the currently displayed one however, since +- * especially for the colourmap stuff. Once fbcon has been fully migrated, +- * we can kill the last 5 references to cfb->currcon. ++ * Note that we now use the new fbcon fix, var and cmap scheme. We do ++ * still have to check which console is the currently displayed one ++ * however, especially for the colourmap stuff. + * +- * We also use the new hotplug PCI subsystem. I'm not sure if there are any +- * such cards, but I'm erring on the side of caution. We don't want to go +- * pop just because someone does have one. ++ * We also use the new hotplug PCI subsystem. I'm not sure if there ++ * are any such cards, but I'm erring on the side of caution. We don't ++ * want to go pop just because someone does have one. + * +- * Note that this doesn't work fully in the case of multiple CyberPro cards +- * with grabbers. We currently can only attach to the first CyberPro card +- * found. ++ * Note that this doesn't work fully in the case of multiple CyberPro ++ * cards with grabbers. We currently can only attach to the first ++ * CyberPro card found. ++ * ++ * When we're in truecolour mode, we power down the LUT RAM as a power ++ * saving feature. Also, when we enter any of the powersaving modes ++ * (except soft blanking) we power down the RAMDACs. This saves about ++ * 1W, which is roughly 8% of the power consumption of a NetWinder ++ * (which, incidentally, is about the same saving as a 2.5in hard disk ++ * entering standby mode.) + */ + #include <linux/config.h> + #include <linux/module.h> +@@ -55,20 +61,16 @@ + #include <video/fbcon-cfb24.h> + #include <video/fbcon-cfb32.h> + +-/* +- * Define this if you don't want RGB565, but RGB555 for 16bpp displays. +- */ +-/*#define CFB16_IS_CFB15*/ +- + #include "cyber2000fb.h" + + struct cfb_info { + struct fb_info fb; + struct display_switch *dispsw; ++ struct display *display; + struct pci_dev *dev; + unsigned char *region; + unsigned char *regs; +- signed int currcon; ++ u_int id; + int func_use_count; + u_long ref_ps; + +@@ -81,10 +83,16 @@ + u8 red, green, blue; + } palette[NR_PALETTE]; + ++ u_char mem_ctl0; + u_char mem_ctl1; + u_char mem_ctl2; + u_char mclk_mult; + u_char mclk_div; ++ /* ++ * RAMDAC control register is both of these or'ed together ++ */ ++ u_char ramdac_ctrl; ++ u_char ramdac_powerdown; + }; + + static char default_font_storage[40]; +@@ -144,7 +152,7 @@ + { + int count = 100000; + +- while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & 0x80) { ++ while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & CO_CTRL_BUSY) { + if (!count--) { + debug_printf("accel_wait timed out\n"); + cyber2000fb_writeb(0, CO_REG_CONTROL, cfb); +@@ -154,24 +162,23 @@ + } + } + +-static void cyber2000_accel_setup(struct display *p) ++static void cyber2000_accel_setup(struct display *display) + { +- struct cfb_info *cfb = (struct cfb_info *)p->fb_info; ++ struct cfb_info *cfb = (struct cfb_info *)display->fb_info; + +- cfb->dispsw->setup(p); ++ cfb->dispsw->setup(display); + } + + static void +-cyber2000_accel_bmove(struct display *p, int sy, int sx, int dy, int dx, ++cyber2000_accel_bmove(struct display *display, int sy, int sx, int dy, int dx, + int height, int width) + { +- struct cfb_info *cfb = (struct cfb_info *)p->fb_info; +- struct fb_var_screeninfo *var = &p->fb_info->var; ++ struct cfb_info *cfb = (struct cfb_info *)display->fb_info; ++ struct fb_var_screeninfo *var = &display->var; + u_long src, dst; +- u_int fh, fw; +- int cmd = CO_CMD_L_PATTERN_FGCOL; ++ u_int fh, fw, cmd = CO_CMD_L_PATTERN_FGCOL; + +- fw = fontwidth(p); ++ fw = fontwidth(display); + sx *= fw; + dx *= fw; + width *= fw; +@@ -183,7 +190,7 @@ + cmd |= CO_CMD_L_INC_LEFT; + } + +- fh = fontheight(p); ++ fh = fontheight(display); + sy *= fh; + dy *= fh; + height *= fh; +@@ -199,227 +206,265 @@ + dst = dx + dy * var->xres_virtual; + + cyber2000_accel_wait(cfb); +- cyber2000fb_writeb(0x00, CO_REG_CONTROL, cfb); +- cyber2000fb_writeb(0x03, CO_REG_FORE_MIX, cfb); +- cyber2000fb_writew(width, CO_REG_WIDTH, cfb); ++ cyber2000fb_writeb(0x00, CO_REG_CONTROL, cfb); ++ cyber2000fb_writew(width, CO_REG_PIXWIDTH, cfb); ++ cyber2000fb_writew(height, CO_REG_PIXHEIGHT, cfb); + +- if (var->bits_per_pixel != 24) { +- cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb); +- cyber2000fb_writel(src, CO_REG_SRC_PTR, cfb); +- } else { +- cyber2000fb_writel(dst * 3, CO_REG_DEST_PTR, cfb); +- cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb); +- cyber2000fb_writel(src * 3, CO_REG_SRC_PTR, cfb); ++ if (var->bits_per_pixel == 24) { ++ cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb); ++ dst *= 3; ++ src *= 3; + } + +- cyber2000fb_writew(height, CO_REG_HEIGHT, cfb); +- cyber2000fb_writew(cmd, CO_REG_CMD_L, cfb); +- cyber2000fb_writew(0x2800, CO_REG_CMD_H, cfb); ++ cyber2000fb_writel(src, CO_REG_SRC1_PTR, cfb); ++ cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb); ++ cyber2000fb_writeb(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb); ++ cyber2000fb_writew(cmd, CO_REG_CMD_L, cfb); ++ cyber2000fb_writew(CO_CMD_H_FGSRCMAP|CO_CMD_H_BLITTER, CO_REG_CMD_H, cfb); + } + + static void +-cyber2000_accel_clear(struct vc_data *conp, struct display *p, int sy, int sx, +- int height, int width) ++cyber2000_accel_clear(struct vc_data *conp, struct display *display, int sy, ++ int sx, int height, int width) + { +- struct cfb_info *cfb = (struct cfb_info *)p->fb_info; +- struct fb_var_screeninfo *var = &p->fb_info->var; ++ struct cfb_info *cfb = (struct cfb_info *)display->fb_info; ++ struct fb_var_screeninfo *var = &display->var; + u_long dst; + u_int fw, fh; +- u32 bgx = attr_bgcol_ec(p, conp); ++ u32 bgx = attr_bgcol_ec(display, conp); + +- fw = fontwidth(p); +- fh = fontheight(p); ++ fw = fontwidth(display); ++ fh = fontheight(display); + + dst = sx * fw + sy * var->xres_virtual * fh; + width = width * fw - 1; + height = height * fh - 1; + + cyber2000_accel_wait(cfb); +- cyber2000fb_writeb(0x00, CO_REG_CONTROL, cfb); +- cyber2000fb_writeb(0x03, CO_REG_FORE_MIX, cfb); +- cyber2000fb_writew(width, CO_REG_WIDTH, cfb); +- cyber2000fb_writew(height, CO_REG_HEIGHT, cfb); +- +- switch (var->bits_per_pixel) { +- case 15: +- case 16: +- bgx = ((u16 *)p->dispsw_data)[bgx]; +- case 8: +- cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb); +- break; ++ cyber2000fb_writeb(0x00, CO_REG_CONTROL, cfb); ++ cyber2000fb_writew(width, CO_REG_PIXWIDTH, cfb); ++ cyber2000fb_writew(height, CO_REG_PIXHEIGHT, cfb); + +- case 24: +- cyber2000fb_writel(dst * 3, CO_REG_DEST_PTR, cfb); ++ if (var->bits_per_pixel == 24) { + cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb); +- bgx = ((u32 *)p->dispsw_data)[bgx]; +- break; +- +- case 32: +- bgx = ((u32 *)p->dispsw_data)[bgx]; +- cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb); +- break; ++ dst *= 3; + } + +- cyber2000fb_writel(bgx, CO_REG_FOREGROUND, cfb); ++ if (var->bits_per_pixel == 16) ++ bgx = ((u16 *)display->dispsw_data)[bgx]; ++ else if (var->bits_per_pixel >= 24) ++ bgx = ((u32 *)display->dispsw_data)[bgx]; ++ ++ cyber2000fb_writel(bgx, CO_REG_FGCOLOUR, cfb); ++ cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb); ++ cyber2000fb_writeb(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb); + cyber2000fb_writew(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L, cfb); +- cyber2000fb_writew(0x0800, CO_REG_CMD_H, cfb); ++ cyber2000fb_writew(CO_CMD_H_BLITTER, CO_REG_CMD_H, cfb); + } + + static void +-cyber2000_accel_putc(struct vc_data *conp, struct display *p, int c, ++cyber2000_accel_putc(struct vc_data *conp, struct display *display, int c, + int yy, int xx) + { +- struct cfb_info *cfb = (struct cfb_info *)p->fb_info; ++ struct cfb_info *cfb = (struct cfb_info *)display->fb_info; + + cyber2000_accel_wait(cfb); +- cfb->dispsw->putc(conp, p, c, yy, xx); ++ cfb->dispsw->putc(conp, display, c, yy, xx); + } + + static void +-cyber2000_accel_putcs(struct vc_data *conp, struct display *p, ++cyber2000_accel_putcs(struct vc_data *conp, struct display *display, + const unsigned short *s, int count, int yy, int xx) + { +- struct cfb_info *cfb = (struct cfb_info *)p->fb_info; ++ struct cfb_info *cfb = (struct cfb_info *)display->fb_info; + + cyber2000_accel_wait(cfb); +- cfb->dispsw->putcs(conp, p, s, count, yy, xx); ++ cfb->dispsw->putcs(conp, display, s, count, yy, xx); + } + +-static void cyber2000_accel_revc(struct display *p, int xx, int yy) ++static void cyber2000_accel_revc(struct display *display, int xx, int yy) + { +- struct cfb_info *cfb = (struct cfb_info *)p->fb_info; ++ struct cfb_info *cfb = (struct cfb_info *)display->fb_info; + + cyber2000_accel_wait(cfb); +- cfb->dispsw->revc(p, xx, yy); ++ cfb->dispsw->revc(display, xx, yy); + } + + static void +-cyber2000_accel_clear_margins(struct vc_data *conp, struct display *p, ++cyber2000_accel_clear_margins(struct vc_data *conp, struct display *display, + int bottom_only) + { +- struct cfb_info *cfb = (struct cfb_info *)p->fb_info; ++ struct cfb_info *cfb = (struct cfb_info *)display->fb_info; + +- cfb->dispsw->clear_margins(conp, p, bottom_only); ++ cfb->dispsw->clear_margins(conp, display, bottom_only); + } + + static struct display_switch fbcon_cyber_accel = { +- setup: cyber2000_accel_setup, +- bmove: cyber2000_accel_bmove, +- clear: cyber2000_accel_clear, +- putc: cyber2000_accel_putc, +- putcs: cyber2000_accel_putcs, +- revc: cyber2000_accel_revc, +- clear_margins: cyber2000_accel_clear_margins, +- fontwidthmask: FONTWIDTH(8)|FONTWIDTH(16) ++ .setup = cyber2000_accel_setup, ++ .bmove = cyber2000_accel_bmove, ++ .clear = cyber2000_accel_clear, ++ .putc = cyber2000_accel_putc, ++ .putcs = cyber2000_accel_putcs, ++ .revc = cyber2000_accel_revc, ++ .clear_margins = cyber2000_accel_clear_margins, ++ .fontwidthmask = FONTWIDTH(8)|FONTWIDTH(16) + }; + ++static inline u32 convert_bitfield(u_int val, struct fb_bitfield *bf) ++{ ++ u_int mask = (1 << bf->length) - 1; ++ ++ return (val >> (16 - bf->length) & mask) << bf->offset; ++} ++ + /* + * Set a single color register. Return != 0 for invalid regno. + */ + static int +-cyber2000_setcolreg(u_int regno, u_int red, u_int green, u_int blue, +- u_int transp, struct fb_info *info) ++cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ++ u_int transp, struct fb_info *info) + { + struct cfb_info *cfb = (struct cfb_info *)info; ++ struct fb_var_screeninfo *var = &cfb->display->var; ++ u32 pseudo_val; ++ int ret = 1; + +- u_int alpha = transp ^ 0xFFFF; +- +- if (regno >= NR_PALETTE) ++ switch (cfb->fb.fix.visual) { ++ default: + return 1; + +- red >>= 8; +- green >>= 8; +- blue >>= 8; +- alpha >>= 8; ++#ifdef FBCON_HAS_CFB8 ++ /* ++ * Pseudocolour: ++ * 8 8 ++ * pixel --/--+--/--> red lut --> red dac ++ * | 8 ++ * +--/--> green lut --> green dac ++ * | 8 ++ * +--/--> blue lut --> blue dac ++ */ ++ case FB_VISUAL_PSEUDOCOLOR: ++ if (regno >= NR_PALETTE) ++ return 1; + +- cfb->palette[regno].red = red; +- cfb->palette[regno].green = green; +- cfb->palette[regno].blue = blue; ++ red >>= 8; ++ green >>= 8; ++ blue >>= 8; ++ ++ cfb->palette[regno].red = red; ++ cfb->palette[regno].green = green; ++ cfb->palette[regno].blue = blue; + +- switch (cfb->fb.var.bits_per_pixel) { +-#ifdef FBCON_HAS_CFB8 +- case 8: + cyber2000fb_writeb(regno, 0x3c8, cfb); +- cyber2000fb_writeb(red, 0x3c9, cfb); ++ cyber2000fb_writeb(red, 0x3c9, cfb); + cyber2000fb_writeb(green, 0x3c9, cfb); +- cyber2000fb_writeb(blue, 0x3c9, cfb); +- break; ++ cyber2000fb_writeb(blue, 0x3c9, cfb); ++ return 0; + #endif + +-#ifdef FBCON_HAS_CFB16 +- case 16: +-#ifndef CFB16_IS_CFB15 +- if (regno < 64) { +- /* write green */ ++ /* ++ * Direct colour: ++ * n rl ++ * pixel --/--+--/--> red lut --> red dac ++ * | gl ++ * +--/--> green lut --> green dac ++ * | bl ++ * +--/--> blue lut --> blue dac ++ * n = bpp, rl = red length, gl = green length, bl = blue length ++ */ ++ case FB_VISUAL_DIRECTCOLOR: ++ red >>= 8; ++ green >>= 8; ++ blue >>= 8; ++ ++ if (var->green.length == 6 && regno < 64) { ++ cfb->palette[regno << 2].green = green; ++ ++ /* ++ * The 6 bits of the green component are applied ++ * to the high 6 bits of the LUT. ++ */ + cyber2000fb_writeb(regno << 2, 0x3c8, cfb); + cyber2000fb_writeb(cfb->palette[regno >> 1].red, 0x3c9, cfb); + cyber2000fb_writeb(green, 0x3c9, cfb); + cyber2000fb_writeb(cfb->palette[regno >> 1].blue, 0x3c9, cfb); ++ ++ green = cfb->palette[regno << 3].green; ++ ++ ret = 0; + } + +- if (regno < 32) { +- /* write red,blue */ ++ if (var->green.length >= 5 && regno < 32) { ++ cfb->palette[regno << 3].red = red; ++ cfb->palette[regno << 3].green = green; ++ cfb->palette[regno << 3].blue = blue; ++ ++ /* ++ * The 5 bits of each colour component are ++ * applied to the high 5 bits of the LUT. ++ */ + cyber2000fb_writeb(regno << 3, 0x3c8, cfb); + cyber2000fb_writeb(red, 0x3c9, cfb); +- cyber2000fb_writeb(cfb->palette[regno << 1].green, 0x3c9, cfb); ++ cyber2000fb_writeb(green, 0x3c9, cfb); + cyber2000fb_writeb(blue, 0x3c9, cfb); ++ ret = 0; + } + +- if (regno < 16) +- ((u16 *)cfb->fb.pseudo_palette)[regno] = +- ((red << 8) & 0xf800) | +- ((green << 3) & 0x07e0) | +- ((blue >> 3)); +- break; +-#endif ++ if (var->green.length == 4 && regno < 16) { ++ cfb->palette[regno << 4].red = red; ++ cfb->palette[regno << 4].green = green; ++ cfb->palette[regno << 4].blue = blue; + +- case 15: +- if (regno < 32) { +- cyber2000fb_writeb(regno << 3, 0x3c8, cfb); ++ /* ++ * The 5 bits of each colour component are ++ * applied to the high 5 bits of the LUT. ++ */ ++ cyber2000fb_writeb(regno << 4, 0x3c8, cfb); + cyber2000fb_writeb(red, 0x3c9, cfb); + cyber2000fb_writeb(green, 0x3c9, cfb); + cyber2000fb_writeb(blue, 0x3c9, cfb); ++ ret = 0; + } +- if (regno < 16) +- ((u16 *)cfb->fb.pseudo_palette)[regno] = +- ((red << 7) & 0x7c00) | +- ((green << 2) & 0x03e0) | +- ((blue >> 3)); +- break; +- +-#endif +- +-#ifdef FBCON_HAS_CFB24 +- case 24: +- cyber2000fb_writeb(regno, 0x3c8, cfb); +- cyber2000fb_writeb(red, 0x3c9, cfb); +- cyber2000fb_writeb(green, 0x3c9, cfb); +- cyber2000fb_writeb(blue, 0x3c9, cfb); + +- if (regno < 16) +- ((u32 *)cfb->fb.pseudo_palette)[regno] = +- (red << 16) | (green << 8) | blue; ++ /* ++ * Since this is only used for the first 16 colours, we ++ * don't have to care about overflowing for regno >= 32 ++ */ ++ pseudo_val = regno << var->red.offset | ++ regno << var->green.offset | ++ regno << var->blue.offset; + break; +-#endif + +-#ifdef FBCON_HAS_CFB32 +- case 32: +- cyber2000fb_writeb(regno, 0x3c8, cfb); +- cyber2000fb_writeb(red, 0x3c9, cfb); +- cyber2000fb_writeb(green, 0x3c9, cfb); +- cyber2000fb_writeb(blue, 0x3c9, cfb); +- +- if (regno < 16) +- ((u32 *)cfb->fb.pseudo_palette)[regno] = +- (alpha << 24) | (red << 16) | (green << 8) | blue; ++ /* ++ * True colour: ++ * n rl ++ * pixel --/--+--/--> red dac ++ * | gl ++ * +--/--> green dac ++ * | bl ++ * +--/--> blue dac ++ * n = bpp, rl = red length, gl = green length, bl = blue length ++ */ ++ case FB_VISUAL_TRUECOLOR: ++ pseudo_val = convert_bitfield(transp ^ 0xffff, &var->transp); ++ pseudo_val |= convert_bitfield(red, &var->red); ++ pseudo_val |= convert_bitfield(green, &var->green); ++ pseudo_val |= convert_bitfield(blue, &var->blue); + break; +-#endif ++ } + +- default: +- return 1; ++ /* ++ * Now set our pseudo palette for the CFB16/24/32 drivers. ++ */ ++ if (regno < 16) { ++ if (var->bits_per_pixel == 16) ++ ((u16 *)cfb->fb.pseudo_palette)[regno] = pseudo_val; ++ else ++ ((u32 *)cfb->fb.pseudo_palette)[regno] = pseudo_val; ++ ret = 0; + } + +- return 0; ++ return ret; + } + + struct par_info { +@@ -428,8 +473,8 @@ + */ + u_char clock_mult; + u_char clock_div; +- u_char visualid; +- u_char pixformat; ++ u_char extseqmisc; ++ u_char co_pixfmt; + u_char crtc_ofl; + u_char crtc[19]; + u_int width; +@@ -439,8 +484,7 @@ + /* + * Other + */ +- u_char palette_ctrl; +- u_int vmode; ++ u_char ramdac; + }; + + static const u_char crtc_idx[] = { +@@ -449,6 +493,18 @@ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 + }; + ++static void cyber2000fb_write_ramdac_ctrl(struct cfb_info *cfb) ++{ ++ unsigned int i; ++ unsigned int val = cfb->ramdac_ctrl | cfb->ramdac_powerdown; ++ ++ cyber2000fb_writeb(0x56, 0x3ce, cfb); ++ i = cyber2000fb_readb(0x3cf, cfb); ++ cyber2000fb_writeb(i | 4, 0x3cf, cfb); ++ cyber2000fb_writeb(val, 0x3c6, cfb); ++ cyber2000fb_writeb(i, 0x3cf, cfb); ++} ++ + static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw) + { + u_int i; +@@ -480,7 +536,7 @@ + for (i = 0x0a; i < 0x10; i++) + cyber2000_crtcw(i, 0, cfb); + +- cyber2000_grphw(0x11, hw->crtc_ofl, cfb); ++ cyber2000_grphw(EXT_CRT_VRTOFL, hw->crtc_ofl, cfb); + cyber2000_grphw(0x00, 0x00, cfb); + cyber2000_grphw(0x01, 0x00, cfb); + cyber2000_grphw(0x02, 0x00, cfb); +@@ -501,30 +557,17 @@ + cyber2000_attrw(0x13, 0x00, cfb); + cyber2000_attrw(0x14, 0x00, cfb); + +- /* woody: set the interlaced bit... */ +- /* FIXME: what about doublescan? */ +- cyber2000fb_writeb(0x11, 0x3ce, cfb); +- i = cyber2000fb_readb(0x3cf, cfb); +- if (hw->vmode == FB_VMODE_INTERLACED) +- i |= 0x20; +- else +- i &= ~0x20; +- cyber2000fb_writeb(i, 0x3cf, cfb); +- + /* PLL registers */ +- cyber2000_grphw(DCLK_MULT, hw->clock_mult, cfb); +- cyber2000_grphw(DCLK_DIV, hw->clock_div, cfb); +- cyber2000_grphw(MCLK_MULT, cfb->mclk_mult, cfb); +- cyber2000_grphw(MCLK_DIV, cfb->mclk_div, cfb); ++ cyber2000_grphw(EXT_DCLK_MULT, hw->clock_mult, cfb); ++ cyber2000_grphw(EXT_DCLK_DIV, hw->clock_div, cfb); ++ cyber2000_grphw(EXT_MCLK_MULT, cfb->mclk_mult, cfb); ++ cyber2000_grphw(EXT_MCLK_DIV, cfb->mclk_div, cfb); + cyber2000_grphw(0x90, 0x01, cfb); + cyber2000_grphw(0xb9, 0x80, cfb); + cyber2000_grphw(0xb9, 0x00, cfb); + +- cyber2000fb_writeb(0x56, 0x3ce, cfb); +- i = cyber2000fb_readb(0x3cf, cfb); +- cyber2000fb_writeb(i | 4, 0x3cf, cfb); +- cyber2000fb_writeb(hw->palette_ctrl, 0x3c6, cfb); +- cyber2000fb_writeb(i, 0x3cf, cfb); ++ cfb->ramdac_ctrl = hw->ramdac; ++ cyber2000fb_write_ramdac_ctrl(cfb); + + cyber2000fb_writeb(0x20, 0x3c0, cfb); + cyber2000fb_writeb(0xff, 0x3c6, cfb); +@@ -532,31 +575,32 @@ + cyber2000_grphw(0x14, hw->fetch, cfb); + cyber2000_grphw(0x15, ((hw->fetch >> 8) & 0x03) | + ((hw->pitch >> 4) & 0x30), cfb); +- cyber2000_grphw(0x77, hw->visualid, cfb); ++ cyber2000_grphw(EXT_SEQ_MISC, hw->extseqmisc, cfb); + +- /* make sure we stay in linear mode */ +- cyber2000_grphw(0x33, 0x0d, cfb); ++// cyber2000_grphw(EXT_BIU_MISC, EXT_BIU_MISC_LIN_ENABLE | ++// EXT_BIU_MISC_COP_ENABLE | ++// EXT_BIU_MISC_COP_BFC, cfb); + + /* + * Set up accelerator registers + */ + cyber2000fb_writew(hw->width, CO_REG_SRC_WIDTH, cfb); + cyber2000fb_writew(hw->width, CO_REG_DEST_WIDTH, cfb); +- cyber2000fb_writeb(hw->pixformat, CO_REG_PIX_FORMAT, cfb); ++ cyber2000fb_writeb(hw->co_pixfmt, CO_REG_PIXFMT, cfb); + } + + static inline int + cyber2000fb_update_start(struct cfb_info *cfb, struct fb_var_screeninfo *var) + { +- u_int base; +- +- base = var->yoffset * var->xres_virtual + var->xoffset; ++ u_int base = var->yoffset * var->xres_virtual + var->xoffset; + +- /* have to be careful, because bits_per_pixel might be 15 +- in this version of the driver -- dok@directfb.org 2002/06/13 */ +- base *= (var->bits_per_pixel + 7) >> 3; ++ base *= var->bits_per_pixel; + +- base >>= 2; ++ /* ++ * Convert to bytes and shift two extra bits because DAC ++ * can only start on 4 byte aligned data. ++ */ ++ base >>= 5; + + if (base >= 1 << 20) + return -EINVAL; +@@ -576,27 +620,20 @@ + struct fb_info *info) + { + struct cfb_info *cfb = (struct cfb_info *)info; +- struct fb_cmap *dcmap = &fb_display[con].cmap; ++ struct display *display = fb_display + con; ++ struct fb_cmap *dcmap = &display->cmap; + int err = 0; + + /* no colormap allocated? */ +- if (!dcmap->len) { +- int size; +- +- if (cfb->fb.var.bits_per_pixel == 16) +- size = 32; +- else +- size = 256; +- +- err = fb_alloc_cmap(dcmap, size, 0); +- } ++ if (!dcmap->len) ++ err = fb_alloc_cmap(dcmap, 256, 0); + + /* + * we should be able to remove this test once fbcon has been + * "improved" --rmk + */ +- if (!err && con == cfb->currcon) { +- err = fb_set_cmap(cmap, kspc, cyber2000_setcolreg, &cfb->fb); ++ if (!err && display == cfb->display) { ++ err = fb_set_cmap(cmap, kspc, cyber2000fb_setcolreg, &cfb->fb); + dcmap = &cfb->fb.cmap; + } + +@@ -672,8 +709,9 @@ + hw->crtc[16] = Vblankend; + hw->crtc[18] = 0xff; + +- /* overflow - graphics reg 0x11 */ +- /* 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10 ++ /* ++ * overflow - graphics reg 0x11 ++ * 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10 + * 4=LINECOMP:10 5-IVIDEO 6=FIXCNT + */ + hw->crtc_ofl = +@@ -681,7 +719,12 @@ + BIT(Vdispend, 10, 0x01, 1) | + BIT(Vsyncstart, 10, 0x01, 2) | + BIT(Vblankstart,10, 0x01, 3) | +- 1 << 4; ++ EXT_CRT_VRTOFL_LINECOMP10; ++ ++ /* woody: set the interlaced bit... */ ++ /* FIXME: what about doublescan? */ ++ if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) ++ hw->crtc_ofl |= EXT_CRT_VRTOFL_INTERLACE; + + return 0; + } +@@ -787,7 +830,7 @@ + vco = ref_ps * best_div1 / best_mult; + if ((ref_ps == 40690) && (vco < 5556)) + /* Set VFSEL when VCO > 180MHz (5.556 ps). */ +- hw->clock_div |= DCLK_DIV_VFSEL; ++ hw->clock_div |= EXT_DCLK_DIV_VFSEL; + + return 0; + } +@@ -801,58 +844,131 @@ + cyber2000fb_decode_var(struct fb_var_screeninfo *var, struct cfb_info *cfb, + struct par_info *hw) + { ++ unsigned int mem; + int err; + + hw->width = var->xres_virtual; +- hw->palette_ctrl = 0x06; +- hw->vmode = var->vmode; ++ hw->ramdac = RAMDAC_VREFEN | RAMDAC_DAC8BIT; ++ ++ var->transp.msb_right = 0; ++ var->red.msb_right = 0; ++ var->green.msb_right = 0; ++ var->blue.msb_right = 0; + + switch (var->bits_per_pixel) { + #ifdef FBCON_HAS_CFB8 + case 8: /* PSEUDOCOLOUR, 256 */ +- hw->pixformat = PIXFORMAT_8BPP; +- hw->visualid = VISUALID_256; ++ hw->co_pixfmt = CO_PIXFMT_8BPP; + hw->pitch = hw->width >> 3; ++ hw->extseqmisc = EXT_SEQ_MISC_8; ++ ++ var->transp.offset = 0; ++ var->transp.length = 0; ++ var->red.offset = 0; ++ var->red.length = 8; ++ var->green.offset = 0; ++ var->green.length = 8; ++ var->blue.offset = 0; ++ var->blue.length = 8; + break; + #endif + #ifdef FBCON_HAS_CFB16 +- case 16:/* DIRECTCOLOUR, 64k */ +-#ifndef CFB16_IS_CFB15 +- hw->pixformat = PIXFORMAT_16BPP; +- hw->visualid = VISUALID_64K; +- hw->pitch = hw->width >> 2; +- hw->palette_ctrl |= 0x10; +- break; +-#endif +- case 15:/* DIRECTCOLOUR, 32k */ +- hw->pixformat = PIXFORMAT_16BPP; +- hw->visualid = VISUALID_32K; ++ case 16:/* DIRECTCOLOUR, 64k or 32k */ ++ hw->co_pixfmt = CO_PIXFMT_16BPP; + hw->pitch = hw->width >> 2; +- hw->palette_ctrl |= 0x10; +- break; + ++ switch (var->green.length) { ++ case 6: /* RGB565, 64k */ ++ hw->extseqmisc = EXT_SEQ_MISC_16_RGB565; ++ ++ var->transp.offset = 0; ++ var->transp.length = 0; ++ var->red.offset = 11; ++ var->red.length = 5; ++ var->green.offset = 5; ++ var->green.length = 6; ++ var->blue.offset = 0; ++ var->blue.length = 5; ++ break; ++ ++ default: ++ case 5: /* RGB555, 32k */ ++ hw->extseqmisc = EXT_SEQ_MISC_16_RGB555; ++ ++ var->transp.offset = 0; ++ var->transp.length = 0; ++ var->red.offset = 10; ++ var->red.length = 5; ++ var->green.offset = 5; ++ var->green.length = 5; ++ var->blue.offset = 0; ++ var->blue.length = 5; ++ break; ++ ++ case 4: /* RGB444, 4k + transparency? */ ++ hw->extseqmisc = EXT_SEQ_MISC_16_RGB444; ++ ++ var->transp.offset = 12; ++ var->transp.length = 4; ++ var->red.offset = 8; ++ var->red.length = 4; ++ var->green.offset = 4; ++ var->green.length = 4; ++ var->blue.offset = 0; ++ var->blue.length = 4; ++ break; ++ } ++ break; + #endif + #ifdef FBCON_HAS_CFB24 + case 24:/* TRUECOLOUR, 16m */ +- hw->pixformat = PIXFORMAT_24BPP; +- hw->visualid = VISUALID_16M; ++ hw->co_pixfmt = CO_PIXFMT_24BPP; + hw->width *= 3; + hw->pitch = hw->width >> 3; +- hw->palette_ctrl |= 0x10; ++ hw->ramdac |= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN); ++ hw->extseqmisc = EXT_SEQ_MISC_24_RGB888; ++ ++ var->transp.offset = 0; ++ var->transp.length = 0; ++ var->red.offset = 16; ++ var->red.length = 8; ++ var->green.offset = 8; ++ var->green.length = 8; ++ var->blue.offset = 0; ++ var->blue.length = 8; + break; + #endif + #ifdef FBCON_HAS_CFB32 + case 32:/* TRUECOLOUR, 16m */ +- hw->pixformat = PIXFORMAT_32BPP; +- hw->visualid = VISUALID_16M_32; ++ hw->co_pixfmt = CO_PIXFMT_32BPP; + hw->pitch = hw->width >> 1; +- hw->palette_ctrl |= 0x10; ++ hw->ramdac |= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN); ++ hw->extseqmisc = EXT_SEQ_MISC_32; ++ ++ var->transp.offset = 24; ++ var->transp.length = 8; ++ var->red.offset = 16; ++ var->red.length = 8; ++ var->green.offset = 8; ++ var->green.length = 8; ++ var->blue.offset = 0; ++ var->blue.length = 8; + break; + #endif + default: + return -EINVAL; + } + ++ mem = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8); ++ if (mem > cfb->fb.fix.smem_len) ++ var->yres_virtual = cfb->fb.fix.smem_len * 8 / ++ (var->bits_per_pixel * var->xres_virtual); ++ ++ if (var->yres > var->yres_virtual) ++ var->yres = var->yres_virtual; ++ if (var->xres > var->xres_virtual) ++ var->xres = var->xres_virtual; ++ + err = cyber2000fb_decode_clock(hw, cfb, var); + if (err) + return err; +@@ -880,7 +996,7 @@ + struct cfb_info *cfb = (struct cfb_info *)info; + struct display *display; + struct par_info hw; +- int err, chgvar = 0; ++ int err, chgvar; + + /* + * CONUPDATE and SMOOTH_XPAN are equal. However, +@@ -888,11 +1004,11 @@ + */ + if (var->vmode & FB_VMODE_CONUPDATE) { + var->vmode |= FB_VMODE_YWRAP; +- var->xoffset = cfb->fb.var.xoffset; +- var->yoffset = cfb->fb.var.yoffset; ++ var->xoffset = cfb->display->var.xoffset; ++ var->yoffset = cfb->display->var.yoffset; + } + +- err = cyber2000fb_decode_var(var, (struct cfb_info *)info, &hw); ++ err = cyber2000fb_decode_var(var, cfb, &hw); + if (err) + return err; + +@@ -902,105 +1018,61 @@ + if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) + return -EINVAL; + +- if (cfb->fb.var.xres != var->xres) +- chgvar = 1; +- if (cfb->fb.var.yres != var->yres) +- chgvar = 1; +- if (cfb->fb.var.xres_virtual != var->xres_virtual) +- chgvar = 1; +- if (cfb->fb.var.yres_virtual != var->yres_virtual) +- chgvar = 1; +- if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel) +- chgvar = 1; +- + if (con < 0) { + display = cfb->fb.disp; +- chgvar = 0; + } else { + display = fb_display + con; + } + +- var->red.msb_right = 0; +- var->green.msb_right = 0; +- var->blue.msb_right = 0; ++ chgvar = cfb->fb.var.xres != var->xres || ++ cfb->fb.var.yres != var->yres || ++ cfb->fb.var.xres_virtual != var->xres_virtual || ++ cfb->fb.var.yres_virtual != var->yres_virtual || ++ cfb->fb.var.bits_per_pixel != var->bits_per_pixel; ++ ++ if (memcmp(&cfb->fb.var.red, &var->red, sizeof(var->red)) || ++ memcmp(&cfb->fb.var.green, &var->green, sizeof(var->green)) || ++ memcmp(&cfb->fb.var.blue, &var->blue, sizeof(var->blue))) ++ chgvar = 1; ++ ++ if (con < 0) ++ chgvar = 0; ++ ++ /* ++ * If we are setting all the virtual consoles, also set the ++ * defaults used to create new consoles. ++ */ ++ err = var->activate; ++ var->activate = FB_ACTIVATE_NOW; ++ if (err & FB_ACTIVATE_ALL) ++ cfb->fb.disp->var = *var; ++ ++ cfb->fb.var = *var; ++ cfb->fb.fix.line_length = var->xres_virtual * var->bits_per_pixel / 8; + + switch (var->bits_per_pixel) { + #ifdef FBCON_HAS_CFB8 + case 8: /* PSEUDOCOLOUR, 256 */ +- var->red.offset = 0; +- var->red.length = 8; +- var->green.offset = 0; +- var->green.length = 8; +- var->blue.offset = 0; +- var->blue.length = 8; +- +- cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; + cfb->dispsw = &fbcon_cfb8; + display->dispsw_data = NULL; +- display->next_line = var->xres_virtual; + break; + #endif + #ifdef FBCON_HAS_CFB16 +- case 16:/* DIRECTCOLOUR, 64k */ +-#ifndef CFB16_IS_CFB15 +- var->red.offset = 11; +- var->red.length = 5; +- var->green.offset = 5; +- var->green.length = 6; +- var->blue.offset = 0; +- var->blue.length = 5; +- +- cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR; ++ case 16:/* DIRECTCOLOUR */ + cfb->dispsw = &fbcon_cfb16; + display->dispsw_data = cfb->fb.pseudo_palette; +- display->next_line = var->xres_virtual * 2; +- break; +-#endif +- case 15:/* DIRECTCOLOUR, 32k */ +- var->bits_per_pixel = 15; +- var->red.offset = 10; +- var->red.length = 5; +- var->green.offset = 5; +- var->green.length = 5; +- var->blue.offset = 0; +- var->blue.length = 5; +- +- cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR; +- cfb->dispsw = &fbcon_cfb16; +- display->dispsw_data = cfb->fb.pseudo_palette; +- display->next_line = var->xres_virtual * 2; + break; + #endif + #ifdef FBCON_HAS_CFB24 + case 24:/* TRUECOLOUR, 16m */ +- var->red.offset = 16; +- var->red.length = 8; +- var->green.offset = 8; +- var->green.length = 8; +- var->blue.offset = 0; +- var->blue.length = 8; +- +- cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; + cfb->dispsw = &fbcon_cfb24; + display->dispsw_data = cfb->fb.pseudo_palette; +- display->next_line = var->xres_virtual * 3; + break; + #endif + #ifdef FBCON_HAS_CFB32 + case 32:/* TRUECOLOUR, 16m */ +- var->transp.offset = 24; +- var->transp.length = 8; +- var->red.offset = 16; +- var->red.length = 8; +- var->green.offset = 8; +- var->green.length = 8; +- var->blue.offset = 0; +- var->blue.length = 8; +- +- cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; + cfb->dispsw = &fbcon_cfb32; + display->dispsw_data = cfb->fb.pseudo_palette; +- display->next_line = var->xres_virtual * 4; + break; + #endif + default:/* in theory this should never happen */ +@@ -1010,15 +1082,27 @@ + break; + } + ++ /* ++ * 8bpp displays are always pseudo colour. ++ * 16bpp and above are direct colour or true colour, depending ++ * on whether the RAMDAC palettes are bypassed. (Direct colour ++ * has palettes, true colour does not.) ++ */ ++ if (var->bits_per_pixel == 8) ++ cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ else if (hw.ramdac & RAMDAC_BYPASS) ++ cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; ++ else ++ cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR; ++ + if (var->accel_flags & FB_ACCELF_TEXT && cfb->dispsw != &fbcon_dummy) + display->dispsw = &fbcon_cyber_accel; + else + display->dispsw = cfb->dispsw; + +- cfb->fb.fix.line_length = display->next_line; +- + display->screen_base = cfb->fb.screen_base; + display->line_length = cfb->fb.fix.line_length; ++ display->next_line = cfb->fb.fix.line_length; + display->visual = cfb->fb.fix.visual; + display->type = cfb->fb.fix.type; + display->type_aux = cfb->fb.fix.type_aux; +@@ -1026,31 +1110,15 @@ + display->ywrapstep = cfb->fb.fix.ywrapstep; + display->can_soft_blank = 1; + display->inverse = 0; ++ display->var = *var; + +- cfb->fb.var = *var; +- cfb->fb.var.activate &= ~FB_ACTIVATE_ALL; +- +- /* +- * Update the old var. The fbcon drivers still use this. +- * Once they are using cfb->fb.var, this can be dropped. +- * --rmk +- */ +- display->var = cfb->fb.var; +- +- /* +- * If we are setting all the virtual consoles, also set the +- * defaults used to create new consoles. +- */ +- if (var->activate & FB_ACTIVATE_ALL) +- cfb->fb.disp->var = cfb->fb.var; ++ cyber2000fb_set_timing(cfb, &hw); ++ cyber2000fb_update_start(cfb, var); ++ fb_set_cmap(&cfb->fb.cmap, 1, cyber2000fb_setcolreg, &cfb->fb); + +- if (chgvar && info && cfb->fb.changevar) ++ if (chgvar && cfb->fb.changevar) + cfb->fb.changevar(con); + +- cyber2000fb_update_start(cfb, var); +- cyber2000fb_set_timing(cfb, &hw); +- fb_set_cmap(&cfb->fb.cmap, 1, cyber2000_setcolreg, &cfb->fb); +- + return 0; + } + +@@ -1072,18 +1140,18 @@ + + if (var->xoffset > (var->xres_virtual - var->xres)) + return -EINVAL; +- if (y_bottom > cfb->fb.var.yres_virtual) ++ if (y_bottom > cfb->display->var.yres_virtual) + return -EINVAL; + + if (cyber2000fb_update_start(cfb, var)) + return -EINVAL; + +- cfb->fb.var.xoffset = var->xoffset; +- cfb->fb.var.yoffset = var->yoffset; ++ cfb->display->var.xoffset = var->xoffset; ++ cfb->display->var.yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) { +- cfb->fb.var.vmode |= FB_VMODE_YWRAP; ++ cfb->display->var.vmode |= FB_VMODE_YWRAP; + } else { +- cfb->fb.var.vmode &= ~FB_VMODE_YWRAP; ++ cfb->display->var.vmode &= ~FB_VMODE_YWRAP; + } + + return 0; +@@ -1106,22 +1174,18 @@ + static int cyber2000fb_switch(int con, struct fb_info *info) + { + struct cfb_info *cfb = (struct cfb_info *)info; +- struct display *disp; ++ struct display *display = cfb->display; + struct fb_cmap *cmap; + +- if (cfb->currcon >= 0) { +- disp = fb_display + cfb->currcon; +- ++ if (display) { + /* + * Save the old colormap and video mode. + */ +- disp->var = cfb->fb.var; +- if (disp->cmap.len) +- fb_copy_cmap(&cfb->fb.cmap, &disp->cmap, 0); ++ if (display->cmap.len) ++ fb_copy_cmap(&cfb->fb.cmap, &display->cmap, 0); + } + +- cfb->currcon = con; +- disp = fb_display + con; ++ cfb->display = display = fb_display + con; + + /* + * Install the new colormap and change the video mode. By default, +@@ -1132,73 +1196,88 @@ + * depth of the new video mode. For now, we leave it at its + * default 256 entry. + */ +- if (disp->cmap.len) +- cmap = &disp->cmap; ++ if (display->cmap.len) ++ cmap = &display->cmap; + else +- cmap = fb_default_cmap(1 << disp->var.bits_per_pixel); ++ cmap = fb_default_cmap(1 << display->var.bits_per_pixel); + + fb_copy_cmap(cmap, &cfb->fb.cmap, 0); + +- cfb->fb.var = disp->var; +- cfb->fb.var.activate = FB_ACTIVATE_NOW; +- +- cyber2000fb_set_var(&cfb->fb.var, con, &cfb->fb); ++ display->var.activate = FB_ACTIVATE_NOW; ++ cyber2000fb_set_var(&display->var, con, &cfb->fb); + + return 0; + } + + /* + * (Un)Blank the display. ++ * ++ * Blank the screen if blank_mode != 0, else unblank. If ++ * blank == NULL then the caller blanks by setting the CLUT ++ * (Color Look Up Table) to all black. Return 0 if blanking ++ * succeeded, != 0 if un-/blanking failed due to e.g. a ++ * video mode which doesn't support it. Implements VESA ++ * suspend and powerdown modes on hardware that supports ++ * disabling hsync/vsync: ++ * blank_mode == 2: suspend vsync ++ * blank_mode == 3: suspend hsync ++ * blank_mode == 4: powerdown ++ * ++ * wms...Enable VESA DMPS compatible powerdown mode ++ * run "setterm -powersave powerdown" to take advantage + */ + static void cyber2000fb_blank(int blank, struct fb_info *info) + { + struct cfb_info *cfb = (struct cfb_info *)info; ++ unsigned int sync = 0; + int i; + +- /* +- * Blank the screen if blank_mode != 0, else unblank. If +- * blank == NULL then the caller blanks by setting the CLUT +- * (Color Look Up Table) to all black. Return 0 if blanking +- * succeeded, != 0 if un-/blanking failed due to e.g. a +- * video mode which doesn't support it. Implements VESA +- * suspend and powerdown modes on hardware that supports +- * disabling hsync/vsync: +- * blank_mode == 2: suspend vsync +- * blank_mode == 3: suspend hsync +- * blank_mode == 4: powerdown +- * +- * wms...Enable VESA DMPS compatible powerdown mode +- * run "setterm -powersave powerdown" to take advantage +- */ +- + switch (blank) { + case 4: /* powerdown - both sync lines down */ +- cyber2000_grphw(0x16, 0x05, cfb); ++ sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_0; + break; + case 3: /* hsync off */ +- cyber2000_grphw(0x16, 0x01, cfb); ++ sync = EXT_SYNC_CTL_VS_NORMAL | EXT_SYNC_CTL_HS_0; + break; + case 2: /* vsync off */ +- cyber2000_grphw(0x16, 0x04, cfb); +- break; ++ sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_NORMAL; ++ break; + case 1: /* soft blank */ +- cyber2000_grphw(0x16, 0x00, cfb); ++ default: /* unblank */ ++ break; ++ } ++ ++ cyber2000_grphw(EXT_SYNC_CTL, sync, cfb); ++ ++ if (blank <= 1) { ++ /* turn on ramdacs */ ++ cfb->ramdac_powerdown &= ~(RAMDAC_DACPWRDN | RAMDAC_BYPASS | RAMDAC_RAMPWRDN); ++ cyber2000fb_write_ramdac_ctrl(cfb); ++ } ++ ++ /* ++ * Soft blank/unblank the display. ++ */ ++ if (blank) { /* soft blank */ + for (i = 0; i < NR_PALETTE; i++) { + cyber2000fb_writeb(i, 0x3c8, cfb); + cyber2000fb_writeb(0, 0x3c9, cfb); + cyber2000fb_writeb(0, 0x3c9, cfb); + cyber2000fb_writeb(0, 0x3c9, cfb); + } +- break; +- default: /* unblank */ +- cyber2000_grphw(0x16, 0x00, cfb); ++ } else { /* unblank */ + for (i = 0; i < NR_PALETTE; i++) { + cyber2000fb_writeb(i, 0x3c8, cfb); + cyber2000fb_writeb(cfb->palette[i].red, 0x3c9, cfb); + cyber2000fb_writeb(cfb->palette[i].green, 0x3c9, cfb); + cyber2000fb_writeb(cfb->palette[i].blue, 0x3c9, cfb); + } +- break; ++ } ++ ++ if (blank >= 2) { ++ /* turn off ramdacs */ ++ cfb->ramdac_powerdown |= RAMDAC_DACPWRDN | RAMDAC_BYPASS | RAMDAC_RAMPWRDN; ++ cyber2000fb_write_ramdac_ctrl(cfb); + } + } + +@@ -1233,51 +1312,61 @@ + } + + static struct fb_ops cyber2000fb_ops = { +- owner: THIS_MODULE, +- fb_set_var: cyber2000fb_set_var, +- fb_set_cmap: cyber2000fb_set_cmap, +- fb_pan_display: cyber2000fb_pan_display, +- fb_get_fix: gen_get_fix, +- fb_get_var: gen_get_var, +- fb_get_cmap: gen_get_cmap, ++ .owner = THIS_MODULE, ++ .fb_set_var = cyber2000fb_set_var, ++ .fb_set_cmap = cyber2000fb_set_cmap, ++ .fb_pan_display = cyber2000fb_pan_display, ++ .fb_get_fix = gen_get_fix, ++ .fb_get_var = gen_get_var, ++ .fb_get_cmap = gen_get_cmap, + }; + + /* ++ * This is the only "static" reference to the internal data structures ++ * of this driver. It is here solely at the moment to support the other ++ * CyberPro modules external to this driver. ++ */ ++static struct cfb_info *int_cfb_info; ++ ++/* + * Enable access to the extended registers + */ +-static void cyber2000fb_enable_extregs(struct cfb_info *cfb) ++void cyber2000fb_enable_extregs(struct cfb_info *cfb) + { + cfb->func_use_count += 1; + + if (cfb->func_use_count == 1) { + int old; + +- old = cyber2000_grphr(FUNC_CTL, cfb); +- cyber2000_grphw(FUNC_CTL, old | FUNC_CTL_EXTREGENBL, cfb); ++ old = cyber2000_grphr(EXT_FUNC_CTL, cfb); ++ old |= EXT_FUNC_CTL_EXTREGENBL; ++ cyber2000_grphw(EXT_FUNC_CTL, old, cfb); + } + } + + /* + * Disable access to the extended registers + */ +-static void cyber2000fb_disable_extregs(struct cfb_info *cfb) ++void cyber2000fb_disable_extregs(struct cfb_info *cfb) + { + if (cfb->func_use_count == 1) { + int old; + +- old = cyber2000_grphr(FUNC_CTL, cfb); +- cyber2000_grphw(FUNC_CTL, old & ~FUNC_CTL_EXTREGENBL, cfb); ++ old = cyber2000_grphr(EXT_FUNC_CTL, cfb); ++ old &= ~EXT_FUNC_CTL_EXTREGENBL; ++ cyber2000_grphw(EXT_FUNC_CTL, old, cfb); + } + +- cfb->func_use_count -= 1; ++ if (cfb->func_use_count == 0) ++ printk(KERN_ERR "disable_extregs: count = 0\n"); ++ else ++ cfb->func_use_count -= 1; + } + +-/* +- * This is the only "static" reference to the internal data structures +- * of this driver. It is here solely at the moment to support the other +- * CyberPro modules external to this driver. +- */ +-static struct cfb_info *int_cfb_info; ++void cyber2000fb_get_fb_var(struct cfb_info *cfb, struct fb_var_screeninfo *var) ++{ ++ memcpy(var, &cfb->display->var, sizeof(struct fb_var_screeninfo)); ++} + + /* + * Attach a capture/tv driver to the core CyberX0X0 driver. +@@ -1311,164 +1400,102 @@ + + EXPORT_SYMBOL(cyber2000fb_attach); + EXPORT_SYMBOL(cyber2000fb_detach); ++EXPORT_SYMBOL(cyber2000fb_enable_extregs); ++EXPORT_SYMBOL(cyber2000fb_disable_extregs); ++EXPORT_SYMBOL(cyber2000fb_get_fb_var); + + /* + * These parameters give + * 640x480, hsync 31.5kHz, vsync 60Hz + */ + static struct fb_videomode __devinitdata cyber2000fb_default_mode = { +- refresh: 60, +- xres: 640, +- yres: 480, +- pixclock: 39722, +- left_margin: 56, +- right_margin: 16, +- upper_margin: 34, +- lower_margin: 9, +- hsync_len: 88, +- vsync_len: 2, +- sync: FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, +- vmode: FB_VMODE_NONINTERLACED ++ .refresh = 60, ++ .xres = 640, ++ .yres = 480, ++ .pixclock = 39722, ++ .left_margin = 56, ++ .right_margin = 16, ++ .upper_margin = 34, ++ .lower_margin = 9, ++ .hsync_len = 88, ++ .vsync_len = 2, ++ .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ .vmode = FB_VMODE_NONINTERLACED + }; + ++/* static register programming for all chips */ + static char igs_regs[] __devinitdata = { +- 0x12, 0x00, 0x13, 0x00, +- 0x16, 0x00, +- 0x31, 0x00, 0x32, 0x00, +- 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, +- 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x01, +- 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, +- 0x70, 0x0b, 0x73, 0x30, +- 0x74, 0x0b, 0x75, 0x17, 0x76, 0x00, 0x7a, 0xc8 ++ EXT_CRT_IRQ, 0, ++ EXT_CRT_TEST, 0, ++ EXT_SYNC_CTL, 0, ++ EXT_SEG_WRITE_PTR, 0, ++ EXT_SEG_READ_PTR, 0, ++ EXT_BIU_MISC, EXT_BIU_MISC_LIN_ENABLE | ++ EXT_BIU_MISC_COP_ENABLE | ++ EXT_BIU_MISC_COP_BFC, ++ EXT_FUNC_CTL, 0, ++ CURS_H_START, 0, ++ CURS_H_START + 1, 0, ++ CURS_H_PRESET, 0, ++ CURS_V_START, 0, ++ CURS_V_START + 1, 0, ++ CURS_V_PRESET, 0, ++ CURS_CTL, 0, ++ EXT_ATTRIB_CTL, EXT_ATTRIB_CTL_EXT, ++ EXT_OVERSCAN_RED, 0, ++ EXT_OVERSCAN_GREEN, 0, ++ EXT_OVERSCAN_BLUE, 0, ++}; ++ ++/* specific register setting for the 2000 series */ ++static char igs_2000_regs[] __devinitdata = { ++ /* some of these are questionable when we have a BIOS */ ++ EXT_MEM_CTL0, EXT_MEM_CTL0_7CLK | ++ EXT_MEM_CTL0_RAS_1 | ++ EXT_MEM_CTL0_MULTCAS, ++ EXT_HIDDEN_CTL1, 0x30, ++ EXT_FIFO_CTL, 0x0b, ++ EXT_FIFO_CTL + 1, 0x17, ++ 0x76, 0x00, ++ EXT_HIDDEN_CTL4, 0xc8 + }; + + /* +- * We need to wake up the CyberPro, and make sure its in linear memory +- * mode. Unfortunately, this is specific to the platform and card that +- * we are running on. +- * +- * On x86 and ARM, should we be initialising the CyberPro first via the +- * IO registers, and then the MMIO registers to catch all cases? Can we +- * end up in the situation where the chip is in MMIO mode, but not awake +- * on an x86 system? +- * +- * Note that on the NetWinder, the firmware automatically detects the +- * type, width and size, and leaves this in extended registers 0x71 and +- * 0x72 for us. ++ * Initialise the CyberPro hardware. + */ +-static inline void cyberpro_init_hw(struct cfb_info *cfb, int at_boot) ++static void cyberpro_init_hw(struct cfb_info *cfb) + { + int i; + +- /* +- * Wake up the CyberPro. +- */ +-#ifdef __sparc__ +-#ifdef __sparc_v9__ +-#error "You loose, consult DaveM." +-#else +- /* +- * SPARC does not have an "outb" instruction, so we generate +- * I/O cycles storing into a reserved memory space at +- * physical address 0x3000000 +- */ +- { +- unsigned char *iop; +- +- iop = ioremap(0x3000000, 0x5000); +- if (iop == NULL) { +- prom_printf("iga5000: cannot map I/O\n"); +- return -ENOMEM; +- } +- +- writeb(0x18, iop + 0x46e8); +- writeb(0x01, iop + 0x102); +- writeb(0x08, iop + 0x46e8); +- writeb(0x33, iop + 0x3ce); +- writeb(0x01, iop + 0x3cf); +- +- iounmap((void *)iop); +- } +-#endif +- +- if (at_boot) { +- /* +- * Use mclk from BIOS. Only read this if we're +- * initialising this card for the first time. +- * FIXME: what about hotplug? +- */ +- cfb->mclk_mult = cyber2000_grphr(MCLK_MULT, cfb); +- cfb->mclk_div = cyber2000_grphr(MCLK_DIV, cfb); +- } +-#endif +-#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) +- /* +- * x86 and MIPS are simple, we just do regular +- * outb's instead of cyber2000fb_writeb. +- */ +- outb(0x18, 0x46e8); +- outb(0x01, 0x102); +- outb(0x08, 0x46e8); +- outb(0x33, 0x3ce); +- outb(0x01, 0x3cf); +- +- if (at_boot) { +- /* +- * Use mclk from BIOS. Only read this if we're +- * initialising this card for the first time. +- * FIXME: what about hotplug? +- */ +- cfb->mclk_mult = cyber2000_grphr(MCLK_MULT, cfb); +- cfb->mclk_div = cyber2000_grphr(MCLK_DIV, cfb); +- } +-#endif +-#ifdef __arm__ +- cyber2000fb_writeb(0x18, 0x46e8, cfb); +- cyber2000fb_writeb(0x01, 0x102, cfb); +- cyber2000fb_writeb(0x08, 0x46e8, cfb); +- cyber2000fb_writeb(0x33, 0x3ce, cfb); +- cyber2000fb_writeb(0x01, 0x3cf, cfb); +- +- /* +- * MCLK on the NetWinder and the Shark is fixed at 75MHz +- */ +- cfb->mclk_mult = 0xdb; +- cfb->mclk_div = 0x54; +-#endif +- +- /* +- * Initialise the CyberPro +- */ + for (i = 0; i < sizeof(igs_regs); i += 2) + cyber2000_grphw(igs_regs[i], igs_regs[i+1], cfb); + +- if (at_boot) { ++ if (cfb->id == ID_CYBERPRO_5000) { + /* +- * get the video RAM size and width from the VGA register. +- * This should have been already initialised by the BIOS, +- * but if it's garbage, claim default 1MB VRAM (woody) ++ * On the CyberPro5XXXX, ensure that we're using the correct ++ * PLL (5XXX's may be programmed to use an additional set of ++ * PLLs.) + */ +- cfb->mem_ctl1 = cyber2000_grphr(MEM_CTL1, cfb); +- cfb->mem_ctl2 = cyber2000_grphr(MEM_CTL2, cfb); ++ unsigned char val; ++ cyber2000fb_writeb(0xba, 0x3ce, cfb); ++ val = cyber2000fb_readb(0x3cf, cfb) & 0x80; ++ cyber2000fb_writeb(val, 0x3cf, cfb); ++ cyber2000fb_ops.fb_pan_display = NULL; /* FIXME: panning broken */ + } else { + /* +- * Reprogram the MEM_CTL1 and MEM_CTL2 registers ++ * Other supported chips (2000 series) appear to need ++ * these registers programming + */ +- cyber2000_grphw(MEM_CTL1, cfb->mem_ctl1, cfb); +- cyber2000_grphw(MEM_CTL2, cfb->mem_ctl2, cfb); ++ for (i = 0; i < sizeof(igs_2000_regs); i += 2) ++ cyber2000_grphw(igs_2000_regs[i], ++ igs_2000_regs[i+1], ++ cfb); + } + +- /* +- * Ensure thatwe are using the correct PLL. +- * (CyberPro 5000's may be programmed to use +- * an additional set of PLLs. +- */ +- cyber2000fb_writeb(0xba, 0x3ce, cfb); +- cyber2000fb_writeb(cyber2000fb_readb(0x3cf, cfb) & 0x80, 0x3cf, cfb); + } + + static struct cfb_info * __devinit +-cyberpro_alloc_fb_info(struct pci_dev *dev, const struct pci_device_id *id, char *name) ++cyberpro_alloc_fb_info(unsigned int id, char *name) + { + struct cfb_info *cfb; + +@@ -1480,10 +1507,9 @@ + + memset(cfb, 0, sizeof(struct cfb_info) + sizeof(struct display)); + +- cfb->currcon = -1; +- cfb->dev = dev; ++ cfb->id = id; + +- if (id->driver_data == FB_ACCEL_IGS_CYBER5000) ++ if (id == ID_CYBERPRO_5000) + cfb->ref_ps = 40690; // 24.576 MHz + else + cfb->ref_ps = 69842; // 14.31818 MHz (69841?) +@@ -1492,7 +1518,7 @@ + cfb->divisors[1] = 2; + cfb->divisors[2] = 4; + +- if (id->driver_data == FB_ACCEL_IGS_CYBER2000) ++ if (id == ID_CYBERPRO_2000) + cfb->divisors[3] = 8; + else + cfb->divisors[3] = 6; +@@ -1504,7 +1530,24 @@ + cfb->fb.fix.xpanstep = 0; + cfb->fb.fix.ypanstep = 1; + cfb->fb.fix.ywrapstep = 0; +- cfb->fb.fix.accel = id->driver_data; ++ ++ switch (id) { ++ case ID_IGA_1682: ++ cfb->fb.fix.accel = 0; ++ break; ++ ++ case ID_CYBERPRO_2000: ++ cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER2000; ++ break; ++ ++ case ID_CYBERPRO_2010: ++ cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER2010; ++ break; ++ ++ case ID_CYBERPRO_5000: ++ cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER5000; ++ break; ++ } + + cfb->fb.var.nonstd = 0; + cfb->fb.var.activate = FB_ACTIVATE_NOW; +@@ -1569,55 +1612,46 @@ + return 0; + } + +-static int __devinit +-cyberpro_probe(struct pci_dev *dev, const struct pci_device_id *id) ++/* ++ * The CyberPro chips can be placed on many different bus types. ++ * This probe function is common to all bus types. The bus-specific ++ * probe function is expected to have: ++ * - enabled access to the linear memory region ++ * - memory mapped access to the registers ++ * - initialised mem_ctl1 and mem_ctl2 appropriately. ++ */ ++static int __devinit cyberpro_common_probe(struct cfb_info *cfb) + { +- struct cfb_info *cfb; +- u_int h_sync, v_sync; + u_long smem_size; +- char name[16]; ++ u_int h_sync, v_sync; + int err; + +- sprintf(name, "CyberPro%4X", id->device); +- +- err = pci_enable_device(dev); +- if (err) +- return err; +- +- err = pci_request_regions(dev, name); +- if (err) +- return err; +- +- err = -ENOMEM; +- cfb = cyberpro_alloc_fb_info(dev, id, name); +- if (!cfb) +- goto failed_release; +- +- cfb->region = ioremap(pci_resource_start(dev, 0), +- pci_resource_len(dev, 0)); +- if (!cfb->region) +- goto failed_ioremap; +- +- cfb->regs = cfb->region + MMIO_OFFSET; ++ cyberpro_init_hw(cfb); + +- cyberpro_init_hw(cfb, 1); ++ /* ++ * Get the video RAM size and width from the VGA register. ++ * This should have been already initialised by the BIOS, ++ * but if it's garbage, claim default 1MB VRAM (woody) ++ */ ++ cfb->mem_ctl0 = cyber2000_grphr(EXT_MEM_CTL0, cfb); ++ cfb->mem_ctl1 = cyber2000_grphr(EXT_MEM_CTL1, cfb); ++ cfb->mem_ctl2 = cyber2000_grphr(EXT_MEM_CTL2, cfb); + ++ /* ++ * Determine the size of the memory. ++ */ + switch (cfb->mem_ctl2 & MEM_CTL2_SIZE_MASK) { + case MEM_CTL2_SIZE_4MB: smem_size = 0x00400000; break; + case MEM_CTL2_SIZE_2MB: smem_size = 0x00200000; break; ++ case MEM_CTL2_SIZE_1MB: smem_size = 0x00100000; break; + default: smem_size = 0x00100000; break; + } + +- /* +- * Hmm, we _need_ a portable way of finding the address for +- * the remap stuff, both for mmio and for smem. +- */ +- cfb->fb.fix.mmio_start = pci_resource_start(dev, 0) + MMIO_OFFSET; +- cfb->fb.fix.smem_start = pci_resource_start(dev, 0); +- cfb->fb.fix.mmio_len = MMIO_SIZE; + cfb->fb.fix.smem_len = smem_size; ++ cfb->fb.fix.mmio_len = MMIO_SIZE; + cfb->fb.screen_base = cfb->region; + ++ err = -EINVAL; + if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0, + &cyber2000fb_default_mode, 8)) { + printk("%s: no valid mode found\n", cfb->fb.fix.id); +@@ -1644,13 +1678,181 @@ + v_sync = h_sync / (cfb->fb.var.yres + cfb->fb.var.upper_margin + + cfb->fb.var.lower_margin + cfb->fb.var.vsync_len); + +- printk(KERN_INFO "%s: %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n", ++ printk(KERN_INFO "%s: %dKiB VRAM, using %dx%d, %d.%03dkHz, %dHz\n", + cfb->fb.fix.id, cfb->fb.fix.smem_len >> 10, + cfb->fb.var.xres, cfb->fb.var.yres, + h_sync / 1000, h_sync % 1000, v_sync); + + err = register_framebuffer(&cfb->fb); +- if (err < 0) ++ ++failed: ++ return err; ++} ++ ++static void cyberpro_common_resume(struct cfb_info *cfb) ++{ ++ cyberpro_init_hw(cfb); ++ ++ /* ++ * Reprogram the MEM_CTL0, 1 and 2 registers ++ */ ++ cyber2000_grphw(EXT_MEM_CTL0, cfb->mem_ctl0, cfb); ++ cyber2000_grphw(EXT_MEM_CTL1, cfb->mem_ctl1, cfb); ++ cyber2000_grphw(EXT_MEM_CTL2, cfb->mem_ctl2, cfb); ++ ++ /* ++ * Restore the old video mode and the palette. ++ * We also need to tell fbcon to redraw the console. ++ */ ++ cfb->fb.var.activate = FB_ACTIVATE_NOW; ++ cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb); ++} ++ ++ ++ ++ ++/* ++ * PCI specific support. ++ */ ++ ++/* ++ * We need to wake up the CyberPro, and make sure its in linear memory ++ * mode. Unfortunately, this is specific to the platform and card that ++ * we are running on. ++ * ++ * On x86 and ARM, should we be initialising the CyberPro first via the ++ * IO registers, and then the MMIO registers to catch all cases? Can we ++ * end up in the situation where the chip is in MMIO mode, but not awake ++ * on an x86 system? ++ */ ++static int cyberpro_pci_enable_mmio(struct cfb_info *cfb) ++{ ++ unsigned char val; ++ ++#if defined(__sparc_v9__) ++#error "You loose, consult DaveM." ++#elif defined(__sparc__) ++ /* ++ * SPARC does not have an "outb" instruction, so we generate ++ * I/O cycles storing into a reserved memory space at ++ * physical address 0x3000000 ++ */ ++ unsigned char *iop; ++ ++ iop = ioremap(0x3000000, 0x5000); ++ if (iop == NULL) { ++ prom_printf("iga5000: cannot map I/O\n"); ++ return -ENOMEM; ++ } ++ ++ writeb(0x18, iop + 0x46e8); ++ writeb(0x01, iop + 0x102); ++ writeb(0x08, iop + 0x46e8); ++ writeb(EXT_BIU_MISC, iop + 0x3ce); ++ writeb(EXT_BIU_MISC_LIN_ENABLE, iop + 0x3cf); ++ ++ iounmap((void *)iop); ++#elif defined(CONFIG_ARCH_SHARK) ++ /* ++ * Shark probably needs to do it this way rather than use the ++ * IO method below. Since the CyberPro on the Shark isn't a ++ * PCI device, we probably want to move this to a bus-specific ++ * probe function. Do we even need to do this? ++ */ ++ cyber2000fb_writeb(0x18, 0x46e8, cfb); ++ cyber2000fb_writeb(0x01, 0x102, cfb); ++ cyber2000fb_writeb(0x08, 0x46e8, cfb); ++ cyber2000fb_writeb(EXT_BIU_MISC, 0x3ce, cfb); ++ cyber2000fb_writeb(EXT_BIU_MISC_LIN_ENABLE, 0x3cf, cfb); ++#else ++ /* ++ * Most other machine types are "normal", so ++ * we use the standard IO-based wakeup. ++ */ ++ outb(0x18, 0x46e8); ++ outb(0x01, 0x102); ++ outb(0x08, 0x46e8); ++ outb(EXT_BIU_MISC, 0x3ce); ++ outb(EXT_BIU_MISC_LIN_ENABLE, 0x3cf); ++#endif ++ ++ /* ++ * Allow the CyberPro to accept PCI burst accesses ++ */ ++ val = cyber2000_grphr(EXT_BUS_CTL, cfb); ++ if (!(val & EXT_BUS_CTL_PCIBURST_WRITE)) { ++ printk(KERN_INFO "%s: enabling PCI bursts\n", cfb->fb.fix.id); ++ ++ val |= EXT_BUS_CTL_PCIBURST_WRITE; ++ ++ if (cfb->id == ID_CYBERPRO_5000) ++ val |= EXT_BUS_CTL_PCIBURST_READ; ++ ++ cyber2000_grphw(EXT_BUS_CTL, val, cfb); ++ } ++ ++ return 0; ++} ++ ++static int __devinit ++cyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) ++{ ++ struct cfb_info *cfb; ++ char name[16]; ++ int err; ++ ++ sprintf(name, "CyberPro%4X", id->device); ++ ++ err = pci_enable_device(dev); ++ if (err) ++ return err; ++ ++ err = pci_request_regions(dev, name); ++ if (err) ++ return err; ++ ++ err = -ENOMEM; ++ cfb = cyberpro_alloc_fb_info(id->driver_data, name); ++ if (!cfb) ++ goto failed_release; ++ ++ cfb->dev = dev; ++ cfb->region = ioremap(pci_resource_start(dev, 0), ++ pci_resource_len(dev, 0)); ++ if (!cfb->region) ++ goto failed_ioremap; ++ ++ cfb->regs = cfb->region + MMIO_OFFSET; ++ cfb->fb.fix.mmio_start = pci_resource_start(dev, 0) + MMIO_OFFSET; ++ cfb->fb.fix.smem_start = pci_resource_start(dev, 0); ++ ++ /* ++ * Bring up the hardware. This is expected to enable access ++ * to the linear memory region, and allow access to the memory ++ * mapped registers. Also, mem_ctl1 and mem_ctl2 must be ++ * initialised. ++ */ ++ err = cyberpro_pci_enable_mmio(cfb); ++ if (err) ++ goto failed; ++ ++ /* ++ * Use MCLK from BIOS. FIXME: what about hotplug? ++ */ ++ cfb->mclk_mult = cyber2000_grphr(EXT_MCLK_MULT, cfb); ++ cfb->mclk_div = cyber2000_grphr(EXT_MCLK_DIV, cfb); ++#ifdef __arm__ ++ if (machine_is_netwinder() || machine_is_shark()) { ++ /* ++ * MCLK on the NetWinder and the Shark is fixed at 75MHz ++ */ ++ cfb->mclk_mult = 0xdb; ++ cfb->mclk_div = 0x54; ++ } ++#endif ++ ++ err = cyberpro_common_probe(cfb); ++ if (err) + goto failed; + + /* +@@ -1672,7 +1874,7 @@ + return err; + } + +-static void __devexit cyberpro_remove(struct pci_dev *dev) ++static void __devexit cyberpro_pci_remove(struct pci_dev *dev) + { + struct cfb_info *cfb = pci_get_drvdata(dev); + +@@ -1701,7 +1903,7 @@ + } + } + +-static int cyberpro_suspend(struct pci_dev *dev, u32 state) ++static int cyberpro_pci_suspend(struct pci_dev *dev, u32 state) + { + return 0; + } +@@ -1709,41 +1911,44 @@ + /* + * Re-initialise the CyberPro hardware + */ +-static int cyberpro_resume(struct pci_dev *dev) ++static int cyberpro_pci_resume(struct pci_dev *dev) + { + struct cfb_info *cfb = pci_get_drvdata(dev); + + if (cfb) { +- cyberpro_init_hw(cfb, 0); +- +- /* +- * Restore the old video mode and the palette. +- * We also need to tell fbcon to redraw the console. +- */ +- cfb->fb.var.activate = FB_ACTIVATE_NOW; +- cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb); ++ cyberpro_pci_enable_mmio(cfb); ++ cyberpro_common_resume(cfb); + } + + return 0; + } + + static struct pci_device_id cyberpro_pci_table[] __devinitdata = { ++// Not yet ++// { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682, ++// PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_IGA_1682 }, + { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000, +- PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER2000 }, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2000 }, + { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010, +- PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER2010 }, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2010 }, + { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000, +- PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER5000 }, ++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_5000 }, + { 0, } + }; + ++MODULE_DEVICE_TABLE(pci,cyberpro_pci_table); ++ ++#ifndef __devexit_p ++#define __devexit_p(x) (x) ++#endif ++ + static struct pci_driver cyberpro_driver = { +- name: "CyberPro", +- probe: cyberpro_probe, +- remove: __devexit_p(cyberpro_remove), +- suspend: cyberpro_suspend, +- resume: cyberpro_resume, +- id_table: cyberpro_pci_table ++ .name = "CyberPro", ++ .probe = cyberpro_pci_probe, ++ .remove = __devexit_p(cyberpro_pci_remove), ++ .suspend = cyberpro_pci_suspend, ++ .resume = cyberpro_pci_resume, ++ .id_table = cyberpro_pci_table + }; + + /* +@@ -1768,5 +1973,4 @@ + + MODULE_AUTHOR("Russell King"); + MODULE_DESCRIPTION("CyberPro 2000, 2010 and 5000 framebuffer driver"); +-MODULE_DEVICE_TABLE(pci,cyberpro_pci_table); + MODULE_LICENSE("GPL"); +--- linux-2.4.25/drivers/video/cyber2000fb.h~2.4.25-vrs2.patch 2002-08-03 02:39:45.000000000 +0200 ++++ linux-2.4.25/drivers/video/cyber2000fb.h 2004-03-31 17:15:09.000000000 +0200 +@@ -36,24 +36,55 @@ + #define debug_printf(x...) do { } while (0) + #endif + +-#define PIXFORMAT_8BPP 0 +-#define PIXFORMAT_16BPP 1 +-#define PIXFORMAT_24BPP 2 +-#define PIXFORMAT_32BPP 3 ++#define RAMDAC_RAMPWRDN 0x01 ++#define RAMDAC_DAC8BIT 0x02 ++#define RAMDAC_VREFEN 0x04 ++#define RAMDAC_BYPASS 0x10 ++#define RAMDAC_DACPWRDN 0x40 + +-#define VISUALID_256 1 +-#define VISUALID_64K 2 +-#define VISUALID_16M_32 3 +-#define VISUALID_16M 4 +-#define VISUALID_32K 6 ++#define EXT_CRT_VRTOFL 0x11 ++#define EXT_CRT_VRTOFL_LINECOMP10 0x10 ++#define EXT_CRT_VRTOFL_INTERLACE 0x20 + +-#define FUNC_CTL 0x3c +-#define FUNC_CTL_EXTREGENBL 0x80 /* enable access to 0xbcxxx */ ++#define EXT_CRT_IRQ 0x12 ++#define EXT_CRT_IRQ_ENABLE 0x01 ++#define EXT_CRT_IRQ_ACT_HIGH 0x04 + +-#define BIU_BM_CONTROL 0x3e +-#define BIU_BM_CONTROL_ENABLE 0x01 /* enable bus-master */ +-#define BIU_BM_CONTROL_BURST 0x02 /* enable burst */ +-#define BIU_BM_CONTROL_BACK2BACK 0x04 /* enable back to back */ ++#define EXT_CRT_TEST 0x13 ++ ++#define EXT_SYNC_CTL 0x16 ++#define EXT_SYNC_CTL_HS_NORMAL 0x00 ++#define EXT_SYNC_CTL_HS_0 0x01 ++#define EXT_SYNC_CTL_HS_1 0x02 ++#define EXT_SYNC_CTL_HS_HSVS 0x03 ++#define EXT_SYNC_CTL_VS_NORMAL 0x00 ++#define EXT_SYNC_CTL_VS_0 0x04 ++#define EXT_SYNC_CTL_VS_1 0x08 ++#define EXT_SYNC_CTL_VS_COMP 0x0c ++ ++#define EXT_BUS_CTL 0x30 ++#define EXT_BUS_CTL_LIN_1MB 0x00 ++#define EXT_BUS_CTL_LIN_2MB 0x01 ++#define EXT_BUS_CTL_LIN_4MB 0x02 ++#define EXT_BUS_CTL_ZEROWAIT 0x04 ++#define EXT_BUS_CTL_PCIBURST_WRITE 0x20 ++#define EXT_BUS_CTL_PCIBURST_READ 0x80 /* CyberPro 5000 only */ ++ ++#define EXT_SEG_WRITE_PTR 0x31 ++#define EXT_SEG_READ_PTR 0x32 ++#define EXT_BIU_MISC 0x33 ++#define EXT_BIU_MISC_LIN_ENABLE 0x01 ++#define EXT_BIU_MISC_COP_ENABLE 0x04 ++#define EXT_BIU_MISC_COP_BFC 0x08 ++ ++#define EXT_FUNC_CTL 0x3c ++#define EXT_FUNC_CTL_EXTREGENBL 0x80 /* enable access to 0xbcxxx */ ++ ++#define PCI_BM_CTL 0x3e ++#define PCI_BM_CTL_ENABLE 0x01 /* enable bus-master */ ++#define PCI_BM_CTL_BURST 0x02 /* enable burst */ ++#define PCI_BM_CTL_BACK2BACK 0x04 /* enable back to back */ ++#define PCI_BM_CTL_DUMMY 0x08 /* insert dummy cycle */ + + #define X_V2_VID_MEM_START 0x40 + #define X_V2_VID_SRC_WIDTH 0x43 +@@ -87,6 +118,19 @@ + + #define K_CAP_X2_CTL1 0x49 + ++#define CURS_H_START 0x50 ++#define CURS_H_PRESET 0x52 ++#define CURS_V_START 0x53 ++#define CURS_V_PRESET 0x55 ++#define CURS_CTL 0x56 ++ ++#define EXT_ATTRIB_CTL 0x57 ++#define EXT_ATTRIB_CTL_EXT 0x01 ++ ++#define EXT_OVERSCAN_RED 0x58 ++#define EXT_OVERSCAN_GREEN 0x59 ++#define EXT_OVERSCAN_BLUE 0x5a ++ + #define CAP_X_START 0x60 + #define CAP_X_END 0x62 + #define CAP_Y_START 0x64 +@@ -96,46 +140,112 @@ + #define CAP_DDA_Y_INIT 0x6c + #define CAP_DDA_Y_INC 0x6e + +-#define MEM_CTL1 0x71 ++#define EXT_MEM_CTL0 0x70 ++#define EXT_MEM_CTL0_7CLK 0x01 ++#define EXT_MEM_CTL0_RAS_1 0x02 ++#define EXT_MEM_CTL0_RAS2CAS_1 0x04 ++#define EXT_MEM_CTL0_MULTCAS 0x08 ++#define EXT_MEM_CTL0_ASYM 0x10 ++#define EXT_MEM_CTL0_CAS1ON 0x20 ++#define EXT_MEM_CTL0_FIFOFLUSH 0x40 ++#define EXT_MEM_CTL0_SEQRESET 0x80 + +-#define MEM_CTL2 0x72 ++#define EXT_MEM_CTL1 0x71 ++#define EXT_MEM_CTL1_PAR 0x00 ++#define EXT_MEM_CTL1_SERPAR 0x01 ++#define EXT_MEM_CTL1_SER 0x03 ++#define EXT_MEM_CTL1_SYNC 0x04 ++#define EXT_MEM_CTL1_VRAM 0x08 ++#define EXT_MEM_CTL1_4K_REFRESH 0x10 ++#define EXT_MEM_CTL1_256Kx4 0x00 ++#define EXT_MEM_CTL1_512Kx8 0x40 ++#define EXT_MEM_CTL1_1Mx16 0x60 ++ ++#define EXT_MEM_CTL2 0x72 ++#define MEM_CTL2_SIZE_1MB 0x00 + #define MEM_CTL2_SIZE_2MB 0x01 + #define MEM_CTL2_SIZE_4MB 0x02 + #define MEM_CTL2_SIZE_MASK 0x03 + #define MEM_CTL2_64BIT 0x04 + ++#define EXT_HIDDEN_CTL1 0x73 ++ + #define EXT_FIFO_CTL 0x74 + ++#define EXT_SEQ_MISC 0x77 ++#define EXT_SEQ_MISC_8 0x01 ++#define EXT_SEQ_MISC_16_RGB565 0x02 ++#define EXT_SEQ_MISC_32 0x03 ++#define EXT_SEQ_MISC_24_RGB888 0x04 ++#define EXT_SEQ_MISC_16_RGB555 0x06 ++#define EXT_SEQ_MISC_8_RGB332 0x09 ++#define EXT_SEQ_MISC_16_RGB444 0x0a ++ ++#define EXT_HIDDEN_CTL4 0x7a ++ ++#define CURS_MEM_START 0x7e /* bits 23..12 */ ++ + #define CAP_PIP_X_START 0x80 + #define CAP_PIP_X_END 0x82 + #define CAP_PIP_Y_START 0x84 + #define CAP_PIP_Y_END 0x86 + +-#define CAP_NEW_CTL1 0x88 ++#define EXT_CAP_CTL1 0x88 + +-#define CAP_NEW_CTL2 0x89 ++#define EXT_CAP_CTL2 0x89 ++#define EXT_CAP_CTL2_ODDFRAMEIRQ 0x01 ++#define EXT_CAP_CTL2_ANYFRAMEIRQ 0x02 + + #define BM_CTRL0 0x9c + #define BM_CTRL1 0x9d + +-#define CAP_MODE1 0xa4 +-#define CAP_MODE1_8BIT 0x01 /* enable 8bit capture mode */ +-#define CAP_MODE1_CCIR656 0x02 /* CCIR656 mode */ +-#define CAP_MODE1_IGNOREVGT 0x04 /* ignore VGT */ +-#define CAP_MODE1_ALTFIFO 0x10 /* use alternate FIFO for capture */ +-#define CAP_MODE1_SWAPUV 0x20 /* swap UV bytes */ +-#define CAP_MODE1_MIRRORY 0x40 /* mirror vertically */ +-#define CAP_MODE1_MIRRORX 0x80 /* mirror horizontally */ ++#define EXT_CAP_MODE1 0xa4 ++#define EXT_CAP_MODE1_8BIT 0x01 /* enable 8bit capture mode */ ++#define EXT_CAP_MODE1_CCIR656 0x02 /* CCIR656 mode */ ++#define EXT_CAP_MODE1_IGNOREVGT 0x04 /* ignore VGT */ ++#define EXT_CAP_MODE1_ALTFIFO 0x10 /* use alternate FIFO for capture */ ++#define EXT_CAP_MODE1_SWAPUV 0x20 /* swap UV bytes */ ++#define EXT_CAP_MODE1_MIRRORY 0x40 /* mirror vertically */ ++#define EXT_CAP_MODE1_MIRRORX 0x80 /* mirror horizontally */ + +-#define DCLK_MULT 0xb0 +-#define DCLK_DIV 0xb1 +-#define DCLK_DIV_VFSEL 0x20 +-#define MCLK_MULT 0xb2 +-#define MCLK_DIV 0xb3 ++#define EXT_CAP_MODE2 0xa5 ++#define EXT_CAP_MODE2_CCIRINVOE 0x01 ++#define EXT_CAP_MODE2_CCIRINVVGT 0x02 ++#define EXT_CAP_MODE2_CCIRINVHGT 0x04 ++#define EXT_CAP_MODE2_CCIRINVDG 0x08 ++#define EXT_CAP_MODE2_DATEND 0x10 ++#define EXT_CAP_MODE2_CCIRDGH 0x20 ++#define EXT_CAP_MODE2_FIXSONY 0x40 ++#define EXT_CAP_MODE2_SYNCFREEZE 0x80 + +-#define CAP_MODE2 0xa5 ++#define EXT_TV_CTL 0xae + +-#define Y_TV_CTL 0xae ++#define EXT_DCLK_MULT 0xb0 ++#define EXT_DCLK_DIV 0xb1 ++#define EXT_DCLK_DIV_VFSEL 0x20 ++#define EXT_MCLK_MULT 0xb2 ++#define EXT_MCLK_DIV 0xb3 ++ ++#define EXT_LATCH1 0xb5 ++#define EXT_LATCH1_VAFC_EN 0x01 /* enable VAFC */ ++ ++#define EXT_FEATURE 0xb7 ++#define EXT_FEATURE_BUS_MASK 0x07 /* host bus mask */ ++#define EXT_FEATURE_BUS_PCI 0x00 ++#define EXT_FEATURE_BUS_VL_STD 0x04 ++#define EXT_FEATURE_BUS_VL_LINEAR 0x05 ++#define EXT_FEATURE_1682 0x20 /* IGS 1682 compatibility */ ++ ++#define EXT_LATCH2 0xb6 ++#define EXT_LATCH2_I2C_CLKEN 0x10 ++#define EXT_LATCH2_I2C_CLK 0x20 ++#define EXT_LATCH2_I2C_DATEN 0x40 ++#define EXT_LATCH2_I2C_DAT 0x80 ++ ++#define EXT_XT_CTL 0xbe ++#define EXT_XT_CAP16 0x04 ++#define EXT_XT_LINEARFB 0x08 ++#define EXT_XT_PAL 0x10 + + #define EXT_MEM_START 0xc0 /* ext start address 21 bits */ + #define HOR_PHASE_SHIFT 0xc2 /* high 3 bits */ +@@ -160,25 +270,37 @@ + #define EXT_VID_FMT_RGB565 0x02 + #define EXT_VID_FMT_RGB888_24 0x03 + #define EXT_VID_FMT_RGB888_32 0x04 ++#define EXT_VID_FMT_RGB8 0x05 ++#define EXT_VID_FMT_RGB4444 0x06 ++#define EXT_VID_FMT_RGB8T 0x07 + #define EXT_VID_FMT_DUP_PIX_ZOON 0x08 /* duplicate pixel zoom */ + #define EXT_VID_FMT_MOD_3RD_PIX 0x20 /* modify 3rd duplicated pixel */ + #define EXT_VID_FMT_DBL_H_PIX 0x40 /* double horiz pixels */ +-#define EXT_VID_FMT_UV128 0x80 /* UV data offset by 128 */ ++#define EXT_VID_FMT_YUV128 0x80 /* YUV data offset by 128 */ + + #define EXT_VID_DISP_CTL1 0xdc + #define EXT_VID_DISP_CTL1_INTRAM 0x01 /* video pixels go to internal RAM */ + #define EXT_VID_DISP_CTL1_IGNORE_CCOMP 0x02 /* ignore colour compare registers */ + #define EXT_VID_DISP_CTL1_NOCLIP 0x04 /* do not clip to 16235,16240 */ + #define EXT_VID_DISP_CTL1_UV_AVG 0x08 /* U/V data is averaged */ +-#define EXT_VID_DISP_CTL1_Y128 0x10 /* Y data offset by 128 */ +-#define EXT_VID_DISP_CTL1_VINTERPOL_OFF 0x20 /* vertical interpolation off */ ++#define EXT_VID_DISP_CTL1_Y128 0x10 /* Y data offset by 128 (if YUV128 set) */ ++#define EXT_VID_DISP_CTL1_VINTERPOL_OFF 0x20 /* disable vertical interpolation */ + #define EXT_VID_DISP_CTL1_FULL_WIN 0x40 /* video out window full */ + #define EXT_VID_DISP_CTL1_ENABLE_WINDOW 0x80 /* enable video window */ + + #define EXT_VID_FIFO_CTL1 0xdd ++#define EXT_VID_FIFO_CTL1_OE_HIGH 0x02 ++#define EXT_VID_FIFO_CTL1_INTERLEAVE 0x04 /* enable interleaved memory read */ ++ ++#define EXT_ROM_UCB4GH 0xe5 ++#define EXT_ROM_UCB4GH_FREEZE 0x02 /* capture frozen */ ++#define EXT_ROM_UCB4GH_ODDFRAME 0x04 /* 1 = odd frame captured */ ++#define EXT_ROM_UCB4GH_1HL 0x08 /* first horizonal line after VGT falling edge */ ++#define EXT_ROM_UCB4GH_ODD 0x10 /* odd frame indicator */ ++#define EXT_ROM_UCB4GH_INTSTAT 0x20 /* video interrupt */ + + #define VFAC_CTL1 0xe8 +-#define VFAC_CTL1_CAPTURE 0x01 /* capture enable */ ++#define VFAC_CTL1_CAPTURE 0x01 /* capture enable (only when VSYNC high)*/ + #define VFAC_CTL1_VFAC_ENABLE 0x02 /* vfac enable */ + #define VFAC_CTL1_FREEZE_CAPTURE 0x04 /* freeze capture */ + #define VFAC_CTL1_FREEZE_CAPTURE_SYNC 0x08 /* sync freeze capture */ +@@ -197,6 +319,13 @@ + #define VFAC_CTL2_INVERT_OVSYNC 0x80 /* invert other vsync input */ + + #define VFAC_CTL3 0xea ++#define VFAC_CTL3_CAP_LARGE_FIFO 0x01 /* large capture fifo */ ++#define VFAC_CTL3_CAP_INTERLACE 0x02 /* capture odd and even fields */ ++#define VFAC_CTL3_CAP_HOLD_4NS 0x00 /* hold capture data for 4ns */ ++#define VFAC_CTL3_CAP_HOLD_2NS 0x04 /* hold capture data for 2ns */ ++#define VFAC_CTL3_CAP_HOLD_6NS 0x08 /* hold capture data for 6ns */ ++#define VFAC_CTL3_CAP_HOLD_0NS 0x0c /* hold capture data for 0ns */ ++#define VFAC_CTL3_CHROMAKEY 0x20 /* capture data will be chromakeyed */ + #define VFAC_CTL3_CAP_IRQ 0x40 /* enable capture interrupt */ + + #define CAP_MEM_START 0xeb /* 18 bits */ +@@ -235,26 +364,98 @@ + #define BM_COUNT 0xbc090 /* read-only */ + + /* +- * Graphics Co-processor ++ * TV registers + */ +-#define CO_CMD_L_PATTERN_FGCOL 0x8000 +-#define CO_CMD_L_INC_LEFT 0x0004 +-#define CO_CMD_L_INC_UP 0x0002 +- +-#define CO_CMD_H_SRC_PIXMAP 0x2000 +-#define CO_CMD_H_BLITTER 0x0800 ++#define TV_VBLANK_EVEN_START 0xbe43c ++#define TV_VBLANK_EVEN_END 0xbe440 ++#define TV_VBLANK_ODD_START 0xbe444 ++#define TV_VBLANK_ODD_END 0xbe448 ++#define TV_SYNC_YGAIN 0xbe44c ++#define TV_UV_GAIN 0xbe450 ++#define TV_PED_UVDET 0xbe454 ++#define TV_UV_BURST_AMP 0xbe458 ++#define TV_HSYNC_START 0xbe45c ++#define TV_HSYNC_END 0xbe460 ++#define TV_Y_DELAY1 0xbe464 ++#define TV_Y_DELAY2 0xbe468 ++#define TV_UV_DELAY1 0xbe46c ++#define TV_BURST_START 0xbe470 ++#define TV_BURST_END 0xbe474 ++#define TV_HBLANK_START 0xbe478 ++#define TV_HBLANK_END 0xbe47c ++#define TV_PED_EVEN_START 0xbe480 ++#define TV_PED_EVEN_END 0xbe484 ++#define TV_PED_ODD_START 0xbe488 ++#define TV_PED_ODD_END 0xbe48c ++#define TV_VSYNC_EVEN_START 0xbe490 ++#define TV_VSYNC_EVEN_END 0xbe494 ++#define TV_VSYNC_ODD_START 0xbe498 ++#define TV_VSYNC_ODD_END 0xbe49c ++#define TV_SCFL 0xbe4a0 ++#define TV_SCFH 0xbe4a4 ++#define TV_SCP 0xbe4a8 ++#define TV_DELAYBYPASS 0xbe4b4 ++#define TV_EQL_END 0xbe4bc ++#define TV_SERR_START 0xbe4c0 ++#define TV_SERR_END 0xbe4c4 ++#define TV_CTL 0xbe4dc /* reflects a previous register- MVFCLR, MVPCLR etc P241*/ ++#define TV_VSYNC_VGA_HS 0xbe4e8 ++#define TV_FLICK_XMIN 0xbe514 ++#define TV_FLICK_XMAX 0xbe518 ++#define TV_FLICK_YMIN 0xbe51c ++#define TV_FLICK_YMAX 0xbe520 + ++/* ++ * Graphics Co-processor ++ */ + #define CO_REG_CONTROL 0xbf011 ++#define CO_CTRL_BUSY 0x80 ++#define CO_CTRL_CMDFULL 0x04 ++#define CO_CTRL_FIFOEMPTY 0x02 ++#define CO_CTRL_READY 0x01 ++ + #define CO_REG_SRC_WIDTH 0xbf018 +-#define CO_REG_PIX_FORMAT 0xbf01c +-#define CO_REG_FORE_MIX 0xbf048 +-#define CO_REG_FOREGROUND 0xbf058 +-#define CO_REG_WIDTH 0xbf060 +-#define CO_REG_HEIGHT 0xbf062 ++#define CO_REG_PIXFMT 0xbf01c ++#define CO_PIXFMT_32BPP 0x03 ++#define CO_PIXFMT_24BPP 0x02 ++#define CO_PIXFMT_16BPP 0x01 ++#define CO_PIXFMT_8BPP 0x00 ++ ++#define CO_REG_FGMIX 0xbf048 ++#define CO_FG_MIX_ZERO 0x00 ++#define CO_FG_MIX_SRC_AND_DST 0x01 ++#define CO_FG_MIX_SRC_AND_NDST 0x02 ++#define CO_FG_MIX_SRC 0x03 ++#define CO_FG_MIX_NSRC_AND_DST 0x04 ++#define CO_FG_MIX_DST 0x05 ++#define CO_FG_MIX_SRC_XOR_DST 0x06 ++#define CO_FG_MIX_SRC_OR_DST 0x07 ++#define CO_FG_MIX_NSRC_AND_NDST 0x08 ++#define CO_FG_MIX_SRC_XOR_NDST 0x09 ++#define CO_FG_MIX_NDST 0x0a ++#define CO_FG_MIX_SRC_OR_NDST 0x0b ++#define CO_FG_MIX_NSRC 0x0c ++#define CO_FG_MIX_NSRC_OR_DST 0x0d ++#define CO_FG_MIX_NSRC_OR_NDST 0x0e ++#define CO_FG_MIX_ONES 0x0f ++ ++#define CO_REG_FGCOLOUR 0xbf058 ++#define CO_REG_BGCOLOUR 0xbf05c ++#define CO_REG_PIXWIDTH 0xbf060 ++#define CO_REG_PIXHEIGHT 0xbf062 + #define CO_REG_X_PHASE 0xbf078 + #define CO_REG_CMD_L 0xbf07c ++#define CO_CMD_L_PATTERN_FGCOL 0x8000 ++#define CO_CMD_L_INC_LEFT 0x0004 ++#define CO_CMD_L_INC_UP 0x0002 ++ + #define CO_REG_CMD_H 0xbf07e +-#define CO_REG_SRC_PTR 0xbf170 ++#define CO_CMD_H_BGSRCMAP 0x8000 /* otherwise bg colour */ ++#define CO_CMD_H_FGSRCMAP 0x2000 /* otherwise fg colour */ ++#define CO_CMD_H_BLITTER 0x0800 ++ ++#define CO_REG_SRC1_PTR 0xbf170 ++#define CO_REG_SRC2_PTR 0xbf174 + #define CO_REG_DEST_PTR 0xbf178 + #define CO_REG_DEST_WIDTH 0xbf218 + +@@ -269,6 +470,7 @@ + char *fb; + char dev_name[32]; + unsigned int fb_size; ++ unsigned int chip_id; + + /* + * The following is a pointer to be passed into the +@@ -288,10 +490,19 @@ + void (*disable_extregs)(struct cfb_info *); + }; + ++#define ID_IGA_1682 0 ++#define ID_CYBERPRO_2000 1 ++#define ID_CYBERPRO_2010 2 ++#define ID_CYBERPRO_5000 3 ++ ++struct fb_var_screeninfo; ++ + /* + * Note! Writing to the Cyber20x0 registers from an interrupt + * routine is definitely a bad idea atm. + */ + int cyber2000fb_attach(struct cyberpro_info *info, int idx); + void cyber2000fb_detach(int idx); +- ++void cyber2000fb_enable_extregs(struct cfb_info *cfb); ++void cyber2000fb_disable_extregs(struct cfb_info *cfb); ++void cyber2000fb_get_fb_var(struct cfb_info *cfb, struct fb_var_screeninfo *var); +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/video/dbmx1fb.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,2002 @@ ++/****************************************************************************** ++ Copyright (C) 2002 Motorola GSG-China ++ ++ 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. ++*******************************************************************************/ ++/***************************************************************************** ++ * File Name: dbmx1fb.c ++ * ++ * Progammers: Chen Ning, Zhang Juan ++ * ++ * Date of Creations: 10 DEC,2001 ++ * ++ * Synopsis: ++ * ++ * Descirption: DB-MX1 LCD controller Linux frame buffer driver ++ * This file is subject to the terms and conditions of the ++ * GNU General Public License. See the file COPYING in the main ++ * directory of this archive for more details. ++ * ++ * Modification History: ++ * 10 DEC, 2001, initialization version, frame work for frame buffer driver ++ * ++*******************************************************************************/ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/ctype.h> ++#include <linux/mm.h> ++#include <linux/tty.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/fb.h> ++#include <linux/delay.h> ++#include <linux/wrapper.h> ++#include <linux/selection.h> ++#include <linux/console.h> ++#include <linux/kd.h> ++#include <linux/vt_kern.h> ++ ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/mach-types.h> ++#include <asm/uaccess.h> ++#include <asm/proc/pgtable.h> ++ ++#include <video/fbcon.h> ++#include <video/fbcon-mfb.h> ++#include <video/fbcon-cfb4.h> ++#include <video/fbcon-cfb8.h> ++#include <video/fbcon-cfb16.h> ++ ++#include "asm/arch/hardware.h" ++#include "asm/arch/platform.h" ++#include "asm/arch/memory.h" ++ ++#include "dbmx1fb.h" ++ ++#undef SUP_TTY0 ++ ++#define LCD_PM ++#ifdef LCD_PM ++#include <linux/pm.h> ++struct pm_dev *pm; ++#endif ++ ++// PLAM - make sure fbmem.c also has this defined for full screen frame ++// buffer support in SDRAM ++#define FULL_SCREEN ++ ++#undef HARDWARE_CURSOR ++// #undef HARDWARE_CURSOR ++#undef DEBUG ++ ++ ++/********************************************************************************/ ++#ifdef DEBUG ++# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) ++#define FUNC_START DPRINTK(KERN_ERR"start\n"); ++#define FUNC_END DPRINTK(KERN_ERR"end\n"); ++#else ++# define DPRINTK(fmt, args...) ++#define FUNC_START ++#define FUNC_END ++#endif ++ ++#define _IO_ADDRESS(r) ((r)+0xf0000000) ++unsigned int READREG(unsigned int r) ++{ ++ volatile unsigned int * reg; ++ reg = (volatile unsigned int*) _IO_ADDRESS(r); ++ return *reg; ++} ++void WRITEREG(unsigned int r, unsigned int val) ++{ ++ volatile unsigned int *reg; ++ reg = (volatile unsigned int*) _IO_ADDRESS(r); ++ *reg = val; ++ return; ++} ++ ++#define FONT_DATA ((unsigned char *)font->data) ++struct fbcon_font_desc *font; ++ ++/* Local LCD controller parameters */ ++struct dbmx1fb_par{ ++ u_char *screen_start_address; /* Screen Start Address */ ++ u_char *v_screen_start_address;/* Virtul Screen Start Address */ ++ unsigned long screen_memory_size; /* screen memory size */ ++ unsigned int palette_size; ++ unsigned int max_xres; ++ unsigned int max_yres; ++ unsigned int xres; ++ unsigned int yres; ++ unsigned int xres_virtual; ++ unsigned int yres_virtual; ++ unsigned int max_bpp; ++ unsigned int bits_per_pixel; ++ unsigned int currcon; ++ unsigned int visual; ++ unsigned int TFT :1; ++ unsigned int color :1 ; ++ unsigned int sharp :1 ; ++ ++ unsigned short cfb16[16]; ++}; ++ ++#ifdef HARDWARE_CURSOR ++/* hardware cursor parameters */ ++struct dbmx1fb_cursor{ ++ // int enable; ++ int startx; ++ int starty; ++ int blinkenable; ++ int blink_rate; ++ int width; ++ int height; ++ int color[3]; ++ int state; ++}; ++ ++/* Frame buffer of LCD information */ ++struct dbmx1fb_info{ ++ struct display_switch dispsw; ++ struct dbmx1fb_cursor cursor; ++}; ++#endif // HARDWARE_CURSOR ++ ++static u_char* p_framebuffer_memory_address; ++static u_char* v_framebuffer_memory_address; ++ ++/* Fake monspecs to fill in fbinfo structure */ ++static struct fb_monspecs monspecs __initdata = { ++ 30000, 70000, 50, 65, 0 /* Generic */ ++}; ++ ++/* color map initial */ ++static unsigned short __attribute__((unused)) color4map[16] = { ++ 0x0000, 0x000f, 0x00f0, 0x0f2a, 0x0f00, 0x0f0f, 0x0f88, 0x0ccc, ++ 0x0888, 0x00ff, 0x00f8, 0x0f44, 0x0fa6, 0x0f22, 0x0ff0, 0x0fff ++}; ++ ++static unsigned short gray4map[16] = { ++ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, ++ 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f ++}; ++ ++static struct display global_disp; /* Initial (default) Display Settings */ ++static struct fb_info fb_info; ++static struct fb_var_screeninfo init_var = {}; ++static struct dbmx1fb_par current_par={ }; ++ ++/* Frame buffer device API */ ++static int dbmx1fb_get_fix(struct fb_fix_screeninfo *fix, int con, ++ struct fb_info *info); ++static int dbmx1fb_get_var(struct fb_var_screeninfo *var, int con, ++ struct fb_info *info); ++static int dbmx1fb_set_var(struct fb_var_screeninfo *var, int con, ++ struct fb_info *info); ++static int dbmx1fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, ++ struct fb_info *info); ++static int dbmx1fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, ++ struct fb_info *info); ++ ++/* Interface to the low level driver */ ++static int dbmx1fb_switch(int con, struct fb_info *info); ++static void dbmx1fb_blank(int blank, struct fb_info *info); ++static int dbmx1fb_updatevar(int con, struct fb_info *info); ++ ++/* Internal routines */ ++static int _reserve_fb_memory(void); ++static void _install_cmap(int con, struct fb_info *info); ++static void _enable_lcd_controller(void); ++static void _disable_lcd_controller(void); ++static int _encode_var(struct fb_var_screeninfo *var, ++ struct dbmx1fb_par *par); ++static int _decode_var(struct fb_var_screeninfo *var, ++ struct dbmx1fb_par *par); ++ ++/* initialization routines */ ++static void __init _init_lcd_system(void); ++static int __init _init_lcd(void); ++static void __init _init_fbinfo(void); ++static int __init _reserve_fb_memory(void); ++ ++/* frame buffer ops */ ++static struct fb_ops dbmx1fb_ops = { ++ owner: THIS_MODULE, ++ fb_get_fix: dbmx1fb_get_fix, ++ fb_get_var: dbmx1fb_get_var, ++ fb_set_var: dbmx1fb_set_var, ++ fb_get_cmap: dbmx1fb_get_cmap, ++ fb_set_cmap: dbmx1fb_set_cmap, ++}; ++ ++#ifdef HARDWARE_CURSOR ++/* Hardware Cursor */ ++static void dbmx1fb_cursor(struct display *p, int mode, int x, int y); ++static int dbmx1fb_set_font(struct display *d, int width, int height); ++static UINT8 cursor_color_map[] = {0xf8}; ++static void dbmx1fb_set_cursor_state(struct dbmx1fb_info *fb,UINT32 state); ++static void dbmx1fb_set_cursor(struct dbmx1fb_info *fb); ++static void dbmx1fb_set_cursor_blink(struct dbmx1fb_info *fb,int blink); ++ ++struct display_switch dbmx1fb_cfb4 = { ++ setup: fbcon_cfb4_setup, ++ bmove: fbcon_cfb4_bmove, ++ clear: fbcon_cfb4_clear, ++ putc: fbcon_cfb4_putc, ++ putcs: fbcon_cfb4_putcs, ++ revc: fbcon_cfb4_revc, ++ cursor: dbmx1fb_cursor, ++ set_font: dbmx1fb_set_font, ++ fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(16) ++}; ++ ++struct display_switch dbmx1fb_cfb8 = { ++ setup: fbcon_cfb8_setup, ++ bmove: fbcon_cfb8_bmove, ++ clear: fbcon_cfb8_clear, ++ putc: fbcon_cfb8_putc, ++ putcs: fbcon_cfb8_putcs, ++ revc: fbcon_cfb8_revc, ++ cursor: dbmx1fb_cursor, ++ set_font: dbmx1fb_set_font, ++ fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(16) ++}; ++ ++struct display_switch dbmx1fb_cfb16 = { ++ setup: fbcon_cfb16_setup, ++ bmove: fbcon_cfb16_bmove, ++ clear: fbcon_cfb16_clear, ++ putc: fbcon_cfb16_putc, ++ putcs: fbcon_cfb16_putcs, ++ revc: fbcon_cfb16_revc, ++ cursor: dbmx1fb_cursor, ++ set_font: dbmx1fb_set_font, ++ fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(16) ++}; ++#endif // HARDWARE_CURSOR ++ ++ ++/***************************************************************************** ++ * Function Name: dbmx1fb_getcolreg() ++ * ++ * Input: regno : Color register ID ++ * red : Color map red[] ++ * green : Color map green[] ++ * blue : Color map blue[] ++ * transparent : Flag ++ * info : Fb_info database ++ * ++ * Value Returned: int : Return status.If no error, return 0. ++ * ++ * Description: Transfer to fb_xxx_cmap handlers as parameters to ++ * control color registers ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++#define RED 0xf00 ++#define GREEN 0xf0 ++#define BLUE 0x0f ++static int dbmx1fb_getcolreg(u_int regno, u_int *red, u_int *green, ++ u_int *blue, u_int *trans, struct fb_info *info) ++{ ++ unsigned int val; ++ ++ FUNC_START; ++ ++ if(regno >= current_par.palette_size) ++ return 1; ++ ++ val = READREG(DBMX1_LCD_MAPRAM+regno); ++ ++ if((current_par.bits_per_pixel == 4)&&(!current_par.color)) ++ { ++ *red = *green = *blue = (val & BLUE) << 4;//TODO: ++ *trans = 0; ++ } ++ else ++ { ++ *red = (val & RED) << 4; ++ *green = (val & GREEN) << 8; ++ *blue = (val & BLUE) << 12; ++ *trans = 0; ++ } ++ ++ FUNC_END; ++ return 0; ++} ++ ++/***************************************************************************** ++ * Function Name: dbmx1fb_setcolreg() ++ * ++ * Input: regno : Color register ID ++ * red : Color map red[] ++ * green : Color map green[] ++ * blue : Color map blue[] ++ * transparent : Flag ++ * info : Fb_info database ++ * ++ * Value Returned: int : Return status.If no error, return 0. ++ * ++ * Description: Transfer to fb_xxx_cmap handlers as parameters to ++ * control color registers ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++ *****************************************************************************/ ++static int ++dbmx1fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ++ u_int trans, struct fb_info *info) ++{ ++ unsigned int val=0; ++ FUNC_START ++ if(regno >= current_par.palette_size) ++ return 1; ++ ++ if((current_par.bits_per_pixel == 4)&&(!current_par.color)) ++ val = (blue & 0x00f) << 12;//TODO: ++ else ++ { ++ val = (blue >> 12 ) & BLUE; ++ val |= (green >> 8) & GREEN; ++ val |= (red >> 4) & RED; ++ } ++ ++ if (regno < 16) { ++ current_par.cfb16[regno] = ++ regno | regno << 5 | regno << 10; ++} ++ ++ WRITEREG(DBMX1_LCD_MAPRAM+regno, val); ++ FUNC_END; ++ return 0; ++} ++ ++/***************************************************************************** ++ * Function Name: dbmx1fb_get_cmap() ++ * ++ * Input: cmap : Ouput data pointer ++ * kspc : Kernel space flag ++ * con : Console ID ++ * info : Frame buffer information ++ * ++ * Value Returned: int : Return status.If no error, return 0. ++ * ++ * Description: Data is copied from hardware or local or system DISPAY, ++ * and copied to cmap. ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++static int ++dbmx1fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, ++ struct fb_info *info) ++{ ++ int err = 0; ++ ++ FUNC_START; ++ DPRINTK("current_par.visual=%d\n", current_par.visual); ++ if (con == current_par.currcon) ++ err = fb_get_cmap(cmap, kspc, dbmx1fb_getcolreg, info); ++ else if (fb_display[con].cmap.len) ++ fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); ++ else ++ fb_copy_cmap(fb_default_cmap(current_par.palette_size), ++ cmap, kspc ? 0 : 2); ++ FUNC_END; ++ return err; ++} ++ ++/***************************************************************************** ++ * Function Name: dbmx1fb_set_cmap() ++ * ++ * Input: cmap : Ouput data pointer ++ * kspc : Kernel space flag ++ * con : Console ID ++ * info : Frame buffer information ++ * ++ * Value Returned: int : Return status.If no error, return 0. ++ * ++ * Description: Copy data from cmap and copy to DISPLAY. If DISPLAy has no cmap, ++ * allocate memory for it. If DISPLAY is current console and visible, ++ * then hardware color map shall be set. ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++static int ++dbmx1fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) ++{ ++ int err = 0; ++ ++ FUNC_START; ++ DPRINTK("current_par.visual=%d\n", current_par.visual); ++ if (!fb_display[con].cmap.len) ++ err = fb_alloc_cmap(&fb_display[con].cmap, ++ current_par.palette_size, 0); ++ ++ if (!err) { ++ if (con == current_par.currcon) ++ err = fb_set_cmap(cmap, kspc, dbmx1fb_setcolreg, ++ info); ++ fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); ++ } ++ FUNC_END; ++ return err; ++} ++/***************************************************************************** ++ * Function Name: dbmx1fb_get_var() ++ * ++ * Input: var : Iuput data pointer ++ * con : Console ID ++ * info : Frame buffer information ++ * ++ * Value Returned: int : Return status.If no error, return 0. ++ * ++ * Functions Called: _encode_var() ++ * ++ * Description: Get color map from current, or global display[console] ++ * used by ioctl ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++static int ++dbmx1fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) ++{ ++ if (con == -1) { ++ _encode_var(var, ¤t_par); ++ } else ++ *var = fb_display[con].var; ++ return 0; ++} ++ ++ ++/***************************************************************************** ++ * Function Name: dbmx1fb_updatevar() ++ * ++ * Value Returned: VOID ++ * ++ * Functions Called: VOID ++ * ++ * Description: Fill in display switch with LCD information, ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++static int dbmx1fb_updatevar(int con, struct fb_info *info) ++{ ++ DPRINTK("entered\n"); ++ return 0; ++} ++ ++ ++/***************************************************************************** ++ * Function Name: dbmx1fb_set_dispsw() ++ * ++ * Input: display : Iuput data pointer ++ * dbmx1fb_info : Frame buffer of LCD information ++ * ++ * Value Returned: VOID ++ * ++ * Functions Called: VOID ++ * ++ * Description: Fill in display switch with LCD information, ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++static void dbmx1fb_set_dispsw(struct display *disp ++#ifdef HARDWARE_CURSOR ++ ,struct dbmx1fb_info *info ++#endif ++ ) ++{ ++ FUNC_START; ++ switch (disp->var.bits_per_pixel) { ++#ifdef HARDWARE_CURSOR ++#ifdef FBCON_HAS_CFB4 ++ case 4: ++ fb_info.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ info->dispsw = dbmx1fb_cfb4; ++ disp->dispsw = &info->dispsw; ++ disp->dispsw_data = NULL; ++ break; ++#endif ++#ifdef FBCON_HAS_CFB8 ++ case 8: ++ fb_info.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ info->dispsw = dbmx1fb_cfb8; ++ disp->dispsw = &info->dispsw; ++ disp->dispsw_data = NULL; ++ break; ++#endif ++#ifdef FBCON_HAS_CFB16 ++ case 12: ++ case 16: ++ fb_info.fix.visual = FB_VISUAL_DIRECTCOLOR; ++ info->dispsw = dbmx1fb_cfb16; ++ disp->dispsw = &info->dispsw; ++ disp->dispsw_data = current_par.cfb16; ++ break; ++#endif ++#else //!HARDWARE_CURSOR ++ /* first step disable the hardware cursor */ ++#ifdef FBCON_HAS_CFB4 ++ case 4: ++ fb_info.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ disp->dispsw = &fbcon_cfb4; ++ disp->dispsw_data = NULL; ++ break; ++#endif ++#ifdef FBCON_HAS_CFB8 ++ case 8: ++ fb_info.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ disp->dispsw = &fbcon_cfb8; ++ disp->dispsw_data = NULL; ++ break; ++#endif ++#ifdef FBCON_HAS_CFB16 ++ case 12: ++ case 16: ++ fb_info.fix.visual = FB_VISUAL_DIRECTCOLOR; ++ disp->dispsw = &fbcon_cfb16; ++ disp->dispsw_data = current_par.cfb16; ++ break; ++#endif ++ ++#endif // HARDWARE_CURSOR ++ default: ++ disp->dispsw = &fbcon_dummy; ++ disp->dispsw_data = NULL; ++ } ++#ifdef HARDWARE_CURSOR ++ if (&info->cursor) ++ { ++ info->dispsw.cursor = dbmx1fb_cursor; ++ info->dispsw.set_font = dbmx1fb_set_font; ++ } ++#endif // HARDWARE_CURSOR ++ FUNC_END; ++} ++ ++/***************************************************************************** ++ * Function Name: dbmx1fb_set_var() ++ * ++ * Input: var : Iuput data pointer ++ * con : Console ID ++ * info : Frame buffer information ++ * ++ * Value Returned: int : Return status.If no error, return 0. ++ * ++ * Functions Called: dbmx1fb_decode_var() ++ * dbmx1fb_encode_var() ++ * dbmx1fb_set_dispsw() ++ * ++ * Description: set current_par by var, also set display data, specially the console ++ * related fileops, then enable the lcd controller, and set cmap to ++ * hardware. ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++static int ++dbmx1fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) ++{ ++ struct display *display; ++ int err, chgvar = 0; ++ struct dbmx1fb_par par; ++ ++ FUNC_START; ++ if (con >= 0) ++ display = &fb_display[con]; /* Display settings for console */ ++ else ++ display = &global_disp; /* Default display settings */ ++ ++ /* Decode var contents into a par structure, adjusting any */ ++ /* out of range values. */ ++ if ((err = _decode_var(var, &par))){ ++ DPRINTK("decode var error!"); ++ return err; ++ } ++ ++ // Store adjusted par values into var structure ++ _encode_var(var, &par); ++ ++ if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST) ++ return 0; ++ ++ else if (((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) && ++ ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NXTOPEN)) ++ return -EINVAL; ++ ++ if (con >= 0) { ++ if ((display->var.xres != var->xres) || ++ (display->var.yres != var->yres) || ++ (display->var.xres_virtual != var->xres_virtual) || ++ (display->var.yres_virtual != var->yres_virtual) || ++ (display->var.sync != var->sync) || ++ (display->var.bits_per_pixel != var->bits_per_pixel) || ++ (memcmp(&display->var.red, &var->red, sizeof(var->red))) || ++ (memcmp(&display->var.green, &var->green, sizeof(var->green) ++ )) || ++ (memcmp(&display->var.blue, &var->blue, sizeof(var->blue)))) ++ chgvar = 1; ++ } ++ ++ display->var = *var; ++ display->screen_base = par.v_screen_start_address; ++ display->visual = par.visual; ++ display->type = FB_TYPE_PACKED_PIXELS; ++ display->type_aux = 0; ++ display->ypanstep = 0; ++ display->ywrapstep = 0; ++ display->line_length = ++ display->next_line = (var->xres * 16) / 8; ++ ++ display->can_soft_blank = 1; ++ display->inverse = 0; ++ ++ dbmx1fb_set_dispsw(display ++#ifdef HARDWARE_CURSOR ++ , (struct dbmx1fb_info *)info ++#endif // HARDWARE_CURSOR ++ ); ++ ++ /* If the console has changed and the console has defined */ ++ /* a changevar function, call that function. */ ++ if (chgvar && info && info->changevar) ++ info->changevar(con); // TODO: ++ ++ /* If the current console is selected and it's not truecolor, ++ * update the palette ++ */ ++ if ((con == current_par.currcon) && ++ (current_par.visual != FB_VISUAL_TRUECOLOR)) { ++ struct fb_cmap *cmap; ++ ++ current_par = par; // TODO ? ++ if (display->cmap.len) ++ cmap = &display->cmap; ++ else ++ cmap = fb_default_cmap(current_par.palette_size); ++ ++ fb_set_cmap(cmap, 1, dbmx1fb_setcolreg, info); ++ } ++ ++ /* If the current console is selected, activate the new var. */ ++ if (con == current_par.currcon){ ++ init_var = *var; // TODO:gcc support structure copy? ++ _enable_lcd_controller(); ++ } ++ ++ FUNC_END; ++ return 0; ++} ++ ++/***************************************************************************** ++ * Function Name: dbmx1fb_get_fix() ++ * ++ * Input: fix : Ouput data pointer ++ * con : Console ID ++ * info : Frame buffer information ++ * ++ * Value Returned: int : Return status.If no error, return 0. ++ * ++ * Functions Called: VOID ++ * ++ * Description: get fix from display data, current_par data ++ * used by ioctl ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++static int ++dbmx1fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) ++{ ++ struct display *display; ++ ++ FUNC_START; ++ memset(fix, 0, sizeof(struct fb_fix_screeninfo)); ++ strcpy(fix->id, DBMX1_NAME); ++ ++ if (con >= 0) ++ { ++ DPRINTK("Using console specific display for con=%d\n",con); ++ display = &fb_display[con]; /* Display settings for console */ ++ } ++ else ++ display = &global_disp; /* Default display settings */ ++ ++ fix->smem_start = (unsigned long)current_par.screen_start_address; ++ fix->smem_len = current_par.screen_memory_size; ++//printk("dbmx1fb_get_fix, pointer fix: 0x%08x, smem_len: 0x%08x\n",fix,fix->smem_len); ++ fix->type = display->type; ++ fix->type_aux = display->type_aux; ++ fix->xpanstep = 0; ++ fix->ypanstep = display->ypanstep; ++ fix->ywrapstep = display->ywrapstep; ++ fix->visual = display->visual; ++ fix->line_length = display->line_length; ++ fix->accel = FB_ACCEL_NONE; ++ ++ FUNC_END; ++ return 0; ++} ++ ++/***************************************************************************** ++ * Function Name: dbmx1fb_inter_handler() ++ * ++ * Input: ++ * ++ * Value Returned: VOID ++ * ++ * Functions Called: VOID ++ * ++ * Description: Interrupt handler ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++static void dbmx1fb_inter_handler(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ unsigned int intsr; ++ FUNC_START; ++ intsr = READREG(DBMX1_LCD_INTSR); // read to clear status ++ printk(KERN_ERR"lcd interrupt!\n"); ++ FUNC_END; ++ // handle ++} ++ ++#ifdef LCD_PM ++#define PM_OPT " [pm]" ++#define LCD_PMST_RESUME 0 ++#define LCD_PMST_SUSPEND 1 ++static unsigned int lcd_pm_status = LCD_PMST_RESUME; ++ ++void lcd_pm_resume(void) ++{ ++ if(lcd_pm_status == LCD_PMST_RESUME) ++ return; ++ WRITEREG(0x21c21c, 0x10000); // light on ++ WRITEREG(DBMX1_LCD_REFMCR, 0xf000002); ++ WRITEREG(DBMX1_LCD_PWMR, 0x00a9008a); ++ lcd_pm_status = LCD_PMST_RESUME; ++// printk(KERN_ERR"lcd resumed\n"); ++} ++ ++void lcd_pm_suspend(void) ++{ ++ unsigned val; ++ if(lcd_pm_status == LCD_PMST_SUSPEND) ++ return; ++ val = READREG(0x20502c); ++ val |= 0x8000; ++ WRITEREG(0x20502c, val); ++ //To produce enough dealy time before trun off the LCDC. ++ for(val=0;val<=600000;val++); ++ val = READREG(0x21c21c); ++ val &= ~0x10000; ++ WRITEREG(0x21c21c, val); // light off ++ WRITEREG(DBMX1_LCD_REFMCR, 0x0); ++ lcd_pm_status = LCD_PMST_SUSPEND; ++// printk(KERN_ERR"lcd suspended\n"); ++} ++ ++int lcd_pm_handler(struct pm_dev *dev, pm_request_t rqst, void *data) ++{ ++ switch(rqst){ ++ case PM_RESUME: ++ lcd_pm_resume(); ++ break; ++ case PM_SUSPEND: ++ lcd_pm_suspend(); ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++#endif // LCD_PM ++ ++/***************************************************************************** ++ * Function Name: dbmx1fb_init() ++ * ++ * Input: VOID ++ * ++ * Value Returned: int : Return status.If no error, return 0. ++ * ++ * Functions Called: _init_fbinfo() ++ * disable_irq() ++ * enable_irq() ++ * _init_lcd() ++ * dbmx1fb_init_cursor() ++ * ++ * Description: initialization module, all of init routine's entry point ++ * initialize fb_info, init_var, current_par ++ * and setup interrupt, memory, lcd controller ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++int __init dbmx1fb_init(void) ++{ ++ int ret; ++#ifdef HARDWARE_CURSOR ++ struct dbmx1fb_info *info; ++#endif // HARDWARE_CURSOR ++ ++ _init_lcd_system(); ++ ++ _init_fbinfo(); ++ ++ if ((ret = _reserve_fb_memory()) != 0){ ++ printk(KERN_ERR"failed for reserved DBMX frame buffer memory\n"); ++ return ret; ++ } ++ ++#if 0 ++ if (request_irq(IRQ_LCD, ++ dbmx1fb_inter_handler, ++ SA_INTERRUPT, ++ DEV_NAME, ++ NULL) != 0) { ++ printk(KERN_ERR "dbmx1fb: failed in request_irq\n"); ++ return -EBUSY; ++ } ++ ++ disable_irq(IRQ_LCD); ++#endif ++ if (dbmx1fb_set_var(&init_var, -1, &fb_info)) ++ ; //current_par.allow_modeset = 0; ++ ++ _init_lcd(); ++ _enable_lcd_controller(); ++ ++#ifdef HARDWARE_CURSOR ++ info = kmalloc(sizeof(struct dbmx1fb_info), GFP_KERNEL); ++ if(info == NULL){ ++ printk(KERN_ERR"can not kmalloc dbmx1fb_info memory\n"); ++ return -1; ++ } ++ ++ memset(info,0,sizeof(struct dbmx1fb_info)); ++ ++ info->cursor.blink_rate = DEFAULT_CURSOR_BLINK_RATE; ++ info->cursor.blinkenable = 0; ++ info->cursor.state = LCD_CURSOR_OFF; ++ WRITEREG(DBMX1_LCD_LCXYP,0x90010001); ++ WRITEREG(DBMX1_LCD_CURBLKCR,0x1F1F0000); ++ WRITEREG(DBMX1_LCD_LCHCC,0x0000F800); ++ ++ DPRINTK(KERN_ERR"LCXYP = %x\n",READREG(DBMX1_LCD_LCXYP)); ++ DPRINTK(KERN_ERR"CURBLICR = %x\n",READREG(DBMX1_LCD_CURBLKCR)); ++ DPRINTK(KERN_ERR"LCHCC = %x\n",READREG(DBMX1_LCD_LCHCC)); ++ ++ //dbmx1fb_set_cursor(info); ++ //info->cursor = dbmx1fb_init_cursor(info); ++#endif // HARDWARE_CURSOR ++ ++ register_framebuffer(&fb_info); ++ ++#ifdef LCD_PM ++ pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, lcd_pm_handler); ++ printk("register LCD power management successfully.\n"); ++#endif ++#if 0 ++ enable_irq(IRQ_LCD); // TODO: ++#endif ++ /* This driver cannot be unloaded at the moment */ ++ MOD_INC_USE_COUNT; ++ ++ return 0; ++} ++ ++/***************************************************************************** ++ * Function Name: dbmx1fb_setup() ++ * ++ * Input: info : VOID ++ * ++ * Value Returned: int : Return status.If no error, return 0. ++ * ++ * Functions Called: VOID ++ * ++ * Description: basically, this routine used to parse command line parameters, which ++ * is initialization parameters for lcd controller, such as freq, xres, ++ * yres, and so on ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++int __init dbmx1fb_setup(char *options) ++{ ++ FUNC_START; ++ FUNC_END; ++ return 0; ++} ++ ++/***************************************************************************** ++ * Function Name: _init_fbinfo() ++ * ++ * Input: VOID ++ * ++ * Value Returned: VOID ++ * ++ * Functions Called: VOID ++ * ++ * Description: while 16bpp is used to store a 12 bits pixels packet, but ++ * it is not a really 16bpp system. maybe in-compatiable with ++ * other system or GUI.There are some field in var which specify ++ * the red/green/blue offset in a 16bit word, just little endian is ++ * concerned ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++static void __init _init_fbinfo(void) ++{ ++// Thomas Wong add this for debugging ++// *((unsigned char *)0xF5000008) = '&'; ++ ++ FUNC_START; ++ strcpy(fb_info.modename, DBMX1_NAME); ++ strcpy(fb_info.fontname, "Acorn8x8"); ++ ++ fb_info.node = -1; ++ fb_info.flags = FBINFO_FLAG_DEFAULT; // Low-level driver is not a module ++ fb_info.fbops = &dbmx1fb_ops; ++ fb_info.monspecs = monspecs; ++ fb_info.disp = &global_disp; ++ fb_info.changevar = NULL; ++ fb_info.switch_con = dbmx1fb_switch; ++ fb_info.updatevar = dbmx1fb_updatevar; ++ fb_info.blank = dbmx1fb_blank; ++ ++/* ++ * * setup initial parameters ++ * */ ++ memset(&init_var, 0, sizeof(init_var)); ++ ++ init_var.transp.length = 0; ++ init_var.nonstd = 0; ++ init_var.activate = FB_ACTIVATE_NOW; ++ init_var.xoffset = 0; ++ init_var.yoffset = 0; ++ init_var.height = -1; ++ init_var.width = -1; ++ init_var.vmode = FB_VMODE_NONINTERLACED; ++ ++ if (1) { ++ current_par.max_xres = LCD_MAXX; ++ current_par.max_yres = LCD_MAXY; ++ current_par.max_bpp = LCD_MAX_BPP; // 12 ++ init_var.red.length = 5; // 5; ++ init_var.green.length = 6; // 6; ++ init_var.blue.length = 5; // 5; ++#ifdef __LITTLE_ENDIAN ++ init_var.red.offset = 11; ++ init_var.green.offset = 5; ++ init_var.blue.offset = 0; ++#endif //__LITTLE_ENDIAN ++ init_var.grayscale = 16; // i suppose, TODO ++ init_var.sync = 0; ++ init_var.pixclock = 171521; // TODO ++ } ++ ++ current_par.screen_start_address = NULL; ++ current_par.v_screen_start_address = NULL; ++ current_par.screen_memory_size = MAX_PIXEL_MEM_SIZE; ++// Thomas Wong add this for debugging ++//printk("_init_fbinfo, pointer to current_par: 0x%08x, screen_memory_size: 0x%08x\n", ¤t_par,current_par.screen_memory_size); ++ current_par.currcon = -1; // TODO ++ ++ init_var.xres = current_par.max_xres; ++ init_var.yres = current_par.max_yres; ++ init_var.xres_virtual = init_var.xres; ++ init_var.yres_virtual = init_var.yres; ++ init_var.bits_per_pixel = current_par.max_bpp; ++ ++ FUNC_END; ++} ++ ++/***************************************************************************** ++ * Function Name: dbmx1fb_blank() ++ * ++ * Input: blank : Blank flag ++ * info : Frame buffer database ++ * ++ * Value Returned: VOID ++ * ++ * Functions Called: _enable_lcd_controller() ++ * _disable_lcd_controller() ++ * ++ * Description: blank the screen, if blank, disable lcd controller, while if no blank ++ * set cmap and enable lcd controller ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++static void ++dbmx1fb_blank(int blank, struct fb_info *info) ++{ ++#ifdef SUP_TTY0 ++ int i; ++ ++ FUNC_START; ++ DPRINTK("blank=%d info->modename=%s\n", blank, info->modename); ++ if (blank) { ++ if (current_par.visual != FB_VISUAL_TRUECOLOR) ++ for (i = 0; i < current_par.palette_size; i++) ++ ; // TODO ++//printk("Disable LCD\n"); ++ _disable_lcd_controller(); ++ } ++ else { ++ if (current_par.visual != FB_VISUAL_TRUECOLOR) ++ dbmx1fb_set_cmap(&fb_display[current_par.currcon].cmap, ++ 1, ++ current_par.currcon, info); ++//printk("Enable LCD\n"); ++ _enable_lcd_controller(); ++ } ++ FUNC_END; ++#endif //SUP_TTY0 ++} ++ ++/***************************************************************************** ++ * Function Name: dbmx1fb_switch() ++ * ++ * Input: info : Frame buffer database ++ * ++ * Value Returned: VOID ++ * ++ * Functions Called: ++ * ++ * Description: Switch to another console ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++static int dbmx1fb_switch(int con, struct fb_info *info) ++{ ++ FUNC_START; ++ if (current_par.visual != FB_VISUAL_TRUECOLOR) { ++ struct fb_cmap *cmap; ++ if (current_par.currcon >= 0) { ++ // Get the colormap for the selected console ++ cmap = &fb_display[current_par.currcon].cmap; ++ ++ if (cmap->len) ++ fb_get_cmap(cmap, 1, dbmx1fb_getcolreg, info); ++ } ++ } ++ ++ current_par.currcon = con; ++ fb_display[con].var.activate = FB_ACTIVATE_NOW; ++ dbmx1fb_set_var(&fb_display[con].var, con, info); ++ FUNC_END; ++ return 0; ++} ++ ++/***************************************************************************** ++ * Function Name: _encode_par() ++ * ++ * Input: var : Input var data ++ * par : LCD controller parameters ++ * ++ * Value Returned: VOID ++ * ++ * Functions Called: ++ * ++ * Description: use current_par to set a var structure ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++static int _encode_var(struct fb_var_screeninfo *var, ++ struct dbmx1fb_par *par) ++{ ++ // Don't know if really want to zero var on entry. ++ // Look at set_var to see. If so, may need to add extra params to par ++ ++ // memset(var, 0, sizeof(struct fb_var_screeninfo)); ++ ++ var->xres = par->xres; ++ var->yres = par->yres; ++ var->xres_virtual = par->xres_virtual; ++ var->yres_virtual = par->yres_virtual; ++ ++ var->bits_per_pixel = par->bits_per_pixel; ++ ++ DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel); ++ switch(var->bits_per_pixel) { ++ case 2: ++ case 4: ++ case 8: ++ var->red.length = 4; ++ var->green = var->red; ++ var->blue = var->red; ++ var->transp.length = 0; ++ break; ++ case 12: // This case should differ for Active/Passive mode ++ case 16: ++ if (1) { ++ var->red.length = 4; ++ var->blue.length = 4; ++ var->green.length = 4; ++ var->transp.length = 0; ++#ifdef __LITTLE_ENDIAN ++ var->red.offset = 8; ++ var->green.offset = 4; ++ var->blue.offset = 0; ++ var->transp.offset = 0; ++#endif // __LITTLE_ENDIAN ++ } ++ else ++ { ++ var->red.length = 5; ++ var->blue.length = 5; ++ var->green.length = 6; ++ var->transp.length = 0; ++ var->red.offset = 11; ++ var->green.offset = 5; ++ var->blue.offset = 0; ++ var->transp.offset = 0; ++ } ++ break; ++ } ++ ++ return 0; ++} ++ ++/***************************************************************************** ++ * Function Name: _decode_var ++ * ++ * Input: var : Input var data ++ * par : LCD controller parameters ++ * ++ * Value Returned: VOID ++ * ++ * Functions Called: VOID ++ * ++ * Description: Get the video params out of 'var'. If a value doesn't fit, ++ * round it up,if it's too big, return -EINVAL. ++ * ++ * Cautions: Round up in the following order: bits_per_pixel, xres, ++ * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, ++ * bitfields, horizontal timing, vertical timing. ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++static int _decode_var(struct fb_var_screeninfo *var, ++ struct dbmx1fb_par *par) ++{ ++ *par = current_par; ++ ++ if ((par->xres = var->xres) < MIN_XRES) ++ par->xres = MIN_XRES; ++ if ((par->yres = var->yres) < MIN_YRES) ++ par->yres = MIN_YRES; ++ if (par->xres > current_par.max_xres) ++ par->xres = current_par.max_xres; ++ if (par->yres > current_par.max_yres) ++ par->yres = current_par.max_yres; ++ par->xres_virtual = ++ var->xres_virtual < par->xres ? par->xres : var->xres_virtual; ++ par->yres_virtual = ++ var->yres_virtual < par->yres ? par->yres : var->yres_virtual; ++ par->bits_per_pixel = var->bits_per_pixel; ++ ++ switch (par->bits_per_pixel) { ++#ifdef FBCON_HAS_CFB4 ++ case 4: ++ par->visual = FB_VISUAL_PSEUDOCOLOR; ++ par->palette_size = 16; ++ break; ++#endif ++#ifdef FBCON_HAS_CFB8 ++ case 8: ++ par->visual = FB_VISUAL_PSEUDOCOLOR; ++ par->palette_size = 256; ++ break; ++#endif ++#ifdef FBCON_HAS_CFB16 ++ case 12: // RGB 444 ++ case 16: /* RGB 565 */ ++ par->visual = FB_VISUAL_TRUECOLOR; ++ par->palette_size = 0; ++ break; ++#endif ++ default: ++ return -EINVAL; ++ } ++ ++ par->screen_start_address =(u_char*)( ++ (u_long)p_framebuffer_memory_address+PAGE_SIZE); ++ par->v_screen_start_address =(u_char*)( ++ (u_long)v_framebuffer_memory_address+PAGE_SIZE); ++ ++// Thomas Wong - try to change start address here (map to SRAM, instead of SDRAM) ++#ifndef FULL_SCREEN ++ par->screen_start_address =(u_char*)(0x00300000); ++ par->v_screen_start_address =(u_char*)(0xF0300000); ++#endif ++ ++// par->screen_start_address =(u_char*)(0x0BE00000); ++// par->v_screen_start_address =(u_char*)(0xFBE00000); ++ ++// par->screen_start_address =(u_char*)(0x12000000); ++// par->v_screen_start_address =(u_char*)(0xF2000000); ++ ++ return 0; ++} ++ ++ ++/***************************************************************************** ++ * Function Name: _reserve_fb_memory() ++ * ++ * Input: VOID ++ * ++ * Value Returned: VOID ++ * ++ * Functions Called: ++ * ++ * Description: get data out of var structure and set related LCD controller registers ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++static int __init _reserve_fb_memory(void) ++{ ++ u_int required_pages; ++ u_int extra_pages; ++ u_int order; ++ struct page *page; ++ char *allocated_region; ++ ++ DPRINTK("frame buffer memory size = %x\n", (unsigned int)ALLOCATED_FB_MEM_SIZE); ++ if (v_framebuffer_memory_address != NULL) ++ return -EINVAL; ++ ++ /* Find order required to allocate enough memory for framebuffer */ ++ required_pages = ALLOCATED_FB_MEM_SIZE >> PAGE_SHIFT; ++ for (order = 0 ; required_pages >> order ; order++) {;} ++ extra_pages = (1 << order) - required_pages; ++ ++ if ((allocated_region = ++ (char *)__get_free_pages(GFP_KERNEL | GFP_DMA, order)) == NULL){ ++ ++ DPRINTK("can not allocated memory\n"); ++ return -ENOMEM; ++ } ++ ++ ++ v_framebuffer_memory_address = (u_char *)allocated_region + ++ (extra_pages << PAGE_SHIFT); ++ p_framebuffer_memory_address = (u_char *)__virt_to_phys( ++ (u_long)v_framebuffer_memory_address); ++#if 0 ++ printk(KERN_ERR"Frame buffer __get_free_pages vd:= %x, pd= %x", ++ (unsigned int)v_framebuffer_memory_address, ++ (unsigned int)p_framebuffer_memory_address); ++#endif ++ /* Free all pages that we don't need but were given to us because */ ++ /* __get_free_pages() works on powers of 2. */ ++ for (;extra_pages;extra_pages--) ++ free_page((u_int)allocated_region + ((extra_pages-1) << PAGE_SHIFT)); ++ ++ /* Set reserved flag for fb memory to allow it to be remapped into */ ++ /* user space by the common fbmem driver using remap_page_range(). */ ++ for(page = virt_to_page(v_framebuffer_memory_address); ++ page < virt_to_page(v_framebuffer_memory_address ++ + ALLOCATED_FB_MEM_SIZE); ++ page++) ++ mem_map_reserve(page); ++#if 0 ++ /* Remap the fb memory to a non-buffered, non-cached region */ ++ v_framebuffer_memory_address = (u_char *)__ioremap( ++ (u_long)p_framebuffer_memory_address, ++ ALLOCATED_FB_MEM_SIZE, ++ L_PTE_PRESENT | ++ L_PTE_YOUNG | ++ L_PTE_DIRTY | ++ L_PTE_WRITE); ++#endif ++ current_par.screen_start_address =(u_char*)( ++ (u_long)p_framebuffer_memory_address+PAGE_SIZE); ++ current_par.v_screen_start_address =(u_char*)( ++ (u_long)v_framebuffer_memory_address+PAGE_SIZE); ++ ++ DPRINTK("physical screen start addres: %x\n", ++ (u_long)p_framebuffer_memory_address+PAGE_SIZE); ++ ++#ifndef FULL_SCREEN ++// Thomas Wong - we'll try to change the screen start address here ++// printk("\n\rMap LCD screen to SDRAM.\n\r"); ++ ++ printk("\n\rMap LCD screen to embedded SRAM.\n\r"); ++ current_par.screen_start_address =(u_char*)(0x00300000); ++ current_par.v_screen_start_address =(u_char*)(0xF0300000); ++#endif ++ ++// printk("\n\rMap LCD screen to SDRAM 0xFBE00000.\n\r"); ++// current_par.screen_start_address =(u_char*)(0x0BE00000); ++// current_par.v_screen_start_address =(u_char*)(0xFBE00000); ++ ++// printk("\n\rMap LCD screen to SRAM 0x12000000.\n\r"); ++// current_par.screen_start_address =(u_char*)(0x12000000); ++// current_par.v_screen_start_address =(u_char*)(0xF2000000); ++ ++ return (v_framebuffer_memory_address == NULL ? -EINVAL : 0); ++} ++ ++/***************************************************************************** ++ * Function Name: _enable_lcd_controller() ++ * ++ * Input: VOID ++ * ++ * Value Returned: VOID ++ * ++ * Functions Called: ++ * ++ * Description: enable Lcd controller, setup registers, ++ * base on current_par value ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++static void _enable_lcd_controller(void) ++{ ++ unsigned int val; ++#if 0 ++ int i; ++ val =0; ++ ++ FUNC_START; ++ _decode_var(&init_var, ¤t_par); ++ ++ val = current_par.xres/16; ++ val <<= 20; ++ val += current_par.yres; ++ WRITEREG(DBMX1_LCD_XYMAX, val); ++ ++ val=0; ++ val=current_par.xres_virtual /2; ++ WRITEREG(DBMX1_LCD_VPW, val); ++ ++ switch(current_par.bits_per_pixel ){ ++ case 4: // for gray only ++ for(i=0; i<16; i++){ ++ WRITEREG(DBMX1_LCD_MAPRAM+i, gray4map[i]); ++ } ++ WRITEREG(DBMX1_LCD_PANELCFG, PANELCFG_VAL_4); ++ WRITEREG(DBMX1_LCD_VCFG, VCFG_VAL_4); ++ WRITEREG(DBMX1_LCD_HCFG, HCFG_VAL_4); ++ WRITEREG(DBMX1_LCD_INTCR, INTCR_VAL_4); // no interrupt ++ WRITEREG(DBMX1_LCD_REFMCR, REFMCR_VAL_4); ++ WRITEREG(DBMX1_LCD_DMACR, DMACR_VAL_4); ++ WRITEREG(DBMX1_LCD_PWMR, PWMR_VAL); ++ break; ++ case 12: ++ case 16: ++ WRITEREG(DBMX1_LCD_PANELCFG, PANELCFG_VAL_12); ++ WRITEREG(DBMX1_LCD_HCFG, HCFG_VAL_12); ++ WRITEREG(DBMX1_LCD_VCFG, VCFG_VAL_12); ++ WRITEREG(DBMX1_LCD_REFMCR, 0x0); ++ WRITEREG(DBMX1_LCD_DMACR, DMACR_VAL_12); ++ WRITEREG(DBMX1_LCD_PWMR, 0x00008200); ++ WRITEREG(DBMX1_LCD_REFMCR, 0x0f000002); ++ WRITEREG(DBMX1_LCD_PWMR, 0x0000008a); ++ ++ break; ++ } ++#else ++ val = READREG(0x21c21c); ++ val |= 0x0010000; ++ WRITEREG(0x21c21c, val); ++ ++ WRITEREG(DBMX1_LCD_PWMR, 0x8200); ++ WRITEREG(DBMX1_LCD_REFMCR, 0xf000002); ++ ++ // Thomas Wong - we want 0x8A not 0x200 ++// WRITEREG(DBMX1_LCD_PWMR, 0x200); ++// PLAM -- for rev2 (endian bit) ++// WRITEREG(DBMX1_LCD_PWMR, 0x0000008A); ++ WRITEREG(DBMX1_LCD_PWMR, 0x00A9008A); ++// end PLAM ++#endif ++ ++ FUNC_END; ++} ++ ++/***************************************************************************** ++ * Function Name: _disable_lcd_controller() ++ * ++ * Input: VOID ++ * ++ * Value Returned: VOID ++ * ++ * Functions Called: VOID ++ * ++ * Description: just disable the LCD controller ++ * disable lcd interrupt. others, i have no ideas ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++static void _disable_lcd_controller(void) ++{ ++ unsigned int val; ++ val = READREG(0x21c21c); ++ val &= ~0x0010000; ++ WRITEREG(0x21c21c, val); ++ ++ WRITEREG(DBMX1_LCD_PWMR, 0x8200); ++// WRITEREG(DBMX1_LCD_REFMCR, DISABLELCD_VAL); ++ WRITEREG(0x205034, 0x0); ++} ++ ++/***************************************************************************** ++ * Function Name: _install_cmap ++ * ++ * Input: VOID ++ * ++ * Value Returned: VOID ++ * ++ * Functions Called: ++ * ++ * Description: set color map to hardware ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++static void _install_cmap(int con, struct fb_info *info) ++{ ++ if (con != current_par.currcon) ++ return ; ++ if (fb_display[con].cmap.len) ++ fb_set_cmap(&fb_display[con].cmap, 1, dbmx1fb_setcolreg, info); ++ else ++ fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), ++ 1, ++ dbmx1fb_setcolreg, ++ info); ++ return ; ++} ++ ++/***************************************************************************** ++ * Function Name: _init_lcd_system ++ * ++ * Input: VOID ++ * ++ * Value Returned: VOID ++ * ++ * Functions Called: ++ * ++ * Description: initialize the gpio port C and port D with DMA enable ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++static void __init _init_lcd_system(void) ++{ ++unsigned int val; ++ ++/* Thomas Wong - we don't need DMA here ++ // dma reset & enable ++ val = READREG(0x209000); ++ val |= 0x02; ++ WRITEREG(0x209000, val); ++ val = READREG(0x209000); ++ val |= 0x01; ++ WRITEREG(0x209000, val); ++*/ ++ // gpio ++ //clear port D for LCD signal ++ WRITEREG(0x21c320, 0x0); ++ WRITEREG(0x21c338, 0x0); ++ ++ val = READREG(0x21c220); ++ val |= 0x10000; ++ WRITEREG(0x21c220, val); ++ val = READREG(0x21c208); ++ val |= 0x03; ++ WRITEREG(0x21c208, val); ++ val = READREG(0x21c200); ++ val |= 0x10000; ++ WRITEREG(0x21c200, val); ++ val = READREG(0x21c238); ++ val |= 0x10000; ++ WRITEREG(0x21c238, val); ++ val = READREG(0x21c21c); ++ val |= 0x10000; ++ WRITEREG(0x21c21c, val); ++ ++} ++ ++static void set_pclk(unsigned int fmhz) ++{ ++ unsigned int div= 96/fmhz; ++ unsigned int reg; ++ reg = READREG(0x21b020); ++ reg &= ~0xf0; ++ WRITEREG(0x21b020, reg); ++ reg |= ((div-1)<<4) &0xf0; ++ WRITEREG(0x21b020, reg); ++} ++ ++/***************************************************************************** ++ * Function Name: _init_lcd ++ * ++ * Input: VOID ++ * ++ * Value Returned: VOID ++ * ++ * Functions Called: _decode_var() ++ * ++ * Description: initialize the LCD controller, use current_par for 12bpp ++ * ++ * Modification History: ++ * 10 DEC,2001, Chen Ning ++******************************************************************************/ ++static int __init _init_lcd() ++{ ++ ++ unsigned int val, rate; ++ int i; ++ unsigned char * pscr; ++ //unsigned long pclk,temp,PCLKDIV2; ++ //unsigned long MFI,MFN,PD,MFD,tempReg,MCUPLLCLK; ++ ++ ++ _decode_var(&init_var, ¤t_par); ++ ++ // gpio begin ++ val = READREG(0x21c21c); ++ val &= ~0x00010000; ++ WRITEREG(0x21c21c, val); ++ DPRINTK(KERN_ERR"DR=%x\n", READREG(0x21c21c)); ++ ++ // LCD regs ++ DPRINTK(KERN_ERR"write SSA by %x\n", ++ (unsigned int)current_par.screen_start_address); ++ WRITEREG(DBMX1_LCD_SSA, (unsigned int)current_par.screen_start_address); ++ DPRINTK(KERN_ERR"SSA=%x\n", READREG(DBMX1_LCD_SSA)); ++ ++ val =0; ++ val = current_par.xres/16; ++ val = val<<20; ++ val += current_par.yres; ++ DPRINTK(KERN_ERR"par.x=%x, y=%x\n", ++ current_par.xres, ++ current_par.yres); ++ WRITEREG(DBMX1_LCD_XYMAX, val); ++ DPRINTK(KERN_ERR"XYMAX=%x\n", READREG(DBMX1_LCD_XYMAX)); ++ ++ val=0; ++ val=current_par.xres_virtual/2; ++ WRITEREG(DBMX1_LCD_VPW, val); ++ DPRINTK(KERN_ERR"VPW=%x\n", READREG(DBMX1_LCD_VPW)); ++ ++ set_pclk(4); ++ ++ DPRINTK(KERN_ERR"DBMX1_LCD_PANELCFG=%x\n", ++ READREG(DBMX1_LCD_PANELCFG)); ++ ++ WRITEREG(DBMX1_LCD_HCFG, 0x04000f06); ++ DPRINTK(KERN_ERR"DBMX1_LCD_HCFG=%x\n", ++ READREG(DBMX1_LCD_HCFG)); ++ ++ WRITEREG(DBMX1_LCD_VCFG, 0x04000907); ++ DPRINTK(KERN_ERR"DBMX1_LCD_VCFG=%x\n", ++ READREG(DBMX1_LCD_VCFG)); ++ ++ WRITEREG(DBMX1_LCD_REFMCR, 0x0); ++ DPRINTK(KERN_ERR"DBMX1_LCD_REFMCR=%x\n", ++ READREG(DBMX1_LCD_REFMCR)); ++ ++ WRITEREG(DBMX1_LCD_DMACR, DMACR_VAL_12); ++ DPRINTK(KERN_ERR"DBMX1_LCD_DMACR=%x\n", ++ READREG(DBMX1_LCD_DMACR)); ++ ++ WRITEREG(DBMX1_LCD_PWMR, 0x00008200); ++ DPRINTK(KERN_ERR"DBMX1_LCD_PWMR=%x\n", ++ READREG(DBMX1_LCD_PWMR)); ++ ++ // Thomas Wong - we don't want to turn it on here ++ /* ++ WRITEREG(DBMX1_LCD_REFMCR, 0x0f000002) ++ DPRINTK(KERN_ERR"DBMX1_LCD_REFMCR=%x\n", ++ READREG(DBMX1_LCD_REFMCR)); ++ */ ++ ++ WRITEREG(DBMX1_LCD_PWMR, 0x0000008a); ++ DPRINTK(KERN_ERR"DBMX1_LCD_PWMR=%x\n", ++ READREG(DBMX1_LCD_PWMR)); ++ ++ // Thomas Wong ++ WRITEREG(0x21B020, 0x000B005B); ++// PLAM -- for rev2 (new register and endian bits) ++ WRITEREG(DBMX1_LCD_PANELCFG, 0xF8008B42); // little endian ++// WRITEREG(DBMX1_LCD_PANELCFG, 0xF8048B42); // big endian ++ WRITEREG(DBMX1_LCD_LGPMR, 0x00090300); ++// WRITEREG(DBMX1_LCD_PWMR, 0x0000008A); ++ WRITEREG (DBMX1_LCD_PWMR, 0x009A008A); ++// end PLAM ++ ++// PLAM -- for rev2 (new DMACR setting) ++// WRITEREG(DBMX1_LCD_DMACR, 0x800C0002); ++ WRITEREG(DBMX1_LCD_DMACR, 0x00040008); ++//end PLAM ++ ++ ++#define DMACR_VAL_12 0x800C0002 ++ ++ ++// WRITEREG(DBMX1_LCD_INTCR, INTCR_VAL_12); ++// DPRINTK(KERN_ERR"DBMX1_LCD_INTCR=%x\n", ++// READREG(DBMX1_LCD_INTCR)); ++ ++ // warm up LCD ++ for(i=0;i<10000000;i++) ; ++ ++ // gpio end ++ val = READREG(0x21c21c); ++ val |= 0x00010000; ++ WRITEREG(0x21c21c, val); ++ DPRINTK(KERN_ERR"DR=%x\n", ++ READREG(0x21c21c)); ++#if 0 ++ // clear screen ++ pscr = current_par.v_screen_start_address; ++ for(i=0; i< (current_par.screen_memory_size - 2*PAGE_SIZE); i++){ ++ *pscr++ = 0xff; ++ } ++#endif ++ DPRINTK(KERN_ERR"_init_lcd end \n"); ++ ++ return 0; ++} ++ ++#ifdef HARDWARE_CURSOR ++ ++/* ++ * Hardware cursor support ++ */ ++ /***************************************************************************** ++ * Function Name: dbmx1fb_set_cursor_color() ++ * ++ * Input: fb : frame buffer database ++ * red : red component level in the cursor ++ * green : green component level in the cursor ++ * blue : blue component level in the cursor ++ * ++ * Value Returned: VOID ++ * ++ * Functions Called: VOID ++ * ++ * Description: Set color of hardware cursor ++ * ++ * Modification History: ++ * 10 DEC,2001, Zhang Juan ++******************************************************************************/ ++static void dbmx1fb_set_cursor_color(struct dbmx1fb_info *fb, UINT8 *red, UINT8 *green, UINT8 *blue) ++{ ++ struct dbmx1fb_cursor *c = &fb->cursor; ++ UINT32 color; ++ ++ FUNC_START; ++ c->color[0] = *red; ++ c->color[1] = *green; ++ c->color[2] = *blue; ++ color = (UINT32)*red; ++ color |= (UINT32)(*green>>5); ++ color |= (UINT32)(*blue>>11); ++ ++ WRITEREG(DBMX1_LCD_LCHCC, color); ++ FUNC_END; ++} ++ ++ /***************************************************************************** ++ * Function Name: dbmx1fb_set_cursor() ++ * ++ * Input: fb : frame buffer database ++ * ++ * Value Returned: VOID ++ * ++ * Functions Called: VOID ++ * ++ * Description: Load information of hardware cursor ++ * ++ * Modification History: ++ * 10 DEC,2001, Zhang Juan ++******************************************************************************/ ++static void dbmx1fb_set_cursor(struct dbmx1fb_info *fb) ++{ ++ struct dbmx1fb_cursor *c = &fb->cursor; ++ UINT32 temp,tempReg,x,y; ++ ++ FUNC_START; ++ //DPRINTK(KERN_ERR"BLINK_RATE=%x\n",c->blink_rate); ++// DPRINTK(KERN_ERR"width=%x\n",c->width); ++// DPRINTK(KERN_ERR"height=%x\n",c->height); ++ ++ x = c->startx << 16; ++ if (c->state == LCD_CURSOR_ON) ++ x |= CURSOR_ON_MASK; ++ ++#ifdef FBCON_HAS_CFB4 ++ else if(c->state == LCD_CURSOR_REVERSED) ++ x |= CURSOR_REVERSED_MASK; ++ else if(c->state == LCD_CURSOR_ON_WHITE) ++ x |= CURSOR_WHITE_MASK; ++#elif defined(FBCON_HAS_CFB8)||defined(FBCON_HAS_CFB16) ++ else if(c->state == LCD_CURSOR_INVERT_BGD) ++ x |= CURSOR_INVERT_MASK; ++ else if(c->state == LCD_CURSOR_AND_BGD) ++ x |= CURSOR_AND_BGD_MASK; ++ else if(c->state == LCD_CURSOR_OR_BGD) ++ x |= CURSOR_OR_BGD_MASK; ++ else if(c->state == LCD_CURSOR_XOR_BGD) ++ x |= CURSOR_XOR_BGD_MASK; ++#endif ++ else ++ x = c->startx; ++ ++ y = c->starty; ++ ++ temp = (UINT32)x | (UINT32)y; ++ WRITEREG(DBMX1_LCD_LCXYP, temp); ++ //DPRINTK(KERN_ERR"lcxyp=%x\n",READREG(DBMX1_LCD_LCXYP)); ++ ++ temp = (UINT32)((c->width<<8) | (c->height)); ++ tempReg = (UINT32)((temp<<16) | c->blink_rate); ++ ++ WRITEREG(DBMX1_LCD_CURBLKCR, tempReg); ++ ++ //c->blink_rate = 10; ++ if (c->blinkenable) ++ dbmx1fb_set_cursor_blink(fb,c->blink_rate); ++ DPRINTK(KERN_ERR"CURBLKCR=%x\n",READREG(DBMX1_LCD_CURBLKCR)); ++ FUNC_END; ++} ++ ++ /***************************************************************************** ++ * Function Name: dbmx1fb_set_cursor_blink() ++ * ++ * Input: fb : frame buffer database ++ * blink : input blink frequency of cursor ++ * ++ * Value Returned: VOID ++ * ++ * Functions Called: VOID ++ * ++ * Description: Set blink frequency of hardware cursor ++ * ++ * Modification History: ++ * 10 DEC,2001, Zhang Juan ++******************************************************************************/ ++static void dbmx1fb_set_cursor_blink(struct dbmx1fb_info *fb,int blink) ++{ ++ struct dbmx1fb_cursor *c = &fb->cursor; ++ ++ unsigned long temp,tempReg; ++ unsigned long PCD, XMAX, YMAX, PCLKDIV2; ++ unsigned long tempMicroPeriod; ++ ++ FUNC_START; ++ DPRINTK(KERN_ERR"dbmx1fb_set_cursor_blink\n"); ++ ++ if(!c){ ++ DPRINTK(KERN_ERR"dangerouts, for c == null\n"); ++ } ++ c->blink_rate = blink; ++ ++ tempReg = READREG(DBMX1_LCD_XYMAX); ++ XMAX = (tempReg & XMAX_MASK) >> 20; ++ YMAX = tempReg & YMAX_MASK; ++ //XMAX = 240; ++ //YMAX = 320; ++ tempReg = READREG(PCDR); ++ PCLKDIV2 = (tempReg & PCLKDIV2_MASK) >> 4; ++ tempReg = READREG(DBMX1_LCD_PANELCFG); ++ PCD = tempReg & PCD_MASK; ++ ++ temp = (PCLKDIV2 + 1); ++ ++ if (!blink) ++ { ++ /* disable the blinking cursor function when frequency is 0 */ ++ tempReg = READREG(DBMX1_LCD_CURBLKCR); ++ tempReg &= CURSORBLINK_DIS_MASK; ++ WRITEREG(DBMX1_LCD_CURBLKCR,tempReg); ++ } ++ else ++ { ++ ++ tempMicroPeriod = temp * XMAX * YMAX * (PCD + 1); ++ temp = 96*10000000/(blink * tempMicroPeriod); ++ tempReg = READREG(DBMX1_LCD_CURBLKCR); ++ tempReg |= CURSORBLINK_EN_MASK; ++ tempReg |= temp; ++ WRITEREG(DBMX1_LCD_CURBLKCR,tempReg); ++ DPRINTK(KERN_ERR"Inter_CURBLKCR=%x\n",READREG(DBMX1_LCD_CURBLKCR)); ++ } ++ ++ FUNC_END; ++} ++ ++ /***************************************************************************** ++ * Function Name: dbmx1fb_set_cursor_state() ++ * ++ * Input: fb : frame buffer database ++ * state : The status of the cursor to be set. e.g. ++ * LCD_CURSOR_OFF ++ * LCD_CURSOR_ON ++ * LCD_CURSOR_REVERSED ++ * LCD_CURSOR_ON_WHITE ++ * LCD_CURSOR_OR_BGD ++ * LCD_CURSOR_XOR_BGD ++ * LCD_CURSOR_AND_BGD ++ * ++ * Value Returned: VOID ++ * ++ * Functions Called: VOID ++ * ++ * Description: Set state of cursor ++ * ++ * Modification History: ++ * 10 DEC,2001, Zhang Juan ++******************************************************************************/ ++static void dbmx1fb_set_cursor_state(struct dbmx1fb_info *fb,UINT32 state) ++{ ++ struct dbmx1fb_cursor *c = &fb->cursor; ++ UINT32 temp; ++ ++ FUNC_START; ++ c->state = state; ++ temp = READREG(DBMX1_LCD_LCXYP); ++ temp &= CURSOR_OFF_MASK; ++ ++ if (state == LCD_CURSOR_OFF) ++ temp = temp; ++ else if (state == LCD_CURSOR_ON) ++ temp |= CURSOR_ON_MASK; ++#ifdef FBCON_HAS_CFB4 ++ else if (state == LCD_CURSOR_REVERSED) ++ temp |= CURSOR_REVERSED_MASK; ++ else if (state == LCD_CURSOR_ON_WHITE) ++ temp |= CURSOR_WHITE_MASK; ++#elif defined(FBCON_HAS_CFB8)||defined(FBCON_HAS_CFB16) ++ else if(state == LCD_CURSOR_INVERT_BGD) ++ temp |= CURSOR_INVERT_MASK; ++ else if (state == LCD_CURSOR_OR_BGD) ++ temp |= CURSOR_OR_BGD_MASK; ++ else if (state == LCD_CURSOR_XOR_BGD) ++ temp |= CURSOR_XOR_BGD_MASK; ++ else if (state == LCD_CURSOR_AND_BGD) ++ temp |= CURSOR_AND_BGD_MASK; ++#endif ++ WRITEREG(DBMX1_LCD_LCXYP,temp); ++ DPRINTK(KERN_ERR"LCDXYP=%x\n",READREG(DBMX1_LCD_LCXYP)); ++ FUNC_END; ++} ++ ++ ++/***************************************************************************** ++ * Function Name: dbmx1fb_cursor() ++ * ++ * Input: fb : frame buffer database ++ * ++ * Value Returned: cursor : The structure of hardware cursor ++ * ++ * Functions Called: dbmx1fb_set_cursor() ++ * dbmx1fb_set_cursor_state() ++ * ++ * Description: The entry for display switch to operate hardware cursor ++ * ++ * Modification History: ++ * 10 DEC,2001, Zhang Juan ++******************************************************************************/ ++static void dbmx1fb_cursor(struct display *p, int mode, int x, int y) ++{ ++ struct dbmx1fb_info *fb = (struct dbmx1fb_info *)p->fb_info; ++ struct dbmx1fb_cursor *c = &fb->cursor; ++ ++ FUNC_START; ++ if (c==0) return; ++ ++ ++ x *= fontwidth(p); ++ y *= fontheight(p); ++ ++ c->startx = x; ++ c->starty = y; ++ ++ switch (mode) { ++ case CM_ERASE: ++ dbmx1fb_set_cursor_state(fb,LCD_CURSOR_OFF); ++ break; ++ ++ case CM_DRAW: ++ case CM_MOVE: ++ c->state = LCD_CURSOR_ON; ++ dbmx1fb_set_cursor(fb); ++ dbmx1fb_set_cursor_state(fb, c->state); ++ break; ++ } ++ FUNC_END; ++} ++ ++/***************************************************************************** ++ * Function Name: dbmx1fb_set_font() ++ * ++ * Input: display : console datebase ++ * width : The new width of cursor to be set. ++ * height : The new height of cursor position to be set ++ * ++ * Value Returned: int : Return status.If no error, return 0. ++ * ++ * Functions Called: dbmx1fb_set_cursor() ++ * dbmx1fb_set_cursor_color() ++ * ++ * Description: Set font for cursor ++ * ++ * Modification History: ++ * 10 DEC,2001, Zhang Juan ++******************************************************************************/ ++static int dbmx1fb_set_font(struct display *d, int width, int height) ++{ ++ struct dbmx1fb_info *fb=(struct dbmx1fb_info *)d->fb_info; ++ struct dbmx1fb_cursor *c = &fb->cursor; ++ ++ FUNC_START; ++ if(!d){ ++ printk(KERN_ERR"dbmx1fb_set_font d=null\n"); ++ return -1; ++ } ++ ++ if (c) { ++ if (!width || !height) { ++ width = 16; ++ height = 16; ++ } ++ ++ c->width = width; ++ c->height = height; ++ ++ DPRINTK(KERN_ERR"set cursor\n"); ++ dbmx1fb_set_cursor(fb); ++ DPRINTK(KERN_ERR"set color cursor\n"); ++ dbmx1fb_set_cursor_color(fb, cursor_color_map, ++ cursor_color_map, cursor_color_map); ++ }else{ ++ DPRINTK(KERN_ERR"set cursor failed, cursor == null\n"); ++ } ++ ++ FUNC_END; ++ return 1; ++} ++#endif // HARDWARE_CURSOR ++/* end of file */ ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/drivers/video/dbmx1fb.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,213 @@ ++/**************************************************************************** ++ * ++ * Copyright (C) 2001, Chen Ning All Rights Reserved ++ * ++ * File Name: dbmx1fb.h ++ * ++ * Progammers: Chen Ning, Zhang Juan ++ * ++ * Date of Creations: 10 DEC,2001 ++ * ++ * Synopsis: ++ * ++ * Descirption: ++ * ++ * Modification History: ++ * 10 DEC, 2001, initialization version, frame work for frame buffer driver ++ * ++*******************************************************************************/ ++ ++#ifndef LCDFB_H ++#define LCDFB_H ++#include "asm/arch/hardware.h" ++#include "asm/arch/platform.h" ++ ++typedef signed char BOOLEAN; ++typedef unsigned char UINT8; /* Unsigned 8 bit quantity */ ++typedef signed char SINT8; /* Signed 8 bit quantity */ ++typedef unsigned short UINT16; /* Unsigned 16 bit quantity */ ++typedef signed short SINT16; /* Signed 16 bit quantity */ ++typedef unsigned long UINT32; /* Unsigned 32 bit quantity */ ++typedef signed long SINT32; /* Signed 32 bit quantity */ ++ ++typedef volatile BOOLEAN VBOOLEAN; ++typedef volatile UINT8 VUINT8; /* Unsigned 8 bit quantity */ ++typedef volatile SINT8 VSINT8; /* Signed 8 bit quantity */ ++typedef volatile UINT16 VUINT16; /* Unsigned 16 bit quantity */ ++typedef volatile SINT16 VSINT16; /* Signed 16 bit quantity */ ++typedef volatile UINT32 VUINT32; /* Unsigned 32 bit quantity */ ++typedef volatile SINT32 VSINT32; /* Signed 32 bit quantity */ ++ ++#define LCDBASE 0x00205000 ++#define LCD_REGIONSIZE 0xc00 ++ ++#define DBMX1_LCD_SSA 0x00205000 ++#define DBMX1_LCD_XYMAX 0x00205004 ++#define DBMX1_LCD_VPW 0x00205008 ++#define DBMX1_LCD_LCXYP 0x0020500c ++#define DBMX1_LCD_CURBLKCR 0x00205010 ++#define DBMX1_LCD_LCHCC 0x00205014 ++#define DBMX1_LCD_PANELCFG 0x00205018 ++#define DBMX1_LCD_HCFG 0x0020501c ++#define DBMX1_LCD_VCFG 0x00205020 ++#define DBMX1_LCD_POS 0x00205024 ++#define DBMX1_LCD_LGPMR 0x00205028 ++#define DBMX1_LCD_PWMR 0x0020502c ++#define DBMX1_LCD_DMACR 0x00205030 ++#define DBMX1_LCD_REFMCR 0x00205034 ++#define DBMX1_LCD_INTCR 0x00205038 ++#define DBMX1_LCD_INTSR 0x00205040 ++#define DBMX1_LCD_MAPRAM 0x00205800 ++ ++#define MPCTL0 0x0021B004 ++#define PCDR 0X0021B020 ++ ++#define SSA DBMX1_LCD_SSA ++#define XYMAX DBMX1_LCD_XYMAX ++#define VPW DBMX1_LCD_VPW ++#define LCXYP DBMX1_LCD_LCXYP ++#define CURBLKCR DBMX1_LCD_CURBLKCR ++#define LCHCC DBMX1_LCD_LCHCC ++#define PANELCFG DBMX1_LCD_PANELCFG ++#define VCFG DBMX1_LCD_VCFG ++#define HCFG DBMX1_LCD_HCFG ++#define POS DBMX1_LCD_POS ++#define LGPMR DBMX1_LCD_LGPMR ++#define PWMR DBMX1_LCD_PWMR ++#define DMACR DBMX1_LCD_DMACR ++#define REFMCR DBMX1_LCD_REFMCR ++#define INTCR DBMX1_LCD_INTCR ++#define INTSR DBMX1_LCD_INTSR ++#define MAPRAM DBMX1_LCD_MAPRAM ++// default value ++#define SHARP_TFT_240x320 ++ ++#ifdef SHARP_TFT_240x320 ++#define PANELCFG_VAL_12 0xf8008b48 ++#define HCFG_VAL_12 0x04000f06 ++#define VCFG_VAL_12 0x04000907 ++#define PWMR_VAL 0x0000008a ++#define LCD_MAXX 240 ++#define LCD_MAXY 320 ++#else //SHARP_TFT_240x320 ++ ++#define PANELCFG_VAL_12 0xf8088c6b ++#define HCFG_VAL_12 0x04000f06 ++#define VCFG_VAL_12 0x04010c03 ++#define PWMR_VAL 0x00000200 ++#define LCD_MAXX 320 ++#define LCD_MAXY 240 ++#endif // SHARP_TFT_240x320 ++ ++#define PANELCFG_VAL_4 0x20008c09 ++#define PANELCFG_VAL_4C 0x60008c09 ++ ++#define HCFG_VAL_4 0x04000f07 ++ ++#define VCFG_VAL_4 0x04010c03 ++ ++ ++#define REFMCR_VAL_4 0x00000003 ++#define REFMCR_VAL_12 0x00000003 ++#define DISABLELCD_VAL 0x00000000 ++ ++#define DMACR_VAL_4 0x800c0003 // 12 & 3 TRIGGER ++#define DMACR_VAL_12 0x00020008 ++ ++#define INTCR_VAL_4 0x00000000 ++#define INTCR_VAL_12 0x00000000 ++ ++#define INTSR_UDRERR 0x00000008 ++#define INTSR_ERRRESP 0x00000004 ++#define INTSR_EOF 0x00000002 ++#define INTSR_BOF 0x00000001 ++ ++#define MIN_XRES 64 ++#define MIN_YRES 64 ++ ++#define LCD_MAX_BPP 16 ++ ++#if 0 ++#define READREG(r) \ ++ inl(IO_ADDRESS(r)) ++ ++#define WRITEREG(r, val) \ ++ outl(val, IO_ADDRESS(r)) ++#else ++#endif // 0 ++ ++#define MAX_PALETTE_NUM_ENTRIES 256 ++#define MAX_PIXEL_MEM_SIZE \ ++ ((current_par.max_xres * current_par.max_yres * current_par.max_bpp)/8) ++#define MAX_FRAMEBUFFER_MEM_SIZE \ ++ (MAX_PIXEL_MEM_SIZE + 32) ++#define ALLOCATED_FB_MEM_SIZE \ ++ (PAGE_ALIGN(MAX_FRAMEBUFFER_MEM_SIZE + PAGE_SIZE * 2)) ++ ++ // TODO: ++#define FBCON_HAS_CFB4 ++#define FBCON_HAS_CFB8 ++#define FBCON_HAS_CFB16 ++ ++#define IRQ_LCD 12 // TODO: which irq? ++#define DBMX1_NAME "DBMX1FB" ++#define DEV_NAME DBMX1_NAME ++#define MAX_PALETTE_NUM_ENTRIES 256 ++#define DEFAULT_CURSOR_BLINK_RATE (20) ++#define CURSOR_DRAW_DELAY (2) ++/*cursor status*/ ++#define LCD_CURSOR_OFF 0 ++#define LCD_CURSOR_ON 1 ++ ++#ifdef FBCON_HAS_CFB4 ++ #define LCD_CURSOR_REVERSED 2 ++ #define LCD_CURSOR_ON_WHITE 3 ++#elif defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) ++ #define LCD_CURSOR_INVERT_BGD 2 ++ #define LCD_CURSOR_AND_BGD 3 ++ #define LCD_CURSOR_OR_BGD 4 ++ #define LCD_CURSOR_XOR_BGD 5 ++#endif //FBCON_HAS_CFB4 ++ ++/* MASK use for caculating MCDUPLLCLK */ ++#define MFI_MASK 0x00003C00 ++#define MFN_MASK 0x000003FF ++#define PD_MASK 0x3C000000 ++#define MFD_MASK 0x03FF0000 ++#define PCLKDIV2_MASK 0x000000F0 ++#define PCD_MASK 0x0000003F ++#define XMAX_MASK 0xF3F00000 ++#define YMAX_MASK 0x000001FF ++#define HWAIT1_MASK 0x0000FF00 ++#define HWAIT2_MASK 0x000000FF ++#define HWIDTH_MASK 0xFC000000 ++#define PASSDIV_MASK 0x00FF0000 ++#define VWAIT1_MASK 0x0000FF00 ++#define VWAIT2_MASK 0x000000FF ++#define VWIDTH_MASK 0xFC000000 ++#define CURSORBLINK_DIS_MASK 0x80000000 ++ ++#define DISPLAY_MODE_MASK 0x80000000 ++ ++#define MCU_FREQUENCE 32768 ++#define COLOR_MASK 0x40000000 ++ ++/* MASK use for indicating the cursor status */ ++#define CURSOR_ON_MASK 0x40000000 ++#define CURSOR_OFF_MASK 0x0FFFFFFF ++#define MAX_CURSOR_WIDTH 31 ++#define MAX_CURSOR_HEIGHT 31 ++#define CURSORBLINK_EN_MASK 0x80000000 ++ ++#ifdef FBCON_HAS_CFB4 ++#define CURSOR_REVERSED_MASK 0x80000000 ++#define CURSOR_WHITE_MASK 0xC0000000 ++#else ++#define CURSOR_INVERT_MASK 0x80000000 ++#define CURSOR_AND_BGD_MASK 0xC0000000 ++#define CURSOR_OR_BGD_MASK 0x50000000 ++#define CURSOR_XOR_BGD_MASK 0x90000000 ++#endif // FBCON_HAS_CFB4 ++ ++#endif //LCDFB_H ++ +--- linux-2.4.25/drivers/video/fbmem.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/drivers/video/fbmem.c 2004-03-31 17:15:09.000000000 +0200 +@@ -61,7 +61,9 @@ + extern int pm2fb_setup(char*); + extern int pm3fb_init(void); + extern int pm3fb_setup(char*); ++extern int clps711xfb_init(void); + extern int cyber2000fb_init(void); ++extern int cyber2000fb_setup(char*); + extern int retz3fb_init(void); + extern int retz3fb_setup(char*); + extern int clgenfb_init(void); +@@ -145,6 +147,8 @@ + extern int sstfb_setup(char*); + extern int it8181fb_init(void); + extern int it8181fb_setup(char*); ++extern int anakinfb_init(void); ++extern int dbmx1fb_init(void); + + static struct { + const char *name; +@@ -170,11 +174,14 @@ + #ifdef CONFIG_FB_AMIGA + { "amifb", amifb_init, amifb_setup }, + #endif ++#ifdef CONFIG_FB_CLPS711X ++ { "clps711xfb", clps711xfb_init, NULL }, ++#endif + #ifdef CONFIG_FB_CYBER + { "cyber", cyberfb_init, cyberfb_setup }, + #endif + #ifdef CONFIG_FB_CYBER2000 +- { "cyber2000", cyber2000fb_init, NULL }, ++ { "cyber2000", cyber2000fb_init, cyber2000fb_setup }, + #endif + #ifdef CONFIG_FB_PM2 + { "pm2fb", pm2fb_init, pm2fb_setup }, +@@ -226,10 +233,10 @@ + #endif + #ifdef CONFIG_FB_S3TRIO + { "s3trio", s3triofb_init, NULL }, +-#endif ++#endif + #ifdef CONFIG_FB_FM2 + { "fm2fb", fm2fb_init, fm2fb_setup }, +-#endif ++#endif + #ifdef CONFIG_FB_SIS + { "sisfb", sisfb_init, sisfb_setup }, + #endif +@@ -242,7 +249,7 @@ + + /* + * Generic drivers that are used as fallbacks +- * ++ * + * These depend on resource management and must be initialized + * _after_ all other frame buffer devices that use resource + * management! +@@ -253,7 +260,7 @@ + #endif + #ifdef CONFIG_FB_VESA + { "vesa", vesafb_init, vesafb_setup }, +-#endif ++#endif + + /* + * Chipset specific drivers that don't use resource management (yet) +@@ -276,7 +283,7 @@ + #endif + #ifdef CONFIG_FB_HGA + { "hga", hgafb_init, hgafb_setup }, +-#endif ++#endif + #ifdef CONFIG_FB_IGA + { "igafb", igafb_init, igafb_setup }, + #endif +@@ -291,7 +298,7 @@ + #endif + #ifdef CONFIG_FB_HP300 + { "hpfb", hpfb_init, NULL }, +-#endif ++#endif + #ifdef CONFIG_FB_G364 + { "g364", g364fb_init, NULL }, + #endif +@@ -307,6 +314,9 @@ + #ifdef CONFIG_FB_TX3912 + { "tx3912", tx3912fb_init, NULL }, + #endif ++#ifdef CONFIG_FB_ANAKIN ++ { "anakinfb", anakinfb_init, NULL }, ++#endif + #ifdef CONFIG_FB_E1355 + { "e1355fb", e1355fb_init, e1355fb_setup }, + #endif +@@ -330,10 +340,13 @@ + #endif + #ifdef CONFIG_FB_AU1100 + { "au1100fb", au1100fb_init, au1100fb_setup }, +-#endif ++#endif + #ifdef CONFIG_FB_IT8181 + { "it8181fb", it8181fb_init, it8181fb_setup }, + #endif ++#ifdef CONFIG_FB_DBMX1 ++ { "dbmx1fb", dbmx1fb_init, NULL }, ++#endif + + + /* +@@ -342,7 +355,7 @@ + + #ifdef CONFIG_FB_VGA16 + { "vga16", vga16fb_init, vga16fb_setup }, +-#endif ++#endif + #ifdef CONFIG_FB_STI + { "stifb", stifb_init, stifb_setup }, + #endif +@@ -371,7 +384,7 @@ + + struct fb_info *registered_fb[FB_MAX]; + int num_registered_fb; +-extern int fbcon_softback_size; ++extern int fbcon_softback_size; + + static int first_fb_vc; + static int last_fb_vc = MAX_NR_CONSOLES-1; +@@ -480,7 +493,7 @@ + } + #endif /* CONFIG_KMOD */ + +-static int ++static int + fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) + { +@@ -492,7 +505,7 @@ + struct fb_fix_screeninfo fix; + struct fb_con2fbmap con2fb; + int i; +- ++ + if (! fb) + return -ENODEV; + switch (cmd) { +@@ -576,7 +589,7 @@ + } + } + +-static int ++static int + fb_mmap(struct file *file, struct vm_area_struct * vma) + { + int fbidx = GET_FB_IDX(file->f_dentry->d_inode->i_rdev); +@@ -667,11 +680,11 @@ + #elif defined(__sh__) + pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE; + #elif defined(__hppa__) +- pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; ++ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; + #elif defined(__ia64__) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + #elif defined(__hppa__) +- pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; ++ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; + #else + #warning What do we have to do here?? + #endif +@@ -724,7 +737,7 @@ + return res; + } + +-static int ++static int + fb_release(struct inode *inode, struct file *file) + { + int fbidx = GET_FB_IDX(inode->i_rdev); +@@ -856,7 +869,7 @@ + * + */ + +-void __init ++void __init + fbmem_init(void) + { + int i; +@@ -904,7 +917,7 @@ + + if (!options || !*options) + return 0; +- ++ + if (!strncmp(options, "scrollback:", 11)) { + options += 11; + if (*options) { +@@ -930,7 +943,7 @@ + } + return 0; + } +- ++ + if (!strncmp(options, "vc:", 3)) { + options += 3; + if (*options) +--- linux-2.4.25/drivers/video/font_acorn_8x8.c~2.4.25-vrs2.patch 1998-09-30 05:56:33.000000000 +0200 ++++ linux-2.4.25/drivers/video/font_acorn_8x8.c 2004-03-31 17:15:09.000000000 +0200 +@@ -11,33 +11,33 @@ + /* 03 */ 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, /* ^C */ + /* 04 */ 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, /* ^D */ + /* 05 */ 0x00, 0x18, 0x3c, 0xe7, 0xe7, 0x3c, 0x18, 0x00, /* ^E */ +-/* 06 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 07 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 09 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 0A */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 0B */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 0C */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 0D */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 0E */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 0F */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++/* 06 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 07 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 08 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 09 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 0A */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 0B */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 0C */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 0D */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 0E */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 0F */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, + /* 10 */ 0x00, 0x60, 0x78, 0x7e, 0x7e, 0x78, 0x60, 0x00, /* |> */ + /* 11 */ 0x00, 0x06, 0x1e, 0x7e, 0x7e, 0x1e, 0x06, 0x00, /* <| */ +-/* 12 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 13 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 14 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 15 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 16 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 17 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 19 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 1A */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 1B */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 1C */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 1D */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++/* 12 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 13 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 14 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 15 */ 0x3c, 0x60, 0x3c, 0x66, 0x3c, 0x06, 0x3c, 0x00, ++/* 16 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 17 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 18 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 19 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 1A */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 1B */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 1C */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 1D */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, + /* 1E */ 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x7e, 0x7e, 0x00, /* /\ */ + /* 1F */ 0x00, 0x7e, 0x7e, 0x3c, 0x3c, 0x18, 0x18, 0x00, /* \/ */ +-/* 20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* */ ++/* 20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* */ + /* 21 */ 0x18, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x00, /* ! */ + /* 22 */ 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, /* " */ + /* 23 */ 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00, /* # */ +@@ -132,55 +132,55 @@ + /* 7C */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, /* | */ + /* 7D */ 0x30, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x30, 0x00, /* } */ + /* 7E */ 0x31, 0x6B, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, /* ~ */ +-/* 7F */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* */ +-/* 80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 81 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 82 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 83 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 84 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 85 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 86 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 87 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 88 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 89 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 8A */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 8B */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 8C */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 8D */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 8E */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 8F */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 91 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 92 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 93 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 94 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 95 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 97 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 98 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 99 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 9A */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 9B */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 9C */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 9D */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 9E */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* 9F */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* A1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* A2 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* A3 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* A4 */ 0x00, 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, +-/* A8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* A9 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* AA */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* AB */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* AC */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* AD */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* AE */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* AF */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++/* 7F */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* */ ++/* 80 */ 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x30, 0x60, ++/* 81 */ 0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x00, ++/* 82 */ 0x0c, 0x18, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, ++/* 83 */ 0x18, 0x66, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00, ++/* 84 */ 0x66, 0x00, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00, ++/* 85 */ 0x30, 0x18, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00, ++/* 86 */ 0x3c, 0x66, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00, ++/* 87 */ 0x00, 0x00, 0x3c, 0x66, 0x60, 0x66, 0x3c, 0x60, ++/* 88 */ 0x3c, 0x66, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, ++/* 89 */ 0x66, 0x00, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, ++/* 8A */ 0x30, 0x18, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, ++/* 8B */ 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00, ++/* 8C */ 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00, ++/* 8D */ 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00, ++/* 8E */ 0x66, 0x66, 0x00, 0x3c, 0x66, 0x7e, 0x66, 0x00, ++/* 8F */ 0x18, 0x66, 0x00, 0x3c, 0x66, 0x7e, 0x66, 0x00, ++/* 90 */ 0x0c, 0x18, 0x7e, 0x60, 0x7c, 0x60, 0x7e, 0x00, ++/* 91 */ 0x00, 0x00, 0x3f, 0x0d, 0x3f, 0x6c, 0x3f, 0x00, ++/* 92 */ 0x3f, 0x66, 0x66, 0x7f, 0x66, 0x66, 0x67, 0x00, ++/* 93 */ 0x3c, 0x66, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00, ++/* 94 */ 0x66, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00, ++/* 95 */ 0x30, 0x18, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00, ++/* 96 */ 0x3c, 0x66, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x00, ++/* 97 */ 0x30, 0x18, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x00, ++/* 98 */ 0x66, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x3c, ++/* 99 */ 0x66, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x00, ++/* 9A */ 0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, ++/* 9B */ 0x08, 0x3e, 0x6b, 0x68, 0x6b, 0x3e, 0x08, 0x00, ++/* 9C */ 0x1c, 0x36, 0x30, 0x7c, 0x30, 0x30, 0x7e, 0x00, ++/* 9D */ 0x66, 0x3c, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, ++/* 9E */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* 9F */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* A0 */ 0x0c, 0x18, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00, ++/* A1 */ 0x0c, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00, ++/* A2 */ 0x0c, 0x18, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00, ++/* A3 */ 0x0c, 0x18, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x00, ++/* A4 */ 0x36, 0x6c, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x00, ++/* A5 */ 0x36, 0x6c, 0x00, 0x66, 0x76, 0x6e, 0x66, 0x00, ++/* A6 */ 0x1c, 0x06, 0x1e, 0x36, 0x1e, 0x00, 0x3e, 0x00, ++/* A7 */ 0x1c, 0x36, 0x36, 0x36, 0x1c, 0x00, 0x3e, 0x00, ++/* A8 */ 0x18, 0x00, 0x18, 0x18, 0x30, 0x66, 0x3c, 0x00, ++/* A9 */ 0x7e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++/* AA */ 0x7e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++/* AB */ 0x40, 0xc0, 0x40, 0x4f, 0x41, 0x0f, 0x08, 0x0f, ++/* AC */ 0x40, 0xc0, 0x40, 0x48, 0x48, 0x0a, 0x0f, 0x02, ++/* AD */ 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, ++/* AE */ 0x00, 0x33, 0x66, 0xcc, 0xcc, 0x66, 0x33, 0x00, ++/* AF */ 0x00, 0xcc, 0x66, 0x33, 0x33, 0x66, 0xcc, 0x00, + /* B0 */ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, + /* B1 */ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, + /* B2 */ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, +@@ -229,37 +229,37 @@ + /* DD */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + /* DE */ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + /* DF */ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, +-/* E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* E1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* E2 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* E3 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* E4 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* E5 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* E6 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* E7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* E8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* E9 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* EA */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* EB */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* EC */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* ED */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* EE */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* EF */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* F1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* F2 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* F3 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* F4 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* F5 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* F6 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* F7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* F8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* F9 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* FA */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* FB */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* FC */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* FD */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +-/* FE */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++/* E0 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* E1 */ 0x3c, 0x66, 0x66, 0x6c, 0x66, 0x66, 0x6c, 0xc0, ++/* E2 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* E3 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* E4 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* E5 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* E6 */ 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x60, ++/* E7 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* E8 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* E9 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* EA */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* EB */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* EC */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* ED */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* EE */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* EF */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* F0 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* F1 */ 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x7e, 0x00, ++/* F2 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* F3 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* F4 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* F5 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* F6 */ 0x00, 0x18, 0x00, 0xff, 0x00, 0x18, 0x00, 0x00, ++/* F7 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* F8 */ 0x3c, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, ++/* F9 */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* FA */ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, ++/* FB */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* FC */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, ++/* FD */ 0x38, 0x04, 0x18, 0x20, 0x3c, 0x00, 0x00, 0x00, ++/* FE */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, + /* FF */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + +--- linux-2.4.25/drivers/video/pm3fb.c~2.4.25-vrs2.patch 2002-08-03 02:39:45.000000000 +0200 ++++ linux-2.4.25/drivers/video/pm3fb.c 2004-03-31 17:15:09.000000000 +0200 +@@ -5,7 +5,6 @@ + * Based on code written by: + * Sven Luther, <luther@dpt-info.u-strasbg.fr> + * Alan Hourihane, <alanh@fairlite.demon.co.uk> +- * Russel King, <rmk@arm.linux.org.uk> + * Based on linux/drivers/video/skeletonfb.c: + * Copyright (C) 1997 Geert Uytterhoeven + * Based on linux/driver/video/pm2fb.c: +@@ -16,13 +15,9 @@ + * License. See the file COPYING in the main directory of this archive for + * more details. + * +- * $Header$ ++ * $Header$ + * + * CHANGELOG: +- * Mon Feb 11 10:35:48 MET 2002, v 1.4.11B: Cosmetic update. +- * Wed Jan 23 14:16:59 MET 2002, v 1.4.11: Preliminary 2.5.x support, patch for 2.5.2. +- * Wed Nov 28 11:08:29 MET 2001, v 1.4.10: potential bug fix for SDRAM-based board, patch for 2.4.16. +- * Thu Sep 20 10:24:42 MET DST 2001, v 1.4.9: sync bug fix, preliminary flatpanel support, better timings. + * Tue Aug 28 10:13:01 MET DST 2001, v 1.4.8: memory timings check, minor bug fixes. + * Wed Jul 18 19:06:14 CEST 2001, v 1.4.7: Mode fix (800x600-100, 1024x768-100 changed), using HW panning + accel bug fix. + * Mon Jun 25 10:33:56 MET DST 2001, v 1.4.6: Depth 12 fix, chip reset ioctl, moved memory erase ioctl to DEBUG. +@@ -53,8 +48,8 @@ + */ + + #include <linux/config.h> +-#include <linux/module.h> + #include <linux/version.h> ++#include <linux/module.h> + #include <linux/kernel.h> + #include <linux/errno.h> + #include <linux/string.h> +@@ -80,7 +75,6 @@ + + #include <asm/io.h> + #include <asm/uaccess.h> +- + #ifdef CONFIG_FB_OF + #include <asm/prom.h> + #endif +@@ -128,7 +122,6 @@ + unsigned long refresh; + unsigned long powerdown; + }; +-typedef enum pm3fb_timing_result { pm3fb_timing_ok, pm3fb_timing_problem, pm3fb_timing_retry } pm3fb_timing_result; + #define PM3FB_UNKNOWN_TIMING_VALUE ((unsigned long)-1) + #define PM3FB_UNKNOWN_TIMINGS { PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE } + +@@ -191,21 +184,13 @@ + PM3VideoControl_VSYNC_ACTIVE_HIGH + | PM3VideoControl_PIXELSIZE_8BIT}}, { + "1024x768-74-32", { +- 78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38, +- 806, 1024, 0, 32, +- PM3VideoControl_ENABLE | +- PM3VideoControl_HSYNC_ACTIVE_HIGH +- | +- PM3VideoControl_VSYNC_ACTIVE_HIGH +- | PM3VideoControl_PIXELSIZE_32BIT}}, +-/* Generated mode : "1600x1024", for the SGI 1600SW flat panel*/ +- { +- "SGI1600SW", { +- 108000, 1600, 1024, 16, 56, 104, 1704, 3, 6, 32, +- 1056, 1600, 0, 8, +- PM3VideoControl_ENABLE| +- PM3VideoControl_HSYNC_ACTIVE_LOW|PM3VideoControl_VSYNC_ACTIVE_LOW| +- PM3VideoControl_PIXELSIZE_32BIT}}, ++ 78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38, ++ 806, 1024, 0, 32, ++ PM3VideoControl_ENABLE | ++ PM3VideoControl_HSYNC_ACTIVE_HIGH ++ | ++ PM3VideoControl_VSYNC_ACTIVE_HIGH ++ | PM3VideoControl_PIXELSIZE_32BIT}}, + /* ##### auto-generated mode, by fbtimings2pm3 */ + /* Generated mode : "640x480-60" */ + { +@@ -554,11 +539,9 @@ + short noaccel[PM3_MAX_BOARD]; + char fontn[PM3_MAX_BOARD][PM3_FONTNAME_SIZE]; + short depth[PM3_MAX_BOARD]; +-short flatpanel[PM3_MAX_BOARD]; + static struct display disp[PM3_MAX_BOARD]; + static char g_options[PM3_OPTIONS_SIZE] __initdata = "pm3fb,dummy"; + short printtimings = 0; +-short forcesize[PM3_MAX_BOARD]; + + /* ********************* */ + /* ***** prototype ***** */ +@@ -566,8 +549,7 @@ + /* card-specific */ + static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info); + /* permedia3-specific */ +-static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info); +-static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info); ++static int pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info); + static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info); + static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info, + unsigned long r); +@@ -683,7 +665,7 @@ + NULL, NULL + }; + #endif /* KERNEL_2_2 */ +-#if (defined KERNEL_2_4) || (defined KERNEL_2_5) ++#ifdef KERNEL_2_4 + struct fbgen_hwswitch pm3fb_switch = { + pm3fb_detect, pm3fb_encode_fix, pm3fb_decode_var, pm3fb_encode_var, + pm3fb_get_par, pm3fb_set_par, pm3fb_getcolreg, pm3fb_setcolreg, +@@ -696,7 +678,7 @@ + fbgen_get_fix, fbgen_get_var, fbgen_set_var, + fbgen_get_cmap, fbgen_set_cmap, fbgen_pan_display, pm3fb_ioctl, NULL, NULL + }; +-#endif /* KERNEL_2_4 or KERNEL_2_5 */ ++#endif /* KERNEL_2_4 */ + #ifdef PM3FB_USE_ACCEL + #ifdef FBCON_HAS_CFB32 + static struct display_switch pm3fb_cfb32 = { +@@ -727,75 +709,52 @@ + #endif /* FBCON_HAS_CFB8 */ + #endif /* PM3FB_USE_ACCEL */ + +-/* ****************************** */ +-/* ***** card-specific data ***** */ +-/* ****************************** */ +-struct pm3fb_card_timings { +- unsigned long memsize; /* 0 for last value (i.e. default) */ +- struct pm3fb_timings memt; +-}; +- +-static struct pm3fb_card_timings t_FormacProFormance3[] = { +- { 16, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} }, +- { 0, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} } /* from 16 MB PF3 */ +-}; +- +-static struct pm3fb_card_timings t_AppianJeronimo2000[] = { +- { 32, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} }, +- { 0, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} } /* from 32MB J2000 */ +-}; +- +-static struct pm3fb_card_timings t_3DLabsOxygenVX1[] = { +- { 32, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} }, +- { 0, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} } /* from 32MB VX1 */ +-}; +- ++/* ********************************** */ ++/* ***** card-specific function ***** */ ++/* ********************************** */ + static struct { + char cardname[32]; /* recognized card name */ + u16 subvendor; /* subvendor of the card */ + u16 subdevice; /* subdevice of the card */ + u8 func; /* function of the card to which the extra init apply */ + void (*specific_setup)(struct pm3fb_info *l_fb_info); /* card/func specific setup, done before _any_ FB access */ +- struct pm3fb_card_timings *c_memt; /* defauls timings for the boards */ ++ struct pm3fb_timings memt; /* default timing for the board WARNING : might be *card* - specific */ + } cardbase[] = { +- { "Unknown Permedia3 board", 0xFFFF, 0xFFFF, 0xFF, NULL, NULL }, +- { "Appian Jeronimo 2000 head 1", 0x1097, 0x3d32, 1, NULL, +- t_AppianJeronimo2000 +- }, ++ { "Unknown Permedia3 board", 0xFFFF, 0xFFFF, 0xFF, NULL, PM3FB_UNKNOWN_TIMINGS }, ++ { "Appian Jeronimo 2000 head 1", 0x1097, 0x3d32, 1, NULL, PM3FB_UNKNOWN_TIMINGS }, + { "Appian Jeronimo 2000 head 2", 0x1097, 0x3d32, 2, pm3fb_j2000_setup, +- t_AppianJeronimo2000 ++ {0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} /* also in pm3fb_j2000_setup */ + }, + { "Formac ProFormance 3", PCI_VENDOR_ID_3DLABS, 0x000a, 0, NULL, /* Formac use 3DLabs ID ?!? */ +- t_FormacProFormance3 ++ { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} /* from the 16Mb ProFormance 3 */ + }, +- { "3DLabs Permedia3 Create!", PCI_VENDOR_ID_3DLABS, 0x0127, 0, NULL, NULL }, ++ { "3DLabs Permedia3 Create!", PCI_VENDOR_ID_3DLABS, 0x0127, 0, NULL, PM3FB_UNKNOWN_TIMINGS }, + { "3DLabs Oxygen VX1 PCI", PCI_VENDOR_ID_3DLABS, 0x0121, 0, NULL, +- t_3DLabsOxygenVX1 ++ { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000 } + }, +- { "3DLabs Oxygen VX1 AGP", PCI_VENDOR_ID_3DLABS, 0x0125, 0, NULL, NULL }, +- { "3DLabs Oxygen VX1-16 AGP", PCI_VENDOR_ID_3DLABS, 0x0140, 0, NULL, NULL }, +- { "3DLabs Oxygen VX1-1600SW PCI", PCI_VENDOR_ID_3DLABS, 0x0800, 0, NULL, NULL }, +- { "\0", 0x0, 0x0, 0, NULL, NULL } ++ { "3DLabs Oxygen VX1 AGP", PCI_VENDOR_ID_3DLABS, 0x0125, 0, NULL, PM3FB_UNKNOWN_TIMINGS }, ++ { "3DLabs Oxygen VX1-16 AGP", PCI_VENDOR_ID_3DLABS, 0x0140, 0, NULL, PM3FB_UNKNOWN_TIMINGS }, ++ { "3DLabs Oxygen VX1-1600SW PCI", PCI_VENDOR_ID_3DLABS, 0x0800, 0, NULL, PM3FB_UNKNOWN_TIMINGS }, ++ { "\0", 0x0, 0x0, 0, NULL, PM3FB_UNKNOWN_TIMINGS } + }; + +-/* ********************************** */ +-/* ***** card-specific function ***** */ +-/* ********************************** */ + static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info) + { /* the appian j2000 require more initialization of the second head */ + /* l_fb_info must point to the _second_ head of the J2000 */ + + DTRACE; +- +- l_fb_info->memt = t_AppianJeronimo2000[0].memt; /* 32 MB, first and only j2000 ? */ ++ ++ /* Memory timings for the Appian J2000 board. also in cardbase */ ++ l_fb_info->memt.caps = 0x02e311B8; ++ l_fb_info->memt.timings = 0x07424905; ++ l_fb_info->memt.control = 0x0c000003; ++ l_fb_info->memt.refresh = 0x00000061; ++ l_fb_info->memt.powerdown = 0x00000000; + + pm3fb_write_memory_timings(l_fb_info); + } + +-/* *************************************** */ +-/* ***** permedia3-specific function ***** */ +-/* *************************************** */ +-static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info) ++static int pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info) + { + l_fb_info->memt.caps = PM3_READ_REG(PM3LocalMemCaps); + l_fb_info->memt.timings = PM3_READ_REG(PM3LocalMemTimings); +@@ -810,35 +769,20 @@ + (l_fb_info->memt.powerdown == PM3FB_UNKNOWN_TIMING_VALUE)) + { + printk(KERN_ERR "pm3fb: invalid memory timings in permedia3 board #%ld\n", l_fb_info->board_num); +- return(pm3fb_try_memory_timings(l_fb_info)); +- } +- return(pm3fb_timing_ok); +-} +- +-static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info) +-{ +- if (cardbase[l_fb_info->board_type].c_memt) +- { +- int i = 0, done = 0; +- while (!done) ++ if ((cardbase[l_fb_info->board_type].memt.caps != PM3FB_UNKNOWN_TIMING_VALUE) && ++ (cardbase[l_fb_info->board_type].memt.timings != PM3FB_UNKNOWN_TIMING_VALUE) && ++ (cardbase[l_fb_info->board_type].memt.control != PM3FB_UNKNOWN_TIMING_VALUE) && ++ (cardbase[l_fb_info->board_type].memt.refresh != PM3FB_UNKNOWN_TIMING_VALUE) && ++ (cardbase[l_fb_info->board_type].memt.powerdown != PM3FB_UNKNOWN_TIMING_VALUE)) + { +- if ((cardbase[l_fb_info->board_type].c_memt[i].memsize == l_fb_info->fb_size) +- || !(cardbase[l_fb_info->board_type].c_memt[i].memsize)) +- { /* will use the 0-sized timings by default */ +- done = 1; +- l_fb_info->memt = cardbase[l_fb_info->board_type].c_memt[i].memt; +- printk(KERN_WARNING "pm3fb: trying to use predefined memory timings for permedia3 board #%ld (%s, %ld MB)\n", +- l_fb_info->board_num, +- cardbase[l_fb_info->board_type].cardname, +- cardbase[l_fb_info->board_type].c_memt[i].memsize); +- pm3fb_write_memory_timings(l_fb_info); +- return(pm3fb_timing_retry); +- } +- i++; ++ l_fb_info->memt = cardbase[l_fb_info->board_type].memt; ++ printk(KERN_WARNING "pm3fb: trying to use predefined memory timings for permedia3 board #%ld (%s)\n", l_fb_info->board_num, cardbase[l_fb_info->board_type].cardname); ++ pm3fb_write_memory_timings(l_fb_info); + } +- } else +- return(pm3fb_timing_problem); +- return(pm3fb_timing_ok); ++ else ++ return(1); ++ } ++ return(0); + } + + static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info) +@@ -873,6 +817,10 @@ + PM3RD_SClkControl_ENABLE); + } + ++/* *************************************** */ ++/* ***** permedia3-specific function ***** */ ++/* *************************************** */ ++ + static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info, + unsigned long r) + { +@@ -1067,7 +1015,6 @@ + /* write the mode to registers */ + static void pm3fb_write_mode(struct pm3fb_info *l_fb_info) + { +- char tempsync = 0x00, tempmisc = 0x00; + DTRACE; + + PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xffffffff); +@@ -1197,26 +1144,22 @@ + /* + PM3_SLOW_WRITE_REG(PM3RD_IndexControl, 0x00); + */ +- if ((l_fb_info->current_par->video & PM3VideoControl_HSYNC_MASK) == +- PM3VideoControl_HSYNC_ACTIVE_HIGH) +- tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH; +- if ((l_fb_info->current_par->video & PM3VideoControl_VSYNC_MASK) == +- PM3VideoControl_VSYNC_ACTIVE_HIGH) +- tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH; +- +- PM3_WRITE_DAC_REG(PM3RD_SyncControl, tempsync); +- DPRINTK(2, "PM3RD_SyncControl: %d\n", tempsync); +- +- if (flatpanel[l_fb_info->board_num]) + { +- PM3_WRITE_DAC_REG(PM3RD_DACControl, PM3RD_DACControl_BLANK_PEDESTAL_ENABLE); +- PM3_WAIT(2); +- PM3_WRITE_REG(PM3VSConfiguration, 0x06); +- PM3_WRITE_REG(0x5a00, 1 << 14); /* black magic... */ +- tempmisc = PM3RD_MiscControl_VSB_OUTPUT_ENABLE; ++ char tempsync = 0x00; ++ ++ if ((l_fb_info->current_par-> ++ video & PM3VideoControl_HSYNC_MASK) == ++ PM3VideoControl_HSYNC_ACTIVE_HIGH) ++ tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH; ++ if ((l_fb_info->current_par-> ++ video & PM3VideoControl_VSYNC_MASK) == ++ PM3VideoControl_VSYNC_ACTIVE_HIGH) ++ tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH; ++ ++ PM3_WRITE_DAC_REG(PM3RD_SyncControl, tempsync); ++ DPRINTK(2, "PM3RD_SyncControl: %d\n", tempsync); + } +- else +- PM3_WRITE_DAC_REG(PM3RD_DACControl, 0x00); ++ PM3_WRITE_DAC_REG(PM3RD_DACControl, 0x00); + + switch (l_fb_info->current_par->depth) { + case 8: +@@ -1225,7 +1168,8 @@ + PM3_WRITE_DAC_REG(PM3RD_ColorFormat, + PM3RD_ColorFormat_CI8_COLOR | + PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); +- tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; ++ PM3_WRITE_DAC_REG(PM3RD_MiscControl, ++ PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE); + break; + case 12: + PM3_WRITE_DAC_REG(PM3RD_PixelSize, +@@ -1234,8 +1178,9 @@ + PM3RD_ColorFormat_4444_COLOR | + PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | + PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); +- tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | +- PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; ++ PM3_WRITE_DAC_REG(PM3RD_MiscControl, ++ PM3RD_MiscControl_DIRECTCOLOR_ENABLE | ++ PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE); + break; + case 15: + PM3_WRITE_DAC_REG(PM3RD_PixelSize, +@@ -1244,8 +1189,9 @@ + PM3RD_ColorFormat_5551_FRONT_COLOR | + PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | + PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); +- tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | +- PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; ++ PM3_WRITE_DAC_REG(PM3RD_MiscControl, ++ PM3RD_MiscControl_DIRECTCOLOR_ENABLE | ++ PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE); + break; + case 16: + PM3_WRITE_DAC_REG(PM3RD_PixelSize, +@@ -1254,8 +1200,9 @@ + PM3RD_ColorFormat_565_FRONT_COLOR | + PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | + PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); +- tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | +- PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; ++ PM3_WRITE_DAC_REG(PM3RD_MiscControl, ++ PM3RD_MiscControl_DIRECTCOLOR_ENABLE | ++ PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE); + break; + case 32: + PM3_WRITE_DAC_REG(PM3RD_PixelSize, +@@ -1263,12 +1210,12 @@ + PM3_WRITE_DAC_REG(PM3RD_ColorFormat, + PM3RD_ColorFormat_8888_COLOR | + PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); +- tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | +- PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; ++ PM3_WRITE_DAC_REG(PM3RD_MiscControl, ++ PM3RD_MiscControl_DIRECTCOLOR_ENABLE | ++ PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE); + break; + } +- PM3_WRITE_DAC_REG(PM3RD_MiscControl, tempmisc); +- ++ + PM3_SHOW_CUR_MODE; + } + +@@ -1390,9 +1337,8 @@ + + static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info) + { +- unsigned long memsize = 0, tempBypass, i, temp1, temp2; ++ unsigned long memsize, tempBypass, i, temp1, temp2; + u16 subvendor, subdevice; +- pm3fb_timing_result ptr; + + DTRACE; + +@@ -1438,7 +1384,7 @@ + + /* card-specific setup is done, we preserve the final + memory timing for future reference */ +- if ((ptr = pm3fb_preserve_memory_timings(l_fb_info)) == pm3fb_timing_problem) { /* memory timings were wrong ! oops.... */ ++ if (pm3fb_preserve_memory_timings(l_fb_info)) { /* memory timings were wrong ! oops.... */ + return(0); + } + +@@ -1464,12 +1410,12 @@ + temp1 = readl((l_fb_info->v_fb + (i * 1048576))); + #endif + #endif /* KERNEL_2_2 */ +-#if (defined KERNEL_2_4) || (defined KERNEL_2_5) ++#ifdef KERNEL_2_4 + fb_writel(i * 0x00345678, + (l_fb_info->v_fb + (i * 1048576))); + mb(); + temp1 = fb_readl((l_fb_info->v_fb + (i * 1048576))); +-#endif /* KERNEL_2_4 or KERNEL_2_5 */ ++#endif /* KERNEL_2_4 */ + /* Let's check for wrapover, write will fail at 16MB boundary */ + if (temp1 == (i * 0x00345678)) + memsize = i; +@@ -1512,7 +1458,7 @@ + ((i - 32) * 1048576))); + #endif + #endif /* KERNEL_2_2 */ +-#if (defined KERNEL_2_4) || (defined KERNEL_2_5) ++#ifdef KERNEL_2_4 + fb_writel(i * 0x00345678, + (l_fb_info->v_fb + (i * 1048576))); + mb(); +@@ -1521,7 +1467,7 @@ + temp2 = + fb_readl((l_fb_info->v_fb + + ((i - 32) * 1048576))); +-#endif /* KERNEL_2_4 or KERNEL_2_5 */ ++#endif /* KERNEL_2_4 */ + if ((temp1 == (i * 0x00345678)) && (temp2 == 0)) /* different value, different RAM... */ + memsize = i; + else +@@ -1538,21 +1484,8 @@ + + DPRINTK(2, "Returning 0x%08lx bytes\n", memsize); + +- if (forcesize[l_fb_info->board_num] && ((forcesize[l_fb_info->board_num] * 1048576) != memsize)) +- { +- printk(KERN_WARNING "pm3fb: mismatch between probed (%ld MB) and specified (%hd MB) memory size, using SPECIFIED !\n", memsize, forcesize[l_fb_info->board_num]); +- memsize = 1048576 * forcesize[l_fb_info->board_num]; +- } +- + l_fb_info->fb_size = memsize; +- +- if (ptr == pm3fb_timing_retry) +- { +- printk(KERN_WARNING "pm3fb: retrying memory timings check"); +- if (pm3fb_try_memory_timings(l_fb_info) == pm3fb_timing_problem) +- return(0); +- } +- ++ + return (memsize); + } + +@@ -1571,7 +1504,7 @@ + writel(cc, (l_fb_info->v_fb + (i * sizeof(u32)))); + #endif + #endif +-#if (defined KERNEL_2_4) || (defined KERNEL_2_5) ++#ifdef KERNEL_2_4 + fb_writel(cc, (l_fb_info->v_fb + (i * sizeof(u32)))); + #endif + } +@@ -1600,7 +1533,7 @@ + disp[l_fb_info->board_num].scrollmode = 0; /* SCROLL_YNOMOVE; *//* 0 means "let fbcon choose" */ + l_fb_info->gen.parsize = sizeof(struct pm3fb_par); + l_fb_info->gen.info.changevar = NULL; +- l_fb_info->gen.info.node = B_FREE; ++ l_fb_info->gen.info.node = -1; + l_fb_info->gen.info.fbops = &pm3fb_ops; + l_fb_info->gen.info.disp = &(disp[l_fb_info->board_num]); + if (fontn[l_fb_info->board_num][0]) +@@ -1765,7 +1698,6 @@ + } + + PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xffffffff); +- PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xffffffff); + PM3_SLOW_WRITE_REG(PM3FBWriteMode, + PM3FBWriteMode_WriteEnable | + PM3FBWriteMode_OpaqueSpan | +@@ -1786,7 +1718,9 @@ + PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 4095); + else + PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, sofb); +- ++ ++ PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xffffffff); ++ + switch (l_fb_info->current_par->depth) { + case 8: + PM3_SLOW_WRITE_REG(PM3DitherMode, +@@ -1842,10 +1776,7 @@ + height = height * fontheight(p); + c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)]; + +- /* block fills in 32bpp are hard, but in low res (width <= 1600 :-) +- we can use 16bpp operations, but not if NoWriteMask is on (SDRAM) */ +- if ((l_fb_info->current_par->width > 1600) || +- (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)) { ++ if (l_fb_info->current_par->width > 1600) { + PM3_WAIT(4); + + PM3_WRITE_REG(PM3Config2D, +@@ -1867,7 +1798,7 @@ + PM3Render2D_SpanOperation | + (PM3Render2D_Width(width)) | + (PM3Render2D_Height(height))); +- } else { ++ } else { /* block fills in 32bpp are hard, but in low res (width <= 1600 :-) we can use 16bpp operations */ + PM3_WAIT(8); + + PM3_WRITE_REG(PM3FBBlockColor, c); +@@ -1992,10 +1923,7 @@ + + PM3_WAIT(4); + +- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) +- PM3_WRITE_REG(PM3ForegroundColor, c); +- else +- PM3_WRITE_REG(PM3FBBlockColor, c); ++ PM3_WRITE_REG(PM3FBBlockColor, c); + + PM3_WRITE_REG(PM3Config2D, + PM3Config2D_UseConstantSource | +@@ -2006,23 +1934,14 @@ + PM3_WRITE_REG(PM3RectanglePosition, + (PM3RectanglePosition_XOffset(sx)) | + (PM3RectanglePosition_YOffset(sy))); +- +- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) +- PM3_WRITE_REG(PM3Render2D, +- PM3Render2D_XPositive | +- PM3Render2D_YPositive | +- PM3Render2D_Operation_Normal | +- PM3Render2D_SpanOperation | +- (PM3Render2D_Width(width)) | +- (PM3Render2D_Height(height))); +- else +- PM3_WRITE_REG(PM3Render2D, +- PM3Render2D_XPositive | +- PM3Render2D_YPositive | +- PM3Render2D_Operation_Normal | +- (PM3Render2D_Width(width)) | +- (PM3Render2D_Height(height))); +- ++ ++ PM3_WRITE_REG(PM3Render2D, ++ PM3Render2D_XPositive | ++ PM3Render2D_YPositive | ++ PM3Render2D_Operation_Normal | ++ (PM3Render2D_Width(width)) | ++ (PM3Render2D_Height(height))); ++ + pm3fb_wait_pm3(l_fb_info); + } + +@@ -2048,69 +1967,45 @@ + PM3Config2D_ForegroundROPEnable | + (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ + PM3Config2D_FBWriteEnable); +- +- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) +- PM3_WRITE_REG(PM3ForegroundColor, c); +- else +- PM3_WRITE_REG(PM3FBBlockColor, c); +- ++ ++ PM3_WRITE_REG(PM3FBBlockColor, c); ++ + PM3_WRITE_REG(PM3RectanglePosition, + (PM3RectanglePosition_XOffset + (p->var.xoffset + + sx)) | (PM3RectanglePosition_YOffset(p-> + var. + yoffset))); +- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) +- PM3_WRITE_REG(PM3Render2D, +- PM3Render2D_XPositive | +- PM3Render2D_YPositive | +- PM3Render2D_Operation_Normal | +- PM3Render2D_SpanOperation | +- (PM3Render2D_Width(p->var.xres - sx)) | +- (PM3Render2D_Height(p->var.yres))); +- else +- PM3_WRITE_REG(PM3Render2D, +- PM3Render2D_XPositive | +- PM3Render2D_YPositive | +- PM3Render2D_Operation_Normal | +- (PM3Render2D_Width(p->var.xres - sx)) | +- (PM3Render2D_Height(p->var.yres))); ++ ++ PM3_WRITE_REG(PM3Render2D, ++ PM3Render2D_XPositive | ++ PM3Render2D_YPositive | ++ PM3Render2D_Operation_Normal | ++ (PM3Render2D_Width(p->var.xres - sx)) | ++ (PM3Render2D_Height(p->var.yres))); + } +- ++ + /* bottom margin left -> right */ + PM3_WAIT(4); +- ++ + PM3_WRITE_REG(PM3Config2D, +- PM3Config2D_UseConstantSource | +- PM3Config2D_ForegroundROPEnable | +- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ +- PM3Config2D_FBWriteEnable); +- +- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) +- PM3_WRITE_REG(PM3ForegroundColor, c); +- else +- PM3_WRITE_REG(PM3FBBlockColor, c); +- +- ++ PM3Config2D_UseConstantSource | ++ PM3Config2D_ForegroundROPEnable | ++ (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ ++ PM3Config2D_FBWriteEnable); ++ ++ PM3_WRITE_REG(PM3FBBlockColor, c); ++ + PM3_WRITE_REG(PM3RectanglePosition, + (PM3RectanglePosition_XOffset(p->var.xoffset)) | + (PM3RectanglePosition_YOffset(p->var.yoffset + sy))); +- +- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) +- PM3_WRITE_REG(PM3Render2D, +- PM3Render2D_XPositive | +- PM3Render2D_YPositive | +- PM3Render2D_Operation_Normal | +- PM3Render2D_SpanOperation | +- (PM3Render2D_Width(p->var.xres)) | +- (PM3Render2D_Height(p->var.yres - sy))); +- else +- PM3_WRITE_REG(PM3Render2D, +- PM3Render2D_XPositive | +- PM3Render2D_YPositive | +- PM3Render2D_Operation_Normal | +- (PM3Render2D_Width(p->var.xres)) | +- (PM3Render2D_Height(p->var.yres - sy))); ++ ++ PM3_WRITE_REG(PM3Render2D, ++ PM3Render2D_XPositive | ++ PM3Render2D_YPositive | ++ PM3Render2D_Operation_Normal | ++ (PM3Render2D_Width(p->var.xres)) | ++ (PM3Render2D_Height(p->var.yres - sy))); + + pm3fb_wait_pm3(l_fb_info); + } +@@ -2288,7 +2183,7 @@ + int c, int yy, int xx) + { + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; +- u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0; ++ u8 *cdat, asx = 0, asy = 0, o_x, o_y; + u32 fgx, bgx, ldat; + int sx, sy, i; + +@@ -2398,7 +2293,7 @@ + int xx) + { + struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; +- u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0; ++ u8 *cdat, asx = 0, asy = 0, o_x, o_y; + u32 fgx, bgx, ldat; + int sx, sy, i, j; + u16 sc; +@@ -2516,12 +2411,7 @@ + yy = yy * fontheight(p); + + if (l_fb_info->current_par->depth == 8) +- { +- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) +- PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0x0F0F0F0F); +- else +- PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0x0F0F0F0F); +- } ++ PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0x0F0F0F0F); + + PM3_WAIT(3); + +@@ -2547,12 +2437,7 @@ + pm3fb_wait_pm3(l_fb_info); + + if (l_fb_info->current_par->depth == 8) +- { +- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) +- PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xFFFFFFFF); +- else +- PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xFFFFFFFF); +- } ++ PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xFFFFFFFF); + } + + #endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */ +@@ -2640,25 +2525,12 @@ + unsigned long bd = simple_strtoul(bds, (char **) NULL, 10); + + if (!(depth_supported(bd))) { +- printk(KERN_WARNING "pm3fb: ignoring invalid depth %s for board #%ld\n", +- bds, board_num); ++ DPRINTK(1, "Invalid depth: %s\n", bds); + return; + } + depth[board_num] = bd; + } + +-static void pm3fb_forcesize_setup(char *bds, unsigned long board_num) +-{ +- unsigned long bd = simple_strtoul(bds, (char **) NULL, 10); +- +- if (bd > 64) { +- printk(KERN_WARNING "pm3fb: ignoring invalid memory size %s for board #%ld\n", +- bds, board_num); +- return; +- } +- forcesize[board_num] = bd; +-} +- + static char *pm3fb_boardnum_setup(char *options, unsigned long *bn) + { + char *next; +@@ -2752,12 +2624,6 @@ + pm3fb_bootdepth_setup(options, bn); + } else if (!strncmp(options, "printtimings", 12)) { + printtimings = 1; +- } else if (!strncmp(options, "flatpanel:", 10)) { +- options = pm3fb_boardnum_setup(options + 10, &bn); +- flatpanel[bn] = 1; +- } else if (!strncmp(options, "forcesize:", 10)) { +- options = pm3fb_boardnum_setup(options + 10, &bn); +- pm3fb_forcesize_setup(options, bn); + } + options = next; + } +@@ -3495,7 +3361,7 @@ + pci_resource_start(l_fb_info->dev, 1); + l_fb_info->v_fb = (unsigned char *) -1; + +-#if (defined KERNEL_2_4) || (defined KERNEL_2_5) /* full resource management, new in linux-2.4.x */ ++#ifdef KERNEL_2_4 /* full resource management, new in linux-2.4.x */ + if (!request_mem_region + ((unsigned long)l_fb_info->p_fb, 64 * 1024 * 1024, /* request full aperture size */ + "pm3fb")) { +@@ -3512,10 +3378,8 @@ + l_fb_info->board_num); + continue; + } +-#endif /* KERNEL_2_4 or KERNEL_2_5 */ +- if (forcesize[l_fb_info->board_num]) +- l_fb_info->fb_size = forcesize[l_fb_info->board_num]; +- ++#endif /* KERNEL_2_4 */ ++ + l_fb_info->fb_size = + pm3fb_size_memory(l_fb_info); + +@@ -3611,7 +3475,7 @@ + /* ***** standard FB API init functions ***** */ + /* ****************************************** */ + +-#if (defined KERNEL_2_4) || (defined KERNEL_2_5) ++#ifdef KERNEL_2_4 + int __init pm3fb_setup(char *options) + #endif + #ifdef KERNEL_2_2 +@@ -3627,12 +3491,12 @@ + PM3_OPTIONS_SIZE) ? PM3_OPTIONS_SIZE : (opsi + 1)); + g_options[PM3_OPTIONS_SIZE - 1] = 0; + +-#if (defined KERNEL_2_4) || (defined KERNEL_2_5) ++#ifdef KERNEL_2_4 + return (0); + #endif + } + +-#if (defined KERNEL_2_4) || (defined KERNEL_2_5) ++#ifdef KERNEL_2_4 + int __init pm3fb_init(void) + #endif + #ifdef KERNEL_2_2 +@@ -3641,7 +3505,7 @@ + { + DTRACE; + +- DPRINTK(2, "This is pm3fb.c, CVS version: $Header$"); ++ DPRINTK(2, "This is pm3fb.c, CVS version: $Header$"); + + pm3fb_real_setup(g_options); + +@@ -3650,7 +3514,7 @@ + if (!fb_info[0].dev) { /* not even one board ??? */ + DPRINTK(1, "No PCI Permedia3 board detected\n"); + } +-#if (defined KERNEL_2_4) || (defined KERNEL_2_5) ++#ifdef KERNEL_2_4 + return (0); + #endif + } +@@ -3753,9 +3617,7 @@ + MODULE_PARM(depth,PM3_MAX_BOARD_MODULE_ARRAY_SHORT); + MODULE_PARM_DESC(depth,"boot-time depth"); + MODULE_PARM(printtimings, "h"); +-MODULE_PARM_DESC(printtimings, "print the memory timings of the card(s)"); +-MODULE_PARM(forcesize, PM3_MAX_BOARD_MODULE_ARRAY_SHORT); +-MODULE_PARM_DESC(forcesize, "force specified memory size"); ++MODULE_PARM_DESC(printtimings, "print the memory timngs of the card(s)"); + /* + MODULE_SUPPORTED_DEVICE("Permedia3 PCI boards") + MODULE_GENERIC_TABLE(gtype,name) +@@ -3829,14 +3691,14 @@ + if (l_fb_info->vIOBase != + (unsigned char *) -1) { + pm3fb_unmapIO(l_fb_info); +-#if (defined KERNEL_2_4) || (defined KERNEL_2_5) ++#ifdef KERNEL_2_4 + release_mem_region(l_fb_info->p_fb, + l_fb_info-> + fb_size); + release_mem_region(l_fb_info-> + pIOBase, + PM3_REGS_SIZE); +-#endif /* KERNEL_2_4 or KERNEL_2_5 */ ++#endif /* KERNEL_2_4 */ + } + unregister_framebuffer(&l_fb_info->gen. + info); +--- linux-2.4.25/drivers/video/pm3fb.h~2.4.25-vrs2.patch 2002-11-29 00:53:15.000000000 +0100 ++++ linux-2.4.25/drivers/video/pm3fb.h 2004-03-31 17:15:09.000000000 +0200 +@@ -8,7 +8,7 @@ + * License. See the file COPYING in the main directory of this archive for + * more details. + * +- * $Header$ ++ * $Header$ + * + */ + +@@ -92,7 +92,6 @@ + #define PM3MemBypassWriteMask 0x1008 + #define PM3MemScratch 0x1010 + #define PM3LocalMemCaps 0x1018 +- #define PM3LocalMemCaps_NoWriteMask (1 << 28) + #define PM3LocalMemTimings 0x1020 + #define PM3LocalMemControl 0x1028 + #define PM3LocalMemRefresh 0x1030 +@@ -1121,10 +1120,6 @@ + + /* kernel -specific definitions */ + /* what kernel is this ? */ +-#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))) +-#define KERNEL_2_5 +-#endif +- + #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))) + #define KERNEL_2_4 + #endif +@@ -1138,8 +1133,8 @@ + #endif + #endif + +-#if (!defined(KERNEL_2_2)) && (!defined(KERNEL_2_4)) && (!defined(KERNEL_2_5)) +-#error "Only kernel 2.2.x, kernel 2.4.y and kernel 2.5.z might work" ++#if (!defined(KERNEL_2_2)) && (!defined(KERNEL_2_4)) ++#error "Only kernel 2.2.x and kernel 2.4.y might work" + #endif + + /* not sure if/why it's needed. doesn't work without on my PowerMac... */ +@@ -1147,11 +1142,6 @@ + #define MUST_BYTESWAP + #endif + +-/* for compatibility between 2.5, 2.4 and 2.2 */ +-#ifndef B_FREE +-#define B_FREE -1 +-#endif +- + /* permedia3 -specific definitions */ + #define PM3_SCALE_TO_CLOCK(pr, fe, po) ((2 * PM3_REF_CLOCK * fe) / (pr * (1 << (po)))) + #define PICOS2KHZ(a) (1000000000UL/(a)) +@@ -1219,10 +1209,10 @@ + #define PM3_READ_REG(r) readl((l_fb_info->vIOBase + r)) + #endif /* MUST_BYTESWAP */ + #endif /* KERNEL_2_2 */ +-#if (defined KERNEL_2_4) || (defined KERNEL_2_5) /* native-endian access */ ++#ifdef KERNEL_2_4 /* native-endian access */ + #define PM3_WRITE_REG(r, v) fb_writel(v, (l_fb_info->vIOBase + r)) + #define PM3_READ_REG(r) fb_readl((l_fb_info->vIOBase + r)) +-#endif /* KERNEL_2_4 or KERNEL_2_5 */ ++#endif /* KERNEL_2_4 */ + + + #define depth2bpp(d) ((d + 7L) & ~7L) +--- linux-2.4.25/drivers/video/sa1100fb.c~2.4.25-vrs2.patch 2001-11-14 23:52:20.000000000 +0100 ++++ linux-2.4.25/drivers/video/sa1100fb.c 2004-03-31 17:15:09.000000000 +0200 +@@ -23,11 +23,11 @@ + * Thank you. + * + * Known problems: +- * - With the Neponset plugged into an Assabet, LCD powerdown +- * doesn't work (LCD stays powered up). Therefore we shouldn't +- * blank the screen. +- * - We don't limit the CPU clock rate nor the mode selection +- * according to the available SDRAM bandwidth. ++ * - With the Neponset plugged into an Assabet, LCD powerdown ++ * doesn't work (LCD stays powered up). Therefore we shouldn't ++ * blank the screen. ++ * - We don't limit the CPU clock rate nor the mode selection ++ * according to the available SDRAM bandwidth. + * + * Other notes: + * - Linear grayscale palettes and the kernel. +@@ -41,6 +41,17 @@ + * David Neuer. It's around 8 lines of C code, plus another 4 to + * detect if we are using grayscale. + * ++ * - The following must never be specified in a panel definition: ++ * LCCR0_LtlEnd, LCCR3_PixClkDiv, LCCR3_VrtSnchL, LCCR3_HorSnchL ++ * ++ * - The following should be specified: ++ * either LCCR0_Color or LCCR0_Mono ++ * either LCCR0_Sngl or LCCR0_Dual ++ * either LCCR0_Act or LCCR0_Pas ++ * either LCCR3_OutEnH or LCCD3_OutEnL ++ * either LCCR3_PixRsEdg or LCCR3_PixFlEdg ++ * either LCCR3_ACBsDiv or LCCR3_ACBsCntOff ++ * + * Code Status: + * 1999/04/01: + * - Driver appears to be working for Brutus 320x200x8bpp mode. Other +@@ -147,6 +158,10 @@ + * + * 2001/10/12: <rmk@arm.linux.org.uk> + * - Add patch 681/1 and clean up stork definitions. ++ * ++ * 2002/02/21: <abraham@2d3d.co.za> ++ * - Added support for ICP LCD-Kit01 on Frodo. ++ * - Added support for backlight via CPLDs on Frodo. + */ + + #include <linux/config.h> +@@ -169,6 +184,7 @@ + #include <asm/mach-types.h> + #include <asm/uaccess.h> + #include <asm/arch/assabet.h> ++#include <asm/arch/shannon.h> + + #include <video/fbcon.h> + #include <video/fbcon-mfb.h> +@@ -177,11 +193,6 @@ + #include <video/fbcon-cfb16.h> + + /* +- * enable this if your panel appears to have broken +- */ +-#undef CHECK_COMPAT +- +-/* + * debugging? + */ + #define DEBUG 0 +@@ -197,243 +208,6 @@ + void (*sa1100fb_blank_helper)(int blank); + EXPORT_SYMBOL(sa1100fb_blank_helper); + +- +-#ifdef CHECK_COMPAT +-static void +-sa1100fb_check_shadow(struct sa1100fb_lcd_reg *new_regs, +- struct fb_var_screeninfo *var, u_int pcd) +-{ +- struct sa1100fb_lcd_reg shadow; +- int different = 0; +- +- /* +- * These machines are good machines! +- */ +- if (machine_is_assabet() || machine_is_h3600()) +- return; +- +- /* +- * The following ones are bad, bad, bad. +- * Please make yours good! +- */ +- if (machine_is_pangolin()) { +- DPRINTK("Configuring Pangolin LCD\n"); +- shadow.lccr0 = +- LCCR0_LEN + LCCR0_Color + LCCR0_LDM + +- LCCR0_BAM + LCCR0_ERM + LCCR0_Act + +- LCCR0_LtlEnd + LCCR0_DMADel(0); +- shadow.lccr1 = +- LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(64) + +- LCCR1_BegLnDel(160) + LCCR1_EndLnDel(24); +- shadow.lccr2 = +- LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(7) + +- LCCR2_BegFrmDel(7) + LCCR2_EndFrmDel(1); +- shadow.lccr3 = +- LCCR3_PixClkDiv(pcd) + LCCR3_HorSnchH + +- LCCR3_VrtSnchH + LCCR3_PixFlEdg + LCCR3_OutEnH; +- +- DPRINTK("pcd = %x, PixCldDiv(pcd)=%x\n", +- pcd, LCCR3_PixClkDiv(pcd)); +- } +- if (machine_is_freebird()) { +- DPRINTK("Configuring Freebird LCD\n"); +-#if 1 +- shadow.lccr0 = 0x00000038; +- shadow.lccr1 = 0x010108e0; +- shadow.lccr2 = 0x0000053f; +- shadow.lccr3 = 0x00000c20; +-#else +- shadow.lccr0 = +- LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + +- LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + LCCR0_Pas + +- LCCR0_LtlEnd + LCCR0_DMADel(0); +- /* Check ,Chester */ +- shadow.lccr1 = +- LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(5) + +- LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9); +- /* Check ,Chester */ +- shadow.lccr2 = +- LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) + +- LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0); +- /* Check ,Chester */ +- shadow.lccr3 = +- LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH + +- LCCR3_HorSnchH + LCCR3_ACBsCntOff + +- LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(pcd); +-#endif +- } +- if (machine_is_brutus()) { +- DPRINTK("Configuring Brutus LCD\n"); +- shadow.lccr0 = +- LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Pas + +- LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + +- LCCR0_DMADel(0); +- shadow.lccr1 = +- LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(3) + +- LCCR1_BegLnDel(41) + LCCR1_EndLnDel(101); +- shadow.lccr2 = +- LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) + +- LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0); +- shadow.lccr3 = +- LCCR3_OutEnH + LCCR3_PixRsEdg + LCCR3_VrtSnchH + +- LCCR3_HorSnchH + LCCR3_ACBsCntOff + +- LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(44); +- } +- if (machine_is_huw_webpanel()) { +- DPRINTK("Configuring HuW LCD\n"); +- shadow.lccr0 = LCCR0_LEN + LCCR0_Dual + LCCR0_LDM; +- shadow.lccr1 = LCCR1_DisWdth(var->xres) + +- LCCR1_HorSnchWdth(3) + +- LCCR1_BegLnDel(41) + LCCR1_EndLnDel(101); +- shadow.lccr2 = 239 + LCCR2_VrtSnchWdth(1); +- shadow.lccr3 = 8 + LCCR3_OutEnH + +- LCCR3_PixRsEdg + LCCR3_VrtSnchH + +- LCCR3_HorSnchH + LCCR3_ACBsCntOff + LCCR3_ACBsDiv(2); +- } +- if (machine_is_lart()) { +- DPRINTK("Configuring LART LCD\n"); +-#if defined LART_GREY_LCD +- shadow.lccr0 = +- LCCR0_LEN + LCCR0_Mono + LCCR0_Sngl + LCCR0_Pas + +- LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + +- LCCR0_DMADel(0); +- shadow.lccr1 = +- LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(1) + +- LCCR1_BegLnDel(4) + LCCR1_EndLnDel(2); +- shadow.lccr2 = +- LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) + +- LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0); +- shadow.lccr3 = +- LCCR3_PixClkDiv(34) + LCCR3_ACBsDiv(512) + +- LCCR3_ACBsCntOff + LCCR3_HorSnchH + LCCR3_VrtSnchH; +-#endif +-#if defined LART_COLOR_LCD +- shadow.lccr0 = +- LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act + +- LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + +- LCCR0_DMADel(0); +- shadow.lccr1 = +- LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(2) + +- LCCR1_BegLnDel(69) + LCCR1_EndLnDel(8); +- shadow.lccr2 = +- LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(3) + +- LCCR2_BegFrmDel(14) + LCCR2_EndFrmDel(4); +- shadow.lccr3 = +- LCCR3_PixClkDiv(34) + LCCR3_ACBsDiv(512) + +- LCCR3_ACBsCntOff + LCCR3_HorSnchL + LCCR3_VrtSnchL + +- LCCR3_PixFlEdg; +-#endif +-#if defined LART_VIDEO_OUT +- shadow.lccr0 = +- LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act + +- LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + +- LCCR0_DMADel(0); +- shadow.lccr1 = +- LCCR1_DisWdth(640) + LCCR1_HorSnchWdth(95) + +- LCCR1_BegLnDel(40) + LCCR1_EndLnDel(24); +- shadow.lccr2 = +- LCCR2_DisHght(480) + LCCR2_VrtSnchWdth(2) + +- LCCR2_BegFrmDel(32) + LCCR2_EndFrmDel(11); +- shadow.lccr3 = +- LCCR3_PixClkDiv(8) + LCCR3_ACBsDiv(512) + +- LCCR3_ACBsCntOff + LCCR3_HorSnchH + LCCR3_VrtSnchH + +- LCCR3_PixFlEdg + LCCR3_OutEnL; +-#endif +- } +- if (machine_is_graphicsclient()) { +- DPRINTK("Configuring GraphicsClient LCD\n"); +- shadow.lccr0 = +- LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act; +- shadow.lccr1 = +- LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(9) + +- LCCR1_EndLnDel(54) + LCCR1_BegLnDel(54); +- shadow.lccr2 = +- LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(9) + +- LCCR2_EndFrmDel(32) + LCCR2_BegFrmDel(24); +- shadow.lccr3 = +- LCCR3_PixClkDiv(10) + LCCR3_ACBsDiv(2) + +- LCCR3_ACBsCntOff + LCCR3_HorSnchL + LCCR3_VrtSnchL; +- } +- if (machine_is_omnimeter()) { +- DPRINTK("Configuring OMNI LCD\n"); +- shadow.lccr0 = LCCR0_LEN | LCCR0_CMS | LCCR0_DPD; +- shadow.lccr1 = +- LCCR1_BegLnDel(10) + LCCR1_EndLnDel(10) + +- LCCR1_HorSnchWdth(1) + LCCR1_DisWdth(var->xres); +- shadow.lccr2 = LCCR2_DisHght(var->yres); +- shadow.lccr3 = +- LCCR3_ACBsDiv(0xFF) + LCCR3_PixClkDiv(44); +-//jca (GetPCD(25) << LCD3_V_PCD); +- } +- if (machine_is_xp860()) { +- DPRINTK("Configuring XP860 LCD\n"); +- shadow.lccr0 = +- LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act + +- LCCR0_LtlEnd + LCCR0_LDM + LCCR0_ERM + LCCR0_DMADel(0); +- shadow.lccr1 = +- LCCR1_DisWdth(var->xres) + +- LCCR1_HorSnchWdth(var->hsync_len) + +- LCCR1_BegLnDel(var->left_margin) + +- LCCR1_EndLnDel(var->right_margin); +- shadow.lccr2 = +- LCCR2_DisHght(var->yres) + +- LCCR2_VrtSnchWdth(var->vsync_len) + +- LCCR2_BegFrmDel(var->upper_margin) + +- LCCR2_EndFrmDel(var->lower_margin); +- shadow.lccr3 = +- LCCR3_PixClkDiv(6) + LCCR3_HorSnchL + LCCR3_VrtSnchL; +- } +- +- /* +- * Ok, since we're calculating these values, we want to know +- * if the calculation is correct. If you see any of these +- * messages _PLEASE_ report the incident to me for diagnosis, +- * including details about what was happening when the +- * messages appeared. --rmk, 30 March 2001 +- */ +- if (shadow.lccr0 != new_regs->lccr0) { +- printk(KERN_ERR "LCCR1 mismatch: 0x%08x != 0x%08x\n", +- shadow.lccr1, new_regs->lccr1); +- different = 1; +- } +- if (shadow.lccr1 != new_regs->lccr1) { +- printk(KERN_ERR "LCCR1 mismatch: 0x%08x != 0x%08x\n", +- shadow.lccr1, new_regs->lccr1); +- different = 1; +- } +- if (shadow.lccr2 != new_regs->lccr2) { +- printk(KERN_ERR "LCCR2 mismatch: 0x%08x != 0x%08x\n", +- shadow.lccr2, new_regs->lccr2); +- different = 1; +- } +- if (shadow.lccr3 != new_regs->lccr3) { +- printk(KERN_ERR "LCCR3 mismatch: 0x%08x != 0x%08x\n", +- shadow.lccr3, new_regs->lccr3); +- different = 1; +- } +- if (different) { +- printk(KERN_ERR "var: xres=%d hslen=%d lm=%d rm=%d\n", +- var->xres, var->hsync_len, +- var->left_margin, var->right_margin); +- printk(KERN_ERR "var: yres=%d vslen=%d um=%d bm=%d\n", +- var->yres, var->vsync_len, +- var->upper_margin, var->lower_margin); +- +- printk(KERN_ERR "Please report this to Russell King " +- "<rmk@arm.linux.org.uk>\n"); +- } +- +- DPRINTK("olccr0 = 0x%08x\n", shadow.lccr0); +- DPRINTK("olccr1 = 0x%08x\n", shadow.lccr1); +- DPRINTK("olccr2 = 0x%08x\n", shadow.lccr2); +- DPRINTK("olccr3 = 0x%08x\n", shadow.lccr3); +-} +-#else +-#define sa1100fb_check_shadow(regs,var,pcd) +-#endif +- +- +- + /* + * IMHO this looks wrong. In 8BPP, length should be 8. + */ +@@ -488,42 +262,56 @@ + #endif + #endif + +-#ifdef CONFIG_SA1100_H3600 +-static struct sa1100fb_mach_info h3600_info __initdata = { +-#ifdef CONFIG_IPAQ_H3100 +- pixclock: 407766, bpp: 4, ++#ifdef CONFIG_SA1100_H3XXX ++static struct sa1100fb_mach_info h3800_info __initdata = { ++ pixclock: 174757, bpp: 16, + xres: 320, yres: 240, + +- hsync_len: 26, vsync_len: 41, +- left_margin: 4, upper_margin: 0, +- right_margin: 4, lower_margin: 0, ++ hsync_len: 3, vsync_len: 3, ++ left_margin: 12, upper_margin: 10, ++ right_margin: 17, lower_margin: 1, + +- sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, +- cmap_greyscale: 1, cmap_static: 1, +- cmap_inverse: 1, ++ sync: 0, cmap_static: 1, + +- lccr0: LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas, +- lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), +-#else +- pixclock: 174757, bpp: 16, ++ lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act, ++ lccr3: LCCR3_ACBsCntOff | LCCR3_PixFlEdg | LCCR3_OutEnH, ++}; ++ ++static struct sa1100fb_mach_info h3600_info __initdata = { ++ pixclock: 174757, bpp: 16, + xres: 320, yres: 240, + + hsync_len: 3, vsync_len: 3, + left_margin: 12, upper_margin: 10, + right_margin: 17, lower_margin: 1, + +- sync: 0, ++ sync: 0, cmap_static: 1, + + lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act, +- lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), +-#endif ++ lccr3: LCCR3_ACBsCntOff | LCCR3_OutEnH | LCCR3_PixFlEdg, + }; + + static struct sa1100fb_rgb h3600_rgb_16 = { + red: { offset: 12, length: 4, }, + green: { offset: 7, length: 4, }, + blue: { offset: 1, length: 4, }, +- transp: { offset: 0, length: 0, }, ++ transp: { offset: 0, length: 0, }, ++}; ++ ++static struct sa1100fb_mach_info h3100_info __initdata = { ++ pixclock: 406977, bpp: 4, ++ xres: 320, yres: 240, ++ ++ hsync_len: 26, vsync_len: 41, ++ left_margin: 4, upper_margin: 0, ++ right_margin: 4, lower_margin: 0, ++ ++ sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ cmap_greyscale: 1, ++ cmap_inverse: 1, ++ ++ lccr0: LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas, ++ lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), + }; + #endif + +@@ -618,6 +406,58 @@ + + #ifdef CONFIG_SA1100_GRAPHICSCLIENT + static struct sa1100fb_mach_info graphicsclient_info __initdata = { ++// for LQ64D343 ++ pixclock: 53500, bpp: 8, ++ xres: 640, yres: 480, ++ ++ hsync_len: 9, vsync_len: 9, ++ left_margin: 54, upper_margin: 24, ++ right_margin: 54, lower_margin: 32, ++ ++ sync: 0, ++ ++ lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act, ++ lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), ++}; ++#endif ++ ++#ifdef CONFIG_SA1100_GRAPHICSMASTER ++static struct sa1100fb_mach_info graphicsmaster_info __initdata = { ++// for LQ64D343 ++ pixclock: 53500, bpp: 8, ++ xres: 640, yres: 480, ++ ++ hsync_len: 9, vsync_len: 9, ++ left_margin: 54, upper_margin: 24, ++ right_margin: 54, lower_margin: 32, ++ ++ sync: 0, ++ ++ lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act, ++ lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), ++}; ++#endif ++ ++#ifdef CONFIG_SA1100_ADSBITSY ++static struct sa1100fb_mach_info adsbitsy_info __initdata = { ++// for LQ64D343 ++ pixclock: 53500, bpp: 8, ++ xres: 640, yres: 480, ++ ++ hsync_len: 9, vsync_len: 9, ++ left_margin: 54, upper_margin: 24, ++ right_margin: 54, lower_margin: 32, ++ ++ sync: 0, ++ ++ lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act, ++ lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), ++}; ++#endif ++ ++#ifdef CONFIG_SA1100_ADSBITSYPLUS ++static struct sa1100fb_mach_info adsbitsyplus_info __initdata = { ++// for LQ64D343 + pixclock: 53500, bpp: 8, + xres: 640, yres: 480, + +@@ -699,7 +539,6 @@ + lccr3: LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512), + }; + #endif +- + #ifdef LART_KIT01_LCD + static struct sa1100fb_mach_info lart_kit01_info __initdata = + { +@@ -707,7 +546,7 @@ + xres: 640, yres: 480, + + hsync_len: 64, vsync_len: 3, +- left_margin: 122, upper_margin: 45, ++ left_margin: 122, upper_margin: 45, + right_margin: 10, lower_margin: 10, + + sync: 0, +@@ -717,6 +556,40 @@ + }; + #endif + ++#ifdef CONFIG_SA1100_FRODO ++static struct sa1100fb_mach_info frodo_kit01_info __initdata = ++{ ++ /* best would be 41731 (25.8mhz), but we can only do 14.743mhz at 191.7mhz clock speed */ ++ pixclock: 73030, bpp: 16, ++ xres: 640, yres: 480, ++ ++ hsync_len: 32, vsync_len: 19, ++ left_margin: 120, upper_margin: 33, ++ right_margin: 17, lower_margin: 12, ++ ++ sync: 0, ++ ++ lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act, ++ lccr3: LCCR3_OutEnH | LCCR3_PixFlEdg ++}; ++#endif ++ ++#ifdef CONFIG_SA1100_SHANNON ++static struct sa1100fb_mach_info shannon_info __initdata = { ++ pixclock: 152500, bpp: 8, ++ xres: 640, yres: 480, ++ ++ hsync_len: 4, vsync_len: 3, ++ left_margin: 2, upper_margin: 0, ++ right_margin: 1, lower_margin: 0, ++ ++ sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ ++ lccr0: LCCR0_Color | LCCR0_Dual | LCCR0_Pas, ++ lccr3: LCCR3_ACBsDiv(512), ++}; ++#endif ++ + #ifdef CONFIG_SA1100_OMNIMETER + static struct sa1100fb_mach_info omnimeter_info __initdata = { + pixclock: 0, bpp: 4, +@@ -752,7 +625,24 @@ + sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + + lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act, +- lccr3: LCCR3_OutEnH | LCCR3_PixFlEdg, ++ lccr3: LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsCntOff, ++}; ++#endif ++ ++#ifdef CONFIG_SA1100_SIMPUTER ++static struct sa1100fb_mach_info simputer_info __initdata = { ++ pixclock: 70000, bpp: 4, ++ xres: 320, yres: 240, ++ ++ hsync_len: 9, vsync_len: 2, ++ left_margin: 9, upper_margin: 0, ++ right_margin: 2, lower_margin: 0, ++ ++ cmap_greyscale: 1, ++ sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT , ++ ++ lccr0: LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono, ++ lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(202), + }; + #endif + +@@ -828,7 +718,6 @@ + #endif + + +- + static struct sa1100fb_mach_info * __init + sa1100fb_get_machine_info(struct sa1100fb_info *fbi) + { +@@ -849,11 +738,17 @@ + #endif + } + #endif +-#ifdef CONFIG_SA1100_H3600 ++#ifdef CONFIG_SA1100_H3XXX + if (machine_is_h3600()) { + inf = &h3600_info; + fbi->rgb[RGB_16] = &h3600_rgb_16; + } ++ if (machine_is_h3100()) { ++ inf = &h3100_info; ++ } ++ if (machine_is_h3800()) { ++ inf = &h3800_info; ++ } + #endif + #ifdef CONFIG_SA1100_BRUTUS + if (machine_is_brutus()) { +@@ -876,6 +771,22 @@ + inf = &graphicsclient_info; + } + #endif ++#ifdef CONFIG_SA1100_GRAPHICSMASTER ++ if (machine_is_graphicsmaster()) { ++ inf = &graphicsmaster_info; ++ } ++#endif ++#ifdef CONFIG_SA1100_ADSBITSY ++ if (machine_is_adsbitsy()) { ++ inf = &adsbitsy_info; ++ } ++#endif ++#ifdef CONFIG_SA1100_ADSBITSYPLUS ++ if (machine_is_adsbitsyplus()) { ++ inf = &adsbitsyplus_info; ++ } ++ } ++#endif + #ifdef CONFIG_SA1100_HUW_WEBPANEL + if (machine_is_huw_webpanel()) { + inf = &huw_webpanel_info; +@@ -897,6 +808,21 @@ + #endif + } + #endif ++#ifdef CONFIG_SA1100_FRODO ++ if (machine_is_frodo()) { ++ inf = &frodo_kit01_info; ++ } ++#endif ++#ifdef CONFIG_SA1100_SHANNON ++ if (machine_is_shannon()) { ++ inf = &shannon_info; ++ } ++#endif ++#ifdef CONFIG_SA1100_SIMPUTER ++ if (machine_is_simputer()) { ++ inf = &simputer_info; ++ } ++#endif + #ifdef CONFIG_SA1100_OMNIMETER + if (machine_is_omnimeter()) { + inf = &omnimeter_info; +@@ -1556,7 +1482,8 @@ + unsigned int pcd; + + if (pixclock) { +- pcd = get_cclk_frequency() * pixclock; ++ pcd = cpufreq_get(0) / 100; ++ pcd *= pixclock; + pcd /= 10000000; + pcd += 1; /* make up for integer math truncations */ + } else { +@@ -1580,6 +1507,7 @@ + return pcd; + } + ++ + /* + * sa1100fb_activate_var(): + * Configures LCD Controller based on entries in var parameter. Settings are +@@ -1659,8 +1587,6 @@ + if (pcd) + new_regs.lccr3 |= LCCR3_PixClkDiv(pcd); + +- sa1100fb_check_shadow(&new_regs, var, pcd); +- + DPRINTK("nlccr0 = 0x%08x\n", new_regs.lccr0); + DPRINTK("nlccr1 = 0x%08x\n", new_regs.lccr1); + DPRINTK("nlccr2 = 0x%08x\n", new_regs.lccr2); +@@ -1733,6 +1659,10 @@ + if (machine_is_omnimeter()) + LEDBacklightOn(); + #endif ++#ifdef CONFIG_SA1100_FRODO ++ if (machine_is_frodo()) ++ frodo_cpld_set (FRODO_CPLD_GENERAL,FRODO_LCD_BACKLIGHT); ++#endif + } + + /* +@@ -1755,6 +1685,10 @@ + if (machine_is_omnimeter()) + LEDBacklightOff(); + #endif ++#ifdef CONFIG_SA1100_FRODO ++ if (machine_is_frodo()) ++ frodo_cpld_clear (FRODO_CPLD_GENERAL,FRODO_LCD_BACKLIGHT); ++#endif + } + + static void sa1100fb_power_up_lcd(struct sa1100fb_info *fbi) +@@ -1773,20 +1707,25 @@ + if (machine_is_omnimeter()) + LCDPowerOn(); + #endif +-#ifdef CONFIG_SA1100_H3600 +- if (machine_is_h3600()) { +- set_h3600_egpio(EGPIO_H3600_LCD_ON | +- EGPIO_H3600_LCD_PCI | +- EGPIO_H3600_LCD_5V_ON | +- EGPIO_H3600_LVDD_ON); +- } +-#endif ++ if (machine_is_h3xxx()) ++ set_h3600_egpio( IPAQ_EGPIO_LCD_ON ); /* Turn on power to the LCD */ + #ifdef CONFIG_SA1100_STORK + if (machine_is_stork()) { + storkSetLCDCPLD(0, 1); + storkSetLatchA(STORK_LCD_BACKLIGHT_INVERTER_ON); + } + #endif ++#ifdef CONFIG_SA1100_FRODO ++ if (machine_is_frodo()) ++ sa1100fb_backlight_on(fbi); ++#endif ++#ifdef CONFIG_SA1100_ADSBITSYPLUS ++ if (machine_is_adsbitsyplus()) { ++ ADS_CPLD_PCON &= ~ADS_PCON_PANEL_ON; ++ ADS_CPLD_SUPPC |= ADS_SUPPC_VEE_ON; ++ } ++#endif ++ + } + + static void sa1100fb_power_down_lcd(struct sa1100fb_info *fbi) +@@ -1802,20 +1741,24 @@ + if (machine_is_huw_webpanel()) + BCR_set(BCR_TFT_NPWR); + #endif +-#ifdef CONFIG_SA1100_H3600 +- if (machine_is_h3600()) { +- clr_h3600_egpio(EGPIO_H3600_LCD_ON | +- EGPIO_H3600_LCD_PCI | +- EGPIO_H3600_LCD_5V_ON | +- EGPIO_H3600_LVDD_ON); +- } +-#endif ++ if (machine_is_h3xxx()) ++ clr_h3600_egpio( IPAQ_EGPIO_LCD_ON ); + #ifdef CONFIG_SA1100_STORK + if (machine_is_stork()) { + storkSetLCDCPLD(0, 0); + storkClearLatchA(STORK_LCD_BACKLIGHT_INVERTER_ON); + } + #endif ++#ifdef CONFIG_SA1100_FRODO ++ if (machine_is_frodo()) ++ sa1100fb_backlight_off(fbi); ++#endif ++#ifdef CONFIG_SA1100_ADSBITSYPLUS ++ if (machine_is_adsbitsyplus()) { ++ ADS_CPLD_PCON |= ADS_PCON_PANEL_ON; ++ ADS_CPLD_SUPPC &= ~ADS_SUPPC_VEE_ON; ++ } ++#endif + } + + static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi) +@@ -1911,15 +1854,29 @@ + LCCR0 |= LCCR0_LEN; + + #ifdef CONFIG_SA1100_GRAPHICSCLIENT +-#error Where is GPIO24 set as an output? Can we fit this in somewhere else? + if (machine_is_graphicsclient()) { + // From ADS doc again...same as disable + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(20 * HZ / 1000); +- GPSR |= GPIO_GPIO24; ++ GPDR |= GPIO_GPIO24; ++ GPSR = GPIO_GPIO24; ++ } ++#endif ++#ifdef CONFIG_SA1100_GRAPHICSMASTER ++ if (machine_is_graphicsmaster()) { ++ // From ADS doc again...same as disable ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ schedule_timeout(20 * HZ / 1000); ++ GPDR |= GPIO_GPIO24; ++ GPSR = GPIO_GPIO24; + } + #endif + ++ if (machine_is_shannon()) { ++ GPDR |= SHANNON_GPIO_DISP_EN; ++ GPSR |= SHANNON_GPIO_DISP_EN; ++ } ++ + DPRINTK("DBAR1 = %p\n", DBAR1); + DPRINTK("DBAR2 = %p\n", DBAR2); + DPRINTK("LCCR0 = 0x%08x\n", LCCR0); +@@ -1935,7 +1892,6 @@ + DPRINTK("Disabling LCD controller\n"); + + #ifdef CONFIG_SA1100_GRAPHICSCLIENT +-#error Where is GPIO24 set as an output? Can we fit this in somewhere else? + if (machine_is_graphicsclient()) { + /* + * From ADS internal document: +@@ -1944,6 +1900,22 @@ + * + * We'll wait 20msec. + */ ++ GPDR |= GPIO_GPIO24; ++ GPCR |= GPIO_GPIO24; ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ schedule_timeout(20 * HZ / 1000); ++ } ++#endif ++#ifdef CONFIG_SA1100_GRAPHICSMASTER ++ if (machine_is_graphicsmaster()) { ++ /* ++ * From ADS internal document: ++ * GPIO24 should be LOW at least 10msec prior to disabling ++ * the LCD interface. ++ * ++ * We'll wait 20msec. ++ */ ++ GPDR |= GPIO_GPIO24; + GPCR |= GPIO_GPIO24; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(20 * HZ / 1000); +@@ -1958,12 +1930,15 @@ + } + #endif + ++ if (machine_is_shannon()) { ++ GPCR |= SHANNON_GPIO_DISP_EN; ++ } ++ + add_wait_queue(&fbi->ctrlr_wait, &wait); + set_current_state(TASK_UNINTERRUPTIBLE); + + LCSR = 0xffffffff; /* Clear LCD Status Register */ + LCCR0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */ +- enable_irq(IRQ_LCD); /* Enable LCD IRQ */ + LCCR0 &= ~LCCR0_LEN; /* Disable LCD Controller */ + + schedule_timeout(20 * HZ / 1000); +@@ -2006,12 +1981,13 @@ + * Disable controller for clock change. If the + * controller is already disabled, then do nothing. + */ +- if (old_state != C_DISABLE) { ++ if (old_state != C_DISABLE && old_state != C_DISABLE_PM) { + fbi->state = state; + sa1100fb_disable_controller(fbi); + } + break; + ++ case C_DISABLE_PM: + case C_DISABLE: + /* + * Disable controller +@@ -2050,6 +2026,16 @@ + } + break; + ++ case C_ENABLE_PM: ++ /* ++ * Re-enable the controller after PM. This is not ++ * perfect - think about the case where we were doing ++ * a clock change, and we suspended half-way through. ++ */ ++ if (old_state != C_DISABLE_PM) ++ break; ++ /* fall through */ ++ + case C_ENABLE: + /* + * Power up the LCD screen, enable controller, and +@@ -2162,10 +2148,10 @@ + + if (state == 0) { + /* Enter D0. */ +- set_ctrlr_state(fbi, C_ENABLE); ++ set_ctrlr_state(fbi, C_ENABLE_PM); + } else { + /* Enter D1-D3. Disable the LCD controller. */ +- set_ctrlr_state(fbi, C_DISABLE); ++ set_ctrlr_state(fbi, C_DISABLE_PM); + } + } + DPRINTK("done\n"); +@@ -2304,7 +2290,7 @@ + goto failed; + + ret = request_irq(IRQ_LCD, sa1100fb_handle_irq, SA_INTERRUPT, +- fbi->fb.fix.id, fbi); ++ "LCD", fbi); + if (ret) { + printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret); + goto failed; +--- linux-2.4.25/drivers/video/sa1100fb.h~2.4.25-vrs2.patch 2001-10-25 22:53:52.000000000 +0200 ++++ linux-2.4.25/drivers/video/sa1100fb.h 2004-03-31 17:15:09.000000000 +0200 +@@ -127,6 +127,8 @@ + #define C_DISABLE_CLKCHANGE (2) + #define C_ENABLE_CLKCHANGE (3) + #define C_REENABLE (4) ++#define C_DISABLE_PM (5) ++#define C_ENABLE_PM (6) + + #define SA1100_NAME "SA1100" + +--- linux-2.4.25/fs/adfs/dir.c~2.4.25-vrs2.patch 2000-09-19 00:14:06.000000000 +0200 ++++ linux-2.4.25/fs/adfs/dir.c 2004-03-31 17:15:09.000000000 +0200 +@@ -23,7 +23,7 @@ + /* + * For future. This should probably be per-directory. + */ +-static rwlock_t adfs_dir_lock; ++static rwlock_t adfs_dir_lock = RW_LOCK_UNLOCKED; + + static int + adfs_readdir(struct file *filp, void *dirent, filldir_t filldir) +--- linux-2.4.25/fs/adfs/map.c~2.4.25-vrs2.patch 2001-10-25 22:53:53.000000000 +0200 ++++ linux-2.4.25/fs/adfs/map.c 2004-03-31 17:15:09.000000000 +0200 +@@ -13,24 +13,27 @@ + #include <linux/adfs_fs.h> + #include <linux/spinlock.h> + ++#include <asm/unaligned.h> ++ + #include "adfs.h" + + /* + * For the future... + */ +-static rwlock_t adfs_map_lock; ++static rwlock_t adfs_map_lock = RW_LOCK_UNLOCKED; + ++/* ++ * This is fun. We need to load up to 19 bits from the map at an ++ * arbitary bit alignment. (We're limited to 19 bits by F+ version ++ * 2). ++ */ + #define GET_FRAG_ID(_map,_start,_idmask) \ + ({ \ +- unsigned long _v2, _frag; \ +- unsigned int _tmp; \ +- _tmp = _start >> 5; \ +- _frag = le32_to_cpu(_map[_tmp]); \ +- _v2 = le32_to_cpu(_map[_tmp + 1]); \ +- _tmp = start & 31; \ +- _frag = (_frag >> _tmp) | (_v2 << (32 - _tmp)); \ ++ unsigned char *_m = _map + (_start >> 3); \ ++ u32 _frag = get_unaligned((u32 *)_m); \ ++ _frag >>= (_start & 7); \ + _frag & _idmask; \ +- }) ++ }) + + /* + * return the map bit offset of the fragment frag_id in +@@ -44,14 +47,13 @@ + const unsigned int frag_id, unsigned int *offset) + { + const unsigned int mapsize = dm->dm_endbit; +- const unsigned int idmask = (1 << idlen) - 1; +- unsigned long *map = ((unsigned long *)dm->dm_bh->b_data) + 1; ++ const u32 idmask = (1 << idlen) - 1; ++ unsigned char *map = dm->dm_bh->b_data + 4; + unsigned int start = dm->dm_startbit; + unsigned int mapptr; ++ u32 frag; + + do { +- unsigned long frag; +- + frag = GET_FRAG_ID(map, start, idmask); + mapptr = start + idlen; + +@@ -59,15 +61,17 @@ + * find end of fragment + */ + { +- unsigned long v2; ++ u32 v, *_map = (u32 *)map; + +- while ((v2 = map[mapptr >> 5] >> (mapptr & 31)) == 0) { ++ v = le32_to_cpu(_map[mapptr >> 5]) >> (mapptr & 31); ++ while (v == 0) { + mapptr = (mapptr & ~31) + 32; + if (mapptr >= mapsize) + goto error; ++ v = le32_to_cpu(_map[mapptr >> 5]); + } + +- mapptr += 1 + ffz(~v2); ++ mapptr += 1 + ffz(~v); + } + + if (frag == frag_id) +@@ -75,8 +79,11 @@ + again: + start = mapptr; + } while (mapptr < mapsize); ++ return -1; + + error: ++ printk(KERN_ERR "adfs: oversized fragment 0x%x at 0x%x-0x%x\n", ++ frag, start, mapptr); + return -1; + + found: +@@ -102,10 +109,10 @@ + const unsigned int mapsize = dm->dm_endbit + 32; + const unsigned int idlen = asb->s_idlen; + const unsigned int frag_idlen = idlen <= 15 ? idlen : 15; +- const unsigned int idmask = (1 << frag_idlen) - 1; +- unsigned long *map = (unsigned long *)dm->dm_bh->b_data; ++ const u32 idmask = (1 << frag_idlen) - 1; ++ unsigned char *map = dm->dm_bh->b_data; + unsigned int start = 8, mapptr; +- unsigned long frag; ++ u32 frag; + unsigned long total = 0; + + /* +@@ -133,15 +140,17 @@ + * find end of fragment + */ + { +- unsigned long v2; ++ u32 v, *_map = (u32 *)map; + +- while ((v2 = map[mapptr >> 5] >> (mapptr & 31)) == 0) { ++ v = le32_to_cpu(_map[mapptr >> 5]) >> (mapptr & 31); ++ while (v == 0) { + mapptr = (mapptr & ~31) + 32; + if (mapptr >= mapsize) + goto error; ++ v = le32_to_cpu(_map[mapptr >> 5]); + } + +- mapptr += 1 + ffz(~v2); ++ mapptr += 1 + ffz(~v); + } + + total += mapptr - start; +--- linux-2.4.25/fs/adfs/super.c~2.4.25-vrs2.patch 2002-02-25 20:38:07.000000000 +0100 ++++ linux-2.4.25/fs/adfs/super.c 2004-03-31 17:15:09.000000000 +0200 +@@ -386,6 +386,14 @@ + sb->u.adfs_sb.s_size = adfs_discsize(dr, sb->s_blocksize_bits); + sb->u.adfs_sb.s_version = dr->format_version; + sb->u.adfs_sb.s_log2sharesize = dr->log2sharesize; ++ ++ printk(KERN_DEBUG "ADFS: idlen %d map bit size %d sector size %d\n", ++ dr->idlen, 1 << dr->log2bpmb, 1 << dr->log2secsize); ++ printk(KERN_DEBUG "ADFS: map size %d map2blk %d version %d share size %d\n", ++ sb->u.adfs_sb.s_map_size, ++ sb->u.adfs_sb.s_map2blk, ++ sb->u.adfs_sb.s_version, ++ 1 << sb->u.adfs_sb.s_log2sharesize); + + sb->u.adfs_sb.s_map = adfs_read_map(sb, dr); + if (!sb->u.adfs_sb.s_map) +@@ -393,6 +401,8 @@ + + brelse(bh); + ++ printk(KERN_DEBUG "ADFS: ids per zone %d\n", sb->u.adfs_sb.s_ids_per_zone); ++ + /* + * set up enough so that we can read an inode + */ +--- linux-2.4.25/fs/binfmt_aout.c~2.4.25-vrs2.patch 2001-11-03 02:39:20.000000000 +0100 ++++ linux-2.4.25/fs/binfmt_aout.c 2004-03-31 17:15:09.000000000 +0200 +@@ -422,7 +422,11 @@ + start_thread(regs, ex.a_entry, current->mm->start_stack); + if (current->ptrace & PT_PTRACED) + send_sig(SIGTRAP, current, 0); ++#ifndef __arm__ + return 0; ++#else ++ return regs->ARM_r0; ++#endif + } + + static int load_aout_library(struct file *file) +@@ -452,8 +456,11 @@ + + /* For QMAGIC, the starting address is 0x20 into the page. We mask + this off to get the starting address for the page */ +- +- start_addr = ex.a_entry & 0xfffff000; ++#ifndef __arm__ ++ start_addr = ex.a_entry & 0xfffff000; ++#else ++ start_addr = ex.a_entry & 0xffff8000; ++#endif + + if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) { + static unsigned long error_time; +--- linux-2.4.25/fs/binfmt_elf.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/fs/binfmt_elf.c 2004-03-31 17:15:09.000000000 +0200 +@@ -635,7 +635,6 @@ + } + + current->mm->start_stack = bprm->p; +- + /* Now we do a little grungy work by mmaping the ELF image into + the correct location in memory. At this point, we assume that + the image should be loaded at fixed address, not at a variable +--- linux-2.4.25/fs/exec.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/fs/exec.c 2004-03-31 17:15:09.000000000 +0200 +@@ -315,6 +315,7 @@ + spin_unlock(&tsk->mm->page_table_lock); + + /* no need for flush_tlb */ ++ memc_update_addr(tsk->mm, *pte, address); + return; + out: + spin_unlock(&tsk->mm->page_table_lock); +--- linux-2.4.25/fs/jffs/inode-v23.c~2.4.25-vrs2.patch 2001-10-05 00:14:35.000000000 +0200 ++++ linux-2.4.25/fs/jffs/inode-v23.c 2004-03-31 17:15:09.000000000 +0200 +@@ -10,7 +10,7 @@ + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * +- * $Id$ ++ * $Id$ + * + * Ported to Linux 2.3.x and MTD: + * Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB +@@ -48,6 +48,7 @@ + #include <linux/stat.h> + #include <linux/blkdev.h> + #include <linux/quotaops.h> ++#include <linux/compatmac.h> + #include <asm/semaphore.h> + #include <asm/byteorder.h> + #include <asm/uaccess.h> +@@ -58,6 +59,11 @@ + #include "jffs_proc.h" + #endif + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2) ++#define minor(x) MINOR(x) ++#define major(x) MAJOR(x) ++#endif ++ + static int jffs_remove(struct inode *dir, struct dentry *dentry, int type); + + static struct super_operations jffs_ops; +@@ -81,7 +87,7 @@ + D1(printk(KERN_NOTICE "JFFS: Trying to mount device %s.\n", + kdevname(dev))); + +- if (MAJOR(dev) != MTD_BLOCK_MAJOR) { ++ if (major(dev) != MTD_BLOCK_MAJOR) { + printk(KERN_WARNING "JFFS: Trying to mount a " + "non-mtd device.\n"); + return 0; +@@ -358,7 +364,7 @@ + inode->i_nlink = raw_inode->nlink; + inode->i_uid = raw_inode->uid; + inode->i_gid = raw_inode->gid; +- inode->i_rdev = 0; ++ inode->i_rdev = NODEV; + inode->i_size = raw_inode->dsize; + inode->i_atime = raw_inode->atime; + inode->i_mtime = raw_inode->mtime; +--- linux-2.4.25/fs/jffs/intrep.c~2.4.25-vrs2.patch 2003-06-13 16:51:37.000000000 +0200 ++++ linux-2.4.25/fs/jffs/intrep.c 2004-03-31 17:15:09.000000000 +0200 +@@ -10,7 +10,7 @@ + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * +- * $Id$ ++ * $Id$ + * + * Ported to Linux 2.3.x and MTD: + * Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB +@@ -772,6 +772,9 @@ + __u32 free_chunk_size1; + __u32 free_chunk_size2; + ++ __u32 largest_hole = 0; ++ __u32 hole_end_offset = 0; ++ __u32 head_offset; + + #define NUMFREEALLOWED 2 /* 2 chunks of at least erase size space allowed */ + int num_free_space = 0; /* Flag err if more than TWO +@@ -884,6 +887,21 @@ + (unsigned int) start, + (unsigned int)(test_start - start))); + ++ D1(printk("Reducing start to 0x%x from 0x%x\n", ++ test_start, start)); ++ if (largest_hole < test_start - start){ ++ ++ D3(printk("was hole = %x end_offset = %x\n", ++ largest_hole, hole_end_offset)); ++ if (fmc->head) { ++ largest_hole = test_start - start; ++ hole_end_offset = test_start; ++ } ++ } ++ ++ D3(printk("now = %x end_offset = %x\n", ++ largest_hole, hole_end_offset)); ++ + /* below, space from "start" to "pos" will be marked dirty. */ + start = test_start; + +@@ -956,6 +974,19 @@ + num_free_space++; + D1(printk("Free space accepted: Starting 0x%x for 0x%x bytes\n", + (unsigned int) start, (unsigned int) (pos - start))); ++ ++ if (largest_hole < pos - start) { ++ ++ D3(printk("was hole = %x end_offset = %x\n", ++ largest_hole, hole_end_offset)); ++ if (fmc->head){ ++ largest_hole = pos - start; ++ hole_end_offset = pos; ++ } ++ ++ D3(printk("now = %x end_offset = %x\n", ++ largest_hole, hole_end_offset)); ++ } + }else{ + num_free_spc_not_accp++; + D1(printk("Free space (#%i) found but *Not* accepted: Starting " +@@ -968,7 +999,7 @@ + (unsigned int) start, (unsigned int) (pos - start))); + jffs_fmalloced(fmc, (__u32) start, + (__u32) (pos - start), 0); +- } ++ } + + } + if(num_free_space > NUMFREEALLOWED){ +@@ -1002,9 +1033,11 @@ + to scan for the magic pattern. */ + D1(printk("*************** Dirty flash memory or " + "bad inode: " +- "hexdump(pos = 0x%lx, len = 128):\n", +- (long)pos)); +- D1(jffs_hexdump(fmc->mtd, pos, 128)); ++ "hexdump(pos = 0x%lx, len = %d):\n", ++ (long)pos, ++ end - pos > 128 ? 128 : end - pos)); ++ D1(jffs_hexdump(fmc->mtd, pos, ++ end - pos > 128 ? 128 : end - pos)); + + for (pos += 4; pos < end; pos += 4) { + switch (flash_read_u32(fmc->mtd, pos)) { +@@ -1197,12 +1230,6 @@ + + return -ENOMEM; + } +- if ((err = jffs_insert_node(c, 0, &raw_inode, +- name, node)) < 0) { +- printk("JFFS: Failed to handle raw inode. " +- "(err = %d)\n", err); +- break; +- } + if (raw_inode.rename) { + struct jffs_delete_list *dl + = (struct jffs_delete_list *) +@@ -1226,6 +1253,12 @@ + c->delete_list = dl; + node->data_size = 0; + } ++ if ((err = jffs_insert_node(c, 0, &raw_inode, ++ name, node)) < 0) { ++ printk("JFFS: Failed to handle raw inode. " ++ "(err = %d)\n", err); ++ break; ++ } + D3(jffs_print_node(node)); + node = 0; /* Don't free the node! */ + } +@@ -1242,7 +1275,19 @@ + jffs_free_node(node); + DJM(no_jffs_node--); + } +- jffs_build_end(fmc); ++ if (fmc->head && fmc->tail_extra && ++ fmc->head->offset + fmc->flash_size - ++ fmc->tail_extra->offset - fmc->tail_extra->size > largest_hole) { ++ head_offset = fmc->head->offset; ++ } ++ else { ++ head_offset = hole_end_offset; ++ } ++ ++ if (jffs_build_end(fmc, head_offset) < 0) { ++ D(printk("jffs_build_end() failed\n")); ++ return -ENOMEM; ++ } + + /* Free read buffer */ + kfree (read_buf); +--- linux-2.4.25/fs/jffs/jffs_fm.c~2.4.25-vrs2.patch 2001-10-05 00:13:18.000000000 +0200 ++++ linux-2.4.25/fs/jffs/jffs_fm.c 2004-03-31 17:15:09.000000000 +0200 +@@ -10,7 +10,7 @@ + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * +- * $Id$ ++ * $Id$ + * + * Ported to Linux 2.3.x and MTD: + * Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB +@@ -20,8 +20,14 @@ + #include <linux/slab.h> + #include <linux/blkdev.h> + #include <linux/jffs.h> ++#include <linux/compatmac.h> + #include "jffs_fm.h" + ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2) ++#define minor(x) MINOR(x) ++#define major(x) MAJOR(x) ++#endif ++ + #if defined(JFFS_MARK_OBSOLETE) && JFFS_MARK_OBSOLETE + static int jffs_mark_obsolete(struct jffs_fmcontrol *fmc, __u32 fm_offset); + #endif +@@ -46,7 +52,7 @@ + } + DJM(no_jffs_fmcontrol++); + +- mtd = get_mtd_device(NULL, MINOR(dev)); ++ mtd = get_mtd_device(NULL, minor(dev)); + + if (!mtd) { + kfree(fmc); +@@ -89,8 +95,8 @@ + + /* When the flash memory scan has completed, this function should be called + before use of the control structure. */ +-void +-jffs_build_end(struct jffs_fmcontrol *fmc) ++int ++jffs_build_end(struct jffs_fmcontrol *fmc, __u32 head_offset) + { + D3(printk("jffs_build_end()\n")); + +@@ -99,13 +105,100 @@ + fmc->tail = fmc->tail_extra; + } + else if (fmc->head_extra) { +- fmc->tail_extra->next = fmc->head; +- fmc->head->prev = fmc->tail_extra; +- fmc->head = fmc->head_extra; ++ struct jffs_fm *fm, *cur; ++ ++ if (head_offset == fmc->head->offset){ ++ fmc->tail->next = fmc->head_extra; ++ fmc->head_extra->prev = fmc->tail; ++ fmc->tail = fmc->tail_extra; ++ } ++ else { ++ fmc->tail_extra->next = fmc->head; ++ fmc->head->prev = fmc->tail_extra; ++ fmc->head = fmc->head_extra; ++ while (fmc->head->offset != head_offset){ ++ fmc->tail->next = fmc->head; ++ fmc->head = fmc->head->next; ++ fmc->head->prev = 0; ++ fmc->tail->next->prev = fmc->tail; ++ fmc->tail = fmc->tail->next; ++ fmc->tail->next = 0; ++ } ++ } ++ /* Make sure the only free space we have is between tail and head. ++ */ ++ for (cur = fmc->head; cur && cur != fmc->tail;) { ++ if (cur->offset + cur->size < cur->next->offset) { ++ if (!(fm = kmalloc(sizeof(struct jffs_fm), GFP_KERNEL))) { ++ D(printk("jffs_buid_end(): kmalloc failed!\n")); ++ return -ENOMEM; ++ } ++ DJM(no_jffs_fm++); ++ fm->size = cur->next->offset - cur->offset - cur->size; ++ fm->offset = cur->offset + cur->size; ++ fm->nodes = 0; ++ fm->next = cur->next; ++ fm->prev = cur; ++ cur->next->prev = fm; ++ cur->next = fm; ++ cur = fm->next; ++ fmc->free_size -= fm->size; ++ fmc->dirty_size += fm->size; ++ } ++ else if (cur->offset > cur->next->offset) { ++ if (cur->offset + cur->size < fmc->flash_size){ ++ if (!(fm = kmalloc(sizeof(struct jffs_fm), GFP_KERNEL))){ ++ ++ D(printk("jffs_buid_end(): kmalloc failed!\n")); ++ return -ENOMEM; ++ } ++ DJM(no_jffs_fm++); ++ fm->size = fmc->flash_size - ++ cur->offset - cur->size; ++ fm->nodes = 0; ++ fm->offset = cur->offset + cur->size; ++ fm->next = cur->next; ++ fm->prev = cur; ++ cur->next->prev = fm; ++ cur->next = fm; ++ cur = fm->next; ++ fmc->free_size -= fm->size; ++ fmc->dirty_size += fm->size; ++ } ++ else { ++ cur = cur->next; ++ } ++ if (cur->offset > 0) { ++ ++ if (!(fm = kmalloc(sizeof(struct jffs_fm), GFP_KERNEL))) { ++ D(printk("jffs_buid_end(): kmalloc failed!\n")); ++ return -ENOMEM; ++ } ++ DJM(no_jffs_fm++); ++ fm->size = cur->offset; ++ fm->nodes = 0; ++ fm->offset = 0; ++ fm->next = cur; ++ fm->prev = cur->prev; ++ cur->prev->next = fm; ++ cur->prev = fm; ++ fmc->free_size -= fm->size; ++ fmc->dirty_size += fm->size; ++ } ++ } ++ else if (cur->offset + cur->size != cur->next->offset) { ++ printk("jffs_build_end(): Internal error.\n"); ++ return -EINVAL; ++ } ++ else { ++ cur = cur->next; ++ } ++ } + } + fmc->head_extra = 0; /* These two instructions should be omitted. */ + fmc->tail_extra = 0; + D3(jffs_print_fmcontrol(fmc)); ++ return 0; + } + + +--- linux-2.4.25/fs/jffs/jffs_fm.h~2.4.25-vrs2.patch 2001-10-05 00:13:18.000000000 +0200 ++++ linux-2.4.25/fs/jffs/jffs_fm.h 2004-03-31 17:15:09.000000000 +0200 +@@ -10,7 +10,7 @@ + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * +- * $Id$ ++ * $Id$ + * + * Ported to Linux 2.3.x and MTD: + * Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB +@@ -123,7 +123,7 @@ + + + struct jffs_fmcontrol *jffs_build_begin(struct jffs_control *c, kdev_t dev); +-void jffs_build_end(struct jffs_fmcontrol *fmc); ++int jffs_build_end(struct jffs_fmcontrol *fmc, __u32 head_offset); + void jffs_cleanup_fmcontrol(struct jffs_fmcontrol *fmc); + + int jffs_fmalloc(struct jffs_fmcontrol *fmc, __u32 size, +--- linux-2.4.25/fs/partitions/Config.in~2.4.25-vrs2.patch 2002-11-29 00:53:15.000000000 +0100 ++++ linux-2.4.25/fs/partitions/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -6,6 +6,7 @@ + bool ' Acorn partition support' CONFIG_ACORN_PARTITION + if [ "$CONFIG_ACORN_PARTITION" != "n" ]; then + # bool ' Cumana partition support' CONFIG_ACORN_PARTITION_CUMANA ++ bool ' EESOX partition support' CONFIG_ACORN_PARTITION_EESOX + bool ' ICS partition support' CONFIG_ACORN_PARTITION_ICS + bool ' Native filecore partition support' CONFIG_ACORN_PARTITION_ADFS + bool ' PowerTec partition support' CONFIG_ACORN_PARTITION_POWERTEC +@@ -52,6 +53,7 @@ + define_bool CONFIG_ACORN_PARTITION y + define_bool CONFIG_ACORN_PARTITION_ADFS y + # define_bool CONFIG_ACORN_PARTITION_CUMANA y ++ define_bool CONFIG_ACORN_PARTITION_EESOX y + define_bool CONFIG_ACORN_PARTITION_ICS y + define_bool CONFIG_ACORN_PARTITION_POWERTEC y + define_bool CONFIG_ACORN_PARTITION_RISCIX y +--- linux-2.4.25/fs/partitions/acorn.c~2.4.25-vrs2.patch 2002-08-03 02:39:45.000000000 +0200 ++++ linux-2.4.25/fs/partitions/acorn.c 2004-03-31 17:15:09.000000000 +0200 +@@ -7,7 +7,10 @@ + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * +- * Scan ADFS partitions on hard disk drives. ++ * Scan ADFS partitions on hard disk drives. Unfortunately, there ++ * isn't a standard for partitioning drives on Acorn machines, so ++ * every single manufacturer of SCSI and IDE cards created their own ++ * method. + */ + #include <linux/config.h> + #include <linux/kernel.h> +@@ -18,10 +21,18 @@ + #include <linux/genhd.h> + #include <linux/fs.h> + #include <linux/pagemap.h> ++#include <linux/adfs_fs.h> + + #include "check.h" + #include "acorn.h" + ++/* ++ * Partition types. (Oh for reusability) ++ */ ++#define PARTITION_RISCIX_MFM 1 ++#define PARTITION_RISCIX_SCSI 2 ++#define PARTITION_LINUX 9 ++ + static void + adfspart_setgeometry(kdev_t dev, unsigned int secspertrack, unsigned int heads) + { +@@ -61,6 +72,21 @@ + } + + #ifdef CONFIG_ACORN_PARTITION_RISCIX ++ ++struct riscix_part { ++ __u32 start; ++ __u32 length; ++ __u32 one; ++ char name[16]; ++}; ++ ++struct riscix_record { ++ __u32 magic; ++#define RISCIX_MAGIC (0x4a657320) ++ __u32 date; ++ struct riscix_part part[8]; ++}; ++ + static int + riscix_partition(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sect, int minor, unsigned long nr_sects) +@@ -102,6 +128,15 @@ + } + #endif + ++#define LINUX_NATIVE_MAGIC 0xdeafa1de ++#define LINUX_SWAP_MAGIC 0xdeafab1e ++ ++struct linux_part { ++ __u32 magic; ++ __u32 start_sect; ++ __u32 nr_sects; ++}; ++ + static int + linux_partition(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sect, int minor, unsigned long nr_sects) +@@ -136,7 +171,7 @@ + } + + #ifdef CONFIG_ACORN_PARTITION_CUMANA +-static int ++int + adfspart_check_CUMANA(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sector, int minor) + { +@@ -147,7 +182,7 @@ + int first = 1; + + /* +- * Try Cumana style partitions - sector 3 contains ADFS boot block ++ * Try Cumana style partitions - sector 6 contains ADFS boot block + * with pointer to next 'drive'. + * + * There are unknowns in this code - is the 'cylinder number' of the +@@ -163,13 +198,13 @@ + struct adfs_discrecord *dr; + unsigned int nr_sects; + +- if (!(minor & mask)) +- break; +- + data = read_dev_sector(bdev, start_blk * 2 + 6, §); + if (!data) + return -1; + ++ if (!(minor & mask)) ++ break; ++ + dr = adfs_partition(hd, name, data, first_sector, minor++); + if (!dr) + break; +@@ -229,7 +264,7 @@ + * hda1 = ADFS partition on first drive. + * hda2 = non-ADFS partition. + */ +-static int ++int + adfspart_check_ADFS(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sector, int minor) + { +@@ -282,11 +317,18 @@ + break; + } + } ++ printk("\n"); + return 1; + } + #endif + + #ifdef CONFIG_ACORN_PARTITION_ICS ++ ++struct ics_part { ++ __u32 start; ++ __s32 size; ++}; ++ + static int adfspart_check_ICSLinux(struct block_device *bdev, unsigned long block) + { + Sector sect; +@@ -303,6 +345,22 @@ + } + + /* ++ * Check for a valid ICS partition using the checksum. ++ */ ++static inline int valid_ics_sector(const unsigned char *data) ++{ ++ unsigned long sum; ++ int i; ++ ++ for (i = 0, sum = 0x50617274; i < 508; i++) ++ sum += data[i]; ++ ++ sum -= le32_to_cpu(*(__u32 *)(&data[508])); ++ ++ return sum == 0; ++} ++ ++/* + * Purpose: allocate ICS partitions. + * Params : hd - pointer to gendisk structure to store partition info. + * dev - device number to access. +@@ -314,15 +372,14 @@ + * hda2 = ADFS partition 1 on first drive. + * ..etc.. + */ +-static int ++int + adfspart_check_ICS(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sector, int minor) + { ++ const unsigned char *data; ++ const struct ics_part *p; ++ unsigned int mask = (1 << hd->minor_shift) - 1; + Sector sect; +- unsigned char *data; +- unsigned long sum; +- unsigned int i, mask = (1 << hd->minor_shift) - 1; +- struct ics_part *p; + + /* + * Try ICS style partitions - sector 0 contains partition info. +@@ -331,21 +388,14 @@ + if (!data) + return -1; + +- /* +- * check for a valid checksum +- */ +- for (i = 0, sum = 0x50617274; i < 508; i++) +- sum += data[i]; +- +- sum -= le32_to_cpu(*(__u32 *)(&data[508])); +- if (sum) { +- put_dev_sector(sect); +- return 0; /* not ICS partition table */ ++ if (!valid_ics_sector(data)) { ++ put_dev_sector(sect); ++ return 0; + } + + printk(" [ICS]"); + +- for (p = (struct ics_part *)data; p->size; p++) { ++ for (p = (const struct ics_part *)data; p->size; p++) { + unsigned long start; + long size; + +@@ -355,12 +405,19 @@ + start = le32_to_cpu(p->start); + size = le32_to_cpu(p->size); + ++ /* ++ * Negative sizes tell the RISC OS ICS driver to ignore ++ * this partition - in effect it says that this does not ++ * contain an ADFS filesystem. ++ */ + if (size < 0) { + size = -size; + + /* +- * We use the first sector to identify what type +- * this partition is... ++ * Our own extension - We use the first sector ++ * of the partition to identify what type this ++ * partition is. We must not make this visible ++ * to the filesystem. + */ + if (size > 1 && adfspart_check_ICSLinux(bdev, start)) { + start += 1; +@@ -375,10 +432,32 @@ + } + + put_dev_sector(sect); ++ printk("\n"); + return 1; + } + #endif + ++#ifdef CONFIG_ACORN_PARTITION_POWERTEC ++struct ptec_part { ++ __u32 unused1; ++ __u32 unused2; ++ __u32 start; ++ __u32 size; ++ __u32 unused5; ++ char type[8]; ++}; ++ ++static inline int valid_ptec_sector(const unsigned char *data) ++{ ++ unsigned char checksum = 0x2a; ++ int i; ++ ++ for (i = 0; i < 511; i++) ++ checksum += data[i]; ++ ++ return checksum == data[511]; ++} ++ + /* + * Purpose: allocate ICS partitions. + * Params : hd - pointer to gendisk structure to store partition info. +@@ -391,32 +470,27 @@ + * hda2 = ADFS partition 1 on first drive. + * ..etc.. + */ +-#ifdef CONFIG_ACORN_PARTITION_POWERTEC +-static int ++int + adfspart_check_POWERTEC(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sector, int minor) + { + Sector sect; +- unsigned char *data; +- struct ptec_partition *p; +- unsigned char checksum; ++ const unsigned char *data; ++ const struct ptec_part *p; + int i; + + data = read_dev_sector(bdev, 0, §); + if (!data) + return -1; + +- for (checksum = 0x2a, i = 0; i < 511; i++) +- checksum += data[i]; +- +- if (checksum != data[511]) { ++ if (!valid_ptec_sector(data)) { + put_dev_sector(sect); + return 0; + } + + printk(" [POWERTEC]"); + +- for (i = 0, p = (struct ptec_partition *)data; i < 12; i++, p++) { ++ for (i = 0, p = (const struct ptec_part *)data; i < 12; i++, p++) { + unsigned long start; + unsigned long size; + +@@ -430,49 +504,82 @@ + } + + put_dev_sector(sect); ++ printk("\n"); + return 1; + } + #endif + +-static int (*partfn[])(struct gendisk *, struct block_device *, unsigned long, int) = { +-#ifdef CONFIG_ACORN_PARTITION_ICS +- adfspart_check_ICS, +-#endif +-#ifdef CONFIG_ACORN_PARTITION_POWERTEC +- adfspart_check_POWERTEC, +-#endif +-#ifdef CONFIG_ACORN_PARTITION_CUMANA +- adfspart_check_CUMANA, +-#endif +-#ifdef CONFIG_ACORN_PARTITION_ADFS +- adfspart_check_ADFS, +-#endif +- NULL ++#ifdef CONFIG_ACORN_PARTITION_EESOX ++struct eesox_part { ++ char magic[6]; ++ char name[10]; ++ u32 start; ++ u32 unused6; ++ u32 unused7; ++ u32 unused8; + }; ++ + /* +- * Purpose: initialise all the partitions on an ADFS drive. +- * These may be other ADFS partitions or a Linux/RiscBSD/RISCiX +- * partition. ++ * Guess who created this format? ++ */ ++static const char eesox_name[] = { ++ 'N', 'e', 'i', 'l', ' ', ++ 'C', 'r', 'i', 't', 'c', 'h', 'e', 'l', 'l', ' ', ' ' ++}; ++ ++/* ++ * EESOX SCSI partition format. + * +- * Params : hd - pointer to gendisk structure +- * dev - device number to access +- * first_sect - first available sector on the disk. +- * first_minor - first available minor on this device. ++ * This is a goddamned awful partition format. We don't seem to store ++ * the size of the partition in this table, only the start addresses. + * +- * Returns: -1 on error, 0 if not ADFS format, 1 if ok. ++ * There are two possibilities where the size comes from: ++ * 1. The individual ADFS boot block entries that are placed on the disk. ++ * 2. The start address of the next entry. + */ +-int acorn_partition(struct gendisk *hd, struct block_device *bdev, +- unsigned long first_sect, int first_minor) ++int ++adfspart_check_EESOX(struct gendisk *hd, struct block_device *bdev, ++ unsigned long first_sector, int minor) + { ++ Sector sect; ++ const unsigned char *data; ++ unsigned char buffer[256]; ++ struct eesox_part *p; ++ u32 start = first_sector; + int i; + +- for (i = 0; partfn[i]; i++) { +- int r = partfn[i](hd, bdev, first_sect, first_minor); +- if (r) { +- if (r > 0) +- printk("\n"); +- return r; +- } ++ data = read_dev_sector(bdev, 7, §); ++ if (!data) ++ return -1; ++ ++ /* ++ * "Decrypt" the partition table. God knows why... ++ */ ++ for (i = 0; i < 256; i++) ++ buffer[i] = data[i] ^ eesox_name[i & 15]; ++ ++ put_dev_sector(sect); ++ ++ for (i = 0, p = (struct eesox_part *)buffer; i < 8; i++, p++) { ++ u32 next; ++ ++ if (memcmp(p->magic, "Eesox", 6)) ++ break; ++ ++ next = le32_to_cpu(p->start) + first_sector; ++ if (i) ++ add_gd_partition(hd, minor++, start, next - start); ++ start = next; + } +- return 0; ++ ++ if (i != 0) { ++ unsigned long size; ++ ++ size = hd->part[MINOR(to_kdev_t(bdev->bd_dev))].nr_sects; ++ add_gd_partition(hd, minor++, start, size - start); ++ printk("\n"); ++ } ++ ++ return i ? 1 : 0; + } ++#endif +--- linux-2.4.25/fs/partitions/acorn.h~2.4.25-vrs2.patch 2001-11-22 20:48:07.000000000 +0100 ++++ linux-2.4.25/fs/partitions/acorn.h 2004-03-31 17:15:09.000000000 +0200 +@@ -1,55 +1,28 @@ + /* +- * fs/partitions/acorn.h ++ * linux/fs/partitions/acorn.h + * +- * Copyright (C) 1996-1998 Russell King +- */ +-#include <linux/adfs_fs.h> +- +-/* +- * Partition types. (Oh for reusability) ++ * Copyright (C) 1996-2001 Russell King. ++ * ++ * I _hate_ this partitioning mess - why can't we have one defined ++ * format, and everyone stick to it? + */ +-#define PARTITION_RISCIX_MFM 1 +-#define PARTITION_RISCIX_SCSI 2 +-#define PARTITION_LINUX 9 +- +-struct riscix_part { +- __u32 start; +- __u32 length; +- __u32 one; +- char name[16]; +-}; + +-struct riscix_record { +- __u32 magic; +-#define RISCIX_MAGIC (0x4a657320) +- __u32 date; +- struct riscix_part part[8]; +-}; +- +-#define LINUX_NATIVE_MAGIC 0xdeafa1de +-#define LINUX_SWAP_MAGIC 0xdeafab1e +- +-struct linux_part { +- __u32 magic; +- __u32 start_sect; +- __u32 nr_sects; +-}; ++int ++adfspart_check_CUMANA(struct gendisk *hd, struct block_device *bdev, ++ unsigned long first_sector, int minor); + +-struct ics_part { +- __u32 start; +- __s32 size; +-}; ++int ++adfspart_check_ADFS(struct gendisk *hd, struct block_device *bdev, ++ unsigned long first_sector, int minor); + +-struct ptec_partition { +- __u32 unused1; +- __u32 unused2; +- __u32 start; +- __u32 size; +- __u32 unused5; +- char type[8]; +-}; +- ++int ++adfspart_check_ICS(struct gendisk *hd, struct block_device *bdev, ++ unsigned long first_sector, int minor); + +-int acorn_partition(struct gendisk *hd, struct block_device *bdev, +- unsigned long first_sect, int first_minor); ++int ++adfspart_check_POWERTEC(struct gendisk *hd, struct block_device *bdev, ++ unsigned long first_sector, int minor); + ++int ++adfspart_check_EESOX(struct gendisk *hd, struct block_device *bdev, ++ unsigned long first_sector, int minor); +--- linux-2.4.25/fs/partitions/check.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/fs/partitions/check.c 2004-03-31 17:15:09.000000000 +0200 +@@ -40,8 +40,30 @@ + int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/ + + static int (*check_part[])(struct gendisk *hd, struct block_device *bdev, unsigned long first_sect, int first_minor) = { +-#ifdef CONFIG_ACORN_PARTITION +- acorn_partition, ++ /* ++ * Probe partition formats with tables at disk address 0 ++ * that also have an ADFS boot block at 0xdc0. ++ */ ++#ifdef CONFIG_ACORN_PARTITION_ICS ++ adfspart_check_ICS, ++#endif ++#ifdef CONFIG_ACORN_PARTITION_POWERTEC ++ adfspart_check_POWERTEC, ++#endif ++#ifdef CONFIG_ACORN_PARTITION_EESOX ++ adfspart_check_EESOX, ++#endif ++ ++ /* ++ * Now move on to formats that only have partition info at ++ * disk address 0xdc0. These should come before MSDOS ++ * partition tables. ++ */ ++#ifdef CONFIG_ACORN_PARTITION_CUMANA ++ adfspart_check_CUMANA, ++#endif ++#ifdef CONFIG_ACORN_PARTITION_ADFS ++ adfspart_check_ADFS, + #endif + #ifdef CONFIG_SGI_PARTITION + sgi_partition, +@@ -79,13 +101,25 @@ + NULL + }; + ++static char *raid_name (struct gendisk *hd, unsigned int unit, unsigned int part, ++ int major_base, char *buf) ++{ ++ int ctlr = hd->major - major_base; ++ if (part == 0) ++ sprintf(buf, "%s/c%dd%d", hd->major_name, ctlr, unit); ++ else ++ sprintf(buf, "%s/c%dd%dp%d", hd->major_name, ctlr, unit, ++ part); ++ return buf; ++} ++ + /* + * This is ucking fugly but its probably the best thing for 2.4.x + * Take it as a clear reminder that: 1) we should put the device name + * generation in the object kdev_t points to in 2.5. + * and 2) ioctls better work on half-opened devices. + */ +- ++ + #ifdef CONFIG_ARCH_S390 + int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL; + int (*genhd_dasd_ioctl)(struct inode *inp, struct file *filp, +@@ -104,10 +138,11 @@ + char *disk_name (struct gendisk *hd, int minor, char *buf) + { + const char *maj = hd->major_name; +- unsigned int unit = (minor >> hd->minor_shift); +- unsigned int part = (minor & ((1 << hd->minor_shift) -1 )); ++ unsigned int unit = minor >> hd->minor_shift; ++ unsigned int part = minor & (( 1 << hd->minor_shift) - 1); ++ char *p; + +- if ((unit < hd->nr_real) && hd->part[minor].de) { ++ if (unit < hd->nr_real && hd->part[minor].de) { + int pos; + + pos = devfs_generate_path (hd->part[minor].de, buf, 64); +@@ -153,51 +188,32 @@ + } + if (hd->major >= SCSI_DISK1_MAJOR && hd->major <= SCSI_DISK7_MAJOR) { + unit = unit + (hd->major - SCSI_DISK1_MAJOR + 1) * 16; +- if (unit+'a' > 'z') { +- unit -= 26; +- sprintf(buf, "sd%c%c", 'a' + unit / 26, 'a' + unit % 26); +- if (part) +- sprintf(buf + 4, "%d", part); +- return buf; +- } + } + if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= COMPAQ_SMART2_MAJOR+7) { +- int ctlr = hd->major - COMPAQ_SMART2_MAJOR; +- if (part == 0) +- sprintf(buf, "%s/c%dd%d", maj, ctlr, unit); +- else +- sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, unit, part); +- return buf; +- } ++ return raid_name(hd, unit, part, COMPAQ_SMART2_MAJOR, buf); ++ } + if (hd->major >= COMPAQ_CISS_MAJOR && hd->major <= COMPAQ_CISS_MAJOR+7) { +- int ctlr = hd->major - COMPAQ_CISS_MAJOR; +- if (part == 0) +- sprintf(buf, "%s/c%dd%d", maj, ctlr, unit); +- else +- sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, unit, part); +- return buf; ++ return raid_name(hd, unit, part, COMPAQ_CISS_MAJOR, buf); + } + if (hd->major >= DAC960_MAJOR && hd->major <= DAC960_MAJOR+7) { +- int ctlr = hd->major - DAC960_MAJOR; ++ return raid_name(hd, unit, part, DAC960_MAJOR, buf); ++ } ++ if (hd->major == ATARAID_MAJOR) { ++ int disk = minor >> hd->minor_shift; ++ int part = minor & (( 1 << hd->minor_shift) - 1); + if (part == 0) +- sprintf(buf, "%s/c%dd%d", maj, ctlr, unit); ++ sprintf(buf, "%s/d%d", maj, disk); + else +- sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, unit, part); ++ sprintf(buf, "%s/d%dp%d", maj, disk, part); + return buf; + } +- if (hd->major == ATARAID_MAJOR) { +- int disk = minor >> hd->minor_shift; +- int part = minor & (( 1 << hd->minor_shift) - 1); +- if (part == 0) +- sprintf(buf, "%s/d%d", maj, disk); +- else +- sprintf(buf, "%s/d%dp%d", maj, disk, part); +- return buf; +- } +- if (part) +- sprintf(buf, "%s%c%d", maj, unit+'a', part); ++ p = buf; ++ if (unit <= 26) ++ p += sprintf(buf, "%s%c", maj, 'a' + unit); + else +- sprintf(buf, "%s%c", maj, unit+'a'); ++ p += sprintf(buf, "%s%c%c", maj, 'a' + unit / 26, 'a' + unit % 26); ++ if (part) ++ sprintf(p, "%d", part); + return buf; + } + +@@ -207,7 +223,7 @@ + void add_gd_partition(struct gendisk *hd, int minor, int start, int size) + { + #ifndef CONFIG_DEVFS_FS +- char buf[40]; ++ char buf[MAX_DISKNAME_LEN]; + #endif + + hd->part[minor].start_sect = start; +@@ -229,7 +245,7 @@ + static int first_time = 1; + unsigned long first_sector; + struct block_device *bdev; +- char buf[64]; ++ char buf[MAX_DISKNAME_LEN]; + int i; + + if (first_time) +--- linux-2.4.25/fs/proc/array.c~2.4.25-vrs2.patch 2003-11-28 19:26:21.000000000 +0100 ++++ linux-2.4.25/fs/proc/array.c 2004-03-31 17:15:09.000000000 +0200 +@@ -362,15 +362,15 @@ + task->cmin_flt, + task->maj_flt, + task->cmaj_flt, +- task->times.tms_utime, +- task->times.tms_stime, +- task->times.tms_cutime, +- task->times.tms_cstime, ++ hz_to_std(task->times.tms_utime), ++ hz_to_std(task->times.tms_stime), ++ hz_to_std(task->times.tms_cutime), ++ hz_to_std(task->times.tms_cstime), + priority, + nice, + 0UL /* removed */, + task->it_real_value, +- task->start_time, ++ hz_to_std(task->start_time), + vsize, + mm ? mm->rss : 0, /* you might want to shift this left 3 */ + task->rlim[RLIMIT_RSS].rlim_cur, +@@ -417,6 +417,7 @@ + end = PMD_SIZE; + do { + pte_t page = *pte; ++ unsigned long pfn; + struct page *ptpage; + + address += PAGE_SIZE; +@@ -426,8 +427,11 @@ + ++*total; + if (!pte_present(page)) + continue; +- ptpage = pte_page(page); +- if ((!VALID_PAGE(ptpage)) || PageReserved(ptpage)) ++ pfn = pte_pfn(page); ++ if (!pfn_valid(pfn)) ++ continue; ++ ptpage = pfn_to_page(pfn); ++ if (PageReserved(ptpage)) + continue; + ++*pages; + if (pte_dirty(page)) +@@ -609,14 +613,14 @@ + + len = sprintf(buffer, + "cpu %lu %lu\n", +- task->times.tms_utime, +- task->times.tms_stime); ++ hz_to_std(task->times.tms_utime), ++ hz_to_std(task->times.tms_stime)); + + for (i = 0 ; i < smp_num_cpus; i++) + len += sprintf(buffer + len, "cpu%d %lu %lu\n", + i, +- task->per_cpu_utime[cpu_logical_map(i)], +- task->per_cpu_stime[cpu_logical_map(i)]); ++ hz_to_std(task->per_cpu_utime[cpu_logical_map(i)]), ++ hz_to_std(task->per_cpu_stime[cpu_logical_map(i)])); + + return len; + } +--- linux-2.4.25/fs/proc/proc_misc.c~2.4.25-vrs2.patch 2003-11-28 19:26:21.000000000 +0100 ++++ linux-2.4.25/fs/proc/proc_misc.c 2004-03-31 17:15:09.000000000 +0200 +@@ -308,16 +308,16 @@ + { + int i, len = 0; + extern unsigned long total_forks; +- unsigned long jif = jiffies; ++ unsigned long jif = hz_to_std(jiffies); + unsigned int sum = 0, user = 0, nice = 0, system = 0; + int major, disk; + + for (i = 0 ; i < smp_num_cpus; i++) { + int cpu = cpu_logical_map(i), j; + +- user += kstat.per_cpu_user[cpu]; +- nice += kstat.per_cpu_nice[cpu]; +- system += kstat.per_cpu_system[cpu]; ++ user += hz_to_std(kstat.per_cpu_user[cpu]); ++ nice += hz_to_std(kstat.per_cpu_nice[cpu]); ++ system += hz_to_std(kstat.per_cpu_system[cpu]); + #if !defined(CONFIG_ARCH_S390) + for (j = 0 ; j < NR_IRQS ; j++) + sum += kstat.irqs[cpu][j]; +@@ -331,10 +331,10 @@ + proc_sprintf(page, &off, &len, + "cpu%d %u %u %u %lu\n", + i, +- kstat.per_cpu_user[cpu_logical_map(i)], +- kstat.per_cpu_nice[cpu_logical_map(i)], +- kstat.per_cpu_system[cpu_logical_map(i)], +- jif - ( kstat.per_cpu_user[cpu_logical_map(i)] \ ++ hz_to_std(kstat.per_cpu_user[cpu_logical_map(i)]), ++ hz_to_std(kstat.per_cpu_nice[cpu_logical_map(i)]), ++ hz_to_std(kstat.per_cpu_system[cpu_logical_map(i)]), ++ jif - hz_to_std( kstat.per_cpu_user[cpu_logical_map(i)] \ + + kstat.per_cpu_nice[cpu_logical_map(i)] \ + + kstat.per_cpu_system[cpu_logical_map(i)])); + proc_sprintf(page, &off, &len, +@@ -440,12 +440,14 @@ + return proc_calc_metrics(page, start, off, count, eof, len); + } + ++#ifdef CONFIG_GENERIC_ISA_DMA + static int dma_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) + { + int len = get_dma_list(page); + return proc_calc_metrics(page, start, off, count, eof, len); + } ++#endif + + static int cmdline_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +@@ -613,7 +615,9 @@ + {"interrupts", interrupts_read_proc}, + #endif + {"filesystems", filesystems_read_proc}, ++#ifdef CONFIG_GENERIC_ISA_DMA + {"dma", dma_read_proc}, ++#endif + {"cmdline", cmdline_read_proc}, + #ifdef CONFIG_SGI_DS1286 + {"rtc", ds1286_read_proc}, +--- linux-2.4.25/fs/stat.c~2.4.25-vrs2.patch 2004-02-18 14:36:31.000000000 +0100 ++++ linux-2.4.25/fs/stat.c 2004-03-31 17:15:09.000000000 +0200 +@@ -26,7 +26,9 @@ + } + + +-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__) && !defined(__mips__) ++#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && \ ++ !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__arm__) && \ ++ !defined(__x86_64__) && !defined(__mips__) + + /* + * For backward compatibility? Maybe this should be moved +@@ -38,7 +40,7 @@ + struct __old_kernel_stat tmp; + + memset(&tmp, 0, sizeof(struct __old_kernel_stat)); +- ++ + if (warncount > 0) { + warncount--; + printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n", +@@ -58,7 +60,7 @@ + #if BITS_PER_LONG == 32 + if (inode->i_size > MAX_NON_LFS) + return -EOVERFLOW; +-#endif ++#endif + tmp.st_size = inode->i_size; + tmp.st_atime = inode->i_atime; + tmp.st_mtime = inode->i_mtime; +@@ -84,7 +86,7 @@ + #if BITS_PER_LONG == 32 + if (inode->i_size > MAX_NON_LFS) + return -EOVERFLOW; +-#endif ++#endif + tmp.st_size = inode->i_size; + tmp.st_atime = inode->i_atime; + tmp.st_mtime = inode->i_mtime; +@@ -129,7 +131,9 @@ + } + + +-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__) && !defined(__mips__) ++#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && \ ++ !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__arm__) && \ ++ !defined(__x86_64__) && !defined(__mips__) + /* + * For backward compatibility? Maybe this should be moved + * into arch/i386 instead? +@@ -165,7 +169,9 @@ + return error; + } + +-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__) && !defined(__mips__) ++#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && \ ++ !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__arm__) && \ ++ !defined(__x86_64__) && !defined(__mips__) + + /* + * For backward compatibility? Maybe this should be moved +@@ -203,7 +209,9 @@ + return error; + } + +-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__) && !defined(__mips__) ++#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && \ ++ !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__arm__) && \ ++ !defined(__x86_64__) && !defined(__mips__) + + /* + * For backward compatibility? Maybe this should be moved +--- linux-2.4.25/include/asm-alpha/ide.h~2.4.25-vrs2.patch 2003-06-13 16:51:38.000000000 +0200 ++++ linux-2.4.25/include/asm-alpha/ide.h 2004-03-31 17:15:09.000000000 +0200 +@@ -19,35 +19,15 @@ + #define MAX_HWIFS 4 + #endif + +-static __inline__ int ide_default_irq(ide_ioreg_t base) +-{ +- switch (base) { +- case 0x1f0: return 14; +- case 0x170: return 15; +- case 0x1e8: return 11; +- case 0x168: return 10; +- default: +- return 0; +- } +-} +- +-static __inline__ ide_ioreg_t ide_default_io_base(int index) +-{ +- switch (index) { +- case 0: return 0x1f0; +- case 1: return 0x170; +- case 2: return 0x1e8; +- case 3: return 0x168; +- default: +- return 0; +- } +-} ++#define ide_default_io_base(i) ((ide_ioreg_t)0) ++#define ide_default_irq(b) (0) + + static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) + { + ide_ioreg_t reg = data_port; + int i; + ++ memset(hw, 0, sizeof(*hw)); + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg; + reg += 1; +@@ -55,7 +35,7 @@ + if (ctrl_port) { + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; + } else { +- hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206; ++ hw->io_ports[IDE_CONTROL_OFFSET] = data_port + 0x206; + } + if (irq != NULL) + *irq = 0; +@@ -70,13 +50,19 @@ + { + #ifndef CONFIG_BLK_DEV_IDEPCI + hw_regs_t hw; +- int index; + +- for (index = 0; index < MAX_HWIFS; index++) { +- ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL); +- hw.irq = ide_default_irq(ide_default_io_base(index)); +- ide_register_hw(&hw, NULL); +- } ++ ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL); ++ hw.irq = 14; ++ ide_register_hw(&hw, NULL); ++ ide_init_hwif_ports(&hw, 0x170, 0x376, NULL); ++ hw.irq = 15; ++ ide_register_hw(&hw, NULL); ++ ide_init_hwif_ports(&hw, 0x1e8, 0x3ee, NULL); ++ hw.irq = 11; ++ ide_register_hw(&hw, NULL); ++ ide_init_hwif_ports(&hw, 0x168, 0x36e, NULL); ++ hw.irq = 10; ++ ide_register_hw(&hw, NULL); + #endif /* CONFIG_BLK_DEV_IDEPCI */ + } + +--- linux-2.4.25/include/asm-alpha/param.h~2.4.25-vrs2.patch 2000-11-08 08:37:31.000000000 +0100 ++++ linux-2.4.25/include/asm-alpha/param.h 2004-03-31 17:15:09.000000000 +0200 +@@ -13,6 +13,9 @@ + # else + # define HZ 1200 + # endif ++#ifdef __KERNEL__ ++# define hz_to_std(a) (a) ++#endif + #endif + + #define EXEC_PAGESIZE 8192 +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-at91rm9200/AT91RM9200_MCI.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,127 @@ ++// ---------------------------------------------------------------------------- ++// ATMEL Microcontroller Software Support - ROUSSET - ++// ---------------------------------------------------------------------------- ++// The software is delivered "AS IS" without warranty or condition of any ++// kind, either express, implied or statutory. This includes without ++// limitation any warranty or condition with respect to merchantability or ++// fitness for any particular purpose, or against the infringements of ++// intellectual property rights of others. ++// ---------------------------------------------------------------------------- ++// File Name : AT91RM9200.h ++// Object : AT91RM9200 / MCI definitions ++// Generated : AT91 SW Application Group 12/03/2002 (10:48:02) ++// ++// ---------------------------------------------------------------------------- ++ ++#ifndef AT91RM9200_MCI_H ++#define AT91RM9200_MCI_H ++ ++// ***************************************************************************** ++// SOFTWARE API DEFINITION FOR Multimedia Card Interface ++// ***************************************************************************** ++#ifndef __ASSEMBLY__ ++ ++typedef struct _AT91S_MCI { ++ AT91_REG MCI_CR; // MCI Control Register ++ AT91_REG MCI_MR; // MCI Mode Register ++ AT91_REG MCI_DTOR; // MCI Data Timeout Register ++ AT91_REG MCI_SDCR; // MCI SD Card Register ++ AT91_REG MCI_ARGR; // MCI Argument Register ++ AT91_REG MCI_CMDR; // MCI Command Register ++ AT91_REG Reserved0[2]; // ++ AT91_REG MCI_RSPR[4]; // MCI Response Register ++ AT91_REG MCI_RDR; // MCI Receive Data Register ++ AT91_REG MCI_TDR; // MCI Transmit Data Register ++ AT91_REG Reserved1[2]; // ++ AT91_REG MCI_SR; // MCI Status Register ++ AT91_REG MCI_IER; // MCI Interrupt Enable Register ++ AT91_REG MCI_IDR; // MCI Interrupt Disable Register ++ AT91_REG MCI_IMR; // MCI Interrupt Mask Register ++ AT91_REG Reserved2[44]; // ++ AT91_REG MCI_RPR; // Receive Pointer Register ++ AT91_REG MCI_RCR; // Receive Counter Register ++ AT91_REG MCI_TPR; // Transmit Pointer Register ++ AT91_REG MCI_TCR; // Transmit Counter Register ++ AT91_REG MCI_RNPR; // Receive Next Pointer Register ++ AT91_REG MCI_RNCR; // Receive Next Counter Register ++ AT91_REG MCI_TNPR; // Transmit Next Pointer Register ++ AT91_REG MCI_TNCR; // Transmit Next Counter Register ++ AT91_REG MCI_PTCR; // PDC Transfer Control Register ++ AT91_REG MCI_PTSR; // PDC Transfer Status Register ++} AT91S_MCI, *AT91PS_MCI; ++ ++#endif ++ ++// -------- MCI_CR : (MCI Offset: 0x0) MCI Control Register -------- ++#define AT91C_MCI_MCIEN ((unsigned int) 0x1 << 0) // (MCI) Multimedia Interface Enable ++#define AT91C_MCI_MCIDIS ((unsigned int) 0x1 << 1) // (MCI) Multimedia Interface Disable ++#define AT91C_MCI_PWSEN ((unsigned int) 0x1 << 2) // (MCI) Power Save Mode Enable ++#define AT91C_MCI_PWSDIS ((unsigned int) 0x1 << 3) // (MCI) Power Save Mode Disable ++// -------- MCI_MR : (MCI Offset: 0x4) MCI Mode Register -------- ++#define AT91C_MCI_CLKDIV ((unsigned int) 0x1 << 0) // (MCI) Clock Divider ++#define AT91C_MCI_PWSDIV ((unsigned int) 0x1 << 8) // (MCI) Power Saving Divider ++#define AT91C_MCI_PDCPADV ((unsigned int) 0x1 << 14) // (MCI) PDC Padding Value ++#define AT91C_MCI_PDCMODE ((unsigned int) 0x1 << 15) // (MCI) PDC Oriented Mode ++#define AT91C_MCI_BLKLEN ((unsigned int) 0x1 << 18) // (MCI) Data Block Length ++// -------- MCI_DTOR : (MCI Offset: 0x8) MCI Data Timeout Register -------- ++#define AT91C_MCI_DTOCYC ((unsigned int) 0x1 << 0) // (MCI) Data Timeout Cycle Number ++#define AT91C_MCI_DTOMUL ((unsigned int) 0x7 << 4) // (MCI) Data Timeout Multiplier ++#define AT91C_MCI_DTOMUL_1 ((unsigned int) 0x0 << 4) // (MCI) DTOCYC x 1 ++#define AT91C_MCI_DTOMUL_16 ((unsigned int) 0x1 << 4) // (MCI) DTOCYC x 16 ++#define AT91C_MCI_DTOMUL_128 ((unsigned int) 0x2 << 4) // (MCI) DTOCYC x 128 ++#define AT91C_MCI_DTOMUL_256 ((unsigned int) 0x3 << 4) // (MCI) DTOCYC x 256 ++#define AT91C_MCI_DTOMUL_1024 ((unsigned int) 0x4 << 4) // (MCI) DTOCYC x 1024 ++#define AT91C_MCI_DTOMUL_4096 ((unsigned int) 0x5 << 4) // (MCI) DTOCYC x 4096 ++#define AT91C_MCI_DTOMUL_65536 ((unsigned int) 0x6 << 4) // (MCI) DTOCYC x 65536 ++#define AT91C_MCI_DTOMUL_1048576 ((unsigned int) 0x7 << 4) // (MCI) DTOCYC x 1048576 ++// -------- MCI_SDCR : (MCI Offset: 0xc) MCI SD Card Register -------- ++#define AT91C_MCI_SCDSEL ((unsigned int) 0x1 << 0) // (MCI) SD Card Selector ++#define AT91C_MCI_SCDBUS ((unsigned int) 0x1 << 7) // (MCI) SD Card Bus Width ++// -------- MCI_CMDR : (MCI Offset: 0x14) MCI Command Register -------- ++#define AT91C_MCI_CMDNB ((unsigned int) 0x1F << 0) // (MCI) Command Number ++#define AT91C_MCI_RSPTYP ((unsigned int) 0x3 << 6) // (MCI) Response Type ++#define AT91C_MCI_RSPTYP_NO ((unsigned int) 0x0 << 6) // (MCI) No response ++#define AT91C_MCI_RSPTYP_48 ((unsigned int) 0x1 << 6) // (MCI) 48-bit response ++#define AT91C_MCI_RSPTYP_136 ((unsigned int) 0x2 << 6) // (MCI) 136-bit response ++#define AT91C_MCI_SPCMD ((unsigned int) 0x7 << 8) // (MCI) Special CMD ++#define AT91C_MCI_SPCMD_NONE ((unsigned int) 0x0 << 8) // (MCI) Not a special CMD ++#define AT91C_MCI_SPCMD_INIT ((unsigned int) 0x1 << 8) // (MCI) Initialization CMD ++#define AT91C_MCI_SPCMD_SYNC ((unsigned int) 0x2 << 8) // (MCI) Synchronized CMD ++#define AT91C_MCI_SPCMD_IT_CMD ((unsigned int) 0x4 << 8) // (MCI) Interrupt command ++#define AT91C_MCI_SPCMD_IT_REP ((unsigned int) 0x5 << 8) // (MCI) Interrupt response ++#define AT91C_MCI_OPDCMD ((unsigned int) 0x1 << 11) // (MCI) Open Drain Command ++#define AT91C_MCI_MAXLAT ((unsigned int) 0x1 << 12) // (MCI) Maximum Latency for Command to respond ++#define AT91C_MCI_TRCMD ((unsigned int) 0x3 << 16) // (MCI) Transfer CMD ++#define AT91C_MCI_TRCMD_NO ((unsigned int) 0x0 << 16) // (MCI) No transfer ++#define AT91C_MCI_TRCMD_START ((unsigned int) 0x1 << 16) // (MCI) Start transfer ++#define AT91C_MCI_TRCMD_STOP ((unsigned int) 0x2 << 16) // (MCI) Stop transfer ++#define AT91C_MCI_TRDIR ((unsigned int) 0x1 << 18) // (MCI) Transfer Direction ++#define AT91C_MCI_TRTYP ((unsigned int) 0x3 << 19) // (MCI) Transfer Type ++#define AT91C_MCI_TRTYP_BLOCK ((unsigned int) 0x0 << 19) // (MCI) Block Transfer type ++#define AT91C_MCI_TRTYP_MULTIPLE ((unsigned int) 0x1 << 19) // (MCI) Multiple Block transfer type ++#define AT91C_MCI_TRTYP_STREAM ((unsigned int) 0x2 << 19) // (MCI) Stream transfer type ++// -------- MCI_SR : (MCI Offset: 0x40) MCI Status Register -------- ++#define AT91C_MCI_CMDRDY ((unsigned int) 0x1 << 0) // (MCI) Command Ready flag ++#define AT91C_MCI_RXRDY ((unsigned int) 0x1 << 1) // (MCI) RX Ready flag ++#define AT91C_MCI_TXRDY ((unsigned int) 0x1 << 2) // (MCI) TX Ready flag ++#define AT91C_MCI_BLKE ((unsigned int) 0x1 << 3) // (MCI) Data Block Transfer Ended flag ++#define AT91C_MCI_DTIP ((unsigned int) 0x1 << 4) // (MCI) Data Transfer in Progress flag ++#define AT91C_MCI_NOTBUSY ((unsigned int) 0x1 << 5) // (MCI) Data Line Not Busy flag ++#define AT91C_MCI_ENDRX ((unsigned int) 0x1 << 6) // (MCI) End of RX Buffer flag ++#define AT91C_MCI_ENDTX ((unsigned int) 0x1 << 7) // (MCI) End of TX Buffer flag ++#define AT91C_MCI_RXBUFF ((unsigned int) 0x1 << 14) // (MCI) RX Buffer Full flag ++#define AT91C_MCI_TXBUFE ((unsigned int) 0x1 << 15) // (MCI) TX Buffer Empty flag ++#define AT91C_MCI_RINDE ((unsigned int) 0x1 << 16) // (MCI) Response Index Error flag ++#define AT91C_MCI_RDIRE ((unsigned int) 0x1 << 17) // (MCI) Response Direction Error flag ++#define AT91C_MCI_RCRCE ((unsigned int) 0x1 << 18) // (MCI) Response CRC Error flag ++#define AT91C_MCI_RENDE ((unsigned int) 0x1 << 19) // (MCI) Response End Bit Error flag ++#define AT91C_MCI_RTOE ((unsigned int) 0x1 << 20) // (MCI) Response Time-out Error flag ++#define AT91C_MCI_DCRCE ((unsigned int) 0x1 << 21) // (MCI) data CRC Error flag ++#define AT91C_MCI_DTOE ((unsigned int) 0x1 << 22) // (MCI) Data timeout Error flag ++#define AT91C_MCI_OVRE ((unsigned int) 0x1 << 30) // (MCI) Overrun flag ++#define AT91C_MCI_UNRE ((unsigned int) 0x1 << 31) // (MCI) Underrun flag ++// -------- MCI_IER : (MCI Offset: 0x44) MCI Interrupt Enable Register -------- ++// -------- MCI_IDR : (MCI Offset: 0x48) MCI Interrupt Disable Register -------- ++// -------- MCI_IMR : (MCI Offset: 0x4c) MCI Interrupt Mask Register -------- ++ ++#endif +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-at91rm9200/AT91RM9200_SSC.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,129 @@ ++// ---------------------------------------------------------------------------- ++// ATMEL Microcontroller Software Support - ROUSSET - ++// ---------------------------------------------------------------------------- ++// The software is delivered "AS IS" without warranty or condition of any ++// kind, either express, implied or statutory. This includes without ++// limitation any warranty or condition with respect to merchantability or ++// fitness for any particular purpose, or against the infringements of ++// intellectual property rights of others. ++// ---------------------------------------------------------------------------- ++// File Name : AT91RM9200.h ++// Object : AT91RM9200 / SSC definitions ++// Generated : AT91 SW Application Group 12/03/2002 (10:48:02) ++// ++// ---------------------------------------------------------------------------- ++ ++#ifndef AT91RM9200_SSC_H ++#define AT91RM9200_SSC_H ++ ++// ***************************************************************************** ++// SOFTWARE API DEFINITION FOR Synchronous Serial Controller Interface ++// ***************************************************************************** ++#ifndef __ASSEMBLY__ ++ ++typedef struct _AT91S_SSC { ++ AT91_REG SSC_CR; // Control Register ++ AT91_REG SSC_CMR; // Clock Mode Register ++ AT91_REG Reserved0[2]; // ++ AT91_REG SSC_RCMR; // Receive Clock ModeRegister ++ AT91_REG SSC_RFMR; // Receive Frame Mode Register ++ AT91_REG SSC_TCMR; // Transmit Clock Mode Register ++ AT91_REG SSC_TFMR; // Transmit Frame Mode Register ++ AT91_REG SSC_RHR; // Receive Holding Register ++ AT91_REG SSC_THR; // Transmit Holding Register ++ AT91_REG Reserved1[2]; // ++ AT91_REG SSC_RSHR; // Receive Sync Holding Register ++ AT91_REG SSC_TSHR; // Transmit Sync Holding Register ++ AT91_REG SSC_RC0R; // Receive Compare 0 Register ++ AT91_REG SSC_RC1R; // Receive Compare 1 Register ++ AT91_REG SSC_SR; // Status Register ++ AT91_REG SSC_IER; // Interrupt Enable Register ++ AT91_REG SSC_IDR; // Interrupt Disable Register ++ AT91_REG SSC_IMR; // Interrupt Mask Register ++ AT91_REG Reserved2[44]; // ++ AT91_REG SSC_RPR; // Receive Pointer Register ++ AT91_REG SSC_RCR; // Receive Counter Register ++ AT91_REG SSC_TPR; // Transmit Pointer Register ++ AT91_REG SSC_TCR; // Transmit Counter Register ++ AT91_REG SSC_RNPR; // Receive Next Pointer Register ++ AT91_REG SSC_RNCR; // Receive Next Counter Register ++ AT91_REG SSC_TNPR; // Transmit Next Pointer Register ++ AT91_REG SSC_TNCR; // Transmit Next Counter Register ++ AT91_REG SSC_PTCR; // PDC Transfer Control Register ++ AT91_REG SSC_PTSR; // PDC Transfer Status Register ++} AT91S_SSC, *AT91PS_SSC; ++ ++#endif ++ ++// -------- SSC_CR : (SSC Offset: 0x0) SSC Control Register -------- ++#define AT91C_SSC_RXEN ( 0x1 << 0) // (SSC) Receive Enable ++#define AT91C_SSC_RXDIS ( 0x1 << 1) // (SSC) Receive Disable ++#define AT91C_SSC_TXEN ( 0x1 << 8) // (SSC) Transmit Enable ++#define AT91C_SSC_TXDIS ( 0x1 << 9) // (SSC) Transmit Disable ++#define AT91C_SSC_SWRST ( 0x1 << 15) // (SSC) Software Reset ++// -------- SSC_RCMR : (SSC Offset: 0x10) SSC Receive Clock Mode Register -------- ++#define AT91C_SSC_CKS ( 0x3 << 0) // (SSC) Receive/Transmit Clock Selection ++#define AT91C_SSC_CKS_DIV ( 0x0) // (SSC) Divided Clock ++#define AT91C_SSC_CKS_TK ( 0x1) // (SSC) TK Clock signal ++#define AT91C_SSC_CKS_RK ( 0x2) // (SSC) RK pin ++#define AT91C_SSC_CKO ( 0x7 << 2) // (SSC) Receive/Transmit Clock Output Mode Selection ++#define AT91C_SSC_CKO_NONE ( 0x0 << 2) // (SSC) Receive/Transmit Clock Output Mode: None RK pin: Input-only ++#define AT91C_SSC_CKO_CONTINOUS ( 0x1 << 2) // (SSC) Continuous Receive/Transmit Clock RK pin: Output ++#define AT91C_SSC_CKO_DATA_TX ( 0x2 << 2) // (SSC) Receive/Transmit Clock only during data transfers RK pin: Output ++#define AT91C_SSC_CKI ( 0x1 << 5) // (SSC) Receive/Transmit Clock Inversion ++#define AT91C_SSC_CKG ( 0x3 << 6) // (SSC) Receive/Transmit Clock Gating Selection ++#define AT91C_SSC_CKG_NONE ( 0x0 << 6) // (SSC) Receive/Transmit Clock Gating: None, continuous clock ++#define AT91C_SSC_CKG_LOW ( 0x1 << 6) // (SSC) Receive/Transmit Clock enabled only if RF Low ++#define AT91C_SSC_CKG_HIGH ( 0x2 << 6) // (SSC) Receive/Transmit Clock enabled only if RF High ++#define AT91C_SSC_START ( 0xF << 8) // (SSC) Receive/Transmit Start Selection ++#define AT91C_SSC_START_CONTINOUS ( 0x0 << 8) // (SSC) Continuous, as soon as the receiver is enabled, and immediately after the end of transfer of the previous data. ++#define AT91C_SSC_START_TX ( 0x1 << 8) // (SSC) Transmit/Receive start ++#define AT91C_SSC_START_LOW_RF ( 0x2 << 8) // (SSC) Detection of a low level on RF input ++#define AT91C_SSC_START_HIGH_RF ( 0x3 << 8) // (SSC) Detection of a high level on RF input ++#define AT91C_SSC_START_FALL_RF ( 0x4 << 8) // (SSC) Detection of a falling edge on RF input ++#define AT91C_SSC_START_RISE_RF ( 0x5 << 8) // (SSC) Detection of a rising edge on RF input ++#define AT91C_SSC_START_LEVEL_RF ( 0x6 << 8) // (SSC) Detection of any level change on RF input ++#define AT91C_SSC_START_EDGE_RF ( 0x7 << 8) // (SSC) Detection of any edge on RF input ++#define AT91C_SSC_START_0 ( 0x8 << 8) // (SSC) Compare 0 ++#define AT91C_SSC_STOP ( 0x1 << 12) // (SSC) Receive Stop Selection ++#define AT91C_SSC_STTOUT ( 0x1 << 15) // (SSC) Receive/Transmit Start Output Selection ++#define AT91C_SSC_STTDLY ( 0xFF << 16) // (SSC) Receive/Transmit Start Delay ++#define AT91C_SSC_PERIOD ( 0xFF << 24) // (SSC) Receive/Transmit Period Divider Selection ++// -------- SSC_RFMR : (SSC Offset: 0x14) SSC Receive Frame Mode Register -------- ++#define AT91C_SSC_DATLEN ( 0x1F << 0) // (SSC) Data Length ++#define AT91C_SSC_LOOP ( 0x1 << 5) // (SSC) Loop Mode ++#define AT91C_SSC_MSBF ( 0x1 << 7) // (SSC) Most Significant Bit First ++#define AT91C_SSC_DATNB ( 0xF << 8) // (SSC) Data Number per Frame ++#define AT91C_SSC_FSLEN ( 0xF << 16) // (SSC) Receive/Transmit Frame Sync length ++#define AT91C_SSC_FSOS ( 0x7 << 20) // (SSC) Receive/Transmit Frame Sync Output Selection ++#define AT91C_SSC_FSOS_NONE ( 0x0 << 20) // (SSC) Selected Receive/Transmit Frame Sync Signal: None RK pin Input-only ++#define AT91C_SSC_FSOS_NEGATIVE ( 0x1 << 20) // (SSC) Selected Receive/Transmit Frame Sync Signal: Negative Pulse ++#define AT91C_SSC_FSOS_POSITIVE ( 0x2 << 20) // (SSC) Selected Receive/Transmit Frame Sync Signal: Positive Pulse ++#define AT91C_SSC_FSOS_LOW ( 0x3 << 20) // (SSC) Selected Receive/Transmit Frame Sync Signal: Driver Low during data transfer ++#define AT91C_SSC_FSOS_HIGH ( 0x4 << 20) // (SSC) Selected Receive/Transmit Frame Sync Signal: Driver High during data transfer ++#define AT91C_SSC_FSOS_TOGGLE ( 0x5 << 20) // (SSC) Selected Receive/Transmit Frame Sync Signal: Toggling at each start of data transfer ++#define AT91C_SSC_FSEDGE ( 0x1 << 24) // (SSC) Frame Sync Edge Detection ++// -------- SSC_TCMR : (SSC Offset: 0x18) SSC Transmit Clock Mode Register -------- ++// -------- SSC_TFMR : (SSC Offset: 0x1c) SSC Transmit Frame Mode Register -------- ++#define AT91C_SSC_DATDEF ( 0x1 << 5) // (SSC) Data Default Value ++#define AT91C_SSC_FSDEN ( 0x1 << 23) // (SSC) Frame Sync Data Enable ++// -------- SSC_SR : (SSC Offset: 0x40) SSC Status Register -------- ++#define AT91C_SSC_TXRDY ( 0x1 << 0) // (SSC) Transmit Ready ++#define AT91C_SSC_TXEMPTY ( 0x1 << 1) // (SSC) Transmit Empty ++#define AT91C_SSC_ENDTX ( 0x1 << 2) // (SSC) End Of Transmission ++#define AT91C_SSC_TXBUFE ( 0x1 << 3) // (SSC) Transmit Buffer Empty ++#define AT91C_SSC_RXRDY ( 0x1 << 4) // (SSC) Receive Ready ++#define AT91C_SSC_OVRUN ( 0x1 << 5) // (SSC) Receive Overrun ++#define AT91C_SSC_ENDRX ( 0x1 << 6) // (SSC) End of Reception ++#define AT91C_SSC_RXBUFF ( 0x1 << 7) // (SSC) Receive Buffer Full ++#define AT91C_SSC_CP0 ( 0x1 << 8) // (SSC) Compare 0 ++#define AT91C_SSC_CP1 ( 0x1 << 9) // (SSC) Compare 1 ++#define AT91C_SSC_TXSYN ( 0x1 << 10) // (SSC) Transmit Sync ++#define AT91C_SSC_RXSYN ( 0x1 << 11) // (SSC) Receive Sync ++#define AT91C_SSC_TXENA ( 0x1 << 16) // (SSC) Transmit Enable ++#define AT91C_SSC_RXENA ( 0x1 << 17) // (SSC) Receive Enable ++// -------- SSC_IER : (SSC Offset: 0x44) SSC Interrupt Enable Register -------- ++// -------- SSC_IDR : (SSC Offset: 0x48) SSC Interrupt Disable Register -------- ++// -------- SSC_IMR : (SSC Offset: 0x4c) SSC Interrupt Mask Register -------- ++ ++#endif +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-at91rm9200/AT91RM9200_TC.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,165 @@ ++// ---------------------------------------------------------------------------- ++// ATMEL Microcontroller Software Support - ROUSSET - ++// ---------------------------------------------------------------------------- ++// The software is delivered "AS IS" without warranty or condition of any ++// kind, either express, implied or statutory. This includes without ++// limitation any warranty or condition with respect to merchantability or ++// fitness for any particular purpose, or against the infringements of ++// intellectual property rights of others. ++// ---------------------------------------------------------------------------- ++// File Name : AT91RM9200.h ++// Object : AT91RM9200 definitions ++// Generated : AT91 SW Application Group 12/03/2002 (10:48:02) ++// ++// ---------------------------------------------------------------------------- ++ ++#ifndef AT91RM9200_TC_H ++#define AT91RM9200_TC_H ++ ++// ***************************************************************************** ++// SOFTWARE API DEFINITION FOR Timer Counter Channel Interface ++// ***************************************************************************** ++#ifndef __ASSEMBLY__ ++ ++typedef struct _AT91S_TC { ++ AT91_REG TC_CCR; // Channel Control Register ++ AT91_REG TC_CMR; // Channel Mode Register ++ AT91_REG Reserved0[2]; // ++ AT91_REG TC_CV; // Counter Value ++ AT91_REG TC_RA; // Register A ++ AT91_REG TC_RB; // Register B ++ AT91_REG TC_RC; // Register C ++ AT91_REG TC_SR; // Status Register ++ AT91_REG TC_IER; // Interrupt Enable Register ++ AT91_REG TC_IDR; // Interrupt Disable Register ++ AT91_REG TC_IMR; // Interrupt Mask Register ++} AT91S_TC, *AT91PS_TC; ++ ++typedef struct _AT91S_TCB { ++ AT91S_TC TCB_TC0; // TC Channel 0 ++ AT91_REG Reserved0[4]; // ++ AT91S_TC TCB_TC1; // TC Channel 1 ++ AT91_REG Reserved1[4]; // ++ AT91S_TC TCB_TC2; // TC Channel 2 ++ AT91_REG Reserved2[4]; // ++ AT91_REG TCB_BCR; // TC Block Control Register ++ AT91_REG TCB_BMR; // TC Block Mode Register ++} AT91S_TCB, *AT91PS_TCB; ++ ++#endif ++ ++// -------- TC_CCR : (TC Offset: 0x0) TC Channel Control Register -------- ++#define AT91C_TC_CLKEN ( 0x1 << 0) // (TC) Counter Clock Enable Command ++#define AT91C_TC_CLKDIS ( 0x1 << 1) // (TC) Counter Clock Disable Command ++#define AT91C_TC_SWTRG ( 0x1 << 2) // (TC) Software Trigger Command ++// -------- TC_CMR : (TC Offset: 0x4) TC Channel Mode Register: Capture Mode / Waveform Mode -------- ++#define AT91C_TC_TCCLKS ( 0x7 << 0) // (TC) Clock Selection ++#define AT91C_TC_TIMER_DIV1_CLOCK ( 0x0 << 0) // (TC) MCK/2 ++#define AT91C_TC_TIMER_DIV2_CLOCK ( 0x1 << 0) // (TC) MCK/8 ++#define AT91C_TC_TIMER_DIV3_CLOCK ( 0x2 << 0) // (TC) MCK/32 ++#define AT91C_TC_TIMER_DIV4_CLOCK ( 0x3 << 0) // (TC) MCK/128 ++#define AT91C_TC_TIMER_DIV5_CLOCK ( 0x4 << 0) // (TC) MCK/256 = SLOW CLOCK ++#define AT91C_TC_TIMER_XC0 ( 0x5 << 0) // (TC) XC0 ++#define AT91C_TC_TIMER_XC1 ( 0x6 << 0) // (TC) XC1 ++#define AT91C_TC_TIMER_XC2 ( 0x7 << 0) // (TC) XC2 ++#define AT91C_TC_CLKI ( 0x1 << 3) // (TC) Clock Invert ++#define AT91C_TC_BURST ( 0x3 << 4) // (TC) Burst Signal Selection ++#define AT91C_TC_CPCSTOP ( 0x1 << 6) // (TC) Counter Clock Stopped with RC Compare ++#define AT91C_TC_CPCDIS ( 0x1 << 7) // (TC) Counter Clock Disable with RC Compare ++#define AT91C_TC_EEVTEDG ( 0x3 << 8) // (TC) External Event Edge Selection ++#define AT91C_TC_EEVTEDG_NONE ( 0x0 << 8) // (TC) Edge: None ++#define AT91C_TC_EEVTEDG_RISING ( 0x1 << 8) // (TC) Edge: rising edge ++#define AT91C_TC_EEVTEDG_FALLING ( 0x2 << 8) // (TC) Edge: falling edge ++#define AT91C_TC_EEVTEDG_BOTH ( 0x3 << 8) // (TC) Edge: each edge ++#define AT91C_TC_EEVT ( 0x3 << 10) // (TC) External Event Selection ++#define AT91C_TC_EEVT_NONE ( 0x0 << 10) // (TC) Signal selected as external event: TIOB TIOB direction: input ++#define AT91C_TC_EEVT_RISING ( 0x1 << 10) // (TC) Signal selected as external event: XC0 TIOB direction: output ++#define AT91C_TC_EEVT_FALLING ( 0x2 << 10) // (TC) Signal selected as external event: XC1 TIOB direction: output ++#define AT91C_TC_EEVT_BOTH ( 0x3 << 10) // (TC) Signal selected as external event: XC2 TIOB direction: output ++#define AT91C_TC_ENETRG ( 0x1 << 12) // (TC) External Event Trigger enable ++#define AT91C_TC_WAVESEL ( 0x3 << 13) // (TC) Waveform Selection ++#define AT91C_TC_WAVESEL_UP ( 0x0 << 13) // (TC) UP mode without atomatic trigger on RC Compare ++#define AT91C_TC_WAVESEL_UP_AUTO ( 0x1 << 13) // (TC) UP mode with automatic trigger on RC Compare ++#define AT91C_TC_WAVESEL_UPDOWN ( 0x2 << 13) // (TC) UPDOWN mode without automatic trigger on RC Compare ++#define AT91C_TC_WAVESEL_UPDOWN_AUTO ( 0x3 << 13) // (TC) UPDOWN mode with automatic trigger on RC Compare ++#define AT91C_TC_CPCTRG ( 0x1 << 14) // (TC) RC Compare Trigger Enable ++#define AT91C_TC_WAVE ( 0x1 << 15) // (TC) ++#define AT91C_TC_ACPA ( 0x3 << 16) // (TC) RA Compare Effect on TIOA ++#define AT91C_TC_ACPA_NONE ( 0x0 << 16) // (TC) Effect: none ++#define AT91C_TC_ACPA_SET ( 0x1 << 16) // (TC) Effect: set ++#define AT91C_TC_ACPA_CLEAR ( 0x2 << 16) // (TC) Effect: clear ++#define AT91C_TC_ACPA_TOGGLE ( 0x3 << 16) // (TC) Effect: toggle ++#define AT91C_TC_ACPC ( 0x3 << 18) // (TC) RC Compare Effect on TIOA ++#define AT91C_TC_ACPC_NONE ( 0x0 << 18) // (TC) Effect: none ++#define AT91C_TC_ACPC_SET ( 0x1 << 18) // (TC) Effect: set ++#define AT91C_TC_ACPC_CLEAR ( 0x2 << 18) // (TC) Effect: clear ++#define AT91C_TC_ACPC_TOGGLE ( 0x3 << 18) // (TC) Effect: toggle ++#define AT91C_TC_AEEVT ( 0x3 << 20) // (TC) External Event Effect on TIOA ++#define AT91C_TC_AEEVT_NONE ( 0x0 << 20) // (TC) Effect: none ++#define AT91C_TC_AEEVT_SET ( 0x1 << 20) // (TC) Effect: set ++#define AT91C_TC_AEEVT_CLEAR ( 0x2 << 20) // (TC) Effect: clear ++#define AT91C_TC_AEEVT_TOGGLE ( 0x3 << 20) // (TC) Effect: toggle ++#define AT91C_TC_ASWTRG ( 0x3 << 22) // (TC) Software Trigger Effect on TIOA ++#define AT91C_TC_ASWTRG_NONE ( 0x0 << 22) // (TC) Effect: none ++#define AT91C_TC_ASWTRG_SET ( 0x1 << 22) // (TC) Effect: set ++#define AT91C_TC_ASWTRG_CLEAR ( 0x2 << 22) // (TC) Effect: clear ++#define AT91C_TC_ASWTRG_TOGGLE ( 0x3 << 22) // (TC) Effect: toggle ++#define AT91C_TC_BCPB ( 0x3 << 24) // (TC) RB Compare Effect on TIOB ++#define AT91C_TC_BCPB_NONE ( 0x0 << 24) // (TC) Effect: none ++#define AT91C_TC_BCPB_SET ( 0x1 << 24) // (TC) Effect: set ++#define AT91C_TC_BCPB_CLEAR ( 0x2 << 24) // (TC) Effect: clear ++#define AT91C_TC_BCPB_TOGGLE ( 0x3 << 24) // (TC) Effect: toggle ++#define AT91C_TC_BCPC ( 0x3 << 26) // (TC) RC Compare Effect on TIOB ++#define AT91C_TC_BCPC_NONE ( 0x0 << 26) // (TC) Effect: none ++#define AT91C_TC_BCPC_SET ( 0x1 << 26) // (TC) Effect: set ++#define AT91C_TC_BCPC_CLEAR ( 0x2 << 26) // (TC) Effect: clear ++#define AT91C_TC_BCPC_TOGGLE ( 0x3 << 26) // (TC) Effect: toggle ++#define AT91C_TC_BEEVT ( 0x3 << 28) // (TC) External Event Effect on TIOB ++#define AT91C_TC_BEEVT_NONE ( 0x0 << 28) // (TC) Effect: none ++#define AT91C_TC_BEEVT_SET ( 0x1 << 28) // (TC) Effect: set ++#define AT91C_TC_BEEVT_CLEAR ( 0x2 << 28) // (TC) Effect: clear ++#define AT91C_TC_BEEVT_TOGGLE ( 0x3 << 28) // (TC) Effect: toggle ++#define AT91C_TC_BSWTRG ( 0x3 << 30) // (TC) Software Trigger Effect on TIOB ++#define AT91C_TC_BSWTRG_NONE ( 0x0 << 30) // (TC) Effect: none ++#define AT91C_TC_BSWTRG_SET ( 0x1 << 30) // (TC) Effect: set ++#define AT91C_TC_BSWTRG_CLEAR ( 0x2 << 30) // (TC) Effect: clear ++#define AT91C_TC_BSWTRG_TOGGLE ( 0x3 << 30) // (TC) Effect: toggle ++// -------- TC_SR : (TC Offset: 0x20) TC Channel Status Register -------- ++#define AT91C_TC_COVFS ( 0x1 << 0) // (TC) Counter Overflow ++#define AT91C_TC_LOVRS ( 0x1 << 1) // (TC) Load Overrun ++#define AT91C_TC_CPAS ( 0x1 << 2) // (TC) RA Compare ++#define AT91C_TC_CPBS ( 0x1 << 3) // (TC) RB Compare ++#define AT91C_TC_CPCS ( 0x1 << 4) // (TC) RC Compare ++#define AT91C_TC_LDRAS ( 0x1 << 5) // (TC) RA Loading ++#define AT91C_TC_LDRBS ( 0x1 << 6) // (TC) RB Loading ++#define AT91C_TC_ETRCS ( 0x1 << 7) // (TC) External Trigger ++#define AT91C_TC_ETRGS ( 0x1 << 16) // (TC) Clock Enabling ++#define AT91C_TC_MTIOA ( 0x1 << 17) // (TC) TIOA Mirror ++#define AT91C_TC_MTIOB ( 0x1 << 18) // (TC) TIOA Mirror ++// -------- TC_IER : (TC Offset: 0x24) TC Channel Interrupt Enable Register -------- ++// -------- TC_IDR : (TC Offset: 0x28) TC Channel Interrupt Disable Register -------- ++// -------- TC_IMR : (TC Offset: 0x2c) TC Channel Interrupt Mask Register -------- ++ ++// ***************************************************************************** ++// SOFTWARE API DEFINITION FOR Timer Counter Interface ++// ***************************************************************************** ++// -------- TCB_BCR : (TCB Offset: 0xc0) TC Block Control Register -------- ++#define AT91C_TCB_SYNC ( 0x1 << 0) // (TCB) Synchro Command ++// -------- TCB_BMR : (TCB Offset: 0xc4) TC Block Mode Register -------- ++#define AT91C_TCB_TC0XC0S ( 0x1 << 0) // (TCB) External Clock Signal 0 Selection ++#define AT91C_TCB_TC0XC0S_TCLK0 ( 0x0) // (TCB) TCLK0 connected to XC0 ++#define AT91C_TCB_TC0XC0S_NONE ( 0x1) // (TCB) None signal connected to XC0 ++#define AT91C_TCB_TC0XC0S_TIOA1 ( 0x2) // (TCB) TIOA1 connected to XC0 ++#define AT91C_TCB_TC0XC0S_TIOA2 ( 0x3) // (TCB) TIOA2 connected to XC0 ++#define AT91C_TCB_TC1XC1S ( 0x1 << 2) // (TCB) External Clock Signal 1 Selection ++#define AT91C_TCB_TC1XC1S_TCLK1 ( 0x0 << 2) // (TCB) TCLK1 connected to XC1 ++#define AT91C_TCB_TC1XC1S_NONE ( 0x1 << 2) // (TCB) None signal connected to XC1 ++#define AT91C_TCB_TC1XC1S_TIOA0 ( 0x2 << 2) // (TCB) TIOA0 connected to XC1 ++#define AT91C_TCB_TC1XC1S_TIOA2 ( 0x3 << 2) // (TCB) TIOA2 connected to XC1 ++#define AT91C_TCB_TC2XC2S ( 0x1 << 4) // (TCB) External Clock Signal 2 Selection ++#define AT91C_TCB_TC2XC2S_TCLK2 ( 0x0 << 4) // (TCB) TCLK2 connected to XC2 ++#define AT91C_TCB_TC2XC2S_NONE ( 0x1 << 4) // (TCB) None signal connected to XC2 ++#define AT91C_TCB_TC2XC2S_TIOA0 ( 0x2 << 4) // (TCB) TIOA0 connected to XC2 ++#define AT91C_TCB_TC2XC2S_TIOA2 ( 0x3 << 4) // (TCB) TIOA2 connected to XC2 ++ ++#endif +--- linux-2.4.25/include/asm-arm/arch-at91rm9200/at91rm9200dk.h~2.4.25-vrs2.patch 2003-08-25 13:44:43.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-at91rm9200/at91rm9200dk.h 2004-03-31 17:15:09.000000000 +0200 +@@ -68,6 +68,7 @@ + #define AT91_SMR_IRQ5 (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Advanced Interrupt Controller (IRQ5) + #define AT91_SMR_IRQ6 (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Advanced Interrupt Controller (IRQ6) + ++#define AT91C_CONSOLE_DEFAULT_BAUDRATE 115200 /* default serial console baud-rate */ + + /* + * Serial port configuration. +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-at91rm9200/csb337.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,82 @@ ++/* ++ * linux/include/asm-arm/arch-at91rm9200/csb337.h ++ * ++ * Copyright (c) 2003 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. ++ * ++ */ ++ ++#ifndef __ASM_ARCH_HARDWARE_CSB337_H ++#define __ASM_ARCH_HARDWARE_CSB337_H ++ ++ ++/* AT91RM92000 clocks on CSB337 */ ++#define AT91C_MAIN_CLOCK 184320000 ++#define AT91C_MASTER_CLOCK 46080000 /* peripheral clock (AT91C_MAIN_CLOCK / 4) */ ++#define AT91C_SLOW_CLOCK 32768 /* slow clock */ ++ ++ ++/* FLASH */ ++#define AT91_FLASH_BASE 0x10000000 // NCS0: Flash physical base address ++ ++/* SDRAM */ ++#define AT91_SDRAM_BASE 0x20000000 // NCS1: SDRAM physical base address ++ ++/* SmartMedia */ ++#define AT91_SMARTMEDIA_BASE 0x40000000 // NCS3: Smartmedia physical base address ++ ++/* Multi-Master Memory controller */ ++#define AT91_UHP_BASE 0x00300000 // USB Host controller ++ ++ ++/* Peripheral interrupt configuration */ ++#define AT91_SMR_FIQ (AT91C_AIC_PRIOR_HIGHEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Advanced Interrupt Controller (FIQ) ++#define AT91_SMR_SYS (AT91C_AIC_PRIOR_HIGHEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // System Peripheral ++#define AT91_SMR_PIOA (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Parallel IO Controller A ++#define AT91_SMR_PIOB (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Parallel IO Controller B ++#define AT91_SMR_PIOC (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Parallel IO Controller C ++#define AT91_SMR_PIOD (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Parallel IO Controller D ++#define AT91_SMR_US0 (AT91C_AIC_PRIOR_6 | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // USART 0 ++#define AT91_SMR_US1 (AT91C_AIC_PRIOR_6 | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // USART 1 ++#define AT91_SMR_US2 (AT91C_AIC_PRIOR_6 | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // USART 2 ++#define AT91_SMR_US3 (AT91C_AIC_PRIOR_6 | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // USART 3 ++#define AT91_SMR_MCI (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Multimedia Card Interface ++#define AT91_SMR_UDP (AT91C_AIC_PRIOR_4 | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // USB Device Port ++#define AT91_SMR_TWI (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Two-Wire Interface ++#define AT91_SMR_SPI (AT91C_AIC_PRIOR_6 | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Serial Peripheral Interface ++#define AT91_SMR_SSC0 (AT91C_AIC_PRIOR_5 | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Serial Synchronous Controller 0 ++#define AT91_SMR_SSC1 (AT91C_AIC_PRIOR_5 | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Serial Synchronous Controller 1 ++#define AT91_SMR_SSC2 (AT91C_AIC_PRIOR_5 | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Serial Synchronous Controller 2 ++#define AT91_SMR_TC0 (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Timer Counter 0 ++#define AT91_SMR_TC1 (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Timer Counter 1 ++#define AT91_SMR_TC2 (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Timer Counter 2 ++#define AT91_SMR_TC3 (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Timer Counter 3 ++#define AT91_SMR_TC4 (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Timer Counter 4 ++#define AT91_SMR_TC5 (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Timer Counter 5 ++#define AT91_SMR_UHP (AT91C_AIC_PRIOR_3 | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // USB Host port ++#define AT91_SMR_EMAC (AT91C_AIC_PRIOR_3 | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Ethernet MAC ++#define AT91_SMR_IRQ0 (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Advanced Interrupt Controller (IRQ0) ++#define AT91_SMR_IRQ1 (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Advanced Interrupt Controller (IRQ1) ++#define AT91_SMR_IRQ2 (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Advanced Interrupt Controller (IRQ2) ++#define AT91_SMR_IRQ3 (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Advanced Interrupt Controller (IRQ3) ++#define AT91_SMR_IRQ4 (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Advanced Interrupt Controller (IRQ4) ++#define AT91_SMR_IRQ5 (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Advanced Interrupt Controller (IRQ5) ++#define AT91_SMR_IRQ6 (AT91C_AIC_PRIOR_LOWEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE) // Advanced Interrupt Controller (IRQ6) ++ ++ ++#define AT91C_CONSOLE_DEFAULT_BAUDRATE 38400 ++ ++/* ++ * Serial port configuration. ++ * 0 .. 3 = USART0 .. USART3 ++ * 4 = DBGU ++ */ ++#define AT91C_UART_MAP { 4, 1, -1, -1, -1 } /* ttyS0, ..., ttyS4 */ ++#define AT91C_CONSOLE 0 /* ttyS0 */ ++ ++#endif +--- linux-2.4.25/include/asm-arm/arch-at91rm9200/hardware.h~2.4.25-vrs2.patch 2003-08-25 13:44:43.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-at91rm9200/hardware.h 2004-03-31 17:15:09.000000000 +0200 +@@ -82,5 +82,8 @@ + #include <asm/arch/at91rm9200dk.h> + #endif + ++#ifdef CONFIG_MACH_CSB337 ++#include <asm/arch/csb337.h> ++#endif + + #endif +--- linux-2.4.25/include/asm-arm/arch-at91rm9200/pio.h~2.4.25-vrs2.patch 2003-08-25 13:44:43.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-at91rm9200/pio.h 2004-03-31 17:15:09.000000000 +0200 +@@ -66,6 +66,18 @@ + } + + /* ++ * Configure interrupt from Ethernet PHY. ++ */ ++static inline void AT91_CfgPIO_EMAC_PHY(void) { ++ AT91_SYS->PMC_PCER = 1 << AT91C_ID_PIOC; /* enable peripheral clock */ ++#ifdef CONFIG_MACH_CSB337 ++ AT91_SYS->PIOC_ODR = AT91C_PIO_PC2; ++#else ++ AT91_SYS->PIOC_ODR = AT91C_PIO_PC4; ++#endif ++} ++ ++/* + * Enable the Two-Wire interface. + */ + static inline void AT91_CfgPIO_TWI(void) { +--- linux-2.4.25/include/asm-arm/arch-at91rm9200/time.h~2.4.25-vrs2.patch 2003-08-25 13:44:43.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-at91rm9200/time.h 2004-03-31 17:15:09.000000000 +0200 +@@ -27,6 +27,21 @@ + extern unsigned long (*gettimeoffset)(void); + + /* ++ * The ST_CRTR is updated asynchronously to the master clock. It is therefore ++ * necessary to read it twice (with the same value) to ensure accuracy. ++ */ ++static inline unsigned long read_CRTR(void) { ++ unsigned long x1, x2; ++ ++ do { ++ x1 = AT91_SYS->ST_CRTR; ++ x2 = AT91_SYS->ST_CRTR; ++ } while (x1 != x2); ++ ++ return x1; ++} ++ ++/* + * Returns number of microseconds since last timer interrupt. Note that interrupts + * will have been disabled by do_gettimeofday() + * 'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy. +@@ -36,7 +51,7 @@ + { + unsigned long elapsed; + +- elapsed = (AT91_SYS->ST_CRTR - AT91_SYS->ST_RTAR) & AT91C_ST_ALMV; ++ elapsed = (read_CRTR() - AT91_SYS->ST_RTAR) & AT91C_ST_ALMV; + + return (unsigned long)(elapsed * tick) / LATCH; + } +@@ -52,7 +67,7 @@ + + AT91_SYS->ST_RTAR = (AT91_SYS->ST_RTAR + LATCH) & AT91C_ST_ALMV; + +- } while (((AT91_SYS->ST_CRTR - AT91_SYS->ST_RTAR) & AT91C_ST_ALMV) >= LATCH); ++ } while (((read_CRTR() - AT91_SYS->ST_RTAR) & AT91C_ST_ALMV) >= LATCH); + + do_profile(regs); + } +--- linux-2.4.25/include/asm-arm/arch-clps711x/system.h~2.4.25-vrs2.patch 2003-06-13 16:51:38.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-clps711x/system.h 2004-03-31 17:15:09.000000000 +0200 +@@ -28,8 +28,8 @@ + { + clps_writel(1, HALT); + __asm__ __volatile__( +- "mov r0, r0 +- mov r0, r0"); ++ "mov r0, r0\n\t" ++ "mov r0, r0"); + } + + static inline void arch_reset(char mode) +--- linux-2.4.25/include/asm-arm/arch-integrator/uncompress.h~2.4.25-vrs2.patch 2002-08-03 02:39:45.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-integrator/uncompress.h 2004-03-31 17:15:09.000000000 +0200 +@@ -18,6 +18,8 @@ + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + ++#include <asm/hardware/serial_amba.h> ++ + #define AMBA_UART_DR (*(volatile unsigned char *)0x16000000) + #define AMBA_UART_LCRH (*(volatile unsigned char *)0x16000008) + #define AMBA_UART_LCRM (*(volatile unsigned char *)0x1600000c) +@@ -30,21 +32,25 @@ + */ + static void puts(const char *s) + { ++ /* Do nothing if the UART is not enabled. */ ++ if (!(AMBA_UART_CR & AMBA_UARTCR_UARTEN)) ++ return; ++ + while (*s) { +- while (AMBA_UART_FR & (1 << 5)) ++ while (AMBA_UART_FR & AMBA_UARTFR_TXFF) + barrier(); + + AMBA_UART_DR = *s; + + if (*s == '\n') { +- while (AMBA_UART_FR & (1 << 5)) ++ while (AMBA_UART_FR & AMBA_UARTFR_TXFF) + barrier(); + + AMBA_UART_DR = '\r'; + } + s++; + } +- while (AMBA_UART_FR & (1 << 3)); ++ while (AMBA_UART_FR & AMBA_UARTFR_BUSY); + } + + /* +--- linux-2.4.25/include/asm-arm/arch-riscstation/system.h~2.4.25-vrs2.patch 2003-08-25 13:44:43.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-riscstation/system.h 2004-03-31 17:15:09.000000000 +0200 +@@ -1,5 +1,5 @@ + /* +- * linux/include/asm-arm/arch-rpc/system.h ++ * linux/include/asm-arm/arch-riscstation/system.h + * + * Copyright (C) 1996-1999 Russell King. + * +@@ -18,7 +18,7 @@ + + static inline void arch_reset(char mode) + { +- iomd_writeb(0, IOMD_ROMCR0); ++ iomd_writeb(0x40, IOMD_ROMCR0); + + /* + * Jump into the ROM +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-s3c2410/S3C2410-clock.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,76 @@ ++/* linux/include/asm-arm/arch-s3c2410/S3C2410-clock.h ++ * ++ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk> ++ * http://www.simtec.co.uk/products/SWLINUX/ ++ * ++ * 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. ++ * ++ * S3C2410 clock register definitions ++ * ++ * Changelog: ++ * 19-06-2003 BJD Created file ++ */ ++ ++#ifndef ASMARM_ARCH_S3C2410_CLOCK_H ++#define ASMARM_ARCH_S3C2410_CLOCK_H ++ ++#define S3C2410_CLKREG(x) ((x) + S3C2410_VA_CLKPWR) ++ ++#define S3C2410_PLLVAL(_m,_p,_s) ((_m) << 12 | ((_p) << 4) | ((_s))) ++ ++#define S3C2410_LOCKTIME S3C2410_CLKREG(0x00) ++#define S3C2410_MPLLCON S3C2410_CLKREG(0x04) ++#define S3C2410_UPLLCON S3C2410_CLKREG(0x08) ++#define S3C2410_CLKCON S3C2410_CLKREG(0x0C) ++#define S3C2410_CLKSLOW S3C2410_CLKREG(0x10) ++#define S3C2410_CLKDIVN S3C2410_CLKREG(0x14) ++ ++#define S3C2410_PLLCON_MDIVSHIFT 12 ++#define S3C2410_PLLCON_PDIVSHIFT 4 ++#define S3C2410_PLLCON_SDIVSHIFT 0 ++#define S3C2410_PLLCON_MDIVMASK ((1<<(1+(19-12)))-1) ++#define S3C2410_PLLCON_PDIVMASK ((1<<5)-1) ++#define S3C2410_PLLCON_SDIVMASK 3 ++ ++/* DCLKCON register addresses in gpio.h */ ++ ++#define S3C2410_DCLKCON_DCLK0EN (1<<0) ++#define S3C2410_DCLKCON_DCLK0_PCLK (0<<1) ++#define S3C2410_DCLKCON_DCLK0_UCLK (1<<1) ++#define S3C2410_DCLKCON_DCLK0_DIV(x) (((x) - 1 )<<4) ++#define S3C2410_DCLKCON_DCLK0_CMP(x) (((x) - 1 )<<8) ++ ++#define S3C2410_DCLKCON_DCLK1EN (1<<16) ++#define S3C2410_DCLKCON_DCLK1_PCLK (0<<17) ++#define S3C2410_DCLKCON_DCLK1_UCLK (1<<17) ++#define S3C2410_DCLKCON_DCLK1_DIV(x) (((x) - 1) <<20) ++ ++#define S3C2410_CLKDIVN_PDIVN (1<<0) ++#define S3C2410_CLKDIVN_HDIVN (1<<1) ++ ++static inline unsigned int ++s3c2410_get_pll(int pllval, int baseclk) ++{ ++ int mdiv, pdiv, sdiv; ++ ++ mdiv = pllval >> S3C2410_PLLCON_MDIVSHIFT; ++ pdiv = pllval >> S3C2410_PLLCON_PDIVSHIFT; ++ sdiv = pllval >> S3C2410_PLLCON_SDIVSHIFT; ++ ++ mdiv &= S3C2410_PLLCON_MDIVMASK; ++ pdiv &= S3C2410_PLLCON_PDIVMASK; ++ sdiv &= S3C2410_PLLCON_SDIVMASK; ++ ++ return (baseclk * (mdiv + 8)) / ((pdiv + 2) << sdiv); ++} ++ ++#endif /* ASMARM_ARCH_S3C2410_CLOCK_H */ ++ ++ ++ ++ ++ ++ ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-s3c2410/S3C2410-gpio.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,602 @@ ++/* linux/include/asm-arm/arch-s3c2410/S3C2410-gpio.h ++ * ++ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk> ++ * http://www.simtec.co.uk/products/SWLINUX/ ++ * ++ * 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. ++ * ++ * S3C2410 GPIO register definitions ++ * ++ * Changelog: ++ * 19-06-2003 BJD Created file ++ * 23-06-2003 BJD Updated GSTATUS registers ++ */ ++ ++#ifndef ASMARM_ARCH_S3C2410_GPIO_H ++#define ASMARM_ARCH_S3C2410_GPIO_H ++ ++/* configure GPIO ports A..G */ ++ ++#define S3C2410_GPIOREG(x) ((x) + S3C2410_VA_GPIO) ++ ++/* port A - 22bits, zero in bit X makes pin X output ++ * 1 makes port special function, this is default ++*/ ++#define S3C2410_GPACON S3C2410_GPIOREG(0x00) ++#define S3C2410_GPADAT S3C2410_GPIOREG(0x04) ++ ++/* 0x08 and 0x0c are reserved */ ++ ++/* GPB is 10 IO pins, each configured by 2 bits each in GPBCON. ++ * 00 = input, 01 = output, 10=special function, 11=reserved ++ * bit 0,1 = pin 0, 2,3= pin 1... ++ * ++ * CPBUP = pull up resistor control, 1=disabled, 0=enabled ++*/ ++ ++#define S3C2410_GPBCON S3C2410_GPIOREG(0x10) ++#define S3C2410_GPBDAT S3C2410_GPIOREG(0x14) ++#define S3C2410_GPBUP S3C2410_GPIOREG(0x18) ++ ++/* no i/o pin in port b can have value 3! */ ++ ++#define S3C2410_GPB0_INP (0x00 << 0) ++#define S3C2410_GPB0_OUTP (0x01 << 0) ++#define S3C2410_GPB0_TOUT0 (0x02 << 0) ++ ++#define S3C2410_GPB1_INP (0x00 << 2) ++#define S3C2410_GPB1_OUTP (0x01 << 2) ++#define S3C2410_GPB1_TOUT1 (0x02 << 2) ++ ++#define S3C2410_GPB2_INP (0x00 << 4) ++#define S3C2410_GPB2_OUTP (0x01 << 4) ++#define S3C2410_GPB2_TOUT2 (0x02 << 4) ++ ++#define S3C2410_GPB3_INP (0x00 << 6) ++#define S3C2410_GPB3_OUTP (0x01 << 6) ++#define S3C2410_GPB3_TOUT3 (0x02 << 6) ++ ++#define S3C2410_GPB4_INP (0x00 << 8) ++#define S3C2410_GPB4_OUTP (0x01 << 8) ++#define S3C2410_GPB4_TCLK0 (0x02 << 8) ++#define S3C2410_GPB4_MASK (0x03 << 8) ++ ++#define S3C2410_GPB5_INP (0x00 << 10) ++#define S3C2410_GPB5_OUTP (0x01 << 10) ++#define S3C2410_GPB5_nXBACK (0x02 << 10) ++ ++#define S3C2410_GPB6_INP (0x00 << 12) ++#define S3C2410_GPB6_OUTP (0x01 << 12) ++#define S3C2410_GPB6_nXBREQ (0x02 << 12) ++ ++#define S3C2410_GPB7_INP (0x00 << 14) ++#define S3C2410_GPB7_OUTP (0x01 << 14) ++#define S3C2410_GPB7_nXDACK1 (0x02 << 14) ++ ++#define S3C2410_GPB8_INP (0x00 << 16) ++#define S3C2410_GPB8_OUTP (0x01 << 16) ++#define S3C2410_GPB8_nXDREQ1 (0x02 << 16) ++ ++#define S3C2410_GPB9_INP (0x00 << 18) ++#define S3C2410_GPB9_OUTP (0x01 << 18) ++#define S3C2410_GPB9_nXDACK0 (0x02 << 18) ++ ++#define S3C2410_GPB10_INP (0x00 << 18) ++#define S3C2410_GPB10_OUTP (0x01 << 18) ++#define S3C2410_GPB10_nXDRE0 (0x02 << 18) ++ ++/* Port C consits of 16 GPIO/Special function ++ * ++ * almost identical setup to port b, but the special functions are mostly ++ * to do with the video system's sync/etc. ++*/ ++ ++#define S3C2410_GPCCON S3C2410_GPIOREG(0x20) ++#define S3C2410_GPCDAT S3C2410_GPIOREG(0x24) ++#define S3C2410_GPCUP S3C2410_GPIOREG(0x28) ++ ++#define S3C2410_GPC0_INP (0x00 << 0) ++#define S3C2410_GPC0_OUTP (0x01 << 0) ++#define S3C2410_GPC0_LEND (0x02 << 0) ++ ++#define S3C2410_GPC1_INP (0x00 << 2) ++#define S3C2410_GPC1_OUTP (0x01 << 2) ++#define S3C2410_GPC1_VCLK (0x02 << 2) ++ ++#define S3C2410_GPC2_INP (0x00 << 4) ++#define S3C2410_GPC2_OUTP (0x01 << 4) ++#define S3C2410_GPC2_VLINE (0x02 << 4) ++ ++#define S3C2410_GPC3_INP (0x00 << 6) ++#define S3C2410_GPC3_OUTP (0x01 << 6) ++#define S3C2410_GPC3_VFRAME (0x02 << 6) ++ ++#define S3C2410_GPC4_INP (0x00 << 8) ++#define S3C2410_GPC4_OUTP (0x01 << 8) ++#define S3C2410_GPC4_VM (0x02 << 8) ++ ++#define S3C2410_GPC5_INP (0x00 << 10) ++#define S3C2410_GPC5_OUTP (0x01 << 10) ++#define S3C2410_GPC5_LCDVF0 (0x02 << 10) ++ ++#define S3C2410_GPC6_INP (0x00 << 12) ++#define S3C2410_GPC6_OUTP (0x01 << 12) ++#define S3C2410_GPC6_LCDVF1 (0x02 << 12) ++ ++#define S3C2410_GPC7_INP (0x00 << 14) ++#define S3C2410_GPC7_OUTP (0x01 << 14) ++#define S3C2410_GPC7_LCDVF2 (0x02 << 14) ++ ++#define S3C2410_GPC8_INP (0x00 << 16) ++#define S3C2410_GPC8_OUTP (0x01 << 16) ++#define S3C2410_GPC8_VD0 (0x02 << 16) ++ ++#define S3C2410_GPC9_INP (0x00 << 18) ++#define S3C2410_GPC9_OUTP (0x01 << 18) ++#define S3C2410_GPC9_VD1 (0x02 << 18) ++ ++#define S3C2410_GPC10_INP (0x00 << 20) ++#define S3C2410_GPC10_OUTP (0x01 << 20) ++#define S3C2410_GPC10_VD2 (0x02 << 20) ++ ++#define S3C2410_GPC11_INP (0x00 << 22) ++#define S3C2410_GPC11_OUTP (0x01 << 22) ++#define S3C2410_GPC11_VD3 (0x02 << 22) ++ ++#define S3C2410_GPC12_INP (0x00 << 24) ++#define S3C2410_GPC12_OUTP (0x01 << 24) ++#define S3C2410_GPC12_VD4 (0x02 << 24) ++ ++#define S3C2410_GPC13_INP (0x00 << 26) ++#define S3C2410_GPC13_OUTP (0x01 << 26) ++#define S3C2410_GPC13_VD5 (0x02 << 26) ++ ++#define S3C2410_GPC14_INP (0x00 << 28) ++#define S3C2410_GPC14_OUTP (0x01 << 28) ++#define S3C2410_GPC14_VD6 (0x02 << 28) ++ ++#define S3C2410_GPC15_INP (0x00 << 30) ++#define S3C2410_GPC15_OUTP (0x01 << 30) ++#define S3C2410_GPC15_VD7 (0x02 << 30) ++ ++/* Port D consists of 16 GPIO/Special function ++ * ++ * almost identical setup to port b, but the special functions are mostly ++ * to do with the video system's data. ++*/ ++ ++#define S3C2410_GPDCON S3C2410_GPIOREG(0x30) ++#define S3C2410_GPDDAT S3C2410_GPIOREG(0x34) ++#define S3C2410_GPDUP S3C2410_GPIOREG(0x38) ++ ++#define S3C2410_GPD0_INP (0x00 << 0) ++#define S3C2410_GPD0_OUTP (0x01 << 0) ++#define S3C2410_GPD0_VD8 (0x02 << 0) ++ ++#define S3C2410_GPD1_INP (0x00 << 2) ++#define S3C2410_GPD1_OUTP (0x01 << 2) ++#define S3C2410_GPD1_VD9 (0x02 << 2) ++ ++#define S3C2410_GPD2_INP (0x00 << 4) ++#define S3C2410_GPD2_OUTP (0x01 << 4) ++#define S3C2410_GPD2_VD10 (0x02 << 4) ++ ++#define S3C2410_GPD3_INP (0x00 << 6) ++#define S3C2410_GPD3_OUTP (0x01 << 6) ++#define S3C2410_GPD3_VD11 (0x02 << 6) ++ ++#define S3C2410_GPD4_INP (0x00 << 8) ++#define S3C2410_GPD4_OUTP (0x01 << 8) ++#define S3C2410_GPD4_VD12 (0x02 << 8) ++ ++#define S3C2410_GPD5_INP (0x00 << 10) ++#define S3C2410_GPD5_OUTP (0x01 << 10) ++#define S3C2410_GPD5_VD13 (0x02 << 10) ++ ++#define S3C2410_GPD6_INP (0x00 << 12) ++#define S3C2410_GPD6_OUTP (0x01 << 12) ++#define S3C2410_GPD6_VD14 (0x02 << 12) ++ ++#define S3C2410_GPD7_INP (0x00 << 14) ++#define S3C2410_GPD7_OUTP (0x01 << 14) ++#define S3C2410_GPD7_VD15 (0x02 << 14) ++ ++#define S3C2410_GPD8_INP (0x00 << 16) ++#define S3C2410_GPD8_OUTP (0x01 << 16) ++#define S3C2410_GPD8_VD16 (0x02 << 16) ++ ++#define S3C2410_GPD9_INP (0x00 << 18) ++#define S3C2410_GPD9_OUTP (0x01 << 18) ++#define S3C2410_GPD9_VD17 (0x02 << 18) ++ ++#define S3C2410_GPD10_INP (0x00 << 20) ++#define S3C2410_GPD10_OUTP (0x01 << 20) ++#define S3C2410_GPD10_VD18 (0x02 << 20) ++ ++#define S3C2410_GPD11_INP (0x00 << 22) ++#define S3C2410_GPD11_OUTP (0x01 << 22) ++#define S3C2410_GPD11_VD19 (0x02 << 22) ++ ++#define S3C2410_GPD12_INP (0x00 << 24) ++#define S3C2410_GPD12_OUTP (0x01 << 24) ++#define S3C2410_GPD12_VD20 (0x02 << 24) ++ ++#define S3C2410_GPD13_INP (0x00 << 26) ++#define S3C2410_GPD13_OUTP (0x01 << 26) ++#define S3C2410_GPD13_VD21 (0x02 << 26) ++ ++#define S3C2410_GPD14_INP (0x00 << 28) ++#define S3C2410_GPD14_OUTP (0x01 << 28) ++#define S3C2410_GPD14_VD22 (0x02 << 28) ++ ++#define S3C2410_GPD15_INP (0x00 << 30) ++#define S3C2410_GPD15_OUTP (0x01 << 30) ++#define S3C2410_GPD15_VD23 (0x02 << 30) ++ ++/* Port E consists of 16 GPIO/Special function ++ * ++ * again, the same as port B, but dealing with I2S, SDI, and ++ * more miscellaneous functions ++*/ ++ ++#define S3C2410_GPECON S3C2410_GPIOREG(0x40) ++#define S3C2410_GPEDAT S3C2410_GPIOREG(0x44) ++#define S3C2410_GPEUP S3C2410_GPIOREG(0x48) ++ ++#define S3C2410_GPE0_INP (0x00 << 0) ++#define S3C2410_GPE0_OUTP (0x01 << 0) ++#define S3C2410_GPE0_I2SLRCK (0x02 << 0) ++#define S3C2410_GPE0_MASK (0x03 << 0) ++ ++#define S3C2410_GPE1_INP (0x00 << 2) ++#define S3C2410_GPE1_OUTP (0x01 << 2) ++#define S3C2410_GPE1_I2SSCLK (0x02 << 2) ++#define S3C2410_GPE1_MASK (0x03 << 2) ++ ++#define S3C2410_GPE2_INP (0x00 << 4) ++#define S3C2410_GPE2_OUTP (0x01 << 4) ++#define S3C2410_GPE2_CDCLK (0x02 << 4) ++ ++#define S3C2410_GPE3_INP (0x00 << 6) ++#define S3C2410_GPE3_OUTP (0x01 << 6) ++#define S3C2410_GPE3_I2SSDI (0x02 << 6) ++#define S3C2410_GPE3_MASK (0x03 << 6) ++ ++#define S3C2410_GPE4_INP (0x00 << 8) ++#define S3C2410_GPE4_OUTP (0x01 << 8) ++#define S3C2410_GPE4_I2SSDO (0x02 << 8) ++#define S3C2410_GPE4_MASK (0x03 << 8) ++ ++#define S3C2410_GPE5_INP (0x00 << 10) ++#define S3C2410_GPE5_OUTP (0x01 << 10) ++#define S3C2410_GPE5_SDCLK (0x02 << 10) ++ ++#define S3C2410_GPE6_INP (0x00 << 12) ++#define S3C2410_GPE6_OUTP (0x01 << 12) ++#define S3C2410_GPE6_SDCLK (0x02 << 12) ++ ++#define S3C2410_GPE7_INP (0x00 << 14) ++#define S3C2410_GPE7_OUTP (0x01 << 14) ++#define S3C2410_GPE7_SDCMD (0x02 << 14) ++ ++#define S3C2410_GPE8_INP (0x00 << 16) ++#define S3C2410_GPE8_OUTP (0x01 << 16) ++#define S3C2410_GPE8_SDDAT1 (0x02 << 16) ++ ++#define S3C2410_GPE9_INP (0x00 << 18) ++#define S3C2410_GPE9_OUTP (0x01 << 18) ++#define S3C2410_GPE9_SDDAT2 (0x02 << 18) ++ ++#define S3C2410_GPE10_INP (0x00 << 20) ++#define S3C2410_GPE10_OUTP (0x01 << 20) ++#define S3C2410_GPE10_SDDAT3 (0x02 << 20) ++ ++#define S3C2410_GPE11_INP (0x00 << 22) ++#define S3C2410_GPE11_OUTP (0x01 << 22) ++#define S3C2410_GPE11_SPIMISO0 (0x02 << 22) ++ ++#define S3C2410_GPE12_INP (0x00 << 24) ++#define S3C2410_GPE12_OUTP (0x01 << 24) ++#define S3C2410_GPE12_SPIMOSI0 (0x02 << 24) ++ ++#define S3C2410_GPE13_INP (0x00 << 26) ++#define S3C2410_GPE13_OUTP (0x01 << 26) ++#define S3C2410_GPE13_SPICLK0 (0x02 << 26) ++ ++#define S3C2410_GPE14_INP (0x00 << 28) ++#define S3C2410_GPE14_OUTP (0x01 << 28) ++#define S3C2410_GPE14_IICSCL (0x02 << 28) ++#define S3C2410_GPE14_MASK (0x03 << 28) ++ ++#define S3C2410_GPE15_INP (0x00 << 30) ++#define S3C2410_GPE15_OUTP (0x01 << 30) ++#define S3C2410_GPE15_IICSDA (0x02 << 30) ++#define S3C2410_GPE15_MASK (0x03 << 30) ++ ++#define S3C2410_GPE_PUPDIS(x) (1<<(x)) ++ ++/* Port F consists of 8 GPIO/Special function ++ * ++ * GPIO / interrupt inputs ++ * ++ * GPFCON has 2 bits for each of the input pins on port F ++ * 00 = 0 input, 1 output, 2 interrupt (EINT0..7), 3 undefined ++ * ++ * pull up works like all other ports. ++*/ ++ ++#define S3C2410_GPFCON S3C2410_GPIOREG(0x50) ++#define S3C2410_GPFDAT S3C2410_GPIOREG(0x54) ++#define S3C2410_GPFUP S3C2410_GPIOREG(0x58) ++ ++ ++#define S3C2410_GPF0_INP (0x00 << 0) ++#define S3C2410_GPF0_OUTP (0x01 << 0) ++#define S3C2410_GPF0_EINT0 (0x02 << 0) ++ ++#define S3C2410_GPF1_INP (0x00 << 2) ++#define S3C2410_GPF1_OUTP (0x01 << 2) ++#define S3C2410_GPF1_EINT1 (0x02 << 2) ++ ++#define S3C2410_GPF2_INP (0x00 << 4) ++#define S3C2410_GPF2_OUTP (0x01 << 4) ++#define S3C2410_GPF2_EINT2 (0x02 << 4) ++ ++#define S3C2410_GPF3_INP (0x00 << 6) ++#define S3C2410_GPF3_OUTP (0x01 << 6) ++#define S3C2410_GPF3_EINT3 (0x02 << 6) ++ ++#define S3C2410_GPF4_INP (0x00 << 8) ++#define S3C2410_GPF4_OUTP (0x01 << 8) ++#define S3C2410_GPF4_EINT4 (0x02 << 8) ++ ++#define S3C2410_GPF5_INP (0x00 << 10) ++#define S3C2410_GPF5_OUTP (0x01 << 10) ++#define S3C2410_GPF5_EINT5 (0x02 << 10) ++ ++#define S3C2410_GPF6_INP (0x00 << 12) ++#define S3C2410_GPF6_OUTP (0x01 << 12) ++#define S3C2410_GPF6_EINT6 (0x02 << 12) ++ ++#define S3C2410_GPF7_INP (0x00 << 14) ++#define S3C2410_GPF7_OUTP (0x01 << 14) ++#define S3C2410_GPF7_EINT7 (0x02 << 14) ++ ++/* Port G consists of 8 GPIO/IRQ/Special function ++ * ++ * GPGCON has 2 bits for each of the input pins on port F ++ * 00 = 0 input, 1 output, 2 interrupt (EINT0..7), 3 special func ++ * ++ * pull up works like all other ports. ++*/ ++ ++#define S3C2410_GPGCON S3C2410_GPIOREG(0x60) ++#define S3C2410_GPGDAT S3C2410_GPIOREG(0x64) ++#define S3C2410_GPGUP S3C2410_GPIOREG(0x68) ++ ++#define S3C2410_GPG0_INP (0x00 << 0) ++#define S3C2410_GPG0_OUTP (0x01 << 0) ++#define S3C2410_GPG0_EINT8 (0x02 << 0) ++ ++#define S3C2410_GPG1_INP (0x00 << 2) ++#define S3C2410_GPG1_OUTP (0x01 << 2) ++#define S3C2410_GPG1_EINT9 (0x02 << 2) ++ ++#define S3C2410_GPG2_INP (0x00 << 4) ++#define S3C2410_GPG2_OUTP (0x01 << 4) ++#define S3C2410_GPG2_EINT10 (0x02 << 4) ++ ++#define S3C2410_GPG3_INP (0x00 << 6) ++#define S3C2410_GPG3_OUTP (0x01 << 6) ++#define S3C2410_GPG3_EINT11 (0x02 << 6) ++ ++#define S3C2410_GPG4_INP (0x00 << 8) ++#define S3C2410_GPG4_OUTP (0x01 << 8) ++#define S3C2410_GPG4_EINT12 (0x02 << 8) ++#define S3C2410_GPG4_LCDPWREN (0x03 << 8) ++ ++#define S3C2410_GPG5_INP (0x00 << 10) ++#define S3C2410_GPG5_OUTP (0x01 << 10) ++#define S3C2410_GPG5_EINT13 (0x02 << 10) ++#define S3C2410_GPG5_SPIMISO1 (0x03 << 10) ++ ++#define S3C2410_GPG6_INP (0x00 << 12) ++#define S3C2410_GPG6_OUTP (0x01 << 12) ++#define S3C2410_GPG6_EINT14 (0x02 << 12) ++#define S3C2410_GPG6_SPIMOSI1 (0x03 << 12) ++ ++#define S3C2410_GPG7_INP (0x00 << 14) ++#define S3C2410_GPG7_OUTP (0x01 << 14) ++#define S3C2410_GPG7_EINT15 (0x02 << 14) ++#define S3C2410_GPG7_SPICLK1 (0x03 << 14) ++ ++#define S3C2410_GPG8_INP (0x00 << 16) ++#define S3C2410_GPG8_OUTP (0x01 << 16) ++#define S3C2410_GPG8_EINT16 (0x02 << 16) ++ ++#define S3C2410_GPG9_INP (0x00 << 18) ++#define S3C2410_GPG9_OUTP (0x01 << 18) ++#define S3C2410_GPG9_EINT17 (0x02 << 18) ++ ++#define S3C2410_GPG10_INP (0x00 << 20) ++#define S3C2410_GPG10_OUTP (0x01 << 20) ++#define S3C2410_GPG10_EINT18 (0x02 << 20) ++ ++#define S3C2410_GPG11_INP (0x00 << 22) ++#define S3C2410_GPG11_OUTP (0x01 << 22) ++#define S3C2410_GPG11_EINT19 (0x02 << 22) ++#define S3C2410_GPG11_TCLK1 (0x03 << 22) ++ ++#define S3C2410_GPG12_INP (0x00 << 24) ++#define S3C2410_GPG12_OUTP (0x01 << 24) ++#define S3C2410_GPG12_EINT18 (0x02 << 24) ++#define S3C2410_GPG12_XMON (0x03 << 24) ++ ++#define S3C2410_GPG13_INP (0x00 << 26) ++#define S3C2410_GPG13_OUTP (0x01 << 26) ++#define S3C2410_GPG13_EINT18 (0x02 << 26) ++#define S3C2410_GPG13_nXPON (0x03 << 26) ++ ++#define S3C2410_GPG14_INP (0x00 << 28) ++#define S3C2410_GPG14_OUTP (0x01 << 28) ++#define S3C2410_GPG14_EINT18 (0x02 << 28) ++#define S3C2410_GPG14_YMON (0x03 << 28) ++ ++#define S3C2410_GPG15_INP (0x00 << 30) ++#define S3C2410_GPG15_OUTP (0x01 << 30) ++#define S3C2410_GPG15_EINT18 (0x02 << 30) ++#define S3C2410_GPG15_nYPON (0x03 << 30) ++ ++ ++#define S3C2410_GPG_PUPDIS(x) (1<<(x)) ++ ++/* Port H consists of11 GPIO/serial/Misc pins ++ * ++ * GPGCON has 2 bits for each of the input pins on port F ++ * 00 = 0 input, 1 output, 2 interrupt (EINT0..7), 3 special func ++ * ++ * pull up works like all other ports. ++*/ ++ ++#define S3C2410_GPHCON S3C2410_GPIOREG(0x70) ++#define S3C2410_GPHDAT S3C2410_GPIOREG(0x74) ++#define S3C2410_GPHUP S3C2410_GPIOREG(0x78) ++ ++#define S3C2410_GPH0_INP (0x00 << 0) ++#define S3C2410_GPH0_OUTP (0x01 << 0) ++#define S3C2410_GPH0_nCTS0 (0x02 << 0) ++ ++#define S3C2410_GPH1_INP (0x00 << 2) ++#define S3C2410_GPH1_OUTP (0x01 << 2) ++#define S3C2410_GPH1_nRTS0 (0x02 << 2) ++ ++#define S3C2410_GPH2_INP (0x00 << 4) ++#define S3C2410_GPH2_OUTP (0x01 << 4) ++#define S3C2410_GPH2_TXD0 (0x02 << 4) ++ ++#define S3C2410_GPH3_INP (0x00 << 6) ++#define S3C2410_GPH3_OUTP (0x01 << 6) ++#define S3C2410_GPH3_RXD0 (0x02 << 6) ++ ++#define S3C2410_GPH4_INP (0x00 << 8) ++#define S3C2410_GPH4_OUTP (0x01 << 8) ++#define S3C2410_GPH4_TXD1 (0x02 << 8) ++ ++#define S3C2410_GPH5_INP (0x00 << 10) ++#define S3C2410_GPH5_OUTP (0x01 << 10) ++#define S3C2410_GPH5_RXD1 (0x02 << 10) ++ ++#define S3C2410_GPH6_INP (0x00 << 12) ++#define S3C2410_GPH6_OUTP (0x01 << 12) ++#define S3C2410_GPH6_TXD2 (0x02 << 12) ++#define S3C2410_GPH6_nRTS1 (0x03 << 12) ++ ++#define S3C2410_GPH7_INP (0x00 << 14) ++#define S3C2410_GPH7_OUTP (0x01 << 14) ++#define S3C2410_GPH7_RXD2 (0x02 << 14) ++#define S3C2410_GPH7_nCTS1 (0x03 << 14) ++ ++#define S3C2410_GPH8_INP (0x00 << 16) ++#define S3C2410_GPH8_OUTP (0x01 << 16) ++#define S3C2410_GPH8_UCLK (0x02 << 16) ++ ++#define S3C2410_GPH9_INP (0x00 << 18) ++#define S3C2410_GPH9_OUTP (0x01 << 18) ++#define S3C2410_GPH9_CLKOUT0 (0x02 << 18) ++ ++#define S3C2410_GPH10_INP (0x00 << 20) ++#define S3C2410_GPH10_OUTP (0x01 << 20) ++#define S3C2410_GPH10_CLKOUT1 (0x02 << 20) ++ ++/* miscellaneous control */ ++ ++#define S3C2410_MISCCR S3C2410_GPIOREG(0x80) ++#define S3C2410_DCLKCON S3C2410_GPIOREG(0x84) ++ ++/* see clock.h for dclk definitions */ ++ ++/* pullup control on databus */ ++#define S3C2410_MISCCR_SPUCR_HEN (0) ++#define S3C2410_MISCCR_SPUCR_HDIS (1<<0) ++#define S3C2410_MISCCR_SPUCR_LEN (0) ++#define S3C2410_MISCCR_SPUCR_LDIS (1<<1) ++ ++#define S3C2410_MISCCR_USBDEV (0) ++#define S3C2410_MISCCR_USBHOST (1<<3) ++ ++#define S3C2410_MISCCR_CLK0_MPLL (0<<4) ++#define S3C2410_MISCCR_CLK0_UPLL (1<<4) ++#define S3C2410_MISCCR_CLK0_FCLK (2<<4) ++#define S3C2410_MISCCR_CLK0_HCLK (3<<4) ++#define S3C2410_MISCCR_CLK0_PCLK (4<<4) ++#define S3C2410_MISCCR_CLK0_DCLK0 (5<<4) ++ ++#define S3C2410_MISCCR_CLK1_MPLL (0<<8) ++#define S3C2410_MISCCR_CLK1_UPLL (1<<8) ++#define S3C2410_MISCCR_CLK1_FCLK (2<<8) ++#define S3C2410_MISCCR_CLK1_HCLK (3<<8) ++#define S3C2410_MISCCR_CLK1_PCLK (4<<8) ++#define S3C2410_MISCCR_CLK1_DCLK1 (5<<8) ++ ++#define S3C2410_MISCCR_USBSUSPND0 (1<<12) ++#define S3C2410_MISCCR_USBSUSPND1 (1<<13) ++ ++#define S3C2410_MISCCR_nRSTCON (1<<16) ++ ++/* external interrupt control... */ ++/* S3C2410_EXTINT0 -> irq sense control for EINT0..EINT7 ++ * S3C2410_EXTINT1 -> irq sense control for EINT8..EINT15 ++ * S3C2410_EXTINT2 -> irq sense control for EINT16..EINT23 ++ * ++ * note S3C2410_EXTINT2 has filtering options for EINT16..EINT23 ++ * ++ * Samsung datasheet p9-25 ++*/ ++ ++#define S3C2410_EXTINT0 S3C2410_GPIOREG(0x88) ++#define S3C2410_EXTINT1 S3C2410_GPIOREG(0x8C) ++#define S3C2410_EXTINT2 S3C2410_GPIOREG(0x90) ++ ++/* values for S3C2410_EXTINT0/1/2 */ ++#define S3C2410_EXTINT_LOWLEV (0x00) ++#define S3C2410_EXTINT_HILEV (0x01) ++#define S3C2410_EXTINT_FALLEDGE (0x02) ++#define S3C2410_EXTINT_RISEEDGE (0x04) ++#define S3C2410_EXTINT_BOTHEDGE (0x06) ++ ++/* interrupt filtering conrrol for EINT16..EINT23 */ ++#define S3C2410_EINFLT0 S3C2410_GPIOREG(0x94) ++#define S3C2410_EINFLT1 S3C2410_GPIOREG(0x98) ++#define S3C2410_EINFLT2 S3C2410_GPIOREG(0x9C) ++#define S3C2410_EINFLT3 S3C2410_GPIOREG(0xA0) ++ ++/* mask: 0=enable, 1=disable ++ * 1 bit EINT, 4=EINT4, 23=EINT23 ++ * EINT0,1,2,3 are not handled here. ++*/ ++#define S3C2410_EINTMASK S3C2410_GPIOREG(0xA4) ++#define S3C2410_EINTPEND S3C2410_GPIOREG(0xA8) ++ ++/* GSTATUS have miscellaneous information in them ++ * ++ */ ++ ++#define S3C2410_GSTATUS0 S3C2410_GPIOREG(0x0AC) ++#define S3C2410_GSTATUS1 S3C2410_GPIOREG(0x0B0) ++#define S3C2410_GSTATUS2 S3C2410_GPIOREG(0x0B4) ++#define S3C2410_GSTATUS3 S3C2410_GPIOREG(0x0B8) ++#define S3C2410_GSTATUS4 S3C2410_GPIOREG(0x0BC) ++ ++#define S3C2410_GSTATUS0_nWAIT (1<<3) ++#define S3C2410_GSTATUS0_NCON (1<<2) ++#define S3C2410_GSTATUS0_RnB (1<<1) ++#define S3C2410_GSTATUS0_nBATTFLT (1<<0) ++ ++#define S3C2410_GSTATUS2_WTRESET (1<<2) ++#define S3C2410_GSTATUs2_OFFRESET (1<<1) ++#define S3C2410_GSTATUS2_PONRESET (1<<0) ++ ++#endif /* ASMARM_ARCH_S3C2410_GPIO_H */ ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-s3c2410/S3C2410-iis.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,61 @@ ++/* linux/include/asm/hardware/s3c2410/iis.h ++ * ++ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk> ++ * http://www.simtec.co.uk/products/SWLINUX/ ++ * ++ * 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. ++ * ++ * S3C2410 IIS register definition ++ * ++ * Changelog: ++ * 19-06-2003 BJD Created file ++ * 26-06-2003 BJD Finished off definitions for register addresses ++ */ ++ ++#ifndef ASMARM_ARCH_S3C2410_IIS_H ++#define ASMARM_ARCH_S3C2410_IIS_H ++ ++#define S3C2410_IISCON (S3C2410_VA_IIS + 0x00) ++ ++#define S3C2410_IISCON_LRINDEX (1<<8) ++#define S3C2410_IISCON_TXFIFORDY (1<<7) ++#define S3C2410_IISCON_RXFIFORDY (1<<6) ++#define S3C2410_IISCON_TXDMAEN (1<<5) ++#define S3C2410_IISCON_RXDMAEN (1<<4) ++#define S3C2410_IISCON_TXIDLE (1<<3) ++#define S3C2410_IISCON_RXIDLE (1<<2) ++#define S3C2410_IISCON_IISEN (1<<0) ++ ++#define S3C2410_IISMOD (S3C2410_VA_IIS + 0x04) ++ ++#define S3C2410_IISMOD_SLAVE (1<<8) ++#define S3C2410_IISMOD_NOXFER (0<<6) ++#define S3C2410_IISMOD_RXMODE (1<<6) ++#define S3C2410_IISMOD_TXMODE (2<<6) ++#define S3C2410_IISMOD_TXRXMODE (3<<6) ++#define S3C2410_IISMOD_LR_LLOW (0<<5) ++#define S3C2410_IISMOD_LR_RLOW (1<<5) ++#define S3C2410_IISMOD_IIS (0<<4) ++#define S3C2410_IISMOD_MSB (1<<4) ++#define S3C2410_IISMOD_8BIT (0<<3) ++#define S3C2410_IISMOD_16BIT (1<<3) ++#define S3C2410_IISMOD_256FS (0<<1) ++#define S3C2410_IISMOD_384FS (1<<1) ++#define S3C2410_IISMOD_16FS (0<<0) ++#define S3C2410_IISMOD_32FS (1<<0) ++#define S3C2410_IISMOD_48FS (2<<0) ++ ++#define S3C2410_IISPSR (S3C2410_VA_IIS + 0x08) ++ ++#define S3C2410_IISFCON (S3C2410_VA_IIS + 0x0c) ++ ++#define S3C2410_IISFCON_TXDMA (1<<15) ++#define S3C2410_IISFCON_RXDMA (1<<14) ++#define S3C2410_IISFCON_TXENABLE (1<<13) ++#define S3C2410_IISFCON_RXENABLE (1<<12) ++ ++#define S3C2410_IISFIFO (S3C2410_VA_IIS + 0x10) ++ ++#endif /* ASMARM_ARCH_S3C2410_IIS_H */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-s3c2410/S3C2410-irq.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,34 @@ ++/* linux/include/asm-arm/arch-s3c2410/S3C2410-irq.h ++ * ++ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk> ++ * http://www.simtec.co.uk/products/SWLINUX/ ++ * ++ * 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: ++ * 19-06-2003 BJD Created file ++ */ ++ ++#ifndef ASMARM_ARCH_S3C2410_IRQ_H ++#define ASMARM_ARCH_S3C2410_IRQ_H ++ ++/* interrupt controller */ ++ ++#define S3C2410_IRQREG(x) ((x) + S3C2410_VA_IRQ) ++#define S3C2410_EINTREG(x) ((x) + S3C2410_VA_GPIO) ++ ++#define S3C2410_SRCPND S3C2410_IRQREG(0x000) ++#define S3C2410_INTMOD S3C2410_IRQREG(0x004) ++#define S3C2410_INTMSK S3C2410_IRQREG(0x008) ++#define S3C2410_PRIORITY S3C2410_IRQREG(0x00C) ++#define S3C2410_INTPND S3C2410_IRQREG(0x010) ++#define S3C2410_INTOFFSET S3C2410_IRQREG(0x014) ++#define S3C2410_SUBSRCPND S3C2410_IRQREG(0x018) ++#define S3C2410_INTSUBMSK S3C2410_IRQREG(0x01C) ++ ++#define S3C2410_EINTMASK S3C2410_EINTREG(0x0A4) ++#define S3C2410_EINTPEND S3C2410_EINTREG(0X0A8) ++ ++#endif /* ASMARM_ARCH_S3C2410_IRQ_H */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-s3c2410/S3C2410-lcd.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,107 @@ ++/* linux/include/asm-arm/arch-s3c2410/S3C2410-lcd.h ++ * ++ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk> ++ * http://www.simtec.co.uk/products/SWLINUX/ ++ * ++ * 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: ++ * 12-06-2003 BJD Created file ++ * 26-06-2003 BJD Updated LCDCON register definitions ++*/ ++ ++#ifndef ASMARM_ARCH_S3C2410_LCD_H ++#define ASMARM_ARCH_S3C2410_LCD_H ++ ++#define S3C2410_LCDREG(x) ((x) + S3C2410_VA_LCD) ++ ++/* LCD control registers */ ++#define S3C2410_LCDCON1 S3C2410_LCDREG(0x00) ++#define S3C2410_LCDCON2 S3C2410_LCDREG(0x04) ++#define S3C2410_LCDCON3 S3C2410_LCDREG(0x08) ++#define S3C2410_LCDCON4 S3C2410_LCDREG(0x0C) ++#define S3C2410_LCDCON5 S3C2410_LCDREG(0x10) ++ ++#define S3C2410_LCDCON1_CLKVAL(x) ((x) << 8) ++#define S3C2410_LCDCON1_MMODE (1<<7) ++#define S3C2410_LCDCON1_DSCAN4 (0<<5) ++#define S3C2410_LCDCON1_STN4 (1<<5) ++#define S3C2410_LCDCON1_STN8 (2<<5) ++#define S3C2410_LCDCON1_TFT (3<<5) ++ ++#define S3C2410_LCDCON1_STN1BPP (0<<1) ++#define S3C2410_LCDCON1_STN2GREY (1<<1) ++#define S3C2410_LCDCON1_STN4GREY (2<<1) ++#define S3C2410_LCDCON1_STN8BPP (3<<1) ++#define S3C2410_LCDCON1_STN12BPP (4<<1) ++ ++#define S3C2410_LCDCON1_TFT1BPP (8<<1) ++#define S3C2410_LCDCON1_TFT2BPP (9<<1) ++#define S3C2410_LCDCON1_TFT4BPP (10<<1) ++#define S3C2410_LCDCON1_TFT8BPP (11<<1) ++#define S3C2410_LCDCON1_TFT16BPP (12<<1) ++#define S3C2410_LCDCON1_TFT24BPP (13<<1) ++ ++#define S3C2410_LCDCON1_ENVDI (1) ++ ++#define S3C2410_LCDCON2_VBPD(x) ((x) << 24) ++#define S3C2410_LCDCON2_LINEVAL(x) ((x) << 14) ++#define S3C2410_LCDCON2_VFPD(x) ((x) << 6) ++#define S3C2410_LCDCON2_VSPW(x) ((x) << 0) ++ ++#define S3C2410_LCDCON3_HBPD(x) ((x) << 19) ++#define S3C2410_LCDCON3_WDLY(x) ((x) << 19) ++#define S3C2410_LCDCON3_HOZVAL(x) ((x) << 8) ++#define S3C2410_LCDCON3_HFPD(x) ((x) << 0) ++#define S3C2410_LCDCON3_LINEBLANK(x)((x) << 0) ++ ++#define S3C2410_LCDCON4_MVAL(x) ((x) << 8) ++#define S3C2410_LCDCON4_HSPW(x) ((x) << 0) ++#define S3C2410_LCDCON4_WLH(x) ((x) << 0) ++ ++#define S3C2410_LCDCON5_BPP24BL (1<<12) ++#define S3C2410_LCDCON5_FRM565 (1<<11) ++#define S3C2410_LCDCON5_INVVCLK (1<<10) ++#define S3C2410_LCDCON5_INVVLINE (1<<9) ++#define S3C2410_LCDCON5_INVVFRAME (1<<8) ++#define S3C2410_LCDCON5_INVVD (1<<7) ++#define S3C2410_LCDCON5_INVVSYNC (1<<8) ++#define S3C2410_LCDCON5_INVHSYNC (1<<9) ++#define S3C2410_LCDCON5_INVVDEN (1<<6) ++#define S3C2410_LCDCON5_INVPWREN (1<<5) ++#define S3C2410_LCDCON5_INVLEND (1<<4) ++#define S3C2410_LCDCON5_PWREN (1<<3) ++#define S3C2410_LCDCON5_ENLEND (1<<2) ++#define S3C2410_LCDCON5_BSWP (1<<1) ++#define S3C2410_LCDCON5_HWSWP (1<<0) ++ ++/* framebuffer start addressed */ ++#define S3C2410_LCDSADDR1 S3C2410_LCDREG(0x14) ++#define S3C2410_LCDSADDR2 S3C2410_LCDREG(0x18) ++#define S3C2410_LCDSADDR3 S3C2410_LCDREG(0x1C) ++ ++/* colour lookup and miscellaneous controls */ ++ ++#define S3C2410_REDLUT S3C2410_LCDREG(0x20) ++#define S3C2410_GREENLUT S3C2410_LCDREG(0x24) ++#define S3C2410_BLUELUT S3C2410_LCDREG(0x28) ++ ++#define S3C2410_DITHMODE S3C2410_LCDREG(0x4C) ++#define S3C2410_TPAL S3C2410_LCDREG(0x50) ++ ++/* interrupt info */ ++#define S3C2410_LCDINTPND S3C2410_LCDREG(0x54) ++#define S3C2410_LCDSRCPND S3C2410_LCDREG(0x58) ++#define S3C2410_LCDINTMSK S3C2410_LCDREG(0x5C) ++#define S3C2410_LPCSEL S3C2410_LCDREG(0x60) ++ ++#define S3C2410_TFTPAL(x) S3C2410_LCDREG((0x400 + (x)*4)) ++ ++#endif /* ASMARM_ARCH_S3C2410_LCD_H */ ++ ++ ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-s3c2410/S3C2410-rtc.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,61 @@ ++/* linux/include/asm-arm/arch-s3c2410/S3C2410-rtc.h ++ * ++ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk> ++ * http://www.simtec.co.uk/products/SWLINUX/ ++ * ++ * 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. ++ * ++ * S3C2410 Timer configuration ++ * ++ * Changelog: ++ * 05-06-2003 BJD Created file ++ */ ++ ++#ifndef ASMARM_ARCH_S3C2410_RTC_H ++#define ASMARM_ARCH_S3C2410_RTC_H ++ ++#define S3C2410_RTCREG(x) ((x) + S3C2410_VA_RTC) ++ ++#define S3C2410_RTCCON S3C2410_RTCREG(0x40) ++#define S3C2410_RTCCON_RTCEN (1<<0) ++#define S3C2410_RTCCON_CLKRST (1<<3) ++ ++#define S3C2410_TICNT S3C2410_RTCREG(0x44) ++#define S3C2410_TICNT_ENABLE (1<<7) ++ ++#define S3C2410_RTCALM S3C2410_RTCREG(0x50) ++#define S3C2410_RTCALM_ALMEN (1<<6) ++#define S3C2410_RTCALM_YEAREN (1<<5) ++#define S3C2410_RTCALM_MONEN (1<<4) ++#define S3C2410_RTCALM_DAYEN (1<<3) ++#define S3C2410_RTCALM_HOUREN (1<<2) ++#define S3C2410_RTCALM_MINEN (1<<1) ++#define S3C2410_RTCALM_SECEN (1<<0) ++ ++#define S3C2410_RTCALM_ALL \ ++ S3C2410_RTCALM_ALMEN | S3C2410_RTCALM_YEAREN | S3C2410_RTCALM_MONEN |\ ++ S3C2410_RTCALM_DAYEN | S3C2410_RTCALM_HOUREN | S3C2410_RTCALM_MINEN |\ ++ S3C2410_RTCALM_SECEN ++ ++ ++#define S3C2410_ALMSEC S3C2410_RTCREG(0x54) ++#define S3C2410_ALMMIN S3C2410_RTCREG(0x58) ++#define S3C2410_ALMHOUR S3C2410_RTCREG(0x5c) ++ ++#define S3C2410_ALMDATE S3C2410_RTCREG(0x60) ++#define S3C2410_ALMMON S3C2410_RTCREG(0x64) ++#define S3C2410_ALMYEAR S3C2410_RTCREG(0x68) ++ ++#define S3C2410_RTCRST S3C2410_RTCREG(0x6c) ++ ++#define S3C2410_RTCSEC S3C2410_RTCREG(0x70) ++#define S3C2410_RTCMIN S3C2410_RTCREG(0x74) ++#define S3C2410_RTCHOUR S3C2410_RTCREG(0x78) ++#define S3C2410_RTCDATE S3C2410_RTCREG(0x7c) ++#define S3C2410_RTCDAY S3C2410_RTCREG(0x80) ++#define S3C2410_RTCMON S3C2410_RTCREG(0x84) ++#define S3C2410_RTCYEAR S3C2410_RTCREG(0x88) ++ ++#endif /* ASMARM_ARCH_S3C2410_RTC_H */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-s3c2410/S3C2410-serial.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,98 @@ ++/* ++ * linux/include/asm-arm/arch-s3c2410/S3C2410-serial.h ++ * ++ * Internal header file for Samsung S3C2410 serial ports (UART0-2) ++ * ++ * Copyright (C) 2002 Shane Nay (shane@minirl.com) ++ * ++ * Additional defines, (c) 2003 Simtec Electronics (linux@simtec.co.uk) ++ * ++ * Adapted from: ++ * ++ * Internal header file for MX1ADS serial ports (UART1 & 2) ++ * ++ * Copyright (C) 2002 Shane Nay (shane@minirl.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 ++ */ ++ ++#ifndef ASMARM_ARCH_S3C2410_SERIAL_H ++#define ASMARM_ARCH_S3C2410_SERIAL_H ++ ++#define S3C2410_UARTRXH0_OFF (0x24) ++#define S3C2410_UARTTXH0_OFF (0x20) ++#define S3C2410_UARTLCON_OFF (0x00) ++#define S3C2410_UARTCON_OFF (0x04) ++#define S3C2410_UARTFCON_OFF (0x08) ++#define S3C2410_UARTMCON_OFF (0x0C) ++#define S3C2410_UARTBRDIV_OFF (0x28) ++#define S3C2410_UARTTRSTAT_OFF (0x10) ++#define S3C2410_UARTERSTAT_OFF (0x14) ++#define S3C2410_UARTFSTAT_OFF (0x18) ++#define S3C2410_UARTMSTAT_OFF (0x1C) ++ ++ ++#define S3C2410_UART1_OFF (0x4000) ++#define S3C2410_UART2_OFF (0x8000) ++ ++#define S3C2410_LCON_CFGMASK ((0xF<<3)|(0x3)) ++ ++#define S3C2410_LCON_CS5 (0x0) ++#define S3C2410_LCON_CS6 (0x1) ++#define S3C2410_LCON_CS7 (0x2) ++#define S3C2410_LCON_CS8 (0x3) ++ ++#define S3C2410_LCON_PNONE (0x0) ++#define S3C2410_LCON_PEVEN ((0x5)<<3) ++#define S3C2410_LCON_PODD ((0x4)<<3) ++ ++#define S3C2410_UMCON_AFC (0x10) ++#define S3C2410_UMCON_RTS (0x1) ++ ++#define S3C2410_UMSTAT_CTS (0x1) ++ ++#define S3C2410_UCON_SBREAK (1<<4) ++ ++#define S3C2410_UCON_TXILEVEL (1<<9) ++#define S3C2410_UCON_RXILEVEL (1<<8) ++#define S3C2410_UCON_TXIRQMODE (1<<2) ++#define S3C2410_UCON_RXIRQMODE (1<<0) ++#define S3C2410_UCON_RXFIFO_TOI (1<<7) ++ ++#define S3C2410_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | S3C2410_UCON_RXILEVEL \ ++ | S3C2410_UCON_TXIRQMODE | S3C2410_UCON_RXIRQMODE \ ++ | S3C2410_UCON_RXFIFO_TOI) ++ ++#define S3C2410_UFCON_FIFOMODE (1<<0) ++#define S3C2410_UFCON_TXTRIG0 (0<<6) ++#define S3C2410_UFCON_RXTRIG8 (1<<4) ++#define S3C2410_UFCON_RXTRIG12 (2<<4) ++ ++#define S3C2410_UFCON_RESETBOTH (3<<1) ++ ++#define S3C2410_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | S3C2410_UFCON_TXTRIG0 \ ++ | S3C2410_UFCON_RXTRIG8 ) ++ ++#define S3C2410_UFSTAT_TXFULL (1<<9) ++#define S3C2410_UFSTAT_RXFULL (1<<8) ++#define S3C2410_UFSTAT_TXMASK (15<<4) ++#define S3C2410_UFSTAT_TXSHIFT (4) ++#define S3C2410_UFSTAT_RXMASK (15<<0) ++#define S3C2410_UFSTAT_RXSHIFT (0) ++ ++#define S3C2410_UTRSTAT_TXFE (1<<1) ++#define S3C2410_UTRSTAT_RXDR (1<<0) ++ ++#endif /* ASMARM_ARCH_S3C2410_SERIAL_H */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-s3c2410/S3C2410-timer.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,81 @@ ++/* linux/include/asm-arm/arch-s3c2410/S3C2410-timer.h ++ * ++ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk> ++ * http://www.simtec.co.uk/products/SWLINUX/ ++ * ++ * 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. ++ * ++ * S3C2410 Timer configuration ++ * ++ * Changelog: ++ * 05-06-2003 BJD Created file ++ * 26-06-2003 BJD Added more timer definitions to mux / control ++ */ ++ ++#ifndef ASMARM_ARCH_S3C2410_TIMER_H ++#define ASMARM_ARCH_S3C2410_TIMER_H ++ ++#define S3C2410_TIMERREG(x) (S3C2410_VA_TIMER + (x)) ++#define S3C2410_TIMERREG2(tmr,reg) S3C2410_TIMERREG((reg)+0x0c+((tmr)*0x0c)) ++ ++#define S3C2410_TCFG0 S3C2410_TIMERREG(0x00) ++#define S3C2410_TCFG1 S3C2410_TIMERREG(0x04) ++#define S3C2410_TCON S3C2410_TIMERREG(0x08) ++ ++ ++#define S3C2410_TCFG1_MUX4_TCLK1 (4<<16) ++#define S3C2410_TCFG1_MUX4_MASK (15<<16) ++ ++#define S3C2410_TCFG1_MUX3_TCLK1 (4<<12) ++#define S3C2410_TCFG1_MUX3_MASK (15<<12) ++ ++#define S3C2410_TCFG1_MUX2_TCLK1 (4<<8) ++#define S3C2410_TCFG1_MUX2_MASK (15<<8) ++ ++#define S3C2410_TCFG1_MUX1_TCLK0 (4<<4) ++#define S3C2410_TCFG1_MUX1_MASK (15<<4) ++ ++#define S3C2410_TCFG1_MUX0_TCLK0 (4<<0) ++#define S3C2410_TCFG1_MUX0_MASK (15<<0) ++ ++/* for each timer, we have an count buffer, an compare buffer and an ++ * observation buffer ++ */ ++ ++/* WARNING - timer 4 has no buffer reg, and it's observation is at +4 */ ++ ++#define S3C2410_TCNTB(tmr) S3C2410_TIMERREG2(tmr, 0x00) ++#define S3C2410_TCMPB(tmr) S3C2410_TIMERREG2(tmr, 0x04) ++#define S3C2410_TCNTO(tmr) S3C2410_TIMERREG2(tmr, (((tmr) == 4) ? 0x04 : 0x08)) ++ ++#define S3C2410_TCON_T4RELOAD (1<<22) ++#define S3C2410_TCON_T4MANUALUPD (1<<21) ++#define S3C2410_TCON_T4START (1<<20) ++ ++#define S3C2410_TCON_T3RELOAD (1<<19) ++#define S3C2410_TCON_T3INVERT (1<<18) ++#define S3C2410_TCON_T3MANUALUPD (1<<17) ++#define S3C2410_TCON_T3START (1<<16) ++ ++#define S3C2410_TCON_T2RELOAD (1<<15) ++#define S3C2410_TCON_T2INVERT (1<<14) ++#define S3C2410_TCON_T2MANUALUPD (1<<13) ++#define S3C2410_TCON_T2START (1<<12) ++ ++#define S3C2410_TCON_T1RELOAD (1<<11) ++#define S3C2410_TCON_T1INVERT (1<<10) ++#define S3C2410_TCON_T1MANUALUPD (1<<9) ++#define S3C2410_TCON_T1START (1<<8) ++ ++#define S3C2410_TCON_T0DEADZONE (1<<4) ++#define S3C2410_TCON_T0RELOAD (1<<3) ++#define S3C2410_TCON_T0INVERT (1<<2) ++#define S3C2410_TCON_T0MANUALUPD (1<<1) ++#define S3C2410_TCON_T0START (1<<0) ++ ++#endif /* ASMARM_ARCH_S3C2410_TIMER_H */ ++ ++ ++ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/arch-s3c2410/S3C2410-watchdog.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,40 @@ ++/* linux/include/asm-arm/arch-s3c2410/S3C2410-watchdog.h ++ * ++ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk> ++ * http://www.simtec.co.uk/products/SWLINUX/ ++ * ++ * 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. ++ * ++ * S3C2410 Watchdog timer control ++ * ++ * Changelog: ++ * 21-06-2003 BJD Created file ++*/ ++ ++#ifndef ASMARM_ARCH_S3C2410_WATCHDOG_H ++#define ASMARM_ARCH_S3C2410_WATCHDOG_H ++ ++#define S3C2410_WDOGREG(x) ((x) + S3C2410_VA_WATCHDOG) ++ ++#define S3C2410_WTCON S3C2410_WDOGREG(0x00) ++#define S3C2410_WTDAT S3C2410_WDOGREG(0x04) ++#define S3C2410_WTCNT S3C2410_WDOGREG(0x08) ++ ++/* the watchdog can either generate a reset pulse, or an interrupt. */ ++ ++#define S3C2410_WTCON_RSTEN (0x01) ++#define S3C2410_WTCON_INTEN (1<<2) ++#define S3C2410_WTCON_ENABLE (1<<5) ++ ++#define S3C2410_WTCON_DIV16 (0<<3) ++#define S3C2410_WTCON_DIV32 (1<<3) ++#define S3C2410_WTCON_DIV64 (2<<3) ++#define S3C2410_WTCON_DIV128 (3<<3) ++ ++#define S3C2410_WTCON_PRESCALE(x) ((x) << 8) ++ ++#endif /* ASMARM_ARCH_S3C2410_WATCHDOG_H */ ++ ++ +--- linux-2.4.25/include/asm-arm/bugs.h~2.4.25-vrs2.patch 2000-09-19 00:15:23.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/bugs.h 2004-03-31 17:15:09.000000000 +0200 +@@ -10,8 +10,17 @@ + #ifndef __ASM_BUGS_H + #define __ASM_BUGS_H + ++#include <linux/config.h> + #include <asm/proc-fns.h> + +-#define check_bugs() cpu_check_bugs() ++extern void check_writebuffer_bugs(void); ++ ++static inline void check_bugs(void) ++{ ++#ifdef CONFIG_CPU_32 ++ check_writebuffer_bugs(); ++#endif ++ cpu_check_bugs(); ++} + + #endif +--- linux-2.4.25/include/asm-arm/div64.h~2.4.25-vrs2.patch 2000-01-13 22:30:31.000000000 +0100 ++++ linux-2.4.25/include/asm-arm/div64.h 2004-03-31 17:15:09.000000000 +0200 +@@ -4,9 +4,13 @@ + /* We're not 64-bit, but... */ + #define do_div(n,base) \ + ({ \ +- int __res; \ +- __res = ((unsigned long)n) % (unsigned int)base; \ +- n = ((unsigned long)n) / (unsigned int)base; \ ++ register int __res asm("r2") = base; \ ++ register unsigned long long __n asm("r0") = n; \ ++ asm("bl do_div64" \ ++ : "=r" (__n), "=r" (__res) \ ++ : "0" (__n), "1" (__res) \ ++ : "r3", "ip", "lr", "cc"); \ ++ n = __n; \ + __res; \ + }) + +--- linux-2.4.25/include/asm-arm/elf.h~2.4.25-vrs2.patch 2003-11-28 19:26:21.000000000 +0100 ++++ linux-2.4.25/include/asm-arm/elf.h 2004-03-31 17:15:09.000000000 +0200 +@@ -45,8 +45,8 @@ + + #define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) + +-/* When the program starts, a1 contains a pointer to a function to be +- registered with atexit, as per the SVR4 ABI. A value of 0 means we ++/* When the program starts, a1 contains a pointer to a function to be ++ registered with atexit, as per the SVR4 ABI. A value of 0 means we + have no such handler. */ + #define ELF_PLAT_INIT(_r, load_addr) (_r)->ARM_r0 = 0 + +--- linux-2.4.25/include/asm-arm/mach/dma.h~2.4.25-vrs2.patch 2003-08-25 13:44:43.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/mach/dma.h 2004-03-31 17:15:09.000000000 +0200 +@@ -41,6 +41,7 @@ + unsigned int dma_base; /* Controller base address */ + int dma_irq; /* Controller IRQ */ + struct scatterlist cur_sg; /* Current controller buffer */ ++ unsigned int state; /* RiscPC DMA status */ + + struct dma_ops *d_ops; + }; +--- linux-2.4.25/include/asm-arm/mach/serial_at91rm9200.h~2.4.25-vrs2.patch 2003-08-25 13:44:43.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/mach/serial_at91rm9200.h 2004-03-31 17:15:09.000000000 +0200 +@@ -10,7 +10,6 @@ + #include <linux/config.h> + + struct uart_port; +-struct uart_info; + + /* + * This is a temporary structure for registering these +@@ -22,11 +21,11 @@ + void (*enable_ms)(struct uart_port *); + void (*pm)(struct uart_port *, u_int, u_int); + int (*set_wake)(struct uart_port *, u_int); +- int (*open)(struct uart_port *, struct uart_info *); +- void (*close)(struct uart_port *, struct uart_info *); ++ int (*open)(struct uart_port *); ++ void (*close)(struct uart_port *); + }; + +-#if defined(CONFIG_SERIAL_AT91RM9200) ++#if defined(CONFIG_SERIAL_AT91) + void at91rm9200_register_uart_fns(struct at91rm9200_port_fns *fns); + void at91rm9200_register_uart(int idx, int port); + #else +--- linux-2.4.25/include/asm-arm/proc-armv/processor.h~2.4.25-vrs2.patch 2003-08-25 13:44:43.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/proc-armv/processor.h 2004-03-31 17:15:09.000000000 +0200 +@@ -54,7 +54,9 @@ + regs->ARM_cpsr = USR_MODE; \ + else \ + regs->ARM_cpsr = USR26_MODE; \ +- regs->ARM_pc = pc; /* pc */ \ ++ if (elf_hwcap & HWCAP_THUMB && pc & 1) \ ++ regs->ARM_cpsr |= PSR_T_BIT; \ ++ regs->ARM_pc = pc & ~1; /* pc */ \ + regs->ARM_sp = sp; /* sp */ \ + regs->ARM_r2 = stack[2]; /* r2 (envp) */ \ + regs->ARM_r1 = stack[1]; /* r1 (argv) */ \ +--- linux-2.4.25/include/asm-arm/proc-armv/ptrace.h~2.4.25-vrs2.patch 2000-11-28 02:07:59.000000000 +0100 ++++ linux-2.4.25/include/asm-arm/proc-armv/ptrace.h 2004-03-31 17:15:09.000000000 +0200 +@@ -33,6 +33,16 @@ + #define CC_N_BIT (1 << 31) + #define PCMASK 0 + ++/* 2.5 versions */ ++#define PSR_T_BIT 0x00000020 ++#define PSR_F_BIT 0x00000040 ++#define PSR_I_BIT 0x00000080 ++#define PSR_J_BIT 0x01000000 ++#define PSR_V_BIT 0x10000000 ++#define PSR_C_BIT 0x20000000 ++#define PSR_Z_BIT 0x40000000 ++#define PSR_N_BIT 0x80000000 ++ + #ifndef __ASSEMBLY__ + + /* this struct defines the way the registers are stored on the +--- linux-2.4.25/include/asm-arm/proc-armv/uaccess.h~2.4.25-vrs2.patch 2001-10-25 22:53:55.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/proc-armv/uaccess.h 2004-03-31 17:15:09.000000000 +0200 +@@ -12,12 +12,11 @@ + * Note that this is actually 0x1,0000,0000 + */ + #define KERNEL_DS 0x00000000 +-#define USER_DS PAGE_OFFSET ++#define USER_DS TASK_SIZE + + static inline void set_fs (mm_segment_t fs) + { + current->addr_limit = fs; +- + modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER); + } + +@@ -38,7 +37,7 @@ + : "cc"); \ + (flag == 0); }) + +-#define __put_user_asm_byte(x,addr,err) \ ++#define __put_user_asm_byte(x,__pu_addr,err) \ + __asm__ __volatile__( \ + "1: strbt %1,[%2],#0\n" \ + "2:\n" \ +@@ -51,18 +50,18 @@ + " .align 3\n" \ + " .long 1b, 3b\n" \ + " .previous" \ +- : "=r" (err) \ +- : "r" (x), "r" (addr), "i" (-EFAULT), "0" (err)) ++ : "+r" (err) \ ++ : "r" (x), "r" (__pu_addr), "i" (-EFAULT) \ ++ : "cc") + +-#define __put_user_asm_half(x,addr,err) \ ++#define __put_user_asm_half(x,__pu_addr,err) \ + ({ \ + unsigned long __temp = (unsigned long)(x); \ +- unsigned long __ptr = (unsigned long)(addr); \ +- __put_user_asm_byte(__temp, __ptr, err); \ +- __put_user_asm_byte(__temp >> 8, __ptr + 1, err); \ ++ __put_user_asm_byte(__temp, __pu_addr, err); \ ++ __put_user_asm_byte(__temp >> 8, __pu_addr + 1, err); \ + }) + +-#define __put_user_asm_word(x,addr,err) \ ++#define __put_user_asm_word(x,__pu_addr,err) \ + __asm__ __volatile__( \ + "1: strt %1,[%2],#0\n" \ + "2:\n" \ +@@ -75,8 +74,28 @@ + " .align 3\n" \ + " .long 1b, 3b\n" \ + " .previous" \ +- : "=r" (err) \ +- : "r" (x), "r" (addr), "i" (-EFAULT), "0" (err)) ++ : "+r" (err) \ ++ : "r" (x), "r" (__pu_addr), "i" (-EFAULT) \ ++ : "cc") ++ ++#define __put_user_asm_dword(x,__pu_addr,err) \ ++ __asm__ __volatile__( \ ++ "1: strt %R2, [%1], #4\n" \ ++ "2: strt %Q2, [%1], #0\n" \ ++ "3:\n" \ ++ " .section .fixup,\"ax\"\n" \ ++ " .align 2\n" \ ++ "4: mov %0, %3\n" \ ++ " b 3b\n" \ ++ " .previous\n" \ ++ " .section __ex_table,\"a\"\n" \ ++ " .align 3\n" \ ++ " .long 1b, 4b\n" \ ++ " .long 2b, 4b\n" \ ++ " .previous" \ ++ : "+r" (err), "+r" (__pu_addr) \ ++ : "r" (x), "i" (-EFAULT) \ ++ : "cc") + + #define __get_user_asm_byte(x,addr,err) \ + __asm__ __volatile__( \ +@@ -92,18 +111,18 @@ + " .align 3\n" \ + " .long 1b, 3b\n" \ + " .previous" \ +- : "=r" (err), "=&r" (x) \ +- : "r" (addr), "i" (-EFAULT), "0" (err)) ++ : "+r" (err), "=&r" (x) \ ++ : "r" (addr), "i" (-EFAULT) \ ++ : "cc") + +-#define __get_user_asm_half(x,addr,err) \ ++#define __get_user_asm_half(x,__gu_addr,err) \ + ({ \ +- unsigned long __b1, __b2, __ptr = (unsigned long)addr; \ +- __get_user_asm_byte(__b1, __ptr, err); \ +- __get_user_asm_byte(__b2, __ptr + 1, err); \ ++ unsigned long __b1, __b2; \ ++ __get_user_asm_byte(__b1, __gu_addr, err); \ ++ __get_user_asm_byte(__b2, __gu_addr + 1, err); \ + (x) = __b1 | (__b2 << 8); \ + }) + +- + #define __get_user_asm_word(x,addr,err) \ + __asm__ __volatile__( \ + "1: ldrt %1,[%2],#0\n" \ +@@ -118,8 +137,9 @@ + " .align 3\n" \ + " .long 1b, 3b\n" \ + " .previous" \ +- : "=r" (err), "=&r" (x) \ +- : "r" (addr), "i" (-EFAULT), "0" (err)) ++ : "+r" (err), "=&r" (x) \ ++ : "r" (addr), "i" (-EFAULT) \ ++ : "cc") + + extern unsigned long __arch_copy_from_user(void *to, const void *from, unsigned long n); + #define __do_copy_from_user(to,from,n) \ +--- linux-2.4.25/include/asm-arm/proc-fns.h~2.4.25-vrs2.patch 2003-08-25 13:44:43.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/proc-fns.h 2004-03-31 17:15:09.000000000 +0200 +@@ -76,6 +76,30 @@ + # define CPU_NAME arm926 + # endif + # endif ++# ifdef CONFIG_CPU_ARM1020 ++# ifdef CPU_NAME ++# undef MULTI_CPU ++# define MULTI_CPU ++# else ++# define CPU_NAME arm1020 ++# endif ++# endif ++# ifdef CONFIG_CPU_ARM1020E ++# ifdef CPU_NAME ++# undef MULTI_CPU ++# define MULTI_CPU ++# else ++# define CPU_NAME arm1020E ++# endif ++# endif ++# ifdef CONFIG_CPU_ARM1022 ++# ifdef CPU_NAME ++# undef MULTI_CPU ++# define MULTI_CPU ++# else ++# define CPU_NAME arm1022 ++# endif ++# endif + # ifdef CONFIG_CPU_ARM1026 + # ifdef CPU_NAME + # undef MULTI_CPU +--- linux-2.4.25/include/asm-arm/processor.h~2.4.25-vrs2.patch 2003-08-25 13:44:43.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/processor.h 2004-03-31 17:15:09.000000000 +0200 +@@ -43,6 +43,7 @@ + #include <asm/atomic.h> + #include <asm/ptrace.h> + #include <asm/arch/memory.h> ++#include <asm/elf.h> + #include <asm/proc/processor.h> + #include <asm/types.h> + +--- linux-2.4.25/include/asm-arm/system.h~2.4.25-vrs2.patch 2003-08-25 13:44:43.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/system.h 2004-03-31 17:15:09.000000000 +0200 +@@ -29,6 +29,10 @@ + + void die_if_kernel(const char *str, struct pt_regs *regs, int err); + ++void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, ++ struct pt_regs *), ++ int sig, const char *name); ++ + #include <asm/proc-fns.h> + + #define xchg(ptr,x) \ +@@ -89,6 +93,14 @@ + #define sti() local_irq_enable() + #define clf() __clf() + #define stf() __stf() ++ ++#define irqs_disabled() \ ++({ \ ++ unsigned long flags; \ ++ local_save_flags(flags); \ ++ flags & PSR_I_BIT; \ ++}) ++ + #define save_flags(x) local_save_flags(x) + #define restore_flags(x) local_irq_restore(x) + #define save_flags_cli(x) local_irq_save(x) +--- linux-2.4.25/include/asm-arm/termios.h~2.4.25-vrs2.patch 2001-06-12 04:15:27.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/termios.h 2004-03-31 17:15:09.000000000 +0200 +@@ -47,6 +47,8 @@ + #define TIOCM_OUT2 0x4000 + #define TIOCM_LOOP 0x8000 + ++#define TIOCM_MODEM_BITS TIOCM_OUT2 /* IRDA support */ ++ + /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ + + /* line disciplines */ +--- linux-2.4.25/include/asm-arm/uaccess.h~2.4.25-vrs2.patch 2001-10-25 22:53:55.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/uaccess.h 2004-03-31 17:15:09.000000000 +0200 +@@ -74,14 +74,14 @@ + __asm__ __volatile__ ("bl __get_user_" #__s \ + : "=&r" (__e), "=r" (__r1) \ + : "0" (__p) \ +- : __i) ++ : __i, "cc") + + #define get_user(x,p) \ + ({ \ + const register typeof(*(p)) *__p asm("r0") = (p); \ + register typeof(*(p)) __r1 asm("r1"); \ + register int __e asm("r0"); \ +- switch (sizeof(*(p))) { \ ++ switch (sizeof(*(__p))) { \ + case 1: \ + __get_user_x(__r1, __p, __e, 1, "lr"); \ + break; \ +@@ -100,8 +100,31 @@ + __e; \ + }) + +-#define __get_user(x,p) __get_user_nocheck((x),(p),sizeof(*(p))) +-#define __get_user_error(x,p,e) __get_user_nocheck_error((x),(p),sizeof(*(p)),(e)) ++#define __get_user(x,ptr) \ ++({ \ ++ long __gu_err = 0; \ ++ __get_user_err((x),(ptr),__gu_err); \ ++ __gu_err; \ ++}) ++ ++#define __get_user_error(x,ptr,err) \ ++({ \ ++ __get_user_err((x),(ptr),err); \ ++ (void) 0; \ ++}) ++ ++#define __get_user_err(x,ptr,err) \ ++do { \ ++ unsigned long __gu_addr = (unsigned long)(ptr); \ ++ unsigned long __gu_val; \ ++ switch (sizeof(*(ptr))) { \ ++ case 1: __get_user_asm_byte(__gu_val,__gu_addr,err); break; \ ++ case 2: __get_user_asm_half(__gu_val,__gu_addr,err); break; \ ++ case 4: __get_user_asm_word(__gu_val,__gu_addr,err); break; \ ++ default: (__gu_val) = __get_user_bad(); \ ++ } \ ++ (x) = (__typeof__(*(ptr)))__gu_val; \ ++} while (0) + + extern int __put_user_1(void *, unsigned int); + extern int __put_user_2(void *, unsigned int); +@@ -113,22 +136,22 @@ + __asm__ __volatile__ ("bl __put_user_" #__s \ + : "=&r" (__e) \ + : "0" (__p), "r" (__r1) \ +- : __i) ++ : __i, "cc") + + #define put_user(x,p) \ + ({ \ + const register typeof(*(p)) __r1 asm("r1") = (x); \ + const register typeof(*(p)) *__p asm("r0") = (p); \ + register int __e asm("r0"); \ +- switch (sizeof(*(p))) { \ ++ switch (sizeof(*(__p))) { \ + case 1: \ +- __put_user_x(__r1, __p, __e, 1, "r2", "lr"); \ ++ __put_user_x(__r1, __p, __e, 1, "ip", "lr"); \ + break; \ + case 2: \ +- __put_user_x(__r1, __p, __e, 2, "r2", "lr"); \ ++ __put_user_x(__r1, __p, __e, 2, "ip", "lr"); \ + break; \ + case 4: \ +- __put_user_x(__r1, __p, __e, 4, "r2", "lr"); \ ++ __put_user_x(__r1, __p, __e, 4, "ip", "lr"); \ + break; \ + case 8: \ + __put_user_x(__r1, __p, __e, 8, "ip", "lr"); \ +@@ -138,8 +161,31 @@ + __e; \ + }) + +-#define __put_user(x,p) __put_user_nocheck((__typeof(*(p)))(x),(p),sizeof(*(p))) +-#define __put_user_error(x,p,e) __put_user_nocheck_error((x),(p),sizeof(*(p)),(e)) ++#define __put_user(x,ptr) \ ++({ \ ++ long __pu_err = 0; \ ++ __put_user_err((x),(ptr),__pu_err); \ ++ __pu_err; \ ++}) ++ ++#define __put_user_error(x,ptr,err) \ ++({ \ ++ __put_user_err((x),(ptr),err); \ ++ (void) 0; \ ++}) ++ ++#define __put_user_err(x,ptr,err) \ ++do { \ ++ unsigned long __pu_addr = (unsigned long)(ptr); \ ++ __typeof__(*(ptr)) __pu_val = (x); \ ++ switch (sizeof(*(ptr))) { \ ++ case 1: __put_user_asm_byte(__pu_val,__pu_addr,err); break; \ ++ case 2: __put_user_asm_half(__pu_val,__pu_addr,err); break; \ ++ case 4: __put_user_asm_word(__pu_val,__pu_addr,err); break; \ ++ case 8: __put_user_asm_dword(__pu_val,__pu_addr,err); break; \ ++ default: __put_user_bad(); \ ++ } \ ++} while (0) + + static __inline__ unsigned long copy_from_user(void *to, const void *from, unsigned long n) + { +@@ -209,82 +255,4 @@ + return res; + } + +-/* +- * These are the work horses of the get/put_user functions +- */ +-#if 0 +-#define __get_user_check(x,ptr,size) \ +-({ \ +- long __gu_err = -EFAULT, __gu_val = 0; \ +- const __typeof__(*(ptr)) *__gu_addr = (ptr); \ +- if (access_ok(VERIFY_READ,__gu_addr,size)) { \ +- __gu_err = 0; \ +- __get_user_size(__gu_val,__gu_addr,(size),__gu_err); \ +- } \ +- (x) = (__typeof__(*(ptr)))__gu_val; \ +- __gu_err; \ +-}) +-#endif +- +-#define __get_user_nocheck(x,ptr,size) \ +-({ \ +- long __gu_err = 0, __gu_val; \ +- __get_user_size(__gu_val,(ptr),(size),__gu_err); \ +- (x) = (__typeof__(*(ptr)))__gu_val; \ +- __gu_err; \ +-}) +- +-#define __get_user_nocheck_error(x,ptr,size,err) \ +-({ \ +- long __gu_val; \ +- __get_user_size(__gu_val,(ptr),(size),(err)); \ +- (x) = (__typeof__(*(ptr)))__gu_val; \ +- (void) 0; \ +-}) +- +-#define __put_user_check(x,ptr,size) \ +-({ \ +- long __pu_err = -EFAULT; \ +- __typeof__(*(ptr)) *__pu_addr = (ptr); \ +- if (access_ok(VERIFY_WRITE,__pu_addr,size)) { \ +- __pu_err = 0; \ +- __put_user_size((x),__pu_addr,(size),__pu_err); \ +- } \ +- __pu_err; \ +-}) +- +-#define __put_user_nocheck(x,ptr,size) \ +-({ \ +- long __pu_err = 0; \ +- __typeof__(*(ptr)) *__pu_addr = (ptr); \ +- __put_user_size((x),__pu_addr,(size),__pu_err); \ +- __pu_err; \ +-}) +- +-#define __put_user_nocheck_error(x,ptr,size,err) \ +-({ \ +- __put_user_size((x),(ptr),(size),err); \ +- (void) 0; \ +-}) +- +-#define __get_user_size(x,ptr,size,retval) \ +-do { \ +- switch (size) { \ +- case 1: __get_user_asm_byte(x,ptr,retval); break; \ +- case 2: __get_user_asm_half(x,ptr,retval); break; \ +- case 4: __get_user_asm_word(x,ptr,retval); break; \ +- default: (x) = __get_user_bad(); \ +- } \ +-} while (0) +- +-#define __put_user_size(x,ptr,size,retval) \ +-do { \ +- switch (size) { \ +- case 1: __put_user_asm_byte(x,ptr,retval); break; \ +- case 2: __put_user_asm_half(x,ptr,retval); break; \ +- case 4: __put_user_asm_word(x,ptr,retval); break; \ +- default: __put_user_bad(); \ +- } \ +-} while (0) +- + #endif /* _ASMARM_UACCESS_H */ +--- linux-2.4.25/include/asm-arm/unistd.h~2.4.25-vrs2.patch 2003-08-25 13:44:43.000000000 +0200 ++++ linux-2.4.25/include/asm-arm/unistd.h 2004-03-31 17:15:09.000000000 +0200 +@@ -31,7 +31,7 @@ + #define __NR_write (__NR_SYSCALL_BASE+ 4) + #define __NR_open (__NR_SYSCALL_BASE+ 5) + #define __NR_close (__NR_SYSCALL_BASE+ 6) +-#define __NR_waitpid (__NR_SYSCALL_BASE+ 7) ++ /* 7 was sys_waitpid */ + #define __NR_creat (__NR_SYSCALL_BASE+ 8) + #define __NR_link (__NR_SYSCALL_BASE+ 9) + #define __NR_unlink (__NR_SYSCALL_BASE+ 10) +@@ -41,8 +41,8 @@ + #define __NR_mknod (__NR_SYSCALL_BASE+ 14) + #define __NR_chmod (__NR_SYSCALL_BASE+ 15) + #define __NR_lchown (__NR_SYSCALL_BASE+ 16) +-#define __NR_break (__NR_SYSCALL_BASE+ 17) +- ++ /* 17 was sys_break */ ++ /* 18 was sys_stat */ + #define __NR_lseek (__NR_SYSCALL_BASE+ 19) + #define __NR_getpid (__NR_SYSCALL_BASE+ 20) + #define __NR_mount (__NR_SYSCALL_BASE+ 21) +@@ -52,14 +52,14 @@ + #define __NR_stime (__NR_SYSCALL_BASE+ 25) + #define __NR_ptrace (__NR_SYSCALL_BASE+ 26) + #define __NR_alarm (__NR_SYSCALL_BASE+ 27) +- ++ /* 28 was sys_fstat */ + #define __NR_pause (__NR_SYSCALL_BASE+ 29) + #define __NR_utime (__NR_SYSCALL_BASE+ 30) +-#define __NR_stty (__NR_SYSCALL_BASE+ 31) +-#define __NR_gtty (__NR_SYSCALL_BASE+ 32) ++ /* 31 was sys_stty */ ++ /* 32 was sys_gtty */ + #define __NR_access (__NR_SYSCALL_BASE+ 33) + #define __NR_nice (__NR_SYSCALL_BASE+ 34) +-#define __NR_ftime (__NR_SYSCALL_BASE+ 35) ++ /* 35 was sys_ftime */ + #define __NR_sync (__NR_SYSCALL_BASE+ 36) + #define __NR_kill (__NR_SYSCALL_BASE+ 37) + #define __NR_rename (__NR_SYSCALL_BASE+ 38) +@@ -68,22 +68,23 @@ + #define __NR_dup (__NR_SYSCALL_BASE+ 41) + #define __NR_pipe (__NR_SYSCALL_BASE+ 42) + #define __NR_times (__NR_SYSCALL_BASE+ 43) +-#define __NR_prof (__NR_SYSCALL_BASE+ 44) ++ /* 44 was sys_prof */ + #define __NR_brk (__NR_SYSCALL_BASE+ 45) + #define __NR_setgid (__NR_SYSCALL_BASE+ 46) + #define __NR_getgid (__NR_SYSCALL_BASE+ 47) +-#define __NR_signal (__NR_SYSCALL_BASE+ 48) ++ /* 48 was sys_signal */ + #define __NR_geteuid (__NR_SYSCALL_BASE+ 49) + #define __NR_getegid (__NR_SYSCALL_BASE+ 50) + #define __NR_acct (__NR_SYSCALL_BASE+ 51) + #define __NR_umount2 (__NR_SYSCALL_BASE+ 52) +-#define __NR_lock (__NR_SYSCALL_BASE+ 53) ++ /* 53 was sys_lock */ + #define __NR_ioctl (__NR_SYSCALL_BASE+ 54) + #define __NR_fcntl (__NR_SYSCALL_BASE+ 55) +-#define __NR_mpx (__NR_SYSCALL_BASE+ 56) ++ /* 56 was sys_mpx */ + #define __NR_setpgid (__NR_SYSCALL_BASE+ 57) + #define __NR_ulimit (__NR_SYSCALL_BASE+ 58) +- ++ /* 58 was sys_ulimit */ ++ /* 59 was sys_olduname */ + #define __NR_umask (__NR_SYSCALL_BASE+ 60) + #define __NR_chroot (__NR_SYSCALL_BASE+ 61) + #define __NR_ustat (__NR_SYSCALL_BASE+ 62) +@@ -92,8 +93,8 @@ + #define __NR_getpgrp (__NR_SYSCALL_BASE+ 65) + #define __NR_setsid (__NR_SYSCALL_BASE+ 66) + #define __NR_sigaction (__NR_SYSCALL_BASE+ 67) +-#define __NR_sgetmask (__NR_SYSCALL_BASE+ 68) +-#define __NR_ssetmask (__NR_SYSCALL_BASE+ 69) ++ /* 68 was sys_sgetmask */ ++ /* 69 was sys_ssetmask */ + #define __NR_setreuid (__NR_SYSCALL_BASE+ 70) + #define __NR_setregid (__NR_SYSCALL_BASE+ 71) + #define __NR_sigsuspend (__NR_SYSCALL_BASE+ 72) +@@ -108,7 +109,7 @@ + #define __NR_setgroups (__NR_SYSCALL_BASE+ 81) + #define __NR_select (__NR_SYSCALL_BASE+ 82) + #define __NR_symlink (__NR_SYSCALL_BASE+ 83) +- ++ /* 84 was sys_lstat */ + #define __NR_readlink (__NR_SYSCALL_BASE+ 85) + #define __NR_uselib (__NR_SYSCALL_BASE+ 86) + #define __NR_swapon (__NR_SYSCALL_BASE+ 87) +@@ -122,10 +123,10 @@ + #define __NR_fchown (__NR_SYSCALL_BASE+ 95) + #define __NR_getpriority (__NR_SYSCALL_BASE+ 96) + #define __NR_setpriority (__NR_SYSCALL_BASE+ 97) +-#define __NR_profil (__NR_SYSCALL_BASE+ 98) ++ /* 98 was sys_profil */ + #define __NR_statfs (__NR_SYSCALL_BASE+ 99) + #define __NR_fstatfs (__NR_SYSCALL_BASE+100) +-#define __NR_ioperm (__NR_SYSCALL_BASE+101) ++ /* 101 was sys_ioperm */ + #define __NR_socketcall (__NR_SYSCALL_BASE+102) + #define __NR_syslog (__NR_SYSCALL_BASE+103) + #define __NR_setitimer (__NR_SYSCALL_BASE+104) +@@ -133,10 +134,10 @@ + #define __NR_stat (__NR_SYSCALL_BASE+106) + #define __NR_lstat (__NR_SYSCALL_BASE+107) + #define __NR_fstat (__NR_SYSCALL_BASE+108) +- +- ++ /* 109 was sys_uname */ ++ /* 110 was sys_iopl */ + #define __NR_vhangup (__NR_SYSCALL_BASE+111) +-#define __NR_idle (__NR_SYSCALL_BASE+112) ++ /* 112 was sys_idle */ + #define __NR_syscall (__NR_SYSCALL_BASE+113) /* syscall to call a syscall! */ + #define __NR_wait4 (__NR_SYSCALL_BASE+114) + #define __NR_swapoff (__NR_SYSCALL_BASE+115) +@@ -147,7 +148,7 @@ + #define __NR_clone (__NR_SYSCALL_BASE+120) + #define __NR_setdomainname (__NR_SYSCALL_BASE+121) + #define __NR_uname (__NR_SYSCALL_BASE+122) +-#define __NR_modify_ldt (__NR_SYSCALL_BASE+123) ++ /* 123 was sys_modify_ldt */ + #define __NR_adjtimex (__NR_SYSCALL_BASE+124) + #define __NR_mprotect (__NR_SYSCALL_BASE+125) + #define __NR_sigprocmask (__NR_SYSCALL_BASE+126) +@@ -161,7 +162,7 @@ + #define __NR_bdflush (__NR_SYSCALL_BASE+134) + #define __NR_sysfs (__NR_SYSCALL_BASE+135) + #define __NR_personality (__NR_SYSCALL_BASE+136) +-#define __NR_afs_syscall (__NR_SYSCALL_BASE+137) /* Syscall for Andrew File System */ ++ /* 137 was sys_afs_syscall */ + #define __NR_setfsuid (__NR_SYSCALL_BASE+138) + #define __NR_setfsgid (__NR_SYSCALL_BASE+139) + #define __NR__llseek (__NR_SYSCALL_BASE+140) +@@ -190,7 +191,7 @@ + #define __NR_mremap (__NR_SYSCALL_BASE+163) + #define __NR_setresuid (__NR_SYSCALL_BASE+164) + #define __NR_getresuid (__NR_SYSCALL_BASE+165) +-#define __NR_vm86 (__NR_SYSCALL_BASE+166) ++ /* 166 was sys_vm86 */ + #define __NR_query_module (__NR_SYSCALL_BASE+167) + #define __NR_poll (__NR_SYSCALL_BASE+168) + #define __NR_nfsservctl (__NR_SYSCALL_BASE+169) +--- linux-2.4.25/include/asm-i386/ide.h~2.4.25-vrs2.patch 2003-06-13 16:51:38.000000000 +0200 ++++ linux-2.4.25/include/asm-i386/ide.h 2004-03-31 17:15:09.000000000 +0200 +@@ -23,39 +23,15 @@ + # endif + #endif + +-static __inline__ int ide_default_irq(ide_ioreg_t base) +-{ +- switch (base) { +- case 0x1f0: return 14; +- case 0x170: return 15; +- case 0x1e8: return 11; +- case 0x168: return 10; +- case 0x1e0: return 8; +- case 0x160: return 12; +- default: +- return 0; +- } +-} +- +-static __inline__ ide_ioreg_t ide_default_io_base(int index) +-{ +- switch (index) { +- case 0: return 0x1f0; +- case 1: return 0x170; +- case 2: return 0x1e8; +- case 3: return 0x168; +- case 4: return 0x1e0; +- case 5: return 0x160; +- default: +- return 0; +- } +-} ++#define ide_default_io_base(i) ((ide_ioreg_t)0) ++#define ide_default_irq(b) (0) + + static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) + { + ide_ioreg_t reg = data_port; + int i; + ++ memset(hw, 0, sizeof(*hw)); + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg; + reg += 1; +@@ -63,7 +39,7 @@ + if (ctrl_port) { + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; + } else { +- hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206; ++ hw->io_ports[IDE_CONTROL_OFFSET] = data_port + 0x206; + } + if (irq != NULL) + *irq = 0; +@@ -74,14 +50,25 @@ + { + #ifndef CONFIG_BLK_DEV_IDEPCI + hw_regs_t hw; +- int index; + +- for(index = 0; index < MAX_HWIFS; index++) { +- memset(&hw, 0, sizeof hw); +- ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL); +- hw.irq = ide_default_irq(ide_default_io_base(index)); +- ide_register_hw(&hw, NULL); +- } ++ ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL); ++ hw.irq = 14; ++ ide_register_hw(&hw, NULL); ++ ide_init_hwif_ports(&hw, 0x170, 0x376, NULL); ++ hw.irq = 15; ++ ide_register_hw(&hw, NULL); ++ ide_init_hwif_ports(&hw, 0x1e8, 0x3ee, NULL); ++ hw.irq = 11; ++ ide_register_hw(&hw, NULL); ++ ide_init_hwif_ports(&hw, 0x168, 0x36e, NULL); ++ hw.irq = 10; ++ ide_register_hw(&hw, NULL); ++ ide_init_hwif_ports(&hw, 0x1e0, 0x3e6, NULL); ++ hw.irq = 8; ++ ide_register_hw(&hw, NULL); ++ ide_init_hwif_ports(&hw, 0x160, 0x366, NULL); ++ hw.irq = 12; ++ ide_register_hw(&hw, NULL); + #endif /* CONFIG_BLK_DEV_IDEPCI */ + } + +--- linux-2.4.25/include/asm-i386/param.h~2.4.25-vrs2.patch 2000-10-27 20:04:43.000000000 +0200 ++++ linux-2.4.25/include/asm-i386/param.h 2004-03-31 17:15:09.000000000 +0200 +@@ -3,6 +3,16 @@ + + #ifndef HZ + #define HZ 100 ++#ifdef __KERNEL__ ++#if HZ == 100 ++/* X86 is defined to provide userspace with a world where HZ=100 ++ We have to do this, (x*const)/const2 isnt optimised out because its not ++ a null operation as it might overflow.. */ ++#define hz_to_std(a) (a) ++#else ++#define hz_to_std(a) ((a)*(100/HZ)+((a)*(100%HZ))/HZ) ++#endif ++#endif + #endif + + #define EXEC_PAGESIZE 4096 +--- linux-2.4.25/include/asm-i386/pgtable.h~2.4.25-vrs2.patch 2002-11-29 00:53:15.000000000 +0100 ++++ linux-2.4.25/include/asm-i386/pgtable.h 2004-03-31 17:15:09.000000000 +0200 +@@ -361,7 +361,6 @@ + #endif /* !__ASSEMBLY__ */ + + /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ +-#define PageSkip(page) (0) + #define kern_addr_valid(addr) (1) + + #define io_remap_page_range remap_page_range +--- linux-2.4.25/include/asm-ia64/param.h~2.4.25-vrs2.patch 2004-02-18 14:36:32.000000000 +0100 ++++ linux-2.4.25/include/asm-ia64/param.h 2004-03-31 17:15:09.000000000 +0200 +@@ -8,6 +8,10 @@ + * David Mosberger-Tang <davidm@hpl.hp.com> + */ + ++#ifdef __KERNEL__ ++#define hz_to_std(a) (a) ++#endif ++ + #define EXEC_PAGESIZE 65536 + + #ifndef NGROUPS +--- linux-2.4.25/include/asm-m68k/param.h~2.4.25-vrs2.patch 2001-01-04 22:00:55.000000000 +0100 ++++ linux-2.4.25/include/asm-m68k/param.h 2004-03-31 17:15:09.000000000 +0200 +@@ -3,6 +3,9 @@ + + #ifndef HZ + #define HZ 100 ++#ifdef __KERNEL__ ++#define hz_to_std(a) (a) ++#endif + #endif + + #define EXEC_PAGESIZE 8192 +--- linux-2.4.25/include/asm-mips/ide.h~2.4.25-vrs2.patch 2003-08-25 13:44:43.000000000 +0200 ++++ linux-2.4.25/include/asm-mips/ide.h 2004-03-31 17:15:09.000000000 +0200 +@@ -27,7 +27,7 @@ + int (*ide_default_irq)(ide_ioreg_t base); + ide_ioreg_t (*ide_default_io_base)(int index); + void (*ide_init_hwif_ports)(hw_regs_t *hw, ide_ioreg_t data_port, +- ide_ioreg_t ctrl_port, int *irq); ++ ide_ioreg_t ctrl_port, int *irq); + }; + + extern struct ide_ops *ide_ops; +--- linux-2.4.25/include/asm-ppc/param.h~2.4.25-vrs2.patch 2003-06-13 16:51:38.000000000 +0200 ++++ linux-2.4.25/include/asm-ppc/param.h 2004-03-31 17:15:09.000000000 +0200 +@@ -3,6 +3,9 @@ + + #ifndef HZ + #define HZ 100 ++#ifdef __KERNEL__ ++#define hz_to_std(a) (a) ++#endif + #endif + + #define EXEC_PAGESIZE 4096 +--- linux-2.4.25/include/asm-s390/param.h~2.4.25-vrs2.patch 2001-02-13 23:13:44.000000000 +0100 ++++ linux-2.4.25/include/asm-s390/param.h 2004-03-31 17:15:09.000000000 +0200 +@@ -11,6 +11,9 @@ + + #ifndef HZ + #define HZ 100 ++#ifdef __KERNEL__ ++#define hz_to_std(a) (a) ++#endif + #endif + + #define EXEC_PAGESIZE 4096 +--- linux-2.4.25/include/asm-sh/param.h~2.4.25-vrs2.patch 2001-01-04 22:19:13.000000000 +0100 ++++ linux-2.4.25/include/asm-sh/param.h 2004-03-31 17:15:09.000000000 +0200 +@@ -3,6 +3,9 @@ + + #ifndef HZ + #define HZ 100 ++#ifdef __KERNEL__ ++#define hz_to_std(a) (a) ++#endif + #endif + + #define EXEC_PAGESIZE 4096 +--- linux-2.4.25/include/asm-sparc/param.h~2.4.25-vrs2.patch 2000-10-30 23:34:12.000000000 +0100 ++++ linux-2.4.25/include/asm-sparc/param.h 2004-03-31 17:15:09.000000000 +0200 +@@ -4,6 +4,9 @@ + + #ifndef HZ + #define HZ 100 ++#ifdef __KERNEL__ ++#define hz_to_std(a) (a) ++#endif + #endif + + #define EXEC_PAGESIZE 8192 /* Thanks for sun4's we carry baggage... */ +--- linux-2.4.25/include/asm-sparc64/ide.h~2.4.25-vrs2.patch 2003-06-13 16:51:38.000000000 +0200 ++++ linux-2.4.25/include/asm-sparc64/ide.h 2004-03-31 17:15:09.000000000 +0200 +@@ -25,21 +25,12 @@ + # endif + #endif + +-static __inline__ int ide_default_irq(ide_ioreg_t base) +-{ +- return 0; +-} +- +-static __inline__ ide_ioreg_t ide_default_io_base(int index) +-{ +- return 0; +-} +- + static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) + { +- ide_ioreg_t reg = data_port; ++ ide_ioreg_t reg = data_port; + int i; + ++ memset(&hw, 0, sizeof(hw)); + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg; + reg += 1; +@@ -60,16 +51,6 @@ + */ + static __inline__ void ide_init_default_hwifs(void) + { +-#ifndef CONFIG_BLK_DEV_IDEPCI +- hw_regs_t hw; +- int index; +- +- for (index = 0; index < MAX_HWIFS; index++) { +- ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL); +- hw.irq = ide_default_irq(ide_default_io_base(index)); +- ide_register_hw(&hw, NULL); +- } +-#endif /* CONFIG_BLK_DEV_IDEPCI */ + } + + #undef SUPPORT_SLOW_DATA_PORTS +--- linux-2.4.25/include/asm-sparc64/param.h~2.4.25-vrs2.patch 2000-10-30 23:34:12.000000000 +0100 ++++ linux-2.4.25/include/asm-sparc64/param.h 2004-03-31 17:15:09.000000000 +0200 +@@ -4,6 +4,9 @@ + + #ifndef HZ + #define HZ 100 ++#ifdef __KERNEL__ ++#define hz_to_std(a) (a) ++#endif + #endif + + #define EXEC_PAGESIZE 8192 /* Thanks for sun4's we carry baggage... */ +--- linux-2.4.25/include/linux/console_struct.h~2.4.25-vrs2.patch 2003-06-13 16:51:38.000000000 +0200 ++++ linux-2.4.25/include/linux/console_struct.h 2004-03-31 17:15:09.000000000 +0200 +@@ -7,6 +7,8 @@ + * Fields marked with [#] must be set by the low-level driver. + * Fields marked with [!] can be changed by the low-level driver + * to achieve effects such as fast scrolling by changing the origin. ++ * ++ * 11/07/1998 RMK Changed vc_state to be a function pointer + */ + + #ifndef _LINUX_CONSOLE_STRUCT_H_ +@@ -34,7 +36,11 @@ + unsigned short vc_s_complement_mask; /* Saved mouse pointer mask */ + unsigned int vc_x, vc_y; /* Cursor position */ + unsigned int vc_top, vc_bottom; /* Scrolling region */ ++#ifdef CONSOLE_WIP ++ int (*vc_state)(int currcons, struct tty_struct *tty, unsigned int c); ++#else + unsigned int vc_state; /* Escape sequence parser state */ ++#endif + unsigned int vc_npar,vc_par[NPAR]; /* Parameters of current escape sequence */ + unsigned long vc_origin; /* [!] Start of real screen */ + unsigned long vc_scr_end; /* [!] End of real screen */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/linux/cpufreq.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,94 @@ ++/* ++ * linux/include/linux/cpufreq.h ++ * ++ * Copyright (C) 2001 Russell King ++ * ++ * $Id$ ++ * ++ * 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 _LINUX_CPUFREQ_H ++#define _LINUX_CPUFREQ_H ++ ++#include <linux/config.h> ++#include <linux/notifier.h> ++ ++#ifndef CONFIG_SMP ++#define cpufreq_current(cpu) ((void)(cpu), __cpufreq_cur) ++#define cpufreq_max(cpu) ((void)(cpu), __cpufreq_max) ++#define cpufreq_min(cpu) ((void)(cpu), __cpufreq_min) ++#else ++/* ++ * Should be something like: ++ * ++ * typedef struct { ++ * u_int current; ++ * u_int max; ++ * u_int min; ++ * } __cacheline_aligned cpufreq_info_t; ++ * ++ * static cpufreq_info_t cpufreq_info; ++ * ++ * #define cpufreq_current(cpu) (cpufreq_info[cpu].current) ++ * #define cpufreq_max(cpu) (cpufreq_info[cpu].max) ++ * #define cpufreq_min(cpu) (cpufreq_info[cpu].min) ++ * ++ * Maybe we should find some other per-cpu structure to ++ * bury this in? ++ */ ++#error fill in SMP version ++#endif ++ ++struct cpufreq_info { ++ unsigned int old_freq; ++ unsigned int new_freq; ++}; ++ ++/* ++ * The max and min frequency rates that the registered device ++ * can tolerate. Never set any element this structure directly - ++ * always use cpu_updateminmax. ++ */ ++struct cpufreq_minmax { ++ unsigned int min_freq; ++ unsigned int max_freq; ++ unsigned int cur_freq; ++ unsigned int new_freq; ++}; ++ ++static inline ++void cpufreq_updateminmax(void *arg, unsigned int min, unsigned int max) ++{ ++ struct cpufreq_minmax *minmax = arg; ++ ++ if (minmax->min_freq < min) ++ minmax->min_freq = min; ++ if (minmax->max_freq > max) ++ minmax->max_freq = max; ++} ++ ++#define CPUFREQ_MINMAX (0) ++#define CPUFREQ_PRECHANGE (1) ++#define CPUFREQ_POSTCHANGE (2) ++ ++int cpufreq_register_notifier(struct notifier_block *nb); ++int cpufreq_unregister_notifier(struct notifier_block *nb); ++ ++int cpufreq_setmax(void); ++int cpufreq_restore(void); ++int cpufreq_set(unsigned int khz); ++unsigned int cpufreq_get(int cpu); ++ ++/* ++ * These two functions are only available at init time. ++ */ ++void cpufreq_init(unsigned int khz, ++ unsigned int min_freq, ++ unsigned int max_freq); ++ ++void cpufreq_setfunctions(unsigned int (*validate)(unsigned int), ++ void (*setspeed)(unsigned int)); ++ ++#endif +--- linux-2.4.25/include/linux/i2c-id.h~2.4.25-vrs2.patch 2004-02-18 14:36:32.000000000 +0100 ++++ linux-2.4.25/include/linux/i2c-id.h 2004-03-31 17:15:09.000000000 +0200 +@@ -20,16 +20,16 @@ + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + /* ------------------------------------------------------------------------- */ + +-/* $Id$ */ ++/* $Id$ */ + + #ifndef I2C_ID_H + #define I2C_ID_H + /* + * This file is part of the i2c-bus package and contains the identifier + * values for drivers, adapters and other folk populating these serial +- * worlds. ++ * worlds. + * +- * These will change often (i.e. additions) , therefore this has been ++ * These will change often (i.e. additions) , therefore this has been + * separated from the functional interface definitions of the i2c api. + * + */ +@@ -38,10 +38,10 @@ + * ---- Driver types ----------------------------------------------------- + * device id name + number function description, i2c address(es) + * +- * Range 1000-1999 range is defined in sensors/sensors.h +- * Range 0x100 - 0x1ff is for V4L2 Common Components ++ * Range 1000-1999 range is defined in sensors/sensors.h ++ * Range 0x100 - 0x1ff is for V4L2 Common Components + * Range 0xf000 - 0xffff is reserved for local experimentation, and should +- * never be used in official drivers ++ * never be used in official drivers + */ + + #define I2C_DRIVERID_MSP3400 1 +@@ -90,7 +90,12 @@ + #define I2C_DRIVERID_DRP3510 43 /* ADR decoder (Astra Radio) */ + #define I2C_DRIVERID_SP5055 44 /* Satellite tuner */ + #define I2C_DRIVERID_STV0030 45 /* Multipurpose switch */ ++#define I2C_DRIVERID_SAA7108 46 /* video decoder, image scaler */ ++#define I2C_DRIVERID_DS1307 47 /* DS1307 real time clock */ + #define I2C_DRIVERID_ADV7175 48 /* ADV 7175/7176 video encoder */ ++#define I2C_DRIVERID_ZR36067 49 /* Zoran 36067 video encoder */ ++#define I2C_DRIVERID_ZR36120 50 /* Zoran 36120 video encoder */ ++#define I2C_DRIVERID_24LC32A 51 /* Microchip 24LC32A 32k EEPROM */ + #define I2C_DRIVERID_MAX1617 56 /* temp sensor */ + #define I2C_DRIVERID_SAA7191 57 /* video decoder */ + #define I2C_DRIVERID_INDYCAM 58 /* SGI IndyCam */ +@@ -102,8 +107,10 @@ + + #define I2C_DRIVERID_I2CDEV 900 + #define I2C_DRIVERID_I2CPROC 901 ++#define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ ++#define I2C_DRIVERID_ALERT 903 /* SMBus Alert Responder Client */ + +-/* IDs -- Use DRIVERIDs 1000-1999 for sensors. ++/* IDs -- Use DRIVERIDs 1000-1999 for sensors. + These were originally in sensors.h in the lm_sensors package */ + #define I2C_DRIVERID_LM78 1002 + #define I2C_DRIVERID_LM75 1003 +@@ -131,6 +138,12 @@ + #define I2C_DRIVERID_ADM1024 1025 + #define I2C_DRIVERID_IT87 1026 + #define I2C_DRIVERID_CH700X 1027 /* single driver for CH7003-7009 digital pc to tv encoders */ ++#define I2C_DRIVERID_FSCPOS 1028 ++#define I2C_DRIVERID_FSCSCY 1029 ++#define I2C_DRIVERID_PCF8591 1030 ++#define I2C_DRIVERID_SMSC47M1 1031 ++#define I2C_DRIVERID_VT1211 1032 ++#define I2C_DRIVERID_LM92 1033 + + /* + * ---- Adapter types ---------------------------------------------------- +@@ -147,7 +160,8 @@ + #define I2C_ALGO_ISA 0x050000 /* lm_sensors ISA pseudo-adapter */ + #define I2C_ALGO_SAA7146 0x060000 /* SAA 7146 video decoder bus */ + #define I2C_ALGO_ACB 0x070000 /* ACCESS.bus algorithm */ +- ++#define I2C_ALGO_IIC 0x080000 /* ITE IIC bus */ ++#define I2C_ALGO_SAA7134 0x090000 + #define I2C_ALGO_EC 0x100000 /* ACPI embedded controller */ + + #define I2C_ALGO_MPC8XX 0x110000 /* MPC8xx PowerPC I2C algorithm */ +@@ -156,13 +170,15 @@ + + #define I2C_ALGO_SGI 0x130000 /* SGI algorithm */ + ++#define I2C_ALGO_OCP 0x120000 /* IBM or otherwise On-chip I2C algorithm */ ++ + #define I2C_ALGO_EXP 0x800000 /* experimental */ + + #define I2C_ALGO_MASK 0xff0000 /* Mask for algorithms */ + #define I2C_ALGO_SHIFT 0x10 /* right shift to get index values */ + + #define I2C_HW_ADAPS 0x10000 /* # adapter types */ +-#define I2C_HW_MASK 0xffff ++#define I2C_HW_MASK 0xffff + + + /* hw specific modules that are defined per algorithm layer +@@ -182,9 +198,13 @@ + #define I2C_HW_B_I810 0x0a /* Intel I810 */ + #define I2C_HW_B_VOO 0x0b /* 3dfx Voodoo 3 / Banshee */ + #define I2C_HW_B_PPORT 0x0c /* Primitive parallel port adapter */ ++#define I2C_HW_B_SAVG 0x0d /* Savage 4 */ + #define I2C_HW_B_RIVA 0x10 /* Riva based graphics cards */ + #define I2C_HW_B_IOC 0x11 /* IOC bit-wiggling */ + #define I2C_HW_B_TSUNA 0x12 /* DEC Tsunami chipset */ ++#define I2C_HW_B_FRODO 0x13 /* 2d3D, Inc. SA-1110 Development Board */ ++#define I2C_HW_B_OMAHA 0x14 /* Omaha I2C interface */ ++#define I2C_HW_B_GUIDE 0x15 /* Guide bit-basher */ + + /* --- PCF 8584 based algorithms */ + #define I2C_HW_P_LP 0x00 /* Parallel port interface */ +@@ -197,6 +217,12 @@ + /* --- MPC8xx PowerPC adapters */ + #define I2C_HW_MPC8XX_EPON 0x00 /* Eponymous MPC8xx I2C adapter */ + ++/* --- ITE based algorithms */ ++#define I2C_HW_I_IIC 0x00 /* controller on the ITE */ ++ ++/* --- PowerPC on-chip adapters */ ++#define I2C_HW_OCP 0x00 /* IBM on-chip I2C adapter */ ++ + /* --- Broadcom SiByte adapters */ + #define I2C_HW_SIBYTE 0x00 + +--- linux-2.4.25/include/linux/ide.h~2.4.25-vrs2.patch 2003-11-28 19:26:21.000000000 +0100 ++++ linux-2.4.25/include/linux/ide.h 2004-03-31 17:15:09.000000000 +0200 +@@ -287,7 +287,9 @@ + * Check for an interrupt and acknowledge the interrupt status + */ + struct hwif_s; ++struct ide_drive_s; + typedef int (ide_ack_intr_t)(struct hwif_s *); ++typedef void (ide_xfer_data_t)(struct ide_drive_s *, void *, unsigned int); + + #ifndef NO_DMA + #define NO_DMA 255 +@@ -311,10 +313,14 @@ + typedef struct hw_regs_s { + ide_ioreg_t io_ports[IDE_NR_PORTS]; /* task file registers */ + int irq; /* our irq number */ +- int dma; /* our dma entry */ ++ int dma; /* our dma number */ + ide_ack_intr_t *ack_intr; /* acknowledge interrupt */ ++ ide_xfer_data_t *ide_output_data; /* write data to i/face */ ++ ide_xfer_data_t *ide_input_data; /* read data from i/face */ ++ ide_xfer_data_t *atapi_output_bytes; /* write bytes to i/face */ ++ ide_xfer_data_t *atapi_input_bytes; /* read bytes from i/face */ + void *priv; /* interface specific data */ +- hwif_chipset_t chipset; ++ hwif_chipset_t chipset; + sata_ioreg_t sata_scr[SATA_NR_PORTS]; + sata_ioreg_t sata_misc[SATA_NR_PORTS]; + } hw_regs_t; +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/linux/l3/algo-bit.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,39 @@ ++/* ++ * linux/include/linux/l3/algo-bit.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. ++ * ++ * L3 Bus bit-banging algorithm. Derived from i2c-algo-bit.h by ++ * Simon G. Vogl. ++ */ ++#ifndef L3_ALGO_BIT_H ++#define L3_ALGO_BIT_H 1 ++ ++#include <linux/l3/l3.h> ++ ++struct l3_algo_bit_data { ++ void (*setdat) (void *data, int state); ++ void (*setclk) (void *data, int state); ++ void (*setmode)(void *data, int state); ++ void (*setdir) (void *data, int in); /* set data direction */ ++ int (*getdat) (void *data); ++ ++ void *data; ++ ++ /* bus timings (us) */ ++ int data_hold; ++ int data_setup; ++ int clock_high; ++ int mode_hold; ++ int mode_setup; ++ int mode; ++}; ++ ++int l3_bit_add_bus(struct l3_adapter *); ++int l3_bit_del_bus(struct l3_adapter *); ++ ++#endif +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/linux/l3/l3.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,208 @@ ++/* ++ * linux/include/linux/l3/l3.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. ++ * ++ * Derived from i2c.h by Simon G. Vogl ++ */ ++#ifndef L3_H ++#define L3_H ++ ++struct l3_msg { ++ unsigned char addr; /* slave address */ ++ unsigned char flags; ++#define L3_M_RD 0x01 ++#define L3_M_NOADDR 0x02 ++ unsigned short len; /* msg length */ ++ unsigned char *buf; /* pointer to msg data */ ++}; ++ ++#ifdef __KERNEL__ ++ ++#include <linux/types.h> ++#include <linux/list.h> ++ ++struct l3_client; ++ ++struct l3_ops { ++ int (*open)(struct l3_client *); ++ int (*command)(struct l3_client *, int cmd, void *arg); ++ void (*close)(struct l3_client *); ++}; ++ ++/* ++ * A driver is capable of handling one or more physical devices present on ++ * L3 adapters. This information is used to inform the driver of adapter ++ * events. ++ */ ++struct l3_driver { ++ /* ++ * This name is used to uniquely identify the driver. ++ * It should be the same as the module name. ++ */ ++ char name[32]; ++ ++ /* ++ * Notifies the driver that a new client wishes to use its ++ * services. Note that the module use count will be increased ++ * prior to this function being called. In addition, the ++ * clients driver and adapter fields will have been setup. ++ */ ++ int (*attach_client)(struct l3_client *); ++ ++ /* ++ * Notifies the driver that the client has finished with its ++ * services, and any memory that it allocated for this client ++ * should be cleaned up. In addition the chip should be ++ * shut down. ++ */ ++ void (*detach_client)(struct l3_client *); ++ ++ /* ++ * Possible operations on the driver. ++ */ ++ struct l3_ops *ops; ++ ++ /* ++ * Module structure, if any. ++ */ ++ struct module *owner; ++ ++ /* ++ * drivers list ++ */ ++ struct list_head drivers; ++}; ++ ++struct l3_adapter; ++ ++struct l3_algorithm { ++ /* textual description */ ++ char name[32]; ++ ++ /* perform bus transactions */ ++ int (*xfer)(struct l3_adapter *, struct l3_msg msgs[], int num); ++}; ++ ++struct semaphore; ++ ++/* ++ * l3_adapter is the structure used to identify a physical L3 bus along ++ * with the access algorithms necessary to access it. ++ */ ++struct l3_adapter { ++ /* ++ * This name is used to uniquely identify the adapter. ++ * It should be the same as the module name. ++ */ ++ char name[32]; ++ ++ /* ++ * the algorithm to access the bus ++ */ ++ struct l3_algorithm *algo; ++ ++ /* ++ * Algorithm specific data ++ */ ++ void *algo_data; ++ ++ /* ++ * This may be NULL, or should point to the module struct ++ */ ++ struct module *owner; ++ ++ /* ++ * private data for the adapter ++ */ ++ void *data; ++ ++ /* ++ * Our lock. Unlike the i2c layer, we allow this to be used for ++ * other stuff, like the i2c layer lock. Some people implement ++ * i2c stuff using the same signals as the l3 bus. ++ */ ++ struct semaphore *lock; ++ ++ /* ++ * List of attached clients. ++ */ ++ struct list_head clients; ++ ++ /* ++ * List of all adapters. ++ */ ++ struct list_head adapters; ++}; ++ ++/* ++ * l3_client identifies a single device (i.e. chip) that is connected to an ++ * L3 bus. The behaviour is defined by the routines of the driver. This ++ * function is mainly used for lookup & other admin. functions. ++ */ ++struct l3_client { ++ struct l3_adapter *adapter; /* the adapter we sit on */ ++ struct l3_driver *driver; /* and our access routines */ ++ void *driver_data; /* private driver data */ ++ struct list_head __adap; ++}; ++ ++ ++extern int l3_add_adapter(struct l3_adapter *); ++extern int l3_del_adapter(struct l3_adapter *); ++ ++extern int l3_add_driver(struct l3_driver *); ++extern int l3_del_driver(struct l3_driver *); ++ ++extern int l3_attach_client(struct l3_client *, const char *, const char *); ++extern int l3_detach_client(struct l3_client *); ++ ++extern int l3_transfer(struct l3_adapter *, struct l3_msg msgs[], int); ++extern int l3_write(struct l3_client *, int, const char *, int); ++extern int l3_read(struct l3_client *, int, char *, int); ++ ++/** ++ * l3_command - send a command to a L3 device driver ++ * @client: registered client structure ++ * @cmd: device driver command ++ * @arg: device driver arguments ++ * ++ * Ask the L3 device driver to perform some function. Further information ++ * should be sought from the device driver in question. ++ * ++ * Returns negative error code on failure. ++ */ ++static inline int l3_command(struct l3_client *clnt, int cmd, void *arg) ++{ ++ struct l3_ops *ops = clnt->driver->ops; ++ int ret = -EINVAL; ++ ++ if (ops && ops->command) ++ ret = ops->command(clnt, cmd, arg); ++ ++ return ret; ++} ++ ++static inline int l3_open(struct l3_client *clnt) ++{ ++ struct l3_ops *ops = clnt->driver->ops; ++ int ret = 0; ++ ++ if (ops && ops->open) ++ ret = ops->open(clnt); ++ return ret; ++} ++ ++static inline void l3_close(struct l3_client *clnt) ++{ ++ struct l3_ops *ops = clnt->driver->ops; ++ if (ops && ops->close) ++ ops->close(clnt); ++} ++#endif ++ ++#endif /* L3_H */ +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/linux/l3/uda1341.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,50 @@ ++/* ++ * linux/include/linux/l3/uda1341.h ++ * ++ * Philips UDA1341 mixer device driver ++ * ++ * Copyright (c) 2000 Nicolas Pitre <nico@cam.org> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License. ++ */ ++ ++#define UDA1341_NAME "uda1341" ++ ++struct uda1341_cfg { ++ unsigned int fs:16; ++ unsigned int format:3; ++}; ++ ++#define FMT_I2S 0 ++#define FMT_LSB16 1 ++#define FMT_LSB18 2 ++#define FMT_LSB20 3 ++#define FMT_MSB 4 ++#define FMT_LSB16MSB 5 ++#define FMT_LSB18MSB 6 ++#define FMT_LSB20MSB 7 ++ ++#define L3_UDA1341_CONFIGURE 0x13410001 ++ ++struct l3_gain { ++ unsigned int left:8; ++ unsigned int right:8; ++ unsigned int unused:8; ++ unsigned int channel:8; ++}; ++ ++#define L3_SET_VOLUME 0x13410002 ++#define L3_SET_TREBLE 0x13410003 ++#define L3_SET_BASS 0x13410004 ++#define L3_SET_GAIN 0x13410005 ++ ++struct l3_agc { ++ unsigned int level:8; ++ unsigned int enable:1; ++ unsigned int attack:7; ++ unsigned int decay:8; ++ unsigned int channel:8; ++}; ++ ++#define L3_INPUT_AGC 0x13410006 +--- linux-2.4.25/include/linux/mm.h~2.4.25-vrs2.patch 2003-11-28 19:26:21.000000000 +0100 ++++ linux-2.4.25/include/linux/mm.h 2004-03-31 17:15:09.000000000 +0200 +@@ -685,6 +685,12 @@ + + extern struct page * vmalloc_to_page(void *addr); + ++#ifndef __arm__ ++#define memc_update_addr(x,y,z) ++#define memc_update_mm(x) ++#define memc_clear(x,y) ++#endif ++ + #endif /* __KERNEL__ */ + + #endif +--- linux-2.4.25/include/linux/pci.h~2.4.25-vrs2.patch 2003-11-28 19:26:21.000000000 +0100 ++++ linux-2.4.25/include/linux/pci.h 2004-03-31 17:15:09.000000000 +0200 +@@ -410,6 +410,7 @@ + + char name[90]; /* device name */ + char slot_name[8]; /* slot name */ ++ u32 saved_state[16]; /* for saving the config space before suspend */ + int active; /* ISAPnP: device is active */ + int ro; /* ISAPnP: read only */ + unsigned short regs; /* ISAPnP: supported registers */ +@@ -496,6 +497,8 @@ + + struct pbus_set_ranges_data + { ++ int found_vga:1; ++ int prefetch_valid:1; + unsigned long io_start, io_end; + unsigned long mem_start, mem_end; + unsigned long prefetch_start, prefetch_end; +@@ -637,6 +640,8 @@ + int pci_restore_state(struct pci_dev *dev, u32 *buffer); + int pci_set_power_state(struct pci_dev *dev, int state); + int pci_enable_wake(struct pci_dev *dev, u32 state, int enable); ++int pci_generic_suspend_save(struct pci_dev *pdev, u32 state); ++int pci_generic_resume_restore(struct pci_dev *pdev); + + /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */ + +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/linux/pld/pld_epxa.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,35 @@ ++#ifndef __LINUX_EPXAPLD_H ++#define __LINUX_EPXAPLD_H ++ ++/* ++ * linux/drivers/char/pld/epxapld.h ++ * ++ * Pld driver for Altera EPXA Excalibur devices ++ * ++ * 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$ ++ * ++ */ ++#define PLD_IOC_MAGIC 'p' ++#if !defined(KERNEL) || defined(CONFIG_PLD_HOTSWAP) ++#define PLD_IOC_ADD_PLD_DEV _IOW(PLD_IOC_MAGIC, 0xa0, struct pldhs_dev_desc) ++#define PLD_IOC_REMOVE_PLD_DEVS _IO(PLD_IOC_MAGIC, 0xa1) ++#define PLD_IOC_SET_INT_MODE _IOW(PLD_IOC_MAGIC, 0xa2, int) ++#endif ++ ++#endif +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/linux/pld/pld_hotswap.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,87 @@ ++#ifndef __LINUX_PLD_HOTSWAP_H ++#define __LINUX_PLD_HOTSWAP_H ++/* ++ * linux/drivers/char/pld/pld_hotswap.h ++ * ++ * Pld driver for Altera EPXA Excalibur devices ++ * ++ * 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$ ++ * ++ */ ++ ++/* ++ * The pld_hotswap ops contain the basic operation required for adding ++ * and removing devices from the system. ++ */ ++ ++struct pldhs_dev_info{ ++ unsigned int size; ++ unsigned short vendor_id; ++ unsigned short product_id; ++ unsigned char fsize; ++ unsigned char nsize; ++ unsigned short pssize; ++ unsigned short cmdsize; ++ unsigned char irq; ++ unsigned char version; ++ unsigned int base_addr; ++ unsigned int reg_size; ++}; ++ ++struct pldhs_dev_desc{ ++ struct pldhs_dev_info* info; ++ char* name; ++ void* data; ++}; ++ ++#include <linux/pld/pld_epxa.h> ++ ++ ++#ifdef __KERNEL__ ++struct pld_hotswap_ops{ ++ struct list_head list; ++ char* name; ++ int (*add_device)(struct pldhs_dev_info *dev_info, void* dev_ps_data); ++ int (*remove_devices)(void); ++ int (*proc_read)(char* buf,char** start,off_t offset,int count,int *eof,void *data); ++}; ++ ++/* ++ * These functions are called by the device drivers to register functions ++ * which should be called when devices are added and removed ++ */ ++extern int pldhs_register_driver(struct pld_hotswap_ops *drv); ++extern int pldhs_unregister_driver(char *driver); ++ ++/* ++ * These functions are called by the pld loader to add and remove ++ * device instances from the system. The call the functions regsistered ++ * the the particular deriver for this purpose ++ */ ++extern int pldhs_add_device(struct pldhs_dev_info* dev_info,char *drv_name, void* dev_ps_data); ++extern int pldhs_remove_devices(void); ++ ++/* Macro for formatting data to appear in the proc/pld file */ ++#define PLDHS_READ_PROC_DATA(buf,name,index,base,irq,ps_string) \ ++ sprintf(buf,":%s:%d Base Address, %#lx, IRQ, %d#\n%s\n",\ ++ name,index,base,irq,ps_string) ++ ++#endif ++ ++#endif +--- linux-2.4.25/include/linux/serial.h~2.4.25-vrs2.patch 2002-08-03 02:39:45.000000000 +0200 ++++ linux-2.4.25/include/linux/serial.h 2004-03-31 17:15:09.000000000 +0200 +@@ -48,7 +48,7 @@ + unsigned char *iomem_base; + unsigned short iomem_reg_shift; + unsigned int port_high; +- int reserved[1]; ++ unsigned long iomap_base; /* cookie passed into ioremap */ + }; + + /* +--- linux-2.4.25/include/linux/serialP.h~2.4.25-vrs2.patch 2002-08-03 02:39:45.000000000 +0200 ++++ linux-2.4.25/include/linux/serialP.h 2004-03-31 17:15:09.000000000 +0200 +@@ -157,8 +157,8 @@ + struct pci_dev *dev; + }; + +-extern int pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable); +-extern int pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable); ++//extern int pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable); ++//extern int pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable); + + #ifndef PCI_ANY_ID + #define PCI_ANY_ID (~0) +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/include/linux/serial_core.h 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,441 @@ ++/* ++ * linux/drivers/char/serial_core.h ++ * ++ * 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$ ++ */ ++ ++/* ++ * The type definitions. These are from Ted Ts'o's serial.h ++ */ ++#define PORT_UNKNOWN 0 ++#define PORT_8250 1 ++#define PORT_16450 2 ++#define PORT_16550 3 ++#define PORT_16550A 4 ++#define PORT_CIRRUS 5 ++#define PORT_16650 6 ++#define PORT_16650V2 7 ++#define PORT_16750 8 ++#define PORT_STARTECH 9 ++#define PORT_16C950 10 ++#define PORT_16654 11 ++#define PORT_16850 12 ++#define PORT_RSA 13 ++#define PORT_NS16550A 14 ++#define PORT_MAX_8250 14 /* max port ID */ ++ ++/* ++ * ARM specific type numbers. These are not currently guaranteed ++ * to be implemented, and will change in the future. These are ++ * separate so any additions to the old serial.c that occur before ++ * we are merged can be easily merged here. ++ */ ++#define PORT_AMBA 32 ++#define PORT_CLPS711X 33 ++#define PORT_SA1100 34 ++#define PORT_UART00 35 ++#define PORT_21285 37 ++ ++/* Sparc type numbers. */ ++#define PORT_SUNZILOG 38 ++#define PORT_SUNSAB 39 ++ ++/* NEC v850. */ ++#define PORT_NB85E_UART 40 ++ ++/* NEC PC-9800 */ ++#define PORT_8251_PC98 41 ++#define PORT_19K_PC98 42 ++#define PORT_FIFO_PC98 43 ++#define PORT_VFAST_PC98 44 ++#define PORT_PC9861 45 ++#define PORT_PC9801_101 46 ++ ++/* DZ */ ++#define PORT_DZ 47 ++ ++#define PORT_OMAHA 48 ++#define PORT_AT91RM9200 49 ++ ++ ++#ifdef __KERNEL__ ++ ++#include <linux/config.h> ++#include <linux/interrupt.h> ++#include <linux/circ_buf.h> ++#include <linux/serial.h> ++#include <linux/spinlock.h> ++ ++struct uart_port; ++struct uart_info; ++struct serial_struct; ++ ++/* ++ * This structure describes all the operations that can be ++ * done on the physical hardware. ++ */ ++struct uart_ops { ++ unsigned int (*tx_empty)(struct uart_port *); ++ void (*set_mctrl)(struct uart_port *, unsigned int mctrl); ++ unsigned int (*get_mctrl)(struct uart_port *); ++ void (*stop_tx)(struct uart_port *, unsigned int tty_stop); ++ void (*start_tx)(struct uart_port *, unsigned int tty_start); ++ void (*send_xchar)(struct uart_port *, char ch); ++ void (*stop_rx)(struct uart_port *); ++ void (*enable_ms)(struct uart_port *); ++ void (*break_ctl)(struct uart_port *, int ctl); ++ int (*startup)(struct uart_port *); ++ void (*shutdown)(struct uart_port *); ++ void (*change_speed)(struct uart_port *, unsigned int cflag, unsigned int iflag, unsigned int quot); ++ void (*pm)(struct uart_port *, unsigned int state, unsigned int oldstate); ++ int (*set_wake)(struct uart_port *, unsigned int state); ++ ++ /* ++ * Return a string describing the type of the port ++ */ ++ const char *(*type)(struct uart_port *); ++ ++ /* ++ * Release IO and memory resources used by the port. ++ * This includes iounmap if necessary. ++ */ ++ void (*release_port)(struct uart_port *); ++ ++ /* ++ * Request IO and memory resources used by the port. ++ * This includes iomapping the port if necessary. ++ */ ++ int (*request_port)(struct uart_port *); ++ void (*config_port)(struct uart_port *, int); ++ int (*verify_port)(struct uart_port *, struct serial_struct *); ++ int (*ioctl)(struct uart_port *, unsigned int, unsigned long); ++}; ++ ++#define UART_CONFIG_TYPE (1 << 0) ++#define UART_CONFIG_IRQ (1 << 1) ++ ++struct uart_icount { ++ __u32 cts; ++ __u32 dsr; ++ __u32 rng; ++ __u32 dcd; ++ __u32 rx; ++ __u32 tx; ++ __u32 frame; ++ __u32 overrun; ++ __u32 parity; ++ __u32 brk; ++ __u32 buf_overrun; ++}; ++ ++struct uart_port { ++ spinlock_t lock; /* port lock */ ++ unsigned int iobase; /* in/out[bwl] */ ++ char *membase; /* read/write[bwl] */ ++ unsigned char fifosize; /* tx fifo size */ ++ unsigned char x_char; /* xon/xoff char */ ++ unsigned char regshift; /* reg offset shift */ ++ unsigned char iotype; /* io access style */ ++ ++#define UPIO_PORT (0) ++#define UPIO_HUB6 (1) ++#define UPIO_MEM (2) ++ ++ unsigned int read_status_mask; /* driver specific */ ++ unsigned int ignore_status_mask; /* driver specific */ ++ ++ struct uart_info *info; /* pointer to parent info */ ++ struct uart_icount icount; /* statistics */ ++ ++ struct console *cons; /* struct console, if any */ ++ unsigned long sysrq; /* sysrq timeout */ ++ ++ unsigned int flags; ++ ++#define UPF_HUP_NOTIFY ASYNC_HUP_NOTIFY ++#define UPF_FOURPORT ASYNC_FOURPORT ++#define UPF_SAK ASYNC_SAK ++#define UPF_SPLIT_TERMIOS ASYNC_SPLIT_TERMIOS ++#define UPF_SPD_MASK (0x1030) ++#define UPF_SPD_HI (0x0010) ++#define UPF_SPD_VHI (0x0020) ++#define UPF_SPD_CUST (0x0030) ++#define UPF_SPD_SHI (0x1000) ++#define UPF_SPD_WARP (0x1010) ++#define UPF_SKIP_TEST ASYNC_SKIP_TEST ++#define UPF_AUTO_IRQ ASYNC_AUTO_IRQ ++#define UPF_SESSION_LOCKOUT ASYNC_SESSION_LOCKOUT ++#define UPF_PGRP_LOCKOUT ASYNCPGRP_LOCKOUT ++#define UPF_CALLOUT_NOHUP ASYNC_CALLOUT_NOHUP ++#define UPF_HARDPPS_CD ASYNC_HARDPPS_CD ++ /* 12 */ ++#define UPF_LOW_LATENCY ASYNC_LOW_LATENCY ++#define UPF_BUGGY_UART ASYNC_BUGGY_UART ++#define UPF_AUTOPROBE ASYNC_AUTOPROBE ++#define UPF_MAGIC_MULTIPLIER (1 << 16) ++#define UPF_BOOT_ONLYMCA ASYNC_BOOT_ONLYMCA ++#define UPF_CONS_FLOW ASYNC_CONS_FLOW ++#define UPF_SHARE_IRQ ASYNC_SHARE_IRQ ++#define UPF_BOOT_AUTOCONF ASYNC_BOOT_AUTOCONF ++#define UPF_RESOURCES (1 << 30) ++#define UPF_IOREMAP (1 << 31) ++ ++#define UPF_CHANGE_MASK (0x17fff) ++#define UPF_USR_MASK (UPF_SPD_MASK|UPF_LOW_LATENCY) ++ ++ unsigned int mctrl; /* current modem ctrl settings */ ++ unsigned int timeout; /* character-based timeout */ ++ unsigned int type; /* port type */ ++ struct uart_ops *ops; ++ unsigned int uartclk; /* base uart clock */ ++ unsigned int custom_divisor; ++ unsigned int irq; /* irq number */ ++ unsigned int line; /* port index */ ++ unsigned long mapbase; /* for ioremap */ ++ unsigned char hub6; /* this should be in the 8250 driver */ ++ unsigned char unused[7]; ++}; ++ ++/* ++ * This is the state information which is persistent across opens. ++ * The low level driver must not to touch any elements contained ++ * within. ++ */ ++struct uart_state { ++ unsigned int close_delay; ++ unsigned int closing_wait; ++ ++#define USF_CLOSING_WAIT_INF (0) ++#define USF_CLOSING_WAIT_NONE (65535) ++ ++ struct termios normal_termios; ++ struct termios callout_termios; ++ ++ int count; ++ struct uart_info *info; ++ struct uart_port *port; ++ ++ struct semaphore sem; ++#ifdef CONFIG_PM ++ struct pm_dev *pm; ++#endif ++}; ++ ++#define UART_XMIT_SIZE 1024 ++/* ++ * This is the state information which is only valid when the port ++ * is open; it may be freed by the core driver once the device has ++ * been closed. Either the low level driver or the core can modify ++ * stuff here. ++ */ ++struct uart_info { ++ struct tty_struct *tty; ++ struct circ_buf xmit; ++ unsigned int flags; ++ ++/* ++ * These are the flags that specific to info->flags, and reflect our ++ * internal state. They can not be accessed via port->flags. Low ++ * level drivers must not change these, but may query them instead. ++ */ ++#define UIF_CHECK_CD ASYNC_CHECK_CD ++#define UIF_CTS_FLOW ASYNC_CTS_FLOW ++#define UIF_CALLOUT_ACTIVE ASYNC_CALLOUT_ACTIVE ++#define UIF_NORMAL_ACTIVE ASYNC_NORMAL_ACTIVE ++#define UIF_INITIALIZED ASYNC_INITIALIZED ++ ++ unsigned char *tmpbuf; ++ struct semaphore tmpbuf_sem; ++ ++ unsigned int driver_priv; ++ int blocked_open; ++ pid_t session; ++ pid_t pgrp; ++ ++ struct tasklet_struct tlet; ++ ++ wait_queue_head_t open_wait; ++ wait_queue_head_t delta_msr_wait; ++}; ++ ++/* number of characters left in xmit buffer before we ask for more */ ++#define WAKEUP_CHARS 256 ++ ++struct module; ++struct tty_driver; ++ ++struct uart_driver { ++ struct module *owner; ++ int normal_major; ++ const char *normal_name; ++ struct tty_driver *normal_driver; ++ int callout_major; ++ const char *callout_name; ++ struct tty_driver *callout_driver; ++ struct tty_struct **table; ++ struct termios **termios; ++ struct termios **termios_locked; ++ int minor; ++ int nr; ++ struct console *cons; ++ ++ /* ++ * these are private; the low level driver should not ++ * touch these; they should be initialised to NULL ++ */ ++ struct uart_state *state; ++}; ++ ++void uart_write_wakeup(struct uart_port *port); ++struct uart_port *uart_get_console(struct uart_port *ports, int nr, ++ struct console *c); ++void uart_parse_options(char *options, int *baud, int *parity, int *bits, ++ int *flow); ++int uart_set_options(struct uart_port *port, struct console *co, int baud, ++ int parity, int bits, int flow); ++ ++/* ++ * Port/driver registration/removal ++ */ ++int uart_register_driver(struct uart_driver *uart); ++void uart_unregister_driver(struct uart_driver *uart); ++void uart_unregister_port(struct uart_driver *reg, int line); ++int uart_register_port(struct uart_driver *reg, struct uart_port *port); ++int uart_add_one_port(struct uart_driver *reg, struct uart_port *port); ++int uart_remove_one_port(struct uart_driver *reg, struct uart_port *port); ++ ++#define uart_circ_empty(circ) ((circ)->head == (circ)->tail) ++#define uart_circ_clear(circ) ((circ)->head = (circ)->tail = 0) ++ ++#define uart_circ_chars_pending(circ) \ ++ (CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE)) ++ ++#define uart_circ_chars_free(circ) \ ++ (CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE)) ++ ++#define uart_tx_stopped(port) \ ++ ((port)->info->tty->stopped || (port)->info->tty->hw_stopped) ++ ++/* ++ * The following are helper functions for the low level drivers. ++ */ ++#ifdef SUPPORT_SYSRQ ++static inline int ++uart_handle_sysrq_char(struct uart_port *port, unsigned int ch, ++ struct pt_regs *regs) ++{ ++ if (port->sysrq) { ++ if (ch && time_before(jiffies, port->sysrq)) { ++ handle_sysrq(ch, regs, NULL, NULL); ++ port->sysrq = 0; ++ return 1; ++ } ++ port->sysrq = 0; ++ } ++ return 0; ++} ++#else ++#define uart_handle_sysrq_char(port,ch,regs) (0) ++#endif ++ ++/* ++ * We do the SysRQ and SAK checking like this... ++ */ ++static inline int uart_handle_break(struct uart_port *port) ++{ ++ struct uart_info *info = port->info; ++#ifdef SUPPORT_SYSRQ ++ if (port->cons && port->cons->index == port->line) { ++ if (!port->sysrq) { ++ port->sysrq = jiffies + HZ*5; ++ return 1; ++ } ++ port->sysrq = 0; ++ } ++#endif ++ if (port->flags & UPF_SAK) ++ do_SAK(info->tty); ++ return 0; ++} ++ ++/** ++ * uart_handle_dcd_change - handle a change of carrier detect state ++ * @port: uart_port structure for the open port ++ * @status: new carrier detect status, nonzero if active ++ */ ++static inline void ++uart_handle_dcd_change(struct uart_port *port, unsigned int status) ++{ ++ struct uart_info *info = port->info; ++ ++ port->icount.dcd++; ++ ++#ifdef CONFIG_HARD_PPS ++ if ((port->flags & UPF_HARDPPS_CD) && status) ++ hardpps(); ++#endif ++ ++ if (info->flags & UIF_CHECK_CD) { ++ if (status) ++ wake_up_interruptible(&info->open_wait); ++ else if (!((info->flags & UIF_CALLOUT_ACTIVE) && ++ (port->flags & UPF_CALLOUT_NOHUP))) { ++ if (info->tty) ++ tty_hangup(info->tty); ++ } ++ } ++} ++ ++/** ++ * uart_handle_cts_change - handle a change of clear-to-send state ++ * @port: uart_port structure for the open port ++ * @status: new clear to send status, nonzero if active ++ */ ++static inline void ++uart_handle_cts_change(struct uart_port *port, unsigned int status) ++{ ++ struct uart_info *info = port->info; ++ struct tty_struct *tty = info->tty; ++ ++ port->icount.cts++; ++ ++ if (info->flags & UIF_CTS_FLOW) { ++ if (tty->hw_stopped) { ++ if (status) { ++ tty->hw_stopped = 0; ++ port->ops->start_tx(port, 0); ++ uart_write_wakeup(port); ++ } ++ } else { ++ if (!status) { ++ tty->hw_stopped = 1; ++ port->ops->stop_tx(port, 0); ++ } ++ } ++ } ++} ++ ++/* ++ * UART_ENABLE_MS - determine if port should enable modem status irqs ++ */ ++#define UART_ENABLE_MS(port,cflag) ((port)->flags & UPF_HARDPPS_CD || \ ++ (cflag) & CRTSCTS || \ ++ !((cflag) & CLOCAL)) ++ ++#endif +--- linux-2.4.25/include/linux/serial_reg.h~2.4.25-vrs2.patch 2001-05-02 01:05:00.000000000 +0200 ++++ linux-2.4.25/include/linux/serial_reg.h 2004-03-31 17:15:09.000000000 +0200 +@@ -121,6 +121,7 @@ + /* + * These are the definitions for the Modem Control Register + */ ++#define UART_MCR_AFE 0x20 /* Enable auto-RTS/CTS (TI16C750) */ + #define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ + #define UART_MCR_OUT2 0x08 /* Out2 complement */ + #define UART_MCR_OUT1 0x04 /* Out1 complement */ +--- linux-2.4.25/include/linux/zlib.h~2.4.25-vrs2.patch 2002-11-29 00:53:15.000000000 +0100 ++++ linux-2.4.25/include/linux/zlib.h 2004-03-31 17:15:09.000000000 +0200 +@@ -31,7 +31,7 @@ + #ifndef _ZLIB_H + #define _ZLIB_H + +-#include <linux/zconf.h> ++#include "zconf.h" + + #ifdef __cplusplus + extern "C" { +--- linux-2.4.25/init/do_mounts.c~2.4.25-vrs2.patch 2003-11-28 19:26:21.000000000 +0100 ++++ linux-2.4.25/init/do_mounts.c 2004-03-31 17:15:09.000000000 +0200 +@@ -888,7 +888,7 @@ + */ + void prepare_namespace(void) + { +- int is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR; ++ int is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR || MAJOR(ROOT_DEV) == 31; + #ifdef CONFIG_ALL_PPC + extern void arch_discover_root(void); + arch_discover_root(); +@@ -951,6 +951,7 @@ + static unsigned inptr; /* index of next byte to be processed in inbuf */ + static unsigned outcnt; /* bytes in output buffer */ + static int exit_code; ++static int unzip_error; + static long bytes_out; + static int crd_infd, crd_outfd; + +@@ -998,13 +999,17 @@ + /* =========================================================================== + * Fill the input buffer. This is called only when the buffer is empty + * and at least one byte is really needed. ++ * Returning -1 does not guarantee that gunzip() will ever return. + */ + static int __init fill_inbuf(void) + { + if (exit_code) return -1; + + insize = read(crd_infd, inbuf, INBUFSIZ); +- if (insize == 0) return -1; ++ if (insize == 0) { ++ error("RAMDISK: ran out of compressed data\n"); ++ return -1; ++ } + + inptr = 1; + +@@ -1018,10 +1023,15 @@ + static void __init flush_window(void) + { + ulg c = crc; /* temporary variable */ +- unsigned n; ++ unsigned n, written; + uch *in, ch; + +- write(crd_outfd, window, outcnt); ++ written = write(crd_outfd, window, outcnt); ++ if (written != outcnt && unzip_error == 0) { ++ printk(KERN_ERR "RAMDISK: incomplete write (%d != %d), " ++ "only wrote %ld\n", written, outcnt, bytes_out); ++ unzip_error = 1; ++ } + in = window; + for (n = 0; n < outcnt; n++) { + ch = *in++; +@@ -1036,6 +1046,7 @@ + { + printk(KERN_ERR "%s", x); + exit_code = 1; ++ unzip_error = 1; + } + + static int __init crd_load(int in_fd, int out_fd) +@@ -1064,6 +1075,8 @@ + } + makecrc(); + result = gunzip(); ++ if (unzip_error) ++ result = 1; + kfree(inbuf); + kfree(window); + return result; +--- linux-2.4.25/kernel/Makefile~2.4.25-vrs2.patch 2001-09-17 06:22:40.000000000 +0200 ++++ linux-2.4.25/kernel/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -9,16 +9,19 @@ + + O_TARGET := kernel.o + +-export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o printk.o ++export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o \ ++ printk.o fork.o cpufreq.o + +-obj-y = sched.o dma.o fork.o exec_domain.o panic.o printk.o \ ++obj-y = sched.o fork.o exec_domain.o panic.o printk.o \ + module.o exit.o itimer.o info.o time.o softirq.o resource.o \ + sysctl.o acct.o capability.o ptrace.o timer.o user.o \ + signal.o sys.o kmod.o context.o + ++obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o + obj-$(CONFIG_UID16) += uid16.o + obj-$(CONFIG_MODULES) += ksyms.o + obj-$(CONFIG_PM) += pm.o ++obj-$(CONFIG_CPU_FREQ) += cpufreq.o + + ifneq ($(CONFIG_IA64),y) + # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/kernel/cpufreq.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,536 @@ ++/* ++ * linux/kernel/cpufreq.c ++ * ++ * Copyright (C) 2001 Russell King ++ * ++ * $Id$ ++ * ++ * 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. ++ * ++ * CPU speed changing core functionality. We provide the following ++ * services to the system: ++ * - notifier lists to inform other code of the freq change both ++ * before and after the freq change. ++ * - the ability to change the freq speed ++ * ++ * ** You'll need to add CTL_CPU = 10 to include/linux/sysctl.h if ++ * it's not already present. ++ * ++ * When this appears in the kernel, the sysctl enums will move to ++ * include/linux/sysctl.h ++ */ ++#include <linux/config.h> ++#include <linux/types.h> ++#include <linux/module.h> ++#include <linux/notifier.h> ++#include <linux/cpufreq.h> ++#include <linux/kernel.h> ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/smp.h> ++#include <linux/fs.h> ++#include <linux/sysctl.h> ++ ++#include <asm/semaphore.h> ++#include <asm/system.h> ++#include <asm/uaccess.h> ++#include <linux/interrupt.h> /* requires system.h */ ++ ++/* ++ * This list is for kernel code that needs to handle ++ * changes to devices when the CPU clock speed changes. ++ */ ++static struct notifier_block *cpufreq_notifier_list; ++static DECLARE_MUTEX_LOCKED(cpufreq_sem); ++static unsigned long cpufreq_ref_loops; ++static unsigned int cpufreq_ref_freq; ++static int cpufreq_initialised; ++static unsigned int (*cpufreq_validatespeed)(unsigned int); ++static void (*cpufreq_setspeed)(unsigned int); ++ ++#ifndef CONFIG_SMP ++static unsigned int __cpufreq_max; ++static unsigned int __cpufreq_min; ++static unsigned int __cpufreq_cur; ++#endif ++ ++static unsigned long scale(unsigned long ref, u_int div, u_int mult) ++{ ++ unsigned long new_jiffy_l, new_jiffy_h; ++ ++ /* ++ * Recalculate loops_per_jiffy. We do it this way to ++ * avoid math overflow on 32-bit machines. Maybe we ++ * should make this architecture dependent? If you have ++ * a better way of doing this, please replace! ++ * ++ * new = old * mult / div ++ */ ++ new_jiffy_h = ref / div; ++ new_jiffy_l = (ref % div) / 100; ++ new_jiffy_h *= mult; ++ new_jiffy_l = new_jiffy_l * mult / div; ++ ++ return new_jiffy_h + new_jiffy_l * 100; ++} ++ ++/* ++ * cpufreq_max command line parameter. Use: ++ * cpufreq=59000-221000 ++ * to set the CPU frequency to 59 to 221MHz. ++ */ ++static int __init cpufreq_setup(char *str) ++{ ++ unsigned int min, max; ++ int i; ++ ++ min = 0; ++ max = simple_strtoul(str, &str, 0); ++ if (*str == '-') { ++ min = max; ++ max = simple_strtoul(str + 1, NULL, 0); ++ } ++ ++ for (i = 0; i < smp_num_cpus; i++) { ++ cpufreq_max(i) = max; ++ cpufreq_min(i) = min; ++ } ++ ++ return 1; ++} ++ ++__setup("cpufreq=", cpufreq_setup); ++ ++/** ++ * cpufreq_register_notifier - register a driver with cpufreq ++ * @nb: notifier function to register ++ * ++ * Add a driver to the list of drivers that which to be notified about ++ * CPU clock rate changes. The driver will be called three times on ++ * clock change. ++ * ++ * This function may sleep, and has the same return conditions as ++ * notifier_chain_register. ++ */ ++int cpufreq_register_notifier(struct notifier_block *nb) ++{ ++ int ret; ++ ++ down(&cpufreq_sem); ++ ret = notifier_chain_register(&cpufreq_notifier_list, nb); ++ up(&cpufreq_sem); ++ ++ return ret; ++} ++ ++EXPORT_SYMBOL(cpufreq_register_notifier); ++ ++/** ++ * cpufreq_unregister_notifier - unregister a driver with cpufreq ++ * @nb: notifier block to be unregistered ++ * ++ * Remove a driver from the CPU frequency notifier lists. ++ * ++ * This function may sleep, and has the same return conditions as ++ * notifier_chain_unregister. ++ */ ++int cpufreq_unregister_notifier(struct notifier_block *nb) ++{ ++ int ret; ++ ++ down(&cpufreq_sem); ++ ret = notifier_chain_unregister(&cpufreq_notifier_list, nb); ++ up(&cpufreq_sem); ++ ++ return ret; ++} ++ ++EXPORT_SYMBOL(cpufreq_unregister_notifier); ++ ++/* ++ * This notifier alters the system "loops_per_jiffy" for the clock ++ * speed change. We ignore CPUFREQ_MINMAX here. ++ */ ++static void adjust_jiffies(unsigned long val, struct cpufreq_info *ci) ++{ ++ if ((val == CPUFREQ_PRECHANGE && ci->old_freq < ci->new_freq) || ++ (val == CPUFREQ_POSTCHANGE && ci->old_freq > ci->new_freq)) ++ loops_per_jiffy = scale(cpufreq_ref_loops, cpufreq_ref_freq, ++ ci->new_freq); ++} ++ ++#ifdef CONFIG_PM ++/** ++ * cpufreq_restore - restore the CPU clock frequency after resume ++ * ++ * Restore the CPU clock frequency so that our idea of the current ++ * frequency reflects the actual hardware. ++ */ ++int cpufreq_restore(void) ++{ ++ unsigned long old_cpus; ++ int cpu = smp_processor_id(); ++ int ret; ++ ++ if (!cpufreq_initialised) ++ panic("cpufreq_restore() called before initialisation!"); ++ if (in_interrupt()) ++ panic("cpufreq_restore() called from interrupt context!"); ++ ++ /* ++ * Bind to the current CPU. ++ */ ++ old_cpus = current->cpus_allowed; ++ current->cpus_allowed = 1UL << cpu_logical_map(cpu); ++ ++ down(&cpufreq_sem); ++ ++ ret = -ENXIO; ++ if (cpufreq_setspeed) { ++ cpufreq_setspeed(cpufreq_current(cpu)); ++ ret = 0; ++ } ++ ++ up(&cpufreq_sem); ++ ++ current->cpus_allowed = old_cpus; ++ ++ return ret; ++} ++ ++EXPORT_SYMBOL_GPL(cpufreq_restore); ++#endif ++ ++/** ++ * cpu_setfreq - change the CPU clock frequency. ++ * @freq: frequency (in kHz) at which we should run. ++ * ++ * Set the CPU clock frequency, informing all registered users of ++ * the change. We bound the frequency according to the cpufreq_max ++ * command line parameter, and the parameters the registered users ++ * will allow. ++ * ++ * This function must be called from process context, and on the ++ * cpu that we wish to change the frequency of. ++ * ++ * We return 0 if successful. (we are currently always successful). ++ */ ++int cpufreq_set(unsigned int freq) ++{ ++ unsigned long old_cpus; ++ struct cpufreq_info clkinfo; ++ struct cpufreq_minmax minmax; ++ int cpu = smp_processor_id(); ++ int ret; ++ ++ if (!cpufreq_initialised) ++ panic("cpufreq_set() called before initialisation!"); ++ if (in_interrupt()) ++ panic("cpufreq_set() called from interrupt context!"); ++ ++ /* ++ * Bind to the current CPU. ++ */ ++ old_cpus = current->cpus_allowed; ++ current->cpus_allowed = 1UL << cpu_logical_map(cpu); ++ ++ down(&cpufreq_sem); ++ ret = -ENXIO; ++ if (!cpufreq_setspeed || !cpufreq_validatespeed) ++ goto out; ++ ++ /* ++ * Don't allow the CPU to be clocked over the limit. ++ */ ++ minmax.min_freq = cpufreq_min(cpu); ++ minmax.max_freq = cpufreq_max(cpu); ++ minmax.cur_freq = cpufreq_current(cpu); ++ minmax.new_freq = freq; ++ ++ /* ++ * Find out what the registered devices will currently tolerate, ++ * and limit the requested clock rate to these values. Drivers ++ * must not rely on the 'new_freq' value - it is only a guide. ++ */ ++ notifier_call_chain(&cpufreq_notifier_list, CPUFREQ_MINMAX, &minmax); ++ if (freq < minmax.min_freq) ++ freq = minmax.min_freq; ++ if (freq > minmax.max_freq) ++ freq = minmax.max_freq; ++ ++ /* ++ * Ask the CPU specific code to validate the speed. If the speed ++ * is not acceptable, make it acceptable. Current policy is to ++ * round the frequency down to the value the processor actually ++ * supports. ++ */ ++ freq = cpufreq_validatespeed(freq); ++ ++ if (cpufreq_current(cpu) != freq) { ++ clkinfo.old_freq = cpufreq_current(cpu); ++ clkinfo.new_freq = freq; ++ ++ notifier_call_chain(&cpufreq_notifier_list, CPUFREQ_PRECHANGE, ++ &clkinfo); ++ ++ adjust_jiffies(CPUFREQ_PRECHANGE, &clkinfo); ++ ++ /* ++ * Actually set the CPU frequency. ++ */ ++ cpufreq_setspeed(freq); ++ cpufreq_current(cpu) = freq; ++ adjust_jiffies(CPUFREQ_POSTCHANGE, &clkinfo); ++ ++ notifier_call_chain(&cpufreq_notifier_list, CPUFREQ_POSTCHANGE, ++ &clkinfo); ++ } ++ ++ ret = 0; ++ ++ out: ++ up(&cpufreq_sem); ++ ++ current->cpus_allowed = old_cpus; ++ ++ return ret; ++} ++ ++EXPORT_SYMBOL_GPL(cpufreq_set); ++ ++/** ++ * cpufreq_setmax - set the CPU to maximum frequency ++ * ++ * Sets the CPU this function is executed on to maximum frequency. ++ */ ++int cpufreq_setmax(void) ++{ ++ return cpufreq_set(cpufreq_max(smp_processor_id())); ++} ++ ++EXPORT_SYMBOL_GPL(cpufreq_setmax); ++ ++/** ++ * cpufreq_get - return the current CPU clock frequency in 1kHz ++ * @cpu: cpu number to obtain frequency for ++ * ++ * Returns the specified CPUs frequency in kHz. ++ */ ++unsigned int cpufreq_get(int cpu) ++{ ++ if (!cpufreq_initialised) ++ panic("cpufreq_get() called before initialisation!"); ++ return cpufreq_current(cpu); ++} ++ ++EXPORT_SYMBOL(cpufreq_get); ++ ++#ifdef CONFIG_SYSCTL ++ ++static int ++cpufreq_procctl(ctl_table *ctl, int write, struct file *filp, ++ void *buffer, size_t *lenp) ++{ ++ char buf[16], *p; ++ int cpu = 0, len, left = *lenp; ++ ++ if (!left || (filp->f_pos && !write)) { ++ *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); ++ } 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 = 0; ++ ++ 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); ++ } ++ return 1; ++} ++ ++enum { ++ CPU_NR_FREQ_MAX = 1, ++ CPU_NR_FREQ_MIN = 2, ++ CPU_NR_FREQ = 3 ++}; ++ ++static ctl_table ctl_cpu_vars[4] = { ++ { ++ ctl_name: CPU_NR_FREQ_MAX, ++ procname: "speed-max", ++ data: &cpufreq_max(0), ++ maxlen: sizeof(cpufreq_max(0)), ++ mode: 0444, ++ proc_handler: proc_dointvec, ++ }, ++ { ++ ctl_name: CPU_NR_FREQ_MIN, ++ procname: "speed-min", ++ data: &cpufreq_min(0), ++ maxlen: sizeof(cpufreq_min(0)), ++ mode: 0444, ++ proc_handler: proc_dointvec, ++ }, ++ { ++ ctl_name: CPU_NR_FREQ, ++ procname: "speed", ++ mode: 0644, ++ proc_handler: cpufreq_procctl, ++ strategy: cpufreq_sysctl, ++ }, ++ { ++ ctl_name: 0, ++ } ++}; ++ ++enum { ++ CPU_NR = 1, ++}; ++ ++static ctl_table ctl_cpu_nr[2] = { ++ { ++ ctl_name: CPU_NR, ++ procname: "0", ++ mode: 0555, ++ child: ctl_cpu_vars, ++ }, ++ { ++ ctl_name: 0, ++ } ++}; ++ ++static ctl_table ctl_cpu[2] = { ++ { ++ ctl_name: CTL_CPU, ++ procname: "cpu", ++ mode: 0555, ++ child: ctl_cpu_nr, ++ }, ++ { ++ ctl_name: 0, ++ } ++}; ++ ++static inline void cpufreq_sysctl_init(void) ++{ ++ register_sysctl_table(ctl_cpu, 0); ++} ++ ++#else ++#define cpufreq_sysctl_init() ++#endif ++ ++/** ++ * cpufreq_setfunctions - Set CPU clock functions ++ * @validate: pointer to validation function ++ * @setspeed: pointer to setspeed function ++ */ ++void ++cpufreq_setfunctions(unsigned int (*validate)(unsigned int), ++ void (*setspeed)(unsigned int)) ++{ ++ down(&cpufreq_sem); ++ cpufreq_validatespeed = validate; ++ cpufreq_setspeed = setspeed; ++ up(&cpufreq_sem); ++} ++ ++EXPORT_SYMBOL_GPL(cpufreq_setfunctions); ++ ++/** ++ * cpufreq_init - Initialise the cpufreq core ++ * @freq: current CPU clock speed. ++ * @min_freq: minimum CPU clock speed. ++ * @max_freq: maximum CPU clock speed. ++ * ++ * Initialise the cpufreq core. If the cpufreq_max command line ++ * parameter has not been specified, we set the maximum clock rate ++ * to the current CPU clock rate. ++ */ ++void cpufreq_init(unsigned int freq, ++ unsigned int min_freq, ++ unsigned int max_freq) ++{ ++ /* ++ * If the user doesn't tell us their maximum frequency, ++ * or if it is invalid, use the values determined ++ * by the cpufreq-arch-specific initialization functions. ++ * The validatespeed code is responsible for limiting ++ * this further. ++ */ ++ if (max_freq && ((cpufreq_max(0) == 0) || (cpufreq_max(0) > max_freq))) ++ cpufreq_max(0) = max_freq; ++ if (min_freq && ((cpufreq_min(0) == 0) || (cpufreq_min(0) < min_freq))) ++ cpufreq_min(0) = min_freq; ++ ++ if (cpufreq_max(0) == 0) ++ cpufreq_max(0) = freq; ++ ++ printk(KERN_INFO "CPU clock: %d.%03d MHz (%d.%03d-%d.%03d MHz)\n", ++ freq / 1000, freq % 1000, ++ cpufreq_min(0) / 1000, cpufreq_min(0) % 1000, ++ cpufreq_max(0) / 1000, cpufreq_max(0) % 1000); ++ ++ cpufreq_ref_loops = loops_per_jiffy; ++ cpufreq_ref_freq = freq; ++ cpufreq_current(smp_processor_id()) = freq; ++ ++ cpufreq_initialised = 1; ++ up(&cpufreq_sem); ++ ++ cpufreq_sysctl_init(); ++} ++ ++EXPORT_SYMBOL_GPL(cpufreq_init); +--- linux-2.4.25/kernel/exit.c~2.4.25-vrs2.patch 2002-11-29 00:53:15.000000000 +0100 ++++ linux-2.4.25/kernel/exit.c 2004-03-31 17:15:09.000000000 +0200 +@@ -587,7 +587,7 @@ + return retval; + } + +-#if !defined(__alpha__) && !defined(__ia64__) ++#if !defined(__alpha__) && !defined(__ia64__) && !defined(__arm__) + + /* + * sys_waitpid() remains for compatibility. waitpid() should be +--- linux-2.4.25/kernel/fork.c~2.4.25-vrs2.patch 2004-02-18 14:36:32.000000000 +0100 ++++ linux-2.4.25/kernel/fork.c 2004-03-31 17:15:09.000000000 +0200 +@@ -75,7 +75,11 @@ + * value: the thread structures can take up at most half + * of memory. + */ ++#if THREAD_SIZE > PAGE_SIZE + max_threads = mempages / (THREAD_SIZE/PAGE_SIZE) / 8; ++#else ++ max_threads = (mempages * PAGE_SIZE) / (8 * THREAD_SIZE); ++#endif + + init_task.rlim[RLIMIT_NPROC].rlim_cur = max_threads/2; + init_task.rlim[RLIMIT_NPROC].rlim_max = max_threads/2; +@@ -220,6 +224,7 @@ + + fail_nomem: + flush_tlb_mm(current->mm); ++ memc_update_mm(mm); + return retval; + } + +--- linux-2.4.25/kernel/ksyms.c~2.4.25-vrs2.patch 2004-02-18 14:36:32.000000000 +0100 ++++ linux-2.4.25/kernel/ksyms.c 2004-03-31 17:15:09.000000000 +0200 +@@ -345,6 +345,7 @@ + + /* tty routines */ + EXPORT_SYMBOL(tty_hangup); ++EXPORT_SYMBOL(tty_vhangup); + EXPORT_SYMBOL(tty_wait_until_sent); + EXPORT_SYMBOL(tty_check_change); + EXPORT_SYMBOL(tty_hung_up_p); +@@ -439,9 +440,11 @@ + EXPORT_SYMBOL(kiobuf_wait_for_io); + + /* dma handling */ ++#ifdef CONFIG_GENERIC_ISA_DMA + EXPORT_SYMBOL(request_dma); + EXPORT_SYMBOL(free_dma); + EXPORT_SYMBOL(dma_spin_lock); ++#endif + #ifdef HAVE_DISABLE_HLT + EXPORT_SYMBOL(disable_hlt); + EXPORT_SYMBOL(enable_hlt); +--- linux-2.4.25/kernel/signal.c~2.4.25-vrs2.patch 2004-02-18 14:36:32.000000000 +0100 ++++ linux-2.4.25/kernel/signal.c 2004-03-31 17:15:09.000000000 +0200 +@@ -778,8 +778,8 @@ + info.si_uid = tsk->uid; + + /* FIXME: find out whether or not this is supposed to be c*time. */ +- info.si_utime = tsk->times.tms_utime; +- info.si_stime = tsk->times.tms_stime; ++ info.si_utime = hz_to_std(tsk->times.tms_utime); ++ info.si_stime = hz_to_std(tsk->times.tms_stime); + + status = tsk->exit_code & 0x7f; + why = SI_KERNEL; /* shouldn't happen */ +@@ -1277,7 +1277,7 @@ + #endif /* __sparc__ */ + #endif + +-#if !defined(__alpha__) && !defined(__ia64__) ++#if !defined(__alpha__) && !defined(__ia64__) && !defined(__arm__) + /* + * For backwards compatibility. Functionality superseded by sigprocmask. + */ +@@ -1305,7 +1305,8 @@ + } + #endif /* !defined(__alpha__) */ + +-#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) ++#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && \ ++ !defined(__arm__) + /* + * For backwards compatibility. Functionality superseded by sigaction. + */ +@@ -1322,4 +1323,4 @@ + + return ret ? ret : (unsigned long)old_sa.sa.sa_handler; + } +-#endif /* !alpha && !__ia64__ && !defined(__mips__) */ ++#endif /* !alpha && !__ia64__ && !defined(__mips__) && !defined(__arm__) */ +--- linux-2.4.25/kernel/sys.c~2.4.25-vrs2.patch 2003-11-28 19:26:21.000000000 +0100 ++++ linux-2.4.25/kernel/sys.c 2004-03-31 17:15:09.000000000 +0200 +@@ -801,16 +801,23 @@ + + asmlinkage long sys_times(struct tms * tbuf) + { ++ struct tms temp; ++ + /* + * In the SMP world we might just be unlucky and have one of + * the times increment as we use it. Since the value is an + * atomically safe type this is just fine. Conceptually its + * as if the syscall took an instant longer to occur. + */ +- if (tbuf) +- if (copy_to_user(tbuf, ¤t->times, sizeof(struct tms))) ++ if (tbuf) { ++ temp.tms_utime = hz_to_std(current->times.tms_utime); ++ temp.tms_stime = hz_to_std(current->times.tms_stime); ++ temp.tms_cutime = hz_to_std(current->times.tms_cutime); ++ temp.tms_cstime = hz_to_std(current->times.tms_cstime); ++ if (copy_to_user(tbuf, &temp, sizeof(struct tms))) + return -EFAULT; +- return jiffies; ++ } ++ return hz_to_std(jiffies); + } + + /* +--- linux-2.4.25/lib/string.c~2.4.25-vrs2.patch 2002-08-03 02:39:46.000000000 +0200 ++++ linux-2.4.25/lib/string.c 2004-03-31 17:15:09.000000000 +0200 +@@ -188,10 +188,10 @@ + */ + char * strchr(const char * s, int c) + { +- for(; *s != (char) c; ++s) +- if (*s == '\0') +- return NULL; +- return (char *) s; ++ for(; *s != '\0'; ++s) ++ if (*s == (char) c) ++ return (char *) s; ++ return NULL; + } + #endif + +--- linux-2.4.25/mm/Makefile~2.4.25-vrs2.patch 2002-08-03 02:39:46.000000000 +0200 ++++ linux-2.4.25/mm/Makefile 2004-03-31 17:15:09.000000000 +0200 +@@ -18,4 +18,5 @@ + + obj-$(CONFIG_HIGHMEM) += highmem.o + ++obj-y += debug.o + include $(TOPDIR)/Rules.make +--- /dev/null 2003-09-23 19:59:22.000000000 +0200 ++++ linux-2.4.25/mm/debug.c 2004-03-31 17:15:09.000000000 +0200 +@@ -0,0 +1,159 @@ ++/* ++ * linux/mm/debug.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. ++ * ++ * Dump out page information on SysRQ-G, and provide show_page_info() ++ * ++ * You are advised to use a serial console with this patch - it ++ * saturates a 38400baud link for 1 minute on a 32MB machine. ++ */ ++#include <linux/kernel.h> ++#include <linux/mm.h> ++#include <linux/pagemap.h> ++#include <linux/sysrq.h> ++#include <linux/init.h> ++ ++/* ++ * We print out the following information for each page in the system: ++ * address: use count, age, mapping, [RSsr] rD [acd] ++ * ++ * The flags are: ++ * R - reserved ++ * S - in swapcache ++ * s - slab page ++ * ++ * r - referenced ++ * D - dirty ++ * ++ * a - active page ++ */ ++static void page_detail(struct page *page) ++{ ++ if (!page) ++ return; ++ ++ printk("%p: %2d %p [%c%c%c] %c%c [%c]\n", ++ page_address(page), ++ page_count(page), ++ page->mapping, ++ ++ PageReserved(page) ? 'R' : '-', ++ PageSwapCache(page) ? 'S' : '-', ++ PageSlab(page) ? 's' : '-', ++ ++ PageReferenced(page) ? 'r' : '-', ++ PageDirty(page) ? 'D' : '-', ++ ++ PageActive(page) ? 'a' : '-'); ++} ++ ++/* ++ * This version collects statistics ++ */ ++static int anon_pages, slab_pages, resvd_pages, unused_pages; ++ ++static void page_statistics(struct page *page) ++{ ++ if (page) { ++ if (PageReserved(page)) ++ resvd_pages++; ++ else if (PageSlab(page)) ++ slab_pages++; ++ else if (!page_count(page)) ++ unused_pages ++; ++ else if (!page->mapping) ++ anon_pages ++; ++ return; ++ } ++ ++ printk(" anon: %d, slab: %d, reserved: %d, free: %d\n", ++ anon_pages, slab_pages, resvd_pages, unused_pages); ++} ++ ++static void show_zone_info(zone_t *zone, void (*fn)(struct page *)) ++{ ++ int i; ++ ++ printk(" total %ld, free %ld\n", ++ zone->size, zone->free_pages); ++ ++ anon_pages = 0; ++ slab_pages = 0; ++ resvd_pages = 0; ++ unused_pages = 0; ++ ++ for (i = 0; i < zone->size; i++) { ++ struct page *page = zone->zone_mem_map + i; ++ ++ fn(page); ++ } ++ ++ fn(NULL); ++} ++ ++static void show_node_info(pg_data_t *pg, void (*fn)(struct page *)) ++{ ++ int type; ++ ++ for (type = 0; type < MAX_NR_ZONES; type++) { ++ zone_t *zone = pg->node_zones + type; ++ ++ if (zone->size == 0) ++ continue; ++ ++ printk("----- Zone %d ------\n", type); ++ ++ show_zone_info(zone, fn); ++ } ++} ++ ++static void __show_page_info(void (*fn)(struct page *)) ++{ ++ pg_data_t *pg; ++ int pgdat = 0; ++ ++ for (pg = pgdat_list; pg; pg = pg->node_next) { ++ ++ printk("===== Node %d =====\n", pgdat++); ++ ++ show_node_info(pg, fn); ++ } ++} ++ ++void show_page_info(void) ++{ ++ __show_page_info(page_detail); ++} ++ ++static void ++show_pg_info(int key, struct pt_regs *regs, struct kbd_struct *kd, ++ struct tty_struct *tty) ++{ ++ void (*fn)(struct page *); ++ show_mem(); ++ if (key == 'g') ++ fn = page_detail; ++ else ++ fn = page_statistics; ++ __show_page_info(fn); ++} ++ ++static struct sysrq_key_op page_info_op = { ++ handler: show_pg_info, ++ help_msg: "paGeinfo", ++ action_msg: "Page Info", ++}; ++ ++static int __init debug_mm_init(void) ++{ ++ register_sysrq_key('g', &page_info_op); ++ register_sysrq_key('h', &page_info_op); ++ return 0; ++} ++ ++__initcall(debug_mm_init); +--- linux-2.4.25/mm/filemap.c~2.4.25-vrs2.patch 2004-02-18 14:36:32.000000000 +0100 ++++ linux-2.4.25/mm/filemap.c 2004-03-31 17:15:09.000000000 +0200 +@@ -2210,10 +2210,14 @@ + pte_t pte = *ptep; + + if (pte_present(pte)) { +- struct page *page = pte_page(pte); +- if (VALID_PAGE(page) && !PageReserved(page) && ptep_test_and_clear_dirty(ptep)) { +- flush_tlb_page(vma, address); +- set_page_dirty(page); ++ unsigned long pfn = pte_pfn(pte); ++ ++ if (pfn_valid(pfn)) { ++ struct page *page = pfn_to_page(pfn); ++ if (!PageReserved(page) && ptep_test_and_clear_dirty(ptep)) { ++ flush_tlb_page(vma, address); ++ set_page_dirty(page); ++ } + } + } + return 0; +--- linux-2.4.25/mm/memory.c~2.4.25-vrs2.patch 2003-11-28 19:26:21.000000000 +0100 ++++ linux-2.4.25/mm/memory.c 2004-03-31 17:15:09.000000000 +0200 +@@ -77,8 +77,13 @@ + */ + void __free_pte(pte_t pte) + { +- struct page *page = pte_page(pte); +- if ((!VALID_PAGE(page)) || PageReserved(page)) ++ unsigned long pfn = pte_pfn(pte); ++ struct page *page; ++ ++ if (!pfn_valid(pfn)) ++ return; ++ page = pfn_to_page(pfn); ++ if (PageReserved(page)) + return; + if (pte_dirty(pte)) + set_page_dirty(page); +@@ -232,6 +237,7 @@ + do { + pte_t pte = *src_pte; + struct page *ptepage; ++ unsigned long pfn; + + /* copy_one_pte */ + +@@ -241,9 +247,11 @@ + swap_duplicate(pte_to_swp_entry(pte)); + goto cont_copy_pte_range; + } +- ptepage = pte_page(pte); +- if ((!VALID_PAGE(ptepage)) || +- PageReserved(ptepage)) ++ pfn = pte_pfn(pte); ++ if (!pfn_valid(pfn)) ++ goto cont_copy_pte_range; ++ ptepage = pfn_to_page(pfn); ++ if (PageReserved(ptepage)) + goto cont_copy_pte_range; + + /* If it's a COW mapping, write protect it both in the parent and the child */ +@@ -314,9 +322,13 @@ + if (pte_none(pte)) + continue; + if (pte_present(pte)) { +- struct page *page = pte_page(pte); +- if (VALID_PAGE(page) && !PageReserved(page)) +- freed ++; ++ unsigned long pfn = pte_pfn(pte); ++ ++ if (pfn_valid(pfn)) { ++ struct page *page = pfn_to_page(pfn); ++ if (!PageReserved(page)) ++ freed ++; ++ } + /* This will eventually call __free_pte on the pte. */ + tlb_remove_page(tlb, ptep, address + offset); + } else { +@@ -354,17 +366,37 @@ + return freed; + } + ++void unmap_page_range(mmu_gather_t *tlb, struct mm_struct *mm, unsigned long address, unsigned long end) ++{ ++ int freed = 0; ++ pgd_t * dir; ++ ++ if (address >= end) ++ BUG(); ++ dir = pgd_offset(mm, address); ++ do { ++ freed += zap_pmd_range(tlb, dir, address, end - address); ++ address = (address + PGDIR_SIZE) & PGDIR_MASK; ++ dir++; ++ } while (address && (address < end)); ++ ++ /* ++ * Update rss for the mm_struct (not necessarily current->mm) ++ * Notice that rss is an unsigned long. ++ */ ++ if (mm->rss > freed) ++ mm->rss -= freed; ++ else ++ mm->rss = 0; ++} ++ + /* + * remove user pages in a given range. + */ + void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size) + { +- mmu_gather_t *tlb; +- pgd_t * dir; + unsigned long start = address, end = address + size; +- int freed = 0; +- +- dir = pgd_offset(mm, address); ++ mmu_gather_t *tlb; + + /* + * This is a long-lived spinlock. That's fine. +@@ -377,25 +409,10 @@ + BUG(); + spin_lock(&mm->page_table_lock); + flush_cache_range(mm, address, end); +- tlb = tlb_gather_mmu(mm); + +- do { +- freed += zap_pmd_range(tlb, dir, address, end - address); +- address = (address + PGDIR_SIZE) & PGDIR_MASK; +- dir++; +- } while (address && (address < end)); +- +- /* this will flush any remaining tlb entries */ ++ tlb = tlb_gather_mmu(mm); ++ unmap_page_range(tlb, mm, address, end); + tlb_finish_mmu(tlb, start, end); +- +- /* +- * Update rss for the mm_struct (not necessarily current->mm) +- * Notice that rss is an unsigned long. +- */ +- if (mm->rss > freed) +- mm->rss -= freed; +- else +- mm->rss = 0; + spin_unlock(&mm->page_table_lock); + } + +@@ -407,6 +424,7 @@ + pgd_t *pgd; + pmd_t *pmd; + pte_t *ptep, pte; ++ unsigned long pfn; + + pgd = pgd_offset(mm, address); + if (pgd_none(*pgd) || pgd_bad(*pgd)) +@@ -423,8 +441,11 @@ + pte = *ptep; + if (pte_present(pte)) { + if (!write || +- (pte_write(pte) && pte_dirty(pte))) +- return pte_page(pte); ++ (pte_write(pte) && pte_dirty(pte))) { ++ pfn = pte_pfn(pte); ++ if (pfn_valid(pfn)) ++ return pfn_to_page(pfn); ++ } + } + + out: +@@ -439,7 +460,8 @@ + + static inline struct page * get_page_map(struct page *page) + { +- if (!VALID_PAGE(page)) ++ unsigned long pfn = page_to_pfn(page); ++ if (!pfn_valid(pfn)) + return 0; + return page; + } +@@ -826,22 +848,22 @@ + unsigned long phys_addr, pgprot_t prot) + { + unsigned long end; ++ unsigned long pfn; + + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; ++ pfn = phys_addr >> PAGE_SHIFT; + do { +- struct page *page; + pte_t oldpage; + oldpage = ptep_get_and_clear(pte); + +- page = virt_to_page(__va(phys_addr)); +- if ((!VALID_PAGE(page)) || PageReserved(page)) +- set_pte(pte, mk_pte_phys(phys_addr, prot)); ++ if (!pfn_valid(pfn) || PageReserved(pfn_to_page(pfn))) ++ set_pte(pte, pfn_pte(pfn, prot)); + forget_pte(oldpage); + address += PAGE_SIZE; +- phys_addr += PAGE_SIZE; ++ pfn++; + pte++; + } while (address && (address < end)); + } +@@ -949,10 +971,11 @@ + unsigned long address, pte_t *page_table, pte_t pte) + { + struct page *old_page, *new_page; ++ unsigned long pfn = pte_pfn(pte); + +- old_page = pte_page(pte); +- if (!VALID_PAGE(old_page)) ++ if (!pfn_valid(pfn)) + goto bad_wp_page; ++ old_page = pte_page(pte); + + if (!TryLockPage(old_page)) { + int reuse = can_share_swap_page(old_page); +@@ -996,7 +1019,7 @@ + + bad_wp_page: + spin_unlock(&mm->page_table_lock); +- printk("do_wp_page: bogus page at address %08lx (page 0x%lx)\n",address,(unsigned long)old_page); ++ printk("do_wp_page: bogus page at address %08lx\n", address); + return -1; + no_mem: + page_cache_release(old_page); +--- linux-2.4.25/mm/mmap.c~2.4.25-vrs2.patch 2004-02-18 14:36:32.000000000 +0100 ++++ linux-2.4.25/mm/mmap.c 2004-03-31 17:15:09.000000000 +0200 +@@ -18,6 +18,9 @@ + + #include <asm/uaccess.h> + #include <asm/pgalloc.h> ++#include <asm/tlb.h> ++ ++extern void unmap_page_range(mmu_gather_t *tlb, struct mm_struct *mm, unsigned long start, unsigned long end); + + /* + * WARNING: the debugging will use recursive algorithms so never enable this +@@ -915,6 +918,8 @@ + * old method of shifting the VA >> by PGDIR_SHIFT doesn't work. + */ + start_index = pgd_index(first); ++ if (start_index < FIRST_USER_PGD_NR) ++ start_index = FIRST_USER_PGD_NR; + end_index = pgd_index(last); + if (end_index > start_index) { + clear_page_tables(mm, start_index, end_index - start_index); +@@ -1046,7 +1051,6 @@ + len = PAGE_ALIGN(len); + if (!len) + return addr; +- + if ((addr + len) > TASK_SIZE || (addr + len) < addr) + return -EINVAL; + +@@ -1135,45 +1139,58 @@ + /* Release all mmaps. */ + void exit_mmap(struct mm_struct * mm) + { ++ mmu_gather_t *tlb; + struct vm_area_struct * mpnt; + + release_segments(mm); + spin_lock(&mm->page_table_lock); ++ ++ tlb = tlb_gather_mmu(mm); ++ ++ flush_cache_mm(mm); ++ mpnt = mm->mmap; ++ while (mpnt) { ++ unsigned long start = mpnt->vm_start; ++ unsigned long end = mpnt->vm_end; ++ ++ mm->map_count--; ++ remove_shared_vm_struct(mpnt); ++ unmap_page_range(tlb, mm, start, end); ++ mpnt = mpnt->vm_next; ++ } ++ ++ /* This is just debugging */ ++ if (mm->map_count) ++ BUG(); ++ ++ tlb_finish_mmu(tlb, 0, TASK_SIZE); ++ + mpnt = mm->mmap; + mm->mmap = mm->mmap_cache = NULL; + mm->mm_rb = RB_ROOT; + mm->rss = 0; +- spin_unlock(&mm->page_table_lock); + mm->total_vm = 0; + mm->locked_vm = 0; + +- flush_cache_mm(mm); ++ spin_unlock(&mm->page_table_lock); ++ ++ clear_page_tables(mm, FIRST_USER_PGD_NR, USER_PTRS_PER_PGD); ++ ++ /* ++ * Walk the list again, actually closing and freeing it ++ * without holding any MM locks. ++ */ + while (mpnt) { + struct vm_area_struct * next = mpnt->vm_next; +- unsigned long start = mpnt->vm_start; +- unsigned long end = mpnt->vm_end; +- unsigned long size = end - start; +- + if (mpnt->vm_ops) { + if (mpnt->vm_ops->close) + mpnt->vm_ops->close(mpnt); + } +- mm->map_count--; +- remove_shared_vm_struct(mpnt); +- zap_page_range(mm, start, size); + if (mpnt->vm_file) + fput(mpnt->vm_file); + kmem_cache_free(vm_area_cachep, mpnt); + mpnt = next; + } +- +- /* This is just debugging */ +- if (mm->map_count) +- BUG(); +- +- clear_page_tables(mm, FIRST_USER_PGD_NR, USER_PTRS_PER_PGD); +- +- flush_tlb_mm(mm); + } + + /* Insert vm structure into process list sorted by address +--- linux-2.4.25/mm/slab.c~2.4.25-vrs2.patch 2003-11-28 19:26:21.000000000 +0100 ++++ linux-2.4.25/mm/slab.c 2004-03-31 17:15:09.000000000 +0200 +@@ -1391,7 +1391,7 @@ + #if DEBUG + # define CHECK_NR(pg) \ + do { \ +- if (!VALID_PAGE(pg)) { \ ++ if (!virt_addr_valid(pg)) { \ + printk(KERN_ERR "kfree: out of range ptr %lxh.\n", \ + (unsigned long)objp); \ + BUG(); \ +@@ -1950,12 +1950,12 @@ + name = cachep->name; + { + char tmp; +- mm_segment_t old_fs; ++ mm_segment_t old_fs; + old_fs = get_fs(); + set_fs(KERNEL_DS); + if (__get_user(tmp, name)) + name = "broken"; +- set_fs(old_fs); ++ set_fs (old_fs); + } + + seq_printf(m, "%-17s %6lu %6lu %6u %4lu %4lu %4u", +--- linux-2.4.25/mm/vmalloc.c~2.4.25-vrs2.patch 2003-08-25 13:44:44.000000000 +0200 ++++ linux-2.4.25/mm/vmalloc.c 2004-03-31 17:15:09.000000000 +0200 +@@ -44,8 +44,13 @@ + if (pte_none(page)) + continue; + if (pte_present(page)) { +- struct page *ptpage = pte_page(page); +- if (VALID_PAGE(ptpage) && (!PageReserved(ptpage))) ++ unsigned long pfn = pte_pfn(page); ++ struct page *ptpage; ++ ++ if (!pfn_valid(pfn)) ++ continue; ++ ptpage = pfn_to_page(pfn); ++ if (!PageReserved(ptpage)) + __free_page(ptpage); + continue; + } +--- linux-2.4.25/mm/vmscan.c~2.4.25-vrs2.patch 2004-02-18 14:36:32.000000000 +0100 ++++ linux-2.4.25/mm/vmscan.c 2004-03-31 17:15:09.000000000 +0200 +@@ -121,6 +121,7 @@ + drop_pte: + mm->rss--; + UnlockPage(page); ++ memc_clear(vma->vm_mm, page); + { + int freeable = page_count(page) - !!page->buffers <= 2; + page_cache_release(page); +@@ -206,13 +207,16 @@ + + do { + if (pte_present(*pte)) { +- struct page *page = pte_page(*pte); ++ unsigned long pfn = pte_pfn(*pte); + +- if (VALID_PAGE(page) && !PageReserved(page)) { +- count -= try_to_swap_out(mm, vma, address, pte, page, classzone); +- if (!count) { +- address += PAGE_SIZE; +- break; ++ if (pfn_valid(pfn)) { ++ struct page *page = pfn_to_page(pfn); ++ if (!PageReserved(page)) { ++ count -= try_to_swap_out(mm, vma, address, pte, page, classzone); ++ if (!count) { ++ address += PAGE_SIZE; ++ break; ++ } + } + } + } +--- linux-2.4.25/net/irda/af_irda.c~2.4.25-vrs2.patch 2003-11-28 19:26:21.000000000 +0100 ++++ linux-2.4.25/net/irda/af_irda.c 2004-03-31 17:15:09.000000000 +0200 +@@ -1176,7 +1176,7 @@ + #endif /* CONFIG_IRDA_ULTRA */ + kfree(self); + MOD_DEC_USE_COUNT; +- ++ + return; + } + +@@ -2571,19 +2571,15 @@ + sock_register(&irda_family_ops); + + irda_packet_type.type = htons(ETH_P_IRDA); +- dev_add_pack(&irda_packet_type); ++ dev_add_pack(&irda_packet_type); + + register_netdevice_notifier(&irda_dev_notifier); +- + irda_init(); + #ifdef MODULE +- irda_device_init(); /* Called by init/main.c when non-modular */ ++ irda_device_init(); /* Called by init/main.c when non-modular */ + #endif + return 0; + } +-#ifdef MODULE +-module_init(irda_proto_init); /* If non-module, called from init/main.c */ +-#endif + + /* + * Function irda_proto_cleanup (void) +@@ -2591,25 +2587,27 @@ + * Remove IrDA protocol layer + * + */ +-#ifdef MODULE +-void irda_proto_cleanup(void) ++static void __exit irda_proto_cleanup(void) + { + irda_packet_type.type = htons(ETH_P_IRDA); +- dev_remove_pack(&irda_packet_type); ++ dev_remove_pack(&irda_packet_type); ++ ++ unregister_netdevice_notifier(&irda_dev_notifier); + +- unregister_netdevice_notifier(&irda_dev_notifier); +- + sock_unregister(PF_IRDA); ++ + irda_cleanup(); +- +- return; + } ++ ++#ifdef MODULE ++module_init(irda_proto_init); + module_exit(irda_proto_cleanup); +- ++ + MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); +-MODULE_DESCRIPTION("The Linux IrDA Protocol Subsystem"); ++MODULE_DESCRIPTION("The Linux IrDA Protocol Subsystem"); + MODULE_LICENSE("GPL"); + #ifdef CONFIG_IRDA_DEBUG + MODULE_PARM(irda_debug, "1l"); + #endif +-#endif /* MODULE */ ++#endif ++ +--- linux-2.4.25/net/irda/iriap.c~2.4.25-vrs2.patch 2002-11-29 00:53:16.000000000 +0100 ++++ linux-2.4.25/net/irda/iriap.c 2004-03-31 17:15:09.000000000 +0200 +@@ -1004,18 +1004,20 @@ + + switch (attrib->value->type) { + case IAS_INTEGER: +- len += sprintf(buf+len, "%d\n", ++ len += sprintf(buf+len, "%d", + attrib->value->t.integer); + break; + case IAS_STRING: +- len += sprintf(buf+len, "\"%s\"\n", ++ len += sprintf(buf+len, "\"%s\"", + attrib->value->t.string); + break; + case IAS_OCT_SEQ: +- len += sprintf(buf+len, "octet sequence (%d bytes)\n", attrib->value->len); ++ len += sprintf(buf+len, ++ "octet sequence (%d bytes)", ++ attrib->value->len); + break; + case IAS_MISSING: +- len += sprintf(buf+len, "missing\n"); ++ len += sprintf(buf+len, "missing"); + break; + default: + IRDA_DEBUG(0, "%s(), Unknown value type!\n", __FUNCTION__); +@@ -1027,6 +1029,7 @@ + hashbin_get_next(obj->attribs); + } + obj = (struct ias_object *) hashbin_get_next(objects); ++ len += sprintf(buf+len, "\n"); + } + restore_flags(flags); + +--- linux-2.4.25/net/irda/irlan/irlan_common.c~2.4.25-vrs2.patch 2003-11-28 19:26:21.000000000 +0100 ++++ linux-2.4.25/net/irda/irlan/irlan_common.c 2004-03-31 17:15:09.000000000 +0200 +@@ -317,6 +317,9 @@ + + del_timer(&self->watchdog_timer); + ++ /* since irlan_do_*_event gobble the skb, we must get it once -- rmk */ ++ skb_get(skb); ++ + /* If you want to pass the skb to *both* state machines, you will + * need to skb_clone() it, so that you don't free it twice. + * As the state machines don't need it, git rid of it here... +--- linux-2.4.25/net/irda/irlap_event.c~2.4.25-vrs2.patch 2003-11-28 19:26:21.000000000 +0100 ++++ linux-2.4.25/net/irda/irlap_event.c 2004-03-31 17:15:09.000000000 +0200 +@@ -532,7 +532,7 @@ + #endif /* CONFIG_IRDA_ULTRA */ + case RECV_TEST_CMD: + /* Remove test frame header */ +- skb_pull(skb, sizeof(struct test_frame)); ++ skb_pull(skb, 10 /*sizeof(struct test_frame)*/); + + /* + * Send response. This skb will not be sent out again, and +@@ -740,7 +740,7 @@ + + switch (event) { + case CONNECT_RESPONSE: +- skb_pull(skb, sizeof(struct snrm_frame)); ++ skb_pull(skb, 11 /*sizeof(struct snrm_frame)*/); + + ASSERT(self->netdev != NULL, return -1;); + +@@ -870,7 +870,7 @@ + + ASSERT(self->netdev != NULL, return -1;); + +- skb_pull(skb, sizeof(struct snrm_frame)); ++ skb_pull(skb, 11 /*sizeof(struct snrm_frame)*/); + + irlap_qos_negotiate(self, skb); + +@@ -902,7 +902,7 @@ + /* Negotiate connection parameters */ + ASSERT(skb->len > 10, return -1;); + +- skb_pull(skb, sizeof(struct ua_frame)); ++ skb_pull(skb, 10 /*sizeof(struct ua_frame)*/); + + ASSERT(self->netdev != NULL, return -1;); + +--- linux-2.4.25/net/irda/irlap_frame.c~2.4.25-vrs2.patch 2003-11-28 19:26:21.000000000 +0100 ++++ linux-2.4.25/net/irda/irlap_frame.c 2004-03-31 17:15:09.000000000 +0200 +@@ -1,5 +1,5 @@ + /********************************************************************* +- * ++ * + * Filename: irlap_frame.c + * Version: 1.0 + * Description: Build and transmit IrLAP frames +@@ -8,18 +8,18 @@ + * Created at: Tue Aug 19 10:27:26 1997 + * Modified at: Wed Jan 5 08:59:04 2000 + * Modified by: Dag Brattli <dagb@cs.uit.no> +- * +- * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, ++ * ++ * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, + * All Rights Reserved. + * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.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 ++ * ++ * 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 Dag Brattli nor University of Troms� admit liability nor +- * provide warranty for any of this software. This material is ++ * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ +@@ -29,11 +29,12 @@ + #include <linux/if_ether.h> + #include <linux/netdevice.h> + #include <linux/irda.h> +- ++ + #include <net/pkt_sched.h> + #include <net/sock.h> +- ++ + #include <asm/byteorder.h> ++#include <asm/unaligned.h> + + #include <net/irda/irda.h> + #include <net/irda/irda_device.h> +@@ -46,18 +47,18 @@ + /* + * Function irlap_insert_info (self, skb) + * +- * Insert minimum turnaround time and speed information into the skb. We ++ * Insert minimum turnaround time and speed information into the skb. We + * need to do this since it's per packet relevant information. Safe to + * have this function inlined since it's only called from one place + */ +-static inline void irlap_insert_info(struct irlap_cb *self, ++static inline void irlap_insert_info(struct irlap_cb *self, + struct sk_buff *skb) + { + struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb; + +- /* ++ /* + * Insert MTT (min. turn time) and speed into skb, so that the +- * device driver knows which settings to use ++ * device driver knows which settings to use + */ + cb->magic = LAP_MAGIC; + cb->mtt = self->mtt_required; +@@ -65,15 +66,15 @@ + + /* Reset */ + self->mtt_required = 0; +- +- /* +- * Delay equals negotiated BOFs count, plus the number of BOFs to +- * force the negotiated minimum turnaround time ++ ++ /* ++ * Delay equals negotiated BOFs count, plus the number of BOFs to ++ * force the negotiated minimum turnaround time + */ + cb->xbofs = self->bofs_count; + cb->next_xbofs = self->next_bofs; + cb->xbofs_delay = self->xbofs_delay; +- ++ + /* Reset XBOF's delay (used only for getting min turn time) */ + self->xbofs_delay = 0; + /* Put the correct xbofs value for the next packet */ +@@ -104,7 +105,7 @@ + * + * Transmits a connect SNRM command frame + */ +-void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos) ++void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos) + { + struct sk_buff *skb; + struct snrm_frame *frame; +@@ -118,7 +119,7 @@ + if (!skb) + return; + +- frame = (struct snrm_frame *) skb_put(skb, 2); ++ frame = (struct snrm_frame *) skb_put(skb, 2); + + /* Insert connection address field */ + if (qos) +@@ -128,17 +129,17 @@ + + /* Insert control field */ + frame->control = SNRM_CMD | PF_BIT; +- ++ + /* +- * If we are establishing a connection then insert QoS paramerters ++ * If we are establishing a connection then insert QoS paramerters + */ + if (qos) { + skb_put(skb, 9); /* 21 left */ +- frame->saddr = cpu_to_le32(self->saddr); +- frame->daddr = cpu_to_le32(self->daddr); ++ put_unaligned(cpu_to_le32(self->saddr), &frame->saddr); ++ put_unaligned(cpu_to_le32(self->daddr), &frame->daddr); + + frame->ncaddr = self->caddr; +- ++ + ret = irlap_insert_qos_negotiation_params(self, skb); + if (ret < 0) { + dev_kfree_skb(skb); +@@ -154,13 +155,13 @@ + * Received SNRM (Set Normal Response Mode) command frame + * + */ +-static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb, +- struct irlap_info *info) ++static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb, ++ struct irlap_info *info) + { + struct snrm_frame *frame; + + frame = (struct snrm_frame *) skb->data; +- ++ + if (skb->len >= sizeof(struct snrm_frame)) { + /* Copy the new connection address ignoring the C/R bit */ + info->caddr = frame->ncaddr & 0xFE; +@@ -170,11 +171,11 @@ + IRDA_DEBUG(3, "%s(), invalid connection address!\n", __FUNCTION__); + return; + } +- ++ + /* Copy peer device address */ +- info->daddr = le32_to_cpu(frame->saddr); +- info->saddr = le32_to_cpu(frame->daddr); +- ++ info->daddr = le32_to_cpu(get_unaligned(&frame->saddr)); ++ info->saddr = le32_to_cpu(get_unaligned(&frame->daddr)); ++ + /* Only accept if addressed directly to us */ + if (info->saddr != self->saddr) { + IRDA_DEBUG(2, "%s(), not addressed to us!\n", __FUNCTION__); +@@ -198,9 +199,9 @@ + struct sk_buff *skb; + struct ua_frame *frame; + int ret; +- ++ + IRDA_DEBUG(2, "%s() <%ld>\n", __FUNCTION__, jiffies); +- ++ + ASSERT(self != NULL, return;); + ASSERT(self->magic == LAP_MAGIC, return;); + +@@ -212,13 +213,13 @@ + return; + + frame = (struct ua_frame *) skb_put(skb, 10); +- ++ + /* Build UA response */ + frame->caddr = self->caddr; + frame->control = UA_RSP | PF_BIT; + +- frame->saddr = cpu_to_le32(self->saddr); +- frame->daddr = cpu_to_le32(self->daddr); ++ put_unaligned(cpu_to_le32(self->saddr), &frame->saddr); ++ put_unaligned(cpu_to_le32(self->daddr), &frame->daddr); + + /* Should we send QoS negotiation parameters? */ + if (qos) { +@@ -243,7 +244,7 @@ + { + struct sk_buff *skb = NULL; + __u8 *frame; +- ++ + ASSERT(self != NULL, return;); + ASSERT(self->magic == LAP_MAGIC, return;); + +@@ -252,7 +253,7 @@ + return; + + frame = skb_put( skb, 2); +- ++ + if (self->state == LAP_NDM) + frame[0] = CBROADCAST; + else +@@ -260,7 +261,7 @@ + + frame[1] = DM_RSP | PF_BIT; + +- irlap_queue_xmit(self, skb); ++ irlap_queue_xmit(self, skb); + } + + /* +@@ -269,11 +270,11 @@ + * Send disconnect (DISC) frame + * + */ +-void irlap_send_disc_frame(struct irlap_cb *self) ++void irlap_send_disc_frame(struct irlap_cb *self) + { + struct sk_buff *skb = NULL; + __u8 *frame; +- ++ + IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + + ASSERT(self != NULL, return;); +@@ -284,7 +285,7 @@ + return; + + frame = skb_put(skb, 2); +- ++ + frame[0] = self->caddr | CMD_FRAME; + frame[1] = DISC_CMD | PF_BIT; + +@@ -295,17 +296,17 @@ + * Function irlap_send_discovery_xid_frame (S, s, command) + * + * Build and transmit a XID (eXchange station IDentifier) discovery +- * frame. ++ * frame. + */ +-void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s, +- __u8 command, discovery_t *discovery) ++void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s, ++ __u8 command, discovery_t *discovery) + { + struct sk_buff *skb = NULL; + struct xid_frame *frame; +- __u32 bcast = BROADCAST; ++ __u32 bcast = BROADCAST, daddr; + __u8 *info; + +- IRDA_DEBUG(4, "%s(), s=%d, S=%d, command=%d\n", __FUNCTION__, s, S, ++ IRDA_DEBUG(4, "%s(), s=%d, S=%d, command=%d\n", __FUNCTION__, s, S, + command); + + ASSERT(self != NULL, return;); +@@ -328,13 +329,14 @@ + } + frame->ident = XID_FORMAT; + +- frame->saddr = cpu_to_le32(self->saddr); +- + if (command) +- frame->daddr = cpu_to_le32(bcast); ++ daddr = bcast; + else +- frame->daddr = cpu_to_le32(discovery->daddr); +- ++ daddr = discovery->daddr; ++ ++ put_unaligned(cpu_to_le32(self->saddr), &frame->saddr); ++ put_unaligned(cpu_to_le32(daddr), &frame->daddr); ++ + switch (S) { + case 1: + frame->flags = 0x00; +@@ -353,10 +355,10 @@ + break; + } + +- frame->slotnr = s; ++ frame->slotnr = s; + frame->version = 0x00; + +- /* ++ /* + * Provide info for final slot only in commands, and for all + * responses. Send the second byte of the hint only if the + * EXTENSION bit is set in the first byte. +@@ -365,7 +367,7 @@ + int len; + + if (discovery->hints.byte[0] & HINT_EXTENSION) { +- info = skb_put(skb, 2); ++ info = skb_put(skb, 2); + info[0] = discovery->hints.byte[0]; + info[1] = discovery->hints.byte[1]; + } else { +@@ -378,7 +380,7 @@ + len = IRDA_MIN(discovery->name_len, skb_tailroom(skb)); + info = skb_put(skb, len); + memcpy(info, discovery->nickname, len); +- } ++ } + irlap_queue_xmit(self, skb); + } + +@@ -388,9 +390,9 @@ + * Received a XID discovery response + * + */ +-static void irlap_recv_discovery_xid_rsp(struct irlap_cb *self, +- struct sk_buff *skb, +- struct irlap_info *info) ++static void irlap_recv_discovery_xid_rsp(struct irlap_cb *self, ++ struct sk_buff *skb, ++ struct irlap_info *info) + { + struct xid_frame *xid; + discovery_t *discovery = NULL; +@@ -404,8 +406,8 @@ + + xid = (struct xid_frame *) skb->data; + +- info->daddr = le32_to_cpu(xid->saddr); +- info->saddr = le32_to_cpu(xid->daddr); ++ info->daddr = le32_to_cpu(get_unaligned(&xid->saddr)); ++ info->saddr = le32_to_cpu(get_unaligned(&xid->daddr)); + + /* Make sure frame is addressed to us */ + if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) { +@@ -439,11 +441,11 @@ + discovery->charset = discovery_info[1]; + text = (char *) &discovery_info[2]; + } +- /* +- * Terminate info string, should be safe since this is where the ++ /* ++ * Terminate info string, should be safe since this is where the + * FCS bytes resides. + */ +- skb->data[skb->len] = '\0'; ++ skb->data[skb->len] = '\0'; + strncpy(discovery->nickname, text, NICKNAME_MAX_LEN); + discovery->name_len = strlen(discovery->nickname); + +@@ -458,9 +460,9 @@ + * Received a XID discovery command + * + */ +-static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self, +- struct sk_buff *skb, +- struct irlap_info *info) ++static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self, ++ struct sk_buff *skb, ++ struct irlap_info *info) + { + struct xid_frame *xid; + discovery_t *discovery = NULL; +@@ -469,8 +471,8 @@ + + xid = (struct xid_frame *) skb->data; + +- info->daddr = le32_to_cpu(xid->saddr); +- info->saddr = le32_to_cpu(xid->daddr); ++ info->daddr = le32_to_cpu(get_unaligned(&xid->saddr)); ++ info->saddr = le32_to_cpu(get_unaligned(&xid->daddr)); + + /* Make sure frame is addressed to us */ + if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) { +@@ -497,11 +499,11 @@ + return; + } + info->s = xid->slotnr; +- ++ + discovery_info = skb_pull(skb, sizeof(struct xid_frame)); + +- /* +- * Check if last frame ++ /* ++ * Check if last frame + */ + if (info->s == 0xff) { + /* Check if things are sane at this point... */ +@@ -518,7 +520,7 @@ + WARNING("%s(), unable to malloc!\n", __FUNCTION__); + return; + } +- ++ + discovery->daddr = info->daddr; + discovery->saddr = self->saddr; + discovery->timestamp = jiffies; +@@ -533,11 +535,11 @@ + discovery->charset = discovery_info[1]; + text = (char *) &discovery_info[2]; + } +- /* +- * Terminate string, should be safe since this is where the ++ /* ++ * Terminate string, should be safe since this is where the + * FCS bytes resides. + */ +- skb->data[skb->len] = '\0'; ++ skb->data[skb->len] = '\0'; + strncpy(discovery->nickname, text, NICKNAME_MAX_LEN); + discovery->name_len = strlen(discovery->nickname); + +@@ -554,7 +556,7 @@ + * Build and transmit RR (Receive Ready) frame. Notice that it is currently + * only possible to send RR frames with the poll bit set. + */ +-void irlap_send_rr_frame(struct irlap_cb *self, int command) ++void irlap_send_rr_frame(struct irlap_cb *self, int command) + { + struct sk_buff *skb; + __u8 *frame; +@@ -562,9 +564,9 @@ + skb = dev_alloc_skb(16); + if (!skb) + return; +- ++ + frame = skb_put(skb, 2); +- ++ + frame[0] = self->caddr; + frame[0] |= (command) ? CMD_FRAME : 0; + +@@ -576,7 +578,7 @@ + /* + * Function irlap_send_rd_frame (self) + * +- * Request disconnect. Used by a secondary station to request the ++ * Request disconnect. Used by a secondary station to request the + * disconnection of the link. + */ + void irlap_send_rd_frame(struct irlap_cb *self) +@@ -587,9 +589,9 @@ + skb = dev_alloc_skb(16); + if (!skb) + return; +- ++ + frame = skb_put(skb, 2); +- ++ + frame[0] = self->caddr; + frame[1] = RD_RSP | PF_BIT; + +@@ -603,8 +605,8 @@ + * making it inline since its called only from one single place + * (irlap_driver_rcv). + */ +-static inline void irlap_recv_rr_frame(struct irlap_cb *self, +- struct sk_buff *skb, ++static inline void irlap_recv_rr_frame(struct irlap_cb *self, ++ struct sk_buff *skb, + struct irlap_info *info, int command) + { + info->nr = skb->data[1] >> 5; +@@ -620,7 +622,7 @@ + { + struct sk_buff *skb = NULL; + __u8 *frame; +- ++ + ASSERT( self != NULL, return;); + ASSERT( self->magic == LAP_MAGIC, return;); + +@@ -629,7 +631,7 @@ + return; + + frame = skb_put( skb, 2); +- ++ + frame[0] = self->caddr; + frame[0] |= (command) ? CMD_FRAME : 0; + +@@ -639,7 +641,7 @@ + + frame[2] = 0; + +- IRDA_DEBUG(4, "%s(), vr=%d, %ld\n", __FUNCTION__, self->vr, jiffies); ++ IRDA_DEBUG(4, "%s(), vr=%d, %ld\n", __FUNCTION__, self->vr, jiffies); + + irlap_queue_xmit(self, skb); + } +@@ -650,8 +652,8 @@ + * Received RNR (Receive Not Ready) frame from peer station + * + */ +-static void irlap_recv_rnr_frame(struct irlap_cb *self, struct sk_buff *skb, +- struct irlap_info *info, int command) ++static void irlap_recv_rnr_frame(struct irlap_cb *self, struct sk_buff *skb, ++ struct irlap_info *info, int command) + { + info->nr = skb->data[1] >> 5; + +@@ -663,13 +665,13 @@ + irlap_do_event(self, RECV_RNR_RSP, skb, info); + } + +-static void irlap_recv_rej_frame(struct irlap_cb *self, struct sk_buff *skb, ++static void irlap_recv_rej_frame(struct irlap_cb *self, struct sk_buff *skb, + struct irlap_info *info, int command) + { + IRDA_DEBUG(0, "%s()\n", __FUNCTION__); + + info->nr = skb->data[1] >> 5; +- ++ + /* Check if this is a command or a response frame */ + if (command) + irlap_do_event(self, RECV_REJ_CMD, skb, info); +@@ -677,13 +679,13 @@ + irlap_do_event(self, RECV_REJ_RSP, skb, info); + } + +-static void irlap_recv_srej_frame(struct irlap_cb *self, struct sk_buff *skb, ++static void irlap_recv_srej_frame(struct irlap_cb *self, struct sk_buff *skb, + struct irlap_info *info, int command) + { + IRDA_DEBUG(0, "%s()\n", __FUNCTION__); + + info->nr = skb->data[1] >> 5; +- ++ + /* Check if this is a command or a response frame */ + if (command) + irlap_do_event(self, RECV_SREJ_CMD, skb, info); +@@ -691,7 +693,7 @@ + irlap_do_event(self, RECV_SREJ_RSP, skb, info); + } + +-static void irlap_recv_disc_frame(struct irlap_cb *self, struct sk_buff *skb, ++static void irlap_recv_disc_frame(struct irlap_cb *self, struct sk_buff *skb, + struct irlap_info *info, int command) + { + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); +@@ -709,9 +711,9 @@ + * Received UA (Unnumbered Acknowledgement) frame + * + */ +-static inline void irlap_recv_ua_frame(struct irlap_cb *self, +- struct sk_buff *skb, +- struct irlap_info *info) ++static inline void irlap_recv_ua_frame(struct irlap_cb *self, ++ struct sk_buff *skb, ++ struct irlap_info *info) + { + irlap_do_event(self, RECV_UA_RSP, skb, info); + } +@@ -728,25 +730,25 @@ + + if (skb->data[1] == I_FRAME) { + +- /* ++ /* + * Insert frame sequence number (Vs) in control field before + * inserting into transmit window queue. + */ + skb->data[1] = I_FRAME | (self->vs << 1); +- ++ + /* Copy buffer */ + tx_skb = skb_clone(skb, GFP_ATOMIC); + if (tx_skb == NULL) { + return; + } +- +- /* +- * Insert frame in store, in case of retransmissions ++ ++ /* ++ * Insert frame in store, in case of retransmissions + */ + skb_queue_tail(&self->wx_list, skb_get(skb)); +- ++ + self->vs = (self->vs + 1) % 8; +- self->ack_required = FALSE; ++ self->ack_required = FALSE; + self->window -= 1; + + irlap_send_i_frame( self, tx_skb, CMD_FRAME); +@@ -761,40 +763,40 @@ + * + * Send I(nformation) frame as primary with poll bit set + */ +-void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb) ++void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb) + { + struct sk_buff *tx_skb; + + /* Stop P timer */ + del_timer(&self->poll_timer); +- ++ + /* Is this reliable or unreliable data? */ + if (skb->data[1] == I_FRAME) { +- +- /* ++ ++ /* + * Insert frame sequence number (Vs) in control field before + * inserting into transmit window queue. + */ + skb->data[1] = I_FRAME | (self->vs << 1); +- ++ + /* Copy buffer */ + tx_skb = skb_clone(skb, GFP_ATOMIC); + if (tx_skb == NULL) { + return; + } +- +- /* +- * Insert frame in store, in case of retransmissions ++ ++ /* ++ * Insert frame in store, in case of retransmissions + */ + skb_queue_tail(&self->wx_list, skb_get(skb)); +- +- /* ++ ++ /* + * Set poll bit if necessary. We do this to the copied + * skb, since retransmitted need to set or clear the poll +- * bit depending on when they are sent. ++ * bit depending on when they are sent. + */ + tx_skb->data[1] |= PF_BIT; +- ++ + self->vs = (self->vs + 1) % 8; + self->ack_required = FALSE; + +@@ -827,8 +829,8 @@ + * Send I(nformation) frame as secondary with final bit set + * + */ +-void irlap_send_data_secondary_final(struct irlap_cb *self, +- struct sk_buff *skb) ++void irlap_send_data_secondary_final(struct irlap_cb *self, ++ struct sk_buff *skb) + { + struct sk_buff *tx_skb = NULL; + +@@ -839,26 +841,26 @@ + /* Is this reliable or unreliable data? */ + if (skb->data[1] == I_FRAME) { + +- /* ++ /* + * Insert frame sequence number (Vs) in control field before + * inserting into transmit window queue. + */ + skb->data[1] = I_FRAME | (self->vs << 1); +- ++ + tx_skb = skb_clone(skb, GFP_ATOMIC); + if (tx_skb == NULL) { + return; +- } ++ } + + /* Insert frame in store */ + skb_queue_tail(&self->wx_list, skb_get(skb)); +- ++ + tx_skb->data[1] |= PF_BIT; +- +- self->vs = (self->vs + 1) % 8; ++ ++ self->vs = (self->vs + 1) % 8; + self->ack_required = FALSE; +- +- irlap_send_i_frame(self, tx_skb, RSP_FRAME); ++ ++ irlap_send_i_frame(self, tx_skb, RSP_FRAME); + } else { + if (self->ack_required) { + irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME); +@@ -885,32 +887,32 @@ + * Send I(nformation) frame as secondary without final bit set + * + */ +-void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb) ++void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb) + { + struct sk_buff *tx_skb = NULL; + + /* Is this reliable or unreliable data? */ + if (skb->data[1] == I_FRAME) { +- +- /* ++ ++ /* + * Insert frame sequence number (Vs) in control field before + * inserting into transmit window queue. + */ + skb->data[1] = I_FRAME | (self->vs << 1); +- ++ + tx_skb = skb_clone(skb, GFP_ATOMIC); + if (tx_skb == NULL) { + return; +- } +- ++ } ++ + /* Insert frame in store */ + skb_queue_tail(&self->wx_list, skb_get(skb)); +- ++ + self->vs = (self->vs + 1) % 8; +- self->ack_required = FALSE; ++ self->ack_required = FALSE; + self->window -= 1; + +- irlap_send_i_frame(self, tx_skb, RSP_FRAME); ++ irlap_send_i_frame(self, tx_skb, RSP_FRAME); + } else { + irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME); + self->window -= 1; +@@ -920,8 +922,8 @@ + /* + * Function irlap_resend_rejected_frames (nr) + * +- * Resend frames which has not been acknowledged. Should be safe to +- * traverse the list without locking it since this function will only be ++ * Resend frames which has not been acknowledged. Should be safe to ++ * traverse the list without locking it since this function will only be + * called from interrupt context (BH) + */ + void irlap_resend_rejected_frames(struct irlap_cb *self, int command) +@@ -943,8 +945,8 @@ + while (skb != NULL) { + irlap_wait_min_turn_around(self, &self->qos_tx); + +- /* We copy the skb to be retransmitted since we will have to +- * modify it. Cloning will confuse packet sniffers ++ /* We copy the skb to be retransmitted since we will have to ++ * modify it. Cloning will confuse packet sniffers + */ + /* tx_skb = skb_clone( skb, GFP_ATOMIC); */ + tx_skb = skb_copy(skb, GFP_ATOMIC); +@@ -959,17 +961,17 @@ + /* Clear old Nr field + poll bit */ + tx_skb->data[1] &= 0x0f; + +- /* ++ /* + * Set poll bit on the last frame retransmitted + */ + if (count-- == 1) + tx_skb->data[1] |= PF_BIT; /* Set p/f bit */ + else + tx_skb->data[1] &= ~PF_BIT; /* Clear p/f bit */ +- ++ + irlap_send_i_frame(self, tx_skb, command); + +- /* ++ /* + * If our skb is the last buffer in the list, then + * we are finished, if not, move to the next sk-buffer + */ +@@ -979,23 +981,23 @@ + skb = skb->next; + } + #if 0 /* Not yet */ +- /* ++ /* + * We can now fill the window with additinal data frames + */ + while (skb_queue_len( &self->txq) > 0) { +- ++ + IRDA_DEBUG(0, "%s(), sending additional frames!\n", __FUNCTION__); +- if ((skb_queue_len( &self->txq) > 0) && ++ if ((skb_queue_len( &self->txq) > 0) && + (self->window > 0)) { +- skb = skb_dequeue( &self->txq); ++ skb = skb_dequeue( &self->txq); + ASSERT(skb != NULL, return;); + + /* +- * If send window > 1 then send frame with pf ++ * If send window > 1 then send frame with pf + * bit cleared +- */ +- if ((self->window > 1) && +- skb_queue_len(&self->txq) > 0) ++ */ ++ if ((self->window > 1) && ++ skb_queue_len(&self->txq) > 0) + { + irlap_send_data_primary(self, skb); + } else { +@@ -1023,14 +1025,14 @@ + if (skb != NULL) { + irlap_wait_min_turn_around(self, &self->qos_tx); + +- /* We copy the skb to be retransmitted since we will have to +- * modify it. Cloning will confuse packet sniffers ++ /* We copy the skb to be retransmitted since we will have to ++ * modify it. Cloning will confuse packet sniffers + */ + /* tx_skb = skb_clone( skb, GFP_ATOMIC); */ + tx_skb = skb_copy(skb, GFP_ATOMIC); + if (!tx_skb) { + IRDA_DEBUG(0, "%s(), unable to copy\n", __FUNCTION__); +- return; ++ return; + } + /* Unlink tx_skb from list */ + tx_skb->next = tx_skb->prev = NULL; +@@ -1041,7 +1043,7 @@ + + /* Set poll/final bit */ + tx_skb->data[1] |= PF_BIT; /* Set p/f bit */ +- ++ + irlap_send_i_frame(self, tx_skb, command); + } + } +@@ -1052,15 +1054,15 @@ + * Contruct and transmit an Unnumbered Information (UI) frame + * + */ +-void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb, ++void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb, + __u8 caddr, int command) + { + IRDA_DEBUG(4, "%s()\n", __FUNCTION__); +- ++ + ASSERT(self != NULL, return;); + ASSERT(self->magic == LAP_MAGIC, return;); + ASSERT(skb != NULL, return;); +- ++ + /* Insert connection address */ + skb->data[0] = caddr | ((command) ? CMD_FRAME : 0); + +@@ -1072,13 +1074,13 @@ + * + * Contruct and transmit Information (I) frame + */ +-void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb, +- int command) ++void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb, ++ int command) + { + /* Insert connection address */ + skb->data[0] = self->caddr; + skb->data[0] |= (command) ? CMD_FRAME : 0; +- ++ + /* Insert next to receive (Vr) */ + skb->data[1] |= (self->vr << 5); /* insert nr */ + +@@ -1091,9 +1093,9 @@ + * Receive and parse an I (Information) frame, no harm in making it inline + * since it's called only from one single place (irlap_driver_rcv). + */ +-static inline void irlap_recv_i_frame(struct irlap_cb *self, +- struct sk_buff *skb, +- struct irlap_info *info, int command) ++static inline void irlap_recv_i_frame(struct irlap_cb *self, ++ struct sk_buff *skb, ++ struct irlap_info *info, int command) + { + info->nr = skb->data[1] >> 5; /* Next to receive */ + info->pf = skb->data[1] & PF_BIT; /* Final bit */ +@@ -1112,7 +1114,7 @@ + * Receive and parse an Unnumbered Information (UI) frame + * + */ +-static void irlap_recv_ui_frame(struct irlap_cb *self, struct sk_buff *skb, ++static void irlap_recv_ui_frame(struct irlap_cb *self, struct sk_buff *skb, + struct irlap_info *info) + { + IRDA_DEBUG( 4, "%s()\n", __FUNCTION__); +@@ -1128,19 +1130,19 @@ + * Received Frame Reject response. + * + */ +-static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb, +- struct irlap_info *info) ++static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb, ++ struct irlap_info *info) + { + __u8 *frame; + int w, x, y, z; + + IRDA_DEBUG(0, "%s()\n", __FUNCTION__); +- ++ + ASSERT(self != NULL, return;); + ASSERT(self->magic == LAP_MAGIC, return;); + ASSERT(skb != NULL, return;); + ASSERT(info != NULL, return;); +- ++ + frame = skb->data; + + info->nr = frame[2] >> 5; /* Next to receive */ +@@ -1151,11 +1153,11 @@ + x = frame[3] & 0x02; + y = frame[3] & 0x04; + z = frame[3] & 0x08; +- ++ + if (w) { + IRDA_DEBUG(0, "Rejected control field is undefined or not " + "implemented.\n"); +- } ++ } + if (x) { + IRDA_DEBUG(0, "Rejected control field was invalid because it " + "contained a non permitted I field.\n"); +@@ -1178,7 +1180,7 @@ + * Send a test frame response + * + */ +-void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr, ++void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr, + struct sk_buff *cmd) + { + struct sk_buff *skb; +@@ -1191,7 +1193,7 @@ + + /* Broadcast frames must include saddr and daddr fields */ + if (caddr == CBROADCAST) { +- frame = (struct test_frame *) ++ frame = (struct test_frame *) + skb_put(skb, sizeof(struct test_frame)); + + /* Insert the swapped addresses */ +@@ -1218,28 +1220,28 @@ + * Receive a test frame + * + */ +-static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb, ++static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb, + struct irlap_info *info, int command) + { + struct test_frame *frame; + + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); +- ++ + frame = (struct test_frame *) skb->data; +- ++ + /* Broadcast frames must carry saddr and daddr fields */ + if (info->caddr == CBROADCAST) { + if (skb->len < sizeof(struct test_frame)) { + IRDA_DEBUG(0, "%s() test frame to short!\n", __FUNCTION__); + return; + } +- ++ + /* Read and swap addresses */ +- info->daddr = le32_to_cpu(frame->saddr); +- info->saddr = le32_to_cpu(frame->daddr); ++ info->daddr = le32_to_cpu(get_unaligned(&frame->saddr)); ++ info->saddr = le32_to_cpu(get_unaligned(&frame->daddr)); + + /* Make sure frame is addressed to us */ +- if ((info->saddr != self->saddr) && ++ if ((info->saddr != self->saddr) && + (info->saddr != BROADCAST)) { + return; + } +@@ -1254,18 +1256,18 @@ + /* + * Function irlap_driver_rcv (skb, netdev, ptype) + * +- * Called when a frame is received. Dispatches the right receive function ++ * Called when a frame is received. Dispatches the right receive function + * for processing of the frame. + * + */ +-int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, ++int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *ptype) + { + struct irlap_info info; + struct irlap_cb *self; + int command; + __u8 control; +- ++ + /* FIXME: should we get our own field? */ + self = (struct irlap_cb *) dev->atalk_ptr; + +@@ -1281,10 +1283,10 @@ + dev_kfree_skb(skb); + return -1; + } +- ++ + command = skb->data[0] & CMD_FRAME; + info.caddr = skb->data[0] & CBROADCAST; +- ++ + info.pf = skb->data[1] & PF_BIT; + info.control = skb->data[1] & ~PF_BIT; /* Mask away poll/final bit */ + +@@ -1295,7 +1297,7 @@ + IRDA_DEBUG(0, "%s(), wrong connection address!\n", __FUNCTION__); + goto out; + } +- /* ++ /* + * Optimize for the common case and check if the frame is an + * I(nformation) frame. Only I-frames have bit 0 set to 0 + */ +@@ -1304,11 +1306,11 @@ + goto out; + } + /* +- * We now check is the frame is an S(upervisory) frame. Only ++ * We now check is the frame is an S(upervisory) frame. Only + * S-frames have bit 0 set to 1 and bit 1 set to 0 + */ + if (~control & 0x02) { +- /* ++ /* + * Received S(upervisory) frame, check which frame type it is + * only the first nibble is of interest + */ +@@ -1332,8 +1334,8 @@ + } + goto out; + } +- /* +- * This must be a C(ontrol) frame ++ /* ++ * This must be a C(ontrol) frame + */ + switch (control) { + case XID_RSP: +@@ -1369,6 +1371,6 @@ + break; + } + out: +- dev_kfree_skb(skb); ++ dev_kfree_skb(skb); + return 0; + } +--- linux-2.4.25/net/irda/irttp.c~2.4.25-vrs2.patch 2003-11-28 19:26:21.000000000 +0100 ++++ linux-2.4.25/net/irda/irttp.c 2004-03-31 17:15:09.000000000 +0200 +@@ -1665,8 +1665,8 @@ + } + self->rx_sdu_size = 0; + } +- +- /* ++ ++ /* + * It's not trivial to keep track of how many credits are available + * by incrementing at each packet, because delivery may fail + * (irttp_do_data_indication() may requeue the frame) and because +@@ -1676,7 +1676,7 @@ + * to send remote_credit. + * No need to spinlock, write is atomic and self correcting... + * Jean II +- */ ++ */ + self->avail_credit = (self->initial_credit - + (self->remote_credit + + skb_queue_len(&self->rx_queue) + +--- linux-2.4.25/net/sched/Config.in~2.4.25-vrs2.patch 2004-02-18 14:36:32.000000000 +0100 ++++ linux-2.4.25/net/sched/Config.in 2004-03-31 17:15:09.000000000 +0200 +@@ -3,9 +3,9 @@ + # + tristate ' CBQ packet scheduler' CONFIG_NET_SCH_CBQ + tristate ' HTB packet scheduler' CONFIG_NET_SCH_HTB +-tristate ' CSZ packet scheduler' CONFIG_NET_SCH_CSZ ++dep_tristate ' CSZ packet scheduler (experimental)' CONFIG_NET_SCH_CSZ $CONFIG_EXPERIMENTAL + #tristate ' H-PFQ packet scheduler' CONFIG_NET_SCH_HPFQ +-tristate ' H-FSC packet scheduler' CONFIG_NET_SCH_HFSC ++tristate ' H-FSC packet scheduler' CONFIG_NET_SCH_HFCS + if [ "$CONFIG_ATM" = "y" -o "$CONFIG_ATM" = "m" ]; then + dep_tristate ' ATM pseudo-scheduler' CONFIG_NET_SCH_ATM $CONFIG_ATM + fi diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/disable-pcmcia-probe.patch b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/disable-pcmcia-probe.patch index e69de29bb2..79ba036323 100644 --- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/disable-pcmcia-probe.patch +++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/disable-pcmcia-probe.patch @@ -0,0 +1,17 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux/drivers/pcmcia/Config.in~disable-pcmcia-probe 2003-05-13 11:18:23.000000000 +0200 ++++ linux/drivers/pcmcia/Config.in 2004-05-27 13:59:50.000000000 +0200 +@@ -15,9 +15,6 @@ + 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 diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/mkdep.patch b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/mkdep.patch index e69de29bb2..57218a7d1a 100644 --- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/mkdep.patch +++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/mkdep.patch @@ -0,0 +1,16 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux-2.4.25/Makefile~mkdep 2004-03-31 17:15:12.000000000 +0200 ++++ linux-2.4.25/Makefile 2004-03-31 17:18:50.000000000 +0200 +@@ -502,7 +502,7 @@ + ifdef CONFIG_MODVERSIONS + $(MAKE) update-modverfile + endif +- scripts/mkdep -- `find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend ++ $(foreach, dir, $(FINDHPATH), scripts/mkdep -- `find $(dir) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` >> .hdepend) + scripts/mkdep -- init/*.c > .depend + + ifdef CONFIG_MODVERSIONS diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/mppe-20040216.patch b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/mppe-20040216.patch index e69de29bb2..4393e2ea83 100644 --- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/mppe-20040216.patch +++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/mppe-20040216.patch @@ -0,0 +1,1225 @@ + +# +# Patch managed by http://www.holgerschurig.de/patcher.html +# + +--- linux-2.4.25/drivers/net/Config.in~mppe-20040216 ++++ linux-2.4.25/drivers/net/Config.in +@@ -327,6 +327,7 @@ + dep_tristate ' PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP + dep_tristate ' PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP + dep_tristate ' PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP $CONFIG_PPP ++ dep_tristate ' PPP MPPE compression (encryption)' CONFIG_PPP_MPPE $CONFIG_PPP + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP + fi +--- /dev/null ++++ linux-2.4.25/drivers/net/arcfour.c +@@ -0,0 +1,75 @@ ++/* ++ * arcfour.c ++ * by Frank Cusack <frank@google.com> ++ * 100% public domain ++ * ++ * Implemented from the description in _Applied Cryptography_, 2nd ed. ++ * ++ * ** Distribution ** of this software is unlimited and unrestricted. ++ * ++ * ** Use ** of this software is almost certainly legal; however, refer ++ * to <http://theory.lcs.mit.edu/~rivest/faq.html>. ++ */ ++ ++#include "arcfour.h" ++#if defined(__linux__) ++#include <linux/string.h> ++#endif ++ ++#define swap(a, b) \ ++{ \ ++ unsigned char t = b; \ ++ b = a; \ ++ a = t; \ ++} ++ ++/* ++ * Initialize arcfour from a key. ++ */ ++void ++arcfour_setkey(arcfour_context *context, const unsigned char *key, ++ unsigned keylen) ++{ ++ unsigned i, j; ++ unsigned char K[256]; ++ ++ context->i = context->j = 0; ++ ++ for (i = 0; i < 256; i++) { ++ context->S[i] = i; ++ K[i] = key[i % keylen]; ++ } ++ ++ j = 0; ++ for (i = 0; i < 256; i++) { ++ j = (j + context->S[i] + K[i]) % 256; ++ swap(context->S[i], context->S[j]); ++ } ++ ++ memset(K, 0, sizeof(K)); ++} ++ ++/* ++ * plaintext -> ciphertext (or vice versa) ++ */ ++void ++arcfour_encrypt(arcfour_context *context, const unsigned char *in, unsigned len, ++ unsigned char *out) ++{ ++ unsigned i = context->i; ++ unsigned j = context->j; ++ unsigned char *S = context->S; ++ unsigned char K; ++ ++ while (len--) { ++ i = (i + 1) % 256; ++ j = (j + S[i]) % 256; ++ swap(S[i], S[j]); ++ K = S[(S[i] + S[j]) % 256]; ++ *out++ = *in++ ^ K; ++ } ++ ++ context->i = i; ++ context->j = j; ++} ++ +--- /dev/null ++++ linux-2.4.25/drivers/net/arcfour.h +@@ -0,0 +1,17 @@ ++/* arcfour.h */ ++ ++#ifndef _ARCFOUR_H ++#define _ARCFOUR_H ++ ++typedef struct { ++ unsigned i; ++ unsigned j; ++ unsigned char S[256]; ++} arcfour_context; ++ ++extern void arcfour_setkey(arcfour_context *, const unsigned char *, unsigned); ++extern void arcfour_encrypt(arcfour_context *, const unsigned char *, unsigned, ++ unsigned char *); ++#define arcfour_decrypt arcfour_encrypt ++ ++#endif /* _ARCFOUR_H */ +--- linux-2.4.25/drivers/net/ppp_generic.c~mppe-20040216 ++++ linux-2.4.25/drivers/net/ppp_generic.c +@@ -102,6 +102,7 @@ + spinlock_t rlock; /* lock for receive side 58 */ + spinlock_t wlock; /* lock for transmit side 5c */ + int mru; /* max receive unit 60 */ ++ int mru_alloc; /* MAX(1500,MRU) for dev_alloc_skb() */ + unsigned int flags; /* control bits 64 */ + unsigned int xstate; /* transmit state bits 68 */ + unsigned int rstate; /* receive state bits 6c */ +@@ -129,6 +130,7 @@ + struct sock_fprog pass_filter; /* filter for packets to pass */ + struct sock_fprog active_filter;/* filter for pkts to reset idle */ + #endif /* CONFIG_PPP_FILTER */ ++ int xpad; /* ECP or CCP (MPPE) transmit padding */ + }; + + /* +@@ -552,7 +554,9 @@ + case PPPIOCSMRU: + if (get_user(val, (int *) arg)) + break; +- ppp->mru = val; ++ ppp->mru_alloc = ppp->mru = val; ++ if (ppp->mru_alloc < PPP_MRU) ++ ppp->mru_alloc = PPP_MRU; /* increase for broken peers */ + err = 0; + break; + +@@ -1031,8 +1035,8 @@ + /* try to do packet compression */ + if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0 + && proto != PPP_LCP && proto != PPP_CCP) { +- new_skb = alloc_skb(ppp->dev->mtu + ppp->dev->hard_header_len, +- GFP_ATOMIC); ++ new_skb = alloc_skb(ppp->dev->mtu + ppp->dev->hard_header_len ++ + ppp->xpad, GFP_ATOMIC); + if (new_skb == 0) { + printk(KERN_ERR "PPP: no memory (comp pkt)\n"); + goto drop; +@@ -1044,15 +1048,28 @@ + /* compressor still expects A/C bytes in hdr */ + len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2, + new_skb->data, skb->len + 2, +- ppp->dev->mtu + PPP_HDRLEN); ++ ppp->dev->mtu + ppp->xpad ++ + PPP_HDRLEN); + if (len > 0 && (ppp->flags & SC_CCP_UP)) { + kfree_skb(skb); + skb = new_skb; + skb_put(skb, len); + skb_pull(skb, 2); /* pull off A/C bytes */ +- } else { ++ } else if (len == 0) { + /* didn't compress, or CCP not up yet */ + kfree_skb(new_skb); ++ } else { ++ /* ++ * (len < 0) ++ * MPPE requires that we do not send unencrypted ++ * frames. The compressor will return -1 if we ++ * should drop the frame. We cannot simply test ++ * the compress_proto because MPPE and MPPC share ++ * the same number. ++ */ ++ printk(KERN_ERR "ppp: compressor dropped pkt\n"); ++ kfree_skb(new_skb); ++ goto drop; + } + } + +@@ -1540,14 +1557,15 @@ + int len; + + if (proto == PPP_COMP) { +- ns = dev_alloc_skb(ppp->mru + PPP_HDRLEN); ++ ns = dev_alloc_skb(ppp->mru_alloc + PPP_HDRLEN); + if (ns == 0) { + printk(KERN_ERR "ppp_decompress_frame: no memory\n"); + goto err; + } + /* the decompressor still expects the A/C bytes in the hdr */ + len = ppp->rcomp->decompress(ppp->rc_state, skb->data - 2, +- skb->len + 2, ns->data, ppp->mru + PPP_HDRLEN); ++ skb->len + 2, ns->data, ++ ppp->mru_alloc + PPP_HDRLEN); + if (len < 0) { + /* Pass the compressed frame to pppd as an + error indication. */ +@@ -1982,6 +2000,20 @@ + ocomp->comp_free(ostate); + err = 0; + } ++ if (ccp_option[0] == CI_MPPE) ++ /* ++ * pppd (userland) has reduced the MTU by MPPE_PAD, ++ * to accomodate "compressor" growth. We must ++ * increase the space allocated for compressor ++ * output in ppp_send_frame() accordingly. Note ++ * that from a purist's view, it may be more correct ++ * to require multilink and fragment large packets, ++ * but that seems inefficient compared to this ++ * little trick. ++ */ ++ ppp->xpad = MPPE_PAD; ++ else ++ ppp->xpad = 0; + + } else { + state = cp->decomp_alloc(ccp_option, data.length); +@@ -2253,6 +2285,7 @@ + /* Initialize the new ppp unit */ + ppp->file.index = unit; + ppp->mru = PPP_MRU; ++ ppp->mru_alloc = PPP_MRU; + init_ppp_file(&ppp->file, INTERFACE); + ppp->file.hdrlen = PPP_HDRLEN - 2; /* don't count proto bytes */ + for (i = 0; i < NUM_NP; ++i) +--- /dev/null ++++ linux-2.4.25/drivers/net/ppp_mppe_compress.c +@@ -0,0 +1,643 @@ ++/* ++ * ==FILEVERSION 20020521== ++ * ++ * ppp_mppe_compress.c - interface MPPE to the PPP code. ++ * This version is for use with Linux kernel 2.2.19+ and 2.4.x. ++ * ++ * By Frank Cusack <frank@google.com>. ++ * Copyright (c) 2002 Google, Inc. ++ * All rights reserved. ++ * ++ * Permission to use, copy, modify, and distribute this software and its ++ * documentation is hereby granted, provided that the above copyright ++ * notice appears in all copies. This software is provided without any ++ * warranty, express or implied. ++ * ++ * Changelog: ++ * 2/15/04 - TS: added #include <version.h> and testing for Kernel ++ * version before using ++ * MOD_DEC_USAGE_COUNT/MOD_INC_USAGE_COUNT which are ++ * depreciated in 2.6 ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/version.h> ++#include <linux/init.h> ++#include <linux/types.h> ++#include <linux/slab.h> ++#include <linux/string.h> ++ ++#include <linux/ppp_defs.h> ++#include <linux/ppp-comp.h> ++ ++#include "arcfour.h" ++#include "sha1.h" ++ ++/* ++ * State for an MPPE (de)compressor. ++ */ ++typedef struct ppp_mppe_state { ++ unsigned char master_key[MPPE_MAX_KEY_LEN]; ++ unsigned char session_key[MPPE_MAX_KEY_LEN]; ++ arcfour_context arcfour_context; /* encryption state */ ++ unsigned keylen; /* key length in bytes */ ++ /* NB: 128-bit == 16, 40-bit == 8! */ ++ /* If we want to support 56-bit, */ ++ /* the unit has to change to bits */ ++ unsigned char bits; /* MPPE control bits */ ++ unsigned ccount; /* 12-bit coherency count (seqno) */ ++ unsigned stateful; /* stateful mode flag */ ++ int discard; /* stateful mode packet loss flag */ ++ int sanity_errors; /* take down LCP if too many */ ++ int unit; ++ int debug; ++ struct compstat stats; ++} ppp_mppe_state; ++ ++/* ppp_mppe_state.bits definitions */ ++#define MPPE_BIT_A 0x80 /* Encryption table were (re)inititalized */ ++#define MPPE_BIT_B 0x40 /* MPPC only (not implemented) */ ++#define MPPE_BIT_C 0x20 /* MPPC only (not implemented) */ ++#define MPPE_BIT_D 0x10 /* This is an encrypted frame */ ++ ++#define MPPE_BIT_FLUSHED MPPE_BIT_A ++#define MPPE_BIT_ENCRYPTED MPPE_BIT_D ++ ++#define MPPE_BITS(p) ((p)[4] & 0xf0) ++#define MPPE_CCOUNT(p) ((((p)[4] & 0x0f) << 8) + (p)[5]) ++#define MPPE_CCOUNT_SPACE 0x1000 /* The size of the ccount space */ ++ ++#define MPPE_OVHD 2 /* MPPE overhead/packet */ ++#define SANITY_MAX 1600 /* Max bogon factor we will tolerate */ ++ ++static void GetNewKeyFromSHA __P((unsigned char *StartKey, ++ unsigned char *SessionKey, ++ unsigned SessionKeyLength, ++ unsigned char *InterimKey)); ++static void mppe_rekey __P((ppp_mppe_state *state, int)); ++static void *mppe_alloc __P((unsigned char *options, int optlen)); ++static void mppe_free __P((void *state)); ++static int mppe_init __P((void *state, unsigned char *options, ++ int optlen, int unit, int debug, const char *)); ++static int mppe_comp_init __P((void *state, unsigned char *options, ++ int optlen, ++ int unit, int hdrlen, int debug)); ++static int mppe_decomp_init __P((void *state, unsigned char *options, ++ int optlen, int unit, ++ int hdrlen, int mru, int debug)); ++static int mppe_compress __P((void *state, unsigned char *ibuf, ++ unsigned char *obuf, ++ int isize, int osize)); ++static void mppe_incomp __P((void *state, unsigned char *ibuf, int icnt)); ++static int mppe_decompress __P((void *state, unsigned char *ibuf, ++ int isize, unsigned char *obuf,int osize)); ++static void mppe_comp_reset __P((void *state)); ++static void mppe_decomp_reset __P((void *state)); ++static void mppe_comp_stats __P((void *state, struct compstat *stats)); ++ ++ ++/* ++ * Key Derivation, from RFC 3078, RFC 3079. ++ * Equivalent to Get_Key() for MS-CHAP as described in RFC 3079. ++ */ ++static void ++GetNewKeyFromSHA(unsigned char *MasterKey, unsigned char *SessionKey, ++ unsigned SessionKeyLength, unsigned char *InterimKey) ++{ ++ SHA1_CTX Context; ++ unsigned char Digest[SHA1_SIGNATURE_SIZE]; ++ ++ unsigned char SHApad1[40] = ++ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ++ unsigned char SHApad2[40] = ++ { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, ++ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, ++ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, ++ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 }; ++ ++ /* assert(SessionKeyLength <= SHA1_SIGNATURE_SIZE); */ ++ ++ SHA1_Init(&Context); ++ SHA1_Update(&Context, MasterKey, SessionKeyLength); ++ SHA1_Update(&Context, SHApad1, sizeof(SHApad1)); ++ SHA1_Update(&Context, SessionKey, SessionKeyLength); ++ SHA1_Update(&Context, SHApad2, sizeof(SHApad2)); ++ SHA1_Final(Digest, &Context); ++ ++ memcpy(InterimKey, Digest, SessionKeyLength); ++} ++ ++/* ++ * Perform the MPPE rekey algorithm, from RFC 3078, sec. 7.3. ++ * Well, not what's written there, but rather what they meant. ++ */ ++static void ++mppe_rekey(ppp_mppe_state *state, int initial_key) ++{ ++ unsigned char InterimKey[MPPE_MAX_KEY_LEN]; ++ ++ GetNewKeyFromSHA(state->master_key, state->session_key, ++ state->keylen, InterimKey); ++ if (!initial_key) { ++ arcfour_setkey(&state->arcfour_context, InterimKey, state->keylen); ++ arcfour_encrypt(&state->arcfour_context, InterimKey, state->keylen, ++ state->session_key); ++ } else { ++ memcpy(state->session_key, InterimKey, state->keylen); ++ } ++ if (state->keylen == 8) { ++ /* See RFC 3078 */ ++ state->session_key[0] = 0xd1; ++ state->session_key[1] = 0x26; ++ state->session_key[2] = 0x9e; ++ } ++ arcfour_setkey(&state->arcfour_context, state->session_key, state->keylen); ++} ++ ++ ++/* ++ * Allocate space for a (de)compressor. ++ */ ++static void * ++mppe_alloc(unsigned char *options, int optlen) ++{ ++ ppp_mppe_state *state; ++ ++ if (optlen != CILEN_MPPE + sizeof(state->master_key) ++ || options[0] != CI_MPPE ++ || options[1] != CILEN_MPPE) ++ return NULL; ++ ++ state = (ppp_mppe_state *) kmalloc(sizeof(*state), GFP_KERNEL); ++ if (state == NULL) ++ return NULL; ++ ++/* ++ Added to avoid module warnings about MOD_INC ++ being depreciated in 2.6.x ++*/ ++#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) ) ++ try_module_get(THIS_MODULE); ++#else ++ MOD_INC_USE_COUNT; ++#endif ++ memset(state, 0, sizeof(*state)); ++ ++ /* Save keys. */ ++ memcpy(state->master_key, &options[CILEN_MPPE], sizeof(state->master_key)); ++ memcpy(state->session_key, state->master_key, sizeof(state->master_key)); ++ /* ++ * We defer initial key generation until mppe_init(), as mppe_alloc() ++ * is called frequently during negotiation. ++ */ ++ ++ return (void *) state; ++} ++ ++/* ++ * Deallocate space for a (de)compressor. ++ */ ++static void ++mppe_free(void *arg) ++{ ++ ppp_mppe_state *state = (ppp_mppe_state *) arg; ++ ++ if (state) { ++ kfree(state); ++/* ++ Added to avoid module warnings about MOD_DEC_USE_COUNT ++ being depreciated in 2.6.x ++*/ ++#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) ) ++ module_put(THIS_MODULE); ++#else ++ MOD_DEC_USE_COUNT; ++#endif ++ } ++} ++ ++ ++/* ++ * Initialize (de)compressor state. ++ */ ++static int ++mppe_init(void *arg, unsigned char *options, int optlen, int unit, int debug, ++ const char *debugstr) ++{ ++ ppp_mppe_state *state = (ppp_mppe_state *) arg; ++ unsigned char mppe_opts; ++ ++ if (optlen != CILEN_MPPE ++ || options[0] != CI_MPPE ++ || options[1] != CILEN_MPPE) ++ return 0; ++ ++ MPPE_CI_TO_OPTS(&options[2], mppe_opts); ++ if (mppe_opts & MPPE_OPT_128) ++ state->keylen = 16; ++ else if (mppe_opts & MPPE_OPT_40) ++ state->keylen = 8; ++ else { ++ printk(KERN_WARNING "%s[%d]: unknown key length\n", debugstr, unit); ++ return 0; ++ } ++ if (mppe_opts & MPPE_OPT_STATEFUL) ++ state->stateful = 1; ++ ++ /* Generate the initial session key. */ ++ mppe_rekey(state, 1); ++ ++ if (debug) { ++ int i; ++ char mkey[sizeof(state->master_key) * 2 + 1]; ++ char skey[sizeof(state->session_key) * 2 + 1]; ++ ++ printk(KERN_DEBUG "%s[%d]: initialized with %d-bit %s mode\n", debugstr, ++ unit, (state->keylen == 16)? 128: 40, ++ (state->stateful)? "stateful": "stateless"); ++ ++ for (i = 0; i < sizeof(state->master_key); i++) ++ sprintf(mkey + i * 2, "%.2x", state->master_key[i]); ++ for (i = 0; i < sizeof(state->session_key); i++) ++ sprintf(skey + i * 2, "%.2x", state->session_key[i]); ++ printk(KERN_DEBUG "%s[%d]: keys: master: %s initial session: %s\n", ++ debugstr, unit, mkey, skey); ++ } ++ ++ /* ++ * Initialize the coherency count. The initial value is not specified ++ * in RFC 3078, but we can make a reasonable assumption that it will ++ * start at 0. Setting it to the max here makes the comp/decomp code ++ * do the right thing (determined through experiment). ++ */ ++ state->ccount = MPPE_CCOUNT_SPACE - 1; ++ ++ /* ++ * Note that even though we have initialized the key table, we don't ++ * set the FLUSHED bit. This is contrary to RFC 3078, sec. 3.1. ++ */ ++ state->bits = MPPE_BIT_ENCRYPTED; ++ ++ state->unit = unit; ++ state->debug = debug; ++ ++ return 1; ++} ++ ++ ++ ++static int ++mppe_comp_init(void *arg, unsigned char *options, int optlen, int unit, ++ int hdrlen, int debug) ++{ ++ /* ARGSUSED */ ++ return mppe_init(arg, options, optlen, unit, debug, "mppe_comp_init"); ++} ++ ++/* ++ * We received a CCP Reset-Request (actually, we are sending a Reset-Ack), ++ * tell the compressor to rekey. Note that we MUST NOT rekey for ++ * every CCP Reset-Request; we only rekey on the next xmit packet. ++ * We might get multiple CCP Reset-Requests if our CCP Reset-Ack is lost. ++ * So, rekeying for every CCP Reset-Request is broken as the peer will not ++ * know how many times we've rekeyed. (If we rekey and THEN get another ++ * CCP Reset-Request, we must rekey again.) ++ */ ++static void ++mppe_comp_reset(void *arg) ++{ ++ ppp_mppe_state *state = (ppp_mppe_state *) arg; ++ ++ state->bits |= MPPE_BIT_FLUSHED; ++} ++ ++/* ++ * Compress (encrypt) a packet. ++ * It's strange to call this a compressor, since the output is always ++ * MPPE_OVHD + 2 bytes larger than the input. ++ */ ++int ++mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf, ++ int isize, int osize) ++{ ++ ppp_mppe_state *state = (ppp_mppe_state *) arg; ++ int proto; ++ ++ /* ++ * Check that the protocol is in the range we handle. ++ */ ++ proto = PPP_PROTOCOL(ibuf); ++ if (proto < 0x0021 || proto > 0x00fa) ++ return 0; ++ ++ /* Make sure we have enough room to generate an encrypted packet. */ ++ if (osize < isize + MPPE_OVHD + 2) { ++ /* Drop the packet if we should encrypt it, but can't. */ ++ printk(KERN_DEBUG "mppe_compress[%d]: osize too small! " ++ "(have: %d need: %d)\n", state->unit, ++ osize, osize + MPPE_OVHD + 2); ++ return -1; ++ } ++ ++ osize = isize + MPPE_OVHD + 2; ++ ++ /* ++ * Copy over the PPP header and set control bits. ++ */ ++ obuf[0] = PPP_ADDRESS(ibuf); ++ obuf[1] = PPP_CONTROL(ibuf); ++ obuf[2] = PPP_COMP >> 8; /* isize + MPPE_OVHD + 1 */ ++ obuf[3] = PPP_COMP; /* isize + MPPE_OVHD + 2 */ ++ obuf += PPP_HDRLEN; ++ ++ state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; ++ if (state->debug >= 7) ++ printk(KERN_DEBUG "mppe_compress[%d]: ccount %d\n", state->unit, ++ state->ccount); ++ obuf[0] = state->ccount >> 8; ++ obuf[1] = state->ccount & 0xff; ++ ++ if (!state->stateful || /* stateless mode */ ++ ((state->ccount & 0xff) == 0xff) || /* "flag" packet */ ++ (state->bits & MPPE_BIT_FLUSHED)) { /* CCP Reset-Request */ ++ /* We must rekey */ ++ if (state->debug && state->stateful) ++ printk(KERN_DEBUG "mppe_compress[%d]: rekeying\n", state->unit); ++ mppe_rekey(state, 0); ++ state->bits |= MPPE_BIT_FLUSHED; ++ } ++ obuf[0] |= state->bits; ++ state->bits &= ~MPPE_BIT_FLUSHED; /* reset for next xmit */ ++ ++ obuf += MPPE_OVHD; ++ ibuf += 2; /* skip to proto field */ ++ isize -= 2; ++ ++ /* Encrypt packet */ ++ arcfour_encrypt(&state->arcfour_context, ibuf, isize, obuf); ++ ++ state->stats.unc_bytes += isize; ++ state->stats.unc_packets++; ++ state->stats.comp_bytes += osize; ++ state->stats.comp_packets++; ++ ++ return osize; ++} ++ ++/* ++ * Since every frame grows by MPPE_OVHD + 2 bytes, this is always going ++ * to look bad ... and the longer the link is up the worse it will get. ++ */ ++static void ++mppe_comp_stats(void *arg, struct compstat *stats) ++{ ++ ppp_mppe_state *state = (ppp_mppe_state *) arg; ++ ++ *stats = state->stats; ++} ++ ++ ++static int ++mppe_decomp_init(void *arg, unsigned char *options, int optlen, int unit, ++ int hdrlen, int mru, int debug) ++{ ++ /* ARGSUSED */ ++ return mppe_init(arg, options, optlen, unit, debug, "mppe_decomp_init"); ++} ++ ++/* ++ * We received a CCP Reset-Ack. Just ignore it. ++ */ ++static void ++mppe_decomp_reset(void *arg) ++{ ++ /* ARGSUSED */ ++ return; ++} ++ ++/* ++ * Decompress (decrypt) an MPPE packet. ++ */ ++int ++mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf, ++ int osize) ++{ ++ ppp_mppe_state *state = (ppp_mppe_state *) arg; ++ unsigned ccount; ++ int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED; ++ int sanity = 0; ++ ++ if (isize <= PPP_HDRLEN + MPPE_OVHD) { ++ if (state->debug) ++ printk(KERN_DEBUG "mppe_decompress[%d]: short pkt (%d)\n", ++ state->unit, isize); ++ return DECOMP_ERROR; ++ } ++ ++ /* Make sure we have enough room to decrypt the packet. */ ++ if (osize < isize - MPPE_OVHD - 2) { ++ printk(KERN_DEBUG "mppe_decompress[%d]: osize too small! " ++ "(have: %d need: %d)\n", state->unit, ++ osize, isize - MPPE_OVHD - 2); ++ return DECOMP_ERROR; ++ } ++ osize = isize - MPPE_OVHD - 2; ++ ++ ccount = MPPE_CCOUNT(ibuf); ++ if (state->debug >= 7) ++ printk(KERN_DEBUG "mppe_decompress[%d]: ccount %d\n", state->unit, ++ ccount); ++ ++ /* sanity checks -- terminate with extreme prejudice */ ++ if (!(MPPE_BITS(ibuf) & MPPE_BIT_ENCRYPTED)) { ++ printk(KERN_DEBUG "mppe_decompress[%d]: ENCRYPTED bit not set!\n", ++ state->unit); ++ state->sanity_errors += 100; ++ sanity = 1; ++ } ++ if (!state->stateful && !flushed) { ++ printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set in " ++ "stateless mode!\n", state->unit); ++ state->sanity_errors += 100; ++ sanity = 1; ++ } ++ if (state->stateful && ((ccount & 0xff) == 0xff) && !flushed) { ++ printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set on " ++ "flag packet!\n", state->unit); ++ state->sanity_errors += 100; ++ sanity = 1; ++ } ++ ++ if (sanity) { ++ if (state->sanity_errors < SANITY_MAX) ++ return DECOMP_ERROR; ++ else ++ /* ++ * Take LCP down if the peer is sending too many bogons. ++ * We don't want to do this for a single or just a few ++ * instances since it could just be due to packet corruption. ++ */ ++ return DECOMP_FATALERROR; ++ } ++ ++ /* ++ * Check the coherency count. ++ */ ++ ++ if (!state->stateful) { ++ /* RFC 3078, sec 8.1. Rekey for every packet. */ ++ while (state->ccount != ccount) { ++ mppe_rekey(state, 0); ++ state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; ++ } ++ } else { ++ /* RFC 3078, sec 8.2. */ ++ if (!state->discard) { ++ /* normal state */ ++ state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; ++ if (ccount != state->ccount) { ++ /* ++ * (ccount > state->ccount) ++ * Packet loss detected, enter the discard state. ++ * Signal the peer to rekey (by sending a CCP Reset-Request). ++ */ ++ state->discard = 1; ++ return DECOMP_ERROR; ++ } ++ } else { ++ /* discard state */ ++ if (!flushed) { ++ /* ccp.c will be silent (no additional CCP Reset-Requests). */ ++ return DECOMP_ERROR; ++ } else { ++ /* Rekey for every missed "flag" packet. */ ++ while ((ccount & ~0xff) != (state->ccount & ~0xff)) { ++ mppe_rekey(state, 0); ++ state->ccount = (state->ccount + 256) % MPPE_CCOUNT_SPACE; ++ } ++ ++ /* reset */ ++ state->discard = 0; ++ state->ccount = ccount; ++ /* ++ * Another problem with RFC 3078 here. It implies that the ++ * peer need not send a Reset-Ack packet. But RFC 1962 ++ * requires it. Hopefully, M$ does send a Reset-Ack; even ++ * though it isn't required for MPPE synchronization, it is ++ * required to reset CCP state. ++ */ ++ } ++ } ++ if (flushed) ++ mppe_rekey(state, 0); ++ } ++ ++ /* ++ * Fill in the first part of the PPP header. The protocol field ++ * comes from the decrypted data. ++ */ ++ obuf[0] = PPP_ADDRESS(ibuf); /* +1 */ ++ obuf[1] = PPP_CONTROL(ibuf); /* +1 */ ++ obuf += 2; ++ ibuf += PPP_HDRLEN + MPPE_OVHD; ++ isize -= PPP_HDRLEN + MPPE_OVHD; /* -6 */ ++ /* net osize: isize-4 */ ++ ++ /* And finally, decrypt the packet. */ ++ arcfour_decrypt(&state->arcfour_context, ibuf, isize, obuf); ++ ++ state->stats.unc_bytes += osize; ++ state->stats.unc_packets++; ++ state->stats.comp_bytes += isize; ++ state->stats.comp_packets++; ++ ++ /* good packet credit */ ++ state->sanity_errors >>= 1; ++ ++ return osize; ++} ++ ++/* ++ * Incompressible data has arrived (this should never happen!). ++ * We should probably drop the link if the protocol is in the range ++ * of what should be encrypted. At the least, we should drop this ++ * packet. (How to do this?) ++ */ ++static void ++mppe_incomp(void *arg, unsigned char *ibuf, int icnt) ++{ ++ ppp_mppe_state *state = (ppp_mppe_state *) arg; ++ ++ if (state->debug && ++ (PPP_PROTOCOL(ibuf) >= 0x0021 && PPP_PROTOCOL(ibuf) <= 0x00fa)) ++ printk(KERN_DEBUG "mppe_incomp[%d]: incompressible (unencrypted) data! " ++ "(proto %04x)\n", state->unit, PPP_PROTOCOL(ibuf)); ++ ++ state->stats.inc_bytes += icnt; ++ state->stats.inc_packets++; ++ state->stats.unc_bytes += icnt; ++ state->stats.unc_packets++; ++} ++ ++/************************************************************* ++ * Module interface table ++ *************************************************************/ ++ ++/* These are in ppp.c (2.2.x) or ppp_generic.c (2.4.x) */ ++extern int ppp_register_compressor (struct compressor *cp); ++extern void ppp_unregister_compressor (struct compressor *cp); ++ ++/* ++ * Procedures exported to if_ppp.c. ++ */ ++struct compressor ppp_mppe = { ++ CI_MPPE, /* compress_proto */ ++ mppe_alloc, /* comp_alloc */ ++ mppe_free, /* comp_free */ ++ mppe_comp_init, /* comp_init */ ++ mppe_comp_reset, /* comp_reset */ ++ mppe_compress, /* compress */ ++ mppe_comp_stats, /* comp_stat */ ++ mppe_alloc, /* decomp_alloc */ ++ mppe_free, /* decomp_free */ ++ mppe_decomp_init, /* decomp_init */ ++ mppe_decomp_reset, /* decomp_reset */ ++ mppe_decompress, /* decompress */ ++ mppe_incomp, /* incomp */ ++ mppe_comp_stats, /* decomp_stat */ ++}; ++ ++/* 2.2 compatibility defines */ ++#ifndef __init ++#define __init ++#endif ++#ifndef __exit ++#define __exit ++#endif ++#ifndef MODULE_LICENSE ++#define MODULE_LICENSE(license) ++#endif ++ ++int __init ++ppp_mppe_init(void) ++{ ++ int answer = ppp_register_compressor(&ppp_mppe); ++ ++ if (answer == 0) ++ printk(KERN_INFO "PPP MPPE Compression module registered\n"); ++ return answer; ++} ++ ++void __exit ++ppp_mppe_cleanup(void) ++{ ++ ppp_unregister_compressor(&ppp_mppe); ++} ++ ++module_init(ppp_mppe_init); ++module_exit(ppp_mppe_cleanup); ++MODULE_LICENSE("BSD without advertisement clause"); +--- /dev/null ++++ linux-2.4.25/drivers/net/sha1.c +@@ -0,0 +1,185 @@ ++/* ++ * ftp://ftp.funet.fi/pub/crypt/hash/sha/sha1.c ++ * ++ * SHA-1 in C ++ * By Steve Reid <steve@edmweb.com> ++ * 100% Public Domain ++ * ++ * Test Vectors (from FIPS PUB 180-1) ++ * "abc" ++ * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D ++ * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" ++ * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 ++ * A million repetitions of "a" ++ * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F ++ */ ++ ++/* #define SHA1HANDSOFF * Copies data before messing with it. */ ++ ++#if defined(__linux__) ++#include <asm/byteorder.h> ++#include <linux/string.h> ++#elif defined(__solaris__) ++#include <sys/isa_defs.h> ++#include <sys/ddi.h> ++#include <sys/sunddi.h> ++#define memcpy(d, s, c) bcopy(s, d, c) ++#define memset(d, b, c) bzero(d, c) ++#endif ++ ++#include "sha1.h" ++ ++static void SHA1_Transform(unsigned long[5], const unsigned char[64]); ++ ++#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) ++ ++/* blk0() and blk() perform the initial expand. */ ++/* I got the idea of expanding during the round function from SSLeay */ ++#if defined(__LITTLE_ENDIAN) || defined(_LITTLE_ENDIAN) ++#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ ++ |(rol(block->l[i],8)&0x00FF00FF)) ++#elif defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN) ++#define blk0(i) block->l[i] ++#else ++#error Endianness not defined ++#endif ++#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ ++ ^block->l[(i+2)&15]^block->l[i&15],1)) ++ ++/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ ++#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); ++#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); ++#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); ++#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); ++#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); ++ ++ ++/* Hash a single 512-bit block. This is the core of the algorithm. */ ++ ++static void ++SHA1_Transform(unsigned long state[5], const unsigned char buffer[64]) ++{ ++ unsigned long a, b, c, d, e; ++ typedef union { ++ unsigned char c[64]; ++ unsigned long l[16]; ++ } CHAR64LONG16; ++ CHAR64LONG16 *block; ++ ++#ifdef SHA1HANDSOFF ++ static unsigned char workspace[64]; ++ block = (CHAR64LONG16 *) workspace; ++ memcpy(block, buffer, 64); ++#else ++ block = (CHAR64LONG16 *) buffer; ++#endif ++ /* Copy context->state[] to working vars */ ++ a = state[0]; ++ b = state[1]; ++ c = state[2]; ++ d = state[3]; ++ e = state[4]; ++ /* 4 rounds of 20 operations each. Loop unrolled. */ ++ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); ++ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); ++ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); ++ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); ++ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); ++ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); ++ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); ++ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); ++ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); ++ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); ++ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); ++ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); ++ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); ++ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); ++ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); ++ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); ++ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); ++ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); ++ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); ++ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); ++ /* Add the working vars back into context.state[] */ ++ state[0] += a; ++ state[1] += b; ++ state[2] += c; ++ state[3] += d; ++ state[4] += e; ++ /* Wipe variables */ ++ a = b = c = d = e = 0; ++} ++ ++ ++/* SHA1Init - Initialize new context */ ++ ++void ++SHA1_Init(SHA1_CTX *context) ++{ ++ /* SHA1 initialization constants */ ++ context->state[0] = 0x67452301; ++ context->state[1] = 0xEFCDAB89; ++ context->state[2] = 0x98BADCFE; ++ context->state[3] = 0x10325476; ++ context->state[4] = 0xC3D2E1F0; ++ context->count[0] = context->count[1] = 0; ++} ++ ++ ++/* Run your data through this. */ ++ ++void ++SHA1_Update(SHA1_CTX *context, const unsigned char *data, unsigned int len) ++{ ++ unsigned int i, j; ++ ++ j = (context->count[0] >> 3) & 63; ++ if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; ++ context->count[1] += (len >> 29); ++ if ((j + len) > 63) { ++ memcpy(&context->buffer[j], data, (i = 64-j)); ++ SHA1_Transform(context->state, context->buffer); ++ for ( ; i + 63 < len; i += 64) { ++ SHA1_Transform(context->state, &data[i]); ++ } ++ j = 0; ++ } ++ else ++ i = 0; ++ ++ memcpy(&context->buffer[j], &data[i], len - i); ++} ++ ++ ++/* Add padding and return the message digest. */ ++ ++void ++SHA1_Final(unsigned char digest[20], SHA1_CTX *context) ++{ ++ unsigned long i, j; ++ unsigned char finalcount[8]; ++ ++ for (i = 0; i < 8; i++) { ++ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] ++ >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ ++ } ++ SHA1_Update(context, (unsigned char *) "\200", 1); ++ while ((context->count[0] & 504) != 448) { ++ SHA1_Update(context, (unsigned char *) "\0", 1); ++ } ++ SHA1_Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ ++ for (i = 0; i < 20; i++) { ++ digest[i] = (unsigned char) ++ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); ++ } ++ /* Wipe variables */ ++ i = j = 0; ++ memset(context->buffer, 0, 64); ++ memset(context->state, 0, 20); ++ memset(context->count, 0, 8); ++ memset(&finalcount, 0, 8); ++#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ ++ SHA1Transform(context->state, context->buffer); ++#endif ++} ++ +--- /dev/null ++++ linux-2.4.25/drivers/net/sha1.h +@@ -0,0 +1,18 @@ ++/* sha1.h */ ++ ++#ifndef _SHA1_H ++#define _SHA1_H ++ ++typedef struct { ++ unsigned long state[5]; ++ unsigned long count[2]; ++ unsigned char buffer[64]; ++} SHA1_CTX; ++ ++#define SHA1_SIGNATURE_SIZE 20 ++ ++extern void SHA1_Init(SHA1_CTX *); ++extern void SHA1_Update(SHA1_CTX *, const unsigned char *, unsigned int); ++extern void SHA1_Final(unsigned char[SHA1_SIGNATURE_SIZE], SHA1_CTX *); ++ ++#endif /* _SHA1_H */ +--- linux-2.4.25/include/linux/ppp-comp.h~mppe-20040216 ++++ linux-2.4.25/include/linux/ppp-comp.h +@@ -187,6 +187,100 @@ + #define DEFLATE_CHK_SEQUENCE 0 + + /* ++ * Definitions for MPPE. ++ */ ++ ++#define CI_MPPE 18 /* config option for MPPE */ ++#define CILEN_MPPE 6 /* length of config option */ ++ ++#define MPPE_PAD 4 /* MPPE growth per frame */ ++#define MPPE_MAX_KEY_LEN 16 /* largest key length (128-bit) */ ++ ++/* option bits for ccp_options.mppe */ ++#define MPPE_OPT_40 0x01 /* 40 bit */ ++#define MPPE_OPT_128 0x02 /* 128 bit */ ++#define MPPE_OPT_STATEFUL 0x04 /* stateful mode */ ++/* unsupported opts */ ++#define MPPE_OPT_56 0x08 /* 56 bit */ ++#define MPPE_OPT_MPPC 0x10 /* MPPC compression */ ++#define MPPE_OPT_D 0x20 /* Unknown */ ++#define MPPE_OPT_UNSUPPORTED (MPPE_OPT_56|MPPE_OPT_MPPC|MPPE_OPT_D) ++#define MPPE_OPT_UNKNOWN 0x40 /* Bits !defined in RFC 3078 were set */ ++ ++/* ++ * This is not nice ... the alternative is a bitfield struct though. ++ * And unfortunately, we cannot share the same bits for the option ++ * names above since C and H are the same bit. We could do a u_int32 ++ * but then we have to do a htonl() all the time and/or we still need ++ * to know which octet is which. ++ */ ++#define MPPE_C_BIT 0x01 /* MPPC */ ++#define MPPE_D_BIT 0x10 /* Obsolete, usage unknown */ ++#define MPPE_L_BIT 0x20 /* 40-bit */ ++#define MPPE_S_BIT 0x40 /* 128-bit */ ++#define MPPE_M_BIT 0x80 /* 56-bit, not supported */ ++#define MPPE_H_BIT 0x01 /* Stateless (in a different byte) */ ++ ++/* Does not include H bit; used for least significant octet only. */ ++#define MPPE_ALL_BITS (MPPE_D_BIT|MPPE_L_BIT|MPPE_S_BIT|MPPE_M_BIT|MPPE_H_BIT) ++ ++/* Build a CI from mppe opts (see RFC 3078) */ ++#define MPPE_OPTS_TO_CI(opts, ci) \ ++ do { \ ++ u_char *ptr = ci; /* u_char[4] */ \ ++ \ ++ /* H bit */ \ ++ if (opts & MPPE_OPT_STATEFUL) \ ++ *ptr++ = 0x0; \ ++ else \ ++ *ptr++ = MPPE_H_BIT; \ ++ *ptr++ = 0; \ ++ *ptr++ = 0; \ ++ \ ++ /* S,L bits */ \ ++ *ptr = 0; \ ++ if (opts & MPPE_OPT_128) \ ++ *ptr |= MPPE_S_BIT; \ ++ if (opts & MPPE_OPT_40) \ ++ *ptr |= MPPE_L_BIT; \ ++ /* M,D,C bits not supported */ \ ++ } while (/* CONSTCOND */ 0) ++ ++/* The reverse of the above */ ++#define MPPE_CI_TO_OPTS(ci, opts) \ ++ do { \ ++ u_char *ptr = ci; /* u_char[4] */ \ ++ \ ++ opts = 0; \ ++ \ ++ /* H bit */ \ ++ if (!(ptr[0] & MPPE_H_BIT)) \ ++ opts |= MPPE_OPT_STATEFUL; \ ++ \ ++ /* S,L bits */ \ ++ if (ptr[3] & MPPE_S_BIT) \ ++ opts |= MPPE_OPT_128; \ ++ if (ptr[3] & MPPE_L_BIT) \ ++ opts |= MPPE_OPT_40; \ ++ \ ++ /* M,D,C bits */ \ ++ if (ptr[3] & MPPE_M_BIT) \ ++ opts |= MPPE_OPT_56; \ ++ if (ptr[3] & MPPE_D_BIT) \ ++ opts |= MPPE_OPT_D; \ ++ if (ptr[3] & MPPE_C_BIT) \ ++ opts |= MPPE_OPT_MPPC; \ ++ \ ++ /* Other bits */ \ ++ if (ptr[0] & ~MPPE_H_BIT) \ ++ opts |= MPPE_OPT_UNKNOWN; \ ++ if (ptr[1] || ptr[2]) \ ++ opts |= MPPE_OPT_UNKNOWN; \ ++ if (ptr[3] & ~MPPE_ALL_BITS) \ ++ opts |= MPPE_OPT_UNKNOWN; \ ++ } while (/* CONSTCOND */ 0) ++ ++/* + * Definitions for other, as yet unsupported, compression methods. + */ + +--- linux-2.4.25/drivers/net/Makefile~mppe-20040216 ++++ linux-2.4.25/drivers/net/Makefile +@@ -18,8 +18,9 @@ + export-objs := 8390.o arlan.o aironet4500_core.o aironet4500_card.o \ + ppp_async.o ppp_generic.o slhc.o pppox.o auto_irq.o \ + net_init.o mii.o +-list-multi := rcpci.o ++list-multi := rcpci.o ppp_mppe.o + rcpci-objs := rcpci45.o rclanmtl.o ++ppp_mppe-objs := ppp_mppe_compress.o sha1.o arcfour.o + + ifeq ($(CONFIG_TULIP),y) + obj-y += tulip/tulip.o +@@ -163,6 +164,14 @@ + obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o + obj-$(CONFIG_PPPOE) += pppox.o pppoe.o + ++ifeq ($(CONFIG_PPP_MPPE),y) ++ obj-y += $(ppp_mppe-objs) ++else ++ ifeq ($(CONFIG_PPP_MPPE),m) ++ obj-m += ppp_mppe.o ++ endif ++endif ++ + obj-$(CONFIG_SLIP) += slip.o + ifeq ($(CONFIG_SLIP_COMPRESSED),y) + obj-$(CONFIG_SLIP) += slhc.o +@@ -269,3 +278,7 @@ + + rcpci.o: $(rcpci-objs) + $(LD) -r -o $@ $(rcpci-objs) ++ ++ppp_mppe.o: $(ppp_mppe-objs) ++ $(LD) -r -o $@ $(ppp_mppe-objs) ++ diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/scrolling-area.patch b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/scrolling-area.patch index e69de29bb2..c4f7758b3c 100644 --- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/scrolling-area.patch +++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/scrolling-area.patch @@ -0,0 +1,18 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux-2.4.25/drivers/video/fbcon.c~scrolling-area.patch 2003-08-25 13:44:42.000000000 +0200 ++++ linux-2.4.25/drivers/video/fbcon.c 2004-03-31 17:15:13.000000000 +0200 +@@ -110,8 +110,8 @@ + # define DPRINTK(fmt, args...) + #endif + +-#define LOGO_H 80 +-#define LOGO_W 80 ++#define LOGO_H 400 ++#define LOGO_W 800 + #define LOGO_LINE (LOGO_W/8) + + struct display fb_display[MAX_NR_CONSOLES]; diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-apm.diff b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-apm.diff index e69de29bb2..dfdbd99237 100644 --- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-apm.diff +++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-apm.diff @@ -0,0 +1,799 @@ +--- /mnt/bdisk/openembedded/oetmp/base/opensimpad-2.4.25-vrs2-pxa1-jpm1-r5/linux-2.4.25/arch/arm/mach-sa1100/pm-common.c 1970-01-01 01:00:00.000000000 +0100 ++++ arch/arm/mach-sa1100/pm-common.c 2004-07-04 14:56:34.000000000 +0200 +@@ -0,0 +1,268 @@ ++/* ++ * SA1100 Power Management Routines ++ * ++ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License. ++ * ++ * History: ++ * ++ * 2001-02-06: Cliff Brake Initial code ++ * ++ * 2001-02-25: Sukjae Cho <sjcho@east.isi.edu> & ++ * Chester Kuo <chester@linux.org.tw> ++ * Save more value for the resume function! Support ++ * Bitsy/Assabet/Freebird board ++ * ++ * 2001-08-29: Nicolas Pitre <nico@cam.org> ++ * Cleaned up, pushed platform dependent stuff ++ * in the platform specific files. ++ * ++ * 2002-05-27: Nicolas Pitre Killed sleep.h and the kmalloced save array. ++ * Storage is local on the stack now. ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/pm.h> ++#include <linux/slab.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/sysctl.h> ++#include <linux/errno.h> ++#include <linux/cpufreq.h> ++ ++#include <asm/hardware.h> ++#include <asm/memory.h> ++#include <asm/system.h> ++#include <asm/leds.h> ++#include <asm/uaccess.h> ++ ++ ++#ifdef CONFIG_IPAQ_HANDHELD ++#include <asm/arch-sa1100/h3600_asic.h> ++#endif ++ ++#define __KERNEL_SYSCALLS__ ++#include <linux/unistd.h> ++ ++/* ++ * Debug macros ++ */ ++#undef DEBUG ++ ++ ++ ++static char pm_helper_path[128] = "/sbin/pm_helper"; ++extern int exec_usermodehelper(char *path, char **argv, char **envp); ++int debug_pm = 0; ++static int pm_helper_veto = 0; ++ ++static int ++run_sbin_pm_helper( pm_request_t action ) ++{ ++ int i; ++ char *argv[3], *envp[8]; ++ ++ if (!pm_helper_path[0]) ++ return 2; ++ ++ if ( action != PM_SUSPEND && action != PM_RESUME ) ++ return 1; ++ ++ /* Be root */ ++ current->uid = current->gid = 0; ++ ++ i = 0; ++ argv[i++] = pm_helper_path; ++ argv[i++] = (action == PM_RESUME ? "resume" : "suspend"); ++ argv[i] = 0; ++ ++ i = 0; ++ /* minimal command environment */ ++ envp[i++] = "HOME=/"; ++ envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; ++ envp[i] = 0; ++ ++ /* other stuff we want to pass to /sbin/pm_helper */ ++ return exec_usermodehelper (argv [0], argv, envp); ++} ++ ++/* ++ * If pm_suggest_suspend_hook is non-NULL, it is called by pm_suggest_suspend. ++ */ ++int (*pm_suggest_suspend_hook)(int state); ++EXPORT_SYMBOL(pm_suggest_suspend_hook); ++ ++/* ++ * If pm_use_sbin_pm_helper is nonzero, then run_sbin_pm_helper is called before suspend and after resume ++ */ ++int pm_use_sbin_pm_helper = 1; ++EXPORT_SYMBOL(pm_use_sbin_pm_helper); ++ ++/* ++ * If sysctl_pm_do_suspend_hook is non-NULL, it is called by sysctl_pm_do_suspend. ++ * If it returns a true value, then pm_suspend is not called. ++ * Use this to hook in apmd, for now. ++ */ ++int (*pm_sysctl_suspend_hook)(int state); ++EXPORT_SYMBOL(pm_sysctl_suspend_hook); ++ ++int pm_suspend(void); ++ ++int pm_suggest_suspend(void) ++{ ++ int retval; ++ ++ if (pm_suggest_suspend_hook) { ++ if (pm_suggest_suspend_hook(PM_SUSPEND)) ++ return 0; ++ } ++ ++ if (pm_use_sbin_pm_helper) { ++ pid_t pid; ++ int res; ++ int status = 0; ++ unsigned int old_fs; ++ ++ pid = kernel_thread ((int (*) (void *)) run_sbin_pm_helper, (void *) PM_SUSPEND, 0 ); ++ if ( pid < 0 ) ++ return pid; ++ ++ if (debug_pm) ++ printk(KERN_CRIT "%s:%d got pid=%d\n", __FUNCTION__, __LINE__, pid); ++ ++ old_fs = get_fs (); ++ set_fs (get_ds ()); ++ res = waitpid(pid, &status, __WCLONE); ++ set_fs (old_fs); ++ ++ if ( pid != res ) { ++ if (debug_pm) ++ printk(KERN_CRIT ": waitpid returned %d (exit_code=%d); not suspending\n", res, status ); ++ ++ return -1; ++ } ++ ++ /*if ( WIFEXITED(status) && ( WIFEXITSTATUS(status) != 0 )) {*/ ++ if (( status & 0xff7f ) != 0 ) { ++ if (pm_helper_veto) { ++ if (debug_pm) ++ printk(KERN_CRIT "%s: SUSPEND WAS CANCELLED BY pm_helper (exit status %d)\n", __FUNCTION__, status >> 8); ++ return -1; ++ } else { ++ if (debug_pm) ++ printk(KERN_CRIT "%s: pm_helper returned %d, but going ahead anyway\n", __FUNCTION__, status >> 8); ++ } ++ } ++ } ++ ++ if (debug_pm) ++ printk(KERN_CRIT "%s: REALLY SUSPENDING NOW\n", __FUNCTION__ ); ++ ++ if (pm_sysctl_suspend_hook) { ++ if (pm_sysctl_suspend_hook(PM_SUSPEND)) ++ return 0; ++ } ++ ++ retval = pm_suspend(); ++ if (retval) { ++ if (debug_pm) ++ printk(KERN_CRIT "pm_suspend returned %d\n", retval); ++ return retval; ++ } ++ ++ if (pm_use_sbin_pm_helper) { ++ pid_t pid; ++ ++ if (debug_pm) ++ printk(KERN_CRIT "%s: running pm_helper for wakeup\n", __FUNCTION__); ++ ++ pid = kernel_thread ((int (*) (void *)) run_sbin_pm_helper, (void *) PM_RESUME, 0 ); ++ if ( pid < 0 ) ++ return pid; ++ ++ if ( pid != waitpid ( pid, NULL, __WCLONE )) ++ return -1; ++ } ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL(pm_suggest_suspend); ++ ++ ++/* ++ * Send us to sleep. ++ */ ++int pm_suspend(void) ++{ ++ int retval; ++ ++ retval = pm_send_all(PM_SUSPEND, (void *)3); ++ if ( retval ) ++ return retval; ++ ++#ifdef CONFIG_IPAQ_HANDHELD ++ retval = h3600_power_management(PM_SUSPEND); ++ if (retval) { ++ pm_send_all(PM_RESUME, (void *)0); ++ return retval; ++ } ++#endif ++ ++ retval = pm_do_suspend(); ++ ++#ifdef CONFIG_IPAQ_HANDHELD ++ /* Allow the power management routines to override resuming */ ++ while ( h3600_power_management(PM_RESUME) ) ++ retval = pm_do_suspend(); ++#endif ++ ++ pm_send_all(PM_RESUME, (void *)0); ++ ++ return retval; ++} ++EXPORT_SYMBOL(pm_suspend); ++ ++#ifdef CONFIG_SYSCTL ++/* ++ * ARGH! ACPI people defined CTL_ACPI in linux/acpi.h rather than ++ * linux/sysctl.h. ++ * ++ * This means our interface here won't survive long - it needs a new ++ * interface. Quick hack to get this working - use sysctl id 9999. ++ */ ++#warning ACPI broke the kernel, this interface needs to be fixed up. ++#define CTL_ACPI 9999 ++#define ACPI_S1_SLP_TYP 19 ++ ++static struct ctl_table pm_table[] = ++{ ++/* {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&sysctl_pm_suspend},*/ ++ {2, "helper", pm_helper_path, sizeof(pm_helper_path), 0644, NULL, (proc_handler *)&proc_dostring}, ++ {3, "debug", &debug_pm, sizeof(debug_pm), 0644, NULL, (proc_handler *)&proc_dointvec}, ++ {4, "helper_veto", &pm_helper_veto, sizeof(pm_helper_veto), 0644, NULL, (proc_handler *)&proc_dointvec}, ++ {0} ++}; ++ ++static struct ctl_table pm_dir_table[] = ++{ ++ {CTL_ACPI, "pm", NULL, 0, 0555, pm_table}, ++ {0} ++}; ++ ++/* ++ * Initialize power interface ++ */ ++static int __init pm_init(void) ++{ ++ register_sysctl_table(pm_dir_table, 1); ++ return 0; ++} ++ ++__initcall(pm_init); ++ ++#endif ++ +--- /mnt/bdisk/openembedded/oetmp/base/opensimpad-2.4.25-vrs2-pxa1-jpm1-r5/linux-2.4.25/arch/arm/mach-sa1100/apm.c 2004-07-01 21:10:30.000000000 +0200 ++++ arch/arm/mach-sa1100/apm.c 2004-07-04 14:53:38.000000000 +0200 +@@ -32,9 +32,7 @@ + + #include <asm/system.h> + #include <asm/hardware.h> +-#if FIXME + #include <asm/arch-sa1100/pm.h> +-#endif + + #ifdef CONFIG_IPAQ_HANDHELD + #include <asm/arch-sa1100/h3600_hal.h> +@@ -92,6 +91,8 @@ + int magic; + struct apm_user * next; + int suser: 1; ++ int writer: 1; ++ int reader: 1; + int suspend_wait: 1; + int suspend_result; + int suspends_pending; +@@ -111,7 +112,7 @@ + /* + * Local variables + */ +-//static int suspends_pending; ++static int suspends_pending; + //static int standbys_pending; + //static int ignore_normal_resume; + +@@ -129,8 +130,6 @@ + #else + static int power_off = 1; + #endif +-static int exit_kapmd; +-static int kapmd_running; + + static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); + static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); +@@ -190,6 +189,42 @@ + return as->events[as->event_tail]; + } + ++static void queue_event(apm_event_t event, struct apm_user *sender) ++{ ++ struct apm_user * as; ++ ++ if (user_list == NULL) ++ return; ++ for (as = user_list; as != NULL; as = as->next) { ++ if ((as == sender) || (!as->reader)) ++ continue; ++ as->event_head = (as->event_head + 1) % APM_MAX_EVENTS; ++ if (as->event_head == as->event_tail) { ++ static int notified; ++ ++ if (notified++ == 0) ++ printk(KERN_ERR "apm: an event queue overflowed\n"); ++ as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; ++ } ++ as->events[as->event_head] = event; ++ if ((!as->suser) || (!as->writer)) ++ continue; ++ switch (event) { ++ case APM_SYS_SUSPEND: ++ case APM_USER_SUSPEND: ++ as->suspends_pending++; ++ suspends_pending++; ++ break; ++ ++ case APM_SYS_STANDBY: ++ case APM_USER_STANDBY: ++ as->standbys_pending++; ++ break; ++ } ++ } ++ wake_up_interruptible(&apm_waitqueue); ++} ++ + static int check_apm_user(struct apm_user *as, const char *func) + { + if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) { +@@ -228,7 +263,6 @@ + i = count; + while ((i >= sizeof(event)) && !queue_empty(as)) { + event = get_queued_event(as); +- printk(" do_read: event=%d\n", event); + if (copy_to_user(buf, &event, sizeof(event))) { + if (i < count) + break; +@@ -280,9 +314,17 @@ + return -EPERM; + switch (cmd) { + case APM_IOC_SUSPEND: +-#if FIXME +- pm_suggest_suspend(); +-#endif ++ if (as->suspends_read > 0) { ++ as->suspends_read--; ++ as->suspends_pending--; ++ suspends_pending--; ++ } else { ++ queue_event(APM_USER_SUSPEND, as); ++ } ++ ++ if (suspends_pending <= 0) ++ wake_up(&apm_suspend_waitqueue); ++ + break; + default: + return -EINVAL; +@@ -299,6 +341,20 @@ + return 0; + filp->private_data = NULL; + lock_kernel(); ++ if (user_list == as) ++ user_list = as->next; ++ else { ++ struct apm_user * as1; ++ ++ for (as1 = user_list; ++ (as1 != NULL) && (as1->next != as); ++ as1 = as1->next) ++ ; ++ if (as1 == NULL) ++ printk(KERN_ERR "apm: filp not in user list\n"); ++ else ++ as1->next = as->next; ++ } + unlock_kernel(); + kfree(as); + return 0; +@@ -326,6 +382,8 @@ + * privileged operation -- cevans + */ + as->suser = capable(CAP_SYS_ADMIN); ++ as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE; ++ as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ; + as->next = user_list; + user_list = as; + filp->private_data = as; +@@ -409,34 +467,6 @@ + return p - buf; + } + +-#ifndef MODULE +-static int __init apm_setup(char *str) +-{ +- int invert; +- +- while ((str != NULL) && (*str != '\0')) { +- if (strncmp(str, "off", 3) == 0) +- apm_disabled = 1; +- if (strncmp(str, "on", 2) == 0) +- apm_disabled = 0; +- invert = (strncmp(str, "no-", 3) == 0); +- if (invert) +- str += 3; +- if (strncmp(str, "debug", 5) == 0) +- debug = !invert; +- if ((strncmp(str, "power-off", 9) == 0) || +- (strncmp(str, "power_off", 9) == 0)) +- power_off = !invert; +- str = strchr(str, ','); +- if (str != NULL) +- str += strspn(str, ", \t"); +- } +- return 1; +-} +- +-__setup("apm=", apm_setup); +-#endif +- + static struct file_operations apm_bios_fops = { + owner: THIS_MODULE, + read: do_read, +@@ -454,6 +484,48 @@ + + #define APM_INIT_ERROR_RETURN return -1 + ++static pid_t apmd_pid; ++static DECLARE_COMPLETION(apmd_exited); ++ ++static int apm(void *unused) ++{ ++ unsigned short bx; ++ unsigned short cx; ++ unsigned short dx; ++ int error; ++ char * power_stat; ++ char * bat_stat; ++ DECLARE_WAITQUEUE(wait, current); ++ struct apm_user au, *as; ++ ++ lock_kernel(); ++ ++ daemonize(); ++ ++ strcpy(current->comm, "kapmd"); ++ ++ as = &au; ++ as->magic = APM_BIOS_MAGIC; ++ as->event_tail = as->event_head = 0; ++ as->suspends_pending = as->standbys_pending = 0; ++ as->suspends_read = as->standbys_read = 0; ++ as->suser = 1; ++ as->writer = 1; ++ as->reader = 0; ++ ++ while (!signal_pending (current)) { ++ interruptible_sleep_on(&apm_suspend_waitqueue); ++ ++ pm_suggest_suspend(); ++ ++ queue_event(APM_NORMAL_RESUME, as); ++ } ++ ++ unlock_kernel(); ++ ++ complete_and_exit(&apmd_exited, 0); ++} ++ + /* + * Just start the APM thread. We do NOT want to do APM BIOS + * calls from anything but the APM thread, if for no other reason +@@ -492,6 +564,8 @@ + + misc_register(&apm_device); + ++ apmd_pid = kernel_thread(apm, NULL, 0); ++ + return 0; + } + +@@ -499,11 +573,10 @@ + { + misc_deregister(&apm_device); + remove_proc_entry("apm", NULL); ++ kill_proc (apmd_pid, SIGTERM, 1); ++ wait_for_completion(&apmd_exited); + if (power_off) + pm_power_off = NULL; +- exit_kapmd = 1; +- while (kapmd_running) +- schedule(); + pm_active = 0; + } + +@@ -512,6 +585,7 @@ + + MODULE_AUTHOR("Jamey Hicks, pulling bits from original by Stephen Rothwell"); + MODULE_DESCRIPTION("A minimal emulation of APM"); ++MODULE_LICENSE("GPL"); + MODULE_PARM(debug, "i"); + MODULE_PARM_DESC(debug, "Enable debug mode"); + MODULE_PARM(power_off, "i"); +diff -bBaruN /mnt/bdisk/openembedded/oetmp/base/opensimpad-2.4.25-vrs2-pxa1-jpm1-r5/linux-2.4.25/include/asm-arm/arch-sa1100/pm.h include/asm-arm/arch/pm.h +--- /mnt/bdisk/openembedded/oetmp/base/opensimpad-2.4.25-vrs2-pxa1-jpm1-r5/linux-2.4.25/include/asm-arm/arch-sa1100/pm.h 1970-01-01 01:00:00.000000000 +0100 ++++ include/asm-arm/arch-sa1100/pm.h 2004-07-04 16:47:18.000000000 +0200 +@@ -0,0 +1,20 @@ ++/* ++ * ++ * Declarations for ARM Linux Power Management ++ * ++ * Copyright 2002 Compaq Computer Corporation. ++ * ++ * 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. ++ * ++ * Author: Jamey Hicks. ++ * ++ */ ++ ++ ++extern int (*pm_suggest_suspend_hook)(int state); ++extern int (*pm_sysctl_suspend_hook)(int state); ++extern int pm_use_sbin_pm_helper; ++extern int pm_suspend(void); ++extern int pm_suggest_suspend(void); /* triggers /sbin/pm_helper or queueing event to apmd */ +--- /mnt/bdisk/openembedded/oetmp/work/opensimpad-64+0-2.4.25-vrs2-pxa1-jpm1-r6/linux-2.4.25/arch/arm/mach-sa1100/Makefile 2004-07-04 19:39:48.000000000 +0200 ++++ arch/arm/mach-sa1100/Makefile 2004-07-04 17:11:35.000000000 +0200 +@@ -19,7 +19,7 @@ + flexanet.o freebird.o frodo.o generic.o h3600.o \ + huw_webpanel.o irq.o sa1111.o sa1111-pcibuf.o \ + system3.o yopy.o usb_ctl.o usb_recv.o usb_send.o simputer.o ssp.o \ +- simpad.o ++ simpad.o pm-sa1100.o + + # These aren't present yet, and prevents a plain -ac kernel building. + # hwtimer.o +@@ -105,7 +105,7 @@ + obj-$(CONFIG_SA1100_USB_CHAR) += usb-char.o + + # Miscelaneous functions +-obj-$(CONFIG_PM) += pm.o sleep.o ++obj-$(CONFIG_PM) += pm-sa1100.o sleep.o + obj-$(CONFIG_APM) += apm.o + + # SIMpad specific +--- /mnt/bdisk/openembedded/oetmp/work/opensimpad-64+0-2.4.25-vrs2-pxa1-jpm1-r6/linux-2.4.25/arch/arm/mach-sa1100/pm-sa1100.c 1970-01-01 01:00:00.000000000 +0100 ++++ arch/arm/mach-sa1100/pm-sa1100.c 2004-07-04 17:11:11.000000000 +0200 +@@ -0,0 +1,225 @@ ++/* ++ * SA1100 Power Management Routines ++ * ++ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License. ++ * ++ * History: ++ * ++ * 2001-02-06: Cliff Brake Initial code ++ * ++ * 2001-02-25: Sukjae Cho <sjcho@east.isi.edu> & ++ * Chester Kuo <chester@linux.org.tw> ++ * Save more value for the resume function! Support ++ * Bitsy/Assabet/Freebird board ++ * ++ * 2001-08-29: Nicolas Pitre <nico@cam.org> ++ * Cleaned up, pushed platform dependent stuff ++ * in the platform specific files. ++ * ++ * 2002-05-27: Nicolas Pitre Killed sleep.h and the kmalloced save array. ++ * Storage is local on the stack now. ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/pm.h> ++#include <linux/slab.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/sysctl.h> ++#include <linux/errno.h> ++#include <linux/cpufreq.h> ++ ++#include <asm/hardware.h> ++#include <asm/memory.h> ++#include <asm/system.h> ++#include <asm/leds.h> ++ ++ ++#ifdef CONFIG_IPAQ_HANDHELD ++#include <asm/arch/h3600_asic.h> ++#endif ++ ++#define __KERNEL_SYSCALLS__ ++#include <linux/unistd.h> ++ ++extern void sa1100_cpu_suspend(void); ++extern void sa1100_cpu_resume(void); ++extern int debug_pm; ++ ++#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x ++#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] ++ ++/* ++ * List of global SA11x0 peripheral registers to preserve. ++ * More ones like CP and general purpose register values are preserved ++ * with the stack location in sleep.S. ++ */ ++enum { SLEEP_SAVE_START = 0, ++ ++ SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER, ++ SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3, ++ ++ SLEEP_SAVE_GPDR, SLEEP_SAVE_GRER, SLEEP_SAVE_GFER, SLEEP_SAVE_GAFR, ++ SLEEP_SAVE_PPDR, SLEEP_SAVE_PPSR, SLEEP_SAVE_PPAR, SLEEP_SAVE_PSDR, ++ ++ SLEEP_SAVE_ICMR, ++#ifdef CONFIG_SA1100_SIMPAD ++ SLEEP_SAVE_MECR, /* needed by SIMpad to get PCMCIA working after resume */ ++#endif ++ SLEEP_SAVE_Ser1SDCR0, ++ ++ SLEEP_SAVE_PWER, ++ SLEEP_SAVE_MSC1, SLEEP_SAVE_MSC2, ++ ++ SLEEP_SAVE_SIZE ++}; ++ ++ ++int pm_do_suspend(void) ++{ ++ unsigned long sleep_save[SLEEP_SAVE_SIZE]; ++ ++ cli(); ++ ++ leds_event(led_stop); ++ ++ /* preserve current time */ ++ RCNR = xtime.tv_sec; ++ ++ /* save vital registers */ ++ SAVE(OSCR); ++ SAVE(OSMR0); ++ SAVE(OSMR1); ++ SAVE(OSMR2); ++ SAVE(OSMR3); ++ SAVE(OIER); ++ ++ SAVE(GPDR); ++ SAVE(GRER); ++ SAVE(GFER); ++ SAVE(GAFR); ++ ++ SAVE(PPDR); ++ SAVE(PPSR); ++ SAVE(PPAR); ++ SAVE(PSDR); ++ ++ SAVE(Ser1SDCR0); ++ ++ SAVE(ICMR); ++#ifdef CONFIG_SA1100_SIMPAD ++ SAVE(MECR); ++#endif ++ SAVE(PWER); ++ SAVE(MSC1); ++ SAVE(MSC2); ++ ++ /* ... maybe a global variable initialized by arch code to set this? */ ++ GRER &= PWER; ++ GFER &= PWER; ++ // Ugly, but I need the AC inserted event ++ // In the future, we're going to care about DCD and USB interrupts as well ++ if ( machine_is_h3800()) { ++#ifdef CONFIG_IPAQ_HANDHELD ++ GFER = GPIO_H3800_AC_IN; ++#endif ++ } else { ++ GFER = 0; ++ if (machine_is_jornada56x()) { ++ /* jca */ ++ GFER = PWER; ++ ICMR |= PWER; ++ } ++ } ++ GEDR = GEDR; ++ ++ /* Clear previous reset status */ ++ RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR; ++ ++ /* set resume return address */ ++ PSPR = virt_to_phys(sa1100_cpu_resume); ++ ++ /* go zzz */ ++ sa1100_cpu_suspend(); ++ ++ /* ensure not to come back here if it wasn't intended */ ++ PSPR = 0; ++ ++ if (debug_pm) ++ printk(KERN_CRIT "*** made it back from resume\n"); ++ ++#ifdef CONFIG_IPAQ_HANDHELD ++ if ( machine_is_ipaq()) { ++ ipaq_model_ops.gedr = GEDR; ++ ipaq_model_ops.icpr = ICPR; ++ } ++#endif ++ ++ /* restore registers */ ++ RESTORE(GPDR); ++ RESTORE(GRER); ++ RESTORE(GFER); ++ RESTORE(GAFR); ++ ++ /* clear any edge detect bit */ ++ GEDR = GEDR; ++ ++ RESTORE(PPDR); ++ RESTORE(PPSR); ++ RESTORE(PPAR); ++ RESTORE(PSDR); ++ ++ RESTORE(Ser1SDCR0); ++ ++ PSSR = PSSR_PH; ++ ++ RESTORE(OSMR0); ++ RESTORE(OSMR1); ++ RESTORE(OSMR2); ++ RESTORE(OSMR3); ++ RESTORE(OSCR); ++ RESTORE(OIER); ++ ++#ifdef CONFIG_IPAQ_HANDHELD ++/* OSMR0 may have fired before we went to sleep, but after interrupts ++ were shut off. Set OSMR0 to something plausible */ ++ OSMR0 = OSCR + LATCH; ++#endif ++ ICLR = 0; ++ ICCR = 1; ++ RESTORE(ICMR); ++#ifdef CONFIG_SA1100_SIMPAD ++ RESTORE(MECR); ++#endif ++ RESTORE(PWER); ++ RESTORE(MSC1); ++ RESTORE(MSC2); ++ /* restore current time */ ++ xtime.tv_sec = RCNR; ++ ++ leds_event(led_start); ++ ++ sti(); ++ ++ if (debug_pm) ++ printk("interrupts are enabled\n"); ++ ++ /* ++ * Restore the CPU frequency settings. ++ */ ++#ifdef CONFIG_CPU_FREQ ++ cpufreq_restore(); ++#endif ++ return 0; ++} ++ ++unsigned long sleep_phys_sp(void *sp) ++{ ++ return virt_to_phys(sp); ++} ++ ++#include "pm-common.c" diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-backlight-if.diff b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-backlight-if.diff index e69de29bb2..50a4ff7628 100644 --- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-backlight-if.diff +++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-backlight-if.diff @@ -0,0 +1,97 @@ +--- /mnt/bdisk/openembedded/oetmp/base/opensimpad-2.4.25-vrs2-pxa1-jpm1-r5/linux-2.4.25/drivers/video/mq200fb.c 2004-07-01 21:10:30.000000000 +0200 ++++ drivers/video/mq200fb.c 2004-07-03 20:58:59.000000000 +0200 +@@ -82,6 +82,20 @@ + write: proc_write_reg + }; + ++#ifdef CONFIG_SA1100_SIMPAD ++ ++static ssize_t proc_read_light(struct file * file, char * buf, ++ size_t nbytes, loff_t *ppos); ++static ssize_t proc_write_light(struct file * file, const char * buffer, ++ size_t count, loff_t *ppos); ++ ++static struct file_operations proc_light_operations = { ++ read: proc_read_light, ++ write: proc_write_light ++}; ++#endif ++ ++ + typedef struct sa1110_reg_entry { + u32 phyaddr; + char* name; +@@ -622,6 +636,20 @@ + } + } + ++#ifdef CONFIG_SA1100_SIMPAD ++ entry = create_proc_entry("backlight", ++ S_IRWXU | S_IRWXG | S_IRWXO, ++ mq200dir); ++ if(entry) { ++ entry->proc_fops = &proc_light_operations; ++ } ++ else { ++ printk( KERN_ERR ++ "mq200fb: can't create /proc/" MQ200_DIRNAME ++ "/backlight\n"); ++ return(-ENOMEM); ++ } ++ #endif + + #ifdef MQ_SA1110 + +@@ -1879,7 +1907,7 @@ + static void writeBrightness(void *pMQMMIO, int brightness) + { + unsigned long dutyCycle, pwmcontrol; +- int MAX_BRIGHT_REG = 0x000000fc; /* int 254 */ ++ int MAX_BRIGHT_REG = 0x000000fe; /* int 254 */ + + if(brightness > MAX_BRIGHT_REG) + return; +@@ -1961,3 +1989,43 @@ + return (count+endp-buffer); + } + ++#ifdef CONFIG_SA1100_SIMPAD ++ ++#define SIMPAD_BACKLIGHT_MASK 0x00a10044 ++ ++static int proc_read_light(struct file * file, char * buf, ++ size_t nbytes, loff_t *ppos) ++{ ++ char outputbuf[15]; ++ int count; ++ u32 pwmctl; ++ if (*ppos>0) /* Assume reading completed in previous read*/ ++ return 0; ++ ++ pwmctl = *((volatile *) mq200_p2v(0x4be0e03c)); ++ pwmctl &= ~SIMPAD_BACKLIGHT_MASK; ++ pwmctl = pwmctl >> 8; ++ pwmctl = 254 - pwmctl; ++ ++ count = sprintf(outputbuf, "%d\n",pwmctl); ++ *ppos+=count; ++ if (count>nbytes) /* Assume output can be read at one time */ ++ return -EINVAL; ++ if (copy_to_user(buf, outputbuf, count)) ++ return -EFAULT; ++ return count; ++} ++ ++static ssize_t proc_write_light(struct file * file, const char * buffer, ++ size_t count, loff_t *ppos) ++{ ++ void * pMQMMIO = (void *) mqMmioAddr; ++ char *endp; ++ unsigned long newvalue = simple_strtoul(buffer,&endp,0); ++ if (newvalue > 254) ++ newvalue = 254; ++ writeBrightness(pMQMMIO,newvalue); ++ mq200_backlight(pMQMMIO,(int)newvalue); ++ return (count+endp-buffer); ++} ++#endif diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-pm-updates.patch b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-pm-updates.patch index e69de29bb2..938c34c67a 100644 --- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-pm-updates.patch +++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-pm-updates.patch @@ -0,0 +1,47 @@ +--- arch/arm/mach-sa1100/pm-sa1100.c 2004-07-14 01:21:38.000000000 +0200 ++++ /home/fuchs/Projekte/simpad/kernel/linux-2.4.25/arch/arm/mach-sa1100/pm-sa1100.c 2004-07-22 00:41:57.000000000 +0200 +@@ -69,6 +69,7 @@ + SLEEP_SAVE_ICMR, + #ifdef CONFIG_SA1100_SIMPAD + SLEEP_SAVE_MECR, /* needed by SIMpad to get PCMCIA working after resume */ ++ SLEEP_SAVE_Ser4MCCR0, SLEEP_SAVE_Ser4MCSR, SLEEP_SAVE_Ser4MCCR1, /* touchscreen */ + #endif + SLEEP_SAVE_Ser1SDCR0, + +@@ -82,7 +83,7 @@ + int pm_do_suspend(void) + { + unsigned long sleep_save[SLEEP_SAVE_SIZE]; +- ++ + cli(); + + leds_event(led_stop); +@@ -113,10 +114,13 @@ + SAVE(ICMR); + #ifdef CONFIG_SA1100_SIMPAD + SAVE(MECR); +-#endif +- SAVE(PWER); +- SAVE(MSC1); +- SAVE(MSC2); ++ SAVE(Ser4MCCR0); ++ SAVE(Ser4MCSR); ++ SAVE(Ser4MCCR1); ++#endif ++ SAVE(PWER); ++ SAVE(MSC1); ++ SAVE(MSC2); + + /* ... maybe a global variable initialized by arch code to set this? */ + GRER &= PWER; +@@ -194,6 +198,9 @@ + RESTORE(ICMR); + #ifdef CONFIG_SA1100_SIMPAD + RESTORE(MECR); ++ RESTORE(Ser4MCCR0); ++ RESTORE(Ser4MCSR); ++ RESTORE(Ser4MCCR1); + #endif + RESTORE(PWER); + RESTORE(MSC1); diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-switches-input.diff b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-switches-input.diff index e69de29bb2..c07dafd17a 100644 --- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-switches-input.diff +++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-switches-input.diff @@ -0,0 +1,126 @@ +--- /mnt/bdisk/openembedded/oetmp/base/opensimpad-2.4.25-vrs2-pxa1-jpm1-r5/linux-2.4.25/drivers/misc/switches.h 2004-07-01 21:10:30.000000000 +0200 ++++ drivers/misc/switches.h 2004-07-03 23:45:46.000000000 +0200 +@@ -25,4 +25,14 @@ + extern int switches_ucb1x00_init(void); + extern void switches_ucb1x00_exit(void); + ++#ifdef CONFIG_SA1100_SIMPAD ++#define SIMPAD_KEY_SUSPEND 0x0002 ++#define SIMPAD_KEY_WWW 0x0008 ++#define SIMPAD_KEY_ENTER 0x0010 ++#define SIMPAD_KEY_UP 0x0020 ++#define SIMPAD_KEY_DOWN 0x0040 ++#define SIMPAD_KEY_LEFT 0x0080 ++#define SIMPAD_KEY_RIGHT 0x0100 ++#endif ++ + #endif /* !defined(_SWITCHES_H) */ +--- /mnt/bdisk/openembedded/oetmp/base/opensimpad-2.4.25-vrs2-pxa1-jpm1-r5/linux-2.4.25/drivers/misc/switches-core.c 2004-07-01 21:10:30.000000000 +0200 ++++ drivers/misc/switches-core.c 2004-07-04 17:57:37.000000000 +0200 +@@ -16,6 +16,9 @@ + * 11 September 2001 - UCB1200 driver framework support added. + * + * 19 December 2001 - separated out SA-1100 and UCB1x00 code. ++ * ++ * 3 July 2004 - Added generating of keyboard events. ++ * Florian Boor <florian@handhelds.org> + */ + + #include <linux/config.h> +@@ -30,7 +33,11 @@ + #include <linux/slab.h> + #include <linux/wait.h> + ++#include <linux/input.h> ++ + #include <asm/uaccess.h> ++#include <asm/hardware.h> ++#include <asm/keyboard.h> + + #include "switches.h" + +@@ -53,6 +60,19 @@ + DECLARE_WAIT_QUEUE_HEAD(switches_wait); + LIST_HEAD(switches_event_queue); + ++#ifdef CONFIG_INPUT ++static struct input_dev idev; ++ ++int ++dummy_k_translate(unsigned char scancode, unsigned char *keycode, char raw_mode) ++{ ++ *keycode = scancode; ++ return 1; ++} ++ ++extern int (*k_translate)(unsigned char, unsigned char *, char); ++ ++#endif + + static ssize_t switches_read(struct file *file, char *buffer, + size_t count, loff_t *pos) +@@ -148,6 +168,31 @@ + { + struct switches_action *action; + ++#ifdef CONFIG_INPUT ++ /* create input events, the events to send depends on the platform */ ++#ifdef CONFIG_SA1100_SIMPAD ++ if (machine_is_simpad()) { ++ if (SWITCHES_COUNT(mask) > 0) ++ { ++ if (mask->events[0] & SIMPAD_KEY_SUSPEND) ++ input_report_key(&idev, KEY_POWER, (mask->states[0] & SIMPAD_KEY_SUSPEND) ? 1 : 0); ++ if (mask->events[0] & SIMPAD_KEY_ENTER) ++ input_report_key(&idev, KEY_ENTER, (mask->states[0] & SIMPAD_KEY_ENTER) ? 1 : 0); ++ if (mask->events[0] & SIMPAD_KEY_UP) ++ input_report_key(&idev, KEY_UP, (mask->states[0] & SIMPAD_KEY_UP) ? 1 : 0); ++ if (mask->events[0] & SIMPAD_KEY_DOWN) ++ input_report_key(&idev, KEY_DOWN, (mask->states[0] & SIMPAD_KEY_DOWN) ? 1 : 0); ++ if (mask->events[0] & SIMPAD_KEY_LEFT) ++ input_report_key(&idev, KEY_LEFT, (mask->states[0] & SIMPAD_KEY_LEFT) ? 1 : 0); ++ if (mask->events[0] & SIMPAD_KEY_RIGHT) ++ input_report_key(&idev, KEY_RIGHT, (mask->states[0] & SIMPAD_KEY_RIGHT) ? 1 : 0); ++ if (mask->events[0] & SIMPAD_KEY_WWW) ++ input_report_key(&idev, KEY_WWW, (mask->states[0] & SIMPAD_KEY_WWW) ? 1 : 0); ++ } ++ } ++#endif ++#endif ++ /* take care of switches device */ + if ((switches_users > 0) && (SWITCHES_COUNT(mask) > 0)) { + + if ((action = (struct switches_action *) +@@ -197,6 +242,21 @@ + return -EIO; + } + ++#ifdef CONFIG_INPUT ++ /* init input driver stuff */ ++ k_translate = dummy_k_translate; ++ idev.evbit[0] = BIT(EV_KEY); /* handle key events */ ++ ++ idev.keybit[LONG(KEY_SUSPEND)] |= BIT(KEY_SUSPEND); ++ idev.keybit[LONG(KEY_UP)] |= BIT(KEY_UP); ++ idev.keybit[LONG(KEY_DOWN)] |= BIT(KEY_DOWN); ++ idev.keybit[LONG(KEY_LEFT)] |= BIT(KEY_LEFT); ++ idev.keybit[LONG(KEY_RIGHT)] |= BIT(KEY_RIGHT); ++ idev.keybit[LONG(KEY_ENTER)] |= BIT(KEY_ENTER); ++ idev.keybit[LONG(KEY_WWW)] |= BIT(KEY_WWW); ++ ++ input_register_device(&idev); ++#endif + printk("Console switches initialized\n"); + + return 0; +@@ -214,6 +274,10 @@ + switches_ucb1x00_exit(); + #endif + ++#ifdef CONFIG_INPUT ++ input_unregister_device(&idev); ++#endif ++ + if (misc_deregister(&switches_misc) < 0) + printk(KERN_ERR "%s: unable to deregister misc device\n", + SWITCHES_NAME); diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-ts-noninput.diff b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-ts-noninput.diff index e69de29bb2..08fffe5882 100644 --- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-ts-noninput.diff +++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-ts-noninput.diff @@ -0,0 +1,11 @@ +--- /mnt/bdisk/openembedded/oetmp/base/opensimpad-2.4.25-vrs2-pxa1-jpm1-r5/linux-2.4.25/drivers/misc/ucb1x00-ts.c 2004-07-01 21:10:30.000000000 +0200 ++++ drivers/misc/ucb1x00-ts.c 2004-07-04 02:00:56.000000000 +0200 +@@ -35,7 +35,7 @@ + /* + * Define this if you want the UCB1x00 stuff to talk to the input layer + */ +-#ifdef CONFIG_INPUT ++#if defined(CONFIG_INPUT) && !defined(CONFIG_SA1100_SIMPAD) + #define USE_INPUT + #else + #undef USE_INPUT diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/sound-volume-reversed.patch b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/sound-volume-reversed.patch index e69de29bb2..11fa5c7ad5 100644 --- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/sound-volume-reversed.patch +++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/sound-volume-reversed.patch @@ -0,0 +1,16 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux-2.4.25/drivers/misc/ucb1x00-audio.c~sound-volume-reversed.patch 2004-03-31 17:15:12.000000000 +0200 ++++ linux-2.4.25/drivers/misc/ucb1x00-audio.c 2004-03-31 17:15:13.000000000 +0200 +@@ -97,7 +97,7 @@ + ucba->output_level = gain | gain << 8; + ucba->mod_cnt++; + ucba->ctrl_b = (ucba->ctrl_b & 0xff00) | +- ((gain * 31) / 100); ++ (((100-gain) * 31) / 100); + ucb1x00_reg_write(ucba->ucb, UCB_AC_B, + ucba->ctrl_b); + ret = 0; diff --git a/linux/openzaurus-2.6.10-rc1-jl1/collie-config-2.6.7-jl2 b/linux/openzaurus-2.6.10-rc1-jl1/collie-config-2.6.7-jl2 index e69de29bb2..ae8799e7a3 100644 --- a/linux/openzaurus-2.6.10-rc1-jl1/collie-config-2.6.7-jl2 +++ b/linux/openzaurus-2.6.10-rc1-jl1/collie-config-2.6.7-jl2 @@ -0,0 +1,769 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_HOTPLUG=y +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_OBSOLETE_MODPARM=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ADIFCC 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_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +CONFIG_ARCH_SA1100=y +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE_PB is not set +CONFIG_SHARP_LOCOMO=y + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +CONFIG_SA1100_COLLIE=y +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HACKKIT 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_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_STORK is not set +# CONFIG_SA1100_SSP is not set +# CONFIG_SA1100_USB is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_SA1100=y +CONFIG_CPU_32v4=y +CONFIG_CPU_ABRT_EV4=y +CONFIG_CPU_CACHE_V4WB=y +CONFIG_CPU_TLB_V4WB=y +CONFIG_CPU_MINICACHE=y + +# +# Processor Features +# + +# +# General setup +# +CONFIG_DISCONTIGMEM=y +CONFIG_ISA=y +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +# CONFIG_CPU_FREQ is not set + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +CONFIG_PCMCIA_SA1100=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_AOUT=m +CONFIG_BINFMT_MISC=m + +# +# Generic Driver Options +# +CONFIG_FW_LOADER=m +# CONFIG_DEBUG_DRIVER is not set +CONFIG_PM=y +CONFIG_PREEMPT=y +CONFIG_APM=y +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="noinitrd root=/dev/mtdblock2 rootfstype=jffs2" +CONFIG_LEDS=y +CONFIG_LEDS_TIMER=y +CONFIG_LEDS_CPU=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +CONFIG_MTD_DEBUG=y +CONFIG_MTD_DEBUG_VERBOSE=1 +CONFIG_MTD_PARTITIONS=y +# 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 + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +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 is not set +# CONFIG_MTD_ABSENT is not set +CONFIG_MTD_OBSOLETE_CHIPS=y +# CONFIG_MTD_AMDSTD is not set +CONFIG_MTD_SHARP=y +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +CONFIG_MTD_SA1100=y +# CONFIG_MTD_EDB7312 is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play support +# +# CONFIG_PNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=1024 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB 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 +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_NETDEVICES is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_TSDEV=y +CONFIG_INPUT_TSDEV_SCREEN_X=240 +CONFIG_INPUT_TSDEV_SCREEN_Y=320 +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=y + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_KEYBOARD_LOCOMO=y +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# 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 +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +CONFIG_I2C=m +# CONFIG_I2C_CHARDEV is not set + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +# CONFIG_I2C_ALGOPCF is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ELEKTOR is not set +CONFIG_I2C_ISA=m +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_SCx200_ACB is not set + +# +# Hardware Sensors Chip support +# +# CONFIG_I2C_SENSOR is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# + +# +# Video Adapters +# +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_SAA5246A is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set + +# +# Radio Adapters +# +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_MAESTRO is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_SF16FMR2 is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS 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_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=1 +# CONFIG_JFFS2_FS_NAND is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_EXPORTFS is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=m +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ISO8859_1=m +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=m + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +CONFIG_FB=y +CONFIG_FB_SA1100=y +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_PCI_CONSOLE=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set + +# +# Logo configuration +# +# CONFIG_LOGO is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Misc devices +# + +# +# USB support +# + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_PXA2XX is not set +# CONFIG_USB_GADGET_GOKU is not set +CONFIG_USB_GADGET_SA1100=y +CONFIG_USB_SA1100=y +# CONFIG_USB_GADGET_DUMMY_HCD is not set +# CONFIG_USB_GADGET_DUALSPEED is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/linux/openzaurus-2.6.10-rc1-jl1/husky-config-2.6.7-jl2 b/linux/openzaurus-2.6.10-rc1-jl1/husky-config-2.6.7-jl2 index e69de29bb2..347657f8ec 100644 --- a/linux/openzaurus-2.6.10-rc1-jl1/husky-config-2.6.7-jl2 +++ b/linux/openzaurus-2.6.10-rc1-jl1/husky-config-2.6.7-jl2 @@ -0,0 +1,855 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_HOTPLUG=y +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_OBSOLETE_MODPARM=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +CONFIG_ARCH_PXA=y +CONFIG_PXA25x=y +# CONFIG_PXA27x 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_IOP3XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set + +# +# CLPS711X/EP721X Implementations +# + +# +# Epxa10db +# + +# +# Footbridge Implementations +# + +# +# IOP3xx Implementation Options +# +# CONFIG_ARCH_IOP310 is not set +# CONFIG_ARCH_IOP321 is not set + +# +# IOP3xx Chipset Features +# + +# +# Intel PXA250/210 Implementations +# +# +# Intel PXA250/210 Implementations +# +# CONFIG_ARCH_LUBBOCK is not set +# CONFIG_ARCH_PXA_IDP is not set +# CONFIG_ARCH_PXA_CERF is not set +# CONFIG_COTULLA_DMA is not set +# CONFIG_SABINAL_DISCOVERY is not set +# CONFIG_ARCH_SABINAL is not set +# CONFIG_ARCH_PXA_POODLE is not set +# CONFIG_POODLE_TR0 is not set +CONFIG_ARCH_PXA_CORGI=y +# CONFIG_MACH_CORGI is not set +CONFIG_MACH_HUSKY=y +# CONFIG_CORGI_TR0 is not set +CONFIG_CORGI_LCD_BUFF=y +# CONFIG_ARCH_PXA_SHEPHERD is not set +CONFIG_ARCH_PXA_HUSKY=y +# CONFIG_ARCH_PXA_BOXER is not set +CONFIG_ARCH_SHARP_SL=y +CONFIG_SL_CCCR_CHANGE=y +CONFIG_SL_CCCR242=y + + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_COLLIE is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HACKKIT 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_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_STORK is not set +# CONFIG_SA1100_SSP is not set +# CONFIG_SA1100_USB is not set + +# +# Processor Type +# +# CONFIG_CPU_32v3 is not set +# CONFIG_CPU_32v4 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# 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_SA110 is not set +# CONFIG_CPU_SA1100 is not set +CONFIG_CPU_32=y +CONFIG_CPU_32v5=y +CONFIG_CPU_XSCALE=y + +CONFIG_SPU_ABRT_EV5T=y +CONFIG_CPU_TLB_v4WBI=y +CONFIG_CPU_MINICACHE=y + + +##### CONFIG_BATT=y +# CONFIG_XSCALE_CACHE_ERRATA is not set +##### CONFIG_ARM_THUMB=y +##### CONFIG_ARM_FCSE=y +# CONFIG_DISCONTIGMEM is not set +##### CONFIG_PREEMPT=y +##### CONFIG_LOCK_BREAK=y + +# +# Processor Features +# + +# +# General setup +# +CONFIG_DISCONTIGMEM=y +CONFIG_ISA=y +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +# CONFIG_CPU_FREQ is not set + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# above was not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_AOUT=m +CONFIG_BINFMT_MISC=m + +# +# Generic Driver Options +# +CONFIG_FW_LOADER=m +# CONFIG_DEBUG_DRIVER is not set +CONFIG_PM=y +CONFIG_PREEMPT=y +CONFIG_APM=y +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="console=ttyS0,9600n8 console=tty0 noinitrd root=/dev/mtdblock4 rootfstype=jffs2" + +# CONFIG_CMDLINE="console=null root=/dev/mtdblock2 mtdparts=sharpsl-nand:7168k@0k(smf),25600k@7168k(root),-(home) jffs2_orphaned_inodes=delete rootfstype=jffs2" +# CONFIG_CMDLINE="root=/dev/mtdblock4 rootfstype=jffs2 jffs2_orphaned_inodes=delete console=null mem=16M" + +CONFIG_LEDS=y +CONFIG_LEDS_TIMER=y +CONFIG_LEDS_CPU=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +CONFIG_MTD_DEBUG=y +#CONFIG_MTD_DEBUG_VERBOSE=1 +CONFIG_MTD_PARTITIONS=y +# 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 + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +# CONFIG_MTD_GEN_PROBE is not set +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +# CONFIG_MTD_CFI_INTELEXT is not set +# 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 + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_SA1100=y +# CONFIG_MTD_EDB7312 is not set +#### CONFIG_MTD_SHARP_SL=y + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +####CONFIG_MTD_NAND=y +####CONFIG_MTD_NAND_ECC=y +####CONFIG_MTD_NAND_VERIFY_WRITE=y +####CONFIG_MTD_NAND_POST_BADBLOCK=y +# CONFIG_MTD_NAND_ERASE_BY_FORCE is not set +####CONFIG_MTD_NAND_LOGICAL_ADDRESS_ACCESS=y +####CONFIG_MTD_NAND_PAGE_CACHE=y +####CONFIG_MTD_NAND_SHARP_SL_CORGI=y +####CONFIG_MTD_NAND_SHARP_SL=y + +# +# Plug and Play support +# +# CONFIG_PNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP 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=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_IPV6 is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB 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 +# CONFIG_NETDEVICES is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# Bluetooth support +# +# CONFIG_BT is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_TSDEV=y +CONFIG_INPUT_TSDEV_SCREEN_X=640 +CONFIG_INPUT_TSDEV_SCREEN_Y=480 +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=y + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_CT82C710 is not set +CONFIG_SHARP_LOCOMO=y + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set + +# CONFIG_KEYBOARD_COLLIE is not set + +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SL7X0_POWER_KEY_OFF=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_SERIAL_PXA=y +CONFIG_SERIAL_PXA_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# 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 +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +CONFIG_I2C=m +# CONFIG_I2C_CHARDEV is not set + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +# CONFIG_I2C_ALGOPCF is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ELEKTOR is not set +CONFIG_I2C_ISA=m +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_SCx200_ACB is not set + +# +# Hardware Sensors Chip support +# +# CONFIG_I2C_SENSOR is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# + +# +# Video Adapters +# +# CONFIG_VIDEO_PMS is not set +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_SAA5246A is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set + +# +# Radio Adapters +# +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_MAESTRO is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_SF16FMR2 is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS 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_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=1 +# CONFIG_JFFS2_FS_NAND is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_EXPORTFS is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=m +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ISO8859_1=m +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=m + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +####CONFIG_FB=y +####CONFIG_FB_CORGI=y +####CONFIG_SL_SYSCLK100=y +# CONFIG_FB_SA1100 is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_PCI_CONSOLE=y + +# BJL - Check these out later +#CONFIG_FBCON_CFB16=y +#CONFIG_FBCON_ADVANCED=y +#CONFIG_FBCON_ROTATE_R=y + +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set + +# +# Logo configuration +# +# CONFIG_LOGO is not set + +# +# Sound +# +# CONFIG_SOUND is not set +# CONFIG_SOUND=y +# CONFIG_SOUND_CORGI=y + +# +# Misc devices +# + +# +# USB support +# + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_NET2280 is not set +CONFIG_USB_GADGET_PXA2XX=y +CONFIG_USB_PXA2XX=y +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_SA1100 is not set +# CONFIG_USB_SA1100 is not set +# CONFIG_USB_GADGET_DUALSPEED is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC32=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/linux/openzaurus-2.6.10-rc1-jl1/patch-2.6.5-rp1.diff b/linux/openzaurus-2.6.10-rc1-jl1/patch-2.6.5-rp1.diff index e69de29bb2..5d69785a47 100644 --- a/linux/openzaurus-2.6.10-rc1-jl1/patch-2.6.5-rp1.diff +++ b/linux/openzaurus-2.6.10-rc1-jl1/patch-2.6.5-rp1.diff @@ -0,0 +1,881 @@ +diff -uNr linux-2.6.5-orig/arch/arm/Kconfig linux-2.6.5/arch/arm/Kconfig +--- linux-2.6.5-orig/arch/arm/Kconfig 2004-06-14 20:31:51.000000000 +0100 ++++ linux-2.6.5/arch/arm/Kconfig 2004-06-14 20:33:06.000000000 +0100 +@@ -500,7 +500,7 @@ + + config LEDS + bool "Timer and CPU usage LEDs" +- depends on ARCH_NETWINDER || ARCH_EBSA110 || ARCH_EBSA285 || ARCH_FTVPCI || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || MACH_POODLE || ARCH_INTEGRATOR || ARCH_CDB89712 || ARCH_P720T ++ depends on ARCH_NETWINDER || ARCH_EBSA110 || ARCH_EBSA285 || ARCH_FTVPCI || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || MACH_POODLE || MACH_HUSKY || ARCH_INTEGRATOR || ARCH_CDB89712 || ARCH_P720T + help + If you say Y here, the LEDs on your machine will be used + to provide useful information about your current system status. +@@ -513,8 +513,8 @@ + system, but the driver will do nothing. + + config LEDS_TIMER +- bool "Timer LED" if LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || MACH_POODLE || ARCH_INTEGRATOR || ARCH_P720T) +- depends on ARCH_NETWINDER || ARCH_EBSA110 || ARCH_EBSA285 || ARCH_FTVPCI || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || MACH_POODLE || ARCH_INTEGRATOR || ARCH_CDB89712 || ARCH_P720T ++ bool "Timer LED" if LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || MACH_POODLE || MACH_HUSKY || ARCH_INTEGRATOR || ARCH_P720T) ++ depends on ARCH_NETWINDER || ARCH_EBSA110 || ARCH_EBSA285 || ARCH_FTVPCI || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || MACH_POODLE || MACH_HUSKY || ARCH_INTEGRATOR || ARCH_CDB89712 || ARCH_P720T + default y if ARCH_EBSA110 + help + If you say Y here, one of the system LEDs (the green one on the +@@ -529,7 +529,7 @@ + + config LEDS_CPU + bool "CPU usage LED" +- depends on LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || MACH_POODLE || ARCH_INTEGRATOR || ARCH_P720T) ++ depends on LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || MACH_POODLE || MACH_HUSKY || ARCH_INTEGRATOR || ARCH_P720T) + help + If you say Y here, the red LED will be used to give a good real + time indication of CPU usage, by lighting whenever the idle task +diff -uNr linux-2.6.5-orig/arch/arm/Makefile linux-2.6.5/arch/arm/Makefile +--- linux-2.6.5-orig/arch/arm/Makefile 2004-06-14 20:31:51.000000000 +0100 ++++ linux-2.6.5/arch/arm/Makefile 2004-06-14 20:33:06.000000000 +0100 +@@ -54,8 +54,8 @@ + tune-$(CONFIG_CPU_V6) :=-mtune=strongarm + + # Need -Uarm for gcc < 3.x +-CFLAGS +=-mapcs-32 $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Wa,-mno-fpu -Uarm +-AFLAGS +=-mapcs-32 $(arch-y) $(tune-y) -msoft-float -Wa,-mno-fpu ++CFLAGS +=-mapcs-32 $(arch-y) $(tune-y) -malignment-traps -msoft-float ++AFLAGS +=-mapcs-32 $(arch-y) $(tune-y) -msoft-float + + #Default value + DATAADDR := . +diff -uNr linux-2.6.5-orig/arch/arm/boot/compressed/Makefile linux-2.6.5/arch/arm/boot/compressed/Makefile +--- linux-2.6.5-orig/arch/arm/boot/compressed/Makefile 2004-06-14 20:31:52.000000000 +0100 ++++ linux-2.6.5/arch/arm/boot/compressed/Makefile 2004-06-14 20:33:06.000000000 +0100 +@@ -55,14 +55,18 @@ + OBJS += head-xscale.o + endif + ++ifeq ($(CONFIG_DEBUG_ICEDCC),y) ++OBJS += ice-dcc.o ++endif ++ + SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/;s/BSS_START/$(ZBSSADDR)/ + + targets := vmlinux vmlinux.lds piggy piggy.gz piggy.o \ + font.o head.o $(OBJS) + EXTRA_CFLAGS := -fpic +-EXTRA_AFLAGS := -traditional ++EXTRA_AFLAGS := + +-LDFLAGS_vmlinux := -p -X \ ++LDFLAGS_vmlinux := -p --no-undefined -X \ + $(shell $(CC) $(CFLAGS) --print-libgcc-file-name) -T + + $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.o \ +diff -uNr linux-2.6.5-orig/arch/arm/boot/compressed/head-xscale.S linux-2.6.5/arch/arm/boot/compressed/head-xscale.S +--- linux-2.6.5-orig/arch/arm/boot/compressed/head-xscale.S 2004-06-14 20:31:52.000000000 +0100 ++++ linux-2.6.5/arch/arm/boot/compressed/head-xscale.S 2004-06-14 20:33:06.000000000 +0100 +@@ -52,6 +52,18 @@ + mov r7, #MACH_TYPE_POODLE + #endif + ++#ifdef CONFIG_MACH_CORGI ++@ mov r7, #MACH_TYPE_CORGI ++ mov r7, #0xa7 ++ add r7, r7, #0x100 ++#endif ++ ++#ifdef CONFIG_MACH_HUSKY ++@ mov r7, #MACH_TYPE_HUSKY ++ mov r7, #0xde ++ add r7, r7, #0x100 ++#endif ++ + #ifdef CONFIG_ARCH_IQ80310 + /* + * Crank the CPU up to 733MHz +diff -uNr linux-2.6.5-orig/arch/arm/boot/compressed/head.S linux-2.6.5/arch/arm/boot/compressed/head.S +--- linux-2.6.5-orig/arch/arm/boot/compressed/head.S 2004-06-14 20:31:53.000000000 +0100 ++++ linux-2.6.5/arch/arm/boot/compressed/head.S 2004-06-14 20:33:06.000000000 +0100 +@@ -10,6 +10,8 @@ + #include <linux/config.h> + #include <linux/linkage.h> + ++#define DEBUG 1 ++ + /* + * Debugging stuff + * +@@ -25,6 +27,12 @@ + .macro writeb, rb + str \rb, [r3, #0x160] + .endm ++#elif defined(CONFIG_DEBUG_ICEDCC) ++ .macro loadsp, rb ++ .endm ++ .macro writeb, rb ++ mcr p14, 0, \rb, c0, c1, 0 ++ .endm + #elif defined(CONFIG_FOOTBRIDGE) + .macro loadsp, rb + mov \rb, #0x7c000000 +@@ -67,6 +75,19 @@ + .macro writeb, rb + str \rb, [r3, #0x14] @ UTDR + .endm ++#elif defined(CONFIG_ARCH_IXP4XX) ++ .macro loadsp, rb ++ mov \rb, #0xc8000000 ++ .endm ++ .macro writeb, rb ++ str \rb, [r3, #0] ++#elif defined(CONFIG_ARCH_LH7A40X) ++ .macro loadsp, rb ++ ldr \rb, =0x80000700 @ UART2 UARTBASE ++ .endm ++ .macro writeb, rb ++ strb \rb, [r3, #0] ++ .endm + #else + #error no serial architecture defined + #endif +@@ -332,11 +353,19 @@ + mov r8, r0, lsr #18 + mov r8, r8, lsl #18 @ start of RAM + add r9, r8, #0x10000000 @ a reasonable RAM size +- mov r1, #0x12 ++@#ifdef CONFIG_CPU_XSCALE ++ mov r1, #0x02 ++@#else ++@ mov r1, #0x12 ++@#endif + orr r1, r1, #3 << 10 + add r2, r3, #16384 + 1: cmp r1, r8 @ if virt > start of RAM +- orrhs r1, r1, #0x0c @ set cacheable, bufferable ++@#ifdef CONFIG_XSCALE_CACHE_ERRATA ++ orrhs r1, r1, #0x08 @ set cacheable, not bufferable ++@#else ++@ orrhs r1, r1, #0x0c @ set cacheable, bufferable ++@#endif + cmp r1, r9 @ if virt > end of RAM + bichs r1, r1, #0x0c @ clear cacheable, bufferable + str r1, [r0], #4 @ 1:1 mapping +diff -uNr linux-2.6.5-orig/arch/arm/boot/compressed/vmlinux.lds.in linux-2.6.5/arch/arm/boot/compressed/vmlinux.lds.in +--- linux-2.6.5-orig/arch/arm/boot/compressed/vmlinux.lds.in 2004-06-14 20:31:53.000000000 +0100 ++++ linux-2.6.5/arch/arm/boot/compressed/vmlinux.lds.in 2004-06-14 20:33:06.000000000 +0100 +@@ -47,7 +47,7 @@ + .bss : { *(.bss) } + _end = .; + +- .stack (NOLOAD) : { *(.stack) } ++ .stack : { *(.stack) } + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } +diff -uNr linux-2.6.5-orig/arch/arm/mach-pxa/Kconfig linux-2.6.5/arch/arm/mach-pxa/Kconfig +--- linux-2.6.5-orig/arch/arm/mach-pxa/Kconfig 2004-06-14 20:31:53.000000000 +0100 ++++ linux-2.6.5/arch/arm/mach-pxa/Kconfig 2004-06-14 20:33:06.000000000 +0100 +@@ -13,10 +13,23 @@ + bool "SHARP Poodle" + depends on ARCH_PXA + ++config MACH_CORGI ++ bool "SHARP Corgi (SL-C700)" ++ depends on ARCH_PXA ++ ++config MACH_SHEPHERD ++ bool "SHARP Shepherd (SL-C750)" ++ depends on ARCH_PXA ++ ++config MACH_HUSKY ++ bool "SHARP Husky (SL-C760)" ++ depends on ARCH_PXA ++ + config SHARP_LOCOMO + bool "SHARP LoCoMo support" + default Y +- depends MACH_POODLE ++ depends MACH_POODLE || MACH_CORGI || MACH_HUSKY ++ + + endmenu + +diff -uNr linux-2.6.5-orig/arch/arm/mach-pxa/Makefile linux-2.6.5/arch/arm/mach-pxa/Makefile +--- linux-2.6.5-orig/arch/arm/mach-pxa/Makefile 2004-06-14 20:31:54.000000000 +0100 ++++ linux-2.6.5/arch/arm/mach-pxa/Makefile 2004-06-14 20:33:06.000000000 +0100 +@@ -9,12 +9,18 @@ + obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o + obj-$(CONFIG_ARCH_PXA_IDP) += idp.o + obj-$(CONFIG_MACH_POODLE) += poodle.o ++obj-$(CONFIG_MACH_CORGI) += corgi.o ++obj-$(CONFIG_MACH_SHEPHERD) += corgi.o ++obj-$(CONFIG_MACH_HUSKY) += corgi.o + + # Support for blinky lights + led-y := leds.o + led-$(CONFIG_ARCH_LUBBOCK) += leds-lubbock.o + led-$(CONFIG_ARCH_PXA_IDP) += leds-idp.o + led-$(CONFIG_MACH_POODLE) += leds-poodle.o ++led-$(CONFIG_MACH_CORGI) += leds-corgi.o ++led-$(CONFIG_MACH_SHEPHERD) += leds-corgi.o ++led-$(CONFIG_MACH_HUSKY) += leds-corgi.o + + obj-$(CONFIG_LEDS) += $(led-y) + +diff -uNr linux-2.6.5-orig/arch/arm/mach-pxa/corgi.c linux-2.6.5/arch/arm/mach-pxa/corgi.c +--- linux-2.6.5-orig/arch/arm/mach-pxa/corgi.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.5/arch/arm/mach-pxa/corgi.c 2004-06-14 20:33:19.000000000 +0100 +@@ -0,0 +1,178 @@ ++/* ++ * linux/arch/arm/mach-pxa/corgi.c ++ * ++ * Support for the SHARP Corgi Board. ++ * ++ * Copyright: Lineo Japan Inc. ++ * ++ * Based on: ++ * linux/arch/arm/mach-pxa/lubbock.c ++ * ++ * Support for the Intel DBPXA250 Development Platform. ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista 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. ++ * ++ * Change Log ++ * 12-Dec-2002 Sharp Corporation for Corgi ++ * 01-Apr-2003 Sharp for Shepherd ++ * ++ * Mar 10, 2004: Lots of changes to port to 2.6 by John Lenz ++ * ++ */ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/device.h> ++#include <linux/major.h> ++#include <linux/fs.h> ++#include <linux/interrupt.h> ++ ++#include <asm/setup.h> ++#include <asm/memory.h> ++#include <asm/mach-types.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/irq.h> ++#include <asm/arch/corgi.h> ++ ++#include "generic.h" ++ ++static void __init scoop_init(void) ++{ ++ ++#define CORGI_SCP_INIT_DATA(adr,dat) (((adr)<<16)|(dat)) ++#define CORGI_SCP_INIT_DATA_END ((unsigned long)-1) ++ static const unsigned long scp_init[] = ++ { ++ CORGI_SCP_INIT_DATA(CORGI_SCP_MCR,0x0140), // 00 ++ CORGI_SCP_INIT_DATA(CORGI_SCP_MCR,0x0100), ++ CORGI_SCP_INIT_DATA(CORGI_SCP_CDR,0x0000), // 04 ++ CORGI_SCP_INIT_DATA(CORGI_SCP_CPR,0x0000), // 0C ++ CORGI_SCP_INIT_DATA(CORGI_SCP_CCR,0x0000), // 10 ++ CORGI_SCP_INIT_DATA(CORGI_SCP_IMR,0x0000), // 18 ++ CORGI_SCP_INIT_DATA(CORGI_SCP_IRM,0x00FF), // 14 ++ CORGI_SCP_INIT_DATA(CORGI_SCP_ISR,0x0000), // 1C ++ CORGI_SCP_INIT_DATA(CORGI_SCP_IRM,0x0000), ++ CORGI_SCP_INIT_DATA(CORGI_SCP_GPCR,CORGI_SCP_IO_DIR), // 20 ++ CORGI_SCP_INIT_DATA(CORGI_SCP_GPWR,CORGI_SCP_IO_OUT), // 24 ++ CORGI_SCP_INIT_DATA_END ++ }; ++ int i; ++ for(i=0; scp_init[i] != CORGI_SCP_INIT_DATA_END; i++) ++ { ++ int adr = scp_init[i] >> 16; ++ CORGI_SCP_REG(adr) = scp_init[i] & 0xFFFF; ++ } ++} ++ ++static void __init corgi_init_irq(void) ++{ ++ pxa_init_irq(); ++ ++ /* setup extra corgi irqs */ ++ ++ /* i2c initialize */ ++ //i2c_init(); RPP Fixme! ++ ++ /* scoop initialize */ ++ scoop_init(); ++ ++ /* initialize SSP & CS */ ++ /*pxa_ssp_init();*/ ++} ++ ++#if 0 ++static void __init ++fixup_corgi(struct machine_desc *desc, struct param_struct *params, ++ char **cmdline, struct meminfo *mi) ++{ ++#if defined(CONFIG_MACH_SHEPHERD) || defined(CONFIG_MACH_HUSKY) ++ SET_BANK (0, 0xa0000000, 64*1024*1024); ++#else ++ SET_BANK (0, 0xa0000000, 32*1024*1024); ++#endif ++ mi->nr_banks = 1; ++#if defined(CONFIG_BLK_DEV_INITRD) ++ setup_ramdisk (1, 0, 0, 8192); ++ setup_initrd (__phys_to_virt(0xa1000000), 4*1024*1024); ++ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); ++#elif defined(CONFIG_MTD) ++ ROOT_DEV = MKDEV(31, 0); /* /dev/mtdblock0 */ ++#endif ++ ++#ifdef CONFIG_SHARPSL_BOOTLDR_PARAMS ++ if (params->u1.s.page_size != PAGE_SIZE) { ++ params->u1.s.page_size = PAGE_SIZE; ++ params->u1.s.nr_pages = 32 * 1024 * 1024 / PAGE_SIZE; ++ params->u1.s.ramdisk_size = 0; ++ params->u1.s.flags = FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT; ++ params->u1.s.rootdev = ROOT_DEV; ++ params->u1.s.initrd_start = 0; ++ params->u1.s.initrd_size = 0; ++ params->u1.s.rd_start = 0; ++ params->u1.s.system_rev = 0; ++ params->u1.s.system_serial_low = 0; ++ params->u1.s.system_serial_high = 0; ++ strcpy(params->commandline, CONFIG_CMDLINE); ++ } ++#endif ++} ++#endif ++ ++static struct map_desc corgi_io_desc[] __initdata = { ++ /* virtual physical length */ ++ { 0xf1000000, 0x08000000, 0x01000000, MT_DEVICE }, /* LCDC (readable for Qt driver) */ ++ { 0xf2000000, 0x10800000, 0x00001000, MT_DEVICE }, /* SCOOP */ ++ { 0xf2100000, 0x0C000000, 0x00001000, MT_DEVICE }, /* Nand Flash */ ++ { 0xef000000, 0x00000000, 0x00800000, MT_DEVICE }, /* Boot Flash */ ++}; ++ ++static void __init corgi_map_io(void) ++{ ++ pxa_map_io(); ++ iotable_init(corgi_io_desc,ARRAY_SIZE(corgi_io_desc)); ++ ++#if 0 ++ /* This enables the BTUART */ ++ CKEN |= CKEN7_BTUART; ++ set_GPIO_mode(GPIO42_BTRXD_MD); ++ set_GPIO_mode(GPIO43_BTTXD_MD); ++ set_GPIO_mode(GPIO44_BTCTS_MD); ++ set_GPIO_mode(GPIO45_BTRTS_MD); ++#endif ++ ++ /* setup sleep mode values */ ++ PWER = 0x00000002; ++ PFER = 0x00000000; ++ PRER = 0x00000002; ++ PGSR0 = 0x0158C000; ++ PGSR1 = 0x00FF0080; ++ PGSR2 = 0x0001C004; ++ PCFR |= PCFR_OPDE; ++} ++ ++#if defined(CONFIG_MACH_SHEPHERD) ++MACHINE_START(SHEPHERD, "SHARP Shepherd") ++#elseif defined(CONFIG_MACH_HUSKY) ++MACHINE_START(HUSKY, "SHARP Husky") ++#else ++MACHINE_START(CORGI, "SHARP Corgi") ++#endif ++ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) ++#ifdef CONFIG_SHARPSL_BOOTLDR_PARAMS ++ BOOT_PARAMS(0xa0000100) ++#endif ++/* FIXUP(fixup_corgi)*/ ++ MAPIO(corgi_map_io) ++ INITIRQ(corgi_init_irq) ++MACHINE_END +diff -uNr linux-2.6.5-orig/arch/arm/mach-pxa/leds-corgi.c linux-2.6.5/arch/arm/mach-pxa/leds-corgi.c +--- linux-2.6.5-orig/arch/arm/mach-pxa/leds-corgi.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.5/arch/arm/mach-pxa/leds-corgi.c 2004-06-14 20:33:19.000000000 +0100 +@@ -0,0 +1,135 @@ ++/* ++ * linux/arch/arm/mach-pxa/leds-corgi.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. ++ * ++ * Copied from arch/arm/mach-sa1100/leds-collie.c ++ * ChangeLog: ++ * - John Lenz <4/27/04> - added support for new locomo device model ++ */ ++ ++#include <linux/config.h> ++#include <linux/init.h> ++#include <linux/device.h> ++ ++#include <asm/hardware.h> ++#include <asm/hardware/locomo.h> ++#include <asm/leds.h> ++#include <asm/system.h> ++ ++#include "leds.h" ++ ++#define LED_STATE_ENABLED 1 ++#define LED_STATE_CLAIMED 2 ++ ++static struct locomo_dev *locomo_dev = NULL; ++static unsigned int led_state; ++static unsigned int hw_led0_state = 0; ++static unsigned int hw_led1_state = 0; ++ ++#define LED_ONOFF_MASK (LOCOMO_LPT_TOFL|LOCOMO_LPT_TOFH) ++#define LED_OFF(REG) ((REG)|=LOCOMO_LPT_TOFL) ++#define LED_ON(REG) ((REG)=((REG)&~LED_ONOFF_MASK)|LOCOMO_LPT_TOFH) ++#define LED_FLIP(REG) ((REG)^=LED_ONOFF_MASK) ++ ++void corgi_leds_event(led_event_t evt) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ switch (evt) { ++ case led_start: ++ led_state = LED_STATE_ENABLED; ++ LED_ON(hw_led0_state); ++ LED_ON(hw_led1_state); ++ break; ++ ++ case led_stop: ++ led_state &= ~LED_STATE_ENABLED; ++ break; ++ ++ case led_claim: ++ led_state |= LED_STATE_CLAIMED; ++ LED_ON(hw_led0_state); ++ LED_ON(hw_led1_state); ++ break; ++ ++ case led_release: ++ led_state &= ~LED_STATE_CLAIMED; ++ LED_ON(hw_led0_state); ++ LED_ON(hw_led1_state); ++ break; ++ ++#ifdef CONFIG_LEDS_TIMER ++ case led_timer: ++ if (!(led_state & LED_STATE_CLAIMED)) { ++ LED_FLIP(hw_led0_state); ++ } ++ break; ++#endif ++ ++#ifdef CONFIG_LEDS_CPU ++ case led_idle_start: ++ /* LED off when system is idle */ ++ if (!(led_state & LED_STATE_CLAIMED)) ++ LED_OFF(hw_led1_state); ++ break; ++ ++ case led_idle_end: ++ if (!(led_state & LED_STATE_CLAIMED)) ++ LED_ON(hw_led1_state); ++ break; ++#endif ++ ++ default: ++ break; ++ } ++ ++ ++ if (locomo_dev && led_state & LED_STATE_ENABLED) { ++ locomo_writel(hw_led0_state, locomo_dev->mapbase + LOCOMO_LPT0); ++ locomo_writel(hw_led1_state, locomo_dev->mapbase + LOCOMO_LPT1); ++ } ++ ++ local_irq_restore(flags); ++} ++ ++static int corgiled_probe(struct locomo_dev *dev) { ++ /* set up the initial led states, since due to the init order, ++ * corgi_leds_event(led_start) might have been called before this */ ++ /*if (led_state & LED_STATE_ENABLED) { ++ //LCM_LPT0 = hw_led0_state; ++ locomo_writel(hw_led0_state, dev->mapbase + LOCOMO_LPT0); ++ //LCM_LPT1 = hw_led1_state; ++ locomo_writel(hw_led1_state, dev->mapbase + LOCOMO_LPT1); ++ }*/ ++ locomo_dev = dev; ++ return 0; ++} ++ ++static int corgiled_remove(struct locomo_dev *dev) { ++ locomo_dev = NULL; ++ return 0; ++} ++ ++static struct locomo_driver corgiled_driver = { ++ .drv = { ++ .name = "locomoled" ++ }, ++ .devid = LOCOMO_DEVID_LED, ++ .probe = corgiled_probe, ++ .remove = corgiled_remove, ++}; ++ ++static int __init corgiled_init(void) { ++ return locomo_driver_register(&corgiled_driver); ++} ++ ++device_initcall(corgiled_init); ++ ++MODULE_AUTHOR("John Lenz <jelenz@wisc.edu>"); ++MODULE_DESCRIPTION("LoCoMo Corgi LED driver"); ++MODULE_LICENSE("GPL"); +diff -uNr linux-2.6.5-orig/arch/arm/mach-pxa/leds.c linux-2.6.5/arch/arm/mach-pxa/leds.c +--- linux-2.6.5-orig/arch/arm/mach-pxa/leds.c 2004-06-14 20:31:54.000000000 +0100 ++++ linux-2.6.5/arch/arm/mach-pxa/leds.c 2004-06-14 20:33:06.000000000 +0100 +@@ -24,7 +24,8 @@ + leds_event = idp_leds_event; + if (machine_is_poodle()) + leds_event = poodle_leds_event; +- ++ if (machine_is_corgi()) ++ leds_event = corgi_leds_event; + leds_event(led_start); + return 0; + } +diff -uNr linux-2.6.5-orig/arch/arm/mach-pxa/leds.h linux-2.6.5/arch/arm/mach-pxa/leds.h +--- linux-2.6.5-orig/arch/arm/mach-pxa/leds.h 2004-06-14 20:31:54.000000000 +0100 ++++ linux-2.6.5/arch/arm/mach-pxa/leds.h 2004-06-14 20:33:06.000000000 +0100 +@@ -10,3 +10,4 @@ + extern void lubbock_leds_event(led_event_t evt); + extern void idp_leds_event(led_event_t evt); + extern void poodle_leds_event(led_event_t evt); ++extern void corgi_leds_event(led_event_t evt); +diff -uNr linux-2.6.5-orig/arch/arm/tools/mach-types linux-2.6.5/arch/arm/tools/mach-types +--- linux-2.6.5-orig/arch/arm/tools/mach-types 2004-06-14 20:31:55.000000000 +0100 ++++ linux-2.6.5/arch/arm/tools/mach-types 2004-06-14 20:33:06.000000000 +0100 +@@ -485,3 +485,4 @@ + vr1000 MACH_VR1000 VR1000 475 + deisterpxa MACH_DEISTERPXA DEISTERPXA 476 + bcm1160 MACH_BCM1160 BCM1160 477 ++husky MACH_HUSKY HUSKY 478 +\ No newline at end of file +diff -uNr linux-2.6.5-orig/drivers/serial/8250.c linux-2.6.5/drivers/serial/8250.c +--- linux-2.6.5-orig/drivers/serial/8250.c 2004-06-14 20:31:55.000000000 +0100 ++++ linux-2.6.5/drivers/serial/8250.c 2004-06-14 20:33:06.000000000 +0100 +@@ -169,7 +169,8 @@ + { "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 }, +- { "NS16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO | UART_NATSEMI } ++ { "NS16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO | UART_NATSEMI }, ++ { "XScale", 32, UART_CLEAR_FIFO | UART_USE_FIFO }, + }; + + static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset) +@@ -1499,6 +1500,8 @@ + up->ier &= ~UART_IER_MSI; + if (UART_ENABLE_MS(&up->port, termios->c_cflag)) + up->ier |= UART_IER_MSI; ++ if (up->port.type == PORT_XSCALE) ++ up->ier |= UART_IER_UUE | UART_IER_RTOIE; + + serial_out(up, UART_IER, up->ier); + +@@ -1930,7 +1933,11 @@ + * First save the UER then disable the interrupts + */ + ier = serial_in(up, UART_IER); +- serial_out(up, UART_IER, 0); ++ ++ if (up->port.type == PORT_XSCALE) ++ serial_out(up, UART_IER, UART_IER_UUE); ++ else ++ serial_out(up, UART_IER, 0); + + /* + * Now, do each character +diff -uNr linux-2.6.5-orig/include/asm-arm/arch-pxa/corgi.h linux-2.6.5/include/asm-arm/arch-pxa/corgi.h +--- linux-2.6.5-orig/include/asm-arm/arch-pxa/corgi.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.5/include/asm-arm/arch-pxa/corgi.h 2004-06-14 20:33:19.000000000 +0100 +@@ -0,0 +1,219 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/corgi.h ++ * ++ * (C) Copyright 2001 Lineo Japan, Inc. ++ * ++ * May be copied or modified under the terms of the GNU General Public ++ * License. See linux/COPYING for more information. ++ * ++ * Based on: ++ * ++ * linux/include/asm-arm/arch-sa1100/collie.h ++ * ++ * This file contains the hardware specific definitions for Collie ++ * ++ * (C) Copyright 2001 Lineo Japan, Inc. ++ * ++ * May be copied or modified under the terms of the GNU General Public ++ * License. See linux/COPYING for more information. ++ * ++ * ChangeLog: ++ * 04-06-2001 Lineo Japan, Inc. ++ * 04-16-2001 SHARP Corporation ++ * ++ * Mar 10, 2004: Updates to 2.6 by John Lenz ++ */ ++#ifndef __ASM_ARCH_CORGI_H ++#define __ASM_ARCH_CORGI_H 1 ++ ++/* ++ * LCDC internal I/O mappings ++ * ++ * We have the following mapping: ++ * phys virt ++ * 08000000 f1000000 ++ */ ++ ++ ++ ++/* ++ * SCOOP internal I/O mappings ++ * ++ * We have the following mapping: ++ * phys virt ++ * 10800000 f2000000 ++ */ ++ ++ ++#define CF_BUF_CTRL_BASE 0xF2000000 ++ ++#define CORGI_SCP_REG(adr) (*(volatile unsigned short*)(CF_BUF_CTRL_BASE+(adr))) ++ ++#define CORGI_SCP_MCR 0x00 ++#define CORGI_SCP_CDR 0x04 ++#define CORGI_SCP_CSR 0x08 ++#define CORGI_SCP_CPR 0x0C ++#define CORGI_SCP_CCR 0x10 ++#define CORGI_SCP_IRR 0x14 ++#define CORGI_SCP_IRM 0x14 ++#define CORGI_SCP_IMR 0x18 ++#define CORGI_SCP_ISR 0x1C ++#define CORGI_SCP_GPCR 0x20 ++#define CORGI_SCP_GPWR 0x24 ++#define CORGI_SCP_GPRR 0x28 ++#define CORGI_SCP_REG_MCR CORGI_SCP_REG(CORGI_SCP_MCR) ++#define CORGI_SCP_REG_CDR CORGI_SCP_REG(CORGI_SCP_CDR) ++#define CORGI_SCP_REG_CSR CORGI_SCP_REG(CORGI_SCP_CSR) ++#define CORGI_SCP_REG_CPR CORGI_SCP_REG(CORGI_SCP_CPR) ++#define CORGI_SCP_REG_CCR CORGI_SCP_REG(CORGI_SCP_CCR) ++#define CORGI_SCP_REG_IRR CORGI_SCP_REG(CORGI_SCP_IRR) ++#define CORGI_SCP_REG_IRM CORGI_SCP_REG(CORGI_SCP_IRM) ++#define CORGI_SCP_REG_IMR CORGI_SCP_REG(CORGI_SCP_IMR) ++#define CORGI_SCP_REG_ISR CORGI_SCP_REG(CORGI_SCP_ISR) ++#define CORGI_SCP_REG_GPCR CORGI_SCP_REG(CORGI_SCP_GPCR) ++#define CORGI_SCP_REG_GPWR CORGI_SCP_REG(CORGI_SCP_GPWR) ++#define CORGI_SCP_REG_GPRR CORGI_SCP_REG(CORGI_SCP_GPRR) ++ ++#define CORGI_SCP_GPCR_PA22 ( 1 << 12 ) ++#define CORGI_SCP_GPCR_PA21 ( 1 << 11 ) ++#define CORGI_SCP_GPCR_PA20 ( 1 << 10 ) ++#define CORGI_SCP_GPCR_PA19 ( 1 << 9 ) ++#define CORGI_SCP_GPCR_PA18 ( 1 << 8 ) ++#define CORGI_SCP_GPCR_PA17 ( 1 << 7 ) ++#define CORGI_SCP_GPCR_PA16 ( 1 << 6 ) ++#define CORGI_SCP_GPCR_PA15 ( 1 << 5 ) ++#define CORGI_SCP_GPCR_PA14 ( 1 << 4 ) ++#define CORGI_SCP_GPCR_PA13 ( 1 << 3 ) ++#define CORGI_SCP_GPCR_PA12 ( 1 << 2 ) ++#define CORGI_SCP_GPCR_PA11 ( 1 << 1 ) ++ ++ ++/* ++ * GPIOs ++ */ ++#define CORGI_SCP_LED_GREEN CORGI_SCP_GPCR_PA11 ++#define CORGI_SCP_SWA CORGI_SCP_GPCR_PA12 ++#define CORGI_SCP_SWB CORGI_SCP_GPCR_PA13 ++#define CORGI_SCP_MUTE_L CORGI_SCP_GPCR_PA14 ++#define CORGI_SCP_MUTE_R CORGI_SCP_GPCR_PA15 ++#define CORGI_SCP_AKIN_PULLUP CORGI_SCP_GPCR_PA16 ++#define CORGI_SCP_APM_ON CORGI_SCP_GPCR_PA17 ++#define CORGI_SCP_BACKLIGHT_CONT CORGI_SCP_GPCR_PA18 ++#define CORGI_SCP_MIC_BIAS CORGI_SCP_GPCR_PA19 ++ ++ ++#define CORGI_SCP_IO_DIR ( CORGI_SCP_LED_GREEN | CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R | \ ++ CORGI_SCP_AKIN_PULLUP | CORGI_SCP_APM_ON | CORGI_SCP_BACKLIGHT_CONT | \ ++ CORGI_SCP_MIC_BIAS ) ++#define CORGI_SCP_IO_OUT ( CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R ) ++#define CORGI_GPIO_CO 16 ++ ++ ++/* ++ * Flash Memory mappings ++ * ++ * We have the following mapping: ++ * phys virt ++ * boot ROM 00000000 ef000000 ++ * NAND Flash 0C000000 f2100000 ++ */ ++#define NAND_FLASH_REG_BASE 0xf2100000 ++#define CORGI_CPLD_REG(ofst) (*(volatile unsigned char*)(NAND_FLASH_REG_BASE+(ofst))) ++ ++/* register offset */ ++#define CORGI_ECCLPLB 0x00 /* line parity 7 - 0 bit */ ++#define CORGI_ECCLPUB 0x04 /* line parity 15 - 8 bit */ ++#define CORGI_ECCCP 0x08 /* column parity 5 - 0 bit */ ++#define CORGI_ECCCNTR 0x0C /* ECC byte counter */ ++#define CORGI_ECCCLRR 0x10 /* cleare ECC */ ++#define CORGI_FLASHIO 0x14 /* Flash I/O */ ++#define CORGI_FLASHCTL 0x18 /* Flash Control */ ++ ++/* Flash control bit */ ++#define CORGI_FLRYBY (1 << 5) ++#define CORGI_FLCE1 (1 << 4) ++#define CORGI_FLWP (1 << 3) ++#define CORGI_FLALE (1 << 2) ++#define CORGI_FLCLE (1 << 1) ++#define CORGI_FLCE0 (1 << 0) ++ ++ ++ ++ ++/* ++CORGI_ * LED ++ */ ++#define CORGI_GPIO_LED_ORANGE (13) ++//#define CORGI_SCP_LED_GREEN CORGI_SCP_GPCR_PA11 ++ ++ ++/* ++ * GPIOs ++ */ ++/* PXA GPIOs */ ++#define CORGI_GPIO_KEY_INT (0) /* key interrupt */ ++#define CORGI_GPIO_AC_IN (1) ++#define CORGI_GPIO_TP_INT (5) /* Touch Panel interrupt */ ++#define CORGI_GPIO_WAKEUP (3) ++#define CORGI_GPIO_IR_ON (22) ++#define CORGI_GPIO_AK_INT (4) // Remote Controller ++#define CORGI_GPIO_HP_IN GPIO_AK_INT ++#define CORGI_GPIO_CF_IRQ (17) ++//#define CORGI_GPIO_CF_PRDY (17) ++#define CORGI_GPIO_LED_ORANGE (13) ++#define CORGI_GPIO_CF_CD (14) ++#define CORGI_GPIO_SD_PWR (33) ++#define CORGI_GPIO_nSD_CLK (6) ++#define CORGI_GPIO_nSD_WP (7) ++#define CORGI_GPIO_nSD_INT (10) ++#define CORGI_GPIO_nSD_DETECT (9) ++#define CORGI_GPIO_MAIN_BAT_LOW (11) ++#define CORGI_GPIO_BAT_COVER (11) ++#define CORGI_GPIO_ADC_TEMP_ON (21) ++#define CORGI_GPIO_CHRG_ON (38) ++#define CORGI_GPIO_CHRG_FULL (16) ++#define CORGI_GPIO_USB_PULLUP (45) ++#define CORGI_GPIO_HSYNC (44) ++ ++/* KeyBoard */ ++#define CORGI_KEY_STROBE_NUM (12) ++#define CORGI_KEY_SENSE_NUM (8) ++#define CORGI_GPIO_ALL_STROBE_BIT (0x00003ffc) ++#define CORGI_GPIO_HIGH_SENSE_BIT (0xfc000000) ++#define CORGI_GPIO_HIGH_SENSE_RSHIFT (26) ++#define CORGI_GPIO_LOW_SENSE_BIT (0x00000003) ++#define CORGI_GPIO_LOW_SENSE_LSHIFT (6) ++#define CORGI_GPIO_STROBE_BIT(a) GPIO_bit(66+(a)) ++#define CORGI_GPIO_SENSE_BIT(a) GPIO_bit(58+(a)) ++#define CORGI_GAFR_ALL_STROBE_BIT (0x0ffffff0) ++#define CORGI_GAFR_HIGH_SENSE_BIT (0xfff00000) ++#define CORGI_GAFR_LOW_SENSE_BIT (0x0000000f) ++#define CORGI_GPIO_KEY_SENSE(a) (58+(a)) ++ ++ ++/* ++ * Interrupts ++ */ ++/* PXA GPIOs */ ++#define CORGI_IRQ_GPIO_KEY_INT IRQ_GPIO(0) ++#define CORGI_IRQ_GPIO_AC_IN IRQ_GPIO(1) ++#define CORGI_IRQ_GPIO_AK_INT IRQ_GPIO(4) ++#define CORGI_IRQ_GPIO_HP_IN IRQ_GPIO_AK_INT ++#define CORGI_IRQ_GPIO_TP_INT IRQ_GPIO(5) ++#define CORGI_IRQ_GPIO_WAKEUP IRQ_GPIO(3) ++#define CORGI_IRQ_GPIO_CO IRQ_GPIO(16) ++#define CORGI_IRQ_GPIO_CF_IRQ IRQ_GPIO(17) ++#define CORGI_IRQ_GPIO_CF_CD IRQ_GPIO(14) ++#define CORGI_IRQ_GPIO_nSD_INT IRQ_GPIO(10) ++#define CORGI_IRQ_GPIO_nSD_DETECT IRQ_GPIO(9) ++#define CORGI_IRQ_GPIO_MAIN_BAT_LOW IRQ_GPIO(11) ++#define CORGI_IRQ_GPIO_KEY_SENSE(a) IRQ_GPIO(58+(a)) ++ ++ ++// CS ++#define CORGI_CS_MAX1111 1 ++#define CORGI_CS_ADS7846 2 ++#define CORGI_CS_LZ9JG18 3 ++ ++#endif /* __ASM_ARCH_CORGI_H */ ++ +diff -uNr linux-2.6.5-orig/include/asm-arm/thread_info.h linux-2.6.5/include/asm-arm/thread_info.h +--- linux-2.6.5-orig/include/asm-arm/thread_info.h 2004-06-14 20:31:55.000000000 +0100 ++++ linux-2.6.5/include/asm-arm/thread_info.h 2004-06-14 20:33:06.000000000 +0100 +@@ -108,8 +108,8 @@ + #define TI_CPU 20 + #define TI_CPU_DOMAIN 24 + #define TI_CPU_SAVE 28 +-#define TI_USED_MATH 76 +-#define TI_FPSTATE (TI_USED_MATH+16) ++#define TI_USED_CP 76 ++#define TI_FPSTATE (TI_USED_CP+16) + + #endif + +diff -uNr linux-2.6.5-orig/include/linux/serial_core.h linux-2.6.5/include/linux/serial_core.h +--- linux-2.6.5-orig/include/linux/serial_core.h 2004-06-14 20:31:56.000000000 +0100 ++++ linux-2.6.5/include/linux/serial_core.h 2004-06-14 20:33:06.000000000 +0100 +@@ -38,7 +38,8 @@ + #define PORT_16850 12 + #define PORT_RSA 13 + #define PORT_NS16550A 14 +-#define PORT_MAX_8250 14 /* max port ID */ ++#define PORT_XSCALE 15 ++#define PORT_MAX_8250 15 /* max port ID */ + + /* + * ARM specific type numbers. These are not currently guaranteed +diff -uNr linux-2.6.5-orig/include/linux/serial_reg.h linux-2.6.5/include/linux/serial_reg.h +--- linux-2.6.5-orig/include/linux/serial_reg.h 2004-06-14 20:31:56.000000000 +0100 ++++ linux-2.6.5/include/linux/serial_reg.h 2004-06-14 20:33:06.000000000 +0100 +@@ -141,7 +141,7 @@ + #define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */ + + /* +- * The Intel PXA2xx chip defines those bits ++ * The Intel XScale on-chip UARTs define these bits + */ + #define UART_IER_DMAE 0x80 /* DMA Requests Enable */ + #define UART_IER_UUE 0x40 /* UART Unit Enable */ +diff -uNr linux-2.6.5-orig/arch/arm/boot/Makefile linux-2.6.5/arch/arm/boot/Makefile +--- linux-2.6.5-orig/arch/arm/boot/Makefile 2004-04-04 04:36:18.000000000 +0100 ++++ linux-2.6.5/arch/arm/boot/Makefile 2004-06-14 21:36:21.000000000 +0100 +@@ -69,6 +69,8 @@ + ZBSSADDR := ALIGN(4) + endif + ++OBJCOPYFLAGS_zImage := --pad-to `(arm-linux-readelf -l arch/arm/boot/compressed/vmlinux | grep LOAD | awk '{ print $$6 }')` ++ + export ZTEXTADDR ZBSSADDR ZRELADDR INITRD_PHYS PARAMS_PHYS + + targets := Image zImage bootpImage diff --git a/linux/openzaurus-2.6.10-rc1-jl1/poodle-config-2.6.7-jl2 b/linux/openzaurus-2.6.10-rc1-jl1/poodle-config-2.6.7-jl2 index e69de29bb2..dc773136f4 100644 --- a/linux/openzaurus-2.6.10-rc1-jl1/poodle-config-2.6.7-jl2 +++ b/linux/openzaurus-2.6.10-rc1-jl1/poodle-config-2.6.7-jl2 @@ -0,0 +1,708 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_HOTPLUG=y +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_OBSOLETE_MODPARM=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ADIFCC 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_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_L7200 is not set +CONFIG_ARCH_PXA=y +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_VERSATILE_PB is not set + +# +# Intel PXA2xx Implementations +# +# CONFIG_ARCH_LUBBOCK is not set +# CONFIG_MACH_MAINSTONE is not set +# CONFIG_ARCH_PXA_IDP is not set +CONFIG_MACH_POODLE=y +CONFIG_SHARP_LOCOMO=y +CONFIG_PXA25x=y + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_XSCALE=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5T=y +CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_MINICACHE=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +CONFIG_XSCALE_PMU=y + +# +# General setup +# +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_AOUT=m +CONFIG_BINFMT_MISC=m + +# +# Generic Driver Options +# +CONFIG_FW_LOADER=m +# CONFIG_DEBUG_DRIVER is not set +CONFIG_PM=y +CONFIG_PREEMPT=y +CONFIG_APM=y +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="noinitrd root=/dev/mtdblock2 rootfstype=jffs2" +CONFIG_LEDS=y +CONFIG_LEDS_TIMER=y +CONFIG_LEDS_CPU=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +CONFIG_MTD_DEBUG=y +CONFIG_MTD_DEBUG_VERBOSE=1 +CONFIG_MTD_PARTITIONS=y +# 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 + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +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 is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_EDB7312 is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=1024 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB 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 +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_NETDEVICES is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_TSDEV=y +CONFIG_INPUT_TSDEV_SCREEN_X=240 +CONFIG_INPUT_TSDEV_SCREEN_Y=320 +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_EVBUG=y + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_LOCOMO is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_PXA is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +# 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 +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +CONFIG_I2C=m +# CONFIG_I2C_CHARDEV is not set + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +# CONFIG_I2C_ALGOPCF is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +CONFIG_I2C_ISA=m +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_SCx200_ACB is not set + +# +# Hardware Sensors Chip support +# +# CONFIG_I2C_SENSOR is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=m + +# +# Video For Linux +# + +# +# Video Adapters +# +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_SAA5246A is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set + +# +# Radio Adapters +# +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_MAESTRO is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS 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_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=1 +# CONFIG_JFFS2_FS_NAND is not set +CONFIG_CRAMFS=y +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_EXPORTFS is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="cp437" +CONFIG_NLS_CODEPAGE_437=m +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ISO8859_1=m +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=m + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +CONFIG_FB=y +CONFIG_FB_PXA=y +# CONFIG_FB_PXA_PARAMETERS is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_PCI_CONSOLE=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set + +# +# Logo configuration +# +# CONFIG_LOGO is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Misc devices +# + +# +# USB support +# + +# +# USB Gadget Support +# +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_NET2280 is not set +CONFIG_USB_GADGET_PXA2XX=y +CONFIG_USB_PXA2XX=y +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_SA1100 is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +# CONFIG_USB_GADGET_DUALSPEED is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluecard_cs.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluecard_cs.patch index e69de29bb2..eacada33f5 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluecard_cs.patch +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluecard_cs.patch @@ -0,0 +1,11 @@ +--- linux-orig/drivers/bluetooth/bluecard_cs.c 2004-02-16 10:51:46.000000000 +0300 ++++ linux/drivers/bluetooth/bluecard_cs.c 2004-02-17 03:45:31.000000000 +0300 +@@ -102,7 +102,7 @@ + + + /* Default baud rate: 57600, 115200, 230400 or 460800 */ +-#define DEFAULT_BAUD_RATE 230400 ++#define DEFAULT_BAUD_RATE 460800 + + + /* Hardware states */ diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluetooth-2.4.18-mh11.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluetooth-2.4.18-mh11.patch index e69de29bb2..f2ea0d699b 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluetooth-2.4.18-mh11.patch +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluetooth-2.4.18-mh11.patch @@ -0,0 +1,31393 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux/arch/alpha/config.in~bluetooth-2.4.18-mh11 2004-01-25 23:28:10.000000000 +0100 ++++ linux/arch/alpha/config.in 2004-01-25 23:37:39.000000000 +0100 +@@ -372,9 +372,7 @@ + source drivers/usb/Config.in + source drivers/input/Config.in + +-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +- source net/bluetooth/Config.in +-fi ++source net/bluetooth/Config.in + + mainmenu_option next_comment + comment 'Kernel hacking' +--- linux/arch/arm/config.in~bluetooth-2.4.18-mh11 2004-01-25 23:28:31.000000000 +0100 ++++ linux/arch/arm/config.in 2004-01-25 23:37:39.000000000 +0100 +@@ -796,9 +796,7 @@ + + source drivers/usb/Config.in + +-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +- source net/bluetooth/Config.in +-fi ++source net/bluetooth/Config.in + + mainmenu_option next_comment + comment 'Kernel hacking' +--- linux/arch/i386/config.in~bluetooth-2.4.18-mh11 2004-01-25 23:28:31.000000000 +0100 ++++ linux/arch/i386/config.in 2004-01-25 23:37:39.000000000 +0100 +@@ -415,9 +415,7 @@ + + source drivers/usb/Config.in + +-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +- source net/bluetooth/Config.in +-fi ++source net/bluetooth/Config.in + + mainmenu_option next_comment + comment 'Kernel hacking' +--- linux/arch/ppc/config.in~bluetooth-2.4.18-mh11 2004-01-25 23:28:11.000000000 +0100 ++++ linux/arch/ppc/config.in 2004-01-25 23:37:39.000000000 +0100 +@@ -390,9 +390,7 @@ + + source drivers/usb/Config.in + +-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +- source net/bluetooth/Config.in +-fi ++source net/bluetooth/Config.in + + mainmenu_option next_comment + comment 'Kernel hacking' +--- linux/arch/sparc/config.in~bluetooth-2.4.18-mh11 2004-01-25 23:28:11.000000000 +0100 ++++ linux/arch/sparc/config.in 2004-01-25 23:37:39.000000000 +0100 +@@ -252,9 +252,7 @@ + + source fs/Config.in + +-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +- source net/bluetooth/Config.in +-fi ++source net/bluetooth/Config.in + + mainmenu_option next_comment + comment 'Watchdog' +--- linux/arch/sparc64/config.in~bluetooth-2.4.18-mh11 2004-01-25 23:28:11.000000000 +0100 ++++ linux/arch/sparc64/config.in 2004-01-25 23:37:39.000000000 +0100 +@@ -284,9 +284,7 @@ + + source drivers/usb/Config.in + +-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +- source net/bluetooth/Config.in +-fi ++source net/bluetooth/Config.in + + mainmenu_option next_comment + comment 'Watchdog' +--- linux/arch/sparc64/kernel/ioctl32.c~bluetooth-2.4.18-mh11 2002-02-25 20:37:56.000000000 +0100 ++++ linux/arch/sparc64/kernel/ioctl32.c 2004-01-25 23:37:39.000000000 +0100 +@@ -92,6 +92,7 @@ + + #include <net/bluetooth/bluetooth.h> + #include <net/bluetooth/hci.h> ++#include <net/bluetooth/rfcomm.h> + + #include <linux/usb.h> + #include <linux/usbdevice_fs.h> +@@ -3822,6 +3823,15 @@ + return err; + } + ++/* Bluetooth ioctls */ ++#define HCIUARTSETPROTO _IOW('U', 200, int) ++#define HCIUARTGETPROTO _IOR('U', 201, int) ++ ++#define BNEPCONNADD _IOW('B', 200, int) ++#define BNEPCONNDEL _IOW('B', 201, int) ++#define BNEPGETCONNLIST _IOR('B', 210, int) ++#define BNEPGETCONNINFO _IOR('B', 211, int) ++ + struct mtd_oob_buf32 { + u32 start; + u32 length; +@@ -3878,6 +3888,11 @@ + return ((0 == ret) ? 0 : -EFAULT); + } + ++#define CMTPCONNADD _IOW('C', 200, int) ++#define CMTPCONNDEL _IOW('C', 201, int) ++#define CMTPGETCONNLIST _IOR('C', 210, int) ++#define CMTPGETCONNINFO _IOR('C', 211, int) ++ + struct ioctl_trans { + unsigned int cmd; + unsigned int handler; +@@ -4540,6 +4555,21 @@ + COMPATIBLE_IOCTL(HCISETSCAN) + COMPATIBLE_IOCTL(HCISETAUTH) + COMPATIBLE_IOCTL(HCIINQUIRY) ++COMPATIBLE_IOCTL(HCIUARTSETPROTO) ++COMPATIBLE_IOCTL(HCIUARTGETPROTO) ++COMPATIBLE_IOCTL(RFCOMMCREATEDEV) ++COMPATIBLE_IOCTL(RFCOMMRELEASEDEV) ++COMPATIBLE_IOCTL(RFCOMMGETDEVLIST) ++COMPATIBLE_IOCTL(RFCOMMGETDEVINFO) ++COMPATIBLE_IOCTL(RFCOMMSTEALDLC) ++COMPATIBLE_IOCTL(BNEPCONNADD) ++COMPATIBLE_IOCTL(BNEPCONNDEL) ++COMPATIBLE_IOCTL(BNEPGETCONNLIST) ++COMPATIBLE_IOCTL(BNEPGETCONNINFO) ++COMPATIBLE_IOCTL(CMTPCONNADD) ++COMPATIBLE_IOCTL(CMTPCONNDEL) ++COMPATIBLE_IOCTL(CMTPGETCONNLIST) ++COMPATIBLE_IOCTL(CMTPGETCONNINFO) + /* Misc. */ + COMPATIBLE_IOCTL(0x41545900) /* ATYIO_CLKR */ + COMPATIBLE_IOCTL(0x41545901) /* ATYIO_CLKW */ +--- linux/CREDITS~bluetooth-2.4.18-mh11 2004-01-25 23:28:29.000000000 +0100 ++++ linux/CREDITS 2004-01-25 23:37:39.000000000 +0100 +@@ -1317,6 +1317,15 @@ + S: Provo, Utah 84606-5607 + S: USA + ++N: Marcel Holtmann ++E: marcel@holtmann.org ++W: http://www.holtmann.org ++D: Maintainer of the Linux Bluetooth Subsystem ++D: Author and maintainer of the various Bluetooth HCI drivers ++D: Author and maintainer of the CAPI message transport protocol driver ++D: Various other Bluetooth related patches, cleanups and fixes ++S: Germany ++ + N: Rob W. W. Hooft + E: hooft@EMBL-Heidelberg.DE + D: Shared libs for graphics-tools and for the f2c compiler +@@ -2555,6 +2564,7 @@ + N: Aristeu Sergio Rozanski Filho + E: aris@conectiva.com.br + D: Support for EtherExpress 10 ISA (i82595) in eepro driver ++D: User level driver support for input + S: Conectiva S.A. + S: R. Tocantins, 89 - Cristo Rei + S: 80050-430 - Curitiba - Paran� +--- linux/Documentation/Configure.help~bluetooth-2.4.18-mh11 2004-01-25 23:28:31.000000000 +0100 ++++ linux/Documentation/Configure.help 2004-01-25 23:37:39.000000000 +0100 +@@ -2847,14 +2847,6 @@ + + If unsure, say N. + +-HCI EMU (virtual device) driver +-CONFIG_BLUEZ_HCIEMU +- Bluetooth Virtual HCI device driver. +- This driver is required if you want to use HCI Emulation software. +- +- Say Y here to compile support for Virtual HCI devices into the +- kernel or say M to compile it as module (hci_usb.o). +- + # Choice: alphatype + Alpha system type + CONFIG_ALPHA_GENERIC +@@ -11067,6 +11059,12 @@ + + If unsure, say N. + ++Hotplug firmware loading support (EXPERIMENTAL) ++CONFIG_FW_LOADER ++ This option is provided for the case where no in-kernel-tree modules require ++ hotplug firmware loading support, but a module built outside the kernel tree ++ does. ++ + Use PCI shared memory for NIC registers + CONFIG_TULIP_MMIO + Use PCI shared memory for the NIC registers, rather than going through +@@ -12967,6 +12965,15 @@ + accessible under char device 13:64+ - /dev/input/eventX in a generic + way. This is the future ... + ++CONFIG_INPUT_UINPUT ++ Say Y here if you want to support user level drivers for input ++ subsystem accessible under char device 10:223 - /dev/input/uinput. ++ ++ This driver is also available as a module ( = code which can be ++ inserted in and removed from the running kernel whenever you want). ++ The module will be called uinput.o. If you want to compile it as a ++ module, say M here and read <file:Documentation/modules.txt>. ++ + USB Scanner support + CONFIG_USB_SCANNER + Say Y here if you want to connect a USB scanner to your computer's +@@ -19986,11 +19993,15 @@ + Bluetooth can be found at <http://www.bluetooth.com/>. + + Linux Bluetooth subsystem consist of several layers: +- HCI Core (device and connection manager, scheduler) ++ BlueZ Core (HCI device and connection manager, scheduler) + HCI Device drivers (interface to the hardware) + L2CAP Module (L2CAP protocol) ++ SCO Module (SCO links) ++ RFCOMM Module (RFCOMM protocol) ++ BNEP Module (BNEP protocol) ++ CMTP Module (CMTP protocol) + +- Say Y here to enable Linux Bluetooth support and to build HCI Core ++ Say Y here to enable Linux Bluetooth support and to build BlueZ Core + layer. + + To use Linux Bluetooth subsystem, you will need several user-space +@@ -19998,7 +20009,7 @@ + Bluetooth kernel modules are provided in the BlueZ package. + For more information, see <http://bluez.sourceforge.net/>. + +- If you want to compile HCI Core as module (hci.o) say M here. ++ If you want to compile BlueZ Core as module (bluez.o) say M here. + + L2CAP protocol support + CONFIG_BLUEZ_L2CAP +@@ -20009,15 +20020,91 @@ + Say Y here to compile L2CAP support into the kernel or say M to + compile it as module (l2cap.o). + ++SCO links support ++CONFIG_BLUEZ_SCO ++ SCO link provides voice transport over Bluetooth. SCO support is ++ required for voice applications like Headset and Audio. ++ ++ Say Y here to compile SCO support into the kernel or say M to ++ compile it as module (sco.o). ++ ++RFCOMM protocol support ++CONFIG_BLUEZ_RFCOMM ++ RFCOMM provides connection oriented stream transport. RFCOMM ++ support is required for Dialup Networking, OBEX and other Bluetooth ++ applications. ++ ++ Say Y here to compile RFCOMM support into the kernel or say M to ++ compile it as module (rfcomm.o). ++ ++RFCOMM TTY emulation support ++CONFIG_BLUEZ_RFCOMM_TTY ++ This option enables TTY emulation support for RFCOMM channels. ++ ++BNEP protocol support ++CONFIG_BLUEZ_BNEP ++ BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet ++ emulation layer on top of Bluetooth. BNEP is required for Bluetooth ++ PAN (Personal Area Network). ++ ++ To use BNEP, you will need user-space utilities provided in the ++ BlueZ-PAN package. ++ For more information, see <http://bluez.sourceforge.net>. ++ ++ Say Y here to compile BNEP support into the kernel or say M to ++ compile it as module (bnep.o). ++ ++CMTP protocol support ++CONFIG_BLUEZ_CMTP ++ CMTP (CAPI Message Transport Protocol) is a transport layer ++ for CAPI messages. CMTP is required for the Bluetooth Common ++ ISDN Access Profile. ++ ++ Say Y here to compile CMTP support into the kernel or say M to ++ compile it as module (cmtp.o). ++ ++BNEP multicast filter support ++CONFIG_BLUEZ_BNEP_MC_FILTER ++ This option enables the multicast filter support for BNEP. ++ ++BNEP protocol filter support ++CONFIG_BLUEZ_BNEP_PROTO_FILTER ++ This option enables the protocol filter support for BNEP. ++ + HCI UART driver + CONFIG_BLUEZ_HCIUART + Bluetooth HCI UART driver. + This driver is required if you want to use Bluetooth devices with +- serial port interface. ++ serial port interface. You will also need this driver if you have ++ UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card ++ adapter and BrainBoxes Bluetooth PC Card. + + Say Y here to compile support for Bluetooth UART devices into the + kernel or say M to compile it as module (hci_uart.o). + ++HCI UART (H4) protocol support ++CONFIG_BLUEZ_HCIUART_H4 ++ UART (H4) is serial protocol for communication between Bluetooth ++ device and host. This protocol is required for most Bluetooth devices ++ with UART interface, including PCMCIA and CF cards. ++ ++ Say Y here to compile support for HCI UART (H4) protocol. ++ ++HCI BCSP protocol support ++CONFIG_BLUEZ_HCIUART_BCSP ++ BCSP (BlueCore Serial Protocol) is serial protocol for communication ++ between Bluetooth device and host. This protocol is required for non ++ USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and ++ CF cards. ++ ++ Say Y here to compile support for HCI BCSP protocol. ++ ++HCI BCSP transmit CRC with every BCSP packet ++CONFIG_BLUEZ_HCIUART_BCSP_TXCRC ++ If you say Y here, a 16-bit CRC checksum will be transmitted along with ++ every BCSP (BlueCore Serial Protocol) packet sent to the Bluetooth chip. ++ This increases reliability, but slightly reduces efficiency. ++ + HCI USB driver + CONFIG_BLUEZ_HCIUSB + Bluetooth HCI USB driver. +@@ -20027,7 +20114,16 @@ + Say Y here to compile support for Bluetooth USB devices into the + kernel or say M to compile it as module (hci_usb.o). + +-HCI VHCI virtual HCI device driver ++HCI USB SCO (voice) support ++CONFIG_BLUEZ_HCIUSB_SCO ++ This option enables the SCO support in the HCI USB driver. You need this ++ to transmit voice data with your Bluetooth USB device. And your device ++ must also support sending SCO data over the HCI layer, because some of ++ them sends the SCO data to an internal PCM adapter. ++ ++ Say Y here to compile support for HCI SCO data. ++ ++HCI VHCI Virtual HCI device driver + CONFIG_BLUEZ_HCIVHCI + Bluetooth Virtual HCI device driver. + This driver is required if you want to use HCI Emulation software. +@@ -20035,6 +20131,66 @@ + Say Y here to compile support for virtual HCI devices into the + kernel or say M to compile it as module (hci_vhci.o). + ++HCI BFUSB device driver ++CONFIG_BLUEZ_HCIBFUSB ++ Bluetooth HCI BlueFRITZ! USB driver. ++ This driver provides support for Bluetooth USB devices with AVM ++ interface: ++ AVM BlueFRITZ! USB ++ ++ Say Y here to compile support for HCI BFUSB devices into the ++ kernel or say M to compile it as module (bfusb.o). ++ ++HCI DTL1 (PC Card) device driver ++CONFIG_BLUEZ_HCIDTL1 ++ Bluetooth HCI DTL1 (PC Card) driver. ++ This driver provides support for Bluetooth PCMCIA devices with ++ Nokia DTL1 interface: ++ Nokia Bluetooth Card ++ Socket Bluetooth CF Card ++ ++ Say Y here to compile support for HCI DTL1 devices into the ++ kernel or say M to compile it as module (dtl1_cs.o). ++ ++HCI BT3C (PC Card) device driver ++CONFIG_BLUEZ_HCIBT3C ++ Bluetooth HCI BT3C (PC Card) driver. ++ This driver provides support for Bluetooth PCMCIA devices with ++ 3Com BT3C interface: ++ 3Com Bluetooth Card (3CRWB6096) ++ HP Bluetooth Card ++ ++ The HCI BT3C driver uses external firmware loader program provided in ++ the BlueFW package. For more information, see <http://bluez.sf.net>. ++ ++ Say Y here to compile support for HCI BT3C devices into the ++ kernel or say M to compile it as module (bt3c_cs.o). ++ ++HCI BlueCard (PC Card) device driver ++CONFIG_BLUEZ_HCIBLUECARD ++ Bluetooth HCI BlueCard (PC Card) driver. ++ This driver provides support for Bluetooth PCMCIA devices with ++ Anycom BlueCard interface: ++ Anycom Bluetooth PC Card ++ Anycom Bluetooth CF Card ++ ++ Say Y here to compile support for HCI BlueCard devices into the ++ kernel or say M to compile it as module (bluecard_cs.o). ++ ++HCI UART (PC Card) device driver ++CONFIG_BLUEZ_HCIBTUART ++ Bluetooth HCI UART (PC Card) driver. ++ This driver provides support for Bluetooth PCMCIA devices with ++ an UART interface: ++ Xircom CreditCard Bluetooth Adapter ++ Xircom RealPort2 Bluetooth Adapter ++ Sphinx PICO Card ++ H-Soft blue+Card ++ Cyber-blue Compact Flash Card ++ ++ Say Y here to compile support for HCI UART devices into the ++ kernel or say M to compile it as module (btuart_cs.o). ++ + # The following options are for Linux when running on the Hitachi + # SuperH family of RISC microprocessors. + +--- linux/Documentation/devices.txt~bluetooth-2.4.18-mh11 2001-11-07 23:46:01.000000000 +0100 ++++ linux/Documentation/devices.txt 2004-01-25 23:37:39.000000000 +0100 +@@ -419,6 +419,7 @@ + 220 = /dev/mptctl Message passing technology (MPT) control + 221 = /dev/mvista/hssdsi Montavista PICMG hot swap system driver + 222 = /dev/mvista/hasi Montavista PICMG high availability ++ 223 = /dev/input/uinput User level driver support for input + 240-255 Reserved for local use + + 11 char Raw keyboard device +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/Documentation/firmware_class/firmware_sample_driver.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,121 @@ ++/* ++ * firmware_sample_driver.c - ++ * ++ * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org> ++ * ++ * Sample code on how to use request_firmware() from drivers. ++ * ++ * Note that register_firmware() is currently useless. ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/string.h> ++ ++#include "linux/firmware.h" ++ ++#define WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE ++#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE ++char __init inkernel_firmware[] = "let's say that this is firmware\n"; ++#endif ++ ++static char ghost_device[] = "ghost0"; ++ ++static void sample_firmware_load(char *firmware, int size) ++{ ++ u8 buf[size+1]; ++ memcpy(buf, firmware, size); ++ buf[size] = '\0'; ++ printk("firmware_sample_driver: firmware: %s\n", buf); ++} ++ ++static void sample_probe_default(void) ++{ ++ /* uses the default method to get the firmware */ ++ const struct firmware *fw_entry; ++ printk("firmware_sample_driver: a ghost device got inserted :)\n"); ++ ++ if(request_firmware(&fw_entry, "sample_driver_fw", ghost_device)!=0) ++ { ++ printk(KERN_ERR ++ "firmware_sample_driver: Firmware not available\n"); ++ return; ++ } ++ ++ sample_firmware_load(fw_entry->data, fw_entry->size); ++ ++ release_firmware(fw_entry); ++ ++ /* finish setting up the device */ ++} ++static void sample_probe_specific(void) ++{ ++ /* Uses some specific hotplug support to get the firmware from ++ * userspace directly into the hardware, or via some sysfs file */ ++ ++ /* NOTE: This currently doesn't work */ ++ ++ printk("firmware_sample_driver: a ghost device got inserted :)\n"); ++ ++ if(request_firmware(NULL, "sample_driver_fw", ghost_device)!=0) ++ { ++ printk(KERN_ERR ++ "firmware_sample_driver: Firmware load failed\n"); ++ return; ++ } ++ ++ /* request_firmware blocks until userspace finished, so at ++ * this point the firmware should be already in the device */ ++ ++ /* finish setting up the device */ ++} ++static void sample_probe_async_cont(const struct firmware *fw, void *context) ++{ ++ if(!fw){ ++ printk(KERN_ERR ++ "firmware_sample_driver: firmware load failed\n"); ++ return; ++ } ++ ++ printk("firmware_sample_driver: device pointer \"%s\"\n", ++ (char *)context); ++ sample_firmware_load(fw->data, fw->size); ++} ++static void sample_probe_async(void) ++{ ++ /* Let's say that I can't sleep */ ++ int error; ++ error = request_firmware_nowait (THIS_MODULE, ++ "sample_driver_fw", ghost_device, ++ "my device pointer", ++ sample_probe_async_cont); ++ if(error){ ++ printk(KERN_ERR ++ "firmware_sample_driver:" ++ " request_firmware_nowait failed\n"); ++ } ++} ++ ++static int sample_init(void) ++{ ++#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE ++ register_firmware("sample_driver_fw", inkernel_firmware, ++ sizeof(inkernel_firmware)); ++#endif ++ /* since there is no real hardware insertion I just call the ++ * sample probe functions here */ ++ sample_probe_specific(); ++ sample_probe_default(); ++ sample_probe_async(); ++ return 0; ++} ++static void __exit sample_exit(void) ++{ ++} ++ ++module_init (sample_init); ++module_exit (sample_exit); ++ ++MODULE_LICENSE("GPL"); +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/Documentation/firmware_class/hotplug-script 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,16 @@ ++#!/bin/sh ++ ++# Simple hotplug script sample: ++# ++# Both $DEVPATH and $FIRMWARE are already provided in the environment. ++ ++HOTPLUG_FW_DIR=/usr/lib/hotplug/firmware/ ++ ++echo 1 > /sysfs/$DEVPATH/loading ++cat $HOTPLUG_FW_DIR/$FIRMWARE > /sysfs/$DEVPATH/data ++echo 0 > /sysfs/$DEVPATH/loading ++ ++# To cancel the load in case of error: ++# ++# echo -1 > /sysfs/$DEVPATH/loading ++# +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/Documentation/firmware_class/README 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,58 @@ ++ ++ request_firmware() hotplug interface: ++ ------------------------------------ ++ Copyright (C) 2003 Manuel Estrada Sainz <ranty@debian.org> ++ ++ Why: ++ --- ++ ++ Today, the most extended way to use firmware in the Linux kernel is linking ++ it statically in a header file. Which has political and technical issues: ++ ++ 1) Some firmware is not legal to redistribute. ++ 2) The firmware occupies memory permanently, even though it often is just ++ used once. ++ 3) Some people, like the Debian crowd, don't consider some firmware free ++ enough and remove entire drivers (e.g.: keyspan). ++ ++ about in-kernel persistence: ++ --------------------------- ++ Under some circumstances, as explained below, it would be interesting to keep ++ firmware images in non-swappable kernel memory or even in the kernel image ++ (probably within initramfs). ++ ++ Note that this functionality has not been implemented. ++ ++ - Why OPTIONAL in-kernel persistence may be a good idea sometimes: ++ ++ - If the device that needs the firmware is needed to access the ++ filesystem. When upon some error the device has to be reset and the ++ firmware reloaded, it won't be possible to get it from userspace. ++ e.g.: ++ - A diskless client with a network card that needs firmware. ++ - The filesystem is stored in a disk behind an scsi device ++ that needs firmware. ++ - Replacing buggy DSDT/SSDT ACPI tables on boot. ++ Note: this would require the persistent objects to be included ++ within the kernel image, probably within initramfs. ++ ++ And the same device can be needed to access the filesystem or not depending ++ on the setup, so I think that the choice on what firmware to make ++ persistent should be left to userspace. ++ ++ - Why register_firmware()+__init can be useful: ++ - For boot devices needing firmware. ++ - To make the transition easier: ++ The firmware can be declared __init and register_firmware() ++ called on module_init. Then the firmware is warranted to be ++ there even if "firmware hotplug userspace" is not there yet or ++ it doesn't yet provide the needed firmware. ++ Once the firmware is widely available in userspace, it can be ++ removed from the kernel. Or made optional (CONFIG_.*_FIRMWARE). ++ ++ In either case, if firmware hotplug support is there, it can move the ++ firmware out of kernel memory into the real filesystem for later ++ usage. ++ ++ Note: If persistence is implemented on top of initramfs, ++ register_firmware() may not be appropriate. +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/drivers/bluetooth/bfusb.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,781 @@ ++/* ++ * ++ * AVM BlueFRITZ! USB driver ++ * ++ * Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org> ++ * ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * 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 <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/types.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/skbuff.h> ++ ++#include <linux/firmware.h> ++#include <linux/usb.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++ ++#ifndef CONFIG_BLUEZ_HCIBFUSB_DEBUG ++#undef BT_DBG ++#define BT_DBG(D...) ++#endif ++ ++#define VERSION "1.1" ++ ++static struct usb_device_id bfusb_table[] = { ++ /* AVM BlueFRITZ! USB */ ++ { USB_DEVICE(0x057c, 0x2200) }, ++ ++ { } /* Terminating entry */ ++}; ++ ++MODULE_DEVICE_TABLE(usb, bfusb_table); ++ ++ ++#define BFUSB_MAX_BLOCK_SIZE 256 ++ ++#define BFUSB_BLOCK_TIMEOUT (HZ * 3) ++ ++#define BFUSB_TX_PROCESS 1 ++#define BFUSB_TX_WAKEUP 2 ++ ++#define BFUSB_MAX_BULK_TX 1 ++#define BFUSB_MAX_BULK_RX 1 ++ ++struct bfusb { ++ struct hci_dev hdev; ++ ++ unsigned long state; ++ ++ struct usb_device *udev; ++ ++ unsigned int bulk_in_ep; ++ unsigned int bulk_out_ep; ++ unsigned int bulk_pkt_size; ++ ++ rwlock_t lock; ++ ++ struct sk_buff_head transmit_q; ++ ++ struct sk_buff *reassembly; ++ ++ atomic_t pending_tx; ++ struct sk_buff_head pending_q; ++ struct sk_buff_head completed_q; ++}; ++ ++struct bfusb_scb { ++ struct urb *urb; ++}; ++ ++static void bfusb_tx_complete(struct urb *urb); ++static void bfusb_rx_complete(struct urb *urb); ++ ++static struct urb *bfusb_get_completed(struct bfusb *bfusb) ++{ ++ struct sk_buff *skb; ++ struct urb *urb = NULL; ++ ++ BT_DBG("bfusb %p", bfusb); ++ ++ skb = skb_dequeue(&bfusb->completed_q); ++ if (skb) { ++ urb = ((struct bfusb_scb *) skb->cb)->urb; ++ kfree_skb(skb); ++ } ++ ++ return urb; ++} ++ ++static inline void bfusb_unlink_urbs(struct bfusb *bfusb) ++{ ++ struct sk_buff *skb; ++ struct urb *urb; ++ ++ BT_DBG("bfusb %p", bfusb); ++ ++ while ((skb = skb_dequeue(&bfusb->pending_q))) { ++ urb = ((struct bfusb_scb *) skb->cb)->urb; ++ usb_unlink_urb(urb); ++ skb_queue_tail(&bfusb->completed_q, skb); ++ } ++ ++ while ((urb = bfusb_get_completed(bfusb))) ++ usb_free_urb(urb); ++} ++ ++ ++static int bfusb_send_bulk(struct bfusb *bfusb, struct sk_buff *skb) ++{ ++ struct bfusb_scb *scb = (void *) skb->cb; ++ struct urb *urb = bfusb_get_completed(bfusb); ++ int err, pipe; ++ ++ BT_DBG("bfusb %p skb %p len %d", bfusb, skb, skb->len); ++ ++ if (!urb && !(urb = usb_alloc_urb(0))) ++ return -ENOMEM; ++ ++ pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep); ++ ++ FILL_BULK_URB(urb, bfusb->udev, pipe, skb->data, skb->len, ++ bfusb_tx_complete, skb); ++ ++ urb->transfer_flags = USB_QUEUE_BULK; ++ ++ scb->urb = urb; ++ ++ skb_queue_tail(&bfusb->pending_q, skb); ++ ++ err = usb_submit_urb(urb); ++ if (err) { ++ BT_ERR("%s bulk tx submit failed urb %p err %d", ++ bfusb->hdev.name, urb, err); ++ skb_unlink(skb); ++ usb_free_urb(urb); ++ } else ++ atomic_inc(&bfusb->pending_tx); ++ ++ return err; ++} ++ ++static void bfusb_tx_wakeup(struct bfusb *bfusb) ++{ ++ struct sk_buff *skb; ++ ++ BT_DBG("bfusb %p", bfusb); ++ ++ if (test_and_set_bit(BFUSB_TX_PROCESS, &bfusb->state)) { ++ set_bit(BFUSB_TX_WAKEUP, &bfusb->state); ++ return; ++ } ++ ++ do { ++ clear_bit(BFUSB_TX_WAKEUP, &bfusb->state); ++ ++ while ((atomic_read(&bfusb->pending_tx) < BFUSB_MAX_BULK_TX) && ++ (skb = skb_dequeue(&bfusb->transmit_q))) { ++ if (bfusb_send_bulk(bfusb, skb) < 0) { ++ skb_queue_head(&bfusb->transmit_q, skb); ++ break; ++ } ++ } ++ ++ } while (test_bit(BFUSB_TX_WAKEUP, &bfusb->state)); ++ ++ clear_bit(BFUSB_TX_PROCESS, &bfusb->state); ++} ++ ++static void bfusb_tx_complete(struct urb *urb) ++{ ++ struct sk_buff *skb = (struct sk_buff *) urb->context; ++ struct bfusb *bfusb = (struct bfusb *) skb->dev; ++ ++ BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len); ++ ++ atomic_dec(&bfusb->pending_tx); ++ ++ if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags)) ++ return; ++ ++ if (!urb->status) ++ bfusb->hdev.stat.byte_tx += skb->len; ++ else ++ bfusb->hdev.stat.err_tx++; ++ ++ read_lock(&bfusb->lock); ++ ++ skb_unlink(skb); ++ skb_queue_tail(&bfusb->completed_q, skb); ++ ++ bfusb_tx_wakeup(bfusb); ++ ++ read_unlock(&bfusb->lock); ++} ++ ++ ++static int bfusb_rx_submit(struct bfusb *bfusb, struct urb *urb) ++{ ++ struct bfusb_scb *scb; ++ struct sk_buff *skb; ++ int err, pipe, size = HCI_MAX_FRAME_SIZE + 32; ++ ++ BT_DBG("bfusb %p urb %p", bfusb, urb); ++ ++ if (!urb && !(urb = usb_alloc_urb(0))) ++ return -ENOMEM; ++ ++ if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) { ++ usb_free_urb(urb); ++ return -ENOMEM; ++ } ++ ++ skb->dev = (void *) bfusb; ++ ++ scb = (struct bfusb_scb *) skb->cb; ++ scb->urb = urb; ++ ++ pipe = usb_rcvbulkpipe(bfusb->udev, bfusb->bulk_in_ep); ++ ++ FILL_BULK_URB(urb, bfusb->udev, pipe, skb->data, size, ++ bfusb_rx_complete, skb); ++ ++ urb->transfer_flags = USB_QUEUE_BULK; ++ ++ skb_queue_tail(&bfusb->pending_q, skb); ++ ++ err = usb_submit_urb(urb); ++ if (err) { ++ BT_ERR("%s bulk rx submit failed urb %p err %d", ++ bfusb->hdev.name, urb, err); ++ skb_unlink(skb); ++ kfree_skb(skb); ++ usb_free_urb(urb); ++ } ++ ++ return err; ++} ++ ++static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *data, int len) ++{ ++ BT_DBG("bfusb %p hdr 0x%02x data %p len %d", bfusb, hdr, data, len); ++ ++ if (hdr & 0x10) { ++ BT_ERR("%s error in block", bfusb->hdev.name); ++ if (bfusb->reassembly) ++ kfree_skb(bfusb->reassembly); ++ bfusb->reassembly = NULL; ++ return -EIO; ++ } ++ ++ if (hdr & 0x04) { ++ struct sk_buff *skb; ++ unsigned char pkt_type; ++ int pkt_len = 0; ++ ++ if (bfusb->reassembly) { ++ BT_ERR("%s unexpected start block", bfusb->hdev.name); ++ kfree_skb(bfusb->reassembly); ++ bfusb->reassembly = NULL; ++ } ++ ++ if (len < 1) { ++ BT_ERR("%s no packet type found", bfusb->hdev.name); ++ return -EPROTO; ++ } ++ ++ pkt_type = *data++; len--; ++ ++ switch (pkt_type) { ++ case HCI_EVENT_PKT: ++ if (len >= HCI_EVENT_HDR_SIZE) { ++ hci_event_hdr *hdr = (hci_event_hdr *) data; ++ pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen; ++ } else { ++ BT_ERR("%s event block is too short", bfusb->hdev.name); ++ return -EILSEQ; ++ } ++ break; ++ ++ case HCI_ACLDATA_PKT: ++ if (len >= HCI_ACL_HDR_SIZE) { ++ hci_acl_hdr *hdr = (hci_acl_hdr *) data; ++ pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen); ++ } else { ++ BT_ERR("%s data block is too short", bfusb->hdev.name); ++ return -EILSEQ; ++ } ++ break; ++ ++ case HCI_SCODATA_PKT: ++ if (len >= HCI_SCO_HDR_SIZE) { ++ hci_sco_hdr *hdr = (hci_sco_hdr *) data; ++ pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen; ++ } else { ++ BT_ERR("%s audio block is too short", bfusb->hdev.name); ++ return -EILSEQ; ++ } ++ break; ++ } ++ ++ skb = bluez_skb_alloc(pkt_len, GFP_ATOMIC); ++ if (!skb) { ++ BT_ERR("%s no memory for the packet", bfusb->hdev.name); ++ return -ENOMEM; ++ } ++ ++ skb->dev = (void *) &bfusb->hdev; ++ skb->pkt_type = pkt_type; ++ ++ bfusb->reassembly = skb; ++ } else { ++ if (!bfusb->reassembly) { ++ BT_ERR("%s unexpected continuation block", bfusb->hdev.name); ++ return -EIO; ++ } ++ } ++ ++ if (len > 0) ++ memcpy(skb_put(bfusb->reassembly, len), data, len); ++ ++ if (hdr & 0x08) { ++ hci_recv_frame(bfusb->reassembly); ++ bfusb->reassembly = NULL; ++ } ++ ++ return 0; ++} ++ ++static void bfusb_rx_complete(struct urb *urb) ++{ ++ struct sk_buff *skb = (struct sk_buff *) urb->context; ++ struct bfusb *bfusb = (struct bfusb *) skb->dev; ++ unsigned char *buf = urb->transfer_buffer; ++ int count = urb->actual_length; ++ int err, hdr, len; ++ ++ BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len); ++ ++ if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags)) ++ return; ++ ++ read_lock(&bfusb->lock); ++ ++ if (urb->status || !count) ++ goto resubmit; ++ ++ bfusb->hdev.stat.byte_rx += count; ++ ++ skb_put(skb, count); ++ ++ while (count) { ++ hdr = buf[0] | (buf[1] << 8); ++ ++ if (hdr & 0x4000) { ++ len = 0; ++ count -= 2; ++ buf += 2; ++ } else { ++ len = (buf[2] == 0) ? 256 : buf[2]; ++ count -= 3; ++ buf += 3; ++ } ++ ++ if (count < len) { ++ BT_ERR("%s block extends over URB buffer ranges", ++ bfusb->hdev.name); ++ } ++ ++ if ((hdr & 0xe1) == 0xc1) ++ bfusb_recv_block(bfusb, hdr, buf, len); ++ ++ count -= len; ++ buf += len; ++ } ++ ++ skb_unlink(skb); ++ kfree_skb(skb); ++ ++ bfusb_rx_submit(bfusb, urb); ++ ++ read_unlock(&bfusb->lock); ++ ++ return; ++ ++resubmit: ++ urb->dev = bfusb->udev; ++ ++ err = usb_submit_urb(urb); ++ if (err) { ++ BT_ERR("%s bulk resubmit failed urb %p err %d", ++ bfusb->hdev.name, urb, err); ++ } ++ ++ read_unlock(&bfusb->lock); ++} ++ ++ ++static int bfusb_open(struct hci_dev *hdev) ++{ ++ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data; ++ unsigned long flags; ++ int i, err; ++ ++ BT_DBG("hdev %p bfusb %p", hdev, bfusb); ++ ++ if (test_and_set_bit(HCI_RUNNING, &hdev->flags)) ++ return 0; ++ ++ MOD_INC_USE_COUNT; ++ ++ write_lock_irqsave(&bfusb->lock, flags); ++ ++ err = bfusb_rx_submit(bfusb, NULL); ++ if (!err) { ++ for (i = 1; i < BFUSB_MAX_BULK_RX; i++) ++ bfusb_rx_submit(bfusb, NULL); ++ } else { ++ clear_bit(HCI_RUNNING, &hdev->flags); ++ MOD_DEC_USE_COUNT; ++ } ++ ++ write_unlock_irqrestore(&bfusb->lock, flags); ++ ++ return err; ++} ++ ++static int bfusb_flush(struct hci_dev *hdev) ++{ ++ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data; ++ ++ BT_DBG("hdev %p bfusb %p", hdev, bfusb); ++ ++ skb_queue_purge(&bfusb->transmit_q); ++ ++ return 0; ++} ++ ++static int bfusb_close(struct hci_dev *hdev) ++{ ++ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data; ++ unsigned long flags; ++ ++ BT_DBG("hdev %p bfusb %p", hdev, bfusb); ++ ++ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) ++ return 0; ++ ++ write_lock_irqsave(&bfusb->lock, flags); ++ ++ bfusb_unlink_urbs(bfusb); ++ bfusb_flush(hdev); ++ ++ write_unlock_irqrestore(&bfusb->lock, flags); ++ ++ MOD_DEC_USE_COUNT; ++ ++ return 0; ++} ++ ++static int bfusb_send_frame(struct sk_buff *skb) ++{ ++ struct hci_dev *hdev = (struct hci_dev *) skb->dev; ++ struct bfusb *bfusb; ++ struct sk_buff *nskb; ++ unsigned char buf[3]; ++ int sent = 0, size, count; ++ ++ BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, skb->pkt_type, skb->len); ++ ++ if (!hdev) { ++ BT_ERR("Frame for unknown HCI device (hdev=NULL)"); ++ return -ENODEV; ++ } ++ ++ if (!test_bit(HCI_RUNNING, &hdev->flags)) ++ return -EBUSY; ++ ++ bfusb = (struct bfusb *) hdev->driver_data; ++ ++ switch (skb->pkt_type) { ++ case HCI_COMMAND_PKT: ++ hdev->stat.cmd_tx++; ++ break; ++ case HCI_ACLDATA_PKT: ++ hdev->stat.acl_tx++; ++ break; ++ case HCI_SCODATA_PKT: ++ hdev->stat.sco_tx++; ++ break; ++ }; ++ ++ /* Prepend skb with frame type */ ++ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); ++ ++ count = skb->len; ++ ++ /* Max HCI frame size seems to be 1511 + 1 */ ++ if (!(nskb = bluez_skb_alloc(count + 32, GFP_ATOMIC))) { ++ BT_ERR("Can't allocate memory for new packet"); ++ return -ENOMEM; ++ } ++ ++ nskb->dev = (void *) bfusb; ++ ++ while (count) { ++ size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE); ++ ++ buf[0] = 0xc1 | ((sent == 0) ? 0x04 : 0) | ((count == size) ? 0x08 : 0); ++ buf[1] = 0x00; ++ buf[2] = (size == BFUSB_MAX_BLOCK_SIZE) ? 0 : size; ++ ++ memcpy(skb_put(nskb, 3), buf, 3); ++ memcpy(skb_put(nskb, size), skb->data + sent, size); ++ ++ sent += size; ++ count -= size; ++ } ++ ++ /* Don't send frame with multiple size of bulk max packet */ ++ if ((nskb->len % bfusb->bulk_pkt_size) == 0) { ++ buf[0] = 0xdd; ++ buf[1] = 0x00; ++ memcpy(skb_put(nskb, 2), buf, 2); ++ } ++ ++ read_lock(&bfusb->lock); ++ ++ skb_queue_tail(&bfusb->transmit_q, nskb); ++ bfusb_tx_wakeup(bfusb); ++ ++ read_unlock(&bfusb->lock); ++ ++ kfree_skb(skb); ++ ++ return 0; ++} ++ ++static void bfusb_destruct(struct hci_dev *hdev) ++{ ++ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data; ++ ++ BT_DBG("hdev %p bfusb %p", hdev, bfusb); ++ ++ kfree(bfusb); ++} ++ ++static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) ++{ ++ return -ENOIOCTLCMD; ++} ++ ++ ++static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int count) ++{ ++ unsigned char *buf; ++ int err, pipe, len, size, sent = 0; ++ ++ BT_DBG("bfusb %p udev %p firmware %p count %d", bfusb, bfusb->udev, firmware, count); ++ ++ BT_INFO("BlueFRITZ! USB loading firmware"); ++ ++ if (usb_set_configuration(bfusb->udev, 1) < 0) { ++ BT_ERR("Can't change to loading configuration"); ++ return -EBUSY; ++ } ++ ++ buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_ATOMIC); ++ if (!buf) { ++ BT_ERR("Can't allocate memory chunk for firmware"); ++ return -ENOMEM; ++ } ++ ++ pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep); ++ ++ while (count) { ++ size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE + 3); ++ ++ memcpy(buf, firmware + sent, size); ++ ++ err = usb_bulk_msg(bfusb->udev, pipe, buf, size, ++ &len, BFUSB_BLOCK_TIMEOUT); ++ ++ if (err || (len != size)) { ++ BT_ERR("Error in firmware loading"); ++ goto error; ++ } ++ ++ sent += size; ++ count -= size; ++ } ++ ++ if ((err = usb_bulk_msg(bfusb->udev, pipe, NULL, 0, ++ &len, BFUSB_BLOCK_TIMEOUT)) < 0) { ++ BT_ERR("Error in null packet request"); ++ goto error; ++ } ++ ++ if ((err = usb_set_configuration(bfusb->udev, 2)) < 0) { ++ BT_ERR("Can't change to running configuration"); ++ goto error; ++ } ++ ++ BT_INFO("BlueFRITZ! USB device ready"); ++ ++ kfree(buf); ++ return 0; ++ ++error: ++ kfree(buf); ++ ++ pipe = usb_sndctrlpipe(bfusb->udev, 0); ++ ++ usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION, ++ 0, 0, 0, NULL, 0, BFUSB_BLOCK_TIMEOUT); ++ ++ return err; ++} ++ ++static void *bfusb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id) ++{ ++ const struct firmware *firmware; ++ char device[16]; ++ struct usb_interface *iface; ++ struct usb_interface_descriptor *iface_desc; ++ struct usb_endpoint_descriptor *bulk_out_ep; ++ struct usb_endpoint_descriptor *bulk_in_ep; ++ struct hci_dev *hdev; ++ struct bfusb *bfusb; ++ ++ BT_DBG("udev %p ifnum %d id %p", udev, ifnum, id); ++ ++ /* Check number of endpoints */ ++ iface = &udev->actconfig->interface[0]; ++ iface_desc = &iface->altsetting[0]; ++ ++ if (iface_desc->bNumEndpoints < 2) ++ return NULL; ++ ++ bulk_out_ep = &iface_desc->endpoint[0]; ++ bulk_in_ep = &iface_desc->endpoint[1]; ++ ++ if (!bulk_out_ep || !bulk_in_ep) { ++ BT_ERR("Bulk endpoints not found"); ++ goto done; ++ } ++ ++ /* Initialize control structure and load firmware */ ++ if (!(bfusb = kmalloc(sizeof(struct bfusb), GFP_KERNEL))) { ++ BT_ERR("Can't allocate memory for control structure"); ++ goto done; ++ } ++ ++ memset(bfusb, 0, sizeof(struct bfusb)); ++ ++ bfusb->udev = udev; ++ bfusb->bulk_in_ep = bulk_in_ep->bEndpointAddress; ++ bfusb->bulk_out_ep = bulk_out_ep->bEndpointAddress; ++ bfusb->bulk_pkt_size = bulk_out_ep->wMaxPacketSize; ++ ++ bfusb->lock = RW_LOCK_UNLOCKED; ++ ++ bfusb->reassembly = NULL; ++ ++ skb_queue_head_init(&bfusb->transmit_q); ++ skb_queue_head_init(&bfusb->pending_q); ++ skb_queue_head_init(&bfusb->completed_q); ++ ++ snprintf(device, sizeof(device), "bfusb%3.3d%3.3d", udev->bus->busnum, udev->devnum); ++ ++ if (request_firmware(&firmware, "bfubase.frm", device) < 0) { ++ BT_ERR("Firmware request failed"); ++ goto error; ++ } ++ ++ if (bfusb_load_firmware(bfusb, firmware->data, firmware->size) < 0) { ++ BT_ERR("Firmware loading failed"); ++ goto release; ++ } ++ ++ release_firmware(firmware); ++ ++ /* Initialize and register HCI device */ ++ hdev = &bfusb->hdev; ++ ++ hdev->type = HCI_USB; ++ hdev->driver_data = bfusb; ++ ++ hdev->open = bfusb_open; ++ hdev->close = bfusb_close; ++ hdev->flush = bfusb_flush; ++ hdev->send = bfusb_send_frame; ++ hdev->destruct = bfusb_destruct; ++ hdev->ioctl = bfusb_ioctl; ++ ++ if (hci_register_dev(hdev) < 0) { ++ BT_ERR("Can't register HCI device"); ++ goto error; ++ } ++ ++ return bfusb; ++ ++release: ++ release_firmware(firmware); ++ ++error: ++ kfree(bfusb); ++ ++done: ++ return NULL; ++} ++ ++static void bfusb_disconnect(struct usb_device *udev, void *ptr) ++{ ++ struct bfusb *bfusb = (struct bfusb *) ptr; ++ struct hci_dev *hdev = &bfusb->hdev; ++ ++ BT_DBG("udev %p ptr %p", udev, ptr); ++ ++ if (!hdev) ++ return; ++ ++ bfusb_close(hdev); ++ ++ if (hci_unregister_dev(hdev) < 0) ++ BT_ERR("Can't unregister HCI device %s", hdev->name); ++} ++ ++static struct usb_driver bfusb_driver = { ++ name: "bfusb", ++ probe: bfusb_probe, ++ disconnect: bfusb_disconnect, ++ id_table: bfusb_table, ++}; ++ ++static int __init bfusb_init(void) ++{ ++ int err; ++ ++ BT_INFO("BlueFRITZ! USB driver ver %s", VERSION); ++ BT_INFO("Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org>"); ++ ++ if ((err = usb_register(&bfusb_driver)) < 0) ++ BT_ERR("Failed to register BlueFRITZ! USB driver"); ++ ++ return err; ++} ++ ++static void __exit bfusb_cleanup(void) ++{ ++ usb_deregister(&bfusb_driver); ++} ++ ++module_init(bfusb_init); ++module_exit(bfusb_cleanup); ++ ++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); ++MODULE_DESCRIPTION("BlueFRITZ! USB driver ver " VERSION); ++MODULE_LICENSE("GPL"); +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/drivers/bluetooth/bluecard_cs.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,1113 @@ ++/* ++ * ++ * Bluetooth driver for the Anycom BlueCard (LSE039/LSE041) ++ * ++ * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org> ++ * ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation; ++ * ++ * Software distributed under the License is distributed on an "AS ++ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++ * implied. See the License for the specific language governing ++ * rights and limitations under the License. ++ * ++ * The initial developer of the original code is David A. Hinds ++ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds ++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/types.h> ++#include <linux/sched.h> ++#include <linux/timer.h> ++#include <linux/errno.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/spinlock.h> ++#include <linux/skbuff.h> ++#include <asm/io.h> ++ ++#include <pcmcia/version.h> ++#include <pcmcia/cs_types.h> ++#include <pcmcia/cs.h> ++#include <pcmcia/cistpl.h> ++#include <pcmcia/ciscode.h> ++#include <pcmcia/ds.h> ++#include <pcmcia/cisreg.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++ ++ ++ ++/* ======================== Module parameters ======================== */ ++ ++ ++/* Bit map of interrupts to choose from */ ++static u_int irq_mask = 0x86bc; ++static int irq_list[4] = { -1 }; ++ ++MODULE_PARM(irq_mask, "i"); ++MODULE_PARM(irq_list, "1-4i"); ++ ++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); ++MODULE_DESCRIPTION("BlueZ driver for the Anycom BlueCard (LSE039/LSE041)"); ++MODULE_LICENSE("GPL"); ++ ++ ++ ++/* ======================== Local structures ======================== */ ++ ++ ++typedef struct bluecard_info_t { ++ dev_link_t link; ++ dev_node_t node; ++ ++ struct hci_dev hdev; ++ ++ spinlock_t lock; /* For serializing operations */ ++ struct timer_list timer; /* For LED control */ ++ ++ struct sk_buff_head txq; ++ unsigned long tx_state; ++ ++ unsigned long rx_state; ++ unsigned long rx_count; ++ struct sk_buff *rx_skb; ++ ++ unsigned char ctrl_reg; ++ unsigned long hw_state; /* Status of the hardware and LED control */ ++} bluecard_info_t; ++ ++ ++void bluecard_config(dev_link_t *link); ++void bluecard_release(u_long arg); ++int bluecard_event(event_t event, int priority, event_callback_args_t *args); ++ ++static dev_info_t dev_info = "bluecard_cs"; ++ ++dev_link_t *bluecard_attach(void); ++void bluecard_detach(dev_link_t *); ++ ++static dev_link_t *dev_list = NULL; ++ ++ ++/* Default baud rate: 57600, 115200, 230400 or 460800 */ ++#define DEFAULT_BAUD_RATE 230400 ++ ++ ++/* Hardware states */ ++#define CARD_READY 1 ++#define CARD_HAS_PCCARD_ID 4 ++#define CARD_HAS_POWER_LED 5 ++#define CARD_HAS_ACTIVITY_LED 6 ++ ++/* Transmit states */ ++#define XMIT_SENDING 1 ++#define XMIT_WAKEUP 2 ++#define XMIT_BUFFER_NUMBER 5 /* unset = buffer one, set = buffer two */ ++#define XMIT_BUF_ONE_READY 6 ++#define XMIT_BUF_TWO_READY 7 ++#define XMIT_SENDING_READY 8 ++ ++/* Receiver states */ ++#define RECV_WAIT_PACKET_TYPE 0 ++#define RECV_WAIT_EVENT_HEADER 1 ++#define RECV_WAIT_ACL_HEADER 2 ++#define RECV_WAIT_SCO_HEADER 3 ++#define RECV_WAIT_DATA 4 ++ ++/* Special packet types */ ++#define PKT_BAUD_RATE_57600 0x80 ++#define PKT_BAUD_RATE_115200 0x81 ++#define PKT_BAUD_RATE_230400 0x82 ++#define PKT_BAUD_RATE_460800 0x83 ++ ++ ++/* These are the register offsets */ ++#define REG_COMMAND 0x20 ++#define REG_INTERRUPT 0x21 ++#define REG_CONTROL 0x22 ++#define REG_RX_CONTROL 0x24 ++#define REG_CARD_RESET 0x30 ++#define REG_LED_CTRL 0x30 ++ ++/* REG_COMMAND */ ++#define REG_COMMAND_TX_BUF_ONE 0x01 ++#define REG_COMMAND_TX_BUF_TWO 0x02 ++#define REG_COMMAND_RX_BUF_ONE 0x04 ++#define REG_COMMAND_RX_BUF_TWO 0x08 ++#define REG_COMMAND_RX_WIN_ONE 0x00 ++#define REG_COMMAND_RX_WIN_TWO 0x10 ++ ++/* REG_CONTROL */ ++#define REG_CONTROL_BAUD_RATE_57600 0x00 ++#define REG_CONTROL_BAUD_RATE_115200 0x01 ++#define REG_CONTROL_BAUD_RATE_230400 0x02 ++#define REG_CONTROL_BAUD_RATE_460800 0x03 ++#define REG_CONTROL_RTS 0x04 ++#define REG_CONTROL_BT_ON 0x08 ++#define REG_CONTROL_BT_RESET 0x10 ++#define REG_CONTROL_BT_RES_PU 0x20 ++#define REG_CONTROL_INTERRUPT 0x40 ++#define REG_CONTROL_CARD_RESET 0x80 ++ ++/* REG_RX_CONTROL */ ++#define RTS_LEVEL_SHIFT_BITS 0x02 ++ ++ ++ ++/* ======================== LED handling routines ======================== */ ++ ++ ++void bluecard_activity_led_timeout(u_long arg) ++{ ++ bluecard_info_t *info = (bluecard_info_t *)arg; ++ unsigned int iobase = info->link.io.BasePort1; ++ ++ if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) { ++ /* Disable activity LED */ ++ outb(0x08 | 0x20, iobase + 0x30); ++ } else { ++ /* Disable power LED */ ++ outb(0x00, iobase + 0x30); ++ } ++} ++ ++ ++static void bluecard_enable_activity_led(bluecard_info_t *info) ++{ ++ unsigned int iobase = info->link.io.BasePort1; ++ ++ if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) { ++ /* Enable activity LED */ ++ outb(0x10 | 0x40, iobase + 0x30); ++ ++ /* Stop the LED after HZ/4 */ ++ mod_timer(&(info->timer), jiffies + HZ / 4); ++ } else { ++ /* Enable power LED */ ++ outb(0x08 | 0x20, iobase + 0x30); ++ ++ /* Stop the LED after HZ/2 */ ++ mod_timer(&(info->timer), jiffies + HZ / 2); ++ } ++} ++ ++ ++ ++/* ======================== Interrupt handling ======================== */ ++ ++ ++static int bluecard_write(unsigned int iobase, unsigned int offset, __u8 *buf, int len) ++{ ++ int i, actual; ++ ++ actual = (len > 15) ? 15 : len; ++ ++ outb_p(actual, iobase + offset); ++ ++ for (i = 0; i < actual; i++) ++ outb_p(buf[i], iobase + offset + i + 1); ++ ++ return actual; ++} ++ ++ ++static void bluecard_write_wakeup(bluecard_info_t *info) ++{ ++ if (!info) { ++ printk(KERN_WARNING "bluecard_cs: Call of write_wakeup for unknown device.\n"); ++ return; ++ } ++ ++ if (!test_bit(XMIT_SENDING_READY, &(info->tx_state))) ++ return; ++ ++ if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { ++ set_bit(XMIT_WAKEUP, &(info->tx_state)); ++ return; ++ } ++ ++ do { ++ register unsigned int iobase = info->link.io.BasePort1; ++ register unsigned int offset; ++ register unsigned char command; ++ register unsigned long ready_bit; ++ register struct sk_buff *skb; ++ register int len; ++ ++ clear_bit(XMIT_WAKEUP, &(info->tx_state)); ++ ++ if (!(info->link.state & DEV_PRESENT)) ++ return; ++ ++ if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) { ++ if (!test_bit(XMIT_BUF_TWO_READY, &(info->tx_state))) ++ break; ++ offset = 0x10; ++ command = REG_COMMAND_TX_BUF_TWO; ++ ready_bit = XMIT_BUF_TWO_READY; ++ } else { ++ if (!test_bit(XMIT_BUF_ONE_READY, &(info->tx_state))) ++ break; ++ offset = 0x00; ++ command = REG_COMMAND_TX_BUF_ONE; ++ ready_bit = XMIT_BUF_ONE_READY; ++ } ++ ++ if (!(skb = skb_dequeue(&(info->txq)))) ++ break; ++ ++ if (skb->pkt_type & 0x80) { ++ /* Disable RTS */ ++ info->ctrl_reg |= REG_CONTROL_RTS; ++ outb(info->ctrl_reg, iobase + REG_CONTROL); ++ } ++ ++ /* Activate LED */ ++ bluecard_enable_activity_led(info); ++ ++ /* Send frame */ ++ len = bluecard_write(iobase, offset, skb->data, skb->len); ++ ++ /* Tell the FPGA to send the data */ ++ outb_p(command, iobase + REG_COMMAND); ++ ++ /* Mark the buffer as dirty */ ++ clear_bit(ready_bit, &(info->tx_state)); ++ ++ if (skb->pkt_type & 0x80) { ++ ++ wait_queue_head_t wait; ++ unsigned char baud_reg; ++ ++ switch (skb->pkt_type) { ++ case PKT_BAUD_RATE_460800: ++ baud_reg = REG_CONTROL_BAUD_RATE_460800; ++ break; ++ case PKT_BAUD_RATE_230400: ++ baud_reg = REG_CONTROL_BAUD_RATE_230400; ++ break; ++ case PKT_BAUD_RATE_115200: ++ baud_reg = REG_CONTROL_BAUD_RATE_115200; ++ break; ++ case PKT_BAUD_RATE_57600: ++ /* Fall through... */ ++ default: ++ baud_reg = REG_CONTROL_BAUD_RATE_57600; ++ break; ++ } ++ ++ /* Wait until the command reaches the baseband */ ++ init_waitqueue_head(&wait); ++ interruptible_sleep_on_timeout(&wait, HZ / 10); ++ ++ /* Set baud on baseband */ ++ info->ctrl_reg &= ~0x03; ++ info->ctrl_reg |= baud_reg; ++ outb(info->ctrl_reg, iobase + REG_CONTROL); ++ ++ /* Enable RTS */ ++ info->ctrl_reg &= ~REG_CONTROL_RTS; ++ outb(info->ctrl_reg, iobase + REG_CONTROL); ++ ++ /* Wait before the next HCI packet can be send */ ++ interruptible_sleep_on_timeout(&wait, HZ); ++ ++ } ++ ++ if (len == skb->len) { ++ kfree_skb(skb); ++ } else { ++ skb_pull(skb, len); ++ skb_queue_head(&(info->txq), skb); ++ } ++ ++ info->hdev.stat.byte_tx += len; ++ ++ /* Change buffer */ ++ change_bit(XMIT_BUFFER_NUMBER, &(info->tx_state)); ++ ++ } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); ++ ++ clear_bit(XMIT_SENDING, &(info->tx_state)); ++} ++ ++ ++static int bluecard_read(unsigned int iobase, unsigned int offset, __u8 *buf, int size) ++{ ++ int i, n, len; ++ ++ outb(REG_COMMAND_RX_WIN_ONE, iobase + REG_COMMAND); ++ ++ len = inb(iobase + offset); ++ n = 0; ++ i = 1; ++ ++ while (n < len) { ++ ++ if (i == 16) { ++ outb(REG_COMMAND_RX_WIN_TWO, iobase + REG_COMMAND); ++ i = 0; ++ } ++ ++ buf[n] = inb(iobase + offset + i); ++ ++ n++; ++ i++; ++ ++ } ++ ++ return len; ++} ++ ++ ++static void bluecard_receive(bluecard_info_t *info, unsigned int offset) ++{ ++ unsigned int iobase; ++ unsigned char buf[31]; ++ int i, len; ++ ++ if (!info) { ++ printk(KERN_WARNING "bluecard_cs: Call of receive for unknown device.\n"); ++ return; ++ } ++ ++ iobase = info->link.io.BasePort1; ++ ++ if (test_bit(XMIT_SENDING_READY, &(info->tx_state))) ++ bluecard_enable_activity_led(info); ++ ++ len = bluecard_read(iobase, offset, buf, sizeof(buf)); ++ ++ for (i = 0; i < len; i++) { ++ ++ /* Allocate packet */ ++ if (info->rx_skb == NULL) { ++ info->rx_state = RECV_WAIT_PACKET_TYPE; ++ info->rx_count = 0; ++ if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { ++ printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n"); ++ return; ++ } ++ } ++ ++ if (info->rx_state == RECV_WAIT_PACKET_TYPE) { ++ ++ info->rx_skb->dev = (void *)&(info->hdev); ++ info->rx_skb->pkt_type = buf[i]; ++ ++ switch (info->rx_skb->pkt_type) { ++ ++ case 0x00: ++ /* init packet */ ++ if (offset != 0x00) { ++ set_bit(XMIT_BUF_ONE_READY, &(info->tx_state)); ++ set_bit(XMIT_BUF_TWO_READY, &(info->tx_state)); ++ set_bit(XMIT_SENDING_READY, &(info->tx_state)); ++ bluecard_write_wakeup(info); ++ } ++ ++ kfree_skb(info->rx_skb); ++ info->rx_skb = NULL; ++ break; ++ ++ case HCI_EVENT_PKT: ++ info->rx_state = RECV_WAIT_EVENT_HEADER; ++ info->rx_count = HCI_EVENT_HDR_SIZE; ++ break; ++ ++ case HCI_ACLDATA_PKT: ++ info->rx_state = RECV_WAIT_ACL_HEADER; ++ info->rx_count = HCI_ACL_HDR_SIZE; ++ break; ++ ++ case HCI_SCODATA_PKT: ++ info->rx_state = RECV_WAIT_SCO_HEADER; ++ info->rx_count = HCI_SCO_HDR_SIZE; ++ break; ++ ++ default: ++ /* unknown packet */ ++ printk(KERN_WARNING "bluecard_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type); ++ info->hdev.stat.err_rx++; ++ ++ kfree_skb(info->rx_skb); ++ info->rx_skb = NULL; ++ break; ++ ++ } ++ ++ } else { ++ ++ *skb_put(info->rx_skb, 1) = buf[i]; ++ info->rx_count--; ++ ++ if (info->rx_count == 0) { ++ ++ int dlen; ++ hci_event_hdr *eh; ++ hci_acl_hdr *ah; ++ hci_sco_hdr *sh; ++ ++ switch (info->rx_state) { ++ ++ case RECV_WAIT_EVENT_HEADER: ++ eh = (hci_event_hdr *)(info->rx_skb->data); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = eh->plen; ++ break; ++ ++ case RECV_WAIT_ACL_HEADER: ++ ah = (hci_acl_hdr *)(info->rx_skb->data); ++ dlen = __le16_to_cpu(ah->dlen); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = dlen; ++ break; ++ ++ case RECV_WAIT_SCO_HEADER: ++ sh = (hci_sco_hdr *)(info->rx_skb->data); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = sh->dlen; ++ break; ++ ++ case RECV_WAIT_DATA: ++ hci_recv_frame(info->rx_skb); ++ info->rx_skb = NULL; ++ break; ++ ++ } ++ ++ } ++ ++ } ++ ++ ++ } ++ ++ info->hdev.stat.byte_rx += len; ++} ++ ++ ++void bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs) ++{ ++ bluecard_info_t *info = dev_inst; ++ unsigned int iobase; ++ unsigned char reg; ++ ++ if (!info) { ++ printk(KERN_WARNING "bluecard_cs: Call of irq %d for unknown device.\n", irq); ++ return; ++ } ++ ++ if (!test_bit(CARD_READY, &(info->hw_state))) ++ return; ++ ++ iobase = info->link.io.BasePort1; ++ ++ spin_lock(&(info->lock)); ++ ++ /* Disable interrupt */ ++ info->ctrl_reg &= ~REG_CONTROL_INTERRUPT; ++ outb(info->ctrl_reg, iobase + REG_CONTROL); ++ ++ reg = inb(iobase + REG_INTERRUPT); ++ ++ if ((reg != 0x00) && (reg != 0xff)) { ++ ++ if (reg & 0x04) { ++ bluecard_receive(info, 0x00); ++ outb(0x04, iobase + REG_INTERRUPT); ++ outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND); ++ } ++ ++ if (reg & 0x08) { ++ bluecard_receive(info, 0x10); ++ outb(0x08, iobase + REG_INTERRUPT); ++ outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND); ++ } ++ ++ if (reg & 0x01) { ++ set_bit(XMIT_BUF_ONE_READY, &(info->tx_state)); ++ outb(0x01, iobase + REG_INTERRUPT); ++ bluecard_write_wakeup(info); ++ } ++ ++ if (reg & 0x02) { ++ set_bit(XMIT_BUF_TWO_READY, &(info->tx_state)); ++ outb(0x02, iobase + REG_INTERRUPT); ++ bluecard_write_wakeup(info); ++ } ++ ++ } ++ ++ /* Enable interrupt */ ++ info->ctrl_reg |= REG_CONTROL_INTERRUPT; ++ outb(info->ctrl_reg, iobase + REG_CONTROL); ++ ++ spin_unlock(&(info->lock)); ++} ++ ++ ++ ++/* ======================== Device specific HCI commands ======================== */ ++ ++ ++static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud) ++{ ++ bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data); ++ struct sk_buff *skb; ++ ++ /* Ericsson baud rate command */ ++ unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 }; ++ ++ if (!(skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { ++ printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n"); ++ return -1; ++ } ++ ++ switch (baud) { ++ case 460800: ++ cmd[4] = 0x00; ++ skb->pkt_type = PKT_BAUD_RATE_460800; ++ break; ++ case 230400: ++ cmd[4] = 0x01; ++ skb->pkt_type = PKT_BAUD_RATE_230400; ++ break; ++ case 115200: ++ cmd[4] = 0x02; ++ skb->pkt_type = PKT_BAUD_RATE_115200; ++ break; ++ case 57600: ++ /* Fall through... */ ++ default: ++ cmd[4] = 0x03; ++ skb->pkt_type = PKT_BAUD_RATE_57600; ++ break; ++ } ++ ++ memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd)); ++ ++ skb_queue_tail(&(info->txq), skb); ++ ++ bluecard_write_wakeup(info); ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== HCI interface ======================== */ ++ ++ ++static int bluecard_hci_flush(struct hci_dev *hdev) ++{ ++ bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data); ++ ++ /* Drop TX queue */ ++ skb_queue_purge(&(info->txq)); ++ ++ return 0; ++} ++ ++ ++static int bluecard_hci_open(struct hci_dev *hdev) ++{ ++ bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data); ++ unsigned int iobase = info->link.io.BasePort1; ++ ++ bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE); ++ ++ if (test_and_set_bit(HCI_RUNNING, &(hdev->flags))) ++ return 0; ++ ++ /* Enable LED */ ++ outb(0x08 | 0x20, iobase + 0x30); ++ ++ return 0; ++} ++ ++ ++static int bluecard_hci_close(struct hci_dev *hdev) ++{ ++ bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data); ++ unsigned int iobase = info->link.io.BasePort1; ++ ++ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) ++ return 0; ++ ++ bluecard_hci_flush(hdev); ++ ++ /* Disable LED */ ++ outb(0x00, iobase + 0x30); ++ ++ return 0; ++} ++ ++ ++static int bluecard_hci_send_frame(struct sk_buff *skb) ++{ ++ bluecard_info_t *info; ++ struct hci_dev *hdev = (struct hci_dev *)(skb->dev); ++ ++ if (!hdev) { ++ printk(KERN_WARNING "bluecard_cs: Frame for unknown HCI device (hdev=NULL)."); ++ return -ENODEV; ++ } ++ ++ info = (bluecard_info_t *)(hdev->driver_data); ++ ++ switch (skb->pkt_type) { ++ case HCI_COMMAND_PKT: ++ hdev->stat.cmd_tx++; ++ break; ++ case HCI_ACLDATA_PKT: ++ hdev->stat.acl_tx++; ++ break; ++ case HCI_SCODATA_PKT: ++ hdev->stat.sco_tx++; ++ break; ++ }; ++ ++ /* Prepend skb with frame type */ ++ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); ++ skb_queue_tail(&(info->txq), skb); ++ ++ bluecard_write_wakeup(info); ++ ++ return 0; ++} ++ ++ ++static void bluecard_hci_destruct(struct hci_dev *hdev) ++{ ++} ++ ++ ++static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) ++{ ++ return -ENOIOCTLCMD; ++} ++ ++ ++ ++/* ======================== Card services HCI interaction ======================== */ ++ ++ ++int bluecard_open(bluecard_info_t *info) ++{ ++ unsigned int iobase = info->link.io.BasePort1; ++ struct hci_dev *hdev; ++ unsigned char id; ++ ++ spin_lock_init(&(info->lock)); ++ ++ init_timer(&(info->timer)); ++ info->timer.function = &bluecard_activity_led_timeout; ++ info->timer.data = (u_long)info; ++ ++ skb_queue_head_init(&(info->txq)); ++ ++ info->rx_state = RECV_WAIT_PACKET_TYPE; ++ info->rx_count = 0; ++ info->rx_skb = NULL; ++ ++ id = inb(iobase + 0x30); ++ ++ if ((id & 0x0f) == 0x02) ++ set_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)); ++ ++ if (id & 0x10) ++ set_bit(CARD_HAS_POWER_LED, &(info->hw_state)); ++ ++ if (id & 0x20) ++ set_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state)); ++ ++ /* Reset card */ ++ info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET; ++ outb(info->ctrl_reg, iobase + REG_CONTROL); ++ ++ /* Turn FPGA off */ ++ outb(0x80, iobase + 0x30); ++ ++ /* Wait some time */ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(HZ / 100); ++ ++ /* Turn FPGA on */ ++ outb(0x00, iobase + 0x30); ++ ++ /* Activate card */ ++ info->ctrl_reg = REG_CONTROL_BT_ON | REG_CONTROL_BT_RES_PU; ++ outb(info->ctrl_reg, iobase + REG_CONTROL); ++ ++ /* Enable interrupt */ ++ outb(0xff, iobase + REG_INTERRUPT); ++ info->ctrl_reg |= REG_CONTROL_INTERRUPT; ++ outb(info->ctrl_reg, iobase + REG_CONTROL); ++ ++ /* Start the RX buffers */ ++ outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND); ++ outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND); ++ ++ /* Signal that the hardware is ready */ ++ set_bit(CARD_READY, &(info->hw_state)); ++ ++ /* Drop TX queue */ ++ skb_queue_purge(&(info->txq)); ++ ++ /* Control the point at which RTS is enabled */ ++ outb((0x0f << RTS_LEVEL_SHIFT_BITS) | 1, iobase + REG_RX_CONTROL); ++ ++ /* Timeout before it is safe to send the first HCI packet */ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout((HZ * 5) / 4); // or set it to 3/2 ++ ++ ++ /* Initialize and register HCI device */ ++ ++ hdev = &(info->hdev); ++ ++ hdev->type = HCI_PCCARD; ++ hdev->driver_data = info; ++ ++ hdev->open = bluecard_hci_open; ++ hdev->close = bluecard_hci_close; ++ hdev->flush = bluecard_hci_flush; ++ hdev->send = bluecard_hci_send_frame; ++ hdev->destruct = bluecard_hci_destruct; ++ hdev->ioctl = bluecard_hci_ioctl; ++ ++ if (hci_register_dev(hdev) < 0) { ++ printk(KERN_WARNING "bluecard_cs: Can't register HCI device %s.\n", hdev->name); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++ ++int bluecard_close(bluecard_info_t *info) ++{ ++ unsigned int iobase = info->link.io.BasePort1; ++ struct hci_dev *hdev = &(info->hdev); ++ ++ bluecard_hci_close(hdev); ++ ++ clear_bit(CARD_READY, &(info->hw_state)); ++ ++ /* Reset card */ ++ info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET; ++ outb(info->ctrl_reg, iobase + REG_CONTROL); ++ ++ /* Turn FPGA off */ ++ outb(0x80, iobase + 0x30); ++ ++ if (hci_unregister_dev(hdev) < 0) ++ printk(KERN_WARNING "bluecard_cs: Can't unregister HCI device %s.\n", hdev->name); ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Card services ======================== */ ++ ++ ++static void cs_error(client_handle_t handle, int func, int ret) ++{ ++ error_info_t err = { func, ret }; ++ ++ CardServices(ReportError, handle, &err); ++} ++ ++ ++dev_link_t *bluecard_attach(void) ++{ ++ bluecard_info_t *info; ++ client_reg_t client_reg; ++ dev_link_t *link; ++ int i, ret; ++ ++ /* Create new info device */ ++ info = kmalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return NULL; ++ memset(info, 0, sizeof(*info)); ++ ++ link = &info->link; ++ link->priv = info; ++ ++ link->release.function = &bluecard_release; ++ link->release.data = (u_long)link; ++ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; ++ link->io.NumPorts1 = 8; ++ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; ++ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; ++ ++ if (irq_list[0] == -1) ++ link->irq.IRQInfo2 = irq_mask; ++ else ++ for (i = 0; i < 4; i++) ++ link->irq.IRQInfo2 |= 1 << irq_list[i]; ++ ++ link->irq.Handler = bluecard_interrupt; ++ link->irq.Instance = info; ++ ++ link->conf.Attributes = CONF_ENABLE_IRQ; ++ link->conf.Vcc = 50; ++ link->conf.IntType = INT_MEMORY_AND_IO; ++ ++ /* Register with Card Services */ ++ link->next = dev_list; ++ dev_list = link; ++ client_reg.dev_info = &dev_info; ++ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; ++ client_reg.EventMask = ++ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | ++ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | ++ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; ++ client_reg.event_handler = &bluecard_event; ++ client_reg.Version = 0x0210; ++ client_reg.event_callback_args.client_data = link; ++ ++ ret = CardServices(RegisterClient, &link->handle, &client_reg); ++ if (ret != CS_SUCCESS) { ++ cs_error(link->handle, RegisterClient, ret); ++ bluecard_detach(link); ++ return NULL; ++ } ++ ++ return link; ++} ++ ++ ++void bluecard_detach(dev_link_t *link) ++{ ++ bluecard_info_t *info = link->priv; ++ dev_link_t **linkp; ++ int ret; ++ ++ /* Locate device structure */ ++ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) ++ if (*linkp == link) ++ break; ++ ++ if (*linkp == NULL) ++ return; ++ ++ del_timer(&link->release); ++ if (link->state & DEV_CONFIG) ++ bluecard_release((u_long)link); ++ ++ if (link->handle) { ++ ret = CardServices(DeregisterClient, link->handle); ++ if (ret != CS_SUCCESS) ++ cs_error(link->handle, DeregisterClient, ret); ++ } ++ ++ /* Unlink device structure, free bits */ ++ *linkp = link->next; ++ ++ kfree(info); ++} ++ ++ ++static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) ++{ ++ int i; ++ ++ i = CardServices(fn, handle, tuple); ++ if (i != CS_SUCCESS) ++ return CS_NO_MORE_ITEMS; ++ ++ i = CardServices(GetTupleData, handle, tuple); ++ if (i != CS_SUCCESS) ++ return i; ++ ++ return CardServices(ParseTuple, handle, tuple, parse); ++} ++ ++ ++#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) ++#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) ++ ++void bluecard_config(dev_link_t *link) ++{ ++ client_handle_t handle = link->handle; ++ bluecard_info_t *info = link->priv; ++ tuple_t tuple; ++ u_short buf[256]; ++ cisparse_t parse; ++ config_info_t config; ++ int i, n, last_ret, last_fn; ++ ++ tuple.TupleData = (cisdata_t *)buf; ++ tuple.TupleOffset = 0; ++ tuple.TupleDataMax = 255; ++ tuple.Attributes = 0; ++ ++ /* Get configuration register information */ ++ tuple.DesiredTuple = CISTPL_CONFIG; ++ last_ret = first_tuple(handle, &tuple, &parse); ++ if (last_ret != CS_SUCCESS) { ++ last_fn = ParseTuple; ++ goto cs_failed; ++ } ++ link->conf.ConfigBase = parse.config.base; ++ link->conf.Present = parse.config.rmask[0]; ++ ++ /* Configure card */ ++ link->state |= DEV_CONFIG; ++ i = CardServices(GetConfigurationInfo, handle, &config); ++ link->conf.Vcc = config.Vcc; ++ ++ link->conf.ConfigIndex = 0x20; ++ link->io.NumPorts1 = 64; ++ link->io.IOAddrLines = 6; ++ ++ for (n = 0; n < 0x400; n += 0x40) { ++ link->io.BasePort1 = n ^ 0x300; ++ i = CardServices(RequestIO, link->handle, &link->io); ++ if (i == CS_SUCCESS) ++ break; ++ } ++ ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestIO, i); ++ goto failed; ++ } ++ ++ i = CardServices(RequestIRQ, link->handle, &link->irq); ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestIRQ, i); ++ link->irq.AssignedIRQ = 0; ++ } ++ ++ i = CardServices(RequestConfiguration, link->handle, &link->conf); ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestConfiguration, i); ++ goto failed; ++ } ++ ++ MOD_INC_USE_COUNT; ++ ++ if (bluecard_open(info) != 0) ++ goto failed; ++ ++ strcpy(info->node.dev_name, info->hdev.name); ++ link->dev = &info->node; ++ link->state &= ~DEV_CONFIG_PENDING; ++ ++ return; ++ ++cs_failed: ++ cs_error(link->handle, last_fn, last_ret); ++ ++failed: ++ bluecard_release((u_long)link); ++} ++ ++ ++void bluecard_release(u_long arg) ++{ ++ dev_link_t *link = (dev_link_t *)arg; ++ bluecard_info_t *info = link->priv; ++ ++ if (link->state & DEV_PRESENT) ++ bluecard_close(info); ++ ++ MOD_DEC_USE_COUNT; ++ ++ link->dev = NULL; ++ ++ CardServices(ReleaseConfiguration, link->handle); ++ CardServices(ReleaseIO, link->handle, &link->io); ++ CardServices(ReleaseIRQ, link->handle, &link->irq); ++ ++ link->state &= ~DEV_CONFIG; ++} ++ ++ ++int bluecard_event(event_t event, int priority, event_callback_args_t *args) ++{ ++ dev_link_t *link = args->client_data; ++ bluecard_info_t *info = link->priv; ++ ++ switch (event) { ++ case CS_EVENT_CARD_REMOVAL: ++ link->state &= ~DEV_PRESENT; ++ if (link->state & DEV_CONFIG) { ++ bluecard_close(info); ++ mod_timer(&link->release, jiffies + HZ / 20); ++ } ++ break; ++ case CS_EVENT_CARD_INSERTION: ++ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; ++ bluecard_config(link); ++ break; ++ case CS_EVENT_PM_SUSPEND: ++ link->state |= DEV_SUSPEND; ++ /* Fall through... */ ++ case CS_EVENT_RESET_PHYSICAL: ++ if (link->state & DEV_CONFIG) ++ CardServices(ReleaseConfiguration, link->handle); ++ break; ++ case CS_EVENT_PM_RESUME: ++ link->state &= ~DEV_SUSPEND; ++ /* Fall through... */ ++ case CS_EVENT_CARD_RESET: ++ if (DEV_OK(link)) ++ CardServices(RequestConfiguration, link->handle, &link->conf); ++ break; ++ } ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Module initialization ======================== */ ++ ++ ++int __init init_bluecard_cs(void) ++{ ++ servinfo_t serv; ++ int err; ++ ++ CardServices(GetCardServicesInfo, &serv); ++ if (serv.Revision != CS_RELEASE_CODE) { ++ printk(KERN_NOTICE "bluecard_cs: Card Services release does not match!\n"); ++ return -1; ++ } ++ ++ err = register_pccard_driver(&dev_info, &bluecard_attach, &bluecard_detach); ++ ++ return err; ++} ++ ++ ++void __exit exit_bluecard_cs(void) ++{ ++ unregister_pccard_driver(&dev_info); ++ ++ while (dev_list != NULL) ++ bluecard_detach(dev_list); ++} ++ ++ ++module_init(init_bluecard_cs); ++module_exit(exit_bluecard_cs); ++ ++EXPORT_NO_SYMBOLS; +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/drivers/bluetooth/bt3c_cs.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,946 @@ ++/* ++ * ++ * Driver for the 3Com Bluetooth PCMCIA card ++ * ++ * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org> ++ * Jose Orlando Pereira <jop@di.uminho.pt> ++ * ++ * ++ * 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; ++ * ++ * Software distributed under the License is distributed on an "AS ++ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++ * implied. See the License for the specific language governing ++ * rights and limitations under the License. ++ * ++ * The initial developer of the original code is David A. Hinds ++ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds ++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#define __KERNEL_SYSCALLS__ ++ ++#include <linux/kernel.h> ++#include <linux/kmod.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/types.h> ++#include <linux/sched.h> ++#include <linux/delay.h> ++#include <linux/timer.h> ++#include <linux/errno.h> ++#include <linux/unistd.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/spinlock.h> ++ ++#include <linux/skbuff.h> ++#include <linux/string.h> ++#include <linux/serial.h> ++#include <linux/serial_reg.h> ++#include <asm/system.h> ++#include <asm/bitops.h> ++#include <asm/io.h> ++ ++#include <pcmcia/version.h> ++#include <pcmcia/cs_types.h> ++#include <pcmcia/cs.h> ++#include <pcmcia/cistpl.h> ++#include <pcmcia/ciscode.h> ++#include <pcmcia/ds.h> ++#include <pcmcia/cisreg.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++ ++ ++ ++/* ======================== Module parameters ======================== */ ++ ++ ++/* Bit map of interrupts to choose from */ ++static u_int irq_mask = 0xffff; ++static int irq_list[4] = { -1 }; ++ ++MODULE_PARM(irq_mask, "i"); ++MODULE_PARM(irq_list, "1-4i"); ++ ++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>"); ++MODULE_DESCRIPTION("BlueZ driver for the 3Com Bluetooth PCMCIA card"); ++MODULE_LICENSE("GPL"); ++ ++ ++ ++/* ======================== Local structures ======================== */ ++ ++ ++typedef struct bt3c_info_t { ++ dev_link_t link; ++ dev_node_t node; ++ ++ struct hci_dev hdev; ++ ++ spinlock_t lock; /* For serializing operations */ ++ ++ struct sk_buff_head txq; ++ unsigned long tx_state; ++ ++ unsigned long rx_state; ++ unsigned long rx_count; ++ struct sk_buff *rx_skb; ++} bt3c_info_t; ++ ++ ++void bt3c_config(dev_link_t *link); ++void bt3c_release(u_long arg); ++int bt3c_event(event_t event, int priority, event_callback_args_t *args); ++ ++static dev_info_t dev_info = "bt3c_cs"; ++ ++dev_link_t *bt3c_attach(void); ++void bt3c_detach(dev_link_t *); ++ ++static dev_link_t *dev_list = NULL; ++ ++ ++/* Transmit states */ ++#define XMIT_SENDING 1 ++#define XMIT_WAKEUP 2 ++#define XMIT_WAITING 8 ++ ++/* Receiver states */ ++#define RECV_WAIT_PACKET_TYPE 0 ++#define RECV_WAIT_EVENT_HEADER 1 ++#define RECV_WAIT_ACL_HEADER 2 ++#define RECV_WAIT_SCO_HEADER 3 ++#define RECV_WAIT_DATA 4 ++ ++ ++ ++/* ======================== Special I/O functions ======================== */ ++ ++ ++#define DATA_L 0 ++#define DATA_H 1 ++#define ADDR_L 2 ++#define ADDR_H 3 ++#define CONTROL 4 ++ ++ ++inline void bt3c_address(unsigned int iobase, unsigned short addr) ++{ ++ outb(addr & 0xff, iobase + ADDR_L); ++ outb((addr >> 8) & 0xff, iobase + ADDR_H); ++} ++ ++ ++inline void bt3c_put(unsigned int iobase, unsigned short value) ++{ ++ outb(value & 0xff, iobase + DATA_L); ++ outb((value >> 8) & 0xff, iobase + DATA_H); ++} ++ ++ ++inline void bt3c_io_write(unsigned int iobase, unsigned short addr, unsigned short value) ++{ ++ bt3c_address(iobase, addr); ++ bt3c_put(iobase, value); ++} ++ ++ ++inline unsigned short bt3c_get(unsigned int iobase) ++{ ++ unsigned short value = inb(iobase + DATA_L); ++ ++ value |= inb(iobase + DATA_H) << 8; ++ ++ return value; ++} ++ ++ ++inline unsigned short bt3c_read(unsigned int iobase, unsigned short addr) ++{ ++ bt3c_address(iobase, addr); ++ ++ return bt3c_get(iobase); ++} ++ ++ ++ ++/* ======================== Interrupt handling ======================== */ ++ ++ ++static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) ++{ ++ int actual = 0; ++ ++ bt3c_address(iobase, 0x7080); ++ ++ /* Fill FIFO with current frame */ ++ while (actual < len) { ++ /* Transmit next byte */ ++ bt3c_put(iobase, buf[actual]); ++ actual++; ++ } ++ ++ bt3c_io_write(iobase, 0x7005, actual); ++ ++ return actual; ++} ++ ++ ++static void bt3c_write_wakeup(bt3c_info_t *info, int from) ++{ ++ unsigned long flags; ++ ++ if (!info) { ++ printk(KERN_WARNING "bt3c_cs: Call of write_wakeup for unknown device.\n"); ++ return; ++ } ++ ++ if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) ++ return; ++ ++ spin_lock_irqsave(&(info->lock), flags); ++ ++ do { ++ register unsigned int iobase = info->link.io.BasePort1; ++ register struct sk_buff *skb; ++ register int len; ++ ++ if (!(info->link.state & DEV_PRESENT)) ++ break; ++ ++ ++ if (!(skb = skb_dequeue(&(info->txq)))) { ++ clear_bit(XMIT_SENDING, &(info->tx_state)); ++ break; ++ } ++ ++ /* Send frame */ ++ len = bt3c_write(iobase, 256, skb->data, skb->len); ++ ++ if (len != skb->len) { ++ printk(KERN_WARNING "bt3c_cs: very strange\n"); ++ } ++ ++ kfree_skb(skb); ++ ++ info->hdev.stat.byte_tx += len; ++ ++ } while (0); ++ ++ spin_unlock_irqrestore(&(info->lock), flags); ++} ++ ++ ++static void bt3c_receive(bt3c_info_t *info) ++{ ++ unsigned int iobase; ++ int size = 0, avail; ++ ++ if (!info) { ++ printk(KERN_WARNING "bt3c_cs: Call of receive for unknown device.\n"); ++ return; ++ } ++ ++ iobase = info->link.io.BasePort1; ++ ++ avail = bt3c_read(iobase, 0x7006); ++ //printk("bt3c_cs: receiving %d bytes\n", avail); ++ ++ bt3c_address(iobase, 0x7480); ++ while (size < avail) { ++ size++; ++ info->hdev.stat.byte_rx++; ++ ++ /* Allocate packet */ ++ if (info->rx_skb == NULL) { ++ info->rx_state = RECV_WAIT_PACKET_TYPE; ++ info->rx_count = 0; ++ if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { ++ printk(KERN_WARNING "bt3c_cs: Can't allocate mem for new packet.\n"); ++ return; ++ } ++ } ++ ++ ++ if (info->rx_state == RECV_WAIT_PACKET_TYPE) { ++ ++ info->rx_skb->dev = (void *)&(info->hdev); ++ info->rx_skb->pkt_type = inb(iobase + DATA_L); ++ inb(iobase + DATA_H); ++ //printk("bt3c: PACKET_TYPE=%02x\n", info->rx_skb->pkt_type); ++ ++ switch (info->rx_skb->pkt_type) { ++ ++ case HCI_EVENT_PKT: ++ info->rx_state = RECV_WAIT_EVENT_HEADER; ++ info->rx_count = HCI_EVENT_HDR_SIZE; ++ break; ++ ++ case HCI_ACLDATA_PKT: ++ info->rx_state = RECV_WAIT_ACL_HEADER; ++ info->rx_count = HCI_ACL_HDR_SIZE; ++ break; ++ ++ case HCI_SCODATA_PKT: ++ info->rx_state = RECV_WAIT_SCO_HEADER; ++ info->rx_count = HCI_SCO_HDR_SIZE; ++ break; ++ ++ default: ++ /* Unknown packet */ ++ printk(KERN_WARNING "bt3c_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type); ++ info->hdev.stat.err_rx++; ++ clear_bit(HCI_RUNNING, &(info->hdev.flags)); ++ ++ kfree_skb(info->rx_skb); ++ info->rx_skb = NULL; ++ break; ++ ++ } ++ ++ } else { ++ ++ __u8 x = inb(iobase + DATA_L); ++ ++ *skb_put(info->rx_skb, 1) = x; ++ inb(iobase + DATA_H); ++ info->rx_count--; ++ ++ if (info->rx_count == 0) { ++ ++ int dlen; ++ hci_event_hdr *eh; ++ hci_acl_hdr *ah; ++ hci_sco_hdr *sh; ++ ++ switch (info->rx_state) { ++ ++ case RECV_WAIT_EVENT_HEADER: ++ eh = (hci_event_hdr *)(info->rx_skb->data); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = eh->plen; ++ break; ++ ++ case RECV_WAIT_ACL_HEADER: ++ ah = (hci_acl_hdr *)(info->rx_skb->data); ++ dlen = __le16_to_cpu(ah->dlen); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = dlen; ++ break; ++ ++ case RECV_WAIT_SCO_HEADER: ++ sh = (hci_sco_hdr *)(info->rx_skb->data); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = sh->dlen; ++ break; ++ ++ case RECV_WAIT_DATA: ++ hci_recv_frame(info->rx_skb); ++ info->rx_skb = NULL; ++ break; ++ ++ } ++ ++ } ++ ++ } ++ ++ } ++ ++ bt3c_io_write(iobase, 0x7006, 0x0000); ++} ++ ++ ++void bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs) ++{ ++ bt3c_info_t *info = dev_inst; ++ unsigned int iobase; ++ int iir; ++ ++ if (!info) { ++ printk(KERN_WARNING "bt3c_cs: Call of irq %d for unknown device.\n", irq); ++ return; ++ } ++ ++ iobase = info->link.io.BasePort1; ++ ++ spin_lock(&(info->lock)); ++ ++ iir = inb(iobase + CONTROL); ++ if (iir & 0x80) { ++ int stat = bt3c_read(iobase, 0x7001); ++ ++ if ((stat & 0xff) == 0x7f) { ++ printk(KERN_WARNING "bt3c_cs: STRANGE stat=%04x\n", stat); ++ } else if ((stat & 0xff) != 0xff) { ++ if (stat & 0x0020) { ++ int stat = bt3c_read(iobase, 0x7002) & 0x10; ++ printk(KERN_WARNING "bt3c_cs: antena %s\n", stat ? "OUT" : "IN"); ++ } ++ if (stat & 0x0001) ++ bt3c_receive(info); ++ if (stat & 0x0002) { ++ //printk("bt3c_cs: ACK %04x\n", stat); ++ clear_bit(XMIT_SENDING, &(info->tx_state)); ++ bt3c_write_wakeup(info, 1); ++ } ++ ++ bt3c_io_write(iobase, 0x7001, 0x0000); ++ ++ outb(iir, iobase + CONTROL); ++ } ++ } ++ ++ spin_unlock(&(info->lock)); ++} ++ ++ ++ ++ ++/* ======================== HCI interface ======================== */ ++ ++ ++static int bt3c_hci_flush(struct hci_dev *hdev) ++{ ++ bt3c_info_t *info = (bt3c_info_t *)(hdev->driver_data); ++ ++ /* Drop TX queue */ ++ skb_queue_purge(&(info->txq)); ++ ++ return 0; ++} ++ ++ ++static int bt3c_hci_open(struct hci_dev *hdev) ++{ ++ set_bit(HCI_RUNNING, &(hdev->flags)); ++ ++ return 0; ++} ++ ++ ++static int bt3c_hci_close(struct hci_dev *hdev) ++{ ++ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) ++ return 0; ++ ++ bt3c_hci_flush(hdev); ++ ++ return 0; ++} ++ ++ ++static int bt3c_hci_send_frame(struct sk_buff *skb) ++{ ++ bt3c_info_t *info; ++ struct hci_dev *hdev = (struct hci_dev *)(skb->dev); ++ ++ if (!hdev) { ++ printk(KERN_WARNING "bt3c_cs: Frame for unknown HCI device (hdev=NULL)."); ++ return -ENODEV; ++ } ++ ++ info = (bt3c_info_t *) (hdev->driver_data); ++ ++ switch (skb->pkt_type) { ++ case HCI_COMMAND_PKT: ++ hdev->stat.cmd_tx++; ++ break; ++ case HCI_ACLDATA_PKT: ++ hdev->stat.acl_tx++; ++ break; ++ case HCI_SCODATA_PKT: ++ hdev->stat.sco_tx++; ++ break; ++ }; ++ ++ /* Prepend skb with frame type */ ++ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); ++ skb_queue_tail(&(info->txq), skb); ++ ++ bt3c_write_wakeup(info, 0); ++ ++ return 0; ++} ++ ++ ++static void bt3c_hci_destruct(struct hci_dev *hdev) ++{ ++} ++ ++ ++static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) ++{ ++ return -ENOIOCTLCMD; ++} ++ ++ ++ ++/* ======================== User mode firmware loader ======================== */ ++ ++ ++#define FW_LOADER "/sbin/bluefw" ++static int errno; ++ ++ ++static int bt3c_fw_loader_exec(void *dev) ++{ ++ char *argv[] = { FW_LOADER, "pccard", dev, NULL }; ++ char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; ++ int err; ++ ++ err = exec_usermodehelper(FW_LOADER, argv, envp); ++ if (err) ++ printk(KERN_WARNING "bt3c_cs: Failed to exec \"%s pccard %s\".\n", FW_LOADER, (char *)dev); ++ ++ return err; ++} ++ ++ ++static int bt3c_firmware_load(bt3c_info_t *info) ++{ ++ sigset_t tmpsig; ++ char dev[16]; ++ pid_t pid; ++ int result; ++ ++ /* Check if root fs is mounted */ ++ if (!current->fs->root) { ++ printk(KERN_WARNING "bt3c_cs: Root filesystem is not mounted.\n"); ++ return -EPERM; ++ } ++ ++ sprintf(dev, "%04x", info->link.io.BasePort1); ++ ++ pid = kernel_thread(bt3c_fw_loader_exec, (void *)dev, 0); ++ if (pid < 0) { ++ printk(KERN_WARNING "bt3c_cs: Forking of kernel thread failed (errno=%d).\n", -pid); ++ return pid; ++ } ++ ++ /* Block signals, everything but SIGKILL/SIGSTOP */ ++ spin_lock_irq(¤t->sigmask_lock); ++ tmpsig = current->blocked; ++ siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)); ++ recalc_sigpending(current); ++ spin_unlock_irq(¤t->sigmask_lock); ++ ++ result = waitpid(pid, NULL, __WCLONE); ++ ++ /* Allow signals again */ ++ spin_lock_irq(¤t->sigmask_lock); ++ current->blocked = tmpsig; ++ recalc_sigpending(current); ++ spin_unlock_irq(¤t->sigmask_lock); ++ ++ if (result != pid) { ++ printk(KERN_WARNING "bt3c_cs: Waiting for pid %d failed (errno=%d).\n", pid, -result); ++ return -result; ++ } ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Card services HCI interaction ======================== */ ++ ++ ++int bt3c_open(bt3c_info_t *info) ++{ ++ struct hci_dev *hdev; ++ int err; ++ ++ spin_lock_init(&(info->lock)); ++ ++ skb_queue_head_init(&(info->txq)); ++ ++ info->rx_state = RECV_WAIT_PACKET_TYPE; ++ info->rx_count = 0; ++ info->rx_skb = NULL; ++ ++ /* Load firmware */ ++ ++ if ((err = bt3c_firmware_load(info)) < 0) ++ return err; ++ ++ /* Timeout before it is safe to send the first HCI packet */ ++ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(HZ); ++ ++ ++ /* Initialize and register HCI device */ ++ ++ hdev = &(info->hdev); ++ ++ hdev->type = HCI_PCCARD; ++ hdev->driver_data = info; ++ ++ hdev->open = bt3c_hci_open; ++ hdev->close = bt3c_hci_close; ++ hdev->flush = bt3c_hci_flush; ++ hdev->send = bt3c_hci_send_frame; ++ hdev->destruct = bt3c_hci_destruct; ++ hdev->ioctl = bt3c_hci_ioctl; ++ ++ if (hci_register_dev(hdev) < 0) { ++ printk(KERN_WARNING "bt3c_cs: Can't register HCI device %s.\n", hdev->name); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++ ++int bt3c_close(bt3c_info_t *info) ++{ ++ struct hci_dev *hdev = &(info->hdev); ++ ++ bt3c_hci_close(hdev); ++ ++ if (hci_unregister_dev(hdev) < 0) ++ printk(KERN_WARNING "bt3c_cs: Can't unregister HCI device %s.\n", hdev->name); ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Card services ======================== */ ++ ++ ++static void cs_error(client_handle_t handle, int func, int ret) ++{ ++ error_info_t err = { func, ret }; ++ ++ CardServices(ReportError, handle, &err); ++} ++ ++ ++dev_link_t *bt3c_attach(void) ++{ ++ bt3c_info_t *info; ++ client_reg_t client_reg; ++ dev_link_t *link; ++ int i, ret; ++ ++ /* Create new info device */ ++ info = kmalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return NULL; ++ memset(info, 0, sizeof(*info)); ++ ++ link = &info->link; ++ link->priv = info; ++ ++ link->release.function = &bt3c_release; ++ link->release.data = (u_long)link; ++ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; ++ link->io.NumPorts1 = 8; ++ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; ++ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; ++ ++ if (irq_list[0] == -1) ++ link->irq.IRQInfo2 = irq_mask; ++ else ++ for (i = 0; i < 4; i++) ++ link->irq.IRQInfo2 |= 1 << irq_list[i]; ++ ++ link->irq.Handler = bt3c_interrupt; ++ link->irq.Instance = info; ++ ++ link->conf.Attributes = CONF_ENABLE_IRQ; ++ link->conf.Vcc = 50; ++ link->conf.IntType = INT_MEMORY_AND_IO; ++ ++ /* Register with Card Services */ ++ link->next = dev_list; ++ dev_list = link; ++ client_reg.dev_info = &dev_info; ++ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; ++ client_reg.EventMask = ++ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | ++ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | ++ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; ++ client_reg.event_handler = &bt3c_event; ++ client_reg.Version = 0x0210; ++ client_reg.event_callback_args.client_data = link; ++ ++ ret = CardServices(RegisterClient, &link->handle, &client_reg); ++ if (ret != CS_SUCCESS) { ++ cs_error(link->handle, RegisterClient, ret); ++ bt3c_detach(link); ++ return NULL; ++ } ++ ++ return link; ++} ++ ++ ++void bt3c_detach(dev_link_t *link) ++{ ++ bt3c_info_t *info = link->priv; ++ dev_link_t **linkp; ++ int ret; ++ ++ /* Locate device structure */ ++ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) ++ if (*linkp == link) ++ break; ++ ++ if (*linkp == NULL) ++ return; ++ ++ del_timer(&link->release); ++ ++ if (link->state & DEV_CONFIG) ++ bt3c_release((u_long)link); ++ ++ if (link->handle) { ++ ret = CardServices(DeregisterClient, link->handle); ++ if (ret != CS_SUCCESS) ++ cs_error(link->handle, DeregisterClient, ret); ++ } ++ ++ /* Unlink device structure, free bits */ ++ *linkp = link->next; ++ ++ kfree(info); ++} ++ ++ ++static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) ++{ ++ int i; ++ ++ i = CardServices(fn, handle, tuple); ++ if (i != CS_SUCCESS) ++ return CS_NO_MORE_ITEMS; ++ ++ i = CardServices(GetTupleData, handle, tuple); ++ if (i != CS_SUCCESS) ++ return i; ++ ++ return CardServices(ParseTuple, handle, tuple, parse); ++} ++ ++ ++#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) ++#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) ++ ++void bt3c_config(dev_link_t *link) ++{ ++ static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; ++ client_handle_t handle = link->handle; ++ bt3c_info_t *info = link->priv; ++ tuple_t tuple; ++ u_short buf[256]; ++ cisparse_t parse; ++ cistpl_cftable_entry_t *cf = &parse.cftable_entry; ++ config_info_t config; ++ int i, j, try, last_ret, last_fn; ++ ++ tuple.TupleData = (cisdata_t *)buf; ++ tuple.TupleOffset = 0; ++ tuple.TupleDataMax = 255; ++ tuple.Attributes = 0; ++ ++ /* Get configuration register information */ ++ tuple.DesiredTuple = CISTPL_CONFIG; ++ last_ret = first_tuple(handle, &tuple, &parse); ++ if (last_ret != CS_SUCCESS) { ++ last_fn = ParseTuple; ++ goto cs_failed; ++ } ++ link->conf.ConfigBase = parse.config.base; ++ link->conf.Present = parse.config.rmask[0]; ++ ++ /* Configure card */ ++ link->state |= DEV_CONFIG; ++ i = CardServices(GetConfigurationInfo, handle, &config); ++ link->conf.Vcc = config.Vcc; ++ ++ /* First pass: look for a config entry that looks normal. */ ++ tuple.TupleData = (cisdata_t *)buf; ++ tuple.TupleOffset = 0; ++ tuple.TupleDataMax = 255; ++ tuple.Attributes = 0; ++ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; ++ /* Two tries: without IO aliases, then with aliases */ ++ for (try = 0; try < 2; try++) { ++ i = first_tuple(handle, &tuple, &parse); ++ while (i != CS_NO_MORE_ITEMS) { ++ if (i != CS_SUCCESS) ++ goto next_entry; ++ if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) ++ link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; ++ if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) { ++ link->conf.ConfigIndex = cf->index; ++ link->io.BasePort1 = cf->io.win[0].base; ++ link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; ++ i = CardServices(RequestIO, link->handle, &link->io); ++ if (i == CS_SUCCESS) ++ goto found_port; ++ } ++next_entry: ++ i = next_tuple(handle, &tuple, &parse); ++ } ++ } ++ ++ /* Second pass: try to find an entry that isn't picky about ++ its base address, then try to grab any standard serial port ++ address, and finally try to get any free port. */ ++ i = first_tuple(handle, &tuple, &parse); ++ while (i != CS_NO_MORE_ITEMS) { ++ if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { ++ link->conf.ConfigIndex = cf->index; ++ for (j = 0; j < 5; j++) { ++ link->io.BasePort1 = base[j]; ++ link->io.IOAddrLines = base[j] ? 16 : 3; ++ i = CardServices(RequestIO, link->handle, &link->io); ++ if (i == CS_SUCCESS) ++ goto found_port; ++ } ++ } ++ i = next_tuple(handle, &tuple, &parse); ++ } ++ ++found_port: ++ if (i != CS_SUCCESS) { ++ printk(KERN_NOTICE "bt3c_cs: No usable port range found. Giving up.\n"); ++ cs_error(link->handle, RequestIO, i); ++ goto failed; ++ } ++ ++ i = CardServices(RequestIRQ, link->handle, &link->irq); ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestIRQ, i); ++ link->irq.AssignedIRQ = 0; ++ } ++ ++ i = CardServices(RequestConfiguration, link->handle, &link->conf); ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestConfiguration, i); ++ goto failed; ++ } ++ ++ MOD_INC_USE_COUNT; ++ ++ if (bt3c_open(info) != 0) ++ goto failed; ++ ++ strcpy(info->node.dev_name, info->hdev.name); ++ link->dev = &info->node; ++ link->state &= ~DEV_CONFIG_PENDING; ++ ++ return; ++ ++cs_failed: ++ cs_error(link->handle, last_fn, last_ret); ++ ++failed: ++ bt3c_release((u_long)link); ++} ++ ++ ++void bt3c_release(u_long arg) ++{ ++ dev_link_t *link = (dev_link_t *)arg; ++ bt3c_info_t *info = link->priv; ++ ++ if (link->state & DEV_PRESENT) ++ bt3c_close(info); ++ ++ MOD_DEC_USE_COUNT; ++ ++ link->dev = NULL; ++ ++ CardServices(ReleaseConfiguration, link->handle); ++ CardServices(ReleaseIO, link->handle, &link->io); ++ CardServices(ReleaseIRQ, link->handle, &link->irq); ++ ++ link->state &= ~DEV_CONFIG; ++} ++ ++ ++int bt3c_event(event_t event, int priority, event_callback_args_t *args) ++{ ++ dev_link_t *link = args->client_data; ++ bt3c_info_t *info = link->priv; ++ ++ switch (event) { ++ case CS_EVENT_CARD_REMOVAL: ++ link->state &= ~DEV_PRESENT; ++ if (link->state & DEV_CONFIG) { ++ bt3c_close(info); ++ mod_timer(&link->release, jiffies + HZ / 20); ++ } ++ break; ++ case CS_EVENT_CARD_INSERTION: ++ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; ++ bt3c_config(link); ++ break; ++ case CS_EVENT_PM_SUSPEND: ++ link->state |= DEV_SUSPEND; ++ /* Fall through... */ ++ case CS_EVENT_RESET_PHYSICAL: ++ if (link->state & DEV_CONFIG) ++ CardServices(ReleaseConfiguration, link->handle); ++ break; ++ case CS_EVENT_PM_RESUME: ++ link->state &= ~DEV_SUSPEND; ++ /* Fall through... */ ++ case CS_EVENT_CARD_RESET: ++ if (DEV_OK(link)) ++ CardServices(RequestConfiguration, link->handle, &link->conf); ++ break; ++ } ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Module initialization ======================== */ ++ ++ ++int __init init_bt3c_cs(void) ++{ ++ servinfo_t serv; ++ int err; ++ ++ CardServices(GetCardServicesInfo, &serv); ++ if (serv.Revision != CS_RELEASE_CODE) { ++ printk(KERN_NOTICE "bt3c_cs: Card Services release does not match!\n"); ++ return -1; ++ } ++ ++ err = register_pccard_driver(&dev_info, &bt3c_attach, &bt3c_detach); ++ ++ return err; ++} ++ ++ ++void __exit exit_bt3c_cs(void) ++{ ++ unregister_pccard_driver(&dev_info); ++ ++ while (dev_list != NULL) ++ bt3c_detach(dev_list); ++} ++ ++ ++module_init(init_bt3c_cs); ++module_exit(exit_bt3c_cs); ++ ++EXPORT_NO_SYMBOLS; +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/drivers/bluetooth/btuart_cs.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,906 @@ ++/* ++ * ++ * Driver for Bluetooth PCMCIA cards with HCI UART interface ++ * ++ * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org> ++ * ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation; ++ * ++ * Software distributed under the License is distributed on an "AS ++ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++ * implied. See the License for the specific language governing ++ * rights and limitations under the License. ++ * ++ * The initial developer of the original code is David A. Hinds ++ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds ++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/types.h> ++#include <linux/sched.h> ++#include <linux/timer.h> ++#include <linux/errno.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/spinlock.h> ++ ++#include <linux/skbuff.h> ++#include <linux/string.h> ++#include <linux/serial.h> ++#include <linux/serial_reg.h> ++#include <asm/system.h> ++#include <asm/bitops.h> ++#include <asm/io.h> ++ ++#include <pcmcia/version.h> ++#include <pcmcia/cs_types.h> ++#include <pcmcia/cs.h> ++#include <pcmcia/cistpl.h> ++#include <pcmcia/ciscode.h> ++#include <pcmcia/ds.h> ++#include <pcmcia/cisreg.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++ ++ ++ ++/* ======================== Module parameters ======================== */ ++ ++ ++/* Bit map of interrupts to choose from */ ++static u_int irq_mask = 0xffff; ++static int irq_list[4] = { -1 }; ++ ++MODULE_PARM(irq_mask, "i"); ++MODULE_PARM(irq_list, "1-4i"); ++ ++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); ++MODULE_DESCRIPTION("BlueZ driver for Bluetooth PCMCIA cards with HCI UART interface"); ++MODULE_LICENSE("GPL"); ++ ++ ++ ++/* ======================== Local structures ======================== */ ++ ++ ++typedef struct btuart_info_t { ++ dev_link_t link; ++ dev_node_t node; ++ ++ struct hci_dev hdev; ++ ++ spinlock_t lock; /* For serializing operations */ ++ ++ struct sk_buff_head txq; ++ unsigned long tx_state; ++ ++ unsigned long rx_state; ++ unsigned long rx_count; ++ struct sk_buff *rx_skb; ++} btuart_info_t; ++ ++ ++void btuart_config(dev_link_t *link); ++void btuart_release(u_long arg); ++int btuart_event(event_t event, int priority, event_callback_args_t *args); ++ ++static dev_info_t dev_info = "btuart_cs"; ++ ++dev_link_t *btuart_attach(void); ++void btuart_detach(dev_link_t *); ++ ++static dev_link_t *dev_list = NULL; ++ ++ ++/* Maximum baud rate */ ++#define SPEED_MAX 115200 ++ ++/* Default baud rate: 57600, 115200, 230400 or 460800 */ ++#define DEFAULT_BAUD_RATE 115200 ++ ++ ++/* Transmit states */ ++#define XMIT_SENDING 1 ++#define XMIT_WAKEUP 2 ++#define XMIT_WAITING 8 ++ ++/* Receiver states */ ++#define RECV_WAIT_PACKET_TYPE 0 ++#define RECV_WAIT_EVENT_HEADER 1 ++#define RECV_WAIT_ACL_HEADER 2 ++#define RECV_WAIT_SCO_HEADER 3 ++#define RECV_WAIT_DATA 4 ++ ++ ++ ++/* ======================== Interrupt handling ======================== */ ++ ++ ++static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) ++{ ++ int actual = 0; ++ ++ /* Tx FIFO should be empty */ ++ if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) ++ return 0; ++ ++ /* Fill FIFO with current frame */ ++ while ((fifo_size-- > 0) && (actual < len)) { ++ /* Transmit next byte */ ++ outb(buf[actual], iobase + UART_TX); ++ actual++; ++ } ++ ++ return actual; ++} ++ ++ ++static void btuart_write_wakeup(btuart_info_t *info) ++{ ++ if (!info) { ++ printk(KERN_WARNING "btuart_cs: Call of write_wakeup for unknown device.\n"); ++ return; ++ } ++ ++ if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { ++ set_bit(XMIT_WAKEUP, &(info->tx_state)); ++ return; ++ } ++ ++ do { ++ register unsigned int iobase = info->link.io.BasePort1; ++ register struct sk_buff *skb; ++ register int len; ++ ++ clear_bit(XMIT_WAKEUP, &(info->tx_state)); ++ ++ if (!(info->link.state & DEV_PRESENT)) ++ return; ++ ++ if (!(skb = skb_dequeue(&(info->txq)))) ++ break; ++ ++ /* Send frame */ ++ len = btuart_write(iobase, 16, skb->data, skb->len); ++ set_bit(XMIT_WAKEUP, &(info->tx_state)); ++ ++ if (len == skb->len) { ++ kfree_skb(skb); ++ } else { ++ skb_pull(skb, len); ++ skb_queue_head(&(info->txq), skb); ++ } ++ ++ info->hdev.stat.byte_tx += len; ++ ++ } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); ++ ++ clear_bit(XMIT_SENDING, &(info->tx_state)); ++} ++ ++ ++static void btuart_receive(btuart_info_t *info) ++{ ++ unsigned int iobase; ++ int boguscount = 0; ++ ++ if (!info) { ++ printk(KERN_WARNING "btuart_cs: Call of receive for unknown device.\n"); ++ return; ++ } ++ ++ iobase = info->link.io.BasePort1; ++ ++ do { ++ info->hdev.stat.byte_rx++; ++ ++ /* Allocate packet */ ++ if (info->rx_skb == NULL) { ++ info->rx_state = RECV_WAIT_PACKET_TYPE; ++ info->rx_count = 0; ++ if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { ++ printk(KERN_WARNING "btuart_cs: Can't allocate mem for new packet.\n"); ++ return; ++ } ++ } ++ ++ if (info->rx_state == RECV_WAIT_PACKET_TYPE) { ++ ++ info->rx_skb->dev = (void *)&(info->hdev); ++ info->rx_skb->pkt_type = inb(iobase + UART_RX); ++ ++ switch (info->rx_skb->pkt_type) { ++ ++ case HCI_EVENT_PKT: ++ info->rx_state = RECV_WAIT_EVENT_HEADER; ++ info->rx_count = HCI_EVENT_HDR_SIZE; ++ break; ++ ++ case HCI_ACLDATA_PKT: ++ info->rx_state = RECV_WAIT_ACL_HEADER; ++ info->rx_count = HCI_ACL_HDR_SIZE; ++ break; ++ ++ case HCI_SCODATA_PKT: ++ info->rx_state = RECV_WAIT_SCO_HEADER; ++ info->rx_count = HCI_SCO_HDR_SIZE; ++ break; ++ ++ default: ++ /* Unknown packet */ ++ printk(KERN_WARNING "btuart_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type); ++ info->hdev.stat.err_rx++; ++ clear_bit(HCI_RUNNING, &(info->hdev.flags)); ++ ++ kfree_skb(info->rx_skb); ++ info->rx_skb = NULL; ++ break; ++ ++ } ++ ++ } else { ++ ++ *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); ++ info->rx_count--; ++ ++ if (info->rx_count == 0) { ++ ++ int dlen; ++ hci_event_hdr *eh; ++ hci_acl_hdr *ah; ++ hci_sco_hdr *sh; ++ ++ ++ switch (info->rx_state) { ++ ++ case RECV_WAIT_EVENT_HEADER: ++ eh = (hci_event_hdr *)(info->rx_skb->data); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = eh->plen; ++ break; ++ ++ case RECV_WAIT_ACL_HEADER: ++ ah = (hci_acl_hdr *)(info->rx_skb->data); ++ dlen = __le16_to_cpu(ah->dlen); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = dlen; ++ break; ++ ++ case RECV_WAIT_SCO_HEADER: ++ sh = (hci_sco_hdr *)(info->rx_skb->data); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = sh->dlen; ++ break; ++ ++ case RECV_WAIT_DATA: ++ hci_recv_frame(info->rx_skb); ++ info->rx_skb = NULL; ++ break; ++ ++ } ++ ++ } ++ ++ } ++ ++ /* Make sure we don't stay here to long */ ++ if (boguscount++ > 16) ++ break; ++ ++ } while (inb(iobase + UART_LSR) & UART_LSR_DR); ++} ++ ++ ++void btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs) ++{ ++ btuart_info_t *info = dev_inst; ++ unsigned int iobase; ++ int boguscount = 0; ++ int iir, lsr; ++ ++ if (!info) { ++ printk(KERN_WARNING "btuart_cs: Call of irq %d for unknown device.\n", irq); ++ return; ++ } ++ ++ iobase = info->link.io.BasePort1; ++ ++ spin_lock(&(info->lock)); ++ ++ iir = inb(iobase + UART_IIR) & UART_IIR_ID; ++ while (iir) { ++ ++ /* Clear interrupt */ ++ lsr = inb(iobase + UART_LSR); ++ ++ switch (iir) { ++ case UART_IIR_RLSI: ++ printk(KERN_NOTICE "btuart_cs: RLSI\n"); ++ break; ++ case UART_IIR_RDI: ++ /* Receive interrupt */ ++ btuart_receive(info); ++ break; ++ case UART_IIR_THRI: ++ if (lsr & UART_LSR_THRE) { ++ /* Transmitter ready for data */ ++ btuart_write_wakeup(info); ++ } ++ break; ++ default: ++ printk(KERN_NOTICE "btuart_cs: Unhandled IIR=%#x\n", iir); ++ break; ++ } ++ ++ /* Make sure we don't stay here to long */ ++ if (boguscount++ > 100) ++ break; ++ ++ iir = inb(iobase + UART_IIR) & UART_IIR_ID; ++ ++ } ++ ++ spin_unlock(&(info->lock)); ++} ++ ++ ++static void btuart_change_speed(btuart_info_t *info, unsigned int speed) ++{ ++ unsigned long flags; ++ unsigned int iobase; ++ int fcr; /* FIFO control reg */ ++ int lcr; /* Line control reg */ ++ int divisor; ++ ++ if (!info) { ++ printk(KERN_WARNING "btuart_cs: Call of change speed for unknown device.\n"); ++ return; ++ } ++ ++ iobase = info->link.io.BasePort1; ++ ++ spin_lock_irqsave(&(info->lock), flags); ++ ++ /* Turn off interrupts */ ++ outb(0, iobase + UART_IER); ++ ++ divisor = SPEED_MAX / speed; ++ ++ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT; ++ ++ /* ++ * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and ++ * almost 1,7 ms at 19200 bps. At speeds above that we can just forget ++ * about this timeout since it will always be fast enough. ++ */ ++ ++ if (speed < 38400) ++ fcr |= UART_FCR_TRIGGER_1; ++ else ++ fcr |= UART_FCR_TRIGGER_14; ++ ++ /* Bluetooth cards use 8N1 */ ++ lcr = UART_LCR_WLEN8; ++ ++ outb(UART_LCR_DLAB | lcr, iobase + UART_LCR); /* Set DLAB */ ++ outb(divisor & 0xff, iobase + UART_DLL); /* Set speed */ ++ outb(divisor >> 8, iobase + UART_DLM); ++ outb(lcr, iobase + UART_LCR); /* Set 8N1 */ ++ outb(fcr, iobase + UART_FCR); /* Enable FIFO's */ ++ ++ /* Turn on interrups */ ++ outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); ++ ++ spin_unlock_irqrestore(&(info->lock), flags); ++} ++ ++ ++ ++/* ======================== HCI interface ======================== */ ++ ++ ++static int btuart_hci_flush(struct hci_dev *hdev) ++{ ++ btuart_info_t *info = (btuart_info_t *)(hdev->driver_data); ++ ++ /* Drop TX queue */ ++ skb_queue_purge(&(info->txq)); ++ ++ return 0; ++} ++ ++ ++static int btuart_hci_open(struct hci_dev *hdev) ++{ ++ set_bit(HCI_RUNNING, &(hdev->flags)); ++ ++ return 0; ++} ++ ++ ++static int btuart_hci_close(struct hci_dev *hdev) ++{ ++ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) ++ return 0; ++ ++ btuart_hci_flush(hdev); ++ ++ return 0; ++} ++ ++ ++static int btuart_hci_send_frame(struct sk_buff *skb) ++{ ++ btuart_info_t *info; ++ struct hci_dev *hdev = (struct hci_dev *)(skb->dev); ++ ++ if (!hdev) { ++ printk(KERN_WARNING "btuart_cs: Frame for unknown HCI device (hdev=NULL)."); ++ return -ENODEV; ++ } ++ ++ info = (btuart_info_t *)(hdev->driver_data); ++ ++ switch (skb->pkt_type) { ++ case HCI_COMMAND_PKT: ++ hdev->stat.cmd_tx++; ++ break; ++ case HCI_ACLDATA_PKT: ++ hdev->stat.acl_tx++; ++ break; ++ case HCI_SCODATA_PKT: ++ hdev->stat.sco_tx++; ++ break; ++ }; ++ ++ /* Prepend skb with frame type */ ++ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); ++ skb_queue_tail(&(info->txq), skb); ++ ++ btuart_write_wakeup(info); ++ ++ return 0; ++} ++ ++ ++static void btuart_hci_destruct(struct hci_dev *hdev) ++{ ++} ++ ++ ++static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) ++{ ++ return -ENOIOCTLCMD; ++} ++ ++ ++ ++/* ======================== Card services HCI interaction ======================== */ ++ ++ ++int btuart_open(btuart_info_t *info) ++{ ++ unsigned long flags; ++ unsigned int iobase = info->link.io.BasePort1; ++ struct hci_dev *hdev; ++ ++ spin_lock_init(&(info->lock)); ++ ++ skb_queue_head_init(&(info->txq)); ++ ++ info->rx_state = RECV_WAIT_PACKET_TYPE; ++ info->rx_count = 0; ++ info->rx_skb = NULL; ++ ++ spin_lock_irqsave(&(info->lock), flags); ++ ++ /* Reset UART */ ++ outb(0, iobase + UART_MCR); ++ ++ /* Turn off interrupts */ ++ outb(0, iobase + UART_IER); ++ ++ /* Initialize UART */ ++ outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */ ++ outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR); ++ ++ /* Turn on interrupts */ ++ // outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); ++ ++ spin_unlock_irqrestore(&(info->lock), flags); ++ ++ btuart_change_speed(info, DEFAULT_BAUD_RATE); ++ ++ /* Timeout before it is safe to send the first HCI packet */ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(HZ); ++ ++ ++ /* Initialize and register HCI device */ ++ ++ hdev = &(info->hdev); ++ ++ hdev->type = HCI_PCCARD; ++ hdev->driver_data = info; ++ ++ hdev->open = btuart_hci_open; ++ hdev->close = btuart_hci_close; ++ hdev->flush = btuart_hci_flush; ++ hdev->send = btuart_hci_send_frame; ++ hdev->destruct = btuart_hci_destruct; ++ hdev->ioctl = btuart_hci_ioctl; ++ ++ if (hci_register_dev(hdev) < 0) { ++ printk(KERN_WARNING "btuart_cs: Can't register HCI device %s.\n", hdev->name); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++ ++int btuart_close(btuart_info_t *info) ++{ ++ unsigned long flags; ++ unsigned int iobase = info->link.io.BasePort1; ++ struct hci_dev *hdev = &(info->hdev); ++ ++ btuart_hci_close(hdev); ++ ++ spin_lock_irqsave(&(info->lock), flags); ++ ++ /* Reset UART */ ++ outb(0, iobase + UART_MCR); ++ ++ /* Turn off interrupts */ ++ outb(0, iobase + UART_IER); ++ ++ spin_unlock_irqrestore(&(info->lock), flags); ++ ++ if (hci_unregister_dev(hdev) < 0) ++ printk(KERN_WARNING "btuart_cs: Can't unregister HCI device %s.\n", hdev->name); ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Card services ======================== */ ++ ++ ++static void cs_error(client_handle_t handle, int func, int ret) ++{ ++ error_info_t err = { func, ret }; ++ ++ CardServices(ReportError, handle, &err); ++} ++ ++ ++dev_link_t *btuart_attach(void) ++{ ++ btuart_info_t *info; ++ client_reg_t client_reg; ++ dev_link_t *link; ++ int i, ret; ++ ++ /* Create new info device */ ++ info = kmalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return NULL; ++ memset(info, 0, sizeof(*info)); ++ ++ link = &info->link; ++ link->priv = info; ++ ++ link->release.function = &btuart_release; ++ link->release.data = (u_long)link; ++ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; ++ link->io.NumPorts1 = 8; ++ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; ++ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; ++ ++ if (irq_list[0] == -1) ++ link->irq.IRQInfo2 = irq_mask; ++ else ++ for (i = 0; i < 4; i++) ++ link->irq.IRQInfo2 |= 1 << irq_list[i]; ++ ++ link->irq.Handler = btuart_interrupt; ++ link->irq.Instance = info; ++ ++ link->conf.Attributes = CONF_ENABLE_IRQ; ++ link->conf.Vcc = 50; ++ link->conf.IntType = INT_MEMORY_AND_IO; ++ ++ /* Register with Card Services */ ++ link->next = dev_list; ++ dev_list = link; ++ client_reg.dev_info = &dev_info; ++ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; ++ client_reg.EventMask = ++ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | ++ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | ++ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; ++ client_reg.event_handler = &btuart_event; ++ client_reg.Version = 0x0210; ++ client_reg.event_callback_args.client_data = link; ++ ++ ret = CardServices(RegisterClient, &link->handle, &client_reg); ++ if (ret != CS_SUCCESS) { ++ cs_error(link->handle, RegisterClient, ret); ++ btuart_detach(link); ++ return NULL; ++ } ++ ++ return link; ++} ++ ++ ++void btuart_detach(dev_link_t *link) ++{ ++ btuart_info_t *info = link->priv; ++ dev_link_t **linkp; ++ int ret; ++ ++ /* Locate device structure */ ++ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) ++ if (*linkp == link) ++ break; ++ ++ if (*linkp == NULL) ++ return; ++ ++ del_timer(&link->release); ++ if (link->state & DEV_CONFIG) ++ btuart_release((u_long)link); ++ ++ if (link->handle) { ++ ret = CardServices(DeregisterClient, link->handle); ++ if (ret != CS_SUCCESS) ++ cs_error(link->handle, DeregisterClient, ret); ++ } ++ ++ /* Unlink device structure, free bits */ ++ *linkp = link->next; ++ ++ kfree(info); ++} ++ ++ ++static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) ++{ ++ int i; ++ ++ i = CardServices(fn, handle, tuple); ++ if (i != CS_SUCCESS) ++ return CS_NO_MORE_ITEMS; ++ ++ i = CardServices(GetTupleData, handle, tuple); ++ if (i != CS_SUCCESS) ++ return i; ++ ++ return CardServices(ParseTuple, handle, tuple, parse); ++} ++ ++ ++#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) ++#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) ++ ++void btuart_config(dev_link_t *link) ++{ ++ static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; ++ client_handle_t handle = link->handle; ++ btuart_info_t *info = link->priv; ++ tuple_t tuple; ++ u_short buf[256]; ++ cisparse_t parse; ++ cistpl_cftable_entry_t *cf = &parse.cftable_entry; ++ config_info_t config; ++ int i, j, try, last_ret, last_fn; ++ ++ tuple.TupleData = (cisdata_t *)buf; ++ tuple.TupleOffset = 0; ++ tuple.TupleDataMax = 255; ++ tuple.Attributes = 0; ++ ++ /* Get configuration register information */ ++ tuple.DesiredTuple = CISTPL_CONFIG; ++ last_ret = first_tuple(handle, &tuple, &parse); ++ if (last_ret != CS_SUCCESS) { ++ last_fn = ParseTuple; ++ goto cs_failed; ++ } ++ link->conf.ConfigBase = parse.config.base; ++ link->conf.Present = parse.config.rmask[0]; ++ ++ /* Configure card */ ++ link->state |= DEV_CONFIG; ++ i = CardServices(GetConfigurationInfo, handle, &config); ++ link->conf.Vcc = config.Vcc; ++ ++ /* First pass: look for a config entry that looks normal. */ ++ tuple.TupleData = (cisdata_t *) buf; ++ tuple.TupleOffset = 0; ++ tuple.TupleDataMax = 255; ++ tuple.Attributes = 0; ++ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; ++ /* Two tries: without IO aliases, then with aliases */ ++ for (try = 0; try < 2; try++) { ++ i = first_tuple(handle, &tuple, &parse); ++ while (i != CS_NO_MORE_ITEMS) { ++ if (i != CS_SUCCESS) ++ goto next_entry; ++ if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) ++ link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; ++ if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) { ++ link->conf.ConfigIndex = cf->index; ++ link->io.BasePort1 = cf->io.win[0].base; ++ link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; ++ i = CardServices(RequestIO, link->handle, &link->io); ++ if (i == CS_SUCCESS) ++ goto found_port; ++ } ++next_entry: ++ i = next_tuple(handle, &tuple, &parse); ++ } ++ } ++ ++ /* Second pass: try to find an entry that isn't picky about ++ its base address, then try to grab any standard serial port ++ address, and finally try to get any free port. */ ++ i = first_tuple(handle, &tuple, &parse); ++ while (i != CS_NO_MORE_ITEMS) { ++ if ((i == CS_SUCCESS) && (cf->io.nwin > 0) ++ && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { ++ link->conf.ConfigIndex = cf->index; ++ for (j = 0; j < 5; j++) { ++ link->io.BasePort1 = base[j]; ++ link->io.IOAddrLines = base[j] ? 16 : 3; ++ i = CardServices(RequestIO, link->handle, &link->io); ++ if (i == CS_SUCCESS) ++ goto found_port; ++ } ++ } ++ i = next_tuple(handle, &tuple, &parse); ++ } ++ ++found_port: ++ if (i != CS_SUCCESS) { ++ printk(KERN_NOTICE "btuart_cs: No usable port range found. Giving up.\n"); ++ cs_error(link->handle, RequestIO, i); ++ goto failed; ++ } ++ ++ i = CardServices(RequestIRQ, link->handle, &link->irq); ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestIRQ, i); ++ link->irq.AssignedIRQ = 0; ++ } ++ ++ i = CardServices(RequestConfiguration, link->handle, &link->conf); ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestConfiguration, i); ++ goto failed; ++ } ++ ++ MOD_INC_USE_COUNT; ++ ++ if (btuart_open(info) != 0) ++ goto failed; ++ ++ strcpy(info->node.dev_name, info->hdev.name); ++ link->dev = &info->node; ++ link->state &= ~DEV_CONFIG_PENDING; ++ ++ return; ++ ++cs_failed: ++ cs_error(link->handle, last_fn, last_ret); ++ ++failed: ++ btuart_release((u_long) link); ++} ++ ++ ++void btuart_release(u_long arg) ++{ ++ dev_link_t *link = (dev_link_t *)arg; ++ btuart_info_t *info = link->priv; ++ ++ if (link->state & DEV_PRESENT) ++ btuart_close(info); ++ ++ MOD_DEC_USE_COUNT; ++ ++ link->dev = NULL; ++ ++ CardServices(ReleaseConfiguration, link->handle); ++ CardServices(ReleaseIO, link->handle, &link->io); ++ CardServices(ReleaseIRQ, link->handle, &link->irq); ++ ++ link->state &= ~DEV_CONFIG; ++} ++ ++ ++int btuart_event(event_t event, int priority, event_callback_args_t *args) ++{ ++ dev_link_t *link = args->client_data; ++ btuart_info_t *info = link->priv; ++ ++ switch (event) { ++ case CS_EVENT_CARD_REMOVAL: ++ link->state &= ~DEV_PRESENT; ++ if (link->state & DEV_CONFIG) { ++ btuart_close(info); ++ mod_timer(&link->release, jiffies + HZ / 20); ++ } ++ break; ++ case CS_EVENT_CARD_INSERTION: ++ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; ++ btuart_config(link); ++ break; ++ case CS_EVENT_PM_SUSPEND: ++ link->state |= DEV_SUSPEND; ++ /* Fall through... */ ++ case CS_EVENT_RESET_PHYSICAL: ++ if (link->state & DEV_CONFIG) ++ CardServices(ReleaseConfiguration, link->handle); ++ break; ++ case CS_EVENT_PM_RESUME: ++ link->state &= ~DEV_SUSPEND; ++ /* Fall through... */ ++ case CS_EVENT_CARD_RESET: ++ if (DEV_OK(link)) ++ CardServices(RequestConfiguration, link->handle, &link->conf); ++ break; ++ } ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Module initialization ======================== */ ++ ++ ++int __init init_btuart_cs(void) ++{ ++ servinfo_t serv; ++ int err; ++ ++ CardServices(GetCardServicesInfo, &serv); ++ if (serv.Revision != CS_RELEASE_CODE) { ++ printk(KERN_NOTICE "btuart_cs: Card Services release does not match!\n"); ++ return -1; ++ } ++ ++ err = register_pccard_driver(&dev_info, &btuart_attach, &btuart_detach); ++ ++ return err; ++} ++ ++ ++void __exit exit_btuart_cs(void) ++{ ++ unregister_pccard_driver(&dev_info); ++ ++ while (dev_list != NULL) ++ btuart_detach(dev_list); ++} ++ ++ ++module_init(init_btuart_cs); ++module_exit(exit_btuart_cs); ++ ++EXPORT_NO_SYMBOLS; +--- linux/drivers/bluetooth/Config.in~bluetooth-2.4.18-mh11 2001-09-07 18:28:38.000000000 +0200 ++++ linux/drivers/bluetooth/Config.in 2004-01-25 23:37:39.000000000 +0100 +@@ -1,8 +1,33 @@ ++# ++# Bluetooth HCI device drivers configuration ++# ++ + mainmenu_option next_comment + comment 'Bluetooth device drivers' + + dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB ++if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then ++ bool ' SCO (voice) support' CONFIG_BLUEZ_HCIUSB_SCO ++fi ++ + dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ +-dep_tristate 'HCI VHCI virtual HCI device driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ ++if [ "$CONFIG_BLUEZ_HCIUART" != "n" ]; then ++ bool ' UART (H4) protocol support' CONFIG_BLUEZ_HCIUART_H4 ++ bool ' BCSP protocol support' CONFIG_BLUEZ_HCIUART_BCSP ++ dep_bool ' Transmit CRC with every BCSP packet' CONFIG_BLUEZ_HCIUART_BCSP_TXCRC $CONFIG_BLUEZ_HCIUART_BCSP ++fi ++ ++dep_tristate 'HCI BlueFRITZ! USB driver' CONFIG_BLUEZ_HCIBFUSB $CONFIG_BLUEZ $CONFIG_USB ++ ++dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ ++ ++dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BLUEZ_HCIBT3C $CONFIG_PCMCIA $CONFIG_BLUEZ ++ ++dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ ++ ++dep_tristate 'HCI UART (PC Card) driver' CONFIG_BLUEZ_HCIBTUART $CONFIG_PCMCIA $CONFIG_BLUEZ ++ ++dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ + + endmenu ++ +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/drivers/bluetooth/dtl1_cs.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,858 @@ ++/* ++ * ++ * A driver for Nokia Connectivity Card DTL-1 devices ++ * ++ * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org> ++ * ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation; ++ * ++ * Software distributed under the License is distributed on an "AS ++ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++ * implied. See the License for the specific language governing ++ * rights and limitations under the License. ++ * ++ * The initial developer of the original code is David A. Hinds ++ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds ++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/types.h> ++#include <linux/sched.h> ++#include <linux/timer.h> ++#include <linux/errno.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/spinlock.h> ++ ++#include <linux/skbuff.h> ++#include <linux/string.h> ++#include <linux/serial.h> ++#include <linux/serial_reg.h> ++#include <asm/system.h> ++#include <asm/bitops.h> ++#include <asm/io.h> ++ ++#include <pcmcia/version.h> ++#include <pcmcia/cs_types.h> ++#include <pcmcia/cs.h> ++#include <pcmcia/cistpl.h> ++#include <pcmcia/ciscode.h> ++#include <pcmcia/ds.h> ++#include <pcmcia/cisreg.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++ ++ ++ ++/* ======================== Module parameters ======================== */ ++ ++ ++/* Bit map of interrupts to choose from */ ++static u_int irq_mask = 0xffff; ++static int irq_list[4] = { -1 }; ++ ++MODULE_PARM(irq_mask, "i"); ++MODULE_PARM(irq_list, "1-4i"); ++ ++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); ++MODULE_DESCRIPTION("BlueZ driver for Nokia Connectivity Card DTL-1"); ++MODULE_LICENSE("GPL"); ++ ++ ++ ++/* ======================== Local structures ======================== */ ++ ++ ++typedef struct dtl1_info_t { ++ dev_link_t link; ++ dev_node_t node; ++ ++ struct hci_dev hdev; ++ ++ spinlock_t lock; /* For serializing operations */ ++ ++ unsigned long flowmask; /* HCI flow mask */ ++ int ri_latch; ++ ++ struct sk_buff_head txq; ++ unsigned long tx_state; ++ ++ unsigned long rx_state; ++ unsigned long rx_count; ++ struct sk_buff *rx_skb; ++} dtl1_info_t; ++ ++ ++void dtl1_config(dev_link_t *link); ++void dtl1_release(u_long arg); ++int dtl1_event(event_t event, int priority, event_callback_args_t *args); ++ ++static dev_info_t dev_info = "dtl1_cs"; ++ ++dev_link_t *dtl1_attach(void); ++void dtl1_detach(dev_link_t *); ++ ++static dev_link_t *dev_list = NULL; ++ ++ ++/* Transmit states */ ++#define XMIT_SENDING 1 ++#define XMIT_WAKEUP 2 ++#define XMIT_WAITING 8 ++ ++/* Receiver States */ ++#define RECV_WAIT_NSH 0 ++#define RECV_WAIT_DATA 1 ++ ++ ++typedef struct { ++ u8 type; ++ u8 zero; ++ u16 len; ++} __attribute__ ((packed)) nsh_t; /* Nokia Specific Header */ ++ ++#define NSHL 4 /* Nokia Specific Header Length */ ++ ++ ++ ++/* ======================== Interrupt handling ======================== */ ++ ++ ++static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) ++{ ++ int actual = 0; ++ ++ /* Tx FIFO should be empty */ ++ if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) ++ return 0; ++ ++ /* Fill FIFO with current frame */ ++ while ((fifo_size-- > 0) && (actual < len)) { ++ /* Transmit next byte */ ++ outb(buf[actual], iobase + UART_TX); ++ actual++; ++ } ++ ++ return actual; ++} ++ ++ ++static void dtl1_write_wakeup(dtl1_info_t *info) ++{ ++ if (!info) { ++ printk(KERN_WARNING "dtl1_cs: Call of write_wakeup for unknown device.\n"); ++ return; ++ } ++ ++ if (test_bit(XMIT_WAITING, &(info->tx_state))) { ++ set_bit(XMIT_WAKEUP, &(info->tx_state)); ++ return; ++ } ++ ++ if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { ++ set_bit(XMIT_WAKEUP, &(info->tx_state)); ++ return; ++ } ++ ++ do { ++ register unsigned int iobase = info->link.io.BasePort1; ++ register struct sk_buff *skb; ++ register int len; ++ ++ clear_bit(XMIT_WAKEUP, &(info->tx_state)); ++ ++ if (!(info->link.state & DEV_PRESENT)) ++ return; ++ ++ if (!(skb = skb_dequeue(&(info->txq)))) ++ break; ++ ++ /* Send frame */ ++ len = dtl1_write(iobase, 32, skb->data, skb->len); ++ ++ if (len == skb->len) { ++ set_bit(XMIT_WAITING, &(info->tx_state)); ++ kfree_skb(skb); ++ } else { ++ skb_pull(skb, len); ++ skb_queue_head(&(info->txq), skb); ++ } ++ ++ info->hdev.stat.byte_tx += len; ++ ++ } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); ++ ++ clear_bit(XMIT_SENDING, &(info->tx_state)); ++} ++ ++ ++static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb) ++{ ++ u8 flowmask = *(u8 *)skb->data; ++ int i; ++ ++ printk(KERN_INFO "dtl1_cs: Nokia control data = "); ++ for (i = 0; i < skb->len; i++) { ++ printk("%02x ", skb->data[i]); ++ } ++ printk("\n"); ++ ++ /* transition to active state */ ++ if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) { ++ clear_bit(XMIT_WAITING, &(info->tx_state)); ++ dtl1_write_wakeup(info); ++ } ++ ++ info->flowmask = flowmask; ++ ++ kfree_skb(skb); ++} ++ ++ ++static void dtl1_receive(dtl1_info_t *info) ++{ ++ unsigned int iobase; ++ nsh_t *nsh; ++ int boguscount = 0; ++ ++ if (!info) { ++ printk(KERN_WARNING "dtl1_cs: Call of receive for unknown device.\n"); ++ return; ++ } ++ ++ iobase = info->link.io.BasePort1; ++ ++ do { ++ info->hdev.stat.byte_rx++; ++ ++ /* Allocate packet */ ++ if (info->rx_skb == NULL) ++ if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { ++ printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n"); ++ info->rx_state = RECV_WAIT_NSH; ++ info->rx_count = NSHL; ++ return; ++ } ++ ++ *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); ++ nsh = (nsh_t *)info->rx_skb->data; ++ ++ info->rx_count--; ++ ++ if (info->rx_count == 0) { ++ ++ switch (info->rx_state) { ++ case RECV_WAIT_NSH: ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = nsh->len + (nsh->len & 0x0001); ++ break; ++ case RECV_WAIT_DATA: ++ info->rx_skb->pkt_type = nsh->type; ++ ++ /* remove PAD byte if it exists */ ++ if (nsh->len & 0x0001) { ++ info->rx_skb->tail--; ++ info->rx_skb->len--; ++ } ++ ++ /* remove NSH */ ++ skb_pull(info->rx_skb, NSHL); ++ ++ switch (info->rx_skb->pkt_type) { ++ case 0x80: ++ /* control data for the Nokia Card */ ++ dtl1_control(info, info->rx_skb); ++ break; ++ case 0x82: ++ case 0x83: ++ case 0x84: ++ /* send frame to the HCI layer */ ++ info->rx_skb->dev = (void *)&(info->hdev); ++ info->rx_skb->pkt_type &= 0x0f; ++ hci_recv_frame(info->rx_skb); ++ break; ++ default: ++ /* unknown packet */ ++ printk(KERN_WARNING "dtl1_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type); ++ kfree_skb(info->rx_skb); ++ break; ++ } ++ ++ info->rx_state = RECV_WAIT_NSH; ++ info->rx_count = NSHL; ++ info->rx_skb = NULL; ++ break; ++ } ++ ++ } ++ ++ /* Make sure we don't stay here to long */ ++ if (boguscount++ > 32) ++ break; ++ ++ } while (inb(iobase + UART_LSR) & UART_LSR_DR); ++} ++ ++ ++void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) ++{ ++ dtl1_info_t *info = dev_inst; ++ unsigned int iobase; ++ unsigned char msr; ++ int boguscount = 0; ++ int iir, lsr; ++ ++ if (!info) { ++ printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq); ++ return; ++ } ++ ++ iobase = info->link.io.BasePort1; ++ ++ spin_lock(&(info->lock)); ++ ++ iir = inb(iobase + UART_IIR) & UART_IIR_ID; ++ while (iir) { ++ ++ /* Clear interrupt */ ++ lsr = inb(iobase + UART_LSR); ++ ++ switch (iir) { ++ case UART_IIR_RLSI: ++ printk(KERN_NOTICE "dtl1_cs: RLSI\n"); ++ break; ++ case UART_IIR_RDI: ++ /* Receive interrupt */ ++ dtl1_receive(info); ++ break; ++ case UART_IIR_THRI: ++ if (lsr & UART_LSR_THRE) { ++ /* Transmitter ready for data */ ++ dtl1_write_wakeup(info); ++ } ++ break; ++ default: ++ printk(KERN_NOTICE "dtl1_cs: Unhandled IIR=%#x\n", iir); ++ break; ++ } ++ ++ /* Make sure we don't stay here to long */ ++ if (boguscount++ > 100) ++ break; ++ ++ iir = inb(iobase + UART_IIR) & UART_IIR_ID; ++ ++ } ++ ++ msr = inb(iobase + UART_MSR); ++ ++ if (info->ri_latch ^ (msr & UART_MSR_RI)) { ++ info->ri_latch = msr & UART_MSR_RI; ++ clear_bit(XMIT_WAITING, &(info->tx_state)); ++ dtl1_write_wakeup(info); ++ } ++ ++ spin_unlock(&(info->lock)); ++} ++ ++ ++ ++/* ======================== HCI interface ======================== */ ++ ++ ++static int dtl1_hci_open(struct hci_dev *hdev) ++{ ++ set_bit(HCI_RUNNING, &(hdev->flags)); ++ ++ return 0; ++} ++ ++ ++static int dtl1_hci_flush(struct hci_dev *hdev) ++{ ++ dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data); ++ ++ /* Drop TX queue */ ++ skb_queue_purge(&(info->txq)); ++ ++ return 0; ++} ++ ++ ++static int dtl1_hci_close(struct hci_dev *hdev) ++{ ++ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) ++ return 0; ++ ++ dtl1_hci_flush(hdev); ++ ++ return 0; ++} ++ ++ ++static int dtl1_hci_send_frame(struct sk_buff *skb) ++{ ++ dtl1_info_t *info; ++ struct hci_dev *hdev = (struct hci_dev *)(skb->dev); ++ struct sk_buff *s; ++ nsh_t nsh; ++ ++ if (!hdev) { ++ printk(KERN_WARNING "dtl1_cs: Frame for unknown HCI device (hdev=NULL)."); ++ return -ENODEV; ++ } ++ ++ info = (dtl1_info_t *)(hdev->driver_data); ++ ++ switch (skb->pkt_type) { ++ case HCI_COMMAND_PKT: ++ hdev->stat.cmd_tx++; ++ nsh.type = 0x81; ++ break; ++ case HCI_ACLDATA_PKT: ++ hdev->stat.acl_tx++; ++ nsh.type = 0x82; ++ break; ++ case HCI_SCODATA_PKT: ++ hdev->stat.sco_tx++; ++ nsh.type = 0x83; ++ break; ++ }; ++ ++ nsh.zero = 0; ++ nsh.len = skb->len; ++ ++ s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC); ++ skb_reserve(s, NSHL); ++ memcpy(skb_put(s, skb->len), skb->data, skb->len); ++ if (skb->len & 0x0001) ++ *skb_put(s, 1) = 0; /* PAD */ ++ ++ /* Prepend skb with Nokia frame header and queue */ ++ memcpy(skb_push(s, NSHL), &nsh, NSHL); ++ skb_queue_tail(&(info->txq), s); ++ ++ dtl1_write_wakeup(info); ++ ++ kfree_skb(skb); ++ ++ return 0; ++} ++ ++ ++static void dtl1_hci_destruct(struct hci_dev *hdev) ++{ ++} ++ ++ ++static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) ++{ ++ return -ENOIOCTLCMD; ++} ++ ++ ++ ++/* ======================== Card services HCI interaction ======================== */ ++ ++ ++int dtl1_open(dtl1_info_t *info) ++{ ++ unsigned long flags; ++ unsigned int iobase = info->link.io.BasePort1; ++ struct hci_dev *hdev; ++ ++ spin_lock_init(&(info->lock)); ++ ++ skb_queue_head_init(&(info->txq)); ++ ++ info->rx_state = RECV_WAIT_NSH; ++ info->rx_count = NSHL; ++ info->rx_skb = NULL; ++ ++ set_bit(XMIT_WAITING, &(info->tx_state)); ++ ++ spin_lock_irqsave(&(info->lock), flags); ++ ++ /* Reset UART */ ++ outb(0, iobase + UART_MCR); ++ ++ /* Turn off interrupts */ ++ outb(0, iobase + UART_IER); ++ ++ /* Initialize UART */ ++ outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */ ++ outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR); ++ ++ info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI; ++ ++ /* Turn on interrupts */ ++ outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); ++ ++ spin_unlock_irqrestore(&(info->lock), flags); ++ ++ /* Timeout before it is safe to send the first HCI packet */ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(HZ * 2); ++ ++ ++ /* Initialize and register HCI device */ ++ ++ hdev = &(info->hdev); ++ ++ hdev->type = HCI_PCCARD; ++ hdev->driver_data = info; ++ ++ hdev->open = dtl1_hci_open; ++ hdev->close = dtl1_hci_close; ++ hdev->flush = dtl1_hci_flush; ++ hdev->send = dtl1_hci_send_frame; ++ hdev->destruct = dtl1_hci_destruct; ++ hdev->ioctl = dtl1_hci_ioctl; ++ ++ if (hci_register_dev(hdev) < 0) { ++ printk(KERN_WARNING "dtl1_cs: Can't register HCI device %s.\n", hdev->name); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++ ++int dtl1_close(dtl1_info_t *info) ++{ ++ unsigned long flags; ++ unsigned int iobase = info->link.io.BasePort1; ++ struct hci_dev *hdev = &(info->hdev); ++ ++ dtl1_hci_close(hdev); ++ ++ spin_lock_irqsave(&(info->lock), flags); ++ ++ /* Reset UART */ ++ outb(0, iobase + UART_MCR); ++ ++ /* Turn off interrupts */ ++ outb(0, iobase + UART_IER); ++ ++ spin_unlock_irqrestore(&(info->lock), flags); ++ ++ if (hci_unregister_dev(hdev) < 0) ++ printk(KERN_WARNING "dtl1_cs: Can't unregister HCI device %s.\n", hdev->name); ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Card services ======================== */ ++ ++ ++static void cs_error(client_handle_t handle, int func, int ret) ++{ ++ error_info_t err = { func, ret }; ++ ++ CardServices(ReportError, handle, &err); ++} ++ ++ ++dev_link_t *dtl1_attach(void) ++{ ++ dtl1_info_t *info; ++ client_reg_t client_reg; ++ dev_link_t *link; ++ int i, ret; ++ ++ /* Create new info device */ ++ info = kmalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return NULL; ++ memset(info, 0, sizeof(*info)); ++ ++ link = &info->link; ++ link->priv = info; ++ ++ link->release.function = &dtl1_release; ++ link->release.data = (u_long)link; ++ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; ++ link->io.NumPorts1 = 8; ++ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; ++ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; ++ ++ if (irq_list[0] == -1) ++ link->irq.IRQInfo2 = irq_mask; ++ else ++ for (i = 0; i < 4; i++) ++ link->irq.IRQInfo2 |= 1 << irq_list[i]; ++ ++ link->irq.Handler = dtl1_interrupt; ++ link->irq.Instance = info; ++ ++ link->conf.Attributes = CONF_ENABLE_IRQ; ++ link->conf.Vcc = 50; ++ link->conf.IntType = INT_MEMORY_AND_IO; ++ ++ /* Register with Card Services */ ++ link->next = dev_list; ++ dev_list = link; ++ client_reg.dev_info = &dev_info; ++ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; ++ client_reg.EventMask = ++ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | ++ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | ++ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; ++ client_reg.event_handler = &dtl1_event; ++ client_reg.Version = 0x0210; ++ client_reg.event_callback_args.client_data = link; ++ ++ ret = CardServices(RegisterClient, &link->handle, &client_reg); ++ if (ret != CS_SUCCESS) { ++ cs_error(link->handle, RegisterClient, ret); ++ dtl1_detach(link); ++ return NULL; ++ } ++ ++ return link; ++} ++ ++ ++void dtl1_detach(dev_link_t *link) ++{ ++ dtl1_info_t *info = link->priv; ++ dev_link_t **linkp; ++ int ret; ++ ++ /* Locate device structure */ ++ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) ++ if (*linkp == link) ++ break; ++ ++ if (*linkp == NULL) ++ return; ++ ++ del_timer(&link->release); ++ if (link->state & DEV_CONFIG) ++ dtl1_release((u_long)link); ++ ++ if (link->handle) { ++ ret = CardServices(DeregisterClient, link->handle); ++ if (ret != CS_SUCCESS) ++ cs_error(link->handle, DeregisterClient, ret); ++ } ++ ++ /* Unlink device structure, free bits */ ++ *linkp = link->next; ++ ++ kfree(info); ++} ++ ++ ++static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) ++{ ++ int i; ++ ++ i = CardServices(fn, handle, tuple); ++ if (i != CS_SUCCESS) ++ return CS_NO_MORE_ITEMS; ++ ++ i = CardServices(GetTupleData, handle, tuple); ++ if (i != CS_SUCCESS) ++ return i; ++ ++ return CardServices(ParseTuple, handle, tuple, parse); ++} ++ ++ ++#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) ++#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) ++ ++void dtl1_config(dev_link_t *link) ++{ ++ client_handle_t handle = link->handle; ++ dtl1_info_t *info = link->priv; ++ tuple_t tuple; ++ u_short buf[256]; ++ cisparse_t parse; ++ cistpl_cftable_entry_t *cf = &parse.cftable_entry; ++ config_info_t config; ++ int i, last_ret, last_fn; ++ ++ tuple.TupleData = (cisdata_t *)buf; ++ tuple.TupleOffset = 0; ++ tuple.TupleDataMax = 255; ++ tuple.Attributes = 0; ++ ++ /* Get configuration register information */ ++ tuple.DesiredTuple = CISTPL_CONFIG; ++ last_ret = first_tuple(handle, &tuple, &parse); ++ if (last_ret != CS_SUCCESS) { ++ last_fn = ParseTuple; ++ goto cs_failed; ++ } ++ link->conf.ConfigBase = parse.config.base; ++ link->conf.Present = parse.config.rmask[0]; ++ ++ /* Configure card */ ++ link->state |= DEV_CONFIG; ++ i = CardServices(GetConfigurationInfo, handle, &config); ++ link->conf.Vcc = config.Vcc; ++ ++ tuple.TupleData = (cisdata_t *)buf; ++ tuple.TupleOffset = 0; ++ tuple.TupleDataMax = 255; ++ tuple.Attributes = 0; ++ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; ++ ++ /* Look for a generic full-sized window */ ++ link->io.NumPorts1 = 8; ++ i = first_tuple(handle, &tuple, &parse); ++ while (i != CS_NO_MORE_ITEMS) { ++ if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) { ++ link->conf.ConfigIndex = cf->index; ++ link->io.BasePort1 = cf->io.win[0].base; ++ link->io.NumPorts1 = cf->io.win[0].len; /*yo */ ++ link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; ++ i = CardServices(RequestIO, link->handle, &link->io); ++ if (i == CS_SUCCESS) ++ break; ++ } ++ i = next_tuple(handle, &tuple, &parse); ++ } ++ ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestIO, i); ++ goto failed; ++ } ++ ++ i = CardServices(RequestIRQ, link->handle, &link->irq); ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestIRQ, i); ++ link->irq.AssignedIRQ = 0; ++ } ++ ++ i = CardServices(RequestConfiguration, link->handle, &link->conf); ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestConfiguration, i); ++ goto failed; ++ } ++ ++ MOD_INC_USE_COUNT; ++ ++ if (dtl1_open(info) != 0) ++ goto failed; ++ ++ strcpy(info->node.dev_name, info->hdev.name); ++ link->dev = &info->node; ++ link->state &= ~DEV_CONFIG_PENDING; ++ ++ return; ++ ++cs_failed: ++ cs_error(link->handle, last_fn, last_ret); ++ ++failed: ++ dtl1_release((u_long)link); ++} ++ ++ ++void dtl1_release(u_long arg) ++{ ++ dev_link_t *link = (dev_link_t *)arg; ++ dtl1_info_t *info = link->priv; ++ ++ if (link->state & DEV_PRESENT) ++ dtl1_close(info); ++ ++ MOD_DEC_USE_COUNT; ++ ++ link->dev = NULL; ++ ++ CardServices(ReleaseConfiguration, link->handle); ++ CardServices(ReleaseIO, link->handle, &link->io); ++ CardServices(ReleaseIRQ, link->handle, &link->irq); ++ ++ link->state &= ~DEV_CONFIG; ++} ++ ++ ++int dtl1_event(event_t event, int priority, event_callback_args_t *args) ++{ ++ dev_link_t *link = args->client_data; ++ dtl1_info_t *info = link->priv; ++ ++ switch (event) { ++ case CS_EVENT_CARD_REMOVAL: ++ link->state &= ~DEV_PRESENT; ++ if (link->state & DEV_CONFIG) { ++ dtl1_close(info); ++ mod_timer(&link->release, jiffies + HZ / 20); ++ } ++ break; ++ case CS_EVENT_CARD_INSERTION: ++ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; ++ dtl1_config(link); ++ break; ++ case CS_EVENT_PM_SUSPEND: ++ link->state |= DEV_SUSPEND; ++ /* Fall through... */ ++ case CS_EVENT_RESET_PHYSICAL: ++ if (link->state & DEV_CONFIG) ++ CardServices(ReleaseConfiguration, link->handle); ++ break; ++ case CS_EVENT_PM_RESUME: ++ link->state &= ~DEV_SUSPEND; ++ /* Fall through... */ ++ case CS_EVENT_CARD_RESET: ++ if (DEV_OK(link)) ++ CardServices(RequestConfiguration, link->handle, &link->conf); ++ break; ++ } ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Module initialization ======================== */ ++ ++ ++int __init init_dtl1_cs(void) ++{ ++ servinfo_t serv; ++ int err; ++ ++ CardServices(GetCardServicesInfo, &serv); ++ if (serv.Revision != CS_RELEASE_CODE) { ++ printk(KERN_NOTICE "dtl1_cs: Card Services release does not match!\n"); ++ return -1; ++ } ++ ++ err = register_pccard_driver(&dev_info, &dtl1_attach, &dtl1_detach); ++ ++ return err; ++} ++ ++ ++void __exit exit_dtl1_cs(void) ++{ ++ unregister_pccard_driver(&dev_info); ++ ++ while (dev_list != NULL) ++ dtl1_detach(dev_list); ++} ++ ++ ++module_init(init_dtl1_cs); ++module_exit(exit_dtl1_cs); ++ ++EXPORT_NO_SYMBOLS; +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/drivers/bluetooth/hci_bcsp.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,710 @@ ++/* ++ BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ). ++ Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com> ++ ++ Based on ++ hci_h4.c by Maxim Krasnyansky <maxk@qualcomm.com> ++ ABCSP by Carl Orsborn <cjo@csr.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#define VERSION "0.1" ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/version.h> ++#include <linux/config.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/sched.h> ++#include <linux/types.h> ++#include <linux/fcntl.h> ++#include <linux/interrupt.h> ++#include <linux/ptrace.h> ++#include <linux/poll.h> ++ ++#include <linux/slab.h> ++#include <linux/tty.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/signal.h> ++#include <linux/ioctl.h> ++#include <linux/skbuff.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++#include "hci_uart.h" ++#include "hci_bcsp.h" ++ ++#ifndef HCI_UART_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#undef BT_DMP ++#define BT_DMP( A... ) ++#endif ++ ++/* ---- BCSP CRC calculation ---- */ ++ ++/* Table for calculating CRC for polynomial 0x1021, LSB processed first, ++initial value 0xffff, bits shifted in reverse order. */ ++ ++static const u16 crc_table[] = { ++ 0x0000, 0x1081, 0x2102, 0x3183, ++ 0x4204, 0x5285, 0x6306, 0x7387, ++ 0x8408, 0x9489, 0xa50a, 0xb58b, ++ 0xc60c, 0xd68d, 0xe70e, 0xf78f ++}; ++ ++/* Initialise the crc calculator */ ++#define BCSP_CRC_INIT(x) x = 0xffff ++ ++/* ++ Update crc with next data byte ++ ++ Implementation note ++ The data byte is treated as two nibbles. The crc is generated ++ in reverse, i.e., bits are fed into the register from the top. ++*/ ++static void bcsp_crc_update(u16 *crc, u8 d) ++{ ++ u16 reg = *crc; ++ ++ reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f]; ++ reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f]; ++ ++ *crc = reg; ++} ++ ++/* ++ Get reverse of generated crc ++ ++ Implementation note ++ The crc generator (bcsp_crc_init() and bcsp_crc_update()) ++ creates a reversed crc, so it needs to be swapped back before ++ being passed on. ++*/ ++static u16 bcsp_crc_reverse(u16 crc) ++{ ++ u16 b, rev; ++ ++ for (b = 0, rev = 0; b < 16; b++) { ++ rev = rev << 1; ++ rev |= (crc & 1); ++ crc = crc >> 1; ++ } ++ return (rev); ++} ++ ++/* ---- BCSP core ---- */ ++ ++static void bcsp_slip_msgdelim(struct sk_buff *skb) ++{ ++ const char pkt_delim = 0xc0; ++ memcpy(skb_put(skb, 1), &pkt_delim, 1); ++} ++ ++static void bcsp_slip_one_byte(struct sk_buff *skb, u8 c) ++{ ++ const char esc_c0[2] = { 0xdb, 0xdc }; ++ const char esc_db[2] = { 0xdb, 0xdd }; ++ ++ switch (c) { ++ case 0xc0: ++ memcpy(skb_put(skb, 2), &esc_c0, 2); ++ break; ++ case 0xdb: ++ memcpy(skb_put(skb, 2), &esc_db, 2); ++ break; ++ default: ++ memcpy(skb_put(skb, 1), &c, 1); ++ } ++} ++ ++static int bcsp_enqueue(struct hci_uart *hu, struct sk_buff *skb) ++{ ++ struct bcsp_struct *bcsp = hu->priv; ++ ++ if (skb->len > 0xFFF) { ++ BT_ERR("Packet too long"); ++ kfree_skb(skb); ++ return 0; ++ } ++ ++ switch (skb->pkt_type) { ++ case HCI_ACLDATA_PKT: ++ case HCI_COMMAND_PKT: ++ skb_queue_tail(&bcsp->rel, skb); ++ break; ++ ++ case HCI_SCODATA_PKT: ++ skb_queue_tail(&bcsp->unrel, skb); ++ break; ++ ++ default: ++ BT_ERR("Unknown packet type"); ++ kfree_skb(skb); ++ break; ++ } ++ return 0; ++} ++ ++static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data, ++ int len, int pkt_type) ++{ ++ struct sk_buff *nskb; ++ u8 hdr[4], chan; ++ int rel, i; ++ ++#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC ++ u16 BCSP_CRC_INIT(bcsp_txmsg_crc); ++#endif ++ ++ switch (pkt_type) { ++ case HCI_ACLDATA_PKT: ++ chan = 6; /* BCSP ACL channel */ ++ rel = 1; /* reliable channel */ ++ break; ++ case HCI_COMMAND_PKT: ++ chan = 5; /* BCSP cmd/evt channel */ ++ rel = 1; /* reliable channel */ ++ break; ++ case HCI_SCODATA_PKT: ++ chan = 7; /* BCSP SCO channel */ ++ rel = 0; /* unreliable channel */ ++ break; ++ case BCSP_LE_PKT: ++ chan = 1; /* BCSP LE channel */ ++ rel = 0; /* unreliable channel */ ++ break; ++ case BCSP_ACK_PKT: ++ chan = 0; /* BCSP internal channel */ ++ rel = 0; /* unreliable channel */ ++ break; ++ default: ++ BT_ERR("Unknown packet type"); ++ return NULL; ++ } ++ ++ /* Max len of packet: (original len +4(bcsp hdr) +2(crc))*2 ++ (because bytes 0xc0 and 0xdb are escaped, worst case is ++ when the packet is all made of 0xc0 and 0xdb :) ) ++ + 2 (0xc0 delimiters at start and end). */ ++ ++ nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC); ++ if (!nskb) ++ return NULL; ++ ++ nskb->pkt_type = pkt_type; ++ ++ bcsp_slip_msgdelim(nskb); ++ ++ hdr[0] = bcsp->rxseq_txack << 3; ++ bcsp->txack_req = 0; ++ BT_DBG("We request packet no %u to card", bcsp->rxseq_txack); ++ ++ if (rel) { ++ hdr[0] |= 0x80 + bcsp->msgq_txseq; ++ BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq); ++ bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07; ++ } ++#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC ++ hdr[0] |= 0x40; ++#endif ++ ++ hdr[1] = (len << 4) & 0xFF; ++ hdr[1] |= chan; ++ hdr[2] = len >> 4; ++ hdr[3] = ~(hdr[0] + hdr[1] + hdr[2]); ++ ++ /* Put BCSP header */ ++ for (i = 0; i < 4; i++) { ++ bcsp_slip_one_byte(nskb, hdr[i]); ++#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC ++ bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]); ++#endif ++ } ++ ++ /* Put payload */ ++ for (i = 0; i < len; i++) { ++ bcsp_slip_one_byte(nskb, data[i]); ++#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC ++ bcsp_crc_update(&bcsp_txmsg_crc, data[i]); ++#endif ++ } ++ ++#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC ++ /* Put CRC */ ++ bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc); ++ bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff)); ++ bcsp_slip_one_byte(nskb, (u8) (bcsp_txmsg_crc & 0x00ff)); ++#endif ++ ++ bcsp_slip_msgdelim(nskb); ++ return nskb; ++} ++ ++/* This is a rewrite of pkt_avail in ABCSP */ ++static struct sk_buff *bcsp_dequeue(struct hci_uart *hu) ++{ ++ struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv; ++ unsigned long flags; ++ struct sk_buff *skb; ++ ++ /* First of all, check for unreliable messages in the queue, ++ since they have priority */ ++ ++ if ((skb = skb_dequeue(&bcsp->unrel)) != NULL) { ++ struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type); ++ if (nskb) { ++ kfree_skb(skb); ++ return nskb; ++ } else { ++ skb_queue_head(&bcsp->unrel, skb); ++ BT_ERR("Could not dequeue pkt because alloc_skb failed"); ++ } ++ } ++ ++ /* Now, try to send a reliable pkt. We can only send a ++ reliable packet if the number of packets sent but not yet ack'ed ++ is < than the winsize */ ++ ++ spin_lock_irqsave(&bcsp->unack.lock, flags); ++ ++ if (bcsp->unack.qlen < BCSP_TXWINSIZE && (skb = skb_dequeue(&bcsp->rel)) != NULL) { ++ struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type); ++ if (nskb) { ++ __skb_queue_tail(&bcsp->unack, skb); ++ mod_timer(&bcsp->tbcsp, jiffies + HZ / 4); ++ spin_unlock_irqrestore(&bcsp->unack.lock, flags); ++ return nskb; ++ } else { ++ skb_queue_head(&bcsp->rel, skb); ++ BT_ERR("Could not dequeue pkt because alloc_skb failed"); ++ } ++ } ++ ++ spin_unlock_irqrestore(&bcsp->unack.lock, flags); ++ ++ ++ /* We could not send a reliable packet, either because there are ++ none or because there are too many unack'ed pkts. Did we receive ++ any packets we have not acknowledged yet ? */ ++ ++ if (bcsp->txack_req) { ++ /* if so, craft an empty ACK pkt and send it on BCSP unreliable ++ channel 0 */ ++ struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, NULL, 0, BCSP_ACK_PKT); ++ return nskb; ++ } ++ ++ /* We have nothing to send */ ++ return NULL; ++} ++ ++static int bcsp_flush(struct hci_uart *hu) ++{ ++ BT_DBG("hu %p", hu); ++ return 0; ++} ++ ++/* Remove ack'ed packets */ ++static void bcsp_pkt_cull(struct bcsp_struct *bcsp) ++{ ++ unsigned long flags; ++ struct sk_buff *skb; ++ int i, pkts_to_be_removed; ++ u8 seqno; ++ ++ spin_lock_irqsave(&bcsp->unack.lock, flags); ++ ++ pkts_to_be_removed = bcsp->unack.qlen; ++ seqno = bcsp->msgq_txseq; ++ ++ while (pkts_to_be_removed) { ++ if (bcsp->rxack == seqno) ++ break; ++ pkts_to_be_removed--; ++ seqno = (seqno - 1) & 0x07; ++ } ++ ++ if (bcsp->rxack != seqno) ++ BT_ERR("Peer acked invalid packet"); ++ ++ BT_DBG("Removing %u pkts out of %u, up to seqno %u", ++ pkts_to_be_removed, bcsp->unack.qlen, (seqno - 1) & 0x07); ++ ++ for (i = 0, skb = ((struct sk_buff *) &bcsp->unack)->next; i < pkts_to_be_removed ++ && skb != (struct sk_buff *) &bcsp->unack; i++) { ++ struct sk_buff *nskb; ++ ++ nskb = skb->next; ++ __skb_unlink(skb, &bcsp->unack); ++ kfree_skb(skb); ++ skb = nskb; ++ } ++ if (bcsp->unack.qlen == 0) ++ del_timer(&bcsp->tbcsp); ++ spin_unlock_irqrestore(&bcsp->unack.lock, flags); ++ ++ if (i != pkts_to_be_removed) ++ BT_ERR("Removed only %u out of %u pkts", i, pkts_to_be_removed); ++} ++ ++/* Handle BCSP link-establishment packets. When we ++ detect a "sync" packet, symptom that the BT module has reset, ++ we do nothing :) (yet) */ ++static void bcsp_handle_le_pkt(struct hci_uart *hu) ++{ ++ struct bcsp_struct *bcsp = hu->priv; ++ u8 conf_pkt[4] = { 0xad, 0xef, 0xac, 0xed }; ++ u8 conf_rsp_pkt[4] = { 0xde, 0xad, 0xd0, 0xd0 }; ++ u8 sync_pkt[4] = { 0xda, 0xdc, 0xed, 0xed }; ++ ++ /* spot "conf" pkts and reply with a "conf rsp" pkt */ ++ if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 && ++ !memcmp(&bcsp->rx_skb->data[4], conf_pkt, 4)) { ++ struct sk_buff *nskb = alloc_skb(4, GFP_ATOMIC); ++ ++ BT_DBG("Found a LE conf pkt"); ++ if (!nskb) ++ return; ++ memcpy(skb_put(nskb, 4), conf_rsp_pkt, 4); ++ nskb->pkt_type = BCSP_LE_PKT; ++ ++ skb_queue_head(&bcsp->unrel, nskb); ++ hci_uart_tx_wakeup(hu); ++ } ++ /* Spot "sync" pkts. If we find one...disaster! */ ++ else if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 && ++ !memcmp(&bcsp->rx_skb->data[4], sync_pkt, 4)) { ++ BT_ERR("Found a LE sync pkt, card has reset"); ++ } ++} ++ ++static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char byte) ++{ ++ const u8 c0 = 0xc0, db = 0xdb; ++ ++ switch (bcsp->rx_esc_state) { ++ case BCSP_ESCSTATE_NOESC: ++ switch (byte) { ++ case 0xdb: ++ bcsp->rx_esc_state = BCSP_ESCSTATE_ESC; ++ break; ++ default: ++ memcpy(skb_put(bcsp->rx_skb, 1), &byte, 1); ++ if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && ++ bcsp->rx_state != BCSP_W4_CRC) ++ bcsp_crc_update(&bcsp->message_crc, byte); ++ bcsp->rx_count--; ++ } ++ break; ++ ++ case BCSP_ESCSTATE_ESC: ++ switch (byte) { ++ case 0xdc: ++ memcpy(skb_put(bcsp->rx_skb, 1), &c0, 1); ++ if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && ++ bcsp->rx_state != BCSP_W4_CRC) ++ bcsp_crc_update(&bcsp-> message_crc, 0xc0); ++ bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC; ++ bcsp->rx_count--; ++ break; ++ ++ case 0xdd: ++ memcpy(skb_put(bcsp->rx_skb, 1), &db, 1); ++ if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && ++ bcsp->rx_state != BCSP_W4_CRC) ++ bcsp_crc_update(&bcsp-> message_crc, 0xdb); ++ bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC; ++ bcsp->rx_count--; ++ break; ++ ++ default: ++ BT_ERR ("Invalid byte %02x after esc byte", byte); ++ kfree_skb(bcsp->rx_skb); ++ bcsp->rx_skb = NULL; ++ bcsp->rx_state = BCSP_W4_PKT_DELIMITER; ++ bcsp->rx_count = 0; ++ } ++ } ++} ++ ++static inline void bcsp_complete_rx_pkt(struct hci_uart *hu) ++{ ++ struct bcsp_struct *bcsp = hu->priv; ++ int pass_up; ++ ++ if (bcsp->rx_skb->data[0] & 0x80) { /* reliable pkt */ ++ BT_DBG("Received seqno %u from card", bcsp->rxseq_txack); ++ bcsp->rxseq_txack++; ++ bcsp->rxseq_txack %= 0x8; ++ bcsp->txack_req = 1; ++ ++ /* If needed, transmit an ack pkt */ ++ hci_uart_tx_wakeup(hu); ++ } ++ ++ bcsp->rxack = (bcsp->rx_skb->data[0] >> 3) & 0x07; ++ BT_DBG("Request for pkt %u from card", bcsp->rxack); ++ ++ bcsp_pkt_cull(bcsp); ++ if ((bcsp->rx_skb->data[1] & 0x0f) == 6 && ++ bcsp->rx_skb->data[0] & 0x80) { ++ bcsp->rx_skb->pkt_type = HCI_ACLDATA_PKT; ++ pass_up = 1; ++ } else if ((bcsp->rx_skb->data[1] & 0x0f) == 5 && ++ bcsp->rx_skb->data[0] & 0x80) { ++ bcsp->rx_skb->pkt_type = HCI_EVENT_PKT; ++ pass_up = 1; ++ } else if ((bcsp->rx_skb->data[1] & 0x0f) == 7) { ++ bcsp->rx_skb->pkt_type = HCI_SCODATA_PKT; ++ pass_up = 1; ++ } else if ((bcsp->rx_skb->data[1] & 0x0f) == 1 && ++ !(bcsp->rx_skb->data[0] & 0x80)) { ++ bcsp_handle_le_pkt(hu); ++ pass_up = 0; ++ } else ++ pass_up = 0; ++ ++ if (!pass_up) { ++ if ((bcsp->rx_skb->data[1] & 0x0f) != 0 && ++ (bcsp->rx_skb->data[1] & 0x0f) != 1) { ++ BT_ERR ("Packet for unknown channel (%u %s)", ++ bcsp->rx_skb->data[1] & 0x0f, ++ bcsp->rx_skb->data[0] & 0x80 ? ++ "reliable" : "unreliable"); ++ } ++ kfree_skb(bcsp->rx_skb); ++ } else { ++ /* Pull out BCSP hdr */ ++ skb_pull(bcsp->rx_skb, 4); ++ ++ hci_recv_frame(bcsp->rx_skb); ++ } ++ bcsp->rx_state = BCSP_W4_PKT_DELIMITER; ++ bcsp->rx_skb = NULL; ++} ++ ++/* Recv data */ ++static int bcsp_recv(struct hci_uart *hu, void *data, int count) ++{ ++ struct bcsp_struct *bcsp = hu->priv; ++ register unsigned char *ptr; ++ ++ BT_DBG("hu %p count %d rx_state %ld rx_count %ld", ++ hu, count, bcsp->rx_state, bcsp->rx_count); ++ ++ ptr = data; ++ while (count) { ++ if (bcsp->rx_count) { ++ if (*ptr == 0xc0) { ++ BT_ERR("Short BCSP packet"); ++ kfree_skb(bcsp->rx_skb); ++ bcsp->rx_state = BCSP_W4_PKT_START; ++ bcsp->rx_count = 0; ++ } else ++ bcsp_unslip_one_byte(bcsp, *ptr); ++ ++ ptr++; count--; ++ continue; ++ } ++ ++ switch (bcsp->rx_state) { ++ case BCSP_W4_BCSP_HDR: ++ if ((0xff & (u8) ~ (bcsp->rx_skb->data[0] + bcsp->rx_skb->data[1] + ++ bcsp->rx_skb->data[2])) != bcsp->rx_skb->data[3]) { ++ BT_ERR("Error in BCSP hdr checksum"); ++ kfree_skb(bcsp->rx_skb); ++ bcsp->rx_state = BCSP_W4_PKT_DELIMITER; ++ bcsp->rx_count = 0; ++ continue; ++ } ++ if (bcsp->rx_skb->data[0] & 0x80 /* reliable pkt */ ++ && (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) { ++ BT_ERR ("Out-of-order packet arrived, got %u expected %u", ++ bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack); ++ ++ kfree_skb(bcsp->rx_skb); ++ bcsp->rx_state = BCSP_W4_PKT_DELIMITER; ++ bcsp->rx_count = 0; ++ continue; ++ } ++ bcsp->rx_state = BCSP_W4_DATA; ++ bcsp->rx_count = (bcsp->rx_skb->data[1] >> 4) + ++ (bcsp->rx_skb->data[2] << 4); /* May be 0 */ ++ continue; ++ ++ case BCSP_W4_DATA: ++ if (bcsp->rx_skb->data[0] & 0x40) { /* pkt with crc */ ++ bcsp->rx_state = BCSP_W4_CRC; ++ bcsp->rx_count = 2; ++ } else ++ bcsp_complete_rx_pkt(hu); ++ continue; ++ ++ case BCSP_W4_CRC: ++ if (bcsp_crc_reverse(bcsp->message_crc) != ++ (bcsp->rx_skb->data[bcsp->rx_skb->len - 2] << 8) + ++ bcsp->rx_skb->data[bcsp->rx_skb->len - 1]) { ++ ++ BT_ERR ("Checksum failed: computed %04x received %04x", ++ bcsp_crc_reverse(bcsp->message_crc), ++ (bcsp->rx_skb-> data[bcsp->rx_skb->len - 2] << 8) + ++ bcsp->rx_skb->data[bcsp->rx_skb->len - 1]); ++ ++ kfree_skb(bcsp->rx_skb); ++ bcsp->rx_state = BCSP_W4_PKT_DELIMITER; ++ bcsp->rx_count = 0; ++ continue; ++ } ++ skb_trim(bcsp->rx_skb, bcsp->rx_skb->len - 2); ++ bcsp_complete_rx_pkt(hu); ++ continue; ++ ++ case BCSP_W4_PKT_DELIMITER: ++ switch (*ptr) { ++ case 0xc0: ++ bcsp->rx_state = BCSP_W4_PKT_START; ++ break; ++ default: ++ /*BT_ERR("Ignoring byte %02x", *ptr);*/ ++ break; ++ } ++ ptr++; count--; ++ break; ++ ++ case BCSP_W4_PKT_START: ++ switch (*ptr) { ++ case 0xc0: ++ ptr++; count--; ++ break; ++ ++ default: ++ bcsp->rx_state = BCSP_W4_BCSP_HDR; ++ bcsp->rx_count = 4; ++ bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC; ++ BCSP_CRC_INIT(bcsp->message_crc); ++ ++ /* Do not increment ptr or decrement count ++ * Allocate packet. Max len of a BCSP pkt= ++ * 0xFFF (payload) +4 (header) +2 (crc) */ ++ ++ bcsp->rx_skb = bluez_skb_alloc(0x1005, GFP_ATOMIC); ++ if (!bcsp->rx_skb) { ++ BT_ERR("Can't allocate mem for new packet"); ++ bcsp->rx_state = BCSP_W4_PKT_DELIMITER; ++ bcsp->rx_count = 0; ++ return 0; ++ } ++ bcsp->rx_skb->dev = (void *) &hu->hdev; ++ break; ++ } ++ break; ++ } ++ } ++ return count; ++} ++ ++ /* Arrange to retransmit all messages in the relq. */ ++static void bcsp_timed_event(unsigned long arg) ++{ ++ struct hci_uart *hu = (struct hci_uart *) arg; ++ struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv; ++ struct sk_buff *skb; ++ unsigned long flags; ++ ++ BT_ERR("Timeout, retransmitting %u pkts", bcsp->unack.qlen); ++ spin_lock_irqsave(&bcsp->unack.lock, flags); ++ ++ while ((skb = __skb_dequeue_tail(&bcsp->unack)) != NULL) { ++ bcsp->msgq_txseq = (bcsp->msgq_txseq - 1) & 0x07; ++ skb_queue_head(&bcsp->rel, skb); ++ } ++ ++ spin_unlock_irqrestore(&bcsp->unack.lock, flags); ++ ++ hci_uart_tx_wakeup(hu); ++} ++ ++static int bcsp_open(struct hci_uart *hu) ++{ ++ struct bcsp_struct *bcsp; ++ ++ BT_DBG("hu %p", hu); ++ ++ bcsp = kmalloc(sizeof(*bcsp), GFP_ATOMIC); ++ if (!bcsp) ++ return -ENOMEM; ++ memset(bcsp, 0, sizeof(*bcsp)); ++ ++ hu->priv = bcsp; ++ skb_queue_head_init(&bcsp->unack); ++ skb_queue_head_init(&bcsp->rel); ++ skb_queue_head_init(&bcsp->unrel); ++ ++ init_timer(&bcsp->tbcsp); ++ bcsp->tbcsp.function = bcsp_timed_event; ++ bcsp->tbcsp.data = (u_long) hu; ++ ++ bcsp->rx_state = BCSP_W4_PKT_DELIMITER; ++ ++ return 0; ++} ++ ++static int bcsp_close(struct hci_uart *hu) ++{ ++ struct bcsp_struct *bcsp = hu->priv; ++ hu->priv = NULL; ++ ++ BT_DBG("hu %p", hu); ++ ++ skb_queue_purge(&bcsp->unack); ++ skb_queue_purge(&bcsp->rel); ++ skb_queue_purge(&bcsp->unrel); ++ del_timer(&bcsp->tbcsp); ++ ++ kfree(bcsp); ++ return 0; ++} ++ ++static struct hci_uart_proto bcsp = { ++ id: HCI_UART_BCSP, ++ open: bcsp_open, ++ close: bcsp_close, ++ enqueue: bcsp_enqueue, ++ dequeue: bcsp_dequeue, ++ recv: bcsp_recv, ++ flush: bcsp_flush ++}; ++ ++int bcsp_init(void) ++{ ++ return hci_uart_register_proto(&bcsp); ++} ++ ++int bcsp_deinit(void) ++{ ++ return hci_uart_unregister_proto(&bcsp); ++} +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/drivers/bluetooth/hci_bcsp.h 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,70 @@ ++/* ++ BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ). ++ Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com> ++ ++ Based on ++ hci_h4.c by Maxim Krasnyansky <maxk@qualcomm.com> ++ ABCSP by Carl Orsborn <cjo@csr.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#ifndef __HCI_BCSP_H__ ++#define __HCI_BCSP_H__ ++ ++#define BCSP_TXWINSIZE 4 ++ ++#define BCSP_ACK_PKT 0x05 ++#define BCSP_LE_PKT 0x06 ++ ++struct bcsp_struct { ++ struct sk_buff_head unack; /* Unack'ed packets queue */ ++ struct sk_buff_head rel; /* Reliable packets queue */ ++ struct sk_buff_head unrel; /* Unreliable packets queue */ ++ ++ unsigned long rx_count; ++ struct sk_buff *rx_skb; ++ u8 rxseq_txack; /* rxseq == txack. */ ++ u8 rxack; /* Last packet sent by us that the peer ack'ed */ ++ struct timer_list tbcsp; ++ ++ enum { ++ BCSP_W4_PKT_DELIMITER, ++ BCSP_W4_PKT_START, ++ BCSP_W4_BCSP_HDR, ++ BCSP_W4_DATA, ++ BCSP_W4_CRC ++ } rx_state; ++ ++ enum { ++ BCSP_ESCSTATE_NOESC, ++ BCSP_ESCSTATE_ESC ++ } rx_esc_state; ++ ++ u16 message_crc; ++ u8 txack_req; /* Do we need to send ack's to the peer? */ ++ ++ /* Reliable packet sequence number - used to assign seq to each rel pkt. */ ++ u8 msgq_txseq; ++}; ++ ++#endif /* __HCI_BCSP_H__ */ +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/drivers/bluetooth/hci_h4.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,277 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * BlueZ HCI UART(H4) protocol. ++ * ++ * $Id$ ++ */ ++#define VERSION "1.2" ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/version.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/sched.h> ++#include <linux/types.h> ++#include <linux/fcntl.h> ++#include <linux/interrupt.h> ++#include <linux/ptrace.h> ++#include <linux/poll.h> ++ ++#include <linux/slab.h> ++#include <linux/tty.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/signal.h> ++#include <linux/ioctl.h> ++#include <linux/skbuff.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++#include "hci_uart.h" ++#include "hci_h4.h" ++ ++#ifndef HCI_UART_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#undef BT_DMP ++#define BT_DMP( A... ) ++#endif ++ ++/* Initialize protocol */ ++static int h4_open(struct hci_uart *hu) ++{ ++ struct h4_struct *h4; ++ ++ BT_DBG("hu %p", hu); ++ ++ h4 = kmalloc(sizeof(*h4), GFP_ATOMIC); ++ if (!h4) ++ return -ENOMEM; ++ memset(h4, 0, sizeof(*h4)); ++ ++ skb_queue_head_init(&h4->txq); ++ ++ hu->priv = h4; ++ return 0; ++} ++ ++/* Flush protocol data */ ++static int h4_flush(struct hci_uart *hu) ++{ ++ struct h4_struct *h4 = hu->priv; ++ ++ BT_DBG("hu %p", hu); ++ skb_queue_purge(&h4->txq); ++ return 0; ++} ++ ++/* Close protocol */ ++static int h4_close(struct hci_uart *hu) ++{ ++ struct h4_struct *h4 = hu->priv; ++ hu->priv = NULL; ++ ++ BT_DBG("hu %p", hu); ++ ++ skb_queue_purge(&h4->txq); ++ if (h4->rx_skb) ++ kfree_skb(h4->rx_skb); ++ ++ hu->priv = NULL; ++ kfree(h4); ++ return 0; ++} ++ ++/* Enqueue frame for transmittion (padding, crc, etc) */ ++static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb) ++{ ++ struct h4_struct *h4 = hu->priv; ++ ++ BT_DBG("hu %p skb %p", hu, skb); ++ ++ /* Prepend skb with frame type */ ++ memcpy(skb_push(skb, 1), &skb->pkt_type, 1); ++ skb_queue_tail(&h4->txq, skb); ++ return 0; ++} ++ ++static inline int h4_check_data_len(struct h4_struct *h4, int len) ++{ ++ register int room = skb_tailroom(h4->rx_skb); ++ ++ BT_DBG("len %d room %d", len, room); ++ if (!len) { ++ BT_DMP(h4->rx_skb->data, h4->rx_skb->len); ++ hci_recv_frame(h4->rx_skb); ++ } else if (len > room) { ++ BT_ERR("Data length is too large"); ++ kfree_skb(h4->rx_skb); ++ } else { ++ h4->rx_state = H4_W4_DATA; ++ h4->rx_count = len; ++ return len; ++ } ++ ++ h4->rx_state = H4_W4_PACKET_TYPE; ++ h4->rx_skb = NULL; ++ h4->rx_count = 0; ++ return 0; ++} ++ ++/* Recv data */ ++static int h4_recv(struct hci_uart *hu, void *data, int count) ++{ ++ struct h4_struct *h4 = hu->priv; ++ register char *ptr; ++ hci_event_hdr *eh; ++ hci_acl_hdr *ah; ++ hci_sco_hdr *sh; ++ register int len, type, dlen; ++ ++ BT_DBG("hu %p count %d rx_state %ld rx_count %ld", ++ hu, count, h4->rx_state, h4->rx_count); ++ ++ ptr = data; ++ while (count) { ++ if (h4->rx_count) { ++ len = MIN(h4->rx_count, count); ++ memcpy(skb_put(h4->rx_skb, len), ptr, len); ++ h4->rx_count -= len; count -= len; ptr += len; ++ ++ if (h4->rx_count) ++ continue; ++ ++ switch (h4->rx_state) { ++ case H4_W4_DATA: ++ BT_DBG("Complete data"); ++ ++ BT_DMP(h4->rx_skb->data, h4->rx_skb->len); ++ ++ hci_recv_frame(h4->rx_skb); ++ ++ h4->rx_state = H4_W4_PACKET_TYPE; ++ h4->rx_skb = NULL; ++ continue; ++ ++ case H4_W4_EVENT_HDR: ++ eh = (hci_event_hdr *) h4->rx_skb->data; ++ ++ BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); ++ ++ h4_check_data_len(h4, eh->plen); ++ continue; ++ ++ case H4_W4_ACL_HDR: ++ ah = (hci_acl_hdr *) h4->rx_skb->data; ++ dlen = __le16_to_cpu(ah->dlen); ++ ++ BT_DBG("ACL header: dlen %d", dlen); ++ ++ h4_check_data_len(h4, dlen); ++ continue; ++ ++ case H4_W4_SCO_HDR: ++ sh = (hci_sco_hdr *) h4->rx_skb->data; ++ ++ BT_DBG("SCO header: dlen %d", sh->dlen); ++ ++ h4_check_data_len(h4, sh->dlen); ++ continue; ++ } ++ } ++ ++ /* H4_W4_PACKET_TYPE */ ++ switch (*ptr) { ++ case HCI_EVENT_PKT: ++ BT_DBG("Event packet"); ++ h4->rx_state = H4_W4_EVENT_HDR; ++ h4->rx_count = HCI_EVENT_HDR_SIZE; ++ type = HCI_EVENT_PKT; ++ break; ++ ++ case HCI_ACLDATA_PKT: ++ BT_DBG("ACL packet"); ++ h4->rx_state = H4_W4_ACL_HDR; ++ h4->rx_count = HCI_ACL_HDR_SIZE; ++ type = HCI_ACLDATA_PKT; ++ break; ++ ++ case HCI_SCODATA_PKT: ++ BT_DBG("SCO packet"); ++ h4->rx_state = H4_W4_SCO_HDR; ++ h4->rx_count = HCI_SCO_HDR_SIZE; ++ type = HCI_SCODATA_PKT; ++ break; ++ ++ default: ++ BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); ++ hu->hdev.stat.err_rx++; ++ ptr++; count--; ++ continue; ++ }; ++ ptr++; count--; ++ ++ /* Allocate packet */ ++ h4->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); ++ if (!h4->rx_skb) { ++ BT_ERR("Can't allocate mem for new packet"); ++ h4->rx_state = H4_W4_PACKET_TYPE; ++ h4->rx_count = 0; ++ return 0; ++ } ++ h4->rx_skb->dev = (void *) &hu->hdev; ++ h4->rx_skb->pkt_type = type; ++ } ++ return count; ++} ++ ++static struct sk_buff *h4_dequeue(struct hci_uart *hu) ++{ ++ struct h4_struct *h4 = hu->priv; ++ return skb_dequeue(&h4->txq); ++} ++ ++static struct hci_uart_proto h4p = { ++ id: HCI_UART_H4, ++ open: h4_open, ++ close: h4_close, ++ recv: h4_recv, ++ enqueue: h4_enqueue, ++ dequeue: h4_dequeue, ++ flush: h4_flush, ++}; ++ ++int h4_init(void) ++{ ++ return hci_uart_register_proto(&h4p); ++} ++ ++int h4_deinit(void) ++{ ++ return hci_uart_unregister_proto(&h4p); ++} +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/drivers/bluetooth/hci_h4.h 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,44 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#ifdef __KERNEL__ ++struct h4_struct { ++ unsigned long rx_state; ++ unsigned long rx_count; ++ struct sk_buff *rx_skb; ++ struct sk_buff_head txq; ++}; ++ ++/* H4 receiver States */ ++#define H4_W4_PACKET_TYPE 0 ++#define H4_W4_EVENT_HDR 1 ++#define H4_W4_ACL_HDR 2 ++#define H4_W4_SCO_HDR 3 ++#define H4_W4_DATA 4 ++ ++#endif /* __KERNEL__ */ +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/drivers/bluetooth/hci_ldisc.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,580 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * BlueZ HCI UART driver. ++ * ++ * $Id$ ++ */ ++#define VERSION "2.1" ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/version.h> ++#include <linux/config.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/sched.h> ++#include <linux/types.h> ++#include <linux/fcntl.h> ++#include <linux/interrupt.h> ++#include <linux/ptrace.h> ++#include <linux/poll.h> ++ ++#include <linux/slab.h> ++#include <linux/tty.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/signal.h> ++#include <linux/ioctl.h> ++#include <linux/skbuff.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++#include "hci_uart.h" ++ ++#ifndef HCI_UART_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#undef BT_DMP ++#define BT_DMP( A... ) ++#endif ++ ++static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; ++ ++int hci_uart_register_proto(struct hci_uart_proto *p) ++{ ++ if (p->id >= HCI_UART_MAX_PROTO) ++ return -EINVAL; ++ ++ if (hup[p->id]) ++ return -EEXIST; ++ ++ hup[p->id] = p; ++ return 0; ++} ++ ++int hci_uart_unregister_proto(struct hci_uart_proto *p) ++{ ++ if (p->id >= HCI_UART_MAX_PROTO) ++ return -EINVAL; ++ ++ if (!hup[p->id]) ++ return -EINVAL; ++ ++ hup[p->id] = NULL; ++ return 0; ++} ++ ++static struct hci_uart_proto *hci_uart_get_proto(unsigned int id) ++{ ++ if (id >= HCI_UART_MAX_PROTO) ++ return NULL; ++ return hup[id]; ++} ++ ++static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type) ++{ ++ struct hci_dev *hdev = &hu->hdev; ++ ++ /* Update HCI stat counters */ ++ switch (pkt_type) { ++ case HCI_COMMAND_PKT: ++ hdev->stat.cmd_tx++; ++ break; ++ ++ case HCI_ACLDATA_PKT: ++ hdev->stat.acl_tx++; ++ break; ++ ++ case HCI_SCODATA_PKT: ++ hdev->stat.cmd_tx++; ++ break; ++ } ++} ++ ++static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) ++{ ++ struct sk_buff *skb = hu->tx_skb; ++ if (!skb) ++ skb = hu->proto->dequeue(hu); ++ else ++ hu->tx_skb = NULL; ++ return skb; ++} ++ ++int hci_uart_tx_wakeup(struct hci_uart *hu) ++{ ++ struct tty_struct *tty = hu->tty; ++ struct hci_dev *hdev = &hu->hdev; ++ struct sk_buff *skb; ++ ++ if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) { ++ set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); ++ return 0; ++ } ++ ++ BT_DBG(""); ++ ++restart: ++ clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); ++ ++ while ((skb = hci_uart_dequeue(hu))) { ++ int len; ++ ++ set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); ++ len = tty->driver.write(tty, 0, skb->data, skb->len); ++ hdev->stat.byte_tx += len; ++ ++ skb_pull(skb, len); ++ if (skb->len) { ++ hu->tx_skb = skb; ++ break; ++ } ++ ++ hci_uart_tx_complete(hu, skb->pkt_type); ++ kfree_skb(skb); ++ } ++ ++ if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state)) ++ goto restart; ++ ++ clear_bit(HCI_UART_SENDING, &hu->tx_state); ++ return 0; ++} ++ ++/* ------- Interface to HCI layer ------ */ ++/* Initialize device */ ++static int hci_uart_open(struct hci_dev *hdev) ++{ ++ BT_DBG("%s %p", hdev->name, hdev); ++ ++ /* Nothing to do for UART driver */ ++ ++ set_bit(HCI_RUNNING, &hdev->flags); ++ return 0; ++} ++ ++/* Reset device */ ++static int hci_uart_flush(struct hci_dev *hdev) ++{ ++ struct hci_uart *hu = (struct hci_uart *) hdev->driver_data; ++ struct tty_struct *tty = hu->tty; ++ ++ BT_DBG("hdev %p tty %p", hdev, tty); ++ ++ if (hu->tx_skb) { ++ kfree_skb(hu->tx_skb); hu->tx_skb = NULL; ++ } ++ ++ /* Flush any pending characters in the driver and discipline. */ ++ if (tty->ldisc.flush_buffer) ++ tty->ldisc.flush_buffer(tty); ++ ++ if (tty->driver.flush_buffer) ++ tty->driver.flush_buffer(tty); ++ ++ if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) ++ hu->proto->flush(hu); ++ ++ return 0; ++} ++ ++/* Close device */ ++static int hci_uart_close(struct hci_dev *hdev) ++{ ++ BT_DBG("hdev %p", hdev); ++ ++ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) ++ return 0; ++ ++ hci_uart_flush(hdev); ++ return 0; ++} ++ ++/* Send frames from HCI layer */ ++static int hci_uart_send_frame(struct sk_buff *skb) ++{ ++ struct hci_dev* hdev = (struct hci_dev *) skb->dev; ++ struct tty_struct *tty; ++ struct hci_uart *hu; ++ ++ if (!hdev) { ++ BT_ERR("Frame for uknown device (hdev=NULL)"); ++ return -ENODEV; ++ } ++ ++ if (!test_bit(HCI_RUNNING, &hdev->flags)) ++ return -EBUSY; ++ ++ hu = (struct hci_uart *) hdev->driver_data; ++ tty = hu->tty; ++ ++ BT_DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len); ++ ++ hu->proto->enqueue(hu, skb); ++ ++ hci_uart_tx_wakeup(hu); ++ return 0; ++} ++ ++static void hci_uart_destruct(struct hci_dev *hdev) ++{ ++ struct hci_uart *hu; ++ ++ if (!hdev) return; ++ ++ BT_DBG("%s", hdev->name); ++ ++ hu = (struct hci_uart *) hdev->driver_data; ++ kfree(hu); ++ ++ MOD_DEC_USE_COUNT; ++} ++ ++/* ------ LDISC part ------ */ ++/* hci_uart_tty_open ++ * ++ * Called when line discipline changed to HCI_UART. ++ * ++ * Arguments: ++ * tty pointer to tty info structure ++ * Return Value: ++ * 0 if success, otherwise error code ++ */ ++static int hci_uart_tty_open(struct tty_struct *tty) ++{ ++ struct hci_uart *hu = (void *) tty->disc_data; ++ ++ BT_DBG("tty %p", tty); ++ ++ if (hu) ++ return -EEXIST; ++ ++ if (!(hu = kmalloc(sizeof(struct hci_uart), GFP_KERNEL))) { ++ BT_ERR("Can't allocate controll structure"); ++ return -ENFILE; ++ } ++ memset(hu, 0, sizeof(struct hci_uart)); ++ ++ tty->disc_data = hu; ++ hu->tty = tty; ++ ++ spin_lock_init(&hu->rx_lock); ++ ++ /* Flush any pending characters in the driver and line discipline */ ++ if (tty->ldisc.flush_buffer) ++ tty->ldisc.flush_buffer(tty); ++ ++ if (tty->driver.flush_buffer) ++ tty->driver.flush_buffer(tty); ++ ++ MOD_INC_USE_COUNT; ++ return 0; ++} ++ ++/* hci_uart_tty_close() ++ * ++ * Called when the line discipline is changed to something ++ * else, the tty is closed, or the tty detects a hangup. ++ */ ++static void hci_uart_tty_close(struct tty_struct *tty) ++{ ++ struct hci_uart *hu = (void *)tty->disc_data; ++ ++ BT_DBG("tty %p", tty); ++ ++ /* Detach from the tty */ ++ tty->disc_data = NULL; ++ ++ if (hu) { ++ struct hci_dev *hdev = &hu->hdev; ++ hci_uart_close(hdev); ++ ++ if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { ++ hu->proto->close(hu); ++ hci_unregister_dev(hdev); ++ } ++ ++ MOD_DEC_USE_COUNT; ++ } ++} ++ ++/* hci_uart_tty_wakeup() ++ * ++ * Callback for transmit wakeup. Called when low level ++ * device driver can accept more send data. ++ * ++ * Arguments: tty pointer to associated tty instance data ++ * Return Value: None ++ */ ++static void hci_uart_tty_wakeup(struct tty_struct *tty) ++{ ++ struct hci_uart *hu = (void *)tty->disc_data; ++ ++ BT_DBG(""); ++ ++ if (!hu) ++ return; ++ ++ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); ++ ++ if (tty != hu->tty) ++ return; ++ ++ if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) ++ hci_uart_tx_wakeup(hu); ++} ++ ++/* hci_uart_tty_room() ++ * ++ * Callback function from tty driver. Return the amount of ++ * space left in the receiver's buffer to decide if remote ++ * transmitter is to be throttled. ++ * ++ * Arguments: tty pointer to associated tty instance data ++ * Return Value: number of bytes left in receive buffer ++ */ ++static int hci_uart_tty_room (struct tty_struct *tty) ++{ ++ return 65536; ++} ++ ++/* hci_uart_tty_receive() ++ * ++ * Called by tty low level driver when receive data is ++ * available. ++ * ++ * Arguments: tty pointer to tty isntance data ++ * data pointer to received data ++ * flags pointer to flags for data ++ * count count of received data in bytes ++ * ++ * Return Value: None ++ */ ++static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count) ++{ ++ struct hci_uart *hu = (void *)tty->disc_data; ++ ++ if (!hu || tty != hu->tty) ++ return; ++ ++ if (!test_bit(HCI_UART_PROTO_SET, &hu->flags)) ++ return; ++ ++ spin_lock(&hu->rx_lock); ++ hu->proto->recv(hu, (void *) data, count); ++ hu->hdev.stat.byte_rx += count; ++ spin_unlock(&hu->rx_lock); ++ ++ if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle) ++ tty->driver.unthrottle(tty); ++} ++ ++static int hci_uart_register_dev(struct hci_uart *hu) ++{ ++ struct hci_dev *hdev; ++ ++ BT_DBG(""); ++ ++ /* Initialize and register HCI device */ ++ hdev = &hu->hdev; ++ ++ hdev->type = HCI_UART; ++ hdev->driver_data = hu; ++ ++ hdev->open = hci_uart_open; ++ hdev->close = hci_uart_close; ++ hdev->flush = hci_uart_flush; ++ hdev->send = hci_uart_send_frame; ++ hdev->destruct = hci_uart_destruct; ++ ++ if (hci_register_dev(hdev) < 0) { ++ BT_ERR("Can't register HCI device %s", hdev->name); ++ return -ENODEV; ++ } ++ MOD_INC_USE_COUNT; ++ return 0; ++} ++ ++static int hci_uart_set_proto(struct hci_uart *hu, int id) ++{ ++ struct hci_uart_proto *p; ++ int err; ++ ++ p = hci_uart_get_proto(id); ++ if (!p) ++ return -EPROTONOSUPPORT; ++ ++ err = p->open(hu); ++ if (err) ++ return err; ++ ++ hu->proto = p; ++ ++ err = hci_uart_register_dev(hu); ++ if (err) { ++ p->close(hu); ++ return err; ++ } ++ return 0; ++} ++ ++/* hci_uart_tty_ioctl() ++ * ++ * Process IOCTL system call for the tty device. ++ * ++ * Arguments: ++ * ++ * tty pointer to tty instance data ++ * file pointer to open file object for device ++ * cmd IOCTL command code ++ * arg argument for IOCTL call (cmd dependent) ++ * ++ * Return Value: Command dependent ++ */ ++static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, ++ unsigned int cmd, unsigned long arg) ++{ ++ struct hci_uart *hu = (void *)tty->disc_data; ++ int err = 0; ++ ++ BT_DBG(""); ++ ++ /* Verify the status of the device */ ++ if (!hu) ++ return -EBADF; ++ ++ switch (cmd) { ++ case HCIUARTSETPROTO: ++ if (!test_and_set_bit(HCI_UART_PROTO_SET, &hu->flags)) { ++ err = hci_uart_set_proto(hu, arg); ++ if (err) { ++ clear_bit(HCI_UART_PROTO_SET, &hu->flags); ++ return err; ++ } ++ tty->low_latency = 1; ++ } else ++ return -EBUSY; ++ ++ case HCIUARTGETPROTO: ++ if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) ++ return hu->proto->id; ++ return -EUNATCH; ++ ++ default: ++ err = n_tty_ioctl(tty, file, cmd, arg); ++ break; ++ }; ++ ++ return err; ++} ++ ++/* ++ * We don't provide read/write/poll interface for user space. ++ */ ++static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr) ++{ ++ return 0; ++} ++static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) ++{ ++ return 0; ++} ++static unsigned int hci_uart_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait) ++{ ++ return 0; ++} ++ ++#ifdef CONFIG_BLUEZ_HCIUART_H4 ++int h4_init(void); ++int h4_deinit(void); ++#endif ++#ifdef CONFIG_BLUEZ_HCIUART_BCSP ++int bcsp_init(void); ++int bcsp_deinit(void); ++#endif ++ ++int __init hci_uart_init(void) ++{ ++ static struct tty_ldisc hci_uart_ldisc; ++ int err; ++ ++ BT_INFO("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", ++ VERSION); ++ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); ++ ++ /* Register the tty discipline */ ++ ++ memset(&hci_uart_ldisc, 0, sizeof (hci_uart_ldisc)); ++ hci_uart_ldisc.magic = TTY_LDISC_MAGIC; ++ hci_uart_ldisc.name = "n_hci"; ++ hci_uart_ldisc.open = hci_uart_tty_open; ++ hci_uart_ldisc.close = hci_uart_tty_close; ++ hci_uart_ldisc.read = hci_uart_tty_read; ++ hci_uart_ldisc.write = hci_uart_tty_write; ++ hci_uart_ldisc.ioctl = hci_uart_tty_ioctl; ++ hci_uart_ldisc.poll = hci_uart_tty_poll; ++ hci_uart_ldisc.receive_room= hci_uart_tty_room; ++ hci_uart_ldisc.receive_buf = hci_uart_tty_receive; ++ hci_uart_ldisc.write_wakeup= hci_uart_tty_wakeup; ++ ++ if ((err = tty_register_ldisc(N_HCI, &hci_uart_ldisc))) { ++ BT_ERR("Can't register HCI line discipline (%d)", err); ++ return err; ++ } ++ ++#ifdef CONFIG_BLUEZ_HCIUART_H4 ++ h4_init(); ++#endif ++#ifdef CONFIG_BLUEZ_HCIUART_BCSP ++ bcsp_init(); ++#endif ++ ++ return 0; ++} ++ ++void hci_uart_cleanup(void) ++{ ++ int err; ++ ++#ifdef CONFIG_BLUEZ_HCIUART_H4 ++ h4_deinit(); ++#endif ++#ifdef CONFIG_BLUEZ_HCIUART_BCSP ++ bcsp_deinit(); ++#endif ++ ++ /* Release tty registration of line discipline */ ++ if ((err = tty_register_ldisc(N_HCI, NULL))) ++ BT_ERR("Can't unregister HCI line discipline (%d)", err); ++} ++ ++module_init(hci_uart_init); ++module_exit(hci_uart_cleanup); ++ ++MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); ++MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION); ++MODULE_LICENSE("GPL"); +--- linux/drivers/bluetooth/hci_uart.c~bluetooth-2.4.18-mh11 ++++ linux/drivers/bluetooth/hci_uart.c +-/* +- BlueZ - Bluetooth protocol stack for Linux +- Copyright (C) 2000-2001 Qualcomm Incorporated +- +- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; +- +- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY +- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES +- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- +- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, +- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS +- SOFTWARE IS DISCLAIMED. +-*/ +- +-/* +- * BlueZ HCI UART driver. +- * +- * $Id$ +- */ +-#define VERSION "1.0" +- +-#include <linux/config.h> +-#include <linux/module.h> +- +-#include <linux/version.h> +-#include <linux/config.h> +-#include <linux/kernel.h> +-#include <linux/init.h> +-#include <linux/sched.h> +-#include <linux/types.h> +-#include <linux/fcntl.h> +-#include <linux/interrupt.h> +-#include <linux/ptrace.h> +-#include <linux/poll.h> +- +-#include <linux/slab.h> +-#include <linux/tty.h> +-#include <linux/errno.h> +-#include <linux/string.h> +-#include <linux/signal.h> +-#include <linux/ioctl.h> +-#include <linux/skbuff.h> +- +-#include <net/bluetooth/bluetooth.h> +-#include <net/bluetooth/bluez.h> +-#include <net/bluetooth/hci_core.h> +-#include <net/bluetooth/hci_uart.h> +- +-#ifndef HCI_UART_DEBUG +-#undef DBG +-#define DBG( A... ) +-#undef DMP +-#define DMP( A... ) +-#endif +- +-/* ------- Interface to HCI layer ------ */ +-/* Initialize device */ +-int n_hci_open(struct hci_dev *hdev) +-{ +- DBG("%s %p", hdev->name, hdev); +- +- /* Nothing to do for UART driver */ +- +- hdev->flags |= HCI_RUNNING; +- +- return 0; +-} +- +-/* Reset device */ +-int n_hci_flush(struct hci_dev *hdev) +-{ +- struct n_hci *n_hci = (struct n_hci *) hdev->driver_data; +- struct tty_struct *tty = n_hci->tty; +- +- DBG("hdev %p tty %p", hdev, tty); +- +- /* Drop TX queue */ +- skb_queue_purge(&n_hci->txq); +- +- /* Flush any pending characters in the driver and discipline. */ +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); +- +- if (tty->driver.flush_buffer) +- tty->driver.flush_buffer(tty); +- +- return 0; +-} +- +-/* Close device */ +-int n_hci_close(struct hci_dev *hdev) +-{ +- DBG("hdev %p", hdev); +- +- hdev->flags &= ~HCI_RUNNING; +- +- n_hci_flush(hdev); +- +- return 0; +-} +- +-int n_hci_tx_wakeup(struct n_hci *n_hci) +-{ +- register struct tty_struct *tty = n_hci->tty; +- +- if (test_and_set_bit(TRANS_SENDING, &n_hci->tx_state)) { +- set_bit(TRANS_WAKEUP, &n_hci->tx_state); +- return 0; +- } +- +- DBG(""); +- do { +- register struct sk_buff *skb; +- register int len; +- +- clear_bit(TRANS_WAKEUP, &n_hci->tx_state); +- +- if (!(skb = skb_dequeue(&n_hci->txq))) +- break; +- +- DMP(skb->data, skb->len); +- +- /* Send frame to TTY driver */ +- tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); +- len = tty->driver.write(tty, 0, skb->data, skb->len); +- +- n_hci->hdev.stat.byte_tx += len; +- +- DBG("sent %d", len); +- +- if (len == skb->len) { +- /* Full frame was sent */ +- kfree_skb(skb); +- } else { +- /* Subtract sent part and requeue */ +- skb_pull(skb, len); +- skb_queue_head(&n_hci->txq, skb); +- } +- } while (test_bit(TRANS_WAKEUP, &n_hci->tx_state)); +- clear_bit(TRANS_SENDING, &n_hci->tx_state); +- +- return 0; +-} +- +-/* Send frames from HCI layer */ +-int n_hci_send_frame(struct sk_buff *skb) +-{ +- struct hci_dev* hdev = (struct hci_dev *) skb->dev; +- struct tty_struct *tty; +- struct n_hci *n_hci; +- +- if (!hdev) { +- ERR("Frame for uknown device (hdev=NULL)"); +- return -ENODEV; +- } +- +- if (!(hdev->flags & HCI_RUNNING)) +- return -EBUSY; +- +- n_hci = (struct n_hci *) hdev->driver_data; +- tty = n_hci2tty(n_hci); +- +- DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len); +- +- switch (skb->pkt_type) { +- case HCI_COMMAND_PKT: +- hdev->stat.cmd_tx++; +- break; +- +- case HCI_ACLDATA_PKT: +- hdev->stat.acl_tx++; +- break; +- +- case HCI_SCODATA_PKT: +- hdev->stat.cmd_tx++; +- break; +- }; +- +- /* Prepend skb with frame type and queue */ +- memcpy(skb_push(skb, 1), &skb->pkt_type, 1); +- skb_queue_tail(&n_hci->txq, skb); +- +- n_hci_tx_wakeup(n_hci); +- +- return 0; +-} +- +-/* ------ LDISC part ------ */ +- +-/* n_hci_tty_open +- * +- * Called when line discipline changed to N_HCI. +- * +- * Arguments: +- * tty pointer to tty info structure +- * Return Value: +- * 0 if success, otherwise error code +- */ +-static int n_hci_tty_open(struct tty_struct *tty) +-{ +- struct n_hci *n_hci = tty2n_hci(tty); +- struct hci_dev *hdev; +- +- DBG("tty %p", tty); +- +- if (n_hci) +- return -EEXIST; +- +- if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) { +- ERR("Can't allocate controll structure"); +- return -ENFILE; +- } +- memset(n_hci, 0, sizeof(struct n_hci)); +- +- /* Initialize and register HCI device */ +- hdev = &n_hci->hdev; +- +- hdev->type = HCI_UART; +- hdev->driver_data = n_hci; +- +- hdev->open = n_hci_open; +- hdev->close = n_hci_close; +- hdev->flush = n_hci_flush; +- hdev->send = n_hci_send_frame; +- +- if (hci_register_dev(hdev) < 0) { +- ERR("Can't register HCI device %s", hdev->name); +- kfree(n_hci); +- return -ENODEV; +- } +- +- tty->disc_data = n_hci; +- n_hci->tty = tty; +- +- spin_lock_init(&n_hci->rx_lock); +- n_hci->rx_state = WAIT_PACKET_TYPE; +- +- skb_queue_head_init(&n_hci->txq); +- +- MOD_INC_USE_COUNT; +- +- /* Flush any pending characters in the driver and discipline. */ +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); +- +- if (tty->driver.flush_buffer) +- tty->driver.flush_buffer(tty); +- +- return 0; +-} +- +-/* n_hci_tty_close() +- * +- * Called when the line discipline is changed to something +- * else, the tty is closed, or the tty detects a hangup. +- */ +-static void n_hci_tty_close(struct tty_struct *tty) +-{ +- struct n_hci *n_hci = tty2n_hci(tty); +- struct hci_dev *hdev = &n_hci->hdev; +- +- DBG("tty %p hdev %p", tty, hdev); +- +- if (n_hci != NULL) { +- n_hci_close(hdev); +- +- if (hci_unregister_dev(hdev) < 0) { +- ERR("Can't unregister HCI device %s",hdev->name); +- } +- +- hdev->driver_data = NULL; +- tty->disc_data = NULL; +- kfree(n_hci); +- +- MOD_DEC_USE_COUNT; +- } +-} +- +-/* n_hci_tty_wakeup() +- * +- * Callback for transmit wakeup. Called when low level +- * device driver can accept more send data. +- * +- * Arguments: tty pointer to associated tty instance data +- * Return Value: None +- */ +-static void n_hci_tty_wakeup( struct tty_struct *tty ) +-{ +- struct n_hci *n_hci = tty2n_hci(tty); +- +- DBG(""); +- +- if (!n_hci) +- return; +- +- tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); +- +- if (tty != n_hci->tty) +- return; +- +- n_hci_tx_wakeup(n_hci); +-} +- +-/* n_hci_tty_room() +- * +- * Callback function from tty driver. Return the amount of +- * space left in the receiver's buffer to decide if remote +- * transmitter is to be throttled. +- * +- * Arguments: tty pointer to associated tty instance data +- * Return Value: number of bytes left in receive buffer +- */ +-static int n_hci_tty_room (struct tty_struct *tty) +-{ +- return 65536; +-} +- +-static inline int n_hci_check_data_len(struct n_hci *n_hci, int len) +-{ +- register int room = skb_tailroom(n_hci->rx_skb); +- +- DBG("len %d room %d", len, room); +- if (!len) { +- DMP(n_hci->rx_skb->data, n_hci->rx_skb->len); +- hci_recv_frame(n_hci->rx_skb); +- } else if (len > room) { +- ERR("Data length is to large"); +- kfree_skb(n_hci->rx_skb); +- n_hci->hdev.stat.err_rx++; +- } else { +- n_hci->rx_state = WAIT_DATA; +- n_hci->rx_count = len; +- return len; +- } +- +- n_hci->rx_state = WAIT_PACKET_TYPE; +- n_hci->rx_skb = NULL; +- n_hci->rx_count = 0; +- return 0; +-} +- +-static inline void n_hci_rx(struct n_hci *n_hci, const __u8 * data, char *flags, int count) +-{ +- register const char *ptr; +- hci_event_hdr *eh; +- hci_acl_hdr *ah; +- hci_sco_hdr *sh; +- register int len, type, dlen; +- +- DBG("count %d state %ld rx_count %ld", count, n_hci->rx_state, n_hci->rx_count); +- +- n_hci->hdev.stat.byte_rx += count; +- +- ptr = data; +- while (count) { +- if (n_hci->rx_count) { +- len = MIN(n_hci->rx_count, count); +- memcpy(skb_put(n_hci->rx_skb, len), ptr, len); +- n_hci->rx_count -= len; count -= len; ptr += len; +- +- if (n_hci->rx_count) +- continue; +- +- switch (n_hci->rx_state) { +- case WAIT_DATA: +- DBG("Complete data"); +- +- DMP(n_hci->rx_skb->data, n_hci->rx_skb->len); +- +- hci_recv_frame(n_hci->rx_skb); +- +- n_hci->rx_state = WAIT_PACKET_TYPE; +- n_hci->rx_skb = NULL; +- continue; +- +- case WAIT_EVENT_HDR: +- eh = (hci_event_hdr *) n_hci->rx_skb->data; +- +- DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); +- +- n_hci_check_data_len(n_hci, eh->plen); +- continue; +- +- case WAIT_ACL_HDR: +- ah = (hci_acl_hdr *) n_hci->rx_skb->data; +- dlen = __le16_to_cpu(ah->dlen); +- +- DBG("ACL header: dlen %d", dlen); +- +- n_hci_check_data_len(n_hci, dlen); +- continue; +- +- case WAIT_SCO_HDR: +- sh = (hci_sco_hdr *) n_hci->rx_skb->data; +- +- DBG("SCO header: dlen %d", sh->dlen); +- +- n_hci_check_data_len(n_hci, sh->dlen); +- continue; +- }; +- } +- +- /* WAIT_PACKET_TYPE */ +- switch (*ptr) { +- case HCI_EVENT_PKT: +- DBG("Event packet"); +- n_hci->rx_state = WAIT_EVENT_HDR; +- n_hci->rx_count = HCI_EVENT_HDR_SIZE; +- type = HCI_EVENT_PKT; +- break; +- +- case HCI_ACLDATA_PKT: +- DBG("ACL packet"); +- n_hci->rx_state = WAIT_ACL_HDR; +- n_hci->rx_count = HCI_ACL_HDR_SIZE; +- type = HCI_ACLDATA_PKT; +- break; +- +- case HCI_SCODATA_PKT: +- DBG("SCO packet"); +- n_hci->rx_state = WAIT_SCO_HDR; +- n_hci->rx_count = HCI_SCO_HDR_SIZE; +- type = HCI_SCODATA_PKT; +- break; +- +- default: +- ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); +- n_hci->hdev.stat.err_rx++; +- ptr++; count--; +- continue; +- }; +- ptr++; count--; +- +- /* Allocate packet */ +- if (!(n_hci->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { +- ERR("Can't allocate mem for new packet"); +- +- n_hci->rx_state = WAIT_PACKET_TYPE; +- n_hci->rx_count = 0; +- return; +- } +- n_hci->rx_skb->dev = (void *) &n_hci->hdev; +- n_hci->rx_skb->pkt_type = type; +- } +-} +- +-/* n_hci_tty_receive() +- * +- * Called by tty low level driver when receive data is +- * available. +- * +- * Arguments: tty pointer to tty isntance data +- * data pointer to received data +- * flags pointer to flags for data +- * count count of received data in bytes +- * +- * Return Value: None +- */ +-static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count) +-{ +- struct n_hci *n_hci = tty2n_hci(tty); +- +- if (!n_hci || tty != n_hci->tty) +- return; +- +- spin_lock(&n_hci->rx_lock); +- n_hci_rx(n_hci, data, flags, count); +- spin_unlock(&n_hci->rx_lock); +- +- if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle) +- tty->driver.unthrottle(tty); +-} +- +-/* n_hci_tty_ioctl() +- * +- * Process IOCTL system call for the tty device. +- * +- * Arguments: +- * +- * tty pointer to tty instance data +- * file pointer to open file object for device +- * cmd IOCTL command code +- * arg argument for IOCTL call (cmd dependent) +- * +- * Return Value: Command dependent +- */ +-static int n_hci_tty_ioctl (struct tty_struct *tty, struct file * file, +- unsigned int cmd, unsigned long arg) +-{ +- struct n_hci *n_hci = tty2n_hci(tty); +- int error = 0; +- +- DBG(""); +- +- /* Verify the status of the device */ +- if (!n_hci) +- return -EBADF; +- +- switch (cmd) { +- default: +- error = n_tty_ioctl(tty, file, cmd, arg); +- break; +- }; +- +- return error; +-} +- +-/* +- * We don't provide read/write/poll interface for user space. +- */ +-static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr) +-{ +- return 0; +-} +-static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) +-{ +- return 0; +-} +-static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait) +-{ +- return 0; +-} +- +-int __init n_hci_init(void) +-{ +- static struct tty_ldisc n_hci_ldisc; +- int err; +- +- INF("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", +- VERSION); +- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); +- +- /* Register the tty discipline */ +- +- memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc)); +- n_hci_ldisc.magic = TTY_LDISC_MAGIC; +- n_hci_ldisc.name = "n_hci"; +- n_hci_ldisc.open = n_hci_tty_open; +- n_hci_ldisc.close = n_hci_tty_close; +- n_hci_ldisc.read = n_hci_tty_read; +- n_hci_ldisc.write = n_hci_tty_write; +- n_hci_ldisc.ioctl = n_hci_tty_ioctl; +- n_hci_ldisc.poll = n_hci_tty_poll; +- n_hci_ldisc.receive_room= n_hci_tty_room; +- n_hci_ldisc.receive_buf = n_hci_tty_receive; +- n_hci_ldisc.write_wakeup= n_hci_tty_wakeup; +- +- if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) { +- ERR("Can't register HCI line discipline (%d)", err); +- return err; +- } +- +- return 0; +-} +- +-void n_hci_cleanup(void) +-{ +- int err; +- +- /* Release tty registration of line discipline */ +- if ((err = tty_register_ldisc(N_HCI, NULL))) +- ERR("Can't unregister HCI line discipline (%d)", err); +-} +- +-module_init(n_hci_init); +-module_exit(n_hci_cleanup); +- +-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); +-MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION); +-MODULE_LICENSE("GPL"); +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/drivers/bluetooth/hci_uart.h 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,81 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#ifndef N_HCI ++#define N_HCI 15 ++#endif ++ ++/* Ioctls */ ++#define HCIUARTSETPROTO _IOW('U', 200, int) ++#define HCIUARTGETPROTO _IOR('U', 201, int) ++ ++/* UART protocols */ ++#define HCI_UART_MAX_PROTO 3 ++ ++#define HCI_UART_H4 0 ++#define HCI_UART_BCSP 1 ++#define HCI_UART_NCSP 2 ++ ++#ifdef __KERNEL__ ++struct hci_uart; ++ ++struct hci_uart_proto { ++ unsigned int id; ++ int (*open)(struct hci_uart *hu); ++ int (*close)(struct hci_uart *hu); ++ int (*flush)(struct hci_uart *hu); ++ int (*recv)(struct hci_uart *hu, void *data, int len); ++ int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb); ++ struct sk_buff *(*dequeue)(struct hci_uart *hu); ++}; ++ ++struct hci_uart { ++ struct tty_struct *tty; ++ struct hci_dev hdev; ++ unsigned long flags; ++ ++ struct hci_uart_proto *proto; ++ void *priv; ++ ++ struct sk_buff *tx_skb; ++ unsigned long tx_state; ++ spinlock_t rx_lock; ++}; ++ ++/* HCI_UART flag bits */ ++#define HCI_UART_PROTO_SET 0 ++ ++/* TX states */ ++#define HCI_UART_SENDING 1 ++#define HCI_UART_TX_WAKEUP 2 ++ ++int hci_uart_register_proto(struct hci_uart_proto *p); ++int hci_uart_unregister_proto(struct hci_uart_proto *p); ++int hci_uart_tx_wakeup(struct hci_uart *hu); ++ ++#endif /* __KERNEL__ */ +--- linux/drivers/bluetooth/hci_usb.c~bluetooth-2.4.18-mh11 2001-09-07 18:28:38.000000000 +0200 ++++ linux/drivers/bluetooth/hci_usb.c 2004-01-25 23:37:39.000000000 +0100 +@@ -1,9 +1,10 @@ + /* +- BlueZ - Bluetooth protocol stack for Linux ++ HCI USB driver for Linux Bluetooth protocol stack (BlueZ) + Copyright (C) 2000-2001 Qualcomm Incorporated +- + Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> + ++ Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.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; +@@ -23,598 +24,914 @@ + */ + + /* +- * BlueZ HCI USB driver. + * Based on original USB Bluetooth driver for Linux kernel + * Copyright (c) 2000 Greg Kroah-Hartman <greg@kroah.com> + * Copyright (c) 2000 Mark Douglas Corner <mcorner@umich.edu> + * +- * $Id$ ++ * $Id$ + */ +-#define VERSION "1.0" ++#define VERSION "2.4" + + #include <linux/config.h> + #include <linux/module.h> + + #include <linux/version.h> +-#include <linux/config.h> + #include <linux/kernel.h> + #include <linux/init.h> + #include <linux/sched.h> ++#include <linux/unistd.h> + #include <linux/types.h> +-#include <linux/fcntl.h> + #include <linux/interrupt.h> +-#include <linux/ptrace.h> +-#include <linux/poll.h> + + #include <linux/slab.h> +-#include <linux/tty.h> + #include <linux/errno.h> + #include <linux/string.h> +-#include <linux/signal.h> +-#include <linux/ioctl.h> + #include <linux/skbuff.h> + + #include <linux/usb.h> + + #include <net/bluetooth/bluetooth.h> +-#include <net/bluetooth/bluez.h> + #include <net/bluetooth/hci_core.h> +-#include <net/bluetooth/hci_usb.h> ++ ++#include "hci_usb.h" + + #ifndef HCI_USB_DEBUG +-#undef DBG +-#define DBG( A... ) +-#undef DMP +-#define DMP( A... ) ++#undef BT_DBG ++#define BT_DBG( A... ) ++#undef BT_DMP ++#define BT_DMP( A... ) + #endif + +-static struct usb_device_id usb_bluetooth_ids [] = { ++#ifndef CONFIG_BLUEZ_HCIUSB_ZERO_PACKET ++#undef USB_ZERO_PACKET ++#define USB_ZERO_PACKET 0 ++#endif ++ ++static struct usb_driver hci_usb_driver; ++ ++static struct usb_device_id bluetooth_ids[] = { ++ /* Digianswer device */ ++ { USB_DEVICE(0x08fd, 0x0001), driver_info: HCI_DIGIANSWER }, ++ ++ /* Generic Bluetooth USB device */ + { USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) }, ++ ++ /* Ericsson with non-standard id */ ++ { USB_DEVICE(0x0bdb, 0x1002) }, ++ ++ /* ALPS Module with non-standard id */ ++ { USB_DEVICE(0x044e, 0x3002) }, ++ ++ /* Bluetooth Ultraport Module from IBM */ ++ { USB_DEVICE(0x04bf, 0x030a) }, ++ + { } /* Terminating entry */ + }; + +-MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids); ++MODULE_DEVICE_TABLE (usb, bluetooth_ids); + +-static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb); +-static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb); ++static struct usb_device_id ignore_ids[] = { ++ /* Broadcom BCM2033 without firmware */ ++ { USB_DEVICE(0x0a5c, 0x2033) }, + +-static void hci_usb_unlink_urbs(struct hci_usb *husb) +-{ +- usb_unlink_urb(husb->read_urb); +- usb_unlink_urb(husb->intr_urb); +- usb_unlink_urb(husb->ctrl_urb); +- usb_unlink_urb(husb->write_urb); +-} ++ { } /* Terminating entry */ ++}; + +-static void hci_usb_free_bufs(struct hci_usb *husb) ++struct _urb *_urb_alloc(int isoc, int gfp) + { +- if (husb->read_urb) { +- if (husb->read_urb->transfer_buffer) +- kfree(husb->read_urb->transfer_buffer); +- usb_free_urb(husb->read_urb); ++ struct _urb *_urb = kmalloc(sizeof(struct _urb) + ++ sizeof(iso_packet_descriptor_t) * isoc, gfp); ++ if (_urb) { ++ memset(_urb, 0, sizeof(*_urb)); ++ spin_lock_init(&_urb->urb.lock); + } ++ return _urb; ++} + +- if (husb->intr_urb) { +- if (husb->intr_urb->transfer_buffer) +- kfree(husb->intr_urb->transfer_buffer); +- usb_free_urb(husb->intr_urb); ++struct _urb *_urb_dequeue(struct _urb_queue *q) ++{ ++ struct _urb *_urb = NULL; ++ unsigned long flags; ++ spin_lock_irqsave(&q->lock, flags); ++ { ++ struct list_head *head = &q->head; ++ struct list_head *next = head->next; ++ if (next != head) { ++ _urb = list_entry(next, struct _urb, list); ++ list_del(next); _urb->queue = NULL; ++ } + } ++ spin_unlock_irqrestore(&q->lock, flags); ++ return _urb; ++} + +- if (husb->ctrl_urb) +- usb_free_urb(husb->ctrl_urb); ++static void hci_usb_rx_complete(struct urb *urb); ++static void hci_usb_tx_complete(struct urb *urb); + +- if (husb->write_urb) +- usb_free_urb(husb->write_urb); ++#define __pending_tx(husb, type) (&husb->pending_tx[type-1]) ++#define __pending_q(husb, type) (&husb->pending_q[type-1]) ++#define __completed_q(husb, type) (&husb->completed_q[type-1]) ++#define __transmit_q(husb, type) (&husb->transmit_q[type-1]) ++#define __reassembly(husb, type) (husb->reassembly[type-1]) + +- if (husb->intr_skb) +- kfree_skb(husb->intr_skb); ++static inline struct _urb *__get_completed(struct hci_usb *husb, int type) ++{ ++ return _urb_dequeue(__completed_q(husb, type)); + } + +-/* ------- Interface to HCI layer ------ */ +-/* Initialize device */ +-int hci_usb_open(struct hci_dev *hdev) ++#ifdef CONFIG_BLUEZ_HCIUSB_SCO ++static void __fill_isoc_desc(struct urb *urb, int len, int mtu) + { +- struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; +- int status; +- +- DBG("%s", hdev->name); +- +- husb->read_urb->dev = husb->udev; +- if ((status = usb_submit_urb(husb->read_urb))) +- DBG("read submit failed. %d", status); +- +- husb->intr_urb->dev = husb->udev; +- if ((status = usb_submit_urb(husb->intr_urb))) +- DBG("interrupt submit failed. %d", status); ++ int offset = 0, i; + +- hdev->flags |= HCI_RUNNING; ++ BT_DBG("len %d mtu %d", len, mtu); + +- return 0; ++ for (i=0; i < HCI_MAX_ISOC_FRAMES && len >= mtu; i++, offset += mtu, len -= mtu) { ++ urb->iso_frame_desc[i].offset = offset; ++ urb->iso_frame_desc[i].length = mtu; ++ BT_DBG("desc %d offset %d len %d", i, offset, mtu); ++ } ++ if (len && i < HCI_MAX_ISOC_FRAMES) { ++ urb->iso_frame_desc[i].offset = offset; ++ urb->iso_frame_desc[i].length = len; ++ BT_DBG("desc %d offset %d len %d", i, offset, len); ++ i++; ++ } ++ urb->number_of_packets = i; + } ++#endif + +-/* Reset device */ +-int hci_usb_flush(struct hci_dev *hdev) ++static int hci_usb_intr_rx_submit(struct hci_usb *husb) + { +- struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; ++ struct _urb *_urb; ++ struct urb *urb; ++ int err, pipe, interval, size; ++ void *buf; + +- DBG("%s", hdev->name); ++ BT_DBG("%s", husb->hdev.name); + +- /* Drop TX queues */ +- skb_queue_purge(&husb->tx_ctrl_q); +- skb_queue_purge(&husb->tx_write_q); ++ size = husb->intr_in_ep->wMaxPacketSize; + +- return 0; ++ buf = kmalloc(size, GFP_ATOMIC); ++ if (!buf) ++ return -ENOMEM; ++ ++ _urb = _urb_alloc(0, GFP_ATOMIC); ++ if (!_urb) { ++ kfree(buf); ++ return -ENOMEM; ++ } ++ _urb->type = HCI_EVENT_PKT; ++ _urb_queue_tail(__pending_q(husb, _urb->type), _urb); ++ ++ urb = &_urb->urb; ++ pipe = usb_rcvintpipe(husb->udev, husb->intr_in_ep->bEndpointAddress); ++ interval = husb->intr_in_ep->bInterval; ++ FILL_INT_URB(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb, interval); ++ ++ err = usb_submit_urb(urb); ++ if (err) { ++ BT_ERR("%s intr rx submit failed urb %p err %d", ++ husb->hdev.name, urb, err); ++ _urb_unlink(_urb); ++ _urb_free(_urb); ++ kfree(buf); ++ } ++ return err; + } + +-/* Close device */ +-int hci_usb_close(struct hci_dev *hdev) ++static int hci_usb_bulk_rx_submit(struct hci_usb *husb) + { +- struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; ++ struct _urb *_urb; ++ struct urb *urb; ++ int err, pipe, size = HCI_MAX_FRAME_SIZE; ++ void *buf; + +- DBG("%s", hdev->name); ++ buf = kmalloc(size, GFP_ATOMIC); ++ if (!buf) ++ return -ENOMEM; + +- hdev->flags &= ~HCI_RUNNING; +- hci_usb_unlink_urbs(husb); ++ _urb = _urb_alloc(0, GFP_ATOMIC); ++ if (!_urb) { ++ kfree(buf); ++ return -ENOMEM; ++ } ++ _urb->type = HCI_ACLDATA_PKT; ++ _urb_queue_tail(__pending_q(husb, _urb->type), _urb); + +- hci_usb_flush(hdev); ++ urb = &_urb->urb; ++ pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep->bEndpointAddress); ++ FILL_BULK_URB(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb); ++ urb->transfer_flags = USB_QUEUE_BULK; + +- return 0; ++ BT_DBG("%s urb %p", husb->hdev.name, urb); ++ ++ err = usb_submit_urb(urb); ++ if (err) { ++ BT_ERR("%s bulk rx submit failed urb %p err %d", ++ husb->hdev.name, urb, err); ++ _urb_unlink(_urb); ++ _urb_free(_urb); ++ kfree(buf); ++ } ++ return err; + } + +-void hci_usb_ctrl_wakeup(struct hci_usb *husb) ++#ifdef CONFIG_BLUEZ_HCIUSB_SCO ++static int hci_usb_isoc_rx_submit(struct hci_usb *husb) + { +- struct sk_buff *skb; +- +- if (test_and_set_bit(HCI_TX_CTRL, &husb->tx_state)) +- return; ++ struct _urb *_urb; ++ struct urb *urb; ++ int err, mtu, size; ++ void *buf; + +- DBG("%s", husb->hdev.name); ++ mtu = husb->isoc_in_ep->wMaxPacketSize; ++ size = mtu * HCI_MAX_ISOC_FRAMES; + +- if (!(skb = skb_dequeue(&husb->tx_ctrl_q))) +- goto done; ++ buf = kmalloc(size, GFP_ATOMIC); ++ if (!buf) ++ return -ENOMEM; + +- if (hci_usb_ctrl_msg(husb, skb)){ +- kfree_skb(skb); +- goto done; ++ _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC); ++ if (!_urb) { ++ kfree(buf); ++ return -ENOMEM; + } ++ _urb->type = HCI_SCODATA_PKT; ++ _urb_queue_tail(__pending_q(husb, _urb->type), _urb); + +- DMP(skb->data, skb->len); ++ urb = &_urb->urb; + +- husb->hdev.stat.byte_tx += skb->len; +- return; ++ urb->context = husb; ++ urb->dev = husb->udev; ++ urb->pipe = usb_rcvisocpipe(husb->udev, husb->isoc_in_ep->bEndpointAddress); ++ urb->complete = hci_usb_rx_complete; + +-done: +- clear_bit(HCI_TX_CTRL, &husb->tx_state); +- return; ++ urb->transfer_buffer_length = size; ++ urb->transfer_buffer = buf; ++ urb->transfer_flags = USB_ISO_ASAP; ++ ++ __fill_isoc_desc(urb, size, mtu); ++ ++ BT_DBG("%s urb %p", husb->hdev.name, urb); ++ ++ err = usb_submit_urb(urb); ++ if (err) { ++ BT_ERR("%s isoc rx submit failed urb %p err %d", ++ husb->hdev.name, urb, err); ++ _urb_unlink(_urb); ++ _urb_free(_urb); ++ kfree(buf); ++ } ++ return err; + } ++#endif + +-void hci_usb_write_wakeup(struct hci_usb *husb) ++/* Initialize device */ ++static int hci_usb_open(struct hci_dev *hdev) + { +- struct sk_buff *skb; ++ struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; ++ int i, err; ++ unsigned long flags; + +- if (test_and_set_bit(HCI_TX_WRITE, &husb->tx_state)) +- return; ++ BT_DBG("%s", hdev->name); + +- DBG("%s", husb->hdev.name); ++ if (test_and_set_bit(HCI_RUNNING, &hdev->flags)) ++ return 0; + +- if (!(skb = skb_dequeue(&husb->tx_write_q))) +- goto done; ++ MOD_INC_USE_COUNT; + +- if (hci_usb_write_msg(husb, skb)) { +- skb_queue_head(&husb->tx_write_q, skb); +- goto done; ++ write_lock_irqsave(&husb->completion_lock, flags); ++ ++ err = hci_usb_intr_rx_submit(husb); ++ if (!err) { ++ for (i = 0; i < HCI_MAX_BULK_RX; i++) ++ hci_usb_bulk_rx_submit(husb); ++ ++#ifdef CONFIG_BLUEZ_HCIUSB_SCO ++ if (husb->isoc_iface) ++ for (i = 0; i < HCI_MAX_ISOC_RX; i++) ++ hci_usb_isoc_rx_submit(husb); ++#endif ++ } else { ++ clear_bit(HCI_RUNNING, &hdev->flags); ++ MOD_DEC_USE_COUNT; + } + +- DMP(skb->data, skb->len); ++ write_unlock_irqrestore(&husb->completion_lock, flags); ++ return err; ++} + +- husb->hdev.stat.byte_tx += skb->len; +- return; ++/* Reset device */ ++static int hci_usb_flush(struct hci_dev *hdev) ++{ ++ struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; ++ int i; + +-done: +- clear_bit(HCI_TX_WRITE, &husb->tx_state); +- return; ++ BT_DBG("%s", hdev->name); ++ ++ for (i=0; i < 4; i++) ++ skb_queue_purge(&husb->transmit_q[i]); ++ return 0; + } + +-/* Send frames from HCI layer */ +-int hci_usb_send_frame(struct sk_buff *skb) ++static void hci_usb_unlink_urbs(struct hci_usb *husb) + { +- struct hci_dev *hdev = (struct hci_dev *) skb->dev; +- struct hci_usb *husb; ++ int i; + +- if (!hdev) { +- ERR("frame for uknown device (hdev=NULL)"); +- return -ENODEV; +- } ++ BT_DBG("%s", husb->hdev.name); + +- if (!(hdev->flags & HCI_RUNNING)) +- return 0; ++ for (i=0; i < 4; i++) { ++ struct _urb *_urb; ++ struct urb *urb; + +- husb = (struct hci_usb *) hdev->driver_data; ++ /* Kill pending requests */ ++ while ((_urb = _urb_dequeue(&husb->pending_q[i]))) { ++ urb = &_urb->urb; ++ BT_DBG("%s unlinking _urb %p type %d urb %p", ++ husb->hdev.name, _urb, _urb->type, urb); ++ usb_unlink_urb(urb); ++ _urb_queue_tail(__completed_q(husb, _urb->type), _urb); ++ } + +- DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); ++ /* Release completed requests */ ++ while ((_urb = _urb_dequeue(&husb->completed_q[i]))) { ++ urb = &_urb->urb; ++ BT_DBG("%s freeing _urb %p type %d urb %p", ++ husb->hdev.name, _urb, _urb->type, urb); ++ if (urb->setup_packet) ++ kfree(urb->setup_packet); ++ if (urb->transfer_buffer) ++ kfree(urb->transfer_buffer); ++ _urb_free(_urb); ++ } + +- switch (skb->pkt_type) { +- case HCI_COMMAND_PKT: +- skb_queue_tail(&husb->tx_ctrl_q, skb); +- hci_usb_ctrl_wakeup(husb); +- hdev->stat.cmd_tx++; +- return 0; ++ /* Release reassembly buffers */ ++ if (husb->reassembly[i]) { ++ kfree_skb(husb->reassembly[i]); ++ husb->reassembly[i] = NULL; ++ } ++ } ++} + +- case HCI_ACLDATA_PKT: +- skb_queue_tail(&husb->tx_write_q, skb); +- hci_usb_write_wakeup(husb); +- hdev->stat.acl_tx++; +- return 0; ++/* Close device */ ++static int hci_usb_close(struct hci_dev *hdev) ++{ ++ struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; ++ unsigned long flags; ++ ++ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) ++ return 0; + +- case HCI_SCODATA_PKT: +- return -EOPNOTSUPP; +- }; ++ BT_DBG("%s", hdev->name); ++ ++ write_lock_irqsave(&husb->completion_lock, flags); ++ ++ hci_usb_unlink_urbs(husb); ++ hci_usb_flush(hdev); ++ ++ write_unlock_irqrestore(&husb->completion_lock, flags); + ++ MOD_DEC_USE_COUNT; + return 0; + } + +-/* ---------- USB ------------- */ ++static int __tx_submit(struct hci_usb *husb, struct _urb *_urb) ++{ ++ struct urb *urb = &_urb->urb; ++ int err; + +-static void hci_usb_ctrl(struct urb *urb) ++ BT_DBG("%s urb %p type %d", husb->hdev.name, urb, _urb->type); ++ ++ _urb_queue_tail(__pending_q(husb, _urb->type), _urb); ++ err = usb_submit_urb(urb); ++ if (err) { ++ BT_ERR("%s tx submit failed urb %p type %d err %d", ++ husb->hdev.name, urb, _urb->type, err); ++ _urb_unlink(_urb); ++ _urb_queue_tail(__completed_q(husb, _urb->type), _urb); ++ } else ++ atomic_inc(__pending_tx(husb, _urb->type)); ++ ++ return err; ++} ++ ++static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb) + { +- struct sk_buff *skb = (struct sk_buff *) urb->context; +- struct hci_dev *hdev; +- struct hci_usb *husb; ++ struct _urb *_urb = __get_completed(husb, skb->pkt_type); ++ devrequest *dr; ++ struct urb *urb; + +- if (!skb) +- return; +- hdev = (struct hci_dev *) skb->dev; +- husb = (struct hci_usb *) hdev->driver_data; ++ if (!_urb) { ++ _urb = _urb_alloc(0, GFP_ATOMIC); ++ if (!_urb) ++ return -ENOMEM; ++ _urb->type = skb->pkt_type; + +- DBG("%s", hdev->name); ++ dr = kmalloc(sizeof(*dr), GFP_ATOMIC); ++ if (!dr) { ++ _urb_free(_urb); ++ return -ENOMEM; ++ } ++ } else ++ dr = (void *) _urb->urb.setup_packet; + +- if (urb->status) +- DBG("%s ctrl status: %d", hdev->name, urb->status); ++ dr->requesttype = husb->ctrl_req; ++ dr->request = 0; ++ dr->index = 0; ++ dr->value = 0; ++ dr->length = __cpu_to_le16(skb->len); + +- clear_bit(HCI_TX_CTRL, &husb->tx_state); +- kfree_skb(skb); ++ urb = &_urb->urb; ++ FILL_CONTROL_URB(urb, husb->udev, usb_sndctrlpipe(husb->udev, 0), ++ (void *) dr, skb->data, skb->len, hci_usb_tx_complete, husb); + +- /* Wake up device */ +- hci_usb_ctrl_wakeup(husb); ++ BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len); ++ ++ _urb->priv = skb; ++ return __tx_submit(husb, _urb); + } + +-static void hci_usb_bulk_write(struct urb *urb) ++static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb) + { +- struct sk_buff *skb = (struct sk_buff *) urb->context; +- struct hci_dev *hdev; +- struct hci_usb *husb; +- +- if (!skb) +- return; +- hdev = (struct hci_dev *) skb->dev; +- husb = (struct hci_usb *) hdev->driver_data; +- +- DBG("%s", hdev->name); ++ struct _urb *_urb = __get_completed(husb, skb->pkt_type); ++ struct urb *urb; ++ int pipe; + +- if (urb->status) +- DBG("%s bulk write status: %d", hdev->name, urb->status); ++ if (!_urb) { ++ _urb = _urb_alloc(0, GFP_ATOMIC); ++ if (!_urb) ++ return -ENOMEM; ++ _urb->type = skb->pkt_type; ++ } + +- clear_bit(HCI_TX_WRITE, &husb->tx_state); +- kfree_skb(skb); ++ urb = &_urb->urb; ++ pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep->bEndpointAddress); ++ FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len, ++ hci_usb_tx_complete, husb); ++ urb->transfer_flags = USB_QUEUE_BULK | USB_ZERO_PACKET; + +- /* Wake up device */ +- hci_usb_write_wakeup(husb); ++ BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len); + +- return; ++ _urb->priv = skb; ++ return __tx_submit(husb, _urb); + } + +-static void hci_usb_intr(struct urb *urb) ++#ifdef CONFIG_BLUEZ_HCIUSB_SCO ++static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb) + { +- struct hci_usb *husb = (struct hci_usb *) urb->context; +- unsigned char *data = urb->transfer_buffer; +- register int count = urb->actual_length; +- register struct sk_buff *skb = husb->intr_skb; +- hci_event_hdr *eh; +- register int len; ++ struct _urb *_urb = __get_completed(husb, skb->pkt_type); ++ struct urb *urb; ++ ++ if (!_urb) { ++ _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC); ++ if (!_urb) ++ return -ENOMEM; ++ _urb->type = skb->pkt_type; ++ } + +- if (!husb) +- return; ++ BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len); + +- DBG("%s count %d", husb->hdev.name, count); ++ urb = &_urb->urb; ++ ++ urb->context = husb; ++ urb->dev = husb->udev; ++ urb->pipe = usb_sndisocpipe(husb->udev, husb->isoc_out_ep->bEndpointAddress); ++ urb->complete = hci_usb_tx_complete; ++ urb->transfer_flags = USB_ISO_ASAP; + +- if (urb->status || !count) { +- DBG("%s intr status %d, count %d", husb->hdev.name, urb->status, count); +- return; +- } ++ urb->transfer_buffer = skb->data; ++ urb->transfer_buffer_length = skb->len; ++ ++ __fill_isoc_desc(urb, skb->len, husb->isoc_out_ep->wMaxPacketSize); + +- /* Do we really have to handle continuations here ? */ +- if (!skb) { +- /* New frame */ +- if (count < HCI_EVENT_HDR_SIZE) { +- DBG("%s bad frame len %d", husb->hdev.name, count); +- return; +- } ++ _urb->priv = skb; ++ return __tx_submit(husb, _urb); ++} ++#endif + +- eh = (hci_event_hdr *) data; +- len = eh->plen + HCI_EVENT_HDR_SIZE; ++static void hci_usb_tx_process(struct hci_usb *husb) ++{ ++ struct sk_buff_head *q; ++ struct sk_buff *skb; + +- if (count > len) { +- DBG("%s corrupted frame, len %d", husb->hdev.name, count); +- return; ++ BT_DBG("%s", husb->hdev.name); ++ ++ do { ++ clear_bit(HCI_USB_TX_WAKEUP, &husb->state); ++ ++ /* Process command queue */ ++ q = __transmit_q(husb, HCI_COMMAND_PKT); ++ if (!atomic_read(__pending_tx(husb, HCI_COMMAND_PKT)) && ++ (skb = skb_dequeue(q))) { ++ if (hci_usb_send_ctrl(husb, skb) < 0) ++ skb_queue_head(q, skb); + } + +- /* Allocate skb */ +- if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) { +- ERR("Can't allocate mem for new packet"); +- return; ++#ifdef CONFIG_BLUEZ_HCIUSB_SCO ++ /* Process SCO queue */ ++ q = __transmit_q(husb, HCI_SCODATA_PKT); ++ if (atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) < HCI_MAX_ISOC_TX && ++ (skb = skb_dequeue(q))) { ++ if (hci_usb_send_isoc(husb, skb) < 0) ++ skb_queue_head(q, skb); + } +- skb->dev = (void *) &husb->hdev; +- skb->pkt_type = HCI_EVENT_PKT; ++#endif ++ ++ /* Process ACL queue */ ++ q = __transmit_q(husb, HCI_ACLDATA_PKT); ++ while (atomic_read(__pending_tx(husb, HCI_ACLDATA_PKT)) < HCI_MAX_BULK_TX && ++ (skb = skb_dequeue(q))) { ++ if (hci_usb_send_bulk(husb, skb) < 0) { ++ skb_queue_head(q, skb); ++ break; ++ } ++ } ++ } while(test_bit(HCI_USB_TX_WAKEUP, &husb->state)); ++} + +- husb->intr_skb = skb; +- husb->intr_count = len; +- } else { +- /* Continuation */ +- if (count > husb->intr_count) { +- ERR("%s bad frame len %d (expected %d)", husb->hdev.name, count, husb->intr_count); ++static inline void hci_usb_tx_wakeup(struct hci_usb *husb) ++{ ++ /* Serialize TX queue processing to avoid data reordering */ ++ if (!test_and_set_bit(HCI_USB_TX_PROCESS, &husb->state)) { ++ hci_usb_tx_process(husb); ++ clear_bit(HCI_USB_TX_PROCESS, &husb->state); ++ } else ++ set_bit(HCI_USB_TX_WAKEUP, &husb->state); ++} + +- kfree_skb(skb); +- husb->intr_skb = NULL; +- husb->intr_count = 0; +- return; +- } ++/* Send frames from HCI layer */ ++static int hci_usb_send_frame(struct sk_buff *skb) ++{ ++ struct hci_dev *hdev = (struct hci_dev *) skb->dev; ++ struct hci_usb *husb; ++ ++ if (!hdev) { ++ BT_ERR("frame for uknown device (hdev=NULL)"); ++ return -ENODEV; + } + +- memcpy(skb_put(skb, count), data, count); +- husb->intr_count -= count; ++ if (!test_bit(HCI_RUNNING, &hdev->flags)) ++ return -EBUSY; + +- DMP(data, count); ++ BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); + +- if (!husb->intr_count) { +- /* Got complete frame */ ++ husb = (struct hci_usb *) hdev->driver_data; + +- husb->hdev.stat.byte_rx += skb->len; +- hci_recv_frame(skb); ++ switch (skb->pkt_type) { ++ case HCI_COMMAND_PKT: ++ hdev->stat.cmd_tx++; ++ break; + +- husb->intr_skb = NULL; +- } +-} ++ case HCI_ACLDATA_PKT: ++ hdev->stat.acl_tx++; ++ break; + +-static void hci_usb_bulk_read(struct urb *urb) +-{ +- struct hci_usb *husb = (struct hci_usb *) urb->context; +- unsigned char *data = urb->transfer_buffer; +- int count = urb->actual_length, status; +- struct sk_buff *skb; +- hci_acl_hdr *ah; +- register __u16 dlen; ++#ifdef CONFIG_BLUEZ_HCIUSB_SCO ++ case HCI_SCODATA_PKT: ++ hdev->stat.sco_tx++; ++ break; ++#endif + +- if (!husb) +- return; ++ default: ++ kfree_skb(skb); ++ return 0; ++ } + +- DBG("%s status %d, count %d, flags %x", husb->hdev.name, urb->status, count, urb->transfer_flags); ++ read_lock(&husb->completion_lock); + +- if (urb->status) { +- /* Do not re-submit URB on critical errors */ +- switch (urb->status) { +- case -ENOENT: +- return; +- default: +- goto resubmit; +- }; +- } +- if (!count) +- goto resubmit; ++ skb_queue_tail(__transmit_q(husb, skb->pkt_type), skb); ++ hci_usb_tx_wakeup(husb); + +- DMP(data, count); ++ read_unlock(&husb->completion_lock); ++ return 0; ++} + +- ah = (hci_acl_hdr *) data; +- dlen = le16_to_cpu(ah->dlen); ++static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int count) ++{ ++ BT_DBG("%s type %d data %p count %d", husb->hdev.name, type, data, count); + +- /* Verify frame len and completeness */ +- if ((count - HCI_ACL_HDR_SIZE) != dlen) { +- ERR("%s corrupted ACL packet: count %d, plen %d", husb->hdev.name, count, dlen); +- goto resubmit; +- } ++ husb->hdev.stat.byte_rx += count; + +- /* Allocate packet */ +- if (!(skb = bluez_skb_alloc(count, GFP_ATOMIC))) { +- ERR("Can't allocate mem for new packet"); +- goto resubmit; +- } ++ while (count) { ++ struct sk_buff *skb = __reassembly(husb, type); ++ struct { int expect; } *scb; ++ int len = 0; ++ ++ if (!skb) { ++ /* Start of the frame */ + +- memcpy(skb_put(skb, count), data, count); +- skb->dev = (void *) &husb->hdev; +- skb->pkt_type = HCI_ACLDATA_PKT; ++ switch (type) { ++ case HCI_EVENT_PKT: ++ if (count >= HCI_EVENT_HDR_SIZE) { ++ hci_event_hdr *h = data; ++ len = HCI_EVENT_HDR_SIZE + h->plen; ++ } else ++ return -EILSEQ; ++ break; + +- husb->hdev.stat.byte_rx += skb->len; ++ case HCI_ACLDATA_PKT: ++ if (count >= HCI_ACL_HDR_SIZE) { ++ hci_acl_hdr *h = data; ++ len = HCI_ACL_HDR_SIZE + __le16_to_cpu(h->dlen); ++ } else ++ return -EILSEQ; ++ break; ++#ifdef CONFIG_BLUEZ_HCIUSB_SCO ++ case HCI_SCODATA_PKT: ++ if (count >= HCI_SCO_HDR_SIZE) { ++ hci_sco_hdr *h = data; ++ len = HCI_SCO_HDR_SIZE + h->dlen; ++ } else ++ return -EILSEQ; ++ break; ++#endif ++ } ++ BT_DBG("new packet len %d", len); ++ ++ skb = bluez_skb_alloc(len, GFP_ATOMIC); ++ if (!skb) { ++ BT_ERR("%s no memory for the packet", husb->hdev.name); ++ return -ENOMEM; ++ } ++ skb->dev = (void *) &husb->hdev; ++ skb->pkt_type = type; ++ ++ __reassembly(husb, type) = skb; + +- hci_recv_frame(skb); ++ scb = (void *) skb->cb; ++ scb->expect = len; ++ } else { ++ /* Continuation */ ++ scb = (void *) skb->cb; ++ len = scb->expect; ++ } + +-resubmit: +- husb->read_urb->dev = husb->udev; +- if ((status = usb_submit_urb(husb->read_urb))) +- DBG("%s read URB submit failed %d", husb->hdev.name, status); ++ len = min(len, count); ++ ++ memcpy(skb_put(skb, len), data, len); + +- DBG("%s read URB re-submited", husb->hdev.name); ++ scb->expect -= len; ++ if (!scb->expect) { ++ /* Complete frame */ ++ __reassembly(husb, type) = NULL; ++ hci_recv_frame(skb); ++ } ++ ++ count -= len; data += len; ++ } ++ return 0; + } + +-static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb) ++static void hci_usb_rx_complete(struct urb *urb) + { +- struct urb *urb = husb->ctrl_urb; +- devrequest *dr = &husb->dev_req; +- int pipe, status; ++ struct _urb *_urb = container_of(urb, struct _urb, urb); ++ struct hci_usb *husb = (void *) urb->context; ++ struct hci_dev *hdev = &husb->hdev; ++ int err, count = urb->actual_length; + +- DBG("%s len %d", husb->hdev.name, skb->len); ++ BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb, ++ _urb->type, urb->status, count, urb->transfer_flags); + +- pipe = usb_sndctrlpipe(husb->udev, 0); ++ if (!test_bit(HCI_RUNNING, &hdev->flags)) ++ return; + +- dr->requesttype = HCI_CTRL_REQ; +- dr->request = 0; +- dr->index = 0; +- dr->value = 0; +- dr->length = cpu_to_le16(skb->len); ++ read_lock(&husb->completion_lock); + +- FILL_CONTROL_URB(urb, husb->udev, pipe, (void*)dr, skb->data, skb->len, +- hci_usb_ctrl, skb); ++ if (urb->status || !count) ++ goto resubmit; + +- if ((status = usb_submit_urb(urb))) { +- DBG("%s control URB submit failed %d", husb->hdev.name, status); +- return status; ++ if (_urb->type == HCI_SCODATA_PKT) { ++#ifdef CONFIG_BLUEZ_HCIUSB_SCO ++ int i; ++ for (i=0; i < urb->number_of_packets; i++) { ++ BT_DBG("desc %d status %d offset %d len %d", i, ++ urb->iso_frame_desc[i].status, ++ urb->iso_frame_desc[i].offset, ++ urb->iso_frame_desc[i].actual_length); ++ ++ if (!urb->iso_frame_desc[i].status) ++ __recv_frame(husb, _urb->type, ++ urb->transfer_buffer + urb->iso_frame_desc[i].offset, ++ urb->iso_frame_desc[i].actual_length); ++ } ++#else ++ ; ++#endif ++ } else { ++ err = __recv_frame(husb, _urb->type, urb->transfer_buffer, count); ++ if (err < 0) { ++ BT_ERR("%s corrupted packet: type %d count %d", ++ husb->hdev.name, _urb->type, count); ++ hdev->stat.err_rx++; ++ } + } + +- return 0; ++resubmit: ++ if (_urb->type != HCI_EVENT_PKT) { ++ urb->dev = husb->udev; ++ err = usb_submit_urb(urb); ++ BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb, ++ _urb->type, err); ++ } ++ read_unlock(&husb->completion_lock); + } + +-static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb) ++static void hci_usb_tx_complete(struct urb *urb) + { +- struct urb *urb = husb->write_urb; +- int pipe, status; ++ struct _urb *_urb = container_of(urb, struct _urb, urb); ++ struct hci_usb *husb = (void *) urb->context; ++ struct hci_dev *hdev = &husb->hdev; + +- DBG("%s len %d", husb->hdev.name, skb->len); ++ BT_DBG("%s urb %p status %d flags %x", hdev->name, urb, ++ urb->status, urb->transfer_flags); + +- pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep_addr); ++ atomic_dec(__pending_tx(husb, _urb->type)); + +- FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len, +- hci_usb_bulk_write, skb); +- urb->transfer_flags |= USB_QUEUE_BULK; ++ urb->transfer_buffer = NULL; ++ kfree_skb((struct sk_buff *) _urb->priv); + +- if ((status = usb_submit_urb(urb))) { +- DBG("%s write URB submit failed %d", husb->hdev.name, status); +- return status; +- } ++ if (!test_bit(HCI_RUNNING, &hdev->flags)) ++ return; + +- return 0; ++ if (!urb->status) ++ hdev->stat.byte_tx += urb->transfer_buffer_length; ++ else ++ hdev->stat.err_tx++; ++ ++ read_lock(&husb->completion_lock); ++ ++ _urb_unlink(_urb); ++ _urb_queue_tail(__completed_q(husb, _urb->type), _urb); ++ ++ hci_usb_tx_wakeup(husb); ++ ++ read_unlock(&husb->completion_lock); + } + +-static void * hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id) ++static void hci_usb_destruct(struct hci_dev *hdev) + { +- struct usb_endpoint_descriptor *bulk_out_ep, *intr_in_ep, *bulk_in_ep; ++ struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; ++ ++ BT_DBG("%s", hdev->name); ++ ++ kfree(husb); ++} ++ ++static void *hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id) ++{ ++ struct usb_endpoint_descriptor *bulk_out_ep[HCI_MAX_IFACE_NUM]; ++ struct usb_endpoint_descriptor *isoc_out_ep[HCI_MAX_IFACE_NUM]; ++ struct usb_endpoint_descriptor *bulk_in_ep[HCI_MAX_IFACE_NUM]; ++ struct usb_endpoint_descriptor *isoc_in_ep[HCI_MAX_IFACE_NUM]; ++ struct usb_endpoint_descriptor *intr_in_ep[HCI_MAX_IFACE_NUM]; + struct usb_interface_descriptor *uif; + struct usb_endpoint_descriptor *ep; ++ struct usb_interface *iface, *isoc_iface; + struct hci_usb *husb; + struct hci_dev *hdev; +- int i, size, pipe; +- __u8 * buf; +- +- DBG("udev %p ifnum %d", udev, ifnum); ++ int i, a, e, size, ifn, isoc_ifnum, isoc_alts; + +- /* Check device signature */ +- if ((udev->descriptor.bDeviceClass != HCI_DEV_CLASS) || +- (udev->descriptor.bDeviceSubClass != HCI_DEV_SUBCLASS)|| +- (udev->descriptor.bDeviceProtocol != HCI_DEV_PROTOCOL) ) +- return NULL; ++ BT_DBG("udev %p ifnum %d", udev, ifnum); + +- MOD_INC_USE_COUNT; ++ iface = &udev->actconfig->interface[0]; + +- uif = &udev->actconfig->interface[ifnum].altsetting[0]; ++ /* Check our black list */ ++ if (usb_match_id(udev, iface, ignore_ids)) ++ return NULL; + +- if (uif->bNumEndpoints != 3) { +- DBG("Wrong number of endpoints %d", uif->bNumEndpoints); +- MOD_DEC_USE_COUNT; ++ /* Check number of endpoints */ ++ if (udev->actconfig->interface[ifnum].altsetting[0].bNumEndpoints < 3) + return NULL; +- } + +- bulk_out_ep = intr_in_ep = bulk_in_ep = NULL; ++ memset(bulk_out_ep, 0, sizeof(bulk_out_ep)); ++ memset(isoc_out_ep, 0, sizeof(isoc_out_ep)); ++ memset(bulk_in_ep, 0, sizeof(bulk_in_ep)); ++ memset(isoc_in_ep, 0, sizeof(isoc_in_ep)); ++ memset(intr_in_ep, 0, sizeof(intr_in_ep)); + ++ size = 0; ++ isoc_iface = NULL; ++ isoc_alts = isoc_ifnum = 0; ++ + /* Find endpoints that we need */ +- for ( i = 0; i < uif->bNumEndpoints; ++i) { +- ep = &uif->endpoint[i]; + +- switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { +- case USB_ENDPOINT_XFER_BULK: +- if (ep->bEndpointAddress & USB_DIR_IN) +- bulk_in_ep = ep; +- else +- bulk_out_ep = ep; +- break; +- +- case USB_ENDPOINT_XFER_INT: +- intr_in_ep = ep; +- break; +- }; +- } ++ ifn = MIN(udev->actconfig->bNumInterfaces, HCI_MAX_IFACE_NUM); ++ for (i = 0; i < ifn; i++) { ++ iface = &udev->actconfig->interface[i]; ++ for (a = 0; a < iface->num_altsetting; a++) { ++ uif = &iface->altsetting[a]; ++ for (e = 0; e < uif->bNumEndpoints; e++) { ++ ep = &uif->endpoint[e]; + +- if (!bulk_in_ep || !bulk_out_ep || !intr_in_ep) { +- DBG("Endpoints not found: %p %p %p", bulk_in_ep, bulk_out_ep, intr_in_ep); +- MOD_DEC_USE_COUNT; +- return NULL; +- } ++ switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { ++ case USB_ENDPOINT_XFER_INT: ++ if (ep->bEndpointAddress & USB_DIR_IN) ++ intr_in_ep[i] = ep; ++ break; + +- if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) { +- ERR("Can't allocate: control structure"); +- MOD_DEC_USE_COUNT; +- return NULL; +- } ++ case USB_ENDPOINT_XFER_BULK: ++ if (ep->bEndpointAddress & USB_DIR_IN) ++ bulk_in_ep[i] = ep; ++ else ++ bulk_out_ep[i] = ep; ++ break; + +- memset(husb, 0, sizeof(struct hci_usb)); ++#ifdef CONFIG_BLUEZ_HCIUSB_SCO ++ case USB_ENDPOINT_XFER_ISOC: ++ if (ep->wMaxPacketSize < size || a > 2) ++ break; ++ size = ep->wMaxPacketSize; + +- husb->udev = udev; +- husb->bulk_out_ep_addr = bulk_out_ep->bEndpointAddress; ++ isoc_iface = iface; ++ isoc_alts = a; ++ isoc_ifnum = i; + +- if (!(husb->ctrl_urb = usb_alloc_urb(0))) { +- ERR("Can't allocate: control URB"); +- goto probe_error; ++ if (ep->bEndpointAddress & USB_DIR_IN) ++ isoc_in_ep[i] = ep; ++ else ++ isoc_out_ep[i] = ep; ++ break; ++#endif ++ } ++ } ++ } + } + +- if (!(husb->write_urb = usb_alloc_urb(0))) { +- ERR("Can't allocate: write URB"); +- goto probe_error; ++ if (!bulk_in_ep[0] || !bulk_out_ep[0] || !intr_in_ep[0]) { ++ BT_DBG("Bulk endpoints not found"); ++ goto done; + } + +- if (!(husb->read_urb = usb_alloc_urb(0))) { +- ERR("Can't allocate: read URB"); +- goto probe_error; ++#ifdef CONFIG_BLUEZ_HCIUSB_SCO ++ if (!isoc_in_ep[1] || !isoc_out_ep[1]) { ++ BT_DBG("Isoc endpoints not found"); ++ isoc_iface = NULL; + } ++#endif + +- ep = bulk_in_ep; +- pipe = usb_rcvbulkpipe(udev, ep->bEndpointAddress); +- size = HCI_MAX_FRAME_SIZE; +- +- if (!(buf = kmalloc(size, GFP_KERNEL))) { +- ERR("Can't allocate: read buffer"); +- goto probe_error; ++ if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) { ++ BT_ERR("Can't allocate: control structure"); ++ goto done; + } + +- FILL_BULK_URB(husb->read_urb, udev, pipe, buf, size, hci_usb_bulk_read, husb); +- husb->read_urb->transfer_flags |= USB_QUEUE_BULK; ++ memset(husb, 0, sizeof(struct hci_usb)); + +- ep = intr_in_ep; +- pipe = usb_rcvintpipe(udev, ep->bEndpointAddress); +- size = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); ++ husb->udev = udev; ++ husb->bulk_out_ep = bulk_out_ep[0]; ++ husb->bulk_in_ep = bulk_in_ep[0]; ++ husb->intr_in_ep = intr_in_ep[0]; + +- if (!(husb->intr_urb = usb_alloc_urb(0))) { +- ERR("Can't allocate: interrupt URB"); +- goto probe_error; +- } ++ if (id->driver_info & HCI_DIGIANSWER) ++ husb->ctrl_req = HCI_DIGI_REQ; ++ else ++ husb->ctrl_req = HCI_CTRL_REQ; + +- if (!(buf = kmalloc(size, GFP_KERNEL))) { +- ERR("Can't allocate: interrupt buffer"); +- goto probe_error; ++#ifdef CONFIG_BLUEZ_HCIUSB_SCO ++ if (isoc_iface) { ++ BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts); ++ if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) { ++ BT_ERR("Can't set isoc interface settings"); ++ isoc_iface = NULL; ++ } ++ usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb); ++ husb->isoc_iface = isoc_iface; ++ husb->isoc_in_ep = isoc_in_ep[isoc_ifnum]; ++ husb->isoc_out_ep = isoc_out_ep[isoc_ifnum]; + } ++#endif ++ ++ husb->completion_lock = RW_LOCK_UNLOCKED; + +- FILL_INT_URB(husb->intr_urb, udev, pipe, buf, size, hci_usb_intr, husb, ep->bInterval); +- +- skb_queue_head_init(&husb->tx_ctrl_q); +- skb_queue_head_init(&husb->tx_write_q); ++ for (i = 0; i < 4; i++) { ++ skb_queue_head_init(&husb->transmit_q[i]); ++ _urb_queue_init(&husb->pending_q[i]); ++ _urb_queue_init(&husb->completed_q[i]); ++ } + + /* Initialize and register HCI device */ + hdev = &husb->hdev; + +- hdev->type = HCI_USB; ++ hdev->type = HCI_USB; + hdev->driver_data = husb; + + hdev->open = hci_usb_open; + hdev->close = hci_usb_close; + hdev->flush = hci_usb_flush; +- hdev->send = hci_usb_send_frame; ++ hdev->send = hci_usb_send_frame; ++ hdev->destruct = hci_usb_destruct; + + if (hci_register_dev(hdev) < 0) { +- ERR("Can't register HCI device %s", hdev->name); ++ BT_ERR("Can't register HCI device"); + goto probe_error; + } + + return husb; + + probe_error: +- hci_usb_free_bufs(husb); + kfree(husb); +- MOD_DEC_USE_COUNT; ++ ++done: + return NULL; + } + +@@ -626,38 +943,34 @@ + if (!husb) + return; + +- DBG("%s", hdev->name); ++ BT_DBG("%s", hdev->name); + + hci_usb_close(hdev); + +- if (hci_unregister_dev(hdev) < 0) { +- ERR("Can't unregister HCI device %s", hdev->name); +- } +- +- hci_usb_free_bufs(husb); +- kfree(husb); ++ if (husb->isoc_iface) ++ usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface); + +- MOD_DEC_USE_COUNT; ++ if (hci_unregister_dev(hdev) < 0) ++ BT_ERR("Can't unregister HCI device %s", hdev->name); + } + +-static struct usb_driver hci_usb_driver = +-{ ++static struct usb_driver hci_usb_driver = { + name: "hci_usb", + probe: hci_usb_probe, + disconnect: hci_usb_disconnect, +- id_table: usb_bluetooth_ids, ++ id_table: bluetooth_ids, + }; + + int hci_usb_init(void) + { + int err; + +- INF("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", ++ BT_INFO("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", + VERSION); +- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); ++ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); + + if ((err = usb_register(&hci_usb_driver)) < 0) +- ERR("Failed to register HCI USB driver"); ++ BT_ERR("Failed to register HCI USB driver"); + + return err; + } +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/drivers/bluetooth/hci_usb.h 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,144 @@ ++/* ++ HCI USB driver for Linux Bluetooth protocol stack (BlueZ) ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> ++ ++ Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#ifdef __KERNEL__ ++ ++/* Class, SubClass, and Protocol codes that describe a Bluetooth device */ ++#define HCI_DEV_CLASS 0xe0 /* Wireless class */ ++#define HCI_DEV_SUBCLASS 0x01 /* RF subclass */ ++#define HCI_DEV_PROTOCOL 0x01 /* Bluetooth programming protocol */ ++ ++#define HCI_CTRL_REQ 0x20 ++#define HCI_DIGI_REQ 0x40 ++ ++#define HCI_DIGIANSWER 0x01 ++ ++#define HCI_MAX_IFACE_NUM 3 ++ ++#define HCI_MAX_BULK_TX 4 ++#define HCI_MAX_BULK_RX 1 ++ ++#define HCI_MAX_ISOC_RX 2 ++#define HCI_MAX_ISOC_TX 2 ++ ++#define HCI_MAX_ISOC_FRAMES 10 ++ ++struct _urb_queue { ++ struct list_head head; ++ spinlock_t lock; ++}; ++ ++struct _urb { ++ struct list_head list; ++ struct _urb_queue *queue; ++ int type; ++ void *priv; ++ struct urb urb; ++}; ++ ++struct _urb *_urb_alloc(int isoc, int gfp); ++ ++static inline void _urb_free(struct _urb *_urb) ++{ ++ kfree(_urb); ++} ++ ++static inline void _urb_queue_init(struct _urb_queue *q) ++{ ++ INIT_LIST_HEAD(&q->head); ++ spin_lock_init(&q->lock); ++} ++ ++static inline void _urb_queue_head(struct _urb_queue *q, struct _urb *_urb) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(&q->lock, flags); ++ list_add(&_urb->list, &q->head); _urb->queue = q; ++ spin_unlock_irqrestore(&q->lock, flags); ++} ++ ++static inline void _urb_queue_tail(struct _urb_queue *q, struct _urb *_urb) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(&q->lock, flags); ++ list_add_tail(&_urb->list, &q->head); _urb->queue = q; ++ spin_unlock_irqrestore(&q->lock, flags); ++} ++ ++static inline void _urb_unlink(struct _urb *_urb) ++{ ++ struct _urb_queue *q = _urb->queue; ++ unsigned long flags; ++ if (q) { ++ spin_lock_irqsave(&q->lock, flags); ++ list_del(&_urb->list); _urb->queue = NULL; ++ spin_unlock_irqrestore(&q->lock, flags); ++ } ++} ++ ++struct _urb *_urb_dequeue(struct _urb_queue *q); ++ ++#ifndef container_of ++#define container_of(ptr, type, member) ({ \ ++ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ++ (type *)( (char *)__mptr - offsetof(type,member) );}) ++#endif ++ ++struct hci_usb { ++ struct hci_dev hdev; ++ ++ unsigned long state; ++ ++ struct usb_device *udev; ++ ++ struct usb_endpoint_descriptor *bulk_in_ep; ++ struct usb_endpoint_descriptor *bulk_out_ep; ++ struct usb_endpoint_descriptor *intr_in_ep; ++ ++ struct usb_interface *isoc_iface; ++ struct usb_endpoint_descriptor *isoc_out_ep; ++ struct usb_endpoint_descriptor *isoc_in_ep; ++ ++ __u8 ctrl_req; ++ ++ struct sk_buff_head transmit_q[4]; ++ struct sk_buff *reassembly[4]; // Reassembly buffers ++ ++ rwlock_t completion_lock; ++ ++ atomic_t pending_tx[4]; // Number of pending requests ++ struct _urb_queue pending_q[4]; // Pending requests ++ struct _urb_queue completed_q[4]; // Completed requests ++}; ++ ++/* States */ ++#define HCI_USB_TX_PROCESS 1 ++#define HCI_USB_TX_WAKEUP 2 ++ ++#endif /* __KERNEL__ */ +--- linux/drivers/bluetooth/hci_vhci.c~bluetooth-2.4.18-mh11 2001-09-07 18:28:38.000000000 +0200 ++++ linux/drivers/bluetooth/hci_vhci.c 2004-01-25 23:37:39.000000000 +0100 +@@ -25,9 +25,9 @@ + /* + * BlueZ HCI virtual device driver. + * +- * $Id$ ++ * $Id$ + */ +-#define VERSION "1.0" ++#define VERSION "1.1" + + #include <linux/config.h> + #include <linux/module.h> +@@ -49,43 +49,56 @@ + #include <asm/uaccess.h> + + #include <net/bluetooth/bluetooth.h> +-#include <net/bluetooth/bluez.h> + #include <net/bluetooth/hci_core.h> +-#include <net/bluetooth/hci_vhci.h> ++#include "hci_vhci.h" + + /* HCI device part */ + +-int hci_vhci_open(struct hci_dev *hdev) ++static int hci_vhci_open(struct hci_dev *hdev) + { +- hdev->flags |= HCI_RUNNING; ++ set_bit(HCI_RUNNING, &hdev->flags); + return 0; + } + +-int hci_vhci_flush(struct hci_dev *hdev) ++static int hci_vhci_flush(struct hci_dev *hdev) + { + struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) hdev->driver_data; + skb_queue_purge(&hci_vhci->readq); + return 0; + } + +-int hci_vhci_close(struct hci_dev *hdev) ++static int hci_vhci_close(struct hci_dev *hdev) + { +- hdev->flags &= ~HCI_RUNNING; ++ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) ++ return 0; ++ + hci_vhci_flush(hdev); + return 0; + } + +-int hci_vhci_send_frame(struct sk_buff *skb) ++static void hci_vhci_destruct(struct hci_dev *hdev) ++{ ++ struct hci_vhci_struct *vhci; ++ ++ if (!hdev) return; ++ ++ vhci = (struct hci_vhci_struct *) hdev->driver_data; ++ kfree(vhci); ++ ++ MOD_DEC_USE_COUNT; ++} ++ ++static int hci_vhci_send_frame(struct sk_buff *skb) + { + struct hci_dev* hdev = (struct hci_dev *) skb->dev; + struct hci_vhci_struct *hci_vhci; + + if (!hdev) { +- ERR("Frame for uknown device (hdev=NULL)"); ++ BT_ERR("Frame for uknown device (hdev=NULL)"); + return -ENODEV; + } + +- if (!(hdev->flags & HCI_RUNNING)) ++ if (!test_bit(HCI_RUNNING, &hdev->flags)) + return -EBUSY; + + hci_vhci = (struct hci_vhci_struct *) hdev->driver_data; +@@ -188,7 +201,7 @@ + + add_wait_queue(&hci_vhci->read_wait, &wait); + while (count) { +- current->state = TASK_INTERRUPTIBLE; ++ set_current_state(TASK_INTERRUPTIBLE); + + /* Read frames from device queue */ + if (!(skb = skb_dequeue(&hci_vhci->readq))) { +@@ -214,8 +227,7 @@ + kfree_skb(skb); + break; + } +- +- current->state = TASK_RUNNING; ++ set_current_state(TASK_RUNNING); + remove_wait_queue(&hci_vhci->read_wait, &wait); + + return ret; +@@ -270,11 +282,13 @@ + hdev->close = hci_vhci_close; + hdev->flush = hci_vhci_flush; + hdev->send = hci_vhci_send_frame; ++ hdev->destruct = hci_vhci_destruct; + + if (hci_register_dev(hdev) < 0) { + kfree(hci_vhci); + return -EBUSY; + } ++ MOD_INC_USE_COUNT; + + file->private_data = hci_vhci; + return 0; +@@ -285,12 +299,10 @@ + struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data; + + if (hci_unregister_dev(&hci_vhci->hdev) < 0) { +- ERR("Can't unregister HCI device %s", hci_vhci->hdev.name); ++ BT_ERR("Can't unregister HCI device %s", hci_vhci->hdev.name); + } + +- kfree(hci_vhci); + file->private_data = NULL; +- + return 0; + } + +@@ -315,12 +327,12 @@ + + int __init hci_vhci_init(void) + { +- INF("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", ++ BT_INFO("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", + VERSION); +- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); ++ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); + + if (misc_register(&hci_vhci_miscdev)) { +- ERR("Can't register misc device %d\n", VHCI_MINOR); ++ BT_ERR("Can't register misc device %d\n", VHCI_MINOR); + return -EIO; + } + +@@ -337,4 +349,4 @@ + + MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); + MODULE_DESCRIPTION("BlueZ VHCI driver ver " VERSION); +-MODULE_LICENSE("GPL"); ++MODULE_LICENSE("GPL"); +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/drivers/bluetooth/hci_vhci.h 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,50 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#ifndef __HCI_VHCI_H ++#define __HCI_VHCI_H ++ ++#ifdef __KERNEL__ ++ ++struct hci_vhci_struct { ++ struct hci_dev hdev; ++ __u32 flags; ++ wait_queue_head_t read_wait; ++ struct sk_buff_head readq; ++ struct fasync_struct *fasync; ++}; ++ ++/* VHCI device flags */ ++#define VHCI_FASYNC 0x0010 ++ ++#endif /* __KERNEL__ */ ++ ++#define VHCI_DEV "/dev/vhci" ++#define VHCI_MINOR 250 ++ ++#endif /* __HCI_VHCI_H */ +--- linux/drivers/bluetooth/Makefile~bluetooth-2.4.18-mh11 2001-09-07 18:28:38.000000000 +0200 ++++ linux/drivers/bluetooth/Makefile 2004-01-25 23:37:39.000000000 +0100 +@@ -1,11 +1,27 @@ + # +-# Makefile for Bluetooth HCI device drivers. ++# Makefile for the Linux Bluetooth HCI device drivers + # + + O_TARGET := bluetooth.o + ++list-multi := hci_uart.o ++ + obj-$(CONFIG_BLUEZ_HCIUSB) += hci_usb.o +-obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o + obj-$(CONFIG_BLUEZ_HCIVHCI) += hci_vhci.o + ++obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o ++uart-y := hci_ldisc.o ++uart-$(CONFIG_BLUEZ_HCIUART_H4) += hci_h4.o ++uart-$(CONFIG_BLUEZ_HCIUART_BCSP) += hci_bcsp.o ++ ++obj-$(CONFIG_BLUEZ_HCIBFUSB) += bfusb.o ++ ++obj-$(CONFIG_BLUEZ_HCIDTL1) += dtl1_cs.o ++obj-$(CONFIG_BLUEZ_HCIBT3C) += bt3c_cs.o ++obj-$(CONFIG_BLUEZ_HCIBLUECARD) += bluecard_cs.o ++obj-$(CONFIG_BLUEZ_HCIBTUART) += btuart_cs.o ++ + include $(TOPDIR)/Rules.make ++ ++hci_uart.o: $(uart-y) ++ $(LD) -r -o $@ $(uart-y) +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/drivers/bluetooth/Makefile.lib 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1 @@ ++obj-$(CONFIG_BLUEZ_HCIBFUSB) += firmware_class.o +--- linux/drivers/char/pcmcia/serial_cs.c~bluetooth-2.4.18-mh11 2004-01-25 23:28:22.000000000 +0100 ++++ linux/drivers/char/pcmcia/serial_cs.c 2004-01-25 23:37:39.000000000 +0100 +@@ -72,14 +72,14 @@ + static int irq_list[4] = { -1 }; + MODULE_PARM(irq_list, "1-4i"); + +-/* Enable the speaker? */ +-INT_MODULE_PARM(do_sound, 1); ++INT_MODULE_PARM(do_sound, 1); /* Enable the speaker? */ ++INT_MODULE_PARM(buggy_uart, 0); /* Skip strict UART tests? */ + + #ifdef PCMCIA_DEBUG + INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); + #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) + static char *version = +-"serial_cs.c 1.128 2001/10/18 12:18:35 (David Hinds)"; ++"serial_cs.c 1.138 2002/10/25 06:24:52 (David Hinds)"; + #else + #define DEBUG(n, args...) + #endif +@@ -98,6 +98,7 @@ + { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 }, + { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 }, + { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 }, ++ { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D2, 2 }, + { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 }, + { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 }, + { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 }, +@@ -151,7 +152,7 @@ + client_reg_t client_reg; + dev_link_t *link; + int i, ret; +- ++ + DEBUG(0, "serial_attach()\n"); + + /* Create new serial device */ +@@ -163,7 +164,7 @@ + link->release.function = &serial_release; + link->release.data = (u_long)link; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; +- link->io.NumPorts1 = 8; ++ link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) +@@ -172,13 +173,12 @@ + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->conf.Attributes = CONF_ENABLE_IRQ; +- link->conf.Vcc = 50; + if (do_sound) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + link->conf.IntType = INT_MEMORY_AND_IO; +- ++ + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; +@@ -197,7 +197,7 @@ + serial_detach(link); + return NULL; + } +- ++ + return link; + } /* serial_attach */ + +@@ -217,7 +217,7 @@ + int ret; + + DEBUG(0, "serial_detach(0x%p)\n", link); +- ++ + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; +@@ -227,17 +227,17 @@ + del_timer(&link->release); + if (link->state & DEV_CONFIG) + serial_release((u_long)link); +- ++ + if (link->handle) { + ret = CardServices(DeregisterClient, link->handle); + if (ret != CS_SUCCESS) + cs_error(link->handle, DeregisterClient, ret); + } +- ++ + /* Unlink device structure, free bits */ + *linkp = link->next; + kfree(info); +- ++ + } /* serial_detach */ + + /*====================================================================*/ +@@ -246,18 +246,20 @@ + { + struct serial_struct serial; + int line; +- ++ + memset(&serial, 0, sizeof(serial)); + serial.port = port; + serial.irq = irq; + serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ; ++ if (buggy_uart) ++ serial.flags |= ASYNC_BUGGY_UART; + line = register_serial(&serial); + if (line < 0) { + printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx," + " irq %d failed\n", (u_long)serial.port, serial.irq); + return -1; + } +- ++ + info->line[info->ndev] = line; + sprintf(info->node[info->ndev].dev_name, "ttyS%d", line); + info->node[info->ndev].major = TTY_MAJOR; +@@ -265,7 +267,7 @@ + if (info->ndev > 0) + info->node[info->ndev-1].next = &info->node[info->ndev]; + info->ndev++; +- ++ + return 0; + } + +@@ -316,7 +318,10 @@ + return setup_serial(info, port, config.AssignedIRQ); + } + link->conf.Vcc = config.Vcc; +- ++ ++ link->io.NumPorts1 = 8; ++ link->io.NumPorts2 = 0; ++ + /* First pass: look for a config entry that looks normal. */ + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; tuple.TupleDataMax = 255; +@@ -343,7 +348,7 @@ + i = next_tuple(handle, &tuple, &parse); + } + } +- ++ + /* Second pass: try to find an entry that isn't picky about + its base address, then try to grab any standard serial port + address, and finally try to get any free port. */ +@@ -355,8 +360,7 @@ + for (j = 0; j < 5; j++) { + link->io.BasePort1 = base[j]; + link->io.IOAddrLines = base[j] ? 16 : 3; +- i = CardServices(RequestIO, link->handle, +- &link->io); ++ i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) goto found_port; + } + } +@@ -368,7 +372,7 @@ + cs_error(link->handle, RequestIO, i); + return -1; + } +- ++ + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIRQ, i); +@@ -393,8 +397,12 @@ + u_char buf[256]; + cisparse_t parse; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; ++ config_info_t config; + int i, base2 = 0; + ++ CardServices(GetConfigurationInfo, handle, &config); ++ link->conf.Vcc = config.Vcc; ++ + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; tuple.TupleDataMax = 255; + tuple.Attributes = 0; +@@ -436,12 +444,12 @@ + i = next_tuple(handle, &tuple, &parse); + } + } +- ++ + if (i != CS_SUCCESS) { +- cs_error(link->handle, RequestIO, i); +- return -1; ++ /* At worst, try to configure as a single port */ ++ return simple_config(link); + } +- ++ + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIRQ, i); +@@ -457,14 +465,27 @@ + cs_error(link->handle, RequestConfiguration, i); + return -1; + } +- ++ ++ /* The Oxford Semiconductor OXCF950 cards are in fact single-port: ++ 8 registers are for the UART, the others are extra registers */ ++ if (info->manfid == MANFID_OXSEMI) { ++ if (cf->index == 1 || cf->index == 3) { ++ setup_serial(info, base2, link->irq.AssignedIRQ); ++ outb(12,link->io.BasePort1+1); ++ } else { ++ setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ); ++ outb(12,base2+1); ++ } ++ return 0; ++ } ++ + setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ); + /* The Nokia cards are not really multiport cards */ + if (info->manfid == MANFID_NOKIA) + return 0; + for (i = 0; i < info->multi-1; i++) + setup_serial(info, base2+(8*i), link->irq.AssignedIRQ); +- ++ + return 0; + } + +@@ -490,7 +511,7 @@ + int i, last_ret, last_fn; + + DEBUG(0, "serial_config(0x%p)\n", link); +- ++ + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; tuple.TupleDataMax = 255; + tuple.Attributes = 0; +@@ -525,7 +546,7 @@ + } + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; +- ++ + /* Configure card */ + link->state |= DEV_CONFIG; + +@@ -533,8 +554,8 @@ + tuple.DesiredTuple = CISTPL_LONGLINK_MFC; + tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; + info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS); +- +- /* Is this a multiport card? */ ++ ++ /* Scan list of known multiport card ID's */ + tuple.DesiredTuple = CISTPL_MANFID; + if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { + info->manfid = le16_to_cpu(buf[0]); +@@ -589,15 +610,15 @@ + } + #endif + } +- ++ + if (info->multi > 1) + multi_config(link); + else + simple_config(link); +- ++ + if (info->ndev == 0) + goto failed; +- ++ + if (info->manfid == MANFID_IBM) { + conf_reg_t reg = { 0, CS_READ, 0x800, 0 }; + CS_CHECK(AccessConfigurationRegister, link->handle, ®); +@@ -614,6 +635,7 @@ + cs_error(link->handle, last_fn, last_ret); + failed: + serial_release((u_long)link); ++ link->state &= ~DEV_CONFIG_PENDING; + + } /* serial_config */ + +@@ -621,7 +643,7 @@ + + After a card is removed, serial_release() will unregister the net + device, and release the PCMCIA configuration. +- ++ + ======================================================================*/ + + void serial_release(u_long arg) +@@ -629,7 +651,7 @@ + dev_link_t *link = (dev_link_t *)arg; + serial_info_t *info = link->priv; + int i; +- ++ + DEBUG(0, "serial_release(0x%p)\n", link); + + for (i = 0; i < info->ndev; i++) { +@@ -642,7 +664,7 @@ + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + } +- ++ + link->state &= ~DEV_CONFIG; + + } /* serial_release */ +@@ -653,7 +675,7 @@ + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the serial drivers from + talking to the ports. +- ++ + ======================================================================*/ + + static int serial_event(event_t event, int priority, +@@ -661,9 +683,9 @@ + { + dev_link_t *link = args->client_data; + serial_info_t *info = link->priv; +- ++ + DEBUG(1, "serial_event(0x%06x)\n", event); +- ++ + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; +@@ -702,7 +724,7 @@ + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "serial_cs: Card Services release " + "does not match!\n"); +- return -1; ++ return -EINVAL; + } + register_pccard_driver(&dev_info, &serial_attach, &serial_detach); + return 0; +--- linux/drivers/input/Config.in~bluetooth-2.4.18-mh11 2001-09-13 00:34:06.000000000 +0200 ++++ linux/drivers/input/Config.in 2004-01-25 23:37:39.000000000 +0100 +@@ -14,5 +14,6 @@ + fi + 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 + + endmenu +--- linux/drivers/input/keybdev.c~bluetooth-2.4.18-mh11 2001-10-11 18:14:32.000000000 +0200 ++++ linux/drivers/input/keybdev.c 2004-01-25 23:37:39.000000000 +0100 +@@ -154,16 +154,18 @@ + + static struct input_handler keybdev_handler; + ++static unsigned int ledstate = 0xff; ++ + void keybdev_ledfunc(unsigned int led) + { + struct input_handle *handle; + +- for (handle = keybdev_handler.handle; handle; handle = handle->hnext) { ++ ledstate = led; + ++ for (handle = keybdev_handler.handle; handle; handle = handle->hnext) { + input_event(handle->dev, EV_LED, LED_SCROLLL, !!(led & 0x01)); + input_event(handle->dev, EV_LED, LED_NUML, !!(led & 0x02)); + input_event(handle->dev, EV_LED, LED_CAPSL, !!(led & 0x04)); +- + } + } + +@@ -202,6 +204,12 @@ + + // printk(KERN_INFO "keybdev.c: Adding keyboard: input%d\n", dev->number); + ++ if (ledstate != 0xff) { ++ input_event(dev, EV_LED, LED_SCROLLL, !!(ledstate & 0x01)); ++ input_event(dev, EV_LED, LED_NUML, !!(ledstate & 0x02)); ++ input_event(dev, EV_LED, LED_CAPSL, !!(ledstate & 0x04)); ++ } ++ + return handle; + } + +--- linux/drivers/input/Makefile~bluetooth-2.4.18-mh11 2000-12-29 23:07:22.000000000 +0100 ++++ linux/drivers/input/Makefile 2004-01-25 23:37:39.000000000 +0100 +@@ -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_UINPUT) += uinput.o + + # The global Rules.make. + +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/drivers/input/uinput.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,428 @@ ++/* ++ * User level driver support for input subsystem ++ * ++ * Heavily based on evdev.c by Vojtech Pavlik ++ * ++ * 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 ++ * ++ * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> ++ * ++ * Changes/Revisions: ++ * 0.1 20/06/2002 ++ * - first public version ++ */ ++ ++#include <linux/poll.h> ++#include <linux/slab.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/input.h> ++#include <linux/smp_lock.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/uinput.h> ++ ++static int uinput_dev_open(struct input_dev *dev) ++{ ++ return 0; ++} ++ ++static void uinput_dev_close(struct input_dev *dev) ++{ ++} ++ ++static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) ++{ ++ struct uinput_device *udev; ++ ++ udev = (struct uinput_device *)dev->private; ++ ++ udev->buff[udev->head].type = type; ++ udev->buff[udev->head].code = code; ++ udev->buff[udev->head].value = value; ++ do_gettimeofday(&udev->buff[udev->head].time); ++ udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE; ++ ++ wake_up_interruptible(&udev->waitq); ++ ++ return 0; ++} ++ ++static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect) ++{ ++ return 0; ++} ++ ++static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) ++{ ++ return 0; ++} ++ ++static int uinput_create_device(struct uinput_device *udev) ++{ ++ if (!udev->dev->name) { ++ printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME); ++ return -EINVAL; ++ } ++ ++ udev->dev->open = uinput_dev_open; ++ udev->dev->close = uinput_dev_close; ++ udev->dev->event = uinput_dev_event; ++ udev->dev->upload_effect = uinput_dev_upload_effect; ++ udev->dev->erase_effect = uinput_dev_erase_effect; ++ udev->dev->private = udev; ++ ++ init_waitqueue_head(&(udev->waitq)); ++ ++ input_register_device(udev->dev); ++ ++ set_bit(UIST_CREATED, &(udev->state)); ++ ++ return 0; ++} ++ ++static int uinput_destroy_device(struct uinput_device *udev) ++{ ++ if (!test_bit(UIST_CREATED, &(udev->state))) { ++ printk(KERN_WARNING "%s: create the device first\n", UINPUT_NAME); ++ return -EINVAL; ++ } ++ ++ input_unregister_device(udev->dev); ++ ++ clear_bit(UIST_CREATED, &(udev->state)); ++ ++ return 0; ++} ++ ++static int uinput_open(struct inode *inode, struct file *file) ++{ ++ struct uinput_device *newdev; ++ struct input_dev *newinput; ++ ++ newdev = kmalloc(sizeof(struct uinput_device), GFP_KERNEL); ++ if (!newdev) ++ goto error; ++ memset(newdev, 0, sizeof(struct uinput_device)); ++ ++ newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL); ++ if (!newinput) ++ goto cleanup; ++ memset(newinput, 0, sizeof(struct input_dev)); ++ ++ newdev->dev = newinput; ++ ++ file->private_data = newdev; ++ ++ return 0; ++cleanup: ++ kfree(newdev); ++error: ++ return -ENOMEM; ++} ++ ++static int uinput_validate_absbits(struct input_dev *dev) ++{ ++ unsigned int cnt; ++ int retval = 0; ++ ++ for (cnt = 0; cnt < ABS_MAX; cnt++) { ++ if (!test_bit(cnt, dev->absbit)) ++ continue; ++ ++ if (/*!dev->absmin[cnt] || !dev->absmax[cnt] || */ ++ (dev->absmax[cnt] <= dev->absmin[cnt])) { ++ printk(KERN_DEBUG ++ "%s: invalid abs[%02x] min:%d max:%d\n", ++ UINPUT_NAME, cnt, ++ dev->absmin[cnt], dev->absmax[cnt]); ++ retval = -EINVAL; ++ break; ++ } ++ ++ if ((dev->absflat[cnt] < dev->absmin[cnt]) || ++ (dev->absflat[cnt] > dev->absmax[cnt])) { ++ printk(KERN_DEBUG ++ "%s: absflat[%02x] out of range: %d " ++ "(min:%d/max:%d)\n", ++ UINPUT_NAME, cnt, dev->absflat[cnt], ++ dev->absmin[cnt], dev->absmax[cnt]); ++ retval = -EINVAL; ++ break; ++ } ++ } ++ return retval; ++} ++ ++static int uinput_alloc_device(struct file *file, const char *buffer, size_t count) ++{ ++ struct uinput_user_dev *user_dev; ++ struct input_dev *dev; ++ struct uinput_device *udev; ++ int size, ++ retval; ++ ++ retval = count; ++ ++ udev = (struct uinput_device *)file->private_data; ++ dev = udev->dev; ++ ++ user_dev = kmalloc(sizeof(*user_dev), GFP_KERNEL); ++ if (!user_dev) { ++ retval = -ENOMEM; ++ goto exit; ++ } ++ ++ if (copy_from_user(user_dev, buffer, sizeof(struct uinput_user_dev))) { ++ retval = -EFAULT; ++ goto exit; ++ } ++ ++ if (NULL != dev->name) ++ kfree(dev->name); ++ ++ size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; ++ dev->name = kmalloc(size, GFP_KERNEL); ++ if (!dev->name) { ++ retval = -ENOMEM; ++ goto exit; ++ } ++ ++ strncpy(dev->name, user_dev->name, size); ++ dev->idbus = user_dev->idbus; ++ dev->idvendor = user_dev->idvendor; ++ dev->idproduct = user_dev->idproduct; ++ dev->idversion = user_dev->idversion; ++ dev->ff_effects_max = user_dev->ff_effects_max; ++ ++ size = sizeof(int) * (ABS_MAX + 1); ++ memcpy(dev->absmax, user_dev->absmax, size); ++ memcpy(dev->absmin, user_dev->absmin, size); ++ memcpy(dev->absfuzz, user_dev->absfuzz, size); ++ memcpy(dev->absflat, user_dev->absflat, size); ++ ++ /* check if absmin/absmax/absfuzz/absflat are filled as ++ * told in Documentation/input/input-programming.txt */ ++ if (test_bit(EV_ABS, dev->evbit)) { ++ retval = uinput_validate_absbits(dev); ++ if (retval < 0) ++ kfree(dev->name); ++ } ++ ++exit: ++ kfree(user_dev); ++ return retval; ++} ++ ++static ssize_t uinput_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) ++{ ++ struct uinput_device *udev = file->private_data; ++ ++ if (test_bit(UIST_CREATED, &(udev->state))) { ++ struct input_event ev; ++ ++ if (copy_from_user(&ev, buffer, sizeof(struct input_event))) ++ return -EFAULT; ++ input_event(udev->dev, ev.type, ev.code, ev.value); ++ } ++ else ++ count = uinput_alloc_device(file, buffer, count); ++ ++ return count; ++} ++ ++static ssize_t uinput_read(struct file *file, char *buffer, size_t count, loff_t *ppos) ++{ ++ struct uinput_device *udev = file->private_data; ++ int retval = 0; ++ ++ if (!test_bit(UIST_CREATED, &(udev->state))) ++ return -ENODEV; ++ ++ if ((udev->head == udev->tail) && (file->f_flags & O_NONBLOCK)) ++ return -EAGAIN; ++ ++ retval = wait_event_interruptible(udev->waitq, ++ (udev->head != udev->tail) || ++ !test_bit(UIST_CREATED, &(udev->state))); ++ ++ if (retval) ++ return retval; ++ ++ if (!test_bit(UIST_CREATED, &(udev->state))) ++ return -ENODEV; ++ ++ while ((udev->head != udev->tail) && ++ (retval + sizeof(struct input_event) <= count)) { ++ if (copy_to_user(buffer + retval, &(udev->buff[udev->tail]), ++ sizeof(struct input_event))) return -EFAULT; ++ udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE; ++ retval += sizeof(struct input_event); ++ } ++ ++ return retval; ++} ++ ++static unsigned int uinput_poll(struct file *file, poll_table *wait) ++{ ++ struct uinput_device *udev = file->private_data; ++ ++ poll_wait(file, &udev->waitq, wait); ++ ++ if (udev->head != udev->tail) ++ return POLLIN | POLLRDNORM; ++ ++ return 0; ++} ++ ++static int uinput_burn_device(struct uinput_device *udev) ++{ ++ if (test_bit(UIST_CREATED, &(udev->state))) ++ uinput_destroy_device(udev); ++ ++ kfree(udev->dev); ++ kfree(udev); ++ ++ return 0; ++} ++ ++static int uinput_close(struct inode *inode, struct file *file) ++{ ++ return uinput_burn_device((struct uinput_device *)file->private_data); ++} ++ ++static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ int retval = 0; ++ struct uinput_device *udev; ++ ++ udev = (struct uinput_device *)file->private_data; ++ ++ /* device attributes can not be changed after the device is created */ ++ if (cmd >= UI_SET_EVBIT && test_bit(UIST_CREATED, &(udev->state))) ++ return -EINVAL; ++ ++ switch (cmd) { ++ case UI_DEV_CREATE: ++ retval = uinput_create_device(udev); ++ break; ++ ++ case UI_DEV_DESTROY: ++ retval = uinput_destroy_device(udev); ++ break; ++ ++ case UI_SET_EVBIT: ++ if (arg > EV_MAX) { ++ retval = -EINVAL; ++ break; ++ } ++ set_bit(arg, udev->dev->evbit); ++ break; ++ ++ case UI_SET_KEYBIT: ++ if (arg > KEY_MAX) { ++ retval = -EINVAL; ++ break; ++ } ++ set_bit(arg, udev->dev->keybit); ++ break; ++ ++ case UI_SET_RELBIT: ++ if (arg > REL_MAX) { ++ retval = -EINVAL; ++ break; ++ } ++ set_bit(arg, udev->dev->relbit); ++ break; ++ ++ case UI_SET_ABSBIT: ++ if (arg > ABS_MAX) { ++ retval = -EINVAL; ++ break; ++ } ++ set_bit(arg, udev->dev->absbit); ++ break; ++ ++ case UI_SET_MSCBIT: ++ if (arg > MSC_MAX) { ++ retval = -EINVAL; ++ break; ++ } ++ set_bit(arg, udev->dev->mscbit); ++ break; ++ ++ case UI_SET_LEDBIT: ++ if (arg > LED_MAX) { ++ retval = -EINVAL; ++ break; ++ } ++ set_bit(arg, udev->dev->ledbit); ++ break; ++ ++ case UI_SET_SNDBIT: ++ if (arg > SND_MAX) { ++ retval = -EINVAL; ++ break; ++ } ++ set_bit(arg, udev->dev->sndbit); ++ break; ++ ++ case UI_SET_FFBIT: ++ if (arg > FF_MAX) { ++ retval = -EINVAL; ++ break; ++ } ++ set_bit(arg, udev->dev->ffbit); ++ break; ++ ++ default: ++ retval = -EFAULT; ++ } ++ return retval; ++} ++ ++struct file_operations uinput_fops = { ++ owner: THIS_MODULE, ++ open: uinput_open, ++ release: uinput_close, ++ read: uinput_read, ++ write: uinput_write, ++ poll: uinput_poll, ++ ioctl: uinput_ioctl, ++}; ++ ++static struct miscdevice uinput_misc = { ++ fops: &uinput_fops, ++ minor: UINPUT_MINOR, ++ name: UINPUT_NAME, ++}; ++ ++static int __init uinput_init(void) ++{ ++ return misc_register(&uinput_misc); ++} ++ ++static void __exit uinput_exit(void) ++{ ++ misc_deregister(&uinput_misc); ++} ++ ++MODULE_AUTHOR("Aristeu Sergio Rozanski Filho"); ++MODULE_DESCRIPTION("User level driver support for input subsystem"); ++MODULE_LICENSE("GPL"); ++ ++module_init(uinput_init); ++module_exit(uinput_exit); ++ +--- linux/drivers/isdn/avmb1/capidrv.c~bluetooth-2.4.18-mh11 2001-12-21 18:41:54.000000000 +0100 ++++ linux/drivers/isdn/avmb1/capidrv.c 2004-01-25 23:37:39.000000000 +0100 +@@ -514,13 +514,25 @@ + + static void send_message(capidrv_contr * card, _cmsg * cmsg) + { +- struct sk_buff *skb; +- size_t len; ++ struct sk_buff *skb; ++ size_t len; ++ u16 err; ++ + capi_cmsg2message(cmsg, cmsg->buf); + len = CAPIMSG_LEN(cmsg->buf); + skb = alloc_skb(len, GFP_ATOMIC); ++ if(!skb) { ++ printk(KERN_ERR "no skb len(%d) memory\n", len); ++ return; ++ } + memcpy(skb_put(skb, len), cmsg->buf, len); +- (*capifuncs->capi_put_message) (global.appid, skb); ++ err = (*capifuncs->capi_put_message) (global.appid, skb); ++ if (err) { ++ printk(KERN_WARNING "%s: capi_put_message error: %04x\n", ++ __FUNCTION__, err); ++ kfree_skb(skb); ++ return; ++ } + global.nsentctlpkt++; + } + +@@ -2179,10 +2191,10 @@ + free_ncci(card, card->bchans[card->nbchan-1].nccip); + if (card->bchans[card->nbchan-1].plcip) + free_plci(card, card->bchans[card->nbchan-1].plcip); +- if (card->plci_list) +- printk(KERN_ERR "capidrv: bug in free_plci()\n"); + card->nbchan--; + } ++ if (card->plci_list) ++ printk(KERN_ERR "capidrv: bug in free_plci()\n"); + kfree(card->bchans); + card->bchans = 0; + +--- linux/drivers/isdn/avmb1/kcapi.c~bluetooth-2.4.18-mh11 2001-12-21 18:41:54.000000000 +0100 ++++ linux/drivers/isdn/avmb1/kcapi.c 2004-01-25 23:37:39.000000000 +0100 +@@ -545,7 +545,13 @@ + static void notify_up(__u32 contr) + { + struct capi_interface_user *p; ++ __u16 appl; + ++ for (appl = 1; appl <= CAPI_MAXAPPL; appl++) { ++ if (!VALID_APPLID(appl)) continue; ++ if (APPL(appl)->releasing) continue; ++ CARD(contr)->driver->register_appl(CARD(contr), appl, &APPL(appl)->rparam); ++ } + printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr); + spin_lock(&capi_users_lock); + for (p = capi_users; p; p = p->next) { +@@ -705,12 +711,16 @@ + nextpp = &(*pp)->next; + } + } +- APPL(appl)->releasing--; +- if (APPL(appl)->releasing <= 0) { +- APPL(appl)->signal = 0; +- APPL_MARK_FREE(appl); +- printk(KERN_INFO "kcapi: appl %d down\n", appl); +- } ++ if (APPL(appl)->releasing) { /* only release if the application was marked for release */ ++ printk(KERN_DEBUG "kcapi: appl %d releasing(%d)\n", appl, APPL(appl)->releasing); ++ APPL(appl)->releasing--; ++ if (APPL(appl)->releasing <= 0) { ++ APPL(appl)->signal = 0; ++ APPL_MARK_FREE(appl); ++ printk(KERN_INFO "kcapi: appl %d down\n", appl); ++ } ++ } else ++ printk(KERN_WARNING "kcapi: appl %d card%d released without request\n", appl, card->cnr); + } + /* + * ncci management +@@ -863,16 +873,7 @@ + + static void controllercb_ready(struct capi_ctr * card) + { +- __u16 appl; +- + card->cardstate = CARD_RUNNING; +- +- for (appl = 1; appl <= CAPI_MAXAPPL; appl++) { +- if (!VALID_APPLID(appl)) continue; +- if (APPL(appl)->releasing) continue; +- card->driver->register_appl(card, appl, &APPL(appl)->rparam); +- } +- + printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n", + CARDNR(card), card->name); + +--- linux/drivers/usb/Config.in~bluetooth-2.4.18-mh11 2004-01-25 23:28:22.000000000 +0100 ++++ linux/drivers/usb/Config.in 2004-01-25 23:37:39.000000000 +0100 +@@ -39,7 +39,13 @@ + + comment 'USB Device Class drivers' + dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND +-dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL ++if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ if [ "$CONFIG_BLUEZ" = "n" ]; then ++ dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB ++ else ++ comment ' USB Bluetooth can only be used with disabled Bluetooth subsystem' ++ fi ++fi + if [ "$CONFIG_SCSI" = "n" ]; then + comment ' SCSI support is needed for USB Storage' + fi +--- linux/drivers/usb/hid-core.c~bluetooth-2.4.18-mh11 2001-12-21 18:41:55.000000000 +0100 ++++ linux/drivers/usb/hid-core.c 2004-01-25 23:37:39.000000000 +0100 +@@ -217,6 +217,8 @@ + + offset = report->size; + report->size += parser->global.report_size * parser->global.report_count; ++ if (usages < parser->global.report_count) ++ usages = parser->global.report_count; + + if (usages == 0) + return 0; /* ignore padding fields */ +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/include/linux/firmware.h 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,20 @@ ++#ifndef _LINUX_FIRMWARE_H ++#define _LINUX_FIRMWARE_H ++#include <linux/module.h> ++#include <linux/types.h> ++#define FIRMWARE_NAME_MAX 30 ++struct firmware { ++ size_t size; ++ u8 *data; ++}; ++int request_firmware (const struct firmware **fw, const char *name, ++ const char *device); ++int request_firmware_nowait ( ++ struct module *module, ++ const char *name, const char *device, void *context, ++ void (*cont)(const struct firmware *fw, void *context)); ++/* On 2.5 'device' is 'struct device *' */ ++ ++void release_firmware (const struct firmware *fw); ++void register_firmware (const char *name, const u8 *data, size_t size); ++#endif +--- linux/include/linux/input.h~bluetooth-2.4.18-mh11 2001-09-13 00:34:06.000000000 +0200 ++++ linux/include/linux/input.h 2004-01-25 23:37:39.000000000 +0100 +@@ -468,6 +468,8 @@ + #define BUS_PCI 0x01 + #define BUS_ISAPNP 0x02 + #define BUS_USB 0x03 ++#define BUS_HIL 0x04 ++#define BUS_BLUETOOTH 0x05 + + #define BUS_ISA 0x10 + #define BUS_I8042 0x11 +--- linux/include/linux/kernel.h~bluetooth-2.4.18-mh11 2002-02-25 20:38:13.000000000 +0100 ++++ linux/include/linux/kernel.h 2004-01-25 23:37:39.000000000 +0100 +@@ -11,6 +11,7 @@ + #include <linux/linkage.h> + #include <linux/stddef.h> + #include <linux/types.h> ++#include <linux/compiler.h> + + /* Optimization barrier */ + /* The "volatile" is due to gcc bugs */ +@@ -181,4 +182,6 @@ + char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */ + }; + +-#endif ++#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) ++ ++#endif /* _LINUX_KERNEL_H */ +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/include/linux/uinput.h 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,79 @@ ++/* ++ * User level driver support for input subsystem ++ * ++ * Heavily based on evdev.c by Vojtech Pavlik ++ * ++ * 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 ++ * ++ * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org> ++ * ++ * Changes/Revisions: ++ * 0.1 20/06/2002 ++ * - first public version ++ */ ++ ++#ifndef __UINPUT_H_ ++#define __UINPUT_H_ ++ ++#ifdef __KERNEL__ ++#define UINPUT_MINOR 223 ++#define UINPUT_NAME "uinput" ++#define UINPUT_BUFFER_SIZE 16 ++ ++/* state flags => bit index for {set|clear|test}_bit ops */ ++#define UIST_CREATED 0 ++ ++struct uinput_device { ++ struct input_dev *dev; ++ unsigned long state; ++ wait_queue_head_t waitq; ++ unsigned char ready, ++ head, ++ tail; ++ struct input_event buff[UINPUT_BUFFER_SIZE]; ++}; ++#endif /* __KERNEL__ */ ++ ++/* ioctl */ ++#define UINPUT_IOCTL_BASE 'U' ++#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1) ++#define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2) ++#define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int) ++#define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int) ++#define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int) ++#define UI_SET_ABSBIT _IOW(UINPUT_IOCTL_BASE, 103, int) ++#define UI_SET_MSCBIT _IOW(UINPUT_IOCTL_BASE, 104, int) ++#define UI_SET_LEDBIT _IOW(UINPUT_IOCTL_BASE, 105, int) ++#define UI_SET_SNDBIT _IOW(UINPUT_IOCTL_BASE, 106, int) ++#define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int) ++ ++#ifndef NBITS ++#define NBITS(x) ((((x)-1)/(sizeof(long)*8))+1) ++#endif /* NBITS */ ++ ++#define UINPUT_MAX_NAME_SIZE 80 ++struct uinput_user_dev { ++ char name[UINPUT_MAX_NAME_SIZE]; ++ unsigned short idbus; ++ unsigned short idvendor; ++ unsigned short idproduct; ++ unsigned short idversion; ++ int ff_effects_max; ++ int absmax[ABS_MAX + 1]; ++ int absmin[ABS_MAX + 1]; ++ int absfuzz[ABS_MAX + 1]; ++ int absflat[ABS_MAX + 1]; ++}; ++#endif /* __UINPUT_H_ */ +--- linux/include/net/bluetooth/bluetooth.h~bluetooth-2.4.18-mh11 2001-09-07 18:28:38.000000000 +0200 ++++ linux/include/net/bluetooth/bluetooth.h 2004-01-25 23:37:39.000000000 +0100 +@@ -23,7 +23,7 @@ + */ + + /* +- * $Id$ ++ * $Id$ + */ + + #ifndef __BLUETOOTH_H +@@ -31,17 +31,63 @@ + + #include <asm/types.h> + #include <asm/byteorder.h> ++#include <linux/poll.h> ++#include <net/sock.h> + + #ifndef AF_BLUETOOTH + #define AF_BLUETOOTH 31 + #define PF_BLUETOOTH AF_BLUETOOTH + #endif + ++/* Reserv for core and drivers use */ ++#define BLUEZ_SKB_RESERVE 8 ++ ++#ifndef MIN ++#define MIN(a,b) ((a) < (b) ? (a) : (b)) ++#endif ++ + #define BTPROTO_L2CAP 0 + #define BTPROTO_HCI 1 ++#define BTPROTO_SCO 2 ++#define BTPROTO_RFCOMM 3 ++#define BTPROTO_BNEP 4 ++#define BTPROTO_CMTP 5 + + #define SOL_HCI 0 + #define SOL_L2CAP 6 ++#define SOL_SCO 17 ++#define SOL_RFCOMM 18 ++ ++/* Debugging */ ++#ifdef CONFIG_BLUEZ_DEBUG ++ ++#define HCI_CORE_DEBUG 1 ++#define HCI_SOCK_DEBUG 1 ++#define HCI_UART_DEBUG 1 ++#define HCI_USB_DEBUG 1 ++//#define HCI_DATA_DUMP 1 ++ ++#define L2CAP_DEBUG 1 ++#define SCO_DEBUG 1 ++#define AF_BLUETOOTH_DEBUG 1 ++ ++#endif /* CONFIG_BLUEZ_DEBUG */ ++ ++extern void bluez_dump(char *pref, __u8 *buf, int count); ++ ++#if __GNUC__ <= 2 && __GNUC_MINOR__ < 95 ++#define __func__ __FUNCTION__ ++#endif ++ ++#define BT_INFO(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg) ++#define BT_DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n" , __func__ , ## arg) ++#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg) ++ ++#ifdef HCI_DATA_DUMP ++#define BT_DMP(buf, len) bluez_dump(__func__, buf, len) ++#else ++#define BT_DMP(D...) ++#endif + + /* Connection and socket states */ + enum { +@@ -50,6 +96,7 @@ + BT_BOUND, + BT_LISTEN, + BT_CONNECT, ++ BT_CONNECT2, + BT_CONFIG, + BT_DISCONN, + BT_CLOSED +@@ -66,7 +113,8 @@ + __u8 b[6]; + } __attribute__((packed)) bdaddr_t; + +-#define BDADDR_ANY ((bdaddr_t *)"\000\000\000\000\000") ++#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}}) ++#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}}) + + /* Copy, swap, convert BD Address */ + static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2) +@@ -82,6 +130,91 @@ + char *batostr(bdaddr_t *ba); + bdaddr_t *strtoba(char *str); + ++/* Common socket structures and functions */ ++ ++#define bluez_pi(sk) ((struct bluez_pinfo *) &sk->protinfo) ++#define bluez_sk(pi) ((struct sock *) \ ++ ((void *)pi - (unsigned long)(&((struct sock *)0)->protinfo))) ++ ++struct bluez_pinfo { ++ bdaddr_t src; ++ bdaddr_t dst; ++ ++ struct list_head accept_q; ++ struct sock *parent; ++}; ++ ++struct bluez_sock_list { ++ struct sock *head; ++ rwlock_t lock; ++}; ++ ++int bluez_sock_register(int proto, struct net_proto_family *ops); ++int bluez_sock_unregister(int proto); ++void bluez_sock_init(struct socket *sock, struct sock *sk); ++void bluez_sock_link(struct bluez_sock_list *l, struct sock *s); ++void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s); ++int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm); ++uint bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait); ++int bluez_sock_wait_state(struct sock *sk, int state, unsigned long timeo); ++ ++void bluez_accept_enqueue(struct sock *parent, struct sock *sk); ++struct sock * bluez_accept_dequeue(struct sock *parent, struct socket *newsock); ++ ++/* Skb helpers */ ++struct bluez_skb_cb { ++ int incomming; ++}; ++#define bluez_cb(skb) ((struct bluez_skb_cb *)(skb->cb)) ++ ++static inline struct sk_buff *bluez_skb_alloc(unsigned int len, int how) ++{ ++ struct sk_buff *skb; ++ ++ if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) { ++ skb_reserve(skb, BLUEZ_SKB_RESERVE); ++ bluez_cb(skb)->incomming = 0; ++ } ++ return skb; ++} ++ ++static inline struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len, ++ int nb, int *err) ++{ ++ struct sk_buff *skb; ++ ++ if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) { ++ skb_reserve(skb, BLUEZ_SKB_RESERVE); ++ bluez_cb(skb)->incomming = 0; ++ } ++ ++ return skb; ++} ++ ++static inline int skb_frags_no(struct sk_buff *skb) ++{ ++ register struct sk_buff *frag = skb_shinfo(skb)->frag_list; ++ register int n = 1; ++ ++ for (; frag; frag=frag->next, n++); ++ return n; ++} ++ ++int hci_core_init(void); ++int hci_core_cleanup(void); ++int hci_sock_init(void); ++int hci_sock_cleanup(void); ++ + int bterr(__u16 code); + ++#ifndef MODULE_LICENSE ++#define MODULE_LICENSE(x) ++#endif ++ ++#ifndef list_for_each_safe ++#define list_for_each_safe(pos, n, head) \ ++ for (pos = (head)->next, n = pos->next; pos != (head); \ ++ pos = n, n = pos->next) ++#endif ++ + #endif /* __BLUETOOTH_H */ +--- linux/include/net/bluetooth/bluez.h~bluetooth-2.4.18-mh11 ++++ linux/include/net/bluetooth/bluez.h +-/* +- BlueZ - Bluetooth protocol stack for Linux +- Copyright (C) 2000-2001 Qualcomm Incorporated +- +- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; +- +- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY +- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES +- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- +- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, +- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS +- SOFTWARE IS DISCLAIMED. +-*/ +- +-/* +- * $Id$ +- */ +- +-#ifndef __IF_BLUEZ_H +-#define __IF_BLUEZ_H +- +-#include <net/sock.h> +- +-#define BLUEZ_MAX_PROTO 2 +- +-/* Reserv for core and drivers use */ +-#define BLUEZ_SKB_RESERVE 8 +- +-#ifndef MIN +-#define MIN(a,b) ((a) < (b) ? (a) : (b)) +-#endif +- +-/* Debugging */ +-#ifdef BLUEZ_DEBUG +- +-#define HCI_CORE_DEBUG 1 +-#define HCI_SOCK_DEBUG 1 +-#define HCI_UART_DEBUG 1 +-#define HCI_USB_DEBUG 1 +-//#define HCI_DATA_DUMP 1 +- +-#define L2CAP_DEBUG 1 +- +-#endif /* BLUEZ_DEBUG */ +- +-extern void bluez_dump(char *pref, __u8 *buf, int count); +- +-#define INF(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg) +-#define DBG(fmt, arg...) printk(KERN_INFO __FUNCTION__ ": " fmt "\n" , ## arg) +-#define ERR(fmt, arg...) printk(KERN_ERR __FUNCTION__ ": " fmt "\n" , ## arg) +- +-#ifdef HCI_DATA_DUMP +-#define DMP(buf, len) bluez_dump(__FUNCTION__, buf, len) +-#else +-#define DMP(D...) +-#endif +- +-/* ----- Sockets ------ */ +-struct bluez_sock_list { +- struct sock *head; +- rwlock_t lock; +-}; +- +-extern int bluez_sock_register(int proto, struct net_proto_family *ops); +-extern int bluez_sock_unregister(int proto); +- +-extern void bluez_sock_link(struct bluez_sock_list *l, struct sock *s); +-extern void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s); +- +-/* ----- SKB helpers ----- */ +-struct bluez_skb_cb { +- int incomming; +-}; +-#define bluez_cb(skb) ((struct bluez_skb_cb *)(skb->cb)) +- +-static inline struct sk_buff *bluez_skb_alloc(unsigned int len, int how) +-{ +- struct sk_buff *skb; +- +- if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) { +- skb_reserve(skb, BLUEZ_SKB_RESERVE); +- bluez_cb(skb)->incomming = 0; +- } +- return skb; +-} +- +-static inline struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len, +- int nb, int *err) +-{ +- struct sk_buff *skb; +- +- if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) { +- skb_reserve(skb, BLUEZ_SKB_RESERVE); +- bluez_cb(skb)->incomming = 0; +- } +- +- return skb; +-} +- +-static inline int skb_frags_no(struct sk_buff *skb) +-{ +- register struct sk_buff *frag = skb_shinfo(skb)->frag_list; +- register int n = 1; +- +- for (; frag; frag=frag->next, n++); +- return n; +-} +- +-extern int hci_core_init(void); +-extern int hci_core_cleanup(void); +-extern int hci_sock_init(void); +-extern int hci_sock_cleanup(void); +- +-#endif /* __IF_BLUEZ_H */ +--- linux/include/net/bluetooth/hci_core.h~bluetooth-2.4.18-mh11 2001-09-07 18:28:38.000000000 +0200 ++++ linux/include/net/bluetooth/hci_core.h 2004-01-25 23:37:39.000000000 +0100 +@@ -23,7 +23,7 @@ + */ + + /* +- * $Id$ ++ * $Id$ + */ + + #ifndef __HCI_CORE_H +@@ -32,14 +32,12 @@ + #include <net/bluetooth/hci.h> + + /* HCI upper protocols */ +-#define HCI_MAX_PROTO 1 + #define HCI_PROTO_L2CAP 0 ++#define HCI_PROTO_SCO 1 + + #define HCI_INIT_TIMEOUT (HZ * 10) + +-/* ----- Inquiry cache ----- */ +-#define INQUIRY_CACHE_AGE_MAX (HZ*5) // 5 seconds +-#define INQUIRY_ENTRY_AGE_MAX (HZ*60) // 60 seconds ++/* HCI Core structures */ + + struct inquiry_entry { + struct inquiry_entry *next; +@@ -53,111 +51,186 @@ + struct inquiry_entry *list; + }; + +-static inline void inquiry_cache_init(struct inquiry_cache *cache) +-{ +- spin_lock_init(&cache->lock); +- cache->list = NULL; +-} ++struct conn_hash { ++ struct list_head list; ++ spinlock_t lock; ++ unsigned int num; ++}; + +-static inline void inquiry_cache_lock(struct inquiry_cache *cache) +-{ +- spin_lock(&cache->lock); +-} ++struct hci_dev { ++ struct list_head list; ++ spinlock_t lock; ++ atomic_t refcnt; + +-static inline void inquiry_cache_unlock(struct inquiry_cache *cache) +-{ +- spin_unlock(&cache->lock); +-} ++ char name[8]; ++ unsigned long flags; ++ __u16 id; ++ __u8 type; ++ bdaddr_t bdaddr; ++ __u8 features[8]; + +-static inline void inquiry_cache_lock_bh(struct inquiry_cache *cache) +-{ +- spin_lock_bh(&cache->lock); +-} ++ __u16 pkt_type; ++ __u16 link_policy; ++ __u16 link_mode; ++ ++ atomic_t cmd_cnt; ++ unsigned int acl_cnt; ++ unsigned int sco_cnt; + +-static inline void inquiry_cache_unlock_bh(struct inquiry_cache *cache) +-{ +- spin_unlock_bh(&cache->lock); +-} ++ unsigned int acl_mtu; ++ unsigned int sco_mtu; ++ unsigned int acl_pkts; ++ unsigned int sco_pkts; + +-static inline long inquiry_cache_age(struct inquiry_cache *cache) +-{ +- return jiffies - cache->timestamp; +-} ++ unsigned long cmd_last_tx; ++ unsigned long acl_last_tx; ++ unsigned long sco_last_tx; ++ ++ struct tasklet_struct cmd_task; ++ struct tasklet_struct rx_task; ++ struct tasklet_struct tx_task; + +-static inline long inquiry_entry_age(struct inquiry_entry *e) +-{ +- return jiffies - e->timestamp; +-} +-extern void inquiry_cache_flush(struct inquiry_cache *cache); ++ struct sk_buff_head rx_q; ++ struct sk_buff_head raw_q; ++ struct sk_buff_head cmd_q; + +-struct hci_dev; ++ struct sk_buff *sent_cmd; ++ ++ struct semaphore req_lock; ++ wait_queue_head_t req_wait_q; ++ __u32 req_status; ++ __u32 req_result; ++ ++ struct inquiry_cache inq_cache; ++ struct conn_hash conn_hash; ++ ++ struct hci_dev_stats stat; ++ ++ void *driver_data; ++ void *core_data; ++ ++ atomic_t promisc; ++ ++ int (*open)(struct hci_dev *hdev); ++ int (*close)(struct hci_dev *hdev); ++ int (*flush)(struct hci_dev *hdev); ++ int (*send)(struct sk_buff *skb); ++ void (*destruct)(struct hci_dev *hdev); ++ int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg); ++}; + +-/* ----- HCI Connections ----- */ + struct hci_conn { + struct list_head list; ++ ++ atomic_t refcnt; ++ spinlock_t lock; ++ + bdaddr_t dst; + __u16 handle; ++ __u16 state; + __u8 type; +- unsigned int sent; ++ __u8 out; ++ __u32 link_mode; ++ unsigned long pend; ++ ++ unsigned int sent; ++ ++ struct sk_buff_head data_q; + ++ struct timer_list timer; ++ + struct hci_dev *hdev; + void *l2cap_data; ++ void *sco_data; + void *priv; + +- struct sk_buff_head data_q; ++ struct hci_conn *link; + }; + +-struct conn_hash { +- struct list_head list; +- spinlock_t lock; +- unsigned int num; +-}; ++extern struct hci_proto *hci_proto[]; ++extern struct list_head hdev_list; ++extern rwlock_t hdev_list_lock; + +-static inline void conn_hash_init(struct conn_hash *h) ++/* ----- Inquiry cache ----- */ ++#define INQUIRY_CACHE_AGE_MAX (HZ*30) // 30 seconds ++#define INQUIRY_ENTRY_AGE_MAX (HZ*60) // 60 seconds ++ ++#define inquiry_cache_lock(c) spin_lock(&c->lock) ++#define inquiry_cache_unlock(c) spin_unlock(&c->lock) ++#define inquiry_cache_lock_bh(c) spin_lock_bh(&c->lock) ++#define inquiry_cache_unlock_bh(c) spin_unlock_bh(&c->lock) ++ ++static inline void inquiry_cache_init(struct hci_dev *hdev) + { +- INIT_LIST_HEAD(&h->list); +- spin_lock_init(&h->lock); +- h->num = 0; ++ struct inquiry_cache *c = &hdev->inq_cache; ++ spin_lock_init(&c->lock); ++ c->list = NULL; + } + +-static inline void conn_hash_lock(struct conn_hash *h) ++static inline int inquiry_cache_empty(struct hci_dev *hdev) + { +- spin_lock(&h->lock); ++ struct inquiry_cache *c = &hdev->inq_cache; ++ return (c->list == NULL); + } + +-static inline void conn_hash_unlock(struct conn_hash *h) ++static inline long inquiry_cache_age(struct hci_dev *hdev) + { +- spin_unlock(&h->lock); ++ struct inquiry_cache *c = &hdev->inq_cache; ++ return jiffies - c->timestamp; + } + +-static inline void __conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c) ++static inline long inquiry_entry_age(struct inquiry_entry *e) + { +- list_add(&c->list, &h->list); +- h->num++; ++ return jiffies - e->timestamp; + } + +-static inline void conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c) ++struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr); ++void inquiry_cache_update(struct hci_dev *hdev, inquiry_info *info); ++void inquiry_cache_flush(struct hci_dev *hdev); ++int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf); ++ ++/* ----- HCI Connections ----- */ ++enum { ++ HCI_CONN_AUTH_PEND, ++ HCI_CONN_ENCRYPT_PEND ++}; ++ ++#define hci_conn_lock(c) spin_lock(&c->lock) ++#define hci_conn_unlock(c) spin_unlock(&c->lock) ++#define hci_conn_lock_bh(c) spin_lock_bh(&c->lock) ++#define hci_conn_unlock_bh(c) spin_unlock_bh(&c->lock) ++ ++#define conn_hash_lock(d) spin_lock(&d->conn_hash->lock) ++#define conn_hash_unlock(d) spin_unlock(&d->conn_hash->lock) ++#define conn_hash_lock_bh(d) spin_lock_bh(&d->conn_hash->lock) ++#define conn_hash_unlock_bh(d) spin_unlock_bh(&d->conn_hash->lock) ++ ++static inline void conn_hash_init(struct hci_dev *hdev) + { +- conn_hash_lock(h); +- __conn_hash_add(h, handle, c); +- conn_hash_unlock(h); ++ struct conn_hash *h = &hdev->conn_hash; ++ INIT_LIST_HEAD(&h->list); ++ spin_lock_init(&h->lock); ++ h->num = 0; + } + +-static inline void __conn_hash_del(struct conn_hash *h, struct hci_conn *c) ++static inline void conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) + { +- list_del(&c->list); +- h->num--; ++ struct conn_hash *h = &hdev->conn_hash; ++ list_add(&c->list, &h->list); ++ h->num++; + } + +-static inline void conn_hash_del(struct conn_hash *h, struct hci_conn *c) ++static inline void conn_hash_del(struct hci_dev *hdev, struct hci_conn *c) + { +- conn_hash_lock(h); +- __conn_hash_del(h, c); +- conn_hash_unlock(h); ++ struct conn_hash *h = &hdev->conn_hash; ++ list_del(&c->list); ++ h->num--; + } + +-static inline struct hci_conn *__conn_hash_lookup(struct conn_hash *h, __u16 handle) ++static inline struct hci_conn *conn_hash_lookup_handle(struct hci_dev *hdev, ++ __u16 handle) + { ++ register struct conn_hash *h = &hdev->conn_hash; + register struct list_head *p; + register struct hci_conn *c; + +@@ -169,101 +242,97 @@ + return NULL; + } + +-static inline struct hci_conn *conn_hash_lookup(struct conn_hash *h, __u16 handle) ++static inline struct hci_conn *conn_hash_lookup_ba(struct hci_dev *hdev, ++ __u8 type, bdaddr_t *ba) + { +- struct hci_conn *conn; ++ register struct conn_hash *h = &hdev->conn_hash; ++ register struct list_head *p; ++ register struct hci_conn *c; + +- conn_hash_lock(h); +- conn = __conn_hash_lookup(h, handle); +- conn_hash_unlock(h); +- return conn; ++ list_for_each(p, &h->list) { ++ c = list_entry(p, struct hci_conn, list); ++ if (c->type == type && !bacmp(&c->dst, ba)) ++ return c; ++ } ++ return NULL; + } + +-/* ----- HCI Devices ----- */ +-struct hci_dev { +- atomic_t refcnt; +- +- char name[8]; +- __u32 flags; +- __u16 id; +- __u8 type; +- bdaddr_t bdaddr; +- __u8 features[8]; +- +- __u16 pkt_type; +- +- atomic_t cmd_cnt; +- unsigned int acl_cnt; +- unsigned int sco_cnt; +- +- unsigned int acl_mtu; +- unsigned int sco_mtu; +- unsigned int acl_max; +- unsigned int sco_max; +- +- void *driver_data; +- void *l2cap_data; +- void *priv; +- +- struct tasklet_struct cmd_task; +- struct tasklet_struct rx_task; +- struct tasklet_struct tx_task; +- +- struct sk_buff_head rx_q; +- struct sk_buff_head raw_q; +- struct sk_buff_head cmd_q; +- +- struct sk_buff *sent_cmd; +- +- struct semaphore req_lock; +- wait_queue_head_t req_wait_q; +- __u32 req_status; +- __u32 req_result; ++void hci_acl_connect(struct hci_conn *conn); ++void hci_acl_disconn(struct hci_conn *conn, __u8 reason); ++void hci_add_sco(struct hci_conn *conn, __u16 handle); + +- struct inquiry_cache inq_cache; ++struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst); ++int hci_conn_del(struct hci_conn *conn); ++void hci_conn_hash_flush(struct hci_dev *hdev); + +- struct conn_hash conn_hash; ++struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src); ++int hci_conn_auth(struct hci_conn *conn); ++int hci_conn_encrypt(struct hci_conn *conn); + +- struct hci_dev_stats stat; ++static inline void hci_conn_set_timer(struct hci_conn *conn, long timeout) ++{ ++ mod_timer(&conn->timer, jiffies + timeout); ++} + +- int (*open)(struct hci_dev *hdev); +- int (*close)(struct hci_dev *hdev); +- int (*flush)(struct hci_dev *hdev); +- int (*send)(struct sk_buff *skb); +-}; ++static inline void hci_conn_del_timer(struct hci_conn *conn) ++{ ++ del_timer(&conn->timer); ++} + +-static inline void hci_dev_hold(struct hci_dev *hdev) ++static inline void hci_conn_hold(struct hci_conn *conn) + { +- atomic_inc(&hdev->refcnt); ++ atomic_inc(&conn->refcnt); ++ hci_conn_del_timer(conn); + } + +-static inline void hci_dev_put(struct hci_dev *hdev) ++static inline void hci_conn_put(struct hci_conn *conn) + { +- atomic_dec(&hdev->refcnt); ++ if (atomic_dec_and_test(&conn->refcnt)) { ++ if (conn->type == ACL_LINK) { ++ unsigned long timeo = (conn->out) ? ++ HCI_DISCONN_TIMEOUT : HCI_DISCONN_TIMEOUT * 2; ++ hci_conn_set_timer(conn, timeo); ++ } else ++ hci_conn_set_timer(conn, HZ / 100); ++ } + } + +-extern struct hci_dev *hci_dev_get(int index); +-extern int hci_register_dev(struct hci_dev *hdev); +-extern int hci_unregister_dev(struct hci_dev *hdev); +-extern int hci_dev_open(__u16 dev); +-extern int hci_dev_close(__u16 dev); +-extern int hci_dev_reset(__u16 dev); +-extern int hci_dev_reset_stat(__u16 dev); +-extern int hci_dev_info(unsigned long arg); +-extern int hci_dev_list(unsigned long arg); +-extern int hci_dev_setscan(unsigned long arg); +-extern int hci_dev_setauth(unsigned long arg); +-extern int hci_dev_setptype(unsigned long arg); +-extern int hci_conn_list(unsigned long arg); +-extern int hci_inquiry(unsigned long arg); ++/* ----- HCI Devices ----- */ ++static inline void hci_dev_put(struct hci_dev *d) ++{ ++ if (atomic_dec_and_test(&d->refcnt)) ++ d->destruct(d); ++} ++#define hci_dev_hold(d) atomic_inc(&d->refcnt) + +-extern __u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode); +-extern __u32 hci_dev_getmode(struct hci_dev *hdev); ++#define hci_dev_lock(d) spin_lock(&d->lock) ++#define hci_dev_unlock(d) spin_unlock(&d->lock) ++#define hci_dev_lock_bh(d) spin_lock_bh(&d->lock) ++#define hci_dev_unlock_bh(d) spin_unlock_bh(&d->lock) + +-extern int hci_recv_frame(struct sk_buff *skb); ++struct hci_dev *hci_dev_get(int index); ++struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst); ++int hci_register_dev(struct hci_dev *hdev); ++int hci_unregister_dev(struct hci_dev *hdev); ++int hci_suspend_dev(struct hci_dev *hdev); ++int hci_resume_dev(struct hci_dev *hdev); ++int hci_dev_open(__u16 dev); ++int hci_dev_close(__u16 dev); ++int hci_dev_reset(__u16 dev); ++int hci_dev_reset_stat(__u16 dev); ++int hci_dev_cmd(unsigned int cmd, unsigned long arg); ++int hci_get_dev_list(unsigned long arg); ++int hci_get_dev_info(unsigned long arg); ++int hci_get_conn_list(unsigned long arg); ++int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg); ++int hci_inquiry(unsigned long arg); ++ ++int hci_recv_frame(struct sk_buff *skb); ++void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); + + /* ----- LMP capabilities ----- */ + #define lmp_rswitch_capable(dev) (dev->features[0] & LMP_RSWITCH) ++#define lmp_encrypt_capable(dev) (dev->features[0] & LMP_ENCRYPT) + + /* ----- HCI tasks ----- */ + static inline void hci_sched_cmd(struct hci_dev *hdev) +@@ -284,43 +353,130 @@ + /* ----- HCI protocols ----- */ + struct hci_proto { + char *name; +- __u32 id; +- __u32 flags; ++ unsigned int id; ++ unsigned long flags; + + void *priv; + +- int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr); +- int (*connect_cfm) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *conn); ++ int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type); ++ int (*connect_cfm) (struct hci_conn *conn, __u8 status); + int (*disconn_ind) (struct hci_conn *conn, __u8 reason); +- int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb , __u16 flags); ++ int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags); + int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb); ++ int (*auth_cfm) (struct hci_conn *conn, __u8 status); ++ int (*encrypt_cfm) (struct hci_conn *conn, __u8 status); + }; + +-extern int hci_register_proto(struct hci_proto *hproto); +-extern int hci_unregister_proto(struct hci_proto *hproto); +-extern int hci_register_notifier(struct notifier_block *nb); +-extern int hci_unregister_notifier(struct notifier_block *nb); +-extern int hci_connect(struct hci_dev * hdev, bdaddr_t * bdaddr); +-extern int hci_disconnect(struct hci_conn *conn, __u8 reason); +-extern int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void * param); +-extern int hci_send_raw(struct sk_buff *skb); +-extern int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags); +-extern int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); ++static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) ++{ ++ register struct hci_proto *hp; ++ int mask = 0; ++ ++ hp = hci_proto[HCI_PROTO_L2CAP]; ++ if (hp && hp->connect_ind) ++ mask |= hp->connect_ind(hdev, bdaddr, type); ++ ++ hp = hci_proto[HCI_PROTO_SCO]; ++ if (hp && hp->connect_ind) ++ mask |= hp->connect_ind(hdev, bdaddr, type); ++ ++ return mask; ++} ++ ++static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status) ++{ ++ register struct hci_proto *hp; ++ ++ hp = hci_proto[HCI_PROTO_L2CAP]; ++ if (hp && hp->connect_cfm) ++ hp->connect_cfm(conn, status); ++ ++ hp = hci_proto[HCI_PROTO_SCO]; ++ if (hp && hp->connect_cfm) ++ hp->connect_cfm(conn, status); ++} ++ ++static inline void hci_proto_disconn_ind(struct hci_conn *conn, __u8 reason) ++{ ++ register struct hci_proto *hp; ++ ++ hp = hci_proto[HCI_PROTO_L2CAP]; ++ if (hp && hp->disconn_ind) ++ hp->disconn_ind(conn, reason); ++ ++ hp = hci_proto[HCI_PROTO_SCO]; ++ if (hp && hp->disconn_ind) ++ hp->disconn_ind(conn, reason); ++} ++ ++static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status) ++{ ++ register struct hci_proto *hp; ++ ++ hp = hci_proto[HCI_PROTO_L2CAP]; ++ if (hp && hp->auth_cfm) ++ hp->auth_cfm(conn, status); ++ ++ hp = hci_proto[HCI_PROTO_SCO]; ++ if (hp && hp->auth_cfm) ++ hp->auth_cfm(conn, status); ++} ++ ++static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status) ++{ ++ register struct hci_proto *hp; ++ ++ hp = hci_proto[HCI_PROTO_L2CAP]; ++ if (hp && hp->encrypt_cfm) ++ hp->encrypt_cfm(conn, status); ++ ++ hp = hci_proto[HCI_PROTO_SCO]; ++ if (hp && hp->encrypt_cfm) ++ hp->encrypt_cfm(conn, status); ++} ++ ++int hci_register_proto(struct hci_proto *hproto); ++int hci_unregister_proto(struct hci_proto *hproto); ++int hci_register_notifier(struct notifier_block *nb); ++int hci_unregister_notifier(struct notifier_block *nb); ++ ++int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param); ++int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags); ++int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); ++ ++void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf); ++ ++void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data); + + /* ----- HCI Sockets ----- */ +-extern void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); ++void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); + + /* HCI info for socket */ +-#define hci_pi(sk) ((struct hci_pinfo *) &sk->protinfo) ++#define hci_pi(sk) ((struct hci_pinfo *) &sk->tp_pinfo) + struct hci_pinfo { + struct hci_dev *hdev; + struct hci_filter filter; + __u32 cmsg_mask; + }; + ++/* HCI security filter */ ++#define HCI_SFLT_MAX_OGF 5 ++ ++struct hci_sec_filter { ++ __u32 type_mask; ++ __u32 event_mask[2]; ++ __u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4]; ++}; ++ + /* ----- HCI requests ----- */ + #define HCI_REQ_DONE 0 + #define HCI_REQ_PEND 1 + #define HCI_REQ_CANCELED 2 + ++#define hci_req_lock(d) down(&d->req_lock) ++#define hci_req_unlock(d) up(&d->req_lock) ++ ++void hci_req_complete(struct hci_dev *hdev, int result); ++void hci_req_cancel(struct hci_dev *hdev, int err); ++ + #endif /* __HCI_CORE_H */ +--- linux/include/net/bluetooth/hci.h~bluetooth-2.4.18-mh11 2001-09-07 18:28:38.000000000 +0200 ++++ linux/include/net/bluetooth/hci.h 2004-01-25 23:37:39.000000000 +0100 +@@ -23,59 +23,75 @@ + */ + + /* +- * $Id$ ++ * $Id$ + */ + + #ifndef __HCI_H + #define __HCI_H + +-#include <asm/byteorder.h> +- +-#define HCI_MAX_DEV 8 +-#define HCI_MAX_FRAME_SIZE 2048 ++#define HCI_MAX_ACL_SIZE 1024 ++#define HCI_MAX_SCO_SIZE 255 ++#define HCI_MAX_EVENT_SIZE 260 ++#define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4) + + /* HCI dev events */ + #define HCI_DEV_REG 1 + #define HCI_DEV_UNREG 2 + #define HCI_DEV_UP 3 + #define HCI_DEV_DOWN 4 ++#define HCI_DEV_SUSPEND 5 ++#define HCI_DEV_RESUME 6 + + /* HCI device types */ +-#define HCI_UART 0 ++#define HCI_VHCI 0 + #define HCI_USB 1 +-#define HCI_VHCI 2 ++#define HCI_PCCARD 2 ++#define HCI_UART 3 ++#define HCI_RS232 4 ++#define HCI_PCI 5 + +-/* HCI device modes */ +-#define HCI_NORMAL 0x0001 +-#define HCI_RAW 0x0002 +-#define HCI_MODE_MASK (HCI_NORMAL | HCI_RAW) +-#define HCI_SOCK 0x1000 ++/* HCI device flags */ ++enum { ++ HCI_UP, ++ HCI_INIT, ++ HCI_RUNNING, + +-/* HCI device states */ +-#define HCI_INIT 0x0010 +-#define HCI_UP 0x0020 +-#define HCI_RUNNING 0x0040 ++ HCI_PSCAN, ++ HCI_ISCAN, ++ HCI_AUTH, ++ HCI_ENCRYPT, ++ HCI_INQUIRY, + +-/* HCI device flags */ +-#define HCI_PSCAN 0x0100 +-#define HCI_ISCAN 0x0200 +-#define HCI_AUTH 0x0400 ++ HCI_RAW ++}; + +-/* HCI Ioctl defines */ ++/* HCI ioctl defines */ + #define HCIDEVUP _IOW('H', 201, int) + #define HCIDEVDOWN _IOW('H', 202, int) + #define HCIDEVRESET _IOW('H', 203, int) +-#define HCIRESETSTAT _IOW('H', 204, int) +-#define HCIGETINFO _IOR('H', 205, int) +-#define HCIGETDEVLIST _IOR('H', 206, int) +-#define HCISETRAW _IOW('H', 207, int) +-#define HCISETSCAN _IOW('H', 208, int) +-#define HCISETAUTH _IOW('H', 209, int) +-#define HCIINQUIRY _IOR('H', 210, int) +-#define HCISETPTYPE _IOW('H', 211, int) ++#define HCIDEVRESTAT _IOW('H', 204, int) ++ ++#define HCIGETDEVLIST _IOR('H', 210, int) ++#define HCIGETDEVINFO _IOR('H', 211, int) + #define HCIGETCONNLIST _IOR('H', 212, int) ++#define HCIGETCONNINFO _IOR('H', 213, int) + +-#ifndef __NO_HCI_DEFS ++#define HCISETRAW _IOW('H', 220, int) ++#define HCISETSCAN _IOW('H', 221, int) ++#define HCISETAUTH _IOW('H', 222, int) ++#define HCISETENCRYPT _IOW('H', 223, int) ++#define HCISETPTYPE _IOW('H', 224, int) ++#define HCISETLINKPOL _IOW('H', 225, int) ++#define HCISETLINKMODE _IOW('H', 226, int) ++#define HCISETACLMTU _IOW('H', 227, int) ++#define HCISETSCOMTU _IOW('H', 228, int) ++ ++#define HCIINQUIRY _IOR('H', 240, int) ++ ++/* HCI timeouts */ ++#define HCI_CONN_TIMEOUT (HZ * 40) ++#define HCI_DISCONN_TIMEOUT (HZ * 2) ++#define HCI_CONN_IDLE_TIMEOUT (HZ * 60) + + /* HCI Packet types */ + #define HCI_COMMAND_PKT 0x01 +@@ -92,11 +108,18 @@ + #define HCI_DH3 0x0800 + #define HCI_DH5 0x8000 + ++#define HCI_HV1 0x0020 ++#define HCI_HV2 0x0040 ++#define HCI_HV3 0x0080 ++ ++#define SCO_PTYPE_MASK (HCI_HV1 | HCI_HV2 | HCI_HV3) ++#define ACL_PTYPE_MASK (~SCO_PTYPE_MASK) ++ + /* ACL flags */ +-#define ACL_CONT 0x0001 +-#define ACL_START 0x0002 +-#define ACL_ACTIVE_BCAST 0x0010 +-#define ACL_PICO_BCAST 0x0020 ++#define ACL_CONT 0x01 ++#define ACL_START 0x02 ++#define ACL_ACTIVE_BCAST 0x04 ++#define ACL_PICO_BCAST 0x08 + + /* Baseband links */ + #define SCO_LINK 0x00 +@@ -125,6 +148,20 @@ + #define LMP_PSCHEME 0x02 + #define LMP_PCONTROL 0x04 + ++/* Link policies */ ++#define HCI_LP_RSWITCH 0x0001 ++#define HCI_LP_HOLD 0x0002 ++#define HCI_LP_SNIFF 0x0004 ++#define HCI_LP_PARK 0x0008 ++ ++/* Link mode */ ++#define HCI_LM_ACCEPT 0x8000 ++#define HCI_LM_MASTER 0x0001 ++#define HCI_LM_AUTH 0x0002 ++#define HCI_LM_ENCRYPT 0x0004 ++#define HCI_LM_TRUSTED 0x0008 ++#define HCI_LM_RELIABLE 0x0010 ++ + /* ----- HCI Commands ----- */ + /* OGF & OCF values */ + +@@ -137,9 +174,10 @@ + __u8 hci_ver; + __u16 hci_rev; + __u8 lmp_ver; +- __u16 man_name; +- __u16 lmp_sub; ++ __u16 manufacturer; ++ __u16 lmp_subver; + } __attribute__ ((packed)) read_local_version_rp; ++#define READ_LOCAL_VERSION_RP_SIZE 9 + + #define OCF_READ_LOCAL_FEATURES 0x0003 + typedef struct { +@@ -165,18 +203,24 @@ + /* Host Controller and Baseband */ + #define OGF_HOST_CTL 0x03 + #define OCF_RESET 0x0003 ++#define OCF_READ_AUTH_ENABLE 0x001F + #define OCF_WRITE_AUTH_ENABLE 0x0020 +- #define AUTH_DISABLED 0x00 +- #define AUTH_ENABLED 0x01 ++ #define AUTH_DISABLED 0x00 ++ #define AUTH_ENABLED 0x01 ++ ++#define OCF_READ_ENCRYPT_MODE 0x0021 ++#define OCF_WRITE_ENCRYPT_MODE 0x0022 ++ #define ENCRYPT_DISABLED 0x00 ++ #define ENCRYPT_P2P 0x01 ++ #define ENCRYPT_BOTH 0x02 + + #define OCF_WRITE_CA_TIMEOUT 0x0016 + #define OCF_WRITE_PG_TIMEOUT 0x0018 + + #define OCF_WRITE_SCAN_ENABLE 0x001A +- #define SCANS_DISABLED 0x00 +- #define IS_ENA_PS_DIS 0x01 +- #define IS_DIS_PS_ENA 0x02 +- #define IS_ENA_PS_ENA 0x03 ++ #define SCAN_DISABLED 0x00 ++ #define SCAN_INQUIRY 0x01 ++ #define SCAN_PAGE 0x02 + + #define OCF_SET_EVENT_FLT 0x0005 + typedef struct { +@@ -226,9 +270,18 @@ + } __attribute__ ((packed)) write_class_of_dev_cp; + #define WRITE_CLASS_OF_DEV_CP_SIZE 3 + ++#define OCF_HOST_BUFFER_SIZE 0x0033 ++typedef struct { ++ __u16 acl_mtu; ++ __u8 sco_mtu; ++ __u16 acl_max_pkt; ++ __u16 sco_max_pkt; ++} __attribute__ ((packed)) host_buffer_size_cp; ++#define HOST_BUFFER_SIZE_CP_SIZE 7 ++ + /* Link Control */ + #define OGF_LINK_CTL 0x01 +-#define OCF_CREATE_CONN 0x0005 ++#define OCF_CREATE_CONN 0x0005 + typedef struct { + bdaddr_t bdaddr; + __u16 pkt_type; +@@ -246,6 +299,13 @@ + } __attribute__ ((packed)) accept_conn_req_cp; + #define ACCEPT_CONN_REQ_CP_SIZE 7 + ++#define OCF_REJECT_CONN_REQ 0x000a ++typedef struct { ++ bdaddr_t bdaddr; ++ __u8 reason; ++} __attribute__ ((packed)) reject_conn_req_cp; ++#define REJECT_CONN_REQ_CP_SIZE 7 ++ + #define OCF_DISCONNECT 0x0006 + typedef struct { + __u16 handle; +@@ -253,17 +313,142 @@ + } __attribute__ ((packed)) disconnect_cp; + #define DISCONNECT_CP_SIZE 3 + ++#define OCF_ADD_SCO 0x0007 ++typedef struct { ++ __u16 handle; ++ __u16 pkt_type; ++} __attribute__ ((packed)) add_sco_cp; ++#define ADD_SCO_CP_SIZE 4 ++ + #define OCF_INQUIRY 0x0001 + typedef struct { + __u8 lap[3]; +- __u8 lenght; ++ __u8 length; + __u8 num_rsp; + } __attribute__ ((packed)) inquiry_cp; + #define INQUIRY_CP_SIZE 5 + +-#define OGF_LINK_POLICY 0x02 /* Link Policy */ ++typedef struct { ++ __u8 status; ++ bdaddr_t bdaddr; ++} __attribute__ ((packed)) status_bdaddr_rp; ++#define STATUS_BDADDR_RP_SIZE 7 + +-/* --------- HCI Events --------- */ ++#define OCF_INQUIRY_CANCEL 0x0002 ++ ++#define OCF_LINK_KEY_REPLY 0x000B ++#define OCF_LINK_KEY_NEG_REPLY 0x000C ++typedef struct { ++ bdaddr_t bdaddr; ++ __u8 link_key[16]; ++} __attribute__ ((packed)) link_key_reply_cp; ++#define LINK_KEY_REPLY_CP_SIZE 22 ++ ++#define OCF_PIN_CODE_REPLY 0x000D ++#define OCF_PIN_CODE_NEG_REPLY 0x000E ++typedef struct { ++ bdaddr_t bdaddr; ++ __u8 pin_len; ++ __u8 pin_code[16]; ++} __attribute__ ((packed)) pin_code_reply_cp; ++#define PIN_CODE_REPLY_CP_SIZE 23 ++ ++#define OCF_CHANGE_CONN_PTYPE 0x000F ++typedef struct { ++ __u16 handle; ++ __u16 pkt_type; ++} __attribute__ ((packed)) change_conn_ptype_cp; ++#define CHANGE_CONN_PTYPE_CP_SIZE 4 ++ ++#define OCF_AUTH_REQUESTED 0x0011 ++typedef struct { ++ __u16 handle; ++} __attribute__ ((packed)) auth_requested_cp; ++#define AUTH_REQUESTED_CP_SIZE 2 ++ ++#define OCF_SET_CONN_ENCRYPT 0x0013 ++typedef struct { ++ __u16 handle; ++ __u8 encrypt; ++} __attribute__ ((packed)) set_conn_encrypt_cp; ++#define SET_CONN_ENCRYPT_CP_SIZE 3 ++ ++#define OCF_REMOTE_NAME_REQ 0x0019 ++typedef struct { ++ bdaddr_t bdaddr; ++ __u8 pscan_rep_mode; ++ __u8 pscan_mode; ++ __u16 clock_offset; ++} __attribute__ ((packed)) remote_name_req_cp; ++#define REMOTE_NAME_REQ_CP_SIZE 10 ++ ++#define OCF_READ_REMOTE_FEATURES 0x001B ++typedef struct { ++ __u16 handle; ++} __attribute__ ((packed)) read_remote_features_cp; ++#define READ_REMOTE_FEATURES_CP_SIZE 2 ++ ++#define OCF_READ_REMOTE_VERSION 0x001D ++typedef struct { ++ __u16 handle; ++} __attribute__ ((packed)) read_remote_version_cp; ++#define READ_REMOTE_VERSION_CP_SIZE 2 ++ ++/* Link Policy */ ++#define OGF_LINK_POLICY 0x02 ++#define OCF_ROLE_DISCOVERY 0x0009 ++typedef struct { ++ __u16 handle; ++} __attribute__ ((packed)) role_discovery_cp; ++#define ROLE_DISCOVERY_CP_SIZE 2 ++typedef struct { ++ __u8 status; ++ __u16 handle; ++ __u8 role; ++} __attribute__ ((packed)) role_discovery_rp; ++#define ROLE_DISCOVERY_RP_SIZE 4 ++ ++#define OCF_READ_LINK_POLICY 0x000C ++typedef struct { ++ __u16 handle; ++} __attribute__ ((packed)) read_link_policy_cp; ++#define READ_LINK_POLICY_CP_SIZE 2 ++typedef struct { ++ __u8 status; ++ __u16 handle; ++ __u16 policy; ++} __attribute__ ((packed)) read_link_policy_rp; ++#define READ_LINK_POLICY_RP_SIZE 5 ++ ++#define OCF_SWITCH_ROLE 0x000B ++typedef struct { ++ bdaddr_t bdaddr; ++ __u8 role; ++} __attribute__ ((packed)) switch_role_cp; ++#define SWITCH_ROLE_CP_SIZE 7 ++ ++#define OCF_WRITE_LINK_POLICY 0x000D ++typedef struct { ++ __u16 handle; ++ __u16 policy; ++} __attribute__ ((packed)) write_link_policy_cp; ++#define WRITE_LINK_POLICY_CP_SIZE 4 ++typedef struct { ++ __u8 status; ++ __u16 handle; ++} __attribute__ ((packed)) write_link_policy_rp; ++#define WRITE_LINK_POLICY_RP_SIZE 3 ++ ++/* Status params */ ++#define OGF_STATUS_PARAM 0x05 ++ ++/* Testing commands */ ++#define OGF_TESTING_CMD 0x3e ++ ++/* Vendor specific commands */ ++#define OGF_VENDOR_CMD 0x3f ++ ++/* ---- HCI Events ---- */ + #define EVT_INQUIRY_COMPLETE 0x01 + + #define EVT_INQUIRY_RESULT 0x02 +@@ -272,11 +457,22 @@ + __u8 pscan_rep_mode; + __u8 pscan_period_mode; + __u8 pscan_mode; +- __u8 class[3]; ++ __u8 dev_class[3]; + __u16 clock_offset; + } __attribute__ ((packed)) inquiry_info; + #define INQUIRY_INFO_SIZE 14 + ++#define EVT_INQUIRY_RESULT_WITH_RSSI 0x22 ++typedef struct { ++ bdaddr_t bdaddr; ++ __u8 pscan_rep_mode; ++ __u8 pscan_period_mode; ++ __u8 dev_class[3]; ++ __u16 clock_offset; ++ __u8 rssi; ++} __attribute__ ((packed)) inquiry_info_with_rssi; ++#define INQUIRY_INFO_WITH_RSSI_SIZE 14 ++ + #define EVT_CONN_COMPLETE 0x03 + typedef struct { + __u8 status; +@@ -303,6 +499,44 @@ + } __attribute__ ((packed)) evt_disconn_complete; + #define EVT_DISCONN_COMPLETE_SIZE 4 + ++#define EVT_AUTH_COMPLETE 0x06 ++typedef struct { ++ __u8 status; ++ __u16 handle; ++} __attribute__ ((packed)) evt_auth_complete; ++#define EVT_AUTH_COMPLETE_SIZE 3 ++ ++#define EVT_REMOTE_NAME_REQ_COMPLETE 0x07 ++typedef struct { ++ __u8 status; ++ bdaddr_t bdaddr; ++ __u8 name[248]; ++} __attribute__ ((packed)) evt_remote_name_req_complete; ++#define EVT_REMOTE_NAME_REQ_COMPLETE_SIZE 255 ++ ++#define EVT_ENCRYPT_CHANGE 0x08 ++typedef struct { ++ __u8 status; ++ __u16 handle; ++ __u8 encrypt; ++} __attribute__ ((packed)) evt_encrypt_change; ++#define EVT_ENCRYPT_CHANGE_SIZE 5 ++ ++#define EVT_QOS_SETUP_COMPLETE 0x0D ++typedef struct { ++ __u8 service_type; ++ __u32 token_rate; ++ __u32 peak_bandwidth; ++ __u32 latency; ++ __u32 delay_variation; ++} __attribute__ ((packed)) hci_qos; ++typedef struct { ++ __u8 status; ++ __u16 handle; ++ hci_qos qos; ++} __attribute__ ((packed)) evt_qos_setup_complete; ++#define EVT_QOS_SETUP_COMPLETE_SIZE 20 ++ + #define EVT_CMD_COMPLETE 0x0e + typedef struct { + __u8 ncmd; +@@ -321,16 +555,78 @@ + #define EVT_NUM_COMP_PKTS 0x13 + typedef struct { + __u8 num_hndl; +- /* variable lenght part */ ++ /* variable length part */ + } __attribute__ ((packed)) evt_num_comp_pkts; + #define EVT_NUM_COMP_PKTS_SIZE 1 + +-#define EVT_HCI_DEV_EVENT 0xfd ++#define EVT_ROLE_CHANGE 0x12 ++typedef struct { ++ __u8 status; ++ bdaddr_t bdaddr; ++ __u8 role; ++} __attribute__ ((packed)) evt_role_change; ++#define EVT_ROLE_CHANGE_SIZE 8 ++ ++#define EVT_PIN_CODE_REQ 0x16 ++typedef struct { ++ bdaddr_t bdaddr; ++} __attribute__ ((packed)) evt_pin_code_req; ++#define EVT_PIN_CODE_REQ_SIZE 6 ++ ++#define EVT_LINK_KEY_REQ 0x17 ++typedef struct { ++ bdaddr_t bdaddr; ++} __attribute__ ((packed)) evt_link_key_req; ++#define EVT_LINK_KEY_REQ_SIZE 6 ++ ++#define EVT_LINK_KEY_NOTIFY 0x18 ++typedef struct { ++ bdaddr_t bdaddr; ++ __u8 link_key[16]; ++ __u8 key_type; ++} __attribute__ ((packed)) evt_link_key_notify; ++#define EVT_LINK_KEY_NOTIFY_SIZE 23 ++ ++#define EVT_READ_REMOTE_FEATURES_COMPLETE 0x0B ++typedef struct { ++ __u8 status; ++ __u16 handle; ++ __u8 features[8]; ++} __attribute__ ((packed)) evt_read_remote_features_complete; ++#define EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE 11 ++ ++#define EVT_READ_REMOTE_VERSION_COMPLETE 0x0C ++typedef struct { ++ __u8 status; ++ __u16 handle; ++ __u8 lmp_ver; ++ __u16 manufacturer; ++ __u16 lmp_subver; ++} __attribute__ ((packed)) evt_read_remote_version_complete; ++#define EVT_READ_REMOTE_VERSION_COMPLETE_SIZE 8 ++ ++/* Internal events generated by BlueZ stack */ ++#define EVT_STACK_INTERNAL 0xfd ++typedef struct { ++ __u16 type; ++ __u8 data[0]; ++} __attribute__ ((packed)) evt_stack_internal; ++#define EVT_STACK_INTERNAL_SIZE 2 ++ ++#define EVT_SI_DEVICE 0x01 ++typedef struct { ++ __u16 event; ++ __u16 dev_id; ++} __attribute__ ((packed)) evt_si_device; ++#define EVT_SI_DEVICE_SIZE 4 ++ ++#define EVT_SI_SECURITY 0x02 + typedef struct { + __u16 event; +- __u16 param; +-} __attribute__ ((packed)) evt_hci_dev_event; +-#define EVT_HCI_DEV_EVENT_SIZE 4 ++ __u16 proto; ++ __u16 subproto; ++ __u8 incomming; ++} __attribute__ ((packed)) evt_si_security; + + /* -------- HCI Packet structures -------- */ + #define HCI_TYPE_LEN 1 +@@ -369,14 +665,14 @@ + #define acl_handle(h) (h & 0x0fff) + #define acl_flags(h) (h >> 12) + +-#endif /* _NO_HCI_DEFS */ +- + /* HCI Socket options */ +-#define HCI_DATA_DIR 0x0001 +-#define HCI_FILTER 0x0002 ++#define HCI_DATA_DIR 1 ++#define HCI_FILTER 2 ++#define HCI_TIME_STAMP 3 + + /* HCI CMSG flags */ + #define HCI_CMSG_DIR 0x0001 ++#define HCI_CMSG_TSTAMP 0x0002 + + struct sockaddr_hci { + sa_family_t hci_family; +@@ -387,27 +683,29 @@ + struct hci_filter { + __u32 type_mask; + __u32 event_mask[2]; ++ __u16 opcode; + }; + +-struct hci_dev_req { +- __u16 dev_id; +- __u32 dev_opt; +-}; +- +-struct hci_dev_list_req { +- __u16 dev_num; +- struct hci_dev_req dev_req[0]; /* hci_dev_req structures */ +-}; ++#define HCI_FLT_TYPE_BITS 31 ++#define HCI_FLT_EVENT_BITS 63 ++#define HCI_FLT_OGF_BITS 63 ++#define HCI_FLT_OCF_BITS 127 + +-struct hci_inquiry_req { +- __u16 dev_id; +- __u16 flags; +- __u8 lap[3]; +- __u8 length; +- __u8 num_rsp; +-}; +-#define IREQ_CACHE_FLUSH 0x0001 ++#if BITS_PER_LONG == 64 ++static inline void hci_set_bit(int nr, void *addr) ++{ ++ *((__u32 *) addr + (nr >> 5)) |= ((__u32) 1 << (nr & 31)); ++} ++static inline int hci_test_bit(int nr, void *addr) ++{ ++ return *((__u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31)); ++} ++#else ++#define hci_set_bit set_bit ++#define hci_test_bit test_bit ++#endif + ++/* Ioctl requests structures */ + struct hci_dev_stats { + __u32 err_rx; + __u32 err_tx; +@@ -433,11 +731,13 @@ + __u8 features[8]; + + __u32 pkt_type; ++ __u32 link_policy; ++ __u32 link_mode; + + __u16 acl_mtu; +- __u16 acl_max; ++ __u16 acl_pkts; + __u16 sco_mtu; +- __u16 sco_max; ++ __u16 sco_pkts; + + struct hci_dev_stats stat; + }; +@@ -445,6 +745,20 @@ + struct hci_conn_info { + __u16 handle; + bdaddr_t bdaddr; ++ __u8 type; ++ __u8 out; ++ __u16 state; ++ __u32 link_mode; ++}; ++ ++struct hci_dev_req { ++ __u16 dev_id; ++ __u32 dev_opt; ++}; ++ ++struct hci_dev_list_req { ++ __u16 dev_num; ++ struct hci_dev_req dev_req[0]; /* hci_dev_req structures */ + }; + + struct hci_conn_list_req { +@@ -453,4 +767,26 @@ + struct hci_conn_info conn_info[0]; + }; + ++struct hci_conn_info_req { ++ bdaddr_t bdaddr; ++ __u8 type; ++ struct hci_conn_info conn_info[0]; ++}; ++ ++struct hci_inquiry_req { ++ __u16 dev_id; ++ __u16 flags; ++ __u8 lap[3]; ++ __u8 length; ++ __u8 num_rsp; ++}; ++#define IREQ_CACHE_FLUSH 0x0001 ++ ++struct hci_remotename_req { ++ __u16 dev_id; ++ __u16 flags; ++ bdaddr_t bdaddr; ++ __u8 name[248]; ++}; ++ + #endif /* __HCI_H */ +--- linux/include/net/bluetooth/hci_uart.h~bluetooth-2.4.18-mh11 ++++ linux/include/net/bluetooth/hci_uart.h +-/* +- BlueZ - Bluetooth protocol stack for Linux +- Copyright (C) 2000-2001 Qualcomm Incorporated +- +- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; +- +- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY +- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES +- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- +- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, +- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS +- SOFTWARE IS DISCLAIMED. +-*/ +- +-/* +- * $Id$ +- */ +- +-#ifndef N_HCI +-#define N_HCI 15 +-#endif +- +-#ifdef __KERNEL__ +- +-#define tty2n_hci(tty) ((struct n_hci *)((tty)->disc_data)) +-#define n_hci2tty(n_hci) ((n_hci)->tty) +- +-struct n_hci { +- struct tty_struct *tty; +- struct hci_dev hdev; +- +- struct sk_buff_head txq; +- unsigned long tx_state; +- +- spinlock_t rx_lock; +- unsigned long rx_state; +- unsigned long rx_count; +- struct sk_buff *rx_skb; +-}; +- +-/* Transmit states */ +-#define TRANS_SENDING 1 +-#define TRANS_WAKEUP 2 +- +-/* Receiver States */ +-#define WAIT_PACKET_TYPE 0 +-#define WAIT_EVENT_HDR 1 +-#define WAIT_ACL_HDR 2 +-#define WAIT_SCO_HDR 3 +-#define WAIT_DATA 4 +- +-#endif /* __KERNEL__ */ +--- linux/include/net/bluetooth/hci_usb.h~bluetooth-2.4.18-mh11 ++++ linux/include/net/bluetooth/hci_usb.h +-/* +- BlueZ - Bluetooth protocol stack for Linux +- Copyright (C) 2000-2001 Qualcomm Incorporated +- +- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; +- +- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY +- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES +- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- +- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, +- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS +- SOFTWARE IS DISCLAIMED. +-*/ +- +-/* +- * $Id$ +- */ +- +-#ifdef __KERNEL__ +- +-/* Class, SubClass, and Protocol codes that describe a Bluetooth device */ +-#define HCI_DEV_CLASS 0xe0 /* Wireless class */ +-#define HCI_DEV_SUBCLASS 0x01 /* RF subclass */ +-#define HCI_DEV_PROTOCOL 0x01 /* Bluetooth programming protocol */ +- +-#define HCI_CTRL_REQ 0x20 +- +-struct hci_usb { +- struct usb_device *udev; +- +- devrequest dev_req; +- struct urb *ctrl_urb; +- struct urb *intr_urb; +- struct urb *read_urb; +- struct urb *write_urb; +- +- __u8 *read_buf; +- __u8 *intr_buf; +- struct sk_buff *intr_skb; +- int intr_count; +- +- __u8 bulk_out_ep_addr; +- __u8 bulk_in_ep_addr; +- __u8 intr_in_ep_addr; +- __u8 intr_in_interval; +- +- struct hci_dev hdev; +- +- unsigned long tx_state; +- struct sk_buff_head tx_ctrl_q; +- struct sk_buff_head tx_write_q; +-}; +- +-/* Transmit states */ +-#define HCI_TX_CTRL 1 +-#define HCI_TX_WRITE 2 +- +-#endif /* __KERNEL__ */ +--- linux/include/net/bluetooth/hci_vhci.h~bluetooth-2.4.18-mh11 ++++ linux/include/net/bluetooth/hci_vhci.h +-/* +- BlueZ - Bluetooth protocol stack for Linux +- Copyright (C) 2000-2001 Qualcomm Incorporated +- +- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; +- +- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY +- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES +- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- +- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, +- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS +- SOFTWARE IS DISCLAIMED. +-*/ +- +-/* +- * $Id$ +- */ +- +-#ifndef __HCI_VHCI_H +-#define __HCI_VHCI_H +- +-#ifdef __KERNEL__ +- +-struct hci_vhci_struct { +- struct hci_dev hdev; +- __u32 flags; +- wait_queue_head_t read_wait; +- struct sk_buff_head readq; +- struct fasync_struct *fasync; +-}; +- +-/* VHCI device flags */ +-#define VHCI_FASYNC 0x0010 +- +-#endif /* __KERNEL__ */ +- +-#define VHCI_DEV "/dev/vhci" +-#define VHCI_MINOR 250 +- +-#endif /* __HCI_VHCI_H */ +--- linux/include/net/bluetooth/l2cap_core.h~bluetooth-2.4.18-mh11 ++++ linux/include/net/bluetooth/l2cap_core.h +-/* +- BlueZ - Bluetooth protocol stack for Linux +- Copyright (C) 2000-2001 Qualcomm Incorporated +- +- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; +- +- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY +- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES +- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- +- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, +- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS +- SOFTWARE IS DISCLAIMED. +-*/ +- +-/* +- * $Id$ +- */ +- +-#ifndef __L2CAP_CORE_H +-#define __L2CAP_CORE_H +- +-#ifdef __KERNEL__ +- +-/* ----- L2CAP interface ----- */ +-struct l2cap_iff { +- struct list_head list; +- struct hci_dev *hdev; +- bdaddr_t *bdaddr; +- __u16 mtu; +- spinlock_t lock; +- struct list_head conn_list; +-}; +- +-static inline void l2cap_iff_lock(struct l2cap_iff *iff) +-{ +- spin_lock(&iff->lock); +-} +- +-static inline void l2cap_iff_unlock(struct l2cap_iff *iff) +-{ +- spin_unlock(&iff->lock); +-} +- +-/* ----- L2CAP connections ----- */ +-struct l2cap_chan_list { +- struct sock *head; +- rwlock_t lock; +- long num; +-}; +- +-struct l2cap_conn { +- struct l2cap_iff *iff; +- struct list_head list; +- +- struct hci_conn *hconn; +- +- __u16 state; +- __u8 out; +- bdaddr_t src; +- bdaddr_t dst; +- +- spinlock_t lock; +- atomic_t refcnt; +- +- struct sk_buff *rx_skb; +- __u32 rx_len; +- __u8 rx_ident; +- __u8 tx_ident; +- +- struct l2cap_chan_list chan_list; +- +- struct timer_list timer; +-}; +- +-static inline void __l2cap_conn_link(struct l2cap_iff *iff, struct l2cap_conn *c) +-{ +- list_add(&c->list, &iff->conn_list); +-} +- +-static inline void __l2cap_conn_unlink(struct l2cap_iff *iff, struct l2cap_conn *c) +-{ +- list_del(&c->list); +-} +- +-/* ----- L2CAP channel and socket info ----- */ +-#define l2cap_pi(sk) ((struct l2cap_pinfo *) &sk->protinfo) +- +-struct l2cap_accept_q { +- struct sock *head; +- struct sock *tail; +-}; +- +-struct l2cap_pinfo { +- bdaddr_t src; +- bdaddr_t dst; +- __u16 psm; +- __u16 dcid; +- __u16 scid; +- __u32 flags; +- +- __u16 imtu; +- __u16 omtu; +- __u16 flush_to; +- +- __u8 conf_state; +- __u16 conf_mtu; +- +- __u8 ident; +- +- struct l2cap_conn *conn; +- struct sock *next_c; +- struct sock *prev_c; +- +- struct sock *parent; +- struct sock *next_q; +- struct sock *prev_q; +- +- struct l2cap_accept_q accept_q; +-}; +- +-#define CONF_REQ_SENT 0x01 +-#define CONF_INPUT_DONE 0x02 +-#define CONF_OUTPUT_DONE 0x04 +- +-extern struct bluez_sock_list l2cap_sk_list; +-extern struct list_head l2cap_iff_list; +-extern rwlock_t l2cap_rt_lock; +- +-extern void l2cap_register_proc(void); +-extern void l2cap_unregister_proc(void); +- +-#endif /* __KERNEL__ */ +- +-#endif /* __L2CAP_CORE_H */ +--- linux/include/net/bluetooth/l2cap.h~bluetooth-2.4.18-mh11 2001-09-07 18:28:38.000000000 +0200 ++++ linux/include/net/bluetooth/l2cap.h 2004-01-25 23:37:39.000000000 +0100 +@@ -23,22 +23,17 @@ + */ + + /* +- * $Id$ ++ * $Id$ + */ + + #ifndef __L2CAP_H + #define __L2CAP_H + +-#include <asm/types.h> +-#include <asm/byteorder.h> +- + /* L2CAP defaults */ + #define L2CAP_DEFAULT_MTU 672 + #define L2CAP_DEFAULT_FLUSH_TO 0xFFFF + + #define L2CAP_CONN_TIMEOUT (HZ * 40) +-#define L2CAP_DISCONN_TIMEOUT (HZ * 2) +-#define L2CAP_CONN_IDLE_TIMEOUT (HZ * 60) + + /* L2CAP socket address */ + struct sockaddr_l2 { +@@ -47,17 +42,12 @@ + bdaddr_t l2_bdaddr; + }; + +-/* set/get sockopt defines */ +-#define L2CAP_OPTIONS 0x01 ++/* Socket options */ ++#define L2CAP_OPTIONS 0x01 + struct l2cap_options { + __u16 omtu; + __u16 imtu; + __u16 flush_to; +- __u32 token_rate; +- __u32 bucket_size; +- __u32 pick_band; +- __u32 latency; +- __u32 delay_var; + }; + + #define L2CAP_CONNINFO 0x02 +@@ -65,6 +55,27 @@ + __u16 hci_handle; + }; + ++#define L2CAP_LM 0x03 ++#define L2CAP_LM_MASTER 0x0001 ++#define L2CAP_LM_AUTH 0x0002 ++#define L2CAP_LM_ENCRYPT 0x0004 ++#define L2CAP_LM_TRUSTED 0x0008 ++#define L2CAP_LM_RELIABLE 0x0010 ++ ++#define L2CAP_QOS 0x04 ++struct l2cap_qos { ++ __u16 service_type; ++ __u32 token_rate; ++ __u32 token_bucket_size; ++ __u32 peak_bandwidth; ++ __u32 latency; ++ __u32 delay_variation; ++}; ++ ++#define L2CAP_SERV_NO_TRAFFIC 0x00 ++#define L2CAP_SERV_BEST_EFFORT 0x01 ++#define L2CAP_SERV_GUARANTEED 0x02 ++ + /* L2CAP command codes */ + #define L2CAP_COMMAND_REJ 0x01 + #define L2CAP_CONN_REQ 0x02 +@@ -79,7 +90,6 @@ + #define L2CAP_INFO_RSP 0x0b + + /* L2CAP structures */ +- + typedef struct { + __u16 len; + __u16 cid; +@@ -112,11 +122,17 @@ + } __attribute__ ((packed)) l2cap_conn_rsp; + #define L2CAP_CONN_RSP_SIZE 8 + +-#define L2CAP_CONN_SUCCESS 0x0000 +-#define L2CAP_CONN_PEND 0x0001 +-#define L2CAP_CONN_BAD_PSM 0x0002 +-#define L2CAP_CONN_SEC_BLOCK 0x0003 +-#define L2CAP_CONN_NO_MEM 0x0004 ++/* connect result */ ++#define L2CAP_CR_SUCCESS 0x0000 ++#define L2CAP_CR_PEND 0x0001 ++#define L2CAP_CR_BAD_PSM 0x0002 ++#define L2CAP_CR_SEC_BLOCK 0x0003 ++#define L2CAP_CR_NO_MEM 0x0004 ++ ++/* connect status */ ++#define L2CAP_CS_NO_INFO 0x0000 ++#define L2CAP_CS_AUTHEN_PEND 0x0001 ++#define L2CAP_CS_AUTHOR_PEND 0x0002 + + typedef struct { + __u16 dcid; +@@ -147,6 +163,8 @@ + #define L2CAP_CONF_FLUSH_TO 0x02 + #define L2CAP_CONF_QOS 0x03 + ++#define L2CAP_CONF_MAX_SIZE 22 ++ + typedef struct { + __u16 dcid; + __u16 scid; +@@ -159,4 +177,74 @@ + } __attribute__ ((packed)) l2cap_disconn_rsp; + #define L2CAP_DISCONN_RSP_SIZE 4 + ++typedef struct { ++ __u16 type; ++ __u8 data[0]; ++} __attribute__ ((packed)) l2cap_info_req; ++#define L2CAP_INFO_REQ_SIZE 2 ++ ++typedef struct { ++ __u16 type; ++ __u16 result; ++ __u8 data[0]; ++} __attribute__ ((packed)) l2cap_info_rsp; ++#define L2CAP_INFO_RSP_SIZE 4 ++ ++/* ----- L2CAP connections ----- */ ++struct l2cap_chan_list { ++ struct sock *head; ++ rwlock_t lock; ++ long num; ++}; ++ ++struct l2cap_conn { ++ struct hci_conn *hcon; ++ ++ bdaddr_t *dst; ++ bdaddr_t *src; ++ ++ unsigned int mtu; ++ ++ spinlock_t lock; ++ ++ struct sk_buff *rx_skb; ++ __u32 rx_len; ++ __u8 rx_ident; ++ __u8 tx_ident; ++ ++ struct l2cap_chan_list chan_list; ++}; ++ ++/* ----- L2CAP channel and socket info ----- */ ++#define l2cap_pi(sk) ((struct l2cap_pinfo *) &sk->tp_pinfo) ++ ++struct l2cap_pinfo { ++ __u16 psm; ++ __u16 dcid; ++ __u16 scid; ++ ++ __u16 imtu; ++ __u16 omtu; ++ __u16 flush_to; ++ ++ __u32 link_mode; ++ ++ __u8 conf_state; ++ __u8 conf_retry; ++ __u16 conf_mtu; ++ ++ __u8 ident; ++ ++ struct l2cap_conn *conn; ++ struct sock *next_c; ++ struct sock *prev_c; ++}; ++ ++#define L2CAP_CONF_REQ_SENT 0x01 ++#define L2CAP_CONF_INPUT_DONE 0x02 ++#define L2CAP_CONF_OUTPUT_DONE 0x04 ++#define L2CAP_CONF_MAX_RETRIES 2 ++ ++void l2cap_load(void); ++ + #endif /* __L2CAP_H */ +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/include/net/bluetooth/rfcomm.h 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,361 @@ ++/* ++ RFCOMM implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com> ++ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ RPN support - Dirk Husemann <hud@zurich.ibm.com> ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#ifndef __RFCOMM_H ++#define __RFCOMM_H ++ ++#define RFCOMM_PSM 3 ++ ++#define RFCOMM_CONN_TIMEOUT (HZ * 30) ++#define RFCOMM_DISC_TIMEOUT (HZ * 20) ++ ++#define RFCOMM_DEFAULT_MTU 127 ++#define RFCOMM_DEFAULT_CREDITS 7 ++ ++#define RFCOMM_MAX_L2CAP_MTU 1024 ++#define RFCOMM_MAX_CREDITS 40 ++ ++#define RFCOMM_SKB_HEAD_RESERVE 8 ++#define RFCOMM_SKB_TAIL_RESERVE 2 ++#define RFCOMM_SKB_RESERVE (RFCOMM_SKB_HEAD_RESERVE + RFCOMM_SKB_TAIL_RESERVE) ++ ++#define RFCOMM_SABM 0x2f ++#define RFCOMM_DISC 0x43 ++#define RFCOMM_UA 0x63 ++#define RFCOMM_DM 0x0f ++#define RFCOMM_UIH 0xef ++ ++#define RFCOMM_TEST 0x08 ++#define RFCOMM_FCON 0x28 ++#define RFCOMM_FCOFF 0x18 ++#define RFCOMM_MSC 0x38 ++#define RFCOMM_RPN 0x24 ++#define RFCOMM_RLS 0x14 ++#define RFCOMM_PN 0x20 ++#define RFCOMM_NSC 0x04 ++ ++#define RFCOMM_V24_FC 0x02 ++#define RFCOMM_V24_RTC 0x04 ++#define RFCOMM_V24_RTR 0x08 ++#define RFCOMM_V24_IC 0x40 ++#define RFCOMM_V24_DV 0x80 ++ ++#define RFCOMM_RPN_BR_2400 0x0 ++#define RFCOMM_RPN_BR_4800 0x1 ++#define RFCOMM_RPN_BR_7200 0x2 ++#define RFCOMM_RPN_BR_9600 0x3 ++#define RFCOMM_RPN_BR_19200 0x4 ++#define RFCOMM_RPN_BR_38400 0x5 ++#define RFCOMM_RPN_BR_57600 0x6 ++#define RFCOMM_RPN_BR_115200 0x7 ++#define RFCOMM_RPN_BR_230400 0x8 ++ ++#define RFCOMM_RPN_DATA_5 0x0 ++#define RFCOMM_RPN_DATA_6 0x1 ++#define RFCOMM_RPN_DATA_7 0x2 ++#define RFCOMM_RPN_DATA_8 0x3 ++ ++#define RFCOMM_RPN_STOP_1 0 ++#define RFCOMM_RPN_STOP_15 1 ++ ++#define RFCOMM_RPN_PARITY_NONE 0x0 ++#define RFCOMM_RPN_PARITY_ODD 0x4 ++#define RFCOMM_RPN_PARITY_EVEN 0x5 ++#define RFCOMM_RPN_PARITY_MARK 0x6 ++#define RFCOMM_RPN_PARITY_SPACE 0x7 ++ ++#define RFCOMM_RPN_FLOW_NONE 0x00 ++ ++#define RFCOMM_RPN_XON_CHAR 0x11 ++#define RFCOMM_RPN_XOFF_CHAR 0x13 ++ ++#define RFCOMM_RPN_PM_BITRATE 0x0001 ++#define RFCOMM_RPN_PM_DATA 0x0002 ++#define RFCOMM_RPN_PM_STOP 0x0004 ++#define RFCOMM_RPN_PM_PARITY 0x0008 ++#define RFCOMM_RPN_PM_PARITY_TYPE 0x0010 ++#define RFCOMM_RPN_PM_XON 0x0020 ++#define RFCOMM_RPN_PM_XOFF 0x0040 ++#define RFCOMM_RPN_PM_FLOW 0x3F00 ++ ++#define RFCOMM_RPN_PM_ALL 0x3F7F ++ ++struct rfcomm_hdr { ++ u8 addr; ++ u8 ctrl; ++ u8 len; // Actual size can be 2 bytes ++} __attribute__ ((packed)); ++ ++struct rfcomm_cmd { ++ u8 addr; ++ u8 ctrl; ++ u8 len; ++ u8 fcs; ++} __attribute__ ((packed)); ++ ++struct rfcomm_mcc { ++ u8 type; ++ u8 len; ++} __attribute__ ((packed)); ++ ++struct rfcomm_pn { ++ u8 dlci; ++ u8 flow_ctrl; ++ u8 priority; ++ u8 ack_timer; ++ u16 mtu; ++ u8 max_retrans; ++ u8 credits; ++} __attribute__ ((packed)); ++ ++struct rfcomm_rpn { ++ u8 dlci; ++ u8 bit_rate; ++ u8 line_settings; ++ u8 flow_ctrl; ++ u8 xon_char; ++ u8 xoff_char; ++ u16 param_mask; ++} __attribute__ ((packed)); ++ ++struct rfcomm_rls { ++ u8 dlci; ++ u8 status; ++} __attribute__ ((packed)); ++ ++struct rfcomm_msc { ++ u8 dlci; ++ u8 v24_sig; ++} __attribute__ ((packed)); ++ ++/* ---- Core structures, flags etc ---- */ ++ ++struct rfcomm_session { ++ struct list_head list; ++ struct socket *sock; ++ unsigned long state; ++ unsigned long flags; ++ atomic_t refcnt; ++ int initiator; ++ ++ /* Default DLC parameters */ ++ int cfc; ++ uint mtu; ++ ++ struct list_head dlcs; ++}; ++ ++struct rfcomm_dlc { ++ struct list_head list; ++ struct rfcomm_session *session; ++ struct sk_buff_head tx_queue; ++ struct timer_list timer; ++ ++ spinlock_t lock; ++ unsigned long state; ++ unsigned long flags; ++ atomic_t refcnt; ++ u8 dlci; ++ u8 addr; ++ u8 priority; ++ u8 v24_sig; ++ u8 mscex; ++ ++ uint mtu; ++ uint cfc; ++ uint rx_credits; ++ uint tx_credits; ++ ++ void *owner; ++ ++ void (*data_ready)(struct rfcomm_dlc *d, struct sk_buff *skb); ++ void (*state_change)(struct rfcomm_dlc *d, int err); ++ void (*modem_status)(struct rfcomm_dlc *d, u8 v24_sig); ++}; ++ ++/* DLC and session flags */ ++#define RFCOMM_RX_THROTTLED 0 ++#define RFCOMM_TX_THROTTLED 1 ++#define RFCOMM_MSC_PENDING 2 ++#define RFCOMM_TIMED_OUT 3 ++ ++/* Scheduling flags and events */ ++#define RFCOMM_SCHED_STATE 0 ++#define RFCOMM_SCHED_RX 1 ++#define RFCOMM_SCHED_TX 2 ++#define RFCOMM_SCHED_TIMEO 3 ++#define RFCOMM_SCHED_WAKEUP 31 ++ ++/* MSC exchange flags */ ++#define RFCOMM_MSCEX_TX 1 ++#define RFCOMM_MSCEX_RX 2 ++#define RFCOMM_MSCEX_OK (RFCOMM_MSCEX_TX + RFCOMM_MSCEX_RX) ++ ++/* CFC states */ ++#define RFCOMM_CFC_UNKNOWN -1 ++#define RFCOMM_CFC_DISABLED 0 ++#define RFCOMM_CFC_ENABLED RFCOMM_MAX_CREDITS ++ ++extern struct task_struct *rfcomm_thread; ++extern unsigned long rfcomm_event; ++ ++static inline void rfcomm_schedule(uint event) ++{ ++ if (!rfcomm_thread) ++ return; ++ set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event); ++ wake_up_process(rfcomm_thread); ++} ++ ++extern struct semaphore rfcomm_sem; ++#define rfcomm_lock() down(&rfcomm_sem); ++#define rfcomm_unlock() up(&rfcomm_sem); ++ ++/* ---- RFCOMM DLCs (channels) ---- */ ++struct rfcomm_dlc *rfcomm_dlc_alloc(int prio); ++void rfcomm_dlc_free(struct rfcomm_dlc *d); ++int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel); ++int rfcomm_dlc_close(struct rfcomm_dlc *d, int reason); ++int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb); ++int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig); ++int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig); ++ ++#define rfcomm_dlc_lock(d) spin_lock(&d->lock) ++#define rfcomm_dlc_unlock(d) spin_unlock(&d->lock) ++ ++static inline void rfcomm_dlc_hold(struct rfcomm_dlc *d) ++{ ++ atomic_inc(&d->refcnt); ++} ++ ++static inline void rfcomm_dlc_put(struct rfcomm_dlc *d) ++{ ++ if (atomic_dec_and_test(&d->refcnt)) ++ rfcomm_dlc_free(d); ++} ++ ++extern void FASTCALL(__rfcomm_dlc_throttle(struct rfcomm_dlc *d)); ++extern void FASTCALL(__rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)); ++ ++static inline void rfcomm_dlc_throttle(struct rfcomm_dlc *d) ++{ ++ if (!test_and_set_bit(RFCOMM_RX_THROTTLED, &d->flags)) ++ __rfcomm_dlc_throttle(d); ++} ++ ++static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) ++{ ++ if (test_and_clear_bit(RFCOMM_RX_THROTTLED, &d->flags)) ++ __rfcomm_dlc_unthrottle(d); ++} ++ ++/* ---- RFCOMM sessions ---- */ ++struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state); ++struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst); ++struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err); ++void rfcomm_session_del(struct rfcomm_session *s); ++void rfcomm_session_close(struct rfcomm_session *s, int err); ++void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst); ++ ++static inline void rfcomm_session_hold(struct rfcomm_session *s) ++{ ++ atomic_inc(&s->refcnt); ++} ++ ++static inline void rfcomm_session_put(struct rfcomm_session *s) ++{ ++ if (atomic_dec_and_test(&s->refcnt)) ++ rfcomm_session_del(s); ++} ++ ++/* ---- RFCOMM chechsum ---- */ ++extern u8 rfcomm_crc_table[]; ++ ++/* ---- RFCOMM sockets ---- */ ++struct sockaddr_rc { ++ sa_family_t rc_family; ++ bdaddr_t rc_bdaddr; ++ u8 rc_channel; ++}; ++ ++#define rfcomm_pi(sk) ((struct rfcomm_pinfo *) &sk->tp_pinfo) ++ ++struct rfcomm_pinfo { ++ struct rfcomm_dlc *dlc; ++ u8 channel; ++}; ++ ++int rfcomm_init_sockets(void); ++void rfcomm_cleanup_sockets(void); ++ ++int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d); ++ ++/* ---- RFCOMM TTY ---- */ ++#define RFCOMM_MAX_DEV 256 ++ ++#define RFCOMMCREATEDEV _IOW('R', 200, int) ++#define RFCOMMRELEASEDEV _IOW('R', 201, int) ++#define RFCOMMGETDEVLIST _IOR('R', 210, int) ++#define RFCOMMGETDEVINFO _IOR('R', 211, int) ++#define RFCOMMSTEALDLC _IOW('R', 220, int) ++ ++#define RFCOMM_REUSE_DLC 0 ++#define RFCOMM_RELEASE_ONHUP 1 ++#define RFCOMM_HANGUP_NOW 2 ++#define RFCOMM_TTY_ATTACHED 3 ++ ++struct rfcomm_dev_req { ++ s16 dev_id; ++ u32 flags; ++ bdaddr_t src; ++ bdaddr_t dst; ++ u8 channel; ++}; ++ ++struct rfcomm_dev_info { ++ s16 id; ++ u32 flags; ++ u16 state; ++ bdaddr_t src; ++ bdaddr_t dst; ++ u8 channel; ++}; ++ ++struct rfcomm_dev_list_req { ++ u16 dev_num; ++ struct rfcomm_dev_info dev_info[0]; ++}; ++ ++int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg); ++int rfcomm_init_ttys(void); ++void rfcomm_cleanup_ttys(void); ++ ++#endif /* __RFCOMM_H */ +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/include/net/bluetooth/sco.h 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,81 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#ifndef __SCO_H ++#define __SCO_H ++ ++/* SCO defaults */ ++#define SCO_DEFAULT_MTU 500 ++#define SCO_DEFAULT_FLUSH_TO 0xFFFF ++ ++#define SCO_CONN_TIMEOUT (HZ * 40) ++#define SCO_DISCONN_TIMEOUT (HZ * 2) ++#define SCO_CONN_IDLE_TIMEOUT (HZ * 60) ++ ++/* SCO socket address */ ++struct sockaddr_sco { ++ sa_family_t sco_family; ++ bdaddr_t sco_bdaddr; ++}; ++ ++/* set/get sockopt defines */ ++#define SCO_OPTIONS 0x01 ++struct sco_options { ++ __u16 mtu; ++}; ++ ++#define SCO_CONNINFO 0x02 ++struct sco_conninfo { ++ __u16 hci_handle; ++}; ++ ++/* ---- SCO connections ---- */ ++struct sco_conn { ++ struct hci_conn *hcon; ++ ++ bdaddr_t *dst; ++ bdaddr_t *src; ++ ++ spinlock_t lock; ++ struct sock *sk; ++ ++ unsigned int mtu; ++}; ++ ++#define sco_conn_lock(c) spin_lock(&c->lock); ++#define sco_conn_unlock(c) spin_unlock(&c->lock); ++ ++/* ----- SCO socket info ----- */ ++#define sco_pi(sk) ((struct sco_pinfo *) &sk->tp_pinfo) ++ ++struct sco_pinfo { ++ __u32 flags; ++ struct sco_conn *conn; ++}; ++ ++#endif /* __SCO_H */ +--- linux/include/pcmcia/ciscode.h~bluetooth-2.4.18-mh11 2001-12-21 18:42:04.000000000 +0100 ++++ linux/include/pcmcia/ciscode.h 2004-01-25 23:37:39.000000000 +0100 +@@ -1,5 +1,5 @@ + /* +- * ciscode.h 1.48 2001/08/24 12:16:12 ++ * ciscode.h 1.57 2002/11/03 20:38:14 + * + * 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 +@@ -60,6 +60,10 @@ + #define PRODID_INTEL_DUAL_RS232 0x0301 + #define PRODID_INTEL_2PLUS 0x8422 + ++#define MANFID_KME 0x0032 ++#define PRODID_KME_KXLC005_A 0x0704 ++#define PRODID_KME_KXLC005_B 0x2904 ++ + #define MANFID_LINKSYS 0x0143 + #define PRODID_LINKSYS_PCMLM28 0xc0ab + #define PRODID_LINKSYS_3400 0x3341 +@@ -94,6 +98,8 @@ + #define PRODID_OSITECH_JACK_336 0x0007 + #define PRODID_OSITECH_SEVEN 0x0008 + ++#define MANFID_OXSEMI 0x0279 ++ + #define MANFID_PIONEER 0x000b + + #define MANFID_PSION 0x016c +@@ -103,6 +109,7 @@ + #define PRODID_QUATECH_SPP100 0x0003 + #define PRODID_QUATECH_DUAL_RS232 0x0012 + #define PRODID_QUATECH_DUAL_RS232_D1 0x0007 ++#define PRODID_QUATECH_DUAL_RS232_D2 0x0052 + #define PRODID_QUATECH_QUAD_RS232 0x001b + #define PRODID_QUATECH_DUAL_RS422 0x000e + #define PRODID_QUATECH_QUAD_RS422 0x0045 +@@ -120,9 +127,12 @@ + + #define MANFID_TDK 0x0105 + #define PRODID_TDK_CF010 0x0900 ++#define PRODID_TDK_GN3410 0x4815 + + #define MANFID_TOSHIBA 0x0098 + ++#define MANFID_UNGERMANN 0x02c0 ++ + #define MANFID_XIRCOM 0x0105 + + #endif /* _LINUX_CISCODE_H */ +--- linux/kernel/ksyms.c~bluetooth-2.4.18-mh11 2004-01-25 23:28:30.000000000 +0100 ++++ linux/kernel/ksyms.c 2004-01-25 23:37:39.000000000 +0100 +@@ -47,6 +47,7 @@ + #include <linux/in6.h> + #include <linux/completion.h> + #include <linux/seq_file.h> ++#include <linux/firmware.h> + #include <asm/checksum.h> + + #if defined(CONFIG_PROC_FS) +@@ -543,6 +544,13 @@ + EXPORT_SYMBOL(strspn); + EXPORT_SYMBOL(strsep); + ++#ifdef CONFIG_FW_LOADER ++EXPORT_SYMBOL(release_firmware); ++EXPORT_SYMBOL(request_firmware); ++EXPORT_SYMBOL(request_firmware_nowait); ++EXPORT_SYMBOL(register_firmware); ++#endif ++ + /* software interrupts */ + EXPORT_SYMBOL(tasklet_hi_vec); + EXPORT_SYMBOL(tasklet_vec); +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/lib/Config.in 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,12 @@ ++# ++# Library configuration ++# ++mainmenu_option next_comment ++comment 'Library routines' ++ ++if [ "$CONFIG_EXPERIMENTAL" = "y" -a \ ++ "$CONFIG_HOTPLUG" = "y" ]; then ++ tristate 'Hotplug firmware loading support (EXPERIMENTAL)' CONFIG_FW_LOADER ++fi ++ ++endmenu +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/lib/firmware_class.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,573 @@ ++/* ++ * firmware_class.c - Multi purpose firmware loading support ++ * ++ * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org> ++ * ++ * Please see Documentation/firmware_class/ for more information. ++ * ++ */ ++/* ++ * Based on kernel/kmod.c and drivers/usb/usb.c ++ */ ++/* ++ kernel/kmod.c ++ Kirk Petersen ++ ++ Reorganized not to be a daemon by Adam Richter, with guidance ++ from Greg Zornetzer. ++ ++ Modified to avoid chroot and file sharing problems. ++ Mikael Pettersson ++ ++ Limit the concurrent number of kmod modprobes to catch loops from ++ "modprobe needs a service that is in a module". ++ Keith Owens <kaos@ocs.com.au> December 1999 ++ ++ Unblock all signals when we exec a usermode process. ++ Shuu Yamaguchi <shuu@wondernetworkresources.com> December 2000 ++*/ ++/* ++ * drivers/usb/usb.c ++ * ++ * (C) Copyright Linus Torvalds 1999 ++ * (C) Copyright Johannes Erdfelt 1999-2001 ++ * (C) Copyright Andreas Gal 1999 ++ * (C) Copyright Gregory P. Smith 1999 ++ * (C) Copyright Deti Fliegl 1999 (new USB architecture) ++ * (C) Copyright Randy Dunlap 2000 ++ * (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id) ++ * (C) Copyright Yggdrasil Computing, Inc. 2000 ++ * (usb_device_id matching changes by Adam J. Richter) ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/string.h> ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/kmod.h> ++#include <linux/proc_fs.h> ++#include <linux/vmalloc.h> ++#include <asm/hardirq.h> ++ ++#include "linux/firmware.h" ++ ++MODULE_AUTHOR("Manuel Estrada Sainz <ranty@debian.org>"); ++MODULE_DESCRIPTION("Multi purpose firmware loading support"); ++MODULE_LICENSE("GPL"); ++ ++#define err(format, arg...) \ ++ printk(KERN_ERR "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg) ++#define warn(format, arg...) \ ++ printk(KERN_WARNING "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg) ++#define dbg(format, arg...) \ ++ printk(KERN_DEBUG "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg) ++ ++static int loading_timeout = 10; /* In seconds */ ++static struct proc_dir_entry *proc_dir_timeout; ++static struct proc_dir_entry *proc_dir; ++ ++#ifdef CONFIG_HOTPLUG ++ ++static int ++call_helper(char *verb, const char *name, const char *device) ++{ ++ char *argv[3], **envp, *buf, *scratch; ++ int i = 0; ++ ++ int retval = 0; ++ ++ if (!hotplug_path[0]) ++ return -ENOENT; ++ if (in_interrupt()) { ++ err("in_interrupt"); ++ return -EFAULT; ++ } ++ if (!current->fs->root) { ++ warn("call_policy %s -- no FS yet", verb); ++ return -EPERM; ++ } ++ ++ if (!(envp = (char **) kmalloc(20 * sizeof (char *), GFP_KERNEL))) { ++ err("unable to allocate envp"); ++ return -ENOMEM; ++ } ++ if (!(buf = kmalloc(256, GFP_KERNEL))) { ++ kfree(envp); ++ err("unable to allocate buf"); ++ return -ENOMEM; ++ } ++ ++ /* only one standardized param to hotplug command: type */ ++ argv[0] = hotplug_path; ++ argv[1] = "firmware"; ++ argv[2] = 0; ++ ++ /* minimal command environment */ ++ envp[i++] = "HOME=/"; ++ envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; ++ ++#ifdef DEBUG ++ /* hint that policy agent should enter no-stdout debug mode */ ++ envp[i++] = "DEBUG=kernel"; ++#endif ++ scratch = buf; ++ ++ if (device) { ++ envp[i++] = scratch; ++ scratch += snprintf(scratch, FIRMWARE_NAME_MAX+25, ++ "DEVPATH=/driver/firmware/%s", device) + 1; ++ } ++ ++ envp[i++] = scratch; ++ scratch += sprintf(scratch, "ACTION=%s", verb) + 1; ++ ++ envp[i++] = scratch; ++ scratch += snprintf(scratch, FIRMWARE_NAME_MAX, ++ "FIRMWARE=%s", name) + 1; ++ ++ envp[i++] = 0; ++ ++#ifdef DEBUG ++ dbg("firmware: %s %s %s", argv[0], argv[1], verb); ++#endif ++ ++ retval = call_usermodehelper(argv[0], argv, envp); ++ if (retval) { ++ printk("call_usermodehelper return %d\n", retval); ++ } ++ ++ kfree(buf); ++ kfree(envp); ++ return retval; ++} ++#else ++ ++static inline int ++call_helper(char *verb, const char *name, const char *device) ++{ ++ return -ENOENT; ++} ++ ++#endif /* CONFIG_HOTPLUG */ ++ ++struct firmware_priv { ++ struct completion completion; ++ struct proc_dir_entry *proc_dir; ++ struct proc_dir_entry *attr_data; ++ struct proc_dir_entry *attr_loading; ++ struct firmware *fw; ++ int loading; ++ int abort; ++ int alloc_size; ++ struct timer_list timeout; ++}; ++ ++static int ++firmware_timeout_show(char *buf, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ return sprintf(buf, "%d\n", loading_timeout); ++} ++ ++/** ++ * firmware_timeout_store: ++ * Description: ++ * Sets the number of seconds to wait for the firmware. Once ++ * this expires an error will be return to the driver and no ++ * firmware will be provided. ++ * ++ * Note: zero means 'wait for ever' ++ * ++ **/ ++static int ++firmware_timeout_store(struct file *file, const char *buf, ++ unsigned long count, void *data) ++{ ++ loading_timeout = simple_strtol(buf, NULL, 10); ++ return count; ++} ++ ++static int ++firmware_loading_show(char *buf, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct firmware_priv *fw_priv = data; ++ return sprintf(buf, "%d\n", fw_priv->loading); ++} ++ ++/** ++ * firmware_loading_store: - loading control file ++ * Description: ++ * The relevant values are: ++ * ++ * 1: Start a load, discarding any previous partial load. ++ * 0: Conclude the load and handle the data to the driver code. ++ * -1: Conclude the load with an error and discard any written data. ++ **/ ++static int ++firmware_loading_store(struct file *file, const char *buf, ++ unsigned long count, void *data) ++{ ++ struct firmware_priv *fw_priv = data; ++ int prev_loading = fw_priv->loading; ++ ++ fw_priv->loading = simple_strtol(buf, NULL, 10); ++ ++ switch (fw_priv->loading) { ++ case -1: ++ fw_priv->abort = 1; ++ wmb(); ++ complete(&fw_priv->completion); ++ break; ++ case 1: ++ kfree(fw_priv->fw->data); ++ fw_priv->fw->data = NULL; ++ fw_priv->fw->size = 0; ++ fw_priv->alloc_size = 0; ++ break; ++ case 0: ++ if (prev_loading == 1) ++ complete(&fw_priv->completion); ++ break; ++ } ++ ++ return count; ++} ++ ++static int ++firmware_data_read(char *buffer, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ struct firmware_priv *fw_priv = data; ++ struct firmware *fw = fw_priv->fw; ++ ++ if (offset > fw->size) ++ return 0; ++ if (offset + count > fw->size) ++ count = fw->size - offset; ++ ++ memcpy(buffer, fw->data + offset, count); ++ *start = (void *) ((long) count); ++ return count; ++} ++static int ++fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size) ++{ ++ u8 *new_data; ++ int new_size; ++ ++ if (min_size <= fw_priv->alloc_size) ++ return 0; ++ if((min_size % PAGE_SIZE) == 0) ++ new_size = min_size; ++ else ++ new_size = (min_size + PAGE_SIZE) & PAGE_MASK; ++ new_data = vmalloc(new_size); ++ if (!new_data) { ++ printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__); ++ /* Make sure that we don't keep incomplete data */ ++ fw_priv->abort = 1; ++ return -ENOMEM; ++ } ++ fw_priv->alloc_size = new_size; ++ if (fw_priv->fw->data) { ++ memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size); ++ vfree(fw_priv->fw->data); ++ } ++ fw_priv->fw->data = new_data; ++ BUG_ON(min_size > fw_priv->alloc_size); ++ return 0; ++} ++ ++/** ++ * firmware_data_write: ++ * ++ * Description: ++ * ++ * Data written to the 'data' attribute will be later handled to ++ * the driver as a firmware image. ++ **/ ++static int ++firmware_data_write(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ struct firmware_priv *fw_priv = data; ++ struct firmware *fw = fw_priv->fw; ++ int offset = file->f_pos; ++ int retval; ++ ++ retval = fw_realloc_buffer(fw_priv, offset + count); ++ if (retval) { ++ printk("%s: retval:%d\n", __FUNCTION__, retval); ++ return retval; ++ } ++ ++ memcpy(fw->data + offset, buffer, count); ++ ++ fw->size = max_t(size_t, offset + count, fw->size); ++ file->f_pos += count; ++ return count; ++} ++ ++static void ++firmware_class_timeout(u_long data) ++{ ++ struct firmware_priv *fw_priv = (struct firmware_priv *) data; ++ fw_priv->abort = 1; ++ wmb(); ++ complete(&fw_priv->completion); ++} ++static int ++fw_setup_class_device(struct firmware_priv **fw_priv_p, ++ const char *fw_name, const char *device) ++{ ++ int retval; ++ struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv), ++ GFP_KERNEL); ++ *fw_priv_p = fw_priv; ++ if (!fw_priv) { ++ retval = -ENOMEM; ++ goto out; ++ } ++ memset(fw_priv, 0, sizeof (*fw_priv)); ++ ++ init_completion(&fw_priv->completion); ++ ++ fw_priv->timeout.function = firmware_class_timeout; ++ fw_priv->timeout.data = (u_long) fw_priv; ++ init_timer(&fw_priv->timeout); ++ ++ retval = -EAGAIN; ++ fw_priv->proc_dir = create_proc_entry(device, 0644 | S_IFDIR, proc_dir); ++ if (!fw_priv->proc_dir) ++ goto err_free_fw_priv; ++ ++ fw_priv->attr_data = create_proc_entry("data", 0644 | S_IFREG, ++ fw_priv->proc_dir); ++ if (!fw_priv->attr_data) ++ goto err_remove_dir; ++ ++ fw_priv->attr_data->read_proc = firmware_data_read; ++ fw_priv->attr_data->write_proc = firmware_data_write; ++ fw_priv->attr_data->data = fw_priv; ++ ++ fw_priv->attr_loading = create_proc_entry("loading", 0644 | S_IFREG, ++ fw_priv->proc_dir); ++ if (!fw_priv->attr_loading) ++ goto err_remove_data; ++ ++ fw_priv->attr_loading->read_proc = firmware_loading_show; ++ fw_priv->attr_loading->write_proc = firmware_loading_store; ++ fw_priv->attr_loading->data = fw_priv; ++ ++ retval = 0; ++ fw_priv->fw = kmalloc(sizeof (struct firmware), GFP_KERNEL); ++ if (!fw_priv->fw) { ++ printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n", ++ __FUNCTION__); ++ retval = -ENOMEM; ++ goto err_remove_loading; ++ } ++ memset(fw_priv->fw, 0, sizeof (*fw_priv->fw)); ++ ++ goto out; ++ ++err_remove_loading: ++ remove_proc_entry("loading", fw_priv->proc_dir); ++err_remove_data: ++ remove_proc_entry("data", fw_priv->proc_dir); ++err_remove_dir: ++ remove_proc_entry(device, proc_dir); ++err_free_fw_priv: ++ kfree(fw_priv); ++out: ++ return retval; ++} ++static void ++fw_remove_class_device(struct firmware_priv *fw_priv) ++{ ++ remove_proc_entry("loading", fw_priv->proc_dir); ++ remove_proc_entry("data", fw_priv->proc_dir); ++ remove_proc_entry(fw_priv->proc_dir->name, proc_dir); ++} ++ ++/** ++ * request_firmware: - request firmware to hotplug and wait for it ++ * Description: ++ * @firmware will be used to return a firmware image by the name ++ * of @name for device @device. ++ * ++ * Should be called from user context where sleeping is allowed. ++ * ++ * @name will be use as $FIRMWARE in the hotplug environment and ++ * should be distinctive enough not to be confused with any other ++ * firmware image for this or any other device. ++ **/ ++int ++request_firmware(const struct firmware **firmware, const char *name, ++ const char *device) ++{ ++ struct firmware_priv *fw_priv; ++ int retval; ++ ++ if (!firmware) { ++ retval = -EINVAL; ++ goto out; ++ } ++ *firmware = NULL; ++ ++ retval = fw_setup_class_device(&fw_priv, name, device); ++ if (retval) ++ goto out; ++ ++ retval = call_helper("add", name, device); ++ if (retval) ++ goto out; ++ if (loading_timeout) { ++ fw_priv->timeout.expires = jiffies + loading_timeout * HZ; ++ add_timer(&fw_priv->timeout); ++ } ++ ++ wait_for_completion(&fw_priv->completion); ++ ++ del_timer(&fw_priv->timeout); ++ fw_remove_class_device(fw_priv); ++ ++ if (fw_priv->fw->size && !fw_priv->abort) { ++ *firmware = fw_priv->fw; ++ } else { ++ retval = -ENOENT; ++ vfree(fw_priv->fw->data); ++ kfree(fw_priv->fw); ++ } ++out: ++ kfree(fw_priv); ++ return retval; ++} ++ ++void ++release_firmware(const struct firmware *fw) ++{ ++ if (fw) { ++ vfree(fw->data); ++ kfree(fw); ++ } ++} ++ ++/** ++ * register_firmware: - provide a firmware image for later usage ++ * ++ * Description: ++ * Make sure that @data will be available by requesting firmware @name. ++ * ++ * Note: This will not be possible until some kind of persistence ++ * is available. ++ **/ ++void ++register_firmware(const char *name, const u8 *data, size_t size) ++{ ++ /* This is meaningless without firmware caching, so until we ++ * decide if firmware caching is reasonable just leave it as a ++ * noop */ ++} ++ ++/* Async support */ ++struct firmware_work { ++ struct tq_struct work; ++ struct module *module; ++ const char *name; ++ const char *device; ++ void *context; ++ void (*cont)(const struct firmware *fw, void *context); ++}; ++ ++static void ++request_firmware_work_func(void *arg) ++{ ++ struct firmware_work *fw_work = arg; ++ const struct firmware *fw; ++ if (!arg) ++ return; ++ request_firmware(&fw, fw_work->name, fw_work->device); ++ fw_work->cont(fw, fw_work->context); ++ release_firmware(fw); ++ __MOD_DEC_USE_COUNT(fw_work->module); ++ kfree(fw_work); ++} ++ ++/** ++ * request_firmware_nowait: ++ * ++ * Description: ++ * Asynchronous variant of request_firmware() for contexts where ++ * it is not possible to sleep. ++ * ++ * @cont will be called asynchronously when the firmware request is over. ++ * ++ * @context will be passed over to @cont. ++ * ++ * @fw may be %NULL if firmware request fails. ++ * ++ **/ ++int ++request_firmware_nowait( ++ struct module *module, ++ const char *name, const char *device, void *context, ++ void (*cont)(const struct firmware *fw, void *context)) ++{ ++ struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work), ++ GFP_ATOMIC); ++ if (!fw_work) ++ return -ENOMEM; ++ if (!try_inc_mod_count(module)) { ++ kfree(fw_work); ++ return -EFAULT; ++ } ++ ++ *fw_work = (struct firmware_work) { ++ .module = module, ++ .name = name, ++ .device = device, ++ .context = context, ++ .cont = cont, ++ }; ++ INIT_TQUEUE(&fw_work->work, request_firmware_work_func, fw_work); ++ ++ schedule_task(&fw_work->work); ++ return 0; ++} ++ ++static int __init ++firmware_class_init(void) ++{ ++ proc_dir = create_proc_entry("driver/firmware", 0755 | S_IFDIR, NULL); ++ if (!proc_dir) ++ return -EAGAIN; ++ proc_dir_timeout = create_proc_entry("timeout", ++ 0644 | S_IFREG, proc_dir); ++ if (!proc_dir_timeout) { ++ remove_proc_entry("driver/firmware", NULL); ++ return -EAGAIN; ++ } ++ proc_dir_timeout->read_proc = firmware_timeout_show; ++ proc_dir_timeout->write_proc = firmware_timeout_store; ++ return 0; ++} ++static void __exit ++firmware_class_exit(void) ++{ ++ remove_proc_entry("timeout", proc_dir); ++ remove_proc_entry("driver/firmware", NULL); ++} ++ ++module_init(firmware_class_init); ++module_exit(firmware_class_exit); ++ ++#ifndef CONFIG_FW_LOADER ++EXPORT_SYMBOL(release_firmware); ++EXPORT_SYMBOL(request_firmware); ++EXPORT_SYMBOL(request_firmware_nowait); ++EXPORT_SYMBOL(register_firmware); ++#endif +--- linux/lib/Makefile~bluetooth-2.4.18-mh11 2001-09-18 00:31:15.000000000 +0200 ++++ linux/lib/Makefile 2004-01-25 23:37:39.000000000 +0100 +@@ -8,13 +8,17 @@ + + L_TARGET := lib.a + +-export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o ++export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o \ ++ firmware_class.o + + obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o bust_spinlocks.o rbtree.o + ++obj-$(CONFIG_FW_LOADER) += firmware_class.o + obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o + obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o + ++include $(TOPDIR)/drivers/bluetooth/Makefile.lib ++ + ifneq ($(CONFIG_HAVE_DEC_LOCK),y) + obj-y += dec_and_lock.o + endif +--- linux/MAINTAINERS~bluetooth-2.4.18-mh11 2004-01-25 23:28:29.000000000 +0100 ++++ linux/MAINTAINERS 2004-01-25 23:37:39.000000000 +0100 +@@ -259,7 +259,84 @@ + L: linux-kernel@vger.kernel.org + S: Maintained + +-BLUETOOTH SUBSYSTEM (BlueZ) ++BLUETOOTH SUBSYSTEM ++P: Marcel Holtmann ++M: marcel@holtmann.org ++P: Maxim Krasnyansky ++M: maxk@qualcomm.com ++L: bluez-devel@lists.sf.net ++W: http://bluez.sf.net ++S: Maintained ++ ++BLUETOOTH RFCOMM LAYER ++P: Marcel Holtmann ++M: marcel@holtmann.org ++P: Maxim Krasnyansky ++M: maxk@qualcomm.com ++W: http://bluez.sf.net ++S: Maintained ++ ++BLUETOOTH BNEP LAYER ++P: Marcel Holtmann ++M: marcel@holtmann.org ++P: Maxim Krasnyansky ++M: maxk@qualcomm.com ++W: http://bluez.sf.net ++S: Maintained ++ ++BLUETOOTH CMTP LAYER ++P: Marcel Holtmann ++M: marcel@holtmann.org ++W: http://www.holtmann.org/linux/bluetooth/ ++S: Maintained ++ ++BLUETOOTH HCI USB DRIVER ++P: Marcel Holtmann ++M: marcel@holtmann.org ++P: Maxim Krasnyansky ++M: maxk@qualcomm.com ++W: http://bluez.sf.net ++S: Maintained ++ ++BLUETOOTH HCI UART DRIVER ++P: Marcel Holtmann ++M: marcel@holtmann.org ++P: Maxim Krasnyansky ++M: maxk@qualcomm.com ++W: http://bluez.sf.net ++S: Maintained ++ ++BLUETOOTH HCI BFUSB DRIVER ++P: Marcel Holtmann ++M: marcel@holtmann.org ++W: http://www.holtmann.org/linux/bluetooth/ ++S: Maintained ++ ++BLUETOOTH HCI DTL1 DRIVER ++P: Marcel Holtmann ++M: marcel@holtmann.org ++W: http://www.holtmann.org/linux/bluetooth/ ++S: Maintained ++ ++BLUETOOTH HCI BLUECARD DRIVER ++P: Marcel Holtmann ++M: marcel@holtmann.org ++W: http://www.holtmann.org/linux/bluetooth/ ++S: Maintained ++ ++BLUETOOTH HCI BT3C DRIVER ++P: Marcel Holtmann ++M: marcel@holtmann.org ++W: http://www.holtmann.org/linux/bluetooth/ ++S: Maintained ++ ++BLUETOOTH HCI BTUART DRIVER ++P: Marcel Holtmann ++M: marcel@holtmann.org ++W: http://www.holtmann.org/linux/bluetooth/ ++S: Maintained ++ ++BLUETOOTH HCI VHCI DRIVER + P: Maxim Krasnyansky + M: maxk@qualcomm.com + W: http://bluez.sf.net +--- linux/net/bluetooth/af_bluetooth.c~bluetooth-2.4.18-mh11 2001-09-07 18:28:38.000000000 +0200 ++++ linux/net/bluetooth/af_bluetooth.c 2004-01-25 23:37:39.000000000 +0100 +@@ -25,14 +25,15 @@ + /* + * BlueZ Bluetooth address family and sockets. + * +- * $Id$ ++ * $Id$ + */ +-#define VERSION "1.1" ++#define VERSION "2.3" + + #include <linux/config.h> + #include <linux/module.h> + + #include <linux/types.h> ++#include <linux/list.h> + #include <linux/errno.h> + #include <linux/kernel.h> + #include <linux/major.h> +@@ -40,6 +41,7 @@ + #include <linux/slab.h> + #include <linux/skbuff.h> + #include <linux/init.h> ++#include <linux/poll.h> + #include <linux/proc_fs.h> + #include <net/sock.h> + +@@ -48,70 +50,79 @@ + #endif + + #include <net/bluetooth/bluetooth.h> +-#include <net/bluetooth/bluez.h> ++ ++#ifndef AF_BLUETOOTH_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#endif + + /* Bluetooth sockets */ +-static struct net_proto_family *bluez_sock[BLUEZ_MAX_PROTO]; ++#define BLUEZ_MAX_PROTO 6 ++static struct net_proto_family *bluez_proto[BLUEZ_MAX_PROTO]; + + int bluez_sock_register(int proto, struct net_proto_family *ops) + { +- if (proto > BLUEZ_MAX_PROTO) ++ if (proto >= BLUEZ_MAX_PROTO) + return -EINVAL; + +- if (bluez_sock[proto]) ++ if (bluez_proto[proto]) + return -EEXIST; + +- bluez_sock[proto] = ops; ++ bluez_proto[proto] = ops; + return 0; + } + + int bluez_sock_unregister(int proto) + { +- if (proto > BLUEZ_MAX_PROTO) ++ if (proto >= BLUEZ_MAX_PROTO) + return -EINVAL; + +- if (!bluez_sock[proto]) ++ if (!bluez_proto[proto]) + return -ENOENT; + +- bluez_sock[proto] = NULL; ++ bluez_proto[proto] = NULL; + return 0; + } + + static int bluez_sock_create(struct socket *sock, int proto) + { +- if (proto > BLUEZ_MAX_PROTO) ++ if (proto >= BLUEZ_MAX_PROTO) + return -EINVAL; + + #if defined(CONFIG_KMOD) +- if (!bluez_sock[proto]) { ++ if (!bluez_proto[proto]) { + char module_name[30]; + sprintf(module_name, "bt-proto-%d", proto); + request_module(module_name); + } + #endif + +- if (!bluez_sock[proto]) ++ if (!bluez_proto[proto]) + return -ENOENT; + +- return bluez_sock[proto]->create(sock, proto); ++ return bluez_proto[proto]->create(sock, proto); ++} ++ ++void bluez_sock_init(struct socket *sock, struct sock *sk) ++{ ++ sock_init_data(sock, sk); ++ INIT_LIST_HEAD(&bluez_pi(sk)->accept_q); + } + + void bluez_sock_link(struct bluez_sock_list *l, struct sock *sk) + { +- write_lock(&l->lock); +- ++ write_lock_bh(&l->lock); + sk->next = l->head; + l->head = sk; + sock_hold(sk); +- +- write_unlock(&l->lock); ++ write_unlock_bh(&l->lock); + } + + void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *sk) + { + struct sock **skp; + +- write_lock(&l->lock); ++ write_lock_bh(&l->lock); + for (skp = &l->head; *skp; skp = &((*skp)->next)) { + if (*skp == sk) { + *skp = sk->next; +@@ -119,7 +130,162 @@ + break; + } + } +- write_unlock(&l->lock); ++ write_unlock_bh(&l->lock); ++} ++ ++void bluez_accept_enqueue(struct sock *parent, struct sock *sk) ++{ ++ BT_DBG("parent %p, sk %p", parent, sk); ++ ++ sock_hold(sk); ++ list_add_tail(&bluez_pi(sk)->accept_q, &bluez_pi(parent)->accept_q); ++ bluez_pi(sk)->parent = parent; ++ parent->ack_backlog++; ++} ++ ++static void bluez_accept_unlink(struct sock *sk) ++{ ++ BT_DBG("sk %p state %d", sk, sk->state); ++ ++ list_del_init(&bluez_pi(sk)->accept_q); ++ bluez_pi(sk)->parent->ack_backlog--; ++ bluez_pi(sk)->parent = NULL; ++ sock_put(sk); ++} ++ ++struct sock *bluez_accept_dequeue(struct sock *parent, struct socket *newsock) ++{ ++ struct list_head *p, *n; ++ struct bluez_pinfo *pi; ++ struct sock *sk; ++ ++ BT_DBG("parent %p", parent); ++ ++ list_for_each_safe(p, n, &bluez_pi(parent)->accept_q) { ++ pi = list_entry(p, struct bluez_pinfo, accept_q); ++ sk = bluez_sk(pi); ++ ++ lock_sock(sk); ++ if (sk->state == BT_CLOSED) { ++ release_sock(sk); ++ bluez_accept_unlink(sk); ++ continue; ++ } ++ ++ if (sk->state == BT_CONNECTED || !newsock) { ++ bluez_accept_unlink(sk); ++ if (newsock) ++ sock_graft(sk, newsock); ++ release_sock(sk); ++ return sk; ++ } ++ release_sock(sk); ++ } ++ return NULL; ++} ++ ++int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm) ++{ ++ int noblock = flags & MSG_DONTWAIT; ++ struct sock *sk = sock->sk; ++ struct sk_buff *skb; ++ int copied, err; ++ ++ BT_DBG("sock %p sk %p len %d", sock, sk, len); ++ ++ if (flags & (MSG_OOB)) ++ return -EOPNOTSUPP; ++ ++ if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) { ++ if (sk->shutdown & RCV_SHUTDOWN) ++ return 0; ++ return err; ++ } ++ ++ msg->msg_namelen = 0; ++ ++ copied = skb->len; ++ if (len < copied) { ++ msg->msg_flags |= MSG_TRUNC; ++ copied = len; ++ } ++ ++ skb->h.raw = skb->data; ++ err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); ++ ++ skb_free_datagram(sk, skb); ++ ++ return err ? : copied; ++} ++ ++unsigned int bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait) ++{ ++ struct sock *sk = sock->sk; ++ unsigned int mask; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ poll_wait(file, sk->sleep, wait); ++ mask = 0; ++ ++ if (sk->err || !skb_queue_empty(&sk->error_queue)) ++ mask |= POLLERR; ++ ++ if (sk->shutdown == SHUTDOWN_MASK) ++ mask |= POLLHUP; ++ ++ if (!skb_queue_empty(&sk->receive_queue) || ++ !list_empty(&bluez_pi(sk)->accept_q) || ++ (sk->shutdown & RCV_SHUTDOWN)) ++ mask |= POLLIN | POLLRDNORM; ++ ++ if (sk->state == BT_CLOSED) ++ mask |= POLLHUP; ++ ++ if (sk->state == BT_CONNECT || sk->state == BT_CONNECT2) ++ return mask; ++ ++ if (sock_writeable(sk)) ++ mask |= POLLOUT | POLLWRNORM | POLLWRBAND; ++ else ++ set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); ++ ++ return mask; ++} ++ ++int bluez_sock_wait_state(struct sock *sk, int state, unsigned long timeo) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ int err = 0; ++ ++ BT_DBG("sk %p", sk); ++ ++ add_wait_queue(sk->sleep, &wait); ++ while (sk->state != state) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ if (!timeo) { ++ err = -EAGAIN; ++ break; ++ } ++ ++ if (signal_pending(current)) { ++ err = sock_intr_errno(timeo); ++ break; ++ } ++ ++ release_sock(sk); ++ timeo = schedule_timeout(timeo); ++ lock_sock(sk); ++ ++ if (sk->err) { ++ err = sock_error(sk); ++ break; ++ } ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(sk->sleep, &wait); ++ return err; + } + + struct net_proto_family bluez_sock_family_ops = +@@ -129,9 +295,9 @@ + + int bluez_init(void) + { +- INF("BlueZ HCI Core ver %s Copyright (C) 2000,2001 Qualcomm Inc", ++ BT_INFO("BlueZ Core ver %s Copyright (C) 2000,2001 Qualcomm Inc", + VERSION); +- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); ++ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); + + proc_mkdir("bluetooth", NULL); + +@@ -164,5 +330,6 @@ + module_exit(bluez_cleanup); + + MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); +-MODULE_DESCRIPTION("BlueZ HCI Core ver " VERSION); ++MODULE_DESCRIPTION("BlueZ Core ver " VERSION); ++MODULE_LICENSE("GPL"); + #endif +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/bnep/bnep.h 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,185 @@ ++/* ++ BNEP protocol definition for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.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. ++ ++ 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$ ++ */ ++ ++#ifndef _BNEP_H ++#define _BNEP_H ++ ++#include <linux/types.h> ++#include <net/bluetooth/bluetooth.h> ++ ++#include "crc32.h" ++ ++// Limits ++#define BNEP_MAX_PROTO_FILTERS 5 ++#define BNEP_MAX_MULTICAST_FILTERS 20 ++ ++// UUIDs ++#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB ++#define BNEP_UUID16 0x02 ++#define BNEP_UUID32 0x04 ++#define BNEP_UUID128 0x16 ++ ++#define BNEP_SVC_PANU 0x1115 ++#define BNEP_SVC_NAP 0x1116 ++#define BNEP_SVC_GN 0x1117 ++ ++// Packet types ++#define BNEP_GENERAL 0x00 ++#define BNEP_CONTROL 0x01 ++#define BNEP_COMPRESSED 0x02 ++#define BNEP_COMPRESSED_SRC_ONLY 0x03 ++#define BNEP_COMPRESSED_DST_ONLY 0x04 ++ ++// Control types ++#define BNEP_CMD_NOT_UNDERSTOOD 0x00 ++#define BNEP_SETUP_CONN_REQ 0x01 ++#define BNEP_SETUP_CONN_RSP 0x02 ++#define BNEP_FILTER_NET_TYPE_SET 0x03 ++#define BNEP_FILTER_NET_TYPE_RSP 0x04 ++#define BNEP_FILTER_MULTI_ADDR_SET 0x05 ++#define BNEP_FILTER_MULTI_ADDR_RSP 0x06 ++ ++// Extension types ++#define BNEP_EXT_CONTROL 0x00 ++ ++// Response messages ++#define BNEP_SUCCESS 0x00 ++ ++#define BNEP_CONN_INVALID_DST 0x01 ++#define BNEP_CONN_INVALID_SRC 0x02 ++#define BNEP_CONN_INVALID_SVC 0x03 ++#define BNEP_CONN_NOT_ALLOWED 0x04 ++ ++#define BNEP_FILTER_UNSUPPORTED_REQ 0x01 ++#define BNEP_FILTER_INVALID_RANGE 0x02 ++#define BNEP_FILTER_INVALID_MCADDR 0x02 ++#define BNEP_FILTER_LIMIT_REACHED 0x03 ++#define BNEP_FILTER_DENIED_SECURITY 0x04 ++ ++// L2CAP settings ++#define BNEP_MTU 1691 ++#define BNEP_PSM 0x0f ++#define BNEP_FLUSH_TO 0xffff ++#define BNEP_CONNECT_TO 15 ++#define BNEP_FILTER_TO 15 ++ ++// Headers ++#define BNEP_TYPE_MASK 0x7f ++#define BNEP_EXT_HEADER 0x80 ++ ++struct bnep_setup_conn_req { ++ __u8 type; ++ __u8 ctrl; ++ __u8 uuid_size; ++ __u8 service[0]; ++} __attribute__((packed)); ++ ++struct bnep_set_filter_req { ++ __u8 type; ++ __u8 ctrl; ++ __u16 len; ++ __u8 list[0]; ++} __attribute__((packed)); ++ ++struct bnep_control_rsp { ++ __u8 type; ++ __u8 ctrl; ++ __u16 resp; ++} __attribute__((packed)); ++ ++struct bnep_ext_hdr { ++ __u8 type; ++ __u8 len; ++ __u8 data[0]; ++} __attribute__((packed)); ++ ++/* BNEP ioctl defines */ ++#define BNEPCONNADD _IOW('B', 200, int) ++#define BNEPCONNDEL _IOW('B', 201, int) ++#define BNEPGETCONNLIST _IOR('B', 210, int) ++#define BNEPGETCONNINFO _IOR('B', 211, int) ++ ++struct bnep_connadd_req { ++ int sock; // Connected socket ++ __u32 flags; ++ __u16 role; ++ char device[16]; // Name of the Ethernet device ++}; ++ ++struct bnep_conndel_req { ++ __u32 flags; ++ __u8 dst[ETH_ALEN]; ++}; ++ ++struct bnep_conninfo { ++ __u32 flags; ++ __u16 role; ++ __u16 state; ++ __u8 dst[ETH_ALEN]; ++ char device[16]; ++}; ++ ++struct bnep_connlist_req { ++ __u32 cnum; ++ struct bnep_conninfo *ci; ++}; ++ ++struct bnep_proto_filter { ++ __u16 start; ++ __u16 end; ++}; ++ ++int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock); ++int bnep_del_connection(struct bnep_conndel_req *req); ++int bnep_get_connlist(struct bnep_connlist_req *req); ++int bnep_get_conninfo(struct bnep_conninfo *ci); ++ ++// BNEP sessions ++struct bnep_session { ++ struct list_head list; ++ ++ unsigned int role; ++ unsigned long state; ++ unsigned long flags; ++ atomic_t killed; ++ ++ struct ethhdr eh; ++ struct msghdr msg; ++ ++ struct bnep_proto_filter proto_filter[BNEP_MAX_PROTO_FILTERS]; ++ u64 mc_filter; ++ ++ struct socket *sock; ++ struct net_device dev; ++ struct net_device_stats stats; ++}; ++ ++int bnep_net_init(struct net_device *dev); ++int bnep_sock_init(void); ++int bnep_sock_cleanup(void); ++ ++static inline int bnep_mc_hash(__u8 *addr) ++{ ++ return (bnep_crc32(~0, addr, ETH_ALEN) >> 26); ++} ++ ++#endif +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/bnep/Config.in 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,11 @@ ++# ++# Bluetooth BNEP layer configuration ++# ++ ++dep_tristate 'BNEP protocol support' CONFIG_BLUEZ_BNEP $CONFIG_BLUEZ_L2CAP ++ ++if [ "$CONFIG_BLUEZ_BNEP" != "n" ]; then ++ bool ' Multicast filter support' CONFIG_BLUEZ_BNEP_MC_FILTER ++ bool ' Protocol filter support' CONFIG_BLUEZ_BNEP_PROTO_FILTER ++fi ++ +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/bnep/core.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,708 @@ ++/* ++ BNEP implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2001-2002 Inventel Systemes ++ Written 2001-2002 by ++ Cl�ment Moreau <clement.moreau@inventel.fr> ++ David Libault <david.libault@inventel.fr> ++ ++ Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#define __KERNEL_SYSCALLS__ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/signal.h> ++#include <linux/init.h> ++#include <linux/wait.h> ++#include <linux/errno.h> ++#include <linux/smp_lock.h> ++#include <linux/net.h> ++#include <net/sock.h> ++ ++#include <linux/socket.h> ++#include <linux/file.h> ++ ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> ++ ++#include <asm/unaligned.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/l2cap.h> ++ ++#include "bnep.h" ++ ++#ifndef CONFIG_BLUEZ_BNEP_DEBUG ++#undef BT_DBG ++#define BT_DBG(D...) ++#endif ++ ++#define VERSION "1.1" ++ ++static LIST_HEAD(bnep_session_list); ++static DECLARE_RWSEM(bnep_session_sem); ++ ++static struct bnep_session *__bnep_get_session(u8 *dst) ++{ ++ struct bnep_session *s; ++ struct list_head *p; ++ ++ BT_DBG(""); ++ ++ list_for_each(p, &bnep_session_list) { ++ s = list_entry(p, struct bnep_session, list); ++ if (!memcmp(dst, s->eh.h_source, ETH_ALEN)) ++ return s; ++ } ++ return NULL; ++} ++ ++static void __bnep_link_session(struct bnep_session *s) ++{ ++ MOD_INC_USE_COUNT; ++ list_add(&s->list, &bnep_session_list); ++} ++ ++static void __bnep_unlink_session(struct bnep_session *s) ++{ ++ list_del(&s->list); ++ MOD_DEC_USE_COUNT; ++} ++ ++static int bnep_send(struct bnep_session *s, void *data, size_t len) ++{ ++ struct socket *sock = s->sock; ++ struct iovec iv = { data, len }; ++ s->msg.msg_iov = &iv; ++ s->msg.msg_iovlen = 1; ++ return sock->ops->sendmsg(sock, &s->msg, len, NULL); ++} ++ ++static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp) ++{ ++ struct bnep_control_rsp rsp; ++ rsp.type = BNEP_CONTROL; ++ rsp.ctrl = ctrl; ++ rsp.resp = htons(resp); ++ return bnep_send(s, &rsp, sizeof(rsp)); ++} ++ ++static int bnep_ctrl_set_netfilter(struct bnep_session *s, u16 *data, int len) ++{ ++ int n; ++ ++ if (len < 2) ++ return -EILSEQ; ++ ++ n = ntohs(get_unaligned(data)); ++ data++; len -= 2; ++ ++ if (len < n) ++ return -EILSEQ; ++ ++ BT_DBG("filter len %d", n); ++ ++#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER ++ n /= 4; ++ if (n <= BNEP_MAX_PROTO_FILTERS) { ++ struct bnep_proto_filter *f = s->proto_filter; ++ int i; ++ ++ for (i = 0; i < n; i++) { ++ f[i].start = get_unaligned(data++); ++ f[i].end = get_unaligned(data++); ++ ++ BT_DBG("proto filter start %d end %d", ++ f[i].start, f[i].end); ++ } ++ if (i < BNEP_MAX_PROTO_FILTERS) ++ memset(f + i, 0, sizeof(*f)); ++ ++ bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS); ++ } else { ++ bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED); ++ } ++#else ++ bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ); ++#endif ++ return 0; ++} ++ ++static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) ++{ ++ int n; ++ ++ if (len < 2) ++ return -EILSEQ; ++ ++ n = ntohs(get_unaligned((u16 *) data)); ++ data += 2; len -= 2; ++ ++ if (len < n) ++ return -EILSEQ; ++ ++ BT_DBG("filter len %d", n); ++ ++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER ++ n /= (ETH_ALEN * 2); ++ ++ if (n > 0) { ++ s->mc_filter = 0; ++ ++ /* Always send broadcast */ ++ set_bit(bnep_mc_hash(s->dev.broadcast), &s->mc_filter); ++ ++ /* Add address ranges to the multicast hash */ ++ for (; n > 0; n--) { ++ u8 a1[6], *a2; ++ ++ memcpy(a1, data, ETH_ALEN); data += ETH_ALEN; ++ a2 = data; data += ETH_ALEN; ++ ++ BT_DBG("mc filter %s -> %s", ++ batostr((void *) a1), batostr((void *) a2)); ++ ++ #define INCA(a) { int i = 5; while (i >=0 && ++a[i--] == 0); } ++ ++ /* Iterate from a1 to a2 */ ++ set_bit(bnep_mc_hash(a1), &s->mc_filter); ++ while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) { ++ INCA(a1); ++ set_bit(bnep_mc_hash(a1), &s->mc_filter); ++ } ++ } ++ } ++ ++ BT_DBG("mc filter hash 0x%llx", s->mc_filter); ++ ++ bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_SUCCESS); ++#else ++ bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_FILTER_UNSUPPORTED_REQ); ++#endif ++ return 0; ++} ++ ++static int bnep_rx_control(struct bnep_session *s, void *data, int len) ++{ ++ u8 cmd = *(u8 *)data; ++ int err = 0; ++ ++ data++; len--; ++ ++ switch (cmd) { ++ case BNEP_CMD_NOT_UNDERSTOOD: ++ case BNEP_SETUP_CONN_REQ: ++ case BNEP_SETUP_CONN_RSP: ++ case BNEP_FILTER_NET_TYPE_RSP: ++ case BNEP_FILTER_MULTI_ADDR_RSP: ++ /* Ignore these for now */ ++ break; ++ ++ case BNEP_FILTER_NET_TYPE_SET: ++ err = bnep_ctrl_set_netfilter(s, data, len); ++ break; ++ ++ case BNEP_FILTER_MULTI_ADDR_SET: ++ err = bnep_ctrl_set_mcfilter(s, data, len); ++ break; ++ ++ default: { ++ u8 pkt[3]; ++ pkt[0] = BNEP_CONTROL; ++ pkt[1] = BNEP_CMD_NOT_UNDERSTOOD; ++ pkt[2] = cmd; ++ bnep_send(s, pkt, sizeof(pkt)); ++ } ++ break; ++ } ++ ++ return err; ++} ++ ++static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb) ++{ ++ struct bnep_ext_hdr *h; ++ int err = 0; ++ ++ do { ++ h = (void *) skb->data; ++ if (!skb_pull(skb, sizeof(*h))) { ++ err = -EILSEQ; ++ break; ++ } ++ ++ BT_DBG("type 0x%x len %d", h->type, h->len); ++ ++ switch (h->type & BNEP_TYPE_MASK) { ++ case BNEP_EXT_CONTROL: ++ bnep_rx_control(s, skb->data, skb->len); ++ break; ++ ++ default: ++ /* Unknown extension, skip it. */ ++ break; ++ } ++ ++ if (!skb_pull(skb, h->len)) { ++ err = -EILSEQ; ++ break; ++ } ++ } while (!err && (h->type & BNEP_EXT_HEADER)); ++ ++ return err; ++} ++ ++static u8 __bnep_rx_hlen[] = { ++ ETH_HLEN, /* BNEP_GENERAL */ ++ 0, /* BNEP_CONTROL */ ++ 2, /* BNEP_COMPRESSED */ ++ ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */ ++ ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */ ++}; ++#define BNEP_RX_TYPES (sizeof(__bnep_rx_hlen) - 1) ++ ++static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) ++{ ++ struct net_device *dev = &s->dev; ++ struct sk_buff *nskb; ++ u8 type; ++ ++ dev->last_rx = jiffies; ++ s->stats.rx_bytes += skb->len; ++ ++ type = *(u8 *) skb->data; skb_pull(skb, 1); ++ ++ if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES) ++ goto badframe; ++ ++ if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) { ++ bnep_rx_control(s, skb->data, skb->len); ++ kfree_skb(skb); ++ return 0; ++ } ++ ++ skb->mac.raw = skb->data; ++ ++ /* Verify and pull out header */ ++ if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK])) ++ goto badframe; ++ ++ s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2)); ++ ++ if (type & BNEP_EXT_HEADER) { ++ if (bnep_rx_extension(s, skb) < 0) ++ goto badframe; ++ } ++ ++ /* Strip 802.1p header */ ++ if (ntohs(s->eh.h_proto) == 0x8100) { ++ if (!skb_pull(skb, 4)) ++ goto badframe; ++ s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2)); ++ } ++ ++ /* We have to alloc new skb and copy data here :(. Because original skb ++ * may not be modified and because of the alignment requirements. */ ++ nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL); ++ if (!nskb) { ++ s->stats.rx_dropped++; ++ kfree_skb(skb); ++ return -ENOMEM; ++ } ++ skb_reserve(nskb, 2); ++ ++ /* Decompress header and construct ether frame */ ++ switch (type & BNEP_TYPE_MASK) { ++ case BNEP_COMPRESSED: ++ memcpy(__skb_put(nskb, ETH_HLEN), &s->eh, ETH_HLEN); ++ break; ++ ++ case BNEP_COMPRESSED_SRC_ONLY: ++ memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN); ++ memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN); ++ put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2)); ++ break; ++ ++ case BNEP_COMPRESSED_DST_ONLY: ++ memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN); ++ memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source, ETH_ALEN + 2); ++ break; ++ ++ case BNEP_GENERAL: ++ memcpy(__skb_put(nskb, ETH_ALEN * 2), skb->mac.raw, ETH_ALEN * 2); ++ put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2)); ++ break; ++ } ++ ++ memcpy(__skb_put(nskb, skb->len), skb->data, skb->len); ++ kfree_skb(skb); ++ ++ s->stats.rx_packets++; ++ nskb->dev = dev; ++ nskb->ip_summed = CHECKSUM_UNNECESSARY; ++ nskb->protocol = eth_type_trans(nskb, dev); ++ netif_rx_ni(nskb); ++ return 0; ++ ++badframe: ++ s->stats.rx_errors++; ++ kfree_skb(skb); ++ return 0; ++} ++ ++static u8 __bnep_tx_types[] = { ++ BNEP_GENERAL, ++ BNEP_COMPRESSED_SRC_ONLY, ++ BNEP_COMPRESSED_DST_ONLY, ++ BNEP_COMPRESSED ++}; ++ ++static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb) ++{ ++ struct ethhdr *eh = (void *) skb->data; ++ struct socket *sock = s->sock; ++ struct iovec iv[3]; ++ int len = 0, il = 0; ++ u8 type = 0; ++ ++ BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type); ++ ++ if (!skb->dev) { ++ /* Control frame sent by us */ ++ goto send; ++ } ++ ++ iv[il++] = (struct iovec) { &type, 1 }; ++ len++; ++ ++ if (!memcmp(eh->h_dest, s->eh.h_source, ETH_ALEN)) ++ type |= 0x01; ++ ++ if (!memcmp(eh->h_source, s->eh.h_dest, ETH_ALEN)) ++ type |= 0x02; ++ ++ if (type) ++ skb_pull(skb, ETH_ALEN * 2); ++ ++ type = __bnep_tx_types[type]; ++ switch (type) { ++ case BNEP_COMPRESSED_SRC_ONLY: ++ iv[il++] = (struct iovec) { eh->h_source, ETH_ALEN }; ++ len += ETH_ALEN; ++ break; ++ ++ case BNEP_COMPRESSED_DST_ONLY: ++ iv[il++] = (struct iovec) { eh->h_dest, ETH_ALEN }; ++ len += ETH_ALEN; ++ break; ++ } ++ ++send: ++ iv[il++] = (struct iovec) { skb->data, skb->len }; ++ len += skb->len; ++ ++ /* FIXME: linearize skb */ ++ ++ s->msg.msg_iov = iv; ++ s->msg.msg_iovlen = il; ++ len = sock->ops->sendmsg(sock, &s->msg, len, NULL); ++ kfree_skb(skb); ++ ++ if (len > 0) { ++ s->stats.tx_bytes += len; ++ s->stats.tx_packets++; ++ return 0; ++ } ++ ++ return len; ++} ++ ++static int bnep_session(void *arg) ++{ ++ struct bnep_session *s = arg; ++ struct net_device *dev = &s->dev; ++ struct sock *sk = s->sock->sk; ++ struct sk_buff *skb; ++ wait_queue_t wait; ++ ++ BT_DBG(""); ++ ++ daemonize(); reparent_to_init(); ++ ++ sprintf(current->comm, "kbnepd %s", dev->name); ++ ++ sigfillset(¤t->blocked); ++ flush_signals(current); ++ ++ current->nice = -15; ++ ++ set_fs(KERNEL_DS); ++ ++ init_waitqueue_entry(&wait, current); ++ add_wait_queue(sk->sleep, &wait); ++ while (!atomic_read(&s->killed)) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ // RX ++ while ((skb = skb_dequeue(&sk->receive_queue))) { ++ skb_orphan(skb); ++ bnep_rx_frame(s, skb); ++ } ++ ++ if (sk->state != BT_CONNECTED) ++ break; ++ ++ // TX ++ while ((skb = skb_dequeue(&sk->write_queue))) ++ if (bnep_tx_frame(s, skb)) ++ break; ++ netif_wake_queue(dev); ++ ++ schedule(); ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(sk->sleep, &wait); ++ ++ /* Cleanup session */ ++ down_write(&bnep_session_sem); ++ ++ /* Delete network device */ ++ unregister_netdev(dev); ++ ++ /* Release the socket */ ++ fput(s->sock->file); ++ ++ __bnep_unlink_session(s); ++ ++ up_write(&bnep_session_sem); ++ kfree(s); ++ return 0; ++} ++ ++int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) ++{ ++ struct net_device *dev; ++ struct bnep_session *s, *ss; ++ u8 dst[ETH_ALEN], src[ETH_ALEN]; ++ int err; ++ ++ BT_DBG(""); ++ ++ baswap((void *) dst, &bluez_pi(sock->sk)->dst); ++ baswap((void *) src, &bluez_pi(sock->sk)->src); ++ ++ s = kmalloc(sizeof(struct bnep_session), GFP_KERNEL); ++ if (!s) ++ return -ENOMEM; ++ memset(s, 0, sizeof(struct bnep_session)); ++ ++ down_write(&bnep_session_sem); ++ ++ ss = __bnep_get_session(dst); ++ if (ss && ss->state == BT_CONNECTED) { ++ err = -EEXIST; ++ goto failed; ++ } ++ ++ dev = &s->dev; ++ ++ if (*req->device) ++ strcpy(dev->name, req->device); ++ else ++ strcpy(dev->name, "bnep%d"); ++ ++ memset(dev->broadcast, 0xff, ETH_ALEN); ++ ++ /* This is rx header therefor addresses are swaped. ++ * ie eh.h_dest is our local address. */ ++ memcpy(s->eh.h_dest, &src, ETH_ALEN); ++ memcpy(s->eh.h_source, &dst, ETH_ALEN); ++ ++ s->sock = sock; ++ s->role = req->role; ++ s->state = BT_CONNECTED; ++ ++ s->msg.msg_flags = MSG_NOSIGNAL; ++ ++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER ++ /* Set default mc filter */ ++ set_bit(bnep_mc_hash(dev->broadcast), &s->mc_filter); ++#endif ++ ++#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER ++ /* Set default protocol filter */ ++ ++ /* (IPv4, ARP) */ ++ s->proto_filter[0].start = htons(0x0800); ++ s->proto_filter[0].end = htons(0x0806); ++ /* (RARP, AppleTalk) */ ++ s->proto_filter[1].start = htons(0x8035); ++ s->proto_filter[1].end = htons(0x80F3); ++ /* (IPX, IPv6) */ ++ s->proto_filter[2].start = htons(0x8137); ++ s->proto_filter[2].end = htons(0x86DD); ++#endif ++ ++ dev->init = bnep_net_init; ++ dev->priv = s; ++ err = register_netdev(dev); ++ if (err) { ++ goto failed; ++ } ++ ++ __bnep_link_session(s); ++ ++ err = kernel_thread(bnep_session, s, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); ++ if (err < 0) { ++ /* Session thread start failed, gotta cleanup. */ ++ unregister_netdev(dev); ++ __bnep_unlink_session(s); ++ goto failed; ++ } ++ ++ up_write(&bnep_session_sem); ++ strcpy(req->device, dev->name); ++ return 0; ++ ++failed: ++ up_write(&bnep_session_sem); ++ kfree(s); ++ return err; ++} ++ ++int bnep_del_connection(struct bnep_conndel_req *req) ++{ ++ struct bnep_session *s; ++ int err = 0; ++ ++ BT_DBG(""); ++ ++ down_read(&bnep_session_sem); ++ ++ s = __bnep_get_session(req->dst); ++ if (s) { ++ /* Wakeup user-space which is polling for socket errors. ++ * This is temporary hack untill we have shutdown in L2CAP */ ++ s->sock->sk->err = EUNATCH; ++ ++ /* Kill session thread */ ++ atomic_inc(&s->killed); ++ wake_up_interruptible(s->sock->sk->sleep); ++ } else ++ err = -ENOENT; ++ ++ up_read(&bnep_session_sem); ++ return err; ++} ++ ++static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s) ++{ ++ memcpy(ci->dst, s->eh.h_source, ETH_ALEN); ++ strcpy(ci->device, s->dev.name); ++ ci->flags = s->flags; ++ ci->state = s->state; ++ ci->role = s->role; ++} ++ ++int bnep_get_connlist(struct bnep_connlist_req *req) ++{ ++ struct list_head *p; ++ int err = 0, n = 0; ++ ++ down_read(&bnep_session_sem); ++ ++ list_for_each(p, &bnep_session_list) { ++ struct bnep_session *s; ++ struct bnep_conninfo ci; ++ ++ s = list_entry(p, struct bnep_session, list); ++ ++ __bnep_copy_ci(&ci, s); ++ ++ if (copy_to_user(req->ci, &ci, sizeof(ci))) { ++ err = -EFAULT; ++ break; ++ } ++ ++ if (++n >= req->cnum) ++ break; ++ ++ req->ci++; ++ } ++ req->cnum = n; ++ ++ up_read(&bnep_session_sem); ++ return err; ++} ++ ++int bnep_get_conninfo(struct bnep_conninfo *ci) ++{ ++ struct bnep_session *s; ++ int err = 0; ++ ++ down_read(&bnep_session_sem); ++ ++ s = __bnep_get_session(ci->dst); ++ if (s) ++ __bnep_copy_ci(ci, s); ++ else ++ err = -ENOENT; ++ ++ up_read(&bnep_session_sem); ++ return err; ++} ++ ++static int __init bnep_init_module(void) ++{ ++ l2cap_load(); ++ ++ bnep_crc32_init(); ++ bnep_sock_init(); ++ ++ BT_INFO("BlueZ BNEP ver %s", VERSION); ++ BT_INFO("Copyright (C) 2001,2002 Inventel Systemes"); ++ BT_INFO("Written 2001,2002 by Clement Moreau <clement.moreau@inventel.fr>"); ++ BT_INFO("Written 2001,2002 by David Libault <david.libault@inventel.fr>"); ++ BT_INFO("Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>"); ++ ++ return 0; ++} ++ ++static void __exit bnep_cleanup_module(void) ++{ ++ bnep_sock_cleanup(); ++ bnep_crc32_cleanup(); ++} ++ ++module_init(bnep_init_module); ++module_exit(bnep_cleanup_module); ++ ++MODULE_DESCRIPTION("BlueZ BNEP ver " VERSION); ++MODULE_AUTHOR("David Libault <david.libault@inventel.fr>, Maxim Krasnyanskiy <maxk@qualcomm.com>"); ++MODULE_LICENSE("GPL"); +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/bnep/crc32.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,59 @@ ++/* ++ * Based on linux-2.5/lib/crc32 by Matt Domsch <Matt_Domsch@dell.com> ++ * ++ * FIXME: Remove in 2.5 ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <asm/atomic.h> ++ ++#include "crc32.h" ++ ++#define CRCPOLY_BE 0x04c11db7 ++#define CRC_BE_BITS 8 ++ ++static u32 *bnep_crc32_table; ++ ++/* ++ * This code is in the public domain; copyright abandoned. ++ * Liability for non-performance of this code is limited to the amount ++ * you paid for it. Since it is distributed for free, your refund will ++ * be very very small. If it breaks, you get to keep both pieces. ++ */ ++u32 bnep_crc32(u32 crc, unsigned char const *p, size_t len) ++{ ++ while (len--) ++ crc = (crc << 8) ^ bnep_crc32_table[(crc >> 24) ^ *p++]; ++ ++ return crc; ++} ++ ++int __init bnep_crc32_init(void) ++{ ++ unsigned i, j; ++ u32 crc = 0x80000000; ++ ++ bnep_crc32_table = kmalloc((1 << CRC_BE_BITS) * sizeof(u32), GFP_KERNEL); ++ if (!bnep_crc32_table) ++ return -ENOMEM; ++ ++ bnep_crc32_table[0] = 0; ++ ++ for (i = 1; i < 1 << CRC_BE_BITS; i <<= 1) { ++ crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0); ++ for (j = 0; j < i; j++) ++ bnep_crc32_table[i + j] = crc ^ bnep_crc32_table[j]; ++ } ++ return 0; ++} ++ ++void __exit bnep_crc32_cleanup(void) ++{ ++ if (bnep_crc32_table) ++ kfree(bnep_crc32_table); ++ bnep_crc32_table = NULL; ++} +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/bnep/crc32.h 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,10 @@ ++/* ++ * crc32.h ++ * See crc32.c for license and changes ++ * ++ * FIXME: Remove in 2.5 ++ */ ++ ++int bnep_crc32_init(void); ++void bnep_crc32_cleanup(void); ++u32 bnep_crc32(u32 crc, unsigned char const *p, size_t len); +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/bnep/Makefile 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,10 @@ ++# ++# Makefile for the Linux Bluetooth BNEP layer ++# ++ ++O_TARGET := bnep.o ++ ++obj-y := core.o sock.o netdev.o crc32.o ++obj-m += $(O_TARGET) ++ ++include $(TOPDIR)/Rules.make +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/bnep/netdev.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,254 @@ ++/* ++ BNEP implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2001-2002 Inventel Systemes ++ Written 2001-2002 by ++ Cl�ment Moreau <clement.moreau@inventel.fr> ++ David Libault <david.libault@inventel.fr> ++ ++ Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/socket.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> ++#include <linux/wait.h> ++ ++#include <asm/unaligned.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++#include <net/bluetooth/l2cap.h> ++ ++#include "bnep.h" ++ ++#ifndef CONFIG_BLUEZ_BNEP_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#endif ++ ++#define BNEP_TX_QUEUE_LEN 20 ++ ++static int bnep_net_open(struct net_device *dev) ++{ ++ netif_start_queue(dev); ++ return 0; ++} ++ ++static int bnep_net_close(struct net_device *dev) ++{ ++ netif_stop_queue(dev); ++ return 0; ++} ++ ++static struct net_device_stats *bnep_net_get_stats(struct net_device *dev) ++{ ++ struct bnep_session *s = dev->priv; ++ return &s->stats; ++} ++ ++static void bnep_net_set_mc_list(struct net_device *dev) ++{ ++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER ++ struct bnep_session *s = dev->priv; ++ struct sock *sk = s->sock->sk; ++ struct bnep_set_filter_req *r; ++ struct sk_buff *skb; ++ int size; ++ ++ BT_DBG("%s mc_count %d", dev->name, dev->mc_count); ++ ++ size = sizeof(*r) + (BNEP_MAX_MULTICAST_FILTERS + 1) * ETH_ALEN * 2; ++ skb = alloc_skb(size, GFP_ATOMIC); ++ if (!skb) { ++ BT_ERR("%s Multicast list allocation failed", dev->name); ++ return; ++ } ++ ++ r = (void *) skb->data; ++ __skb_put(skb, sizeof(*r)); ++ ++ r->type = BNEP_CONTROL; ++ r->ctrl = BNEP_FILTER_MULTI_ADDR_SET; ++ ++ if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) { ++ u8 start[ETH_ALEN] = { 0x01 }; ++ ++ /* Request all addresses */ ++ memcpy(__skb_put(skb, ETH_ALEN), start, ETH_ALEN); ++ memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN); ++ r->len = htons(ETH_ALEN * 2); ++ } else { ++ struct dev_mc_list *dmi = dev->mc_list; ++ int i, len = skb->len; ++ ++ if (dev->flags & IFF_BROADCAST) { ++ memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN); ++ memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN); ++ } ++ ++ /* FIXME: We should group addresses here. */ ++ ++ for (i = 0; i < dev->mc_count && i < BNEP_MAX_MULTICAST_FILTERS; i++) { ++ memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN); ++ memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN); ++ dmi = dmi->next; ++ } ++ r->len = htons(skb->len - len); ++ } ++ ++ skb_queue_tail(&sk->write_queue, skb); ++ wake_up_interruptible(sk->sleep); ++#endif ++} ++ ++static int bnep_net_set_mac_addr(struct net_device *dev, void *arg) ++{ ++ BT_DBG("%s", dev->name); ++ return 0; ++} ++ ++static void bnep_net_timeout(struct net_device *dev) ++{ ++ BT_DBG("net_timeout"); ++ netif_wake_queue(dev); ++} ++ ++static int bnep_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ++{ ++ return -EINVAL; ++} ++ ++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER ++static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s) ++{ ++ struct ethhdr *eh = (void *) skb->data; ++ ++ if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), &s->mc_filter)) { ++ BT_DBG("BNEP: filtered skb %p, dst %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", skb, ++ eh->h_dest[0], eh->h_dest[1], eh->h_dest[2], ++ eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]); ++ return 1; ++ } ++ return 0; ++} ++#endif ++ ++#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER ++/* Determine ether protocol. Based on eth_type_trans. */ ++static inline u16 bnep_net_eth_proto(struct sk_buff *skb) ++{ ++ struct ethhdr *eh = (void *) skb->data; ++ ++ if (ntohs(eh->h_proto) >= 1536) ++ return eh->h_proto; ++ ++ if (get_unaligned((u16 *) skb->data) == 0xFFFF) ++ return htons(ETH_P_802_3); ++ ++ return htons(ETH_P_802_2); ++} ++ ++static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s) ++{ ++ u16 proto = bnep_net_eth_proto(skb); ++ struct bnep_proto_filter *f = s->proto_filter; ++ int i; ++ ++ for (i = 0; i < BNEP_MAX_PROTO_FILTERS && f[i].end; i++) { ++ if (proto >= f[i].start && proto <= f[i].end) ++ return 0; ++ } ++ ++ BT_DBG("BNEP: filtered skb %p, proto 0x%.4x", skb, proto); ++ return 1; ++} ++#endif ++ ++static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct bnep_session *s = dev->priv; ++ struct sock *sk = s->sock->sk; ++ ++ BT_DBG("skb %p, dev %p", skb, dev); ++ ++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER ++ if (bnep_net_mc_filter(skb, s)) { ++ kfree_skb(skb); ++ return 0; ++ } ++#endif ++ ++#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER ++ if (bnep_net_proto_filter(skb, s)) { ++ kfree_skb(skb); ++ return 0; ++ } ++#endif ++ ++ /* ++ * We cannot send L2CAP packets from here as we are potentially in a bh. ++ * So we have to queue them and wake up session thread which is sleeping ++ * on the sk->sleep. ++ */ ++ dev->trans_start = jiffies; ++ skb_queue_tail(&sk->write_queue, skb); ++ wake_up_interruptible(sk->sleep); ++ ++ if (skb_queue_len(&sk->write_queue) >= BNEP_TX_QUEUE_LEN) { ++ BT_DBG("tx queue is full"); ++ ++ /* Stop queuing. ++ * Session thread will do netif_wake_queue() */ ++ netif_stop_queue(dev); ++ } ++ ++ return 0; ++} ++ ++int bnep_net_init(struct net_device *dev) ++{ ++ struct bnep_session *s = dev->priv; ++ ++ memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN); ++ dev->addr_len = ETH_ALEN; ++ ++ ether_setup(dev); ++ ++ dev->open = bnep_net_open; ++ dev->stop = bnep_net_close; ++ dev->hard_start_xmit = bnep_net_xmit; ++ dev->get_stats = bnep_net_get_stats; ++ dev->do_ioctl = bnep_net_ioctl; ++ dev->set_mac_address = bnep_net_set_mac_addr; ++ dev->set_multicast_list = bnep_net_set_mc_list; ++ ++ dev->watchdog_timeo = HZ * 2; ++ dev->tx_timeout = bnep_net_timeout; ++ ++ return 0; ++} +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/bnep/sock.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,238 @@ ++/* ++ BNEP implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2001-2002 Inventel Systemes ++ Written 2001-2002 by ++ David Libault <david.libault@inventel.fr> ++ ++ Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/skbuff.h> ++#include <linux/socket.h> ++#include <linux/ioctl.h> ++#include <linux/file.h> ++#include <net/sock.h> ++ ++#include <asm/system.h> ++#include <asm/uaccess.h> ++ ++#include "bnep.h" ++ ++#ifndef CONFIG_BLUEZ_BNEP_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#endif ++ ++static inline struct socket *socki_lookup(struct inode *inode) ++{ ++ return &inode->u.socket_i; ++} ++ ++static struct socket *sockfd_lookup(int fd, int *err) ++{ ++ struct file *file; ++ struct inode *inode; ++ struct socket *sock; ++ ++ if (!(file = fget(fd))) { ++ *err = -EBADF; ++ return NULL; ++ } ++ ++ inode = file->f_dentry->d_inode; ++ if (!inode->i_sock || !(sock = socki_lookup(inode))) { ++ *err = -ENOTSOCK; ++ fput(file); ++ return NULL; ++ } ++ ++ if (sock->file != file) { ++ printk(KERN_ERR "socki_lookup: socket file changed!\n"); ++ sock->file = file; ++ } ++ return sock; ++} ++ ++static int bnep_sock_release(struct socket *sock) ++{ ++ struct sock *sk = sock->sk; ++ ++ BT_DBG("sock %p sk %p", sock, sk); ++ ++ if (!sk) ++ return 0; ++ ++ sock_orphan(sk); ++ sock_put(sk); ++ ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ++{ ++ struct bnep_connlist_req cl; ++ struct bnep_connadd_req ca; ++ struct bnep_conndel_req cd; ++ struct bnep_conninfo ci; ++ struct socket *nsock; ++ int err; ++ ++ BT_DBG("cmd %x arg %lx", cmd, arg); ++ ++ switch (cmd) { ++ case BNEPCONNADD: ++ if (!capable(CAP_NET_ADMIN)) ++ return -EACCES; ++ ++ if (copy_from_user(&ca, (void *) arg, sizeof(ca))) ++ return -EFAULT; ++ ++ nsock = sockfd_lookup(ca.sock, &err); ++ if (!nsock) ++ return err; ++ ++ if (nsock->sk->state != BT_CONNECTED) ++ return -EBADFD; ++ ++ err = bnep_add_connection(&ca, nsock); ++ if (!err) { ++ if (copy_to_user((void *) arg, &ca, sizeof(ca))) ++ err = -EFAULT; ++ } else ++ fput(nsock->file); ++ ++ return err; ++ ++ case BNEPCONNDEL: ++ if (!capable(CAP_NET_ADMIN)) ++ return -EACCES; ++ ++ if (copy_from_user(&cd, (void *) arg, sizeof(cd))) ++ return -EFAULT; ++ ++ return bnep_del_connection(&cd); ++ ++ case BNEPGETCONNLIST: ++ if (copy_from_user(&cl, (void *) arg, sizeof(cl))) ++ return -EFAULT; ++ ++ if (cl.cnum <= 0) ++ return -EINVAL; ++ ++ err = bnep_get_connlist(&cl); ++ if (!err && copy_to_user((void *) arg, &cl, sizeof(cl))) ++ return -EFAULT; ++ ++ return err; ++ ++ case BNEPGETCONNINFO: ++ if (copy_from_user(&ci, (void *) arg, sizeof(ci))) ++ return -EFAULT; ++ ++ err = bnep_get_conninfo(&ci); ++ if (!err && copy_to_user((void *) arg, &ci, sizeof(ci))) ++ return -EFAULT; ++ ++ return err; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static struct proto_ops bnep_sock_ops = { ++ family: PF_BLUETOOTH, ++ release: bnep_sock_release, ++ ioctl: bnep_sock_ioctl, ++ bind: sock_no_bind, ++ getname: sock_no_getname, ++ sendmsg: sock_no_sendmsg, ++ recvmsg: sock_no_recvmsg, ++ poll: sock_no_poll, ++ listen: sock_no_listen, ++ shutdown: sock_no_shutdown, ++ setsockopt: sock_no_setsockopt, ++ getsockopt: sock_no_getsockopt, ++ connect: sock_no_connect, ++ socketpair: sock_no_socketpair, ++ accept: sock_no_accept, ++ mmap: sock_no_mmap ++}; ++ ++static int bnep_sock_create(struct socket *sock, int protocol) ++{ ++ struct sock *sk; ++ ++ BT_DBG("sock %p", sock); ++ ++ if (sock->type != SOCK_RAW) ++ return -ESOCKTNOSUPPORT; ++ ++ sock->ops = &bnep_sock_ops; ++ ++ if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1))) ++ return -ENOMEM; ++ ++ MOD_INC_USE_COUNT; ++ ++ sock->state = SS_UNCONNECTED; ++ sock_init_data(sock, sk); ++ ++ sk->destruct = NULL; ++ sk->protocol = protocol; ++ ++ return 0; ++} ++ ++static struct net_proto_family bnep_sock_family_ops = { ++ family: PF_BLUETOOTH, ++ create: bnep_sock_create ++}; ++ ++int bnep_sock_init(void) ++{ ++ bluez_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops); ++ return 0; ++} ++ ++int bnep_sock_cleanup(void) ++{ ++ if (bluez_sock_unregister(BTPROTO_BNEP)) ++ BT_ERR("Can't unregister BNEP socket"); ++ return 0; ++} +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/cmtp/capi.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,707 @@ ++/* ++ CMTP implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/skbuff.h> ++#include <linux/socket.h> ++#include <linux/ioctl.h> ++#include <linux/file.h> ++#include <net/sock.h> ++ ++#include <linux/capi.h> ++ ++#include "../drivers/isdn/avmb1/capilli.h" ++#include "../drivers/isdn/avmb1/capicmd.h" ++#include "../drivers/isdn/avmb1/capiutil.h" ++ ++#include "cmtp.h" ++ ++#ifndef CONFIG_BLUEZ_CMTP_DEBUG ++#undef BT_DBG ++#define BT_DBG(D...) ++#endif ++ ++#define REVISION "1.0" ++ ++#define CAPI_INTEROPERABILITY 0x20 ++ ++#define CAPI_INTEROPERABILITY_REQ CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ) ++#define CAPI_INTEROPERABILITY_CONF CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF) ++#define CAPI_INTEROPERABILITY_IND CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND) ++#define CAPI_INTEROPERABILITY_RESP CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP) ++ ++#define CAPI_INTEROPERABILITY_REQ_LEN (CAPI_MSG_BASELEN + 2) ++#define CAPI_INTEROPERABILITY_CONF_LEN (CAPI_MSG_BASELEN + 4) ++#define CAPI_INTEROPERABILITY_IND_LEN (CAPI_MSG_BASELEN + 2) ++#define CAPI_INTEROPERABILITY_RESP_LEN (CAPI_MSG_BASELEN + 2) ++ ++#define CAPI_FUNCTION_REGISTER 0 ++#define CAPI_FUNCTION_RELEASE 1 ++#define CAPI_FUNCTION_GET_PROFILE 2 ++#define CAPI_FUNCTION_GET_MANUFACTURER 3 ++#define CAPI_FUNCTION_GET_VERSION 4 ++#define CAPI_FUNCTION_GET_SERIAL_NUMBER 5 ++#define CAPI_FUNCTION_MANUFACTURER 6 ++#define CAPI_FUNCTION_LOOPBACK 7 ++ ++static struct capi_driver_interface *di; ++ ++ ++#define CMTP_MSGNUM 1 ++#define CMTP_APPLID 2 ++#define CMTP_MAPPING 3 ++ ++static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl) ++{ ++ struct cmtp_application *app = kmalloc(sizeof(*app), GFP_KERNEL); ++ ++ BT_DBG("session %p application %p appl %d", session, app, appl); ++ ++ if (!app) ++ return NULL; ++ ++ memset(app, 0, sizeof(*app)); ++ ++ app->state = BT_OPEN; ++ app->appl = appl; ++ ++ list_add_tail(&app->list, &session->applications); ++ ++ return app; ++} ++ ++static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app) ++{ ++ BT_DBG("session %p application %p", session, app); ++ ++ if (app) { ++ list_del(&app->list); ++ kfree(app); ++ } ++} ++ ++static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value) ++{ ++ struct cmtp_application *app; ++ struct list_head *p, *n; ++ ++ list_for_each_safe(p, n, &session->applications) { ++ app = list_entry(p, struct cmtp_application, list); ++ switch (pattern) { ++ case CMTP_MSGNUM: ++ if (app->msgnum == value) ++ return app; ++ break; ++ case CMTP_APPLID: ++ if (app->appl == value) ++ return app; ++ break; ++ case CMTP_MAPPING: ++ if (app->mapping == value) ++ return app; ++ break; ++ } ++ } ++ ++ return NULL; ++} ++ ++static int cmtp_msgnum_get(struct cmtp_session *session) ++{ ++ session->msgnum++; ++ ++ if ((session->msgnum & 0xff) > 200) ++ session->msgnum = CMTP_INITIAL_MSGNUM + 1; ++ ++ return session->msgnum; ++} ++ ++ ++static void cmtp_send_interopmsg(struct cmtp_session *session, ++ __u8 subcmd, __u16 appl, __u16 msgnum, ++ __u16 function, unsigned char *buf, int len) ++{ ++ struct sk_buff *skb; ++ unsigned char *s; ++ ++ BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum); ++ ++ if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) { ++ BT_ERR("Can't allocate memory for interoperability packet"); ++ return; ++ } ++ ++ s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len); ++ ++ capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len); ++ capimsg_setu16(s, 2, appl); ++ capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY); ++ capimsg_setu8 (s, 5, subcmd); ++ capimsg_setu16(s, 6, msgnum); ++ ++ /* Interoperability selector (Bluetooth Device Management) */ ++ capimsg_setu16(s, 8, 0x0001); ++ ++ capimsg_setu8 (s, 10, 3 + len); ++ capimsg_setu16(s, 11, function); ++ capimsg_setu8 (s, 13, len); ++ ++ if (len > 0) ++ memcpy(s + 14, buf, len); ++ ++ cmtp_send_capimsg(session, skb); ++} ++ ++static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb) ++{ ++ struct capi_ctr *ctrl = session->ctrl; ++ struct cmtp_application *application; ++ __u16 appl, msgnum, func, info; ++ __u32 controller; ++ ++ BT_DBG("session %p skb %p len %d", session, skb, skb->len); ++ ++ switch (CAPIMSG_SUBCOMMAND(skb->data)) { ++ case CAPI_CONF: ++ func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5); ++ info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8); ++ ++ switch (func) { ++ case CAPI_FUNCTION_REGISTER: ++ msgnum = CAPIMSG_MSGID(skb->data); ++ ++ application = cmtp_application_get(session, CMTP_MSGNUM, msgnum); ++ if (application) { ++ application->state = BT_CONNECTED; ++ application->msgnum = 0; ++ application->mapping = CAPIMSG_APPID(skb->data); ++ wake_up_interruptible(&session->wait); ++ } ++ ++ break; ++ ++ case CAPI_FUNCTION_RELEASE: ++ appl = CAPIMSG_APPID(skb->data); ++ ++ application = cmtp_application_get(session, CMTP_MAPPING, appl); ++ if (application) { ++ application->state = BT_CLOSED; ++ application->msgnum = 0; ++ wake_up_interruptible(&session->wait); ++ } ++ ++ break; ++ ++ case CAPI_FUNCTION_GET_PROFILE: ++ controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11); ++ msgnum = CAPIMSG_MSGID(skb->data); ++ ++ if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) { ++ session->ncontroller = controller; ++ wake_up_interruptible(&session->wait); ++ break; ++ } ++ ++ if (!info && ctrl) { ++ memcpy(&ctrl->profile, ++ skb->data + CAPI_MSG_BASELEN + 11, ++ sizeof(capi_profile)); ++ session->state = BT_CONNECTED; ++ ctrl->ready(ctrl); ++ } ++ ++ break; ++ ++ case CAPI_FUNCTION_GET_MANUFACTURER: ++ controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10); ++ ++ if (!info && ctrl) { ++ strncpy(ctrl->manu, ++ skb->data + CAPI_MSG_BASELEN + 15, ++ skb->data[CAPI_MSG_BASELEN + 14]); ++ } ++ ++ break; ++ ++ case CAPI_FUNCTION_GET_VERSION: ++ controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12); ++ ++ if (!info && ctrl) { ++ ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16); ++ ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20); ++ ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24); ++ ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28); ++ } ++ ++ break; ++ ++ case CAPI_FUNCTION_GET_SERIAL_NUMBER: ++ controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12); ++ ++ if (!info && ctrl) { ++ memset(ctrl->serial, 0, CAPI_SERIAL_LEN); ++ strncpy(ctrl->serial, ++ skb->data + CAPI_MSG_BASELEN + 17, ++ skb->data[CAPI_MSG_BASELEN + 16]); ++ } ++ ++ break; ++ } ++ ++ break; ++ ++ case CAPI_IND: ++ func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3); ++ ++ if (func == CAPI_FUNCTION_LOOPBACK) { ++ appl = CAPIMSG_APPID(skb->data); ++ msgnum = CAPIMSG_MSGID(skb->data); ++ cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func, ++ skb->data + CAPI_MSG_BASELEN + 6, ++ skb->data[CAPI_MSG_BASELEN + 5]); ++ } ++ ++ break; ++ } ++ ++ kfree_skb(skb); ++} ++ ++void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb) ++{ ++ struct capi_ctr *ctrl = session->ctrl; ++ struct cmtp_application *application; ++ __u16 cmd, appl, info; ++ __u32 ncci, contr; ++ ++ BT_DBG("session %p skb %p len %d", session, skb, skb->len); ++ ++ if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) { ++ cmtp_recv_interopmsg(session, skb); ++ return; ++ } ++ ++ if (session->flags & (1 << CMTP_LOOPBACK)) { ++ kfree_skb(skb); ++ return; ++ } ++ ++ cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data)); ++ appl = CAPIMSG_APPID(skb->data); ++ contr = CAPIMSG_CONTROL(skb->data); ++ ++ application = cmtp_application_get(session, CMTP_MAPPING, appl); ++ if (application) { ++ appl = application->appl; ++ CAPIMSG_SETAPPID(skb->data, appl); ++ } else { ++ BT_ERR("Can't find application with id %d", appl); ++ kfree_skb(skb); ++ return; ++ } ++ ++ if ((contr & 0x7f) == 0x01) { ++ contr = (contr & 0xffffff80) | session->num; ++ CAPIMSG_SETCONTROL(skb->data, contr); ++ } ++ ++ if (!ctrl) { ++ BT_ERR("Can't find controller %d for message", session->num); ++ kfree_skb(skb); ++ return; ++ } ++ ++ switch (cmd) { ++ case CAPI_CONNECT_B3_CONF: ++ ncci = CAPIMSG_NCCI(skb->data); ++ info = CAPIMSG_U16(skb->data, 12); ++ ++ BT_DBG("CONNECT_B3_CONF ncci 0x%02x info 0x%02x", ncci, info); ++ ++ if (info == 0) ++ ctrl->new_ncci(ctrl, appl, ncci, 8); ++ ++ ctrl->handle_capimsg(ctrl, appl, skb); ++ break; ++ ++ case CAPI_CONNECT_B3_IND: ++ ncci = CAPIMSG_NCCI(skb->data); ++ ++ BT_DBG("CONNECT_B3_IND ncci 0x%02x", ncci); ++ ++ ctrl->new_ncci(ctrl, appl, ncci, 8); ++ ctrl->handle_capimsg(ctrl, appl, skb); ++ break; ++ ++ case CAPI_DISCONNECT_B3_IND: ++ ncci = CAPIMSG_NCCI(skb->data); ++ ++ BT_DBG("DISCONNECT_B3_IND ncci 0x%02x", ncci); ++ ++ if (ncci == 0xffffffff) ++ BT_ERR("DISCONNECT_B3_IND with ncci 0xffffffff"); ++ ++ ctrl->handle_capimsg(ctrl, appl, skb); ++ ctrl->free_ncci(ctrl, appl, ncci); ++ break; ++ ++ default: ++ ctrl->handle_capimsg(ctrl, appl, skb); ++ break; ++ } ++} ++ ++void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb) ++{ ++ struct cmtp_scb *scb = (void *) skb->cb; ++ ++ BT_DBG("session %p skb %p len %d", session, skb, skb->len); ++ ++ scb->id = -1; ++ scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3); ++ ++ skb_queue_tail(&session->transmit, skb); ++ ++ cmtp_schedule(session); ++} ++ ++ ++static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) ++{ ++ BT_DBG("ctrl %p data %p", ctrl, data); ++ ++ return -EIO; ++} ++ ++static void cmtp_reset_ctr(struct capi_ctr *ctrl) ++{ ++ BT_DBG("ctrl %p", ctrl); ++ ++ ctrl->reseted(ctrl); ++} ++ ++static void cmtp_remove_ctr(struct capi_ctr *ctrl) ++{ ++ struct cmtp_session *session = ctrl->driverdata; ++ ++ BT_DBG("ctrl %p", ctrl); ++ ++ ctrl->suspend_output(ctrl); ++ ++ atomic_inc(&session->terminate); ++ cmtp_schedule(session); ++} ++ ++static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ struct cmtp_session *session = ctrl->driverdata; ++ struct cmtp_application *application; ++ unsigned long timeo = CMTP_INTEROP_TIMEOUT; ++ unsigned char buf[8]; ++ int err = 0, nconn, want = rp->level3cnt; ++ ++ BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d", ++ ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen); ++ ++ application = cmtp_application_add(session, appl); ++ if (!application) { ++ BT_ERR("Can't allocate memory for new application"); ++ ctrl->appl_released(ctrl, appl); ++ return; ++ } ++ ++ if (want < 0) ++ nconn = ctrl->profile.nbchannel * -want; ++ else ++ nconn = want; ++ ++ if (nconn == 0) ++ nconn = ctrl->profile.nbchannel; ++ ++ capimsg_setu16(buf, 0, nconn); ++ capimsg_setu16(buf, 2, rp->datablkcnt); ++ capimsg_setu16(buf, 4, rp->datablklen); ++ ++ application->state = BT_CONFIG; ++ application->msgnum = cmtp_msgnum_get(session); ++ ++ cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum, ++ CAPI_FUNCTION_REGISTER, buf, 6); ++ ++ add_wait_queue(&session->wait, &wait); ++ while (1) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ if (!timeo) { ++ err = -EAGAIN; ++ break; ++ } ++ ++ if (application->state == BT_CLOSED) { ++ err = -application->err; ++ break; ++ } ++ ++ if (application->state == BT_CONNECTED) ++ break; ++ ++ if (signal_pending(current)) { ++ err = -EINTR; ++ break; ++ } ++ ++ timeo = schedule_timeout(timeo); ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&session->wait, &wait); ++ ++ if (err) { ++ ctrl->appl_released(ctrl, appl); ++ cmtp_application_del(session, application); ++ return; ++ } ++ ++ ctrl->appl_registered(ctrl, appl); ++} ++ ++static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ struct cmtp_session *session = ctrl->driverdata; ++ struct cmtp_application *application; ++ unsigned long timeo = CMTP_INTEROP_TIMEOUT; ++ ++ BT_DBG("ctrl %p appl %d", ctrl, appl); ++ ++ application = cmtp_application_get(session, CMTP_APPLID, appl); ++ if (!application) { ++ BT_ERR("Can't find application"); ++ return; ++ } ++ ++ application->msgnum = cmtp_msgnum_get(session); ++ ++ cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum, ++ CAPI_FUNCTION_RELEASE, NULL, 0); ++ ++ add_wait_queue(&session->wait, &wait); ++ while (timeo) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ if (application->state == BT_CLOSED) ++ break; ++ ++ if (signal_pending(current)) ++ break; ++ ++ timeo = schedule_timeout(timeo); ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&session->wait, &wait); ++ ++ cmtp_application_del(session, application); ++ ctrl->appl_released(ctrl, appl); ++} ++ ++static void cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) ++{ ++ struct cmtp_session *session = ctrl->driverdata; ++ struct cmtp_application *application; ++ __u16 appl; ++ __u32 contr; ++ ++ BT_DBG("ctrl %p skb %p", ctrl, skb); ++ ++ appl = CAPIMSG_APPID(skb->data); ++ contr = CAPIMSG_CONTROL(skb->data); ++ ++ application = cmtp_application_get(session, CMTP_APPLID, appl); ++ if ((!application) || (application->state != BT_CONNECTED)) { ++ BT_ERR("Can't find application with id %d", appl); ++ kfree_skb(skb); ++ return; ++ } ++ ++ CAPIMSG_SETAPPID(skb->data, application->mapping); ++ ++ if ((contr & 0x7f) == session->num) { ++ contr = (contr & 0xffffff80) | 0x01; ++ CAPIMSG_SETCONTROL(skb->data, contr); ++ } ++ ++ cmtp_send_capimsg(session, skb); ++} ++ ++static char *cmtp_procinfo(struct capi_ctr *ctrl) ++{ ++ return "CAPI Message Transport Protocol"; ++} ++ ++static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl) ++{ ++ struct cmtp_session *session = ctrl->driverdata; ++ struct cmtp_application *app; ++ struct list_head *p, *n; ++ int len = 0; ++ ++ len += sprintf(page + len, "%s (Revision %s)\n\n", cmtp_procinfo(ctrl), REVISION); ++ len += sprintf(page + len, "addr %s\n", session->name); ++ len += sprintf(page + len, "ctrl %d\n", session->num); ++ ++ list_for_each_safe(p, n, &session->applications) { ++ app = list_entry(p, struct cmtp_application, list); ++ len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping); ++ } ++ ++ if (off + count >= len) ++ *eof = 1; ++ ++ if (len < off) ++ return 0; ++ ++ *start = page + off; ++ ++ return ((count < len - off) ? count : len - off); ++} ++ ++static struct capi_driver cmtp_driver = { ++ name: "cmtp", ++ revision: REVISION, ++ load_firmware: cmtp_load_firmware, ++ reset_ctr: cmtp_reset_ctr, ++ remove_ctr: cmtp_remove_ctr, ++ register_appl: cmtp_register_appl, ++ release_appl: cmtp_release_appl, ++ send_message: cmtp_send_message, ++ procinfo: cmtp_procinfo, ++ ctr_read_proc: cmtp_ctr_read_proc, ++ ++ driver_read_proc: 0, ++ add_card: 0, ++}; ++ ++ ++int cmtp_attach_device(struct cmtp_session *session) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long timeo = CMTP_INTEROP_TIMEOUT; ++ unsigned char buf[4]; ++ ++ BT_DBG("session %p", session); ++ ++ capimsg_setu32(buf, 0, 0); ++ ++ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM, ++ CAPI_FUNCTION_GET_PROFILE, buf, 4); ++ ++ add_wait_queue(&session->wait, &wait); ++ while (timeo) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ if (session->ncontroller) ++ break; ++ ++ if (signal_pending(current)) ++ break; ++ ++ timeo = schedule_timeout(timeo); ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&session->wait, &wait); ++ ++ BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name); ++ ++ if (!timeo) ++ return -ETIMEDOUT; ++ ++ if (!session->ncontroller) ++ return -ENODEV; ++ ++ ++ if (session->ncontroller > 1) ++ BT_INFO("Setting up only CAPI controller 1"); ++ ++ if (!(session->ctrl = di->attach_ctr(&cmtp_driver, session->name, session))) { ++ BT_ERR("Can't attach new controller"); ++ return -EBUSY; ++ } ++ ++ session->num = session->ctrl->cnr; ++ ++ BT_DBG("session %p ctrl %p num %d", session, session->ctrl, session->num); ++ ++ capimsg_setu32(buf, 0, 1); ++ ++ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), ++ CAPI_FUNCTION_GET_MANUFACTURER, buf, 4); ++ ++ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), ++ CAPI_FUNCTION_GET_VERSION, buf, 4); ++ ++ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), ++ CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4); ++ ++ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), ++ CAPI_FUNCTION_GET_PROFILE, buf, 4); ++ ++ return 0; ++} ++ ++void cmtp_detach_device(struct cmtp_session *session) ++{ ++ struct capi_ctr *ctrl = session->ctrl; ++ ++ BT_DBG("session %p ctrl %p", session, ctrl); ++ ++ if (!ctrl) ++ return; ++ ++ ctrl->reseted(ctrl); ++ ++ di->detach_ctr(ctrl); ++} ++ ++int cmtp_init_capi(void) ++{ ++ if (!(di = attach_capi_driver(&cmtp_driver))) { ++ BT_ERR("Can't attach CAPI driver"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++void cmtp_cleanup_capi(void) ++{ ++ detach_capi_driver(&cmtp_driver); ++} +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/cmtp/cmtp.h 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,138 @@ ++/* ++ CMTP implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++#ifndef __CMTP_H ++#define __CMTP_H ++ ++#include <linux/types.h> ++#include <net/bluetooth/bluetooth.h> ++ ++#define BTNAMSIZ 18 ++ ++/* CMTP ioctl defines */ ++#define CMTPCONNADD _IOW('C', 200, int) ++#define CMTPCONNDEL _IOW('C', 201, int) ++#define CMTPGETCONNLIST _IOR('C', 210, int) ++#define CMTPGETCONNINFO _IOR('C', 211, int) ++ ++#define CMTP_LOOPBACK 0 ++ ++struct cmtp_connadd_req { ++ int sock; // Connected socket ++ __u32 flags; ++}; ++ ++struct cmtp_conndel_req { ++ bdaddr_t bdaddr; ++ __u32 flags; ++}; ++ ++struct cmtp_conninfo { ++ bdaddr_t bdaddr; ++ __u32 flags; ++ __u16 state; ++ int num; ++}; ++ ++struct cmtp_connlist_req { ++ __u32 cnum; ++ struct cmtp_conninfo *ci; ++}; ++ ++int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock); ++int cmtp_del_connection(struct cmtp_conndel_req *req); ++int cmtp_get_connlist(struct cmtp_connlist_req *req); ++int cmtp_get_conninfo(struct cmtp_conninfo *ci); ++ ++/* CMTP session defines */ ++#define CMTP_INTEROP_TIMEOUT (HZ * 5) ++#define CMTP_INITIAL_MSGNUM 0xff00 ++ ++struct cmtp_session { ++ struct list_head list; ++ ++ struct socket *sock; ++ ++ bdaddr_t bdaddr; ++ ++ unsigned long state; ++ unsigned long flags; ++ ++ uint mtu; ++ ++ char name[BTNAMSIZ]; ++ ++ atomic_t terminate; ++ ++ wait_queue_head_t wait; ++ ++ int ncontroller; ++ int num; ++ struct capi_ctr *ctrl; ++ ++ struct list_head applications; ++ ++ unsigned long blockids; ++ int msgnum; ++ ++ struct sk_buff_head transmit; ++ ++ struct sk_buff *reassembly[16]; ++}; ++ ++struct cmtp_application { ++ struct list_head list; ++ ++ unsigned long state; ++ int err; ++ ++ __u16 appl; ++ __u16 mapping; ++ ++ __u16 msgnum; ++}; ++ ++struct cmtp_scb { ++ int id; ++ int data; ++}; ++ ++int cmtp_attach_device(struct cmtp_session *session); ++void cmtp_detach_device(struct cmtp_session *session); ++ ++void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb); ++void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb); ++ ++static inline void cmtp_schedule(struct cmtp_session *session) ++{ ++ struct sock *sk = session->sock->sk; ++ ++ wake_up_interruptible(sk->sleep); ++} ++ ++/* CMTP init defines */ ++int cmtp_init_capi(void); ++int cmtp_init_sockets(void); ++void cmtp_cleanup_capi(void); ++void cmtp_cleanup_sockets(void); ++ ++#endif /* __CMTP_H */ +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/cmtp/Config.in 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,7 @@ ++# ++# Bluetooth CMTP layer configuration ++# ++ ++if [ "$CONFIG_ISDN" = "y" -o "$CONFIG_ISDN" = "m" ]; then ++ dep_tristate 'CMTP protocol support' CONFIG_BLUEZ_CMTP $CONFIG_ISDN_CAPI $CONFIG_BLUEZ_L2CAP ++fi +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/cmtp/core.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,515 @@ ++/* ++ CMTP implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/skbuff.h> ++#include <linux/socket.h> ++#include <linux/ioctl.h> ++#include <linux/file.h> ++#include <linux/init.h> ++#include <net/sock.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/l2cap.h> ++ ++#include "cmtp.h" ++ ++#ifndef CONFIG_BLUEZ_CMTP_DEBUG ++#undef BT_DBG ++#define BT_DBG(D...) ++#endif ++ ++#define VERSION "1.0" ++ ++static DECLARE_RWSEM(cmtp_session_sem); ++static LIST_HEAD(cmtp_session_list); ++ ++static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr) ++{ ++ struct cmtp_session *session; ++ struct list_head *p; ++ ++ BT_DBG(""); ++ ++ list_for_each(p, &cmtp_session_list) { ++ session = list_entry(p, struct cmtp_session, list); ++ if (!bacmp(bdaddr, &session->bdaddr)) ++ return session; ++ } ++ return NULL; ++} ++ ++static void __cmtp_link_session(struct cmtp_session *session) ++{ ++ MOD_INC_USE_COUNT; ++ list_add(&session->list, &cmtp_session_list); ++} ++ ++static void __cmtp_unlink_session(struct cmtp_session *session) ++{ ++ list_del(&session->list); ++ MOD_DEC_USE_COUNT; ++} ++ ++static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci) ++{ ++ bacpy(&ci->bdaddr, &session->bdaddr); ++ ++ ci->flags = session->flags; ++ ci->state = session->state; ++ ++ ci->num = session->num; ++} ++ ++ ++static inline int cmtp_alloc_block_id(struct cmtp_session *session) ++{ ++ int i, id = -1; ++ ++ for (i = 0; i < 16; i++) ++ if (!test_and_set_bit(i, &session->blockids)) { ++ id = i; ++ break; ++ } ++ ++ return id; ++} ++ ++static inline void cmtp_free_block_id(struct cmtp_session *session, int id) ++{ ++ clear_bit(id, &session->blockids); ++} ++ ++static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const unsigned char *buf, int count) ++{ ++ struct sk_buff *skb = session->reassembly[id], *nskb; ++ int size; ++ ++ BT_DBG("session %p buf %p count %d", session, buf, count); ++ ++ size = (skb) ? skb->len + count : count; ++ ++ if (!(nskb = alloc_skb(size, GFP_ATOMIC))) { ++ BT_ERR("Can't allocate memory for CAPI message"); ++ return; ++ } ++ ++ if (skb && (skb->len > 0)) ++ memcpy(skb_put(nskb, skb->len), skb->data, skb->len); ++ ++ memcpy(skb_put(nskb, count), buf, count); ++ ++ session->reassembly[id] = nskb; ++ ++ if (skb) ++ kfree_skb(skb); ++} ++ ++static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb) ++{ ++ __u8 hdr, hdrlen, id; ++ __u16 len; ++ ++ BT_DBG("session %p skb %p len %d", session, skb, skb->len); ++ ++ while (skb->len > 0) { ++ hdr = skb->data[0]; ++ ++ switch (hdr & 0xc0) { ++ case 0x40: ++ hdrlen = 2; ++ len = skb->data[1]; ++ break; ++ case 0x80: ++ hdrlen = 3; ++ len = skb->data[1] | (skb->data[2] << 8); ++ break; ++ default: ++ hdrlen = 1; ++ len = 0; ++ break; ++ } ++ ++ id = (hdr & 0x3c) >> 2; ++ ++ BT_DBG("hdr 0x%02x hdrlen %d len %d id %d", hdr, hdrlen, len, id); ++ ++ if (hdrlen + len > skb->len) { ++ BT_ERR("Wrong size or header information in CMTP frame"); ++ break; ++ } ++ ++ if (len == 0) { ++ skb_pull(skb, hdrlen); ++ continue; ++ } ++ ++ switch (hdr & 0x03) { ++ case 0x00: ++ cmtp_add_msgpart(session, id, skb->data + hdrlen, len); ++ cmtp_recv_capimsg(session, session->reassembly[id]); ++ session->reassembly[id] = NULL; ++ break; ++ case 0x01: ++ cmtp_add_msgpart(session, id, skb->data + hdrlen, len); ++ break; ++ default: ++ if (session->reassembly[id] != NULL) ++ kfree_skb(session->reassembly[id]); ++ session->reassembly[id] = NULL; ++ break; ++ } ++ ++ skb_pull(skb, hdrlen + len); ++ } ++ ++ kfree_skb(skb); ++ return 0; ++} ++ ++static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, int len) ++{ ++ struct socket *sock = session->sock; ++ struct iovec iv = { data, len }; ++ struct msghdr msg; ++ int err; ++ ++ BT_DBG("session %p data %p len %d", session, data, len); ++ ++ if (!len) ++ return 0; ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.msg_iovlen = 1; ++ msg.msg_iov = &iv; ++ ++ err = sock->ops->sendmsg(sock, &msg, len, 0); ++ return err; ++} ++ ++static int cmtp_process_transmit(struct cmtp_session *session) ++{ ++ struct sk_buff *skb, *nskb; ++ unsigned char *hdr; ++ unsigned int size, tail; ++ ++ BT_DBG("session %p", session); ++ ++ if (!(nskb = alloc_skb(session->mtu, GFP_ATOMIC))) { ++ BT_ERR("Can't allocate memory for new frame"); ++ return -ENOMEM; ++ } ++ ++ while ((skb = skb_dequeue(&session->transmit))) { ++ struct cmtp_scb *scb = (void *) skb->cb; ++ ++ if ((tail = (session->mtu - nskb->len)) < 5) { ++ cmtp_send_frame(session, nskb->data, nskb->len); ++ skb_trim(nskb, 0); ++ tail = session->mtu; ++ } ++ ++ size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len); ++ ++ if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) { ++ skb_queue_head(&session->transmit, skb); ++ break; ++ } ++ ++ if (size < 256) { ++ hdr = skb_put(nskb, 2); ++ hdr[0] = 0x40 ++ | ((scb->id << 2) & 0x3c) ++ | ((skb->len == size) ? 0x00 : 0x01); ++ hdr[1] = size; ++ } else { ++ hdr = skb_put(nskb, 3); ++ hdr[0] = 0x80 ++ | ((scb->id << 2) & 0x3c) ++ | ((skb->len == size) ? 0x00 : 0x01); ++ hdr[1] = size & 0xff; ++ hdr[2] = size >> 8; ++ } ++ ++ memcpy(skb_put(nskb, size), skb->data, size); ++ skb_pull(skb, size); ++ ++ if (skb->len > 0) { ++ skb_queue_head(&session->transmit, skb); ++ } else { ++ cmtp_free_block_id(session, scb->id); ++ if (scb->data) { ++ cmtp_send_frame(session, nskb->data, nskb->len); ++ skb_trim(nskb, 0); ++ } ++ kfree_skb(skb); ++ } ++ } ++ ++ cmtp_send_frame(session, nskb->data, nskb->len); ++ ++ kfree_skb(nskb); ++ ++ return skb_queue_len(&session->transmit); ++} ++ ++static int cmtp_session(void *arg) ++{ ++ struct cmtp_session *session = arg; ++ struct sock *sk = session->sock->sk; ++ struct sk_buff *skb; ++ wait_queue_t wait; ++ ++ BT_DBG("session %p", session); ++ ++ daemonize(); reparent_to_init(); ++ ++ sprintf(current->comm, "kcmtpd_ctr_%d", session->num); ++ ++ sigfillset(¤t->blocked); ++ flush_signals(current); ++ ++ current->nice = -15; ++ ++ set_fs(KERNEL_DS); ++ ++ init_waitqueue_entry(&wait, current); ++ add_wait_queue(sk->sleep, &wait); ++ while (!atomic_read(&session->terminate)) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ if (sk->state != BT_CONNECTED) ++ break; ++ ++ while ((skb = skb_dequeue(&sk->receive_queue))) { ++ skb_orphan(skb); ++ cmtp_recv_frame(session, skb); ++ } ++ ++ cmtp_process_transmit(session); ++ ++ schedule(); ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(sk->sleep, &wait); ++ ++ down_write(&cmtp_session_sem); ++ ++ if (!(session->flags & (1 << CMTP_LOOPBACK))) ++ cmtp_detach_device(session); ++ ++ fput(session->sock->file); ++ ++ __cmtp_unlink_session(session); ++ ++ up_write(&cmtp_session_sem); ++ ++ kfree(session); ++ return 0; ++} ++ ++int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) ++{ ++ struct cmtp_session *session, *s; ++ bdaddr_t src, dst; ++ int i, err; ++ ++ BT_DBG(""); ++ ++ baswap(&src, &bluez_pi(sock->sk)->src); ++ baswap(&dst, &bluez_pi(sock->sk)->dst); ++ ++ session = kmalloc(sizeof(struct cmtp_session), GFP_KERNEL); ++ if (!session) ++ return -ENOMEM; ++ memset(session, 0, sizeof(struct cmtp_session)); ++ ++ down_write(&cmtp_session_sem); ++ ++ s = __cmtp_get_session(&bluez_pi(sock->sk)->dst); ++ if (s && s->state == BT_CONNECTED) { ++ err = -EEXIST; ++ goto failed; ++ } ++ ++ bacpy(&session->bdaddr, &bluez_pi(sock->sk)->dst); ++ ++ session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu); ++ ++ BT_DBG("mtu %d", session->mtu); ++ ++ sprintf(session->name, "%s", batostr(&dst)); ++ ++ session->sock = sock; ++ session->state = BT_CONFIG; ++ ++ init_waitqueue_head(&session->wait); ++ ++ session->ctrl = NULL; ++ session->msgnum = CMTP_INITIAL_MSGNUM; ++ ++ INIT_LIST_HEAD(&session->applications); ++ ++ skb_queue_head_init(&session->transmit); ++ ++ for (i = 0; i < 16; i++) ++ session->reassembly[i] = NULL; ++ ++ session->flags = req->flags; ++ ++ __cmtp_link_session(session); ++ ++ err = kernel_thread(cmtp_session, session, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); ++ if (err < 0) ++ goto unlink; ++ ++ if (!(session->flags & (1 << CMTP_LOOPBACK))) { ++ err = cmtp_attach_device(session); ++ if (err < 0) ++ goto detach; ++ } ++ ++ up_write(&cmtp_session_sem); ++ return 0; ++ ++detach: ++ cmtp_detach_device(session); ++ ++unlink: ++ __cmtp_unlink_session(session); ++ ++failed: ++ up_write(&cmtp_session_sem); ++ kfree(session); ++ return err; ++} ++ ++int cmtp_del_connection(struct cmtp_conndel_req *req) ++{ ++ struct cmtp_session *session; ++ int err = 0; ++ ++ BT_DBG(""); ++ ++ down_read(&cmtp_session_sem); ++ ++ session = __cmtp_get_session(&req->bdaddr); ++ if (session) { ++ /* Flush the transmit queue */ ++ skb_queue_purge(&session->transmit); ++ ++ /* Kill session thread */ ++ atomic_inc(&session->terminate); ++ cmtp_schedule(session); ++ } else ++ err = -ENOENT; ++ ++ up_read(&cmtp_session_sem); ++ return err; ++} ++ ++int cmtp_get_connlist(struct cmtp_connlist_req *req) ++{ ++ struct list_head *p; ++ int err = 0, n = 0; ++ ++ BT_DBG(""); ++ ++ down_read(&cmtp_session_sem); ++ ++ list_for_each(p, &cmtp_session_list) { ++ struct cmtp_session *session; ++ struct cmtp_conninfo ci; ++ ++ session = list_entry(p, struct cmtp_session, list); ++ ++ __cmtp_copy_session(session, &ci); ++ ++ if (copy_to_user(req->ci, &ci, sizeof(ci))) { ++ err = -EFAULT; ++ break; ++ } ++ ++ if (++n >= req->cnum) ++ break; ++ ++ req->ci++; ++ } ++ req->cnum = n; ++ ++ up_read(&cmtp_session_sem); ++ return err; ++} ++ ++int cmtp_get_conninfo(struct cmtp_conninfo *ci) ++{ ++ struct cmtp_session *session; ++ int err = 0; ++ ++ down_read(&cmtp_session_sem); ++ ++ session = __cmtp_get_session(&ci->bdaddr); ++ if (session) ++ __cmtp_copy_session(session, ci); ++ else ++ err = -ENOENT; ++ ++ up_read(&cmtp_session_sem); ++ return err; ++} ++ ++ ++int __init init_cmtp(void) ++{ ++ l2cap_load(); ++ ++ cmtp_init_capi(); ++ cmtp_init_sockets(); ++ ++ BT_INFO("BlueZ CMTP ver %s", VERSION); ++ BT_INFO("Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>"); ++ ++ return 0; ++} ++ ++void __exit exit_cmtp(void) ++{ ++ cmtp_cleanup_sockets(); ++ cmtp_cleanup_capi(); ++} ++ ++module_init(init_cmtp); ++module_exit(exit_cmtp); ++ ++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); ++MODULE_DESCRIPTION("BlueZ CMTP ver " VERSION); ++MODULE_LICENSE("GPL"); +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/cmtp/Makefile 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,10 @@ ++# ++# Makefile for the Linux Bluetooth CMTP layer ++# ++ ++O_TARGET := cmtp.o ++ ++obj-y := core.o sock.o capi.o ++obj-m += $(O_TARGET) ++ ++include $(TOPDIR)/Rules.make +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/cmtp/sock.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,236 @@ ++/* ++ CMTP implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/skbuff.h> ++#include <linux/socket.h> ++#include <linux/ioctl.h> ++#include <linux/file.h> ++#include <net/sock.h> ++ ++#include <asm/system.h> ++#include <asm/uaccess.h> ++ ++#include "cmtp.h" ++ ++#ifndef CONFIG_BLUEZ_CMTP_DEBUG ++#undef BT_DBG ++#define BT_DBG(D...) ++#endif ++ ++static inline struct socket *socki_lookup(struct inode *inode) ++{ ++ return &inode->u.socket_i; ++} ++ ++static struct socket *sockfd_lookup(int fd, int *err) ++{ ++ struct file *file; ++ struct inode *inode; ++ struct socket *sock; ++ ++ if (!(file = fget(fd))) { ++ *err = -EBADF; ++ return NULL; ++ } ++ ++ inode = file->f_dentry->d_inode; ++ if (!inode->i_sock || !(sock = socki_lookup(inode))) { ++ *err = -ENOTSOCK; ++ fput(file); ++ return NULL; ++ } ++ ++ if (sock->file != file) { ++ printk(KERN_ERR "socki_lookup: socket file changed!\n"); ++ sock->file = file; ++ } ++ return sock; ++} ++ ++static int cmtp_sock_release(struct socket *sock) ++{ ++ struct sock *sk = sock->sk; ++ ++ BT_DBG("sock %p sk %p", sock, sk); ++ ++ if (!sk) ++ return 0; ++ ++ sock_orphan(sk); ++ sock_put(sk); ++ ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ++{ ++ struct cmtp_connadd_req ca; ++ struct cmtp_conndel_req cd; ++ struct cmtp_connlist_req cl; ++ struct cmtp_conninfo ci; ++ struct socket *nsock; ++ int err; ++ ++ BT_DBG("cmd %x arg %lx", cmd, arg); ++ ++ switch (cmd) { ++ case CMTPCONNADD: ++ if (!capable(CAP_NET_ADMIN)) ++ return -EACCES; ++ ++ if (copy_from_user(&ca, (void *) arg, sizeof(ca))) ++ return -EFAULT; ++ ++ nsock = sockfd_lookup(ca.sock, &err); ++ if (!nsock) ++ return err; ++ ++ if (nsock->sk->state != BT_CONNECTED) ++ return -EBADFD; ++ ++ err = cmtp_add_connection(&ca, nsock); ++ if (!err) { ++ if (copy_to_user((void *) arg, &ca, sizeof(ca))) ++ err = -EFAULT; ++ } else ++ fput(nsock->file); ++ ++ return err; ++ ++ case CMTPCONNDEL: ++ if (!capable(CAP_NET_ADMIN)) ++ return -EACCES; ++ ++ if (copy_from_user(&cd, (void *) arg, sizeof(cd))) ++ return -EFAULT; ++ ++ return cmtp_del_connection(&cd); ++ ++ case CMTPGETCONNLIST: ++ if (copy_from_user(&cl, (void *) arg, sizeof(cl))) ++ return -EFAULT; ++ ++ if (cl.cnum <= 0) ++ return -EINVAL; ++ ++ err = cmtp_get_connlist(&cl); ++ if (!err && copy_to_user((void *) arg, &cl, sizeof(cl))) ++ return -EFAULT; ++ ++ return err; ++ ++ case CMTPGETCONNINFO: ++ if (copy_from_user(&ci, (void *) arg, sizeof(ci))) ++ return -EFAULT; ++ ++ err = cmtp_get_conninfo(&ci); ++ if (!err && copy_to_user((void *) arg, &ci, sizeof(ci))) ++ return -EFAULT; ++ ++ return err; ++ } ++ ++ return -EINVAL; ++} ++ ++static struct proto_ops cmtp_sock_ops = { ++ family: PF_BLUETOOTH, ++ release: cmtp_sock_release, ++ ioctl: cmtp_sock_ioctl, ++ bind: sock_no_bind, ++ getname: sock_no_getname, ++ sendmsg: sock_no_sendmsg, ++ recvmsg: sock_no_recvmsg, ++ poll: sock_no_poll, ++ listen: sock_no_listen, ++ shutdown: sock_no_shutdown, ++ setsockopt: sock_no_setsockopt, ++ getsockopt: sock_no_getsockopt, ++ connect: sock_no_connect, ++ socketpair: sock_no_socketpair, ++ accept: sock_no_accept, ++ mmap: sock_no_mmap ++}; ++ ++static int cmtp_sock_create(struct socket *sock, int protocol) ++{ ++ struct sock *sk; ++ ++ BT_DBG("sock %p", sock); ++ ++ if (sock->type != SOCK_RAW) ++ return -ESOCKTNOSUPPORT; ++ ++ sock->ops = &cmtp_sock_ops; ++ ++ if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1))) ++ return -ENOMEM; ++ ++ MOD_INC_USE_COUNT; ++ ++ sock->state = SS_UNCONNECTED; ++ sock_init_data(sock, sk); ++ ++ sk->destruct = NULL; ++ sk->protocol = protocol; ++ ++ return 0; ++} ++ ++static struct net_proto_family cmtp_sock_family_ops = { ++ family: PF_BLUETOOTH, ++ create: cmtp_sock_create ++}; ++ ++int cmtp_init_sockets(void) ++{ ++ int err; ++ ++ if ((err = bluez_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops))) { ++ BT_ERR("Can't register CMTP socket layer (%d)", err); ++ return err; ++ } ++ ++ return 0; ++} ++ ++void cmtp_cleanup_sockets(void) ++{ ++ int err; ++ ++ if ((err = bluez_sock_unregister(BTPROTO_CMTP))) ++ BT_ERR("Can't unregister CMTP socket layer (%d)", err); ++ ++ return; ++} +--- linux/net/bluetooth/Config.in~bluetooth-2.4.18-mh11 2001-06-12 04:15:27.000000000 +0200 ++++ linux/net/bluetooth/Config.in 2004-01-25 23:37:39.000000000 +0100 +@@ -1,16 +1,22 @@ + # +-# Bluetooth configuration ++# Bluetooth subsystem configuration + # + + if [ "$CONFIG_NET" != "n" ]; then ++ + mainmenu_option next_comment + comment 'Bluetooth support' + dep_tristate 'Bluetooth subsystem support' CONFIG_BLUEZ $CONFIG_NET + + if [ "$CONFIG_BLUEZ" != "n" ]; then + dep_tristate 'L2CAP protocol support' CONFIG_BLUEZ_L2CAP $CONFIG_BLUEZ ++ dep_tristate 'SCO links support' CONFIG_BLUEZ_SCO $CONFIG_BLUEZ ++ source net/bluetooth/rfcomm/Config.in ++ source net/bluetooth/bnep/Config.in ++ source net/bluetooth/cmtp/Config.in + source drivers/bluetooth/Config.in + fi ++ + endmenu + fi + +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/hci_conn.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,435 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * HCI Connection handling. ++ * ++ * $Id$ ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/init.h> ++#include <linux/skbuff.h> ++#include <linux/interrupt.h> ++#include <linux/notifier.h> ++#include <net/sock.h> ++ ++#include <asm/system.h> ++#include <asm/uaccess.h> ++#include <asm/unaligned.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++ ++#ifndef HCI_CORE_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#endif ++ ++void hci_acl_connect(struct hci_conn *conn) ++{ ++ struct hci_dev *hdev = conn->hdev; ++ struct inquiry_entry *ie; ++ create_conn_cp cp; ++ ++ BT_DBG("%p", conn); ++ ++ conn->state = BT_CONNECT; ++ conn->out = 1; ++ conn->link_mode = HCI_LM_MASTER; ++ ++ memset(&cp, 0, sizeof(cp)); ++ bacpy(&cp.bdaddr, &conn->dst); ++ cp.pscan_rep_mode = 0x02; ++ ++ if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) && ++ inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { ++ cp.pscan_rep_mode = ie->info.pscan_rep_mode; ++ cp.pscan_mode = ie->info.pscan_mode; ++ cp.clock_offset = ie->info.clock_offset | __cpu_to_le16(0x8000); ++ } ++ ++ cp.pkt_type = __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK); ++ if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER)) ++ cp.role_switch = 0x01; ++ else ++ cp.role_switch = 0x00; ++ ++ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, ++ CREATE_CONN_CP_SIZE, &cp); ++} ++ ++void hci_acl_disconn(struct hci_conn *conn, __u8 reason) ++{ ++ disconnect_cp cp; ++ ++ BT_DBG("%p", conn); ++ ++ conn->state = BT_DISCONN; ++ ++ cp.handle = __cpu_to_le16(conn->handle); ++ cp.reason = reason; ++ hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT, ++ DISCONNECT_CP_SIZE, &cp); ++} ++ ++void hci_add_sco(struct hci_conn *conn, __u16 handle) ++{ ++ struct hci_dev *hdev = conn->hdev; ++ add_sco_cp cp; ++ ++ BT_DBG("%p", conn); ++ ++ conn->state = BT_CONNECT; ++ conn->out = 1; ++ ++ cp.pkt_type = __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); ++ cp.handle = __cpu_to_le16(handle); ++ ++ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, ADD_SCO_CP_SIZE, &cp); ++} ++ ++static void hci_conn_timeout(unsigned long arg) ++{ ++ struct hci_conn *conn = (void *)arg; ++ struct hci_dev *hdev = conn->hdev; ++ ++ BT_DBG("conn %p state %d", conn, conn->state); ++ ++ if (atomic_read(&conn->refcnt)) ++ return; ++ ++ hci_dev_lock(hdev); ++ if (conn->state == BT_CONNECTED) ++ hci_acl_disconn(conn, 0x13); ++ else ++ conn->state = BT_CLOSED; ++ hci_dev_unlock(hdev); ++ return; ++} ++ ++static void hci_conn_init_timer(struct hci_conn *conn) ++{ ++ init_timer(&conn->timer); ++ conn->timer.function = hci_conn_timeout; ++ conn->timer.data = (unsigned long)conn; ++} ++ ++struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) ++{ ++ struct hci_conn *conn; ++ ++ BT_DBG("%s dst %s", hdev->name, batostr(dst)); ++ ++ if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC))) ++ return NULL; ++ memset(conn, 0, sizeof(struct hci_conn)); ++ ++ bacpy(&conn->dst, dst); ++ conn->type = type; ++ conn->hdev = hdev; ++ conn->state = BT_OPEN; ++ ++ skb_queue_head_init(&conn->data_q); ++ hci_conn_init_timer(conn); ++ ++ atomic_set(&conn->refcnt, 0); ++ ++ hci_dev_hold(hdev); ++ ++ tasklet_disable(&hdev->tx_task); ++ conn_hash_add(hdev, conn); ++ tasklet_enable(&hdev->tx_task); ++ ++ return conn; ++} ++ ++int hci_conn_del(struct hci_conn *conn) ++{ ++ struct hci_dev *hdev = conn->hdev; ++ ++ BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle); ++ ++ hci_conn_del_timer(conn); ++ ++ if (conn->type == SCO_LINK) { ++ struct hci_conn *acl = conn->link; ++ if (acl) { ++ acl->link = NULL; ++ hci_conn_put(acl); ++ } ++ } else { ++ struct hci_conn *sco = conn->link; ++ if (sco) ++ sco->link = NULL; ++ ++ /* Unacked frames */ ++ hdev->acl_cnt += conn->sent; ++ } ++ ++ tasklet_disable(&hdev->tx_task); ++ conn_hash_del(hdev, conn); ++ tasklet_enable(&hdev->tx_task); ++ ++ skb_queue_purge(&conn->data_q); ++ ++ hci_dev_put(hdev); ++ ++ kfree(conn); ++ return 0; ++} ++ ++struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) ++{ ++ int use_src = bacmp(src, BDADDR_ANY); ++ struct hci_dev *hdev = NULL; ++ struct list_head *p; ++ ++ BT_DBG("%s -> %s", batostr(src), batostr(dst)); ++ ++ read_lock_bh(&hdev_list_lock); ++ ++ list_for_each(p, &hdev_list) { ++ struct hci_dev *d; ++ d = list_entry(p, struct hci_dev, list); ++ ++ if (!test_bit(HCI_UP, &d->flags)) ++ continue; ++ ++ /* Simple routing: ++ * No source address - find interface with bdaddr != dst ++ * Source address - find interface with bdaddr == src ++ */ ++ ++ if (use_src) { ++ if (!bacmp(&d->bdaddr, src)) { ++ hdev = d; break; ++ } ++ } else { ++ if (bacmp(&d->bdaddr, dst)) { ++ hdev = d; break; ++ } ++ } ++ } ++ ++ if (hdev) ++ hci_dev_hold(hdev); ++ ++ read_unlock_bh(&hdev_list_lock); ++ return hdev; ++} ++ ++/* Create SCO or ACL connection. ++ * Device _must_ be locked */ ++struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst) ++{ ++ struct hci_conn *acl; ++ ++ BT_DBG("%s dst %s", hdev->name, batostr(dst)); ++ ++ if (!(acl = conn_hash_lookup_ba(hdev, ACL_LINK, dst))) { ++ if (!(acl = hci_conn_add(hdev, ACL_LINK, dst))) ++ return NULL; ++ } ++ ++ hci_conn_hold(acl); ++ ++ if (acl->state == BT_OPEN || acl->state == BT_CLOSED) ++ hci_acl_connect(acl); ++ ++ if (type == SCO_LINK) { ++ struct hci_conn *sco; ++ ++ if (!(sco = conn_hash_lookup_ba(hdev, SCO_LINK, dst))) { ++ if (!(sco = hci_conn_add(hdev, SCO_LINK, dst))) { ++ hci_conn_put(acl); ++ return NULL; ++ } ++ } ++ acl->link = sco; ++ sco->link = acl; ++ ++ hci_conn_hold(sco); ++ ++ if (acl->state == BT_CONNECTED && ++ (sco->state == BT_OPEN || sco->state == BT_CLOSED)) ++ hci_add_sco(sco, acl->handle); ++ ++ return sco; ++ } else { ++ return acl; ++ } ++} ++ ++/* Authenticate remote device */ ++int hci_conn_auth(struct hci_conn *conn) ++{ ++ BT_DBG("conn %p", conn); ++ ++ if (conn->link_mode & HCI_LM_AUTH) ++ return 1; ++ ++ if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { ++ auth_requested_cp ar; ++ ar.handle = __cpu_to_le16(conn->handle); ++ hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_AUTH_REQUESTED, ++ AUTH_REQUESTED_CP_SIZE, &ar); ++ } ++ return 0; ++} ++ ++/* Enable encryption */ ++int hci_conn_encrypt(struct hci_conn *conn) ++{ ++ BT_DBG("conn %p", conn); ++ ++ if (conn->link_mode & HCI_LM_ENCRYPT) ++ return 1; ++ ++ if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) ++ return 0; ++ ++ if (hci_conn_auth(conn)) { ++ set_conn_encrypt_cp ce; ++ ce.handle = __cpu_to_le16(conn->handle); ++ ce.encrypt = 1; ++ hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT, ++ SET_CONN_ENCRYPT_CP_SIZE, &ce); ++ } ++ return 0; ++} ++ ++/* Drop all connection on the device */ ++void hci_conn_hash_flush(struct hci_dev *hdev) ++{ ++ struct conn_hash *h = &hdev->conn_hash; ++ struct list_head *p; ++ ++ BT_DBG("hdev %s", hdev->name); ++ ++ p = h->list.next; ++ while (p != &h->list) { ++ struct hci_conn *c; ++ ++ c = list_entry(p, struct hci_conn, list); ++ p = p->next; ++ ++ c->state = BT_CLOSED; ++ ++ hci_proto_disconn_ind(c, 0x16); ++ hci_conn_del(c); ++ } ++} ++ ++int hci_get_conn_list(unsigned long arg) ++{ ++ struct hci_conn_list_req req, *cl; ++ struct hci_conn_info *ci; ++ struct hci_dev *hdev; ++ struct list_head *p; ++ int n = 0, size; ++ ++ if (copy_from_user(&req, (void *) arg, sizeof(req))) ++ return -EFAULT; ++ ++ if (!(hdev = hci_dev_get(req.dev_id))) ++ return -ENODEV; ++ ++ size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req); ++ ++ if (verify_area(VERIFY_WRITE, (void *)arg, size)) ++ return -EFAULT; ++ ++ if (!(cl = (void *) kmalloc(size, GFP_KERNEL))) ++ return -ENOMEM; ++ ci = cl->conn_info; ++ ++ hci_dev_lock_bh(hdev); ++ list_for_each(p, &hdev->conn_hash.list) { ++ register struct hci_conn *c; ++ c = list_entry(p, struct hci_conn, list); ++ ++ bacpy(&(ci + n)->bdaddr, &c->dst); ++ (ci + n)->handle = c->handle; ++ (ci + n)->type = c->type; ++ (ci + n)->out = c->out; ++ (ci + n)->state = c->state; ++ (ci + n)->link_mode = c->link_mode; ++ n++; ++ } ++ hci_dev_unlock_bh(hdev); ++ ++ cl->dev_id = hdev->id; ++ cl->conn_num = n; ++ size = n * sizeof(struct hci_conn_info) + sizeof(req); ++ ++ hci_dev_put(hdev); ++ ++ copy_to_user((void *) arg, cl, size); ++ kfree(cl); ++ ++ return 0; ++} ++ ++int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg) ++{ ++ struct hci_conn_info_req req; ++ struct hci_conn_info ci; ++ struct hci_conn *conn; ++ char *ptr = (void *) arg + sizeof(req); ++ ++ if (copy_from_user(&req, (void *) arg, sizeof(req))) ++ return -EFAULT; ++ ++ if (verify_area(VERIFY_WRITE, ptr, sizeof(ci))) ++ return -EFAULT; ++ ++ hci_dev_lock_bh(hdev); ++ conn = conn_hash_lookup_ba(hdev, req.type, &req.bdaddr); ++ if (conn) { ++ bacpy(&ci.bdaddr, &conn->dst); ++ ci.handle = conn->handle; ++ ci.type = conn->type; ++ ci.out = conn->out; ++ ci.state = conn->state; ++ ci.link_mode = conn->link_mode; ++ } ++ hci_dev_unlock_bh(hdev); ++ ++ if (!conn) ++ return -ENOENT; ++ ++ copy_to_user(ptr, &ci, sizeof(ci)); ++ return 0; ++} +--- linux/net/bluetooth/hci_core.c~bluetooth-2.4.18-mh11 2001-11-09 23:21:21.000000000 +0100 ++++ linux/net/bluetooth/hci_core.c 2004-01-25 23:37:39.000000000 +0100 +@@ -25,11 +25,12 @@ + /* + * BlueZ HCI Core. + * +- * $Id$ ++ * $Id$ + */ + + #include <linux/config.h> + #include <linux/module.h> ++#include <linux/kmod.h> + + #include <linux/types.h> + #include <linux/errno.h> +@@ -50,12 +51,11 @@ + #include <asm/unaligned.h> + + #include <net/bluetooth/bluetooth.h> +-#include <net/bluetooth/bluez.h> + #include <net/bluetooth/hci_core.h> + + #ifndef HCI_CORE_DEBUG +-#undef DBG +-#define DBG( A... ) ++#undef BT_DBG ++#define BT_DBG( A... ) + #endif + + static void hci_cmd_task(unsigned long arg); +@@ -63,279 +63,69 @@ + static void hci_tx_task(unsigned long arg); + static void hci_notify(struct hci_dev *hdev, int event); + +-static rwlock_t hci_task_lock = RW_LOCK_UNLOCKED; ++rwlock_t hci_task_lock = RW_LOCK_UNLOCKED; + + /* HCI device list */ +-struct hci_dev *hdev_list[HCI_MAX_DEV]; +-spinlock_t hdev_list_lock; +-#define GET_HDEV(a) (hdev_list[a]) ++LIST_HEAD(hdev_list); ++rwlock_t hdev_list_lock = RW_LOCK_UNLOCKED; + +-/* HCI protocol list */ +-struct hci_proto *hproto_list[HCI_MAX_PROTO]; +-#define GET_HPROTO(a) (hproto_list[a]) ++/* HCI protocols */ ++#define HCI_MAX_PROTO 2 ++struct hci_proto *hci_proto[HCI_MAX_PROTO]; + + /* HCI notifiers list */ +-struct notifier_block *hci_dev_notifier; +- +-/* HCI device notifications */ +-int hci_register_notifier(struct notifier_block *nb) +-{ +- int err, i; +- struct hci_dev *hdev; +- +- if ((err = notifier_chain_register(&hci_dev_notifier, nb))) +- return err; +- +- /* Notify about already registered devices */ +- spin_lock(&hdev_list_lock); +- for (i = 0; i < HCI_MAX_DEV; i++) { +- if (!(hdev = GET_HDEV(i))) +- continue; +- if (hdev->flags & HCI_UP) +- (*nb->notifier_call)(nb, HCI_DEV_UP, hdev); +- } +- spin_unlock(&hdev_list_lock); +- +- return 0; +-} +- +-int hci_unregister_notifier(struct notifier_block *nb) +-{ +- return notifier_chain_unregister(&hci_dev_notifier, nb); +-} +- +-static inline void hci_notify(struct hci_dev *hdev, int event) +-{ +- notifier_call_chain(&hci_dev_notifier, event, hdev); +-} +- +-/* Get HCI device by index (device is locked on return)*/ +-struct hci_dev *hci_dev_get(int index) +-{ +- struct hci_dev *hdev; +- DBG("%d", index); +- +- if (index < 0 || index >= HCI_MAX_DEV) +- return NULL; +- +- spin_lock(&hdev_list_lock); +- if ((hdev = GET_HDEV(index))) +- hci_dev_hold(hdev); +- spin_unlock(&hdev_list_lock); +- +- return hdev; +-} +- +-/* Flush inquiry cache */ +-void inquiry_cache_flush(struct inquiry_cache *cache) +-{ +- struct inquiry_entry *next = cache->list, *e; +- +- DBG("cache %p", cache); +- +- cache->list = NULL; +- while ((e = next)) { +- next = e->next; +- kfree(e); +- } +-} +- +-/* Lookup by bdaddr. +- * Cache must be locked. */ +-static struct inquiry_entry * __inquiry_cache_lookup(struct inquiry_cache *cache, bdaddr_t *bdaddr) +-{ +- struct inquiry_entry *e; +- +- DBG("cache %p, %s", cache, batostr(bdaddr)); +- +- for (e = cache->list; e; e = e->next) +- if (!bacmp(&e->info.bdaddr, bdaddr)) +- break; +- +- return e; +-} +- +-static void inquiry_cache_update(struct inquiry_cache *cache, inquiry_info *info) +-{ +- struct inquiry_entry *e; +- +- DBG("cache %p, %s", cache, batostr(&info->bdaddr)); +- +- inquiry_cache_lock(cache); +- +- if (!(e = __inquiry_cache_lookup(cache, &info->bdaddr))) { +- /* Entry not in the cache. Add new one. */ +- if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC))) +- goto unlock; +- memset(e, 0, sizeof(struct inquiry_entry)); +- e->next = cache->list; +- cache->list = e; +- } +- +- memcpy(&e->info, info, sizeof(inquiry_info)); +- e->timestamp = jiffies; +- cache->timestamp = jiffies; +-unlock: +- inquiry_cache_unlock(cache); +-} +- +-static int inquiry_cache_dump(struct inquiry_cache *cache, int num, __u8 *buf) +-{ +- inquiry_info *info = (inquiry_info *) buf; +- struct inquiry_entry *e; +- int copied = 0; +- +- inquiry_cache_lock(cache); +- +- for (e = cache->list; e && copied < num; e = e->next, copied++) +- memcpy(info++, &e->info, sizeof(inquiry_info)); ++static struct notifier_block *hci_notifier; + +- inquiry_cache_unlock(cache); + +- DBG("cache %p, copied %d", cache, copied); +- return copied; +-} ++/* ---- HCI notifications ---- */ + +-/* --------- BaseBand connections --------- */ +-static struct hci_conn *hci_conn_add(struct hci_dev *hdev, __u16 handle, __u8 type, bdaddr_t *dst) ++int hci_register_notifier(struct notifier_block *nb) + { +- struct hci_conn *conn; +- +- DBG("%s handle %d dst %s", hdev->name, handle, batostr(dst)); +- +- if ( conn_hash_lookup(&hdev->conn_hash, handle)) { +- ERR("%s handle 0x%x already exists", hdev->name, handle); +- return NULL; +- } +- +- if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC))) +- return NULL; +- memset(conn, 0, sizeof(struct hci_conn)); +- +- bacpy(&conn->dst, dst); +- conn->handle = handle; +- conn->type = type; +- conn->hdev = hdev; +- +- skb_queue_head_init(&conn->data_q); +- +- hci_dev_hold(hdev); +- conn_hash_add(&hdev->conn_hash, handle, conn); +- +- return conn; ++ return notifier_chain_register(&hci_notifier, nb); + } + +-static int hci_conn_del(struct hci_dev *hdev, struct hci_conn *conn) ++int hci_unregister_notifier(struct notifier_block *nb) + { +- DBG("%s conn %p handle %d", hdev->name, conn, conn->handle); +- +- conn_hash_del(&hdev->conn_hash, conn); +- hci_dev_put(hdev); +- +- /* Unacked frames */ +- hdev->acl_cnt += conn->sent; +- +- skb_queue_purge(&conn->data_q); +- +- kfree(conn); +- return 0; ++ return notifier_chain_unregister(&hci_notifier, nb); + } + +-/* Drop all connection on the device */ +-static void hci_conn_hash_flush(struct hci_dev *hdev) ++void hci_notify(struct hci_dev *hdev, int event) + { +- struct conn_hash *h = &hdev->conn_hash; +- struct hci_proto *hp; +- struct list_head *p; +- +- DBG("hdev %s", hdev->name); +- +- p = h->list.next; +- while (p != &h->list) { +- struct hci_conn *c; +- +- c = list_entry(p, struct hci_conn, list); +- p = p->next; +- +- if (c->type == ACL_LINK) { +- /* ACL link notify L2CAP layer */ +- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->disconn_ind) +- hp->disconn_ind(c, 0x16); +- } else { +- /* SCO link (no notification) */ +- } +- +- hci_conn_del(hdev, c); +- } ++ notifier_call_chain(&hci_notifier, event, hdev); + } + +-int hci_connect(struct hci_dev *hdev, bdaddr_t *bdaddr) +-{ +- struct inquiry_cache *cache = &hdev->inq_cache; +- struct inquiry_entry *e; +- create_conn_cp cc; +- __u16 clock_offset; +- +- DBG("%s bdaddr %s", hdev->name, batostr(bdaddr)); +- +- if (!(hdev->flags & HCI_UP)) +- return -ENODEV; +- +- inquiry_cache_lock_bh(cache); +- +- if (!(e = __inquiry_cache_lookup(cache, bdaddr)) || inquiry_entry_age(e) > INQUIRY_ENTRY_AGE_MAX) { +- cc.pscan_rep_mode = 0; +- cc.pscan_mode = 0; +- clock_offset = 0; +- } else { +- cc.pscan_rep_mode = e->info.pscan_rep_mode; +- cc.pscan_mode = e->info.pscan_mode; +- clock_offset = __le16_to_cpu(e->info.clock_offset) & 0x8000; +- } +- +- inquiry_cache_unlock_bh(cache); +- +- bacpy(&cc.bdaddr, bdaddr); +- cc.pkt_type = __cpu_to_le16(hdev->pkt_type); +- cc.clock_offset = __cpu_to_le16(clock_offset); +- +- if (lmp_rswitch_capable(hdev)) +- cc.role_switch = 0x01; +- else +- cc.role_switch = 0x00; +- +- hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, CREATE_CONN_CP_SIZE, &cc); ++/* ---- HCI hotplug support ---- */ + +- return 0; +-} ++#ifdef CONFIG_HOTPLUG + +-int hci_disconnect(struct hci_conn *conn, __u8 reason) ++static int hci_run_hotplug(char *dev, char *action) + { +- disconnect_cp dc; +- +- DBG("conn %p handle %d", conn, conn->handle); ++ char *argv[3], *envp[5], dstr[20], astr[32]; + +- dc.handle = __cpu_to_le16(conn->handle); +- dc.reason = reason; +- hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT, DISCONNECT_CP_SIZE, &dc); ++ sprintf(dstr, "DEVICE=%s", dev); ++ sprintf(astr, "ACTION=%s", action); + +- return 0; +-} ++ argv[0] = hotplug_path; ++ argv[1] = "bluetooth"; ++ argv[2] = NULL; + +-/* --------- HCI request handling ------------ */ +-static inline void hci_req_lock(struct hci_dev *hdev) +-{ +- down(&hdev->req_lock); ++ envp[0] = "HOME=/"; ++ envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; ++ envp[2] = dstr; ++ envp[3] = astr; ++ envp[4] = NULL; ++ ++ return call_usermodehelper(argv[0], argv, envp); + } ++#else ++#define hci_run_hotplug(A...) ++#endif + +-static inline void hci_req_unlock(struct hci_dev *hdev) +-{ +- up(&hdev->req_lock); +-} ++/* ---- HCI requests ---- */ + +-static inline void hci_req_complete(struct hci_dev *hdev, int result) ++void hci_req_complete(struct hci_dev *hdev, int result) + { +- DBG("%s result 0x%2.2x", hdev->name, result); ++ BT_DBG("%s result 0x%2.2x", hdev->name, result); + + if (hdev->req_status == HCI_REQ_PEND) { + hdev->req_result = result; +@@ -344,9 +134,9 @@ + } + } + +-static inline void hci_req_cancel(struct hci_dev *hdev, int err) ++void hci_req_cancel(struct hci_dev *hdev, int err) + { +- DBG("%s err 0x%2.2x", hdev->name, err); ++ BT_DBG("%s err 0x%2.2x", hdev->name, err); + + if (hdev->req_status == HCI_REQ_PEND) { + hdev->req_result = err; +@@ -356,23 +146,22 @@ + } + + /* Execute request and wait for completion. */ +-static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt), +- unsigned long opt, __u32 timeout) ++static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt), unsigned long opt, __u32 timeout) + { + DECLARE_WAITQUEUE(wait, current); + int err = 0; + +- DBG("%s start", hdev->name); ++ BT_DBG("%s start", hdev->name); + + hdev->req_status = HCI_REQ_PEND; + + add_wait_queue(&hdev->req_wait_q, &wait); +- current->state = TASK_INTERRUPTIBLE; ++ set_current_state(TASK_INTERRUPTIBLE); + + req(hdev, opt); + schedule_timeout(timeout); + +- current->state = TASK_RUNNING; ++ set_current_state(TASK_RUNNING); + remove_wait_queue(&hdev->req_wait_q, &wait); + + if (signal_pending(current)) +@@ -394,7 +183,7 @@ + + hdev->req_status = hdev->req_result = 0; + +- DBG("%s end: err %d", hdev->name, err); ++ BT_DBG("%s end: err %d", hdev->name, err); + + return err; + } +@@ -412,10 +201,9 @@ + return ret; + } + +-/* --------- HCI requests ---------- */ + static void hci_reset_req(struct hci_dev *hdev, unsigned long opt) + { +- DBG("%s %ld", hdev->name, opt); ++ BT_DBG("%s %ld", hdev->name, opt); + + /* Reset device */ + hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL); +@@ -423,10 +211,10 @@ + + static void hci_init_req(struct hci_dev *hdev, unsigned long opt) + { +- set_event_flt_cp ec; ++ set_event_flt_cp ef; + __u16 param; + +- DBG("%s %ld", hdev->name, opt); ++ BT_DBG("%s %ld", hdev->name, opt); + + /* Mandatory initialization */ + +@@ -436,14 +224,27 @@ + /* Read Buffer Size (ACL mtu, max pkt, etc.) */ + hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE, 0, NULL); + ++#if 0 ++ /* Host buffer size */ ++ { ++ host_buffer_size_cp bs; ++ bs.acl_mtu = __cpu_to_le16(HCI_MAX_ACL_SIZE); ++ bs.sco_mtu = HCI_MAX_SCO_SIZE; ++ bs.acl_max_pkt = __cpu_to_le16(0xffff); ++ bs.sco_max_pkt = __cpu_to_le16(0xffff); ++ hci_send_cmd(hdev, OGF_HOST_CTL, OCF_HOST_BUFFER_SIZE, ++ HOST_BUFFER_SIZE_CP_SIZE, &bs); ++ } ++#endif ++ + /* Read BD Address */ + hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL); + + /* Optional initialization */ + + /* Clear Event Filters */ +- ec.flt_type = FLT_CLEAR_ALL; +- hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &ec); ++ ef.flt_type = FLT_CLEAR_ALL; ++ hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &ef); + + /* Page timeout ~20 secs */ + param = __cpu_to_le16(0x8000); +@@ -458,7 +259,7 @@ + { + __u8 scan = opt; + +- DBG("%s %x", hdev->name, scan); ++ BT_DBG("%s %x", hdev->name, scan); + + /* Inquiry and Page scans */ + hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, 1, &scan); +@@ -468,27 +269,190 @@ + { + __u8 auth = opt; + +- DBG("%s %x", hdev->name, auth); ++ BT_DBG("%s %x", hdev->name, auth); + + /* Authentication */ + hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE, 1, &auth); + } + ++static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt) ++{ ++ __u8 encrypt = opt; ++ ++ BT_DBG("%s %x", hdev->name, encrypt); ++ ++ /* Authentication */ ++ hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE, 1, &encrypt); ++} ++ ++/* Get HCI device by index. ++ * Device is locked on return. */ ++struct hci_dev *hci_dev_get(int index) ++{ ++ struct hci_dev *hdev; ++ struct list_head *p; ++ ++ BT_DBG("%d", index); ++ ++ if (index < 0) ++ return NULL; ++ ++ read_lock(&hdev_list_lock); ++ list_for_each(p, &hdev_list) { ++ hdev = list_entry(p, struct hci_dev, list); ++ if (hdev->id == index) { ++ hci_dev_hold(hdev); ++ goto done; ++ } ++ } ++ hdev = NULL; ++done: ++ read_unlock(&hdev_list_lock); ++ return hdev; ++} ++ ++/* ---- Inquiry support ---- */ ++void inquiry_cache_flush(struct hci_dev *hdev) ++{ ++ struct inquiry_cache *cache = &hdev->inq_cache; ++ struct inquiry_entry *next = cache->list, *e; ++ ++ BT_DBG("cache %p", cache); ++ ++ cache->list = NULL; ++ while ((e = next)) { ++ next = e->next; ++ kfree(e); ++ } ++} ++ ++struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr) ++{ ++ struct inquiry_cache *cache = &hdev->inq_cache; ++ struct inquiry_entry *e; ++ ++ BT_DBG("cache %p, %s", cache, batostr(bdaddr)); ++ ++ for (e = cache->list; e; e = e->next) ++ if (!bacmp(&e->info.bdaddr, bdaddr)) ++ break; ++ return e; ++} ++ ++void inquiry_cache_update(struct hci_dev *hdev, inquiry_info *info) ++{ ++ struct inquiry_cache *cache = &hdev->inq_cache; ++ struct inquiry_entry *e; ++ ++ BT_DBG("cache %p, %s", cache, batostr(&info->bdaddr)); ++ ++ if (!(e = inquiry_cache_lookup(hdev, &info->bdaddr))) { ++ /* Entry not in the cache. Add new one. */ ++ if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC))) ++ return; ++ memset(e, 0, sizeof(struct inquiry_entry)); ++ e->next = cache->list; ++ cache->list = e; ++ } ++ ++ memcpy(&e->info, info, sizeof(inquiry_info)); ++ e->timestamp = jiffies; ++ cache->timestamp = jiffies; ++} ++ ++int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf) ++{ ++ struct inquiry_cache *cache = &hdev->inq_cache; ++ inquiry_info *info = (inquiry_info *) buf; ++ struct inquiry_entry *e; ++ int copied = 0; ++ ++ for (e = cache->list; e && copied < num; e = e->next, copied++) ++ memcpy(info++, &e->info, sizeof(inquiry_info)); ++ ++ BT_DBG("cache %p, copied %d", cache, copied); ++ return copied; ++} ++ + static void hci_inq_req(struct hci_dev *hdev, unsigned long opt) + { + struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt; + inquiry_cp ic; + +- DBG("%s", hdev->name); ++ BT_DBG("%s", hdev->name); ++ ++ if (test_bit(HCI_INQUIRY, &hdev->flags)) ++ return; + + /* Start Inquiry */ + memcpy(&ic.lap, &ir->lap, 3); +- ic.lenght = ir->length; ++ ic.length = ir->length; + ic.num_rsp = ir->num_rsp; + hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, INQUIRY_CP_SIZE, &ic); + } + +-/* HCI ioctl helpers */ ++int hci_inquiry(unsigned long arg) ++{ ++ struct hci_inquiry_req ir; ++ struct hci_dev *hdev; ++ int err = 0, do_inquiry = 0, max_rsp; ++ long timeo; ++ __u8 *buf, *ptr; ++ ++ ptr = (void *) arg; ++ if (copy_from_user(&ir, ptr, sizeof(ir))) ++ return -EFAULT; ++ ++ if (!(hdev = hci_dev_get(ir.dev_id))) ++ return -ENODEV; ++ ++ hci_dev_lock_bh(hdev); ++ if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX || ++ inquiry_cache_empty(hdev) || ++ ir.flags & IREQ_CACHE_FLUSH) { ++ inquiry_cache_flush(hdev); ++ do_inquiry = 1; ++ } ++ hci_dev_unlock_bh(hdev); ++ ++ timeo = ir.length * 2 * HZ; ++ if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0) ++ goto done; ++ ++ /* for unlimited number of responses we will use buffer with 255 entries */ ++ max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp; ++ ++ /* cache_dump can't sleep. Therefore we allocate temp buffer and then ++ * copy it to the user space. ++ */ ++ if (!(buf = kmalloc(sizeof(inquiry_info) * max_rsp, GFP_KERNEL))) { ++ err = -ENOMEM; ++ goto done; ++ } ++ ++ hci_dev_lock_bh(hdev); ++ ir.num_rsp = inquiry_cache_dump(hdev, max_rsp, buf); ++ hci_dev_unlock_bh(hdev); ++ ++ BT_DBG("num_rsp %d", ir.num_rsp); ++ ++ if (!verify_area(VERIFY_WRITE, ptr, sizeof(ir) + ++ (sizeof(inquiry_info) * ir.num_rsp))) { ++ copy_to_user(ptr, &ir, sizeof(ir)); ++ ptr += sizeof(ir); ++ copy_to_user(ptr, buf, sizeof(inquiry_info) * ir.num_rsp); ++ } else ++ err = -EFAULT; ++ ++ kfree(buf); ++ ++done: ++ hci_dev_put(hdev); ++ return err; ++} ++ ++/* ---- HCI ioctl helpers ---- */ ++ + int hci_dev_open(__u16 dev) + { + struct hci_dev *hdev; +@@ -497,11 +461,11 @@ + if (!(hdev = hci_dev_get(dev))) + return -ENODEV; + +- DBG("%s %p", hdev->name, hdev); ++ BT_DBG("%s %p", hdev->name, hdev); + + hci_req_lock(hdev); + +- if (hdev->flags & HCI_UP) { ++ if (test_bit(HCI_UP, &hdev->flags)) { + ret = -EALREADY; + goto done; + } +@@ -511,18 +475,18 @@ + goto done; + } + +- if (hdev->flags & HCI_NORMAL) { ++ if (!test_bit(HCI_RAW, &hdev->flags)) { + atomic_set(&hdev->cmd_cnt, 1); +- hdev->flags |= HCI_INIT; ++ set_bit(HCI_INIT, &hdev->flags); + + //__hci_request(hdev, hci_reset_req, 0, HZ); + ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT); + +- hdev->flags &= ~HCI_INIT; ++ clear_bit(HCI_INIT, &hdev->flags); + } + + if (!ret) { +- hdev->flags |= HCI_UP; ++ set_bit(HCI_UP, &hdev->flags); + hci_notify(hdev, HCI_DEV_UP); + } else { + /* Init failed, cleanup */ +@@ -542,42 +506,36 @@ + } + + hdev->close(hdev); ++ hdev->flags = 0; + } + + done: + hci_req_unlock(hdev); + hci_dev_put(hdev); +- + return ret; + } + +-int hci_dev_close(__u16 dev) ++static int hci_dev_do_close(struct hci_dev *hdev) + { +- struct hci_dev *hdev; +- +- if (!(hdev = hci_dev_get(dev))) +- return -ENODEV; +- +- DBG("%s %p", hdev->name, hdev); ++ BT_DBG("%s %p", hdev->name, hdev); + + hci_req_cancel(hdev, ENODEV); + hci_req_lock(hdev); + +- if (!(hdev->flags & HCI_UP)) +- goto done; ++ if (!test_and_clear_bit(HCI_UP, &hdev->flags)) { ++ hci_req_unlock(hdev); ++ return 0; ++ } + + /* Kill RX and TX tasks */ + tasklet_kill(&hdev->rx_task); + tasklet_kill(&hdev->tx_task); + +- inquiry_cache_flush(&hdev->inq_cache); +- ++ hci_dev_lock_bh(hdev); ++ inquiry_cache_flush(hdev); + hci_conn_hash_flush(hdev); +- +- /* Clear flags */ +- hdev->flags &= HCI_SOCK; +- hdev->flags |= HCI_NORMAL; +- ++ hci_dev_unlock_bh(hdev); ++ + hci_notify(hdev, HCI_DEV_DOWN); + + if (hdev->flush) +@@ -586,9 +544,9 @@ + /* Reset device */ + skb_queue_purge(&hdev->cmd_q); + atomic_set(&hdev->cmd_cnt, 1); +- hdev->flags |= HCI_INIT; +- __hci_request(hdev, hci_reset_req, 0, HZ); +- hdev->flags &= ~HCI_INIT; ++ set_bit(HCI_INIT, &hdev->flags); ++ __hci_request(hdev, hci_reset_req, 0, HZ/4); ++ clear_bit(HCI_INIT, &hdev->flags); + + /* Kill cmd task */ + tasklet_kill(&hdev->cmd_task); +@@ -605,17 +563,28 @@ + } + + /* After this point our queues are empty +- * and no tasks are scheduled. +- */ ++ * and no tasks are scheduled. */ + hdev->close(hdev); + +-done: +- hci_req_unlock(hdev); +- hci_dev_put(hdev); ++ /* Clear flags */ ++ hdev->flags = 0; + ++ hci_req_unlock(hdev); + return 0; + } + ++int hci_dev_close(__u16 dev) ++{ ++ struct hci_dev *hdev; ++ int err; ++ ++ if (!(hdev = hci_dev_get(dev))) ++ return -ENODEV; ++ err = hci_dev_do_close(hdev); ++ hci_dev_put(hdev); ++ return err; ++} ++ + int hci_dev_reset(__u16 dev) + { + struct hci_dev *hdev; +@@ -627,16 +596,17 @@ + hci_req_lock(hdev); + tasklet_disable(&hdev->tx_task); + +- if (!(hdev->flags & HCI_UP)) ++ if (!test_bit(HCI_UP, &hdev->flags)) + goto done; + + /* Drop queues */ + skb_queue_purge(&hdev->rx_q); + skb_queue_purge(&hdev->cmd_q); + +- inquiry_cache_flush(&hdev->inq_cache); +- ++ hci_dev_lock_bh(hdev); ++ inquiry_cache_flush(hdev); + hci_conn_hash_flush(hdev); ++ hci_dev_unlock_bh(hdev); + + if (hdev->flush) + hdev->flush(hdev); +@@ -650,7 +620,6 @@ + tasklet_enable(&hdev->tx_task); + hci_req_unlock(hdev); + hci_dev_put(hdev); +- + return ret; + } + +@@ -669,30 +638,11 @@ + return ret; + } + +-int hci_dev_setauth(unsigned long arg) +-{ +- struct hci_dev *hdev; +- struct hci_dev_req dr; +- int ret = 0; +- +- if (copy_from_user(&dr, (void *) arg, sizeof(dr))) +- return -EFAULT; +- +- if (!(hdev = hci_dev_get(dr.dev_id))) +- return -ENODEV; +- +- ret = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT); +- +- hci_dev_put(hdev); +- +- return ret; +-} +- +-int hci_dev_setscan(unsigned long arg) ++int hci_dev_cmd(unsigned int cmd, unsigned long arg) + { + struct hci_dev *hdev; + struct hci_dev_req dr; +- int ret = 0; ++ int err = 0; + + if (copy_from_user(&dr, (void *) arg, sizeof(dr))) + return -EFAULT; +@@ -700,48 +650,78 @@ + if (!(hdev = hci_dev_get(dr.dev_id))) + return -ENODEV; + +- ret = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT); +- +- hci_dev_put(hdev); ++ switch (cmd) { ++ case HCISETAUTH: ++ err = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT); ++ break; + +- return ret; +-} ++ case HCISETENCRYPT: ++ if (!lmp_encrypt_capable(hdev)) { ++ err = -EOPNOTSUPP; ++ break; ++ } + +-int hci_dev_setptype(unsigned long arg) +-{ +- struct hci_dev *hdev; +- struct hci_dev_req dr; +- int ret = 0; ++ if (!test_bit(HCI_AUTH, &hdev->flags)) { ++ /* Auth must be enabled first */ ++ err = hci_request(hdev, hci_auth_req, ++ dr.dev_opt, HCI_INIT_TIMEOUT); ++ if (err) ++ break; ++ } ++ ++ err = hci_request(hdev, hci_encrypt_req, ++ dr.dev_opt, HCI_INIT_TIMEOUT); ++ break; ++ ++ case HCISETSCAN: ++ err = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT); ++ break; ++ ++ case HCISETPTYPE: ++ hdev->pkt_type = (__u16) dr.dev_opt; ++ break; ++ ++ case HCISETLINKPOL: ++ hdev->link_policy = (__u16) dr.dev_opt; ++ break; + +- if (copy_from_user(&dr, (void *) arg, sizeof(dr))) +- return -EFAULT; ++ case HCISETLINKMODE: ++ hdev->link_mode = ((__u16) dr.dev_opt) & (HCI_LM_MASTER | HCI_LM_ACCEPT); ++ break; + +- if (!(hdev = hci_dev_get(dr.dev_id))) +- return -ENODEV; ++ case HCISETACLMTU: ++ hdev->acl_mtu = *((__u16 *)&dr.dev_opt + 1); ++ hdev->acl_pkts = *((__u16 *)&dr.dev_opt + 0); ++ break; + +- hdev->pkt_type = (__u16) dr.dev_opt; ++ case HCISETSCOMTU: ++ hdev->sco_mtu = *((__u16 *)&dr.dev_opt + 1); ++ hdev->sco_pkts = *((__u16 *)&dr.dev_opt + 0); ++ break; + ++ default: ++ err = -EINVAL; ++ break; ++ } + hci_dev_put(hdev); +- +- return ret; ++ return err; + } + +-int hci_dev_list(unsigned long arg) ++int hci_get_dev_list(unsigned long arg) + { + struct hci_dev_list_req *dl; + struct hci_dev_req *dr; +- struct hci_dev *hdev; +- int i, n, size; ++ struct list_head *p; ++ int n = 0, size; + __u16 dev_num; + + if (get_user(dev_num, (__u16 *) arg)) + return -EFAULT; + +- /* Avoid long loop, overflow */ +- if (dev_num > 2048) ++ if (!dev_num) + return -EINVAL; + +- size = dev_num * sizeof(struct hci_dev_req) + sizeof(__u16); ++ size = dev_num * sizeof(*dr) + sizeof(*dl); + + if (verify_area(VERIFY_WRITE, (void *) arg, size)) + return -EFAULT; +@@ -750,25 +730,27 @@ + return -ENOMEM; + dr = dl->dev_req; + +- spin_lock_bh(&hdev_list_lock); +- for (i = 0, n = 0; i < HCI_MAX_DEV && n < dev_num; i++) { +- if ((hdev = hdev_list[i])) { +- (dr + n)->dev_id = hdev->id; +- (dr + n)->dev_opt = hdev->flags; +- n++; +- } ++ read_lock_bh(&hdev_list_lock); ++ list_for_each(p, &hdev_list) { ++ struct hci_dev *hdev; ++ hdev = list_entry(p, struct hci_dev, list); ++ (dr + n)->dev_id = hdev->id; ++ (dr + n)->dev_opt = hdev->flags; ++ if (++n >= dev_num) ++ break; + } +- spin_unlock_bh(&hdev_list_lock); ++ read_unlock_bh(&hdev_list_lock); + + dl->dev_num = n; +- size = n * sizeof(struct hci_dev_req) + sizeof(__u16); ++ size = n * sizeof(*dr) + sizeof(*dl); + + copy_to_user((void *) arg, dl, size); ++ kfree(dl); + + return 0; + } + +-int hci_dev_info(unsigned long arg) ++int hci_get_dev_info(unsigned long arg) + { + struct hci_dev *hdev; + struct hci_dev_info di; +@@ -786,9 +768,11 @@ + di.flags = hdev->flags; + di.pkt_type = hdev->pkt_type; + di.acl_mtu = hdev->acl_mtu; +- di.acl_max = hdev->acl_max; ++ di.acl_pkts = hdev->acl_pkts; + di.sco_mtu = hdev->sco_mtu; +- di.sco_max = hdev->sco_max; ++ di.sco_pkts = hdev->sco_pkts; ++ di.link_policy = hdev->link_policy; ++ di.link_mode = hdev->link_mode; + + memcpy(&di.stat, &hdev->stat, sizeof(di.stat)); + memcpy(&di.features, &hdev->features, sizeof(di.features)); +@@ -801,258 +785,168 @@ + return err; + } + +-__u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode) +-{ +- __u32 omode = hdev->flags & HCI_MODE_MASK; +- +- hdev->flags &= ~HCI_MODE_MASK; +- hdev->flags |= (mode & HCI_MODE_MASK); + +- return omode; +-} +- +-__u32 hci_dev_getmode(struct hci_dev *hdev) +-{ +- return hdev->flags & HCI_MODE_MASK; +-} ++/* ---- Interface to HCI drivers ---- */ + +-int hci_conn_list(unsigned long arg) ++/* Register HCI device */ ++int hci_register_dev(struct hci_dev *hdev) + { +- struct hci_conn_list_req req, *cl; +- struct hci_conn_info *ci; +- struct hci_dev *hdev; +- struct list_head *p; +- int n = 0, size; +- +- if (copy_from_user(&req, (void *) arg, sizeof(req))) +- return -EFAULT; ++ struct list_head *head = &hdev_list, *p; ++ int id = 0; + +- if (!(hdev = hci_dev_get(req.dev_id))) +- return -ENODEV; ++ BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type); + +- /* Set a limit to avoid overlong loops, and also numeric overflow - AC */ +- if(req.conn_num < 2048) ++ if (!hdev->open || !hdev->close || !hdev->destruct) + return -EINVAL; +- +- size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req); + +- if (!(cl = kmalloc(size, GFP_KERNEL))) +- return -ENOMEM; +- ci = cl->conn_info; +- +- local_bh_disable(); +- conn_hash_lock(&hdev->conn_hash); +- list_for_each(p, &hdev->conn_hash.list) { +- register struct hci_conn *c; +- c = list_entry(p, struct hci_conn, list); ++ write_lock_bh(&hdev_list_lock); + +- (ci + n)->handle = c->handle; +- bacpy(&(ci + n)->bdaddr, &c->dst); +- n++; ++ /* Find first available device id */ ++ list_for_each(p, &hdev_list) { ++ if (list_entry(p, struct hci_dev, list)->id != id) ++ break; ++ head = p; id++; + } +- conn_hash_unlock(&hdev->conn_hash); +- local_bh_enable(); +- +- cl->dev_id = hdev->id; +- cl->conn_num = n; +- size = n * sizeof(struct hci_conn_info) + sizeof(req); +- +- hci_dev_put(hdev); +- +- if(copy_to_user((void *) arg, cl, size)) +- return -EFAULT; +- return 0; +-} +- +-int hci_inquiry(unsigned long arg) +-{ +- struct inquiry_cache *cache; +- struct hci_inquiry_req ir; +- struct hci_dev *hdev; +- int err = 0, do_inquiry = 0; +- long timeo; +- __u8 *buf, *ptr; +- +- ptr = (void *) arg; +- if (copy_from_user(&ir, ptr, sizeof(ir))) +- return -EFAULT; ++ ++ sprintf(hdev->name, "hci%d", id); ++ hdev->id = id; ++ list_add(&hdev->list, head); + +- if (!(hdev = hci_dev_get(ir.dev_id))) +- return -ENODEV; ++ atomic_set(&hdev->refcnt, 1); ++ spin_lock_init(&hdev->lock); ++ ++ hdev->flags = 0; ++ hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1); ++ hdev->link_mode = (HCI_LM_ACCEPT); + +- cache = &hdev->inq_cache; ++ tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev); ++ tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev); ++ tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); + +- inquiry_cache_lock(cache); +- if (inquiry_cache_age(cache) > INQUIRY_CACHE_AGE_MAX || ir.flags & IREQ_CACHE_FLUSH) { +- inquiry_cache_flush(cache); +- do_inquiry = 1; +- } +- inquiry_cache_unlock(cache); ++ skb_queue_head_init(&hdev->rx_q); ++ skb_queue_head_init(&hdev->cmd_q); ++ skb_queue_head_init(&hdev->raw_q); + +- /* Limit inquiry time, also avoid overflows */ ++ init_waitqueue_head(&hdev->req_wait_q); ++ init_MUTEX(&hdev->req_lock); + +- if(ir.length > 2048 || ir.num_rsp > 2048) +- { +- err = -EINVAL; +- goto done; +- } ++ inquiry_cache_init(hdev); + +- timeo = ir.length * 2 * HZ; +- if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0) +- goto done; ++ conn_hash_init(hdev); + +- /* cache_dump can't sleep. Therefore we allocate temp buffer and then +- * copy it to the user space. +- */ +- if (!(buf = kmalloc(sizeof(inquiry_info) * ir.num_rsp, GFP_KERNEL))) { +- err = -ENOMEM; +- goto done; +- } +- ir.num_rsp = inquiry_cache_dump(cache, ir.num_rsp, buf); ++ memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); + +- DBG("num_rsp %d", ir.num_rsp); ++ atomic_set(&hdev->promisc, 0); + +- if (!verify_area(VERIFY_WRITE, ptr, sizeof(ir) + (sizeof(inquiry_info) * ir.num_rsp))) { +- copy_to_user(ptr, &ir, sizeof(ir)); +- ptr += sizeof(ir); +- copy_to_user(ptr, buf, sizeof(inquiry_info) * ir.num_rsp); +- } else +- err = -EFAULT; ++ MOD_INC_USE_COUNT; + +- kfree(buf); ++ write_unlock_bh(&hdev_list_lock); + +-done: +- hci_dev_put(hdev); ++ hci_notify(hdev, HCI_DEV_REG); ++ hci_run_hotplug(hdev->name, "register"); + +- return err; ++ return id; + } + +-/* Interface to HCI drivers */ +- +-/* Register HCI device */ +-int hci_register_dev(struct hci_dev *hdev) ++/* Unregister HCI device */ ++int hci_unregister_dev(struct hci_dev *hdev) + { +- int i; +- +- DBG("%p name %s type %d", hdev, hdev->name, hdev->type); +- +- /* Find free slot */ +- spin_lock_bh(&hdev_list_lock); +- for (i = 0; i < HCI_MAX_DEV; i++) { +- if (!hdev_list[i]) { +- hdev_list[i] = hdev; +- +- sprintf(hdev->name, "hci%d", i); +- atomic_set(&hdev->refcnt, 0); +- hdev->id = i; +- hdev->flags = HCI_NORMAL; +- +- hdev->pkt_type = (HCI_DM1 | HCI_DH1); +- +- tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev); +- tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev); +- tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); +- +- skb_queue_head_init(&hdev->rx_q); +- skb_queue_head_init(&hdev->cmd_q); +- skb_queue_head_init(&hdev->raw_q); +- +- init_waitqueue_head(&hdev->req_wait_q); +- init_MUTEX(&hdev->req_lock); +- +- inquiry_cache_init(&hdev->inq_cache); ++ BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type); + +- conn_hash_init(&hdev->conn_hash); ++ write_lock_bh(&hdev_list_lock); ++ list_del(&hdev->list); ++ write_unlock_bh(&hdev_list_lock); + +- memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); ++ hci_dev_do_close(hdev); + +- hci_notify(hdev, HCI_DEV_REG); ++ hci_notify(hdev, HCI_DEV_UNREG); ++ hci_run_hotplug(hdev->name, "unregister"); + +- MOD_INC_USE_COUNT; +- break; +- } +- } +- spin_unlock_bh(&hdev_list_lock); ++ hci_dev_put(hdev); + +- return (i == HCI_MAX_DEV) ? -1 : i; ++ MOD_DEC_USE_COUNT; ++ return 0; + } + +-/* Unregister HCI device */ +-int hci_unregister_dev(struct hci_dev *hdev) ++/* Suspend HCI device */ ++int hci_suspend_dev(struct hci_dev *hdev) + { +- int i; ++ hci_notify(hdev, HCI_DEV_SUSPEND); ++ hci_run_hotplug(hdev->name, "suspend"); ++ return 0; ++} + +- DBG("%p name %s type %d", hdev, hdev->name, hdev->type); ++/* Resume HCI device */ ++int hci_resume_dev(struct hci_dev *hdev) ++{ ++ hci_notify(hdev, HCI_DEV_RESUME); ++ hci_run_hotplug(hdev->name, "resume"); ++ return 0; ++} + +- if (hdev->flags & HCI_UP) +- hci_dev_close(hdev->id); ++/* Receive frame from HCI drivers */ ++int hci_recv_frame(struct sk_buff *skb) ++{ ++ struct hci_dev *hdev = (struct hci_dev *) skb->dev; + +- /* Find device slot */ +- spin_lock(&hdev_list_lock); +- for (i = 0; i < HCI_MAX_DEV; i++) { +- if (hdev_list[i] == hdev) { +- hdev_list[i] = NULL; +- MOD_DEC_USE_COUNT; +- break; +- } ++ if (!hdev || (!test_bit(HCI_UP, &hdev->flags) && ++ !test_bit(HCI_INIT, &hdev->flags)) ) { ++ kfree_skb(skb); ++ return -1; + } +- spin_unlock(&hdev_list_lock); + +- hci_notify(hdev, HCI_DEV_UNREG); +- +- /* Sleep while device is in use */ +- while (atomic_read(&hdev->refcnt)) { +- int sleep_cnt = 100; ++ BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); + +- DBG("%s sleeping on lock %d", hdev->name, atomic_read(&hdev->refcnt)); ++ /* Incomming skb */ ++ bluez_cb(skb)->incomming = 1; + +- sleep_on_timeout(&hdev->req_wait_q, HZ*10); +- if (!(--sleep_cnt)) +- break; +- } ++ /* Time stamp */ ++ do_gettimeofday(&skb->stamp); + ++ /* Queue frame for rx task */ ++ skb_queue_tail(&hdev->rx_q, skb); ++ hci_sched_rx(hdev); + return 0; + } + +-/* Interface to upper protocols */ ++/* ---- Interface to upper protocols ---- */ + + /* Register/Unregister protocols. +- * hci_task_lock is used to ensure that no tasks are running. +- */ +-int hci_register_proto(struct hci_proto *hproto) ++ * hci_task_lock is used to ensure that no tasks are running. */ ++int hci_register_proto(struct hci_proto *hp) + { + int err = 0; + +- DBG("%p name %s", hproto, hproto->name); ++ BT_DBG("%p name %s id %d", hp, hp->name, hp->id); + +- if (hproto->id >= HCI_MAX_PROTO) ++ if (hp->id >= HCI_MAX_PROTO) + return -EINVAL; + + write_lock_bh(&hci_task_lock); + +- if (!hproto_list[hproto->id]) +- hproto_list[hproto->id] = hproto; ++ if (!hci_proto[hp->id]) ++ hci_proto[hp->id] = hp; + else +- err = -1; ++ err = -EEXIST; + + write_unlock_bh(&hci_task_lock); + + return err; + } + +-int hci_unregister_proto(struct hci_proto *hproto) ++int hci_unregister_proto(struct hci_proto *hp) + { + int err = 0; + +- DBG("%p name %s", hproto, hproto->name); ++ BT_DBG("%p name %s id %d", hp, hp->name, hp->id); + +- if (hproto->id > HCI_MAX_PROTO) ++ if (hp->id >= HCI_MAX_PROTO) + return -EINVAL; + + write_lock_bh(&hci_task_lock); + +- if (hproto_list[hproto->id]) +- hproto_list[hproto->id] = NULL; ++ if (hci_proto[hp->id]) ++ hci_proto[hp->id] = NULL; + else + err = -ENOENT; + +@@ -1070,10 +964,14 @@ + return -ENODEV; + } + +- DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); ++ BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); ++ ++ if (atomic_read(&hdev->promisc)) { ++ /* Time stamp */ ++ do_gettimeofday(&skb->stamp); + +- if (hdev->flags & HCI_SOCK) + hci_send_to_sock(hdev, skb); ++ } + + /* Get rid of skb owner, prior to sending to the driver. */ + skb_orphan(skb); +@@ -1081,128 +979,6 @@ + return hdev->send(skb); + } + +-/* Connection scheduler */ +-static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote) +-{ +- struct conn_hash *h = &hdev->conn_hash; +- struct hci_conn *conn = NULL; +- int num = 0, min = 0xffff; +- struct list_head *p; +- +- conn_hash_lock(h); +- list_for_each(p, &h->list) { +- register struct hci_conn *c; +- +- c = list_entry(p, struct hci_conn, list); +- +- if (c->type != type || skb_queue_empty(&c->data_q)) +- continue; +- num++; +- +- if (c->sent < min) { +- min = c->sent; +- conn = c; +- } +- } +- conn_hash_unlock(h); +- +- if (conn) { +- int q = hdev->acl_cnt / num; +- *quote = q ? q : 1; +- } else +- *quote = 0; +- +- DBG("conn %p quote %d", conn, *quote); +- +- return conn; +-} +- +-static inline void hci_sched_acl(struct hci_dev *hdev) +-{ +- struct hci_conn *conn; +- struct sk_buff *skb; +- int quote; +- +- DBG("%s", hdev->name); +- +- while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, "e))) { +- while (quote && (skb = skb_dequeue(&conn->data_q))) { +- DBG("skb %p len %d", skb, skb->len); +- +- hci_send_frame(skb); +- +- conn->sent++; +- hdev->acl_cnt--; +- quote--; +- } +- } +-} +- +-/* Schedule SCO */ +-static inline void hci_sched_sco(struct hci_dev *hdev) +-{ +- /* FIXME: For now we queue SCO packets to the raw queue +- +- while (hdev->sco_cnt && (skb = skb_dequeue(&conn->data_q))) { +- hci_send_frame(skb); +- conn->sco_sent++; +- hdev->sco_cnt--; +- } +- */ +-} +- +-/* Get data from the previously sent command */ +-static void * hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf) +-{ +- hci_command_hdr *hc; +- +- if (!hdev->sent_cmd) +- return NULL; +- +- hc = (void *) hdev->sent_cmd->data; +- +- if (hc->opcode != __cpu_to_le16(cmd_opcode_pack(ogf, ocf))) +- return NULL; +- +- DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf); +- +- return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE; +-} +- +-/* Send raw HCI frame */ +-int hci_send_raw(struct sk_buff *skb) +-{ +- struct hci_dev *hdev = (struct hci_dev *) skb->dev; +- +- if (!hdev) { +- kfree_skb(skb); +- return -ENODEV; +- } +- +- DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); +- +- if (hdev->flags & HCI_NORMAL) { +- /* Queue frame according it's type */ +- switch (skb->pkt_type) { +- case HCI_COMMAND_PKT: +- skb_queue_tail(&hdev->cmd_q, skb); +- hci_sched_cmd(hdev); +- return 0; +- +- case HCI_ACLDATA_PKT: +- case HCI_SCODATA_PKT: +- /* FIXME: +- * Check header here and queue to apropriate connection. +- */ +- break; +- } +- } +- +- skb_queue_tail(&hdev->raw_q, skb); +- hci_sched_tx(hdev); +- return 0; +-} +- + /* Send HCI command */ + int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param) + { +@@ -1210,10 +986,10 @@ + hci_command_hdr *hc; + struct sk_buff *skb; + +- DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen); ++ BT_DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen); + + if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) { +- ERR("%s Can't allocate memory for HCI command", hdev->name); ++ BT_ERR("%s Can't allocate memory for HCI command", hdev->name); + return -ENOMEM; + } + +@@ -1224,7 +1000,7 @@ + if (plen) + memcpy(skb_put(skb, plen), param, plen); + +- DBG("skb len %d", skb->len); ++ BT_DBG("skb len %d", skb->len); + + skb->pkt_type = HCI_COMMAND_PKT; + skb->dev = (void *) hdev; +@@ -1234,10 +1010,28 @@ + return 0; + } + ++/* Get data from the previously sent command */ ++void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf) ++{ ++ hci_command_hdr *hc; ++ ++ if (!hdev->sent_cmd) ++ return NULL; ++ ++ hc = (void *) hdev->sent_cmd->data; ++ ++ if (hc->opcode != __cpu_to_le16(cmd_opcode_pack(ogf, ocf))) ++ return NULL; ++ ++ BT_DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf); ++ ++ return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE; ++} ++ + /* Send ACL data */ + static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags) + { +- int len = skb->len; ++ int len = skb->len; + hci_acl_hdr *ah; + + ah = (hci_acl_hdr *) skb_push(skb, HCI_ACL_HDR_SIZE); +@@ -1252,7 +1046,7 @@ + struct hci_dev *hdev = conn->hdev; + struct sk_buff *list; + +- DBG("%s conn %p flags 0x%x", hdev->name, conn, flags); ++ BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags); + + skb->dev = (void *) hdev; + skb->pkt_type = HCI_ACLDATA_PKT; +@@ -1260,12 +1054,12 @@ + + if (!(list = skb_shinfo(skb)->frag_list)) { + /* Non fragmented */ +- DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len); ++ BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len); + + skb_queue_tail(&conn->data_q, skb); + } else { + /* Fragmented */ +- DBG("%s frag %p len %d", hdev->name, skb, skb->len); ++ BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len); + + skb_shinfo(skb)->frag_list = NULL; + +@@ -1280,7 +1074,7 @@ + skb->pkt_type = HCI_ACLDATA_PKT; + hci_add_acl_hdr(skb, conn->handle, flags | ACL_CONT); + +- DBG("%s frag %p len %d", hdev->name, skb, skb->len); ++ BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len); + + __skb_queue_tail(&conn->data_q, skb); + } while (list); +@@ -1298,7 +1092,7 @@ + struct hci_dev *hdev = conn->hdev; + hci_sco_hdr hs; + +- DBG("%s len %d", hdev->name, skb->len); ++ BT_DBG("%s len %d", hdev->name, skb->len); + + if (skb->len > hdev->sco_mtu) { + kfree_skb(skb); +@@ -1315,544 +1109,136 @@ + skb->pkt_type = HCI_SCODATA_PKT; + skb_queue_tail(&conn->data_q, skb); + hci_sched_tx(hdev); +- + return 0; + } + +-/* Handle HCI Event packets */ +- +-/* Command Complete OGF LINK_CTL */ +-static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) +-{ +- DBG("%s ocf 0x%x", hdev->name, ocf); +- +- switch (ocf) { +- default: +- DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf); +- break; +- }; +-} +- +-/* Command Complete OGF LINK_POLICY */ +-static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) +-{ +- DBG("%s ocf 0x%x", hdev->name, ocf); +- +- switch (ocf) { +- default: +- DBG("%s: Command complete: ogf LINK_POLICY ocf %x", hdev->name, ocf); +- break; +- }; +-} +- +-/* Command Complete OGF HOST_CTL */ +-static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) +-{ +- __u8 status, param; +- void *sent; +- +- +- DBG("%s ocf 0x%x", hdev->name, ocf); +- +- switch (ocf) { +- case OCF_RESET: +- status = *((__u8 *) skb->data); +- +- hci_req_complete(hdev, status); +- break; +- +- case OCF_SET_EVENT_FLT: +- status = *((__u8 *) skb->data); +- +- if (status) { +- DBG("%s SET_EVENT_FLT failed %d", hdev->name, status); +- } else { +- DBG("%s SET_EVENT_FLT succeseful", hdev->name); +- } +- break; +- +- case OCF_WRITE_AUTH_ENABLE: +- if (!(sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE))) +- break; +- +- status = *((__u8 *) skb->data); +- param = *((__u8 *) sent); +- +- if (!status) { +- if (param == AUTH_ENABLED) +- hdev->flags |= HCI_AUTH; +- else +- hdev->flags &= ~HCI_AUTH; +- } +- hci_req_complete(hdev, status); +- break; +- +- case OCF_WRITE_CA_TIMEOUT: +- status = *((__u8 *) skb->data); +- +- if (status) { +- DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status); +- } else { +- DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name); +- } +- break; +- +- case OCF_WRITE_PG_TIMEOUT: +- status = *((__u8 *) skb->data); +- +- if (status) { +- DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status); +- } else { +- DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name); +- } +- break; +- +- case OCF_WRITE_SCAN_ENABLE: +- if (!(sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE))) +- break; +- status = *((__u8 *) skb->data); +- param = *((__u8 *) sent); +- +- DBG("param 0x%x", param); +- +- if (!status) { +- switch (param) { +- case IS_ENA_PS_ENA: +- hdev->flags |= HCI_PSCAN | HCI_ISCAN; +- break; +- +- case IS_ENA_PS_DIS: +- hdev->flags &= ~HCI_PSCAN; +- hdev->flags |= HCI_ISCAN; +- break; +- +- case IS_DIS_PS_ENA: +- hdev->flags &= ~HCI_ISCAN; +- hdev->flags |= HCI_PSCAN; +- break; +- +- default: +- hdev->flags &= ~(HCI_ISCAN | HCI_PSCAN); +- break; +- }; +- } +- hci_req_complete(hdev, status); +- break; +- +- default: +- DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf); +- break; +- }; +-} +- +-/* Command Complete OGF INFO_PARAM */ +-static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) +-{ +- read_local_features_rp *lf; +- read_buffer_size_rp *bs; +- read_bd_addr_rp *ba; +- +- DBG("%s ocf 0x%x", hdev->name, ocf); +- +- switch (ocf) { +- case OCF_READ_LOCAL_FEATURES: +- lf = (read_local_features_rp *) skb->data; +- +- if (lf->status) { +- DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status); +- break; +- } +- +- memcpy(hdev->features, lf->features, sizeof(hdev->features)); +- +- /* Adjust default settings according to features +- * supported by device. */ +- if (hdev->features[0] & LMP_3SLOT) +- hdev->pkt_type |= (HCI_DM3 | HCI_DH3); +- +- if (hdev->features[0] & LMP_5SLOT) +- hdev->pkt_type |= (HCI_DM5 | HCI_DH5); +- +- DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]); +- +- break; +- +- case OCF_READ_BUFFER_SIZE: +- bs = (read_buffer_size_rp *) skb->data; +- +- if (bs->status) { +- DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status); +- break; +- } +- +- hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu); +- hdev->sco_mtu = bs->sco_mtu; +- hdev->acl_max = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt); +- hdev->sco_max = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt); +- +- DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name, +- hdev->acl_mtu, hdev->sco_mtu, hdev->acl_max, hdev->sco_max); +- +- break; +- +- case OCF_READ_BD_ADDR: +- ba = (read_bd_addr_rp *) skb->data; +- +- if (!ba->status) { +- bacpy(&hdev->bdaddr, &ba->bdaddr); +- } else { +- DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status); +- } +- +- hci_req_complete(hdev, ba->status); +- break; +- +- default: +- DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf); +- break; +- }; +-} ++/* ---- HCI TX task (outgoing data) ---- */ + +-/* Command Status OGF LINK_CTL */ +-static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status) ++/* HCI Connection scheduler */ ++static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote) + { +- struct hci_proto * hp; +- +- DBG("%s ocf 0x%x", hdev->name, ocf); +- +- switch (ocf) { +- case OCF_CREATE_CONN: +- if (status) { +- create_conn_cp *cc = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN); +- +- if (!cc) +- break; ++ struct conn_hash *h = &hdev->conn_hash; ++ struct hci_conn *conn = NULL; ++ int num = 0, min = ~0; ++ struct list_head *p; + +- DBG("%s Create connection error: status 0x%x %s", hdev->name, +- status, batostr(&cc->bdaddr)); ++ /* We don't have to lock device here. Connections are always ++ * added and removed with TX task disabled. */ ++ list_for_each(p, &h->list) { ++ struct hci_conn *c; ++ c = list_entry(p, struct hci_conn, list); + +- /* Notify upper protocols */ +- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm) { +- tasklet_disable(&hdev->tx_task); +- hp->connect_cfm(hdev, &cc->bdaddr, status, NULL); +- tasklet_enable(&hdev->tx_task); +- } +- } +- break; ++ if (c->type != type || c->state != BT_CONNECTED ++ || skb_queue_empty(&c->data_q)) ++ continue; ++ num++; + +- case OCF_INQUIRY: +- if (status) { +- DBG("%s Inquiry error: status 0x%x", hdev->name, status); +- hci_req_complete(hdev, status); ++ if (c->sent < min) { ++ min = c->sent; ++ conn = c; + } +- break; +- +- default: +- DBG("%s Command status: ogf LINK_CTL ocf %x", hdev->name, ocf); +- break; +- }; +-} +- +-/* Command Status OGF LINK_POLICY */ +-static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status) +-{ +- DBG("%s ocf 0x%x", hdev->name, ocf); +- +- switch (ocf) { +- default: +- DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf); +- break; +- }; +-} +- +-/* Command Status OGF HOST_CTL */ +-static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status) +-{ +- DBG("%s ocf 0x%x", hdev->name, ocf); +- +- switch (ocf) { +- default: +- DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf); +- break; +- }; +-} +- +-/* Command Status OGF INFO_PARAM */ +-static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status) +-{ +- DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf); +- +- switch (ocf) { +- default: +- DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf); +- break; +- }; +-} +- +-/* Inquiry Complete */ +-static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +-{ +- __u8 status = *((__u8 *) skb->data); +- +- DBG("%s status %d", hdev->name, status); +- +- hci_req_complete(hdev, status); +-} +- +-/* Inquiry Result */ +-static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) +-{ +- inquiry_info *info = (inquiry_info *) (skb->data + 1); +- int num_rsp = *((__u8 *) skb->data); ++ } + +- DBG("%s num_rsp %d", hdev->name, num_rsp); ++ if (conn) { ++ int cnt = (type == ACL_LINK ? hdev->acl_cnt : hdev->sco_cnt); ++ int q = cnt / num; ++ *quote = q ? q : 1; ++ } else ++ *quote = 0; + +- for (; num_rsp; num_rsp--) +- inquiry_cache_update(&hdev->inq_cache, info++); ++ BT_DBG("conn %p quote %d", conn, *quote); ++ return conn; + } + +-/* Connect Request */ +-static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) ++static inline void hci_acl_tx_to(struct hci_dev *hdev) + { +- evt_conn_request *cr = (evt_conn_request *) skb->data; +- struct hci_proto *hp; +- accept_conn_req_cp ac; +- int accept = 0; ++ struct conn_hash *h = &hdev->conn_hash; ++ struct list_head *p; ++ struct hci_conn *c; + +- DBG("%s Connection request: %s type 0x%x", hdev->name, batostr(&cr->bdaddr), cr->link_type); ++ BT_ERR("%s ACL tx timeout", hdev->name); + +- /* Notify upper protocols */ +- if (cr->link_type == ACL_LINK) { +- /* ACL link notify L2CAP */ +- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_ind) { +- tasklet_disable(&hdev->tx_task); +- accept = hp->connect_ind(hdev, &cr->bdaddr); +- tasklet_enable(&hdev->tx_task); ++ /* Kill stalled connections */ ++ list_for_each(p, &h->list) { ++ c = list_entry(p, struct hci_conn, list); ++ if (c->type == ACL_LINK && c->sent) { ++ BT_ERR("%s killing stalled ACL connection %s", ++ hdev->name, batostr(&c->dst)); ++ hci_acl_disconn(c, 0x13); + } +- } else { +- /* SCO link (no notification) */ +- /* FIXME: Should be accept it here or let the requester (app) accept it ? */ +- accept = 1; +- } +- +- if (accept) { +- /* Connection accepted by upper layer */ +- bacpy(&ac.bdaddr, &cr->bdaddr); +- ac.role = 0x01; /* Remain slave */ +- hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, ACCEPT_CONN_REQ_CP_SIZE, &ac); +- } else { +- /* Connection rejected by upper layer */ +- /* FIXME: +- * Should we use HCI reject here ? +- */ +- return; + } + } + +-/* Connect Complete */ +-static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ++static inline void hci_sched_acl(struct hci_dev *hdev) + { +- evt_conn_complete *cc = (evt_conn_complete *) skb->data; +- struct hci_conn *conn = NULL; +- struct hci_proto *hp; ++ struct hci_conn *conn; ++ struct sk_buff *skb; ++ int quote; + +- DBG("%s", hdev->name); ++ BT_DBG("%s", hdev->name); + +- tasklet_disable(&hdev->tx_task); ++ /* ACL tx timeout must be longer than maximum ++ * link supervision timeout (40.9 seconds) */ ++ if (!hdev->acl_cnt && (jiffies - hdev->acl_last_tx) > (HZ * 45)) ++ hci_acl_tx_to(hdev); + +- if (!cc->status) +- conn = hci_conn_add(hdev, __le16_to_cpu(cc->handle), cc->link_type, &cc->bdaddr); ++ while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, "e))) { ++ while (quote-- && (skb = skb_dequeue(&conn->data_q))) { ++ BT_DBG("skb %p len %d", skb, skb->len); ++ hci_send_frame(skb); ++ hdev->acl_last_tx = jiffies; + +- /* Notify upper protocols */ +- if (cc->link_type == ACL_LINK) { +- /* ACL link notify L2CAP layer */ +- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm) +- hp->connect_cfm(hdev, &cc->bdaddr, cc->status, conn); +- } else { +- /* SCO link (no notification) */ ++ hdev->acl_cnt--; ++ conn->sent++; ++ } + } +- +- tasklet_enable(&hdev->tx_task); + } + +-/* Disconnect Complete */ +-static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ++/* Schedule SCO */ ++static inline void hci_sched_sco(struct hci_dev *hdev) + { +- evt_disconn_complete *dc = (evt_disconn_complete *) skb->data; +- struct hci_conn *conn = NULL; +- struct hci_proto *hp; +- __u16 handle = __le16_to_cpu(dc->handle); ++ struct hci_conn *conn; ++ struct sk_buff *skb; ++ int quote; + +- DBG("%s", hdev->name); ++ BT_DBG("%s", hdev->name); + +- if (!dc->status && (conn = conn_hash_lookup(&hdev->conn_hash, handle))) { +- tasklet_disable(&hdev->tx_task); ++ while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, "e))) { ++ while (quote-- && (skb = skb_dequeue(&conn->data_q))) { ++ BT_DBG("skb %p len %d", skb, skb->len); ++ hci_send_frame(skb); + +- /* Notify upper protocols */ +- if (conn->type == ACL_LINK) { +- /* ACL link notify L2CAP layer */ +- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->disconn_ind) +- hp->disconn_ind(conn, dc->reason); +- } else { +- /* SCO link (no notification) */ ++ conn->sent++; ++ if (conn->sent == ~0) ++ conn->sent = 0; + } +- +- hci_conn_del(hdev, conn); +- +- tasklet_enable(&hdev->tx_task); + } + } + +-/* Number of completed packets */ +-static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb) ++static void hci_tx_task(unsigned long arg) + { +- evt_num_comp_pkts *nc = (evt_num_comp_pkts *) skb->data; +- __u16 *ptr; +- int i; +- +- skb_pull(skb, EVT_NUM_COMP_PKTS_SIZE); +- +- DBG("%s num_hndl %d", hdev->name, nc->num_hndl); ++ struct hci_dev *hdev = (struct hci_dev *) arg; ++ struct sk_buff *skb; + +- if (skb->len < nc->num_hndl * 4) { +- DBG("%s bad parameters", hdev->name); +- return; +- } ++ read_lock(&hci_task_lock); + +- tasklet_disable(&hdev->tx_task); ++ BT_DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt); + +- for (i = 0, ptr = (__u16 *) skb->data; i < nc->num_hndl; i++) { +- struct hci_conn *conn; +- __u16 handle, count; ++ /* Schedule queues and send stuff to HCI driver */ + +- handle = __le16_to_cpu(get_unaligned(ptr++)); +- count = __le16_to_cpu(get_unaligned(ptr++)); ++ hci_sched_acl(hdev); + +- hdev->acl_cnt += count; ++ hci_sched_sco(hdev); + +- if ((conn = conn_hash_lookup(&hdev->conn_hash, handle))) +- conn->sent -= count; +- } ++ /* Send next queued raw (unknown type) packet */ ++ while ((skb = skb_dequeue(&hdev->raw_q))) ++ hci_send_frame(skb); + +- tasklet_enable(&hdev->tx_task); +- +- hci_sched_tx(hdev); ++ read_unlock(&hci_task_lock); + } + +-static inline void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) +-{ +- hci_event_hdr *he = (hci_event_hdr *) skb->data; +- evt_cmd_status *cs; +- evt_cmd_complete *ec; +- __u16 opcode, ocf, ogf; +- +- skb_pull(skb, HCI_EVENT_HDR_SIZE); +- +- DBG("%s evt 0x%x", hdev->name, he->evt); +- +- switch (he->evt) { +- case EVT_NUM_COMP_PKTS: +- hci_num_comp_pkts_evt(hdev, skb); +- break; +- +- case EVT_INQUIRY_COMPLETE: +- hci_inquiry_complete_evt(hdev, skb); +- break; +- +- case EVT_INQUIRY_RESULT: +- hci_inquiry_result_evt(hdev, skb); +- break; +- +- case EVT_CONN_REQUEST: +- hci_conn_request_evt(hdev, skb); +- break; +- +- case EVT_CONN_COMPLETE: +- hci_conn_complete_evt(hdev, skb); +- break; +- +- case EVT_DISCONN_COMPLETE: +- hci_disconn_complete_evt(hdev, skb); +- break; +- +- case EVT_CMD_STATUS: +- cs = (evt_cmd_status *) skb->data; +- skb_pull(skb, EVT_CMD_STATUS_SIZE); +- +- opcode = __le16_to_cpu(cs->opcode); +- ogf = cmd_opcode_ogf(opcode); +- ocf = cmd_opcode_ocf(opcode); +- +- switch (ogf) { +- case OGF_INFO_PARAM: +- hci_cs_info_param(hdev, ocf, cs->status); +- break; +- +- case OGF_HOST_CTL: +- hci_cs_host_ctl(hdev, ocf, cs->status); +- break; + +- case OGF_LINK_CTL: +- hci_cs_link_ctl(hdev, ocf, cs->status); +- break; +- +- case OGF_LINK_POLICY: +- hci_cs_link_policy(hdev, ocf, cs->status); +- break; +- +- default: +- DBG("%s Command Status OGF %x", hdev->name, ogf); +- break; +- }; +- +- if (cs->ncmd) { +- atomic_set(&hdev->cmd_cnt, 1); +- if (!skb_queue_empty(&hdev->cmd_q)) +- hci_sched_cmd(hdev); +- } +- break; +- +- case EVT_CMD_COMPLETE: +- ec = (evt_cmd_complete *) skb->data; +- skb_pull(skb, EVT_CMD_COMPLETE_SIZE); +- +- opcode = __le16_to_cpu(ec->opcode); +- ogf = cmd_opcode_ogf(opcode); +- ocf = cmd_opcode_ocf(opcode); +- +- switch (ogf) { +- case OGF_INFO_PARAM: +- hci_cc_info_param(hdev, ocf, skb); +- break; +- +- case OGF_HOST_CTL: +- hci_cc_host_ctl(hdev, ocf, skb); +- break; +- +- case OGF_LINK_CTL: +- hci_cc_link_ctl(hdev, ocf, skb); +- break; +- +- case OGF_LINK_POLICY: +- hci_cc_link_policy(hdev, ocf, skb); +- break; +- +- default: +- DBG("%s Command Completed OGF %x", hdev->name, ogf); +- break; +- }; +- +- if (ec->ncmd) { +- atomic_set(&hdev->cmd_cnt, 1); +- if (!skb_queue_empty(&hdev->cmd_q)) +- hci_sched_cmd(hdev); +- } +- break; +- }; +- +- kfree_skb(skb); +- hdev->stat.evt_rx++; +-} ++/* ----- HCI RX task (incomming data proccessing) ----- */ + + /* ACL data packet */ + static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb) +@@ -1867,51 +1253,86 @@ + flags = acl_flags(handle); + handle = acl_handle(handle); + +- DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags); ++ BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags); + +- if ((conn = conn_hash_lookup(&hdev->conn_hash, handle))) { ++ hdev->stat.acl_rx++; ++ ++ hci_dev_lock(hdev); ++ conn = conn_hash_lookup_handle(hdev, handle); ++ hci_dev_unlock(hdev); ++ ++ if (conn) { + register struct hci_proto *hp; + + /* Send to upper protocol */ +- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->recv_acldata) { ++ if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) { + hp->recv_acldata(conn, skb, flags); +- goto sent; ++ return; + } + } else { +- ERR("%s ACL packet for unknown connection handle %d", hdev->name, handle); ++ BT_ERR("%s ACL packet for unknown connection handle %d", ++ hdev->name, handle); + } + + kfree_skb(skb); +-sent: +- hdev->stat.acl_rx++; + } + + /* SCO data packet */ + static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb) + { +- DBG("%s len %d", hdev->name, skb->len); ++ hci_sco_hdr *sh = (void *) skb->data; ++ struct hci_conn *conn; ++ __u16 handle; ++ ++ skb_pull(skb, HCI_SCO_HDR_SIZE); ++ ++ handle = __le16_to_cpu(sh->handle); ++ ++ BT_DBG("%s len %d handle 0x%x", hdev->name, skb->len, handle); + +- kfree_skb(skb); + hdev->stat.sco_rx++; ++ ++ hci_dev_lock(hdev); ++ conn = conn_hash_lookup_handle(hdev, handle); ++ hci_dev_unlock(hdev); ++ ++ if (conn) { ++ register struct hci_proto *hp; ++ ++ /* Send to upper protocol */ ++ if ((hp = hci_proto[HCI_PROTO_SCO]) && hp->recv_scodata) { ++ hp->recv_scodata(conn, skb); ++ return; ++ } ++ } else { ++ BT_ERR("%s SCO packet for unknown connection handle %d", ++ hdev->name, handle); ++ } ++ ++ kfree_skb(skb); + } + +-/* ----- HCI tasks ----- */ + void hci_rx_task(unsigned long arg) + { + struct hci_dev *hdev = (struct hci_dev *) arg; + struct sk_buff *skb; + +- DBG("%s", hdev->name); ++ BT_DBG("%s", hdev->name); + + read_lock(&hci_task_lock); + + while ((skb = skb_dequeue(&hdev->rx_q))) { +- if (hdev->flags & HCI_SOCK) { ++ if (atomic_read(&hdev->promisc)) { + /* Send copy to the sockets */ + hci_send_to_sock(hdev, skb); + } + +- if (hdev->flags & HCI_INIT) { ++ if (test_bit(HCI_RAW, &hdev->flags)) { ++ kfree_skb(skb); ++ continue; ++ } ++ ++ if (test_bit(HCI_INIT, &hdev->flags)) { + /* Don't process data packets in this states. */ + switch (skb->pkt_type) { + case HCI_ACLDATA_PKT: +@@ -1921,64 +1342,43 @@ + }; + } + +- if (hdev->flags & HCI_NORMAL) { +- /* Process frame */ +- switch (skb->pkt_type) { +- case HCI_EVENT_PKT: +- hci_event_packet(hdev, skb); +- break; ++ /* Process frame */ ++ switch (skb->pkt_type) { ++ case HCI_EVENT_PKT: ++ hci_event_packet(hdev, skb); ++ break; + +- case HCI_ACLDATA_PKT: +- DBG("%s ACL data packet", hdev->name); +- hci_acldata_packet(hdev, skb); +- break; ++ case HCI_ACLDATA_PKT: ++ BT_DBG("%s ACL data packet", hdev->name); ++ hci_acldata_packet(hdev, skb); ++ break; + +- case HCI_SCODATA_PKT: +- DBG("%s SCO data packet", hdev->name); +- hci_scodata_packet(hdev, skb); +- break; ++ case HCI_SCODATA_PKT: ++ BT_DBG("%s SCO data packet", hdev->name); ++ hci_scodata_packet(hdev, skb); ++ break; + +- default: +- kfree_skb(skb); +- break; +- }; +- } else { ++ default: + kfree_skb(skb); ++ break; + } + } + + read_unlock(&hci_task_lock); + } + +-static void hci_tx_task(unsigned long arg) +-{ +- struct hci_dev *hdev = (struct hci_dev *) arg; +- struct sk_buff *skb; +- +- read_lock(&hci_task_lock); +- +- DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt); +- +- /* Schedule queues and send stuff to HCI driver */ +- +- hci_sched_acl(hdev); +- +- hci_sched_sco(hdev); +- +- /* Send next queued raw (unknown type) packet */ +- while ((skb = skb_dequeue(&hdev->raw_q))) +- hci_send_frame(skb); +- +- read_unlock(&hci_task_lock); +-} +- + static void hci_cmd_task(unsigned long arg) + { + struct hci_dev *hdev = (struct hci_dev *) arg; + struct sk_buff *skb; + +- DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt)); ++ BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt)); + ++ if (!atomic_read(&hdev->cmd_cnt) && (jiffies - hdev->cmd_last_tx) > HZ) { ++ BT_ERR("%s command tx timeout", hdev->name); ++ atomic_set(&hdev->cmd_cnt, 1); ++ } ++ + /* Send queued commands */ + if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) { + if (hdev->sent_cmd) +@@ -1987,6 +1387,7 @@ + if ((hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC))) { + atomic_dec(&hdev->cmd_cnt); + hci_send_frame(skb); ++ hdev->cmd_last_tx = jiffies; + } else { + skb_queue_head(&hdev->cmd_q, skb); + hci_sched_cmd(hdev); +@@ -1994,33 +1395,10 @@ + } + } + +-/* Receive frame from HCI drivers */ +-int hci_recv_frame(struct sk_buff *skb) +-{ +- struct hci_dev *hdev = (struct hci_dev *) skb->dev; +- +- if (!hdev || !(hdev->flags & (HCI_UP | HCI_INIT))) { +- kfree_skb(skb); +- return -1; +- } +- +- DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); +- +- /* Incomming skb */ +- bluez_cb(skb)->incomming = 1; +- +- /* Queue frame for rx task */ +- skb_queue_tail(&hdev->rx_q, skb); +- hci_sched_rx(hdev); +- +- return 0; +-} ++/* ---- Initialization ---- */ + + int hci_core_init(void) + { +- /* Init locks */ +- spin_lock_init(&hdev_list_lock); +- + return 0; + } + +@@ -2028,5 +1406,3 @@ + { + return 0; + } +- +-MODULE_LICENSE("GPL"); +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/hci_event.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,910 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * HCI Events. ++ * ++ * $Id$ ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/init.h> ++#include <linux/skbuff.h> ++#include <linux/interrupt.h> ++#include <linux/notifier.h> ++#include <net/sock.h> ++ ++#include <asm/system.h> ++#include <asm/uaccess.h> ++#include <asm/unaligned.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++ ++#ifndef HCI_CORE_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#endif ++ ++/* Handle HCI Event packets */ ++ ++/* Command Complete OGF LINK_CTL */ ++static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) ++{ ++ __u8 status; ++ ++ BT_DBG("%s ocf 0x%x", hdev->name, ocf); ++ ++ switch (ocf) { ++ case OCF_INQUIRY_CANCEL: ++ status = *((__u8 *) skb->data); ++ ++ if (status) { ++ BT_DBG("%s Inquiry cancel error: status 0x%x", hdev->name, status); ++ } else { ++ clear_bit(HCI_INQUIRY, &hdev->flags); ++ hci_req_complete(hdev, status); ++ } ++ break; ++ ++ default: ++ BT_DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf); ++ break; ++ }; ++} ++ ++/* Command Complete OGF LINK_POLICY */ ++static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) ++{ ++ struct hci_conn *conn; ++ role_discovery_rp *rd; ++ ++ BT_DBG("%s ocf 0x%x", hdev->name, ocf); ++ ++ switch (ocf) { ++ case OCF_ROLE_DISCOVERY: ++ rd = (void *) skb->data; ++ ++ if (rd->status) ++ break; ++ ++ hci_dev_lock(hdev); ++ ++ conn = conn_hash_lookup_handle(hdev, __le16_to_cpu(rd->handle)); ++ if (conn) { ++ if (rd->role) ++ conn->link_mode &= ~HCI_LM_MASTER; ++ else ++ conn->link_mode |= HCI_LM_MASTER; ++ } ++ ++ hci_dev_unlock(hdev); ++ break; ++ ++ default: ++ BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x", ++ hdev->name, ocf); ++ break; ++ }; ++} ++ ++/* Command Complete OGF HOST_CTL */ ++static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) ++{ ++ __u8 status, param; ++ void *sent; ++ ++ BT_DBG("%s ocf 0x%x", hdev->name, ocf); ++ ++ switch (ocf) { ++ case OCF_RESET: ++ status = *((__u8 *) skb->data); ++ hci_req_complete(hdev, status); ++ break; ++ ++ case OCF_SET_EVENT_FLT: ++ status = *((__u8 *) skb->data); ++ if (status) { ++ BT_DBG("%s SET_EVENT_FLT failed %d", hdev->name, status); ++ } else { ++ BT_DBG("%s SET_EVENT_FLT succeseful", hdev->name); ++ } ++ break; ++ ++ case OCF_WRITE_AUTH_ENABLE: ++ sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE); ++ if (!sent) ++ break; ++ ++ status = *((__u8 *) skb->data); ++ param = *((__u8 *) sent); ++ ++ if (!status) { ++ if (param == AUTH_ENABLED) ++ set_bit(HCI_AUTH, &hdev->flags); ++ else ++ clear_bit(HCI_AUTH, &hdev->flags); ++ } ++ hci_req_complete(hdev, status); ++ break; ++ ++ case OCF_WRITE_ENCRYPT_MODE: ++ sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE); ++ if (!sent) ++ break; ++ ++ status = *((__u8 *) skb->data); ++ param = *((__u8 *) sent); ++ ++ if (!status) { ++ if (param) ++ set_bit(HCI_ENCRYPT, &hdev->flags); ++ else ++ clear_bit(HCI_ENCRYPT, &hdev->flags); ++ } ++ hci_req_complete(hdev, status); ++ break; ++ ++ case OCF_WRITE_CA_TIMEOUT: ++ status = *((__u8 *) skb->data); ++ if (status) { ++ BT_DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status); ++ } else { ++ BT_DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name); ++ } ++ break; ++ ++ case OCF_WRITE_PG_TIMEOUT: ++ status = *((__u8 *) skb->data); ++ if (status) { ++ BT_DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status); ++ } else { ++ BT_DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name); ++ } ++ break; ++ ++ case OCF_WRITE_SCAN_ENABLE: ++ sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE); ++ if (!sent) ++ break; ++ status = *((__u8 *) skb->data); ++ param = *((__u8 *) sent); ++ ++ BT_DBG("param 0x%x", param); ++ ++ if (!status) { ++ clear_bit(HCI_PSCAN, &hdev->flags); ++ clear_bit(HCI_ISCAN, &hdev->flags); ++ if (param & SCAN_INQUIRY) ++ set_bit(HCI_ISCAN, &hdev->flags); ++ ++ if (param & SCAN_PAGE) ++ set_bit(HCI_PSCAN, &hdev->flags); ++ } ++ hci_req_complete(hdev, status); ++ break; ++ ++ case OCF_HOST_BUFFER_SIZE: ++ status = *((__u8 *) skb->data); ++ if (status) { ++ BT_DBG("%s OCF_BUFFER_SIZE failed %d", hdev->name, status); ++ hci_req_complete(hdev, status); ++ } ++ break; ++ ++ default: ++ BT_DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf); ++ break; ++ }; ++} ++ ++/* Command Complete OGF INFO_PARAM */ ++static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) ++{ ++ read_local_features_rp *lf; ++ read_buffer_size_rp *bs; ++ read_bd_addr_rp *ba; ++ ++ BT_DBG("%s ocf 0x%x", hdev->name, ocf); ++ ++ switch (ocf) { ++ case OCF_READ_LOCAL_FEATURES: ++ lf = (read_local_features_rp *) skb->data; ++ ++ if (lf->status) { ++ BT_DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status); ++ break; ++ } ++ ++ memcpy(hdev->features, lf->features, sizeof(hdev->features)); ++ ++ /* Adjust default settings according to features ++ * supported by device. */ ++ if (hdev->features[0] & LMP_3SLOT) ++ hdev->pkt_type |= (HCI_DM3 | HCI_DH3); ++ ++ if (hdev->features[0] & LMP_5SLOT) ++ hdev->pkt_type |= (HCI_DM5 | HCI_DH5); ++ ++ if (hdev->features[1] & LMP_HV2) ++ hdev->pkt_type |= (HCI_HV2); ++ ++ if (hdev->features[1] & LMP_HV3) ++ hdev->pkt_type |= (HCI_HV3); ++ ++ BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]); ++ ++ break; ++ ++ case OCF_READ_BUFFER_SIZE: ++ bs = (read_buffer_size_rp *) skb->data; ++ ++ if (bs->status) { ++ BT_DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status); ++ hci_req_complete(hdev, bs->status); ++ break; ++ } ++ ++ hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu); ++ hdev->sco_mtu = bs->sco_mtu ? bs->sco_mtu : 64; ++ hdev->acl_pkts = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt); ++ hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt); ++ ++ BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name, ++ hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts); ++ break; ++ ++ case OCF_READ_BD_ADDR: ++ ba = (read_bd_addr_rp *) skb->data; ++ ++ if (!ba->status) { ++ bacpy(&hdev->bdaddr, &ba->bdaddr); ++ } else { ++ BT_DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status); ++ } ++ ++ hci_req_complete(hdev, ba->status); ++ break; ++ ++ default: ++ BT_DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf); ++ break; ++ }; ++} ++ ++/* Command Status OGF LINK_CTL */ ++static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) ++{ ++ struct hci_conn *conn; ++ create_conn_cp *cc = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN); ++ ++ if (!cc) ++ return; ++ ++ hci_dev_lock(hdev); ++ ++ conn = conn_hash_lookup_ba(hdev, ACL_LINK, &cc->bdaddr); ++ ++ BT_DBG("%s status 0x%x bdaddr %s conn %p", hdev->name, ++ status, batostr(&cc->bdaddr), conn); ++ ++ if (status) { ++ if (conn) { ++ conn->state = BT_CLOSED; ++ hci_proto_connect_cfm(conn, status); ++ hci_conn_del(conn); ++ } ++ } else { ++ if (!conn) { ++ conn = hci_conn_add(hdev, ACL_LINK, &cc->bdaddr); ++ if (conn) { ++ conn->out = 1; ++ conn->link_mode |= HCI_LM_MASTER; ++ } else ++ BT_ERR("No memmory for new connection"); ++ } ++ } ++ ++ hci_dev_unlock(hdev); ++} ++ ++static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status) ++{ ++ BT_DBG("%s ocf 0x%x", hdev->name, ocf); ++ ++ switch (ocf) { ++ case OCF_CREATE_CONN: ++ hci_cs_create_conn(hdev, status); ++ break; ++ ++ case OCF_ADD_SCO: ++ if (status) { ++ struct hci_conn *acl, *sco; ++ add_sco_cp *cp = hci_sent_cmd_data(hdev, ++ OGF_LINK_CTL, OCF_ADD_SCO); ++ __u16 handle; ++ ++ if (!cp) ++ break; ++ ++ handle = __le16_to_cpu(cp->handle); ++ ++ BT_DBG("%s Add SCO error: handle %d status 0x%x", hdev->name, handle, status); ++ ++ hci_dev_lock(hdev); ++ ++ acl = conn_hash_lookup_handle(hdev, handle); ++ if (acl && (sco = acl->link)) { ++ sco->state = BT_CLOSED; ++ hci_proto_connect_cfm(sco, status); ++ hci_conn_del(sco); ++ } ++ ++ hci_dev_unlock(hdev); ++ } ++ break; ++ ++ case OCF_INQUIRY: ++ if (status) { ++ BT_DBG("%s Inquiry error: status 0x%x", hdev->name, status); ++ hci_req_complete(hdev, status); ++ } else { ++ set_bit(HCI_INQUIRY, &hdev->flags); ++ } ++ break; ++ ++ default: ++ BT_DBG("%s Command status: ogf LINK_CTL ocf %x status %d", ++ hdev->name, ocf, status); ++ break; ++ }; ++} ++ ++/* Command Status OGF LINK_POLICY */ ++static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status) ++{ ++ BT_DBG("%s ocf 0x%x", hdev->name, ocf); ++ ++ switch (ocf) { ++ default: ++ BT_DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf); ++ break; ++ }; ++} ++ ++/* Command Status OGF HOST_CTL */ ++static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status) ++{ ++ BT_DBG("%s ocf 0x%x", hdev->name, ocf); ++ ++ switch (ocf) { ++ default: ++ BT_DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf); ++ break; ++ }; ++} ++ ++/* Command Status OGF INFO_PARAM */ ++static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status) ++{ ++ BT_DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf); ++ ++ switch (ocf) { ++ default: ++ BT_DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf); ++ break; ++ }; ++} ++ ++/* Inquiry Complete */ ++static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ __u8 status = *((__u8 *) skb->data); ++ ++ BT_DBG("%s status %d", hdev->name, status); ++ ++ clear_bit(HCI_INQUIRY, &hdev->flags); ++ hci_req_complete(hdev, status); ++} ++ ++/* Inquiry Result */ ++static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ inquiry_info *info = (inquiry_info *) (skb->data + 1); ++ int num_rsp = *((__u8 *) skb->data); ++ ++ BT_DBG("%s num_rsp %d", hdev->name, num_rsp); ++ ++ hci_dev_lock(hdev); ++ for (; num_rsp; num_rsp--) ++ inquiry_cache_update(hdev, info++); ++ hci_dev_unlock(hdev); ++} ++ ++/* Inquiry Result With RSSI */ ++static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ inquiry_info_with_rssi *info = (inquiry_info_with_rssi *) (skb->data + 1); ++ int num_rsp = *((__u8 *) skb->data); ++ ++ BT_DBG("%s num_rsp %d", hdev->name, num_rsp); ++ ++ hci_dev_lock(hdev); ++ for (; num_rsp; num_rsp--) { ++ inquiry_info tmp; ++ bacpy(&tmp.bdaddr, &info->bdaddr); ++ tmp.pscan_rep_mode = info->pscan_rep_mode; ++ tmp.pscan_period_mode = info->pscan_period_mode; ++ tmp.pscan_mode = 0x00; ++ memcpy(tmp.dev_class, &info->dev_class, 3); ++ tmp.clock_offset = info->clock_offset; ++ info++; ++ inquiry_cache_update(hdev, &tmp); ++ } ++ hci_dev_unlock(hdev); ++} ++ ++/* Connect Request */ ++static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ evt_conn_request *cr = (evt_conn_request *) skb->data; ++ int mask = hdev->link_mode; ++ ++ BT_DBG("%s Connection request: %s type 0x%x", hdev->name, ++ batostr(&cr->bdaddr), cr->link_type); ++ ++ mask |= hci_proto_connect_ind(hdev, &cr->bdaddr, cr->link_type); ++ ++ if (mask & HCI_LM_ACCEPT) { ++ /* Connection accepted */ ++ struct hci_conn *conn; ++ accept_conn_req_cp ac; ++ ++ hci_dev_lock(hdev); ++ conn = conn_hash_lookup_ba(hdev, cr->link_type, &cr->bdaddr); ++ if (!conn) { ++ if (!(conn = hci_conn_add(hdev, cr->link_type, &cr->bdaddr))) { ++ BT_ERR("No memmory for new connection"); ++ hci_dev_unlock(hdev); ++ return; ++ } ++ } ++ conn->state = BT_CONNECT; ++ hci_dev_unlock(hdev); ++ ++ bacpy(&ac.bdaddr, &cr->bdaddr); ++ ++ if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) ++ ac.role = 0x00; /* Become master */ ++ else ++ ac.role = 0x01; /* Remain slave */ ++ ++ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, ++ ACCEPT_CONN_REQ_CP_SIZE, &ac); ++ } else { ++ /* Connection rejected */ ++ reject_conn_req_cp rc; ++ ++ bacpy(&rc.bdaddr, &cr->bdaddr); ++ rc.reason = 0x0f; ++ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_REJECT_CONN_REQ, ++ REJECT_CONN_REQ_CP_SIZE, &rc); ++ } ++} ++ ++/* Connect Complete */ ++static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ evt_conn_complete *cc = (evt_conn_complete *) skb->data; ++ struct hci_conn *conn = NULL; ++ ++ BT_DBG("%s", hdev->name); ++ ++ hci_dev_lock(hdev); ++ ++ conn = conn_hash_lookup_ba(hdev, cc->link_type, &cc->bdaddr); ++ if (!conn) { ++ hci_dev_unlock(hdev); ++ return; ++ } ++ ++ if (!cc->status) { ++ conn->handle = __le16_to_cpu(cc->handle); ++ conn->state = BT_CONNECTED; ++ ++ if (test_bit(HCI_AUTH, &hdev->flags)) ++ conn->link_mode |= HCI_LM_AUTH; ++ ++ if (test_bit(HCI_ENCRYPT, &hdev->flags)) ++ conn->link_mode |= HCI_LM_ENCRYPT; ++ ++ ++ /* Set link policy */ ++ if (conn->type == ACL_LINK && hdev->link_policy) { ++ write_link_policy_cp lp; ++ lp.handle = cc->handle; ++ lp.policy = __cpu_to_le16(hdev->link_policy); ++ hci_send_cmd(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY, ++ WRITE_LINK_POLICY_CP_SIZE, &lp); ++ } ++ ++ /* Set packet type for incomming connection */ ++ if (!conn->out) { ++ change_conn_ptype_cp cp; ++ cp.handle = cc->handle; ++ cp.pkt_type = (conn->type == ACL_LINK) ? ++ __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK): ++ __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); ++ ++ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_PTYPE, ++ CHANGE_CONN_PTYPE_CP_SIZE, &cp); ++ } ++ } else ++ conn->state = BT_CLOSED; ++ ++ if (conn->type == ACL_LINK) { ++ struct hci_conn *sco = conn->link; ++ if (sco) { ++ if (!cc->status) ++ hci_add_sco(sco, conn->handle); ++ else { ++ hci_proto_connect_cfm(sco, cc->status); ++ hci_conn_del(sco); ++ } ++ } ++ } ++ ++ hci_proto_connect_cfm(conn, cc->status); ++ if (cc->status) ++ hci_conn_del(conn); ++ ++ hci_dev_unlock(hdev); ++} ++ ++/* Disconnect Complete */ ++static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ evt_disconn_complete *dc = (evt_disconn_complete *) skb->data; ++ struct hci_conn *conn = NULL; ++ __u16 handle = __le16_to_cpu(dc->handle); ++ ++ BT_DBG("%s status %d", hdev->name, dc->status); ++ ++ if (dc->status) ++ return; ++ ++ hci_dev_lock(hdev); ++ ++ conn = conn_hash_lookup_handle(hdev, handle); ++ if (conn) { ++ conn->state = BT_CLOSED; ++ hci_proto_disconn_ind(conn, dc->reason); ++ hci_conn_del(conn); ++ } ++ ++ hci_dev_unlock(hdev); ++} ++ ++/* Number of completed packets */ ++static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ evt_num_comp_pkts *nc = (evt_num_comp_pkts *) skb->data; ++ __u16 *ptr; ++ int i; ++ ++ skb_pull(skb, EVT_NUM_COMP_PKTS_SIZE); ++ ++ BT_DBG("%s num_hndl %d", hdev->name, nc->num_hndl); ++ ++ if (skb->len < nc->num_hndl * 4) { ++ BT_DBG("%s bad parameters", hdev->name); ++ return; ++ } ++ ++ tasklet_disable(&hdev->tx_task); ++ ++ for (i = 0, ptr = (__u16 *) skb->data; i < nc->num_hndl; i++) { ++ struct hci_conn *conn; ++ __u16 handle, count; ++ ++ handle = __le16_to_cpu(get_unaligned(ptr++)); ++ count = __le16_to_cpu(get_unaligned(ptr++)); ++ ++ conn = conn_hash_lookup_handle(hdev, handle); ++ if (conn) { ++ conn->sent -= count; ++ ++ if (conn->type == SCO_LINK) { ++ if ((hdev->sco_cnt += count) > hdev->sco_pkts) ++ hdev->sco_cnt = hdev->sco_pkts; ++ } else { ++ if ((hdev->acl_cnt += count) > hdev->acl_pkts) ++ hdev->acl_cnt = hdev->acl_pkts; ++ } ++ } ++ } ++ hci_sched_tx(hdev); ++ ++ tasklet_enable(&hdev->tx_task); ++} ++ ++/* Role Change */ ++static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ evt_role_change *rc = (evt_role_change *) skb->data; ++ struct hci_conn *conn = NULL; ++ ++ BT_DBG("%s status %d", hdev->name, rc->status); ++ ++ if (rc->status) ++ return; ++ ++ hci_dev_lock(hdev); ++ ++ conn = conn_hash_lookup_ba(hdev, ACL_LINK, &rc->bdaddr); ++ if (conn) { ++ if (rc->role) ++ conn->link_mode &= ~HCI_LM_MASTER; ++ else ++ conn->link_mode |= HCI_LM_MASTER; ++ } ++ ++ hci_dev_unlock(hdev); ++} ++ ++/* Authentication Complete */ ++static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ evt_auth_complete *ac = (evt_auth_complete *) skb->data; ++ struct hci_conn *conn = NULL; ++ __u16 handle = __le16_to_cpu(ac->handle); ++ ++ BT_DBG("%s status %d", hdev->name, ac->status); ++ ++ hci_dev_lock(hdev); ++ ++ conn = conn_hash_lookup_handle(hdev, handle); ++ if (conn) { ++ if (!ac->status) ++ conn->link_mode |= HCI_LM_AUTH; ++ clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); ++ ++ hci_proto_auth_cfm(conn, ac->status); ++ ++ if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { ++ if (!ac->status) { ++ set_conn_encrypt_cp ce; ++ ce.handle = __cpu_to_le16(conn->handle); ++ ce.encrypt = 1; ++ hci_send_cmd(conn->hdev, OGF_LINK_CTL, ++ OCF_SET_CONN_ENCRYPT, ++ SET_CONN_ENCRYPT_CP_SIZE, &ce); ++ } else { ++ clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); ++ hci_proto_encrypt_cfm(conn, ac->status); ++ } ++ } ++ } ++ ++ hci_dev_unlock(hdev); ++} ++ ++/* Encryption Change */ ++static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ evt_encrypt_change *ec = (evt_encrypt_change *) skb->data; ++ struct hci_conn *conn = NULL; ++ __u16 handle = __le16_to_cpu(ec->handle); ++ ++ BT_DBG("%s status %d", hdev->name, ec->status); ++ ++ hci_dev_lock(hdev); ++ ++ conn = conn_hash_lookup_handle(hdev, handle); ++ if (conn) { ++ if (!ec->status) { ++ if (ec->encrypt) ++ conn->link_mode |= HCI_LM_ENCRYPT; ++ else ++ conn->link_mode &= ~HCI_LM_ENCRYPT; ++ } ++ clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); ++ ++ hci_proto_encrypt_cfm(conn, ec->status); ++ } ++ ++ hci_dev_unlock(hdev); ++} ++ ++void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ hci_event_hdr *he = (hci_event_hdr *) skb->data; ++ evt_cmd_status *cs; ++ evt_cmd_complete *ec; ++ __u16 opcode, ocf, ogf; ++ ++ skb_pull(skb, HCI_EVENT_HDR_SIZE); ++ ++ BT_DBG("%s evt 0x%x", hdev->name, he->evt); ++ ++ switch (he->evt) { ++ case EVT_NUM_COMP_PKTS: ++ hci_num_comp_pkts_evt(hdev, skb); ++ break; ++ ++ case EVT_INQUIRY_COMPLETE: ++ hci_inquiry_complete_evt(hdev, skb); ++ break; ++ ++ case EVT_INQUIRY_RESULT: ++ hci_inquiry_result_evt(hdev, skb); ++ break; ++ ++ case EVT_INQUIRY_RESULT_WITH_RSSI: ++ hci_inquiry_result_with_rssi_evt(hdev, skb); ++ break; ++ ++ case EVT_CONN_REQUEST: ++ hci_conn_request_evt(hdev, skb); ++ break; ++ ++ case EVT_CONN_COMPLETE: ++ hci_conn_complete_evt(hdev, skb); ++ break; ++ ++ case EVT_DISCONN_COMPLETE: ++ hci_disconn_complete_evt(hdev, skb); ++ break; ++ ++ case EVT_ROLE_CHANGE: ++ hci_role_change_evt(hdev, skb); ++ break; ++ ++ case EVT_AUTH_COMPLETE: ++ hci_auth_complete_evt(hdev, skb); ++ break; ++ ++ case EVT_ENCRYPT_CHANGE: ++ hci_encrypt_change_evt(hdev, skb); ++ break; ++ ++ case EVT_CMD_STATUS: ++ cs = (evt_cmd_status *) skb->data; ++ skb_pull(skb, EVT_CMD_STATUS_SIZE); ++ ++ opcode = __le16_to_cpu(cs->opcode); ++ ogf = cmd_opcode_ogf(opcode); ++ ocf = cmd_opcode_ocf(opcode); ++ ++ switch (ogf) { ++ case OGF_INFO_PARAM: ++ hci_cs_info_param(hdev, ocf, cs->status); ++ break; ++ ++ case OGF_HOST_CTL: ++ hci_cs_host_ctl(hdev, ocf, cs->status); ++ break; ++ ++ case OGF_LINK_CTL: ++ hci_cs_link_ctl(hdev, ocf, cs->status); ++ break; ++ ++ case OGF_LINK_POLICY: ++ hci_cs_link_policy(hdev, ocf, cs->status); ++ break; ++ ++ default: ++ BT_DBG("%s Command Status OGF %x", hdev->name, ogf); ++ break; ++ }; ++ ++ if (cs->ncmd) { ++ atomic_set(&hdev->cmd_cnt, 1); ++ if (!skb_queue_empty(&hdev->cmd_q)) ++ hci_sched_cmd(hdev); ++ } ++ break; ++ ++ case EVT_CMD_COMPLETE: ++ ec = (evt_cmd_complete *) skb->data; ++ skb_pull(skb, EVT_CMD_COMPLETE_SIZE); ++ ++ opcode = __le16_to_cpu(ec->opcode); ++ ogf = cmd_opcode_ogf(opcode); ++ ocf = cmd_opcode_ocf(opcode); ++ ++ switch (ogf) { ++ case OGF_INFO_PARAM: ++ hci_cc_info_param(hdev, ocf, skb); ++ break; ++ ++ case OGF_HOST_CTL: ++ hci_cc_host_ctl(hdev, ocf, skb); ++ break; ++ ++ case OGF_LINK_CTL: ++ hci_cc_link_ctl(hdev, ocf, skb); ++ break; ++ ++ case OGF_LINK_POLICY: ++ hci_cc_link_policy(hdev, ocf, skb); ++ break; ++ ++ default: ++ BT_DBG("%s Command Completed OGF %x", hdev->name, ogf); ++ break; ++ }; ++ ++ if (ec->ncmd) { ++ atomic_set(&hdev->cmd_cnt, 1); ++ if (!skb_queue_empty(&hdev->cmd_q)) ++ hci_sched_cmd(hdev); ++ } ++ break; ++ }; ++ ++ kfree_skb(skb); ++ hdev->stat.evt_rx++; ++} ++ ++/* General internal stack event */ ++void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) ++{ ++ hci_event_hdr *eh; ++ evt_stack_internal *si; ++ struct sk_buff *skb; ++ int size; ++ void *ptr; ++ ++ size = HCI_EVENT_HDR_SIZE + EVT_STACK_INTERNAL_SIZE + dlen; ++ skb = bluez_skb_alloc(size, GFP_ATOMIC); ++ if (!skb) ++ return; ++ ++ ptr = skb_put(skb, size); ++ ++ eh = ptr; ++ eh->evt = EVT_STACK_INTERNAL; ++ eh->plen = EVT_STACK_INTERNAL_SIZE + dlen; ++ ptr += HCI_EVENT_HDR_SIZE; ++ ++ si = ptr; ++ si->type = type; ++ memcpy(si->data, data, dlen); ++ ++ skb->pkt_type = HCI_EVENT_PKT; ++ skb->dev = (void *) hdev; ++ hci_send_to_sock(hdev, skb); ++ kfree_skb(skb); ++} +--- linux/net/bluetooth/hci_sock.c~bluetooth-2.4.18-mh11 2001-09-07 18:28:38.000000000 +0200 ++++ linux/net/bluetooth/hci_sock.c 2004-01-25 23:37:39.000000000 +0100 +@@ -25,7 +25,7 @@ + /* + * BlueZ HCI socket layer. + * +- * $Id$ ++ * $Id$ + */ + + #include <linux/config.h> +@@ -49,45 +49,54 @@ + + #include <asm/system.h> + #include <asm/uaccess.h> ++#include <asm/unaligned.h> + + #include <net/bluetooth/bluetooth.h> +-#include <net/bluetooth/bluez.h> + #include <net/bluetooth/hci_core.h> + + #ifndef HCI_SOCK_DEBUG +-#undef DBG +-#define DBG( A... ) ++#undef BT_DBG ++#define BT_DBG( A... ) + #endif + +-/* HCI socket interface */ ++/* ----- HCI socket interface ----- */ ++ ++/* Security filter */ ++static struct hci_sec_filter hci_sec_filter = { ++ /* Packet types */ ++ 0x10, ++ /* Events */ ++ { 0x1000d9fe, 0x0000300c }, ++ /* Commands */ ++ { ++ { 0x0 }, ++ /* OGF_LINK_CTL */ ++ { 0xbe000006, 0x00000001, 0x0000, 0x00 }, ++ /* OGF_LINK_POLICY */ ++ { 0x00005200, 0x00000000, 0x0000, 0x00 }, ++ /* OGF_HOST_CTL */ ++ { 0xaab00200, 0x2b402aaa, 0x0154, 0x00 }, ++ /* OGF_INFO_PARAM */ ++ { 0x000002be, 0x00000000, 0x0000, 0x00 }, ++ /* OGF_STATUS_PARAM */ ++ { 0x000000ea, 0x00000000, 0x0000, 0x00 } ++ } ++}; + + static struct bluez_sock_list hci_sk_list = { + lock: RW_LOCK_UNLOCKED + }; + +-static struct sock *hci_sock_lookup(struct hci_dev *hdev) +-{ +- struct sock *sk; +- +- read_lock(&hci_sk_list.lock); +- for (sk = hci_sk_list.head; sk; sk = sk->next) { +- if (hci_pi(sk)->hdev == hdev) +- break; +- } +- read_unlock(&hci_sk_list.lock); +- return sk; +-} +- + /* Send frame to RAW socket */ + void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) + { + struct sock * sk; + +- DBG("hdev %p len %d", hdev, skb->len); ++ BT_DBG("hdev %p len %d", hdev, skb->len); + + read_lock(&hci_sk_list.lock); + for (sk = hci_sk_list.head; sk; sk = sk->next) { +- struct hci_filter *flt; ++ struct hci_filter *flt; + struct sk_buff *nskb; + + if (sk->state != BT_BOUND || hci_pi(sk)->hdev != hdev) +@@ -100,13 +109,19 @@ + /* Apply filter */ + flt = &hci_pi(sk)->filter; + +- if (!test_bit(skb->pkt_type, &flt->type_mask)) ++ if (!hci_test_bit((skb->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask)) + continue; + + if (skb->pkt_type == HCI_EVENT_PKT) { +- register int evt = (*(__u8 *)skb->data & 63); ++ register int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS); ++ ++ if (!hci_test_bit(evt, &flt->event_mask)) ++ continue; + +- if (!test_bit(evt, &flt->event_mask)) ++ if (flt->opcode && ((evt == EVT_CMD_COMPLETE && ++ flt->opcode != *(__u16 *)(skb->data + 3)) || ++ (evt == EVT_CMD_STATUS && ++ flt->opcode != *(__u16 *)(skb->data + 4)))) + continue; + } + +@@ -116,8 +131,8 @@ + /* Put type byte before the data */ + memcpy(skb_push(nskb, 1), &nskb->pkt_type, 1); + +- skb_queue_tail(&sk->receive_queue, nskb); +- sk->data_ready(sk, nskb->len); ++ if (sock_queue_rcv_skb(sk, nskb)) ++ kfree_skb(nskb); + } + read_unlock(&hci_sk_list.lock); + } +@@ -127,7 +142,7 @@ + struct sock *sk = sock->sk; + struct hci_dev *hdev = hci_pi(sk)->hdev; + +- DBG("sock %p sk %p", sock, sk); ++ BT_DBG("sock %p sk %p", sock, sk); + + if (!sk) + return 0; +@@ -135,9 +150,7 @@ + bluez_sock_unlink(&hci_sk_list, sk); + + if (hdev) { +- if (!hci_sock_lookup(hdev)) +- hdev->flags &= ~HCI_SOCK; +- ++ atomic_dec(&hdev->promisc); + hci_dev_put(hdev); + } + +@@ -149,24 +162,55 @@ + sock_put(sk); + + MOD_DEC_USE_COUNT; +- + return 0; + } + +-static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ++/* Ioctls that require bound socket */ ++static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg) + { +- struct sock *sk = sock->sk; + struct hci_dev *hdev = hci_pi(sk)->hdev; +- __u32 mode; + +- DBG("cmd %x arg %lx", cmd, arg); ++ if (!hdev) ++ return -EBADFD; + + switch (cmd) { +- case HCIGETINFO: +- return hci_dev_info(arg); ++ case HCISETRAW: ++ if (!capable(CAP_NET_ADMIN)) ++ return -EACCES; ++ ++ if (arg) ++ set_bit(HCI_RAW, &hdev->flags); ++ else ++ clear_bit(HCI_RAW, &hdev->flags); ++ ++ return 0; ++ ++ case HCIGETCONNINFO: ++ return hci_get_conn_info(hdev, arg); + ++ default: ++ if (hdev->ioctl) ++ return hdev->ioctl(hdev, cmd, arg); ++ return -EINVAL; ++ } ++} ++ ++static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ++{ ++ struct sock *sk = sock->sk; ++ int err; ++ ++ BT_DBG("cmd %x arg %lx", cmd, arg); ++ ++ switch (cmd) { + case HCIGETDEVLIST: +- return hci_dev_list(arg); ++ return hci_get_dev_list(arg); ++ ++ case HCIGETDEVINFO: ++ return hci_get_dev_info(arg); ++ ++ case HCIGETCONNLIST: ++ return hci_get_conn_list(arg); + + case HCIDEVUP: + if (!capable(CAP_NET_ADMIN)) +@@ -183,48 +227,31 @@ + return -EACCES; + return hci_dev_reset(arg); + +- case HCIRESETSTAT: ++ case HCIDEVRESTAT: + if (!capable(CAP_NET_ADMIN)) + return -EACCES; + return hci_dev_reset_stat(arg); + + case HCISETSCAN: +- if (!capable(CAP_NET_ADMIN)) +- return -EACCES; +- return hci_dev_setscan(arg); +- + case HCISETAUTH: +- if (!capable(CAP_NET_ADMIN)) +- return -EACCES; +- return hci_dev_setauth(arg); +- +- case HCISETRAW: +- if (!capable(CAP_NET_ADMIN)) +- return -EACCES; +- +- if (!hdev) +- return -EBADFD; +- +- if (arg) +- mode = HCI_RAW; +- else +- mode = HCI_NORMAL; +- +- return hci_dev_setmode(hdev, mode); +- ++ case HCISETENCRYPT: + case HCISETPTYPE: ++ case HCISETLINKPOL: ++ case HCISETLINKMODE: ++ case HCISETACLMTU: ++ case HCISETSCOMTU: + if (!capable(CAP_NET_ADMIN)) + return -EACCES; +- return hci_dev_setptype(arg); ++ return hci_dev_cmd(cmd, arg); + + case HCIINQUIRY: + return hci_inquiry(arg); + +- case HCIGETCONNLIST: +- return hci_conn_list(arg); +- + default: +- return -EINVAL; ++ lock_sock(sk); ++ err = hci_sock_bound_ioctl(sk, cmd, arg); ++ release_sock(sk); ++ return err; + }; + } + +@@ -233,28 +260,35 @@ + struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr; + struct sock *sk = sock->sk; + struct hci_dev *hdev = NULL; ++ int err = 0; + +- DBG("sock %p sk %p", sock, sk); ++ BT_DBG("sock %p sk %p", sock, sk); + + if (!haddr || haddr->hci_family != AF_BLUETOOTH) + return -EINVAL; + ++ lock_sock(sk); ++ + if (hci_pi(sk)->hdev) { +- /* Already bound */ +- return 0; ++ err = -EALREADY; ++ goto done; + } + + if (haddr->hci_dev != HCI_DEV_NONE) { +- if (!(hdev = hci_dev_get(haddr->hci_dev))) +- return -ENODEV; ++ if (!(hdev = hci_dev_get(haddr->hci_dev))) { ++ err = -ENODEV; ++ goto done; ++ } + +- hdev->flags |= HCI_SOCK; ++ atomic_inc(&hdev->promisc); + } + + hci_pi(sk)->hdev = hdev; + sk->state = BT_BOUND; + +- return 0; ++done: ++ release_sock(sk); ++ return err; + } + + static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer) +@@ -262,73 +296,44 @@ + struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr; + struct sock *sk = sock->sk; + +- DBG("sock %p sk %p", sock, sk); ++ BT_DBG("sock %p sk %p", sock, sk); ++ ++ lock_sock(sk); + + *addr_len = sizeof(*haddr); + haddr->hci_family = AF_BLUETOOTH; + haddr->hci_dev = hci_pi(sk)->hdev->id; + ++ release_sock(sk); + return 0; + } + +-static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, +- struct scm_cookie *scm) +-{ +- struct sock *sk = sock->sk; +- struct hci_dev *hdev = hci_pi(sk)->hdev; +- struct sk_buff *skb; +- int err; +- +- DBG("sock %p sk %p", sock, sk); +- +- if (msg->msg_flags & MSG_OOB) +- return -EOPNOTSUPP; +- +- if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE)) +- return -EINVAL; +- +- if (!hdev) +- return -EBADFD; +- +- if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err))) +- return err; +- +- if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { +- kfree_skb(skb); +- return -EFAULT; +- } +- +- skb->dev = (void *) hdev; +- skb->pkt_type = *((unsigned char *) skb->data); +- skb_pull(skb, 1); +- +- /* Send frame to HCI core */ +- hci_send_raw(skb); +- +- return len; +-} +- + static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) + { + __u32 mask = hci_pi(sk)->cmsg_mask; + + if (mask & HCI_CMSG_DIR) + put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(int), &bluez_cb(skb)->incomming); ++ ++ if (mask & HCI_CMSG_TSTAMP) ++ put_cmsg(msg, SOL_HCI, HCI_CMSG_TSTAMP, sizeof(skb->stamp), &skb->stamp); + } + +-static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, +- int flags, struct scm_cookie *scm) ++static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm) + { + int noblock = flags & MSG_DONTWAIT; + struct sock *sk = sock->sk; + struct sk_buff *skb; + int copied, err; + +- DBG("sock %p sk %p", sock, sk); ++ BT_DBG("sock %p, sk %p", sock, sk); + +- if (flags & (MSG_OOB | MSG_PEEK)) ++ if (flags & (MSG_OOB)) + return -EOPNOTSUPP; + ++ if (sk->state == BT_CLOSED) ++ return 0; ++ + if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) + return err; + +@@ -343,28 +348,107 @@ + skb->h.raw = skb->data; + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + +- if (hci_pi(sk)->cmsg_mask) +- hci_sock_cmsg(sk, msg, skb); +- ++ hci_sock_cmsg(sk, msg, skb); ++ + skb_free_datagram(sk, skb); + + return err ? : copied; + } + ++static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, ++ struct scm_cookie *scm) ++{ ++ struct sock *sk = sock->sk; ++ struct hci_dev *hdev; ++ struct sk_buff *skb; ++ int err; ++ ++ BT_DBG("sock %p sk %p", sock, sk); ++ ++ if (msg->msg_flags & MSG_OOB) ++ return -EOPNOTSUPP; ++ ++ if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE)) ++ return -EINVAL; ++ ++ if (len < 4) ++ return -EINVAL; ++ ++ lock_sock(sk); ++ ++ if (!(hdev = hci_pi(sk)->hdev)) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err))) ++ goto done; ++ ++ if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { ++ err = -EFAULT; ++ goto drop; ++ } ++ ++ skb->pkt_type = *((unsigned char *) skb->data); ++ skb_pull(skb, 1); ++ skb->dev = (void *) hdev; ++ ++ if (skb->pkt_type == HCI_COMMAND_PKT) { ++ u16 opcode = __le16_to_cpu(get_unaligned((u16 *)skb->data)); ++ u16 ogf = cmd_opcode_ogf(opcode); ++ u16 ocf = cmd_opcode_ocf(opcode); ++ ++ if (((ogf > HCI_SFLT_MAX_OGF) || ++ !hci_test_bit(ocf & HCI_FLT_OCF_BITS, &hci_sec_filter.ocf_mask[ogf])) && ++ !capable(CAP_NET_RAW)) { ++ err = -EPERM; ++ goto drop; ++ } ++ ++ if (test_bit(HCI_RAW, &hdev->flags) || (ogf == OGF_VENDOR_CMD)) { ++ skb_queue_tail(&hdev->raw_q, skb); ++ hci_sched_tx(hdev); ++ } else { ++ skb_queue_tail(&hdev->cmd_q, skb); ++ hci_sched_cmd(hdev); ++ } ++ } else { ++ if (!capable(CAP_NET_RAW)) { ++ err = -EPERM; ++ goto drop; ++ } ++ ++ skb_queue_tail(&hdev->raw_q, skb); ++ hci_sched_tx(hdev); ++ } ++ ++ err = len; ++ ++done: ++ release_sock(sk); ++ return err; ++ ++drop: ++ kfree_skb(skb); ++ goto done; ++} ++ + int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int len) + { + struct sock *sk = sock->sk; +- struct hci_filter flt; ++ struct hci_filter flt = { opcode: 0 }; + int err = 0, opt = 0; + +- DBG("sk %p, opt %d", sk, optname); ++ BT_DBG("sk %p, opt %d", sk, optname); + + lock_sock(sk); + + switch (optname) { + case HCI_DATA_DIR: +- if (get_user(opt, (int *)optval)) +- return -EFAULT; ++ if (get_user(opt, (int *)optval)) { ++ err = -EFAULT; ++ break; ++ } + + if (opt) + hci_pi(sk)->cmsg_mask |= HCI_CMSG_DIR; +@@ -372,12 +456,31 @@ + hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_DIR; + break; + ++ case HCI_TIME_STAMP: ++ if (get_user(opt, (int *)optval)) { ++ err = -EFAULT; ++ break; ++ } ++ ++ if (opt) ++ hci_pi(sk)->cmsg_mask |= HCI_CMSG_TSTAMP; ++ else ++ hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_TSTAMP; ++ break; ++ + case HCI_FILTER: + len = MIN(len, sizeof(struct hci_filter)); + if (copy_from_user(&flt, optval, len)) { + err = -EFAULT; + break; + } ++ ++ if (!capable(CAP_NET_RAW)) { ++ flt.type_mask &= hci_sec_filter.type_mask; ++ flt.event_mask[0] &= hci_sec_filter.event_mask[0]; ++ flt.event_mask[1] &= hci_sec_filter.event_mask[1]; ++ } ++ + memcpy(&hci_pi(sk)->filter, &flt, len); + break; + +@@ -409,6 +512,16 @@ + return -EFAULT; + break; + ++ case HCI_TIME_STAMP: ++ if (hci_pi(sk)->cmsg_mask & HCI_CMSG_TSTAMP) ++ opt = 1; ++ else ++ opt = 0; ++ ++ if (put_user(opt, optval)) ++ return -EFAULT; ++ break; ++ + case HCI_FILTER: + len = MIN(len, sizeof(struct hci_filter)); + if (copy_to_user(optval, &hci_pi(sk)->filter, len)) +@@ -446,7 +559,7 @@ + { + struct sock *sk; + +- DBG("sock %p", sock); ++ BT_DBG("sock %p", sock); + + if (sock->type != SOCK_RAW) + return -ESOCKTNOSUPPORT; +@@ -464,44 +577,31 @@ + sk->protocol = protocol; + sk->state = BT_OPEN; + +- /* Initialize filter */ +- hci_pi(sk)->filter.type_mask = (1<<HCI_EVENT_PKT); +- hci_pi(sk)->filter.event_mask[0] = ~0L; +- hci_pi(sk)->filter.event_mask[1] = ~0L; +- + bluez_sock_link(&hci_sk_list, sk); + + MOD_INC_USE_COUNT; +- + return 0; + } + + static int hci_sock_dev_event(struct notifier_block *this, unsigned long event, void *ptr) + { + struct hci_dev *hdev = (struct hci_dev *) ptr; +- struct sk_buff *skb; +- +- DBG("hdev %s event %ld", hdev->name, event); ++ evt_si_device sd; ++ ++ BT_DBG("hdev %s event %ld", hdev->name, event); + + /* Send event to sockets */ +- if ((skb = bluez_skb_alloc(HCI_EVENT_HDR_SIZE + EVT_HCI_DEV_EVENT_SIZE, GFP_ATOMIC))) { +- hci_event_hdr eh = { EVT_HCI_DEV_EVENT, EVT_HCI_DEV_EVENT_SIZE }; +- evt_hci_dev_event he = { event, hdev->id }; +- +- skb->pkt_type = HCI_EVENT_PKT; +- memcpy(skb_put(skb, HCI_EVENT_HDR_SIZE), &eh, HCI_EVENT_HDR_SIZE); +- memcpy(skb_put(skb, EVT_HCI_DEV_EVENT_SIZE), &he, EVT_HCI_DEV_EVENT_SIZE); +- +- hci_send_to_sock(NULL, skb); +- kfree_skb(skb); +- } +- ++ sd.event = event; ++ sd.dev_id = hdev->id; ++ hci_si_event(NULL, EVT_SI_DEVICE, EVT_SI_DEVICE_SIZE, &sd); ++ + if (event == HCI_DEV_UNREG) { + struct sock *sk; + + /* Detach sockets from device */ + read_lock(&hci_sk_list.lock); + for (sk = hci_sk_list.head; sk; sk = sk->next) { ++ bh_lock_sock(sk); + if (hci_pi(sk)->hdev == hdev) { + hci_pi(sk)->hdev = NULL; + sk->err = EPIPE; +@@ -510,6 +610,7 @@ + + hci_dev_put(hdev); + } ++ bh_unlock_sock(sk); + } + read_unlock(&hci_sk_list.lock); + } +@@ -529,21 +630,19 @@ + int hci_sock_init(void) + { + if (bluez_sock_register(BTPROTO_HCI, &hci_sock_family_ops)) { +- ERR("Can't register HCI socket"); ++ BT_ERR("Can't register HCI socket"); + return -EPROTO; + } + + hci_register_notifier(&hci_sock_nblock); +- + return 0; + } + + int hci_sock_cleanup(void) + { + if (bluez_sock_unregister(BTPROTO_HCI)) +- ERR("Can't unregister HCI socket"); ++ BT_ERR("Can't unregister HCI socket"); + + hci_unregister_notifier(&hci_sock_nblock); +- + return 0; + } +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/l2cap.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,2187 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * BlueZ L2CAP core and sockets. ++ * ++ * $Id$ ++ */ ++#define VERSION "2.3" ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/init.h> ++#include <linux/skbuff.h> ++#include <linux/interrupt.h> ++#include <linux/socket.h> ++#include <linux/skbuff.h> ++#include <linux/proc_fs.h> ++#include <linux/list.h> ++#include <net/sock.h> ++ ++#include <asm/system.h> ++#include <asm/uaccess.h> ++#include <asm/unaligned.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++#include <net/bluetooth/l2cap.h> ++ ++#ifndef L2CAP_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#endif ++ ++static struct proto_ops l2cap_sock_ops; ++ ++struct bluez_sock_list l2cap_sk_list = { ++ lock: RW_LOCK_UNLOCKED ++}; ++ ++static int l2cap_conn_del(struct hci_conn *conn, int err); ++ ++static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent); ++static void l2cap_chan_del(struct sock *sk, int err); ++static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len); ++ ++static void __l2cap_sock_close(struct sock *sk, int reason); ++static void l2cap_sock_close(struct sock *sk); ++static void l2cap_sock_kill(struct sock *sk); ++ ++static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data); ++static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data); ++ ++/* ----- L2CAP timers ------ */ ++static void l2cap_sock_timeout(unsigned long arg) ++{ ++ struct sock *sk = (struct sock *) arg; ++ ++ BT_DBG("sock %p state %d", sk, sk->state); ++ ++ bh_lock_sock(sk); ++ __l2cap_sock_close(sk, ETIMEDOUT); ++ bh_unlock_sock(sk); ++ ++ l2cap_sock_kill(sk); ++ sock_put(sk); ++} ++ ++static void l2cap_sock_set_timer(struct sock *sk, long timeout) ++{ ++ BT_DBG("sk %p state %d timeout %ld", sk, sk->state, timeout); ++ ++ if (!mod_timer(&sk->timer, jiffies + timeout)) ++ sock_hold(sk); ++} ++ ++static void l2cap_sock_clear_timer(struct sock *sk) ++{ ++ BT_DBG("sock %p state %d", sk, sk->state); ++ ++ if (timer_pending(&sk->timer) && del_timer(&sk->timer)) ++ __sock_put(sk); ++} ++ ++static void l2cap_sock_init_timer(struct sock *sk) ++{ ++ init_timer(&sk->timer); ++ sk->timer.function = l2cap_sock_timeout; ++ sk->timer.data = (unsigned long)sk; ++} ++ ++/* -------- L2CAP connections --------- */ ++static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, __u8 status) ++{ ++ struct l2cap_conn *conn; ++ ++ if ((conn = hcon->l2cap_data)) ++ return conn; ++ ++ if (status) ++ return conn; ++ ++ if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_ATOMIC))) ++ return NULL; ++ memset(conn, 0, sizeof(struct l2cap_conn)); ++ ++ hcon->l2cap_data = conn; ++ conn->hcon = hcon; ++ ++ conn->mtu = hcon->hdev->acl_mtu; ++ conn->src = &hcon->hdev->bdaddr; ++ conn->dst = &hcon->dst; ++ ++ spin_lock_init(&conn->lock); ++ conn->chan_list.lock = RW_LOCK_UNLOCKED; ++ ++ BT_DBG("hcon %p conn %p", hcon, conn); ++ ++ MOD_INC_USE_COUNT; ++ return conn; ++} ++ ++static int l2cap_conn_del(struct hci_conn *hcon, int err) ++{ ++ struct l2cap_conn *conn; ++ struct sock *sk; ++ ++ if (!(conn = hcon->l2cap_data)) ++ return 0; ++ ++ BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); ++ ++ if (conn->rx_skb) ++ kfree_skb(conn->rx_skb); ++ ++ /* Kill channels */ ++ while ((sk = conn->chan_list.head)) { ++ bh_lock_sock(sk); ++ l2cap_chan_del(sk, err); ++ bh_unlock_sock(sk); ++ l2cap_sock_kill(sk); ++ } ++ ++ hcon->l2cap_data = NULL; ++ kfree(conn); ++ ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++/* -------- Socket interface ---------- */ ++static struct sock *__l2cap_get_sock_by_addr(__u16 psm, bdaddr_t *src) ++{ ++ struct sock *sk; ++ for (sk = l2cap_sk_list.head; sk; sk = sk->next) { ++ if (sk->sport == psm && !bacmp(&bluez_pi(sk)->src, src)) ++ break; ++ } ++ return sk; ++} ++ ++/* Find socket with psm and source bdaddr. ++ * Returns closest match. ++ */ ++static struct sock *__l2cap_get_sock_by_psm(int state, __u16 psm, bdaddr_t *src) ++{ ++ struct sock *sk, *sk1 = NULL; ++ ++ for (sk = l2cap_sk_list.head; sk; sk = sk->next) { ++ if (state && sk->state != state) ++ continue; ++ ++ if (l2cap_pi(sk)->psm == psm) { ++ /* Exact match. */ ++ if (!bacmp(&bluez_pi(sk)->src, src)) ++ break; ++ ++ /* Closest match */ ++ if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY)) ++ sk1 = sk; ++ } ++ } ++ return sk ? sk : sk1; ++} ++ ++/* Find socket with given address (psm, src). ++ * Returns locked socket */ ++static inline struct sock *l2cap_get_sock_by_psm(int state, __u16 psm, bdaddr_t *src) ++{ ++ struct sock *s; ++ read_lock(&l2cap_sk_list.lock); ++ s = __l2cap_get_sock_by_psm(state, psm, src); ++ if (s) bh_lock_sock(s); ++ read_unlock(&l2cap_sk_list.lock); ++ return s; ++} ++ ++static void l2cap_sock_destruct(struct sock *sk) ++{ ++ BT_DBG("sk %p", sk); ++ ++ skb_queue_purge(&sk->receive_queue); ++ skb_queue_purge(&sk->write_queue); ++ ++ MOD_DEC_USE_COUNT; ++} ++ ++static void l2cap_sock_cleanup_listen(struct sock *parent) ++{ ++ struct sock *sk; ++ ++ BT_DBG("parent %p", parent); ++ ++ /* Close not yet accepted channels */ ++ while ((sk = bluez_accept_dequeue(parent, NULL))) ++ l2cap_sock_close(sk); ++ ++ parent->state = BT_CLOSED; ++ parent->zapped = 1; ++} ++ ++/* Kill socket (only if zapped and orphan) ++ * Must be called on unlocked socket. ++ */ ++static void l2cap_sock_kill(struct sock *sk) ++{ ++ if (!sk->zapped || sk->socket) ++ return; ++ ++ BT_DBG("sk %p state %d", sk, sk->state); ++ ++ /* Kill poor orphan */ ++ bluez_sock_unlink(&l2cap_sk_list, sk); ++ sk->dead = 1; ++ sock_put(sk); ++} ++ ++/* Close socket. ++ */ ++static void __l2cap_sock_close(struct sock *sk, int reason) ++{ ++ BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket); ++ ++ switch (sk->state) { ++ case BT_LISTEN: ++ l2cap_sock_cleanup_listen(sk); ++ break; ++ ++ case BT_CONNECTED: ++ case BT_CONFIG: ++ case BT_CONNECT2: ++ if (sk->type == SOCK_SEQPACKET) { ++ struct l2cap_conn *conn = l2cap_pi(sk)->conn; ++ l2cap_disconn_req req; ++ ++ sk->state = BT_DISCONN; ++ l2cap_sock_set_timer(sk, sk->sndtimeo); ++ ++ req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid); ++ req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); ++ l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req); ++ } else { ++ l2cap_chan_del(sk, reason); ++ } ++ break; ++ ++ case BT_CONNECT: ++ case BT_DISCONN: ++ l2cap_chan_del(sk, reason); ++ break; ++ ++ default: ++ sk->zapped = 1; ++ break; ++ }; ++} ++ ++/* Must be called on unlocked socket. */ ++static void l2cap_sock_close(struct sock *sk) ++{ ++ l2cap_sock_clear_timer(sk); ++ lock_sock(sk); ++ __l2cap_sock_close(sk, ECONNRESET); ++ release_sock(sk); ++ l2cap_sock_kill(sk); ++} ++ ++static void l2cap_sock_init(struct sock *sk, struct sock *parent) ++{ ++ struct l2cap_pinfo *pi = l2cap_pi(sk); ++ ++ BT_DBG("sk %p", sk); ++ ++ if (parent) { ++ sk->type = parent->type; ++ pi->imtu = l2cap_pi(parent)->imtu; ++ pi->omtu = l2cap_pi(parent)->omtu; ++ pi->link_mode = l2cap_pi(parent)->link_mode; ++ } else { ++ pi->imtu = L2CAP_DEFAULT_MTU; ++ pi->omtu = 0; ++ pi->link_mode = 0; ++ } ++ ++ /* Default config options */ ++ pi->conf_mtu = L2CAP_DEFAULT_MTU; ++ pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; ++} ++ ++static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio) ++{ ++ struct sock *sk; ++ ++ if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1))) ++ return NULL; ++ ++ bluez_sock_init(sock, sk); ++ ++ sk->zapped = 0; ++ ++ sk->destruct = l2cap_sock_destruct; ++ sk->sndtimeo = L2CAP_CONN_TIMEOUT; ++ ++ sk->protocol = proto; ++ sk->state = BT_OPEN; ++ ++ l2cap_sock_init_timer(sk); ++ ++ bluez_sock_link(&l2cap_sk_list, sk); ++ ++ MOD_INC_USE_COUNT; ++ return sk; ++} ++ ++static int l2cap_sock_create(struct socket *sock, int protocol) ++{ ++ struct sock *sk; ++ ++ BT_DBG("sock %p", sock); ++ ++ sock->state = SS_UNCONNECTED; ++ ++ if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_DGRAM && sock->type != SOCK_RAW) ++ return -ESOCKTNOSUPPORT; ++ ++ if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW)) ++ return -EPERM; ++ ++ sock->ops = &l2cap_sock_ops; ++ ++ if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL))) ++ return -ENOMEM; ++ ++ l2cap_sock_init(sk, NULL); ++ return 0; ++} ++ ++static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) ++{ ++ struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm); ++ ++ if (!addr || addr->sa_family != AF_BLUETOOTH) ++ return -EINVAL; ++ ++ lock_sock(sk); ++ ++ if (sk->state != BT_OPEN) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ write_lock_bh(&l2cap_sk_list.lock); ++ if (la->l2_psm && __l2cap_get_sock_by_addr(la->l2_psm, &la->l2_bdaddr)) { ++ err = -EADDRINUSE; ++ } else { ++ /* Save source address */ ++ bacpy(&bluez_pi(sk)->src, &la->l2_bdaddr); ++ l2cap_pi(sk)->psm = la->l2_psm; ++ sk->sport = la->l2_psm; ++ sk->state = BT_BOUND; ++ } ++ write_unlock_bh(&l2cap_sk_list.lock); ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++static int l2cap_do_connect(struct sock *sk) ++{ ++ bdaddr_t *src = &bluez_pi(sk)->src; ++ bdaddr_t *dst = &bluez_pi(sk)->dst; ++ struct l2cap_conn *conn; ++ struct hci_conn *hcon; ++ struct hci_dev *hdev; ++ int err = 0; ++ ++ BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm); ++ ++ if (!(hdev = hci_get_route(dst, src))) ++ return -EHOSTUNREACH; ++ ++ hci_dev_lock_bh(hdev); ++ ++ err = -ENOMEM; ++ ++ hcon = hci_connect(hdev, ACL_LINK, dst); ++ if (!hcon) ++ goto done; ++ ++ conn = l2cap_conn_add(hcon, 0); ++ if (!conn) { ++ hci_conn_put(hcon); ++ goto done; ++ } ++ ++ err = 0; ++ ++ /* Update source addr of the socket */ ++ bacpy(src, conn->src); ++ ++ l2cap_chan_add(conn, sk, NULL); ++ ++ sk->state = BT_CONNECT; ++ l2cap_sock_set_timer(sk, sk->sndtimeo); ++ ++ if (hcon->state == BT_CONNECTED) { ++ if (sk->type == SOCK_SEQPACKET) { ++ l2cap_conn_req req; ++ req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); ++ req.psm = l2cap_pi(sk)->psm; ++ l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req); ++ } else { ++ l2cap_sock_clear_timer(sk); ++ sk->state = BT_CONNECTED; ++ } ++ } ++ ++done: ++ hci_dev_unlock_bh(hdev); ++ hci_dev_put(hdev); ++ return err; ++} ++ ++static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) ++{ ++ struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ lock_sock(sk); ++ ++ BT_DBG("sk %p", sk); ++ ++ if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) { ++ err = -EINVAL; ++ goto done; ++ } ++ ++ if (sk->type == SOCK_SEQPACKET && !la->l2_psm) { ++ err = -EINVAL; ++ goto done; ++ } ++ ++ switch(sk->state) { ++ case BT_CONNECT: ++ case BT_CONNECT2: ++ case BT_CONFIG: ++ /* Already connecting */ ++ goto wait; ++ ++ case BT_CONNECTED: ++ /* Already connected */ ++ goto done; ++ ++ case BT_OPEN: ++ case BT_BOUND: ++ /* Can connect */ ++ break; ++ ++ default: ++ err = -EBADFD; ++ goto done; ++ } ++ ++ /* Set destination address and psm */ ++ bacpy(&bluez_pi(sk)->dst, &la->l2_bdaddr); ++ l2cap_pi(sk)->psm = la->l2_psm; ++ ++ if ((err = l2cap_do_connect(sk))) ++ goto done; ++ ++wait: ++ err = bluez_sock_wait_state(sk, BT_CONNECTED, ++ sock_sndtimeo(sk, flags & O_NONBLOCK)); ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++int l2cap_sock_listen(struct socket *sock, int backlog) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sk %p backlog %d", sk, backlog); ++ ++ lock_sock(sk); ++ ++ if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ if (!l2cap_pi(sk)->psm) { ++ err = -EINVAL; ++ goto done; ++ } ++ ++ sk->max_ack_backlog = backlog; ++ sk->ack_backlog = 0; ++ sk->state = BT_LISTEN; ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ struct sock *sk = sock->sk, *nsk; ++ long timeo; ++ int err = 0; ++ ++ lock_sock(sk); ++ ++ if (sk->state != BT_LISTEN) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); ++ ++ BT_DBG("sk %p timeo %ld", sk, timeo); ++ ++ /* Wait for an incoming connection. (wake-one). */ ++ add_wait_queue_exclusive(sk->sleep, &wait); ++ while (!(nsk = bluez_accept_dequeue(sk, newsock))) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ if (!timeo) { ++ err = -EAGAIN; ++ break; ++ } ++ ++ release_sock(sk); ++ timeo = schedule_timeout(timeo); ++ lock_sock(sk); ++ ++ if (sk->state != BT_LISTEN) { ++ err = -EBADFD; ++ break; ++ } ++ ++ if (signal_pending(current)) { ++ err = sock_intr_errno(timeo); ++ break; ++ } ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(sk->sleep, &wait); ++ ++ if (err) ++ goto done; ++ ++ newsock->state = SS_CONNECTED; ++ ++ BT_DBG("new socket %p", nsk); ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer) ++{ ++ struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; ++ struct sock *sk = sock->sk; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ addr->sa_family = AF_BLUETOOTH; ++ *len = sizeof(struct sockaddr_l2); ++ ++ if (peer) ++ bacpy(&la->l2_bdaddr, &bluez_pi(sk)->dst); ++ else ++ bacpy(&la->l2_bdaddr, &bluez_pi(sk)->src); ++ ++ la->l2_psm = l2cap_pi(sk)->psm; ++ return 0; ++} ++ ++static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ if (sk->err) ++ return sock_error(sk); ++ ++ if (msg->msg_flags & MSG_OOB) ++ return -EOPNOTSUPP; ++ ++ /* Check outgoing MTU */ ++ if (len > l2cap_pi(sk)->omtu) ++ return -EINVAL; ++ ++ lock_sock(sk); ++ ++ if (sk->state == BT_CONNECTED) ++ err = l2cap_chan_send(sk, msg, len); ++ else ++ err = -ENOTCONN; ++ ++ release_sock(sk); ++ return err; ++} ++ ++static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) ++{ ++ struct sock *sk = sock->sk; ++ struct l2cap_options opts; ++ int err = 0, len; ++ __u32 opt; ++ ++ BT_DBG("sk %p", sk); ++ ++ lock_sock(sk); ++ ++ switch (optname) { ++ case L2CAP_OPTIONS: ++ len = MIN(sizeof(opts), optlen); ++ if (copy_from_user((char *)&opts, optval, len)) { ++ err = -EFAULT; ++ break; ++ } ++ l2cap_pi(sk)->imtu = opts.imtu; ++ l2cap_pi(sk)->omtu = opts.omtu; ++ break; ++ ++ case L2CAP_LM: ++ if (get_user(opt, (__u32 *)optval)) { ++ err = -EFAULT; ++ break; ++ } ++ ++ l2cap_pi(sk)->link_mode = opt; ++ break; ++ ++ default: ++ err = -ENOPROTOOPT; ++ break; ++ } ++ ++ release_sock(sk); ++ return err; ++} ++ ++static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) ++{ ++ struct sock *sk = sock->sk; ++ struct l2cap_options opts; ++ struct l2cap_conninfo cinfo; ++ int len, err = 0; ++ ++ if (get_user(len, optlen)) ++ return -EFAULT; ++ ++ lock_sock(sk); ++ ++ switch (optname) { ++ case L2CAP_OPTIONS: ++ opts.imtu = l2cap_pi(sk)->imtu; ++ opts.omtu = l2cap_pi(sk)->omtu; ++ opts.flush_to = l2cap_pi(sk)->flush_to; ++ ++ len = MIN(len, sizeof(opts)); ++ if (copy_to_user(optval, (char *)&opts, len)) ++ err = -EFAULT; ++ ++ break; ++ ++ case L2CAP_LM: ++ if (put_user(l2cap_pi(sk)->link_mode, (__u32 *)optval)) ++ err = -EFAULT; ++ break; ++ ++ case L2CAP_CONNINFO: ++ if (sk->state != BT_CONNECTED) { ++ err = -ENOTCONN; ++ break; ++ } ++ ++ cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle; ++ ++ len = MIN(len, sizeof(cinfo)); ++ if (copy_to_user(optval, (char *)&cinfo, len)) ++ err = -EFAULT; ++ ++ break; ++ ++ default: ++ err = -ENOPROTOOPT; ++ break; ++ } ++ ++ release_sock(sk); ++ return err; ++} ++ ++static int l2cap_sock_shutdown(struct socket *sock, int how) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ if (!sk) return 0; ++ ++ lock_sock(sk); ++ if (!sk->shutdown) { ++ sk->shutdown = SHUTDOWN_MASK; ++ l2cap_sock_clear_timer(sk); ++ __l2cap_sock_close(sk, 0); ++ ++ if (sk->linger) ++ err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime); ++ } ++ release_sock(sk); ++ return err; ++} ++ ++static int l2cap_sock_release(struct socket *sock) ++{ ++ struct sock *sk = sock->sk; ++ int err; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ if (!sk) return 0; ++ ++ err = l2cap_sock_shutdown(sock, 2); ++ ++ sock_orphan(sk); ++ l2cap_sock_kill(sk); ++ return err; ++} ++ ++/* --------- L2CAP channels --------- */ ++static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid) ++{ ++ struct sock *s; ++ for (s = l->head; s; s = l2cap_pi(s)->next_c) { ++ if (l2cap_pi(s)->dcid == cid) ++ break; ++ } ++ return s; ++} ++ ++static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid) ++{ ++ struct sock *s; ++ for (s = l->head; s; s = l2cap_pi(s)->next_c) { ++ if (l2cap_pi(s)->scid == cid) ++ break; ++ } ++ return s; ++} ++ ++/* Find channel with given SCID. ++ * Returns locked socket */ ++static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid) ++{ ++ struct sock *s; ++ read_lock(&l->lock); ++ s = __l2cap_get_chan_by_scid(l, cid); ++ if (s) bh_lock_sock(s); ++ read_unlock(&l->lock); ++ return s; ++} ++ ++static __u16 l2cap_alloc_cid(struct l2cap_chan_list *l) ++{ ++ __u16 cid = 0x0040; ++ ++ for (; cid < 0xffff; cid++) { ++ if(!__l2cap_get_chan_by_scid(l, cid)) ++ return cid; ++ } ++ ++ return 0; ++} ++ ++static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk) ++{ ++ sock_hold(sk); ++ ++ if (l->head) ++ l2cap_pi(l->head)->prev_c = sk; ++ ++ l2cap_pi(sk)->next_c = l->head; ++ l2cap_pi(sk)->prev_c = NULL; ++ l->head = sk; ++} ++ ++static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) ++{ ++ struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c; ++ ++ write_lock(&l->lock); ++ if (sk == l->head) ++ l->head = next; ++ ++ if (next) ++ l2cap_pi(next)->prev_c = prev; ++ if (prev) ++ l2cap_pi(prev)->next_c = next; ++ write_unlock(&l->lock); ++ ++ __sock_put(sk); ++} ++ ++static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) ++{ ++ struct l2cap_chan_list *l = &conn->chan_list; ++ ++ BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); ++ ++ l2cap_pi(sk)->conn = conn; ++ ++ if (sk->type == SOCK_SEQPACKET) { ++ /* Alloc CID for connection-oriented socket */ ++ l2cap_pi(sk)->scid = l2cap_alloc_cid(l); ++ } else if (sk->type == SOCK_DGRAM) { ++ /* Connectionless socket */ ++ l2cap_pi(sk)->scid = 0x0002; ++ l2cap_pi(sk)->dcid = 0x0002; ++ l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; ++ } else { ++ /* Raw socket can send/recv signalling messages only */ ++ l2cap_pi(sk)->scid = 0x0001; ++ l2cap_pi(sk)->dcid = 0x0001; ++ l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; ++ } ++ ++ __l2cap_chan_link(l, sk); ++ ++ if (parent) ++ bluez_accept_enqueue(parent, sk); ++} ++ ++static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) ++{ ++ struct l2cap_chan_list *l = &conn->chan_list; ++ write_lock(&l->lock); ++ __l2cap_chan_add(conn, sk, parent); ++ write_unlock(&l->lock); ++} ++ ++/* Delete channel. ++ * Must be called on the locked socket. */ ++static void l2cap_chan_del(struct sock *sk, int err) ++{ ++ struct l2cap_conn *conn = l2cap_pi(sk)->conn; ++ struct sock *parent = bluez_pi(sk)->parent; ++ ++ l2cap_sock_clear_timer(sk); ++ ++ BT_DBG("sk %p, conn %p, err %d", sk, conn, err); ++ ++ if (conn) { ++ /* Unlink from channel list */ ++ l2cap_chan_unlink(&conn->chan_list, sk); ++ l2cap_pi(sk)->conn = NULL; ++ hci_conn_put(conn->hcon); ++ } ++ ++ sk->state = BT_CLOSED; ++ sk->zapped = 1; ++ ++ if (err) ++ sk->err = err; ++ ++ if (parent) ++ parent->data_ready(parent, 0); ++ else ++ sk->state_change(sk); ++} ++ ++static void l2cap_conn_ready(struct l2cap_conn *conn) ++{ ++ struct l2cap_chan_list *l = &conn->chan_list; ++ struct sock *sk; ++ ++ BT_DBG("conn %p", conn); ++ ++ read_lock(&l->lock); ++ ++ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { ++ bh_lock_sock(sk); ++ ++ if (sk->type != SOCK_SEQPACKET) { ++ l2cap_sock_clear_timer(sk); ++ sk->state = BT_CONNECTED; ++ sk->state_change(sk); ++ } else if (sk->state == BT_CONNECT) { ++ l2cap_conn_req req; ++ req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); ++ req.psm = l2cap_pi(sk)->psm; ++ l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req); ++ } ++ ++ bh_unlock_sock(sk); ++ } ++ ++ read_unlock(&l->lock); ++} ++ ++/* Notify sockets that we cannot guaranty reliability anymore */ ++static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) ++{ ++ struct l2cap_chan_list *l = &conn->chan_list; ++ struct sock *sk; ++ ++ BT_DBG("conn %p", conn); ++ ++ read_lock(&l->lock); ++ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { ++ if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE) ++ sk->err = err; ++ } ++ read_unlock(&l->lock); ++} ++ ++static void l2cap_chan_ready(struct sock *sk) ++{ ++ struct sock *parent = bluez_pi(sk)->parent; ++ ++ BT_DBG("sk %p, parent %p", sk, parent); ++ ++ l2cap_pi(sk)->conf_state = 0; ++ l2cap_sock_clear_timer(sk); ++ ++ if (!parent) { ++ /* Outgoing channel. ++ * Wake up socket sleeping on connect. ++ */ ++ sk->state = BT_CONNECTED; ++ sk->state_change(sk); ++ } else { ++ /* Incomming channel. ++ * Wake up socket sleeping on accept. ++ */ ++ parent->data_ready(parent, 0); ++ } ++} ++ ++/* Copy frame to all raw sockets on that connection */ ++void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) ++{ ++ struct l2cap_chan_list *l = &conn->chan_list; ++ struct sk_buff *nskb; ++ struct sock * sk; ++ ++ BT_DBG("conn %p", conn); ++ ++ read_lock(&l->lock); ++ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { ++ if (sk->type != SOCK_RAW) ++ continue; ++ ++ /* Don't send frame to the socket it came from */ ++ if (skb->sk == sk) ++ continue; ++ ++ if (!(nskb = skb_clone(skb, GFP_ATOMIC))) ++ continue; ++ ++ if (sock_queue_rcv_skb(sk, nskb)) ++ kfree_skb(nskb); ++ } ++ read_unlock(&l->lock); ++} ++ ++static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len) ++{ ++ struct l2cap_conn *conn = l2cap_pi(sk)->conn; ++ struct sk_buff *skb, **frag; ++ int err, hlen, count, sent=0; ++ l2cap_hdr *lh; ++ ++ BT_DBG("sk %p len %d", sk, len); ++ ++ /* First fragment (with L2CAP header) */ ++ if (sk->type == SOCK_DGRAM) ++ hlen = L2CAP_HDR_SIZE + 2; ++ else ++ hlen = L2CAP_HDR_SIZE; ++ ++ count = MIN(conn->mtu - hlen, len); ++ ++ skb = bluez_skb_send_alloc(sk, hlen + count, ++ msg->msg_flags & MSG_DONTWAIT, &err); ++ if (!skb) ++ return err; ++ ++ /* Create L2CAP header */ ++ lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); ++ lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid); ++ lh->len = __cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); ++ ++ if (sk->type == SOCK_DGRAM) ++ put_unaligned(l2cap_pi(sk)->psm, (__u16 *) skb_put(skb, 2)); ++ ++ if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) { ++ err = -EFAULT; ++ goto fail; ++ } ++ ++ sent += count; ++ len -= count; ++ ++ /* Continuation fragments (no L2CAP header) */ ++ frag = &skb_shinfo(skb)->frag_list; ++ while (len) { ++ count = MIN(conn->mtu, len); ++ ++ *frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err); ++ if (!*frag) ++ goto fail; ++ ++ if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) { ++ err = -EFAULT; ++ goto fail; ++ } ++ ++ sent += count; ++ len -= count; ++ ++ frag = &(*frag)->next; ++ } ++ ++ if ((err = hci_send_acl(conn->hcon, skb, 0)) < 0) ++ goto fail; ++ ++ return sent; ++ ++fail: ++ kfree_skb(skb); ++ return err; ++} ++ ++/* --------- L2CAP signalling commands --------- */ ++static inline __u8 l2cap_get_ident(struct l2cap_conn *conn) ++{ ++ __u8 id; ++ ++ /* Get next available identificator. ++ * 1 - 199 are used by kernel. ++ * 200 - 254 are used by utilities like l2ping, etc ++ */ ++ ++ spin_lock(&conn->lock); ++ ++ if (++conn->tx_ident > 199) ++ conn->tx_ident = 1; ++ ++ id = conn->tx_ident; ++ ++ spin_unlock(&conn->lock); ++ ++ return id; ++} ++ ++static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, ++ __u8 code, __u8 ident, __u16 dlen, void *data) ++{ ++ struct sk_buff *skb, **frag; ++ l2cap_cmd_hdr *cmd; ++ l2cap_hdr *lh; ++ int len, count; ++ ++ BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", conn, code, ident, dlen); ++ ++ len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen; ++ count = MIN(conn->mtu, len); ++ ++ skb = bluez_skb_alloc(count, GFP_ATOMIC); ++ if (!skb) ++ return NULL; ++ ++ lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); ++ lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen); ++ lh->cid = __cpu_to_le16(0x0001); ++ ++ cmd = (l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE); ++ cmd->code = code; ++ cmd->ident = ident; ++ cmd->len = __cpu_to_le16(dlen); ++ ++ if (dlen) { ++ count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE; ++ memcpy(skb_put(skb, count), data, count); ++ data += count; ++ } ++ ++ len -= skb->len; ++ ++ /* Continuation fragments (no L2CAP header) */ ++ frag = &skb_shinfo(skb)->frag_list; ++ while (len) { ++ count = MIN(conn->mtu, len); ++ ++ *frag = bluez_skb_alloc(count, GFP_ATOMIC); ++ if (!*frag) ++ goto fail; ++ ++ memcpy(skb_put(*frag, count), data, count); ++ ++ len -= count; ++ data += count; ++ ++ frag = &(*frag)->next; ++ } ++ ++ return skb; ++ ++fail: ++ kfree_skb(skb); ++ return NULL; ++} ++ ++static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data) ++{ ++ __u8 ident = l2cap_get_ident(conn); ++ struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data); ++ ++ BT_DBG("code 0x%2.2x", code); ++ ++ if (!skb) ++ return -ENOMEM; ++ return hci_send_acl(conn->hcon, skb, 0); ++} ++ ++static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data) ++{ ++ struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data); ++ ++ BT_DBG("code 0x%2.2x", code); ++ ++ if (!skb) ++ return -ENOMEM; ++ return hci_send_acl(conn->hcon, skb, 0); ++} ++ ++static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val) ++{ ++ l2cap_conf_opt *opt = *ptr; ++ int len; ++ ++ len = L2CAP_CONF_OPT_SIZE + opt->len; ++ *ptr += len; ++ ++ *type = opt->type; ++ *olen = opt->len; ++ ++ switch (opt->len) { ++ case 1: ++ *val = *((__u8 *) opt->val); ++ break; ++ ++ case 2: ++ *val = __le16_to_cpu(*((__u16 *)opt->val)); ++ break; ++ ++ case 4: ++ *val = __le32_to_cpu(*((__u32 *)opt->val)); ++ break; ++ ++ default: ++ *val = (unsigned long) opt->val; ++ break; ++ }; ++ ++ BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val); ++ return len; ++} ++ ++static inline void l2cap_parse_conf_req(struct sock *sk, void *data, int len) ++{ ++ int type, hint, olen; ++ unsigned long val; ++ void *ptr = data; ++ ++ BT_DBG("sk %p len %d", sk, len); ++ ++ while (len >= L2CAP_CONF_OPT_SIZE) { ++ len -= l2cap_get_conf_opt(&ptr, &type, &olen, &val); ++ ++ hint = type & 0x80; ++ type &= 0x7f; ++ ++ switch (type) { ++ case L2CAP_CONF_MTU: ++ l2cap_pi(sk)->conf_mtu = val; ++ break; ++ ++ case L2CAP_CONF_FLUSH_TO: ++ l2cap_pi(sk)->flush_to = val; ++ break; ++ ++ case L2CAP_CONF_QOS: ++ break; ++ ++ default: ++ if (hint) ++ break; ++ ++ /* FIXME: Reject unknown option */ ++ break; ++ }; ++ } ++} ++ ++static void l2cap_add_conf_opt(void **ptr, __u8 type, __u8 len, unsigned long val) ++{ ++ register l2cap_conf_opt *opt = *ptr; ++ ++ BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val); ++ ++ opt->type = type; ++ opt->len = len; ++ ++ switch (len) { ++ case 1: ++ *((__u8 *) opt->val) = val; ++ break; ++ ++ case 2: ++ *((__u16 *) opt->val) = __cpu_to_le16(val); ++ break; ++ ++ case 4: ++ *((__u32 *) opt->val) = __cpu_to_le32(val); ++ break; ++ ++ default: ++ memcpy(opt->val, (void *) val, len); ++ break; ++ }; ++ ++ *ptr += L2CAP_CONF_OPT_SIZE + len; ++} ++ ++static int l2cap_build_conf_req(struct sock *sk, void *data) ++{ ++ struct l2cap_pinfo *pi = l2cap_pi(sk); ++ l2cap_conf_req *req = (l2cap_conf_req *) data; ++ void *ptr = req->data; ++ ++ BT_DBG("sk %p", sk); ++ ++ if (pi->imtu != L2CAP_DEFAULT_MTU) ++ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu); ++ ++ /* FIXME. Need actual value of the flush timeout */ ++ //if (flush_to != L2CAP_DEFAULT_FLUSH_TO) ++ // l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to); ++ ++ req->dcid = __cpu_to_le16(pi->dcid); ++ req->flags = __cpu_to_le16(0); ++ ++ return ptr - data; ++} ++ ++static inline int l2cap_conf_output(struct sock *sk, void **ptr) ++{ ++ struct l2cap_pinfo *pi = l2cap_pi(sk); ++ int result = 0; ++ ++ /* Configure output options and let the other side know ++ * which ones we don't like. ++ */ ++ if (pi->conf_mtu < pi->omtu) { ++ l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, pi->omtu); ++ result = L2CAP_CONF_UNACCEPT; ++ } else { ++ pi->omtu = pi->conf_mtu; ++ } ++ ++ BT_DBG("sk %p result %d", sk, result); ++ return result; ++} ++ ++static int l2cap_build_conf_rsp(struct sock *sk, void *data, int *result) ++{ ++ l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data; ++ void *ptr = rsp->data; ++ u16 flags = 0; ++ ++ BT_DBG("sk %p complete %d", sk, result ? 1 : 0); ++ ++ if (result) ++ *result = l2cap_conf_output(sk, &ptr); ++ else ++ flags |= 0x0001; ++ ++ rsp->scid = __cpu_to_le16(l2cap_pi(sk)->dcid); ++ rsp->result = __cpu_to_le16(result ? *result : 0); ++ rsp->flags = __cpu_to_le16(flags); ++ ++ return ptr - data; ++} ++ ++static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) ++{ ++ struct l2cap_chan_list *list = &conn->chan_list; ++ l2cap_conn_req *req = (l2cap_conn_req *) data; ++ l2cap_conn_rsp rsp; ++ struct sock *sk, *parent; ++ int result = 0, status = 0; ++ ++ __u16 dcid = 0, scid = __le16_to_cpu(req->scid); ++ __u16 psm = req->psm; ++ ++ BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid); ++ ++ /* Check if we have socket listening on psm */ ++ parent = l2cap_get_sock_by_psm(BT_LISTEN, psm, conn->src); ++ if (!parent) { ++ result = L2CAP_CR_BAD_PSM; ++ goto sendresp; ++ } ++ ++ result = L2CAP_CR_NO_MEM; ++ ++ /* Check for backlog size */ ++ if (parent->ack_backlog > parent->max_ack_backlog) { ++ BT_DBG("backlog full %d", parent->ack_backlog); ++ goto response; ++ } ++ ++ sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC); ++ if (!sk) ++ goto response; ++ ++ write_lock(&list->lock); ++ ++ /* Check if we already have channel with that dcid */ ++ if (__l2cap_get_chan_by_dcid(list, scid)) { ++ write_unlock(&list->lock); ++ sk->zapped = 1; ++ l2cap_sock_kill(sk); ++ goto response; ++ } ++ ++ hci_conn_hold(conn->hcon); ++ ++ l2cap_sock_init(sk, parent); ++ bacpy(&bluez_pi(sk)->src, conn->src); ++ bacpy(&bluez_pi(sk)->dst, conn->dst); ++ l2cap_pi(sk)->psm = psm; ++ l2cap_pi(sk)->dcid = scid; ++ ++ __l2cap_chan_add(conn, sk, parent); ++ dcid = l2cap_pi(sk)->scid; ++ ++ l2cap_sock_set_timer(sk, sk->sndtimeo); ++ ++ /* Service level security */ ++ result = L2CAP_CR_PEND; ++ status = L2CAP_CS_AUTHEN_PEND; ++ sk->state = BT_CONNECT2; ++ l2cap_pi(sk)->ident = cmd->ident; ++ ++ if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) { ++ if (!hci_conn_encrypt(conn->hcon)) ++ goto done; ++ } else if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) { ++ if (!hci_conn_auth(conn->hcon)) ++ goto done; ++ } ++ ++ sk->state = BT_CONFIG; ++ result = status = 0; ++ ++done: ++ write_unlock(&list->lock); ++ ++response: ++ bh_unlock_sock(parent); ++ ++sendresp: ++ rsp.scid = __cpu_to_le16(scid); ++ rsp.dcid = __cpu_to_le16(dcid); ++ rsp.result = __cpu_to_le16(result); ++ rsp.status = __cpu_to_le16(status); ++ l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp); ++ return 0; ++} ++ ++static inline int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) ++{ ++ l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data; ++ __u16 scid, dcid, result, status; ++ struct sock *sk; ++ char req[128]; ++ ++ scid = __le16_to_cpu(rsp->scid); ++ dcid = __le16_to_cpu(rsp->dcid); ++ result = __le16_to_cpu(rsp->result); ++ status = __le16_to_cpu(rsp->status); ++ ++ BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); ++ ++ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) ++ return -ENOENT; ++ ++ switch (result) { ++ case L2CAP_CR_SUCCESS: ++ sk->state = BT_CONFIG; ++ l2cap_pi(sk)->dcid = dcid; ++ l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; ++ ++ l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req); ++ break; ++ ++ case L2CAP_CR_PEND: ++ break; ++ ++ default: ++ l2cap_chan_del(sk, ECONNREFUSED); ++ break; ++ } ++ ++ bh_unlock_sock(sk); ++ return 0; ++} ++ ++static inline int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) ++{ ++ l2cap_conf_req * req = (l2cap_conf_req *) data; ++ __u16 dcid, flags; ++ __u8 rsp[64]; ++ struct sock *sk; ++ int result; ++ ++ dcid = __le16_to_cpu(req->dcid); ++ flags = __le16_to_cpu(req->flags); ++ ++ BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags); ++ ++ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid))) ++ return -ENOENT; ++ ++ l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE); ++ ++ if (flags & 0x0001) { ++ /* Incomplete config. Send empty response. */ ++ l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp); ++ goto unlock; ++ } ++ ++ /* Complete config. */ ++ l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp); ++ ++ if (result) ++ goto unlock; ++ ++ /* Output config done */ ++ l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE; ++ ++ if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) { ++ sk->state = BT_CONNECTED; ++ l2cap_chan_ready(sk); ++ } else if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) { ++ char req[64]; ++ l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req); ++ } ++ ++unlock: ++ bh_unlock_sock(sk); ++ return 0; ++} ++ ++static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) ++{ ++ l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data; ++ __u16 scid, flags, result; ++ struct sock *sk; ++ int err = 0; ++ ++ scid = __le16_to_cpu(rsp->scid); ++ flags = __le16_to_cpu(rsp->flags); ++ result = __le16_to_cpu(rsp->result); ++ ++ BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result); ++ ++ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) ++ return -ENOENT; ++ ++ switch (result) { ++ case L2CAP_CONF_SUCCESS: ++ break; ++ ++ case L2CAP_CONF_UNACCEPT: ++ if (++l2cap_pi(sk)->conf_retry < L2CAP_CONF_MAX_RETRIES) { ++ char req[128]; ++ /* ++ It does not make sense to adjust L2CAP parameters ++ that are currently defined in the spec. We simply ++ resend config request that we sent earlier. It is ++ stupid :) but it helps qualification testing ++ which expects at least some response from us. ++ */ ++ l2cap_send_req(conn, L2CAP_CONF_REQ, ++ l2cap_build_conf_req(sk, req), req); ++ goto done; ++ } ++ default: ++ sk->state = BT_DISCONN; ++ sk->err = ECONNRESET; ++ l2cap_sock_set_timer(sk, HZ * 5); ++ { ++ l2cap_disconn_req req; ++ req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid); ++ req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); ++ l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req); ++ } ++ goto done; ++ } ++ ++ if (flags & 0x01) ++ goto done; ++ ++ /* Input config done */ ++ l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE; ++ ++ if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) { ++ sk->state = BT_CONNECTED; ++ l2cap_chan_ready(sk); ++ } ++ ++done: ++ bh_unlock_sock(sk); ++ return err; ++} ++ ++static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) ++{ ++ l2cap_disconn_req *req = (l2cap_disconn_req *) data; ++ l2cap_disconn_rsp rsp; ++ __u16 dcid, scid; ++ struct sock *sk; ++ ++ scid = __le16_to_cpu(req->scid); ++ dcid = __le16_to_cpu(req->dcid); ++ ++ BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); ++ ++ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid))) ++ return 0; ++ ++ rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid); ++ rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid); ++ l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp); ++ ++ sk->shutdown = SHUTDOWN_MASK; ++ ++ l2cap_chan_del(sk, ECONNRESET); ++ bh_unlock_sock(sk); ++ ++ l2cap_sock_kill(sk); ++ return 0; ++} ++ ++static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) ++{ ++ l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data; ++ __u16 dcid, scid; ++ struct sock *sk; ++ ++ scid = __le16_to_cpu(rsp->scid); ++ dcid = __le16_to_cpu(rsp->dcid); ++ ++ BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); ++ ++ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) ++ return 0; ++ l2cap_chan_del(sk, 0); ++ bh_unlock_sock(sk); ++ ++ l2cap_sock_kill(sk); ++ return 0; ++} ++ ++static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) ++{ ++ __u8 *data = skb->data; ++ int len = skb->len; ++ l2cap_cmd_hdr cmd; ++ int err = 0; ++ ++ while (len >= L2CAP_CMD_HDR_SIZE) { ++ memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE); ++ data += L2CAP_CMD_HDR_SIZE; ++ len -= L2CAP_CMD_HDR_SIZE; ++ ++ cmd.len = __le16_to_cpu(cmd.len); ++ ++ BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident); ++ ++ if (cmd.len > len || !cmd.ident) { ++ BT_DBG("corrupted command"); ++ break; ++ } ++ ++ switch (cmd.code) { ++ case L2CAP_CONN_REQ: ++ err = l2cap_connect_req(conn, &cmd, data); ++ break; ++ ++ case L2CAP_CONN_RSP: ++ err = l2cap_connect_rsp(conn, &cmd, data); ++ break; ++ ++ case L2CAP_CONF_REQ: ++ err = l2cap_config_req(conn, &cmd, data); ++ break; ++ ++ case L2CAP_CONF_RSP: ++ err = l2cap_config_rsp(conn, &cmd, data); ++ break; ++ ++ case L2CAP_DISCONN_REQ: ++ err = l2cap_disconnect_req(conn, &cmd, data); ++ break; ++ ++ case L2CAP_DISCONN_RSP: ++ err = l2cap_disconnect_rsp(conn, &cmd, data); ++ break; ++ ++ case L2CAP_COMMAND_REJ: ++ /* FIXME: We should process this */ ++ l2cap_raw_recv(conn, skb); ++ break; ++ ++ case L2CAP_ECHO_REQ: ++ l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data); ++ break; ++ ++ case L2CAP_ECHO_RSP: ++ case L2CAP_INFO_REQ: ++ case L2CAP_INFO_RSP: ++ l2cap_raw_recv(conn, skb); ++ break; ++ ++ default: ++ BT_ERR("Uknown signaling command 0x%2.2x", cmd.code); ++ err = -EINVAL; ++ break; ++ }; ++ ++ if (err) { ++ l2cap_cmd_rej rej; ++ BT_DBG("error %d", err); ++ ++ /* FIXME: Map err to a valid reason. */ ++ rej.reason = __cpu_to_le16(0); ++ l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej); ++ } ++ ++ data += cmd.len; ++ len -= cmd.len; ++ } ++ ++ kfree_skb(skb); ++} ++ ++static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb) ++{ ++ struct sock *sk; ++ ++ sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); ++ if (!sk) { ++ BT_DBG("unknown cid 0x%4.4x", cid); ++ goto drop; ++ } ++ ++ BT_DBG("sk %p, len %d", sk, skb->len); ++ ++ if (sk->state != BT_CONNECTED) ++ goto drop; ++ ++ if (l2cap_pi(sk)->imtu < skb->len) ++ goto drop; ++ ++ /* If socket recv buffers overflows we drop data here ++ * which is *bad* because L2CAP has to be reliable. ++ * But we don't have any other choice. L2CAP doesn't ++ * provide flow control mechanism */ ++ ++ if (!sock_queue_rcv_skb(sk, skb)) ++ goto done; ++ ++drop: ++ kfree_skb(skb); ++ ++done: ++ if (sk) bh_unlock_sock(sk); ++ return 0; ++} ++ ++static inline int l2cap_conless_channel(struct l2cap_conn *conn, __u16 psm, struct sk_buff *skb) ++{ ++ struct sock *sk; ++ ++ sk = l2cap_get_sock_by_psm(0, psm, conn->src); ++ if (!sk) ++ goto drop; ++ ++ BT_DBG("sk %p, len %d", sk, skb->len); ++ ++ if (sk->state != BT_BOUND && sk->state != BT_CONNECTED) ++ goto drop; ++ ++ if (l2cap_pi(sk)->imtu < skb->len) ++ goto drop; ++ ++ if (!sock_queue_rcv_skb(sk, skb)) ++ goto done; ++ ++drop: ++ kfree_skb(skb); ++ ++done: ++ if (sk) bh_unlock_sock(sk); ++ return 0; ++} ++ ++static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) ++{ ++ l2cap_hdr *lh = (l2cap_hdr *) skb->data; ++ __u16 cid, psm, len; ++ ++ skb_pull(skb, L2CAP_HDR_SIZE); ++ cid = __le16_to_cpu(lh->cid); ++ len = __le16_to_cpu(lh->len); ++ ++ BT_DBG("len %d, cid 0x%4.4x", len, cid); ++ ++ switch (cid) { ++ case 0x0001: ++ l2cap_sig_channel(conn, skb); ++ break; ++ ++ case 0x0002: ++ psm = get_unaligned((__u16 *) skb->data); ++ skb_pull(skb, 2); ++ l2cap_conless_channel(conn, psm, skb); ++ break; ++ ++ default: ++ l2cap_data_channel(conn, cid, skb); ++ break; ++ } ++} ++ ++/* ------------ L2CAP interface with lower layer (HCI) ------------- */ ++ ++static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) ++{ ++ int exact = 0, lm1 = 0, lm2 = 0; ++ register struct sock *sk; ++ ++ if (type != ACL_LINK) ++ return 0; ++ ++ BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); ++ ++ /* Find listening sockets and check their link_mode */ ++ read_lock(&l2cap_sk_list.lock); ++ for (sk = l2cap_sk_list.head; sk; sk = sk->next) { ++ if (sk->state != BT_LISTEN) ++ continue; ++ ++ if (!bacmp(&bluez_pi(sk)->src, &hdev->bdaddr)) { ++ lm1 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode); ++ exact++; ++ } else if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY)) ++ lm2 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode); ++ } ++ read_unlock(&l2cap_sk_list.lock); ++ ++ return exact ? lm1 : lm2; ++} ++ ++static int l2cap_connect_cfm(struct hci_conn *hcon, __u8 status) ++{ ++ BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); ++ ++ if (hcon->type != ACL_LINK) ++ return 0; ++ ++ if (!status) { ++ struct l2cap_conn *conn; ++ ++ conn = l2cap_conn_add(hcon, status); ++ if (conn) ++ l2cap_conn_ready(conn); ++ } else ++ l2cap_conn_del(hcon, bterr(status)); ++ ++ return 0; ++} ++ ++static int l2cap_disconn_ind(struct hci_conn *hcon, __u8 reason) ++{ ++ BT_DBG("hcon %p reason %d", hcon, reason); ++ ++ if (hcon->type != ACL_LINK) ++ return 0; ++ ++ l2cap_conn_del(hcon, bterr(reason)); ++ return 0; ++} ++ ++static int l2cap_auth_cfm(struct hci_conn *hcon, __u8 status) ++{ ++ struct l2cap_chan_list *l; ++ struct l2cap_conn *conn; ++ l2cap_conn_rsp rsp; ++ struct sock *sk; ++ int result; ++ ++ if (!(conn = hcon->l2cap_data)) ++ return 0; ++ l = &conn->chan_list; ++ ++ BT_DBG("conn %p", conn); ++ ++ read_lock(&l->lock); ++ ++ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { ++ bh_lock_sock(sk); ++ ++ if (sk->state != BT_CONNECT2 || ++ (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT)) { ++ bh_unlock_sock(sk); ++ continue; ++ } ++ ++ if (!status) { ++ sk->state = BT_CONFIG; ++ result = 0; ++ } else { ++ sk->state = BT_DISCONN; ++ l2cap_sock_set_timer(sk, HZ/10); ++ result = L2CAP_CR_SEC_BLOCK; ++ } ++ ++ rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid); ++ rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid); ++ rsp.result = __cpu_to_le16(result); ++ rsp.status = __cpu_to_le16(0); ++ l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP, ++ L2CAP_CONN_RSP_SIZE, &rsp); ++ ++ bh_unlock_sock(sk); ++ } ++ ++ read_unlock(&l->lock); ++ return 0; ++} ++ ++static int l2cap_encrypt_cfm(struct hci_conn *hcon, __u8 status) ++{ ++ struct l2cap_chan_list *l; ++ struct l2cap_conn *conn; ++ l2cap_conn_rsp rsp; ++ struct sock *sk; ++ int result; ++ ++ if (!(conn = hcon->l2cap_data)) ++ return 0; ++ l = &conn->chan_list; ++ ++ BT_DBG("conn %p", conn); ++ ++ read_lock(&l->lock); ++ ++ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { ++ bh_lock_sock(sk); ++ ++ if (sk->state != BT_CONNECT2) { ++ bh_unlock_sock(sk); ++ continue; ++ } ++ ++ if (!status) { ++ sk->state = BT_CONFIG; ++ result = 0; ++ } else { ++ sk->state = BT_DISCONN; ++ l2cap_sock_set_timer(sk, HZ/10); ++ result = L2CAP_CR_SEC_BLOCK; ++ } ++ ++ rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid); ++ rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid); ++ rsp.result = __cpu_to_le16(result); ++ rsp.status = __cpu_to_le16(0); ++ l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP, ++ L2CAP_CONN_RSP_SIZE, &rsp); ++ ++ bh_unlock_sock(sk); ++ } ++ ++ read_unlock(&l->lock); ++ return 0; ++} ++ ++static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, __u16 flags) ++{ ++ struct l2cap_conn *conn = hcon->l2cap_data; ++ ++ if (!conn && !(conn = l2cap_conn_add(hcon, 0))) ++ goto drop; ++ ++ BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags); ++ ++ if (flags & ACL_START) { ++ l2cap_hdr *hdr; ++ int len; ++ ++ if (conn->rx_len) { ++ BT_ERR("Unexpected start frame (len %d)", skb->len); ++ kfree_skb(conn->rx_skb); ++ conn->rx_skb = NULL; ++ conn->rx_len = 0; ++ l2cap_conn_unreliable(conn, ECOMM); ++ } ++ ++ if (skb->len < 2) { ++ BT_ERR("Frame is too short (len %d)", skb->len); ++ l2cap_conn_unreliable(conn, ECOMM); ++ goto drop; ++ } ++ ++ hdr = (l2cap_hdr *) skb->data; ++ len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE; ++ ++ if (len == skb->len) { ++ /* Complete frame received */ ++ l2cap_recv_frame(conn, skb); ++ return 0; ++ } ++ ++ BT_DBG("Start: total len %d, frag len %d", len, skb->len); ++ ++ if (skb->len > len) { ++ BT_ERR("Frame is too long (len %d, expected len %d)", ++ skb->len, len); ++ l2cap_conn_unreliable(conn, ECOMM); ++ goto drop; ++ } ++ ++ /* Allocate skb for the complete frame including header */ ++ conn->rx_skb = bluez_skb_alloc(len, GFP_ATOMIC); ++ if (!conn->rx_skb) ++ goto drop; ++ ++ memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len); ++ conn->rx_len = len - skb->len; ++ } else { ++ BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len); ++ ++ if (!conn->rx_len) { ++ BT_ERR("Unexpected continuation frame (len %d)", skb->len); ++ l2cap_conn_unreliable(conn, ECOMM); ++ goto drop; ++ } ++ ++ if (skb->len > conn->rx_len) { ++ BT_ERR("Fragment is too long (len %d, expected %d)", ++ skb->len, conn->rx_len); ++ kfree_skb(conn->rx_skb); ++ conn->rx_skb = NULL; ++ conn->rx_len = 0; ++ l2cap_conn_unreliable(conn, ECOMM); ++ goto drop; ++ } ++ ++ memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len); ++ conn->rx_len -= skb->len; ++ ++ if (!conn->rx_len) { ++ /* Complete frame received */ ++ l2cap_recv_frame(conn, conn->rx_skb); ++ conn->rx_skb = NULL; ++ } ++ } ++ ++drop: ++ kfree_skb(skb); ++ return 0; ++} ++ ++/* ----- Proc fs support ------ */ ++static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list) ++{ ++ struct l2cap_pinfo *pi; ++ struct sock *sk; ++ char *ptr = buf; ++ ++ read_lock_bh(&list->lock); ++ ++ for (sk = list->head; sk; sk = sk->next) { ++ pi = l2cap_pi(sk); ++ ptr += sprintf(ptr, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n", ++ batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst), ++ sk->state, pi->psm, pi->scid, pi->dcid, pi->imtu, pi->omtu, ++ pi->link_mode); ++ } ++ ++ read_unlock_bh(&list->lock); ++ ++ ptr += sprintf(ptr, "\n"); ++ return ptr - buf; ++} ++ ++static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv) ++{ ++ char *ptr = buf; ++ int len; ++ ++ BT_DBG("count %d, offset %ld", count, offset); ++ ++ ptr += l2cap_sock_dump(ptr, &l2cap_sk_list); ++ len = ptr - buf; ++ ++ if (len <= count + offset) ++ *eof = 1; ++ ++ *start = buf + offset; ++ len -= offset; ++ ++ if (len > count) ++ len = count; ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++ ++static struct proto_ops l2cap_sock_ops = { ++ family: PF_BLUETOOTH, ++ release: l2cap_sock_release, ++ bind: l2cap_sock_bind, ++ connect: l2cap_sock_connect, ++ listen: l2cap_sock_listen, ++ accept: l2cap_sock_accept, ++ getname: l2cap_sock_getname, ++ sendmsg: l2cap_sock_sendmsg, ++ recvmsg: bluez_sock_recvmsg, ++ poll: bluez_sock_poll, ++ socketpair: sock_no_socketpair, ++ ioctl: sock_no_ioctl, ++ shutdown: l2cap_sock_shutdown, ++ setsockopt: l2cap_sock_setsockopt, ++ getsockopt: l2cap_sock_getsockopt, ++ mmap: sock_no_mmap ++}; ++ ++static struct net_proto_family l2cap_sock_family_ops = { ++ family: PF_BLUETOOTH, ++ create: l2cap_sock_create ++}; ++ ++static struct hci_proto l2cap_hci_proto = { ++ name: "L2CAP", ++ id: HCI_PROTO_L2CAP, ++ connect_ind: l2cap_connect_ind, ++ connect_cfm: l2cap_connect_cfm, ++ disconn_ind: l2cap_disconn_ind, ++ recv_acldata: l2cap_recv_acldata, ++ auth_cfm: l2cap_auth_cfm, ++ encrypt_cfm: l2cap_encrypt_cfm ++}; ++ ++int __init l2cap_init(void) ++{ ++ int err; ++ ++ if ((err = bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops))) { ++ BT_ERR("Can't register L2CAP socket"); ++ return err; ++ } ++ ++ if ((err = hci_register_proto(&l2cap_hci_proto))) { ++ BT_ERR("Can't register L2CAP protocol"); ++ return err; ++ } ++ ++ create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL); ++ ++ BT_INFO("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION); ++ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); ++ return 0; ++} ++ ++void l2cap_cleanup(void) ++{ ++ remove_proc_entry("bluetooth/l2cap", NULL); ++ ++ /* Unregister socket and protocol */ ++ if (bluez_sock_unregister(BTPROTO_L2CAP)) ++ BT_ERR("Can't unregister L2CAP socket"); ++ ++ if (hci_unregister_proto(&l2cap_hci_proto)) ++ BT_ERR("Can't unregister L2CAP protocol"); ++} ++ ++void l2cap_load(void) ++{ ++ /* Dummy function to trigger automatic L2CAP module loading by ++ other modules that use L2CAP sockets but do not use any other ++ symbols from it. */ ++ return; ++} ++ ++EXPORT_SYMBOL(l2cap_load); ++ ++module_init(l2cap_init); ++module_exit(l2cap_cleanup); ++ ++MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); ++MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION); ++MODULE_LICENSE("GPL"); +--- linux/net/bluetooth/l2cap_core.c~bluetooth-2.4.18-mh11 ++++ linux/net/bluetooth/l2cap_core.c +-/* +- BlueZ - Bluetooth protocol stack for Linux +- Copyright (C) 2000-2001 Qualcomm Incorporated +- +- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; +- +- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY +- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES +- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- +- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, +- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS +- SOFTWARE IS DISCLAIMED. +-*/ +- +-/* +- * BlueZ L2CAP core and sockets. +- * +- * $Id$ +- */ +-#define VERSION "1.1" +- +-#include <linux/config.h> +-#include <linux/module.h> +- +-#include <linux/types.h> +-#include <linux/errno.h> +-#include <linux/kernel.h> +-#include <linux/major.h> +-#include <linux/sched.h> +-#include <linux/slab.h> +-#include <linux/poll.h> +-#include <linux/fcntl.h> +-#include <linux/init.h> +-#include <linux/skbuff.h> +-#include <linux/interrupt.h> +-#include <linux/socket.h> +-#include <linux/skbuff.h> +-#include <linux/proc_fs.h> +-#include <linux/list.h> +-#include <net/sock.h> +- +-#include <asm/system.h> +-#include <asm/uaccess.h> +- +-#include <net/bluetooth/bluetooth.h> +-#include <net/bluetooth/bluez.h> +-#include <net/bluetooth/hci_core.h> +-#include <net/bluetooth/l2cap.h> +-#include <net/bluetooth/l2cap_core.h> +- +-#ifndef L2CAP_DEBUG +-#undef DBG +-#define DBG( A... ) +-#endif +- +-struct proto_ops l2cap_sock_ops; +- +-struct bluez_sock_list l2cap_sk_list = { +- lock: RW_LOCK_UNLOCKED +-}; +- +-struct list_head l2cap_iff_list = LIST_HEAD_INIT(l2cap_iff_list); +-rwlock_t l2cap_rt_lock = RW_LOCK_UNLOCKED; +- +-static int l2cap_conn_del(struct l2cap_conn *conn, int err); +- +-static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent); +-static void l2cap_chan_del(struct sock *sk, int err); +-static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len); +- +-static void l2cap_sock_close(struct sock *sk); +-static void l2cap_sock_kill(struct sock *sk); +- +-static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data); +-static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data); +- +-/* -------- L2CAP interfaces & routing --------- */ +-/* Add/delete L2CAP interface. +- * Must be called with locked rt_lock +- */ +- +-static void l2cap_iff_add(struct hci_dev *hdev) +-{ +- struct l2cap_iff *iff; +- +- DBG("%s", hdev->name); +- +- DBG("iff_list %p next %p prev %p", &l2cap_iff_list, l2cap_iff_list.next, l2cap_iff_list.prev); +- +- /* Allocate new interface and lock HCI device */ +- if (!(iff = kmalloc(sizeof(struct l2cap_iff), GFP_KERNEL))) { +- ERR("Can't allocate new interface %s", hdev->name); +- return; +- } +- memset(iff, 0, sizeof(struct l2cap_iff)); +- +- hci_dev_hold(hdev); +- hdev->l2cap_data = iff; +- iff->hdev = hdev; +- iff->mtu = hdev->acl_mtu - HCI_ACL_HDR_SIZE; +- iff->bdaddr = &hdev->bdaddr; +- +- spin_lock_init(&iff->lock); +- INIT_LIST_HEAD(&iff->conn_list); +- +- list_add(&iff->list, &l2cap_iff_list); +-} +- +-static void l2cap_iff_del(struct hci_dev *hdev) +-{ +- struct l2cap_iff *iff; +- +- if (!(iff = hdev->l2cap_data)) +- return; +- +- DBG("%s iff %p", hdev->name, iff); +- +- list_del(&iff->list); +- +- l2cap_iff_lock(iff); +- +- /* Drop connections */ +- while (!list_empty(&iff->conn_list)) { +- struct l2cap_conn *c; +- +- c = list_entry(iff->conn_list.next, struct l2cap_conn, list); +- l2cap_conn_del(c, ENODEV); +- } +- +- l2cap_iff_unlock(iff); +- +- /* Unlock HCI device */ +- hdev->l2cap_data = NULL; +- hci_dev_put(hdev); +- +- kfree(iff); +-} +- +-/* Get route. Returns L2CAP interface. +- * Must be called with locked rt_lock +- */ +-static struct l2cap_iff *l2cap_get_route(bdaddr_t *src, bdaddr_t *dst) +-{ +- struct list_head *p; +- int use_src; +- +- DBG("%s -> %s", batostr(src), batostr(dst)); +- +- use_src = bacmp(src, BDADDR_ANY) ? 0 : 1; +- +- /* Simple routing: +- * No source address - find interface with bdaddr != dst +- * Source address - find interface with bdaddr == src +- */ +- +- list_for_each(p, &l2cap_iff_list) { +- struct l2cap_iff *iff; +- +- iff = list_entry(p, struct l2cap_iff, list); +- +- if (use_src && !bacmp(iff->bdaddr, src)) +- return iff; +- else if (bacmp(iff->bdaddr, dst)) +- return iff; +- } +- return NULL; +-} +- +-/* ----- L2CAP timers ------ */ +-static void l2cap_sock_timeout(unsigned long arg) +-{ +- struct sock *sk = (struct sock *) arg; +- +- DBG("sock %p state %d", sk, sk->state); +- +- bh_lock_sock(sk); +- switch (sk->state) { +- case BT_DISCONN: +- l2cap_chan_del(sk, ETIMEDOUT); +- break; +- +- default: +- sk->err = ETIMEDOUT; +- sk->state_change(sk); +- break; +- }; +- bh_unlock_sock(sk); +- +- l2cap_sock_kill(sk); +- sock_put(sk); +-} +- +-static void l2cap_sock_set_timer(struct sock *sk, long timeout) +-{ +- DBG("sock %p state %d timeout %ld", sk, sk->state, timeout); +- +- if (!mod_timer(&sk->timer, jiffies + timeout)) +- sock_hold(sk); +-} +- +-static void l2cap_sock_clear_timer(struct sock *sk) +-{ +- DBG("sock %p state %d", sk, sk->state); +- +- if (timer_pending(&sk->timer) && del_timer(&sk->timer)) +- __sock_put(sk); +-} +- +-static void l2cap_sock_init_timer(struct sock *sk) +-{ +- init_timer(&sk->timer); +- sk->timer.function = l2cap_sock_timeout; +- sk->timer.data = (unsigned long)sk; +-} +- +-static void l2cap_conn_timeout(unsigned long arg) +-{ +- struct l2cap_conn *conn = (void *)arg; +- +- DBG("conn %p state %d", conn, conn->state); +- +- if (conn->state == BT_CONNECTED) { +- hci_disconnect(conn->hconn, 0x13); +- } +- +- return; +-} +- +-static void l2cap_conn_set_timer(struct l2cap_conn *conn, long timeout) +-{ +- DBG("conn %p state %d timeout %ld", conn, conn->state, timeout); +- +- mod_timer(&conn->timer, jiffies + timeout); +-} +- +-static void l2cap_conn_clear_timer(struct l2cap_conn *conn) +-{ +- DBG("conn %p state %d", conn, conn->state); +- +- del_timer(&conn->timer); +-} +- +-static void l2cap_conn_init_timer(struct l2cap_conn *conn) +-{ +- init_timer(&conn->timer); +- conn->timer.function = l2cap_conn_timeout; +- conn->timer.data = (unsigned long)conn; +-} +- +-/* -------- L2CAP connections --------- */ +-/* Add new connection to the interface. +- * Interface must be locked +- */ +-static struct l2cap_conn *l2cap_conn_add(struct l2cap_iff *iff, bdaddr_t *dst) +-{ +- struct l2cap_conn *conn; +- bdaddr_t *src = iff->bdaddr; +- +- if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_KERNEL))) +- return NULL; +- +- memset(conn, 0, sizeof(struct l2cap_conn)); +- +- conn->state = BT_OPEN; +- conn->iff = iff; +- bacpy(&conn->src, src); +- bacpy(&conn->dst, dst); +- +- spin_lock_init(&conn->lock); +- conn->chan_list.lock = RW_LOCK_UNLOCKED; +- +- l2cap_conn_init_timer(conn); +- +- __l2cap_conn_link(iff, conn); +- +- DBG("%s -> %s, %p", batostr(src), batostr(dst), conn); +- +- MOD_INC_USE_COUNT; +- +- return conn; +-} +- +-/* Delete connection on the interface. +- * Interface must be locked +- */ +-static int l2cap_conn_del(struct l2cap_conn *conn, int err) +-{ +- struct sock *sk; +- +- DBG("conn %p, state %d, err %d", conn, conn->state, err); +- +- l2cap_conn_clear_timer(conn); +- __l2cap_conn_unlink(conn->iff, conn); +- +- conn->state = BT_CLOSED; +- +- if (conn->rx_skb) +- kfree_skb(conn->rx_skb); +- +- /* Kill channels */ +- while ((sk = conn->chan_list.head)) { +- bh_lock_sock(sk); +- l2cap_sock_clear_timer(sk); +- l2cap_chan_del(sk, err); +- bh_unlock_sock(sk); +- +- l2cap_sock_kill(sk); +- } +- +- kfree(conn); +- +- MOD_DEC_USE_COUNT; +- return 0; +-} +- +-static inline struct l2cap_conn *l2cap_get_conn_by_addr(struct l2cap_iff *iff, bdaddr_t *dst) +-{ +- struct list_head *p; +- +- list_for_each(p, &iff->conn_list) { +- struct l2cap_conn *c; +- +- c = list_entry(p, struct l2cap_conn, list); +- if (!bacmp(&c->dst, dst)) +- return c; +- } +- return NULL; +-} +- +-int l2cap_connect(struct sock *sk) +-{ +- bdaddr_t *src = &l2cap_pi(sk)->src; +- bdaddr_t *dst = &l2cap_pi(sk)->dst; +- struct l2cap_conn *conn; +- struct l2cap_iff *iff; +- int err = 0; +- +- DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm); +- +- read_lock_bh(&l2cap_rt_lock); +- +- /* Get route to remote BD address */ +- if (!(iff = l2cap_get_route(src, dst))) { +- err = -EHOSTUNREACH; +- goto done; +- } +- +- /* Update source addr of the socket */ +- bacpy(src, iff->bdaddr); +- +- l2cap_iff_lock(iff); +- +- if (!(conn = l2cap_get_conn_by_addr(iff, dst))) { +- /* Connection doesn't exist */ +- if (!(conn = l2cap_conn_add(iff, dst))) { +- l2cap_iff_unlock(iff); +- err = -ENOMEM; +- goto done; +- } +- conn->out = 1; +- } +- +- l2cap_iff_unlock(iff); +- +- l2cap_chan_add(conn, sk, NULL); +- +- sk->state = BT_CONNECT; +- l2cap_sock_set_timer(sk, sk->sndtimeo); +- +- switch (conn->state) { +- case BT_CONNECTED: +- if (sk->type == SOCK_SEQPACKET) { +- l2cap_conn_req req; +- req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); +- req.psm = l2cap_pi(sk)->psm; +- l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req); +- } else { +- l2cap_sock_clear_timer(sk); +- sk->state = BT_CONNECTED; +- } +- break; +- +- case BT_CONNECT: +- break; +- +- default: +- /* Create ACL connection */ +- conn->state = BT_CONNECT; +- hci_connect(iff->hdev, dst); +- break; +- }; +- +-done: +- read_unlock_bh(&l2cap_rt_lock); +- return err; +-} +- +-/* ------ Channel queues for listening sockets ------ */ +-void l2cap_accept_queue(struct sock *parent, struct sock *sk) +-{ +- struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q; +- +- DBG("parent %p, sk %p", parent, sk); +- +- sock_hold(sk); +- l2cap_pi(sk)->parent = parent; +- l2cap_pi(sk)->next_q = NULL; +- +- if (!q->head) { +- q->head = q->tail = sk; +- } else { +- struct sock *tail = q->tail; +- +- l2cap_pi(sk)->prev_q = tail; +- l2cap_pi(tail)->next_q = sk; +- q->tail = sk; +- } +- +- parent->ack_backlog++; +-} +- +-void l2cap_accept_unlink(struct sock *sk) +-{ +- struct sock *parent = l2cap_pi(sk)->parent; +- struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q; +- struct sock *next, *prev; +- +- DBG("sk %p", sk); +- +- next = l2cap_pi(sk)->next_q; +- prev = l2cap_pi(sk)->prev_q; +- +- if (sk == q->head) +- q->head = next; +- if (sk == q->tail) +- q->tail = prev; +- +- if (next) +- l2cap_pi(next)->prev_q = prev; +- if (prev) +- l2cap_pi(prev)->next_q = next; +- +- l2cap_pi(sk)->parent = NULL; +- +- parent->ack_backlog--; +- __sock_put(sk); +-} +- +-/* Get next connected channel in queue. */ +-struct sock *l2cap_accept_dequeue(struct sock *parent, int state) +-{ +- struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q; +- struct sock *sk; +- +- for (sk = q->head; sk; sk = l2cap_pi(sk)->next_q) { +- if (!state || sk->state == state) { +- l2cap_accept_unlink(sk); +- break; +- } +- } +- +- DBG("parent %p, sk %p", parent, sk); +- +- return sk; +-} +- +-/* -------- Socket interface ---------- */ +-static struct sock *__l2cap_get_sock_by_addr(struct sockaddr_l2 *addr) +-{ +- bdaddr_t *src = &addr->l2_bdaddr; +- __u16 psm = addr->l2_psm; +- struct sock *sk; +- +- for (sk = l2cap_sk_list.head; sk; sk = sk->next) { +- if (l2cap_pi(sk)->psm == psm && +- !bacmp(&l2cap_pi(sk)->src, src)) +- break; +- } +- +- return sk; +-} +- +-/* Find socket listening on psm and source bdaddr. +- * Returns closest match. +- */ +-static struct sock *l2cap_get_sock_listen(bdaddr_t *src, __u16 psm) +-{ +- struct sock *sk, *sk1 = NULL; +- +- read_lock(&l2cap_sk_list.lock); +- +- for (sk = l2cap_sk_list.head; sk; sk = sk->next) { +- struct l2cap_pinfo *pi; +- +- if (sk->state != BT_LISTEN) +- continue; +- +- pi = l2cap_pi(sk); +- +- if (pi->psm == psm) { +- /* Exact match. */ +- if (!bacmp(&pi->src, src)) +- break; +- +- /* Closest match */ +- if (!bacmp(&pi->src, BDADDR_ANY)) +- sk1 = sk; +- } +- } +- +- read_unlock(&l2cap_sk_list.lock); +- +- return sk ? sk : sk1; +-} +- +-static void l2cap_sock_destruct(struct sock *sk) +-{ +- DBG("sk %p", sk); +- +- skb_queue_purge(&sk->receive_queue); +- skb_queue_purge(&sk->write_queue); +- +- MOD_DEC_USE_COUNT; +-} +- +-static void l2cap_sock_cleanup_listen(struct sock *parent) +-{ +- struct sock *sk; +- +- DBG("parent %p", parent); +- +- /* Close not yet accepted channels */ +- while ((sk = l2cap_accept_dequeue(parent, 0))) +- l2cap_sock_close(sk); +- +- parent->state = BT_CLOSED; +- parent->zapped = 1; +-} +- +-/* Kill socket (only if zapped and orphan) +- * Must be called on unlocked socket. +- */ +-static void l2cap_sock_kill(struct sock *sk) +-{ +- if (!sk->zapped || sk->socket) +- return; +- +- DBG("sk %p state %d", sk, sk->state); +- +- /* Kill poor orphan */ +- bluez_sock_unlink(&l2cap_sk_list, sk); +- sk->dead = 1; +- sock_put(sk); +-} +- +-/* Close socket. +- * Must be called on unlocked socket. +- */ +-static void l2cap_sock_close(struct sock *sk) +-{ +- struct l2cap_conn *conn; +- +- l2cap_sock_clear_timer(sk); +- +- lock_sock(sk); +- +- conn = l2cap_pi(sk)->conn; +- +- DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket); +- +- switch (sk->state) { +- case BT_LISTEN: +- l2cap_sock_cleanup_listen(sk); +- break; +- +- case BT_CONNECTED: +- case BT_CONFIG: +- if (sk->type == SOCK_SEQPACKET) { +- l2cap_disconn_req req; +- +- sk->state = BT_DISCONN; +- +- req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid); +- req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); +- l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req); +- +- l2cap_sock_set_timer(sk, sk->sndtimeo); +- } else { +- l2cap_chan_del(sk, ECONNRESET); +- } +- break; +- +- case BT_CONNECT: +- case BT_DISCONN: +- l2cap_chan_del(sk, ECONNRESET); +- break; +- +- default: +- sk->zapped = 1; +- break; +- }; +- +- release_sock(sk); +- +- l2cap_sock_kill(sk); +-} +- +-static void l2cap_sock_init(struct sock *sk, struct sock *parent) +-{ +- struct l2cap_pinfo *pi = l2cap_pi(sk); +- +- DBG("sk %p", sk); +- +- if (parent) { +- sk->type = parent->type; +- +- pi->imtu = l2cap_pi(parent)->imtu; +- pi->omtu = l2cap_pi(parent)->omtu; +- } else { +- pi->imtu = L2CAP_DEFAULT_MTU; +- pi->omtu = 0; +- } +- +- /* Default config options */ +- pi->conf_mtu = L2CAP_DEFAULT_MTU; +- pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; +-} +- +-static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio) +-{ +- struct sock *sk; +- +- if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1))) +- return NULL; +- +- sock_init_data(sock, sk); +- +- sk->zapped = 0; +- +- sk->destruct = l2cap_sock_destruct; +- sk->sndtimeo = L2CAP_CONN_TIMEOUT; +- +- sk->protocol = proto; +- sk->state = BT_OPEN; +- +- l2cap_sock_init_timer(sk); +- +- bluez_sock_link(&l2cap_sk_list, sk); +- +- MOD_INC_USE_COUNT; +- +- return sk; +-} +- +-static int l2cap_sock_create(struct socket *sock, int protocol) +-{ +- struct sock *sk; +- +- DBG("sock %p", sock); +- +- sock->state = SS_UNCONNECTED; +- +- if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_RAW) +- return -ESOCKTNOSUPPORT; +- +- sock->ops = &l2cap_sock_ops; +- +- if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL))) +- return -ENOMEM; +- +- l2cap_sock_init(sk, NULL); +- +- return 0; +-} +- +-static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) +-{ +- struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; +- struct sock *sk = sock->sk; +- int err = 0; +- +- DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm); +- +- if (!addr || addr->sa_family != AF_BLUETOOTH) +- return -EINVAL; +- +- lock_sock(sk); +- +- if (sk->state != BT_OPEN) { +- err = -EBADFD; +- goto done; +- } +- +- write_lock(&l2cap_sk_list.lock); +- +- if (la->l2_psm && __l2cap_get_sock_by_addr(la)) { +- err = -EADDRINUSE; +- goto unlock; +- } +- +- /* Save source address */ +- bacpy(&l2cap_pi(sk)->src, &la->l2_bdaddr); +- l2cap_pi(sk)->psm = la->l2_psm; +- sk->state = BT_BOUND; +- +-unlock: +- write_unlock(&l2cap_sk_list.lock); +- +-done: +- release_sock(sk); +- +- return err; +-} +- +-static int l2cap_sock_w4_connect(struct sock *sk, int flags) +-{ +- DECLARE_WAITQUEUE(wait, current); +- long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); +- int err = 0; +- +- DBG("sk %p", sk); +- +- add_wait_queue(sk->sleep, &wait); +- current->state = TASK_INTERRUPTIBLE; +- +- while (sk->state != BT_CONNECTED) { +- if (!timeo) { +- err = -EAGAIN; +- break; +- } +- +- release_sock(sk); +- timeo = schedule_timeout(timeo); +- lock_sock(sk); +- +- err = 0; +- if (sk->state == BT_CONNECTED) +- break; +- +- if (sk->err) { +- err = sock_error(sk); +- break; +- } +- +- if (signal_pending(current)) { +- err = sock_intr_errno(timeo); +- break; +- } +- } +- current->state = TASK_RUNNING; +- remove_wait_queue(sk->sleep, &wait); +- +- return err; +-} +- +-static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) +-{ +- struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; +- struct sock *sk = sock->sk; +- int err = 0; +- +- lock_sock(sk); +- +- DBG("sk %p", sk); +- +- if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) { +- err = -EINVAL; +- goto done; +- } +- +- if (sk->state != BT_OPEN && sk->state != BT_BOUND) { +- err = -EBADFD; +- goto done; +- } +- +- if (sk->type == SOCK_SEQPACKET && !la->l2_psm) { +- err = -EINVAL; +- goto done; +- } +- +- /* Set destination address and psm */ +- bacpy(&l2cap_pi(sk)->dst, &la->l2_bdaddr); +- l2cap_pi(sk)->psm = la->l2_psm; +- +- if ((err = l2cap_connect(sk))) +- goto done; +- +- err = l2cap_sock_w4_connect(sk, flags); +- +-done: +- release_sock(sk); +- return err; +-} +- +-int l2cap_sock_listen(struct socket *sock, int backlog) +-{ +- struct sock *sk = sock->sk; +- int err = 0; +- +- DBG("sk %p backlog %d", sk, backlog); +- +- lock_sock(sk); +- +- if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) { +- err = -EBADFD; +- goto done; +- } +- +- if (!l2cap_pi(sk)->psm) { +- err = -EINVAL; +- goto done; +- } +- +- sk->max_ack_backlog = backlog; +- sk->ack_backlog = 0; +- sk->state = BT_LISTEN; +- +-done: +- release_sock(sk); +- return err; +-} +- +-int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags) +-{ +- DECLARE_WAITQUEUE(wait, current); +- struct sock *sk = sock->sk, *ch; +- long timeo; +- int err = 0; +- +- lock_sock(sk); +- +- if (sk->state != BT_LISTEN) { +- err = -EBADFD; +- goto done; +- } +- +- timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); +- +- DBG("sk %p timeo %ld", sk, timeo); +- +- /* Wait for an incoming connection. (wake-one). */ +- add_wait_queue_exclusive(sk->sleep, &wait); +- current->state = TASK_INTERRUPTIBLE; +- while (!(ch = l2cap_accept_dequeue(sk, BT_CONNECTED))) { +- if (!timeo) { +- err = -EAGAIN; +- break; +- } +- +- release_sock(sk); +- timeo = schedule_timeout(timeo); +- lock_sock(sk); +- +- if (sk->state != BT_LISTEN) { +- err = -EBADFD; +- break; +- } +- +- if (signal_pending(current)) { +- err = sock_intr_errno(timeo); +- break; +- } +- } +- current->state = TASK_RUNNING; +- remove_wait_queue(sk->sleep, &wait); +- +- if (err) +- goto done; +- +- sock_graft(ch, newsock); +- newsock->state = SS_CONNECTED; +- +- DBG("new socket %p", ch); +- +-done: +- release_sock(sk); +- +- return err; +-} +- +-static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer) +-{ +- struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; +- struct sock *sk = sock->sk; +- +- DBG("sock %p, sk %p", sock, sk); +- +- addr->sa_family = AF_BLUETOOTH; +- *len = sizeof(struct sockaddr_l2); +- +- if (peer) +- bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->dst); +- else +- bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->src); +- +- la->l2_psm = l2cap_pi(sk)->psm; +- +- return 0; +-} +- +-static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) +-{ +- struct sock *sk = sock->sk; +- int err = 0; +- +- DBG("sock %p, sk %p", sock, sk); +- +- if (sk->err) +- return sock_error(sk); +- +- if (msg->msg_flags & MSG_OOB) +- return -EOPNOTSUPP; +- +- lock_sock(sk); +- +- if (sk->state == BT_CONNECTED) +- err = l2cap_chan_send(sk, msg, len); +- else +- err = -ENOTCONN; +- +- release_sock(sk); +- return err; +-} +- +-static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm) +-{ +- struct sock *sk = sock->sk; +- int noblock = flags & MSG_DONTWAIT; +- int copied, err; +- struct sk_buff *skb; +- +- DBG("sock %p, sk %p", sock, sk); +- +- if (flags & (MSG_OOB)) +- return -EOPNOTSUPP; +- +- if (sk->state == BT_CLOSED) +- return 0; +- +- if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) +- return err; +- +- msg->msg_namelen = 0; +- +- copied = skb->len; +- if (len < copied) { +- msg->msg_flags |= MSG_TRUNC; +- copied = len; +- } +- +- skb->h.raw = skb->data; +- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); +- +- skb_free_datagram(sk, skb); +- +- return err ? : copied; +-} +- +-int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) +-{ +- struct sock *sk = sock->sk; +- struct l2cap_options opts; +- int err = 0; +- +- DBG("sk %p", sk); +- +- lock_sock(sk); +- +- switch (optname) { +- case L2CAP_OPTIONS: +- if (copy_from_user((char *)&opts, optval, optlen)) { +- err = -EFAULT; +- break; +- } +- l2cap_pi(sk)->imtu = opts.imtu; +- l2cap_pi(sk)->omtu = opts.omtu; +- break; +- +- default: +- err = -ENOPROTOOPT; +- break; +- }; +- +- release_sock(sk); +- return err; +-} +- +-int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) +-{ +- struct sock *sk = sock->sk; +- struct l2cap_options opts; +- struct l2cap_conninfo cinfo; +- int len, err = 0; +- +- if (get_user(len, optlen)) +- return -EFAULT; +- +- lock_sock(sk); +- +- switch (optname) { +- case L2CAP_OPTIONS: +- opts.imtu = l2cap_pi(sk)->imtu; +- opts.omtu = l2cap_pi(sk)->omtu; +- opts.flush_to = l2cap_pi(sk)->flush_to; +- +- len = MIN(len, sizeof(opts)); +- if (copy_to_user(optval, (char *)&opts, len)) +- err = -EFAULT; +- +- break; +- +- case L2CAP_CONNINFO: +- if (sk->state != BT_CONNECTED) { +- err = -ENOTCONN; +- break; +- } +- +- cinfo.hci_handle = l2cap_pi(sk)->conn->hconn->handle; +- +- len = MIN(len, sizeof(cinfo)); +- if (copy_to_user(optval, (char *)&cinfo, len)) +- err = -EFAULT; +- +- break; +- +- default: +- err = -ENOPROTOOPT; +- break; +- }; +- +- release_sock(sk); +- return err; +-} +- +-static unsigned int l2cap_sock_poll(struct file * file, struct socket *sock, poll_table *wait) +-{ +- struct sock *sk = sock->sk; +- struct l2cap_accept_q *aq; +- unsigned int mask; +- +- DBG("sock %p, sk %p", sock, sk); +- +- poll_wait(file, sk->sleep, wait); +- mask = 0; +- +- if (sk->err || !skb_queue_empty(&sk->error_queue)) +- mask |= POLLERR; +- +- if (sk->shutdown == SHUTDOWN_MASK) +- mask |= POLLHUP; +- +- aq = &l2cap_pi(sk)->accept_q; +- if (!skb_queue_empty(&sk->receive_queue) || aq->head || (sk->shutdown & RCV_SHUTDOWN)) +- mask |= POLLIN | POLLRDNORM; +- +- if (sk->state == BT_CLOSED) +- mask |= POLLHUP; +- +- if (sock_writeable(sk)) +- mask |= POLLOUT | POLLWRNORM | POLLWRBAND; +- else +- set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); +- +- return mask; +-} +- +-static int l2cap_sock_release(struct socket *sock) +-{ +- struct sock *sk = sock->sk; +- +- DBG("sock %p, sk %p", sock, sk); +- +- if (!sk) +- return 0; +- +- sock_orphan(sk); +- +- l2cap_sock_close(sk); +- +- return 0; +-} +- +-/* --------- L2CAP channels --------- */ +-static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid) +-{ +- struct sock *s; +- +- for (s = l->head; s; s = l2cap_pi(s)->next_c) { +- if (l2cap_pi(s)->dcid == cid) +- break; +- } +- +- return s; +-} +- +-static inline struct sock *l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid) +-{ +- struct sock *s; +- +- read_lock(&l->lock); +- s = __l2cap_get_chan_by_dcid(l, cid); +- read_unlock(&l->lock); +- +- return s; +-} +- +-static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid) +-{ +- struct sock *s; +- +- for (s = l->head; s; s = l2cap_pi(s)->next_c) { +- if (l2cap_pi(s)->scid == cid) +- break; +- } +- +- return s; +-} +-static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid) +-{ +- struct sock *s; +- +- read_lock(&l->lock); +- s = __l2cap_get_chan_by_scid(l, cid); +- read_unlock(&l->lock); +- +- return s; +-} +- +-static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident) +-{ +- struct sock *s; +- +- for (s = l->head; s; s = l2cap_pi(s)->next_c) { +- if (l2cap_pi(s)->ident == ident) +- break; +- } +- +- return s; +-} +- +-static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident) +-{ +- struct sock *s; +- +- read_lock(&l->lock); +- s = __l2cap_get_chan_by_ident(l, ident); +- read_unlock(&l->lock); +- +- return s; +-} +- +-static __u16 l2cap_alloc_cid(struct l2cap_chan_list *l) +-{ +- __u16 cid = 0x0040; +- +- for (; cid < 0xffff; cid++) { +- if(!__l2cap_get_chan_by_scid(l, cid)) +- return cid; +- } +- +- return 0; +-} +- +-static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk) +-{ +- sock_hold(sk); +- +- if (l->head) +- l2cap_pi(l->head)->prev_c = sk; +- +- l2cap_pi(sk)->next_c = l->head; +- l2cap_pi(sk)->prev_c = NULL; +- l->head = sk; +-} +- +-static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) +-{ +- struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c; +- +- write_lock(&l->lock); +- if (sk == l->head) +- l->head = next; +- +- if (next) +- l2cap_pi(next)->prev_c = prev; +- if (prev) +- l2cap_pi(prev)->next_c = next; +- write_unlock(&l->lock); +- +- __sock_put(sk); +-} +- +-static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) +-{ +- struct l2cap_chan_list *l = &conn->chan_list; +- +- DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); +- +- l2cap_conn_clear_timer(conn); +- +- atomic_inc(&conn->refcnt); +- l2cap_pi(sk)->conn = conn; +- +- if (sk->type == SOCK_SEQPACKET) { +- /* Alloc CID for normal socket */ +- l2cap_pi(sk)->scid = l2cap_alloc_cid(l); +- } else { +- /* Raw socket can send only signalling messages */ +- l2cap_pi(sk)->scid = 0x0001; +- l2cap_pi(sk)->dcid = 0x0001; +- l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; +- } +- +- __l2cap_chan_link(l, sk); +- +- if (parent) +- l2cap_accept_queue(parent, sk); +-} +- +-static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) +-{ +- struct l2cap_chan_list *l = &conn->chan_list; +- +- write_lock(&l->lock); +- __l2cap_chan_add(conn, sk, parent); +- write_unlock(&l->lock); +-} +- +-/* Delete channel. +- * Must be called on the locked socket. */ +-static void l2cap_chan_del(struct sock *sk, int err) +-{ +- struct l2cap_conn *conn; +- struct sock *parent; +- +- conn = l2cap_pi(sk)->conn; +- parent = l2cap_pi(sk)->parent; +- +- DBG("sk %p, conn %p, err %d", sk, conn, err); +- +- if (parent) { +- /* Unlink from parent accept queue */ +- bh_lock_sock(parent); +- l2cap_accept_unlink(sk); +- bh_unlock_sock(parent); +- } +- +- if (conn) { +- long timeout; +- +- /* Unlink from channel list */ +- l2cap_chan_unlink(&conn->chan_list, sk); +- l2cap_pi(sk)->conn = NULL; +- +- if (conn->out) +- timeout = L2CAP_DISCONN_TIMEOUT; +- else +- timeout = L2CAP_CONN_IDLE_TIMEOUT; +- +- if (atomic_dec_and_test(&conn->refcnt) && conn->state == BT_CONNECTED) { +- /* Schedule Baseband disconnect */ +- l2cap_conn_set_timer(conn, timeout); +- } +- } +- +- sk->state = BT_CLOSED; +- sk->err = err; +- sk->state_change(sk); +- +- sk->zapped = 1; +-} +- +-static void l2cap_conn_ready(struct l2cap_conn *conn) +-{ +- struct l2cap_chan_list *l = &conn->chan_list; +- struct sock *sk; +- +- DBG("conn %p", conn); +- +- read_lock(&l->lock); +- +- for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { +- bh_lock_sock(sk); +- +- if (sk->type != SOCK_SEQPACKET) { +- sk->state = BT_CONNECTED; +- sk->state_change(sk); +- l2cap_sock_clear_timer(sk); +- } else if (sk->state == BT_CONNECT) { +- l2cap_conn_req req; +- req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); +- req.psm = l2cap_pi(sk)->psm; +- l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req); +- +- l2cap_sock_set_timer(sk, sk->sndtimeo); +- } +- +- bh_unlock_sock(sk); +- } +- +- read_unlock(&l->lock); +-} +- +-static void l2cap_chan_ready(struct sock *sk) +-{ +- struct sock *parent = l2cap_pi(sk)->parent; +- +- DBG("sk %p, parent %p", sk, parent); +- +- l2cap_pi(sk)->conf_state = 0; +- l2cap_sock_clear_timer(sk); +- +- if (!parent) { +- /* Outgoing channel. +- * Wake up socket sleeping on connect. +- */ +- sk->state = BT_CONNECTED; +- sk->state_change(sk); +- } else { +- /* Incomming channel. +- * Wake up socket sleeping on accept. +- */ +- parent->data_ready(parent, 1); +- } +-} +- +-/* Copy frame to all raw sockets on that connection */ +-void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) +-{ +- struct l2cap_chan_list *l = &conn->chan_list; +- struct sk_buff *nskb; +- struct sock * sk; +- +- DBG("conn %p", conn); +- +- read_lock(&l->lock); +- for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { +- if (sk->type != SOCK_RAW) +- continue; +- +- /* Don't send frame to the socket it came from */ +- if (skb->sk == sk) +- continue; +- +- if (!(nskb = skb_clone(skb, GFP_ATOMIC))) +- continue; +- +- skb_queue_tail(&sk->receive_queue, nskb); +- sk->data_ready(sk, nskb->len); +- } +- read_unlock(&l->lock); +-} +- +-static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len) +-{ +- struct l2cap_conn *conn = l2cap_pi(sk)->conn; +- struct sk_buff *skb, **frag; +- int err, size, count, sent=0; +- l2cap_hdr *lh; +- +- /* Check outgoing MTU */ +- if (len > l2cap_pi(sk)->omtu) +- return -EINVAL; +- +- DBG("sk %p len %d", sk, len); +- +- /* First fragment (with L2CAP header) */ +- count = MIN(conn->iff->mtu - L2CAP_HDR_SIZE, len); +- size = L2CAP_HDR_SIZE + count; +- if (!(skb = bluez_skb_send_alloc(sk, size, msg->msg_flags & MSG_DONTWAIT, &err))) +- return err; +- +- /* Create L2CAP header */ +- lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); +- lh->len = __cpu_to_le16(len); +- lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid); +- +- if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) { +- err = -EFAULT; +- goto fail; +- } +- +- sent += count; +- len -= count; +- +- /* Continuation fragments (no L2CAP header) */ +- frag = &skb_shinfo(skb)->frag_list; +- while (len) { +- count = MIN(conn->iff->mtu, len); +- +- *frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err); +- if (!*frag) +- goto fail; +- +- if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) { +- err = -EFAULT; +- goto fail; +- } +- +- sent += count; +- len -= count; +- +- frag = &(*frag)->next; +- } +- +- if ((err = hci_send_acl(conn->hconn, skb, 0)) < 0) +- goto fail; +- +- return sent; +- +-fail: +- kfree_skb(skb); +- return err; +-} +- +-/* --------- L2CAP signalling commands --------- */ +-static inline __u8 l2cap_get_ident(struct l2cap_conn *conn) +-{ +- __u8 id; +- +- /* Get next available identificator. +- * 1 - 199 are used by kernel. +- * 200 - 254 are used by utilities like l2ping, etc +- */ +- +- spin_lock(&conn->lock); +- +- if (++conn->tx_ident > 199) +- conn->tx_ident = 1; +- +- id = conn->tx_ident; +- +- spin_unlock(&conn->lock); +- +- return id; +-} +- +-static inline struct sk_buff *l2cap_build_cmd(__u8 code, __u8 ident, __u16 len, void *data) +-{ +- struct sk_buff *skb; +- l2cap_cmd_hdr *cmd; +- l2cap_hdr *lh; +- int size; +- +- DBG("code 0x%2.2x, ident 0x%2.2x, len %d", code, ident, len); +- +- size = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + len; +- if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) +- return NULL; +- +- lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); +- lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + len); +- lh->cid = __cpu_to_le16(0x0001); +- +- cmd = (l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE); +- cmd->code = code; +- cmd->ident = ident; +- cmd->len = __cpu_to_le16(len); +- +- if (len) +- memcpy(skb_put(skb, len), data, len); +- +- return skb; +-} +- +-static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data) +-{ +- struct sk_buff *skb; +- __u8 ident; +- +- DBG("code 0x%2.2x", code); +- +- ident = l2cap_get_ident(conn); +- if (!(skb = l2cap_build_cmd(code, ident, len, data))) +- return -ENOMEM; +- return hci_send_acl(conn->hconn, skb, 0); +-} +- +-static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data) +-{ +- struct sk_buff *skb; +- +- DBG("code 0x%2.2x", code); +- +- if (!(skb = l2cap_build_cmd(code, ident, len, data))) +- return -ENOMEM; +- return hci_send_acl(conn->hconn, skb, 0); +-} +- +-static inline int l2cap_get_conf_opt(__u8 **ptr, __u8 *type, __u32 *val) +-{ +- l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr); +- int len; +- +- *type = opt->type; +- switch (opt->len) { +- case 1: +- *val = *((__u8 *) opt->val); +- break; +- +- case 2: +- *val = __le16_to_cpu(*((__u16 *)opt->val)); +- break; +- +- case 4: +- *val = __le32_to_cpu(*((__u32 *)opt->val)); +- break; +- +- default: +- *val = 0L; +- break; +- }; +- +- DBG("type 0x%2.2x len %d val 0x%8.8x", *type, opt->len, *val); +- +- len = L2CAP_CONF_OPT_SIZE + opt->len; +- +- *ptr += len; +- +- return len; +-} +- +-static inline void l2cap_parse_conf_req(struct sock *sk, char *data, int len) +-{ +- __u8 type, hint; __u32 val; +- __u8 *ptr = data; +- +- DBG("sk %p len %d", sk, len); +- +- while (len >= L2CAP_CONF_OPT_SIZE) { +- len -= l2cap_get_conf_opt(&ptr, &type, &val); +- +- hint = type & 0x80; +- type &= 0x7f; +- +- switch (type) { +- case L2CAP_CONF_MTU: +- l2cap_pi(sk)->conf_mtu = val; +- break; +- +- case L2CAP_CONF_FLUSH_TO: +- l2cap_pi(sk)->flush_to = val; +- break; +- +- case L2CAP_CONF_QOS: +- break; +- +- default: +- if (hint) +- break; +- +- /* FIXME: Reject unknon option */ +- break; +- }; +- } +-} +- +-static inline void l2cap_add_conf_opt(__u8 **ptr, __u8 type, __u8 len, __u32 val) +-{ +- register l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr); +- +- DBG("type 0x%2.2x len %d val 0x%8.8x", type, len, val); +- +- opt->type = type; +- opt->len = len; +- switch (len) { +- case 1: +- *((__u8 *) opt->val) = val; +- break; +- +- case 2: +- *((__u16 *) opt->val) = __cpu_to_le16(val); +- break; +- +- case 4: +- *((__u32 *) opt->val) = __cpu_to_le32(val); +- break; +- }; +- +- *ptr += L2CAP_CONF_OPT_SIZE + len; +-} +- +-static int l2cap_build_conf_req(struct sock *sk, __u8 *data) +-{ +- struct l2cap_pinfo *pi = l2cap_pi(sk); +- l2cap_conf_req *req = (l2cap_conf_req *) data; +- __u8 *ptr = req->data; +- +- DBG("sk %p", sk); +- +- if (pi->imtu != L2CAP_DEFAULT_MTU) +- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu); +- +- /* FIXME. Need actual value of the flush timeout */ +- //if (flush_to != L2CAP_DEFAULT_FLUSH_TO) +- // l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to); +- +- req->dcid = __cpu_to_le16(pi->dcid); +- req->flags = __cpu_to_le16(0); +- +- return ptr - data; +-} +- +-static int l2cap_conf_output(struct sock *sk, __u8 **ptr) +-{ +- struct l2cap_pinfo *pi = l2cap_pi(sk); +- int result = 0; +- +- /* Configure output options and let other side know +- * which ones we don't like. +- */ +- if (pi->conf_mtu < pi->omtu) { +- l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, l2cap_pi(sk)->omtu); +- result = L2CAP_CONF_UNACCEPT; +- } else { +- pi->omtu = pi->conf_mtu; +- } +- +- DBG("sk %p result %d", sk, result); +- return result; +-} +- +-static int l2cap_build_conf_rsp(struct sock *sk, __u8 *data, int *result) +-{ +- l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data; +- __u8 *ptr = rsp->data; +- +- DBG("sk %p complete %d", sk, result ? 1 : 0); +- +- if (result) +- *result = l2cap_conf_output(sk, &ptr); +- +- rsp->scid = __cpu_to_le16(l2cap_pi(sk)->dcid); +- rsp->result = __cpu_to_le16(result ? *result : 0); +- rsp->flags = __cpu_to_le16(0); +- +- return ptr - data; +-} +- +-static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) +-{ +- struct l2cap_chan_list *list = &conn->chan_list; +- l2cap_conn_req *req = (l2cap_conn_req *) data; +- l2cap_conn_rsp rsp; +- struct sock *sk, *parent; +- +- __u16 scid = __le16_to_cpu(req->scid); +- __u16 psm = req->psm; +- +- DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid); +- +- /* Check if we have socket listening on psm */ +- if (!(parent = l2cap_get_sock_listen(&conn->src, psm))) +- goto reject; +- +- bh_lock_sock(parent); +- write_lock(&list->lock); +- +- /* Check if we already have channel with that dcid */ +- if (__l2cap_get_chan_by_dcid(list, scid)) +- goto unlock; +- +- /* Check for backlog size */ +- if (parent->ack_backlog > parent->max_ack_backlog) +- goto unlock; +- +- if (!(sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC))) +- goto unlock; +- +- l2cap_sock_init(sk, parent); +- +- bacpy(&l2cap_pi(sk)->src, &conn->src); +- bacpy(&l2cap_pi(sk)->dst, &conn->dst); +- l2cap_pi(sk)->psm = psm; +- l2cap_pi(sk)->dcid = scid; +- +- __l2cap_chan_add(conn, sk, parent); +- sk->state = BT_CONFIG; +- +- write_unlock(&list->lock); +- bh_unlock_sock(parent); +- +- rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid); +- rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid); +- rsp.result = __cpu_to_le16(0); +- rsp.status = __cpu_to_le16(0); +- l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp); +- +- return 0; +- +-unlock: +- write_unlock(&list->lock); +- bh_unlock_sock(parent); +- +-reject: +- rsp.scid = __cpu_to_le16(scid); +- rsp.dcid = __cpu_to_le16(0); +- rsp.status = __cpu_to_le16(0); +- rsp.result = __cpu_to_le16(L2CAP_CONN_NO_MEM); +- l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp); +- +- return 0; +-} +- +-static inline int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) +-{ +- l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data; +- __u16 scid, dcid, result, status; +- struct sock *sk; +- +- scid = __le16_to_cpu(rsp->scid); +- dcid = __le16_to_cpu(rsp->dcid); +- result = __le16_to_cpu(rsp->result); +- status = __le16_to_cpu(rsp->status); +- +- DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); +- +- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) +- return -ENOENT; +- +- bh_lock_sock(sk); +- +- if (!result) { +- char req[64]; +- +- sk->state = BT_CONFIG; +- l2cap_pi(sk)->dcid = dcid; +- l2cap_pi(sk)->conf_state |= CONF_REQ_SENT; +- +- l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req); +- } else { +- l2cap_chan_del(sk, ECONNREFUSED); +- } +- +- bh_unlock_sock(sk); +- return 0; +-} +- +-static inline int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) +-{ +- l2cap_conf_req * req = (l2cap_conf_req *) data; +- __u16 dcid, flags; +- __u8 rsp[64]; +- struct sock *sk; +- int result; +- +- dcid = __le16_to_cpu(req->dcid); +- flags = __le16_to_cpu(req->flags); +- +- DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags); +- +- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid))) +- return -ENOENT; +- +- bh_lock_sock(sk); +- +- l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE); +- +- if (flags & 0x01) { +- /* Incomplete config. Send empty response. */ +- l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp); +- goto unlock; +- } +- +- /* Complete config. */ +- l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp); +- +- if (result) +- goto unlock; +- +- /* Output config done */ +- l2cap_pi(sk)->conf_state |= CONF_OUTPUT_DONE; +- +- if (l2cap_pi(sk)->conf_state & CONF_INPUT_DONE) { +- sk->state = BT_CONNECTED; +- l2cap_chan_ready(sk); +- } else if (!(l2cap_pi(sk)->conf_state & CONF_REQ_SENT)) { +- char req[64]; +- l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req); +- } +- +-unlock: +- bh_unlock_sock(sk); +- +- return 0; +-} +- +-static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) +-{ +- l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data; +- __u16 scid, flags, result; +- struct sock *sk; +- int err = 0; +- +- scid = __le16_to_cpu(rsp->scid); +- flags = __le16_to_cpu(rsp->flags); +- result = __le16_to_cpu(rsp->result); +- +- DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result); +- +- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) +- return -ENOENT; +- +- bh_lock_sock(sk); +- +- if (result) { +- l2cap_disconn_req req; +- +- /* They didn't like our options. Well... we do not negotiate. +- * Close channel. +- */ +- sk->state = BT_DISCONN; +- +- req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid); +- req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); +- l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req); +- +- l2cap_sock_set_timer(sk, sk->sndtimeo); +- goto done; +- } +- +- if (flags & 0x01) +- goto done; +- +- /* Input config done */ +- l2cap_pi(sk)->conf_state |= CONF_INPUT_DONE; +- +- if (l2cap_pi(sk)->conf_state & CONF_OUTPUT_DONE) { +- sk->state = BT_CONNECTED; +- l2cap_chan_ready(sk); +- } +- +-done: +- bh_unlock_sock(sk); +- +- return err; +-} +- +-static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) +-{ +- l2cap_disconn_req *req = (l2cap_disconn_req *) data; +- l2cap_disconn_rsp rsp; +- __u16 dcid, scid; +- struct sock *sk; +- +- scid = __le16_to_cpu(req->scid); +- dcid = __le16_to_cpu(req->dcid); +- +- DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); +- +- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid))) +- return 0; +- +- bh_lock_sock(sk); +- +- rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid); +- rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid); +- l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp); +- +- l2cap_chan_del(sk, ECONNRESET); +- +- bh_unlock_sock(sk); +- +- l2cap_sock_kill(sk); +- +- return 0; +-} +- +-static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) +-{ +- l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data; +- __u16 dcid, scid; +- struct sock *sk; +- +- scid = __le16_to_cpu(rsp->scid); +- dcid = __le16_to_cpu(rsp->dcid); +- +- DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); +- +- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) +- return -ENOENT; +- +- bh_lock_sock(sk); +- l2cap_sock_clear_timer(sk); +- l2cap_chan_del(sk, ECONNABORTED); +- bh_unlock_sock(sk); +- +- l2cap_sock_kill(sk); +- +- return 0; +-} +- +-static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) +-{ +- __u8 *data = skb->data; +- int len = skb->len; +- l2cap_cmd_hdr cmd; +- int err = 0; +- +- while (len >= L2CAP_CMD_HDR_SIZE) { +- memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE); +- data += L2CAP_CMD_HDR_SIZE; +- len -= L2CAP_CMD_HDR_SIZE; +- +- cmd.len = __le16_to_cpu(cmd.len); +- +- DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident); +- +- if (cmd.len > len || !cmd.ident) { +- DBG("corrupted command"); +- break; +- } +- +- switch (cmd.code) { +- case L2CAP_CONN_REQ: +- err = l2cap_connect_req(conn, &cmd, data); +- break; +- +- case L2CAP_CONN_RSP: +- err = l2cap_connect_rsp(conn, &cmd, data); +- break; +- +- case L2CAP_CONF_REQ: +- err = l2cap_config_req(conn, &cmd, data); +- break; +- +- case L2CAP_CONF_RSP: +- err = l2cap_config_rsp(conn, &cmd, data); +- break; +- +- case L2CAP_DISCONN_REQ: +- err = l2cap_disconnect_req(conn, &cmd, data); +- break; +- +- case L2CAP_DISCONN_RSP: +- err = l2cap_disconnect_rsp(conn, &cmd, data); +- break; +- +- case L2CAP_COMMAND_REJ: +- /* FIXME: We should process this */ +- l2cap_raw_recv(conn, skb); +- break; +- +- case L2CAP_ECHO_REQ: +- l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data); +- break; +- +- case L2CAP_ECHO_RSP: +- case L2CAP_INFO_REQ: +- case L2CAP_INFO_RSP: +- l2cap_raw_recv(conn, skb); +- break; +- +- default: +- ERR("Uknown signaling command 0x%2.2x", cmd.code); +- err = -EINVAL; +- break; +- }; +- +- if (err) { +- l2cap_cmd_rej rej; +- DBG("error %d", err); +- +- /* FIXME: Map err to a valid reason. */ +- rej.reason = __cpu_to_le16(0); +- l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej); +- } +- +- data += cmd.len; +- len -= cmd.len; +- } +- +- kfree_skb(skb); +-} +- +-static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb) +-{ +- struct sock *sk; +- +- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, cid))) { +- DBG("unknown cid 0x%4.4x", cid); +- goto drop; +- } +- +- DBG("sk %p, len %d", sk, skb->len); +- +- if (sk->state != BT_CONNECTED) +- goto drop; +- +- if (l2cap_pi(sk)->imtu < skb->len) +- goto drop; +- +- skb_queue_tail(&sk->receive_queue, skb); +- sk->data_ready(sk, skb->len); +- +- return 0; +- +-drop: +- kfree_skb(skb); +- +- return 0; +-} +- +-static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) +-{ +- l2cap_hdr *lh = (l2cap_hdr *) skb->data; +- __u16 cid, len; +- +- skb_pull(skb, L2CAP_HDR_SIZE); +- cid = __le16_to_cpu(lh->cid); +- len = __le16_to_cpu(lh->len); +- +- DBG("len %d, cid 0x%4.4x", len, cid); +- +- if (cid == 0x0001) +- l2cap_sig_channel(conn, skb); +- else +- l2cap_data_channel(conn, cid, skb); +-} +- +-/* ------------ L2CAP interface with lower layer (HCI) ------------- */ +-static int l2cap_dev_event(struct notifier_block *this, unsigned long event, void *ptr) +-{ +- struct hci_dev *hdev = (struct hci_dev *) ptr; +- +- DBG("hdev %s, event %ld", hdev->name, event); +- +- write_lock(&l2cap_rt_lock); +- +- switch (event) { +- case HCI_DEV_UP: +- l2cap_iff_add(hdev); +- break; +- +- case HCI_DEV_DOWN: +- l2cap_iff_del(hdev); +- break; +- }; +- +- write_unlock(&l2cap_rt_lock); +- +- return NOTIFY_DONE; +-} +- +-int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) +-{ +- struct l2cap_iff *iff; +- +- DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); +- +- if (!(iff = hdev->l2cap_data)) { +- ERR("unknown interface"); +- return 0; +- } +- +- /* Always accept connection */ +- return 1; +-} +- +-int l2cap_connect_cfm(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *hconn) +-{ +- struct l2cap_conn *conn; +- struct l2cap_iff *iff; +- int err = 0; +- +- DBG("hdev %s bdaddr %s hconn %p", hdev->name, batostr(bdaddr), hconn); +- +- if (!(iff = hdev->l2cap_data)) { +- ERR("unknown interface"); +- return 0; +- } +- +- l2cap_iff_lock(iff); +- +- conn = l2cap_get_conn_by_addr(iff, bdaddr); +- +- if (conn) { +- /* Outgoing connection */ +- DBG("Outgoing connection: %s -> %s, %p, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), conn, status); +- +- if (!status && hconn) { +- conn->state = BT_CONNECTED; +- conn->hconn = hconn; +- +- hconn->l2cap_data = (void *)conn; +- +- /* Establish channels */ +- l2cap_conn_ready(conn); +- } else { +- l2cap_conn_del(conn, bterr(status)); +- } +- } else { +- /* Incomming connection */ +- DBG("Incomming connection: %s -> %s, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), status); +- +- if (status || !hconn) +- goto done; +- +- if (!(conn = l2cap_conn_add(iff, bdaddr))) { +- err = -ENOMEM; +- goto done; +- } +- +- conn->hconn = hconn; +- hconn->l2cap_data = (void *)conn; +- +- conn->state = BT_CONNECTED; +- } +- +-done: +- l2cap_iff_unlock(iff); +- +- return err; +-} +- +-int l2cap_disconn_ind(struct hci_conn *hconn, __u8 reason) +-{ +- struct l2cap_conn *conn = hconn->l2cap_data; +- +- DBG("hconn %p reason %d", hconn, reason); +- +- if (!conn) { +- ERR("unknown connection"); +- return 0; +- } +- conn->hconn = NULL; +- +- l2cap_iff_lock(conn->iff); +- l2cap_conn_del(conn, bterr(reason)); +- l2cap_iff_unlock(conn->iff); +- +- return 0; +-} +- +-int l2cap_recv_acldata(struct hci_conn *hconn, struct sk_buff *skb, __u16 flags) +-{ +- struct l2cap_conn *conn = hconn->l2cap_data; +- +- if (!conn) { +- ERR("unknown connection %p", hconn); +- goto drop; +- } +- +- DBG("conn %p len %d flags 0x%x", conn, skb->len, flags); +- +- if (flags & ACL_START) { +- int flen, tlen, size; +- l2cap_hdr *lh; +- +- if (conn->rx_len) { +- ERR("Unexpected start frame (len %d)", skb->len); +- kfree_skb(conn->rx_skb); conn->rx_skb = NULL; +- conn->rx_len = 0; +- } +- +- if (skb->len < L2CAP_HDR_SIZE) { +- ERR("Frame is too small (len %d)", skb->len); +- goto drop; +- } +- +- lh = (l2cap_hdr *)skb->data; +- tlen = __le16_to_cpu(lh->len); +- flen = skb->len - L2CAP_HDR_SIZE; +- +- DBG("Start: total len %d, frag len %d", tlen, flen); +- +- if (flen == tlen) { +- /* Complete frame received */ +- l2cap_recv_frame(conn, skb); +- return 0; +- } +- +- /* Allocate skb for the complete frame (with header) */ +- size = L2CAP_HDR_SIZE + tlen; +- if (!(conn->rx_skb = bluez_skb_alloc(size, GFP_ATOMIC))) +- goto drop; +- +- memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len); +- +- conn->rx_len = tlen - flen; +- } else { +- DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len); +- +- if (!conn->rx_len) { +- ERR("Unexpected continuation frame (len %d)", skb->len); +- goto drop; +- } +- +- if (skb->len > conn->rx_len) { +- ERR("Fragment is too large (len %d)", skb->len); +- kfree_skb(conn->rx_skb); conn->rx_skb = NULL; +- goto drop; +- } +- +- memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len); +- conn->rx_len -= skb->len; +- +- if (!conn->rx_len) { +- /* Complete frame received */ +- l2cap_recv_frame(conn, conn->rx_skb); +- conn->rx_skb = NULL; +- } +- } +- +-drop: +- kfree_skb(skb); +- return 0; +-} +- +-struct proto_ops l2cap_sock_ops = { +- family: PF_BLUETOOTH, +- release: l2cap_sock_release, +- bind: l2cap_sock_bind, +- connect: l2cap_sock_connect, +- listen: l2cap_sock_listen, +- accept: l2cap_sock_accept, +- getname: l2cap_sock_getname, +- sendmsg: l2cap_sock_sendmsg, +- recvmsg: l2cap_sock_recvmsg, +- poll: l2cap_sock_poll, +- socketpair: sock_no_socketpair, +- ioctl: sock_no_ioctl, +- shutdown: sock_no_shutdown, +- setsockopt: l2cap_sock_setsockopt, +- getsockopt: l2cap_sock_getsockopt, +- mmap: sock_no_mmap +-}; +- +-struct net_proto_family l2cap_sock_family_ops = { +- family: PF_BLUETOOTH, +- create: l2cap_sock_create +-}; +- +-struct hci_proto l2cap_hci_proto = { +- name: "L2CAP", +- id: HCI_PROTO_L2CAP, +- connect_ind: l2cap_connect_ind, +- connect_cfm: l2cap_connect_cfm, +- disconn_ind: l2cap_disconn_ind, +- recv_acldata: l2cap_recv_acldata, +-}; +- +-struct notifier_block l2cap_nblock = { +- notifier_call: l2cap_dev_event +-}; +- +-int __init l2cap_init(void) +-{ +- INF("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc", +- VERSION); +- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); +- +- if (bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops)) { +- ERR("Can't register L2CAP socket"); +- return -EPROTO; +- } +- +- if (hci_register_proto(&l2cap_hci_proto) < 0) { +- ERR("Can't register L2CAP protocol"); +- return -EPROTO; +- } +- +- hci_register_notifier(&l2cap_nblock); +- +- l2cap_register_proc(); +- +- return 0; +-} +- +-void l2cap_cleanup(void) +-{ +- l2cap_unregister_proc(); +- +- /* Unregister socket, protocol and notifier */ +- if (bluez_sock_unregister(BTPROTO_L2CAP)) +- ERR("Can't unregister L2CAP socket"); +- +- if (hci_unregister_proto(&l2cap_hci_proto) < 0) +- ERR("Can't unregister L2CAP protocol"); +- +- hci_unregister_notifier(&l2cap_nblock); +- +- /* We _must_ not have any sockets and/or connections +- * at this stage. +- */ +- +- /* Free interface list and unlock HCI devices */ +- { +- struct list_head *list = &l2cap_iff_list; +- +- while (!list_empty(list)) { +- struct l2cap_iff *iff; +- +- iff = list_entry(list->next, struct l2cap_iff, list); +- l2cap_iff_del(iff->hdev); +- } +- } +-} +- +-module_init(l2cap_init); +-module_exit(l2cap_cleanup); +- +-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); +-MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION); +-MODULE_LICENSE("GPL"); +- +--- linux/net/bluetooth/l2cap_proc.c~bluetooth-2.4.18-mh11 ++++ linux/net/bluetooth/l2cap_proc.c +-/* +- BlueZ - Bluetooth protocol stack for Linux +- Copyright (C) 2000-2001 Qualcomm Incorporated +- +- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; +- +- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY +- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES +- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- +- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, +- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS +- SOFTWARE IS DISCLAIMED. +-*/ +- +-/* +- * BlueZ L2CAP proc fs support. +- * +- * $Id$ +- */ +- +-#include <linux/config.h> +-#include <linux/module.h> +- +-#include <linux/types.h> +-#include <linux/errno.h> +-#include <linux/kernel.h> +-#include <linux/major.h> +-#include <linux/sched.h> +-#include <linux/slab.h> +-#include <linux/poll.h> +-#include <linux/fcntl.h> +-#include <linux/init.h> +-#include <linux/skbuff.h> +-#include <linux/interrupt.h> +-#include <linux/socket.h> +-#include <linux/skbuff.h> +-#include <linux/proc_fs.h> +-#include <linux/list.h> +-#include <net/sock.h> +- +-#include <asm/system.h> +-#include <asm/uaccess.h> +- +-#include <net/bluetooth/bluez.h> +-#include <net/bluetooth/bluetooth.h> +-#include <net/bluetooth/hci_core.h> +-#include <net/bluetooth/l2cap_core.h> +- +-#ifndef L2CAP_DEBUG +-#undef DBG +-#define DBG( A... ) +-#endif +- +-/* ----- PROC fs support ----- */ +-static int l2cap_conn_dump(char *buf, struct l2cap_iff *iff) +-{ +- struct list_head *p; +- char *ptr = buf; +- +- list_for_each(p, &iff->conn_list) { +- struct l2cap_conn *c; +- +- c = list_entry(p, struct l2cap_conn, list); +- ptr += sprintf(ptr, " %p %d %p %p %s %s\n", +- c, c->state, c->iff, c->hconn, batostr(&c->src), batostr(&c->dst)); +- } +- +- return ptr - buf; +-} +- +-static int l2cap_iff_dump(char *buf) +-{ +- struct list_head *p; +- char *ptr = buf; +- +- ptr += sprintf(ptr, "Interfaces:\n"); +- +- write_lock(&l2cap_rt_lock); +- +- list_for_each(p, &l2cap_iff_list) { +- struct l2cap_iff *iff; +- +- iff = list_entry(p, struct l2cap_iff, list); +- +- ptr += sprintf(ptr, " %s %p %p\n", iff->hdev->name, iff, iff->hdev); +- +- l2cap_iff_lock(iff); +- ptr += l2cap_conn_dump(ptr, iff); +- l2cap_iff_unlock(iff); +- } +- +- write_unlock(&l2cap_rt_lock); +- +- ptr += sprintf(ptr, "\n"); +- +- return ptr - buf; +-} +- +-static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list) +-{ +- struct l2cap_pinfo *pi; +- struct sock *sk; +- char *ptr = buf; +- +- ptr += sprintf(ptr, "Sockets:\n"); +- +- write_lock(&list->lock); +- +- for (sk = list->head; sk; sk = sk->next) { +- pi = l2cap_pi(sk); +- ptr += sprintf(ptr, " %p %d %p %d %s %s 0x%4.4x 0x%4.4x %d %d\n", sk, sk->state, pi->conn, pi->psm, +- batostr(&pi->src), batostr(&pi->dst), pi->scid, pi->dcid, pi->imtu, pi->omtu ); +- } +- +- write_unlock(&list->lock); +- +- ptr += sprintf(ptr, "\n"); +- +- return ptr - buf; +-} +- +-static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv) +-{ +- char *ptr = buf; +- int len; +- +- DBG("count %d, offset %ld", count, offset); +- +- ptr += l2cap_iff_dump(ptr); +- ptr += l2cap_sock_dump(ptr, &l2cap_sk_list); +- len = ptr - buf; +- +- if (len <= count + offset) +- *eof = 1; +- +- *start = buf + offset; +- len -= offset; +- +- if (len > count) +- len = count; +- if (len < 0) +- len = 0; +- +- return len; +-} +- +-void l2cap_register_proc(void) +-{ +- create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL); +-} +- +-void l2cap_unregister_proc(void) +-{ +- remove_proc_entry("bluetooth/l2cap", NULL); +-} +--- linux/net/bluetooth/lib.c~bluetooth-2.4.18-mh11 2001-09-07 18:28:38.000000000 +0200 ++++ linux/net/bluetooth/lib.c 2004-01-25 23:37:39.000000000 +0100 +@@ -25,7 +25,7 @@ + /* + * BlueZ kernel library. + * +- * $Id$ ++ * $Id$ + */ + + #include <linux/kernel.h> +@@ -105,7 +105,7 @@ + return EACCES; + + case 0x06: +- return EINVAL; ++ return EBADE; + + case 0x07: + return ENOMEM; +--- linux/net/bluetooth/Makefile~bluetooth-2.4.18-mh11 2001-06-12 04:15:27.000000000 +0200 ++++ linux/net/bluetooth/Makefile 2004-01-25 23:37:39.000000000 +0100 +@@ -1,20 +1,31 @@ + # +-# Makefile for the Bluetooth subsystem ++# Makefile for the Linux Bluetooth subsystem + # +-O_TARGET := bluetooth.o + +-list-multi := hci.o l2cap.o +-export-objs := syms.o +-hci-objs := af_bluetooth.o hci_core.o hci_sock.o lib.o syms.o +-l2cap-objs := l2cap_core.o l2cap_proc.o ++O_TARGET := bluetooth.o + +-obj-$(CONFIG_BLUEZ) += hci.o ++list-multi := bluez.o ++export-objs := syms.o l2cap.o ++ ++bluez-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o lib.o syms.o ++ ++obj-$(CONFIG_BLUEZ) += bluez.o + obj-$(CONFIG_BLUEZ_L2CAP) += l2cap.o ++obj-$(CONFIG_BLUEZ_SCO) += sco.o + +-include $(TOPDIR)/Rules.make ++subdir-$(CONFIG_BLUEZ_RFCOMM) += rfcomm ++subdir-$(CONFIG_BLUEZ_BNEP) += bnep ++subdir-$(CONFIG_BLUEZ_CMTP) += cmtp + +-hci.o: $(hci-objs) +- $(LD) -r -o $@ $(hci-objs) ++ifeq ($(CONFIG_BLUEZ_RFCOMM),y) ++obj-y += rfcomm/rfcomm.o ++endif + +-l2cap.o: $(l2cap-objs) +- $(LD) -r -o $@ $(l2cap-objs) ++ifeq ($(CONFIG_BLUEZ_BNEP),y) ++obj-y += bnep/bnep.o ++endif ++ ++include $(TOPDIR)/Rules.make ++ ++bluez.o: $(bluez-objs) ++ $(LD) -r -o $@ $(bluez-objs) +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/rfcomm/Config.in 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,10 @@ ++# ++# Bluetooth RFCOMM layer configuration ++# ++ ++dep_tristate 'RFCOMM protocol support' CONFIG_BLUEZ_RFCOMM $CONFIG_BLUEZ_L2CAP ++ ++if [ "$CONFIG_BLUEZ_RFCOMM" != "n" ]; then ++ bool ' RFCOMM TTY support' CONFIG_BLUEZ_RFCOMM_TTY ++fi ++ +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/rfcomm/core.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,1939 @@ ++/* ++ RFCOMM implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com> ++ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ RPN support - Dirk Husemann <hud@zurich.ibm.com> ++*/ ++ ++/* ++ * RFCOMM core. ++ * ++ * $Id$ ++ */ ++ ++#define __KERNEL_SYSCALLS__ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/signal.h> ++#include <linux/init.h> ++#include <linux/wait.h> ++#include <linux/net.h> ++#include <linux/proc_fs.h> ++#include <net/sock.h> ++#include <asm/uaccess.h> ++#include <asm/unaligned.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/l2cap.h> ++#include <net/bluetooth/rfcomm.h> ++ ++#define VERSION "1.1" ++ ++#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG ++#undef BT_DBG ++#define BT_DBG(D...) ++#endif ++ ++struct task_struct *rfcomm_thread; ++DECLARE_MUTEX(rfcomm_sem); ++unsigned long rfcomm_event; ++ ++static LIST_HEAD(session_list); ++static atomic_t terminate, running; ++ ++static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len); ++static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci); ++static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci); ++static int rfcomm_queue_disc(struct rfcomm_dlc *d); ++static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type); ++static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d); ++static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig); ++static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len); ++static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits); ++static void rfcomm_make_uih(struct sk_buff *skb, u8 addr); ++ ++static void rfcomm_process_connect(struct rfcomm_session *s); ++ ++/* ---- RFCOMM frame parsing macros ---- */ ++#define __get_dlci(b) ((b & 0xfc) >> 2) ++#define __get_channel(b) ((b & 0xf8) >> 3) ++#define __get_dir(b) ((b & 0x04) >> 2) ++#define __get_type(b) ((b & 0xef)) ++ ++#define __test_ea(b) ((b & 0x01)) ++#define __test_cr(b) ((b & 0x02)) ++#define __test_pf(b) ((b & 0x10)) ++ ++#define __addr(cr, dlci) (((dlci & 0x3f) << 2) | (cr << 1) | 0x01) ++#define __ctrl(type, pf) (((type & 0xef) | (pf << 4))) ++#define __dlci(dir, chn) (((chn & 0x1f) << 1) | dir) ++#define __srv_channel(dlci) (dlci >> 1) ++#define __dir(dlci) (dlci & 0x01) ++ ++#define __len8(len) (((len) << 1) | 1) ++#define __len16(len) ((len) << 1) ++ ++/* MCC macros */ ++#define __mcc_type(cr, type) (((type << 2) | (cr << 1) | 0x01)) ++#define __get_mcc_type(b) ((b & 0xfc) >> 2) ++#define __get_mcc_len(b) ((b & 0xfe) >> 1) ++ ++/* RPN macros */ ++#define __rpn_line_settings(data, stop, parity) ((data & 0x3) | ((stop & 0x1) << 2) | ((parity & 0x3) << 3)) ++#define __get_rpn_data_bits(line) ((line) & 0x3) ++#define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1) ++#define __get_rpn_parity(line) (((line) >> 3) & 0x3) ++ ++/* ---- RFCOMM FCS computation ---- */ ++ ++/* CRC on 2 bytes */ ++#define __crc(data) (rfcomm_crc_table[rfcomm_crc_table[0xff ^ data[0]] ^ data[1]]) ++ ++/* FCS on 2 bytes */ ++static inline u8 __fcs(u8 *data) ++{ ++ return (0xff - __crc(data)); ++} ++ ++/* FCS on 3 bytes */ ++static inline u8 __fcs2(u8 *data) ++{ ++ return (0xff - rfcomm_crc_table[__crc(data) ^ data[2]]); ++} ++ ++/* Check FCS */ ++static inline int __check_fcs(u8 *data, int type, u8 fcs) ++{ ++ u8 f = __crc(data); ++ ++ if (type != RFCOMM_UIH) ++ f = rfcomm_crc_table[f ^ data[2]]; ++ ++ return rfcomm_crc_table[f ^ fcs] != 0xcf; ++} ++ ++/* ---- L2CAP callbacks ---- */ ++static void rfcomm_l2state_change(struct sock *sk) ++{ ++ BT_DBG("%p state %d", sk, sk->state); ++ rfcomm_schedule(RFCOMM_SCHED_STATE); ++} ++ ++static void rfcomm_l2data_ready(struct sock *sk, int bytes) ++{ ++ BT_DBG("%p bytes %d", sk, bytes); ++ rfcomm_schedule(RFCOMM_SCHED_RX); ++} ++ ++static int rfcomm_l2sock_create(struct socket **sock) ++{ ++ int err; ++ ++ BT_DBG(""); ++ ++ err = sock_create(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP, sock); ++ if (!err) { ++ struct sock *sk = (*sock)->sk; ++ sk->data_ready = rfcomm_l2data_ready; ++ sk->state_change = rfcomm_l2state_change; ++ } ++ return err; ++} ++ ++/* ---- RFCOMM DLCs ---- */ ++static void rfcomm_dlc_timeout(unsigned long arg) ++{ ++ struct rfcomm_dlc *d = (void *) arg; ++ ++ BT_DBG("dlc %p state %ld", d, d->state); ++ ++ set_bit(RFCOMM_TIMED_OUT, &d->flags); ++ rfcomm_dlc_put(d); ++ rfcomm_schedule(RFCOMM_SCHED_TIMEO); ++} ++ ++static void rfcomm_dlc_set_timer(struct rfcomm_dlc *d, long timeout) ++{ ++ BT_DBG("dlc %p state %ld timeout %ld", d, d->state, timeout); ++ ++ if (!mod_timer(&d->timer, jiffies + timeout)) ++ rfcomm_dlc_hold(d); ++} ++ ++static void rfcomm_dlc_clear_timer(struct rfcomm_dlc *d) ++{ ++ BT_DBG("dlc %p state %ld", d, d->state); ++ ++ if (timer_pending(&d->timer) && del_timer(&d->timer)) ++ rfcomm_dlc_put(d); ++} ++ ++static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d) ++{ ++ BT_DBG("%p", d); ++ ++ d->state = BT_OPEN; ++ d->flags = 0; ++ d->mscex = 0; ++ d->mtu = RFCOMM_DEFAULT_MTU; ++ d->v24_sig = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV; ++ ++ d->cfc = RFCOMM_CFC_DISABLED; ++ d->rx_credits = RFCOMM_DEFAULT_CREDITS; ++} ++ ++struct rfcomm_dlc *rfcomm_dlc_alloc(int prio) ++{ ++ struct rfcomm_dlc *d = kmalloc(sizeof(*d), prio); ++ if (!d) ++ return NULL; ++ memset(d, 0, sizeof(*d)); ++ ++ init_timer(&d->timer); ++ d->timer.function = rfcomm_dlc_timeout; ++ d->timer.data = (unsigned long) d; ++ ++ skb_queue_head_init(&d->tx_queue); ++ spin_lock_init(&d->lock); ++ atomic_set(&d->refcnt, 1); ++ ++ rfcomm_dlc_clear_state(d); ++ ++ BT_DBG("%p", d); ++ return d; ++} ++ ++void rfcomm_dlc_free(struct rfcomm_dlc *d) ++{ ++ BT_DBG("%p", d); ++ ++ skb_queue_purge(&d->tx_queue); ++ kfree(d); ++} ++ ++static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d) ++{ ++ BT_DBG("dlc %p session %p", d, s); ++ ++ rfcomm_session_hold(s); ++ ++ rfcomm_dlc_hold(d); ++ list_add(&d->list, &s->dlcs); ++ d->session = s; ++} ++ ++static void rfcomm_dlc_unlink(struct rfcomm_dlc *d) ++{ ++ struct rfcomm_session *s = d->session; ++ ++ BT_DBG("dlc %p refcnt %d session %p", d, atomic_read(&d->refcnt), s); ++ ++ list_del(&d->list); ++ d->session = NULL; ++ rfcomm_dlc_put(d); ++ ++ rfcomm_session_put(s); ++} ++ ++static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci) ++{ ++ struct rfcomm_dlc *d; ++ struct list_head *p; ++ ++ list_for_each(p, &s->dlcs) { ++ d = list_entry(p, struct rfcomm_dlc, list); ++ if (d->dlci == dlci) ++ return d; ++ } ++ return NULL; ++} ++ ++static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel) ++{ ++ struct rfcomm_session *s; ++ int err = 0; ++ u8 dlci; ++ ++ BT_DBG("dlc %p state %ld %s %s channel %d", ++ d, d->state, batostr(src), batostr(dst), channel); ++ ++ if (channel < 1 || channel > 30) ++ return -EINVAL; ++ ++ if (d->state != BT_OPEN && d->state != BT_CLOSED) ++ return 0; ++ ++ s = rfcomm_session_get(src, dst); ++ if (!s) { ++ s = rfcomm_session_create(src, dst, &err); ++ if (!s) ++ return err; ++ } ++ ++ dlci = __dlci(!s->initiator, channel); ++ ++ /* Check if DLCI already exists */ ++ if (rfcomm_dlc_get(s, dlci)) ++ return -EBUSY; ++ ++ rfcomm_dlc_clear_state(d); ++ ++ d->dlci = dlci; ++ d->addr = __addr(s->initiator, dlci); ++ d->priority = 7; ++ ++ d->state = BT_CONFIG; ++ rfcomm_dlc_link(s, d); ++ ++ d->mtu = s->mtu; ++ d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc; ++ ++ if (s->state == BT_CONNECTED) ++ rfcomm_send_pn(s, 1, d); ++ rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT); ++ return 0; ++} ++ ++int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel) ++{ ++ mm_segment_t fs; ++ int r; ++ ++ rfcomm_lock(); ++ ++ fs = get_fs(); set_fs(KERNEL_DS); ++ r = __rfcomm_dlc_open(d, src, dst, channel); ++ set_fs(fs); ++ ++ rfcomm_unlock(); ++ return r; ++} ++ ++static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) ++{ ++ struct rfcomm_session *s = d->session; ++ if (!s) ++ return 0; ++ ++ BT_DBG("dlc %p state %ld dlci %d err %d session %p", ++ d, d->state, d->dlci, err, s); ++ ++ switch (d->state) { ++ case BT_CONNECTED: ++ case BT_CONFIG: ++ case BT_CONNECT: ++ d->state = BT_DISCONN; ++ if (skb_queue_empty(&d->tx_queue)) { ++ rfcomm_send_disc(s, d->dlci); ++ rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT); ++ } else { ++ rfcomm_queue_disc(d); ++ rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2); ++ } ++ break; ++ ++ default: ++ rfcomm_dlc_clear_timer(d); ++ ++ rfcomm_dlc_lock(d); ++ d->state = BT_CLOSED; ++ d->state_change(d, err); ++ rfcomm_dlc_unlock(d); ++ ++ skb_queue_purge(&d->tx_queue); ++ rfcomm_dlc_unlink(d); ++ } ++ ++ return 0; ++} ++ ++int rfcomm_dlc_close(struct rfcomm_dlc *d, int err) ++{ ++ mm_segment_t fs; ++ int r; ++ ++ rfcomm_lock(); ++ ++ fs = get_fs(); set_fs(KERNEL_DS); ++ r = __rfcomm_dlc_close(d, err); ++ set_fs(fs); ++ ++ rfcomm_unlock(); ++ return r; ++} ++ ++int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb) ++{ ++ int len = skb->len; ++ ++ if (d->state != BT_CONNECTED) ++ return -ENOTCONN; ++ ++ BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len); ++ ++ if (len > d->mtu) ++ return -EINVAL; ++ ++ rfcomm_make_uih(skb, d->addr); ++ skb_queue_tail(&d->tx_queue, skb); ++ ++ if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags)) ++ rfcomm_schedule(RFCOMM_SCHED_TX); ++ return len; ++} ++ ++void __rfcomm_dlc_throttle(struct rfcomm_dlc *d) ++{ ++ BT_DBG("dlc %p state %ld", d, d->state); ++ ++ if (!d->cfc) { ++ d->v24_sig |= RFCOMM_V24_FC; ++ set_bit(RFCOMM_MSC_PENDING, &d->flags); ++ } ++ rfcomm_schedule(RFCOMM_SCHED_TX); ++} ++ ++void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) ++{ ++ BT_DBG("dlc %p state %ld", d, d->state); ++ ++ if (!d->cfc) { ++ d->v24_sig &= ~RFCOMM_V24_FC; ++ set_bit(RFCOMM_MSC_PENDING, &d->flags); ++ } ++ rfcomm_schedule(RFCOMM_SCHED_TX); ++} ++ ++/* ++ Set/get modem status functions use _local_ status i.e. what we report ++ to the other side. ++ Remote status is provided by dlc->modem_status() callback. ++ */ ++int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig) ++{ ++ BT_DBG("dlc %p state %ld v24_sig 0x%x", ++ d, d->state, v24_sig); ++ ++ if (test_bit(RFCOMM_RX_THROTTLED, &d->flags)) ++ v24_sig |= RFCOMM_V24_FC; ++ else ++ v24_sig &= ~RFCOMM_V24_FC; ++ ++ d->v24_sig = v24_sig; ++ ++ if (!test_and_set_bit(RFCOMM_MSC_PENDING, &d->flags)) ++ rfcomm_schedule(RFCOMM_SCHED_TX); ++ ++ return 0; ++} ++ ++int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig) ++{ ++ BT_DBG("dlc %p state %ld v24_sig 0x%x", ++ d, d->state, d->v24_sig); ++ ++ *v24_sig = d->v24_sig; ++ return 0; ++} ++ ++/* ---- RFCOMM sessions ---- */ ++struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state) ++{ ++ struct rfcomm_session *s = kmalloc(sizeof(*s), GFP_KERNEL); ++ if (!s) ++ return NULL; ++ memset(s, 0, sizeof(*s)); ++ ++ BT_DBG("session %p sock %p", s, sock); ++ ++ INIT_LIST_HEAD(&s->dlcs); ++ s->state = state; ++ s->sock = sock; ++ ++ s->mtu = RFCOMM_DEFAULT_MTU; ++ s->cfc = RFCOMM_CFC_UNKNOWN; ++ ++ list_add(&s->list, &session_list); ++ ++ /* Do not increment module usage count for listeting sessions. ++ * Otherwise we won't be able to unload the module. */ ++ if (state != BT_LISTEN) ++ MOD_INC_USE_COUNT; ++ return s; ++} ++ ++void rfcomm_session_del(struct rfcomm_session *s) ++{ ++ int state = s->state; ++ ++ BT_DBG("session %p state %ld", s, s->state); ++ ++ list_del(&s->list); ++ ++ if (state == BT_CONNECTED) ++ rfcomm_send_disc(s, 0); ++ ++ sock_release(s->sock); ++ kfree(s); ++ ++ if (state != BT_LISTEN) ++ MOD_DEC_USE_COUNT; ++} ++ ++struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst) ++{ ++ struct rfcomm_session *s; ++ struct list_head *p, *n; ++ struct bluez_pinfo *pi; ++ list_for_each_safe(p, n, &session_list) { ++ s = list_entry(p, struct rfcomm_session, list); ++ pi = bluez_pi(s->sock->sk); ++ ++ if ((!bacmp(src, BDADDR_ANY) || !bacmp(&pi->src, src)) && ++ !bacmp(&pi->dst, dst)) ++ return s; ++ } ++ return NULL; ++} ++ ++void rfcomm_session_close(struct rfcomm_session *s, int err) ++{ ++ struct rfcomm_dlc *d; ++ struct list_head *p, *n; ++ ++ BT_DBG("session %p state %ld err %d", s, s->state, err); ++ ++ rfcomm_session_hold(s); ++ ++ s->state = BT_CLOSED; ++ ++ /* Close all dlcs */ ++ list_for_each_safe(p, n, &s->dlcs) { ++ d = list_entry(p, struct rfcomm_dlc, list); ++ d->state = BT_CLOSED; ++ __rfcomm_dlc_close(d, err); ++ } ++ ++ rfcomm_session_put(s); ++} ++ ++struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err) ++{ ++ struct rfcomm_session *s = NULL; ++ struct sockaddr_l2 addr; ++ struct l2cap_options opts; ++ struct socket *sock; ++ int size; ++ ++ BT_DBG("%s %s", batostr(src), batostr(dst)); ++ ++ *err = rfcomm_l2sock_create(&sock); ++ if (*err < 0) ++ return NULL; ++ ++ bacpy(&addr.l2_bdaddr, src); ++ addr.l2_family = AF_BLUETOOTH; ++ addr.l2_psm = 0; ++ *err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr)); ++ if (*err < 0) ++ goto failed; ++ ++ /* Set L2CAP options */ ++ size = sizeof(opts); ++ sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size); ++ ++ opts.imtu = RFCOMM_MAX_L2CAP_MTU; ++ sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size); ++ ++ s = rfcomm_session_add(sock, BT_BOUND); ++ if (!s) { ++ *err = -ENOMEM; ++ goto failed; ++ } ++ ++ s->initiator = 1; ++ ++ bacpy(&addr.l2_bdaddr, dst); ++ addr.l2_family = AF_BLUETOOTH; ++ addr.l2_psm = htobs(RFCOMM_PSM); ++ *err = sock->ops->connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK); ++ if (*err == 0 || *err == -EAGAIN) ++ return s; ++ ++ rfcomm_session_del(s); ++ return NULL; ++ ++failed: ++ sock_release(sock); ++ return NULL; ++} ++ ++void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst) ++{ ++ struct sock *sk = s->sock->sk; ++ if (src) ++ bacpy(src, &bluez_pi(sk)->src); ++ if (dst) ++ bacpy(dst, &bluez_pi(sk)->dst); ++} ++ ++/* ---- RFCOMM frame sending ---- */ ++static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len) ++{ ++ struct socket *sock = s->sock; ++ struct iovec iv = { data, len }; ++ struct msghdr msg; ++ int err; ++ ++ BT_DBG("session %p len %d", s, len); ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.msg_iovlen = 1; ++ msg.msg_iov = &iv; ++ ++ err = sock->ops->sendmsg(sock, &msg, len, 0); ++ return err; ++} ++ ++static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci) ++{ ++ struct rfcomm_cmd cmd; ++ ++ BT_DBG("%p dlci %d", s, dlci); ++ ++ cmd.addr = __addr(s->initiator, dlci); ++ cmd.ctrl = __ctrl(RFCOMM_SABM, 1); ++ cmd.len = __len8(0); ++ cmd.fcs = __fcs2((u8 *) &cmd); ++ ++ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd)); ++} ++ ++static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci) ++{ ++ struct rfcomm_cmd cmd; ++ ++ BT_DBG("%p dlci %d", s, dlci); ++ ++ cmd.addr = __addr(!s->initiator, dlci); ++ cmd.ctrl = __ctrl(RFCOMM_UA, 1); ++ cmd.len = __len8(0); ++ cmd.fcs = __fcs2((u8 *) &cmd); ++ ++ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd)); ++} ++ ++static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci) ++{ ++ struct rfcomm_cmd cmd; ++ ++ BT_DBG("%p dlci %d", s, dlci); ++ ++ cmd.addr = __addr(s->initiator, dlci); ++ cmd.ctrl = __ctrl(RFCOMM_DISC, 1); ++ cmd.len = __len8(0); ++ cmd.fcs = __fcs2((u8 *) &cmd); ++ ++ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd)); ++} ++ ++static int rfcomm_queue_disc(struct rfcomm_dlc *d) ++{ ++ struct rfcomm_cmd *cmd; ++ struct sk_buff *skb; ++ ++ BT_DBG("dlc %p dlci %d", d, d->dlci); ++ ++ skb = alloc_skb(sizeof(*cmd), GFP_KERNEL); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (void *) __skb_put(skb, sizeof(*cmd)); ++ cmd->addr = d->addr; ++ cmd->ctrl = __ctrl(RFCOMM_DISC, 1); ++ cmd->len = __len8(0); ++ cmd->fcs = __fcs2((u8 *) cmd); ++ ++ skb_queue_tail(&d->tx_queue, skb); ++ rfcomm_schedule(RFCOMM_SCHED_TX); ++ return 0; ++} ++ ++static int rfcomm_send_dm(struct rfcomm_session *s, u8 dlci) ++{ ++ struct rfcomm_cmd cmd; ++ ++ BT_DBG("%p dlci %d", s, dlci); ++ ++ cmd.addr = __addr(!s->initiator, dlci); ++ cmd.ctrl = __ctrl(RFCOMM_DM, 1); ++ cmd.len = __len8(0); ++ cmd.fcs = __fcs2((u8 *) &cmd); ++ ++ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd)); ++} ++ ++static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type) ++{ ++ struct rfcomm_hdr *hdr; ++ struct rfcomm_mcc *mcc; ++ u8 buf[16], *ptr = buf; ++ ++ BT_DBG("%p cr %d type %d", s, cr, type); ++ ++ hdr = (void *) ptr; ptr += sizeof(*hdr); ++ hdr->addr = __addr(s->initiator, 0); ++ hdr->ctrl = __ctrl(RFCOMM_UIH, 0); ++ hdr->len = __len8(sizeof(*mcc) + 1); ++ ++ mcc = (void *) ptr; ptr += sizeof(*mcc); ++ mcc->type = __mcc_type(cr, RFCOMM_NSC); ++ mcc->len = __len8(1); ++ ++ /* Type that we didn't like */ ++ *ptr = __mcc_type(cr, type); ptr++; ++ ++ *ptr = __fcs(buf); ptr++; ++ ++ return rfcomm_send_frame(s, buf, ptr - buf); ++} ++ ++static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d) ++{ ++ struct rfcomm_hdr *hdr; ++ struct rfcomm_mcc *mcc; ++ struct rfcomm_pn *pn; ++ u8 buf[16], *ptr = buf; ++ ++ BT_DBG("%p cr %d dlci %d mtu %d", s, cr, d->dlci, d->mtu); ++ ++ hdr = (void *) ptr; ptr += sizeof(*hdr); ++ hdr->addr = __addr(s->initiator, 0); ++ hdr->ctrl = __ctrl(RFCOMM_UIH, 0); ++ hdr->len = __len8(sizeof(*mcc) + sizeof(*pn)); ++ ++ mcc = (void *) ptr; ptr += sizeof(*mcc); ++ mcc->type = __mcc_type(cr, RFCOMM_PN); ++ mcc->len = __len8(sizeof(*pn)); ++ ++ pn = (void *) ptr; ptr += sizeof(*pn); ++ pn->dlci = d->dlci; ++ pn->priority = d->priority; ++ pn->ack_timer = 0; ++ pn->max_retrans = 0; ++ ++ if (s->cfc) { ++ pn->flow_ctrl = cr ? 0xf0 : 0xe0; ++ pn->credits = RFCOMM_DEFAULT_CREDITS; ++ } else { ++ pn->flow_ctrl = 0; ++ pn->credits = 0; ++ } ++ ++ pn->mtu = htobs(d->mtu); ++ ++ *ptr = __fcs(buf); ptr++; ++ ++ return rfcomm_send_frame(s, buf, ptr - buf); ++} ++ ++static int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci, ++ u8 bit_rate, u8 data_bits, u8 stop_bits, ++ u8 parity, u8 flow_ctrl_settings, ++ u8 xon_char, u8 xoff_char, u16 param_mask) ++{ ++ struct rfcomm_hdr *hdr; ++ struct rfcomm_mcc *mcc; ++ struct rfcomm_rpn *rpn; ++ u8 buf[16], *ptr = buf; ++ ++ BT_DBG("%p cr %d dlci %d bit_r 0x%x data_b 0x%x stop_b 0x%x parity 0x%x" ++ "flwc_s 0x%x xon_c 0x%x xoff_c 0x%x p_mask 0x%x", ++ s, cr, dlci, bit_rate, data_bits, stop_bits, parity, ++ flow_ctrl_settings, xon_char, xoff_char, param_mask); ++ ++ hdr = (void *) ptr; ptr += sizeof(*hdr); ++ hdr->addr = __addr(s->initiator, 0); ++ hdr->ctrl = __ctrl(RFCOMM_UIH, 0); ++ hdr->len = __len8(sizeof(*mcc) + sizeof(*rpn)); ++ ++ mcc = (void *) ptr; ptr += sizeof(*mcc); ++ mcc->type = __mcc_type(cr, RFCOMM_RPN); ++ mcc->len = __len8(sizeof(*rpn)); ++ ++ rpn = (void *) ptr; ptr += sizeof(*rpn); ++ rpn->dlci = __addr(1, dlci); ++ rpn->bit_rate = bit_rate; ++ rpn->line_settings = __rpn_line_settings(data_bits, stop_bits, parity); ++ rpn->flow_ctrl = flow_ctrl_settings; ++ rpn->xon_char = xon_char; ++ rpn->xoff_char = xoff_char; ++ rpn->param_mask = param_mask; ++ ++ *ptr = __fcs(buf); ptr++; ++ ++ return rfcomm_send_frame(s, buf, ptr - buf); ++} ++ ++static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status) ++{ ++ struct rfcomm_hdr *hdr; ++ struct rfcomm_mcc *mcc; ++ struct rfcomm_rls *rls; ++ u8 buf[16], *ptr = buf; ++ ++ BT_DBG("%p cr %d status 0x%x", s, cr, status); ++ ++ hdr = (void *) ptr; ptr += sizeof(*hdr); ++ hdr->addr = __addr(s->initiator, 0); ++ hdr->ctrl = __ctrl(RFCOMM_UIH, 0); ++ hdr->len = __len8(sizeof(*mcc) + sizeof(*rls)); ++ ++ mcc = (void *) ptr; ptr += sizeof(*mcc); ++ mcc->type = __mcc_type(cr, RFCOMM_RLS); ++ mcc->len = __len8(sizeof(*rls)); ++ ++ rls = (void *) ptr; ptr += sizeof(*rls); ++ rls->dlci = __addr(1, dlci); ++ rls->status = status; ++ ++ *ptr = __fcs(buf); ptr++; ++ ++ return rfcomm_send_frame(s, buf, ptr - buf); ++} ++ ++static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig) ++{ ++ struct rfcomm_hdr *hdr; ++ struct rfcomm_mcc *mcc; ++ struct rfcomm_msc *msc; ++ u8 buf[16], *ptr = buf; ++ ++ BT_DBG("%p cr %d v24 0x%x", s, cr, v24_sig); ++ ++ hdr = (void *) ptr; ptr += sizeof(*hdr); ++ hdr->addr = __addr(s->initiator, 0); ++ hdr->ctrl = __ctrl(RFCOMM_UIH, 0); ++ hdr->len = __len8(sizeof(*mcc) + sizeof(*msc)); ++ ++ mcc = (void *) ptr; ptr += sizeof(*mcc); ++ mcc->type = __mcc_type(cr, RFCOMM_MSC); ++ mcc->len = __len8(sizeof(*msc)); ++ ++ msc = (void *) ptr; ptr += sizeof(*msc); ++ msc->dlci = __addr(1, dlci); ++ msc->v24_sig = v24_sig | 0x01; ++ ++ *ptr = __fcs(buf); ptr++; ++ ++ return rfcomm_send_frame(s, buf, ptr - buf); ++} ++ ++static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr) ++{ ++ struct rfcomm_hdr *hdr; ++ struct rfcomm_mcc *mcc; ++ u8 buf[16], *ptr = buf; ++ ++ BT_DBG("%p cr %d", s, cr); ++ ++ hdr = (void *) ptr; ptr += sizeof(*hdr); ++ hdr->addr = __addr(s->initiator, 0); ++ hdr->ctrl = __ctrl(RFCOMM_UIH, 0); ++ hdr->len = __len8(sizeof(*mcc)); ++ ++ mcc = (void *) ptr; ptr += sizeof(*mcc); ++ mcc->type = __mcc_type(cr, RFCOMM_FCOFF); ++ mcc->len = __len8(0); ++ ++ *ptr = __fcs(buf); ptr++; ++ ++ return rfcomm_send_frame(s, buf, ptr - buf); ++} ++ ++static int rfcomm_send_fcon(struct rfcomm_session *s, int cr) ++{ ++ struct rfcomm_hdr *hdr; ++ struct rfcomm_mcc *mcc; ++ u8 buf[16], *ptr = buf; ++ ++ BT_DBG("%p cr %d", s, cr); ++ ++ hdr = (void *) ptr; ptr += sizeof(*hdr); ++ hdr->addr = __addr(s->initiator, 0); ++ hdr->ctrl = __ctrl(RFCOMM_UIH, 0); ++ hdr->len = __len8(sizeof(*mcc)); ++ ++ mcc = (void *) ptr; ptr += sizeof(*mcc); ++ mcc->type = __mcc_type(cr, RFCOMM_FCON); ++ mcc->len = __len8(0); ++ ++ *ptr = __fcs(buf); ptr++; ++ ++ return rfcomm_send_frame(s, buf, ptr - buf); ++} ++ ++static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len) ++{ ++ struct socket *sock = s->sock; ++ struct iovec iv[3]; ++ struct msghdr msg; ++ unsigned char hdr[5], crc[1]; ++ ++ if (len > 125) ++ return -EINVAL; ++ ++ BT_DBG("%p cr %d", s, cr); ++ ++ hdr[0] = __addr(s->initiator, 0); ++ hdr[1] = __ctrl(RFCOMM_UIH, 0); ++ hdr[2] = 0x01 | ((len + 2) << 1); ++ hdr[3] = 0x01 | ((cr & 0x01) << 1) | (RFCOMM_TEST << 2); ++ hdr[4] = 0x01 | (len << 1); ++ ++ crc[0] = __fcs(hdr); ++ ++ iv[0].iov_base = hdr; ++ iv[0].iov_len = 5; ++ iv[1].iov_base = pattern; ++ iv[1].iov_len = len; ++ iv[2].iov_base = crc; ++ iv[2].iov_len = 1; ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.msg_iovlen = 3; ++ msg.msg_iov = iv; ++ return sock->ops->sendmsg(sock, &msg, 6 + len, 0); ++} ++ ++static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits) ++{ ++ struct rfcomm_hdr *hdr; ++ u8 buf[16], *ptr = buf; ++ ++ BT_DBG("%p addr %d credits %d", s, addr, credits); ++ ++ hdr = (void *) ptr; ptr += sizeof(*hdr); ++ hdr->addr = addr; ++ hdr->ctrl = __ctrl(RFCOMM_UIH, 1); ++ hdr->len = __len8(0); ++ ++ *ptr = credits; ptr++; ++ ++ *ptr = __fcs(buf); ptr++; ++ ++ return rfcomm_send_frame(s, buf, ptr - buf); ++} ++ ++static void rfcomm_make_uih(struct sk_buff *skb, u8 addr) ++{ ++ struct rfcomm_hdr *hdr; ++ int len = skb->len; ++ u8 *crc; ++ ++ if (len > 127) { ++ hdr = (void *) skb_push(skb, 4); ++ put_unaligned(htobs(__len16(len)), (u16 *) &hdr->len); ++ } else { ++ hdr = (void *) skb_push(skb, 3); ++ hdr->len = __len8(len); ++ } ++ hdr->addr = addr; ++ hdr->ctrl = __ctrl(RFCOMM_UIH, 0); ++ ++ crc = skb_put(skb, 1); ++ *crc = __fcs((void *) hdr); ++} ++ ++/* ---- RFCOMM frame reception ---- */ ++static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci) ++{ ++ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); ++ ++ if (dlci) { ++ /* Data channel */ ++ struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci); ++ if (!d) { ++ rfcomm_send_dm(s, dlci); ++ return 0; ++ } ++ ++ switch (d->state) { ++ case BT_CONNECT: ++ rfcomm_dlc_clear_timer(d); ++ ++ rfcomm_dlc_lock(d); ++ d->state = BT_CONNECTED; ++ d->state_change(d, 0); ++ rfcomm_dlc_unlock(d); ++ ++ rfcomm_send_msc(s, 1, dlci, d->v24_sig); ++ break; ++ ++ case BT_DISCONN: ++ d->state = BT_CLOSED; ++ __rfcomm_dlc_close(d, 0); ++ break; ++ } ++ } else { ++ /* Control channel */ ++ switch (s->state) { ++ case BT_CONNECT: ++ s->state = BT_CONNECTED; ++ rfcomm_process_connect(s); ++ break; ++ } ++ } ++ return 0; ++} ++ ++static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci) ++{ ++ int err = 0; ++ ++ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); ++ ++ if (dlci) { ++ /* Data DLC */ ++ struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci); ++ if (d) { ++ if (d->state == BT_CONNECT || d->state == BT_CONFIG) ++ err = ECONNREFUSED; ++ else ++ err = ECONNRESET; ++ ++ d->state = BT_CLOSED; ++ __rfcomm_dlc_close(d, err); ++ } ++ } else { ++ if (s->state == BT_CONNECT) ++ err = ECONNREFUSED; ++ else ++ err = ECONNRESET; ++ ++ s->state = BT_CLOSED; ++ rfcomm_session_close(s, err); ++ } ++ return 0; ++} ++ ++static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci) ++{ ++ int err = 0; ++ ++ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); ++ ++ if (dlci) { ++ struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci); ++ if (d) { ++ rfcomm_send_ua(s, dlci); ++ ++ if (d->state == BT_CONNECT || d->state == BT_CONFIG) ++ err = ECONNREFUSED; ++ else ++ err = ECONNRESET; ++ ++ d->state = BT_CLOSED; ++ __rfcomm_dlc_close(d, err); ++ } else ++ rfcomm_send_dm(s, dlci); ++ ++ } else { ++ rfcomm_send_ua(s, 0); ++ ++ if (s->state == BT_CONNECT) ++ err = ECONNREFUSED; ++ else ++ err = ECONNRESET; ++ ++ s->state = BT_CLOSED; ++ rfcomm_session_close(s, err); ++ } ++ ++ return 0; ++} ++ ++static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci) ++{ ++ struct rfcomm_dlc *d; ++ u8 channel; ++ ++ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); ++ ++ if (!dlci) { ++ rfcomm_send_ua(s, 0); ++ ++ if (s->state == BT_OPEN) { ++ s->state = BT_CONNECTED; ++ rfcomm_process_connect(s); ++ } ++ return 0; ++ } ++ ++ /* Check if DLC exists */ ++ d = rfcomm_dlc_get(s, dlci); ++ if (d) { ++ if (d->state == BT_OPEN) { ++ /* DLC was previously opened by PN request */ ++ rfcomm_send_ua(s, dlci); ++ ++ rfcomm_dlc_lock(d); ++ d->state = BT_CONNECTED; ++ d->state_change(d, 0); ++ rfcomm_dlc_unlock(d); ++ ++ rfcomm_send_msc(s, 1, dlci, d->v24_sig); ++ } ++ return 0; ++ } ++ ++ /* Notify socket layer about incomming connection */ ++ channel = __srv_channel(dlci); ++ if (rfcomm_connect_ind(s, channel, &d)) { ++ d->dlci = dlci; ++ d->addr = __addr(s->initiator, dlci); ++ rfcomm_dlc_link(s, d); ++ ++ rfcomm_send_ua(s, dlci); ++ ++ rfcomm_dlc_lock(d); ++ d->state = BT_CONNECTED; ++ d->state_change(d, 0); ++ rfcomm_dlc_unlock(d); ++ ++ rfcomm_send_msc(s, 1, dlci, d->v24_sig); ++ } else { ++ rfcomm_send_dm(s, dlci); ++ } ++ ++ return 0; ++} ++ ++static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn) ++{ ++ struct rfcomm_session *s = d->session; ++ ++ BT_DBG("dlc %p state %ld dlci %d mtu %d fc 0x%x credits %d", ++ d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits); ++ ++ if (pn->flow_ctrl == 0xf0 || pn->flow_ctrl == 0xe0) { ++ d->cfc = s->cfc = RFCOMM_CFC_ENABLED; ++ d->tx_credits = pn->credits; ++ } else { ++ d->cfc = s->cfc = RFCOMM_CFC_DISABLED; ++ set_bit(RFCOMM_TX_THROTTLED, &d->flags); ++ } ++ ++ d->priority = pn->priority; ++ ++ d->mtu = s->mtu = btohs(pn->mtu); ++ ++ return 0; ++} ++ ++static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb) ++{ ++ struct rfcomm_pn *pn = (void *) skb->data; ++ struct rfcomm_dlc *d; ++ u8 dlci = pn->dlci; ++ ++ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); ++ ++ if (!dlci) ++ return 0; ++ ++ d = rfcomm_dlc_get(s, dlci); ++ if (d) { ++ if (cr) { ++ /* PN request */ ++ rfcomm_apply_pn(d, cr, pn); ++ rfcomm_send_pn(s, 0, d); ++ } else { ++ /* PN response */ ++ switch (d->state) { ++ case BT_CONFIG: ++ rfcomm_apply_pn(d, cr, pn); ++ ++ d->state = BT_CONNECT; ++ rfcomm_send_sabm(s, d->dlci); ++ break; ++ } ++ } ++ } else { ++ u8 channel = __srv_channel(dlci); ++ ++ if (!cr) ++ return 0; ++ ++ /* PN request for non existing DLC. ++ * Assume incomming connection. */ ++ if (rfcomm_connect_ind(s, channel, &d)) { ++ d->dlci = dlci; ++ d->addr = __addr(s->initiator, dlci); ++ rfcomm_dlc_link(s, d); ++ ++ rfcomm_apply_pn(d, cr, pn); ++ ++ d->state = BT_OPEN; ++ rfcomm_send_pn(s, 0, d); ++ } else { ++ rfcomm_send_dm(s, dlci); ++ } ++ } ++ return 0; ++} ++ ++static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb) ++{ ++ struct rfcomm_rpn *rpn = (void *) skb->data; ++ u8 dlci = __get_dlci(rpn->dlci); ++ ++ u8 bit_rate = 0; ++ u8 data_bits = 0; ++ u8 stop_bits = 0; ++ u8 parity = 0; ++ u8 flow_ctrl = 0; ++ u8 xon_char = 0; ++ u8 xoff_char = 0; ++ u16 rpn_mask = RFCOMM_RPN_PM_ALL; ++ ++ BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", ++ dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl, ++ rpn->xon_char, rpn->xoff_char, rpn->param_mask); ++ ++ if (!cr) ++ return 0; ++ ++ if (len == 1) { ++ /* request: return default setting */ ++ bit_rate = RFCOMM_RPN_BR_115200; ++ data_bits = RFCOMM_RPN_DATA_8; ++ stop_bits = RFCOMM_RPN_STOP_1; ++ parity = RFCOMM_RPN_PARITY_NONE; ++ flow_ctrl = RFCOMM_RPN_FLOW_NONE; ++ xon_char = RFCOMM_RPN_XON_CHAR; ++ xoff_char = RFCOMM_RPN_XOFF_CHAR; ++ ++ goto rpn_out; ++ } ++ /* check for sane values: ignore/accept bit_rate, 8 bits, 1 stop bit, no parity, ++ no flow control lines, normal XON/XOFF chars */ ++ if (rpn->param_mask & RFCOMM_RPN_PM_BITRATE) { ++ bit_rate = rpn->bit_rate; ++ if (bit_rate != RFCOMM_RPN_BR_115200) { ++ BT_DBG("RPN bit rate mismatch 0x%x", bit_rate); ++ bit_rate = RFCOMM_RPN_BR_115200; ++ rpn_mask ^= RFCOMM_RPN_PM_BITRATE; ++ } ++ } ++ if (rpn->param_mask & RFCOMM_RPN_PM_DATA) { ++ data_bits = __get_rpn_data_bits(rpn->line_settings); ++ if (data_bits != RFCOMM_RPN_DATA_8) { ++ BT_DBG("RPN data bits mismatch 0x%x", data_bits); ++ data_bits = RFCOMM_RPN_DATA_8; ++ rpn_mask ^= RFCOMM_RPN_PM_DATA; ++ } ++ } ++ if (rpn->param_mask & RFCOMM_RPN_PM_STOP) { ++ stop_bits = __get_rpn_stop_bits(rpn->line_settings); ++ if (stop_bits != RFCOMM_RPN_STOP_1) { ++ BT_DBG("RPN stop bits mismatch 0x%x", stop_bits); ++ stop_bits = RFCOMM_RPN_STOP_1; ++ rpn_mask ^= RFCOMM_RPN_PM_STOP; ++ } ++ } ++ if (rpn->param_mask & RFCOMM_RPN_PM_PARITY) { ++ parity = __get_rpn_parity(rpn->line_settings); ++ if (parity != RFCOMM_RPN_PARITY_NONE) { ++ BT_DBG("RPN parity mismatch 0x%x", parity); ++ parity = RFCOMM_RPN_PARITY_NONE; ++ rpn_mask ^= RFCOMM_RPN_PM_PARITY; ++ } ++ } ++ if (rpn->param_mask & RFCOMM_RPN_PM_FLOW) { ++ flow_ctrl = rpn->flow_ctrl; ++ if (flow_ctrl != RFCOMM_RPN_FLOW_NONE) { ++ BT_DBG("RPN flow ctrl mismatch 0x%x", flow_ctrl); ++ flow_ctrl = RFCOMM_RPN_FLOW_NONE; ++ rpn_mask ^= RFCOMM_RPN_PM_FLOW; ++ } ++ } ++ if (rpn->param_mask & RFCOMM_RPN_PM_XON) { ++ xon_char = rpn->xon_char; ++ if (xon_char != RFCOMM_RPN_XON_CHAR) { ++ BT_DBG("RPN XON char mismatch 0x%x", xon_char); ++ xon_char = RFCOMM_RPN_XON_CHAR; ++ rpn_mask ^= RFCOMM_RPN_PM_XON; ++ } ++ } ++ if (rpn->param_mask & RFCOMM_RPN_PM_XOFF) { ++ xoff_char = rpn->xoff_char; ++ if (xoff_char != RFCOMM_RPN_XOFF_CHAR) { ++ BT_DBG("RPN XOFF char mismatch 0x%x", xoff_char); ++ xoff_char = RFCOMM_RPN_XOFF_CHAR; ++ rpn_mask ^= RFCOMM_RPN_PM_XOFF; ++ } ++ } ++ ++rpn_out: ++ rfcomm_send_rpn(s, 0, dlci, ++ bit_rate, data_bits, stop_bits, parity, flow_ctrl, ++ xon_char, xoff_char, rpn_mask); ++ ++ return 0; ++} ++ ++static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb) ++{ ++ struct rfcomm_rls *rls = (void *) skb->data; ++ u8 dlci = __get_dlci(rls->dlci); ++ ++ BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status); ++ ++ if (!cr) ++ return 0; ++ ++ /* FIXME: We should probably do something with this ++ information here. But for now it's sufficient just ++ to reply -- Bluetooth 1.1 says it's mandatory to ++ recognise and respond to RLS */ ++ ++ rfcomm_send_rls(s, 0, dlci, rls->status); ++ ++ return 0; ++} ++ ++static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb) ++{ ++ struct rfcomm_msc *msc = (void *) skb->data; ++ struct rfcomm_dlc *d; ++ u8 dlci = __get_dlci(msc->dlci); ++ ++ BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig); ++ ++ d = rfcomm_dlc_get(s, dlci); ++ if (!d) ++ return 0; ++ ++ if (cr) { ++ if (msc->v24_sig & RFCOMM_V24_FC && !d->cfc) ++ set_bit(RFCOMM_TX_THROTTLED, &d->flags); ++ else ++ clear_bit(RFCOMM_TX_THROTTLED, &d->flags); ++ ++ rfcomm_dlc_lock(d); ++ if (d->modem_status) ++ d->modem_status(d, msc->v24_sig); ++ rfcomm_dlc_unlock(d); ++ ++ rfcomm_send_msc(s, 0, dlci, msc->v24_sig); ++ ++ d->mscex |= RFCOMM_MSCEX_RX; ++ } else ++ d->mscex |= RFCOMM_MSCEX_TX; ++ ++ return 0; ++} ++ ++static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb) ++{ ++ struct rfcomm_mcc *mcc = (void *) skb->data; ++ u8 type, cr, len; ++ ++ cr = __test_cr(mcc->type); ++ type = __get_mcc_type(mcc->type); ++ len = __get_mcc_len(mcc->len); ++ ++ BT_DBG("%p type 0x%x cr %d", s, type, cr); ++ ++ skb_pull(skb, 2); ++ ++ switch (type) { ++ case RFCOMM_PN: ++ rfcomm_recv_pn(s, cr, skb); ++ break; ++ ++ case RFCOMM_RPN: ++ rfcomm_recv_rpn(s, cr, len, skb); ++ break; ++ ++ case RFCOMM_RLS: ++ rfcomm_recv_rls(s, cr, skb); ++ break; ++ ++ case RFCOMM_MSC: ++ rfcomm_recv_msc(s, cr, skb); ++ break; ++ ++ case RFCOMM_FCOFF: ++ if (cr) { ++ set_bit(RFCOMM_TX_THROTTLED, &s->flags); ++ rfcomm_send_fcoff(s, 0); ++ } ++ break; ++ ++ case RFCOMM_FCON: ++ if (cr) { ++ clear_bit(RFCOMM_TX_THROTTLED, &s->flags); ++ rfcomm_send_fcon(s, 0); ++ } ++ break; ++ ++ case RFCOMM_TEST: ++ if (cr) ++ rfcomm_send_test(s, 0, skb->data, skb->len); ++ break; ++ ++ case RFCOMM_NSC: ++ break; ++ ++ default: ++ BT_ERR("Unknown control type 0x%02x", type); ++ rfcomm_send_nsc(s, cr, type); ++ break; ++ } ++ return 0; ++} ++ ++static int rfcomm_recv_data(struct rfcomm_session *s, u8 dlci, int pf, struct sk_buff *skb) ++{ ++ struct rfcomm_dlc *d; ++ ++ BT_DBG("session %p state %ld dlci %d pf %d", s, s->state, dlci, pf); ++ ++ d = rfcomm_dlc_get(s, dlci); ++ if (!d) { ++ rfcomm_send_dm(s, dlci); ++ goto drop; ++ } ++ ++ if (pf && d->cfc) { ++ u8 credits = *(u8 *) skb->data; skb_pull(skb, 1); ++ ++ d->tx_credits += credits; ++ if (d->tx_credits) ++ clear_bit(RFCOMM_TX_THROTTLED, &d->flags); ++ } ++ ++ if (skb->len && d->state == BT_CONNECTED) { ++ rfcomm_dlc_lock(d); ++ d->rx_credits--; ++ d->data_ready(d, skb); ++ rfcomm_dlc_unlock(d); ++ return 0; ++ } ++ ++drop: ++ kfree_skb(skb); ++ return 0; ++} ++ ++static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb) ++{ ++ struct rfcomm_hdr *hdr = (void *) skb->data; ++ u8 type, dlci, fcs; ++ ++ dlci = __get_dlci(hdr->addr); ++ type = __get_type(hdr->ctrl); ++ ++ /* Trim FCS */ ++ skb->len--; skb->tail--; ++ fcs = *(u8 *) skb->tail; ++ ++ if (__check_fcs(skb->data, type, fcs)) { ++ BT_ERR("bad checksum in packet"); ++ kfree_skb(skb); ++ return -EILSEQ; ++ } ++ ++ if (__test_ea(hdr->len)) ++ skb_pull(skb, 3); ++ else ++ skb_pull(skb, 4); ++ ++ switch (type) { ++ case RFCOMM_SABM: ++ if (__test_pf(hdr->ctrl)) ++ rfcomm_recv_sabm(s, dlci); ++ break; ++ ++ case RFCOMM_DISC: ++ if (__test_pf(hdr->ctrl)) ++ rfcomm_recv_disc(s, dlci); ++ break; ++ ++ case RFCOMM_UA: ++ if (__test_pf(hdr->ctrl)) ++ rfcomm_recv_ua(s, dlci); ++ break; ++ ++ case RFCOMM_DM: ++ rfcomm_recv_dm(s, dlci); ++ break; ++ ++ case RFCOMM_UIH: ++ if (dlci) ++ return rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb); ++ ++ rfcomm_recv_mcc(s, skb); ++ break; ++ ++ default: ++ BT_ERR("Unknown packet type 0x%02x\n", type); ++ break; ++ } ++ kfree_skb(skb); ++ return 0; ++} ++ ++/* ---- Connection and data processing ---- */ ++ ++static void rfcomm_process_connect(struct rfcomm_session *s) ++{ ++ struct rfcomm_dlc *d; ++ struct list_head *p, *n; ++ ++ BT_DBG("session %p state %ld", s, s->state); ++ ++ list_for_each_safe(p, n, &s->dlcs) { ++ d = list_entry(p, struct rfcomm_dlc, list); ++ if (d->state == BT_CONFIG) { ++ d->mtu = s->mtu; ++ rfcomm_send_pn(s, 1, d); ++ } ++ } ++} ++ ++/* Send data queued for the DLC. ++ * Return number of frames left in the queue. ++ */ ++static inline int rfcomm_process_tx(struct rfcomm_dlc *d) ++{ ++ struct sk_buff *skb; ++ int err; ++ ++ BT_DBG("dlc %p state %ld cfc %d rx_credits %d tx_credits %d", ++ d, d->state, d->cfc, d->rx_credits, d->tx_credits); ++ ++ /* Send pending MSC */ ++ if (test_and_clear_bit(RFCOMM_MSC_PENDING, &d->flags)) ++ rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig); ++ ++ if (d->cfc) { ++ /* CFC enabled. ++ * Give them some credits */ ++ if (!test_bit(RFCOMM_RX_THROTTLED, &d->flags) && ++ d->rx_credits <= (d->cfc >> 2)) { ++ rfcomm_send_credits(d->session, d->addr, d->cfc - d->rx_credits); ++ d->rx_credits = d->cfc; ++ } ++ } else { ++ /* CFC disabled. ++ * Give ourselves some credits */ ++ d->tx_credits = 5; ++ } ++ ++ if (test_bit(RFCOMM_TX_THROTTLED, &d->flags)) ++ return skb_queue_len(&d->tx_queue); ++ ++ while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) { ++ err = rfcomm_send_frame(d->session, skb->data, skb->len); ++ if (err < 0) { ++ skb_queue_head(&d->tx_queue, skb); ++ break; ++ } ++ kfree_skb(skb); ++ d->tx_credits--; ++ } ++ ++ if (d->cfc && !d->tx_credits) { ++ /* We're out of TX credits. ++ * Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */ ++ set_bit(RFCOMM_TX_THROTTLED, &d->flags); ++ } ++ ++ return skb_queue_len(&d->tx_queue); ++} ++ ++static inline void rfcomm_process_dlcs(struct rfcomm_session *s) ++{ ++ struct rfcomm_dlc *d; ++ struct list_head *p, *n; ++ ++ BT_DBG("session %p state %ld", s, s->state); ++ ++ list_for_each_safe(p, n, &s->dlcs) { ++ d = list_entry(p, struct rfcomm_dlc, list); ++ if (test_bit(RFCOMM_TIMED_OUT, &d->flags)) { ++ __rfcomm_dlc_close(d, ETIMEDOUT); ++ continue; ++ } ++ ++ if (test_bit(RFCOMM_TX_THROTTLED, &s->flags)) ++ continue; ++ ++ if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) && ++ d->mscex == RFCOMM_MSCEX_OK) ++ rfcomm_process_tx(d); ++ } ++} ++ ++static inline void rfcomm_process_rx(struct rfcomm_session *s) ++{ ++ struct socket *sock = s->sock; ++ struct sock *sk = sock->sk; ++ struct sk_buff *skb; ++ ++ BT_DBG("session %p state %ld qlen %d", s, s->state, skb_queue_len(&sk->receive_queue)); ++ ++ /* Get data directly from socket receive queue without copying it. */ ++ while ((skb = skb_dequeue(&sk->receive_queue))) { ++ skb_orphan(skb); ++ rfcomm_recv_frame(s, skb); ++ } ++ ++ if (sk->state == BT_CLOSED) { ++ if (!s->initiator) ++ rfcomm_session_put(s); ++ ++ rfcomm_session_close(s, sk->err); ++ } ++} ++ ++static inline void rfcomm_accept_connection(struct rfcomm_session *s) ++{ ++ struct socket *sock = s->sock, *nsock; ++ int err; ++ ++ /* Fast check for a new connection. ++ * Avoids unnesesary socket allocations. */ ++ if (list_empty(&bluez_pi(sock->sk)->accept_q)) ++ return; ++ ++ BT_DBG("session %p", s); ++ ++ nsock = sock_alloc(); ++ if (!nsock) ++ return; ++ ++ nsock->type = sock->type; ++ nsock->ops = sock->ops; ++ ++ err = sock->ops->accept(sock, nsock, O_NONBLOCK); ++ if (err < 0) { ++ sock_release(nsock); ++ return; ++ } ++ ++ /* Set our callbacks */ ++ nsock->sk->data_ready = rfcomm_l2data_ready; ++ nsock->sk->state_change = rfcomm_l2state_change; ++ ++ s = rfcomm_session_add(nsock, BT_OPEN); ++ if (s) ++ rfcomm_session_hold(s); ++ else ++ sock_release(nsock); ++} ++ ++static inline void rfcomm_check_connection(struct rfcomm_session *s) ++{ ++ struct sock *sk = s->sock->sk; ++ ++ BT_DBG("%p state %ld", s, s->state); ++ ++ switch(sk->state) { ++ case BT_CONNECTED: ++ s->state = BT_CONNECT; ++ ++ /* We can adjust MTU on outgoing sessions. ++ * L2CAP MTU minus UIH header and FCS. */ ++ s->mtu = min(l2cap_pi(sk)->omtu, l2cap_pi(sk)->imtu) - 5; ++ ++ rfcomm_send_sabm(s, 0); ++ break; ++ ++ case BT_CLOSED: ++ s->state = BT_CLOSED; ++ rfcomm_session_close(s, sk->err); ++ break; ++ } ++} ++ ++static inline void rfcomm_process_sessions(void) ++{ ++ struct list_head *p, *n; ++ ++ rfcomm_lock(); ++ ++ list_for_each_safe(p, n, &session_list) { ++ struct rfcomm_session *s; ++ s = list_entry(p, struct rfcomm_session, list); ++ ++ if (s->state == BT_LISTEN) { ++ rfcomm_accept_connection(s); ++ continue; ++ } ++ ++ rfcomm_session_hold(s); ++ ++ switch (s->state) { ++ case BT_BOUND: ++ rfcomm_check_connection(s); ++ break; ++ ++ default: ++ rfcomm_process_rx(s); ++ break; ++ } ++ ++ rfcomm_process_dlcs(s); ++ ++ rfcomm_session_put(s); ++ } ++ ++ rfcomm_unlock(); ++} ++ ++static void rfcomm_worker(void) ++{ ++ BT_DBG(""); ++ ++ daemonize(); reparent_to_init(); ++ set_fs(KERNEL_DS); ++ ++ while (!atomic_read(&terminate)) { ++ BT_DBG("worker loop event 0x%lx", rfcomm_event); ++ ++ if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) { ++ /* No pending events. Let's sleep. ++ * Incomming connections and data will wake us up. */ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule(); ++ } ++ ++ /* Process stuff */ ++ clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event); ++ rfcomm_process_sessions(); ++ } ++ set_current_state(TASK_RUNNING); ++ return; ++} ++ ++static int rfcomm_add_listener(bdaddr_t *ba) ++{ ++ struct sockaddr_l2 addr; ++ struct l2cap_options opts; ++ struct socket *sock; ++ struct rfcomm_session *s; ++ int size, err = 0; ++ ++ /* Create socket */ ++ err = rfcomm_l2sock_create(&sock); ++ if (err < 0) { ++ BT_ERR("Create socket failed %d", err); ++ return err; ++ } ++ ++ /* Bind socket */ ++ bacpy(&addr.l2_bdaddr, ba); ++ addr.l2_family = AF_BLUETOOTH; ++ addr.l2_psm = htobs(RFCOMM_PSM); ++ err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr)); ++ if (err < 0) { ++ BT_ERR("Bind failed %d", err); ++ goto failed; ++ } ++ ++ /* Set L2CAP options */ ++ size = sizeof(opts); ++ sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size); ++ ++ opts.imtu = RFCOMM_MAX_L2CAP_MTU; ++ sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size); ++ ++ /* Start listening on the socket */ ++ err = sock->ops->listen(sock, 10); ++ if (err) { ++ BT_ERR("Listen failed %d", err); ++ goto failed; ++ } ++ ++ /* Add listening session */ ++ s = rfcomm_session_add(sock, BT_LISTEN); ++ if (!s) ++ goto failed; ++ ++ rfcomm_session_hold(s); ++ return 0; ++failed: ++ sock_release(sock); ++ return err; ++} ++ ++static void rfcomm_kill_listener(void) ++{ ++ struct rfcomm_session *s; ++ struct list_head *p, *n; ++ ++ BT_DBG(""); ++ ++ list_for_each_safe(p, n, &session_list) { ++ s = list_entry(p, struct rfcomm_session, list); ++ rfcomm_session_del(s); ++ } ++} ++ ++static int rfcomm_run(void *unused) ++{ ++ rfcomm_thread = current; ++ ++ atomic_inc(&running); ++ ++ daemonize(); reparent_to_init(); ++ ++ sigfillset(¤t->blocked); ++ set_fs(KERNEL_DS); ++ ++ sprintf(current->comm, "krfcommd"); ++ ++ BT_DBG(""); ++ ++ rfcomm_add_listener(BDADDR_ANY); ++ ++ rfcomm_worker(); ++ ++ rfcomm_kill_listener(); ++ ++ atomic_dec(&running); ++ return 0; ++} ++ ++/* ---- Proc fs support ---- */ ++static int rfcomm_dlc_dump(char *buf) ++{ ++ struct rfcomm_session *s; ++ struct sock *sk; ++ struct list_head *p, *pp; ++ char *ptr = buf; ++ ++ rfcomm_lock(); ++ ++ list_for_each(p, &session_list) { ++ s = list_entry(p, struct rfcomm_session, list); ++ sk = s->sock->sk; ++ ++ list_for_each(pp, &s->dlcs) { ++ struct rfcomm_dlc *d; ++ d = list_entry(pp, struct rfcomm_dlc, list); ++ ++ ptr += sprintf(ptr, "dlc %s %s %ld %d %d %d %d\n", ++ batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst), ++ d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits); ++ } ++ } ++ ++ rfcomm_unlock(); ++ ++ return ptr - buf; ++} ++ ++extern int rfcomm_sock_dump(char *buf); ++ ++static int rfcomm_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv) ++{ ++ char *ptr = buf; ++ int len; ++ ++ BT_DBG("count %d, offset %ld", count, offset); ++ ++ ptr += rfcomm_dlc_dump(ptr); ++ ptr += rfcomm_sock_dump(ptr); ++ len = ptr - buf; ++ ++ if (len <= count + offset) ++ *eof = 1; ++ ++ *start = buf + offset; ++ len -= offset; ++ ++ if (len > count) ++ len = count; ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++ ++/* ---- Initialization ---- */ ++int __init rfcomm_init(void) ++{ ++ l2cap_load(); ++ ++ kernel_thread(rfcomm_run, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); ++ ++ rfcomm_init_sockets(); ++ ++#ifdef CONFIG_BLUEZ_RFCOMM_TTY ++ rfcomm_init_ttys(); ++#endif ++ ++ create_proc_read_entry("bluetooth/rfcomm", 0, 0, rfcomm_read_proc, NULL); ++ ++ BT_INFO("BlueZ RFCOMM ver %s", VERSION); ++ BT_INFO("Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>"); ++ BT_INFO("Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>"); ++ return 0; ++} ++ ++void rfcomm_cleanup(void) ++{ ++ /* Terminate working thread. ++ * ie. Set terminate flag and wake it up */ ++ atomic_inc(&terminate); ++ rfcomm_schedule(RFCOMM_SCHED_STATE); ++ ++ /* Wait until thread is running */ ++ while (atomic_read(&running)) ++ schedule(); ++ ++ remove_proc_entry("bluetooth/rfcomm", NULL); ++ ++#ifdef CONFIG_BLUEZ_RFCOMM_TTY ++ rfcomm_cleanup_ttys(); ++#endif ++ ++ rfcomm_cleanup_sockets(); ++ return; ++} ++ ++module_init(rfcomm_init); ++module_exit(rfcomm_cleanup); ++ ++MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>"); ++MODULE_DESCRIPTION("BlueZ RFCOMM ver " VERSION); ++MODULE_LICENSE("GPL"); +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/rfcomm/crc.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,71 @@ ++/* ++ RFCOMM implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com> ++ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * RFCOMM FCS calculation. ++ * ++ * $Id$ ++ */ ++ ++/* reversed, 8-bit, poly=0x07 */ ++unsigned char rfcomm_crc_table[256] = { ++ 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75, ++ 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b, ++ 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69, ++ 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67, ++ ++ 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d, ++ 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43, ++ 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51, ++ 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f, ++ ++ 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05, ++ 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b, ++ 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19, ++ 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17, ++ ++ 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d, ++ 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33, ++ 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21, ++ 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f, ++ ++ 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95, ++ 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b, ++ 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89, ++ 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87, ++ ++ 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad, ++ 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3, ++ 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1, ++ 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf, ++ ++ 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5, ++ 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb, ++ 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9, ++ 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7, ++ ++ 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd, ++ 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3, ++ 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1, ++ 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf ++}; +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/rfcomm/Makefile 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,11 @@ ++# ++# Makefile for the Linux Bluetooth RFCOMM layer ++# ++ ++O_TARGET := rfcomm.o ++ ++obj-y := core.o sock.o crc.o ++obj-$(CONFIG_BLUEZ_RFCOMM_TTY) += tty.o ++obj-m += $(O_TARGET) ++ ++include $(TOPDIR)/Rules.make +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/rfcomm/sock.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,847 @@ ++/* ++ RFCOMM implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com> ++ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * RFCOMM sockets. ++ * ++ * $Id$ ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/init.h> ++#include <linux/skbuff.h> ++#include <linux/interrupt.h> ++#include <linux/socket.h> ++#include <linux/skbuff.h> ++#include <linux/list.h> ++#include <net/sock.h> ++ ++#include <asm/system.h> ++#include <asm/uaccess.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/rfcomm.h> ++ ++#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG ++#undef BT_DBG ++#define BT_DBG(D...) ++#endif ++ ++static struct proto_ops rfcomm_sock_ops; ++ ++static struct bluez_sock_list rfcomm_sk_list = { ++ lock: RW_LOCK_UNLOCKED ++}; ++ ++static void rfcomm_sock_close(struct sock *sk); ++static void rfcomm_sock_kill(struct sock *sk); ++ ++/* ---- DLC callbacks ---- ++ * ++ * called under rfcomm_dlc_lock() ++ */ ++static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb) ++{ ++ struct sock *sk = d->owner; ++ if (!sk) ++ return; ++ ++ atomic_add(skb->len, &sk->rmem_alloc); ++ skb_queue_tail(&sk->receive_queue, skb); ++ sk->data_ready(sk, skb->len); ++ ++ if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) ++ rfcomm_dlc_throttle(d); ++} ++ ++static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err) ++{ ++ struct sock *sk = d->owner, *parent; ++ if (!sk) ++ return; ++ ++ BT_DBG("dlc %p state %ld err %d", d, d->state, err); ++ ++ bh_lock_sock(sk); ++ ++ if (err) ++ sk->err = err; ++ sk->state = d->state; ++ ++ parent = bluez_pi(sk)->parent; ++ if (!parent) { ++ if (d->state == BT_CONNECTED) ++ rfcomm_session_getaddr(d->session, &bluez_pi(sk)->src, NULL); ++ sk->state_change(sk); ++ } else ++ parent->data_ready(parent, 0); ++ ++ bh_unlock_sock(sk); ++} ++ ++/* ---- Socket functions ---- */ ++static struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src) ++{ ++ struct sock *sk; ++ ++ for (sk = rfcomm_sk_list.head; sk; sk = sk->next) { ++ if (rfcomm_pi(sk)->channel == channel && ++ !bacmp(&bluez_pi(sk)->src, src)) ++ break; ++ } ++ ++ return sk; ++} ++ ++/* Find socket with channel and source bdaddr. ++ * Returns closest match. ++ */ ++static struct sock *__rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src) ++{ ++ struct sock *sk, *sk1 = NULL; ++ ++ for (sk = rfcomm_sk_list.head; sk; sk = sk->next) { ++ if (state && sk->state != state) ++ continue; ++ ++ if (rfcomm_pi(sk)->channel == channel) { ++ /* Exact match. */ ++ if (!bacmp(&bluez_pi(sk)->src, src)) ++ break; ++ ++ /* Closest match */ ++ if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY)) ++ sk1 = sk; ++ } ++ } ++ return sk ? sk : sk1; ++} ++ ++/* Find socket with given address (channel, src). ++ * Returns locked socket */ ++static inline struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src) ++{ ++ struct sock *s; ++ read_lock(&rfcomm_sk_list.lock); ++ s = __rfcomm_get_sock_by_channel(state, channel, src); ++ if (s) bh_lock_sock(s); ++ read_unlock(&rfcomm_sk_list.lock); ++ return s; ++} ++ ++static void rfcomm_sock_destruct(struct sock *sk) ++{ ++ struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc; ++ ++ BT_DBG("sk %p dlc %p", sk, d); ++ ++ skb_queue_purge(&sk->receive_queue); ++ skb_queue_purge(&sk->write_queue); ++ ++ rfcomm_dlc_lock(d); ++ rfcomm_pi(sk)->dlc = NULL; ++ ++ /* Detach DLC if it's owned by this socket */ ++ if (d->owner == sk) ++ d->owner = NULL; ++ rfcomm_dlc_unlock(d); ++ ++ rfcomm_dlc_put(d); ++ ++ MOD_DEC_USE_COUNT; ++} ++ ++static void rfcomm_sock_cleanup_listen(struct sock *parent) ++{ ++ struct sock *sk; ++ ++ BT_DBG("parent %p", parent); ++ ++ /* Close not yet accepted dlcs */ ++ while ((sk = bluez_accept_dequeue(parent, NULL))) { ++ rfcomm_sock_close(sk); ++ rfcomm_sock_kill(sk); ++ } ++ ++ parent->state = BT_CLOSED; ++ parent->zapped = 1; ++} ++ ++/* Kill socket (only if zapped and orphan) ++ * Must be called on unlocked socket. ++ */ ++static void rfcomm_sock_kill(struct sock *sk) ++{ ++ if (!sk->zapped || sk->socket) ++ return; ++ ++ BT_DBG("sk %p state %d refcnt %d", sk, sk->state, atomic_read(&sk->refcnt)); ++ ++ /* Kill poor orphan */ ++ bluez_sock_unlink(&rfcomm_sk_list, sk); ++ sk->dead = 1; ++ sock_put(sk); ++} ++ ++static void __rfcomm_sock_close(struct sock *sk) ++{ ++ struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc; ++ ++ BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket); ++ ++ switch (sk->state) { ++ case BT_LISTEN: ++ rfcomm_sock_cleanup_listen(sk); ++ break; ++ ++ case BT_CONNECT: ++ case BT_CONNECT2: ++ case BT_CONFIG: ++ case BT_CONNECTED: ++ rfcomm_dlc_close(d, 0); ++ ++ default: ++ sk->zapped = 1; ++ break; ++ } ++} ++ ++/* Close socket. ++ * Must be called on unlocked socket. ++ */ ++static void rfcomm_sock_close(struct sock *sk) ++{ ++ lock_sock(sk); ++ __rfcomm_sock_close(sk); ++ release_sock(sk); ++} ++ ++static void rfcomm_sock_init(struct sock *sk, struct sock *parent) ++{ ++ BT_DBG("sk %p", sk); ++ ++ if (parent) ++ sk->type = parent->type; ++} ++ ++static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio) ++{ ++ struct rfcomm_dlc *d; ++ struct sock *sk; ++ ++ sk = sk_alloc(PF_BLUETOOTH, prio, 1); ++ if (!sk) ++ return NULL; ++ ++ d = rfcomm_dlc_alloc(prio); ++ if (!d) { ++ sk_free(sk); ++ return NULL; ++ } ++ d->data_ready = rfcomm_sk_data_ready; ++ d->state_change = rfcomm_sk_state_change; ++ ++ rfcomm_pi(sk)->dlc = d; ++ d->owner = sk; ++ ++ bluez_sock_init(sock, sk); ++ ++ sk->zapped = 0; ++ ++ sk->destruct = rfcomm_sock_destruct; ++ sk->sndtimeo = RFCOMM_CONN_TIMEOUT; ++ ++ sk->sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10; ++ sk->rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10; ++ ++ sk->protocol = proto; ++ sk->state = BT_OPEN; ++ ++ bluez_sock_link(&rfcomm_sk_list, sk); ++ ++ BT_DBG("sk %p", sk); ++ ++ MOD_INC_USE_COUNT; ++ return sk; ++} ++ ++static int rfcomm_sock_create(struct socket *sock, int protocol) ++{ ++ struct sock *sk; ++ ++ BT_DBG("sock %p", sock); ++ ++ sock->state = SS_UNCONNECTED; ++ ++ if (sock->type != SOCK_STREAM && sock->type != SOCK_RAW) ++ return -ESOCKTNOSUPPORT; ++ ++ sock->ops = &rfcomm_sock_ops; ++ ++ if (!(sk = rfcomm_sock_alloc(sock, protocol, GFP_KERNEL))) ++ return -ENOMEM; ++ ++ rfcomm_sock_init(sk, NULL); ++ return 0; ++} ++ ++static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) ++{ ++ struct sockaddr_rc *sa = (struct sockaddr_rc *) addr; ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sk %p %s", sk, batostr(&sa->rc_bdaddr)); ++ ++ if (!addr || addr->sa_family != AF_BLUETOOTH) ++ return -EINVAL; ++ ++ lock_sock(sk); ++ ++ if (sk->state != BT_OPEN) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ write_lock_bh(&rfcomm_sk_list.lock); ++ ++ if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) { ++ err = -EADDRINUSE; ++ } else { ++ /* Save source address */ ++ bacpy(&bluez_pi(sk)->src, &sa->rc_bdaddr); ++ rfcomm_pi(sk)->channel = sa->rc_channel; ++ sk->state = BT_BOUND; ++ } ++ ++ write_unlock_bh(&rfcomm_sk_list.lock); ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) ++{ ++ struct sockaddr_rc *sa = (struct sockaddr_rc *) addr; ++ struct sock *sk = sock->sk; ++ struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc; ++ int err = 0; ++ ++ BT_DBG("sk %p", sk); ++ ++ if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_rc)) ++ return -EINVAL; ++ ++ if (sk->state != BT_OPEN && sk->state != BT_BOUND) ++ return -EBADFD; ++ ++ if (sk->type != SOCK_STREAM) ++ return -EINVAL; ++ ++ lock_sock(sk); ++ ++ sk->state = BT_CONNECT; ++ bacpy(&bluez_pi(sk)->dst, &sa->rc_bdaddr); ++ rfcomm_pi(sk)->channel = sa->rc_channel; ++ ++ err = rfcomm_dlc_open(d, &bluez_pi(sk)->src, &sa->rc_bdaddr, sa->rc_channel); ++ if (!err) ++ err = bluez_sock_wait_state(sk, BT_CONNECTED, ++ sock_sndtimeo(sk, flags & O_NONBLOCK)); ++ ++ release_sock(sk); ++ return err; ++} ++ ++int rfcomm_sock_listen(struct socket *sock, int backlog) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sk %p backlog %d", sk, backlog); ++ ++ lock_sock(sk); ++ ++ if (sk->state != BT_BOUND) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ sk->max_ack_backlog = backlog; ++ sk->ack_backlog = 0; ++ sk->state = BT_LISTEN; ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ struct sock *sk = sock->sk, *nsk; ++ long timeo; ++ int err = 0; ++ ++ lock_sock(sk); ++ ++ if (sk->state != BT_LISTEN) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); ++ ++ BT_DBG("sk %p timeo %ld", sk, timeo); ++ ++ /* Wait for an incoming connection. (wake-one). */ ++ add_wait_queue_exclusive(sk->sleep, &wait); ++ while (!(nsk = bluez_accept_dequeue(sk, newsock))) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ if (!timeo) { ++ err = -EAGAIN; ++ break; ++ } ++ ++ release_sock(sk); ++ timeo = schedule_timeout(timeo); ++ lock_sock(sk); ++ ++ if (sk->state != BT_LISTEN) { ++ err = -EBADFD; ++ break; ++ } ++ ++ if (signal_pending(current)) { ++ err = sock_intr_errno(timeo); ++ break; ++ } ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(sk->sleep, &wait); ++ ++ if (err) ++ goto done; ++ ++ newsock->state = SS_CONNECTED; ++ ++ BT_DBG("new socket %p", nsk); ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer) ++{ ++ struct sockaddr_rc *sa = (struct sockaddr_rc *) addr; ++ struct sock *sk = sock->sk; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ sa->rc_family = AF_BLUETOOTH; ++ sa->rc_channel = rfcomm_pi(sk)->channel; ++ if (peer) ++ bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->dst); ++ else ++ bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->src); ++ ++ *len = sizeof(struct sockaddr_rc); ++ return 0; ++} ++ ++static int rfcomm_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, ++ struct scm_cookie *scm) ++{ ++ struct sock *sk = sock->sk; ++ struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc; ++ struct sk_buff *skb; ++ int err, size; ++ int sent = 0; ++ ++ if (msg->msg_flags & MSG_OOB) ++ return -EOPNOTSUPP; ++ ++ if (sk->shutdown & SEND_SHUTDOWN) ++ return -EPIPE; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ lock_sock(sk); ++ ++ while (len) { ++ size = min_t(uint, len, d->mtu); ++ ++ skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE, ++ msg->msg_flags & MSG_DONTWAIT, &err); ++ if (!skb) ++ break; ++ skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE); ++ ++ err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); ++ if (err) { ++ kfree_skb(skb); ++ sent = err; ++ break; ++ } ++ ++ err = rfcomm_dlc_send(d, skb); ++ if (err < 0) { ++ kfree_skb(skb); ++ break; ++ } ++ ++ sent += size; ++ len -= size; ++ } ++ ++ release_sock(sk); ++ ++ return sent ? sent : err; ++} ++ ++static long rfcomm_sock_data_wait(struct sock *sk, long timeo) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ ++ add_wait_queue(sk->sleep, &wait); ++ for (;;) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ if (skb_queue_len(&sk->receive_queue) || sk->err || (sk->shutdown & RCV_SHUTDOWN) || ++ signal_pending(current) || !timeo) ++ break; ++ ++ set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags); ++ release_sock(sk); ++ timeo = schedule_timeout(timeo); ++ lock_sock(sk); ++ clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags); ++ } ++ ++ __set_current_state(TASK_RUNNING); ++ remove_wait_queue(sk->sleep, &wait); ++ return timeo; ++} ++ ++static int rfcomm_sock_recvmsg(struct socket *sock, struct msghdr *msg, int size, ++ int flags, struct scm_cookie *scm) ++{ ++ struct sock *sk = sock->sk; ++ int target, err = 0, copied = 0; ++ long timeo; ++ ++ if (flags & MSG_OOB) ++ return -EOPNOTSUPP; ++ ++ msg->msg_namelen = 0; ++ ++ BT_DBG("sk %p size %d", sk, size); ++ ++ lock_sock(sk); ++ ++ target = sock_rcvlowat(sk, flags & MSG_WAITALL, size); ++ timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); ++ ++ do { ++ struct sk_buff *skb; ++ int chunk; ++ ++ skb = skb_dequeue(&sk->receive_queue); ++ if (!skb) { ++ if (copied >= target) ++ break; ++ ++ if ((err = sock_error(sk)) != 0) ++ break; ++ if (sk->shutdown & RCV_SHUTDOWN) ++ break; ++ ++ err = -EAGAIN; ++ if (!timeo) ++ break; ++ ++ timeo = rfcomm_sock_data_wait(sk, timeo); ++ ++ if (signal_pending(current)) { ++ err = sock_intr_errno(timeo); ++ goto out; ++ } ++ continue; ++ } ++ ++ chunk = min_t(unsigned int, skb->len, size); ++ if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) { ++ skb_queue_head(&sk->receive_queue, skb); ++ if (!copied) ++ copied = -EFAULT; ++ break; ++ } ++ copied += chunk; ++ size -= chunk; ++ ++ if (!(flags & MSG_PEEK)) { ++ atomic_sub(chunk, &sk->rmem_alloc); ++ ++ skb_pull(skb, chunk); ++ if (skb->len) { ++ skb_queue_head(&sk->receive_queue, skb); ++ break; ++ } ++ kfree_skb(skb); ++ ++ } else { ++ /* put message back and return */ ++ skb_queue_head(&sk->receive_queue, skb); ++ break; ++ } ++ } while (size); ++ ++out: ++ if (atomic_read(&sk->rmem_alloc) <= (sk->rcvbuf >> 2)) ++ rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc); ++ ++ release_sock(sk); ++ return copied ? : err; ++} ++ ++static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sk %p", sk); ++ ++ lock_sock(sk); ++ ++ switch (optname) { ++ default: ++ err = -ENOPROTOOPT; ++ break; ++ }; ++ ++ release_sock(sk); ++ return err; ++} ++ ++static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) ++{ ++ struct sock *sk = sock->sk; ++ int len, err = 0; ++ ++ BT_DBG("sk %p", sk); ++ ++ if (get_user(len, optlen)) ++ return -EFAULT; ++ ++ lock_sock(sk); ++ ++ switch (optname) { ++ default: ++ err = -ENOPROTOOPT; ++ break; ++ }; ++ ++ release_sock(sk); ++ return err; ++} ++ ++static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ++{ ++ struct sock *sk = sock->sk; ++ int err; ++ ++ lock_sock(sk); ++ ++#ifdef CONFIG_BLUEZ_RFCOMM_TTY ++ err = rfcomm_dev_ioctl(sk, cmd, arg); ++#else ++ err = -EOPNOTSUPP; ++#endif ++ ++ release_sock(sk); ++ ++ return err; ++} ++ ++static int rfcomm_sock_shutdown(struct socket *sock, int how) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ if (!sk) return 0; ++ ++ lock_sock(sk); ++ if (!sk->shutdown) { ++ sk->shutdown = SHUTDOWN_MASK; ++ __rfcomm_sock_close(sk); ++ ++ if (sk->linger) ++ err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime); ++ } ++ release_sock(sk); ++ return err; ++} ++ ++static int rfcomm_sock_release(struct socket *sock) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ if (!sk) ++ return 0; ++ ++ err = rfcomm_sock_shutdown(sock, 2); ++ ++ sock_orphan(sk); ++ rfcomm_sock_kill(sk); ++ return err; ++} ++ ++/* ---- RFCOMM core layer callbacks ---- ++ * ++ * called under rfcomm_lock() ++ */ ++int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d) ++{ ++ struct sock *sk, *parent; ++ bdaddr_t src, dst; ++ int result = 0; ++ ++ BT_DBG("session %p channel %d", s, channel); ++ ++ rfcomm_session_getaddr(s, &src, &dst); ++ ++ /* Check if we have socket listening on this channel */ ++ parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &src); ++ if (!parent) ++ return 0; ++ ++ /* Check for backlog size */ ++ if (parent->ack_backlog > parent->max_ack_backlog) { ++ BT_DBG("backlog full %d", parent->ack_backlog); ++ goto done; ++ } ++ ++ sk = rfcomm_sock_alloc(NULL, BTPROTO_RFCOMM, GFP_ATOMIC); ++ if (!sk) ++ goto done; ++ ++ rfcomm_sock_init(sk, parent); ++ bacpy(&bluez_pi(sk)->src, &src); ++ bacpy(&bluez_pi(sk)->dst, &dst); ++ rfcomm_pi(sk)->channel = channel; ++ ++ sk->state = BT_CONFIG; ++ bluez_accept_enqueue(parent, sk); ++ ++ /* Accept connection and return socket DLC */ ++ *d = rfcomm_pi(sk)->dlc; ++ result = 1; ++ ++done: ++ bh_unlock_sock(parent); ++ return result; ++} ++ ++/* ---- Proc fs support ---- */ ++int rfcomm_sock_dump(char *buf) ++{ ++ struct bluez_sock_list *list = &rfcomm_sk_list; ++ struct rfcomm_pinfo *pi; ++ struct sock *sk; ++ char *ptr = buf; ++ ++ write_lock_bh(&list->lock); ++ ++ for (sk = list->head; sk; sk = sk->next) { ++ pi = rfcomm_pi(sk); ++ ptr += sprintf(ptr, "sk %s %s %d %d\n", ++ batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst), ++ sk->state, rfcomm_pi(sk)->channel); ++ } ++ ++ write_unlock_bh(&list->lock); ++ ++ return ptr - buf; ++} ++ ++static struct proto_ops rfcomm_sock_ops = { ++ family: PF_BLUETOOTH, ++ release: rfcomm_sock_release, ++ bind: rfcomm_sock_bind, ++ connect: rfcomm_sock_connect, ++ listen: rfcomm_sock_listen, ++ accept: rfcomm_sock_accept, ++ getname: rfcomm_sock_getname, ++ sendmsg: rfcomm_sock_sendmsg, ++ recvmsg: rfcomm_sock_recvmsg, ++ shutdown: rfcomm_sock_shutdown, ++ setsockopt: rfcomm_sock_setsockopt, ++ getsockopt: rfcomm_sock_getsockopt, ++ ioctl: rfcomm_sock_ioctl, ++ poll: bluez_sock_poll, ++ socketpair: sock_no_socketpair, ++ mmap: sock_no_mmap ++}; ++ ++static struct net_proto_family rfcomm_sock_family_ops = { ++ family: PF_BLUETOOTH, ++ create: rfcomm_sock_create ++}; ++ ++int rfcomm_init_sockets(void) ++{ ++ int err; ++ ++ if ((err = bluez_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops))) { ++ BT_ERR("Can't register RFCOMM socket layer"); ++ return err; ++ } ++ ++ return 0; ++} ++ ++void rfcomm_cleanup_sockets(void) ++{ ++ int err; ++ ++ /* Unregister socket, protocol and notifier */ ++ if ((err = bluez_sock_unregister(BTPROTO_RFCOMM))) ++ BT_ERR("Can't unregister RFCOMM socket layer %d", err); ++} +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/rfcomm/tty.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,945 @@ ++/* ++ RFCOMM implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com> ++ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * RFCOMM TTY. ++ * ++ * $Id$ ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/tty.h> ++#include <linux/tty_driver.h> ++#include <linux/tty_flip.h> ++ ++#include <linux/slab.h> ++#include <linux/skbuff.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/rfcomm.h> ++ ++#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG ++#undef BT_DBG ++#define BT_DBG(D...) ++#endif ++ ++#define RFCOMM_TTY_MAGIC 0x6d02 /* magic number for rfcomm struct */ ++#define RFCOMM_TTY_PORTS RFCOMM_MAX_DEV /* whole lotta rfcomm devices */ ++#define RFCOMM_TTY_MAJOR 216 /* device node major id of the usb/bluetooth.c driver */ ++#define RFCOMM_TTY_MINOR 0 ++ ++struct rfcomm_dev { ++ struct list_head list; ++ atomic_t refcnt; ++ ++ char name[12]; ++ int id; ++ unsigned long flags; ++ int opened; ++ int err; ++ ++ bdaddr_t src; ++ bdaddr_t dst; ++ u8 channel; ++ ++ uint modem_status; ++ ++ struct rfcomm_dlc *dlc; ++ struct tty_struct *tty; ++ wait_queue_head_t wait; ++ struct tasklet_struct wakeup_task; ++ ++ atomic_t wmem_alloc; ++}; ++ ++static LIST_HEAD(rfcomm_dev_list); ++static rwlock_t rfcomm_dev_lock = RW_LOCK_UNLOCKED; ++ ++static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb); ++static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err); ++static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig); ++ ++static void rfcomm_tty_wakeup(unsigned long arg); ++ ++/* ---- Device functions ---- */ ++static void rfcomm_dev_destruct(struct rfcomm_dev *dev) ++{ ++ struct rfcomm_dlc *dlc = dev->dlc; ++ ++ BT_DBG("dev %p dlc %p", dev, dlc); ++ ++ rfcomm_dlc_lock(dlc); ++ /* Detach DLC if it's owned by this dev */ ++ if (dlc->owner == dev) ++ dlc->owner = NULL; ++ rfcomm_dlc_unlock(dlc); ++ ++ rfcomm_dlc_put(dlc); ++ kfree(dev); ++ ++ MOD_DEC_USE_COUNT; ++} ++ ++static inline void rfcomm_dev_hold(struct rfcomm_dev *dev) ++{ ++ atomic_inc(&dev->refcnt); ++} ++ ++static inline void rfcomm_dev_put(struct rfcomm_dev *dev) ++{ ++ if (atomic_dec_and_test(&dev->refcnt)) ++ rfcomm_dev_destruct(dev); ++} ++ ++static struct rfcomm_dev *__rfcomm_dev_get(int id) ++{ ++ struct rfcomm_dev *dev; ++ struct list_head *p; ++ ++ list_for_each(p, &rfcomm_dev_list) { ++ dev = list_entry(p, struct rfcomm_dev, list); ++ if (dev->id == id) ++ return dev; ++ } ++ ++ return NULL; ++} ++ ++static inline struct rfcomm_dev *rfcomm_dev_get(int id) ++{ ++ struct rfcomm_dev *dev; ++ ++ read_lock(&rfcomm_dev_lock); ++ dev = __rfcomm_dev_get(id); ++ read_unlock(&rfcomm_dev_lock); ++ ++ if (dev) rfcomm_dev_hold(dev); ++ return dev; ++} ++ ++static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) ++{ ++ struct rfcomm_dev *dev; ++ struct list_head *head = &rfcomm_dev_list, *p; ++ int err = 0; ++ ++ BT_DBG("id %d channel %d", req->dev_id, req->channel); ++ ++ dev = kmalloc(sizeof(struct rfcomm_dev), GFP_KERNEL); ++ if (!dev) ++ return -ENOMEM; ++ memset(dev, 0, sizeof(struct rfcomm_dev)); ++ ++ write_lock_bh(&rfcomm_dev_lock); ++ ++ if (req->dev_id < 0) { ++ dev->id = 0; ++ ++ list_for_each(p, &rfcomm_dev_list) { ++ if (list_entry(p, struct rfcomm_dev, list)->id != dev->id) ++ break; ++ ++ dev->id++; ++ head = p; ++ } ++ } else { ++ dev->id = req->dev_id; ++ ++ list_for_each(p, &rfcomm_dev_list) { ++ struct rfcomm_dev *entry = list_entry(p, struct rfcomm_dev, list); ++ ++ if (entry->id == dev->id) { ++ err = -EADDRINUSE; ++ goto out; ++ } ++ ++ if (entry->id > dev->id - 1) ++ break; ++ ++ head = p; ++ } ++ } ++ ++ if ((dev->id < 0) || (dev->id > RFCOMM_MAX_DEV - 1)) { ++ err = -ENFILE; ++ goto out; ++ } ++ ++ sprintf(dev->name, "rfcomm%d", dev->id); ++ ++ list_add(&dev->list, head); ++ atomic_set(&dev->refcnt, 1); ++ ++ bacpy(&dev->src, &req->src); ++ bacpy(&dev->dst, &req->dst); ++ dev->channel = req->channel; ++ ++ dev->flags = req->flags & ++ ((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC)); ++ ++ init_waitqueue_head(&dev->wait); ++ tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev); ++ ++ rfcomm_dlc_lock(dlc); ++ dlc->data_ready = rfcomm_dev_data_ready; ++ dlc->state_change = rfcomm_dev_state_change; ++ dlc->modem_status = rfcomm_dev_modem_status; ++ ++ dlc->owner = dev; ++ dev->dlc = dlc; ++ rfcomm_dlc_unlock(dlc); ++ ++ MOD_INC_USE_COUNT; ++ ++out: ++ write_unlock_bh(&rfcomm_dev_lock); ++ ++ if (err) { ++ kfree(dev); ++ return err; ++ } else ++ return dev->id; ++} ++ ++static void rfcomm_dev_del(struct rfcomm_dev *dev) ++{ ++ BT_DBG("dev %p", dev); ++ ++ write_lock_bh(&rfcomm_dev_lock); ++ list_del_init(&dev->list); ++ write_unlock_bh(&rfcomm_dev_lock); ++ ++ rfcomm_dev_put(dev); ++} ++ ++/* ---- Send buffer ---- */ ++ ++static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc) ++{ ++ /* We can't let it be zero, because we don't get a callback ++ when tx_credits becomes nonzero, hence we'd never wake up */ ++ return dlc->mtu * (dlc->tx_credits?:1); ++} ++ ++static void rfcomm_wfree(struct sk_buff *skb) ++{ ++ struct rfcomm_dev *dev = (void *) skb->sk; ++ atomic_sub(skb->truesize, &dev->wmem_alloc); ++ if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags)) ++ tasklet_schedule(&dev->wakeup_task); ++ rfcomm_dev_put(dev); ++} ++ ++static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev) ++{ ++ rfcomm_dev_hold(dev); ++ atomic_add(skb->truesize, &dev->wmem_alloc); ++ skb->sk = (void *) dev; ++ skb->destructor = rfcomm_wfree; ++} ++ ++static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int force, int priority) ++{ ++ if (force || atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) { ++ struct sk_buff *skb = alloc_skb(size, priority); ++ if (skb) { ++ rfcomm_set_owner_w(skb, dev); ++ return skb; ++ } ++ } ++ return NULL; ++} ++ ++/* ---- Device IOCTLs ---- */ ++ ++#define NOCAP_FLAGS ((1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP)) ++ ++static int rfcomm_create_dev(struct sock *sk, unsigned long arg) ++{ ++ struct rfcomm_dev_req req; ++ struct rfcomm_dlc *dlc; ++ int id; ++ ++ if (copy_from_user(&req, (void *) arg, sizeof(req))) ++ return -EFAULT; ++ ++ BT_DBG("sk %p dev_id %id flags 0x%x", sk, req.dev_id, req.flags); ++ ++ if (req.flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ if (req.flags & (1 << RFCOMM_REUSE_DLC)) { ++ /* Socket must be connected */ ++ if (sk->state != BT_CONNECTED) ++ return -EBADFD; ++ ++ dlc = rfcomm_pi(sk)->dlc; ++ rfcomm_dlc_hold(dlc); ++ } else { ++ dlc = rfcomm_dlc_alloc(GFP_KERNEL); ++ if (!dlc) ++ return -ENOMEM; ++ } ++ ++ id = rfcomm_dev_add(&req, dlc); ++ if (id < 0) { ++ rfcomm_dlc_put(dlc); ++ return id; ++ } ++ ++ if (req.flags & (1 << RFCOMM_REUSE_DLC)) { ++ /* DLC is now used by device. ++ * Socket must be disconnected */ ++ sk->state = BT_CLOSED; ++ } ++ ++ return id; ++} ++ ++static int rfcomm_release_dev(unsigned long arg) ++{ ++ struct rfcomm_dev_req req; ++ struct rfcomm_dev *dev; ++ ++ if (copy_from_user(&req, (void *) arg, sizeof(req))) ++ return -EFAULT; ++ ++ BT_DBG("dev_id %id flags 0x%x", req.dev_id, req.flags); ++ ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ if (!(dev = rfcomm_dev_get(req.dev_id))) ++ return -ENODEV; ++ ++ if (req.flags & (1 << RFCOMM_HANGUP_NOW)) ++ rfcomm_dlc_close(dev->dlc, 0); ++ ++ rfcomm_dev_del(dev); ++ rfcomm_dev_put(dev); ++ return 0; ++} ++ ++static int rfcomm_get_dev_list(unsigned long arg) ++{ ++ struct rfcomm_dev_list_req *dl; ++ struct rfcomm_dev_info *di; ++ struct list_head *p; ++ int n = 0, size; ++ u16 dev_num; ++ ++ BT_DBG(""); ++ ++ if (get_user(dev_num, (u16 *) arg)) ++ return -EFAULT; ++ ++ if (!dev_num) ++ return -EINVAL; ++ ++ size = sizeof(*dl) + dev_num * sizeof(*di); ++ ++ if (verify_area(VERIFY_WRITE, (void *)arg, size)) ++ return -EFAULT; ++ ++ if (!(dl = kmalloc(size, GFP_KERNEL))) ++ return -ENOMEM; ++ ++ di = dl->dev_info; ++ ++ read_lock_bh(&rfcomm_dev_lock); ++ ++ list_for_each(p, &rfcomm_dev_list) { ++ struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list); ++ (di + n)->id = dev->id; ++ (di + n)->flags = dev->flags; ++ (di + n)->state = dev->dlc->state; ++ (di + n)->channel = dev->channel; ++ bacpy(&(di + n)->src, &dev->src); ++ bacpy(&(di + n)->dst, &dev->dst); ++ if (++n >= dev_num) ++ break; ++ } ++ ++ read_unlock_bh(&rfcomm_dev_lock); ++ ++ dl->dev_num = n; ++ size = sizeof(*dl) + n * sizeof(*di); ++ ++ copy_to_user((void *) arg, dl, size); ++ kfree(dl); ++ return 0; ++} ++ ++static int rfcomm_get_dev_info(unsigned long arg) ++{ ++ struct rfcomm_dev *dev; ++ struct rfcomm_dev_info di; ++ int err = 0; ++ ++ BT_DBG(""); ++ ++ if (copy_from_user(&di, (void *)arg, sizeof(di))) ++ return -EFAULT; ++ ++ if (!(dev = rfcomm_dev_get(di.id))) ++ return -ENODEV; ++ ++ di.flags = dev->flags; ++ di.channel = dev->channel; ++ di.state = dev->dlc->state; ++ bacpy(&di.src, &dev->src); ++ bacpy(&di.dst, &dev->dst); ++ ++ if (copy_to_user((void *)arg, &di, sizeof(di))) ++ err = -EFAULT; ++ ++ rfcomm_dev_put(dev); ++ return err; ++} ++ ++int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg) ++{ ++ BT_DBG("cmd %d arg %ld", cmd, arg); ++ ++ switch (cmd) { ++ case RFCOMMCREATEDEV: ++ return rfcomm_create_dev(sk, arg); ++ ++ case RFCOMMRELEASEDEV: ++ return rfcomm_release_dev(arg); ++ ++ case RFCOMMGETDEVLIST: ++ return rfcomm_get_dev_list(arg); ++ ++ case RFCOMMGETDEVINFO: ++ return rfcomm_get_dev_info(arg); ++ } ++ ++ return -EINVAL; ++} ++ ++/* ---- DLC callbacks ---- */ ++static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb) ++{ ++ struct rfcomm_dev *dev = dlc->owner; ++ struct tty_struct *tty; ++ ++ if (!dev || !(tty = dev->tty)) { ++ kfree_skb(skb); ++ return; ++ } ++ ++ BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len); ++ ++ if (test_bit(TTY_DONT_FLIP, &tty->flags)) { ++ register int i; ++ for (i = 0; i < skb->len; i++) { ++ if (tty->flip.count >= TTY_FLIPBUF_SIZE) ++ tty_flip_buffer_push(tty); ++ ++ tty_insert_flip_char(tty, skb->data[i], 0); ++ } ++ tty_flip_buffer_push(tty); ++ } else ++ tty->ldisc.receive_buf(tty, skb->data, NULL, skb->len); ++ ++ kfree_skb(skb); ++} ++ ++static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) ++{ ++ struct rfcomm_dev *dev = dlc->owner; ++ if (!dev) ++ return; ++ ++ BT_DBG("dlc %p dev %p err %d", dlc, dev, err); ++ ++ dev->err = err; ++ wake_up_interruptible(&dev->wait); ++ ++ if (dlc->state == BT_CLOSED) { ++ if (!dev->tty) { ++ if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) { ++ rfcomm_dev_hold(dev); ++ rfcomm_dev_del(dev); ++ ++ /* We have to drop DLC lock here, otherwise ++ * rfcomm_dev_put() will dead lock if it's the last refference */ ++ rfcomm_dlc_unlock(dlc); ++ rfcomm_dev_put(dev); ++ rfcomm_dlc_lock(dlc); ++ } ++ } else ++ tty_hangup(dev->tty); ++ } ++} ++ ++static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig) ++{ ++ struct rfcomm_dev *dev = dlc->owner; ++ if (!dev) ++ return; ++ ++ BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig); ++ ++ dev->modem_status = ++ ((v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0) | ++ ((v24_sig & RFCOMM_V24_RTR) ? (TIOCM_RTS | TIOCM_CTS) : 0) | ++ ((v24_sig & RFCOMM_V24_IC) ? TIOCM_RI : 0) | ++ ((v24_sig & RFCOMM_V24_DV) ? TIOCM_CD : 0); ++} ++ ++/* ---- TTY functions ---- */ ++static void rfcomm_tty_wakeup(unsigned long arg) ++{ ++ struct rfcomm_dev *dev = (void *) arg; ++ struct tty_struct *tty = dev->tty; ++ if (!tty) ++ return; ++ ++ BT_DBG("dev %p tty %p", dev, tty); ++ ++ if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup) ++ (tty->ldisc.write_wakeup)(tty); ++ ++ wake_up_interruptible(&tty->write_wait); ++#ifdef SERIAL_HAVE_POLL_WAIT ++ wake_up_interruptible(&tty->poll_wait); ++#endif ++} ++ ++static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ struct rfcomm_dev *dev; ++ struct rfcomm_dlc *dlc; ++ int err, id; ++ ++ id = MINOR(tty->device) - tty->driver.minor_start; ++ ++ BT_DBG("tty %p id %d", tty, id); ++ ++ dev = rfcomm_dev_get(id); ++ if (!dev) ++ return -ENODEV; ++ ++ BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst), dev->channel, dev->opened); ++ ++ if (dev->opened++ != 0) ++ return 0; ++ ++ dlc = dev->dlc; ++ ++ /* Attach TTY and open DLC */ ++ ++ rfcomm_dlc_lock(dlc); ++ tty->driver_data = dev; ++ dev->tty = tty; ++ rfcomm_dlc_unlock(dlc); ++ set_bit(RFCOMM_TTY_ATTACHED, &dev->flags); ++ ++ err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel); ++ if (err < 0) ++ return err; ++ ++ /* Wait for DLC to connect */ ++ add_wait_queue(&dev->wait, &wait); ++ while (1) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ if (dlc->state == BT_CLOSED) { ++ err = -dev->err; ++ break; ++ } ++ ++ if (dlc->state == BT_CONNECTED) ++ break; ++ ++ if (signal_pending(current)) { ++ err = -EINTR; ++ break; ++ } ++ ++ schedule(); ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&dev->wait, &wait); ++ ++ return err; ++} ++ ++static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ if (!dev) ++ return; ++ ++ BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, dev->opened); ++ ++ if (--dev->opened == 0) { ++ /* Close DLC and dettach TTY */ ++ rfcomm_dlc_close(dev->dlc, 0); ++ ++ clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags); ++ tasklet_kill(&dev->wakeup_task); ++ ++ rfcomm_dlc_lock(dev->dlc); ++ tty->driver_data = NULL; ++ dev->tty = NULL; ++ rfcomm_dlc_unlock(dev->dlc); ++ } ++ ++ rfcomm_dev_put(dev); ++} ++ ++static int rfcomm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ struct rfcomm_dlc *dlc = dev->dlc; ++ struct sk_buff *skb; ++ int err = 0, sent = 0, size; ++ ++ BT_DBG("tty %p from_user %d count %d", tty, from_user, count); ++ ++ while (count) { ++ size = min_t(uint, count, dlc->mtu); ++ ++ if (from_user) ++ skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, 0, GFP_KERNEL); ++ else ++ skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, 0, GFP_ATOMIC); ++ ++ if (!skb) ++ break; ++ ++ skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE); ++ ++ if (from_user) ++ copy_from_user(skb_put(skb, size), buf + sent, size); ++ else ++ memcpy(skb_put(skb, size), buf + sent, size); ++ ++ if ((err = rfcomm_dlc_send(dlc, skb)) < 0) { ++ kfree_skb(skb); ++ break; ++ } ++ ++ sent += size; ++ count -= size; ++ } ++ ++ return sent ? sent : err; ++} ++ ++static void rfcomm_tty_put_char(struct tty_struct *tty, unsigned char ch) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ struct rfcomm_dlc *dlc = dev->dlc; ++ struct sk_buff *skb; ++ ++ BT_DBG("tty %p char %x", tty, ch); ++ ++ skb = rfcomm_wmalloc(dev, 1 + RFCOMM_SKB_RESERVE, 1, GFP_ATOMIC); ++ ++ if (!skb) ++ return; ++ ++ skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE); ++ ++ *(char *)skb_put(skb, 1) = ch; ++ ++ if ((rfcomm_dlc_send(dlc, skb)) < 0) ++ kfree_skb(skb); ++} ++ ++static int rfcomm_tty_write_room(struct tty_struct *tty) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ int room; ++ ++ BT_DBG("tty %p", tty); ++ ++ room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc); ++ if (room < 0) ++ room = 0; ++ ++ return room; ++} ++ ++static int rfcomm_tty_set_modem_status(uint cmd, struct rfcomm_dlc *dlc, uint status) ++{ ++ u8 v24_sig, mask; ++ ++ BT_DBG("dlc %p cmd 0x%02x", dlc, cmd); ++ ++ if (cmd == TIOCMSET) ++ v24_sig = 0; ++ else ++ rfcomm_dlc_get_modem_status(dlc, &v24_sig); ++ ++ mask = ((status & TIOCM_DSR) ? RFCOMM_V24_RTC : 0) | ++ ((status & TIOCM_DTR) ? RFCOMM_V24_RTC : 0) | ++ ((status & TIOCM_RTS) ? RFCOMM_V24_RTR : 0) | ++ ((status & TIOCM_CTS) ? RFCOMM_V24_RTR : 0) | ++ ((status & TIOCM_RI) ? RFCOMM_V24_IC : 0) | ++ ((status & TIOCM_CD) ? RFCOMM_V24_DV : 0); ++ ++ if (cmd == TIOCMBIC) ++ v24_sig &= ~mask; ++ else ++ v24_sig |= mask; ++ ++ rfcomm_dlc_set_modem_status(dlc, v24_sig); ++ return 0; ++} ++ ++static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ struct rfcomm_dlc *dlc = dev->dlc; ++ uint status; ++ int err; ++ ++ BT_DBG("tty %p cmd 0x%02x", tty, cmd); ++ ++ switch (cmd) { ++ case TCGETS: ++ BT_DBG("TCGETS is not supported"); ++ return -ENOIOCTLCMD; ++ ++ case TCSETS: ++ BT_DBG("TCSETS is not supported"); ++ return -ENOIOCTLCMD; ++ ++ case TIOCMGET: ++ BT_DBG("TIOCMGET"); ++ ++ return put_user(dev->modem_status, (unsigned int *)arg); ++ ++ case TIOCMSET: /* Turns on and off the lines as specified by the mask */ ++ case TIOCMBIS: /* Turns on the lines as specified by the mask */ ++ case TIOCMBIC: /* Turns off the lines as specified by the mask */ ++ if ((err = get_user(status, (unsigned int *)arg))) ++ return err; ++ return rfcomm_tty_set_modem_status(cmd, dlc, status); ++ ++ case TIOCMIWAIT: ++ BT_DBG("TIOCMIWAIT"); ++ break; ++ ++ case TIOCGICOUNT: ++ BT_DBG("TIOCGICOUNT"); ++ break; ++ ++ case TIOCGSERIAL: ++ BT_ERR("TIOCGSERIAL is not supported"); ++ return -ENOIOCTLCMD; ++ ++ case TIOCSSERIAL: ++ BT_ERR("TIOCSSERIAL is not supported"); ++ return -ENOIOCTLCMD; ++ ++ case TIOCSERGSTRUCT: ++ BT_ERR("TIOCSERGSTRUCT is not supported"); ++ return -ENOIOCTLCMD; ++ ++ case TIOCSERGETLSR: ++ BT_ERR("TIOCSERGETLSR is not supported"); ++ return -ENOIOCTLCMD; ++ ++ case TIOCSERCONFIG: ++ BT_ERR("TIOCSERCONFIG is not supported"); ++ return -ENOIOCTLCMD; ++ ++ default: ++ return -ENOIOCTLCMD; /* ioctls which we must ignore */ ++ ++ } ++ ++ return -ENOIOCTLCMD; ++} ++ ++#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) ++ ++static void rfcomm_tty_set_termios(struct tty_struct *tty, struct termios *old) ++{ ++ BT_DBG("tty %p", tty); ++ ++ if ((tty->termios->c_cflag == old->c_cflag) && ++ (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old->c_iflag))) ++ return; ++ ++ /* handle turning off CRTSCTS */ ++ if ((old->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { ++ BT_DBG("turning off CRTSCTS"); ++ } ++} ++ ++static void rfcomm_tty_throttle(struct tty_struct *tty) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ ++ BT_DBG("tty %p dev %p", tty, dev); ++ ++ rfcomm_dlc_throttle(dev->dlc); ++} ++ ++static void rfcomm_tty_unthrottle(struct tty_struct *tty) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ ++ BT_DBG("tty %p dev %p", tty, dev); ++ ++ rfcomm_dlc_unthrottle(dev->dlc); ++} ++ ++static int rfcomm_tty_chars_in_buffer(struct tty_struct *tty) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ struct rfcomm_dlc *dlc = dev->dlc; ++ ++ BT_DBG("tty %p dev %p", tty, dev); ++ ++ if (skb_queue_len(&dlc->tx_queue)) ++ return dlc->mtu; ++ ++ return 0; ++} ++ ++static void rfcomm_tty_flush_buffer(struct tty_struct *tty) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ if (!dev) ++ return; ++ ++ BT_DBG("tty %p dev %p", tty, dev); ++ ++ skb_queue_purge(&dev->dlc->tx_queue); ++ ++ if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup) ++ tty->ldisc.write_wakeup(tty); ++} ++ ++static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch) ++{ ++ BT_DBG("tty %p ch %c", tty, ch); ++} ++ ++static void rfcomm_tty_wait_until_sent(struct tty_struct *tty, int timeout) ++{ ++ BT_DBG("tty %p timeout %d", tty, timeout); ++} ++ ++static void rfcomm_tty_hangup(struct tty_struct *tty) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ if (!dev) ++ return; ++ ++ BT_DBG("tty %p dev %p", tty, dev); ++ ++ rfcomm_tty_flush_buffer(tty); ++ ++ if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) ++ rfcomm_dev_del(dev); ++} ++ ++static int rfcomm_tty_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused) ++{ ++ return 0; ++} ++ ++/* ---- TTY structure ---- */ ++static int rfcomm_tty_refcount; /* If we manage several devices */ ++ ++static struct tty_struct *rfcomm_tty_table[RFCOMM_TTY_PORTS]; ++static struct termios *rfcomm_tty_termios[RFCOMM_TTY_PORTS]; ++static struct termios *rfcomm_tty_termios_locked[RFCOMM_TTY_PORTS]; ++ ++static struct tty_driver rfcomm_tty_driver = { ++ magic: TTY_DRIVER_MAGIC, ++ driver_name: "rfcomm", ++#ifdef CONFIG_DEVFS_FS ++ name: "bluetooth/rfcomm/%d", ++#else ++ name: "rfcomm", ++#endif ++ major: RFCOMM_TTY_MAJOR, ++ minor_start: RFCOMM_TTY_MINOR, ++ num: RFCOMM_TTY_PORTS, ++ type: TTY_DRIVER_TYPE_SERIAL, ++ subtype: SERIAL_TYPE_NORMAL, ++ flags: TTY_DRIVER_REAL_RAW, ++ ++ refcount: &rfcomm_tty_refcount, ++ table: rfcomm_tty_table, ++ termios: rfcomm_tty_termios, ++ termios_locked: rfcomm_tty_termios_locked, ++ ++ open: rfcomm_tty_open, ++ close: rfcomm_tty_close, ++ put_char: rfcomm_tty_put_char, ++ write: rfcomm_tty_write, ++ write_room: rfcomm_tty_write_room, ++ chars_in_buffer: rfcomm_tty_chars_in_buffer, ++ flush_buffer: rfcomm_tty_flush_buffer, ++ ioctl: rfcomm_tty_ioctl, ++ throttle: rfcomm_tty_throttle, ++ unthrottle: rfcomm_tty_unthrottle, ++ set_termios: rfcomm_tty_set_termios, ++ send_xchar: rfcomm_tty_send_xchar, ++ stop: NULL, ++ start: NULL, ++ hangup: rfcomm_tty_hangup, ++ wait_until_sent: rfcomm_tty_wait_until_sent, ++ read_proc: rfcomm_tty_read_proc, ++}; ++ ++int rfcomm_init_ttys(void) ++{ ++ int i; ++ ++ /* Initalize our global data */ ++ for (i = 0; i < RFCOMM_TTY_PORTS; i++) ++ rfcomm_tty_table[i] = NULL; ++ ++ /* Register the TTY driver */ ++ rfcomm_tty_driver.init_termios = tty_std_termios; ++ rfcomm_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; ++ rfcomm_tty_driver.flags = TTY_DRIVER_REAL_RAW; ++ ++ if (tty_register_driver(&rfcomm_tty_driver)) { ++ BT_ERR("Can't register RFCOMM TTY driver"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++void rfcomm_cleanup_ttys(void) ++{ ++ tty_unregister_driver(&rfcomm_tty_driver); ++ return; ++} +--- /dev/null 1970-01-01 01:00:00.000000000 +0100 ++++ linux/net/bluetooth/sco.c 2004-01-25 23:37:39.000000000 +0100 +@@ -0,0 +1,1019 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * BlueZ SCO sockets. ++ * ++ * $Id$ ++ */ ++#define VERSION "0.3" ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/init.h> ++#include <linux/skbuff.h> ++#include <linux/interrupt.h> ++#include <linux/socket.h> ++#include <linux/skbuff.h> ++#include <linux/proc_fs.h> ++#include <linux/list.h> ++#include <net/sock.h> ++ ++#include <asm/system.h> ++#include <asm/uaccess.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++#include <net/bluetooth/sco.h> ++ ++#ifndef SCO_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#endif ++ ++static struct proto_ops sco_sock_ops; ++ ++static struct bluez_sock_list sco_sk_list = { ++ lock: RW_LOCK_UNLOCKED ++}; ++ ++static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent); ++static void sco_chan_del(struct sock *sk, int err); ++static inline struct sock * sco_chan_get(struct sco_conn *conn); ++ ++static int sco_conn_del(struct hci_conn *conn, int err); ++ ++static void sco_sock_close(struct sock *sk); ++static void sco_sock_kill(struct sock *sk); ++ ++/* ----- SCO timers ------ */ ++static void sco_sock_timeout(unsigned long arg) ++{ ++ struct sock *sk = (struct sock *) arg; ++ ++ BT_DBG("sock %p state %d", sk, sk->state); ++ ++ bh_lock_sock(sk); ++ sk->err = ETIMEDOUT; ++ sk->state_change(sk); ++ bh_unlock_sock(sk); ++ ++ sco_sock_kill(sk); ++ sock_put(sk); ++} ++ ++static void sco_sock_set_timer(struct sock *sk, long timeout) ++{ ++ BT_DBG("sock %p state %d timeout %ld", sk, sk->state, timeout); ++ ++ if (!mod_timer(&sk->timer, jiffies + timeout)) ++ sock_hold(sk); ++} ++ ++static void sco_sock_clear_timer(struct sock *sk) ++{ ++ BT_DBG("sock %p state %d", sk, sk->state); ++ ++ if (timer_pending(&sk->timer) && del_timer(&sk->timer)) ++ __sock_put(sk); ++} ++ ++static void sco_sock_init_timer(struct sock *sk) ++{ ++ init_timer(&sk->timer); ++ sk->timer.function = sco_sock_timeout; ++ sk->timer.data = (unsigned long)sk; ++} ++ ++/* -------- SCO connections --------- */ ++static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status) ++{ ++ struct hci_dev *hdev = hcon->hdev; ++ struct sco_conn *conn; ++ ++ if ((conn = hcon->sco_data)) ++ return conn; ++ ++ if (status) ++ return conn; ++ ++ if (!(conn = kmalloc(sizeof(struct sco_conn), GFP_ATOMIC))) ++ return NULL; ++ memset(conn, 0, sizeof(struct sco_conn)); ++ ++ spin_lock_init(&conn->lock); ++ ++ hcon->sco_data = conn; ++ conn->hcon = hcon; ++ ++ conn->src = &hdev->bdaddr; ++ conn->dst = &hcon->dst; ++ ++ if (hdev->sco_mtu > 0) ++ conn->mtu = hdev->sco_mtu; ++ else ++ conn->mtu = 60; ++ ++ BT_DBG("hcon %p conn %p", hcon, conn); ++ ++ MOD_INC_USE_COUNT; ++ return conn; ++} ++ ++static int sco_conn_del(struct hci_conn *hcon, int err) ++{ ++ struct sco_conn *conn; ++ struct sock *sk; ++ ++ if (!(conn = hcon->sco_data)) ++ return 0; ++ ++ BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); ++ ++ /* Kill socket */ ++ if ((sk = sco_chan_get(conn))) { ++ bh_lock_sock(sk); ++ sco_sock_clear_timer(sk); ++ sco_chan_del(sk, err); ++ bh_unlock_sock(sk); ++ sco_sock_kill(sk); ++ } ++ ++ hcon->sco_data = NULL; ++ kfree(conn); ++ ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++int sco_connect(struct sock *sk) ++{ ++ bdaddr_t *src = &bluez_pi(sk)->src; ++ bdaddr_t *dst = &bluez_pi(sk)->dst; ++ struct sco_conn *conn; ++ struct hci_conn *hcon; ++ struct hci_dev *hdev; ++ int err = 0; ++ ++ BT_DBG("%s -> %s", batostr(src), batostr(dst)); ++ ++ if (!(hdev = hci_get_route(dst, src))) ++ return -EHOSTUNREACH; ++ ++ hci_dev_lock_bh(hdev); ++ ++ err = -ENOMEM; ++ ++ hcon = hci_connect(hdev, SCO_LINK, dst); ++ if (!hcon) ++ goto done; ++ ++ conn = sco_conn_add(hcon, 0); ++ if (!conn) { ++ hci_conn_put(hcon); ++ goto done; ++ } ++ ++ /* Update source addr of the socket */ ++ bacpy(src, conn->src); ++ ++ err = sco_chan_add(conn, sk, NULL); ++ if (err) ++ goto done; ++ ++ if (hcon->state == BT_CONNECTED) { ++ sco_sock_clear_timer(sk); ++ sk->state = BT_CONNECTED; ++ } else { ++ sk->state = BT_CONNECT; ++ sco_sock_set_timer(sk, sk->sndtimeo); ++ } ++done: ++ hci_dev_unlock_bh(hdev); ++ hci_dev_put(hdev); ++ return err; ++} ++ ++static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) ++{ ++ struct sco_conn *conn = sco_pi(sk)->conn; ++ struct sk_buff *skb; ++ int err, count; ++ ++ /* Check outgoing MTU */ ++ if (len > conn->mtu) ++ return -EINVAL; ++ ++ BT_DBG("sk %p len %d", sk, len); ++ ++ count = MIN(conn->mtu, len); ++ if (!(skb = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err))) ++ return err; ++ ++ if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) { ++ err = -EFAULT; ++ goto fail; ++ } ++ ++ if ((err = hci_send_sco(conn->hcon, skb)) < 0) ++ goto fail; ++ ++ return count; ++ ++fail: ++ kfree_skb(skb); ++ return err; ++} ++ ++static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) ++{ ++ struct sock *sk = sco_chan_get(conn); ++ ++ if (!sk) ++ goto drop; ++ ++ BT_DBG("sk %p len %d", sk, skb->len); ++ ++ if (sk->state != BT_CONNECTED) ++ goto drop; ++ ++ if (!sock_queue_rcv_skb(sk, skb)) ++ return; ++ ++drop: ++ kfree_skb(skb); ++ return; ++} ++ ++/* -------- Socket interface ---------- */ ++static struct sock *__sco_get_sock_by_addr(bdaddr_t *ba) ++{ ++ struct sock *sk; ++ ++ for (sk = sco_sk_list.head; sk; sk = sk->next) { ++ if (!bacmp(&bluez_pi(sk)->src, ba)) ++ break; ++ } ++ ++ return sk; ++} ++ ++/* Find socket listening on source bdaddr. ++ * Returns closest match. ++ */ ++static struct sock *sco_get_sock_listen(bdaddr_t *src) ++{ ++ struct sock *sk, *sk1 = NULL; ++ ++ read_lock(&sco_sk_list.lock); ++ ++ for (sk = sco_sk_list.head; sk; sk = sk->next) { ++ if (sk->state != BT_LISTEN) ++ continue; ++ ++ /* Exact match. */ ++ if (!bacmp(&bluez_pi(sk)->src, src)) ++ break; ++ ++ /* Closest match */ ++ if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY)) ++ sk1 = sk; ++ } ++ ++ read_unlock(&sco_sk_list.lock); ++ ++ return sk ? sk : sk1; ++} ++ ++static void sco_sock_destruct(struct sock *sk) ++{ ++ BT_DBG("sk %p", sk); ++ ++ skb_queue_purge(&sk->receive_queue); ++ skb_queue_purge(&sk->write_queue); ++ ++ MOD_DEC_USE_COUNT; ++} ++ ++static void sco_sock_cleanup_listen(struct sock *parent) ++{ ++ struct sock *sk; ++ ++ BT_DBG("parent %p", parent); ++ ++ /* Close not yet accepted channels */ ++ while ((sk = bluez_accept_dequeue(parent, NULL))) { ++ sco_sock_close(sk); ++ sco_sock_kill(sk); ++ } ++ ++ parent->state = BT_CLOSED; ++ parent->zapped = 1; ++} ++ ++/* Kill socket (only if zapped and orphan) ++ * Must be called on unlocked socket. ++ */ ++static void sco_sock_kill(struct sock *sk) ++{ ++ if (!sk->zapped || sk->socket) ++ return; ++ ++ BT_DBG("sk %p state %d", sk, sk->state); ++ ++ /* Kill poor orphan */ ++ bluez_sock_unlink(&sco_sk_list, sk); ++ sk->dead = 1; ++ sock_put(sk); ++} ++ ++/* Close socket. ++ * Must be called on unlocked socket. ++ */ ++static void sco_sock_close(struct sock *sk) ++{ ++ struct sco_conn *conn; ++ ++ sco_sock_clear_timer(sk); ++ ++ lock_sock(sk); ++ ++ conn = sco_pi(sk)->conn; ++ ++ BT_DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket); ++ ++ switch (sk->state) { ++ case BT_LISTEN: ++ sco_sock_cleanup_listen(sk); ++ break; ++ ++ case BT_CONNECTED: ++ case BT_CONFIG: ++ case BT_CONNECT: ++ case BT_DISCONN: ++ sco_chan_del(sk, ECONNRESET); ++ break; ++ ++ default: ++ sk->zapped = 1; ++ break; ++ }; ++ ++ release_sock(sk); ++} ++ ++static void sco_sock_init(struct sock *sk, struct sock *parent) ++{ ++ BT_DBG("sk %p", sk); ++ ++ if (parent) ++ sk->type = parent->type; ++} ++ ++static struct sock *sco_sock_alloc(struct socket *sock, int proto, int prio) ++{ ++ struct sock *sk; ++ ++ if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1))) ++ return NULL; ++ ++ bluez_sock_init(sock, sk); ++ ++ sk->zapped = 0; ++ ++ sk->destruct = sco_sock_destruct; ++ sk->sndtimeo = SCO_CONN_TIMEOUT; ++ ++ sk->protocol = proto; ++ sk->state = BT_OPEN; ++ ++ sco_sock_init_timer(sk); ++ ++ bluez_sock_link(&sco_sk_list, sk); ++ ++ MOD_INC_USE_COUNT; ++ return sk; ++} ++ ++static int sco_sock_create(struct socket *sock, int protocol) ++{ ++ struct sock *sk; ++ ++ BT_DBG("sock %p", sock); ++ ++ sock->state = SS_UNCONNECTED; ++ ++ if (sock->type != SOCK_SEQPACKET) ++ return -ESOCKTNOSUPPORT; ++ ++ sock->ops = &sco_sock_ops; ++ ++ if (!(sk = sco_sock_alloc(sock, protocol, GFP_KERNEL))) ++ return -ENOMEM; ++ ++ sco_sock_init(sk, NULL); ++ return 0; ++} ++ ++static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) ++{ ++ struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; ++ struct sock *sk = sock->sk; ++ bdaddr_t *src = &sa->sco_bdaddr; ++ int err = 0; ++ ++ BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr)); ++ ++ if (!addr || addr->sa_family != AF_BLUETOOTH) ++ return -EINVAL; ++ ++ lock_sock(sk); ++ ++ if (sk->state != BT_OPEN) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ write_lock_bh(&sco_sk_list.lock); ++ ++ if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) { ++ err = -EADDRINUSE; ++ } else { ++ /* Save source address */ ++ bacpy(&bluez_pi(sk)->src, &sa->sco_bdaddr); ++ sk->state = BT_BOUND; ++ } ++ ++ write_unlock_bh(&sco_sk_list.lock); ++ ++done: ++ release_sock(sk); ++ ++ return err; ++} ++ ++static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) ++{ ++ struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ ++ BT_DBG("sk %p", sk); ++ ++ if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_sco)) ++ return -EINVAL; ++ ++ if (sk->state != BT_OPEN && sk->state != BT_BOUND) ++ return -EBADFD; ++ ++ if (sk->type != SOCK_SEQPACKET) ++ return -EINVAL; ++ ++ lock_sock(sk); ++ ++ /* Set destination address and psm */ ++ bacpy(&bluez_pi(sk)->dst, &sa->sco_bdaddr); ++ ++ if ((err = sco_connect(sk))) ++ goto done; ++ ++ err = bluez_sock_wait_state(sk, BT_CONNECTED, ++ sock_sndtimeo(sk, flags & O_NONBLOCK)); ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++int sco_sock_listen(struct socket *sock, int backlog) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sk %p backlog %d", sk, backlog); ++ ++ lock_sock(sk); ++ ++ if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ sk->max_ack_backlog = backlog; ++ sk->ack_backlog = 0; ++ sk->state = BT_LISTEN; ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++int sco_sock_accept(struct socket *sock, struct socket *newsock, int flags) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ struct sock *sk = sock->sk, *ch; ++ long timeo; ++ int err = 0; ++ ++ lock_sock(sk); ++ ++ if (sk->state != BT_LISTEN) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); ++ ++ BT_DBG("sk %p timeo %ld", sk, timeo); ++ ++ /* Wait for an incoming connection. (wake-one). */ ++ add_wait_queue_exclusive(sk->sleep, &wait); ++ while (!(ch = bluez_accept_dequeue(sk, newsock))) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ if (!timeo) { ++ err = -EAGAIN; ++ break; ++ } ++ ++ release_sock(sk); ++ timeo = schedule_timeout(timeo); ++ lock_sock(sk); ++ ++ if (sk->state != BT_LISTEN) { ++ err = -EBADFD; ++ break; ++ } ++ ++ if (signal_pending(current)) { ++ err = sock_intr_errno(timeo); ++ break; ++ } ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(sk->sleep, &wait); ++ ++ if (err) ++ goto done; ++ ++ newsock->state = SS_CONNECTED; ++ ++ BT_DBG("new socket %p", ch); ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer) ++{ ++ struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; ++ struct sock *sk = sock->sk; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ addr->sa_family = AF_BLUETOOTH; ++ *len = sizeof(struct sockaddr_sco); ++ ++ if (peer) ++ bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->dst); ++ else ++ bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->src); ++ ++ return 0; ++} ++ ++static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ if (sk->err) ++ return sock_error(sk); ++ ++ if (msg->msg_flags & MSG_OOB) ++ return -EOPNOTSUPP; ++ ++ lock_sock(sk); ++ ++ if (sk->state == BT_CONNECTED) ++ err = sco_send_frame(sk, msg, len); ++ else ++ err = -ENOTCONN; ++ ++ release_sock(sk); ++ return err; ++} ++ ++int sco_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sk %p", sk); ++ ++ lock_sock(sk); ++ ++ switch (optname) { ++ default: ++ err = -ENOPROTOOPT; ++ break; ++ }; ++ ++ release_sock(sk); ++ return err; ++} ++ ++int sco_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) ++{ ++ struct sock *sk = sock->sk; ++ struct sco_options opts; ++ struct sco_conninfo cinfo; ++ int len, err = 0; ++ ++ BT_DBG("sk %p", sk); ++ ++ if (get_user(len, optlen)) ++ return -EFAULT; ++ ++ lock_sock(sk); ++ ++ switch (optname) { ++ case SCO_OPTIONS: ++ if (sk->state != BT_CONNECTED) { ++ err = -ENOTCONN; ++ break; ++ } ++ ++ opts.mtu = sco_pi(sk)->conn->mtu; ++ ++ BT_DBG("mtu %d", opts.mtu); ++ ++ len = MIN(len, sizeof(opts)); ++ if (copy_to_user(optval, (char *)&opts, len)) ++ err = -EFAULT; ++ ++ break; ++ ++ case SCO_CONNINFO: ++ if (sk->state != BT_CONNECTED) { ++ err = -ENOTCONN; ++ break; ++ } ++ ++ cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle; ++ ++ len = MIN(len, sizeof(cinfo)); ++ if (copy_to_user(optval, (char *)&cinfo, len)) ++ err = -EFAULT; ++ ++ break; ++ ++ default: ++ err = -ENOPROTOOPT; ++ break; ++ }; ++ ++ release_sock(sk); ++ return err; ++} ++ ++static int sco_sock_release(struct socket *sock) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ if (!sk) ++ return 0; ++ ++ sco_sock_close(sk); ++ if (sk->linger) { ++ lock_sock(sk); ++ err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime); ++ release_sock(sk); ++ } ++ ++ sock_orphan(sk); ++ sco_sock_kill(sk); ++ return err; ++} ++ ++static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) ++{ ++ BT_DBG("conn %p", conn); ++ ++ sco_pi(sk)->conn = conn; ++ conn->sk = sk; ++ ++ if (parent) ++ bluez_accept_enqueue(parent, sk); ++} ++ ++static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) ++{ ++ int err = 0; ++ ++ sco_conn_lock(conn); ++ if (conn->sk) { ++ err = -EBUSY; ++ } else { ++ __sco_chan_add(conn, sk, parent); ++ } ++ sco_conn_unlock(conn); ++ return err; ++} ++ ++static inline struct sock * sco_chan_get(struct sco_conn *conn) ++{ ++ struct sock *sk = NULL; ++ sco_conn_lock(conn); ++ sk = conn->sk; ++ sco_conn_unlock(conn); ++ return sk; ++} ++ ++/* Delete channel. ++ * Must be called on the locked socket. */ ++static void sco_chan_del(struct sock *sk, int err) ++{ ++ struct sco_conn *conn; ++ ++ conn = sco_pi(sk)->conn; ++ ++ BT_DBG("sk %p, conn %p, err %d", sk, conn, err); ++ ++ if (conn) { ++ sco_conn_lock(conn); ++ conn->sk = NULL; ++ sco_pi(sk)->conn = NULL; ++ sco_conn_unlock(conn); ++ hci_conn_put(conn->hcon); ++ } ++ ++ sk->state = BT_CLOSED; ++ sk->err = err; ++ sk->state_change(sk); ++ ++ sk->zapped = 1; ++} ++ ++static void sco_conn_ready(struct sco_conn *conn) ++{ ++ struct sock *parent, *sk; ++ ++ BT_DBG("conn %p", conn); ++ ++ sco_conn_lock(conn); ++ ++ if ((sk = conn->sk)) { ++ sco_sock_clear_timer(sk); ++ bh_lock_sock(sk); ++ sk->state = BT_CONNECTED; ++ sk->state_change(sk); ++ bh_unlock_sock(sk); ++ } else { ++ parent = sco_get_sock_listen(conn->src); ++ if (!parent) ++ goto done; ++ ++ bh_lock_sock(parent); ++ ++ sk = sco_sock_alloc(NULL, BTPROTO_SCO, GFP_ATOMIC); ++ if (!sk) { ++ bh_unlock_sock(parent); ++ goto done; ++ } ++ ++ sco_sock_init(sk, parent); ++ ++ bacpy(&bluez_pi(sk)->src, conn->src); ++ bacpy(&bluez_pi(sk)->dst, conn->dst); ++ ++ hci_conn_hold(conn->hcon); ++ __sco_chan_add(conn, sk, parent); ++ ++ sk->state = BT_CONNECTED; ++ ++ /* Wake up parent */ ++ parent->data_ready(parent, 1); ++ ++ bh_unlock_sock(parent); ++ } ++ ++done: ++ sco_conn_unlock(conn); ++} ++ ++/* ----- SCO interface with lower layer (HCI) ----- */ ++int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) ++{ ++ BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); ++ ++ /* Always accept connection */ ++ return HCI_LM_ACCEPT; ++} ++ ++int sco_connect_cfm(struct hci_conn *hcon, __u8 status) ++{ ++ BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); ++ ++ if (hcon->type != SCO_LINK) ++ return 0; ++ ++ if (!status) { ++ struct sco_conn *conn; ++ ++ conn = sco_conn_add(hcon, status); ++ if (conn) ++ sco_conn_ready(conn); ++ } else ++ sco_conn_del(hcon, bterr(status)); ++ ++ return 0; ++} ++ ++int sco_disconn_ind(struct hci_conn *hcon, __u8 reason) ++{ ++ BT_DBG("hcon %p reason %d", hcon, reason); ++ ++ if (hcon->type != SCO_LINK) ++ return 0; ++ ++ sco_conn_del(hcon, bterr(reason)); ++ return 0; ++} ++ ++int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb) ++{ ++ struct sco_conn *conn = hcon->sco_data; ++ ++ if (!conn) ++ goto drop; ++ ++ BT_DBG("conn %p len %d", conn, skb->len); ++ ++ if (skb->len) { ++ sco_recv_frame(conn, skb); ++ return 0; ++ } ++ ++drop: ++ kfree_skb(skb); ++ return 0; ++} ++ ++/* ----- Proc fs support ------ */ ++static int sco_sock_dump(char *buf, struct bluez_sock_list *list) ++{ ++ struct sco_pinfo *pi; ++ struct sock *sk; ++ char *ptr = buf; ++ ++ write_lock_bh(&list->lock); ++ ++ for (sk = list->head; sk; sk = sk->next) { ++ pi = sco_pi(sk); ++ ptr += sprintf(ptr, "%s %s %d\n", ++ batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst), ++ sk->state); ++ } ++ ++ write_unlock_bh(&list->lock); ++ ++ ptr += sprintf(ptr, "\n"); ++ ++ return ptr - buf; ++} ++ ++static int sco_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv) ++{ ++ char *ptr = buf; ++ int len; ++ ++ BT_DBG("count %d, offset %ld", count, offset); ++ ++ ptr += sco_sock_dump(ptr, &sco_sk_list); ++ len = ptr - buf; ++ ++ if (len <= count + offset) ++ *eof = 1; ++ ++ *start = buf + offset; ++ len -= offset; ++ ++ if (len > count) ++ len = count; ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++ ++static struct proto_ops sco_sock_ops = { ++ family: PF_BLUETOOTH, ++ release: sco_sock_release, ++ bind: sco_sock_bind, ++ connect: sco_sock_connect, ++ listen: sco_sock_listen, ++ accept: sco_sock_accept, ++ getname: sco_sock_getname, ++ sendmsg: sco_sock_sendmsg, ++ recvmsg: bluez_sock_recvmsg, ++ poll: bluez_sock_poll, ++ socketpair: sock_no_socketpair, ++ ioctl: sock_no_ioctl, ++ shutdown: sock_no_shutdown, ++ setsockopt: sco_sock_setsockopt, ++ getsockopt: sco_sock_getsockopt, ++ mmap: sock_no_mmap ++}; ++ ++static struct net_proto_family sco_sock_family_ops = { ++ family: PF_BLUETOOTH, ++ create: sco_sock_create ++}; ++ ++static struct hci_proto sco_hci_proto = { ++ name: "SCO", ++ id: HCI_PROTO_SCO, ++ connect_ind: sco_connect_ind, ++ connect_cfm: sco_connect_cfm, ++ disconn_ind: sco_disconn_ind, ++ recv_scodata: sco_recv_scodata, ++}; ++ ++int __init sco_init(void) ++{ ++ int err; ++ ++ if ((err = bluez_sock_register(BTPROTO_SCO, &sco_sock_family_ops))) { ++ BT_ERR("Can't register SCO socket layer"); ++ return err; ++ } ++ ++ if ((err = hci_register_proto(&sco_hci_proto))) { ++ BT_ERR("Can't register SCO protocol"); ++ return err; ++ } ++ ++ create_proc_read_entry("bluetooth/sco", 0, 0, sco_read_proc, NULL); ++ ++ BT_INFO("BlueZ SCO ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION); ++ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); ++ return 0; ++} ++ ++void sco_cleanup(void) ++{ ++ int err; ++ ++ remove_proc_entry("bluetooth/sco", NULL); ++ ++ /* Unregister socket, protocol and notifier */ ++ if ((err = bluez_sock_unregister(BTPROTO_SCO))) ++ BT_ERR("Can't unregister SCO socket layer %d", err); ++ ++ if ((err = hci_unregister_proto(&sco_hci_proto))) ++ BT_ERR("Can't unregister SCO protocol %d", err); ++} ++ ++module_init(sco_init); ++module_exit(sco_cleanup); ++ ++MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); ++MODULE_DESCRIPTION("BlueZ SCO ver " VERSION); ++MODULE_LICENSE("GPL"); +--- linux/net/bluetooth/syms.c~bluetooth-2.4.18-mh11 2001-09-07 18:28:38.000000000 +0200 ++++ linux/net/bluetooth/syms.c 2004-01-25 23:37:39.000000000 +0100 +@@ -25,7 +25,7 @@ + /* + * BlueZ symbols. + * +- * $Id$ ++ * $Id$ + */ + + #include <linux/config.h> +@@ -39,25 +39,28 @@ + #include <linux/socket.h> + + #include <net/bluetooth/bluetooth.h> +-#include <net/bluetooth/bluez.h> + #include <net/bluetooth/hci_core.h> + + /* HCI Core */ + EXPORT_SYMBOL(hci_register_dev); + EXPORT_SYMBOL(hci_unregister_dev); ++EXPORT_SYMBOL(hci_suspend_dev); ++EXPORT_SYMBOL(hci_resume_dev); ++ + EXPORT_SYMBOL(hci_register_proto); + EXPORT_SYMBOL(hci_unregister_proto); +-EXPORT_SYMBOL(hci_register_notifier); +-EXPORT_SYMBOL(hci_unregister_notifier); + ++EXPORT_SYMBOL(hci_get_route); + EXPORT_SYMBOL(hci_connect); +-EXPORT_SYMBOL(hci_disconnect); + EXPORT_SYMBOL(hci_dev_get); ++EXPORT_SYMBOL(hci_conn_auth); ++EXPORT_SYMBOL(hci_conn_encrypt); + + EXPORT_SYMBOL(hci_recv_frame); + EXPORT_SYMBOL(hci_send_acl); + EXPORT_SYMBOL(hci_send_sco); +-EXPORT_SYMBOL(hci_send_raw); ++EXPORT_SYMBOL(hci_send_cmd); ++EXPORT_SYMBOL(hci_si_event); + + /* BlueZ lib */ + EXPORT_SYMBOL(bluez_dump); +@@ -68,5 +71,11 @@ + /* BlueZ sockets */ + EXPORT_SYMBOL(bluez_sock_register); + EXPORT_SYMBOL(bluez_sock_unregister); ++EXPORT_SYMBOL(bluez_sock_init); + EXPORT_SYMBOL(bluez_sock_link); + EXPORT_SYMBOL(bluez_sock_unlink); ++EXPORT_SYMBOL(bluez_sock_recvmsg); ++EXPORT_SYMBOL(bluez_sock_poll); ++EXPORT_SYMBOL(bluez_accept_enqueue); ++EXPORT_SYMBOL(bluez_accept_dequeue); ++EXPORT_SYMBOL(bluez_sock_wait_state); diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bt950_cs.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bt950_cs.patch index e69de29bb2..c29f0d02f2 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bt950_cs.patch +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bt950_cs.patch @@ -0,0 +1,1174 @@ +diff -Nur linux-orig/drivers/bluetooth/bt950_cs.c linux/drivers/bluetooth/bt950_cs.c +--- linux-orig/drivers/bluetooth/bt950_cs.c 1970-01-01 03:00:00.000000000 +0300 ++++ linux/drivers/bluetooth/bt950_cs.c 2004-02-04 09:55:04.000000000 +0300 +@@ -0,0 +1,1133 @@ ++/* ++ * ++ * Driver for Bluetooth cards with OXCF950 UART interface ++ * ++ * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org> ++ * Albert Rybalkin <albertr@iral.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; ++ * ++ * Software distributed under the License is distributed on an "AS ++ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++ * implied. See the License for the specific language governing ++ * rights and limitations under the License. ++ * ++ * The initial developer of the original code is David A. Hinds ++ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds ++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. ++ * ++ */ ++ ++#include <linux/config.h> ++ ++#ifdef CONFIG_MODVERSIONS ++#ifndef MODVERSIONS ++#define MODVERSIONS ++#endif ++#include <linux/modversions.h> ++#endif ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/types.h> ++#include <linux/sched.h> ++#include <linux/timer.h> ++#include <linux/errno.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/spinlock.h> ++#include <linux/delay.h> ++ ++#include <linux/skbuff.h> ++#include <linux/string.h> ++#include <linux/serial.h> ++#include <linux/serial_reg.h> ++#include <asm/system.h> ++#include <asm/bitops.h> ++#include <asm/io.h> ++ ++#include <pcmcia/version.h> ++#include <pcmcia/cs_types.h> ++#include <pcmcia/cs.h> ++#include <pcmcia/cistpl.h> ++#include <pcmcia/ciscode.h> ++#include <pcmcia/ds.h> ++#include <pcmcia/cisreg.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++ ++/* Default baud rate: 57600, 115200, 230400 or 460800 */ ++#define DEFAULT_BAUD_RATE 460800 ++ ++ ++/* ======================== Module parameters ======================== */ ++ ++ ++/* Bit map of interrupts to choose from */ ++static u_int irq_mask = 0x86bc; ++static int irq_list[4] = { -1 }; ++static long baud_rate = DEFAULT_BAUD_RATE; ++ ++MODULE_PARM(irq_mask, "i"); ++MODULE_PARM(irq_list, "1-4i"); ++MODULE_PARM(baud_rate, "l"); ++ ++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Albert Rybalkin <albertr@iral.com>"); ++MODULE_DESCRIPTION("BlueZ driver for Bluetooth cards with OXCF950 UART interface"); ++MODULE_LICENSE("GPL"); ++ ++ ++ ++/* ======================== Local structures ======================== */ ++ ++ ++typedef struct bt950_info_t { ++ dev_link_t link; ++ dev_node_t node; ++ ++ struct hci_dev hdev; ++ ++ spinlock_t lock; /* For serializing operations */ ++ ++ struct sk_buff_head txq; ++ unsigned long tx_state; ++ ++ unsigned long rx_state; ++ unsigned long rx_count; ++ struct sk_buff *rx_skb; ++} bt950_info_t; ++ ++ ++static void bt950_config(dev_link_t *link); ++static void bt950_release(u_long arg); ++static int bt950_event(event_t event, int priority, event_callback_args_t *args); ++ ++static dev_info_t dev_info = "bt950_cs"; ++ ++static dev_link_t *bt950_attach(void); ++static void bt950_detach(dev_link_t *); ++ ++static dev_link_t *dev_list = NULL; ++ ++/* Transmit states */ ++#define XMIT_SENDING 1 ++#define XMIT_WAKEUP 2 ++#define XMIT_WAITING 8 ++ ++/* Receiver states */ ++#define RECV_WAIT_PACKET_TYPE 0 ++#define RECV_WAIT_EVENT_HEADER 1 ++#define RECV_WAIT_ACL_HEADER 2 ++#define RECV_WAIT_SCO_HEADER 3 ++#define RECV_WAIT_DATA 4 ++ ++/* Special packet types */ ++#define PKT_BAUD_RATE_57600 0x80 ++#define PKT_BAUD_RATE_115200 0x81 ++#define PKT_BAUD_RATE_230400 0x82 ++#define PKT_BAUD_RATE_460800 0x83 ++ ++/* 950-specific stuff */ ++#define MAX_WAIT 0xFFFF ++#define FIFO_SIZE 128 ++ ++#define TR_TX_INT 0x10 /* TTL: TX interrupt trigger level (0-127) */ ++#define TR_RX_INT 0x40 /* RTL: RX interrupt trigger level (1-127) */ ++#define TR_CTL_LO 0x08 /* FCL: auto flow control LOWER trigger level (0-127) */ ++#define TR_CTL_HI 0x60 /* FCH: auto flow control HIGH trigger level (1-127) */ ++ ++/* 950-specific registers and values we use. It should ++ * eventually go to include/linux/serial_reg.h */ ++#define UART_IER_CTS 0x80 /* enable CTS interrupt */ ++#define UART_IER_RTS 0x40 /* enable RTS interrupt */ ++#define UART_IER_SLP 0x10 /* enable sleep mode */ ++#define UART_LCR_650 0xBF /* enable 650-compatible registers access */ ++#define UART_LSR_DE 0x80 /* data error */ ++#define UART_LSR_ERR (UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI|UART_LSR_DE) ++#define UART_IIR_RXTOUT 0x0C /* RX timeout interrupt */ ++#define UART_IIR_CTSRTS 0x20 /* CTS or RTS change interrupt */ ++#define UART_IIR_RTS 0x40 ++#define UART_IIR_CTS 0x80 ++#define UART_IIR_MASK 0x3E /* interrupt mask */ ++#define UART_SRT 0x0D /* soft reset register */ ++ ++ ++ ++/* ======================== Interrupt handling ======================== */ ++ ++ ++static int bt950_write(unsigned int iobase, int fifo_size, const unsigned char *buf, int len) ++{ ++ int i, actual = 0; ++ ++ /* Activate DTR and RTS */ ++ outb(UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2, iobase + UART_MCR); ++ ++ /* Wait for CTS flow control */ ++ for (i = MAX_WAIT; i; i--) ++ if (inb(iobase + UART_MSR) & UART_MSR_CTS) ++ break; ++ ++ if (!i) { ++ printk(KERN_WARNING "bt950_cs: Timeout waiting for CTS on write.\n"); ++ return 0; ++ } ++ ++ /* The TX FIFO should be empty */ ++ for (i = MAX_WAIT; i; i--) ++ if (inb(iobase + UART_LSR) & UART_LSR_THRE) ++ break; ++ ++ if (!i) { ++ printk(KERN_WARNING "bt950_cs: Timeout waiting for empty TX FIFO on write.\n"); ++ return 0; ++ } ++ ++ /* Fill FIFO with current frame */ ++ while ((fifo_size-- > 0) && (actual < len)) { ++ /* Transmit next byte */ ++ outb(buf[actual], iobase + UART_TX); ++ actual++; ++ } ++ ++ return actual; ++} ++ ++ ++static void bt950_write_wakeup(bt950_info_t *info) ++{ ++ unsigned char lcr; ++ unsigned int divisor; ++ ++ if (!info) { ++ printk(KERN_WARNING "bt950_cs: Call of write_wakeup for unknown device.\n"); ++ return; ++ } ++ ++ if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { ++ set_bit(XMIT_WAKEUP, &(info->tx_state)); ++ return; ++ } ++ ++ do { ++ register unsigned int iobase = info->link.io.BasePort1; ++ register struct sk_buff *skb; ++ register int len; ++ ++ clear_bit(XMIT_WAKEUP, &(info->tx_state)); ++ ++ if (!(info->link.state & DEV_PRESENT)) ++ return; ++ ++ if (!(skb = skb_dequeue(&(info->txq)))) ++ break; ++ ++ if (skb->pkt_type & 0x80) { ++ /* Disable RTS */ ++ outb((inb(iobase + UART_MCR) & ~UART_MCR_RTS), iobase + UART_MCR); ++ } ++ ++ /* Send frame */ ++ len = bt950_write(iobase, FIFO_SIZE, skb->data, skb->len); ++ ++ set_bit(XMIT_WAKEUP, &(info->tx_state)); ++ ++ if (skb->pkt_type & 0x80) { ++ ++ wait_queue_head_t wait; ++ ++ switch (skb->pkt_type) { ++ ++ case PKT_BAUD_RATE_460800: ++ divisor = 1; ++ break; ++ ++ case PKT_BAUD_RATE_230400: ++ divisor = 2; ++ break; ++ ++ case PKT_BAUD_RATE_115200: ++ divisor = 4; ++ break; ++ ++ case PKT_BAUD_RATE_57600: ++ /* Fall through... */ ++ ++ default: ++ divisor = 8; ++ break; ++ } ++ ++ /* Wait until the command reaches the baseband */ ++ init_waitqueue_head(&wait); ++ interruptible_sleep_on_timeout(&wait, HZ / 10); ++ ++ /* Set baud on baseband */ ++ /* Enable divisor latch access */ ++ lcr = inb(iobase + UART_LCR) & 0x3F; ++ outb(lcr | UART_LCR_DLAB, iobase + UART_LCR); ++ ++ /* Setup divisor latch */ ++ outb(divisor & 0x00FF, iobase + UART_DLL); /* divisor latch LOW byte */ ++ outb((divisor & 0xFF00) >> 8, iobase + UART_DLM); /* divisor latch HI byte */ ++ ++ /* Disable divisor latch access */ ++ outb(lcr, iobase + UART_LCR); ++ ++ /* Enable RTS */ ++ outb((inb(iobase + UART_MCR) | UART_MCR_RTS), iobase + UART_MCR); ++ ++ /* Wait before the next HCI packet can be send */ ++ interruptible_sleep_on_timeout(&wait, HZ); ++ ++ } ++ ++ if (len == skb->len) { ++ kfree_skb(skb); ++ } else { ++ skb_pull(skb, len); ++ skb_queue_head(&(info->txq), skb); ++ } ++ ++ info->hdev.stat.byte_tx += len; ++ ++ } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); ++ ++ clear_bit(XMIT_SENDING, &(info->tx_state)); ++} ++ ++ ++static inline void bt950_receive(bt950_info_t *info) ++{ ++ unsigned int iobase; ++ int boguscount = 0; ++ ++ if (!info) { ++ printk(KERN_ERR "bt950_cs: Call of receive for unknown device.\n"); ++ return; ++ } ++ ++ iobase = info->link.io.BasePort1; ++ ++ /* Fixme: BUG? */ ++ inb(iobase + UART_MCR); ++ ++ do { ++ info->hdev.stat.byte_rx++; ++ ++ /* Allocate packet */ ++ if (info->rx_skb == NULL) { ++ info->rx_state = RECV_WAIT_PACKET_TYPE; ++ info->rx_count = 0; ++ if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { ++ printk(KERN_ERR "bt950_cs: Can't allocate mem for new packet.\n"); ++ return; ++ } ++ } ++ ++ if (info->rx_state == RECV_WAIT_PACKET_TYPE) { ++ ++ info->rx_skb->dev = (void *)&(info->hdev); ++ info->rx_skb->pkt_type = inb(iobase + UART_RX); ++ ++ switch (info->rx_skb->pkt_type) { ++ ++ case HCI_EVENT_PKT: ++ info->rx_state = RECV_WAIT_EVENT_HEADER; ++ info->rx_count = HCI_EVENT_HDR_SIZE; ++ break; ++ ++ case HCI_ACLDATA_PKT: ++ info->rx_state = RECV_WAIT_ACL_HEADER; ++ info->rx_count = HCI_ACL_HDR_SIZE; ++ break; ++ ++ case HCI_SCODATA_PKT: ++ info->rx_state = RECV_WAIT_SCO_HEADER; ++ info->rx_count = HCI_SCO_HDR_SIZE; ++ break; ++ ++ default: ++ /* Unknown packet */ ++ printk(KERN_WARNING "bt950_cs: Unknown HCI packet with type 0x%02X received.\n", info->rx_skb->pkt_type); ++ info->hdev.stat.err_rx++; ++ ++ kfree_skb(info->rx_skb); ++ info->rx_skb = NULL; ++ break; ++ ++ } ++ ++ } else { ++ ++ *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); ++ info->rx_count--; ++ ++ if (info->rx_count == 0) { ++ ++ int dlen; ++ hci_event_hdr *eh; ++ hci_acl_hdr *ah; ++ hci_sco_hdr *sh; ++ ++ ++ switch (info->rx_state) { ++ ++ case RECV_WAIT_EVENT_HEADER: ++ eh = (hci_event_hdr *)(info->rx_skb->data); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = eh->plen; ++ break; ++ ++ case RECV_WAIT_ACL_HEADER: ++ ah = (hci_acl_hdr *)(info->rx_skb->data); ++ dlen = __le16_to_cpu(ah->dlen); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = dlen; ++ break; ++ ++ case RECV_WAIT_SCO_HEADER: ++ sh = (hci_sco_hdr *)(info->rx_skb->data); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = sh->dlen; ++ break; ++ ++ case RECV_WAIT_DATA: ++ hci_recv_frame(info->rx_skb); ++ info->rx_skb = NULL; ++ break; ++ ++ } ++ ++ } ++ ++ } ++ ++ /* Make sure we don't stay here too long */ ++ if (boguscount++ > 16) ++ break; ++ ++ } while (inb(iobase + UART_LSR) & UART_LSR_DR); ++} ++ ++ ++static void bt950_interrupt(int irq, void *dev_inst, struct pt_regs *regs) ++{ ++ bt950_info_t *info = dev_inst; ++ unsigned int iobase; ++ int boguscount = 0; ++ int iir, lsr; ++ ++ if (!info) { ++ printk(KERN_ERR "bt950_cs: Call of irq %d for unknown device.\n", irq); ++ return; ++ } ++ ++ iobase = info->link.io.BasePort1; ++ ++ spin_lock(&(info->lock)); ++ ++ iir = inb(iobase + UART_IIR); ++ ++ while (!(iir & UART_IIR_NO_INT)) { ++ ++ switch (iir & UART_IIR_ID) { ++ case UART_IIR_RLSI: ++ /* Clear RLSI interrupt */ ++ lsr = inb(iobase + UART_LSR); ++ printk(KERN_NOTICE "bt950_cs: RLSI interrupt, LSR=%#x\n", lsr); ++ /* Fixme: we need to process errors ... */ ++ break; ++ case UART_IIR_RDI: ++ /* Receive interrupt */ ++ bt950_receive(info); ++ break; ++ case UART_IIR_THRI: ++ /* Transmitter ready for data */ ++ bt950_write_wakeup(info); ++ break; ++ default: ++ printk(KERN_NOTICE "bt950_cs: Unhandled IIR=%#x\n", iir); ++ break; ++ } ++ ++ /* Make sure we don't stay here too long */ ++ if (boguscount++ > 100) ++ break; ++ ++ iir = inb(iobase + UART_IIR); ++ ++ } ++ ++ spin_unlock(&(info->lock)); ++} ++ ++/* ======================== Device specific HCI commands ======================== */ ++ ++ ++static int bt950_hci_set_baud_rate(struct hci_dev *hdev, int baud) ++{ ++ bt950_info_t *info = (bt950_info_t *)(hdev->driver_data); ++ struct sk_buff *skb; ++ ++ /* Ericsson baud rate command */ ++ unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 }; ++ ++ if (!(skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { ++ printk(KERN_WARNING "bt950_cs: Can't allocate mem for new packet.\n"); ++ return -1; ++ } ++ ++ switch (baud) { ++ case 460800: ++ cmd[4] = 0x00; ++ skb->pkt_type = PKT_BAUD_RATE_460800; ++ break; ++ case 230400: ++ cmd[4] = 0x01; ++ skb->pkt_type = PKT_BAUD_RATE_230400; ++ break; ++ case 115200: ++ cmd[4] = 0x02; ++ skb->pkt_type = PKT_BAUD_RATE_115200; ++ break; ++ case 57600: ++ /* Fall through... */ ++ default: ++ baud = 57600; ++ cmd[4] = 0x03; ++ skb->pkt_type = PKT_BAUD_RATE_57600; ++ break; ++ } ++ ++ memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd)); ++ ++ skb_queue_tail(&(info->txq), skb); ++ ++ printk(KERN_WARNING "bt950_cs: setting baud rate: %d.\n", baud); ++ ++ bt950_write_wakeup(info); ++ ++ return 0; ++} ++ ++ ++/* ======================== HCI interface ======================== */ ++ ++ ++static int bt950_hci_flush(struct hci_dev *hdev) ++{ ++ bt950_info_t *info = (bt950_info_t *)(hdev->driver_data); ++ ++ /* Drop TX queue */ ++ skb_queue_purge(&(info->txq)); ++ ++ return 0; ++} ++ ++ ++static int bt950_hci_open(struct hci_dev *hdev) ++{ ++ bt950_hci_set_baud_rate(hdev, baud_rate); ++ set_bit(HCI_RUNNING, &(hdev->flags)); ++ ++ return 0; ++} ++ ++ ++static int bt950_hci_close(struct hci_dev *hdev) ++{ ++ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) ++ return 0; ++ ++ bt950_hci_flush(hdev); ++ ++ return 0; ++} ++ ++ ++static int bt950_hci_send_frame(struct sk_buff *skb) ++{ ++ bt950_info_t *info; ++ struct hci_dev *hdev = (struct hci_dev *)(skb->dev); ++ ++ if (!hdev) { ++ printk(KERN_ERR "bt950_cs: Frame for unknown HCI device (hdev=NULL)."); ++ return -ENODEV; ++ } ++ ++ info = (bt950_info_t *)(hdev->driver_data); ++ ++ switch (skb->pkt_type) { ++ case HCI_COMMAND_PKT: ++ hdev->stat.cmd_tx++; ++ break; ++ case HCI_ACLDATA_PKT: ++ hdev->stat.acl_tx++; ++ break; ++ case HCI_SCODATA_PKT: ++ hdev->stat.sco_tx++; ++ break; ++ }; ++ ++ /* Prepend skb with frame type */ ++ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); ++ skb_queue_tail(&(info->txq), skb); ++ ++ bt950_write_wakeup(info); ++ ++ return 0; ++} ++ ++ ++static void bt950_hci_destruct(struct hci_dev *hdev) ++{ ++} ++ ++ ++static int bt950_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) ++{ ++ return -ENOIOCTLCMD; ++} ++ ++ ++ ++/* ======================== Card services HCI interaction ======================== */ ++ ++ ++static int bt950_setup_uart(bt950_info_t *info) ++{ ++ unsigned long flags; ++ unsigned int iobase = info->link.io.BasePort1; ++ unsigned char lcr, ier = UART_IER_RDI | UART_IER_RLSI | UART_IER_SLP; ++ unsigned int divisor = 8; /* Fixme: divisor == 0x0c ??? */ ++ unsigned char id1, id2, id3, rev; ++ register int i; ++ ++ spin_lock_irqsave(&(info->lock), flags); ++ ++ /* Disable interrupts */ ++ outb(0, iobase + UART_IER); ++ ++ /* Activate RTS and OUT2 */ ++ /* Fixme: is OUT2 used to enable interrupts? */ ++ outb(UART_MCR_RTS | UART_MCR_OUT2, iobase + UART_MCR); ++ ++ /* Setup the FIFO's */ ++ outb(0, iobase + UART_FCR); ++ inb(iobase + UART_RX); ++ outb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | ++ UART_FCR_CLEAR_XMIT | UART_FCR_TRIGGER_14, iobase + UART_FCR); ++ ++ /* Disable divisor latch access */ ++ lcr = inb(iobase + UART_LCR) & 0x3F; /* mask out UART_LCR_DLAB and UART_LCR_SBC */ ++ outb(lcr, iobase + UART_LCR); ++ ++ /* Read up to 4 bytes from RX FIFO */ ++ for (i = 0; i < 4; i++) { ++ inb(iobase + UART_RX); ++ if (!(inb(iobase + UART_LSR) & UART_LSR_DR)) ++ break; ++ } ++ ++ /* Wait if CTS/DSR/DCD changing */ ++ for (i = 1; i < 0x3E8; i++) { ++ if (!(inb(iobase + UART_MSR) & UART_MSR_ANY_DELTA)) ++ break; ++ } ++ ++ /* Enable divisor latch access */ ++ outb(lcr | UART_LCR_DLAB, iobase + UART_LCR); ++ ++ /* Setup divisor latch */ ++ outb(divisor & 0x00FF, iobase + UART_DLL); /* divisor latch LOW byte */ ++ outb((divisor & 0xFF00) >> 8, iobase + UART_DLM); /* divisor latch HIGH byte */ ++ ++ /* Disable divisor latch access */ ++ outb(lcr, iobase + UART_LCR); ++ ++ /* Setup interrupts, enable sleep mode */ ++ outb(ier, iobase + UART_IER); /* we don't want to handle TX interrupts */ ++ ++ /* Skip pending interrupts */ ++ for (i = 0; i < 4; i++) { ++ if (inb(iobase + UART_IIR) & UART_IIR_NO_INT) ++ break; ++ } ++ ++ /* 8N1 */ ++ lcr = UART_LCR_WLEN8; ++ outb(lcr, iobase + UART_LCR); ++ ++ /* Setup CTS/RTS flow control and 950 enhanced mode */ ++ outb(UART_LCR_650, iobase + UART_LCR); ++ outb(UART_EFR_CTS | UART_EFR_RTS | UART_EFR_ECB, ++ iobase + UART_EFR); ++ outb(lcr, iobase + UART_LCR); ++ ++ /* Read core id and revision */ ++ outb(UART_ACR, iobase + UART_EMSR); ++ outb(UART_ACR_ICRRD, iobase + UART_LSR); /* enable ICR read access, we don't need to save the old value of ACR */ ++ ++ outb(UART_ID1, iobase + UART_EMSR); ++ id1 = inb(iobase + UART_LSR); ++ ++ outb(UART_ID2, iobase + UART_EMSR); ++ id2 = inb(iobase + UART_LSR); ++ ++ outb(UART_ID3, iobase + UART_EMSR); ++ id3 = inb(iobase + UART_LSR); ++ ++ outb(UART_REV, iobase + UART_EMSR); ++ rev = inb(iobase + UART_LSR); ++ ++ if (id1 != 0x16 || id2 != 0xC9 || id3 != 0x50) { ++ printk(KERN_ERR "bt950_cs: Unknown UART core %02X%02X%02X found.\n", id1, id2, id3); ++ spin_unlock_irqrestore(&(info->lock), flags); ++ return -ENODEV; ++ } ++ ++ ++ /* Init ICR registers */ ++ outb(UART_TTL, iobase + UART_EMSR); ++ outb(TR_TX_INT, iobase + UART_LSR); /* TX interrupt trigger level (0-127) */ ++ ++ outb(UART_RTL, iobase + UART_EMSR); ++ outb(TR_RX_INT, iobase + UART_LSR); /* RX interrupt trigger level (1-127) */ ++ ++ outb(UART_FCL, iobase + UART_EMSR); ++ outb(TR_CTL_LO, iobase + UART_LSR); /* auto flow control LOWER trigger level (0-127) */ ++ ++ outb(UART_FCH, iobase + UART_EMSR); ++ outb(TR_CTL_HI, iobase + UART_LSR); /* auto flow control HIGH trigger level (1-127) */ ++ ++ outb(UART_ACR, iobase + UART_EMSR); ++ outb(UART_ACR_TLENB, iobase + UART_LSR); /* disable ICR read access, enable trigger levels */ ++ ++ spin_unlock_irqrestore(&(info->lock), flags); ++ ++ return 0; ++} ++ ++ ++static void bt950_stop_uart(bt950_info_t *info) ++{ ++ unsigned long flags; ++ unsigned int iobase = info->link.io.BasePort1; ++ ++ spin_lock_irqsave(&(info->lock), flags); ++ ++ /* Disable interrupts */ ++ outb(0, iobase + UART_IER); ++ ++ /* Set RTS and OUT2 low */ ++ outb(0, iobase + UART_MCR); ++ ++ spin_unlock_irqrestore(&(info->lock), flags); ++} ++ ++ ++static int bt950_open(bt950_info_t *info) ++{ ++ struct hci_dev *hdev; ++ int err; ++ ++ spin_lock_init(&(info->lock)); ++ ++ skb_queue_head_init(&(info->txq)); ++ ++ info->rx_state = RECV_WAIT_PACKET_TYPE; ++ info->rx_count = 0; ++ info->rx_skb = NULL; ++ ++ /* Setup hardware */ ++ if ((err = bt950_setup_uart(info)) < 0) ++ return err; ++ ++ /* Timeout before it is safe to send the first HCI packet */ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(HZ); ++ ++ ++ /* Initialize and register HCI device */ ++ ++ hdev = &(info->hdev); ++ ++ hdev->type = HCI_PCCARD; ++ hdev->driver_data = info; ++ ++ hdev->open = bt950_hci_open; ++ hdev->close = bt950_hci_close; ++ hdev->flush = bt950_hci_flush; ++ hdev->send = bt950_hci_send_frame; ++ hdev->destruct = bt950_hci_destruct; ++ hdev->ioctl = bt950_hci_ioctl; ++ ++ if (hci_register_dev(hdev) < 0) { ++ printk(KERN_ERR "bt950_cs: Can't register HCI device %s.\n", hdev->name); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++ ++static int bt950_close(bt950_info_t *info) ++{ ++ struct hci_dev *hdev = &(info->hdev); ++ ++ bt950_hci_close(hdev); ++ ++ /* Stop hardware */ ++ bt950_stop_uart(info); ++ ++ if (hci_unregister_dev(hdev) < 0) ++ printk(KERN_ERR "bt950_cs: Can't unregister HCI device %s.\n", hdev->name); ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Card services ======================== */ ++ ++ ++static void cs_error(client_handle_t handle, int func, int ret) ++{ ++ error_info_t err = { func, ret }; ++ ++ CardServices(ReportError, handle, &err); ++} ++ ++ ++static dev_link_t *bt950_attach(void) ++{ ++ bt950_info_t *info; ++ client_reg_t client_reg; ++ dev_link_t *link; ++ int i, ret; ++ ++ /* Create new info device */ ++ info = kmalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return NULL; ++ memset(info, 0, sizeof(*info)); ++ ++ link = &info->link; ++ link->priv = info; ++ ++ link->release.function = &bt950_release; ++ link->release.data = (u_long)link; ++ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; ++ link->io.NumPorts1 = 8; ++ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; ++ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; ++ ++ if (irq_list[0] == -1) ++ link->irq.IRQInfo2 = irq_mask; ++ else ++ for (i = 0; i < 4; i++) ++ link->irq.IRQInfo2 |= 1 << irq_list[i]; ++ ++ link->irq.Handler = bt950_interrupt; ++ link->irq.Instance = info; ++ ++ link->conf.Attributes = CONF_ENABLE_IRQ; ++ link->conf.IntType = INT_MEMORY_AND_IO; ++ link->conf.Present = ++ PRESENT_OPTION | PRESENT_STATUS | PRESENT_PIN_REPLACE | ++ PRESENT_COPY; ++ ++ /* Register with Card Services */ ++ link->next = dev_list; ++ dev_list = link; ++ client_reg.dev_info = &dev_info; ++ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; ++ client_reg.EventMask = ++ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | ++ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | ++ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; ++ client_reg.event_handler = &bt950_event; ++ client_reg.Version = 0x0210; ++ client_reg.event_callback_args.client_data = link; ++ ++ ret = CardServices(RegisterClient, &link->handle, &client_reg); ++ if (ret != CS_SUCCESS) { ++ cs_error(link->handle, RegisterClient, ret); ++ bt950_detach(link); ++ return NULL; ++ } ++ ++ return link; ++} ++ ++ ++static void bt950_detach(dev_link_t *link) ++{ ++ bt950_info_t *info = link->priv; ++ dev_link_t **linkp; ++ int ret; ++ ++ /* Locate device structure */ ++ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) ++ if (*linkp == link) ++ break; ++ ++ if (*linkp == NULL) ++ return; ++ ++ del_timer(&link->release); ++ if (link->state & DEV_CONFIG) ++ bt950_release((u_long) link); ++ ++ if (link->handle) { ++ ret = CardServices(DeregisterClient, link->handle); ++ if (ret != CS_SUCCESS) ++ cs_error(link->handle, DeregisterClient, ret); ++ } ++ ++ /* Unlink device structure, free bits */ ++ *linkp = link->next; ++ ++ kfree(info); ++} ++ ++ ++static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) ++{ ++ int i; ++ ++ i = CardServices(fn, handle, tuple); ++ if (i != CS_SUCCESS) ++ return CS_NO_MORE_ITEMS; ++ ++ i = CardServices(GetTupleData, handle, tuple); ++ if (i != CS_SUCCESS) ++ return i; ++ ++ return CardServices(ParseTuple, handle, tuple, parse); ++} ++ ++ ++#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) ++#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) ++ ++static void bt950_config(dev_link_t *link) ++{ ++ static ioaddr_t base[4] = { 0x2f8, 0x3e8, 0x2e8, 0x0 }; ++ client_handle_t handle = link->handle; ++ bt950_info_t *info = link->priv; ++ tuple_t tuple; ++ u_short buf[256]; ++ cisparse_t parse; ++ cistpl_cftable_entry_t *cf = &parse.cftable_entry; ++ config_info_t config; ++ int i, j, try, last_ret, last_fn; ++ ++ tuple.TupleData = (cisdata_t *)buf; ++ tuple.TupleOffset = 0; ++ tuple.TupleDataMax = 255; ++ tuple.Attributes = 0; ++ ++ /* Get configuration register information */ ++ tuple.DesiredTuple = CISTPL_CONFIG; ++ last_ret = first_tuple(handle, &tuple, &parse); ++ if (last_ret != CS_SUCCESS) { ++ last_fn = ParseTuple; ++ goto cs_failed; ++ } ++ link->conf.ConfigBase = parse.config.base; ++ link->conf.Present = parse.config.rmask[0]; ++ ++ /* Configure card */ ++ link->state |= DEV_CONFIG; ++ i = CardServices(GetConfigurationInfo, handle, &config); ++ link->conf.Vcc = config.Vcc; ++ ++ /* First pass: look for a config entry that looks normal. */ ++ tuple.TupleData = (cisdata_t *) buf; ++ tuple.TupleOffset = 0; ++ tuple.TupleDataMax = 255; ++ tuple.Attributes = 0; ++ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; ++ /* Two tries: without IO aliases, then with aliases */ ++ for (try = 0; try < 2; try++) { ++ i = first_tuple(handle, &tuple, &parse); ++ while (i != CS_NO_MORE_ITEMS) { ++ if (i != CS_SUCCESS) ++ goto next_entry; ++ if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) ++ link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; ++ if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) { ++ link->conf.ConfigIndex = cf->index; ++ link->io.BasePort1 = cf->io.win[0].base; ++ link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; ++ i = CardServices(RequestIO, link->handle, &link->io); ++ if (i == CS_SUCCESS) ++ goto found_port; ++ } ++next_entry: ++ i = next_tuple(handle, &tuple, &parse); ++ } ++ } ++ ++ /* Second pass: try to find an entry that isn't picky about ++ its base address, then try to grab any standard serial port ++ address, and finally try to get any free port. */ ++ i = first_tuple(handle, &tuple, &parse); ++ while (i != CS_NO_MORE_ITEMS) { ++ if ((i == CS_SUCCESS) && (cf->io.nwin > 0) ++ && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { ++ link->conf.ConfigIndex = cf->index; ++ for (j = 0; j < 5; j++) { ++ link->io.BasePort1 = base[j]; ++ link->io.IOAddrLines = base[j] ? 16 : 3; ++ i = CardServices(RequestIO, link->handle, &link->io); ++ if (i == CS_SUCCESS) ++ goto found_port; ++ } ++ } ++ i = next_tuple(handle, &tuple, &parse); ++ } ++ ++found_port: ++ if (i != CS_SUCCESS) { ++ printk(KERN_ERR "bt950_cs: No usable port range found. Giving up.\n"); ++ cs_error(link->handle, RequestIO, i); ++ goto failed; ++ } ++ ++ i = CardServices(RequestIRQ, link->handle, &link->irq); ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestIRQ, i); ++ link->irq.AssignedIRQ = 0; ++ } ++ ++ i = CardServices(RequestConfiguration, link->handle, &link->conf); ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestConfiguration, i); ++ goto failed; ++ } ++ ++ MOD_INC_USE_COUNT; ++ ++ if (bt950_open(info) != 0) ++ goto failed; ++ ++ strcpy(info->node.dev_name, info->hdev.name); ++ link->dev = &info->node; ++ link->state &= ~DEV_CONFIG_PENDING; ++ ++ return; ++ ++cs_failed: ++ cs_error(link->handle, last_fn, last_ret); ++ ++failed: ++ bt950_release((u_long)link); ++ link->state &= ~DEV_CONFIG_PENDING; ++} ++ ++ ++static void bt950_release(u_long arg) ++{ ++ dev_link_t *link = (dev_link_t *) arg; ++ bt950_info_t *info = link->priv; ++ ++ if (link->state & DEV_PRESENT) ++ bt950_close(info); ++ ++ MOD_DEC_USE_COUNT; ++ ++ link->dev = NULL; ++ ++ CardServices(ReleaseConfiguration, link->handle); ++ CardServices(ReleaseIO, link->handle, &link->io); ++ CardServices(ReleaseIRQ, link->handle, &link->irq); ++ ++ link->state &= ~DEV_CONFIG; ++} ++ ++ ++static int bt950_event(event_t event, int priority, event_callback_args_t *args) ++{ ++ dev_link_t *link = args->client_data; ++ bt950_info_t *info = link->priv; ++ ++ switch (event) { ++ case CS_EVENT_CARD_REMOVAL: ++ link->state &= ~DEV_PRESENT; ++ if (link->state & DEV_CONFIG) { ++ bt950_close(info); ++ link->state |= DEV_RELEASE_PENDING; ++ mod_timer(&link->release, jiffies + HZ / 20); ++ } ++ break; ++ case CS_EVENT_CARD_INSERTION: ++ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; ++ bt950_config(link); ++ break; ++ case CS_EVENT_PM_SUSPEND: ++ link->state |= DEV_SUSPEND; ++ /* Fall through... */ ++ case CS_EVENT_RESET_PHYSICAL: ++ if (link->state & DEV_CONFIG) { ++ bt950_stop_uart(info); ++ CardServices(ReleaseConfiguration, link->handle); ++ } ++ break; ++ case CS_EVENT_PM_RESUME: ++ link->state &= ~DEV_SUSPEND; ++ /* Fall through... */ ++ case CS_EVENT_CARD_RESET: ++ if (link->state & DEV_CONFIG) { ++ CardServices(RequestConfiguration, link->handle, &link->conf); ++ bt950_setup_uart(info); ++ } ++ break; ++ } ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Module initialization ======================== */ ++ ++ ++int __init init_bt950_cs(void) ++{ ++ servinfo_t serv; ++ int err; ++ ++ CardServices(GetCardServicesInfo, &serv); ++ if (serv.Revision != CS_RELEASE_CODE) { ++ printk(KERN_NOTICE "bt950_cs: Card Services release does not match!\n"); ++// return -1; ++ } ++ ++ err = register_pccard_driver(&dev_info, &bt950_attach, &bt950_detach); ++ ++ return err; ++} ++ ++ ++void __exit exit_bt950_cs(void) ++{ ++ unregister_pccard_driver(&dev_info); ++ ++ while (dev_list != NULL) ++ bt950_detach(dev_list); ++} ++ ++ ++module_init(init_bt950_cs); ++module_exit(exit_bt950_cs); ++ ++EXPORT_NO_SYMBOLS; +diff -Nur linux-orig/drivers/bluetooth/Config.in linux/drivers/bluetooth/Config.in +--- linux-orig/drivers/bluetooth/Config.in 2004-02-16 08:45:33.000000000 +0300 ++++ linux/drivers/bluetooth/Config.in 2004-02-16 08:50:36.000000000 +0300 +@@ -21,7 +21,7 @@ + + dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ + +-dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BLUEZ_HCIBT3C $CONFIG_PCMCIA $CONFIG_BLUEZ ++# dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BLUEZ_HCIBT3C $CONFIG_PCMCIA $CONFIG_BLUEZ + + dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ + +@@ -29,5 +29,7 @@ + + dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ + ++dep_tristate 'HCI BT950 (BT950 device) driver' CONFIG_BLUEZ_BT950 $CONFIG_BLUEZ ++ + endmenu + +diff -Nur linux-orig/drivers/bluetooth/Makefile linux/drivers/bluetooth/Makefile +--- linux-orig/drivers/bluetooth/Makefile 2004-02-16 08:45:33.000000000 +0300 ++++ linux/drivers/bluetooth/Makefile 2004-02-16 08:50:47.000000000 +0300 +@@ -17,10 +17,12 @@ + obj-$(CONFIG_BLUEZ_HCIBFUSB) += bfusb.o + + obj-$(CONFIG_BLUEZ_HCIDTL1) += dtl1_cs.o +-obj-$(CONFIG_BLUEZ_HCIBT3C) += bt3c_cs.o ++# obj-$(CONFIG_BLUEZ_HCIBT3C) += bt3c_cs.o + obj-$(CONFIG_BLUEZ_HCIBLUECARD) += bluecard_cs.o + obj-$(CONFIG_BLUEZ_HCIBTUART) += btuart_cs.o + ++obj-$(CONFIG_BLUEZ_BT950) += bt950_cs.o ++ + include $(TOPDIR)/Rules.make + + hci_uart.o: $(uart-y) diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/buffered-fbmem.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/buffered-fbmem.patch index e69de29bb2..554f118936 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/buffered-fbmem.patch +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/buffered-fbmem.patch @@ -0,0 +1,19 @@ + +# +# Made by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux/drivers/video/fbmem.c~buffered-fbmem 2003-09-16 00:48:18.000000000 +0200 ++++ linux/drivers/video/fbmem.c 2003-09-19 00:38:00.000000000 +0200 +@@ -650,7 +650,11 @@ + pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; + pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED; + #elif defined(__arm__) ++#ifdef CONFIG_PXA ++ vma->vm_page_prot = pgprot_noncached_buffered(vma->vm_page_prot); ++#else + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++#endif + #ifdef CONFIG_POODLE_CONSISTENT_ALLOC + vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | L_PTE_CACHEABLE); + #endif diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/compile.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/compile.patch index e69de29bb2..1a19b85daa 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/compile.patch +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/compile.patch @@ -0,0 +1,14 @@ +--- linux/include/linux/jffs2_fs_i.h.old 2003-02-01 00:24:48.000000000 -0600 ++++ linux/include/linux/jffs2_fs_i.h 2003-02-01 00:25:14.000000000 -0600 +@@ -48,9 +48,11 @@ + uint32_t nr_frags; + #endif + ++#ifdef KERNEL_VERSION + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2) + struct inode vfs_inode; + #endif ++#endif + }; + + #endif /* _JFFS2_FS_I */ diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/deviceinfo.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/deviceinfo.patch index e69de29bb2..58343c5b55 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/deviceinfo.patch +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/deviceinfo.patch @@ -0,0 +1,26 @@ +--- linux/arch/arm/mach-pxa/Makefile.old 2004-09-24 20:49:09.000000000 +0930 ++++ linux/arch/arm/mach-pxa/Makefile 2004-09-24 20:49:11.000000000 +0930 +@@ -94,6 +94,23 @@ + endif + endif + ++ifeq ($(CONFIG_DEVICEINFO),m) ++ obj-$(CONFIG_DEVICEINFO) += devinfo.o ++ ifeq ($(CONFIG_SABINAL_DISCOVERY),y) ++ devinfo-objs-m += deviceinfo.o ++ devinfo-objs-$(CONFIG_DISCOVERY_DEVICEINFO) += discovery_deviceinfo.o ++ endif ++ ifeq ($(CONFIG_ARCH_PXA_POODLE),y) ++ devinfo-objs-m += sharpsl_deviceinfo.o ++ endif ++ ifeq ($(CONFIG_ARCH_PXA_CORGI),y) ++ devinfo-objs-m += sharpsl_deviceinfo.o ++ endif ++ ifeq ($(CONFIG_ARCH_PXA_TOSA),y) ++ devinfo-objs-m += sharpsl_deviceinfo.o ++ endif ++endif ++ + obj-m += registers.o + + include $(TOPDIR)/Rules.make diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/disable-pcmcia-probe.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/disable-pcmcia-probe.patch index e69de29bb2..79ba036323 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/disable-pcmcia-probe.patch +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/disable-pcmcia-probe.patch @@ -0,0 +1,17 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux/drivers/pcmcia/Config.in~disable-pcmcia-probe 2003-05-13 11:18:23.000000000 +0200 ++++ linux/drivers/pcmcia/Config.in 2004-05-27 13:59:50.000000000 +0200 +@@ -15,9 +15,6 @@ + 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 diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/enable-sysrq.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/enable-sysrq.patch index e69de29bb2..ece8fd9a5d 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/enable-sysrq.patch +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/enable-sysrq.patch @@ -0,0 +1,45 @@ +--- linux/drivers/char/corgi_keyb.c~enable-sysrq 2003-09-05 01:18:15.000000000 +0200 ++++ linux/drivers/char/corgi_keyb.c 2003-09-05 01:40:17.000000000 +0200 +@@ -23,7 +23,7 @@ + #include <linux/init.h> + #include <linux/poll.h> + #include <linux/wait.h> +-#include <asm/arch/keyboard.h> ++#include <asm/keyboard.h> + #include <asm/uaccess.h> + #include <linux/tqueue.h> + #include <linux/kbd_ll.h> +@@ -46,6 +46,18 @@ + #endif + + /* ++ * This is the KeyCode [not ScanCode!] to ASCII Code mapping table ++ */ ++ ++#ifdef CONFIG_MAGIC_SYSRQ ++static unsigned char corgi_sysrq_xlate[128] = ++ "\000abcdefghijklmno" /* 00-0f */ ++ "pqrstuvwxyz\000\000\000\000\000" /* 10-1f */ ++ " \000\000\000\000\000\000\000\0001234567" /* 20-2f */ ++ "890\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 30-3f */ ++#endif ++ ++/* + * common logical driver definition + */ + extern void sharppda_kbd_press(int keycode); +@@ -251,7 +263,13 @@ + corgi_wakeup_button_init(); + #endif // USE_WAKEUP_BUTTON + +- printk("keyboard initilaized.\n"); ++ printk("keyboard initialized.\n"); ++#ifdef CONFIG_MAGIC_SYSRQ ++ k_sysrq_key = 0x28; // KEY_HOME ++ k_sysrq_xlate = corgi_sysrq_xlate; ++ printk("magic_sysrq initialized.\n"); ++#endif ++ + } + + int corgi_kbd_translate(unsigned char scancode, unsigned char *keycode_p) diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/idecs.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/idecs.patch index e69de29bb2..62038c34e2 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/idecs.patch +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/idecs.patch @@ -0,0 +1,77 @@ +--- linux/drivers/ide/ide-cs.c 2003-02-28 17:04:00.000000000 -0600 ++++ linux.new/drivers/ide/ide-cs.c 2003-02-28 17:18:53.000000000 -0600 +@@ -2,7 +2,7 @@ + + A driver for PCMCIA IDE/ATA disk cards + +- ide_cs.c 1.26 1999/11/16 02:10:49 ++ ide-cs.c 1.26 1999/11/16 02:10:49 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file +@@ -66,7 +66,7 @@ + MODULE_PARM(pc_debug, "i"); + #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) + static char *version = +-"ide_cs.c 1.26 1999/11/16 02:10:49 (David Hinds)"; ++"ide-cs.c 1.26 1999/11/16 02:10:49 (David Hinds)"; + #else + #define DEBUG(n, args...) + #endif +@@ -110,7 +110,7 @@ + static int ide_event(event_t event, int priority, + event_callback_args_t *args); + +-static dev_info_t dev_info = "ide_cs"; ++static dev_info_t dev_info = "ide-cs"; + + static dev_link_t *ide_attach(void); + static void ide_detach(dev_link_t *); +@@ -356,7 +356,7 @@ + } + + if (hd < 0) { +- printk(KERN_NOTICE "ide_cs: ide_register() at 0x%03x & 0x%03x" ++ printk(KERN_NOTICE "ide-cs: ide_register() at 0x%03x & 0x%03x" + ", irq %u failed\n", io_base, ctl_base, + link->irq.AssignedIRQ); + goto failed; +@@ -369,7 +369,7 @@ + info->node.minor = 0; + info->hd = hd; + link->dev = &info->node; +- printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n", ++ printk(KERN_INFO "ide-cs: %s: Vcc = %d.%d, Vpp = %d.%d\n", + info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10, + link->conf.Vpp1/10, link->conf.Vpp1%10); + +@@ -409,9 +409,9 @@ + MOD_DEC_USE_COUNT; + } + +- request_region(link->io.BasePort1, link->io.NumPorts1,"ide_cs"); ++ request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs"); + if (link->io.NumPorts2) +- request_region(link->io.BasePort2, link->io.NumPorts2,"ide_cs"); ++ request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs"); + + info->ndev = 0; + link->dev = NULL; +@@ -508,7 +508,7 @@ + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { +- printk(KERN_NOTICE "ide_cs: Card Services release " ++ printk(KERN_NOTICE "ide-cs: Card Services release " + "does not match!\n"); + return -1; + } +@@ -518,7 +518,7 @@ + + static void __exit exit_ide_cs(void) + { +- DEBUG(0, "ide_cs: unloading\n"); ++ DEBUG(0, "ide-cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + ide_detach(dev_list); diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/initsh.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/initsh.patch index e69de29bb2..a672631194 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/initsh.patch +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/initsh.patch @@ -0,0 +1,14 @@ +--- linux/init/main.c 2002-02-25 13:38:13.000000000 -0600 ++++ linux.new/init/main.c 2003-03-16 11:49:45.000000000 -0600 +@@ -830,8 +830,10 @@ + * trying to recover a really broken machine. + */ + +- if (execute_command) ++ if (execute_command) { ++ argv_init[0] = execute_command; + execve(execute_command,argv_init,envp_init); ++ } + execve("/sbin/init",argv_init,envp_init); + execve("/etc/init",argv_init,envp_init); + execve("/bin/init",argv_init,envp_init); diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/irda-qos.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/irda-qos.patch index e69de29bb2..559f4ad564 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/irda-qos.patch +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/irda-qos.patch @@ -0,0 +1,108 @@ +diff -urN linux.orig/net/irda/irsysctl.c linux/net/irda/irsysctl.c +--- linux.orig/net/irda/irsysctl.c Fri Feb 27 18:28:04 2004 ++++ linux/net/irda/irsysctl.c Wed Jan 14 19:36:40 2004 +@@ -40,7 +40,8 @@ + + enum { DISCOVERY=1, DEVNAME, DEBUG, FAST_POLL, DISCOVERY_SLOTS, + DISCOVERY_TIMEOUT, SLOT_TIMEOUT, MAX_BAUD_RATE, MIN_TX_TURN_TIME, +- MAX_NOREPLY_TIME, WARN_NOREPLY_TIME, LAP_KEEPALIVE_TIME, SPECIFIC_DEV }; ++ MAX_TX_WINDOW, MAX_NOREPLY_TIME, WARN_NOREPLY_TIME, ++ LAP_KEEPALIVE_TIME, SPECIFIC_DEV }; + + extern int sysctl_discovery; + extern int sysctl_discovery_slots; +@@ -51,6 +52,7 @@ + extern char sysctl_devname[]; + extern int sysctl_max_baud_rate; + extern int sysctl_min_tx_turn_time; ++extern int sysctl_max_tx_window; + extern int sysctl_max_noreply_time; + extern int sysctl_warn_noreply_time; + extern int sysctl_lap_keepalive_time; +@@ -71,6 +73,8 @@ + static int min_max_baud_rate = 2400; + static int max_min_tx_turn_time = 10000; /* See qos.c - IrLAP spec */ + static int min_min_tx_turn_time = 0; ++static int max_max_tx_window=7; ++static int min_max_tx_window=1; + static int max_max_noreply_time = 40; /* See qos.c - IrLAP spec */ + static int min_max_noreply_time = 3; + static int max_warn_noreply_time = 3; /* 3s == standard */ +@@ -128,6 +132,9 @@ + { MIN_TX_TURN_TIME, "min_tx_turn_time", &sysctl_min_tx_turn_time, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, + NULL, &min_min_tx_turn_time, &max_min_tx_turn_time }, ++ { MAX_TX_WINDOW, "max_tx_window", &sysctl_max_tx_window, ++ sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, ++ NULL, &min_max_tx_window, &max_max_tx_window }, + { MAX_NOREPLY_TIME, "max_noreply_time", &sysctl_max_noreply_time, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, + NULL, &min_max_noreply_time, &max_max_noreply_time }, +diff -urN linux.orig/net/irda/parameters.c linux/net/irda/parameters.c +--- linux.orig/net/irda/parameters.c Sat Nov 10 01:22:17 2001 ++++ linux/net/irda/parameters.c Wed Jan 14 19:34:23 2004 +@@ -204,12 +204,14 @@ + { + irda_param_t p; + int n = 0; ++ int extract_len; + int err; + + p.pi = pi; /* In case handler needs to know */ + p.pl = buf[1]; /* Extract lenght of value */ + p.pv.i = 0; /* Clear value */ +- ++ extract_len = p.pl; ++ + /* Check if buffer is long enough for parsing */ + if (len < (2+p.pl)) { + WARNING(__FUNCTION__ "(), buffer to short for parsing! " +@@ -226,12 +228,15 @@ + "Expected %d bytes, but value had %d bytes!\n", + type & PV_MASK, p.pl); + +- /* Skip parameter */ ++ if((p.pl < (type & PV_MASK)) || (type & PV_BIG_ENDIAN)) { + return p.pl+2; ++ } else { ++ extract_len = type & PV_MASK; ++ } + } + + +- switch (p.pl) { ++ switch (extract_len) { + case 1: + n += irda_param_unpack(buf+2, "b", &p.pv.i); + break; +diff -urN linux.orig/net/irda/qos.c linux/net/irda/qos.c +--- linux.orig/net/irda/qos.c Fri Feb 27 18:28:04 2004 ++++ linux/net/irda/qos.c Wed Jan 14 18:18:20 2004 +@@ -65,6 +65,7 @@ + */ + unsigned sysctl_min_tx_turn_time = 10; + ++unsigned sysctl_max_tx_window = 7; + /* + * Specific device list limits some negotiation parameters at the connection + * with listed peer devices. +@@ -212,6 +213,9 @@ + __u16 msb = 0x8000; + int index = 15; /* Current MSB */ + ++ if(!word) ++ word=0x1; ++ + while (msb) { + if (word & msb) + break; /* Found it! */ +@@ -386,6 +390,9 @@ + qos->max_turn_time.value = 500; + } + ++ if(qos->window_size.value > sysctl_max_tx_window) ++ qos->window_size.value = sysctl_max_tx_window; ++ + /* + * The data size must be adjusted according to the baud rate and max + * turn time diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw240_we15-6.diff b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw240_we15-6.diff index e69de29bb2..2ebfd8ec12 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw240_we15-6.diff +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw240_we15-6.diff @@ -0,0 +1,399 @@ +diff -u -p linux/include/linux/wireless.14.h linux/include/linux/wireless.h +--- linux/include/linux/wireless.14.h Mon Dec 2 18:51:00 2002 ++++ linux/include/linux/wireless.h Mon Dec 2 18:53:35 2002 +@@ -1,7 +1,7 @@ + /* + * This file define a set of standard wireless extensions + * +- * Version : 14 25.1.02 ++ * Version : 15 12.7.02 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> + * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. +@@ -80,7 +80,7 @@ + * (there is some stuff that will be added in the future...) + * I just plan to increment with each new version. + */ +-#define WIRELESS_EXT 14 ++#define WIRELESS_EXT 15 + + /* + * Changes : +@@ -153,17 +153,32 @@ + * - Define additional specific event numbers + * - Add "addr" and "param" fields in union iwreq_data + * - AP scanning stuff (SIOCSIWSCAN and friends) ++ * ++ * V14 to V15 ++ * ---------- ++ * - Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg ++ * - Make struct iw_freq signed (both m & e), add explicit padding ++ * - Add IWEVCUSTOM for driver specific event/scanning token ++ * - Add IW_MAX_GET_SPY for driver returning a lot of addresses ++ * - Add IW_TXPOW_RANGE for range of Tx Powers ++ * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points ++ * - Add IW_MODE_MONITOR for passive monitor + */ + + /**************************** CONSTANTS ****************************/ + + /* -------------------------- IOCTL LIST -------------------------- */ + +-/* Basic operations */ ++/* Wireless Identification */ + #define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */ + #define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ +-#define SIOCSIWNWID 0x8B02 /* set network id (the cell) */ +-#define SIOCGIWNWID 0x8B03 /* get network id */ ++/* SIOCGIWNAME is used to verify the presence of Wireless Extensions. ++ * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"... ++ * Don't put the name of your driver there, it's useless. */ ++ ++/* Basic operations */ ++#define SIOCSIWNWID 0x8B02 /* set network id (pre-802.11) */ ++#define SIOCGIWNWID 0x8B03 /* get network id (the cell) */ + #define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */ + #define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */ + #define SIOCSIWMODE 0x8B06 /* set operation mode */ +@@ -178,16 +193,18 @@ + #define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */ + #define SIOCSIWSTATS 0x8B0E /* Unused */ + #define SIOCGIWSTATS 0x8B0F /* Get /proc/net/wireless stats */ ++/* SIOCGIWSTATS is strictly used between user space and the kernel, and ++ * is never passed to the driver (i.e. the driver will never see it). */ + +-/* Mobile IP support */ ++/* Mobile IP support (statistics per MAC address) */ + #define SIOCSIWSPY 0x8B10 /* set spy addresses */ + #define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */ + + /* Access Point manipulation */ + #define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ + #define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ +-#define SIOCGIWAPLIST 0x8B17 /* get list of access point in range */ +-#define SIOCSIWSCAN 0x8B18 /* trigger scanning */ ++#define SIOCGIWAPLIST 0x8B17 /* Deprecated in favor of scanning */ ++#define SIOCSIWSCAN 0x8B18 /* trigger scanning (list cells) */ + #define SIOCGIWSCAN 0x8B19 /* get scanning results */ + + /* 802.11 specific support */ +@@ -197,9 +214,7 @@ + #define SIOCGIWNICKN 0x8B1D /* get node name/nickname */ + /* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit + * within the 'iwreq' structure, so we need to use the 'data' member to +- * point to a string in user space, like it is done for RANGE... +- * The "flags" member indicate if the ESSID is active or not (promiscuous). +- */ ++ * point to a string in user space, like it is done for RANGE... */ + + /* Other parameters useful in 802.11 and some other devices */ + #define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */ +@@ -257,7 +272,10 @@ + /* Most events use the same identifier as ioctl requests */ + + #define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ +-#define IWEVQUAL 0x8C01 /* Quality part of statistics */ ++#define IWEVQUAL 0x8C01 /* Quality part of statistics (scan) */ ++#define IWEVCUSTOM 0x8C02 /* Driver specific ascii string */ ++#define IWEVREGISTERED 0x8C03 /* Discovered a new node (AP mode) */ ++#define IWEVEXPIRED 0x8C04 /* Expired a node (AP mode) */ + + #define IWEVFIRST 0x8C00 + +@@ -273,7 +291,8 @@ + #define IW_PRIV_TYPE_BYTE 0x1000 /* Char as number */ + #define IW_PRIV_TYPE_CHAR 0x2000 /* Char as character */ + #define IW_PRIV_TYPE_INT 0x4000 /* 32 bits int */ +-#define IW_PRIV_TYPE_FLOAT 0x5000 ++#define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */ ++#define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */ + + #define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed nuber of args */ + +@@ -297,13 +316,16 @@ + + /* Maximum tx powers in the range struct */ + #define IW_MAX_TXPOWER 8 ++/* Note : if you more than 8 TXPowers, just set the max and min or ++ * a few of them in the struct iw_range. */ + + /* Maximum of address that you may set with SPY */ +-#define IW_MAX_SPY 8 ++#define IW_MAX_SPY 8 /* set */ ++#define IW_MAX_GET_SPY 64 /* get */ + + /* Maximum of address that you may get in the + list of access points in range */ +-#define IW_MAX_AP 8 ++#define IW_MAX_AP 64 + + /* Maximum size of the ESSID and NICKN strings */ + #define IW_ESSID_MAX_SIZE 32 +@@ -315,6 +337,7 @@ + #define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */ + #define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */ + #define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ ++#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */ + + /* Maximum number of size of encoding token available + * they are listed in the range structure */ +@@ -350,8 +373,10 @@ + #define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ + + /* Transmit Power flags available */ ++#define IW_TXPOW_TYPE 0x00FF /* Type of value */ + #define IW_TXPOW_DBM 0x0000 /* Value is in dBm */ + #define IW_TXPOW_MWATT 0x0001 /* Value is in mW */ ++#define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */ + + /* Retry limits and lifetime flags available */ + #define IW_RETRY_ON 0x0000 /* No details... */ +@@ -376,6 +401,9 @@ + /* Maximum size of returned data */ + #define IW_SCAN_MAX_DATA 4096 /* In bytes */ + ++/* Max number of char in custom event - use multiple of them if needed */ ++#define IW_CUSTOM_MAX 256 /* In bytes */ ++ + /****************************** TYPES ******************************/ + + /* --------------------------- SUBTYPES --------------------------- */ +@@ -411,9 +439,10 @@ struct iw_point + */ + struct iw_freq + { +- __u32 m; /* Mantissa */ +- __u16 e; /* Exponent */ ++ __s32 m; /* Mantissa */ ++ __s16 e; /* Exponent */ + __u8 i; /* List index (when in range struct) */ ++ __u8 pad; /* Unused - just for alignement */ + }; + + /* +diff -u -p linux/include/net/iw_handler.14.h linux/include/net/iw_handler.h +--- linux/include/net/iw_handler.14.h Mon Dec 2 18:51:17 2002 ++++ linux/include/net/iw_handler.h Mon Dec 2 18:54:51 2002 +@@ -1,7 +1,7 @@ + /* + * This file define the new driver API for Wireless Extensions + * +- * Version : 3 17.1.02 ++ * Version : 4 21.6.02 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> + * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved. +@@ -206,7 +206,7 @@ + * will be needed... + * I just plan to increment with each new version. + */ +-#define IW_HANDLER_VERSION 3 ++#define IW_HANDLER_VERSION 4 + + /* + * Changes : +@@ -217,6 +217,9 @@ + * - Add Wireless Event support : + * o wireless_send_event() prototype + * o iwe_stream_add_event/point() inline functions ++ * V3 to V4 ++ * -------- ++ * - Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes + */ + + /**************************** CONSTANTS ****************************/ +@@ -233,10 +236,10 @@ + #define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */ + #define IW_HEADER_TYPE_UINT 4 /* __u32 */ + #define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */ +-#define IW_HEADER_TYPE_POINT 6 /* struct iw_point */ +-#define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */ +-#define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */ +-#define IW_HEADER_TYPE_QUAL 9 /* struct iw_quality */ ++#define IW_HEADER_TYPE_ADDR 6 /* struct sockaddr */ ++#define IW_HEADER_TYPE_POINT 8 /* struct iw_point */ ++#define IW_HEADER_TYPE_PARAM 9 /* struct iw_param */ ++#define IW_HEADER_TYPE_QUAL 10 /* struct iw_quality */ + + /* Handling flags */ + /* Most are not implemented. I just use them as a reminder of some +diff -u -p linux/net/core/wireless.14.c linux/net/core/wireless.c +--- linux/net/core/wireless.14.c Mon Dec 2 18:51:35 2002 ++++ linux/net/core/wireless.c Mon Dec 2 18:53:10 2002 +@@ -33,8 +33,16 @@ + * o Propagate events as rtnetlink IFLA_WIRELESS option + * o Generate event on selected SET requests + * +- * v4 - 18.04.01 - Jean II ++ * v4 - 18.04.02 - Jean II + * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1 ++ * ++ * v5 - 21.06.02 - Jean II ++ * o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup) ++ * o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes ++ * o Add IWEVCUSTOM for driver specific event/scanning token ++ * o Turn on WE_STRICT_WRITE by default + kernel warning ++ * o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num) ++ * o Fix off-by-one in test (extra_size <= IFNAMSIZ) + */ + + /***************************** INCLUDES *****************************/ +@@ -50,8 +58,9 @@ + + /**************************** CONSTANTS ****************************/ + +-/* This will be turned on later on... */ +-#undef WE_STRICT_WRITE /* Check write buffer size */ ++/* Enough lenience, let's make sure things are proper... */ ++#define WE_STRICT_WRITE /* Check write buffer size */ ++/* I'll probably drop both the define and kernel message in the next version */ + + /* Debuging stuff */ + #undef WE_IOCTL_DEBUG /* Debug IOCTL API */ +@@ -106,7 +115,7 @@ static const struct iw_ioctl_description + /* SIOCSIWSPY */ + { IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0}, + /* SIOCGIWSPY */ +- { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0}, ++ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_GET_SPY, 0}, + /* -- hole -- */ + { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, + /* -- hole -- */ +@@ -176,25 +185,41 @@ static const struct iw_ioctl_description + { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, + /* IWEVQUAL */ + { IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0}, ++ /* IWEVCUSTOM */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_CUSTOM_MAX, 0}, ++ /* IWEVREGISTERED */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, ++ /* IWEVEXPIRED */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, + }; + static const int standard_event_num = (sizeof(standard_event) / + sizeof(struct iw_ioctl_description)); + + /* Size (in bytes) of the various private data types */ +-static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; ++static const char priv_type_size[] = { ++ 0, /* IW_PRIV_TYPE_NONE */ ++ 1, /* IW_PRIV_TYPE_BYTE */ ++ 1, /* IW_PRIV_TYPE_CHAR */ ++ 0, /* Not defined */ ++ sizeof(__u32), /* IW_PRIV_TYPE_INT */ ++ sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */ ++ sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */ ++ 0, /* Not defined */ ++}; + + /* Size (in bytes) of various events */ + static const int event_type_size[] = { +- IW_EV_LCP_LEN, ++ IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */ ++ 0, ++ IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ + 0, +- IW_EV_CHAR_LEN, ++ IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */ ++ IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ ++ IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ + 0, +- IW_EV_UINT_LEN, +- IW_EV_FREQ_LEN, + IW_EV_POINT_LEN, /* Without variable payload */ +- IW_EV_PARAM_LEN, +- IW_EV_ADDR_LEN, +- IW_EV_QUAL_LEN, ++ IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ ++ IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ + }; + + /************************ COMMON SUBROUTINES ************************/ +@@ -440,8 +465,10 @@ static inline int ioctl_export_private(s + return -EFAULT; + #ifdef WE_STRICT_WRITE + /* Check if there is enough buffer up there */ +- if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1)) ++ if(iwr->u.data.length < dev->wireless_handlers->num_private_args) { ++ printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args); + return -E2BIG; ++ } + #endif /* WE_STRICT_WRITE */ + + /* Set the number of available ioctls. */ +@@ -471,6 +498,7 @@ static inline int ioctl_standard_call(st + const struct iw_ioctl_description * descr; + struct iw_request_info info; + int ret = -EINVAL; ++ int user_size = 0; + + /* Get the description of the IOCTL */ + if((cmd - SIOCIWFIRST) >= standard_ioctl_num) +@@ -518,11 +546,8 @@ static inline int ioctl_standard_call(st + /* Check NULL pointer */ + if(iwr->u.data.pointer == NULL) + return -EFAULT; +-#ifdef WE_STRICT_WRITE +- /* Check if there is enough buffer up there */ +- if(iwr->u.data.length < descr->max_tokens) +- return -E2BIG; +-#endif /* WE_STRICT_WRITE */ ++ /* Save user space buffer size for checking */ ++ user_size = iwr->u.data.length; + } + + #ifdef WE_IOCTL_DEBUG +@@ -559,6 +584,15 @@ static inline int ioctl_standard_call(st + + /* If we have something to return to the user */ + if (!ret && IW_IS_GET(cmd)) { ++#ifdef WE_STRICT_WRITE ++ /* Check if there is enough buffer up there */ ++ if(user_size < iwr->u.data.length) { ++ printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length); ++ kfree(extra); ++ return -E2BIG; ++ } ++#endif /* WE_STRICT_WRITE */ ++ + err = copy_to_user(iwr->u.data.pointer, extra, + iwr->u.data.length * + descr->token_size); +@@ -646,12 +680,18 @@ static inline int ioctl_private_call(str + /* Compute the size of the set/get arguments */ + if(descr != NULL) { + if(IW_IS_SET(cmd)) { ++ int offset = 0; /* For sub-ioctls */ ++ /* Check for sub-ioctl handler */ ++ if(descr->name[0] == '\0') ++ /* Reserve one int for sub-ioctl index */ ++ offset = sizeof(__u32); ++ + /* Size of set arguments */ + extra_size = get_priv_size(descr->set_args); + + /* Does it fits in iwr ? */ + if((descr->set_args & IW_PRIV_SIZE_FIXED) && +- (extra_size < IFNAMSIZ)) ++ ((extra_size + offset) <= IFNAMSIZ)) + extra_size = 0; + } else { + /* Size of set arguments */ +@@ -659,7 +699,7 @@ static inline int ioctl_private_call(str + + /* Does it fits in iwr ? */ + if((descr->get_args & IW_PRIV_SIZE_FIXED) && +- (extra_size < IFNAMSIZ)) ++ (extra_size <= IFNAMSIZ)) + extra_size = 0; + } + } +@@ -925,7 +965,7 @@ void wireless_send_event(struct net_devi + * The best the driver could do is to log an error message. + * We will do it ourselves instead... + */ +- printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n", ++ printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n", + dev->name, cmd); + return; + } diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w13-5.diff b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w13-5.diff index e69de29bb2..a27a7654a9 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w13-5.diff +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w13-5.diff @@ -0,0 +1,1513 @@ +diff -u -p -r --new-file linux/include/linux-w12/netdevice.h linux/include/linux/netdevice.h +--- linux/include/linux-w12/netdevice.h Thu Nov 22 11:47:09 2001 ++++ linux/include/linux/netdevice.h Thu Jan 17 12:00:39 2002 +@@ -278,6 +278,10 @@ struct net_device + struct net_device_stats* (*get_stats)(struct net_device *dev); + struct iw_statistics* (*get_wireless_stats)(struct net_device *dev); + ++ /* List of functions to handle Wireless Extensions (instead of ioctl). ++ * See <net/iw_handler.h> for details. Jean II */ ++ struct iw_handler_def * wireless_handlers; ++ + /* + * This marks the end of the "visible" part of the structure. All + * fields hereafter are internal to the system, and may change at +diff -u -p -r --new-file linux/include/linux-w12/wireless.h linux/include/linux/wireless.h +--- linux/include/linux-w12/wireless.h Thu Nov 22 11:47:12 2001 ++++ linux/include/linux/wireless.h Thu Jan 17 12:04:08 2002 +@@ -1,9 +1,10 @@ + /* + * This file define a set of standard wireless extensions + * +- * Version : 12 5.10.01 ++ * Version : 13 6.12.01 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> ++ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. + */ + + #ifndef _LINUX_WIRELESS_H +@@ -11,6 +12,8 @@ + + /************************** DOCUMENTATION **************************/ + /* ++ * Initial APIs (1996 -> onward) : ++ * ----------------------------- + * Basically, the wireless extensions are for now a set of standard ioctl + * call + /proc/net/wireless + * +@@ -27,16 +30,27 @@ + * We have the list of command plus a structure descibing the + * data exchanged... + * Note that to add these ioctl, I was obliged to modify : +- * net/core/dev.c (two place + add include) +- * net/ipv4/af_inet.c (one place + add include) ++ * # net/core/dev.c (two place + add include) ++ * # net/ipv4/af_inet.c (one place + add include) + * + * /proc/net/wireless is a copy of /proc/net/dev. + * We have a structure for data passed from the driver to /proc/net/wireless + * Too add this, I've modified : +- * net/core/dev.c (two other places) +- * include/linux/netdevice.h (one place) +- * include/linux/proc_fs.h (one place) ++ * # net/core/dev.c (two other places) ++ * # include/linux/netdevice.h (one place) ++ * # include/linux/proc_fs.h (one place) ++ * ++ * New driver API (2001 -> onward) : ++ * ------------------------------- ++ * This file is only concerned with the user space API and common definitions. ++ * The new driver API is defined and documented in : ++ * # include/net/iw_handler.h + * ++ * Note as well that /proc/net/wireless implementation has now moved in : ++ * # include/linux/wireless.c ++ * ++ * Other comments : ++ * -------------- + * Do not add here things that are redundant with other mechanisms + * (drivers init, ifconfig, /proc/net/dev, ...) and with are not + * wireless specific. +@@ -54,16 +68,14 @@ + #include <linux/socket.h> /* for "struct sockaddr" et al */ + #include <linux/if.h> /* for IFNAMSIZ and co... */ + +-/**************************** CONSTANTS ****************************/ +- +-/* --------------------------- VERSION --------------------------- */ ++/***************************** VERSION *****************************/ + /* + * This constant is used to know the availability of the wireless + * extensions and to know which version of wireless extensions it is + * (there is some stuff that will be added in the future...) + * I just plan to increment with each new version. + */ +-#define WIRELESS_EXT 12 ++#define WIRELESS_EXT 13 + + /* + * Changes : +@@ -123,12 +135,20 @@ + * - Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space + * - Add new statistics (frag, retry, beacon) + * - Add average quality (for user space calibration) ++ * ++ * V12 to V13 ++ * ---------- ++ * - Document creation of new driver API. ++ * - Extract union iwreq_data from struct iwreq (for new driver API). ++ * - Rename SIOCSIWNAME as SIOCSIWCOMMIT + */ + ++/**************************** CONSTANTS ****************************/ ++ + /* -------------------------- IOCTL LIST -------------------------- */ + + /* Basic operations */ +-#define SIOCSIWNAME 0x8B00 /* Unused */ ++#define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */ + #define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ + #define SIOCSIWNWID 0x8B02 /* set network id (the cell) */ + #define SIOCGIWNWID 0x8B03 /* get network id */ +@@ -414,13 +434,49 @@ struct iw_statistics + + /* ------------------------ IOCTL REQUEST ------------------------ */ + /* ++ * This structure defines the payload of an ioctl, and is used ++ * below. ++ * ++ * Note that this structure should fit on the memory footprint ++ * of iwreq (which is the same as ifreq), which mean a max size of ++ * 16 octets = 128 bits. Warning, pointers might be 64 bits wide... ++ * You should check this when increasing the structures defined ++ * above in this file... ++ */ ++union iwreq_data ++{ ++ /* Config - generic */ ++ char name[IFNAMSIZ]; ++ /* Name : used to verify the presence of wireless extensions. ++ * Name of the protocol/provider... */ ++ ++ struct iw_point essid; /* Extended network name */ ++ struct iw_param nwid; /* network id (or domain - the cell) */ ++ struct iw_freq freq; /* frequency or channel : ++ * 0-1000 = channel ++ * > 1000 = frequency in Hz */ ++ ++ struct iw_param sens; /* signal level threshold */ ++ struct iw_param bitrate; /* default bit rate */ ++ struct iw_param txpower; /* default transmit power */ ++ struct iw_param rts; /* RTS threshold threshold */ ++ struct iw_param frag; /* Fragmentation threshold */ ++ __u32 mode; /* Operation mode */ ++ struct iw_param retry; /* Retry limits & lifetime */ ++ ++ struct iw_point encoding; /* Encoding stuff : tokens */ ++ struct iw_param power; /* PM duration/timeout */ ++ ++ struct sockaddr ap_addr; /* Access point address */ ++ ++ struct iw_point data; /* Other large parameters */ ++}; ++ ++/* + * The structure to exchange data for ioctl. + * This structure is the same as 'struct ifreq', but (re)defined for + * convenience... +- * +- * Note that it should fit on the same memory footprint ! +- * You should check this when increasing the above structures (16 octets) +- * 16 octets = 128 bits. Warning, pointers might be 64 bits wide... ++ * Do I need to remind you about structure size (32 octets) ? + */ + struct iwreq + { +@@ -429,35 +485,8 @@ struct iwreq + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */ + } ifr_ifrn; + +- /* Data part */ +- union +- { +- /* Config - generic */ +- char name[IFNAMSIZ]; +- /* Name : used to verify the presence of wireless extensions. +- * Name of the protocol/provider... */ +- +- struct iw_point essid; /* Extended network name */ +- struct iw_param nwid; /* network id (or domain - the cell) */ +- struct iw_freq freq; /* frequency or channel : +- * 0-1000 = channel +- * > 1000 = frequency in Hz */ +- +- struct iw_param sens; /* signal level threshold */ +- struct iw_param bitrate; /* default bit rate */ +- struct iw_param txpower; /* default transmit power */ +- struct iw_param rts; /* RTS threshold threshold */ +- struct iw_param frag; /* Fragmentation threshold */ +- __u32 mode; /* Operation mode */ +- struct iw_param retry; /* Retry limits & lifetime */ +- +- struct iw_point encoding; /* Encoding stuff : tokens */ +- struct iw_param power; /* PM duration/timeout */ +- +- struct sockaddr ap_addr; /* Access point address */ +- +- struct iw_point data; /* Other large parameters */ +- } u; ++ /* Data part (defined just above) */ ++ union iwreq_data u; + }; + + /* -------------------------- IOCTL DATA -------------------------- */ +diff -u -p -r --new-file linux/include/net-w12/iw_handler.h linux/include/net/iw_handler.h +--- linux/include/net-w12/iw_handler.h Wed Dec 31 16:00:00 1969 ++++ linux/include/net/iw_handler.h Thu Jan 17 12:16:46 2002 +@@ -0,0 +1,374 @@ ++/* ++ * This file define the new driver API for Wireless Extensions ++ * ++ * Version : 2 6.12.01 ++ * ++ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> ++ * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved. ++ */ ++ ++#ifndef _IW_HANDLER_H ++#define _IW_HANDLER_H ++ ++/************************** DOCUMENTATION **************************/ ++/* ++ * Initial driver API (1996 -> onward) : ++ * ----------------------------------- ++ * The initial API just sends the IOCTL request received from user space ++ * to the driver (via the driver ioctl handler). The driver has to ++ * handle all the rest... ++ * ++ * The initial API also defines a specific handler in struct net_device ++ * to handle wireless statistics. ++ * ++ * The initial APIs served us well and has proven a reasonably good design. ++ * However, there is a few shortcommings : ++ * o No events, everything is a request to the driver. ++ * o Large ioctl function in driver with gigantic switch statement ++ * (i.e. spaghetti code). ++ * o Driver has to mess up with copy_to/from_user, and in many cases ++ * does it unproperly. Common mistakes are : ++ * * buffer overflows (no checks or off by one checks) ++ * * call copy_to/from_user with irq disabled ++ * o The user space interface is tied to ioctl because of the use ++ * copy_to/from_user. ++ * ++ * New driver API (2001 -> onward) : ++ * ------------------------------- ++ * The new driver API is just a bunch of standard functions (handlers), ++ * each handling a specific Wireless Extension. The driver just export ++ * the list of handler it supports, and those will be called apropriately. ++ * ++ * I tried to keep the main advantage of the previous API (simplicity, ++ * efficiency and light weight), and also I provide a good dose of backward ++ * compatibility (most structures are the same, driver can use both API ++ * simultaneously, ...). ++ * Hopefully, I've also addressed the shortcomming of the initial API. ++ * ++ * The advantage of the new API are : ++ * o Handling of Extensions in driver broken in small contained functions ++ * o Tighter checks of ioctl before calling the driver ++ * o Flexible commit strategy (at least, the start of it) ++ * o Backward compatibility (can be mixed with old API) ++ * o Driver doesn't have to worry about memory and user-space issues ++ * The last point is important for the following reasons : ++ * o You are now able to call the new driver API from any API you ++ * want (including from within other parts of the kernel). ++ * o Common mistakes are avoided (buffer overflow, user space copy ++ * with irq disabled and so on). ++ * ++ * The Drawback of the new API are : ++ * o bloat (especially kernel) ++ * o need to migrate existing drivers to new API ++ * My initial testing shows that the new API adds around 3kB to the kernel ++ * and save between 0 and 5kB from a typical driver. ++ * Also, as all structures and data types are unchanged, the migration is ++ * quite straightforward (but tedious). ++ * ++ * --- ++ * ++ * The new driver API is defined below in this file. User space should ++ * not be aware of what's happening down there... ++ * ++ * A new kernel wrapper is in charge of validating the IOCTLs and calling ++ * the appropriate driver handler. This is implemented in : ++ * # net/core/wireless.c ++ * ++ * The driver export the list of handlers in : ++ * # include/linux/netdevice.h (one place) ++ * ++ * The new driver API is available for WIRELESS_EXT >= 13. ++ * Good luck with migration to the new API ;-) ++ */ ++ ++/* ---------------------- THE IMPLEMENTATION ---------------------- */ ++/* ++ * Some of the choice I've made are pretty controversials. Defining an ++ * API is very much weighting compromises. This goes into some of the ++ * details and the thinking behind the implementation. ++ * ++ * Implementation goals : ++ * -------------------- ++ * The implementation goals were as follow : ++ * o Obvious : you should not need a PhD to understand what's happening, ++ * the benefit is easier maintainance. ++ * o Flexible : it should accomodate a wide variety of driver ++ * implementations and be as flexible as the old API. ++ * o Lean : it should be efficient memory wise to minimise the impact ++ * on kernel footprint. ++ * o Transparent to user space : the large number of user space ++ * applications that use Wireless Extensions should not need ++ * any modifications. ++ * ++ * Array of functions versus Struct of functions ++ * --------------------------------------------- ++ * 1) Having an array of functions allow the kernel code to access the ++ * handler in a single lookup, which is much more efficient (think hash ++ * table here). ++ * 2) The only drawback is that driver writer may put their handler in ++ * the wrong slot. This is trivial to test (I set the frequency, the ++ * bitrate changes). Once the handler is in the proper slot, it will be ++ * there forever, because the array is only extended at the end. ++ * 3) Backward/forward compatibility : adding new handler just require ++ * extending the array, so you can put newer driver in older kernel ++ * without having to patch the kernel code (and vice versa). ++ * ++ * All handler are of the same generic type ++ * ---------------------------------------- ++ * That's a feature !!! ++ * 1) Having a generic handler allow to have generic code, which is more ++ * efficient. If each of the handler was individually typed I would need ++ * to add a big switch in the kernel (== more bloat). This solution is ++ * more scalable, adding new Wireless Extensions doesn't add new code. ++ * 2) You can use the same handler in different slots of the array. For ++ * hardware, it may be more efficient or logical to handle multiple ++ * Wireless Extensions with a single function, and the API allow you to ++ * do that. (An example would be a single record on the card to control ++ * both bitrate and frequency, the handler would read the old record, ++ * modify it according to info->cmd and rewrite it). ++ * ++ * Functions prototype uses union iwreq_data ++ * ----------------------------------------- ++ * Some would have prefered functions defined this way : ++ * static int mydriver_ioctl_setrate(struct net_device *dev, ++ * long rate, int auto) ++ * 1) The kernel code doesn't "validate" the content of iwreq_data, and ++ * can't do it (different hardware may have different notion of what a ++ * valid frequency is), so we don't pretend that we do it. ++ * 2) The above form is not extendable. If I want to add a flag (for ++ * example to distinguish setting max rate and basic rate), I would ++ * break the prototype. Using iwreq_data is more flexible. ++ * 3) Also, the above form is not generic (see above). ++ * 4) I don't expect driver developper using the wrong field of the ++ * union (Doh !), so static typechecking doesn't add much value. ++ * 5) Lastly, you can skip the union by doing : ++ * static int mydriver_ioctl_setrate(struct net_device *dev, ++ * struct iw_request_info *info, ++ * struct iw_param *rrq, ++ * char *extra) ++ * And then adding the handler in the array like this : ++ * (iw_handler) mydriver_ioctl_setrate, // SIOCSIWRATE ++ * ++ * Using functions and not a registry ++ * ---------------------------------- ++ * Another implementation option would have been for every instance to ++ * define a registry (a struct containing all the Wireless Extensions) ++ * and only have a function to commit the registry to the hardware. ++ * 1) This approach can be emulated by the current code, but not ++ * vice versa. ++ * 2) Some drivers don't keep any configuration in the driver, for them ++ * adding such a registry would be a significant bloat. ++ * 3) The code to translate from Wireless Extension to native format is ++ * needed anyway, so it would not reduce significantely the amount of code. ++ * 4) The current approach only selectively translate Wireless Extensions ++ * to native format and only selectively set, whereas the registry approach ++ * would require to translate all WE and set all parameters for any single ++ * change. ++ * 5) For many Wireless Extensions, the GET operation return the current ++ * dynamic value, not the value that was set. ++ * ++ * This header is <net/iw_handler.h> ++ * --------------------------------- ++ * 1) This header is kernel space only and should not be exported to ++ * user space. Headers in "include/linux/" are exported, headers in ++ * "include/net/" are not. ++ * ++ * Mixed 32/64 bit issues ++ * ---------------------- ++ * The Wireless Extensions are designed to be 64 bit clean, by using only ++ * datatypes with explicit storage size. ++ * There are some issues related to kernel and user space using different ++ * memory model, and in particular 64bit kernel with 32bit user space. ++ * The problem is related to struct iw_point, that contains a pointer ++ * that *may* need to be translated. ++ * This is quite messy. The new API doesn't solve this problem (it can't), ++ * but is a step in the right direction : ++ * 1) Meta data about each ioctl is easily available, so we know what type ++ * of translation is needed. ++ * 2) The move of data between kernel and user space is only done in a single ++ * place in the kernel, so adding specific hooks in there is possible. ++ * 3) In the long term, it allows to move away from using ioctl as the ++ * user space API. ++ * ++ * So many comments and so few code ++ * -------------------------------- ++ * That's a feature. Comments won't bloat the resulting kernel binary. ++ */ ++ ++/***************************** INCLUDES *****************************/ ++ ++#include <linux/wireless.h> /* IOCTL user space API */ ++ ++/***************************** VERSION *****************************/ ++/* ++ * This constant is used to know which version of the driver API is ++ * available. Hopefully, this will be pretty stable and no changes ++ * will be needed... ++ * I just plan to increment with each new version. ++ */ ++#define IW_HANDLER_VERSION 2 ++ ++/**************************** CONSTANTS ****************************/ ++ ++/* Special error message for the driver to indicate that we ++ * should do a commit after return from the iw_handler */ ++#define EIWCOMMIT EINPROGRESS ++ ++/* Flags available in struct iw_request_info */ ++#define IW_REQUEST_FLAG_NONE 0x0000 /* No flag so far */ ++ ++/* Type of headers we know about (basically union iwreq_data) */ ++#define IW_HEADER_TYPE_NULL 0 /* Not available */ ++#define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */ ++#define IW_HEADER_TYPE_UINT 4 /* __u32 */ ++#define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */ ++#define IW_HEADER_TYPE_POINT 6 /* struct iw_point */ ++#define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */ ++#define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */ ++ ++/* Handling flags */ ++/* Most are not implemented. I just use them as a reminder of some ++ * cool features we might need one day ;-) */ ++#define IW_DESCR_FLAG_NONE 0x0000 /* Obvious */ ++/* Wrapper level flags */ ++#define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */ ++#define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */ ++#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET request is ROOT only */ ++/* Driver level flags */ ++#define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */ ++ ++/****************************** TYPES ******************************/ ++ ++/* ----------------------- WIRELESS HANDLER ----------------------- */ ++/* ++ * A wireless handler is just a standard function, that looks like the ++ * ioctl handler. ++ * We also define there how a handler list look like... As the Wireless ++ * Extension space is quite dense, we use a simple array, which is faster ++ * (that's the perfect hash table ;-). ++ */ ++ ++/* ++ * Meta data about the request passed to the iw_handler. ++ * Most handlers can safely ignore what's in there. ++ * The 'cmd' field might come handy if you want to use the same handler ++ * for multiple command... ++ * This struct is also my long term insurance. I can add new fields here ++ * without breaking the prototype of iw_handler... ++ */ ++struct iw_request_info ++{ ++ __u16 cmd; /* Wireless Extension command */ ++ __u16 flags; /* More to come ;-) */ ++}; ++ ++/* ++ * This is how a function handling a Wireless Extension should look ++ * like (both get and set, standard and private). ++ */ ++typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++/* ++ * This define all the handler that the driver export. ++ * As you need only one per driver type, please use a static const ++ * shared by all driver instances... Same for the members... ++ * This will be linked from net_device in <linux/netdevice.h> ++ */ ++struct iw_handler_def ++{ ++ /* Number of handlers defined (more precisely, index of the ++ * last defined handler + 1) */ ++ __u16 num_standard; ++ __u16 num_private; ++ /* Number of private arg description */ ++ __u16 num_private_args; ++ ++ /* Array of handlers for standard ioctls ++ * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME] ++ */ ++ iw_handler * standard; ++ ++ /* Array of handlers for private ioctls ++ * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV] ++ */ ++ iw_handler * private; ++ ++ /* Arguments of private handler. This one is just a list, so you ++ * can put it in any order you want and should not leave holes... ++ * We will automatically export that to user space... */ ++ struct iw_priv_args * private_args; ++ ++ /* In the long term, get_wireless_stats will move from ++ * 'struct net_device' to here, to minimise bloat. */ ++}; ++ ++/* ----------------------- WIRELESS EVENTS ----------------------- */ ++/* ++ * Currently we don't support events, so let's just plan for the ++ * future... ++ */ ++ ++/* ++ * A Wireless Event. ++ */ ++// How do we define short header ? We don't want a flag on length. ++// Probably a flag on event ? Highest bit to zero... ++struct iw_event ++{ ++ __u16 length; /* Lenght of this stuff */ ++ __u16 event; /* Wireless IOCTL */ ++ union iwreq_data header; /* IOCTL fixed payload */ ++ char extra[0]; /* Optional IOCTL data */ ++}; ++ ++/* ---------------------- IOCTL DESCRIPTION ---------------------- */ ++/* ++ * One of the main goal of the new interface is to deal entirely with ++ * user space/kernel space memory move. ++ * For that, we need to know : ++ * o if iwreq is a pointer or contain the full data ++ * o what is the size of the data to copy ++ * ++ * For private IOCTLs, we use the same rules as used by iwpriv and ++ * defined in struct iw_priv_args. ++ * ++ * For standard IOCTLs, things are quite different and we need to ++ * use the stuctures below. Actually, this struct is also more ++ * efficient, but that's another story... ++ */ ++ ++/* ++ * Describe how a standard IOCTL looks like. ++ */ ++struct iw_ioctl_description ++{ ++ __u8 header_type; /* NULL, iw_point or other */ ++ __u8 token_type; /* Future */ ++ __u16 token_size; /* Granularity of payload */ ++ __u16 min_tokens; /* Min acceptable token number */ ++ __u16 max_tokens; /* Max acceptable token number */ ++ __u32 flags; /* Special handling of the request */ ++}; ++ ++/* Need to think of short header translation table. Later. */ ++ ++/**************************** PROTOTYPES ****************************/ ++/* ++ * Functions part of the Wireless Extensions (defined in net/core/wireless.c). ++ * Those may be called only within the kernel. ++ */ ++ ++/* First : function strictly used inside the kernel */ ++ ++/* Handle /proc/net/wireless, called in net/code/dev.c */ ++extern int dev_get_wireless_info(char * buffer, char **start, off_t offset, ++ int length); ++ ++/* Handle IOCTLs, called in net/code/dev.c */ ++extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd); ++ ++/* Second : functions that may be called by driver modules */ ++/* None yet */ ++ ++#endif /* _LINUX_WIRELESS_H */ +diff -u -p -r --new-file linux/net/core-w12/Makefile linux/net/core/Makefile +--- linux/net/core-w12/Makefile Tue Oct 30 15:08:12 2001 ++++ linux/net/core/Makefile Thu Jan 17 11:06:07 2002 +@@ -26,5 +26,8 @@ obj-$(CONFIG_NET) += dev.o dev_mcast.o d + obj-$(CONFIG_NETFILTER) += netfilter.o + obj-$(CONFIG_NET_DIVERT) += dv.o + obj-$(CONFIG_NET_PROFILE) += profile.o ++obj-$(CONFIG_NET_RADIO) += wireless.o ++# Ugly. I wish all wireless drivers were moved in drivers/net/wireless ++obj-$(CONFIG_NET_PCMCIA_RADIO) += wireless.o + + include $(TOPDIR)/Rules.make +diff -u -p -r --new-file linux/net/core-w12/dev.c linux/net/core/dev.c +--- linux/net/core-w12/dev.c Wed Nov 7 14:39:36 2001 ++++ linux/net/core/dev.c Thu Jan 17 11:06:07 2002 +@@ -102,6 +102,7 @@ + #include <linux/module.h> + #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO) + #include <linux/wireless.h> /* Note : will define WIRELESS_EXT */ ++#include <net/iw_handler.h> + #endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ + #ifdef CONFIG_PLIP + extern int plip_init(void); +@@ -1796,122 +1797,6 @@ static int dev_proc_stats(char *buffer, + #endif /* CONFIG_PROC_FS */ + + +-#ifdef WIRELESS_EXT +-#ifdef CONFIG_PROC_FS +- +-/* +- * Print one entry of /proc/net/wireless +- * This is a clone of /proc/net/dev (just above) +- */ +-static int sprintf_wireless_stats(char *buffer, struct net_device *dev) +-{ +- /* Get stats from the driver */ +- struct iw_statistics *stats = (dev->get_wireless_stats ? +- dev->get_wireless_stats(dev) : +- (struct iw_statistics *) NULL); +- int size; +- +- if (stats != (struct iw_statistics *) NULL) { +- size = sprintf(buffer, +- "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d %6d %6d %6d\n", +- dev->name, +- stats->status, +- stats->qual.qual, +- stats->qual.updated & 1 ? '.' : ' ', +- stats->qual.level, +- stats->qual.updated & 2 ? '.' : ' ', +- stats->qual.noise, +- stats->qual.updated & 4 ? '.' : ' ', +- stats->discard.nwid, +- stats->discard.code, +- stats->discard.fragment, +- stats->discard.retries, +- stats->discard.misc, +- stats->miss.beacon); +- stats->qual.updated = 0; +- } +- else +- size = 0; +- +- return size; +-} +- +-/* +- * Print info for /proc/net/wireless (print all entries) +- * This is a clone of /proc/net/dev (just above) +- */ +-static int dev_get_wireless_info(char * buffer, char **start, off_t offset, +- int length) +-{ +- int len = 0; +- off_t begin = 0; +- off_t pos = 0; +- int size; +- +- struct net_device * dev; +- +- size = sprintf(buffer, +- "Inter-| sta-| Quality | Discarded packets | Missed\n" +- " face | tus | link level noise | nwid crypt frag retry misc | beacon\n" +- ); +- +- pos += size; +- len += size; +- +- read_lock(&dev_base_lock); +- for (dev = dev_base; dev != NULL; dev = dev->next) { +- size = sprintf_wireless_stats(buffer + len, dev); +- len += size; +- pos = begin + len; +- +- if (pos < offset) { +- len = 0; +- begin = pos; +- } +- if (pos > offset + length) +- break; +- } +- read_unlock(&dev_base_lock); +- +- *start = buffer + (offset - begin); /* Start of wanted data */ +- len -= (offset - begin); /* Start slop */ +- if (len > length) +- len = length; /* Ending slop */ +- if (len < 0) +- len = 0; +- +- return len; +-} +-#endif /* CONFIG_PROC_FS */ +- +-/* +- * Allow programatic access to /proc/net/wireless even if /proc +- * doesn't exist... Also more efficient... +- */ +-static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr) +-{ +- /* Get stats from the driver */ +- struct iw_statistics *stats = (dev->get_wireless_stats ? +- dev->get_wireless_stats(dev) : +- (struct iw_statistics *) NULL); +- +- if (stats != (struct iw_statistics *) NULL) { +- struct iwreq * wrq = (struct iwreq *)ifr; +- +- /* Copy statistics to the user buffer */ +- if(copy_to_user(wrq->u.data.pointer, stats, +- sizeof(struct iw_statistics))) +- return -EFAULT; +- +- /* Check if we need to clear the update flag */ +- if(wrq->u.data.flags != 0) +- stats->qual.updated = 0; +- return(0); +- } else +- return -EOPNOTSUPP; +-} +-#endif /* WIRELESS_EXT */ +- + /** + * netdev_set_master - set up master/slave pair + * @slave: slave device +@@ -2209,11 +2094,6 @@ static int dev_ifsioc(struct ifreq *ifr, + notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); + return 0; + +-#ifdef WIRELESS_EXT +- case SIOCGIWSTATS: +- return dev_iwstats(dev, ifr); +-#endif /* WIRELESS_EXT */ +- + /* + * Unknown or private ioctl + */ +@@ -2239,17 +2119,6 @@ static int dev_ifsioc(struct ifreq *ifr, + return -EOPNOTSUPP; + } + +-#ifdef WIRELESS_EXT +- if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { +- if (dev->do_ioctl) { +- if (!netif_device_present(dev)) +- return -ENODEV; +- return dev->do_ioctl(dev, ifr, cmd); +- } +- return -EOPNOTSUPP; +- } +-#endif /* WIRELESS_EXT */ +- + } + return -EINVAL; + } +@@ -2431,7 +2300,8 @@ int dev_ioctl(unsigned int cmd, void *ar + } + dev_load(ifr.ifr_name); + rtnl_lock(); +- ret = dev_ifsioc(&ifr, cmd); ++ /* Follow me in net/core/wireless.c */ ++ ret = wireless_process_ioctl(&ifr, cmd); + rtnl_unlock(); + if (!ret && IW_IS_GET(cmd) && + copy_to_user(arg, &ifr, sizeof(struct ifreq))) +@@ -2856,6 +2726,7 @@ int __init net_dev_init(void) + proc_net_create("dev", 0, dev_get_info); + create_proc_read_entry("net/softnet_stat", 0, 0, dev_proc_stats, NULL); + #ifdef WIRELESS_EXT ++ /* Available in net/core/wireless.c */ + proc_net_create("wireless", 0, dev_get_wireless_info); + #endif /* WIRELESS_EXT */ + #endif /* CONFIG_PROC_FS */ +diff -u -p -r --new-file linux/net/core-w12/wireless.c linux/net/core/wireless.c +--- linux/net/core-w12/wireless.c Wed Dec 31 16:00:00 1969 ++++ linux/net/core/wireless.c Mon Jan 21 11:13:23 2002 +@@ -0,0 +1,733 @@ ++/* ++ * This file implement the Wireless Extensions APIs. ++ * ++ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> ++ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. ++ * ++ * (As all part of the Linux kernel, this file is GPL) ++ */ ++ ++/************************** DOCUMENTATION **************************/ ++/* ++ * API definition : ++ * -------------- ++ * See <linux/wireless.h> for details of the APIs and the rest. ++ * ++ * History : ++ * ------- ++ * ++ * v1 - 5.12.01 - Jean II ++ * o Created this file. ++ * ++ * v2 - 13.12.01 - Jean II ++ * o Move /proc/net/wireless stuff from net/core/dev.c to here ++ * o Make Wireless Extension IOCTLs go through here ++ * o Added iw_handler handling ;-) ++ * o Added standard ioctl description ++ * o Initial dumb commit strategy based on orinoco.c ++ */ ++ ++/***************************** INCLUDES *****************************/ ++ ++#include <asm/uaccess.h> /* copy_to_user() */ ++#include <linux/config.h> /* Not needed ??? */ ++#include <linux/types.h> /* off_t */ ++#include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */ ++ ++#include <linux/wireless.h> /* Pretty obvious */ ++#include <net/iw_handler.h> /* New driver API */ ++ ++/**************************** CONSTANTS ****************************/ ++ ++/* This will be turned on later on... */ ++#undef WE_STRICT_WRITE /* Check write buffer size */ ++ ++/* Debuging stuff */ ++#undef WE_IOCTL_DEBUG /* Debug IOCTL API */ ++ ++/************************* GLOBAL VARIABLES *************************/ ++/* ++ * You should not use global variables, because or re-entrancy. ++ * On our case, it's only const, so it's OK... ++ */ ++static const struct iw_ioctl_description standard_ioctl[] = { ++ /* SIOCSIWCOMMIT (internal) */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWNAME */ ++ { IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWNWID */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT}, ++ /* SIOCGIWNWID */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWFREQ */ ++ { IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT}, ++ /* SIOCGIWFREQ */ ++ { IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWMODE */ ++ { IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT}, ++ /* SIOCGIWMODE */ ++ { IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWSENS */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWSENS */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWRANGE */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWRANGE */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_range), IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWPRIV */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWPRIV (handled directly by us) */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWSTATS */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWSTATS (handled directly by us) */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWSPY */ ++ { IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0}, ++ /* SIOCGIWSPY */ ++ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWAP */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, ++ /* SIOCGIWAP */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWAPLIST */ ++ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWESSID */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT}, ++ /* SIOCGIWESSID */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWNICKN */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, ++ /* SIOCGIWNICKN */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWRATE */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWRATE */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWRTS */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWRTS */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWFRAG */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWFRAG */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWTXPOW */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWTXPOW */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWRETRY */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWRETRY */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWENCODE */ ++ { IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT}, ++ /* SIOCGIWENCODE */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT}, ++ /* SIOCSIWPOWER */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWPOWER */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++}; ++ ++/* Size (in bytes) of the various private data types */ ++char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; ++ ++/************************ COMMON SUBROUTINES ************************/ ++/* ++ * Stuff that may be used in various place or doesn't fit in one ++ * of the section below. ++ */ ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Return the driver handler associated with a specific Wireless Extension. ++ * Called from various place, so make sure it remains efficient. ++ */ ++static inline iw_handler get_handler(struct net_device *dev, ++ unsigned int cmd) ++{ ++ unsigned int index; /* MUST be unsigned */ ++ ++ /* Check if we have some wireless handlers defined */ ++ if(dev->wireless_handlers == NULL) ++ return NULL; ++ ++ /* Try as a standard command */ ++ index = cmd - SIOCIWFIRST; ++ if(index < dev->wireless_handlers->num_standard) ++ return dev->wireless_handlers->standard[index]; ++ ++ /* Try as a private command */ ++ index = cmd - SIOCIWFIRSTPRIV; ++ if(index < dev->wireless_handlers->num_private) ++ return dev->wireless_handlers->private[index]; ++ ++ /* Not found */ ++ return NULL; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Get statistics out of the driver ++ */ ++static inline struct iw_statistics *get_wireless_stats(struct net_device *dev) ++{ ++ return (dev->get_wireless_stats ? ++ dev->get_wireless_stats(dev) : ++ (struct iw_statistics *) NULL); ++ /* In the future, get_wireless_stats may move from 'struct net_device' ++ * to 'struct iw_handler_def', to de-bloat struct net_device. ++ * Definitely worse a thought... */ ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Call the commit handler in the driver ++ * (if exist and if conditions are right) ++ * ++ * Note : our current commit strategy is currently pretty dumb, ++ * but we will be able to improve on that... ++ * The goal is to try to agreagate as many changes as possible ++ * before doing the commit. Drivers that will define a commit handler ++ * are usually those that need a reset after changing parameters, so ++ * we want to minimise the number of reset. ++ * A cool idea is to use a timer : at each "set" command, we re-set the ++ * timer, when the timer eventually fires, we call the driver. ++ * Hopefully, more on that later. ++ * ++ * Also, I'm waiting to see how many people will complain about the ++ * netif_running(dev) test. I'm open on that one... ++ * Hopefully, the driver will remember to do a commit in "open()" ;-) ++ */ ++static inline int call_commit_handler(struct net_device * dev) ++{ ++ if((netif_running(dev)) && ++ (dev->wireless_handlers->standard[0] != NULL)) { ++ /* Call the commit handler on the driver */ ++ return dev->wireless_handlers->standard[0](dev, NULL, ++ NULL, NULL); ++ } else ++ return 0; /* Command completed successfully */ ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Number of private arguments ++ */ ++static inline int get_priv_size(__u16 args) ++{ ++ int num = args & IW_PRIV_SIZE_MASK; ++ int type = (args & IW_PRIV_TYPE_MASK) >> 12; ++ ++ return num * priv_type_size[type]; ++} ++ ++ ++/******************** /proc/net/wireless SUPPORT ********************/ ++/* ++ * The /proc/net/wireless file is a human readable user-space interface ++ * exporting various wireless specific statistics from the wireless devices. ++ * This is the most popular part of the Wireless Extensions ;-) ++ * ++ * This interface is a pure clone of /proc/net/dev (in net/core/dev.c). ++ * The content of the file is basically the content of "struct iw_statistics". ++ */ ++ ++#ifdef CONFIG_PROC_FS ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Print one entry (line) of /proc/net/wireless ++ */ ++static inline int sprintf_wireless_stats(char *buffer, struct net_device *dev) ++{ ++ /* Get stats from the driver */ ++ struct iw_statistics *stats; ++ int size; ++ ++ stats = get_wireless_stats(dev); ++ if (stats != (struct iw_statistics *) NULL) { ++ size = sprintf(buffer, ++ "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d %6d %6d %6d\n", ++ dev->name, ++ stats->status, ++ stats->qual.qual, ++ stats->qual.updated & 1 ? '.' : ' ', ++ stats->qual.level, ++ stats->qual.updated & 2 ? '.' : ' ', ++ stats->qual.noise, ++ stats->qual.updated & 4 ? '.' : ' ', ++ stats->discard.nwid, ++ stats->discard.code, ++ stats->discard.fragment, ++ stats->discard.retries, ++ stats->discard.misc, ++ stats->miss.beacon); ++ stats->qual.updated = 0; ++ } ++ else ++ size = 0; ++ ++ return size; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Print info for /proc/net/wireless (print all entries) ++ */ ++int dev_get_wireless_info(char * buffer, char **start, off_t offset, ++ int length) ++{ ++ int len = 0; ++ off_t begin = 0; ++ off_t pos = 0; ++ int size; ++ ++ struct net_device * dev; ++ ++ size = sprintf(buffer, ++ "Inter-| sta-| Quality | Discarded packets | Missed\n" ++ " face | tus | link level noise | nwid crypt frag retry misc | beacon\n" ++ ); ++ ++ pos += size; ++ len += size; ++ ++ read_lock(&dev_base_lock); ++ for (dev = dev_base; dev != NULL; dev = dev->next) { ++ size = sprintf_wireless_stats(buffer + len, dev); ++ len += size; ++ pos = begin + len; ++ ++ if (pos < offset) { ++ len = 0; ++ begin = pos; ++ } ++ if (pos > offset + length) ++ break; ++ } ++ read_unlock(&dev_base_lock); ++ ++ *start = buffer + (offset - begin); /* Start of wanted data */ ++ len -= (offset - begin); /* Start slop */ ++ if (len > length) ++ len = length; /* Ending slop */ ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++#endif /* CONFIG_PROC_FS */ ++ ++/************************** IOCTL SUPPORT **************************/ ++/* ++ * The original user space API to configure all those Wireless Extensions ++ * is through IOCTLs. ++ * In there, we check if we need to call the new driver API (iw_handler) ++ * or just call the driver ioctl handler. ++ */ ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Allow programatic access to /proc/net/wireless even if /proc ++ * doesn't exist... Also more efficient... ++ */ ++static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr) ++{ ++ /* Get stats from the driver */ ++ struct iw_statistics *stats; ++ ++ stats = get_wireless_stats(dev); ++ if (stats != (struct iw_statistics *) NULL) { ++ struct iwreq * wrq = (struct iwreq *)ifr; ++ ++ /* Copy statistics to the user buffer */ ++ if(copy_to_user(wrq->u.data.pointer, stats, ++ sizeof(struct iw_statistics))) ++ return -EFAULT; ++ ++ /* Check if we need to clear the update flag */ ++ if(wrq->u.data.flags != 0) ++ stats->qual.updated = 0; ++ return 0; ++ } else ++ return -EOPNOTSUPP; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Export the driver private handler definition ++ * They will be picked up by tools like iwpriv... ++ */ ++static inline int ioctl_export_private(struct net_device * dev, ++ struct ifreq * ifr) ++{ ++ struct iwreq * iwr = (struct iwreq *) ifr; ++ ++ /* Check if the driver has something to export */ ++ if((dev->wireless_handlers->num_private_args == 0) || ++ (dev->wireless_handlers->private_args == NULL)) ++ return -EOPNOTSUPP; ++ ++ /* Check NULL pointer */ ++ if(iwr->u.data.pointer == NULL) ++ return -EFAULT; ++#ifdef WE_STRICT_WRITE ++ /* Check if there is enough buffer up there */ ++ if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1)) ++ return -E2BIG; ++#endif /* WE_STRICT_WRITE */ ++ ++ /* Set the number of available ioctls. */ ++ iwr->u.data.length = dev->wireless_handlers->num_private_args; ++ ++ /* Copy structure to the user buffer. */ ++ if (copy_to_user(iwr->u.data.pointer, ++ dev->wireless_handlers->private_args, ++ sizeof(struct iw_priv_args) * iwr->u.data.length)) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Wrapper to call a standard Wireless Extension handler. ++ * We do various checks and also take care of moving data between ++ * user space and kernel space. ++ */ ++static inline int ioctl_standard_call(struct net_device * dev, ++ struct ifreq * ifr, ++ unsigned int cmd, ++ iw_handler handler) ++{ ++ struct iwreq * iwr = (struct iwreq *) ifr; ++ const struct iw_ioctl_description * descr; ++ struct iw_request_info info; ++ int ret = -EINVAL; ++ ++ /* Get the description of the IOCTL */ ++ descr = &(standard_ioctl[cmd - SIOCIWFIRST]); ++ ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n", ++ ifr->ifr_name, cmd); ++ printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); ++#endif /* WE_IOCTL_DEBUG */ ++ ++ /* Prepare the call */ ++ info.cmd = cmd; ++ info.flags = 0; ++ ++ /* Check if we have a pointer to user space data or not */ ++ if(descr->header_type != IW_HEADER_TYPE_POINT) { ++ /* No extra arguments. Trivial to handle */ ++ ret = handler(dev, &info, &(iwr->u), NULL); ++ } else { ++ char * extra; ++ int err; ++ ++ /* Check what user space is giving us */ ++ if(IW_IS_SET(cmd)) { ++ /* Check NULL pointer */ ++ if((iwr->u.data.pointer == NULL) && ++ (iwr->u.data.length != 0)) ++ return -EFAULT; ++ /* Check if number of token fits within bounds */ ++ if(iwr->u.data.length > descr->max_tokens) ++ return -E2BIG; ++ if(iwr->u.data.length < descr->min_tokens) ++ return -EINVAL; ++ } else { ++ /* Check NULL pointer */ ++ if(iwr->u.data.pointer == NULL) ++ return -EFAULT; ++#ifdef WE_STRICT_WRITE ++ /* Check if there is enough buffer up there */ ++ if(iwr->u.data.length < descr->max_tokens) ++ return -E2BIG; ++#endif /* WE_STRICT_WRITE */ ++ } ++ ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Malloc %d bytes\n", ++ descr->max_tokens * descr->token_size); ++#endif /* WE_IOCTL_DEBUG */ ++ ++ /* Always allocate for max space. Easier, and won't last ++ * long... */ ++ extra = kmalloc(descr->max_tokens * descr->token_size, ++ GFP_KERNEL); ++ if (extra == NULL) { ++ return -ENOMEM; ++ } ++ ++ /* If it is a SET, get all the extra data in here */ ++ if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { ++ err = copy_from_user(extra, iwr->u.data.pointer, ++ iwr->u.data.length * ++ descr->token_size); ++ if (err) { ++ kfree(extra); ++ return -EFAULT; ++ } ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Got %d bytes\n", ++ iwr->u.data.length * descr->token_size); ++#endif /* WE_IOCTL_DEBUG */ ++ } ++ ++ /* Call the handler */ ++ ret = handler(dev, &info, &(iwr->u), extra); ++ ++ /* If we have something to return to the user */ ++ if (!ret && IW_IS_GET(cmd)) { ++ err = copy_to_user(iwr->u.data.pointer, extra, ++ iwr->u.data.length * ++ descr->token_size); ++ if (err) ++ ret = -EFAULT; ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Wrote %d bytes\n", ++ iwr->u.data.length * descr->token_size); ++#endif /* WE_IOCTL_DEBUG */ ++ } ++ ++ /* Cleanup - I told you it wasn't that long ;-) */ ++ kfree(extra); ++ } ++ ++ /* Call commit handler if needed and defined */ ++ if(ret == -EIWCOMMIT) ++ ret = call_commit_handler(dev); ++ ++ /* Here, we will generate the appropriate event if needed */ ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Wrapper to call a private Wireless Extension handler. ++ * We do various checks and also take care of moving data between ++ * user space and kernel space. ++ * It's not as nice and slimline as the standard wrapper. The cause ++ * is struct iw_priv_args, which was not really designed for the ++ * job we are going here. ++ * ++ * IMPORTANT : This function prevent to set and get data on the same ++ * IOCTL and enforce the SET/GET convention. Not doing it would be ++ * far too hairy... ++ * If you need to set and get data at the same time, please don't use ++ * a iw_handler but process it in your ioctl handler (i.e. use the ++ * old driver API). ++ */ ++static inline int ioctl_private_call(struct net_device * dev, ++ struct ifreq * ifr, ++ unsigned int cmd, ++ iw_handler handler) ++{ ++ struct iwreq * iwr = (struct iwreq *) ifr; ++ struct iw_priv_args * descr = NULL; ++ struct iw_request_info info; ++ int extra_size = 0; ++ int i; ++ int ret = -EINVAL; ++ ++ /* Get the description of the IOCTL */ ++ for(i = 0; i < dev->wireless_handlers->num_private_args; i++) ++ if(cmd == dev->wireless_handlers->private_args[i].cmd) { ++ descr = &(dev->wireless_handlers->private_args[i]); ++ break; ++ } ++ ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n", ++ ifr->ifr_name, cmd); ++ if(descr) { ++ printk(KERN_DEBUG "Name %s, set %X, get %X\n", ++ descr->name, descr->set_args, descr->get_args); ++ } ++#endif /* WE_IOCTL_DEBUG */ ++ ++ /* Compute the size of the set/get arguments */ ++ if(descr != NULL) { ++ if(IW_IS_SET(cmd)) { ++ /* Size of set arguments */ ++ extra_size = get_priv_size(descr->set_args); ++ ++ /* Does it fits in iwr ? */ ++ if((descr->set_args & IW_PRIV_SIZE_FIXED) && ++ (extra_size < IFNAMSIZ)) ++ extra_size = 0; ++ } else { ++ /* Size of set arguments */ ++ extra_size = get_priv_size(descr->get_args); ++ ++ /* Does it fits in iwr ? */ ++ if((descr->get_args & IW_PRIV_SIZE_FIXED) && ++ (extra_size < IFNAMSIZ)) ++ extra_size = 0; ++ } ++ } ++ ++ /* Prepare the call */ ++ info.cmd = cmd; ++ info.flags = 0; ++ ++ /* Check if we have a pointer to user space data or not. */ ++ if(extra_size == 0) { ++ /* No extra arguments. Trivial to handle */ ++ ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u)); ++ } else { ++ char * extra; ++ int err; ++ ++ /* Check what user space is giving us */ ++ if(IW_IS_SET(cmd)) { ++ /* Check NULL pointer */ ++ if((iwr->u.data.pointer == NULL) && ++ (iwr->u.data.length != 0)) ++ return -EFAULT; ++ ++ /* Does it fits within bounds ? */ ++ if(iwr->u.data.length > (descr->set_args & ++ IW_PRIV_SIZE_MASK)) ++ return -E2BIG; ++ } else { ++ /* Check NULL pointer */ ++ if(iwr->u.data.pointer == NULL) ++ return -EFAULT; ++ } ++ ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Malloc %d bytes\n", extra_size); ++#endif /* WE_IOCTL_DEBUG */ ++ ++ /* Always allocate for max space. Easier, and won't last ++ * long... */ ++ extra = kmalloc(extra_size, GFP_KERNEL); ++ if (extra == NULL) { ++ return -ENOMEM; ++ } ++ ++ /* If it is a SET, get all the extra data in here */ ++ if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { ++ err = copy_from_user(extra, iwr->u.data.pointer, ++ extra_size); ++ if (err) { ++ kfree(extra); ++ return -EFAULT; ++ } ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length); ++#endif /* WE_IOCTL_DEBUG */ ++ } ++ ++ /* Call the handler */ ++ ret = handler(dev, &info, &(iwr->u), extra); ++ ++ /* If we have something to return to the user */ ++ if (!ret && IW_IS_GET(cmd)) { ++ err = copy_to_user(iwr->u.data.pointer, extra, ++ extra_size); ++ if (err) ++ ret = -EFAULT; ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Wrote %d elem\n", ++ iwr->u.data.length); ++#endif /* WE_IOCTL_DEBUG */ ++ } ++ ++ /* Cleanup - I told you it wasn't that long ;-) */ ++ kfree(extra); ++ } ++ ++ ++ /* Call commit handler if needed and defined */ ++ if(ret == -EIWCOMMIT) ++ ret = call_commit_handler(dev); ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Main IOCTl dispatcher. Called from the main networking code ++ * (dev_ioctl() in net/core/dev.c). ++ * Check the type of IOCTL and call the appropriate wrapper... ++ */ ++int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd) ++{ ++ struct net_device *dev; ++ iw_handler handler; ++ ++ /* Permissions are already checked in dev_ioctl() before calling us. ++ * The copy_to/from_user() of ifr is also dealt with in there */ ++ ++ /* Make sure the device exist */ ++ if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) ++ return -ENODEV; ++ ++ /* A bunch of special cases, then the generic case... ++ * Note that 'cmd' is already filtered in dev_ioctl() with ++ * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ ++ switch(cmd) ++ { ++ case SIOCGIWSTATS: ++ /* Get Wireless Stats */ ++ return dev_iwstats(dev, ifr); ++ ++ case SIOCGIWPRIV: ++ /* Check if we have some wireless handlers defined */ ++ if(dev->wireless_handlers != NULL) { ++ /* We export to user space the definition of ++ * the private handler ourselves */ ++ return ioctl_export_private(dev, ifr); ++ } ++ // ## Fall-through for old API ## ++ default: ++ /* Generic IOCTL */ ++ /* Basic check */ ++ if (!netif_device_present(dev)) ++ return -ENODEV; ++ /* New driver API : try to find the handler */ ++ handler = get_handler(dev, cmd); ++ if(handler != NULL) { ++ /* Standard and private are not the same */ ++ if(cmd < SIOCIWFIRSTPRIV) ++ return ioctl_standard_call(dev, ++ ifr, ++ cmd, ++ handler); ++ else ++ return ioctl_private_call(dev, ++ ifr, ++ cmd, ++ handler); ++ } ++ /* Old driver API : call driver ioctl handler */ ++ if (dev->do_ioctl) { ++ return dev->do_ioctl(dev, ifr, cmd); ++ } ++ return -EOPNOTSUPP; ++ } ++ /* Not reached */ ++ return -EINVAL; ++} diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w14-5.diff b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w14-5.diff index e69de29bb2..539b160068 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w14-5.diff +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w14-5.diff @@ -0,0 +1,838 @@ +diff -u -p -r --new-file linux/include/linux-w13/rtnetlink.h linux/include/linux/rtnetlink.h +--- linux/include/linux-w13/rtnetlink.h Thu Jun 6 14:44:08 2002 ++++ linux/include/linux/rtnetlink.h Thu Jun 6 15:47:44 2002 +@@ -440,12 +440,14 @@ enum + #define IFLA_COST IFLA_COST + IFLA_PRIORITY, + #define IFLA_PRIORITY IFLA_PRIORITY +- IFLA_MASTER ++ IFLA_MASTER, + #define IFLA_MASTER IFLA_MASTER ++ IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */ ++#define IFLA_WIRELESS IFLA_WIRELESS + }; + + +-#define IFLA_MAX IFLA_MASTER ++#define IFLA_MAX IFLA_WIRELESS + + #define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) + #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) +diff -u -p -r --new-file linux/include/linux-w13/wireless.h linux/include/linux/wireless.h +--- linux/include/linux-w13/wireless.h Thu Jun 6 15:00:28 2002 ++++ linux/include/linux/wireless.h Thu Jun 6 15:47:44 2002 +@@ -1,10 +1,10 @@ + /* + * This file define a set of standard wireless extensions + * +- * Version : 13 6.12.01 ++ * Version : 14 25.1.02 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> +- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. ++ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. + */ + + #ifndef _LINUX_WIRELESS_H +@@ -40,7 +40,7 @@ + * # include/linux/netdevice.h (one place) + * # include/linux/proc_fs.h (one place) + * +- * New driver API (2001 -> onward) : ++ * New driver API (2002 -> onward) : + * ------------------------------- + * This file is only concerned with the user space API and common definitions. + * The new driver API is defined and documented in : +@@ -49,6 +49,11 @@ + * Note as well that /proc/net/wireless implementation has now moved in : + * # include/linux/wireless.c + * ++ * Wireless Events (2002 -> onward) : ++ * -------------------------------- ++ * Events are defined at the end of this file, and implemented in : ++ * # include/linux/wireless.c ++ * + * Other comments : + * -------------- + * Do not add here things that are redundant with other mechanisms +@@ -75,7 +80,7 @@ + * (there is some stuff that will be added in the future...) + * I just plan to increment with each new version. + */ +-#define WIRELESS_EXT 13 ++#define WIRELESS_EXT 14 + + /* + * Changes : +@@ -141,6 +146,13 @@ + * - Document creation of new driver API. + * - Extract union iwreq_data from struct iwreq (for new driver API). + * - Rename SIOCSIWNAME as SIOCSIWCOMMIT ++ * ++ * V13 to V14 ++ * ---------- ++ * - Wireless Events support : define struct iw_event ++ * - Define additional specific event numbers ++ * - Add "addr" and "param" fields in union iwreq_data ++ * - AP scanning stuff (SIOCSIWSCAN and friends) + */ + + /**************************** CONSTANTS ****************************/ +@@ -175,6 +187,8 @@ + #define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ + #define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ + #define SIOCGIWAPLIST 0x8B17 /* get list of access point in range */ ++#define SIOCSIWSCAN 0x8B18 /* trigger scanning */ ++#define SIOCGIWSCAN 0x8B19 /* get scanning results */ + + /* 802.11 specific support */ + #define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */ +@@ -238,6 +252,15 @@ + #define IW_IS_SET(cmd) (!((cmd) & 0x1)) + #define IW_IS_GET(cmd) ((cmd) & 0x1) + ++/* ----------------------- WIRELESS EVENTS ----------------------- */ ++/* Those are *NOT* ioctls, do not issue request on them !!! */ ++/* Most events use the same identifier as ioctl requests */ ++ ++#define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ ++#define IWEVQUAL 0x8C01 /* Quality part of statistics */ ++ ++#define IWEVFIRST 0x8C00 ++ + /* ------------------------- PRIVATE INFO ------------------------- */ + /* + * The following is used with SIOCGIWPRIV. It allow a driver to define +@@ -340,6 +363,19 @@ + #define IW_RETRY_MAX 0x0002 /* Value is a maximum */ + #define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ + ++/* Scanning request flags */ ++#define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */ ++#define IW_SCAN_ALL_ESSID 0x0001 /* Scan all ESSIDs */ ++#define IW_SCAN_THIS_ESSID 0x0002 /* Scan only this ESSID */ ++#define IW_SCAN_ALL_FREQ 0x0004 /* Scan all Frequencies */ ++#define IW_SCAN_THIS_FREQ 0x0008 /* Scan only this Frequency */ ++#define IW_SCAN_ALL_MODE 0x0010 /* Scan all Modes */ ++#define IW_SCAN_THIS_MODE 0x0020 /* Scan only this Mode */ ++#define IW_SCAN_ALL_RATE 0x0040 /* Scan all Bit-Rates */ ++#define IW_SCAN_THIS_RATE 0x0080 /* Scan only this Bit-Rate */ ++/* Maximum size of returned data */ ++#define IW_SCAN_MAX_DATA 4096 /* In bytes */ ++ + /****************************** TYPES ******************************/ + + /* --------------------------- SUBTYPES --------------------------- */ +@@ -466,9 +502,12 @@ union iwreq_data + + struct iw_point encoding; /* Encoding stuff : tokens */ + struct iw_param power; /* PM duration/timeout */ ++ struct iw_quality qual; /* Quality part of statistics */ + + struct sockaddr ap_addr; /* Access point address */ ++ struct sockaddr addr; /* Destination address (hw) */ + ++ struct iw_param param; /* Other small parameters */ + struct iw_point data; /* Other large parameters */ + }; + +@@ -595,5 +634,36 @@ struct iw_priv_args + __u16 get_args; /* Type and number of args */ + char name[IFNAMSIZ]; /* Name of the extension */ + }; ++ ++/* ----------------------- WIRELESS EVENTS ----------------------- */ ++/* ++ * Wireless events are carried through the rtnetlink socket to user ++ * space. They are encapsulated in the IFLA_WIRELESS field of ++ * a RTM_NEWLINK message. ++ */ ++ ++/* ++ * A Wireless Event. Contains basically the same data as the ioctl... ++ */ ++struct iw_event ++{ ++ __u16 len; /* Real lenght of this stuff */ ++ __u16 cmd; /* Wireless IOCTL */ ++ union iwreq_data u; /* IOCTL fixed payload */ ++}; ++ ++/* Size of the Event prefix (including padding and alignement junk) */ ++#define IW_EV_LCP_LEN (sizeof(struct iw_event) - sizeof(union iwreq_data)) ++/* Size of the various events */ ++#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ) ++#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32)) ++#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq)) ++#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point)) ++#define IW_EV_PARAM_LEN (IW_EV_LCP_LEN + sizeof(struct iw_param)) ++#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr)) ++#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality)) ++ ++/* Note : in the case of iw_point, the extra data will come at the ++ * end of the event */ + + #endif /* _LINUX_WIRELESS_H */ +diff -u -p -r --new-file linux/include/net-w13/iw_handler.h linux/include/net/iw_handler.h +--- linux/include/net-w13/iw_handler.h Thu Jun 6 15:06:16 2002 ++++ linux/include/net/iw_handler.h Thu Jun 6 15:48:06 2002 +@@ -1,10 +1,10 @@ + /* + * This file define the new driver API for Wireless Extensions + * +- * Version : 2 6.12.01 ++ * Version : 3 17.1.02 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> +- * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved. ++ * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved. + */ + + #ifndef _IW_HANDLER_H +@@ -33,7 +33,7 @@ + * o The user space interface is tied to ioctl because of the use + * copy_to/from_user. + * +- * New driver API (2001 -> onward) : ++ * New driver API (2002 -> onward) : + * ------------------------------- + * The new driver API is just a bunch of standard functions (handlers), + * each handling a specific Wireless Extension. The driver just export +@@ -206,7 +206,18 @@ + * will be needed... + * I just plan to increment with each new version. + */ +-#define IW_HANDLER_VERSION 2 ++#define IW_HANDLER_VERSION 3 ++ ++/* ++ * Changes : ++ * ++ * V2 to V3 ++ * -------- ++ * - Move event definition in <linux/wireless.h> ++ * - Add Wireless Event support : ++ * o wireless_send_event() prototype ++ * o iwe_stream_add_event/point() inline functions ++ */ + + /**************************** CONSTANTS ****************************/ + +@@ -225,6 +236,7 @@ + #define IW_HEADER_TYPE_POINT 6 /* struct iw_point */ + #define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */ + #define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */ ++#define IW_HEADER_TYPE_QUAL 9 /* struct iw_quality */ + + /* Handling flags */ + /* Most are not implemented. I just use them as a reminder of some +@@ -233,7 +245,8 @@ + /* Wrapper level flags */ + #define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */ + #define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */ +-#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET request is ROOT only */ ++#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */ ++ /* SET : Omit payload from generated iwevent */ + /* Driver level flags */ + #define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */ + +@@ -303,25 +316,6 @@ struct iw_handler_def + * 'struct net_device' to here, to minimise bloat. */ + }; + +-/* ----------------------- WIRELESS EVENTS ----------------------- */ +-/* +- * Currently we don't support events, so let's just plan for the +- * future... +- */ +- +-/* +- * A Wireless Event. +- */ +-// How do we define short header ? We don't want a flag on length. +-// Probably a flag on event ? Highest bit to zero... +-struct iw_event +-{ +- __u16 length; /* Lenght of this stuff */ +- __u16 event; /* Wireless IOCTL */ +- union iwreq_data header; /* IOCTL fixed payload */ +- char extra[0]; /* Optional IOCTL data */ +-}; +- + /* ---------------------- IOCTL DESCRIPTION ---------------------- */ + /* + * One of the main goal of the new interface is to deal entirely with +@@ -369,6 +363,88 @@ extern int dev_get_wireless_info(char * + extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd); + + /* Second : functions that may be called by driver modules */ +-/* None yet */ + +-#endif /* _LINUX_WIRELESS_H */ ++/* Send a single event to user space */ ++extern void wireless_send_event(struct net_device * dev, ++ unsigned int cmd, ++ union iwreq_data * wrqu, ++ char * extra); ++ ++/* We may need a function to send a stream of events to user space. ++ * More on that later... */ ++ ++/************************* INLINE FUNTIONS *************************/ ++/* ++ * Function that are so simple that it's more efficient inlining them ++ */ ++ ++/*------------------------------------------------------------------*/ ++/* ++ * Wrapper to add an Wireless Event to a stream of events. ++ */ ++static inline char * ++iwe_stream_add_event(char * stream, /* Stream of events */ ++ char * ends, /* End of stream */ ++ struct iw_event *iwe, /* Payload */ ++ int event_len) /* Real size of payload */ ++{ ++ /* Check if it's possible */ ++ if((stream + event_len) < ends) { ++ iwe->len = event_len; ++ memcpy(stream, (char *) iwe, event_len); ++ stream += event_len; ++ } ++ return stream; ++} ++ ++/*------------------------------------------------------------------*/ ++/* ++ * Wrapper to add an short Wireless Event containing a pointer to a ++ * stream of events. ++ */ ++static inline char * ++iwe_stream_add_point(char * stream, /* Stream of events */ ++ char * ends, /* End of stream */ ++ struct iw_event *iwe, /* Payload */ ++ char * extra) ++{ ++ int event_len = IW_EV_POINT_LEN + iwe->u.data.length; ++ /* Check if it's possible */ ++ if((stream + event_len) < ends) { ++ iwe->len = event_len; ++ memcpy(stream, (char *) iwe, IW_EV_POINT_LEN); ++ memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length); ++ stream += event_len; ++ } ++ return stream; ++} ++ ++/*------------------------------------------------------------------*/ ++/* ++ * Wrapper to add a value to a Wireless Event in a stream of events. ++ * Be careful, this one is tricky to use properly : ++ * At the first run, you need to have (value = event + IW_EV_LCP_LEN). ++ */ ++static inline char * ++iwe_stream_add_value(char * event, /* Event in the stream */ ++ char * value, /* Value in event */ ++ char * ends, /* End of stream */ ++ struct iw_event *iwe, /* Payload */ ++ int event_len) /* Real size of payload */ ++{ ++ /* Don't duplicate LCP */ ++ event_len -= IW_EV_LCP_LEN; ++ ++ /* Check if it's possible */ ++ if((value + event_len) < ends) { ++ /* Add new value */ ++ memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len); ++ value += event_len; ++ /* Patch LCP */ ++ iwe->len = value - event; ++ memcpy(event, (char *) iwe, IW_EV_LCP_LEN); ++ } ++ return value; ++} ++ ++#endif /* _IW_HANDLER_H */ +diff -u -p -r --new-file linux/net/netsyms-w13.c linux/net/netsyms.c +--- linux/net/netsyms-w13.c Thu Jun 6 15:46:34 2002 ++++ linux/net/netsyms.c Thu Jun 6 15:47:44 2002 +@@ -588,4 +588,10 @@ EXPORT_SYMBOL(register_gifconf); + EXPORT_SYMBOL(net_call_rx_atomic); + EXPORT_SYMBOL(softnet_data); + ++#if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO) ++/* Don't include the whole header mess for a single function */ ++extern void wireless_send_event(struct net_device *dev, unsigned int cmd, union iwreq_data *wrqu, char *extra); ++EXPORT_SYMBOL(wireless_send_event); ++#endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ ++ + #endif /* CONFIG_NET */ +diff -u -p -r --new-file linux/net/core/wireless-w13.c linux/net/core/wireless.c +--- linux/net/core/wireless-w13.c Thu Jun 6 15:46:45 2002 ++++ linux/net/core/wireless.c Thu Jun 6 15:48:06 2002 +@@ -2,7 +2,7 @@ + * This file implement the Wireless Extensions APIs. + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> +- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. ++ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. + * + * (As all part of the Linux kernel, this file is GPL) + */ +@@ -25,6 +25,16 @@ + * o Added iw_handler handling ;-) + * o Added standard ioctl description + * o Initial dumb commit strategy based on orinoco.c ++ * ++ * v3 - 19.12.01 - Jean II ++ * o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call ++ * o Add event dispatcher function ++ * o Add event description ++ * o Propagate events as rtnetlink IFLA_WIRELESS option ++ * o Generate event on selected SET requests ++ * ++ * v4 - 18.04.01 - Jean II ++ * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1 + */ + + /***************************** INCLUDES *****************************/ +@@ -33,6 +43,7 @@ + #include <linux/config.h> /* Not needed ??? */ + #include <linux/types.h> /* off_t */ + #include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */ ++#include <linux/rtnetlink.h> /* rtnetlink stuff */ + + #include <linux/wireless.h> /* Pretty obvious */ + #include <net/iw_handler.h> /* New driver API */ +@@ -44,14 +55,23 @@ + + /* Debuging stuff */ + #undef WE_IOCTL_DEBUG /* Debug IOCTL API */ ++#undef WE_EVENT_DEBUG /* Debug Event dispatcher */ ++ ++/* Options */ ++#define WE_EVENT_NETLINK /* Propagate events using rtnetlink */ ++#define WE_SET_EVENT /* Generate an event on some set commands */ + + /************************* GLOBAL VARIABLES *************************/ + /* + * You should not use global variables, because or re-entrancy. + * On our case, it's only const, so it's OK... + */ ++/* ++ * Meta-data about all the standard Wireless Extension request we ++ * know about. ++ */ + static const struct iw_ioctl_description standard_ioctl[] = { +- /* SIOCSIWCOMMIT (internal) */ ++ /* SIOCSIWCOMMIT */ + { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, + /* SIOCGIWNAME */ + { IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, +@@ -99,18 +119,18 @@ static const struct iw_ioctl_description + { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, + /* SIOCGIWAPLIST */ + { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0}, +- /* -- hole -- */ +- { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, +- /* -- hole -- */ +- { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWSCAN */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWSCAN */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, 0}, + /* SIOCSIWESSID */ +- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_EVENT}, + /* SIOCGIWESSID */ +- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_DUMP}, + /* SIOCSIWNICKN */ +- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0}, + /* SIOCGIWNICKN */ +- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0}, + /* -- hole -- */ + { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, + /* -- hole -- */ +@@ -136,7 +156,7 @@ static const struct iw_ioctl_description + /* SIOCGIWRETRY */ + { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, + /* SIOCSIWENCODE */ +- { IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT}, + /* SIOCGIWENCODE */ + { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT}, + /* SIOCSIWPOWER */ +@@ -144,9 +164,38 @@ static const struct iw_ioctl_description + /* SIOCGIWPOWER */ + { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, + }; ++static const int standard_ioctl_num = (sizeof(standard_ioctl) / ++ sizeof(struct iw_ioctl_description)); ++ ++/* ++ * Meta-data about all the additional standard Wireless Extension events ++ * we know about. ++ */ ++static const struct iw_ioctl_description standard_event[] = { ++ /* IWEVTXDROP */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, ++ /* IWEVQUAL */ ++ { IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0}, ++}; ++static const int standard_event_num = (sizeof(standard_event) / ++ sizeof(struct iw_ioctl_description)); + + /* Size (in bytes) of the various private data types */ +-char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; ++static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; ++ ++/* Size (in bytes) of various events */ ++static const int event_type_size[] = { ++ IW_EV_LCP_LEN, ++ 0, ++ IW_EV_CHAR_LEN, ++ 0, ++ IW_EV_UINT_LEN, ++ IW_EV_FREQ_LEN, ++ IW_EV_POINT_LEN, /* Without variable payload */ ++ IW_EV_PARAM_LEN, ++ IW_EV_ADDR_LEN, ++ IW_EV_QUAL_LEN, ++}; + + /************************ COMMON SUBROUTINES ************************/ + /* +@@ -162,7 +211,8 @@ char priv_type_size[] = { 0, 1, 1, 0, 4, + static inline iw_handler get_handler(struct net_device *dev, + unsigned int cmd) + { +- unsigned int index; /* MUST be unsigned */ ++ /* Don't "optimise" the following variable, it will crash */ ++ unsigned int index; /* *MUST* be unsigned */ + + /* Check if we have some wireless handlers defined */ + if(dev->wireless_handlers == NULL) +@@ -269,9 +319,9 @@ static inline int sprintf_wireless_stats + stats->status, + stats->qual.qual, + stats->qual.updated & 1 ? '.' : ' ', +- stats->qual.level, ++ ((__u8) stats->qual.level), + stats->qual.updated & 2 ? '.' : ' ', +- stats->qual.noise, ++ ((__u8) stats->qual.noise), + stats->qual.updated & 4 ? '.' : ' ', + stats->discard.nwid, + stats->discard.code, +@@ -423,12 +473,14 @@ static inline int ioctl_standard_call(st + int ret = -EINVAL; + + /* Get the description of the IOCTL */ ++ if((cmd - SIOCIWFIRST) >= standard_ioctl_num) ++ return -EOPNOTSUPP; + descr = &(standard_ioctl[cmd - SIOCIWFIRST]); + + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n", ++ printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n", + ifr->ifr_name, cmd); +- printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); ++ printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); + #endif /* WE_IOCTL_DEBUG */ + + /* Prepare the call */ +@@ -437,8 +489,16 @@ static inline int ioctl_standard_call(st + + /* Check if we have a pointer to user space data or not */ + if(descr->header_type != IW_HEADER_TYPE_POINT) { ++ + /* No extra arguments. Trivial to handle */ + ret = handler(dev, &info, &(iwr->u), NULL); ++ ++#ifdef WE_SET_EVENT ++ /* Generate an event to notify listeners of the change */ ++ if((descr->flags & IW_DESCR_FLAG_EVENT) && ++ ((ret == 0) || (ret == -EIWCOMMIT))) ++ wireless_send_event(dev, cmd, &(iwr->u), NULL); ++#endif /* WE_SET_EVENT */ + } else { + char * extra; + int err; +@@ -466,8 +526,8 @@ static inline int ioctl_standard_call(st + } + + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Malloc %d bytes\n", +- descr->max_tokens * descr->token_size); ++ printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", ++ dev->name, descr->max_tokens * descr->token_size); + #endif /* WE_IOCTL_DEBUG */ + + /* Always allocate for max space. Easier, and won't last +@@ -488,7 +548,8 @@ static inline int ioctl_standard_call(st + return -EFAULT; + } + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Got %d bytes\n", ++ printk(KERN_DEBUG "%s (WE) : Got %d bytes\n", ++ dev->name, + iwr->u.data.length * descr->token_size); + #endif /* WE_IOCTL_DEBUG */ + } +@@ -504,11 +565,26 @@ static inline int ioctl_standard_call(st + if (err) + ret = -EFAULT; + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Wrote %d bytes\n", ++ printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n", ++ dev->name, + iwr->u.data.length * descr->token_size); + #endif /* WE_IOCTL_DEBUG */ + } + ++#ifdef WE_SET_EVENT ++ /* Generate an event to notify listeners of the change */ ++ if((descr->flags & IW_DESCR_FLAG_EVENT) && ++ ((ret == 0) || (ret == -EIWCOMMIT))) { ++ if(descr->flags & IW_DESCR_FLAG_RESTRICT) ++ /* If the event is restricted, don't ++ * export the payload */ ++ wireless_send_event(dev, cmd, &(iwr->u), NULL); ++ else ++ wireless_send_event(dev, cmd, &(iwr->u), ++ extra); ++ } ++#endif /* WE_SET_EVENT */ ++ + /* Cleanup - I told you it wasn't that long ;-) */ + kfree(extra); + } +@@ -558,11 +634,12 @@ static inline int ioctl_private_call(str + } + + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n", ++ printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n", + ifr->ifr_name, cmd); + if(descr) { +- printk(KERN_DEBUG "Name %s, set %X, get %X\n", +- descr->name, descr->set_args, descr->get_args); ++ printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n", ++ dev->name, descr->name, ++ descr->set_args, descr->get_args); + } + #endif /* WE_IOCTL_DEBUG */ + +@@ -617,7 +694,8 @@ static inline int ioctl_private_call(str + } + + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Malloc %d bytes\n", extra_size); ++ printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", ++ dev->name, extra_size); + #endif /* WE_IOCTL_DEBUG */ + + /* Always allocate for max space. Easier, and won't last +@@ -636,7 +714,8 @@ static inline int ioctl_private_call(str + return -EFAULT; + } + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length); ++ printk(KERN_DEBUG "%s (WE) : Got %d elem\n", ++ dev->name, iwr->u.data.length); + #endif /* WE_IOCTL_DEBUG */ + } + +@@ -650,8 +729,8 @@ static inline int ioctl_private_call(str + if (err) + ret = -EFAULT; + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Wrote %d elem\n", +- iwr->u.data.length); ++ printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n", ++ dev->name, iwr->u.data.length); + #endif /* WE_IOCTL_DEBUG */ + } + +@@ -730,4 +809,178 @@ int wireless_process_ioctl(struct ifreq + } + /* Not reached */ + return -EINVAL; ++} ++ ++/************************* EVENT PROCESSING *************************/ ++/* ++ * Process events generated by the wireless layer or the driver. ++ * Most often, the event will be propagated through rtnetlink ++ */ ++ ++#ifdef WE_EVENT_NETLINK ++/* "rtnl" is defined in net/core/rtnetlink.c, but we need it here. ++ * It is declared in <linux/rtnetlink.h> */ ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Fill a rtnetlink message with our event data. ++ * Note that we propage only the specified event and don't dump the ++ * current wireless config. Dumping the wireless config is far too ++ * expensive (for each parameter, the driver need to query the hardware). ++ */ ++static inline int rtnetlink_fill_iwinfo(struct sk_buff * skb, ++ struct net_device * dev, ++ int type, ++ char * event, ++ int event_len) ++{ ++ struct ifinfomsg *r; ++ struct nlmsghdr *nlh; ++ unsigned char *b = skb->tail; ++ ++ nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r)); ++ r = NLMSG_DATA(nlh); ++ r->ifi_family = AF_UNSPEC; ++ r->ifi_type = dev->type; ++ r->ifi_index = dev->ifindex; ++ r->ifi_flags = dev->flags; ++ r->ifi_change = 0; /* Wireless changes don't affect those flags */ ++ ++ /* Add the wireless events in the netlink packet */ ++ RTA_PUT(skb, IFLA_WIRELESS, ++ event_len, event); ++ ++ nlh->nlmsg_len = skb->tail - b; ++ return skb->len; ++ ++nlmsg_failure: ++rtattr_failure: ++ skb_trim(skb, b - skb->data); ++ return -1; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Create and broadcast and send it on the standard rtnetlink socket ++ * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c ++ * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field ++ * within a RTM_NEWLINK event. ++ */ ++static inline void rtmsg_iwinfo(struct net_device * dev, ++ char * event, ++ int event_len) ++{ ++ struct sk_buff *skb; ++ int size = NLMSG_GOODSIZE; ++ ++ skb = alloc_skb(size, GFP_ATOMIC); ++ if (!skb) ++ return; ++ ++ if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, ++ event, event_len) < 0) { ++ kfree_skb(skb); ++ return; ++ } ++ NETLINK_CB(skb).dst_groups = RTMGRP_LINK; ++ netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC); ++} ++#endif /* WE_EVENT_NETLINK */ ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Main event dispatcher. Called from other parts and drivers. ++ * Send the event on the apropriate channels. ++ * May be called from interrupt context. ++ */ ++void wireless_send_event(struct net_device * dev, ++ unsigned int cmd, ++ union iwreq_data * wrqu, ++ char * extra) ++{ ++ const struct iw_ioctl_description * descr = NULL; ++ int extra_len = 0; ++ struct iw_event *event; /* Mallocated whole event */ ++ int event_len; /* Its size */ ++ int hdr_len; /* Size of the event header */ ++ /* Don't "optimise" the following variable, it will crash */ ++ unsigned cmd_index; /* *MUST* be unsigned */ ++ ++ /* Get the description of the IOCTL */ ++ if(cmd <= SIOCIWLAST) { ++ cmd_index = cmd - SIOCIWFIRST; ++ if(cmd_index < standard_ioctl_num) ++ descr = &(standard_ioctl[cmd_index]); ++ } else { ++ cmd_index = cmd - IWEVFIRST; ++ if(cmd_index < standard_event_num) ++ descr = &(standard_event[cmd_index]); ++ } ++ /* Don't accept unknown events */ ++ if(descr == NULL) { ++ /* Note : we don't return an error to the driver, because ++ * the driver would not know what to do about it. It can't ++ * return an error to the user, because the event is not ++ * initiated by a user request. ++ * The best the driver could do is to log an error message. ++ * We will do it ourselves instead... ++ */ ++ printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n", ++ dev->name, cmd); ++ return; ++ } ++#ifdef WE_EVENT_DEBUG ++ printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n", ++ dev->name, cmd); ++ printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); ++#endif /* WE_EVENT_DEBUG */ ++ ++ /* Check extra parameters and set extra_len */ ++ if(descr->header_type == IW_HEADER_TYPE_POINT) { ++ /* Check if number of token fits within bounds */ ++ if(wrqu->data.length > descr->max_tokens) { ++ printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length); ++ return; ++ } ++ if(wrqu->data.length < descr->min_tokens) { ++ printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length); ++ return; ++ } ++ /* Calculate extra_len - extra is NULL for restricted events */ ++ if(extra != NULL) ++ extra_len = wrqu->data.length * descr->token_size; ++#ifdef WE_EVENT_DEBUG ++ printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len); ++#endif /* WE_EVENT_DEBUG */ ++ } ++ ++ /* Total length of the event */ ++ hdr_len = event_type_size[descr->header_type]; ++ event_len = hdr_len + extra_len; ++ ++#ifdef WE_EVENT_DEBUG ++ printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len); ++#endif /* WE_EVENT_DEBUG */ ++ ++ /* Create temporary buffer to hold the event */ ++ event = kmalloc(event_len, GFP_ATOMIC); ++ if(event == NULL) ++ return; ++ ++ /* Fill event */ ++ event->len = event_len; ++ event->cmd = cmd; ++ memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN); ++ if(extra != NULL) ++ memcpy(((char *) event) + hdr_len, extra, extra_len); ++ ++#ifdef WE_EVENT_NETLINK ++ /* rtnetlink event channel */ ++ rtmsg_iwinfo(dev, (char *) event, event_len); ++#endif /* WE_EVENT_NETLINK */ ++ ++ /* Cleanup */ ++ kfree(event); ++ ++ return; /* Always success, I guess ;-) */ + } diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/keyboard-ctrl+alt.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/keyboard-ctrl+alt.patch index e69de29bb2..93a80bae3c 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/keyboard-ctrl+alt.patch +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/keyboard-ctrl+alt.patch @@ -0,0 +1,79 @@ + +# +# Made by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux/drivers/char/corgi_rawmap.h~keyboard-ctrl+alt 2003-09-15 14:30:08.000000000 +0200 ++++ linux/drivers/char/corgi_rawmap.h 2003-09-16 00:45:39.000000000 +0200 +@@ -55,7 +55,7 @@ + SLKEY_ACTIVITY, SLKEY_W, SLKEY_S, SLKEY_F, SLKEY_V, SLKEY_H, SLKEY_M, SLKEY_L, KEY_IGN, SLKEY_RSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_CONTACTS, SLKEY_A, SLKEY_D, SLKEY_C, SLKEY_B, SLKEY_N, SLKEY_PERIOD, KEY_IGN, SLKEY_ENTER, KEY_IGN, SLKEY_LSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_MAIL, SLKEY_Z, SLKEY_X, SLKEY_MINUS, SLKEY_SPACE, SLKEY_COMMA, KEY_IGN, SLKEY_UP, KEY_IGN, KEY_IGN, KEY_IGN, SLKEY_2ND, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, +- SLKEY_HOME, SLKEY_KANA, SLKEY_ZENHAN, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, ++ SLKEY_HOME, SLKEY_LCONTROL, SLKEY_LALT, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_OFF, SLKEY_EXSELECT, SLKEY_EXCANCEL, SLKEY_EXJOGDOWN, SLKEY_EXJOGUP, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN}; + + static unsigned char rawkeytable_table_NormalUpper[(NR_KEYCODES+1)] = { +@@ -66,7 +66,7 @@ + SLKEY_ACTIVITY, SLKEY_W, SLKEY_S, SLKEY_F, SLKEY_V, SLKEY_H, SLKEY_M, SLKEY_L, KEY_IGN, SLKEY_RSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_CONTACTS, SLKEY_A, SLKEY_D, SLKEY_C, SLKEY_B, SLKEY_N, SLKEY_PERIOD, KEY_IGN, SLKEY_ENTER, KEY_IGN, SLKEY_LSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_MAIL, SLKEY_Z, SLKEY_X, SLKEY_MINUS, SLKEY_SPACE, SLKEY_COMMA, KEY_IGN, SLKEY_UP, KEY_IGN, KEY_IGN, KEY_IGN, SLKEY_2ND, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, +- SLKEY_HOME, SLKEY_KANA, SLKEY_ZENHAN, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, ++ SLKEY_HOME, SLKEY_LCONTROL, SLKEY_LALT, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_OFF, SLKEY_EXSELECT, SLKEY_EXCANCEL, SLKEY_EXJOGDOWN, SLKEY_EXJOGUP, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN}; + + static unsigned char rawkeytable_table_2ndLower[(NR_KEYCODES+1)] = { +@@ -77,7 +77,7 @@ + SLKEY_ACTIVITY, SLKEY_W, SLKEY_S, SLKEY_F, SLKEY_V, SLKEY_H, SLKEY_M, SLKEY_L, KEY_IGN, SLKEY_RSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_CONTACTS, SLKEY_A, SLKEY_D, SLKEY_C, SLKEY_B, SLKEY_N, SLKEY_PERIOD, KEY_IGN, SLKEY_ENTER, KEY_IGN, SLKEY_LSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_MAIL, SLKEY_Z, SLKEY_X, SLKEY_MINUS, SLKEY_SPACE, SLKEY_COMMA, KEY_IGN, SLKEY_UP, KEY_IGN, KEY_IGN, KEY_IGN, SLKEY_2ND, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, +- SLKEY_HOME, SLKEY_KANA, SLKEY_ZENHAN, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, ++ SLKEY_HOME, SLKEY_LCONTROL, SLKEY_LALT, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_OFF, SLKEY_EXSELECT, SLKEY_EXCANCEL, SLKEY_EXJOGDOWN, SLKEY_EXJOGUP, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN}; + + static unsigned char rawkeytable_table_2ndUpper[(NR_KEYCODES+1)] = { +@@ -88,7 +88,7 @@ + SLKEY_ACTIVITY, SLKEY_W, SLKEY_S, SLKEY_F, SLKEY_V, SLKEY_H, SLKEY_M, SLKEY_L, KEY_IGN, SLKEY_RSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_CONTACTS, SLKEY_A, SLKEY_D, SLKEY_PRINTSCREEN, SLKEY_B, SLKEY_N, SLKEY_PERIOD, KEY_IGN, SLKEY_ENTER, KEY_IGN, SLKEY_LSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_MAIL, SLKEY_Z, SLKEY_X, SLKEY_MINUS, SLKEY_SPACE, SLKEY_COMMA, KEY_IGN, SLKEY_UP, KEY_IGN, KEY_IGN, KEY_IGN, SLKEY_2ND, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, +- SLKEY_HOME, SLKEY_KANA, SLKEY_ZENHAN, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, ++ SLKEY_HOME, SLKEY_LCONTROL, SLKEY_LALT, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_OFF, SLKEY_EXSELECT, SLKEY_EXCANCEL, SLKEY_EXJOGDOWN, SLKEY_EXJOGUP, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN}; + + static unsigned char rawkeytable_table_NumlockLower[(NR_KEYCODES+1)] = { +@@ -99,7 +99,7 @@ + SLKEY_ACTIVITY, SLKEY_W, SLKEY_S, SLKEY_F, SLKEY_V, SLKEY_H, SLKEY_M, SLKEY_L, KEY_IGN, SLKEY_RSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_CONTACTS, SLKEY_A, SLKEY_D, SLKEY_C, SLKEY_B, SLKEY_N, SLKEY_PERIOD, KEY_IGN, SLKEY_ENTER, KEY_IGN, SLKEY_LSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_MAIL, SLKEY_Z, SLKEY_X, SLKEY_MINUS, SLKEY_SPACE, SLKEY_COMMA, KEY_IGN, SLKEY_UP, KEY_IGN, KEY_IGN, KEY_IGN, SLKEY_2ND, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, +- SLKEY_HOME, SLKEY_KANA, SLKEY_ZENHAN, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, ++ SLKEY_HOME, SLKEY_LCONTROL, SLKEY_LALT, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_OFF, SLKEY_EXSELECT, SLKEY_EXCANCEL, SLKEY_EXJOGDOWN, SLKEY_EXJOGUP, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN}; + + static unsigned char rawkeytable_table_NumlockUpper[(NR_KEYCODES+1)] = { +@@ -110,7 +110,7 @@ + SLKEY_ACTIVITY, SLKEY_W, SLKEY_S, SLKEY_F, SLKEY_V, SLKEY_H, SLKEY_M, SLKEY_L, KEY_IGN, SLKEY_RSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_CONTACTS, SLKEY_A, SLKEY_D, SLKEY_C, SLKEY_B, SLKEY_N, SLKEY_PERIOD, KEY_IGN, SLKEY_ENTER, KEY_IGN, SLKEY_LSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_MAIL, SLKEY_Z, SLKEY_X, SLKEY_MINUS, SLKEY_SPACE, SLKEY_COMMA, KEY_IGN, SLKEY_UP, KEY_IGN, KEY_IGN, KEY_IGN, SLKEY_2ND, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, +- SLKEY_HOME, SLKEY_KANA, SLKEY_ZENHAN, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, ++ SLKEY_HOME, SLKEY_LCONTROL, SLKEY_LALT, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_OFF, SLKEY_EXSELECT, SLKEY_EXCANCEL, SLKEY_EXJOGDOWN, SLKEY_EXJOGUP, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN}; + + static unsigned char rawkeytable_table_Num2ndLower[(NR_KEYCODES+1)] = { +@@ -121,7 +121,7 @@ + SLKEY_ACTIVITY, SLKEY_W, SLKEY_S, SLKEY_F, SLKEY_V, SLKEY_H, SLKEY_M, SLKEY_L, KEY_IGN, SLKEY_RSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_CONTACTS, SLKEY_A, SLKEY_D, SLKEY_C, SLKEY_B, SLKEY_N, SLKEY_PERIOD, KEY_IGN, SLKEY_ENTER, KEY_IGN, SLKEY_LSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_MAIL, SLKEY_Z, SLKEY_X, SLKEY_MINUS, SLKEY_SPACE, SLKEY_COMMA, KEY_IGN, SLKEY_UP, KEY_IGN, KEY_IGN, KEY_IGN, SLKEY_2ND, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, +- SLKEY_HOME, SLKEY_KANA, SLKEY_ZENHAN, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, ++ SLKEY_HOME, SLKEY_LCONTROL, SLKEY_LALT, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_OFF, SLKEY_EXSELECT, SLKEY_EXCANCEL, SLKEY_EXJOGDOWN, SLKEY_EXJOGUP, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN}; + + static unsigned char rawkeytable_table_Num2ndUpper[(NR_KEYCODES+1)] = { +@@ -132,7 +132,7 @@ + SLKEY_ACTIVITY, SLKEY_W, SLKEY_S, SLKEY_F, SLKEY_V, SLKEY_H, SLKEY_M, SLKEY_L, KEY_IGN, SLKEY_RSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_CONTACTS, SLKEY_A, SLKEY_D, SLKEY_PRINTSCREEN, SLKEY_B, SLKEY_N, SLKEY_PERIOD, KEY_IGN, SLKEY_ENTER, KEY_IGN, SLKEY_LSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_MAIL, SLKEY_Z, SLKEY_X, SLKEY_MINUS, SLKEY_SPACE, SLKEY_COMMA, KEY_IGN, SLKEY_UP, KEY_IGN, KEY_IGN, KEY_IGN, SLKEY_2ND, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, +- SLKEY_HOME, SLKEY_KANA, SLKEY_ZENHAN, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, ++ SLKEY_HOME, SLKEY_LCONTROL, SLKEY_LALT, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, + SLKEY_OFF, SLKEY_EXSELECT, SLKEY_EXCANCEL, SLKEY_EXJOGDOWN, SLKEY_EXJOGUP, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN}; + + diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/keymap-more-sane.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/keymap-more-sane.patch index e69de29bb2..a58dd13fbd 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/keymap-more-sane.patch +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/keymap-more-sane.patch @@ -0,0 +1,23 @@ +--- linux/drivers/char/corgi_keymap.map~keymap-more-sane 2003-08-30 01:05:14.000000000 +0200 ++++ linux/drivers/char/corgi_keymap.map 2003-09-03 20:44:27.000000000 +0200 +@@ -71,9 +71,11 @@ + # (Cancel:34) F9 -> Escape + keycode 34 = Escape + keycode 35 = Left ++ alt keycode 35 = Decr_Console + keycode 36 = Up + keycode 37 = Down + keycode 38 = Right ++ alt keycode 38 = Incr_Console + # (OK:39) F4 -> Return + keycode 39 = Return + keycode 40 = +@@ -100,7 +102,7 @@ + keycode 60 = Shift_Lock + keycode 61 = at + keycode 62 = question +-keycode 63 = comma slash ++keycode 63 = slash comma + alt keycode 63 = less + keycode 64 = period question + alt keycode 64 = greater diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/logo.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/logo.patch index e69de29bb2..c006684f23 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/logo.patch +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/logo.patch @@ -0,0 +1,2598 @@ +--- linux/drivers/video/fbcon.c 2003-02-27 21:47:36.000000000 -0600 ++++ linux.new/drivers/video/fbcon.c 2003-02-27 18:39:39.000000000 -0600 +@@ -126,8 +126,8 @@ + #define LOGO_H (320-16) + #define LOGO_W 240 + #else +-#define LOGO_H 80 +-#define LOGO_W 80 ++#define LOGO_H 52 ++#define LOGO_W 240 + #endif + #define LOGO_LINE (LOGO_W/8) + #if defined(CONFIG_SHARP_LOGO_SCREEN) +--- linux/include/linux/linux_logo.h 2001-06-11 21:15:27.000000000 -0500 ++++ linux.new/include/linux/linux_logo.h 2003-02-27 15:58:15.000000000 -0600 +@@ -1,4 +1,4 @@ +-/* $Id$ ++/* linux_logo.h created with fblogo, 2002/12/29 02:43:36 + * include/linux/linux_logo.h: This is a linux logo + * to be displayed on boot. + * +@@ -7,907 +7,1673 @@ + * + * You can put anything here, but: + * LINUX_LOGO_COLORS has to be less than 224 +- * image size has to be 80x80 +- * values have to start from 0x20 +- * (i.e. RGB(linux_logo_red[0], +- * linux_logo_green[0], +- * linux_logo_blue[0]) is color 0x20) +- * BW image has to be 80x80 as well, with MS bit +- * on the left +- * Serial_console ascii image can be any size, +- * but should contain %s to display the version ++ * Generated by fblogo version 0.5.0 ++ * ++ * ++ * Remember to modify drivers/video/fbcon.c: ++ * Change "#define LOGO_H 80" to "#define LOGO_H 52" ++ * Change "#define LOGO_W 80" to "#define LOGO_W 240" + */ + + #ifndef __HAVE_ARCH_LINUX_LOGO +-#define LINUX_LOGO_COLORS 187 ++#define LINUX_LOGO_COLORS 223 + #endif +- + #ifdef INCLUDE_LINUX_LOGO_DATA +- + #ifndef __HAVE_ARCH_LINUX_LOGO +- + unsigned char linux_logo_red[] __initdata = { +- 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22, +- 0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56, +- 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65, +- 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6, +- 0xc3, 0x65, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6, +- 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7, +- 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x76, 0x79, +- 0x62, 0x36, 0x9a, 0xe2, 0xec, 0xe1, 0xb8, 0xd7, +- 0xaf, 0x25, 0xbc, 0xc0, 0xef, 0xea, 0xe8, 0xe8, +- 0xf5, 0xf1, 0xda, 0xd3, 0x79, 0xdb, 0xf4, 0xf6, +- 0xf6, 0xf6, 0xe2, 0x3d, 0xb4, 0xce, 0xe6, 0xee, +- 0xf6, 0x68, 0xd8, 0xec, 0xf5, 0xc6, 0xc8, 0x9c, +- 0x89, 0xd2, 0xee, 0xcb, 0xb9, 0xd2, 0x66, 0x5e, +- 0x8b, 0xbe, 0xa8, 0xd5, 0xca, 0xb6, 0xae, 0x9c, +- 0xc5, 0xbe, 0xbe, 0xca, 0x90, 0xb2, 0x9a, 0xa8, +- 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x12, +- 0x4a, 0x8e, 0xf2, 0xf6, 0xf6, 0xee, 0xb5, 0xe4, +- 0xf1, 0x26, 0x9a, 0xea, 0xf6, 0xe0, 0xd2, 0x16, +- 0x9a, 0x2e, 0x70, 0xd6, 0x46, 0x7c, 0xb4, 0x62, +- 0xd6, 0xa3, 0x74, 0xa7, 0xa2, 0xca, 0xe0, 0xae, +- 0xbe, 0xce, 0xa3, 0x8e, 0x6d, 0x8e, 0x32, 0xaf, +- 0x50, 0x9e, 0x5b, 0x8a, 0x98, 0x82, 0x7a, 0x82, +- 0x56, 0x7c, 0x8a, 0x56, 0x5e, 0x86, 0x6a, 0x52, +- 0x59, 0x64, 0x5e, ++ 0x00, 0x02, 0x06, 0x0A, 0x56, 0xA6, 0xBE, 0xBA, ++ 0xB6, 0x92, 0x3E, 0x1A, 0x8A, 0xF3, 0xFB, 0xEE, ++ 0xC6, 0x62, 0x4A, 0x12, 0x26, 0x0E, 0x76, 0xDA, ++ 0x6E, 0x32, 0x8E, 0x1E, 0x2A, 0xCE, 0xE2, 0x36, ++ 0x66, 0xA2, 0x2E, 0x9E, 0xCA, 0x6A, 0x5A, 0x82, ++ 0x7E, 0xE9, 0xD2, 0xDE, 0x22, 0x72, 0xAE, 0xD6, ++ 0x86, 0x3A, 0x52, 0x9A, 0xAA, 0x16, 0x46, 0x4E, ++ 0x42, 0xC2, 0x96, 0x7A, 0x5E, 0xB2, 0x32, 0x7E, ++ 0x3A, 0x16, 0x02, 0x02, 0x06, 0x1F, 0x02, 0x02, ++ 0x06, 0x02, 0x22, 0x3A, 0x35, 0x16, 0x0A, 0x02, ++ 0x2A, 0x3E, 0x39, 0x32, 0x2A, 0x1E, 0x16, 0x06, ++ 0x22, 0x22, 0x1E, 0x16, 0x6E, 0x82, 0x6E, 0x2E, ++ 0x1E, 0x2E, 0x1E, 0x0A, 0x3A, 0xDA, 0xFE, 0xFA, ++ 0xFA, 0xE2, 0x6A, 0x3A, 0x1A, 0xFA, 0xF6, 0x9E, ++ 0x02, 0x6E, 0xFE, 0xF6, 0x3E, 0x66, 0x52, 0x1B, ++ 0xD6, 0x5A, 0xEE, 0xC6, 0x72, 0x36, 0x22, 0x1E, ++ 0x02, 0x96, 0xF6, 0xDE, 0xA2, 0xD6, 0x39, 0x0E, ++ 0xAA, 0x52, 0x5A, 0xD2, 0xDE, 0x61, 0x46, 0xDE, ++ 0x7A, 0x57, 0x9E, 0xBA, 0xB6, 0x4A, 0x5A, 0xA6, ++ 0x96, 0x23, 0x1E, 0x12, 0x9A, 0x4E, 0x76, 0xAE, ++ 0x2E, 0xBE, 0x86, 0x48, 0xA6, 0x52, 0x06, 0x2E, ++ 0x56, 0x13, 0x2A, 0x4A, 0x36, 0x56, 0x2E, 0x1E, ++ 0x46, 0x3A, 0x66, 0x02, 0x3D, 0x3E, 0x2E, 0x3E, ++ 0x4A, 0x32, 0x52, 0x72, 0x76, 0x67, 0x68, 0x5A, ++ 0x3A, 0x1A, 0x0E, 0x2E, 0x4E, 0x02, 0x3E, 0x0A, ++ 0x28, 0x42, 0x10, 0x26, 0x8E, 0x0A, 0x86, 0xC2, ++ 0x02, 0x6E, 0x92, 0x02, 0x42, 0x02, 0xBE, 0x4E, ++ 0x02, 0x22, 0x02, 0x3E, 0x3A, 0x32 + }; + + unsigned char linux_logo_green[] __initdata = { +- 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22, +- 0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56, +- 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65, +- 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6, +- 0xc3, 0x62, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6, +- 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7, +- 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x62, 0x5c, +- 0x4e, 0x26, 0x72, 0xaa, 0xba, 0xaf, 0x90, 0xae, +- 0x92, 0x1a, 0xa4, 0x85, 0xb6, 0xbe, 0xc3, 0xc8, +- 0xcf, 0xd0, 0xc2, 0xce, 0x57, 0xa2, 0xd6, 0xda, +- 0xda, 0xd7, 0xb8, 0x2a, 0x7b, 0x91, 0xae, 0xca, +- 0xda, 0x45, 0x9e, 0xb2, 0xd7, 0x9b, 0x90, 0x76, +- 0x5c, 0xa2, 0xbe, 0xa6, 0x85, 0x96, 0x4e, 0x46, +- 0x66, 0x92, 0x7a, 0x9a, 0x96, 0x9d, 0x9a, 0x6b, +- 0x8a, 0x8e, 0xb2, 0xca, 0x90, 0xa6, 0x79, 0x7c, +- 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x0e, +- 0x36, 0x86, 0xba, 0xbe, 0xe6, 0xcc, 0x8e, 0xb8, +- 0xc4, 0x1e, 0x8e, 0xae, 0xba, 0xb2, 0xa6, 0x12, +- 0x7a, 0x20, 0x64, 0xaa, 0x2f, 0x70, 0x85, 0x46, +- 0xa6, 0x6e, 0x51, 0x72, 0x92, 0xa2, 0xa6, 0x87, +- 0x96, 0xa2, 0x85, 0x7a, 0x6a, 0x6e, 0x22, 0x76, +- 0x36, 0x76, 0x3c, 0x6e, 0x63, 0x53, 0x66, 0x62, +- 0x42, 0x50, 0x56, 0x42, 0x56, 0x56, 0x56, 0x3e, +- 0x51, 0x52, 0x56, ++ 0x00, 0x02, 0x06, 0x0A, 0x56, 0xA6, 0xBE, 0xBA, ++ 0xB6, 0x92, 0x3E, 0x1A, 0x8A, 0xF3, 0xFB, 0xEE, ++ 0xC6, 0x62, 0x4A, 0x12, 0x26, 0x0E, 0x76, 0xDA, ++ 0x6E, 0x32, 0x8E, 0x1E, 0x2A, 0xCE, 0xE2, 0x36, ++ 0x66, 0xA2, 0x2E, 0x9E, 0xCA, 0x6A, 0x5A, 0x82, ++ 0x7E, 0xE9, 0xD2, 0xDE, 0x22, 0x72, 0xAE, 0xD6, ++ 0x86, 0x3A, 0x52, 0x9A, 0xAA, 0x16, 0x46, 0x4E, ++ 0x42, 0xC2, 0x96, 0x7A, 0x5E, 0xB2, 0x2E, 0x7E, ++ 0x3A, 0x3E, 0x6A, 0xA2, 0x92, 0x30, 0x95, 0x76, ++ 0x4E, 0x86, 0x36, 0x7E, 0x9A, 0x6E, 0x42, 0x56, ++ 0x5A, 0xC2, 0xBE, 0xB2, 0xAA, 0x9A, 0x63, 0x1E, ++ 0xA2, 0x9E, 0x96, 0x5A, 0x3A, 0x42, 0x4A, 0x52, ++ 0x91, 0x46, 0x4E, 0x62, 0x22, 0x4A, 0x6E, 0x86, ++ 0x92, 0x9A, 0x52, 0x4A, 0x76, 0x7A, 0x9E, 0x76, ++ 0x62, 0x32, 0x5E, 0xAE, 0x3E, 0x66, 0x52, 0x81, ++ 0xA6, 0x5A, 0xEE, 0xC6, 0x72, 0x5C, 0x6A, 0x8A, ++ 0x36, 0x3E, 0xBA, 0xBA, 0xA2, 0xD6, 0xAA, 0x4E, ++ 0x8A, 0x4E, 0x5A, 0xD2, 0xDE, 0x64, 0x32, 0x9A, ++ 0x5E, 0x57, 0x9E, 0xBA, 0xB6, 0x52, 0x62, 0xA6, ++ 0x9A, 0x47, 0x3E, 0x56, 0x02, 0x1A, 0x76, 0xAE, ++ 0x4A, 0x02, 0x02, 0x38, 0x02, 0x4A, 0x46, 0x86, ++ 0x1E, 0x2E, 0x7A, 0xD2, 0x5E, 0x26, 0x92, 0x62, ++ 0xCA, 0x42, 0x66, 0x26, 0x67, 0xB6, 0x62, 0x92, ++ 0x9E, 0x72, 0xB2, 0xF2, 0xFE, 0xDE, 0xFE, 0xFE, ++ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0x8A, 0x2A, ++ 0x42, 0x52, 0x6A, 0x26, 0x8E, 0x26, 0x86, 0xC2, ++ 0xE2, 0x6E, 0x92, 0xBE, 0x42, 0xC6, 0xBE, 0x4E, ++ 0xEE, 0x5A, 0xEA, 0x3E, 0x4A, 0x32 + }; + + unsigned char linux_logo_blue[] __initdata = { +- 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22, +- 0x12, 0x01, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56, +- 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x06, 0x65, +- 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6, +- 0xc3, 0x59, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6, +- 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7, +- 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x2e, 0x08, +- 0x0a, 0x06, 0x0a, 0x0b, 0x0b, 0x0f, 0x0c, 0x0f, +- 0x3d, 0x09, 0x73, 0x09, 0x0d, 0x0a, 0x10, 0x1e, +- 0x2d, 0x13, 0x86, 0xba, 0x19, 0x0a, 0x36, 0x3c, +- 0x26, 0x14, 0x0d, 0x06, 0x07, 0x0a, 0x0b, 0x0f, +- 0x4a, 0x06, 0x0a, 0x0c, 0x2b, 0x0a, 0x0b, 0x0a, +- 0x06, 0x0a, 0x0a, 0x11, 0x0b, 0x0a, 0x0a, 0x1e, +- 0x0f, 0x0d, 0x0a, 0x0b, 0x22, 0x6a, 0x72, 0x0b, +- 0x0b, 0x22, 0x90, 0xca, 0x90, 0x92, 0x3c, 0x2c, +- 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x06, +- 0x0e, 0x6a, 0x0e, 0x0e, 0xbe, 0x5b, 0x2c, 0x3e, +- 0x0e, 0x0a, 0x5a, 0x0d, 0x0e, 0x3e, 0x0a, 0x06, +- 0x2e, 0x06, 0x4e, 0x36, 0x06, 0x58, 0x24, 0x06, +- 0x3a, 0x08, 0x08, 0x07, 0x5e, 0x45, 0x0a, 0x32, +- 0x2e, 0x2a, 0x43, 0x48, 0x5f, 0x2e, 0x06, 0x06, +- 0x07, 0x24, 0x06, 0x32, 0x06, 0x06, 0x46, 0x2e, +- 0x22, 0x06, 0x06, 0x1e, 0x4c, 0x06, 0x3a, 0x22, +- 0x42, 0x34, 0x42, ++ 0x00, 0x02, 0x06, 0x0A, 0x56, 0xA6, 0xBE, 0xBA, ++ 0xB6, 0x92, 0x3E, 0x1A, 0x8A, 0xF3, 0xFB, 0xEE, ++ 0xC6, 0x62, 0x4A, 0x12, 0x26, 0x0E, 0x76, 0xDA, ++ 0x6E, 0x32, 0x8E, 0x1E, 0x2A, 0xCE, 0xE2, 0x36, ++ 0x66, 0xA2, 0x2E, 0x9E, 0xCA, 0x6A, 0x5A, 0x82, ++ 0x7E, 0xE9, 0xD2, 0xDE, 0x22, 0x72, 0xAE, 0xD6, ++ 0x86, 0x3A, 0x52, 0x9A, 0xAA, 0x16, 0x46, 0x4E, ++ 0x42, 0xC2, 0x96, 0x7A, 0x5E, 0xB2, 0x1A, 0x06, ++ 0x1A, 0x2A, 0x36, 0x52, 0x46, 0x23, 0x4D, 0x3E, ++ 0x2A, 0x42, 0x2A, 0x5A, 0x69, 0x42, 0x26, 0x2E, ++ 0x42, 0x7E, 0x7C, 0x72, 0x6A, 0x5E, 0x3B, 0x12, ++ 0x62, 0x5E, 0x5A, 0x36, 0x26, 0x1E, 0x26, 0x42, ++ 0x56, 0x3A, 0x36, 0x36, 0x1E, 0x2E, 0x2A, 0x22, ++ 0x22, 0x1A, 0x16, 0x42, 0x46, 0x26, 0x1E, 0x12, ++ 0x32, 0x2A, 0x2E, 0x16, 0x2A, 0x1A, 0x2E, 0x4E, ++ 0x12, 0x22, 0x02, 0x02, 0x12, 0x4A, 0x46, 0x52, ++ 0x1E, 0x1E, 0x16, 0x0E, 0x02, 0x02, 0x6F, 0x2E, ++ 0x0E, 0x1A, 0x06, 0x02, 0x02, 0x04, 0x22, 0x16, ++ 0x0E, 0x12, 0x02, 0x02, 0x02, 0x0A, 0x5A, 0x02, ++ 0x02, 0x1B, 0x2E, 0x32, 0x02, 0x02, 0x02, 0x02, ++ 0x16, 0x02, 0x02, 0x10, 0x02, 0x02, 0x26, 0x5A, ++ 0x02, 0x1F, 0x52, 0x8E, 0x22, 0x02, 0x5E, 0x3E, ++ 0x86, 0x0E, 0x16, 0x16, 0x52, 0x7A, 0x4A, 0x66, ++ 0x72, 0x52, 0x82, 0xB2, 0xBA, 0xA4, 0xB2, 0xAA, ++ 0x9E, 0x8E, 0x88, 0x96, 0xA6, 0x82, 0x62, 0x1A, ++ 0x34, 0x4A, 0x31, 0x16, 0x02, 0x1A, 0x02, 0x02, ++ 0x72, 0x02, 0x02, 0x5E, 0x1A, 0x62, 0x02, 0x0E, ++ 0x76, 0x1E, 0x76, 0x1E, 0x0A, 0x02 + }; + + unsigned char linux_logo[] __initdata = { +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, +- 0x22, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, +- 0x26, 0x26, 0x25, 0x28, 0x23, 0x22, 0x21, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x21, 0x23, 0x25, 0x2a, 0x2b, 0x2c, 0x2d, 0x2d, +- 0x2d, 0x2e, 0x2c, 0x2b, 0x2a, 0x25, 0x28, 0x22, +- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, +- 0x24, 0x2a, 0x2c, 0x2f, 0x2c, 0x30, 0x30, 0x24, +- 0x25, 0x27, 0x2b, 0x2c, 0x2f, 0x31, 0x32, 0x25, +- 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25, +- 0x33, 0x34, 0x35, 0x21, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x21, 0x2b, 0x2f, 0x2c, +- 0x30, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33, +- 0x2d, 0x27, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x31, +- 0x2d, 0x32, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, 0x2a, 0x34, +- 0x25, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x23, 0x32, 0x27, 0x21, 0x36, +- 0x2a, 0x2d, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x22, 0x26, 0x2c, 0x35, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x25, 0x2f, 0x37, 0x32, 0x22, +- 0x36, 0x35, 0x31, 0x27, 0x22, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x22, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x26, 0x38, 0x38, 0x35, 0x25, +- 0x36, 0x21, 0x2d, 0x2b, 0x24, 0x21, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x21, 0x24, 0x39, 0x39, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x25, 0x2b, 0x30, 0x28, 0x22, +- 0x36, 0x36, 0x27, 0x34, 0x30, 0x23, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x21, 0x26, 0x2d, 0x26, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x22, 0x22, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x2d, 0x33, 0x28, 0x21, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x2b, 0x2c, 0x25, 0x21, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x36, 0x36, +- 0x36, 0x21, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x21, 0x23, 0x22, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x28, 0x34, 0x27, 0x22, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36, +- 0x21, 0x21, 0x24, 0x27, 0x21, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x28, 0x27, 0x22, 0x33, 0x24, 0x36, +- 0x36, 0x36, 0x36, 0x22, 0x2f, 0x2a, 0x23, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36, +- 0x30, 0x3a, 0x38, 0x24, 0x24, 0x36, 0x36, 0x36, +- 0x23, 0x2f, 0x3b, 0x3c, 0x3d, 0x30, 0x25, 0x21, +- 0x36, 0x36, 0x36, 0x36, 0x2f, 0x32, 0x23, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x23, +- 0x3e, 0x3f, 0x40, 0x3a, 0x22, 0x36, 0x36, 0x21, +- 0x41, 0x42, 0x43, 0x44, 0x45, 0x3e, 0x23, 0x21, +- 0x36, 0x36, 0x36, 0x36, 0x2f, 0x33, 0x28, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x2b, +- 0x44, 0x40, 0x46, 0x47, 0x35, 0x36, 0x36, 0x26, +- 0x43, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x2e, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x23, 0x32, 0x34, 0x36, 0x4d, +- 0x4e, 0x25, 0x2f, 0x46, 0x4a, 0x22, 0x23, 0x32, +- 0x4f, 0x50, 0x21, 0x31, 0x51, 0x52, 0x53, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x21, 0x3a, +- 0x4d, 0x21, 0x31, 0x54, 0x55, 0x28, 0x30, 0x2b, +- 0x4b, 0x4d, 0x36, 0x23, 0x32, 0x50, 0x3f, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x29, 0x20, 0x29, 0x20, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x23, 0x2a, 0x38, 0x23, 0x37, +- 0x55, 0x36, 0x28, 0x3a, 0x56, 0x57, 0x57, 0x58, +- 0x3c, 0x4d, 0x36, 0x36, 0x36, 0x40, 0x40, 0x21, +- 0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x30, 0x51, 0x23, 0x35, +- 0x43, 0x25, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, +- 0x5f, 0x60, 0x61, 0x36, 0x31, 0x47, 0x3b, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x31, 0x2c, 0x25, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x22, +- 0x40, 0x62, 0x63, 0x5d, 0x64, 0x65, 0x66, 0x67, +- 0x68, 0x69, 0x66, 0x5e, 0x6a, 0x6b, 0x2a, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x33, 0x2e, 0x26, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x27, 0x2f, 0x23, 0x36, +- 0x6c, 0x63, 0x6d, 0x64, 0x5c, 0x66, 0x69, 0x6e, +- 0x6f, 0x70, 0x71, 0x69, 0x69, 0x72, 0x6c, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x33, 0x34, 0x27, 0x22, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x27, 0x34, 0x26, 0x73, +- 0x74, 0x75, 0x76, 0x64, 0x65, 0x77, 0x69, 0x78, +- 0x70, 0x71, 0x71, 0x71, 0x72, 0x5f, 0x5e, 0x21, +- 0x36, 0x36, 0x36, 0x36, 0x25, 0x38, 0x2a, 0x23, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x33, 0x79, +- 0x63, 0x7a, 0x7b, 0x5c, 0x66, 0x69, 0x6e, 0x7c, +- 0x71, 0x71, 0x69, 0x7d, 0x7e, 0x7a, 0x7f, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x21, 0x51, 0x2b, 0x28, +- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x32, 0x24, +- 0x80, 0x81, 0x64, 0x82, 0x77, 0x69, 0x71, 0x71, +- 0x69, 0x83, 0x84, 0x85, 0x7a, 0x85, 0x86, 0x36, +- 0x21, 0x2b, 0x23, 0x36, 0x36, 0x39, 0x2e, 0x26, +- 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x27, 0x2d, 0x33, 0x21, +- 0x87, 0x88, 0x89, 0x72, 0x67, 0x66, 0x5f, 0x89, +- 0x8a, 0x63, 0x85, 0x8b, 0x8c, 0x8d, 0x41, 0x36, +- 0x36, 0x2d, 0x3a, 0x35, 0x36, 0x24, 0x51, 0x32, +- 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x33, 0x21, +- 0x55, 0x8e, 0x8f, 0x8a, 0x7d, 0x5e, 0x90, 0x7e, +- 0x75, 0x75, 0x90, 0x62, 0x40, 0x3f, 0x49, 0x23, +- 0x36, 0x24, 0x3a, 0x3a, 0x24, 0x36, 0x2e, 0x31, +- 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x21, 0x28, 0x33, 0x37, 0x25, 0x22, +- 0x3b, 0x50, 0x8e, 0x8f, 0x90, 0x7e, 0x90, 0x63, +- 0x74, 0x91, 0x92, 0x42, 0x93, 0x4b, 0x45, 0x2c, +- 0x36, 0x36, 0x33, 0x39, 0x21, 0x36, 0x22, 0x51, +- 0x33, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x22, 0x27, 0x2e, 0x2e, 0x36, 0x21, +- 0x94, 0x3f, 0x50, 0x95, 0x96, 0x8f, 0x8f, 0x97, +- 0x8e, 0x42, 0x50, 0x43, 0x47, 0x48, 0x48, 0x98, +- 0x21, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, +- 0x2e, 0x27, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x22, 0x24, 0x2b, 0x38, 0x28, 0x36, 0x32, +- 0x4c, 0x4b, 0x50, 0x50, 0x50, 0x42, 0x42, 0x50, +- 0x50, 0x40, 0x45, 0x99, 0x48, 0x48, 0x48, 0x48, +- 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x23, +- 0x2f, 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x21, 0x28, 0x32, 0x51, 0x32, 0x28, 0x21, 0x98, +- 0x48, 0x47, 0x9a, 0x50, 0x50, 0x50, 0x50, 0x50, +- 0x9a, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x93, 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x2a, 0x2f, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, +- 0x23, 0x30, 0x2e, 0x2c, 0x36, 0x21, 0x51, 0x9b, +- 0x48, 0x48, 0x52, 0x3f, 0x50, 0x50, 0x40, 0x4b, +- 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x2d, 0x31, 0x27, 0x23, 0x21, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, +- 0x27, 0x2c, 0x2d, 0x21, 0x36, 0x28, 0x44, 0x48, +- 0x48, 0x48, 0x48, 0x47, 0x46, 0x4f, 0x47, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x9c, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x28, 0x51, 0x39, 0x26, 0x22, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25, +- 0x35, 0x51, 0x28, 0x36, 0x36, 0x9d, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x4f, 0x28, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x28, 0x38, 0x2b, 0x25, 0x22, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33, +- 0x51, 0x25, 0x36, 0x36, 0x23, 0x40, 0x9b, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x9b, 0x99, 0x2b, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x30, 0x2f, 0x33, 0x24, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x21, 0x23, 0x30, 0x34, +- 0x27, 0x36, 0x36, 0x36, 0x2a, 0x40, 0x47, 0x48, +- 0x48, 0x48, 0x48, 0x9b, 0x99, 0x99, 0x9b, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x47, 0x52, +- 0x46, 0x4f, 0x37, 0x21, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x30, 0x34, 0x2a, 0x23, +- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x22, 0x25, 0x39, 0x2c, +- 0x36, 0x36, 0x36, 0x21, 0x31, 0x4e, 0x9a, 0x4c, +- 0x47, 0x9b, 0x9b, 0x52, 0x46, 0x4f, 0x52, 0x9b, +- 0x9b, 0x9b, 0x47, 0x4f, 0x45, 0x9a, 0x93, 0x93, +- 0x3f, 0x93, 0x98, 0x28, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, 0x26, +- 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x28, +- 0x36, 0x36, 0x36, 0x22, 0x38, 0x98, 0x44, 0x99, +- 0x9b, 0x48, 0x48, 0x9b, 0x4c, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x47, 0x52, 0x46, 0x43, 0x93, +- 0x40, 0x40, 0x43, 0x53, 0x21, 0x23, 0x33, 0x23, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x2f, 0x32, +- 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x21, 0x24, 0x2b, 0x31, 0x36, +- 0x36, 0x22, 0x36, 0x24, 0x9e, 0x4f, 0x9b, 0x48, +- 0x48, 0x48, 0x48, 0x9b, 0x99, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x47, +- 0x4f, 0x9a, 0x3f, 0x46, 0x38, 0x36, 0x21, 0x30, +- 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, +- 0x25, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x26, 0x2e, 0x33, 0x36, +- 0x25, 0x25, 0x36, 0x4d, 0x52, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x47, 0x44, 0x93, 0x43, 0x23, 0x36, 0x36, +- 0x26, 0x24, 0x36, 0x36, 0x36, 0x36, 0x28, 0x2f, +- 0x2a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x23, 0x2a, 0x51, 0x24, 0x36, +- 0x2a, 0x36, 0x28, 0x44, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x9b, 0x4b, 0x44, 0x37, 0x36, 0x23, +- 0x28, 0x30, 0x22, 0x36, 0x36, 0x36, 0x36, 0x2d, +- 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x21, 0x28, 0x2b, 0x34, 0x36, 0x25, +- 0x24, 0x36, 0x4a, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x9b, 0x52, 0x3f, 0x21, 0x30, +- 0x35, 0x25, 0x30, 0x36, 0x36, 0x36, 0x36, 0x32, +- 0x2d, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x22, 0x26, 0x2e, 0x35, 0x36, 0x2a, +- 0x36, 0x24, 0x4f, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x47, 0x32, 0x30, +- 0x2a, 0x23, 0x30, 0x23, 0x36, 0x36, 0x36, 0x21, +- 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x21, 0x23, 0x2a, 0x51, 0x28, 0x28, 0x25, +- 0x36, 0x3a, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x9b, 0x52, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x38, 0x21, +- 0x36, 0x36, 0x22, 0x27, 0x36, 0x36, 0x36, 0x36, +- 0x2e, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x22, 0x25, 0x2c, 0x34, 0x36, 0x30, 0x21, +- 0x23, 0x43, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x47, 0x99, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x94, 0x36, +- 0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36, +- 0x2a, 0x2e, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x21, 0x23, 0x2a, 0x51, 0x25, 0x21, 0x2a, 0x36, +- 0x2e, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x99, 0x99, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x98, 0x36, +- 0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36, +- 0x22, 0x2f, 0x30, 0x22, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x22, 0x25, 0x2c, 0x34, 0x36, 0x24, 0x28, 0x36, +- 0x54, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4c, 0x99, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36, +- 0x36, 0x36, 0x36, 0x30, 0x36, 0x36, 0x36, 0x36, +- 0x21, 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, +- 0x28, 0x32, 0x2f, 0x28, 0x36, 0x27, 0x22, 0x21, +- 0x43, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4c, 0x99, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4b, 0x21, +- 0x36, 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, +- 0x25, 0x2c, 0x39, 0x36, 0x36, 0x30, 0x22, 0x25, +- 0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4f, 0x52, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4f, 0x21, +- 0x36, 0x36, 0x22, 0x26, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, +- 0x30, 0x2d, 0x21, 0x36, 0x36, 0x32, 0x23, 0x2a, +- 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4f, 0x99, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4c, 0x22, +- 0x36, 0x36, 0x24, 0x23, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, +- 0x33, 0x2e, 0x36, 0x36, 0x23, 0x31, 0x27, 0x39, +- 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4c, 0x23, +- 0x36, 0x36, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, +- 0x2b, 0x39, 0x36, 0x36, 0x36, 0x26, 0x32, 0x31, +- 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x46, 0x22, +- 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, +- 0x35, 0x39, 0x36, 0x36, 0x36, 0x36, 0x26, 0x2d, +- 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36, +- 0x24, 0x27, 0x9f, 0x24, 0x25, 0x28, 0x21, 0x36, +- 0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x25, +- 0x39, 0x4d, 0xa0, 0x84, 0x81, 0x57, 0x21, 0x39, +- 0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x53, 0x28, +- 0x23, 0x36, 0x36, 0x36, 0x21, 0x28, 0x2c, 0x30, +- 0x21, 0x38, 0x33, 0x28, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x28, 0x30, +- 0x2d, 0xa1, 0x7a, 0xa2, 0xa3, 0xa3, 0x7f, 0x22, +- 0x51, 0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0xa4, 0xa5, 0xa5, 0xa6, 0x61, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x30, 0x32, +- 0x25, 0x4d, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x21, 0x23, 0x24, 0x26, 0x30, 0x33, 0x31, +- 0x4d, 0x91, 0x5b, 0xa2, 0xa3, 0xa3, 0xa3, 0x5a, +- 0x21, 0x2e, 0x46, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0xa7, 0xa8, 0x69, 0x66, 0xa9, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x26, 0x25, +- 0x83, 0xaa, 0x2c, 0x25, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x21, 0x28, 0x30, 0x35, 0x2d, 0x2f, 0x37, 0x4a, +- 0x60, 0x85, 0xab, 0xac, 0xa3, 0xa3, 0xa3, 0x82, +- 0x86, 0x36, 0x32, 0x3f, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4c, 0x99, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0xad, 0xa2, 0xa8, 0xae, 0xaf, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x57, +- 0x77, 0x66, 0x34, 0x27, 0x22, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x23, 0x30, 0x31, 0xb0, 0x91, 0x7e, 0x90, 0x90, +- 0x8b, 0x5b, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0x5d, 0xb1, 0x36, 0x24, 0x53, 0x9b, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x9b, 0x99, 0xad, 0x64, 0x5c, 0x8b, 0xb1, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x73, 0x5d, +- 0x82, 0x5c, 0xb2, 0x2a, 0x23, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, +- 0x24, 0x2b, 0xb0, 0x8b, 0x5b, 0x76, 0x5b, 0x5b, +- 0x7b, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa8, 0x5e, 0x22, 0x36, 0x21, 0x3a, 0x99, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x4f, 0x3f, 0xb3, 0x7b, 0x7b, 0x85, 0x80, +- 0x9f, 0x36, 0x36, 0x36, 0x21, 0xb4, 0x7e, 0x7b, +- 0x64, 0x64, 0xb5, 0x35, 0x24, 0x21, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, +- 0x26, 0x31, 0xb6, 0x5b, 0x64, 0xa2, 0xa2, 0xac, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0x66, 0xb7, 0x36, 0x36, 0x36, 0x2c, 0x4b, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x9a, 0x3f, 0xb8, 0x76, 0x76, 0x7a, 0x63, +- 0xb9, 0xba, 0x86, 0xba, 0xbb, 0x90, 0x5b, 0x64, +- 0xa2, 0xa2, 0xbc, 0x2d, 0x27, 0x23, 0x21, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, +- 0x26, 0x2d, 0x91, 0x5b, 0x64, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa8, 0x83, 0xaf, 0x36, 0x36, 0x36, 0x30, +- 0x44, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x9b, 0x9a, 0x3f, 0xbd, 0x5b, 0x7b, 0xbe, 0x85, +- 0x7e, 0x90, 0x63, 0x90, 0x85, 0x5b, 0xa2, 0xa3, +- 0xa3, 0xac, 0x5d, 0xb5, 0x39, 0x26, 0x23, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, +- 0x26, 0x2d, 0xbf, 0xbe, 0x64, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa8, 0x88, 0x36, 0x36, 0x36, 0x36, +- 0x2d, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x9b, 0x45, 0x3f, 0xc0, 0x6d, 0x7b, 0xab, 0xbe, +- 0x7a, 0x8b, 0x8b, 0x7a, 0x5b, 0x64, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa2, 0xc1, 0x37, 0x35, 0x26, 0x23, +- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, +- 0x26, 0x2e, 0xbf, 0x7a, 0x7b, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa8, 0x72, 0x73, 0x36, 0x36, 0x36, +- 0x24, 0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x46, 0x42, 0xb6, 0x7a, 0x7b, 0x64, 0x7b, +- 0x76, 0x5b, 0x5b, 0x76, 0x7b, 0xa2, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xac, 0x64, 0xc1, 0x4d, 0x2c, 0x27, +- 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, +- 0x25, 0x31, 0xc2, 0x8b, 0x7b, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa8, 0x89, 0x9f, 0x36, 0x36, +- 0x32, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x4b, 0x2f, 0x8f, 0x7a, 0x7b, 0xa2, 0xac, +- 0xa2, 0x64, 0x64, 0xa2, 0xa2, 0xac, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0x5d, 0xc3, 0x2c, +- 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, +- 0x25, 0x31, 0xc2, 0x85, 0x7b, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0x66, 0x57, 0x27, 0x4d, +- 0x4b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x99, 0x34, 0x9f, 0xb9, 0x7a, 0x7b, 0xa2, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xc2, +- 0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, +- 0x26, 0x2d, 0xc2, 0x85, 0x7b, 0xac, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa8, 0x5f, 0x92, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x44, +- 0x35, 0x36, 0xaf, 0xbb, 0x7a, 0x7b, 0xac, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0xa2, 0xc0, +- 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, +- 0x30, 0x2f, 0xb6, 0x8b, 0x7b, 0xac, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x66, 0x89, 0x45, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x4e, 0x25, +- 0x36, 0x36, 0x61, 0xb9, 0x6d, 0x64, 0xac, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0x7b, 0xbe, 0xc3, +- 0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, +- 0x33, 0xc4, 0x63, 0xbe, 0xa2, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0x72, 0x81, 0xc5, +- 0x46, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x3f, 0x2c, 0x36, 0x36, +- 0x36, 0x36, 0xc6, 0x8f, 0x6d, 0x64, 0xac, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa2, 0xab, 0x8b, 0xb0, 0x2c, +- 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, +- 0x35, 0x96, 0x75, 0xab, 0xa2, 0xac, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0x7b, 0x81, 0xb9, +- 0x73, 0x3b, 0x44, 0x9b, 0x48, 0x48, 0x48, 0x9b, +- 0x99, 0x43, 0x94, 0x2c, 0x21, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x73, 0xb9, 0x7a, 0x7b, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0x64, 0x76, 0x7a, 0x91, 0xb5, 0x31, 0x30, +- 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, +- 0x39, 0x97, 0x75, 0xbe, 0x7b, 0x64, 0xa2, 0xa2, +- 0xac, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x7b, 0x7a, 0xc7, +- 0xc8, 0x36, 0x21, 0x26, 0x2b, 0x39, 0x33, 0x30, +- 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x21, 0xc8, 0xbb, 0x8b, 0x7b, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0x64, 0x64, +- 0x76, 0x85, 0xbf, 0xb5, 0x34, 0x2b, 0x27, 0x28, +- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, +- 0x33, 0xc9, 0x63, 0x7e, 0x7a, 0x6d, 0xbe, 0x5b, +- 0x76, 0x7b, 0x64, 0x64, 0xa2, 0xac, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0x76, 0x85, 0xb9, +- 0x79, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x21, 0xca, 0xbb, 0x75, 0x76, 0xa2, 0xa3, +- 0xa3, 0xa3, 0xac, 0xa2, 0x64, 0x76, 0xbe, 0x8b, +- 0xb6, 0xb5, 0x2f, 0x35, 0x30, 0x24, 0x22, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, +- 0x27, 0x31, 0xcb, 0xc9, 0xbb, 0x74, 0x63, 0x90, +- 0x7e, 0x75, 0x8b, 0x6d, 0xbe, 0x76, 0x64, 0xa2, +- 0xac, 0xac, 0xac, 0xac, 0x64, 0x7a, 0x84, 0xcc, +- 0x79, 0x9f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x21, 0xc8, 0xcc, 0x63, 0x6d, 0x7b, 0x64, +- 0xac, 0xa2, 0x64, 0x7b, 0xbe, 0x75, 0x63, 0x96, +- 0x38, 0x39, 0x2a, 0x24, 0x23, 0x21, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, +- 0x28, 0x27, 0x35, 0x2d, 0x41, 0xb5, 0xc5, 0x8f, +- 0xb9, 0xbb, 0xc7, 0x74, 0x84, 0x90, 0x85, 0x6d, +- 0x5b, 0x7b, 0x7b, 0xab, 0x6d, 0x90, 0xb9, 0xcd, +- 0xca, 0x22, 0x36, 0x36, 0x28, 0x30, 0x30, 0x30, +- 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x25, 0x36, +- 0x36, 0x21, 0xb4, 0x80, 0xc7, 0x7e, 0x6d, 0x76, +- 0xab, 0x76, 0x6d, 0x85, 0x63, 0xb9, 0xb5, 0x34, +- 0x33, 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x21, 0x23, 0x24, 0x27, 0x2a, 0x35, 0x2e, 0x2f, +- 0x41, 0xce, 0xcf, 0x6c, 0x80, 0xcc, 0xb9, 0x74, +- 0x84, 0x90, 0x75, 0x7e, 0x74, 0x8f, 0xcd, 0x79, +- 0xc6, 0x2b, 0x9d, 0x41, 0x2f, 0x34, 0x2d, 0x2d, +- 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x34, 0x2f, 0x38, +- 0x4d, 0x37, 0xd0, 0xd1, 0x8f, 0x74, 0x63, 0x7e, +- 0x75, 0x7e, 0x63, 0xc7, 0x88, 0xc4, 0x31, 0x2a, +- 0x24, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x21, 0x22, 0x23, 0x24, 0x26, 0x30, +- 0x33, 0x39, 0x2e, 0x51, 0x41, 0xb2, 0x6c, 0xd1, +- 0x80, 0xcc, 0xcc, 0xcc, 0xd2, 0xd1, 0xb7, 0xd3, +- 0x41, 0x34, 0x35, 0x32, 0x30, 0x27, 0x27, 0x27, +- 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x30, 0x2a, +- 0x2b, 0x34, 0xd4, 0xca, 0xd5, 0x8f, 0xbb, 0xc7, +- 0xc7, 0xbb, 0xcc, 0x6c, 0x41, 0x39, 0x27, 0x28, +- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, +- 0x28, 0x24, 0x26, 0x2a, 0x33, 0x2c, 0x2f, 0x41, +- 0xd6, 0xb7, 0x79, 0x79, 0x79, 0xca, 0xd7, 0x51, +- 0x39, 0x30, 0x24, 0x23, 0x22, 0x22, 0x22, 0x22, +- 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, +- 0x24, 0x2a, 0x31, 0xd8, 0xc8, 0x79, 0xd1, 0x80, +- 0xd5, 0xba, 0xd9, 0x2f, 0x35, 0x26, 0x23, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x21, 0x22, 0x23, 0x28, 0x25, 0x30, 0x2b, +- 0x31, 0x2f, 0xd4, 0xd8, 0xd8, 0x2f, 0x2e, 0x33, +- 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x21, 0x28, 0x27, 0x35, 0x34, 0xd8, 0xd8, 0xd8, +- 0xda, 0xd4, 0x2e, 0x33, 0x25, 0x23, 0x21, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x23, 0x28, +- 0x26, 0x30, 0x32, 0x2b, 0x33, 0x2a, 0x26, 0x28, +- 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x21, 0x23, 0x25, 0x30, 0x33, 0x35, 0x35, +- 0x2b, 0x2a, 0x26, 0x28, 0x22, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, +- 0x21, 0x22, 0x23, 0x28, 0x28, 0x23, 0x22, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x21, 0x23, 0x28, 0x24, 0x24, +- 0x28, 0x23, 0x22, 0x21, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x23, 0x33, 0x22, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x23, 0x61, 0x62, 0x2B, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x35, 0x61, 0x63, 0x64, 0x35, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x65, 0x66, 0x66, 0x67, 0x55, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3B, ++ 0x3B, 0x68, 0x64, 0x69, 0x62, 0x55, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x22, 0x23, 0x23, 0x55, 0x6A, 0x6B, ++ 0x6C, 0x6D, 0x6E, 0x6F, 0x6F, 0x33, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, ++ 0x22, 0x23, 0x35, 0x33, 0x3B, 0x70, 0x71, 0x72, ++ 0x73, 0x74, 0x75, 0x76, 0x77, 0x55, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x22, 0x23, 0x23, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x23, 0x55, ++ 0x2B, 0x34, 0x34, 0x42, 0x70, 0x71, 0x73, 0x78, ++ 0x78, 0x78, 0x79, 0x7A, 0x7B, 0x34, 0x22, 0x21, ++ 0x55, 0x33, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x22, 0x3B, 0x7C, 0x7D, 0x7E, 0x34, 0x35, ++ 0x21, 0x21, 0x21, 0x21, 0x35, 0x3B, 0x4C, 0x3C, ++ 0x42, 0x3F, 0x56, 0x7F, 0x71, 0x74, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x79, 0x80, 0x81, 0x3C, 0x82, ++ 0x83, 0x62, 0x61, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x23, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, ++ 0x3B, 0x21, 0x55, 0x55, 0x2B, 0x34, 0x39, 0x3F, ++ 0x2A, 0x57, 0x8B, 0x72, 0x74, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x75, 0x8C, 0x6F, 0x63, ++ 0x63, 0x66, 0x61, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x84, 0x85, 0x86, 0x8D, 0x88, 0x8E, 0x8F, 0x5E, ++ 0x3C, 0x34, 0x3B, 0x34, 0x3F, 0x2A, 0x58, 0x57, ++ 0x52, 0x46, 0x6C, 0x73, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x79, 0x7A, 0x6E, 0x69, ++ 0x69, 0x90, 0x34, 0x33, 0x22, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, ++ 0x91, 0x92, 0x8D, 0x87, 0x8E, 0x93, 0x8A, 0x35, ++ 0x94, 0x95, 0x96, 0x56, 0x32, 0x32, 0x52, 0x5C, ++ 0x4D, 0x82, 0x72, 0x78, 0x78, 0x78, 0x78, 0x79, ++ 0x97, 0x78, 0x78, 0x78, 0x78, 0x75, 0x6D, 0x6F, ++ 0x62, 0x65, 0x34, 0x4C, 0x33, 0x22, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B, ++ 0x91, 0x86, 0x87, 0x88, 0x93, 0x98, 0x60, 0x3F, ++ 0x99, 0x9A, 0x9A, 0x9B, 0x9C, 0x57, 0x5C, 0x36, ++ 0x9D, 0x9E, 0x6D, 0x78, 0x78, 0x78, 0x97, 0x6E, ++ 0x9F, 0x78, 0x78, 0x78, 0x78, 0x79, 0x80, 0xA0, ++ 0x61, 0x51, 0x51, 0x3C, 0x4C, 0x55, 0x35, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x3B, 0x22, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4C, ++ 0xA1, 0x8D, 0x88, 0x8E, 0xA2, 0xA3, 0x94, 0x42, ++ 0x51, 0xA4, 0x9A, 0x9A, 0x9A, 0xA5, 0x9C, 0x2A, ++ 0xA6, 0x74, 0x8C, 0x75, 0x97, 0xA7, 0x76, 0x75, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75, 0x6E, ++ 0x46, 0x52, 0x56, 0x3F, 0x42, 0x34, 0x33, 0x35, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x22, 0x22, 0x21, 0x21, 0x22, ++ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x3A, ++ 0x5A, 0x53, 0x53, 0x29, 0x43, 0x50, 0x53, 0x5A, ++ 0x5A, 0x29, 0x5A, 0x43, 0x53, 0x5D, 0x44, 0x2A, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x55, ++ 0x7D, 0x87, 0x8E, 0x93, 0xA8, 0xA9, 0xAA, 0x2A, ++ 0x57, 0x94, 0xA4, 0x9B, 0xAB, 0xAC, 0x9A, 0x9B, ++ 0xAD, 0x76, 0x79, 0x78, 0x75, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75, 0x6D, ++ 0x46, 0x5C, 0x57, 0x56, 0x51, 0x42, 0x4C, 0x55, ++ 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x23, 0x24, 0x25, 0x26, 0x26, 0x27, 0x28, 0x27, ++ 0x29, 0x2A, 0x2B, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x38, 0x30, ++ 0x59, 0x3D, 0x3D, 0x3D, 0x27, 0x27, 0x26, 0x5D, ++ 0x27, 0x27, 0x54, 0x37, 0x2E, 0x4A, 0x36, 0x2B, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0xAE, 0x88, 0xAF, 0xB0, 0xAA, 0x2A, 0x39, 0x34, ++ 0x4C, 0x5C, 0x58, 0xB1, 0xB2, 0xB3, 0xAB, 0xA5, ++ 0x9A, 0xB4, 0xB5, 0x8C, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x80, ++ 0xB6, 0x38, 0x5C, 0x57, 0x56, 0x3F, 0x42, 0x3B, ++ 0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, ++ 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x32, ++ 0x31, 0x2C, 0x26, 0x2C, 0x33, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x34, ++ 0x32, 0x2B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x33, ++ 0x33, 0x55, 0x55, 0x55, 0x23, 0x23, 0x35, 0x23, ++ 0x23, 0x35, 0x2B, 0x4E, 0x4F, 0x2A, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x55, 0x38, 0x25, ++ 0x2C, 0x52, 0x34, 0x22, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x55, 0x8A, 0x8F, 0x39, 0x34, 0x3C, 0x57, 0x32, ++ 0x46, 0x42, 0x52, 0x4A, 0x51, 0xAA, 0xB7, 0xB3, ++ 0xAB, 0xAC, 0xAC, 0xB8, 0xB9, 0x79, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x7A, ++ 0xBA, 0x70, 0x7B, 0xBB, 0x82, 0x56, 0x3F, 0x34, ++ 0x4C, 0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, 0x36, ++ 0x2D, 0x37, 0x38, 0x2A, 0x2B, 0x21, 0x21, 0x21, ++ 0x21, 0x22, 0x39, 0x3A, 0x2C, 0x3B, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x33, 0x3C, 0x22, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x24, 0x3D, ++ 0x3E, 0x25, 0x3C, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x33, 0x29, 0x26, 0x2A, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x54, 0x3E, 0x28, ++ 0x28, 0x59, 0x59, 0x48, 0x51, 0x3F, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x2B, 0x56, 0x4D, 0x29, 0x5B, 0x34, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x55, 0x60, 0x3F, 0x42, 0x51, 0x32, 0x52, ++ 0x40, 0x38, 0x40, 0x46, 0x42, 0xBC, 0xBD, 0xBE, ++ 0xBF, 0x9B, 0xAB, 0x9B, 0xC0, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75, ++ 0xA7, 0x63, 0x63, 0x66, 0x6F, 0x58, 0x56, 0x39, ++ 0x34, 0x2B, 0x23, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x2F, ++ 0x3D, 0x3F, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x22, 0x40, 0x41, 0x3B, 0x21, ++ 0x21, 0x22, 0x42, 0x38, 0x43, 0x44, 0x3A, 0x45, ++ 0x34, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x46, 0x30, 0x47, ++ 0x2A, 0x48, 0x48, 0x21, 0x21, 0x21, 0x21, 0x22, ++ 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x22, 0x34, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x22, 0x4D, 0x44, 0x2A, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x22, 0x50, 0x4A, 0x57, 0x35, ++ 0x35, 0x2B, 0x56, 0x27, 0x4B, 0x5D, 0x35, 0x21, ++ 0x21, 0x21, 0x21, 0x3B, 0x52, 0x23, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B, ++ 0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3B, 0x38, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33, ++ 0x3C, 0x42, 0x21, 0x33, 0x24, 0x35, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33, ++ 0x2B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x33, 0x38, 0x59, 0x37, 0x27, 0x27, 0x4A, 0x47, ++ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x23, 0x4C, 0x4C, 0x2A, 0x56, 0x46, 0x31, ++ 0x4D, 0x36, 0x50, 0x5A, 0x35, 0xC1, 0xC1, 0xC2, ++ 0xC3, 0xB7, 0xB3, 0xBE, 0x76, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75, ++ 0x6D, 0x62, 0x69, 0x6F, 0x58, 0x46, 0x32, 0x2A, ++ 0x39, 0x34, 0x35, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x3B, 0x44, 0x49, ++ 0x31, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x23, 0x29, 0x48, 0x22, ++ 0x42, 0x3A, 0x4A, 0x49, 0x4B, 0x2E, 0x4B, 0x3E, ++ 0x4A, 0x2C, 0x34, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x30, 0x40, 0x22, ++ 0x21, 0x32, 0x3A, 0x22, 0x21, 0x21, 0x21, 0x39, ++ 0x36, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, ++ 0x31, 0x4F, 0x2A, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x31, 0x59, 0x2A, 0x22, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x55, 0x27, 0x24, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x4C, 0x44, 0x27, 0x35, 0x21, ++ 0x21, 0x21, 0x21, 0x2A, 0x26, 0x2B, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3A, ++ 0x40, 0x21, 0x21, 0x21, 0x21, 0x21, 0x51, 0x49, ++ 0x35, 0x21, 0x21, 0x21, 0x21, 0x22, 0x58, 0x25, ++ 0x5A, 0x57, 0x21, 0x4C, 0x3D, 0x34, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x38, ++ 0x47, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, ++ 0x3A, 0x4B, 0x53, 0x56, 0x55, 0x33, 0x42, 0x56, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x55, 0x4C, 0x42, 0x2A, 0x57, 0x5C, 0x38, ++ 0x36, 0x47, 0x5A, 0xB6, 0x77, 0xC4, 0xC1, 0xC1, ++ 0xC4, 0xC5, 0xB7, 0xB9, 0x79, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75, ++ 0x97, 0xC6, 0x68, 0x57, 0x4D, 0x38, 0x46, 0x32, ++ 0x51, 0x42, 0x2B, 0x35, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x4D, 0x2D, 0x38, ++ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x4C, 0x4E, 0x3C, ++ 0x47, 0x4F, 0x50, 0x51, 0x3F, 0x44, 0x42, 0x34, ++ 0x52, 0x53, 0x28, 0x2A, 0x22, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x48, 0x54, 0x33, 0x21, ++ 0x23, 0x3A, 0x3A, 0x22, 0x21, 0x21, 0x21, 0x2A, ++ 0x26, 0x33, 0x21, 0x21, 0x21, 0x21, 0x23, 0x45, ++ 0x37, 0x3D, 0x41, 0x22, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x31, ++ 0x59, 0x3F, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x3C, 0x28, 0x33, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x23, 0x27, 0x5B, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x3C, 0x54, 0x55, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4C, 0x4B, ++ 0x46, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3B, 0x49, ++ 0x2B, 0x21, 0x21, 0x21, 0x23, 0x40, 0x43, 0x32, ++ 0x35, 0x21, 0x21, 0x33, 0x28, 0x4C, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x4F, ++ 0x5B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x50, ++ 0x44, 0x39, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x23, 0x3B, 0x34, 0x3F, 0x58, 0x46, 0x40, 0x36, ++ 0x50, 0x41, 0x4D, 0xC7, 0x65, 0xC2, 0xC1, 0xC1, ++ 0xC8, 0xBF, 0xB1, 0x97, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, ++ 0x80, 0xC9, 0x36, 0x50, 0x36, 0x38, 0x31, 0x32, ++ 0x56, 0x39, 0x34, 0x33, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x2B, 0x3D, 0x28, 0x35, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x40, 0x4D, ++ 0x55, 0x2B, 0x21, 0x21, 0x2B, 0x28, 0x3B, 0x21, ++ 0x21, 0x22, 0x52, 0x27, 0x56, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x23, 0x2A, 0x30, 0x3F, 0x21, 0x22, ++ 0x57, 0x44, 0x58, 0x21, 0x21, 0x21, 0x21, 0x56, ++ 0x37, 0x2B, 0x21, 0x21, 0x21, 0x21, 0x56, 0x3E, ++ 0x36, 0x2A, 0x59, 0x23, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x33, 0x50, 0x3D, ++ 0x42, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x40, 0x5A, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x56, 0x49, 0x24, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x42, 0x54, 0x33, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4D, 0x59, ++ 0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, 0x4A, ++ 0x51, 0x21, 0x21, 0x33, 0x47, 0x47, 0x33, 0x21, ++ 0x21, 0x21, 0x21, 0x55, 0x27, 0x3B, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x32, 0x4B, ++ 0x4C, 0x21, 0x21, 0x21, 0x21, 0x21, 0x34, 0x44, ++ 0x3F, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x33, 0x4C, 0x3C, 0x51, 0x57, 0x5C, 0x38, 0x38, ++ 0x9D, 0xCA, 0x61, 0xCB, 0xCC, 0xCD, 0xC4, 0xC8, ++ 0xA4, 0x9C, 0x76, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, ++ 0x7A, 0x7F, 0x41, 0x29, 0x47, 0x38, 0x40, 0x57, ++ 0x32, 0x51, 0x42, 0x2B, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x57, 0x49, 0x32, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x57, 0x27, ++ 0x35, 0x21, 0x21, 0x21, 0x2B, 0x59, 0x2A, 0x21, ++ 0x21, 0x21, 0x21, 0x56, 0x54, 0x2B, 0x21, 0x21, ++ 0x21, 0x21, 0x4C, 0x2E, 0x5A, 0x23, 0x55, 0x5B, ++ 0x49, 0x3A, 0x22, 0x21, 0x21, 0x21, 0x21, 0x32, ++ 0x3E, 0x3B, 0x21, 0x21, 0x21, 0x35, 0x54, 0x53, ++ 0x23, 0x55, 0x4F, 0x55, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x25, 0x44, 0x42, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x23, 0x41, 0x46, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x23, 0x53, 0x2F, 0x2A, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x32, 0x28, 0x33, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, 0x59, 0x5B, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x54, ++ 0x57, 0x21, 0x35, 0x53, 0x47, 0x23, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x3C, 0x44, 0x3B, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x41, 0x43, ++ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3F, 0x29, ++ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x55, 0x4C, 0x3F, 0x2A, 0x46, 0x31, 0x36, 0x46, ++ 0x71, 0x97, 0xCE, 0xCB, 0xCF, 0xA4, 0x9C, 0xA4, ++ 0xAD, 0x76, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0x8C, ++ 0x7A, 0xA7, 0x36, 0x50, 0x3A, 0x36, 0x38, 0x52, ++ 0x32, 0x2A, 0x3F, 0x2B, 0x22, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x22, 0x5A, 0x5A, 0x23, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x28, ++ 0x35, 0x21, 0x21, 0x21, 0x55, 0x30, 0x56, 0x21, ++ 0x21, 0x21, 0x21, 0x22, 0x5B, 0x45, 0x21, 0x21, ++ 0x21, 0x21, 0x2B, 0x2E, 0x25, 0x47, 0x3D, 0x2D, ++ 0x25, 0x4C, 0x21, 0x21, 0x21, 0x21, 0x21, 0x39, ++ 0x44, 0x55, 0x21, 0x21, 0x21, 0x46, 0x59, 0x3B, ++ 0x21, 0x23, 0x30, 0x34, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x2A, 0x28, 0x4E, 0x42, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x3C, 0x3D, 0x42, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x51, 0x4B, 0x49, 0x39, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x5C, 0x25, 0x23, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x38, 0x4B, 0x3B, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x54, ++ 0x56, 0x21, 0x5B, 0x3A, 0x35, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x51, 0x59, 0x55, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x32, 0x2D, 0x42, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4C, 0x3A, ++ 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x2B, 0x3C, 0x39, 0x56, 0x46, 0x40, 0x36, 0xB6, ++ 0x73, 0x82, 0xCB, 0xD0, 0x75, 0xD1, 0xD2, 0xD1, ++ 0x8C, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x74, 0xCE, ++ 0x9E, 0x6E, 0xD3, 0xC6, 0x6F, 0x81, 0x38, 0x5C, ++ 0x52, 0x58, 0x39, 0x4C, 0x35, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x4C, 0x4A, 0x40, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x3A, ++ 0x21, 0x21, 0x21, 0x21, 0x55, 0x27, 0x3F, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x25, 0x3B, 0x21, ++ 0x21, 0x21, 0x42, 0x2E, 0x2D, 0x2D, 0x26, 0x46, ++ 0x35, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x51, ++ 0x44, 0x55, 0x21, 0x21, 0x35, 0x25, 0x40, 0x21, ++ 0x21, 0x22, 0x4E, 0x58, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x39, 0x59, 0x38, 0x35, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x56, 0x59, 0x23, 0x21, 0x21, 0x21, ++ 0x21, 0x4C, 0x54, 0x5B, 0x59, 0x4C, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x57, 0x3A, 0x22, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x22, 0x4D, 0x49, 0x26, 0x23, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x53, ++ 0x32, 0x51, 0x27, 0x42, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x42, 0x25, 0x35, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x22, 0x24, 0x37, 0x3E, 0x35, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x48, ++ 0x48, 0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33, ++ 0x3B, 0x39, 0x3F, 0x32, 0x5C, 0x38, 0x47, 0xD4, ++ 0x7A, 0xC7, 0xCB, 0xD0, 0x74, 0x80, 0x8C, 0x9F, ++ 0x80, 0x79, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x73, 0x72, 0xD5, 0xCA, 0x61, 0xD3, 0x40, 0x5C, ++ 0x46, 0x58, 0x51, 0x42, 0x33, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x39, 0x4B, 0x58, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x2A, 0x3D, 0x51, ++ 0x21, 0x21, 0x21, 0x21, 0x55, 0x28, 0x42, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x47, 0x52, 0x21, ++ 0x21, 0x21, 0x58, 0x59, 0x42, 0x3C, 0x35, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x57, ++ 0x4E, 0x23, 0x21, 0x22, 0x4D, 0x54, 0x35, 0x21, ++ 0x21, 0x21, 0x5A, 0x46, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x22, 0x56, 0x59, 0x36, 0x35, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x36, 0x5B, 0x21, 0x21, 0x21, 0x21, ++ 0x23, 0x53, 0x48, 0x3F, 0x27, 0x55, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x24, 0x47, 0x22, 0x21, 0x21, ++ 0x21, 0x21, 0x22, 0x40, 0x27, 0x29, 0x29, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x47, ++ 0x40, 0x41, 0x5C, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x39, 0x41, 0x23, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x32, 0x26, 0x47, 0x28, 0x22, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B, ++ 0x53, 0x28, 0x36, 0x42, 0x23, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, ++ 0x4C, 0x39, 0x58, 0x32, 0x31, 0x38, 0x47, 0xD4, ++ 0xCF, 0xD0, 0x6C, 0x9E, 0xD6, 0x6B, 0xD7, 0xD8, ++ 0xD7, 0x6B, 0xCF, 0x7B, 0x80, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x74, 0x72, 0xD0, 0xA6, 0x70, 0x51, ++ 0x46, 0x56, 0x51, 0x42, 0x55, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x5C, 0x27, 0x35, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x32, 0x37, 0x54, 0x33, ++ 0x21, 0x21, 0x21, 0x21, 0x2B, 0x44, 0x2A, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x2C, 0x21, ++ 0x21, 0x21, 0x47, 0x36, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, ++ 0x54, 0x23, 0x21, 0x24, 0x4F, 0x46, 0x21, 0x21, ++ 0x21, 0x21, 0x38, 0x2C, 0x22, 0x21, 0x21, 0x21, ++ 0x21, 0x42, 0x55, 0x21, 0x21, 0x21, 0x21, 0x33, ++ 0x45, 0x54, 0x56, 0x22, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x22, 0x53, 0x24, 0x21, 0x21, 0x21, 0x21, ++ 0x46, 0x5D, 0x4C, 0x52, 0x4E, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x31, 0x48, 0x22, 0x21, 0x21, ++ 0x21, 0x22, 0x46, 0x54, 0x3B, 0x45, 0x29, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x47, ++ 0x28, 0x28, 0x55, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x51, 0x41, 0x22, 0x21, 0x21, ++ 0x21, 0x21, 0x56, 0x54, 0x39, 0x56, 0x28, 0x22, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x23, 0x34, 0x50, 0x30, 0x4E, 0x40, 0x34, 0x22, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, ++ 0x4C, 0x39, 0x58, 0x52, 0x5C, 0x38, 0x47, 0x9D, ++ 0xC9, 0xD9, 0xDA, 0xDB, 0xDC, 0xDC, 0xDC, 0xDC, ++ 0xDC, 0xDC, 0xDC, 0xDD, 0x6B, 0x7B, 0x75, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x74, 0x71, 0xD0, 0x3F, ++ 0x52, 0x57, 0x2A, 0x42, 0x2B, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x47, 0x3A, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x35, 0x45, 0x4A, 0x2C, 0x3B, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x2B, 0x30, 0x56, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x58, 0x29, 0x21, ++ 0x21, 0x21, 0x53, 0x3F, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x31, ++ 0x43, 0x22, 0x3B, 0x28, 0x48, 0x22, 0x21, 0x21, ++ 0x21, 0x21, 0x56, 0x25, 0x35, 0x21, 0x21, 0x21, ++ 0x39, 0x54, 0x34, 0x21, 0x21, 0x21, 0x35, 0x3A, ++ 0x30, 0x57, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x33, 0x39, 0x21, 0x21, ++ 0x21, 0x35, 0x25, 0x3F, 0x21, 0x21, 0x21, 0x56, ++ 0x30, 0x58, 0x21, 0x24, 0x43, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x4D, 0x29, 0x22, 0x21, 0x21, ++ 0x22, 0x32, 0x26, 0x42, 0x21, 0x46, 0x2C, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x48, ++ 0x2E, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x56, 0x28, 0x35, 0x21, 0x21, ++ 0x21, 0x3F, 0x27, 0x32, 0x21, 0x51, 0x25, 0x22, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x22, 0x39, 0x38, 0x25, 0x54, 0x50, ++ 0x58, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33, ++ 0x4C, 0x3F, 0x56, 0x52, 0x31, 0x4D, 0x47, 0x39, ++ 0xD8, 0xDC, 0xDC, 0xDC, 0xDE, 0xDF, 0xDF, 0xDF, ++ 0xDF, 0xDF, 0xDE, 0xDE, 0xDC, 0xDD, 0xD6, 0x97, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x75, 0x97, 0x56, ++ 0x46, 0x57, 0x2A, 0x42, 0x2B, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x38, 0x29, 0x22, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x35, 0x5B, 0x3D, 0x40, 0x35, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x2B, 0x59, 0x3F, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x40, 0x5A, 0x21, ++ 0x21, 0x22, 0x5D, 0x34, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x5B, ++ 0x2C, 0x33, 0x29, 0x28, 0x3B, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x34, 0x59, 0x3C, 0x21, 0x21, 0x2B, ++ 0x53, 0x36, 0x22, 0x21, 0x21, 0x34, 0x5A, 0x28, ++ 0x3F, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x40, 0x41, 0x23, 0x21, ++ 0x21, 0x3B, 0x28, 0x2B, 0x21, 0x21, 0x2A, 0x44, ++ 0x38, 0x22, 0x21, 0x24, 0x50, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x50, 0x25, 0x23, 0x21, 0x23, ++ 0x45, 0x5D, 0x52, 0x21, 0x21, 0x40, 0x50, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x50, ++ 0x2D, 0x39, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x46, 0x30, 0x33, 0x21, 0x22, ++ 0x24, 0x4E, 0x45, 0x22, 0x21, 0x58, 0x25, 0x22, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x33, 0x3C, 0x48, ++ 0x27, 0x39, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, ++ 0x34, 0x3F, 0x58, 0x57, 0x31, 0x4D, 0x47, 0x56, ++ 0xDB, 0xDC, 0xDE, 0xE0, 0xE1, 0xE2, 0xE2, 0xE2, ++ 0xE2, 0xE2, 0xE1, 0xE3, 0xE4, 0xDE, 0xDC, 0x6B, ++ 0x8C, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0xA7, 0x38, ++ 0x46, 0x56, 0x2A, 0x39, 0x3B, 0x23, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x32, 0x44, 0x34, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x3F, ++ 0x4D, 0x41, 0x29, 0x42, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x2B, 0x44, 0x46, 0x34, ++ 0x2B, 0x55, 0x55, 0x2B, 0x56, 0x59, 0x36, 0x21, ++ 0x21, 0x22, 0x59, 0x2B, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x55, 0x5C, 0x21, 0x21, 0x21, 0x40, ++ 0x50, 0x4D, 0x4F, 0x32, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x55, 0x44, 0x31, 0x22, 0x3B, 0x5A, ++ 0x41, 0x55, 0x21, 0x35, 0x57, 0x4A, 0x2E, 0x48, ++ 0x57, 0x32, 0x3F, 0x55, 0x35, 0x22, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x25, 0x47, 0x22, 0x21, ++ 0x21, 0x4C, 0x28, 0x35, 0x21, 0x34, 0x30, 0x3A, ++ 0x23, 0x21, 0x21, 0x58, 0x3A, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x4D, 0x4E, 0x35, 0x33, 0x48, ++ 0x44, 0x56, 0x21, 0x21, 0x21, 0x58, 0x41, 0x23, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x29, ++ 0x4A, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x32, 0x44, 0x2B, 0x23, 0x45, ++ 0x3D, 0x31, 0x22, 0x21, 0x21, 0x4C, 0x27, 0x35, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, ++ 0x53, 0x53, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, ++ 0x34, 0x3F, 0x58, 0x57, 0x40, 0x38, 0x47, 0xD4, ++ 0xDC, 0xDE, 0xE0, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE2, 0xE1, 0xDF, 0xDC, ++ 0xE6, 0x8C, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0x2A, 0x40, ++ 0x46, 0x58, 0x2A, 0x42, 0x34, 0x34, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x2B, 0x54, 0x5A, 0x34, 0x23, ++ 0x35, 0x23, 0x35, 0x33, 0x2B, 0x24, 0x54, 0x4B, ++ 0x59, 0x5C, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x4B, 0x44, 0x59, ++ 0x27, 0x26, 0x26, 0x4A, 0x3E, 0x41, 0x55, 0x21, ++ 0x21, 0x22, 0x41, 0x39, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x34, 0x53, 0x4D, 0x21, 0x21, 0x21, 0x5C, ++ 0x4B, 0x4F, 0x40, 0x22, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x48, 0x30, 0x50, 0x26, 0x54, ++ 0x34, 0x21, 0x55, 0x4E, 0x2D, 0x2F, 0x4F, 0x37, ++ 0x3E, 0x4B, 0x4B, 0x30, 0x27, 0x53, 0x2C, 0x57, ++ 0x42, 0x4C, 0x55, 0x22, 0x22, 0x22, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x39, 0x4A, 0x3F, 0x21, 0x21, ++ 0x21, 0x55, 0x53, 0x55, 0x2A, 0x26, 0x54, 0x33, ++ 0x21, 0x21, 0x21, 0x51, 0x54, 0x3B, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x51, 0x3D, 0x46, 0x5A, 0x4F, ++ 0x52, 0x21, 0x21, 0x21, 0x21, 0x22, 0x27, 0x31, ++ 0x33, 0x23, 0x42, 0x4C, 0x21, 0x21, 0x21, 0x5B, ++ 0x54, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x3B, 0x44, 0x45, 0x48, 0x4B, ++ 0x38, 0x22, 0x21, 0x21, 0x21, 0x21, 0x53, 0x48, ++ 0x33, 0x23, 0x34, 0x3C, 0x22, 0x57, 0x4D, 0x33, ++ 0x21, 0x21, 0x21, 0x21, 0x22, 0x23, 0x34, 0x40, ++ 0x44, 0x31, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, ++ 0x3B, 0x42, 0x2A, 0x57, 0x31, 0x38, 0x5C, 0xD8, ++ 0xDC, 0xE4, 0xE2, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE2, 0xE0, ++ 0xDE, 0xCA, 0x9F, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x80, 0x76, 0x57, 0x5C, ++ 0x31, 0x6E, 0x34, 0x3C, 0xC9, 0x3B, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x33, 0x5B, 0x30, 0x25, ++ 0x5D, 0x5A, 0x53, 0x27, 0x26, 0x59, 0x36, 0x56, ++ 0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x3D, 0x2A, 0x55, ++ 0x42, 0x51, 0x56, 0x24, 0x2A, 0x35, 0x21, 0x21, ++ 0x21, 0x21, 0x45, 0x53, 0x3B, 0x22, 0x22, 0x35, ++ 0x46, 0x59, 0x54, 0x55, 0x21, 0x21, 0x21, 0x31, ++ 0x2D, 0x47, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x33, 0x50, 0x5D, 0x45, 0x55, ++ 0x21, 0x21, 0x34, 0x4F, 0x29, 0x58, 0x33, 0x4C, ++ 0x39, 0x3C, 0x2A, 0x40, 0x48, 0x54, 0x3D, 0x3D, ++ 0x37, 0x4A, 0x59, 0x29, 0x5B, 0x36, 0x52, 0x2A, ++ 0x42, 0x3C, 0x32, 0x30, 0x41, 0x35, 0x21, 0x21, ++ 0x21, 0x33, 0x41, 0x26, 0x4B, 0x5A, 0x35, 0x21, ++ 0x21, 0x21, 0x21, 0x3C, 0x3E, 0x41, 0x23, 0x21, ++ 0x21, 0x21, 0x21, 0x23, 0x41, 0x49, 0x30, 0x32, ++ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x4F, ++ 0x5D, 0x41, 0x27, 0x58, 0x21, 0x21, 0x21, 0x5B, ++ 0x41, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x47, 0x49, 0x4F, 0x5C, ++ 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x39, 0x4A, ++ 0x28, 0x43, 0x27, 0x5C, 0x35, 0x25, 0x49, 0x5B, ++ 0x58, 0x52, 0x5C, 0x38, 0x48, 0x41, 0x4A, 0x4B, ++ 0x50, 0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, ++ 0x3B, 0x3C, 0x2A, 0x32, 0x5C, 0x40, 0x32, 0xDD, ++ 0xDC, 0xE3, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE1, 0xE0, 0xBB, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x80, 0xE7, 0x58, 0x52, ++ 0x5C, 0x67, 0xE7, 0x6C, 0xE8, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x23, 0x39, 0x5C, ++ 0x29, 0x5A, 0x4D, 0x5C, 0x2A, 0x2B, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x44, 0x42, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x33, 0x27, 0x30, 0x5A, 0x2C, 0x25, ++ 0x4B, 0x50, 0x3B, 0x21, 0x21, 0x21, 0x21, 0x33, ++ 0x2C, 0x3B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x4C, 0x22, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x55, 0x2B, ++ 0x39, 0x32, 0x4D, 0x29, 0x26, 0x3D, 0x2D, 0x2D, ++ 0x4B, 0x4B, 0x2F, 0x30, 0x42, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x3B, 0x29, 0x2C, 0x55, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x23, 0x50, 0x4D, 0x22, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x2B, 0x32, 0x3B, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x51, ++ 0x48, 0x45, 0x34, 0x21, 0x21, 0x21, 0x21, 0x38, ++ 0x44, 0x35, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x33, 0x32, 0x34, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3C, ++ 0x5B, 0x4D, 0x42, 0x21, 0x21, 0x34, 0x4D, 0x47, ++ 0x5A, 0x5D, 0x27, 0x4E, 0x25, 0x3A, 0x5C, 0x42, ++ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, ++ 0x2B, 0x34, 0x51, 0x56, 0x46, 0x40, 0xE9, 0xDA, ++ 0xDD, 0xE1, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE2, 0xEA, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x76, 0xD3, 0x67, 0x39, ++ 0x3C, 0xCF, 0xD5, 0x9F, 0x3B, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x28, 0x2B, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x3C, 0x53, 0x44, 0x3D, 0x43, ++ 0x57, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x35, 0x55, 0x3F, 0x2A, ++ 0x57, 0x24, 0x3F, 0x3B, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x22, 0x22, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x55, ++ 0x3C, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x55, 0x4C, 0x3F, 0x58, 0x46, 0x31, 0x8B, 0xAD, ++ 0xCC, 0xE2, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xEA, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x97, 0x35, 0x6E, 0xC6, 0x82, ++ 0xA6, 0x73, 0x75, 0xBA, 0x2B, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x34, 0x44, 0x3B, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x23, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x33, 0x34, 0xEB, 0x34, 0x57, 0x5C, 0x4C, 0xA4, ++ 0xEC, 0x64, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0x83, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x80, 0xED, 0xCF, 0xCE, 0x78, 0x78, ++ 0x78, 0x7A, 0x6D, 0x34, 0x22, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x55, 0x25, 0x55, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x23, 0x34, 0xEE, 0xEF, 0x5F, 0x96, 0x23, 0xB3, ++ 0xBF, 0xB5, 0xF0, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xBB, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x9F, 0x78, 0x78, 0x78, 0x78, ++ 0x80, 0x9F, 0x65, 0x33, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x28, 0x55, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x22, 0x4C, 0xF1, 0xA5, 0xAC, 0xAB, 0x60, 0xB3, ++ 0xB3, 0xF2, 0xEA, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xF3, 0x6D, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x80, 0x61, 0x34, 0x23, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x25, 0x22, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B, 0x5E, ++ 0x4C, 0x3B, 0xF4, 0xA5, 0x9B, 0x9B, 0xB4, 0xEF, ++ 0xEF, 0xBF, 0xAD, 0xF5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0x67, 0x75, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x80, ++ 0xA7, 0x3F, 0x55, 0x22, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x4E, 0x23, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B, 0x5F, ++ 0x9B, 0xD2, 0x3C, 0xB7, 0xEF, 0xEF, 0xEF, 0xEF, ++ 0xEF, 0xB3, 0xB8, 0xEA, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xF0, 0xBB, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0x82, ++ 0x34, 0x3B, 0x33, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x5D, 0x23, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x60, ++ 0xAB, 0xA5, 0xB8, 0xB1, 0xEF, 0xEF, 0xEF, 0xEF, ++ 0xEF, 0xF6, 0xB7, 0xB5, 0xF0, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0x67, 0x80, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x80, 0x9F, 0xBA, 0x42, ++ 0x4C, 0x2B, 0x22, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x3A, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x55, ++ 0xF2, 0x9B, 0x9B, 0xB4, 0xEF, 0xEF, 0xEF, 0xEF, ++ 0xEF, 0xEF, 0xB4, 0x5F, 0x63, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xF5, ++ 0x76, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x80, 0x6D, 0x65, 0x3C, 0x34, ++ 0x3B, 0x35, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x2A, 0x29, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, ++ 0xF7, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, ++ 0xEF, 0xEF, 0xB3, 0xB8, 0xEA, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xF8, 0x68, ++ 0x7A, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x80, 0x97, 0x82, 0x39, 0x39, 0x34, 0x3B, ++ 0x33, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x2A, 0x29, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x3B, 0xB8, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, ++ 0xEF, 0xEF, 0xF6, 0xB2, 0xF9, 0xFA, 0xFA, 0xFA, ++ 0xFA, 0xF8, 0xF8, 0xF8, 0xF0, 0xF0, 0x6F, 0x97, ++ 0x80, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x8C, 0x61, 0x39, 0x2A, 0x3F, 0x3C, 0x4C, 0x55, ++ 0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x31, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x22, 0xFB, 0xF6, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, ++ 0xEF, 0xEF, 0xB3, 0xB2, 0xF9, 0xF3, 0xF3, 0xF3, ++ 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0x90, 0x6D, 0x97, ++ 0x8C, 0x6D, 0x76, 0xBB, 0xC6, 0xB9, 0xC0, 0xFC, ++ 0xAD, 0xFB, 0x2A, 0x58, 0x42, 0x4C, 0x55, 0x33, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x33, 0xD2, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, ++ 0xEF, 0xEF, 0xB4, 0xB8, 0xEB, 0xE8, 0x7F, 0xD6, ++ 0xD6, 0xD6, 0xD6, 0x9D, 0x9D, 0x52, 0xEB, 0x5F, ++ 0x5F, 0x5F, 0xF2, 0xA4, 0xBF, 0xBF, 0xB4, 0xBF, ++ 0xEE, 0x56, 0x2A, 0x42, 0x4C, 0x2B, 0x33, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x4C, 0xBE, 0xF6, 0xEF, 0xEF, 0xEF, ++ 0xF6, 0xB4, 0xB2, 0xF1, 0x3C, 0x56, 0x46, 0x5C, ++ 0x31, 0x38, 0x40, 0x40, 0x4D, 0x4D, 0xB8, 0xAC, ++ 0xBF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xB4, ++ 0xB1, 0x39, 0x39, 0x3B, 0x2B, 0x23, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x3B, 0xAD, 0xA4, 0xBF, 0xBF, ++ 0xB7, 0xB2, 0xEE, 0x5E, 0x39, 0x51, 0x2A, 0x32, ++ 0x52, 0x46, 0x5C, 0x31, 0x31, 0x2A, 0xA5, 0xEF, ++ 0xFD, 0xB4, 0xEF, 0xF6, 0xF6, 0xEF, 0xF6, 0xB2, ++ 0x3F, 0x34, 0x2B, 0x55, 0x23, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x33, 0xEB, 0xF7, 0xAA, ++ 0xAA, 0xF7, 0xEB, 0x55, 0x3B, 0x3C, 0x39, 0x51, ++ 0x2A, 0x56, 0x32, 0x57, 0x57, 0x2A, 0x96, 0x3C, ++ 0x2A, 0xEE, 0xEF, 0x5F, 0xD2, 0xEF, 0xB4, 0xAA, ++ 0x42, 0x55, 0x35, 0x22, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x3B, ++ 0x3B, 0x35, 0x21, 0x23, 0x33, 0x3B, 0x4C, 0x3C, ++ 0x39, 0x3F, 0x51, 0x2A, 0x51, 0x51, 0x58, 0x32, ++ 0x56, 0xF4, 0xB1, 0x42, 0x3C, 0xF2, 0x9C, 0x3F, ++ 0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x33, 0x55, ++ 0x3B, 0x4C, 0x4C, 0x3C, 0x42, 0x42, 0x3C, 0x34, ++ 0x34, 0x3F, 0x4C, 0x3B, 0x4C, 0x3B, 0x3C, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x35, 0x33, 0x55, 0x33, 0x33, 0x33, 0x55, 0x2B, ++ 0x2B, 0x35, 0x35, 0x35, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 + }; + + #endif /* !__HAVE_ARCH_LINUX_LOGO */ +@@ -994,7 +1760,7 @@ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + #endif /* !__HAVE_ARCH_LINUX_LOGOBW */ +@@ -1401,7 +2167,7 @@ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + #endif /* !__HAVE_ARCH_LINUX_LOGO16 */ diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/mkdep.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/mkdep.patch index e69de29bb2..4daeaa11be 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/mkdep.patch +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/mkdep.patch @@ -0,0 +1,16 @@ + +# +# Made by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux/Makefile~mkdep 2003-12-19 09:36:51.000000000 -0800 ++++ linux/Makefile 2003-12-19 09:57:44.000000000 -0800 +@@ -458,7 +458,7 @@ + + dep-files: scripts/mkdep archdep include/linux/version.h + scripts/mkdep -- init/*.c > .depend +- scripts/mkdep -- `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend ++ $(foreach, dir, $(FINDHPATH), scripts/mkdep -- `find $(dir) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` >> .hdepend) + $(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)" + ifdef CONFIG_MODVERSIONS + $(MAKE) update-modverfile diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/swap-performance.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/swap-performance.patch index e69de29bb2..1cde717bb4 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/swap-performance.patch +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/swap-performance.patch @@ -0,0 +1,19 @@ +*** ../linux/mm/swap.c Tue Jan 14 14:54:41 2003 +--- linux/mm/swap.c Sun Sep 28 21:34:25 2003 +*************** +*** 32,38 **** + int page_cluster; + + pager_daemon_t pager_daemon = { +! 512, /* base number for calculating the number of tries */ + SWAP_CLUSTER_MAX, /* minimum number of tries */ + 8, /* do swap I/O in clusters of this size */ + }; +--- 32,38 ---- + int page_cluster; + + pager_daemon_t pager_daemon = { +! 128, /* base number for calculating the number of tries */ + SWAP_CLUSTER_MAX, /* minimum number of tries */ + 8, /* do swap I/O in clusters of this size */ + }; diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch index e69de29bb2..c9296cf224 100644 --- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch +++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch @@ -0,0 +1,3433 @@ +diff -Nur linux-2.4.18/drivers/usb/device/bi/sa1100.c linux-2.4.18-usb-storage/drivers/usb/device/bi/sa1100.c +--- linux-2.4.18/drivers/usb/device/bi/sa1100.c 2003-05-13 13:18:44.000000000 +0400 ++++ linux-2.4.18-usb-storage/drivers/usb/device/bi/sa1100.c 2004-03-01 07:20:38.000000000 +0300 +@@ -440,6 +440,7 @@ + udc_interrupts, *(UDCSR), *(UDCCS0), *(UDCAR)); + + usbd_device_event (udc_device, DEVICE_RESET, 0); ++ usbd_device_event (udc_device, DEVICE_ADDRESS_ASSIGNED,0); + } + + if (status & UDCSR_SUSIR) { +diff -Nur linux-2.4.18/drivers/usb/device/Config.in linux-2.4.18-usb-storage/drivers/usb/device/Config.in +--- linux-2.4.18/drivers/usb/device/Config.in 2003-05-13 13:18:45.000000000 +0400 ++++ linux-2.4.18-usb-storage/drivers/usb/device/Config.in 2003-11-07 05:35:14.000000000 +0300 +@@ -34,6 +34,7 @@ + comment 'USB Device functions' + source drivers/usb/device/net_fd/Config.in + source drivers/usb/device/serial_fd/Config.in ++ source drivers/usb/device/storage_fd/Config.in + + comment 'USB Device bus interfaces' + source drivers/usb/device/bi/Config.in +diff -Nur linux-2.4.18/drivers/usb/device/Makefile linux-2.4.18-usb-storage/drivers/usb/device/Makefile +--- linux-2.4.18/drivers/usb/device/Makefile 2003-05-13 13:18:45.000000000 +0400 ++++ linux-2.4.18-usb-storage/drivers/usb/device/Makefile 2003-11-07 05:35:01.000000000 +0300 +@@ -20,6 +20,7 @@ + + subdir-$(CONFIG_USBD_NET) += net_fd + subdir-$(CONFIG_USBD_SERIAL) += serial_fd ++subdir-$(CONFIG_USBD_STORAGE) += storage_fd + + #subdir-$(CONFIG_USBD_GENERIC_BUS) += gen_bi + #subdir-$(CONFIG_USBD_L7205_BUS) += l7205_bi +diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/Config.help linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/Config.help +--- linux-2.4.18/drivers/usb/device/storage_fd/Config.help 1970-01-01 03:00:00.000000000 +0300 ++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/Config.help 2003-11-07 05:34:43.000000000 +0300 +@@ -0,0 +1,55 @@ ++CONFIG_USBD_STORAGE ++ Enable the generic mass storage function driver. This function is ++ used emulating a Linux block driver. ++ ++CONFIG_USBD_STORAGE_VENDORID ++ Optionally specify the mass storage USB Device Vendor ID. The top ++ level Vendor ID will be used if this is not specified. ++ ++CONFIG_USBD_STORAGE_PRODUCTID ++ Optionally specify the mass storage USB Device Product ID. The top ++ level Vendor ID will be used if this is not specified. ++ ++CONFIG_USBD_STORAGE_OUT_ENDPOINT ++ Specify the preferred OUT (received data) endpoint number. This is a ++ number from 0-15 and must be allowed by the bus interface device. ++ ++ Some devices such as the SA-1110 or L7205/L7210 may override this ++ value with a fixed value. ++ ++CONFIG_USBD_STORAGE_IN_ENDPOINT ++ Specify the preferred IN (transmit data) endpoint number. This is a ++ number from 0-15 and must be allowed by the bus interface device. ++ ++ Some devices such as the SA-1110 or L7205/L7210 may override this ++ value with a fixed value. ++ ++CONFIG_USBD_STORAGE_INT_ENDPOINT ++ Specify the preferred INT (interrupt) endpoint number. This is a ++ number from 0-15 and must be allowed by the bus interface device. ++ ++ Some devices such as the L7205/L7210 may override this value with a ++ fixed value. Others such as the SA-1110 do not allow an interrupt ++ value. ++ ++CONFIG_USBD_STORAGE_OUT_PKTSIZE ++ Specify the maximum packet size for the OUT endpoint. This allowable ++ values are normally 16, 32 and 64. ++ ++ Some devices such as the Linkup L7205/L7210 may override this value ++ with a lower maximum value (such as 32). ++ ++CONFIG_USBD_STORAGE_IN_PKTSIZE ++ Specify the maximum packet size for the IN endpoint. This allowable ++ values are normally 16, 32 and 64. ++ ++ Some devices such as the Linkup L7205/L7210 may override this value ++ with a lower maximum value (such as 32). ++ ++CONFIG_USBD_STORAGE_INT_PKTSIZE ++ Specify the maximum packet size for the INT endpoint. This allowable ++ values are normally 8 and 16. Some bus interface devices may not ++ support all values. ++ ++CONFIG_USBD_STORAGE_DEF_DEVICE_NAME ++ Specify the default block device name to used on mass storage. +diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/Config.in linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/Config.in +--- linux-2.4.18/drivers/usb/device/storage_fd/Config.in 1970-01-01 03:00:00.000000000 +0300 ++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/Config.in 2003-11-07 05:34:43.000000000 +0300 +@@ -0,0 +1,29 @@ ++# ++# Generic Mass Storage Function Driver ++# ++# Copyright (c) 2003 Communication Technology Inc. ++# Copyright (C) 2001 Lineo, Inc. ++# Copyright (C) 2001 Hewlett-Packard Co. ++mainmenu_option next_comment ++comment "Mass Storage Function" ++ ++dep_tristate ' Mass Storage Function Driver' CONFIG_USBD_STORAGE $CONFIG_USBD ++if [ "$CONFIG_USBD_STORAGE" = "y" -o "$CONFIG_USBD_STORAGE" = "m" ]; then ++ hex ' Overide VendorID (hex value)' CONFIG_USBD_STORAGE_VENDORID "0000" ++ hex ' Overide ProductID (hex value)' CONFIG_USBD_STORAGE_PRODUCTID "0000" ++ ++ # allow setting of endpoint configurations for some architectures ++ int ' OUT Endpoint (0-15)' CONFIG_USBD_STORAGE_OUT_ENDPOINT "1" ++ int ' OUT PacketSize (16, 32, 64)' CONFIG_USBD_STORAGE_OUT_PKTSIZE "64" ++ int ' IN Endpoint (0-15)' CONFIG_USBD_STORAGE_IN_ENDPOINT "2" ++ int ' IN PacketSize (16, 32, 64)' CONFIG_USBD_STORAGE_IN_PKTSIZE "64" ++ ++ if [ ! "$CONFIG_ARCH_SA1100" = "y" -a ! "$CONFIG_ARCH_L7200" = "y" ]; then ++ int ' INT Endpoint (0-15)' CONFIG_USBD_STORAGE_INT_ENDPOINT "3" ++ int ' INT PacketSize (8, 16)' CONFIG_USBD_STORAGE_INT_PKTSIZE "16" ++ fi ++ ++ string ' Default Mass Storage device name' CONFIG_USBD_STORAGE_DEF_DEVICE_NAME "" ++fi ++ ++endmenu +diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/Makefile linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/Makefile +--- linux-2.4.18/drivers/usb/device/storage_fd/Makefile 1970-01-01 03:00:00.000000000 +0300 ++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/Makefile 2003-11-07 05:34:43.000000000 +0300 +@@ -0,0 +1,58 @@ ++# ++# SA1100 Function driver for a network USB Device ++# ++# Copyright (C) 2001 Lineo, Inc. ++# Copyright (C) 2001 Hewlett-Packard Co. ++ ++ ++O_TARGET := storage_fd_drv.o ++list-multi := storage_fd.o ++ ++storage_fd-objs := storage-fd.o storageproto.o schedule_task.o # netproto.o crc32.o ++ ++# Object file lists. ++ ++obj-y := ++obj-m := ++obj-n := ++obj- := ++ ++# Each configuration option enables a list of files. ++ ++obj-$(CONFIG_USBD_STORAGE) += storage_fd.o ++ ++# Extract lists of the multi-part drivers. ++# The 'int-*' lists are the 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)) ++ ++# 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))) ++MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) ++MIX_OBJS := $(sort $(filter $(export-objs), $(int-m))) ++ ++# The global Rules.make. ++ ++include $(TOPDIR)/Rules.make ++ ++# Link rules for multi-part drivers. ++ ++storage_fd.o: $(storage_fd-objs) ++ $(LD) -r -o $@ $(storage_fd-objs) ++ ++# dependencies: ++ ++storage-fd.o: ../usbd.h ../usbd-bus.h ../usbd-func.h ++ +diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/schedule_task.c linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/schedule_task.c +--- linux-2.4.18/drivers/usb/device/storage_fd/schedule_task.c 1970-01-01 03:00:00.000000000 +0300 ++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/schedule_task.c 2003-11-07 05:34:43.000000000 +0300 +@@ -0,0 +1,230 @@ ++/* ++ * linux/drivers/usb/device/storage_fd/schedule_task.c - schedule task library ++ * ++ * Copyright (c) 2003 Lineo Solutions, Inc. ++ * ++ * Written by Shunnosuke kabata ++ * ++ * 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 File ++******************************************************************************/ ++#include <linux/config.h> ++#include <linux/fs.h> ++#include <linux/string.h> ++#include <linux/mm.h> ++#include <linux/dcache.h> ++#include <linux/init.h> ++#include <linux/quotaops.h> ++#include <linux/slab.h> ++#include <linux/cache.h> ++#include <linux/swap.h> ++#include <linux/swapctl.h> ++#include <linux/prefetch.h> ++#include <linux/locks.h> ++#include <asm/uaccess.h> ++ ++#include "schedule_task.h" ++ ++/****************************************************************************** ++** Macro Define ++******************************************************************************/ ++#define TASK_DESC_NUM (512) ++ ++/****************************************************************************** ++** Structure Define ++******************************************************************************/ ++ ++/************************************** ++** TASK_DESC ++**************************************/ ++typedef struct _TASK_DESC{ ++ struct _TASK_DESC* next; ++ SCHEDULE_TASK_FUNC task_entry; ++ int task_param1; ++ int task_param2; ++ int task_param3; ++ int task_param4; ++ int task_param5; ++ char* file; ++ int line; ++} TASK_DESC; ++ ++/************************************** ++** OS_WRP_TASK_DATA ++**************************************/ ++typedef struct{ ++ volatile TASK_DESC* read_desc; ++ volatile TASK_DESC* write_desc; ++ TASK_DESC desc_pool[TASK_DESC_NUM]; ++ spinlock_t spin_lock; ++ struct tq_struct task_que; ++ unsigned long use_num; ++ unsigned long max_num; ++} TASK_DATA; ++ ++/****************************************************************************** ++** Variable Declaration ++******************************************************************************/ ++static TASK_DATA TaskData; ++ ++/****************************************************************************** ++** Local Function Prototype ++******************************************************************************/ ++static void task_entry(void*); ++ ++/****************************************************************************** ++** Global Function ++******************************************************************************/ ++void schedule_task_init(void) ++{ ++ int i; ++ ++ /* 0 clear */ ++ memset(&TaskData, 0x00, sizeof(TaskData)); ++ ++ /* Read/write pointer initialize */ ++ TaskData.read_desc = TaskData.write_desc = &TaskData.desc_pool[0]; ++ ++ /* Ling buffer initialize */ ++ for(i=0; i<(TASK_DESC_NUM-1); i++){ ++ TaskData.desc_pool[i].next = &TaskData.desc_pool[i+1]; ++ } ++ TaskData.desc_pool[i].next = &TaskData.desc_pool[0]; ++ ++ /* Spin lock initialize */ ++ spin_lock_init(&TaskData.spin_lock); ++ ++ /* Task queue initialize */ ++ PREPARE_TQUEUE(&TaskData.task_que, task_entry, &TaskData); ++ ++ return; ++} ++ ++int schedule_task_register(SCHEDULE_TASK_FUNC entry, int param1, int param2, ++ int param3, int param4, int param5) ++{ ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(&TaskData.spin_lock, flags); ++ ++ /* Free descriptor check */ ++ if(TaskData.write_desc->next == TaskData.read_desc){ ++ printk(KERN_INFO "storage_fd: schedule task no descriptor.\n"); ++ spin_unlock_irqrestore(&TaskData.spin_lock, flags); ++ return -1; ++ } ++ ++ /* Descriptor set */ ++ TaskData.write_desc->task_entry = entry; ++ TaskData.write_desc->task_param1 = param1; ++ TaskData.write_desc->task_param2 = param2; ++ TaskData.write_desc->task_param3 = param3; ++ TaskData.write_desc->task_param4 = param4; ++ TaskData.write_desc->task_param5 = param5; ++ ++ /* Pointer update */ ++ TaskData.write_desc = TaskData.write_desc->next; ++ ++ /* Statistics set */ ++ TaskData.use_num++; ++ if(TaskData.use_num > TaskData.max_num){ ++ TaskData.max_num = TaskData.use_num; ++ } ++ ++ spin_unlock_irqrestore(&TaskData.spin_lock, flags); ++ ++ /* Task queue register */ ++ schedule_task(&TaskData.task_que); ++ ++ return 0; ++} ++ ++void schedule_task_all_unregister(void) ++{ ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(&TaskData.spin_lock, flags); ++ TaskData.read_desc = TaskData.write_desc; ++ TaskData.use_num = 0; ++ spin_unlock_irqrestore(&TaskData.spin_lock, flags); ++} ++ ++ssize_t schedule_task_proc_read(struct file* file, char* buf, size_t count, ++ loff_t* pos) ++{ ++ char string[1024]; ++ int len = 0; ++ ++ len += sprintf(string + len, "Schedule task max num:0x%d\n", ++ TASK_DESC_NUM); ++ ++ len += sprintf(string + len, "Schedule task use num:0x%ld\n", ++ TaskData.use_num); ++ ++ len += sprintf(string + len, "Schedule task max use num:0x%ld\n", ++ TaskData.max_num); ++ ++ *pos += len; ++ if(len > count){ ++ len = -EINVAL; ++ } ++ else ++ if(len > 0 && copy_to_user(buf, string, len)) { ++ len = -EFAULT; ++ } ++ ++ return len; ++} ++ ++/****************************************************************************** ++** Local Function ++******************************************************************************/ ++static void task_entry(void* data) ++{ ++ int cond; ++ unsigned long flags = 0; ++ volatile TASK_DESC* desc; ++ ++ for(;;){ ++ ++ spin_lock_irqsave(&TaskData.spin_lock, flags); ++ desc = TaskData.read_desc; ++ cond = (TaskData.read_desc == TaskData.write_desc); ++ spin_unlock_irqrestore(&TaskData.spin_lock, flags); ++ ++ if(cond) break; ++ ++ /* Task call */ ++ desc->task_entry(desc->task_param1, desc->task_param2, ++ desc->task_param3, desc->task_param4, desc->task_param5); ++ ++ spin_lock_irqsave(&TaskData.spin_lock, flags); ++ ++ /* Pointer update */ ++ TaskData.read_desc = TaskData.read_desc->next; ++ ++ /* Statistics set */ ++ TaskData.use_num--; ++ ++ spin_unlock_irqrestore(&TaskData.spin_lock, flags); ++ } ++ ++ return; ++} ++ +diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/schedule_task.h linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/schedule_task.h +--- linux-2.4.18/drivers/usb/device/storage_fd/schedule_task.h 1970-01-01 03:00:00.000000000 +0300 ++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/schedule_task.h 2003-11-07 05:34:43.000000000 +0300 +@@ -0,0 +1,41 @@ ++/* ++ * linux/drivers/usb/device/storage_fd/schedule_task.h - schedule task library header ++ * ++ * Copyright (c) 2003 Lineo Solutions, Inc. ++ * ++ * Written by Shunnosuke kabata ++ * ++ * 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 _SCHEDULE_TASK_H_ ++#define _SCHEDULE_TASK_H_ ++ ++/****************************************************************************** ++** Macro Define ++******************************************************************************/ ++typedef int (*SCHEDULE_TASK_FUNC)(int, int, int, int, int); ++ ++/****************************************************************************** ++** Global Function Prototype ++******************************************************************************/ ++void schedule_task_init(void); ++int schedule_task_register(SCHEDULE_TASK_FUNC, int, int, int, int, int); ++void schedule_task_all_unregister(void); ++ssize_t schedule_task_proc_read(struct file*, char*, size_t, loff_t*); ++ ++#endif /* _SCHEDULE_TASK_H_ */ ++ +diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/storage-fd.c linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/storage-fd.c +--- linux-2.4.18/drivers/usb/device/storage_fd/storage-fd.c 1970-01-01 03:00:00.000000000 +0300 ++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/storage-fd.c 2003-11-07 05:34:43.000000000 +0300 +@@ -0,0 +1,865 @@ ++/* ++ * linux/drivers/usb/device/storage_fd/storage-fd.c - mass storage function driver ++ * ++ * Copyright (c) 2003 Lineo Solutions, Inc. ++ * ++ * Written by Shunnosuke kabata ++ * ++ * 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. ++ * ++ * Based on ++ * ++ * linux/drivers/usbd/net_fd/net-fd.c - network function driver ++ * ++ * Copyright (c) 2000, 2001, 2002 Lineo ++ * Copyright (c) 2001 Hewlett Packard ++ * ++ * By: ++ * Stuart Lynne <sl@lineo.com>, ++ * Tom Rushworth <tbr@lineo.com>, ++ * Bruce Balden <balden@lineo.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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++/****************************************************************************** ++** Include File ++******************************************************************************/ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include "../usbd-export.h" ++#include "../usbd-build.h" ++#include "../usbd-module.h" ++ ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/list.h> ++#include <linux/netdevice.h> ++#include <linux/skbuff.h> ++#include <linux/etherdevice.h> ++#include <linux/rtnetlink.h> ++#include <linux/smp_lock.h> ++#include <linux/ctype.h> ++#include <linux/timer.h> ++#include <linux/string.h> ++#include <linux/atmdev.h> ++#include <linux/pkt_sched.h> ++#include <linux/delay.h> ++#include <asm/uaccess.h> ++#include <asm/system.h> ++#include <net/arp.h> ++ ++#include <linux/autoconf.h> ++ ++#include "../usbd.h" ++#include "../usbd-func.h" ++#include "../usbd-bus.h" ++#include "../usbd-inline.h" ++#include "../usbd-arch.h" ++#include "../hotplug.h" ++ ++#include "schedule_task.h" ++#include "storageproto.h" ++ ++/****************************************************************************** ++** Macro Define ++******************************************************************************/ ++ ++/************************************** ++** Module Information ++**************************************/ ++ ++MODULE_AUTHOR("Shunnosuke kabata"); ++MODULE_DESCRIPTION("USB Device Mass Storage Function"); ++USBD_MODULE_INFO("storage_fd 0.1"); ++ ++/************************************** ++** Configration Check ++**************************************/ ++ ++#if !defined (CONFIG_USBD_VENDORID) && !defined(CONFIG_USBD_STORAGE_VENDORID) ++#error No Vendor ID ++#endif ++#if !defined (CONFIG_USBD_PRODUCTID) && !defined(CONFIG_USBD_STORAGE_PRODUCTID) ++#error No Product ID ++#endif ++ ++#if defined(CONFIG_USBD_STORAGE_VENDORID) && (CONFIG_USBD_STORAGE_VENDORID > 0) ++#undef CONFIG_USBD_VENDORID ++#define CONFIG_USBD_VENDORID CONFIG_USBD_STORAGE_VENDORID ++#endif ++ ++#if defined(CONFIG_USBD_STORAGE_PRODUCTID) && (CONFIG_USBD_STORAGE_PRODUCTID > 0) ++#undef CONFIG_USBD_PRODUCTID ++#define CONFIG_USBD_PRODUCTID CONFIG_USBD_STORAGE_PRODUCTID ++#endif ++ ++#ifndef CONFIG_USBD_MAXPOWER ++#define CONFIG_USBD_MAXPOWER 0 ++#endif ++ ++#ifndef CONFIG_USBD_MANUFACTURER ++#define CONFIG_USBD_MANUFACTURER "Sharp" ++#endif ++ ++#define MAXTRANSFER (512) ++ ++#ifndef CONFIG_USBD_VENDORID ++#error "CONFIG_USBD_VENDORID not defined" ++#endif ++ ++#ifndef CONFIG_USBD_PRODUCTID ++#error "CONFIG_USBD_PRODUCTID not defined" ++#endif ++ ++#ifndef CONFIG_USBD_PRODUCT_NAME ++#define CONFIG_USBD_PRODUCT_NAME "Linux Mass Storage Driver" ++#endif ++ ++#ifndef CONFIG_USBD_SERIAL_NUMBER_STR ++#define CONFIG_USBD_SERIAL_NUMBER_STR "" ++#endif ++ ++/* ++ * USB 2.0 spec does not mention it, but MaxPower is expected to be at least one ++ * and is tested for in USB configuration tests. ++ */ ++ ++#ifdef CONFIG_USBD_SELFPOWERED ++#define BMATTRIBUTE BMATTRIBUTE_RESERVED | BMATTRIBUTE_SELF_POWERED ++#define BMAXPOWER 1 ++#else ++#define BMATTRIBUTE BMATTRIBUTE_RESERVED ++#define BMAXPOWER CONFIG_USBD_MAXPOWER ++#endif ++ ++/* ++ * setup some default values for pktsizes and endpoint addresses. ++ */ ++ ++#ifndef CONFIG_USBD_STORAGE_OUT_PKTSIZE ++#define CONFIG_USBD_STORAGE_OUT_PKTSIZE 64 ++#endif ++ ++#ifndef CONFIG_USBD_STORAGE_IN_PKTSIZE ++#define CONFIG_USBD_STORAGE_IN_PKTSIZE 64 ++#endif ++ ++#ifndef CONFIG_USBD_STORAGE_INT_PKTSIZE ++#define CONFIG_USBD_STORAGE_INT_PKTSIZE 16 ++#endif ++ ++#ifndef CONFIG_USBD_STORAGE_OUT_ENDPOINT ++#define CONFIG_USBD_STORAGE_OUT_ENDPOINT 1 ++#endif ++ ++#ifndef CONFIG_USBD_STORAGE_IN_ENDPOINT ++#define CONFIG_USBD_STORAGE_IN_ENDPOINT 2 ++#endif ++ ++#ifndef CONFIG_USBD_STORAGE_INT_ENDPOINT ++#define CONFIG_USBD_STORAGE_INT_ENDPOINT 3 ++#endif ++ ++/* ++ * check for architecture specific endpoint configurations ++ */ ++ ++#if defined(ABS_OUT_ADDR) ++ //#warning ++ //#warning USING ABS ENDPOINT OUT ADDRESS ++ #undef CONFIG_USBD_STORAGE_OUT_ENDPOINT ++ ++ #if ABS_OUT_ADDR > 0 ++ #define CONFIG_USBD_STORAGE_OUT_ENDPOINT ABS_OUT_ADDR ++ #endif ++ ++#elif defined(MAX_OUT_ADDR) && defined(CONFIG_USBD_STORAGE_OUT_ENDPOINT) && (CONFIG_USBD_STORAGE_OUT_ENDPOINT > MAX_OUT_ADDR) ++ //#warning ++ //#warning USING DEFAULT ENDPOINT OUT ADDRESS ++ #undef CONFIG_USBD_STORAGE_OUT_ENDPOINT ++ #define CONFIG_USBD_STORAGE_OUT_ENDPOINT DFL_OUT_ADDR ++ ++#endif /* elif */ ++ ++#if defined(ABS_IN_ADDR) ++ //#warning ++ //#warning USING ABS ENDPOINT IN ADDRESS ++ #undef CONFIG_USBD_STORAGE_IN_ENDPOINT ++ ++ #if ABS_IN_ADDR > 0 ++ #define CONFIG_USBD_STORAGE_IN_ENDPOINT ABS_IN_ADDR ++ #endif ++ ++#elif defined(MAX_IN_ADDR) && defined(CONFIG_USBD_STORAGE_IN_ENDPOINT) && (CONFIG_USBD_STORAGE_IN_ENDPOINT > MAX_IN_ADDR) ++ //#warning ++ //#warning USING DEFAULT ENDPOINT IN ADDRESS ++ #undef CONFIG_USBD_STORAGE_IN_ENDPOINT ++ #define CONFIG_USBD_STORAGE_IN_ENDPOINT DFL_IN_ADDR ++ ++#endif /* elif */ ++ ++#if defined(ABS_INT_ADDR) ++ //#warning ++ //#warning USING ABS ENDPOINT INT ADDRESS ++ #undef CONFIG_USBD_STORAGE_INT_ENDPOINT ++ ++ #if ABS_INT_ADDR ++ #define CONFIG_USBD_STORAGE_INT_ENDPOINT ABS_INT_ADDR ++ #endif ++ ++#elif defined(MAX_INT_ADDR) && defined(CONFIG_USBD_STORAGE_INT_ENDPOINT) && (CONFIG_USBD_STORAGE_INT_ENDPOINT > MAX_INT_ADDR) ++ //#warning ++ //#warning USING DEFAULT ENDPOINT INT ADDRESS ++ #undef CONFIG_USBD_STORAGE_INT_ENDPOINT ++ #define CONFIG_USBD_STORAGE_INT_ENDPOINT DFL_INT_ADDR ++ ++#endif /* elif */ ++ ++#if defined(MAX_OUT_PKTSIZE) && defined(CONFIG_USBD_STORAGE_OUT_PKTSIZE) && CONFIG_USBD_STORAGE_OUT_PKTSIZE > MAX_OUT_PKTSIZE ++ //#warning ++ //#warning OVERIDING ENDPOINT OUT PKTSIZE ++ #undef CONFIG_USBD_STORAGE_OUT_PKTSIZE ++ #define CONFIG_USBD_STORAGE_OUT_PKTSIZE MAX_OUT_PKTSIZE ++#endif ++ ++#if defined(MAX_IN_PKTSIZE) && defined(CONFIG_USBD_STORAGE_IN_PKTSIZE) && CONFIG_USBD_STORAGE_IN_PKTSIZE > MAX_IN_PKTSIZE ++ //#warning ++ //#warning OVERIDING ENDPOINT IN PKTSIZE ++ #undef CONFIG_USBD_STORAGE_IN_PKTSIZE ++ #define CONFIG_USBD_STORAGE_IN_PKTSIZE MAX_IN_PKTSIZE ++#endif ++ ++#if defined(MAX_INT_PKTSIZE) && defined(CONFIG_USBD_STORAGE_INT_PKTSIZE) && CONFIG_USBD_STORAGE_INT_PKTSIZE > MAX_INT_PKTSIZE ++ //#warning ++ //#warning OVERIDING ENDPOINT INT PKTSIZE ++ #undef CONFIG_USBD_STORAGE_INT_PKTSIZE ++ #define CONFIG_USBD_STORAGE_INT_PKTSIZE MAX_INT_PKTSIZE ++#endif ++ ++/****************************************************************************** ++** Variable Declaration ++******************************************************************************/ ++ ++/************************************** ++** Module Parameters ++**************************************/ ++ ++static u32 vendor_id; ++static u32 product_id; ++static int out_pkt_sz = CONFIG_USBD_STORAGE_OUT_PKTSIZE; ++static int in_pkt_sz = CONFIG_USBD_STORAGE_IN_PKTSIZE; ++ ++MODULE_PARM(vendor_id, "i"); ++MODULE_PARM(product_id, "i"); ++MODULE_PARM(out_pkt_sz, "i"); ++MODULE_PARM(in_pkt_sz, "i"); ++ ++MODULE_PARM_DESC(vendor_id, "vendor id"); ++MODULE_PARM_DESC(product_id, "product id"); ++ ++/************************************** ++** Mass Storage Configuration ++**************************************/ ++ ++/* ++ * Data Interface Alternate 1 endpoints ++ */ ++static __initdata struct usb_endpoint_description StorageAlt1Endpoints[] = { ++ { ++ bEndpointAddress:CONFIG_USBD_STORAGE_OUT_ENDPOINT, ++ bmAttributes:BULK, ++ wMaxPacketSize:CONFIG_USBD_STORAGE_OUT_PKTSIZE, ++ bInterval:0, ++ direction:OUT, ++ transferSize:MAXTRANSFER, ++ }, ++ ++ { ++ bEndpointAddress:CONFIG_USBD_STORAGE_IN_ENDPOINT, ++ bmAttributes:BULK, ++ wMaxPacketSize:CONFIG_USBD_STORAGE_IN_PKTSIZE, ++ bInterval:0, ++ direction:IN, ++ transferSize:MAXTRANSFER, ++ }, ++ ++#if defined(CONFIG_USBD_STORAGE_INT_ENDPOINT) && (CONFIG_USBD_STORAGE_INT_ENDPOINT > 0) ++ { ++ bEndpointAddress:CONFIG_USBD_STORAGE_INT_ENDPOINT, ++ bmAttributes:INTERRUPT, ++ wMaxPacketSize:CONFIG_USBD_STORAGE_INT_PKTSIZE, ++ bInterval:10, ++ direction:IN, ++ transferSize:CONFIG_USBD_STORAGE_INT_PKTSIZE, ++ }, ++#endif ++}; ++ ++ ++/* ++ * Data Interface Alternate description(s) ++ */ ++static __initdata struct usb_alternate_description StorageAlternateDescriptions[] = { ++ { ++ #if defined(CONFIG_USBD_STORAGE_NO_STRINGS) ++ iInterface:"", ++ #else ++ iInterface:"Mass Storage Interface", ++ #endif ++ bAlternateSetting:0, ++ classes:0, ++ class_list:NULL, ++ endpoints:sizeof (StorageAlt1Endpoints) / sizeof (struct usb_endpoint_description), ++ endpoint_list:StorageAlt1Endpoints, ++ }, ++}; ++ ++/* ++ * Interface description(s) ++ */ ++static __initdata struct usb_interface_description StorageInterfaces[] = { ++ { ++ #if defined(CONFIG_USBD_STORAGE_NO_STRINGS) ++ iInterface:"", ++ #else ++ iInterface:"Mass Storage Interface", ++ #endif ++ bInterfaceClass:MASS_STORAGE_CLASS, ++ bInterfaceSubClass:MASS_STORAGE_SUBCLASS_SCSI, ++ bInterfaceProtocol:MASS_STORAGE_PROTO_BULK_ONLY, ++ alternates:sizeof (StorageAlternateDescriptions) / sizeof (struct usb_alternate_description), ++ alternate_list:StorageAlternateDescriptions, ++ }, ++}; ++ ++/****************************************************************************** ++** USB Configuration ++******************************************************************************/ ++ ++/* ++ * Configuration description(s) ++ */ ++struct __initdata usb_configuration_description StorageDescription[] = { ++ { ++ #if defined(CONFIG_USBD_STORAGE_NO_STRINGS) ++ iConfiguration:"", ++ #else ++ iConfiguration:"Mass Storage Configuration", ++ #endif ++ bmAttributes:BMATTRIBUTE, ++ bMaxPower:BMAXPOWER, ++ interfaces:sizeof (StorageInterfaces) / sizeof (struct usb_interface_description), ++ interface_list:StorageInterfaces, ++ }, ++}; ++ ++/* ++ * Device Description ++ */ ++struct __initdata usb_device_description StorageDeviceDescription = { ++ bDeviceClass:0, ++ bDeviceSubClass:0, // XXX ++ bDeviceProtocol:0, // XXX ++ idVendor:CONFIG_USBD_VENDORID, ++ idProduct:CONFIG_USBD_PRODUCTID, ++ iManufacturer:CONFIG_USBD_MANUFACTURER, ++ iProduct:CONFIG_USBD_PRODUCT_NAME, ++ iSerialNumber:CONFIG_USBD_SERIAL_NUMBER_STR, ++}; ++ ++/************************************** ++** Other Variable ++**************************************/ ++static int storage_exit_flag = 0; ++static pid_t storage_pid = 0; ++static struct semaphore storage_sem; ++struct timer_list storage_usb_event_tim; ++ ++ ++/****************************************************************************** ++** Global Function ++******************************************************************************/ ++ ++void storage_urb_send(struct usb_device_instance* device, void* buffer, ++ int length) ++{ ++ int port = 0; ++ struct urb* urb; ++ ++ if(!(urb = usbd_alloc_urb(device, ++ device->function_instance_array + port, ++ CONFIG_USBD_STORAGE_IN_ENDPOINT, ++ length + 5 + in_pkt_sz))){ ++ printk(KERN_INFO "storage_fd: usbd_alloc_urb failed. length '%d'.\n", length); ++ return; ++ } ++ ++ if(buffer){ ++ memcpy(urb->buffer, buffer, length); ++ } ++ else{ ++ memset(urb->buffer, 0x00, length); ++ } ++ urb->actual_length = length; ++ ++ if(usbd_send_urb(urb)){ ++ printk(KERN_INFO "storage_fd: usbd_send_urb failed.\n"); ++ usbd_dealloc_urb(urb); ++ return; ++ } ++ ++ return; ++} ++ ++/****************************************************************************** ++** Local Function ++******************************************************************************/ ++ ++/************************************** ++** Called when a USB Device is created or destroyed ++**************************************/ ++ ++static int storage_thread(void *_c) ++{ ++ siginfo_t info; ++ unsigned long signr; ++ char buff[32]; ++ ++ /* current status set */ ++ daemonize(); ++ ++ /* PID set */ ++ storage_pid = current->pid; ++ ++ /* thread name set */ ++ sprintf(current->comm, STORAGE_THREAD_NAME); ++ (current)->nice = 10; ++ ++ /* signal register */ ++ spin_lock_irq(¤t->sigmask_lock); ++ siginitsetinv(¤t->blocked, ++ sigmask(SIGUSR1) | sigmask(SIGHUP) | sigmask(SIGKILL) | ++ sigmask(SIGSTOP) | sigmask(SIGCONT) | sigmask(SIGTERM) | ++ sigmask(SIGALRM)); ++ recalc_sigpending(current); ++ spin_unlock_irq(¤t->sigmask_lock); ++ ++ /* media open */ ++ schedule_task_register( ++ (SCHEDULE_TASK_FUNC)storageproto_media_status_check, CONTEXT_STORAGE, ++ 0, 0, 0, 0); ++ ++ /* thread active indicate */ ++ sprintf(buff, "%d\n", storage_pid); ++ hotplug("usbdstorage", buff, "active"); ++ ++ for(;;){ ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ if (!signal_pending(current)) { ++ schedule(); ++ continue; ++ } ++ ++ spin_lock_irq(¤t->sigmask_lock); ++ signr = dequeue_signal(¤t->blocked, &info); ++ spin_unlock_irq(¤t->sigmask_lock); ++ ++ switch(signr) { ++ case SIGHUP: ++ /* media signal indicate */ ++ schedule_task_register( ++ (SCHEDULE_TASK_FUNC)storageproto_media_status_check, CONTEXT_STORAGE, ++ 0, 0, 0, 0); ++ ++ DBG_STORAGE_FD(KERN_INFO "storage_fd: signal receive 'SIGHUP'.\n"); ++ break; ++ ++ default: ++ DBG_STORAGE_FD(KERN_INFO "storage_fd: signal receive '%ld'\n", signr); ++ break; ++ } ++ ++ if(storage_exit_flag) break; ++ } ++ /* current status set */ ++ current->state = TASK_RUNNING; ++ ++ /* PID clear */ ++ storage_pid = 0; ++ ++ /* thread inactive indicate */ ++ hotplug("usbdstorage", buff, "inactive"); ++ ++ up(&storage_sem); ++ ++ return 0; ++} ++ ++static void storage_function_init(struct usb_bus_instance* bus, ++ struct usb_device_instance* device, ++ struct usb_function_driver* function_driver) ++{ ++ /* schedule task init */ ++ schedule_task_init(); ++ ++ /* storage protocol initialize */ ++ storageproto_init(); ++ ++ /* semaphore init */ ++ sema_init(&storage_sem, 0); ++ ++ /* timer initialize */ ++ init_timer(&storage_usb_event_tim); ++ ++ /* thread create */ ++ storage_pid = kernel_thread(storage_thread, NULL, 0); ++ ++ return; ++} ++ ++static void storage_function_exit(struct usb_device_instance* device) ++{ ++ /* thread kill */ ++ storage_exit_flag = 1; ++ kill_proc(storage_pid, SIGKILL, 1); ++ down(&storage_sem); ++ ++ /* delete timer */ ++ del_timer(&storage_usb_event_tim); ++ ++ /* storage protocol exit */ ++ storageproto_exit(); ++ ++ /* schedule task delete */ ++ schedule_task_all_unregister(); ++ ++ return; ++} ++ ++ ++/************************************** ++** Called to handle USB Events ++**************************************/ ++ ++static void storage_usb_event_delay_timeout(unsigned long param) ++{ ++ /* media signal indicate */ ++ schedule_task_register( ++ (SCHEDULE_TASK_FUNC)storageproto_usb_status_check, (int)param, ++ 0, 0, 0, 0); ++ ++ return; ++} ++ ++/* ++ * storage_event - process a device event ++ * @device: usb device ++ * @event: the event that happened ++ * ++ * Called by the usb device core layer to respond to various USB events. ++ * ++ * This routine IS called at interrupt time. Please use the usual precautions. ++ * ++ */ ++void storage_event(struct usb_device_instance* device, ++ usb_device_event_t event, int data) ++{ ++#if 0 ++ static struct { ++ usb_device_event_t event; ++ char* string; ++ } eventAnal[] = { ++ {DEVICE_UNKNOWN, "DEVICE_UNKNOWN"}, ++ {DEVICE_INIT, "DEVICE_INIT"}, ++ {DEVICE_CREATE, "DEVICE_CREATE"}, ++ {DEVICE_HUB_CONFIGURED, "DEVICE_HUB_CONFIGURED"}, ++ {DEVICE_RESET, "DEVICE_RESET"}, ++ {DEVICE_ADDRESS_ASSIGNED, "DEVICE_ADDRESS_ASSIGNED"}, ++ {DEVICE_CONFIGURED, "DEVICE_CONFIGURED"}, ++ {DEVICE_SET_INTERFACE, "DEVICE_SET_INTERFACE"}, ++ {DEVICE_SET_FEATURE, "DEVICE_SET_FEATURE"}, ++ {DEVICE_CLEAR_FEATURE, "DEVICE_CLEAR_FEATURE"}, ++ {DEVICE_DE_CONFIGURED, "DEVICE_DE_CONFIGURED"}, ++ {DEVICE_BUS_INACTIVE, "DEVICE_BUS_INACTIVE"}, ++ {DEVICE_BUS_ACTIVITY, "DEVICE_BUS_ACTIVITY"}, ++ {DEVICE_POWER_INTERRUPTION, "DEVICE_POWER_INTERRUPTION"}, ++ {DEVICE_HUB_RESET, "DEVICE_HUB_RESET"}, ++ {DEVICE_DESTROY, "DEVICE_DESTROY"}, ++ {DEVICE_FUNCTION_PRIVATE, "DEVICE_FUNCTION_PRIVATE"} ++ }; ++ int i; ++ ++ for(i=0; i<(sizeof(eventAnal)/sizeof(eventAnal[0])); i++){ ++ if(event == eventAnal[i].event){ ++ DBG_STORAGE_FD(KERN_INFO "storage_fd: event receive '%s'.\n", ++ eventAnal[i].string); ++ break; ++ } ++ } ++ if(i == (sizeof(eventAnal)/sizeof(eventAnal[0]))){ ++ DBG_STORAGE_FD(KERN_INFO "storage_fd: unknown event receive.\n"); ++ } ++#endif ++ ++ switch(event){ ++ case DEVICE_ADDRESS_ASSIGNED: ++ { ++ static int Is1stCheck = 1; ++ if(Is1stCheck){ ++ Is1stCheck = 0; ++ ++ /* delay timer set */ ++ del_timer(&storage_usb_event_tim); ++ storage_usb_event_tim.expires = jiffies + ((USB_EVENT_DELAY_TIM * HZ) / 1000); ++ storage_usb_event_tim.data = USB_DISCONNECT; ++ storage_usb_event_tim.function = storage_usb_event_delay_timeout; ++ add_timer(&storage_usb_event_tim); ++ break; ++ } ++ } ++ case DEVICE_BUS_ACTIVITY: ++ /* delay timer set */ ++ del_timer(&storage_usb_event_tim); ++ storage_usb_event_tim.expires = jiffies + ((USB_EVENT_DELAY_TIM * HZ) / 1000); ++ storage_usb_event_tim.data = USB_CONNECT; ++ storage_usb_event_tim.function = storage_usb_event_delay_timeout; ++ add_timer(&storage_usb_event_tim); ++ break; ++ ++ case DEVICE_BUS_INACTIVE: ++ /* delay timer set */ ++ del_timer(&storage_usb_event_tim); ++ storage_usb_event_tim.expires = jiffies + ((USB_EVENT_DELAY_TIM * HZ) / 1000); ++ storage_usb_event_tim.data = USB_DISCONNECT; ++ storage_usb_event_tim.function = storage_usb_event_delay_timeout; ++ add_timer(&storage_usb_event_tim); ++ break; ++ ++ case DEVICE_RESET: ++ schedule_task_register( ++ (SCHEDULE_TASK_FUNC)storageproto_usb_reset_ind, ++ 0, 0, 0, 0, 0); ++ break; ++ ++ default: ++ break; ++ } ++ ++ return; ++} ++ ++/* ++ * storage_recv_setup - called with a control URB ++ * @urb - pointer to struct urb ++ * ++ * Check if this is a setup packet, process the device request, put results ++ * back into the urb and return zero or non-zero to indicate success (DATA) ++ * or failure (STALL). ++ * ++ * This routine IS called at interrupt time. Please use the usual precautions. ++ * ++ */ ++int storage_recv_setup(struct urb* urb) ++{ ++ return 0; ++} ++ ++/* ++ * storage_recv_urb - called with a received URB ++ * @urb - pointer to struct urb ++ * ++ * Return non-zero if we failed and urb is still valid (not disposed) ++ * ++ * This routine IS called at interrupt time. Please use the usual precautions. ++ * ++ */ ++int storage_recv_urb(struct urb* urb) ++{ ++ int port = 0; // XXX compound device ++ struct usb_device_instance* device; ++ struct usb_function_instance* function; ++ ++ if(!urb || !(device = urb->device) || ++ !(function = device->function_instance_array + port)){ ++ return -EINVAL; ++ } ++ ++ if(urb->status != RECV_OK){ ++ return -EINVAL; ++ } ++ ++ /* URB urb_analysis */ ++ schedule_task_register( ++ (SCHEDULE_TASK_FUNC)storageproto_urb_analysis, (int)urb, ++ 0, 0, 0, 0); ++ ++ return 0; ++} ++ ++/* ++ * storage_urb_sent - called to indicate URB transmit finished ++ * @urb: pointer to struct urb ++ * @rc: result ++ * ++ * The usb device core layer will use this to let us know when an URB has ++ * been finished with. ++ * ++ * This routine IS called at interrupt time. Please use the usual precautions. ++ * ++ */ ++int storage_urb_sent(struct urb* urb, int rc) ++{ ++ int port = 0; // XXX compound device ++ struct usb_device_instance* device; ++ struct usb_function_instance* function; ++ ++ if(!urb || !(device = urb->device) || ++ !(function = device->function_instance_array + port)){ ++ return -EINVAL; ++ } ++ ++ usbd_dealloc_urb (urb); ++ ++ return 0; ++} ++ ++/************************************** ++** Proc file system ++**************************************/ ++ ++static ssize_t storage_proc_read(struct file* file, char* buf, size_t count, ++ loff_t* pos) ++{ ++ int len = 0, ret; ++ ++ if(*pos > 0) return 0; ++ ++ if((ret = storageproto_proc_read(file, buf + len, count - len, pos)) < 0){ ++ return ret; ++ } ++ len += ret; ++ ++ if((ret = schedule_task_proc_read(file, buf + len, count - len, pos)) < 0){ ++ return ret; ++ } ++ len += ret; ++ ++ return len; ++} ++ ++static struct file_operations StorageProcOps = { ++ read:storage_proc_read, ++}; ++ ++/************************************** ++** Module init and exit ++**************************************/ ++ ++struct usb_function_operations StorageFunctionOps = { ++ event:storage_event, ++ recv_urb:storage_recv_urb, ++ recv_setup:storage_recv_setup, ++ urb_sent:storage_urb_sent, ++ function_init:storage_function_init, ++ function_exit:storage_function_exit, ++}; ++ ++struct usb_function_driver StorageFunctionDriver = { ++ name:"Mass Storage", ++ ops:&StorageFunctionOps, ++ device_description:&StorageDeviceDescription, ++ configurations:sizeof (StorageDescription) / sizeof (struct usb_configuration_description), ++ configuration_description:StorageDescription, ++ this_module:THIS_MODULE, ++}; ++ ++/* ++ * net_modinit - module init ++ * ++ */ ++static int __init net_modinit(void) ++{ ++ struct proc_dir_entry* proc_entry; ++ ++ printk(KERN_INFO "storage_fd: %s (OUT=%d,IN=%d)\n", ++ __usbd_module_info, out_pkt_sz, in_pkt_sz); ++ ++ printk(KERN_INFO "storage_fd: vendorID: %x productID: %x\n", ++ CONFIG_USBD_VENDORID, CONFIG_USBD_PRODUCTID); ++ ++ // verify pkt sizes not too small ++ if (out_pkt_sz < 3 || in_pkt_sz < 3){ ++ printk(KERN_INFO "storage_fd: Rx pkt size %d or Tx pkt size %d too small\n", ++ out_pkt_sz, in_pkt_sz); ++ return (-EINVAL); ++ } ++ ++ if(vendor_id){ ++ StorageDeviceDescription.idVendor = vendor_id; ++ } ++ if(product_id){ ++ StorageDeviceDescription.idProduct = product_id; ++ } ++ ++ // register us with the usb device support layer ++ if(usbd_register_function(&StorageFunctionDriver)){ ++ printk(KERN_INFO "storage_fd: usbd_register_function failed.\n"); ++ return -EINVAL; ++ } ++ ++ // create proc entry ++ if ((proc_entry = create_proc_entry("usb-storage", 0, 0)) == NULL) { ++ usbd_deregister_function (&StorageFunctionDriver); ++ printk(KERN_INFO "storage_fd: create_proc_entry failed.\n"); ++ return -ENOMEM; ++ } ++ proc_entry->proc_fops = &StorageProcOps; ++ ++ return 0; ++} ++ ++/* ++ * function_exit - module cleanup ++ * ++ */ ++static void __exit net_modexit (void) ++{ ++ // de-register us with the usb device support layer ++ usbd_deregister_function (&StorageFunctionDriver); ++ ++ // remove proc entry ++ remove_proc_entry("usb-storage", NULL); ++ ++ return; ++} ++ ++module_init (net_modinit); ++module_exit (net_modexit); +diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/storageproto.c linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/storageproto.c +--- linux-2.4.18/drivers/usb/device/storage_fd/storageproto.c 1970-01-01 03:00:00.000000000 +0300 ++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/storageproto.c 2003-11-07 05:34:43.000000000 +0300 +@@ -0,0 +1,1505 @@ ++/* ++ * linux/drivers/usb/device/storage_fd/storageproto.c - mass storage protocol library ++ * ++ * Copyright (c) 2003 Lineo Solutions, Inc. ++ * ++ * Written by Shunnosuke kabata ++ * ++ * 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 File ++******************************************************************************/ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include "../usbd-export.h" ++#include "../usbd-build.h" ++#include "../usbd-module.h" ++ ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/list.h> ++#include <linux/netdevice.h> ++#include <linux/skbuff.h> ++#include <linux/etherdevice.h> ++#include <linux/rtnetlink.h> ++#include <linux/smp_lock.h> ++#include <linux/ctype.h> ++#include <linux/timer.h> ++#include <linux/string.h> ++#include <linux/atmdev.h> ++#include <linux/pkt_sched.h> ++#include <linux/delay.h> ++#include <linux/blkdev.h> ++#include <linux/file.h> ++#include <asm/uaccess.h> ++#include <asm/system.h> ++#include <net/arp.h> ++ ++#include <linux/autoconf.h> ++ ++#include "../usbd.h" ++#include "../usbd-func.h" ++#include "../usbd-bus.h" ++#include "../usbd-inline.h" ++#include "../usbd-arch.h" ++#include "../hotplug.h" ++ ++#include "schedule_task.h" ++#include "storageproto.h" ++ ++/****************************************************************************** ++** macro define ++******************************************************************************/ ++ ++#define DEVICE_BLOCK_SIZE 512 ++ ++#define BLOCK_BUFFER_SIZE (1024 * 64) ++ ++#define DEF_NUMBER_OF_HEADS 0x10 ++#define DEF_SECTORS_PER_TRACK 0x20 ++ ++/****************************************************************************** ++** Structure Define ++******************************************************************************/ ++ ++typedef struct{ ++ unsigned char scsi_command; ++ unsigned char* command_name; ++ void (*scsi_func)(struct usb_device_instance*, ++ COMMAND_BLOCK_WRAPPER*); ++} SCSI_ANALYSIS_TBL; ++ ++typedef struct{ ++ unsigned char scsi_command; ++ unsigned char* command_name; ++ void (*bulkout_func)(struct usb_device_instance*, ++ void*, int); ++} SCSI_BULKOUT_ANALYSIS_TBL; ++ ++/****************************************************************************** ++** Variable Declaration ++******************************************************************************/ ++ ++/************************************** ++** Module Parameters ++**************************************/ ++ ++static char* storage_device = CONFIG_USBD_STORAGE_DEF_DEVICE_NAME; ++MODULE_PARM(storage_device, "s"); ++ ++/************************************** ++** Device Information ++**************************************/ ++ ++static struct file* DeviceFile = NULL; ++static int DeviceSize = 0; ++static int DeviceBlockSize = DEVICE_BLOCK_SIZE; ++static int DeviceWrProtect = WR_PROTECT_OFF; ++ ++/************************************** ++** Status ++**************************************/ ++ ++static int StorageStatus = STORAGE_IDLE; ++static int UsbStatus = USB_DISCONNECT; ++static int MediaStatus = MEDIA_EJECT; ++static int MediaChange = MEDIA_CHANGE_OFF; ++ ++/************************************** ++** Keep Information ++**************************************/ ++ ++static SCSI_REQUEST_SENSE_DATA RequestSenseData; ++static COMMAND_BLOCK_WRAPPER KeepCBW; ++static unsigned long BulkOutLength = 0; ++static unsigned char BlockBuffer[BLOCK_BUFFER_SIZE]; ++ ++/************************************** ++** Statistics ++**************************************/ ++static unsigned long StatMaxBulkInSize = 0; ++static unsigned long StatMaxBulkOutSize = 0; ++static unsigned long StatDevWriteError = 0; ++static unsigned long StatDevReadError = 0; ++static unsigned long StatDevFlushError = 0; ++static unsigned long StatWriteTimout = 0; ++static unsigned long StatMaxWriteTime = 0; ++ ++/************************************** ++** Timer ++**************************************/ ++static struct timer_list BulkOutTim; ++static struct timer_list MediaCheckTim; ++ ++/****************************************************************************** ++** Local Function ++******************************************************************************/ ++ ++static void storage_bulkout_timeout(unsigned long param) ++{ ++ /* statistics update */ ++ StatWriteTimout++; ++ printk(KERN_INFO "storage_fd: write bulk out timeout. length '%ld/%ld'.\n", ++ BulkOutLength, KeepCBW.dCBWDataTransferLength); ++ ++ return; ++} ++ ++static void media_check_timeout(unsigned long param) ++{ ++ /* media check */ ++ schedule_task_register( ++ (SCHEDULE_TASK_FUNC)storageproto_media_status_check, CONTEXT_TIMER, ++ 0, 0, 0, 0); ++ ++ return; ++} ++ ++static void request_sense_data_set(unsigned char sense_key, unsigned char asc, ++ unsigned char ascq, unsigned long info) ++{ ++ /* ++ * set REQUEST SENSE DATA ++ */ ++ ++ memset(&RequestSenseData, 0x00, sizeof(RequestSenseData)); ++ ++ RequestSenseData.ErrorCode = 0x70; ++ RequestSenseData.Valid = (info) ? 1 : 0; ++ RequestSenseData.SenseKey = sense_key; ++ memcpy(RequestSenseData.Information, &info, sizeof(info)); ++ RequestSenseData.AdditionalSenseLength = 0x0a; ++ RequestSenseData.AdditionalSenseCode = asc; ++ RequestSenseData.AdditionalSenseCodeQualifier = ascq; ++ ++ return; ++} ++ ++static void scsi_inquiry_analysis(struct usb_device_instance* device, ++ COMMAND_BLOCK_WRAPPER* cbw) ++{ ++ SCSI_INQUIRY_DATA data; ++ COMMAND_STATUS_WRAPPER csw; ++ unsigned long data_len; ++ ++ /* ++ * data transport ++ */ ++ ++ memset(&data, 0x00, sizeof(data)); ++ ++ data.PeripheralDeviceType = 0x00; ++ data.RMB = 1; ++ data.ResponseDataFormat = 0x01; ++ data.AdditionalLength = 0x1f; ++ strncpy(data.VendorInformation, CONFIG_USBD_MANUFACTURER, ++ sizeof(data.VendorInformation)); ++ strncpy(data.ProductIdentification, CONFIG_USBD_PRODUCT_NAME, ++ sizeof(data.ProductIdentification)); ++ strncpy(data.ProductRevisionLevel, PRODUCT_REVISION_LEVEL, ++ sizeof(data.ProductRevisionLevel)); ++ ++ data_len = sizeof(data); ++ if(cbw->dCBWDataTransferLength < data_len){ ++ data_len = cbw->dCBWDataTransferLength; ++ } ++ ++ storage_urb_send(device, &data, data_len); ++ ++ /* ++ * status transport ++ */ ++ ++ memset(&csw, 0x00, sizeof(csw)); ++ ++ csw.dCSWSignature = CSW_SIGNATURE; ++ csw.dCSWTag = cbw->dCBWTag; ++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength - data_len; ++ csw.bCSWStatus = 0; ++ ++ storage_urb_send(device, &csw, sizeof(csw)); ++ ++ return; ++} ++ ++static void scsi_read_format_capacity_analysis(struct usb_device_instance* device, ++ COMMAND_BLOCK_WRAPPER* cbw) ++{ ++ SCSI_READ_FORMAT_CAPACITY_DATA data; ++ COMMAND_STATUS_WRAPPER csw; ++ unsigned long block_num, data_len; ++ unsigned short block_len; ++ ++ /* ++ * data transport ++ */ ++ ++ block_num = 0xffffffff; ++ block_len = (unsigned short)DeviceBlockSize; ++ block_num = htonl(block_num); ++ block_len = htons(block_len); ++ ++ memset(&data, 0x00, sizeof(data)); ++ ++ data.CapacityListHeader.CapacityListLength = ++ sizeof(data.CurrentMaximumCapacityDescriptor); ++ memcpy(data.CurrentMaximumCapacityDescriptor.NumberofBlocks, &block_num, ++ sizeof(block_num)); ++ data.CurrentMaximumCapacityDescriptor.DescriptorCode = 0x03; ++ memcpy(data.CurrentMaximumCapacityDescriptor.BlockLength + 1, &block_len, ++ sizeof(block_len)); ++ ++ data_len = sizeof(data); ++ if(cbw->dCBWDataTransferLength < data_len){ ++ data_len = cbw->dCBWDataTransferLength; ++ } ++ ++ storage_urb_send(device, &data, data_len); ++ ++ /* ++ * status transport ++ */ ++ ++ memset(&csw, 0x00, sizeof(csw)); ++ ++ csw.dCSWSignature = CSW_SIGNATURE; ++ csw.dCSWTag = cbw->dCBWTag; ++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength - data_len; ++ csw.bCSWStatus = 0; ++ ++ storage_urb_send(device, &csw, sizeof(csw)); ++ ++ return; ++} ++ ++static void scsi_read_capacity_analysis(struct usb_device_instance* device, ++ COMMAND_BLOCK_WRAPPER* cbw) ++{ ++ SCSI_READ_CAPACITY_DATA data; ++ COMMAND_STATUS_WRAPPER csw; ++ unsigned char data_len, status = 0; ++ ++ if(DeviceFile == NULL){ ++ /* 0 clear */ ++ memset(&data, 0x00, sizeof(data)); ++ ++ /* data length set */ ++ data_len = cbw->dCBWDataTransferLength; ++ ++ /* status set */ ++ status = 1; ++ ++ /* error code save REQUEST SENSE */ ++ request_sense_data_set(0x02, 0x3a, 0x00, 0x00); ++ } ++ else ++ if(MediaChange == MEDIA_CHANGE_ON){ ++ /* 0 clear */ ++ memset(&data, 0x00, sizeof(data)); ++ ++ /* data length set */ ++ data_len = cbw->dCBWDataTransferLength; ++ ++ /* status set */ ++ status = 1; ++ ++ /* error code save REQUEST SENSE */ ++ request_sense_data_set(0x06, 0x28, 0x00, 0x00); ++ ++ /* media change flag off */ ++ MediaChange = MEDIA_CHANGE_OFF; ++ } ++ else{ ++ unsigned long last_lba, block_len; ++ ++ /* 0 clear */ ++ memset(&data, 0x00, sizeof(data)); ++ ++ /* data set */ ++ last_lba = (DeviceSize / DeviceBlockSize) - 1; ++ block_len = DeviceBlockSize; ++ last_lba = htonl(last_lba); ++ block_len = htonl(block_len); ++ ++ memcpy(data.LastLogicalBlockAddress, &last_lba, sizeof(last_lba)); ++ memcpy(data.BlockLengthInBytes, &block_len, sizeof(block_len)); ++ ++ /* data length set */ ++ data_len = sizeof(data); ++ ++ /* status set */ ++ status = 0; ++ } ++ ++ /* ++ * data transport ++ */ ++ ++ if(cbw->dCBWDataTransferLength < data_len){ ++ data_len = cbw->dCBWDataTransferLength; ++ } ++ ++ storage_urb_send(device, &data, data_len); ++ ++ /* ++ * status transport ++ */ ++ ++ memset(&csw, 0x00, sizeof(csw)); ++ ++ csw.dCSWSignature = CSW_SIGNATURE; ++ csw.dCSWTag = cbw->dCBWTag; ++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength - data_len; ++ csw.bCSWStatus = status; ++ ++ storage_urb_send(device, &csw, sizeof(csw)); ++ ++ return; ++} ++ ++static void scsi_request_sense_analysis(struct usb_device_instance* device, ++ COMMAND_BLOCK_WRAPPER* cbw) ++{ ++ COMMAND_STATUS_WRAPPER csw; ++ unsigned long data_len; ++ ++ /* ++ * data transport ++ */ ++ ++ data_len = sizeof(RequestSenseData); ++ if(cbw->dCBWDataTransferLength < data_len){ ++ data_len = cbw->dCBWDataTransferLength; ++ } ++ ++ storage_urb_send(device, &RequestSenseData, data_len); ++ ++ /* ++ * status transport ++ */ ++ ++ memset(&csw, 0x00, sizeof(csw)); ++ ++ csw.dCSWSignature = CSW_SIGNATURE; ++ csw.dCSWTag = cbw->dCBWTag; ++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength - data_len; ++ csw.bCSWStatus = 0; ++ ++ storage_urb_send(device, &csw, sizeof(csw)); ++ ++ return; ++} ++ ++static void scsi_read_10_analysis(struct usb_device_instance* device, ++ COMMAND_BLOCK_WRAPPER* cbw) ++{ ++ SCSI_READ_10_COMMAND* command = (SCSI_READ_10_COMMAND*)cbw->CBWCB; ++ COMMAND_STATUS_WRAPPER csw; ++ unsigned char status = 0; ++ unsigned short len; ++ unsigned long lba, size, offset; ++ ++ memcpy(&lba, command->LogicalBlockAddress, sizeof(lba)); ++ memcpy(&len, command->TransferLength, sizeof(len)); ++ lba = ntohl(lba); ++ len = ntohs(len); ++ offset = lba * DeviceBlockSize; ++ size = cbw->dCBWDataTransferLength; ++ ++ if(DeviceFile == NULL){ ++ /* command fail */ ++ status = 1; ++ ++ /* error code save REQUEST SENSE */ ++ request_sense_data_set(0x02, 0x3a, 0x00, 0x00); ++ ++ /* ++ * data transport ++ */ ++ ++ storage_urb_send(device, NULL, size); ++ } ++ else ++ if(MediaChange == MEDIA_CHANGE_ON){ ++ /* command fail */ ++ status = 1; ++ ++ /* error code save REQUEST SENSE */ ++ request_sense_data_set(0x06, 0x28, 0x00, 0x00); ++ ++ /* media change flag off */ ++ MediaChange = MEDIA_CHANGE_OFF; ++ ++ /* ++ * data transport ++ */ ++ ++ storage_urb_send(device, NULL, size); ++ } ++ else{ ++ unsigned long count, read_size; ++ ++ /* ++ * data transport ++ */ ++ ++ /* device seek */ ++ DeviceFile->f_op->llseek(DeviceFile, offset, 0); ++ ++ /* device read */ ++ for(count = size; count; count -= read_size){ ++ read_size = (count > sizeof(BlockBuffer)) ? ++ sizeof(BlockBuffer) : count; ++ if(DeviceFile && ++ DeviceFile->f_op->read(DeviceFile, BlockBuffer, read_size, ++ &DeviceFile->f_pos) != read_size){ ++ ++ /* command fail */ ++ status = 1; ++ ++ /* error code save REQUEST SENSE */ ++ request_sense_data_set(0x02, 0x3a, 0x00, 0x00); ++ ++ /* statistics update */ ++ StatDevReadError++; ++ printk(KERN_INFO "storage_fd: device read error. length '%ld'.\n", read_size); ++ } ++ ++ storage_urb_send(device, BlockBuffer, read_size); ++ } ++ } ++ ++ /* ++ * status transport ++ */ ++ ++ memset(&csw, 0x00, sizeof(csw)); ++ ++ csw.dCSWSignature = CSW_SIGNATURE; ++ csw.dCSWTag = cbw->dCBWTag; ++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength - size; ++ csw.bCSWStatus = status; ++ ++ storage_urb_send(device, &csw, sizeof(csw)); ++ ++ return; ++} ++ ++static void scsi_mode_sense_analysis(struct usb_device_instance* device, ++ COMMAND_BLOCK_WRAPPER* cbw) ++{ ++ static READ_WRITE_ERROR_RECOVERY_PAGE page_01 = { ++ PageCode:0x01, ++ PageLength:0x0A, ++ ReadRetryCount:0x03, ++ WriteRetryCount:0x80, ++ }; ++ static FLEXIBLE_DISK_PAGE page_05 = { ++ PageCode:0x05, ++ PageLength:0x1E, ++ TransferRate:{0x00, 0xFA}, ++ NumberofHeads:0xA0, ++ SectorsperTrack:0x00, ++ DataBytesperSector:{0x02, 0x00}, ++ NumberofCylinders:{0x00, 0x00}, ++ MotorOnDelay:0x05, ++ MotorOffDelay:0x1E, ++ MediumRotationRate:{0x01, 0x68}, ++ }; ++ static REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE page_1b = { ++ PageCode:0x1B, ++ PageLength:0x0A, ++ TLUN:0x01, ++ }; ++ static TIMER_AND_PROTECT_PAGE page_1c = { ++ PageCode:0x1c, ++ PageLength:0x06, ++ InactivityTimeMultiplier:0x0A, ++ }; ++ ++ ++ SCSI_MODE_SENSE_COMMAND* command = (SCSI_MODE_SENSE_COMMAND*)cbw->CBWCB; ++ SCSI_MODE_SENSE_DATA data; ++ COMMAND_STATUS_WRAPPER csw; ++ unsigned char data_len, status = 0; ++ unsigned short cylinder, sector; ++ unsigned long size; ++ ++ /* ++ * data transport ++ */ ++ ++ memset(&data, 0x00, sizeof(data)); ++ ++ /* set write protect */ ++ data.ModeParameterHeader.WP = DeviceWrProtect; ++ ++ /* set Flexible Disk Page */ ++ if(DeviceFile == NULL){ ++ sector = (unsigned short)DeviceBlockSize; ++ cylinder = 0; ++ sector = htons(sector); ++ cylinder = htons(cylinder); ++ ++ page_05.NumberofHeads = 0; ++ page_05.SectorsperTrack = 0; ++ memcpy(page_05.DataBytesperSector, §or, sizeof(sector)); ++ memcpy(page_05.NumberofCylinders, &cylinder, sizeof(cylinder)); ++ } ++ else{ ++ sector = (unsigned short)DeviceBlockSize; ++ size = DEF_NUMBER_OF_HEADS * DEF_SECTORS_PER_TRACK * sector; ++ cylinder = DeviceSize / size; ++ sector = htons(sector); ++ cylinder = htons(cylinder); ++ ++ page_05.NumberofHeads = DEF_NUMBER_OF_HEADS; ++ page_05.SectorsperTrack = DEF_SECTORS_PER_TRACK; ++ memcpy(page_05.DataBytesperSector, §or, sizeof(sector)); ++ memcpy(page_05.NumberofCylinders, &cylinder, sizeof(cylinder)); ++ } ++ ++ if(command->PC == 0 && command->PageCode == 0x01){ ++ data_len = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_01); ++ data.ModeParameterHeader.ModeDataLength = data_len - 1; ++ memcpy(&data.ModePages, &page_01, sizeof(page_01)); ++ } ++ else ++ if(command->PC == 0 && command->PageCode == 0x05){ ++ data_len = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_05); ++ data.ModeParameterHeader.ModeDataLength = data_len - 1; ++ memcpy(&data.ModePages, &page_05, sizeof(page_05)); ++ } ++ else ++ if(command->PC == 0 && command->PageCode == 0x1b){ ++ data_len = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_1b); ++ data.ModeParameterHeader.ModeDataLength = data_len - 1; ++ memcpy(&data.ModePages, &page_1b, sizeof(page_1b)); ++ } ++ else ++ if(command->PC == 0 && command->PageCode == 0x1c){ ++ data_len = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_1c); ++ data.ModeParameterHeader.ModeDataLength = data_len - 1; ++ memcpy(&data.ModePages, &page_1c, sizeof(page_1c)); ++ } ++ else ++ if(command->PC == 0 && command->PageCode == 0x3f){ ++ data_len = sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_ALL_PAGES); ++ data.ModeParameterHeader.ModeDataLength = data_len - 1; ++ memcpy(&data.ModePages.ModeAllPages.ReadWriteErrorRecoveryPage, ++ &page_01, sizeof(page_01)); ++ memcpy(&data.ModePages.ModeAllPages.FlexibleDiskPage, ++ &page_05, sizeof(page_05)); ++ memcpy(&data.ModePages.ModeAllPages.RemovableBlockAccessCapabilitiesPage, ++ &page_1b, sizeof(page_1b)); ++ memcpy(&data.ModePages.ModeAllPages.TimerAndProtectPage, ++ &page_1c, sizeof(page_1c)); ++ } ++ else{ ++ /* command fail */ ++ status = 1; ++ data_len = cbw->dCBWDataTransferLength; ++ ++ /* error code save REQUEST SENSE */ ++ request_sense_data_set(0x05, 0x24, 0x00, 0x00); ++ } ++ ++ if(cbw->dCBWDataTransferLength < data_len){ ++ data_len = cbw->dCBWDataTransferLength; ++ } ++ ++ storage_urb_send(device, &data, data_len); ++ ++ /* ++ * status transport ++ */ ++ ++ memset(&csw, 0x00, sizeof(csw)); ++ ++ csw.dCSWSignature = CSW_SIGNATURE; ++ csw.dCSWTag = cbw->dCBWTag; ++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength - data_len; ++ csw.bCSWStatus = status; ++ ++ storage_urb_send(device, &csw, sizeof(csw)); ++ ++ return; ++} ++ ++static void scsi_test_unit_ready_analysis(struct usb_device_instance* device, ++ COMMAND_BLOCK_WRAPPER* cbw) ++{ ++ COMMAND_STATUS_WRAPPER csw; ++ unsigned char status = 0; ++ ++ if(DeviceFile == NULL){ ++ /* command fail */ ++ status = 1; ++ ++ /* error code save REQUEST SENSE */ ++ request_sense_data_set(0x02, 0x3a, 0x00, 0x00); ++ } ++ else ++ if(MediaChange == MEDIA_CHANGE_ON){ ++ /* command fail */ ++ status = 1; ++ ++ /* error code save REQUEST SENSE */ ++ request_sense_data_set(0x06, 0x28, 0x00, 0x00); ++ ++ /* media change flag off */ ++ MediaChange = MEDIA_CHANGE_OFF; ++ } ++ ++ /* ++ * status transport ++ */ ++ ++ memset(&csw, 0x00, sizeof(csw)); ++ ++ csw.dCSWSignature = CSW_SIGNATURE; ++ csw.dCSWTag = cbw->dCBWTag; ++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength; ++ csw.bCSWStatus = status; ++ ++ storage_urb_send(device, &csw, sizeof(csw)); ++ ++ return; ++} ++ ++static void scsi_prevent_allow_medium_removal_analysis(struct usb_device_instance* device, ++ COMMAND_BLOCK_WRAPPER* cbw) ++{ ++ SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL_COMMAND* command = (SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL_COMMAND*)cbw->CBWCB; ++ COMMAND_STATUS_WRAPPER csw; ++ unsigned char status = 0; ++ ++ if(command->Prevent){ ++ /* command fail */ ++ status = 1; ++ ++ /* error code save REQUEST SENSE */ ++ request_sense_data_set(0x05, 0x24, 0x00, 0x00); ++ } ++ ++ /* ++ * status transport ++ */ ++ ++ memset(&csw, 0x00, sizeof(csw)); ++ ++ csw.dCSWSignature = CSW_SIGNATURE; ++ csw.dCSWTag = cbw->dCBWTag; ++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength; ++ csw.bCSWStatus = status; ++ ++ storage_urb_send(device, &csw, sizeof(csw)); ++ ++ return; ++} ++ ++static void scsi_start_stop_analysis(struct usb_device_instance* device, ++ COMMAND_BLOCK_WRAPPER* cbw) ++{ ++ SCSI_START_STOP_COMMAND* command = (SCSI_START_STOP_COMMAND*)cbw->CBWCB; ++ COMMAND_STATUS_WRAPPER csw; ++ unsigned char status = 0; ++ ++ if(DeviceFile == NULL){ ++ /* command fail */ ++ status = 1; ++ ++ /* error code save REQUEST SENSE */ ++ request_sense_data_set(0x02, 0x3a, 0x00, 0x00); ++ } ++ else ++ if(MediaChange == MEDIA_CHANGE_ON){ ++ /* command fail */ ++ status = 1; ++ ++ /* error code save REQUEST SENSE */ ++ request_sense_data_set(0x06, 0x28, 0x00, 0x00); ++ ++ /* media change flag off */ ++ MediaChange = MEDIA_CHANGE_OFF; ++ } ++ else ++ if(command->Start && command->LoEj){ ++ /* command fail */ ++ status = 1; ++ ++ /* error code save REQUEST SENSE */ ++ request_sense_data_set(0x05, 0x24, 0x00, 0x00); ++ } ++ ++ /* device buffer flush */ ++ if(DeviceFile && DeviceFile->f_op->ioctl(DeviceFile->f_dentry->d_inode, ++ DeviceFile, BLKFLSBUF, 0) != 0){ ++ /* statistics update */ ++ StatDevFlushError++; ++ printk(KERN_INFO "storage_fd: device flush error.\n"); ++ } ++ ++ /* ++ * status transport ++ */ ++ ++ memset(&csw, 0x00, sizeof(csw)); ++ ++ csw.dCSWSignature = CSW_SIGNATURE; ++ csw.dCSWTag = cbw->dCBWTag; ++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength; ++ csw.bCSWStatus = status; ++ ++ storage_urb_send(device, &csw, sizeof(csw)); ++ ++ return; ++} ++ ++static void scsi_write_10_analysis(struct usb_device_instance* device, ++ COMMAND_BLOCK_WRAPPER* cbw) ++{ ++ /* status set */ ++ BulkOutLength = 0; ++ StorageStatus = STORAGE_BULKOUT; ++ ++ /* timer set */ ++ del_timer(&BulkOutTim); ++ BulkOutTim.expires = jiffies + ((WR_BULKOUT_CHK_TIM * HZ) / 1000); ++ BulkOutTim.data = 0; ++ BulkOutTim.function = storage_bulkout_timeout; ++ add_timer(&BulkOutTim); ++ ++ return; ++} ++ ++static void scsi_verify_analysis(struct usb_device_instance* device, ++ COMMAND_BLOCK_WRAPPER* cbw) ++{ ++ COMMAND_STATUS_WRAPPER csw; ++ unsigned char status = 0; ++ ++ if(DeviceFile == NULL){ ++ /* command fail */ ++ status = 1; ++ ++ /* error code save REQUEST SENSE */ ++ request_sense_data_set(0x02, 0x3a, 0x00, 0x00); ++ } ++ else ++ if(MediaChange == MEDIA_CHANGE_ON){ ++ /* command fail */ ++ status = 1; ++ ++ /* error code save REQUEST SENSE */ ++ request_sense_data_set(0x06, 0x28, 0x00, 0x00); ++ ++ /* media change flag off */ ++ MediaChange = MEDIA_CHANGE_OFF; ++ } ++ ++ /* ++ * status transport ++ */ ++ ++ memset(&csw, 0x00, sizeof(csw)); ++ ++ csw.dCSWSignature = CSW_SIGNATURE; ++ csw.dCSWTag = cbw->dCBWTag; ++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength; ++ csw.bCSWStatus = status; ++ ++ storage_urb_send(device, &csw, sizeof(csw)); ++ ++ return; ++} ++ ++static void scsi_unsupport_analysis(struct usb_device_instance* device, ++ COMMAND_BLOCK_WRAPPER* cbw) ++{ ++ COMMAND_STATUS_WRAPPER csw; ++ unsigned char data_len = 0; ++ ++ if(((cbw->bmCBWFlags & 0x80) == 0x00) && (cbw->dCBWDataTransferLength)){ ++ /* BLKOUT */ ++ ++ /* status set */ ++ BulkOutLength = 0; ++ StorageStatus = STORAGE_BULKOUT; ++ } ++ else{ ++ /* BLKIN */ ++ ++ if(cbw->dCBWDataTransferLength){ ++ data_len = cbw->dCBWDataTransferLength; ++ storage_urb_send(device, NULL, data_len); ++ } ++ ++ /* ++ * status transport ++ */ ++ ++ memset(&csw, 0x00, sizeof(csw)); ++ ++ csw.dCSWSignature = CSW_SIGNATURE; ++ csw.dCSWTag = cbw->dCBWTag; ++ csw.dCSWDataResidue = cbw->dCBWDataTransferLength - data_len; ++ csw.bCSWStatus = 0x01; ++ storage_urb_send(device, &csw, sizeof(csw)); ++ ++ } ++ ++ /* error code save REQUEST SENSE */ ++ request_sense_data_set(0x05, 0x20, 0x00, 0x00); ++ ++ return; ++} ++ ++static void scsi_bulkout_write_10_analysis(struct usb_device_instance* device, ++ void* buffer, int length) ++{ ++ COMMAND_STATUS_WRAPPER csw; ++ unsigned char status = 0; ++ unsigned long buff_used_len, buff_offset; ++ unsigned long s_tick, e_tick, wr_tick; ++ ++ buff_offset = BulkOutLength % sizeof(BlockBuffer); ++ ++ memcpy(BlockBuffer + buff_offset, buffer, length); ++ BulkOutLength += length; ++ ++ buff_used_len = BulkOutLength % sizeof(BlockBuffer); ++ if(buff_used_len == 0) buff_used_len = sizeof(BlockBuffer); ++ ++ /* delete timer */ ++ if(BulkOutLength >= KeepCBW.dCBWDataTransferLength){ ++ del_timer(&BulkOutTim); ++ } ++ ++ if(buff_used_len >= sizeof(BlockBuffer) || ++ BulkOutLength >= KeepCBW.dCBWDataTransferLength){ ++ ++ /* buffer full */ ++ SCSI_WRITE_10_COMMAND* command = (SCSI_WRITE_10_COMMAND*)&KeepCBW.CBWCB; ++ unsigned short len; ++ unsigned long lba, offset; ++ ++ memcpy(&lba, command->LogicalBlockAddress, sizeof(lba)); ++ memcpy(&len, command->TransferLength, sizeof(len)); ++ lba = ntohl(lba); ++ len = ntohs(len); ++ ++ offset = (lba * DeviceBlockSize) + ++ (sizeof(BlockBuffer) * ((BulkOutLength - 1) / sizeof(BlockBuffer))); ++ ++ /* device check */ ++ if(DeviceFile && ++ MediaChange != MEDIA_CHANGE_ON && ++ DeviceWrProtect != WR_PROTECT_ON){ ++ ++ /* write before jiffies get */ ++ s_tick = jiffies; ++ ++ /* device seek */ ++ DeviceFile->f_op->llseek(DeviceFile, offset, 0); ++ ++ /* device write */ ++ if(DeviceFile->f_op->write(DeviceFile, BlockBuffer, buff_used_len, ++ &DeviceFile->f_pos) != buff_used_len){ ++ /* statistics update */ ++ StatDevWriteError++; ++ printk(KERN_INFO "storage_fd: device write error. length '%ld'.\n", buff_used_len); ++ } ++ ++ /* write after jiffies get */ ++ e_tick = jiffies; ++ ++ /* statistics update */ ++ wr_tick = e_tick - s_tick; ++ if(wr_tick > StatMaxWriteTime){ ++ StatMaxWriteTime = wr_tick; ++ } ++ } ++ } ++ ++ if(BulkOutLength >= KeepCBW.dCBWDataTransferLength){ ++ if(DeviceFile == NULL){ ++ /* command fail */ ++ status = 1; ++ ++ /* error code save REQUEST SENSE */ ++ request_sense_data_set(0x02, 0x3a, 0x00, 0x00); ++ } ++ else ++ if(MediaChange == MEDIA_CHANGE_ON){ ++ /* command fail */ ++ status = 1; ++ ++ /* error code save REQUEST SENSE */ ++ request_sense_data_set(0x06, 0x28, 0x00, 0x00); ++ ++ /* media change flag off */ ++ MediaChange = MEDIA_CHANGE_OFF; ++ } ++ else ++ if(DeviceWrProtect == WR_PROTECT_ON){ ++ /* command fail */ ++ status = 1; ++ ++ /* error code save REQUEST SENSE */ ++ request_sense_data_set(0x07, 0x27, 0x00, 0x00); ++ ++ /* media change flag off */ ++ MediaChange = MEDIA_CHANGE_OFF; ++ } ++ ++ /* ++ * status transport ++ */ ++ ++ memset(&csw, 0x00, sizeof(csw)); ++ ++ csw.dCSWSignature = CSW_SIGNATURE; ++ csw.dCSWTag = KeepCBW.dCBWTag; ++ csw.dCSWDataResidue = KeepCBW.dCBWDataTransferLength - BulkOutLength; ++ csw.bCSWStatus = status; ++ ++ storage_urb_send(device, &csw, sizeof(csw)); ++ ++ /* status reset */ ++ BulkOutLength = 0; ++ StorageStatus = STORAGE_IDLE; ++ ++ /* flush before jiffies get */ ++ s_tick = jiffies; ++ ++ /* device buffer flush */ ++ if(DeviceFile && DeviceFile->f_op->ioctl(DeviceFile->f_dentry->d_inode, ++ DeviceFile, BLKFLSBUF, 0) != 0){ ++ /* statistics update */ ++ StatDevFlushError++; ++ printk(KERN_INFO "storage_fd: device flush error.\n"); ++ } ++ ++ /* flush after jiffies get */ ++ e_tick = jiffies; ++ ++ /* statistics update */ ++ wr_tick = e_tick - s_tick; ++ if(wr_tick > StatMaxWriteTime){ ++ StatMaxWriteTime = wr_tick; ++ } ++ ++ } ++ ++ return; ++} ++ ++static void scsi_bulkout_unsupport_analysis(struct usb_device_instance* device, ++ void* buffer, int length) ++{ ++ COMMAND_STATUS_WRAPPER csw; ++ ++ BulkOutLength += length; ++ ++ if(BulkOutLength >= KeepCBW.dCBWDataTransferLength){ ++ /* ++ * status transport ++ */ ++ ++ memset(&csw, 0x00, sizeof(csw)); ++ ++ csw.dCSWSignature = CSW_SIGNATURE; ++ csw.dCSWTag = KeepCBW.dCBWTag; ++ csw.dCSWDataResidue = KeepCBW.dCBWDataTransferLength - BulkOutLength; ++ csw.bCSWStatus = 1; ++ ++ storage_urb_send(device, &csw, sizeof(csw)); ++ ++ /* error code save REQUEST SENSE */ ++ request_sense_data_set(0x05, 0x20, 0x00, 0x00); ++ ++ /* status reset */ ++ BulkOutLength = 0; ++ StorageStatus = STORAGE_IDLE; ++ } ++ ++ return; ++} ++ ++/****************************************************************************** ++** Global Function ++******************************************************************************/ ++ ++static SCSI_ANALYSIS_TBL ScsiAnalysisTbl[] = { ++ {SCSI_FORMAT_UNT, "SCSI_FORMAT_UNT", NULL}, ++ {SCSI_INQUIRY, "SCSI_INQUIRY", scsi_inquiry_analysis}, ++ {SCSI_START_STOP, "SCSI_START_STOP", scsi_start_stop_analysis}, ++ {SCSI_MODE_SELECT, "SCSI_MODE_SELECT", NULL}, ++ {SCSI_MODE_SENSE, "SCSI_MODE_SENSE", scsi_mode_sense_analysis}, ++ {SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL, "SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL", scsi_prevent_allow_medium_removal_analysis}, ++ {SCSI_READ_10, "SCSI_READ_10", scsi_read_10_analysis}, ++ {SCSI_READ_12, "SCSI_READ_12", NULL}, ++ {SCSI_READ_CAPACITY, "SCSI_READ_CAPACITY", scsi_read_capacity_analysis}, ++ {SCSI_READ_FORMAT_CAPACITY, "SCSI_READ_FORMAT_CAPACITY", scsi_read_format_capacity_analysis}, ++ {SCSI_REQUEST_SENSE, "SCSI_REQUEST_SENSE", scsi_request_sense_analysis}, ++ {SCSI_REZERO_UNIT, "SCSI_REZERO_UNIT", NULL}, ++ {SCSI_SEEK_10, "SCSI_SEEK_10", NULL}, ++ {SCSI_SEND_DIAGNOSTIC, "SCSI_SEND_DIAGNOSTIC", NULL}, ++ {SCSI_TEST_UNIT_READY, "SCSI_TEST_UNIT_READY", scsi_test_unit_ready_analysis}, ++ {SCSI_VERIFY, "SCSI_VERIFY", scsi_verify_analysis}, ++ {SCSI_WRITE_10, "SCSI_WRITE_10", scsi_write_10_analysis}, ++ {SCSI_WRITE_12, "SCSI_WRITE_12", NULL}, ++ {SCSI_WRITE_AND_VERIFY, "SCSI_WRITE_AND_VERIFY", NULL} ++}; ++ ++static SCSI_BULKOUT_ANALYSIS_TBL ScsiBlkOutAnalysisTbl[] = { ++ {SCSI_WRITE_10, "SCSI_WRITE_10", scsi_bulkout_write_10_analysis}, ++}; ++ ++void storageproto_urb_analysis(struct urb* urb) ++{ ++ COMMAND_BLOCK_WRAPPER* cbw = (COMMAND_BLOCK_WRAPPER*)urb->buffer; ++ int i; ++ ++ /* status BLKOUT check */ ++ if(StorageStatus == STORAGE_BULKOUT){ ++ for(i = 0; ++ i < sizeof(ScsiBlkOutAnalysisTbl) / sizeof(SCSI_ANALYSIS_TBL); ++ i++){ ++ if(ScsiBlkOutAnalysisTbl[i].scsi_command == KeepCBW.CBWCB[0]){ ++ if(ScsiBlkOutAnalysisTbl[i].bulkout_func){ ++ ScsiBlkOutAnalysisTbl[i].bulkout_func(urb->device, ++ urb->buffer, ++ urb->actual_length); ++ goto RETURN_LABEL; ++ } ++ break; ++ } ++ } ++ scsi_bulkout_unsupport_analysis(urb->device, urb->buffer, urb->actual_length); ++ goto RETURN_LABEL; ++ } ++ ++ /* signature check */ ++ if(cbw->dCBWSignature != CBW_SIGNATURE){ ++ printk(KERN_INFO "storage_fd: signature error. '0x%08lx'.\n", ++ cbw->dCBWSignature); ++ goto RETURN_LABEL; ++ } ++ ++ /* statistics set */ ++ if(cbw->dCBWDataTransferLength){ ++ if(((cbw->bmCBWFlags & 0x80) == 0x00) && (cbw->dCBWDataTransferLength)){ ++ /* BULK OUT */ ++ if(StatMaxBulkOutSize < cbw->dCBWDataTransferLength){ ++ StatMaxBulkOutSize = cbw->dCBWDataTransferLength; ++ } ++ } ++ else{ ++ /* BULK IN */ ++ if(StatMaxBulkInSize < cbw->dCBWDataTransferLength){ ++ StatMaxBulkInSize = cbw->dCBWDataTransferLength; ++ } ++ } ++ } ++ ++ /* save CBW and set storage status */ ++ memcpy(&KeepCBW, cbw, sizeof(KeepCBW)); ++ ++ /* UFI command analysis */ ++ for(i = 0; i < sizeof(ScsiAnalysisTbl) / sizeof(SCSI_ANALYSIS_TBL); i++){ ++ if(ScsiAnalysisTbl[i].scsi_command == cbw->CBWCB[0]){ ++ if(ScsiAnalysisTbl[i].scsi_func){ ++ ScsiAnalysisTbl[i].scsi_func(urb->device, cbw); ++ goto RETURN_LABEL; ++ } ++ break; ++ } ++ } ++ ++ scsi_unsupport_analysis(urb->device, cbw); ++ printk(KERN_INFO "storage_fd: SCSI command error. '0x%02x'.\n", ++ cbw->CBWCB[0]); ++ goto RETURN_LABEL; ++ ++RETURN_LABEL: ++ ++ /* URB free */ ++ usbd_recycle_urb(urb); ++ ++ return; ++} ++ ++int storageproto_device_open_check(void) ++{ ++ struct file* file; ++ struct inode* inode; ++ kdev_t dev; ++ int read_org; ++ ++ /* device already open check */ ++ if(DeviceFile){ ++ storageproto_device_close(); ++ } ++ ++ /* device open */ ++ file = filp_open(storage_device, O_RDWR, 0000); ++ if(IS_ERR(file)){ ++ file = filp_open(storage_device, O_RDONLY, 0000); ++ if(IS_ERR(file)){ ++ storageproto_device_close(); ++ return MEDIA_EJECT; ++ } ++ DeviceWrProtect = WR_PROTECT_ON; ++ } ++ ++ file->f_op->llseek(file, 0, 0); ++ if(file->f_op->read(file, (void*)&read_org, sizeof(read_org), &file->f_pos) ++ != sizeof(read_org)){ ++ filp_close(file, NULL); ++ storageproto_device_close(); ++ return MEDIA_EJECT; ++ } ++ ++ /* struct file pointer save */ ++ DeviceFile = file; ++ ++ /* device information */ ++ inode = file->f_dentry->d_inode; ++ dev = inode->i_rdev; ++ ++ if (blk_size[MAJOR(dev)]){ ++ DeviceSize = blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS; ++ } ++ else{ ++ DeviceSize = INT_MAX << BLOCK_SIZE_BITS; ++ } ++ ++ if(blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)]){ ++ DeviceBlockSize = DEVICE_BLOCK_SIZE; ++ } ++ else{ ++ DeviceBlockSize = DEVICE_BLOCK_SIZE; ++ } ++ ++ return MEDIA_INSERT; ++} ++ ++void storageproto_device_close(void) ++{ ++ if(DeviceFile){ ++ filp_close(DeviceFile, NULL); ++ DeviceFile = NULL; ++ DeviceSize = 0; ++ DeviceBlockSize = DEVICE_BLOCK_SIZE; ++ DeviceWrProtect = WR_PROTECT_OFF; ++ } ++ ++ return; ++} ++ ++void storageproto_usb_status_check(int status) ++{ ++ static int Is1stCheck = 1; ++ ++ /* USB status check */ ++ if(Is1stCheck){ ++ Is1stCheck = 0; ++ } ++ else{ ++ if(UsbStatus == status) goto RETURN_LABEL; ++ } ++ ++ /* set status */ ++ UsbStatus = status; ++ ++ switch(UsbStatus){ ++ case USB_CONNECT: ++ /* media status check */ ++ storageproto_media_status_check(CONTEXT_SCHEDULE); ++ ++ switch(MediaStatus){ ++ case MEDIA_EJECT: ++ break; ++ ++ case MEDIA_INSERT: ++ hotplug("usbdstorage", storage_device, "umount"); ++ break; ++ ++ default: ++ break; ++ } ++ hotplug("usbdstorage", storage_device, "connect"); ++ break; ++ ++ case USB_DISCONNECT: ++ /* device close */ ++ storageproto_device_close(); ++ ++ switch(MediaStatus){ ++ case MEDIA_EJECT: ++ break; ++ ++ case MEDIA_INSERT: ++ hotplug("usbdstorage", storage_device, "mount"); ++ break; ++ ++ default: ++ break; ++ } ++ hotplug("usbdstorage", storage_device, "disconnect"); ++ break; ++ ++ default: ++ break; ++ } ++ ++RETURN_LABEL: ++ DBG_STORAGE_FD(KERN_INFO "storage_fd: USB check '%s' '%s' 'file:%p'.\n", ++ (UsbStatus) ? "USB_CONNECT" : "USB_DISCONNECT", ++ (MediaStatus) ? "MEDIA_INSERT" : "MEDIA_EJECT", DeviceFile); ++ ++ return; ++} ++ ++void storageproto_media_status_check(int call_context) ++{ ++ static unsigned long RetryCount = 0; ++ int status; ++ ++ /* media open check */ ++ status = storageproto_device_open_check(); ++ ++ /* media status check retry */ ++ if(status == MEDIA_EJECT){ ++ switch(call_context){ ++ case CONTEXT_STORAGE: ++ ++ /* retry counter init */ ++ RetryCount = 0; ++ ++ /* timer set */ ++ del_timer(&MediaCheckTim); ++ MediaCheckTim.expires = jiffies + ((MEDIA_CHECK_TIM * HZ) / 1000); ++ MediaCheckTim.data = 0; ++ MediaCheckTim.function = media_check_timeout; ++ add_timer(&MediaCheckTim); ++ ++ break; ++ ++ case CONTEXT_TIMER: ++ ++ /* retry counter update */ ++ RetryCount++; ++ ++ /* retry counter check */ ++ if(RetryCount >= MEDIA_CHECK_RETRY) break; ++ ++ /* timer set */ ++ del_timer(&MediaCheckTim); ++ MediaCheckTim.expires = jiffies + ((MEDIA_CHECK_TIM * HZ) / 1000); ++ MediaCheckTim.data = 0; ++ MediaCheckTim.function = media_check_timeout; ++ add_timer(&MediaCheckTim); ++ ++ break; ++ ++ default: ++ break; ++ } ++ } ++ else ++ if(status == MEDIA_INSERT){ ++ /* delete timer */ ++ del_timer(&MediaCheckTim); ++ } ++ ++ /* media status check */ ++ if(status == MediaStatus){ ++ if(UsbStatus == USB_DISCONNECT){ ++ storageproto_device_close(); ++ } ++ if(MediaStatus == MEDIA_INSERT){ ++ if(call_context == CONTEXT_STORAGE || call_context == CONTEXT_TIMER){ ++ MediaChange = MEDIA_CHANGE_ON; ++ } ++ } ++ goto RETURN_LABEL; ++ } ++ ++ /* set status */ ++ MediaStatus = status; ++ ++ switch(MediaStatus){ ++ case MEDIA_INSERT: ++ /* set status */ ++ MediaChange = MEDIA_CHANGE_ON; ++ ++ switch(UsbStatus){ ++ case USB_DISCONNECT: ++ storageproto_device_close(); ++ break; ++ ++ case USB_CONNECT: ++ break; ++ ++ default: ++ break; ++ } ++ hotplug("usbdstorage", storage_device, "insert"); ++ break; ++ ++ case MEDIA_EJECT: ++ switch(UsbStatus){ ++ case USB_DISCONNECT: ++ storageproto_device_close(); ++ break; ++ ++ case USB_CONNECT: ++ break; ++ ++ default: ++ break; ++ } ++ hotplug("usbdstorage", storage_device, "eject"); ++ break; ++ ++ default: ++ break; ++ } ++ ++RETURN_LABEL: ++ DBG_STORAGE_FD(KERN_INFO "storage_fd: media check. '%s' '%s' 'file:%p' '%s'.\n", ++ (UsbStatus) ? "USB_CONNECT" : "USB_DISCONNECT", ++ (MediaStatus) ? "MEDIA_INSERT" : "MEDIA_EJECT", DeviceFile, ++ (call_context == CONTEXT_SCHEDULE) ? "CONTEXT_SCHEDULE" : ++ (call_context == CONTEXT_STORAGE) ? "CONTEXT_STORAGE" : "CONTEXT_TIMER"); ++ ++ return; ++} ++ ++void storageproto_usb_reset_ind(void) ++{ ++ /* status reset */ ++ BulkOutLength = 0; ++ StorageStatus = STORAGE_IDLE; ++ ++ DBG_STORAGE_FD(KERN_INFO "storage_fd: storage protocol reset.\n"); ++ ++ return; ++} ++ ++void storageproto_init(void) ++{ ++ /* timer init */ ++ init_timer(&BulkOutTim); ++ ++ /* timer init */ ++ init_timer(&MediaCheckTim); ++ ++ return; ++} ++ ++void storageproto_exit(void) ++{ ++ /* device close */ ++ storageproto_device_close(); ++ ++ /* delete timer */ ++ del_timer(&BulkOutTim); ++ ++ /* delete timer */ ++ del_timer(&MediaCheckTim); ++ ++ return; ++} ++ ++ssize_t storageproto_proc_read(struct file* file, char* buf, size_t count, ++ loff_t* pos) ++{ ++ char string[1024]; ++ int len = 0; ++ ++ len += sprintf(string + len, "Protocol status:%s\n", ++ (StorageStatus == STORAGE_IDLE) ? "STORAGE_IDLE" : ++ (StorageStatus == STORAGE_BULKIN) ? "STORAGE_BULKIN" : ++ "STORAGE_BULKOUT"); ++ ++ len += sprintf(string + len, "USB status:%s\n", ++ (UsbStatus == USB_DISCONNECT) ? "USB_DISCONNECT" : ++ "USB_CONNECT"); ++ ++ len += sprintf(string + len, "Media status:%s\n", ++ (MediaStatus == MEDIA_EJECT) ? "MEDIA_EJECT" : ++ "MEDIA_INSERT"); ++ ++ len += sprintf(string + len, "Media chage:%s\n", ++ (MediaChange == MEDIA_CHANGE_OFF) ? "MEDIA_CHANGE_OFF" : ++ "MEDIA_CHANGE_ON"); ++ ++ len += sprintf(string + len, "Device name:%s\n", ++ storage_device); ++ ++ len += sprintf(string + len, "Device file descriptor:0x%p\n", ++ DeviceFile); ++ ++ len += sprintf(string + len, "Device size:0x%d\n", ++ DeviceSize); ++ ++ len += sprintf(string + len, "Device block size:0x%d\n", ++ DeviceBlockSize); ++ ++ len += sprintf(string + len, "Device write protect:%s\n", ++ (DeviceWrProtect == WR_PROTECT_OFF) ? "WR_PROTECT_OFF": ++ "WR_PROTECT_ON"); ++ ++ len += sprintf(string + len, "Bulk in max size:%ld\n", ++ StatMaxBulkInSize); ++ ++ len += sprintf(string + len, "Bulk out max size:%ld\n", ++ StatMaxBulkOutSize); ++ ++ len += sprintf(string + len, "device write error:%ld\n", ++ StatDevWriteError); ++ ++ len += sprintf(string + len, "device read error:%ld\n", ++ StatDevReadError); ++ ++ len += sprintf(string + len, "device flush error:%ld\n", ++ StatDevFlushError); ++ ++ len += sprintf(string + len, "write data bulk out timout:%ld\n", ++ StatWriteTimout); ++ ++ len += sprintf(string + len, "device write max time:%ld msec\n", ++ (StatMaxWriteTime * 1000) / HZ); ++ ++ *pos += len; ++ if(len > count){ ++ len = -EINVAL; ++ } ++ else ++ if(len > 0 && copy_to_user(buf, string, len)) { ++ len = -EFAULT; ++ } ++ ++ return len; ++} ++ +diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/storageproto.h linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/storageproto.h +--- linux-2.4.18/drivers/usb/device/storage_fd/storageproto.h 1970-01-01 03:00:00.000000000 +0300 ++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/storageproto.h 2003-11-07 05:34:43.000000000 +0300 +@@ -0,0 +1,585 @@ ++/* ++ * linux/drivers/usb/device/storage_fd/storageproto.h - mass storage protocol library header ++ * ++ * Copyright (c) 2003 Lineo Solutions, Inc. ++ * ++ * Written by Shunnosuke kabata ++ * ++ * 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 _STORAGEPROTO_H_ ++#define _STORAGEPROTO_H_ ++ ++/****************************************************************************** ++** Macro Define ++******************************************************************************/ ++ ++/************************************** ++** Class Code ++**************************************/ ++ ++/* ++ * Class ++ */ ++ ++#define MASS_STORAGE_CLASS 0x08 ++ ++/* ++ * SubClass ++ */ ++ ++#define MASS_STORAGE_SUBCLASS_RBC 0x01 ++#define MASS_STORAGE_SUBCLASS_SFF8020I 0x02 ++#define MASS_STORAGE_SUBCLASS_QIC157 0x03 ++#define MASS_STORAGE_SUBCLASS_UFI 0x04 ++#define MASS_STORAGE_SUBCLASS_SFF8070I 0x05 ++#define MASS_STORAGE_SUBCLASS_SCSI 0x06 ++ ++/* ++ * Protocol ++ */ ++ ++#define MASS_STORAGE_PROTO_CBI_WITH_COMP 0x00 ++#define MASS_STORAGE_PROTO_CBI_NO_COMP 0x01 ++#define MASS_STORAGE_PROTO_BULK_ONLY 0x50 ++ ++/************************************** ++** SCSI Command ++**************************************/ ++ ++#define SCSI_FORMAT_UNT 0x04 ++#define SCSI_INQUIRY 0x12 ++#define SCSI_START_STOP 0x1b ++#define SCSI_MODE_SELECT 0x55 ++#define SCSI_MODE_SENSE 0x1a ++#define SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e ++#define SCSI_READ_10 0x28 ++#define SCSI_READ_12 0xa8 ++#define SCSI_READ_CAPACITY 0x25 ++#define SCSI_READ_FORMAT_CAPACITY 0x23 ++#define SCSI_REQUEST_SENSE 0x03 ++#define SCSI_REZERO_UNIT 0x01 ++#define SCSI_SEEK_10 0x2b ++#define SCSI_SEND_DIAGNOSTIC 0x1d ++#define SCSI_TEST_UNIT_READY 0x00 ++#define SCSI_VERIFY 0x2f ++#define SCSI_WRITE_10 0x2a ++#define SCSI_WRITE_12 0xaa ++#define SCSI_WRITE_AND_VERIFY 0x2e ++ ++/************************************** ++** SCSI Command Parameter ++**************************************/ ++ ++#define CBW_SIGNATURE 0x43425355 /* USBC */ ++#define CSW_SIGNATURE 0x53425355 /* USBS */ ++ ++#define PRODUCT_REVISION_LEVEL "1.00" ++ ++/************************************** ++** Status ++**************************************/ ++ ++#define WR_PROTECT_OFF 0 ++#define WR_PROTECT_ON 1 ++ ++#define STORAGE_IDLE 0 ++#define STORAGE_BULKIN 1 ++#define STORAGE_BULKOUT 2 ++ ++#define USB_DISCONNECT 0 ++#define USB_CONNECT 1 ++ ++#define MEDIA_EJECT 0 ++#define MEDIA_INSERT 1 ++ ++#define MEDIA_CHANGE_OFF 0 ++#define MEDIA_CHANGE_ON 1 ++ ++/************************************** ++** Mass Storage Thread Name ++**************************************/ ++ ++#define STORAGE_THREAD_NAME "usbdstorage" ++ ++/************************************** ++** Media Signal Delay Time(ms) ++**************************************/ ++ ++#define USB_EVENT_DELAY_TIM 1000 ++ ++/************************************** ++** Write Bulk Out Check Time(ms) ++**************************************/ ++ ++#define WR_BULKOUT_CHK_TIM 1000 ++ ++/************************************** ++** Media Check Time(ms) ++**************************************/ ++ ++#define MEDIA_CHECK_TIM 3000 ++#define MEDIA_CHECK_RETRY 3 ++ ++/************************************** ++** Context ++**************************************/ ++ ++#define CONTEXT_SCHEDULE 0 ++#define CONTEXT_STORAGE 1 ++#define CONTEXT_TIMER 2 ++ ++/************************************** ++** Debug Message ++**************************************/ ++#if 0 ++#define DBG_STORAGE_FD(fmt, args...) printk(fmt, ##args) ++#else ++#define DBG_STORAGE_FD(fmt, args...) ++#endif ++ ++/****************************************************************************** ++** Structure Define ++******************************************************************************/ ++ ++/************************************** ++** Command Block Wrapper / Command Status Wrapper ++**************************************/ ++ ++/* ++ * Command Block Wrapper ++ */ ++typedef struct{ ++ unsigned long dCBWSignature; ++ unsigned long dCBWTag; ++ unsigned long dCBWDataTransferLength; ++ unsigned char bmCBWFlags; ++ unsigned char bCBWLUN:4, ++ Reserved:4; ++ unsigned char bCBWCBLength:5, ++ Reserved2:3; ++ unsigned char CBWCB[16]; ++} __attribute__((packed)) COMMAND_BLOCK_WRAPPER; ++ ++/* ++ * Command Status Wrapper ++ */ ++typedef struct{ ++ unsigned long dCSWSignature; ++ unsigned long dCSWTag; ++ unsigned long dCSWDataResidue; ++ unsigned char bCSWStatus; ++} __attribute__((packed)) COMMAND_STATUS_WRAPPER; ++ ++/************************************** ++** SCSI Command ++**************************************/ ++ ++/* ++ * INQUIRY ++ */ ++ ++typedef struct{ ++ unsigned char OperationCode; ++ unsigned char EVPD:1, ++ Reserved1:4, ++ LogicalUnitNumber:3; ++ unsigned char PageCode; ++ unsigned char Reserved2; ++ unsigned char AllocationLength; ++ unsigned char Reserved3; ++ unsigned char Reserved4; ++ unsigned char Reserved5; ++ unsigned char Reserved6; ++ unsigned char Reserved7; ++ unsigned char Reserved8; ++ unsigned char Reserved9; ++} __attribute__((packed)) SCSI_INQUIRY_COMMAND; ++ ++typedef struct{ ++ unsigned char PeripheralDeviceType:5, ++ Reserved1:3; ++ unsigned char Reserved2:7, ++ RMB:1; ++ unsigned char ANSIVersion:3, ++ ECMAVersion:3, ++ ISOVersion:2; ++ unsigned char ResponseDataFormat:4, ++ Reserved3:4; ++ unsigned char AdditionalLength; ++ unsigned char Reserved4; ++ unsigned char Reserved5; ++ unsigned char Reserved6; ++ unsigned char VendorInformation[8]; ++ unsigned char ProductIdentification[16]; ++ unsigned char ProductRevisionLevel[4]; ++} __attribute__((packed)) SCSI_INQUIRY_DATA; ++ ++/* ++ * READ FORMAT CAPACITY ++ */ ++ ++typedef struct{ ++ unsigned char OperationCode; ++ unsigned char Reserved1:5, ++ LogicalUnitNumber:3; ++ unsigned char Reserved2; ++ unsigned char Reserved3; ++ unsigned char Reserved4; ++ unsigned char Reserved5; ++ unsigned char Reserved6; ++ unsigned char AllocationLength[2]; ++ unsigned char Reserved7; ++ unsigned char Reserved8; ++ unsigned char Reserved9; ++} __attribute__((packed)) SCSI_READ_FORMAT_CAPACITY_COMMAND; ++ ++typedef struct{ ++ struct{ ++ unsigned char Reserved1; ++ unsigned char Reserved2; ++ unsigned char Reserved3; ++ unsigned char CapacityListLength; ++ } __attribute__((packed)) CapacityListHeader; ++ struct{ ++ unsigned char NumberofBlocks[4]; ++ unsigned char DescriptorCode:2, ++ Reserved1:6; ++ unsigned char BlockLength[3]; ++ } __attribute__((packed)) CurrentMaximumCapacityDescriptor; ++} __attribute__((packed)) SCSI_READ_FORMAT_CAPACITY_DATA; ++ ++/* ++ * READ FORMAT CAPACITY ++ */ ++ ++typedef struct{ ++ unsigned char OperationCode; ++ unsigned char RelAdr:1, ++ Reserved1:4, ++ LogicalUnitNumber:3; ++ unsigned char LogicalBlockAddress[4]; ++ unsigned char Reserved2; ++ unsigned char Reserved3; ++ unsigned char PMI:1, ++ Reserved4:7; ++ unsigned char Reserved5; ++ unsigned char Reserved6; ++ unsigned char Reserved7; ++} __attribute__((packed)) SCSI_READ_CAPACITY_COMMAND; ++ ++typedef struct{ ++ unsigned char LastLogicalBlockAddress[4]; ++ unsigned char BlockLengthInBytes[4]; ++} __attribute__((packed)) SCSI_READ_CAPACITY_DATA; ++ ++/* ++ * REQUEST SENSE ++ */ ++ ++typedef struct{ ++ unsigned char OperationCode; ++ unsigned char Reserved1:5, ++ LogicalUnitNumber:3; ++ unsigned char Reserved2; ++ unsigned char Reserved3; ++ unsigned char AllocationLength; ++ unsigned char Reserved4; ++ unsigned char Reserved5; ++ unsigned char Reserved6; ++ unsigned char Reserved7; ++ unsigned char Reserved8; ++ unsigned char Reserved9; ++ unsigned char Reserved10; ++} __attribute__((packed)) SCSI_REQUEST_SENSE_COMMAND; ++ ++typedef struct{ ++ unsigned char ErrorCode:7, ++ Valid:1; ++ unsigned char Reserved1; ++ unsigned char SenseKey:4, ++ Reserved2:4; ++ unsigned char Information[4]; ++ unsigned char AdditionalSenseLength; ++ unsigned char Reserved3[4]; ++ unsigned char AdditionalSenseCode; ++ unsigned char AdditionalSenseCodeQualifier; ++ unsigned char Reserved4; ++ unsigned char Reserved5[3]; ++} __attribute__((packed)) SCSI_REQUEST_SENSE_DATA; ++ ++/* ++ * READ(10) ++ */ ++ ++typedef struct{ ++ unsigned char OperationCode; ++ unsigned char RelAdr:1, ++ Reserved1:2, ++ FUA:1, ++ DPO:1, ++ LogicalUnitNumber:3; ++ unsigned char LogicalBlockAddress[4]; ++ unsigned char Reserved2; ++ unsigned char TransferLength[2]; ++ unsigned char Reserved3; ++ unsigned char Reserved4; ++ unsigned char Reserved5; ++} __attribute__((packed)) SCSI_READ_10_COMMAND; ++ ++/* ++ * MODE SENSE ++ */ ++ ++typedef struct{ ++ unsigned char OperationCode; ++ unsigned char Reserved1:3, ++ DBD:1, ++ Reserved2:1, ++ LogicalUnitNumber:3; ++ unsigned char PageCode:6, ++ PC:2; ++ unsigned char Reserved3; ++ unsigned char Reserved4; ++ unsigned char Reserved5; ++ unsigned char Reserved6; ++ unsigned char ParameterListLength[2]; ++ unsigned char Reserved7; ++ unsigned char Reserved8; ++ unsigned char Reserved9; ++} __attribute__((packed)) SCSI_MODE_SENSE_COMMAND; ++ ++typedef struct{ ++ unsigned char ModeDataLength; ++ unsigned char MediumTypeCode; ++ unsigned char Reserved1:4, ++ DPOFUA:1, ++ Reserved2:2, ++ WP:1; ++ unsigned char Reserved3; ++} __attribute__((packed)) MODE_PARAMETER_HEADER; ++ ++typedef struct{ ++ unsigned char PageCode:6, ++ Reserved1:1, ++ PS:1; ++ unsigned char PageLength; ++ unsigned char DCR:1, ++ Reserved2:1, ++ PER:1, ++ Reserved3:1, ++ RC:1, ++ Reserved4:1, ++ Reserved5:1, ++ AWRE:1; ++ unsigned char ReadRetryCount; ++ unsigned char Reserved6[4]; ++ unsigned char WriteRetryCount; ++ unsigned char Reserved7[3]; ++} __attribute__((packed)) READ_WRITE_ERROR_RECOVERY_PAGE; ++ ++typedef struct{ ++ unsigned char PageCode:6, ++ Reserved1:1, ++ PS:1; ++ unsigned char PageLength; ++ unsigned char TransferRate[2]; ++ unsigned char NumberofHeads; ++ unsigned char SectorsperTrack; ++ unsigned char DataBytesperSector[2]; ++ unsigned char NumberofCylinders[2]; ++ unsigned char Reserved2[9]; ++ unsigned char MotorOnDelay; ++ unsigned char MotorOffDelay; ++ unsigned char Reserved3[7]; ++ unsigned char MediumRotationRate[2]; ++ unsigned char Reserved4; ++ unsigned char Reserved5; ++} __attribute__((packed)) FLEXIBLE_DISK_PAGE; ++ ++typedef struct{ ++ unsigned char PageCode:6, ++ Reserved1:1, ++ PS:1; ++ unsigned char PageLength; ++ unsigned char Reserved2:6, ++ SRFP:1, ++ SFLP:1; ++ unsigned char TLUN:3, ++ Reserved3:3, ++ SML:1, ++ NCD:1; ++ unsigned char Reserved4[8]; ++} __attribute__((packed)) REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE; ++ ++typedef struct{ ++ unsigned char PageCode:6, ++ Reserved1:1, ++ PS:1; ++ unsigned char PageLength; ++ unsigned char Reserved2; ++ unsigned char InactivityTimeMultiplier:4, ++ Reserved3:4; ++ unsigned char SWPP:1, ++ DISP:1, ++ Reserved4:6; ++ unsigned char Reserved5; ++ unsigned char Reserved6; ++ unsigned char Reserved7; ++} __attribute__((packed)) TIMER_AND_PROTECT_PAGE; ++ ++typedef struct{ ++ READ_WRITE_ERROR_RECOVERY_PAGE ReadWriteErrorRecoveryPage; ++ FLEXIBLE_DISK_PAGE FlexibleDiskPage; ++ REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE RemovableBlockAccessCapabilitiesPage; ++ TIMER_AND_PROTECT_PAGE TimerAndProtectPage; ++} __attribute__((packed)) MODE_ALL_PAGES; ++ ++typedef struct{ ++ MODE_PARAMETER_HEADER ModeParameterHeader; ++ union{ ++ READ_WRITE_ERROR_RECOVERY_PAGE ReadWriteErrorRecoveryPage; ++ FLEXIBLE_DISK_PAGE FlexibleDiskPage; ++ REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE RemovableBlockAccessCapabilitiesPage; ++ TIMER_AND_PROTECT_PAGE TimerAndProtectPage; ++ MODE_ALL_PAGES ModeAllPages; ++ } __attribute__((packed)) ModePages; ++} __attribute__((packed)) SCSI_MODE_SENSE_DATA; ++ ++/* ++ * TEST UNIT READY ++ */ ++ ++typedef struct{ ++ unsigned char OperationCode; ++ unsigned char Reserved1:5, ++ LogicalUnitNumber:3; ++ unsigned char Reserved2; ++ unsigned char Reserved3; ++ unsigned char Reserved4; ++ unsigned char Reserved5; ++ unsigned char Reserved6; ++ unsigned char Reserved7; ++ unsigned char Reserved8; ++ unsigned char Reserved9; ++ unsigned char Reserved10; ++ unsigned char Reserved11; ++} __attribute__((packed)) SCSI_TEST_UNIT_READY_COMMAND; ++ ++/* ++ * PREVENT-ALLOW MEDIUM REMOVAL ++ */ ++ ++typedef struct{ ++ unsigned char OperationCode; ++ unsigned char Reserved1:5, ++ LogicalUnitNumber:3; ++ unsigned char Reserved2; ++ unsigned char Reserved3; ++ unsigned char Prevent:1, ++ Reserved4:7; ++ unsigned char Reserved5; ++ unsigned char Reserved6; ++ unsigned char Reserved7; ++ unsigned char Reserved8; ++ unsigned char Reserved9; ++ unsigned char Reserved10; ++ unsigned char Reserved11; ++} __attribute__((packed)) SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL_COMMAND; ++ ++/* ++ * START-STOP UNIT ++ */ ++ ++typedef struct{ ++ unsigned char OperationCode; ++ unsigned char IMMED:1, ++ Reserved1:4, ++ LogicalUnitNumber:3; ++ unsigned char Reserved2; ++ unsigned char Reserved3; ++ unsigned char Start:1, ++ LoEj:1, ++ Reserved4:6; ++ unsigned char Reserved5; ++ unsigned char Reserved6; ++ unsigned char Reserved7; ++ unsigned char Reserved8; ++ unsigned char Reserved9; ++ unsigned char Reserved10; ++ unsigned char Reserved11; ++} __attribute__((packed)) SCSI_START_STOP_COMMAND; ++ ++/* ++ * WRITE(10) ++ */ ++ ++typedef struct{ ++ unsigned char OperationCode; ++ unsigned char RelAdr:1, ++ Reserved1:2, ++ FUA:1, ++ DPO:1, ++ LogicalUnitNumber:3; ++ unsigned char LogicalBlockAddress[4]; ++ unsigned char Reserved2; ++ unsigned char TransferLength[2]; ++ unsigned char Reserved3; ++ unsigned char Reserved4; ++ unsigned char Reserved5; ++} __attribute__((packed)) SCSI_WRITE_10_COMMAND; ++ ++/* ++ * VERIFY ++ */ ++ ++typedef struct{ ++ unsigned char OperationCode; ++ unsigned char RelAdr:1, ++ ByteChk:1, ++ Reserved1:1, ++ Reserved2:1, ++ DPO:1, ++ LogicalUnitNumber:3; ++ unsigned char LogicalBlockAddress[4]; ++ unsigned char Reserved3; ++ unsigned char VerificationLength[2]; ++ unsigned char Reserved4; ++ unsigned char Reserved5; ++ unsigned char Reserved6; ++} __attribute__((packed)) SCSI_VERIFY_COMMAND; ++ ++/****************************************************************************** ++** Global Function Prototype ++******************************************************************************/ ++ ++/* storage-fd.c */ ++void storage_urb_send(struct usb_device_instance*, void*, int); ++ ++/* storageproto.c */ ++void storageproto_urb_analysis(struct urb*); ++int storageproto_device_open_check(void); ++void storageproto_device_close(void); ++void storageproto_usb_status_check(int); ++void storageproto_media_status_check(int); ++void storageproto_usb_reset_ind(void); ++ssize_t storageproto_proc_read(struct file*, char*, size_t, loff_t* pos); ++void storageproto_init(void); ++void storageproto_exit(void); ++ ++#endif /* _STORAGEPROTO_H_ */ ++ diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/battery.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/battery.patch index e69de29bb2..1912b33328 100644 --- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/battery.patch +++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/battery.patch @@ -0,0 +1,326 @@ + +--- linux/arch/arm/mach-sa1100/collie_battery.c Tue Jul 22 02:24:32 2003 ++++ linux/arch/arm/mach-sa1100/collie_battery.c Tue Jul 22 03:07:56 2003 +@@ -14,10 +14,11 @@ + * 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. + * + * ChangeLog: ++ * Nov 2002 Dietz Proepper: improved battery status. + * 12-Nov-2001 Lineo Japan, Inc. + * 30-Jul-2002 Lineo Japan, Inc. for 2.4.18 + * 29-Jan-2003 Sharp Corporation modify for new QT I/F + * + */ +@@ -79,10 +80,11 @@ int collie_read_BackBattery(void); + int collie_read_Temp(void); + int collie_check_temp(void); + int collie_check_voltage(void); + static void collie_charge_on(void); + static void collie_charge_off(void); ++static void do_main_battery(void); + int set_led_status(int which,int status); + int GetMainLevel( int Volt ); + int GetBackLevel( int Volt ); + int collie_get_main_battery(void); + unsigned short GetBackupBatteryAD(void); +@@ -91,40 +93,35 @@ int suspend_collie_read_Temp(void); + /*** extern ***********************************************************************/ + extern u32 apm_wakeup_src_mask; + extern int counter_step_contrast; + + +-/*** gloabal variables ************************************************************/ +-int charge_status = 0; /* charge status 1 : charge 0: not charge */ +- +-typedef struct BatteryThresh { +- int high; +- int low; +- int verylow; +-} BATTERY_THRESH; ++/* defines */ ++#define COLLIE_BATTERY_STATUS_HIGH APM_BATTERY_STATUS_HIGH ++#define COLLIE_BATTERY_STATUS_LOW APM_BATTERY_STATUS_LOW ++#define COLLIE_BATTERY_STATUS_VERYLOW APM_BATTERY_STATUS_VERY_LOW ++#define COLLIE_BATTERY_STATUS_CRITICAL APM_BATTERY_STATUS_CRITICAL + ++/*** gloabal variables ************************************************************/ ++int charge_status = 0; /* charge status 1 : charge 0: not charge */ + +-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0) || \ +- defined(CONFIG_COLLIE_TR1) || defined(CONFIG_COLLIE_DEV) +-BATTERY_THRESH collie_main_battery_thresh_fl = { +- 368, 358, 356 +-}; +- +-BATTERY_THRESH collie_main_battery_thresh_nofl = { +- 378, 364, 362 +-}; +-#else +-BATTERY_THRESH collie_main_battery_thresh_fl = { +- 368, 358, 356 +-}; +- +-BATTERY_THRESH collie_main_battery_thresh_nofl = { +- 378, 365, 363 ++typedef struct { ++ int voltage_thres[2]; /* 0: nofl 1: fl */ ++ int percent; ++ int state; ++} main_battery_thres; ++ ++#define MAIN_BATTERY_THRES 4 ++ ++main_battery_thres main_batt_thres[MAIN_BATTERY_THRES+2] = { ++ {{5000, 5000}, 100, COLLIE_BATTERY_STATUS_HIGH }, /* do not remove! */ ++ {{412,408}, 100, COLLIE_BATTERY_STATUS_HIGH}, ++ {{378,368}, 40, COLLIE_BATTERY_STATUS_HIGH}, ++ {{364,358}, 5, COLLIE_BATTERY_STATUS_LOW}, ++ {{362,356}, 1, COLLIE_BATTERY_STATUS_CRITICAL}, ++ {{0, 0}, 1, COLLIE_BATTERY_STATUS_CRITICAL } /* do not remove, too! */ + }; +-#endif +- +- + + typedef struct ChargeThresh { + int bar1; + int bar2; + int bar3; +@@ -180,24 +177,18 @@ static struct miscdevice battery_device + #define GetBackADCtoPower(x) (( 330 * x * 2 ) / 1024 ) // MAX 3.3V + #define ConvRevise(x) ( ( ad_revise * x ) / 652 ) + #define MAIN_DIFF 50 // 0.5V + #define DIFF_CNT ( 3 - 1 ) + +-#define COLLIE_BATTERY_STATUS_HIGH APM_BATTERY_STATUS_HIGH +-#define COLLIE_BATTERY_STATUS_LOW APM_BATTERY_STATUS_LOW +-#define COLLIE_BATTERY_STATUS_VERYLOW APM_BATTERY_STATUS_VERY_LOW +-#define COLLIE_BATTERY_STATUS_CRITICAL APM_BATTERY_STATUS_CRITICAL +- + #define COLLIE_AC_LINE_STATUS (!( GPLR & GPIO_AC_IN ) ? APM_AC_OFFLINE : APM_AC_ONLINE) + +- + #define COLLIE_PM_TICK ( 1000 / 10 ) // 1sec + #define COLLIE_APO_TICKTIME ( 5 * COLLIE_PM_TICK ) // 5sec + #define COLLIE_LPO_TICKTIME COLLIE_APO_TICKTIME + #define COLLIE_APO_DEFAULT ( ( 3 * 60 ) * COLLIE_PM_TICK ) // 3 min + #define COLLIE_LPO_DEFAULT ( 20 * COLLIE_PM_TICK ) // 20 sec +-#define COLLIE_MAIN_GOOD_COUNT ( 10*60 / ( COLLIE_APO_TICKTIME / COLLIE_PM_TICK ) ) ++#define COLLIE_MAIN_GOOD_COUNT ( 1*60 / ( COLLIE_APO_TICKTIME / COLLIE_PM_TICK ) ) + #define COLLIE_MAIN_NOGOOD_COUNT ( 1*60 / ( COLLIE_APO_TICKTIME / COLLIE_PM_TICK ) ) + + #define COLLIE_BACKUP_BATTERY_CK_TIME ( 10*60*1*100 ) // 10min + #define COLLIE_BACKUP_BATTERY_LOW ( 190 ) + +@@ -212,10 +203,11 @@ unsigned int LPOCntWk = 0; + static DECLARE_WAIT_QUEUE_HEAD(queue); + static int msglevel; + + int collie_backup_battery = COLLIE_BATTERY_STATUS_HIGH; + int collie_main_battery = COLLIE_BATTERY_STATUS_HIGH; ++int collie_main_battery_percent = 100; + int collie_main_charge_battery = 100; + int collie_ac_status = APM_AC_OFFLINE; + int ad_revise = 0; + + static int MainCntWk = COLLIE_MAIN_GOOD_COUNT; +@@ -229,10 +221,11 @@ static struct pm_dev *battery_pm_dev; / + + static int battery_off_flag = 0; /* charge : suspend while get adc */ + static int collie_charge_temp = 973; + static int collie_charge_volt = 465; /* charge : check charge 3.0V */ + static int charge_off_mode = 0; /* charge : check volt or non */ ++static int collie_main_battery_voltage = 400; + + static DECLARE_WAIT_QUEUE_HEAD(wq_on); + static DECLARE_WAIT_QUEUE_HEAD(wq_off); + #if 1 // 2003.1.29 + static DECLARE_WAIT_QUEUE_HEAD(battery_waitqueue); +@@ -276,28 +269,11 @@ int collie_apm_get_power_status(u_char * + } + collie_battery_status = *battery_status; + #endif + + // main battery status to percentage +- switch (*battery_status) +- { +- case COLLIE_BATTERY_STATUS_HIGH: +- *battery_percentage = 100; +- break; +- case COLLIE_BATTERY_STATUS_LOW: +- *battery_percentage = 40; +- break; +- case COLLIE_BATTERY_STATUS_VERYLOW: +- *battery_percentage = 5; +- break; +- case COLLIE_BATTERY_STATUS_CRITICAL: +- *battery_percentage = 1; +- break; +- default: +- *battery_percentage = 100; +- break; +- } ++ *battery_percentage = collie_main_battery_percent; + + if ( *ac_line_status == APM_AC_ONLINE ) + *battery_percentage = 100; + + // good or ac in --> GOOD_COUNT +@@ -529,12 +505,13 @@ int collie_get_main_battery(void) + voltage = collie_read_MainBattery(); + if ( voltage > 0 ) break; + if ( i++ > 5 ) { voltage = 380; break; } + } + +- collie_main_battery = GetMainLevel(GetMainADCtoPower(voltage)); +- collie_main_charge_battery = GetMainChargePercent(GetMainADCtoPower(voltage)); ++ collie_main_battery_voltage = GetMainADCtoPower(voltage); ++ do_main_battery(); ++ collie_main_charge_battery = GetMainChargePercent(collie_main_battery_voltage); + + DPRINTK2("charge percent = %d ( at %d ) \n",collie_main_charge_battery,jiffies); + + DPRINTK(" get Main battery status %d\n",collie_main_battery); + +@@ -562,36 +539,36 @@ int GetMainChargePercent( int Volt ) + } else { + return 5; + } + } + +-int GetMainLevel( int Volt ) ++static void do_main_battery() + { +- +- DPRINTK(" volt = %d \n",Volt); +- +- +- if ( counter_step_contrast ) { +- if ( Volt > collie_main_battery_thresh_fl.high ) +- return COLLIE_BATTERY_STATUS_HIGH; +- else if ( Volt > collie_main_battery_thresh_fl.low ) +- return COLLIE_BATTERY_STATUS_LOW; +- else if ( Volt > collie_main_battery_thresh_fl.verylow ) +- return COLLIE_BATTERY_STATUS_VERYLOW; +- else +- return COLLIE_BATTERY_STATUS_CRITICAL; +- } else { +- if ( Volt > collie_main_battery_thresh_nofl.high ) +- return COLLIE_BATTERY_STATUS_HIGH; +- else if ( Volt > collie_main_battery_thresh_nofl.low ) +- return COLLIE_BATTERY_STATUS_LOW; +- else if ( Volt > collie_main_battery_thresh_nofl.verylow ) +- return COLLIE_BATTERY_STATUS_VERYLOW; +- else +- return COLLIE_BATTERY_STATUS_CRITICAL; +- } +- ++ int i = MAIN_BATTERY_THRES; ++ int fl = (counter_step_contrast)? 1 : 0; ++ ++ while ( i > 0 && ++ ( collie_main_battery_voltage > main_batt_thres[i].voltage_thres[fl] ) ) ++ i--; ++ /* i is now between 0 and MAIN_BATTERY_THRES. That means ++ * we can safely access main_batt_thres[i] and ++ * main_batt_thres[i+1] */ ++ ++ collie_main_battery = main_batt_thres[i].state; ++ { /* perhaps we should put that deltas to our table, too? */ ++ long deltav = main_batt_thres[i].voltage_thres[fl] - ++ main_batt_thres[i+1].voltage_thres[fl]; ++ long deltap = main_batt_thres[i].percent - ++ main_batt_thres[i+1].percent; ++ ++ collie_main_battery_percent = /* (1) */ ++ main_batt_thres[i+1].percent + ++ deltap * (collie_main_battery_voltage - ++ main_batt_thres[i+1].voltage_thres[fl]) / ++ deltav; ++ DPRINTK("Battery stuff: v=%i i=%i , dv=%li , dp=%li , p=%i",collie_main_battery_voltage , i, deltav, deltap, collie_main_battery_percent ); ++ } + } + + + int GetBackLevel( int Volt ) + { +@@ -834,20 +811,18 @@ unsigned short chkFatalBatt(void) + GEDR = GPIO_CO; + // printk("CO = %x\n",GEDR&GPIO_CO); + } + + +- if ( volt < collie_main_battery_thresh_nofl.verylow ) ++ if ( volt < main_batt_thres[MAIN_BATTERY_THRES].voltage_thres[0] ) + return 0; + else + return 1; + #endif + } + + +- +- + int suspend_collie_check_temp(void) + { + unsigned short temp , i = 0; + + while(1) { +@@ -1032,10 +1007,11 @@ struct proc_dir_entry *proc_batt; + typedef struct collie_battery_entry { + int* addr; + int def_value; + char* name; + char* description; ++ char readonly; + unsigned short low_ino; + } collie_battery_entry_t; + + #if 1 // 2003.1.29 + static collie_battery_entry_t collie_battery_params[] = { +@@ -1044,11 +1020,13 @@ static collie_battery_entry_t collie_bat + { &collie_change_battery_status , 0 , "chg_status", "Change status" } + }; + #else + static collie_battery_entry_t collie_battery_params[] = { + /* { addr, def_value, name, description }*/ +- { &msglevel, 0, "msglevel", "debug message output level" } ++/* { &msglevel, 0, "msglevel", "debug message output level" } */ ++ { &msglevel, 0, "msglevel", "debug message output level", 0 }, ++ { &collie_main_battery_voltage, -1, "main_voltage", "main battery voltage", 1 } + }; + #endif + #define NUM_OF_BATTERY_ENTRY (sizeof(collie_battery_params)/sizeof(collie_battery_entry_t)) + + static ssize_t collie_battery_read_params(struct file *file, char *buf, +@@ -1069,11 +1047,12 @@ static ssize_t collie_battery_read_param + } + } + if (current_param==NULL) { + return -EINVAL; + } +- count = sprintf(outputbuf, "0x%08X\n", ++// count = sprintf(outputbuf, "0x%08X\n", ++ count = sprintf(outputbuf, "%04i\n", + *((volatile Word *) current_param->addr)); + *ppos += count; + if (count>nbytes) /* Assume output can be read at one time */ + return -EINVAL; + if (copy_to_user(buf, outputbuf, count)) +@@ -1094,11 +1073,12 @@ static ssize_t collie_battery_write_para + if(collie_battery_params[i].low_ino==i_ino) { + current_param = &collie_battery_params[i]; + break; + } + } +- if (current_param==NULL) { ++// if (current_param==NULL) { ++ if (current_param==NULL || current_param->readonly) { + return -EINVAL; + } + + param = simple_strtoul(buf,&endp,0); + if (param == -1) { + diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/bluetooth-patch-2.4.18-mh9.diff b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/bluetooth-patch-2.4.18-mh9.diff index e69de29bb2..b31c57992f 100644 --- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/bluetooth-patch-2.4.18-mh9.diff +++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/bluetooth-patch-2.4.18-mh9.diff @@ -0,0 +1,30831 @@ +diff -urN linux-2.4.18/CREDITS linux-2.4.18-mh9/CREDITS +--- linux-2.4.18/CREDITS Mon Feb 25 20:37:50 2002 ++++ linux-2.4.18-mh9/CREDITS Mon Aug 25 18:38:09 2003 +@@ -1317,6 +1317,14 @@ + S: Provo, Utah 84606-5607 + S: USA + ++N: Marcel Holtmann ++E: marcel@holtmann.org ++W: http://www.holtmann.org ++D: Author and maintainer of the various Bluetooth HCI drivers ++D: Author and maintainer of the CAPI message transport protocol driver ++D: Various other Bluetooth related patches, cleanups and fixes ++S: Germany ++ + N: Rob W. W. Hooft + E: hooft@EMBL-Heidelberg.DE + D: Shared libs for graphics-tools and for the f2c compiler +diff -urN linux-2.4.18/Documentation/Configure.help linux-2.4.18-mh9/Documentation/Configure.help +--- linux-2.4.18/Documentation/Configure.help Mon Feb 25 20:37:51 2002 ++++ linux-2.4.18-mh9/Documentation/Configure.help Mon Aug 25 18:38:10 2003 +@@ -2824,14 +2824,6 @@ + + If unsure, say N. + +-HCI EMU (virtual device) driver +-CONFIG_BLUEZ_HCIEMU +- Bluetooth Virtual HCI device driver. +- This driver is required if you want to use HCI Emulation software. +- +- Say Y here to compile support for Virtual HCI devices into the +- kernel or say M to compile it as module (hci_usb.o). +- + # Choice: alphatype + Alpha system type + CONFIG_ALPHA_GENERIC +@@ -11037,6 +11029,12 @@ + + If unsure, say N. + ++Hotplug firmware loading support (EXPERIMENTAL) ++CONFIG_FW_LOADER ++ This option is provided for the case where no in-kernel-tree modules require ++ hotplug firmware loading support, but a module built outside the kernel tree ++ does. ++ + Use PCI shared memory for NIC registers + CONFIG_TULIP_MMIO + Use PCI shared memory for the NIC registers, rather than going through +@@ -19870,11 +19868,15 @@ + Bluetooth can be found at <http://www.bluetooth.com/>. + + Linux Bluetooth subsystem consist of several layers: +- HCI Core (device and connection manager, scheduler) ++ BlueZ Core (HCI device and connection manager, scheduler) + HCI Device drivers (interface to the hardware) + L2CAP Module (L2CAP protocol) ++ SCO Module (SCO links) ++ RFCOMM Module (RFCOMM protocol) ++ BNEP Module (BNEP protocol) ++ CMTP Module (CMTP protocol) + +- Say Y here to enable Linux Bluetooth support and to build HCI Core ++ Say Y here to enable Linux Bluetooth support and to build BlueZ Core + layer. + + To use Linux Bluetooth subsystem, you will need several user-space +@@ -19882,7 +19884,7 @@ + Bluetooth kernel modules are provided in the BlueZ package. + For more information, see <http://bluez.sourceforge.net/>. + +- If you want to compile HCI Core as module (hci.o) say M here. ++ If you want to compile BlueZ Core as module (bluez.o) say M here. + + L2CAP protocol support + CONFIG_BLUEZ_L2CAP +@@ -19893,15 +19895,91 @@ + Say Y here to compile L2CAP support into the kernel or say M to + compile it as module (l2cap.o). + ++SCO links support ++CONFIG_BLUEZ_SCO ++ SCO link provides voice transport over Bluetooth. SCO support is ++ required for voice applications like Headset and Audio. ++ ++ Say Y here to compile SCO support into the kernel or say M to ++ compile it as module (sco.o). ++ ++RFCOMM protocol support ++CONFIG_BLUEZ_RFCOMM ++ RFCOMM provides connection oriented stream transport. RFCOMM ++ support is required for Dialup Networking, OBEX and other Bluetooth ++ applications. ++ ++ Say Y here to compile RFCOMM support into the kernel or say M to ++ compile it as module (rfcomm.o). ++ ++RFCOMM TTY emulation support ++CONFIG_BLUEZ_RFCOMM_TTY ++ This option enables TTY emulation support for RFCOMM channels. ++ ++BNEP protocol support ++CONFIG_BLUEZ_BNEP ++ BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet ++ emulation layer on top of Bluetooth. BNEP is required for Bluetooth ++ PAN (Personal Area Network). ++ ++ To use BNEP, you will need user-space utilities provided in the ++ BlueZ-PAN package. ++ For more information, see <http://bluez.sourceforge.net>. ++ ++ Say Y here to compile BNEP support into the kernel or say M to ++ compile it as module (bnep.o). ++ ++CMTP protocol support ++CONFIG_BLUEZ_CMTP ++ CMTP (CAPI Message Transport Protocol) is a transport layer ++ for CAPI messages. CMTP is required for the Bluetooth Common ++ ISDN Access Profile. ++ ++ Say Y here to compile CMTP support into the kernel or say M to ++ compile it as module (cmtp.o). ++ ++BNEP multicast filter support ++CONFIG_BLUEZ_BNEP_MC_FILTER ++ This option enables the multicast filter support for BNEP. ++ ++BNEP protocol filter support ++CONFIG_BLUEZ_BNEP_PROTO_FILTER ++ This option enables the protocol filter support for BNEP. ++ + HCI UART driver + CONFIG_BLUEZ_HCIUART + Bluetooth HCI UART driver. + This driver is required if you want to use Bluetooth devices with +- serial port interface. ++ serial port interface. You will also need this driver if you have ++ UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card ++ adapter and BrainBoxes Bluetooth PC Card. + + Say Y here to compile support for Bluetooth UART devices into the + kernel or say M to compile it as module (hci_uart.o). + ++HCI UART (H4) protocol support ++CONFIG_BLUEZ_HCIUART_H4 ++ UART (H4) is serial protocol for communication between Bluetooth ++ device and host. This protocol is required for most Bluetooth devices ++ with UART interface, including PCMCIA and CF cards. ++ ++ Say Y here to compile support for HCI UART (H4) protocol. ++ ++HCI BCSP protocol support ++CONFIG_BLUEZ_HCIUART_BCSP ++ BCSP (BlueCore Serial Protocol) is serial protocol for communication ++ between Bluetooth device and host. This protocol is required for non ++ USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and ++ CF cards. ++ ++ Say Y here to compile support for HCI BCSP protocol. ++ ++HCI BCSP transmit CRC with every BCSP packet ++CONFIG_BLUEZ_HCIUART_BCSP_TXCRC ++ If you say Y here, a 16-bit CRC checksum will be transmitted along with ++ every BCSP (BlueCore Serial Protocol) packet sent to the Bluetooth chip. ++ This increases reliability, but slightly reduces efficiency. ++ + HCI USB driver + CONFIG_BLUEZ_HCIUSB + Bluetooth HCI USB driver. +@@ -19911,13 +19989,90 @@ + Say Y here to compile support for Bluetooth USB devices into the + kernel or say M to compile it as module (hci_usb.o). + +-HCI VHCI virtual HCI device driver ++HCI USB SCO (voice) support ++CONFIG_BLUEZ_USB_SCO ++ This option enables the SCO support in the HCI USB driver. You need this ++ to transmit voice data with your Bluetooth USB device. And your device ++ must also support sending SCO data over the HCI layer, because some of ++ them sends the SCO data to an internal PCM adapter. ++ ++ Say Y here to compile support for HCI SCO data. ++ ++HCI USB zero packet support ++CONFIG_BLUEZ_USB_ZERO_PACKET ++ This option is provided only as a work around for buggy Bluetooth USB ++ devices. Do NOT enable it unless you know for sure that your device ++ requires zero packets. ++ ++ Most people should say N here. ++ ++HCI VHCI Virtual HCI device driver + CONFIG_BLUEZ_HCIVHCI + Bluetooth Virtual HCI device driver. + This driver is required if you want to use HCI Emulation software. + + Say Y here to compile support for virtual HCI devices into the + kernel or say M to compile it as module (hci_vhci.o). ++ ++HCI BFUSB device driver ++CONFIG_BLUEZ_HCIBFUSB ++ Bluetooth HCI BlueFRITZ! USB driver. ++ This driver provides support for Bluetooth USB devices with AVM ++ interface: ++ AVM BlueFRITZ! USB ++ ++ Say Y here to compile support for HCI BFUSB devices into the ++ kernel or say M to compile it as module (bfusb.o). ++ ++HCI DTL1 (PC Card) device driver ++CONFIG_BLUEZ_HCIDTL1 ++ Bluetooth HCI DTL1 (PC Card) driver. ++ This driver provides support for Bluetooth PCMCIA devices with ++ Nokia DTL1 interface: ++ Nokia Bluetooth Card ++ Socket Bluetooth CF Card ++ ++ Say Y here to compile support for HCI DTL1 devices into the ++ kernel or say M to compile it as module (dtl1_cs.o). ++ ++HCI BT3C (PC Card) device driver ++CONFIG_BLUEZ_HCIBT3C ++ Bluetooth HCI BT3C (PC Card) driver. ++ This driver provides support for Bluetooth PCMCIA devices with ++ 3Com BT3C interface: ++ 3Com Bluetooth Card (3CRWB6096) ++ HP Bluetooth Card ++ ++ The HCI BT3C driver uses external firmware loader program provided in ++ the BlueFW package. For more information, see <http://bluez.sf.net>. ++ ++ Say Y here to compile support for HCI BT3C devices into the ++ kernel or say M to compile it as module (bt3c_cs.o). ++ ++HCI BlueCard (PC Card) device driver ++CONFIG_BLUEZ_HCIBLUECARD ++ Bluetooth HCI BlueCard (PC Card) driver. ++ This driver provides support for Bluetooth PCMCIA devices with ++ Anycom BlueCard interface: ++ Anycom Bluetooth PC Card ++ Anycom Bluetooth CF Card ++ ++ Say Y here to compile support for HCI BlueCard devices into the ++ kernel or say M to compile it as module (bluecard_cs.o). ++ ++HCI UART (PC Card) device driver ++CONFIG_BLUEZ_HCIBTUART ++ Bluetooth HCI UART (PC Card) driver. ++ This driver provides support for Bluetooth PCMCIA devices with ++ an UART interface: ++ Xircom CreditCard Bluetooth Adapter ++ Xircom RealPort2 Bluetooth Adapter ++ Sphinx PICO Card ++ H-Soft blue+Card ++ Cyber-blue Compact Flash Card ++ ++ Say Y here to compile support for HCI UART devices into the ++ kernel or say M to compile it as module (btuart_cs.o). + + # The following options are for Linux when running on the Hitachi + # SuperH family of RISC microprocessors. +diff -urN linux-2.4.18/Documentation/firmware_class/README linux-2.4.18-mh9/Documentation/firmware_class/README +--- linux-2.4.18/Documentation/firmware_class/README Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/Documentation/firmware_class/README Mon Aug 25 18:38:10 2003 +@@ -0,0 +1,58 @@ ++ ++ request_firmware() hotplug interface: ++ ------------------------------------ ++ Copyright (C) 2003 Manuel Estrada Sainz <ranty@debian.org> ++ ++ Why: ++ --- ++ ++ Today, the most extended way to use firmware in the Linux kernel is linking ++ it statically in a header file. Which has political and technical issues: ++ ++ 1) Some firmware is not legal to redistribute. ++ 2) The firmware occupies memory permanently, even though it often is just ++ used once. ++ 3) Some people, like the Debian crowd, don't consider some firmware free ++ enough and remove entire drivers (e.g.: keyspan). ++ ++ about in-kernel persistence: ++ --------------------------- ++ Under some circumstances, as explained below, it would be interesting to keep ++ firmware images in non-swappable kernel memory or even in the kernel image ++ (probably within initramfs). ++ ++ Note that this functionality has not been implemented. ++ ++ - Why OPTIONAL in-kernel persistence may be a good idea sometimes: ++ ++ - If the device that needs the firmware is needed to access the ++ filesystem. When upon some error the device has to be reset and the ++ firmware reloaded, it won't be possible to get it from userspace. ++ e.g.: ++ - A diskless client with a network card that needs firmware. ++ - The filesystem is stored in a disk behind an scsi device ++ that needs firmware. ++ - Replacing buggy DSDT/SSDT ACPI tables on boot. ++ Note: this would require the persistent objects to be included ++ within the kernel image, probably within initramfs. ++ ++ And the same device can be needed to access the filesystem or not depending ++ on the setup, so I think that the choice on what firmware to make ++ persistent should be left to userspace. ++ ++ - Why register_firmware()+__init can be useful: ++ - For boot devices needing firmware. ++ - To make the transition easier: ++ The firmware can be declared __init and register_firmware() ++ called on module_init. Then the firmware is warranted to be ++ there even if "firmware hotplug userspace" is not there yet or ++ it doesn't yet provide the needed firmware. ++ Once the firmware is widely available in userspace, it can be ++ removed from the kernel. Or made optional (CONFIG_.*_FIRMWARE). ++ ++ In either case, if firmware hotplug support is there, it can move the ++ firmware out of kernel memory into the real filesystem for later ++ usage. ++ ++ Note: If persistence is implemented on top of initramfs, ++ register_firmware() may not be appropriate. +diff -urN linux-2.4.18/Documentation/firmware_class/firmware_sample_driver.c linux-2.4.18-mh9/Documentation/firmware_class/firmware_sample_driver.c +--- linux-2.4.18/Documentation/firmware_class/firmware_sample_driver.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/Documentation/firmware_class/firmware_sample_driver.c Mon Aug 25 18:38:10 2003 +@@ -0,0 +1,121 @@ ++/* ++ * firmware_sample_driver.c - ++ * ++ * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org> ++ * ++ * Sample code on how to use request_firmware() from drivers. ++ * ++ * Note that register_firmware() is currently useless. ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/string.h> ++ ++#include "linux/firmware.h" ++ ++#define WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE ++#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE ++char __init inkernel_firmware[] = "let's say that this is firmware\n"; ++#endif ++ ++static char ghost_device[] = "ghost0"; ++ ++static void sample_firmware_load(char *firmware, int size) ++{ ++ u8 buf[size+1]; ++ memcpy(buf, firmware, size); ++ buf[size] = '\0'; ++ printk("firmware_sample_driver: firmware: %s\n", buf); ++} ++ ++static void sample_probe_default(void) ++{ ++ /* uses the default method to get the firmware */ ++ const struct firmware *fw_entry; ++ printk("firmware_sample_driver: a ghost device got inserted :)\n"); ++ ++ if(request_firmware(&fw_entry, "sample_driver_fw", ghost_device)!=0) ++ { ++ printk(KERN_ERR ++ "firmware_sample_driver: Firmware not available\n"); ++ return; ++ } ++ ++ sample_firmware_load(fw_entry->data, fw_entry->size); ++ ++ release_firmware(fw_entry); ++ ++ /* finish setting up the device */ ++} ++static void sample_probe_specific(void) ++{ ++ /* Uses some specific hotplug support to get the firmware from ++ * userspace directly into the hardware, or via some sysfs file */ ++ ++ /* NOTE: This currently doesn't work */ ++ ++ printk("firmware_sample_driver: a ghost device got inserted :)\n"); ++ ++ if(request_firmware(NULL, "sample_driver_fw", ghost_device)!=0) ++ { ++ printk(KERN_ERR ++ "firmware_sample_driver: Firmware load failed\n"); ++ return; ++ } ++ ++ /* request_firmware blocks until userspace finished, so at ++ * this point the firmware should be already in the device */ ++ ++ /* finish setting up the device */ ++} ++static void sample_probe_async_cont(const struct firmware *fw, void *context) ++{ ++ if(!fw){ ++ printk(KERN_ERR ++ "firmware_sample_driver: firmware load failed\n"); ++ return; ++ } ++ ++ printk("firmware_sample_driver: device pointer \"%s\"\n", ++ (char *)context); ++ sample_firmware_load(fw->data, fw->size); ++} ++static void sample_probe_async(void) ++{ ++ /* Let's say that I can't sleep */ ++ int error; ++ error = request_firmware_nowait (THIS_MODULE, ++ "sample_driver_fw", ghost_device, ++ "my device pointer", ++ sample_probe_async_cont); ++ if(error){ ++ printk(KERN_ERR ++ "firmware_sample_driver:" ++ " request_firmware_nowait failed\n"); ++ } ++} ++ ++static int sample_init(void) ++{ ++#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE ++ register_firmware("sample_driver_fw", inkernel_firmware, ++ sizeof(inkernel_firmware)); ++#endif ++ /* since there is no real hardware insertion I just call the ++ * sample probe functions here */ ++ sample_probe_specific(); ++ sample_probe_default(); ++ sample_probe_async(); ++ return 0; ++} ++static void __exit sample_exit(void) ++{ ++} ++ ++module_init (sample_init); ++module_exit (sample_exit); ++ ++MODULE_LICENSE("GPL"); +diff -urN linux-2.4.18/Documentation/firmware_class/hotplug-script linux-2.4.18-mh9/Documentation/firmware_class/hotplug-script +--- linux-2.4.18/Documentation/firmware_class/hotplug-script Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/Documentation/firmware_class/hotplug-script Mon Aug 25 18:38:10 2003 +@@ -0,0 +1,16 @@ ++#!/bin/sh ++ ++# Simple hotplug script sample: ++# ++# Both $DEVPATH and $FIRMWARE are already provided in the environment. ++ ++HOTPLUG_FW_DIR=/usr/lib/hotplug/firmware/ ++ ++echo 1 > /sysfs/$DEVPATH/loading ++cat $HOTPLUG_FW_DIR/$FIRMWARE > /sysfs/$DEVPATH/data ++echo 0 > /sysfs/$DEVPATH/loading ++ ++# To cancel the load in case of error: ++# ++# echo -1 > /sysfs/$DEVPATH/loading ++# +diff -urN linux-2.4.18/MAINTAINERS linux-2.4.18-mh9/MAINTAINERS +--- linux-2.4.18/MAINTAINERS Mon Feb 25 20:37:52 2002 ++++ linux-2.4.18-mh9/MAINTAINERS Mon Aug 25 18:38:10 2003 +@@ -252,7 +252,73 @@ + L: linux-kernel@vger.kernel.org + S: Maintained + +-BLUETOOTH SUBSYSTEM (BlueZ) ++BLUETOOTH SUBSYSTEM ++P: Maxim Krasnyansky ++M: maxk@qualcomm.com ++W: http://bluez.sf.net ++S: Maintained ++ ++BLUETOOTH RFCOMM LAYER ++P: Maxim Krasnyansky ++M: maxk@qualcomm.com ++W: http://bluez.sf.net ++S: Maintained ++ ++BLUETOOTH BNEP LAYER ++P: Maxim Krasnyansky ++M: maxk@qualcomm.com ++W: http://bluez.sf.net ++S: Maintained ++ ++BLUETOOTH CMTP LAYER ++P: Marcel Holtmann ++M: marcel@holtmann.org ++W: http://www.holtmann.org/linux/bluetooth/ ++S: Maintained ++ ++BLUETOOTH HCI USB DRIVER ++P: Maxim Krasnyansky ++M: maxk@qualcomm.com ++W: http://bluez.sf.net ++S: Maintained ++ ++BLUETOOTH HCI UART DRIVER ++P: Maxim Krasnyansky ++M: maxk@qualcomm.com ++W: http://bluez.sf.net ++S: Maintained ++ ++BLUETOOTH HCI BFUSB DRIVER ++P: Marcel Holtmann ++M: marcel@holtmann.org ++W: http://www.holtmann.org/linux/bluetooth/ ++S: Maintained ++ ++BLUETOOTH HCI DTL1 DRIVER ++P: Marcel Holtmann ++M: marcel@holtmann.org ++W: http://www.holtmann.org/linux/bluetooth/ ++S: Maintained ++ ++BLUETOOTH HCI BLUECARD DRIVER ++P: Marcel Holtmann ++M: marcel@holtmann.org ++W: http://www.holtmann.org/linux/bluetooth/ ++S: Maintained ++ ++BLUETOOTH HCI BT3C DRIVER ++P: Marcel Holtmann ++M: marcel@holtmann.org ++W: http://www.holtmann.org/linux/bluetooth/ ++S: Maintained ++ ++BLUETOOTH HCI BTUART DRIVER ++P: Marcel Holtmann ++M: marcel@holtmann.org ++W: http://www.holtmann.org/linux/bluetooth/ ++S: Maintained ++ ++BLUETOOTH HCI VHCI DRIVER + P: Maxim Krasnyansky + M: maxk@qualcomm.com + W: http://bluez.sf.net +diff -urN linux-2.4.18/arch/alpha/config.in linux-2.4.18-mh9/arch/alpha/config.in +--- linux-2.4.18/arch/alpha/config.in Wed Nov 21 00:49:31 2001 ++++ linux-2.4.18-mh9/arch/alpha/config.in Mon Aug 25 18:38:10 2003 +@@ -371,9 +371,7 @@ + source drivers/usb/Config.in + source drivers/input/Config.in + +-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +- source net/bluetooth/Config.in +-fi ++source net/bluetooth/Config.in + + mainmenu_option next_comment + comment 'Kernel hacking' +diff -urN linux-2.4.18/arch/arm/config.in linux-2.4.18-mh9/arch/arm/config.in +--- linux-2.4.18/arch/arm/config.in Fri Nov 9 22:58:02 2001 ++++ linux-2.4.18-mh9/arch/arm/config.in Mon Aug 25 18:38:10 2003 +@@ -584,9 +584,7 @@ + + source drivers/usb/Config.in + +-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +- source net/bluetooth/Config.in +-fi ++source net/bluetooth/Config.in + + mainmenu_option next_comment + comment 'Kernel hacking' +diff -urN linux-2.4.18/arch/i386/config.in linux-2.4.18-mh9/arch/i386/config.in +--- linux-2.4.18/arch/i386/config.in Mon Feb 25 20:37:52 2002 ++++ linux-2.4.18-mh9/arch/i386/config.in Mon Aug 25 18:38:10 2003 +@@ -407,9 +407,7 @@ + + source drivers/usb/Config.in + +-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +- source net/bluetooth/Config.in +-fi ++source net/bluetooth/Config.in + + mainmenu_option next_comment + comment 'Kernel hacking' +diff -urN linux-2.4.18/arch/ppc/config.in linux-2.4.18-mh9/arch/ppc/config.in +--- linux-2.4.18/arch/ppc/config.in Mon Feb 25 20:37:55 2002 ++++ linux-2.4.18-mh9/arch/ppc/config.in Mon Aug 25 18:38:10 2003 +@@ -389,9 +389,7 @@ + + source drivers/usb/Config.in + +-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +- source net/bluetooth/Config.in +-fi ++source net/bluetooth/Config.in + + mainmenu_option next_comment + comment 'Kernel hacking' +diff -urN linux-2.4.18/arch/sparc/config.in linux-2.4.18-mh9/arch/sparc/config.in +--- linux-2.4.18/arch/sparc/config.in Tue Jun 12 04:15:27 2001 ++++ linux-2.4.18-mh9/arch/sparc/config.in Mon Aug 25 18:38:10 2003 +@@ -251,9 +251,7 @@ + + source fs/Config.in + +-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +- source net/bluetooth/Config.in +-fi ++source net/bluetooth/Config.in + + mainmenu_option next_comment + comment 'Watchdog' +diff -urN linux-2.4.18/arch/sparc64/config.in linux-2.4.18-mh9/arch/sparc64/config.in +--- linux-2.4.18/arch/sparc64/config.in Fri Dec 21 18:41:53 2001 ++++ linux-2.4.18-mh9/arch/sparc64/config.in Mon Aug 25 18:38:10 2003 +@@ -283,9 +283,7 @@ + + source drivers/usb/Config.in + +-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +- source net/bluetooth/Config.in +-fi ++source net/bluetooth/Config.in + + mainmenu_option next_comment + comment 'Watchdog' +diff -urN linux-2.4.18/arch/sparc64/kernel/ioctl32.c linux-2.4.18-mh9/arch/sparc64/kernel/ioctl32.c +--- linux-2.4.18/arch/sparc64/kernel/ioctl32.c Mon Feb 25 20:37:56 2002 ++++ linux-2.4.18-mh9/arch/sparc64/kernel/ioctl32.c Mon Aug 25 18:38:10 2003 +@@ -92,6 +92,7 @@ + + #include <net/bluetooth/bluetooth.h> + #include <net/bluetooth/hci.h> ++#include <net/bluetooth/rfcomm.h> + + #include <linux/usb.h> + #include <linux/usbdevice_fs.h> +@@ -3822,6 +3823,15 @@ + return err; + } + ++/* Bluetooth ioctls */ ++#define HCIUARTSETPROTO _IOW('U', 200, int) ++#define HCIUARTGETPROTO _IOR('U', 201, int) ++ ++#define BNEPCONNADD _IOW('B', 200, int) ++#define BNEPCONNDEL _IOW('B', 201, int) ++#define BNEPGETCONNLIST _IOR('B', 210, int) ++#define BNEPGETCONNINFO _IOR('B', 211, int) ++ + struct mtd_oob_buf32 { + u32 start; + u32 length; +@@ -3878,6 +3888,11 @@ + return ((0 == ret) ? 0 : -EFAULT); + } + ++#define CMTPCONNADD _IOW('C', 200, int) ++#define CMTPCONNDEL _IOW('C', 201, int) ++#define CMTPGETCONNLIST _IOR('C', 210, int) ++#define CMTPGETCONNINFO _IOR('C', 211, int) ++ + struct ioctl_trans { + unsigned int cmd; + unsigned int handler; +@@ -4540,6 +4555,21 @@ + COMPATIBLE_IOCTL(HCISETSCAN) + COMPATIBLE_IOCTL(HCISETAUTH) + COMPATIBLE_IOCTL(HCIINQUIRY) ++COMPATIBLE_IOCTL(HCIUARTSETPROTO) ++COMPATIBLE_IOCTL(HCIUARTGETPROTO) ++COMPATIBLE_IOCTL(RFCOMMCREATEDEV) ++COMPATIBLE_IOCTL(RFCOMMRELEASEDEV) ++COMPATIBLE_IOCTL(RFCOMMGETDEVLIST) ++COMPATIBLE_IOCTL(RFCOMMGETDEVINFO) ++COMPATIBLE_IOCTL(RFCOMMSTEALDLC) ++COMPATIBLE_IOCTL(BNEPCONNADD) ++COMPATIBLE_IOCTL(BNEPCONNDEL) ++COMPATIBLE_IOCTL(BNEPGETCONNLIST) ++COMPATIBLE_IOCTL(BNEPGETCONNINFO) ++COMPATIBLE_IOCTL(CMTPCONNADD) ++COMPATIBLE_IOCTL(CMTPCONNDEL) ++COMPATIBLE_IOCTL(CMTPGETCONNLIST) ++COMPATIBLE_IOCTL(CMTPGETCONNINFO) + /* Misc. */ + COMPATIBLE_IOCTL(0x41545900) /* ATYIO_CLKR */ + COMPATIBLE_IOCTL(0x41545901) /* ATYIO_CLKW */ +diff -urN linux-2.4.18/drivers/bluetooth/Config.in linux-2.4.18-mh9/drivers/bluetooth/Config.in +--- linux-2.4.18/drivers/bluetooth/Config.in Fri Sep 7 18:28:38 2001 ++++ linux-2.4.18-mh9/drivers/bluetooth/Config.in Mon Aug 25 18:38:10 2003 +@@ -1,8 +1,34 @@ ++# ++# Bluetooth HCI device drivers configuration ++# ++ + mainmenu_option next_comment + comment 'Bluetooth device drivers' + + dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB ++if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then ++ bool ' SCO (voice) support' CONFIG_BLUEZ_USB_SCO ++ bool ' USB zero packet support' CONFIG_BLUEZ_USB_ZERO_PACKET ++fi ++ + dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ +-dep_tristate 'HCI VHCI virtual HCI device driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ ++if [ "$CONFIG_BLUEZ_HCIUART" != "n" ]; then ++ bool ' UART (H4) protocol support' CONFIG_BLUEZ_HCIUART_H4 ++ bool ' BCSP protocol support' CONFIG_BLUEZ_HCIUART_BCSP ++ dep_bool ' Transmit CRC with every BCSP packet' CONFIG_BLUEZ_HCIUART_BCSP_TXCRC $CONFIG_BLUEZ_HCIUART_BCSP ++fi ++ ++dep_tristate 'HCI BlueFRITZ! USB driver' CONFIG_BLUEZ_HCIBFUSB $CONFIG_BLUEZ $CONFIG_USB ++ ++dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ ++ ++dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BLUEZ_HCIBT3C $CONFIG_PCMCIA $CONFIG_BLUEZ ++ ++dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ ++ ++dep_tristate 'HCI UART (PC Card) driver' CONFIG_BLUEZ_HCIBTUART $CONFIG_PCMCIA $CONFIG_BLUEZ ++ ++dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ + + endmenu ++ +diff -urN linux-2.4.18/drivers/bluetooth/Makefile linux-2.4.18-mh9/drivers/bluetooth/Makefile +--- linux-2.4.18/drivers/bluetooth/Makefile Fri Sep 7 18:28:38 2001 ++++ linux-2.4.18-mh9/drivers/bluetooth/Makefile Mon Aug 25 18:38:10 2003 +@@ -1,11 +1,27 @@ + # +-# Makefile for Bluetooth HCI device drivers. ++# Makefile for the Linux Bluetooth HCI device drivers + # + + O_TARGET := bluetooth.o + ++list-multi := hci_uart.o ++ + obj-$(CONFIG_BLUEZ_HCIUSB) += hci_usb.o +-obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o + obj-$(CONFIG_BLUEZ_HCIVHCI) += hci_vhci.o + ++obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o ++uart-y := hci_ldisc.o ++uart-$(CONFIG_BLUEZ_HCIUART_H4) += hci_h4.o ++uart-$(CONFIG_BLUEZ_HCIUART_BCSP) += hci_bcsp.o ++ ++obj-$(CONFIG_BLUEZ_HCIBFUSB) += bfusb.o ++ ++obj-$(CONFIG_BLUEZ_HCIDTL1) += dtl1_cs.o ++obj-$(CONFIG_BLUEZ_HCIBT3C) += bt3c_cs.o ++obj-$(CONFIG_BLUEZ_HCIBLUECARD) += bluecard_cs.o ++obj-$(CONFIG_BLUEZ_HCIBTUART) += btuart_cs.o ++ + include $(TOPDIR)/Rules.make ++ ++hci_uart.o: $(uart-y) ++ $(LD) -r -o $@ $(uart-y) +diff -urN linux-2.4.18/drivers/bluetooth/Makefile.lib linux-2.4.18-mh9/drivers/bluetooth/Makefile.lib +--- linux-2.4.18/drivers/bluetooth/Makefile.lib Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/drivers/bluetooth/Makefile.lib Mon Aug 25 18:38:10 2003 +@@ -0,0 +1 @@ ++obj-$(CONFIG_BLUEZ_HCIBFUSB) += firmware_class.o +diff -urN linux-2.4.18/drivers/bluetooth/bfusb.c linux-2.4.18-mh9/drivers/bluetooth/bfusb.c +--- linux-2.4.18/drivers/bluetooth/bfusb.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/drivers/bluetooth/bfusb.c Mon Aug 25 18:38:10 2003 +@@ -0,0 +1,781 @@ ++/* ++ * ++ * AVM BlueFRITZ! USB driver ++ * ++ * Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org> ++ * ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * 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 <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/types.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/skbuff.h> ++ ++#include <linux/firmware.h> ++#include <linux/usb.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++ ++#ifndef CONFIG_BLUEZ_HCIBFUSB_DEBUG ++#undef BT_DBG ++#define BT_DBG(D...) ++#endif ++ ++#define VERSION "1.1" ++ ++static struct usb_device_id bfusb_table[] = { ++ /* AVM BlueFRITZ! USB */ ++ { USB_DEVICE(0x057c, 0x2200) }, ++ ++ { } /* Terminating entry */ ++}; ++ ++MODULE_DEVICE_TABLE(usb, bfusb_table); ++ ++ ++#define BFUSB_MAX_BLOCK_SIZE 256 ++ ++#define BFUSB_BLOCK_TIMEOUT (HZ * 3) ++ ++#define BFUSB_TX_PROCESS 1 ++#define BFUSB_TX_WAKEUP 2 ++ ++#define BFUSB_MAX_BULK_TX 1 ++#define BFUSB_MAX_BULK_RX 1 ++ ++struct bfusb { ++ struct hci_dev hdev; ++ ++ unsigned long state; ++ ++ struct usb_device *udev; ++ ++ unsigned int bulk_in_ep; ++ unsigned int bulk_out_ep; ++ unsigned int bulk_pkt_size; ++ ++ rwlock_t lock; ++ ++ struct sk_buff_head transmit_q; ++ ++ struct sk_buff *reassembly; ++ ++ atomic_t pending_tx; ++ struct sk_buff_head pending_q; ++ struct sk_buff_head completed_q; ++}; ++ ++struct bfusb_scb { ++ struct urb *urb; ++}; ++ ++static void bfusb_tx_complete(struct urb *urb); ++static void bfusb_rx_complete(struct urb *urb); ++ ++static struct urb *bfusb_get_completed(struct bfusb *bfusb) ++{ ++ struct sk_buff *skb; ++ struct urb *urb = NULL; ++ ++ BT_DBG("bfusb %p", bfusb); ++ ++ skb = skb_dequeue(&bfusb->completed_q); ++ if (skb) { ++ urb = ((struct bfusb_scb *) skb->cb)->urb; ++ kfree_skb(skb); ++ } ++ ++ return urb; ++} ++ ++static inline void bfusb_unlink_urbs(struct bfusb *bfusb) ++{ ++ struct sk_buff *skb; ++ struct urb *urb; ++ ++ BT_DBG("bfusb %p", bfusb); ++ ++ while ((skb = skb_dequeue(&bfusb->pending_q))) { ++ urb = ((struct bfusb_scb *) skb->cb)->urb; ++ usb_unlink_urb(urb); ++ skb_queue_tail(&bfusb->completed_q, skb); ++ } ++ ++ while ((urb = bfusb_get_completed(bfusb))) ++ usb_free_urb(urb); ++} ++ ++ ++static int bfusb_send_bulk(struct bfusb *bfusb, struct sk_buff *skb) ++{ ++ struct bfusb_scb *scb = (void *) skb->cb; ++ struct urb *urb = bfusb_get_completed(bfusb); ++ int err, pipe; ++ ++ BT_DBG("bfusb %p skb %p len %d", bfusb, skb, skb->len); ++ ++ if (!urb && !(urb = usb_alloc_urb(0))) ++ return -ENOMEM; ++ ++ pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep); ++ ++ FILL_BULK_URB(urb, bfusb->udev, pipe, skb->data, skb->len, ++ bfusb_tx_complete, skb); ++ ++ urb->transfer_flags = USB_QUEUE_BULK; ++ ++ scb->urb = urb; ++ ++ skb_queue_tail(&bfusb->pending_q, skb); ++ ++ err = usb_submit_urb(urb); ++ if (err) { ++ BT_ERR("%s bulk tx submit failed urb %p err %d", ++ bfusb->hdev.name, urb, err); ++ skb_unlink(skb); ++ usb_free_urb(urb); ++ } else ++ atomic_inc(&bfusb->pending_tx); ++ ++ return err; ++} ++ ++static void bfusb_tx_wakeup(struct bfusb *bfusb) ++{ ++ struct sk_buff *skb; ++ ++ BT_DBG("bfusb %p", bfusb); ++ ++ if (test_and_set_bit(BFUSB_TX_PROCESS, &bfusb->state)) { ++ set_bit(BFUSB_TX_WAKEUP, &bfusb->state); ++ return; ++ } ++ ++ do { ++ clear_bit(BFUSB_TX_WAKEUP, &bfusb->state); ++ ++ while ((atomic_read(&bfusb->pending_tx) < BFUSB_MAX_BULK_TX) && ++ (skb = skb_dequeue(&bfusb->transmit_q))) { ++ if (bfusb_send_bulk(bfusb, skb) < 0) { ++ skb_queue_head(&bfusb->transmit_q, skb); ++ break; ++ } ++ } ++ ++ } while (test_bit(BFUSB_TX_WAKEUP, &bfusb->state)); ++ ++ clear_bit(BFUSB_TX_PROCESS, &bfusb->state); ++} ++ ++static void bfusb_tx_complete(struct urb *urb) ++{ ++ struct sk_buff *skb = (struct sk_buff *) urb->context; ++ struct bfusb *bfusb = (struct bfusb *) skb->dev; ++ ++ BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len); ++ ++ atomic_dec(&bfusb->pending_tx); ++ ++ if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags)) ++ return; ++ ++ if (!urb->status) ++ bfusb->hdev.stat.byte_tx += skb->len; ++ else ++ bfusb->hdev.stat.err_tx++; ++ ++ read_lock(&bfusb->lock); ++ ++ skb_unlink(skb); ++ skb_queue_tail(&bfusb->completed_q, skb); ++ ++ bfusb_tx_wakeup(bfusb); ++ ++ read_unlock(&bfusb->lock); ++} ++ ++ ++static int bfusb_rx_submit(struct bfusb *bfusb, struct urb *urb) ++{ ++ struct bfusb_scb *scb; ++ struct sk_buff *skb; ++ int err, pipe, size = HCI_MAX_FRAME_SIZE + 32; ++ ++ BT_DBG("bfusb %p urb %p", bfusb, urb); ++ ++ if (!urb && !(urb = usb_alloc_urb(0))) ++ return -ENOMEM; ++ ++ if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) { ++ usb_free_urb(urb); ++ return -ENOMEM; ++ } ++ ++ skb->dev = (void *) bfusb; ++ ++ scb = (struct bfusb_scb *) skb->cb; ++ scb->urb = urb; ++ ++ pipe = usb_rcvbulkpipe(bfusb->udev, bfusb->bulk_in_ep); ++ ++ FILL_BULK_URB(urb, bfusb->udev, pipe, skb->data, size, ++ bfusb_rx_complete, skb); ++ ++ urb->transfer_flags = USB_QUEUE_BULK; ++ ++ skb_queue_tail(&bfusb->pending_q, skb); ++ ++ err = usb_submit_urb(urb); ++ if (err) { ++ BT_ERR("%s bulk rx submit failed urb %p err %d", ++ bfusb->hdev.name, urb, err); ++ skb_unlink(skb); ++ kfree_skb(skb); ++ usb_free_urb(urb); ++ } ++ ++ return err; ++} ++ ++static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *data, int len) ++{ ++ BT_DBG("bfusb %p hdr 0x%02x data %p len %d", bfusb, hdr, data, len); ++ ++ if (hdr & 0x10) { ++ BT_ERR("%s error in block", bfusb->hdev.name); ++ if (bfusb->reassembly) ++ kfree_skb(bfusb->reassembly); ++ bfusb->reassembly = NULL; ++ return -EIO; ++ } ++ ++ if (hdr & 0x04) { ++ struct sk_buff *skb; ++ unsigned char pkt_type; ++ int pkt_len = 0; ++ ++ if (bfusb->reassembly) { ++ BT_ERR("%s unexpected start block", bfusb->hdev.name); ++ kfree_skb(bfusb->reassembly); ++ bfusb->reassembly = NULL; ++ } ++ ++ if (len < 1) { ++ BT_ERR("%s no packet type found", bfusb->hdev.name); ++ return -EPROTO; ++ } ++ ++ pkt_type = *data++; len--; ++ ++ switch (pkt_type) { ++ case HCI_EVENT_PKT: ++ if (len >= HCI_EVENT_HDR_SIZE) { ++ hci_event_hdr *hdr = (hci_event_hdr *) data; ++ pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen; ++ } else { ++ BT_ERR("%s event block is too short", bfusb->hdev.name); ++ return -EILSEQ; ++ } ++ break; ++ ++ case HCI_ACLDATA_PKT: ++ if (len >= HCI_ACL_HDR_SIZE) { ++ hci_acl_hdr *hdr = (hci_acl_hdr *) data; ++ pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen); ++ } else { ++ BT_ERR("%s data block is too short", bfusb->hdev.name); ++ return -EILSEQ; ++ } ++ break; ++ ++ case HCI_SCODATA_PKT: ++ if (len >= HCI_SCO_HDR_SIZE) { ++ hci_sco_hdr *hdr = (hci_sco_hdr *) data; ++ pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen; ++ } else { ++ BT_ERR("%s audio block is too short", bfusb->hdev.name); ++ return -EILSEQ; ++ } ++ break; ++ } ++ ++ skb = bluez_skb_alloc(pkt_len, GFP_ATOMIC); ++ if (!skb) { ++ BT_ERR("%s no memory for the packet", bfusb->hdev.name); ++ return -ENOMEM; ++ } ++ ++ skb->dev = (void *) &bfusb->hdev; ++ skb->pkt_type = pkt_type; ++ ++ bfusb->reassembly = skb; ++ } else { ++ if (!bfusb->reassembly) { ++ BT_ERR("%s unexpected continuation block", bfusb->hdev.name); ++ return -EIO; ++ } ++ } ++ ++ if (len > 0) ++ memcpy(skb_put(bfusb->reassembly, len), data, len); ++ ++ if (hdr & 0x08) { ++ hci_recv_frame(bfusb->reassembly); ++ bfusb->reassembly = NULL; ++ } ++ ++ return 0; ++} ++ ++static void bfusb_rx_complete(struct urb *urb) ++{ ++ struct sk_buff *skb = (struct sk_buff *) urb->context; ++ struct bfusb *bfusb = (struct bfusb *) skb->dev; ++ unsigned char *buf = urb->transfer_buffer; ++ int count = urb->actual_length; ++ int err, hdr, len; ++ ++ BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len); ++ ++ if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags)) ++ return; ++ ++ read_lock(&bfusb->lock); ++ ++ if (urb->status || !count) ++ goto resubmit; ++ ++ bfusb->hdev.stat.byte_rx += count; ++ ++ skb_put(skb, count); ++ ++ while (count) { ++ hdr = buf[0] | (buf[1] << 8); ++ ++ if (hdr & 0x4000) { ++ len = 0; ++ count -= 2; ++ buf += 2; ++ } else { ++ len = (buf[2] == 0) ? 256 : buf[2]; ++ count -= 3; ++ buf += 3; ++ } ++ ++ if (count < len) { ++ BT_ERR("%s block extends over URB buffer ranges", ++ bfusb->hdev.name); ++ } ++ ++ if ((hdr & 0xe1) == 0xc1) ++ bfusb_recv_block(bfusb, hdr, buf, len); ++ ++ count -= len; ++ buf += len; ++ } ++ ++ skb_unlink(skb); ++ kfree_skb(skb); ++ ++ bfusb_rx_submit(bfusb, urb); ++ ++ read_unlock(&bfusb->lock); ++ ++ return; ++ ++resubmit: ++ urb->dev = bfusb->udev; ++ ++ err = usb_submit_urb(urb); ++ if (err) { ++ BT_ERR("%s bulk resubmit failed urb %p err %d", ++ bfusb->hdev.name, urb, err); ++ } ++ ++ read_unlock(&bfusb->lock); ++} ++ ++ ++static int bfusb_open(struct hci_dev *hdev) ++{ ++ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data; ++ unsigned long flags; ++ int i, err; ++ ++ BT_DBG("hdev %p bfusb %p", hdev, bfusb); ++ ++ if (test_and_set_bit(HCI_RUNNING, &hdev->flags)) ++ return 0; ++ ++ MOD_INC_USE_COUNT; ++ ++ write_lock_irqsave(&bfusb->lock, flags); ++ ++ err = bfusb_rx_submit(bfusb, NULL); ++ if (!err) { ++ for (i = 1; i < BFUSB_MAX_BULK_RX; i++) ++ bfusb_rx_submit(bfusb, NULL); ++ } else { ++ clear_bit(HCI_RUNNING, &hdev->flags); ++ MOD_DEC_USE_COUNT; ++ } ++ ++ write_unlock_irqrestore(&bfusb->lock, flags); ++ ++ return err; ++} ++ ++static int bfusb_flush(struct hci_dev *hdev) ++{ ++ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data; ++ ++ BT_DBG("hdev %p bfusb %p", hdev, bfusb); ++ ++ skb_queue_purge(&bfusb->transmit_q); ++ ++ return 0; ++} ++ ++static int bfusb_close(struct hci_dev *hdev) ++{ ++ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data; ++ unsigned long flags; ++ ++ BT_DBG("hdev %p bfusb %p", hdev, bfusb); ++ ++ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) ++ return 0; ++ ++ write_lock_irqsave(&bfusb->lock, flags); ++ ++ bfusb_unlink_urbs(bfusb); ++ bfusb_flush(hdev); ++ ++ write_unlock_irqrestore(&bfusb->lock, flags); ++ ++ MOD_DEC_USE_COUNT; ++ ++ return 0; ++} ++ ++static int bfusb_send_frame(struct sk_buff *skb) ++{ ++ struct hci_dev *hdev = (struct hci_dev *) skb->dev; ++ struct bfusb *bfusb; ++ struct sk_buff *nskb; ++ unsigned char buf[3]; ++ int sent = 0, size, count; ++ ++ BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, skb->pkt_type, skb->len); ++ ++ if (!hdev) { ++ BT_ERR("Frame for unknown HCI device (hdev=NULL)"); ++ return -ENODEV; ++ } ++ ++ if (!test_bit(HCI_RUNNING, &hdev->flags)) ++ return -EBUSY; ++ ++ bfusb = (struct bfusb *) hdev->driver_data; ++ ++ switch (skb->pkt_type) { ++ case HCI_COMMAND_PKT: ++ hdev->stat.cmd_tx++; ++ break; ++ case HCI_ACLDATA_PKT: ++ hdev->stat.acl_tx++; ++ break; ++ case HCI_SCODATA_PKT: ++ hdev->stat.sco_tx++; ++ break; ++ }; ++ ++ /* Prepend skb with frame type */ ++ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); ++ ++ count = skb->len; ++ ++ /* Max HCI frame size seems to be 1511 + 1 */ ++ if (!(nskb = bluez_skb_alloc(count + 32, GFP_ATOMIC))) { ++ BT_ERR("Can't allocate memory for new packet"); ++ return -ENOMEM; ++ } ++ ++ nskb->dev = (void *) bfusb; ++ ++ while (count) { ++ size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE); ++ ++ buf[0] = 0xc1 | ((sent == 0) ? 0x04 : 0) | ((count == size) ? 0x08 : 0); ++ buf[1] = 0x00; ++ buf[2] = (size == BFUSB_MAX_BLOCK_SIZE) ? 0 : size; ++ ++ memcpy(skb_put(nskb, 3), buf, 3); ++ memcpy(skb_put(nskb, size), skb->data + sent, size); ++ ++ sent += size; ++ count -= size; ++ } ++ ++ /* Don't send frame with multiple size of bulk max packet */ ++ if ((nskb->len % bfusb->bulk_pkt_size) == 0) { ++ buf[0] = 0xdd; ++ buf[1] = 0x00; ++ memcpy(skb_put(nskb, 2), buf, 2); ++ } ++ ++ read_lock(&bfusb->lock); ++ ++ skb_queue_tail(&bfusb->transmit_q, nskb); ++ bfusb_tx_wakeup(bfusb); ++ ++ read_unlock(&bfusb->lock); ++ ++ kfree_skb(skb); ++ ++ return 0; ++} ++ ++static void bfusb_destruct(struct hci_dev *hdev) ++{ ++ struct bfusb *bfusb = (struct bfusb *) hdev->driver_data; ++ ++ BT_DBG("hdev %p bfusb %p", hdev, bfusb); ++ ++ kfree(bfusb); ++} ++ ++static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) ++{ ++ return -ENOIOCTLCMD; ++} ++ ++ ++static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int count) ++{ ++ unsigned char *buf; ++ int err, pipe, len, size, sent = 0; ++ ++ BT_DBG("bfusb %p udev %p firmware %p count %d", bfusb, bfusb->udev, firmware, count); ++ ++ BT_INFO("BlueFRITZ! USB loading firmware"); ++ ++ if (usb_set_configuration(bfusb->udev, 1) < 0) { ++ BT_ERR("Can't change to loading configuration"); ++ return -EBUSY; ++ } ++ ++ buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_ATOMIC); ++ if (!buf) { ++ BT_ERR("Can't allocate memory chunk for firmware"); ++ return -ENOMEM; ++ } ++ ++ pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep); ++ ++ while (count) { ++ size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE + 3); ++ ++ memcpy(buf, firmware + sent, size); ++ ++ err = usb_bulk_msg(bfusb->udev, pipe, buf, size, ++ &len, BFUSB_BLOCK_TIMEOUT); ++ ++ if (err || (len != size)) { ++ BT_ERR("Error in firmware loading"); ++ goto error; ++ } ++ ++ sent += size; ++ count -= size; ++ } ++ ++ if ((err = usb_bulk_msg(bfusb->udev, pipe, NULL, 0, ++ &len, BFUSB_BLOCK_TIMEOUT)) < 0) { ++ BT_ERR("Error in null packet request"); ++ goto error; ++ } ++ ++ if ((err = usb_set_configuration(bfusb->udev, 2)) < 0) { ++ BT_ERR("Can't change to running configuration"); ++ goto error; ++ } ++ ++ BT_INFO("BlueFRITZ! USB device ready"); ++ ++ kfree(buf); ++ return 0; ++ ++error: ++ kfree(buf); ++ ++ pipe = usb_sndctrlpipe(bfusb->udev, 0); ++ ++ usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION, ++ 0, 0, 0, NULL, 0, BFUSB_BLOCK_TIMEOUT); ++ ++ return err; ++} ++ ++static void *bfusb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id) ++{ ++ const struct firmware *firmware; ++ char device[16]; ++ struct usb_interface *iface; ++ struct usb_interface_descriptor *iface_desc; ++ struct usb_endpoint_descriptor *bulk_out_ep; ++ struct usb_endpoint_descriptor *bulk_in_ep; ++ struct hci_dev *hdev; ++ struct bfusb *bfusb; ++ ++ BT_DBG("udev %p ifnum %d id %p", udev, ifnum, id); ++ ++ /* Check number of endpoints */ ++ iface = &udev->actconfig->interface[0]; ++ iface_desc = &iface->altsetting[0]; ++ ++ if (iface_desc->bNumEndpoints < 2) ++ return NULL; ++ ++ bulk_out_ep = &iface_desc->endpoint[0]; ++ bulk_in_ep = &iface_desc->endpoint[1]; ++ ++ if (!bulk_out_ep || !bulk_in_ep) { ++ BT_ERR("Bulk endpoints not found"); ++ goto done; ++ } ++ ++ /* Initialize control structure and load firmware */ ++ if (!(bfusb = kmalloc(sizeof(struct bfusb), GFP_KERNEL))) { ++ BT_ERR("Can't allocate memory for control structure"); ++ goto done; ++ } ++ ++ memset(bfusb, 0, sizeof(struct bfusb)); ++ ++ bfusb->udev = udev; ++ bfusb->bulk_in_ep = bulk_in_ep->bEndpointAddress; ++ bfusb->bulk_out_ep = bulk_out_ep->bEndpointAddress; ++ bfusb->bulk_pkt_size = bulk_out_ep->wMaxPacketSize; ++ ++ bfusb->lock = RW_LOCK_UNLOCKED; ++ ++ bfusb->reassembly = NULL; ++ ++ skb_queue_head_init(&bfusb->transmit_q); ++ skb_queue_head_init(&bfusb->pending_q); ++ skb_queue_head_init(&bfusb->completed_q); ++ ++ snprintf(device, sizeof(device), "bfusb%3.3d%3.3d", udev->bus->busnum, udev->devnum); ++ ++ if (request_firmware(&firmware, "bfubase.frm", device) < 0) { ++ BT_ERR("Firmware request failed"); ++ goto error; ++ } ++ ++ if (bfusb_load_firmware(bfusb, firmware->data, firmware->size) < 0) { ++ BT_ERR("Firmware loading failed"); ++ goto release; ++ } ++ ++ release_firmware(firmware); ++ ++ /* Initialize and register HCI device */ ++ hdev = &bfusb->hdev; ++ ++ hdev->type = HCI_USB; ++ hdev->driver_data = bfusb; ++ ++ hdev->open = bfusb_open; ++ hdev->close = bfusb_close; ++ hdev->flush = bfusb_flush; ++ hdev->send = bfusb_send_frame; ++ hdev->destruct = bfusb_destruct; ++ hdev->ioctl = bfusb_ioctl; ++ ++ if (hci_register_dev(hdev) < 0) { ++ BT_ERR("Can't register HCI device"); ++ goto error; ++ } ++ ++ return bfusb; ++ ++release: ++ release_firmware(firmware); ++ ++error: ++ kfree(bfusb); ++ ++done: ++ return NULL; ++} ++ ++static void bfusb_disconnect(struct usb_device *udev, void *ptr) ++{ ++ struct bfusb *bfusb = (struct bfusb *) ptr; ++ struct hci_dev *hdev = &bfusb->hdev; ++ ++ BT_DBG("udev %p ptr %p", udev, ptr); ++ ++ if (!hdev) ++ return; ++ ++ bfusb_close(hdev); ++ ++ if (hci_unregister_dev(hdev) < 0) ++ BT_ERR("Can't unregister HCI device %s", hdev->name); ++} ++ ++static struct usb_driver bfusb_driver = { ++ name: "bfusb", ++ probe: bfusb_probe, ++ disconnect: bfusb_disconnect, ++ id_table: bfusb_table, ++}; ++ ++static int __init bfusb_init(void) ++{ ++ int err; ++ ++ BT_INFO("BlueFRITZ! USB driver ver %s", VERSION); ++ BT_INFO("Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org>"); ++ ++ if ((err = usb_register(&bfusb_driver)) < 0) ++ BT_ERR("Failed to register BlueFRITZ! USB driver"); ++ ++ return err; ++} ++ ++static void __exit bfusb_cleanup(void) ++{ ++ usb_deregister(&bfusb_driver); ++} ++ ++module_init(bfusb_init); ++module_exit(bfusb_cleanup); ++ ++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); ++MODULE_DESCRIPTION("BlueFRITZ! USB driver ver " VERSION); ++MODULE_LICENSE("GPL"); +diff -urN linux-2.4.18/drivers/bluetooth/bluecard_cs.c linux-2.4.18-mh9/drivers/bluetooth/bluecard_cs.c +--- linux-2.4.18/drivers/bluetooth/bluecard_cs.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/drivers/bluetooth/bluecard_cs.c Mon Aug 25 18:38:10 2003 +@@ -0,0 +1,1113 @@ ++/* ++ * ++ * Bluetooth driver for the Anycom BlueCard (LSE039/LSE041) ++ * ++ * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org> ++ * ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation; ++ * ++ * Software distributed under the License is distributed on an "AS ++ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++ * implied. See the License for the specific language governing ++ * rights and limitations under the License. ++ * ++ * The initial developer of the original code is David A. Hinds ++ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds ++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/types.h> ++#include <linux/sched.h> ++#include <linux/timer.h> ++#include <linux/errno.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/spinlock.h> ++#include <linux/skbuff.h> ++#include <asm/io.h> ++ ++#include <pcmcia/version.h> ++#include <pcmcia/cs_types.h> ++#include <pcmcia/cs.h> ++#include <pcmcia/cistpl.h> ++#include <pcmcia/ciscode.h> ++#include <pcmcia/ds.h> ++#include <pcmcia/cisreg.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++ ++ ++ ++/* ======================== Module parameters ======================== */ ++ ++ ++/* Bit map of interrupts to choose from */ ++static u_int irq_mask = 0x86bc; ++static int irq_list[4] = { -1 }; ++ ++MODULE_PARM(irq_mask, "i"); ++MODULE_PARM(irq_list, "1-4i"); ++ ++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); ++MODULE_DESCRIPTION("BlueZ driver for the Anycom BlueCard (LSE039/LSE041)"); ++MODULE_LICENSE("GPL"); ++ ++ ++ ++/* ======================== Local structures ======================== */ ++ ++ ++typedef struct bluecard_info_t { ++ dev_link_t link; ++ dev_node_t node; ++ ++ struct hci_dev hdev; ++ ++ spinlock_t lock; /* For serializing operations */ ++ struct timer_list timer; /* For LED control */ ++ ++ struct sk_buff_head txq; ++ unsigned long tx_state; ++ ++ unsigned long rx_state; ++ unsigned long rx_count; ++ struct sk_buff *rx_skb; ++ ++ unsigned char ctrl_reg; ++ unsigned long hw_state; /* Status of the hardware and LED control */ ++} bluecard_info_t; ++ ++ ++void bluecard_config(dev_link_t *link); ++void bluecard_release(u_long arg); ++int bluecard_event(event_t event, int priority, event_callback_args_t *args); ++ ++static dev_info_t dev_info = "bluecard_cs"; ++ ++dev_link_t *bluecard_attach(void); ++void bluecard_detach(dev_link_t *); ++ ++static dev_link_t *dev_list = NULL; ++ ++ ++/* Default baud rate: 57600, 115200, 230400 or 460800 */ ++#define DEFAULT_BAUD_RATE 230400 ++ ++ ++/* Hardware states */ ++#define CARD_READY 1 ++#define CARD_HAS_PCCARD_ID 4 ++#define CARD_HAS_POWER_LED 5 ++#define CARD_HAS_ACTIVITY_LED 6 ++ ++/* Transmit states */ ++#define XMIT_SENDING 1 ++#define XMIT_WAKEUP 2 ++#define XMIT_BUFFER_NUMBER 5 /* unset = buffer one, set = buffer two */ ++#define XMIT_BUF_ONE_READY 6 ++#define XMIT_BUF_TWO_READY 7 ++#define XMIT_SENDING_READY 8 ++ ++/* Receiver states */ ++#define RECV_WAIT_PACKET_TYPE 0 ++#define RECV_WAIT_EVENT_HEADER 1 ++#define RECV_WAIT_ACL_HEADER 2 ++#define RECV_WAIT_SCO_HEADER 3 ++#define RECV_WAIT_DATA 4 ++ ++/* Special packet types */ ++#define PKT_BAUD_RATE_57600 0x80 ++#define PKT_BAUD_RATE_115200 0x81 ++#define PKT_BAUD_RATE_230400 0x82 ++#define PKT_BAUD_RATE_460800 0x83 ++ ++ ++/* These are the register offsets */ ++#define REG_COMMAND 0x20 ++#define REG_INTERRUPT 0x21 ++#define REG_CONTROL 0x22 ++#define REG_RX_CONTROL 0x24 ++#define REG_CARD_RESET 0x30 ++#define REG_LED_CTRL 0x30 ++ ++/* REG_COMMAND */ ++#define REG_COMMAND_TX_BUF_ONE 0x01 ++#define REG_COMMAND_TX_BUF_TWO 0x02 ++#define REG_COMMAND_RX_BUF_ONE 0x04 ++#define REG_COMMAND_RX_BUF_TWO 0x08 ++#define REG_COMMAND_RX_WIN_ONE 0x00 ++#define REG_COMMAND_RX_WIN_TWO 0x10 ++ ++/* REG_CONTROL */ ++#define REG_CONTROL_BAUD_RATE_57600 0x00 ++#define REG_CONTROL_BAUD_RATE_115200 0x01 ++#define REG_CONTROL_BAUD_RATE_230400 0x02 ++#define REG_CONTROL_BAUD_RATE_460800 0x03 ++#define REG_CONTROL_RTS 0x04 ++#define REG_CONTROL_BT_ON 0x08 ++#define REG_CONTROL_BT_RESET 0x10 ++#define REG_CONTROL_BT_RES_PU 0x20 ++#define REG_CONTROL_INTERRUPT 0x40 ++#define REG_CONTROL_CARD_RESET 0x80 ++ ++/* REG_RX_CONTROL */ ++#define RTS_LEVEL_SHIFT_BITS 0x02 ++ ++ ++ ++/* ======================== LED handling routines ======================== */ ++ ++ ++void bluecard_activity_led_timeout(u_long arg) ++{ ++ bluecard_info_t *info = (bluecard_info_t *)arg; ++ unsigned int iobase = info->link.io.BasePort1; ++ ++ if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) { ++ /* Disable activity LED */ ++ outb(0x08 | 0x20, iobase + 0x30); ++ } else { ++ /* Disable power LED */ ++ outb(0x00, iobase + 0x30); ++ } ++} ++ ++ ++static void bluecard_enable_activity_led(bluecard_info_t *info) ++{ ++ unsigned int iobase = info->link.io.BasePort1; ++ ++ if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) { ++ /* Enable activity LED */ ++ outb(0x10 | 0x40, iobase + 0x30); ++ ++ /* Stop the LED after HZ/4 */ ++ mod_timer(&(info->timer), jiffies + HZ / 4); ++ } else { ++ /* Enable power LED */ ++ outb(0x08 | 0x20, iobase + 0x30); ++ ++ /* Stop the LED after HZ/2 */ ++ mod_timer(&(info->timer), jiffies + HZ / 2); ++ } ++} ++ ++ ++ ++/* ======================== Interrupt handling ======================== */ ++ ++ ++static int bluecard_write(unsigned int iobase, unsigned int offset, __u8 *buf, int len) ++{ ++ int i, actual; ++ ++ actual = (len > 15) ? 15 : len; ++ ++ outb_p(actual, iobase + offset); ++ ++ for (i = 0; i < actual; i++) ++ outb_p(buf[i], iobase + offset + i + 1); ++ ++ return actual; ++} ++ ++ ++static void bluecard_write_wakeup(bluecard_info_t *info) ++{ ++ if (!info) { ++ printk(KERN_WARNING "bluecard_cs: Call of write_wakeup for unknown device.\n"); ++ return; ++ } ++ ++ if (!test_bit(XMIT_SENDING_READY, &(info->tx_state))) ++ return; ++ ++ if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { ++ set_bit(XMIT_WAKEUP, &(info->tx_state)); ++ return; ++ } ++ ++ do { ++ register unsigned int iobase = info->link.io.BasePort1; ++ register unsigned int offset; ++ register unsigned char command; ++ register unsigned long ready_bit; ++ register struct sk_buff *skb; ++ register int len; ++ ++ clear_bit(XMIT_WAKEUP, &(info->tx_state)); ++ ++ if (!(info->link.state & DEV_PRESENT)) ++ return; ++ ++ if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) { ++ if (!test_bit(XMIT_BUF_TWO_READY, &(info->tx_state))) ++ break; ++ offset = 0x10; ++ command = REG_COMMAND_TX_BUF_TWO; ++ ready_bit = XMIT_BUF_TWO_READY; ++ } else { ++ if (!test_bit(XMIT_BUF_ONE_READY, &(info->tx_state))) ++ break; ++ offset = 0x00; ++ command = REG_COMMAND_TX_BUF_ONE; ++ ready_bit = XMIT_BUF_ONE_READY; ++ } ++ ++ if (!(skb = skb_dequeue(&(info->txq)))) ++ break; ++ ++ if (skb->pkt_type & 0x80) { ++ /* Disable RTS */ ++ info->ctrl_reg |= REG_CONTROL_RTS; ++ outb(info->ctrl_reg, iobase + REG_CONTROL); ++ } ++ ++ /* Activate LED */ ++ bluecard_enable_activity_led(info); ++ ++ /* Send frame */ ++ len = bluecard_write(iobase, offset, skb->data, skb->len); ++ ++ /* Tell the FPGA to send the data */ ++ outb_p(command, iobase + REG_COMMAND); ++ ++ /* Mark the buffer as dirty */ ++ clear_bit(ready_bit, &(info->tx_state)); ++ ++ if (skb->pkt_type & 0x80) { ++ ++ wait_queue_head_t wait; ++ unsigned char baud_reg; ++ ++ switch (skb->pkt_type) { ++ case PKT_BAUD_RATE_460800: ++ baud_reg = REG_CONTROL_BAUD_RATE_460800; ++ break; ++ case PKT_BAUD_RATE_230400: ++ baud_reg = REG_CONTROL_BAUD_RATE_230400; ++ break; ++ case PKT_BAUD_RATE_115200: ++ baud_reg = REG_CONTROL_BAUD_RATE_115200; ++ break; ++ case PKT_BAUD_RATE_57600: ++ /* Fall through... */ ++ default: ++ baud_reg = REG_CONTROL_BAUD_RATE_57600; ++ break; ++ } ++ ++ /* Wait until the command reaches the baseband */ ++ init_waitqueue_head(&wait); ++ interruptible_sleep_on_timeout(&wait, HZ / 10); ++ ++ /* Set baud on baseband */ ++ info->ctrl_reg &= ~0x03; ++ info->ctrl_reg |= baud_reg; ++ outb(info->ctrl_reg, iobase + REG_CONTROL); ++ ++ /* Enable RTS */ ++ info->ctrl_reg &= ~REG_CONTROL_RTS; ++ outb(info->ctrl_reg, iobase + REG_CONTROL); ++ ++ /* Wait before the next HCI packet can be send */ ++ interruptible_sleep_on_timeout(&wait, HZ); ++ ++ } ++ ++ if (len == skb->len) { ++ kfree_skb(skb); ++ } else { ++ skb_pull(skb, len); ++ skb_queue_head(&(info->txq), skb); ++ } ++ ++ info->hdev.stat.byte_tx += len; ++ ++ /* Change buffer */ ++ change_bit(XMIT_BUFFER_NUMBER, &(info->tx_state)); ++ ++ } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); ++ ++ clear_bit(XMIT_SENDING, &(info->tx_state)); ++} ++ ++ ++static int bluecard_read(unsigned int iobase, unsigned int offset, __u8 *buf, int size) ++{ ++ int i, n, len; ++ ++ outb(REG_COMMAND_RX_WIN_ONE, iobase + REG_COMMAND); ++ ++ len = inb(iobase + offset); ++ n = 0; ++ i = 1; ++ ++ while (n < len) { ++ ++ if (i == 16) { ++ outb(REG_COMMAND_RX_WIN_TWO, iobase + REG_COMMAND); ++ i = 0; ++ } ++ ++ buf[n] = inb(iobase + offset + i); ++ ++ n++; ++ i++; ++ ++ } ++ ++ return len; ++} ++ ++ ++static void bluecard_receive(bluecard_info_t *info, unsigned int offset) ++{ ++ unsigned int iobase; ++ unsigned char buf[31]; ++ int i, len; ++ ++ if (!info) { ++ printk(KERN_WARNING "bluecard_cs: Call of receive for unknown device.\n"); ++ return; ++ } ++ ++ iobase = info->link.io.BasePort1; ++ ++ if (test_bit(XMIT_SENDING_READY, &(info->tx_state))) ++ bluecard_enable_activity_led(info); ++ ++ len = bluecard_read(iobase, offset, buf, sizeof(buf)); ++ ++ for (i = 0; i < len; i++) { ++ ++ /* Allocate packet */ ++ if (info->rx_skb == NULL) { ++ info->rx_state = RECV_WAIT_PACKET_TYPE; ++ info->rx_count = 0; ++ if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { ++ printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n"); ++ return; ++ } ++ } ++ ++ if (info->rx_state == RECV_WAIT_PACKET_TYPE) { ++ ++ info->rx_skb->dev = (void *)&(info->hdev); ++ info->rx_skb->pkt_type = buf[i]; ++ ++ switch (info->rx_skb->pkt_type) { ++ ++ case 0x00: ++ /* init packet */ ++ if (offset != 0x00) { ++ set_bit(XMIT_BUF_ONE_READY, &(info->tx_state)); ++ set_bit(XMIT_BUF_TWO_READY, &(info->tx_state)); ++ set_bit(XMIT_SENDING_READY, &(info->tx_state)); ++ bluecard_write_wakeup(info); ++ } ++ ++ kfree_skb(info->rx_skb); ++ info->rx_skb = NULL; ++ break; ++ ++ case HCI_EVENT_PKT: ++ info->rx_state = RECV_WAIT_EVENT_HEADER; ++ info->rx_count = HCI_EVENT_HDR_SIZE; ++ break; ++ ++ case HCI_ACLDATA_PKT: ++ info->rx_state = RECV_WAIT_ACL_HEADER; ++ info->rx_count = HCI_ACL_HDR_SIZE; ++ break; ++ ++ case HCI_SCODATA_PKT: ++ info->rx_state = RECV_WAIT_SCO_HEADER; ++ info->rx_count = HCI_SCO_HDR_SIZE; ++ break; ++ ++ default: ++ /* unknown packet */ ++ printk(KERN_WARNING "bluecard_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type); ++ info->hdev.stat.err_rx++; ++ ++ kfree_skb(info->rx_skb); ++ info->rx_skb = NULL; ++ break; ++ ++ } ++ ++ } else { ++ ++ *skb_put(info->rx_skb, 1) = buf[i]; ++ info->rx_count--; ++ ++ if (info->rx_count == 0) { ++ ++ int dlen; ++ hci_event_hdr *eh; ++ hci_acl_hdr *ah; ++ hci_sco_hdr *sh; ++ ++ switch (info->rx_state) { ++ ++ case RECV_WAIT_EVENT_HEADER: ++ eh = (hci_event_hdr *)(info->rx_skb->data); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = eh->plen; ++ break; ++ ++ case RECV_WAIT_ACL_HEADER: ++ ah = (hci_acl_hdr *)(info->rx_skb->data); ++ dlen = __le16_to_cpu(ah->dlen); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = dlen; ++ break; ++ ++ case RECV_WAIT_SCO_HEADER: ++ sh = (hci_sco_hdr *)(info->rx_skb->data); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = sh->dlen; ++ break; ++ ++ case RECV_WAIT_DATA: ++ hci_recv_frame(info->rx_skb); ++ info->rx_skb = NULL; ++ break; ++ ++ } ++ ++ } ++ ++ } ++ ++ ++ } ++ ++ info->hdev.stat.byte_rx += len; ++} ++ ++ ++void bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs) ++{ ++ bluecard_info_t *info = dev_inst; ++ unsigned int iobase; ++ unsigned char reg; ++ ++ if (!info) { ++ printk(KERN_WARNING "bluecard_cs: Call of irq %d for unknown device.\n", irq); ++ return; ++ } ++ ++ if (!test_bit(CARD_READY, &(info->hw_state))) ++ return; ++ ++ iobase = info->link.io.BasePort1; ++ ++ spin_lock(&(info->lock)); ++ ++ /* Disable interrupt */ ++ info->ctrl_reg &= ~REG_CONTROL_INTERRUPT; ++ outb(info->ctrl_reg, iobase + REG_CONTROL); ++ ++ reg = inb(iobase + REG_INTERRUPT); ++ ++ if ((reg != 0x00) && (reg != 0xff)) { ++ ++ if (reg & 0x04) { ++ bluecard_receive(info, 0x00); ++ outb(0x04, iobase + REG_INTERRUPT); ++ outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND); ++ } ++ ++ if (reg & 0x08) { ++ bluecard_receive(info, 0x10); ++ outb(0x08, iobase + REG_INTERRUPT); ++ outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND); ++ } ++ ++ if (reg & 0x01) { ++ set_bit(XMIT_BUF_ONE_READY, &(info->tx_state)); ++ outb(0x01, iobase + REG_INTERRUPT); ++ bluecard_write_wakeup(info); ++ } ++ ++ if (reg & 0x02) { ++ set_bit(XMIT_BUF_TWO_READY, &(info->tx_state)); ++ outb(0x02, iobase + REG_INTERRUPT); ++ bluecard_write_wakeup(info); ++ } ++ ++ } ++ ++ /* Enable interrupt */ ++ info->ctrl_reg |= REG_CONTROL_INTERRUPT; ++ outb(info->ctrl_reg, iobase + REG_CONTROL); ++ ++ spin_unlock(&(info->lock)); ++} ++ ++ ++ ++/* ======================== Device specific HCI commands ======================== */ ++ ++ ++static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud) ++{ ++ bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data); ++ struct sk_buff *skb; ++ ++ /* Ericsson baud rate command */ ++ unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 }; ++ ++ if (!(skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { ++ printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n"); ++ return -1; ++ } ++ ++ switch (baud) { ++ case 460800: ++ cmd[4] = 0x00; ++ skb->pkt_type = PKT_BAUD_RATE_460800; ++ break; ++ case 230400: ++ cmd[4] = 0x01; ++ skb->pkt_type = PKT_BAUD_RATE_230400; ++ break; ++ case 115200: ++ cmd[4] = 0x02; ++ skb->pkt_type = PKT_BAUD_RATE_115200; ++ break; ++ case 57600: ++ /* Fall through... */ ++ default: ++ cmd[4] = 0x03; ++ skb->pkt_type = PKT_BAUD_RATE_57600; ++ break; ++ } ++ ++ memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd)); ++ ++ skb_queue_tail(&(info->txq), skb); ++ ++ bluecard_write_wakeup(info); ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== HCI interface ======================== */ ++ ++ ++static int bluecard_hci_flush(struct hci_dev *hdev) ++{ ++ bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data); ++ ++ /* Drop TX queue */ ++ skb_queue_purge(&(info->txq)); ++ ++ return 0; ++} ++ ++ ++static int bluecard_hci_open(struct hci_dev *hdev) ++{ ++ bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data); ++ unsigned int iobase = info->link.io.BasePort1; ++ ++ bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE); ++ ++ if (test_and_set_bit(HCI_RUNNING, &(hdev->flags))) ++ return 0; ++ ++ /* Enable LED */ ++ outb(0x08 | 0x20, iobase + 0x30); ++ ++ return 0; ++} ++ ++ ++static int bluecard_hci_close(struct hci_dev *hdev) ++{ ++ bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data); ++ unsigned int iobase = info->link.io.BasePort1; ++ ++ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) ++ return 0; ++ ++ bluecard_hci_flush(hdev); ++ ++ /* Disable LED */ ++ outb(0x00, iobase + 0x30); ++ ++ return 0; ++} ++ ++ ++static int bluecard_hci_send_frame(struct sk_buff *skb) ++{ ++ bluecard_info_t *info; ++ struct hci_dev *hdev = (struct hci_dev *)(skb->dev); ++ ++ if (!hdev) { ++ printk(KERN_WARNING "bluecard_cs: Frame for unknown HCI device (hdev=NULL)."); ++ return -ENODEV; ++ } ++ ++ info = (bluecard_info_t *)(hdev->driver_data); ++ ++ switch (skb->pkt_type) { ++ case HCI_COMMAND_PKT: ++ hdev->stat.cmd_tx++; ++ break; ++ case HCI_ACLDATA_PKT: ++ hdev->stat.acl_tx++; ++ break; ++ case HCI_SCODATA_PKT: ++ hdev->stat.sco_tx++; ++ break; ++ }; ++ ++ /* Prepend skb with frame type */ ++ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); ++ skb_queue_tail(&(info->txq), skb); ++ ++ bluecard_write_wakeup(info); ++ ++ return 0; ++} ++ ++ ++static void bluecard_hci_destruct(struct hci_dev *hdev) ++{ ++} ++ ++ ++static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) ++{ ++ return -ENOIOCTLCMD; ++} ++ ++ ++ ++/* ======================== Card services HCI interaction ======================== */ ++ ++ ++int bluecard_open(bluecard_info_t *info) ++{ ++ unsigned int iobase = info->link.io.BasePort1; ++ struct hci_dev *hdev; ++ unsigned char id; ++ ++ spin_lock_init(&(info->lock)); ++ ++ init_timer(&(info->timer)); ++ info->timer.function = &bluecard_activity_led_timeout; ++ info->timer.data = (u_long)info; ++ ++ skb_queue_head_init(&(info->txq)); ++ ++ info->rx_state = RECV_WAIT_PACKET_TYPE; ++ info->rx_count = 0; ++ info->rx_skb = NULL; ++ ++ id = inb(iobase + 0x30); ++ ++ if ((id & 0x0f) == 0x02) ++ set_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)); ++ ++ if (id & 0x10) ++ set_bit(CARD_HAS_POWER_LED, &(info->hw_state)); ++ ++ if (id & 0x20) ++ set_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state)); ++ ++ /* Reset card */ ++ info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET; ++ outb(info->ctrl_reg, iobase + REG_CONTROL); ++ ++ /* Turn FPGA off */ ++ outb(0x80, iobase + 0x30); ++ ++ /* Wait some time */ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(HZ / 100); ++ ++ /* Turn FPGA on */ ++ outb(0x00, iobase + 0x30); ++ ++ /* Activate card */ ++ info->ctrl_reg = REG_CONTROL_BT_ON | REG_CONTROL_BT_RES_PU; ++ outb(info->ctrl_reg, iobase + REG_CONTROL); ++ ++ /* Enable interrupt */ ++ outb(0xff, iobase + REG_INTERRUPT); ++ info->ctrl_reg |= REG_CONTROL_INTERRUPT; ++ outb(info->ctrl_reg, iobase + REG_CONTROL); ++ ++ /* Start the RX buffers */ ++ outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND); ++ outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND); ++ ++ /* Signal that the hardware is ready */ ++ set_bit(CARD_READY, &(info->hw_state)); ++ ++ /* Drop TX queue */ ++ skb_queue_purge(&(info->txq)); ++ ++ /* Control the point at which RTS is enabled */ ++ outb((0x0f << RTS_LEVEL_SHIFT_BITS) | 1, iobase + REG_RX_CONTROL); ++ ++ /* Timeout before it is safe to send the first HCI packet */ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout((HZ * 5) / 4); // or set it to 3/2 ++ ++ ++ /* Initialize and register HCI device */ ++ ++ hdev = &(info->hdev); ++ ++ hdev->type = HCI_PCCARD; ++ hdev->driver_data = info; ++ ++ hdev->open = bluecard_hci_open; ++ hdev->close = bluecard_hci_close; ++ hdev->flush = bluecard_hci_flush; ++ hdev->send = bluecard_hci_send_frame; ++ hdev->destruct = bluecard_hci_destruct; ++ hdev->ioctl = bluecard_hci_ioctl; ++ ++ if (hci_register_dev(hdev) < 0) { ++ printk(KERN_WARNING "bluecard_cs: Can't register HCI device %s.\n", hdev->name); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++ ++int bluecard_close(bluecard_info_t *info) ++{ ++ unsigned int iobase = info->link.io.BasePort1; ++ struct hci_dev *hdev = &(info->hdev); ++ ++ bluecard_hci_close(hdev); ++ ++ clear_bit(CARD_READY, &(info->hw_state)); ++ ++ /* Reset card */ ++ info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET; ++ outb(info->ctrl_reg, iobase + REG_CONTROL); ++ ++ /* Turn FPGA off */ ++ outb(0x80, iobase + 0x30); ++ ++ if (hci_unregister_dev(hdev) < 0) ++ printk(KERN_WARNING "bluecard_cs: Can't unregister HCI device %s.\n", hdev->name); ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Card services ======================== */ ++ ++ ++static void cs_error(client_handle_t handle, int func, int ret) ++{ ++ error_info_t err = { func, ret }; ++ ++ CardServices(ReportError, handle, &err); ++} ++ ++ ++dev_link_t *bluecard_attach(void) ++{ ++ bluecard_info_t *info; ++ client_reg_t client_reg; ++ dev_link_t *link; ++ int i, ret; ++ ++ /* Create new info device */ ++ info = kmalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return NULL; ++ memset(info, 0, sizeof(*info)); ++ ++ link = &info->link; ++ link->priv = info; ++ ++ link->release.function = &bluecard_release; ++ link->release.data = (u_long)link; ++ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; ++ link->io.NumPorts1 = 8; ++ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; ++ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; ++ ++ if (irq_list[0] == -1) ++ link->irq.IRQInfo2 = irq_mask; ++ else ++ for (i = 0; i < 4; i++) ++ link->irq.IRQInfo2 |= 1 << irq_list[i]; ++ ++ link->irq.Handler = bluecard_interrupt; ++ link->irq.Instance = info; ++ ++ link->conf.Attributes = CONF_ENABLE_IRQ; ++ link->conf.Vcc = 50; ++ link->conf.IntType = INT_MEMORY_AND_IO; ++ ++ /* Register with Card Services */ ++ link->next = dev_list; ++ dev_list = link; ++ client_reg.dev_info = &dev_info; ++ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; ++ client_reg.EventMask = ++ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | ++ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | ++ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; ++ client_reg.event_handler = &bluecard_event; ++ client_reg.Version = 0x0210; ++ client_reg.event_callback_args.client_data = link; ++ ++ ret = CardServices(RegisterClient, &link->handle, &client_reg); ++ if (ret != CS_SUCCESS) { ++ cs_error(link->handle, RegisterClient, ret); ++ bluecard_detach(link); ++ return NULL; ++ } ++ ++ return link; ++} ++ ++ ++void bluecard_detach(dev_link_t *link) ++{ ++ bluecard_info_t *info = link->priv; ++ dev_link_t **linkp; ++ int ret; ++ ++ /* Locate device structure */ ++ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) ++ if (*linkp == link) ++ break; ++ ++ if (*linkp == NULL) ++ return; ++ ++ del_timer(&link->release); ++ if (link->state & DEV_CONFIG) ++ bluecard_release((u_long)link); ++ ++ if (link->handle) { ++ ret = CardServices(DeregisterClient, link->handle); ++ if (ret != CS_SUCCESS) ++ cs_error(link->handle, DeregisterClient, ret); ++ } ++ ++ /* Unlink device structure, free bits */ ++ *linkp = link->next; ++ ++ kfree(info); ++} ++ ++ ++static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) ++{ ++ int i; ++ ++ i = CardServices(fn, handle, tuple); ++ if (i != CS_SUCCESS) ++ return CS_NO_MORE_ITEMS; ++ ++ i = CardServices(GetTupleData, handle, tuple); ++ if (i != CS_SUCCESS) ++ return i; ++ ++ return CardServices(ParseTuple, handle, tuple, parse); ++} ++ ++ ++#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) ++#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) ++ ++void bluecard_config(dev_link_t *link) ++{ ++ client_handle_t handle = link->handle; ++ bluecard_info_t *info = link->priv; ++ tuple_t tuple; ++ u_short buf[256]; ++ cisparse_t parse; ++ config_info_t config; ++ int i, n, last_ret, last_fn; ++ ++ tuple.TupleData = (cisdata_t *)buf; ++ tuple.TupleOffset = 0; ++ tuple.TupleDataMax = 255; ++ tuple.Attributes = 0; ++ ++ /* Get configuration register information */ ++ tuple.DesiredTuple = CISTPL_CONFIG; ++ last_ret = first_tuple(handle, &tuple, &parse); ++ if (last_ret != CS_SUCCESS) { ++ last_fn = ParseTuple; ++ goto cs_failed; ++ } ++ link->conf.ConfigBase = parse.config.base; ++ link->conf.Present = parse.config.rmask[0]; ++ ++ /* Configure card */ ++ link->state |= DEV_CONFIG; ++ i = CardServices(GetConfigurationInfo, handle, &config); ++ link->conf.Vcc = config.Vcc; ++ ++ link->conf.ConfigIndex = 0x20; ++ link->io.NumPorts1 = 64; ++ link->io.IOAddrLines = 6; ++ ++ for (n = 0; n < 0x400; n += 0x40) { ++ link->io.BasePort1 = n ^ 0x300; ++ i = CardServices(RequestIO, link->handle, &link->io); ++ if (i == CS_SUCCESS) ++ break; ++ } ++ ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestIO, i); ++ goto failed; ++ } ++ ++ i = CardServices(RequestIRQ, link->handle, &link->irq); ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestIRQ, i); ++ link->irq.AssignedIRQ = 0; ++ } ++ ++ i = CardServices(RequestConfiguration, link->handle, &link->conf); ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestConfiguration, i); ++ goto failed; ++ } ++ ++ MOD_INC_USE_COUNT; ++ ++ if (bluecard_open(info) != 0) ++ goto failed; ++ ++ strcpy(info->node.dev_name, info->hdev.name); ++ link->dev = &info->node; ++ link->state &= ~DEV_CONFIG_PENDING; ++ ++ return; ++ ++cs_failed: ++ cs_error(link->handle, last_fn, last_ret); ++ ++failed: ++ bluecard_release((u_long)link); ++} ++ ++ ++void bluecard_release(u_long arg) ++{ ++ dev_link_t *link = (dev_link_t *)arg; ++ bluecard_info_t *info = link->priv; ++ ++ if (link->state & DEV_PRESENT) ++ bluecard_close(info); ++ ++ MOD_DEC_USE_COUNT; ++ ++ link->dev = NULL; ++ ++ CardServices(ReleaseConfiguration, link->handle); ++ CardServices(ReleaseIO, link->handle, &link->io); ++ CardServices(ReleaseIRQ, link->handle, &link->irq); ++ ++ link->state &= ~DEV_CONFIG; ++} ++ ++ ++int bluecard_event(event_t event, int priority, event_callback_args_t *args) ++{ ++ dev_link_t *link = args->client_data; ++ bluecard_info_t *info = link->priv; ++ ++ switch (event) { ++ case CS_EVENT_CARD_REMOVAL: ++ link->state &= ~DEV_PRESENT; ++ if (link->state & DEV_CONFIG) { ++ bluecard_close(info); ++ mod_timer(&link->release, jiffies + HZ / 20); ++ } ++ break; ++ case CS_EVENT_CARD_INSERTION: ++ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; ++ bluecard_config(link); ++ break; ++ case CS_EVENT_PM_SUSPEND: ++ link->state |= DEV_SUSPEND; ++ /* Fall through... */ ++ case CS_EVENT_RESET_PHYSICAL: ++ if (link->state & DEV_CONFIG) ++ CardServices(ReleaseConfiguration, link->handle); ++ break; ++ case CS_EVENT_PM_RESUME: ++ link->state &= ~DEV_SUSPEND; ++ /* Fall through... */ ++ case CS_EVENT_CARD_RESET: ++ if (DEV_OK(link)) ++ CardServices(RequestConfiguration, link->handle, &link->conf); ++ break; ++ } ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Module initialization ======================== */ ++ ++ ++int __init init_bluecard_cs(void) ++{ ++ servinfo_t serv; ++ int err; ++ ++ CardServices(GetCardServicesInfo, &serv); ++ if (serv.Revision != CS_RELEASE_CODE) { ++ printk(KERN_NOTICE "bluecard_cs: Card Services release does not match!\n"); ++ return -1; ++ } ++ ++ err = register_pccard_driver(&dev_info, &bluecard_attach, &bluecard_detach); ++ ++ return err; ++} ++ ++ ++void __exit exit_bluecard_cs(void) ++{ ++ unregister_pccard_driver(&dev_info); ++ ++ while (dev_list != NULL) ++ bluecard_detach(dev_list); ++} ++ ++ ++module_init(init_bluecard_cs); ++module_exit(exit_bluecard_cs); ++ ++EXPORT_NO_SYMBOLS; +diff -urN linux-2.4.18/drivers/bluetooth/bt3c_cs.c linux-2.4.18-mh9/drivers/bluetooth/bt3c_cs.c +--- linux-2.4.18/drivers/bluetooth/bt3c_cs.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/drivers/bluetooth/bt3c_cs.c Mon Aug 25 18:38:10 2003 +@@ -0,0 +1,946 @@ ++/* ++ * ++ * Driver for the 3Com Bluetooth PCMCIA card ++ * ++ * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org> ++ * Jose Orlando Pereira <jop@di.uminho.pt> ++ * ++ * ++ * 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; ++ * ++ * Software distributed under the License is distributed on an "AS ++ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++ * implied. See the License for the specific language governing ++ * rights and limitations under the License. ++ * ++ * The initial developer of the original code is David A. Hinds ++ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds ++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#define __KERNEL_SYSCALLS__ ++ ++#include <linux/kernel.h> ++#include <linux/kmod.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/types.h> ++#include <linux/sched.h> ++#include <linux/delay.h> ++#include <linux/timer.h> ++#include <linux/errno.h> ++#include <linux/unistd.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/spinlock.h> ++ ++#include <linux/skbuff.h> ++#include <linux/string.h> ++#include <linux/serial.h> ++#include <linux/serial_reg.h> ++#include <asm/system.h> ++#include <asm/bitops.h> ++#include <asm/io.h> ++ ++#include <pcmcia/version.h> ++#include <pcmcia/cs_types.h> ++#include <pcmcia/cs.h> ++#include <pcmcia/cistpl.h> ++#include <pcmcia/ciscode.h> ++#include <pcmcia/ds.h> ++#include <pcmcia/cisreg.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++ ++ ++ ++/* ======================== Module parameters ======================== */ ++ ++ ++/* Bit map of interrupts to choose from */ ++static u_int irq_mask = 0xffff; ++static int irq_list[4] = { -1 }; ++ ++MODULE_PARM(irq_mask, "i"); ++MODULE_PARM(irq_list, "1-4i"); ++ ++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>"); ++MODULE_DESCRIPTION("BlueZ driver for the 3Com Bluetooth PCMCIA card"); ++MODULE_LICENSE("GPL"); ++ ++ ++ ++/* ======================== Local structures ======================== */ ++ ++ ++typedef struct bt3c_info_t { ++ dev_link_t link; ++ dev_node_t node; ++ ++ struct hci_dev hdev; ++ ++ spinlock_t lock; /* For serializing operations */ ++ ++ struct sk_buff_head txq; ++ unsigned long tx_state; ++ ++ unsigned long rx_state; ++ unsigned long rx_count; ++ struct sk_buff *rx_skb; ++} bt3c_info_t; ++ ++ ++void bt3c_config(dev_link_t *link); ++void bt3c_release(u_long arg); ++int bt3c_event(event_t event, int priority, event_callback_args_t *args); ++ ++static dev_info_t dev_info = "bt3c_cs"; ++ ++dev_link_t *bt3c_attach(void); ++void bt3c_detach(dev_link_t *); ++ ++static dev_link_t *dev_list = NULL; ++ ++ ++/* Transmit states */ ++#define XMIT_SENDING 1 ++#define XMIT_WAKEUP 2 ++#define XMIT_WAITING 8 ++ ++/* Receiver states */ ++#define RECV_WAIT_PACKET_TYPE 0 ++#define RECV_WAIT_EVENT_HEADER 1 ++#define RECV_WAIT_ACL_HEADER 2 ++#define RECV_WAIT_SCO_HEADER 3 ++#define RECV_WAIT_DATA 4 ++ ++ ++ ++/* ======================== Special I/O functions ======================== */ ++ ++ ++#define DATA_L 0 ++#define DATA_H 1 ++#define ADDR_L 2 ++#define ADDR_H 3 ++#define CONTROL 4 ++ ++ ++inline void bt3c_address(unsigned int iobase, unsigned short addr) ++{ ++ outb(addr & 0xff, iobase + ADDR_L); ++ outb((addr >> 8) & 0xff, iobase + ADDR_H); ++} ++ ++ ++inline void bt3c_put(unsigned int iobase, unsigned short value) ++{ ++ outb(value & 0xff, iobase + DATA_L); ++ outb((value >> 8) & 0xff, iobase + DATA_H); ++} ++ ++ ++inline void bt3c_io_write(unsigned int iobase, unsigned short addr, unsigned short value) ++{ ++ bt3c_address(iobase, addr); ++ bt3c_put(iobase, value); ++} ++ ++ ++inline unsigned short bt3c_get(unsigned int iobase) ++{ ++ unsigned short value = inb(iobase + DATA_L); ++ ++ value |= inb(iobase + DATA_H) << 8; ++ ++ return value; ++} ++ ++ ++inline unsigned short bt3c_read(unsigned int iobase, unsigned short addr) ++{ ++ bt3c_address(iobase, addr); ++ ++ return bt3c_get(iobase); ++} ++ ++ ++ ++/* ======================== Interrupt handling ======================== */ ++ ++ ++static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) ++{ ++ int actual = 0; ++ ++ bt3c_address(iobase, 0x7080); ++ ++ /* Fill FIFO with current frame */ ++ while (actual < len) { ++ /* Transmit next byte */ ++ bt3c_put(iobase, buf[actual]); ++ actual++; ++ } ++ ++ bt3c_io_write(iobase, 0x7005, actual); ++ ++ return actual; ++} ++ ++ ++static void bt3c_write_wakeup(bt3c_info_t *info, int from) ++{ ++ unsigned long flags; ++ ++ if (!info) { ++ printk(KERN_WARNING "bt3c_cs: Call of write_wakeup for unknown device.\n"); ++ return; ++ } ++ ++ if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) ++ return; ++ ++ spin_lock_irqsave(&(info->lock), flags); ++ ++ do { ++ register unsigned int iobase = info->link.io.BasePort1; ++ register struct sk_buff *skb; ++ register int len; ++ ++ if (!(info->link.state & DEV_PRESENT)) ++ break; ++ ++ ++ if (!(skb = skb_dequeue(&(info->txq)))) { ++ clear_bit(XMIT_SENDING, &(info->tx_state)); ++ break; ++ } ++ ++ /* Send frame */ ++ len = bt3c_write(iobase, 256, skb->data, skb->len); ++ ++ if (len != skb->len) { ++ printk(KERN_WARNING "bt3c_cs: very strange\n"); ++ } ++ ++ kfree_skb(skb); ++ ++ info->hdev.stat.byte_tx += len; ++ ++ } while (0); ++ ++ spin_unlock_irqrestore(&(info->lock), flags); ++} ++ ++ ++static void bt3c_receive(bt3c_info_t *info) ++{ ++ unsigned int iobase; ++ int size = 0, avail; ++ ++ if (!info) { ++ printk(KERN_WARNING "bt3c_cs: Call of receive for unknown device.\n"); ++ return; ++ } ++ ++ iobase = info->link.io.BasePort1; ++ ++ avail = bt3c_read(iobase, 0x7006); ++ //printk("bt3c_cs: receiving %d bytes\n", avail); ++ ++ bt3c_address(iobase, 0x7480); ++ while (size < avail) { ++ size++; ++ info->hdev.stat.byte_rx++; ++ ++ /* Allocate packet */ ++ if (info->rx_skb == NULL) { ++ info->rx_state = RECV_WAIT_PACKET_TYPE; ++ info->rx_count = 0; ++ if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { ++ printk(KERN_WARNING "bt3c_cs: Can't allocate mem for new packet.\n"); ++ return; ++ } ++ } ++ ++ ++ if (info->rx_state == RECV_WAIT_PACKET_TYPE) { ++ ++ info->rx_skb->dev = (void *)&(info->hdev); ++ info->rx_skb->pkt_type = inb(iobase + DATA_L); ++ inb(iobase + DATA_H); ++ //printk("bt3c: PACKET_TYPE=%02x\n", info->rx_skb->pkt_type); ++ ++ switch (info->rx_skb->pkt_type) { ++ ++ case HCI_EVENT_PKT: ++ info->rx_state = RECV_WAIT_EVENT_HEADER; ++ info->rx_count = HCI_EVENT_HDR_SIZE; ++ break; ++ ++ case HCI_ACLDATA_PKT: ++ info->rx_state = RECV_WAIT_ACL_HEADER; ++ info->rx_count = HCI_ACL_HDR_SIZE; ++ break; ++ ++ case HCI_SCODATA_PKT: ++ info->rx_state = RECV_WAIT_SCO_HEADER; ++ info->rx_count = HCI_SCO_HDR_SIZE; ++ break; ++ ++ default: ++ /* Unknown packet */ ++ printk(KERN_WARNING "bt3c_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type); ++ info->hdev.stat.err_rx++; ++ clear_bit(HCI_RUNNING, &(info->hdev.flags)); ++ ++ kfree_skb(info->rx_skb); ++ info->rx_skb = NULL; ++ break; ++ ++ } ++ ++ } else { ++ ++ __u8 x = inb(iobase + DATA_L); ++ ++ *skb_put(info->rx_skb, 1) = x; ++ inb(iobase + DATA_H); ++ info->rx_count--; ++ ++ if (info->rx_count == 0) { ++ ++ int dlen; ++ hci_event_hdr *eh; ++ hci_acl_hdr *ah; ++ hci_sco_hdr *sh; ++ ++ switch (info->rx_state) { ++ ++ case RECV_WAIT_EVENT_HEADER: ++ eh = (hci_event_hdr *)(info->rx_skb->data); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = eh->plen; ++ break; ++ ++ case RECV_WAIT_ACL_HEADER: ++ ah = (hci_acl_hdr *)(info->rx_skb->data); ++ dlen = __le16_to_cpu(ah->dlen); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = dlen; ++ break; ++ ++ case RECV_WAIT_SCO_HEADER: ++ sh = (hci_sco_hdr *)(info->rx_skb->data); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = sh->dlen; ++ break; ++ ++ case RECV_WAIT_DATA: ++ hci_recv_frame(info->rx_skb); ++ info->rx_skb = NULL; ++ break; ++ ++ } ++ ++ } ++ ++ } ++ ++ } ++ ++ bt3c_io_write(iobase, 0x7006, 0x0000); ++} ++ ++ ++void bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs) ++{ ++ bt3c_info_t *info = dev_inst; ++ unsigned int iobase; ++ int iir; ++ ++ if (!info) { ++ printk(KERN_WARNING "bt3c_cs: Call of irq %d for unknown device.\n", irq); ++ return; ++ } ++ ++ iobase = info->link.io.BasePort1; ++ ++ spin_lock(&(info->lock)); ++ ++ iir = inb(iobase + CONTROL); ++ if (iir & 0x80) { ++ int stat = bt3c_read(iobase, 0x7001); ++ ++ if ((stat & 0xff) == 0x7f) { ++ printk(KERN_WARNING "bt3c_cs: STRANGE stat=%04x\n", stat); ++ } else if ((stat & 0xff) != 0xff) { ++ if (stat & 0x0020) { ++ int stat = bt3c_read(iobase, 0x7002) & 0x10; ++ printk(KERN_WARNING "bt3c_cs: antena %s\n", stat ? "OUT" : "IN"); ++ } ++ if (stat & 0x0001) ++ bt3c_receive(info); ++ if (stat & 0x0002) { ++ //printk("bt3c_cs: ACK %04x\n", stat); ++ clear_bit(XMIT_SENDING, &(info->tx_state)); ++ bt3c_write_wakeup(info, 1); ++ } ++ ++ bt3c_io_write(iobase, 0x7001, 0x0000); ++ ++ outb(iir, iobase + CONTROL); ++ } ++ } ++ ++ spin_unlock(&(info->lock)); ++} ++ ++ ++ ++ ++/* ======================== HCI interface ======================== */ ++ ++ ++static int bt3c_hci_flush(struct hci_dev *hdev) ++{ ++ bt3c_info_t *info = (bt3c_info_t *)(hdev->driver_data); ++ ++ /* Drop TX queue */ ++ skb_queue_purge(&(info->txq)); ++ ++ return 0; ++} ++ ++ ++static int bt3c_hci_open(struct hci_dev *hdev) ++{ ++ set_bit(HCI_RUNNING, &(hdev->flags)); ++ ++ return 0; ++} ++ ++ ++static int bt3c_hci_close(struct hci_dev *hdev) ++{ ++ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) ++ return 0; ++ ++ bt3c_hci_flush(hdev); ++ ++ return 0; ++} ++ ++ ++static int bt3c_hci_send_frame(struct sk_buff *skb) ++{ ++ bt3c_info_t *info; ++ struct hci_dev *hdev = (struct hci_dev *)(skb->dev); ++ ++ if (!hdev) { ++ printk(KERN_WARNING "bt3c_cs: Frame for unknown HCI device (hdev=NULL)."); ++ return -ENODEV; ++ } ++ ++ info = (bt3c_info_t *) (hdev->driver_data); ++ ++ switch (skb->pkt_type) { ++ case HCI_COMMAND_PKT: ++ hdev->stat.cmd_tx++; ++ break; ++ case HCI_ACLDATA_PKT: ++ hdev->stat.acl_tx++; ++ break; ++ case HCI_SCODATA_PKT: ++ hdev->stat.sco_tx++; ++ break; ++ }; ++ ++ /* Prepend skb with frame type */ ++ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); ++ skb_queue_tail(&(info->txq), skb); ++ ++ bt3c_write_wakeup(info, 0); ++ ++ return 0; ++} ++ ++ ++static void bt3c_hci_destruct(struct hci_dev *hdev) ++{ ++} ++ ++ ++static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) ++{ ++ return -ENOIOCTLCMD; ++} ++ ++ ++ ++/* ======================== User mode firmware loader ======================== */ ++ ++ ++#define FW_LOADER "/sbin/bluefw" ++static int errno; ++ ++ ++static int bt3c_fw_loader_exec(void *dev) ++{ ++ char *argv[] = { FW_LOADER, "pccard", dev, NULL }; ++ char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; ++ int err; ++ ++ err = exec_usermodehelper(FW_LOADER, argv, envp); ++ if (err) ++ printk(KERN_WARNING "bt3c_cs: Failed to exec \"%s pccard %s\".\n", FW_LOADER, (char *)dev); ++ ++ return err; ++} ++ ++ ++static int bt3c_firmware_load(bt3c_info_t *info) ++{ ++ sigset_t tmpsig; ++ char dev[16]; ++ pid_t pid; ++ int result; ++ ++ /* Check if root fs is mounted */ ++ if (!current->fs->root) { ++ printk(KERN_WARNING "bt3c_cs: Root filesystem is not mounted.\n"); ++ return -EPERM; ++ } ++ ++ sprintf(dev, "%04x", info->link.io.BasePort1); ++ ++ pid = kernel_thread(bt3c_fw_loader_exec, (void *)dev, 0); ++ if (pid < 0) { ++ printk(KERN_WARNING "bt3c_cs: Forking of kernel thread failed (errno=%d).\n", -pid); ++ return pid; ++ } ++ ++ /* Block signals, everything but SIGKILL/SIGSTOP */ ++ spin_lock_irq(¤t->sigmask_lock); ++ tmpsig = current->blocked; ++ siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)); ++ recalc_sigpending(current); ++ spin_unlock_irq(¤t->sigmask_lock); ++ ++ result = waitpid(pid, NULL, __WCLONE); ++ ++ /* Allow signals again */ ++ spin_lock_irq(¤t->sigmask_lock); ++ current->blocked = tmpsig; ++ recalc_sigpending(current); ++ spin_unlock_irq(¤t->sigmask_lock); ++ ++ if (result != pid) { ++ printk(KERN_WARNING "bt3c_cs: Waiting for pid %d failed (errno=%d).\n", pid, -result); ++ return -result; ++ } ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Card services HCI interaction ======================== */ ++ ++ ++int bt3c_open(bt3c_info_t *info) ++{ ++ struct hci_dev *hdev; ++ int err; ++ ++ spin_lock_init(&(info->lock)); ++ ++ skb_queue_head_init(&(info->txq)); ++ ++ info->rx_state = RECV_WAIT_PACKET_TYPE; ++ info->rx_count = 0; ++ info->rx_skb = NULL; ++ ++ /* Load firmware */ ++ ++ if ((err = bt3c_firmware_load(info)) < 0) ++ return err; ++ ++ /* Timeout before it is safe to send the first HCI packet */ ++ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(HZ); ++ ++ ++ /* Initialize and register HCI device */ ++ ++ hdev = &(info->hdev); ++ ++ hdev->type = HCI_PCCARD; ++ hdev->driver_data = info; ++ ++ hdev->open = bt3c_hci_open; ++ hdev->close = bt3c_hci_close; ++ hdev->flush = bt3c_hci_flush; ++ hdev->send = bt3c_hci_send_frame; ++ hdev->destruct = bt3c_hci_destruct; ++ hdev->ioctl = bt3c_hci_ioctl; ++ ++ if (hci_register_dev(hdev) < 0) { ++ printk(KERN_WARNING "bt3c_cs: Can't register HCI device %s.\n", hdev->name); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++ ++int bt3c_close(bt3c_info_t *info) ++{ ++ struct hci_dev *hdev = &(info->hdev); ++ ++ bt3c_hci_close(hdev); ++ ++ if (hci_unregister_dev(hdev) < 0) ++ printk(KERN_WARNING "bt3c_cs: Can't unregister HCI device %s.\n", hdev->name); ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Card services ======================== */ ++ ++ ++static void cs_error(client_handle_t handle, int func, int ret) ++{ ++ error_info_t err = { func, ret }; ++ ++ CardServices(ReportError, handle, &err); ++} ++ ++ ++dev_link_t *bt3c_attach(void) ++{ ++ bt3c_info_t *info; ++ client_reg_t client_reg; ++ dev_link_t *link; ++ int i, ret; ++ ++ /* Create new info device */ ++ info = kmalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return NULL; ++ memset(info, 0, sizeof(*info)); ++ ++ link = &info->link; ++ link->priv = info; ++ ++ link->release.function = &bt3c_release; ++ link->release.data = (u_long)link; ++ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; ++ link->io.NumPorts1 = 8; ++ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; ++ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; ++ ++ if (irq_list[0] == -1) ++ link->irq.IRQInfo2 = irq_mask; ++ else ++ for (i = 0; i < 4; i++) ++ link->irq.IRQInfo2 |= 1 << irq_list[i]; ++ ++ link->irq.Handler = bt3c_interrupt; ++ link->irq.Instance = info; ++ ++ link->conf.Attributes = CONF_ENABLE_IRQ; ++ link->conf.Vcc = 50; ++ link->conf.IntType = INT_MEMORY_AND_IO; ++ ++ /* Register with Card Services */ ++ link->next = dev_list; ++ dev_list = link; ++ client_reg.dev_info = &dev_info; ++ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; ++ client_reg.EventMask = ++ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | ++ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | ++ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; ++ client_reg.event_handler = &bt3c_event; ++ client_reg.Version = 0x0210; ++ client_reg.event_callback_args.client_data = link; ++ ++ ret = CardServices(RegisterClient, &link->handle, &client_reg); ++ if (ret != CS_SUCCESS) { ++ cs_error(link->handle, RegisterClient, ret); ++ bt3c_detach(link); ++ return NULL; ++ } ++ ++ return link; ++} ++ ++ ++void bt3c_detach(dev_link_t *link) ++{ ++ bt3c_info_t *info = link->priv; ++ dev_link_t **linkp; ++ int ret; ++ ++ /* Locate device structure */ ++ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) ++ if (*linkp == link) ++ break; ++ ++ if (*linkp == NULL) ++ return; ++ ++ del_timer(&link->release); ++ ++ if (link->state & DEV_CONFIG) ++ bt3c_release((u_long)link); ++ ++ if (link->handle) { ++ ret = CardServices(DeregisterClient, link->handle); ++ if (ret != CS_SUCCESS) ++ cs_error(link->handle, DeregisterClient, ret); ++ } ++ ++ /* Unlink device structure, free bits */ ++ *linkp = link->next; ++ ++ kfree(info); ++} ++ ++ ++static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) ++{ ++ int i; ++ ++ i = CardServices(fn, handle, tuple); ++ if (i != CS_SUCCESS) ++ return CS_NO_MORE_ITEMS; ++ ++ i = CardServices(GetTupleData, handle, tuple); ++ if (i != CS_SUCCESS) ++ return i; ++ ++ return CardServices(ParseTuple, handle, tuple, parse); ++} ++ ++ ++#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) ++#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) ++ ++void bt3c_config(dev_link_t *link) ++{ ++ static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; ++ client_handle_t handle = link->handle; ++ bt3c_info_t *info = link->priv; ++ tuple_t tuple; ++ u_short buf[256]; ++ cisparse_t parse; ++ cistpl_cftable_entry_t *cf = &parse.cftable_entry; ++ config_info_t config; ++ int i, j, try, last_ret, last_fn; ++ ++ tuple.TupleData = (cisdata_t *)buf; ++ tuple.TupleOffset = 0; ++ tuple.TupleDataMax = 255; ++ tuple.Attributes = 0; ++ ++ /* Get configuration register information */ ++ tuple.DesiredTuple = CISTPL_CONFIG; ++ last_ret = first_tuple(handle, &tuple, &parse); ++ if (last_ret != CS_SUCCESS) { ++ last_fn = ParseTuple; ++ goto cs_failed; ++ } ++ link->conf.ConfigBase = parse.config.base; ++ link->conf.Present = parse.config.rmask[0]; ++ ++ /* Configure card */ ++ link->state |= DEV_CONFIG; ++ i = CardServices(GetConfigurationInfo, handle, &config); ++ link->conf.Vcc = config.Vcc; ++ ++ /* First pass: look for a config entry that looks normal. */ ++ tuple.TupleData = (cisdata_t *)buf; ++ tuple.TupleOffset = 0; ++ tuple.TupleDataMax = 255; ++ tuple.Attributes = 0; ++ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; ++ /* Two tries: without IO aliases, then with aliases */ ++ for (try = 0; try < 2; try++) { ++ i = first_tuple(handle, &tuple, &parse); ++ while (i != CS_NO_MORE_ITEMS) { ++ if (i != CS_SUCCESS) ++ goto next_entry; ++ if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) ++ link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; ++ if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) { ++ link->conf.ConfigIndex = cf->index; ++ link->io.BasePort1 = cf->io.win[0].base; ++ link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; ++ i = CardServices(RequestIO, link->handle, &link->io); ++ if (i == CS_SUCCESS) ++ goto found_port; ++ } ++next_entry: ++ i = next_tuple(handle, &tuple, &parse); ++ } ++ } ++ ++ /* Second pass: try to find an entry that isn't picky about ++ its base address, then try to grab any standard serial port ++ address, and finally try to get any free port. */ ++ i = first_tuple(handle, &tuple, &parse); ++ while (i != CS_NO_MORE_ITEMS) { ++ if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { ++ link->conf.ConfigIndex = cf->index; ++ for (j = 0; j < 5; j++) { ++ link->io.BasePort1 = base[j]; ++ link->io.IOAddrLines = base[j] ? 16 : 3; ++ i = CardServices(RequestIO, link->handle, &link->io); ++ if (i == CS_SUCCESS) ++ goto found_port; ++ } ++ } ++ i = next_tuple(handle, &tuple, &parse); ++ } ++ ++found_port: ++ if (i != CS_SUCCESS) { ++ printk(KERN_NOTICE "bt3c_cs: No usable port range found. Giving up.\n"); ++ cs_error(link->handle, RequestIO, i); ++ goto failed; ++ } ++ ++ i = CardServices(RequestIRQ, link->handle, &link->irq); ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestIRQ, i); ++ link->irq.AssignedIRQ = 0; ++ } ++ ++ i = CardServices(RequestConfiguration, link->handle, &link->conf); ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestConfiguration, i); ++ goto failed; ++ } ++ ++ MOD_INC_USE_COUNT; ++ ++ if (bt3c_open(info) != 0) ++ goto failed; ++ ++ strcpy(info->node.dev_name, info->hdev.name); ++ link->dev = &info->node; ++ link->state &= ~DEV_CONFIG_PENDING; ++ ++ return; ++ ++cs_failed: ++ cs_error(link->handle, last_fn, last_ret); ++ ++failed: ++ bt3c_release((u_long)link); ++} ++ ++ ++void bt3c_release(u_long arg) ++{ ++ dev_link_t *link = (dev_link_t *)arg; ++ bt3c_info_t *info = link->priv; ++ ++ if (link->state & DEV_PRESENT) ++ bt3c_close(info); ++ ++ MOD_DEC_USE_COUNT; ++ ++ link->dev = NULL; ++ ++ CardServices(ReleaseConfiguration, link->handle); ++ CardServices(ReleaseIO, link->handle, &link->io); ++ CardServices(ReleaseIRQ, link->handle, &link->irq); ++ ++ link->state &= ~DEV_CONFIG; ++} ++ ++ ++int bt3c_event(event_t event, int priority, event_callback_args_t *args) ++{ ++ dev_link_t *link = args->client_data; ++ bt3c_info_t *info = link->priv; ++ ++ switch (event) { ++ case CS_EVENT_CARD_REMOVAL: ++ link->state &= ~DEV_PRESENT; ++ if (link->state & DEV_CONFIG) { ++ bt3c_close(info); ++ mod_timer(&link->release, jiffies + HZ / 20); ++ } ++ break; ++ case CS_EVENT_CARD_INSERTION: ++ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; ++ bt3c_config(link); ++ break; ++ case CS_EVENT_PM_SUSPEND: ++ link->state |= DEV_SUSPEND; ++ /* Fall through... */ ++ case CS_EVENT_RESET_PHYSICAL: ++ if (link->state & DEV_CONFIG) ++ CardServices(ReleaseConfiguration, link->handle); ++ break; ++ case CS_EVENT_PM_RESUME: ++ link->state &= ~DEV_SUSPEND; ++ /* Fall through... */ ++ case CS_EVENT_CARD_RESET: ++ if (DEV_OK(link)) ++ CardServices(RequestConfiguration, link->handle, &link->conf); ++ break; ++ } ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Module initialization ======================== */ ++ ++ ++int __init init_bt3c_cs(void) ++{ ++ servinfo_t serv; ++ int err; ++ ++ CardServices(GetCardServicesInfo, &serv); ++ if (serv.Revision != CS_RELEASE_CODE) { ++ printk(KERN_NOTICE "bt3c_cs: Card Services release does not match!\n"); ++ return -1; ++ } ++ ++ err = register_pccard_driver(&dev_info, &bt3c_attach, &bt3c_detach); ++ ++ return err; ++} ++ ++ ++void __exit exit_bt3c_cs(void) ++{ ++ unregister_pccard_driver(&dev_info); ++ ++ while (dev_list != NULL) ++ bt3c_detach(dev_list); ++} ++ ++ ++module_init(init_bt3c_cs); ++module_exit(exit_bt3c_cs); ++ ++EXPORT_NO_SYMBOLS; +diff -urN linux-2.4.18/drivers/bluetooth/btuart_cs.c linux-2.4.18-mh9/drivers/bluetooth/btuart_cs.c +--- linux-2.4.18/drivers/bluetooth/btuart_cs.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/drivers/bluetooth/btuart_cs.c Mon Aug 25 18:38:10 2003 +@@ -0,0 +1,906 @@ ++/* ++ * ++ * Driver for Bluetooth PCMCIA cards with HCI UART interface ++ * ++ * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org> ++ * ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation; ++ * ++ * Software distributed under the License is distributed on an "AS ++ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++ * implied. See the License for the specific language governing ++ * rights and limitations under the License. ++ * ++ * The initial developer of the original code is David A. Hinds ++ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds ++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/types.h> ++#include <linux/sched.h> ++#include <linux/timer.h> ++#include <linux/errno.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/spinlock.h> ++ ++#include <linux/skbuff.h> ++#include <linux/string.h> ++#include <linux/serial.h> ++#include <linux/serial_reg.h> ++#include <asm/system.h> ++#include <asm/bitops.h> ++#include <asm/io.h> ++ ++#include <pcmcia/version.h> ++#include <pcmcia/cs_types.h> ++#include <pcmcia/cs.h> ++#include <pcmcia/cistpl.h> ++#include <pcmcia/ciscode.h> ++#include <pcmcia/ds.h> ++#include <pcmcia/cisreg.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++ ++ ++ ++/* ======================== Module parameters ======================== */ ++ ++ ++/* Bit map of interrupts to choose from */ ++static u_int irq_mask = 0xffff; ++static int irq_list[4] = { -1 }; ++ ++MODULE_PARM(irq_mask, "i"); ++MODULE_PARM(irq_list, "1-4i"); ++ ++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); ++MODULE_DESCRIPTION("BlueZ driver for Bluetooth PCMCIA cards with HCI UART interface"); ++MODULE_LICENSE("GPL"); ++ ++ ++ ++/* ======================== Local structures ======================== */ ++ ++ ++typedef struct btuart_info_t { ++ dev_link_t link; ++ dev_node_t node; ++ ++ struct hci_dev hdev; ++ ++ spinlock_t lock; /* For serializing operations */ ++ ++ struct sk_buff_head txq; ++ unsigned long tx_state; ++ ++ unsigned long rx_state; ++ unsigned long rx_count; ++ struct sk_buff *rx_skb; ++} btuart_info_t; ++ ++ ++void btuart_config(dev_link_t *link); ++void btuart_release(u_long arg); ++int btuart_event(event_t event, int priority, event_callback_args_t *args); ++ ++static dev_info_t dev_info = "btuart_cs"; ++ ++dev_link_t *btuart_attach(void); ++void btuart_detach(dev_link_t *); ++ ++static dev_link_t *dev_list = NULL; ++ ++ ++/* Maximum baud rate */ ++#define SPEED_MAX 115200 ++ ++/* Default baud rate: 57600, 115200, 230400 or 460800 */ ++#define DEFAULT_BAUD_RATE 115200 ++ ++ ++/* Transmit states */ ++#define XMIT_SENDING 1 ++#define XMIT_WAKEUP 2 ++#define XMIT_WAITING 8 ++ ++/* Receiver states */ ++#define RECV_WAIT_PACKET_TYPE 0 ++#define RECV_WAIT_EVENT_HEADER 1 ++#define RECV_WAIT_ACL_HEADER 2 ++#define RECV_WAIT_SCO_HEADER 3 ++#define RECV_WAIT_DATA 4 ++ ++ ++ ++/* ======================== Interrupt handling ======================== */ ++ ++ ++static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) ++{ ++ int actual = 0; ++ ++ /* Tx FIFO should be empty */ ++ if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) ++ return 0; ++ ++ /* Fill FIFO with current frame */ ++ while ((fifo_size-- > 0) && (actual < len)) { ++ /* Transmit next byte */ ++ outb(buf[actual], iobase + UART_TX); ++ actual++; ++ } ++ ++ return actual; ++} ++ ++ ++static void btuart_write_wakeup(btuart_info_t *info) ++{ ++ if (!info) { ++ printk(KERN_WARNING "btuart_cs: Call of write_wakeup for unknown device.\n"); ++ return; ++ } ++ ++ if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { ++ set_bit(XMIT_WAKEUP, &(info->tx_state)); ++ return; ++ } ++ ++ do { ++ register unsigned int iobase = info->link.io.BasePort1; ++ register struct sk_buff *skb; ++ register int len; ++ ++ clear_bit(XMIT_WAKEUP, &(info->tx_state)); ++ ++ if (!(info->link.state & DEV_PRESENT)) ++ return; ++ ++ if (!(skb = skb_dequeue(&(info->txq)))) ++ break; ++ ++ /* Send frame */ ++ len = btuart_write(iobase, 16, skb->data, skb->len); ++ set_bit(XMIT_WAKEUP, &(info->tx_state)); ++ ++ if (len == skb->len) { ++ kfree_skb(skb); ++ } else { ++ skb_pull(skb, len); ++ skb_queue_head(&(info->txq), skb); ++ } ++ ++ info->hdev.stat.byte_tx += len; ++ ++ } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); ++ ++ clear_bit(XMIT_SENDING, &(info->tx_state)); ++} ++ ++ ++static void btuart_receive(btuart_info_t *info) ++{ ++ unsigned int iobase; ++ int boguscount = 0; ++ ++ if (!info) { ++ printk(KERN_WARNING "btuart_cs: Call of receive for unknown device.\n"); ++ return; ++ } ++ ++ iobase = info->link.io.BasePort1; ++ ++ do { ++ info->hdev.stat.byte_rx++; ++ ++ /* Allocate packet */ ++ if (info->rx_skb == NULL) { ++ info->rx_state = RECV_WAIT_PACKET_TYPE; ++ info->rx_count = 0; ++ if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { ++ printk(KERN_WARNING "btuart_cs: Can't allocate mem for new packet.\n"); ++ return; ++ } ++ } ++ ++ if (info->rx_state == RECV_WAIT_PACKET_TYPE) { ++ ++ info->rx_skb->dev = (void *)&(info->hdev); ++ info->rx_skb->pkt_type = inb(iobase + UART_RX); ++ ++ switch (info->rx_skb->pkt_type) { ++ ++ case HCI_EVENT_PKT: ++ info->rx_state = RECV_WAIT_EVENT_HEADER; ++ info->rx_count = HCI_EVENT_HDR_SIZE; ++ break; ++ ++ case HCI_ACLDATA_PKT: ++ info->rx_state = RECV_WAIT_ACL_HEADER; ++ info->rx_count = HCI_ACL_HDR_SIZE; ++ break; ++ ++ case HCI_SCODATA_PKT: ++ info->rx_state = RECV_WAIT_SCO_HEADER; ++ info->rx_count = HCI_SCO_HDR_SIZE; ++ break; ++ ++ default: ++ /* Unknown packet */ ++ printk(KERN_WARNING "btuart_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type); ++ info->hdev.stat.err_rx++; ++ clear_bit(HCI_RUNNING, &(info->hdev.flags)); ++ ++ kfree_skb(info->rx_skb); ++ info->rx_skb = NULL; ++ break; ++ ++ } ++ ++ } else { ++ ++ *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); ++ info->rx_count--; ++ ++ if (info->rx_count == 0) { ++ ++ int dlen; ++ hci_event_hdr *eh; ++ hci_acl_hdr *ah; ++ hci_sco_hdr *sh; ++ ++ ++ switch (info->rx_state) { ++ ++ case RECV_WAIT_EVENT_HEADER: ++ eh = (hci_event_hdr *)(info->rx_skb->data); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = eh->plen; ++ break; ++ ++ case RECV_WAIT_ACL_HEADER: ++ ah = (hci_acl_hdr *)(info->rx_skb->data); ++ dlen = __le16_to_cpu(ah->dlen); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = dlen; ++ break; ++ ++ case RECV_WAIT_SCO_HEADER: ++ sh = (hci_sco_hdr *)(info->rx_skb->data); ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = sh->dlen; ++ break; ++ ++ case RECV_WAIT_DATA: ++ hci_recv_frame(info->rx_skb); ++ info->rx_skb = NULL; ++ break; ++ ++ } ++ ++ } ++ ++ } ++ ++ /* Make sure we don't stay here to long */ ++ if (boguscount++ > 16) ++ break; ++ ++ } while (inb(iobase + UART_LSR) & UART_LSR_DR); ++} ++ ++ ++void btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs) ++{ ++ btuart_info_t *info = dev_inst; ++ unsigned int iobase; ++ int boguscount = 0; ++ int iir, lsr; ++ ++ if (!info) { ++ printk(KERN_WARNING "btuart_cs: Call of irq %d for unknown device.\n", irq); ++ return; ++ } ++ ++ iobase = info->link.io.BasePort1; ++ ++ spin_lock(&(info->lock)); ++ ++ iir = inb(iobase + UART_IIR) & UART_IIR_ID; ++ while (iir) { ++ ++ /* Clear interrupt */ ++ lsr = inb(iobase + UART_LSR); ++ ++ switch (iir) { ++ case UART_IIR_RLSI: ++ printk(KERN_NOTICE "btuart_cs: RLSI\n"); ++ break; ++ case UART_IIR_RDI: ++ /* Receive interrupt */ ++ btuart_receive(info); ++ break; ++ case UART_IIR_THRI: ++ if (lsr & UART_LSR_THRE) { ++ /* Transmitter ready for data */ ++ btuart_write_wakeup(info); ++ } ++ break; ++ default: ++ printk(KERN_NOTICE "btuart_cs: Unhandled IIR=%#x\n", iir); ++ break; ++ } ++ ++ /* Make sure we don't stay here to long */ ++ if (boguscount++ > 100) ++ break; ++ ++ iir = inb(iobase + UART_IIR) & UART_IIR_ID; ++ ++ } ++ ++ spin_unlock(&(info->lock)); ++} ++ ++ ++static void btuart_change_speed(btuart_info_t *info, unsigned int speed) ++{ ++ unsigned long flags; ++ unsigned int iobase; ++ int fcr; /* FIFO control reg */ ++ int lcr; /* Line control reg */ ++ int divisor; ++ ++ if (!info) { ++ printk(KERN_WARNING "btuart_cs: Call of change speed for unknown device.\n"); ++ return; ++ } ++ ++ iobase = info->link.io.BasePort1; ++ ++ spin_lock_irqsave(&(info->lock), flags); ++ ++ /* Turn off interrupts */ ++ outb(0, iobase + UART_IER); ++ ++ divisor = SPEED_MAX / speed; ++ ++ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT; ++ ++ /* ++ * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and ++ * almost 1,7 ms at 19200 bps. At speeds above that we can just forget ++ * about this timeout since it will always be fast enough. ++ */ ++ ++ if (speed < 38400) ++ fcr |= UART_FCR_TRIGGER_1; ++ else ++ fcr |= UART_FCR_TRIGGER_14; ++ ++ /* Bluetooth cards use 8N1 */ ++ lcr = UART_LCR_WLEN8; ++ ++ outb(UART_LCR_DLAB | lcr, iobase + UART_LCR); /* Set DLAB */ ++ outb(divisor & 0xff, iobase + UART_DLL); /* Set speed */ ++ outb(divisor >> 8, iobase + UART_DLM); ++ outb(lcr, iobase + UART_LCR); /* Set 8N1 */ ++ outb(fcr, iobase + UART_FCR); /* Enable FIFO's */ ++ ++ /* Turn on interrups */ ++ outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); ++ ++ spin_unlock_irqrestore(&(info->lock), flags); ++} ++ ++ ++ ++/* ======================== HCI interface ======================== */ ++ ++ ++static int btuart_hci_flush(struct hci_dev *hdev) ++{ ++ btuart_info_t *info = (btuart_info_t *)(hdev->driver_data); ++ ++ /* Drop TX queue */ ++ skb_queue_purge(&(info->txq)); ++ ++ return 0; ++} ++ ++ ++static int btuart_hci_open(struct hci_dev *hdev) ++{ ++ set_bit(HCI_RUNNING, &(hdev->flags)); ++ ++ return 0; ++} ++ ++ ++static int btuart_hci_close(struct hci_dev *hdev) ++{ ++ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) ++ return 0; ++ ++ btuart_hci_flush(hdev); ++ ++ return 0; ++} ++ ++ ++static int btuart_hci_send_frame(struct sk_buff *skb) ++{ ++ btuart_info_t *info; ++ struct hci_dev *hdev = (struct hci_dev *)(skb->dev); ++ ++ if (!hdev) { ++ printk(KERN_WARNING "btuart_cs: Frame for unknown HCI device (hdev=NULL)."); ++ return -ENODEV; ++ } ++ ++ info = (btuart_info_t *)(hdev->driver_data); ++ ++ switch (skb->pkt_type) { ++ case HCI_COMMAND_PKT: ++ hdev->stat.cmd_tx++; ++ break; ++ case HCI_ACLDATA_PKT: ++ hdev->stat.acl_tx++; ++ break; ++ case HCI_SCODATA_PKT: ++ hdev->stat.sco_tx++; ++ break; ++ }; ++ ++ /* Prepend skb with frame type */ ++ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); ++ skb_queue_tail(&(info->txq), skb); ++ ++ btuart_write_wakeup(info); ++ ++ return 0; ++} ++ ++ ++static void btuart_hci_destruct(struct hci_dev *hdev) ++{ ++} ++ ++ ++static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) ++{ ++ return -ENOIOCTLCMD; ++} ++ ++ ++ ++/* ======================== Card services HCI interaction ======================== */ ++ ++ ++int btuart_open(btuart_info_t *info) ++{ ++ unsigned long flags; ++ unsigned int iobase = info->link.io.BasePort1; ++ struct hci_dev *hdev; ++ ++ spin_lock_init(&(info->lock)); ++ ++ skb_queue_head_init(&(info->txq)); ++ ++ info->rx_state = RECV_WAIT_PACKET_TYPE; ++ info->rx_count = 0; ++ info->rx_skb = NULL; ++ ++ spin_lock_irqsave(&(info->lock), flags); ++ ++ /* Reset UART */ ++ outb(0, iobase + UART_MCR); ++ ++ /* Turn off interrupts */ ++ outb(0, iobase + UART_IER); ++ ++ /* Initialize UART */ ++ outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */ ++ outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR); ++ ++ /* Turn on interrupts */ ++ // outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); ++ ++ spin_unlock_irqrestore(&(info->lock), flags); ++ ++ btuart_change_speed(info, DEFAULT_BAUD_RATE); ++ ++ /* Timeout before it is safe to send the first HCI packet */ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(HZ); ++ ++ ++ /* Initialize and register HCI device */ ++ ++ hdev = &(info->hdev); ++ ++ hdev->type = HCI_PCCARD; ++ hdev->driver_data = info; ++ ++ hdev->open = btuart_hci_open; ++ hdev->close = btuart_hci_close; ++ hdev->flush = btuart_hci_flush; ++ hdev->send = btuart_hci_send_frame; ++ hdev->destruct = btuart_hci_destruct; ++ hdev->ioctl = btuart_hci_ioctl; ++ ++ if (hci_register_dev(hdev) < 0) { ++ printk(KERN_WARNING "btuart_cs: Can't register HCI device %s.\n", hdev->name); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++ ++int btuart_close(btuart_info_t *info) ++{ ++ unsigned long flags; ++ unsigned int iobase = info->link.io.BasePort1; ++ struct hci_dev *hdev = &(info->hdev); ++ ++ btuart_hci_close(hdev); ++ ++ spin_lock_irqsave(&(info->lock), flags); ++ ++ /* Reset UART */ ++ outb(0, iobase + UART_MCR); ++ ++ /* Turn off interrupts */ ++ outb(0, iobase + UART_IER); ++ ++ spin_unlock_irqrestore(&(info->lock), flags); ++ ++ if (hci_unregister_dev(hdev) < 0) ++ printk(KERN_WARNING "btuart_cs: Can't unregister HCI device %s.\n", hdev->name); ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Card services ======================== */ ++ ++ ++static void cs_error(client_handle_t handle, int func, int ret) ++{ ++ error_info_t err = { func, ret }; ++ ++ CardServices(ReportError, handle, &err); ++} ++ ++ ++dev_link_t *btuart_attach(void) ++{ ++ btuart_info_t *info; ++ client_reg_t client_reg; ++ dev_link_t *link; ++ int i, ret; ++ ++ /* Create new info device */ ++ info = kmalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return NULL; ++ memset(info, 0, sizeof(*info)); ++ ++ link = &info->link; ++ link->priv = info; ++ ++ link->release.function = &btuart_release; ++ link->release.data = (u_long)link; ++ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; ++ link->io.NumPorts1 = 8; ++ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; ++ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; ++ ++ if (irq_list[0] == -1) ++ link->irq.IRQInfo2 = irq_mask; ++ else ++ for (i = 0; i < 4; i++) ++ link->irq.IRQInfo2 |= 1 << irq_list[i]; ++ ++ link->irq.Handler = btuart_interrupt; ++ link->irq.Instance = info; ++ ++ link->conf.Attributes = CONF_ENABLE_IRQ; ++ link->conf.Vcc = 50; ++ link->conf.IntType = INT_MEMORY_AND_IO; ++ ++ /* Register with Card Services */ ++ link->next = dev_list; ++ dev_list = link; ++ client_reg.dev_info = &dev_info; ++ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; ++ client_reg.EventMask = ++ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | ++ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | ++ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; ++ client_reg.event_handler = &btuart_event; ++ client_reg.Version = 0x0210; ++ client_reg.event_callback_args.client_data = link; ++ ++ ret = CardServices(RegisterClient, &link->handle, &client_reg); ++ if (ret != CS_SUCCESS) { ++ cs_error(link->handle, RegisterClient, ret); ++ btuart_detach(link); ++ return NULL; ++ } ++ ++ return link; ++} ++ ++ ++void btuart_detach(dev_link_t *link) ++{ ++ btuart_info_t *info = link->priv; ++ dev_link_t **linkp; ++ int ret; ++ ++ /* Locate device structure */ ++ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) ++ if (*linkp == link) ++ break; ++ ++ if (*linkp == NULL) ++ return; ++ ++ del_timer(&link->release); ++ if (link->state & DEV_CONFIG) ++ btuart_release((u_long)link); ++ ++ if (link->handle) { ++ ret = CardServices(DeregisterClient, link->handle); ++ if (ret != CS_SUCCESS) ++ cs_error(link->handle, DeregisterClient, ret); ++ } ++ ++ /* Unlink device structure, free bits */ ++ *linkp = link->next; ++ ++ kfree(info); ++} ++ ++ ++static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) ++{ ++ int i; ++ ++ i = CardServices(fn, handle, tuple); ++ if (i != CS_SUCCESS) ++ return CS_NO_MORE_ITEMS; ++ ++ i = CardServices(GetTupleData, handle, tuple); ++ if (i != CS_SUCCESS) ++ return i; ++ ++ return CardServices(ParseTuple, handle, tuple, parse); ++} ++ ++ ++#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) ++#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) ++ ++void btuart_config(dev_link_t *link) ++{ ++ static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; ++ client_handle_t handle = link->handle; ++ btuart_info_t *info = link->priv; ++ tuple_t tuple; ++ u_short buf[256]; ++ cisparse_t parse; ++ cistpl_cftable_entry_t *cf = &parse.cftable_entry; ++ config_info_t config; ++ int i, j, try, last_ret, last_fn; ++ ++ tuple.TupleData = (cisdata_t *)buf; ++ tuple.TupleOffset = 0; ++ tuple.TupleDataMax = 255; ++ tuple.Attributes = 0; ++ ++ /* Get configuration register information */ ++ tuple.DesiredTuple = CISTPL_CONFIG; ++ last_ret = first_tuple(handle, &tuple, &parse); ++ if (last_ret != CS_SUCCESS) { ++ last_fn = ParseTuple; ++ goto cs_failed; ++ } ++ link->conf.ConfigBase = parse.config.base; ++ link->conf.Present = parse.config.rmask[0]; ++ ++ /* Configure card */ ++ link->state |= DEV_CONFIG; ++ i = CardServices(GetConfigurationInfo, handle, &config); ++ link->conf.Vcc = config.Vcc; ++ ++ /* First pass: look for a config entry that looks normal. */ ++ tuple.TupleData = (cisdata_t *) buf; ++ tuple.TupleOffset = 0; ++ tuple.TupleDataMax = 255; ++ tuple.Attributes = 0; ++ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; ++ /* Two tries: without IO aliases, then with aliases */ ++ for (try = 0; try < 2; try++) { ++ i = first_tuple(handle, &tuple, &parse); ++ while (i != CS_NO_MORE_ITEMS) { ++ if (i != CS_SUCCESS) ++ goto next_entry; ++ if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) ++ link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; ++ if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) { ++ link->conf.ConfigIndex = cf->index; ++ link->io.BasePort1 = cf->io.win[0].base; ++ link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; ++ i = CardServices(RequestIO, link->handle, &link->io); ++ if (i == CS_SUCCESS) ++ goto found_port; ++ } ++next_entry: ++ i = next_tuple(handle, &tuple, &parse); ++ } ++ } ++ ++ /* Second pass: try to find an entry that isn't picky about ++ its base address, then try to grab any standard serial port ++ address, and finally try to get any free port. */ ++ i = first_tuple(handle, &tuple, &parse); ++ while (i != CS_NO_MORE_ITEMS) { ++ if ((i == CS_SUCCESS) && (cf->io.nwin > 0) ++ && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { ++ link->conf.ConfigIndex = cf->index; ++ for (j = 0; j < 5; j++) { ++ link->io.BasePort1 = base[j]; ++ link->io.IOAddrLines = base[j] ? 16 : 3; ++ i = CardServices(RequestIO, link->handle, &link->io); ++ if (i == CS_SUCCESS) ++ goto found_port; ++ } ++ } ++ i = next_tuple(handle, &tuple, &parse); ++ } ++ ++found_port: ++ if (i != CS_SUCCESS) { ++ printk(KERN_NOTICE "btuart_cs: No usable port range found. Giving up.\n"); ++ cs_error(link->handle, RequestIO, i); ++ goto failed; ++ } ++ ++ i = CardServices(RequestIRQ, link->handle, &link->irq); ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestIRQ, i); ++ link->irq.AssignedIRQ = 0; ++ } ++ ++ i = CardServices(RequestConfiguration, link->handle, &link->conf); ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestConfiguration, i); ++ goto failed; ++ } ++ ++ MOD_INC_USE_COUNT; ++ ++ if (btuart_open(info) != 0) ++ goto failed; ++ ++ strcpy(info->node.dev_name, info->hdev.name); ++ link->dev = &info->node; ++ link->state &= ~DEV_CONFIG_PENDING; ++ ++ return; ++ ++cs_failed: ++ cs_error(link->handle, last_fn, last_ret); ++ ++failed: ++ btuart_release((u_long) link); ++} ++ ++ ++void btuart_release(u_long arg) ++{ ++ dev_link_t *link = (dev_link_t *)arg; ++ btuart_info_t *info = link->priv; ++ ++ if (link->state & DEV_PRESENT) ++ btuart_close(info); ++ ++ MOD_DEC_USE_COUNT; ++ ++ link->dev = NULL; ++ ++ CardServices(ReleaseConfiguration, link->handle); ++ CardServices(ReleaseIO, link->handle, &link->io); ++ CardServices(ReleaseIRQ, link->handle, &link->irq); ++ ++ link->state &= ~DEV_CONFIG; ++} ++ ++ ++int btuart_event(event_t event, int priority, event_callback_args_t *args) ++{ ++ dev_link_t *link = args->client_data; ++ btuart_info_t *info = link->priv; ++ ++ switch (event) { ++ case CS_EVENT_CARD_REMOVAL: ++ link->state &= ~DEV_PRESENT; ++ if (link->state & DEV_CONFIG) { ++ btuart_close(info); ++ mod_timer(&link->release, jiffies + HZ / 20); ++ } ++ break; ++ case CS_EVENT_CARD_INSERTION: ++ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; ++ btuart_config(link); ++ break; ++ case CS_EVENT_PM_SUSPEND: ++ link->state |= DEV_SUSPEND; ++ /* Fall through... */ ++ case CS_EVENT_RESET_PHYSICAL: ++ if (link->state & DEV_CONFIG) ++ CardServices(ReleaseConfiguration, link->handle); ++ break; ++ case CS_EVENT_PM_RESUME: ++ link->state &= ~DEV_SUSPEND; ++ /* Fall through... */ ++ case CS_EVENT_CARD_RESET: ++ if (DEV_OK(link)) ++ CardServices(RequestConfiguration, link->handle, &link->conf); ++ break; ++ } ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Module initialization ======================== */ ++ ++ ++int __init init_btuart_cs(void) ++{ ++ servinfo_t serv; ++ int err; ++ ++ CardServices(GetCardServicesInfo, &serv); ++ if (serv.Revision != CS_RELEASE_CODE) { ++ printk(KERN_NOTICE "btuart_cs: Card Services release does not match!\n"); ++ return -1; ++ } ++ ++ err = register_pccard_driver(&dev_info, &btuart_attach, &btuart_detach); ++ ++ return err; ++} ++ ++ ++void __exit exit_btuart_cs(void) ++{ ++ unregister_pccard_driver(&dev_info); ++ ++ while (dev_list != NULL) ++ btuart_detach(dev_list); ++} ++ ++ ++module_init(init_btuart_cs); ++module_exit(exit_btuart_cs); ++ ++EXPORT_NO_SYMBOLS; +diff -urN linux-2.4.18/drivers/bluetooth/dtl1_cs.c linux-2.4.18-mh9/drivers/bluetooth/dtl1_cs.c +--- linux-2.4.18/drivers/bluetooth/dtl1_cs.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/drivers/bluetooth/dtl1_cs.c Mon Aug 25 18:38:10 2003 +@@ -0,0 +1,858 @@ ++/* ++ * ++ * A driver for Nokia Connectivity Card DTL-1 devices ++ * ++ * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org> ++ * ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation; ++ * ++ * Software distributed under the License is distributed on an "AS ++ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++ * implied. See the License for the specific language governing ++ * rights and limitations under the License. ++ * ++ * The initial developer of the original code is David A. Hinds ++ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds ++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/types.h> ++#include <linux/sched.h> ++#include <linux/timer.h> ++#include <linux/errno.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/spinlock.h> ++ ++#include <linux/skbuff.h> ++#include <linux/string.h> ++#include <linux/serial.h> ++#include <linux/serial_reg.h> ++#include <asm/system.h> ++#include <asm/bitops.h> ++#include <asm/io.h> ++ ++#include <pcmcia/version.h> ++#include <pcmcia/cs_types.h> ++#include <pcmcia/cs.h> ++#include <pcmcia/cistpl.h> ++#include <pcmcia/ciscode.h> ++#include <pcmcia/ds.h> ++#include <pcmcia/cisreg.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++ ++ ++ ++/* ======================== Module parameters ======================== */ ++ ++ ++/* Bit map of interrupts to choose from */ ++static u_int irq_mask = 0xffff; ++static int irq_list[4] = { -1 }; ++ ++MODULE_PARM(irq_mask, "i"); ++MODULE_PARM(irq_list, "1-4i"); ++ ++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); ++MODULE_DESCRIPTION("BlueZ driver for Nokia Connectivity Card DTL-1"); ++MODULE_LICENSE("GPL"); ++ ++ ++ ++/* ======================== Local structures ======================== */ ++ ++ ++typedef struct dtl1_info_t { ++ dev_link_t link; ++ dev_node_t node; ++ ++ struct hci_dev hdev; ++ ++ spinlock_t lock; /* For serializing operations */ ++ ++ unsigned long flowmask; /* HCI flow mask */ ++ int ri_latch; ++ ++ struct sk_buff_head txq; ++ unsigned long tx_state; ++ ++ unsigned long rx_state; ++ unsigned long rx_count; ++ struct sk_buff *rx_skb; ++} dtl1_info_t; ++ ++ ++void dtl1_config(dev_link_t *link); ++void dtl1_release(u_long arg); ++int dtl1_event(event_t event, int priority, event_callback_args_t *args); ++ ++static dev_info_t dev_info = "dtl1_cs"; ++ ++dev_link_t *dtl1_attach(void); ++void dtl1_detach(dev_link_t *); ++ ++static dev_link_t *dev_list = NULL; ++ ++ ++/* Transmit states */ ++#define XMIT_SENDING 1 ++#define XMIT_WAKEUP 2 ++#define XMIT_WAITING 8 ++ ++/* Receiver States */ ++#define RECV_WAIT_NSH 0 ++#define RECV_WAIT_DATA 1 ++ ++ ++typedef struct { ++ u8 type; ++ u8 zero; ++ u16 len; ++} __attribute__ ((packed)) nsh_t; /* Nokia Specific Header */ ++ ++#define NSHL 4 /* Nokia Specific Header Length */ ++ ++ ++ ++/* ======================== Interrupt handling ======================== */ ++ ++ ++static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) ++{ ++ int actual = 0; ++ ++ /* Tx FIFO should be empty */ ++ if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) ++ return 0; ++ ++ /* Fill FIFO with current frame */ ++ while ((fifo_size-- > 0) && (actual < len)) { ++ /* Transmit next byte */ ++ outb(buf[actual], iobase + UART_TX); ++ actual++; ++ } ++ ++ return actual; ++} ++ ++ ++static void dtl1_write_wakeup(dtl1_info_t *info) ++{ ++ if (!info) { ++ printk(KERN_WARNING "dtl1_cs: Call of write_wakeup for unknown device.\n"); ++ return; ++ } ++ ++ if (test_bit(XMIT_WAITING, &(info->tx_state))) { ++ set_bit(XMIT_WAKEUP, &(info->tx_state)); ++ return; ++ } ++ ++ if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { ++ set_bit(XMIT_WAKEUP, &(info->tx_state)); ++ return; ++ } ++ ++ do { ++ register unsigned int iobase = info->link.io.BasePort1; ++ register struct sk_buff *skb; ++ register int len; ++ ++ clear_bit(XMIT_WAKEUP, &(info->tx_state)); ++ ++ if (!(info->link.state & DEV_PRESENT)) ++ return; ++ ++ if (!(skb = skb_dequeue(&(info->txq)))) ++ break; ++ ++ /* Send frame */ ++ len = dtl1_write(iobase, 32, skb->data, skb->len); ++ ++ if (len == skb->len) { ++ set_bit(XMIT_WAITING, &(info->tx_state)); ++ kfree_skb(skb); ++ } else { ++ skb_pull(skb, len); ++ skb_queue_head(&(info->txq), skb); ++ } ++ ++ info->hdev.stat.byte_tx += len; ++ ++ } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); ++ ++ clear_bit(XMIT_SENDING, &(info->tx_state)); ++} ++ ++ ++static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb) ++{ ++ u8 flowmask = *(u8 *)skb->data; ++ int i; ++ ++ printk(KERN_INFO "dtl1_cs: Nokia control data = "); ++ for (i = 0; i < skb->len; i++) { ++ printk("%02x ", skb->data[i]); ++ } ++ printk("\n"); ++ ++ /* transition to active state */ ++ if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) { ++ clear_bit(XMIT_WAITING, &(info->tx_state)); ++ dtl1_write_wakeup(info); ++ } ++ ++ info->flowmask = flowmask; ++ ++ kfree_skb(skb); ++} ++ ++ ++static void dtl1_receive(dtl1_info_t *info) ++{ ++ unsigned int iobase; ++ nsh_t *nsh; ++ int boguscount = 0; ++ ++ if (!info) { ++ printk(KERN_WARNING "dtl1_cs: Call of receive for unknown device.\n"); ++ return; ++ } ++ ++ iobase = info->link.io.BasePort1; ++ ++ do { ++ info->hdev.stat.byte_rx++; ++ ++ /* Allocate packet */ ++ if (info->rx_skb == NULL) ++ if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { ++ printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n"); ++ info->rx_state = RECV_WAIT_NSH; ++ info->rx_count = NSHL; ++ return; ++ } ++ ++ *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); ++ nsh = (nsh_t *)info->rx_skb->data; ++ ++ info->rx_count--; ++ ++ if (info->rx_count == 0) { ++ ++ switch (info->rx_state) { ++ case RECV_WAIT_NSH: ++ info->rx_state = RECV_WAIT_DATA; ++ info->rx_count = nsh->len + (nsh->len & 0x0001); ++ break; ++ case RECV_WAIT_DATA: ++ info->rx_skb->pkt_type = nsh->type; ++ ++ /* remove PAD byte if it exists */ ++ if (nsh->len & 0x0001) { ++ info->rx_skb->tail--; ++ info->rx_skb->len--; ++ } ++ ++ /* remove NSH */ ++ skb_pull(info->rx_skb, NSHL); ++ ++ switch (info->rx_skb->pkt_type) { ++ case 0x80: ++ /* control data for the Nokia Card */ ++ dtl1_control(info, info->rx_skb); ++ break; ++ case 0x82: ++ case 0x83: ++ case 0x84: ++ /* send frame to the HCI layer */ ++ info->rx_skb->dev = (void *)&(info->hdev); ++ info->rx_skb->pkt_type &= 0x0f; ++ hci_recv_frame(info->rx_skb); ++ break; ++ default: ++ /* unknown packet */ ++ printk(KERN_WARNING "dtl1_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type); ++ kfree_skb(info->rx_skb); ++ break; ++ } ++ ++ info->rx_state = RECV_WAIT_NSH; ++ info->rx_count = NSHL; ++ info->rx_skb = NULL; ++ break; ++ } ++ ++ } ++ ++ /* Make sure we don't stay here to long */ ++ if (boguscount++ > 32) ++ break; ++ ++ } while (inb(iobase + UART_LSR) & UART_LSR_DR); ++} ++ ++ ++void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) ++{ ++ dtl1_info_t *info = dev_inst; ++ unsigned int iobase; ++ unsigned char msr; ++ int boguscount = 0; ++ int iir, lsr; ++ ++ if (!info) { ++ printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq); ++ return; ++ } ++ ++ iobase = info->link.io.BasePort1; ++ ++ spin_lock(&(info->lock)); ++ ++ iir = inb(iobase + UART_IIR) & UART_IIR_ID; ++ while (iir) { ++ ++ /* Clear interrupt */ ++ lsr = inb(iobase + UART_LSR); ++ ++ switch (iir) { ++ case UART_IIR_RLSI: ++ printk(KERN_NOTICE "dtl1_cs: RLSI\n"); ++ break; ++ case UART_IIR_RDI: ++ /* Receive interrupt */ ++ dtl1_receive(info); ++ break; ++ case UART_IIR_THRI: ++ if (lsr & UART_LSR_THRE) { ++ /* Transmitter ready for data */ ++ dtl1_write_wakeup(info); ++ } ++ break; ++ default: ++ printk(KERN_NOTICE "dtl1_cs: Unhandled IIR=%#x\n", iir); ++ break; ++ } ++ ++ /* Make sure we don't stay here to long */ ++ if (boguscount++ > 100) ++ break; ++ ++ iir = inb(iobase + UART_IIR) & UART_IIR_ID; ++ ++ } ++ ++ msr = inb(iobase + UART_MSR); ++ ++ if (info->ri_latch ^ (msr & UART_MSR_RI)) { ++ info->ri_latch = msr & UART_MSR_RI; ++ clear_bit(XMIT_WAITING, &(info->tx_state)); ++ dtl1_write_wakeup(info); ++ } ++ ++ spin_unlock(&(info->lock)); ++} ++ ++ ++ ++/* ======================== HCI interface ======================== */ ++ ++ ++static int dtl1_hci_open(struct hci_dev *hdev) ++{ ++ set_bit(HCI_RUNNING, &(hdev->flags)); ++ ++ return 0; ++} ++ ++ ++static int dtl1_hci_flush(struct hci_dev *hdev) ++{ ++ dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data); ++ ++ /* Drop TX queue */ ++ skb_queue_purge(&(info->txq)); ++ ++ return 0; ++} ++ ++ ++static int dtl1_hci_close(struct hci_dev *hdev) ++{ ++ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) ++ return 0; ++ ++ dtl1_hci_flush(hdev); ++ ++ return 0; ++} ++ ++ ++static int dtl1_hci_send_frame(struct sk_buff *skb) ++{ ++ dtl1_info_t *info; ++ struct hci_dev *hdev = (struct hci_dev *)(skb->dev); ++ struct sk_buff *s; ++ nsh_t nsh; ++ ++ if (!hdev) { ++ printk(KERN_WARNING "dtl1_cs: Frame for unknown HCI device (hdev=NULL)."); ++ return -ENODEV; ++ } ++ ++ info = (dtl1_info_t *)(hdev->driver_data); ++ ++ switch (skb->pkt_type) { ++ case HCI_COMMAND_PKT: ++ hdev->stat.cmd_tx++; ++ nsh.type = 0x81; ++ break; ++ case HCI_ACLDATA_PKT: ++ hdev->stat.acl_tx++; ++ nsh.type = 0x82; ++ break; ++ case HCI_SCODATA_PKT: ++ hdev->stat.sco_tx++; ++ nsh.type = 0x83; ++ break; ++ }; ++ ++ nsh.zero = 0; ++ nsh.len = skb->len; ++ ++ s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC); ++ skb_reserve(s, NSHL); ++ memcpy(skb_put(s, skb->len), skb->data, skb->len); ++ if (skb->len & 0x0001) ++ *skb_put(s, 1) = 0; /* PAD */ ++ ++ /* Prepend skb with Nokia frame header and queue */ ++ memcpy(skb_push(s, NSHL), &nsh, NSHL); ++ skb_queue_tail(&(info->txq), s); ++ ++ dtl1_write_wakeup(info); ++ ++ kfree_skb(skb); ++ ++ return 0; ++} ++ ++ ++static void dtl1_hci_destruct(struct hci_dev *hdev) ++{ ++} ++ ++ ++static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) ++{ ++ return -ENOIOCTLCMD; ++} ++ ++ ++ ++/* ======================== Card services HCI interaction ======================== */ ++ ++ ++int dtl1_open(dtl1_info_t *info) ++{ ++ unsigned long flags; ++ unsigned int iobase = info->link.io.BasePort1; ++ struct hci_dev *hdev; ++ ++ spin_lock_init(&(info->lock)); ++ ++ skb_queue_head_init(&(info->txq)); ++ ++ info->rx_state = RECV_WAIT_NSH; ++ info->rx_count = NSHL; ++ info->rx_skb = NULL; ++ ++ set_bit(XMIT_WAITING, &(info->tx_state)); ++ ++ spin_lock_irqsave(&(info->lock), flags); ++ ++ /* Reset UART */ ++ outb(0, iobase + UART_MCR); ++ ++ /* Turn off interrupts */ ++ outb(0, iobase + UART_IER); ++ ++ /* Initialize UART */ ++ outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */ ++ outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR); ++ ++ info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI; ++ ++ /* Turn on interrupts */ ++ outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); ++ ++ spin_unlock_irqrestore(&(info->lock), flags); ++ ++ /* Timeout before it is safe to send the first HCI packet */ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(HZ * 2); ++ ++ ++ /* Initialize and register HCI device */ ++ ++ hdev = &(info->hdev); ++ ++ hdev->type = HCI_PCCARD; ++ hdev->driver_data = info; ++ ++ hdev->open = dtl1_hci_open; ++ hdev->close = dtl1_hci_close; ++ hdev->flush = dtl1_hci_flush; ++ hdev->send = dtl1_hci_send_frame; ++ hdev->destruct = dtl1_hci_destruct; ++ hdev->ioctl = dtl1_hci_ioctl; ++ ++ if (hci_register_dev(hdev) < 0) { ++ printk(KERN_WARNING "dtl1_cs: Can't register HCI device %s.\n", hdev->name); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++ ++int dtl1_close(dtl1_info_t *info) ++{ ++ unsigned long flags; ++ unsigned int iobase = info->link.io.BasePort1; ++ struct hci_dev *hdev = &(info->hdev); ++ ++ dtl1_hci_close(hdev); ++ ++ spin_lock_irqsave(&(info->lock), flags); ++ ++ /* Reset UART */ ++ outb(0, iobase + UART_MCR); ++ ++ /* Turn off interrupts */ ++ outb(0, iobase + UART_IER); ++ ++ spin_unlock_irqrestore(&(info->lock), flags); ++ ++ if (hci_unregister_dev(hdev) < 0) ++ printk(KERN_WARNING "dtl1_cs: Can't unregister HCI device %s.\n", hdev->name); ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Card services ======================== */ ++ ++ ++static void cs_error(client_handle_t handle, int func, int ret) ++{ ++ error_info_t err = { func, ret }; ++ ++ CardServices(ReportError, handle, &err); ++} ++ ++ ++dev_link_t *dtl1_attach(void) ++{ ++ dtl1_info_t *info; ++ client_reg_t client_reg; ++ dev_link_t *link; ++ int i, ret; ++ ++ /* Create new info device */ ++ info = kmalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return NULL; ++ memset(info, 0, sizeof(*info)); ++ ++ link = &info->link; ++ link->priv = info; ++ ++ link->release.function = &dtl1_release; ++ link->release.data = (u_long)link; ++ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; ++ link->io.NumPorts1 = 8; ++ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; ++ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; ++ ++ if (irq_list[0] == -1) ++ link->irq.IRQInfo2 = irq_mask; ++ else ++ for (i = 0; i < 4; i++) ++ link->irq.IRQInfo2 |= 1 << irq_list[i]; ++ ++ link->irq.Handler = dtl1_interrupt; ++ link->irq.Instance = info; ++ ++ link->conf.Attributes = CONF_ENABLE_IRQ; ++ link->conf.Vcc = 50; ++ link->conf.IntType = INT_MEMORY_AND_IO; ++ ++ /* Register with Card Services */ ++ link->next = dev_list; ++ dev_list = link; ++ client_reg.dev_info = &dev_info; ++ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; ++ client_reg.EventMask = ++ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | ++ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | ++ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; ++ client_reg.event_handler = &dtl1_event; ++ client_reg.Version = 0x0210; ++ client_reg.event_callback_args.client_data = link; ++ ++ ret = CardServices(RegisterClient, &link->handle, &client_reg); ++ if (ret != CS_SUCCESS) { ++ cs_error(link->handle, RegisterClient, ret); ++ dtl1_detach(link); ++ return NULL; ++ } ++ ++ return link; ++} ++ ++ ++void dtl1_detach(dev_link_t *link) ++{ ++ dtl1_info_t *info = link->priv; ++ dev_link_t **linkp; ++ int ret; ++ ++ /* Locate device structure */ ++ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) ++ if (*linkp == link) ++ break; ++ ++ if (*linkp == NULL) ++ return; ++ ++ del_timer(&link->release); ++ if (link->state & DEV_CONFIG) ++ dtl1_release((u_long)link); ++ ++ if (link->handle) { ++ ret = CardServices(DeregisterClient, link->handle); ++ if (ret != CS_SUCCESS) ++ cs_error(link->handle, DeregisterClient, ret); ++ } ++ ++ /* Unlink device structure, free bits */ ++ *linkp = link->next; ++ ++ kfree(info); ++} ++ ++ ++static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) ++{ ++ int i; ++ ++ i = CardServices(fn, handle, tuple); ++ if (i != CS_SUCCESS) ++ return CS_NO_MORE_ITEMS; ++ ++ i = CardServices(GetTupleData, handle, tuple); ++ if (i != CS_SUCCESS) ++ return i; ++ ++ return CardServices(ParseTuple, handle, tuple, parse); ++} ++ ++ ++#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) ++#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) ++ ++void dtl1_config(dev_link_t *link) ++{ ++ client_handle_t handle = link->handle; ++ dtl1_info_t *info = link->priv; ++ tuple_t tuple; ++ u_short buf[256]; ++ cisparse_t parse; ++ cistpl_cftable_entry_t *cf = &parse.cftable_entry; ++ config_info_t config; ++ int i, last_ret, last_fn; ++ ++ tuple.TupleData = (cisdata_t *)buf; ++ tuple.TupleOffset = 0; ++ tuple.TupleDataMax = 255; ++ tuple.Attributes = 0; ++ ++ /* Get configuration register information */ ++ tuple.DesiredTuple = CISTPL_CONFIG; ++ last_ret = first_tuple(handle, &tuple, &parse); ++ if (last_ret != CS_SUCCESS) { ++ last_fn = ParseTuple; ++ goto cs_failed; ++ } ++ link->conf.ConfigBase = parse.config.base; ++ link->conf.Present = parse.config.rmask[0]; ++ ++ /* Configure card */ ++ link->state |= DEV_CONFIG; ++ i = CardServices(GetConfigurationInfo, handle, &config); ++ link->conf.Vcc = config.Vcc; ++ ++ tuple.TupleData = (cisdata_t *)buf; ++ tuple.TupleOffset = 0; ++ tuple.TupleDataMax = 255; ++ tuple.Attributes = 0; ++ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; ++ ++ /* Look for a generic full-sized window */ ++ link->io.NumPorts1 = 8; ++ i = first_tuple(handle, &tuple, &parse); ++ while (i != CS_NO_MORE_ITEMS) { ++ if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) { ++ link->conf.ConfigIndex = cf->index; ++ link->io.BasePort1 = cf->io.win[0].base; ++ link->io.NumPorts1 = cf->io.win[0].len; /*yo */ ++ link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; ++ i = CardServices(RequestIO, link->handle, &link->io); ++ if (i == CS_SUCCESS) ++ break; ++ } ++ i = next_tuple(handle, &tuple, &parse); ++ } ++ ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestIO, i); ++ goto failed; ++ } ++ ++ i = CardServices(RequestIRQ, link->handle, &link->irq); ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestIRQ, i); ++ link->irq.AssignedIRQ = 0; ++ } ++ ++ i = CardServices(RequestConfiguration, link->handle, &link->conf); ++ if (i != CS_SUCCESS) { ++ cs_error(link->handle, RequestConfiguration, i); ++ goto failed; ++ } ++ ++ MOD_INC_USE_COUNT; ++ ++ if (dtl1_open(info) != 0) ++ goto failed; ++ ++ strcpy(info->node.dev_name, info->hdev.name); ++ link->dev = &info->node; ++ link->state &= ~DEV_CONFIG_PENDING; ++ ++ return; ++ ++cs_failed: ++ cs_error(link->handle, last_fn, last_ret); ++ ++failed: ++ dtl1_release((u_long)link); ++} ++ ++ ++void dtl1_release(u_long arg) ++{ ++ dev_link_t *link = (dev_link_t *)arg; ++ dtl1_info_t *info = link->priv; ++ ++ if (link->state & DEV_PRESENT) ++ dtl1_close(info); ++ ++ MOD_DEC_USE_COUNT; ++ ++ link->dev = NULL; ++ ++ CardServices(ReleaseConfiguration, link->handle); ++ CardServices(ReleaseIO, link->handle, &link->io); ++ CardServices(ReleaseIRQ, link->handle, &link->irq); ++ ++ link->state &= ~DEV_CONFIG; ++} ++ ++ ++int dtl1_event(event_t event, int priority, event_callback_args_t *args) ++{ ++ dev_link_t *link = args->client_data; ++ dtl1_info_t *info = link->priv; ++ ++ switch (event) { ++ case CS_EVENT_CARD_REMOVAL: ++ link->state &= ~DEV_PRESENT; ++ if (link->state & DEV_CONFIG) { ++ dtl1_close(info); ++ mod_timer(&link->release, jiffies + HZ / 20); ++ } ++ break; ++ case CS_EVENT_CARD_INSERTION: ++ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; ++ dtl1_config(link); ++ break; ++ case CS_EVENT_PM_SUSPEND: ++ link->state |= DEV_SUSPEND; ++ /* Fall through... */ ++ case CS_EVENT_RESET_PHYSICAL: ++ if (link->state & DEV_CONFIG) ++ CardServices(ReleaseConfiguration, link->handle); ++ break; ++ case CS_EVENT_PM_RESUME: ++ link->state &= ~DEV_SUSPEND; ++ /* Fall through... */ ++ case CS_EVENT_CARD_RESET: ++ if (DEV_OK(link)) ++ CardServices(RequestConfiguration, link->handle, &link->conf); ++ break; ++ } ++ ++ return 0; ++} ++ ++ ++ ++/* ======================== Module initialization ======================== */ ++ ++ ++int __init init_dtl1_cs(void) ++{ ++ servinfo_t serv; ++ int err; ++ ++ CardServices(GetCardServicesInfo, &serv); ++ if (serv.Revision != CS_RELEASE_CODE) { ++ printk(KERN_NOTICE "dtl1_cs: Card Services release does not match!\n"); ++ return -1; ++ } ++ ++ err = register_pccard_driver(&dev_info, &dtl1_attach, &dtl1_detach); ++ ++ return err; ++} ++ ++ ++void __exit exit_dtl1_cs(void) ++{ ++ unregister_pccard_driver(&dev_info); ++ ++ while (dev_list != NULL) ++ dtl1_detach(dev_list); ++} ++ ++ ++module_init(init_dtl1_cs); ++module_exit(exit_dtl1_cs); ++ ++EXPORT_NO_SYMBOLS; +diff -urN linux-2.4.18/drivers/bluetooth/hci_bcsp.c linux-2.4.18-mh9/drivers/bluetooth/hci_bcsp.c +--- linux-2.4.18/drivers/bluetooth/hci_bcsp.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/drivers/bluetooth/hci_bcsp.c Mon Aug 25 18:38:10 2003 +@@ -0,0 +1,710 @@ ++/* ++ BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ). ++ Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com> ++ ++ Based on ++ hci_h4.c by Maxim Krasnyansky <maxk@qualcomm.com> ++ ABCSP by Carl Orsborn <cjo@csr.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#define VERSION "0.1" ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/version.h> ++#include <linux/config.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/sched.h> ++#include <linux/types.h> ++#include <linux/fcntl.h> ++#include <linux/interrupt.h> ++#include <linux/ptrace.h> ++#include <linux/poll.h> ++ ++#include <linux/slab.h> ++#include <linux/tty.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/signal.h> ++#include <linux/ioctl.h> ++#include <linux/skbuff.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++#include "hci_uart.h" ++#include "hci_bcsp.h" ++ ++#ifndef HCI_UART_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#undef BT_DMP ++#define BT_DMP( A... ) ++#endif ++ ++/* ---- BCSP CRC calculation ---- */ ++ ++/* Table for calculating CRC for polynomial 0x1021, LSB processed first, ++initial value 0xffff, bits shifted in reverse order. */ ++ ++static const u16 crc_table[] = { ++ 0x0000, 0x1081, 0x2102, 0x3183, ++ 0x4204, 0x5285, 0x6306, 0x7387, ++ 0x8408, 0x9489, 0xa50a, 0xb58b, ++ 0xc60c, 0xd68d, 0xe70e, 0xf78f ++}; ++ ++/* Initialise the crc calculator */ ++#define BCSP_CRC_INIT(x) x = 0xffff ++ ++/* ++ Update crc with next data byte ++ ++ Implementation note ++ The data byte is treated as two nibbles. The crc is generated ++ in reverse, i.e., bits are fed into the register from the top. ++*/ ++static void bcsp_crc_update(u16 *crc, u8 d) ++{ ++ u16 reg = *crc; ++ ++ reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f]; ++ reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f]; ++ ++ *crc = reg; ++} ++ ++/* ++ Get reverse of generated crc ++ ++ Implementation note ++ The crc generator (bcsp_crc_init() and bcsp_crc_update()) ++ creates a reversed crc, so it needs to be swapped back before ++ being passed on. ++*/ ++static u16 bcsp_crc_reverse(u16 crc) ++{ ++ u16 b, rev; ++ ++ for (b = 0, rev = 0; b < 16; b++) { ++ rev = rev << 1; ++ rev |= (crc & 1); ++ crc = crc >> 1; ++ } ++ return (rev); ++} ++ ++/* ---- BCSP core ---- */ ++ ++static void bcsp_slip_msgdelim(struct sk_buff *skb) ++{ ++ const char pkt_delim = 0xc0; ++ memcpy(skb_put(skb, 1), &pkt_delim, 1); ++} ++ ++static void bcsp_slip_one_byte(struct sk_buff *skb, u8 c) ++{ ++ const char esc_c0[2] = { 0xdb, 0xdc }; ++ const char esc_db[2] = { 0xdb, 0xdd }; ++ ++ switch (c) { ++ case 0xc0: ++ memcpy(skb_put(skb, 2), &esc_c0, 2); ++ break; ++ case 0xdb: ++ memcpy(skb_put(skb, 2), &esc_db, 2); ++ break; ++ default: ++ memcpy(skb_put(skb, 1), &c, 1); ++ } ++} ++ ++static int bcsp_enqueue(struct hci_uart *hu, struct sk_buff *skb) ++{ ++ struct bcsp_struct *bcsp = hu->priv; ++ ++ if (skb->len > 0xFFF) { ++ BT_ERR("Packet too long"); ++ kfree_skb(skb); ++ return 0; ++ } ++ ++ switch (skb->pkt_type) { ++ case HCI_ACLDATA_PKT: ++ case HCI_COMMAND_PKT: ++ skb_queue_tail(&bcsp->rel, skb); ++ break; ++ ++ case HCI_SCODATA_PKT: ++ skb_queue_tail(&bcsp->unrel, skb); ++ break; ++ ++ default: ++ BT_ERR("Unknown packet type"); ++ kfree_skb(skb); ++ break; ++ } ++ return 0; ++} ++ ++static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data, ++ int len, int pkt_type) ++{ ++ struct sk_buff *nskb; ++ u8 hdr[4], chan; ++ int rel, i; ++ ++#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC ++ u16 BCSP_CRC_INIT(bcsp_txmsg_crc); ++#endif ++ ++ switch (pkt_type) { ++ case HCI_ACLDATA_PKT: ++ chan = 6; /* BCSP ACL channel */ ++ rel = 1; /* reliable channel */ ++ break; ++ case HCI_COMMAND_PKT: ++ chan = 5; /* BCSP cmd/evt channel */ ++ rel = 1; /* reliable channel */ ++ break; ++ case HCI_SCODATA_PKT: ++ chan = 7; /* BCSP SCO channel */ ++ rel = 0; /* unreliable channel */ ++ break; ++ case BCSP_LE_PKT: ++ chan = 1; /* BCSP LE channel */ ++ rel = 0; /* unreliable channel */ ++ break; ++ case BCSP_ACK_PKT: ++ chan = 0; /* BCSP internal channel */ ++ rel = 0; /* unreliable channel */ ++ break; ++ default: ++ BT_ERR("Unknown packet type"); ++ return NULL; ++ } ++ ++ /* Max len of packet: (original len +4(bcsp hdr) +2(crc))*2 ++ (because bytes 0xc0 and 0xdb are escaped, worst case is ++ when the packet is all made of 0xc0 and 0xdb :) ) ++ + 2 (0xc0 delimiters at start and end). */ ++ ++ nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC); ++ if (!nskb) ++ return NULL; ++ ++ nskb->pkt_type = pkt_type; ++ ++ bcsp_slip_msgdelim(nskb); ++ ++ hdr[0] = bcsp->rxseq_txack << 3; ++ bcsp->txack_req = 0; ++ BT_DBG("We request packet no %u to card", bcsp->rxseq_txack); ++ ++ if (rel) { ++ hdr[0] |= 0x80 + bcsp->msgq_txseq; ++ BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq); ++ bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07; ++ } ++#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC ++ hdr[0] |= 0x40; ++#endif ++ ++ hdr[1] = (len << 4) & 0xFF; ++ hdr[1] |= chan; ++ hdr[2] = len >> 4; ++ hdr[3] = ~(hdr[0] + hdr[1] + hdr[2]); ++ ++ /* Put BCSP header */ ++ for (i = 0; i < 4; i++) { ++ bcsp_slip_one_byte(nskb, hdr[i]); ++#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC ++ bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]); ++#endif ++ } ++ ++ /* Put payload */ ++ for (i = 0; i < len; i++) { ++ bcsp_slip_one_byte(nskb, data[i]); ++#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC ++ bcsp_crc_update(&bcsp_txmsg_crc, data[i]); ++#endif ++ } ++ ++#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC ++ /* Put CRC */ ++ bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc); ++ bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff)); ++ bcsp_slip_one_byte(nskb, (u8) (bcsp_txmsg_crc & 0x00ff)); ++#endif ++ ++ bcsp_slip_msgdelim(nskb); ++ return nskb; ++} ++ ++/* This is a rewrite of pkt_avail in ABCSP */ ++static struct sk_buff *bcsp_dequeue(struct hci_uart *hu) ++{ ++ struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv; ++ unsigned long flags; ++ struct sk_buff *skb; ++ ++ /* First of all, check for unreliable messages in the queue, ++ since they have priority */ ++ ++ if ((skb = skb_dequeue(&bcsp->unrel)) != NULL) { ++ struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type); ++ if (nskb) { ++ kfree_skb(skb); ++ return nskb; ++ } else { ++ skb_queue_head(&bcsp->unrel, skb); ++ BT_ERR("Could not dequeue pkt because alloc_skb failed"); ++ } ++ } ++ ++ /* Now, try to send a reliable pkt. We can only send a ++ reliable packet if the number of packets sent but not yet ack'ed ++ is < than the winsize */ ++ ++ spin_lock_irqsave(&bcsp->unack.lock, flags); ++ ++ if (bcsp->unack.qlen < BCSP_TXWINSIZE && (skb = skb_dequeue(&bcsp->rel)) != NULL) { ++ struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type); ++ if (nskb) { ++ __skb_queue_tail(&bcsp->unack, skb); ++ mod_timer(&bcsp->tbcsp, jiffies + HZ / 4); ++ spin_unlock_irqrestore(&bcsp->unack.lock, flags); ++ return nskb; ++ } else { ++ skb_queue_head(&bcsp->rel, skb); ++ BT_ERR("Could not dequeue pkt because alloc_skb failed"); ++ } ++ } ++ ++ spin_unlock_irqrestore(&bcsp->unack.lock, flags); ++ ++ ++ /* We could not send a reliable packet, either because there are ++ none or because there are too many unack'ed pkts. Did we receive ++ any packets we have not acknowledged yet ? */ ++ ++ if (bcsp->txack_req) { ++ /* if so, craft an empty ACK pkt and send it on BCSP unreliable ++ channel 0 */ ++ struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, NULL, 0, BCSP_ACK_PKT); ++ return nskb; ++ } ++ ++ /* We have nothing to send */ ++ return NULL; ++} ++ ++static int bcsp_flush(struct hci_uart *hu) ++{ ++ BT_DBG("hu %p", hu); ++ return 0; ++} ++ ++/* Remove ack'ed packets */ ++static void bcsp_pkt_cull(struct bcsp_struct *bcsp) ++{ ++ unsigned long flags; ++ struct sk_buff *skb; ++ int i, pkts_to_be_removed; ++ u8 seqno; ++ ++ spin_lock_irqsave(&bcsp->unack.lock, flags); ++ ++ pkts_to_be_removed = bcsp->unack.qlen; ++ seqno = bcsp->msgq_txseq; ++ ++ while (pkts_to_be_removed) { ++ if (bcsp->rxack == seqno) ++ break; ++ pkts_to_be_removed--; ++ seqno = (seqno - 1) & 0x07; ++ } ++ ++ if (bcsp->rxack != seqno) ++ BT_ERR("Peer acked invalid packet"); ++ ++ BT_DBG("Removing %u pkts out of %u, up to seqno %u", ++ pkts_to_be_removed, bcsp->unack.qlen, (seqno - 1) & 0x07); ++ ++ for (i = 0, skb = ((struct sk_buff *) &bcsp->unack)->next; i < pkts_to_be_removed ++ && skb != (struct sk_buff *) &bcsp->unack; i++) { ++ struct sk_buff *nskb; ++ ++ nskb = skb->next; ++ __skb_unlink(skb, &bcsp->unack); ++ kfree_skb(skb); ++ skb = nskb; ++ } ++ if (bcsp->unack.qlen == 0) ++ del_timer(&bcsp->tbcsp); ++ spin_unlock_irqrestore(&bcsp->unack.lock, flags); ++ ++ if (i != pkts_to_be_removed) ++ BT_ERR("Removed only %u out of %u pkts", i, pkts_to_be_removed); ++} ++ ++/* Handle BCSP link-establishment packets. When we ++ detect a "sync" packet, symptom that the BT module has reset, ++ we do nothing :) (yet) */ ++static void bcsp_handle_le_pkt(struct hci_uart *hu) ++{ ++ struct bcsp_struct *bcsp = hu->priv; ++ u8 conf_pkt[4] = { 0xad, 0xef, 0xac, 0xed }; ++ u8 conf_rsp_pkt[4] = { 0xde, 0xad, 0xd0, 0xd0 }; ++ u8 sync_pkt[4] = { 0xda, 0xdc, 0xed, 0xed }; ++ ++ /* spot "conf" pkts and reply with a "conf rsp" pkt */ ++ if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 && ++ !memcmp(&bcsp->rx_skb->data[4], conf_pkt, 4)) { ++ struct sk_buff *nskb = alloc_skb(4, GFP_ATOMIC); ++ ++ BT_DBG("Found a LE conf pkt"); ++ if (!nskb) ++ return; ++ memcpy(skb_put(nskb, 4), conf_rsp_pkt, 4); ++ nskb->pkt_type = BCSP_LE_PKT; ++ ++ skb_queue_head(&bcsp->unrel, nskb); ++ hci_uart_tx_wakeup(hu); ++ } ++ /* Spot "sync" pkts. If we find one...disaster! */ ++ else if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 && ++ !memcmp(&bcsp->rx_skb->data[4], sync_pkt, 4)) { ++ BT_ERR("Found a LE sync pkt, card has reset"); ++ } ++} ++ ++static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char byte) ++{ ++ const u8 c0 = 0xc0, db = 0xdb; ++ ++ switch (bcsp->rx_esc_state) { ++ case BCSP_ESCSTATE_NOESC: ++ switch (byte) { ++ case 0xdb: ++ bcsp->rx_esc_state = BCSP_ESCSTATE_ESC; ++ break; ++ default: ++ memcpy(skb_put(bcsp->rx_skb, 1), &byte, 1); ++ if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && ++ bcsp->rx_state != BCSP_W4_CRC) ++ bcsp_crc_update(&bcsp->message_crc, byte); ++ bcsp->rx_count--; ++ } ++ break; ++ ++ case BCSP_ESCSTATE_ESC: ++ switch (byte) { ++ case 0xdc: ++ memcpy(skb_put(bcsp->rx_skb, 1), &c0, 1); ++ if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && ++ bcsp->rx_state != BCSP_W4_CRC) ++ bcsp_crc_update(&bcsp-> message_crc, 0xc0); ++ bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC; ++ bcsp->rx_count--; ++ break; ++ ++ case 0xdd: ++ memcpy(skb_put(bcsp->rx_skb, 1), &db, 1); ++ if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && ++ bcsp->rx_state != BCSP_W4_CRC) ++ bcsp_crc_update(&bcsp-> message_crc, 0xdb); ++ bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC; ++ bcsp->rx_count--; ++ break; ++ ++ default: ++ BT_ERR ("Invalid byte %02x after esc byte", byte); ++ kfree_skb(bcsp->rx_skb); ++ bcsp->rx_skb = NULL; ++ bcsp->rx_state = BCSP_W4_PKT_DELIMITER; ++ bcsp->rx_count = 0; ++ } ++ } ++} ++ ++static inline void bcsp_complete_rx_pkt(struct hci_uart *hu) ++{ ++ struct bcsp_struct *bcsp = hu->priv; ++ int pass_up; ++ ++ if (bcsp->rx_skb->data[0] & 0x80) { /* reliable pkt */ ++ BT_DBG("Received seqno %u from card", bcsp->rxseq_txack); ++ bcsp->rxseq_txack++; ++ bcsp->rxseq_txack %= 0x8; ++ bcsp->txack_req = 1; ++ ++ /* If needed, transmit an ack pkt */ ++ hci_uart_tx_wakeup(hu); ++ } ++ ++ bcsp->rxack = (bcsp->rx_skb->data[0] >> 3) & 0x07; ++ BT_DBG("Request for pkt %u from card", bcsp->rxack); ++ ++ bcsp_pkt_cull(bcsp); ++ if ((bcsp->rx_skb->data[1] & 0x0f) == 6 && ++ bcsp->rx_skb->data[0] & 0x80) { ++ bcsp->rx_skb->pkt_type = HCI_ACLDATA_PKT; ++ pass_up = 1; ++ } else if ((bcsp->rx_skb->data[1] & 0x0f) == 5 && ++ bcsp->rx_skb->data[0] & 0x80) { ++ bcsp->rx_skb->pkt_type = HCI_EVENT_PKT; ++ pass_up = 1; ++ } else if ((bcsp->rx_skb->data[1] & 0x0f) == 7) { ++ bcsp->rx_skb->pkt_type = HCI_SCODATA_PKT; ++ pass_up = 1; ++ } else if ((bcsp->rx_skb->data[1] & 0x0f) == 1 && ++ !(bcsp->rx_skb->data[0] & 0x80)) { ++ bcsp_handle_le_pkt(hu); ++ pass_up = 0; ++ } else ++ pass_up = 0; ++ ++ if (!pass_up) { ++ if ((bcsp->rx_skb->data[1] & 0x0f) != 0 && ++ (bcsp->rx_skb->data[1] & 0x0f) != 1) { ++ BT_ERR ("Packet for unknown channel (%u %s)", ++ bcsp->rx_skb->data[1] & 0x0f, ++ bcsp->rx_skb->data[0] & 0x80 ? ++ "reliable" : "unreliable"); ++ } ++ kfree_skb(bcsp->rx_skb); ++ } else { ++ /* Pull out BCSP hdr */ ++ skb_pull(bcsp->rx_skb, 4); ++ ++ hci_recv_frame(bcsp->rx_skb); ++ } ++ bcsp->rx_state = BCSP_W4_PKT_DELIMITER; ++ bcsp->rx_skb = NULL; ++} ++ ++/* Recv data */ ++static int bcsp_recv(struct hci_uart *hu, void *data, int count) ++{ ++ struct bcsp_struct *bcsp = hu->priv; ++ register unsigned char *ptr; ++ ++ BT_DBG("hu %p count %d rx_state %ld rx_count %ld", ++ hu, count, bcsp->rx_state, bcsp->rx_count); ++ ++ ptr = data; ++ while (count) { ++ if (bcsp->rx_count) { ++ if (*ptr == 0xc0) { ++ BT_ERR("Short BCSP packet"); ++ kfree_skb(bcsp->rx_skb); ++ bcsp->rx_state = BCSP_W4_PKT_START; ++ bcsp->rx_count = 0; ++ } else ++ bcsp_unslip_one_byte(bcsp, *ptr); ++ ++ ptr++; count--; ++ continue; ++ } ++ ++ switch (bcsp->rx_state) { ++ case BCSP_W4_BCSP_HDR: ++ if ((0xff & (u8) ~ (bcsp->rx_skb->data[0] + bcsp->rx_skb->data[1] + ++ bcsp->rx_skb->data[2])) != bcsp->rx_skb->data[3]) { ++ BT_ERR("Error in BCSP hdr checksum"); ++ kfree_skb(bcsp->rx_skb); ++ bcsp->rx_state = BCSP_W4_PKT_DELIMITER; ++ bcsp->rx_count = 0; ++ continue; ++ } ++ if (bcsp->rx_skb->data[0] & 0x80 /* reliable pkt */ ++ && (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) { ++ BT_ERR ("Out-of-order packet arrived, got %u expected %u", ++ bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack); ++ ++ kfree_skb(bcsp->rx_skb); ++ bcsp->rx_state = BCSP_W4_PKT_DELIMITER; ++ bcsp->rx_count = 0; ++ continue; ++ } ++ bcsp->rx_state = BCSP_W4_DATA; ++ bcsp->rx_count = (bcsp->rx_skb->data[1] >> 4) + ++ (bcsp->rx_skb->data[2] << 4); /* May be 0 */ ++ continue; ++ ++ case BCSP_W4_DATA: ++ if (bcsp->rx_skb->data[0] & 0x40) { /* pkt with crc */ ++ bcsp->rx_state = BCSP_W4_CRC; ++ bcsp->rx_count = 2; ++ } else ++ bcsp_complete_rx_pkt(hu); ++ continue; ++ ++ case BCSP_W4_CRC: ++ if (bcsp_crc_reverse(bcsp->message_crc) != ++ (bcsp->rx_skb->data[bcsp->rx_skb->len - 2] << 8) + ++ bcsp->rx_skb->data[bcsp->rx_skb->len - 1]) { ++ ++ BT_ERR ("Checksum failed: computed %04x received %04x", ++ bcsp_crc_reverse(bcsp->message_crc), ++ (bcsp->rx_skb-> data[bcsp->rx_skb->len - 2] << 8) + ++ bcsp->rx_skb->data[bcsp->rx_skb->len - 1]); ++ ++ kfree_skb(bcsp->rx_skb); ++ bcsp->rx_state = BCSP_W4_PKT_DELIMITER; ++ bcsp->rx_count = 0; ++ continue; ++ } ++ skb_trim(bcsp->rx_skb, bcsp->rx_skb->len - 2); ++ bcsp_complete_rx_pkt(hu); ++ continue; ++ ++ case BCSP_W4_PKT_DELIMITER: ++ switch (*ptr) { ++ case 0xc0: ++ bcsp->rx_state = BCSP_W4_PKT_START; ++ break; ++ default: ++ /*BT_ERR("Ignoring byte %02x", *ptr);*/ ++ break; ++ } ++ ptr++; count--; ++ break; ++ ++ case BCSP_W4_PKT_START: ++ switch (*ptr) { ++ case 0xc0: ++ ptr++; count--; ++ break; ++ ++ default: ++ bcsp->rx_state = BCSP_W4_BCSP_HDR; ++ bcsp->rx_count = 4; ++ bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC; ++ BCSP_CRC_INIT(bcsp->message_crc); ++ ++ /* Do not increment ptr or decrement count ++ * Allocate packet. Max len of a BCSP pkt= ++ * 0xFFF (payload) +4 (header) +2 (crc) */ ++ ++ bcsp->rx_skb = bluez_skb_alloc(0x1005, GFP_ATOMIC); ++ if (!bcsp->rx_skb) { ++ BT_ERR("Can't allocate mem for new packet"); ++ bcsp->rx_state = BCSP_W4_PKT_DELIMITER; ++ bcsp->rx_count = 0; ++ return 0; ++ } ++ bcsp->rx_skb->dev = (void *) &hu->hdev; ++ break; ++ } ++ break; ++ } ++ } ++ return count; ++} ++ ++ /* Arrange to retransmit all messages in the relq. */ ++static void bcsp_timed_event(unsigned long arg) ++{ ++ struct hci_uart *hu = (struct hci_uart *) arg; ++ struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv; ++ struct sk_buff *skb; ++ unsigned long flags; ++ ++ BT_ERR("Timeout, retransmitting %u pkts", bcsp->unack.qlen); ++ spin_lock_irqsave(&bcsp->unack.lock, flags); ++ ++ while ((skb = __skb_dequeue_tail(&bcsp->unack)) != NULL) { ++ bcsp->msgq_txseq = (bcsp->msgq_txseq - 1) & 0x07; ++ skb_queue_head(&bcsp->rel, skb); ++ } ++ ++ spin_unlock_irqrestore(&bcsp->unack.lock, flags); ++ ++ hci_uart_tx_wakeup(hu); ++} ++ ++static int bcsp_open(struct hci_uart *hu) ++{ ++ struct bcsp_struct *bcsp; ++ ++ BT_DBG("hu %p", hu); ++ ++ bcsp = kmalloc(sizeof(*bcsp), GFP_ATOMIC); ++ if (!bcsp) ++ return -ENOMEM; ++ memset(bcsp, 0, sizeof(*bcsp)); ++ ++ hu->priv = bcsp; ++ skb_queue_head_init(&bcsp->unack); ++ skb_queue_head_init(&bcsp->rel); ++ skb_queue_head_init(&bcsp->unrel); ++ ++ init_timer(&bcsp->tbcsp); ++ bcsp->tbcsp.function = bcsp_timed_event; ++ bcsp->tbcsp.data = (u_long) hu; ++ ++ bcsp->rx_state = BCSP_W4_PKT_DELIMITER; ++ ++ return 0; ++} ++ ++static int bcsp_close(struct hci_uart *hu) ++{ ++ struct bcsp_struct *bcsp = hu->priv; ++ hu->priv = NULL; ++ ++ BT_DBG("hu %p", hu); ++ ++ skb_queue_purge(&bcsp->unack); ++ skb_queue_purge(&bcsp->rel); ++ skb_queue_purge(&bcsp->unrel); ++ del_timer(&bcsp->tbcsp); ++ ++ kfree(bcsp); ++ return 0; ++} ++ ++static struct hci_uart_proto bcsp = { ++ id: HCI_UART_BCSP, ++ open: bcsp_open, ++ close: bcsp_close, ++ enqueue: bcsp_enqueue, ++ dequeue: bcsp_dequeue, ++ recv: bcsp_recv, ++ flush: bcsp_flush ++}; ++ ++int bcsp_init(void) ++{ ++ return hci_uart_register_proto(&bcsp); ++} ++ ++int bcsp_deinit(void) ++{ ++ return hci_uart_unregister_proto(&bcsp); ++} +diff -urN linux-2.4.18/drivers/bluetooth/hci_bcsp.h linux-2.4.18-mh9/drivers/bluetooth/hci_bcsp.h +--- linux-2.4.18/drivers/bluetooth/hci_bcsp.h Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/drivers/bluetooth/hci_bcsp.h Mon Aug 25 18:38:10 2003 +@@ -0,0 +1,70 @@ ++/* ++ BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ). ++ Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com> ++ ++ Based on ++ hci_h4.c by Maxim Krasnyansky <maxk@qualcomm.com> ++ ABCSP by Carl Orsborn <cjo@csr.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#ifndef __HCI_BCSP_H__ ++#define __HCI_BCSP_H__ ++ ++#define BCSP_TXWINSIZE 4 ++ ++#define BCSP_ACK_PKT 0x05 ++#define BCSP_LE_PKT 0x06 ++ ++struct bcsp_struct { ++ struct sk_buff_head unack; /* Unack'ed packets queue */ ++ struct sk_buff_head rel; /* Reliable packets queue */ ++ struct sk_buff_head unrel; /* Unreliable packets queue */ ++ ++ unsigned long rx_count; ++ struct sk_buff *rx_skb; ++ u8 rxseq_txack; /* rxseq == txack. */ ++ u8 rxack; /* Last packet sent by us that the peer ack'ed */ ++ struct timer_list tbcsp; ++ ++ enum { ++ BCSP_W4_PKT_DELIMITER, ++ BCSP_W4_PKT_START, ++ BCSP_W4_BCSP_HDR, ++ BCSP_W4_DATA, ++ BCSP_W4_CRC ++ } rx_state; ++ ++ enum { ++ BCSP_ESCSTATE_NOESC, ++ BCSP_ESCSTATE_ESC ++ } rx_esc_state; ++ ++ u16 message_crc; ++ u8 txack_req; /* Do we need to send ack's to the peer? */ ++ ++ /* Reliable packet sequence number - used to assign seq to each rel pkt. */ ++ u8 msgq_txseq; ++}; ++ ++#endif /* __HCI_BCSP_H__ */ +diff -urN linux-2.4.18/drivers/bluetooth/hci_h4.c linux-2.4.18-mh9/drivers/bluetooth/hci_h4.c +--- linux-2.4.18/drivers/bluetooth/hci_h4.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/drivers/bluetooth/hci_h4.c Mon Aug 25 18:38:10 2003 +@@ -0,0 +1,277 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * BlueZ HCI UART(H4) protocol. ++ * ++ * $Id$ ++ */ ++#define VERSION "1.2" ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/version.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/sched.h> ++#include <linux/types.h> ++#include <linux/fcntl.h> ++#include <linux/interrupt.h> ++#include <linux/ptrace.h> ++#include <linux/poll.h> ++ ++#include <linux/slab.h> ++#include <linux/tty.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/signal.h> ++#include <linux/ioctl.h> ++#include <linux/skbuff.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++#include "hci_uart.h" ++#include "hci_h4.h" ++ ++#ifndef HCI_UART_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#undef BT_DMP ++#define BT_DMP( A... ) ++#endif ++ ++/* Initialize protocol */ ++static int h4_open(struct hci_uart *hu) ++{ ++ struct h4_struct *h4; ++ ++ BT_DBG("hu %p", hu); ++ ++ h4 = kmalloc(sizeof(*h4), GFP_ATOMIC); ++ if (!h4) ++ return -ENOMEM; ++ memset(h4, 0, sizeof(*h4)); ++ ++ skb_queue_head_init(&h4->txq); ++ ++ hu->priv = h4; ++ return 0; ++} ++ ++/* Flush protocol data */ ++static int h4_flush(struct hci_uart *hu) ++{ ++ struct h4_struct *h4 = hu->priv; ++ ++ BT_DBG("hu %p", hu); ++ skb_queue_purge(&h4->txq); ++ return 0; ++} ++ ++/* Close protocol */ ++static int h4_close(struct hci_uart *hu) ++{ ++ struct h4_struct *h4 = hu->priv; ++ hu->priv = NULL; ++ ++ BT_DBG("hu %p", hu); ++ ++ skb_queue_purge(&h4->txq); ++ if (h4->rx_skb) ++ kfree_skb(h4->rx_skb); ++ ++ hu->priv = NULL; ++ kfree(h4); ++ return 0; ++} ++ ++/* Enqueue frame for transmittion (padding, crc, etc) */ ++static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb) ++{ ++ struct h4_struct *h4 = hu->priv; ++ ++ BT_DBG("hu %p skb %p", hu, skb); ++ ++ /* Prepend skb with frame type */ ++ memcpy(skb_push(skb, 1), &skb->pkt_type, 1); ++ skb_queue_tail(&h4->txq, skb); ++ return 0; ++} ++ ++static inline int h4_check_data_len(struct h4_struct *h4, int len) ++{ ++ register int room = skb_tailroom(h4->rx_skb); ++ ++ BT_DBG("len %d room %d", len, room); ++ if (!len) { ++ BT_DMP(h4->rx_skb->data, h4->rx_skb->len); ++ hci_recv_frame(h4->rx_skb); ++ } else if (len > room) { ++ BT_ERR("Data length is too large"); ++ kfree_skb(h4->rx_skb); ++ } else { ++ h4->rx_state = H4_W4_DATA; ++ h4->rx_count = len; ++ return len; ++ } ++ ++ h4->rx_state = H4_W4_PACKET_TYPE; ++ h4->rx_skb = NULL; ++ h4->rx_count = 0; ++ return 0; ++} ++ ++/* Recv data */ ++static int h4_recv(struct hci_uart *hu, void *data, int count) ++{ ++ struct h4_struct *h4 = hu->priv; ++ register char *ptr; ++ hci_event_hdr *eh; ++ hci_acl_hdr *ah; ++ hci_sco_hdr *sh; ++ register int len, type, dlen; ++ ++ BT_DBG("hu %p count %d rx_state %ld rx_count %ld", ++ hu, count, h4->rx_state, h4->rx_count); ++ ++ ptr = data; ++ while (count) { ++ if (h4->rx_count) { ++ len = MIN(h4->rx_count, count); ++ memcpy(skb_put(h4->rx_skb, len), ptr, len); ++ h4->rx_count -= len; count -= len; ptr += len; ++ ++ if (h4->rx_count) ++ continue; ++ ++ switch (h4->rx_state) { ++ case H4_W4_DATA: ++ BT_DBG("Complete data"); ++ ++ BT_DMP(h4->rx_skb->data, h4->rx_skb->len); ++ ++ hci_recv_frame(h4->rx_skb); ++ ++ h4->rx_state = H4_W4_PACKET_TYPE; ++ h4->rx_skb = NULL; ++ continue; ++ ++ case H4_W4_EVENT_HDR: ++ eh = (hci_event_hdr *) h4->rx_skb->data; ++ ++ BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); ++ ++ h4_check_data_len(h4, eh->plen); ++ continue; ++ ++ case H4_W4_ACL_HDR: ++ ah = (hci_acl_hdr *) h4->rx_skb->data; ++ dlen = __le16_to_cpu(ah->dlen); ++ ++ BT_DBG("ACL header: dlen %d", dlen); ++ ++ h4_check_data_len(h4, dlen); ++ continue; ++ ++ case H4_W4_SCO_HDR: ++ sh = (hci_sco_hdr *) h4->rx_skb->data; ++ ++ BT_DBG("SCO header: dlen %d", sh->dlen); ++ ++ h4_check_data_len(h4, sh->dlen); ++ continue; ++ } ++ } ++ ++ /* H4_W4_PACKET_TYPE */ ++ switch (*ptr) { ++ case HCI_EVENT_PKT: ++ BT_DBG("Event packet"); ++ h4->rx_state = H4_W4_EVENT_HDR; ++ h4->rx_count = HCI_EVENT_HDR_SIZE; ++ type = HCI_EVENT_PKT; ++ break; ++ ++ case HCI_ACLDATA_PKT: ++ BT_DBG("ACL packet"); ++ h4->rx_state = H4_W4_ACL_HDR; ++ h4->rx_count = HCI_ACL_HDR_SIZE; ++ type = HCI_ACLDATA_PKT; ++ break; ++ ++ case HCI_SCODATA_PKT: ++ BT_DBG("SCO packet"); ++ h4->rx_state = H4_W4_SCO_HDR; ++ h4->rx_count = HCI_SCO_HDR_SIZE; ++ type = HCI_SCODATA_PKT; ++ break; ++ ++ default: ++ BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); ++ hu->hdev.stat.err_rx++; ++ ptr++; count--; ++ continue; ++ }; ++ ptr++; count--; ++ ++ /* Allocate packet */ ++ h4->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); ++ if (!h4->rx_skb) { ++ BT_ERR("Can't allocate mem for new packet"); ++ h4->rx_state = H4_W4_PACKET_TYPE; ++ h4->rx_count = 0; ++ return 0; ++ } ++ h4->rx_skb->dev = (void *) &hu->hdev; ++ h4->rx_skb->pkt_type = type; ++ } ++ return count; ++} ++ ++static struct sk_buff *h4_dequeue(struct hci_uart *hu) ++{ ++ struct h4_struct *h4 = hu->priv; ++ return skb_dequeue(&h4->txq); ++} ++ ++static struct hci_uart_proto h4p = { ++ id: HCI_UART_H4, ++ open: h4_open, ++ close: h4_close, ++ recv: h4_recv, ++ enqueue: h4_enqueue, ++ dequeue: h4_dequeue, ++ flush: h4_flush, ++}; ++ ++int h4_init(void) ++{ ++ return hci_uart_register_proto(&h4p); ++} ++ ++int h4_deinit(void) ++{ ++ return hci_uart_unregister_proto(&h4p); ++} +diff -urN linux-2.4.18/drivers/bluetooth/hci_h4.h linux-2.4.18-mh9/drivers/bluetooth/hci_h4.h +--- linux-2.4.18/drivers/bluetooth/hci_h4.h Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/drivers/bluetooth/hci_h4.h Mon Aug 25 18:38:10 2003 +@@ -0,0 +1,44 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#ifdef __KERNEL__ ++struct h4_struct { ++ unsigned long rx_state; ++ unsigned long rx_count; ++ struct sk_buff *rx_skb; ++ struct sk_buff_head txq; ++}; ++ ++/* H4 receiver States */ ++#define H4_W4_PACKET_TYPE 0 ++#define H4_W4_EVENT_HDR 1 ++#define H4_W4_ACL_HDR 2 ++#define H4_W4_SCO_HDR 3 ++#define H4_W4_DATA 4 ++ ++#endif /* __KERNEL__ */ +diff -urN linux-2.4.18/drivers/bluetooth/hci_ldisc.c linux-2.4.18-mh9/drivers/bluetooth/hci_ldisc.c +--- linux-2.4.18/drivers/bluetooth/hci_ldisc.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/drivers/bluetooth/hci_ldisc.c Mon Aug 25 18:38:10 2003 +@@ -0,0 +1,580 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * BlueZ HCI UART driver. ++ * ++ * $Id$ ++ */ ++#define VERSION "2.1" ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/version.h> ++#include <linux/config.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/sched.h> ++#include <linux/types.h> ++#include <linux/fcntl.h> ++#include <linux/interrupt.h> ++#include <linux/ptrace.h> ++#include <linux/poll.h> ++ ++#include <linux/slab.h> ++#include <linux/tty.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/signal.h> ++#include <linux/ioctl.h> ++#include <linux/skbuff.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++#include "hci_uart.h" ++ ++#ifndef HCI_UART_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#undef BT_DMP ++#define BT_DMP( A... ) ++#endif ++ ++static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; ++ ++int hci_uart_register_proto(struct hci_uart_proto *p) ++{ ++ if (p->id >= HCI_UART_MAX_PROTO) ++ return -EINVAL; ++ ++ if (hup[p->id]) ++ return -EEXIST; ++ ++ hup[p->id] = p; ++ return 0; ++} ++ ++int hci_uart_unregister_proto(struct hci_uart_proto *p) ++{ ++ if (p->id >= HCI_UART_MAX_PROTO) ++ return -EINVAL; ++ ++ if (!hup[p->id]) ++ return -EINVAL; ++ ++ hup[p->id] = NULL; ++ return 0; ++} ++ ++static struct hci_uart_proto *hci_uart_get_proto(unsigned int id) ++{ ++ if (id >= HCI_UART_MAX_PROTO) ++ return NULL; ++ return hup[id]; ++} ++ ++static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type) ++{ ++ struct hci_dev *hdev = &hu->hdev; ++ ++ /* Update HCI stat counters */ ++ switch (pkt_type) { ++ case HCI_COMMAND_PKT: ++ hdev->stat.cmd_tx++; ++ break; ++ ++ case HCI_ACLDATA_PKT: ++ hdev->stat.acl_tx++; ++ break; ++ ++ case HCI_SCODATA_PKT: ++ hdev->stat.cmd_tx++; ++ break; ++ } ++} ++ ++static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) ++{ ++ struct sk_buff *skb = hu->tx_skb; ++ if (!skb) ++ skb = hu->proto->dequeue(hu); ++ else ++ hu->tx_skb = NULL; ++ return skb; ++} ++ ++int hci_uart_tx_wakeup(struct hci_uart *hu) ++{ ++ struct tty_struct *tty = hu->tty; ++ struct hci_dev *hdev = &hu->hdev; ++ struct sk_buff *skb; ++ ++ if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) { ++ set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); ++ return 0; ++ } ++ ++ BT_DBG(""); ++ ++restart: ++ clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); ++ ++ while ((skb = hci_uart_dequeue(hu))) { ++ int len; ++ ++ set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); ++ len = tty->driver.write(tty, 0, skb->data, skb->len); ++ hdev->stat.byte_tx += len; ++ ++ skb_pull(skb, len); ++ if (skb->len) { ++ hu->tx_skb = skb; ++ break; ++ } ++ ++ hci_uart_tx_complete(hu, skb->pkt_type); ++ kfree_skb(skb); ++ } ++ ++ if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state)) ++ goto restart; ++ ++ clear_bit(HCI_UART_SENDING, &hu->tx_state); ++ return 0; ++} ++ ++/* ------- Interface to HCI layer ------ */ ++/* Initialize device */ ++static int hci_uart_open(struct hci_dev *hdev) ++{ ++ BT_DBG("%s %p", hdev->name, hdev); ++ ++ /* Nothing to do for UART driver */ ++ ++ set_bit(HCI_RUNNING, &hdev->flags); ++ return 0; ++} ++ ++/* Reset device */ ++static int hci_uart_flush(struct hci_dev *hdev) ++{ ++ struct hci_uart *hu = (struct hci_uart *) hdev->driver_data; ++ struct tty_struct *tty = hu->tty; ++ ++ BT_DBG("hdev %p tty %p", hdev, tty); ++ ++ if (hu->tx_skb) { ++ kfree_skb(hu->tx_skb); hu->tx_skb = NULL; ++ } ++ ++ /* Flush any pending characters in the driver and discipline. */ ++ if (tty->ldisc.flush_buffer) ++ tty->ldisc.flush_buffer(tty); ++ ++ if (tty->driver.flush_buffer) ++ tty->driver.flush_buffer(tty); ++ ++ if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) ++ hu->proto->flush(hu); ++ ++ return 0; ++} ++ ++/* Close device */ ++static int hci_uart_close(struct hci_dev *hdev) ++{ ++ BT_DBG("hdev %p", hdev); ++ ++ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) ++ return 0; ++ ++ hci_uart_flush(hdev); ++ return 0; ++} ++ ++/* Send frames from HCI layer */ ++static int hci_uart_send_frame(struct sk_buff *skb) ++{ ++ struct hci_dev* hdev = (struct hci_dev *) skb->dev; ++ struct tty_struct *tty; ++ struct hci_uart *hu; ++ ++ if (!hdev) { ++ BT_ERR("Frame for uknown device (hdev=NULL)"); ++ return -ENODEV; ++ } ++ ++ if (!test_bit(HCI_RUNNING, &hdev->flags)) ++ return -EBUSY; ++ ++ hu = (struct hci_uart *) hdev->driver_data; ++ tty = hu->tty; ++ ++ BT_DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len); ++ ++ hu->proto->enqueue(hu, skb); ++ ++ hci_uart_tx_wakeup(hu); ++ return 0; ++} ++ ++static void hci_uart_destruct(struct hci_dev *hdev) ++{ ++ struct hci_uart *hu; ++ ++ if (!hdev) return; ++ ++ BT_DBG("%s", hdev->name); ++ ++ hu = (struct hci_uart *) hdev->driver_data; ++ kfree(hu); ++ ++ MOD_DEC_USE_COUNT; ++} ++ ++/* ------ LDISC part ------ */ ++/* hci_uart_tty_open ++ * ++ * Called when line discipline changed to HCI_UART. ++ * ++ * Arguments: ++ * tty pointer to tty info structure ++ * Return Value: ++ * 0 if success, otherwise error code ++ */ ++static int hci_uart_tty_open(struct tty_struct *tty) ++{ ++ struct hci_uart *hu = (void *) tty->disc_data; ++ ++ BT_DBG("tty %p", tty); ++ ++ if (hu) ++ return -EEXIST; ++ ++ if (!(hu = kmalloc(sizeof(struct hci_uart), GFP_KERNEL))) { ++ BT_ERR("Can't allocate controll structure"); ++ return -ENFILE; ++ } ++ memset(hu, 0, sizeof(struct hci_uart)); ++ ++ tty->disc_data = hu; ++ hu->tty = tty; ++ ++ spin_lock_init(&hu->rx_lock); ++ ++ /* Flush any pending characters in the driver and line discipline */ ++ if (tty->ldisc.flush_buffer) ++ tty->ldisc.flush_buffer(tty); ++ ++ if (tty->driver.flush_buffer) ++ tty->driver.flush_buffer(tty); ++ ++ MOD_INC_USE_COUNT; ++ return 0; ++} ++ ++/* hci_uart_tty_close() ++ * ++ * Called when the line discipline is changed to something ++ * else, the tty is closed, or the tty detects a hangup. ++ */ ++static void hci_uart_tty_close(struct tty_struct *tty) ++{ ++ struct hci_uart *hu = (void *)tty->disc_data; ++ ++ BT_DBG("tty %p", tty); ++ ++ /* Detach from the tty */ ++ tty->disc_data = NULL; ++ ++ if (hu) { ++ struct hci_dev *hdev = &hu->hdev; ++ hci_uart_close(hdev); ++ ++ if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { ++ hu->proto->close(hu); ++ hci_unregister_dev(hdev); ++ } ++ ++ MOD_DEC_USE_COUNT; ++ } ++} ++ ++/* hci_uart_tty_wakeup() ++ * ++ * Callback for transmit wakeup. Called when low level ++ * device driver can accept more send data. ++ * ++ * Arguments: tty pointer to associated tty instance data ++ * Return Value: None ++ */ ++static void hci_uart_tty_wakeup(struct tty_struct *tty) ++{ ++ struct hci_uart *hu = (void *)tty->disc_data; ++ ++ BT_DBG(""); ++ ++ if (!hu) ++ return; ++ ++ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); ++ ++ if (tty != hu->tty) ++ return; ++ ++ if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) ++ hci_uart_tx_wakeup(hu); ++} ++ ++/* hci_uart_tty_room() ++ * ++ * Callback function from tty driver. Return the amount of ++ * space left in the receiver's buffer to decide if remote ++ * transmitter is to be throttled. ++ * ++ * Arguments: tty pointer to associated tty instance data ++ * Return Value: number of bytes left in receive buffer ++ */ ++static int hci_uart_tty_room (struct tty_struct *tty) ++{ ++ return 65536; ++} ++ ++/* hci_uart_tty_receive() ++ * ++ * Called by tty low level driver when receive data is ++ * available. ++ * ++ * Arguments: tty pointer to tty isntance data ++ * data pointer to received data ++ * flags pointer to flags for data ++ * count count of received data in bytes ++ * ++ * Return Value: None ++ */ ++static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count) ++{ ++ struct hci_uart *hu = (void *)tty->disc_data; ++ ++ if (!hu || tty != hu->tty) ++ return; ++ ++ if (!test_bit(HCI_UART_PROTO_SET, &hu->flags)) ++ return; ++ ++ spin_lock(&hu->rx_lock); ++ hu->proto->recv(hu, (void *) data, count); ++ hu->hdev.stat.byte_rx += count; ++ spin_unlock(&hu->rx_lock); ++ ++ if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle) ++ tty->driver.unthrottle(tty); ++} ++ ++static int hci_uart_register_dev(struct hci_uart *hu) ++{ ++ struct hci_dev *hdev; ++ ++ BT_DBG(""); ++ ++ /* Initialize and register HCI device */ ++ hdev = &hu->hdev; ++ ++ hdev->type = HCI_UART; ++ hdev->driver_data = hu; ++ ++ hdev->open = hci_uart_open; ++ hdev->close = hci_uart_close; ++ hdev->flush = hci_uart_flush; ++ hdev->send = hci_uart_send_frame; ++ hdev->destruct = hci_uart_destruct; ++ ++ if (hci_register_dev(hdev) < 0) { ++ BT_ERR("Can't register HCI device %s", hdev->name); ++ return -ENODEV; ++ } ++ MOD_INC_USE_COUNT; ++ return 0; ++} ++ ++static int hci_uart_set_proto(struct hci_uart *hu, int id) ++{ ++ struct hci_uart_proto *p; ++ int err; ++ ++ p = hci_uart_get_proto(id); ++ if (!p) ++ return -EPROTONOSUPPORT; ++ ++ err = p->open(hu); ++ if (err) ++ return err; ++ ++ hu->proto = p; ++ ++ err = hci_uart_register_dev(hu); ++ if (err) { ++ p->close(hu); ++ return err; ++ } ++ return 0; ++} ++ ++/* hci_uart_tty_ioctl() ++ * ++ * Process IOCTL system call for the tty device. ++ * ++ * Arguments: ++ * ++ * tty pointer to tty instance data ++ * file pointer to open file object for device ++ * cmd IOCTL command code ++ * arg argument for IOCTL call (cmd dependent) ++ * ++ * Return Value: Command dependent ++ */ ++static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, ++ unsigned int cmd, unsigned long arg) ++{ ++ struct hci_uart *hu = (void *)tty->disc_data; ++ int err = 0; ++ ++ BT_DBG(""); ++ ++ /* Verify the status of the device */ ++ if (!hu) ++ return -EBADF; ++ ++ switch (cmd) { ++ case HCIUARTSETPROTO: ++ if (!test_and_set_bit(HCI_UART_PROTO_SET, &hu->flags)) { ++ err = hci_uart_set_proto(hu, arg); ++ if (err) { ++ clear_bit(HCI_UART_PROTO_SET, &hu->flags); ++ return err; ++ } ++ tty->low_latency = 1; ++ } else ++ return -EBUSY; ++ ++ case HCIUARTGETPROTO: ++ if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) ++ return hu->proto->id; ++ return -EUNATCH; ++ ++ default: ++ err = n_tty_ioctl(tty, file, cmd, arg); ++ break; ++ }; ++ ++ return err; ++} ++ ++/* ++ * We don't provide read/write/poll interface for user space. ++ */ ++static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr) ++{ ++ return 0; ++} ++static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) ++{ ++ return 0; ++} ++static unsigned int hci_uart_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait) ++{ ++ return 0; ++} ++ ++#ifdef CONFIG_BLUEZ_HCIUART_H4 ++int h4_init(void); ++int h4_deinit(void); ++#endif ++#ifdef CONFIG_BLUEZ_HCIUART_BCSP ++int bcsp_init(void); ++int bcsp_deinit(void); ++#endif ++ ++int __init hci_uart_init(void) ++{ ++ static struct tty_ldisc hci_uart_ldisc; ++ int err; ++ ++ BT_INFO("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", ++ VERSION); ++ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); ++ ++ /* Register the tty discipline */ ++ ++ memset(&hci_uart_ldisc, 0, sizeof (hci_uart_ldisc)); ++ hci_uart_ldisc.magic = TTY_LDISC_MAGIC; ++ hci_uart_ldisc.name = "n_hci"; ++ hci_uart_ldisc.open = hci_uart_tty_open; ++ hci_uart_ldisc.close = hci_uart_tty_close; ++ hci_uart_ldisc.read = hci_uart_tty_read; ++ hci_uart_ldisc.write = hci_uart_tty_write; ++ hci_uart_ldisc.ioctl = hci_uart_tty_ioctl; ++ hci_uart_ldisc.poll = hci_uart_tty_poll; ++ hci_uart_ldisc.receive_room= hci_uart_tty_room; ++ hci_uart_ldisc.receive_buf = hci_uart_tty_receive; ++ hci_uart_ldisc.write_wakeup= hci_uart_tty_wakeup; ++ ++ if ((err = tty_register_ldisc(N_HCI, &hci_uart_ldisc))) { ++ BT_ERR("Can't register HCI line discipline (%d)", err); ++ return err; ++ } ++ ++#ifdef CONFIG_BLUEZ_HCIUART_H4 ++ h4_init(); ++#endif ++#ifdef CONFIG_BLUEZ_HCIUART_BCSP ++ bcsp_init(); ++#endif ++ ++ return 0; ++} ++ ++void hci_uart_cleanup(void) ++{ ++ int err; ++ ++#ifdef CONFIG_BLUEZ_HCIUART_H4 ++ h4_deinit(); ++#endif ++#ifdef CONFIG_BLUEZ_HCIUART_BCSP ++ bcsp_deinit(); ++#endif ++ ++ /* Release tty registration of line discipline */ ++ if ((err = tty_register_ldisc(N_HCI, NULL))) ++ BT_ERR("Can't unregister HCI line discipline (%d)", err); ++} ++ ++module_init(hci_uart_init); ++module_exit(hci_uart_cleanup); ++ ++MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); ++MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION); ++MODULE_LICENSE("GPL"); +diff -urN linux-2.4.18/drivers/bluetooth/hci_uart.c linux-2.4.18-mh9/drivers/bluetooth/hci_uart.c +--- linux-2.4.18/drivers/bluetooth/hci_uart.c Fri Sep 7 18:28:38 2001 ++++ linux-2.4.18-mh9/drivers/bluetooth/hci_uart.c Thu Jan 1 01:00:00 1970 +@@ -1,580 +0,0 @@ +-/* +- BlueZ - Bluetooth protocol stack for Linux +- Copyright (C) 2000-2001 Qualcomm Incorporated +- +- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; +- +- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY +- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES +- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- +- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, +- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS +- SOFTWARE IS DISCLAIMED. +-*/ +- +-/* +- * BlueZ HCI UART driver. +- * +- * $Id$ +- */ +-#define VERSION "1.0" +- +-#include <linux/config.h> +-#include <linux/module.h> +- +-#include <linux/version.h> +-#include <linux/config.h> +-#include <linux/kernel.h> +-#include <linux/init.h> +-#include <linux/sched.h> +-#include <linux/types.h> +-#include <linux/fcntl.h> +-#include <linux/interrupt.h> +-#include <linux/ptrace.h> +-#include <linux/poll.h> +- +-#include <linux/slab.h> +-#include <linux/tty.h> +-#include <linux/errno.h> +-#include <linux/string.h> +-#include <linux/signal.h> +-#include <linux/ioctl.h> +-#include <linux/skbuff.h> +- +-#include <net/bluetooth/bluetooth.h> +-#include <net/bluetooth/bluez.h> +-#include <net/bluetooth/hci_core.h> +-#include <net/bluetooth/hci_uart.h> +- +-#ifndef HCI_UART_DEBUG +-#undef DBG +-#define DBG( A... ) +-#undef DMP +-#define DMP( A... ) +-#endif +- +-/* ------- Interface to HCI layer ------ */ +-/* Initialize device */ +-int n_hci_open(struct hci_dev *hdev) +-{ +- DBG("%s %p", hdev->name, hdev); +- +- /* Nothing to do for UART driver */ +- +- hdev->flags |= HCI_RUNNING; +- +- return 0; +-} +- +-/* Reset device */ +-int n_hci_flush(struct hci_dev *hdev) +-{ +- struct n_hci *n_hci = (struct n_hci *) hdev->driver_data; +- struct tty_struct *tty = n_hci->tty; +- +- DBG("hdev %p tty %p", hdev, tty); +- +- /* Drop TX queue */ +- skb_queue_purge(&n_hci->txq); +- +- /* Flush any pending characters in the driver and discipline. */ +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); +- +- if (tty->driver.flush_buffer) +- tty->driver.flush_buffer(tty); +- +- return 0; +-} +- +-/* Close device */ +-int n_hci_close(struct hci_dev *hdev) +-{ +- DBG("hdev %p", hdev); +- +- hdev->flags &= ~HCI_RUNNING; +- +- n_hci_flush(hdev); +- +- return 0; +-} +- +-int n_hci_tx_wakeup(struct n_hci *n_hci) +-{ +- register struct tty_struct *tty = n_hci->tty; +- +- if (test_and_set_bit(TRANS_SENDING, &n_hci->tx_state)) { +- set_bit(TRANS_WAKEUP, &n_hci->tx_state); +- return 0; +- } +- +- DBG(""); +- do { +- register struct sk_buff *skb; +- register int len; +- +- clear_bit(TRANS_WAKEUP, &n_hci->tx_state); +- +- if (!(skb = skb_dequeue(&n_hci->txq))) +- break; +- +- DMP(skb->data, skb->len); +- +- /* Send frame to TTY driver */ +- tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); +- len = tty->driver.write(tty, 0, skb->data, skb->len); +- +- n_hci->hdev.stat.byte_tx += len; +- +- DBG("sent %d", len); +- +- if (len == skb->len) { +- /* Full frame was sent */ +- kfree_skb(skb); +- } else { +- /* Subtract sent part and requeue */ +- skb_pull(skb, len); +- skb_queue_head(&n_hci->txq, skb); +- } +- } while (test_bit(TRANS_WAKEUP, &n_hci->tx_state)); +- clear_bit(TRANS_SENDING, &n_hci->tx_state); +- +- return 0; +-} +- +-/* Send frames from HCI layer */ +-int n_hci_send_frame(struct sk_buff *skb) +-{ +- struct hci_dev* hdev = (struct hci_dev *) skb->dev; +- struct tty_struct *tty; +- struct n_hci *n_hci; +- +- if (!hdev) { +- ERR("Frame for uknown device (hdev=NULL)"); +- return -ENODEV; +- } +- +- if (!(hdev->flags & HCI_RUNNING)) +- return -EBUSY; +- +- n_hci = (struct n_hci *) hdev->driver_data; +- tty = n_hci2tty(n_hci); +- +- DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len); +- +- switch (skb->pkt_type) { +- case HCI_COMMAND_PKT: +- hdev->stat.cmd_tx++; +- break; +- +- case HCI_ACLDATA_PKT: +- hdev->stat.acl_tx++; +- break; +- +- case HCI_SCODATA_PKT: +- hdev->stat.cmd_tx++; +- break; +- }; +- +- /* Prepend skb with frame type and queue */ +- memcpy(skb_push(skb, 1), &skb->pkt_type, 1); +- skb_queue_tail(&n_hci->txq, skb); +- +- n_hci_tx_wakeup(n_hci); +- +- return 0; +-} +- +-/* ------ LDISC part ------ */ +- +-/* n_hci_tty_open +- * +- * Called when line discipline changed to N_HCI. +- * +- * Arguments: +- * tty pointer to tty info structure +- * Return Value: +- * 0 if success, otherwise error code +- */ +-static int n_hci_tty_open(struct tty_struct *tty) +-{ +- struct n_hci *n_hci = tty2n_hci(tty); +- struct hci_dev *hdev; +- +- DBG("tty %p", tty); +- +- if (n_hci) +- return -EEXIST; +- +- if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) { +- ERR("Can't allocate controll structure"); +- return -ENFILE; +- } +- memset(n_hci, 0, sizeof(struct n_hci)); +- +- /* Initialize and register HCI device */ +- hdev = &n_hci->hdev; +- +- hdev->type = HCI_UART; +- hdev->driver_data = n_hci; +- +- hdev->open = n_hci_open; +- hdev->close = n_hci_close; +- hdev->flush = n_hci_flush; +- hdev->send = n_hci_send_frame; +- +- if (hci_register_dev(hdev) < 0) { +- ERR("Can't register HCI device %s", hdev->name); +- kfree(n_hci); +- return -ENODEV; +- } +- +- tty->disc_data = n_hci; +- n_hci->tty = tty; +- +- spin_lock_init(&n_hci->rx_lock); +- n_hci->rx_state = WAIT_PACKET_TYPE; +- +- skb_queue_head_init(&n_hci->txq); +- +- MOD_INC_USE_COUNT; +- +- /* Flush any pending characters in the driver and discipline. */ +- if (tty->ldisc.flush_buffer) +- tty->ldisc.flush_buffer(tty); +- +- if (tty->driver.flush_buffer) +- tty->driver.flush_buffer(tty); +- +- return 0; +-} +- +-/* n_hci_tty_close() +- * +- * Called when the line discipline is changed to something +- * else, the tty is closed, or the tty detects a hangup. +- */ +-static void n_hci_tty_close(struct tty_struct *tty) +-{ +- struct n_hci *n_hci = tty2n_hci(tty); +- struct hci_dev *hdev = &n_hci->hdev; +- +- DBG("tty %p hdev %p", tty, hdev); +- +- if (n_hci != NULL) { +- n_hci_close(hdev); +- +- if (hci_unregister_dev(hdev) < 0) { +- ERR("Can't unregister HCI device %s",hdev->name); +- } +- +- hdev->driver_data = NULL; +- tty->disc_data = NULL; +- kfree(n_hci); +- +- MOD_DEC_USE_COUNT; +- } +-} +- +-/* n_hci_tty_wakeup() +- * +- * Callback for transmit wakeup. Called when low level +- * device driver can accept more send data. +- * +- * Arguments: tty pointer to associated tty instance data +- * Return Value: None +- */ +-static void n_hci_tty_wakeup( struct tty_struct *tty ) +-{ +- struct n_hci *n_hci = tty2n_hci(tty); +- +- DBG(""); +- +- if (!n_hci) +- return; +- +- tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); +- +- if (tty != n_hci->tty) +- return; +- +- n_hci_tx_wakeup(n_hci); +-} +- +-/* n_hci_tty_room() +- * +- * Callback function from tty driver. Return the amount of +- * space left in the receiver's buffer to decide if remote +- * transmitter is to be throttled. +- * +- * Arguments: tty pointer to associated tty instance data +- * Return Value: number of bytes left in receive buffer +- */ +-static int n_hci_tty_room (struct tty_struct *tty) +-{ +- return 65536; +-} +- +-static inline int n_hci_check_data_len(struct n_hci *n_hci, int len) +-{ +- register int room = skb_tailroom(n_hci->rx_skb); +- +- DBG("len %d room %d", len, room); +- if (!len) { +- DMP(n_hci->rx_skb->data, n_hci->rx_skb->len); +- hci_recv_frame(n_hci->rx_skb); +- } else if (len > room) { +- ERR("Data length is to large"); +- kfree_skb(n_hci->rx_skb); +- n_hci->hdev.stat.err_rx++; +- } else { +- n_hci->rx_state = WAIT_DATA; +- n_hci->rx_count = len; +- return len; +- } +- +- n_hci->rx_state = WAIT_PACKET_TYPE; +- n_hci->rx_skb = NULL; +- n_hci->rx_count = 0; +- return 0; +-} +- +-static inline void n_hci_rx(struct n_hci *n_hci, const __u8 * data, char *flags, int count) +-{ +- register const char *ptr; +- hci_event_hdr *eh; +- hci_acl_hdr *ah; +- hci_sco_hdr *sh; +- register int len, type, dlen; +- +- DBG("count %d state %ld rx_count %ld", count, n_hci->rx_state, n_hci->rx_count); +- +- n_hci->hdev.stat.byte_rx += count; +- +- ptr = data; +- while (count) { +- if (n_hci->rx_count) { +- len = MIN(n_hci->rx_count, count); +- memcpy(skb_put(n_hci->rx_skb, len), ptr, len); +- n_hci->rx_count -= len; count -= len; ptr += len; +- +- if (n_hci->rx_count) +- continue; +- +- switch (n_hci->rx_state) { +- case WAIT_DATA: +- DBG("Complete data"); +- +- DMP(n_hci->rx_skb->data, n_hci->rx_skb->len); +- +- hci_recv_frame(n_hci->rx_skb); +- +- n_hci->rx_state = WAIT_PACKET_TYPE; +- n_hci->rx_skb = NULL; +- continue; +- +- case WAIT_EVENT_HDR: +- eh = (hci_event_hdr *) n_hci->rx_skb->data; +- +- DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen); +- +- n_hci_check_data_len(n_hci, eh->plen); +- continue; +- +- case WAIT_ACL_HDR: +- ah = (hci_acl_hdr *) n_hci->rx_skb->data; +- dlen = __le16_to_cpu(ah->dlen); +- +- DBG("ACL header: dlen %d", dlen); +- +- n_hci_check_data_len(n_hci, dlen); +- continue; +- +- case WAIT_SCO_HDR: +- sh = (hci_sco_hdr *) n_hci->rx_skb->data; +- +- DBG("SCO header: dlen %d", sh->dlen); +- +- n_hci_check_data_len(n_hci, sh->dlen); +- continue; +- }; +- } +- +- /* WAIT_PACKET_TYPE */ +- switch (*ptr) { +- case HCI_EVENT_PKT: +- DBG("Event packet"); +- n_hci->rx_state = WAIT_EVENT_HDR; +- n_hci->rx_count = HCI_EVENT_HDR_SIZE; +- type = HCI_EVENT_PKT; +- break; +- +- case HCI_ACLDATA_PKT: +- DBG("ACL packet"); +- n_hci->rx_state = WAIT_ACL_HDR; +- n_hci->rx_count = HCI_ACL_HDR_SIZE; +- type = HCI_ACLDATA_PKT; +- break; +- +- case HCI_SCODATA_PKT: +- DBG("SCO packet"); +- n_hci->rx_state = WAIT_SCO_HDR; +- n_hci->rx_count = HCI_SCO_HDR_SIZE; +- type = HCI_SCODATA_PKT; +- break; +- +- default: +- ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); +- n_hci->hdev.stat.err_rx++; +- ptr++; count--; +- continue; +- }; +- ptr++; count--; +- +- /* Allocate packet */ +- if (!(n_hci->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { +- ERR("Can't allocate mem for new packet"); +- +- n_hci->rx_state = WAIT_PACKET_TYPE; +- n_hci->rx_count = 0; +- return; +- } +- n_hci->rx_skb->dev = (void *) &n_hci->hdev; +- n_hci->rx_skb->pkt_type = type; +- } +-} +- +-/* n_hci_tty_receive() +- * +- * Called by tty low level driver when receive data is +- * available. +- * +- * Arguments: tty pointer to tty isntance data +- * data pointer to received data +- * flags pointer to flags for data +- * count count of received data in bytes +- * +- * Return Value: None +- */ +-static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count) +-{ +- struct n_hci *n_hci = tty2n_hci(tty); +- +- if (!n_hci || tty != n_hci->tty) +- return; +- +- spin_lock(&n_hci->rx_lock); +- n_hci_rx(n_hci, data, flags, count); +- spin_unlock(&n_hci->rx_lock); +- +- if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle) +- tty->driver.unthrottle(tty); +-} +- +-/* n_hci_tty_ioctl() +- * +- * Process IOCTL system call for the tty device. +- * +- * Arguments: +- * +- * tty pointer to tty instance data +- * file pointer to open file object for device +- * cmd IOCTL command code +- * arg argument for IOCTL call (cmd dependent) +- * +- * Return Value: Command dependent +- */ +-static int n_hci_tty_ioctl (struct tty_struct *tty, struct file * file, +- unsigned int cmd, unsigned long arg) +-{ +- struct n_hci *n_hci = tty2n_hci(tty); +- int error = 0; +- +- DBG(""); +- +- /* Verify the status of the device */ +- if (!n_hci) +- return -EBADF; +- +- switch (cmd) { +- default: +- error = n_tty_ioctl(tty, file, cmd, arg); +- break; +- }; +- +- return error; +-} +- +-/* +- * We don't provide read/write/poll interface for user space. +- */ +-static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr) +-{ +- return 0; +-} +-static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) +-{ +- return 0; +-} +-static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait) +-{ +- return 0; +-} +- +-int __init n_hci_init(void) +-{ +- static struct tty_ldisc n_hci_ldisc; +- int err; +- +- INF("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", +- VERSION); +- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); +- +- /* Register the tty discipline */ +- +- memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc)); +- n_hci_ldisc.magic = TTY_LDISC_MAGIC; +- n_hci_ldisc.name = "n_hci"; +- n_hci_ldisc.open = n_hci_tty_open; +- n_hci_ldisc.close = n_hci_tty_close; +- n_hci_ldisc.read = n_hci_tty_read; +- n_hci_ldisc.write = n_hci_tty_write; +- n_hci_ldisc.ioctl = n_hci_tty_ioctl; +- n_hci_ldisc.poll = n_hci_tty_poll; +- n_hci_ldisc.receive_room= n_hci_tty_room; +- n_hci_ldisc.receive_buf = n_hci_tty_receive; +- n_hci_ldisc.write_wakeup= n_hci_tty_wakeup; +- +- if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) { +- ERR("Can't register HCI line discipline (%d)", err); +- return err; +- } +- +- return 0; +-} +- +-void n_hci_cleanup(void) +-{ +- int err; +- +- /* Release tty registration of line discipline */ +- if ((err = tty_register_ldisc(N_HCI, NULL))) +- ERR("Can't unregister HCI line discipline (%d)", err); +-} +- +-module_init(n_hci_init); +-module_exit(n_hci_cleanup); +- +-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); +-MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION); +-MODULE_LICENSE("GPL"); +diff -urN linux-2.4.18/drivers/bluetooth/hci_uart.h linux-2.4.18-mh9/drivers/bluetooth/hci_uart.h +--- linux-2.4.18/drivers/bluetooth/hci_uart.h Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/drivers/bluetooth/hci_uart.h Mon Aug 25 18:38:10 2003 +@@ -0,0 +1,81 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#ifndef N_HCI ++#define N_HCI 15 ++#endif ++ ++/* Ioctls */ ++#define HCIUARTSETPROTO _IOW('U', 200, int) ++#define HCIUARTGETPROTO _IOR('U', 201, int) ++ ++/* UART protocols */ ++#define HCI_UART_MAX_PROTO 3 ++ ++#define HCI_UART_H4 0 ++#define HCI_UART_BCSP 1 ++#define HCI_UART_NCSP 2 ++ ++#ifdef __KERNEL__ ++struct hci_uart; ++ ++struct hci_uart_proto { ++ unsigned int id; ++ int (*open)(struct hci_uart *hu); ++ int (*close)(struct hci_uart *hu); ++ int (*flush)(struct hci_uart *hu); ++ int (*recv)(struct hci_uart *hu, void *data, int len); ++ int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb); ++ struct sk_buff *(*dequeue)(struct hci_uart *hu); ++}; ++ ++struct hci_uart { ++ struct tty_struct *tty; ++ struct hci_dev hdev; ++ unsigned long flags; ++ ++ struct hci_uart_proto *proto; ++ void *priv; ++ ++ struct sk_buff *tx_skb; ++ unsigned long tx_state; ++ spinlock_t rx_lock; ++}; ++ ++/* HCI_UART flag bits */ ++#define HCI_UART_PROTO_SET 0 ++ ++/* TX states */ ++#define HCI_UART_SENDING 1 ++#define HCI_UART_TX_WAKEUP 2 ++ ++int hci_uart_register_proto(struct hci_uart_proto *p); ++int hci_uart_unregister_proto(struct hci_uart_proto *p); ++int hci_uart_tx_wakeup(struct hci_uart *hu); ++ ++#endif /* __KERNEL__ */ +diff -urN linux-2.4.18/drivers/bluetooth/hci_usb.c linux-2.4.18-mh9/drivers/bluetooth/hci_usb.c +--- linux-2.4.18/drivers/bluetooth/hci_usb.c Fri Sep 7 18:28:38 2001 ++++ linux-2.4.18-mh9/drivers/bluetooth/hci_usb.c Mon Aug 25 18:38:12 2003 +@@ -1,9 +1,10 @@ + /* +- BlueZ - Bluetooth protocol stack for Linux ++ HCI USB driver for Linux Bluetooth protocol stack (BlueZ) + Copyright (C) 2000-2001 Qualcomm Incorporated +- + Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> + ++ Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.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; +@@ -23,598 +24,901 @@ + */ + + /* +- * BlueZ HCI USB driver. + * Based on original USB Bluetooth driver for Linux kernel + * Copyright (c) 2000 Greg Kroah-Hartman <greg@kroah.com> + * Copyright (c) 2000 Mark Douglas Corner <mcorner@umich.edu> + * +- * $Id$ ++ * $Id$ + */ +-#define VERSION "1.0" ++#define VERSION "2.4" + + #include <linux/config.h> + #include <linux/module.h> + + #include <linux/version.h> +-#include <linux/config.h> + #include <linux/kernel.h> + #include <linux/init.h> + #include <linux/sched.h> ++#include <linux/unistd.h> + #include <linux/types.h> +-#include <linux/fcntl.h> + #include <linux/interrupt.h> +-#include <linux/ptrace.h> +-#include <linux/poll.h> + + #include <linux/slab.h> +-#include <linux/tty.h> + #include <linux/errno.h> + #include <linux/string.h> +-#include <linux/signal.h> +-#include <linux/ioctl.h> + #include <linux/skbuff.h> + + #include <linux/usb.h> + + #include <net/bluetooth/bluetooth.h> +-#include <net/bluetooth/bluez.h> + #include <net/bluetooth/hci_core.h> +-#include <net/bluetooth/hci_usb.h> ++ ++#include "hci_usb.h" + + #ifndef HCI_USB_DEBUG +-#undef DBG +-#define DBG( A... ) +-#undef DMP +-#define DMP( A... ) ++#undef BT_DBG ++#define BT_DBG( A... ) ++#undef BT_DMP ++#define BT_DMP( A... ) + #endif + +-static struct usb_device_id usb_bluetooth_ids [] = { ++#ifndef CONFIG_BLUEZ_USB_ZERO_PACKET ++#undef USB_ZERO_PACKET ++#define USB_ZERO_PACKET 0 ++#endif ++ ++static struct usb_driver hci_usb_driver; ++ ++static struct usb_device_id bluetooth_ids[] = { ++ /* Generic Bluetooth USB device */ + { USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) }, ++ ++ /* Ericsson with non-standard id */ ++ { USB_DEVICE(0x0bdb, 0x1002) }, ++ ++ /* Bluetooth Ultraport Module from IBM */ ++ { USB_DEVICE(0x04bf, 0x030a) }, ++ + { } /* Terminating entry */ + }; + +-MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids); ++MODULE_DEVICE_TABLE (usb, bluetooth_ids); + +-static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb); +-static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb); ++static struct usb_device_id ignore_ids[] = { ++ /* Broadcom BCM2033 without firmware */ ++ { USB_DEVICE(0x0a5c, 0x2033) }, + +-static void hci_usb_unlink_urbs(struct hci_usb *husb) +-{ +- usb_unlink_urb(husb->read_urb); +- usb_unlink_urb(husb->intr_urb); +- usb_unlink_urb(husb->ctrl_urb); +- usb_unlink_urb(husb->write_urb); +-} ++ { } /* Terminating entry */ ++}; + +-static void hci_usb_free_bufs(struct hci_usb *husb) ++struct _urb *_urb_alloc(int isoc, int gfp) + { +- if (husb->read_urb) { +- if (husb->read_urb->transfer_buffer) +- kfree(husb->read_urb->transfer_buffer); +- usb_free_urb(husb->read_urb); +- } +- +- if (husb->intr_urb) { +- if (husb->intr_urb->transfer_buffer) +- kfree(husb->intr_urb->transfer_buffer); +- usb_free_urb(husb->intr_urb); ++ struct _urb *_urb = kmalloc(sizeof(struct _urb) + ++ sizeof(iso_packet_descriptor_t) * isoc, gfp); ++ if (_urb) { ++ memset(_urb, 0, sizeof(*_urb)); ++ spin_lock_init(&_urb->urb.lock); ++ } ++ return _urb; ++} ++ ++struct _urb *_urb_dequeue(struct _urb_queue *q) ++{ ++ struct _urb *_urb = NULL; ++ unsigned long flags; ++ spin_lock_irqsave(&q->lock, flags); ++ { ++ struct list_head *head = &q->head; ++ struct list_head *next = head->next; ++ if (next != head) { ++ _urb = list_entry(next, struct _urb, list); ++ list_del(next); _urb->queue = NULL; ++ } + } ++ spin_unlock_irqrestore(&q->lock, flags); ++ return _urb; ++} + +- if (husb->ctrl_urb) +- usb_free_urb(husb->ctrl_urb); ++static void hci_usb_rx_complete(struct urb *urb); ++static void hci_usb_tx_complete(struct urb *urb); + +- if (husb->write_urb) +- usb_free_urb(husb->write_urb); ++#define __pending_tx(husb, type) (&husb->pending_tx[type-1]) ++#define __pending_q(husb, type) (&husb->pending_q[type-1]) ++#define __completed_q(husb, type) (&husb->completed_q[type-1]) ++#define __transmit_q(husb, type) (&husb->transmit_q[type-1]) ++#define __reassembly(husb, type) (husb->reassembly[type-1]) + +- if (husb->intr_skb) +- kfree_skb(husb->intr_skb); ++static inline struct _urb *__get_completed(struct hci_usb *husb, int type) ++{ ++ return _urb_dequeue(__completed_q(husb, type)); + } + +-/* ------- Interface to HCI layer ------ */ +-/* Initialize device */ +-int hci_usb_open(struct hci_dev *hdev) ++static void __fill_isoc_desc(struct urb *urb, int len, int mtu) + { +- struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; +- int status; +- +- DBG("%s", hdev->name); +- +- husb->read_urb->dev = husb->udev; +- if ((status = usb_submit_urb(husb->read_urb))) +- DBG("read submit failed. %d", status); ++ int offset = 0, i; + +- husb->intr_urb->dev = husb->udev; +- if ((status = usb_submit_urb(husb->intr_urb))) +- DBG("interrupt submit failed. %d", status); ++ BT_DBG("len %d mtu %d", len, mtu); + +- hdev->flags |= HCI_RUNNING; +- +- return 0; ++ for (i=0; i < HCI_MAX_ISOC_FRAMES && len >= mtu; i++, offset += mtu, len -= mtu) { ++ urb->iso_frame_desc[i].offset = offset; ++ urb->iso_frame_desc[i].length = mtu; ++ BT_DBG("desc %d offset %d len %d", i, offset, mtu); ++ } ++ if (len && i < HCI_MAX_ISOC_FRAMES) { ++ urb->iso_frame_desc[i].offset = offset; ++ urb->iso_frame_desc[i].length = len; ++ BT_DBG("desc %d offset %d len %d", i, offset, len); ++ i++; ++ } ++ urb->number_of_packets = i; + } + +-/* Reset device */ +-int hci_usb_flush(struct hci_dev *hdev) ++static int hci_usb_intr_rx_submit(struct hci_usb *husb) + { +- struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; ++ struct _urb *_urb; ++ struct urb *urb; ++ int err, pipe, interval, size; ++ void *buf; + +- DBG("%s", hdev->name); ++ BT_DBG("%s", husb->hdev.name); + +- /* Drop TX queues */ +- skb_queue_purge(&husb->tx_ctrl_q); +- skb_queue_purge(&husb->tx_write_q); ++ size = husb->intr_in_ep->wMaxPacketSize; + +- return 0; ++ buf = kmalloc(size, GFP_ATOMIC); ++ if (!buf) ++ return -ENOMEM; ++ ++ _urb = _urb_alloc(0, GFP_ATOMIC); ++ if (!_urb) { ++ kfree(buf); ++ return -ENOMEM; ++ } ++ _urb->type = HCI_EVENT_PKT; ++ _urb_queue_tail(__pending_q(husb, _urb->type), _urb); ++ ++ urb = &_urb->urb; ++ pipe = usb_rcvintpipe(husb->udev, husb->intr_in_ep->bEndpointAddress); ++ interval = husb->intr_in_ep->bInterval; ++ FILL_INT_URB(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb, interval); ++ ++ err = usb_submit_urb(urb); ++ if (err) { ++ BT_ERR("%s intr rx submit failed urb %p err %d", ++ husb->hdev.name, urb, err); ++ _urb_unlink(_urb); ++ _urb_free(_urb); ++ kfree(buf); ++ } ++ return err; + } + +-/* Close device */ +-int hci_usb_close(struct hci_dev *hdev) ++static int hci_usb_bulk_rx_submit(struct hci_usb *husb) + { +- struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; ++ struct _urb *_urb; ++ struct urb *urb; ++ int err, pipe, size = HCI_MAX_FRAME_SIZE; ++ void *buf; + +- DBG("%s", hdev->name); ++ buf = kmalloc(size, GFP_ATOMIC); ++ if (!buf) ++ return -ENOMEM; + +- hdev->flags &= ~HCI_RUNNING; +- hci_usb_unlink_urbs(husb); ++ _urb = _urb_alloc(0, GFP_ATOMIC); ++ if (!_urb) { ++ kfree(buf); ++ return -ENOMEM; ++ } ++ _urb->type = HCI_ACLDATA_PKT; ++ _urb_queue_tail(__pending_q(husb, _urb->type), _urb); + +- hci_usb_flush(hdev); ++ urb = &_urb->urb; ++ pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep->bEndpointAddress); ++ FILL_BULK_URB(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb); ++ urb->transfer_flags = USB_QUEUE_BULK; + +- return 0; ++ BT_DBG("%s urb %p", husb->hdev.name, urb); ++ ++ err = usb_submit_urb(urb); ++ if (err) { ++ BT_ERR("%s bulk rx submit failed urb %p err %d", ++ husb->hdev.name, urb, err); ++ _urb_unlink(_urb); ++ _urb_free(_urb); ++ kfree(buf); ++ } ++ return err; + } + +-void hci_usb_ctrl_wakeup(struct hci_usb *husb) ++#ifdef CONFIG_BLUEZ_USB_SCO ++static int hci_usb_isoc_rx_submit(struct hci_usb *husb) + { +- struct sk_buff *skb; +- +- if (test_and_set_bit(HCI_TX_CTRL, &husb->tx_state)) +- return; ++ struct _urb *_urb; ++ struct urb *urb; ++ int err, mtu, size; ++ void *buf; + +- DBG("%s", husb->hdev.name); ++ mtu = husb->isoc_in_ep->wMaxPacketSize; ++ size = mtu * HCI_MAX_ISOC_FRAMES; + +- if (!(skb = skb_dequeue(&husb->tx_ctrl_q))) +- goto done; ++ buf = kmalloc(size, GFP_ATOMIC); ++ if (!buf) ++ return -ENOMEM; + +- if (hci_usb_ctrl_msg(husb, skb)){ +- kfree_skb(skb); +- goto done; ++ _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC); ++ if (!_urb) { ++ kfree(buf); ++ return -ENOMEM; + } ++ _urb->type = HCI_SCODATA_PKT; ++ _urb_queue_tail(__pending_q(husb, _urb->type), _urb); + +- DMP(skb->data, skb->len); ++ urb = &_urb->urb; + +- husb->hdev.stat.byte_tx += skb->len; +- return; ++ urb->context = husb; ++ urb->dev = husb->udev; ++ urb->pipe = usb_rcvisocpipe(husb->udev, husb->isoc_in_ep->bEndpointAddress); ++ urb->complete = hci_usb_rx_complete; + +-done: +- clear_bit(HCI_TX_CTRL, &husb->tx_state); +- return; ++ urb->transfer_buffer_length = size; ++ urb->transfer_buffer = buf; ++ urb->transfer_flags = USB_ISO_ASAP; ++ ++ __fill_isoc_desc(urb, size, mtu); ++ ++ BT_DBG("%s urb %p", husb->hdev.name, urb); ++ ++ err = usb_submit_urb(urb); ++ if (err) { ++ BT_ERR("%s isoc rx submit failed urb %p err %d", ++ husb->hdev.name, urb, err); ++ _urb_unlink(_urb); ++ _urb_free(_urb); ++ kfree(buf); ++ } ++ return err; + } ++#endif + +-void hci_usb_write_wakeup(struct hci_usb *husb) ++/* Initialize device */ ++static int hci_usb_open(struct hci_dev *hdev) + { +- struct sk_buff *skb; ++ struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; ++ int i, err; ++ unsigned long flags; + +- if (test_and_set_bit(HCI_TX_WRITE, &husb->tx_state)) +- return; ++ BT_DBG("%s", hdev->name); + +- DBG("%s", husb->hdev.name); ++ if (test_and_set_bit(HCI_RUNNING, &hdev->flags)) ++ return 0; + +- if (!(skb = skb_dequeue(&husb->tx_write_q))) +- goto done; ++ MOD_INC_USE_COUNT; + +- if (hci_usb_write_msg(husb, skb)) { +- skb_queue_head(&husb->tx_write_q, skb); +- goto done; ++ write_lock_irqsave(&husb->completion_lock, flags); ++ ++ err = hci_usb_intr_rx_submit(husb); ++ if (!err) { ++ for (i = 0; i < HCI_MAX_BULK_RX; i++) ++ hci_usb_bulk_rx_submit(husb); ++ ++#ifdef CONFIG_BLUEZ_USB_SCO ++ if (husb->isoc_iface) ++ for (i = 0; i < HCI_MAX_ISOC_RX; i++) ++ hci_usb_isoc_rx_submit(husb); ++#endif ++ } else { ++ clear_bit(HCI_RUNNING, &hdev->flags); ++ MOD_DEC_USE_COUNT; + } + +- DMP(skb->data, skb->len); ++ write_unlock_irqrestore(&husb->completion_lock, flags); ++ return err; ++} ++ ++/* Reset device */ ++static int hci_usb_flush(struct hci_dev *hdev) ++{ ++ struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; ++ int i; + +- husb->hdev.stat.byte_tx += skb->len; +- return; ++ BT_DBG("%s", hdev->name); + +-done: +- clear_bit(HCI_TX_WRITE, &husb->tx_state); +- return; ++ for (i=0; i < 4; i++) ++ skb_queue_purge(&husb->transmit_q[i]); ++ return 0; + } + +-/* Send frames from HCI layer */ +-int hci_usb_send_frame(struct sk_buff *skb) ++static void hci_usb_unlink_urbs(struct hci_usb *husb) + { +- struct hci_dev *hdev = (struct hci_dev *) skb->dev; +- struct hci_usb *husb; ++ int i; + +- if (!hdev) { +- ERR("frame for uknown device (hdev=NULL)"); +- return -ENODEV; ++ BT_DBG("%s", husb->hdev.name); ++ ++ for (i=0; i < 4; i++) { ++ struct _urb *_urb; ++ struct urb *urb; ++ ++ /* Kill pending requests */ ++ while ((_urb = _urb_dequeue(&husb->pending_q[i]))) { ++ urb = &_urb->urb; ++ BT_DBG("%s unlinking _urb %p type %d urb %p", ++ husb->hdev.name, _urb, _urb->type, urb); ++ usb_unlink_urb(urb); ++ _urb_queue_tail(__completed_q(husb, _urb->type), _urb); ++ } ++ ++ /* Release completed requests */ ++ while ((_urb = _urb_dequeue(&husb->completed_q[i]))) { ++ urb = &_urb->urb; ++ BT_DBG("%s freeing _urb %p type %d urb %p", ++ husb->hdev.name, _urb, _urb->type, urb); ++ if (urb->setup_packet) ++ kfree(urb->setup_packet); ++ if (urb->transfer_buffer) ++ kfree(urb->transfer_buffer); ++ _urb_free(_urb); ++ } ++ ++ /* Release reassembly buffers */ ++ if (husb->reassembly[i]) { ++ kfree_skb(husb->reassembly[i]); ++ husb->reassembly[i] = NULL; ++ } + } ++} + +- if (!(hdev->flags & HCI_RUNNING)) ++/* Close device */ ++static int hci_usb_close(struct hci_dev *hdev) ++{ ++ struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; ++ unsigned long flags; ++ ++ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) + return 0; + +- husb = (struct hci_usb *) hdev->driver_data; ++ BT_DBG("%s", hdev->name); + +- DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); ++ write_lock_irqsave(&husb->completion_lock, flags); ++ ++ hci_usb_unlink_urbs(husb); ++ hci_usb_flush(hdev); + +- switch (skb->pkt_type) { +- case HCI_COMMAND_PKT: +- skb_queue_tail(&husb->tx_ctrl_q, skb); +- hci_usb_ctrl_wakeup(husb); +- hdev->stat.cmd_tx++; +- return 0; +- +- case HCI_ACLDATA_PKT: +- skb_queue_tail(&husb->tx_write_q, skb); +- hci_usb_write_wakeup(husb); +- hdev->stat.acl_tx++; +- return 0; +- +- case HCI_SCODATA_PKT: +- return -EOPNOTSUPP; +- }; ++ write_unlock_irqrestore(&husb->completion_lock, flags); + ++ MOD_DEC_USE_COUNT; + return 0; + } + +-/* ---------- USB ------------- */ +- +-static void hci_usb_ctrl(struct urb *urb) ++static int __tx_submit(struct hci_usb *husb, struct _urb *_urb) + { +- struct sk_buff *skb = (struct sk_buff *) urb->context; +- struct hci_dev *hdev; +- struct hci_usb *husb; +- +- if (!skb) +- return; +- hdev = (struct hci_dev *) skb->dev; +- husb = (struct hci_usb *) hdev->driver_data; ++ struct urb *urb = &_urb->urb; ++ int err; + +- DBG("%s", hdev->name); ++ BT_DBG("%s urb %p type %d", husb->hdev.name, urb, _urb->type); ++ ++ _urb_queue_tail(__pending_q(husb, _urb->type), _urb); ++ err = usb_submit_urb(urb); ++ if (err) { ++ BT_ERR("%s tx submit failed urb %p type %d err %d", ++ husb->hdev.name, urb, _urb->type, err); ++ _urb_unlink(_urb); ++ _urb_queue_tail(__completed_q(husb, _urb->type), _urb); ++ } else ++ atomic_inc(__pending_tx(husb, _urb->type)); ++ ++ return err; ++} ++ ++static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb) ++{ ++ struct _urb *_urb = __get_completed(husb, skb->pkt_type); ++ devrequest *dr; ++ struct urb *urb; ++ ++ if (!_urb) { ++ _urb = _urb_alloc(0, GFP_ATOMIC); ++ if (!_urb) ++ return -ENOMEM; ++ _urb->type = skb->pkt_type; ++ ++ dr = kmalloc(sizeof(*dr), GFP_ATOMIC); ++ if (!dr) { ++ _urb_free(_urb); ++ return -ENOMEM; ++ } ++ } else ++ dr = (void *) _urb->urb.setup_packet; + +- if (urb->status) +- DBG("%s ctrl status: %d", hdev->name, urb->status); ++ dr->requesttype = HCI_CTRL_REQ; ++ dr->request = 0; ++ dr->index = 0; ++ dr->value = 0; ++ dr->length = __cpu_to_le16(skb->len); + +- clear_bit(HCI_TX_CTRL, &husb->tx_state); +- kfree_skb(skb); ++ urb = &_urb->urb; ++ FILL_CONTROL_URB(urb, husb->udev, usb_sndctrlpipe(husb->udev, 0), ++ (void *) dr, skb->data, skb->len, hci_usb_tx_complete, husb); + +- /* Wake up device */ +- hci_usb_ctrl_wakeup(husb); ++ BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len); ++ ++ _urb->priv = skb; ++ return __tx_submit(husb, _urb); + } + +-static void hci_usb_bulk_write(struct urb *urb) ++static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb) + { +- struct sk_buff *skb = (struct sk_buff *) urb->context; +- struct hci_dev *hdev; +- struct hci_usb *husb; +- +- if (!skb) +- return; +- hdev = (struct hci_dev *) skb->dev; +- husb = (struct hci_usb *) hdev->driver_data; ++ struct _urb *_urb = __get_completed(husb, skb->pkt_type); ++ struct urb *urb; ++ int pipe; + +- DBG("%s", hdev->name); +- +- if (urb->status) +- DBG("%s bulk write status: %d", hdev->name, urb->status); ++ if (!_urb) { ++ _urb = _urb_alloc(0, GFP_ATOMIC); ++ if (!_urb) ++ return -ENOMEM; ++ _urb->type = skb->pkt_type; ++ } + +- clear_bit(HCI_TX_WRITE, &husb->tx_state); +- kfree_skb(skb); ++ urb = &_urb->urb; ++ pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep->bEndpointAddress); ++ FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len, ++ hci_usb_tx_complete, husb); ++ urb->transfer_flags = USB_QUEUE_BULK | USB_ZERO_PACKET; + +- /* Wake up device */ +- hci_usb_write_wakeup(husb); ++ BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len); + +- return; ++ _urb->priv = skb; ++ return __tx_submit(husb, _urb); + } + +-static void hci_usb_intr(struct urb *urb) ++#ifdef CONFIG_BLUEZ_USB_SCO ++static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb) + { +- struct hci_usb *husb = (struct hci_usb *) urb->context; +- unsigned char *data = urb->transfer_buffer; +- register int count = urb->actual_length; +- register struct sk_buff *skb = husb->intr_skb; +- hci_event_hdr *eh; +- register int len; ++ struct _urb *_urb = __get_completed(husb, skb->pkt_type); ++ struct urb *urb; ++ ++ if (!_urb) { ++ _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC); ++ if (!_urb) ++ return -ENOMEM; ++ _urb->type = skb->pkt_type; ++ } + +- if (!husb) +- return; ++ BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len); + +- DBG("%s count %d", husb->hdev.name, count); ++ urb = &_urb->urb; ++ ++ urb->context = husb; ++ urb->dev = husb->udev; ++ urb->pipe = usb_sndisocpipe(husb->udev, husb->isoc_out_ep->bEndpointAddress); ++ urb->complete = hci_usb_tx_complete; ++ urb->transfer_flags = USB_ISO_ASAP; + +- if (urb->status || !count) { +- DBG("%s intr status %d, count %d", husb->hdev.name, urb->status, count); +- return; +- } ++ urb->transfer_buffer = skb->data; ++ urb->transfer_buffer_length = skb->len; ++ ++ __fill_isoc_desc(urb, skb->len, husb->isoc_out_ep->wMaxPacketSize); + +- /* Do we really have to handle continuations here ? */ +- if (!skb) { +- /* New frame */ +- if (count < HCI_EVENT_HDR_SIZE) { +- DBG("%s bad frame len %d", husb->hdev.name, count); +- return; +- } ++ _urb->priv = skb; ++ return __tx_submit(husb, _urb); ++} ++#endif ++ ++static void hci_usb_tx_process(struct hci_usb *husb) ++{ ++ struct sk_buff_head *q; ++ struct sk_buff *skb; + +- eh = (hci_event_hdr *) data; +- len = eh->plen + HCI_EVENT_HDR_SIZE; ++ BT_DBG("%s", husb->hdev.name); + +- if (count > len) { +- DBG("%s corrupted frame, len %d", husb->hdev.name, count); +- return; ++ do { ++ clear_bit(HCI_USB_TX_WAKEUP, &husb->state); ++ ++ /* Process command queue */ ++ q = __transmit_q(husb, HCI_COMMAND_PKT); ++ if (!atomic_read(__pending_tx(husb, HCI_COMMAND_PKT)) && ++ (skb = skb_dequeue(q))) { ++ if (hci_usb_send_ctrl(husb, skb) < 0) ++ skb_queue_head(q, skb); + } + +- /* Allocate skb */ +- if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) { +- ERR("Can't allocate mem for new packet"); +- return; ++#ifdef CONFIG_BLUEZ_USB_SCO ++ /* Process SCO queue */ ++ q = __transmit_q(husb, HCI_SCODATA_PKT); ++ if (atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) < HCI_MAX_ISOC_TX && ++ (skb = skb_dequeue(q))) { ++ if (hci_usb_send_isoc(husb, skb) < 0) ++ skb_queue_head(q, skb); ++ } ++#endif ++ ++ /* Process ACL queue */ ++ q = __transmit_q(husb, HCI_ACLDATA_PKT); ++ while (atomic_read(__pending_tx(husb, HCI_ACLDATA_PKT)) < HCI_MAX_BULK_TX && ++ (skb = skb_dequeue(q))) { ++ if (hci_usb_send_bulk(husb, skb) < 0) { ++ skb_queue_head(q, skb); ++ break; ++ } + } +- skb->dev = (void *) &husb->hdev; +- skb->pkt_type = HCI_EVENT_PKT; ++ } while(test_bit(HCI_USB_TX_WAKEUP, &husb->state)); ++} + +- husb->intr_skb = skb; +- husb->intr_count = len; +- } else { +- /* Continuation */ +- if (count > husb->intr_count) { +- ERR("%s bad frame len %d (expected %d)", husb->hdev.name, count, husb->intr_count); ++static inline void hci_usb_tx_wakeup(struct hci_usb *husb) ++{ ++ /* Serialize TX queue processing to avoid data reordering */ ++ if (!test_and_set_bit(HCI_USB_TX_PROCESS, &husb->state)) { ++ hci_usb_tx_process(husb); ++ clear_bit(HCI_USB_TX_PROCESS, &husb->state); ++ } else ++ set_bit(HCI_USB_TX_WAKEUP, &husb->state); ++} + +- kfree_skb(skb); +- husb->intr_skb = NULL; +- husb->intr_count = 0; +- return; +- } ++/* Send frames from HCI layer */ ++static int hci_usb_send_frame(struct sk_buff *skb) ++{ ++ struct hci_dev *hdev = (struct hci_dev *) skb->dev; ++ struct hci_usb *husb; ++ ++ if (!hdev) { ++ BT_ERR("frame for uknown device (hdev=NULL)"); ++ return -ENODEV; + } + +- memcpy(skb_put(skb, count), data, count); +- husb->intr_count -= count; ++ if (!test_bit(HCI_RUNNING, &hdev->flags)) ++ return -EBUSY; + +- DMP(data, count); ++ BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); + +- if (!husb->intr_count) { +- /* Got complete frame */ ++ husb = (struct hci_usb *) hdev->driver_data; + +- husb->hdev.stat.byte_rx += skb->len; +- hci_recv_frame(skb); ++ switch (skb->pkt_type) { ++ case HCI_COMMAND_PKT: ++ hdev->stat.cmd_tx++; ++ break; ++ ++ case HCI_ACLDATA_PKT: ++ hdev->stat.acl_tx++; ++ break; ++ ++#ifdef CONFIG_BLUEZ_USB_SCO ++ case HCI_SCODATA_PKT: ++ hdev->stat.sco_tx++; ++ break; ++#endif + +- husb->intr_skb = NULL; ++ default: ++ kfree_skb(skb); ++ return 0; + } ++ ++ read_lock(&husb->completion_lock); ++ ++ skb_queue_tail(__transmit_q(husb, skb->pkt_type), skb); ++ hci_usb_tx_wakeup(husb); ++ ++ read_unlock(&husb->completion_lock); ++ return 0; + } + +-static void hci_usb_bulk_read(struct urb *urb) ++static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int count) + { +- struct hci_usb *husb = (struct hci_usb *) urb->context; +- unsigned char *data = urb->transfer_buffer; +- int count = urb->actual_length, status; +- struct sk_buff *skb; +- hci_acl_hdr *ah; +- register __u16 dlen; +- +- if (!husb) +- return; ++ BT_DBG("%s type %d data %p count %d", husb->hdev.name, type, data, count); + +- DBG("%s status %d, count %d, flags %x", husb->hdev.name, urb->status, count, urb->transfer_flags); ++ husb->hdev.stat.byte_rx += count; + +- if (urb->status) { +- /* Do not re-submit URB on critical errors */ +- switch (urb->status) { +- case -ENOENT: +- return; +- default: +- goto resubmit; +- }; +- } +- if (!count) +- goto resubmit; ++ while (count) { ++ struct sk_buff *skb = __reassembly(husb, type); ++ struct { int expect; } *scb; ++ int len = 0; ++ ++ if (!skb) { ++ /* Start of the frame */ ++ ++ switch (type) { ++ case HCI_EVENT_PKT: ++ if (count >= HCI_EVENT_HDR_SIZE) { ++ hci_event_hdr *h = data; ++ len = HCI_EVENT_HDR_SIZE + h->plen; ++ } else ++ return -EILSEQ; ++ break; + +- DMP(data, count); ++ case HCI_ACLDATA_PKT: ++ if (count >= HCI_ACL_HDR_SIZE) { ++ hci_acl_hdr *h = data; ++ len = HCI_ACL_HDR_SIZE + __le16_to_cpu(h->dlen); ++ } else ++ return -EILSEQ; ++ break; ++#ifdef CONFIG_BLUEZ_USB_SCO ++ case HCI_SCODATA_PKT: ++ if (count >= HCI_SCO_HDR_SIZE) { ++ hci_sco_hdr *h = data; ++ len = HCI_SCO_HDR_SIZE + h->dlen; ++ } else ++ return -EILSEQ; ++ break; ++#endif ++ } ++ BT_DBG("new packet len %d", len); ++ ++ skb = bluez_skb_alloc(len, GFP_ATOMIC); ++ if (!skb) { ++ BT_ERR("%s no memory for the packet", husb->hdev.name); ++ return -ENOMEM; ++ } ++ skb->dev = (void *) &husb->hdev; ++ skb->pkt_type = type; ++ ++ __reassembly(husb, type) = skb; ++ ++ scb = (void *) skb->cb; ++ scb->expect = len; ++ } else { ++ /* Continuation */ ++ scb = (void *) skb->cb; ++ len = scb->expect; ++ } + +- ah = (hci_acl_hdr *) data; +- dlen = le16_to_cpu(ah->dlen); ++ len = min(len, count); ++ ++ memcpy(skb_put(skb, len), data, len); ++ ++ scb->expect -= len; ++ if (!scb->expect) { ++ /* Complete frame */ ++ __reassembly(husb, type) = NULL; ++ hci_recv_frame(skb); ++ } + +- /* Verify frame len and completeness */ +- if ((count - HCI_ACL_HDR_SIZE) != dlen) { +- ERR("%s corrupted ACL packet: count %d, plen %d", husb->hdev.name, count, dlen); +- goto resubmit; ++ count -= len; data += len; + } ++ return 0; ++} + +- /* Allocate packet */ +- if (!(skb = bluez_skb_alloc(count, GFP_ATOMIC))) { +- ERR("Can't allocate mem for new packet"); +- goto resubmit; +- } ++static void hci_usb_rx_complete(struct urb *urb) ++{ ++ struct _urb *_urb = container_of(urb, struct _urb, urb); ++ struct hci_usb *husb = (void *) urb->context; ++ struct hci_dev *hdev = &husb->hdev; ++ int err, count = urb->actual_length; + +- memcpy(skb_put(skb, count), data, count); +- skb->dev = (void *) &husb->hdev; +- skb->pkt_type = HCI_ACLDATA_PKT; ++ BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb, ++ _urb->type, urb->status, count, urb->transfer_flags); + +- husb->hdev.stat.byte_rx += skb->len; ++ if (!test_bit(HCI_RUNNING, &hdev->flags)) ++ return; + +- hci_recv_frame(skb); ++ read_lock(&husb->completion_lock); + +-resubmit: +- husb->read_urb->dev = husb->udev; +- if ((status = usb_submit_urb(husb->read_urb))) +- DBG("%s read URB submit failed %d", husb->hdev.name, status); ++ if (urb->status || !count) ++ goto resubmit; ++ ++ if (_urb->type == HCI_SCODATA_PKT) { ++#ifdef CONFIG_BLUEZ_USB_SCO ++ int i; ++ for (i=0; i < urb->number_of_packets; i++) { ++ BT_DBG("desc %d status %d offset %d len %d", i, ++ urb->iso_frame_desc[i].status, ++ urb->iso_frame_desc[i].offset, ++ urb->iso_frame_desc[i].actual_length); ++ ++ if (!urb->iso_frame_desc[i].status) ++ __recv_frame(husb, _urb->type, ++ urb->transfer_buffer + urb->iso_frame_desc[i].offset, ++ urb->iso_frame_desc[i].actual_length); ++ } ++#else ++ ; ++#endif ++ } else { ++ err = __recv_frame(husb, _urb->type, urb->transfer_buffer, count); ++ if (err < 0) { ++ BT_ERR("%s corrupted packet: type %d count %d", ++ husb->hdev.name, _urb->type, count); ++ hdev->stat.err_rx++; ++ } ++ } + +- DBG("%s read URB re-submited", husb->hdev.name); ++resubmit: ++ if (_urb->type != HCI_EVENT_PKT) { ++ urb->dev = husb->udev; ++ err = usb_submit_urb(urb); ++ BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb, ++ _urb->type, err); ++ } ++ read_unlock(&husb->completion_lock); + } + +-static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb) ++static void hci_usb_tx_complete(struct urb *urb) + { +- struct urb *urb = husb->ctrl_urb; +- devrequest *dr = &husb->dev_req; +- int pipe, status; ++ struct _urb *_urb = container_of(urb, struct _urb, urb); ++ struct hci_usb *husb = (void *) urb->context; ++ struct hci_dev *hdev = &husb->hdev; + +- DBG("%s len %d", husb->hdev.name, skb->len); ++ BT_DBG("%s urb %p status %d flags %x", hdev->name, urb, ++ urb->status, urb->transfer_flags); + +- pipe = usb_sndctrlpipe(husb->udev, 0); ++ atomic_dec(__pending_tx(husb, _urb->type)); + +- dr->requesttype = HCI_CTRL_REQ; +- dr->request = 0; +- dr->index = 0; +- dr->value = 0; +- dr->length = cpu_to_le16(skb->len); ++ urb->transfer_buffer = NULL; ++ kfree_skb((struct sk_buff *) _urb->priv); + +- FILL_CONTROL_URB(urb, husb->udev, pipe, (void*)dr, skb->data, skb->len, +- hci_usb_ctrl, skb); +- +- if ((status = usb_submit_urb(urb))) { +- DBG("%s control URB submit failed %d", husb->hdev.name, status); +- return status; +- } ++ if (!test_bit(HCI_RUNNING, &hdev->flags)) ++ return; + +- return 0; +-} ++ if (!urb->status) ++ hdev->stat.byte_tx += urb->transfer_buffer_length; ++ else ++ hdev->stat.err_tx++; + +-static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb) +-{ +- struct urb *urb = husb->write_urb; +- int pipe, status; ++ read_lock(&husb->completion_lock); + +- DBG("%s len %d", husb->hdev.name, skb->len); ++ _urb_unlink(_urb); ++ _urb_queue_tail(__completed_q(husb, _urb->type), _urb); + +- pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep_addr); ++ hci_usb_tx_wakeup(husb); ++ ++ read_unlock(&husb->completion_lock); ++} + +- FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len, +- hci_usb_bulk_write, skb); +- urb->transfer_flags |= USB_QUEUE_BULK; ++static void hci_usb_destruct(struct hci_dev *hdev) ++{ ++ struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; + +- if ((status = usb_submit_urb(urb))) { +- DBG("%s write URB submit failed %d", husb->hdev.name, status); +- return status; +- } ++ BT_DBG("%s", hdev->name); + +- return 0; ++ kfree(husb); + } + +-static void * hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id) ++static void *hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id) + { +- struct usb_endpoint_descriptor *bulk_out_ep, *intr_in_ep, *bulk_in_ep; ++ struct usb_endpoint_descriptor *bulk_out_ep[HCI_MAX_IFACE_NUM]; ++ struct usb_endpoint_descriptor *isoc_out_ep[HCI_MAX_IFACE_NUM]; ++ struct usb_endpoint_descriptor *bulk_in_ep[HCI_MAX_IFACE_NUM]; ++ struct usb_endpoint_descriptor *isoc_in_ep[HCI_MAX_IFACE_NUM]; ++ struct usb_endpoint_descriptor *intr_in_ep[HCI_MAX_IFACE_NUM]; + struct usb_interface_descriptor *uif; + struct usb_endpoint_descriptor *ep; ++ struct usb_interface *iface, *isoc_iface; + struct hci_usb *husb; + struct hci_dev *hdev; +- int i, size, pipe; +- __u8 * buf; ++ int i, a, e, size, ifn, isoc_ifnum, isoc_alts; + +- DBG("udev %p ifnum %d", udev, ifnum); +- +- /* Check device signature */ +- if ((udev->descriptor.bDeviceClass != HCI_DEV_CLASS) || +- (udev->descriptor.bDeviceSubClass != HCI_DEV_SUBCLASS)|| +- (udev->descriptor.bDeviceProtocol != HCI_DEV_PROTOCOL) ) +- return NULL; +- +- MOD_INC_USE_COUNT; ++ BT_DBG("udev %p ifnum %d", udev, ifnum); + +- uif = &udev->actconfig->interface[ifnum].altsetting[0]; ++ iface = &udev->actconfig->interface[0]; + +- if (uif->bNumEndpoints != 3) { +- DBG("Wrong number of endpoints %d", uif->bNumEndpoints); +- MOD_DEC_USE_COUNT; ++ /* Check our black list */ ++ if (usb_match_id(udev, iface, ignore_ids)) + return NULL; +- } + +- bulk_out_ep = intr_in_ep = bulk_in_ep = NULL; ++ /* Check number of endpoints */ ++ if (udev->actconfig->interface[ifnum].altsetting[0].bNumEndpoints < 3) ++ return NULL; + ++ memset(bulk_out_ep, 0, sizeof(bulk_out_ep)); ++ memset(isoc_out_ep, 0, sizeof(isoc_out_ep)); ++ memset(bulk_in_ep, 0, sizeof(bulk_in_ep)); ++ memset(isoc_in_ep, 0, sizeof(isoc_in_ep)); ++ memset(intr_in_ep, 0, sizeof(intr_in_ep)); ++ ++ size = 0; ++ isoc_iface = NULL; ++ isoc_alts = isoc_ifnum = 0; ++ + /* Find endpoints that we need */ +- for ( i = 0; i < uif->bNumEndpoints; ++i) { +- ep = &uif->endpoint[i]; + +- switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { +- case USB_ENDPOINT_XFER_BULK: +- if (ep->bEndpointAddress & USB_DIR_IN) +- bulk_in_ep = ep; +- else +- bulk_out_ep = ep; +- break; ++ ifn = MIN(udev->actconfig->bNumInterfaces, HCI_MAX_IFACE_NUM); ++ for (i = 0; i < ifn; i++) { ++ iface = &udev->actconfig->interface[i]; ++ for (a = 0; a < iface->num_altsetting; a++) { ++ uif = &iface->altsetting[a]; ++ for (e = 0; e < uif->bNumEndpoints; e++) { ++ ep = &uif->endpoint[e]; ++ ++ switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { ++ case USB_ENDPOINT_XFER_INT: ++ if (ep->bEndpointAddress & USB_DIR_IN) ++ intr_in_ep[i] = ep; ++ break; ++ ++ case USB_ENDPOINT_XFER_BULK: ++ if (ep->bEndpointAddress & USB_DIR_IN) ++ bulk_in_ep[i] = ep; ++ else ++ bulk_out_ep[i] = ep; ++ break; ++ ++#ifdef CONFIG_BLUEZ_USB_SCO ++ case USB_ENDPOINT_XFER_ISOC: ++ if (ep->wMaxPacketSize < size || a > 2) ++ break; ++ size = ep->wMaxPacketSize; ++ ++ isoc_iface = iface; ++ isoc_alts = a; ++ isoc_ifnum = i; ++ ++ if (ep->bEndpointAddress & USB_DIR_IN) ++ isoc_in_ep[i] = ep; ++ else ++ isoc_out_ep[i] = ep; ++ break; ++#endif ++ } ++ } ++ } ++ } + +- case USB_ENDPOINT_XFER_INT: +- intr_in_ep = ep; +- break; +- }; ++ if (!bulk_in_ep[0] || !bulk_out_ep[0] || !intr_in_ep[0]) { ++ BT_DBG("Bulk endpoints not found"); ++ goto done; + } + +- if (!bulk_in_ep || !bulk_out_ep || !intr_in_ep) { +- DBG("Endpoints not found: %p %p %p", bulk_in_ep, bulk_out_ep, intr_in_ep); +- MOD_DEC_USE_COUNT; +- return NULL; ++#ifdef CONFIG_BLUEZ_USB_SCO ++ if (!isoc_in_ep[1] || !isoc_out_ep[1]) { ++ BT_DBG("Isoc endpoints not found"); ++ isoc_iface = NULL; + } ++#endif + + if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) { +- ERR("Can't allocate: control structure"); +- MOD_DEC_USE_COUNT; +- return NULL; ++ BT_ERR("Can't allocate: control structure"); ++ goto done; + } + + memset(husb, 0, sizeof(struct hci_usb)); + + husb->udev = udev; +- husb->bulk_out_ep_addr = bulk_out_ep->bEndpointAddress; +- +- if (!(husb->ctrl_urb = usb_alloc_urb(0))) { +- ERR("Can't allocate: control URB"); +- goto probe_error; +- } +- +- if (!(husb->write_urb = usb_alloc_urb(0))) { +- ERR("Can't allocate: write URB"); +- goto probe_error; +- } +- +- if (!(husb->read_urb = usb_alloc_urb(0))) { +- ERR("Can't allocate: read URB"); +- goto probe_error; +- } +- +- ep = bulk_in_ep; +- pipe = usb_rcvbulkpipe(udev, ep->bEndpointAddress); +- size = HCI_MAX_FRAME_SIZE; +- +- if (!(buf = kmalloc(size, GFP_KERNEL))) { +- ERR("Can't allocate: read buffer"); +- goto probe_error; +- } +- +- FILL_BULK_URB(husb->read_urb, udev, pipe, buf, size, hci_usb_bulk_read, husb); +- husb->read_urb->transfer_flags |= USB_QUEUE_BULK; +- +- ep = intr_in_ep; +- pipe = usb_rcvintpipe(udev, ep->bEndpointAddress); +- size = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); +- +- if (!(husb->intr_urb = usb_alloc_urb(0))) { +- ERR("Can't allocate: interrupt URB"); +- goto probe_error; ++ husb->bulk_out_ep = bulk_out_ep[0]; ++ husb->bulk_in_ep = bulk_in_ep[0]; ++ husb->intr_in_ep = intr_in_ep[0]; ++ ++#ifdef CONFIG_BLUEZ_USB_SCO ++ if (isoc_iface) { ++ BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts); ++ if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) { ++ BT_ERR("Can't set isoc interface settings"); ++ isoc_iface = NULL; ++ } ++ usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb); ++ husb->isoc_iface = isoc_iface; ++ husb->isoc_in_ep = isoc_in_ep[isoc_ifnum]; ++ husb->isoc_out_ep = isoc_out_ep[isoc_ifnum]; + } ++#endif ++ ++ husb->completion_lock = RW_LOCK_UNLOCKED; + +- if (!(buf = kmalloc(size, GFP_KERNEL))) { +- ERR("Can't allocate: interrupt buffer"); +- goto probe_error; ++ for (i = 0; i < 4; i++) { ++ skb_queue_head_init(&husb->transmit_q[i]); ++ _urb_queue_init(&husb->pending_q[i]); ++ _urb_queue_init(&husb->completed_q[i]); + } + +- FILL_INT_URB(husb->intr_urb, udev, pipe, buf, size, hci_usb_intr, husb, ep->bInterval); +- +- skb_queue_head_init(&husb->tx_ctrl_q); +- skb_queue_head_init(&husb->tx_write_q); +- + /* Initialize and register HCI device */ + hdev = &husb->hdev; + +- hdev->type = HCI_USB; ++ hdev->type = HCI_USB; + hdev->driver_data = husb; + + hdev->open = hci_usb_open; + hdev->close = hci_usb_close; + hdev->flush = hci_usb_flush; +- hdev->send = hci_usb_send_frame; ++ hdev->send = hci_usb_send_frame; ++ hdev->destruct = hci_usb_destruct; + + if (hci_register_dev(hdev) < 0) { +- ERR("Can't register HCI device %s", hdev->name); ++ BT_ERR("Can't register HCI device"); + goto probe_error; + } + + return husb; + + probe_error: +- hci_usb_free_bufs(husb); + kfree(husb); +- MOD_DEC_USE_COUNT; ++ ++done: + return NULL; + } + +@@ -626,38 +930,34 @@ + if (!husb) + return; + +- DBG("%s", hdev->name); ++ BT_DBG("%s", hdev->name); + + hci_usb_close(hdev); + +- if (hci_unregister_dev(hdev) < 0) { +- ERR("Can't unregister HCI device %s", hdev->name); +- } ++ if (husb->isoc_iface) ++ usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface); + +- hci_usb_free_bufs(husb); +- kfree(husb); +- +- MOD_DEC_USE_COUNT; ++ if (hci_unregister_dev(hdev) < 0) ++ BT_ERR("Can't unregister HCI device %s", hdev->name); + } + +-static struct usb_driver hci_usb_driver = +-{ ++static struct usb_driver hci_usb_driver = { + name: "hci_usb", + probe: hci_usb_probe, + disconnect: hci_usb_disconnect, +- id_table: usb_bluetooth_ids, ++ id_table: bluetooth_ids, + }; + + int hci_usb_init(void) + { + int err; + +- INF("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", ++ BT_INFO("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", + VERSION); +- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); ++ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); + + if ((err = usb_register(&hci_usb_driver)) < 0) +- ERR("Failed to register HCI USB driver"); ++ BT_ERR("Failed to register HCI USB driver"); + + return err; + } +diff -urN linux-2.4.18/drivers/bluetooth/hci_usb.h linux-2.4.18-mh9/drivers/bluetooth/hci_usb.h +--- linux-2.4.18/drivers/bluetooth/hci_usb.h Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/drivers/bluetooth/hci_usb.h Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,139 @@ ++/* ++ HCI USB driver for Linux Bluetooth protocol stack (BlueZ) ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> ++ ++ Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#ifdef __KERNEL__ ++ ++/* Class, SubClass, and Protocol codes that describe a Bluetooth device */ ++#define HCI_DEV_CLASS 0xe0 /* Wireless class */ ++#define HCI_DEV_SUBCLASS 0x01 /* RF subclass */ ++#define HCI_DEV_PROTOCOL 0x01 /* Bluetooth programming protocol */ ++ ++#define HCI_CTRL_REQ 0x20 ++ ++#define HCI_MAX_IFACE_NUM 3 ++ ++#define HCI_MAX_BULK_TX 4 ++#define HCI_MAX_BULK_RX 1 ++ ++#define HCI_MAX_ISOC_RX 2 ++#define HCI_MAX_ISOC_TX 2 ++ ++#define HCI_MAX_ISOC_FRAMES 10 ++ ++struct _urb_queue { ++ struct list_head head; ++ spinlock_t lock; ++}; ++ ++struct _urb { ++ struct list_head list; ++ struct _urb_queue *queue; ++ int type; ++ void *priv; ++ struct urb urb; ++}; ++ ++struct _urb *_urb_alloc(int isoc, int gfp); ++ ++static inline void _urb_free(struct _urb *_urb) ++{ ++ kfree(_urb); ++} ++ ++static inline void _urb_queue_init(struct _urb_queue *q) ++{ ++ INIT_LIST_HEAD(&q->head); ++ spin_lock_init(&q->lock); ++} ++ ++static inline void _urb_queue_head(struct _urb_queue *q, struct _urb *_urb) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(&q->lock, flags); ++ list_add(&_urb->list, &q->head); _urb->queue = q; ++ spin_unlock_irqrestore(&q->lock, flags); ++} ++ ++static inline void _urb_queue_tail(struct _urb_queue *q, struct _urb *_urb) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(&q->lock, flags); ++ list_add_tail(&_urb->list, &q->head); _urb->queue = q; ++ spin_unlock_irqrestore(&q->lock, flags); ++} ++ ++static inline void _urb_unlink(struct _urb *_urb) ++{ ++ struct _urb_queue *q = _urb->queue; ++ unsigned long flags; ++ if (q) { ++ spin_lock_irqsave(&q->lock, flags); ++ list_del(&_urb->list); _urb->queue = NULL; ++ spin_unlock_irqrestore(&q->lock, flags); ++ } ++} ++ ++struct _urb *_urb_dequeue(struct _urb_queue *q); ++ ++#ifndef container_of ++#define container_of(ptr, type, member) ({ \ ++ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ++ (type *)( (char *)__mptr - offsetof(type,member) );}) ++#endif ++ ++struct hci_usb { ++ struct hci_dev hdev; ++ ++ unsigned long state; ++ ++ struct usb_device *udev; ++ ++ struct usb_endpoint_descriptor *bulk_in_ep; ++ struct usb_endpoint_descriptor *bulk_out_ep; ++ struct usb_endpoint_descriptor *intr_in_ep; ++ ++ struct usb_interface *isoc_iface; ++ struct usb_endpoint_descriptor *isoc_out_ep; ++ struct usb_endpoint_descriptor *isoc_in_ep; ++ ++ struct sk_buff_head transmit_q[4]; ++ struct sk_buff *reassembly[4]; // Reassembly buffers ++ ++ rwlock_t completion_lock; ++ ++ atomic_t pending_tx[4]; // Number of pending requests ++ struct _urb_queue pending_q[4]; // Pending requests ++ struct _urb_queue completed_q[4]; // Completed requests ++}; ++ ++/* States */ ++#define HCI_USB_TX_PROCESS 1 ++#define HCI_USB_TX_WAKEUP 2 ++ ++#endif /* __KERNEL__ */ +diff -urN linux-2.4.18/drivers/bluetooth/hci_vhci.c linux-2.4.18-mh9/drivers/bluetooth/hci_vhci.c +--- linux-2.4.18/drivers/bluetooth/hci_vhci.c Fri Sep 7 18:28:38 2001 ++++ linux-2.4.18-mh9/drivers/bluetooth/hci_vhci.c Mon Aug 25 18:38:10 2003 +@@ -25,9 +25,9 @@ + /* + * BlueZ HCI virtual device driver. + * +- * $Id$ ++ * $Id$ + */ +-#define VERSION "1.0" ++#define VERSION "1.1" + + #include <linux/config.h> + #include <linux/module.h> +@@ -49,43 +49,56 @@ + #include <asm/uaccess.h> + + #include <net/bluetooth/bluetooth.h> +-#include <net/bluetooth/bluez.h> + #include <net/bluetooth/hci_core.h> +-#include <net/bluetooth/hci_vhci.h> ++#include "hci_vhci.h" + + /* HCI device part */ + +-int hci_vhci_open(struct hci_dev *hdev) ++static int hci_vhci_open(struct hci_dev *hdev) + { +- hdev->flags |= HCI_RUNNING; ++ set_bit(HCI_RUNNING, &hdev->flags); + return 0; + } + +-int hci_vhci_flush(struct hci_dev *hdev) ++static int hci_vhci_flush(struct hci_dev *hdev) + { + struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) hdev->driver_data; + skb_queue_purge(&hci_vhci->readq); + return 0; + } + +-int hci_vhci_close(struct hci_dev *hdev) ++static int hci_vhci_close(struct hci_dev *hdev) + { +- hdev->flags &= ~HCI_RUNNING; ++ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) ++ return 0; ++ + hci_vhci_flush(hdev); + return 0; + } + +-int hci_vhci_send_frame(struct sk_buff *skb) ++static void hci_vhci_destruct(struct hci_dev *hdev) ++{ ++ struct hci_vhci_struct *vhci; ++ ++ if (!hdev) return; ++ ++ vhci = (struct hci_vhci_struct *) hdev->driver_data; ++ kfree(vhci); ++ ++ MOD_DEC_USE_COUNT; ++} ++ ++static int hci_vhci_send_frame(struct sk_buff *skb) + { + struct hci_dev* hdev = (struct hci_dev *) skb->dev; + struct hci_vhci_struct *hci_vhci; + + if (!hdev) { +- ERR("Frame for uknown device (hdev=NULL)"); ++ BT_ERR("Frame for uknown device (hdev=NULL)"); + return -ENODEV; + } + +- if (!(hdev->flags & HCI_RUNNING)) ++ if (!test_bit(HCI_RUNNING, &hdev->flags)) + return -EBUSY; + + hci_vhci = (struct hci_vhci_struct *) hdev->driver_data; +@@ -188,7 +201,7 @@ + + add_wait_queue(&hci_vhci->read_wait, &wait); + while (count) { +- current->state = TASK_INTERRUPTIBLE; ++ set_current_state(TASK_INTERRUPTIBLE); + + /* Read frames from device queue */ + if (!(skb = skb_dequeue(&hci_vhci->readq))) { +@@ -214,8 +227,7 @@ + kfree_skb(skb); + break; + } +- +- current->state = TASK_RUNNING; ++ set_current_state(TASK_RUNNING); + remove_wait_queue(&hci_vhci->read_wait, &wait); + + return ret; +@@ -270,11 +282,13 @@ + hdev->close = hci_vhci_close; + hdev->flush = hci_vhci_flush; + hdev->send = hci_vhci_send_frame; ++ hdev->destruct = hci_vhci_destruct; + + if (hci_register_dev(hdev) < 0) { + kfree(hci_vhci); + return -EBUSY; + } ++ MOD_INC_USE_COUNT; + + file->private_data = hci_vhci; + return 0; +@@ -285,12 +299,10 @@ + struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data; + + if (hci_unregister_dev(&hci_vhci->hdev) < 0) { +- ERR("Can't unregister HCI device %s", hci_vhci->hdev.name); ++ BT_ERR("Can't unregister HCI device %s", hci_vhci->hdev.name); + } + +- kfree(hci_vhci); + file->private_data = NULL; +- + return 0; + } + +@@ -315,12 +327,12 @@ + + int __init hci_vhci_init(void) + { +- INF("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", ++ BT_INFO("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", + VERSION); +- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); ++ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); + + if (misc_register(&hci_vhci_miscdev)) { +- ERR("Can't register misc device %d\n", VHCI_MINOR); ++ BT_ERR("Can't register misc device %d\n", VHCI_MINOR); + return -EIO; + } + +@@ -337,4 +349,4 @@ + + MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); + MODULE_DESCRIPTION("BlueZ VHCI driver ver " VERSION); +-MODULE_LICENSE("GPL"); ++MODULE_LICENSE("GPL"); +diff -urN linux-2.4.18/drivers/bluetooth/hci_vhci.h linux-2.4.18-mh9/drivers/bluetooth/hci_vhci.h +--- linux-2.4.18/drivers/bluetooth/hci_vhci.h Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/drivers/bluetooth/hci_vhci.h Mon Aug 25 18:38:10 2003 +@@ -0,0 +1,50 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#ifndef __HCI_VHCI_H ++#define __HCI_VHCI_H ++ ++#ifdef __KERNEL__ ++ ++struct hci_vhci_struct { ++ struct hci_dev hdev; ++ __u32 flags; ++ wait_queue_head_t read_wait; ++ struct sk_buff_head readq; ++ struct fasync_struct *fasync; ++}; ++ ++/* VHCI device flags */ ++#define VHCI_FASYNC 0x0010 ++ ++#endif /* __KERNEL__ */ ++ ++#define VHCI_DEV "/dev/vhci" ++#define VHCI_MINOR 250 ++ ++#endif /* __HCI_VHCI_H */ +diff -urN linux-2.4.18/drivers/char/pcmcia/serial_cs.c linux-2.4.18-mh9/drivers/char/pcmcia/serial_cs.c +--- linux-2.4.18/drivers/char/pcmcia/serial_cs.c Fri Dec 21 18:41:54 2001 ++++ linux-2.4.18-mh9/drivers/char/pcmcia/serial_cs.c Mon Aug 25 18:38:10 2003 +@@ -2,7 +2,7 @@ + + A driver for PCMCIA serial devices + +- serial_cs.c 1.128 2001/10/18 12:18:35 ++ serial_cs.c 1.138 2002/10/25 06:24:52 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file +@@ -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 <linux/module.h> +@@ -69,14 +69,14 @@ + static int irq_list[4] = { -1 }; + MODULE_PARM(irq_list, "1-4i"); + +-/* Enable the speaker? */ +-INT_MODULE_PARM(do_sound, 1); ++INT_MODULE_PARM(do_sound, 1); /* Enable the speaker? */ ++INT_MODULE_PARM(buggy_uart, 0); /* Skip strict UART tests? */ + + #ifdef PCMCIA_DEBUG + INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); + #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) + static char *version = +-"serial_cs.c 1.128 2001/10/18 12:18:35 (David Hinds)"; ++"serial_cs.c 1.138 2002/10/25 06:24:52 (David Hinds)"; + #else + #define DEBUG(n, args...) + #endif +@@ -95,6 +95,7 @@ + { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 }, + { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 }, + { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 }, ++ { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D2, 2 }, + { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 }, + { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 }, + { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 }, +@@ -148,7 +149,7 @@ + client_reg_t client_reg; + dev_link_t *link; + int i, ret; +- ++ + DEBUG(0, "serial_attach()\n"); + + /* Create new serial device */ +@@ -160,7 +161,7 @@ + link->release.function = &serial_release; + link->release.data = (u_long)link; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; +- link->io.NumPorts1 = 8; ++ link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) +@@ -169,13 +170,12 @@ + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->conf.Attributes = CONF_ENABLE_IRQ; +- link->conf.Vcc = 50; + if (do_sound) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + link->conf.IntType = INT_MEMORY_AND_IO; +- ++ + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; +@@ -194,7 +194,7 @@ + serial_detach(link); + return NULL; + } +- ++ + return link; + } /* serial_attach */ + +@@ -214,7 +214,7 @@ + int ret; + + DEBUG(0, "serial_detach(0x%p)\n", link); +- ++ + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; +@@ -224,17 +224,17 @@ + del_timer(&link->release); + if (link->state & DEV_CONFIG) + serial_release((u_long)link); +- ++ + if (link->handle) { + ret = CardServices(DeregisterClient, link->handle); + if (ret != CS_SUCCESS) + cs_error(link->handle, DeregisterClient, ret); + } +- ++ + /* Unlink device structure, free bits */ + *linkp = link->next; + kfree(info); +- ++ + } /* serial_detach */ + + /*====================================================================*/ +@@ -243,18 +243,20 @@ + { + struct serial_struct serial; + int line; +- ++ + memset(&serial, 0, sizeof(serial)); + serial.port = port; + serial.irq = irq; + serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ; ++ if (buggy_uart) ++ serial.flags |= ASYNC_BUGGY_UART; + line = register_serial(&serial); + if (line < 0) { + printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx," + " irq %d failed\n", (u_long)serial.port, serial.irq); + return -1; + } +- ++ + info->line[info->ndev] = line; + sprintf(info->node[info->ndev].dev_name, "ttyS%d", line); + info->node[info->ndev].major = TTY_MAJOR; +@@ -262,7 +264,7 @@ + if (info->ndev > 0) + info->node[info->ndev-1].next = &info->node[info->ndev]; + info->ndev++; +- ++ + return 0; + } + +@@ -313,7 +315,10 @@ + return setup_serial(info, port, config.AssignedIRQ); + } + link->conf.Vcc = config.Vcc; +- ++ ++ link->io.NumPorts1 = 8; ++ link->io.NumPorts2 = 0; ++ + /* First pass: look for a config entry that looks normal. */ + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; tuple.TupleDataMax = 255; +@@ -340,7 +345,7 @@ + i = next_tuple(handle, &tuple, &parse); + } + } +- ++ + /* Second pass: try to find an entry that isn't picky about + its base address, then try to grab any standard serial port + address, and finally try to get any free port. */ +@@ -352,8 +357,7 @@ + for (j = 0; j < 5; j++) { + link->io.BasePort1 = base[j]; + link->io.IOAddrLines = base[j] ? 16 : 3; +- i = CardServices(RequestIO, link->handle, +- &link->io); ++ i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) goto found_port; + } + } +@@ -365,7 +369,7 @@ + cs_error(link->handle, RequestIO, i); + return -1; + } +- ++ + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIRQ, i); +@@ -390,8 +394,12 @@ + u_char buf[256]; + cisparse_t parse; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; ++ config_info_t config; + int i, base2 = 0; + ++ CardServices(GetConfigurationInfo, handle, &config); ++ link->conf.Vcc = config.Vcc; ++ + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; tuple.TupleDataMax = 255; + tuple.Attributes = 0; +@@ -433,12 +441,12 @@ + i = next_tuple(handle, &tuple, &parse); + } + } +- ++ + if (i != CS_SUCCESS) { +- cs_error(link->handle, RequestIO, i); +- return -1; ++ /* At worst, try to configure as a single port */ ++ return simple_config(link); + } +- ++ + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIRQ, i); +@@ -454,14 +462,27 @@ + cs_error(link->handle, RequestConfiguration, i); + return -1; + } +- ++ ++ /* The Oxford Semiconductor OXCF950 cards are in fact single-port: ++ 8 registers are for the UART, the others are extra registers */ ++ if (info->manfid == MANFID_OXSEMI) { ++ if (cf->index == 1 || cf->index == 3) { ++ setup_serial(info, base2, link->irq.AssignedIRQ); ++ outb(12,link->io.BasePort1+1); ++ } else { ++ setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ); ++ outb(12,base2+1); ++ } ++ return 0; ++ } ++ + setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ); + /* The Nokia cards are not really multiport cards */ + if (info->manfid == MANFID_NOKIA) + return 0; + for (i = 0; i < info->multi-1; i++) + setup_serial(info, base2+(8*i), link->irq.AssignedIRQ); +- ++ + return 0; + } + +@@ -487,7 +508,7 @@ + int i, last_ret, last_fn; + + DEBUG(0, "serial_config(0x%p)\n", link); +- ++ + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; tuple.TupleDataMax = 255; + tuple.Attributes = 0; +@@ -500,7 +521,7 @@ + } + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; +- ++ + /* Configure card */ + link->state |= DEV_CONFIG; + +@@ -508,8 +529,8 @@ + tuple.DesiredTuple = CISTPL_LONGLINK_MFC; + tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; + info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS); +- +- /* Is this a multiport card? */ ++ ++ /* Scan list of known multiport card ID's */ + tuple.DesiredTuple = CISTPL_MANFID; + if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { + info->manfid = le16_to_cpu(buf[0]); +@@ -537,15 +558,15 @@ + info->multi = 2; + } + } +- ++ + if (info->multi > 1) + multi_config(link); + else + simple_config(link); +- ++ + if (info->ndev == 0) + goto failed; +- ++ + if (info->manfid == MANFID_IBM) { + conf_reg_t reg = { 0, CS_READ, 0x800, 0 }; + CS_CHECK(AccessConfigurationRegister, link->handle, ®); +@@ -562,6 +583,7 @@ + cs_error(link->handle, last_fn, last_ret); + failed: + serial_release((u_long)link); ++ link->state &= ~DEV_CONFIG_PENDING; + + } /* serial_config */ + +@@ -569,7 +591,7 @@ + + After a card is removed, serial_release() will unregister the net + device, and release the PCMCIA configuration. +- ++ + ======================================================================*/ + + void serial_release(u_long arg) +@@ -577,7 +599,7 @@ + dev_link_t *link = (dev_link_t *)arg; + serial_info_t *info = link->priv; + int i; +- ++ + DEBUG(0, "serial_release(0x%p)\n", link); + + for (i = 0; i < info->ndev; i++) { +@@ -590,7 +612,7 @@ + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + } +- ++ + link->state &= ~DEV_CONFIG; + + } /* serial_release */ +@@ -601,7 +623,7 @@ + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the serial drivers from + talking to the ports. +- ++ + ======================================================================*/ + + static int serial_event(event_t event, int priority, +@@ -609,9 +631,9 @@ + { + dev_link_t *link = args->client_data; + serial_info_t *info = link->priv; +- ++ + DEBUG(1, "serial_event(0x%06x)\n", event); +- ++ + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; +@@ -650,7 +672,7 @@ + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "serial_cs: Card Services release " + "does not match!\n"); +- return -1; ++ return -EINVAL; + } + register_pccard_driver(&dev_info, &serial_attach, &serial_detach); + return 0; +diff -urN linux-2.4.18/drivers/usb/Config.in linux-2.4.18-mh9/drivers/usb/Config.in +--- linux-2.4.18/drivers/usb/Config.in Mon Feb 25 20:38:07 2002 ++++ linux-2.4.18-mh9/drivers/usb/Config.in Mon Aug 25 18:38:10 2003 +@@ -31,7 +31,13 @@ + + comment 'USB Device Class drivers' + dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND +-dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL ++if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ if [ "$CONFIG_BLUEZ" = "n" ]; then ++ dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB ++ else ++ comment ' USB Bluetooth can only be used with disabled Bluetooth subsystem' ++ fi ++fi + if [ "$CONFIG_SCSI" = "n" ]; then + comment ' SCSI support is needed for USB Storage' + fi +diff -urN linux-2.4.18/include/linux/firmware.h linux-2.4.18-mh9/include/linux/firmware.h +--- linux-2.4.18/include/linux/firmware.h Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/include/linux/firmware.h Mon Aug 25 18:38:10 2003 +@@ -0,0 +1,20 @@ ++#ifndef _LINUX_FIRMWARE_H ++#define _LINUX_FIRMWARE_H ++#include <linux/module.h> ++#include <linux/types.h> ++#define FIRMWARE_NAME_MAX 30 ++struct firmware { ++ size_t size; ++ u8 *data; ++}; ++int request_firmware (const struct firmware **fw, const char *name, ++ const char *device); ++int request_firmware_nowait ( ++ struct module *module, ++ const char *name, const char *device, void *context, ++ void (*cont)(const struct firmware *fw, void *context)); ++/* On 2.5 'device' is 'struct device *' */ ++ ++void release_firmware (const struct firmware *fw); ++void register_firmware (const char *name, const u8 *data, size_t size); ++#endif +diff -urN linux-2.4.18/include/linux/kernel.h linux-2.4.18-mh9/include/linux/kernel.h +--- linux-2.4.18/include/linux/kernel.h Mon Feb 25 20:38:13 2002 ++++ linux-2.4.18-mh9/include/linux/kernel.h Mon Aug 25 18:38:11 2003 +@@ -11,6 +11,7 @@ + #include <linux/linkage.h> + #include <linux/stddef.h> + #include <linux/types.h> ++#include <linux/compiler.h> + + /* Optimization barrier */ + /* The "volatile" is due to gcc bugs */ +@@ -181,4 +182,6 @@ + char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */ + }; + +-#endif ++#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) ++ ++#endif /* _LINUX_KERNEL_H */ +diff -urN linux-2.4.18/include/net/bluetooth/bluetooth.h linux-2.4.18-mh9/include/net/bluetooth/bluetooth.h +--- linux-2.4.18/include/net/bluetooth/bluetooth.h Fri Sep 7 18:28:38 2001 ++++ linux-2.4.18-mh9/include/net/bluetooth/bluetooth.h Mon Aug 25 18:38:11 2003 +@@ -23,7 +23,7 @@ + */ + + /* +- * $Id$ ++ * $Id$ + */ + + #ifndef __BLUETOOTH_H +@@ -31,17 +31,63 @@ + + #include <asm/types.h> + #include <asm/byteorder.h> ++#include <linux/poll.h> ++#include <net/sock.h> + + #ifndef AF_BLUETOOTH + #define AF_BLUETOOTH 31 + #define PF_BLUETOOTH AF_BLUETOOTH + #endif + ++/* Reserv for core and drivers use */ ++#define BLUEZ_SKB_RESERVE 8 ++ ++#ifndef MIN ++#define MIN(a,b) ((a) < (b) ? (a) : (b)) ++#endif ++ + #define BTPROTO_L2CAP 0 + #define BTPROTO_HCI 1 ++#define BTPROTO_SCO 2 ++#define BTPROTO_RFCOMM 3 ++#define BTPROTO_BNEP 4 ++#define BTPROTO_CMTP 5 + + #define SOL_HCI 0 + #define SOL_L2CAP 6 ++#define SOL_SCO 17 ++#define SOL_RFCOMM 18 ++ ++/* Debugging */ ++#ifdef CONFIG_BLUEZ_DEBUG ++ ++#define HCI_CORE_DEBUG 1 ++#define HCI_SOCK_DEBUG 1 ++#define HCI_UART_DEBUG 1 ++#define HCI_USB_DEBUG 1 ++//#define HCI_DATA_DUMP 1 ++ ++#define L2CAP_DEBUG 1 ++#define SCO_DEBUG 1 ++#define AF_BLUETOOTH_DEBUG 1 ++ ++#endif /* CONFIG_BLUEZ_DEBUG */ ++ ++extern void bluez_dump(char *pref, __u8 *buf, int count); ++ ++#if __GNUC__ <= 2 && __GNUC_MINOR__ < 95 ++#define __func__ __FUNCTION__ ++#endif ++ ++#define BT_INFO(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg) ++#define BT_DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n" , __func__ , ## arg) ++#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg) ++ ++#ifdef HCI_DATA_DUMP ++#define BT_DMP(buf, len) bluez_dump(__func__, buf, len) ++#else ++#define BT_DMP(D...) ++#endif + + /* Connection and socket states */ + enum { +@@ -50,6 +96,7 @@ + BT_BOUND, + BT_LISTEN, + BT_CONNECT, ++ BT_CONNECT2, + BT_CONFIG, + BT_DISCONN, + BT_CLOSED +@@ -66,7 +113,8 @@ + __u8 b[6]; + } __attribute__((packed)) bdaddr_t; + +-#define BDADDR_ANY ((bdaddr_t *)"\000\000\000\000\000") ++#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}}) ++#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}}) + + /* Copy, swap, convert BD Address */ + static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2) +@@ -82,6 +130,91 @@ + char *batostr(bdaddr_t *ba); + bdaddr_t *strtoba(char *str); + ++/* Common socket structures and functions */ ++ ++#define bluez_pi(sk) ((struct bluez_pinfo *) &sk->protinfo) ++#define bluez_sk(pi) ((struct sock *) \ ++ ((void *)pi - (unsigned long)(&((struct sock *)0)->protinfo))) ++ ++struct bluez_pinfo { ++ bdaddr_t src; ++ bdaddr_t dst; ++ ++ struct list_head accept_q; ++ struct sock *parent; ++}; ++ ++struct bluez_sock_list { ++ struct sock *head; ++ rwlock_t lock; ++}; ++ ++int bluez_sock_register(int proto, struct net_proto_family *ops); ++int bluez_sock_unregister(int proto); ++void bluez_sock_init(struct socket *sock, struct sock *sk); ++void bluez_sock_link(struct bluez_sock_list *l, struct sock *s); ++void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s); ++int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm); ++uint bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait); ++int bluez_sock_wait_state(struct sock *sk, int state, unsigned long timeo); ++ ++void bluez_accept_enqueue(struct sock *parent, struct sock *sk); ++struct sock * bluez_accept_dequeue(struct sock *parent, struct socket *newsock); ++ ++/* Skb helpers */ ++struct bluez_skb_cb { ++ int incomming; ++}; ++#define bluez_cb(skb) ((struct bluez_skb_cb *)(skb->cb)) ++ ++static inline struct sk_buff *bluez_skb_alloc(unsigned int len, int how) ++{ ++ struct sk_buff *skb; ++ ++ if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) { ++ skb_reserve(skb, BLUEZ_SKB_RESERVE); ++ bluez_cb(skb)->incomming = 0; ++ } ++ return skb; ++} ++ ++static inline struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len, ++ int nb, int *err) ++{ ++ struct sk_buff *skb; ++ ++ if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) { ++ skb_reserve(skb, BLUEZ_SKB_RESERVE); ++ bluez_cb(skb)->incomming = 0; ++ } ++ ++ return skb; ++} ++ ++static inline int skb_frags_no(struct sk_buff *skb) ++{ ++ register struct sk_buff *frag = skb_shinfo(skb)->frag_list; ++ register int n = 1; ++ ++ for (; frag; frag=frag->next, n++); ++ return n; ++} ++ ++int hci_core_init(void); ++int hci_core_cleanup(void); ++int hci_sock_init(void); ++int hci_sock_cleanup(void); ++ + int bterr(__u16 code); ++ ++#ifndef MODULE_LICENSE ++#define MODULE_LICENSE(x) ++#endif ++ ++#ifndef list_for_each_safe ++#define list_for_each_safe(pos, n, head) \ ++ for (pos = (head)->next, n = pos->next; pos != (head); \ ++ pos = n, n = pos->next) ++#endif + + #endif /* __BLUETOOTH_H */ +diff -urN linux-2.4.18/include/net/bluetooth/bluez.h linux-2.4.18-mh9/include/net/bluetooth/bluez.h +--- linux-2.4.18/include/net/bluetooth/bluez.h Fri Sep 7 18:28:38 2001 ++++ linux-2.4.18-mh9/include/net/bluetooth/bluez.h Thu Jan 1 01:00:00 1970 +@@ -1,124 +0,0 @@ +-/* +- BlueZ - Bluetooth protocol stack for Linux +- Copyright (C) 2000-2001 Qualcomm Incorporated +- +- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; +- +- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY +- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES +- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- +- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, +- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS +- SOFTWARE IS DISCLAIMED. +-*/ +- +-/* +- * $Id$ +- */ +- +-#ifndef __IF_BLUEZ_H +-#define __IF_BLUEZ_H +- +-#include <net/sock.h> +- +-#define BLUEZ_MAX_PROTO 2 +- +-/* Reserv for core and drivers use */ +-#define BLUEZ_SKB_RESERVE 8 +- +-#ifndef MIN +-#define MIN(a,b) ((a) < (b) ? (a) : (b)) +-#endif +- +-/* Debugging */ +-#ifdef BLUEZ_DEBUG +- +-#define HCI_CORE_DEBUG 1 +-#define HCI_SOCK_DEBUG 1 +-#define HCI_UART_DEBUG 1 +-#define HCI_USB_DEBUG 1 +-//#define HCI_DATA_DUMP 1 +- +-#define L2CAP_DEBUG 1 +- +-#endif /* BLUEZ_DEBUG */ +- +-extern void bluez_dump(char *pref, __u8 *buf, int count); +- +-#define INF(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg) +-#define DBG(fmt, arg...) printk(KERN_INFO __FUNCTION__ ": " fmt "\n" , ## arg) +-#define ERR(fmt, arg...) printk(KERN_ERR __FUNCTION__ ": " fmt "\n" , ## arg) +- +-#ifdef HCI_DATA_DUMP +-#define DMP(buf, len) bluez_dump(__FUNCTION__, buf, len) +-#else +-#define DMP(D...) +-#endif +- +-/* ----- Sockets ------ */ +-struct bluez_sock_list { +- struct sock *head; +- rwlock_t lock; +-}; +- +-extern int bluez_sock_register(int proto, struct net_proto_family *ops); +-extern int bluez_sock_unregister(int proto); +- +-extern void bluez_sock_link(struct bluez_sock_list *l, struct sock *s); +-extern void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s); +- +-/* ----- SKB helpers ----- */ +-struct bluez_skb_cb { +- int incomming; +-}; +-#define bluez_cb(skb) ((struct bluez_skb_cb *)(skb->cb)) +- +-static inline struct sk_buff *bluez_skb_alloc(unsigned int len, int how) +-{ +- struct sk_buff *skb; +- +- if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) { +- skb_reserve(skb, BLUEZ_SKB_RESERVE); +- bluez_cb(skb)->incomming = 0; +- } +- return skb; +-} +- +-static inline struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len, +- int nb, int *err) +-{ +- struct sk_buff *skb; +- +- if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) { +- skb_reserve(skb, BLUEZ_SKB_RESERVE); +- bluez_cb(skb)->incomming = 0; +- } +- +- return skb; +-} +- +-static inline int skb_frags_no(struct sk_buff *skb) +-{ +- register struct sk_buff *frag = skb_shinfo(skb)->frag_list; +- register int n = 1; +- +- for (; frag; frag=frag->next, n++); +- return n; +-} +- +-extern int hci_core_init(void); +-extern int hci_core_cleanup(void); +-extern int hci_sock_init(void); +-extern int hci_sock_cleanup(void); +- +-#endif /* __IF_BLUEZ_H */ +diff -urN linux-2.4.18/include/net/bluetooth/hci.h linux-2.4.18-mh9/include/net/bluetooth/hci.h +--- linux-2.4.18/include/net/bluetooth/hci.h Fri Sep 7 18:28:38 2001 ++++ linux-2.4.18-mh9/include/net/bluetooth/hci.h Mon Aug 25 18:38:12 2003 +@@ -23,59 +23,80 @@ + */ + + /* +- * $Id$ ++ * $Id$ + */ + + #ifndef __HCI_H + #define __HCI_H + +-#include <asm/byteorder.h> +- +-#define HCI_MAX_DEV 8 +-#define HCI_MAX_FRAME_SIZE 2048 ++#define HCI_MAX_ACL_SIZE 1024 ++#define HCI_MAX_SCO_SIZE 255 ++#define HCI_MAX_EVENT_SIZE 260 ++#define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4) + + /* HCI dev events */ + #define HCI_DEV_REG 1 + #define HCI_DEV_UNREG 2 + #define HCI_DEV_UP 3 + #define HCI_DEV_DOWN 4 ++#define HCI_DEV_SUSPEND 5 ++#define HCI_DEV_RESUME 6 ++ ++/* HCI notify events */ ++#define HCI_NOTIFY_CONN_ADD 1 ++#define HCI_NOTIFY_CONN_DEL 2 ++#define HCI_NOTIFY_VOICE_SETTING 3 + + /* HCI device types */ +-#define HCI_UART 0 ++#define HCI_VHCI 0 + #define HCI_USB 1 +-#define HCI_VHCI 2 +- +-/* HCI device modes */ +-#define HCI_NORMAL 0x0001 +-#define HCI_RAW 0x0002 +-#define HCI_MODE_MASK (HCI_NORMAL | HCI_RAW) +-#define HCI_SOCK 0x1000 +- +-/* HCI device states */ +-#define HCI_INIT 0x0010 +-#define HCI_UP 0x0020 +-#define HCI_RUNNING 0x0040 ++#define HCI_PCCARD 2 ++#define HCI_UART 3 ++#define HCI_RS232 4 ++#define HCI_PCI 5 + + /* HCI device flags */ +-#define HCI_PSCAN 0x0100 +-#define HCI_ISCAN 0x0200 +-#define HCI_AUTH 0x0400 ++enum { ++ HCI_UP, ++ HCI_INIT, ++ HCI_RUNNING, ++ ++ HCI_PSCAN, ++ HCI_ISCAN, ++ HCI_AUTH, ++ HCI_ENCRYPT, ++ HCI_INQUIRY, ++ ++ HCI_RAW ++}; + +-/* HCI Ioctl defines */ ++/* HCI ioctl defines */ + #define HCIDEVUP _IOW('H', 201, int) + #define HCIDEVDOWN _IOW('H', 202, int) + #define HCIDEVRESET _IOW('H', 203, int) +-#define HCIRESETSTAT _IOW('H', 204, int) +-#define HCIGETINFO _IOR('H', 205, int) +-#define HCIGETDEVLIST _IOR('H', 206, int) +-#define HCISETRAW _IOW('H', 207, int) +-#define HCISETSCAN _IOW('H', 208, int) +-#define HCISETAUTH _IOW('H', 209, int) +-#define HCIINQUIRY _IOR('H', 210, int) +-#define HCISETPTYPE _IOW('H', 211, int) ++#define HCIDEVRESTAT _IOW('H', 204, int) ++ ++#define HCIGETDEVLIST _IOR('H', 210, int) ++#define HCIGETDEVINFO _IOR('H', 211, int) + #define HCIGETCONNLIST _IOR('H', 212, int) ++#define HCIGETCONNINFO _IOR('H', 213, int) + +-#ifndef __NO_HCI_DEFS ++#define HCISETRAW _IOW('H', 220, int) ++#define HCISETSCAN _IOW('H', 221, int) ++#define HCISETAUTH _IOW('H', 222, int) ++#define HCISETENCRYPT _IOW('H', 223, int) ++#define HCISETPTYPE _IOW('H', 224, int) ++#define HCISETLINKPOL _IOW('H', 225, int) ++#define HCISETLINKMODE _IOW('H', 226, int) ++#define HCISETACLMTU _IOW('H', 227, int) ++#define HCISETSCOMTU _IOW('H', 228, int) ++ ++#define HCIINQUIRY _IOR('H', 240, int) ++ ++/* HCI timeouts */ ++#define HCI_CONN_TIMEOUT (HZ * 40) ++#define HCI_DISCONN_TIMEOUT (HZ * 2) ++#define HCI_CONN_IDLE_TIMEOUT (HZ * 60) + + /* HCI Packet types */ + #define HCI_COMMAND_PKT 0x01 +@@ -92,11 +113,18 @@ + #define HCI_DH3 0x0800 + #define HCI_DH5 0x8000 + ++#define HCI_HV1 0x0020 ++#define HCI_HV2 0x0040 ++#define HCI_HV3 0x0080 ++ ++#define SCO_PTYPE_MASK (HCI_HV1 | HCI_HV2 | HCI_HV3) ++#define ACL_PTYPE_MASK (~SCO_PTYPE_MASK) ++ + /* ACL flags */ +-#define ACL_CONT 0x0001 +-#define ACL_START 0x0002 +-#define ACL_ACTIVE_BCAST 0x0010 +-#define ACL_PICO_BCAST 0x0020 ++#define ACL_CONT 0x01 ++#define ACL_START 0x02 ++#define ACL_ACTIVE_BCAST 0x04 ++#define ACL_PICO_BCAST 0x08 + + /* Baseband links */ + #define SCO_LINK 0x00 +@@ -125,6 +153,20 @@ + #define LMP_PSCHEME 0x02 + #define LMP_PCONTROL 0x04 + ++/* Link policies */ ++#define HCI_LP_RSWITCH 0x0001 ++#define HCI_LP_HOLD 0x0002 ++#define HCI_LP_SNIFF 0x0004 ++#define HCI_LP_PARK 0x0008 ++ ++/* Link mode */ ++#define HCI_LM_ACCEPT 0x8000 ++#define HCI_LM_MASTER 0x0001 ++#define HCI_LM_AUTH 0x0002 ++#define HCI_LM_ENCRYPT 0x0004 ++#define HCI_LM_TRUSTED 0x0008 ++#define HCI_LM_RELIABLE 0x0010 ++ + /* ----- HCI Commands ----- */ + /* OGF & OCF values */ + +@@ -137,9 +179,10 @@ + __u8 hci_ver; + __u16 hci_rev; + __u8 lmp_ver; +- __u16 man_name; +- __u16 lmp_sub; ++ __u16 manufacturer; ++ __u16 lmp_subver; + } __attribute__ ((packed)) read_local_version_rp; ++#define READ_LOCAL_VERSION_RP_SIZE 9 + + #define OCF_READ_LOCAL_FEATURES 0x0003 + typedef struct { +@@ -165,18 +208,24 @@ + /* Host Controller and Baseband */ + #define OGF_HOST_CTL 0x03 + #define OCF_RESET 0x0003 ++#define OCF_READ_AUTH_ENABLE 0x001F + #define OCF_WRITE_AUTH_ENABLE 0x0020 +- #define AUTH_DISABLED 0x00 +- #define AUTH_ENABLED 0x01 ++ #define AUTH_DISABLED 0x00 ++ #define AUTH_ENABLED 0x01 ++ ++#define OCF_READ_ENCRYPT_MODE 0x0021 ++#define OCF_WRITE_ENCRYPT_MODE 0x0022 ++ #define ENCRYPT_DISABLED 0x00 ++ #define ENCRYPT_P2P 0x01 ++ #define ENCRYPT_BOTH 0x02 + + #define OCF_WRITE_CA_TIMEOUT 0x0016 + #define OCF_WRITE_PG_TIMEOUT 0x0018 + + #define OCF_WRITE_SCAN_ENABLE 0x001A +- #define SCANS_DISABLED 0x00 +- #define IS_ENA_PS_DIS 0x01 +- #define IS_DIS_PS_ENA 0x02 +- #define IS_ENA_PS_ENA 0x03 ++ #define SCAN_DISABLED 0x00 ++ #define SCAN_INQUIRY 0x01 ++ #define SCAN_PAGE 0x02 + + #define OCF_SET_EVENT_FLT 0x0005 + typedef struct { +@@ -226,9 +275,31 @@ + } __attribute__ ((packed)) write_class_of_dev_cp; + #define WRITE_CLASS_OF_DEV_CP_SIZE 3 + ++#define OCF_READ_VOICE_SETTING 0x0025 ++typedef struct { ++ __u8 status; ++ __u16 voice_setting; ++} __attribute__ ((packed)) read_voice_setting_rp; ++#define READ_VOICE_SETTING_RP_SIZE 3 ++ ++#define OCF_WRITE_VOICE_SETTING 0x0026 ++typedef struct { ++ __u16 voice_setting; ++} __attribute__ ((packed)) write_voice_setting_cp; ++#define WRITE_VOICE_SETTING_CP_SIZE 2 ++ ++#define OCF_HOST_BUFFER_SIZE 0x0033 ++typedef struct { ++ __u16 acl_mtu; ++ __u8 sco_mtu; ++ __u16 acl_max_pkt; ++ __u16 sco_max_pkt; ++} __attribute__ ((packed)) host_buffer_size_cp; ++#define HOST_BUFFER_SIZE_CP_SIZE 7 ++ + /* Link Control */ + #define OGF_LINK_CTL 0x01 +-#define OCF_CREATE_CONN 0x0005 ++#define OCF_CREATE_CONN 0x0005 + typedef struct { + bdaddr_t bdaddr; + __u16 pkt_type; +@@ -246,6 +317,13 @@ + } __attribute__ ((packed)) accept_conn_req_cp; + #define ACCEPT_CONN_REQ_CP_SIZE 7 + ++#define OCF_REJECT_CONN_REQ 0x000a ++typedef struct { ++ bdaddr_t bdaddr; ++ __u8 reason; ++} __attribute__ ((packed)) reject_conn_req_cp; ++#define REJECT_CONN_REQ_CP_SIZE 7 ++ + #define OCF_DISCONNECT 0x0006 + typedef struct { + __u16 handle; +@@ -253,17 +331,142 @@ + } __attribute__ ((packed)) disconnect_cp; + #define DISCONNECT_CP_SIZE 3 + ++#define OCF_ADD_SCO 0x0007 ++typedef struct { ++ __u16 handle; ++ __u16 pkt_type; ++} __attribute__ ((packed)) add_sco_cp; ++#define ADD_SCO_CP_SIZE 4 ++ + #define OCF_INQUIRY 0x0001 + typedef struct { + __u8 lap[3]; +- __u8 lenght; ++ __u8 length; + __u8 num_rsp; + } __attribute__ ((packed)) inquiry_cp; + #define INQUIRY_CP_SIZE 5 + +-#define OGF_LINK_POLICY 0x02 /* Link Policy */ ++typedef struct { ++ __u8 status; ++ bdaddr_t bdaddr; ++} __attribute__ ((packed)) status_bdaddr_rp; ++#define STATUS_BDADDR_RP_SIZE 7 ++ ++#define OCF_INQUIRY_CANCEL 0x0002 ++ ++#define OCF_LINK_KEY_REPLY 0x000B ++#define OCF_LINK_KEY_NEG_REPLY 0x000C ++typedef struct { ++ bdaddr_t bdaddr; ++ __u8 link_key[16]; ++} __attribute__ ((packed)) link_key_reply_cp; ++#define LINK_KEY_REPLY_CP_SIZE 22 ++ ++#define OCF_PIN_CODE_REPLY 0x000D ++#define OCF_PIN_CODE_NEG_REPLY 0x000E ++typedef struct { ++ bdaddr_t bdaddr; ++ __u8 pin_len; ++ __u8 pin_code[16]; ++} __attribute__ ((packed)) pin_code_reply_cp; ++#define PIN_CODE_REPLY_CP_SIZE 23 ++ ++#define OCF_CHANGE_CONN_PTYPE 0x000F ++typedef struct { ++ __u16 handle; ++ __u16 pkt_type; ++} __attribute__ ((packed)) change_conn_ptype_cp; ++#define CHANGE_CONN_PTYPE_CP_SIZE 4 ++ ++#define OCF_AUTH_REQUESTED 0x0011 ++typedef struct { ++ __u16 handle; ++} __attribute__ ((packed)) auth_requested_cp; ++#define AUTH_REQUESTED_CP_SIZE 2 ++ ++#define OCF_SET_CONN_ENCRYPT 0x0013 ++typedef struct { ++ __u16 handle; ++ __u8 encrypt; ++} __attribute__ ((packed)) set_conn_encrypt_cp; ++#define SET_CONN_ENCRYPT_CP_SIZE 3 ++ ++#define OCF_REMOTE_NAME_REQ 0x0019 ++typedef struct { ++ bdaddr_t bdaddr; ++ __u8 pscan_rep_mode; ++ __u8 pscan_mode; ++ __u16 clock_offset; ++} __attribute__ ((packed)) remote_name_req_cp; ++#define REMOTE_NAME_REQ_CP_SIZE 10 ++ ++#define OCF_READ_REMOTE_FEATURES 0x001B ++typedef struct { ++ __u16 handle; ++} __attribute__ ((packed)) read_remote_features_cp; ++#define READ_REMOTE_FEATURES_CP_SIZE 2 ++ ++#define OCF_READ_REMOTE_VERSION 0x001D ++typedef struct { ++ __u16 handle; ++} __attribute__ ((packed)) read_remote_version_cp; ++#define READ_REMOTE_VERSION_CP_SIZE 2 ++ ++/* Link Policy */ ++#define OGF_LINK_POLICY 0x02 ++#define OCF_ROLE_DISCOVERY 0x0009 ++typedef struct { ++ __u16 handle; ++} __attribute__ ((packed)) role_discovery_cp; ++#define ROLE_DISCOVERY_CP_SIZE 2 ++typedef struct { ++ __u8 status; ++ __u16 handle; ++ __u8 role; ++} __attribute__ ((packed)) role_discovery_rp; ++#define ROLE_DISCOVERY_RP_SIZE 4 + +-/* --------- HCI Events --------- */ ++#define OCF_READ_LINK_POLICY 0x000C ++typedef struct { ++ __u16 handle; ++} __attribute__ ((packed)) read_link_policy_cp; ++#define READ_LINK_POLICY_CP_SIZE 2 ++typedef struct { ++ __u8 status; ++ __u16 handle; ++ __u16 policy; ++} __attribute__ ((packed)) read_link_policy_rp; ++#define READ_LINK_POLICY_RP_SIZE 5 ++ ++#define OCF_SWITCH_ROLE 0x000B ++typedef struct { ++ bdaddr_t bdaddr; ++ __u8 role; ++} __attribute__ ((packed)) switch_role_cp; ++#define SWITCH_ROLE_CP_SIZE 7 ++ ++#define OCF_WRITE_LINK_POLICY 0x000D ++typedef struct { ++ __u16 handle; ++ __u16 policy; ++} __attribute__ ((packed)) write_link_policy_cp; ++#define WRITE_LINK_POLICY_CP_SIZE 4 ++typedef struct { ++ __u8 status; ++ __u16 handle; ++} __attribute__ ((packed)) write_link_policy_rp; ++#define WRITE_LINK_POLICY_RP_SIZE 3 ++ ++/* Status params */ ++#define OGF_STATUS_PARAM 0x05 ++ ++/* Testing commands */ ++#define OGF_TESTING_CMD 0x3e ++ ++/* Vendor specific commands */ ++#define OGF_VENDOR_CMD 0x3f ++ ++/* ---- HCI Events ---- */ + #define EVT_INQUIRY_COMPLETE 0x01 + + #define EVT_INQUIRY_RESULT 0x02 +@@ -272,7 +475,7 @@ + __u8 pscan_rep_mode; + __u8 pscan_period_mode; + __u8 pscan_mode; +- __u8 class[3]; ++ __u8 dev_class[3]; + __u16 clock_offset; + } __attribute__ ((packed)) inquiry_info; + #define INQUIRY_INFO_SIZE 14 +@@ -303,6 +506,44 @@ + } __attribute__ ((packed)) evt_disconn_complete; + #define EVT_DISCONN_COMPLETE_SIZE 4 + ++#define EVT_AUTH_COMPLETE 0x06 ++typedef struct { ++ __u8 status; ++ __u16 handle; ++} __attribute__ ((packed)) evt_auth_complete; ++#define EVT_AUTH_COMPLETE_SIZE 3 ++ ++#define EVT_REMOTE_NAME_REQ_COMPLETE 0x07 ++typedef struct { ++ __u8 status; ++ bdaddr_t bdaddr; ++ __u8 name[248]; ++} __attribute__ ((packed)) evt_remote_name_req_complete; ++#define EVT_REMOTE_NAME_REQ_COMPLETE_SIZE 255 ++ ++#define EVT_ENCRYPT_CHANGE 0x08 ++typedef struct { ++ __u8 status; ++ __u16 handle; ++ __u8 encrypt; ++} __attribute__ ((packed)) evt_encrypt_change; ++#define EVT_ENCRYPT_CHANGE_SIZE 5 ++ ++#define EVT_QOS_SETUP_COMPLETE 0x0D ++typedef struct { ++ __u8 service_type; ++ __u32 token_rate; ++ __u32 peak_bandwidth; ++ __u32 latency; ++ __u32 delay_variation; ++} __attribute__ ((packed)) hci_qos; ++typedef struct { ++ __u8 status; ++ __u16 handle; ++ hci_qos qos; ++} __attribute__ ((packed)) evt_qos_setup_complete; ++#define EVT_QOS_SETUP_COMPLETE_SIZE 20 ++ + #define EVT_CMD_COMPLETE 0x0e + typedef struct { + __u8 ncmd; +@@ -321,16 +562,78 @@ + #define EVT_NUM_COMP_PKTS 0x13 + typedef struct { + __u8 num_hndl; +- /* variable lenght part */ ++ /* variable length part */ + } __attribute__ ((packed)) evt_num_comp_pkts; + #define EVT_NUM_COMP_PKTS_SIZE 1 + +-#define EVT_HCI_DEV_EVENT 0xfd ++#define EVT_ROLE_CHANGE 0x12 ++typedef struct { ++ __u8 status; ++ bdaddr_t bdaddr; ++ __u8 role; ++} __attribute__ ((packed)) evt_role_change; ++#define EVT_ROLE_CHANGE_SIZE 8 ++ ++#define EVT_PIN_CODE_REQ 0x16 ++typedef struct { ++ bdaddr_t bdaddr; ++} __attribute__ ((packed)) evt_pin_code_req; ++#define EVT_PIN_CODE_REQ_SIZE 6 ++ ++#define EVT_LINK_KEY_REQ 0x17 ++typedef struct { ++ bdaddr_t bdaddr; ++} __attribute__ ((packed)) evt_link_key_req; ++#define EVT_LINK_KEY_REQ_SIZE 6 ++ ++#define EVT_LINK_KEY_NOTIFY 0x18 ++typedef struct { ++ bdaddr_t bdaddr; ++ __u8 link_key[16]; ++ __u8 key_type; ++} __attribute__ ((packed)) evt_link_key_notify; ++#define EVT_LINK_KEY_NOTIFY_SIZE 23 ++ ++#define EVT_READ_REMOTE_FEATURES_COMPLETE 0x0B ++typedef struct { ++ __u8 status; ++ __u16 handle; ++ __u8 features[8]; ++} __attribute__ ((packed)) evt_read_remote_features_complete; ++#define EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE 11 ++ ++#define EVT_READ_REMOTE_VERSION_COMPLETE 0x0C ++typedef struct { ++ __u8 status; ++ __u16 handle; ++ __u8 lmp_ver; ++ __u16 manufacturer; ++ __u16 lmp_subver; ++} __attribute__ ((packed)) evt_read_remote_version_complete; ++#define EVT_READ_REMOTE_VERSION_COMPLETE_SIZE 8 ++ ++/* Internal events generated by BlueZ stack */ ++#define EVT_STACK_INTERNAL 0xfd ++typedef struct { ++ __u16 type; ++ __u8 data[0]; ++} __attribute__ ((packed)) evt_stack_internal; ++#define EVT_STACK_INTERNAL_SIZE 2 ++ ++#define EVT_SI_DEVICE 0x01 ++typedef struct { ++ __u16 event; ++ __u16 dev_id; ++} __attribute__ ((packed)) evt_si_device; ++#define EVT_SI_DEVICE_SIZE 4 ++ ++#define EVT_SI_SECURITY 0x02 + typedef struct { + __u16 event; +- __u16 param; +-} __attribute__ ((packed)) evt_hci_dev_event; +-#define EVT_HCI_DEV_EVENT_SIZE 4 ++ __u16 proto; ++ __u16 subproto; ++ __u8 incomming; ++} __attribute__ ((packed)) evt_si_security; + + /* -------- HCI Packet structures -------- */ + #define HCI_TYPE_LEN 1 +@@ -369,14 +672,14 @@ + #define acl_handle(h) (h & 0x0fff) + #define acl_flags(h) (h >> 12) + +-#endif /* _NO_HCI_DEFS */ +- + /* HCI Socket options */ +-#define HCI_DATA_DIR 0x0001 +-#define HCI_FILTER 0x0002 ++#define HCI_DATA_DIR 1 ++#define HCI_FILTER 2 ++#define HCI_TIME_STAMP 3 + + /* HCI CMSG flags */ + #define HCI_CMSG_DIR 0x0001 ++#define HCI_CMSG_TSTAMP 0x0002 + + struct sockaddr_hci { + sa_family_t hci_family; +@@ -387,27 +690,29 @@ + struct hci_filter { + __u32 type_mask; + __u32 event_mask[2]; ++ __u16 opcode; + }; + +-struct hci_dev_req { +- __u16 dev_id; +- __u32 dev_opt; +-}; +- +-struct hci_dev_list_req { +- __u16 dev_num; +- struct hci_dev_req dev_req[0]; /* hci_dev_req structures */ +-}; +- +-struct hci_inquiry_req { +- __u16 dev_id; +- __u16 flags; +- __u8 lap[3]; +- __u8 length; +- __u8 num_rsp; +-}; +-#define IREQ_CACHE_FLUSH 0x0001 ++#define HCI_FLT_TYPE_BITS 31 ++#define HCI_FLT_EVENT_BITS 63 ++#define HCI_FLT_OGF_BITS 63 ++#define HCI_FLT_OCF_BITS 127 ++ ++#if BITS_PER_LONG == 64 ++static inline void hci_set_bit(int nr, void *addr) ++{ ++ *((__u32 *) addr + (nr >> 5)) |= ((__u32) 1 << (nr & 31)); ++} ++static inline int hci_test_bit(int nr, void *addr) ++{ ++ return *((__u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31)); ++} ++#else ++#define hci_set_bit set_bit ++#define hci_test_bit test_bit ++#endif + ++/* Ioctl requests structures */ + struct hci_dev_stats { + __u32 err_rx; + __u32 err_tx; +@@ -433,11 +738,13 @@ + __u8 features[8]; + + __u32 pkt_type; ++ __u32 link_policy; ++ __u32 link_mode; + + __u16 acl_mtu; +- __u16 acl_max; ++ __u16 acl_pkts; + __u16 sco_mtu; +- __u16 sco_max; ++ __u16 sco_pkts; + + struct hci_dev_stats stat; + }; +@@ -445,12 +752,48 @@ + struct hci_conn_info { + __u16 handle; + bdaddr_t bdaddr; ++ __u8 type; ++ __u8 out; ++ __u16 state; ++ __u32 link_mode; ++}; ++ ++struct hci_dev_req { ++ __u16 dev_id; ++ __u32 dev_opt; ++}; ++ ++struct hci_dev_list_req { ++ __u16 dev_num; ++ struct hci_dev_req dev_req[0]; /* hci_dev_req structures */ + }; + + struct hci_conn_list_req { + __u16 dev_id; + __u16 conn_num; + struct hci_conn_info conn_info[0]; ++}; ++ ++struct hci_conn_info_req { ++ bdaddr_t bdaddr; ++ __u8 type; ++ struct hci_conn_info conn_info[0]; ++}; ++ ++struct hci_inquiry_req { ++ __u16 dev_id; ++ __u16 flags; ++ __u8 lap[3]; ++ __u8 length; ++ __u8 num_rsp; ++}; ++#define IREQ_CACHE_FLUSH 0x0001 ++ ++struct hci_remotename_req { ++ __u16 dev_id; ++ __u16 flags; ++ bdaddr_t bdaddr; ++ __u8 name[248]; + }; + + #endif /* __HCI_H */ +diff -urN linux-2.4.18/include/net/bluetooth/hci_core.h linux-2.4.18-mh9/include/net/bluetooth/hci_core.h +--- linux-2.4.18/include/net/bluetooth/hci_core.h Fri Sep 7 18:28:38 2001 ++++ linux-2.4.18-mh9/include/net/bluetooth/hci_core.h Mon Aug 25 18:38:12 2003 +@@ -23,7 +23,7 @@ + */ + + /* +- * $Id$ ++ * $Id$ + */ + + #ifndef __HCI_CORE_H +@@ -32,14 +32,12 @@ + #include <net/bluetooth/hci.h> + + /* HCI upper protocols */ +-#define HCI_MAX_PROTO 1 + #define HCI_PROTO_L2CAP 0 ++#define HCI_PROTO_SCO 1 + + #define HCI_INIT_TIMEOUT (HZ * 10) + +-/* ----- Inquiry cache ----- */ +-#define INQUIRY_CACHE_AGE_MAX (HZ*5) // 5 seconds +-#define INQUIRY_ENTRY_AGE_MAX (HZ*60) // 60 seconds ++/* HCI Core structures */ + + struct inquiry_entry { + struct inquiry_entry *next; +@@ -53,111 +51,182 @@ + struct inquiry_entry *list; + }; + +-static inline void inquiry_cache_init(struct inquiry_cache *cache) +-{ +- spin_lock_init(&cache->lock); +- cache->list = NULL; +-} ++struct conn_hash { ++ struct list_head list; ++ spinlock_t lock; ++ unsigned int num; ++}; + +-static inline void inquiry_cache_lock(struct inquiry_cache *cache) +-{ +- spin_lock(&cache->lock); +-} ++struct hci_dev { ++ struct list_head list; ++ spinlock_t lock; ++ atomic_t refcnt; + +-static inline void inquiry_cache_unlock(struct inquiry_cache *cache) +-{ +- spin_unlock(&cache->lock); +-} ++ char name[8]; ++ unsigned long flags; ++ __u16 id; ++ __u8 type; ++ bdaddr_t bdaddr; ++ __u8 features[8]; ++ __u16 voice_setting; + +-static inline void inquiry_cache_lock_bh(struct inquiry_cache *cache) +-{ +- spin_lock_bh(&cache->lock); +-} ++ __u16 pkt_type; ++ __u16 link_policy; ++ __u16 link_mode; + +-static inline void inquiry_cache_unlock_bh(struct inquiry_cache *cache) +-{ +- spin_unlock_bh(&cache->lock); +-} ++ atomic_t cmd_cnt; ++ unsigned int acl_cnt; ++ unsigned int sco_cnt; + +-static inline long inquiry_cache_age(struct inquiry_cache *cache) +-{ +- return jiffies - cache->timestamp; +-} ++ unsigned int acl_mtu; ++ unsigned int sco_mtu; ++ unsigned int acl_pkts; ++ unsigned int sco_pkts; + +-static inline long inquiry_entry_age(struct inquiry_entry *e) +-{ +- return jiffies - e->timestamp; +-} +-extern void inquiry_cache_flush(struct inquiry_cache *cache); ++ unsigned long cmd_last_tx; ++ unsigned long acl_last_tx; ++ unsigned long sco_last_tx; ++ ++ struct tasklet_struct cmd_task; ++ struct tasklet_struct rx_task; ++ struct tasklet_struct tx_task; + +-struct hci_dev; ++ struct sk_buff_head rx_q; ++ struct sk_buff_head raw_q; ++ struct sk_buff_head cmd_q; ++ ++ struct sk_buff *sent_cmd; ++ ++ struct semaphore req_lock; ++ wait_queue_head_t req_wait_q; ++ __u32 req_status; ++ __u32 req_result; ++ ++ struct inquiry_cache inq_cache; ++ struct conn_hash conn_hash; ++ ++ struct hci_dev_stats stat; ++ ++ void *driver_data; ++ void *core_data; ++ ++ atomic_t promisc; ++ ++ int (*open)(struct hci_dev *hdev); ++ int (*close)(struct hci_dev *hdev); ++ int (*flush)(struct hci_dev *hdev); ++ int (*send)(struct sk_buff *skb); ++ void (*destruct)(struct hci_dev *hdev); ++ void (*notify)(struct hci_dev *hdev, unsigned int evt, unsigned long arg); ++ int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg); ++}; + +-/* ----- HCI Connections ----- */ + struct hci_conn { + struct list_head list; ++ ++ atomic_t refcnt; ++ spinlock_t lock; ++ + bdaddr_t dst; + __u16 handle; ++ __u16 state; + __u8 type; +- unsigned int sent; ++ __u8 out; ++ __u32 link_mode; ++ unsigned long pend; ++ ++ unsigned int sent; ++ ++ struct sk_buff_head data_q; + ++ struct timer_list timer; ++ + struct hci_dev *hdev; + void *l2cap_data; ++ void *sco_data; + void *priv; + +- struct sk_buff_head data_q; ++ struct hci_conn *link; + }; + +-struct conn_hash { +- struct list_head list; +- spinlock_t lock; +- unsigned int num; +-}; ++extern struct hci_proto *hci_proto[]; ++extern struct list_head hdev_list; ++extern rwlock_t hdev_list_lock; ++ ++/* ----- Inquiry cache ----- */ ++#define INQUIRY_CACHE_AGE_MAX (HZ*30) // 30 seconds ++#define INQUIRY_ENTRY_AGE_MAX (HZ*60) // 60 seconds ++ ++#define inquiry_cache_lock(c) spin_lock(&c->lock) ++#define inquiry_cache_unlock(c) spin_unlock(&c->lock) ++#define inquiry_cache_lock_bh(c) spin_lock_bh(&c->lock) ++#define inquiry_cache_unlock_bh(c) spin_unlock_bh(&c->lock) + +-static inline void conn_hash_init(struct conn_hash *h) ++static inline void inquiry_cache_init(struct hci_dev *hdev) + { +- INIT_LIST_HEAD(&h->list); +- spin_lock_init(&h->lock); +- h->num = 0; ++ struct inquiry_cache *c = &hdev->inq_cache; ++ spin_lock_init(&c->lock); ++ c->list = NULL; + } + +-static inline void conn_hash_lock(struct conn_hash *h) ++static inline long inquiry_cache_age(struct hci_dev *hdev) + { +- spin_lock(&h->lock); ++ struct inquiry_cache *c = &hdev->inq_cache; ++ return jiffies - c->timestamp; + } + +-static inline void conn_hash_unlock(struct conn_hash *h) ++static inline long inquiry_entry_age(struct inquiry_entry *e) + { +- spin_unlock(&h->lock); ++ return jiffies - e->timestamp; + } + +-static inline void __conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c) ++struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr); ++void inquiry_cache_update(struct hci_dev *hdev, inquiry_info *info); ++void inquiry_cache_flush(struct hci_dev *hdev); ++int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf); ++ ++/* ----- HCI Connections ----- */ ++enum { ++ HCI_CONN_AUTH_PEND, ++ HCI_CONN_ENCRYPT_PEND ++}; ++ ++#define hci_conn_lock(c) spin_lock(&c->lock) ++#define hci_conn_unlock(c) spin_unlock(&c->lock) ++#define hci_conn_lock_bh(c) spin_lock_bh(&c->lock) ++#define hci_conn_unlock_bh(c) spin_unlock_bh(&c->lock) ++ ++#define conn_hash_lock(d) spin_lock(&d->conn_hash->lock) ++#define conn_hash_unlock(d) spin_unlock(&d->conn_hash->lock) ++#define conn_hash_lock_bh(d) spin_lock_bh(&d->conn_hash->lock) ++#define conn_hash_unlock_bh(d) spin_unlock_bh(&d->conn_hash->lock) ++ ++static inline void conn_hash_init(struct hci_dev *hdev) + { +- list_add(&c->list, &h->list); +- h->num++; ++ struct conn_hash *h = &hdev->conn_hash; ++ INIT_LIST_HEAD(&h->list); ++ spin_lock_init(&h->lock); ++ h->num = 0; + } + +-static inline void conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c) ++static inline void conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) + { +- conn_hash_lock(h); +- __conn_hash_add(h, handle, c); +- conn_hash_unlock(h); ++ struct conn_hash *h = &hdev->conn_hash; ++ list_add(&c->list, &h->list); ++ h->num++; + } + +-static inline void __conn_hash_del(struct conn_hash *h, struct hci_conn *c) ++static inline void conn_hash_del(struct hci_dev *hdev, struct hci_conn *c) + { ++ struct conn_hash *h = &hdev->conn_hash; + list_del(&c->list); + h->num--; + } + +-static inline void conn_hash_del(struct conn_hash *h, struct hci_conn *c) +-{ +- conn_hash_lock(h); +- __conn_hash_del(h, c); +- conn_hash_unlock(h); +-} +- +-static inline struct hci_conn *__conn_hash_lookup(struct conn_hash *h, __u16 handle) ++static inline struct hci_conn *conn_hash_lookup_handle(struct hci_dev *hdev, ++ __u16 handle) + { ++ register struct conn_hash *h = &hdev->conn_hash; + register struct list_head *p; + register struct hci_conn *c; + +@@ -169,101 +238,95 @@ + return NULL; + } + +-static inline struct hci_conn *conn_hash_lookup(struct conn_hash *h, __u16 handle) ++static inline struct hci_conn *conn_hash_lookup_ba(struct hci_dev *hdev, ++ __u8 type, bdaddr_t *ba) + { +- struct hci_conn *conn; ++ register struct conn_hash *h = &hdev->conn_hash; ++ register struct list_head *p; ++ register struct hci_conn *c; + +- conn_hash_lock(h); +- conn = __conn_hash_lookup(h, handle); +- conn_hash_unlock(h); +- return conn; ++ list_for_each(p, &h->list) { ++ c = list_entry(p, struct hci_conn, list); ++ if (c->type == type && !bacmp(&c->dst, ba)) ++ return c; ++ } ++ return NULL; + } + +-/* ----- HCI Devices ----- */ +-struct hci_dev { +- atomic_t refcnt; +- +- char name[8]; +- __u32 flags; +- __u16 id; +- __u8 type; +- bdaddr_t bdaddr; +- __u8 features[8]; +- +- __u16 pkt_type; +- +- atomic_t cmd_cnt; +- unsigned int acl_cnt; +- unsigned int sco_cnt; +- +- unsigned int acl_mtu; +- unsigned int sco_mtu; +- unsigned int acl_max; +- unsigned int sco_max; +- +- void *driver_data; +- void *l2cap_data; +- void *priv; +- +- struct tasklet_struct cmd_task; +- struct tasklet_struct rx_task; +- struct tasklet_struct tx_task; +- +- struct sk_buff_head rx_q; +- struct sk_buff_head raw_q; +- struct sk_buff_head cmd_q; +- +- struct sk_buff *sent_cmd; +- +- struct semaphore req_lock; +- wait_queue_head_t req_wait_q; +- __u32 req_status; +- __u32 req_result; +- +- struct inquiry_cache inq_cache; ++void hci_acl_connect(struct hci_conn *conn); ++void hci_acl_disconn(struct hci_conn *conn, __u8 reason); ++void hci_add_sco(struct hci_conn *conn, __u16 handle); + +- struct conn_hash conn_hash; ++struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst); ++int hci_conn_del(struct hci_conn *conn); ++void hci_conn_hash_flush(struct hci_dev *hdev); + +- struct hci_dev_stats stat; ++struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src); ++int hci_conn_auth(struct hci_conn *conn); ++int hci_conn_encrypt(struct hci_conn *conn); + +- int (*open)(struct hci_dev *hdev); +- int (*close)(struct hci_dev *hdev); +- int (*flush)(struct hci_dev *hdev); +- int (*send)(struct sk_buff *skb); +-}; ++static inline void hci_conn_set_timer(struct hci_conn *conn, long timeout) ++{ ++ mod_timer(&conn->timer, jiffies + timeout); ++} + +-static inline void hci_dev_hold(struct hci_dev *hdev) ++static inline void hci_conn_del_timer(struct hci_conn *conn) + { +- atomic_inc(&hdev->refcnt); ++ del_timer(&conn->timer); + } + +-static inline void hci_dev_put(struct hci_dev *hdev) ++static inline void hci_conn_hold(struct hci_conn *conn) + { +- atomic_dec(&hdev->refcnt); ++ atomic_inc(&conn->refcnt); ++ hci_conn_del_timer(conn); + } + +-extern struct hci_dev *hci_dev_get(int index); +-extern int hci_register_dev(struct hci_dev *hdev); +-extern int hci_unregister_dev(struct hci_dev *hdev); +-extern int hci_dev_open(__u16 dev); +-extern int hci_dev_close(__u16 dev); +-extern int hci_dev_reset(__u16 dev); +-extern int hci_dev_reset_stat(__u16 dev); +-extern int hci_dev_info(unsigned long arg); +-extern int hci_dev_list(unsigned long arg); +-extern int hci_dev_setscan(unsigned long arg); +-extern int hci_dev_setauth(unsigned long arg); +-extern int hci_dev_setptype(unsigned long arg); +-extern int hci_conn_list(unsigned long arg); +-extern int hci_inquiry(unsigned long arg); ++static inline void hci_conn_put(struct hci_conn *conn) ++{ ++ if (atomic_dec_and_test(&conn->refcnt)) { ++ if (conn->type == SCO_LINK) ++ hci_conn_set_timer(conn, HZ / 100); ++ else if (conn->out) ++ hci_conn_set_timer(conn, HCI_DISCONN_TIMEOUT); ++ } ++} + +-extern __u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode); +-extern __u32 hci_dev_getmode(struct hci_dev *hdev); ++/* ----- HCI Devices ----- */ ++static inline void hci_dev_put(struct hci_dev *d) ++{ ++ if (atomic_dec_and_test(&d->refcnt)) ++ d->destruct(d); ++} ++#define hci_dev_hold(d) atomic_inc(&d->refcnt) ++ ++#define hci_dev_lock(d) spin_lock(&d->lock) ++#define hci_dev_unlock(d) spin_unlock(&d->lock) ++#define hci_dev_lock_bh(d) spin_lock_bh(&d->lock) ++#define hci_dev_unlock_bh(d) spin_unlock_bh(&d->lock) ++ ++struct hci_dev *hci_dev_get(int index); ++struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst); ++int hci_register_dev(struct hci_dev *hdev); ++int hci_unregister_dev(struct hci_dev *hdev); ++int hci_suspend_dev(struct hci_dev *hdev); ++int hci_resume_dev(struct hci_dev *hdev); ++int hci_dev_open(__u16 dev); ++int hci_dev_close(__u16 dev); ++int hci_dev_reset(__u16 dev); ++int hci_dev_reset_stat(__u16 dev); ++int hci_dev_cmd(unsigned int cmd, unsigned long arg); ++int hci_get_dev_list(unsigned long arg); ++int hci_get_dev_info(unsigned long arg); ++int hci_get_conn_list(unsigned long arg); ++int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg); ++int hci_inquiry(unsigned long arg); + +-extern int hci_recv_frame(struct sk_buff *skb); ++int hci_recv_frame(struct sk_buff *skb); ++void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); + + /* ----- LMP capabilities ----- */ + #define lmp_rswitch_capable(dev) (dev->features[0] & LMP_RSWITCH) ++#define lmp_encrypt_capable(dev) (dev->features[0] & LMP_ENCRYPT) + + /* ----- HCI tasks ----- */ + static inline void hci_sched_cmd(struct hci_dev *hdev) +@@ -284,43 +347,130 @@ + /* ----- HCI protocols ----- */ + struct hci_proto { + char *name; +- __u32 id; +- __u32 flags; ++ unsigned int id; ++ unsigned long flags; + + void *priv; + +- int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr); +- int (*connect_cfm) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *conn); ++ int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type); ++ int (*connect_cfm) (struct hci_conn *conn, __u8 status); + int (*disconn_ind) (struct hci_conn *conn, __u8 reason); +- int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb , __u16 flags); ++ int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags); + int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb); ++ int (*auth_cfm) (struct hci_conn *conn, __u8 status); ++ int (*encrypt_cfm) (struct hci_conn *conn, __u8 status); + }; + +-extern int hci_register_proto(struct hci_proto *hproto); +-extern int hci_unregister_proto(struct hci_proto *hproto); +-extern int hci_register_notifier(struct notifier_block *nb); +-extern int hci_unregister_notifier(struct notifier_block *nb); +-extern int hci_connect(struct hci_dev * hdev, bdaddr_t * bdaddr); +-extern int hci_disconnect(struct hci_conn *conn, __u8 reason); +-extern int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void * param); +-extern int hci_send_raw(struct sk_buff *skb); +-extern int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags); +-extern int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); ++static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) ++{ ++ register struct hci_proto *hp; ++ int mask = 0; ++ ++ hp = hci_proto[HCI_PROTO_L2CAP]; ++ if (hp && hp->connect_ind) ++ mask |= hp->connect_ind(hdev, bdaddr, type); ++ ++ hp = hci_proto[HCI_PROTO_SCO]; ++ if (hp && hp->connect_ind) ++ mask |= hp->connect_ind(hdev, bdaddr, type); ++ ++ return mask; ++} ++ ++static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status) ++{ ++ register struct hci_proto *hp; ++ ++ hp = hci_proto[HCI_PROTO_L2CAP]; ++ if (hp && hp->connect_cfm) ++ hp->connect_cfm(conn, status); ++ ++ hp = hci_proto[HCI_PROTO_SCO]; ++ if (hp && hp->connect_cfm) ++ hp->connect_cfm(conn, status); ++} ++ ++static inline void hci_proto_disconn_ind(struct hci_conn *conn, __u8 reason) ++{ ++ register struct hci_proto *hp; ++ ++ hp = hci_proto[HCI_PROTO_L2CAP]; ++ if (hp && hp->disconn_ind) ++ hp->disconn_ind(conn, reason); ++ ++ hp = hci_proto[HCI_PROTO_SCO]; ++ if (hp && hp->disconn_ind) ++ hp->disconn_ind(conn, reason); ++} ++ ++static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status) ++{ ++ register struct hci_proto *hp; ++ ++ hp = hci_proto[HCI_PROTO_L2CAP]; ++ if (hp && hp->auth_cfm) ++ hp->auth_cfm(conn, status); ++ ++ hp = hci_proto[HCI_PROTO_SCO]; ++ if (hp && hp->auth_cfm) ++ hp->auth_cfm(conn, status); ++} ++ ++static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status) ++{ ++ register struct hci_proto *hp; ++ ++ hp = hci_proto[HCI_PROTO_L2CAP]; ++ if (hp && hp->encrypt_cfm) ++ hp->encrypt_cfm(conn, status); ++ ++ hp = hci_proto[HCI_PROTO_SCO]; ++ if (hp && hp->encrypt_cfm) ++ hp->encrypt_cfm(conn, status); ++} ++ ++int hci_register_proto(struct hci_proto *hproto); ++int hci_unregister_proto(struct hci_proto *hproto); ++int hci_register_notifier(struct notifier_block *nb); ++int hci_unregister_notifier(struct notifier_block *nb); ++ ++int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param); ++int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags); ++int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); ++ ++void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf); ++ ++void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data); + + /* ----- HCI Sockets ----- */ +-extern void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); ++void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); + + /* HCI info for socket */ +-#define hci_pi(sk) ((struct hci_pinfo *) &sk->protinfo) ++#define hci_pi(sk) ((struct hci_pinfo *) &sk->tp_pinfo) + struct hci_pinfo { + struct hci_dev *hdev; + struct hci_filter filter; + __u32 cmsg_mask; + }; + ++/* HCI security filter */ ++#define HCI_SFLT_MAX_OGF 5 ++ ++struct hci_sec_filter { ++ __u32 type_mask; ++ __u32 event_mask[2]; ++ __u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4]; ++}; ++ + /* ----- HCI requests ----- */ + #define HCI_REQ_DONE 0 + #define HCI_REQ_PEND 1 + #define HCI_REQ_CANCELED 2 ++ ++#define hci_req_lock(d) down(&d->req_lock) ++#define hci_req_unlock(d) up(&d->req_lock) ++ ++void hci_req_complete(struct hci_dev *hdev, int result); ++void hci_req_cancel(struct hci_dev *hdev, int err); + + #endif /* __HCI_CORE_H */ +diff -urN linux-2.4.18/include/net/bluetooth/hci_uart.h linux-2.4.18-mh9/include/net/bluetooth/hci_uart.h +--- linux-2.4.18/include/net/bluetooth/hci_uart.h Fri Sep 7 18:28:38 2001 ++++ linux-2.4.18-mh9/include/net/bluetooth/hci_uart.h Thu Jan 1 01:00:00 1970 +@@ -1,62 +0,0 @@ +-/* +- BlueZ - Bluetooth protocol stack for Linux +- Copyright (C) 2000-2001 Qualcomm Incorporated +- +- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; +- +- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY +- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES +- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- +- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, +- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS +- SOFTWARE IS DISCLAIMED. +-*/ +- +-/* +- * $Id$ +- */ +- +-#ifndef N_HCI +-#define N_HCI 15 +-#endif +- +-#ifdef __KERNEL__ +- +-#define tty2n_hci(tty) ((struct n_hci *)((tty)->disc_data)) +-#define n_hci2tty(n_hci) ((n_hci)->tty) +- +-struct n_hci { +- struct tty_struct *tty; +- struct hci_dev hdev; +- +- struct sk_buff_head txq; +- unsigned long tx_state; +- +- spinlock_t rx_lock; +- unsigned long rx_state; +- unsigned long rx_count; +- struct sk_buff *rx_skb; +-}; +- +-/* Transmit states */ +-#define TRANS_SENDING 1 +-#define TRANS_WAKEUP 2 +- +-/* Receiver States */ +-#define WAIT_PACKET_TYPE 0 +-#define WAIT_EVENT_HDR 1 +-#define WAIT_ACL_HDR 2 +-#define WAIT_SCO_HDR 3 +-#define WAIT_DATA 4 +- +-#endif /* __KERNEL__ */ +diff -urN linux-2.4.18/include/net/bluetooth/hci_usb.h linux-2.4.18-mh9/include/net/bluetooth/hci_usb.h +--- linux-2.4.18/include/net/bluetooth/hci_usb.h Fri Sep 7 18:28:38 2001 ++++ linux-2.4.18-mh9/include/net/bluetooth/hci_usb.h Thu Jan 1 01:00:00 1970 +@@ -1,68 +0,0 @@ +-/* +- BlueZ - Bluetooth protocol stack for Linux +- Copyright (C) 2000-2001 Qualcomm Incorporated +- +- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; +- +- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY +- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES +- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- +- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, +- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS +- SOFTWARE IS DISCLAIMED. +-*/ +- +-/* +- * $Id$ +- */ +- +-#ifdef __KERNEL__ +- +-/* Class, SubClass, and Protocol codes that describe a Bluetooth device */ +-#define HCI_DEV_CLASS 0xe0 /* Wireless class */ +-#define HCI_DEV_SUBCLASS 0x01 /* RF subclass */ +-#define HCI_DEV_PROTOCOL 0x01 /* Bluetooth programming protocol */ +- +-#define HCI_CTRL_REQ 0x20 +- +-struct hci_usb { +- struct usb_device *udev; +- +- devrequest dev_req; +- struct urb *ctrl_urb; +- struct urb *intr_urb; +- struct urb *read_urb; +- struct urb *write_urb; +- +- __u8 *read_buf; +- __u8 *intr_buf; +- struct sk_buff *intr_skb; +- int intr_count; +- +- __u8 bulk_out_ep_addr; +- __u8 bulk_in_ep_addr; +- __u8 intr_in_ep_addr; +- __u8 intr_in_interval; +- +- struct hci_dev hdev; +- +- unsigned long tx_state; +- struct sk_buff_head tx_ctrl_q; +- struct sk_buff_head tx_write_q; +-}; +- +-/* Transmit states */ +-#define HCI_TX_CTRL 1 +-#define HCI_TX_WRITE 2 +- +-#endif /* __KERNEL__ */ +diff -urN linux-2.4.18/include/net/bluetooth/hci_vhci.h linux-2.4.18-mh9/include/net/bluetooth/hci_vhci.h +--- linux-2.4.18/include/net/bluetooth/hci_vhci.h Fri Sep 7 18:28:38 2001 ++++ linux-2.4.18-mh9/include/net/bluetooth/hci_vhci.h Thu Jan 1 01:00:00 1970 +@@ -1,50 +0,0 @@ +-/* +- BlueZ - Bluetooth protocol stack for Linux +- Copyright (C) 2000-2001 Qualcomm Incorporated +- +- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; +- +- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY +- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES +- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- +- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, +- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS +- SOFTWARE IS DISCLAIMED. +-*/ +- +-/* +- * $Id$ +- */ +- +-#ifndef __HCI_VHCI_H +-#define __HCI_VHCI_H +- +-#ifdef __KERNEL__ +- +-struct hci_vhci_struct { +- struct hci_dev hdev; +- __u32 flags; +- wait_queue_head_t read_wait; +- struct sk_buff_head readq; +- struct fasync_struct *fasync; +-}; +- +-/* VHCI device flags */ +-#define VHCI_FASYNC 0x0010 +- +-#endif /* __KERNEL__ */ +- +-#define VHCI_DEV "/dev/vhci" +-#define VHCI_MINOR 250 +- +-#endif /* __HCI_VHCI_H */ +diff -urN linux-2.4.18/include/net/bluetooth/l2cap.h linux-2.4.18-mh9/include/net/bluetooth/l2cap.h +--- linux-2.4.18/include/net/bluetooth/l2cap.h Fri Sep 7 18:28:38 2001 ++++ linux-2.4.18-mh9/include/net/bluetooth/l2cap.h Mon Aug 25 18:38:12 2003 +@@ -23,22 +23,17 @@ + */ + + /* +- * $Id$ ++ * $Id$ + */ + + #ifndef __L2CAP_H + #define __L2CAP_H + +-#include <asm/types.h> +-#include <asm/byteorder.h> +- + /* L2CAP defaults */ + #define L2CAP_DEFAULT_MTU 672 + #define L2CAP_DEFAULT_FLUSH_TO 0xFFFF + + #define L2CAP_CONN_TIMEOUT (HZ * 40) +-#define L2CAP_DISCONN_TIMEOUT (HZ * 2) +-#define L2CAP_CONN_IDLE_TIMEOUT (HZ * 60) + + /* L2CAP socket address */ + struct sockaddr_l2 { +@@ -47,17 +42,12 @@ + bdaddr_t l2_bdaddr; + }; + +-/* set/get sockopt defines */ +-#define L2CAP_OPTIONS 0x01 ++/* Socket options */ ++#define L2CAP_OPTIONS 0x01 + struct l2cap_options { + __u16 omtu; + __u16 imtu; + __u16 flush_to; +- __u32 token_rate; +- __u32 bucket_size; +- __u32 pick_band; +- __u32 latency; +- __u32 delay_var; + }; + + #define L2CAP_CONNINFO 0x02 +@@ -65,6 +55,27 @@ + __u16 hci_handle; + }; + ++#define L2CAP_LM 0x03 ++#define L2CAP_LM_MASTER 0x0001 ++#define L2CAP_LM_AUTH 0x0002 ++#define L2CAP_LM_ENCRYPT 0x0004 ++#define L2CAP_LM_TRUSTED 0x0008 ++#define L2CAP_LM_RELIABLE 0x0010 ++ ++#define L2CAP_QOS 0x04 ++struct l2cap_qos { ++ __u16 service_type; ++ __u32 token_rate; ++ __u32 token_bucket_size; ++ __u32 peak_bandwidth; ++ __u32 latency; ++ __u32 delay_variation; ++}; ++ ++#define L2CAP_SERV_NO_TRAFFIC 0x00 ++#define L2CAP_SERV_BEST_EFFORT 0x01 ++#define L2CAP_SERV_GUARANTEED 0x02 ++ + /* L2CAP command codes */ + #define L2CAP_COMMAND_REJ 0x01 + #define L2CAP_CONN_REQ 0x02 +@@ -79,7 +90,6 @@ + #define L2CAP_INFO_RSP 0x0b + + /* L2CAP structures */ +- + typedef struct { + __u16 len; + __u16 cid; +@@ -112,11 +122,17 @@ + } __attribute__ ((packed)) l2cap_conn_rsp; + #define L2CAP_CONN_RSP_SIZE 8 + +-#define L2CAP_CONN_SUCCESS 0x0000 +-#define L2CAP_CONN_PEND 0x0001 +-#define L2CAP_CONN_BAD_PSM 0x0002 +-#define L2CAP_CONN_SEC_BLOCK 0x0003 +-#define L2CAP_CONN_NO_MEM 0x0004 ++/* connect result */ ++#define L2CAP_CR_SUCCESS 0x0000 ++#define L2CAP_CR_PEND 0x0001 ++#define L2CAP_CR_BAD_PSM 0x0002 ++#define L2CAP_CR_SEC_BLOCK 0x0003 ++#define L2CAP_CR_NO_MEM 0x0004 ++ ++/* connect status */ ++#define L2CAP_CS_NO_INFO 0x0000 ++#define L2CAP_CS_AUTHEN_PEND 0x0001 ++#define L2CAP_CS_AUTHOR_PEND 0x0002 + + typedef struct { + __u16 dcid; +@@ -147,6 +163,8 @@ + #define L2CAP_CONF_FLUSH_TO 0x02 + #define L2CAP_CONF_QOS 0x03 + ++#define L2CAP_CONF_MAX_SIZE 22 ++ + typedef struct { + __u16 dcid; + __u16 scid; +@@ -158,5 +176,75 @@ + __u16 scid; + } __attribute__ ((packed)) l2cap_disconn_rsp; + #define L2CAP_DISCONN_RSP_SIZE 4 ++ ++typedef struct { ++ __u16 type; ++ __u8 data[0]; ++} __attribute__ ((packed)) l2cap_info_req; ++#define L2CAP_INFO_REQ_SIZE 2 ++ ++typedef struct { ++ __u16 type; ++ __u16 result; ++ __u8 data[0]; ++} __attribute__ ((packed)) l2cap_info_rsp; ++#define L2CAP_INFO_RSP_SIZE 4 ++ ++/* ----- L2CAP connections ----- */ ++struct l2cap_chan_list { ++ struct sock *head; ++ rwlock_t lock; ++ long num; ++}; ++ ++struct l2cap_conn { ++ struct hci_conn *hcon; ++ ++ bdaddr_t *dst; ++ bdaddr_t *src; ++ ++ unsigned int mtu; ++ ++ spinlock_t lock; ++ ++ struct sk_buff *rx_skb; ++ __u32 rx_len; ++ __u8 rx_ident; ++ __u8 tx_ident; ++ ++ struct l2cap_chan_list chan_list; ++}; ++ ++/* ----- L2CAP channel and socket info ----- */ ++#define l2cap_pi(sk) ((struct l2cap_pinfo *) &sk->tp_pinfo) ++ ++struct l2cap_pinfo { ++ __u16 psm; ++ __u16 dcid; ++ __u16 scid; ++ ++ __u16 imtu; ++ __u16 omtu; ++ __u16 flush_to; ++ ++ __u32 link_mode; ++ ++ __u8 conf_state; ++ __u8 conf_retry; ++ __u16 conf_mtu; ++ ++ __u8 ident; ++ ++ struct l2cap_conn *conn; ++ struct sock *next_c; ++ struct sock *prev_c; ++}; ++ ++#define L2CAP_CONF_REQ_SENT 0x01 ++#define L2CAP_CONF_INPUT_DONE 0x02 ++#define L2CAP_CONF_OUTPUT_DONE 0x04 ++#define L2CAP_CONF_MAX_RETRIES 2 ++ ++void l2cap_load(void); + + #endif /* __L2CAP_H */ +diff -urN linux-2.4.18/include/net/bluetooth/l2cap_core.h linux-2.4.18-mh9/include/net/bluetooth/l2cap_core.h +--- linux-2.4.18/include/net/bluetooth/l2cap_core.h Fri Sep 7 18:28:38 2001 ++++ linux-2.4.18-mh9/include/net/bluetooth/l2cap_core.h Thu Jan 1 01:00:00 1970 +@@ -1,144 +0,0 @@ +-/* +- BlueZ - Bluetooth protocol stack for Linux +- Copyright (C) 2000-2001 Qualcomm Incorporated +- +- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; +- +- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY +- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES +- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- +- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, +- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS +- SOFTWARE IS DISCLAIMED. +-*/ +- +-/* +- * $Id$ +- */ +- +-#ifndef __L2CAP_CORE_H +-#define __L2CAP_CORE_H +- +-#ifdef __KERNEL__ +- +-/* ----- L2CAP interface ----- */ +-struct l2cap_iff { +- struct list_head list; +- struct hci_dev *hdev; +- bdaddr_t *bdaddr; +- __u16 mtu; +- spinlock_t lock; +- struct list_head conn_list; +-}; +- +-static inline void l2cap_iff_lock(struct l2cap_iff *iff) +-{ +- spin_lock(&iff->lock); +-} +- +-static inline void l2cap_iff_unlock(struct l2cap_iff *iff) +-{ +- spin_unlock(&iff->lock); +-} +- +-/* ----- L2CAP connections ----- */ +-struct l2cap_chan_list { +- struct sock *head; +- rwlock_t lock; +- long num; +-}; +- +-struct l2cap_conn { +- struct l2cap_iff *iff; +- struct list_head list; +- +- struct hci_conn *hconn; +- +- __u16 state; +- __u8 out; +- bdaddr_t src; +- bdaddr_t dst; +- +- spinlock_t lock; +- atomic_t refcnt; +- +- struct sk_buff *rx_skb; +- __u32 rx_len; +- __u8 rx_ident; +- __u8 tx_ident; +- +- struct l2cap_chan_list chan_list; +- +- struct timer_list timer; +-}; +- +-static inline void __l2cap_conn_link(struct l2cap_iff *iff, struct l2cap_conn *c) +-{ +- list_add(&c->list, &iff->conn_list); +-} +- +-static inline void __l2cap_conn_unlink(struct l2cap_iff *iff, struct l2cap_conn *c) +-{ +- list_del(&c->list); +-} +- +-/* ----- L2CAP channel and socket info ----- */ +-#define l2cap_pi(sk) ((struct l2cap_pinfo *) &sk->protinfo) +- +-struct l2cap_accept_q { +- struct sock *head; +- struct sock *tail; +-}; +- +-struct l2cap_pinfo { +- bdaddr_t src; +- bdaddr_t dst; +- __u16 psm; +- __u16 dcid; +- __u16 scid; +- __u32 flags; +- +- __u16 imtu; +- __u16 omtu; +- __u16 flush_to; +- +- __u8 conf_state; +- __u16 conf_mtu; +- +- __u8 ident; +- +- struct l2cap_conn *conn; +- struct sock *next_c; +- struct sock *prev_c; +- +- struct sock *parent; +- struct sock *next_q; +- struct sock *prev_q; +- +- struct l2cap_accept_q accept_q; +-}; +- +-#define CONF_REQ_SENT 0x01 +-#define CONF_INPUT_DONE 0x02 +-#define CONF_OUTPUT_DONE 0x04 +- +-extern struct bluez_sock_list l2cap_sk_list; +-extern struct list_head l2cap_iff_list; +-extern rwlock_t l2cap_rt_lock; +- +-extern void l2cap_register_proc(void); +-extern void l2cap_unregister_proc(void); +- +-#endif /* __KERNEL__ */ +- +-#endif /* __L2CAP_CORE_H */ +diff -urN linux-2.4.18/include/net/bluetooth/rfcomm.h linux-2.4.18-mh9/include/net/bluetooth/rfcomm.h +--- linux-2.4.18/include/net/bluetooth/rfcomm.h Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/include/net/bluetooth/rfcomm.h Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,356 @@ ++/* ++ RFCOMM implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com> ++ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ RPN support - Dirk Husemann <hud@zurich.ibm.com> ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#ifndef __RFCOMM_H ++#define __RFCOMM_H ++ ++#define RFCOMM_PSM 3 ++ ++#define RFCOMM_CONN_TIMEOUT (HZ * 30) ++#define RFCOMM_DISC_TIMEOUT (HZ * 20) ++ ++#define RFCOMM_DEFAULT_MTU 127 ++#define RFCOMM_DEFAULT_CREDITS 7 ++ ++#define RFCOMM_MAX_L2CAP_MTU 1024 ++#define RFCOMM_MAX_CREDITS 40 ++ ++#define RFCOMM_SKB_HEAD_RESERVE 8 ++#define RFCOMM_SKB_TAIL_RESERVE 2 ++#define RFCOMM_SKB_RESERVE (RFCOMM_SKB_HEAD_RESERVE + RFCOMM_SKB_TAIL_RESERVE) ++ ++#define RFCOMM_SABM 0x2f ++#define RFCOMM_DISC 0x43 ++#define RFCOMM_UA 0x63 ++#define RFCOMM_DM 0x0f ++#define RFCOMM_UIH 0xef ++ ++#define RFCOMM_TEST 0x08 ++#define RFCOMM_FCON 0x28 ++#define RFCOMM_FCOFF 0x18 ++#define RFCOMM_MSC 0x38 ++#define RFCOMM_RPN 0x24 ++#define RFCOMM_RLS 0x14 ++#define RFCOMM_PN 0x20 ++#define RFCOMM_NSC 0x04 ++ ++#define RFCOMM_V24_FC 0x02 ++#define RFCOMM_V24_RTC 0x04 ++#define RFCOMM_V24_RTR 0x08 ++#define RFCOMM_V24_IC 0x40 ++#define RFCOMM_V24_DV 0x80 ++ ++#define RFCOMM_RPN_BR_2400 0x0 ++#define RFCOMM_RPN_BR_4800 0x1 ++#define RFCOMM_RPN_BR_7200 0x2 ++#define RFCOMM_RPN_BR_9600 0x3 ++#define RFCOMM_RPN_BR_19200 0x4 ++#define RFCOMM_RPN_BR_38400 0x5 ++#define RFCOMM_RPN_BR_57600 0x6 ++#define RFCOMM_RPN_BR_115200 0x7 ++#define RFCOMM_RPN_BR_230400 0x8 ++ ++#define RFCOMM_RPN_DATA_5 0x0 ++#define RFCOMM_RPN_DATA_6 0x1 ++#define RFCOMM_RPN_DATA_7 0x2 ++#define RFCOMM_RPN_DATA_8 0x3 ++ ++#define RFCOMM_RPN_STOP_1 0 ++#define RFCOMM_RPN_STOP_15 1 ++ ++#define RFCOMM_RPN_PARITY_NONE 0x0 ++#define RFCOMM_RPN_PARITY_ODD 0x4 ++#define RFCOMM_RPN_PARITY_EVEN 0x5 ++#define RFCOMM_RPN_PARITY_MARK 0x6 ++#define RFCOMM_RPN_PARITY_SPACE 0x7 ++ ++#define RFCOMM_RPN_FLOW_NONE 0x00 ++ ++#define RFCOMM_RPN_XON_CHAR 0x11 ++#define RFCOMM_RPN_XOFF_CHAR 0x13 ++ ++#define RFCOMM_RPN_PM_BITRATE 0x0001 ++#define RFCOMM_RPN_PM_DATA 0x0002 ++#define RFCOMM_RPN_PM_STOP 0x0004 ++#define RFCOMM_RPN_PM_PARITY 0x0008 ++#define RFCOMM_RPN_PM_PARITY_TYPE 0x0010 ++#define RFCOMM_RPN_PM_XON 0x0020 ++#define RFCOMM_RPN_PM_XOFF 0x0040 ++#define RFCOMM_RPN_PM_FLOW 0x3F00 ++ ++#define RFCOMM_RPN_PM_ALL 0x3F7F ++ ++struct rfcomm_hdr { ++ u8 addr; ++ u8 ctrl; ++ u8 len; // Actual size can be 2 bytes ++} __attribute__ ((packed)); ++ ++struct rfcomm_cmd { ++ u8 addr; ++ u8 ctrl; ++ u8 len; ++ u8 fcs; ++} __attribute__ ((packed)); ++ ++struct rfcomm_mcc { ++ u8 type; ++ u8 len; ++} __attribute__ ((packed)); ++ ++struct rfcomm_pn { ++ u8 dlci; ++ u8 flow_ctrl; ++ u8 priority; ++ u8 ack_timer; ++ u16 mtu; ++ u8 max_retrans; ++ u8 credits; ++} __attribute__ ((packed)); ++ ++struct rfcomm_rpn { ++ u8 dlci; ++ u8 bit_rate; ++ u8 line_settings; ++ u8 flow_ctrl; ++ u8 xon_char; ++ u8 xoff_char; ++ u16 param_mask; ++} __attribute__ ((packed)); ++ ++struct rfcomm_rls { ++ u8 dlci; ++ u8 status; ++} __attribute__ ((packed)); ++ ++struct rfcomm_msc { ++ u8 dlci; ++ u8 v24_sig; ++} __attribute__ ((packed)); ++ ++/* ---- Core structures, flags etc ---- */ ++ ++struct rfcomm_session { ++ struct list_head list; ++ struct socket *sock; ++ unsigned long state; ++ unsigned long flags; ++ atomic_t refcnt; ++ int initiator; ++ ++ /* Default DLC parameters */ ++ uint mtu; ++ uint credits; ++ ++ struct list_head dlcs; ++}; ++ ++struct rfcomm_dlc { ++ struct list_head list; ++ struct rfcomm_session *session; ++ struct sk_buff_head tx_queue; ++ struct timer_list timer; ++ ++ spinlock_t lock; ++ unsigned long state; ++ unsigned long flags; ++ atomic_t refcnt; ++ u8 dlci; ++ u8 addr; ++ u8 priority; ++ u8 v24_sig; ++ u8 mscex; ++ ++ uint mtu; ++ uint credits; ++ uint rx_credits; ++ uint tx_credits; ++ ++ void *owner; ++ ++ void (*data_ready)(struct rfcomm_dlc *d, struct sk_buff *skb); ++ void (*state_change)(struct rfcomm_dlc *d, int err); ++ void (*modem_status)(struct rfcomm_dlc *d, u8 v24_sig); ++}; ++ ++/* DLC and session flags */ ++#define RFCOMM_RX_THROTTLED 0 ++#define RFCOMM_TX_THROTTLED 1 ++#define RFCOMM_MSC_PENDING 2 ++#define RFCOMM_TIMED_OUT 3 ++ ++/* Scheduling flags and events */ ++#define RFCOMM_SCHED_STATE 0 ++#define RFCOMM_SCHED_RX 1 ++#define RFCOMM_SCHED_TX 2 ++#define RFCOMM_SCHED_TIMEO 3 ++#define RFCOMM_SCHED_WAKEUP 31 ++ ++/* MSC exchange flags */ ++#define RFCOMM_MSCEX_TX 1 ++#define RFCOMM_MSCEX_RX 2 ++#define RFCOMM_MSCEX_OK (RFCOMM_MSCEX_TX + RFCOMM_MSCEX_RX) ++ ++extern struct task_struct *rfcomm_thread; ++extern unsigned long rfcomm_event; ++ ++static inline void rfcomm_schedule(uint event) ++{ ++ if (!rfcomm_thread) ++ return; ++ set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event); ++ wake_up_process(rfcomm_thread); ++} ++ ++extern struct semaphore rfcomm_sem; ++#define rfcomm_lock() down(&rfcomm_sem); ++#define rfcomm_unlock() up(&rfcomm_sem); ++ ++/* ---- RFCOMM DLCs (channels) ---- */ ++struct rfcomm_dlc *rfcomm_dlc_alloc(int prio); ++void rfcomm_dlc_free(struct rfcomm_dlc *d); ++int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel); ++int rfcomm_dlc_close(struct rfcomm_dlc *d, int reason); ++int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb); ++int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig); ++int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig); ++ ++#define rfcomm_dlc_lock(d) spin_lock(&d->lock) ++#define rfcomm_dlc_unlock(d) spin_unlock(&d->lock) ++ ++static inline void rfcomm_dlc_hold(struct rfcomm_dlc *d) ++{ ++ atomic_inc(&d->refcnt); ++} ++ ++static inline void rfcomm_dlc_put(struct rfcomm_dlc *d) ++{ ++ if (atomic_dec_and_test(&d->refcnt)) ++ rfcomm_dlc_free(d); ++} ++ ++extern void FASTCALL(__rfcomm_dlc_throttle(struct rfcomm_dlc *d)); ++extern void FASTCALL(__rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)); ++ ++static inline void rfcomm_dlc_throttle(struct rfcomm_dlc *d) ++{ ++ if (!test_and_set_bit(RFCOMM_RX_THROTTLED, &d->flags)) ++ __rfcomm_dlc_throttle(d); ++} ++ ++static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) ++{ ++ if (test_and_clear_bit(RFCOMM_RX_THROTTLED, &d->flags)) ++ __rfcomm_dlc_unthrottle(d); ++} ++ ++/* ---- RFCOMM sessions ---- */ ++struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state); ++struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst); ++struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err); ++void rfcomm_session_del(struct rfcomm_session *s); ++void rfcomm_session_close(struct rfcomm_session *s, int err); ++void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst); ++ ++static inline void rfcomm_session_hold(struct rfcomm_session *s) ++{ ++ atomic_inc(&s->refcnt); ++} ++ ++static inline void rfcomm_session_put(struct rfcomm_session *s) ++{ ++ if (atomic_dec_and_test(&s->refcnt)) ++ rfcomm_session_del(s); ++} ++ ++/* ---- RFCOMM chechsum ---- */ ++extern u8 rfcomm_crc_table[]; ++ ++/* ---- RFCOMM sockets ---- */ ++struct sockaddr_rc { ++ sa_family_t rc_family; ++ bdaddr_t rc_bdaddr; ++ u8 rc_channel; ++}; ++ ++#define rfcomm_pi(sk) ((struct rfcomm_pinfo *) &sk->tp_pinfo) ++ ++struct rfcomm_pinfo { ++ struct rfcomm_dlc *dlc; ++ u8 channel; ++}; ++ ++int rfcomm_init_sockets(void); ++void rfcomm_cleanup_sockets(void); ++ ++int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d); ++ ++/* ---- RFCOMM TTY ---- */ ++#define RFCOMM_MAX_DEV 256 ++ ++#define RFCOMMCREATEDEV _IOW('R', 200, int) ++#define RFCOMMRELEASEDEV _IOW('R', 201, int) ++#define RFCOMMGETDEVLIST _IOR('R', 210, int) ++#define RFCOMMGETDEVINFO _IOR('R', 211, int) ++#define RFCOMMSTEALDLC _IOW('R', 220, int) ++ ++#define RFCOMM_REUSE_DLC 0 ++#define RFCOMM_RELEASE_ONHUP 1 ++#define RFCOMM_HANGUP_NOW 2 ++#define RFCOMM_TTY_ATTACHED 3 ++ ++struct rfcomm_dev_req { ++ s16 dev_id; ++ u32 flags; ++ bdaddr_t src; ++ bdaddr_t dst; ++ u8 channel; ++}; ++ ++struct rfcomm_dev_info { ++ s16 id; ++ u32 flags; ++ u16 state; ++ bdaddr_t src; ++ bdaddr_t dst; ++ u8 channel; ++}; ++ ++struct rfcomm_dev_list_req { ++ u16 dev_num; ++ struct rfcomm_dev_info dev_info[0]; ++}; ++ ++int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg); ++int rfcomm_init_ttys(void); ++void rfcomm_cleanup_ttys(void); ++ ++#endif /* __RFCOMM_H */ +diff -urN linux-2.4.18/include/net/bluetooth/sco.h linux-2.4.18-mh9/include/net/bluetooth/sco.h +--- linux-2.4.18/include/net/bluetooth/sco.h Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/include/net/bluetooth/sco.h Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,81 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#ifndef __SCO_H ++#define __SCO_H ++ ++/* SCO defaults */ ++#define SCO_DEFAULT_MTU 500 ++#define SCO_DEFAULT_FLUSH_TO 0xFFFF ++ ++#define SCO_CONN_TIMEOUT (HZ * 40) ++#define SCO_DISCONN_TIMEOUT (HZ * 2) ++#define SCO_CONN_IDLE_TIMEOUT (HZ * 60) ++ ++/* SCO socket address */ ++struct sockaddr_sco { ++ sa_family_t sco_family; ++ bdaddr_t sco_bdaddr; ++}; ++ ++/* set/get sockopt defines */ ++#define SCO_OPTIONS 0x01 ++struct sco_options { ++ __u16 mtu; ++}; ++ ++#define SCO_CONNINFO 0x02 ++struct sco_conninfo { ++ __u16 hci_handle; ++}; ++ ++/* ---- SCO connections ---- */ ++struct sco_conn { ++ struct hci_conn *hcon; ++ ++ bdaddr_t *dst; ++ bdaddr_t *src; ++ ++ spinlock_t lock; ++ struct sock *sk; ++ ++ unsigned int mtu; ++}; ++ ++#define sco_conn_lock(c) spin_lock(&c->lock); ++#define sco_conn_unlock(c) spin_unlock(&c->lock); ++ ++/* ----- SCO socket info ----- */ ++#define sco_pi(sk) ((struct sco_pinfo *) &sk->tp_pinfo) ++ ++struct sco_pinfo { ++ __u32 flags; ++ struct sco_conn *conn; ++}; ++ ++#endif /* __SCO_H */ +diff -urN linux-2.4.18/include/pcmcia/ciscode.h linux-2.4.18-mh9/include/pcmcia/ciscode.h +--- linux-2.4.18/include/pcmcia/ciscode.h Fri Dec 21 18:42:04 2001 ++++ linux-2.4.18-mh9/include/pcmcia/ciscode.h Mon Aug 25 18:38:12 2003 +@@ -1,5 +1,5 @@ + /* +- * ciscode.h 1.48 2001/08/24 12:16:12 ++ * ciscode.h 1.57 2002/11/03 20:38:14 + * + * 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 +@@ -60,6 +60,10 @@ + #define PRODID_INTEL_DUAL_RS232 0x0301 + #define PRODID_INTEL_2PLUS 0x8422 + ++#define MANFID_KME 0x0032 ++#define PRODID_KME_KXLC005_A 0x0704 ++#define PRODID_KME_KXLC005_B 0x2904 ++ + #define MANFID_LINKSYS 0x0143 + #define PRODID_LINKSYS_PCMLM28 0xc0ab + #define PRODID_LINKSYS_3400 0x3341 +@@ -94,6 +98,8 @@ + #define PRODID_OSITECH_JACK_336 0x0007 + #define PRODID_OSITECH_SEVEN 0x0008 + ++#define MANFID_OXSEMI 0x0279 ++ + #define MANFID_PIONEER 0x000b + + #define MANFID_PSION 0x016c +@@ -103,6 +109,7 @@ + #define PRODID_QUATECH_SPP100 0x0003 + #define PRODID_QUATECH_DUAL_RS232 0x0012 + #define PRODID_QUATECH_DUAL_RS232_D1 0x0007 ++#define PRODID_QUATECH_DUAL_RS232_D2 0x0052 + #define PRODID_QUATECH_QUAD_RS232 0x001b + #define PRODID_QUATECH_DUAL_RS422 0x000e + #define PRODID_QUATECH_QUAD_RS422 0x0045 +@@ -120,8 +127,11 @@ + + #define MANFID_TDK 0x0105 + #define PRODID_TDK_CF010 0x0900 ++#define PRODID_TDK_GN3410 0x4815 + + #define MANFID_TOSHIBA 0x0098 ++ ++#define MANFID_UNGERMANN 0x02c0 + + #define MANFID_XIRCOM 0x0105 + +diff -urN linux-2.4.18/lib/Config.in linux-2.4.18-mh9/lib/Config.in +--- linux-2.4.18/lib/Config.in Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/lib/Config.in Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,12 @@ ++# ++# Library configuration ++# ++mainmenu_option next_comment ++comment 'Library routines' ++ ++if [ "$CONFIG_EXPERIMENTAL" = "y" -a \ ++ "$CONFIG_HOTPLUG" = "y" ]; then ++ tristate 'Hotplug firmware loading support (EXPERIMENTAL)' CONFIG_FW_LOADER ++fi ++ ++endmenu +diff -urN linux-2.4.18/lib/Makefile linux-2.4.18-mh9/lib/Makefile +--- linux-2.4.18/lib/Makefile Tue Sep 18 00:31:15 2001 ++++ linux-2.4.18-mh9/lib/Makefile Mon Aug 25 18:38:12 2003 +@@ -8,12 +8,16 @@ + + L_TARGET := lib.a + +-export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o ++export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o \ ++ firmware_class.o + + obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o bust_spinlocks.o rbtree.o + ++obj-$(CONFIG_FW_LOADER) += firmware_class.o + obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o + obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o ++ ++include $(TOPDIR)/drivers/bluetooth/Makefile.lib + + ifneq ($(CONFIG_HAVE_DEC_LOCK),y) + obj-y += dec_and_lock.o +diff -urN linux-2.4.18/lib/firmware_class.c linux-2.4.18-mh9/lib/firmware_class.c +--- linux-2.4.18/lib/firmware_class.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/lib/firmware_class.c Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,571 @@ ++/* ++ * firmware_class.c - Multi purpose firmware loading support ++ * ++ * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org> ++ * ++ * Please see Documentation/firmware_class/ for more information. ++ * ++ */ ++/* ++ * Based on kernel/kmod.c and drivers/usb/usb.c ++ */ ++/* ++ kernel/kmod.c ++ Kirk Petersen ++ ++ Reorganized not to be a daemon by Adam Richter, with guidance ++ from Greg Zornetzer. ++ ++ Modified to avoid chroot and file sharing problems. ++ Mikael Pettersson ++ ++ Limit the concurrent number of kmod modprobes to catch loops from ++ "modprobe needs a service that is in a module". ++ Keith Owens <kaos@ocs.com.au> December 1999 ++ ++ Unblock all signals when we exec a usermode process. ++ Shuu Yamaguchi <shuu@wondernetworkresources.com> December 2000 ++*/ ++/* ++ * drivers/usb/usb.c ++ * ++ * (C) Copyright Linus Torvalds 1999 ++ * (C) Copyright Johannes Erdfelt 1999-2001 ++ * (C) Copyright Andreas Gal 1999 ++ * (C) Copyright Gregory P. Smith 1999 ++ * (C) Copyright Deti Fliegl 1999 (new USB architecture) ++ * (C) Copyright Randy Dunlap 2000 ++ * (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id) ++ * (C) Copyright Yggdrasil Computing, Inc. 2000 ++ * (usb_device_id matching changes by Adam J. Richter) ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/string.h> ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/kmod.h> ++#include <linux/proc_fs.h> ++#include <linux/vmalloc.h> ++#include <asm/hardirq.h> ++ ++#include "linux/firmware.h" ++ ++MODULE_AUTHOR("Manuel Estrada Sainz <ranty@debian.org>"); ++MODULE_DESCRIPTION("Multi purpose firmware loading support"); ++MODULE_LICENSE("GPL"); ++ ++#define err(format, arg...) \ ++ printk(KERN_ERR "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg) ++#define warn(format, arg...) \ ++ printk(KERN_WARNING "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg) ++#define dbg(format, arg...) \ ++ printk(KERN_DEBUG "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg) ++ ++static int loading_timeout = 10; /* In seconds */ ++static struct proc_dir_entry *proc_dir_timeout; ++static struct proc_dir_entry *proc_dir; ++ ++#ifdef CONFIG_HOTPLUG ++ ++static int ++call_helper(char *verb, const char *name, const char *device) ++{ ++ char *argv[3], **envp, *buf, *scratch; ++ int i = 0; ++ ++ int retval = 0; ++ ++ if (!hotplug_path[0]) ++ return -ENOENT; ++ if (in_interrupt()) { ++ err("in_interrupt"); ++ return -EFAULT; ++ } ++ if (!current->fs->root) { ++ warn("call_policy %s -- no FS yet", verb); ++ return -EPERM; ++ } ++ ++ if (!(envp = (char **) kmalloc(20 * sizeof (char *), GFP_KERNEL))) { ++ err("unable to allocate envp"); ++ return -ENOMEM; ++ } ++ if (!(buf = kmalloc(256, GFP_KERNEL))) { ++ kfree(envp); ++ err("unable to allocate buf"); ++ return -ENOMEM; ++ } ++ ++ /* only one standardized param to hotplug command: type */ ++ argv[0] = hotplug_path; ++ argv[1] = "firmware"; ++ argv[2] = 0; ++ ++ /* minimal command environment */ ++ envp[i++] = "HOME=/"; ++ envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; ++ ++#ifdef DEBUG ++ /* hint that policy agent should enter no-stdout debug mode */ ++ envp[i++] = "DEBUG=kernel"; ++#endif ++ scratch = buf; ++ ++ if (device) { ++ envp[i++] = scratch; ++ scratch += snprintf(scratch, FIRMWARE_NAME_MAX+25, ++ "DEVPATH=/driver/firmware/%s", device) + 1; ++ } ++ ++ envp[i++] = scratch; ++ scratch += sprintf(scratch, "ACTION=%s", verb) + 1; ++ ++ envp[i++] = scratch; ++ scratch += snprintf(scratch, FIRMWARE_NAME_MAX, ++ "FIRMWARE=%s", name) + 1; ++ ++ envp[i++] = 0; ++ ++#ifdef DEBUG ++ dbg("firmware: %s %s %s", argv[0], argv[1], verb); ++#endif ++ ++ retval = call_usermodehelper(argv[0], argv, envp); ++ if (retval) { ++ printk("call_usermodehelper return %d\n", retval); ++ } ++ ++ kfree(buf); ++ kfree(envp); ++ return retval; ++} ++#else ++ ++static inline int ++call_helper(char *verb, const char *name, const char *device) ++{ ++ return -ENOENT; ++} ++ ++#endif /* CONFIG_HOTPLUG */ ++ ++struct firmware_priv { ++ struct completion completion; ++ struct proc_dir_entry *proc_dir; ++ struct proc_dir_entry *attr_data; ++ struct proc_dir_entry *attr_loading; ++ struct firmware *fw; ++ int loading; ++ int abort; ++ int alloc_size; ++ struct timer_list timeout; ++}; ++ ++static int ++firmware_timeout_show(char *buf, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ return sprintf(buf, "%d\n", loading_timeout); ++} ++ ++/** ++ * firmware_timeout_store: ++ * Description: ++ * Sets the number of seconds to wait for the firmware. Once ++ * this expires an error will be return to the driver and no ++ * firmware will be provided. ++ * ++ * Note: zero means 'wait for ever' ++ * ++ **/ ++static int ++firmware_timeout_store(struct file *file, const char *buf, ++ unsigned long count, void *data) ++{ ++ loading_timeout = simple_strtol(buf, NULL, 10); ++ return count; ++} ++ ++static int ++firmware_loading_show(char *buf, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ struct firmware_priv *fw_priv = data; ++ return sprintf(buf, "%d\n", fw_priv->loading); ++} ++ ++/** ++ * firmware_loading_store: - loading control file ++ * Description: ++ * The relevant values are: ++ * ++ * 1: Start a load, discarding any previous partial load. ++ * 0: Conclude the load and handle the data to the driver code. ++ * -1: Conclude the load with an error and discard any written data. ++ **/ ++static int ++firmware_loading_store(struct file *file, const char *buf, ++ unsigned long count, void *data) ++{ ++ struct firmware_priv *fw_priv = data; ++ int prev_loading = fw_priv->loading; ++ ++ fw_priv->loading = simple_strtol(buf, NULL, 10); ++ ++ switch (fw_priv->loading) { ++ case -1: ++ fw_priv->abort = 1; ++ wmb(); ++ complete(&fw_priv->completion); ++ break; ++ case 1: ++ kfree(fw_priv->fw->data); ++ fw_priv->fw->data = NULL; ++ fw_priv->fw->size = 0; ++ fw_priv->alloc_size = 0; ++ break; ++ case 0: ++ if (prev_loading == 1) ++ complete(&fw_priv->completion); ++ break; ++ } ++ ++ return count; ++} ++ ++static int ++firmware_data_read(char *buffer, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ struct firmware_priv *fw_priv = data; ++ struct firmware *fw = fw_priv->fw; ++ ++ if (offset > fw->size) ++ return 0; ++ if (offset + count > fw->size) ++ count = fw->size - offset; ++ ++ memcpy(buffer, fw->data + offset, count); ++ *start = (void *) ((long) count); ++ return count; ++} ++static int ++fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size) ++{ ++ u8 *new_data; ++ int new_size; ++ ++ if (min_size <= fw_priv->alloc_size) ++ return 0; ++ if((min_size % PAGE_SIZE) == 0) ++ new_size = min_size; ++ else ++ new_size = (min_size + PAGE_SIZE) & PAGE_MASK; ++ new_data = vmalloc(new_size); ++ if (!new_data) { ++ printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__); ++ /* Make sure that we don't keep incomplete data */ ++ fw_priv->abort = 1; ++ return -ENOMEM; ++ } ++ fw_priv->alloc_size = new_size; ++ if (fw_priv->fw->data) { ++ memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size); ++ vfree(fw_priv->fw->data); ++ } ++ fw_priv->fw->data = new_data; ++ BUG_ON(min_size > fw_priv->alloc_size); ++ return 0; ++} ++ ++/** ++ * firmware_data_write: ++ * ++ * Description: ++ * ++ * Data written to the 'data' attribute will be later handled to ++ * the driver as a firmware image. ++ **/ ++static int ++firmware_data_write(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ struct firmware_priv *fw_priv = data; ++ struct firmware *fw = fw_priv->fw; ++ int offset = file->f_pos; ++ int retval; ++ ++ retval = fw_realloc_buffer(fw_priv, offset + count); ++ if (retval) { ++ printk("%s: retval:%d\n", __FUNCTION__, retval); ++ return retval; ++ } ++ ++ memcpy(fw->data + offset, buffer, count); ++ ++ fw->size = max_t(size_t, offset + count, fw->size); ++ file->f_pos += count; ++ return count; ++} ++ ++static void ++firmware_class_timeout(u_long data) ++{ ++ struct firmware_priv *fw_priv = (struct firmware_priv *) data; ++ fw_priv->abort = 1; ++ wmb(); ++ complete(&fw_priv->completion); ++} ++static int ++fw_setup_class_device(struct firmware_priv **fw_priv_p, ++ const char *fw_name, const char *device) ++{ ++ int retval; ++ struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv), ++ GFP_KERNEL); ++ *fw_priv_p = fw_priv; ++ if (!fw_priv) { ++ retval = -ENOMEM; ++ goto out; ++ } ++ memset(fw_priv, 0, sizeof (*fw_priv)); ++ ++ init_completion(&fw_priv->completion); ++ ++ fw_priv->timeout.function = firmware_class_timeout; ++ fw_priv->timeout.data = (u_long) fw_priv; ++ init_timer(&fw_priv->timeout); ++ ++ retval = -EAGAIN; ++ fw_priv->proc_dir = create_proc_entry(device, 0644 | S_IFDIR, proc_dir); ++ if (!fw_priv->proc_dir) ++ goto err_free_fw_priv; ++ ++ fw_priv->attr_data = create_proc_entry("data", 0644 | S_IFREG, ++ fw_priv->proc_dir); ++ if (!fw_priv->attr_data) ++ goto err_remove_dir; ++ ++ fw_priv->attr_data->read_proc = firmware_data_read; ++ fw_priv->attr_data->write_proc = firmware_data_write; ++ fw_priv->attr_data->data = fw_priv; ++ ++ fw_priv->attr_loading = create_proc_entry("loading", 0644 | S_IFREG, ++ fw_priv->proc_dir); ++ if (!fw_priv->attr_loading) ++ goto err_remove_data; ++ ++ fw_priv->attr_loading->read_proc = firmware_loading_show; ++ fw_priv->attr_loading->write_proc = firmware_loading_store; ++ fw_priv->attr_loading->data = fw_priv; ++ ++ retval = 0; ++ fw_priv->fw = kmalloc(sizeof (struct firmware), GFP_KERNEL); ++ if (!fw_priv->fw) { ++ printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n", ++ __FUNCTION__); ++ retval = -ENOMEM; ++ goto err_remove_loading; ++ } ++ memset(fw_priv->fw, 0, sizeof (*fw_priv->fw)); ++ ++ goto out; ++ ++err_remove_loading: ++ remove_proc_entry("loading", fw_priv->proc_dir); ++err_remove_data: ++ remove_proc_entry("data", fw_priv->proc_dir); ++err_remove_dir: ++ remove_proc_entry(device, proc_dir); ++err_free_fw_priv: ++ kfree(fw_priv); ++out: ++ return retval; ++} ++static void ++fw_remove_class_device(struct firmware_priv *fw_priv) ++{ ++ remove_proc_entry("loading", fw_priv->proc_dir); ++ remove_proc_entry("data", fw_priv->proc_dir); ++ remove_proc_entry(fw_priv->proc_dir->name, proc_dir); ++} ++ ++/** ++ * request_firmware: - request firmware to hotplug and wait for it ++ * Description: ++ * @firmware will be used to return a firmware image by the name ++ * of @name for device @device. ++ * ++ * Should be called from user context where sleeping is allowed. ++ * ++ * @name will be use as $FIRMWARE in the hotplug environment and ++ * should be distinctive enough not to be confused with any other ++ * firmware image for this or any other device. ++ **/ ++int ++request_firmware(const struct firmware **firmware, const char *name, ++ const char *device) ++{ ++ struct firmware_priv *fw_priv; ++ int retval; ++ ++ if (!firmware) { ++ retval = -EINVAL; ++ goto out; ++ } ++ *firmware = NULL; ++ ++ retval = fw_setup_class_device(&fw_priv, name, device); ++ if (retval) ++ goto out; ++ ++ retval = call_helper("add", name, device); ++ if (retval) ++ goto out; ++ if (loading_timeout) { ++ fw_priv->timeout.expires = jiffies + loading_timeout * HZ; ++ add_timer(&fw_priv->timeout); ++ } ++ ++ wait_for_completion(&fw_priv->completion); ++ ++ del_timer(&fw_priv->timeout); ++ fw_remove_class_device(fw_priv); ++ ++ if (fw_priv->fw->size && !fw_priv->abort) { ++ *firmware = fw_priv->fw; ++ } else { ++ retval = -ENOENT; ++ vfree(fw_priv->fw->data); ++ kfree(fw_priv->fw); ++ } ++out: ++ kfree(fw_priv); ++ return retval; ++} ++ ++void ++release_firmware(const struct firmware *fw) ++{ ++ if (fw) { ++ vfree(fw->data); ++ kfree(fw); ++ } ++} ++ ++/** ++ * register_firmware: - provide a firmware image for later usage ++ * ++ * Description: ++ * Make sure that @data will be available by requesting firmware @name. ++ * ++ * Note: This will not be possible until some kind of persistence ++ * is available. ++ **/ ++void ++register_firmware(const char *name, const u8 *data, size_t size) ++{ ++ /* This is meaningless without firmware caching, so until we ++ * decide if firmware caching is reasonable just leave it as a ++ * noop */ ++} ++ ++/* Async support */ ++struct firmware_work { ++ struct tq_struct work; ++ struct module *module; ++ const char *name; ++ const char *device; ++ void *context; ++ void (*cont)(const struct firmware *fw, void *context); ++}; ++ ++static void ++request_firmware_work_func(void *arg) ++{ ++ struct firmware_work *fw_work = arg; ++ const struct firmware *fw; ++ if (!arg) ++ return; ++ request_firmware(&fw, fw_work->name, fw_work->device); ++ fw_work->cont(fw, fw_work->context); ++ release_firmware(fw); ++ __MOD_DEC_USE_COUNT(fw_work->module); ++ kfree(fw_work); ++} ++ ++/** ++ * request_firmware_nowait: ++ * ++ * Description: ++ * Asynchronous variant of request_firmware() for contexts where ++ * it is not possible to sleep. ++ * ++ * @cont will be called asynchronously when the firmware request is over. ++ * ++ * @context will be passed over to @cont. ++ * ++ * @fw may be %NULL if firmware request fails. ++ * ++ **/ ++int ++request_firmware_nowait( ++ struct module *module, ++ const char *name, const char *device, void *context, ++ void (*cont)(const struct firmware *fw, void *context)) ++{ ++ struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work), ++ GFP_ATOMIC); ++ if (!fw_work) ++ return -ENOMEM; ++ if (!try_inc_mod_count(module)) { ++ kfree(fw_work); ++ return -EFAULT; ++ } ++ ++ *fw_work = (struct firmware_work) { ++ .module = module, ++ .name = name, ++ .device = device, ++ .context = context, ++ .cont = cont, ++ }; ++ INIT_TQUEUE(&fw_work->work, request_firmware_work_func, fw_work); ++ ++ schedule_task(&fw_work->work); ++ return 0; ++} ++ ++static int __init ++firmware_class_init(void) ++{ ++ proc_dir = create_proc_entry("driver/firmware", 0755 | S_IFDIR, NULL); ++ if (!proc_dir) ++ return -EAGAIN; ++ proc_dir_timeout = create_proc_entry("timeout", ++ 0644 | S_IFREG, proc_dir); ++ if (!proc_dir_timeout) { ++ remove_proc_entry("driver/firmware", NULL); ++ return -EAGAIN; ++ } ++ proc_dir_timeout->read_proc = firmware_timeout_show; ++ proc_dir_timeout->write_proc = firmware_timeout_store; ++ return 0; ++} ++static void __exit ++firmware_class_exit(void) ++{ ++ remove_proc_entry("timeout", proc_dir); ++ remove_proc_entry("driver/firmware", NULL); ++} ++ ++module_init(firmware_class_init); ++module_exit(firmware_class_exit); ++ ++EXPORT_SYMBOL(release_firmware); ++EXPORT_SYMBOL(request_firmware); ++EXPORT_SYMBOL(request_firmware_nowait); ++EXPORT_SYMBOL(register_firmware); +diff -urN linux-2.4.18/net/bluetooth/Config.in linux-2.4.18-mh9/net/bluetooth/Config.in +--- linux-2.4.18/net/bluetooth/Config.in Tue Jun 12 04:15:27 2001 ++++ linux-2.4.18-mh9/net/bluetooth/Config.in Mon Aug 25 18:38:12 2003 +@@ -1,16 +1,22 @@ + # +-# Bluetooth configuration ++# Bluetooth subsystem configuration + # + + if [ "$CONFIG_NET" != "n" ]; then ++ + mainmenu_option next_comment + comment 'Bluetooth support' + dep_tristate 'Bluetooth subsystem support' CONFIG_BLUEZ $CONFIG_NET + + if [ "$CONFIG_BLUEZ" != "n" ]; then + dep_tristate 'L2CAP protocol support' CONFIG_BLUEZ_L2CAP $CONFIG_BLUEZ ++ dep_tristate 'SCO links support' CONFIG_BLUEZ_SCO $CONFIG_BLUEZ ++ source net/bluetooth/rfcomm/Config.in ++ source net/bluetooth/bnep/Config.in ++ source net/bluetooth/cmtp/Config.in + source drivers/bluetooth/Config.in + fi ++ + endmenu + fi + +diff -urN linux-2.4.18/net/bluetooth/Makefile linux-2.4.18-mh9/net/bluetooth/Makefile +--- linux-2.4.18/net/bluetooth/Makefile Tue Jun 12 04:15:27 2001 ++++ linux-2.4.18-mh9/net/bluetooth/Makefile Mon Aug 25 18:38:12 2003 +@@ -1,20 +1,31 @@ + # +-# Makefile for the Bluetooth subsystem ++# Makefile for the Linux Bluetooth subsystem + # +-O_TARGET := bluetooth.o + +-list-multi := hci.o l2cap.o +-export-objs := syms.o +-hci-objs := af_bluetooth.o hci_core.o hci_sock.o lib.o syms.o +-l2cap-objs := l2cap_core.o l2cap_proc.o ++O_TARGET := bluetooth.o + +-obj-$(CONFIG_BLUEZ) += hci.o ++list-multi := bluez.o ++export-objs := syms.o l2cap.o ++ ++bluez-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o lib.o syms.o ++ ++obj-$(CONFIG_BLUEZ) += bluez.o + obj-$(CONFIG_BLUEZ_L2CAP) += l2cap.o ++obj-$(CONFIG_BLUEZ_SCO) += sco.o + +-include $(TOPDIR)/Rules.make ++subdir-$(CONFIG_BLUEZ_RFCOMM) += rfcomm ++subdir-$(CONFIG_BLUEZ_BNEP) += bnep ++subdir-$(CONFIG_BLUEZ_CMTP) += cmtp + +-hci.o: $(hci-objs) +- $(LD) -r -o $@ $(hci-objs) ++ifeq ($(CONFIG_BLUEZ_RFCOMM),y) ++obj-y += rfcomm/rfcomm.o ++endif ++ ++ifeq ($(CONFIG_BLUEZ_BNEP),y) ++obj-y += bnep/bnep.o ++endif ++ ++include $(TOPDIR)/Rules.make + +-l2cap.o: $(l2cap-objs) +- $(LD) -r -o $@ $(l2cap-objs) ++bluez.o: $(bluez-objs) ++ $(LD) -r -o $@ $(bluez-objs) +diff -urN linux-2.4.18/net/bluetooth/af_bluetooth.c linux-2.4.18-mh9/net/bluetooth/af_bluetooth.c +--- linux-2.4.18/net/bluetooth/af_bluetooth.c Fri Sep 7 18:28:38 2001 ++++ linux-2.4.18-mh9/net/bluetooth/af_bluetooth.c Mon Aug 25 18:38:12 2003 +@@ -25,14 +25,15 @@ + /* + * BlueZ Bluetooth address family and sockets. + * +- * $Id$ ++ * $Id$ + */ +-#define VERSION "1.1" ++#define VERSION "2.4" + + #include <linux/config.h> + #include <linux/module.h> + + #include <linux/types.h> ++#include <linux/list.h> + #include <linux/errno.h> + #include <linux/kernel.h> + #include <linux/major.h> +@@ -40,6 +41,7 @@ + #include <linux/slab.h> + #include <linux/skbuff.h> + #include <linux/init.h> ++#include <linux/poll.h> + #include <linux/proc_fs.h> + #include <net/sock.h> + +@@ -48,70 +50,79 @@ + #endif + + #include <net/bluetooth/bluetooth.h> +-#include <net/bluetooth/bluez.h> ++ ++#ifndef AF_BLUETOOTH_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#endif + + /* Bluetooth sockets */ +-static struct net_proto_family *bluez_sock[BLUEZ_MAX_PROTO]; ++#define BLUEZ_MAX_PROTO 6 ++static struct net_proto_family *bluez_proto[BLUEZ_MAX_PROTO]; + + int bluez_sock_register(int proto, struct net_proto_family *ops) + { +- if (proto > BLUEZ_MAX_PROTO) ++ if (proto >= BLUEZ_MAX_PROTO) + return -EINVAL; + +- if (bluez_sock[proto]) ++ if (bluez_proto[proto]) + return -EEXIST; + +- bluez_sock[proto] = ops; ++ bluez_proto[proto] = ops; + return 0; + } + + int bluez_sock_unregister(int proto) + { +- if (proto > BLUEZ_MAX_PROTO) ++ if (proto >= BLUEZ_MAX_PROTO) + return -EINVAL; + +- if (!bluez_sock[proto]) ++ if (!bluez_proto[proto]) + return -ENOENT; + +- bluez_sock[proto] = NULL; ++ bluez_proto[proto] = NULL; + return 0; + } + + static int bluez_sock_create(struct socket *sock, int proto) + { +- if (proto > BLUEZ_MAX_PROTO) ++ if (proto >= BLUEZ_MAX_PROTO) + return -EINVAL; + + #if defined(CONFIG_KMOD) +- if (!bluez_sock[proto]) { ++ if (!bluez_proto[proto]) { + char module_name[30]; + sprintf(module_name, "bt-proto-%d", proto); + request_module(module_name); + } + #endif + +- if (!bluez_sock[proto]) ++ if (!bluez_proto[proto]) + return -ENOENT; + +- return bluez_sock[proto]->create(sock, proto); ++ return bluez_proto[proto]->create(sock, proto); ++} ++ ++void bluez_sock_init(struct socket *sock, struct sock *sk) ++{ ++ sock_init_data(sock, sk); ++ INIT_LIST_HEAD(&bluez_pi(sk)->accept_q); + } + + void bluez_sock_link(struct bluez_sock_list *l, struct sock *sk) + { +- write_lock(&l->lock); +- ++ write_lock_bh(&l->lock); + sk->next = l->head; + l->head = sk; + sock_hold(sk); +- +- write_unlock(&l->lock); ++ write_unlock_bh(&l->lock); + } + + void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *sk) + { + struct sock **skp; + +- write_lock(&l->lock); ++ write_lock_bh(&l->lock); + for (skp = &l->head; *skp; skp = &((*skp)->next)) { + if (*skp == sk) { + *skp = sk->next; +@@ -119,7 +130,162 @@ + break; + } + } +- write_unlock(&l->lock); ++ write_unlock_bh(&l->lock); ++} ++ ++void bluez_accept_enqueue(struct sock *parent, struct sock *sk) ++{ ++ BT_DBG("parent %p, sk %p", parent, sk); ++ ++ sock_hold(sk); ++ list_add_tail(&bluez_pi(sk)->accept_q, &bluez_pi(parent)->accept_q); ++ bluez_pi(sk)->parent = parent; ++ parent->ack_backlog++; ++} ++ ++static void bluez_accept_unlink(struct sock *sk) ++{ ++ BT_DBG("sk %p state %d", sk, sk->state); ++ ++ list_del_init(&bluez_pi(sk)->accept_q); ++ bluez_pi(sk)->parent->ack_backlog--; ++ bluez_pi(sk)->parent = NULL; ++ sock_put(sk); ++} ++ ++struct sock *bluez_accept_dequeue(struct sock *parent, struct socket *newsock) ++{ ++ struct list_head *p, *n; ++ struct bluez_pinfo *pi; ++ struct sock *sk; ++ ++ BT_DBG("parent %p", parent); ++ ++ list_for_each_safe(p, n, &bluez_pi(parent)->accept_q) { ++ pi = list_entry(p, struct bluez_pinfo, accept_q); ++ sk = bluez_sk(pi); ++ ++ lock_sock(sk); ++ if (sk->state == BT_CLOSED) { ++ release_sock(sk); ++ bluez_accept_unlink(sk); ++ continue; ++ } ++ ++ if (sk->state == BT_CONNECTED || !newsock) { ++ bluez_accept_unlink(sk); ++ if (newsock) ++ sock_graft(sk, newsock); ++ release_sock(sk); ++ return sk; ++ } ++ release_sock(sk); ++ } ++ return NULL; ++} ++ ++int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm) ++{ ++ int noblock = flags & MSG_DONTWAIT; ++ struct sock *sk = sock->sk; ++ struct sk_buff *skb; ++ int copied, err; ++ ++ BT_DBG("sock %p sk %p len %d", sock, sk, len); ++ ++ if (flags & (MSG_OOB)) ++ return -EOPNOTSUPP; ++ ++ if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) { ++ if (sk->shutdown & RCV_SHUTDOWN) ++ return 0; ++ return err; ++ } ++ ++ msg->msg_namelen = 0; ++ ++ copied = skb->len; ++ if (len < copied) { ++ msg->msg_flags |= MSG_TRUNC; ++ copied = len; ++ } ++ ++ skb->h.raw = skb->data; ++ err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); ++ ++ skb_free_datagram(sk, skb); ++ ++ return err ? : copied; ++} ++ ++unsigned int bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait) ++{ ++ struct sock *sk = sock->sk; ++ unsigned int mask; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ poll_wait(file, sk->sleep, wait); ++ mask = 0; ++ ++ if (sk->err || !skb_queue_empty(&sk->error_queue)) ++ mask |= POLLERR; ++ ++ if (sk->shutdown == SHUTDOWN_MASK) ++ mask |= POLLHUP; ++ ++ if (!skb_queue_empty(&sk->receive_queue) || ++ !list_empty(&bluez_pi(sk)->accept_q) || ++ (sk->shutdown & RCV_SHUTDOWN)) ++ mask |= POLLIN | POLLRDNORM; ++ ++ if (sk->state == BT_CLOSED) ++ mask |= POLLHUP; ++ ++ if (sk->state == BT_CONNECT || sk->state == BT_CONNECT2) ++ return mask; ++ ++ if (sock_writeable(sk)) ++ mask |= POLLOUT | POLLWRNORM | POLLWRBAND; ++ else ++ set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); ++ ++ return mask; ++} ++ ++int bluez_sock_wait_state(struct sock *sk, int state, unsigned long timeo) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ int err = 0; ++ ++ BT_DBG("sk %p", sk); ++ ++ add_wait_queue(sk->sleep, &wait); ++ while (sk->state != state) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ if (!timeo) { ++ err = -EAGAIN; ++ break; ++ } ++ ++ if (signal_pending(current)) { ++ err = sock_intr_errno(timeo); ++ break; ++ } ++ ++ release_sock(sk); ++ timeo = schedule_timeout(timeo); ++ lock_sock(sk); ++ ++ if (sk->err) { ++ err = sock_error(sk); ++ break; ++ } ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(sk->sleep, &wait); ++ return err; + } + + struct net_proto_family bluez_sock_family_ops = +@@ -129,9 +295,9 @@ + + int bluez_init(void) + { +- INF("BlueZ HCI Core ver %s Copyright (C) 2000,2001 Qualcomm Inc", ++ BT_INFO("BlueZ Core ver %s Copyright (C) 2000,2001 Qualcomm Inc", + VERSION); +- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); ++ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); + + proc_mkdir("bluetooth", NULL); + +@@ -164,5 +330,6 @@ + module_exit(bluez_cleanup); + + MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); +-MODULE_DESCRIPTION("BlueZ HCI Core ver " VERSION); ++MODULE_DESCRIPTION("BlueZ Core ver " VERSION); ++MODULE_LICENSE("GPL"); + #endif +diff -urN linux-2.4.18/net/bluetooth/bnep/Config.in linux-2.4.18-mh9/net/bluetooth/bnep/Config.in +--- linux-2.4.18/net/bluetooth/bnep/Config.in Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/bnep/Config.in Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,11 @@ ++# ++# Bluetooth BNEP layer configuration ++# ++ ++dep_tristate 'BNEP protocol support' CONFIG_BLUEZ_BNEP $CONFIG_BLUEZ_L2CAP ++ ++if [ "$CONFIG_BLUEZ_BNEP" != "n" ]; then ++ bool ' Multicast filter support' CONFIG_BLUEZ_BNEP_MC_FILTER ++ bool ' Protocol filter support' CONFIG_BLUEZ_BNEP_PROTO_FILTER ++fi ++ +diff -urN linux-2.4.18/net/bluetooth/bnep/Makefile linux-2.4.18-mh9/net/bluetooth/bnep/Makefile +--- linux-2.4.18/net/bluetooth/bnep/Makefile Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/bnep/Makefile Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,10 @@ ++# ++# Makefile for the Linux Bluetooth BNEP layer ++# ++ ++O_TARGET := bnep.o ++ ++obj-y := core.o sock.o netdev.o crc32.o ++obj-m += $(O_TARGET) ++ ++include $(TOPDIR)/Rules.make +diff -urN linux-2.4.18/net/bluetooth/bnep/bnep.h linux-2.4.18-mh9/net/bluetooth/bnep/bnep.h +--- linux-2.4.18/net/bluetooth/bnep/bnep.h Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/bnep/bnep.h Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,185 @@ ++/* ++ BNEP protocol definition for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.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. ++ ++ 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$ ++ */ ++ ++#ifndef _BNEP_H ++#define _BNEP_H ++ ++#include <linux/types.h> ++#include <net/bluetooth/bluetooth.h> ++ ++#include "crc32.h" ++ ++// Limits ++#define BNEP_MAX_PROTO_FILTERS 5 ++#define BNEP_MAX_MULTICAST_FILTERS 20 ++ ++// UUIDs ++#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB ++#define BNEP_UUID16 0x02 ++#define BNEP_UUID32 0x04 ++#define BNEP_UUID128 0x16 ++ ++#define BNEP_SVC_PANU 0x1115 ++#define BNEP_SVC_NAP 0x1116 ++#define BNEP_SVC_GN 0x1117 ++ ++// Packet types ++#define BNEP_GENERAL 0x00 ++#define BNEP_CONTROL 0x01 ++#define BNEP_COMPRESSED 0x02 ++#define BNEP_COMPRESSED_SRC_ONLY 0x03 ++#define BNEP_COMPRESSED_DST_ONLY 0x04 ++ ++// Control types ++#define BNEP_CMD_NOT_UNDERSTOOD 0x00 ++#define BNEP_SETUP_CONN_REQ 0x01 ++#define BNEP_SETUP_CONN_RSP 0x02 ++#define BNEP_FILTER_NET_TYPE_SET 0x03 ++#define BNEP_FILTER_NET_TYPE_RSP 0x04 ++#define BNEP_FILTER_MULTI_ADDR_SET 0x05 ++#define BNEP_FILTER_MULTI_ADDR_RSP 0x06 ++ ++// Extension types ++#define BNEP_EXT_CONTROL 0x00 ++ ++// Response messages ++#define BNEP_SUCCESS 0x00 ++ ++#define BNEP_CONN_INVALID_DST 0x01 ++#define BNEP_CONN_INVALID_SRC 0x02 ++#define BNEP_CONN_INVALID_SVC 0x03 ++#define BNEP_CONN_NOT_ALLOWED 0x04 ++ ++#define BNEP_FILTER_UNSUPPORTED_REQ 0x01 ++#define BNEP_FILTER_INVALID_RANGE 0x02 ++#define BNEP_FILTER_INVALID_MCADDR 0x02 ++#define BNEP_FILTER_LIMIT_REACHED 0x03 ++#define BNEP_FILTER_DENIED_SECURITY 0x04 ++ ++// L2CAP settings ++#define BNEP_MTU 1691 ++#define BNEP_PSM 0x0f ++#define BNEP_FLUSH_TO 0xffff ++#define BNEP_CONNECT_TO 15 ++#define BNEP_FILTER_TO 15 ++ ++// Headers ++#define BNEP_TYPE_MASK 0x7f ++#define BNEP_EXT_HEADER 0x80 ++ ++struct bnep_setup_conn_req { ++ __u8 type; ++ __u8 ctrl; ++ __u8 uuid_size; ++ __u8 service[0]; ++} __attribute__((packed)); ++ ++struct bnep_set_filter_req { ++ __u8 type; ++ __u8 ctrl; ++ __u16 len; ++ __u8 list[0]; ++} __attribute__((packed)); ++ ++struct bnep_control_rsp { ++ __u8 type; ++ __u8 ctrl; ++ __u16 resp; ++} __attribute__((packed)); ++ ++struct bnep_ext_hdr { ++ __u8 type; ++ __u8 len; ++ __u8 data[0]; ++} __attribute__((packed)); ++ ++/* BNEP ioctl defines */ ++#define BNEPCONNADD _IOW('B', 200, int) ++#define BNEPCONNDEL _IOW('B', 201, int) ++#define BNEPGETCONNLIST _IOR('B', 210, int) ++#define BNEPGETCONNINFO _IOR('B', 211, int) ++ ++struct bnep_connadd_req { ++ int sock; // Connected socket ++ __u32 flags; ++ __u16 role; ++ char device[16]; // Name of the Ethernet device ++}; ++ ++struct bnep_conndel_req { ++ __u32 flags; ++ __u8 dst[ETH_ALEN]; ++}; ++ ++struct bnep_conninfo { ++ __u32 flags; ++ __u16 role; ++ __u16 state; ++ __u8 dst[ETH_ALEN]; ++ char device[16]; ++}; ++ ++struct bnep_connlist_req { ++ __u32 cnum; ++ struct bnep_conninfo *ci; ++}; ++ ++struct bnep_proto_filter { ++ __u16 start; ++ __u16 end; ++}; ++ ++int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock); ++int bnep_del_connection(struct bnep_conndel_req *req); ++int bnep_get_connlist(struct bnep_connlist_req *req); ++int bnep_get_conninfo(struct bnep_conninfo *ci); ++ ++// BNEP sessions ++struct bnep_session { ++ struct list_head list; ++ ++ unsigned int role; ++ unsigned long state; ++ unsigned long flags; ++ atomic_t killed; ++ ++ struct ethhdr eh; ++ struct msghdr msg; ++ ++ struct bnep_proto_filter proto_filter[BNEP_MAX_PROTO_FILTERS]; ++ u64 mc_filter; ++ ++ struct socket *sock; ++ struct net_device dev; ++ struct net_device_stats stats; ++}; ++ ++int bnep_net_init(struct net_device *dev); ++int bnep_sock_init(void); ++int bnep_sock_cleanup(void); ++ ++static inline int bnep_mc_hash(__u8 *addr) ++{ ++ return (bnep_crc32(~0, addr, ETH_ALEN) >> 26); ++} ++ ++#endif +diff -urN linux-2.4.18/net/bluetooth/bnep/core.c linux-2.4.18-mh9/net/bluetooth/bnep/core.c +--- linux-2.4.18/net/bluetooth/bnep/core.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/bnep/core.c Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,708 @@ ++/* ++ BNEP implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2001-2002 Inventel Systemes ++ Written 2001-2002 by ++ Cl�ment Moreau <clement.moreau@inventel.fr> ++ David Libault <david.libault@inventel.fr> ++ ++ Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#define __KERNEL_SYSCALLS__ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/signal.h> ++#include <linux/init.h> ++#include <linux/wait.h> ++#include <linux/errno.h> ++#include <linux/smp_lock.h> ++#include <linux/net.h> ++#include <net/sock.h> ++ ++#include <linux/socket.h> ++#include <linux/file.h> ++ ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> ++ ++#include <asm/unaligned.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/l2cap.h> ++ ++#include "bnep.h" ++ ++#ifndef CONFIG_BLUEZ_BNEP_DEBUG ++#undef BT_DBG ++#define BT_DBG(D...) ++#endif ++ ++#define VERSION "1.1" ++ ++static LIST_HEAD(bnep_session_list); ++static DECLARE_RWSEM(bnep_session_sem); ++ ++static struct bnep_session *__bnep_get_session(u8 *dst) ++{ ++ struct bnep_session *s; ++ struct list_head *p; ++ ++ BT_DBG(""); ++ ++ list_for_each(p, &bnep_session_list) { ++ s = list_entry(p, struct bnep_session, list); ++ if (!memcmp(dst, s->eh.h_source, ETH_ALEN)) ++ return s; ++ } ++ return NULL; ++} ++ ++static void __bnep_link_session(struct bnep_session *s) ++{ ++ MOD_INC_USE_COUNT; ++ list_add(&s->list, &bnep_session_list); ++} ++ ++static void __bnep_unlink_session(struct bnep_session *s) ++{ ++ list_del(&s->list); ++ MOD_DEC_USE_COUNT; ++} ++ ++static int bnep_send(struct bnep_session *s, void *data, size_t len) ++{ ++ struct socket *sock = s->sock; ++ struct iovec iv = { data, len }; ++ s->msg.msg_iov = &iv; ++ s->msg.msg_iovlen = 1; ++ return sock->ops->sendmsg(sock, &s->msg, len, NULL); ++} ++ ++static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp) ++{ ++ struct bnep_control_rsp rsp; ++ rsp.type = BNEP_CONTROL; ++ rsp.ctrl = ctrl; ++ rsp.resp = htons(resp); ++ return bnep_send(s, &rsp, sizeof(rsp)); ++} ++ ++static int bnep_ctrl_set_netfilter(struct bnep_session *s, u16 *data, int len) ++{ ++ int n; ++ ++ if (len < 2) ++ return -EILSEQ; ++ ++ n = ntohs(get_unaligned(data)); ++ data++; len -= 2; ++ ++ if (len < n) ++ return -EILSEQ; ++ ++ BT_DBG("filter len %d", n); ++ ++#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER ++ n /= 4; ++ if (n <= BNEP_MAX_PROTO_FILTERS) { ++ struct bnep_proto_filter *f = s->proto_filter; ++ int i; ++ ++ for (i = 0; i < n; i++) { ++ f[i].start = get_unaligned(data++); ++ f[i].end = get_unaligned(data++); ++ ++ BT_DBG("proto filter start %d end %d", ++ f[i].start, f[i].end); ++ } ++ if (i < BNEP_MAX_PROTO_FILTERS) ++ memset(f + i, 0, sizeof(*f)); ++ ++ bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS); ++ } else { ++ bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED); ++ } ++#else ++ bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ); ++#endif ++ return 0; ++} ++ ++static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) ++{ ++ int n; ++ ++ if (len < 2) ++ return -EILSEQ; ++ ++ n = ntohs(get_unaligned((u16 *) data)); ++ data += 2; len -= 2; ++ ++ if (len < n) ++ return -EILSEQ; ++ ++ BT_DBG("filter len %d", n); ++ ++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER ++ n /= (ETH_ALEN * 2); ++ ++ if (n > 0) { ++ s->mc_filter = 0; ++ ++ /* Always send broadcast */ ++ set_bit(bnep_mc_hash(s->dev.broadcast), &s->mc_filter); ++ ++ /* Add address ranges to the multicast hash */ ++ for (; n > 0; n--) { ++ u8 a1[6], *a2; ++ ++ memcpy(a1, data, ETH_ALEN); data += ETH_ALEN; ++ a2 = data; data += ETH_ALEN; ++ ++ BT_DBG("mc filter %s -> %s", ++ batostr((void *) a1), batostr((void *) a2)); ++ ++ #define INCA(a) { int i = 5; while (i >=0 && ++a[i--] == 0); } ++ ++ /* Iterate from a1 to a2 */ ++ set_bit(bnep_mc_hash(a1), &s->mc_filter); ++ while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) { ++ INCA(a1); ++ set_bit(bnep_mc_hash(a1), &s->mc_filter); ++ } ++ } ++ } ++ ++ BT_DBG("mc filter hash 0x%llx", s->mc_filter); ++ ++ bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_SUCCESS); ++#else ++ bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_FILTER_UNSUPPORTED_REQ); ++#endif ++ return 0; ++} ++ ++static int bnep_rx_control(struct bnep_session *s, void *data, int len) ++{ ++ u8 cmd = *(u8 *)data; ++ int err = 0; ++ ++ data++; len--; ++ ++ switch (cmd) { ++ case BNEP_CMD_NOT_UNDERSTOOD: ++ case BNEP_SETUP_CONN_REQ: ++ case BNEP_SETUP_CONN_RSP: ++ case BNEP_FILTER_NET_TYPE_RSP: ++ case BNEP_FILTER_MULTI_ADDR_RSP: ++ /* Ignore these for now */ ++ break; ++ ++ case BNEP_FILTER_NET_TYPE_SET: ++ err = bnep_ctrl_set_netfilter(s, data, len); ++ break; ++ ++ case BNEP_FILTER_MULTI_ADDR_SET: ++ err = bnep_ctrl_set_mcfilter(s, data, len); ++ break; ++ ++ default: { ++ u8 pkt[3]; ++ pkt[0] = BNEP_CONTROL; ++ pkt[1] = BNEP_CMD_NOT_UNDERSTOOD; ++ pkt[2] = cmd; ++ bnep_send(s, pkt, sizeof(pkt)); ++ } ++ break; ++ } ++ ++ return err; ++} ++ ++static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb) ++{ ++ struct bnep_ext_hdr *h; ++ int err = 0; ++ ++ do { ++ h = (void *) skb->data; ++ if (!skb_pull(skb, sizeof(*h))) { ++ err = -EILSEQ; ++ break; ++ } ++ ++ BT_DBG("type 0x%x len %d", h->type, h->len); ++ ++ switch (h->type & BNEP_TYPE_MASK) { ++ case BNEP_EXT_CONTROL: ++ bnep_rx_control(s, skb->data, skb->len); ++ break; ++ ++ default: ++ /* Unknown extension, skip it. */ ++ break; ++ } ++ ++ if (!skb_pull(skb, h->len)) { ++ err = -EILSEQ; ++ break; ++ } ++ } while (!err && (h->type & BNEP_EXT_HEADER)); ++ ++ return err; ++} ++ ++static u8 __bnep_rx_hlen[] = { ++ ETH_HLEN, /* BNEP_GENERAL */ ++ 0, /* BNEP_CONTROL */ ++ 2, /* BNEP_COMPRESSED */ ++ ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */ ++ ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */ ++}; ++#define BNEP_RX_TYPES (sizeof(__bnep_rx_hlen) - 1) ++ ++static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) ++{ ++ struct net_device *dev = &s->dev; ++ struct sk_buff *nskb; ++ u8 type; ++ ++ dev->last_rx = jiffies; ++ s->stats.rx_bytes += skb->len; ++ ++ type = *(u8 *) skb->data; skb_pull(skb, 1); ++ ++ if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES) ++ goto badframe; ++ ++ if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) { ++ bnep_rx_control(s, skb->data, skb->len); ++ kfree_skb(skb); ++ return 0; ++ } ++ ++ skb->mac.raw = skb->data; ++ ++ /* Verify and pull out header */ ++ if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK])) ++ goto badframe; ++ ++ s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2)); ++ ++ if (type & BNEP_EXT_HEADER) { ++ if (bnep_rx_extension(s, skb) < 0) ++ goto badframe; ++ } ++ ++ /* Strip 802.1p header */ ++ if (ntohs(s->eh.h_proto) == 0x8100) { ++ if (!skb_pull(skb, 4)) ++ goto badframe; ++ s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2)); ++ } ++ ++ /* We have to alloc new skb and copy data here :(. Because original skb ++ * may not be modified and because of the alignment requirements. */ ++ nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL); ++ if (!nskb) { ++ s->stats.rx_dropped++; ++ kfree_skb(skb); ++ return -ENOMEM; ++ } ++ skb_reserve(nskb, 2); ++ ++ /* Decompress header and construct ether frame */ ++ switch (type & BNEP_TYPE_MASK) { ++ case BNEP_COMPRESSED: ++ memcpy(__skb_put(nskb, ETH_HLEN), &s->eh, ETH_HLEN); ++ break; ++ ++ case BNEP_COMPRESSED_SRC_ONLY: ++ memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN); ++ memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN); ++ put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2)); ++ break; ++ ++ case BNEP_COMPRESSED_DST_ONLY: ++ memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN); ++ memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source, ETH_ALEN + 2); ++ break; ++ ++ case BNEP_GENERAL: ++ memcpy(__skb_put(nskb, ETH_ALEN * 2), skb->mac.raw, ETH_ALEN * 2); ++ put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2)); ++ break; ++ } ++ ++ memcpy(__skb_put(nskb, skb->len), skb->data, skb->len); ++ kfree_skb(skb); ++ ++ s->stats.rx_packets++; ++ nskb->dev = dev; ++ nskb->ip_summed = CHECKSUM_UNNECESSARY; ++ nskb->protocol = eth_type_trans(nskb, dev); ++ netif_rx_ni(nskb); ++ return 0; ++ ++badframe: ++ s->stats.rx_errors++; ++ kfree_skb(skb); ++ return 0; ++} ++ ++static u8 __bnep_tx_types[] = { ++ BNEP_GENERAL, ++ BNEP_COMPRESSED_SRC_ONLY, ++ BNEP_COMPRESSED_DST_ONLY, ++ BNEP_COMPRESSED ++}; ++ ++static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb) ++{ ++ struct ethhdr *eh = (void *) skb->data; ++ struct socket *sock = s->sock; ++ struct iovec iv[3]; ++ int len = 0, il = 0; ++ u8 type = 0; ++ ++ BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type); ++ ++ if (!skb->dev) { ++ /* Control frame sent by us */ ++ goto send; ++ } ++ ++ iv[il++] = (struct iovec) { &type, 1 }; ++ len++; ++ ++ if (!memcmp(eh->h_dest, s->eh.h_source, ETH_ALEN)) ++ type |= 0x01; ++ ++ if (!memcmp(eh->h_source, s->eh.h_dest, ETH_ALEN)) ++ type |= 0x02; ++ ++ if (type) ++ skb_pull(skb, ETH_ALEN * 2); ++ ++ type = __bnep_tx_types[type]; ++ switch (type) { ++ case BNEP_COMPRESSED_SRC_ONLY: ++ iv[il++] = (struct iovec) { eh->h_source, ETH_ALEN }; ++ len += ETH_ALEN; ++ break; ++ ++ case BNEP_COMPRESSED_DST_ONLY: ++ iv[il++] = (struct iovec) { eh->h_dest, ETH_ALEN }; ++ len += ETH_ALEN; ++ break; ++ } ++ ++send: ++ iv[il++] = (struct iovec) { skb->data, skb->len }; ++ len += skb->len; ++ ++ /* FIXME: linearize skb */ ++ ++ s->msg.msg_iov = iv; ++ s->msg.msg_iovlen = il; ++ len = sock->ops->sendmsg(sock, &s->msg, len, NULL); ++ kfree_skb(skb); ++ ++ if (len > 0) { ++ s->stats.tx_bytes += len; ++ s->stats.tx_packets++; ++ return 0; ++ } ++ ++ return len; ++} ++ ++static int bnep_session(void *arg) ++{ ++ struct bnep_session *s = arg; ++ struct net_device *dev = &s->dev; ++ struct sock *sk = s->sock->sk; ++ struct sk_buff *skb; ++ wait_queue_t wait; ++ ++ BT_DBG(""); ++ ++ daemonize(); reparent_to_init(); ++ ++ sprintf(current->comm, "kbnepd %s", dev->name); ++ ++ sigfillset(¤t->blocked); ++ flush_signals(current); ++ ++ current->nice = -15; ++ ++ set_fs(KERNEL_DS); ++ ++ init_waitqueue_entry(&wait, current); ++ add_wait_queue(sk->sleep, &wait); ++ while (!atomic_read(&s->killed)) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ // RX ++ while ((skb = skb_dequeue(&sk->receive_queue))) { ++ skb_orphan(skb); ++ bnep_rx_frame(s, skb); ++ } ++ ++ if (sk->state != BT_CONNECTED) ++ break; ++ ++ // TX ++ while ((skb = skb_dequeue(&sk->write_queue))) ++ if (bnep_tx_frame(s, skb)) ++ break; ++ netif_wake_queue(dev); ++ ++ schedule(); ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(sk->sleep, &wait); ++ ++ /* Cleanup session */ ++ down_write(&bnep_session_sem); ++ ++ /* Delete network device */ ++ unregister_netdev(dev); ++ ++ /* Release the socket */ ++ fput(s->sock->file); ++ ++ __bnep_unlink_session(s); ++ ++ up_write(&bnep_session_sem); ++ kfree(s); ++ return 0; ++} ++ ++int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) ++{ ++ struct net_device *dev; ++ struct bnep_session *s, *ss; ++ u8 dst[ETH_ALEN], src[ETH_ALEN]; ++ int err; ++ ++ BT_DBG(""); ++ ++ baswap((void *) dst, &bluez_pi(sock->sk)->dst); ++ baswap((void *) src, &bluez_pi(sock->sk)->src); ++ ++ s = kmalloc(sizeof(struct bnep_session), GFP_KERNEL); ++ if (!s) ++ return -ENOMEM; ++ memset(s, 0, sizeof(struct bnep_session)); ++ ++ down_write(&bnep_session_sem); ++ ++ ss = __bnep_get_session(dst); ++ if (ss && ss->state == BT_CONNECTED) { ++ err = -EEXIST; ++ goto failed; ++ } ++ ++ dev = &s->dev; ++ ++ if (*req->device) ++ strcpy(dev->name, req->device); ++ else ++ strcpy(dev->name, "bnep%d"); ++ ++ memset(dev->broadcast, 0xff, ETH_ALEN); ++ ++ /* This is rx header therefor addresses are swaped. ++ * ie eh.h_dest is our local address. */ ++ memcpy(s->eh.h_dest, &src, ETH_ALEN); ++ memcpy(s->eh.h_source, &dst, ETH_ALEN); ++ ++ s->sock = sock; ++ s->role = req->role; ++ s->state = BT_CONNECTED; ++ ++ s->msg.msg_flags = MSG_NOSIGNAL; ++ ++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER ++ /* Set default mc filter */ ++ set_bit(bnep_mc_hash(dev->broadcast), &s->mc_filter); ++#endif ++ ++#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER ++ /* Set default protocol filter */ ++ ++ /* (IPv4, ARP) */ ++ s->proto_filter[0].start = htons(0x0800); ++ s->proto_filter[0].end = htons(0x0806); ++ /* (RARP, AppleTalk) */ ++ s->proto_filter[1].start = htons(0x8035); ++ s->proto_filter[1].end = htons(0x80F3); ++ /* (IPX, IPv6) */ ++ s->proto_filter[2].start = htons(0x8137); ++ s->proto_filter[2].end = htons(0x86DD); ++#endif ++ ++ dev->init = bnep_net_init; ++ dev->priv = s; ++ err = register_netdev(dev); ++ if (err) { ++ goto failed; ++ } ++ ++ __bnep_link_session(s); ++ ++ err = kernel_thread(bnep_session, s, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); ++ if (err < 0) { ++ /* Session thread start failed, gotta cleanup. */ ++ unregister_netdev(dev); ++ __bnep_unlink_session(s); ++ goto failed; ++ } ++ ++ up_write(&bnep_session_sem); ++ strcpy(req->device, dev->name); ++ return 0; ++ ++failed: ++ up_write(&bnep_session_sem); ++ kfree(s); ++ return err; ++} ++ ++int bnep_del_connection(struct bnep_conndel_req *req) ++{ ++ struct bnep_session *s; ++ int err = 0; ++ ++ BT_DBG(""); ++ ++ down_read(&bnep_session_sem); ++ ++ s = __bnep_get_session(req->dst); ++ if (s) { ++ /* Wakeup user-space which is polling for socket errors. ++ * This is temporary hack untill we have shutdown in L2CAP */ ++ s->sock->sk->err = EUNATCH; ++ ++ /* Kill session thread */ ++ atomic_inc(&s->killed); ++ wake_up_interruptible(s->sock->sk->sleep); ++ } else ++ err = -ENOENT; ++ ++ up_read(&bnep_session_sem); ++ return err; ++} ++ ++static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s) ++{ ++ memcpy(ci->dst, s->eh.h_source, ETH_ALEN); ++ strcpy(ci->device, s->dev.name); ++ ci->flags = s->flags; ++ ci->state = s->state; ++ ci->role = s->role; ++} ++ ++int bnep_get_connlist(struct bnep_connlist_req *req) ++{ ++ struct list_head *p; ++ int err = 0, n = 0; ++ ++ down_read(&bnep_session_sem); ++ ++ list_for_each(p, &bnep_session_list) { ++ struct bnep_session *s; ++ struct bnep_conninfo ci; ++ ++ s = list_entry(p, struct bnep_session, list); ++ ++ __bnep_copy_ci(&ci, s); ++ ++ if (copy_to_user(req->ci, &ci, sizeof(ci))) { ++ err = -EFAULT; ++ break; ++ } ++ ++ if (++n >= req->cnum) ++ break; ++ ++ req->ci++; ++ } ++ req->cnum = n; ++ ++ up_read(&bnep_session_sem); ++ return err; ++} ++ ++int bnep_get_conninfo(struct bnep_conninfo *ci) ++{ ++ struct bnep_session *s; ++ int err = 0; ++ ++ down_read(&bnep_session_sem); ++ ++ s = __bnep_get_session(ci->dst); ++ if (s) ++ __bnep_copy_ci(ci, s); ++ else ++ err = -ENOENT; ++ ++ up_read(&bnep_session_sem); ++ return err; ++} ++ ++static int __init bnep_init_module(void) ++{ ++ l2cap_load(); ++ ++ bnep_crc32_init(); ++ bnep_sock_init(); ++ ++ BT_INFO("BlueZ BNEP ver %s", VERSION); ++ BT_INFO("Copyright (C) 2001,2002 Inventel Systemes"); ++ BT_INFO("Written 2001,2002 by Clement Moreau <clement.moreau@inventel.fr>"); ++ BT_INFO("Written 2001,2002 by David Libault <david.libault@inventel.fr>"); ++ BT_INFO("Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>"); ++ ++ return 0; ++} ++ ++static void __exit bnep_cleanup_module(void) ++{ ++ bnep_sock_cleanup(); ++ bnep_crc32_cleanup(); ++} ++ ++module_init(bnep_init_module); ++module_exit(bnep_cleanup_module); ++ ++MODULE_DESCRIPTION("BlueZ BNEP ver " VERSION); ++MODULE_AUTHOR("David Libault <david.libault@inventel.fr>, Maxim Krasnyanskiy <maxk@qualcomm.com>"); ++MODULE_LICENSE("GPL"); +diff -urN linux-2.4.18/net/bluetooth/bnep/crc32.c linux-2.4.18-mh9/net/bluetooth/bnep/crc32.c +--- linux-2.4.18/net/bluetooth/bnep/crc32.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/bnep/crc32.c Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,59 @@ ++/* ++ * Based on linux-2.5/lib/crc32 by Matt Domsch <Matt_Domsch@dell.com> ++ * ++ * FIXME: Remove in 2.5 ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <asm/atomic.h> ++ ++#include "crc32.h" ++ ++#define CRCPOLY_BE 0x04c11db7 ++#define CRC_BE_BITS 8 ++ ++static u32 *bnep_crc32_table; ++ ++/* ++ * This code is in the public domain; copyright abandoned. ++ * Liability for non-performance of this code is limited to the amount ++ * you paid for it. Since it is distributed for free, your refund will ++ * be very very small. If it breaks, you get to keep both pieces. ++ */ ++u32 bnep_crc32(u32 crc, unsigned char const *p, size_t len) ++{ ++ while (len--) ++ crc = (crc << 8) ^ bnep_crc32_table[(crc >> 24) ^ *p++]; ++ ++ return crc; ++} ++ ++int __init bnep_crc32_init(void) ++{ ++ unsigned i, j; ++ u32 crc = 0x80000000; ++ ++ bnep_crc32_table = kmalloc((1 << CRC_BE_BITS) * sizeof(u32), GFP_KERNEL); ++ if (!bnep_crc32_table) ++ return -ENOMEM; ++ ++ bnep_crc32_table[0] = 0; ++ ++ for (i = 1; i < 1 << CRC_BE_BITS; i <<= 1) { ++ crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0); ++ for (j = 0; j < i; j++) ++ bnep_crc32_table[i + j] = crc ^ bnep_crc32_table[j]; ++ } ++ return 0; ++} ++ ++void __exit bnep_crc32_cleanup(void) ++{ ++ if (bnep_crc32_table) ++ kfree(bnep_crc32_table); ++ bnep_crc32_table = NULL; ++} +diff -urN linux-2.4.18/net/bluetooth/bnep/crc32.h linux-2.4.18-mh9/net/bluetooth/bnep/crc32.h +--- linux-2.4.18/net/bluetooth/bnep/crc32.h Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/bnep/crc32.h Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,10 @@ ++/* ++ * crc32.h ++ * See crc32.c for license and changes ++ * ++ * FIXME: Remove in 2.5 ++ */ ++ ++int bnep_crc32_init(void); ++void bnep_crc32_cleanup(void); ++u32 bnep_crc32(u32 crc, unsigned char const *p, size_t len); +diff -urN linux-2.4.18/net/bluetooth/bnep/netdev.c linux-2.4.18-mh9/net/bluetooth/bnep/netdev.c +--- linux-2.4.18/net/bluetooth/bnep/netdev.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/bnep/netdev.c Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,254 @@ ++/* ++ BNEP implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2001-2002 Inventel Systemes ++ Written 2001-2002 by ++ Cl�ment Moreau <clement.moreau@inventel.fr> ++ David Libault <david.libault@inventel.fr> ++ ++ Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/socket.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> ++#include <linux/wait.h> ++ ++#include <asm/unaligned.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++#include <net/bluetooth/l2cap.h> ++ ++#include "bnep.h" ++ ++#ifndef CONFIG_BLUEZ_BNEP_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#endif ++ ++#define BNEP_TX_QUEUE_LEN 20 ++ ++static int bnep_net_open(struct net_device *dev) ++{ ++ netif_start_queue(dev); ++ return 0; ++} ++ ++static int bnep_net_close(struct net_device *dev) ++{ ++ netif_stop_queue(dev); ++ return 0; ++} ++ ++static struct net_device_stats *bnep_net_get_stats(struct net_device *dev) ++{ ++ struct bnep_session *s = dev->priv; ++ return &s->stats; ++} ++ ++static void bnep_net_set_mc_list(struct net_device *dev) ++{ ++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER ++ struct bnep_session *s = dev->priv; ++ struct sock *sk = s->sock->sk; ++ struct bnep_set_filter_req *r; ++ struct sk_buff *skb; ++ int size; ++ ++ BT_DBG("%s mc_count %d", dev->name, dev->mc_count); ++ ++ size = sizeof(*r) + (BNEP_MAX_MULTICAST_FILTERS + 1) * ETH_ALEN * 2; ++ skb = alloc_skb(size, GFP_ATOMIC); ++ if (!skb) { ++ BT_ERR("%s Multicast list allocation failed", dev->name); ++ return; ++ } ++ ++ r = (void *) skb->data; ++ __skb_put(skb, sizeof(*r)); ++ ++ r->type = BNEP_CONTROL; ++ r->ctrl = BNEP_FILTER_MULTI_ADDR_SET; ++ ++ if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) { ++ u8 start[ETH_ALEN] = { 0x01 }; ++ ++ /* Request all addresses */ ++ memcpy(__skb_put(skb, ETH_ALEN), start, ETH_ALEN); ++ memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN); ++ r->len = htons(ETH_ALEN * 2); ++ } else { ++ struct dev_mc_list *dmi = dev->mc_list; ++ int i, len = skb->len; ++ ++ if (dev->flags & IFF_BROADCAST) { ++ memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN); ++ memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN); ++ } ++ ++ /* FIXME: We should group addresses here. */ ++ ++ for (i = 0; i < dev->mc_count && i < BNEP_MAX_MULTICAST_FILTERS; i++) { ++ memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN); ++ memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN); ++ dmi = dmi->next; ++ } ++ r->len = htons(skb->len - len); ++ } ++ ++ skb_queue_tail(&sk->write_queue, skb); ++ wake_up_interruptible(sk->sleep); ++#endif ++} ++ ++static int bnep_net_set_mac_addr(struct net_device *dev, void *arg) ++{ ++ BT_DBG("%s", dev->name); ++ return 0; ++} ++ ++static void bnep_net_timeout(struct net_device *dev) ++{ ++ BT_DBG("net_timeout"); ++ netif_wake_queue(dev); ++} ++ ++static int bnep_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ++{ ++ return -EINVAL; ++} ++ ++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER ++static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s) ++{ ++ struct ethhdr *eh = (void *) skb->data; ++ ++ if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), &s->mc_filter)) { ++ BT_DBG("BNEP: filtered skb %p, dst %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", skb, ++ eh->h_dest[0], eh->h_dest[1], eh->h_dest[2], ++ eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]); ++ return 1; ++ } ++ return 0; ++} ++#endif ++ ++#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER ++/* Determine ether protocol. Based on eth_type_trans. */ ++static inline u16 bnep_net_eth_proto(struct sk_buff *skb) ++{ ++ struct ethhdr *eh = (void *) skb->data; ++ ++ if (ntohs(eh->h_proto) >= 1536) ++ return eh->h_proto; ++ ++ if (get_unaligned((u16 *) skb->data) == 0xFFFF) ++ return htons(ETH_P_802_3); ++ ++ return htons(ETH_P_802_2); ++} ++ ++static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s) ++{ ++ u16 proto = bnep_net_eth_proto(skb); ++ struct bnep_proto_filter *f = s->proto_filter; ++ int i; ++ ++ for (i = 0; i < BNEP_MAX_PROTO_FILTERS && f[i].end; i++) { ++ if (proto >= f[i].start && proto <= f[i].end) ++ return 0; ++ } ++ ++ BT_DBG("BNEP: filtered skb %p, proto 0x%.4x", skb, proto); ++ return 1; ++} ++#endif ++ ++static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct bnep_session *s = dev->priv; ++ struct sock *sk = s->sock->sk; ++ ++ BT_DBG("skb %p, dev %p", skb, dev); ++ ++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER ++ if (bnep_net_mc_filter(skb, s)) { ++ kfree_skb(skb); ++ return 0; ++ } ++#endif ++ ++#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER ++ if (bnep_net_proto_filter(skb, s)) { ++ kfree_skb(skb); ++ return 0; ++ } ++#endif ++ ++ /* ++ * We cannot send L2CAP packets from here as we are potentially in a bh. ++ * So we have to queue them and wake up session thread which is sleeping ++ * on the sk->sleep. ++ */ ++ dev->trans_start = jiffies; ++ skb_queue_tail(&sk->write_queue, skb); ++ wake_up_interruptible(sk->sleep); ++ ++ if (skb_queue_len(&sk->write_queue) >= BNEP_TX_QUEUE_LEN) { ++ BT_DBG("tx queue is full"); ++ ++ /* Stop queuing. ++ * Session thread will do netif_wake_queue() */ ++ netif_stop_queue(dev); ++ } ++ ++ return 0; ++} ++ ++int bnep_net_init(struct net_device *dev) ++{ ++ struct bnep_session *s = dev->priv; ++ ++ memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN); ++ dev->addr_len = ETH_ALEN; ++ ++ ether_setup(dev); ++ ++ dev->open = bnep_net_open; ++ dev->stop = bnep_net_close; ++ dev->hard_start_xmit = bnep_net_xmit; ++ dev->get_stats = bnep_net_get_stats; ++ dev->do_ioctl = bnep_net_ioctl; ++ dev->set_mac_address = bnep_net_set_mac_addr; ++ dev->set_multicast_list = bnep_net_set_mc_list; ++ ++ dev->watchdog_timeo = HZ * 2; ++ dev->tx_timeout = bnep_net_timeout; ++ ++ return 0; ++} +diff -urN linux-2.4.18/net/bluetooth/bnep/sock.c linux-2.4.18-mh9/net/bluetooth/bnep/sock.c +--- linux-2.4.18/net/bluetooth/bnep/sock.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/bnep/sock.c Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,238 @@ ++/* ++ BNEP implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2001-2002 Inventel Systemes ++ Written 2001-2002 by ++ David Libault <david.libault@inventel.fr> ++ ++ Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * $Id$ ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/skbuff.h> ++#include <linux/socket.h> ++#include <linux/ioctl.h> ++#include <linux/file.h> ++#include <net/sock.h> ++ ++#include <asm/system.h> ++#include <asm/uaccess.h> ++ ++#include "bnep.h" ++ ++#ifndef CONFIG_BLUEZ_BNEP_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#endif ++ ++static inline struct socket *socki_lookup(struct inode *inode) ++{ ++ return &inode->u.socket_i; ++} ++ ++static struct socket *sockfd_lookup(int fd, int *err) ++{ ++ struct file *file; ++ struct inode *inode; ++ struct socket *sock; ++ ++ if (!(file = fget(fd))) { ++ *err = -EBADF; ++ return NULL; ++ } ++ ++ inode = file->f_dentry->d_inode; ++ if (!inode->i_sock || !(sock = socki_lookup(inode))) { ++ *err = -ENOTSOCK; ++ fput(file); ++ return NULL; ++ } ++ ++ if (sock->file != file) { ++ printk(KERN_ERR "socki_lookup: socket file changed!\n"); ++ sock->file = file; ++ } ++ return sock; ++} ++ ++static int bnep_sock_release(struct socket *sock) ++{ ++ struct sock *sk = sock->sk; ++ ++ BT_DBG("sock %p sk %p", sock, sk); ++ ++ if (!sk) ++ return 0; ++ ++ sock_orphan(sk); ++ sock_put(sk); ++ ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ++{ ++ struct bnep_connlist_req cl; ++ struct bnep_connadd_req ca; ++ struct bnep_conndel_req cd; ++ struct bnep_conninfo ci; ++ struct socket *nsock; ++ int err; ++ ++ BT_DBG("cmd %x arg %lx", cmd, arg); ++ ++ switch (cmd) { ++ case BNEPCONNADD: ++ if (!capable(CAP_NET_ADMIN)) ++ return -EACCES; ++ ++ if (copy_from_user(&ca, (void *) arg, sizeof(ca))) ++ return -EFAULT; ++ ++ nsock = sockfd_lookup(ca.sock, &err); ++ if (!nsock) ++ return err; ++ ++ if (nsock->sk->state != BT_CONNECTED) ++ return -EBADFD; ++ ++ err = bnep_add_connection(&ca, nsock); ++ if (!err) { ++ if (copy_to_user((void *) arg, &ca, sizeof(ca))) ++ err = -EFAULT; ++ } else ++ fput(nsock->file); ++ ++ return err; ++ ++ case BNEPCONNDEL: ++ if (!capable(CAP_NET_ADMIN)) ++ return -EACCES; ++ ++ if (copy_from_user(&cd, (void *) arg, sizeof(cd))) ++ return -EFAULT; ++ ++ return bnep_del_connection(&cd); ++ ++ case BNEPGETCONNLIST: ++ if (copy_from_user(&cl, (void *) arg, sizeof(cl))) ++ return -EFAULT; ++ ++ if (cl.cnum <= 0) ++ return -EINVAL; ++ ++ err = bnep_get_connlist(&cl); ++ if (!err && copy_to_user((void *) arg, &cl, sizeof(cl))) ++ return -EFAULT; ++ ++ return err; ++ ++ case BNEPGETCONNINFO: ++ if (copy_from_user(&ci, (void *) arg, sizeof(ci))) ++ return -EFAULT; ++ ++ err = bnep_get_conninfo(&ci); ++ if (!err && copy_to_user((void *) arg, &ci, sizeof(ci))) ++ return -EFAULT; ++ ++ return err; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static struct proto_ops bnep_sock_ops = { ++ family: PF_BLUETOOTH, ++ release: bnep_sock_release, ++ ioctl: bnep_sock_ioctl, ++ bind: sock_no_bind, ++ getname: sock_no_getname, ++ sendmsg: sock_no_sendmsg, ++ recvmsg: sock_no_recvmsg, ++ poll: sock_no_poll, ++ listen: sock_no_listen, ++ shutdown: sock_no_shutdown, ++ setsockopt: sock_no_setsockopt, ++ getsockopt: sock_no_getsockopt, ++ connect: sock_no_connect, ++ socketpair: sock_no_socketpair, ++ accept: sock_no_accept, ++ mmap: sock_no_mmap ++}; ++ ++static int bnep_sock_create(struct socket *sock, int protocol) ++{ ++ struct sock *sk; ++ ++ BT_DBG("sock %p", sock); ++ ++ if (sock->type != SOCK_RAW) ++ return -ESOCKTNOSUPPORT; ++ ++ sock->ops = &bnep_sock_ops; ++ ++ if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1))) ++ return -ENOMEM; ++ ++ MOD_INC_USE_COUNT; ++ ++ sock->state = SS_UNCONNECTED; ++ sock_init_data(sock, sk); ++ ++ sk->destruct = NULL; ++ sk->protocol = protocol; ++ ++ return 0; ++} ++ ++static struct net_proto_family bnep_sock_family_ops = { ++ family: PF_BLUETOOTH, ++ create: bnep_sock_create ++}; ++ ++int bnep_sock_init(void) ++{ ++ bluez_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops); ++ return 0; ++} ++ ++int bnep_sock_cleanup(void) ++{ ++ if (bluez_sock_unregister(BTPROTO_BNEP)) ++ BT_ERR("Can't unregister BNEP socket"); ++ return 0; ++} +diff -urN linux-2.4.18/net/bluetooth/cmtp/Config.in linux-2.4.18-mh9/net/bluetooth/cmtp/Config.in +--- linux-2.4.18/net/bluetooth/cmtp/Config.in Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/cmtp/Config.in Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,7 @@ ++# ++# Bluetooth CMTP layer configuration ++# ++ ++if [ "$CONFIG_ISDN" = "y" -o "$CONFIG_ISDN" = "m" ]; then ++ dep_tristate 'CMTP protocol support' CONFIG_BLUEZ_CMTP $CONFIG_ISDN_CAPI $CONFIG_BLUEZ_L2CAP ++fi +diff -urN linux-2.4.18/net/bluetooth/cmtp/Makefile linux-2.4.18-mh9/net/bluetooth/cmtp/Makefile +--- linux-2.4.18/net/bluetooth/cmtp/Makefile Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/cmtp/Makefile Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,10 @@ ++# ++# Makefile for the Linux Bluetooth CMTP layer ++# ++ ++O_TARGET := cmtp.o ++ ++obj-y := core.o sock.o capi.o ++obj-m += $(O_TARGET) ++ ++include $(TOPDIR)/Rules.make +diff -urN linux-2.4.18/net/bluetooth/cmtp/capi.c linux-2.4.18-mh9/net/bluetooth/cmtp/capi.c +--- linux-2.4.18/net/bluetooth/cmtp/capi.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/cmtp/capi.c Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,707 @@ ++/* ++ CMTP implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/skbuff.h> ++#include <linux/socket.h> ++#include <linux/ioctl.h> ++#include <linux/file.h> ++#include <net/sock.h> ++ ++#include <linux/capi.h> ++ ++#include "../drivers/isdn/avmb1/capilli.h" ++#include "../drivers/isdn/avmb1/capicmd.h" ++#include "../drivers/isdn/avmb1/capiutil.h" ++ ++#include "cmtp.h" ++ ++#ifndef CONFIG_BLUEZ_CMTP_DEBUG ++#undef BT_DBG ++#define BT_DBG(D...) ++#endif ++ ++#define REVISION "1.0" ++ ++#define CAPI_INTEROPERABILITY 0x20 ++ ++#define CAPI_INTEROPERABILITY_REQ CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ) ++#define CAPI_INTEROPERABILITY_CONF CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF) ++#define CAPI_INTEROPERABILITY_IND CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND) ++#define CAPI_INTEROPERABILITY_RESP CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP) ++ ++#define CAPI_INTEROPERABILITY_REQ_LEN (CAPI_MSG_BASELEN + 2) ++#define CAPI_INTEROPERABILITY_CONF_LEN (CAPI_MSG_BASELEN + 4) ++#define CAPI_INTEROPERABILITY_IND_LEN (CAPI_MSG_BASELEN + 2) ++#define CAPI_INTEROPERABILITY_RESP_LEN (CAPI_MSG_BASELEN + 2) ++ ++#define CAPI_FUNCTION_REGISTER 0 ++#define CAPI_FUNCTION_RELEASE 1 ++#define CAPI_FUNCTION_GET_PROFILE 2 ++#define CAPI_FUNCTION_GET_MANUFACTURER 3 ++#define CAPI_FUNCTION_GET_VERSION 4 ++#define CAPI_FUNCTION_GET_SERIAL_NUMBER 5 ++#define CAPI_FUNCTION_MANUFACTURER 6 ++#define CAPI_FUNCTION_LOOPBACK 7 ++ ++static struct capi_driver_interface *di; ++ ++ ++#define CMTP_MSGNUM 1 ++#define CMTP_APPLID 2 ++#define CMTP_MAPPING 3 ++ ++static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl) ++{ ++ struct cmtp_application *app = kmalloc(sizeof(*app), GFP_KERNEL); ++ ++ BT_DBG("session %p application %p appl %d", session, app, appl); ++ ++ if (!app) ++ return NULL; ++ ++ memset(app, 0, sizeof(*app)); ++ ++ app->state = BT_OPEN; ++ app->appl = appl; ++ ++ list_add_tail(&app->list, &session->applications); ++ ++ return app; ++} ++ ++static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app) ++{ ++ BT_DBG("session %p application %p", session, app); ++ ++ if (app) { ++ list_del(&app->list); ++ kfree(app); ++ } ++} ++ ++static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value) ++{ ++ struct cmtp_application *app; ++ struct list_head *p, *n; ++ ++ list_for_each_safe(p, n, &session->applications) { ++ app = list_entry(p, struct cmtp_application, list); ++ switch (pattern) { ++ case CMTP_MSGNUM: ++ if (app->msgnum == value) ++ return app; ++ break; ++ case CMTP_APPLID: ++ if (app->appl == value) ++ return app; ++ break; ++ case CMTP_MAPPING: ++ if (app->mapping == value) ++ return app; ++ break; ++ } ++ } ++ ++ return NULL; ++} ++ ++static int cmtp_msgnum_get(struct cmtp_session *session) ++{ ++ session->msgnum++; ++ ++ if ((session->msgnum & 0xff) > 200) ++ session->msgnum = CMTP_INITIAL_MSGNUM + 1; ++ ++ return session->msgnum; ++} ++ ++ ++static void cmtp_send_interopmsg(struct cmtp_session *session, ++ __u8 subcmd, __u16 appl, __u16 msgnum, ++ __u16 function, unsigned char *buf, int len) ++{ ++ struct sk_buff *skb; ++ unsigned char *s; ++ ++ BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum); ++ ++ if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) { ++ BT_ERR("Can't allocate memory for interoperability packet"); ++ return; ++ } ++ ++ s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len); ++ ++ capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len); ++ capimsg_setu16(s, 2, appl); ++ capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY); ++ capimsg_setu8 (s, 5, subcmd); ++ capimsg_setu16(s, 6, msgnum); ++ ++ /* Interoperability selector (Bluetooth Device Management) */ ++ capimsg_setu16(s, 8, 0x0001); ++ ++ capimsg_setu8 (s, 10, 3 + len); ++ capimsg_setu16(s, 11, function); ++ capimsg_setu8 (s, 13, len); ++ ++ if (len > 0) ++ memcpy(s + 14, buf, len); ++ ++ cmtp_send_capimsg(session, skb); ++} ++ ++static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb) ++{ ++ struct capi_ctr *ctrl = session->ctrl; ++ struct cmtp_application *application; ++ __u16 appl, msgnum, func, info; ++ __u32 controller; ++ ++ BT_DBG("session %p skb %p len %d", session, skb, skb->len); ++ ++ switch (CAPIMSG_SUBCOMMAND(skb->data)) { ++ case CAPI_CONF: ++ func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5); ++ info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8); ++ ++ switch (func) { ++ case CAPI_FUNCTION_REGISTER: ++ msgnum = CAPIMSG_MSGID(skb->data); ++ ++ application = cmtp_application_get(session, CMTP_MSGNUM, msgnum); ++ if (application) { ++ application->state = BT_CONNECTED; ++ application->msgnum = 0; ++ application->mapping = CAPIMSG_APPID(skb->data); ++ wake_up_interruptible(&session->wait); ++ } ++ ++ break; ++ ++ case CAPI_FUNCTION_RELEASE: ++ appl = CAPIMSG_APPID(skb->data); ++ ++ application = cmtp_application_get(session, CMTP_MAPPING, appl); ++ if (application) { ++ application->state = BT_CLOSED; ++ application->msgnum = 0; ++ wake_up_interruptible(&session->wait); ++ } ++ ++ break; ++ ++ case CAPI_FUNCTION_GET_PROFILE: ++ controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11); ++ msgnum = CAPIMSG_MSGID(skb->data); ++ ++ if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) { ++ session->ncontroller = controller; ++ wake_up_interruptible(&session->wait); ++ break; ++ } ++ ++ if (!info && ctrl) { ++ memcpy(&ctrl->profile, ++ skb->data + CAPI_MSG_BASELEN + 11, ++ sizeof(capi_profile)); ++ session->state = BT_CONNECTED; ++ ctrl->ready(ctrl); ++ } ++ ++ break; ++ ++ case CAPI_FUNCTION_GET_MANUFACTURER: ++ controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10); ++ ++ if (!info && ctrl) { ++ strncpy(ctrl->manu, ++ skb->data + CAPI_MSG_BASELEN + 15, ++ skb->data[CAPI_MSG_BASELEN + 14]); ++ } ++ ++ break; ++ ++ case CAPI_FUNCTION_GET_VERSION: ++ controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12); ++ ++ if (!info && ctrl) { ++ ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16); ++ ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20); ++ ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24); ++ ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28); ++ } ++ ++ break; ++ ++ case CAPI_FUNCTION_GET_SERIAL_NUMBER: ++ controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12); ++ ++ if (!info && ctrl) { ++ memset(ctrl->serial, 0, CAPI_SERIAL_LEN); ++ strncpy(ctrl->serial, ++ skb->data + CAPI_MSG_BASELEN + 17, ++ skb->data[CAPI_MSG_BASELEN + 16]); ++ } ++ ++ break; ++ } ++ ++ break; ++ ++ case CAPI_IND: ++ func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3); ++ ++ if (func == CAPI_FUNCTION_LOOPBACK) { ++ appl = CAPIMSG_APPID(skb->data); ++ msgnum = CAPIMSG_MSGID(skb->data); ++ cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func, ++ skb->data + CAPI_MSG_BASELEN + 6, ++ skb->data[CAPI_MSG_BASELEN + 5]); ++ } ++ ++ break; ++ } ++ ++ kfree_skb(skb); ++} ++ ++void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb) ++{ ++ struct capi_ctr *ctrl = session->ctrl; ++ struct cmtp_application *application; ++ __u16 cmd, appl, info; ++ __u32 ncci, contr; ++ ++ BT_DBG("session %p skb %p len %d", session, skb, skb->len); ++ ++ if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) { ++ cmtp_recv_interopmsg(session, skb); ++ return; ++ } ++ ++ if (session->flags & (1 << CMTP_LOOPBACK)) { ++ kfree_skb(skb); ++ return; ++ } ++ ++ cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data)); ++ appl = CAPIMSG_APPID(skb->data); ++ contr = CAPIMSG_CONTROL(skb->data); ++ ++ application = cmtp_application_get(session, CMTP_MAPPING, appl); ++ if (application) { ++ appl = application->appl; ++ CAPIMSG_SETAPPID(skb->data, appl); ++ } else { ++ BT_ERR("Can't find application with id %d", appl); ++ kfree_skb(skb); ++ return; ++ } ++ ++ if ((contr & 0x7f) == 0x01) { ++ contr = (contr & 0xffffff80) | session->num; ++ CAPIMSG_SETCONTROL(skb->data, contr); ++ } ++ ++ if (!ctrl) { ++ BT_ERR("Can't find controller %d for message", session->num); ++ kfree_skb(skb); ++ return; ++ } ++ ++ switch (cmd) { ++ case CAPI_CONNECT_B3_CONF: ++ ncci = CAPIMSG_NCCI(skb->data); ++ info = CAPIMSG_U16(skb->data, 12); ++ ++ BT_DBG("CONNECT_B3_CONF ncci 0x%02x info 0x%02x", ncci, info); ++ ++ if (info == 0) ++ ctrl->new_ncci(ctrl, appl, ncci, 8); ++ ++ ctrl->handle_capimsg(ctrl, appl, skb); ++ break; ++ ++ case CAPI_CONNECT_B3_IND: ++ ncci = CAPIMSG_NCCI(skb->data); ++ ++ BT_DBG("CONNECT_B3_IND ncci 0x%02x", ncci); ++ ++ ctrl->new_ncci(ctrl, appl, ncci, 8); ++ ctrl->handle_capimsg(ctrl, appl, skb); ++ break; ++ ++ case CAPI_DISCONNECT_B3_IND: ++ ncci = CAPIMSG_NCCI(skb->data); ++ ++ BT_DBG("DISCONNECT_B3_IND ncci 0x%02x", ncci); ++ ++ if (ncci == 0xffffffff) ++ BT_ERR("DISCONNECT_B3_IND with ncci 0xffffffff"); ++ ++ ctrl->handle_capimsg(ctrl, appl, skb); ++ ctrl->free_ncci(ctrl, appl, ncci); ++ break; ++ ++ default: ++ ctrl->handle_capimsg(ctrl, appl, skb); ++ break; ++ } ++} ++ ++void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb) ++{ ++ struct cmtp_scb *scb = (void *) skb->cb; ++ ++ BT_DBG("session %p skb %p len %d", session, skb, skb->len); ++ ++ scb->id = -1; ++ scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3); ++ ++ skb_queue_tail(&session->transmit, skb); ++ ++ cmtp_schedule(session); ++} ++ ++ ++static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) ++{ ++ BT_DBG("ctrl %p data %p", ctrl, data); ++ ++ return -EIO; ++} ++ ++static void cmtp_reset_ctr(struct capi_ctr *ctrl) ++{ ++ BT_DBG("ctrl %p", ctrl); ++ ++ ctrl->reseted(ctrl); ++} ++ ++static void cmtp_remove_ctr(struct capi_ctr *ctrl) ++{ ++ struct cmtp_session *session = ctrl->driverdata; ++ ++ BT_DBG("ctrl %p", ctrl); ++ ++ ctrl->suspend_output(ctrl); ++ ++ atomic_inc(&session->terminate); ++ cmtp_schedule(session); ++} ++ ++static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ struct cmtp_session *session = ctrl->driverdata; ++ struct cmtp_application *application; ++ unsigned long timeo = CMTP_INTEROP_TIMEOUT; ++ unsigned char buf[8]; ++ int err = 0, nconn, want = rp->level3cnt; ++ ++ BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d", ++ ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen); ++ ++ application = cmtp_application_add(session, appl); ++ if (!application) { ++ BT_ERR("Can't allocate memory for new application"); ++ ctrl->appl_released(ctrl, appl); ++ return; ++ } ++ ++ if (want < 0) ++ nconn = ctrl->profile.nbchannel * -want; ++ else ++ nconn = want; ++ ++ if (nconn == 0) ++ nconn = ctrl->profile.nbchannel; ++ ++ capimsg_setu16(buf, 0, nconn); ++ capimsg_setu16(buf, 2, rp->datablkcnt); ++ capimsg_setu16(buf, 4, rp->datablklen); ++ ++ application->state = BT_CONFIG; ++ application->msgnum = cmtp_msgnum_get(session); ++ ++ cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum, ++ CAPI_FUNCTION_REGISTER, buf, 6); ++ ++ add_wait_queue(&session->wait, &wait); ++ while (1) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ if (!timeo) { ++ err = -EAGAIN; ++ break; ++ } ++ ++ if (application->state == BT_CLOSED) { ++ err = -application->err; ++ break; ++ } ++ ++ if (application->state == BT_CONNECTED) ++ break; ++ ++ if (signal_pending(current)) { ++ err = -EINTR; ++ break; ++ } ++ ++ timeo = schedule_timeout(timeo); ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&session->wait, &wait); ++ ++ if (err) { ++ ctrl->appl_released(ctrl, appl); ++ cmtp_application_del(session, application); ++ return; ++ } ++ ++ ctrl->appl_registered(ctrl, appl); ++} ++ ++static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ struct cmtp_session *session = ctrl->driverdata; ++ struct cmtp_application *application; ++ unsigned long timeo = CMTP_INTEROP_TIMEOUT; ++ ++ BT_DBG("ctrl %p appl %d", ctrl, appl); ++ ++ application = cmtp_application_get(session, CMTP_APPLID, appl); ++ if (!application) { ++ BT_ERR("Can't find application"); ++ return; ++ } ++ ++ application->msgnum = cmtp_msgnum_get(session); ++ ++ cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum, ++ CAPI_FUNCTION_RELEASE, NULL, 0); ++ ++ add_wait_queue(&session->wait, &wait); ++ while (timeo) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ if (application->state == BT_CLOSED) ++ break; ++ ++ if (signal_pending(current)) ++ break; ++ ++ timeo = schedule_timeout(timeo); ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&session->wait, &wait); ++ ++ cmtp_application_del(session, application); ++ ctrl->appl_released(ctrl, appl); ++} ++ ++static void cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) ++{ ++ struct cmtp_session *session = ctrl->driverdata; ++ struct cmtp_application *application; ++ __u16 appl; ++ __u32 contr; ++ ++ BT_DBG("ctrl %p skb %p", ctrl, skb); ++ ++ appl = CAPIMSG_APPID(skb->data); ++ contr = CAPIMSG_CONTROL(skb->data); ++ ++ application = cmtp_application_get(session, CMTP_APPLID, appl); ++ if ((!application) || (application->state != BT_CONNECTED)) { ++ BT_ERR("Can't find application with id %d", appl); ++ kfree_skb(skb); ++ return; ++ } ++ ++ CAPIMSG_SETAPPID(skb->data, application->mapping); ++ ++ if ((contr & 0x7f) == session->num) { ++ contr = (contr & 0xffffff80) | 0x01; ++ CAPIMSG_SETCONTROL(skb->data, contr); ++ } ++ ++ cmtp_send_capimsg(session, skb); ++} ++ ++static char *cmtp_procinfo(struct capi_ctr *ctrl) ++{ ++ return "CAPI Message Transport Protocol"; ++} ++ ++static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl) ++{ ++ struct cmtp_session *session = ctrl->driverdata; ++ struct cmtp_application *app; ++ struct list_head *p, *n; ++ int len = 0; ++ ++ len += sprintf(page + len, "%s (Revision %s)\n\n", cmtp_procinfo(ctrl), REVISION); ++ len += sprintf(page + len, "addr %s\n", session->name); ++ len += sprintf(page + len, "ctrl %d\n", session->num); ++ ++ list_for_each_safe(p, n, &session->applications) { ++ app = list_entry(p, struct cmtp_application, list); ++ len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping); ++ } ++ ++ if (off + count >= len) ++ *eof = 1; ++ ++ if (len < off) ++ return 0; ++ ++ *start = page + off; ++ ++ return ((count < len - off) ? count : len - off); ++} ++ ++static struct capi_driver cmtp_driver = { ++ name: "cmtp", ++ revision: REVISION, ++ load_firmware: cmtp_load_firmware, ++ reset_ctr: cmtp_reset_ctr, ++ remove_ctr: cmtp_remove_ctr, ++ register_appl: cmtp_register_appl, ++ release_appl: cmtp_release_appl, ++ send_message: cmtp_send_message, ++ procinfo: cmtp_procinfo, ++ ctr_read_proc: cmtp_ctr_read_proc, ++ ++ driver_read_proc: 0, ++ add_card: 0, ++}; ++ ++ ++int cmtp_attach_device(struct cmtp_session *session) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long timeo = CMTP_INTEROP_TIMEOUT; ++ unsigned char buf[4]; ++ ++ BT_DBG("session %p", session); ++ ++ capimsg_setu32(buf, 0, 0); ++ ++ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM, ++ CAPI_FUNCTION_GET_PROFILE, buf, 4); ++ ++ add_wait_queue(&session->wait, &wait); ++ while (timeo) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ if (session->ncontroller) ++ break; ++ ++ if (signal_pending(current)) ++ break; ++ ++ timeo = schedule_timeout(timeo); ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&session->wait, &wait); ++ ++ BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name); ++ ++ if (!timeo) ++ return -ETIMEDOUT; ++ ++ if (!session->ncontroller) ++ return -ENODEV; ++ ++ ++ if (session->ncontroller > 1) ++ BT_INFO("Setting up only CAPI controller 1"); ++ ++ if (!(session->ctrl = di->attach_ctr(&cmtp_driver, session->name, session))) { ++ BT_ERR("Can't attach new controller"); ++ return -EBUSY; ++ } ++ ++ session->num = session->ctrl->cnr; ++ ++ BT_DBG("session %p ctrl %p num %d", session, session->ctrl, session->num); ++ ++ capimsg_setu32(buf, 0, 1); ++ ++ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), ++ CAPI_FUNCTION_GET_MANUFACTURER, buf, 4); ++ ++ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), ++ CAPI_FUNCTION_GET_VERSION, buf, 4); ++ ++ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), ++ CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4); ++ ++ cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session), ++ CAPI_FUNCTION_GET_PROFILE, buf, 4); ++ ++ return 0; ++} ++ ++void cmtp_detach_device(struct cmtp_session *session) ++{ ++ struct capi_ctr *ctrl = session->ctrl; ++ ++ BT_DBG("session %p ctrl %p", session, ctrl); ++ ++ if (!ctrl) ++ return; ++ ++ ctrl->reseted(ctrl); ++ ++ di->detach_ctr(ctrl); ++} ++ ++int cmtp_init_capi(void) ++{ ++ if (!(di = attach_capi_driver(&cmtp_driver))) { ++ BT_ERR("Can't attach CAPI driver"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++void cmtp_cleanup_capi(void) ++{ ++ detach_capi_driver(&cmtp_driver); ++} +diff -urN linux-2.4.18/net/bluetooth/cmtp/cmtp.h linux-2.4.18-mh9/net/bluetooth/cmtp/cmtp.h +--- linux-2.4.18/net/bluetooth/cmtp/cmtp.h Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/cmtp/cmtp.h Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,138 @@ ++/* ++ CMTP implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++#ifndef __CMTP_H ++#define __CMTP_H ++ ++#include <linux/types.h> ++#include <net/bluetooth/bluetooth.h> ++ ++#define BTNAMSIZ 18 ++ ++/* CMTP ioctl defines */ ++#define CMTPCONNADD _IOW('C', 200, int) ++#define CMTPCONNDEL _IOW('C', 201, int) ++#define CMTPGETCONNLIST _IOR('C', 210, int) ++#define CMTPGETCONNINFO _IOR('C', 211, int) ++ ++#define CMTP_LOOPBACK 0 ++ ++struct cmtp_connadd_req { ++ int sock; // Connected socket ++ __u32 flags; ++}; ++ ++struct cmtp_conndel_req { ++ bdaddr_t bdaddr; ++ __u32 flags; ++}; ++ ++struct cmtp_conninfo { ++ bdaddr_t bdaddr; ++ __u32 flags; ++ __u16 state; ++ int num; ++}; ++ ++struct cmtp_connlist_req { ++ __u32 cnum; ++ struct cmtp_conninfo *ci; ++}; ++ ++int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock); ++int cmtp_del_connection(struct cmtp_conndel_req *req); ++int cmtp_get_connlist(struct cmtp_connlist_req *req); ++int cmtp_get_conninfo(struct cmtp_conninfo *ci); ++ ++/* CMTP session defines */ ++#define CMTP_INTEROP_TIMEOUT (HZ * 5) ++#define CMTP_INITIAL_MSGNUM 0xff00 ++ ++struct cmtp_session { ++ struct list_head list; ++ ++ struct socket *sock; ++ ++ bdaddr_t bdaddr; ++ ++ unsigned long state; ++ unsigned long flags; ++ ++ uint mtu; ++ ++ char name[BTNAMSIZ]; ++ ++ atomic_t terminate; ++ ++ wait_queue_head_t wait; ++ ++ int ncontroller; ++ int num; ++ struct capi_ctr *ctrl; ++ ++ struct list_head applications; ++ ++ unsigned long blockids; ++ int msgnum; ++ ++ struct sk_buff_head transmit; ++ ++ struct sk_buff *reassembly[16]; ++}; ++ ++struct cmtp_application { ++ struct list_head list; ++ ++ unsigned long state; ++ int err; ++ ++ __u16 appl; ++ __u16 mapping; ++ ++ __u16 msgnum; ++}; ++ ++struct cmtp_scb { ++ int id; ++ int data; ++}; ++ ++int cmtp_attach_device(struct cmtp_session *session); ++void cmtp_detach_device(struct cmtp_session *session); ++ ++void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb); ++void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb); ++ ++static inline void cmtp_schedule(struct cmtp_session *session) ++{ ++ struct sock *sk = session->sock->sk; ++ ++ wake_up_interruptible(sk->sleep); ++} ++ ++/* CMTP init defines */ ++int cmtp_init_capi(void); ++int cmtp_init_sockets(void); ++void cmtp_cleanup_capi(void); ++void cmtp_cleanup_sockets(void); ++ ++#endif /* __CMTP_H */ +diff -urN linux-2.4.18/net/bluetooth/cmtp/core.c linux-2.4.18-mh9/net/bluetooth/cmtp/core.c +--- linux-2.4.18/net/bluetooth/cmtp/core.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/cmtp/core.c Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,515 @@ ++/* ++ CMTP implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/skbuff.h> ++#include <linux/socket.h> ++#include <linux/ioctl.h> ++#include <linux/file.h> ++#include <linux/init.h> ++#include <net/sock.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/l2cap.h> ++ ++#include "cmtp.h" ++ ++#ifndef CONFIG_BLUEZ_CMTP_DEBUG ++#undef BT_DBG ++#define BT_DBG(D...) ++#endif ++ ++#define VERSION "1.0" ++ ++static DECLARE_RWSEM(cmtp_session_sem); ++static LIST_HEAD(cmtp_session_list); ++ ++static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr) ++{ ++ struct cmtp_session *session; ++ struct list_head *p; ++ ++ BT_DBG(""); ++ ++ list_for_each(p, &cmtp_session_list) { ++ session = list_entry(p, struct cmtp_session, list); ++ if (!bacmp(bdaddr, &session->bdaddr)) ++ return session; ++ } ++ return NULL; ++} ++ ++static void __cmtp_link_session(struct cmtp_session *session) ++{ ++ MOD_INC_USE_COUNT; ++ list_add(&session->list, &cmtp_session_list); ++} ++ ++static void __cmtp_unlink_session(struct cmtp_session *session) ++{ ++ list_del(&session->list); ++ MOD_DEC_USE_COUNT; ++} ++ ++static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci) ++{ ++ bacpy(&ci->bdaddr, &session->bdaddr); ++ ++ ci->flags = session->flags; ++ ci->state = session->state; ++ ++ ci->num = session->num; ++} ++ ++ ++static inline int cmtp_alloc_block_id(struct cmtp_session *session) ++{ ++ int i, id = -1; ++ ++ for (i = 0; i < 16; i++) ++ if (!test_and_set_bit(i, &session->blockids)) { ++ id = i; ++ break; ++ } ++ ++ return id; ++} ++ ++static inline void cmtp_free_block_id(struct cmtp_session *session, int id) ++{ ++ clear_bit(id, &session->blockids); ++} ++ ++static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const unsigned char *buf, int count) ++{ ++ struct sk_buff *skb = session->reassembly[id], *nskb; ++ int size; ++ ++ BT_DBG("session %p buf %p count %d", session, buf, count); ++ ++ size = (skb) ? skb->len + count : count; ++ ++ if (!(nskb = alloc_skb(size, GFP_ATOMIC))) { ++ BT_ERR("Can't allocate memory for CAPI message"); ++ return; ++ } ++ ++ if (skb && (skb->len > 0)) ++ memcpy(skb_put(nskb, skb->len), skb->data, skb->len); ++ ++ memcpy(skb_put(nskb, count), buf, count); ++ ++ session->reassembly[id] = nskb; ++ ++ if (skb) ++ kfree_skb(skb); ++} ++ ++static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb) ++{ ++ __u8 hdr, hdrlen, id; ++ __u16 len; ++ ++ BT_DBG("session %p skb %p len %d", session, skb, skb->len); ++ ++ while (skb->len > 0) { ++ hdr = skb->data[0]; ++ ++ switch (hdr & 0xc0) { ++ case 0x40: ++ hdrlen = 2; ++ len = skb->data[1]; ++ break; ++ case 0x80: ++ hdrlen = 3; ++ len = skb->data[1] | (skb->data[2] << 8); ++ break; ++ default: ++ hdrlen = 1; ++ len = 0; ++ break; ++ } ++ ++ id = (hdr & 0x3c) >> 2; ++ ++ BT_DBG("hdr 0x%02x hdrlen %d len %d id %d", hdr, hdrlen, len, id); ++ ++ if (hdrlen + len > skb->len) { ++ BT_ERR("Wrong size or header information in CMTP frame"); ++ break; ++ } ++ ++ if (len == 0) { ++ skb_pull(skb, hdrlen); ++ continue; ++ } ++ ++ switch (hdr & 0x03) { ++ case 0x00: ++ cmtp_add_msgpart(session, id, skb->data + hdrlen, len); ++ cmtp_recv_capimsg(session, session->reassembly[id]); ++ session->reassembly[id] = NULL; ++ break; ++ case 0x01: ++ cmtp_add_msgpart(session, id, skb->data + hdrlen, len); ++ break; ++ default: ++ if (session->reassembly[id] != NULL) ++ kfree_skb(session->reassembly[id]); ++ session->reassembly[id] = NULL; ++ break; ++ } ++ ++ skb_pull(skb, hdrlen + len); ++ } ++ ++ kfree_skb(skb); ++ return 0; ++} ++ ++static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, int len) ++{ ++ struct socket *sock = session->sock; ++ struct iovec iv = { data, len }; ++ struct msghdr msg; ++ int err; ++ ++ BT_DBG("session %p data %p len %d", session, data, len); ++ ++ if (!len) ++ return 0; ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.msg_iovlen = 1; ++ msg.msg_iov = &iv; ++ ++ err = sock->ops->sendmsg(sock, &msg, len, 0); ++ return err; ++} ++ ++static int cmtp_process_transmit(struct cmtp_session *session) ++{ ++ struct sk_buff *skb, *nskb; ++ unsigned char *hdr; ++ unsigned int size, tail; ++ ++ BT_DBG("session %p", session); ++ ++ if (!(nskb = alloc_skb(session->mtu, GFP_ATOMIC))) { ++ BT_ERR("Can't allocate memory for new frame"); ++ return -ENOMEM; ++ } ++ ++ while ((skb = skb_dequeue(&session->transmit))) { ++ struct cmtp_scb *scb = (void *) skb->cb; ++ ++ if ((tail = (session->mtu - nskb->len)) < 5) { ++ cmtp_send_frame(session, nskb->data, nskb->len); ++ skb_trim(nskb, 0); ++ tail = session->mtu; ++ } ++ ++ size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len); ++ ++ if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) { ++ skb_queue_head(&session->transmit, skb); ++ break; ++ } ++ ++ if (size < 256) { ++ hdr = skb_put(nskb, 2); ++ hdr[0] = 0x40 ++ | ((scb->id << 2) & 0x3c) ++ | ((skb->len == size) ? 0x00 : 0x01); ++ hdr[1] = size; ++ } else { ++ hdr = skb_put(nskb, 3); ++ hdr[0] = 0x80 ++ | ((scb->id << 2) & 0x3c) ++ | ((skb->len == size) ? 0x00 : 0x01); ++ hdr[1] = size & 0xff; ++ hdr[2] = size >> 8; ++ } ++ ++ memcpy(skb_put(nskb, size), skb->data, size); ++ skb_pull(skb, size); ++ ++ if (skb->len > 0) { ++ skb_queue_head(&session->transmit, skb); ++ } else { ++ cmtp_free_block_id(session, scb->id); ++ if (scb->data) { ++ cmtp_send_frame(session, nskb->data, nskb->len); ++ skb_trim(nskb, 0); ++ } ++ kfree_skb(skb); ++ } ++ } ++ ++ cmtp_send_frame(session, nskb->data, nskb->len); ++ ++ kfree_skb(nskb); ++ ++ return skb_queue_len(&session->transmit); ++} ++ ++static int cmtp_session(void *arg) ++{ ++ struct cmtp_session *session = arg; ++ struct sock *sk = session->sock->sk; ++ struct sk_buff *skb; ++ wait_queue_t wait; ++ ++ BT_DBG("session %p", session); ++ ++ daemonize(); reparent_to_init(); ++ ++ sprintf(current->comm, "kcmtpd_ctr_%d", session->num); ++ ++ sigfillset(¤t->blocked); ++ flush_signals(current); ++ ++ current->nice = -15; ++ ++ set_fs(KERNEL_DS); ++ ++ init_waitqueue_entry(&wait, current); ++ add_wait_queue(sk->sleep, &wait); ++ while (!atomic_read(&session->terminate)) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ if (sk->state != BT_CONNECTED) ++ break; ++ ++ while ((skb = skb_dequeue(&sk->receive_queue))) { ++ skb_orphan(skb); ++ cmtp_recv_frame(session, skb); ++ } ++ ++ cmtp_process_transmit(session); ++ ++ schedule(); ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(sk->sleep, &wait); ++ ++ down_write(&cmtp_session_sem); ++ ++ if (!(session->flags & (1 << CMTP_LOOPBACK))) ++ cmtp_detach_device(session); ++ ++ fput(session->sock->file); ++ ++ __cmtp_unlink_session(session); ++ ++ up_write(&cmtp_session_sem); ++ ++ kfree(session); ++ return 0; ++} ++ ++int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) ++{ ++ struct cmtp_session *session, *s; ++ bdaddr_t src, dst; ++ int i, err; ++ ++ BT_DBG(""); ++ ++ baswap(&src, &bluez_pi(sock->sk)->src); ++ baswap(&dst, &bluez_pi(sock->sk)->dst); ++ ++ session = kmalloc(sizeof(struct cmtp_session), GFP_KERNEL); ++ if (!session) ++ return -ENOMEM; ++ memset(session, 0, sizeof(struct cmtp_session)); ++ ++ down_write(&cmtp_session_sem); ++ ++ s = __cmtp_get_session(&bluez_pi(sock->sk)->dst); ++ if (s && s->state == BT_CONNECTED) { ++ err = -EEXIST; ++ goto failed; ++ } ++ ++ bacpy(&session->bdaddr, &bluez_pi(sock->sk)->dst); ++ ++ session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu); ++ ++ BT_DBG("mtu %d", session->mtu); ++ ++ sprintf(session->name, "%s", batostr(&dst)); ++ ++ session->sock = sock; ++ session->state = BT_CONFIG; ++ ++ init_waitqueue_head(&session->wait); ++ ++ session->ctrl = NULL; ++ session->msgnum = CMTP_INITIAL_MSGNUM; ++ ++ INIT_LIST_HEAD(&session->applications); ++ ++ skb_queue_head_init(&session->transmit); ++ ++ for (i = 0; i < 16; i++) ++ session->reassembly[i] = NULL; ++ ++ session->flags = req->flags; ++ ++ __cmtp_link_session(session); ++ ++ err = kernel_thread(cmtp_session, session, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); ++ if (err < 0) ++ goto unlink; ++ ++ if (!(session->flags & (1 << CMTP_LOOPBACK))) { ++ err = cmtp_attach_device(session); ++ if (err < 0) ++ goto detach; ++ } ++ ++ up_write(&cmtp_session_sem); ++ return 0; ++ ++detach: ++ cmtp_detach_device(session); ++ ++unlink: ++ __cmtp_unlink_session(session); ++ ++failed: ++ up_write(&cmtp_session_sem); ++ kfree(session); ++ return err; ++} ++ ++int cmtp_del_connection(struct cmtp_conndel_req *req) ++{ ++ struct cmtp_session *session; ++ int err = 0; ++ ++ BT_DBG(""); ++ ++ down_read(&cmtp_session_sem); ++ ++ session = __cmtp_get_session(&req->bdaddr); ++ if (session) { ++ /* Flush the transmit queue */ ++ skb_queue_purge(&session->transmit); ++ ++ /* Kill session thread */ ++ atomic_inc(&session->terminate); ++ cmtp_schedule(session); ++ } else ++ err = -ENOENT; ++ ++ up_read(&cmtp_session_sem); ++ return err; ++} ++ ++int cmtp_get_connlist(struct cmtp_connlist_req *req) ++{ ++ struct list_head *p; ++ int err = 0, n = 0; ++ ++ BT_DBG(""); ++ ++ down_read(&cmtp_session_sem); ++ ++ list_for_each(p, &cmtp_session_list) { ++ struct cmtp_session *session; ++ struct cmtp_conninfo ci; ++ ++ session = list_entry(p, struct cmtp_session, list); ++ ++ __cmtp_copy_session(session, &ci); ++ ++ if (copy_to_user(req->ci, &ci, sizeof(ci))) { ++ err = -EFAULT; ++ break; ++ } ++ ++ if (++n >= req->cnum) ++ break; ++ ++ req->ci++; ++ } ++ req->cnum = n; ++ ++ up_read(&cmtp_session_sem); ++ return err; ++} ++ ++int cmtp_get_conninfo(struct cmtp_conninfo *ci) ++{ ++ struct cmtp_session *session; ++ int err = 0; ++ ++ down_read(&cmtp_session_sem); ++ ++ session = __cmtp_get_session(&ci->bdaddr); ++ if (session) ++ __cmtp_copy_session(session, ci); ++ else ++ err = -ENOENT; ++ ++ up_read(&cmtp_session_sem); ++ return err; ++} ++ ++ ++int __init init_cmtp(void) ++{ ++ l2cap_load(); ++ ++ cmtp_init_capi(); ++ cmtp_init_sockets(); ++ ++ BT_INFO("BlueZ CMTP ver %s", VERSION); ++ BT_INFO("Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>"); ++ ++ return 0; ++} ++ ++void __exit exit_cmtp(void) ++{ ++ cmtp_cleanup_sockets(); ++ cmtp_cleanup_capi(); ++} ++ ++module_init(init_cmtp); ++module_exit(exit_cmtp); ++ ++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); ++MODULE_DESCRIPTION("BlueZ CMTP ver " VERSION); ++MODULE_LICENSE("GPL"); +diff -urN linux-2.4.18/net/bluetooth/cmtp/sock.c linux-2.4.18-mh9/net/bluetooth/cmtp/sock.c +--- linux-2.4.18/net/bluetooth/cmtp/sock.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/cmtp/sock.c Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,236 @@ ++/* ++ CMTP implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/skbuff.h> ++#include <linux/socket.h> ++#include <linux/ioctl.h> ++#include <linux/file.h> ++#include <net/sock.h> ++ ++#include <asm/system.h> ++#include <asm/uaccess.h> ++ ++#include "cmtp.h" ++ ++#ifndef CONFIG_BLUEZ_CMTP_DEBUG ++#undef BT_DBG ++#define BT_DBG(D...) ++#endif ++ ++static inline struct socket *socki_lookup(struct inode *inode) ++{ ++ return &inode->u.socket_i; ++} ++ ++static struct socket *sockfd_lookup(int fd, int *err) ++{ ++ struct file *file; ++ struct inode *inode; ++ struct socket *sock; ++ ++ if (!(file = fget(fd))) { ++ *err = -EBADF; ++ return NULL; ++ } ++ ++ inode = file->f_dentry->d_inode; ++ if (!inode->i_sock || !(sock = socki_lookup(inode))) { ++ *err = -ENOTSOCK; ++ fput(file); ++ return NULL; ++ } ++ ++ if (sock->file != file) { ++ printk(KERN_ERR "socki_lookup: socket file changed!\n"); ++ sock->file = file; ++ } ++ return sock; ++} ++ ++static int cmtp_sock_release(struct socket *sock) ++{ ++ struct sock *sk = sock->sk; ++ ++ BT_DBG("sock %p sk %p", sock, sk); ++ ++ if (!sk) ++ return 0; ++ ++ sock_orphan(sk); ++ sock_put(sk); ++ ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ++{ ++ struct cmtp_connadd_req ca; ++ struct cmtp_conndel_req cd; ++ struct cmtp_connlist_req cl; ++ struct cmtp_conninfo ci; ++ struct socket *nsock; ++ int err; ++ ++ BT_DBG("cmd %x arg %lx", cmd, arg); ++ ++ switch (cmd) { ++ case CMTPCONNADD: ++ if (!capable(CAP_NET_ADMIN)) ++ return -EACCES; ++ ++ if (copy_from_user(&ca, (void *) arg, sizeof(ca))) ++ return -EFAULT; ++ ++ nsock = sockfd_lookup(ca.sock, &err); ++ if (!nsock) ++ return err; ++ ++ if (nsock->sk->state != BT_CONNECTED) ++ return -EBADFD; ++ ++ err = cmtp_add_connection(&ca, nsock); ++ if (!err) { ++ if (copy_to_user((void *) arg, &ca, sizeof(ca))) ++ err = -EFAULT; ++ } else ++ fput(nsock->file); ++ ++ return err; ++ ++ case CMTPCONNDEL: ++ if (!capable(CAP_NET_ADMIN)) ++ return -EACCES; ++ ++ if (copy_from_user(&cd, (void *) arg, sizeof(cd))) ++ return -EFAULT; ++ ++ return cmtp_del_connection(&cd); ++ ++ case CMTPGETCONNLIST: ++ if (copy_from_user(&cl, (void *) arg, sizeof(cl))) ++ return -EFAULT; ++ ++ if (cl.cnum <= 0) ++ return -EINVAL; ++ ++ err = cmtp_get_connlist(&cl); ++ if (!err && copy_to_user((void *) arg, &cl, sizeof(cl))) ++ return -EFAULT; ++ ++ return err; ++ ++ case CMTPGETCONNINFO: ++ if (copy_from_user(&ci, (void *) arg, sizeof(ci))) ++ return -EFAULT; ++ ++ err = cmtp_get_conninfo(&ci); ++ if (!err && copy_to_user((void *) arg, &ci, sizeof(ci))) ++ return -EFAULT; ++ ++ return err; ++ } ++ ++ return -EINVAL; ++} ++ ++static struct proto_ops cmtp_sock_ops = { ++ family: PF_BLUETOOTH, ++ release: cmtp_sock_release, ++ ioctl: cmtp_sock_ioctl, ++ bind: sock_no_bind, ++ getname: sock_no_getname, ++ sendmsg: sock_no_sendmsg, ++ recvmsg: sock_no_recvmsg, ++ poll: sock_no_poll, ++ listen: sock_no_listen, ++ shutdown: sock_no_shutdown, ++ setsockopt: sock_no_setsockopt, ++ getsockopt: sock_no_getsockopt, ++ connect: sock_no_connect, ++ socketpair: sock_no_socketpair, ++ accept: sock_no_accept, ++ mmap: sock_no_mmap ++}; ++ ++static int cmtp_sock_create(struct socket *sock, int protocol) ++{ ++ struct sock *sk; ++ ++ BT_DBG("sock %p", sock); ++ ++ if (sock->type != SOCK_RAW) ++ return -ESOCKTNOSUPPORT; ++ ++ sock->ops = &cmtp_sock_ops; ++ ++ if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1))) ++ return -ENOMEM; ++ ++ MOD_INC_USE_COUNT; ++ ++ sock->state = SS_UNCONNECTED; ++ sock_init_data(sock, sk); ++ ++ sk->destruct = NULL; ++ sk->protocol = protocol; ++ ++ return 0; ++} ++ ++static struct net_proto_family cmtp_sock_family_ops = { ++ family: PF_BLUETOOTH, ++ create: cmtp_sock_create ++}; ++ ++int cmtp_init_sockets(void) ++{ ++ int err; ++ ++ if ((err = bluez_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops))) { ++ BT_ERR("Can't register CMTP socket layer (%d)", err); ++ return err; ++ } ++ ++ return 0; ++} ++ ++void cmtp_cleanup_sockets(void) ++{ ++ int err; ++ ++ if ((err = bluez_sock_unregister(BTPROTO_CMTP))) ++ BT_ERR("Can't unregister CMTP socket layer (%d)", err); ++ ++ return; ++} +diff -urN linux-2.4.18/net/bluetooth/hci_conn.c linux-2.4.18-mh9/net/bluetooth/hci_conn.c +--- linux-2.4.18/net/bluetooth/hci_conn.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/hci_conn.c Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,441 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * HCI Connection handling. ++ * ++ * $Id$ ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/init.h> ++#include <linux/skbuff.h> ++#include <linux/interrupt.h> ++#include <linux/notifier.h> ++#include <net/sock.h> ++ ++#include <asm/system.h> ++#include <asm/uaccess.h> ++#include <asm/unaligned.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++ ++#ifndef HCI_CORE_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#endif ++ ++void hci_acl_connect(struct hci_conn *conn) ++{ ++ struct hci_dev *hdev = conn->hdev; ++ struct inquiry_entry *ie; ++ create_conn_cp cp; ++ ++ BT_DBG("%p", conn); ++ ++ conn->state = BT_CONNECT; ++ conn->out = 1; ++ conn->link_mode = HCI_LM_MASTER; ++ ++ memset(&cp, 0, sizeof(cp)); ++ bacpy(&cp.bdaddr, &conn->dst); ++ cp.pscan_rep_mode = 0x01; ++ ++ if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) && ++ inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { ++ cp.pscan_rep_mode = ie->info.pscan_rep_mode; ++ cp.pscan_mode = ie->info.pscan_mode; ++ cp.clock_offset = ie->info.clock_offset | __cpu_to_le16(0x8000); ++ } ++ ++ cp.pkt_type = __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK); ++ if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER)) ++ cp.role_switch = 0x01; ++ else ++ cp.role_switch = 0x00; ++ ++ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, ++ CREATE_CONN_CP_SIZE, &cp); ++} ++ ++void hci_acl_disconn(struct hci_conn *conn, __u8 reason) ++{ ++ disconnect_cp cp; ++ ++ BT_DBG("%p", conn); ++ ++ conn->state = BT_DISCONN; ++ ++ cp.handle = __cpu_to_le16(conn->handle); ++ cp.reason = reason; ++ hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT, ++ DISCONNECT_CP_SIZE, &cp); ++} ++ ++void hci_add_sco(struct hci_conn *conn, __u16 handle) ++{ ++ struct hci_dev *hdev = conn->hdev; ++ add_sco_cp cp; ++ ++ BT_DBG("%p", conn); ++ ++ conn->state = BT_CONNECT; ++ conn->out = 1; ++ ++ cp.pkt_type = __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); ++ cp.handle = __cpu_to_le16(handle); ++ ++ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, ADD_SCO_CP_SIZE, &cp); ++} ++ ++static void hci_conn_timeout(unsigned long arg) ++{ ++ struct hci_conn *conn = (void *)arg; ++ struct hci_dev *hdev = conn->hdev; ++ ++ BT_DBG("conn %p state %d", conn, conn->state); ++ ++ if (atomic_read(&conn->refcnt)) ++ return; ++ ++ hci_dev_lock(hdev); ++ if (conn->state == BT_CONNECTED) ++ hci_acl_disconn(conn, 0x13); ++ else ++ conn->state = BT_CLOSED; ++ hci_dev_unlock(hdev); ++ return; ++} ++ ++static void hci_conn_init_timer(struct hci_conn *conn) ++{ ++ init_timer(&conn->timer); ++ conn->timer.function = hci_conn_timeout; ++ conn->timer.data = (unsigned long)conn; ++} ++ ++struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) ++{ ++ struct hci_conn *conn; ++ ++ BT_DBG("%s dst %s", hdev->name, batostr(dst)); ++ ++ if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC))) ++ return NULL; ++ memset(conn, 0, sizeof(struct hci_conn)); ++ ++ bacpy(&conn->dst, dst); ++ conn->type = type; ++ conn->hdev = hdev; ++ conn->state = BT_OPEN; ++ ++ skb_queue_head_init(&conn->data_q); ++ hci_conn_init_timer(conn); ++ ++ atomic_set(&conn->refcnt, 0); ++ ++ hci_dev_hold(hdev); ++ ++ if (hdev->notify) ++ hdev->notify(hdev, HCI_NOTIFY_CONN_ADD, (unsigned long) conn); ++ ++ tasklet_disable(&hdev->tx_task); ++ conn_hash_add(hdev, conn); ++ tasklet_enable(&hdev->tx_task); ++ ++ return conn; ++} ++ ++int hci_conn_del(struct hci_conn *conn) ++{ ++ struct hci_dev *hdev = conn->hdev; ++ ++ BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle); ++ ++ hci_conn_del_timer(conn); ++ ++ if (conn->type == SCO_LINK) { ++ struct hci_conn *acl = conn->link; ++ if (acl) { ++ acl->link = NULL; ++ hci_conn_put(acl); ++ } ++ } else { ++ struct hci_conn *sco = conn->link; ++ if (sco) ++ sco->link = NULL; ++ ++ /* Unacked frames */ ++ hdev->acl_cnt += conn->sent; ++ } ++ ++ tasklet_disable(&hdev->tx_task); ++ conn_hash_del(hdev, conn); ++ tasklet_enable(&hdev->tx_task); ++ ++ skb_queue_purge(&conn->data_q); ++ ++ if (hdev->notify) ++ hdev->notify(hdev, HCI_NOTIFY_CONN_DEL, (unsigned long) conn); ++ ++ hci_dev_put(hdev); ++ ++ kfree(conn); ++ return 0; ++} ++ ++struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) ++{ ++ int use_src = bacmp(src, BDADDR_ANY); ++ struct hci_dev *hdev = NULL; ++ struct list_head *p; ++ ++ BT_DBG("%s -> %s", batostr(src), batostr(dst)); ++ ++ read_lock_bh(&hdev_list_lock); ++ ++ list_for_each(p, &hdev_list) { ++ struct hci_dev *d; ++ d = list_entry(p, struct hci_dev, list); ++ ++ if (!test_bit(HCI_UP, &d->flags)) ++ continue; ++ ++ /* Simple routing: ++ * No source address - find interface with bdaddr != dst ++ * Source address - find interface with bdaddr == src ++ */ ++ ++ if (use_src) { ++ if (!bacmp(&d->bdaddr, src)) { ++ hdev = d; break; ++ } ++ } else { ++ if (bacmp(&d->bdaddr, dst)) { ++ hdev = d; break; ++ } ++ } ++ } ++ ++ if (hdev) ++ hci_dev_hold(hdev); ++ ++ read_unlock_bh(&hdev_list_lock); ++ return hdev; ++} ++ ++/* Create SCO or ACL connection. ++ * Device _must_ be locked */ ++struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst) ++{ ++ struct hci_conn *acl; ++ ++ BT_DBG("%s dst %s", hdev->name, batostr(dst)); ++ ++ if (!(acl = conn_hash_lookup_ba(hdev, ACL_LINK, dst))) { ++ if (!(acl = hci_conn_add(hdev, ACL_LINK, dst))) ++ return NULL; ++ } ++ ++ hci_conn_hold(acl); ++ ++ if (acl->state == BT_OPEN || acl->state == BT_CLOSED) ++ hci_acl_connect(acl); ++ ++ if (type == SCO_LINK) { ++ struct hci_conn *sco; ++ ++ if (!(sco = conn_hash_lookup_ba(hdev, SCO_LINK, dst))) { ++ if (!(sco = hci_conn_add(hdev, SCO_LINK, dst))) { ++ hci_conn_put(acl); ++ return NULL; ++ } ++ } ++ acl->link = sco; ++ sco->link = acl; ++ ++ hci_conn_hold(sco); ++ ++ if (acl->state == BT_CONNECTED && ++ (sco->state == BT_OPEN || sco->state == BT_CLOSED)) ++ hci_add_sco(sco, acl->handle); ++ ++ return sco; ++ } else { ++ return acl; ++ } ++} ++ ++/* Authenticate remote device */ ++int hci_conn_auth(struct hci_conn *conn) ++{ ++ BT_DBG("conn %p", conn); ++ ++ if (conn->link_mode & HCI_LM_AUTH) ++ return 1; ++ ++ if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { ++ auth_requested_cp ar; ++ ar.handle = __cpu_to_le16(conn->handle); ++ hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_AUTH_REQUESTED, ++ AUTH_REQUESTED_CP_SIZE, &ar); ++ } ++ return 0; ++} ++ ++/* Enable encryption */ ++int hci_conn_encrypt(struct hci_conn *conn) ++{ ++ BT_DBG("conn %p", conn); ++ ++ if (conn->link_mode & HCI_LM_ENCRYPT) ++ return 1; ++ ++ if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) ++ return 0; ++ ++ if (hci_conn_auth(conn)) { ++ set_conn_encrypt_cp ce; ++ ce.handle = __cpu_to_le16(conn->handle); ++ ce.encrypt = 1; ++ hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT, ++ SET_CONN_ENCRYPT_CP_SIZE, &ce); ++ } ++ return 0; ++} ++ ++/* Drop all connection on the device */ ++void hci_conn_hash_flush(struct hci_dev *hdev) ++{ ++ struct conn_hash *h = &hdev->conn_hash; ++ struct list_head *p; ++ ++ BT_DBG("hdev %s", hdev->name); ++ ++ p = h->list.next; ++ while (p != &h->list) { ++ struct hci_conn *c; ++ ++ c = list_entry(p, struct hci_conn, list); ++ p = p->next; ++ ++ c->state = BT_CLOSED; ++ ++ hci_proto_disconn_ind(c, 0x16); ++ hci_conn_del(c); ++ } ++} ++ ++int hci_get_conn_list(unsigned long arg) ++{ ++ struct hci_conn_list_req req, *cl; ++ struct hci_conn_info *ci; ++ struct hci_dev *hdev; ++ struct list_head *p; ++ int n = 0, size; ++ ++ if (copy_from_user(&req, (void *) arg, sizeof(req))) ++ return -EFAULT; ++ ++ if (!(hdev = hci_dev_get(req.dev_id))) ++ return -ENODEV; ++ ++ size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req); ++ ++ if (verify_area(VERIFY_WRITE, (void *)arg, size)) ++ return -EFAULT; ++ ++ if (!(cl = (void *) kmalloc(size, GFP_KERNEL))) ++ return -ENOMEM; ++ ci = cl->conn_info; ++ ++ hci_dev_lock_bh(hdev); ++ list_for_each(p, &hdev->conn_hash.list) { ++ register struct hci_conn *c; ++ c = list_entry(p, struct hci_conn, list); ++ ++ bacpy(&(ci + n)->bdaddr, &c->dst); ++ (ci + n)->handle = c->handle; ++ (ci + n)->type = c->type; ++ (ci + n)->out = c->out; ++ (ci + n)->state = c->state; ++ (ci + n)->link_mode = c->link_mode; ++ n++; ++ } ++ hci_dev_unlock_bh(hdev); ++ ++ cl->dev_id = hdev->id; ++ cl->conn_num = n; ++ size = n * sizeof(struct hci_conn_info) + sizeof(req); ++ ++ hci_dev_put(hdev); ++ ++ copy_to_user((void *) arg, cl, size); ++ kfree(cl); ++ ++ return 0; ++} ++ ++int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg) ++{ ++ struct hci_conn_info_req req; ++ struct hci_conn_info ci; ++ struct hci_conn *conn; ++ char *ptr = (void *) arg + sizeof(req); ++ ++ if (copy_from_user(&req, (void *) arg, sizeof(req))) ++ return -EFAULT; ++ ++ if (verify_area(VERIFY_WRITE, ptr, sizeof(ci))) ++ return -EFAULT; ++ ++ hci_dev_lock_bh(hdev); ++ conn = conn_hash_lookup_ba(hdev, req.type, &req.bdaddr); ++ if (conn) { ++ bacpy(&ci.bdaddr, &conn->dst); ++ ci.handle = conn->handle; ++ ci.type = conn->type; ++ ci.out = conn->out; ++ ci.state = conn->state; ++ ci.link_mode = conn->link_mode; ++ } ++ hci_dev_unlock_bh(hdev); ++ ++ if (!conn) ++ return -ENOENT; ++ ++ copy_to_user(ptr, &ci, sizeof(ci)); ++ return 0; ++} +diff -urN linux-2.4.18/net/bluetooth/hci_core.c linux-2.4.18-mh9/net/bluetooth/hci_core.c +--- linux-2.4.18/net/bluetooth/hci_core.c Fri Nov 9 23:21:21 2001 ++++ linux-2.4.18-mh9/net/bluetooth/hci_core.c Mon Aug 25 18:38:12 2003 +@@ -25,11 +25,12 @@ + /* + * BlueZ HCI Core. + * +- * $Id$ ++ * $Id$ + */ + + #include <linux/config.h> + #include <linux/module.h> ++#include <linux/kmod.h> + + #include <linux/types.h> + #include <linux/errno.h> +@@ -50,12 +51,11 @@ + #include <asm/unaligned.h> + + #include <net/bluetooth/bluetooth.h> +-#include <net/bluetooth/bluez.h> + #include <net/bluetooth/hci_core.h> + + #ifndef HCI_CORE_DEBUG +-#undef DBG +-#define DBG( A... ) ++#undef BT_DBG ++#define BT_DBG( A... ) + #endif + + static void hci_cmd_task(unsigned long arg); +@@ -63,279 +63,69 @@ + static void hci_tx_task(unsigned long arg); + static void hci_notify(struct hci_dev *hdev, int event); + +-static rwlock_t hci_task_lock = RW_LOCK_UNLOCKED; ++rwlock_t hci_task_lock = RW_LOCK_UNLOCKED; + + /* HCI device list */ +-struct hci_dev *hdev_list[HCI_MAX_DEV]; +-spinlock_t hdev_list_lock; +-#define GET_HDEV(a) (hdev_list[a]) +- +-/* HCI protocol list */ +-struct hci_proto *hproto_list[HCI_MAX_PROTO]; +-#define GET_HPROTO(a) (hproto_list[a]) ++LIST_HEAD(hdev_list); ++rwlock_t hdev_list_lock = RW_LOCK_UNLOCKED; + +-/* HCI notifiers list */ +-struct notifier_block *hci_dev_notifier; +- +-/* HCI device notifications */ +-int hci_register_notifier(struct notifier_block *nb) +-{ +- int err, i; +- struct hci_dev *hdev; +- +- if ((err = notifier_chain_register(&hci_dev_notifier, nb))) +- return err; +- +- /* Notify about already registered devices */ +- spin_lock(&hdev_list_lock); +- for (i = 0; i < HCI_MAX_DEV; i++) { +- if (!(hdev = GET_HDEV(i))) +- continue; +- if (hdev->flags & HCI_UP) +- (*nb->notifier_call)(nb, HCI_DEV_UP, hdev); +- } +- spin_unlock(&hdev_list_lock); +- +- return 0; +-} +- +-int hci_unregister_notifier(struct notifier_block *nb) +-{ +- return notifier_chain_unregister(&hci_dev_notifier, nb); +-} +- +-static inline void hci_notify(struct hci_dev *hdev, int event) +-{ +- notifier_call_chain(&hci_dev_notifier, event, hdev); +-} +- +-/* Get HCI device by index (device is locked on return)*/ +-struct hci_dev *hci_dev_get(int index) +-{ +- struct hci_dev *hdev; +- DBG("%d", index); +- +- if (index < 0 || index >= HCI_MAX_DEV) +- return NULL; +- +- spin_lock(&hdev_list_lock); +- if ((hdev = GET_HDEV(index))) +- hci_dev_hold(hdev); +- spin_unlock(&hdev_list_lock); +- +- return hdev; +-} +- +-/* Flush inquiry cache */ +-void inquiry_cache_flush(struct inquiry_cache *cache) +-{ +- struct inquiry_entry *next = cache->list, *e; +- +- DBG("cache %p", cache); +- +- cache->list = NULL; +- while ((e = next)) { +- next = e->next; +- kfree(e); +- } +-} +- +-/* Lookup by bdaddr. +- * Cache must be locked. */ +-static struct inquiry_entry * __inquiry_cache_lookup(struct inquiry_cache *cache, bdaddr_t *bdaddr) +-{ +- struct inquiry_entry *e; +- +- DBG("cache %p, %s", cache, batostr(bdaddr)); +- +- for (e = cache->list; e; e = e->next) +- if (!bacmp(&e->info.bdaddr, bdaddr)) +- break; +- +- return e; +-} +- +-static void inquiry_cache_update(struct inquiry_cache *cache, inquiry_info *info) +-{ +- struct inquiry_entry *e; +- +- DBG("cache %p, %s", cache, batostr(&info->bdaddr)); +- +- inquiry_cache_lock(cache); +- +- if (!(e = __inquiry_cache_lookup(cache, &info->bdaddr))) { +- /* Entry not in the cache. Add new one. */ +- if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC))) +- goto unlock; +- memset(e, 0, sizeof(struct inquiry_entry)); +- e->next = cache->list; +- cache->list = e; +- } +- +- memcpy(&e->info, info, sizeof(inquiry_info)); +- e->timestamp = jiffies; +- cache->timestamp = jiffies; +-unlock: +- inquiry_cache_unlock(cache); +-} +- +-static int inquiry_cache_dump(struct inquiry_cache *cache, int num, __u8 *buf) +-{ +- inquiry_info *info = (inquiry_info *) buf; +- struct inquiry_entry *e; +- int copied = 0; ++/* HCI protocols */ ++#define HCI_MAX_PROTO 2 ++struct hci_proto *hci_proto[HCI_MAX_PROTO]; + +- inquiry_cache_lock(cache); +- +- for (e = cache->list; e && copied < num; e = e->next, copied++) +- memcpy(info++, &e->info, sizeof(inquiry_info)); ++/* HCI notifiers list */ ++static struct notifier_block *hci_notifier; + +- inquiry_cache_unlock(cache); + +- DBG("cache %p, copied %d", cache, copied); +- return copied; +-} ++/* ---- HCI notifications ---- */ + +-/* --------- BaseBand connections --------- */ +-static struct hci_conn *hci_conn_add(struct hci_dev *hdev, __u16 handle, __u8 type, bdaddr_t *dst) ++int hci_register_notifier(struct notifier_block *nb) + { +- struct hci_conn *conn; +- +- DBG("%s handle %d dst %s", hdev->name, handle, batostr(dst)); +- +- if ( conn_hash_lookup(&hdev->conn_hash, handle)) { +- ERR("%s handle 0x%x already exists", hdev->name, handle); +- return NULL; +- } +- +- if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC))) +- return NULL; +- memset(conn, 0, sizeof(struct hci_conn)); +- +- bacpy(&conn->dst, dst); +- conn->handle = handle; +- conn->type = type; +- conn->hdev = hdev; +- +- skb_queue_head_init(&conn->data_q); +- +- hci_dev_hold(hdev); +- conn_hash_add(&hdev->conn_hash, handle, conn); +- +- return conn; ++ return notifier_chain_register(&hci_notifier, nb); + } + +-static int hci_conn_del(struct hci_dev *hdev, struct hci_conn *conn) ++int hci_unregister_notifier(struct notifier_block *nb) + { +- DBG("%s conn %p handle %d", hdev->name, conn, conn->handle); +- +- conn_hash_del(&hdev->conn_hash, conn); +- hci_dev_put(hdev); +- +- /* Unacked frames */ +- hdev->acl_cnt += conn->sent; +- +- skb_queue_purge(&conn->data_q); +- +- kfree(conn); +- return 0; ++ return notifier_chain_unregister(&hci_notifier, nb); + } + +-/* Drop all connection on the device */ +-static void hci_conn_hash_flush(struct hci_dev *hdev) ++void hci_notify(struct hci_dev *hdev, int event) + { +- struct conn_hash *h = &hdev->conn_hash; +- struct hci_proto *hp; +- struct list_head *p; +- +- DBG("hdev %s", hdev->name); +- +- p = h->list.next; +- while (p != &h->list) { +- struct hci_conn *c; +- +- c = list_entry(p, struct hci_conn, list); +- p = p->next; +- +- if (c->type == ACL_LINK) { +- /* ACL link notify L2CAP layer */ +- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->disconn_ind) +- hp->disconn_ind(c, 0x16); +- } else { +- /* SCO link (no notification) */ +- } +- +- hci_conn_del(hdev, c); +- } ++ notifier_call_chain(&hci_notifier, event, hdev); + } + +-int hci_connect(struct hci_dev *hdev, bdaddr_t *bdaddr) +-{ +- struct inquiry_cache *cache = &hdev->inq_cache; +- struct inquiry_entry *e; +- create_conn_cp cc; +- __u16 clock_offset; +- +- DBG("%s bdaddr %s", hdev->name, batostr(bdaddr)); +- +- if (!(hdev->flags & HCI_UP)) +- return -ENODEV; +- +- inquiry_cache_lock_bh(cache); +- +- if (!(e = __inquiry_cache_lookup(cache, bdaddr)) || inquiry_entry_age(e) > INQUIRY_ENTRY_AGE_MAX) { +- cc.pscan_rep_mode = 0; +- cc.pscan_mode = 0; +- clock_offset = 0; +- } else { +- cc.pscan_rep_mode = e->info.pscan_rep_mode; +- cc.pscan_mode = e->info.pscan_mode; +- clock_offset = __le16_to_cpu(e->info.clock_offset) & 0x8000; +- } +- +- inquiry_cache_unlock_bh(cache); +- +- bacpy(&cc.bdaddr, bdaddr); +- cc.pkt_type = __cpu_to_le16(hdev->pkt_type); +- cc.clock_offset = __cpu_to_le16(clock_offset); +- +- if (lmp_rswitch_capable(hdev)) +- cc.role_switch = 0x01; +- else +- cc.role_switch = 0x00; +- +- hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, CREATE_CONN_CP_SIZE, &cc); ++/* ---- HCI hotplug support ---- */ + +- return 0; +-} ++#ifdef CONFIG_HOTPLUG + +-int hci_disconnect(struct hci_conn *conn, __u8 reason) ++static int hci_run_hotplug(char *dev, char *action) + { +- disconnect_cp dc; +- +- DBG("conn %p handle %d", conn, conn->handle); ++ char *argv[3], *envp[5], dstr[20], astr[32]; + +- dc.handle = __cpu_to_le16(conn->handle); +- dc.reason = reason; +- hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT, DISCONNECT_CP_SIZE, &dc); ++ sprintf(dstr, "DEVICE=%s", dev); ++ sprintf(astr, "ACTION=%s", action); + +- return 0; +-} ++ argv[0] = hotplug_path; ++ argv[1] = "bluetooth"; ++ argv[2] = NULL; + +-/* --------- HCI request handling ------------ */ +-static inline void hci_req_lock(struct hci_dev *hdev) +-{ +- down(&hdev->req_lock); ++ envp[0] = "HOME=/"; ++ envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; ++ envp[2] = dstr; ++ envp[3] = astr; ++ envp[4] = NULL; ++ ++ return call_usermodehelper(argv[0], argv, envp); + } ++#else ++#define hci_run_hotplug(A...) ++#endif + +-static inline void hci_req_unlock(struct hci_dev *hdev) +-{ +- up(&hdev->req_lock); +-} ++/* ---- HCI requests ---- */ + +-static inline void hci_req_complete(struct hci_dev *hdev, int result) ++void hci_req_complete(struct hci_dev *hdev, int result) + { +- DBG("%s result 0x%2.2x", hdev->name, result); ++ BT_DBG("%s result 0x%2.2x", hdev->name, result); + + if (hdev->req_status == HCI_REQ_PEND) { + hdev->req_result = result; +@@ -344,9 +134,9 @@ + } + } + +-static inline void hci_req_cancel(struct hci_dev *hdev, int err) ++void hci_req_cancel(struct hci_dev *hdev, int err) + { +- DBG("%s err 0x%2.2x", hdev->name, err); ++ BT_DBG("%s err 0x%2.2x", hdev->name, err); + + if (hdev->req_status == HCI_REQ_PEND) { + hdev->req_result = err; +@@ -356,23 +146,22 @@ + } + + /* Execute request and wait for completion. */ +-static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt), +- unsigned long opt, __u32 timeout) ++static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt), unsigned long opt, __u32 timeout) + { + DECLARE_WAITQUEUE(wait, current); + int err = 0; + +- DBG("%s start", hdev->name); ++ BT_DBG("%s start", hdev->name); + + hdev->req_status = HCI_REQ_PEND; + + add_wait_queue(&hdev->req_wait_q, &wait); +- current->state = TASK_INTERRUPTIBLE; ++ set_current_state(TASK_INTERRUPTIBLE); + + req(hdev, opt); + schedule_timeout(timeout); + +- current->state = TASK_RUNNING; ++ set_current_state(TASK_RUNNING); + remove_wait_queue(&hdev->req_wait_q, &wait); + + if (signal_pending(current)) +@@ -394,7 +183,7 @@ + + hdev->req_status = hdev->req_result = 0; + +- DBG("%s end: err %d", hdev->name, err); ++ BT_DBG("%s end: err %d", hdev->name, err); + + return err; + } +@@ -412,10 +201,9 @@ + return ret; + } + +-/* --------- HCI requests ---------- */ + static void hci_reset_req(struct hci_dev *hdev, unsigned long opt) + { +- DBG("%s %ld", hdev->name, opt); ++ BT_DBG("%s %ld", hdev->name, opt); + + /* Reset device */ + hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL); +@@ -423,10 +211,10 @@ + + static void hci_init_req(struct hci_dev *hdev, unsigned long opt) + { +- set_event_flt_cp ec; ++ set_event_flt_cp ef; + __u16 param; + +- DBG("%s %ld", hdev->name, opt); ++ BT_DBG("%s %ld", hdev->name, opt); + + /* Mandatory initialization */ + +@@ -436,14 +224,30 @@ + /* Read Buffer Size (ACL mtu, max pkt, etc.) */ + hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE, 0, NULL); + ++#if 0 ++ /* Host buffer size */ ++ { ++ host_buffer_size_cp bs; ++ bs.acl_mtu = __cpu_to_le16(HCI_MAX_ACL_SIZE); ++ bs.sco_mtu = HCI_MAX_SCO_SIZE; ++ bs.acl_max_pkt = __cpu_to_le16(0xffff); ++ bs.sco_max_pkt = __cpu_to_le16(0xffff); ++ hci_send_cmd(hdev, OGF_HOST_CTL, OCF_HOST_BUFFER_SIZE, ++ HOST_BUFFER_SIZE_CP_SIZE, &bs); ++ } ++#endif ++ + /* Read BD Address */ + hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL); + ++ /* Read Voice Setting */ ++ hci_send_cmd(hdev, OGF_HOST_CTL, OCF_READ_VOICE_SETTING, 0, NULL); ++ + /* Optional initialization */ + + /* Clear Event Filters */ +- ec.flt_type = FLT_CLEAR_ALL; +- hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &ec); ++ ef.flt_type = FLT_CLEAR_ALL; ++ hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &ef); + + /* Page timeout ~20 secs */ + param = __cpu_to_le16(0x8000); +@@ -458,7 +262,7 @@ + { + __u8 scan = opt; + +- DBG("%s %x", hdev->name, scan); ++ BT_DBG("%s %x", hdev->name, scan); + + /* Inquiry and Page scans */ + hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, 1, &scan); +@@ -468,116 +272,272 @@ + { + __u8 auth = opt; + +- DBG("%s %x", hdev->name, auth); ++ BT_DBG("%s %x", hdev->name, auth); + + /* Authentication */ + hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE, 1, &auth); + } + +-static void hci_inq_req(struct hci_dev *hdev, unsigned long opt) ++static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt) + { +- struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt; +- inquiry_cp ic; ++ __u8 encrypt = opt; + +- DBG("%s", hdev->name); ++ BT_DBG("%s %x", hdev->name, encrypt); + +- /* Start Inquiry */ +- memcpy(&ic.lap, &ir->lap, 3); +- ic.lenght = ir->length; +- ic.num_rsp = ir->num_rsp; +- hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, INQUIRY_CP_SIZE, &ic); ++ /* Authentication */ ++ hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE, 1, &encrypt); + } + +-/* HCI ioctl helpers */ +-int hci_dev_open(__u16 dev) ++/* Get HCI device by index. ++ * Device is locked on return. */ ++struct hci_dev *hci_dev_get(int index) + { + struct hci_dev *hdev; +- int ret = 0; +- +- if (!(hdev = hci_dev_get(dev))) +- return -ENODEV; ++ struct list_head *p; + +- DBG("%s %p", hdev->name, hdev); ++ BT_DBG("%d", index); + +- hci_req_lock(hdev); ++ if (index < 0) ++ return NULL; + +- if (hdev->flags & HCI_UP) { +- ret = -EALREADY; +- goto done; ++ read_lock(&hdev_list_lock); ++ list_for_each(p, &hdev_list) { ++ hdev = list_entry(p, struct hci_dev, list); ++ if (hdev->id == index) { ++ hci_dev_hold(hdev); ++ goto done; ++ } + } ++ hdev = NULL; ++done: ++ read_unlock(&hdev_list_lock); ++ return hdev; ++} + +- if (hdev->open(hdev)) { +- ret = -EIO; +- goto done; +- } ++/* ---- Inquiry support ---- */ ++void inquiry_cache_flush(struct hci_dev *hdev) ++{ ++ struct inquiry_cache *cache = &hdev->inq_cache; ++ struct inquiry_entry *next = cache->list, *e; + +- if (hdev->flags & HCI_NORMAL) { +- atomic_set(&hdev->cmd_cnt, 1); +- hdev->flags |= HCI_INIT; ++ BT_DBG("cache %p", cache); + +- //__hci_request(hdev, hci_reset_req, 0, HZ); +- ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT); +- +- hdev->flags &= ~HCI_INIT; ++ cache->list = NULL; ++ while ((e = next)) { ++ next = e->next; ++ kfree(e); + } ++} + +- if (!ret) { +- hdev->flags |= HCI_UP; +- hci_notify(hdev, HCI_DEV_UP); +- } else { +- /* Init failed, cleanup */ +- tasklet_kill(&hdev->rx_task); +- tasklet_kill(&hdev->tx_task); +- tasklet_kill(&hdev->cmd_task); ++struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr) ++{ ++ struct inquiry_cache *cache = &hdev->inq_cache; ++ struct inquiry_entry *e; + +- skb_queue_purge(&hdev->cmd_q); +- skb_queue_purge(&hdev->rx_q); ++ BT_DBG("cache %p, %s", cache, batostr(bdaddr)); + +- if (hdev->flush) +- hdev->flush(hdev); ++ for (e = cache->list; e; e = e->next) ++ if (!bacmp(&e->info.bdaddr, bdaddr)) ++ break; ++ return e; ++} + +- if (hdev->sent_cmd) { +- kfree_skb(hdev->sent_cmd); +- hdev->sent_cmd = NULL; +- } ++void inquiry_cache_update(struct hci_dev *hdev, inquiry_info *info) ++{ ++ struct inquiry_cache *cache = &hdev->inq_cache; ++ struct inquiry_entry *e; + +- hdev->close(hdev); +- } ++ BT_DBG("cache %p, %s", cache, batostr(&info->bdaddr)); + +-done: +- hci_req_unlock(hdev); +- hci_dev_put(hdev); ++ if (!(e = inquiry_cache_lookup(hdev, &info->bdaddr))) { ++ /* Entry not in the cache. Add new one. */ ++ if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC))) ++ return; ++ memset(e, 0, sizeof(struct inquiry_entry)); ++ e->next = cache->list; ++ cache->list = e; ++ } + +- return ret; ++ memcpy(&e->info, info, sizeof(inquiry_info)); ++ e->timestamp = jiffies; ++ cache->timestamp = jiffies; + } + +-int hci_dev_close(__u16 dev) ++int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf) + { +- struct hci_dev *hdev; +- +- if (!(hdev = hci_dev_get(dev))) +- return -ENODEV; ++ struct inquiry_cache *cache = &hdev->inq_cache; ++ inquiry_info *info = (inquiry_info *) buf; ++ struct inquiry_entry *e; ++ int copied = 0; + +- DBG("%s %p", hdev->name, hdev); ++ for (e = cache->list; e && copied < num; e = e->next, copied++) ++ memcpy(info++, &e->info, sizeof(inquiry_info)); + +- hci_req_cancel(hdev, ENODEV); +- hci_req_lock(hdev); ++ BT_DBG("cache %p, copied %d", cache, copied); ++ return copied; ++} + +- if (!(hdev->flags & HCI_UP)) +- goto done; ++static void hci_inq_req(struct hci_dev *hdev, unsigned long opt) ++{ ++ struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt; ++ inquiry_cp ic; + +- /* Kill RX and TX tasks */ +- tasklet_kill(&hdev->rx_task); +- tasklet_kill(&hdev->tx_task); ++ BT_DBG("%s", hdev->name); + +- inquiry_cache_flush(&hdev->inq_cache); ++ if (test_bit(HCI_INQUIRY, &hdev->flags)) ++ return; + +- hci_conn_hash_flush(hdev); ++ /* Start Inquiry */ ++ memcpy(&ic.lap, &ir->lap, 3); ++ ic.length = ir->length; ++ ic.num_rsp = ir->num_rsp; ++ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, INQUIRY_CP_SIZE, &ic); ++} + +- /* Clear flags */ +- hdev->flags &= HCI_SOCK; +- hdev->flags |= HCI_NORMAL; ++int hci_inquiry(unsigned long arg) ++{ ++ struct hci_inquiry_req ir; ++ struct hci_dev *hdev; ++ int err = 0, do_inquiry = 0, max_rsp; ++ long timeo; ++ __u8 *buf, *ptr; + ++ ptr = (void *) arg; ++ if (copy_from_user(&ir, ptr, sizeof(ir))) ++ return -EFAULT; ++ ++ if (!(hdev = hci_dev_get(ir.dev_id))) ++ return -ENODEV; ++ ++ hci_dev_lock_bh(hdev); ++ if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX || ++ ir.flags & IREQ_CACHE_FLUSH) { ++ inquiry_cache_flush(hdev); ++ do_inquiry = 1; ++ } ++ hci_dev_unlock_bh(hdev); ++ ++ timeo = ir.length * 2 * HZ; ++ if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0) ++ goto done; ++ ++ /* for unlimited number of responses we will use buffer with 255 entries */ ++ max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp; ++ ++ /* cache_dump can't sleep. Therefore we allocate temp buffer and then ++ * copy it to the user space. ++ */ ++ if (!(buf = kmalloc(sizeof(inquiry_info) * max_rsp, GFP_KERNEL))) { ++ err = -ENOMEM; ++ goto done; ++ } ++ ++ hci_dev_lock_bh(hdev); ++ ir.num_rsp = inquiry_cache_dump(hdev, max_rsp, buf); ++ hci_dev_unlock_bh(hdev); ++ ++ BT_DBG("num_rsp %d", ir.num_rsp); ++ ++ if (!verify_area(VERIFY_WRITE, ptr, sizeof(ir) + ++ (sizeof(inquiry_info) * ir.num_rsp))) { ++ copy_to_user(ptr, &ir, sizeof(ir)); ++ ptr += sizeof(ir); ++ copy_to_user(ptr, buf, sizeof(inquiry_info) * ir.num_rsp); ++ } else ++ err = -EFAULT; ++ ++ kfree(buf); ++ ++done: ++ hci_dev_put(hdev); ++ return err; ++} ++ ++/* ---- HCI ioctl helpers ---- */ ++ ++int hci_dev_open(__u16 dev) ++{ ++ struct hci_dev *hdev; ++ int ret = 0; ++ ++ if (!(hdev = hci_dev_get(dev))) ++ return -ENODEV; ++ ++ BT_DBG("%s %p", hdev->name, hdev); ++ ++ hci_req_lock(hdev); ++ ++ if (test_bit(HCI_UP, &hdev->flags)) { ++ ret = -EALREADY; ++ goto done; ++ } ++ ++ if (hdev->open(hdev)) { ++ ret = -EIO; ++ goto done; ++ } ++ ++ if (!test_bit(HCI_RAW, &hdev->flags)) { ++ atomic_set(&hdev->cmd_cnt, 1); ++ set_bit(HCI_INIT, &hdev->flags); ++ ++ //__hci_request(hdev, hci_reset_req, 0, HZ); ++ ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT); ++ ++ clear_bit(HCI_INIT, &hdev->flags); ++ } ++ ++ if (!ret) { ++ set_bit(HCI_UP, &hdev->flags); ++ hci_notify(hdev, HCI_DEV_UP); ++ } else { ++ /* Init failed, cleanup */ ++ tasklet_kill(&hdev->rx_task); ++ tasklet_kill(&hdev->tx_task); ++ tasklet_kill(&hdev->cmd_task); ++ ++ skb_queue_purge(&hdev->cmd_q); ++ skb_queue_purge(&hdev->rx_q); ++ ++ if (hdev->flush) ++ hdev->flush(hdev); ++ ++ if (hdev->sent_cmd) { ++ kfree_skb(hdev->sent_cmd); ++ hdev->sent_cmd = NULL; ++ } ++ ++ hdev->close(hdev); ++ hdev->flags = 0; ++ } ++ ++done: ++ hci_req_unlock(hdev); ++ hci_dev_put(hdev); ++ return ret; ++} ++ ++static int hci_dev_do_close(struct hci_dev *hdev) ++{ ++ BT_DBG("%s %p", hdev->name, hdev); ++ ++ hci_req_cancel(hdev, ENODEV); ++ hci_req_lock(hdev); ++ ++ if (!test_and_clear_bit(HCI_UP, &hdev->flags)) { ++ hci_req_unlock(hdev); ++ return 0; ++ } ++ ++ /* Kill RX and TX tasks */ ++ tasklet_kill(&hdev->rx_task); ++ tasklet_kill(&hdev->tx_task); ++ ++ hci_dev_lock_bh(hdev); ++ inquiry_cache_flush(hdev); ++ hci_conn_hash_flush(hdev); ++ hci_dev_unlock_bh(hdev); ++ + hci_notify(hdev, HCI_DEV_DOWN); + + if (hdev->flush) +@@ -586,9 +546,9 @@ + /* Reset device */ + skb_queue_purge(&hdev->cmd_q); + atomic_set(&hdev->cmd_cnt, 1); +- hdev->flags |= HCI_INIT; +- __hci_request(hdev, hci_reset_req, 0, HZ); +- hdev->flags &= ~HCI_INIT; ++ set_bit(HCI_INIT, &hdev->flags); ++ __hci_request(hdev, hci_reset_req, 0, HZ/4); ++ clear_bit(HCI_INIT, &hdev->flags); + + /* Kill cmd task */ + tasklet_kill(&hdev->cmd_task); +@@ -605,17 +565,28 @@ + } + + /* After this point our queues are empty +- * and no tasks are scheduled. +- */ ++ * and no tasks are scheduled. */ + hdev->close(hdev); + +-done: +- hci_req_unlock(hdev); +- hci_dev_put(hdev); ++ /* Clear flags */ ++ hdev->flags = 0; + ++ hci_req_unlock(hdev); + return 0; + } + ++int hci_dev_close(__u16 dev) ++{ ++ struct hci_dev *hdev; ++ int err; ++ ++ if (!(hdev = hci_dev_get(dev))) ++ return -ENODEV; ++ err = hci_dev_do_close(hdev); ++ hci_dev_put(hdev); ++ return err; ++} ++ + int hci_dev_reset(__u16 dev) + { + struct hci_dev *hdev; +@@ -627,16 +598,17 @@ + hci_req_lock(hdev); + tasklet_disable(&hdev->tx_task); + +- if (!(hdev->flags & HCI_UP)) ++ if (!test_bit(HCI_UP, &hdev->flags)) + goto done; + + /* Drop queues */ + skb_queue_purge(&hdev->rx_q); + skb_queue_purge(&hdev->cmd_q); + +- inquiry_cache_flush(&hdev->inq_cache); +- ++ hci_dev_lock_bh(hdev); ++ inquiry_cache_flush(hdev); + hci_conn_hash_flush(hdev); ++ hci_dev_unlock_bh(hdev); + + if (hdev->flush) + hdev->flush(hdev); +@@ -650,7 +622,6 @@ + tasklet_enable(&hdev->tx_task); + hci_req_unlock(hdev); + hci_dev_put(hdev); +- + return ret; + } + +@@ -669,30 +640,11 @@ + return ret; + } + +-int hci_dev_setauth(unsigned long arg) +-{ +- struct hci_dev *hdev; +- struct hci_dev_req dr; +- int ret = 0; +- +- if (copy_from_user(&dr, (void *) arg, sizeof(dr))) +- return -EFAULT; +- +- if (!(hdev = hci_dev_get(dr.dev_id))) +- return -ENODEV; +- +- ret = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT); +- +- hci_dev_put(hdev); +- +- return ret; +-} +- +-int hci_dev_setscan(unsigned long arg) ++int hci_dev_cmd(unsigned int cmd, unsigned long arg) + { + struct hci_dev *hdev; + struct hci_dev_req dr; +- int ret = 0; ++ int err = 0; + + if (copy_from_user(&dr, (void *) arg, sizeof(dr))) + return -EFAULT; +@@ -700,48 +652,78 @@ + if (!(hdev = hci_dev_get(dr.dev_id))) + return -ENODEV; + +- ret = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT); +- +- hci_dev_put(hdev); ++ switch (cmd) { ++ case HCISETAUTH: ++ err = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT); ++ break; + +- return ret; +-} ++ case HCISETENCRYPT: ++ if (!lmp_encrypt_capable(hdev)) { ++ err = -EOPNOTSUPP; ++ break; ++ } + +-int hci_dev_setptype(unsigned long arg) +-{ +- struct hci_dev *hdev; +- struct hci_dev_req dr; +- int ret = 0; ++ if (!test_bit(HCI_AUTH, &hdev->flags)) { ++ /* Auth must be enabled first */ ++ err = hci_request(hdev, hci_auth_req, ++ dr.dev_opt, HCI_INIT_TIMEOUT); ++ if (err) ++ break; ++ } ++ ++ err = hci_request(hdev, hci_encrypt_req, ++ dr.dev_opt, HCI_INIT_TIMEOUT); ++ break; ++ ++ case HCISETSCAN: ++ err = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT); ++ break; ++ ++ case HCISETPTYPE: ++ hdev->pkt_type = (__u16) dr.dev_opt; ++ break; ++ ++ case HCISETLINKPOL: ++ hdev->link_policy = (__u16) dr.dev_opt; ++ break; + +- if (copy_from_user(&dr, (void *) arg, sizeof(dr))) +- return -EFAULT; ++ case HCISETLINKMODE: ++ hdev->link_mode = ((__u16) dr.dev_opt) & (HCI_LM_MASTER | HCI_LM_ACCEPT); ++ break; + +- if (!(hdev = hci_dev_get(dr.dev_id))) +- return -ENODEV; ++ case HCISETACLMTU: ++ hdev->acl_mtu = *((__u16 *)&dr.dev_opt + 1); ++ hdev->acl_pkts = *((__u16 *)&dr.dev_opt + 0); ++ break; + +- hdev->pkt_type = (__u16) dr.dev_opt; ++ case HCISETSCOMTU: ++ hdev->sco_mtu = *((__u16 *)&dr.dev_opt + 1); ++ hdev->sco_pkts = *((__u16 *)&dr.dev_opt + 0); ++ break; + ++ default: ++ err = -EINVAL; ++ break; ++ } + hci_dev_put(hdev); +- +- return ret; ++ return err; + } + +-int hci_dev_list(unsigned long arg) ++int hci_get_dev_list(unsigned long arg) + { + struct hci_dev_list_req *dl; + struct hci_dev_req *dr; +- struct hci_dev *hdev; +- int i, n, size; ++ struct list_head *p; ++ int n = 0, size; + __u16 dev_num; + + if (get_user(dev_num, (__u16 *) arg)) + return -EFAULT; + +- /* Avoid long loop, overflow */ +- if (dev_num > 2048) ++ if (!dev_num) + return -EINVAL; + +- size = dev_num * sizeof(struct hci_dev_req) + sizeof(__u16); ++ size = dev_num * sizeof(*dr) + sizeof(*dl); + + if (verify_area(VERIFY_WRITE, (void *) arg, size)) + return -EFAULT; +@@ -750,25 +732,27 @@ + return -ENOMEM; + dr = dl->dev_req; + +- spin_lock_bh(&hdev_list_lock); +- for (i = 0, n = 0; i < HCI_MAX_DEV && n < dev_num; i++) { +- if ((hdev = hdev_list[i])) { +- (dr + n)->dev_id = hdev->id; +- (dr + n)->dev_opt = hdev->flags; +- n++; +- } ++ read_lock_bh(&hdev_list_lock); ++ list_for_each(p, &hdev_list) { ++ struct hci_dev *hdev; ++ hdev = list_entry(p, struct hci_dev, list); ++ (dr + n)->dev_id = hdev->id; ++ (dr + n)->dev_opt = hdev->flags; ++ if (++n >= dev_num) ++ break; + } +- spin_unlock_bh(&hdev_list_lock); ++ read_unlock_bh(&hdev_list_lock); + + dl->dev_num = n; +- size = n * sizeof(struct hci_dev_req) + sizeof(__u16); ++ size = n * sizeof(*dr) + sizeof(*dl); + + copy_to_user((void *) arg, dl, size); ++ kfree(dl); + + return 0; + } + +-int hci_dev_info(unsigned long arg) ++int hci_get_dev_info(unsigned long arg) + { + struct hci_dev *hdev; + struct hci_dev_info di; +@@ -786,9 +770,11 @@ + di.flags = hdev->flags; + di.pkt_type = hdev->pkt_type; + di.acl_mtu = hdev->acl_mtu; +- di.acl_max = hdev->acl_max; ++ di.acl_pkts = hdev->acl_pkts; + di.sco_mtu = hdev->sco_mtu; +- di.sco_max = hdev->sco_max; ++ di.sco_pkts = hdev->sco_pkts; ++ di.link_policy = hdev->link_policy; ++ di.link_mode = hdev->link_mode; + + memcpy(&di.stat, &hdev->stat, sizeof(di.stat)); + memcpy(&di.features, &hdev->features, sizeof(di.features)); +@@ -801,258 +787,168 @@ + return err; + } + +-__u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode) +-{ +- __u32 omode = hdev->flags & HCI_MODE_MASK; +- +- hdev->flags &= ~HCI_MODE_MASK; +- hdev->flags |= (mode & HCI_MODE_MASK); + +- return omode; +-} ++/* ---- Interface to HCI drivers ---- */ + +-__u32 hci_dev_getmode(struct hci_dev *hdev) ++/* Register HCI device */ ++int hci_register_dev(struct hci_dev *hdev) + { +- return hdev->flags & HCI_MODE_MASK; +-} ++ struct list_head *head = &hdev_list, *p; ++ int id = 0; + +-int hci_conn_list(unsigned long arg) +-{ +- struct hci_conn_list_req req, *cl; +- struct hci_conn_info *ci; +- struct hci_dev *hdev; +- struct list_head *p; +- int n = 0, size; ++ BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type); + +- if (copy_from_user(&req, (void *) arg, sizeof(req))) +- return -EFAULT; ++ if (!hdev->open || !hdev->close || !hdev->destruct) ++ return -EINVAL; + +- if (!(hdev = hci_dev_get(req.dev_id))) +- return -ENODEV; ++ write_lock_bh(&hdev_list_lock); + +- /* Set a limit to avoid overlong loops, and also numeric overflow - AC */ +- if(req.conn_num < 2048) +- return -EINVAL; ++ /* Find first available device id */ ++ list_for_each(p, &hdev_list) { ++ if (list_entry(p, struct hci_dev, list)->id != id) ++ break; ++ head = p; id++; ++ } + +- size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req); +- +- if (!(cl = kmalloc(size, GFP_KERNEL))) +- return -ENOMEM; +- ci = cl->conn_info; ++ sprintf(hdev->name, "hci%d", id); ++ hdev->id = id; ++ list_add(&hdev->list, head); + +- local_bh_disable(); +- conn_hash_lock(&hdev->conn_hash); +- list_for_each(p, &hdev->conn_hash.list) { +- register struct hci_conn *c; +- c = list_entry(p, struct hci_conn, list); ++ atomic_set(&hdev->refcnt, 1); ++ spin_lock_init(&hdev->lock); ++ ++ hdev->flags = 0; ++ hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1); ++ hdev->link_mode = (HCI_LM_ACCEPT); + +- (ci + n)->handle = c->handle; +- bacpy(&(ci + n)->bdaddr, &c->dst); +- n++; +- } +- conn_hash_unlock(&hdev->conn_hash); +- local_bh_enable(); +- +- cl->dev_id = hdev->id; +- cl->conn_num = n; +- size = n * sizeof(struct hci_conn_info) + sizeof(req); ++ tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev); ++ tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev); ++ tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); + +- hci_dev_put(hdev); ++ skb_queue_head_init(&hdev->rx_q); ++ skb_queue_head_init(&hdev->cmd_q); ++ skb_queue_head_init(&hdev->raw_q); + +- if(copy_to_user((void *) arg, cl, size)) +- return -EFAULT; +- return 0; +-} ++ init_waitqueue_head(&hdev->req_wait_q); ++ init_MUTEX(&hdev->req_lock); + +-int hci_inquiry(unsigned long arg) +-{ +- struct inquiry_cache *cache; +- struct hci_inquiry_req ir; +- struct hci_dev *hdev; +- int err = 0, do_inquiry = 0; +- long timeo; +- __u8 *buf, *ptr; ++ inquiry_cache_init(hdev); + +- ptr = (void *) arg; +- if (copy_from_user(&ir, ptr, sizeof(ir))) +- return -EFAULT; ++ conn_hash_init(hdev); + +- if (!(hdev = hci_dev_get(ir.dev_id))) +- return -ENODEV; ++ memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); + +- cache = &hdev->inq_cache; ++ atomic_set(&hdev->promisc, 0); + +- inquiry_cache_lock(cache); +- if (inquiry_cache_age(cache) > INQUIRY_CACHE_AGE_MAX || ir.flags & IREQ_CACHE_FLUSH) { +- inquiry_cache_flush(cache); +- do_inquiry = 1; +- } +- inquiry_cache_unlock(cache); ++ MOD_INC_USE_COUNT; + +- /* Limit inquiry time, also avoid overflows */ ++ write_unlock_bh(&hdev_list_lock); + +- if(ir.length > 2048 || ir.num_rsp > 2048) +- { +- err = -EINVAL; +- goto done; +- } ++ hci_notify(hdev, HCI_DEV_REG); ++ hci_run_hotplug(hdev->name, "register"); + +- timeo = ir.length * 2 * HZ; +- if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0) +- goto done; ++ return id; ++} + +- /* cache_dump can't sleep. Therefore we allocate temp buffer and then +- * copy it to the user space. +- */ +- if (!(buf = kmalloc(sizeof(inquiry_info) * ir.num_rsp, GFP_KERNEL))) { +- err = -ENOMEM; +- goto done; +- } +- ir.num_rsp = inquiry_cache_dump(cache, ir.num_rsp, buf); ++/* Unregister HCI device */ ++int hci_unregister_dev(struct hci_dev *hdev) ++{ ++ BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type); + +- DBG("num_rsp %d", ir.num_rsp); ++ write_lock_bh(&hdev_list_lock); ++ list_del(&hdev->list); ++ write_unlock_bh(&hdev_list_lock); + +- if (!verify_area(VERIFY_WRITE, ptr, sizeof(ir) + (sizeof(inquiry_info) * ir.num_rsp))) { +- copy_to_user(ptr, &ir, sizeof(ir)); +- ptr += sizeof(ir); +- copy_to_user(ptr, buf, sizeof(inquiry_info) * ir.num_rsp); +- } else +- err = -EFAULT; ++ hci_dev_do_close(hdev); + +- kfree(buf); ++ hci_notify(hdev, HCI_DEV_UNREG); ++ hci_run_hotplug(hdev->name, "unregister"); + +-done: + hci_dev_put(hdev); + +- return err; ++ MOD_DEC_USE_COUNT; ++ return 0; + } + +-/* Interface to HCI drivers */ +- +-/* Register HCI device */ +-int hci_register_dev(struct hci_dev *hdev) ++/* Suspend HCI device */ ++int hci_suspend_dev(struct hci_dev *hdev) + { +- int i; +- +- DBG("%p name %s type %d", hdev, hdev->name, hdev->type); +- +- /* Find free slot */ +- spin_lock_bh(&hdev_list_lock); +- for (i = 0; i < HCI_MAX_DEV; i++) { +- if (!hdev_list[i]) { +- hdev_list[i] = hdev; ++ hci_notify(hdev, HCI_DEV_SUSPEND); ++ hci_run_hotplug(hdev->name, "suspend"); ++ return 0; ++} + +- sprintf(hdev->name, "hci%d", i); +- atomic_set(&hdev->refcnt, 0); +- hdev->id = i; +- hdev->flags = HCI_NORMAL; ++/* Resume HCI device */ ++int hci_resume_dev(struct hci_dev *hdev) ++{ ++ hci_notify(hdev, HCI_DEV_RESUME); ++ hci_run_hotplug(hdev->name, "resume"); ++ return 0; ++} + +- hdev->pkt_type = (HCI_DM1 | HCI_DH1); +- +- tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev); +- tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev); +- tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); +- +- skb_queue_head_init(&hdev->rx_q); +- skb_queue_head_init(&hdev->cmd_q); +- skb_queue_head_init(&hdev->raw_q); +- +- init_waitqueue_head(&hdev->req_wait_q); +- init_MUTEX(&hdev->req_lock); +- +- inquiry_cache_init(&hdev->inq_cache); +- +- conn_hash_init(&hdev->conn_hash); +- +- memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); +- +- hci_notify(hdev, HCI_DEV_REG); +- +- MOD_INC_USE_COUNT; +- break; +- } +- } +- spin_unlock_bh(&hdev_list_lock); +- +- return (i == HCI_MAX_DEV) ? -1 : i; +-} +- +-/* Unregister HCI device */ +-int hci_unregister_dev(struct hci_dev *hdev) ++/* Receive frame from HCI drivers */ ++int hci_recv_frame(struct sk_buff *skb) + { +- int i; +- +- DBG("%p name %s type %d", hdev, hdev->name, hdev->type); +- +- if (hdev->flags & HCI_UP) +- hci_dev_close(hdev->id); ++ struct hci_dev *hdev = (struct hci_dev *) skb->dev; + +- /* Find device slot */ +- spin_lock(&hdev_list_lock); +- for (i = 0; i < HCI_MAX_DEV; i++) { +- if (hdev_list[i] == hdev) { +- hdev_list[i] = NULL; +- MOD_DEC_USE_COUNT; +- break; +- } ++ if (!hdev || (!test_bit(HCI_UP, &hdev->flags) && ++ !test_bit(HCI_INIT, &hdev->flags)) ) { ++ kfree_skb(skb); ++ return -1; + } +- spin_unlock(&hdev_list_lock); +- +- hci_notify(hdev, HCI_DEV_UNREG); + +- /* Sleep while device is in use */ +- while (atomic_read(&hdev->refcnt)) { +- int sleep_cnt = 100; ++ BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); + +- DBG("%s sleeping on lock %d", hdev->name, atomic_read(&hdev->refcnt)); ++ /* Incomming skb */ ++ bluez_cb(skb)->incomming = 1; + +- sleep_on_timeout(&hdev->req_wait_q, HZ*10); +- if (!(--sleep_cnt)) +- break; +- } ++ /* Time stamp */ ++ do_gettimeofday(&skb->stamp); + ++ /* Queue frame for rx task */ ++ skb_queue_tail(&hdev->rx_q, skb); ++ hci_sched_rx(hdev); + return 0; + } + +-/* Interface to upper protocols */ ++/* ---- Interface to upper protocols ---- */ + + /* Register/Unregister protocols. +- * hci_task_lock is used to ensure that no tasks are running. +- */ +-int hci_register_proto(struct hci_proto *hproto) ++ * hci_task_lock is used to ensure that no tasks are running. */ ++int hci_register_proto(struct hci_proto *hp) + { + int err = 0; + +- DBG("%p name %s", hproto, hproto->name); ++ BT_DBG("%p name %s id %d", hp, hp->name, hp->id); + +- if (hproto->id >= HCI_MAX_PROTO) ++ if (hp->id >= HCI_MAX_PROTO) + return -EINVAL; + + write_lock_bh(&hci_task_lock); + +- if (!hproto_list[hproto->id]) +- hproto_list[hproto->id] = hproto; ++ if (!hci_proto[hp->id]) ++ hci_proto[hp->id] = hp; + else +- err = -1; ++ err = -EEXIST; + + write_unlock_bh(&hci_task_lock); + + return err; + } + +-int hci_unregister_proto(struct hci_proto *hproto) ++int hci_unregister_proto(struct hci_proto *hp) + { + int err = 0; + +- DBG("%p name %s", hproto, hproto->name); ++ BT_DBG("%p name %s id %d", hp, hp->name, hp->id); + +- if (hproto->id > HCI_MAX_PROTO) ++ if (hp->id >= HCI_MAX_PROTO) + return -EINVAL; + + write_lock_bh(&hci_task_lock); + +- if (hproto_list[hproto->id]) +- hproto_list[hproto->id] = NULL; ++ if (hci_proto[hp->id]) ++ hci_proto[hp->id] = NULL; + else + err = -ENOENT; + +@@ -1070,10 +966,14 @@ + return -ENODEV; + } + +- DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); ++ BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); ++ ++ if (atomic_read(&hdev->promisc)) { ++ /* Time stamp */ ++ do_gettimeofday(&skb->stamp); + +- if (hdev->flags & HCI_SOCK) + hci_send_to_sock(hdev, skb); ++ } + + /* Get rid of skb owner, prior to sending to the driver. */ + skb_orphan(skb); +@@ -1081,128 +981,6 @@ + return hdev->send(skb); + } + +-/* Connection scheduler */ +-static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote) +-{ +- struct conn_hash *h = &hdev->conn_hash; +- struct hci_conn *conn = NULL; +- int num = 0, min = 0xffff; +- struct list_head *p; +- +- conn_hash_lock(h); +- list_for_each(p, &h->list) { +- register struct hci_conn *c; +- +- c = list_entry(p, struct hci_conn, list); +- +- if (c->type != type || skb_queue_empty(&c->data_q)) +- continue; +- num++; +- +- if (c->sent < min) { +- min = c->sent; +- conn = c; +- } +- } +- conn_hash_unlock(h); +- +- if (conn) { +- int q = hdev->acl_cnt / num; +- *quote = q ? q : 1; +- } else +- *quote = 0; +- +- DBG("conn %p quote %d", conn, *quote); +- +- return conn; +-} +- +-static inline void hci_sched_acl(struct hci_dev *hdev) +-{ +- struct hci_conn *conn; +- struct sk_buff *skb; +- int quote; +- +- DBG("%s", hdev->name); +- +- while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, "e))) { +- while (quote && (skb = skb_dequeue(&conn->data_q))) { +- DBG("skb %p len %d", skb, skb->len); +- +- hci_send_frame(skb); +- +- conn->sent++; +- hdev->acl_cnt--; +- quote--; +- } +- } +-} +- +-/* Schedule SCO */ +-static inline void hci_sched_sco(struct hci_dev *hdev) +-{ +- /* FIXME: For now we queue SCO packets to the raw queue +- +- while (hdev->sco_cnt && (skb = skb_dequeue(&conn->data_q))) { +- hci_send_frame(skb); +- conn->sco_sent++; +- hdev->sco_cnt--; +- } +- */ +-} +- +-/* Get data from the previously sent command */ +-static void * hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf) +-{ +- hci_command_hdr *hc; +- +- if (!hdev->sent_cmd) +- return NULL; +- +- hc = (void *) hdev->sent_cmd->data; +- +- if (hc->opcode != __cpu_to_le16(cmd_opcode_pack(ogf, ocf))) +- return NULL; +- +- DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf); +- +- return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE; +-} +- +-/* Send raw HCI frame */ +-int hci_send_raw(struct sk_buff *skb) +-{ +- struct hci_dev *hdev = (struct hci_dev *) skb->dev; +- +- if (!hdev) { +- kfree_skb(skb); +- return -ENODEV; +- } +- +- DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); +- +- if (hdev->flags & HCI_NORMAL) { +- /* Queue frame according it's type */ +- switch (skb->pkt_type) { +- case HCI_COMMAND_PKT: +- skb_queue_tail(&hdev->cmd_q, skb); +- hci_sched_cmd(hdev); +- return 0; +- +- case HCI_ACLDATA_PKT: +- case HCI_SCODATA_PKT: +- /* FIXME: +- * Check header here and queue to apropriate connection. +- */ +- break; +- } +- } +- +- skb_queue_tail(&hdev->raw_q, skb); +- hci_sched_tx(hdev); +- return 0; +-} +- + /* Send HCI command */ + int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param) + { +@@ -1210,10 +988,10 @@ + hci_command_hdr *hc; + struct sk_buff *skb; + +- DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen); ++ BT_DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen); + + if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) { +- ERR("%s Can't allocate memory for HCI command", hdev->name); ++ BT_ERR("%s Can't allocate memory for HCI command", hdev->name); + return -ENOMEM; + } + +@@ -1224,7 +1002,7 @@ + if (plen) + memcpy(skb_put(skb, plen), param, plen); + +- DBG("skb len %d", skb->len); ++ BT_DBG("skb len %d", skb->len); + + skb->pkt_type = HCI_COMMAND_PKT; + skb->dev = (void *) hdev; +@@ -1234,10 +1012,28 @@ + return 0; + } + ++/* Get data from the previously sent command */ ++void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf) ++{ ++ hci_command_hdr *hc; ++ ++ if (!hdev->sent_cmd) ++ return NULL; ++ ++ hc = (void *) hdev->sent_cmd->data; ++ ++ if (hc->opcode != __cpu_to_le16(cmd_opcode_pack(ogf, ocf))) ++ return NULL; ++ ++ BT_DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf); ++ ++ return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE; ++} ++ + /* Send ACL data */ + static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags) + { +- int len = skb->len; ++ int len = skb->len; + hci_acl_hdr *ah; + + ah = (hci_acl_hdr *) skb_push(skb, HCI_ACL_HDR_SIZE); +@@ -1252,7 +1048,7 @@ + struct hci_dev *hdev = conn->hdev; + struct sk_buff *list; + +- DBG("%s conn %p flags 0x%x", hdev->name, conn, flags); ++ BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags); + + skb->dev = (void *) hdev; + skb->pkt_type = HCI_ACLDATA_PKT; +@@ -1260,12 +1056,12 @@ + + if (!(list = skb_shinfo(skb)->frag_list)) { + /* Non fragmented */ +- DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len); ++ BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len); + + skb_queue_tail(&conn->data_q, skb); + } else { + /* Fragmented */ +- DBG("%s frag %p len %d", hdev->name, skb, skb->len); ++ BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len); + + skb_shinfo(skb)->frag_list = NULL; + +@@ -1280,7 +1076,7 @@ + skb->pkt_type = HCI_ACLDATA_PKT; + hci_add_acl_hdr(skb, conn->handle, flags | ACL_CONT); + +- DBG("%s frag %p len %d", hdev->name, skb, skb->len); ++ BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len); + + __skb_queue_tail(&conn->data_q, skb); + } while (list); +@@ -1298,7 +1094,7 @@ + struct hci_dev *hdev = conn->hdev; + hci_sco_hdr hs; + +- DBG("%s len %d", hdev->name, skb->len); ++ BT_DBG("%s len %d", hdev->name, skb->len); + + if (skb->len > hdev->sco_mtu) { + kfree_skb(skb); +@@ -1315,544 +1111,136 @@ + skb->pkt_type = HCI_SCODATA_PKT; + skb_queue_tail(&conn->data_q, skb); + hci_sched_tx(hdev); +- + return 0; + } + +-/* Handle HCI Event packets */ +- +-/* Command Complete OGF LINK_CTL */ +-static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) +-{ +- DBG("%s ocf 0x%x", hdev->name, ocf); +- +- switch (ocf) { +- default: +- DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf); +- break; +- }; +-} +- +-/* Command Complete OGF LINK_POLICY */ +-static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) +-{ +- DBG("%s ocf 0x%x", hdev->name, ocf); +- +- switch (ocf) { +- default: +- DBG("%s: Command complete: ogf LINK_POLICY ocf %x", hdev->name, ocf); +- break; +- }; +-} +- +-/* Command Complete OGF HOST_CTL */ +-static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) +-{ +- __u8 status, param; +- void *sent; +- +- +- DBG("%s ocf 0x%x", hdev->name, ocf); +- +- switch (ocf) { +- case OCF_RESET: +- status = *((__u8 *) skb->data); +- +- hci_req_complete(hdev, status); +- break; +- +- case OCF_SET_EVENT_FLT: +- status = *((__u8 *) skb->data); +- +- if (status) { +- DBG("%s SET_EVENT_FLT failed %d", hdev->name, status); +- } else { +- DBG("%s SET_EVENT_FLT succeseful", hdev->name); +- } +- break; +- +- case OCF_WRITE_AUTH_ENABLE: +- if (!(sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE))) +- break; +- +- status = *((__u8 *) skb->data); +- param = *((__u8 *) sent); ++/* ---- HCI TX task (outgoing data) ---- */ + +- if (!status) { +- if (param == AUTH_ENABLED) +- hdev->flags |= HCI_AUTH; +- else +- hdev->flags &= ~HCI_AUTH; +- } +- hci_req_complete(hdev, status); +- break; +- +- case OCF_WRITE_CA_TIMEOUT: +- status = *((__u8 *) skb->data); +- +- if (status) { +- DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status); +- } else { +- DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name); +- } +- break; +- +- case OCF_WRITE_PG_TIMEOUT: +- status = *((__u8 *) skb->data); +- +- if (status) { +- DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status); +- } else { +- DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name); +- } +- break; +- +- case OCF_WRITE_SCAN_ENABLE: +- if (!(sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE))) +- break; +- status = *((__u8 *) skb->data); +- param = *((__u8 *) sent); +- +- DBG("param 0x%x", param); +- +- if (!status) { +- switch (param) { +- case IS_ENA_PS_ENA: +- hdev->flags |= HCI_PSCAN | HCI_ISCAN; +- break; +- +- case IS_ENA_PS_DIS: +- hdev->flags &= ~HCI_PSCAN; +- hdev->flags |= HCI_ISCAN; +- break; +- +- case IS_DIS_PS_ENA: +- hdev->flags &= ~HCI_ISCAN; +- hdev->flags |= HCI_PSCAN; +- break; +- +- default: +- hdev->flags &= ~(HCI_ISCAN | HCI_PSCAN); +- break; +- }; +- } +- hci_req_complete(hdev, status); +- break; +- +- default: +- DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf); +- break; +- }; +-} +- +-/* Command Complete OGF INFO_PARAM */ +-static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) ++/* HCI Connection scheduler */ ++static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote) + { +- read_local_features_rp *lf; +- read_buffer_size_rp *bs; +- read_bd_addr_rp *ba; +- +- DBG("%s ocf 0x%x", hdev->name, ocf); +- +- switch (ocf) { +- case OCF_READ_LOCAL_FEATURES: +- lf = (read_local_features_rp *) skb->data; +- +- if (lf->status) { +- DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status); +- break; +- } +- +- memcpy(hdev->features, lf->features, sizeof(hdev->features)); +- +- /* Adjust default settings according to features +- * supported by device. */ +- if (hdev->features[0] & LMP_3SLOT) +- hdev->pkt_type |= (HCI_DM3 | HCI_DH3); +- +- if (hdev->features[0] & LMP_5SLOT) +- hdev->pkt_type |= (HCI_DM5 | HCI_DH5); +- +- DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]); +- +- break; +- +- case OCF_READ_BUFFER_SIZE: +- bs = (read_buffer_size_rp *) skb->data; +- +- if (bs->status) { +- DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status); +- break; +- } +- +- hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu); +- hdev->sco_mtu = bs->sco_mtu; +- hdev->acl_max = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt); +- hdev->sco_max = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt); +- +- DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name, +- hdev->acl_mtu, hdev->sco_mtu, hdev->acl_max, hdev->sco_max); ++ struct conn_hash *h = &hdev->conn_hash; ++ struct hci_conn *conn = NULL; ++ int num = 0, min = ~0; ++ struct list_head *p; + +- break; ++ /* We don't have to lock device here. Connections are always ++ * added and removed with TX task disabled. */ ++ list_for_each(p, &h->list) { ++ struct hci_conn *c; ++ c = list_entry(p, struct hci_conn, list); + +- case OCF_READ_BD_ADDR: +- ba = (read_bd_addr_rp *) skb->data; ++ if (c->type != type || c->state != BT_CONNECTED ++ || skb_queue_empty(&c->data_q)) ++ continue; ++ num++; + +- if (!ba->status) { +- bacpy(&hdev->bdaddr, &ba->bdaddr); +- } else { +- DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status); ++ if (c->sent < min) { ++ min = c->sent; ++ conn = c; + } ++ } + +- hci_req_complete(hdev, ba->status); +- break; ++ if (conn) { ++ int cnt = (type == ACL_LINK ? hdev->acl_cnt : hdev->sco_cnt); ++ int q = cnt / num; ++ *quote = q ? q : 1; ++ } else ++ *quote = 0; + +- default: +- DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf); +- break; +- }; ++ BT_DBG("conn %p quote %d", conn, *quote); ++ return conn; + } + +-/* Command Status OGF LINK_CTL */ +-static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status) ++static inline void hci_acl_tx_to(struct hci_dev *hdev) + { +- struct hci_proto * hp; +- +- DBG("%s ocf 0x%x", hdev->name, ocf); +- +- switch (ocf) { +- case OCF_CREATE_CONN: +- if (status) { +- create_conn_cp *cc = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN); +- +- if (!cc) +- break; +- +- DBG("%s Create connection error: status 0x%x %s", hdev->name, +- status, batostr(&cc->bdaddr)); ++ struct conn_hash *h = &hdev->conn_hash; ++ struct list_head *p; ++ struct hci_conn *c; + +- /* Notify upper protocols */ +- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm) { +- tasklet_disable(&hdev->tx_task); +- hp->connect_cfm(hdev, &cc->bdaddr, status, NULL); +- tasklet_enable(&hdev->tx_task); +- } +- } +- break; ++ BT_ERR("%s ACL tx timeout", hdev->name); + +- case OCF_INQUIRY: +- if (status) { +- DBG("%s Inquiry error: status 0x%x", hdev->name, status); +- hci_req_complete(hdev, status); ++ /* Kill stalled connections */ ++ list_for_each(p, &h->list) { ++ c = list_entry(p, struct hci_conn, list); ++ if (c->type == ACL_LINK && c->sent) { ++ BT_ERR("%s killing stalled ACL connection %s", ++ hdev->name, batostr(&c->dst)); ++ hci_acl_disconn(c, 0x13); + } +- break; +- +- default: +- DBG("%s Command status: ogf LINK_CTL ocf %x", hdev->name, ocf); +- break; +- }; +-} +- +-/* Command Status OGF LINK_POLICY */ +-static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status) +-{ +- DBG("%s ocf 0x%x", hdev->name, ocf); +- +- switch (ocf) { +- default: +- DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf); +- break; +- }; +-} +- +-/* Command Status OGF HOST_CTL */ +-static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status) +-{ +- DBG("%s ocf 0x%x", hdev->name, ocf); +- +- switch (ocf) { +- default: +- DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf); +- break; +- }; +-} +- +-/* Command Status OGF INFO_PARAM */ +-static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status) +-{ +- DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf); +- +- switch (ocf) { +- default: +- DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf); +- break; +- }; +-} +- +-/* Inquiry Complete */ +-static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +-{ +- __u8 status = *((__u8 *) skb->data); +- +- DBG("%s status %d", hdev->name, status); +- +- hci_req_complete(hdev, status); ++ } + } + +-/* Inquiry Result */ +-static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) ++static inline void hci_sched_acl(struct hci_dev *hdev) + { +- inquiry_info *info = (inquiry_info *) (skb->data + 1); +- int num_rsp = *((__u8 *) skb->data); +- +- DBG("%s num_rsp %d", hdev->name, num_rsp); ++ struct hci_conn *conn; ++ struct sk_buff *skb; ++ int quote; + +- for (; num_rsp; num_rsp--) +- inquiry_cache_update(&hdev->inq_cache, info++); +-} ++ BT_DBG("%s", hdev->name); + +-/* Connect Request */ +-static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) +-{ +- evt_conn_request *cr = (evt_conn_request *) skb->data; +- struct hci_proto *hp; +- accept_conn_req_cp ac; +- int accept = 0; ++ /* ACL tx timeout must be longer than maximum ++ * link supervision timeout (40.9 seconds) */ ++ if (!hdev->acl_cnt && (jiffies - hdev->acl_last_tx) > (HZ * 45)) ++ hci_acl_tx_to(hdev); + +- DBG("%s Connection request: %s type 0x%x", hdev->name, batostr(&cr->bdaddr), cr->link_type); ++ while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, "e))) { ++ while (quote-- && (skb = skb_dequeue(&conn->data_q))) { ++ BT_DBG("skb %p len %d", skb, skb->len); ++ hci_send_frame(skb); ++ hdev->acl_last_tx = jiffies; + +- /* Notify upper protocols */ +- if (cr->link_type == ACL_LINK) { +- /* ACL link notify L2CAP */ +- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_ind) { +- tasklet_disable(&hdev->tx_task); +- accept = hp->connect_ind(hdev, &cr->bdaddr); +- tasklet_enable(&hdev->tx_task); ++ hdev->acl_cnt--; ++ conn->sent++; + } +- } else { +- /* SCO link (no notification) */ +- /* FIXME: Should be accept it here or let the requester (app) accept it ? */ +- accept = 1; +- } +- +- if (accept) { +- /* Connection accepted by upper layer */ +- bacpy(&ac.bdaddr, &cr->bdaddr); +- ac.role = 0x01; /* Remain slave */ +- hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, ACCEPT_CONN_REQ_CP_SIZE, &ac); +- } else { +- /* Connection rejected by upper layer */ +- /* FIXME: +- * Should we use HCI reject here ? +- */ +- return; + } + } + +-/* Connect Complete */ +-static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ++/* Schedule SCO */ ++static inline void hci_sched_sco(struct hci_dev *hdev) + { +- evt_conn_complete *cc = (evt_conn_complete *) skb->data; +- struct hci_conn *conn = NULL; +- struct hci_proto *hp; +- +- DBG("%s", hdev->name); +- +- tasklet_disable(&hdev->tx_task); +- +- if (!cc->status) +- conn = hci_conn_add(hdev, __le16_to_cpu(cc->handle), cc->link_type, &cc->bdaddr); ++ struct hci_conn *conn; ++ struct sk_buff *skb; ++ int quote; + +- /* Notify upper protocols */ +- if (cc->link_type == ACL_LINK) { +- /* ACL link notify L2CAP layer */ +- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm) +- hp->connect_cfm(hdev, &cc->bdaddr, cc->status, conn); +- } else { +- /* SCO link (no notification) */ +- } ++ BT_DBG("%s", hdev->name); + +- tasklet_enable(&hdev->tx_task); +-} ++ while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, "e))) { ++ while (quote-- && (skb = skb_dequeue(&conn->data_q))) { ++ BT_DBG("skb %p len %d", skb, skb->len); ++ hci_send_frame(skb); + +-/* Disconnect Complete */ +-static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +-{ +- evt_disconn_complete *dc = (evt_disconn_complete *) skb->data; +- struct hci_conn *conn = NULL; +- struct hci_proto *hp; +- __u16 handle = __le16_to_cpu(dc->handle); +- +- DBG("%s", hdev->name); +- +- if (!dc->status && (conn = conn_hash_lookup(&hdev->conn_hash, handle))) { +- tasklet_disable(&hdev->tx_task); +- +- /* Notify upper protocols */ +- if (conn->type == ACL_LINK) { +- /* ACL link notify L2CAP layer */ +- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->disconn_ind) +- hp->disconn_ind(conn, dc->reason); +- } else { +- /* SCO link (no notification) */ ++ conn->sent++; ++ if (conn->sent == ~0) ++ conn->sent = 0; + } +- +- hci_conn_del(hdev, conn); +- +- tasklet_enable(&hdev->tx_task); + } + } + +-/* Number of completed packets */ +-static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb) ++static void hci_tx_task(unsigned long arg) + { +- evt_num_comp_pkts *nc = (evt_num_comp_pkts *) skb->data; +- __u16 *ptr; +- int i; +- +- skb_pull(skb, EVT_NUM_COMP_PKTS_SIZE); +- +- DBG("%s num_hndl %d", hdev->name, nc->num_hndl); ++ struct hci_dev *hdev = (struct hci_dev *) arg; ++ struct sk_buff *skb; + +- if (skb->len < nc->num_hndl * 4) { +- DBG("%s bad parameters", hdev->name); +- return; +- } ++ read_lock(&hci_task_lock); + +- tasklet_disable(&hdev->tx_task); ++ BT_DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt); + +- for (i = 0, ptr = (__u16 *) skb->data; i < nc->num_hndl; i++) { +- struct hci_conn *conn; +- __u16 handle, count; ++ /* Schedule queues and send stuff to HCI driver */ + +- handle = __le16_to_cpu(get_unaligned(ptr++)); +- count = __le16_to_cpu(get_unaligned(ptr++)); ++ hci_sched_acl(hdev); + +- hdev->acl_cnt += count; ++ hci_sched_sco(hdev); + +- if ((conn = conn_hash_lookup(&hdev->conn_hash, handle))) +- conn->sent -= count; +- } ++ /* Send next queued raw (unknown type) packet */ ++ while ((skb = skb_dequeue(&hdev->raw_q))) ++ hci_send_frame(skb); + +- tasklet_enable(&hdev->tx_task); +- +- hci_sched_tx(hdev); ++ read_unlock(&hci_task_lock); + } + +-static inline void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) +-{ +- hci_event_hdr *he = (hci_event_hdr *) skb->data; +- evt_cmd_status *cs; +- evt_cmd_complete *ec; +- __u16 opcode, ocf, ogf; +- +- skb_pull(skb, HCI_EVENT_HDR_SIZE); +- +- DBG("%s evt 0x%x", hdev->name, he->evt); +- +- switch (he->evt) { +- case EVT_NUM_COMP_PKTS: +- hci_num_comp_pkts_evt(hdev, skb); +- break; +- +- case EVT_INQUIRY_COMPLETE: +- hci_inquiry_complete_evt(hdev, skb); +- break; +- +- case EVT_INQUIRY_RESULT: +- hci_inquiry_result_evt(hdev, skb); +- break; +- +- case EVT_CONN_REQUEST: +- hci_conn_request_evt(hdev, skb); +- break; +- +- case EVT_CONN_COMPLETE: +- hci_conn_complete_evt(hdev, skb); +- break; +- +- case EVT_DISCONN_COMPLETE: +- hci_disconn_complete_evt(hdev, skb); +- break; +- +- case EVT_CMD_STATUS: +- cs = (evt_cmd_status *) skb->data; +- skb_pull(skb, EVT_CMD_STATUS_SIZE); +- +- opcode = __le16_to_cpu(cs->opcode); +- ogf = cmd_opcode_ogf(opcode); +- ocf = cmd_opcode_ocf(opcode); +- +- switch (ogf) { +- case OGF_INFO_PARAM: +- hci_cs_info_param(hdev, ocf, cs->status); +- break; +- +- case OGF_HOST_CTL: +- hci_cs_host_ctl(hdev, ocf, cs->status); +- break; +- +- case OGF_LINK_CTL: +- hci_cs_link_ctl(hdev, ocf, cs->status); +- break; +- +- case OGF_LINK_POLICY: +- hci_cs_link_policy(hdev, ocf, cs->status); +- break; +- +- default: +- DBG("%s Command Status OGF %x", hdev->name, ogf); +- break; +- }; +- +- if (cs->ncmd) { +- atomic_set(&hdev->cmd_cnt, 1); +- if (!skb_queue_empty(&hdev->cmd_q)) +- hci_sched_cmd(hdev); +- } +- break; +- +- case EVT_CMD_COMPLETE: +- ec = (evt_cmd_complete *) skb->data; +- skb_pull(skb, EVT_CMD_COMPLETE_SIZE); +- +- opcode = __le16_to_cpu(ec->opcode); +- ogf = cmd_opcode_ogf(opcode); +- ocf = cmd_opcode_ocf(opcode); +- +- switch (ogf) { +- case OGF_INFO_PARAM: +- hci_cc_info_param(hdev, ocf, skb); +- break; +- +- case OGF_HOST_CTL: +- hci_cc_host_ctl(hdev, ocf, skb); +- break; +- +- case OGF_LINK_CTL: +- hci_cc_link_ctl(hdev, ocf, skb); +- break; +- +- case OGF_LINK_POLICY: +- hci_cc_link_policy(hdev, ocf, skb); +- break; + +- default: +- DBG("%s Command Completed OGF %x", hdev->name, ogf); +- break; +- }; +- +- if (ec->ncmd) { +- atomic_set(&hdev->cmd_cnt, 1); +- if (!skb_queue_empty(&hdev->cmd_q)) +- hci_sched_cmd(hdev); +- } +- break; +- }; +- +- kfree_skb(skb); +- hdev->stat.evt_rx++; +-} ++/* ----- HCI RX task (incomming data proccessing) ----- */ + + /* ACL data packet */ + static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb) +@@ -1867,51 +1255,86 @@ + flags = acl_flags(handle); + handle = acl_handle(handle); + +- DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags); ++ BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags); ++ ++ hdev->stat.acl_rx++; + +- if ((conn = conn_hash_lookup(&hdev->conn_hash, handle))) { ++ hci_dev_lock(hdev); ++ conn = conn_hash_lookup_handle(hdev, handle); ++ hci_dev_unlock(hdev); ++ ++ if (conn) { + register struct hci_proto *hp; + + /* Send to upper protocol */ +- if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->recv_acldata) { ++ if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) { + hp->recv_acldata(conn, skb, flags); +- goto sent; ++ return; + } + } else { +- ERR("%s ACL packet for unknown connection handle %d", hdev->name, handle); ++ BT_ERR("%s ACL packet for unknown connection handle %d", ++ hdev->name, handle); + } + + kfree_skb(skb); +-sent: +- hdev->stat.acl_rx++; + } + + /* SCO data packet */ + static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb) + { +- DBG("%s len %d", hdev->name, skb->len); ++ hci_sco_hdr *sh = (void *) skb->data; ++ struct hci_conn *conn; ++ __u16 handle; ++ ++ skb_pull(skb, HCI_SCO_HDR_SIZE); ++ ++ handle = __le16_to_cpu(sh->handle); ++ ++ BT_DBG("%s len %d handle 0x%x", hdev->name, skb->len, handle); + +- kfree_skb(skb); + hdev->stat.sco_rx++; ++ ++ hci_dev_lock(hdev); ++ conn = conn_hash_lookup_handle(hdev, handle); ++ hci_dev_unlock(hdev); ++ ++ if (conn) { ++ register struct hci_proto *hp; ++ ++ /* Send to upper protocol */ ++ if ((hp = hci_proto[HCI_PROTO_SCO]) && hp->recv_scodata) { ++ hp->recv_scodata(conn, skb); ++ return; ++ } ++ } else { ++ BT_ERR("%s SCO packet for unknown connection handle %d", ++ hdev->name, handle); ++ } ++ ++ kfree_skb(skb); + } + +-/* ----- HCI tasks ----- */ + void hci_rx_task(unsigned long arg) + { + struct hci_dev *hdev = (struct hci_dev *) arg; + struct sk_buff *skb; + +- DBG("%s", hdev->name); ++ BT_DBG("%s", hdev->name); + + read_lock(&hci_task_lock); + + while ((skb = skb_dequeue(&hdev->rx_q))) { +- if (hdev->flags & HCI_SOCK) { ++ if (atomic_read(&hdev->promisc)) { + /* Send copy to the sockets */ + hci_send_to_sock(hdev, skb); + } + +- if (hdev->flags & HCI_INIT) { ++ if (test_bit(HCI_RAW, &hdev->flags)) { ++ kfree_skb(skb); ++ continue; ++ } ++ ++ if (test_bit(HCI_INIT, &hdev->flags)) { + /* Don't process data packets in this states. */ + switch (skb->pkt_type) { + case HCI_ACLDATA_PKT: +@@ -1921,64 +1344,43 @@ + }; + } + +- if (hdev->flags & HCI_NORMAL) { +- /* Process frame */ +- switch (skb->pkt_type) { +- case HCI_EVENT_PKT: +- hci_event_packet(hdev, skb); +- break; ++ /* Process frame */ ++ switch (skb->pkt_type) { ++ case HCI_EVENT_PKT: ++ hci_event_packet(hdev, skb); ++ break; + +- case HCI_ACLDATA_PKT: +- DBG("%s ACL data packet", hdev->name); +- hci_acldata_packet(hdev, skb); +- break; ++ case HCI_ACLDATA_PKT: ++ BT_DBG("%s ACL data packet", hdev->name); ++ hci_acldata_packet(hdev, skb); ++ break; + +- case HCI_SCODATA_PKT: +- DBG("%s SCO data packet", hdev->name); +- hci_scodata_packet(hdev, skb); +- break; ++ case HCI_SCODATA_PKT: ++ BT_DBG("%s SCO data packet", hdev->name); ++ hci_scodata_packet(hdev, skb); ++ break; + +- default: +- kfree_skb(skb); +- break; +- }; +- } else { ++ default: + kfree_skb(skb); ++ break; + } + } + + read_unlock(&hci_task_lock); + } + +-static void hci_tx_task(unsigned long arg) +-{ +- struct hci_dev *hdev = (struct hci_dev *) arg; +- struct sk_buff *skb; +- +- read_lock(&hci_task_lock); +- +- DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt); +- +- /* Schedule queues and send stuff to HCI driver */ +- +- hci_sched_acl(hdev); +- +- hci_sched_sco(hdev); +- +- /* Send next queued raw (unknown type) packet */ +- while ((skb = skb_dequeue(&hdev->raw_q))) +- hci_send_frame(skb); +- +- read_unlock(&hci_task_lock); +-} +- + static void hci_cmd_task(unsigned long arg) + { + struct hci_dev *hdev = (struct hci_dev *) arg; + struct sk_buff *skb; + +- DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt)); ++ BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt)); + ++ if (!atomic_read(&hdev->cmd_cnt) && (jiffies - hdev->cmd_last_tx) > HZ) { ++ BT_ERR("%s command tx timeout", hdev->name); ++ atomic_set(&hdev->cmd_cnt, 1); ++ } ++ + /* Send queued commands */ + if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) { + if (hdev->sent_cmd) +@@ -1987,6 +1389,7 @@ + if ((hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC))) { + atomic_dec(&hdev->cmd_cnt); + hci_send_frame(skb); ++ hdev->cmd_last_tx = jiffies; + } else { + skb_queue_head(&hdev->cmd_q, skb); + hci_sched_cmd(hdev); +@@ -1994,33 +1397,10 @@ + } + } + +-/* Receive frame from HCI drivers */ +-int hci_recv_frame(struct sk_buff *skb) +-{ +- struct hci_dev *hdev = (struct hci_dev *) skb->dev; +- +- if (!hdev || !(hdev->flags & (HCI_UP | HCI_INIT))) { +- kfree_skb(skb); +- return -1; +- } +- +- DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); +- +- /* Incomming skb */ +- bluez_cb(skb)->incomming = 1; +- +- /* Queue frame for rx task */ +- skb_queue_tail(&hdev->rx_q, skb); +- hci_sched_rx(hdev); +- +- return 0; +-} ++/* ---- Initialization ---- */ + + int hci_core_init(void) + { +- /* Init locks */ +- spin_lock_init(&hdev_list_lock); +- + return 0; + } + +@@ -2028,5 +1408,3 @@ + { + return 0; + } +- +-MODULE_LICENSE("GPL"); +diff -urN linux-2.4.18/net/bluetooth/hci_event.c linux-2.4.18-mh9/net/bluetooth/hci_event.c +--- linux-2.4.18/net/bluetooth/hci_event.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/hci_event.c Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,927 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * HCI Events. ++ * ++ * $Id$ ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/init.h> ++#include <linux/skbuff.h> ++#include <linux/interrupt.h> ++#include <linux/notifier.h> ++#include <net/sock.h> ++ ++#include <asm/system.h> ++#include <asm/uaccess.h> ++#include <asm/unaligned.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++ ++#ifndef HCI_CORE_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#endif ++ ++/* Handle HCI Event packets */ ++ ++/* Command Complete OGF LINK_CTL */ ++static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) ++{ ++ __u8 status; ++ ++ BT_DBG("%s ocf 0x%x", hdev->name, ocf); ++ ++ switch (ocf) { ++ case OCF_INQUIRY_CANCEL: ++ status = *((__u8 *) skb->data); ++ ++ if (status) { ++ BT_DBG("%s Inquiry cancel error: status 0x%x", hdev->name, status); ++ } else { ++ clear_bit(HCI_INQUIRY, &hdev->flags); ++ hci_req_complete(hdev, status); ++ } ++ break; ++ ++ default: ++ BT_DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf); ++ break; ++ }; ++} ++ ++/* Command Complete OGF LINK_POLICY */ ++static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) ++{ ++ struct hci_conn *conn; ++ role_discovery_rp *rd; ++ ++ BT_DBG("%s ocf 0x%x", hdev->name, ocf); ++ ++ switch (ocf) { ++ case OCF_ROLE_DISCOVERY: ++ rd = (void *) skb->data; ++ ++ if (rd->status) ++ break; ++ ++ hci_dev_lock(hdev); ++ ++ conn = conn_hash_lookup_handle(hdev, __le16_to_cpu(rd->handle)); ++ if (conn) { ++ if (rd->role) ++ conn->link_mode &= ~HCI_LM_MASTER; ++ else ++ conn->link_mode |= HCI_LM_MASTER; ++ } ++ ++ hci_dev_unlock(hdev); ++ break; ++ ++ default: ++ BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x", ++ hdev->name, ocf); ++ break; ++ }; ++} ++ ++/* Command Complete OGF HOST_CTL */ ++static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) ++{ ++ __u8 status, param; ++ __u16 setting; ++ read_voice_setting_rp *vs; ++ void *sent; ++ ++ BT_DBG("%s ocf 0x%x", hdev->name, ocf); ++ ++ switch (ocf) { ++ case OCF_RESET: ++ status = *((__u8 *) skb->data); ++ hci_req_complete(hdev, status); ++ break; ++ ++ case OCF_SET_EVENT_FLT: ++ status = *((__u8 *) skb->data); ++ if (status) { ++ BT_DBG("%s SET_EVENT_FLT failed %d", hdev->name, status); ++ } else { ++ BT_DBG("%s SET_EVENT_FLT succeseful", hdev->name); ++ } ++ break; ++ ++ case OCF_WRITE_AUTH_ENABLE: ++ sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE); ++ if (!sent) ++ break; ++ ++ status = *((__u8 *) skb->data); ++ param = *((__u8 *) sent); ++ ++ if (!status) { ++ if (param == AUTH_ENABLED) ++ set_bit(HCI_AUTH, &hdev->flags); ++ else ++ clear_bit(HCI_AUTH, &hdev->flags); ++ } ++ hci_req_complete(hdev, status); ++ break; ++ ++ case OCF_WRITE_ENCRYPT_MODE: ++ sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE); ++ if (!sent) ++ break; ++ ++ status = *((__u8 *) skb->data); ++ param = *((__u8 *) sent); ++ ++ if (!status) { ++ if (param) ++ set_bit(HCI_ENCRYPT, &hdev->flags); ++ else ++ clear_bit(HCI_ENCRYPT, &hdev->flags); ++ } ++ hci_req_complete(hdev, status); ++ break; ++ ++ case OCF_WRITE_CA_TIMEOUT: ++ status = *((__u8 *) skb->data); ++ if (status) { ++ BT_DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status); ++ } else { ++ BT_DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name); ++ } ++ break; ++ ++ case OCF_WRITE_PG_TIMEOUT: ++ status = *((__u8 *) skb->data); ++ if (status) { ++ BT_DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status); ++ } else { ++ BT_DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name); ++ } ++ break; ++ ++ case OCF_WRITE_SCAN_ENABLE: ++ sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE); ++ if (!sent) ++ break; ++ ++ status = *((__u8 *) skb->data); ++ param = *((__u8 *) sent); ++ ++ BT_DBG("param 0x%x", param); ++ ++ if (!status) { ++ clear_bit(HCI_PSCAN, &hdev->flags); ++ clear_bit(HCI_ISCAN, &hdev->flags); ++ if (param & SCAN_INQUIRY) ++ set_bit(HCI_ISCAN, &hdev->flags); ++ ++ if (param & SCAN_PAGE) ++ set_bit(HCI_PSCAN, &hdev->flags); ++ } ++ hci_req_complete(hdev, status); ++ break; ++ ++ case OCF_READ_VOICE_SETTING: ++ vs = (read_voice_setting_rp *) skb->data; ++ ++ if (vs->status) { ++ BT_DBG("%s READ_VOICE_SETTING failed %d", hdev->name, vc->status); ++ break; ++ } ++ ++ setting = __le16_to_cpu(vs->voice_setting); ++ ++ if (hdev->voice_setting != setting ) { ++ hdev->voice_setting = setting; ++ ++ BT_DBG("%s: voice setting 0x%04x", hdev->name, setting); ++ ++ if (hdev->notify) ++ hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING, 0); ++ } ++ ++ break; ++ ++ case OCF_WRITE_VOICE_SETTING: ++ sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING); ++ if (!sent) ++ break; ++ ++ status = *((__u8 *) skb->data); ++ setting = __le16_to_cpu(get_unaligned((__u16 *) sent)); ++ ++ if (!status && hdev->voice_setting != setting) { ++ hdev->voice_setting = setting; ++ ++ BT_DBG("%s: voice setting 0x%04x", hdev->name, setting); ++ ++ if (hdev->notify) ++ hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING, 0); ++ } ++ hci_req_complete(hdev, status); ++ break; ++ ++ case OCF_HOST_BUFFER_SIZE: ++ status = *((__u8 *) skb->data); ++ if (status) { ++ BT_DBG("%s OCF_BUFFER_SIZE failed %d", hdev->name, status); ++ hci_req_complete(hdev, status); ++ } ++ break; ++ ++ default: ++ BT_DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf); ++ break; ++ }; ++} ++ ++/* Command Complete OGF INFO_PARAM */ ++static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) ++{ ++ read_local_features_rp *lf; ++ read_buffer_size_rp *bs; ++ read_bd_addr_rp *ba; ++ ++ BT_DBG("%s ocf 0x%x", hdev->name, ocf); ++ ++ switch (ocf) { ++ case OCF_READ_LOCAL_FEATURES: ++ lf = (read_local_features_rp *) skb->data; ++ ++ if (lf->status) { ++ BT_DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status); ++ break; ++ } ++ ++ memcpy(hdev->features, lf->features, sizeof(hdev->features)); ++ ++ /* Adjust default settings according to features ++ * supported by device. */ ++ if (hdev->features[0] & LMP_3SLOT) ++ hdev->pkt_type |= (HCI_DM3 | HCI_DH3); ++ ++ if (hdev->features[0] & LMP_5SLOT) ++ hdev->pkt_type |= (HCI_DM5 | HCI_DH5); ++ ++ if (hdev->features[1] & LMP_HV2) ++ hdev->pkt_type |= (HCI_HV2); ++ ++ if (hdev->features[1] & LMP_HV3) ++ hdev->pkt_type |= (HCI_HV3); ++ ++ BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]); ++ ++ break; ++ ++ case OCF_READ_BUFFER_SIZE: ++ bs = (read_buffer_size_rp *) skb->data; ++ ++ if (bs->status) { ++ BT_DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status); ++ hci_req_complete(hdev, bs->status); ++ break; ++ } ++ ++ hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu); ++ hdev->sco_mtu = bs->sco_mtu ? bs->sco_mtu : 64; ++ hdev->acl_pkts = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt); ++ hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt); ++ ++ BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name, ++ hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts); ++ ++ break; ++ ++ case OCF_READ_BD_ADDR: ++ ba = (read_bd_addr_rp *) skb->data; ++ ++ if (!ba->status) { ++ bacpy(&hdev->bdaddr, &ba->bdaddr); ++ } else { ++ BT_DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status); ++ } ++ ++ hci_req_complete(hdev, ba->status); ++ break; ++ ++ default: ++ BT_DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf); ++ break; ++ }; ++} ++ ++/* Command Status OGF LINK_CTL */ ++static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) ++{ ++ struct hci_conn *conn; ++ create_conn_cp *cc = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN); ++ ++ if (!cc) ++ return; ++ ++ hci_dev_lock(hdev); ++ ++ conn = conn_hash_lookup_ba(hdev, ACL_LINK, &cc->bdaddr); ++ ++ BT_DBG("%s status 0x%x bdaddr %s conn %p", hdev->name, ++ status, batostr(&cc->bdaddr), conn); ++ ++ if (status) { ++ if (conn) { ++ conn->state = BT_CLOSED; ++ hci_proto_connect_cfm(conn, status); ++ hci_conn_del(conn); ++ } ++ } else { ++ if (!conn) { ++ conn = hci_conn_add(hdev, ACL_LINK, &cc->bdaddr); ++ if (conn) { ++ conn->out = 1; ++ conn->link_mode |= HCI_LM_MASTER; ++ } else ++ BT_ERR("No memmory for new connection"); ++ } ++ } ++ ++ hci_dev_unlock(hdev); ++} ++ ++static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status) ++{ ++ BT_DBG("%s ocf 0x%x", hdev->name, ocf); ++ ++ switch (ocf) { ++ case OCF_CREATE_CONN: ++ hci_cs_create_conn(hdev, status); ++ break; ++ ++ case OCF_ADD_SCO: ++ if (status) { ++ struct hci_conn *acl, *sco; ++ add_sco_cp *cp = hci_sent_cmd_data(hdev, ++ OGF_LINK_CTL, OCF_ADD_SCO); ++ __u16 handle; ++ ++ if (!cp) ++ break; ++ ++ handle = __le16_to_cpu(cp->handle); ++ ++ BT_DBG("%s Add SCO error: handle %d status 0x%x", hdev->name, handle, status); ++ ++ hci_dev_lock(hdev); ++ ++ acl = conn_hash_lookup_handle(hdev, handle); ++ if (acl && (sco = acl->link)) { ++ sco->state = BT_CLOSED; ++ hci_proto_connect_cfm(sco, status); ++ hci_conn_del(sco); ++ } ++ ++ hci_dev_unlock(hdev); ++ } ++ break; ++ ++ case OCF_INQUIRY: ++ if (status) { ++ BT_DBG("%s Inquiry error: status 0x%x", hdev->name, status); ++ hci_req_complete(hdev, status); ++ } else { ++ set_bit(HCI_INQUIRY, &hdev->flags); ++ } ++ break; ++ ++ default: ++ BT_DBG("%s Command status: ogf LINK_CTL ocf %x status %d", ++ hdev->name, ocf, status); ++ break; ++ }; ++} ++ ++/* Command Status OGF LINK_POLICY */ ++static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status) ++{ ++ BT_DBG("%s ocf 0x%x", hdev->name, ocf); ++ ++ switch (ocf) { ++ default: ++ BT_DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf); ++ break; ++ }; ++} ++ ++/* Command Status OGF HOST_CTL */ ++static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status) ++{ ++ BT_DBG("%s ocf 0x%x", hdev->name, ocf); ++ ++ switch (ocf) { ++ default: ++ BT_DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf); ++ break; ++ }; ++} ++ ++/* Command Status OGF INFO_PARAM */ ++static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status) ++{ ++ BT_DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf); ++ ++ switch (ocf) { ++ default: ++ BT_DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf); ++ break; ++ }; ++} ++ ++/* Inquiry Complete */ ++static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ __u8 status = *((__u8 *) skb->data); ++ ++ BT_DBG("%s status %d", hdev->name, status); ++ ++ clear_bit(HCI_INQUIRY, &hdev->flags); ++ hci_req_complete(hdev, status); ++} ++ ++/* Inquiry Result */ ++static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ inquiry_info *info = (inquiry_info *) (skb->data + 1); ++ int num_rsp = *((__u8 *) skb->data); ++ ++ BT_DBG("%s num_rsp %d", hdev->name, num_rsp); ++ ++ hci_dev_lock(hdev); ++ for (; num_rsp; num_rsp--) ++ inquiry_cache_update(hdev, info++); ++ hci_dev_unlock(hdev); ++} ++ ++/* Connect Request */ ++static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ evt_conn_request *cr = (evt_conn_request *) skb->data; ++ int mask = hdev->link_mode; ++ ++ BT_DBG("%s Connection request: %s type 0x%x", hdev->name, ++ batostr(&cr->bdaddr), cr->link_type); ++ ++ mask |= hci_proto_connect_ind(hdev, &cr->bdaddr, cr->link_type); ++ ++ if (mask & HCI_LM_ACCEPT) { ++ /* Connection accepted */ ++ struct hci_conn *conn; ++ accept_conn_req_cp ac; ++ ++ hci_dev_lock(hdev); ++ conn = conn_hash_lookup_ba(hdev, cr->link_type, &cr->bdaddr); ++ if (!conn) { ++ if (!(conn = hci_conn_add(hdev, cr->link_type, &cr->bdaddr))) { ++ BT_ERR("No memmory for new connection"); ++ hci_dev_unlock(hdev); ++ return; ++ } ++ } ++ conn->state = BT_CONNECT; ++ hci_dev_unlock(hdev); ++ ++ bacpy(&ac.bdaddr, &cr->bdaddr); ++ ++ if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) ++ ac.role = 0x00; /* Become master */ ++ else ++ ac.role = 0x01; /* Remain slave */ ++ ++ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, ++ ACCEPT_CONN_REQ_CP_SIZE, &ac); ++ } else { ++ /* Connection rejected */ ++ reject_conn_req_cp rc; ++ ++ bacpy(&rc.bdaddr, &cr->bdaddr); ++ rc.reason = 0x0f; ++ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_REJECT_CONN_REQ, ++ REJECT_CONN_REQ_CP_SIZE, &rc); ++ } ++} ++ ++/* Connect Complete */ ++static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ evt_conn_complete *cc = (evt_conn_complete *) skb->data; ++ struct hci_conn *conn = NULL; ++ ++ BT_DBG("%s", hdev->name); ++ ++ hci_dev_lock(hdev); ++ ++ conn = conn_hash_lookup_ba(hdev, cc->link_type, &cc->bdaddr); ++ if (!conn) { ++ hci_dev_unlock(hdev); ++ return; ++ } ++ ++ if (!cc->status) { ++ conn->handle = __le16_to_cpu(cc->handle); ++ conn->state = BT_CONNECTED; ++ ++ if (test_bit(HCI_AUTH, &hdev->flags)) ++ conn->link_mode |= HCI_LM_AUTH; ++ ++ if (test_bit(HCI_ENCRYPT, &hdev->flags)) ++ conn->link_mode |= HCI_LM_ENCRYPT; ++ ++ ++ /* Set link policy */ ++ if (conn->type == ACL_LINK && hdev->link_policy) { ++ write_link_policy_cp lp; ++ lp.handle = cc->handle; ++ lp.policy = __cpu_to_le16(hdev->link_policy); ++ hci_send_cmd(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY, ++ WRITE_LINK_POLICY_CP_SIZE, &lp); ++ } ++ ++ /* Set packet type for incomming connection */ ++ if (!conn->out) { ++ change_conn_ptype_cp cp; ++ cp.handle = cc->handle; ++ cp.pkt_type = (conn->type == ACL_LINK) ? ++ __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK): ++ __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); ++ ++ hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_PTYPE, ++ CHANGE_CONN_PTYPE_CP_SIZE, &cp); ++ } ++ } else ++ conn->state = BT_CLOSED; ++ ++ if (conn->type == ACL_LINK) { ++ struct hci_conn *sco = conn->link; ++ if (sco) { ++ if (!cc->status) ++ hci_add_sco(sco, conn->handle); ++ else { ++ hci_proto_connect_cfm(sco, cc->status); ++ hci_conn_del(sco); ++ } ++ } ++ } ++ ++ hci_proto_connect_cfm(conn, cc->status); ++ if (cc->status) ++ hci_conn_del(conn); ++ ++ hci_dev_unlock(hdev); ++} ++ ++/* Disconnect Complete */ ++static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ evt_disconn_complete *dc = (evt_disconn_complete *) skb->data; ++ struct hci_conn *conn = NULL; ++ __u16 handle = __le16_to_cpu(dc->handle); ++ ++ BT_DBG("%s status %d", hdev->name, dc->status); ++ ++ if (dc->status) ++ return; ++ ++ hci_dev_lock(hdev); ++ ++ conn = conn_hash_lookup_handle(hdev, handle); ++ if (conn) { ++ conn->state = BT_CLOSED; ++ hci_proto_disconn_ind(conn, dc->reason); ++ hci_conn_del(conn); ++ } ++ ++ hci_dev_unlock(hdev); ++} ++ ++/* Number of completed packets */ ++static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ evt_num_comp_pkts *nc = (evt_num_comp_pkts *) skb->data; ++ __u16 *ptr; ++ int i; ++ ++ skb_pull(skb, EVT_NUM_COMP_PKTS_SIZE); ++ ++ BT_DBG("%s num_hndl %d", hdev->name, nc->num_hndl); ++ ++ if (skb->len < nc->num_hndl * 4) { ++ BT_DBG("%s bad parameters", hdev->name); ++ return; ++ } ++ ++ tasklet_disable(&hdev->tx_task); ++ ++ for (i = 0, ptr = (__u16 *) skb->data; i < nc->num_hndl; i++) { ++ struct hci_conn *conn; ++ __u16 handle, count; ++ ++ handle = __le16_to_cpu(get_unaligned(ptr++)); ++ count = __le16_to_cpu(get_unaligned(ptr++)); ++ ++ conn = conn_hash_lookup_handle(hdev, handle); ++ if (conn) { ++ conn->sent -= count; ++ ++ if (conn->type == SCO_LINK) { ++ if ((hdev->sco_cnt += count) > hdev->sco_pkts) ++ hdev->sco_cnt = hdev->sco_pkts; ++ } else { ++ if ((hdev->acl_cnt += count) > hdev->acl_pkts) ++ hdev->acl_cnt = hdev->acl_pkts; ++ } ++ } ++ } ++ hci_sched_tx(hdev); ++ ++ tasklet_enable(&hdev->tx_task); ++} ++ ++/* Role Change */ ++static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ evt_role_change *rc = (evt_role_change *) skb->data; ++ struct hci_conn *conn = NULL; ++ ++ BT_DBG("%s status %d", hdev->name, rc->status); ++ ++ if (rc->status) ++ return; ++ ++ hci_dev_lock(hdev); ++ ++ conn = conn_hash_lookup_ba(hdev, ACL_LINK, &rc->bdaddr); ++ if (conn) { ++ if (rc->role) ++ conn->link_mode &= ~HCI_LM_MASTER; ++ else ++ conn->link_mode |= HCI_LM_MASTER; ++ } ++ ++ hci_dev_unlock(hdev); ++} ++ ++/* Authentication Complete */ ++static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ evt_auth_complete *ac = (evt_auth_complete *) skb->data; ++ struct hci_conn *conn = NULL; ++ __u16 handle = __le16_to_cpu(ac->handle); ++ ++ BT_DBG("%s status %d", hdev->name, ac->status); ++ ++ hci_dev_lock(hdev); ++ ++ conn = conn_hash_lookup_handle(hdev, handle); ++ if (conn) { ++ if (!ac->status) ++ conn->link_mode |= HCI_LM_AUTH; ++ clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); ++ ++ hci_proto_auth_cfm(conn, ac->status); ++ ++ if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { ++ if (!ac->status) { ++ set_conn_encrypt_cp ce; ++ ce.handle = __cpu_to_le16(conn->handle); ++ ce.encrypt = 1; ++ hci_send_cmd(conn->hdev, OGF_LINK_CTL, ++ OCF_SET_CONN_ENCRYPT, ++ SET_CONN_ENCRYPT_CP_SIZE, &ce); ++ } else { ++ clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); ++ hci_proto_encrypt_cfm(conn, ac->status); ++ } ++ } ++ } ++ ++ hci_dev_unlock(hdev); ++} ++ ++/* Encryption Change */ ++static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ evt_encrypt_change *ec = (evt_encrypt_change *) skb->data; ++ struct hci_conn *conn = NULL; ++ __u16 handle = __le16_to_cpu(ec->handle); ++ ++ BT_DBG("%s status %d", hdev->name, ec->status); ++ ++ hci_dev_lock(hdev); ++ ++ conn = conn_hash_lookup_handle(hdev, handle); ++ if (conn) { ++ if (!ec->status) { ++ if (ec->encrypt) ++ conn->link_mode |= HCI_LM_ENCRYPT; ++ else ++ conn->link_mode &= ~HCI_LM_ENCRYPT; ++ } ++ clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); ++ ++ hci_proto_encrypt_cfm(conn, ec->status); ++ } ++ ++ hci_dev_unlock(hdev); ++} ++ ++void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) ++{ ++ hci_event_hdr *he = (hci_event_hdr *) skb->data; ++ evt_cmd_status *cs; ++ evt_cmd_complete *ec; ++ __u16 opcode, ocf, ogf; ++ ++ skb_pull(skb, HCI_EVENT_HDR_SIZE); ++ ++ BT_DBG("%s evt 0x%x", hdev->name, he->evt); ++ ++ switch (he->evt) { ++ case EVT_NUM_COMP_PKTS: ++ hci_num_comp_pkts_evt(hdev, skb); ++ break; ++ ++ case EVT_INQUIRY_COMPLETE: ++ hci_inquiry_complete_evt(hdev, skb); ++ break; ++ ++ case EVT_INQUIRY_RESULT: ++ hci_inquiry_result_evt(hdev, skb); ++ break; ++ ++ case EVT_CONN_REQUEST: ++ hci_conn_request_evt(hdev, skb); ++ break; ++ ++ case EVT_CONN_COMPLETE: ++ hci_conn_complete_evt(hdev, skb); ++ break; ++ ++ case EVT_DISCONN_COMPLETE: ++ hci_disconn_complete_evt(hdev, skb); ++ break; ++ ++ case EVT_ROLE_CHANGE: ++ hci_role_change_evt(hdev, skb); ++ break; ++ ++ case EVT_AUTH_COMPLETE: ++ hci_auth_complete_evt(hdev, skb); ++ break; ++ ++ case EVT_ENCRYPT_CHANGE: ++ hci_encrypt_change_evt(hdev, skb); ++ break; ++ ++ case EVT_CMD_STATUS: ++ cs = (evt_cmd_status *) skb->data; ++ skb_pull(skb, EVT_CMD_STATUS_SIZE); ++ ++ opcode = __le16_to_cpu(cs->opcode); ++ ogf = cmd_opcode_ogf(opcode); ++ ocf = cmd_opcode_ocf(opcode); ++ ++ switch (ogf) { ++ case OGF_INFO_PARAM: ++ hci_cs_info_param(hdev, ocf, cs->status); ++ break; ++ ++ case OGF_HOST_CTL: ++ hci_cs_host_ctl(hdev, ocf, cs->status); ++ break; ++ ++ case OGF_LINK_CTL: ++ hci_cs_link_ctl(hdev, ocf, cs->status); ++ break; ++ ++ case OGF_LINK_POLICY: ++ hci_cs_link_policy(hdev, ocf, cs->status); ++ break; ++ ++ default: ++ BT_DBG("%s Command Status OGF %x", hdev->name, ogf); ++ break; ++ }; ++ ++ if (cs->ncmd) { ++ atomic_set(&hdev->cmd_cnt, 1); ++ if (!skb_queue_empty(&hdev->cmd_q)) ++ hci_sched_cmd(hdev); ++ } ++ break; ++ ++ case EVT_CMD_COMPLETE: ++ ec = (evt_cmd_complete *) skb->data; ++ skb_pull(skb, EVT_CMD_COMPLETE_SIZE); ++ ++ opcode = __le16_to_cpu(ec->opcode); ++ ogf = cmd_opcode_ogf(opcode); ++ ocf = cmd_opcode_ocf(opcode); ++ ++ switch (ogf) { ++ case OGF_INFO_PARAM: ++ hci_cc_info_param(hdev, ocf, skb); ++ break; ++ ++ case OGF_HOST_CTL: ++ hci_cc_host_ctl(hdev, ocf, skb); ++ break; ++ ++ case OGF_LINK_CTL: ++ hci_cc_link_ctl(hdev, ocf, skb); ++ break; ++ ++ case OGF_LINK_POLICY: ++ hci_cc_link_policy(hdev, ocf, skb); ++ break; ++ ++ default: ++ BT_DBG("%s Command Completed OGF %x", hdev->name, ogf); ++ break; ++ }; ++ ++ if (ec->ncmd) { ++ atomic_set(&hdev->cmd_cnt, 1); ++ if (!skb_queue_empty(&hdev->cmd_q)) ++ hci_sched_cmd(hdev); ++ } ++ break; ++ }; ++ ++ kfree_skb(skb); ++ hdev->stat.evt_rx++; ++} ++ ++/* General internal stack event */ ++void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data) ++{ ++ hci_event_hdr *eh; ++ evt_stack_internal *si; ++ struct sk_buff *skb; ++ int size; ++ void *ptr; ++ ++ size = HCI_EVENT_HDR_SIZE + EVT_STACK_INTERNAL_SIZE + dlen; ++ skb = bluez_skb_alloc(size, GFP_ATOMIC); ++ if (!skb) ++ return; ++ ++ ptr = skb_put(skb, size); ++ ++ eh = ptr; ++ eh->evt = EVT_STACK_INTERNAL; ++ eh->plen = EVT_STACK_INTERNAL_SIZE + dlen; ++ ptr += HCI_EVENT_HDR_SIZE; ++ ++ si = ptr; ++ si->type = type; ++ memcpy(si->data, data, dlen); ++ ++ skb->pkt_type = HCI_EVENT_PKT; ++ skb->dev = (void *) hdev; ++ hci_send_to_sock(hdev, skb); ++ kfree_skb(skb); ++} +diff -urN linux-2.4.18/net/bluetooth/hci_sock.c linux-2.4.18-mh9/net/bluetooth/hci_sock.c +--- linux-2.4.18/net/bluetooth/hci_sock.c Fri Sep 7 18:28:38 2001 ++++ linux-2.4.18-mh9/net/bluetooth/hci_sock.c Mon Aug 25 18:38:12 2003 +@@ -25,7 +25,7 @@ + /* + * BlueZ HCI socket layer. + * +- * $Id$ ++ * $Id$ + */ + + #include <linux/config.h> +@@ -49,45 +49,54 @@ + + #include <asm/system.h> + #include <asm/uaccess.h> ++#include <asm/unaligned.h> + + #include <net/bluetooth/bluetooth.h> +-#include <net/bluetooth/bluez.h> + #include <net/bluetooth/hci_core.h> + + #ifndef HCI_SOCK_DEBUG +-#undef DBG +-#define DBG( A... ) ++#undef BT_DBG ++#define BT_DBG( A... ) + #endif + +-/* HCI socket interface */ ++/* ----- HCI socket interface ----- */ ++ ++/* Security filter */ ++static struct hci_sec_filter hci_sec_filter = { ++ /* Packet types */ ++ 0x10, ++ /* Events */ ++ { 0xd9fe, 0x0 }, ++ /* Commands */ ++ { ++ { 0x0 }, ++ /* OGF_LINK_CTL */ ++ { 0x2a000002, 0x0, 0x0, 0x0 }, ++ /* OGF_LINK_POLICY */ ++ { 0x1200, 0x0, 0x0, 0x0 }, ++ /* OGF_HOST_CTL */ ++ { 0x80100000, 0x202a, 0x0, 0x0 }, ++ /* OGF_INFO_PARAM */ ++ { 0x22a, 0x0, 0x0, 0x0 }, ++ /* OGF_STATUS_PARAM */ ++ { 0x2e, 0x0, 0x0, 0x0 } ++ } ++}; + + static struct bluez_sock_list hci_sk_list = { + lock: RW_LOCK_UNLOCKED + }; + +-static struct sock *hci_sock_lookup(struct hci_dev *hdev) +-{ +- struct sock *sk; +- +- read_lock(&hci_sk_list.lock); +- for (sk = hci_sk_list.head; sk; sk = sk->next) { +- if (hci_pi(sk)->hdev == hdev) +- break; +- } +- read_unlock(&hci_sk_list.lock); +- return sk; +-} +- + /* Send frame to RAW socket */ + void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) + { + struct sock * sk; + +- DBG("hdev %p len %d", hdev, skb->len); ++ BT_DBG("hdev %p len %d", hdev, skb->len); + + read_lock(&hci_sk_list.lock); + for (sk = hci_sk_list.head; sk; sk = sk->next) { +- struct hci_filter *flt; ++ struct hci_filter *flt; + struct sk_buff *nskb; + + if (sk->state != BT_BOUND || hci_pi(sk)->hdev != hdev) +@@ -100,13 +109,19 @@ + /* Apply filter */ + flt = &hci_pi(sk)->filter; + +- if (!test_bit(skb->pkt_type, &flt->type_mask)) ++ if (!hci_test_bit((skb->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask)) + continue; + + if (skb->pkt_type == HCI_EVENT_PKT) { +- register int evt = (*(__u8 *)skb->data & 63); ++ register int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS); ++ ++ if (!hci_test_bit(evt, &flt->event_mask)) ++ continue; + +- if (!test_bit(evt, &flt->event_mask)) ++ if (flt->opcode && ((evt == EVT_CMD_COMPLETE && ++ flt->opcode != *(__u16 *)(skb->data + 3)) || ++ (evt == EVT_CMD_STATUS && ++ flt->opcode != *(__u16 *)(skb->data + 4)))) + continue; + } + +@@ -116,8 +131,8 @@ + /* Put type byte before the data */ + memcpy(skb_push(nskb, 1), &nskb->pkt_type, 1); + +- skb_queue_tail(&sk->receive_queue, nskb); +- sk->data_ready(sk, nskb->len); ++ if (sock_queue_rcv_skb(sk, nskb)) ++ kfree_skb(nskb); + } + read_unlock(&hci_sk_list.lock); + } +@@ -127,7 +142,7 @@ + struct sock *sk = sock->sk; + struct hci_dev *hdev = hci_pi(sk)->hdev; + +- DBG("sock %p sk %p", sock, sk); ++ BT_DBG("sock %p sk %p", sock, sk); + + if (!sk) + return 0; +@@ -135,9 +150,7 @@ + bluez_sock_unlink(&hci_sk_list, sk); + + if (hdev) { +- if (!hci_sock_lookup(hdev)) +- hdev->flags &= ~HCI_SOCK; +- ++ atomic_dec(&hdev->promisc); + hci_dev_put(hdev); + } + +@@ -149,24 +162,55 @@ + sock_put(sk); + + MOD_DEC_USE_COUNT; +- + return 0; + } + +-static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ++/* Ioctls that require bound socket */ ++static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg) + { +- struct sock *sk = sock->sk; + struct hci_dev *hdev = hci_pi(sk)->hdev; +- __u32 mode; + +- DBG("cmd %x arg %lx", cmd, arg); ++ if (!hdev) ++ return -EBADFD; + + switch (cmd) { +- case HCIGETINFO: +- return hci_dev_info(arg); ++ case HCISETRAW: ++ if (!capable(CAP_NET_ADMIN)) ++ return -EACCES; + ++ if (arg) ++ set_bit(HCI_RAW, &hdev->flags); ++ else ++ clear_bit(HCI_RAW, &hdev->flags); ++ ++ return 0; ++ ++ case HCIGETCONNINFO: ++ return hci_get_conn_info(hdev, arg); ++ ++ default: ++ if (hdev->ioctl) ++ return hdev->ioctl(hdev, cmd, arg); ++ return -EINVAL; ++ } ++} ++ ++static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ++{ ++ struct sock *sk = sock->sk; ++ int err; ++ ++ BT_DBG("cmd %x arg %lx", cmd, arg); ++ ++ switch (cmd) { + case HCIGETDEVLIST: +- return hci_dev_list(arg); ++ return hci_get_dev_list(arg); ++ ++ case HCIGETDEVINFO: ++ return hci_get_dev_info(arg); ++ ++ case HCIGETCONNLIST: ++ return hci_get_conn_list(arg); + + case HCIDEVUP: + if (!capable(CAP_NET_ADMIN)) +@@ -183,48 +227,31 @@ + return -EACCES; + return hci_dev_reset(arg); + +- case HCIRESETSTAT: ++ case HCIDEVRESTAT: + if (!capable(CAP_NET_ADMIN)) + return -EACCES; + return hci_dev_reset_stat(arg); + + case HCISETSCAN: +- if (!capable(CAP_NET_ADMIN)) +- return -EACCES; +- return hci_dev_setscan(arg); +- + case HCISETAUTH: +- if (!capable(CAP_NET_ADMIN)) +- return -EACCES; +- return hci_dev_setauth(arg); +- +- case HCISETRAW: +- if (!capable(CAP_NET_ADMIN)) +- return -EACCES; +- +- if (!hdev) +- return -EBADFD; +- +- if (arg) +- mode = HCI_RAW; +- else +- mode = HCI_NORMAL; +- +- return hci_dev_setmode(hdev, mode); +- ++ case HCISETENCRYPT: + case HCISETPTYPE: ++ case HCISETLINKPOL: ++ case HCISETLINKMODE: ++ case HCISETACLMTU: ++ case HCISETSCOMTU: + if (!capable(CAP_NET_ADMIN)) + return -EACCES; +- return hci_dev_setptype(arg); ++ return hci_dev_cmd(cmd, arg); + + case HCIINQUIRY: + return hci_inquiry(arg); + +- case HCIGETCONNLIST: +- return hci_conn_list(arg); +- + default: +- return -EINVAL; ++ lock_sock(sk); ++ err = hci_sock_bound_ioctl(sk, cmd, arg); ++ release_sock(sk); ++ return err; + }; + } + +@@ -233,28 +260,35 @@ + struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr; + struct sock *sk = sock->sk; + struct hci_dev *hdev = NULL; ++ int err = 0; + +- DBG("sock %p sk %p", sock, sk); ++ BT_DBG("sock %p sk %p", sock, sk); + + if (!haddr || haddr->hci_family != AF_BLUETOOTH) + return -EINVAL; + ++ lock_sock(sk); ++ + if (hci_pi(sk)->hdev) { +- /* Already bound */ +- return 0; ++ err = -EALREADY; ++ goto done; + } + + if (haddr->hci_dev != HCI_DEV_NONE) { +- if (!(hdev = hci_dev_get(haddr->hci_dev))) +- return -ENODEV; ++ if (!(hdev = hci_dev_get(haddr->hci_dev))) { ++ err = -ENODEV; ++ goto done; ++ } + +- hdev->flags |= HCI_SOCK; ++ atomic_inc(&hdev->promisc); + } + + hci_pi(sk)->hdev = hdev; + sk->state = BT_BOUND; + +- return 0; ++done: ++ release_sock(sk); ++ return err; + } + + static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer) +@@ -262,73 +296,44 @@ + struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr; + struct sock *sk = sock->sk; + +- DBG("sock %p sk %p", sock, sk); ++ BT_DBG("sock %p sk %p", sock, sk); ++ ++ lock_sock(sk); + + *addr_len = sizeof(*haddr); + haddr->hci_family = AF_BLUETOOTH; + haddr->hci_dev = hci_pi(sk)->hdev->id; + ++ release_sock(sk); + return 0; + } + +-static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, +- struct scm_cookie *scm) +-{ +- struct sock *sk = sock->sk; +- struct hci_dev *hdev = hci_pi(sk)->hdev; +- struct sk_buff *skb; +- int err; +- +- DBG("sock %p sk %p", sock, sk); +- +- if (msg->msg_flags & MSG_OOB) +- return -EOPNOTSUPP; +- +- if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE)) +- return -EINVAL; +- +- if (!hdev) +- return -EBADFD; +- +- if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err))) +- return err; +- +- if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { +- kfree_skb(skb); +- return -EFAULT; +- } +- +- skb->dev = (void *) hdev; +- skb->pkt_type = *((unsigned char *) skb->data); +- skb_pull(skb, 1); +- +- /* Send frame to HCI core */ +- hci_send_raw(skb); +- +- return len; +-} +- + static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) + { + __u32 mask = hci_pi(sk)->cmsg_mask; + + if (mask & HCI_CMSG_DIR) + put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(int), &bluez_cb(skb)->incomming); ++ ++ if (mask & HCI_CMSG_TSTAMP) ++ put_cmsg(msg, SOL_HCI, HCI_CMSG_TSTAMP, sizeof(skb->stamp), &skb->stamp); + } + +-static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, +- int flags, struct scm_cookie *scm) ++static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm) + { + int noblock = flags & MSG_DONTWAIT; + struct sock *sk = sock->sk; + struct sk_buff *skb; + int copied, err; + +- DBG("sock %p sk %p", sock, sk); ++ BT_DBG("sock %p, sk %p", sock, sk); + +- if (flags & (MSG_OOB | MSG_PEEK)) ++ if (flags & (MSG_OOB)) + return -EOPNOTSUPP; + ++ if (sk->state == BT_CLOSED) ++ return 0; ++ + if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) + return err; + +@@ -343,28 +348,107 @@ + skb->h.raw = skb->data; + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); + +- if (hci_pi(sk)->cmsg_mask) +- hci_sock_cmsg(sk, msg, skb); +- ++ hci_sock_cmsg(sk, msg, skb); ++ + skb_free_datagram(sk, skb); + + return err ? : copied; + } + ++static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, ++ struct scm_cookie *scm) ++{ ++ struct sock *sk = sock->sk; ++ struct hci_dev *hdev; ++ struct sk_buff *skb; ++ int err; ++ ++ BT_DBG("sock %p sk %p", sock, sk); ++ ++ if (msg->msg_flags & MSG_OOB) ++ return -EOPNOTSUPP; ++ ++ if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE)) ++ return -EINVAL; ++ ++ if (len < 4) ++ return -EINVAL; ++ ++ lock_sock(sk); ++ ++ if (!(hdev = hci_pi(sk)->hdev)) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err))) ++ goto done; ++ ++ if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { ++ err = -EFAULT; ++ goto drop; ++ } ++ ++ skb->pkt_type = *((unsigned char *) skb->data); ++ skb_pull(skb, 1); ++ skb->dev = (void *) hdev; ++ ++ if (skb->pkt_type == HCI_COMMAND_PKT) { ++ u16 opcode = __le16_to_cpu(get_unaligned((u16 *)skb->data)); ++ u16 ogf = cmd_opcode_ogf(opcode); ++ u16 ocf = cmd_opcode_ocf(opcode); ++ ++ if (((ogf > HCI_SFLT_MAX_OGF) || ++ !hci_test_bit(ocf & HCI_FLT_OCF_BITS, &hci_sec_filter.ocf_mask[ogf])) && ++ !capable(CAP_NET_RAW)) { ++ err = -EPERM; ++ goto drop; ++ } ++ ++ if (test_bit(HCI_RAW, &hdev->flags) || (ogf == OGF_VENDOR_CMD)) { ++ skb_queue_tail(&hdev->raw_q, skb); ++ hci_sched_tx(hdev); ++ } else { ++ skb_queue_tail(&hdev->cmd_q, skb); ++ hci_sched_cmd(hdev); ++ } ++ } else { ++ if (!capable(CAP_NET_RAW)) { ++ err = -EPERM; ++ goto drop; ++ } ++ ++ skb_queue_tail(&hdev->raw_q, skb); ++ hci_sched_tx(hdev); ++ } ++ ++ err = len; ++ ++done: ++ release_sock(sk); ++ return err; ++ ++drop: ++ kfree_skb(skb); ++ goto done; ++} ++ + int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int len) + { + struct sock *sk = sock->sk; +- struct hci_filter flt; ++ struct hci_filter flt = { opcode: 0 }; + int err = 0, opt = 0; + +- DBG("sk %p, opt %d", sk, optname); ++ BT_DBG("sk %p, opt %d", sk, optname); + + lock_sock(sk); + + switch (optname) { + case HCI_DATA_DIR: +- if (get_user(opt, (int *)optval)) +- return -EFAULT; ++ if (get_user(opt, (int *)optval)) { ++ err = -EFAULT; ++ break; ++ } + + if (opt) + hci_pi(sk)->cmsg_mask |= HCI_CMSG_DIR; +@@ -372,12 +456,31 @@ + hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_DIR; + break; + ++ case HCI_TIME_STAMP: ++ if (get_user(opt, (int *)optval)) { ++ err = -EFAULT; ++ break; ++ } ++ ++ if (opt) ++ hci_pi(sk)->cmsg_mask |= HCI_CMSG_TSTAMP; ++ else ++ hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_TSTAMP; ++ break; ++ + case HCI_FILTER: + len = MIN(len, sizeof(struct hci_filter)); + if (copy_from_user(&flt, optval, len)) { + err = -EFAULT; + break; + } ++ ++ if (!capable(CAP_NET_RAW)) { ++ flt.type_mask &= hci_sec_filter.type_mask; ++ flt.event_mask[0] &= hci_sec_filter.event_mask[0]; ++ flt.event_mask[1] &= hci_sec_filter.event_mask[1]; ++ } ++ + memcpy(&hci_pi(sk)->filter, &flt, len); + break; + +@@ -409,6 +512,16 @@ + return -EFAULT; + break; + ++ case HCI_TIME_STAMP: ++ if (hci_pi(sk)->cmsg_mask & HCI_CMSG_TSTAMP) ++ opt = 1; ++ else ++ opt = 0; ++ ++ if (put_user(opt, optval)) ++ return -EFAULT; ++ break; ++ + case HCI_FILTER: + len = MIN(len, sizeof(struct hci_filter)); + if (copy_to_user(optval, &hci_pi(sk)->filter, len)) +@@ -446,7 +559,7 @@ + { + struct sock *sk; + +- DBG("sock %p", sock); ++ BT_DBG("sock %p", sock); + + if (sock->type != SOCK_RAW) + return -ESOCKTNOSUPPORT; +@@ -464,44 +577,31 @@ + sk->protocol = protocol; + sk->state = BT_OPEN; + +- /* Initialize filter */ +- hci_pi(sk)->filter.type_mask = (1<<HCI_EVENT_PKT); +- hci_pi(sk)->filter.event_mask[0] = ~0L; +- hci_pi(sk)->filter.event_mask[1] = ~0L; +- + bluez_sock_link(&hci_sk_list, sk); + + MOD_INC_USE_COUNT; +- + return 0; + } + + static int hci_sock_dev_event(struct notifier_block *this, unsigned long event, void *ptr) + { + struct hci_dev *hdev = (struct hci_dev *) ptr; +- struct sk_buff *skb; +- +- DBG("hdev %s event %ld", hdev->name, event); ++ evt_si_device sd; ++ ++ BT_DBG("hdev %s event %ld", hdev->name, event); + + /* Send event to sockets */ +- if ((skb = bluez_skb_alloc(HCI_EVENT_HDR_SIZE + EVT_HCI_DEV_EVENT_SIZE, GFP_ATOMIC))) { +- hci_event_hdr eh = { EVT_HCI_DEV_EVENT, EVT_HCI_DEV_EVENT_SIZE }; +- evt_hci_dev_event he = { event, hdev->id }; +- +- skb->pkt_type = HCI_EVENT_PKT; +- memcpy(skb_put(skb, HCI_EVENT_HDR_SIZE), &eh, HCI_EVENT_HDR_SIZE); +- memcpy(skb_put(skb, EVT_HCI_DEV_EVENT_SIZE), &he, EVT_HCI_DEV_EVENT_SIZE); +- +- hci_send_to_sock(NULL, skb); +- kfree_skb(skb); +- } +- ++ sd.event = event; ++ sd.dev_id = hdev->id; ++ hci_si_event(NULL, EVT_SI_DEVICE, EVT_SI_DEVICE_SIZE, &sd); ++ + if (event == HCI_DEV_UNREG) { + struct sock *sk; + + /* Detach sockets from device */ + read_lock(&hci_sk_list.lock); + for (sk = hci_sk_list.head; sk; sk = sk->next) { ++ bh_lock_sock(sk); + if (hci_pi(sk)->hdev == hdev) { + hci_pi(sk)->hdev = NULL; + sk->err = EPIPE; +@@ -510,6 +610,7 @@ + + hci_dev_put(hdev); + } ++ bh_unlock_sock(sk); + } + read_unlock(&hci_sk_list.lock); + } +@@ -529,21 +630,19 @@ + int hci_sock_init(void) + { + if (bluez_sock_register(BTPROTO_HCI, &hci_sock_family_ops)) { +- ERR("Can't register HCI socket"); ++ BT_ERR("Can't register HCI socket"); + return -EPROTO; + } + + hci_register_notifier(&hci_sock_nblock); +- + return 0; + } + + int hci_sock_cleanup(void) + { + if (bluez_sock_unregister(BTPROTO_HCI)) +- ERR("Can't unregister HCI socket"); ++ BT_ERR("Can't unregister HCI socket"); + + hci_unregister_notifier(&hci_sock_nblock); +- + return 0; + } +diff -urN linux-2.4.18/net/bluetooth/l2cap.c linux-2.4.18-mh9/net/bluetooth/l2cap.c +--- linux-2.4.18/net/bluetooth/l2cap.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/l2cap.c Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,2187 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * BlueZ L2CAP core and sockets. ++ * ++ * $Id$ ++ */ ++#define VERSION "2.3" ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/init.h> ++#include <linux/skbuff.h> ++#include <linux/interrupt.h> ++#include <linux/socket.h> ++#include <linux/skbuff.h> ++#include <linux/proc_fs.h> ++#include <linux/list.h> ++#include <net/sock.h> ++ ++#include <asm/system.h> ++#include <asm/uaccess.h> ++#include <asm/unaligned.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++#include <net/bluetooth/l2cap.h> ++ ++#ifndef L2CAP_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#endif ++ ++static struct proto_ops l2cap_sock_ops; ++ ++struct bluez_sock_list l2cap_sk_list = { ++ lock: RW_LOCK_UNLOCKED ++}; ++ ++static int l2cap_conn_del(struct hci_conn *conn, int err); ++ ++static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent); ++static void l2cap_chan_del(struct sock *sk, int err); ++static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len); ++ ++static void __l2cap_sock_close(struct sock *sk, int reason); ++static void l2cap_sock_close(struct sock *sk); ++static void l2cap_sock_kill(struct sock *sk); ++ ++static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data); ++static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data); ++ ++/* ----- L2CAP timers ------ */ ++static void l2cap_sock_timeout(unsigned long arg) ++{ ++ struct sock *sk = (struct sock *) arg; ++ ++ BT_DBG("sock %p state %d", sk, sk->state); ++ ++ bh_lock_sock(sk); ++ __l2cap_sock_close(sk, ETIMEDOUT); ++ bh_unlock_sock(sk); ++ ++ l2cap_sock_kill(sk); ++ sock_put(sk); ++} ++ ++static void l2cap_sock_set_timer(struct sock *sk, long timeout) ++{ ++ BT_DBG("sk %p state %d timeout %ld", sk, sk->state, timeout); ++ ++ if (!mod_timer(&sk->timer, jiffies + timeout)) ++ sock_hold(sk); ++} ++ ++static void l2cap_sock_clear_timer(struct sock *sk) ++{ ++ BT_DBG("sock %p state %d", sk, sk->state); ++ ++ if (timer_pending(&sk->timer) && del_timer(&sk->timer)) ++ __sock_put(sk); ++} ++ ++static void l2cap_sock_init_timer(struct sock *sk) ++{ ++ init_timer(&sk->timer); ++ sk->timer.function = l2cap_sock_timeout; ++ sk->timer.data = (unsigned long)sk; ++} ++ ++/* -------- L2CAP connections --------- */ ++static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, __u8 status) ++{ ++ struct l2cap_conn *conn; ++ ++ if ((conn = hcon->l2cap_data)) ++ return conn; ++ ++ if (status) ++ return conn; ++ ++ if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_ATOMIC))) ++ return NULL; ++ memset(conn, 0, sizeof(struct l2cap_conn)); ++ ++ hcon->l2cap_data = conn; ++ conn->hcon = hcon; ++ ++ conn->mtu = hcon->hdev->acl_mtu; ++ conn->src = &hcon->hdev->bdaddr; ++ conn->dst = &hcon->dst; ++ ++ spin_lock_init(&conn->lock); ++ conn->chan_list.lock = RW_LOCK_UNLOCKED; ++ ++ BT_DBG("hcon %p conn %p", hcon, conn); ++ ++ MOD_INC_USE_COUNT; ++ return conn; ++} ++ ++static int l2cap_conn_del(struct hci_conn *hcon, int err) ++{ ++ struct l2cap_conn *conn; ++ struct sock *sk; ++ ++ if (!(conn = hcon->l2cap_data)) ++ return 0; ++ ++ BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); ++ ++ if (conn->rx_skb) ++ kfree_skb(conn->rx_skb); ++ ++ /* Kill channels */ ++ while ((sk = conn->chan_list.head)) { ++ bh_lock_sock(sk); ++ l2cap_chan_del(sk, err); ++ bh_unlock_sock(sk); ++ l2cap_sock_kill(sk); ++ } ++ ++ hcon->l2cap_data = NULL; ++ kfree(conn); ++ ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++/* -------- Socket interface ---------- */ ++static struct sock *__l2cap_get_sock_by_addr(__u16 psm, bdaddr_t *src) ++{ ++ struct sock *sk; ++ for (sk = l2cap_sk_list.head; sk; sk = sk->next) { ++ if (sk->sport == psm && !bacmp(&bluez_pi(sk)->src, src)) ++ break; ++ } ++ return sk; ++} ++ ++/* Find socket with psm and source bdaddr. ++ * Returns closest match. ++ */ ++static struct sock *__l2cap_get_sock_by_psm(int state, __u16 psm, bdaddr_t *src) ++{ ++ struct sock *sk, *sk1 = NULL; ++ ++ for (sk = l2cap_sk_list.head; sk; sk = sk->next) { ++ if (state && sk->state != state) ++ continue; ++ ++ if (l2cap_pi(sk)->psm == psm) { ++ /* Exact match. */ ++ if (!bacmp(&bluez_pi(sk)->src, src)) ++ break; ++ ++ /* Closest match */ ++ if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY)) ++ sk1 = sk; ++ } ++ } ++ return sk ? sk : sk1; ++} ++ ++/* Find socket with given address (psm, src). ++ * Returns locked socket */ ++static inline struct sock *l2cap_get_sock_by_psm(int state, __u16 psm, bdaddr_t *src) ++{ ++ struct sock *s; ++ read_lock(&l2cap_sk_list.lock); ++ s = __l2cap_get_sock_by_psm(state, psm, src); ++ if (s) bh_lock_sock(s); ++ read_unlock(&l2cap_sk_list.lock); ++ return s; ++} ++ ++static void l2cap_sock_destruct(struct sock *sk) ++{ ++ BT_DBG("sk %p", sk); ++ ++ skb_queue_purge(&sk->receive_queue); ++ skb_queue_purge(&sk->write_queue); ++ ++ MOD_DEC_USE_COUNT; ++} ++ ++static void l2cap_sock_cleanup_listen(struct sock *parent) ++{ ++ struct sock *sk; ++ ++ BT_DBG("parent %p", parent); ++ ++ /* Close not yet accepted channels */ ++ while ((sk = bluez_accept_dequeue(parent, NULL))) ++ l2cap_sock_close(sk); ++ ++ parent->state = BT_CLOSED; ++ parent->zapped = 1; ++} ++ ++/* Kill socket (only if zapped and orphan) ++ * Must be called on unlocked socket. ++ */ ++static void l2cap_sock_kill(struct sock *sk) ++{ ++ if (!sk->zapped || sk->socket) ++ return; ++ ++ BT_DBG("sk %p state %d", sk, sk->state); ++ ++ /* Kill poor orphan */ ++ bluez_sock_unlink(&l2cap_sk_list, sk); ++ sk->dead = 1; ++ sock_put(sk); ++} ++ ++/* Close socket. ++ */ ++static void __l2cap_sock_close(struct sock *sk, int reason) ++{ ++ BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket); ++ ++ switch (sk->state) { ++ case BT_LISTEN: ++ l2cap_sock_cleanup_listen(sk); ++ break; ++ ++ case BT_CONNECTED: ++ case BT_CONFIG: ++ case BT_CONNECT2: ++ if (sk->type == SOCK_SEQPACKET) { ++ struct l2cap_conn *conn = l2cap_pi(sk)->conn; ++ l2cap_disconn_req req; ++ ++ sk->state = BT_DISCONN; ++ l2cap_sock_set_timer(sk, sk->sndtimeo); ++ ++ req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid); ++ req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); ++ l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req); ++ } else { ++ l2cap_chan_del(sk, reason); ++ } ++ break; ++ ++ case BT_CONNECT: ++ case BT_DISCONN: ++ l2cap_chan_del(sk, reason); ++ break; ++ ++ default: ++ sk->zapped = 1; ++ break; ++ }; ++} ++ ++/* Must be called on unlocked socket. */ ++static void l2cap_sock_close(struct sock *sk) ++{ ++ l2cap_sock_clear_timer(sk); ++ lock_sock(sk); ++ __l2cap_sock_close(sk, ECONNRESET); ++ release_sock(sk); ++ l2cap_sock_kill(sk); ++} ++ ++static void l2cap_sock_init(struct sock *sk, struct sock *parent) ++{ ++ struct l2cap_pinfo *pi = l2cap_pi(sk); ++ ++ BT_DBG("sk %p", sk); ++ ++ if (parent) { ++ sk->type = parent->type; ++ pi->imtu = l2cap_pi(parent)->imtu; ++ pi->omtu = l2cap_pi(parent)->omtu; ++ pi->link_mode = l2cap_pi(parent)->link_mode; ++ } else { ++ pi->imtu = L2CAP_DEFAULT_MTU; ++ pi->omtu = 0; ++ pi->link_mode = 0; ++ } ++ ++ /* Default config options */ ++ pi->conf_mtu = L2CAP_DEFAULT_MTU; ++ pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; ++} ++ ++static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio) ++{ ++ struct sock *sk; ++ ++ if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1))) ++ return NULL; ++ ++ bluez_sock_init(sock, sk); ++ ++ sk->zapped = 0; ++ ++ sk->destruct = l2cap_sock_destruct; ++ sk->sndtimeo = L2CAP_CONN_TIMEOUT; ++ ++ sk->protocol = proto; ++ sk->state = BT_OPEN; ++ ++ l2cap_sock_init_timer(sk); ++ ++ bluez_sock_link(&l2cap_sk_list, sk); ++ ++ MOD_INC_USE_COUNT; ++ return sk; ++} ++ ++static int l2cap_sock_create(struct socket *sock, int protocol) ++{ ++ struct sock *sk; ++ ++ BT_DBG("sock %p", sock); ++ ++ sock->state = SS_UNCONNECTED; ++ ++ if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_DGRAM && sock->type != SOCK_RAW) ++ return -ESOCKTNOSUPPORT; ++ ++ if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW)) ++ return -EPERM; ++ ++ sock->ops = &l2cap_sock_ops; ++ ++ if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL))) ++ return -ENOMEM; ++ ++ l2cap_sock_init(sk, NULL); ++ return 0; ++} ++ ++static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) ++{ ++ struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm); ++ ++ if (!addr || addr->sa_family != AF_BLUETOOTH) ++ return -EINVAL; ++ ++ lock_sock(sk); ++ ++ if (sk->state != BT_OPEN) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ write_lock_bh(&l2cap_sk_list.lock); ++ if (la->l2_psm && __l2cap_get_sock_by_addr(la->l2_psm, &la->l2_bdaddr)) { ++ err = -EADDRINUSE; ++ } else { ++ /* Save source address */ ++ bacpy(&bluez_pi(sk)->src, &la->l2_bdaddr); ++ l2cap_pi(sk)->psm = la->l2_psm; ++ sk->sport = la->l2_psm; ++ sk->state = BT_BOUND; ++ } ++ write_unlock_bh(&l2cap_sk_list.lock); ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++static int l2cap_do_connect(struct sock *sk) ++{ ++ bdaddr_t *src = &bluez_pi(sk)->src; ++ bdaddr_t *dst = &bluez_pi(sk)->dst; ++ struct l2cap_conn *conn; ++ struct hci_conn *hcon; ++ struct hci_dev *hdev; ++ int err = 0; ++ ++ BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm); ++ ++ if (!(hdev = hci_get_route(dst, src))) ++ return -EHOSTUNREACH; ++ ++ hci_dev_lock_bh(hdev); ++ ++ err = -ENOMEM; ++ ++ hcon = hci_connect(hdev, ACL_LINK, dst); ++ if (!hcon) ++ goto done; ++ ++ conn = l2cap_conn_add(hcon, 0); ++ if (!conn) { ++ hci_conn_put(hcon); ++ goto done; ++ } ++ ++ err = 0; ++ ++ /* Update source addr of the socket */ ++ bacpy(src, conn->src); ++ ++ l2cap_chan_add(conn, sk, NULL); ++ ++ sk->state = BT_CONNECT; ++ l2cap_sock_set_timer(sk, sk->sndtimeo); ++ ++ if (hcon->state == BT_CONNECTED) { ++ if (sk->type == SOCK_SEQPACKET) { ++ l2cap_conn_req req; ++ req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); ++ req.psm = l2cap_pi(sk)->psm; ++ l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req); ++ } else { ++ l2cap_sock_clear_timer(sk); ++ sk->state = BT_CONNECTED; ++ } ++ } ++ ++done: ++ hci_dev_unlock_bh(hdev); ++ hci_dev_put(hdev); ++ return err; ++} ++ ++static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) ++{ ++ struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ lock_sock(sk); ++ ++ BT_DBG("sk %p", sk); ++ ++ if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) { ++ err = -EINVAL; ++ goto done; ++ } ++ ++ if (sk->type == SOCK_SEQPACKET && !la->l2_psm) { ++ err = -EINVAL; ++ goto done; ++ } ++ ++ switch(sk->state) { ++ case BT_CONNECT: ++ case BT_CONNECT2: ++ case BT_CONFIG: ++ /* Already connecting */ ++ goto wait; ++ ++ case BT_CONNECTED: ++ /* Already connected */ ++ goto done; ++ ++ case BT_OPEN: ++ case BT_BOUND: ++ /* Can connect */ ++ break; ++ ++ default: ++ err = -EBADFD; ++ goto done; ++ } ++ ++ /* Set destination address and psm */ ++ bacpy(&bluez_pi(sk)->dst, &la->l2_bdaddr); ++ l2cap_pi(sk)->psm = la->l2_psm; ++ ++ if ((err = l2cap_do_connect(sk))) ++ goto done; ++ ++wait: ++ err = bluez_sock_wait_state(sk, BT_CONNECTED, ++ sock_sndtimeo(sk, flags & O_NONBLOCK)); ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++int l2cap_sock_listen(struct socket *sock, int backlog) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sk %p backlog %d", sk, backlog); ++ ++ lock_sock(sk); ++ ++ if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ if (!l2cap_pi(sk)->psm) { ++ err = -EINVAL; ++ goto done; ++ } ++ ++ sk->max_ack_backlog = backlog; ++ sk->ack_backlog = 0; ++ sk->state = BT_LISTEN; ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ struct sock *sk = sock->sk, *nsk; ++ long timeo; ++ int err = 0; ++ ++ lock_sock(sk); ++ ++ if (sk->state != BT_LISTEN) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); ++ ++ BT_DBG("sk %p timeo %ld", sk, timeo); ++ ++ /* Wait for an incoming connection. (wake-one). */ ++ add_wait_queue_exclusive(sk->sleep, &wait); ++ while (!(nsk = bluez_accept_dequeue(sk, newsock))) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ if (!timeo) { ++ err = -EAGAIN; ++ break; ++ } ++ ++ release_sock(sk); ++ timeo = schedule_timeout(timeo); ++ lock_sock(sk); ++ ++ if (sk->state != BT_LISTEN) { ++ err = -EBADFD; ++ break; ++ } ++ ++ if (signal_pending(current)) { ++ err = sock_intr_errno(timeo); ++ break; ++ } ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(sk->sleep, &wait); ++ ++ if (err) ++ goto done; ++ ++ newsock->state = SS_CONNECTED; ++ ++ BT_DBG("new socket %p", nsk); ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer) ++{ ++ struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; ++ struct sock *sk = sock->sk; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ addr->sa_family = AF_BLUETOOTH; ++ *len = sizeof(struct sockaddr_l2); ++ ++ if (peer) ++ bacpy(&la->l2_bdaddr, &bluez_pi(sk)->dst); ++ else ++ bacpy(&la->l2_bdaddr, &bluez_pi(sk)->src); ++ ++ la->l2_psm = l2cap_pi(sk)->psm; ++ return 0; ++} ++ ++static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ if (sk->err) ++ return sock_error(sk); ++ ++ if (msg->msg_flags & MSG_OOB) ++ return -EOPNOTSUPP; ++ ++ /* Check outgoing MTU */ ++ if (len > l2cap_pi(sk)->omtu) ++ return -EINVAL; ++ ++ lock_sock(sk); ++ ++ if (sk->state == BT_CONNECTED) ++ err = l2cap_chan_send(sk, msg, len); ++ else ++ err = -ENOTCONN; ++ ++ release_sock(sk); ++ return err; ++} ++ ++static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) ++{ ++ struct sock *sk = sock->sk; ++ struct l2cap_options opts; ++ int err = 0, len; ++ __u32 opt; ++ ++ BT_DBG("sk %p", sk); ++ ++ lock_sock(sk); ++ ++ switch (optname) { ++ case L2CAP_OPTIONS: ++ len = MIN(sizeof(opts), optlen); ++ if (copy_from_user((char *)&opts, optval, len)) { ++ err = -EFAULT; ++ break; ++ } ++ l2cap_pi(sk)->imtu = opts.imtu; ++ l2cap_pi(sk)->omtu = opts.omtu; ++ break; ++ ++ case L2CAP_LM: ++ if (get_user(opt, (__u32 *)optval)) { ++ err = -EFAULT; ++ break; ++ } ++ ++ l2cap_pi(sk)->link_mode = opt; ++ break; ++ ++ default: ++ err = -ENOPROTOOPT; ++ break; ++ } ++ ++ release_sock(sk); ++ return err; ++} ++ ++static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) ++{ ++ struct sock *sk = sock->sk; ++ struct l2cap_options opts; ++ struct l2cap_conninfo cinfo; ++ int len, err = 0; ++ ++ if (get_user(len, optlen)) ++ return -EFAULT; ++ ++ lock_sock(sk); ++ ++ switch (optname) { ++ case L2CAP_OPTIONS: ++ opts.imtu = l2cap_pi(sk)->imtu; ++ opts.omtu = l2cap_pi(sk)->omtu; ++ opts.flush_to = l2cap_pi(sk)->flush_to; ++ ++ len = MIN(len, sizeof(opts)); ++ if (copy_to_user(optval, (char *)&opts, len)) ++ err = -EFAULT; ++ ++ break; ++ ++ case L2CAP_LM: ++ if (put_user(l2cap_pi(sk)->link_mode, (__u32 *)optval)) ++ err = -EFAULT; ++ break; ++ ++ case L2CAP_CONNINFO: ++ if (sk->state != BT_CONNECTED) { ++ err = -ENOTCONN; ++ break; ++ } ++ ++ cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle; ++ ++ len = MIN(len, sizeof(cinfo)); ++ if (copy_to_user(optval, (char *)&cinfo, len)) ++ err = -EFAULT; ++ ++ break; ++ ++ default: ++ err = -ENOPROTOOPT; ++ break; ++ } ++ ++ release_sock(sk); ++ return err; ++} ++ ++static int l2cap_sock_shutdown(struct socket *sock, int how) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ if (!sk) return 0; ++ ++ lock_sock(sk); ++ if (!sk->shutdown) { ++ sk->shutdown = SHUTDOWN_MASK; ++ l2cap_sock_clear_timer(sk); ++ __l2cap_sock_close(sk, 0); ++ ++ if (sk->linger) ++ err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime); ++ } ++ release_sock(sk); ++ return err; ++} ++ ++static int l2cap_sock_release(struct socket *sock) ++{ ++ struct sock *sk = sock->sk; ++ int err; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ if (!sk) return 0; ++ ++ err = l2cap_sock_shutdown(sock, 2); ++ ++ sock_orphan(sk); ++ l2cap_sock_kill(sk); ++ return err; ++} ++ ++/* --------- L2CAP channels --------- */ ++static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid) ++{ ++ struct sock *s; ++ for (s = l->head; s; s = l2cap_pi(s)->next_c) { ++ if (l2cap_pi(s)->dcid == cid) ++ break; ++ } ++ return s; ++} ++ ++static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid) ++{ ++ struct sock *s; ++ for (s = l->head; s; s = l2cap_pi(s)->next_c) { ++ if (l2cap_pi(s)->scid == cid) ++ break; ++ } ++ return s; ++} ++ ++/* Find channel with given SCID. ++ * Returns locked socket */ ++static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid) ++{ ++ struct sock *s; ++ read_lock(&l->lock); ++ s = __l2cap_get_chan_by_scid(l, cid); ++ if (s) bh_lock_sock(s); ++ read_unlock(&l->lock); ++ return s; ++} ++ ++static __u16 l2cap_alloc_cid(struct l2cap_chan_list *l) ++{ ++ __u16 cid = 0x0040; ++ ++ for (; cid < 0xffff; cid++) { ++ if(!__l2cap_get_chan_by_scid(l, cid)) ++ return cid; ++ } ++ ++ return 0; ++} ++ ++static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk) ++{ ++ sock_hold(sk); ++ ++ if (l->head) ++ l2cap_pi(l->head)->prev_c = sk; ++ ++ l2cap_pi(sk)->next_c = l->head; ++ l2cap_pi(sk)->prev_c = NULL; ++ l->head = sk; ++} ++ ++static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) ++{ ++ struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c; ++ ++ write_lock(&l->lock); ++ if (sk == l->head) ++ l->head = next; ++ ++ if (next) ++ l2cap_pi(next)->prev_c = prev; ++ if (prev) ++ l2cap_pi(prev)->next_c = next; ++ write_unlock(&l->lock); ++ ++ __sock_put(sk); ++} ++ ++static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) ++{ ++ struct l2cap_chan_list *l = &conn->chan_list; ++ ++ BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); ++ ++ l2cap_pi(sk)->conn = conn; ++ ++ if (sk->type == SOCK_SEQPACKET) { ++ /* Alloc CID for connection-oriented socket */ ++ l2cap_pi(sk)->scid = l2cap_alloc_cid(l); ++ } else if (sk->type == SOCK_DGRAM) { ++ /* Connectionless socket */ ++ l2cap_pi(sk)->scid = 0x0002; ++ l2cap_pi(sk)->dcid = 0x0002; ++ l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; ++ } else { ++ /* Raw socket can send/recv signalling messages only */ ++ l2cap_pi(sk)->scid = 0x0001; ++ l2cap_pi(sk)->dcid = 0x0001; ++ l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; ++ } ++ ++ __l2cap_chan_link(l, sk); ++ ++ if (parent) ++ bluez_accept_enqueue(parent, sk); ++} ++ ++static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) ++{ ++ struct l2cap_chan_list *l = &conn->chan_list; ++ write_lock(&l->lock); ++ __l2cap_chan_add(conn, sk, parent); ++ write_unlock(&l->lock); ++} ++ ++/* Delete channel. ++ * Must be called on the locked socket. */ ++static void l2cap_chan_del(struct sock *sk, int err) ++{ ++ struct l2cap_conn *conn = l2cap_pi(sk)->conn; ++ struct sock *parent = bluez_pi(sk)->parent; ++ ++ l2cap_sock_clear_timer(sk); ++ ++ BT_DBG("sk %p, conn %p, err %d", sk, conn, err); ++ ++ if (conn) { ++ /* Unlink from channel list */ ++ l2cap_chan_unlink(&conn->chan_list, sk); ++ l2cap_pi(sk)->conn = NULL; ++ hci_conn_put(conn->hcon); ++ } ++ ++ sk->state = BT_CLOSED; ++ sk->zapped = 1; ++ ++ if (err) ++ sk->err = err; ++ ++ if (parent) ++ parent->data_ready(parent, 0); ++ else ++ sk->state_change(sk); ++} ++ ++static void l2cap_conn_ready(struct l2cap_conn *conn) ++{ ++ struct l2cap_chan_list *l = &conn->chan_list; ++ struct sock *sk; ++ ++ BT_DBG("conn %p", conn); ++ ++ read_lock(&l->lock); ++ ++ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { ++ bh_lock_sock(sk); ++ ++ if (sk->type != SOCK_SEQPACKET) { ++ l2cap_sock_clear_timer(sk); ++ sk->state = BT_CONNECTED; ++ sk->state_change(sk); ++ } else if (sk->state == BT_CONNECT) { ++ l2cap_conn_req req; ++ req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); ++ req.psm = l2cap_pi(sk)->psm; ++ l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req); ++ } ++ ++ bh_unlock_sock(sk); ++ } ++ ++ read_unlock(&l->lock); ++} ++ ++/* Notify sockets that we cannot guaranty reliability anymore */ ++static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) ++{ ++ struct l2cap_chan_list *l = &conn->chan_list; ++ struct sock *sk; ++ ++ BT_DBG("conn %p", conn); ++ ++ read_lock(&l->lock); ++ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { ++ if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE) ++ sk->err = err; ++ } ++ read_unlock(&l->lock); ++} ++ ++static void l2cap_chan_ready(struct sock *sk) ++{ ++ struct sock *parent = bluez_pi(sk)->parent; ++ ++ BT_DBG("sk %p, parent %p", sk, parent); ++ ++ l2cap_pi(sk)->conf_state = 0; ++ l2cap_sock_clear_timer(sk); ++ ++ if (!parent) { ++ /* Outgoing channel. ++ * Wake up socket sleeping on connect. ++ */ ++ sk->state = BT_CONNECTED; ++ sk->state_change(sk); ++ } else { ++ /* Incomming channel. ++ * Wake up socket sleeping on accept. ++ */ ++ parent->data_ready(parent, 0); ++ } ++} ++ ++/* Copy frame to all raw sockets on that connection */ ++void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) ++{ ++ struct l2cap_chan_list *l = &conn->chan_list; ++ struct sk_buff *nskb; ++ struct sock * sk; ++ ++ BT_DBG("conn %p", conn); ++ ++ read_lock(&l->lock); ++ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { ++ if (sk->type != SOCK_RAW) ++ continue; ++ ++ /* Don't send frame to the socket it came from */ ++ if (skb->sk == sk) ++ continue; ++ ++ if (!(nskb = skb_clone(skb, GFP_ATOMIC))) ++ continue; ++ ++ if (sock_queue_rcv_skb(sk, nskb)) ++ kfree_skb(nskb); ++ } ++ read_unlock(&l->lock); ++} ++ ++static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len) ++{ ++ struct l2cap_conn *conn = l2cap_pi(sk)->conn; ++ struct sk_buff *skb, **frag; ++ int err, hlen, count, sent=0; ++ l2cap_hdr *lh; ++ ++ BT_DBG("sk %p len %d", sk, len); ++ ++ /* First fragment (with L2CAP header) */ ++ if (sk->type == SOCK_DGRAM) ++ hlen = L2CAP_HDR_SIZE + 2; ++ else ++ hlen = L2CAP_HDR_SIZE; ++ ++ count = MIN(conn->mtu - hlen, len); ++ ++ skb = bluez_skb_send_alloc(sk, hlen + count, ++ msg->msg_flags & MSG_DONTWAIT, &err); ++ if (!skb) ++ return err; ++ ++ /* Create L2CAP header */ ++ lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); ++ lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid); ++ lh->len = __cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); ++ ++ if (sk->type == SOCK_DGRAM) ++ put_unaligned(l2cap_pi(sk)->psm, (__u16 *) skb_put(skb, 2)); ++ ++ if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) { ++ err = -EFAULT; ++ goto fail; ++ } ++ ++ sent += count; ++ len -= count; ++ ++ /* Continuation fragments (no L2CAP header) */ ++ frag = &skb_shinfo(skb)->frag_list; ++ while (len) { ++ count = MIN(conn->mtu, len); ++ ++ *frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err); ++ if (!*frag) ++ goto fail; ++ ++ if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) { ++ err = -EFAULT; ++ goto fail; ++ } ++ ++ sent += count; ++ len -= count; ++ ++ frag = &(*frag)->next; ++ } ++ ++ if ((err = hci_send_acl(conn->hcon, skb, 0)) < 0) ++ goto fail; ++ ++ return sent; ++ ++fail: ++ kfree_skb(skb); ++ return err; ++} ++ ++/* --------- L2CAP signalling commands --------- */ ++static inline __u8 l2cap_get_ident(struct l2cap_conn *conn) ++{ ++ __u8 id; ++ ++ /* Get next available identificator. ++ * 1 - 199 are used by kernel. ++ * 200 - 254 are used by utilities like l2ping, etc ++ */ ++ ++ spin_lock(&conn->lock); ++ ++ if (++conn->tx_ident > 199) ++ conn->tx_ident = 1; ++ ++ id = conn->tx_ident; ++ ++ spin_unlock(&conn->lock); ++ ++ return id; ++} ++ ++static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, ++ __u8 code, __u8 ident, __u16 dlen, void *data) ++{ ++ struct sk_buff *skb, **frag; ++ l2cap_cmd_hdr *cmd; ++ l2cap_hdr *lh; ++ int len, count; ++ ++ BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", conn, code, ident, dlen); ++ ++ len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen; ++ count = MIN(conn->mtu, len); ++ ++ skb = bluez_skb_alloc(count, GFP_ATOMIC); ++ if (!skb) ++ return NULL; ++ ++ lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); ++ lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen); ++ lh->cid = __cpu_to_le16(0x0001); ++ ++ cmd = (l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE); ++ cmd->code = code; ++ cmd->ident = ident; ++ cmd->len = __cpu_to_le16(dlen); ++ ++ if (dlen) { ++ count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE; ++ memcpy(skb_put(skb, count), data, count); ++ data += count; ++ } ++ ++ len -= skb->len; ++ ++ /* Continuation fragments (no L2CAP header) */ ++ frag = &skb_shinfo(skb)->frag_list; ++ while (len) { ++ count = MIN(conn->mtu, len); ++ ++ *frag = bluez_skb_alloc(count, GFP_ATOMIC); ++ if (!*frag) ++ goto fail; ++ ++ memcpy(skb_put(*frag, count), data, count); ++ ++ len -= count; ++ data += count; ++ ++ frag = &(*frag)->next; ++ } ++ ++ return skb; ++ ++fail: ++ kfree_skb(skb); ++ return NULL; ++} ++ ++static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data) ++{ ++ __u8 ident = l2cap_get_ident(conn); ++ struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data); ++ ++ BT_DBG("code 0x%2.2x", code); ++ ++ if (!skb) ++ return -ENOMEM; ++ return hci_send_acl(conn->hcon, skb, 0); ++} ++ ++static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data) ++{ ++ struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data); ++ ++ BT_DBG("code 0x%2.2x", code); ++ ++ if (!skb) ++ return -ENOMEM; ++ return hci_send_acl(conn->hcon, skb, 0); ++} ++ ++static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val) ++{ ++ l2cap_conf_opt *opt = *ptr; ++ int len; ++ ++ len = L2CAP_CONF_OPT_SIZE + opt->len; ++ *ptr += len; ++ ++ *type = opt->type; ++ *olen = opt->len; ++ ++ switch (opt->len) { ++ case 1: ++ *val = *((__u8 *) opt->val); ++ break; ++ ++ case 2: ++ *val = __le16_to_cpu(*((__u16 *)opt->val)); ++ break; ++ ++ case 4: ++ *val = __le32_to_cpu(*((__u32 *)opt->val)); ++ break; ++ ++ default: ++ *val = (unsigned long) opt->val; ++ break; ++ }; ++ ++ BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val); ++ return len; ++} ++ ++static inline void l2cap_parse_conf_req(struct sock *sk, void *data, int len) ++{ ++ int type, hint, olen; ++ unsigned long val; ++ void *ptr = data; ++ ++ BT_DBG("sk %p len %d", sk, len); ++ ++ while (len >= L2CAP_CONF_OPT_SIZE) { ++ len -= l2cap_get_conf_opt(&ptr, &type, &olen, &val); ++ ++ hint = type & 0x80; ++ type &= 0x7f; ++ ++ switch (type) { ++ case L2CAP_CONF_MTU: ++ l2cap_pi(sk)->conf_mtu = val; ++ break; ++ ++ case L2CAP_CONF_FLUSH_TO: ++ l2cap_pi(sk)->flush_to = val; ++ break; ++ ++ case L2CAP_CONF_QOS: ++ break; ++ ++ default: ++ if (hint) ++ break; ++ ++ /* FIXME: Reject unknown option */ ++ break; ++ }; ++ } ++} ++ ++static void l2cap_add_conf_opt(void **ptr, __u8 type, __u8 len, unsigned long val) ++{ ++ register l2cap_conf_opt *opt = *ptr; ++ ++ BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val); ++ ++ opt->type = type; ++ opt->len = len; ++ ++ switch (len) { ++ case 1: ++ *((__u8 *) opt->val) = val; ++ break; ++ ++ case 2: ++ *((__u16 *) opt->val) = __cpu_to_le16(val); ++ break; ++ ++ case 4: ++ *((__u32 *) opt->val) = __cpu_to_le32(val); ++ break; ++ ++ default: ++ memcpy(opt->val, (void *) val, len); ++ break; ++ }; ++ ++ *ptr += L2CAP_CONF_OPT_SIZE + len; ++} ++ ++static int l2cap_build_conf_req(struct sock *sk, void *data) ++{ ++ struct l2cap_pinfo *pi = l2cap_pi(sk); ++ l2cap_conf_req *req = (l2cap_conf_req *) data; ++ void *ptr = req->data; ++ ++ BT_DBG("sk %p", sk); ++ ++ if (pi->imtu != L2CAP_DEFAULT_MTU) ++ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu); ++ ++ /* FIXME. Need actual value of the flush timeout */ ++ //if (flush_to != L2CAP_DEFAULT_FLUSH_TO) ++ // l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to); ++ ++ req->dcid = __cpu_to_le16(pi->dcid); ++ req->flags = __cpu_to_le16(0); ++ ++ return ptr - data; ++} ++ ++static inline int l2cap_conf_output(struct sock *sk, void **ptr) ++{ ++ struct l2cap_pinfo *pi = l2cap_pi(sk); ++ int result = 0; ++ ++ /* Configure output options and let the other side know ++ * which ones we don't like. ++ */ ++ if (pi->conf_mtu < pi->omtu) { ++ l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, pi->omtu); ++ result = L2CAP_CONF_UNACCEPT; ++ } else { ++ pi->omtu = pi->conf_mtu; ++ } ++ ++ BT_DBG("sk %p result %d", sk, result); ++ return result; ++} ++ ++static int l2cap_build_conf_rsp(struct sock *sk, void *data, int *result) ++{ ++ l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data; ++ void *ptr = rsp->data; ++ u16 flags = 0; ++ ++ BT_DBG("sk %p complete %d", sk, result ? 1 : 0); ++ ++ if (result) ++ *result = l2cap_conf_output(sk, &ptr); ++ else ++ flags |= 0x0001; ++ ++ rsp->scid = __cpu_to_le16(l2cap_pi(sk)->dcid); ++ rsp->result = __cpu_to_le16(result ? *result : 0); ++ rsp->flags = __cpu_to_le16(flags); ++ ++ return ptr - data; ++} ++ ++static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) ++{ ++ struct l2cap_chan_list *list = &conn->chan_list; ++ l2cap_conn_req *req = (l2cap_conn_req *) data; ++ l2cap_conn_rsp rsp; ++ struct sock *sk, *parent; ++ int result = 0, status = 0; ++ ++ __u16 dcid = 0, scid = __le16_to_cpu(req->scid); ++ __u16 psm = req->psm; ++ ++ BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid); ++ ++ /* Check if we have socket listening on psm */ ++ parent = l2cap_get_sock_by_psm(BT_LISTEN, psm, conn->src); ++ if (!parent) { ++ result = L2CAP_CR_BAD_PSM; ++ goto sendresp; ++ } ++ ++ result = L2CAP_CR_NO_MEM; ++ ++ /* Check for backlog size */ ++ if (parent->ack_backlog > parent->max_ack_backlog) { ++ BT_DBG("backlog full %d", parent->ack_backlog); ++ goto response; ++ } ++ ++ sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC); ++ if (!sk) ++ goto response; ++ ++ write_lock(&list->lock); ++ ++ /* Check if we already have channel with that dcid */ ++ if (__l2cap_get_chan_by_dcid(list, scid)) { ++ write_unlock(&list->lock); ++ sk->zapped = 1; ++ l2cap_sock_kill(sk); ++ goto response; ++ } ++ ++ hci_conn_hold(conn->hcon); ++ ++ l2cap_sock_init(sk, parent); ++ bacpy(&bluez_pi(sk)->src, conn->src); ++ bacpy(&bluez_pi(sk)->dst, conn->dst); ++ l2cap_pi(sk)->psm = psm; ++ l2cap_pi(sk)->dcid = scid; ++ ++ __l2cap_chan_add(conn, sk, parent); ++ dcid = l2cap_pi(sk)->scid; ++ ++ l2cap_sock_set_timer(sk, sk->sndtimeo); ++ ++ /* Service level security */ ++ result = L2CAP_CR_PEND; ++ status = L2CAP_CS_AUTHEN_PEND; ++ sk->state = BT_CONNECT2; ++ l2cap_pi(sk)->ident = cmd->ident; ++ ++ if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) { ++ if (!hci_conn_encrypt(conn->hcon)) ++ goto done; ++ } else if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) { ++ if (!hci_conn_auth(conn->hcon)) ++ goto done; ++ } ++ ++ sk->state = BT_CONFIG; ++ result = status = 0; ++ ++done: ++ write_unlock(&list->lock); ++ ++response: ++ bh_unlock_sock(parent); ++ ++sendresp: ++ rsp.scid = __cpu_to_le16(scid); ++ rsp.dcid = __cpu_to_le16(dcid); ++ rsp.result = __cpu_to_le16(result); ++ rsp.status = __cpu_to_le16(status); ++ l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp); ++ return 0; ++} ++ ++static inline int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) ++{ ++ l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data; ++ __u16 scid, dcid, result, status; ++ struct sock *sk; ++ char req[128]; ++ ++ scid = __le16_to_cpu(rsp->scid); ++ dcid = __le16_to_cpu(rsp->dcid); ++ result = __le16_to_cpu(rsp->result); ++ status = __le16_to_cpu(rsp->status); ++ ++ BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); ++ ++ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) ++ return -ENOENT; ++ ++ switch (result) { ++ case L2CAP_CR_SUCCESS: ++ sk->state = BT_CONFIG; ++ l2cap_pi(sk)->dcid = dcid; ++ l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; ++ ++ l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req); ++ break; ++ ++ case L2CAP_CR_PEND: ++ break; ++ ++ default: ++ l2cap_chan_del(sk, ECONNREFUSED); ++ break; ++ } ++ ++ bh_unlock_sock(sk); ++ return 0; ++} ++ ++static inline int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) ++{ ++ l2cap_conf_req * req = (l2cap_conf_req *) data; ++ __u16 dcid, flags; ++ __u8 rsp[64]; ++ struct sock *sk; ++ int result; ++ ++ dcid = __le16_to_cpu(req->dcid); ++ flags = __le16_to_cpu(req->flags); ++ ++ BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags); ++ ++ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid))) ++ return -ENOENT; ++ ++ l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE); ++ ++ if (flags & 0x0001) { ++ /* Incomplete config. Send empty response. */ ++ l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp); ++ goto unlock; ++ } ++ ++ /* Complete config. */ ++ l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp); ++ ++ if (result) ++ goto unlock; ++ ++ /* Output config done */ ++ l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE; ++ ++ if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) { ++ sk->state = BT_CONNECTED; ++ l2cap_chan_ready(sk); ++ } else if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) { ++ char req[64]; ++ l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req); ++ } ++ ++unlock: ++ bh_unlock_sock(sk); ++ return 0; ++} ++ ++static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) ++{ ++ l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data; ++ __u16 scid, flags, result; ++ struct sock *sk; ++ int err = 0; ++ ++ scid = __le16_to_cpu(rsp->scid); ++ flags = __le16_to_cpu(rsp->flags); ++ result = __le16_to_cpu(rsp->result); ++ ++ BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result); ++ ++ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) ++ return -ENOENT; ++ ++ switch (result) { ++ case L2CAP_CONF_SUCCESS: ++ break; ++ ++ case L2CAP_CONF_UNACCEPT: ++ if (++l2cap_pi(sk)->conf_retry < L2CAP_CONF_MAX_RETRIES) { ++ char req[128]; ++ /* ++ It does not make sense to adjust L2CAP parameters ++ that are currently defined in the spec. We simply ++ resend config request that we sent earlier. It is ++ stupid :) but it helps qualification testing ++ which expects at least some response from us. ++ */ ++ l2cap_send_req(conn, L2CAP_CONF_REQ, ++ l2cap_build_conf_req(sk, req), req); ++ goto done; ++ } ++ default: ++ sk->state = BT_DISCONN; ++ sk->err = ECONNRESET; ++ l2cap_sock_set_timer(sk, HZ * 5); ++ { ++ l2cap_disconn_req req; ++ req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid); ++ req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); ++ l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req); ++ } ++ goto done; ++ } ++ ++ if (flags & 0x01) ++ goto done; ++ ++ /* Input config done */ ++ l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE; ++ ++ if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) { ++ sk->state = BT_CONNECTED; ++ l2cap_chan_ready(sk); ++ } ++ ++done: ++ bh_unlock_sock(sk); ++ return err; ++} ++ ++static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) ++{ ++ l2cap_disconn_req *req = (l2cap_disconn_req *) data; ++ l2cap_disconn_rsp rsp; ++ __u16 dcid, scid; ++ struct sock *sk; ++ ++ scid = __le16_to_cpu(req->scid); ++ dcid = __le16_to_cpu(req->dcid); ++ ++ BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); ++ ++ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid))) ++ return 0; ++ ++ rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid); ++ rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid); ++ l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp); ++ ++ sk->shutdown = SHUTDOWN_MASK; ++ ++ l2cap_chan_del(sk, ECONNRESET); ++ bh_unlock_sock(sk); ++ ++ l2cap_sock_kill(sk); ++ return 0; ++} ++ ++static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) ++{ ++ l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data; ++ __u16 dcid, scid; ++ struct sock *sk; ++ ++ scid = __le16_to_cpu(rsp->scid); ++ dcid = __le16_to_cpu(rsp->dcid); ++ ++ BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); ++ ++ if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) ++ return 0; ++ l2cap_chan_del(sk, 0); ++ bh_unlock_sock(sk); ++ ++ l2cap_sock_kill(sk); ++ return 0; ++} ++ ++static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) ++{ ++ __u8 *data = skb->data; ++ int len = skb->len; ++ l2cap_cmd_hdr cmd; ++ int err = 0; ++ ++ while (len >= L2CAP_CMD_HDR_SIZE) { ++ memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE); ++ data += L2CAP_CMD_HDR_SIZE; ++ len -= L2CAP_CMD_HDR_SIZE; ++ ++ cmd.len = __le16_to_cpu(cmd.len); ++ ++ BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident); ++ ++ if (cmd.len > len || !cmd.ident) { ++ BT_DBG("corrupted command"); ++ break; ++ } ++ ++ switch (cmd.code) { ++ case L2CAP_CONN_REQ: ++ err = l2cap_connect_req(conn, &cmd, data); ++ break; ++ ++ case L2CAP_CONN_RSP: ++ err = l2cap_connect_rsp(conn, &cmd, data); ++ break; ++ ++ case L2CAP_CONF_REQ: ++ err = l2cap_config_req(conn, &cmd, data); ++ break; ++ ++ case L2CAP_CONF_RSP: ++ err = l2cap_config_rsp(conn, &cmd, data); ++ break; ++ ++ case L2CAP_DISCONN_REQ: ++ err = l2cap_disconnect_req(conn, &cmd, data); ++ break; ++ ++ case L2CAP_DISCONN_RSP: ++ err = l2cap_disconnect_rsp(conn, &cmd, data); ++ break; ++ ++ case L2CAP_COMMAND_REJ: ++ /* FIXME: We should process this */ ++ l2cap_raw_recv(conn, skb); ++ break; ++ ++ case L2CAP_ECHO_REQ: ++ l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data); ++ break; ++ ++ case L2CAP_ECHO_RSP: ++ case L2CAP_INFO_REQ: ++ case L2CAP_INFO_RSP: ++ l2cap_raw_recv(conn, skb); ++ break; ++ ++ default: ++ BT_ERR("Uknown signaling command 0x%2.2x", cmd.code); ++ err = -EINVAL; ++ break; ++ }; ++ ++ if (err) { ++ l2cap_cmd_rej rej; ++ BT_DBG("error %d", err); ++ ++ /* FIXME: Map err to a valid reason. */ ++ rej.reason = __cpu_to_le16(0); ++ l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej); ++ } ++ ++ data += cmd.len; ++ len -= cmd.len; ++ } ++ ++ kfree_skb(skb); ++} ++ ++static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb) ++{ ++ struct sock *sk; ++ ++ sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); ++ if (!sk) { ++ BT_DBG("unknown cid 0x%4.4x", cid); ++ goto drop; ++ } ++ ++ BT_DBG("sk %p, len %d", sk, skb->len); ++ ++ if (sk->state != BT_CONNECTED) ++ goto drop; ++ ++ if (l2cap_pi(sk)->imtu < skb->len) ++ goto drop; ++ ++ /* If socket recv buffers overflows we drop data here ++ * which is *bad* because L2CAP has to be reliable. ++ * But we don't have any other choice. L2CAP doesn't ++ * provide flow control mechanism */ ++ ++ if (!sock_queue_rcv_skb(sk, skb)) ++ goto done; ++ ++drop: ++ kfree_skb(skb); ++ ++done: ++ if (sk) bh_unlock_sock(sk); ++ return 0; ++} ++ ++static inline int l2cap_conless_channel(struct l2cap_conn *conn, __u16 psm, struct sk_buff *skb) ++{ ++ struct sock *sk; ++ ++ sk = l2cap_get_sock_by_psm(0, psm, conn->src); ++ if (!sk) ++ goto drop; ++ ++ BT_DBG("sk %p, len %d", sk, skb->len); ++ ++ if (sk->state != BT_BOUND && sk->state != BT_CONNECTED) ++ goto drop; ++ ++ if (l2cap_pi(sk)->imtu < skb->len) ++ goto drop; ++ ++ if (!sock_queue_rcv_skb(sk, skb)) ++ goto done; ++ ++drop: ++ kfree_skb(skb); ++ ++done: ++ if (sk) bh_unlock_sock(sk); ++ return 0; ++} ++ ++static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) ++{ ++ l2cap_hdr *lh = (l2cap_hdr *) skb->data; ++ __u16 cid, psm, len; ++ ++ skb_pull(skb, L2CAP_HDR_SIZE); ++ cid = __le16_to_cpu(lh->cid); ++ len = __le16_to_cpu(lh->len); ++ ++ BT_DBG("len %d, cid 0x%4.4x", len, cid); ++ ++ switch (cid) { ++ case 0x0001: ++ l2cap_sig_channel(conn, skb); ++ break; ++ ++ case 0x0002: ++ psm = get_unaligned((__u16 *) skb->data); ++ skb_pull(skb, 2); ++ l2cap_conless_channel(conn, psm, skb); ++ break; ++ ++ default: ++ l2cap_data_channel(conn, cid, skb); ++ break; ++ } ++} ++ ++/* ------------ L2CAP interface with lower layer (HCI) ------------- */ ++ ++static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) ++{ ++ int exact = 0, lm1 = 0, lm2 = 0; ++ register struct sock *sk; ++ ++ if (type != ACL_LINK) ++ return 0; ++ ++ BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); ++ ++ /* Find listening sockets and check their link_mode */ ++ read_lock(&l2cap_sk_list.lock); ++ for (sk = l2cap_sk_list.head; sk; sk = sk->next) { ++ if (sk->state != BT_LISTEN) ++ continue; ++ ++ if (!bacmp(&bluez_pi(sk)->src, &hdev->bdaddr)) { ++ lm1 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode); ++ exact++; ++ } else if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY)) ++ lm2 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode); ++ } ++ read_unlock(&l2cap_sk_list.lock); ++ ++ return exact ? lm1 : lm2; ++} ++ ++static int l2cap_connect_cfm(struct hci_conn *hcon, __u8 status) ++{ ++ BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); ++ ++ if (hcon->type != ACL_LINK) ++ return 0; ++ ++ if (!status) { ++ struct l2cap_conn *conn; ++ ++ conn = l2cap_conn_add(hcon, status); ++ if (conn) ++ l2cap_conn_ready(conn); ++ } else ++ l2cap_conn_del(hcon, bterr(status)); ++ ++ return 0; ++} ++ ++static int l2cap_disconn_ind(struct hci_conn *hcon, __u8 reason) ++{ ++ BT_DBG("hcon %p reason %d", hcon, reason); ++ ++ if (hcon->type != ACL_LINK) ++ return 0; ++ ++ l2cap_conn_del(hcon, bterr(reason)); ++ return 0; ++} ++ ++static int l2cap_auth_cfm(struct hci_conn *hcon, __u8 status) ++{ ++ struct l2cap_chan_list *l; ++ struct l2cap_conn *conn; ++ l2cap_conn_rsp rsp; ++ struct sock *sk; ++ int result; ++ ++ if (!(conn = hcon->l2cap_data)) ++ return 0; ++ l = &conn->chan_list; ++ ++ BT_DBG("conn %p", conn); ++ ++ read_lock(&l->lock); ++ ++ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { ++ bh_lock_sock(sk); ++ ++ if (sk->state != BT_CONNECT2 || ++ (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT)) { ++ bh_unlock_sock(sk); ++ continue; ++ } ++ ++ if (!status) { ++ sk->state = BT_CONFIG; ++ result = 0; ++ } else { ++ sk->state = BT_DISCONN; ++ l2cap_sock_set_timer(sk, HZ/10); ++ result = L2CAP_CR_SEC_BLOCK; ++ } ++ ++ rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid); ++ rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid); ++ rsp.result = __cpu_to_le16(result); ++ rsp.status = __cpu_to_le16(0); ++ l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP, ++ L2CAP_CONN_RSP_SIZE, &rsp); ++ ++ bh_unlock_sock(sk); ++ } ++ ++ read_unlock(&l->lock); ++ return 0; ++} ++ ++static int l2cap_encrypt_cfm(struct hci_conn *hcon, __u8 status) ++{ ++ struct l2cap_chan_list *l; ++ struct l2cap_conn *conn; ++ l2cap_conn_rsp rsp; ++ struct sock *sk; ++ int result; ++ ++ if (!(conn = hcon->l2cap_data)) ++ return 0; ++ l = &conn->chan_list; ++ ++ BT_DBG("conn %p", conn); ++ ++ read_lock(&l->lock); ++ ++ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { ++ bh_lock_sock(sk); ++ ++ if (sk->state != BT_CONNECT2) { ++ bh_unlock_sock(sk); ++ continue; ++ } ++ ++ if (!status) { ++ sk->state = BT_CONFIG; ++ result = 0; ++ } else { ++ sk->state = BT_DISCONN; ++ l2cap_sock_set_timer(sk, HZ/10); ++ result = L2CAP_CR_SEC_BLOCK; ++ } ++ ++ rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid); ++ rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid); ++ rsp.result = __cpu_to_le16(result); ++ rsp.status = __cpu_to_le16(0); ++ l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP, ++ L2CAP_CONN_RSP_SIZE, &rsp); ++ ++ bh_unlock_sock(sk); ++ } ++ ++ read_unlock(&l->lock); ++ return 0; ++} ++ ++static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, __u16 flags) ++{ ++ struct l2cap_conn *conn = hcon->l2cap_data; ++ ++ if (!conn && !(conn = l2cap_conn_add(hcon, 0))) ++ goto drop; ++ ++ BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags); ++ ++ if (flags & ACL_START) { ++ l2cap_hdr *hdr; ++ int len; ++ ++ if (conn->rx_len) { ++ BT_ERR("Unexpected start frame (len %d)", skb->len); ++ kfree_skb(conn->rx_skb); ++ conn->rx_skb = NULL; ++ conn->rx_len = 0; ++ l2cap_conn_unreliable(conn, ECOMM); ++ } ++ ++ if (skb->len < 2) { ++ BT_ERR("Frame is too short (len %d)", skb->len); ++ l2cap_conn_unreliable(conn, ECOMM); ++ goto drop; ++ } ++ ++ hdr = (l2cap_hdr *) skb->data; ++ len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE; ++ ++ if (len == skb->len) { ++ /* Complete frame received */ ++ l2cap_recv_frame(conn, skb); ++ return 0; ++ } ++ ++ BT_DBG("Start: total len %d, frag len %d", len, skb->len); ++ ++ if (skb->len > len) { ++ BT_ERR("Frame is too long (len %d, expected len %d)", ++ skb->len, len); ++ l2cap_conn_unreliable(conn, ECOMM); ++ goto drop; ++ } ++ ++ /* Allocate skb for the complete frame including header */ ++ conn->rx_skb = bluez_skb_alloc(len, GFP_ATOMIC); ++ if (!conn->rx_skb) ++ goto drop; ++ ++ memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len); ++ conn->rx_len = len - skb->len; ++ } else { ++ BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len); ++ ++ if (!conn->rx_len) { ++ BT_ERR("Unexpected continuation frame (len %d)", skb->len); ++ l2cap_conn_unreliable(conn, ECOMM); ++ goto drop; ++ } ++ ++ if (skb->len > conn->rx_len) { ++ BT_ERR("Fragment is too long (len %d, expected %d)", ++ skb->len, conn->rx_len); ++ kfree_skb(conn->rx_skb); ++ conn->rx_skb = NULL; ++ conn->rx_len = 0; ++ l2cap_conn_unreliable(conn, ECOMM); ++ goto drop; ++ } ++ ++ memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len); ++ conn->rx_len -= skb->len; ++ ++ if (!conn->rx_len) { ++ /* Complete frame received */ ++ l2cap_recv_frame(conn, conn->rx_skb); ++ conn->rx_skb = NULL; ++ } ++ } ++ ++drop: ++ kfree_skb(skb); ++ return 0; ++} ++ ++/* ----- Proc fs support ------ */ ++static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list) ++{ ++ struct l2cap_pinfo *pi; ++ struct sock *sk; ++ char *ptr = buf; ++ ++ read_lock_bh(&list->lock); ++ ++ for (sk = list->head; sk; sk = sk->next) { ++ pi = l2cap_pi(sk); ++ ptr += sprintf(ptr, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n", ++ batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst), ++ sk->state, pi->psm, pi->scid, pi->dcid, pi->imtu, pi->omtu, ++ pi->link_mode); ++ } ++ ++ read_unlock_bh(&list->lock); ++ ++ ptr += sprintf(ptr, "\n"); ++ return ptr - buf; ++} ++ ++static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv) ++{ ++ char *ptr = buf; ++ int len; ++ ++ BT_DBG("count %d, offset %ld", count, offset); ++ ++ ptr += l2cap_sock_dump(ptr, &l2cap_sk_list); ++ len = ptr - buf; ++ ++ if (len <= count + offset) ++ *eof = 1; ++ ++ *start = buf + offset; ++ len -= offset; ++ ++ if (len > count) ++ len = count; ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++ ++static struct proto_ops l2cap_sock_ops = { ++ family: PF_BLUETOOTH, ++ release: l2cap_sock_release, ++ bind: l2cap_sock_bind, ++ connect: l2cap_sock_connect, ++ listen: l2cap_sock_listen, ++ accept: l2cap_sock_accept, ++ getname: l2cap_sock_getname, ++ sendmsg: l2cap_sock_sendmsg, ++ recvmsg: bluez_sock_recvmsg, ++ poll: bluez_sock_poll, ++ socketpair: sock_no_socketpair, ++ ioctl: sock_no_ioctl, ++ shutdown: l2cap_sock_shutdown, ++ setsockopt: l2cap_sock_setsockopt, ++ getsockopt: l2cap_sock_getsockopt, ++ mmap: sock_no_mmap ++}; ++ ++static struct net_proto_family l2cap_sock_family_ops = { ++ family: PF_BLUETOOTH, ++ create: l2cap_sock_create ++}; ++ ++static struct hci_proto l2cap_hci_proto = { ++ name: "L2CAP", ++ id: HCI_PROTO_L2CAP, ++ connect_ind: l2cap_connect_ind, ++ connect_cfm: l2cap_connect_cfm, ++ disconn_ind: l2cap_disconn_ind, ++ recv_acldata: l2cap_recv_acldata, ++ auth_cfm: l2cap_auth_cfm, ++ encrypt_cfm: l2cap_encrypt_cfm ++}; ++ ++int __init l2cap_init(void) ++{ ++ int err; ++ ++ if ((err = bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops))) { ++ BT_ERR("Can't register L2CAP socket"); ++ return err; ++ } ++ ++ if ((err = hci_register_proto(&l2cap_hci_proto))) { ++ BT_ERR("Can't register L2CAP protocol"); ++ return err; ++ } ++ ++ create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL); ++ ++ BT_INFO("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION); ++ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); ++ return 0; ++} ++ ++void l2cap_cleanup(void) ++{ ++ remove_proc_entry("bluetooth/l2cap", NULL); ++ ++ /* Unregister socket and protocol */ ++ if (bluez_sock_unregister(BTPROTO_L2CAP)) ++ BT_ERR("Can't unregister L2CAP socket"); ++ ++ if (hci_unregister_proto(&l2cap_hci_proto)) ++ BT_ERR("Can't unregister L2CAP protocol"); ++} ++ ++void l2cap_load(void) ++{ ++ /* Dummy function to trigger automatic L2CAP module loading by ++ other modules that use L2CAP sockets but do not use any other ++ symbols from it. */ ++ return; ++} ++ ++EXPORT_SYMBOL(l2cap_load); ++ ++module_init(l2cap_init); ++module_exit(l2cap_cleanup); ++ ++MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); ++MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION); ++MODULE_LICENSE("GPL"); +diff -urN linux-2.4.18/net/bluetooth/l2cap_core.c linux-2.4.18-mh9/net/bluetooth/l2cap_core.c +--- linux-2.4.18/net/bluetooth/l2cap_core.c Sun Sep 30 21:26:08 2001 ++++ linux-2.4.18-mh9/net/bluetooth/l2cap_core.c Thu Jan 1 01:00:00 1970 +@@ -1,2316 +0,0 @@ +-/* +- BlueZ - Bluetooth protocol stack for Linux +- Copyright (C) 2000-2001 Qualcomm Incorporated +- +- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; +- +- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY +- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES +- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- +- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, +- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS +- SOFTWARE IS DISCLAIMED. +-*/ +- +-/* +- * BlueZ L2CAP core and sockets. +- * +- * $Id$ +- */ +-#define VERSION "1.1" +- +-#include <linux/config.h> +-#include <linux/module.h> +- +-#include <linux/types.h> +-#include <linux/errno.h> +-#include <linux/kernel.h> +-#include <linux/major.h> +-#include <linux/sched.h> +-#include <linux/slab.h> +-#include <linux/poll.h> +-#include <linux/fcntl.h> +-#include <linux/init.h> +-#include <linux/skbuff.h> +-#include <linux/interrupt.h> +-#include <linux/socket.h> +-#include <linux/skbuff.h> +-#include <linux/proc_fs.h> +-#include <linux/list.h> +-#include <net/sock.h> +- +-#include <asm/system.h> +-#include <asm/uaccess.h> +- +-#include <net/bluetooth/bluetooth.h> +-#include <net/bluetooth/bluez.h> +-#include <net/bluetooth/hci_core.h> +-#include <net/bluetooth/l2cap.h> +-#include <net/bluetooth/l2cap_core.h> +- +-#ifndef L2CAP_DEBUG +-#undef DBG +-#define DBG( A... ) +-#endif +- +-struct proto_ops l2cap_sock_ops; +- +-struct bluez_sock_list l2cap_sk_list = { +- lock: RW_LOCK_UNLOCKED +-}; +- +-struct list_head l2cap_iff_list = LIST_HEAD_INIT(l2cap_iff_list); +-rwlock_t l2cap_rt_lock = RW_LOCK_UNLOCKED; +- +-static int l2cap_conn_del(struct l2cap_conn *conn, int err); +- +-static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent); +-static void l2cap_chan_del(struct sock *sk, int err); +-static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len); +- +-static void l2cap_sock_close(struct sock *sk); +-static void l2cap_sock_kill(struct sock *sk); +- +-static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data); +-static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data); +- +-/* -------- L2CAP interfaces & routing --------- */ +-/* Add/delete L2CAP interface. +- * Must be called with locked rt_lock +- */ +- +-static void l2cap_iff_add(struct hci_dev *hdev) +-{ +- struct l2cap_iff *iff; +- +- DBG("%s", hdev->name); +- +- DBG("iff_list %p next %p prev %p", &l2cap_iff_list, l2cap_iff_list.next, l2cap_iff_list.prev); +- +- /* Allocate new interface and lock HCI device */ +- if (!(iff = kmalloc(sizeof(struct l2cap_iff), GFP_KERNEL))) { +- ERR("Can't allocate new interface %s", hdev->name); +- return; +- } +- memset(iff, 0, sizeof(struct l2cap_iff)); +- +- hci_dev_hold(hdev); +- hdev->l2cap_data = iff; +- iff->hdev = hdev; +- iff->mtu = hdev->acl_mtu - HCI_ACL_HDR_SIZE; +- iff->bdaddr = &hdev->bdaddr; +- +- spin_lock_init(&iff->lock); +- INIT_LIST_HEAD(&iff->conn_list); +- +- list_add(&iff->list, &l2cap_iff_list); +-} +- +-static void l2cap_iff_del(struct hci_dev *hdev) +-{ +- struct l2cap_iff *iff; +- +- if (!(iff = hdev->l2cap_data)) +- return; +- +- DBG("%s iff %p", hdev->name, iff); +- +- list_del(&iff->list); +- +- l2cap_iff_lock(iff); +- +- /* Drop connections */ +- while (!list_empty(&iff->conn_list)) { +- struct l2cap_conn *c; +- +- c = list_entry(iff->conn_list.next, struct l2cap_conn, list); +- l2cap_conn_del(c, ENODEV); +- } +- +- l2cap_iff_unlock(iff); +- +- /* Unlock HCI device */ +- hdev->l2cap_data = NULL; +- hci_dev_put(hdev); +- +- kfree(iff); +-} +- +-/* Get route. Returns L2CAP interface. +- * Must be called with locked rt_lock +- */ +-static struct l2cap_iff *l2cap_get_route(bdaddr_t *src, bdaddr_t *dst) +-{ +- struct list_head *p; +- int use_src; +- +- DBG("%s -> %s", batostr(src), batostr(dst)); +- +- use_src = bacmp(src, BDADDR_ANY) ? 0 : 1; +- +- /* Simple routing: +- * No source address - find interface with bdaddr != dst +- * Source address - find interface with bdaddr == src +- */ +- +- list_for_each(p, &l2cap_iff_list) { +- struct l2cap_iff *iff; +- +- iff = list_entry(p, struct l2cap_iff, list); +- +- if (use_src && !bacmp(iff->bdaddr, src)) +- return iff; +- else if (bacmp(iff->bdaddr, dst)) +- return iff; +- } +- return NULL; +-} +- +-/* ----- L2CAP timers ------ */ +-static void l2cap_sock_timeout(unsigned long arg) +-{ +- struct sock *sk = (struct sock *) arg; +- +- DBG("sock %p state %d", sk, sk->state); +- +- bh_lock_sock(sk); +- switch (sk->state) { +- case BT_DISCONN: +- l2cap_chan_del(sk, ETIMEDOUT); +- break; +- +- default: +- sk->err = ETIMEDOUT; +- sk->state_change(sk); +- break; +- }; +- bh_unlock_sock(sk); +- +- l2cap_sock_kill(sk); +- sock_put(sk); +-} +- +-static void l2cap_sock_set_timer(struct sock *sk, long timeout) +-{ +- DBG("sock %p state %d timeout %ld", sk, sk->state, timeout); +- +- if (!mod_timer(&sk->timer, jiffies + timeout)) +- sock_hold(sk); +-} +- +-static void l2cap_sock_clear_timer(struct sock *sk) +-{ +- DBG("sock %p state %d", sk, sk->state); +- +- if (timer_pending(&sk->timer) && del_timer(&sk->timer)) +- __sock_put(sk); +-} +- +-static void l2cap_sock_init_timer(struct sock *sk) +-{ +- init_timer(&sk->timer); +- sk->timer.function = l2cap_sock_timeout; +- sk->timer.data = (unsigned long)sk; +-} +- +-static void l2cap_conn_timeout(unsigned long arg) +-{ +- struct l2cap_conn *conn = (void *)arg; +- +- DBG("conn %p state %d", conn, conn->state); +- +- if (conn->state == BT_CONNECTED) { +- hci_disconnect(conn->hconn, 0x13); +- } +- +- return; +-} +- +-static void l2cap_conn_set_timer(struct l2cap_conn *conn, long timeout) +-{ +- DBG("conn %p state %d timeout %ld", conn, conn->state, timeout); +- +- mod_timer(&conn->timer, jiffies + timeout); +-} +- +-static void l2cap_conn_clear_timer(struct l2cap_conn *conn) +-{ +- DBG("conn %p state %d", conn, conn->state); +- +- del_timer(&conn->timer); +-} +- +-static void l2cap_conn_init_timer(struct l2cap_conn *conn) +-{ +- init_timer(&conn->timer); +- conn->timer.function = l2cap_conn_timeout; +- conn->timer.data = (unsigned long)conn; +-} +- +-/* -------- L2CAP connections --------- */ +-/* Add new connection to the interface. +- * Interface must be locked +- */ +-static struct l2cap_conn *l2cap_conn_add(struct l2cap_iff *iff, bdaddr_t *dst) +-{ +- struct l2cap_conn *conn; +- bdaddr_t *src = iff->bdaddr; +- +- if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_KERNEL))) +- return NULL; +- +- memset(conn, 0, sizeof(struct l2cap_conn)); +- +- conn->state = BT_OPEN; +- conn->iff = iff; +- bacpy(&conn->src, src); +- bacpy(&conn->dst, dst); +- +- spin_lock_init(&conn->lock); +- conn->chan_list.lock = RW_LOCK_UNLOCKED; +- +- l2cap_conn_init_timer(conn); +- +- __l2cap_conn_link(iff, conn); +- +- DBG("%s -> %s, %p", batostr(src), batostr(dst), conn); +- +- MOD_INC_USE_COUNT; +- +- return conn; +-} +- +-/* Delete connection on the interface. +- * Interface must be locked +- */ +-static int l2cap_conn_del(struct l2cap_conn *conn, int err) +-{ +- struct sock *sk; +- +- DBG("conn %p, state %d, err %d", conn, conn->state, err); +- +- l2cap_conn_clear_timer(conn); +- __l2cap_conn_unlink(conn->iff, conn); +- +- conn->state = BT_CLOSED; +- +- if (conn->rx_skb) +- kfree_skb(conn->rx_skb); +- +- /* Kill channels */ +- while ((sk = conn->chan_list.head)) { +- bh_lock_sock(sk); +- l2cap_sock_clear_timer(sk); +- l2cap_chan_del(sk, err); +- bh_unlock_sock(sk); +- +- l2cap_sock_kill(sk); +- } +- +- kfree(conn); +- +- MOD_DEC_USE_COUNT; +- return 0; +-} +- +-static inline struct l2cap_conn *l2cap_get_conn_by_addr(struct l2cap_iff *iff, bdaddr_t *dst) +-{ +- struct list_head *p; +- +- list_for_each(p, &iff->conn_list) { +- struct l2cap_conn *c; +- +- c = list_entry(p, struct l2cap_conn, list); +- if (!bacmp(&c->dst, dst)) +- return c; +- } +- return NULL; +-} +- +-int l2cap_connect(struct sock *sk) +-{ +- bdaddr_t *src = &l2cap_pi(sk)->src; +- bdaddr_t *dst = &l2cap_pi(sk)->dst; +- struct l2cap_conn *conn; +- struct l2cap_iff *iff; +- int err = 0; +- +- DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm); +- +- read_lock_bh(&l2cap_rt_lock); +- +- /* Get route to remote BD address */ +- if (!(iff = l2cap_get_route(src, dst))) { +- err = -EHOSTUNREACH; +- goto done; +- } +- +- /* Update source addr of the socket */ +- bacpy(src, iff->bdaddr); +- +- l2cap_iff_lock(iff); +- +- if (!(conn = l2cap_get_conn_by_addr(iff, dst))) { +- /* Connection doesn't exist */ +- if (!(conn = l2cap_conn_add(iff, dst))) { +- l2cap_iff_unlock(iff); +- err = -ENOMEM; +- goto done; +- } +- conn->out = 1; +- } +- +- l2cap_iff_unlock(iff); +- +- l2cap_chan_add(conn, sk, NULL); +- +- sk->state = BT_CONNECT; +- l2cap_sock_set_timer(sk, sk->sndtimeo); +- +- switch (conn->state) { +- case BT_CONNECTED: +- if (sk->type == SOCK_SEQPACKET) { +- l2cap_conn_req req; +- req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); +- req.psm = l2cap_pi(sk)->psm; +- l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req); +- } else { +- l2cap_sock_clear_timer(sk); +- sk->state = BT_CONNECTED; +- } +- break; +- +- case BT_CONNECT: +- break; +- +- default: +- /* Create ACL connection */ +- conn->state = BT_CONNECT; +- hci_connect(iff->hdev, dst); +- break; +- }; +- +-done: +- read_unlock_bh(&l2cap_rt_lock); +- return err; +-} +- +-/* ------ Channel queues for listening sockets ------ */ +-void l2cap_accept_queue(struct sock *parent, struct sock *sk) +-{ +- struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q; +- +- DBG("parent %p, sk %p", parent, sk); +- +- sock_hold(sk); +- l2cap_pi(sk)->parent = parent; +- l2cap_pi(sk)->next_q = NULL; +- +- if (!q->head) { +- q->head = q->tail = sk; +- } else { +- struct sock *tail = q->tail; +- +- l2cap_pi(sk)->prev_q = tail; +- l2cap_pi(tail)->next_q = sk; +- q->tail = sk; +- } +- +- parent->ack_backlog++; +-} +- +-void l2cap_accept_unlink(struct sock *sk) +-{ +- struct sock *parent = l2cap_pi(sk)->parent; +- struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q; +- struct sock *next, *prev; +- +- DBG("sk %p", sk); +- +- next = l2cap_pi(sk)->next_q; +- prev = l2cap_pi(sk)->prev_q; +- +- if (sk == q->head) +- q->head = next; +- if (sk == q->tail) +- q->tail = prev; +- +- if (next) +- l2cap_pi(next)->prev_q = prev; +- if (prev) +- l2cap_pi(prev)->next_q = next; +- +- l2cap_pi(sk)->parent = NULL; +- +- parent->ack_backlog--; +- __sock_put(sk); +-} +- +-/* Get next connected channel in queue. */ +-struct sock *l2cap_accept_dequeue(struct sock *parent, int state) +-{ +- struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q; +- struct sock *sk; +- +- for (sk = q->head; sk; sk = l2cap_pi(sk)->next_q) { +- if (!state || sk->state == state) { +- l2cap_accept_unlink(sk); +- break; +- } +- } +- +- DBG("parent %p, sk %p", parent, sk); +- +- return sk; +-} +- +-/* -------- Socket interface ---------- */ +-static struct sock *__l2cap_get_sock_by_addr(struct sockaddr_l2 *addr) +-{ +- bdaddr_t *src = &addr->l2_bdaddr; +- __u16 psm = addr->l2_psm; +- struct sock *sk; +- +- for (sk = l2cap_sk_list.head; sk; sk = sk->next) { +- if (l2cap_pi(sk)->psm == psm && +- !bacmp(&l2cap_pi(sk)->src, src)) +- break; +- } +- +- return sk; +-} +- +-/* Find socket listening on psm and source bdaddr. +- * Returns closest match. +- */ +-static struct sock *l2cap_get_sock_listen(bdaddr_t *src, __u16 psm) +-{ +- struct sock *sk, *sk1 = NULL; +- +- read_lock(&l2cap_sk_list.lock); +- +- for (sk = l2cap_sk_list.head; sk; sk = sk->next) { +- struct l2cap_pinfo *pi; +- +- if (sk->state != BT_LISTEN) +- continue; +- +- pi = l2cap_pi(sk); +- +- if (pi->psm == psm) { +- /* Exact match. */ +- if (!bacmp(&pi->src, src)) +- break; +- +- /* Closest match */ +- if (!bacmp(&pi->src, BDADDR_ANY)) +- sk1 = sk; +- } +- } +- +- read_unlock(&l2cap_sk_list.lock); +- +- return sk ? sk : sk1; +-} +- +-static void l2cap_sock_destruct(struct sock *sk) +-{ +- DBG("sk %p", sk); +- +- skb_queue_purge(&sk->receive_queue); +- skb_queue_purge(&sk->write_queue); +- +- MOD_DEC_USE_COUNT; +-} +- +-static void l2cap_sock_cleanup_listen(struct sock *parent) +-{ +- struct sock *sk; +- +- DBG("parent %p", parent); +- +- /* Close not yet accepted channels */ +- while ((sk = l2cap_accept_dequeue(parent, 0))) +- l2cap_sock_close(sk); +- +- parent->state = BT_CLOSED; +- parent->zapped = 1; +-} +- +-/* Kill socket (only if zapped and orphan) +- * Must be called on unlocked socket. +- */ +-static void l2cap_sock_kill(struct sock *sk) +-{ +- if (!sk->zapped || sk->socket) +- return; +- +- DBG("sk %p state %d", sk, sk->state); +- +- /* Kill poor orphan */ +- bluez_sock_unlink(&l2cap_sk_list, sk); +- sk->dead = 1; +- sock_put(sk); +-} +- +-/* Close socket. +- * Must be called on unlocked socket. +- */ +-static void l2cap_sock_close(struct sock *sk) +-{ +- struct l2cap_conn *conn; +- +- l2cap_sock_clear_timer(sk); +- +- lock_sock(sk); +- +- conn = l2cap_pi(sk)->conn; +- +- DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket); +- +- switch (sk->state) { +- case BT_LISTEN: +- l2cap_sock_cleanup_listen(sk); +- break; +- +- case BT_CONNECTED: +- case BT_CONFIG: +- if (sk->type == SOCK_SEQPACKET) { +- l2cap_disconn_req req; +- +- sk->state = BT_DISCONN; +- +- req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid); +- req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); +- l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req); +- +- l2cap_sock_set_timer(sk, sk->sndtimeo); +- } else { +- l2cap_chan_del(sk, ECONNRESET); +- } +- break; +- +- case BT_CONNECT: +- case BT_DISCONN: +- l2cap_chan_del(sk, ECONNRESET); +- break; +- +- default: +- sk->zapped = 1; +- break; +- }; +- +- release_sock(sk); +- +- l2cap_sock_kill(sk); +-} +- +-static void l2cap_sock_init(struct sock *sk, struct sock *parent) +-{ +- struct l2cap_pinfo *pi = l2cap_pi(sk); +- +- DBG("sk %p", sk); +- +- if (parent) { +- sk->type = parent->type; +- +- pi->imtu = l2cap_pi(parent)->imtu; +- pi->omtu = l2cap_pi(parent)->omtu; +- } else { +- pi->imtu = L2CAP_DEFAULT_MTU; +- pi->omtu = 0; +- } +- +- /* Default config options */ +- pi->conf_mtu = L2CAP_DEFAULT_MTU; +- pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; +-} +- +-static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio) +-{ +- struct sock *sk; +- +- if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1))) +- return NULL; +- +- sock_init_data(sock, sk); +- +- sk->zapped = 0; +- +- sk->destruct = l2cap_sock_destruct; +- sk->sndtimeo = L2CAP_CONN_TIMEOUT; +- +- sk->protocol = proto; +- sk->state = BT_OPEN; +- +- l2cap_sock_init_timer(sk); +- +- bluez_sock_link(&l2cap_sk_list, sk); +- +- MOD_INC_USE_COUNT; +- +- return sk; +-} +- +-static int l2cap_sock_create(struct socket *sock, int protocol) +-{ +- struct sock *sk; +- +- DBG("sock %p", sock); +- +- sock->state = SS_UNCONNECTED; +- +- if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_RAW) +- return -ESOCKTNOSUPPORT; +- +- sock->ops = &l2cap_sock_ops; +- +- if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL))) +- return -ENOMEM; +- +- l2cap_sock_init(sk, NULL); +- +- return 0; +-} +- +-static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) +-{ +- struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; +- struct sock *sk = sock->sk; +- int err = 0; +- +- DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm); +- +- if (!addr || addr->sa_family != AF_BLUETOOTH) +- return -EINVAL; +- +- lock_sock(sk); +- +- if (sk->state != BT_OPEN) { +- err = -EBADFD; +- goto done; +- } +- +- write_lock(&l2cap_sk_list.lock); +- +- if (la->l2_psm && __l2cap_get_sock_by_addr(la)) { +- err = -EADDRINUSE; +- goto unlock; +- } +- +- /* Save source address */ +- bacpy(&l2cap_pi(sk)->src, &la->l2_bdaddr); +- l2cap_pi(sk)->psm = la->l2_psm; +- sk->state = BT_BOUND; +- +-unlock: +- write_unlock(&l2cap_sk_list.lock); +- +-done: +- release_sock(sk); +- +- return err; +-} +- +-static int l2cap_sock_w4_connect(struct sock *sk, int flags) +-{ +- DECLARE_WAITQUEUE(wait, current); +- long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); +- int err = 0; +- +- DBG("sk %p", sk); +- +- add_wait_queue(sk->sleep, &wait); +- current->state = TASK_INTERRUPTIBLE; +- +- while (sk->state != BT_CONNECTED) { +- if (!timeo) { +- err = -EAGAIN; +- break; +- } +- +- release_sock(sk); +- timeo = schedule_timeout(timeo); +- lock_sock(sk); +- +- err = 0; +- if (sk->state == BT_CONNECTED) +- break; +- +- if (sk->err) { +- err = sock_error(sk); +- break; +- } +- +- if (signal_pending(current)) { +- err = sock_intr_errno(timeo); +- break; +- } +- } +- current->state = TASK_RUNNING; +- remove_wait_queue(sk->sleep, &wait); +- +- return err; +-} +- +-static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) +-{ +- struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; +- struct sock *sk = sock->sk; +- int err = 0; +- +- lock_sock(sk); +- +- DBG("sk %p", sk); +- +- if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) { +- err = -EINVAL; +- goto done; +- } +- +- if (sk->state != BT_OPEN && sk->state != BT_BOUND) { +- err = -EBADFD; +- goto done; +- } +- +- if (sk->type == SOCK_SEQPACKET && !la->l2_psm) { +- err = -EINVAL; +- goto done; +- } +- +- /* Set destination address and psm */ +- bacpy(&l2cap_pi(sk)->dst, &la->l2_bdaddr); +- l2cap_pi(sk)->psm = la->l2_psm; +- +- if ((err = l2cap_connect(sk))) +- goto done; +- +- err = l2cap_sock_w4_connect(sk, flags); +- +-done: +- release_sock(sk); +- return err; +-} +- +-int l2cap_sock_listen(struct socket *sock, int backlog) +-{ +- struct sock *sk = sock->sk; +- int err = 0; +- +- DBG("sk %p backlog %d", sk, backlog); +- +- lock_sock(sk); +- +- if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) { +- err = -EBADFD; +- goto done; +- } +- +- if (!l2cap_pi(sk)->psm) { +- err = -EINVAL; +- goto done; +- } +- +- sk->max_ack_backlog = backlog; +- sk->ack_backlog = 0; +- sk->state = BT_LISTEN; +- +-done: +- release_sock(sk); +- return err; +-} +- +-int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags) +-{ +- DECLARE_WAITQUEUE(wait, current); +- struct sock *sk = sock->sk, *ch; +- long timeo; +- int err = 0; +- +- lock_sock(sk); +- +- if (sk->state != BT_LISTEN) { +- err = -EBADFD; +- goto done; +- } +- +- timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); +- +- DBG("sk %p timeo %ld", sk, timeo); +- +- /* Wait for an incoming connection. (wake-one). */ +- add_wait_queue_exclusive(sk->sleep, &wait); +- current->state = TASK_INTERRUPTIBLE; +- while (!(ch = l2cap_accept_dequeue(sk, BT_CONNECTED))) { +- if (!timeo) { +- err = -EAGAIN; +- break; +- } +- +- release_sock(sk); +- timeo = schedule_timeout(timeo); +- lock_sock(sk); +- +- if (sk->state != BT_LISTEN) { +- err = -EBADFD; +- break; +- } +- +- if (signal_pending(current)) { +- err = sock_intr_errno(timeo); +- break; +- } +- } +- current->state = TASK_RUNNING; +- remove_wait_queue(sk->sleep, &wait); +- +- if (err) +- goto done; +- +- sock_graft(ch, newsock); +- newsock->state = SS_CONNECTED; +- +- DBG("new socket %p", ch); +- +-done: +- release_sock(sk); +- +- return err; +-} +- +-static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer) +-{ +- struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; +- struct sock *sk = sock->sk; +- +- DBG("sock %p, sk %p", sock, sk); +- +- addr->sa_family = AF_BLUETOOTH; +- *len = sizeof(struct sockaddr_l2); +- +- if (peer) +- bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->dst); +- else +- bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->src); +- +- la->l2_psm = l2cap_pi(sk)->psm; +- +- return 0; +-} +- +-static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) +-{ +- struct sock *sk = sock->sk; +- int err = 0; +- +- DBG("sock %p, sk %p", sock, sk); +- +- if (sk->err) +- return sock_error(sk); +- +- if (msg->msg_flags & MSG_OOB) +- return -EOPNOTSUPP; +- +- lock_sock(sk); +- +- if (sk->state == BT_CONNECTED) +- err = l2cap_chan_send(sk, msg, len); +- else +- err = -ENOTCONN; +- +- release_sock(sk); +- return err; +-} +- +-static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm) +-{ +- struct sock *sk = sock->sk; +- int noblock = flags & MSG_DONTWAIT; +- int copied, err; +- struct sk_buff *skb; +- +- DBG("sock %p, sk %p", sock, sk); +- +- if (flags & (MSG_OOB)) +- return -EOPNOTSUPP; +- +- if (sk->state == BT_CLOSED) +- return 0; +- +- if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) +- return err; +- +- msg->msg_namelen = 0; +- +- copied = skb->len; +- if (len < copied) { +- msg->msg_flags |= MSG_TRUNC; +- copied = len; +- } +- +- skb->h.raw = skb->data; +- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); +- +- skb_free_datagram(sk, skb); +- +- return err ? : copied; +-} +- +-int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) +-{ +- struct sock *sk = sock->sk; +- struct l2cap_options opts; +- int err = 0; +- +- DBG("sk %p", sk); +- +- lock_sock(sk); +- +- switch (optname) { +- case L2CAP_OPTIONS: +- if (copy_from_user((char *)&opts, optval, optlen)) { +- err = -EFAULT; +- break; +- } +- l2cap_pi(sk)->imtu = opts.imtu; +- l2cap_pi(sk)->omtu = opts.omtu; +- break; +- +- default: +- err = -ENOPROTOOPT; +- break; +- }; +- +- release_sock(sk); +- return err; +-} +- +-int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) +-{ +- struct sock *sk = sock->sk; +- struct l2cap_options opts; +- struct l2cap_conninfo cinfo; +- int len, err = 0; +- +- if (get_user(len, optlen)) +- return -EFAULT; +- +- lock_sock(sk); +- +- switch (optname) { +- case L2CAP_OPTIONS: +- opts.imtu = l2cap_pi(sk)->imtu; +- opts.omtu = l2cap_pi(sk)->omtu; +- opts.flush_to = l2cap_pi(sk)->flush_to; +- +- len = MIN(len, sizeof(opts)); +- if (copy_to_user(optval, (char *)&opts, len)) +- err = -EFAULT; +- +- break; +- +- case L2CAP_CONNINFO: +- if (sk->state != BT_CONNECTED) { +- err = -ENOTCONN; +- break; +- } +- +- cinfo.hci_handle = l2cap_pi(sk)->conn->hconn->handle; +- +- len = MIN(len, sizeof(cinfo)); +- if (copy_to_user(optval, (char *)&cinfo, len)) +- err = -EFAULT; +- +- break; +- +- default: +- err = -ENOPROTOOPT; +- break; +- }; +- +- release_sock(sk); +- return err; +-} +- +-static unsigned int l2cap_sock_poll(struct file * file, struct socket *sock, poll_table *wait) +-{ +- struct sock *sk = sock->sk; +- struct l2cap_accept_q *aq; +- unsigned int mask; +- +- DBG("sock %p, sk %p", sock, sk); +- +- poll_wait(file, sk->sleep, wait); +- mask = 0; +- +- if (sk->err || !skb_queue_empty(&sk->error_queue)) +- mask |= POLLERR; +- +- if (sk->shutdown == SHUTDOWN_MASK) +- mask |= POLLHUP; +- +- aq = &l2cap_pi(sk)->accept_q; +- if (!skb_queue_empty(&sk->receive_queue) || aq->head || (sk->shutdown & RCV_SHUTDOWN)) +- mask |= POLLIN | POLLRDNORM; +- +- if (sk->state == BT_CLOSED) +- mask |= POLLHUP; +- +- if (sock_writeable(sk)) +- mask |= POLLOUT | POLLWRNORM | POLLWRBAND; +- else +- set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); +- +- return mask; +-} +- +-static int l2cap_sock_release(struct socket *sock) +-{ +- struct sock *sk = sock->sk; +- +- DBG("sock %p, sk %p", sock, sk); +- +- if (!sk) +- return 0; +- +- sock_orphan(sk); +- +- l2cap_sock_close(sk); +- +- return 0; +-} +- +-/* --------- L2CAP channels --------- */ +-static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid) +-{ +- struct sock *s; +- +- for (s = l->head; s; s = l2cap_pi(s)->next_c) { +- if (l2cap_pi(s)->dcid == cid) +- break; +- } +- +- return s; +-} +- +-static inline struct sock *l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid) +-{ +- struct sock *s; +- +- read_lock(&l->lock); +- s = __l2cap_get_chan_by_dcid(l, cid); +- read_unlock(&l->lock); +- +- return s; +-} +- +-static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid) +-{ +- struct sock *s; +- +- for (s = l->head; s; s = l2cap_pi(s)->next_c) { +- if (l2cap_pi(s)->scid == cid) +- break; +- } +- +- return s; +-} +-static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid) +-{ +- struct sock *s; +- +- read_lock(&l->lock); +- s = __l2cap_get_chan_by_scid(l, cid); +- read_unlock(&l->lock); +- +- return s; +-} +- +-static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident) +-{ +- struct sock *s; +- +- for (s = l->head; s; s = l2cap_pi(s)->next_c) { +- if (l2cap_pi(s)->ident == ident) +- break; +- } +- +- return s; +-} +- +-static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident) +-{ +- struct sock *s; +- +- read_lock(&l->lock); +- s = __l2cap_get_chan_by_ident(l, ident); +- read_unlock(&l->lock); +- +- return s; +-} +- +-static __u16 l2cap_alloc_cid(struct l2cap_chan_list *l) +-{ +- __u16 cid = 0x0040; +- +- for (; cid < 0xffff; cid++) { +- if(!__l2cap_get_chan_by_scid(l, cid)) +- return cid; +- } +- +- return 0; +-} +- +-static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk) +-{ +- sock_hold(sk); +- +- if (l->head) +- l2cap_pi(l->head)->prev_c = sk; +- +- l2cap_pi(sk)->next_c = l->head; +- l2cap_pi(sk)->prev_c = NULL; +- l->head = sk; +-} +- +-static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) +-{ +- struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c; +- +- write_lock(&l->lock); +- if (sk == l->head) +- l->head = next; +- +- if (next) +- l2cap_pi(next)->prev_c = prev; +- if (prev) +- l2cap_pi(prev)->next_c = next; +- write_unlock(&l->lock); +- +- __sock_put(sk); +-} +- +-static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) +-{ +- struct l2cap_chan_list *l = &conn->chan_list; +- +- DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); +- +- l2cap_conn_clear_timer(conn); +- +- atomic_inc(&conn->refcnt); +- l2cap_pi(sk)->conn = conn; +- +- if (sk->type == SOCK_SEQPACKET) { +- /* Alloc CID for normal socket */ +- l2cap_pi(sk)->scid = l2cap_alloc_cid(l); +- } else { +- /* Raw socket can send only signalling messages */ +- l2cap_pi(sk)->scid = 0x0001; +- l2cap_pi(sk)->dcid = 0x0001; +- l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; +- } +- +- __l2cap_chan_link(l, sk); +- +- if (parent) +- l2cap_accept_queue(parent, sk); +-} +- +-static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) +-{ +- struct l2cap_chan_list *l = &conn->chan_list; +- +- write_lock(&l->lock); +- __l2cap_chan_add(conn, sk, parent); +- write_unlock(&l->lock); +-} +- +-/* Delete channel. +- * Must be called on the locked socket. */ +-static void l2cap_chan_del(struct sock *sk, int err) +-{ +- struct l2cap_conn *conn; +- struct sock *parent; +- +- conn = l2cap_pi(sk)->conn; +- parent = l2cap_pi(sk)->parent; +- +- DBG("sk %p, conn %p, err %d", sk, conn, err); +- +- if (parent) { +- /* Unlink from parent accept queue */ +- bh_lock_sock(parent); +- l2cap_accept_unlink(sk); +- bh_unlock_sock(parent); +- } +- +- if (conn) { +- long timeout; +- +- /* Unlink from channel list */ +- l2cap_chan_unlink(&conn->chan_list, sk); +- l2cap_pi(sk)->conn = NULL; +- +- if (conn->out) +- timeout = L2CAP_DISCONN_TIMEOUT; +- else +- timeout = L2CAP_CONN_IDLE_TIMEOUT; +- +- if (atomic_dec_and_test(&conn->refcnt) && conn->state == BT_CONNECTED) { +- /* Schedule Baseband disconnect */ +- l2cap_conn_set_timer(conn, timeout); +- } +- } +- +- sk->state = BT_CLOSED; +- sk->err = err; +- sk->state_change(sk); +- +- sk->zapped = 1; +-} +- +-static void l2cap_conn_ready(struct l2cap_conn *conn) +-{ +- struct l2cap_chan_list *l = &conn->chan_list; +- struct sock *sk; +- +- DBG("conn %p", conn); +- +- read_lock(&l->lock); +- +- for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { +- bh_lock_sock(sk); +- +- if (sk->type != SOCK_SEQPACKET) { +- sk->state = BT_CONNECTED; +- sk->state_change(sk); +- l2cap_sock_clear_timer(sk); +- } else if (sk->state == BT_CONNECT) { +- l2cap_conn_req req; +- req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); +- req.psm = l2cap_pi(sk)->psm; +- l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req); +- +- l2cap_sock_set_timer(sk, sk->sndtimeo); +- } +- +- bh_unlock_sock(sk); +- } +- +- read_unlock(&l->lock); +-} +- +-static void l2cap_chan_ready(struct sock *sk) +-{ +- struct sock *parent = l2cap_pi(sk)->parent; +- +- DBG("sk %p, parent %p", sk, parent); +- +- l2cap_pi(sk)->conf_state = 0; +- l2cap_sock_clear_timer(sk); +- +- if (!parent) { +- /* Outgoing channel. +- * Wake up socket sleeping on connect. +- */ +- sk->state = BT_CONNECTED; +- sk->state_change(sk); +- } else { +- /* Incomming channel. +- * Wake up socket sleeping on accept. +- */ +- parent->data_ready(parent, 1); +- } +-} +- +-/* Copy frame to all raw sockets on that connection */ +-void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) +-{ +- struct l2cap_chan_list *l = &conn->chan_list; +- struct sk_buff *nskb; +- struct sock * sk; +- +- DBG("conn %p", conn); +- +- read_lock(&l->lock); +- for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { +- if (sk->type != SOCK_RAW) +- continue; +- +- /* Don't send frame to the socket it came from */ +- if (skb->sk == sk) +- continue; +- +- if (!(nskb = skb_clone(skb, GFP_ATOMIC))) +- continue; +- +- skb_queue_tail(&sk->receive_queue, nskb); +- sk->data_ready(sk, nskb->len); +- } +- read_unlock(&l->lock); +-} +- +-static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len) +-{ +- struct l2cap_conn *conn = l2cap_pi(sk)->conn; +- struct sk_buff *skb, **frag; +- int err, size, count, sent=0; +- l2cap_hdr *lh; +- +- /* Check outgoing MTU */ +- if (len > l2cap_pi(sk)->omtu) +- return -EINVAL; +- +- DBG("sk %p len %d", sk, len); +- +- /* First fragment (with L2CAP header) */ +- count = MIN(conn->iff->mtu - L2CAP_HDR_SIZE, len); +- size = L2CAP_HDR_SIZE + count; +- if (!(skb = bluez_skb_send_alloc(sk, size, msg->msg_flags & MSG_DONTWAIT, &err))) +- return err; +- +- /* Create L2CAP header */ +- lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); +- lh->len = __cpu_to_le16(len); +- lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid); +- +- if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) { +- err = -EFAULT; +- goto fail; +- } +- +- sent += count; +- len -= count; +- +- /* Continuation fragments (no L2CAP header) */ +- frag = &skb_shinfo(skb)->frag_list; +- while (len) { +- count = MIN(conn->iff->mtu, len); +- +- *frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err); +- if (!*frag) +- goto fail; +- +- if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) { +- err = -EFAULT; +- goto fail; +- } +- +- sent += count; +- len -= count; +- +- frag = &(*frag)->next; +- } +- +- if ((err = hci_send_acl(conn->hconn, skb, 0)) < 0) +- goto fail; +- +- return sent; +- +-fail: +- kfree_skb(skb); +- return err; +-} +- +-/* --------- L2CAP signalling commands --------- */ +-static inline __u8 l2cap_get_ident(struct l2cap_conn *conn) +-{ +- __u8 id; +- +- /* Get next available identificator. +- * 1 - 199 are used by kernel. +- * 200 - 254 are used by utilities like l2ping, etc +- */ +- +- spin_lock(&conn->lock); +- +- if (++conn->tx_ident > 199) +- conn->tx_ident = 1; +- +- id = conn->tx_ident; +- +- spin_unlock(&conn->lock); +- +- return id; +-} +- +-static inline struct sk_buff *l2cap_build_cmd(__u8 code, __u8 ident, __u16 len, void *data) +-{ +- struct sk_buff *skb; +- l2cap_cmd_hdr *cmd; +- l2cap_hdr *lh; +- int size; +- +- DBG("code 0x%2.2x, ident 0x%2.2x, len %d", code, ident, len); +- +- size = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + len; +- if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) +- return NULL; +- +- lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); +- lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + len); +- lh->cid = __cpu_to_le16(0x0001); +- +- cmd = (l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE); +- cmd->code = code; +- cmd->ident = ident; +- cmd->len = __cpu_to_le16(len); +- +- if (len) +- memcpy(skb_put(skb, len), data, len); +- +- return skb; +-} +- +-static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data) +-{ +- struct sk_buff *skb; +- __u8 ident; +- +- DBG("code 0x%2.2x", code); +- +- ident = l2cap_get_ident(conn); +- if (!(skb = l2cap_build_cmd(code, ident, len, data))) +- return -ENOMEM; +- return hci_send_acl(conn->hconn, skb, 0); +-} +- +-static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data) +-{ +- struct sk_buff *skb; +- +- DBG("code 0x%2.2x", code); +- +- if (!(skb = l2cap_build_cmd(code, ident, len, data))) +- return -ENOMEM; +- return hci_send_acl(conn->hconn, skb, 0); +-} +- +-static inline int l2cap_get_conf_opt(__u8 **ptr, __u8 *type, __u32 *val) +-{ +- l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr); +- int len; +- +- *type = opt->type; +- switch (opt->len) { +- case 1: +- *val = *((__u8 *) opt->val); +- break; +- +- case 2: +- *val = __le16_to_cpu(*((__u16 *)opt->val)); +- break; +- +- case 4: +- *val = __le32_to_cpu(*((__u32 *)opt->val)); +- break; +- +- default: +- *val = 0L; +- break; +- }; +- +- DBG("type 0x%2.2x len %d val 0x%8.8x", *type, opt->len, *val); +- +- len = L2CAP_CONF_OPT_SIZE + opt->len; +- +- *ptr += len; +- +- return len; +-} +- +-static inline void l2cap_parse_conf_req(struct sock *sk, char *data, int len) +-{ +- __u8 type, hint; __u32 val; +- __u8 *ptr = data; +- +- DBG("sk %p len %d", sk, len); +- +- while (len >= L2CAP_CONF_OPT_SIZE) { +- len -= l2cap_get_conf_opt(&ptr, &type, &val); +- +- hint = type & 0x80; +- type &= 0x7f; +- +- switch (type) { +- case L2CAP_CONF_MTU: +- l2cap_pi(sk)->conf_mtu = val; +- break; +- +- case L2CAP_CONF_FLUSH_TO: +- l2cap_pi(sk)->flush_to = val; +- break; +- +- case L2CAP_CONF_QOS: +- break; +- +- default: +- if (hint) +- break; +- +- /* FIXME: Reject unknon option */ +- break; +- }; +- } +-} +- +-static inline void l2cap_add_conf_opt(__u8 **ptr, __u8 type, __u8 len, __u32 val) +-{ +- register l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr); +- +- DBG("type 0x%2.2x len %d val 0x%8.8x", type, len, val); +- +- opt->type = type; +- opt->len = len; +- switch (len) { +- case 1: +- *((__u8 *) opt->val) = val; +- break; +- +- case 2: +- *((__u16 *) opt->val) = __cpu_to_le16(val); +- break; +- +- case 4: +- *((__u32 *) opt->val) = __cpu_to_le32(val); +- break; +- }; +- +- *ptr += L2CAP_CONF_OPT_SIZE + len; +-} +- +-static int l2cap_build_conf_req(struct sock *sk, __u8 *data) +-{ +- struct l2cap_pinfo *pi = l2cap_pi(sk); +- l2cap_conf_req *req = (l2cap_conf_req *) data; +- __u8 *ptr = req->data; +- +- DBG("sk %p", sk); +- +- if (pi->imtu != L2CAP_DEFAULT_MTU) +- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu); +- +- /* FIXME. Need actual value of the flush timeout */ +- //if (flush_to != L2CAP_DEFAULT_FLUSH_TO) +- // l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to); +- +- req->dcid = __cpu_to_le16(pi->dcid); +- req->flags = __cpu_to_le16(0); +- +- return ptr - data; +-} +- +-static int l2cap_conf_output(struct sock *sk, __u8 **ptr) +-{ +- struct l2cap_pinfo *pi = l2cap_pi(sk); +- int result = 0; +- +- /* Configure output options and let other side know +- * which ones we don't like. +- */ +- if (pi->conf_mtu < pi->omtu) { +- l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, l2cap_pi(sk)->omtu); +- result = L2CAP_CONF_UNACCEPT; +- } else { +- pi->omtu = pi->conf_mtu; +- } +- +- DBG("sk %p result %d", sk, result); +- return result; +-} +- +-static int l2cap_build_conf_rsp(struct sock *sk, __u8 *data, int *result) +-{ +- l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data; +- __u8 *ptr = rsp->data; +- +- DBG("sk %p complete %d", sk, result ? 1 : 0); +- +- if (result) +- *result = l2cap_conf_output(sk, &ptr); +- +- rsp->scid = __cpu_to_le16(l2cap_pi(sk)->dcid); +- rsp->result = __cpu_to_le16(result ? *result : 0); +- rsp->flags = __cpu_to_le16(0); +- +- return ptr - data; +-} +- +-static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) +-{ +- struct l2cap_chan_list *list = &conn->chan_list; +- l2cap_conn_req *req = (l2cap_conn_req *) data; +- l2cap_conn_rsp rsp; +- struct sock *sk, *parent; +- +- __u16 scid = __le16_to_cpu(req->scid); +- __u16 psm = req->psm; +- +- DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid); +- +- /* Check if we have socket listening on psm */ +- if (!(parent = l2cap_get_sock_listen(&conn->src, psm))) +- goto reject; +- +- bh_lock_sock(parent); +- write_lock(&list->lock); +- +- /* Check if we already have channel with that dcid */ +- if (__l2cap_get_chan_by_dcid(list, scid)) +- goto unlock; +- +- /* Check for backlog size */ +- if (parent->ack_backlog > parent->max_ack_backlog) +- goto unlock; +- +- if (!(sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC))) +- goto unlock; +- +- l2cap_sock_init(sk, parent); +- +- bacpy(&l2cap_pi(sk)->src, &conn->src); +- bacpy(&l2cap_pi(sk)->dst, &conn->dst); +- l2cap_pi(sk)->psm = psm; +- l2cap_pi(sk)->dcid = scid; +- +- __l2cap_chan_add(conn, sk, parent); +- sk->state = BT_CONFIG; +- +- write_unlock(&list->lock); +- bh_unlock_sock(parent); +- +- rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid); +- rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid); +- rsp.result = __cpu_to_le16(0); +- rsp.status = __cpu_to_le16(0); +- l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp); +- +- return 0; +- +-unlock: +- write_unlock(&list->lock); +- bh_unlock_sock(parent); +- +-reject: +- rsp.scid = __cpu_to_le16(scid); +- rsp.dcid = __cpu_to_le16(0); +- rsp.status = __cpu_to_le16(0); +- rsp.result = __cpu_to_le16(L2CAP_CONN_NO_MEM); +- l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp); +- +- return 0; +-} +- +-static inline int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) +-{ +- l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data; +- __u16 scid, dcid, result, status; +- struct sock *sk; +- +- scid = __le16_to_cpu(rsp->scid); +- dcid = __le16_to_cpu(rsp->dcid); +- result = __le16_to_cpu(rsp->result); +- status = __le16_to_cpu(rsp->status); +- +- DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); +- +- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) +- return -ENOENT; +- +- bh_lock_sock(sk); +- +- if (!result) { +- char req[64]; +- +- sk->state = BT_CONFIG; +- l2cap_pi(sk)->dcid = dcid; +- l2cap_pi(sk)->conf_state |= CONF_REQ_SENT; +- +- l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req); +- } else { +- l2cap_chan_del(sk, ECONNREFUSED); +- } +- +- bh_unlock_sock(sk); +- return 0; +-} +- +-static inline int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) +-{ +- l2cap_conf_req * req = (l2cap_conf_req *) data; +- __u16 dcid, flags; +- __u8 rsp[64]; +- struct sock *sk; +- int result; +- +- dcid = __le16_to_cpu(req->dcid); +- flags = __le16_to_cpu(req->flags); +- +- DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags); +- +- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid))) +- return -ENOENT; +- +- bh_lock_sock(sk); +- +- l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE); +- +- if (flags & 0x01) { +- /* Incomplete config. Send empty response. */ +- l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp); +- goto unlock; +- } +- +- /* Complete config. */ +- l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp); +- +- if (result) +- goto unlock; +- +- /* Output config done */ +- l2cap_pi(sk)->conf_state |= CONF_OUTPUT_DONE; +- +- if (l2cap_pi(sk)->conf_state & CONF_INPUT_DONE) { +- sk->state = BT_CONNECTED; +- l2cap_chan_ready(sk); +- } else if (!(l2cap_pi(sk)->conf_state & CONF_REQ_SENT)) { +- char req[64]; +- l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req); +- } +- +-unlock: +- bh_unlock_sock(sk); +- +- return 0; +-} +- +-static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) +-{ +- l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data; +- __u16 scid, flags, result; +- struct sock *sk; +- int err = 0; +- +- scid = __le16_to_cpu(rsp->scid); +- flags = __le16_to_cpu(rsp->flags); +- result = __le16_to_cpu(rsp->result); +- +- DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result); +- +- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) +- return -ENOENT; +- +- bh_lock_sock(sk); +- +- if (result) { +- l2cap_disconn_req req; +- +- /* They didn't like our options. Well... we do not negotiate. +- * Close channel. +- */ +- sk->state = BT_DISCONN; +- +- req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid); +- req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); +- l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req); +- +- l2cap_sock_set_timer(sk, sk->sndtimeo); +- goto done; +- } +- +- if (flags & 0x01) +- goto done; +- +- /* Input config done */ +- l2cap_pi(sk)->conf_state |= CONF_INPUT_DONE; +- +- if (l2cap_pi(sk)->conf_state & CONF_OUTPUT_DONE) { +- sk->state = BT_CONNECTED; +- l2cap_chan_ready(sk); +- } +- +-done: +- bh_unlock_sock(sk); +- +- return err; +-} +- +-static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) +-{ +- l2cap_disconn_req *req = (l2cap_disconn_req *) data; +- l2cap_disconn_rsp rsp; +- __u16 dcid, scid; +- struct sock *sk; +- +- scid = __le16_to_cpu(req->scid); +- dcid = __le16_to_cpu(req->dcid); +- +- DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); +- +- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid))) +- return 0; +- +- bh_lock_sock(sk); +- +- rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid); +- rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid); +- l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp); +- +- l2cap_chan_del(sk, ECONNRESET); +- +- bh_unlock_sock(sk); +- +- l2cap_sock_kill(sk); +- +- return 0; +-} +- +-static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data) +-{ +- l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data; +- __u16 dcid, scid; +- struct sock *sk; +- +- scid = __le16_to_cpu(rsp->scid); +- dcid = __le16_to_cpu(rsp->dcid); +- +- DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); +- +- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) +- return -ENOENT; +- +- bh_lock_sock(sk); +- l2cap_sock_clear_timer(sk); +- l2cap_chan_del(sk, ECONNABORTED); +- bh_unlock_sock(sk); +- +- l2cap_sock_kill(sk); +- +- return 0; +-} +- +-static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb) +-{ +- __u8 *data = skb->data; +- int len = skb->len; +- l2cap_cmd_hdr cmd; +- int err = 0; +- +- while (len >= L2CAP_CMD_HDR_SIZE) { +- memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE); +- data += L2CAP_CMD_HDR_SIZE; +- len -= L2CAP_CMD_HDR_SIZE; +- +- cmd.len = __le16_to_cpu(cmd.len); +- +- DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident); +- +- if (cmd.len > len || !cmd.ident) { +- DBG("corrupted command"); +- break; +- } +- +- switch (cmd.code) { +- case L2CAP_CONN_REQ: +- err = l2cap_connect_req(conn, &cmd, data); +- break; +- +- case L2CAP_CONN_RSP: +- err = l2cap_connect_rsp(conn, &cmd, data); +- break; +- +- case L2CAP_CONF_REQ: +- err = l2cap_config_req(conn, &cmd, data); +- break; +- +- case L2CAP_CONF_RSP: +- err = l2cap_config_rsp(conn, &cmd, data); +- break; +- +- case L2CAP_DISCONN_REQ: +- err = l2cap_disconnect_req(conn, &cmd, data); +- break; +- +- case L2CAP_DISCONN_RSP: +- err = l2cap_disconnect_rsp(conn, &cmd, data); +- break; +- +- case L2CAP_COMMAND_REJ: +- /* FIXME: We should process this */ +- l2cap_raw_recv(conn, skb); +- break; +- +- case L2CAP_ECHO_REQ: +- l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data); +- break; +- +- case L2CAP_ECHO_RSP: +- case L2CAP_INFO_REQ: +- case L2CAP_INFO_RSP: +- l2cap_raw_recv(conn, skb); +- break; +- +- default: +- ERR("Uknown signaling command 0x%2.2x", cmd.code); +- err = -EINVAL; +- break; +- }; +- +- if (err) { +- l2cap_cmd_rej rej; +- DBG("error %d", err); +- +- /* FIXME: Map err to a valid reason. */ +- rej.reason = __cpu_to_le16(0); +- l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej); +- } +- +- data += cmd.len; +- len -= cmd.len; +- } +- +- kfree_skb(skb); +-} +- +-static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb) +-{ +- struct sock *sk; +- +- if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, cid))) { +- DBG("unknown cid 0x%4.4x", cid); +- goto drop; +- } +- +- DBG("sk %p, len %d", sk, skb->len); +- +- if (sk->state != BT_CONNECTED) +- goto drop; +- +- if (l2cap_pi(sk)->imtu < skb->len) +- goto drop; +- +- skb_queue_tail(&sk->receive_queue, skb); +- sk->data_ready(sk, skb->len); +- +- return 0; +- +-drop: +- kfree_skb(skb); +- +- return 0; +-} +- +-static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) +-{ +- l2cap_hdr *lh = (l2cap_hdr *) skb->data; +- __u16 cid, len; +- +- skb_pull(skb, L2CAP_HDR_SIZE); +- cid = __le16_to_cpu(lh->cid); +- len = __le16_to_cpu(lh->len); +- +- DBG("len %d, cid 0x%4.4x", len, cid); +- +- if (cid == 0x0001) +- l2cap_sig_channel(conn, skb); +- else +- l2cap_data_channel(conn, cid, skb); +-} +- +-/* ------------ L2CAP interface with lower layer (HCI) ------------- */ +-static int l2cap_dev_event(struct notifier_block *this, unsigned long event, void *ptr) +-{ +- struct hci_dev *hdev = (struct hci_dev *) ptr; +- +- DBG("hdev %s, event %ld", hdev->name, event); +- +- write_lock(&l2cap_rt_lock); +- +- switch (event) { +- case HCI_DEV_UP: +- l2cap_iff_add(hdev); +- break; +- +- case HCI_DEV_DOWN: +- l2cap_iff_del(hdev); +- break; +- }; +- +- write_unlock(&l2cap_rt_lock); +- +- return NOTIFY_DONE; +-} +- +-int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) +-{ +- struct l2cap_iff *iff; +- +- DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); +- +- if (!(iff = hdev->l2cap_data)) { +- ERR("unknown interface"); +- return 0; +- } +- +- /* Always accept connection */ +- return 1; +-} +- +-int l2cap_connect_cfm(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *hconn) +-{ +- struct l2cap_conn *conn; +- struct l2cap_iff *iff; +- int err = 0; +- +- DBG("hdev %s bdaddr %s hconn %p", hdev->name, batostr(bdaddr), hconn); +- +- if (!(iff = hdev->l2cap_data)) { +- ERR("unknown interface"); +- return 0; +- } +- +- l2cap_iff_lock(iff); +- +- conn = l2cap_get_conn_by_addr(iff, bdaddr); +- +- if (conn) { +- /* Outgoing connection */ +- DBG("Outgoing connection: %s -> %s, %p, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), conn, status); +- +- if (!status && hconn) { +- conn->state = BT_CONNECTED; +- conn->hconn = hconn; +- +- hconn->l2cap_data = (void *)conn; +- +- /* Establish channels */ +- l2cap_conn_ready(conn); +- } else { +- l2cap_conn_del(conn, bterr(status)); +- } +- } else { +- /* Incomming connection */ +- DBG("Incomming connection: %s -> %s, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), status); +- +- if (status || !hconn) +- goto done; +- +- if (!(conn = l2cap_conn_add(iff, bdaddr))) { +- err = -ENOMEM; +- goto done; +- } +- +- conn->hconn = hconn; +- hconn->l2cap_data = (void *)conn; +- +- conn->state = BT_CONNECTED; +- } +- +-done: +- l2cap_iff_unlock(iff); +- +- return err; +-} +- +-int l2cap_disconn_ind(struct hci_conn *hconn, __u8 reason) +-{ +- struct l2cap_conn *conn = hconn->l2cap_data; +- +- DBG("hconn %p reason %d", hconn, reason); +- +- if (!conn) { +- ERR("unknown connection"); +- return 0; +- } +- conn->hconn = NULL; +- +- l2cap_iff_lock(conn->iff); +- l2cap_conn_del(conn, bterr(reason)); +- l2cap_iff_unlock(conn->iff); +- +- return 0; +-} +- +-int l2cap_recv_acldata(struct hci_conn *hconn, struct sk_buff *skb, __u16 flags) +-{ +- struct l2cap_conn *conn = hconn->l2cap_data; +- +- if (!conn) { +- ERR("unknown connection %p", hconn); +- goto drop; +- } +- +- DBG("conn %p len %d flags 0x%x", conn, skb->len, flags); +- +- if (flags & ACL_START) { +- int flen, tlen, size; +- l2cap_hdr *lh; +- +- if (conn->rx_len) { +- ERR("Unexpected start frame (len %d)", skb->len); +- kfree_skb(conn->rx_skb); conn->rx_skb = NULL; +- conn->rx_len = 0; +- } +- +- if (skb->len < L2CAP_HDR_SIZE) { +- ERR("Frame is too small (len %d)", skb->len); +- goto drop; +- } +- +- lh = (l2cap_hdr *)skb->data; +- tlen = __le16_to_cpu(lh->len); +- flen = skb->len - L2CAP_HDR_SIZE; +- +- DBG("Start: total len %d, frag len %d", tlen, flen); +- +- if (flen == tlen) { +- /* Complete frame received */ +- l2cap_recv_frame(conn, skb); +- return 0; +- } +- +- /* Allocate skb for the complete frame (with header) */ +- size = L2CAP_HDR_SIZE + tlen; +- if (!(conn->rx_skb = bluez_skb_alloc(size, GFP_ATOMIC))) +- goto drop; +- +- memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len); +- +- conn->rx_len = tlen - flen; +- } else { +- DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len); +- +- if (!conn->rx_len) { +- ERR("Unexpected continuation frame (len %d)", skb->len); +- goto drop; +- } +- +- if (skb->len > conn->rx_len) { +- ERR("Fragment is too large (len %d)", skb->len); +- kfree_skb(conn->rx_skb); conn->rx_skb = NULL; +- goto drop; +- } +- +- memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len); +- conn->rx_len -= skb->len; +- +- if (!conn->rx_len) { +- /* Complete frame received */ +- l2cap_recv_frame(conn, conn->rx_skb); +- conn->rx_skb = NULL; +- } +- } +- +-drop: +- kfree_skb(skb); +- return 0; +-} +- +-struct proto_ops l2cap_sock_ops = { +- family: PF_BLUETOOTH, +- release: l2cap_sock_release, +- bind: l2cap_sock_bind, +- connect: l2cap_sock_connect, +- listen: l2cap_sock_listen, +- accept: l2cap_sock_accept, +- getname: l2cap_sock_getname, +- sendmsg: l2cap_sock_sendmsg, +- recvmsg: l2cap_sock_recvmsg, +- poll: l2cap_sock_poll, +- socketpair: sock_no_socketpair, +- ioctl: sock_no_ioctl, +- shutdown: sock_no_shutdown, +- setsockopt: l2cap_sock_setsockopt, +- getsockopt: l2cap_sock_getsockopt, +- mmap: sock_no_mmap +-}; +- +-struct net_proto_family l2cap_sock_family_ops = { +- family: PF_BLUETOOTH, +- create: l2cap_sock_create +-}; +- +-struct hci_proto l2cap_hci_proto = { +- name: "L2CAP", +- id: HCI_PROTO_L2CAP, +- connect_ind: l2cap_connect_ind, +- connect_cfm: l2cap_connect_cfm, +- disconn_ind: l2cap_disconn_ind, +- recv_acldata: l2cap_recv_acldata, +-}; +- +-struct notifier_block l2cap_nblock = { +- notifier_call: l2cap_dev_event +-}; +- +-int __init l2cap_init(void) +-{ +- INF("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc", +- VERSION); +- INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); +- +- if (bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops)) { +- ERR("Can't register L2CAP socket"); +- return -EPROTO; +- } +- +- if (hci_register_proto(&l2cap_hci_proto) < 0) { +- ERR("Can't register L2CAP protocol"); +- return -EPROTO; +- } +- +- hci_register_notifier(&l2cap_nblock); +- +- l2cap_register_proc(); +- +- return 0; +-} +- +-void l2cap_cleanup(void) +-{ +- l2cap_unregister_proc(); +- +- /* Unregister socket, protocol and notifier */ +- if (bluez_sock_unregister(BTPROTO_L2CAP)) +- ERR("Can't unregister L2CAP socket"); +- +- if (hci_unregister_proto(&l2cap_hci_proto) < 0) +- ERR("Can't unregister L2CAP protocol"); +- +- hci_unregister_notifier(&l2cap_nblock); +- +- /* We _must_ not have any sockets and/or connections +- * at this stage. +- */ +- +- /* Free interface list and unlock HCI devices */ +- { +- struct list_head *list = &l2cap_iff_list; +- +- while (!list_empty(list)) { +- struct l2cap_iff *iff; +- +- iff = list_entry(list->next, struct l2cap_iff, list); +- l2cap_iff_del(iff->hdev); +- } +- } +-} +- +-module_init(l2cap_init); +-module_exit(l2cap_cleanup); +- +-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); +-MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION); +-MODULE_LICENSE("GPL"); +- +diff -urN linux-2.4.18/net/bluetooth/l2cap_proc.c linux-2.4.18-mh9/net/bluetooth/l2cap_proc.c +--- linux-2.4.18/net/bluetooth/l2cap_proc.c Fri Sep 7 18:28:38 2001 ++++ linux-2.4.18-mh9/net/bluetooth/l2cap_proc.c Thu Jan 1 01:00:00 1970 +@@ -1,165 +0,0 @@ +-/* +- BlueZ - Bluetooth protocol stack for Linux +- Copyright (C) 2000-2001 Qualcomm Incorporated +- +- Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; +- +- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. +- IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY +- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES +- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +- +- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, +- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS +- SOFTWARE IS DISCLAIMED. +-*/ +- +-/* +- * BlueZ L2CAP proc fs support. +- * +- * $Id$ +- */ +- +-#include <linux/config.h> +-#include <linux/module.h> +- +-#include <linux/types.h> +-#include <linux/errno.h> +-#include <linux/kernel.h> +-#include <linux/major.h> +-#include <linux/sched.h> +-#include <linux/slab.h> +-#include <linux/poll.h> +-#include <linux/fcntl.h> +-#include <linux/init.h> +-#include <linux/skbuff.h> +-#include <linux/interrupt.h> +-#include <linux/socket.h> +-#include <linux/skbuff.h> +-#include <linux/proc_fs.h> +-#include <linux/list.h> +-#include <net/sock.h> +- +-#include <asm/system.h> +-#include <asm/uaccess.h> +- +-#include <net/bluetooth/bluez.h> +-#include <net/bluetooth/bluetooth.h> +-#include <net/bluetooth/hci_core.h> +-#include <net/bluetooth/l2cap_core.h> +- +-#ifndef L2CAP_DEBUG +-#undef DBG +-#define DBG( A... ) +-#endif +- +-/* ----- PROC fs support ----- */ +-static int l2cap_conn_dump(char *buf, struct l2cap_iff *iff) +-{ +- struct list_head *p; +- char *ptr = buf; +- +- list_for_each(p, &iff->conn_list) { +- struct l2cap_conn *c; +- +- c = list_entry(p, struct l2cap_conn, list); +- ptr += sprintf(ptr, " %p %d %p %p %s %s\n", +- c, c->state, c->iff, c->hconn, batostr(&c->src), batostr(&c->dst)); +- } +- +- return ptr - buf; +-} +- +-static int l2cap_iff_dump(char *buf) +-{ +- struct list_head *p; +- char *ptr = buf; +- +- ptr += sprintf(ptr, "Interfaces:\n"); +- +- write_lock(&l2cap_rt_lock); +- +- list_for_each(p, &l2cap_iff_list) { +- struct l2cap_iff *iff; +- +- iff = list_entry(p, struct l2cap_iff, list); +- +- ptr += sprintf(ptr, " %s %p %p\n", iff->hdev->name, iff, iff->hdev); +- +- l2cap_iff_lock(iff); +- ptr += l2cap_conn_dump(ptr, iff); +- l2cap_iff_unlock(iff); +- } +- +- write_unlock(&l2cap_rt_lock); +- +- ptr += sprintf(ptr, "\n"); +- +- return ptr - buf; +-} +- +-static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list) +-{ +- struct l2cap_pinfo *pi; +- struct sock *sk; +- char *ptr = buf; +- +- ptr += sprintf(ptr, "Sockets:\n"); +- +- write_lock(&list->lock); +- +- for (sk = list->head; sk; sk = sk->next) { +- pi = l2cap_pi(sk); +- ptr += sprintf(ptr, " %p %d %p %d %s %s 0x%4.4x 0x%4.4x %d %d\n", sk, sk->state, pi->conn, pi->psm, +- batostr(&pi->src), batostr(&pi->dst), pi->scid, pi->dcid, pi->imtu, pi->omtu ); +- } +- +- write_unlock(&list->lock); +- +- ptr += sprintf(ptr, "\n"); +- +- return ptr - buf; +-} +- +-static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv) +-{ +- char *ptr = buf; +- int len; +- +- DBG("count %d, offset %ld", count, offset); +- +- ptr += l2cap_iff_dump(ptr); +- ptr += l2cap_sock_dump(ptr, &l2cap_sk_list); +- len = ptr - buf; +- +- if (len <= count + offset) +- *eof = 1; +- +- *start = buf + offset; +- len -= offset; +- +- if (len > count) +- len = count; +- if (len < 0) +- len = 0; +- +- return len; +-} +- +-void l2cap_register_proc(void) +-{ +- create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL); +-} +- +-void l2cap_unregister_proc(void) +-{ +- remove_proc_entry("bluetooth/l2cap", NULL); +-} +diff -urN linux-2.4.18/net/bluetooth/lib.c linux-2.4.18-mh9/net/bluetooth/lib.c +--- linux-2.4.18/net/bluetooth/lib.c Fri Sep 7 18:28:38 2001 ++++ linux-2.4.18-mh9/net/bluetooth/lib.c Mon Aug 25 18:38:12 2003 +@@ -25,7 +25,7 @@ + /* + * BlueZ kernel library. + * +- * $Id$ ++ * $Id$ + */ + + #include <linux/kernel.h> +@@ -105,7 +105,7 @@ + return EACCES; + + case 0x06: +- return EINVAL; ++ return EBADE; + + case 0x07: + return ENOMEM; +diff -urN linux-2.4.18/net/bluetooth/rfcomm/Config.in linux-2.4.18-mh9/net/bluetooth/rfcomm/Config.in +--- linux-2.4.18/net/bluetooth/rfcomm/Config.in Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/rfcomm/Config.in Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,10 @@ ++# ++# Bluetooth RFCOMM layer configuration ++# ++ ++dep_tristate 'RFCOMM protocol support' CONFIG_BLUEZ_RFCOMM $CONFIG_BLUEZ_L2CAP ++ ++if [ "$CONFIG_BLUEZ_RFCOMM" != "n" ]; then ++ bool ' RFCOMM TTY support' CONFIG_BLUEZ_RFCOMM_TTY ++fi ++ +diff -urN linux-2.4.18/net/bluetooth/rfcomm/Makefile linux-2.4.18-mh9/net/bluetooth/rfcomm/Makefile +--- linux-2.4.18/net/bluetooth/rfcomm/Makefile Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/rfcomm/Makefile Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,11 @@ ++# ++# Makefile for the Linux Bluetooth RFCOMM layer ++# ++ ++O_TARGET := rfcomm.o ++ ++obj-y := core.o sock.o crc.o ++obj-$(CONFIG_BLUEZ_RFCOMM_TTY) += tty.o ++obj-m += $(O_TARGET) ++ ++include $(TOPDIR)/Rules.make +diff -urN linux-2.4.18/net/bluetooth/rfcomm/core.c linux-2.4.18-mh9/net/bluetooth/rfcomm/core.c +--- linux-2.4.18/net/bluetooth/rfcomm/core.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/rfcomm/core.c Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,1951 @@ ++/* ++ RFCOMM implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com> ++ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ RPN support - Dirk Husemann <hud@zurich.ibm.com> ++*/ ++ ++/* ++ * RFCOMM core. ++ * ++ * $Id$ ++ */ ++ ++#define __KERNEL_SYSCALLS__ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/signal.h> ++#include <linux/init.h> ++#include <linux/wait.h> ++#include <linux/net.h> ++#include <linux/proc_fs.h> ++#include <net/sock.h> ++#include <asm/uaccess.h> ++#include <asm/unaligned.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/l2cap.h> ++#include <net/bluetooth/rfcomm.h> ++ ++#define VERSION "1.0" ++ ++#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG ++#undef BT_DBG ++#define BT_DBG(D...) ++#endif ++ ++struct task_struct *rfcomm_thread; ++DECLARE_MUTEX(rfcomm_sem); ++unsigned long rfcomm_event; ++ ++static LIST_HEAD(session_list); ++static atomic_t terminate, running; ++ ++static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len); ++static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci); ++static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci); ++static int rfcomm_queue_disc(struct rfcomm_dlc *d); ++static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type); ++static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d); ++static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig); ++static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len); ++static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits); ++static void rfcomm_make_uih(struct sk_buff *skb, u8 addr); ++ ++static void rfcomm_process_connect(struct rfcomm_session *s); ++ ++/* ---- RFCOMM frame parsing macros ---- */ ++#define __get_dlci(b) ((b & 0xfc) >> 2) ++#define __get_channel(b) ((b & 0xf8) >> 3) ++#define __get_dir(b) ((b & 0x04) >> 2) ++#define __get_type(b) ((b & 0xef)) ++ ++#define __test_ea(b) ((b & 0x01)) ++#define __test_cr(b) ((b & 0x02)) ++#define __test_pf(b) ((b & 0x10)) ++ ++#define __addr(cr, dlci) (((dlci & 0x3f) << 2) | (cr << 1) | 0x01) ++#define __ctrl(type, pf) (((type & 0xef) | (pf << 4))) ++#define __dlci(dir, chn) (((chn & 0x1f) << 1) | dir) ++#define __srv_channel(dlci) (dlci >> 1) ++#define __dir(dlci) (dlci & 0x01) ++ ++#define __len8(len) (((len) << 1) | 1) ++#define __len16(len) ((len) << 1) ++ ++/* MCC macros */ ++#define __mcc_type(cr, type) (((type << 2) | (cr << 1) | 0x01)) ++#define __get_mcc_type(b) ((b & 0xfc) >> 2) ++#define __get_mcc_len(b) ((b & 0xfe) >> 1) ++ ++/* RPN macros */ ++#define __rpn_line_settings(data, stop, parity) ((data & 0x3) | ((stop & 0x1) << 2) | ((parity & 0x3) << 3)) ++#define __get_rpn_data_bits(line) ((line) & 0x3) ++#define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1) ++#define __get_rpn_parity(line) (((line) >> 3) & 0x3) ++ ++/* ---- RFCOMM FCS computation ---- */ ++ ++/* CRC on 2 bytes */ ++#define __crc(data) (rfcomm_crc_table[rfcomm_crc_table[0xff ^ data[0]] ^ data[1]]) ++ ++/* FCS on 2 bytes */ ++static inline u8 __fcs(u8 *data) ++{ ++ return (0xff - __crc(data)); ++} ++ ++/* FCS on 3 bytes */ ++static inline u8 __fcs2(u8 *data) ++{ ++ return (0xff - rfcomm_crc_table[__crc(data) ^ data[2]]); ++} ++ ++/* Check FCS */ ++static inline int __check_fcs(u8 *data, int type, u8 fcs) ++{ ++ u8 f = __crc(data); ++ ++ if (type != RFCOMM_UIH) ++ f = rfcomm_crc_table[f ^ data[2]]; ++ ++ return rfcomm_crc_table[f ^ fcs] != 0xcf; ++} ++ ++/* ---- L2CAP callbacks ---- */ ++static void rfcomm_l2state_change(struct sock *sk) ++{ ++ BT_DBG("%p state %d", sk, sk->state); ++ rfcomm_schedule(RFCOMM_SCHED_STATE); ++} ++ ++static void rfcomm_l2data_ready(struct sock *sk, int bytes) ++{ ++ BT_DBG("%p bytes %d", sk, bytes); ++ rfcomm_schedule(RFCOMM_SCHED_RX); ++} ++ ++static int rfcomm_l2sock_create(struct socket **sock) ++{ ++ int err; ++ ++ BT_DBG(""); ++ ++ err = sock_create(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP, sock); ++ if (!err) { ++ struct sock *sk = (*sock)->sk; ++ sk->data_ready = rfcomm_l2data_ready; ++ sk->state_change = rfcomm_l2state_change; ++ } ++ return err; ++} ++ ++/* ---- RFCOMM DLCs ---- */ ++static void rfcomm_dlc_timeout(unsigned long arg) ++{ ++ struct rfcomm_dlc *d = (void *) arg; ++ ++ BT_DBG("dlc %p state %ld", d, d->state); ++ ++ set_bit(RFCOMM_TIMED_OUT, &d->flags); ++ rfcomm_dlc_put(d); ++ rfcomm_schedule(RFCOMM_SCHED_TIMEO); ++} ++ ++static void rfcomm_dlc_set_timer(struct rfcomm_dlc *d, long timeout) ++{ ++ BT_DBG("dlc %p state %ld timeout %ld", d, d->state, timeout); ++ ++ if (!mod_timer(&d->timer, jiffies + timeout)) ++ rfcomm_dlc_hold(d); ++} ++ ++static void rfcomm_dlc_clear_timer(struct rfcomm_dlc *d) ++{ ++ BT_DBG("dlc %p state %ld", d, d->state); ++ ++ if (timer_pending(&d->timer) && del_timer(&d->timer)) ++ rfcomm_dlc_put(d); ++} ++ ++static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d) ++{ ++ BT_DBG("%p", d); ++ ++ d->state = BT_OPEN; ++ d->flags = 0; ++ d->mscex = 0; ++ d->mtu = RFCOMM_DEFAULT_MTU; ++ d->v24_sig = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV; ++ ++ d->credits = 0; ++ d->rx_credits = RFCOMM_DEFAULT_CREDITS; ++} ++ ++struct rfcomm_dlc *rfcomm_dlc_alloc(int prio) ++{ ++ struct rfcomm_dlc *d = kmalloc(sizeof(*d), prio); ++ if (!d) ++ return NULL; ++ memset(d, 0, sizeof(*d)); ++ ++ init_timer(&d->timer); ++ d->timer.function = rfcomm_dlc_timeout; ++ d->timer.data = (unsigned long) d; ++ ++ skb_queue_head_init(&d->tx_queue); ++ spin_lock_init(&d->lock); ++ atomic_set(&d->refcnt, 1); ++ ++ rfcomm_dlc_clear_state(d); ++ ++ BT_DBG("%p", d); ++ return d; ++} ++ ++void rfcomm_dlc_free(struct rfcomm_dlc *d) ++{ ++ BT_DBG("%p", d); ++ ++ skb_queue_purge(&d->tx_queue); ++ kfree(d); ++} ++ ++static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d) ++{ ++ BT_DBG("dlc %p session %p", d, s); ++ ++ rfcomm_session_hold(s); ++ ++ rfcomm_dlc_hold(d); ++ list_add(&d->list, &s->dlcs); ++ d->session = s; ++} ++ ++static void rfcomm_dlc_unlink(struct rfcomm_dlc *d) ++{ ++ struct rfcomm_session *s = d->session; ++ ++ BT_DBG("dlc %p refcnt %d session %p", d, atomic_read(&d->refcnt), s); ++ ++ list_del(&d->list); ++ d->session = NULL; ++ rfcomm_dlc_put(d); ++ ++ rfcomm_session_put(s); ++} ++ ++static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci) ++{ ++ struct rfcomm_dlc *d; ++ struct list_head *p; ++ ++ list_for_each(p, &s->dlcs) { ++ d = list_entry(p, struct rfcomm_dlc, list); ++ if (d->dlci == dlci) ++ return d; ++ } ++ return NULL; ++} ++ ++static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel) ++{ ++ struct rfcomm_session *s; ++ int err = 0; ++ u8 dlci; ++ ++ BT_DBG("dlc %p state %ld %s %s channel %d", ++ d, d->state, batostr(src), batostr(dst), channel); ++ ++ if (channel < 1 || channel > 30) ++ return -EINVAL; ++ ++ if (d->state != BT_OPEN && d->state != BT_CLOSED) ++ return 0; ++ ++ s = rfcomm_session_get(src, dst); ++ if (!s) { ++ s = rfcomm_session_create(src, dst, &err); ++ if (!s) ++ return err; ++ } ++ ++ dlci = __dlci(!s->initiator, channel); ++ ++ /* Check if DLCI already exists */ ++ if (rfcomm_dlc_get(s, dlci)) ++ return -EBUSY; ++ ++ rfcomm_dlc_clear_state(d); ++ ++ d->dlci = dlci; ++ d->addr = __addr(s->initiator, dlci); ++ d->priority = 7; ++ ++ d->state = BT_CONFIG; ++ rfcomm_dlc_link(s, d); ++ ++ d->mtu = s->mtu; ++ d->credits = s->credits; ++ ++ if (s->state == BT_CONNECTED) ++ rfcomm_send_pn(s, 1, d); ++ rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT); ++ return 0; ++} ++ ++int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel) ++{ ++ mm_segment_t fs; ++ int r; ++ ++ rfcomm_lock(); ++ ++ fs = get_fs(); set_fs(KERNEL_DS); ++ r = __rfcomm_dlc_open(d, src, dst, channel); ++ set_fs(fs); ++ ++ rfcomm_unlock(); ++ return r; ++} ++ ++static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) ++{ ++ struct rfcomm_session *s = d->session; ++ if (!s) ++ return 0; ++ ++ BT_DBG("dlc %p state %ld dlci %d err %d session %p", ++ d, d->state, d->dlci, err, s); ++ ++ switch (d->state) { ++ case BT_CONNECTED: ++ case BT_CONFIG: ++ case BT_CONNECT: ++ d->state = BT_DISCONN; ++ if (skb_queue_empty(&d->tx_queue)) { ++ rfcomm_send_disc(s, d->dlci); ++ rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT); ++ } else { ++ rfcomm_queue_disc(d); ++ rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2); ++ } ++ break; ++ ++ default: ++ rfcomm_dlc_clear_timer(d); ++ ++ rfcomm_dlc_lock(d); ++ d->state = BT_CLOSED; ++ d->state_change(d, err); ++ rfcomm_dlc_unlock(d); ++ ++ skb_queue_purge(&d->tx_queue); ++ rfcomm_dlc_unlink(d); ++ } ++ ++ return 0; ++} ++ ++int rfcomm_dlc_close(struct rfcomm_dlc *d, int err) ++{ ++ mm_segment_t fs; ++ int r; ++ ++ rfcomm_lock(); ++ ++ fs = get_fs(); set_fs(KERNEL_DS); ++ r = __rfcomm_dlc_close(d, err); ++ set_fs(fs); ++ ++ rfcomm_unlock(); ++ return r; ++} ++ ++int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb) ++{ ++ int len = skb->len; ++ ++ if (d->state != BT_CONNECTED) ++ return -ENOTCONN; ++ ++ BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len); ++ ++ if (len > d->mtu) ++ return -EINVAL; ++ ++ rfcomm_make_uih(skb, d->addr); ++ skb_queue_tail(&d->tx_queue, skb); ++ ++ if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags)) ++ rfcomm_schedule(RFCOMM_SCHED_TX); ++ return len; ++} ++ ++void __rfcomm_dlc_throttle(struct rfcomm_dlc *d) ++{ ++ BT_DBG("dlc %p state %ld", d, d->state); ++ ++ if (!d->credits) { ++ d->v24_sig |= RFCOMM_V24_FC; ++ set_bit(RFCOMM_MSC_PENDING, &d->flags); ++ } ++ rfcomm_schedule(RFCOMM_SCHED_TX); ++} ++ ++void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) ++{ ++ BT_DBG("dlc %p state %ld", d, d->state); ++ ++ if (!d->credits) { ++ d->v24_sig &= ~RFCOMM_V24_FC; ++ set_bit(RFCOMM_MSC_PENDING, &d->flags); ++ } ++ rfcomm_schedule(RFCOMM_SCHED_TX); ++} ++ ++/* ++ Set/get modem status functions use _local_ status i.e. what we report ++ to the other side. ++ Remote status is provided by dlc->modem_status() callback. ++ */ ++int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig) ++{ ++ BT_DBG("dlc %p state %ld v24_sig 0x%x", ++ d, d->state, v24_sig); ++ ++ if (test_bit(RFCOMM_RX_THROTTLED, &d->flags)) ++ v24_sig |= RFCOMM_V24_FC; ++ else ++ v24_sig &= ~RFCOMM_V24_FC; ++ ++ d->v24_sig = v24_sig; ++ ++ if (!test_and_set_bit(RFCOMM_MSC_PENDING, &d->flags)) ++ rfcomm_schedule(RFCOMM_SCHED_TX); ++ ++ return 0; ++} ++ ++int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig) ++{ ++ BT_DBG("dlc %p state %ld v24_sig 0x%x", ++ d, d->state, d->v24_sig); ++ ++ *v24_sig = d->v24_sig; ++ return 0; ++} ++ ++/* ---- RFCOMM sessions ---- */ ++struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state) ++{ ++ struct rfcomm_session *s = kmalloc(sizeof(*s), GFP_KERNEL); ++ if (!s) ++ return NULL; ++ memset(s, 0, sizeof(*s)); ++ ++ BT_DBG("session %p sock %p", s, sock); ++ ++ INIT_LIST_HEAD(&s->dlcs); ++ s->state = state; ++ s->sock = sock; ++ ++ s->mtu = RFCOMM_DEFAULT_MTU; ++ s->credits = 0; ++ ++ list_add(&s->list, &session_list); ++ ++ /* Do not increment module usage count for listeting sessions. ++ * Otherwise we won't be able to unload the module. */ ++ if (state != BT_LISTEN) ++ MOD_INC_USE_COUNT; ++ return s; ++} ++ ++void rfcomm_session_del(struct rfcomm_session *s) ++{ ++ int state = s->state; ++ ++ BT_DBG("session %p state %ld", s, s->state); ++ ++ list_del(&s->list); ++ ++ if (state == BT_CONNECTED) ++ rfcomm_send_disc(s, 0); ++ ++ sock_release(s->sock); ++ kfree(s); ++ ++ if (state != BT_LISTEN) ++ MOD_DEC_USE_COUNT; ++} ++ ++struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst) ++{ ++ struct rfcomm_session *s; ++ struct list_head *p, *n; ++ struct bluez_pinfo *pi; ++ list_for_each_safe(p, n, &session_list) { ++ s = list_entry(p, struct rfcomm_session, list); ++ pi = bluez_pi(s->sock->sk); ++ ++ if ((!bacmp(src, BDADDR_ANY) || !bacmp(&pi->src, src)) && ++ !bacmp(&pi->dst, dst)) ++ return s; ++ } ++ return NULL; ++} ++ ++void rfcomm_session_close(struct rfcomm_session *s, int err) ++{ ++ struct rfcomm_dlc *d; ++ struct list_head *p, *n; ++ ++ BT_DBG("session %p state %ld err %d", s, s->state, err); ++ ++ rfcomm_session_hold(s); ++ ++ s->state = BT_CLOSED; ++ ++ /* Close all dlcs */ ++ list_for_each_safe(p, n, &s->dlcs) { ++ d = list_entry(p, struct rfcomm_dlc, list); ++ d->state = BT_CLOSED; ++ __rfcomm_dlc_close(d, err); ++ } ++ ++ rfcomm_session_put(s); ++} ++ ++struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err) ++{ ++ struct rfcomm_session *s = NULL; ++ struct sockaddr_l2 addr; ++ struct l2cap_options opts; ++ struct socket *sock; ++ int size; ++ ++ BT_DBG("%s %s", batostr(src), batostr(dst)); ++ ++ *err = rfcomm_l2sock_create(&sock); ++ if (*err < 0) ++ return NULL; ++ ++ bacpy(&addr.l2_bdaddr, src); ++ addr.l2_family = AF_BLUETOOTH; ++ addr.l2_psm = 0; ++ *err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr)); ++ if (*err < 0) ++ goto failed; ++ ++ /* Set L2CAP options */ ++ size = sizeof(opts); ++ sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size); ++ ++ opts.imtu = RFCOMM_MAX_L2CAP_MTU; ++ sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size); ++ ++ s = rfcomm_session_add(sock, BT_BOUND); ++ if (!s) { ++ *err = -ENOMEM; ++ goto failed; ++ } ++ ++ s->initiator = 1; ++ ++ bacpy(&addr.l2_bdaddr, dst); ++ addr.l2_family = AF_BLUETOOTH; ++ addr.l2_psm = htobs(RFCOMM_PSM); ++ *err = sock->ops->connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK); ++ if (*err == 0 || *err == -EAGAIN) ++ return s; ++ ++ rfcomm_session_del(s); ++ return NULL; ++ ++failed: ++ sock_release(sock); ++ return NULL; ++} ++ ++void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst) ++{ ++ struct sock *sk = s->sock->sk; ++ if (src) ++ bacpy(src, &bluez_pi(sk)->src); ++ if (dst) ++ bacpy(dst, &bluez_pi(sk)->dst); ++} ++ ++/* ---- RFCOMM frame sending ---- */ ++static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len) ++{ ++ struct socket *sock = s->sock; ++ struct iovec iv = { data, len }; ++ struct msghdr msg; ++ int err; ++ ++ BT_DBG("session %p len %d", s, len); ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.msg_iovlen = 1; ++ msg.msg_iov = &iv; ++ ++ err = sock->ops->sendmsg(sock, &msg, len, 0); ++ return err; ++} ++ ++static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci) ++{ ++ struct rfcomm_cmd cmd; ++ ++ BT_DBG("%p dlci %d", s, dlci); ++ ++ cmd.addr = __addr(s->initiator, dlci); ++ cmd.ctrl = __ctrl(RFCOMM_SABM, 1); ++ cmd.len = __len8(0); ++ cmd.fcs = __fcs2((u8 *) &cmd); ++ ++ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd)); ++} ++ ++static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci) ++{ ++ struct rfcomm_cmd cmd; ++ ++ BT_DBG("%p dlci %d", s, dlci); ++ ++ cmd.addr = __addr(!s->initiator, dlci); ++ cmd.ctrl = __ctrl(RFCOMM_UA, 1); ++ cmd.len = __len8(0); ++ cmd.fcs = __fcs2((u8 *) &cmd); ++ ++ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd)); ++} ++ ++static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci) ++{ ++ struct rfcomm_cmd cmd; ++ ++ BT_DBG("%p dlci %d", s, dlci); ++ ++ cmd.addr = __addr(s->initiator, dlci); ++ cmd.ctrl = __ctrl(RFCOMM_DISC, 1); ++ cmd.len = __len8(0); ++ cmd.fcs = __fcs2((u8 *) &cmd); ++ ++ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd)); ++} ++ ++static int rfcomm_queue_disc(struct rfcomm_dlc *d) ++{ ++ struct rfcomm_cmd *cmd; ++ struct sk_buff *skb; ++ ++ BT_DBG("dlc %p dlci %d", d, d->dlci); ++ ++ skb = alloc_skb(sizeof(*cmd), GFP_KERNEL); ++ if (!skb) ++ return -ENOMEM; ++ ++ cmd = (void *) __skb_put(skb, sizeof(*cmd)); ++ cmd->addr = d->addr; ++ cmd->ctrl = __ctrl(RFCOMM_DISC, 1); ++ cmd->len = __len8(0); ++ cmd->fcs = __fcs2((u8 *) cmd); ++ ++ skb_queue_tail(&d->tx_queue, skb); ++ rfcomm_schedule(RFCOMM_SCHED_TX); ++ return 0; ++} ++ ++static int rfcomm_send_dm(struct rfcomm_session *s, u8 dlci) ++{ ++ struct rfcomm_cmd cmd; ++ ++ BT_DBG("%p dlci %d", s, dlci); ++ ++ cmd.addr = __addr(!s->initiator, dlci); ++ cmd.ctrl = __ctrl(RFCOMM_DM, 1); ++ cmd.len = __len8(0); ++ cmd.fcs = __fcs2((u8 *) &cmd); ++ ++ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd)); ++} ++ ++static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type) ++{ ++ struct rfcomm_hdr *hdr; ++ struct rfcomm_mcc *mcc; ++ u8 buf[16], *ptr = buf; ++ ++ BT_DBG("%p cr %d type %d", s, cr, type); ++ ++ hdr = (void *) ptr; ptr += sizeof(*hdr); ++ hdr->addr = __addr(s->initiator, 0); ++ hdr->ctrl = __ctrl(RFCOMM_UIH, 0); ++ hdr->len = __len8(sizeof(*mcc) + 1); ++ ++ mcc = (void *) ptr; ptr += sizeof(*mcc); ++ mcc->type = __mcc_type(cr, RFCOMM_NSC); ++ mcc->len = __len8(1); ++ ++ /* Type that we didn't like */ ++ *ptr = __mcc_type(cr, type); ptr++; ++ ++ *ptr = __fcs(buf); ptr++; ++ ++ return rfcomm_send_frame(s, buf, ptr - buf); ++} ++ ++static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d) ++{ ++ struct rfcomm_hdr *hdr; ++ struct rfcomm_mcc *mcc; ++ struct rfcomm_pn *pn; ++ u8 buf[16], *ptr = buf; ++ ++ BT_DBG("%p cr %d dlci %d mtu %d", s, cr, d->dlci, d->mtu); ++ ++ hdr = (void *) ptr; ptr += sizeof(*hdr); ++ hdr->addr = __addr(s->initiator, 0); ++ hdr->ctrl = __ctrl(RFCOMM_UIH, 0); ++ hdr->len = __len8(sizeof(*mcc) + sizeof(*pn)); ++ ++ mcc = (void *) ptr; ptr += sizeof(*mcc); ++ mcc->type = __mcc_type(cr, RFCOMM_PN); ++ mcc->len = __len8(sizeof(*pn)); ++ ++ pn = (void *) ptr; ptr += sizeof(*pn); ++ pn->dlci = d->dlci; ++ pn->priority = d->priority; ++ pn->ack_timer = 0; ++ pn->max_retrans = 0; ++ ++ if (cr || d->credits) { ++ pn->flow_ctrl = cr ? 0xf0 : 0xe0; ++ pn->credits = RFCOMM_DEFAULT_CREDITS; ++ } else { ++ pn->flow_ctrl = 0; ++ pn->credits = 0; ++ } ++ ++ pn->mtu = htobs(d->mtu); ++ ++ *ptr = __fcs(buf); ptr++; ++ ++ return rfcomm_send_frame(s, buf, ptr - buf); ++} ++ ++static int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci, ++ u8 bit_rate, u8 data_bits, u8 stop_bits, ++ u8 parity, u8 flow_ctrl_settings, ++ u8 xon_char, u8 xoff_char, u16 param_mask) ++{ ++ struct rfcomm_hdr *hdr; ++ struct rfcomm_mcc *mcc; ++ struct rfcomm_rpn *rpn; ++ u8 buf[16], *ptr = buf; ++ ++ BT_DBG("%p cr %d dlci %d bit_r 0x%x data_b 0x%x stop_b 0x%x parity 0x%x" ++ "flwc_s 0x%x xon_c 0x%x xoff_c 0x%x p_mask 0x%x", ++ s, cr, dlci, bit_rate, data_bits, stop_bits, parity, ++ flow_ctrl_settings, xon_char, xoff_char, param_mask); ++ ++ hdr = (void *) ptr; ptr += sizeof(*hdr); ++ hdr->addr = __addr(s->initiator, 0); ++ hdr->ctrl = __ctrl(RFCOMM_UIH, 0); ++ hdr->len = __len8(sizeof(*mcc) + sizeof(*rpn)); ++ ++ mcc = (void *) ptr; ptr += sizeof(*mcc); ++ mcc->type = __mcc_type(cr, RFCOMM_RPN); ++ mcc->len = __len8(sizeof(*rpn)); ++ ++ rpn = (void *) ptr; ptr += sizeof(*rpn); ++ rpn->dlci = __addr(1, dlci); ++ rpn->bit_rate = bit_rate; ++ rpn->line_settings = __rpn_line_settings(data_bits, stop_bits, parity); ++ rpn->flow_ctrl = flow_ctrl_settings; ++ rpn->xon_char = xon_char; ++ rpn->xoff_char = xoff_char; ++ rpn->param_mask = param_mask; ++ ++ *ptr = __fcs(buf); ptr++; ++ ++ return rfcomm_send_frame(s, buf, ptr - buf); ++} ++ ++static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status) ++{ ++ struct rfcomm_hdr *hdr; ++ struct rfcomm_mcc *mcc; ++ struct rfcomm_rls *rls; ++ u8 buf[16], *ptr = buf; ++ ++ BT_DBG("%p cr %d status 0x%x", s, cr, status); ++ ++ hdr = (void *) ptr; ptr += sizeof(*hdr); ++ hdr->addr = __addr(s->initiator, 0); ++ hdr->ctrl = __ctrl(RFCOMM_UIH, 0); ++ hdr->len = __len8(sizeof(*mcc) + sizeof(*rls)); ++ ++ mcc = (void *) ptr; ptr += sizeof(*mcc); ++ mcc->type = __mcc_type(cr, RFCOMM_RLS); ++ mcc->len = __len8(sizeof(*rls)); ++ ++ rls = (void *) ptr; ptr += sizeof(*rls); ++ rls->dlci = __addr(1, dlci); ++ rls->status = status; ++ ++ *ptr = __fcs(buf); ptr++; ++ ++ return rfcomm_send_frame(s, buf, ptr - buf); ++} ++ ++static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig) ++{ ++ struct rfcomm_hdr *hdr; ++ struct rfcomm_mcc *mcc; ++ struct rfcomm_msc *msc; ++ u8 buf[16], *ptr = buf; ++ ++ BT_DBG("%p cr %d v24 0x%x", s, cr, v24_sig); ++ ++ hdr = (void *) ptr; ptr += sizeof(*hdr); ++ hdr->addr = __addr(s->initiator, 0); ++ hdr->ctrl = __ctrl(RFCOMM_UIH, 0); ++ hdr->len = __len8(sizeof(*mcc) + sizeof(*msc)); ++ ++ mcc = (void *) ptr; ptr += sizeof(*mcc); ++ mcc->type = __mcc_type(cr, RFCOMM_MSC); ++ mcc->len = __len8(sizeof(*msc)); ++ ++ msc = (void *) ptr; ptr += sizeof(*msc); ++ msc->dlci = __addr(1, dlci); ++ msc->v24_sig = v24_sig | 0x01; ++ ++ *ptr = __fcs(buf); ptr++; ++ ++ return rfcomm_send_frame(s, buf, ptr - buf); ++} ++ ++static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr) ++{ ++ struct rfcomm_hdr *hdr; ++ struct rfcomm_mcc *mcc; ++ u8 buf[16], *ptr = buf; ++ ++ BT_DBG("%p cr %d", s, cr); ++ ++ hdr = (void *) ptr; ptr += sizeof(*hdr); ++ hdr->addr = __addr(s->initiator, 0); ++ hdr->ctrl = __ctrl(RFCOMM_UIH, 0); ++ hdr->len = __len8(sizeof(*mcc)); ++ ++ mcc = (void *) ptr; ptr += sizeof(*mcc); ++ mcc->type = __mcc_type(cr, RFCOMM_FCOFF); ++ mcc->len = __len8(0); ++ ++ *ptr = __fcs(buf); ptr++; ++ ++ return rfcomm_send_frame(s, buf, ptr - buf); ++} ++ ++static int rfcomm_send_fcon(struct rfcomm_session *s, int cr) ++{ ++ struct rfcomm_hdr *hdr; ++ struct rfcomm_mcc *mcc; ++ u8 buf[16], *ptr = buf; ++ ++ BT_DBG("%p cr %d", s, cr); ++ ++ hdr = (void *) ptr; ptr += sizeof(*hdr); ++ hdr->addr = __addr(s->initiator, 0); ++ hdr->ctrl = __ctrl(RFCOMM_UIH, 0); ++ hdr->len = __len8(sizeof(*mcc)); ++ ++ mcc = (void *) ptr; ptr += sizeof(*mcc); ++ mcc->type = __mcc_type(cr, RFCOMM_FCON); ++ mcc->len = __len8(0); ++ ++ *ptr = __fcs(buf); ptr++; ++ ++ return rfcomm_send_frame(s, buf, ptr - buf); ++} ++ ++static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len) ++{ ++ struct socket *sock = s->sock; ++ struct iovec iv[3]; ++ struct msghdr msg; ++ unsigned char hdr[5], crc[1]; ++ ++ if (len > 125) ++ return -EINVAL; ++ ++ BT_DBG("%p cr %d", s, cr); ++ ++ hdr[0] = __addr(s->initiator, 0); ++ hdr[1] = __ctrl(RFCOMM_UIH, 0); ++ hdr[2] = 0x01 | ((len + 2) << 1); ++ hdr[3] = 0x01 | ((cr & 0x01) << 1) | (RFCOMM_TEST << 2); ++ hdr[4] = 0x01 | (len << 1); ++ ++ crc[0] = __fcs(hdr); ++ ++ iv[0].iov_base = hdr; ++ iv[0].iov_len = 5; ++ iv[1].iov_base = pattern; ++ iv[1].iov_len = len; ++ iv[2].iov_base = crc; ++ iv[2].iov_len = 1; ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.msg_iovlen = 3; ++ msg.msg_iov = iv; ++ return sock->ops->sendmsg(sock, &msg, 6 + len, 0); ++} ++ ++static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits) ++{ ++ struct rfcomm_hdr *hdr; ++ u8 buf[16], *ptr = buf; ++ ++ BT_DBG("%p addr %d credits %d", s, addr, credits); ++ ++ hdr = (void *) ptr; ptr += sizeof(*hdr); ++ hdr->addr = addr; ++ hdr->ctrl = __ctrl(RFCOMM_UIH, 1); ++ hdr->len = __len8(0); ++ ++ *ptr = credits; ptr++; ++ ++ *ptr = __fcs(buf); ptr++; ++ ++ return rfcomm_send_frame(s, buf, ptr - buf); ++} ++ ++static void rfcomm_make_uih(struct sk_buff *skb, u8 addr) ++{ ++ struct rfcomm_hdr *hdr; ++ int len = skb->len; ++ u8 *crc; ++ ++ if (len > 127) { ++ hdr = (void *) skb_push(skb, 4); ++ put_unaligned(htobs(__len16(len)), (u16 *) &hdr->len); ++ } else { ++ hdr = (void *) skb_push(skb, 3); ++ hdr->len = __len8(len); ++ } ++ hdr->addr = addr; ++ hdr->ctrl = __ctrl(RFCOMM_UIH, 0); ++ ++ crc = skb_put(skb, 1); ++ *crc = __fcs((void *) hdr); ++} ++ ++/* ---- RFCOMM frame reception ---- */ ++static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci) ++{ ++ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); ++ ++ if (dlci) { ++ /* Data channel */ ++ struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci); ++ if (!d) { ++ rfcomm_send_dm(s, dlci); ++ return 0; ++ } ++ ++ switch (d->state) { ++ case BT_CONNECT: ++ rfcomm_dlc_clear_timer(d); ++ ++ rfcomm_dlc_lock(d); ++ d->state = BT_CONNECTED; ++ d->state_change(d, 0); ++ rfcomm_dlc_unlock(d); ++ ++ rfcomm_send_msc(s, 1, dlci, d->v24_sig); ++ break; ++ ++ case BT_DISCONN: ++ d->state = BT_CLOSED; ++ __rfcomm_dlc_close(d, 0); ++ break; ++ } ++ } else { ++ /* Control channel */ ++ switch (s->state) { ++ case BT_CONNECT: ++ s->state = BT_CONNECTED; ++ rfcomm_process_connect(s); ++ break; ++ } ++ } ++ return 0; ++} ++ ++static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci) ++{ ++ int err = 0; ++ ++ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); ++ ++ if (dlci) { ++ /* Data DLC */ ++ struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci); ++ if (d) { ++ if (d->state == BT_CONNECT || d->state == BT_CONFIG) ++ err = ECONNREFUSED; ++ else ++ err = ECONNRESET; ++ ++ d->state = BT_CLOSED; ++ __rfcomm_dlc_close(d, err); ++ } ++ } else { ++ if (s->state == BT_CONNECT) ++ err = ECONNREFUSED; ++ else ++ err = ECONNRESET; ++ ++ s->state = BT_CLOSED; ++ rfcomm_session_close(s, err); ++ } ++ return 0; ++} ++ ++static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci) ++{ ++ int err = 0; ++ ++ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); ++ ++ if (dlci) { ++ struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci); ++ if (d) { ++ rfcomm_send_ua(s, dlci); ++ ++ if (d->state == BT_CONNECT || d->state == BT_CONFIG) ++ err = ECONNREFUSED; ++ else ++ err = ECONNRESET; ++ ++ d->state = BT_CLOSED; ++ __rfcomm_dlc_close(d, err); ++ } else ++ rfcomm_send_dm(s, dlci); ++ ++ } else { ++ rfcomm_send_ua(s, 0); ++ ++ if (s->state == BT_CONNECT) ++ err = ECONNREFUSED; ++ else ++ err = ECONNRESET; ++ ++ s->state = BT_CLOSED; ++ rfcomm_session_close(s, err); ++ } ++ ++ return 0; ++} ++ ++static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci) ++{ ++ struct rfcomm_dlc *d; ++ u8 channel; ++ ++ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); ++ ++ if (!dlci) { ++ rfcomm_send_ua(s, 0); ++ ++ if (s->state == BT_OPEN) { ++ s->state = BT_CONNECTED; ++ rfcomm_process_connect(s); ++ } ++ return 0; ++ } ++ ++ /* Check if DLC exists */ ++ d = rfcomm_dlc_get(s, dlci); ++ if (d) { ++ if (d->state == BT_OPEN) { ++ /* DLC was previously opened by PN request */ ++ rfcomm_send_ua(s, dlci); ++ ++ rfcomm_dlc_lock(d); ++ d->state = BT_CONNECTED; ++ d->state_change(d, 0); ++ rfcomm_dlc_unlock(d); ++ ++ rfcomm_send_msc(s, 1, dlci, d->v24_sig); ++ } ++ return 0; ++ } ++ ++ /* Notify socket layer about incomming connection */ ++ channel = __srv_channel(dlci); ++ if (rfcomm_connect_ind(s, channel, &d)) { ++ d->dlci = dlci; ++ d->addr = __addr(s->initiator, dlci); ++ rfcomm_dlc_link(s, d); ++ ++ rfcomm_send_ua(s, dlci); ++ ++ rfcomm_dlc_lock(d); ++ d->state = BT_CONNECTED; ++ d->state_change(d, 0); ++ rfcomm_dlc_unlock(d); ++ ++ rfcomm_send_msc(s, 1, dlci, d->v24_sig); ++ } else { ++ rfcomm_send_dm(s, dlci); ++ } ++ ++ return 0; ++} ++ ++static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn) ++{ ++ struct rfcomm_session *s = d->session; ++ ++ BT_DBG("dlc %p state %ld dlci %d mtu %d fc 0x%x credits %d", ++ d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits); ++ ++ if (cr) { ++ if (pn->flow_ctrl == 0xf0) { ++ s->credits = RFCOMM_MAX_CREDITS; ++ d->credits = s->credits; ++ d->tx_credits = pn->credits; ++ } else { ++ set_bit(RFCOMM_TX_THROTTLED, &d->flags); ++ d->credits = 0; ++ } ++ } else { ++ if (pn->flow_ctrl == 0xe0) { ++ s->credits = RFCOMM_MAX_CREDITS; ++ d->credits = s->credits; ++ d->tx_credits = pn->credits; ++ } else { ++ set_bit(RFCOMM_TX_THROTTLED, &d->flags); ++ d->credits = 0; ++ } ++ } ++ ++ d->priority = pn->priority; ++ ++ d->mtu = btohs(pn->mtu); ++ ++ return 0; ++} ++ ++static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb) ++{ ++ struct rfcomm_pn *pn = (void *) skb->data; ++ struct rfcomm_dlc *d; ++ u8 dlci = pn->dlci; ++ ++ BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); ++ ++ if (!dlci) ++ return 0; ++ ++ d = rfcomm_dlc_get(s, dlci); ++ if (d) { ++ if (cr) { ++ /* PN request */ ++ rfcomm_apply_pn(d, cr, pn); ++ rfcomm_send_pn(s, 0, d); ++ } else { ++ /* PN response */ ++ switch (d->state) { ++ case BT_CONFIG: ++ rfcomm_apply_pn(d, cr, pn); ++ ++ d->state = BT_CONNECT; ++ rfcomm_send_sabm(s, d->dlci); ++ break; ++ } ++ } ++ } else { ++ u8 channel = __srv_channel(dlci); ++ ++ if (!cr) ++ return 0; ++ ++ /* PN request for non existing DLC. ++ * Assume incomming connection. */ ++ if (rfcomm_connect_ind(s, channel, &d)) { ++ d->dlci = dlci; ++ d->addr = __addr(s->initiator, dlci); ++ rfcomm_dlc_link(s, d); ++ ++ rfcomm_apply_pn(d, cr, pn); ++ ++ d->state = BT_OPEN; ++ rfcomm_send_pn(s, 0, d); ++ } else { ++ rfcomm_send_dm(s, dlci); ++ } ++ } ++ return 0; ++} ++ ++static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb) ++{ ++ struct rfcomm_rpn *rpn = (void *) skb->data; ++ u8 dlci = __get_dlci(rpn->dlci); ++ ++ u8 bit_rate = 0; ++ u8 data_bits = 0; ++ u8 stop_bits = 0; ++ u8 parity = 0; ++ u8 flow_ctrl = 0; ++ u8 xon_char = 0; ++ u8 xoff_char = 0; ++ u16 rpn_mask = RFCOMM_RPN_PM_ALL; ++ ++ BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", ++ dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl, ++ rpn->xon_char, rpn->xoff_char, rpn->param_mask); ++ ++ if (!cr) ++ return 0; ++ ++ if (len == 1) { ++ /* request: return default setting */ ++ bit_rate = RFCOMM_RPN_BR_115200; ++ data_bits = RFCOMM_RPN_DATA_8; ++ stop_bits = RFCOMM_RPN_STOP_1; ++ parity = RFCOMM_RPN_PARITY_NONE; ++ flow_ctrl = RFCOMM_RPN_FLOW_NONE; ++ xon_char = RFCOMM_RPN_XON_CHAR; ++ xoff_char = RFCOMM_RPN_XOFF_CHAR; ++ ++ goto rpn_out; ++ } ++ /* check for sane values: ignore/accept bit_rate, 8 bits, 1 stop bit, no parity, ++ no flow control lines, normal XON/XOFF chars */ ++ if (rpn->param_mask & RFCOMM_RPN_PM_BITRATE) { ++ bit_rate = rpn->bit_rate; ++ if (bit_rate != RFCOMM_RPN_BR_115200) { ++ BT_DBG("RPN bit rate mismatch 0x%x", bit_rate); ++ bit_rate = RFCOMM_RPN_BR_115200; ++ rpn_mask ^= RFCOMM_RPN_PM_BITRATE; ++ } ++ } ++ if (rpn->param_mask & RFCOMM_RPN_PM_DATA) { ++ data_bits = __get_rpn_data_bits(rpn->line_settings); ++ if (data_bits != RFCOMM_RPN_DATA_8) { ++ BT_DBG("RPN data bits mismatch 0x%x", data_bits); ++ data_bits = RFCOMM_RPN_DATA_8; ++ rpn_mask ^= RFCOMM_RPN_PM_DATA; ++ } ++ } ++ if (rpn->param_mask & RFCOMM_RPN_PM_STOP) { ++ stop_bits = __get_rpn_stop_bits(rpn->line_settings); ++ if (stop_bits != RFCOMM_RPN_STOP_1) { ++ BT_DBG("RPN stop bits mismatch 0x%x", stop_bits); ++ stop_bits = RFCOMM_RPN_STOP_1; ++ rpn_mask ^= RFCOMM_RPN_PM_STOP; ++ } ++ } ++ if (rpn->param_mask & RFCOMM_RPN_PM_PARITY) { ++ parity = __get_rpn_parity(rpn->line_settings); ++ if (parity != RFCOMM_RPN_PARITY_NONE) { ++ BT_DBG("RPN parity mismatch 0x%x", parity); ++ parity = RFCOMM_RPN_PARITY_NONE; ++ rpn_mask ^= RFCOMM_RPN_PM_PARITY; ++ } ++ } ++ if (rpn->param_mask & RFCOMM_RPN_PM_FLOW) { ++ flow_ctrl = rpn->flow_ctrl; ++ if (flow_ctrl != RFCOMM_RPN_FLOW_NONE) { ++ BT_DBG("RPN flow ctrl mismatch 0x%x", flow_ctrl); ++ flow_ctrl = RFCOMM_RPN_FLOW_NONE; ++ rpn_mask ^= RFCOMM_RPN_PM_FLOW; ++ } ++ } ++ if (rpn->param_mask & RFCOMM_RPN_PM_XON) { ++ xon_char = rpn->xon_char; ++ if (xon_char != RFCOMM_RPN_XON_CHAR) { ++ BT_DBG("RPN XON char mismatch 0x%x", xon_char); ++ xon_char = RFCOMM_RPN_XON_CHAR; ++ rpn_mask ^= RFCOMM_RPN_PM_XON; ++ } ++ } ++ if (rpn->param_mask & RFCOMM_RPN_PM_XOFF) { ++ xoff_char = rpn->xoff_char; ++ if (xoff_char != RFCOMM_RPN_XOFF_CHAR) { ++ BT_DBG("RPN XOFF char mismatch 0x%x", xoff_char); ++ xoff_char = RFCOMM_RPN_XOFF_CHAR; ++ rpn_mask ^= RFCOMM_RPN_PM_XOFF; ++ } ++ } ++ ++rpn_out: ++ rfcomm_send_rpn(s, 0, dlci, ++ bit_rate, data_bits, stop_bits, parity, flow_ctrl, ++ xon_char, xoff_char, rpn_mask); ++ ++ return 0; ++} ++ ++static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb) ++{ ++ struct rfcomm_rls *rls = (void *) skb->data; ++ u8 dlci = __get_dlci(rls->dlci); ++ ++ BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status); ++ ++ if (!cr) ++ return 0; ++ ++ /* FIXME: We should probably do something with this ++ information here. But for now it's sufficient just ++ to reply -- Bluetooth 1.1 says it's mandatory to ++ recognise and respond to RLS */ ++ ++ rfcomm_send_rls(s, 0, dlci, rls->status); ++ ++ return 0; ++} ++ ++static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb) ++{ ++ struct rfcomm_msc *msc = (void *) skb->data; ++ struct rfcomm_dlc *d; ++ u8 dlci = __get_dlci(msc->dlci); ++ ++ BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig); ++ ++ d = rfcomm_dlc_get(s, dlci); ++ if (!d) ++ return 0; ++ ++ if (cr) { ++ if (msc->v24_sig & RFCOMM_V24_FC && !d->credits) ++ set_bit(RFCOMM_TX_THROTTLED, &d->flags); ++ else ++ clear_bit(RFCOMM_TX_THROTTLED, &d->flags); ++ ++ rfcomm_dlc_lock(d); ++ if (d->modem_status) ++ d->modem_status(d, msc->v24_sig); ++ rfcomm_dlc_unlock(d); ++ ++ rfcomm_send_msc(s, 0, dlci, msc->v24_sig); ++ ++ d->mscex |= RFCOMM_MSCEX_RX; ++ } else ++ d->mscex |= RFCOMM_MSCEX_TX; ++ ++ return 0; ++} ++ ++static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb) ++{ ++ struct rfcomm_mcc *mcc = (void *) skb->data; ++ u8 type, cr, len; ++ ++ cr = __test_cr(mcc->type); ++ type = __get_mcc_type(mcc->type); ++ len = __get_mcc_len(mcc->len); ++ ++ BT_DBG("%p type 0x%x cr %d", s, type, cr); ++ ++ skb_pull(skb, 2); ++ ++ switch (type) { ++ case RFCOMM_PN: ++ rfcomm_recv_pn(s, cr, skb); ++ break; ++ ++ case RFCOMM_RPN: ++ rfcomm_recv_rpn(s, cr, len, skb); ++ break; ++ ++ case RFCOMM_RLS: ++ rfcomm_recv_rls(s, cr, skb); ++ break; ++ ++ case RFCOMM_MSC: ++ rfcomm_recv_msc(s, cr, skb); ++ break; ++ ++ case RFCOMM_FCOFF: ++ if (cr) { ++ set_bit(RFCOMM_TX_THROTTLED, &s->flags); ++ rfcomm_send_fcoff(s, 0); ++ } ++ break; ++ ++ case RFCOMM_FCON: ++ if (cr) { ++ clear_bit(RFCOMM_TX_THROTTLED, &s->flags); ++ rfcomm_send_fcon(s, 0); ++ } ++ break; ++ ++ case RFCOMM_TEST: ++ if (cr) ++ rfcomm_send_test(s, 0, skb->data, skb->len); ++ break; ++ ++ case RFCOMM_NSC: ++ break; ++ ++ default: ++ BT_ERR("Unknown control type 0x%02x", type); ++ rfcomm_send_nsc(s, cr, type); ++ break; ++ } ++ return 0; ++} ++ ++static int rfcomm_recv_data(struct rfcomm_session *s, u8 dlci, int pf, struct sk_buff *skb) ++{ ++ struct rfcomm_dlc *d; ++ ++ BT_DBG("session %p state %ld dlci %d pf %d", s, s->state, dlci, pf); ++ ++ d = rfcomm_dlc_get(s, dlci); ++ if (!d) { ++ rfcomm_send_dm(s, dlci); ++ goto drop; ++ } ++ ++ if (pf && d->credits) { ++ u8 credits = *(u8 *) skb->data; skb_pull(skb, 1); ++ ++ d->tx_credits += credits; ++ if (d->tx_credits) ++ clear_bit(RFCOMM_TX_THROTTLED, &d->flags); ++ } ++ ++ if (skb->len && d->state == BT_CONNECTED) { ++ rfcomm_dlc_lock(d); ++ d->rx_credits--; ++ d->data_ready(d, skb); ++ rfcomm_dlc_unlock(d); ++ return 0; ++ } ++ ++drop: ++ kfree_skb(skb); ++ return 0; ++} ++ ++static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb) ++{ ++ struct rfcomm_hdr *hdr = (void *) skb->data; ++ u8 type, dlci, fcs; ++ ++ dlci = __get_dlci(hdr->addr); ++ type = __get_type(hdr->ctrl); ++ ++ /* Trim FCS */ ++ skb->len--; skb->tail--; ++ fcs = *(u8 *) skb->tail; ++ ++ if (__check_fcs(skb->data, type, fcs)) { ++ BT_ERR("bad checksum in packet"); ++ kfree_skb(skb); ++ return -EILSEQ; ++ } ++ ++ if (__test_ea(hdr->len)) ++ skb_pull(skb, 3); ++ else ++ skb_pull(skb, 4); ++ ++ switch (type) { ++ case RFCOMM_SABM: ++ if (__test_pf(hdr->ctrl)) ++ rfcomm_recv_sabm(s, dlci); ++ break; ++ ++ case RFCOMM_DISC: ++ if (__test_pf(hdr->ctrl)) ++ rfcomm_recv_disc(s, dlci); ++ break; ++ ++ case RFCOMM_UA: ++ if (__test_pf(hdr->ctrl)) ++ rfcomm_recv_ua(s, dlci); ++ break; ++ ++ case RFCOMM_DM: ++ rfcomm_recv_dm(s, dlci); ++ break; ++ ++ case RFCOMM_UIH: ++ if (dlci) ++ return rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb); ++ ++ rfcomm_recv_mcc(s, skb); ++ break; ++ ++ default: ++ BT_ERR("Unknown packet type 0x%02x\n", type); ++ break; ++ } ++ kfree_skb(skb); ++ return 0; ++} ++ ++/* ---- Connection and data processing ---- */ ++ ++static void rfcomm_process_connect(struct rfcomm_session *s) ++{ ++ struct rfcomm_dlc *d; ++ struct list_head *p, *n; ++ ++ BT_DBG("session %p state %ld", s, s->state); ++ ++ list_for_each_safe(p, n, &s->dlcs) { ++ d = list_entry(p, struct rfcomm_dlc, list); ++ if (d->state == BT_CONFIG) { ++ d->mtu = s->mtu; ++ rfcomm_send_pn(s, 1, d); ++ } ++ } ++} ++ ++/* Send data queued for the DLC. ++ * Return number of frames left in the queue. ++ */ ++static inline int rfcomm_process_tx(struct rfcomm_dlc *d) ++{ ++ struct sk_buff *skb; ++ int err; ++ ++ BT_DBG("dlc %p state %ld credits %d rx_credits %d tx_credits %d", ++ d, d->state, d->credits, d->rx_credits, d->tx_credits); ++ ++ /* Send pending MSC */ ++ if (test_and_clear_bit(RFCOMM_MSC_PENDING, &d->flags)) ++ rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig); ++ ++ if (d->credits) { ++ /* CFC enabled. ++ * Give them some credits */ ++ if (!test_bit(RFCOMM_RX_THROTTLED, &d->flags) && ++ d->rx_credits <= (d->credits >> 2)) { ++ rfcomm_send_credits(d->session, d->addr, d->credits - d->rx_credits); ++ d->rx_credits = d->credits; ++ } ++ } else { ++ /* CFC disabled. ++ * Give ourselves some credits */ ++ d->tx_credits = 5; ++ } ++ ++ if (test_bit(RFCOMM_TX_THROTTLED, &d->flags)) ++ return skb_queue_len(&d->tx_queue); ++ ++ while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) { ++ err = rfcomm_send_frame(d->session, skb->data, skb->len); ++ if (err < 0) { ++ skb_queue_head(&d->tx_queue, skb); ++ break; ++ } ++ kfree_skb(skb); ++ d->tx_credits--; ++ } ++ ++ if (d->credits && !d->tx_credits) { ++ /* We're out of TX credits. ++ * Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */ ++ set_bit(RFCOMM_TX_THROTTLED, &d->flags); ++ } ++ ++ return skb_queue_len(&d->tx_queue); ++} ++ ++static inline void rfcomm_process_dlcs(struct rfcomm_session *s) ++{ ++ struct rfcomm_dlc *d; ++ struct list_head *p, *n; ++ ++ BT_DBG("session %p state %ld", s, s->state); ++ ++ list_for_each_safe(p, n, &s->dlcs) { ++ d = list_entry(p, struct rfcomm_dlc, list); ++ if (test_bit(RFCOMM_TIMED_OUT, &d->flags)) { ++ __rfcomm_dlc_close(d, ETIMEDOUT); ++ continue; ++ } ++ ++ if (test_bit(RFCOMM_TX_THROTTLED, &s->flags)) ++ continue; ++ ++ if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) && ++ d->mscex == RFCOMM_MSCEX_OK) ++ rfcomm_process_tx(d); ++ } ++} ++ ++static inline void rfcomm_process_rx(struct rfcomm_session *s) ++{ ++ struct socket *sock = s->sock; ++ struct sock *sk = sock->sk; ++ struct sk_buff *skb; ++ ++ BT_DBG("session %p state %ld qlen %d", s, s->state, skb_queue_len(&sk->receive_queue)); ++ ++ /* Get data directly from socket receive queue without copying it. */ ++ while ((skb = skb_dequeue(&sk->receive_queue))) { ++ skb_orphan(skb); ++ rfcomm_recv_frame(s, skb); ++ } ++ ++ if (sk->state == BT_CLOSED) { ++ if (!s->initiator) ++ rfcomm_session_put(s); ++ ++ rfcomm_session_close(s, sk->err); ++ } ++} ++ ++static inline void rfcomm_accept_connection(struct rfcomm_session *s) ++{ ++ struct socket *sock = s->sock, *nsock; ++ int err; ++ ++ /* Fast check for a new connection. ++ * Avoids unnesesary socket allocations. */ ++ if (list_empty(&bluez_pi(sock->sk)->accept_q)) ++ return; ++ ++ BT_DBG("session %p", s); ++ ++ nsock = sock_alloc(); ++ if (!nsock) ++ return; ++ ++ nsock->type = sock->type; ++ nsock->ops = sock->ops; ++ ++ err = sock->ops->accept(sock, nsock, O_NONBLOCK); ++ if (err < 0) { ++ sock_release(nsock); ++ return; ++ } ++ ++ /* Set our callbacks */ ++ nsock->sk->data_ready = rfcomm_l2data_ready; ++ nsock->sk->state_change = rfcomm_l2state_change; ++ ++ s = rfcomm_session_add(nsock, BT_OPEN); ++ if (s) ++ rfcomm_session_hold(s); ++ else ++ sock_release(nsock); ++} ++ ++static inline void rfcomm_check_connection(struct rfcomm_session *s) ++{ ++ struct sock *sk = s->sock->sk; ++ ++ BT_DBG("%p state %ld", s, s->state); ++ ++ switch(sk->state) { ++ case BT_CONNECTED: ++ s->state = BT_CONNECT; ++ ++ /* We can adjust MTU on outgoing sessions. ++ * L2CAP MTU minus UIH header and FCS. */ ++ s->mtu = min(l2cap_pi(sk)->omtu, l2cap_pi(sk)->imtu) - 5; ++ ++ rfcomm_send_sabm(s, 0); ++ break; ++ ++ case BT_CLOSED: ++ s->state = BT_CLOSED; ++ rfcomm_session_close(s, sk->err); ++ break; ++ } ++} ++ ++static inline void rfcomm_process_sessions(void) ++{ ++ struct list_head *p, *n; ++ ++ rfcomm_lock(); ++ ++ list_for_each_safe(p, n, &session_list) { ++ struct rfcomm_session *s; ++ s = list_entry(p, struct rfcomm_session, list); ++ ++ if (s->state == BT_LISTEN) { ++ rfcomm_accept_connection(s); ++ continue; ++ } ++ ++ rfcomm_session_hold(s); ++ ++ switch (s->state) { ++ case BT_BOUND: ++ rfcomm_check_connection(s); ++ break; ++ ++ default: ++ rfcomm_process_rx(s); ++ break; ++ } ++ ++ rfcomm_process_dlcs(s); ++ ++ rfcomm_session_put(s); ++ } ++ ++ rfcomm_unlock(); ++} ++ ++static void rfcomm_worker(void) ++{ ++ BT_DBG(""); ++ ++ daemonize(); reparent_to_init(); ++ set_fs(KERNEL_DS); ++ ++ while (!atomic_read(&terminate)) { ++ BT_DBG("worker loop event 0x%lx", rfcomm_event); ++ ++ if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) { ++ /* No pending events. Let's sleep. ++ * Incomming connections and data will wake us up. */ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule(); ++ } ++ ++ /* Process stuff */ ++ clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event); ++ rfcomm_process_sessions(); ++ } ++ set_current_state(TASK_RUNNING); ++ return; ++} ++ ++static int rfcomm_add_listener(bdaddr_t *ba) ++{ ++ struct sockaddr_l2 addr; ++ struct l2cap_options opts; ++ struct socket *sock; ++ struct rfcomm_session *s; ++ int size, err = 0; ++ ++ /* Create socket */ ++ err = rfcomm_l2sock_create(&sock); ++ if (err < 0) { ++ BT_ERR("Create socket failed %d", err); ++ return err; ++ } ++ ++ /* Bind socket */ ++ bacpy(&addr.l2_bdaddr, ba); ++ addr.l2_family = AF_BLUETOOTH; ++ addr.l2_psm = htobs(RFCOMM_PSM); ++ err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr)); ++ if (err < 0) { ++ BT_ERR("Bind failed %d", err); ++ goto failed; ++ } ++ ++ /* Set L2CAP options */ ++ size = sizeof(opts); ++ sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size); ++ ++ opts.imtu = RFCOMM_MAX_L2CAP_MTU; ++ sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size); ++ ++ /* Start listening on the socket */ ++ err = sock->ops->listen(sock, 10); ++ if (err) { ++ BT_ERR("Listen failed %d", err); ++ goto failed; ++ } ++ ++ /* Add listening session */ ++ s = rfcomm_session_add(sock, BT_LISTEN); ++ if (!s) ++ goto failed; ++ ++ rfcomm_session_hold(s); ++ return 0; ++failed: ++ sock_release(sock); ++ return err; ++} ++ ++static void rfcomm_kill_listener(void) ++{ ++ struct rfcomm_session *s; ++ struct list_head *p, *n; ++ ++ BT_DBG(""); ++ ++ list_for_each_safe(p, n, &session_list) { ++ s = list_entry(p, struct rfcomm_session, list); ++ rfcomm_session_del(s); ++ } ++} ++ ++static int rfcomm_run(void *unused) ++{ ++ rfcomm_thread = current; ++ ++ atomic_inc(&running); ++ ++ daemonize(); reparent_to_init(); ++ ++ sigfillset(¤t->blocked); ++ set_fs(KERNEL_DS); ++ ++ sprintf(current->comm, "krfcommd"); ++ ++ BT_DBG(""); ++ ++ rfcomm_add_listener(BDADDR_ANY); ++ ++ rfcomm_worker(); ++ ++ rfcomm_kill_listener(); ++ ++ atomic_dec(&running); ++ return 0; ++} ++ ++/* ---- Proc fs support ---- */ ++static int rfcomm_dlc_dump(char *buf) ++{ ++ struct rfcomm_session *s; ++ struct sock *sk; ++ struct list_head *p, *pp; ++ char *ptr = buf; ++ ++ rfcomm_lock(); ++ ++ list_for_each(p, &session_list) { ++ s = list_entry(p, struct rfcomm_session, list); ++ sk = s->sock->sk; ++ ++ list_for_each(pp, &s->dlcs) { ++ struct rfcomm_dlc *d; ++ d = list_entry(pp, struct rfcomm_dlc, list); ++ ++ ptr += sprintf(ptr, "dlc %s %s %ld %d %d %d %d\n", ++ batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst), ++ d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits); ++ } ++ } ++ ++ rfcomm_unlock(); ++ ++ return ptr - buf; ++} ++ ++extern int rfcomm_sock_dump(char *buf); ++ ++static int rfcomm_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv) ++{ ++ char *ptr = buf; ++ int len; ++ ++ BT_DBG("count %d, offset %ld", count, offset); ++ ++ ptr += rfcomm_dlc_dump(ptr); ++ ptr += rfcomm_sock_dump(ptr); ++ len = ptr - buf; ++ ++ if (len <= count + offset) ++ *eof = 1; ++ ++ *start = buf + offset; ++ len -= offset; ++ ++ if (len > count) ++ len = count; ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++ ++/* ---- Initialization ---- */ ++int __init rfcomm_init(void) ++{ ++ l2cap_load(); ++ ++ kernel_thread(rfcomm_run, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); ++ ++ rfcomm_init_sockets(); ++ ++#ifdef CONFIG_BLUEZ_RFCOMM_TTY ++ rfcomm_init_ttys(); ++#endif ++ ++ create_proc_read_entry("bluetooth/rfcomm", 0, 0, rfcomm_read_proc, NULL); ++ ++ BT_INFO("BlueZ RFCOMM ver %s", VERSION); ++ BT_INFO("Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>"); ++ BT_INFO("Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>"); ++ return 0; ++} ++ ++void rfcomm_cleanup(void) ++{ ++ /* Terminate working thread. ++ * ie. Set terminate flag and wake it up */ ++ atomic_inc(&terminate); ++ rfcomm_schedule(RFCOMM_SCHED_STATE); ++ ++ /* Wait until thread is running */ ++ while (atomic_read(&running)) ++ schedule(); ++ ++ remove_proc_entry("bluetooth/rfcomm", NULL); ++ ++#ifdef CONFIG_BLUEZ_RFCOMM_TTY ++ rfcomm_cleanup_ttys(); ++#endif ++ ++ rfcomm_cleanup_sockets(); ++ return; ++} ++ ++module_init(rfcomm_init); ++module_exit(rfcomm_cleanup); ++ ++MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>"); ++MODULE_DESCRIPTION("BlueZ RFCOMM ver " VERSION); ++MODULE_LICENSE("GPL"); +diff -urN linux-2.4.18/net/bluetooth/rfcomm/crc.c linux-2.4.18-mh9/net/bluetooth/rfcomm/crc.c +--- linux-2.4.18/net/bluetooth/rfcomm/crc.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/rfcomm/crc.c Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,71 @@ ++/* ++ RFCOMM implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com> ++ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * RFCOMM FCS calculation. ++ * ++ * $Id$ ++ */ ++ ++/* reversed, 8-bit, poly=0x07 */ ++unsigned char rfcomm_crc_table[256] = { ++ 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75, ++ 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b, ++ 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69, ++ 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67, ++ ++ 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d, ++ 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43, ++ 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51, ++ 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f, ++ ++ 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05, ++ 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b, ++ 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19, ++ 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17, ++ ++ 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d, ++ 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33, ++ 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21, ++ 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f, ++ ++ 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95, ++ 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b, ++ 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89, ++ 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87, ++ ++ 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad, ++ 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3, ++ 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1, ++ 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf, ++ ++ 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5, ++ 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb, ++ 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9, ++ 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7, ++ ++ 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd, ++ 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3, ++ 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1, ++ 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf ++}; +diff -urN linux-2.4.18/net/bluetooth/rfcomm/sock.c linux-2.4.18-mh9/net/bluetooth/rfcomm/sock.c +--- linux-2.4.18/net/bluetooth/rfcomm/sock.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/rfcomm/sock.c Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,847 @@ ++/* ++ RFCOMM implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com> ++ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * RFCOMM sockets. ++ * ++ * $Id$ ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/init.h> ++#include <linux/skbuff.h> ++#include <linux/interrupt.h> ++#include <linux/socket.h> ++#include <linux/skbuff.h> ++#include <linux/list.h> ++#include <net/sock.h> ++ ++#include <asm/system.h> ++#include <asm/uaccess.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/rfcomm.h> ++ ++#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG ++#undef BT_DBG ++#define BT_DBG(D...) ++#endif ++ ++static struct proto_ops rfcomm_sock_ops; ++ ++static struct bluez_sock_list rfcomm_sk_list = { ++ lock: RW_LOCK_UNLOCKED ++}; ++ ++static void rfcomm_sock_close(struct sock *sk); ++static void rfcomm_sock_kill(struct sock *sk); ++ ++/* ---- DLC callbacks ---- ++ * ++ * called under rfcomm_dlc_lock() ++ */ ++static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb) ++{ ++ struct sock *sk = d->owner; ++ if (!sk) ++ return; ++ ++ atomic_add(skb->len, &sk->rmem_alloc); ++ skb_queue_tail(&sk->receive_queue, skb); ++ sk->data_ready(sk, skb->len); ++ ++ if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) ++ rfcomm_dlc_throttle(d); ++} ++ ++static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err) ++{ ++ struct sock *sk = d->owner, *parent; ++ if (!sk) ++ return; ++ ++ BT_DBG("dlc %p state %ld err %d", d, d->state, err); ++ ++ bh_lock_sock(sk); ++ ++ if (err) ++ sk->err = err; ++ sk->state = d->state; ++ ++ parent = bluez_pi(sk)->parent; ++ if (!parent) { ++ if (d->state == BT_CONNECTED) ++ rfcomm_session_getaddr(d->session, &bluez_pi(sk)->src, NULL); ++ sk->state_change(sk); ++ } else ++ parent->data_ready(parent, 0); ++ ++ bh_unlock_sock(sk); ++} ++ ++/* ---- Socket functions ---- */ ++static struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src) ++{ ++ struct sock *sk; ++ ++ for (sk = rfcomm_sk_list.head; sk; sk = sk->next) { ++ if (rfcomm_pi(sk)->channel == channel && ++ !bacmp(&bluez_pi(sk)->src, src)) ++ break; ++ } ++ ++ return sk; ++} ++ ++/* Find socket with channel and source bdaddr. ++ * Returns closest match. ++ */ ++static struct sock *__rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src) ++{ ++ struct sock *sk, *sk1 = NULL; ++ ++ for (sk = rfcomm_sk_list.head; sk; sk = sk->next) { ++ if (state && sk->state != state) ++ continue; ++ ++ if (rfcomm_pi(sk)->channel == channel) { ++ /* Exact match. */ ++ if (!bacmp(&bluez_pi(sk)->src, src)) ++ break; ++ ++ /* Closest match */ ++ if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY)) ++ sk1 = sk; ++ } ++ } ++ return sk ? sk : sk1; ++} ++ ++/* Find socket with given address (channel, src). ++ * Returns locked socket */ ++static inline struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src) ++{ ++ struct sock *s; ++ read_lock(&rfcomm_sk_list.lock); ++ s = __rfcomm_get_sock_by_channel(state, channel, src); ++ if (s) bh_lock_sock(s); ++ read_unlock(&rfcomm_sk_list.lock); ++ return s; ++} ++ ++static void rfcomm_sock_destruct(struct sock *sk) ++{ ++ struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc; ++ ++ BT_DBG("sk %p dlc %p", sk, d); ++ ++ skb_queue_purge(&sk->receive_queue); ++ skb_queue_purge(&sk->write_queue); ++ ++ rfcomm_dlc_lock(d); ++ rfcomm_pi(sk)->dlc = NULL; ++ ++ /* Detach DLC if it's owned by this socket */ ++ if (d->owner == sk) ++ d->owner = NULL; ++ rfcomm_dlc_unlock(d); ++ ++ rfcomm_dlc_put(d); ++ ++ MOD_DEC_USE_COUNT; ++} ++ ++static void rfcomm_sock_cleanup_listen(struct sock *parent) ++{ ++ struct sock *sk; ++ ++ BT_DBG("parent %p", parent); ++ ++ /* Close not yet accepted dlcs */ ++ while ((sk = bluez_accept_dequeue(parent, NULL))) { ++ rfcomm_sock_close(sk); ++ rfcomm_sock_kill(sk); ++ } ++ ++ parent->state = BT_CLOSED; ++ parent->zapped = 1; ++} ++ ++/* Kill socket (only if zapped and orphan) ++ * Must be called on unlocked socket. ++ */ ++static void rfcomm_sock_kill(struct sock *sk) ++{ ++ if (!sk->zapped || sk->socket) ++ return; ++ ++ BT_DBG("sk %p state %d refcnt %d", sk, sk->state, atomic_read(&sk->refcnt)); ++ ++ /* Kill poor orphan */ ++ bluez_sock_unlink(&rfcomm_sk_list, sk); ++ sk->dead = 1; ++ sock_put(sk); ++} ++ ++static void __rfcomm_sock_close(struct sock *sk) ++{ ++ struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc; ++ ++ BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket); ++ ++ switch (sk->state) { ++ case BT_LISTEN: ++ rfcomm_sock_cleanup_listen(sk); ++ break; ++ ++ case BT_CONNECT: ++ case BT_CONNECT2: ++ case BT_CONFIG: ++ case BT_CONNECTED: ++ rfcomm_dlc_close(d, 0); ++ ++ default: ++ sk->zapped = 1; ++ break; ++ } ++} ++ ++/* Close socket. ++ * Must be called on unlocked socket. ++ */ ++static void rfcomm_sock_close(struct sock *sk) ++{ ++ lock_sock(sk); ++ __rfcomm_sock_close(sk); ++ release_sock(sk); ++} ++ ++static void rfcomm_sock_init(struct sock *sk, struct sock *parent) ++{ ++ BT_DBG("sk %p", sk); ++ ++ if (parent) ++ sk->type = parent->type; ++} ++ ++static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio) ++{ ++ struct rfcomm_dlc *d; ++ struct sock *sk; ++ ++ sk = sk_alloc(PF_BLUETOOTH, prio, 1); ++ if (!sk) ++ return NULL; ++ ++ d = rfcomm_dlc_alloc(prio); ++ if (!d) { ++ sk_free(sk); ++ return NULL; ++ } ++ d->data_ready = rfcomm_sk_data_ready; ++ d->state_change = rfcomm_sk_state_change; ++ ++ rfcomm_pi(sk)->dlc = d; ++ d->owner = sk; ++ ++ bluez_sock_init(sock, sk); ++ ++ sk->zapped = 0; ++ ++ sk->destruct = rfcomm_sock_destruct; ++ sk->sndtimeo = RFCOMM_CONN_TIMEOUT; ++ ++ sk->sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10; ++ sk->rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10; ++ ++ sk->protocol = proto; ++ sk->state = BT_OPEN; ++ ++ bluez_sock_link(&rfcomm_sk_list, sk); ++ ++ BT_DBG("sk %p", sk); ++ ++ MOD_INC_USE_COUNT; ++ return sk; ++} ++ ++static int rfcomm_sock_create(struct socket *sock, int protocol) ++{ ++ struct sock *sk; ++ ++ BT_DBG("sock %p", sock); ++ ++ sock->state = SS_UNCONNECTED; ++ ++ if (sock->type != SOCK_STREAM && sock->type != SOCK_RAW) ++ return -ESOCKTNOSUPPORT; ++ ++ sock->ops = &rfcomm_sock_ops; ++ ++ if (!(sk = rfcomm_sock_alloc(sock, protocol, GFP_KERNEL))) ++ return -ENOMEM; ++ ++ rfcomm_sock_init(sk, NULL); ++ return 0; ++} ++ ++static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) ++{ ++ struct sockaddr_rc *sa = (struct sockaddr_rc *) addr; ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sk %p %s", sk, batostr(&sa->rc_bdaddr)); ++ ++ if (!addr || addr->sa_family != AF_BLUETOOTH) ++ return -EINVAL; ++ ++ lock_sock(sk); ++ ++ if (sk->state != BT_OPEN) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ write_lock_bh(&rfcomm_sk_list.lock); ++ ++ if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) { ++ err = -EADDRINUSE; ++ } else { ++ /* Save source address */ ++ bacpy(&bluez_pi(sk)->src, &sa->rc_bdaddr); ++ rfcomm_pi(sk)->channel = sa->rc_channel; ++ sk->state = BT_BOUND; ++ } ++ ++ write_unlock_bh(&rfcomm_sk_list.lock); ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) ++{ ++ struct sockaddr_rc *sa = (struct sockaddr_rc *) addr; ++ struct sock *sk = sock->sk; ++ struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc; ++ int err = 0; ++ ++ BT_DBG("sk %p", sk); ++ ++ if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_rc)) ++ return -EINVAL; ++ ++ if (sk->state != BT_OPEN && sk->state != BT_BOUND) ++ return -EBADFD; ++ ++ if (sk->type != SOCK_STREAM) ++ return -EINVAL; ++ ++ lock_sock(sk); ++ ++ sk->state = BT_CONNECT; ++ bacpy(&bluez_pi(sk)->dst, &sa->rc_bdaddr); ++ rfcomm_pi(sk)->channel = sa->rc_channel; ++ ++ err = rfcomm_dlc_open(d, &bluez_pi(sk)->src, &sa->rc_bdaddr, sa->rc_channel); ++ if (!err) ++ err = bluez_sock_wait_state(sk, BT_CONNECTED, ++ sock_sndtimeo(sk, flags & O_NONBLOCK)); ++ ++ release_sock(sk); ++ return err; ++} ++ ++int rfcomm_sock_listen(struct socket *sock, int backlog) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sk %p backlog %d", sk, backlog); ++ ++ lock_sock(sk); ++ ++ if (sk->state != BT_BOUND) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ sk->max_ack_backlog = backlog; ++ sk->ack_backlog = 0; ++ sk->state = BT_LISTEN; ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ struct sock *sk = sock->sk, *nsk; ++ long timeo; ++ int err = 0; ++ ++ lock_sock(sk); ++ ++ if (sk->state != BT_LISTEN) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); ++ ++ BT_DBG("sk %p timeo %ld", sk, timeo); ++ ++ /* Wait for an incoming connection. (wake-one). */ ++ add_wait_queue_exclusive(sk->sleep, &wait); ++ while (!(nsk = bluez_accept_dequeue(sk, newsock))) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ if (!timeo) { ++ err = -EAGAIN; ++ break; ++ } ++ ++ release_sock(sk); ++ timeo = schedule_timeout(timeo); ++ lock_sock(sk); ++ ++ if (sk->state != BT_LISTEN) { ++ err = -EBADFD; ++ break; ++ } ++ ++ if (signal_pending(current)) { ++ err = sock_intr_errno(timeo); ++ break; ++ } ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(sk->sleep, &wait); ++ ++ if (err) ++ goto done; ++ ++ newsock->state = SS_CONNECTED; ++ ++ BT_DBG("new socket %p", nsk); ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer) ++{ ++ struct sockaddr_rc *sa = (struct sockaddr_rc *) addr; ++ struct sock *sk = sock->sk; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ sa->rc_family = AF_BLUETOOTH; ++ sa->rc_channel = rfcomm_pi(sk)->channel; ++ if (peer) ++ bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->dst); ++ else ++ bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->src); ++ ++ *len = sizeof(struct sockaddr_rc); ++ return 0; ++} ++ ++static int rfcomm_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, ++ struct scm_cookie *scm) ++{ ++ struct sock *sk = sock->sk; ++ struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc; ++ struct sk_buff *skb; ++ int err, size; ++ int sent = 0; ++ ++ if (msg->msg_flags & MSG_OOB) ++ return -EOPNOTSUPP; ++ ++ if (sk->shutdown & SEND_SHUTDOWN) ++ return -EPIPE; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ lock_sock(sk); ++ ++ while (len) { ++ size = min_t(uint, len, d->mtu); ++ ++ skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE, ++ msg->msg_flags & MSG_DONTWAIT, &err); ++ if (!skb) ++ break; ++ skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE); ++ ++ err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); ++ if (err) { ++ kfree_skb(skb); ++ sent = err; ++ break; ++ } ++ ++ err = rfcomm_dlc_send(d, skb); ++ if (err < 0) { ++ kfree_skb(skb); ++ break; ++ } ++ ++ sent += size; ++ len -= size; ++ } ++ ++ release_sock(sk); ++ ++ return sent ? sent : err; ++} ++ ++static long rfcomm_sock_data_wait(struct sock *sk, long timeo) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ ++ add_wait_queue(sk->sleep, &wait); ++ for (;;) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ if (skb_queue_len(&sk->receive_queue) || sk->err || (sk->shutdown & RCV_SHUTDOWN) || ++ signal_pending(current) || !timeo) ++ break; ++ ++ set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags); ++ release_sock(sk); ++ timeo = schedule_timeout(timeo); ++ lock_sock(sk); ++ clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags); ++ } ++ ++ __set_current_state(TASK_RUNNING); ++ remove_wait_queue(sk->sleep, &wait); ++ return timeo; ++} ++ ++static int rfcomm_sock_recvmsg(struct socket *sock, struct msghdr *msg, int size, ++ int flags, struct scm_cookie *scm) ++{ ++ struct sock *sk = sock->sk; ++ int target, err = 0, copied = 0; ++ long timeo; ++ ++ if (flags & MSG_OOB) ++ return -EOPNOTSUPP; ++ ++ msg->msg_namelen = 0; ++ ++ BT_DBG("sk %p size %d", sk, size); ++ ++ lock_sock(sk); ++ ++ target = sock_rcvlowat(sk, flags & MSG_WAITALL, size); ++ timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); ++ ++ do { ++ struct sk_buff *skb; ++ int chunk; ++ ++ skb = skb_dequeue(&sk->receive_queue); ++ if (!skb) { ++ if (copied >= target) ++ break; ++ ++ if ((err = sock_error(sk)) != 0) ++ break; ++ if (sk->shutdown & RCV_SHUTDOWN) ++ break; ++ ++ err = -EAGAIN; ++ if (!timeo) ++ break; ++ ++ timeo = rfcomm_sock_data_wait(sk, timeo); ++ ++ if (signal_pending(current)) { ++ err = sock_intr_errno(timeo); ++ goto out; ++ } ++ continue; ++ } ++ ++ chunk = min_t(unsigned int, skb->len, size); ++ if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) { ++ skb_queue_head(&sk->receive_queue, skb); ++ if (!copied) ++ copied = -EFAULT; ++ break; ++ } ++ copied += chunk; ++ size -= chunk; ++ ++ if (!(flags & MSG_PEEK)) { ++ atomic_sub(chunk, &sk->rmem_alloc); ++ ++ skb_pull(skb, chunk); ++ if (skb->len) { ++ skb_queue_head(&sk->receive_queue, skb); ++ break; ++ } ++ kfree_skb(skb); ++ ++ } else { ++ /* put message back and return */ ++ skb_queue_head(&sk->receive_queue, skb); ++ break; ++ } ++ } while (size); ++ ++out: ++ if (atomic_read(&sk->rmem_alloc) <= (sk->rcvbuf >> 2)) ++ rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc); ++ ++ release_sock(sk); ++ return copied ? : err; ++} ++ ++static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sk %p", sk); ++ ++ lock_sock(sk); ++ ++ switch (optname) { ++ default: ++ err = -ENOPROTOOPT; ++ break; ++ }; ++ ++ release_sock(sk); ++ return err; ++} ++ ++static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) ++{ ++ struct sock *sk = sock->sk; ++ int len, err = 0; ++ ++ BT_DBG("sk %p", sk); ++ ++ if (get_user(len, optlen)) ++ return -EFAULT; ++ ++ lock_sock(sk); ++ ++ switch (optname) { ++ default: ++ err = -ENOPROTOOPT; ++ break; ++ }; ++ ++ release_sock(sk); ++ return err; ++} ++ ++static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ++{ ++ struct sock *sk = sock->sk; ++ int err; ++ ++ lock_sock(sk); ++ ++#ifdef CONFIG_BLUEZ_RFCOMM_TTY ++ err = rfcomm_dev_ioctl(sk, cmd, arg); ++#else ++ err = -EOPNOTSUPP; ++#endif ++ ++ release_sock(sk); ++ ++ return err; ++} ++ ++static int rfcomm_sock_shutdown(struct socket *sock, int how) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ if (!sk) return 0; ++ ++ lock_sock(sk); ++ if (!sk->shutdown) { ++ sk->shutdown = SHUTDOWN_MASK; ++ __rfcomm_sock_close(sk); ++ ++ if (sk->linger) ++ err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime); ++ } ++ release_sock(sk); ++ return err; ++} ++ ++static int rfcomm_sock_release(struct socket *sock) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ if (!sk) ++ return 0; ++ ++ err = rfcomm_sock_shutdown(sock, 2); ++ ++ sock_orphan(sk); ++ rfcomm_sock_kill(sk); ++ return err; ++} ++ ++/* ---- RFCOMM core layer callbacks ---- ++ * ++ * called under rfcomm_lock() ++ */ ++int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d) ++{ ++ struct sock *sk, *parent; ++ bdaddr_t src, dst; ++ int result = 0; ++ ++ BT_DBG("session %p channel %d", s, channel); ++ ++ rfcomm_session_getaddr(s, &src, &dst); ++ ++ /* Check if we have socket listening on this channel */ ++ parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &src); ++ if (!parent) ++ return 0; ++ ++ /* Check for backlog size */ ++ if (parent->ack_backlog > parent->max_ack_backlog) { ++ BT_DBG("backlog full %d", parent->ack_backlog); ++ goto done; ++ } ++ ++ sk = rfcomm_sock_alloc(NULL, BTPROTO_RFCOMM, GFP_ATOMIC); ++ if (!sk) ++ goto done; ++ ++ rfcomm_sock_init(sk, parent); ++ bacpy(&bluez_pi(sk)->src, &src); ++ bacpy(&bluez_pi(sk)->dst, &dst); ++ rfcomm_pi(sk)->channel = channel; ++ ++ sk->state = BT_CONFIG; ++ bluez_accept_enqueue(parent, sk); ++ ++ /* Accept connection and return socket DLC */ ++ *d = rfcomm_pi(sk)->dlc; ++ result = 1; ++ ++done: ++ bh_unlock_sock(parent); ++ return result; ++} ++ ++/* ---- Proc fs support ---- */ ++int rfcomm_sock_dump(char *buf) ++{ ++ struct bluez_sock_list *list = &rfcomm_sk_list; ++ struct rfcomm_pinfo *pi; ++ struct sock *sk; ++ char *ptr = buf; ++ ++ write_lock_bh(&list->lock); ++ ++ for (sk = list->head; sk; sk = sk->next) { ++ pi = rfcomm_pi(sk); ++ ptr += sprintf(ptr, "sk %s %s %d %d\n", ++ batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst), ++ sk->state, rfcomm_pi(sk)->channel); ++ } ++ ++ write_unlock_bh(&list->lock); ++ ++ return ptr - buf; ++} ++ ++static struct proto_ops rfcomm_sock_ops = { ++ family: PF_BLUETOOTH, ++ release: rfcomm_sock_release, ++ bind: rfcomm_sock_bind, ++ connect: rfcomm_sock_connect, ++ listen: rfcomm_sock_listen, ++ accept: rfcomm_sock_accept, ++ getname: rfcomm_sock_getname, ++ sendmsg: rfcomm_sock_sendmsg, ++ recvmsg: rfcomm_sock_recvmsg, ++ shutdown: rfcomm_sock_shutdown, ++ setsockopt: rfcomm_sock_setsockopt, ++ getsockopt: rfcomm_sock_getsockopt, ++ ioctl: rfcomm_sock_ioctl, ++ poll: bluez_sock_poll, ++ socketpair: sock_no_socketpair, ++ mmap: sock_no_mmap ++}; ++ ++static struct net_proto_family rfcomm_sock_family_ops = { ++ family: PF_BLUETOOTH, ++ create: rfcomm_sock_create ++}; ++ ++int rfcomm_init_sockets(void) ++{ ++ int err; ++ ++ if ((err = bluez_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops))) { ++ BT_ERR("Can't register RFCOMM socket layer"); ++ return err; ++ } ++ ++ return 0; ++} ++ ++void rfcomm_cleanup_sockets(void) ++{ ++ int err; ++ ++ /* Unregister socket, protocol and notifier */ ++ if ((err = bluez_sock_unregister(BTPROTO_RFCOMM))) ++ BT_ERR("Can't unregister RFCOMM socket layer %d", err); ++} +diff -urN linux-2.4.18/net/bluetooth/rfcomm/tty.c linux-2.4.18-mh9/net/bluetooth/rfcomm/tty.c +--- linux-2.4.18/net/bluetooth/rfcomm/tty.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/rfcomm/tty.c Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,945 @@ ++/* ++ RFCOMM implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com> ++ Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org> ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * RFCOMM TTY. ++ * ++ * $Id$ ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/tty.h> ++#include <linux/tty_driver.h> ++#include <linux/tty_flip.h> ++ ++#include <linux/slab.h> ++#include <linux/skbuff.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/rfcomm.h> ++ ++#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG ++#undef BT_DBG ++#define BT_DBG(D...) ++#endif ++ ++#define RFCOMM_TTY_MAGIC 0x6d02 /* magic number for rfcomm struct */ ++#define RFCOMM_TTY_PORTS RFCOMM_MAX_DEV /* whole lotta rfcomm devices */ ++#define RFCOMM_TTY_MAJOR 216 /* device node major id of the usb/bluetooth.c driver */ ++#define RFCOMM_TTY_MINOR 0 ++ ++struct rfcomm_dev { ++ struct list_head list; ++ atomic_t refcnt; ++ ++ char name[12]; ++ int id; ++ unsigned long flags; ++ int opened; ++ int err; ++ ++ bdaddr_t src; ++ bdaddr_t dst; ++ u8 channel; ++ ++ uint modem_status; ++ ++ struct rfcomm_dlc *dlc; ++ struct tty_struct *tty; ++ wait_queue_head_t wait; ++ struct tasklet_struct wakeup_task; ++ ++ atomic_t wmem_alloc; ++}; ++ ++static LIST_HEAD(rfcomm_dev_list); ++static rwlock_t rfcomm_dev_lock = RW_LOCK_UNLOCKED; ++ ++static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb); ++static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err); ++static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig); ++ ++static void rfcomm_tty_wakeup(unsigned long arg); ++ ++/* ---- Device functions ---- */ ++static void rfcomm_dev_destruct(struct rfcomm_dev *dev) ++{ ++ struct rfcomm_dlc *dlc = dev->dlc; ++ ++ BT_DBG("dev %p dlc %p", dev, dlc); ++ ++ rfcomm_dlc_lock(dlc); ++ /* Detach DLC if it's owned by this dev */ ++ if (dlc->owner == dev) ++ dlc->owner = NULL; ++ rfcomm_dlc_unlock(dlc); ++ ++ rfcomm_dlc_put(dlc); ++ kfree(dev); ++ ++ MOD_DEC_USE_COUNT; ++} ++ ++static inline void rfcomm_dev_hold(struct rfcomm_dev *dev) ++{ ++ atomic_inc(&dev->refcnt); ++} ++ ++static inline void rfcomm_dev_put(struct rfcomm_dev *dev) ++{ ++ if (atomic_dec_and_test(&dev->refcnt)) ++ rfcomm_dev_destruct(dev); ++} ++ ++static struct rfcomm_dev *__rfcomm_dev_get(int id) ++{ ++ struct rfcomm_dev *dev; ++ struct list_head *p; ++ ++ list_for_each(p, &rfcomm_dev_list) { ++ dev = list_entry(p, struct rfcomm_dev, list); ++ if (dev->id == id) ++ return dev; ++ } ++ ++ return NULL; ++} ++ ++static inline struct rfcomm_dev *rfcomm_dev_get(int id) ++{ ++ struct rfcomm_dev *dev; ++ ++ read_lock(&rfcomm_dev_lock); ++ dev = __rfcomm_dev_get(id); ++ read_unlock(&rfcomm_dev_lock); ++ ++ if (dev) rfcomm_dev_hold(dev); ++ return dev; ++} ++ ++static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) ++{ ++ struct rfcomm_dev *dev; ++ struct list_head *head = &rfcomm_dev_list, *p; ++ int err = 0; ++ ++ BT_DBG("id %d channel %d", req->dev_id, req->channel); ++ ++ dev = kmalloc(sizeof(struct rfcomm_dev), GFP_KERNEL); ++ if (!dev) ++ return -ENOMEM; ++ memset(dev, 0, sizeof(struct rfcomm_dev)); ++ ++ write_lock_bh(&rfcomm_dev_lock); ++ ++ if (req->dev_id < 0) { ++ dev->id = 0; ++ ++ list_for_each(p, &rfcomm_dev_list) { ++ if (list_entry(p, struct rfcomm_dev, list)->id != dev->id) ++ break; ++ ++ dev->id++; ++ head = p; ++ } ++ } else { ++ dev->id = req->dev_id; ++ ++ list_for_each(p, &rfcomm_dev_list) { ++ struct rfcomm_dev *entry = list_entry(p, struct rfcomm_dev, list); ++ ++ if (entry->id == dev->id) { ++ err = -EADDRINUSE; ++ goto out; ++ } ++ ++ if (entry->id > dev->id - 1) ++ break; ++ ++ head = p; ++ } ++ } ++ ++ if ((dev->id < 0) || (dev->id > RFCOMM_MAX_DEV - 1)) { ++ err = -ENFILE; ++ goto out; ++ } ++ ++ sprintf(dev->name, "rfcomm%d", dev->id); ++ ++ list_add(&dev->list, head); ++ atomic_set(&dev->refcnt, 1); ++ ++ bacpy(&dev->src, &req->src); ++ bacpy(&dev->dst, &req->dst); ++ dev->channel = req->channel; ++ ++ dev->flags = req->flags & ++ ((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC)); ++ ++ init_waitqueue_head(&dev->wait); ++ tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev); ++ ++ rfcomm_dlc_lock(dlc); ++ dlc->data_ready = rfcomm_dev_data_ready; ++ dlc->state_change = rfcomm_dev_state_change; ++ dlc->modem_status = rfcomm_dev_modem_status; ++ ++ dlc->owner = dev; ++ dev->dlc = dlc; ++ rfcomm_dlc_unlock(dlc); ++ ++ MOD_INC_USE_COUNT; ++ ++out: ++ write_unlock_bh(&rfcomm_dev_lock); ++ ++ if (err) { ++ kfree(dev); ++ return err; ++ } else ++ return dev->id; ++} ++ ++static void rfcomm_dev_del(struct rfcomm_dev *dev) ++{ ++ BT_DBG("dev %p", dev); ++ ++ write_lock_bh(&rfcomm_dev_lock); ++ list_del_init(&dev->list); ++ write_unlock_bh(&rfcomm_dev_lock); ++ ++ rfcomm_dev_put(dev); ++} ++ ++/* ---- Send buffer ---- */ ++ ++static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc) ++{ ++ /* We can't let it be zero, because we don't get a callback ++ when tx_credits becomes nonzero, hence we'd never wake up */ ++ return dlc->mtu * (dlc->tx_credits?:1); ++} ++ ++static void rfcomm_wfree(struct sk_buff *skb) ++{ ++ struct rfcomm_dev *dev = (void *) skb->sk; ++ atomic_sub(skb->truesize, &dev->wmem_alloc); ++ if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags)) ++ tasklet_schedule(&dev->wakeup_task); ++ rfcomm_dev_put(dev); ++} ++ ++static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev) ++{ ++ rfcomm_dev_hold(dev); ++ atomic_add(skb->truesize, &dev->wmem_alloc); ++ skb->sk = (void *) dev; ++ skb->destructor = rfcomm_wfree; ++} ++ ++static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int force, int priority) ++{ ++ if (force || atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) { ++ struct sk_buff *skb = alloc_skb(size, priority); ++ if (skb) { ++ rfcomm_set_owner_w(skb, dev); ++ return skb; ++ } ++ } ++ return NULL; ++} ++ ++/* ---- Device IOCTLs ---- */ ++ ++#define NOCAP_FLAGS ((1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP)) ++ ++static int rfcomm_create_dev(struct sock *sk, unsigned long arg) ++{ ++ struct rfcomm_dev_req req; ++ struct rfcomm_dlc *dlc; ++ int id; ++ ++ if (copy_from_user(&req, (void *) arg, sizeof(req))) ++ return -EFAULT; ++ ++ BT_DBG("sk %p dev_id %id flags 0x%x", sk, req.dev_id, req.flags); ++ ++ if (req.flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ if (req.flags & (1 << RFCOMM_REUSE_DLC)) { ++ /* Socket must be connected */ ++ if (sk->state != BT_CONNECTED) ++ return -EBADFD; ++ ++ dlc = rfcomm_pi(sk)->dlc; ++ rfcomm_dlc_hold(dlc); ++ } else { ++ dlc = rfcomm_dlc_alloc(GFP_KERNEL); ++ if (!dlc) ++ return -ENOMEM; ++ } ++ ++ id = rfcomm_dev_add(&req, dlc); ++ if (id < 0) { ++ rfcomm_dlc_put(dlc); ++ return id; ++ } ++ ++ if (req.flags & (1 << RFCOMM_REUSE_DLC)) { ++ /* DLC is now used by device. ++ * Socket must be disconnected */ ++ sk->state = BT_CLOSED; ++ } ++ ++ return id; ++} ++ ++static int rfcomm_release_dev(unsigned long arg) ++{ ++ struct rfcomm_dev_req req; ++ struct rfcomm_dev *dev; ++ ++ if (copy_from_user(&req, (void *) arg, sizeof(req))) ++ return -EFAULT; ++ ++ BT_DBG("dev_id %id flags 0x%x", req.dev_id, req.flags); ++ ++ if (!capable(CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ if (!(dev = rfcomm_dev_get(req.dev_id))) ++ return -ENODEV; ++ ++ if (req.flags & (1 << RFCOMM_HANGUP_NOW)) ++ rfcomm_dlc_close(dev->dlc, 0); ++ ++ rfcomm_dev_del(dev); ++ rfcomm_dev_put(dev); ++ return 0; ++} ++ ++static int rfcomm_get_dev_list(unsigned long arg) ++{ ++ struct rfcomm_dev_list_req *dl; ++ struct rfcomm_dev_info *di; ++ struct list_head *p; ++ int n = 0, size; ++ u16 dev_num; ++ ++ BT_DBG(""); ++ ++ if (get_user(dev_num, (u16 *) arg)) ++ return -EFAULT; ++ ++ if (!dev_num) ++ return -EINVAL; ++ ++ size = sizeof(*dl) + dev_num * sizeof(*di); ++ ++ if (verify_area(VERIFY_WRITE, (void *)arg, size)) ++ return -EFAULT; ++ ++ if (!(dl = kmalloc(size, GFP_KERNEL))) ++ return -ENOMEM; ++ ++ di = dl->dev_info; ++ ++ read_lock_bh(&rfcomm_dev_lock); ++ ++ list_for_each(p, &rfcomm_dev_list) { ++ struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list); ++ (di + n)->id = dev->id; ++ (di + n)->flags = dev->flags; ++ (di + n)->state = dev->dlc->state; ++ (di + n)->channel = dev->channel; ++ bacpy(&(di + n)->src, &dev->src); ++ bacpy(&(di + n)->dst, &dev->dst); ++ if (++n >= dev_num) ++ break; ++ } ++ ++ read_unlock_bh(&rfcomm_dev_lock); ++ ++ dl->dev_num = n; ++ size = sizeof(*dl) + n * sizeof(*di); ++ ++ copy_to_user((void *) arg, dl, size); ++ kfree(dl); ++ return 0; ++} ++ ++static int rfcomm_get_dev_info(unsigned long arg) ++{ ++ struct rfcomm_dev *dev; ++ struct rfcomm_dev_info di; ++ int err = 0; ++ ++ BT_DBG(""); ++ ++ if (copy_from_user(&di, (void *)arg, sizeof(di))) ++ return -EFAULT; ++ ++ if (!(dev = rfcomm_dev_get(di.id))) ++ return -ENODEV; ++ ++ di.flags = dev->flags; ++ di.channel = dev->channel; ++ di.state = dev->dlc->state; ++ bacpy(&di.src, &dev->src); ++ bacpy(&di.dst, &dev->dst); ++ ++ if (copy_to_user((void *)arg, &di, sizeof(di))) ++ err = -EFAULT; ++ ++ rfcomm_dev_put(dev); ++ return err; ++} ++ ++int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg) ++{ ++ BT_DBG("cmd %d arg %ld", cmd, arg); ++ ++ switch (cmd) { ++ case RFCOMMCREATEDEV: ++ return rfcomm_create_dev(sk, arg); ++ ++ case RFCOMMRELEASEDEV: ++ return rfcomm_release_dev(arg); ++ ++ case RFCOMMGETDEVLIST: ++ return rfcomm_get_dev_list(arg); ++ ++ case RFCOMMGETDEVINFO: ++ return rfcomm_get_dev_info(arg); ++ } ++ ++ return -EINVAL; ++} ++ ++/* ---- DLC callbacks ---- */ ++static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb) ++{ ++ struct rfcomm_dev *dev = dlc->owner; ++ struct tty_struct *tty; ++ ++ if (!dev || !(tty = dev->tty)) { ++ kfree_skb(skb); ++ return; ++ } ++ ++ BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len); ++ ++ if (test_bit(TTY_DONT_FLIP, &tty->flags)) { ++ register int i; ++ for (i = 0; i < skb->len; i++) { ++ if (tty->flip.count >= TTY_FLIPBUF_SIZE) ++ tty_flip_buffer_push(tty); ++ ++ tty_insert_flip_char(tty, skb->data[i], 0); ++ } ++ tty_flip_buffer_push(tty); ++ } else ++ tty->ldisc.receive_buf(tty, skb->data, NULL, skb->len); ++ ++ kfree_skb(skb); ++} ++ ++static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) ++{ ++ struct rfcomm_dev *dev = dlc->owner; ++ if (!dev) ++ return; ++ ++ BT_DBG("dlc %p dev %p err %d", dlc, dev, err); ++ ++ dev->err = err; ++ wake_up_interruptible(&dev->wait); ++ ++ if (dlc->state == BT_CLOSED) { ++ if (!dev->tty) { ++ if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) { ++ rfcomm_dev_hold(dev); ++ rfcomm_dev_del(dev); ++ ++ /* We have to drop DLC lock here, otherwise ++ * rfcomm_dev_put() will dead lock if it's the last refference */ ++ rfcomm_dlc_unlock(dlc); ++ rfcomm_dev_put(dev); ++ rfcomm_dlc_lock(dlc); ++ } ++ } else ++ tty_hangup(dev->tty); ++ } ++} ++ ++static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig) ++{ ++ struct rfcomm_dev *dev = dlc->owner; ++ if (!dev) ++ return; ++ ++ BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig); ++ ++ dev->modem_status = ++ ((v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0) | ++ ((v24_sig & RFCOMM_V24_RTR) ? (TIOCM_RTS | TIOCM_CTS) : 0) | ++ ((v24_sig & RFCOMM_V24_IC) ? TIOCM_RI : 0) | ++ ((v24_sig & RFCOMM_V24_DV) ? TIOCM_CD : 0); ++} ++ ++/* ---- TTY functions ---- */ ++static void rfcomm_tty_wakeup(unsigned long arg) ++{ ++ struct rfcomm_dev *dev = (void *) arg; ++ struct tty_struct *tty = dev->tty; ++ if (!tty) ++ return; ++ ++ BT_DBG("dev %p tty %p", dev, tty); ++ ++ if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup) ++ (tty->ldisc.write_wakeup)(tty); ++ ++ wake_up_interruptible(&tty->write_wait); ++#ifdef SERIAL_HAVE_POLL_WAIT ++ wake_up_interruptible(&tty->poll_wait); ++#endif ++} ++ ++static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ struct rfcomm_dev *dev; ++ struct rfcomm_dlc *dlc; ++ int err, id; ++ ++ id = MINOR(tty->device) - tty->driver.minor_start; ++ ++ BT_DBG("tty %p id %d", tty, id); ++ ++ dev = rfcomm_dev_get(id); ++ if (!dev) ++ return -ENODEV; ++ ++ BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst), dev->channel, dev->opened); ++ ++ if (dev->opened++ != 0) ++ return 0; ++ ++ dlc = dev->dlc; ++ ++ /* Attach TTY and open DLC */ ++ ++ rfcomm_dlc_lock(dlc); ++ tty->driver_data = dev; ++ dev->tty = tty; ++ rfcomm_dlc_unlock(dlc); ++ set_bit(RFCOMM_TTY_ATTACHED, &dev->flags); ++ ++ err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel); ++ if (err < 0) ++ return err; ++ ++ /* Wait for DLC to connect */ ++ add_wait_queue(&dev->wait, &wait); ++ while (1) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ if (dlc->state == BT_CLOSED) { ++ err = -dev->err; ++ break; ++ } ++ ++ if (dlc->state == BT_CONNECTED) ++ break; ++ ++ if (signal_pending(current)) { ++ err = -EINTR; ++ break; ++ } ++ ++ schedule(); ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&dev->wait, &wait); ++ ++ return err; ++} ++ ++static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ if (!dev) ++ return; ++ ++ BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, dev->opened); ++ ++ if (--dev->opened == 0) { ++ /* Close DLC and dettach TTY */ ++ rfcomm_dlc_close(dev->dlc, 0); ++ ++ clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags); ++ tasklet_kill(&dev->wakeup_task); ++ ++ rfcomm_dlc_lock(dev->dlc); ++ tty->driver_data = NULL; ++ dev->tty = NULL; ++ rfcomm_dlc_unlock(dev->dlc); ++ } ++ ++ rfcomm_dev_put(dev); ++} ++ ++static int rfcomm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ struct rfcomm_dlc *dlc = dev->dlc; ++ struct sk_buff *skb; ++ int err = 0, sent = 0, size; ++ ++ BT_DBG("tty %p from_user %d count %d", tty, from_user, count); ++ ++ while (count) { ++ size = min_t(uint, count, dlc->mtu); ++ ++ if (from_user) ++ skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, 0, GFP_KERNEL); ++ else ++ skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, 0, GFP_ATOMIC); ++ ++ if (!skb) ++ break; ++ ++ skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE); ++ ++ if (from_user) ++ copy_from_user(skb_put(skb, size), buf + sent, size); ++ else ++ memcpy(skb_put(skb, size), buf + sent, size); ++ ++ if ((err = rfcomm_dlc_send(dlc, skb)) < 0) { ++ kfree_skb(skb); ++ break; ++ } ++ ++ sent += size; ++ count -= size; ++ } ++ ++ return sent ? sent : err; ++} ++ ++static void rfcomm_tty_put_char(struct tty_struct *tty, unsigned char ch) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ struct rfcomm_dlc *dlc = dev->dlc; ++ struct sk_buff *skb; ++ ++ BT_DBG("tty %p char %x", tty, ch); ++ ++ skb = rfcomm_wmalloc(dev, 1 + RFCOMM_SKB_RESERVE, 1, GFP_ATOMIC); ++ ++ if (!skb) ++ return; ++ ++ skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE); ++ ++ *(char *)skb_put(skb, 1) = ch; ++ ++ if ((rfcomm_dlc_send(dlc, skb)) < 0) ++ kfree_skb(skb); ++} ++ ++static int rfcomm_tty_write_room(struct tty_struct *tty) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ int room; ++ ++ BT_DBG("tty %p", tty); ++ ++ room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc); ++ if (room < 0) ++ room = 0; ++ ++ return room; ++} ++ ++static int rfcomm_tty_set_modem_status(uint cmd, struct rfcomm_dlc *dlc, uint status) ++{ ++ u8 v24_sig, mask; ++ ++ BT_DBG("dlc %p cmd 0x%02x", dlc, cmd); ++ ++ if (cmd == TIOCMSET) ++ v24_sig = 0; ++ else ++ rfcomm_dlc_get_modem_status(dlc, &v24_sig); ++ ++ mask = ((status & TIOCM_DSR) ? RFCOMM_V24_RTC : 0) | ++ ((status & TIOCM_DTR) ? RFCOMM_V24_RTC : 0) | ++ ((status & TIOCM_RTS) ? RFCOMM_V24_RTR : 0) | ++ ((status & TIOCM_CTS) ? RFCOMM_V24_RTR : 0) | ++ ((status & TIOCM_RI) ? RFCOMM_V24_IC : 0) | ++ ((status & TIOCM_CD) ? RFCOMM_V24_DV : 0); ++ ++ if (cmd == TIOCMBIC) ++ v24_sig &= ~mask; ++ else ++ v24_sig |= mask; ++ ++ rfcomm_dlc_set_modem_status(dlc, v24_sig); ++ return 0; ++} ++ ++static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ struct rfcomm_dlc *dlc = dev->dlc; ++ uint status; ++ int err; ++ ++ BT_DBG("tty %p cmd 0x%02x", tty, cmd); ++ ++ switch (cmd) { ++ case TCGETS: ++ BT_DBG("TCGETS is not supported"); ++ return -ENOIOCTLCMD; ++ ++ case TCSETS: ++ BT_DBG("TCSETS is not supported"); ++ return -ENOIOCTLCMD; ++ ++ case TIOCMGET: ++ BT_DBG("TIOCMGET"); ++ ++ return put_user(dev->modem_status, (unsigned int *)arg); ++ ++ case TIOCMSET: /* Turns on and off the lines as specified by the mask */ ++ case TIOCMBIS: /* Turns on the lines as specified by the mask */ ++ case TIOCMBIC: /* Turns off the lines as specified by the mask */ ++ if ((err = get_user(status, (unsigned int *)arg))) ++ return err; ++ return rfcomm_tty_set_modem_status(cmd, dlc, status); ++ ++ case TIOCMIWAIT: ++ BT_DBG("TIOCMIWAIT"); ++ break; ++ ++ case TIOCGICOUNT: ++ BT_DBG("TIOCGICOUNT"); ++ break; ++ ++ case TIOCGSERIAL: ++ BT_ERR("TIOCGSERIAL is not supported"); ++ return -ENOIOCTLCMD; ++ ++ case TIOCSSERIAL: ++ BT_ERR("TIOCSSERIAL is not supported"); ++ return -ENOIOCTLCMD; ++ ++ case TIOCSERGSTRUCT: ++ BT_ERR("TIOCSERGSTRUCT is not supported"); ++ return -ENOIOCTLCMD; ++ ++ case TIOCSERGETLSR: ++ BT_ERR("TIOCSERGETLSR is not supported"); ++ return -ENOIOCTLCMD; ++ ++ case TIOCSERCONFIG: ++ BT_ERR("TIOCSERCONFIG is not supported"); ++ return -ENOIOCTLCMD; ++ ++ default: ++ return -ENOIOCTLCMD; /* ioctls which we must ignore */ ++ ++ } ++ ++ return -ENOIOCTLCMD; ++} ++ ++#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) ++ ++static void rfcomm_tty_set_termios(struct tty_struct *tty, struct termios *old) ++{ ++ BT_DBG("tty %p", tty); ++ ++ if ((tty->termios->c_cflag == old->c_cflag) && ++ (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old->c_iflag))) ++ return; ++ ++ /* handle turning off CRTSCTS */ ++ if ((old->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { ++ BT_DBG("turning off CRTSCTS"); ++ } ++} ++ ++static void rfcomm_tty_throttle(struct tty_struct *tty) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ ++ BT_DBG("tty %p dev %p", tty, dev); ++ ++ rfcomm_dlc_throttle(dev->dlc); ++} ++ ++static void rfcomm_tty_unthrottle(struct tty_struct *tty) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ ++ BT_DBG("tty %p dev %p", tty, dev); ++ ++ rfcomm_dlc_unthrottle(dev->dlc); ++} ++ ++static int rfcomm_tty_chars_in_buffer(struct tty_struct *tty) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ struct rfcomm_dlc *dlc = dev->dlc; ++ ++ BT_DBG("tty %p dev %p", tty, dev); ++ ++ if (skb_queue_len(&dlc->tx_queue)) ++ return dlc->mtu; ++ ++ return 0; ++} ++ ++static void rfcomm_tty_flush_buffer(struct tty_struct *tty) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ if (!dev) ++ return; ++ ++ BT_DBG("tty %p dev %p", tty, dev); ++ ++ skb_queue_purge(&dev->dlc->tx_queue); ++ ++ if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup) ++ tty->ldisc.write_wakeup(tty); ++} ++ ++static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch) ++{ ++ BT_DBG("tty %p ch %c", tty, ch); ++} ++ ++static void rfcomm_tty_wait_until_sent(struct tty_struct *tty, int timeout) ++{ ++ BT_DBG("tty %p timeout %d", tty, timeout); ++} ++ ++static void rfcomm_tty_hangup(struct tty_struct *tty) ++{ ++ struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; ++ if (!dev) ++ return; ++ ++ BT_DBG("tty %p dev %p", tty, dev); ++ ++ rfcomm_tty_flush_buffer(tty); ++ ++ if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) ++ rfcomm_dev_del(dev); ++} ++ ++static int rfcomm_tty_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused) ++{ ++ return 0; ++} ++ ++/* ---- TTY structure ---- */ ++static int rfcomm_tty_refcount; /* If we manage several devices */ ++ ++static struct tty_struct *rfcomm_tty_table[RFCOMM_TTY_PORTS]; ++static struct termios *rfcomm_tty_termios[RFCOMM_TTY_PORTS]; ++static struct termios *rfcomm_tty_termios_locked[RFCOMM_TTY_PORTS]; ++ ++static struct tty_driver rfcomm_tty_driver = { ++ magic: TTY_DRIVER_MAGIC, ++ driver_name: "rfcomm", ++#ifdef CONFIG_DEVFS_FS ++ name: "bluetooth/rfcomm/%d", ++#else ++ name: "rfcomm", ++#endif ++ major: RFCOMM_TTY_MAJOR, ++ minor_start: RFCOMM_TTY_MINOR, ++ num: RFCOMM_TTY_PORTS, ++ type: TTY_DRIVER_TYPE_SERIAL, ++ subtype: SERIAL_TYPE_NORMAL, ++ flags: TTY_DRIVER_REAL_RAW, ++ ++ refcount: &rfcomm_tty_refcount, ++ table: rfcomm_tty_table, ++ termios: rfcomm_tty_termios, ++ termios_locked: rfcomm_tty_termios_locked, ++ ++ open: rfcomm_tty_open, ++ close: rfcomm_tty_close, ++ put_char: rfcomm_tty_put_char, ++ write: rfcomm_tty_write, ++ write_room: rfcomm_tty_write_room, ++ chars_in_buffer: rfcomm_tty_chars_in_buffer, ++ flush_buffer: rfcomm_tty_flush_buffer, ++ ioctl: rfcomm_tty_ioctl, ++ throttle: rfcomm_tty_throttle, ++ unthrottle: rfcomm_tty_unthrottle, ++ set_termios: rfcomm_tty_set_termios, ++ send_xchar: rfcomm_tty_send_xchar, ++ stop: NULL, ++ start: NULL, ++ hangup: rfcomm_tty_hangup, ++ wait_until_sent: rfcomm_tty_wait_until_sent, ++ read_proc: rfcomm_tty_read_proc, ++}; ++ ++int rfcomm_init_ttys(void) ++{ ++ int i; ++ ++ /* Initalize our global data */ ++ for (i = 0; i < RFCOMM_TTY_PORTS; i++) ++ rfcomm_tty_table[i] = NULL; ++ ++ /* Register the TTY driver */ ++ rfcomm_tty_driver.init_termios = tty_std_termios; ++ rfcomm_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; ++ rfcomm_tty_driver.flags = TTY_DRIVER_REAL_RAW; ++ ++ if (tty_register_driver(&rfcomm_tty_driver)) { ++ BT_ERR("Can't register RFCOMM TTY driver"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++void rfcomm_cleanup_ttys(void) ++{ ++ tty_unregister_driver(&rfcomm_tty_driver); ++ return; ++} +diff -urN linux-2.4.18/net/bluetooth/sco.c linux-2.4.18-mh9/net/bluetooth/sco.c +--- linux-2.4.18/net/bluetooth/sco.c Thu Jan 1 01:00:00 1970 ++++ linux-2.4.18-mh9/net/bluetooth/sco.c Mon Aug 25 18:38:12 2003 +@@ -0,0 +1,1019 @@ ++/* ++ BlueZ - Bluetooth protocol stack for Linux ++ Copyright (C) 2000-2001 Qualcomm Incorporated ++ ++ Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.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; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++/* ++ * BlueZ SCO sockets. ++ * ++ * $Id$ ++ */ ++#define VERSION "0.3" ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/init.h> ++#include <linux/skbuff.h> ++#include <linux/interrupt.h> ++#include <linux/socket.h> ++#include <linux/skbuff.h> ++#include <linux/proc_fs.h> ++#include <linux/list.h> ++#include <net/sock.h> ++ ++#include <asm/system.h> ++#include <asm/uaccess.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/hci_core.h> ++#include <net/bluetooth/sco.h> ++ ++#ifndef SCO_DEBUG ++#undef BT_DBG ++#define BT_DBG( A... ) ++#endif ++ ++static struct proto_ops sco_sock_ops; ++ ++static struct bluez_sock_list sco_sk_list = { ++ lock: RW_LOCK_UNLOCKED ++}; ++ ++static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent); ++static void sco_chan_del(struct sock *sk, int err); ++static inline struct sock * sco_chan_get(struct sco_conn *conn); ++ ++static int sco_conn_del(struct hci_conn *conn, int err); ++ ++static void sco_sock_close(struct sock *sk); ++static void sco_sock_kill(struct sock *sk); ++ ++/* ----- SCO timers ------ */ ++static void sco_sock_timeout(unsigned long arg) ++{ ++ struct sock *sk = (struct sock *) arg; ++ ++ BT_DBG("sock %p state %d", sk, sk->state); ++ ++ bh_lock_sock(sk); ++ sk->err = ETIMEDOUT; ++ sk->state_change(sk); ++ bh_unlock_sock(sk); ++ ++ sco_sock_kill(sk); ++ sock_put(sk); ++} ++ ++static void sco_sock_set_timer(struct sock *sk, long timeout) ++{ ++ BT_DBG("sock %p state %d timeout %ld", sk, sk->state, timeout); ++ ++ if (!mod_timer(&sk->timer, jiffies + timeout)) ++ sock_hold(sk); ++} ++ ++static void sco_sock_clear_timer(struct sock *sk) ++{ ++ BT_DBG("sock %p state %d", sk, sk->state); ++ ++ if (timer_pending(&sk->timer) && del_timer(&sk->timer)) ++ __sock_put(sk); ++} ++ ++static void sco_sock_init_timer(struct sock *sk) ++{ ++ init_timer(&sk->timer); ++ sk->timer.function = sco_sock_timeout; ++ sk->timer.data = (unsigned long)sk; ++} ++ ++/* -------- SCO connections --------- */ ++static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status) ++{ ++ struct hci_dev *hdev = hcon->hdev; ++ struct sco_conn *conn; ++ ++ if ((conn = hcon->sco_data)) ++ return conn; ++ ++ if (status) ++ return conn; ++ ++ if (!(conn = kmalloc(sizeof(struct sco_conn), GFP_ATOMIC))) ++ return NULL; ++ memset(conn, 0, sizeof(struct sco_conn)); ++ ++ spin_lock_init(&conn->lock); ++ ++ hcon->sco_data = conn; ++ conn->hcon = hcon; ++ ++ conn->src = &hdev->bdaddr; ++ conn->dst = &hcon->dst; ++ ++ if (hdev->sco_mtu > 0) ++ conn->mtu = hdev->sco_mtu; ++ else ++ conn->mtu = 60; ++ ++ BT_DBG("hcon %p conn %p", hcon, conn); ++ ++ MOD_INC_USE_COUNT; ++ return conn; ++} ++ ++static int sco_conn_del(struct hci_conn *hcon, int err) ++{ ++ struct sco_conn *conn; ++ struct sock *sk; ++ ++ if (!(conn = hcon->sco_data)) ++ return 0; ++ ++ BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); ++ ++ /* Kill socket */ ++ if ((sk = sco_chan_get(conn))) { ++ bh_lock_sock(sk); ++ sco_sock_clear_timer(sk); ++ sco_chan_del(sk, err); ++ bh_unlock_sock(sk); ++ sco_sock_kill(sk); ++ } ++ ++ hcon->sco_data = NULL; ++ kfree(conn); ++ ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++int sco_connect(struct sock *sk) ++{ ++ bdaddr_t *src = &bluez_pi(sk)->src; ++ bdaddr_t *dst = &bluez_pi(sk)->dst; ++ struct sco_conn *conn; ++ struct hci_conn *hcon; ++ struct hci_dev *hdev; ++ int err = 0; ++ ++ BT_DBG("%s -> %s", batostr(src), batostr(dst)); ++ ++ if (!(hdev = hci_get_route(dst, src))) ++ return -EHOSTUNREACH; ++ ++ hci_dev_lock_bh(hdev); ++ ++ err = -ENOMEM; ++ ++ hcon = hci_connect(hdev, SCO_LINK, dst); ++ if (!hcon) ++ goto done; ++ ++ conn = sco_conn_add(hcon, 0); ++ if (!conn) { ++ hci_conn_put(hcon); ++ goto done; ++ } ++ ++ /* Update source addr of the socket */ ++ bacpy(src, conn->src); ++ ++ err = sco_chan_add(conn, sk, NULL); ++ if (err) ++ goto done; ++ ++ if (hcon->state == BT_CONNECTED) { ++ sco_sock_clear_timer(sk); ++ sk->state = BT_CONNECTED; ++ } else { ++ sk->state = BT_CONNECT; ++ sco_sock_set_timer(sk, sk->sndtimeo); ++ } ++done: ++ hci_dev_unlock_bh(hdev); ++ hci_dev_put(hdev); ++ return err; ++} ++ ++static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) ++{ ++ struct sco_conn *conn = sco_pi(sk)->conn; ++ struct sk_buff *skb; ++ int err, count; ++ ++ /* Check outgoing MTU */ ++ if (len > conn->mtu) ++ return -EINVAL; ++ ++ BT_DBG("sk %p len %d", sk, len); ++ ++ count = MIN(conn->mtu, len); ++ if (!(skb = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err))) ++ return err; ++ ++ if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) { ++ err = -EFAULT; ++ goto fail; ++ } ++ ++ if ((err = hci_send_sco(conn->hcon, skb)) < 0) ++ goto fail; ++ ++ return count; ++ ++fail: ++ kfree_skb(skb); ++ return err; ++} ++ ++static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) ++{ ++ struct sock *sk = sco_chan_get(conn); ++ ++ if (!sk) ++ goto drop; ++ ++ BT_DBG("sk %p len %d", sk, skb->len); ++ ++ if (sk->state != BT_CONNECTED) ++ goto drop; ++ ++ if (!sock_queue_rcv_skb(sk, skb)) ++ return; ++ ++drop: ++ kfree_skb(skb); ++ return; ++} ++ ++/* -------- Socket interface ---------- */ ++static struct sock *__sco_get_sock_by_addr(bdaddr_t *ba) ++{ ++ struct sock *sk; ++ ++ for (sk = sco_sk_list.head; sk; sk = sk->next) { ++ if (!bacmp(&bluez_pi(sk)->src, ba)) ++ break; ++ } ++ ++ return sk; ++} ++ ++/* Find socket listening on source bdaddr. ++ * Returns closest match. ++ */ ++static struct sock *sco_get_sock_listen(bdaddr_t *src) ++{ ++ struct sock *sk, *sk1 = NULL; ++ ++ read_lock(&sco_sk_list.lock); ++ ++ for (sk = sco_sk_list.head; sk; sk = sk->next) { ++ if (sk->state != BT_LISTEN) ++ continue; ++ ++ /* Exact match. */ ++ if (!bacmp(&bluez_pi(sk)->src, src)) ++ break; ++ ++ /* Closest match */ ++ if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY)) ++ sk1 = sk; ++ } ++ ++ read_unlock(&sco_sk_list.lock); ++ ++ return sk ? sk : sk1; ++} ++ ++static void sco_sock_destruct(struct sock *sk) ++{ ++ BT_DBG("sk %p", sk); ++ ++ skb_queue_purge(&sk->receive_queue); ++ skb_queue_purge(&sk->write_queue); ++ ++ MOD_DEC_USE_COUNT; ++} ++ ++static void sco_sock_cleanup_listen(struct sock *parent) ++{ ++ struct sock *sk; ++ ++ BT_DBG("parent %p", parent); ++ ++ /* Close not yet accepted channels */ ++ while ((sk = bluez_accept_dequeue(parent, NULL))) { ++ sco_sock_close(sk); ++ sco_sock_kill(sk); ++ } ++ ++ parent->state = BT_CLOSED; ++ parent->zapped = 1; ++} ++ ++/* Kill socket (only if zapped and orphan) ++ * Must be called on unlocked socket. ++ */ ++static void sco_sock_kill(struct sock *sk) ++{ ++ if (!sk->zapped || sk->socket) ++ return; ++ ++ BT_DBG("sk %p state %d", sk, sk->state); ++ ++ /* Kill poor orphan */ ++ bluez_sock_unlink(&sco_sk_list, sk); ++ sk->dead = 1; ++ sock_put(sk); ++} ++ ++/* Close socket. ++ * Must be called on unlocked socket. ++ */ ++static void sco_sock_close(struct sock *sk) ++{ ++ struct sco_conn *conn; ++ ++ sco_sock_clear_timer(sk); ++ ++ lock_sock(sk); ++ ++ conn = sco_pi(sk)->conn; ++ ++ BT_DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket); ++ ++ switch (sk->state) { ++ case BT_LISTEN: ++ sco_sock_cleanup_listen(sk); ++ break; ++ ++ case BT_CONNECTED: ++ case BT_CONFIG: ++ case BT_CONNECT: ++ case BT_DISCONN: ++ sco_chan_del(sk, ECONNRESET); ++ break; ++ ++ default: ++ sk->zapped = 1; ++ break; ++ }; ++ ++ release_sock(sk); ++} ++ ++static void sco_sock_init(struct sock *sk, struct sock *parent) ++{ ++ BT_DBG("sk %p", sk); ++ ++ if (parent) ++ sk->type = parent->type; ++} ++ ++static struct sock *sco_sock_alloc(struct socket *sock, int proto, int prio) ++{ ++ struct sock *sk; ++ ++ if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1))) ++ return NULL; ++ ++ bluez_sock_init(sock, sk); ++ ++ sk->zapped = 0; ++ ++ sk->destruct = sco_sock_destruct; ++ sk->sndtimeo = SCO_CONN_TIMEOUT; ++ ++ sk->protocol = proto; ++ sk->state = BT_OPEN; ++ ++ sco_sock_init_timer(sk); ++ ++ bluez_sock_link(&sco_sk_list, sk); ++ ++ MOD_INC_USE_COUNT; ++ return sk; ++} ++ ++static int sco_sock_create(struct socket *sock, int protocol) ++{ ++ struct sock *sk; ++ ++ BT_DBG("sock %p", sock); ++ ++ sock->state = SS_UNCONNECTED; ++ ++ if (sock->type != SOCK_SEQPACKET) ++ return -ESOCKTNOSUPPORT; ++ ++ sock->ops = &sco_sock_ops; ++ ++ if (!(sk = sco_sock_alloc(sock, protocol, GFP_KERNEL))) ++ return -ENOMEM; ++ ++ sco_sock_init(sk, NULL); ++ return 0; ++} ++ ++static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) ++{ ++ struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; ++ struct sock *sk = sock->sk; ++ bdaddr_t *src = &sa->sco_bdaddr; ++ int err = 0; ++ ++ BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr)); ++ ++ if (!addr || addr->sa_family != AF_BLUETOOTH) ++ return -EINVAL; ++ ++ lock_sock(sk); ++ ++ if (sk->state != BT_OPEN) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ write_lock_bh(&sco_sk_list.lock); ++ ++ if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) { ++ err = -EADDRINUSE; ++ } else { ++ /* Save source address */ ++ bacpy(&bluez_pi(sk)->src, &sa->sco_bdaddr); ++ sk->state = BT_BOUND; ++ } ++ ++ write_unlock_bh(&sco_sk_list.lock); ++ ++done: ++ release_sock(sk); ++ ++ return err; ++} ++ ++static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) ++{ ++ struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ ++ BT_DBG("sk %p", sk); ++ ++ if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_sco)) ++ return -EINVAL; ++ ++ if (sk->state != BT_OPEN && sk->state != BT_BOUND) ++ return -EBADFD; ++ ++ if (sk->type != SOCK_SEQPACKET) ++ return -EINVAL; ++ ++ lock_sock(sk); ++ ++ /* Set destination address and psm */ ++ bacpy(&bluez_pi(sk)->dst, &sa->sco_bdaddr); ++ ++ if ((err = sco_connect(sk))) ++ goto done; ++ ++ err = bluez_sock_wait_state(sk, BT_CONNECTED, ++ sock_sndtimeo(sk, flags & O_NONBLOCK)); ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++int sco_sock_listen(struct socket *sock, int backlog) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sk %p backlog %d", sk, backlog); ++ ++ lock_sock(sk); ++ ++ if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ sk->max_ack_backlog = backlog; ++ sk->ack_backlog = 0; ++ sk->state = BT_LISTEN; ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++int sco_sock_accept(struct socket *sock, struct socket *newsock, int flags) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ struct sock *sk = sock->sk, *ch; ++ long timeo; ++ int err = 0; ++ ++ lock_sock(sk); ++ ++ if (sk->state != BT_LISTEN) { ++ err = -EBADFD; ++ goto done; ++ } ++ ++ timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); ++ ++ BT_DBG("sk %p timeo %ld", sk, timeo); ++ ++ /* Wait for an incoming connection. (wake-one). */ ++ add_wait_queue_exclusive(sk->sleep, &wait); ++ while (!(ch = bluez_accept_dequeue(sk, newsock))) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ if (!timeo) { ++ err = -EAGAIN; ++ break; ++ } ++ ++ release_sock(sk); ++ timeo = schedule_timeout(timeo); ++ lock_sock(sk); ++ ++ if (sk->state != BT_LISTEN) { ++ err = -EBADFD; ++ break; ++ } ++ ++ if (signal_pending(current)) { ++ err = sock_intr_errno(timeo); ++ break; ++ } ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(sk->sleep, &wait); ++ ++ if (err) ++ goto done; ++ ++ newsock->state = SS_CONNECTED; ++ ++ BT_DBG("new socket %p", ch); ++ ++done: ++ release_sock(sk); ++ return err; ++} ++ ++static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer) ++{ ++ struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; ++ struct sock *sk = sock->sk; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ addr->sa_family = AF_BLUETOOTH; ++ *len = sizeof(struct sockaddr_sco); ++ ++ if (peer) ++ bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->dst); ++ else ++ bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->src); ++ ++ return 0; ++} ++ ++static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ if (sk->err) ++ return sock_error(sk); ++ ++ if (msg->msg_flags & MSG_OOB) ++ return -EOPNOTSUPP; ++ ++ lock_sock(sk); ++ ++ if (sk->state == BT_CONNECTED) ++ err = sco_send_frame(sk, msg, len); ++ else ++ err = -ENOTCONN; ++ ++ release_sock(sk); ++ return err; ++} ++ ++int sco_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sk %p", sk); ++ ++ lock_sock(sk); ++ ++ switch (optname) { ++ default: ++ err = -ENOPROTOOPT; ++ break; ++ }; ++ ++ release_sock(sk); ++ return err; ++} ++ ++int sco_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) ++{ ++ struct sock *sk = sock->sk; ++ struct sco_options opts; ++ struct sco_conninfo cinfo; ++ int len, err = 0; ++ ++ BT_DBG("sk %p", sk); ++ ++ if (get_user(len, optlen)) ++ return -EFAULT; ++ ++ lock_sock(sk); ++ ++ switch (optname) { ++ case SCO_OPTIONS: ++ if (sk->state != BT_CONNECTED) { ++ err = -ENOTCONN; ++ break; ++ } ++ ++ opts.mtu = sco_pi(sk)->conn->mtu; ++ ++ BT_DBG("mtu %d", opts.mtu); ++ ++ len = MIN(len, sizeof(opts)); ++ if (copy_to_user(optval, (char *)&opts, len)) ++ err = -EFAULT; ++ ++ break; ++ ++ case SCO_CONNINFO: ++ if (sk->state != BT_CONNECTED) { ++ err = -ENOTCONN; ++ break; ++ } ++ ++ cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle; ++ ++ len = MIN(len, sizeof(cinfo)); ++ if (copy_to_user(optval, (char *)&cinfo, len)) ++ err = -EFAULT; ++ ++ break; ++ ++ default: ++ err = -ENOPROTOOPT; ++ break; ++ }; ++ ++ release_sock(sk); ++ return err; ++} ++ ++static int sco_sock_release(struct socket *sock) ++{ ++ struct sock *sk = sock->sk; ++ int err = 0; ++ ++ BT_DBG("sock %p, sk %p", sock, sk); ++ ++ if (!sk) ++ return 0; ++ ++ sco_sock_close(sk); ++ if (sk->linger) { ++ lock_sock(sk); ++ err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime); ++ release_sock(sk); ++ } ++ ++ sock_orphan(sk); ++ sco_sock_kill(sk); ++ return err; ++} ++ ++static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) ++{ ++ BT_DBG("conn %p", conn); ++ ++ sco_pi(sk)->conn = conn; ++ conn->sk = sk; ++ ++ if (parent) ++ bluez_accept_enqueue(parent, sk); ++} ++ ++static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) ++{ ++ int err = 0; ++ ++ sco_conn_lock(conn); ++ if (conn->sk) { ++ err = -EBUSY; ++ } else { ++ __sco_chan_add(conn, sk, parent); ++ } ++ sco_conn_unlock(conn); ++ return err; ++} ++ ++static inline struct sock * sco_chan_get(struct sco_conn *conn) ++{ ++ struct sock *sk = NULL; ++ sco_conn_lock(conn); ++ sk = conn->sk; ++ sco_conn_unlock(conn); ++ return sk; ++} ++ ++/* Delete channel. ++ * Must be called on the locked socket. */ ++static void sco_chan_del(struct sock *sk, int err) ++{ ++ struct sco_conn *conn; ++ ++ conn = sco_pi(sk)->conn; ++ ++ BT_DBG("sk %p, conn %p, err %d", sk, conn, err); ++ ++ if (conn) { ++ sco_conn_lock(conn); ++ conn->sk = NULL; ++ sco_pi(sk)->conn = NULL; ++ sco_conn_unlock(conn); ++ hci_conn_put(conn->hcon); ++ } ++ ++ sk->state = BT_CLOSED; ++ sk->err = err; ++ sk->state_change(sk); ++ ++ sk->zapped = 1; ++} ++ ++static void sco_conn_ready(struct sco_conn *conn) ++{ ++ struct sock *parent, *sk; ++ ++ BT_DBG("conn %p", conn); ++ ++ sco_conn_lock(conn); ++ ++ if ((sk = conn->sk)) { ++ sco_sock_clear_timer(sk); ++ bh_lock_sock(sk); ++ sk->state = BT_CONNECTED; ++ sk->state_change(sk); ++ bh_unlock_sock(sk); ++ } else { ++ parent = sco_get_sock_listen(conn->src); ++ if (!parent) ++ goto done; ++ ++ bh_lock_sock(parent); ++ ++ sk = sco_sock_alloc(NULL, BTPROTO_SCO, GFP_ATOMIC); ++ if (!sk) { ++ bh_unlock_sock(parent); ++ goto done; ++ } ++ ++ sco_sock_init(sk, parent); ++ ++ bacpy(&bluez_pi(sk)->src, conn->src); ++ bacpy(&bluez_pi(sk)->dst, conn->dst); ++ ++ hci_conn_hold(conn->hcon); ++ __sco_chan_add(conn, sk, parent); ++ ++ sk->state = BT_CONNECTED; ++ ++ /* Wake up parent */ ++ parent->data_ready(parent, 1); ++ ++ bh_unlock_sock(parent); ++ } ++ ++done: ++ sco_conn_unlock(conn); ++} ++ ++/* ----- SCO interface with lower layer (HCI) ----- */ ++int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) ++{ ++ BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); ++ ++ /* Always accept connection */ ++ return HCI_LM_ACCEPT; ++} ++ ++int sco_connect_cfm(struct hci_conn *hcon, __u8 status) ++{ ++ BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); ++ ++ if (hcon->type != SCO_LINK) ++ return 0; ++ ++ if (!status) { ++ struct sco_conn *conn; ++ ++ conn = sco_conn_add(hcon, status); ++ if (conn) ++ sco_conn_ready(conn); ++ } else ++ sco_conn_del(hcon, bterr(status)); ++ ++ return 0; ++} ++ ++int sco_disconn_ind(struct hci_conn *hcon, __u8 reason) ++{ ++ BT_DBG("hcon %p reason %d", hcon, reason); ++ ++ if (hcon->type != SCO_LINK) ++ return 0; ++ ++ sco_conn_del(hcon, bterr(reason)); ++ return 0; ++} ++ ++int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb) ++{ ++ struct sco_conn *conn = hcon->sco_data; ++ ++ if (!conn) ++ goto drop; ++ ++ BT_DBG("conn %p len %d", conn, skb->len); ++ ++ if (skb->len) { ++ sco_recv_frame(conn, skb); ++ return 0; ++ } ++ ++drop: ++ kfree_skb(skb); ++ return 0; ++} ++ ++/* ----- Proc fs support ------ */ ++static int sco_sock_dump(char *buf, struct bluez_sock_list *list) ++{ ++ struct sco_pinfo *pi; ++ struct sock *sk; ++ char *ptr = buf; ++ ++ write_lock_bh(&list->lock); ++ ++ for (sk = list->head; sk; sk = sk->next) { ++ pi = sco_pi(sk); ++ ptr += sprintf(ptr, "%s %s %d\n", ++ batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst), ++ sk->state); ++ } ++ ++ write_unlock_bh(&list->lock); ++ ++ ptr += sprintf(ptr, "\n"); ++ ++ return ptr - buf; ++} ++ ++static int sco_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv) ++{ ++ char *ptr = buf; ++ int len; ++ ++ BT_DBG("count %d, offset %ld", count, offset); ++ ++ ptr += sco_sock_dump(ptr, &sco_sk_list); ++ len = ptr - buf; ++ ++ if (len <= count + offset) ++ *eof = 1; ++ ++ *start = buf + offset; ++ len -= offset; ++ ++ if (len > count) ++ len = count; ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++ ++static struct proto_ops sco_sock_ops = { ++ family: PF_BLUETOOTH, ++ release: sco_sock_release, ++ bind: sco_sock_bind, ++ connect: sco_sock_connect, ++ listen: sco_sock_listen, ++ accept: sco_sock_accept, ++ getname: sco_sock_getname, ++ sendmsg: sco_sock_sendmsg, ++ recvmsg: bluez_sock_recvmsg, ++ poll: bluez_sock_poll, ++ socketpair: sock_no_socketpair, ++ ioctl: sock_no_ioctl, ++ shutdown: sock_no_shutdown, ++ setsockopt: sco_sock_setsockopt, ++ getsockopt: sco_sock_getsockopt, ++ mmap: sock_no_mmap ++}; ++ ++static struct net_proto_family sco_sock_family_ops = { ++ family: PF_BLUETOOTH, ++ create: sco_sock_create ++}; ++ ++static struct hci_proto sco_hci_proto = { ++ name: "SCO", ++ id: HCI_PROTO_SCO, ++ connect_ind: sco_connect_ind, ++ connect_cfm: sco_connect_cfm, ++ disconn_ind: sco_disconn_ind, ++ recv_scodata: sco_recv_scodata, ++}; ++ ++int __init sco_init(void) ++{ ++ int err; ++ ++ if ((err = bluez_sock_register(BTPROTO_SCO, &sco_sock_family_ops))) { ++ BT_ERR("Can't register SCO socket layer"); ++ return err; ++ } ++ ++ if ((err = hci_register_proto(&sco_hci_proto))) { ++ BT_ERR("Can't register SCO protocol"); ++ return err; ++ } ++ ++ create_proc_read_entry("bluetooth/sco", 0, 0, sco_read_proc, NULL); ++ ++ BT_INFO("BlueZ SCO ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION); ++ BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"); ++ return 0; ++} ++ ++void sco_cleanup(void) ++{ ++ int err; ++ ++ remove_proc_entry("bluetooth/sco", NULL); ++ ++ /* Unregister socket, protocol and notifier */ ++ if ((err = bluez_sock_unregister(BTPROTO_SCO))) ++ BT_ERR("Can't unregister SCO socket layer %d", err); ++ ++ if ((err = hci_unregister_proto(&sco_hci_proto))) ++ BT_ERR("Can't unregister SCO protocol %d", err); ++} ++ ++module_init(sco_init); ++module_exit(sco_cleanup); ++ ++MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>"); ++MODULE_DESCRIPTION("BlueZ SCO ver " VERSION); ++MODULE_LICENSE("GPL"); +diff -urN linux-2.4.18/net/bluetooth/syms.c linux-2.4.18-mh9/net/bluetooth/syms.c +--- linux-2.4.18/net/bluetooth/syms.c Fri Sep 7 18:28:38 2001 ++++ linux-2.4.18-mh9/net/bluetooth/syms.c Mon Aug 25 18:38:12 2003 +@@ -25,7 +25,7 @@ + /* + * BlueZ symbols. + * +- * $Id$ ++ * $Id$ + */ + + #include <linux/config.h> +@@ -39,25 +39,28 @@ + #include <linux/socket.h> + + #include <net/bluetooth/bluetooth.h> +-#include <net/bluetooth/bluez.h> + #include <net/bluetooth/hci_core.h> + + /* HCI Core */ + EXPORT_SYMBOL(hci_register_dev); + EXPORT_SYMBOL(hci_unregister_dev); ++EXPORT_SYMBOL(hci_suspend_dev); ++EXPORT_SYMBOL(hci_resume_dev); ++ + EXPORT_SYMBOL(hci_register_proto); + EXPORT_SYMBOL(hci_unregister_proto); +-EXPORT_SYMBOL(hci_register_notifier); +-EXPORT_SYMBOL(hci_unregister_notifier); + ++EXPORT_SYMBOL(hci_get_route); + EXPORT_SYMBOL(hci_connect); +-EXPORT_SYMBOL(hci_disconnect); + EXPORT_SYMBOL(hci_dev_get); ++EXPORT_SYMBOL(hci_conn_auth); ++EXPORT_SYMBOL(hci_conn_encrypt); + + EXPORT_SYMBOL(hci_recv_frame); + EXPORT_SYMBOL(hci_send_acl); + EXPORT_SYMBOL(hci_send_sco); +-EXPORT_SYMBOL(hci_send_raw); ++EXPORT_SYMBOL(hci_send_cmd); ++EXPORT_SYMBOL(hci_si_event); + + /* BlueZ lib */ + EXPORT_SYMBOL(bluez_dump); +@@ -68,5 +71,11 @@ + /* BlueZ sockets */ + EXPORT_SYMBOL(bluez_sock_register); + EXPORT_SYMBOL(bluez_sock_unregister); ++EXPORT_SYMBOL(bluez_sock_init); + EXPORT_SYMBOL(bluez_sock_link); + EXPORT_SYMBOL(bluez_sock_unlink); ++EXPORT_SYMBOL(bluez_sock_recvmsg); ++EXPORT_SYMBOL(bluez_sock_poll); ++EXPORT_SYMBOL(bluez_accept_enqueue); ++EXPORT_SYMBOL(bluez_accept_dequeue); ++EXPORT_SYMBOL(bluez_sock_wait_state); diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/disable-pcmcia-probe.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/disable-pcmcia-probe.patch index e69de29bb2..79ba036323 100644 --- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/disable-pcmcia-probe.patch +++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/disable-pcmcia-probe.patch @@ -0,0 +1,17 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux/drivers/pcmcia/Config.in~disable-pcmcia-probe 2003-05-13 11:18:23.000000000 +0200 ++++ linux/drivers/pcmcia/Config.in 2004-05-27 13:59:50.000000000 +0200 +@@ -15,9 +15,6 @@ + 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 diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/idecs.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/idecs.patch index e69de29bb2..62038c34e2 100644 --- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/idecs.patch +++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/idecs.patch @@ -0,0 +1,77 @@ +--- linux/drivers/ide/ide-cs.c 2003-02-28 17:04:00.000000000 -0600 ++++ linux.new/drivers/ide/ide-cs.c 2003-02-28 17:18:53.000000000 -0600 +@@ -2,7 +2,7 @@ + + A driver for PCMCIA IDE/ATA disk cards + +- ide_cs.c 1.26 1999/11/16 02:10:49 ++ ide-cs.c 1.26 1999/11/16 02:10:49 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file +@@ -66,7 +66,7 @@ + MODULE_PARM(pc_debug, "i"); + #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) + static char *version = +-"ide_cs.c 1.26 1999/11/16 02:10:49 (David Hinds)"; ++"ide-cs.c 1.26 1999/11/16 02:10:49 (David Hinds)"; + #else + #define DEBUG(n, args...) + #endif +@@ -110,7 +110,7 @@ + static int ide_event(event_t event, int priority, + event_callback_args_t *args); + +-static dev_info_t dev_info = "ide_cs"; ++static dev_info_t dev_info = "ide-cs"; + + static dev_link_t *ide_attach(void); + static void ide_detach(dev_link_t *); +@@ -356,7 +356,7 @@ + } + + if (hd < 0) { +- printk(KERN_NOTICE "ide_cs: ide_register() at 0x%03x & 0x%03x" ++ printk(KERN_NOTICE "ide-cs: ide_register() at 0x%03x & 0x%03x" + ", irq %u failed\n", io_base, ctl_base, + link->irq.AssignedIRQ); + goto failed; +@@ -369,7 +369,7 @@ + info->node.minor = 0; + info->hd = hd; + link->dev = &info->node; +- printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n", ++ printk(KERN_INFO "ide-cs: %s: Vcc = %d.%d, Vpp = %d.%d\n", + info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10, + link->conf.Vpp1/10, link->conf.Vpp1%10); + +@@ -409,9 +409,9 @@ + MOD_DEC_USE_COUNT; + } + +- request_region(link->io.BasePort1, link->io.NumPorts1,"ide_cs"); ++ request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs"); + if (link->io.NumPorts2) +- request_region(link->io.BasePort2, link->io.NumPorts2,"ide_cs"); ++ request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs"); + + info->ndev = 0; + link->dev = NULL; +@@ -508,7 +508,7 @@ + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { +- printk(KERN_NOTICE "ide_cs: Card Services release " ++ printk(KERN_NOTICE "ide-cs: Card Services release " + "does not match!\n"); + return -1; + } +@@ -518,7 +518,7 @@ + + static void __exit exit_ide_cs(void) + { +- DEBUG(0, "ide_cs: unloading\n"); ++ DEBUG(0, "ide-cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + ide_detach(dev_list); diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/initsh.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/initsh.patch index e69de29bb2..a672631194 100644 --- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/initsh.patch +++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/initsh.patch @@ -0,0 +1,14 @@ +--- linux/init/main.c 2002-02-25 13:38:13.000000000 -0600 ++++ linux.new/init/main.c 2003-03-16 11:49:45.000000000 -0600 +@@ -830,8 +830,10 @@ + * trying to recover a really broken machine. + */ + +- if (execute_command) ++ if (execute_command) { ++ argv_init[0] = execute_command; + execve(execute_command,argv_init,envp_init); ++ } + execve("/sbin/init",argv_init,envp_init); + execve("/etc/init",argv_init,envp_init); + execve("/bin/init",argv_init,envp_init); diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw240_we15-6.diff b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw240_we15-6.diff index e69de29bb2..2ebfd8ec12 100644 --- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw240_we15-6.diff +++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw240_we15-6.diff @@ -0,0 +1,399 @@ +diff -u -p linux/include/linux/wireless.14.h linux/include/linux/wireless.h +--- linux/include/linux/wireless.14.h Mon Dec 2 18:51:00 2002 ++++ linux/include/linux/wireless.h Mon Dec 2 18:53:35 2002 +@@ -1,7 +1,7 @@ + /* + * This file define a set of standard wireless extensions + * +- * Version : 14 25.1.02 ++ * Version : 15 12.7.02 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> + * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. +@@ -80,7 +80,7 @@ + * (there is some stuff that will be added in the future...) + * I just plan to increment with each new version. + */ +-#define WIRELESS_EXT 14 ++#define WIRELESS_EXT 15 + + /* + * Changes : +@@ -153,17 +153,32 @@ + * - Define additional specific event numbers + * - Add "addr" and "param" fields in union iwreq_data + * - AP scanning stuff (SIOCSIWSCAN and friends) ++ * ++ * V14 to V15 ++ * ---------- ++ * - Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg ++ * - Make struct iw_freq signed (both m & e), add explicit padding ++ * - Add IWEVCUSTOM for driver specific event/scanning token ++ * - Add IW_MAX_GET_SPY for driver returning a lot of addresses ++ * - Add IW_TXPOW_RANGE for range of Tx Powers ++ * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points ++ * - Add IW_MODE_MONITOR for passive monitor + */ + + /**************************** CONSTANTS ****************************/ + + /* -------------------------- IOCTL LIST -------------------------- */ + +-/* Basic operations */ ++/* Wireless Identification */ + #define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */ + #define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ +-#define SIOCSIWNWID 0x8B02 /* set network id (the cell) */ +-#define SIOCGIWNWID 0x8B03 /* get network id */ ++/* SIOCGIWNAME is used to verify the presence of Wireless Extensions. ++ * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"... ++ * Don't put the name of your driver there, it's useless. */ ++ ++/* Basic operations */ ++#define SIOCSIWNWID 0x8B02 /* set network id (pre-802.11) */ ++#define SIOCGIWNWID 0x8B03 /* get network id (the cell) */ + #define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */ + #define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */ + #define SIOCSIWMODE 0x8B06 /* set operation mode */ +@@ -178,16 +193,18 @@ + #define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */ + #define SIOCSIWSTATS 0x8B0E /* Unused */ + #define SIOCGIWSTATS 0x8B0F /* Get /proc/net/wireless stats */ ++/* SIOCGIWSTATS is strictly used between user space and the kernel, and ++ * is never passed to the driver (i.e. the driver will never see it). */ + +-/* Mobile IP support */ ++/* Mobile IP support (statistics per MAC address) */ + #define SIOCSIWSPY 0x8B10 /* set spy addresses */ + #define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */ + + /* Access Point manipulation */ + #define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ + #define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ +-#define SIOCGIWAPLIST 0x8B17 /* get list of access point in range */ +-#define SIOCSIWSCAN 0x8B18 /* trigger scanning */ ++#define SIOCGIWAPLIST 0x8B17 /* Deprecated in favor of scanning */ ++#define SIOCSIWSCAN 0x8B18 /* trigger scanning (list cells) */ + #define SIOCGIWSCAN 0x8B19 /* get scanning results */ + + /* 802.11 specific support */ +@@ -197,9 +214,7 @@ + #define SIOCGIWNICKN 0x8B1D /* get node name/nickname */ + /* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit + * within the 'iwreq' structure, so we need to use the 'data' member to +- * point to a string in user space, like it is done for RANGE... +- * The "flags" member indicate if the ESSID is active or not (promiscuous). +- */ ++ * point to a string in user space, like it is done for RANGE... */ + + /* Other parameters useful in 802.11 and some other devices */ + #define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */ +@@ -257,7 +272,10 @@ + /* Most events use the same identifier as ioctl requests */ + + #define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ +-#define IWEVQUAL 0x8C01 /* Quality part of statistics */ ++#define IWEVQUAL 0x8C01 /* Quality part of statistics (scan) */ ++#define IWEVCUSTOM 0x8C02 /* Driver specific ascii string */ ++#define IWEVREGISTERED 0x8C03 /* Discovered a new node (AP mode) */ ++#define IWEVEXPIRED 0x8C04 /* Expired a node (AP mode) */ + + #define IWEVFIRST 0x8C00 + +@@ -273,7 +291,8 @@ + #define IW_PRIV_TYPE_BYTE 0x1000 /* Char as number */ + #define IW_PRIV_TYPE_CHAR 0x2000 /* Char as character */ + #define IW_PRIV_TYPE_INT 0x4000 /* 32 bits int */ +-#define IW_PRIV_TYPE_FLOAT 0x5000 ++#define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */ ++#define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */ + + #define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed nuber of args */ + +@@ -297,13 +316,16 @@ + + /* Maximum tx powers in the range struct */ + #define IW_MAX_TXPOWER 8 ++/* Note : if you more than 8 TXPowers, just set the max and min or ++ * a few of them in the struct iw_range. */ + + /* Maximum of address that you may set with SPY */ +-#define IW_MAX_SPY 8 ++#define IW_MAX_SPY 8 /* set */ ++#define IW_MAX_GET_SPY 64 /* get */ + + /* Maximum of address that you may get in the + list of access points in range */ +-#define IW_MAX_AP 8 ++#define IW_MAX_AP 64 + + /* Maximum size of the ESSID and NICKN strings */ + #define IW_ESSID_MAX_SIZE 32 +@@ -315,6 +337,7 @@ + #define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */ + #define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */ + #define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ ++#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */ + + /* Maximum number of size of encoding token available + * they are listed in the range structure */ +@@ -350,8 +373,10 @@ + #define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ + + /* Transmit Power flags available */ ++#define IW_TXPOW_TYPE 0x00FF /* Type of value */ + #define IW_TXPOW_DBM 0x0000 /* Value is in dBm */ + #define IW_TXPOW_MWATT 0x0001 /* Value is in mW */ ++#define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */ + + /* Retry limits and lifetime flags available */ + #define IW_RETRY_ON 0x0000 /* No details... */ +@@ -376,6 +401,9 @@ + /* Maximum size of returned data */ + #define IW_SCAN_MAX_DATA 4096 /* In bytes */ + ++/* Max number of char in custom event - use multiple of them if needed */ ++#define IW_CUSTOM_MAX 256 /* In bytes */ ++ + /****************************** TYPES ******************************/ + + /* --------------------------- SUBTYPES --------------------------- */ +@@ -411,9 +439,10 @@ struct iw_point + */ + struct iw_freq + { +- __u32 m; /* Mantissa */ +- __u16 e; /* Exponent */ ++ __s32 m; /* Mantissa */ ++ __s16 e; /* Exponent */ + __u8 i; /* List index (when in range struct) */ ++ __u8 pad; /* Unused - just for alignement */ + }; + + /* +diff -u -p linux/include/net/iw_handler.14.h linux/include/net/iw_handler.h +--- linux/include/net/iw_handler.14.h Mon Dec 2 18:51:17 2002 ++++ linux/include/net/iw_handler.h Mon Dec 2 18:54:51 2002 +@@ -1,7 +1,7 @@ + /* + * This file define the new driver API for Wireless Extensions + * +- * Version : 3 17.1.02 ++ * Version : 4 21.6.02 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> + * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved. +@@ -206,7 +206,7 @@ + * will be needed... + * I just plan to increment with each new version. + */ +-#define IW_HANDLER_VERSION 3 ++#define IW_HANDLER_VERSION 4 + + /* + * Changes : +@@ -217,6 +217,9 @@ + * - Add Wireless Event support : + * o wireless_send_event() prototype + * o iwe_stream_add_event/point() inline functions ++ * V3 to V4 ++ * -------- ++ * - Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes + */ + + /**************************** CONSTANTS ****************************/ +@@ -233,10 +236,10 @@ + #define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */ + #define IW_HEADER_TYPE_UINT 4 /* __u32 */ + #define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */ +-#define IW_HEADER_TYPE_POINT 6 /* struct iw_point */ +-#define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */ +-#define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */ +-#define IW_HEADER_TYPE_QUAL 9 /* struct iw_quality */ ++#define IW_HEADER_TYPE_ADDR 6 /* struct sockaddr */ ++#define IW_HEADER_TYPE_POINT 8 /* struct iw_point */ ++#define IW_HEADER_TYPE_PARAM 9 /* struct iw_param */ ++#define IW_HEADER_TYPE_QUAL 10 /* struct iw_quality */ + + /* Handling flags */ + /* Most are not implemented. I just use them as a reminder of some +diff -u -p linux/net/core/wireless.14.c linux/net/core/wireless.c +--- linux/net/core/wireless.14.c Mon Dec 2 18:51:35 2002 ++++ linux/net/core/wireless.c Mon Dec 2 18:53:10 2002 +@@ -33,8 +33,16 @@ + * o Propagate events as rtnetlink IFLA_WIRELESS option + * o Generate event on selected SET requests + * +- * v4 - 18.04.01 - Jean II ++ * v4 - 18.04.02 - Jean II + * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1 ++ * ++ * v5 - 21.06.02 - Jean II ++ * o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup) ++ * o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes ++ * o Add IWEVCUSTOM for driver specific event/scanning token ++ * o Turn on WE_STRICT_WRITE by default + kernel warning ++ * o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num) ++ * o Fix off-by-one in test (extra_size <= IFNAMSIZ) + */ + + /***************************** INCLUDES *****************************/ +@@ -50,8 +58,9 @@ + + /**************************** CONSTANTS ****************************/ + +-/* This will be turned on later on... */ +-#undef WE_STRICT_WRITE /* Check write buffer size */ ++/* Enough lenience, let's make sure things are proper... */ ++#define WE_STRICT_WRITE /* Check write buffer size */ ++/* I'll probably drop both the define and kernel message in the next version */ + + /* Debuging stuff */ + #undef WE_IOCTL_DEBUG /* Debug IOCTL API */ +@@ -106,7 +115,7 @@ static const struct iw_ioctl_description + /* SIOCSIWSPY */ + { IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0}, + /* SIOCGIWSPY */ +- { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0}, ++ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_GET_SPY, 0}, + /* -- hole -- */ + { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, + /* -- hole -- */ +@@ -176,25 +185,41 @@ static const struct iw_ioctl_description + { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, + /* IWEVQUAL */ + { IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0}, ++ /* IWEVCUSTOM */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_CUSTOM_MAX, 0}, ++ /* IWEVREGISTERED */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, ++ /* IWEVEXPIRED */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, + }; + static const int standard_event_num = (sizeof(standard_event) / + sizeof(struct iw_ioctl_description)); + + /* Size (in bytes) of the various private data types */ +-static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; ++static const char priv_type_size[] = { ++ 0, /* IW_PRIV_TYPE_NONE */ ++ 1, /* IW_PRIV_TYPE_BYTE */ ++ 1, /* IW_PRIV_TYPE_CHAR */ ++ 0, /* Not defined */ ++ sizeof(__u32), /* IW_PRIV_TYPE_INT */ ++ sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */ ++ sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */ ++ 0, /* Not defined */ ++}; + + /* Size (in bytes) of various events */ + static const int event_type_size[] = { +- IW_EV_LCP_LEN, ++ IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */ ++ 0, ++ IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ + 0, +- IW_EV_CHAR_LEN, ++ IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */ ++ IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ ++ IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ + 0, +- IW_EV_UINT_LEN, +- IW_EV_FREQ_LEN, + IW_EV_POINT_LEN, /* Without variable payload */ +- IW_EV_PARAM_LEN, +- IW_EV_ADDR_LEN, +- IW_EV_QUAL_LEN, ++ IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ ++ IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ + }; + + /************************ COMMON SUBROUTINES ************************/ +@@ -440,8 +465,10 @@ static inline int ioctl_export_private(s + return -EFAULT; + #ifdef WE_STRICT_WRITE + /* Check if there is enough buffer up there */ +- if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1)) ++ if(iwr->u.data.length < dev->wireless_handlers->num_private_args) { ++ printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args); + return -E2BIG; ++ } + #endif /* WE_STRICT_WRITE */ + + /* Set the number of available ioctls. */ +@@ -471,6 +498,7 @@ static inline int ioctl_standard_call(st + const struct iw_ioctl_description * descr; + struct iw_request_info info; + int ret = -EINVAL; ++ int user_size = 0; + + /* Get the description of the IOCTL */ + if((cmd - SIOCIWFIRST) >= standard_ioctl_num) +@@ -518,11 +546,8 @@ static inline int ioctl_standard_call(st + /* Check NULL pointer */ + if(iwr->u.data.pointer == NULL) + return -EFAULT; +-#ifdef WE_STRICT_WRITE +- /* Check if there is enough buffer up there */ +- if(iwr->u.data.length < descr->max_tokens) +- return -E2BIG; +-#endif /* WE_STRICT_WRITE */ ++ /* Save user space buffer size for checking */ ++ user_size = iwr->u.data.length; + } + + #ifdef WE_IOCTL_DEBUG +@@ -559,6 +584,15 @@ static inline int ioctl_standard_call(st + + /* If we have something to return to the user */ + if (!ret && IW_IS_GET(cmd)) { ++#ifdef WE_STRICT_WRITE ++ /* Check if there is enough buffer up there */ ++ if(user_size < iwr->u.data.length) { ++ printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length); ++ kfree(extra); ++ return -E2BIG; ++ } ++#endif /* WE_STRICT_WRITE */ ++ + err = copy_to_user(iwr->u.data.pointer, extra, + iwr->u.data.length * + descr->token_size); +@@ -646,12 +680,18 @@ static inline int ioctl_private_call(str + /* Compute the size of the set/get arguments */ + if(descr != NULL) { + if(IW_IS_SET(cmd)) { ++ int offset = 0; /* For sub-ioctls */ ++ /* Check for sub-ioctl handler */ ++ if(descr->name[0] == '\0') ++ /* Reserve one int for sub-ioctl index */ ++ offset = sizeof(__u32); ++ + /* Size of set arguments */ + extra_size = get_priv_size(descr->set_args); + + /* Does it fits in iwr ? */ + if((descr->set_args & IW_PRIV_SIZE_FIXED) && +- (extra_size < IFNAMSIZ)) ++ ((extra_size + offset) <= IFNAMSIZ)) + extra_size = 0; + } else { + /* Size of set arguments */ +@@ -659,7 +699,7 @@ static inline int ioctl_private_call(str + + /* Does it fits in iwr ? */ + if((descr->get_args & IW_PRIV_SIZE_FIXED) && +- (extra_size < IFNAMSIZ)) ++ (extra_size <= IFNAMSIZ)) + extra_size = 0; + } + } +@@ -925,7 +965,7 @@ void wireless_send_event(struct net_devi + * The best the driver could do is to log an error message. + * We will do it ourselves instead... + */ +- printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n", ++ printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n", + dev->name, cmd); + return; + } diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w13-5.diff b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w13-5.diff index e69de29bb2..a27a7654a9 100644 --- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w13-5.diff +++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w13-5.diff @@ -0,0 +1,1513 @@ +diff -u -p -r --new-file linux/include/linux-w12/netdevice.h linux/include/linux/netdevice.h +--- linux/include/linux-w12/netdevice.h Thu Nov 22 11:47:09 2001 ++++ linux/include/linux/netdevice.h Thu Jan 17 12:00:39 2002 +@@ -278,6 +278,10 @@ struct net_device + struct net_device_stats* (*get_stats)(struct net_device *dev); + struct iw_statistics* (*get_wireless_stats)(struct net_device *dev); + ++ /* List of functions to handle Wireless Extensions (instead of ioctl). ++ * See <net/iw_handler.h> for details. Jean II */ ++ struct iw_handler_def * wireless_handlers; ++ + /* + * This marks the end of the "visible" part of the structure. All + * fields hereafter are internal to the system, and may change at +diff -u -p -r --new-file linux/include/linux-w12/wireless.h linux/include/linux/wireless.h +--- linux/include/linux-w12/wireless.h Thu Nov 22 11:47:12 2001 ++++ linux/include/linux/wireless.h Thu Jan 17 12:04:08 2002 +@@ -1,9 +1,10 @@ + /* + * This file define a set of standard wireless extensions + * +- * Version : 12 5.10.01 ++ * Version : 13 6.12.01 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> ++ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. + */ + + #ifndef _LINUX_WIRELESS_H +@@ -11,6 +12,8 @@ + + /************************** DOCUMENTATION **************************/ + /* ++ * Initial APIs (1996 -> onward) : ++ * ----------------------------- + * Basically, the wireless extensions are for now a set of standard ioctl + * call + /proc/net/wireless + * +@@ -27,16 +30,27 @@ + * We have the list of command plus a structure descibing the + * data exchanged... + * Note that to add these ioctl, I was obliged to modify : +- * net/core/dev.c (two place + add include) +- * net/ipv4/af_inet.c (one place + add include) ++ * # net/core/dev.c (two place + add include) ++ * # net/ipv4/af_inet.c (one place + add include) + * + * /proc/net/wireless is a copy of /proc/net/dev. + * We have a structure for data passed from the driver to /proc/net/wireless + * Too add this, I've modified : +- * net/core/dev.c (two other places) +- * include/linux/netdevice.h (one place) +- * include/linux/proc_fs.h (one place) ++ * # net/core/dev.c (two other places) ++ * # include/linux/netdevice.h (one place) ++ * # include/linux/proc_fs.h (one place) ++ * ++ * New driver API (2001 -> onward) : ++ * ------------------------------- ++ * This file is only concerned with the user space API and common definitions. ++ * The new driver API is defined and documented in : ++ * # include/net/iw_handler.h + * ++ * Note as well that /proc/net/wireless implementation has now moved in : ++ * # include/linux/wireless.c ++ * ++ * Other comments : ++ * -------------- + * Do not add here things that are redundant with other mechanisms + * (drivers init, ifconfig, /proc/net/dev, ...) and with are not + * wireless specific. +@@ -54,16 +68,14 @@ + #include <linux/socket.h> /* for "struct sockaddr" et al */ + #include <linux/if.h> /* for IFNAMSIZ and co... */ + +-/**************************** CONSTANTS ****************************/ +- +-/* --------------------------- VERSION --------------------------- */ ++/***************************** VERSION *****************************/ + /* + * This constant is used to know the availability of the wireless + * extensions and to know which version of wireless extensions it is + * (there is some stuff that will be added in the future...) + * I just plan to increment with each new version. + */ +-#define WIRELESS_EXT 12 ++#define WIRELESS_EXT 13 + + /* + * Changes : +@@ -123,12 +135,20 @@ + * - Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space + * - Add new statistics (frag, retry, beacon) + * - Add average quality (for user space calibration) ++ * ++ * V12 to V13 ++ * ---------- ++ * - Document creation of new driver API. ++ * - Extract union iwreq_data from struct iwreq (for new driver API). ++ * - Rename SIOCSIWNAME as SIOCSIWCOMMIT + */ + ++/**************************** CONSTANTS ****************************/ ++ + /* -------------------------- IOCTL LIST -------------------------- */ + + /* Basic operations */ +-#define SIOCSIWNAME 0x8B00 /* Unused */ ++#define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */ + #define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ + #define SIOCSIWNWID 0x8B02 /* set network id (the cell) */ + #define SIOCGIWNWID 0x8B03 /* get network id */ +@@ -414,13 +434,49 @@ struct iw_statistics + + /* ------------------------ IOCTL REQUEST ------------------------ */ + /* ++ * This structure defines the payload of an ioctl, and is used ++ * below. ++ * ++ * Note that this structure should fit on the memory footprint ++ * of iwreq (which is the same as ifreq), which mean a max size of ++ * 16 octets = 128 bits. Warning, pointers might be 64 bits wide... ++ * You should check this when increasing the structures defined ++ * above in this file... ++ */ ++union iwreq_data ++{ ++ /* Config - generic */ ++ char name[IFNAMSIZ]; ++ /* Name : used to verify the presence of wireless extensions. ++ * Name of the protocol/provider... */ ++ ++ struct iw_point essid; /* Extended network name */ ++ struct iw_param nwid; /* network id (or domain - the cell) */ ++ struct iw_freq freq; /* frequency or channel : ++ * 0-1000 = channel ++ * > 1000 = frequency in Hz */ ++ ++ struct iw_param sens; /* signal level threshold */ ++ struct iw_param bitrate; /* default bit rate */ ++ struct iw_param txpower; /* default transmit power */ ++ struct iw_param rts; /* RTS threshold threshold */ ++ struct iw_param frag; /* Fragmentation threshold */ ++ __u32 mode; /* Operation mode */ ++ struct iw_param retry; /* Retry limits & lifetime */ ++ ++ struct iw_point encoding; /* Encoding stuff : tokens */ ++ struct iw_param power; /* PM duration/timeout */ ++ ++ struct sockaddr ap_addr; /* Access point address */ ++ ++ struct iw_point data; /* Other large parameters */ ++}; ++ ++/* + * The structure to exchange data for ioctl. + * This structure is the same as 'struct ifreq', but (re)defined for + * convenience... +- * +- * Note that it should fit on the same memory footprint ! +- * You should check this when increasing the above structures (16 octets) +- * 16 octets = 128 bits. Warning, pointers might be 64 bits wide... ++ * Do I need to remind you about structure size (32 octets) ? + */ + struct iwreq + { +@@ -429,35 +485,8 @@ struct iwreq + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */ + } ifr_ifrn; + +- /* Data part */ +- union +- { +- /* Config - generic */ +- char name[IFNAMSIZ]; +- /* Name : used to verify the presence of wireless extensions. +- * Name of the protocol/provider... */ +- +- struct iw_point essid; /* Extended network name */ +- struct iw_param nwid; /* network id (or domain - the cell) */ +- struct iw_freq freq; /* frequency or channel : +- * 0-1000 = channel +- * > 1000 = frequency in Hz */ +- +- struct iw_param sens; /* signal level threshold */ +- struct iw_param bitrate; /* default bit rate */ +- struct iw_param txpower; /* default transmit power */ +- struct iw_param rts; /* RTS threshold threshold */ +- struct iw_param frag; /* Fragmentation threshold */ +- __u32 mode; /* Operation mode */ +- struct iw_param retry; /* Retry limits & lifetime */ +- +- struct iw_point encoding; /* Encoding stuff : tokens */ +- struct iw_param power; /* PM duration/timeout */ +- +- struct sockaddr ap_addr; /* Access point address */ +- +- struct iw_point data; /* Other large parameters */ +- } u; ++ /* Data part (defined just above) */ ++ union iwreq_data u; + }; + + /* -------------------------- IOCTL DATA -------------------------- */ +diff -u -p -r --new-file linux/include/net-w12/iw_handler.h linux/include/net/iw_handler.h +--- linux/include/net-w12/iw_handler.h Wed Dec 31 16:00:00 1969 ++++ linux/include/net/iw_handler.h Thu Jan 17 12:16:46 2002 +@@ -0,0 +1,374 @@ ++/* ++ * This file define the new driver API for Wireless Extensions ++ * ++ * Version : 2 6.12.01 ++ * ++ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> ++ * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved. ++ */ ++ ++#ifndef _IW_HANDLER_H ++#define _IW_HANDLER_H ++ ++/************************** DOCUMENTATION **************************/ ++/* ++ * Initial driver API (1996 -> onward) : ++ * ----------------------------------- ++ * The initial API just sends the IOCTL request received from user space ++ * to the driver (via the driver ioctl handler). The driver has to ++ * handle all the rest... ++ * ++ * The initial API also defines a specific handler in struct net_device ++ * to handle wireless statistics. ++ * ++ * The initial APIs served us well and has proven a reasonably good design. ++ * However, there is a few shortcommings : ++ * o No events, everything is a request to the driver. ++ * o Large ioctl function in driver with gigantic switch statement ++ * (i.e. spaghetti code). ++ * o Driver has to mess up with copy_to/from_user, and in many cases ++ * does it unproperly. Common mistakes are : ++ * * buffer overflows (no checks or off by one checks) ++ * * call copy_to/from_user with irq disabled ++ * o The user space interface is tied to ioctl because of the use ++ * copy_to/from_user. ++ * ++ * New driver API (2001 -> onward) : ++ * ------------------------------- ++ * The new driver API is just a bunch of standard functions (handlers), ++ * each handling a specific Wireless Extension. The driver just export ++ * the list of handler it supports, and those will be called apropriately. ++ * ++ * I tried to keep the main advantage of the previous API (simplicity, ++ * efficiency and light weight), and also I provide a good dose of backward ++ * compatibility (most structures are the same, driver can use both API ++ * simultaneously, ...). ++ * Hopefully, I've also addressed the shortcomming of the initial API. ++ * ++ * The advantage of the new API are : ++ * o Handling of Extensions in driver broken in small contained functions ++ * o Tighter checks of ioctl before calling the driver ++ * o Flexible commit strategy (at least, the start of it) ++ * o Backward compatibility (can be mixed with old API) ++ * o Driver doesn't have to worry about memory and user-space issues ++ * The last point is important for the following reasons : ++ * o You are now able to call the new driver API from any API you ++ * want (including from within other parts of the kernel). ++ * o Common mistakes are avoided (buffer overflow, user space copy ++ * with irq disabled and so on). ++ * ++ * The Drawback of the new API are : ++ * o bloat (especially kernel) ++ * o need to migrate existing drivers to new API ++ * My initial testing shows that the new API adds around 3kB to the kernel ++ * and save between 0 and 5kB from a typical driver. ++ * Also, as all structures and data types are unchanged, the migration is ++ * quite straightforward (but tedious). ++ * ++ * --- ++ * ++ * The new driver API is defined below in this file. User space should ++ * not be aware of what's happening down there... ++ * ++ * A new kernel wrapper is in charge of validating the IOCTLs and calling ++ * the appropriate driver handler. This is implemented in : ++ * # net/core/wireless.c ++ * ++ * The driver export the list of handlers in : ++ * # include/linux/netdevice.h (one place) ++ * ++ * The new driver API is available for WIRELESS_EXT >= 13. ++ * Good luck with migration to the new API ;-) ++ */ ++ ++/* ---------------------- THE IMPLEMENTATION ---------------------- */ ++/* ++ * Some of the choice I've made are pretty controversials. Defining an ++ * API is very much weighting compromises. This goes into some of the ++ * details and the thinking behind the implementation. ++ * ++ * Implementation goals : ++ * -------------------- ++ * The implementation goals were as follow : ++ * o Obvious : you should not need a PhD to understand what's happening, ++ * the benefit is easier maintainance. ++ * o Flexible : it should accomodate a wide variety of driver ++ * implementations and be as flexible as the old API. ++ * o Lean : it should be efficient memory wise to minimise the impact ++ * on kernel footprint. ++ * o Transparent to user space : the large number of user space ++ * applications that use Wireless Extensions should not need ++ * any modifications. ++ * ++ * Array of functions versus Struct of functions ++ * --------------------------------------------- ++ * 1) Having an array of functions allow the kernel code to access the ++ * handler in a single lookup, which is much more efficient (think hash ++ * table here). ++ * 2) The only drawback is that driver writer may put their handler in ++ * the wrong slot. This is trivial to test (I set the frequency, the ++ * bitrate changes). Once the handler is in the proper slot, it will be ++ * there forever, because the array is only extended at the end. ++ * 3) Backward/forward compatibility : adding new handler just require ++ * extending the array, so you can put newer driver in older kernel ++ * without having to patch the kernel code (and vice versa). ++ * ++ * All handler are of the same generic type ++ * ---------------------------------------- ++ * That's a feature !!! ++ * 1) Having a generic handler allow to have generic code, which is more ++ * efficient. If each of the handler was individually typed I would need ++ * to add a big switch in the kernel (== more bloat). This solution is ++ * more scalable, adding new Wireless Extensions doesn't add new code. ++ * 2) You can use the same handler in different slots of the array. For ++ * hardware, it may be more efficient or logical to handle multiple ++ * Wireless Extensions with a single function, and the API allow you to ++ * do that. (An example would be a single record on the card to control ++ * both bitrate and frequency, the handler would read the old record, ++ * modify it according to info->cmd and rewrite it). ++ * ++ * Functions prototype uses union iwreq_data ++ * ----------------------------------------- ++ * Some would have prefered functions defined this way : ++ * static int mydriver_ioctl_setrate(struct net_device *dev, ++ * long rate, int auto) ++ * 1) The kernel code doesn't "validate" the content of iwreq_data, and ++ * can't do it (different hardware may have different notion of what a ++ * valid frequency is), so we don't pretend that we do it. ++ * 2) The above form is not extendable. If I want to add a flag (for ++ * example to distinguish setting max rate and basic rate), I would ++ * break the prototype. Using iwreq_data is more flexible. ++ * 3) Also, the above form is not generic (see above). ++ * 4) I don't expect driver developper using the wrong field of the ++ * union (Doh !), so static typechecking doesn't add much value. ++ * 5) Lastly, you can skip the union by doing : ++ * static int mydriver_ioctl_setrate(struct net_device *dev, ++ * struct iw_request_info *info, ++ * struct iw_param *rrq, ++ * char *extra) ++ * And then adding the handler in the array like this : ++ * (iw_handler) mydriver_ioctl_setrate, // SIOCSIWRATE ++ * ++ * Using functions and not a registry ++ * ---------------------------------- ++ * Another implementation option would have been for every instance to ++ * define a registry (a struct containing all the Wireless Extensions) ++ * and only have a function to commit the registry to the hardware. ++ * 1) This approach can be emulated by the current code, but not ++ * vice versa. ++ * 2) Some drivers don't keep any configuration in the driver, for them ++ * adding such a registry would be a significant bloat. ++ * 3) The code to translate from Wireless Extension to native format is ++ * needed anyway, so it would not reduce significantely the amount of code. ++ * 4) The current approach only selectively translate Wireless Extensions ++ * to native format and only selectively set, whereas the registry approach ++ * would require to translate all WE and set all parameters for any single ++ * change. ++ * 5) For many Wireless Extensions, the GET operation return the current ++ * dynamic value, not the value that was set. ++ * ++ * This header is <net/iw_handler.h> ++ * --------------------------------- ++ * 1) This header is kernel space only and should not be exported to ++ * user space. Headers in "include/linux/" are exported, headers in ++ * "include/net/" are not. ++ * ++ * Mixed 32/64 bit issues ++ * ---------------------- ++ * The Wireless Extensions are designed to be 64 bit clean, by using only ++ * datatypes with explicit storage size. ++ * There are some issues related to kernel and user space using different ++ * memory model, and in particular 64bit kernel with 32bit user space. ++ * The problem is related to struct iw_point, that contains a pointer ++ * that *may* need to be translated. ++ * This is quite messy. The new API doesn't solve this problem (it can't), ++ * but is a step in the right direction : ++ * 1) Meta data about each ioctl is easily available, so we know what type ++ * of translation is needed. ++ * 2) The move of data between kernel and user space is only done in a single ++ * place in the kernel, so adding specific hooks in there is possible. ++ * 3) In the long term, it allows to move away from using ioctl as the ++ * user space API. ++ * ++ * So many comments and so few code ++ * -------------------------------- ++ * That's a feature. Comments won't bloat the resulting kernel binary. ++ */ ++ ++/***************************** INCLUDES *****************************/ ++ ++#include <linux/wireless.h> /* IOCTL user space API */ ++ ++/***************************** VERSION *****************************/ ++/* ++ * This constant is used to know which version of the driver API is ++ * available. Hopefully, this will be pretty stable and no changes ++ * will be needed... ++ * I just plan to increment with each new version. ++ */ ++#define IW_HANDLER_VERSION 2 ++ ++/**************************** CONSTANTS ****************************/ ++ ++/* Special error message for the driver to indicate that we ++ * should do a commit after return from the iw_handler */ ++#define EIWCOMMIT EINPROGRESS ++ ++/* Flags available in struct iw_request_info */ ++#define IW_REQUEST_FLAG_NONE 0x0000 /* No flag so far */ ++ ++/* Type of headers we know about (basically union iwreq_data) */ ++#define IW_HEADER_TYPE_NULL 0 /* Not available */ ++#define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */ ++#define IW_HEADER_TYPE_UINT 4 /* __u32 */ ++#define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */ ++#define IW_HEADER_TYPE_POINT 6 /* struct iw_point */ ++#define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */ ++#define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */ ++ ++/* Handling flags */ ++/* Most are not implemented. I just use them as a reminder of some ++ * cool features we might need one day ;-) */ ++#define IW_DESCR_FLAG_NONE 0x0000 /* Obvious */ ++/* Wrapper level flags */ ++#define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */ ++#define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */ ++#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET request is ROOT only */ ++/* Driver level flags */ ++#define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */ ++ ++/****************************** TYPES ******************************/ ++ ++/* ----------------------- WIRELESS HANDLER ----------------------- */ ++/* ++ * A wireless handler is just a standard function, that looks like the ++ * ioctl handler. ++ * We also define there how a handler list look like... As the Wireless ++ * Extension space is quite dense, we use a simple array, which is faster ++ * (that's the perfect hash table ;-). ++ */ ++ ++/* ++ * Meta data about the request passed to the iw_handler. ++ * Most handlers can safely ignore what's in there. ++ * The 'cmd' field might come handy if you want to use the same handler ++ * for multiple command... ++ * This struct is also my long term insurance. I can add new fields here ++ * without breaking the prototype of iw_handler... ++ */ ++struct iw_request_info ++{ ++ __u16 cmd; /* Wireless Extension command */ ++ __u16 flags; /* More to come ;-) */ ++}; ++ ++/* ++ * This is how a function handling a Wireless Extension should look ++ * like (both get and set, standard and private). ++ */ ++typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra); ++ ++/* ++ * This define all the handler that the driver export. ++ * As you need only one per driver type, please use a static const ++ * shared by all driver instances... Same for the members... ++ * This will be linked from net_device in <linux/netdevice.h> ++ */ ++struct iw_handler_def ++{ ++ /* Number of handlers defined (more precisely, index of the ++ * last defined handler + 1) */ ++ __u16 num_standard; ++ __u16 num_private; ++ /* Number of private arg description */ ++ __u16 num_private_args; ++ ++ /* Array of handlers for standard ioctls ++ * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME] ++ */ ++ iw_handler * standard; ++ ++ /* Array of handlers for private ioctls ++ * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV] ++ */ ++ iw_handler * private; ++ ++ /* Arguments of private handler. This one is just a list, so you ++ * can put it in any order you want and should not leave holes... ++ * We will automatically export that to user space... */ ++ struct iw_priv_args * private_args; ++ ++ /* In the long term, get_wireless_stats will move from ++ * 'struct net_device' to here, to minimise bloat. */ ++}; ++ ++/* ----------------------- WIRELESS EVENTS ----------------------- */ ++/* ++ * Currently we don't support events, so let's just plan for the ++ * future... ++ */ ++ ++/* ++ * A Wireless Event. ++ */ ++// How do we define short header ? We don't want a flag on length. ++// Probably a flag on event ? Highest bit to zero... ++struct iw_event ++{ ++ __u16 length; /* Lenght of this stuff */ ++ __u16 event; /* Wireless IOCTL */ ++ union iwreq_data header; /* IOCTL fixed payload */ ++ char extra[0]; /* Optional IOCTL data */ ++}; ++ ++/* ---------------------- IOCTL DESCRIPTION ---------------------- */ ++/* ++ * One of the main goal of the new interface is to deal entirely with ++ * user space/kernel space memory move. ++ * For that, we need to know : ++ * o if iwreq is a pointer or contain the full data ++ * o what is the size of the data to copy ++ * ++ * For private IOCTLs, we use the same rules as used by iwpriv and ++ * defined in struct iw_priv_args. ++ * ++ * For standard IOCTLs, things are quite different and we need to ++ * use the stuctures below. Actually, this struct is also more ++ * efficient, but that's another story... ++ */ ++ ++/* ++ * Describe how a standard IOCTL looks like. ++ */ ++struct iw_ioctl_description ++{ ++ __u8 header_type; /* NULL, iw_point or other */ ++ __u8 token_type; /* Future */ ++ __u16 token_size; /* Granularity of payload */ ++ __u16 min_tokens; /* Min acceptable token number */ ++ __u16 max_tokens; /* Max acceptable token number */ ++ __u32 flags; /* Special handling of the request */ ++}; ++ ++/* Need to think of short header translation table. Later. */ ++ ++/**************************** PROTOTYPES ****************************/ ++/* ++ * Functions part of the Wireless Extensions (defined in net/core/wireless.c). ++ * Those may be called only within the kernel. ++ */ ++ ++/* First : function strictly used inside the kernel */ ++ ++/* Handle /proc/net/wireless, called in net/code/dev.c */ ++extern int dev_get_wireless_info(char * buffer, char **start, off_t offset, ++ int length); ++ ++/* Handle IOCTLs, called in net/code/dev.c */ ++extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd); ++ ++/* Second : functions that may be called by driver modules */ ++/* None yet */ ++ ++#endif /* _LINUX_WIRELESS_H */ +diff -u -p -r --new-file linux/net/core-w12/Makefile linux/net/core/Makefile +--- linux/net/core-w12/Makefile Tue Oct 30 15:08:12 2001 ++++ linux/net/core/Makefile Thu Jan 17 11:06:07 2002 +@@ -26,5 +26,8 @@ obj-$(CONFIG_NET) += dev.o dev_mcast.o d + obj-$(CONFIG_NETFILTER) += netfilter.o + obj-$(CONFIG_NET_DIVERT) += dv.o + obj-$(CONFIG_NET_PROFILE) += profile.o ++obj-$(CONFIG_NET_RADIO) += wireless.o ++# Ugly. I wish all wireless drivers were moved in drivers/net/wireless ++obj-$(CONFIG_NET_PCMCIA_RADIO) += wireless.o + + include $(TOPDIR)/Rules.make +diff -u -p -r --new-file linux/net/core-w12/dev.c linux/net/core/dev.c +--- linux/net/core-w12/dev.c Wed Nov 7 14:39:36 2001 ++++ linux/net/core/dev.c Thu Jan 17 11:06:07 2002 +@@ -102,6 +102,7 @@ + #include <linux/module.h> + #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO) + #include <linux/wireless.h> /* Note : will define WIRELESS_EXT */ ++#include <net/iw_handler.h> + #endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ + #ifdef CONFIG_PLIP + extern int plip_init(void); +@@ -1796,122 +1797,6 @@ static int dev_proc_stats(char *buffer, + #endif /* CONFIG_PROC_FS */ + + +-#ifdef WIRELESS_EXT +-#ifdef CONFIG_PROC_FS +- +-/* +- * Print one entry of /proc/net/wireless +- * This is a clone of /proc/net/dev (just above) +- */ +-static int sprintf_wireless_stats(char *buffer, struct net_device *dev) +-{ +- /* Get stats from the driver */ +- struct iw_statistics *stats = (dev->get_wireless_stats ? +- dev->get_wireless_stats(dev) : +- (struct iw_statistics *) NULL); +- int size; +- +- if (stats != (struct iw_statistics *) NULL) { +- size = sprintf(buffer, +- "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d %6d %6d %6d\n", +- dev->name, +- stats->status, +- stats->qual.qual, +- stats->qual.updated & 1 ? '.' : ' ', +- stats->qual.level, +- stats->qual.updated & 2 ? '.' : ' ', +- stats->qual.noise, +- stats->qual.updated & 4 ? '.' : ' ', +- stats->discard.nwid, +- stats->discard.code, +- stats->discard.fragment, +- stats->discard.retries, +- stats->discard.misc, +- stats->miss.beacon); +- stats->qual.updated = 0; +- } +- else +- size = 0; +- +- return size; +-} +- +-/* +- * Print info for /proc/net/wireless (print all entries) +- * This is a clone of /proc/net/dev (just above) +- */ +-static int dev_get_wireless_info(char * buffer, char **start, off_t offset, +- int length) +-{ +- int len = 0; +- off_t begin = 0; +- off_t pos = 0; +- int size; +- +- struct net_device * dev; +- +- size = sprintf(buffer, +- "Inter-| sta-| Quality | Discarded packets | Missed\n" +- " face | tus | link level noise | nwid crypt frag retry misc | beacon\n" +- ); +- +- pos += size; +- len += size; +- +- read_lock(&dev_base_lock); +- for (dev = dev_base; dev != NULL; dev = dev->next) { +- size = sprintf_wireless_stats(buffer + len, dev); +- len += size; +- pos = begin + len; +- +- if (pos < offset) { +- len = 0; +- begin = pos; +- } +- if (pos > offset + length) +- break; +- } +- read_unlock(&dev_base_lock); +- +- *start = buffer + (offset - begin); /* Start of wanted data */ +- len -= (offset - begin); /* Start slop */ +- if (len > length) +- len = length; /* Ending slop */ +- if (len < 0) +- len = 0; +- +- return len; +-} +-#endif /* CONFIG_PROC_FS */ +- +-/* +- * Allow programatic access to /proc/net/wireless even if /proc +- * doesn't exist... Also more efficient... +- */ +-static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr) +-{ +- /* Get stats from the driver */ +- struct iw_statistics *stats = (dev->get_wireless_stats ? +- dev->get_wireless_stats(dev) : +- (struct iw_statistics *) NULL); +- +- if (stats != (struct iw_statistics *) NULL) { +- struct iwreq * wrq = (struct iwreq *)ifr; +- +- /* Copy statistics to the user buffer */ +- if(copy_to_user(wrq->u.data.pointer, stats, +- sizeof(struct iw_statistics))) +- return -EFAULT; +- +- /* Check if we need to clear the update flag */ +- if(wrq->u.data.flags != 0) +- stats->qual.updated = 0; +- return(0); +- } else +- return -EOPNOTSUPP; +-} +-#endif /* WIRELESS_EXT */ +- + /** + * netdev_set_master - set up master/slave pair + * @slave: slave device +@@ -2209,11 +2094,6 @@ static int dev_ifsioc(struct ifreq *ifr, + notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); + return 0; + +-#ifdef WIRELESS_EXT +- case SIOCGIWSTATS: +- return dev_iwstats(dev, ifr); +-#endif /* WIRELESS_EXT */ +- + /* + * Unknown or private ioctl + */ +@@ -2239,17 +2119,6 @@ static int dev_ifsioc(struct ifreq *ifr, + return -EOPNOTSUPP; + } + +-#ifdef WIRELESS_EXT +- if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { +- if (dev->do_ioctl) { +- if (!netif_device_present(dev)) +- return -ENODEV; +- return dev->do_ioctl(dev, ifr, cmd); +- } +- return -EOPNOTSUPP; +- } +-#endif /* WIRELESS_EXT */ +- + } + return -EINVAL; + } +@@ -2431,7 +2300,8 @@ int dev_ioctl(unsigned int cmd, void *ar + } + dev_load(ifr.ifr_name); + rtnl_lock(); +- ret = dev_ifsioc(&ifr, cmd); ++ /* Follow me in net/core/wireless.c */ ++ ret = wireless_process_ioctl(&ifr, cmd); + rtnl_unlock(); + if (!ret && IW_IS_GET(cmd) && + copy_to_user(arg, &ifr, sizeof(struct ifreq))) +@@ -2856,6 +2726,7 @@ int __init net_dev_init(void) + proc_net_create("dev", 0, dev_get_info); + create_proc_read_entry("net/softnet_stat", 0, 0, dev_proc_stats, NULL); + #ifdef WIRELESS_EXT ++ /* Available in net/core/wireless.c */ + proc_net_create("wireless", 0, dev_get_wireless_info); + #endif /* WIRELESS_EXT */ + #endif /* CONFIG_PROC_FS */ +diff -u -p -r --new-file linux/net/core-w12/wireless.c linux/net/core/wireless.c +--- linux/net/core-w12/wireless.c Wed Dec 31 16:00:00 1969 ++++ linux/net/core/wireless.c Mon Jan 21 11:13:23 2002 +@@ -0,0 +1,733 @@ ++/* ++ * This file implement the Wireless Extensions APIs. ++ * ++ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> ++ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. ++ * ++ * (As all part of the Linux kernel, this file is GPL) ++ */ ++ ++/************************** DOCUMENTATION **************************/ ++/* ++ * API definition : ++ * -------------- ++ * See <linux/wireless.h> for details of the APIs and the rest. ++ * ++ * History : ++ * ------- ++ * ++ * v1 - 5.12.01 - Jean II ++ * o Created this file. ++ * ++ * v2 - 13.12.01 - Jean II ++ * o Move /proc/net/wireless stuff from net/core/dev.c to here ++ * o Make Wireless Extension IOCTLs go through here ++ * o Added iw_handler handling ;-) ++ * o Added standard ioctl description ++ * o Initial dumb commit strategy based on orinoco.c ++ */ ++ ++/***************************** INCLUDES *****************************/ ++ ++#include <asm/uaccess.h> /* copy_to_user() */ ++#include <linux/config.h> /* Not needed ??? */ ++#include <linux/types.h> /* off_t */ ++#include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */ ++ ++#include <linux/wireless.h> /* Pretty obvious */ ++#include <net/iw_handler.h> /* New driver API */ ++ ++/**************************** CONSTANTS ****************************/ ++ ++/* This will be turned on later on... */ ++#undef WE_STRICT_WRITE /* Check write buffer size */ ++ ++/* Debuging stuff */ ++#undef WE_IOCTL_DEBUG /* Debug IOCTL API */ ++ ++/************************* GLOBAL VARIABLES *************************/ ++/* ++ * You should not use global variables, because or re-entrancy. ++ * On our case, it's only const, so it's OK... ++ */ ++static const struct iw_ioctl_description standard_ioctl[] = { ++ /* SIOCSIWCOMMIT (internal) */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWNAME */ ++ { IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWNWID */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT}, ++ /* SIOCGIWNWID */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWFREQ */ ++ { IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT}, ++ /* SIOCGIWFREQ */ ++ { IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWMODE */ ++ { IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT}, ++ /* SIOCGIWMODE */ ++ { IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWSENS */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWSENS */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWRANGE */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWRANGE */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_range), IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWPRIV */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWPRIV (handled directly by us) */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWSTATS */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWSTATS (handled directly by us) */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWSPY */ ++ { IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0}, ++ /* SIOCGIWSPY */ ++ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWAP */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, ++ /* SIOCGIWAP */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCGIWAPLIST */ ++ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWESSID */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT}, ++ /* SIOCGIWESSID */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP}, ++ /* SIOCSIWNICKN */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, ++ /* SIOCGIWNICKN */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* -- hole -- */ ++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWRATE */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWRATE */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWRTS */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWRTS */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWFRAG */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWFRAG */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWTXPOW */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWTXPOW */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWRETRY */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWRETRY */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCSIWENCODE */ ++ { IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT}, ++ /* SIOCGIWENCODE */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT}, ++ /* SIOCSIWPOWER */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWPOWER */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++}; ++ ++/* Size (in bytes) of the various private data types */ ++char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; ++ ++/************************ COMMON SUBROUTINES ************************/ ++/* ++ * Stuff that may be used in various place or doesn't fit in one ++ * of the section below. ++ */ ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Return the driver handler associated with a specific Wireless Extension. ++ * Called from various place, so make sure it remains efficient. ++ */ ++static inline iw_handler get_handler(struct net_device *dev, ++ unsigned int cmd) ++{ ++ unsigned int index; /* MUST be unsigned */ ++ ++ /* Check if we have some wireless handlers defined */ ++ if(dev->wireless_handlers == NULL) ++ return NULL; ++ ++ /* Try as a standard command */ ++ index = cmd - SIOCIWFIRST; ++ if(index < dev->wireless_handlers->num_standard) ++ return dev->wireless_handlers->standard[index]; ++ ++ /* Try as a private command */ ++ index = cmd - SIOCIWFIRSTPRIV; ++ if(index < dev->wireless_handlers->num_private) ++ return dev->wireless_handlers->private[index]; ++ ++ /* Not found */ ++ return NULL; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Get statistics out of the driver ++ */ ++static inline struct iw_statistics *get_wireless_stats(struct net_device *dev) ++{ ++ return (dev->get_wireless_stats ? ++ dev->get_wireless_stats(dev) : ++ (struct iw_statistics *) NULL); ++ /* In the future, get_wireless_stats may move from 'struct net_device' ++ * to 'struct iw_handler_def', to de-bloat struct net_device. ++ * Definitely worse a thought... */ ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Call the commit handler in the driver ++ * (if exist and if conditions are right) ++ * ++ * Note : our current commit strategy is currently pretty dumb, ++ * but we will be able to improve on that... ++ * The goal is to try to agreagate as many changes as possible ++ * before doing the commit. Drivers that will define a commit handler ++ * are usually those that need a reset after changing parameters, so ++ * we want to minimise the number of reset. ++ * A cool idea is to use a timer : at each "set" command, we re-set the ++ * timer, when the timer eventually fires, we call the driver. ++ * Hopefully, more on that later. ++ * ++ * Also, I'm waiting to see how many people will complain about the ++ * netif_running(dev) test. I'm open on that one... ++ * Hopefully, the driver will remember to do a commit in "open()" ;-) ++ */ ++static inline int call_commit_handler(struct net_device * dev) ++{ ++ if((netif_running(dev)) && ++ (dev->wireless_handlers->standard[0] != NULL)) { ++ /* Call the commit handler on the driver */ ++ return dev->wireless_handlers->standard[0](dev, NULL, ++ NULL, NULL); ++ } else ++ return 0; /* Command completed successfully */ ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Number of private arguments ++ */ ++static inline int get_priv_size(__u16 args) ++{ ++ int num = args & IW_PRIV_SIZE_MASK; ++ int type = (args & IW_PRIV_TYPE_MASK) >> 12; ++ ++ return num * priv_type_size[type]; ++} ++ ++ ++/******************** /proc/net/wireless SUPPORT ********************/ ++/* ++ * The /proc/net/wireless file is a human readable user-space interface ++ * exporting various wireless specific statistics from the wireless devices. ++ * This is the most popular part of the Wireless Extensions ;-) ++ * ++ * This interface is a pure clone of /proc/net/dev (in net/core/dev.c). ++ * The content of the file is basically the content of "struct iw_statistics". ++ */ ++ ++#ifdef CONFIG_PROC_FS ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Print one entry (line) of /proc/net/wireless ++ */ ++static inline int sprintf_wireless_stats(char *buffer, struct net_device *dev) ++{ ++ /* Get stats from the driver */ ++ struct iw_statistics *stats; ++ int size; ++ ++ stats = get_wireless_stats(dev); ++ if (stats != (struct iw_statistics *) NULL) { ++ size = sprintf(buffer, ++ "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d %6d %6d %6d\n", ++ dev->name, ++ stats->status, ++ stats->qual.qual, ++ stats->qual.updated & 1 ? '.' : ' ', ++ stats->qual.level, ++ stats->qual.updated & 2 ? '.' : ' ', ++ stats->qual.noise, ++ stats->qual.updated & 4 ? '.' : ' ', ++ stats->discard.nwid, ++ stats->discard.code, ++ stats->discard.fragment, ++ stats->discard.retries, ++ stats->discard.misc, ++ stats->miss.beacon); ++ stats->qual.updated = 0; ++ } ++ else ++ size = 0; ++ ++ return size; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Print info for /proc/net/wireless (print all entries) ++ */ ++int dev_get_wireless_info(char * buffer, char **start, off_t offset, ++ int length) ++{ ++ int len = 0; ++ off_t begin = 0; ++ off_t pos = 0; ++ int size; ++ ++ struct net_device * dev; ++ ++ size = sprintf(buffer, ++ "Inter-| sta-| Quality | Discarded packets | Missed\n" ++ " face | tus | link level noise | nwid crypt frag retry misc | beacon\n" ++ ); ++ ++ pos += size; ++ len += size; ++ ++ read_lock(&dev_base_lock); ++ for (dev = dev_base; dev != NULL; dev = dev->next) { ++ size = sprintf_wireless_stats(buffer + len, dev); ++ len += size; ++ pos = begin + len; ++ ++ if (pos < offset) { ++ len = 0; ++ begin = pos; ++ } ++ if (pos > offset + length) ++ break; ++ } ++ read_unlock(&dev_base_lock); ++ ++ *start = buffer + (offset - begin); /* Start of wanted data */ ++ len -= (offset - begin); /* Start slop */ ++ if (len > length) ++ len = length; /* Ending slop */ ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++#endif /* CONFIG_PROC_FS */ ++ ++/************************** IOCTL SUPPORT **************************/ ++/* ++ * The original user space API to configure all those Wireless Extensions ++ * is through IOCTLs. ++ * In there, we check if we need to call the new driver API (iw_handler) ++ * or just call the driver ioctl handler. ++ */ ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Allow programatic access to /proc/net/wireless even if /proc ++ * doesn't exist... Also more efficient... ++ */ ++static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr) ++{ ++ /* Get stats from the driver */ ++ struct iw_statistics *stats; ++ ++ stats = get_wireless_stats(dev); ++ if (stats != (struct iw_statistics *) NULL) { ++ struct iwreq * wrq = (struct iwreq *)ifr; ++ ++ /* Copy statistics to the user buffer */ ++ if(copy_to_user(wrq->u.data.pointer, stats, ++ sizeof(struct iw_statistics))) ++ return -EFAULT; ++ ++ /* Check if we need to clear the update flag */ ++ if(wrq->u.data.flags != 0) ++ stats->qual.updated = 0; ++ return 0; ++ } else ++ return -EOPNOTSUPP; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Export the driver private handler definition ++ * They will be picked up by tools like iwpriv... ++ */ ++static inline int ioctl_export_private(struct net_device * dev, ++ struct ifreq * ifr) ++{ ++ struct iwreq * iwr = (struct iwreq *) ifr; ++ ++ /* Check if the driver has something to export */ ++ if((dev->wireless_handlers->num_private_args == 0) || ++ (dev->wireless_handlers->private_args == NULL)) ++ return -EOPNOTSUPP; ++ ++ /* Check NULL pointer */ ++ if(iwr->u.data.pointer == NULL) ++ return -EFAULT; ++#ifdef WE_STRICT_WRITE ++ /* Check if there is enough buffer up there */ ++ if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1)) ++ return -E2BIG; ++#endif /* WE_STRICT_WRITE */ ++ ++ /* Set the number of available ioctls. */ ++ iwr->u.data.length = dev->wireless_handlers->num_private_args; ++ ++ /* Copy structure to the user buffer. */ ++ if (copy_to_user(iwr->u.data.pointer, ++ dev->wireless_handlers->private_args, ++ sizeof(struct iw_priv_args) * iwr->u.data.length)) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Wrapper to call a standard Wireless Extension handler. ++ * We do various checks and also take care of moving data between ++ * user space and kernel space. ++ */ ++static inline int ioctl_standard_call(struct net_device * dev, ++ struct ifreq * ifr, ++ unsigned int cmd, ++ iw_handler handler) ++{ ++ struct iwreq * iwr = (struct iwreq *) ifr; ++ const struct iw_ioctl_description * descr; ++ struct iw_request_info info; ++ int ret = -EINVAL; ++ ++ /* Get the description of the IOCTL */ ++ descr = &(standard_ioctl[cmd - SIOCIWFIRST]); ++ ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n", ++ ifr->ifr_name, cmd); ++ printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); ++#endif /* WE_IOCTL_DEBUG */ ++ ++ /* Prepare the call */ ++ info.cmd = cmd; ++ info.flags = 0; ++ ++ /* Check if we have a pointer to user space data or not */ ++ if(descr->header_type != IW_HEADER_TYPE_POINT) { ++ /* No extra arguments. Trivial to handle */ ++ ret = handler(dev, &info, &(iwr->u), NULL); ++ } else { ++ char * extra; ++ int err; ++ ++ /* Check what user space is giving us */ ++ if(IW_IS_SET(cmd)) { ++ /* Check NULL pointer */ ++ if((iwr->u.data.pointer == NULL) && ++ (iwr->u.data.length != 0)) ++ return -EFAULT; ++ /* Check if number of token fits within bounds */ ++ if(iwr->u.data.length > descr->max_tokens) ++ return -E2BIG; ++ if(iwr->u.data.length < descr->min_tokens) ++ return -EINVAL; ++ } else { ++ /* Check NULL pointer */ ++ if(iwr->u.data.pointer == NULL) ++ return -EFAULT; ++#ifdef WE_STRICT_WRITE ++ /* Check if there is enough buffer up there */ ++ if(iwr->u.data.length < descr->max_tokens) ++ return -E2BIG; ++#endif /* WE_STRICT_WRITE */ ++ } ++ ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Malloc %d bytes\n", ++ descr->max_tokens * descr->token_size); ++#endif /* WE_IOCTL_DEBUG */ ++ ++ /* Always allocate for max space. Easier, and won't last ++ * long... */ ++ extra = kmalloc(descr->max_tokens * descr->token_size, ++ GFP_KERNEL); ++ if (extra == NULL) { ++ return -ENOMEM; ++ } ++ ++ /* If it is a SET, get all the extra data in here */ ++ if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { ++ err = copy_from_user(extra, iwr->u.data.pointer, ++ iwr->u.data.length * ++ descr->token_size); ++ if (err) { ++ kfree(extra); ++ return -EFAULT; ++ } ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Got %d bytes\n", ++ iwr->u.data.length * descr->token_size); ++#endif /* WE_IOCTL_DEBUG */ ++ } ++ ++ /* Call the handler */ ++ ret = handler(dev, &info, &(iwr->u), extra); ++ ++ /* If we have something to return to the user */ ++ if (!ret && IW_IS_GET(cmd)) { ++ err = copy_to_user(iwr->u.data.pointer, extra, ++ iwr->u.data.length * ++ descr->token_size); ++ if (err) ++ ret = -EFAULT; ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Wrote %d bytes\n", ++ iwr->u.data.length * descr->token_size); ++#endif /* WE_IOCTL_DEBUG */ ++ } ++ ++ /* Cleanup - I told you it wasn't that long ;-) */ ++ kfree(extra); ++ } ++ ++ /* Call commit handler if needed and defined */ ++ if(ret == -EIWCOMMIT) ++ ret = call_commit_handler(dev); ++ ++ /* Here, we will generate the appropriate event if needed */ ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Wrapper to call a private Wireless Extension handler. ++ * We do various checks and also take care of moving data between ++ * user space and kernel space. ++ * It's not as nice and slimline as the standard wrapper. The cause ++ * is struct iw_priv_args, which was not really designed for the ++ * job we are going here. ++ * ++ * IMPORTANT : This function prevent to set and get data on the same ++ * IOCTL and enforce the SET/GET convention. Not doing it would be ++ * far too hairy... ++ * If you need to set and get data at the same time, please don't use ++ * a iw_handler but process it in your ioctl handler (i.e. use the ++ * old driver API). ++ */ ++static inline int ioctl_private_call(struct net_device * dev, ++ struct ifreq * ifr, ++ unsigned int cmd, ++ iw_handler handler) ++{ ++ struct iwreq * iwr = (struct iwreq *) ifr; ++ struct iw_priv_args * descr = NULL; ++ struct iw_request_info info; ++ int extra_size = 0; ++ int i; ++ int ret = -EINVAL; ++ ++ /* Get the description of the IOCTL */ ++ for(i = 0; i < dev->wireless_handlers->num_private_args; i++) ++ if(cmd == dev->wireless_handlers->private_args[i].cmd) { ++ descr = &(dev->wireless_handlers->private_args[i]); ++ break; ++ } ++ ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n", ++ ifr->ifr_name, cmd); ++ if(descr) { ++ printk(KERN_DEBUG "Name %s, set %X, get %X\n", ++ descr->name, descr->set_args, descr->get_args); ++ } ++#endif /* WE_IOCTL_DEBUG */ ++ ++ /* Compute the size of the set/get arguments */ ++ if(descr != NULL) { ++ if(IW_IS_SET(cmd)) { ++ /* Size of set arguments */ ++ extra_size = get_priv_size(descr->set_args); ++ ++ /* Does it fits in iwr ? */ ++ if((descr->set_args & IW_PRIV_SIZE_FIXED) && ++ (extra_size < IFNAMSIZ)) ++ extra_size = 0; ++ } else { ++ /* Size of set arguments */ ++ extra_size = get_priv_size(descr->get_args); ++ ++ /* Does it fits in iwr ? */ ++ if((descr->get_args & IW_PRIV_SIZE_FIXED) && ++ (extra_size < IFNAMSIZ)) ++ extra_size = 0; ++ } ++ } ++ ++ /* Prepare the call */ ++ info.cmd = cmd; ++ info.flags = 0; ++ ++ /* Check if we have a pointer to user space data or not. */ ++ if(extra_size == 0) { ++ /* No extra arguments. Trivial to handle */ ++ ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u)); ++ } else { ++ char * extra; ++ int err; ++ ++ /* Check what user space is giving us */ ++ if(IW_IS_SET(cmd)) { ++ /* Check NULL pointer */ ++ if((iwr->u.data.pointer == NULL) && ++ (iwr->u.data.length != 0)) ++ return -EFAULT; ++ ++ /* Does it fits within bounds ? */ ++ if(iwr->u.data.length > (descr->set_args & ++ IW_PRIV_SIZE_MASK)) ++ return -E2BIG; ++ } else { ++ /* Check NULL pointer */ ++ if(iwr->u.data.pointer == NULL) ++ return -EFAULT; ++ } ++ ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Malloc %d bytes\n", extra_size); ++#endif /* WE_IOCTL_DEBUG */ ++ ++ /* Always allocate for max space. Easier, and won't last ++ * long... */ ++ extra = kmalloc(extra_size, GFP_KERNEL); ++ if (extra == NULL) { ++ return -ENOMEM; ++ } ++ ++ /* If it is a SET, get all the extra data in here */ ++ if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { ++ err = copy_from_user(extra, iwr->u.data.pointer, ++ extra_size); ++ if (err) { ++ kfree(extra); ++ return -EFAULT; ++ } ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length); ++#endif /* WE_IOCTL_DEBUG */ ++ } ++ ++ /* Call the handler */ ++ ret = handler(dev, &info, &(iwr->u), extra); ++ ++ /* If we have something to return to the user */ ++ if (!ret && IW_IS_GET(cmd)) { ++ err = copy_to_user(iwr->u.data.pointer, extra, ++ extra_size); ++ if (err) ++ ret = -EFAULT; ++#ifdef WE_IOCTL_DEBUG ++ printk(KERN_DEBUG "Wrote %d elem\n", ++ iwr->u.data.length); ++#endif /* WE_IOCTL_DEBUG */ ++ } ++ ++ /* Cleanup - I told you it wasn't that long ;-) */ ++ kfree(extra); ++ } ++ ++ ++ /* Call commit handler if needed and defined */ ++ if(ret == -EIWCOMMIT) ++ ret = call_commit_handler(dev); ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Main IOCTl dispatcher. Called from the main networking code ++ * (dev_ioctl() in net/core/dev.c). ++ * Check the type of IOCTL and call the appropriate wrapper... ++ */ ++int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd) ++{ ++ struct net_device *dev; ++ iw_handler handler; ++ ++ /* Permissions are already checked in dev_ioctl() before calling us. ++ * The copy_to/from_user() of ifr is also dealt with in there */ ++ ++ /* Make sure the device exist */ ++ if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) ++ return -ENODEV; ++ ++ /* A bunch of special cases, then the generic case... ++ * Note that 'cmd' is already filtered in dev_ioctl() with ++ * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ ++ switch(cmd) ++ { ++ case SIOCGIWSTATS: ++ /* Get Wireless Stats */ ++ return dev_iwstats(dev, ifr); ++ ++ case SIOCGIWPRIV: ++ /* Check if we have some wireless handlers defined */ ++ if(dev->wireless_handlers != NULL) { ++ /* We export to user space the definition of ++ * the private handler ourselves */ ++ return ioctl_export_private(dev, ifr); ++ } ++ // ## Fall-through for old API ## ++ default: ++ /* Generic IOCTL */ ++ /* Basic check */ ++ if (!netif_device_present(dev)) ++ return -ENODEV; ++ /* New driver API : try to find the handler */ ++ handler = get_handler(dev, cmd); ++ if(handler != NULL) { ++ /* Standard and private are not the same */ ++ if(cmd < SIOCIWFIRSTPRIV) ++ return ioctl_standard_call(dev, ++ ifr, ++ cmd, ++ handler); ++ else ++ return ioctl_private_call(dev, ++ ifr, ++ cmd, ++ handler); ++ } ++ /* Old driver API : call driver ioctl handler */ ++ if (dev->do_ioctl) { ++ return dev->do_ioctl(dev, ifr, cmd); ++ } ++ return -EOPNOTSUPP; ++ } ++ /* Not reached */ ++ return -EINVAL; ++} diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w14-5.diff b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w14-5.diff index e69de29bb2..539b160068 100644 --- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w14-5.diff +++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w14-5.diff @@ -0,0 +1,838 @@ +diff -u -p -r --new-file linux/include/linux-w13/rtnetlink.h linux/include/linux/rtnetlink.h +--- linux/include/linux-w13/rtnetlink.h Thu Jun 6 14:44:08 2002 ++++ linux/include/linux/rtnetlink.h Thu Jun 6 15:47:44 2002 +@@ -440,12 +440,14 @@ enum + #define IFLA_COST IFLA_COST + IFLA_PRIORITY, + #define IFLA_PRIORITY IFLA_PRIORITY +- IFLA_MASTER ++ IFLA_MASTER, + #define IFLA_MASTER IFLA_MASTER ++ IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */ ++#define IFLA_WIRELESS IFLA_WIRELESS + }; + + +-#define IFLA_MAX IFLA_MASTER ++#define IFLA_MAX IFLA_WIRELESS + + #define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) + #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) +diff -u -p -r --new-file linux/include/linux-w13/wireless.h linux/include/linux/wireless.h +--- linux/include/linux-w13/wireless.h Thu Jun 6 15:00:28 2002 ++++ linux/include/linux/wireless.h Thu Jun 6 15:47:44 2002 +@@ -1,10 +1,10 @@ + /* + * This file define a set of standard wireless extensions + * +- * Version : 13 6.12.01 ++ * Version : 14 25.1.02 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> +- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. ++ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. + */ + + #ifndef _LINUX_WIRELESS_H +@@ -40,7 +40,7 @@ + * # include/linux/netdevice.h (one place) + * # include/linux/proc_fs.h (one place) + * +- * New driver API (2001 -> onward) : ++ * New driver API (2002 -> onward) : + * ------------------------------- + * This file is only concerned with the user space API and common definitions. + * The new driver API is defined and documented in : +@@ -49,6 +49,11 @@ + * Note as well that /proc/net/wireless implementation has now moved in : + * # include/linux/wireless.c + * ++ * Wireless Events (2002 -> onward) : ++ * -------------------------------- ++ * Events are defined at the end of this file, and implemented in : ++ * # include/linux/wireless.c ++ * + * Other comments : + * -------------- + * Do not add here things that are redundant with other mechanisms +@@ -75,7 +80,7 @@ + * (there is some stuff that will be added in the future...) + * I just plan to increment with each new version. + */ +-#define WIRELESS_EXT 13 ++#define WIRELESS_EXT 14 + + /* + * Changes : +@@ -141,6 +146,13 @@ + * - Document creation of new driver API. + * - Extract union iwreq_data from struct iwreq (for new driver API). + * - Rename SIOCSIWNAME as SIOCSIWCOMMIT ++ * ++ * V13 to V14 ++ * ---------- ++ * - Wireless Events support : define struct iw_event ++ * - Define additional specific event numbers ++ * - Add "addr" and "param" fields in union iwreq_data ++ * - AP scanning stuff (SIOCSIWSCAN and friends) + */ + + /**************************** CONSTANTS ****************************/ +@@ -175,6 +187,8 @@ + #define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ + #define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ + #define SIOCGIWAPLIST 0x8B17 /* get list of access point in range */ ++#define SIOCSIWSCAN 0x8B18 /* trigger scanning */ ++#define SIOCGIWSCAN 0x8B19 /* get scanning results */ + + /* 802.11 specific support */ + #define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */ +@@ -238,6 +252,15 @@ + #define IW_IS_SET(cmd) (!((cmd) & 0x1)) + #define IW_IS_GET(cmd) ((cmd) & 0x1) + ++/* ----------------------- WIRELESS EVENTS ----------------------- */ ++/* Those are *NOT* ioctls, do not issue request on them !!! */ ++/* Most events use the same identifier as ioctl requests */ ++ ++#define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ ++#define IWEVQUAL 0x8C01 /* Quality part of statistics */ ++ ++#define IWEVFIRST 0x8C00 ++ + /* ------------------------- PRIVATE INFO ------------------------- */ + /* + * The following is used with SIOCGIWPRIV. It allow a driver to define +@@ -340,6 +363,19 @@ + #define IW_RETRY_MAX 0x0002 /* Value is a maximum */ + #define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ + ++/* Scanning request flags */ ++#define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */ ++#define IW_SCAN_ALL_ESSID 0x0001 /* Scan all ESSIDs */ ++#define IW_SCAN_THIS_ESSID 0x0002 /* Scan only this ESSID */ ++#define IW_SCAN_ALL_FREQ 0x0004 /* Scan all Frequencies */ ++#define IW_SCAN_THIS_FREQ 0x0008 /* Scan only this Frequency */ ++#define IW_SCAN_ALL_MODE 0x0010 /* Scan all Modes */ ++#define IW_SCAN_THIS_MODE 0x0020 /* Scan only this Mode */ ++#define IW_SCAN_ALL_RATE 0x0040 /* Scan all Bit-Rates */ ++#define IW_SCAN_THIS_RATE 0x0080 /* Scan only this Bit-Rate */ ++/* Maximum size of returned data */ ++#define IW_SCAN_MAX_DATA 4096 /* In bytes */ ++ + /****************************** TYPES ******************************/ + + /* --------------------------- SUBTYPES --------------------------- */ +@@ -466,9 +502,12 @@ union iwreq_data + + struct iw_point encoding; /* Encoding stuff : tokens */ + struct iw_param power; /* PM duration/timeout */ ++ struct iw_quality qual; /* Quality part of statistics */ + + struct sockaddr ap_addr; /* Access point address */ ++ struct sockaddr addr; /* Destination address (hw) */ + ++ struct iw_param param; /* Other small parameters */ + struct iw_point data; /* Other large parameters */ + }; + +@@ -595,5 +634,36 @@ struct iw_priv_args + __u16 get_args; /* Type and number of args */ + char name[IFNAMSIZ]; /* Name of the extension */ + }; ++ ++/* ----------------------- WIRELESS EVENTS ----------------------- */ ++/* ++ * Wireless events are carried through the rtnetlink socket to user ++ * space. They are encapsulated in the IFLA_WIRELESS field of ++ * a RTM_NEWLINK message. ++ */ ++ ++/* ++ * A Wireless Event. Contains basically the same data as the ioctl... ++ */ ++struct iw_event ++{ ++ __u16 len; /* Real lenght of this stuff */ ++ __u16 cmd; /* Wireless IOCTL */ ++ union iwreq_data u; /* IOCTL fixed payload */ ++}; ++ ++/* Size of the Event prefix (including padding and alignement junk) */ ++#define IW_EV_LCP_LEN (sizeof(struct iw_event) - sizeof(union iwreq_data)) ++/* Size of the various events */ ++#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ) ++#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32)) ++#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq)) ++#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point)) ++#define IW_EV_PARAM_LEN (IW_EV_LCP_LEN + sizeof(struct iw_param)) ++#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr)) ++#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality)) ++ ++/* Note : in the case of iw_point, the extra data will come at the ++ * end of the event */ + + #endif /* _LINUX_WIRELESS_H */ +diff -u -p -r --new-file linux/include/net-w13/iw_handler.h linux/include/net/iw_handler.h +--- linux/include/net-w13/iw_handler.h Thu Jun 6 15:06:16 2002 ++++ linux/include/net/iw_handler.h Thu Jun 6 15:48:06 2002 +@@ -1,10 +1,10 @@ + /* + * This file define the new driver API for Wireless Extensions + * +- * Version : 2 6.12.01 ++ * Version : 3 17.1.02 + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> +- * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved. ++ * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved. + */ + + #ifndef _IW_HANDLER_H +@@ -33,7 +33,7 @@ + * o The user space interface is tied to ioctl because of the use + * copy_to/from_user. + * +- * New driver API (2001 -> onward) : ++ * New driver API (2002 -> onward) : + * ------------------------------- + * The new driver API is just a bunch of standard functions (handlers), + * each handling a specific Wireless Extension. The driver just export +@@ -206,7 +206,18 @@ + * will be needed... + * I just plan to increment with each new version. + */ +-#define IW_HANDLER_VERSION 2 ++#define IW_HANDLER_VERSION 3 ++ ++/* ++ * Changes : ++ * ++ * V2 to V3 ++ * -------- ++ * - Move event definition in <linux/wireless.h> ++ * - Add Wireless Event support : ++ * o wireless_send_event() prototype ++ * o iwe_stream_add_event/point() inline functions ++ */ + + /**************************** CONSTANTS ****************************/ + +@@ -225,6 +236,7 @@ + #define IW_HEADER_TYPE_POINT 6 /* struct iw_point */ + #define IW_HEADER_TYPE_PARAM 7 /* struct iw_param */ + #define IW_HEADER_TYPE_ADDR 8 /* struct sockaddr */ ++#define IW_HEADER_TYPE_QUAL 9 /* struct iw_quality */ + + /* Handling flags */ + /* Most are not implemented. I just use them as a reminder of some +@@ -233,7 +245,8 @@ + /* Wrapper level flags */ + #define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */ + #define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */ +-#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET request is ROOT only */ ++#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */ ++ /* SET : Omit payload from generated iwevent */ + /* Driver level flags */ + #define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */ + +@@ -303,25 +316,6 @@ struct iw_handler_def + * 'struct net_device' to here, to minimise bloat. */ + }; + +-/* ----------------------- WIRELESS EVENTS ----------------------- */ +-/* +- * Currently we don't support events, so let's just plan for the +- * future... +- */ +- +-/* +- * A Wireless Event. +- */ +-// How do we define short header ? We don't want a flag on length. +-// Probably a flag on event ? Highest bit to zero... +-struct iw_event +-{ +- __u16 length; /* Lenght of this stuff */ +- __u16 event; /* Wireless IOCTL */ +- union iwreq_data header; /* IOCTL fixed payload */ +- char extra[0]; /* Optional IOCTL data */ +-}; +- + /* ---------------------- IOCTL DESCRIPTION ---------------------- */ + /* + * One of the main goal of the new interface is to deal entirely with +@@ -369,6 +363,88 @@ extern int dev_get_wireless_info(char * + extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd); + + /* Second : functions that may be called by driver modules */ +-/* None yet */ + +-#endif /* _LINUX_WIRELESS_H */ ++/* Send a single event to user space */ ++extern void wireless_send_event(struct net_device * dev, ++ unsigned int cmd, ++ union iwreq_data * wrqu, ++ char * extra); ++ ++/* We may need a function to send a stream of events to user space. ++ * More on that later... */ ++ ++/************************* INLINE FUNTIONS *************************/ ++/* ++ * Function that are so simple that it's more efficient inlining them ++ */ ++ ++/*------------------------------------------------------------------*/ ++/* ++ * Wrapper to add an Wireless Event to a stream of events. ++ */ ++static inline char * ++iwe_stream_add_event(char * stream, /* Stream of events */ ++ char * ends, /* End of stream */ ++ struct iw_event *iwe, /* Payload */ ++ int event_len) /* Real size of payload */ ++{ ++ /* Check if it's possible */ ++ if((stream + event_len) < ends) { ++ iwe->len = event_len; ++ memcpy(stream, (char *) iwe, event_len); ++ stream += event_len; ++ } ++ return stream; ++} ++ ++/*------------------------------------------------------------------*/ ++/* ++ * Wrapper to add an short Wireless Event containing a pointer to a ++ * stream of events. ++ */ ++static inline char * ++iwe_stream_add_point(char * stream, /* Stream of events */ ++ char * ends, /* End of stream */ ++ struct iw_event *iwe, /* Payload */ ++ char * extra) ++{ ++ int event_len = IW_EV_POINT_LEN + iwe->u.data.length; ++ /* Check if it's possible */ ++ if((stream + event_len) < ends) { ++ iwe->len = event_len; ++ memcpy(stream, (char *) iwe, IW_EV_POINT_LEN); ++ memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length); ++ stream += event_len; ++ } ++ return stream; ++} ++ ++/*------------------------------------------------------------------*/ ++/* ++ * Wrapper to add a value to a Wireless Event in a stream of events. ++ * Be careful, this one is tricky to use properly : ++ * At the first run, you need to have (value = event + IW_EV_LCP_LEN). ++ */ ++static inline char * ++iwe_stream_add_value(char * event, /* Event in the stream */ ++ char * value, /* Value in event */ ++ char * ends, /* End of stream */ ++ struct iw_event *iwe, /* Payload */ ++ int event_len) /* Real size of payload */ ++{ ++ /* Don't duplicate LCP */ ++ event_len -= IW_EV_LCP_LEN; ++ ++ /* Check if it's possible */ ++ if((value + event_len) < ends) { ++ /* Add new value */ ++ memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len); ++ value += event_len; ++ /* Patch LCP */ ++ iwe->len = value - event; ++ memcpy(event, (char *) iwe, IW_EV_LCP_LEN); ++ } ++ return value; ++} ++ ++#endif /* _IW_HANDLER_H */ +diff -u -p -r --new-file linux/net/netsyms-w13.c linux/net/netsyms.c +--- linux/net/netsyms-w13.c Thu Jun 6 15:46:34 2002 ++++ linux/net/netsyms.c Thu Jun 6 15:47:44 2002 +@@ -588,4 +588,10 @@ EXPORT_SYMBOL(register_gifconf); + EXPORT_SYMBOL(net_call_rx_atomic); + EXPORT_SYMBOL(softnet_data); + ++#if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO) ++/* Don't include the whole header mess for a single function */ ++extern void wireless_send_event(struct net_device *dev, unsigned int cmd, union iwreq_data *wrqu, char *extra); ++EXPORT_SYMBOL(wireless_send_event); ++#endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ ++ + #endif /* CONFIG_NET */ +diff -u -p -r --new-file linux/net/core/wireless-w13.c linux/net/core/wireless.c +--- linux/net/core/wireless-w13.c Thu Jun 6 15:46:45 2002 ++++ linux/net/core/wireless.c Thu Jun 6 15:48:06 2002 +@@ -2,7 +2,7 @@ + * This file implement the Wireless Extensions APIs. + * + * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> +- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved. ++ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. + * + * (As all part of the Linux kernel, this file is GPL) + */ +@@ -25,6 +25,16 @@ + * o Added iw_handler handling ;-) + * o Added standard ioctl description + * o Initial dumb commit strategy based on orinoco.c ++ * ++ * v3 - 19.12.01 - Jean II ++ * o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call ++ * o Add event dispatcher function ++ * o Add event description ++ * o Propagate events as rtnetlink IFLA_WIRELESS option ++ * o Generate event on selected SET requests ++ * ++ * v4 - 18.04.01 - Jean II ++ * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1 + */ + + /***************************** INCLUDES *****************************/ +@@ -33,6 +43,7 @@ + #include <linux/config.h> /* Not needed ??? */ + #include <linux/types.h> /* off_t */ + #include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */ ++#include <linux/rtnetlink.h> /* rtnetlink stuff */ + + #include <linux/wireless.h> /* Pretty obvious */ + #include <net/iw_handler.h> /* New driver API */ +@@ -44,14 +55,23 @@ + + /* Debuging stuff */ + #undef WE_IOCTL_DEBUG /* Debug IOCTL API */ ++#undef WE_EVENT_DEBUG /* Debug Event dispatcher */ ++ ++/* Options */ ++#define WE_EVENT_NETLINK /* Propagate events using rtnetlink */ ++#define WE_SET_EVENT /* Generate an event on some set commands */ + + /************************* GLOBAL VARIABLES *************************/ + /* + * You should not use global variables, because or re-entrancy. + * On our case, it's only const, so it's OK... + */ ++/* ++ * Meta-data about all the standard Wireless Extension request we ++ * know about. ++ */ + static const struct iw_ioctl_description standard_ioctl[] = { +- /* SIOCSIWCOMMIT (internal) */ ++ /* SIOCSIWCOMMIT */ + { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, + /* SIOCGIWNAME */ + { IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP}, +@@ -99,18 +119,18 @@ static const struct iw_ioctl_description + { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, + /* SIOCGIWAPLIST */ + { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0}, +- /* -- hole -- */ +- { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, +- /* -- hole -- */ +- { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, ++ /* SIOCSIWSCAN */ ++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, ++ /* SIOCGIWSCAN */ ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, 0}, + /* SIOCSIWESSID */ +- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_EVENT}, + /* SIOCGIWESSID */ +- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_DUMP}, + /* SIOCSIWNICKN */ +- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0}, + /* SIOCGIWNICKN */ +- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0}, + /* -- hole -- */ + { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0}, + /* -- hole -- */ +@@ -136,7 +156,7 @@ static const struct iw_ioctl_description + /* SIOCGIWRETRY */ + { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, + /* SIOCSIWENCODE */ +- { IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT}, ++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT}, + /* SIOCGIWENCODE */ + { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT}, + /* SIOCSIWPOWER */ +@@ -144,9 +164,38 @@ static const struct iw_ioctl_description + /* SIOCGIWPOWER */ + { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0}, + }; ++static const int standard_ioctl_num = (sizeof(standard_ioctl) / ++ sizeof(struct iw_ioctl_description)); ++ ++/* ++ * Meta-data about all the additional standard Wireless Extension events ++ * we know about. ++ */ ++static const struct iw_ioctl_description standard_event[] = { ++ /* IWEVTXDROP */ ++ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0}, ++ /* IWEVQUAL */ ++ { IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0}, ++}; ++static const int standard_event_num = (sizeof(standard_event) / ++ sizeof(struct iw_ioctl_description)); + + /* Size (in bytes) of the various private data types */ +-char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; ++static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 }; ++ ++/* Size (in bytes) of various events */ ++static const int event_type_size[] = { ++ IW_EV_LCP_LEN, ++ 0, ++ IW_EV_CHAR_LEN, ++ 0, ++ IW_EV_UINT_LEN, ++ IW_EV_FREQ_LEN, ++ IW_EV_POINT_LEN, /* Without variable payload */ ++ IW_EV_PARAM_LEN, ++ IW_EV_ADDR_LEN, ++ IW_EV_QUAL_LEN, ++}; + + /************************ COMMON SUBROUTINES ************************/ + /* +@@ -162,7 +211,8 @@ char priv_type_size[] = { 0, 1, 1, 0, 4, + static inline iw_handler get_handler(struct net_device *dev, + unsigned int cmd) + { +- unsigned int index; /* MUST be unsigned */ ++ /* Don't "optimise" the following variable, it will crash */ ++ unsigned int index; /* *MUST* be unsigned */ + + /* Check if we have some wireless handlers defined */ + if(dev->wireless_handlers == NULL) +@@ -269,9 +319,9 @@ static inline int sprintf_wireless_stats + stats->status, + stats->qual.qual, + stats->qual.updated & 1 ? '.' : ' ', +- stats->qual.level, ++ ((__u8) stats->qual.level), + stats->qual.updated & 2 ? '.' : ' ', +- stats->qual.noise, ++ ((__u8) stats->qual.noise), + stats->qual.updated & 4 ? '.' : ' ', + stats->discard.nwid, + stats->discard.code, +@@ -423,12 +473,14 @@ static inline int ioctl_standard_call(st + int ret = -EINVAL; + + /* Get the description of the IOCTL */ ++ if((cmd - SIOCIWFIRST) >= standard_ioctl_num) ++ return -EOPNOTSUPP; + descr = &(standard_ioctl[cmd - SIOCIWFIRST]); + + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n", ++ printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n", + ifr->ifr_name, cmd); +- printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); ++ printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); + #endif /* WE_IOCTL_DEBUG */ + + /* Prepare the call */ +@@ -437,8 +489,16 @@ static inline int ioctl_standard_call(st + + /* Check if we have a pointer to user space data or not */ + if(descr->header_type != IW_HEADER_TYPE_POINT) { ++ + /* No extra arguments. Trivial to handle */ + ret = handler(dev, &info, &(iwr->u), NULL); ++ ++#ifdef WE_SET_EVENT ++ /* Generate an event to notify listeners of the change */ ++ if((descr->flags & IW_DESCR_FLAG_EVENT) && ++ ((ret == 0) || (ret == -EIWCOMMIT))) ++ wireless_send_event(dev, cmd, &(iwr->u), NULL); ++#endif /* WE_SET_EVENT */ + } else { + char * extra; + int err; +@@ -466,8 +526,8 @@ static inline int ioctl_standard_call(st + } + + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Malloc %d bytes\n", +- descr->max_tokens * descr->token_size); ++ printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", ++ dev->name, descr->max_tokens * descr->token_size); + #endif /* WE_IOCTL_DEBUG */ + + /* Always allocate for max space. Easier, and won't last +@@ -488,7 +548,8 @@ static inline int ioctl_standard_call(st + return -EFAULT; + } + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Got %d bytes\n", ++ printk(KERN_DEBUG "%s (WE) : Got %d bytes\n", ++ dev->name, + iwr->u.data.length * descr->token_size); + #endif /* WE_IOCTL_DEBUG */ + } +@@ -504,11 +565,26 @@ static inline int ioctl_standard_call(st + if (err) + ret = -EFAULT; + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Wrote %d bytes\n", ++ printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n", ++ dev->name, + iwr->u.data.length * descr->token_size); + #endif /* WE_IOCTL_DEBUG */ + } + ++#ifdef WE_SET_EVENT ++ /* Generate an event to notify listeners of the change */ ++ if((descr->flags & IW_DESCR_FLAG_EVENT) && ++ ((ret == 0) || (ret == -EIWCOMMIT))) { ++ if(descr->flags & IW_DESCR_FLAG_RESTRICT) ++ /* If the event is restricted, don't ++ * export the payload */ ++ wireless_send_event(dev, cmd, &(iwr->u), NULL); ++ else ++ wireless_send_event(dev, cmd, &(iwr->u), ++ extra); ++ } ++#endif /* WE_SET_EVENT */ ++ + /* Cleanup - I told you it wasn't that long ;-) */ + kfree(extra); + } +@@ -558,11 +634,12 @@ static inline int ioctl_private_call(str + } + + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n", ++ printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n", + ifr->ifr_name, cmd); + if(descr) { +- printk(KERN_DEBUG "Name %s, set %X, get %X\n", +- descr->name, descr->set_args, descr->get_args); ++ printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n", ++ dev->name, descr->name, ++ descr->set_args, descr->get_args); + } + #endif /* WE_IOCTL_DEBUG */ + +@@ -617,7 +694,8 @@ static inline int ioctl_private_call(str + } + + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Malloc %d bytes\n", extra_size); ++ printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", ++ dev->name, extra_size); + #endif /* WE_IOCTL_DEBUG */ + + /* Always allocate for max space. Easier, and won't last +@@ -636,7 +714,8 @@ static inline int ioctl_private_call(str + return -EFAULT; + } + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length); ++ printk(KERN_DEBUG "%s (WE) : Got %d elem\n", ++ dev->name, iwr->u.data.length); + #endif /* WE_IOCTL_DEBUG */ + } + +@@ -650,8 +729,8 @@ static inline int ioctl_private_call(str + if (err) + ret = -EFAULT; + #ifdef WE_IOCTL_DEBUG +- printk(KERN_DEBUG "Wrote %d elem\n", +- iwr->u.data.length); ++ printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n", ++ dev->name, iwr->u.data.length); + #endif /* WE_IOCTL_DEBUG */ + } + +@@ -730,4 +809,178 @@ int wireless_process_ioctl(struct ifreq + } + /* Not reached */ + return -EINVAL; ++} ++ ++/************************* EVENT PROCESSING *************************/ ++/* ++ * Process events generated by the wireless layer or the driver. ++ * Most often, the event will be propagated through rtnetlink ++ */ ++ ++#ifdef WE_EVENT_NETLINK ++/* "rtnl" is defined in net/core/rtnetlink.c, but we need it here. ++ * It is declared in <linux/rtnetlink.h> */ ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Fill a rtnetlink message with our event data. ++ * Note that we propage only the specified event and don't dump the ++ * current wireless config. Dumping the wireless config is far too ++ * expensive (for each parameter, the driver need to query the hardware). ++ */ ++static inline int rtnetlink_fill_iwinfo(struct sk_buff * skb, ++ struct net_device * dev, ++ int type, ++ char * event, ++ int event_len) ++{ ++ struct ifinfomsg *r; ++ struct nlmsghdr *nlh; ++ unsigned char *b = skb->tail; ++ ++ nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r)); ++ r = NLMSG_DATA(nlh); ++ r->ifi_family = AF_UNSPEC; ++ r->ifi_type = dev->type; ++ r->ifi_index = dev->ifindex; ++ r->ifi_flags = dev->flags; ++ r->ifi_change = 0; /* Wireless changes don't affect those flags */ ++ ++ /* Add the wireless events in the netlink packet */ ++ RTA_PUT(skb, IFLA_WIRELESS, ++ event_len, event); ++ ++ nlh->nlmsg_len = skb->tail - b; ++ return skb->len; ++ ++nlmsg_failure: ++rtattr_failure: ++ skb_trim(skb, b - skb->data); ++ return -1; ++} ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Create and broadcast and send it on the standard rtnetlink socket ++ * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c ++ * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field ++ * within a RTM_NEWLINK event. ++ */ ++static inline void rtmsg_iwinfo(struct net_device * dev, ++ char * event, ++ int event_len) ++{ ++ struct sk_buff *skb; ++ int size = NLMSG_GOODSIZE; ++ ++ skb = alloc_skb(size, GFP_ATOMIC); ++ if (!skb) ++ return; ++ ++ if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, ++ event, event_len) < 0) { ++ kfree_skb(skb); ++ return; ++ } ++ NETLINK_CB(skb).dst_groups = RTMGRP_LINK; ++ netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC); ++} ++#endif /* WE_EVENT_NETLINK */ ++ ++/* ---------------------------------------------------------------- */ ++/* ++ * Main event dispatcher. Called from other parts and drivers. ++ * Send the event on the apropriate channels. ++ * May be called from interrupt context. ++ */ ++void wireless_send_event(struct net_device * dev, ++ unsigned int cmd, ++ union iwreq_data * wrqu, ++ char * extra) ++{ ++ const struct iw_ioctl_description * descr = NULL; ++ int extra_len = 0; ++ struct iw_event *event; /* Mallocated whole event */ ++ int event_len; /* Its size */ ++ int hdr_len; /* Size of the event header */ ++ /* Don't "optimise" the following variable, it will crash */ ++ unsigned cmd_index; /* *MUST* be unsigned */ ++ ++ /* Get the description of the IOCTL */ ++ if(cmd <= SIOCIWLAST) { ++ cmd_index = cmd - SIOCIWFIRST; ++ if(cmd_index < standard_ioctl_num) ++ descr = &(standard_ioctl[cmd_index]); ++ } else { ++ cmd_index = cmd - IWEVFIRST; ++ if(cmd_index < standard_event_num) ++ descr = &(standard_event[cmd_index]); ++ } ++ /* Don't accept unknown events */ ++ if(descr == NULL) { ++ /* Note : we don't return an error to the driver, because ++ * the driver would not know what to do about it. It can't ++ * return an error to the user, because the event is not ++ * initiated by a user request. ++ * The best the driver could do is to log an error message. ++ * We will do it ourselves instead... ++ */ ++ printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n", ++ dev->name, cmd); ++ return; ++ } ++#ifdef WE_EVENT_DEBUG ++ printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n", ++ dev->name, cmd); ++ printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); ++#endif /* WE_EVENT_DEBUG */ ++ ++ /* Check extra parameters and set extra_len */ ++ if(descr->header_type == IW_HEADER_TYPE_POINT) { ++ /* Check if number of token fits within bounds */ ++ if(wrqu->data.length > descr->max_tokens) { ++ printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length); ++ return; ++ } ++ if(wrqu->data.length < descr->min_tokens) { ++ printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length); ++ return; ++ } ++ /* Calculate extra_len - extra is NULL for restricted events */ ++ if(extra != NULL) ++ extra_len = wrqu->data.length * descr->token_size; ++#ifdef WE_EVENT_DEBUG ++ printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len); ++#endif /* WE_EVENT_DEBUG */ ++ } ++ ++ /* Total length of the event */ ++ hdr_len = event_type_size[descr->header_type]; ++ event_len = hdr_len + extra_len; ++ ++#ifdef WE_EVENT_DEBUG ++ printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len); ++#endif /* WE_EVENT_DEBUG */ ++ ++ /* Create temporary buffer to hold the event */ ++ event = kmalloc(event_len, GFP_ATOMIC); ++ if(event == NULL) ++ return; ++ ++ /* Fill event */ ++ event->len = event_len; ++ event->cmd = cmd; ++ memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN); ++ if(extra != NULL) ++ memcpy(((char *) event) + hdr_len, extra, extra_len); ++ ++#ifdef WE_EVENT_NETLINK ++ /* rtnetlink event channel */ ++ rtmsg_iwinfo(dev, (char *) event, event_len); ++#endif /* WE_EVENT_NETLINK */ ++ ++ /* Cleanup */ ++ kfree(event); ++ ++ return; /* Always success, I guess ;-) */ + } diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/keymap-more-sane.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/keymap-more-sane.patch index e69de29bb2..a7eefd1e16 100644 --- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/keymap-more-sane.patch +++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/keymap-more-sane.patch @@ -0,0 +1,19 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux/drivers/char/collie_keymap.map~keymap-more-sane 2003-05-13 11:18:18.000000000 +0200 ++++ linux/drivers/char/collie_keymap.map 2004-06-23 00:03:19.000000000 +0200 +@@ -55,9 +55,11 @@ + # (Cancel:34) F9 -> Escape + keycode 34 = Escape + keycode 35 = Left ++ control keycode 35 = Decr_Console + keycode 36 = Up + keycode 37 = Down + keycode 38 = Right ++ control keycode 38 = Incr_Console + # (OK:39) F4 -> Return + keycode 39 = Return + keycode 40 = diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/logo.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/logo.patch index e69de29bb2..c006684f23 100644 --- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/logo.patch +++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/logo.patch @@ -0,0 +1,2598 @@ +--- linux/drivers/video/fbcon.c 2003-02-27 21:47:36.000000000 -0600 ++++ linux.new/drivers/video/fbcon.c 2003-02-27 18:39:39.000000000 -0600 +@@ -126,8 +126,8 @@ + #define LOGO_H (320-16) + #define LOGO_W 240 + #else +-#define LOGO_H 80 +-#define LOGO_W 80 ++#define LOGO_H 52 ++#define LOGO_W 240 + #endif + #define LOGO_LINE (LOGO_W/8) + #if defined(CONFIG_SHARP_LOGO_SCREEN) +--- linux/include/linux/linux_logo.h 2001-06-11 21:15:27.000000000 -0500 ++++ linux.new/include/linux/linux_logo.h 2003-02-27 15:58:15.000000000 -0600 +@@ -1,4 +1,4 @@ +-/* $Id$ ++/* linux_logo.h created with fblogo, 2002/12/29 02:43:36 + * include/linux/linux_logo.h: This is a linux logo + * to be displayed on boot. + * +@@ -7,907 +7,1673 @@ + * + * You can put anything here, but: + * LINUX_LOGO_COLORS has to be less than 224 +- * image size has to be 80x80 +- * values have to start from 0x20 +- * (i.e. RGB(linux_logo_red[0], +- * linux_logo_green[0], +- * linux_logo_blue[0]) is color 0x20) +- * BW image has to be 80x80 as well, with MS bit +- * on the left +- * Serial_console ascii image can be any size, +- * but should contain %s to display the version ++ * Generated by fblogo version 0.5.0 ++ * ++ * ++ * Remember to modify drivers/video/fbcon.c: ++ * Change "#define LOGO_H 80" to "#define LOGO_H 52" ++ * Change "#define LOGO_W 80" to "#define LOGO_W 240" + */ + + #ifndef __HAVE_ARCH_LINUX_LOGO +-#define LINUX_LOGO_COLORS 187 ++#define LINUX_LOGO_COLORS 223 + #endif +- + #ifdef INCLUDE_LINUX_LOGO_DATA +- + #ifndef __HAVE_ARCH_LINUX_LOGO +- + unsigned char linux_logo_red[] __initdata = { +- 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22, +- 0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56, +- 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65, +- 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6, +- 0xc3, 0x65, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6, +- 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7, +- 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x76, 0x79, +- 0x62, 0x36, 0x9a, 0xe2, 0xec, 0xe1, 0xb8, 0xd7, +- 0xaf, 0x25, 0xbc, 0xc0, 0xef, 0xea, 0xe8, 0xe8, +- 0xf5, 0xf1, 0xda, 0xd3, 0x79, 0xdb, 0xf4, 0xf6, +- 0xf6, 0xf6, 0xe2, 0x3d, 0xb4, 0xce, 0xe6, 0xee, +- 0xf6, 0x68, 0xd8, 0xec, 0xf5, 0xc6, 0xc8, 0x9c, +- 0x89, 0xd2, 0xee, 0xcb, 0xb9, 0xd2, 0x66, 0x5e, +- 0x8b, 0xbe, 0xa8, 0xd5, 0xca, 0xb6, 0xae, 0x9c, +- 0xc5, 0xbe, 0xbe, 0xca, 0x90, 0xb2, 0x9a, 0xa8, +- 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x12, +- 0x4a, 0x8e, 0xf2, 0xf6, 0xf6, 0xee, 0xb5, 0xe4, +- 0xf1, 0x26, 0x9a, 0xea, 0xf6, 0xe0, 0xd2, 0x16, +- 0x9a, 0x2e, 0x70, 0xd6, 0x46, 0x7c, 0xb4, 0x62, +- 0xd6, 0xa3, 0x74, 0xa7, 0xa2, 0xca, 0xe0, 0xae, +- 0xbe, 0xce, 0xa3, 0x8e, 0x6d, 0x8e, 0x32, 0xaf, +- 0x50, 0x9e, 0x5b, 0x8a, 0x98, 0x82, 0x7a, 0x82, +- 0x56, 0x7c, 0x8a, 0x56, 0x5e, 0x86, 0x6a, 0x52, +- 0x59, 0x64, 0x5e, ++ 0x00, 0x02, 0x06, 0x0A, 0x56, 0xA6, 0xBE, 0xBA, ++ 0xB6, 0x92, 0x3E, 0x1A, 0x8A, 0xF3, 0xFB, 0xEE, ++ 0xC6, 0x62, 0x4A, 0x12, 0x26, 0x0E, 0x76, 0xDA, ++ 0x6E, 0x32, 0x8E, 0x1E, 0x2A, 0xCE, 0xE2, 0x36, ++ 0x66, 0xA2, 0x2E, 0x9E, 0xCA, 0x6A, 0x5A, 0x82, ++ 0x7E, 0xE9, 0xD2, 0xDE, 0x22, 0x72, 0xAE, 0xD6, ++ 0x86, 0x3A, 0x52, 0x9A, 0xAA, 0x16, 0x46, 0x4E, ++ 0x42, 0xC2, 0x96, 0x7A, 0x5E, 0xB2, 0x32, 0x7E, ++ 0x3A, 0x16, 0x02, 0x02, 0x06, 0x1F, 0x02, 0x02, ++ 0x06, 0x02, 0x22, 0x3A, 0x35, 0x16, 0x0A, 0x02, ++ 0x2A, 0x3E, 0x39, 0x32, 0x2A, 0x1E, 0x16, 0x06, ++ 0x22, 0x22, 0x1E, 0x16, 0x6E, 0x82, 0x6E, 0x2E, ++ 0x1E, 0x2E, 0x1E, 0x0A, 0x3A, 0xDA, 0xFE, 0xFA, ++ 0xFA, 0xE2, 0x6A, 0x3A, 0x1A, 0xFA, 0xF6, 0x9E, ++ 0x02, 0x6E, 0xFE, 0xF6, 0x3E, 0x66, 0x52, 0x1B, ++ 0xD6, 0x5A, 0xEE, 0xC6, 0x72, 0x36, 0x22, 0x1E, ++ 0x02, 0x96, 0xF6, 0xDE, 0xA2, 0xD6, 0x39, 0x0E, ++ 0xAA, 0x52, 0x5A, 0xD2, 0xDE, 0x61, 0x46, 0xDE, ++ 0x7A, 0x57, 0x9E, 0xBA, 0xB6, 0x4A, 0x5A, 0xA6, ++ 0x96, 0x23, 0x1E, 0x12, 0x9A, 0x4E, 0x76, 0xAE, ++ 0x2E, 0xBE, 0x86, 0x48, 0xA6, 0x52, 0x06, 0x2E, ++ 0x56, 0x13, 0x2A, 0x4A, 0x36, 0x56, 0x2E, 0x1E, ++ 0x46, 0x3A, 0x66, 0x02, 0x3D, 0x3E, 0x2E, 0x3E, ++ 0x4A, 0x32, 0x52, 0x72, 0x76, 0x67, 0x68, 0x5A, ++ 0x3A, 0x1A, 0x0E, 0x2E, 0x4E, 0x02, 0x3E, 0x0A, ++ 0x28, 0x42, 0x10, 0x26, 0x8E, 0x0A, 0x86, 0xC2, ++ 0x02, 0x6E, 0x92, 0x02, 0x42, 0x02, 0xBE, 0x4E, ++ 0x02, 0x22, 0x02, 0x3E, 0x3A, 0x32 + }; + + unsigned char linux_logo_green[] __initdata = { +- 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22, +- 0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56, +- 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65, +- 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6, +- 0xc3, 0x62, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6, +- 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7, +- 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x62, 0x5c, +- 0x4e, 0x26, 0x72, 0xaa, 0xba, 0xaf, 0x90, 0xae, +- 0x92, 0x1a, 0xa4, 0x85, 0xb6, 0xbe, 0xc3, 0xc8, +- 0xcf, 0xd0, 0xc2, 0xce, 0x57, 0xa2, 0xd6, 0xda, +- 0xda, 0xd7, 0xb8, 0x2a, 0x7b, 0x91, 0xae, 0xca, +- 0xda, 0x45, 0x9e, 0xb2, 0xd7, 0x9b, 0x90, 0x76, +- 0x5c, 0xa2, 0xbe, 0xa6, 0x85, 0x96, 0x4e, 0x46, +- 0x66, 0x92, 0x7a, 0x9a, 0x96, 0x9d, 0x9a, 0x6b, +- 0x8a, 0x8e, 0xb2, 0xca, 0x90, 0xa6, 0x79, 0x7c, +- 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x0e, +- 0x36, 0x86, 0xba, 0xbe, 0xe6, 0xcc, 0x8e, 0xb8, +- 0xc4, 0x1e, 0x8e, 0xae, 0xba, 0xb2, 0xa6, 0x12, +- 0x7a, 0x20, 0x64, 0xaa, 0x2f, 0x70, 0x85, 0x46, +- 0xa6, 0x6e, 0x51, 0x72, 0x92, 0xa2, 0xa6, 0x87, +- 0x96, 0xa2, 0x85, 0x7a, 0x6a, 0x6e, 0x22, 0x76, +- 0x36, 0x76, 0x3c, 0x6e, 0x63, 0x53, 0x66, 0x62, +- 0x42, 0x50, 0x56, 0x42, 0x56, 0x56, 0x56, 0x3e, +- 0x51, 0x52, 0x56, ++ 0x00, 0x02, 0x06, 0x0A, 0x56, 0xA6, 0xBE, 0xBA, ++ 0xB6, 0x92, 0x3E, 0x1A, 0x8A, 0xF3, 0xFB, 0xEE, ++ 0xC6, 0x62, 0x4A, 0x12, 0x26, 0x0E, 0x76, 0xDA, ++ 0x6E, 0x32, 0x8E, 0x1E, 0x2A, 0xCE, 0xE2, 0x36, ++ 0x66, 0xA2, 0x2E, 0x9E, 0xCA, 0x6A, 0x5A, 0x82, ++ 0x7E, 0xE9, 0xD2, 0xDE, 0x22, 0x72, 0xAE, 0xD6, ++ 0x86, 0x3A, 0x52, 0x9A, 0xAA, 0x16, 0x46, 0x4E, ++ 0x42, 0xC2, 0x96, 0x7A, 0x5E, 0xB2, 0x2E, 0x7E, ++ 0x3A, 0x3E, 0x6A, 0xA2, 0x92, 0x30, 0x95, 0x76, ++ 0x4E, 0x86, 0x36, 0x7E, 0x9A, 0x6E, 0x42, 0x56, ++ 0x5A, 0xC2, 0xBE, 0xB2, 0xAA, 0x9A, 0x63, 0x1E, ++ 0xA2, 0x9E, 0x96, 0x5A, 0x3A, 0x42, 0x4A, 0x52, ++ 0x91, 0x46, 0x4E, 0x62, 0x22, 0x4A, 0x6E, 0x86, ++ 0x92, 0x9A, 0x52, 0x4A, 0x76, 0x7A, 0x9E, 0x76, ++ 0x62, 0x32, 0x5E, 0xAE, 0x3E, 0x66, 0x52, 0x81, ++ 0xA6, 0x5A, 0xEE, 0xC6, 0x72, 0x5C, 0x6A, 0x8A, ++ 0x36, 0x3E, 0xBA, 0xBA, 0xA2, 0xD6, 0xAA, 0x4E, ++ 0x8A, 0x4E, 0x5A, 0xD2, 0xDE, 0x64, 0x32, 0x9A, ++ 0x5E, 0x57, 0x9E, 0xBA, 0xB6, 0x52, 0x62, 0xA6, ++ 0x9A, 0x47, 0x3E, 0x56, 0x02, 0x1A, 0x76, 0xAE, ++ 0x4A, 0x02, 0x02, 0x38, 0x02, 0x4A, 0x46, 0x86, ++ 0x1E, 0x2E, 0x7A, 0xD2, 0x5E, 0x26, 0x92, 0x62, ++ 0xCA, 0x42, 0x66, 0x26, 0x67, 0xB6, 0x62, 0x92, ++ 0x9E, 0x72, 0xB2, 0xF2, 0xFE, 0xDE, 0xFE, 0xFE, ++ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0x8A, 0x2A, ++ 0x42, 0x52, 0x6A, 0x26, 0x8E, 0x26, 0x86, 0xC2, ++ 0xE2, 0x6E, 0x92, 0xBE, 0x42, 0xC6, 0xBE, 0x4E, ++ 0xEE, 0x5A, 0xEA, 0x3E, 0x4A, 0x32 + }; + + unsigned char linux_logo_blue[] __initdata = { +- 0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22, +- 0x12, 0x01, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56, +- 0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x06, 0x65, +- 0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6, +- 0xc3, 0x59, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6, +- 0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7, +- 0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x2e, 0x08, +- 0x0a, 0x06, 0x0a, 0x0b, 0x0b, 0x0f, 0x0c, 0x0f, +- 0x3d, 0x09, 0x73, 0x09, 0x0d, 0x0a, 0x10, 0x1e, +- 0x2d, 0x13, 0x86, 0xba, 0x19, 0x0a, 0x36, 0x3c, +- 0x26, 0x14, 0x0d, 0x06, 0x07, 0x0a, 0x0b, 0x0f, +- 0x4a, 0x06, 0x0a, 0x0c, 0x2b, 0x0a, 0x0b, 0x0a, +- 0x06, 0x0a, 0x0a, 0x11, 0x0b, 0x0a, 0x0a, 0x1e, +- 0x0f, 0x0d, 0x0a, 0x0b, 0x22, 0x6a, 0x72, 0x0b, +- 0x0b, 0x22, 0x90, 0xca, 0x90, 0x92, 0x3c, 0x2c, +- 0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x06, +- 0x0e, 0x6a, 0x0e, 0x0e, 0xbe, 0x5b, 0x2c, 0x3e, +- 0x0e, 0x0a, 0x5a, 0x0d, 0x0e, 0x3e, 0x0a, 0x06, +- 0x2e, 0x06, 0x4e, 0x36, 0x06, 0x58, 0x24, 0x06, +- 0x3a, 0x08, 0x08, 0x07, 0x5e, 0x45, 0x0a, 0x32, +- 0x2e, 0x2a, 0x43, 0x48, 0x5f, 0x2e, 0x06, 0x06, +- 0x07, 0x24, 0x06, 0x32, 0x06, 0x06, 0x46, 0x2e, +- 0x22, 0x06, 0x06, 0x1e, 0x4c, 0x06, 0x3a, 0x22, +- 0x42, 0x34, 0x42, ++ 0x00, 0x02, 0x06, 0x0A, 0x56, 0xA6, 0xBE, 0xBA, ++ 0xB6, 0x92, 0x3E, 0x1A, 0x8A, 0xF3, 0xFB, 0xEE, ++ 0xC6, 0x62, 0x4A, 0x12, 0x26, 0x0E, 0x76, 0xDA, ++ 0x6E, 0x32, 0x8E, 0x1E, 0x2A, 0xCE, 0xE2, 0x36, ++ 0x66, 0xA2, 0x2E, 0x9E, 0xCA, 0x6A, 0x5A, 0x82, ++ 0x7E, 0xE9, 0xD2, 0xDE, 0x22, 0x72, 0xAE, 0xD6, ++ 0x86, 0x3A, 0x52, 0x9A, 0xAA, 0x16, 0x46, 0x4E, ++ 0x42, 0xC2, 0x96, 0x7A, 0x5E, 0xB2, 0x1A, 0x06, ++ 0x1A, 0x2A, 0x36, 0x52, 0x46, 0x23, 0x4D, 0x3E, ++ 0x2A, 0x42, 0x2A, 0x5A, 0x69, 0x42, 0x26, 0x2E, ++ 0x42, 0x7E, 0x7C, 0x72, 0x6A, 0x5E, 0x3B, 0x12, ++ 0x62, 0x5E, 0x5A, 0x36, 0x26, 0x1E, 0x26, 0x42, ++ 0x56, 0x3A, 0x36, 0x36, 0x1E, 0x2E, 0x2A, 0x22, ++ 0x22, 0x1A, 0x16, 0x42, 0x46, 0x26, 0x1E, 0x12, ++ 0x32, 0x2A, 0x2E, 0x16, 0x2A, 0x1A, 0x2E, 0x4E, ++ 0x12, 0x22, 0x02, 0x02, 0x12, 0x4A, 0x46, 0x52, ++ 0x1E, 0x1E, 0x16, 0x0E, 0x02, 0x02, 0x6F, 0x2E, ++ 0x0E, 0x1A, 0x06, 0x02, 0x02, 0x04, 0x22, 0x16, ++ 0x0E, 0x12, 0x02, 0x02, 0x02, 0x0A, 0x5A, 0x02, ++ 0x02, 0x1B, 0x2E, 0x32, 0x02, 0x02, 0x02, 0x02, ++ 0x16, 0x02, 0x02, 0x10, 0x02, 0x02, 0x26, 0x5A, ++ 0x02, 0x1F, 0x52, 0x8E, 0x22, 0x02, 0x5E, 0x3E, ++ 0x86, 0x0E, 0x16, 0x16, 0x52, 0x7A, 0x4A, 0x66, ++ 0x72, 0x52, 0x82, 0xB2, 0xBA, 0xA4, 0xB2, 0xAA, ++ 0x9E, 0x8E, 0x88, 0x96, 0xA6, 0x82, 0x62, 0x1A, ++ 0x34, 0x4A, 0x31, 0x16, 0x02, 0x1A, 0x02, 0x02, ++ 0x72, 0x02, 0x02, 0x5E, 0x1A, 0x62, 0x02, 0x0E, ++ 0x76, 0x1E, 0x76, 0x1E, 0x0A, 0x02 + }; + + unsigned char linux_logo[] __initdata = { +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, +- 0x22, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, +- 0x26, 0x26, 0x25, 0x28, 0x23, 0x22, 0x21, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x21, 0x23, 0x25, 0x2a, 0x2b, 0x2c, 0x2d, 0x2d, +- 0x2d, 0x2e, 0x2c, 0x2b, 0x2a, 0x25, 0x28, 0x22, +- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, +- 0x24, 0x2a, 0x2c, 0x2f, 0x2c, 0x30, 0x30, 0x24, +- 0x25, 0x27, 0x2b, 0x2c, 0x2f, 0x31, 0x32, 0x25, +- 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25, +- 0x33, 0x34, 0x35, 0x21, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x21, 0x2b, 0x2f, 0x2c, +- 0x30, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33, +- 0x2d, 0x27, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x31, +- 0x2d, 0x32, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, 0x2a, 0x34, +- 0x25, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x23, 0x32, 0x27, 0x21, 0x36, +- 0x2a, 0x2d, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x22, 0x26, 0x2c, 0x35, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x25, 0x2f, 0x37, 0x32, 0x22, +- 0x36, 0x35, 0x31, 0x27, 0x22, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x22, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x26, 0x38, 0x38, 0x35, 0x25, +- 0x36, 0x21, 0x2d, 0x2b, 0x24, 0x21, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x21, 0x24, 0x39, 0x39, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x25, 0x2b, 0x30, 0x28, 0x22, +- 0x36, 0x36, 0x27, 0x34, 0x30, 0x23, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x21, 0x26, 0x2d, 0x26, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x22, 0x22, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x2d, 0x33, 0x28, 0x21, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x2b, 0x2c, 0x25, 0x21, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x36, 0x36, +- 0x36, 0x21, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x21, 0x23, 0x22, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x28, 0x34, 0x27, 0x22, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36, +- 0x21, 0x21, 0x24, 0x27, 0x21, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x28, 0x27, 0x22, 0x33, 0x24, 0x36, +- 0x36, 0x36, 0x36, 0x22, 0x2f, 0x2a, 0x23, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36, +- 0x30, 0x3a, 0x38, 0x24, 0x24, 0x36, 0x36, 0x36, +- 0x23, 0x2f, 0x3b, 0x3c, 0x3d, 0x30, 0x25, 0x21, +- 0x36, 0x36, 0x36, 0x36, 0x2f, 0x32, 0x23, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x23, +- 0x3e, 0x3f, 0x40, 0x3a, 0x22, 0x36, 0x36, 0x21, +- 0x41, 0x42, 0x43, 0x44, 0x45, 0x3e, 0x23, 0x21, +- 0x36, 0x36, 0x36, 0x36, 0x2f, 0x33, 0x28, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x2b, +- 0x44, 0x40, 0x46, 0x47, 0x35, 0x36, 0x36, 0x26, +- 0x43, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x2e, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x23, 0x32, 0x34, 0x36, 0x4d, +- 0x4e, 0x25, 0x2f, 0x46, 0x4a, 0x22, 0x23, 0x32, +- 0x4f, 0x50, 0x21, 0x31, 0x51, 0x52, 0x53, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x21, 0x3a, +- 0x4d, 0x21, 0x31, 0x54, 0x55, 0x28, 0x30, 0x2b, +- 0x4b, 0x4d, 0x36, 0x23, 0x32, 0x50, 0x3f, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x29, 0x20, 0x29, 0x20, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x23, 0x2a, 0x38, 0x23, 0x37, +- 0x55, 0x36, 0x28, 0x3a, 0x56, 0x57, 0x57, 0x58, +- 0x3c, 0x4d, 0x36, 0x36, 0x36, 0x40, 0x40, 0x21, +- 0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x29, 0x29, 0x29, 0x20, 0x29, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x30, 0x51, 0x23, 0x35, +- 0x43, 0x25, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, +- 0x5f, 0x60, 0x61, 0x36, 0x31, 0x47, 0x3b, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x31, 0x2c, 0x25, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x22, +- 0x40, 0x62, 0x63, 0x5d, 0x64, 0x65, 0x66, 0x67, +- 0x68, 0x69, 0x66, 0x5e, 0x6a, 0x6b, 0x2a, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x33, 0x2e, 0x26, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x27, 0x2f, 0x23, 0x36, +- 0x6c, 0x63, 0x6d, 0x64, 0x5c, 0x66, 0x69, 0x6e, +- 0x6f, 0x70, 0x71, 0x69, 0x69, 0x72, 0x6c, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x33, 0x34, 0x27, 0x22, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x27, 0x34, 0x26, 0x73, +- 0x74, 0x75, 0x76, 0x64, 0x65, 0x77, 0x69, 0x78, +- 0x70, 0x71, 0x71, 0x71, 0x72, 0x5f, 0x5e, 0x21, +- 0x36, 0x36, 0x36, 0x36, 0x25, 0x38, 0x2a, 0x23, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x33, 0x79, +- 0x63, 0x7a, 0x7b, 0x5c, 0x66, 0x69, 0x6e, 0x7c, +- 0x71, 0x71, 0x69, 0x7d, 0x7e, 0x7a, 0x7f, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x21, 0x51, 0x2b, 0x28, +- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x32, 0x24, +- 0x80, 0x81, 0x64, 0x82, 0x77, 0x69, 0x71, 0x71, +- 0x69, 0x83, 0x84, 0x85, 0x7a, 0x85, 0x86, 0x36, +- 0x21, 0x2b, 0x23, 0x36, 0x36, 0x39, 0x2e, 0x26, +- 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x27, 0x2d, 0x33, 0x21, +- 0x87, 0x88, 0x89, 0x72, 0x67, 0x66, 0x5f, 0x89, +- 0x8a, 0x63, 0x85, 0x8b, 0x8c, 0x8d, 0x41, 0x36, +- 0x36, 0x2d, 0x3a, 0x35, 0x36, 0x24, 0x51, 0x32, +- 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x33, 0x21, +- 0x55, 0x8e, 0x8f, 0x8a, 0x7d, 0x5e, 0x90, 0x7e, +- 0x75, 0x75, 0x90, 0x62, 0x40, 0x3f, 0x49, 0x23, +- 0x36, 0x24, 0x3a, 0x3a, 0x24, 0x36, 0x2e, 0x31, +- 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x21, 0x28, 0x33, 0x37, 0x25, 0x22, +- 0x3b, 0x50, 0x8e, 0x8f, 0x90, 0x7e, 0x90, 0x63, +- 0x74, 0x91, 0x92, 0x42, 0x93, 0x4b, 0x45, 0x2c, +- 0x36, 0x36, 0x33, 0x39, 0x21, 0x36, 0x22, 0x51, +- 0x33, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x22, 0x27, 0x2e, 0x2e, 0x36, 0x21, +- 0x94, 0x3f, 0x50, 0x95, 0x96, 0x8f, 0x8f, 0x97, +- 0x8e, 0x42, 0x50, 0x43, 0x47, 0x48, 0x48, 0x98, +- 0x21, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, +- 0x2e, 0x27, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x22, 0x24, 0x2b, 0x38, 0x28, 0x36, 0x32, +- 0x4c, 0x4b, 0x50, 0x50, 0x50, 0x42, 0x42, 0x50, +- 0x50, 0x40, 0x45, 0x99, 0x48, 0x48, 0x48, 0x48, +- 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x23, +- 0x2f, 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x21, 0x28, 0x32, 0x51, 0x32, 0x28, 0x21, 0x98, +- 0x48, 0x47, 0x9a, 0x50, 0x50, 0x50, 0x50, 0x50, +- 0x9a, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x93, 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x2a, 0x2f, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, +- 0x23, 0x30, 0x2e, 0x2c, 0x36, 0x21, 0x51, 0x9b, +- 0x48, 0x48, 0x52, 0x3f, 0x50, 0x50, 0x40, 0x4b, +- 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x2d, 0x31, 0x27, 0x23, 0x21, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, +- 0x27, 0x2c, 0x2d, 0x21, 0x36, 0x28, 0x44, 0x48, +- 0x48, 0x48, 0x48, 0x47, 0x46, 0x4f, 0x47, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x9c, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x28, 0x51, 0x39, 0x26, 0x22, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25, +- 0x35, 0x51, 0x28, 0x36, 0x36, 0x9d, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x4f, 0x28, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x28, 0x38, 0x2b, 0x25, 0x22, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33, +- 0x51, 0x25, 0x36, 0x36, 0x23, 0x40, 0x9b, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x9b, 0x99, 0x2b, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x30, 0x2f, 0x33, 0x24, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x21, 0x23, 0x30, 0x34, +- 0x27, 0x36, 0x36, 0x36, 0x2a, 0x40, 0x47, 0x48, +- 0x48, 0x48, 0x48, 0x9b, 0x99, 0x99, 0x9b, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x47, 0x52, +- 0x46, 0x4f, 0x37, 0x21, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x30, 0x34, 0x2a, 0x23, +- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x22, 0x25, 0x39, 0x2c, +- 0x36, 0x36, 0x36, 0x21, 0x31, 0x4e, 0x9a, 0x4c, +- 0x47, 0x9b, 0x9b, 0x52, 0x46, 0x4f, 0x52, 0x9b, +- 0x9b, 0x9b, 0x47, 0x4f, 0x45, 0x9a, 0x93, 0x93, +- 0x3f, 0x93, 0x98, 0x28, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, 0x26, +- 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x28, +- 0x36, 0x36, 0x36, 0x22, 0x38, 0x98, 0x44, 0x99, +- 0x9b, 0x48, 0x48, 0x9b, 0x4c, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x47, 0x52, 0x46, 0x43, 0x93, +- 0x40, 0x40, 0x43, 0x53, 0x21, 0x23, 0x33, 0x23, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x2f, 0x32, +- 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x21, 0x24, 0x2b, 0x31, 0x36, +- 0x36, 0x22, 0x36, 0x24, 0x9e, 0x4f, 0x9b, 0x48, +- 0x48, 0x48, 0x48, 0x9b, 0x99, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x47, +- 0x4f, 0x9a, 0x3f, 0x46, 0x38, 0x36, 0x21, 0x30, +- 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, +- 0x25, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x22, 0x26, 0x2e, 0x33, 0x36, +- 0x25, 0x25, 0x36, 0x4d, 0x52, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x47, 0x44, 0x93, 0x43, 0x23, 0x36, 0x36, +- 0x26, 0x24, 0x36, 0x36, 0x36, 0x36, 0x28, 0x2f, +- 0x2a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x23, 0x2a, 0x51, 0x24, 0x36, +- 0x2a, 0x36, 0x28, 0x44, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x9b, 0x4b, 0x44, 0x37, 0x36, 0x23, +- 0x28, 0x30, 0x22, 0x36, 0x36, 0x36, 0x36, 0x2d, +- 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x21, 0x28, 0x2b, 0x34, 0x36, 0x25, +- 0x24, 0x36, 0x4a, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x9b, 0x52, 0x3f, 0x21, 0x30, +- 0x35, 0x25, 0x30, 0x36, 0x36, 0x36, 0x36, 0x32, +- 0x2d, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x22, 0x26, 0x2e, 0x35, 0x36, 0x2a, +- 0x36, 0x24, 0x4f, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x47, 0x32, 0x30, +- 0x2a, 0x23, 0x30, 0x23, 0x36, 0x36, 0x36, 0x21, +- 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x21, 0x23, 0x2a, 0x51, 0x28, 0x28, 0x25, +- 0x36, 0x3a, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x9b, 0x52, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x38, 0x21, +- 0x36, 0x36, 0x22, 0x27, 0x36, 0x36, 0x36, 0x36, +- 0x2e, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x22, 0x25, 0x2c, 0x34, 0x36, 0x30, 0x21, +- 0x23, 0x43, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x47, 0x99, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x94, 0x36, +- 0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36, +- 0x2a, 0x2e, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x21, 0x23, 0x2a, 0x51, 0x25, 0x21, 0x2a, 0x36, +- 0x2e, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x99, 0x99, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x98, 0x36, +- 0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36, +- 0x22, 0x2f, 0x30, 0x22, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x22, 0x25, 0x2c, 0x34, 0x36, 0x24, 0x28, 0x36, +- 0x54, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4c, 0x99, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36, +- 0x36, 0x36, 0x36, 0x30, 0x36, 0x36, 0x36, 0x36, +- 0x21, 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, +- 0x28, 0x32, 0x2f, 0x28, 0x36, 0x27, 0x22, 0x21, +- 0x43, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4c, 0x99, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4b, 0x21, +- 0x36, 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, +- 0x25, 0x2c, 0x39, 0x36, 0x36, 0x30, 0x22, 0x25, +- 0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4f, 0x52, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4f, 0x21, +- 0x36, 0x36, 0x22, 0x26, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, +- 0x30, 0x2d, 0x21, 0x36, 0x36, 0x32, 0x23, 0x2a, +- 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4f, 0x99, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4c, 0x22, +- 0x36, 0x36, 0x24, 0x23, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, +- 0x33, 0x2e, 0x36, 0x36, 0x23, 0x31, 0x27, 0x39, +- 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4c, 0x23, +- 0x36, 0x36, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, +- 0x2b, 0x39, 0x36, 0x36, 0x36, 0x26, 0x32, 0x31, +- 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x46, 0x22, +- 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, +- 0x35, 0x39, 0x36, 0x36, 0x36, 0x36, 0x26, 0x2d, +- 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36, +- 0x24, 0x27, 0x9f, 0x24, 0x25, 0x28, 0x21, 0x36, +- 0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x25, +- 0x39, 0x4d, 0xa0, 0x84, 0x81, 0x57, 0x21, 0x39, +- 0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x53, 0x28, +- 0x23, 0x36, 0x36, 0x36, 0x21, 0x28, 0x2c, 0x30, +- 0x21, 0x38, 0x33, 0x28, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x28, 0x30, +- 0x2d, 0xa1, 0x7a, 0xa2, 0xa3, 0xa3, 0x7f, 0x22, +- 0x51, 0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0xa4, 0xa5, 0xa5, 0xa6, 0x61, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x30, 0x32, +- 0x25, 0x4d, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x21, 0x23, 0x24, 0x26, 0x30, 0x33, 0x31, +- 0x4d, 0x91, 0x5b, 0xa2, 0xa3, 0xa3, 0xa3, 0x5a, +- 0x21, 0x2e, 0x46, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0xa7, 0xa8, 0x69, 0x66, 0xa9, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x26, 0x25, +- 0x83, 0xaa, 0x2c, 0x25, 0x21, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x21, 0x28, 0x30, 0x35, 0x2d, 0x2f, 0x37, 0x4a, +- 0x60, 0x85, 0xab, 0xac, 0xa3, 0xa3, 0xa3, 0x82, +- 0x86, 0x36, 0x32, 0x3f, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x4c, 0x99, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0xad, 0xa2, 0xa8, 0xae, 0xaf, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x57, +- 0x77, 0x66, 0x34, 0x27, 0x22, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x23, 0x30, 0x31, 0xb0, 0x91, 0x7e, 0x90, 0x90, +- 0x8b, 0x5b, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0x5d, 0xb1, 0x36, 0x24, 0x53, 0x9b, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x9b, 0x99, 0xad, 0x64, 0x5c, 0x8b, 0xb1, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x73, 0x5d, +- 0x82, 0x5c, 0xb2, 0x2a, 0x23, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, +- 0x24, 0x2b, 0xb0, 0x8b, 0x5b, 0x76, 0x5b, 0x5b, +- 0x7b, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa8, 0x5e, 0x22, 0x36, 0x21, 0x3a, 0x99, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x4f, 0x3f, 0xb3, 0x7b, 0x7b, 0x85, 0x80, +- 0x9f, 0x36, 0x36, 0x36, 0x21, 0xb4, 0x7e, 0x7b, +- 0x64, 0x64, 0xb5, 0x35, 0x24, 0x21, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, +- 0x26, 0x31, 0xb6, 0x5b, 0x64, 0xa2, 0xa2, 0xac, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0x66, 0xb7, 0x36, 0x36, 0x36, 0x2c, 0x4b, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x9a, 0x3f, 0xb8, 0x76, 0x76, 0x7a, 0x63, +- 0xb9, 0xba, 0x86, 0xba, 0xbb, 0x90, 0x5b, 0x64, +- 0xa2, 0xa2, 0xbc, 0x2d, 0x27, 0x23, 0x21, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, +- 0x26, 0x2d, 0x91, 0x5b, 0x64, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa8, 0x83, 0xaf, 0x36, 0x36, 0x36, 0x30, +- 0x44, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x9b, 0x9a, 0x3f, 0xbd, 0x5b, 0x7b, 0xbe, 0x85, +- 0x7e, 0x90, 0x63, 0x90, 0x85, 0x5b, 0xa2, 0xa3, +- 0xa3, 0xac, 0x5d, 0xb5, 0x39, 0x26, 0x23, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, +- 0x26, 0x2d, 0xbf, 0xbe, 0x64, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa8, 0x88, 0x36, 0x36, 0x36, 0x36, +- 0x2d, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x9b, 0x45, 0x3f, 0xc0, 0x6d, 0x7b, 0xab, 0xbe, +- 0x7a, 0x8b, 0x8b, 0x7a, 0x5b, 0x64, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa2, 0xc1, 0x37, 0x35, 0x26, 0x23, +- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, +- 0x26, 0x2e, 0xbf, 0x7a, 0x7b, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa8, 0x72, 0x73, 0x36, 0x36, 0x36, +- 0x24, 0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x46, 0x42, 0xb6, 0x7a, 0x7b, 0x64, 0x7b, +- 0x76, 0x5b, 0x5b, 0x76, 0x7b, 0xa2, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xac, 0x64, 0xc1, 0x4d, 0x2c, 0x27, +- 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, +- 0x25, 0x31, 0xc2, 0x8b, 0x7b, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa8, 0x89, 0x9f, 0x36, 0x36, +- 0x32, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x4b, 0x2f, 0x8f, 0x7a, 0x7b, 0xa2, 0xac, +- 0xa2, 0x64, 0x64, 0xa2, 0xa2, 0xac, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0x5d, 0xc3, 0x2c, +- 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, +- 0x25, 0x31, 0xc2, 0x85, 0x7b, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0x66, 0x57, 0x27, 0x4d, +- 0x4b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x99, 0x34, 0x9f, 0xb9, 0x7a, 0x7b, 0xa2, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xc2, +- 0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, +- 0x26, 0x2d, 0xc2, 0x85, 0x7b, 0xac, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa8, 0x5f, 0x92, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x44, +- 0x35, 0x36, 0xaf, 0xbb, 0x7a, 0x7b, 0xac, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0xa2, 0xc0, +- 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, +- 0x30, 0x2f, 0xb6, 0x8b, 0x7b, 0xac, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x66, 0x89, 0x45, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x4e, 0x25, +- 0x36, 0x36, 0x61, 0xb9, 0x6d, 0x64, 0xac, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0x7b, 0xbe, 0xc3, +- 0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, +- 0x33, 0xc4, 0x63, 0xbe, 0xa2, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0x72, 0x81, 0xc5, +- 0x46, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, +- 0x48, 0x48, 0x48, 0x48, 0x3f, 0x2c, 0x36, 0x36, +- 0x36, 0x36, 0xc6, 0x8f, 0x6d, 0x64, 0xac, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa2, 0xab, 0x8b, 0xb0, 0x2c, +- 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, +- 0x35, 0x96, 0x75, 0xab, 0xa2, 0xac, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0x7b, 0x81, 0xb9, +- 0x73, 0x3b, 0x44, 0x9b, 0x48, 0x48, 0x48, 0x9b, +- 0x99, 0x43, 0x94, 0x2c, 0x21, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x73, 0xb9, 0x7a, 0x7b, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0x64, 0x76, 0x7a, 0x91, 0xb5, 0x31, 0x30, +- 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, +- 0x39, 0x97, 0x75, 0xbe, 0x7b, 0x64, 0xa2, 0xa2, +- 0xac, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x7b, 0x7a, 0xc7, +- 0xc8, 0x36, 0x21, 0x26, 0x2b, 0x39, 0x33, 0x30, +- 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x21, 0xc8, 0xbb, 0x8b, 0x7b, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0x64, 0x64, +- 0x76, 0x85, 0xbf, 0xb5, 0x34, 0x2b, 0x27, 0x28, +- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28, +- 0x33, 0xc9, 0x63, 0x7e, 0x7a, 0x6d, 0xbe, 0x5b, +- 0x76, 0x7b, 0x64, 0x64, 0xa2, 0xac, 0xa3, 0xa3, +- 0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0x76, 0x85, 0xb9, +- 0x79, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x21, 0xca, 0xbb, 0x75, 0x76, 0xa2, 0xa3, +- 0xa3, 0xa3, 0xac, 0xa2, 0x64, 0x76, 0xbe, 0x8b, +- 0xb6, 0xb5, 0x2f, 0x35, 0x30, 0x24, 0x22, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23, +- 0x27, 0x31, 0xcb, 0xc9, 0xbb, 0x74, 0x63, 0x90, +- 0x7e, 0x75, 0x8b, 0x6d, 0xbe, 0x76, 0x64, 0xa2, +- 0xac, 0xac, 0xac, 0xac, 0x64, 0x7a, 0x84, 0xcc, +- 0x79, 0x9f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +- 0x36, 0x21, 0xc8, 0xcc, 0x63, 0x6d, 0x7b, 0x64, +- 0xac, 0xa2, 0x64, 0x7b, 0xbe, 0x75, 0x63, 0x96, +- 0x38, 0x39, 0x2a, 0x24, 0x23, 0x21, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, +- 0x28, 0x27, 0x35, 0x2d, 0x41, 0xb5, 0xc5, 0x8f, +- 0xb9, 0xbb, 0xc7, 0x74, 0x84, 0x90, 0x85, 0x6d, +- 0x5b, 0x7b, 0x7b, 0xab, 0x6d, 0x90, 0xb9, 0xcd, +- 0xca, 0x22, 0x36, 0x36, 0x28, 0x30, 0x30, 0x30, +- 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x25, 0x36, +- 0x36, 0x21, 0xb4, 0x80, 0xc7, 0x7e, 0x6d, 0x76, +- 0xab, 0x76, 0x6d, 0x85, 0x63, 0xb9, 0xb5, 0x34, +- 0x33, 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x21, 0x23, 0x24, 0x27, 0x2a, 0x35, 0x2e, 0x2f, +- 0x41, 0xce, 0xcf, 0x6c, 0x80, 0xcc, 0xb9, 0x74, +- 0x84, 0x90, 0x75, 0x7e, 0x74, 0x8f, 0xcd, 0x79, +- 0xc6, 0x2b, 0x9d, 0x41, 0x2f, 0x34, 0x2d, 0x2d, +- 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x34, 0x2f, 0x38, +- 0x4d, 0x37, 0xd0, 0xd1, 0x8f, 0x74, 0x63, 0x7e, +- 0x75, 0x7e, 0x63, 0xc7, 0x88, 0xc4, 0x31, 0x2a, +- 0x24, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x21, 0x22, 0x23, 0x24, 0x26, 0x30, +- 0x33, 0x39, 0x2e, 0x51, 0x41, 0xb2, 0x6c, 0xd1, +- 0x80, 0xcc, 0xcc, 0xcc, 0xd2, 0xd1, 0xb7, 0xd3, +- 0x41, 0x34, 0x35, 0x32, 0x30, 0x27, 0x27, 0x27, +- 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x30, 0x2a, +- 0x2b, 0x34, 0xd4, 0xca, 0xd5, 0x8f, 0xbb, 0xc7, +- 0xc7, 0xbb, 0xcc, 0x6c, 0x41, 0x39, 0x27, 0x28, +- 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, +- 0x28, 0x24, 0x26, 0x2a, 0x33, 0x2c, 0x2f, 0x41, +- 0xd6, 0xb7, 0x79, 0x79, 0x79, 0xca, 0xd7, 0x51, +- 0x39, 0x30, 0x24, 0x23, 0x22, 0x22, 0x22, 0x22, +- 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23, +- 0x24, 0x2a, 0x31, 0xd8, 0xc8, 0x79, 0xd1, 0x80, +- 0xd5, 0xba, 0xd9, 0x2f, 0x35, 0x26, 0x23, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x21, 0x22, 0x23, 0x28, 0x25, 0x30, 0x2b, +- 0x31, 0x2f, 0xd4, 0xd8, 0xd8, 0x2f, 0x2e, 0x33, +- 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x21, 0x28, 0x27, 0x35, 0x34, 0xd8, 0xd8, 0xd8, +- 0xda, 0xd4, 0x2e, 0x33, 0x25, 0x23, 0x21, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x23, 0x28, +- 0x26, 0x30, 0x32, 0x2b, 0x33, 0x2a, 0x26, 0x28, +- 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x21, 0x23, 0x25, 0x30, 0x33, 0x35, 0x35, +- 0x2b, 0x2a, 0x26, 0x28, 0x22, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, +- 0x21, 0x22, 0x23, 0x28, 0x28, 0x23, 0x22, 0x21, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x21, 0x23, 0x28, 0x24, 0x24, +- 0x28, 0x23, 0x22, 0x21, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x23, 0x33, 0x22, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x23, 0x61, 0x62, 0x2B, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x35, 0x61, 0x63, 0x64, 0x35, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x65, 0x66, 0x66, 0x67, 0x55, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3B, ++ 0x3B, 0x68, 0x64, 0x69, 0x62, 0x55, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x22, 0x23, 0x23, 0x55, 0x6A, 0x6B, ++ 0x6C, 0x6D, 0x6E, 0x6F, 0x6F, 0x33, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, ++ 0x22, 0x23, 0x35, 0x33, 0x3B, 0x70, 0x71, 0x72, ++ 0x73, 0x74, 0x75, 0x76, 0x77, 0x55, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x22, 0x23, 0x23, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x23, 0x55, ++ 0x2B, 0x34, 0x34, 0x42, 0x70, 0x71, 0x73, 0x78, ++ 0x78, 0x78, 0x79, 0x7A, 0x7B, 0x34, 0x22, 0x21, ++ 0x55, 0x33, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x22, 0x3B, 0x7C, 0x7D, 0x7E, 0x34, 0x35, ++ 0x21, 0x21, 0x21, 0x21, 0x35, 0x3B, 0x4C, 0x3C, ++ 0x42, 0x3F, 0x56, 0x7F, 0x71, 0x74, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x79, 0x80, 0x81, 0x3C, 0x82, ++ 0x83, 0x62, 0x61, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x23, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, ++ 0x3B, 0x21, 0x55, 0x55, 0x2B, 0x34, 0x39, 0x3F, ++ 0x2A, 0x57, 0x8B, 0x72, 0x74, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x75, 0x8C, 0x6F, 0x63, ++ 0x63, 0x66, 0x61, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x84, 0x85, 0x86, 0x8D, 0x88, 0x8E, 0x8F, 0x5E, ++ 0x3C, 0x34, 0x3B, 0x34, 0x3F, 0x2A, 0x58, 0x57, ++ 0x52, 0x46, 0x6C, 0x73, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x79, 0x7A, 0x6E, 0x69, ++ 0x69, 0x90, 0x34, 0x33, 0x22, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, ++ 0x91, 0x92, 0x8D, 0x87, 0x8E, 0x93, 0x8A, 0x35, ++ 0x94, 0x95, 0x96, 0x56, 0x32, 0x32, 0x52, 0x5C, ++ 0x4D, 0x82, 0x72, 0x78, 0x78, 0x78, 0x78, 0x79, ++ 0x97, 0x78, 0x78, 0x78, 0x78, 0x75, 0x6D, 0x6F, ++ 0x62, 0x65, 0x34, 0x4C, 0x33, 0x22, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B, ++ 0x91, 0x86, 0x87, 0x88, 0x93, 0x98, 0x60, 0x3F, ++ 0x99, 0x9A, 0x9A, 0x9B, 0x9C, 0x57, 0x5C, 0x36, ++ 0x9D, 0x9E, 0x6D, 0x78, 0x78, 0x78, 0x97, 0x6E, ++ 0x9F, 0x78, 0x78, 0x78, 0x78, 0x79, 0x80, 0xA0, ++ 0x61, 0x51, 0x51, 0x3C, 0x4C, 0x55, 0x35, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x3B, 0x22, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4C, ++ 0xA1, 0x8D, 0x88, 0x8E, 0xA2, 0xA3, 0x94, 0x42, ++ 0x51, 0xA4, 0x9A, 0x9A, 0x9A, 0xA5, 0x9C, 0x2A, ++ 0xA6, 0x74, 0x8C, 0x75, 0x97, 0xA7, 0x76, 0x75, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75, 0x6E, ++ 0x46, 0x52, 0x56, 0x3F, 0x42, 0x34, 0x33, 0x35, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x22, 0x22, 0x21, 0x21, 0x22, ++ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x3A, ++ 0x5A, 0x53, 0x53, 0x29, 0x43, 0x50, 0x53, 0x5A, ++ 0x5A, 0x29, 0x5A, 0x43, 0x53, 0x5D, 0x44, 0x2A, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x55, ++ 0x7D, 0x87, 0x8E, 0x93, 0xA8, 0xA9, 0xAA, 0x2A, ++ 0x57, 0x94, 0xA4, 0x9B, 0xAB, 0xAC, 0x9A, 0x9B, ++ 0xAD, 0x76, 0x79, 0x78, 0x75, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75, 0x6D, ++ 0x46, 0x5C, 0x57, 0x56, 0x51, 0x42, 0x4C, 0x55, ++ 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x23, 0x24, 0x25, 0x26, 0x26, 0x27, 0x28, 0x27, ++ 0x29, 0x2A, 0x2B, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x38, 0x30, ++ 0x59, 0x3D, 0x3D, 0x3D, 0x27, 0x27, 0x26, 0x5D, ++ 0x27, 0x27, 0x54, 0x37, 0x2E, 0x4A, 0x36, 0x2B, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0xAE, 0x88, 0xAF, 0xB0, 0xAA, 0x2A, 0x39, 0x34, ++ 0x4C, 0x5C, 0x58, 0xB1, 0xB2, 0xB3, 0xAB, 0xA5, ++ 0x9A, 0xB4, 0xB5, 0x8C, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x80, ++ 0xB6, 0x38, 0x5C, 0x57, 0x56, 0x3F, 0x42, 0x3B, ++ 0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, ++ 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x32, ++ 0x31, 0x2C, 0x26, 0x2C, 0x33, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x34, ++ 0x32, 0x2B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x33, ++ 0x33, 0x55, 0x55, 0x55, 0x23, 0x23, 0x35, 0x23, ++ 0x23, 0x35, 0x2B, 0x4E, 0x4F, 0x2A, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x55, 0x38, 0x25, ++ 0x2C, 0x52, 0x34, 0x22, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x55, 0x8A, 0x8F, 0x39, 0x34, 0x3C, 0x57, 0x32, ++ 0x46, 0x42, 0x52, 0x4A, 0x51, 0xAA, 0xB7, 0xB3, ++ 0xAB, 0xAC, 0xAC, 0xB8, 0xB9, 0x79, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x7A, ++ 0xBA, 0x70, 0x7B, 0xBB, 0x82, 0x56, 0x3F, 0x34, ++ 0x4C, 0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, 0x36, ++ 0x2D, 0x37, 0x38, 0x2A, 0x2B, 0x21, 0x21, 0x21, ++ 0x21, 0x22, 0x39, 0x3A, 0x2C, 0x3B, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x33, 0x3C, 0x22, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x24, 0x3D, ++ 0x3E, 0x25, 0x3C, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x33, 0x29, 0x26, 0x2A, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x54, 0x3E, 0x28, ++ 0x28, 0x59, 0x59, 0x48, 0x51, 0x3F, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x2B, 0x56, 0x4D, 0x29, 0x5B, 0x34, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x55, 0x60, 0x3F, 0x42, 0x51, 0x32, 0x52, ++ 0x40, 0x38, 0x40, 0x46, 0x42, 0xBC, 0xBD, 0xBE, ++ 0xBF, 0x9B, 0xAB, 0x9B, 0xC0, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75, ++ 0xA7, 0x63, 0x63, 0x66, 0x6F, 0x58, 0x56, 0x39, ++ 0x34, 0x2B, 0x23, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x2F, ++ 0x3D, 0x3F, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x22, 0x40, 0x41, 0x3B, 0x21, ++ 0x21, 0x22, 0x42, 0x38, 0x43, 0x44, 0x3A, 0x45, ++ 0x34, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x46, 0x30, 0x47, ++ 0x2A, 0x48, 0x48, 0x21, 0x21, 0x21, 0x21, 0x22, ++ 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x22, 0x34, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x22, 0x4D, 0x44, 0x2A, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x22, 0x50, 0x4A, 0x57, 0x35, ++ 0x35, 0x2B, 0x56, 0x27, 0x4B, 0x5D, 0x35, 0x21, ++ 0x21, 0x21, 0x21, 0x3B, 0x52, 0x23, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B, ++ 0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3B, 0x38, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33, ++ 0x3C, 0x42, 0x21, 0x33, 0x24, 0x35, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33, ++ 0x2B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x33, 0x38, 0x59, 0x37, 0x27, 0x27, 0x4A, 0x47, ++ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x23, 0x4C, 0x4C, 0x2A, 0x56, 0x46, 0x31, ++ 0x4D, 0x36, 0x50, 0x5A, 0x35, 0xC1, 0xC1, 0xC2, ++ 0xC3, 0xB7, 0xB3, 0xBE, 0x76, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75, ++ 0x6D, 0x62, 0x69, 0x6F, 0x58, 0x46, 0x32, 0x2A, ++ 0x39, 0x34, 0x35, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x3B, 0x44, 0x49, ++ 0x31, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x23, 0x29, 0x48, 0x22, ++ 0x42, 0x3A, 0x4A, 0x49, 0x4B, 0x2E, 0x4B, 0x3E, ++ 0x4A, 0x2C, 0x34, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x30, 0x40, 0x22, ++ 0x21, 0x32, 0x3A, 0x22, 0x21, 0x21, 0x21, 0x39, ++ 0x36, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, ++ 0x31, 0x4F, 0x2A, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x31, 0x59, 0x2A, 0x22, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x55, 0x27, 0x24, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x4C, 0x44, 0x27, 0x35, 0x21, ++ 0x21, 0x21, 0x21, 0x2A, 0x26, 0x2B, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3A, ++ 0x40, 0x21, 0x21, 0x21, 0x21, 0x21, 0x51, 0x49, ++ 0x35, 0x21, 0x21, 0x21, 0x21, 0x22, 0x58, 0x25, ++ 0x5A, 0x57, 0x21, 0x4C, 0x3D, 0x34, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x38, ++ 0x47, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, ++ 0x3A, 0x4B, 0x53, 0x56, 0x55, 0x33, 0x42, 0x56, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x55, 0x4C, 0x42, 0x2A, 0x57, 0x5C, 0x38, ++ 0x36, 0x47, 0x5A, 0xB6, 0x77, 0xC4, 0xC1, 0xC1, ++ 0xC4, 0xC5, 0xB7, 0xB9, 0x79, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75, ++ 0x97, 0xC6, 0x68, 0x57, 0x4D, 0x38, 0x46, 0x32, ++ 0x51, 0x42, 0x2B, 0x35, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x4D, 0x2D, 0x38, ++ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x4C, 0x4E, 0x3C, ++ 0x47, 0x4F, 0x50, 0x51, 0x3F, 0x44, 0x42, 0x34, ++ 0x52, 0x53, 0x28, 0x2A, 0x22, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x48, 0x54, 0x33, 0x21, ++ 0x23, 0x3A, 0x3A, 0x22, 0x21, 0x21, 0x21, 0x2A, ++ 0x26, 0x33, 0x21, 0x21, 0x21, 0x21, 0x23, 0x45, ++ 0x37, 0x3D, 0x41, 0x22, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x31, ++ 0x59, 0x3F, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x3C, 0x28, 0x33, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x23, 0x27, 0x5B, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x3C, 0x54, 0x55, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4C, 0x4B, ++ 0x46, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3B, 0x49, ++ 0x2B, 0x21, 0x21, 0x21, 0x23, 0x40, 0x43, 0x32, ++ 0x35, 0x21, 0x21, 0x33, 0x28, 0x4C, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x4F, ++ 0x5B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x50, ++ 0x44, 0x39, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x23, 0x3B, 0x34, 0x3F, 0x58, 0x46, 0x40, 0x36, ++ 0x50, 0x41, 0x4D, 0xC7, 0x65, 0xC2, 0xC1, 0xC1, ++ 0xC8, 0xBF, 0xB1, 0x97, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, ++ 0x80, 0xC9, 0x36, 0x50, 0x36, 0x38, 0x31, 0x32, ++ 0x56, 0x39, 0x34, 0x33, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x2B, 0x3D, 0x28, 0x35, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x40, 0x4D, ++ 0x55, 0x2B, 0x21, 0x21, 0x2B, 0x28, 0x3B, 0x21, ++ 0x21, 0x22, 0x52, 0x27, 0x56, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x23, 0x2A, 0x30, 0x3F, 0x21, 0x22, ++ 0x57, 0x44, 0x58, 0x21, 0x21, 0x21, 0x21, 0x56, ++ 0x37, 0x2B, 0x21, 0x21, 0x21, 0x21, 0x56, 0x3E, ++ 0x36, 0x2A, 0x59, 0x23, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x33, 0x50, 0x3D, ++ 0x42, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x40, 0x5A, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x56, 0x49, 0x24, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x42, 0x54, 0x33, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4D, 0x59, ++ 0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, 0x4A, ++ 0x51, 0x21, 0x21, 0x33, 0x47, 0x47, 0x33, 0x21, ++ 0x21, 0x21, 0x21, 0x55, 0x27, 0x3B, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x32, 0x4B, ++ 0x4C, 0x21, 0x21, 0x21, 0x21, 0x21, 0x34, 0x44, ++ 0x3F, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x33, 0x4C, 0x3C, 0x51, 0x57, 0x5C, 0x38, 0x38, ++ 0x9D, 0xCA, 0x61, 0xCB, 0xCC, 0xCD, 0xC4, 0xC8, ++ 0xA4, 0x9C, 0x76, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, ++ 0x7A, 0x7F, 0x41, 0x29, 0x47, 0x38, 0x40, 0x57, ++ 0x32, 0x51, 0x42, 0x2B, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x57, 0x49, 0x32, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x57, 0x27, ++ 0x35, 0x21, 0x21, 0x21, 0x2B, 0x59, 0x2A, 0x21, ++ 0x21, 0x21, 0x21, 0x56, 0x54, 0x2B, 0x21, 0x21, ++ 0x21, 0x21, 0x4C, 0x2E, 0x5A, 0x23, 0x55, 0x5B, ++ 0x49, 0x3A, 0x22, 0x21, 0x21, 0x21, 0x21, 0x32, ++ 0x3E, 0x3B, 0x21, 0x21, 0x21, 0x35, 0x54, 0x53, ++ 0x23, 0x55, 0x4F, 0x55, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x25, 0x44, 0x42, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x23, 0x41, 0x46, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x23, 0x53, 0x2F, 0x2A, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x32, 0x28, 0x33, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, 0x59, 0x5B, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x54, ++ 0x57, 0x21, 0x35, 0x53, 0x47, 0x23, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x3C, 0x44, 0x3B, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x41, 0x43, ++ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3F, 0x29, ++ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x55, 0x4C, 0x3F, 0x2A, 0x46, 0x31, 0x36, 0x46, ++ 0x71, 0x97, 0xCE, 0xCB, 0xCF, 0xA4, 0x9C, 0xA4, ++ 0xAD, 0x76, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0x8C, ++ 0x7A, 0xA7, 0x36, 0x50, 0x3A, 0x36, 0x38, 0x52, ++ 0x32, 0x2A, 0x3F, 0x2B, 0x22, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x22, 0x5A, 0x5A, 0x23, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x28, ++ 0x35, 0x21, 0x21, 0x21, 0x55, 0x30, 0x56, 0x21, ++ 0x21, 0x21, 0x21, 0x22, 0x5B, 0x45, 0x21, 0x21, ++ 0x21, 0x21, 0x2B, 0x2E, 0x25, 0x47, 0x3D, 0x2D, ++ 0x25, 0x4C, 0x21, 0x21, 0x21, 0x21, 0x21, 0x39, ++ 0x44, 0x55, 0x21, 0x21, 0x21, 0x46, 0x59, 0x3B, ++ 0x21, 0x23, 0x30, 0x34, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x2A, 0x28, 0x4E, 0x42, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x3C, 0x3D, 0x42, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x51, 0x4B, 0x49, 0x39, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x5C, 0x25, 0x23, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x38, 0x4B, 0x3B, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x54, ++ 0x56, 0x21, 0x5B, 0x3A, 0x35, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x51, 0x59, 0x55, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x32, 0x2D, 0x42, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4C, 0x3A, ++ 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x2B, 0x3C, 0x39, 0x56, 0x46, 0x40, 0x36, 0xB6, ++ 0x73, 0x82, 0xCB, 0xD0, 0x75, 0xD1, 0xD2, 0xD1, ++ 0x8C, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x74, 0xCE, ++ 0x9E, 0x6E, 0xD3, 0xC6, 0x6F, 0x81, 0x38, 0x5C, ++ 0x52, 0x58, 0x39, 0x4C, 0x35, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x4C, 0x4A, 0x40, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x3A, ++ 0x21, 0x21, 0x21, 0x21, 0x55, 0x27, 0x3F, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x25, 0x3B, 0x21, ++ 0x21, 0x21, 0x42, 0x2E, 0x2D, 0x2D, 0x26, 0x46, ++ 0x35, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x51, ++ 0x44, 0x55, 0x21, 0x21, 0x35, 0x25, 0x40, 0x21, ++ 0x21, 0x22, 0x4E, 0x58, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x39, 0x59, 0x38, 0x35, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x56, 0x59, 0x23, 0x21, 0x21, 0x21, ++ 0x21, 0x4C, 0x54, 0x5B, 0x59, 0x4C, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x57, 0x3A, 0x22, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x22, 0x4D, 0x49, 0x26, 0x23, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x53, ++ 0x32, 0x51, 0x27, 0x42, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x42, 0x25, 0x35, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x22, 0x24, 0x37, 0x3E, 0x35, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x48, ++ 0x48, 0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33, ++ 0x3B, 0x39, 0x3F, 0x32, 0x5C, 0x38, 0x47, 0xD4, ++ 0x7A, 0xC7, 0xCB, 0xD0, 0x74, 0x80, 0x8C, 0x9F, ++ 0x80, 0x79, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x73, 0x72, 0xD5, 0xCA, 0x61, 0xD3, 0x40, 0x5C, ++ 0x46, 0x58, 0x51, 0x42, 0x33, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x39, 0x4B, 0x58, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x2A, 0x3D, 0x51, ++ 0x21, 0x21, 0x21, 0x21, 0x55, 0x28, 0x42, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x47, 0x52, 0x21, ++ 0x21, 0x21, 0x58, 0x59, 0x42, 0x3C, 0x35, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x57, ++ 0x4E, 0x23, 0x21, 0x22, 0x4D, 0x54, 0x35, 0x21, ++ 0x21, 0x21, 0x5A, 0x46, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x22, 0x56, 0x59, 0x36, 0x35, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x36, 0x5B, 0x21, 0x21, 0x21, 0x21, ++ 0x23, 0x53, 0x48, 0x3F, 0x27, 0x55, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x24, 0x47, 0x22, 0x21, 0x21, ++ 0x21, 0x21, 0x22, 0x40, 0x27, 0x29, 0x29, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x47, ++ 0x40, 0x41, 0x5C, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x39, 0x41, 0x23, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x32, 0x26, 0x47, 0x28, 0x22, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B, ++ 0x53, 0x28, 0x36, 0x42, 0x23, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, ++ 0x4C, 0x39, 0x58, 0x32, 0x31, 0x38, 0x47, 0xD4, ++ 0xCF, 0xD0, 0x6C, 0x9E, 0xD6, 0x6B, 0xD7, 0xD8, ++ 0xD7, 0x6B, 0xCF, 0x7B, 0x80, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x74, 0x72, 0xD0, 0xA6, 0x70, 0x51, ++ 0x46, 0x56, 0x51, 0x42, 0x55, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x5C, 0x27, 0x35, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x32, 0x37, 0x54, 0x33, ++ 0x21, 0x21, 0x21, 0x21, 0x2B, 0x44, 0x2A, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x2C, 0x21, ++ 0x21, 0x21, 0x47, 0x36, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, ++ 0x54, 0x23, 0x21, 0x24, 0x4F, 0x46, 0x21, 0x21, ++ 0x21, 0x21, 0x38, 0x2C, 0x22, 0x21, 0x21, 0x21, ++ 0x21, 0x42, 0x55, 0x21, 0x21, 0x21, 0x21, 0x33, ++ 0x45, 0x54, 0x56, 0x22, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x22, 0x53, 0x24, 0x21, 0x21, 0x21, 0x21, ++ 0x46, 0x5D, 0x4C, 0x52, 0x4E, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x31, 0x48, 0x22, 0x21, 0x21, ++ 0x21, 0x22, 0x46, 0x54, 0x3B, 0x45, 0x29, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x47, ++ 0x28, 0x28, 0x55, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x51, 0x41, 0x22, 0x21, 0x21, ++ 0x21, 0x21, 0x56, 0x54, 0x39, 0x56, 0x28, 0x22, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x23, 0x34, 0x50, 0x30, 0x4E, 0x40, 0x34, 0x22, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, ++ 0x4C, 0x39, 0x58, 0x52, 0x5C, 0x38, 0x47, 0x9D, ++ 0xC9, 0xD9, 0xDA, 0xDB, 0xDC, 0xDC, 0xDC, 0xDC, ++ 0xDC, 0xDC, 0xDC, 0xDD, 0x6B, 0x7B, 0x75, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x74, 0x71, 0xD0, 0x3F, ++ 0x52, 0x57, 0x2A, 0x42, 0x2B, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x47, 0x3A, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x35, 0x45, 0x4A, 0x2C, 0x3B, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x2B, 0x30, 0x56, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x58, 0x29, 0x21, ++ 0x21, 0x21, 0x53, 0x3F, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x31, ++ 0x43, 0x22, 0x3B, 0x28, 0x48, 0x22, 0x21, 0x21, ++ 0x21, 0x21, 0x56, 0x25, 0x35, 0x21, 0x21, 0x21, ++ 0x39, 0x54, 0x34, 0x21, 0x21, 0x21, 0x35, 0x3A, ++ 0x30, 0x57, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x33, 0x39, 0x21, 0x21, ++ 0x21, 0x35, 0x25, 0x3F, 0x21, 0x21, 0x21, 0x56, ++ 0x30, 0x58, 0x21, 0x24, 0x43, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x4D, 0x29, 0x22, 0x21, 0x21, ++ 0x22, 0x32, 0x26, 0x42, 0x21, 0x46, 0x2C, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x48, ++ 0x2E, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x56, 0x28, 0x35, 0x21, 0x21, ++ 0x21, 0x3F, 0x27, 0x32, 0x21, 0x51, 0x25, 0x22, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x22, 0x39, 0x38, 0x25, 0x54, 0x50, ++ 0x58, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33, ++ 0x4C, 0x3F, 0x56, 0x52, 0x31, 0x4D, 0x47, 0x39, ++ 0xD8, 0xDC, 0xDC, 0xDC, 0xDE, 0xDF, 0xDF, 0xDF, ++ 0xDF, 0xDF, 0xDE, 0xDE, 0xDC, 0xDD, 0xD6, 0x97, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x75, 0x97, 0x56, ++ 0x46, 0x57, 0x2A, 0x42, 0x2B, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x38, 0x29, 0x22, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x35, 0x5B, 0x3D, 0x40, 0x35, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x2B, 0x59, 0x3F, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x40, 0x5A, 0x21, ++ 0x21, 0x22, 0x5D, 0x34, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x5B, ++ 0x2C, 0x33, 0x29, 0x28, 0x3B, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x34, 0x59, 0x3C, 0x21, 0x21, 0x2B, ++ 0x53, 0x36, 0x22, 0x21, 0x21, 0x34, 0x5A, 0x28, ++ 0x3F, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x40, 0x41, 0x23, 0x21, ++ 0x21, 0x3B, 0x28, 0x2B, 0x21, 0x21, 0x2A, 0x44, ++ 0x38, 0x22, 0x21, 0x24, 0x50, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x50, 0x25, 0x23, 0x21, 0x23, ++ 0x45, 0x5D, 0x52, 0x21, 0x21, 0x40, 0x50, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x50, ++ 0x2D, 0x39, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x46, 0x30, 0x33, 0x21, 0x22, ++ 0x24, 0x4E, 0x45, 0x22, 0x21, 0x58, 0x25, 0x22, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x33, 0x3C, 0x48, ++ 0x27, 0x39, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, ++ 0x34, 0x3F, 0x58, 0x57, 0x31, 0x4D, 0x47, 0x56, ++ 0xDB, 0xDC, 0xDE, 0xE0, 0xE1, 0xE2, 0xE2, 0xE2, ++ 0xE2, 0xE2, 0xE1, 0xE3, 0xE4, 0xDE, 0xDC, 0x6B, ++ 0x8C, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0xA7, 0x38, ++ 0x46, 0x56, 0x2A, 0x39, 0x3B, 0x23, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x32, 0x44, 0x34, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x3F, ++ 0x4D, 0x41, 0x29, 0x42, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x2B, 0x44, 0x46, 0x34, ++ 0x2B, 0x55, 0x55, 0x2B, 0x56, 0x59, 0x36, 0x21, ++ 0x21, 0x22, 0x59, 0x2B, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x55, 0x5C, 0x21, 0x21, 0x21, 0x40, ++ 0x50, 0x4D, 0x4F, 0x32, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x55, 0x44, 0x31, 0x22, 0x3B, 0x5A, ++ 0x41, 0x55, 0x21, 0x35, 0x57, 0x4A, 0x2E, 0x48, ++ 0x57, 0x32, 0x3F, 0x55, 0x35, 0x22, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x25, 0x47, 0x22, 0x21, ++ 0x21, 0x4C, 0x28, 0x35, 0x21, 0x34, 0x30, 0x3A, ++ 0x23, 0x21, 0x21, 0x58, 0x3A, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x4D, 0x4E, 0x35, 0x33, 0x48, ++ 0x44, 0x56, 0x21, 0x21, 0x21, 0x58, 0x41, 0x23, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x29, ++ 0x4A, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x32, 0x44, 0x2B, 0x23, 0x45, ++ 0x3D, 0x31, 0x22, 0x21, 0x21, 0x4C, 0x27, 0x35, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, ++ 0x53, 0x53, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, ++ 0x34, 0x3F, 0x58, 0x57, 0x40, 0x38, 0x47, 0xD4, ++ 0xDC, 0xDE, 0xE0, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE2, 0xE1, 0xDF, 0xDC, ++ 0xE6, 0x8C, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0x2A, 0x40, ++ 0x46, 0x58, 0x2A, 0x42, 0x34, 0x34, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x2B, 0x54, 0x5A, 0x34, 0x23, ++ 0x35, 0x23, 0x35, 0x33, 0x2B, 0x24, 0x54, 0x4B, ++ 0x59, 0x5C, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x4B, 0x44, 0x59, ++ 0x27, 0x26, 0x26, 0x4A, 0x3E, 0x41, 0x55, 0x21, ++ 0x21, 0x22, 0x41, 0x39, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x34, 0x53, 0x4D, 0x21, 0x21, 0x21, 0x5C, ++ 0x4B, 0x4F, 0x40, 0x22, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x48, 0x30, 0x50, 0x26, 0x54, ++ 0x34, 0x21, 0x55, 0x4E, 0x2D, 0x2F, 0x4F, 0x37, ++ 0x3E, 0x4B, 0x4B, 0x30, 0x27, 0x53, 0x2C, 0x57, ++ 0x42, 0x4C, 0x55, 0x22, 0x22, 0x22, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x39, 0x4A, 0x3F, 0x21, 0x21, ++ 0x21, 0x55, 0x53, 0x55, 0x2A, 0x26, 0x54, 0x33, ++ 0x21, 0x21, 0x21, 0x51, 0x54, 0x3B, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x51, 0x3D, 0x46, 0x5A, 0x4F, ++ 0x52, 0x21, 0x21, 0x21, 0x21, 0x22, 0x27, 0x31, ++ 0x33, 0x23, 0x42, 0x4C, 0x21, 0x21, 0x21, 0x5B, ++ 0x54, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x3B, 0x44, 0x45, 0x48, 0x4B, ++ 0x38, 0x22, 0x21, 0x21, 0x21, 0x21, 0x53, 0x48, ++ 0x33, 0x23, 0x34, 0x3C, 0x22, 0x57, 0x4D, 0x33, ++ 0x21, 0x21, 0x21, 0x21, 0x22, 0x23, 0x34, 0x40, ++ 0x44, 0x31, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, ++ 0x3B, 0x42, 0x2A, 0x57, 0x31, 0x38, 0x5C, 0xD8, ++ 0xDC, 0xE4, 0xE2, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE2, 0xE0, ++ 0xDE, 0xCA, 0x9F, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x80, 0x76, 0x57, 0x5C, ++ 0x31, 0x6E, 0x34, 0x3C, 0xC9, 0x3B, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x33, 0x5B, 0x30, 0x25, ++ 0x5D, 0x5A, 0x53, 0x27, 0x26, 0x59, 0x36, 0x56, ++ 0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x3D, 0x2A, 0x55, ++ 0x42, 0x51, 0x56, 0x24, 0x2A, 0x35, 0x21, 0x21, ++ 0x21, 0x21, 0x45, 0x53, 0x3B, 0x22, 0x22, 0x35, ++ 0x46, 0x59, 0x54, 0x55, 0x21, 0x21, 0x21, 0x31, ++ 0x2D, 0x47, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x33, 0x50, 0x5D, 0x45, 0x55, ++ 0x21, 0x21, 0x34, 0x4F, 0x29, 0x58, 0x33, 0x4C, ++ 0x39, 0x3C, 0x2A, 0x40, 0x48, 0x54, 0x3D, 0x3D, ++ 0x37, 0x4A, 0x59, 0x29, 0x5B, 0x36, 0x52, 0x2A, ++ 0x42, 0x3C, 0x32, 0x30, 0x41, 0x35, 0x21, 0x21, ++ 0x21, 0x33, 0x41, 0x26, 0x4B, 0x5A, 0x35, 0x21, ++ 0x21, 0x21, 0x21, 0x3C, 0x3E, 0x41, 0x23, 0x21, ++ 0x21, 0x21, 0x21, 0x23, 0x41, 0x49, 0x30, 0x32, ++ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x4F, ++ 0x5D, 0x41, 0x27, 0x58, 0x21, 0x21, 0x21, 0x5B, ++ 0x41, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x47, 0x49, 0x4F, 0x5C, ++ 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x39, 0x4A, ++ 0x28, 0x43, 0x27, 0x5C, 0x35, 0x25, 0x49, 0x5B, ++ 0x58, 0x52, 0x5C, 0x38, 0x48, 0x41, 0x4A, 0x4B, ++ 0x50, 0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, ++ 0x3B, 0x3C, 0x2A, 0x32, 0x5C, 0x40, 0x32, 0xDD, ++ 0xDC, 0xE3, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE1, 0xE0, 0xBB, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x80, 0xE7, 0x58, 0x52, ++ 0x5C, 0x67, 0xE7, 0x6C, 0xE8, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x23, 0x39, 0x5C, ++ 0x29, 0x5A, 0x4D, 0x5C, 0x2A, 0x2B, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x44, 0x42, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x33, 0x27, 0x30, 0x5A, 0x2C, 0x25, ++ 0x4B, 0x50, 0x3B, 0x21, 0x21, 0x21, 0x21, 0x33, ++ 0x2C, 0x3B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x4C, 0x22, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x55, 0x2B, ++ 0x39, 0x32, 0x4D, 0x29, 0x26, 0x3D, 0x2D, 0x2D, ++ 0x4B, 0x4B, 0x2F, 0x30, 0x42, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x3B, 0x29, 0x2C, 0x55, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x23, 0x50, 0x4D, 0x22, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x2B, 0x32, 0x3B, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x51, ++ 0x48, 0x45, 0x34, 0x21, 0x21, 0x21, 0x21, 0x38, ++ 0x44, 0x35, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x33, 0x32, 0x34, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3C, ++ 0x5B, 0x4D, 0x42, 0x21, 0x21, 0x34, 0x4D, 0x47, ++ 0x5A, 0x5D, 0x27, 0x4E, 0x25, 0x3A, 0x5C, 0x42, ++ 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, ++ 0x2B, 0x34, 0x51, 0x56, 0x46, 0x40, 0xE9, 0xDA, ++ 0xDD, 0xE1, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE2, 0xEA, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x76, 0xD3, 0x67, 0x39, ++ 0x3C, 0xCF, 0xD5, 0x9F, 0x3B, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x28, 0x2B, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x3C, 0x53, 0x44, 0x3D, 0x43, ++ 0x57, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x35, 0x55, 0x3F, 0x2A, ++ 0x57, 0x24, 0x3F, 0x3B, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x22, 0x22, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x55, ++ 0x3C, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x55, 0x4C, 0x3F, 0x58, 0x46, 0x31, 0x8B, 0xAD, ++ 0xCC, 0xE2, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xEA, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x97, 0x35, 0x6E, 0xC6, 0x82, ++ 0xA6, 0x73, 0x75, 0xBA, 0x2B, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x34, 0x44, 0x3B, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x23, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x33, 0x34, 0xEB, 0x34, 0x57, 0x5C, 0x4C, 0xA4, ++ 0xEC, 0x64, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0x83, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x80, 0xED, 0xCF, 0xCE, 0x78, 0x78, ++ 0x78, 0x7A, 0x6D, 0x34, 0x22, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x55, 0x25, 0x55, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x23, 0x34, 0xEE, 0xEF, 0x5F, 0x96, 0x23, 0xB3, ++ 0xBF, 0xB5, 0xF0, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xBB, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x9F, 0x78, 0x78, 0x78, 0x78, ++ 0x80, 0x9F, 0x65, 0x33, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x28, 0x55, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x22, 0x4C, 0xF1, 0xA5, 0xAC, 0xAB, 0x60, 0xB3, ++ 0xB3, 0xF2, 0xEA, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xF3, 0x6D, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x80, 0x61, 0x34, 0x23, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x3B, 0x25, 0x22, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B, 0x5E, ++ 0x4C, 0x3B, 0xF4, 0xA5, 0x9B, 0x9B, 0xB4, 0xEF, ++ 0xEF, 0xBF, 0xAD, 0xF5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0x67, 0x75, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x80, ++ 0xA7, 0x3F, 0x55, 0x22, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x4E, 0x23, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B, 0x5F, ++ 0x9B, 0xD2, 0x3C, 0xB7, 0xEF, 0xEF, 0xEF, 0xEF, ++ 0xEF, 0xB3, 0xB8, 0xEA, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0xF0, 0xBB, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0x82, ++ 0x34, 0x3B, 0x33, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x5D, 0x23, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x60, ++ 0xAB, 0xA5, 0xB8, 0xB1, 0xEF, 0xEF, 0xEF, 0xEF, ++ 0xEF, 0xF6, 0xB7, 0xB5, 0xF0, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, ++ 0x67, 0x80, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x78, 0x80, 0x9F, 0xBA, 0x42, ++ 0x4C, 0x2B, 0x22, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x3A, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x55, ++ 0xF2, 0x9B, 0x9B, 0xB4, 0xEF, 0xEF, 0xEF, 0xEF, ++ 0xEF, 0xEF, 0xB4, 0x5F, 0x63, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xF5, ++ 0x76, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x78, 0x78, 0x80, 0x6D, 0x65, 0x3C, 0x34, ++ 0x3B, 0x35, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x2A, 0x29, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, ++ 0xF7, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, ++ 0xEF, 0xEF, 0xB3, 0xB8, 0xEA, 0xE5, 0xE5, 0xE5, ++ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xF8, 0x68, ++ 0x7A, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x78, 0x80, 0x97, 0x82, 0x39, 0x39, 0x34, 0x3B, ++ 0x33, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x2A, 0x29, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x3B, 0xB8, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, ++ 0xEF, 0xEF, 0xF6, 0xB2, 0xF9, 0xFA, 0xFA, 0xFA, ++ 0xFA, 0xF8, 0xF8, 0xF8, 0xF0, 0xF0, 0x6F, 0x97, ++ 0x80, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, ++ 0x8C, 0x61, 0x39, 0x2A, 0x3F, 0x3C, 0x4C, 0x55, ++ 0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x4C, 0x31, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x22, 0xFB, 0xF6, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, ++ 0xEF, 0xEF, 0xB3, 0xB2, 0xF9, 0xF3, 0xF3, 0xF3, ++ 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0x90, 0x6D, 0x97, ++ 0x8C, 0x6D, 0x76, 0xBB, 0xC6, 0xB9, 0xC0, 0xFC, ++ 0xAD, 0xFB, 0x2A, 0x58, 0x42, 0x4C, 0x55, 0x33, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x33, 0xD2, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, ++ 0xEF, 0xEF, 0xB4, 0xB8, 0xEB, 0xE8, 0x7F, 0xD6, ++ 0xD6, 0xD6, 0xD6, 0x9D, 0x9D, 0x52, 0xEB, 0x5F, ++ 0x5F, 0x5F, 0xF2, 0xA4, 0xBF, 0xBF, 0xB4, 0xBF, ++ 0xEE, 0x56, 0x2A, 0x42, 0x4C, 0x2B, 0x33, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x4C, 0xBE, 0xF6, 0xEF, 0xEF, 0xEF, ++ 0xF6, 0xB4, 0xB2, 0xF1, 0x3C, 0x56, 0x46, 0x5C, ++ 0x31, 0x38, 0x40, 0x40, 0x4D, 0x4D, 0xB8, 0xAC, ++ 0xBF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xB4, ++ 0xB1, 0x39, 0x39, 0x3B, 0x2B, 0x23, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x3B, 0xAD, 0xA4, 0xBF, 0xBF, ++ 0xB7, 0xB2, 0xEE, 0x5E, 0x39, 0x51, 0x2A, 0x32, ++ 0x52, 0x46, 0x5C, 0x31, 0x31, 0x2A, 0xA5, 0xEF, ++ 0xFD, 0xB4, 0xEF, 0xF6, 0xF6, 0xEF, 0xF6, 0xB2, ++ 0x3F, 0x34, 0x2B, 0x55, 0x23, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x33, 0xEB, 0xF7, 0xAA, ++ 0xAA, 0xF7, 0xEB, 0x55, 0x3B, 0x3C, 0x39, 0x51, ++ 0x2A, 0x56, 0x32, 0x57, 0x57, 0x2A, 0x96, 0x3C, ++ 0x2A, 0xEE, 0xEF, 0x5F, 0xD2, 0xEF, 0xB4, 0xAA, ++ 0x42, 0x55, 0x35, 0x22, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x3B, ++ 0x3B, 0x35, 0x21, 0x23, 0x33, 0x3B, 0x4C, 0x3C, ++ 0x39, 0x3F, 0x51, 0x2A, 0x51, 0x51, 0x58, 0x32, ++ 0x56, 0xF4, 0xB1, 0x42, 0x3C, 0xF2, 0x9C, 0x3F, ++ 0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x33, 0x55, ++ 0x3B, 0x4C, 0x4C, 0x3C, 0x42, 0x42, 0x3C, 0x34, ++ 0x34, 0x3F, 0x4C, 0x3B, 0x4C, 0x3B, 0x3C, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x35, 0x33, 0x55, 0x33, 0x33, 0x33, 0x55, 0x2B, ++ 0x2B, 0x35, 0x35, 0x35, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, ++ 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 + }; + + #endif /* !__HAVE_ARCH_LINUX_LOGO */ +@@ -994,7 +1760,7 @@ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + #endif /* !__HAVE_ARCH_LINUX_LOGOBW */ +@@ -1401,7 +2167,7 @@ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + #endif /* !__HAVE_ARCH_LINUX_LOGO16 */ diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/mkdep.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/mkdep.patch index e69de29bb2..4daeaa11be 100644 --- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/mkdep.patch +++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/mkdep.patch @@ -0,0 +1,16 @@ + +# +# Made by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux/Makefile~mkdep 2003-12-19 09:36:51.000000000 -0800 ++++ linux/Makefile 2003-12-19 09:57:44.000000000 -0800 +@@ -458,7 +458,7 @@ + + dep-files: scripts/mkdep archdep include/linux/version.h + scripts/mkdep -- init/*.c > .depend +- scripts/mkdep -- `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend ++ $(foreach, dir, $(FINDHPATH), scripts/mkdep -- `find $(dir) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` >> .hdepend) + $(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)" + ifdef CONFIG_MODVERSIONS + $(MAKE) update-modverfile diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/sound-2.4.18r2.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/sound-2.4.18r2.patch index e69de29bb2..867774aab8 100644 --- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/sound-2.4.18r2.patch +++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/sound-2.4.18r2.patch @@ -0,0 +1,5602 @@ +diff -Nuar linux-2.4.18/arch/arm/mach-sa1100/m62332.c linux-2.4.18p/arch/arm/mach-sa1100/m62332.c +--- linux-2.4.18/arch/arm/mach-sa1100/m62332.c 2003-05-13 11:18:14.000000000 +0200 ++++ linux-2.4.18p/arch/arm/mach-sa1100/m62332.c 2004-10-12 22:36:36.000000000 +0200 +@@ -131,3 +131,5 @@ + + return 0; + } ++EXPORT_SYMBOL(m62332_senddata); ++ +diff -Nuar linux-2.4.18/arch/arm/mach-sa1100/Makefile linux-2.4.18p/arch/arm/mach-sa1100/Makefile +--- linux-2.4.18/arch/arm/mach-sa1100/Makefile 2003-05-13 11:18:14.000000000 +0200 ++++ linux-2.4.18p/arch/arm/mach-sa1100/Makefile 2004-10-12 22:36:19.000000000 +0200 +@@ -18,7 +18,7 @@ + export-objs := assabet.o consus.o badge4.o dma-sa1100.o dma-sa1111.o \ + flexanet.o freebird.o generic.o h3600.o \ + huw_webpanel.o irq.o pcipool.o sa1111.o sa1111-pcibuf.o \ +- system3.o yopy.o usb_ctl.o usb_recv.o usb_send.o ++ system3.o yopy.o usb_ctl.o usb_recv.o usb_send.o m62332.o + + # These aren't present yet, and prevents a plain -ac kernel building. + # hwtimer.o +@@ -36,7 +36,7 @@ + obj-$(CONFIG_SA1100_LART) += cpu-sa1100.o + endif + +-obj-$(CONFIG_SA1100_COLLIE) += collie.o m62332.o collie_battery.o collie_led.o collie_buzzer.o ++obj-$(CONFIG_SA1100_COLLIE) += collie.o m62332.o collie_battery.o collie_led.o + + # Next, the SA1111 stuff. + obj-$(CONFIG_SA1111) += sa1111.o dma-sa1111.o +diff -Nuar linux-2.4.18/drivers/char/Makefile linux-2.4.18p/drivers/char/Makefile +--- linux-2.4.18/drivers/char/Makefile 2003-05-13 11:18:18.000000000 +0200 ++++ linux-2.4.18p/drivers/char/Makefile 2004-10-12 17:26:44.000000000 +0200 +@@ -228,7 +228,7 @@ + obj-y += joystick/js.o + endif + +-obj-$(CONFIG_SA1100_COLLIE) += sharp_led.o sharp_kbdctl.o sharp_buzzer.o ++obj-$(CONFIG_SA1100_COLLIE) += sharp_led.o sharp_kbdctl.o + obj-$(CONFIG_DISCOVERY_LED) += sharp_led.o discovery_led.o + obj-$(CONFIG_ARCH_PXA_POODLE) += sharp_led.o sharp_kbdctl.o sharpsl_led.o sharp_buzzer.o + obj-$(CONFIG_ARCH_PXA_CORGI) += sharp_led.o sharpsl_led.o sharp_kbdctl.o corgi_rc.o sharp_buzzer.o +diff -Nuar linux-2.4.18/drivers/sound/colliebuzzer.h linux-2.4.18p/drivers/sound/colliebuzzer.h +--- linux-2.4.18/drivers/sound/colliebuzzer.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.18p/drivers/sound/colliebuzzer.h 2004-10-13 15:24:51.028208808 +0200 +@@ -0,0 +1,756 @@ ++unsigned short tap_data[] = { ++ 0x0000 , 0xff00 , 0xff00 , 0x0000 , ++ 0xff00 , 0x0000 , 0x0000 , 0x0100 , ++ 0x0000 , 0x0100 , 0x0000 , 0x0100 , ++ 0x0100 , 0x0000 , 0x0100 , 0x0100 , ++ 0x0100 , 0x0100 , 0x0100 , 0x0100 , ++ 0x0100 , 0x0100 , 0x0100 , 0x0100 , ++ 0x0100 , 0x0000 , 0x0100 , 0x0000 , ++ 0x0100 , 0xff00 , 0x0100 , 0x0000 , ++ 0x0100 , 0x0000 , 0x0000 , 0x0100 , ++ 0x0000 , 0x0100 , 0x0000 , 0x0100 , ++ 0x0000 , 0x0000 , 0x0000 , 0x0000 , ++ 0x0000 , 0x0100 , 0x0000 , 0x0100 , ++ 0x0000 , 0x0100 , 0x0700 , 0x1c00 , ++ 0xc800 , 0xd900 , 0x2b00 , 0x2700 , ++ 0xbf00 , 0xe000 , 0x0d00 , 0x1000 , ++ 0xf500 , 0xd700 , 0x0100 , 0x0a00 , ++ 0xfb00 , 0xfa00 , 0x2200 , 0x0100 , ++ 0xeb00 , 0x0300 , 0x0600 , 0x1600 , ++ 0xe500 , 0xf500 , 0x0d00 , 0x0a00 , ++ 0x0100 , 0xfb00 , 0x0000 , 0x0100 , ++ 0xf200 , 0x0400 , 0x0600 , 0x0000 , ++ 0xf100 , 0x0300 , 0x1200 , 0xfe00 , ++ 0xe900 , 0x0400 , 0x0100 , 0x0d00 , ++ 0xf500 , 0x0100 , 0x0100 , 0xfe00 , ++ 0x0100 , 0xfb00 , 0x0400 , 0xff00 , ++ 0xf700 , 0x0400 , 0x0000 , 0xfe00 , ++ 0x0200 , 0x0000 , 0x0100 , 0xfd00 , ++ 0x0000 , 0xff00 , 0x0200 , 0x0000 , ++ 0xff00 , 0x0000 , 0x0200 , 0xfc00 , ++ 0xfe00 , 0xff00 , 0x0100 , 0x0200 , ++ 0x0000 , 0xff00 , 0xfc00 , 0x0100 , ++ 0x0100 , 0x0100 , 0xff00 , 0x0000 , ++ 0x0300 , 0xfe00 , 0xfe00 , 0x0200 , ++ 0xff00 , 0x0000 , 0x0000 , 0xfe00 , ++ 0x0000 , 0xff00 , 0x0000 , 0x0000 , ++ 0x0000 , 0xff00 , 0x0000 , 0x0000 , ++ 0xff00 , 0xfe00 , 0xfd00 , 0x0100 , ++ 0x0000 , 0xfe00 , 0xff00 , 0xff00 , ++ 0x0000 , 0xff00 , 0x0100 , 0xfe00 , ++ 0xff00 , 0xff00 , 0x0000 , 0x0000 , ++ 0xfe00 , 0xff00 , 0x0100 , 0x0100 , ++ 0xff00 , 0x0100 , 0x0100 , 0xfe00 , ++ 0x0000 , 0x0000 , 0x0000 , 0x0100 , ++ 0x0000 , 0x0000 , 0xff00 , 0x0000 , ++ 0x0100 , 0x0000 , 0x0200 }; ++ ++ ++unsigned short click_data[] = { ++ 0x0100 , 0x0100 , 0x0100 , 0x0000 , ++ 0x0100 , 0xff00 , 0x0100 , 0x0000 , ++ 0xff00 , 0xff00 , 0xff00 , 0x0000 , ++ 0xff00 , 0xff00 , 0xff00 , 0xff00 , ++ 0xff00 , 0xff00 , 0x0000 , 0xff00 , ++ 0xff00 , 0xff00 , 0x0000 , 0xff00 , ++ 0xff00 , 0xff00 , 0xff00 , 0x0100 , ++ 0x0000 , 0xff00 , 0xfe00 , 0x0100 , ++ 0xff00 , 0x0100 , 0xff00 , 0x0100 , ++ 0x0100 , 0x0300 , 0xff00 , 0xff00 , ++ 0xff00 , 0x0100 , 0x0100 , 0x0000 , ++ 0xfe00 , 0xfe00 , 0xfe00 , 0xfc00 , ++ 0xfe00 , 0x0100 , 0xfd00 , 0xff00 , ++ 0xff00 , 0xfc00 , 0xfe00 , 0xfd00 , ++ 0x0100 , 0xfe00 , 0x0100 , 0xf800 , ++ 0xfe00 , 0xfe00 , 0xfc00 , 0xe600 , ++ 0xdb00 , 0x2500 , 0xdb00 , 0xee00 , ++ 0xdb00 , 0x0600 , 0xeb00 , 0x1f00 , ++ 0x1e00 , 0xeb00 , 0xfe00 , 0x0000 , ++ 0xff00 , 0x1900 , 0xef00 , 0xf700 , ++ 0x2100 , 0xe400 , 0x0100 , 0x0600 , ++ 0xff00 , 0x0300 , 0xf900 , 0x0f00 , ++ 0xf600 , 0x0100 , 0xfe00 , 0xf900 , ++ 0x0500 , 0xf500 , 0x0600 , 0xfb00 , ++ 0x0800 , 0x0100 , 0x0300 , 0x0100 , ++ 0xf700 , 0xfa00 , 0xfd00 , 0xfc00 , ++ 0x0800 , 0xfb00 , 0x0500 , 0xfe00 , ++ 0xfc00 , 0xfc00 , 0xfe00 , 0x0400 , ++ 0xff00 , 0xff00 , 0x0500 , 0x0100 , ++ 0xfc00 , 0xff00 , 0xfe00 , 0xfb00 , ++ 0x0200 , 0x0200 , 0xff00 , 0xfe00 , ++ 0xfe00 , 0x0600 , 0xfb00 , 0xff00 , ++ 0xfc00 , 0x0600 , 0xfb00 , 0xff00 , ++ 0xff00 , 0x0100 , 0xff00 , 0x0200 , ++ 0xff00 , 0xfb00 , 0xff00 , 0x0200 , ++ 0xff00 , 0x0200 , 0x0100 , 0xfe00 , ++ 0xfe00 , 0x0100 , 0xfd00 , 0x0200 , ++ 0xfc00 , 0x0800 , 0xfe00 , 0xfe00 , ++ 0x0400 , 0xfc00 , 0xff00 , 0xfc00 , ++ 0x0500 , 0x0200 , 0x0800 , 0x0200 , ++ 0x0100 , 0xfe00 , 0x0100 , 0xff00 , ++ 0x0700 , 0xfb00 , 0xfc00 , 0x0100 , ++ 0xfe00 , 0xfc00 , 0x0b00 , 0xfb00 , ++ 0xfb00 , 0x0700 , 0xfb00 , 0xfb00 , ++ 0x0100 , 0xff00 , 0xfb00 , 0xfd00 , ++ 0x0000 , 0xfe00 , 0xfe00 , 0xff00 , ++ 0xfc00 , 0x0400 , 0x0000 , 0xfe00 , ++ 0xff00 , 0x0200 , 0xff00 , 0x0000 , ++ 0x0500 , 0x0100 , 0x0100 , 0x0100 , ++ 0x0100 , 0x0000 , 0x0300 , 0xfe00 , ++ 0xff00 , 0x0100 , 0x0100 , 0xfe00 , ++ 0x0000 , 0xff00 , 0x0100 , 0xff00 , ++ 0x0200 , 0xff00 , 0xff00 , 0xff00 , ++ 0xff00 , 0xfe00 , 0x0000 , 0xff00 , ++ 0xfe00 , 0xff00 , 0xfd00 , 0x0000 , ++ 0xff00 , 0xfe00 , 0xff00 , 0xfc00 , ++ 0x0100 , 0xfd00 , 0xff00 , 0xff00 , ++ 0x0200 , 0xff00 , 0x0100 , 0xff00 , ++ 0xfc00 , 0x0300 , 0xff00 , 0x0200 , ++ 0xff00 , 0x0100 , 0xff00 , 0x0100 , ++ 0xff00 , 0xff00 , 0x0100 , 0xfe00 , ++ 0x0300 , 0xfc00 , 0x0100 , 0xff00 , ++ 0x0100 , 0x0100 , 0x0100 , 0xfc00 , ++ 0xff00 , 0x0100 , 0x0100 , 0xfe00 , ++ 0x0100 , 0xff00 , 0x0100 , 0xfc00 , ++ 0x0100 , 0x0200 , 0xff00 , 0x0100 , ++ 0xff00 , 0xff00 , 0x0200 , 0xfd00 , ++ 0xfe00 , 0x0100 , 0xff00 , 0x0100 , ++ 0xfe00 , 0x0100 , 0x0300 , 0xfe00 , ++ 0x0300 , 0xfe00 , 0xff00 , 0x0100 , ++ 0xff00 , 0x0200 , 0xfd00 , 0x0000 , ++ 0xff00 , 0x0200 , 0xff00 , 0x0200 , ++ 0xff00 , 0x0100 , 0x0000 , 0xff00 , ++ 0x0200 , 0x0100 , 0x0000 , 0xff00 , ++ 0x0100 , 0xfe00 , 0x0200 , 0xfe00 , ++ 0xfe00 , 0x0100 , 0xfe00 , 0x0100 , ++ 0xfd00 , 0xff00 , 0xff00 , 0xfe00 , ++ 0xff00 , 0xfc00 , 0x0100 , 0xfe00 , ++ 0x0100 , 0xff00 , 0xfe00 , 0xff00 , ++ 0xff00 , 0xfe00 , 0x0100 , 0xfe00 , ++ 0x0100 , 0xff00 , 0x0100 , 0xfe00 , ++ 0xff00 , 0x0200 , 0xfe00 , 0x0000 , ++ 0x0100 , 0x0200 , 0xff00 , 0x0200 , ++ 0xff00 , 0x0000 , 0x0100 , 0x0100 , ++ 0xff00 , 0x0200 , 0xfe00 , 0xff00 , ++ 0xff00 , 0xff00 , 0x0100 , 0x0000 , ++ 0xff00 , 0x0100 , 0xff00 , 0x0000 , ++ 0x0100 , 0xff00 , 0xfe00 , 0xff00 , ++ 0xff00 , 0x0100 , 0xff00 , 0x0100 , ++ 0xfe00 , 0xff00 , 0xff00 , 0xff00 , ++ 0xfe00 , 0xff00 , 0xff00 , 0x0100 , ++ 0xff00 , 0x0200 , 0xff00 , 0x0100 , ++ 0xff00 , 0xff00 }; ++ ++ ++unsigned short alarm_data[] = { ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8 ++ 0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5 ++ ++}; ++ ++ ++ ++ ++ ++#define SHARP_BUZ_TOUCHSOUND 1 ++#define SHARP_BUZ_KEYSOUND 2 ++#define SHARP_BUZ_ALARM 11 ++#define SHARP_BUZZER_MAKESOUND 0x5680 ++ ++static int collie_ct_s16_buzzer(const u_char *userPtr, size_t userCount, ++ u_char frame[], ssize_t *frameUsed, ++ ssize_t frameLeft) ++{ ++ ssize_t count, used; ++ signed short *fp = (unsigned short *) &frame[*frameUsed]; ++ signed short *up = (unsigned short *) userPtr; ++ ++ DPRINTK("Collie_ct_s16 begin\n"); ++ ++ used = count = (userCount < frameLeft) ? userCount/2 : frameLeft/4; ++ ++ DPRINTK("Collie_ct_s16 begin count %d \n",count); ++ ++ while (count > 0) { ++ *fp++ = *up; ++ *fp++ = *up++; ++ count--; ++ } ++ ++ *frameUsed+=used*4; ++ DPRINTK("Collie_ct_s16 exit\n"); ++ return used*2; ++} ++ ++ ++static ssize_t sq_write_buzzer(int soundid) ++{ ++ const char * src; ++ audio_stream_t *s = &output_stream; ++ u_char *dest; ++ ssize_t uUsed, bUsed, bLeft, uLeft, ret = 0; ++ ++ ++ if ((collie_tc_status!=NA) && (collie_tc_status!=PLAY)) ++ return -EPERM; ++ ++ collie_tc_status=PLAY; ++ ++ if (!s->buffers && sq_allocate_buffers(s)) { ++ return -ENOMEM; ++ } ++ ++ ++#ifdef CONFIG_PM ++ /* Auto Power off cancel */ ++// autoPowerCancel = 0; ++#endif ++ DPRINTK("sq_write_buzzer: id:%d\n", soundid); ++ ++ switch (soundid) { ++ case SHARP_BUZ_TOUCHSOUND: ++ src=tap_data; ++ uLeft=176*2; ++ break; ++ case SHARP_BUZ_KEYSOUND: ++ src=click_data; ++ uLeft=360*2; ++ break; ++ case SHARP_BUZ_ALARM: ++ src=alarm_data; ++ uLeft=3072*2; ++ break; ++ default: ++ return 0; ++ } ++ DPRINTK("sq_write_buzzer: uLeft=%d\n", uLeft); ++ ++ collie_tc_mute_off(); ++ while (uLeft > 0) { ++ audio_buf_t *b = s->buf; ++ ++ ret = -ERESTARTSYS; ++ if (down_interruptible(&b->sem)) { ++ break; ++ } ++ ++ dest = b->start + b->size; ++ bUsed = 0; ++ bLeft = s->fragsize - b->size; ++ uUsed = collie_ct_s16_buzzer(src, uLeft, dest, &bUsed, bLeft); ++ cpu_cache_clean_invalidate_range((unsigned long)dest, ++ (unsigned long)(dest+(audio_fragsize)), 0); ++ ++ DPRINTK("back to sq_write_buzzer %p\n",dest); ++ ++ if (uUsed < 0) { ++ up(&b->sem); ++ return -EFAULT; ++ } ++ src += uUsed; ++ uLeft -= uUsed; ++ b->size += bUsed; ++ ++ if (b->size < s->fragsize) { ++ up(&b->sem); ++ break; ++ } ++ ++ /* Send current buffer to dma */ ++ sa1100_dma_queue_buffer(COLLIE_BUZZER_DMA_CHANNEL, ++ (void *) b, b->dma_addr, b->size); ++ ++ Collie_volume_set(50); ++ ++ b->size = 0; /* indicate that the buffer has been sent */ ++ NEXT_BUF(s, buf); ++ } ++ ++ DPRINTK("sq_write_buzzer: return\n"); ++ return ret; ++} ++ ++ ++ ++ ++ ++ ++ +diff -Nuar linux-2.4.18/drivers/sound/collie_ssp.c linux-2.4.18p/drivers/sound/collie_ssp.c +--- linux-2.4.18/drivers/sound/collie_ssp.c 2003-05-13 11:18:37.000000000 +0200 ++++ linux-2.4.18p/drivers/sound/collie_ssp.c 2004-10-13 15:05:36.000000000 +0200 +@@ -9,6 +9,7 @@ + * I/F : Synchronous serial port (SSP) TI mode + * + * Copyright (C) 2001 SHARP ++ * p.nis/dolOps messed around with it too! + * + * 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 +@@ -24,7 +25,18 @@ + * 23-Oct-2001 SHARP + * tune hardware control method + * 12-Nov-2001 Lineo Japan, Inc. +- * 14-Feb-2003 Sharp Corporation 8bit , GETOSPACE ++ * ++ * 26-Dec-2002 getospace added, some unneeded things removed ++ * ++ * 28-Dec-2002 cut out old stuff, reorder stuff ++ * ++ * 04-Jan-2003 put in getospace from lineo's collie-tc35143.c ++ * also added collie_record_on off, and exported these symbols ++ * ++ * 06-Jan-2003 if mixer ioctl SOUND_MIXER_READ_DEVMASK returns 0 as mask, ++ * than the headphone(/mic) is not connected ++ * ++ * + */ + #include <linux/module.h> + #include <linux/sched.h> +@@ -35,7 +47,7 @@ + #include <linux/fcntl.h> + #include <linux/errno.h> + #include <linux/mm.h> +-#include <linux/malloc.h> ++#include <linux/slab.h> + #include <linux/sound.h> + #include <linux/init.h> + #include <linux/delay.h> +@@ -48,38 +60,30 @@ + #include <asm/uaccess.h> + #include <asm/io.h> + #include <asm/dma.h> +-#include <asm/ucb1200.h> + + #include <linux/soundcard.h> + #include <asm/proc/cache.h> + +-#include <asm/arch/gpio.h> ++#include <asm/arch/hardware.h> + #include <asm/arch/m62332.h> + #include <asm/arch/tc35143.h> + + #undef DEBUG +-//#define DEBUG + #ifdef DEBUG + #define DPRINTK( x... ) printk( ##x ) + #else + #define DPRINTK( x... ) + #endif + +-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0) || \ +- defined(CONFIG_COLLIE_TR1) || defined(CONFIG_COLLIE_DEV) +-#define COLLIE_TRY_ONE +-#else +-#undef COLLIE_TRY_ONE +-#endif ++#define COLLIE_TRY_ONE + + #ifdef COLLIE_TRY_ONE + #ifndef GPIO_REMOCON_ADC_SW + #define GPIO_REMOCON_ADC_SW GPIO_GPIO(18) + #endif + ++static int collie_rc_irq; + static DECLARE_WAIT_QUEUE_HEAD(audio_on); +- +- + static inline void collie_rc_set_int_mode(void) + { + GPSR = GPIO_REMOCON_ADC_SW; +@@ -91,14 +95,12 @@ + } + #endif + +- + int collie_dmasound_irq = -1; +-#define COLLIE_SOUND_DMA_CHANNEL (collie_dmasound_irq) + ++#define COLLIE_SOUND_DMA_CHANNEL (collie_dmasound_irq) + #define SND_NDEVS 256 /* Number of supported devices */ + #define SND_DEV_CTL 0 /* Control port /dev/mixer */ +-#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM +- synthesizer and MIDI output) */ ++#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM synthesizer and MIDI output) */ + #define SND_DEV_MIDIN 2 /* Raw midi access */ + #define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */ + #define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */ +@@ -121,142 +123,25 @@ + #endif + + /*** Some declarations ***********************************************/ +-#define DMASND_TT 1 +-#define DMASND_FALCON 2 +-#define DMASND_AMIGA 3 +-#define DMASND_AWACS 4 +-#define DMASND_IRIS 5 +-#define DMASND_COLLIE 6 + +-#define COLLIE_WAIT_AMP_ON 1 /* 10ms */ ++ + #define COLLIE_WAIT_LCM_ACC_XEN 50 /* 500ms */ +-#ifdef MODULE +-static int catchRadius = 0; +-#endif ++ + static int collie_amp_init = 0; + static int collie_dac_init = 0; +-static int collie_op_shdn_on = 0; + static int collie_resume = 0; + static int collie_hard_mute = 1; + static int collie_soft_mute = 1; + static int collie_volume = 0; ++int collie_recording=0; ++static int playing=0; ++static int headphone; + +-int collie_buzzer_volume = 0; +- +-#if 1 +-static DECLARE_WAIT_QUEUE_HEAD(open_queue); ++#define AUDIO_NBFRAGS_DEFAULT 64 ++#define AUDIO_FRAGSIZE_DEFAULT 4096 + +-#define SIGNAL_RECEIVED (signal_pending(current)) +-#define ONE_SECOND HZ /* in jiffies (100ths of a second) */ +-#define SLEEP(queue, time_limit) \ +- interruptible_sleep_on_timeout((wait_queue_head_t*)&queue, (time_limit)); +-#define WAKE_UP(queue) (wake_up_interruptible((wait_queue_head_t*)&queue)) +-#endif +- +-#define AUDIO_NBFRAGS_DEFAULT 8 +-#define AUDIO_FRAGSIZE_DEFAULT 8192 +- +- +-#define TRACE 0 +-#if TRACE +-#define TRACE_ON 1 +-#define TRACE_SEM 0 +-#define TRACE_SENDDATA 0 +-#define TRACE_PM 1 +-#define TRACE_AMP 1 +-#define TRACE_DAC 1 +-#define TRACE_OP_SHDN 1 +-#define TRACE_WRITE 1 +-#define TRACE_MUTE 1 +-#define TRACE_CLOCK 1 +-#define TRACE_PAIF 1 +-#define TRACE_SSP 1 +-#define TRACE_VOLUME 1 +-#define TRACE_MIC 1 +-#define TRACE_INTERRUPT 0 +-int cLevel = 0; +-char *pLevel[16] = { +- /* 0 */"", +- /* 1 */" ", +- /* 2 */" ", +- /* 3 */" ", +- /* 4 */" ", +- /* 5 */" ", +- /* 6 */" ", +- /* 7 */" ", +- /* 8 */" ", +- /* 9 */" ", +- /* 10 */" ", +- /* 11 */" ", +- /* 12 */" ", +- /* 13 */" ", +- /* 14 */" ", +- /* 15 */" " +-}; +-char * +-indent(int level) +-{ +- int i; +- return (level < 16 ) ? pLevel[level] : pLevel[15]; +-} +- +-#define P_ID (current->tgid) +-#define ENTER(f,fn) {if(f)printk("%d:%s+[%d]%s\n",jiffies,indent(cLevel),P_ID,(fn));cLevel++;} +-#define LEAVE(f,fn) {cLevel--;if(f>1)printk("%d:%s-[%d]%s\n",jiffies,indent(cLevel),P_ID,(fn));} +-#else /* ! TRACE */ +-#define ENTER(f,fn) +-#define LEAVE(f,fn) +-#endif /* end TRACE */ + +-/* +- * DAC power management +- */ +-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0) || \ +- defined(CONFIG_COLLIE_TR1) || defined(CONFIG_COLLIE_DEV) +-#define DAC_OFF_WITH_DEVICE_OFF 1 +-#undef HARD_MUTE_CTRL_DISABLE +-#else +-#undef DAC_OFF_WITH_DEVICE_OFF + #undef HARD_MUTE_CTRL_DISABLE +-#endif +- +- +-#define TRY_DELAY_OFF +-#ifdef TRY_DELAY_OFF /* H.Hayami SHARP 2001.12.19 */ +-static DECLARE_WAIT_QUEUE_HEAD(delay_off); +-struct semaphore df_sem; +-/* +- * delay execution +- */ +-static unsigned int DelayedFlag = 0; +-#define DELAY_DAC_OFF 0x1 +-#define DELAY_HARD_MUTE_ON 0x2 +- +-static inline void ResetDelayAll(void) +-{ +- DelayedFlag = 0; +-} +- +-static inline int isDelayedExist(void) +-{ +- return DelayedFlag; +-} +- +-static inline void SetDelay(unsigned int flag) +-{ +- DelayedFlag |= flag; +-} +- +-static inline void ResetDelay(unsigned int flag) +-{ +- DelayedFlag &= ~flag; +-} +- +-static inline unsigned int isDelayed(unsigned int flag) +-{ +- return DelayedFlag & flag; +-} +-#endif + + /* + * Buffer Management +@@ -268,6 +153,7 @@ + dma_addr_t dma_addr; /* physical buffer address */ + struct semaphore sem; /* down before touching the buffer */ + int master; /* master owner for buffer allocation */ ++ u_int idx; /* buffer index, so that we know which buffer was sent last*/ + } audio_buf_t; + + typedef struct { +@@ -291,16 +177,6 @@ + + static volatile int audio_wr_refcount; /* nbr of concurrent open() for playback */ + +-static ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL; +- +-#ifdef MODULE +-MODULE_PARM(catchRadius, "i"); +-#endif +-MODULE_PARM(numBufs, "i"); +-MODULE_PARM(bufSize, "i"); +- +-#define min(x, y) ((x) < (y) ? (x) : (y)) +- + #define IOCTL_IN(arg, ret) \ + do { int error = get_user(ret, (int *)(arg)); \ + if (error) return error; \ +@@ -310,11 +186,7 @@ + /* + * SA1110 GPIO (17) + */ +-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0) +-#define COLLIE_GPIO_OPSHDN GPIO_GPIO (17) /* AMP contorol */ +-#else /* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */ + #define COLLIE_GPIO_MIC GPIO_GPIO (17) /* MIC contorol */ +-#endif /* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */ + + /* + * DAC setup data +@@ -352,122 +224,11 @@ + ( LCM_ACC_XSEL1 | LCM_ACC_CLKSEL101 ) , + }; + ++/*** "Translations" ************************************************************/ + +-/* 16 bit mu-law */ +- +-static short ulaw2dma16[] = { +- -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, +- -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, +- -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412, +- -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, +- -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, +- -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, +- -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, +- -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, +- -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, +- -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, +- -876, -844, -812, -780, -748, -716, -684, -652, +- -620, -588, -556, -524, -492, -460, -428, -396, +- -372, -356, -340, -324, -308, -292, -276, -260, +- -244, -228, -212, -196, -180, -164, -148, -132, +- -120, -112, -104, -96, -88, -80, -72, -64, +- -56, -48, -40, -32, -24, -16, -8, 0, +- 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, +- 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, +- 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, +- 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, +- 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, +- 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, +- 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, +- 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, +- 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, +- 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, +- 876, 844, 812, 780, 748, 716, 684, 652, +- 620, 588, 556, 524, 492, 460, 428, 396, +- 372, 356, 340, 324, 308, 292, 276, 260, +- 244, 228, 212, 196, 180, 164, 148, 132, +- 120, 112, 104, 96, 88, 80, 72, 64, +- 56, 48, 40, 32, 24, 16, 8, 0, +-}; +- +-/* 16 bit A-law */ +- +-static short alaw2dma16[] = { +- -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, +- -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, +- -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, +- -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, +- -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, +- -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, +- -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, +- -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, +- -344, -328, -376, -360, -280, -264, -312, -296, +- -472, -456, -504, -488, -408, -392, -440, -424, +- -88, -72, -120, -104, -24, -8, -56, -40, +- -216, -200, -248, -232, -152, -136, -184, -168, +- -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, +- -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, +- -688, -656, -752, -720, -560, -528, -624, -592, +- -944, -912, -1008, -976, -816, -784, -880, -848, +- 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, +- 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, +- 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, +- 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, +- 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, +- 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, +- 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, +- 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, +- 344, 328, 376, 360, 280, 264, 312, 296, +- 472, 456, 504, 488, 408, 392, 440, 424, +- 88, 72, 120, 104, 24, 8, 56, 40, +- 216, 200, 248, 232, 152, 136, 184, 168, +- 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, +- 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, +- 688, 656, 752, 720, 560, 528, 624, 592, +- 944, 912, 1008, 976, 816, 784, 880, 848, +-}; +- +- +- +-/*** Translations ************************************************************/ +- +-static ssize_t collie_ct_law(const u_char *userPtr, size_t userCount, +- u_char frame[], ssize_t *frameUsed, +- ssize_t frameLeft); +-static ssize_t collie_ct_s8(const u_char *userPtr, size_t userCount, +- u_char frame[], ssize_t *frameUsed, +- ssize_t frameLeft); +-static ssize_t collie_ct_u8(const u_char *userPtr, size_t userCount, +- u_char frame[], ssize_t *frameUsed, +- ssize_t frameLeft); + static ssize_t collie_ct_s16(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft); +-static ssize_t collie_ct_u16(const u_char *userPtr, size_t userCount, +- u_char frame[], ssize_t *frameUsed, +- ssize_t frameLeft); +- +-/*** Machine definitions *****************************************************/ +- +- +-typedef struct { +- int type; +- void *(*dma_alloc)(unsigned int, int); +- void (*dma_free)(void *, unsigned int); +- int (*irqinit)(void); +-#ifdef MODULE +- void (*irqcleanup)(void); +-#endif /* MODULE */ +- void (*init)(void); +- void (*silence)(void); +- int (*setFormat)(int); +- int (*setVolume)(int); +- int (*setBass)(int); +- int (*setTreble)(int); +- int (*setGain)(int); +- void (*play)(void); +-} MACHINE; +- + + /*** Low level stuff *********************************************************/ + +@@ -477,71 +238,28 @@ + int stereo; /* 0 = mono, 1 = stereo */ + int size; /* 8/16 bit*/ + int speed; /* speed */ ++ int volume; + } SETTINGS; + +-typedef struct { +- ssize_t (*ct_ulaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); +- ssize_t (*ct_alaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); +- ssize_t (*ct_s8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); +- ssize_t (*ct_u8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); +- ssize_t (*ct_s16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); +- ssize_t (*ct_u16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); +- ssize_t (*ct_s16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); +- ssize_t (*ct_u16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t); +-} TRANS; +- +-struct sound_settings { +- MACHINE mach; /* machine dependent things */ +- SETTINGS hard; /* hardware settings */ +- SETTINGS soft; /* software settings */ +- SETTINGS dsp; /* /dev/dsp default settings */ +- TRANS *trans; /* supported translations */ +- int volume_left; /* volume (range is machine dependent) */ +- int volume_right; +- int bass; /* tone (range is machine dependent) */ +- int treble; +- int gain; +- int minDev; /* minor device number currently open */ +-}; +- +-static struct sound_settings sound; ++static SETTINGS sound; + + #ifdef CONFIG_PM +-extern int autoPowerCancel; ++//extern int autoPowerCancel; + #endif +-int collie_main_volume; +-extern int collie_under_recording; /* collie_buzzer.c */ +-#define COLLE_RECORDING (collie_under_recording) + + static void Collie_Set_Volume(int volume); + static int Collie_Get_Volume(void); +-static void Collie_disable_sound(void); +-#ifdef CONFIG_PM +-#if 0 +-static void Collie_clock_stop(void); +-static void Collie_FS8KLPF_stop(void); +-#endif +-#endif + static int CollieIrqInit(void); + static int CollieGetSamp(void); +-static void Collie_OP_SHDN_on(void); +-static void Collie_OP_SHDN_off(void); +-static void Collie_FS8KLPF_start(void); +-#ifdef MODULE +-static void CollieIrqCleanUp(void); +-#endif /* MODULE */ +-static void CollieSilence(void); + static void Collie_DAC_sendword(int); +-static void CollieInit(void); + static int CollieSetFormat(int format); + static void Collie_sq_interrupt(void*, int); + static int sq_allocate_buffers(audio_stream_t*); + static void sq_release_buffers(audio_stream_t*); ++static inline void Collie_volume_init(void); ++static void Collie_volume_set(int); + + /*** Mid level stuff *********************************************************/ +-static void sound_silence(void); +-static void sound_init(void); +-static int sound_set_format(int format); + static int sound_set_speed(int speed); + static int sound_set_stereo(int stereo); + +@@ -572,468 +290,122 @@ + static long long sound_lseek(struct file *file, long long offset, int orig); + static inline int ioctl_return(int *addr, int value) + { +- ENTER(TRACE_ON,"ioctl_return"); + if (value < 0) { +- LEAVE(TRACE_ON,"ioctl_return"); + return(value); + } +- +- LEAVE(TRACE_ON,"ioctl_return"); + return put_user(value, addr)? -EFAULT: 0; + } + +- +-/*** Config & Setup **********************************************************/ +- +- +-void dmasound_init(void); +-void dmasound_setup(char *str, int *ints); +- +- +-/*** Translations ************************************************************/ +- +- +-/* ++TeSche: radically changed for new expanding purposes... +- * +- * These two routines now deal with copying/expanding/translating the samples +- * from user space into our buffer at the right frequency. They take care about +- * how much data there's actually to read, how much buffer space there is and +- * to convert samples into the right frequency/encoding. They will only work on +- * complete samples so it may happen they leave some bytes in the input stream +- * if the user didn't write a multiple of the current sample size. They both +- * return the number of bytes they've used from both streams so you may detect +- * such a situation. Luckily all programs should be able to cope with that. +- * +- * I think I've optimized anything as far as one can do in plain C, all +- * variables should fit in registers and the loops are really short. There's +- * one loop for every possible situation. Writing a more generalized and thus +- * parameterized loop would only produce slower code. Feel free to optimize +- * this in assembler if you like. :) +- * +- * I think these routines belong here because they're not yet really hardware +- * independent, especially the fact that the Falcon can play 16bit samples +- * only in stereo is hardcoded in both of them! +- * +- * ++geert: split in even more functions (one per format) +- */ +- +-static ssize_t collie_ct_law(const u_char *userPtr, size_t userCount, +- u_char frame[], ssize_t *frameUsed, +- ssize_t frameLeft) +-{ +- short *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16; +- ssize_t count, used; +- short *p = (short *) &frame[*frameUsed]; +- int val, stereo = sound.soft.stereo; +- +- ENTER(TRACE_ON,"collie_ct_law"); +- frameLeft >>= 2; +- if (stereo) +- userCount >>= 1; +- used = count = min(userCount, frameLeft); +- if (!COLLE_RECORDING) { +- while (count > 0) { +- u_char data; +- if (get_user(data, userPtr++)) { +- LEAVE(TRACE_ON,"collie_ct_law"); +- return -EFAULT; +- } +- val = table[data]; +- *p++ = val; /* Left Ch. */ +- if (stereo) { +- if (get_user(data, userPtr++)) { +- LEAVE(TRACE_ON,"collie_ct_law"); +- return -EFAULT; +- } +- val = table[data]; +- } +- *p++ = val; /* Right Ch. */ +- count--; +- } +- } else { +- while (count > 0) { +- u_char data; +- int ave; +- if (get_user(data, userPtr++)) { +- LEAVE(TRACE_ON,"collie_ct_law"); +- return -EFAULT; +- } +- val = table[data]; +- ave = val; /* Left Ch. */ +- if (stereo) { +- if (get_user(data, userPtr++)) { +- LEAVE(TRACE_ON,"collie_ct_law"); +- return -EFAULT; +- } +- val = table[data]; +- } +- ave += val; /* Right Ch. */ +- ave >>= 1; +- *p++ = 0; /* Left Ch. */ +- *p++ = ave; /* Right Ch. */ +- count--; +- } +- } +- *frameUsed += used * 4; +- LEAVE(TRACE_ON,"collie_ct_law"); +- return stereo? used * 2: used; +-} +- +- +-static ssize_t collie_ct_s8(const u_char *userPtr, size_t userCount, +- u_char frame[], ssize_t *frameUsed, +- ssize_t frameLeft) +-{ +- ssize_t count, used; +- short *p = (short *) &frame[*frameUsed]; +- int stereo = sound.soft.stereo; +- short val; +- +- ENTER(TRACE_ON,"collie_ct_s8"); +- frameLeft >>= 2; +- if (stereo) +- userCount >>= 1; +- used = count = min(userCount, frameLeft); +- if (!COLLE_RECORDING) { +- while (count > 0) { +- u_char data; +- +- if (get_user(data, userPtr++)) { +- LEAVE(TRACE_ON,"collie_ct_s8"); +- return -EFAULT; +- } +- val = ( data - 0x80 ) << 8; +- *p++ = val; /* Left Ch. */ +- if ( stereo ) { +- if ( get_user(data, userPtr++)) { +- LEAVE(TRACE_ON,"collie_ct_s8"); +- return -EFAULT; +- } +- val = ( data - 0x80 ) << 8; +- } +- *p++ = val; /* Right Ch. */ +- count--; +- } +- } else { +- while (count > 0) { +- u_char data; +- int ave; +- +- if (get_user(data, userPtr++)) { +- LEAVE(TRACE_ON,"collie_ct_s8"); +- return -EFAULT; +- } +- val = ( data - 0x80 ) << 8; +- ave = val; /* Left Ch. */ +- if ( stereo ) { +- if ( get_user(data, userPtr++)) { +- LEAVE(TRACE_ON,"collie_ct_s8"); +- return -EFAULT; +- } +- val = ( data - 0x80 ) << 8; +- } +- ave += val; /* Right Ch. */ +- ave >>= 1; +- *p++ = 0; /* Left Ch. */ +- *p++ = ave; /* Right Ch. */ +- count--; +- } +- } +- *frameUsed += used * 4; +- LEAVE(TRACE_ON,"collie_ct_s8"); +- return stereo? used * 2: used; +-} +- +- +-static ssize_t collie_ct_u8(const u_char *userPtr, size_t userCount, +- u_char frame[], ssize_t *frameUsed, +- ssize_t frameLeft) ++static void wait_ms(int ten_ms) + { +- ssize_t count, used; +- short *p = (short *) &frame[*frameUsed]; +- int stereo = sound.soft.stereo; +- short val; +- +- ENTER(TRACE_ON,"collie_ct_u8"); +- frameLeft >>= 2; +- if (stereo) +- userCount >>= 1; +- used = count = min(userCount, frameLeft); +- if (!COLLE_RECORDING) { +- while (count > 0) { +- u_char data; +- +- if (get_user(data, userPtr++)) { +- LEAVE(TRACE_ON,"collie_ct_u8"); +- return -EFAULT; +- } +- val = data; +- *p++ = (val ^ 0x80) << 8; /* Left Ch. */ +- if ( stereo ) { +- if ( get_user(data, userPtr++)) { +- LEAVE(TRACE_ON,"collie_ct_u8"); +- return -EFAULT; +- } +- val = data; +- } +- *p++ = (val ^ 0x80) << 8; /* Right Ch. */ +- count--; +- } +- } else { +- while (count > 0) { +- u_char data; +- int ave; +- +- if (get_user(data, userPtr++)) { +- LEAVE(TRACE_ON,"collie_ct_u8"); +- return -EFAULT; +- } +- val = data; +- ave = (val ^ 0x80) << 8; /* Left Ch. */ +- if ( stereo ) { +- if ( get_user(data, userPtr++)) { +- LEAVE(TRACE_ON,"collie_ct_u8"); +- return -EFAULT; +- } +- val = data; +- } +- ave += (val ^ 0x80) << 8; /* Right Ch. */ +- ave >>= 1; +- *p++ = 0; /* Left Ch. */ +- *p++ = ave; /* Right Ch. */ +- count--; +- } +- } +- *frameUsed += used * 4; +- LEAVE(TRACE_ON,"collie_ct_u8"); +- return stereo? used * 2: used; ++ schedule_timeout(ten_ms); + } + ++/*** Translation ************************************************************/ + + static ssize_t collie_ct_s16(const u_char *userPtr, size_t userCount, + u_char frame[], ssize_t *frameUsed, + ssize_t frameLeft) + { + ssize_t count, used; +- int stereo = sound.soft.stereo; + short *fp = (short *) &frame[*frameUsed]; ++ short *up = (short *) userPtr; + +- ENTER(TRACE_ON,"collie_ct_s16"); + frameLeft >>= 2; +- userCount >>= (stereo? 2: 1); +- used = count = min(userCount, frameLeft); +- if (!stereo) { +- short *up = (short *) userPtr; +- while (count > 0) { +- short data; +- if (get_user(data, up++)) { +- LEAVE(TRACE_ON,"collie_ct_s16"); +- return -EFAULT; +- } +- *fp++ = (!COLLE_RECORDING) ? data : 0; /* Left Ch. */ +- *fp++ = data; +- count--; ++ userCount >>= 2; ++ used = count = (userCount < frameLeft) ? userCount : frameLeft; ++ ++ while (count > 0) { ++ ++ short data; ++ if (get_user(data, up++)) { ++ return -EFAULT; + } +- } else { +- short *up = (short *) userPtr; +- while (count > 0) { +- short data; +- short temp; +- if (get_user(data, up++)) { +- LEAVE(TRACE_ON,"collie_ct_s16"); +- return -EFAULT; +- } +- if (get_user(temp, up++)) { +- LEAVE(TRACE_ON,"collie_ct_s16"); +- return -EFAULT; +- } +- if (!COLLE_RECORDING) { +- *fp++ = data; /* Left Ch. */ +- *fp++ = temp; /* Right Ch. */ +- } else { +- data >>= 1; +- data += (temp >> 1); +- *fp++ = 0; /* Left Ch. */ +- *fp++ = data; /* Right Ch. */ +- } +- count--; ++ if (!collie_recording) *fp++ = data; ++ else *fp++=0; ++ ++ if (get_user(data, up++)) { ++ return -EFAULT; + } ++ *fp++ = data; ++ count--; + } ++ + *frameUsed += used * 4; +- LEAVE(TRACE_ON,"collie_ct_s16"); +- return stereo? used * 4: used * 2; ++ return used * 4; + } + +-static ssize_t collie_ct_u16(const u_char *userPtr, size_t userCount, +- u_char frame[], ssize_t *frameUsed, +- ssize_t frameLeft) +-{ +- ssize_t count, used; +- int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000); +- int stereo = sound.soft.stereo; +- short *fp = (short *) &frame[*frameUsed]; +- short *up = (short *) userPtr; ++/*** HARDWARE dependent stuff *********************************************************/ + +- ENTER(TRACE_ON,"collie_ct_u16"); +- frameLeft >>= 2; +- userCount >>= (stereo? 2: 1); +- used = count = min(userCount, frameLeft); +- if (!COLLE_RECORDING) { +- while (count > 0) { +- int data; +- int temp; +- if (get_user(data, up++)) { +- LEAVE(TRACE_ON,"collie_ct_u16"); +- return -EFAULT; +- } +- data ^= mask; +- *fp++ = data; /* Left Ch. */ +- if (stereo) { +- if (get_user(temp, up++)) { +- LEAVE(TRACE_ON,"collie_ct_u16"); +- return -EFAULT; +- } +- temp ^= mask; +- data = temp; +- data ^= mask; +- } +- *fp++ = data; /* Right Ch. */ +- count--; +- } ++static inline void Collie_DAC_sendbit(int bit_data) ++{ ++ if (bit_data & 1) { ++ LCM_GPO |= (LCM_GPIO_DAC_SDATA); + } else { +- while (count > 0) { +- int data; +- int temp; +- int ave; +- if (get_user(data, up++)) { +- LEAVE(TRACE_ON,"collie_ct_u16"); +- return -EFAULT; +- } +- data ^= mask; +- ave = data; /* Left Ch. */ +- if (stereo) { +- if (get_user(temp, up++)) { +- LEAVE(TRACE_ON,"collie_ct_u16"); +- return -EFAULT; +- } +- temp ^= mask; +- data = temp; +- data ^= mask; +- } +- ave += data; +- ave >>= 1; +- *fp++ = 0; /* Left Ch. */ +- *fp++ = ave; /* Right Ch. */ +- count--; +- } ++ LCM_GPO &= ~(LCM_GPIO_DAC_SDATA); + } +- *frameUsed += used * 4; +- LEAVE(TRACE_ON,"collie_ct_u16"); +- return stereo? used * 4: used * 2; +-} + +-static TRANS transCollie = { +- collie_ct_law, collie_ct_law, collie_ct_s8, collie_ct_u8, +- collie_ct_s16, collie_ct_u16, collie_ct_s16, collie_ct_u16 +-}; ++ udelay(1); ++ LCM_GPO |= (LCM_GPIO_DAC_SCK); + +-/*** Low level stuff *********************************************************/ ++ udelay(1); ++ LCM_GPO &= ~(LCM_GPIO_DAC_SCK); ++ udelay(1); ++ LCM_GPO &= ~(LCM_GPIO_DAC_SDATA); ++ udelay(1); ++} + +-static void Collie_Set_Volume(int volume) ++static void Collie_DAC_sendword(int data) + { +- ENTER(TRACE_ON,"Collie_Set_Volume"); +- +- sound.volume_left = volume & 0xff; +- if ( sound.volume_left > 100 ) sound.volume_left = 100; +- +- collie_main_volume = sound.volume_left; +- +- sound.volume_right = ( volume & 0xff00 >> 8); +- if ( sound.volume_right > 100 ) sound.volume_right = 100; +- LEAVE(TRACE_ON,"Collie_Set_Volume"); ++ int i; + +- collie_buzzer_volume = sound.volume_right; ++#if defined(CONFIG_COLLIE_PCM1741) ++ ++ LCM_GPO &= ~(LCM_GPIO_DAC_SCK); ++ udelay(1); ++ LCM_GPO |= (LCM_GPIO_DAC_SLOAD); ++ udelay(1); + +-} ++ for (i = 0; i < 16; i++) ++ Collie_DAC_sendbit(data >> (15 - i)); + ++ LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD); ++ udelay(2); + +-static int Collie_Get_Volume(void) +-{ +- ENTER(TRACE_ON,"Collie_Get_Volume"); +- LEAVE(TRACE_ON,"Collie_Get_Volume"); +- return ( sound.volume_right << 8 | sound.volume_left ); +-} ++#elif defined(CONFIG_COLLIE_PCM1717) ++ ++ LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD); ++ udelay(1000); ++ LCM_GPO |= (LCM_GPIO_DAC_SLOAD); ++ udelay(1000); ++ LCM_GPO &= ~(LCM_GPIO_DAC_SCK); ++ udelay(1000); + +-static void wait_ms(int ten_ms) +-{ +- ENTER(TRACE_ON,"wait_ms"); +- LEAVE(TRACE_ON,"wait_ms"); +- schedule_timeout(ten_ms); +-} ++ for (i = 0; i < 16; i++) ++ Collie_DAC_sendbit(data >> (15 - i)); + +-static inline void Collie_AMP_off(void) +-{ +-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0) +- ENTER(TRACE_AMP,"Collie_AMP_off"); +-#if 0 /* OBSOLETED: power controled by only OP_SHDN */ +- /* Set up TC35143 GPIO I/O Direction (GPIO4 output mode) */ +- ucb1200_set_io_direction(TC35143_GPIO_AMP_ON, +- TC35143_IODIR_OUTPUT); +- /* AMP OFF */ +- ucb1200_set_io(TC35143_GPIO_AMP_ON, +- TC35143_IODAT_LOW); +- collie_amp_init = 0; +-#endif /* 0 */ +- LEAVE(TRACE_AMP,"Collie_AMP_off"); +-#endif /* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */ +-} +- +-static inline void Collie_AMP_on(void) +-{ +-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0) +- ENTER(TRACE_AMP,"Collie_AMP_on"); +-// if (!collie_amp_init) { +- /* Set up TC35143 GPIO I/O Direction (GPIO4 output mode) */ +- ucb1200_set_io_direction(TC35143_GPIO_AMP_ON, +- TC35143_IODIR_OUTPUT); +- /* AMP ON */ +- ucb1200_set_io(TC35143_GPIO_AMP_ON, TC35143_IODAT_HIGH); +- SCP_REG_GPWR |= SCP_AMP_ON; +- wait_ms(COLLIE_WAIT_AMP_ON); +- collie_amp_init = 1; +-// } +- LEAVE(TRACE_AMP,"Collie_AMP_on"); +-#endif /* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */ ++ LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD); ++ udelay(1000); ++ LCM_GPO |= (LCM_GPIO_DAC_SLOAD); ++ udelay(1000); ++ LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD); ++ udelay(1000); ++#endif + } + +-static inline void Collie_AMP_init(void) +-{ +-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0) +- ENTER(TRACE_AMP,"Collie_AMP_init"); +- Collie_AMP_off(); +- LEAVE(TRACE_AMP,"Collie_AMP_init"); +-#endif /* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */ +-} + + static inline void Collie_DAC_off(void) + { +- ENTER(TRACE_DAC,"Collie_DAC_off"); +- if (!COLLE_RECORDING) { +- /* DAC OFF */ +- LCM_GPD &= ~(LCM_GPIO_DAC_ON); /* set up output */ +- LCM_GPO &= ~(LCM_GPIO_DAC_ON); +- +- /* LoCoMo GPIO disable */ +- LCM_GPE &= ~(LCM_GPIO_DAC_ON); +- collie_dac_init = 0; +- } +- LEAVE(TRACE_DAC,"Collie_DAC_off"); ++ /* DAC OFF */ ++ LCM_GPD &= ~(LCM_GPIO_DAC_ON); /* set up output */ ++ LCM_GPO &= ~(LCM_GPIO_DAC_ON); ++ /* LoCoMo GPIO disable */ ++ LCM_GPE &= ~(LCM_GPIO_DAC_ON); ++ collie_dac_init = 0; + } + + static inline void Collie_DAC_on(void) + { +- ENTER(TRACE_DAC,"Collie_DAC_on"); +-// if (!collie_dac_init) { + if (!(LCM_GPO & LCM_GPIO_DAC_ON)) { + /* LoCoMo GPIO enable */ + LCM_GPE &= ~LCM_GPIO_DAC_ON; +@@ -1049,24 +421,10 @@ + schedule(); + } + } +-// } +- LEAVE(TRACE_DAC,"Collie_DAC_on"); +-} +- +-#ifdef TRY_DELAY_OFF /* H.Hayami SHARP */ +-static inline void Collie_DAC_delay_off(void) +-{ +- ENTER(TRACE_DAC,"Collie_DAC_deleay_off"); +- down(&df_sem); +- SetDelay(DELAY_DAC_OFF); +- up(&df_sem); +- LEAVE(TRACE_DAC,"Collie_DAC_delay_off"); + } +-#endif + + static inline void Collie_DAC_init(void) + { +- ENTER(TRACE_DAC,"Collie_DAC_init"); + /* LoCoMo GPIO enable */ + LCM_GPE &= + ~(LCM_GPIO_DAC_SDATA | LCM_GPIO_DAC_SCK | LCM_GPIO_DAC_SLOAD); +@@ -1075,7 +433,6 @@ + ~(LCM_GPIO_DAC_SDATA | LCM_GPIO_DAC_SCK | LCM_GPIO_DAC_SLOAD); + + #if defined(CONFIG_COLLIE_PCM1741) +- + Collie_DAC_sendword(DAC_REG16_SetupData); /* register16 */ + Collie_DAC_sendword(DAC_REG17_SetupData); /* register17 */ + Collie_DAC_sendword(DAC_REG18_SetupData); /* register18 */ +@@ -1083,78 +440,53 @@ + Collie_DAC_sendword(DAC_REG20_SetupData); /* register20 */ + //// Collie_DAC_sendword(DAC_REG21_SetupData); /* register21 */ + Collie_DAC_sendword(DAC_REG22_SetupData); /* register22 */ +- + #elif defined(CONFIG_COLLIE_PCM1717) +- + Collie_DAC_sendword(DAC_MODE0_SetupData); /* MODE0 */ + Collie_DAC_sendword(DAC_MODE1_SetupData); /* MODE1 */ + Collie_DAC_sendword(DAC_MODE2_SetupData); /* MODE2 */ + Collie_DAC_sendword(DAC_MODE3_SetupData); /* MODE3 */ +- + #endif +- + /* LoCoMo GPIO disable */ + LCM_GPE &= + ~(LCM_GPIO_DAC_SDATA | LCM_GPIO_DAC_SCK | LCM_GPIO_DAC_SLOAD); +- LEAVE(TRACE_DAC,"Collie_DAC_init"); + } + + static inline void Collie_soft_DAC_on(void) + { + #if defined(CONFIG_COLLIE_PCM1741) +- ENTER(TRACE_DAC, "Collie_soft_DAC_on"); + Collie_DAC_sendword(DAC_REG19_DACOn); /* register19 */ +- LEAVE(TRACE_DAC, "Collie_soft_DAC_on"); + #endif /* CONFIG_COLLIE_PCM1741 */ + } + + static inline void Collie_soft_DAC_off(void) + { + #if defined(CONFIG_COLLIE_PCM1741) +- ENTER(TRACE_DAC, "Collie_soft_DAC_off"); + Collie_DAC_sendword(DAC_REG19_DACOff); /* register19 */ +- LEAVE(TRACE_DAC, "Collie_soft_DAC_off"); +-#endif /* CONFIG_COLLIE_PCM1741 */ +-} +- +-static inline void Collie_soft_mute_init(void) +-{ +-#if defined(CONFIG_COLLIE_PCM1741) +- ENTER(TRACE_MUTE, "Collie_soft_mute_init"); +- Collie_DAC_sendword(DAC_REG18_MuteOn); /* register18 */ +- collie_soft_mute = 1; +- LEAVE(TRACE_MUTE, "Collie_soft_mute_init"); + #endif /* CONFIG_COLLIE_PCM1741 */ + } + + static inline void Collie_soft_mute_on(void) + { + #if defined(CONFIG_COLLIE_PCM1741) +- ENTER(TRACE_MUTE, "Collie_soft_mute_on"); + if (!collie_soft_mute) { + Collie_DAC_sendword(DAC_REG18_MuteOn); /* register18 */ + collie_soft_mute = 1; + } +- LEAVE(TRACE_MUTE, "Collie_soft_mute_on"); + #endif /* CONFIG_COLLIE_PCM1741 */ + } + + static inline void Collie_soft_mute_off(void) + { + #if defined(CONFIG_COLLIE_PCM1741) +- ENTER(TRACE_MUTE, "Collie_soft_mute_off"); + if (collie_soft_mute) { + Collie_DAC_sendword(DAC_REG18_MuteOff); /* register18 */ + collie_soft_mute = 0; + } +- LEAVE(TRACE_MUTE, "Collie_soft_mute_off"); + #endif /* CONFIG_COLLIE_PCM1741 */ + } + + static inline void Collie_hard_mute_init(void) + { +-#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0) +- ENTER(TRACE_MUTE, "Collie_hard_mute_init"); + SCP_REG_GPCR |= (SCP_GPCR_PA14 | SCP_GPCR_PA15); + #ifdef HARD_MUTE_CTRL_DISABLE + SCP_REG_GPWR |= (SCP_GPCR_PA14 | SCP_GPCR_PA15); +@@ -1162,84 +494,107 @@ + SCP_REG_GPWR &= ~(SCP_GPCR_PA14 | SCP_GPCR_PA15); + #endif /* HARD_MUTE_CTRL_DISABLE */ + collie_hard_mute = 1; +-#if !defined(CONFIG_COLLIE_TR1) && !defined(CONFIG_COLLIE_DEV) ++ + { + int time = jiffies + 5; + while (jiffies <= time) + schedule(); + } +-#endif +- LEAVE(TRACE_MUTE, "Collie_hard_mute_init"); +-#endif /* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */ + } + + static inline void Collie_hard_mute_on(void) + { +-#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0) + #ifndef HARD_MUTE_CTRL_DISABLE +- ENTER(TRACE_MUTE, "Collie_hard_mute_on"); + if (!collie_hard_mute) { + SCP_REG_GPWR &= ~(SCP_GPCR_PA14 | SCP_GPCR_PA15); + collie_hard_mute = 1; +-#if !defined(CONFIG_COLLIE_TR1) && !defined(CONFIG_COLLIE_DEV) + { + int time = jiffies + 5; + while (jiffies <= time) + schedule(); + } +-#endif + } +- LEAVE(TRACE_MUTE, "Collie_hard_mute_on"); + #endif /* HARD_MUTE_CTRL_DISABLE */ +-#endif /* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */ + } + + static inline void Collie_hard_mute_off(void) + { +-#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0) + #ifndef HARD_MUTE_CTRL_DISABLE +- ENTER(TRACE_MUTE, "Collie_hard_mute_off"); + if (collie_hard_mute) { +- if (!COLLE_RECORDING) + SCP_REG_GPWR |= (SCP_GPCR_PA14 | SCP_GPCR_PA15); +- else +- SCP_REG_GPWR |= (SCP_GPCR_PA15); + collie_hard_mute = 0; +-#if !defined(CONFIG_COLLIE_TR1) && !defined(CONFIG_COLLIE_DEV) + { + int i; + for (i=0; i<=1000; i++) { + udelay(1); + } + } +-#endif + } +- LEAVE(TRACE_MUTE, "Collie_hard_mute_off"); + #endif /* HARD_MUTE_CTRL_DISABLE */ +-#endif /* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */ +-} +- +-#ifdef TRY_DELAY_OFF /* H.Hayami SHARP 2001.12.19 */ +-static inline void Collie_hard_mute_delay_on(void) +-{ +- ENTER(TRACE_MUTE, "Collie_hard_mute_delay_on"); +- down(&df_sem); +- SetDelay(DELAY_HARD_MUTE_ON); +- up(&df_sem); +- LEAVE(TRACE_MUTE, "Collie_hard_mute_delay_on"); + } +-#endif + +-static inline void Collie_audio_clock_init(void) ++static inline void Collie_hard_mute_left_on(void) ++{ ++#ifndef HARD_MUTE_CTRL_DISABLE ++// if (!collie_hard_mute) { ++ SCP_REG_GPWR &= ~(SCP_GPCR_PA14); ++ { ++ int time = jiffies + 5; ++ while (jiffies <= time) ++ schedule(); ++ } ++// } ++#endif /* HARD_MUTE_CTRL_DISABLE */ ++} ++ ++static inline void Collie_hard_mute_left_off(void) ++{ ++#ifndef HARD_MUTE_CTRL_DISABLE ++// if (collie_hard_mute) { ++ SCP_REG_GPWR |= (SCP_GPCR_PA14); ++ { ++ int i; ++ for (i=0; i<=1000; i++) { ++ udelay(1); ++ } ++ } ++// } ++#endif /* HARD_MUTE_CTRL_DISABLE */ ++} ++ ++ ++static int CollieGetSamp(void) ++{ ++ switch (sound.speed) { ++ case 8000: ++ return clock_set_data[7]; ++ case 44100: ++ return clock_set_data[0]; ++ case 22050: ++ return clock_set_data[1]; ++ case 11025: ++ return clock_set_data[2]; ++ case 48000: ++ return clock_set_data[3]; ++ case 32000: ++ return clock_set_data[4]; ++ case 24000: ++ return clock_set_data[5]; ++ case 16000: ++ return clock_set_data[6]; ++ default: ++ printk("Collie sound: Illegal sound rate %d\n", sound.speed); ++ return clock_set_data[7]; ++ } ++} ++ ++static inline void Collie_audio_clock_init(void) + { +- ENTER(TRACE_CLOCK, "Collie_audio_clock_init"); + LCM_ACC = 0; +- LEAVE(TRACE_CLOCK, "Collie_audio_clock_init"); + } + + static inline void Collie_audio_clock_on(void) + { +- ENTER(TRACE_CLOCK, "Collie_audio_clock_on"); + /* LoCoMo Audio clock on */ + LCM_ACC = CollieGetSamp(); + barrier(); +@@ -1248,263 +603,58 @@ + LCM_ACC |= LCM_ACC_XEN; + barrier(); + LCM_ACC |= (LCM_ACC_MCLKEN | LCM_ACC_64FSEN); +- LEAVE(TRACE_CLOCK, "Collie_audio_clock_on"); + } + + static inline void Collie_audio_clock_off(void) + { +- ENTER(TRACE_CLOCK, "Collie_audio_clock_off"); + /* LoCoMo Audio clock off */ + LCM_ACC &= ~(LCM_ACC_XEN | LCM_ACC_MCLKEN | LCM_ACC_64FSEN); + barrier(); + LCM_ACC &= ~(LCM_ACC_XON); +- LEAVE(TRACE_CLOCK, "Collie_audio_clock_off"); +-} +- +-static inline void Collie_paif_init(void) +-{ +- ENTER(TRACE_PAIF, "Collie_paif_init"); +- // LCM_PAIF = (LCM_PAIF_SCINV | LCM_PAIF_LRCRST); +- LCM_PAIF = (LCM_PAIF_LRCRST); +- LEAVE(TRACE_PAIF, "Collie_paif_init"); + } + + static inline void Collie_paif_on(void) + { +- ENTER(TRACE_PAIF, "Collie_paif_on"); + LCM_PAIF = (LCM_PAIF_SCINV | LCM_PAIF_LRCRST); + LCM_PAIF &= ~(LCM_PAIF_LRCRST); + LCM_PAIF |= (LCM_PAIF_SCEN | LCM_PAIF_LRCEN); +- LEAVE(TRACE_PAIF, "Collie_paif_on"); + } + + static inline void Collie_paif_off(void) + { +- ENTER(TRACE_PAIF, "Collie_paif_off"); +- // LCM_PAIF = (LCM_PAIF_SCINV | LCM_PAIF_LRCRST); + LCM_PAIF = (LCM_PAIF_LRCRST); +- LEAVE(TRACE_PAIF, "Collie_paif_off"); + } + + static inline void Collie_MIC_init(void) + { +-#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0) +- ENTER(TRACE_MIC, "Collie_MIC_init"); + /* MIC to GPIO 17 */ + /* alternate functions for the GPIOs */ +- GAFR &= ~( COLLIE_GPIO_MIC ); +- ++ GAFR &= ~( COLLIE_GPIO_MIC ); + /* Set the direction: 17 output */ + GPDR |= ( COLLIE_GPIO_MIC ); +- +-#if defined(CONFIG_COLLIE_TR1) +- /* Set pin level (Low) */ +- GPCR = ( COLLIE_GPIO_MIC ); +-#else + /* Set pin level (High) */ + GPSR = ( COLLIE_GPIO_MIC ); +-#endif +- LEAVE(TRACE_MIC, "Collie_MIC_init"); +-#endif /* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */ + } + + static inline void Collie_MIC_on(void) + { +-#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0) +- ENTER(TRACE_MIC, "Collie_MIC_on"); +-#if defined(CONFIG_COLLIE_TR1) +- GPSR = ( COLLIE_GPIO_MIC ); +-#else + GPCR = ( COLLIE_GPIO_MIC ); +-#endif +- LEAVE(TRACE_MIC, "Collie_MIC_on"); +-#endif /* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */ + } + + static inline void Collie_MIC_off(void) + { +-#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0) +- ENTER(TRACE_MIC, "Collie_MIC_off"); +- if (!COLLE_RECORDING) { +-#if defined(CONFIG_COLLIE_TR1) +- GPCR = ( COLLIE_GPIO_MIC ); +-#else +- GPSR = ( COLLIE_GPIO_MIC ); +-#endif +- } +- LEAVE(TRACE_MIC, "Collie_MIC_off"); +-#endif /* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */ +-} +- +-static inline void Collie_volume_init(void) +-{ +- ENTER(TRACE_VOLUME, "Collie_volume_init"); +- m62332_senddata(0, M62332_EVR_CH); +- collie_volume = 0; +- LEAVE(TRACE_VOLUME, "Collie_volume_init"); +-} +- +-static inline void Collie_volume_on(void) +-{ +- ENTER(TRACE_VOLUME, "Collie_volume_on"); +- if (collie_volume != sound.volume_left) { +- //Collie_hard_mute_on(); +- m62332_senddata(0xff * sound.volume_left / 100, M62332_EVR_CH); +- //Collie_hard_mute_off(); +- collie_volume = sound.volume_left; +- } +- LEAVE(TRACE_VOLUME, "Collie_volume_on"); +-} +- +-static inline void Collie_volume_off(void) +-{ +- ENTER(TRACE_VOLUME, "Collie_volume_off"); +- if (collie_volume) { +- //Collie_hard_mute_on(); +- m62332_senddata(0, M62332_EVR_CH); +- //Collie_hard_mute_off(); +- collie_volume = 0; +- } +- LEAVE(TRACE_VOLUME, "Collie_volume_off"); +-} +- +-#define VOL_THRES 40 +-static void Collie_volume_half_adjust(void) +-{ +- int volume = collie_volume; +- ENTER(TRACE_VOLUME, "Collie_volume_half_adjust"); +- if (collie_volume > sound.volume_left) { +- /* volume down */ +- if (collie_volume > VOL_THRES) { +- if (sound.volume_left > VOL_THRES) { +- volume = (collie_volume + sound.volume_left)/2; +- if (volume == collie_volume) { +- volume = sound.volume_left; +- } +- } else { +- volume = (collie_volume + VOL_THRES)/2; +- if (volume == collie_volume) { +- volume = VOL_THRES; +- } +- } +- } else { +- /* we can pull down without noise */ +- volume = sound.volume_left; +- } +- } else if (collie_volume < sound.volume_left) { +- /* volume up */ +- if (sound.volume_left > VOL_THRES) { +- if (collie_volume < VOL_THRES) { +- /* we can pull up to VOL_THRES without noise */ +- volume = VOL_THRES;; +- } else { +- volume = (collie_volume + sound.volume_left)/2; +- if (volume == collie_volume) { +- volume = sound.volume_left; +- } +- } +- } else { +- /* we can pull up without noise */ +- volume = sound.volume_left; +- } +- } +- if (collie_volume != volume) { +- m62332_senddata(0xff * volume / 100, M62332_EVR_CH); +- collie_volume = volume; +- } +- LEAVE(TRACE_VOLUME, "Collie_volume_half_adjust"); +-} +- +-static void Collie_volume_half_off(void) +-{ +- int volume; +- int delta = 1; +- ENTER(TRACE_VOLUME, "Collie_volume_half_off"); +- while (0 < collie_volume) { +- if (collie_volume <= VOL_THRES) { +- volume = 0; +- } else { +- if (collie_volume > delta) { +- volume = collie_volume - delta; +- } else { +- volume = 0; +- } +- if (volume && volume < VOL_THRES) { +- volume = VOL_THRES; +- } +- delta <<= 1; +- } +- m62332_senddata(0xff * volume / 100, M62332_EVR_CH); +- collie_volume = volume; +- udelay(100); +- } +- LEAVE(TRACE_VOLUME, "Collie_volume_half_off"); +-} +- +-static void Collie_OP_SHDN_on(void) +-{ +-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0) +- ENTER(TRACE_OP_SHDN,"Collie_OP_SHDN_on"); +- if (!collie_op_shdn_on) { +- /* set volume */ +- Collie_volume_off(); +- +- /* OP_SHDN to GPIO 17 */ +- /* alternate functions for the GPIOs */ +- GAFR &= ~( COLLIE_GPIO_OPSHDN ); +- +- /* Set the direction: 17 output */ +- GPDR |= ( COLLIE_GPIO_OPSHDN ); +- +- /* Set pin level (high) */ +- GPSR |= ( COLLIE_GPIO_OPSHDN ); +- +- /* set volume */ +- Collie_volume_on(); +- +- collie_op_shdn_on = 1; +- } +- LEAVE(TRACE_OP_SHDN,"Collie_OP_SHDN_on"); +-#endif /* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */ +-} +- +-static void Collie_OP_SHDN_off(void) +-{ +-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0) +- ENTER(TRACE_OP_SHDN,"Collie_OP_SHDN_off"); +- /* OP_SHDN to GPIO 17 */ +- /* alternate functions for the GPIOs */ +- GAFR &= ~( COLLIE_GPIO_OPSHDN ); +- +- /* Set the direction: 17 output */ +- GPDR |= ( COLLIE_GPIO_OPSHDN ); +- +- /* Clear pin level (low) */ +- GPCR |= ( COLLIE_GPIO_OPSHDN ); +- +- collie_op_shdn_on = 0; +- LEAVE(TRACE_OP_SHDN,"Collie_OP_SHDN_off"); +-#endif /* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */ ++ GPSR = ( COLLIE_GPIO_MIC ); + } + + static inline void Collie_ssp_init(void) + { +- ENTER(TRACE_SSP, "Collie_ssp_init"); + /* alternate functions for the GPIOs */ + /* SSP port to GPIO 10,12,13, 19 */ + GAFR |= ( GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM | GPIO_SSP_CLK ); +-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0) +- /* SSP port to GPIO 11 */ +- GAFR |= GPIO_SSP_RXD; +-#endif /* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */ + + /* Set the direction: 10, 12, 13 output; 19 input */ + GPDR |= ( GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM ); + GPDR &= ~( GPIO_SSP_CLK ); +-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0) +- /* Set the direction: 11 input */ +- GPDR &= ~( GPIO_SSP_RXD ); +-#endif /* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */ + + /* enable SSP pin swap */ + PPAR |= PPAR_SPR; +@@ -1516,400 +666,162 @@ + /* the SSP setting */ + Ser4SSCR0 = (SSCR0_DataSize(16) | SSCR0_TI | SSCR0_SerClkDiv(2)); + Ser4SSCR1 = (SSCR1_SClkIactL | SSCR1_SClk1P | SSCR1_ExtClk); +- +- LEAVE(TRACE_SSP, "Collie_ssp_init"); + } + + static inline void Collie_ssp_on(void) + { +- ENTER(TRACE_SSP, "Collie_ssp_on"); + /* turn on the SSP */ + Ser4SSCR0 |= ( SSCR0_SSE ); +- LEAVE(TRACE_SSP, "Collie_ssp_on"); + } + + static inline void Collie_ssp_off(void) + { +- ENTER(TRACE_SSP, "Collie_ssp_off"); + /* turn off the SSP */ + Ser4SSCR0 &= ~( SSCR0_SSE ); +- LEAVE(TRACE_SSP, "Collie_ssp_off"); +-} +- +-static inline void Collie_sound_hard_init(void) +-{ +- ENTER(TRACE_ON, "Collie_sound_hard_init"); +- Collie_hard_mute_init(); +- Collie_audio_clock_init(); +- Collie_paif_init(); +- Collie_volume_init(); +- Collie_ssp_init(); +- Collie_MIC_init(); +- +- Collie_FS8KLPF_start(); +- LEAVE(TRACE_ON, "Collie_sound_hard_init"); +-} +- +-static inline void Collie_sound_hard_term(void) +-{ +- ENTER(TRACE_ON, "Collie_sound_hard_term"); +-#ifdef DAC_OFF_WITH_DEVICE_OFF +- /* DAC Off */ +- Collie_DAC_off(); +-#endif +- LEAVE(TRACE_ON, "Collie_sound_hard_term"); +-} +- +-static void Collie_FS8KLPF_start(void) +-{ +-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0) +- ENTER(TRACE_ON,"Collie_FS8KLPF_start"); +- /* Set up TC35143 GPIO I/O Direction (GPIO5 output mode) */ +- ucb1200_set_io_direction(TC35143_GPIO_FS8KLPF, +- TC35143_IODIR_OUTPUT); +- /* Set up TC35143 GPIO 5 (set LOW) */ +- ucb1200_set_io(TC35143_GPIO_FS8KLPF, TC35143_IODAT_LOW); +- LEAVE(TRACE_ON,"Collie_FS8KLPF_start"); +-#endif /* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */ +-} +- +-#ifdef CONFIG_PM +-#if 0 +-static void Collie_FS8KLPF_stop(void) +-{ +- /* Set up TC35143 GPIO I/O Direction (GPIO5 output mode) */ +- ucb1200_set_io_direction(TC35143_GPIO_FS8KLPF, +- TC35143_IODIR_OUTPUT); +- /* Set up TC35143 GPIO 5 (set LOW) */ +- ucb1200_set_io(TC35143_GPIO_FS8KLPF, TC35143_IODAT_HIGH); +-} +- +-static void Collie_clock_stop(void) +-{ +- /* LoCoMo PCM audio interface */ +- Collie_paif_off(); +- +- /* LoCoMo audio clock off */ +- Collie_audio_clock_off(); +-} +-#endif +-#endif +- +-#ifdef TRY_DELAY_OFF /* H.Hayami SHARP 2001.12.19 */ +-static unsigned long in_timehandle = 0; +-static struct timer_list timer; +- +-static void collieDoDelayedSilence(void) +-{ +- ENTER(TRACE_ON,"collieDoDelayedSilence"); +- down(&df_sem); +- if(isDelayed(DELAY_HARD_MUTE_ON)) { +- Collie_hard_mute_on(); +- } +- if(isDelayed(DELAY_DAC_OFF)) { +- Collie_DAC_off(); +- } +- ResetDelayAll(); +- up(&df_sem); +- LEAVE(TRACE_ON,"colliDoDelayedSilence"); +-} +- +-static void collieDelayedSilence(void) +-{ +- ENTER(TRACE_ON,"collieDelayedSilence"); +- while (1) { +- sleep_on(&delay_off); +- collieDoDelayedSilence(); +- } +- LEAVE(TRACE_ON,"collieDelayedSilence"); +-} +- +-static void collieStartDelayedSilence(unsigned long data) +-{ +- ENTER(TRACE_ON,"collieStartDelayedSilence"); +- in_timehandle = 0; +- wake_up(&delay_off); +- LEAVE(TRACE_ON,"collieStartDelayedSilence"); +-} +- +-static void collieTriggerDelayedSilence(void) +-{ +- ENTER(TRACE_ON,"collieTriggerDelayedSilence"); +- in_timehandle = 1; +- init_timer(&timer); +- timer.function = collieStartDelayedSilence; +- timer.expires = jiffies + 5*100; +- add_timer(&timer); +- LEAVE(TRACE_ON,"collieTriggerDelayedSilence"); +-} +- +-static void collieCancelDelayedSilence(void) +-{ +- ENTER(TRACE_ON,"collieCancelDelayedSilence"); +- down(&df_sem); +- ResetDelayAll();; +- up(&df_sem); +- if (in_timehandle) { +- del_timer(&timer); +- in_timehandle = 0; +- } +- LEAVE(TRACE_ON,"collieCancelDelayedSilence"); +-} +-#endif +- +-static void Collie_disable_sound(void) +-{ +- ENTER(TRACE_ON,"Collie_disable_sound"); +- sa1100_dma_stop(COLLIE_SOUND_DMA_CHANNEL); +- sa1100_dma_flush_all(COLLIE_SOUND_DMA_CHANNEL); +-#ifndef TRY_DELAY_OFF /* H.Hayami SHARP 2001.12.18 */ +- Collie_volume_half_off(); +- Collie_hard_mute_on(); +- Collie_soft_mute_on(); +- +- Collie_ssp_off(); +- +- /* Collie_clock_stop(); */ +-#endif +- LEAVE(TRACE_ON,"Collie_disable_sound"); +-} +- +-static void CollieSilence(void) +-{ +- ENTER(TRACE_ON,"CollieSilence"); +- /* Disable sound & DMA */ +- Collie_disable_sound(); +- +-#ifdef TRY_DELAY_OFF /* H.Hayami SHARP 2001.12.18 */ +- Collie_volume_half_off(); +- Collie_hard_mute_delay_on(); +- Collie_soft_mute_on(); +- +- Collie_ssp_off(); +- +- /* Collie_clock_stop(); */ +-#endif +- +-#if 0 /* H.Hayami SHARP 2001.12.18 */ +-#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0) && \ +- !defined(CONFIG_COLLIE_TR1) && !defined(CONFIG_COLLIE_DEV) +- Collie_volume_off(); +-#endif +-#endif +- Collie_OP_SHDN_off(); +- Collie_soft_DAC_off(); +- Collie_paif_off(); +- Collie_audio_clock_off(); +- +- //Collie_MIC_on(); +- +-#ifndef DAC_OFF_WITH_DEVICE_OFF +- /* DAC Off */ +-#ifdef TRY_DELAY_OFF /* H.Hayami 2001.12.15 */ +- Collie_DAC_delay_off(); +-#else +- Collie_DAC_off(); +-#endif +-#endif /* end DAC_OFF_WITH_DEVICE_OFF */ +- +- /* AMP Off */ +- Collie_AMP_off(); +- +-#ifdef TRY_DELAY_OFF /* H.Hayami SHARP 2001.12.18 */ +- collieTriggerDelayedSilence(); +-#endif +- LEAVE(TRACE_ON,"CollieSilence"); +-} +- +-static int CollieGetSamp(void) +-{ +- ENTER(TRACE_ON,"CollieGetSamp"); +- switch (sound.soft.speed) { +- case 8000: +- LEAVE(TRACE_ON,"CollieGetSamp"); +- return clock_set_data[7]; +- case 44100: +- LEAVE(TRACE_ON,"CollieGetSamp"); +- return clock_set_data[0]; +- case 22050: +- LEAVE(TRACE_ON,"CollieGetSamp"); +- return clock_set_data[1]; +- case 11025: +- LEAVE(TRACE_ON,"CollieGetSamp"); +- return clock_set_data[2]; +- case 48000: +- LEAVE(TRACE_ON,"CollieGetSamp"); +- return clock_set_data[3]; +- case 32000: +- LEAVE(TRACE_ON,"CollieGetSamp"); +- return clock_set_data[4]; +- case 24000: +- LEAVE(TRACE_ON,"CollieGetSamp"); +- return clock_set_data[5]; +- case 16000: +- LEAVE(TRACE_ON,"CollieGetSamp"); +- return clock_set_data[6]; +- default: +- printk("Collie sound: Illegal sound rate %d\n", sound.soft.speed); +- LEAVE(TRACE_ON,"CollieGetSamp"); +- return clock_set_data[7]; +- } +-} +- +-static inline void Collie_DAC_sendbit(int bit_data) +-{ +- ENTER(TRACE_SENDDATA,"Collie_DAC_sendbit"); +- if (bit_data & 1) { +- LCM_GPO |= (LCM_GPIO_DAC_SDATA); +- } else { +- LCM_GPO &= ~(LCM_GPIO_DAC_SDATA); +- } +- +- udelay(1); +- LCM_GPO |= (LCM_GPIO_DAC_SCK); +- +- udelay(1); +- LCM_GPO &= ~(LCM_GPIO_DAC_SCK); +- udelay(1); +- LCM_GPO &= ~(LCM_GPIO_DAC_SDATA); +- udelay(1); +- LEAVE(TRACE_SENDDATA,"Collie_DAC_sendbit"); +-} +- +-static void Collie_DAC_sendword(int data) +-{ +- int i; +- +- ENTER(TRACE_SENDDATA,"Collie_DAC_sendword"); +-#if defined(CONFIG_COLLIE_PCM1741) +- +- LCM_GPO &= ~(LCM_GPIO_DAC_SCK); +- udelay(1); +- LCM_GPO |= (LCM_GPIO_DAC_SLOAD); +- udelay(1); +- +- for (i = 0; i < 16; i++) +- Collie_DAC_sendbit(data >> (15 - i)); +- +- LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD); +- udelay(2); +- +-#elif defined(CONFIG_COLLIE_PCM1717) +- +- LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD); +- udelay(1000); +- LCM_GPO |= (LCM_GPIO_DAC_SLOAD); +- udelay(1000); +- LCM_GPO &= ~(LCM_GPIO_DAC_SCK); +- udelay(1000); +- +- for (i = 0; i < 16; i++) +- Collie_DAC_sendbit(data >> (15 - i)); +- +- LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD); +- udelay(1000); +- LCM_GPO |= (LCM_GPIO_DAC_SLOAD); +- udelay(1000); +- LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD); +- udelay(1000); +- +-#endif +- LEAVE(TRACE_SENDDATA,"Collie_DAC_sendword"); + } + +-void +-Collie_audio_power_on(void) ++ ++static inline void Collie_sound_hard_init(void) + { +- int send_data; ++ Collie_hard_mute_init(); ++ Collie_audio_clock_init(); ++ Collie_paif_off(); ++ Collie_volume_init(); ++ Collie_ssp_init(); ++ Collie_MIC_init(); ++ Collie_soft_mute_on(); ++ Collie_DAC_on(); ++} + +- ENTER(TRACE_ON,"Collie_audio_power_on"); ++void Collie_recording_on(void) ++{ ++ collie_recording=1; ++ if (!playing) ++ Collie_DAC_on(); ++ else ++ Collie_hard_mute_left_on(); ++ Collie_MIC_on(); ++} + +-#ifdef TRY_DELAY_OFF /* H.Hayami SHARP 2001.12.19 */ +- collieCancelDelayedSilence(); +-#endif ++void Collie_recording_off(void) ++{ ++ collie_recording=0; ++ Collie_MIC_off(); ++ if (!playing) ++ Collie_DAC_off(); ++ else ++ Collie_hard_mute_left_off(); ++} + ++static void Collie_audio_power_on(void) ++{ ++ playing=1; + collie_amp_init = 0; +- +- /* OP_SHDN off */ +- Collie_OP_SHDN_off(); +- +- /* AMP on */ +- Collie_AMP_on(); +- +- /* DAC ON */ +- Collie_DAC_on(); +- +- Collie_MIC_off(); +- Collie_ssp_on(); +- +- /* LoCoMo Audio clock */ +- Collie_audio_clock_off(); ++ if (!collie_recording) ++ Collie_DAC_on(); ++ Collie_ssp_on(); ++ Collie_audio_clock_off(); /* LoCoMo Audio clock */ + Collie_audio_clock_on(); +- +- /* LoCoMo PCM audio interface */ +- Collie_paif_on(); +- ++ Collie_paif_on(); /* LoCoMo PCM audio interface */ + udelay(1000); +- +- /* DAC Setting */ + Collie_DAC_init(); +- + Collie_soft_DAC_on(); +- Collie_soft_mute_init(); ++ Collie_soft_mute_off(); ++ Collie_hard_mute_off(); ++ if (collie_recording) ++ Collie_hard_mute_left_on(); ++ Collie_volume_set(sound.volume); ++} + +- sound.hard = sound.soft; ++static void Collie_audio_power_off(void){ /* Disable sound only */ ++ Collie_volume_set(0); ++ Collie_hard_mute_on(); ++ Collie_soft_mute_on(); ++ Collie_ssp_off(); ++ Collie_soft_DAC_off(); ++ Collie_paif_off(); ++ Collie_audio_clock_off(); ++ if (!collie_recording) ++ Collie_DAC_off(); ++ playing=0; ++} + +-#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0) && \ +- !defined(CONFIG_COLLIE_TR1) && !defined(CONFIG_COLLIE_DEV) +- /* Volume set */ +- Collie_volume_half_adjust(); +- { +- int i; +- for (i=0; i<10*1000; i++) { +- udelay(1); ++ ++static inline void Collie_volume_init(void) ++{ ++ m62332_senddata(0, M62332_EVR_CH); ++ collie_volume = 0; ++} ++ ++#define VOL_THRES 10 ++ ++static void Collie_volume_set(int dest) ++{ ++ int chn; ++ while (dest != collie_volume) { ++ chn = dest-collie_volume; ++ if (chn>VOL_THRES) ++ chn=VOL_THRES; ++ else if (chn<-VOL_THRES) ++ chn=-VOL_THRES; ++ if (chn) { ++ collie_volume += chn; ++ m62332_senddata(0xff * collie_volume / 100, M62332_EVR_CH); + } ++ udelay(100); + } +-#endif ++} + +- Collie_soft_mute_off(); +- Collie_hard_mute_off(); ++static int sound_set_speed(int speed) ++{ ++ if (speed < 0) { ++ return(sound.speed); ++ } ++ ++ if (speed<8000) sound.speed=8000; ++ else if (speed<=11025) sound.speed=11025; ++ else if (speed<=16000) sound.speed=16000; ++ else if (speed<=22050) sound.speed=22050; ++ else if (speed<=24000) sound.speed=24000; ++ else if (speed<=32000) sound.speed=32000; ++ else if (speed<=44100) sound.speed=44100; ++ else sound.speed=48000; ++ ++ /* LoCoMo Audio clock */ ++ Collie_audio_clock_off(); ++ Collie_audio_clock_on(); ++ return(sound.speed); ++} + +- LEAVE(TRACE_ON,"Collie_audio_power_on"); ++/*** Mid level stuff *********************************************************/ ++ ++static void Collie_Set_Volume(int volume) ++{ ++ sound.volume = volume & 0xff; ++ sound.volume += ( volume & 0xff00 >> 8); ++ sound.volume >>=1; ++ if (sound.volume>100) sound.volume=100; + } + +-static void CollieInit(void) ++static int Collie_Get_Volume(void) + { +- ENTER(TRACE_ON,"CollieInit"); +- sound.hard = sound.soft; +- LEAVE(TRACE_ON,"CollieInit"); ++ return ( sound.volume << 8 | sound.volume ); + } + ++ + static void Collie_sq_interrupt(void* id, int size) + { + audio_buf_t *b = (audio_buf_t *) id; +- ENTER(TRACE_INTERRUPT,"Collie_sq_interrupt"); +-/***** DEBUG ***** +-printk("Collie_sq_interrupt: Start\n"); +-*****************/ ++ + /* + * Current buffer is sent: wake up any process waiting for it. + */ +- ENTER(TRACE_SEM,"up sem"); + up(&b->sem); +- LEAVE(TRACE_SEM,"up sem"); +-/***** DEBUG ***** +-printk("Collie_sq_interrupt: up End\n"); +-*****************/ + /* And any process polling on write. */ +- ENTER(TRACE_SEM,"up wait"); +- wake_up(&b->sem.wait); +- LEAVE(TRACE_SEM,"up wait"); +-/***** DEBUG ***** +-printk("Collie_sq_interrupt: wake_up End\n"); +-*****************/ ++ wake_up_interruptible(&b->sem.wait); ++ /* And indicate which was the last buffer sent */ + + DPRINTK("Collie_sq_interrupt \n"); +- LEAVE(TRACE_INTERRUPT,"Collie_sq_interrupt"); + } + + +@@ -1917,191 +829,52 @@ + { + int err; + +- ENTER(TRACE_ON,"CollieIrqInit"); + err = sa1100_request_dma(&collie_dmasound_irq, "dmasound", + DMA_Ser4SSPWr); + if (err) { +- LEAVE(TRACE_ON,"CollieIrqInit"); + return 0; + } +- /* printk("collie_dmasound_irq=%d\n", collie_dmasound_irq); */ ++ printk("collie_dmasound_irq=%d\n", collie_dmasound_irq); + + sa1100_dma_set_callback(collie_dmasound_irq, + (dma_callback_t)Collie_sq_interrupt); + +- +- /* Disable sound & DMA */ +- Collie_disable_sound(); +- +- LEAVE(TRACE_ON,"CollieIrqInit"); ++ sa1100_dma_stop(COLLIE_SOUND_DMA_CHANNEL); ++ sa1100_dma_flush_all(COLLIE_SOUND_DMA_CHANNEL); ++ Collie_audio_power_off(); + return(1); +- +-} +- +-#ifdef MODULE +-static void CollieIrqCleanUp(void) +-{ +- ENTER(TRACE_ON,"CollieIrqCleanUp"); +- /* Disable sound & DMA */ +- Collie_disable_sound(); +- +- /* release the interrupt */ +- free_irq(IRQ_DMA, Collie_sq_interrupt); +- LEAVE(TRACE_ON,"CollieIrqCleanUp"); + } +-#endif /* MODULE */ +- + + static int CollieSetFormat(int format) + { + int size; + +- ENTER(TRACE_ON,"CollieSetFormat"); +- /* Falcon sound DMA supports 8bit and 16bit modes */ +- + switch (format) { + case AFMT_QUERY: +- LEAVE(TRACE_ON,"CollieSetFormat"); +- return(sound.soft.format); +- case AFMT_MU_LAW: +- size = 8; +- ct_func = sound.trans->ct_ulaw; +- break; +- case AFMT_A_LAW: +- size = 8; +- ct_func = sound.trans->ct_alaw; +- break; +- case AFMT_S8: +- size = 8; +- ct_func = sound.trans->ct_s8; +- break; +- case AFMT_U8: +- size = 8; +- ct_func = sound.trans->ct_u8; +- break; +- case AFMT_S16_BE: +- size = 16; +- ct_func = sound.trans->ct_s16be; +- break; +- case AFMT_U16_BE: +- size = 16; +- ct_func = sound.trans->ct_u16be; +- break; +- case AFMT_S16_LE: +- size = 16; +- ct_func = sound.trans->ct_s16le; +- break; +- case AFMT_U16_LE: ++ return(sound.format); ++ default: /* This is the only one supported by the hardware it seems */ + size = 16; +- ct_func = sound.trans->ct_u16le; +- break; +- default: /* :-) */ +- size = 8; +- format = AFMT_S8; +- } +- +- sound.soft.format = format; +- sound.soft.size = size; +- if (sound.minDev == SND_DEV_DSP) { +- sound.dsp.format = format; +- sound.dsp.size = sound.soft.size; ++ format = AFMT_S16_LE; + } ++ sound.format = format; ++ sound.size = size; + +- LEAVE(TRACE_ON,"CollieSetFormat"); + return(format); + } + +-/*** Machine definitions *****************************************************/ +- +-static MACHINE machCollie = { +- DMASND_COLLIE, // int type +- NULL, // void *dma_alloc(uint, int) +- NULL, // void dma_free(void *, uint) +- CollieIrqInit, // void irqinit(void) +-#ifdef MODULE +- CollieIrqCleanUp, // void irqcleanup(void) +-#endif /* MODULE */ +- CollieInit, // void init(void) +- CollieSilence, // void silence(void) +- CollieSetFormat, // int setFormat(int) +- NULL, // int setVolume(int) +- NULL, // int setBass(int) +- NULL, // int setTreble(int) +- NULL, // int setGain(int) +- NULL // void play(void) +-}; +- +- +-/*** Mid level stuff *********************************************************/ +- +- +-static void sound_silence(void) +-{ +- ENTER(TRACE_ON,"sound_silence"); +- /* update hardware settings one more */ +- //(*sound.mach.init)(); +- (*sound.mach.silence)(); +- LEAVE(TRACE_ON,"sound_silence"); +- +-} +- +- +-static void sound_init(void) +-{ +- ENTER(TRACE_ON,"sound_init"); +- (*sound.mach.init)(); +- LEAVE(TRACE_ON,"sound_init"); +-} +- +- +-static int sound_set_format(int format) +-{ +- ENTER(TRACE_ON,"sound_set_format"); +- LEAVE(TRACE_ON,"sound_set_format"); +- return(*sound.mach.setFormat)(format); +-} +- +- +-static int sound_set_speed(int speed) +-{ +- ENTER(TRACE_ON,"sound_set_speed"); +- if (speed < 0) { +- LEAVE(TRACE_ON,"sound_set_speed"); +- return(sound.soft.speed); +- } +- +- sound.soft.speed = speed; +- (*sound.mach.init)(); +- if (sound.minDev == SND_DEV_DSP) +- sound.dsp.speed = sound.soft.speed; +- +- /* LoCoMo Audio clock */ +- Collie_audio_clock_off(); +- Collie_audio_clock_on(); +- +- LEAVE(TRACE_ON,"sound_set_speed"); +- return(sound.soft.speed); +-} + + + static int sound_set_stereo(int stereo) + { +- ENTER(TRACE_ON,"sound_set_stereo"); ++/* Only stereo is supported by hardware */ + if (stereo < 0) { +- LEAVE(TRACE_ON,"sound_set_stereo"); +- return(sound.soft.stereo); ++ return(sound.stereo); + } ++ return(1); ++} + +- stereo = !!stereo; /* should be 0 or 1 now */ +- +- sound.soft.stereo = stereo; +- if (sound.minDev == SND_DEV_DSP) +- sound.dsp.stereo = stereo; +- //(*sound.mach.init)(); + +- LEAVE(TRACE_ON,"sound_set_stereo"); +- return(stereo); +-} ++/* Higher level stuff ************************************************/ + + /* + * /dev/mixer abstraction +@@ -2109,20 +882,15 @@ + + static int mixer_open(struct inode *inode, struct file *file) + { +- ENTER(TRACE_ON,"mixer_open"); + MOD_INC_USE_COUNT; + mixer.busy = 1; +- LEAVE(TRACE_ON,"mixer_open"); + return 0; + } + +- + static int mixer_release(struct inode *inode, struct file *file) + { +- ENTER(TRACE_ON,"mixer_release"); + mixer.busy = 0; + MOD_DEC_USE_COUNT; +- LEAVE(TRACE_ON,"mixer_release"); + return 0; + } + +@@ -2132,58 +900,37 @@ + { + int data; + +- ENTER(TRACE_ON,"mixer_ioctl"); +- switch (sound.mach.type) { +- case DMASND_COLLIE: +- { +- switch (cmd) { +- case SOUND_MIXER_READ_DEVMASK: +- LEAVE(TRACE_ON,"mixer_ioctl"); +- return IOCTL_OUT(arg, SOUND_MASK_VOLUME ); +- case SOUND_MIXER_READ_RECMASK: +- LEAVE(TRACE_ON,"mixer_ioctl"); +- return IOCTL_OUT(arg, 0); +- case SOUND_MIXER_READ_STEREODEVS: +- LEAVE(TRACE_ON,"mixer_ioctl"); +- return IOCTL_OUT(arg, SOUND_MASK_VOLUME); +- case SOUND_MIXER_READ_CAPS: +- LEAVE(TRACE_ON,"mixer_ioctl"); +- return IOCTL_OUT(arg, 0); +- +- case SOUND_MIXER_WRITE_VOLUME: +- IOCTL_IN(arg, data); +- Collie_Set_Volume(data); +- case SOUND_MIXER_READ_VOLUME: +- LEAVE(TRACE_ON,"mixer_ioctl"); +- return IOCTL_OUT(arg, Collie_Get_Volume()); +- +- case SOUND_MIXER_READ_TREBLE: +- LEAVE(TRACE_ON,"mixer_ioctl"); +- return IOCTL_OUT(arg, 0); +- case SOUND_MIXER_WRITE_TREBLE: +- LEAVE(TRACE_ON,"mixer_ioctl"); +- return IOCTL_OUT(arg, 0); +- +- case SOUND_MIXER_WRITE_MIC: +- LEAVE(TRACE_ON,"mixer_ioctl"); +- return IOCTL_OUT(arg, 0); +- case SOUND_MIXER_READ_MIC: +- LEAVE(TRACE_ON,"mixer_ioctl"); +- return IOCTL_OUT(arg, 0); +- +- case SOUND_MIXER_READ_SPEAKER: +- LEAVE(TRACE_ON,"mixer_ioctl"); +- return IOCTL_OUT(arg, 0); +- case SOUND_MIXER_WRITE_SPEAKER: +- LEAVE(TRACE_ON,"mixer_ioctl"); +- return IOCTL_OUT(arg, 0); +- } +- break; +- } +- } +- LEAVE(TRACE_ON,"mixer_ioctl"); ++ switch (cmd) { ++ case SOUND_MIXER_READ_DEVMASK: ++ return IOCTL_OUT(arg, headphone ? SOUND_MASK_VOLUME : 0 ); ++ case SOUND_MIXER_READ_RECMASK: ++ return IOCTL_OUT(arg, 0); ++ case SOUND_MIXER_READ_STEREODEVS: ++ return IOCTL_OUT(arg, headphone ? SOUND_MASK_VOLUME : 0 ); ++ case SOUND_MIXER_READ_CAPS: ++ return IOCTL_OUT(arg, 0); ++ ++ case SOUND_MIXER_WRITE_VOLUME: ++ IOCTL_IN(arg, data); ++ Collie_Set_Volume(data); ++ case SOUND_MIXER_READ_VOLUME: ++ return IOCTL_OUT(arg, Collie_Get_Volume()); ++ case SOUND_MIXER_READ_TREBLE: ++ return IOCTL_OUT(arg, 0); ++ case SOUND_MIXER_WRITE_TREBLE: ++ return IOCTL_OUT(arg, 0); ++ ++ case SOUND_MIXER_WRITE_MIC: ++ return IOCTL_OUT(arg, 0); ++ case SOUND_MIXER_READ_MIC: ++ return IOCTL_OUT(arg, 0); ++ ++ case SOUND_MIXER_READ_SPEAKER: ++ return IOCTL_OUT(arg, 0); ++ case SOUND_MIXER_WRITE_SPEAKER: ++ return IOCTL_OUT(arg, 0); ++ } + return -EINVAL; +- + } + + +@@ -2198,32 +945,13 @@ + + static void __init mixer_init(void) + { +-#ifndef MODULE +- int mixer_unit; +-#endif +- ENTER(TRACE_ON,"mixer_init"); + mixer_unit = register_sound_mixer(&mixer_fops, -1); + if (mixer_unit < 0) { +- LEAVE(TRACE_ON,"mixer_init"); + return; + } +- + mixer.busy = 0; +- sound.treble = 0; +- sound.bass = 0; +- switch (sound.mach.type) { +- case DMASND_COLLIE: +- // sound.volume_left = 0x3c; +- // sound.volume_right = 0x3c; +- sound.volume_left = 80; +- sound.volume_right = 80; +- collie_main_volume = sound.volume_left; +- break; +- } +- +- // printk("mixer_init : ret \n"); +- +- LEAVE(TRACE_ON,"mixer_init"); ++ sound.volume = 80; ++ Collie_volume_set(sound.volume); + } + + /* This function allocates the buffer structure array and buffer data space +@@ -2237,11 +965,9 @@ + char *dmabuf = 0; + dma_addr_t dmaphys = 0; + +- ENTER(TRACE_ON,"sq_allocate_buffers"); + DPRINTK("sq_allocate_buffers\n"); + + if (s->buffers) { +- LEAVE(TRACE_ON,"sq_allocate_buffers"); + return -EBUSY; + } + +@@ -2279,10 +1005,8 @@ + + b->start = dmabuf; + b->dma_addr = dmaphys; ++ b->idx = frag; + 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; +@@ -2291,13 +1015,12 @@ + s->buf_idx = 0; + s->buf = &s->buffers[0]; + +- LEAVE(TRACE_ON,"sq_allocate_buffers"); ++ + return 0; + + err: + printk("sound driver : unable to allocate audio memory\n "); + sq_release_buffers(s); +- LEAVE(TRACE_ON,"sq_allocate_buffers"); + return -ENOMEM; + } + +@@ -2307,7 +1030,6 @@ + + static void sq_release_buffers(audio_stream_t * s) + { +- ENTER(TRACE_ON,"sq_release_buffers"); + DPRINTK("sq_release_buffers\n"); + + /* ensure DMA won't run anymore */ +@@ -2328,7 +1050,6 @@ + + s->buf_idx = 0; + s->buf = NULL; +- LEAVE(TRACE_ON,"sq_release_buffers"); + } + + static ssize_t sq_write(struct file *file, const char *src, size_t uLeft, +@@ -2339,27 +1060,20 @@ + u_char *dest; + ssize_t uUsed, bUsed, bLeft, ret = 0; + +- ENTER(TRACE_WRITE,"sq_write"); + DPRINTK("sq_write: uLeft=%d\n", uLeft); + +- /* OP_SHDN on */ +- Collie_OP_SHDN_on(); +- + switch (file->f_flags & O_ACCMODE) { + case O_WRONLY: + case O_RDWR: + break; + default: +- LEAVE(TRACE_WRITE,"sq_write1"); + return -EPERM; + } + + if (!s->buffers && sq_allocate_buffers(s)) { +- LEAVE(TRACE_WRITE,"sq_write2"); + return -ENOMEM; + } + +-#if 1 + if (collie_resume == 1) { + int i; + collie_resume = 0; +@@ -2367,10 +1081,9 @@ + udelay(1); + } + } +-#endif + #ifdef CONFIG_PM + /* Auto Power off cancel */ +- autoPowerCancel = 0; ++// autoPowerCancel = 0; + #endif + + while (uLeft > 0) { +@@ -2379,41 +1092,30 @@ + /* Wait for a buffer to become free */ + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; +- ENTER(TRACE_SEM,"down_try sem"); + if (down_trylock(&b->sem)) { +- LEAVE(TRACE_SEM,"down_try1 sem"); + break; + } +- LEAVE(TRACE_SEM,"down_try2 sem"); + } else { + ret = -ERESTARTSYS; +- ENTER(TRACE_SEM,"down_int sem"); +- //printk("### 0x%08x:%d\n", &b->sem.count, atomic_read(&b->sem.count)); + if (down_interruptible(&b->sem)) { +- LEAVE(TRACE_SEM,"down_int1 sem"); + break; + } +- LEAVE(TRACE_SEM,"down_int2 sem"); + } + + dest = b->start + b->size; + bUsed = 0; + bLeft = s->fragsize - b->size; + +- if (ct_func) { +- uUsed = ct_func(src, uLeft, dest, &bUsed, bLeft); ++ if (collie_ct_s16) { ++ uUsed = collie_ct_s16(src, uLeft, dest, &bUsed, bLeft); + cpu_cache_clean_invalidate_range((unsigned long)dest, + (unsigned long)(dest+(audio_fragsize)), 0); + } else { +- LEAVE(TRACE_WRITE,"sq_write3"); + return -EFAULT; + } + + if (uUsed < 0) { +- ENTER(TRACE_SEM,"up sem"); + up(&b->sem); +- LEAVE(TRACE_SEM,"up sem"); +- LEAVE(TRACE_WRITE,"sq_write4"); + return -EFAULT; + } + src += uUsed; +@@ -2421,9 +1123,7 @@ + b->size += bUsed; + + if (b->size < s->fragsize) { +- ENTER(TRACE_SEM,"up sem"); + up(&b->sem); +- LEAVE(TRACE_SEM,"up sem"); + break; + } + +@@ -2431,7 +1131,7 @@ + sa1100_dma_queue_buffer(COLLIE_SOUND_DMA_CHANNEL, + (void *) b, b->dma_addr, b->size); + +- Collie_volume_half_adjust(); ++ Collie_volume_set(sound.volume); + + b->size = 0; /* indicate that the buffer has been sent */ + NEXT_BUF(s, buf); +@@ -2440,7 +1140,6 @@ + if ((src - buffer0)) + ret = src - buffer0; + DPRINTK("sq_write: return=%d\n", ret); +- LEAVE(TRACE_WRITE,"sq_write0"); + return ret; + } + +@@ -2450,7 +1149,6 @@ + unsigned int mask = 0; + int i; + +- ENTER(TRACE_ON,"sq_poll"); + DPRINTK("sq_poll(): mode=%s%s\n", + (file->f_mode & FMODE_READ) ? "r" : "", + (file->f_mode & FMODE_WRITE) ? "w" : ""); +@@ -2458,12 +1156,9 @@ + if (file->f_mode & FMODE_WRITE) { + if (!output_stream.buffers + && sq_allocate_buffers(&output_stream)) { +- LEAVE(TRACE_ON,"sq_poll"); + return -ENOMEM; + } +- ENTER(TRACE_SEM,"poll_wait wait"); + poll_wait(file, &output_stream.buf->sem.wait, wait); +- LEAVE(TRACE_SEM,"poll_wait wait"); + } + + if (file->f_mode & FMODE_WRITE) { +@@ -2477,65 +1172,33 @@ + (mask & POLLIN) ? "r" : "", + (mask & POLLOUT) ? "w" : ""); + +- LEAVE(TRACE_ON,"sq_poll"); + return mask; + } + + static int sq_open(struct inode *inode, struct file *file) + { +- ENTER(TRACE_ON,"sq_open"); + DPRINTK("sq_open\n"); + + if (((file->f_flags & O_ACCMODE) == O_WRONLY) + || ((file->f_flags & O_ACCMODE) == O_RDWR)) { +-#if 0 +- MOD_INC_USE_COUNT; +- while(audio_wr_refcount) { +- SLEEP(open_queue, ONE_SECOND); +- if (SIGNAL_RECEIVED) { +- MOD_DEC_USE_COUNT; +- LEAVE(TRACE_ON,"sq_open"); +- return -EINTR; +- } +- } +-#else + if (audio_wr_refcount) { + DPRINTK(" sq_open EBUSY\n"); +- LEAVE(TRACE_ON,"sq_open"); + return -EBUSY; + } + MOD_INC_USE_COUNT; +-#endif + audio_wr_refcount++; + } else { + DPRINTK(" sq_open EINVAL\n"); +- LEAVE(TRACE_ON,"sq_open"); + return -EINVAL; + } + +- if (audio_wr_refcount == 1) { +- DPRINTK("cold\n"); +- +- audio_fragsize = AUDIO_FRAGSIZE_DEFAULT; +- audio_nbfrags = AUDIO_NBFRAGS_DEFAULT; +- sq_release_buffers(&output_stream); +- sound.minDev = MINOR(inode->i_rdev) & 0x0f; +- sound.soft = sound.dsp; +- sound.hard = sound.dsp; +- +- if ((MINOR(inode->i_rdev) & 0x0f) == SND_DEV_AUDIO) { +- sound_set_speed(8000); +- sound_set_stereo(0); +- sound_set_format(AFMT_MU_LAW); +- } +- Collie_audio_power_on(); +- } + +-#if 0 +- MOD_INC_USE_COUNT; +-#endif +- LEAVE(TRACE_ON,"sq_open"); +- return 0; ++ audio_fragsize = AUDIO_FRAGSIZE_DEFAULT; ++ audio_nbfrags = AUDIO_NBFRAGS_DEFAULT; ++ sq_release_buffers(&output_stream); ++ output_stream.buf_idx=0; ++ Collie_audio_power_on(); ++ return 0; + } + + static int sq_fsync(struct file *filp, struct dentry *dentry) +@@ -2543,11 +1206,9 @@ + audio_stream_t *s = &output_stream; + audio_buf_t *b = s->buf; + +- ENTER(TRACE_ON,"sq_fsync"); + DPRINTK("sq_fsync\n"); + + if (!s->buffers) { +- LEAVE(TRACE_ON,"sq_fsync"); + return 0; + } + +@@ -2557,12 +1218,10 @@ + + #ifdef CONFIG_PM + /* Auto Power off cancel */ +- autoPowerCancel = 0; ++// autoPowerCancel = 0; + #endif + +- ENTER(TRACE_SEM,"down sem"); + down(&b->sem); +- LEAVE(TRACE_SEM,"down sem"); + sa1100_dma_queue_buffer(COLLIE_SOUND_DMA_CHANNEL, + (void *) b, b->dma_addr, b->size); + b->size = 0; +@@ -2576,23 +1235,15 @@ + * - the buffer was already free thus nothing else to sync. + */ + b = s->buffers + ((s->nbfrags + s->buf_idx - 1) % s->nbfrags); +- ENTER(TRACE_SEM,"down-int sem"); + if (down_interruptible(&b->sem)) { +- LEAVE(TRACE_SEM,"down-int sem"); +- LEAVE(TRACE_ON,"sq_fsync"); + return -EINTR; + } +- LEAVE(TRACE_SEM,"down-int sem"); +- ENTER(TRACE_SEM,"up sem"); + up(&b->sem); +- LEAVE(TRACE_SEM,"up sem"); +- LEAVE(TRACE_ON,"sq_fsync"); + return 0; + } + + static int sq_release(struct inode *inode, struct file *file) + { +- ENTER(TRACE_ON,"sq_release"); + DPRINTK("sq_release\n"); + + switch (file->f_flags & O_ACCMODE) { +@@ -2606,24 +1257,12 @@ + } + + if (!audio_wr_refcount) { +- sound.soft = sound.dsp; +- sound.hard = sound.dsp; +- sound_silence(); +- Collie_OP_SHDN_off(); ++ sa1100_dma_stop(COLLIE_SOUND_DMA_CHANNEL); ++ sa1100_dma_flush_all(COLLIE_SOUND_DMA_CHANNEL); ++ Collie_audio_power_off(); + } + +-#if 0 +- switch (file->f_flags & O_ACCMODE) { +- case O_WRONLY: +- case O_RDWR: +- if (!audio_wr_refcount) { +- WAKE_UP(open_queue); +- } +- } +-#endif +- + MOD_DEC_USE_COUNT; +- LEAVE(TRACE_ON,"sq_release"); + return 0; + } + +@@ -2634,8 +1273,8 @@ + u_long fmt; + int data; + long val; ++// audio_buf_info abinfo; + +- ENTER(TRACE_ON,"sq_ioctl"); + switch (cmd) { + case SNDCTL_DSP_RESET: + switch (file->f_flags & O_ACCMODE) { +@@ -2643,11 +1282,9 @@ + case O_RDWR: + sq_release_buffers(&output_stream); + } +- LEAVE(TRACE_ON,"sq_ioctl"); + return 0; + case SNDCTL_DSP_POST: + case SNDCTL_DSP_SYNC: +- LEAVE(TRACE_ON,"sq_ioctl"); + return sq_fsync(file, file->f_dentry); + + /* ++TeSche: before changing any of these it's +@@ -2656,59 +1293,34 @@ + case SNDCTL_DSP_SPEED: + sq_fsync(file, file->f_dentry); + IOCTL_IN(arg, data); +- LEAVE(TRACE_ON,"sq_ioctl"); + return IOCTL_OUT(arg, sound_set_speed(data)); + case SNDCTL_DSP_STEREO: + sq_fsync(file, file->f_dentry); + IOCTL_IN(arg, data); +- LEAVE(TRACE_ON,"sq_ioctl"); + return IOCTL_OUT(arg, sound_set_stereo(data)); +- case SOUND_PCM_WRITE_CHANNELS: ++ case SNDCTL_DSP_CHANNELS: + sq_fsync(file, file->f_dentry); + IOCTL_IN(arg, data); +- LEAVE(TRACE_ON,"sq_ioctl"); + return IOCTL_OUT(arg, sound_set_stereo(data-1)+1); + case SNDCTL_DSP_SETFMT: + sq_fsync(file, file->f_dentry); + IOCTL_IN(arg, data); +- LEAVE(TRACE_ON,"sq_ioctl"); +- return IOCTL_OUT(arg, sound_set_format(data)); ++ return IOCTL_OUT(arg, CollieSetFormat(data)); + case SNDCTL_DSP_GETFMTS: +- fmt = 0; +- if (sound.trans) { +- if (sound.trans->ct_ulaw) +- fmt |= AFMT_MU_LAW; +- if (sound.trans->ct_alaw) +- fmt |= AFMT_A_LAW; +- if (sound.trans->ct_s8) +- fmt |= AFMT_S8; +- if (sound.trans->ct_u8) +- fmt |= AFMT_U8; +- if (sound.trans->ct_s16be) +- fmt |= AFMT_S16_BE; +- if (sound.trans->ct_u16be) +- fmt |= AFMT_U16_BE; +- if (sound.trans->ct_s16le) +- fmt |= AFMT_S16_LE; +- if (sound.trans->ct_u16le) +- fmt |= AFMT_U16_LE; +- } +- LEAVE(TRACE_ON,"sq_ioctl"); ++ fmt = AFMT_S16_LE; + return IOCTL_OUT(arg, fmt); + case SNDCTL_DSP_GETBLKSIZE: +- LEAVE(TRACE_ON,"sq_ioctl"); + return IOCTL_OUT(arg, audio_fragsize); + case SNDCTL_DSP_SUBDIVIDE: + break; + case SNDCTL_DSP_SETFRAGMENT: + if (output_stream.buffers) { +- LEAVE(TRACE_ON,"sq_ioctl"); + return -EBUSY; + } + get_user(val, (long *) arg); + audio_fragsize = 1 << (val & 0xFFFF); +- if (audio_fragsize < 16) +- audio_fragsize = 16; ++ if (audio_fragsize < 256) ++ audio_fragsize = 256; + if (audio_fragsize > 16384) + audio_fragsize = 16384; + audio_nbfrags = (val >> 16) & 0x7FFF; +@@ -2717,46 +1329,54 @@ + if (audio_nbfrags * audio_fragsize > 128 * 1024) + audio_nbfrags = 128 * 1024 / audio_fragsize; + if (sq_allocate_buffers(&output_stream)) { +- LEAVE(TRACE_ON,"sq_ioctl"); + return -ENOMEM; + } +- LEAVE(TRACE_ON,"sq_ioctl"); + return 0; + +-#if 1 // 2003.2.14 ++/* case SNDCTL_DSP_GETOSPACE: ++ abinfo.fragsize = audio_fragsize; ++ abinfo.fragstotal = audio_nbfrags; ++ abinfo.fragments = lastsent-output_stream.buf_idx; ++ if (abinfo.fragments<0) ++ abinfo.fragments += abinfo.fragstotal; ++ abinfo.bytes = abinfo.fragments*abinfo.fragsize; ++ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; ++*/ + case SNDCTL_DSP_GETOSPACE: + { +- audio_buf_info inf = { 0, }; ++ audio_stream_t *s = &output_stream; ++ audio_buf_info *inf = (audio_buf_info *) arg; ++ int err = verify_area(VERIFY_WRITE, inf, sizeof(*inf)); + int i; ++ int frags = 0, bytes = 0; + +- if (!(file->f_mode & FMODE_WRITE)) +- return -EINVAL; +- if (!output_stream.buffers && sq_allocate_buffers(&output_stream)) +- return -ENOMEM; +- for (i = 0; i < output_stream.nbfrags; i++) { +- if (atomic_read(&output_stream.buffers[i].sem.count) > 0) { +- if (output_stream.buffers[i].size == 0) +- inf.fragments++; +- inf.bytes += output_stream.fragsize - output_stream.buffers[i].size; +- } ++ if (err) ++ return err; ++ if (output_stream.buffers) { ++ for (i = 0; i < s->nbfrags; i++) { ++ if (atomic_read(&s->buffers[i].sem.count) > 0) { ++ if (s->buffers[i].size == 0) frags++; ++ bytes += s->fragsize - s->buffers[i].size; ++ } ++ } ++ put_user(s->nbfrags, &inf->fragstotal); ++ put_user(s->fragsize, &inf->fragsize); ++ } else { ++ frags=audio_nbfrags; ++ bytes=frags*audio_fragsize; ++ put_user(frags, &inf->fragstotal); ++ put_user(audio_fragsize, &inf->fragsize); + } +- inf.fragstotal = output_stream.nbfrags; +- inf.fragsize = output_stream.fragsize; +- return copy_to_user((void *)arg, &inf, sizeof(inf)); ++ put_user(frags, &inf->fragments); ++ return put_user(bytes, &inf->bytes); + } +-#endif +- + + default: +- LEAVE(TRACE_ON,"sq_ioctl"); + return mixer_ioctl(inode, file, cmd, arg); + } +- LEAVE(TRACE_ON,"sq_ioctl"); + return -EINVAL; + } + +- +- + static struct file_operations sq_fops = + { + llseek: sound_lseek, +@@ -2770,40 +1390,18 @@ + + static void __init sq_init(void) + { +-#ifndef MODULE +- int sq_unit; +-#endif +- ENTER(TRACE_ON,"sq_init"); + sq_unit = register_sound_dsp(&sq_fops, -1); + if (sq_unit < 0) { +- LEAVE(TRACE_ON,"sq_init"); + return; + } + +- /* whatever you like as startup mode for /dev/dsp, +- * (/dev/audio hasn't got a startup mode). note that +- * once changed a new open() will *not* restore these! +- */ +- sound.dsp.format = AFMT_S16_LE; +- +- sound.dsp.stereo = 0; +- sound.dsp.size = 16; +- +- /* set minimum rate possible without expanding */ +- switch (sound.mach.type) { +- case DMASND_COLLIE: +- sound.dsp.speed = 8000; +- break; +- } +- +- /* before the first open to /dev/dsp this wouldn't be set */ +- sound.soft = sound.dsp; +- sound.hard = sound.dsp; +- sound.trans = &transCollie; +- +- CollieSetFormat(sound.dsp.format); +- sound_silence(); +- LEAVE(TRACE_ON,"sq_init"); ++ sound.format = AFMT_S16_LE; ++ sound.stereo = 1; ++ sound.speed = 44100; ++ ++ CollieSetFormat(AFMT_S16_LE); ++ Collie_audio_power_off(); ++ output_stream.buf=output_stream.buffers=NULL; + } + + /* +@@ -2816,9 +1414,7 @@ + char *buffer = state.buf; + int len = 0; + +- ENTER(TRACE_ON,"state_open"); + if (state.busy) { +- LEAVE(TRACE_ON,"state_open"); + return -EBUSY; + } + +@@ -2828,8 +1424,8 @@ + + len += sprintf(buffer+len, " COLLIE DMA sound driver:\n"); + +- len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format); +- switch (sound.soft.format) { ++ len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.format); ++ switch (sound.format) { + case AFMT_MU_LAW: + len += sprintf(buffer+len, " (mu-law)"); + break; +@@ -2857,22 +1453,19 @@ + } + len += sprintf(buffer+len, "\n"); + len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n", +- sound.soft.speed, sound.hard.speed); ++ sound.speed, sound.speed); + len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n", +- sound.soft.stereo, +- sound.soft.stereo ? "stereo" : "mono"); ++ sound.stereo, ++ sound.stereo ? "stereo" : "mono"); + state.len = len; +- LEAVE(TRACE_ON,"state_open"); + return 0; + } + + + static int state_release(struct inode *inode, struct file *file) + { +- ENTER(TRACE_ON,"state_release"); + state.busy = 0; + MOD_DEC_USE_COUNT; +- LEAVE(TRACE_ON,"state_release"); + return 0; + } + +@@ -2881,19 +1474,15 @@ + loff_t *ppos) + { + int n = state.len - state.ptr; +- ENTER(TRACE_ON,"state_read"); + if (n > count) + n = count; + if (n <= 0) { +- LEAVE(TRACE_ON,"state_read"); + return 0; + } + if (copy_to_user(buf, &state.buf[state.ptr], n)) { +- LEAVE(TRACE_ON,"state_read"); + return -EFAULT; + } + state.ptr += n; +- LEAVE(TRACE_ON,"state_read"); + return n; + } + +@@ -2909,20 +1498,11 @@ + + static void __init state_init(void) + { +-#ifndef MODULE +- int state_unit; +-#endif +- ENTER(TRACE_ON,"state_unit"); + state_unit = register_sound_special(&state_fops, SND_DEV_STATUS); + if (state_unit < 0) { +- LEAVE(TRACE_ON,"state_unit"); + return; + } + state.busy = 0; +- +- // printk("state_init : ret \n"); +- LEAVE(TRACE_ON,"state_unit"); +- + } + + +@@ -2930,8 +1510,6 @@ + + static long long sound_lseek(struct file *file, long long offset, int orig) + { +- ENTER(TRACE_ON,"sound_lseek"); +- LEAVE(TRACE_ON,"sound_lseek"); + return -ESPIPE; + } + +@@ -2941,96 +1519,41 @@ + static int collie_sound_pm_callback(struct pm_dev *pm_dev, + pm_request_t req, void *data) + { +- ENTER(TRACE_PM,"collie_sound_pm_callback"); + switch (req) { + case PM_SUSPEND: + #ifdef COLLIE_TRY_ONE + disable_irq(IRQ_GPIO_nREMOCON_INT); + #endif +-#ifdef TRY_DELAY_OFF /* H.Hayami SHARP 2001.12.19 */ +- collieDoDelayedSilence(); +- collieCancelDelayedSilence(); +-#endif +- if (audio_wr_refcount == 1) { +- Collie_volume_off(); +- Collie_hard_mute_on(); +- Collie_soft_mute_on(); +- sa1100_dma_sleep((dmach_t)COLLIE_SOUND_DMA_CHANNEL); +- +-#if 0 /* H.Hayami SHARP 2001.12.18 */ +-#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0) && \ +- !defined(CONFIG_COLLIE_TR1) && !defined(CONFIG_COLLIE_DEV) +- Collie_volume_off(); +-#endif +-#endif +- Collie_OP_SHDN_off(); +- Collie_soft_DAC_off(); +- Collie_paif_off(); +- Collie_audio_clock_off(); +- //Collie_MIC_on(); +- Collie_DAC_off(); +- Collie_AMP_off(); +- } else { +- sa1100_dma_sleep((dmach_t)COLLIE_SOUND_DMA_CHANNEL); +- } +- Collie_sound_hard_term(); ++ sa1100_dma_sleep((dmach_t)COLLIE_SOUND_DMA_CHANNEL); ++ Collie_audio_power_off(); + break; + case PM_RESUME: +-/***** DEBUG *****g +-printk("collie_sound_pm_callback: audio_wr_refcount=%d\n", audio_wr_refcount); +-*****************/ ++ + #ifdef COLLIE_TRY_ONE + enable_irq(IRQ_GPIO_nREMOCON_INT); + #endif +- +- Collie_sound_hard_init(); +- +- if (audio_wr_refcount == 1) { +- collie_resume = 1; +- +- Collie_audio_power_on(); +- +- sa1100_dma_wakeup((dmach_t)COLLIE_SOUND_DMA_CHANNEL); +-#if 0 /* H.Hayami SHARP 2001.12.18 */ +- Collie_soft_mute_off(); +- Collie_hard_mute_off(); +-#endif +- } else { ++ Collie_sound_hard_init(); /* this needs to be done! */ ++ collie_resume = 1; ++ Collie_audio_power_off(); ++ if (audio_wr_refcount) Collie_audio_power_on(); ++ if (collie_recording) Collie_recording_on(); ++ sa1100_dma_wakeup((dmach_t)COLLIE_SOUND_DMA_CHANNEL); + #ifdef COLLIE_TRY_ONE +- if ( !( GPLR & GPIO_nREMOCON_INT ) ) ++ if ( !( GPLR & GPIO_nREMOCON_INT ) ) + Collie_DAC_on(); + #endif +- sa1100_dma_wakeup((dmach_t)COLLIE_SOUND_DMA_CHANNEL); +- } +- +- + break; +- + } +- LEAVE(TRACE_PM,"collie_sound_pm_callback"); + return 0; + } + #endif + + + #ifdef COLLIE_TRY_ONE +- +-static void collie_audio_on(void) +-{ +- while(1) { +- sleep_on(&audio_on); +- +- /* DAC ON */ +- Collie_DAC_on(); +- // printk("call audio on \n"); +- +- } +-} +- + void Collie_rc_interrupt(int irq, void *dev_id, struct pt_regs *regs) + { +- // printk("int !\n"); +- wake_up(&audio_on); ++ headphone=!headphone; ++ printk("%s headphone \n",headphone ? "connected" : "disconnected"); + } + #endif + +@@ -3038,113 +1561,85 @@ + + int __init Collie_sound_init(void) + { +- int has_sound = 0; +- +- +- ENTER(TRACE_ON,"Collie_sound_init"); +- has_sound = 1; +- sound.mach = machCollie; +- +- if (!has_sound) { +- LEAVE(TRACE_ON,"Collie_sound_init"); +- return -1; +- } +- +-#ifdef TRY_DELAY_OFF /* H.Hayami SHARP 2001.12.19 */ +- sema_init(&df_sem, 1); +- kernel_thread(collieDelayedSilence, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); +-#endif +- + Collie_sound_hard_init(); +- +- if (!sound.mach.irqinit()) { ++ if (!CollieIrqInit()) { + printk("Sound driver: Interrupt initialization failed\n"); +- LEAVE(TRACE_ON,"Collie_sound_init"); + return -1; + } +- +- /* Set up sound queue, /dev/audio and /dev/dsp. */ +- + /* Set default settings. */ + sq_init(); +- + /* Set up /dev/sndstat. */ + state_init(); +- + /* Set up /dev/mixer. */ + mixer_init(); +- + #ifdef MODULE + irq_installed = 1; + #endif +- + printk("Collie Sound Driver Installed\n"); +- + #ifdef CONFIG_PM + collie_sound_pm_dev = pm_register(PM_SYS_DEV, 0, + collie_sound_pm_callback); + #endif +- +- + #ifdef COLLIE_TRY_ONE + /* enable int sw */ + collie_rc_set_int_mode(); +- + /* GPIO15(int):IN, GPIO18(sw):OUT */ + GPDR = ((GPDR)&~GPIO_nREMOCON_INT)|GPIO_REMOCON_ADC_SW; +- + /* GPIO15,18:not Alternate */ + GAFR &= ~(GPIO_nREMOCON_INT|GPIO_REMOCON_ADC_SW); +- ++ /* Initialize headphone state */ ++ headphone=!(GPLR & GPIO_nREMOCON_INT); + /* GPIO15:Falling Edge */ +- set_GPIO_IRQ_edge(GPIO_nREMOCON_INT, GPIO_FALLING_EDGE); +- ++ set_GPIO_IRQ_edge(GPIO_nREMOCON_INT, GPIO_BOTH_EDGES); + /* Register interrupt handler */ + if ( request_irq(IRQ_GPIO_nREMOCON_INT, Collie_rc_interrupt, +- SA_INTERRUPT, "INSERT-HEADPHONE", Collie_rc_interrupt)) { +- printk("%s: request_irq(%d) failed.\n", +- __FUNCTION__, IRQ_GPIO_nREMOCON_INT); +- } ++ SA_INTERRUPT, "headphone", 0)) { ++ printk("headphone: request_irq failed.\n"); + +- /* Make threads */ +- kernel_thread(collie_audio_on, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); ++ } ++ printk("Requested irq collie_rc succesfully (headphone) \n"); ++ printk("Headphone is now %s\n",headphone ? "connected" : "disconnected"); + #endif + +- +- LEAVE(TRACE_ON,"Collie_sound_init"); ++ Collie_audio_power_on(); // decreasing rec. noise? ++ Collie_audio_power_off(); + return 0; + } + +-module_init(Collie_sound_init); +- +- + #ifdef MODULE +- +-int init_module(void) ++static int collie_ssp_init_module(void) + { +- ENTER(TRACE_ON,"init_module"); + Collie_sound_init(); +- LEAVE(TRACE_ON,"init_module"); + return 0; + } + +-void cleanup_module(void) ++static void collie_ssp_cleanup_module(void) + { +- ENTER(TRACE_ON,"cleanup_module"); ++#ifdef CONFIG_PM ++ pm_unregister(collie_sound_pm_dev); ++#endif + if (irq_installed) { +- sound_silence(); +- sound.mach.irqcleanup(); ++ sa1100_dma_stop(COLLIE_SOUND_DMA_CHANNEL); ++ sa1100_dma_flush_all(COLLIE_SOUND_DMA_CHANNEL); ++ Collie_audio_power_off(); ++ sa1100_free_dma(COLLIE_SOUND_DMA_CHANNEL); + } +- +- sq_release_buffers(); +- +- if (mixer_unit >= 0) +- unregister_sound_mixer(mixer_unit); +- if (state_unit >= 0) +- unregister_sound_special(state_unit); +- if (sq_unit >= 0) +- unregister_sound_dsp(sq_unit); +- LEAVE(TRACE_ON,"cleanup_module"); +-} +- ++#ifdef COLLIE_TRY_ONE ++ free_irq(IRQ_GPIO_nREMOCON_INT,0); ++#endif ++ unregister_sound_mixer(mixer_unit); ++ unregister_sound_special(state_unit); ++ unregister_sound_dsp(sq_unit); ++ printk("collie_ssp has to go now, see you later!\n"); ++} ++ ++module_init(collie_ssp_init_module); ++module_exit(collie_ssp_cleanup_module); ++MODULE_DESCRIPTION("Collie 16bit sound driver"); ++MODULE_AUTHOR("SHARP"); ++MODULE_LICENSE("GPL"); ++EXPORT_SYMBOL(Collie_recording_off); ++EXPORT_SYMBOL(Collie_recording_on); ++EXPORT_SYMBOL(collie_recording); + #endif /* MODULE */ ++ +diff -Nuar linux-2.4.18/drivers/sound/collie_tc35143af.c linux-2.4.18p/drivers/sound/collie_tc35143af.c +--- linux-2.4.18/drivers/sound/collie_tc35143af.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.18p/drivers/sound/collie_tc35143af.c 2004-10-13 15:26:20.336631864 +0200 +@@ -0,0 +1,1457 @@ ++/* ++ TODO ++ ++ buzzer compatibility is not fool proof - if an app starts sending buzzer ioctls ++ and then write or read, nothing good will happen / but this api is obsolote anyway ++ ++ mixer_ioctls missing: write/read_mic/igain (there are sane defaults for those) ++ ++ fixed samplerate at 22050hz (mono,s16_le), although it can be changed ++ between 8000-22050hz hardwarewise ++ ++ ++ DONE ++ ++ buffers are only allocated once, and freed when module is unloaded ++ mute left channel when duplex playing & recording ++ cleanup ++ depend on collie_ssp, and call needed functions when needed ++ (recording noise should be gone too as a consequence) ++ lineo's getospace incorporated (getispace left alone) ++ "optimized" default fragsize and number, so there is now no clicking all the time ++ commented out scndctl_dsp_setfragment so that no application can set bad settings (eg.xmms) ++ if you start reading from this device, than it won't let you write later unless you close it first ++ (and vica-versa) ++ speaker is muted if nothing is playing, so noise is gone ++ ++*/ ++ ++#include <linux/module.h> ++#include <linux/sched.h> ++#include <linux/timer.h> ++#include <linux/poll.h> ++#include <linux/major.h> ++#include <linux/config.h> ++#include <linux/fcntl.h> ++#include <linux/errno.h> ++#include <linux/mm.h> ++#include <linux/slab.h> ++#include <linux/sound.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++ ++#include <linux/pm.h> ++ ++#include <asm/system.h> ++#include <asm/irq.h> ++#include <asm/pgtable.h> ++#include <asm/uaccess.h> ++#include <asm/io.h> ++#include <asm/dma.h> ++ ++#include <asm/ucb1200.h> ++#include <linux/soundcard.h> ++#include <asm/proc/cache.h> ++ ++#include <asm/arch/hardware.h> ++#include <asm/arch/tc35143.h> ++ ++#undef DEBUG ++#ifdef DEBUG ++#define DPRINTK( x... ) printk( ##x ) ++#else ++#define DPRINTK( x... ) ++#endif ++ ++extern int collie_recording; ++extern void Collie_recording_on(void); ++extern void Collie_recording_off(void); ++ ++int collie_tc35143f_irq = -1; ++int collie_tc35143f_input_irq = -1; ++ ++#define COLLIE_BUZZER_DMA_CHANNEL (collie_tc35143f_irq) ++#define COLLIE_BUZZER_DMA_CHANNEL_INPUT (collie_tc35143f_input_irq) ++#define COLLIE_GPIO_MIC GPIO_GPIO (17) ++ ++#define SND_NDEVS 256 /* Number of supported devices */ ++#define SND_DEV_CTL 0 /* Control port /dev/mixer */ ++#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM synthesizer and MIDI output) */ ++#define SND_DEV_MIDIN 2 /* Raw midi access */ ++#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */ ++#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */ ++#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */ ++#define SND_DEV_STATUS 6 /* /dev/sndstat */ ++/* #7 not in use now. Was in 2.4. Free for use after v3.0. */ ++#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */ ++#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */ ++#define SND_DEV_PSS SND_DEV_SNDPROC ++ ++#ifdef MODULE ++static int sq_unit = -1; ++static int mixer_unit = -1; ++static int state_unit = -1; ++static int irq_installed = 0; ++#endif /* MODULE */ ++ ++#ifdef CONFIG_PM ++static struct pm_dev* collie_sound_pm_dev; ++#endif ++ ++/*** Some declarations ***********************************************/ ++static int collie_buzzer_volume = 100; ++static int audio_igain = 0; ++static int audio_iamp = 0x05; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19)) ++static struct ucb1x00 * ucbstruct; ++#endif ++static int TC35143f_control_reg_a; ++static int TC35143f_control_reg_b; ++static int TC35143f_mode; ++ ++#define AUDIO_NBFRAGS_DEFAULT 32 ++#define AUDIO_FRAGSIZE_DEFAULT 2048 ++ ++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; /* master owner for buffer allocation */ ++ u_int idx; /* buffer index, so that we know which buffer was sent last*/ ++} audio_buf_t; ++ ++typedef struct { ++ 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 */ ++} audio_stream_t; ++ ++static audio_stream_t output_stream, input_stream; ++ ++#define NEXT_BUF(_s_,_b_) { \ ++ (_s_)->_b_##_idx++; \ ++ (_s_)->_b_##_idx %= (_s_)->nbfrags; \ ++ (_s_)->_b_ = (_s_)->buffers + (_s_)->_b_##_idx; } ++ ++/* Current specs for incoming audio data */ ++static u_int audio_fragsize=AUDIO_FRAGSIZE_DEFAULT; ++static u_int audio_nbfrags=AUDIO_NBFRAGS_DEFAULT; ++ ++static volatile int audio_refcount; /* nbr of concurrent open() for playback */ ++typedef enum { REC,PLAY,NA,BUZZ } collie_tc_status_t; ++static collie_tc_status_t collie_tc_status; ++int collie_tc_muted; ++ ++#define IOCTL_IN(arg, ret) \ ++ do { int error = get_user(ret, (int *)(arg)); \ ++ if (error) return error; \ ++ } while (0) ++#define IOCTL_OUT(arg, ret) ioctl_return((int *)(arg), ret) ++ ++/*** "Translations" ************************************************************/ ++ ++static ssize_t collie_ct_s16(const u_char *userPtr, size_t userCount, ++ u_char frame[], ssize_t *frameUsed, ++ ssize_t frameLeft); ++static signed short ct_out=0; ++/*** Low level stuff *********************************************************/ ++ ++ ++typedef struct { ++ int format; /* AFMT_* */ ++ int stereo; /* 0 = mono, 1 = stereo */ ++ int size; /* 8/16 bit*/ ++ int speed; /* speed */ ++ int volume; ++} SETTINGS; ++ ++static SETTINGS sound; ++ ++#ifdef CONFIG_PM ++//extern int autoPowerCancel; ++#endif ++ ++static void Collie_Set_Volume(int volume); ++static int Collie_Get_Volume(void); ++static int CollieIrqInit(void); ++static int CollieSetFormat(int format); ++static void Collie_sq_interrupt(void*, int); ++static int sq_allocate_buffers(audio_stream_t*); ++static void sq_release_buffers(audio_stream_t*); ++ ++/*** Mid level stuff *********************************************************/ ++static int sound_set_speed(int speed); ++ ++/* ++ * /dev/mixer abstraction ++ */ ++ ++struct sound_mixer { ++ int busy; ++}; ++ ++static struct sound_mixer mixer; ++ ++/* ++ * /dev/sndstat ++ */ ++ ++/*** Common stuff ********************************************************/ ++ ++static long long sound_lseek(struct file *file, long long offset, int orig); ++static inline int ioctl_return(int *addr, int value) ++{ ++ if (value < 0) { ++ return(value); ++ } ++ return put_user(value, addr)? -EFAULT: 0; ++} ++ ++static void wait_ms(int ten_ms) ++{ ++ schedule_timeout(ten_ms); ++} ++ ++/*** Translation ************************************************************/ ++ ++static ssize_t collie_ct_s16(const u_char *userPtr, size_t userCount, ++ u_char frame[], ssize_t *frameUsed, ++ ssize_t frameLeft) ++{ ++ ssize_t count, used; ++ signed short *fp = (unsigned short *) &frame[*frameUsed]; ++ signed short *up = (unsigned short *) userPtr; ++ ++ frameLeft >>= 1; ++ userCount >>= 1; ++ used = count = (userCount < frameLeft) ? userCount : frameLeft; ++ ++ while (count > 0) { ++ signed short data; ++ if (get_user(data, up++)) { ++ return -EFAULT; ++ } /* lowpass filtering, not that it matters much - something is resonating inside the Zaurus at high frequencies ? */ ++ *fp++ = ct_out = (short)( ( (long)data + (long)ct_out ) >> 1LL ); ++ count--; ++ } ++ ++ *frameUsed += used * 2; ++ return used * 2; ++} ++ ++/*** HARDWARE dependent stuff *********************************************************/ ++#define VOL_THRES 10 ++#define CODEC_ASD_NUMERATOR 13 ++/*~ (9216000 / ( 32 * 22050 )) */ ++ ++static int Collie_Sampling_value(void) ++{ ++ int asd = CODEC_ASD_NUMERATOR; ++ DPRINTK("Collie_Sampling_value %x\n",asd); ++ return asd; ++} ++ ++static void Collie_sound_hard_init(void) ++{ ++ int asd; ++ ++ DPRINTK("CollieInit\n"); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19)) ++ ucb1x00_enable(ucbstruct); ++ ucb1x00_io_set_dir(ucbstruct,0, TC35143_GPIO_BUZZER_BIAS); ++ ucb1x00_disable(ucbstruct); ++#else ++ ucb1200_set_io_direction(TC35143_GPIO_BUZZER_BIAS, TC35143_IODIR_OUTPUT); ++#endif ++ ++ DPRINTK("TC35143F Init"); ++ ++ // init MCP ++ asd = Collie_Sampling_value(); ++ Ser4MCCR0 &= ~MCCR0_MCE; ++ Ser4MCCR0 &= ~0xff; ++ Ser4MCCR0 |= (MCCR0_ARE | MCCR0_ATE |MCCR0_ADM | MCCR0_ECS | asd); ++ Ser4MCCR0 |= MCCR0_MCE; ++ Ser4MCSR = 0xffffffff; ++ ++ DPRINTK("Init MCP %x\n",Ser4MCCR0); ++} ++ ++static void Collie_audio_power_on(void) ++{ ++ if ( collie_buzzer_volume > 100 ) collie_buzzer_volume = 100; ++ if ( collie_buzzer_volume < 0 ) collie_buzzer_volume = 0; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19)) ++ ucb1x00_enable(ucbstruct); ++#endif ++ TC35143f_control_reg_a = ( TC35143_VDIV_22KHZ ); ++ TC35143f_control_reg_b = ( TC35143_VADMUTE | TC35143_VHSMUTE | ( 7 - collie_buzzer_volume / 13)); ++ TC35143f_mode = ( TC35143_VOFFCAN | TC35143_VCOF_22_OR_16KHZ ); ++ TC35143f_control_reg_a &= ~(TC35143_VINSEL_MASK | TC35143_VGAIN_MASK | TC35143_VAMP_MASK); ++ TC35143f_control_reg_a |= (TC35143_VINSEL_VBIN2 | ((audio_igain & 0x3)<<11) | ((audio_iamp & 0x0f)<<7)); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19)) ++ ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_B , TC35143f_control_reg_b); ++ ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_A , TC35143f_control_reg_a); ++ ucb1x00_reg_write(ucbstruct,TC35143_MODE_REG , TC35143f_mode ); ++ ucb1x00_io_write(ucbstruct, TC35143_GPIO_BUZZER_BIAS,0); ++ ucb1x00_disable(ucbstruct); ++#else ++ ucb1200_write_reg(TC35143_CONTROL_REG_B , TC35143f_control_reg_b ); ++ ucb1200_write_reg(TC35143_MODE_REG , TC35143f_mode ); ++ ucb1200_write_reg(TC35143_CONTROL_REG_A , TC35143f_control_reg_a ); ++ ucb1200_set_io(TC35143_GPIO_BUZZER_BIAS, TC35143_IODAT_HIGH); ++#endif ++ collie_tc_muted=1; ++} ++ ++static void Collie_audio_power_off(void){ /* Disable sound only */ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19)) ++ ucb1x00_enable(ucbstruct); ++ ucb1x00_io_write(ucbstruct,0, TC35143_GPIO_BUZZER_BIAS); ++#else ++ ucb1200_set_io(TC35143_GPIO_BUZZER_BIAS, TC35143_IODAT_LOW); ++#endif ++ ++ TC35143f_control_reg_a = ( TC35143_VDIV_22KHZ ); ++ TC35143f_control_reg_b = ( TC35143_ALL_MUTE ); ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19)) ++ ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_B , TC35143f_control_reg_b); ++ ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_A , TC35143f_control_reg_a); ++ ucb1x00_disable(ucbstruct); ++#else ++ ucb1200_write_reg(TC35143_CONTROL_REG_B , TC35143f_control_reg_b ); ++ ucb1200_write_reg(TC35143_CONTROL_REG_A , TC35143f_control_reg_a ); ++#endif ++} ++ ++static void collie_tc_mute_on(void){ ++ unsigned int reg_b; ++ unsigned int reg_a; ++ ++ if (!collie_tc_muted) { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19)) ++ ucb1x00_enable(ucbstruct); ++ reg_b = ucb1x00_reg_read(ucbstruct,TC35143_CONTROL_REG_B); ++ reg_a = ucb1x00_reg_read(ucbstruct,TC35143_CONTROL_REG_A); ++#else ++ reg_b = ucb1200_read_reg(TC35143_CONTROL_REG_B); ++ reg_a = ucb1200_read_reg(TC35143_CONTROL_REG_A); ++#endif ++ reg_b &= ~TC35143_VOUT1_EN; ++ reg_a &= ~TC35143_VOUT2_EN; ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19)) ++ ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_A, reg_a); ++ ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_B, reg_b); ++ ucb1x00_disable(ucbstruct); ++#else ++ ucb1200_write_reg(TC35143_CONTROL_REG_A, reg_a); ++ ucb1200_write_reg(TC35143_CONTROL_REG_B, reg_b); ++#endif ++ collie_tc_muted=1; ++ } ++} ++ ++static void collie_tc_mute_off(void){ ++ unsigned int reg_b; ++ unsigned int reg_a; ++ ++ if (collie_tc_muted) { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19)) ++ ucb1x00_enable(ucbstruct); ++ reg_b = ucb1x00_reg_read(ucbstruct,TC35143_CONTROL_REG_B); ++ reg_a = ucb1x00_reg_read(ucbstruct,TC35143_CONTROL_REG_A); ++#else ++ reg_b = ucb1200_read_reg(TC35143_CONTROL_REG_B); ++ reg_a = ucb1200_read_reg(TC35143_CONTROL_REG_A); ++#endif ++ reg_b |= TC35143_VOUT1_EN ; ++ reg_b &= ~7; ++ reg_b |= ( 7 - collie_buzzer_volume / 13); ++ reg_a |= TC35143_VOUT2_EN; ++ reg_a &= ~(TC35143_VGAIN_MASK | TC35143_VAMP_MASK); ++ reg_a |= (((audio_igain & 0x3)<<11) | ((audio_iamp & 0x0f)<<7)); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19)) ++ ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_A, reg_a); ++ ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_B, reg_b); ++ ucb1x00_disable(ucbstruct); ++#else ++ ucb1200_write_reg(TC35143_CONTROL_REG_A, reg_a); ++ ucb1200_write_reg(TC35143_CONTROL_REG_B, reg_b); ++#endif ++ collie_tc_muted=0; ++ } ++} ++ ++ ++static void Collie_volume_set(int dest) ++{ ++ if (collie_buzzer_volume==dest) return; ++ collie_buzzer_volume=dest; ++ collie_tc_mute_on(); ++ collie_tc_mute_off(); ++} ++ ++ ++/*********** GENERAL stuff, same as collie_ssp *******************************/ ++ ++ ++static void Collie_Set_Volume(int volume) ++{ ++ sound.volume = volume & 0xff; ++ sound.volume += ( volume & 0xff00 >> 8); ++ sound.volume >>=1; ++ if (sound.volume>100) sound.volume=100; ++} ++ ++static int Collie_Get_Volume(void) ++{ ++ return ( sound.volume << 8 | sound.volume ); ++} ++ ++static void Collie_sq_interrupt(void* id, int size) ++{ ++ audio_buf_t *b = (audio_buf_t *) id; ++ audio_buf_t *b2 = output_stream.buffers + ((b->idx + 1) % output_stream.nbfrags); ++ ++ /* If this is the last buffer for know, let's mute the speaker */ ++ if (!down_trylock(&b2->sem)) { ++ collie_tc_mute_on(); ++ up(&b2->sem); ++ } ++ ++ /* ++ * Current buffer is sent: wake up any process waiting for it. ++ */ ++ up(&b->sem); ++ /* And any process polling on write. */ ++ wake_up_interruptible(&b->sem.wait); ++ ++ DPRINTK("Collie_sq_interrupt \n"); ++} ++ ++static void Collie_sq_input_interrupt(void* id, int size) ++{ ++ audio_buf_t *b = (audio_buf_t *) id; ++ /* ++ * Current buffer is sent: wake up any process waiting for it. ++ */ ++ b->size = size; ++ up(&b->sem); ++ /* And any process polling on write. */ ++ wake_up_interruptible(&b->sem.wait); ++ /* And indicate which was the last buffer sent */ ++ ++ DPRINTK("Collie_sq_input_interrupt \n"); ++} ++ ++ ++static int __init CollieIrqInit(void) ++{ ++ int err; ++ ++ err = sa1100_request_dma(&COLLIE_BUZZER_DMA_CHANNEL, "buzzer output", ++ DMA_Ser4MCP0Wr); ++ ++ if (err) { ++ return 0; ++ } ++ printk("collie_tc35143f_irq=%d\n", collie_tc35143f_irq); ++ ++ err = sa1100_request_dma(&COLLIE_BUZZER_DMA_CHANNEL_INPUT, "buzzer input", ++ DMA_Ser4MCP0Rd); ++ ++ if (err) { ++ return 0; ++ } ++ printk("collie_tc35143f_input_irq=%d\n", collie_tc35143f_input_irq); ++ ++ ++ sa1100_dma_set_callback(COLLIE_BUZZER_DMA_CHANNEL, ++ (dma_callback_t)Collie_sq_interrupt); ++ ++ sa1100_dma_set_callback(COLLIE_BUZZER_DMA_CHANNEL_INPUT, ++ (dma_callback_t)Collie_sq_input_interrupt); ++ ++ ++ sa1100_dma_stop(COLLIE_BUZZER_DMA_CHANNEL); ++ Collie_audio_power_off(); ++ sa1100_dma_stop(COLLIE_BUZZER_DMA_CHANNEL_INPUT); ++ sa1100_dma_flush_all(COLLIE_BUZZER_DMA_CHANNEL); ++ return(1); ++} ++ ++static int CollieSetFormat(int format) ++{ ++ int size; ++ ++ switch (format) { ++ case AFMT_QUERY: ++ return(sound.format); ++ default: /* This is the only one supported by the hardware it seems */ ++ size = 16; ++ format = AFMT_S16_LE; ++ } ++ sound.format = format; ++ sound.size = size; ++ ++ return(format); ++} ++ ++ ++static int sound_set_speed(int speed) ++{ ++ if (speed < 0) { ++ return(sound.speed); ++ } ++ sound.speed=22050; ++ return(sound.speed); ++} ++ ++/* Higher level stuff ************************************************/ ++ ++/* ++ * /dev/mixer abstraction ++ */ ++ ++static int mixer_open(struct inode *inode, struct file *file) ++{ ++ MOD_INC_USE_COUNT; ++ mixer.busy = 1; ++ return 0; ++} ++ ++static int mixer_release(struct inode *inode, struct file *file) ++{ ++ mixer.busy = 0; ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++ ++static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, ++ u_long arg) ++{ ++ int data; ++ ++ DPRINTK("Got mixer ioctl \n"); ++ ++ switch (cmd) { ++ case SOUND_MIXER_INFO: ++ DPRINTK("0\n"); ++ return 0; ++ case SOUND_OLD_MIXER_INFO: ++ DPRINTK("0\n"); ++ return 0; ++ ++ case SOUND_MIXER_READ_DEVMASK: ++ DPRINTK("1\n"); ++ return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_IGAIN ); ++ case SOUND_MIXER_READ_RECMASK: ++ DPRINTK("2\n"); ++ return IOCTL_OUT(arg, SOUND_MASK_MIC); ++ case SOUND_MIXER_READ_STEREODEVS: ++ DPRINTK("3\n"); ++ return IOCTL_OUT(arg, 0); ++ case SOUND_MIXER_READ_CAPS: ++ DPRINTK("4\n"); ++ return IOCTL_OUT(arg, 0); ++ ++ case SOUND_MIXER_WRITE_VOLUME: ++ IOCTL_IN(arg, data); ++ Collie_Set_Volume(data); ++ DPRINTK("mix_io returning\n"); ++ return IOCTL_OUT(arg, data); ++ case SOUND_MIXER_READ_VOLUME: ++ DPRINTK("5\n"); ++ return IOCTL_OUT(arg, Collie_Get_Volume()); ++ case SOUND_MIXER_READ_TREBLE: ++ DPRINTK("6\n"); ++ return IOCTL_OUT(arg, 0); ++ case SOUND_MIXER_WRITE_TREBLE: ++ DPRINTK("7\n"); ++ return IOCTL_OUT(arg, 0); ++ ++ case SOUND_MIXER_READ_BASS: ++ DPRINTK("6b\n"); ++ return IOCTL_OUT(arg, 0); ++ case SOUND_MIXER_WRITE_BASS: ++ DPRINTK("7b\n"); ++ return IOCTL_OUT(arg, 0); ++ ++ ++ case SOUND_MIXER_WRITE_MIC: ++ case SOUND_MIXER_WRITE_IGAIN: ++ DPRINTK("8\n"); ++ return IOCTL_OUT(arg, 100); ++ case SOUND_MIXER_READ_MIC: ++ case SOUND_MIXER_READ_IGAIN: ++ DPRINTK("9\n"); ++ return IOCTL_OUT(arg, 0); ++ ++ case SOUND_MIXER_READ_SPEAKER: ++ DPRINTK("10\n"); ++ return IOCTL_OUT(arg, 0); ++ case SOUND_MIXER_WRITE_SPEAKER: ++ DPRINTK("11\n"); ++ return IOCTL_OUT(arg, 0); ++ default: ++ DPRINTK("12 %d\n",cmd); ++ return -ENOSYS; ++ } ++ DPRINTK("EINVAL %d??\n",cmd); ++ return -EINVAL; ++} ++ ++ ++static struct file_operations mixer_fops = ++{ ++ llseek: sound_lseek, ++ ioctl: mixer_ioctl, ++ open: mixer_open, ++ release: mixer_release, ++}; ++ ++ ++static void __init mixer_init(void) ++{ ++ mixer_unit = register_sound_mixer(&mixer_fops, -1); ++ if (mixer_unit < 0) { ++ return; ++ } ++ mixer.busy = 0; ++ sound.volume = 100; ++ Collie_volume_set(sound.volume); ++} ++ ++/* This function initializes the buffer ++ */ ++ ++static void sq_clean_buffers(audio_stream_t * s) ++{ ++ int frag; ++ ++ sa1100_dma_flush_all(COLLIE_BUZZER_DMA_CHANNEL); ++ sa1100_dma_flush_all(COLLIE_BUZZER_DMA_CHANNEL_INPUT); ++ ++ s->nbfrags = audio_nbfrags; ++ s->fragsize = audio_fragsize; ++ ++ if (!s->buffers) ++ goto err; ++ ++ for (frag = 0; frag < s->nbfrags; frag++) { ++ audio_buf_t *b = &s->buffers[frag]; ++ b->size=0; ++ sema_init(&b->sem, 1); ++ } ++ s->buf_idx = 0; ++ s->buf = &s->buffers[0]; ++ return; ++ ++err: ++ printk("sound driver : where did the buffer go ??\n "); ++} ++ ++/* This function allocates the buffer structure array and buffer data space ++ * according to the current number of fragments and fragment size. ++ */ ++ ++static int sq_allocate_buffers(audio_stream_t * s) ++{ ++ int frag; ++ int dmasize = 0; ++ char *dmabuf = 0; ++ dma_addr_t dmaphys = 0; ++ ++ DPRINTK("sq_allocate_buffers\n"); ++ ++ if (s->buffers) { ++ return -EBUSY; ++ } ++ ++ s->nbfrags = audio_nbfrags; ++ s->fragsize = audio_fragsize; ++ ++ 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; ++ } ++ ++ b->start = dmabuf; ++ b->dma_addr = dmaphys; ++ b->idx = frag; ++ sema_init(&b->sem, 1); ++ dmabuf += s->fragsize; ++ dmaphys += s->fragsize; ++ dmasize -= s->fragsize; ++ } ++ ++ s->buf_idx = 0; ++ s->buf = &s->buffers[0]; ++ ++ return 0; ++ ++err: ++ printk("sound driver : unable to allocate audio memory\n "); ++ sq_release_buffers(s); ++ return -ENOMEM; ++} ++ ++/* ++ * This function frees all buffers ++ */ ++ ++static void sq_release_buffers(audio_stream_t * s) ++{ ++ DPRINTK("sq_release_buffers\n"); ++ ++ /* ensure DMA won't run anymore */ ++ sa1100_dma_flush_all(COLLIE_BUZZER_DMA_CHANNEL); ++ sa1100_dma_flush_all(COLLIE_BUZZER_DMA_CHANNEL_INPUT); ++ ++ 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; ++} ++ ++static int audio_recording(audio_stream_t * s) ++{ ++ int i; ++ unsigned int reg_b; ++ ++ if (!collie_recording) { ++ /* ++ * Set TC35143 Audio in enable ++ */ ++//// DPRINTK("audio_recording : audio in enable\n"); ++//// reg_b = ucb1200_read_reg(TC35143_CONTROL_REG_B); ++//// reg_b &= ~(TC35143_VADMUTE); ++//// reg_b |= (TC35143_VIN_EN | TC35143_VCLP_CLR); ++//// ucb1200_write_reg(TC35143_CONTROL_REG_B, reg_b); ++ ++ /* ++ * We must ensure there is an output stream at any time while ++ * recording since this is how the TC35143 gets its clock. ++ * So if there is no playback data to send, the output DMA will ++ * spin with all zeroes. ++ */ ++ ++ Collie_recording_on(); ++ collie_tc_mute_off(); /* This is needed for good volume */ ++ DPRINTK("audio_recording : sa1100_dma_set_spin\n"); ++ sa1100_dma_set_spin(COLLIE_BUZZER_DMA_CHANNEL, ++ (dma_addr_t) FLUSH_BASE_PHYS, 2048); ++ ++ /* ++ * Since we just allocated all buffers, we must send them to ++ * the DMA code before receiving data. ++ */ ++ DPRINTK("audio_recording : for loop\n"); ++ for (i = 0; i < s->nbfrags; i++) { ++ audio_buf_t *b = s->buf; ++ down(&b->sem); ++ sa1100_dma_queue_buffer(COLLIE_BUZZER_DMA_CHANNEL_INPUT, (void *) b, ++ b->dma_addr, s->fragsize); ++ NEXT_BUF(s, buf); ++ } ++ DPRINTK("audio_recording : End for loop\n"); ++ ++ /* ++ * Set TC35143 Audio in enable ++ */ ++ DPRINTK("audio_recording : audio in enable\n"); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19)) ++ ucb1x00_enable(ucbstruct); ++ ucb1x00_io_write(ucbstruct, 0, TC35143_GPIO_BUZZER_BIAS); ++ reg_b = ucb1x00_reg_read(ucbstruct,TC35143_CONTROL_REG_B); ++#else ++ ucb1200_set_io(TC35143_GPIO_BUZZER_BIAS, TC35143_IODAT_LOW); ++ reg_b = ucb1200_read_reg(TC35143_CONTROL_REG_B); ++#endif ++ reg_b &= ~(TC35143_VADMUTE); ++ reg_b |= (TC35143_VIN_EN | TC35143_VCLP_CLR); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19)) ++ ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_B, reg_b); ++ ucb1x00_disable(ucbstruct); ++#else ++ ucb1200_write_reg(TC35143_CONTROL_REG_B, reg_b); ++#endif ++ } ++ return 0; ++} ++ ++ ++static int sq_read(struct file *file, char *buffer, ++ size_t count, loff_t * ppos) ++{ ++ char *buffer0 = buffer; ++ audio_stream_t *s = &input_stream; ++ int chunksize, ret = 0; ++ ++ DPRINTK("audio_read: count=%d\n", count); ++ ++ ++ ret = audio_recording(s); ++ ++ if ((collie_tc_status!=NA) && (collie_tc_status!=REC)) ++ return -EPERM; ++ collie_tc_status=REC; ++ ++ if (ret) ++ return ret; ++ ++ /* be sure to have a full sample byte count */ ++ count &= ~0x03; ++ ++// DPRINTK("audio_read : Start while loop\n"); ++ while (count > 0) { ++ audio_buf_t *b = s->buf; ++ ++ /* Wait for a buffer to become full */ ++ if (file->f_flags & O_NONBLOCK) { ++// DPRINTK("audio_read : down_trylock\n"); ++ ret = -EAGAIN; ++ if (down_trylock(&b->sem)) ++ break; ++ } else { ++// DPRINTK("audio_read : down_interruptible\n"); ++ 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); ++ DPRINTK("not copied to buffer \n"); ++ return -EFAULT; ++ } ++ DPRINTK("copied to buffer \n"); ++ ++ 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(COLLIE_BUZZER_DMA_CHANNEL_INPUT, (void *) b, ++ b->dma_addr, s->fragsize); ++ NEXT_BUF(s, buf); ++ } ++// DPRINTK("audio_read : End while loop\n"); ++ ++ if ((buffer - buffer0)) ++ ret = buffer - buffer0; ++// DPRINTK("audio_read: return=%d\n", ret); ++ return ret; ++} ++ ++static ssize_t sq_write(struct file *file, const char *src, size_t uLeft, ++ loff_t *ppos) ++{ ++ const char *buffer0 = src; ++ audio_stream_t *s = &output_stream; ++ u_char *dest; ++ ssize_t uUsed, bUsed, bLeft, ret = 0; ++ ++ DPRINTK("sq_write: uLeft=%d\n", uLeft); ++ ++ if ((collie_tc_status!=NA) && (collie_tc_status!=PLAY)) ++ return -EPERM; ++ ++ collie_tc_status=PLAY; ++ ++ if (!s->buffers && sq_allocate_buffers(s)) { ++ return -ENOMEM; ++ } ++ ++ ++#ifdef CONFIG_PM ++ /* Auto Power off cancel */ ++// autoPowerCancel = 0; ++#endif ++ ++ collie_tc_mute_off(); ++ while (uLeft > 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; ++ } ++ } ++ ++ dest = b->start + b->size; ++ bUsed = 0; ++ bLeft = s->fragsize - b->size; ++ ++ if (collie_ct_s16) { ++ uUsed = collie_ct_s16(src, uLeft, dest, &bUsed, bLeft); ++ cpu_cache_clean_invalidate_range((unsigned long)dest, ++ (unsigned long)(dest+(audio_fragsize)), 0); ++ } else { ++ return -EFAULT; ++ } ++ ++ if (uUsed < 0) { ++ up(&b->sem); ++ return -EFAULT; ++ } ++ src += uUsed; ++ uLeft -= uUsed; ++ b->size += bUsed; ++ ++ if (b->size < s->fragsize) { ++ up(&b->sem); ++ break; ++ } ++ ++ /* Send current buffer to dma */ ++ sa1100_dma_queue_buffer(COLLIE_BUZZER_DMA_CHANNEL, ++ (void *) b, b->dma_addr, b->size); ++ ++ Collie_volume_set(sound.volume); ++ ++ b->size = 0; /* indicate that the buffer has been sent */ ++ NEXT_BUF(s, buf); ++ } ++ ++ if ((src - buffer0)) ++ ret = src - buffer0; ++ DPRINTK("sq_write: return=%d\n", ret); ++ return ret; ++} ++ ++static unsigned int sq_poll(struct file *file, ++ struct poll_table_struct *wait) ++{ ++ unsigned int mask = 0; ++ int i,ret; ++ ++ DPRINTK("sq_poll(): mode=%s%s\n", ++ (file->f_mode & FMODE_READ) ? "r" : "", ++ (file->f_mode & FMODE_WRITE) ? "w" : ""); ++ ++ if ((file->f_mode & FMODE_READ) && (file->f_mode & FMODE_WRITE) && (collie_tc_status==NA)) ++ return mask; ++ ++ if ((file->f_mode & FMODE_WRITE) && (collie_tc_status!=REC)) { ++ if (!output_stream.buffers ++ && sq_allocate_buffers(&output_stream)) { ++ return -ENOMEM; ++ } ++ poll_wait(file, &output_stream.buf->sem.wait, wait); ++ } ++ ++ if ((file->f_mode & FMODE_WRITE) && (collie_tc_status!=REC)) { ++ for (i = 0; i < output_stream.nbfrags; i++) { ++ if (atomic_read(&output_stream.buffers[i].sem.count) > 0) ++ mask |= POLLOUT | POLLWRNORM; ++ } ++ } ++ ++ if ((file->f_mode & FMODE_READ) && (collie_tc_status!=PLAY)) { ++ ret = audio_recording(&input_stream); ++ if (ret<0) { ++ return ret; ++ } ++ poll_wait(file, &input_stream.buf->sem.wait, wait); ++ } ++ ++ if ((file->f_mode & FMODE_READ) && (collie_tc_status!=PLAY)) { ++ for (i = 0; i < input_stream.nbfrags; i++) { ++ if (atomic_read(&input_stream.buffers[i].sem.count) > 0) ++ mask |= POLLIN | POLLRDNORM; ++ } ++ } ++ ++ DPRINTK("sq_poll() returned mask of %s%s\n", ++ (mask & POLLIN) ? "r" : "", ++ (mask & POLLOUT) ? "w" : ""); ++ ++ return mask; ++} ++ ++static int sq_open(struct inode *inode, struct file *file) ++{ ++ DPRINTK("sq_open\n"); ++ ++ if (audio_refcount) { ++ DPRINTK(" sq_open EBUSY\n"); ++ return -EBUSY; ++ } ++ ++ switch (file->f_flags & O_ACCMODE) { ++ case O_WRONLY: ++ collie_tc_status=PLAY; ++ sa1100_dma_stop(COLLIE_BUZZER_DMA_CHANNEL_INPUT); ++ break; ++ case O_RDONLY: ++ collie_tc_status=REC; ++ break; ++ case O_RDWR: ++ collie_tc_status=NA; ++ break; ++ default: ++ DPRINTK(" sq_open EINVAL\n"); ++ return -EINVAL; ++ } ++ ++ MOD_INC_USE_COUNT; ++ audio_refcount++; ++ ++ audio_fragsize = AUDIO_FRAGSIZE_DEFAULT; ++ audio_nbfrags = AUDIO_NBFRAGS_DEFAULT; ++ sq_clean_buffers(&input_stream); ++ sq_clean_buffers(&output_stream); ++ Collie_audio_power_on(); ++ DPRINTK("Going back\n"); ++ return 0; ++} ++ ++static int sq_post(void) ++{ ++ audio_stream_t *s = &output_stream; ++ audio_buf_t *b = s->buf; ++ ++ DPRINTK("sq_post\n"); ++ ++ if (!s->buffers) { ++ return 0; ++ } ++ ++ /* Send half-full buffers */ ++ if (b->size != 0) { ++ DPRINTK("half-full_buf\n"); ++ ++#ifdef CONFIG_PM ++ /* Auto Power off cancel */ ++// autoPowerCancel = 0; ++#endif ++ ++ down(&b->sem); ++ sa1100_dma_queue_buffer(COLLIE_BUZZER_DMA_CHANNEL, ++ (void *) b, b->dma_addr, b->size); ++ b->size = 0; ++ NEXT_BUF(s, buf); ++ } ++ return 0; ++} ++ ++static int sq_fsync(void) ++{ ++ audio_stream_t *s = &output_stream; ++ audio_buf_t *b = s->buf; ++ ++ DPRINTK("sq_fsync\n"); ++ ++ if (!s->buffers) { ++ return 0; ++ } ++ ++ /* Send half-full buffers */ ++ if (b->size != 0) { ++ DPRINTK("half-full_buf\n"); ++ ++#ifdef CONFIG_PM ++ /* Auto Power off cancel */ ++// autoPowerCancel = 0; ++#endif ++ ++ down(&b->sem); ++ sa1100_dma_queue_buffer(COLLIE_BUZZER_DMA_CHANNEL, ++ (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 sq_release(struct inode *inode, struct file *file) ++{ ++ DPRINTK("speaker_sq_release\n"); ++ ++ switch (collie_tc_status) { ++ ++ case REC: ++ sa1100_dma_set_spin(COLLIE_BUZZER_DMA_CHANNEL,0,0); ++ sq_clean_buffers(&input_stream); ++ Collie_recording_off(); ++ break; ++ case PLAY: ++ sq_fsync(); ++ sq_clean_buffers(&output_stream); ++ break; ++ default: ++ break; ++ } ++ audio_refcount = 0; ++ collie_tc_status=NA; ++ sa1100_dma_stop(COLLIE_BUZZER_DMA_CHANNEL); ++ Collie_audio_power_off(); ++ sa1100_dma_stop(COLLIE_BUZZER_DMA_CHANNEL_INPUT); ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++/* Buzzer compatibility */ ++#include "colliebuzzer.h" ++ ++ ++static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, ++ u_long arg) ++{ ++ u_long fmt; ++ int data,ret; ++// audio_buf_info abinfo; ++ ++ DPRINTK("Got ioctl %ld \n",cmd); ++ ++ switch (cmd) { ++ case 22144: ++ sq_write_buzzer(arg); ++ sq_fsync(); ++ return 0; ++ case SNDCTL_DSP_RESET: ++ switch (collie_tc_status) { ++ case REC: ++ sq_clean_buffers(&input_stream); ++ case PLAY: ++ sq_fsync(); ++ sq_clean_buffers(&output_stream); ++ default: ++ break; ++ } ++ return 0; ++ case SNDCTL_DSP_POST: ++ sq_post(); ++ return 0; ++ case SNDCTL_DSP_SYNC: ++ sq_fsync(); ++ return 0; ++ ++ /* ++TeSche: before changing any of these it's ++ * probably wise to wait until sound playing has ++ * settled down. */ ++ case SNDCTL_DSP_SPEED: ++// sq_fsync(file, file->f_dentry); ++ IOCTL_IN(arg, data); ++ return IOCTL_OUT(arg, sound_set_speed(data)); ++ ++ case SOUND_PCM_READ_RATE: ++ return 0; ++ ++ case SNDCTL_DSP_STEREO: ++// sq_fsync(file, file->f_dentry); ++ IOCTL_IN(arg, data); ++ return IOCTL_OUT(arg, 0); ++ case SNDCTL_DSP_CHANNELS: ++// sq_fsync(file, file->f_dentry); ++ IOCTL_IN(arg, data); ++ return IOCTL_OUT(arg, 1); ++ case SNDCTL_DSP_SETFMT: ++// sq_fsync(file, file->f_dentry); ++ IOCTL_IN(arg, data); ++ return IOCTL_OUT(arg, CollieSetFormat(data)); ++ case SNDCTL_DSP_GETFMTS: ++ fmt = AFMT_S16_LE; ++ return IOCTL_OUT(arg, fmt); ++ case SNDCTL_DSP_GETBLKSIZE: ++ return IOCTL_OUT(arg, audio_fragsize); ++ case SNDCTL_DSP_SUBDIVIDE: ++ break; ++ case SNDCTL_DSP_SETFRAGMENT: ++/* if (output_stream.buffers) { ++ return -EBUSY; ++ } ++ get_user(val, (long *) arg); ++ audio_fragsize = 1 << (val & 0xFFFF); ++ if (audio_fragsize < 256) ++ audio_fragsize = 256; ++ if (audio_fragsize > 16384) ++ audio_fragsize = 16384; ++ audio_nbfrags = (val >> 16) & 0x7FFF; ++ if (audio_nbfrags < 2) ++ audio_nbfrags = 2; ++ if (audio_nbfrags * audio_fragsize > 128 * 1024) ++ audio_nbfrags = 128 * 1024 / audio_fragsize; ++ if (sq_allocate_buffers(&output_stream)) { ++ return -ENOMEM; ++ } ++ return 0; ++ case SNDCTL_DSP_GETOSPACE: ++ abinfo.fragsize = audio_fragsize; ++ abinfo.fragstotal = audio_nbfrags; ++ abinfo.fragments = lastsent-output_stream.buf_idx; ++ if (abinfo.fragments<0) ++ abinfo.fragments += abinfo.fragstotal; ++ abinfo.bytes = abinfo.fragments*abinfo.fragsize; ++ return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; ++*/ ++ ++ case SNDCTL_DSP_GETOSPACE: ++ { ++ audio_stream_t *s = &output_stream; ++ audio_buf_info *inf = (audio_buf_info *) arg; ++ int err = verify_area(VERIFY_WRITE, inf, sizeof(*inf)); ++ int i; ++ int frags = 0, bytes = 0; ++ ++ if (err) ++ return err; ++ if (output_stream.buffers) { ++ for (i = 0; i < s->nbfrags; i++) { ++ if (atomic_read(&s->buffers[i].sem.count) > 0) { ++ if (s->buffers[i].size == 0) frags++; ++ bytes += s->fragsize - s->buffers[i].size; ++ } ++ } ++ put_user(s->nbfrags, &inf->fragstotal); ++ put_user(s->fragsize, &inf->fragsize); ++ } else { ++ frags=audio_nbfrags; ++ bytes=frags*audio_fragsize; ++ put_user(frags, &inf->fragstotal); ++ put_user(audio_fragsize, &inf->fragsize); ++ } ++ put_user(frags, &inf->fragments); ++ return put_user(bytes, &inf->bytes); ++ } ++ ++ case SNDCTL_DSP_GETISPACE: ++ { ++ audio_stream_t *s = &input_stream; ++ audio_buf_info *inf = (audio_buf_info *) arg; ++ int err = verify_area(VERIFY_WRITE, inf, sizeof(*inf)); ++ int i; ++ int frags = 0, bytes = 0; ++ ++ if (err) ++ return err; ++ if (input_stream.buffers) ++ for (i = 0; i < s->nbfrags; i++) { ++ if (atomic_read(&s->buffers[i].sem.count) > 0) { ++ if (s->buffers[i].size == s->fragsize) frags++; ++ bytes += s->buffers[i].size; ++ } ++ } ++ else { ++ frags=0; ++ bytes=0; ++ } ++ put_user(frags, &inf->fragments); ++ put_user(s->nbfrags, &inf->fragstotal); ++ put_user(s->fragsize, &inf->fragsize); ++ return put_user(bytes, &inf->bytes); ++ } ++ ++ default: ++ ret = mixer_ioctl(inode, file, cmd, arg); ++ DPRINTK("Returning after mixer_ioctl\n"); ++ return ret; ++ } ++ return -EINVAL; ++} ++ ++static struct file_operations sq_fops = ++{ ++ llseek: sound_lseek, ++ write: sq_write, ++ read: sq_read, ++ poll: sq_poll, ++ ioctl: sq_ioctl, ++ open: sq_open, ++ release: sq_release, ++}; ++ ++ ++static void __init sq_init(void) ++{ ++ sq_unit = register_sound_dsp(&sq_fops, -1); ++ if (sq_unit < 0) { ++ return; ++ } ++ ++ sound.format = AFMT_S16_LE; ++ sound.stereo = 0; ++ sound.speed = 22050; ++ ++ CollieSetFormat(sound.format); ++ Collie_audio_power_off(); ++ input_stream.buf=input_stream.buffers=output_stream.buf=output_stream.buffers=NULL; ++} ++ ++ ++/*** Common stuff ********************************************************/ ++ ++static long long sound_lseek(struct file *file, long long offset, int orig) ++{ ++ return -ESPIPE; ++} ++ ++/*** Power Management ****************************************************/ ++ ++#ifdef CONFIG_PM ++static int collie_sound_pm_callback(struct pm_dev *pm_dev, ++ pm_request_t req, void *data) ++{ ++ switch (req) { ++ case PM_SUSPEND: ++ if (audio_refcount == 1) { ++ sa1100_dma_sleep((dmach_t)COLLIE_BUZZER_DMA_CHANNEL); ++ sa1100_dma_sleep((dmach_t)COLLIE_BUZZER_DMA_CHANNEL_INPUT); ++ Collie_audio_power_off(); ++ } else { ++ sa1100_dma_sleep((dmach_t)COLLIE_BUZZER_DMA_CHANNEL); ++ sa1100_dma_sleep((dmach_t)COLLIE_BUZZER_DMA_CHANNEL_INPUT); ++ } ++ break; ++ case PM_RESUME: ++ Collie_sound_hard_init(); ++// Collie_audio_power_off(); ++ if (audio_refcount == 1) { ++ Collie_audio_power_on(); ++ sa1100_dma_wakeup((dmach_t)COLLIE_BUZZER_DMA_CHANNEL); ++ sa1100_dma_wakeup((dmach_t)COLLIE_BUZZER_DMA_CHANNEL_INPUT); ++ } else { ++ sa1100_dma_wakeup((dmach_t)COLLIE_BUZZER_DMA_CHANNEL); ++ sa1100_dma_wakeup((dmach_t)COLLIE_BUZZER_DMA_CHANNEL_INPUT); ++ } ++ break; ++ } ++ return 0; ++} ++#endif ++ ++/*** Config & Setup ******************************************************/ ++ ++int __init Collie_sound_init(void) ++{ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19)) ++ ucbstruct = ucb1x00_get(); ++#endif ++ if (!CollieIrqInit()) { ++ printk("Sound driver: Interrupt initialization failed\n"); ++ return -1; ++ } ++ Ser4MCDR0 = 0; /* ucb1200_sa1100_set_mcdr0(0); */ ++ ++ Collie_sound_hard_init(); ++ ++ /* Set default settings. */ ++ sq_init(); ++ /* Set up /dev/mixer. */ ++ mixer_init(); ++#ifdef MODULE ++ irq_installed = 1; ++#endif ++ printk("Collie tc35143af Sound Driver Installed\n"); ++#ifdef CONFIG_PM ++ collie_sound_pm_dev = pm_register(PM_SYS_DEV, 0, ++ collie_sound_pm_callback); ++#endif ++ return 0; ++} ++ ++#ifdef MODULE ++static int collie_tc35143_init_module(void) ++{ ++ Collie_sound_init(); ++ sq_allocate_buffers(&output_stream); ++ sq_allocate_buffers(&input_stream); ++ return 0; ++} ++ ++static void collie_tc35143_cleanup_module(void) ++{ ++#ifdef CONFIG_PM ++ pm_unregister(collie_sound_pm_dev); ++#endif ++ if (irq_installed) { ++ sa1100_free_dma(COLLIE_BUZZER_DMA_CHANNEL); ++ sa1100_free_dma(COLLIE_BUZZER_DMA_CHANNEL_INPUT); ++ } ++ ++ sq_release_buffers(&output_stream); ++ sq_release_buffers(&input_stream); ++ unregister_sound_mixer(mixer_unit); ++ unregister_sound_special(state_unit); ++ unregister_sound_dsp(sq_unit); ++ printk("collie_tc35143af has to go now, see you later!\n"); ++} ++ ++module_init(collie_tc35143_init_module); ++module_exit(collie_tc35143_cleanup_module); ++MODULE_DESCRIPTION("Collie tc35143af 16bit sound driver"); ++MODULE_AUTHOR("SHARP"); ++MODULE_LICENSE("GPL"); ++#endif /* MODULE */ ++ +diff -Nuar linux-2.4.18/drivers/sound/Makefile linux-2.4.18p/drivers/sound/Makefile +--- linux-2.4.18/drivers/sound/Makefile 2003-05-13 11:18:36.000000000 +0200 ++++ linux-2.4.18p/drivers/sound/Makefile 2004-10-12 23:11:29.000000000 +0200 +@@ -11,7 +11,7 @@ + msnd.o opl3.o sb_common.o sequencer_syms.o \ + sound_core.o sound_syms.o uart401.o \ + nm256_audio.o ac97.o ac97_codec.o aci.o \ +- sa1100-audio.o pxa-audio.o pxa-ac97.o ++ sa1100-audio.o pxa-audio.o pxa-ac97.o collie_ssp.o + + # Each configuration option enables a list of files. + +@@ -78,7 +78,7 @@ + obj-$(CONFIG_SOUND_SA1111_UDA1341) += sa1111-uda1341.o + obj-$(CONFIG_SOUND_SA1100SSP) += sa1100ssp.o + obj-$(CONFIG_SOUND_COLLIE_SSP) += collie_ssp.o +-obj-$(CONFIG_SOUND_COLLIE_TC35143) += collie-tc35143.o ++obj-$(CONFIG_SOUND_COLLIE_TC35143) += collie_tc35143af.o + obj-$(CONFIG_SOUND_PXA_AC97)+= pxa-ac97.o pxa-audio.o ac97_codec.o + obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o + obj-$(CONFIG_SOUND_RME96XX) += rme96xx.o -- cgit v1.2.3