# This is a cumulative patch consisting of: # # linux-vtcomparison.patch # linux-mkdep.patch # linux-iw241_we16-6.patch # arm-noshortloads.patch # pxa-pcmcia.patch # pxa-smc91x.patch # pxa-usb.patch # pxa-usbeth.patch # pxa-irda.patch # pxa-ac97.patch # pxa-timerint.patch # fb-buffered.patch # fb-turn180.patch # i2c-ds1337.patch # keyb-input.patch # keyb-module.patch # logo-noscrollregion.patch # net-dhcp-timeout.patch # pm.patch # swap-performance.patch # small-nocramdisk.patch # smc91x-ethtool.patch # ucb1x00.patch # vmalloc.patch # usb-sl811.patch # orinoco013e.patch # ramses.patch # ramses-ac97.patch # ramses-keyb.patch # ramses-mtd.patch # ramses-orinoco-ignorecis.patch # ramses-pcmcia.patch # ramses-serial.patch # ramses-smc91x.patch # ramses-sysctl.patch # ramses-ucb1x00-dejitter.patch # ramses-lcd.patch # ramses-usb.patch # ramses-corevolt.patch # wedge.patch # usb-sonycamera.patch # ramses-ucb1x00-rotate.patch # vt-noblank.patch # # Patch managed by http://www.holgerschurig.de/patcher.html # --- linux-2.4.21/Makefile~linux-mkdep +++ linux-2.4.21/Makefile @@ -14,10 +14,11 @@ else echo sh; fi ; fi) TOPDIR := $(shell /bin/pwd) +PATH := /usr/local/arm/3.3/bin:$(PATH) HPATH = $(TOPDIR)/include FINDHPATH = $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net $(HPATH)/math-emu -HOSTCC = gcc +HOSTCC = ccache gcc HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer CROSS_COMPILE = arm-linux- @@ -28,7 +29,7 @@ AS = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld -CC = $(CROSS_COMPILE)gcc +CC = ccache $(CROSS_COMPILE)gcc CPP = $(CC) -E AR = $(CROSS_COMPILE)ar NM = $(CROSS_COMPILE)nm @@ -80,6 +81,7 @@ # makefile but the arguement can be passed to make if needed. # +export INSTALL_MOD_PATH = /tftpboot/ramses2 MODLIB := $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE) export MODLIB @@ -140,7 +142,6 @@ DRIVERS-y += drivers/serial/serial.o \ drivers/char/char.o \ drivers/block/block.o \ - drivers/misc/misc.o \ drivers/net/net.o DRIVERS-$(CONFIG_AGP) += drivers/char/agp/agp.o DRIVERS-$(CONFIG_DRM_NEW) += drivers/char/drm/drm.o @@ -197,6 +198,7 @@ DRIVERS-$(CONFIG_ISDN_BOOL) += drivers/isdn/vmlinux-obj.o DRIVERS-$(CONFIG_PLD) += drivers/pld/pld.o DRIVERS-$(CONFIG_ARCH_AT91RM9200) += drivers/at91/at91drv.o +DRIVERS-y += drivers/misc/misc.o DRIVERS := $(DRIVERS-y) @@ -416,7 +418,7 @@ endif .PHONY: _modinst_post _modinst_post: _modinst_post_pcmcia - if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi +# if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi # Backwards compatibilty symlinks for people still using old versions # of pcmcia-cs with hard coded pathnames on insmod. Remove @@ -495,7 +497,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 @@ -574,3 +576,14 @@ . scripts/mkversion > .version ; \ rpm -ta $(TOPDIR)/../$(KERNELPATH).tar.gz ; \ rm $(TOPDIR)/../$(KERNELPATH).tar.gz + + + +# +# Burn Linux Image for ArmBoot using the bdi2000 +# +burn burn_zImage: + python ../hwtester/burner.py arch/arm/boot/zImage 0x40000 + +publish: arch/arm/boot/zImage + cp arch/arm/boot/zImage /tftpboot/bdi/zImage.testing --- linux-2.4.21/arch/arm/Makefile~arm-noshortloads +++ linux-2.4.21/arch/arm/Makefile @@ -55,8 +55,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) @@ -289,7 +289,7 @@ arch/arm/kernel arch/arm/mm arch/arm/lib: dummy $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@) -bzImage zImage zinstall Image xipImage bootpImage install: vmlinux +bzImage zImage zinstall Image xipImage bootpImage: vmlinux @$(MAKEBOOT) $@ CLEAN_FILES += \ --- linux-2.4.21/arch/arm/config.in~pm +++ linux-2.4.21/arch/arm/config.in @@ -152,6 +152,7 @@ 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 ' M und N Ramses' CONFIG_ARCH_RAMSES $CONFIG_ARCH_PXA dep_bool ' Trizeps-II MT6N' CONFIG_ARCH_TRIZEPS2 $CONFIG_ARCH_PXA if [ "$CONFIG_ARCH_PXA_CERF" = "y" ]; then @@ -586,6 +587,7 @@ tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC dep_bool 'Power Management support (experimental)' CONFIG_PM $CONFIG_EXPERIMENTAL +dep_bool 'Advanced power management emulation support' CONFIG_APM $CONFIG_PM dep_tristate 'RISC OS personality' CONFIG_ARTHUR $CONFIG_CPU_32 string 'Default kernel command string' CONFIG_CMDLINE "" --- /dev/null +++ linux-2.4.21/arch/arm/def-configs/ramses @@ -0,0 +1,1128 @@ +# +# 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_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 + +# +# 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_RAMSES=y +# CONFIG_ARCH_TRIZEPS2 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_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_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_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=y +CONFIG_ZBOOT_ROM_TEXT=00040000 +CONFIG_ZBOOT_ROM_BSS=a00c0000 +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 +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_APM=y +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="debug" +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_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 is not set +CONFIG_MTD_RAMSES=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 +# 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=m +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_BLK_STATS=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=m +# 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=m +CONFIG_NET_IPGRE=m +# 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=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 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=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=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_HERMES=m +CONFIG_PCMCIA_HERMES=m +# CONFIG_AIRO_CS 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 + +# +# 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 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 is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +CONFIG_IRDA=m +CONFIG_IRLAN=m +CONFIG_IRNET=m +CONFIG_IRCOMM=m +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=m +CONFIG_IRPORT_SIR=m +# 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_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_PXA_FIR=m + +# +# 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=m +CONFIG_BLK_DEV_SD=m +CONFIG_SD_EXTRA_DEVS=4 +# 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 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_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_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_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# PCMCIA SCSI adapter support +# +# CONFIG_SCSI_PCMCIA 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_RAMSES_KEYB=y +CONFIG_INPUT_RAMSES_WEDGE=y +# 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=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_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=32 + +# +# 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=m +CONFIG_I2C_PROC=m +# CONFIG_I2C_DS1307 is not set +CONFIG_I2C_DS1337=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_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 is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_AMD_PM768 is not set +# CONFIG_NVRAM is not set +CONFIG_RTC=m +CONFIG_PXA_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 + +# +# PCMCIA character devices +# +# CONFIG_PCMCIA_SERIAL_CS is not set +# CONFIG_SYNCLINK_CS 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 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 +# CONFIG_VIDEO_CYBERPRO 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 + +# +# 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=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=m +# CONFIG_CRAMFS_LINEAR is not set +# CONFIG_CRAMFS_LINEAR_XIP is not set +# CONFIG_ROOT_CRAMFS_LINEAR 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=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=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 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=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_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_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 is not set +# 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=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 + +# +# USB support +# +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set +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_SL811HS_ALT=m +CONFIG_USB_AUDIO=m +CONFIG_USB_EMI26=m +# CONFIG_USB_BLUETOOTH is not set +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 is not set +CONFIG_USB_PRINTER=m +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_KBD=m +# 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_VICAM=m +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DABUSB 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 is not set +# 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 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 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 + +# +# Library routines +# +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y --- linux-2.4.21/arch/arm/mach-pxa/Makefile~pm +++ linux-2.4.21/arch/arm/mach-pxa/Makefile @@ -14,8 +14,11 @@ obj-n := obj- := -export-objs := generic.o irq.o dma.o sa1111.o \ - usb_ctl.o usb_recv.o usb_send.o +export-objs := apm.o generic.o irq.o dma.o sa1111.o \ + usb_ctl.o usb_recv.o usb_send.o pm.o + + +export-objs += ramses.o # Common support (must be linked before board specific support) obj-y += generic.o irq.o dma.o @@ -27,6 +30,7 @@ obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o obj-$(CONFIG_ARCH_PXA_CERF) += cerf.o obj-$(CONFIG_ARCH_PXA_IDP) += idp.o +obj-$(CONFIG_ARCH_RAMSES) += ramses.o obj-$(CONFIG_ARCH_TRIZEPS2) += trizeps2.o # Support for blinky lights @@ -48,6 +52,7 @@ # Misc features obj-$(CONFIG_PM) += pm.o sleep.o +obj-$(CONFIG_APM) += apm.o obj-$(CONFIG_CPU_FREQ) += cpu-pxa.o include $(TOPDIR)/Rules.make --- /dev/null +++ linux-2.4.21/arch/arm/mach-pxa/apm.c @@ -0,0 +1,491 @@ +/* + * bios-less APM driver for ARM Linux + * Jamey Hicks + * adapted from the APM BIOS driver for Linux by Stephen Rothwell (sfr@linuxcare.com) + * + * APM 1.2 Reference: + * Intel Corporation, Microsoft Corporation. Advanced Power Management + * (APM) BIOS Interface Specification, Revision 1.2, February 1996. + * + * [This document is available from Microsoft at: + * http://www.microsoft.com/hwdev/busbios/amp_12.htm] + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_SA1100_H3XXX +#include +#endif + +#include "pm-common.c" + +struct apm_bios_info apm_bios_info = { + /* this driver simulates APM version 1.2 */ + version: 0x102, + flags: APM_32_BIT_SUPPORT +}; + +/* + * The apm_bios device is one of the misc char devices. + * This is its minor number. + */ +#define APM_MINOR_DEV 134 + +/* + * See Documentation/Config.help for the configuration options. + * + * Various options can be changed at boot time as follows: + * (We allow underscores for compatibility with the modules code) + * apm=on/off enable/disable APM + * [no-]power[-_]off power off on shutdown + */ + +/* + * Maximum number of events stored + */ +#define APM_MAX_EVENTS 10 + +/* + * The per-file APM data + */ +struct apm_user { + int magic; + struct apm_user * next; + int suser: 1; + int suspend_wait: 1; + int suspend_result; + int suspends_pending; + int standbys_pending; + int suspends_read; + int standbys_read; + int event_head; + int event_tail; + apm_event_t events[APM_MAX_EVENTS]; +}; + +/* + * The magic number in apm_user + */ +#define APM_BIOS_MAGIC 0x4101 + +/* + * Local variables + */ + +#ifdef CONFIG_APM_RTC_IS_GMT +#define clock_cmos_diff 0 +#define got_clock_diff 1 +#endif +static int apm_disabled; +#ifdef CONFIG_SMP +static int power_off; +#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); +static struct apm_user * user_list = NULL; + +static char driver_version[] = "1.13"; /* no spaces */ + +typedef struct lookup_t { + int key; + char * msg; +} lookup_t; + +static const lookup_t error_table[] = { +/* N/A { APM_SUCCESS, "Operation succeeded" }, */ + { APM_DISABLED, "Power management disabled" }, + { APM_CONNECTED, "Real mode interface already connected" }, + { APM_NOT_CONNECTED, "Interface not connected" }, + { APM_16_CONNECTED, "16 bit interface already connected" }, +/* N/A { APM_16_UNSUPPORTED, "16 bit interface not supported" }, */ + { APM_32_CONNECTED, "32 bit interface already connected" }, + { APM_32_UNSUPPORTED, "32 bit interface not supported" }, + { APM_BAD_DEVICE, "Unrecognized device ID" }, + { APM_BAD_PARAM, "Parameter out of range" }, + { APM_NOT_ENGAGED, "Interface not engaged" }, + { APM_BAD_FUNCTION, "Function not supported" }, + { APM_RESUME_DISABLED, "Resume timer disabled" }, + { APM_BAD_STATE, "Unable to enter requested state" }, +/* N/A { APM_NO_EVENTS, "No events pending" }, */ + { APM_NO_ERROR, "BIOS did not set a return code" }, + { APM_NOT_PRESENT, "No APM present" } +}; +#define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t)) + +static int (*apm_get_power_status)(u_char *ac_line_status, + u_char *battery_status, + u_char *battery_flag, + u_char *battery_percentage, + u_short *battery_life) = 0; + +void apm_register_get_power_status( int (*fn)(u_char *ac_line_status, + u_char *battery_status, + u_char *battery_flag, + u_char *battery_percentage, + u_short *battery_life)) +{ + apm_get_power_status = fn; +} + +static int queue_empty(struct apm_user *as) +{ + return as->event_head == as->event_tail; +} + +static apm_event_t get_queued_event(struct apm_user *as) +{ + as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; + return as->events[as->event_tail]; +} + +static int check_apm_user(struct apm_user *as, const char *func) +{ + if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) { + printk(KERN_ERR "apm: %s passed bad filp\n", func); + return 1; + } + return 0; +} + +static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos) +{ + struct apm_user * as; + int i; + apm_event_t event; + DECLARE_WAITQUEUE(wait, current); + + as = fp->private_data; + if (check_apm_user(as, "read")) + return -EIO; + if (count < sizeof(apm_event_t)) + return -EINVAL; + if (queue_empty(as)) { + if (fp->f_flags & O_NONBLOCK) + return -EAGAIN; + add_wait_queue(&apm_waitqueue, &wait); + printk("do_read: waiting\n"); +repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (queue_empty(as) && !signal_pending(current)) { + schedule(); + goto repeat; + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&apm_waitqueue, &wait); + } + 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; + return -EFAULT; + } + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + as->suspends_read++; + break; + + case APM_SYS_STANDBY: + case APM_USER_STANDBY: + as->standbys_read++; + break; + } + buf += sizeof(event); + i -= sizeof(event); + } + if (i < count) + return count - i; + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + +static unsigned int do_poll(struct file *fp, poll_table * wait) +{ + struct apm_user * as; + + as = fp->private_data; + if (check_apm_user(as, "poll")) + return 0; + poll_wait(fp, &apm_waitqueue, wait); + if (!queue_empty(as)) + return POLLIN | POLLRDNORM; + return 0; +} + +static int do_ioctl(struct inode * inode, struct file *filp, + u_int cmd, u_long arg) +{ + struct apm_user * as; + + as = filp->private_data; + if (check_apm_user(as, "ioctl")) + return -EIO; + if (!as->suser) + return -EPERM; + switch (cmd) { + case APM_IOC_SUSPEND: + pm_suggest_suspend(); + break; + default: + printk("//hs %x\n", cmd); + return -EINVAL; + } + return 0; +} + +static int do_release(struct inode * inode, struct file * filp) +{ + struct apm_user * as; + + as = filp->private_data; + if (check_apm_user(as, "release")) + return 0; + filp->private_data = NULL; + lock_kernel(); + unlock_kernel(); + kfree(as); + return 0; +} + +static int do_open(struct inode * inode, struct file * filp) +{ + struct apm_user * as; + + as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL); + if (as == NULL) { + printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n", + sizeof(*as)); + return -ENOMEM; + } + 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; + /* + * XXX - this is a tiny bit broken, when we consider BSD + * process accounting. If the device is opened by root, we + * instantly flag that we used superuser privs. Who knows, + * we might close the device immediately without doing a + * privileged operation -- cevans + */ + as->suser = capable(CAP_SYS_ADMIN); + as->next = user_list; + user_list = as; + filp->private_data = as; + return 0; +} + +static int apm_get_info(char *buf, char **start, off_t fpos, int length) +{ + char * p; + unsigned short dx; + unsigned short error; + unsigned char ac_line_status = 0xff; + unsigned char battery_status = 0xff; + unsigned char battery_flag = 0xff; + unsigned char percentage = 0xff; + int time_units = -1; + char *units = "?"; + + p = buf; + + if ( (smp_num_cpus == 1) && + apm_get_power_status && + !(error = apm_get_power_status(&ac_line_status, + &battery_status, &battery_flag, &percentage, &dx))) { + if (apm_bios_info.version > 0x100) { + if (dx != 0xffff) { + units = (dx & 0x8000) ? "min" : "sec"; + time_units = dx & 0x7fff; + } + } + } + /* Arguments, with symbols from linux/apm_bios.h. Information is + from the Get Power Status (0x0a) call unless otherwise noted. + + 0) Linux driver version (this will change if format changes) + 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2. + 2) APM flags from APM Installation Check (0x00): + bit 0: APM_16_BIT_SUPPORT + bit 1: APM_32_BIT_SUPPORT + bit 2: APM_IDLE_SLOWS_CLOCK + bit 3: APM_BIOS_DISABLED + bit 4: APM_BIOS_DISENGAGED + 3) AC line status + 0x00: Off-line + 0x01: On-line + 0x02: On backup power (BIOS >= 1.1 only) + 0xff: Unknown + 4) Battery status + 0x00: High + 0x01: Low + 0x02: Critical + 0x03: Charging + 0x04: Selected battery not present (BIOS >= 1.2 only) + 0xff: Unknown + 5) Battery flag + bit 0: High + bit 1: Low + bit 2: Critical + bit 3: Charging + bit 7: No system battery + 0xff: Unknown + 6) Remaining battery life (percentage of charge): + 0-100: valid + -1: Unknown + 7) Remaining battery life (time units): + Number of remaining minutes or seconds + -1: Unknown + 8) min = minutes; sec = seconds */ + + p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", + driver_version, + (apm_bios_info.version >> 8) & 0xff, + apm_bios_info.version & 0xff, + apm_bios_info.flags, + ac_line_status, + battery_status, + battery_flag, + percentage, + time_units, + units); + + return p - buf; +} + +#ifndef MODULE +static int __init apm_setup(char *str) +{ + int invert; + +printk("//hs apm_setup\n"); + 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, "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, + poll: do_poll, + ioctl: do_ioctl, + open: do_open, + release: do_release, +}; + +static struct miscdevice apm_device = { + APM_MINOR_DEV, + "apm_bios", + &apm_bios_fops +}; + +#define APM_INIT_ERROR_RETURN return -1 + +/* + * 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 + * than the fact that we don't trust the APM BIOS. This way, + * most common APM BIOS problems that lead to protection errors + * etc will have at least some level of being contained... + * + * In short, if something bad happens, at least we have a choice + * of just killing the apm thread.. + */ +static int __init apm_init(void) +{ + if (apm_bios_info.version == 0) { + printk(KERN_INFO "apm: BIOS not found.\n"); + APM_INIT_ERROR_RETURN; + } + printk(KERN_INFO + "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n", + ((apm_bios_info.version >> 8) & 0xff), + (apm_bios_info.version & 0xff), + apm_bios_info.flags, + driver_version); + + if (apm_disabled) { + printk(KERN_NOTICE "apm: disabled on user request.\n"); + APM_INIT_ERROR_RETURN; + } + + if (PM_IS_ACTIVE()) { + printk(KERN_NOTICE "apm: overridden by ACPI.\n"); + APM_INIT_ERROR_RETURN; + } + pm_active = 1; + + create_proc_info_entry("apm", 0, NULL, apm_get_info); + + misc_register(&apm_device); + + return 0; +} + +module_init(apm_init); + +#ifdef MODULE +static void __exit apm_exit(void) +{ + misc_deregister(&apm_device); + remove_proc_entry("apm", NULL); + if (power_off) + pm_power_off = NULL; + exit_kapmd = 1; + while (kapmd_running) + schedule(); + pm_active = 0; +} + +module_exit(apm_exit); + +MODULE_AUTHOR("Jamey Hicks, pulling bits from original by Stephen Rothwell"); +MODULE_DESCRIPTION("A minimal emulation of APM"); +MODULE_PARM(power_off, "i"); +MODULE_PARM_DESC(power_off, "Enable power off"); +#endif --- linux-2.4.21/arch/arm/mach-pxa/cpu-pxa.c~ramses-corevolt +++ linux-2.4.21/arch/arm/mach-pxa/cpu-pxa.c @@ -39,7 +39,7 @@ #include -#define DEBUGGING 1 +#define DEBUGGING 0 #if DEBUGGING static unsigned int freq_debug = DEBUGGING; @@ -52,6 +52,7 @@ unsigned int khz; unsigned int cccr; unsigned int pxbus; + unsigned int corevolt; } pxa_freqs_t; #define CCLKCFG_TURBO 0x1 @@ -79,23 +80,23 @@ 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 */ + {199100, 0x141, 99, 115}, /* mem= 99, run=199, turbo=199, PXbus= 99 */ + {298600, 0x1c1, 99, 125}, /* mem= 99, run=199, turbo=298, PXbus= 99 */ + {398100, 0x241, 99, 135}, /* 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 */ + { 99000, 0x121, 50, 105}, /* mem= 99, run= 99, turbo= 99, PXbus= 50 */ +OC( {118000, 0x122, 59, 115},)/* mem=118, run=118, turbo=118, PXbus= 59 OC'd mem */ + {199100, 0x141, 99, 115}, /* mem= 99, run=199, turbo=199, PXbus= 99 */ +OC( {236000, 0x142,118, 125},)/* mem=118, run=236, turbo=236, PXbus=118 OC'd mem */ + {298600, 0x1c1, 99, 125}, /* mem= 99, run=199, turbo=298, PXbus= 99 */ +OC( {354000, 0x1c2,118, 135},)/* mem=118, run=236, turbo=354, PXbus=118 OC'd mem */ + {398099, 0x241, 99, 135}, /* mem= 99, run=199, turbo=398, PXbus= 99 */ + {398100, 0x161,196, 135}, /* mem= 99, run=398, turbo=398, PXbus=196 */ +OC( {471000, 0x162,236, 150},)/* mem=118, run=471, turbo=471, PXbus=236 OC'd mem/core/bus */ {0,0} }; @@ -109,7 +110,7 @@ int i=0; while( pxa_valid_freqs[i].khz) { - if( pxa_valid_freqs[i].khz == khz) + if (pxa_valid_freqs[i].khz == khz) return &pxa_valid_freqs[i]; i++; } @@ -141,14 +142,17 @@ void *ramstart = phys_to_virt(0xa0000000); pxa_freqs_t *freq_info; - if( ! supported) return; + if (! supported) return; freq_info = pxa_get_freq_info( khz); - if( ! freq_info) return; + if (! freq_info) return; + + if (freq_info->corevolt > ramses_corevolt_shadow) + ramses_set_corevolt(freq_info->corevolt); CCCR = freq_info->cccr; - if( freq_debug) + if (freq_debug) printk(KERN_INFO "Changing CPU frequency to %d Mhz (PXbus=%dMhz).\n", khz/1000, freq_info->pxbus); @@ -184,6 +188,9 @@ : "r" (&MDREFR), "r" (CCLKCFG_TURBO|CCLKCFG_FCS), "r" (ramstart) : "r4", "r5"); local_irq_restore(flags); + + if (freq_info->corevolt < ramses_corevolt_shadow) + ramses_set_corevolt(freq_info->corevolt); } static int pxa_init_freqs( void) @@ -191,19 +198,19 @@ int cpu_ver; asm("mrc%? p15, 0, %0, c0, c0" : "=r" (cpu_ver)); - if( (cpu_ver & 0xf) <= PXA250_REV_A1) + if ((cpu_ver & 0xf) <= PXA250_REV_A1) { return 0; } - if( (cpu_ver & 0xf) <= PXA250_REV_B2) + if ((cpu_ver & 0xf) <= PXA250_REV_B2) { - if( freq_debug) printk(KERN_INFO "Using PXA250 frequency points.\n"); + 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"); + if (freq_debug) printk(KERN_INFO "Using PXA255 frequency points.\n"); pxa_valid_freqs = pxa255_valid_freqs; } @@ -212,24 +219,23 @@ static int __init pxa_clk_init(void) { - if( pxa_init_freqs()) + if (pxa_init_freqs()) { - if( freq_debug) printk(KERN_INFO "Registering CPU frequency change support.\n"); + 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"); + 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); } + cpufreq_setfunctions(pxa_validate_speed, pxa_setspeed); return 0; } --- linux-2.4.21/arch/arm/mach-pxa/generic.c~pm +++ linux-2.4.21/arch/arm/mach-pxa/generic.c @@ -28,6 +28,11 @@ #include #include +#ifdef CONFIG_PXA_RTC_HACK +#include +#include +#endif + #include "generic.h" /* @@ -139,4 +144,41 @@ { iotable_init(standard_io_desc); get_clk_frequency_khz( 1); +#ifdef CONFIG_PXA_RTC_HACK + pxa_rtc_hack_init(); +#endif +} + + + +#ifdef CONFIG_PXA_RTC_HACK +unsigned long *save_RCNR = 0; + +void pxa_rtc_hack_init(void) +{ + /* + This has to be here since I guess the bootmem API is the + right choice to allocate the memory during boot + place. And we are sure that timer iqr is not already + running. + - Christian Pellegin + */ + unsigned long pxa_rtc_hack = 0; + + pxa_rtc_hack = meminfo.bank[meminfo.nr_banks-1].start + + meminfo.bank[meminfo.nr_banks-1].size - + PAGE_SIZE; + reserve_bootmem(pxa_rtc_hack, PAGE_SIZE); + printk("Reserved %ld bytes at %lx for RTC hack\n", + PAGE_SIZE, pxa_rtc_hack); + save_RCNR = (unsigned long *) phys_to_virt(pxa_rtc_hack); + if ( (save_RCNR[0] ^ save_RCNR[1]) == 0xffffffff ) { + printk("Restoring saved RCNR value to %ld (from %lx)\n", + save_RCNR[0], (unsigned long) save_RCNR); + RCNR = save_RCNR[0]; + } + else { + printk("No valid saved RCNR value found at %lx\n", (unsigned long) save_RCNR); + } } +#endif /* CONFIG_PXA_RTC_HACK */ --- linux-2.4.21/arch/arm/mach-pxa/generic.h~pm +++ linux-2.4.21/arch/arm/mach-pxa/generic.h @@ -17,3 +17,7 @@ mi->bank[__nr].size = (__size), \ mi->bank[__nr].node = (((unsigned)(__start) - PHYS_OFFSET) >> 27) +#ifdef CONFIG_PXA_RTC_HACK +void pxa_rtc_hack_init(void); +extern unsigned long *save_RCNR; +#endif --- /dev/null +++ linux-2.4.21/arch/arm/mach-pxa/pm-common.c @@ -0,0 +1,285 @@ +/* + * SA1100 Power Management Routines + * + * Copyright (c) 2001 Cliff Brake + * + * 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 & + * Chester Kuo + * Save more value for the resume function! Support + * Bitsy/Assabet/Freebird board + * + * 2001-08-29: Nicolas Pitre + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#ifdef CONFIG_IPAQ_HANDHELD +#include +#endif + +#define __KERNEL_SYSCALLS__ +#include + + + +static char pm_helper_path[128] = "/etc/apm/apmd_proxy"; +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"); + + if (action == PM_RESUME) + argv[i++]="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 + +/* + * 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}, + {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 + --- linux-2.4.21/arch/arm/mach-pxa/pm.c~pm +++ linux-2.4.21/arch/arm/mach-pxa/pm.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -82,7 +83,7 @@ /* * Temporary solution. This won't be necessary once - * we move pxa support into the serial/* driver + * we move pxa support into the serial driver * Save the FF UART */ SAVE(FFIER); @@ -176,7 +177,7 @@ /* * Temporary solution. This won't be necessary once - * we move pxa support into the serial/* driver. + * we move pxa support into the serial driver. * Restore the FF UART. */ RESTORE(FFMCR); @@ -209,6 +210,12 @@ return virt_to_phys(sp); } +#ifndef CONFIG_APM +/* + * This code is only needed if we don't compile in APM support. + * If we compile APM support in, then this code is in pm-common.c + */ + #ifdef CONFIG_SYSCTL /* * ARGH! ACPI people defined CTL_ACPI in linux/acpi.h rather than @@ -263,3 +270,6 @@ __initcall(pm_init); #endif +#endif + +EXPORT_SYMBOL(pm_do_suspend); --- linux-2.4.21/arch/arm/mach-pxa/pxa_usb.h~pxa-usb +++ linux-2.4.21/arch/arm/mach-pxa/pxa_usb.h @@ -39,6 +39,7 @@ int pxa_usb_xmitter_avail( void ); int pxa_usb_send(char *buf, int len, usb_callback_t callback); void sa110a_usb_send_reset(void); +void pxa_usb_send_reset(void); /* in usb_recev.c */ int pxa_usb_recv(char *buf, int len, usb_callback_t callback); --- /dev/null +++ linux-2.4.21/arch/arm/mach-pxa/ramses.c @@ -0,0 +1,844 @@ +/* + * linux/arch/arm/mach-pxa/ramses.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,2003,2004 by M&N Logistik-Lösungen Online GmbH + * written by Holger Schurig + * + * 2001-09-13: Cliff Brake + * Initial code + * + * 2002-10-09: adaptions to ramses + */ + +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_APM +#include +#endif +#define USE_UCB +//#define PFI_LED +#define PFI_TURNOFF + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef USE_UCB +#include "../drivers/misc/ucb1x00.h" +#endif + +#include "generic.h" + + +/* shadow registers for write only registers */ +u16 ramses_control_shadow = + RAMSES_CONTROL_LED_BLUE_ + + RAMSES_CONTROL_LED_ORANGE_ + + RAMSES_CONTROL_SCANNER_WAKE_ + + RAMSES_CONTROL_SCANNER_TRIG_; + +/* various flags the change the behavior of the kernel */ +unsigned int ramses_flags = + RAMSES_FLAGS_KEY_SCAN + + RAMSES_FLAGS_KEY_SUSPEND + + RAMSES_FLAGS_KEY_OFF; + + +/******************************************************************/ +/* Corevoltage settings */ +/******************************************************************/ + +int ramses_corevolt_shadow = 150; + +void ramses_set_corevolt(int volt) +{ + int val = 0; + switch (volt) { + case 150: + val = 5; + break; + case 135: + val = 8; + break; + case 125: + val = 10; + break; + case 115: + val = 12; + break; + case 105: + val = 14; + break; + } + if (val) { + ramses_corevolt_shadow = volt; + RAMSES_COREVOLT = val; + RAMSES_CPLD_PERIPH_PWR |= CORE_VAR_EN; + } +} + + +/******************************************************************/ +/* LCD stuff */ +/******************************************************************/ + +u16 ramses_lcd_type; + +void ramses_lcd_power_on(void) +{ + //printk("--> ramses_lcd_power_on\n"); + + /* 1. VCC */ + RAMSES_CPLD_LCD |= RAMSES_LCD_VCC; + + /* 2. Signal */ + + /* 3. the PWM */ + CKEN |= (CKEN0_PWM0 | CKEN1_PWM1); + + /* 4. nDISPOFF (done at backlight_on time) */ + RAMSES_CPLD_LCD |= RAMSES_LCD_DISPOFF; +} + + +void ramses_lcd_power_off(void) +{ + //printk("--> ramses_lcd_power_off\n"); + if (RAMSES_CPLD_LCD & RAMSES_LCD_DISPOFF) { + //printk("--> turn bl off first\n"); + ramses_lcd_backlight_off(); + } + + /* 1. nDISPOFF (just to be sure) */ + RAMSES_CPLD_LCD &= ~RAMSES_LCD_DISPOFF; + + // for Torisan: wait until all has been sent out + if (ramses_lcd_type == 2) { + int i; + for (i=0; i<33; i++) + udelay(1500); + } + + /* 2. disable the PWM */ + set_GPIO_mode(GPIO16_PWM0 | GPIO_OUT); + set_GPIO_mode(GPIO17_PWM1 | GPIO_OUT); + CKEN &= ~(CKEN0_PWM0 | CKEN1_PWM1); + + /* 3. SIGNAL */ + + /* 4. VCC */ + RAMSES_CPLD_LCD &= ~RAMSES_LCD_VCC; +} + + +void ramses_lcd_backlight_on(void) +{ + int i; + + //printk("--> ramses_lcd_backlight_on\n"); + if ((ramses_control_shadow & RAMSES_CONTROL_LCD_BLIGHT) != 0) + return; + //printk(" state: %d\n", ramses_control_shadow & RAMSES_CONTROL_LCD_BLIGHT); + + set_GPIO_mode(GPIO17_PWM1 | GPIO_OUT); + + /* 4. nDISPOFF */ + RAMSES_CPLD_LCD |= RAMSES_LCD_DISPOFF; + + /* Backlight can be turned on at any time */ + RAMSES_LCD_BLIGHT_ON(); + + for (i=0; i<33; i++) + udelay(1500); + set_GPIO_mode(GPIO16_PWM0_MD); + set_GPIO_mode(GPIO17_PWM1_MD); +} + + +void ramses_lcd_backlight_off(void) +{ + int i; + + //printk("--> ramses_lcd_backlight_off\n"); + if ((ramses_control_shadow & RAMSES_CONTROL_LCD_BLIGHT) == 0) + return; + //printk(" state: %d\n", ramses_control_shadow & RAMSES_CONTROL_LCD_BLIGHT); + + set_GPIO_mode(GPIO17_PWM1 | GPIO_OUT); + for (i=0; i<100; i++) + udelay(1500); + + /* Backlight can be turned off at any time */ + RAMSES_LCD_BLIGHT_OFF(); + udelay(1500); + + /* 1. nDISPOFF */ + if (ramses_lcd_type != 2) + RAMSES_CPLD_LCD &= ~RAMSES_LCD_DISPOFF; + + //set_GPIO_mode(GPIO16_PWM0 | GPIO_IN); + //set_GPIO_mode(GPIO17_PWM1 | GPIO_IN); +} + + +void ramses_lcd_set_brightness(int b) +{ + if (b > 255) b = 255; + if (b < 0) b = 0; + PWM_PWDUTY1 = 510-(b<<1); +} + + +int ramses_lcd_get_brightness(void) +{ + return 255-(PWM_PWDUTY1 >> 1); +} + + +void ramses_lcd_set_contrast(int c) +{ + if (c > 255) c = 255; + if (c < 0) c = 0; + PWM_PWDUTY0 = 542-c; +} + + +int ramses_lcd_get_contrast(void) +{ + return 542-PWM_PWDUTY0; +} + + +void ramses_lcd_set_intensity(int i) +{ + //printk("--> ramses_lcd_set_intensity(%d)\n", i); + if (i) { + ramses_lcd_backlight_on(); + } else { + ramses_lcd_backlight_off(); + } +} + + +int ramses_lcd_get_intensity(void) +{ + return ramses_control_shadow & RAMSES_CONTROL_LCD_BLIGHT; +} + + + + + +/******************************************************************/ +/* HDQ communication */ +/******************************************************************/ + +#define GPIO_HDQ 2 + +#define HDQ_LO GPCR(GPIO_HDQ) = GPIO_bit(GPIO_HDQ) +#define HDQ_HI GPSR(GPIO_HDQ) = GPIO_bit(GPIO_HDQ) +#define HDQ_GET (GPLR(GPIO_HDQ) & (1 << GPIO_HDQ)) + +#define MAXLOOPS 800 +#define MAXTRIES 3 + + +static void hdq_break(void) +{ + HDQ_LO; + set_GPIO_mode(GPIO_HDQ | GPIO_OUT); + udelay(220); + HDQ_HI; + udelay(50); +} + + +/** + * Send data on the 1-bit wire. + * + * LSB first. Depending on the bit, do the low phase short or + * small. The used timings in usec's are made so that our send + * stuff has exactly the timing that the BQ2050 battery sends + * us back. +*/ +static void hdq_put_data(unsigned char cmd) +{ + unsigned char mask = 1; + + HDQ_HI; + set_GPIO_mode(GPIO_HDQ | GPIO_OUT); + + while (1) { + HDQ_LO; + udelay(cmd & mask ? 37 : 115); + HDQ_HI; + udelay(cmd & mask ? 163 : 85); + if (mask == 0x80) break; + mask = mask << 1; + } + set_GPIO_mode(GPIO_HDQ | GPIO_IN); +} + + +/** + * Receive data on the 1-bit wire. + * + * Little state-machine with two states (yuck) that measures the time + * in the low-state. If it exceeds some value, then the bit was a 0, + * otherwise it's a 1. +*/ +static int hdq_get_data(void) +{ + enum { ST_WAITLOW, ST_LOW }; + + int i; + int lastlow = 0; + int state = ST_WAITLOW; + unsigned char mask = 1; + unsigned char d = 0; + + for (i=0; i %08x\n", old_shadow, ramses_control_shadow); + + RAMSES_CPLD_PERIPH_PWR &= ~PER_PWR_EN; + break; + + case PM_RESUME: + RAMSES_CPLD_PERIPH_PWR |= PER_PWR_EN; + ramses_control_shadow = old_shadow; + PWM_CTRL0 = old_ctrl0; + PWM_CTRL1 = old_ctrl1; + PWM_PERVAL0 = old_perval0; + PWM_PERVAL1 = old_perval1; + PWM_PWDUTY0 = old_duty0; + PWM_PWDUTY1 = old_duty1; + + break; + } + return 0; +} + +#endif + + + +static void pf_interrupt(int irq, void *dummy, struct pt_regs *fp) +{ +#ifdef PFI_LED + RAMSES_LED_BLUE_ON(); + RAMSES_LED_ORANGE_ON(); +#endif +#ifdef PFI_TURNOFF + // Make sure we can't be turned on by setting low onto the CPLD's columns + RAMSES_CPLD_KB_COL_LOW = 0; + RAMSES_CPLD_KB_COL_HIGH = 0; + + // turn power off + RAMSES_POWER_OFF(); + + // wait until VCC fades + while (1) { } +#endif +} + + +void ramses_shut_off(void) +{ + // Make sure we can't be turned on by setting low onto the CPLD's columns + RAMSES_CPLD_KB_COL_LOW = 0; + RAMSES_CPLD_KB_COL_HIGH = 0; + //printk("--> ramses_shut_off calling ramses_lcd_backlight_off\n"); + ramses_lcd_backlight_off(); + //printk("--> ramses_shut_off calling ramses_lcd_power_off\n"); + ramses_lcd_power_off(); + + // turn power off + RAMSES_POWER_OFF(); + + // wait until voltage fades + while (1) {} +} + + + + +#ifdef CONFIG_APM +static int ramses_get_power_status(u_char *ac_line_status, + u_char *battery_status, + u_char *battery_flag, + u_char *battery_percentage, + u_short *battery_life) +{ +#ifdef USE_UCB + int adc3; + struct ucb1x00 *ucb = ucb1x00_get(); + + ucb1x00_adc_enable(ucb); + adc3 = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD3, 0); + ucb1x00_adc_disable(ucb); + + /* + * when charged: 0..430 + * when discharging: 0..340 + */ + +#define CHG_LO 165 +#define CHG_HI 420 +#define OFF_LO 60 +#define OFF_HI 350 + if ((RAMSES_CPLD_MISC_STATUS & RAMSES_CHG_STS) == 0) { + // in Docking-Station + if (adc3 > CHG_HI) adc3 = CHG_HI; + if (adc3 < CHG_LO) adc3 = CHG_LO; + adc3 -= CHG_LO; + *battery_percentage = adc3 * 100 / (CHG_HI-CHG_LO); + *ac_line_status = 0x01; + } else { + // offline + if (adc3 > OFF_HI) adc3 = OFF_HI; + if (adc3 < OFF_LO) adc3 = OFF_LO; + adc3 -= OFF_LO; + *battery_percentage = adc3 * 100 / (OFF_HI-OFF_LO); + *ac_line_status = 0x00; + } + + if (*battery_percentage > 100) + *battery_percentage = 100; + + if (*ac_line_status) { + *battery_status = 3; // charging + *battery_flag = 1<<3; + } else + if (*battery_percentage >= 30) { + *battery_status = 0; // high + *battery_flag = 1<<0; + } else + if (*battery_percentage >= 15) { + *battery_status = 1; // low + *battery_flag = 1<<1; + } else { + *battery_status = 2; // critical + *battery_flag = 1<<2; + } + + // assume 5.5 hours operation, 330 minutes + *battery_life = (*battery_percentage * 330 / 100) | 0x8000; +#endif + + +#ifdef USE_HDQ +#error HDQ + // SAE is something like mAh * 10 + int sae, sael; + + sael = ramses_hdq_get_reg(HDQ_SAEL); + sae = ramses_hdq_get_reg(HDQ_SAEH); + + if (sae == -1 || sael == -1) { + //printk("ramses: could not read HDQ_SAE\n"); + *ac_line_status = 0xff; + *battery_status = 0xff; + *battery_flag = 0xff; + *battery_percentage = 0xff; + *battery_life = -1; + return 0; + } + + sae = (sae << 16) + sael; + if (sae > 27000) { + printk("ramses: capped HDQ_SAE from %d to 27000\n", sae); + sae = 27000; + } + + if (sae < 4000) { + *battery_status = 2; // critical + *battery_flag = 1<<2; + } else + if (sae < 10000) { + *battery_status = 1; // low + *battery_flag = 1<<1; + } else { + *battery_status = 0; // high + *battery_flag = 1<<0; + } + + if ((RAMSES_CPLD_MISC_STATUS & RAMSES_CHG_STS) == 0) { + *battery_status = 3; // charging + *battery_flag = 1<<3; + *ac_line_status = 0x01; // online + } else { + *ac_line_status = 0x00; // offline + } + + *battery_percentage = sae / 270; + *battery_life = (sae / 56) | 0x8000; +#endif + + +#if !defined(USE_UCB) && !defined(USE_HDQ) +#error NONE + *ac_line_status = 0xff; + *battery_status = 0xff; + *battery_flag = 0xff; + *battery_percentage = 0xff; + *battery_life = -1; +#endif + + return 0; +} +#endif + + + + +/******************************************************************/ +/* Initialisation */ +/******************************************************************/ + +static struct map_desc ramses_io_desc[] __initdata = { + /* virtual physical length domain r w c b */ + { RAMSES_IDE_BASE, RAMSES_IDE_PHYS, RAMSES_IDE_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { RAMSES_ETH_BASE, RAMSES_ETH_PHYS, RAMSES_ETH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { RAMSES_COREVOLT_BASE, RAMSES_COREVOLT_PHYS, RAMSES_COREVOLT_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { RAMSES_CPLD_BASE, RAMSES_CPLD_PHYS, RAMSES_CPLD_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { RAMSES_CONTROL_BASE, RAMSES_CONTROL_PHYS, RAMSES_CONTROL_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC +}; + + + + + +/* + * Uncompressing Linux...... done, booting the kernel. + * Linux version 2.4.19-rmk4-pxa1-mn ... + * CPU: Intel XScale-PXA250 revision 4 + * Machine: Ramses + * fixup_ramses() + */ + +static void __init +fixup_ramses(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + SET_BANK (0, 0xa0000000,128*1024*1024); + mi->nr_banks = 1; +} + + + + +/* + * fixup_ramses() + * ramses_map_io() + */ + +static void __init ramses_map_io(void) +{ + u16 smc_eeprom_read(long ioaddr, u16 location); + + pxa_map_io(); + iotable_init(ramses_io_desc); + +#ifdef IPAQ + // set power managament stuff + PGSR0 = GPSRx_SleepValue; + PGSR1 = GPSRy_SleepValue; + PGSR2 = GPSRz_SleepValue; + PWER = PWER_GPIO0 | PWER_RTC; + PFER = PWER_GPIO0 | PWER_RTC; + PRER = 0; +#endif + + ramses_lcd_type = smc_eeprom_read(RAMSES_ETH_BASE+0x300, RAMSES_LCD_TYPE_OFFSET); + // here we could make a special case about ramses_lcd_type == 0xffff + ramses_flags |= (ramses_lcd_type & RAMSES_FLAGS_LCD_FBTURN); +} + + + + +/* + * ramses_map_io() + * Memory clock: 99.53MHz (*27) + * Run Mode clock: 199.07MHz (*2) + * Turbo Mode clock: 398.13MHz (*2.0, active) * On node 0 totalpages: 16384 + * zone(0): 32768 pages. + * zone(1): 0 pages. + * zone(2): 0 pages. + * Kernel command line: root=/dev/nfsroot ... + * ramses_init_irq() + */ + +static void __init ramses_init_irq(void) +{ + set_GPIO_IRQ_edge(21, GPIO_FALLING_EDGE); // UCB 1400 + + RAMSES_SCANNER_OFF(); + RAMSES_GSM_OFF(); + RAMSES_GSM_RESET_OFF(); + RAMSES_GSM_BOOT_OFF(); + pxa_init_irq(); +} + + + + +/* + * ramses_init_irq() + * Console: colour dummy device 80x30 + * serial_console_init + * serial_console_setup + * Calibrating delay loop... 397.31 BogoMIPS + * Memory: 128MB = 128MB total + * Memory: 127872KB available (1355K code, 272K data, 112K init) + * Dentry cache hash table entries: 16384 (order: 5, 131072 bytes) + * Inode cache hash table entries: 8192 (order: 4, 65536 bytes) + * Mount-cache hash table entries: 2048 (order: 2, 16384 bytes) + * Buffer-cache hash table entries: 8192 (order: 3, 32768 bytes) + * Page-cache hash table entries: 32768 (order: 5, 131072 bytes) + * POSIX conformance testing by UNIFIX + * Linux NET4.0 for Linux 2.4 + * Based upon Swansea University Computer Society NET3.039 + * Initializing RT netlink socket + * ramses_init() + */ + +static int __init ramses_init(void) +{ + unsigned int irq_gpio_pin; + + // Set IRQ for Touchpanel (via UCB 1400) + irq_gpio_pin = IRQ_TO_GPIO_2_80(TOUCH_PANEL_IRQ); + set_GPIO_IRQ_edge(irq_gpio_pin, TOUCH_PANEL_IRQ_EDGE); + + // Set IRQ for Power Fail Interrupt + set_GPIO_IRQ_edge(1, GPIO_FALLING_EDGE); + request_irq(IRQ_GPIO(1), pf_interrupt, 0, "PWR FAIL", NULL); + + // Setup IRQ edge for Ethernet + //set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(27), GPIO_RISING_EDGE); + set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(ETHERNET_IRQ), ETHERNET_IRQ_EDGE); + + // Configure PWMs for LCD + PWM_CTRL0 = 0; + PWM_PERVAL0 = 512; + PWM_PWDUTY0 = 440; + PWM_CTRL1 = 0; + PWM_PERVAL1 = 512; + PWM_PWDUTY1 = 450; + + // Request Memory Regions of core components + request_mem_region(RAMSES_CONTROL_BASE, RAMSES_CONTROL_SIZE, "Ramses Control"); + request_mem_region(RAMSES_CPLD_BASE, RAMSES_CPLD_SIZE, "Ramses CPLD"); + request_mem_region(RAMSES_COREVOLT_BASE, RAMSES_COREVOLT_SIZE, "Ramses Corevolt"); + +#ifdef CONFIG_PM +#ifdef PM_DEBUG + pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ramses_pm_callback, "ramses"); +#else + pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ramses_pm_callback); +#endif + //TODO PWER (PXA255: 3-25) + //TODO PRER (PXA255: 3-26) + //TODO PFER (PXA255: 3-27) + //TODO PSSR (PXA255: 3-29) + //TODO PGSR0..PGSR2 (PXA255: 3-32) +#endif + +#ifdef CONFIG_APM + apm_register_get_power_status(ramses_get_power_status); +#endif + + PCFR = PCFR_OPDE | PCFR_FS | PCFR_FP; // PXA255: 3-24 + + pm_power_off = ramses_shut_off; + + return 0; +} + +__initcall(ramses_init); + + + +/* + * ramses_init() + * Using PXA255 frequency points. + * Registering CPU frequency change support. + * CPU clock: 398.131 MHz (99.000-400.000 MHz) + * Starting kswapd + * devfs: v1.12a (20020514) Richard Gooch (rgooch@atnf.csiro.au) + * devfs: boot_options: 0x1 + * pty: 256 Unix98 ptys configured + * pxa & ti16c754b serial driver + * tts/0 at irq 14 is a PXA UART + * tts/1 at irq 13 is a PXA UART + * tts/2 at irq 12 is a PXA UART + * tts/3 at irq 45 is a TI16750 + * tts/4 at irq 46 is a TI16750 + * tts/5 at irq 47 is a TI16750 + * tts/6 at irq 48 is a TI16750 + * LAN91C111: You shouldn't use auto-probing with insmod! + * SMSC LAN91C111 Driver (v2.2), (Linux Kernel 2.4 + Support for Odd Byte) ... + * eth0: SMC91C11xFD(rev:1) at 0xf0100300 IRQ:26 MEMSIZE ... + * ac97_codec: AC97 Audio codec, id: 0x5053:0x4304 (Philips UCB1400) + * NET4: Linux TCP/IP 1.0 for NET4.0 + * IP Protocols: ICMP, UDP, TCP + * IP: routing cache hash table of 512 buckets, 4Kbytes + * TCP: Hash tables configured (established 4096 bind 4096) + * IP-Config: ... + * NET4: Unix domain sockets 1.0/SMP for Linux NET4.0. + * NetWinder Floating Point Emulator V0.95 (c) 1998-1999 Rebel.com + * Looking up port of RPC 100003/2 on 192.168.233.66 + * Looking up port of RPC 100005/1 on 192.168.233.66 + * VFS: Mounted root (nfs filesystem). + * Mounted devfs on /dev + * Freeing init memory: 68K + * INIT: version 2.84 booting + */ + + + +MACHINE_START(RAMSES, "Ramses") + MAINTAINER("M&N Logistik-Lösungen Online GmbH") + BOOT_MEM(0xa0000000, 0x40000000, 0xfc000000) + BOOT_PARAMS(0xa0000100) + FIXUP(fixup_ramses) + MAPIO(ramses_map_io) + INITIRQ(ramses_init_irq) +MACHINE_END + +EXPORT_SYMBOL(ramses_lcd_type); +EXPORT_SYMBOL(ramses_lcd_power_on); +EXPORT_SYMBOL(ramses_lcd_power_off); +EXPORT_SYMBOL(ramses_lcd_backlight_on); +EXPORT_SYMBOL(ramses_lcd_backlight_off); +EXPORT_SYMBOL(ramses_lcd_set_intensity); +EXPORT_SYMBOL(ramses_lcd_set_brightness); +EXPORT_SYMBOL(ramses_lcd_set_contrast); +EXPORT_SYMBOL(ramses_lcd_get_intensity); +EXPORT_SYMBOL(ramses_lcd_get_brightness); +EXPORT_SYMBOL(ramses_lcd_get_contrast); +EXPORT_SYMBOL(ramses_hdq_get_reg); +EXPORT_SYMBOL(ramses_set_corevolt); +EXPORT_SYMBOL(ramses_corevolt_shadow); --- linux-2.4.21/arch/arm/mach-pxa/usb-char.c~pxa-usb +++ linux-2.4.21/arch/arm/mach-pxa/usb-char.c @@ -211,7 +211,6 @@ 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; @@ -220,6 +219,7 @@ if ( machine_is_extenex1() ) { #ifdef CONFIG_SA1100_EXTENEX1 + string_desc_t * pString; pDesc->dev.idVendor = make_word_c( 0xC9F ); pDesc->dev.idProduct = 1; pDesc->dev.bcdDevice = make_word_c( 0x0001 ); --- linux-2.4.21/arch/arm/mach-pxa/usb-eth.c~pxa-usbeth +++ linux-2.4.21/arch/arm/mach-pxa/usb-eth.c @@ -52,6 +52,7 @@ #define ETHERNET_VENDOR_ID 0x49f #define ETHERNET_PRODUCT_ID 0x505A +#define ETHERNET_DEVICE_ID 0x0200 #define MAX_PACKET 32768 #define MIN(a, b) (((a) < (b)) ? (a) : (b)) @@ -329,6 +330,7 @@ pd->b.ep2.wMaxPacketSize = make_word( usb_wsize ); pd->dev.idVendor = ETHERNET_VENDOR_ID; pd->dev.idProduct = ETHERNET_PRODUCT_ID; + pd->dev.bcdDevice = ETHERNET_DEVICE_ID; pstr = pxa_usb_kmalloc_string_descriptor( "PXA USB NIC" ); if ( pstr ) { pxa_usb_set_string_descriptor( 1, pstr ); --- linux-2.4.21/drivers/char/Config.in~i2c-ds1337 +++ linux-2.4.21/drivers/char/Config.in @@ -164,6 +164,7 @@ if [ "$CONFIG_I2C" != "n" ]; then dep_tristate ' DS1307 RTC' CONFIG_I2C_DS1307 $CONFIG_I2C + dep_tristate ' DS1337 RTC' CONFIG_I2C_DS1337 $CONFIG_I2C fi source drivers/l3/Config.in --- linux-2.4.21/drivers/char/Makefile~i2c-ds1337 +++ linux-2.4.21/drivers/char/Makefile @@ -21,10 +21,11 @@ # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. -export-objs := busmouse.o console.o keyboard.o sysrq.o \ +export-objs := vt.o busmouse.o console.o keyboard.o sysrq.o \ misc.o pty.o random.o selection.o serial.o \ sonypi.o tty_io.o tty_ioctl.o generic_serial.o \ - au1000_gpio.o hp_psaux.o nvram.o scx200.o + au1000_gpio.o hp_psaux.o nvram.o scx200.o \ + input_keyb.o mod-subdirs := joystick ftape drm drm-4.0 pcmcia @@ -129,6 +130,11 @@ ifeq ($(CONFIG_SA1100_CERF_CPLD),y) KEYBD += cerf_keyb.o endif + ifeq ($(CONFIG_ARCH_RAMSES),y) + KEYMAP = german.o + KEYBD += input_keyb.o + obj-m += sysctl.o + endif ifeq ($(CONFIG_ARCH_FORTUNET),y) KEYMAP := defkeymap.o endif @@ -337,6 +343,7 @@ # I2C char devices obj-$(CONFIG_I2C_DS1307) += ds1307.o +obj-$(CONFIG_I2C_DS1337) += ds1337.o subdir-$(CONFIG_MWAVE) += mwave ifeq ($(CONFIG_MWAVE),y) @@ -372,4 +379,7 @@ set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@ qtronixmap.c: qtronixmap.map + set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@ + +german.c: german.map set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@ --- linux-2.4.21/drivers/char/console.c~keyb-module +++ linux-2.4.21/drivers/char/console.c @@ -150,7 +150,7 @@ static int con_open(struct tty_struct *, struct file *); static void vc_init(unsigned int console, unsigned int rows, unsigned int cols, int do_clear); -static void blank_screen(unsigned long dummy); +//static void blank_screen(unsigned long dummy); static void gotoxy(int currcons, int new_x, int new_y); static void save_cur(int currcons); static void reset_terminal(int currcons, int do_clear); @@ -158,7 +158,7 @@ static void set_vesa_blanking(unsigned long arg); static void set_cursor(int currcons); static void hide_cursor(int currcons); -static void unblank_screen_t(unsigned long dummy); +//static void unblank_screen_t(unsigned long dummy); static void console_callback(void *ignored); static int printable; /* Is console ready for printing? */ @@ -167,7 +167,7 @@ int console_blanked; static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ -static int blankinterval = 10*60*HZ; +//static int blankinterval = 10*60*HZ; static int vesa_off_interval; static struct tq_struct console_callback_tq = { @@ -209,9 +209,9 @@ * Hook so that the power management routines can (un)blank * the console on our behalf. */ -int (*console_blank_hook)(int); +//int (*console_blank_hook)(int); -static struct timer_list console_timer; +//static struct timer_list console_timer; /* * Low-Level Functions @@ -543,7 +543,7 @@ static void set_cursor(int currcons) { - if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS) + if (!IS_FG || vcmode == KD_GRAPHICS) return; if (deccm) { if (currcons == sel_cons) @@ -1287,7 +1287,7 @@ update_attr(currcons); break; case 9: /* set blanking interval */ - blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ; + //blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ; poke_blanked_console(); break; case 10: /* set bell frequency in Hz */ @@ -2575,11 +2575,11 @@ if (tty_register_driver(&console_driver)) panic("Couldn't register console driver\n"); - init_timer(&console_timer); - console_timer.function = blank_screen; - if (blankinterval) { - mod_timer(&console_timer, jiffies + blankinterval); - } + //init_timer(&console_timer); + //console_timer.function = blank_screen; + //if (blankinterval) { + // mod_timer(&console_timer, jiffies + blankinterval); + //} /* * kmalloc is not running yet - we use the bootmem allocator. @@ -2744,11 +2744,12 @@ */ static void vesa_powerdown_screen(unsigned long dummy) { - console_timer.function = unblank_screen_t; + //console_timer.function = unblank_screen_t; vesa_powerdown(); } +#if 0 static void timer_do_blank_screen(int entering_gfx, int from_timer_handler) { int currcons = fg_console; @@ -2797,12 +2798,14 @@ if (vesa_blank_mode) sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1); } +#endif void do_blank_screen(int entering_gfx) { - timer_do_blank_screen(entering_gfx, 0); + //timer_do_blank_screen(entering_gfx, 0); } +#if 0 /* * This is a timer handler */ @@ -2810,12 +2813,14 @@ { unblank_screen(); } +#endif /* * Called by timer as well as from vt_console_driver */ void unblank_screen(void) { +#if 0 int currcons; if (!console_blanked) @@ -2842,6 +2847,7 @@ /* Low-level driver cannot restore -> do it ourselves */ update_screen(fg_console); set_cursor(fg_console); +#endif } /* @@ -2849,11 +2855,12 @@ */ static void blank_screen(unsigned long dummy) { - timer_do_blank_screen(0, 1); + //timer_do_blank_screen(0, 1); } void poke_blanked_console(void) { +#if 0 del_timer(&console_timer); if (!vt_cons[fg_console] || vt_cons[fg_console]->vc_mode == KD_GRAPHICS) return; @@ -2863,6 +2870,7 @@ } else if (blankinterval) { mod_timer(&console_timer, jiffies + blankinterval); } +#endif } /* @@ -3088,7 +3096,7 @@ unblank_screen(); break; case PM_SUSPEND: - do_blank_screen(0); + //do_blank_screen(0); break; } return 0; @@ -3106,7 +3114,8 @@ EXPORT_SYMBOL(video_scan_lines); EXPORT_SYMBOL(vc_resize); EXPORT_SYMBOL(fg_console); -EXPORT_SYMBOL(console_blank_hook); +//EXPORT_SYMBOL(console_blank_hook); +EXPORT_SYMBOL(console_driver); #ifdef CONFIG_VT EXPORT_SYMBOL(vt_cons); #endif --- /dev/null +++ linux-2.4.21/drivers/char/ds1337.c @@ -0,0 +1,545 @@ +/* + * ds1337.c + * + * Device driver for Dallas Semiconductor's Real Time Controller DS1337. + * + * Copyright (C) 2003 M&N Logistik-Lösungen Online GmbH + * + * 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. + * + * Documentation for this Chip: http://pdfserv.maxim-ic.com/arpdf/DS1337.pdf + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ds1337.h" + +//#define DEBUG 1 + +#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 = DS1337_I2C_SLAVE_ADDR; +struct i2c_driver ds1337_driver; +struct i2c_client *ds1337_i2c_client = 0; +static spinlock_t ds1337_rtc_lock = SPIN_LOCK_UNLOCKED; + +static unsigned short ignore[] = { I2C_CLIENT_END }; +static unsigned short normal_addr[] = { DS1337_I2C_SLAVE_ADDR, I2C_CLIENT_END }; + +static int ds1337_rtc_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +static int ds1337_rtc_noop(struct inode *inode, struct file *file); + +static int ds1337_probe(struct i2c_adapter *adap); +static int ds1337_detach(struct i2c_client *client); +static int ds1337_command(struct i2c_client *client, unsigned int cmd, void *arg); + + +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 struct file_operations rtc_fops = { + .owner = THIS_MODULE, + .ioctl = ds1337_rtc_ioctl, + .open = ds1337_rtc_noop, + .release = ds1337_rtc_noop, +}; + +static struct miscdevice ds1337_rtc_miscdev = { + RTC_MINOR, + "rtc", + &rtc_fops +}; + + +struct i2c_driver ds1337_driver = { + .name = "DS1337", + .id = I2C_DRIVERID_DS1337, + .flags = I2C_DF_NOTIFY, + .attach_adapter = ds1337_probe, + .detach_client = ds1337_detach, + .command = ds1337_command +}; + +#define DAT(x) ((unsigned int)((x)->data)) /* keep the control register info */ + + +static int ds1337_readram(char *buf, int len) +{ + unsigned long flags; + unsigned char ad[1] = { 0 }; + int ret; + struct i2c_msg msgs[2] = { + {ds1337_i2c_client->addr, 0, 1, ad}, + {ds1337_i2c_client->addr, I2C_M_RD, len, buf} + }; + + spin_lock_irqsave(&ds1337_rtc_lock, flags); + ret = i2c_transfer(ds1337_i2c_client->adapter, msgs, 2); + spin_unlock_irqrestore(&ds1337_rtc_lock, flags); + + return ret; +} + + +static void ds1337_setreg(struct i2c_client *c, unsigned char reg, unsigned char val) +{ + unsigned char buf[2]; + buf[0] = reg; + buf[1] = val; + i2c_master_send(c, (char *) buf, 2); +} + +static int ds1337_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct i2c_client *c; + unsigned char buf[DS1337_MEM_SIZE], ad[1] = { 7 }; + struct i2c_msg msgs[2] = { + {addr, 0, 1, ad}, + {addr, I2C_M_RD, 1, buf} + }; + int ret; + + if (rtc_debug>1) + printk("%s(adap,%d,%d,%d)\n", __FUNCTION__, addr, flags, kind); + + c = (struct i2c_client *) kmalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return -ENOMEM; + + strcpy(c->name, "DS1337"); + c->id = ds1337_driver.id; + c->flags = 0; + c->addr = addr; + c->adapter = adap; + c->driver = &ds1337_driver; + c->data = NULL; + + ret = i2c_transfer(c->adapter, msgs, 2); + + if (ret == 2) { + DAT(c) = buf[0]; + } else + printk("ds1337_attach(): i2c_transfer() returned %d.\n", ret); + + ds1337_i2c_client = c; + + ds1337_readram(buf, DS1337_MEM_SIZE); + + // set 24 hour mode + ds1337_setreg(c, 0x2, buf[2] | DS1337_HOUR24); + // INTCN sets INTB to alarm2 (disables SQW) + ds1337_setreg(c, 0x5, buf[5] & 0x7f); // clear century + ds1337_setreg(c, 0x7, 0x00); // clear Alarm 1 seconds + ds1337_setreg(c, 0x8, 0x00); // clear Alarm 1 minutes + ds1337_setreg(c, 0x9, 0x40); // clear Alarm 1 hours, 24 hour on + ds1337_setreg(c, 0xA, 0x00); // clear Alarm 1 date + ds1337_setreg(c, 0xB, 0x00); // clear Alarm 2 minutes + ds1337_setreg(c, 0xC, 0x40); // clear Alarm 2 hours, 24 hour on + ds1337_setreg(c, 0xD, 0x00); // clear Alarm 2 date + ds1337_setreg(c, 0xe, 4); // nEOSC enabled + ds1337_setreg(c, 0xf, 0); // clear OSF, A2F, A1F + + return i2c_attach_client(c); +} + + +static int ds1337_probe(struct i2c_adapter *adap) +{ + if (rtc_debug>1) + printk("%s()\n", __FUNCTION__); + + return i2c_probe(adap, &addr_data, ds1337_attach); +} + + +static int ds1337_detach(struct i2c_client *client) +{ + if (rtc_debug>1) + printk("%s()\n", __FUNCTION__); + + i2c_detach_client(client); + + return 0; +} + + +static void ds1337_convert_to_time(struct rtc_time *dt, char *buf) +{ + if (rtc_debug>1) + printk("%s()\n", __FUNCTION__); + + dt->tm_sec = BCD_TO_BIN(buf[0]); + dt->tm_min = BCD_TO_BIN(buf[1]); + dt->tm_hour = DS1337_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("ds1337_get_datetime: year = %d\n", dt->tm_year); + printk("ds1337_get_datetime: mon = %d\n", dt->tm_mon); + printk("ds1337_get_datetime: mday = %d\n", dt->tm_mday); + printk("ds1337_get_datetime: hour = %d\n", dt->tm_hour); + printk("ds1337_get_datetime: min = %d\n", dt->tm_min); + printk("ds1337_get_datetime: sec = %d\n", dt->tm_sec); + } +} + + +static int ds1337_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; + + if (rtc_debug) + printk("%s()\n", __FUNCTION__); + + memset(buf, 0, sizeof(buf)); + + ret = i2c_transfer(client->adapter, msgs, 2); + + if (ret == 2) { + ds1337_convert_to_time(dt, buf); + ret = 0; + } else + printk("ds1337_get_datetime(), i2c_transfer() returned %d\n", ret); + + return ret; +} + + +static int ds1337_set_datetime(struct i2c_client *client, + struct rtc_time *dt, int datetoo) +{ + unsigned char buf[8]; + int ret, len = 4; + + if (rtc_debug) + printk("%s()\n", __FUNCTION__); + + if (rtc_debug > 2) { + printk("ds1337_set_datetime: tm_year = %d\n", dt->tm_year); + printk("ds1337_set_datetime: tm_mon = %d\n", dt->tm_mon); + printk("ds1337_set_datetime: tm_mday = %d\n", dt->tm_mday); + printk("ds1337_set_datetime: tm_hour = %d\n", dt->tm_hour); + printk("ds1337_set_datetime: tm_min = %d\n", dt->tm_min); + printk("ds1337_set_datetime: tm_sec = %d\n", dt->tm_sec); + } + + buf[0] = 0; /* register address on DS1337 */ + buf[1] = (BIN_TO_BCD(dt->tm_sec)); + buf[2] = (BIN_TO_BCD(dt->tm_min)); + buf[3] = (BIN_TO_BCD(dt->tm_hour)) | DS1337_HOUR24; + + 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("ds1337_set_datetime(), i2c_master_send() returned %d\n", + ret); + + + return ret; +} + + +#if 0 +static int ds1337_get_ctrl(struct i2c_client *client, unsigned char *ctrl) +{ + *ctrl = DAT(client); + + if (rtc_debug) + printk("%s():%d\n", __FUNCTION__, *ctrl); + + return 0; +} + + +static int ds1337_set_ctrl(struct i2c_client *client, unsigned char *cinfo) +{ + unsigned char buf[2]; + int ret; + + if (rtc_debug) + printk("%s(%d)\n", __FUNCTION__, *cinfo); + + buf[0] = 7; /* control register address on DS1337 */ + 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; +} +#endif + + +static int ds1337_command(struct i2c_client *client, unsigned int cmd, + void *arg) +{ + if (rtc_debug) + printk("%s(client,,%u,arg)\n", __FUNCTION__, cmd); + + switch (cmd) { + case DS1337_GETDATETIME: + return ds1337_get_datetime(client, arg); + + case DS1337_SETTIME: + return ds1337_set_datetime(client, arg, 0); + + case DS1337_SETDATETIME: + return ds1337_set_datetime(client, arg, 1); + + default: + return -EINVAL; + } +} + + +static int ds1337_rtc_noop(struct inode *inode, struct file *file) +{ + return 0; +} + + +static int ds1337_rtc_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned long flags; + struct rtc_time wtime; + int status = 0; + + if (rtc_debug) + printk("%s()\n", __FUNCTION__); + + switch (cmd) { + default: + case RTC_UIE_ON: // mask ints from RTC updates + case RTC_UIE_OFF: + case RTC_PIE_ON: // allow periodic interrupts + case RTC_PIE_OFF: + case RTC_AIE_ON: // mask alarm int enable bit + case RTC_AIE_OFF: + case RTC_ALM_SET: + /* + * This expects a struct rtc_time. Writing 0xff means + * "don't care" or "match all". Only the tm_hour, + * tm_min and tm_sec are used. + */ + case RTC_ALM_READ: + // get_rtc_alm_time(&wtime); + case RTC_IRQP_READ: // Read the periodic IRQ rate + case RTC_IRQP_SET: // Set periodic IRQ rate + case RTC_EPOCH_READ: + // return put_user (epoch, (unsigned long *)arg); + case RTC_EPOCH_SET: + case RTC_WKALM_SET: + case RTC_WKALM_RD: + status = -EINVAL; + break; + + case RTC_RD_TIME: + spin_lock_irqsave(&ds1337_rtc_lock, flags); + ds1337_command(ds1337_i2c_client, DS1337_GETDATETIME, &wtime); + spin_unlock_irqrestore(&ds1337_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(&ds1337_rtc_lock, flags); + ds1337_command(ds1337_i2c_client, DS1337_SETDATETIME, &wtime); + spin_unlock_irqrestore(&ds1337_rtc_lock, flags); + break; + } + + return status; +} + + +static char *ds1337_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 ds1337_rtc_proc_output(char *buf) +{ +#define CHECK(ctrl,bit) ((ctrl & bit) ? "yes" : "no") + + unsigned char ram[DS1337_MEM_SIZE]; + int ret; + + char *p = buf; + + ret = ds1337_readram(ram, DS1337_MEM_SIZE); + if (ret > 0) { +#ifdef DEBUG + int i; + char text[9]; +#endif + struct rtc_time dt; + + p += sprintf(p, "DS1337 (i2c Serial Real Time Clock)\n"); + + ds1337_convert_to_time(&dt, ram); + p += sprintf(p, "Date/Time: %02d-%s-%04d %02d:%02d:%02d\n", + dt.tm_mday, ds1337_mon2str(dt.tm_mon), + dt.tm_year + 1900, dt.tm_hour, dt.tm_min, dt.tm_sec); + +#ifdef DEBUG + p += sprintf(p, "RAM dump:\n"); + text[8] = '\0'; + for (i = 0; i < DS1337_MEM_SIZE; i++) { + if ((i % 8) == 0) + p += sprintf(p, "%02X: ", 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"); +#endif + } else { + p += sprintf(p, "Failed to read RTC memory!\n"); + } + + return p - buf; +} + + +static int ds1337_rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = ds1337_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 ds1337_init(void) +{ + int retval = 0; + + if (rtc_debug>1) + printk("%s()\n", __FUNCTION__); + + if (slave_address != 0xffff) { + normal_addr[0] = slave_address; + } + + if (normal_addr[0] == 0xffff) { + printk(KERN_ERR + "I2C: Invalid slave address for DS1337 RTC (%#x)\n", + normal_addr[0]); + return -EINVAL; + } + + retval = i2c_add_driver(&ds1337_driver); + + if (retval == 0) { + misc_register(&ds1337_rtc_miscdev); + create_proc_read_entry(DS1337_PROC_NAME, 0, 0, + ds1337_rtc_read_proc, NULL); + printk("I2C: DS1337 RTC driver loaded\n"); + } + return retval; +} + + +static __exit void ds1337_exit(void) +{ + if (rtc_debug>1) + printk("%s()\n", __FUNCTION__); + + remove_proc_entry(DS1337_PROC_NAME, NULL); + misc_deregister(&ds1337_rtc_miscdev); + i2c_del_driver(&ds1337_driver); +} + + +module_init(ds1337_init); +module_exit(ds1337_exit); + +MODULE_PARM(slave_address, "i"); +MODULE_PARM_DESC(slave_address, "I2C slave address for DS1337 RTC"); + +MODULE_AUTHOR("M&N Logistik-Lösungen Online GmbH"); +MODULE_LICENSE("GPL"); --- /dev/null +++ linux-2.4.21/drivers/char/ds1337.h @@ -0,0 +1,43 @@ +/* + * ds1337.h + * + * Copyright (C) 2003 M&N Logistik-Lösungen Online GmbH + * + * 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 DS1337_H +#define DS1337_H + +#define DS1337_I2C_SLAVE_ADDR 0x68 +//#define DS1337_RAM_ADDR_START 0x10 +//#define DS1337_RAM_ADDR_END 0x10 +#define DS1337_MEM_SIZE 0x10 + +#define DS1337_PROC_NAME "driver/ds1337" + +struct rtc_mem { + unsigned int loc; + unsigned int nr; + unsigned char *data; +}; + +#define DS1337_GETDATETIME 0 +#define DS1337_SETTIME 1 +#define DS1337_SETDATETIME 2 + +#define DS1337_RATE_1HZ 0x00 /* Rate Select 1 Hz */ +#define DS1337_RATE_4096HZ 0x01 /* Rate Select 4096 kHz */ +#define DS1337_RATE_8192HZ 0x02 /* Rate Select 8192 kHz */ +#define DS1337_RATE_32768HZ 0x03 /* Rate Select 32768 kHz */ + +#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10) +#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10) + +#define DS1337_HOUR12 0x40 +#define DS1337_HOUR24 0x00 +#define DS1337_HOURS_24(val) BCD_TO_BIN((val & 0x3f)) + +#endif --- /dev/null +++ linux-2.4.21/drivers/char/german.map @@ -0,0 +1,528 @@ +keymaps 0-2,4-6,8-10,12 +keycode 1 = Escape Escape + alt keycode 1 = Meta_Escape + shift alt keycode 1 = Meta_Escape +keycode 2 = one exclam + alt keycode 2 = Meta_one + shift alt keycode 2 = Meta_exclam +keycode 3 = two quotedbl twosuperior nul + alt keycode 3 = Meta_two + shift alt keycode 3 = Meta_quotedbl + control alt keycode 3 = Meta_nul +keycode 4 = three section threesuperior Escape + alt keycode 4 = Meta_three + control alt keycode 4 = Meta_Escape +keycode 5 = four dollar + alt keycode 5 = Meta_four + shift alt keycode 5 = Meta_dollar +keycode 6 = five percent + alt keycode 6 = Meta_five + shift alt keycode 6 = Meta_percent +keycode 7 = six ampersand + control keycode 7 = Control_asciicircum + alt keycode 7 = Meta_six + shift alt keycode 7 = Meta_ampersand +keycode 8 = seven slash braceleft + alt keycode 8 = Meta_seven + shift alt keycode 8 = Meta_slash + altgr alt keycode 8 = Meta_braceleft +keycode 9 = eight parenleft bracketleft + alt keycode 9 = Meta_eight + shift alt keycode 9 = Meta_parenleft + altgr alt keycode 9 = Meta_bracketleft +keycode 10 = nine parenright bracketright + altgr control keycode 10 = Control_bracketright + alt keycode 10 = Meta_nine + shift alt keycode 10 = Meta_parenright + altgr alt keycode 10 = Meta_bracketright +keycode 11 = zero equal braceright + alt keycode 11 = Meta_zero + shift alt keycode 11 = Meta_equal + altgr alt keycode 11 = Meta_braceright +keycode 12 = ssharp question backslash + altgr control keycode 12 = Control_backslash + shift alt keycode 12 = Meta_question + altgr alt keycode 12 = Meta_backslash +keycode 13 = apostrophe grave + alt keycode 13 = 0x08b4 + shift alt keycode 13 = Meta_grave +keycode 14 = BackSpace Delete + alt keycode 14 = Meta_BackSpace + shift alt keycode 14 = Meta_Delete +keycode 15 = Tab Tab + alt keycode 15 = Meta_Tab + shift alt keycode 15 = Meta_Tab +keycode 16 = +q +Q at Control_q Control_q Control_q Meta_q Meta_Q Meta_at Meta_Control_q +keycode 17 = w +keycode 18 = +e +E currency Control_e Control_e Control_e Meta_e Meta_E Meta_e Meta_Control_e +keycode 19 = r +keycode 20 = t +keycode 21 = z +keycode 22 = u +keycode 23 = i +keycode 24 = o +keycode 25 = p +keycode 26 = +udiaeresis +Udiaeresis +keycode 27 = plus asterisk asciitilde + alt keycode 27 = Meta_plus + shift alt keycode 27 = Meta_asterisk +keycode 28 = Return + alt keycode 28 = Meta_Control_m +keycode 29 = Control +keycode 30 = a +keycode 31 = s +keycode 32 = d +keycode 33 = f +keycode 34 = g +keycode 35 = h +keycode 36 = j +keycode 37 = k +keycode 38 = l +keycode 39 = +odiaeresis +Odiaeresis +keycode 40 = +adiaeresis +Adiaeresis +keycode 41 = asciicircum degree Meta_asciicircum Control_asciicircum + control alt keycode 41 = Meta_Control_asciicircum +keycode 42 = Shift +keycode 43 = numbersign apostrophe + alt keycode 43 = Meta_numbersign + shift alt keycode 43 = Meta_apostrophe +keycode 44 = y +keycode 45 = x +keycode 46 = c +keycode 47 = v +keycode 48 = b +keycode 49 = n +keycode 50 = +m +M mu Control_m Control_m Control_m Meta_m Meta_M Meta_m Meta_Control_m +keycode 51 = comma semicolon + alt keycode 51 = Meta_comma + shift alt keycode 51 = Meta_semicolon +keycode 52 = period colon + alt keycode 52 = Meta_period + shift alt keycode 52 = Meta_colon +keycode 53 = minus underscore Meta_minus + shift control keycode 53 = Control_underscore + alt keycode 53 = Meta_minus + shift alt keycode 53 = Meta_underscore +keycode 54 = Shift +keycode 55 = KP_Multiply + altgr keycode 55 = Hex_C +keycode 56 = Alt +keycode 57 = space space Meta_space nul + alt keycode 57 = Meta_space + shift alt keycode 57 = Meta_space + control alt keycode 57 = Meta_nul +keycode 58 = Caps_Lock +keycode 59 = F1 F13 Console_13 F25 + altgr control keycode 59 = F1 + alt keycode 59 = Console_1 + control alt keycode 59 = Console_1 +keycode 60 = F2 F14 Console_14 F26 + altgr control keycode 60 = F2 + alt keycode 60 = Console_2 + control alt keycode 60 = Console_2 +keycode 61 = F3 F15 Console_15 F27 + altgr control keycode 61 = F3 + alt keycode 61 = Console_3 + control alt keycode 61 = Console_3 +keycode 62 = F4 F16 Console_16 F28 + altgr control keycode 62 = F4 + alt keycode 62 = Console_4 + control alt keycode 62 = Console_4 +keycode 63 = F5 F17 Console_17 F29 + altgr control keycode 63 = F5 + alt keycode 63 = Console_5 + control alt keycode 63 = Console_5 +keycode 64 = F6 F18 Console_18 F30 + altgr control keycode 64 = F6 + alt keycode 64 = Console_6 + control alt keycode 64 = Console_6 +keycode 65 = F7 F19 Console_19 F31 + altgr control keycode 65 = F7 + alt keycode 65 = Console_7 + control alt keycode 65 = Console_7 +keycode 66 = F8 F20 Console_20 F32 + altgr control keycode 66 = F8 + alt keycode 66 = Console_8 + control alt keycode 66 = Console_8 +keycode 67 = F9 F21 Console_21 F33 + altgr control keycode 67 = F9 + alt keycode 67 = Console_9 + control alt keycode 67 = Console_9 +keycode 68 = F10 F22 Console_22 F34 + altgr control keycode 68 = F10 + alt keycode 68 = Console_10 + control alt keycode 68 = Console_10 +keycode 69 = Num_Lock + altgr keycode 69 = Hex_A +keycode 70 = Scroll_Lock Show_Memory Show_Registers Show_State + alt keycode 70 = Scroll_Lock +keycode 71 = KP_7 + altgr keycode 71 = Hex_7 + alt keycode 71 = Ascii_7 +keycode 72 = KP_8 + altgr keycode 72 = Hex_8 + alt keycode 72 = Ascii_8 +keycode 73 = KP_9 + altgr keycode 73 = Hex_9 + alt keycode 73 = Ascii_9 +keycode 74 = KP_Subtract + altgr keycode 74 = Hex_D +keycode 75 = KP_4 + altgr keycode 75 = Hex_4 + alt keycode 75 = Ascii_4 +keycode 76 = KP_5 + altgr keycode 76 = Hex_5 + alt keycode 76 = Ascii_5 +keycode 77 = KP_6 + altgr keycode 77 = Hex_6 + alt keycode 77 = Ascii_6 +keycode 78 = KP_Add + altgr keycode 78 = Hex_E +keycode 79 = KP_1 + altgr keycode 79 = Hex_1 + alt keycode 79 = Ascii_1 +keycode 80 = KP_2 + altgr keycode 80 = Hex_2 + alt keycode 80 = Ascii_2 +keycode 81 = KP_3 + altgr keycode 81 = Hex_3 + alt keycode 81 = Ascii_3 +keycode 82 = KP_0 + altgr keycode 82 = Hex_0 + alt keycode 82 = Ascii_0 +keycode 83 = KP_Comma + 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 + shift alt keycode 86 = Meta_greater + altgr alt keycode 86 = Meta_bar +keycode 87 = F11 F23 Console_23 F35 + altgr control keycode 87 = F11 + alt keycode 87 = Console_11 + control alt keycode 87 = Console_11 +keycode 88 = F12 F24 Console_24 F36 + altgr control keycode 88 = F12 + alt keycode 88 = Console_12 + control alt keycode 88 = Console_12 +keycode 89 = slash question degree + alt keycode 89 = Meta_slash + shift alt keycode 89 = Meta_question +keycode 90 = +keycode 91 = +keycode 92 = +keycode 93 = +keycode 94 = +keycode 95 = +keycode 96 = KP_Enter + altgr keycode 96 = Hex_F +keycode 97 = Control +keycode 98 = KP_Divide + altgr keycode 98 = Hex_B +keycode 99 = Compose +keycode 100 = AltGr + alt keycode 100 = Compose +keycode 101 = Break +keycode 102 = Find +keycode 103 = Up + alt keycode 103 = KeyboardSignal +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 + shift alt keycode 112 = VoidSymbol + altgr alt keycode 112 = VoidSymbol +keycode 113 = F13 + shift alt keycode 113 = VoidSymbol + altgr alt keycode 113 = VoidSymbol +keycode 114 = F14 + shift alt keycode 114 = VoidSymbol + altgr alt keycode 114 = VoidSymbol +keycode 115 = Help + shift alt keycode 115 = VoidSymbol + altgr alt keycode 115 = VoidSymbol +keycode 116 = Do + shift alt keycode 116 = VoidSymbol + altgr alt keycode 116 = VoidSymbol +keycode 117 = F17 + shift alt keycode 117 = VoidSymbol + altgr alt keycode 117 = VoidSymbol +keycode 118 = KP_MinPlus + shift alt keycode 118 = VoidSymbol + altgr alt keycode 118 = VoidSymbol +keycode 119 = Pause +keycode 120 = +keycode 121 = +keycode 122 = +keycode 123 = +keycode 124 = +#keycode 125 = Decr_Console +#keycode 126 = Incr_Console +keycode 127 = Compose +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 '!' '!' to 'Ą' +compose '"' 'A' to 'Ä' +compose '"' 'E' to 'Ë' +compose '"' 'I' to 'Ď' +compose '"' 'O' to 'Ö' +compose '"' 'U' to 'Ü' +compose '"' 'Y' to 'ž' +compose '"' 'a' to 'ä' +compose '"' 'c' to 'Š' +compose '"' 'e' to 'ë' +compose '"' 'i' to 'ď' +compose '"' 'o' to 'ö' +compose '"' 'r' to 'Ž' +compose '"' 'u' to 'ü' +compose '"' 'y' to '˙' +compose '(' 'c' to 'Š' +compose '(' 'r' to 'Ž' +compose '+' '-' to 'ą' +compose ',' 'A' to 'Ą' +compose ',' 'C' to 'Ç' +compose ',' 'E' to 'Ę' +compose ',' 'G' to 'Ť' +compose ',' 'I' to 'Ç' +compose ',' 'K' to 'Ó' +compose ',' 'L' to 'Ś' +compose ',' 'N' to 'Ń' +compose ',' 'R' to 'Ł' +compose ',' 'S' to 'Ş' +compose ',' 'T' to 'Ţ' +compose ',' 'U' to 'Ů' +compose ',' 'a' to 'ą' +compose ',' 'c' to 'ç' +compose ',' 'e' to 'ę' +compose ',' 'g' to 'ť' +compose ',' 'i' to 'ç' +compose ',' 'k' to 'ó' +compose ',' 'l' to 'ś' +compose ',' 'n' to 'ń' +compose ',' 'r' to 'ł' +compose ',' 's' to 'ş' +compose ',' 't' to 'ţ' +compose ',' 'u' to 'ů' +compose '-' ':' to '÷' +compose '-' 'A' to 'Ş' +compose '-' 'C' to '˘' +compose '-' 'D' to 'Đ' +compose '-' 'E' to '¤' +compose '-' 'H' to 'Ą' +compose '-' 'L' to 'Ł' +compose '-' 'O' to 'ş' +compose '-' 'T' to 'Ź' +compose '-' 'Y' to 'Ľ' +compose '-' 'a' to 'Ş' +compose '-' 'c' to '˘' +compose '-' 'd' to 'đ' +compose '-' 'e' to '¤' +compose '-' 'h' to 'ą' +compose '-' 'l' to 'Ł' +compose '-' 'l' to 'Ľ' +compose '-' 'l' to 'ł' +compose '-' 'o' to 'ş' +compose '-' 't' to 'ź' +compose '.' '.' to 'ˇ' +compose '.' 'C' to 'Ĺ' +compose '.' 'C' to 'Ő' +compose '.' 'E' to 'Ě' +compose '.' 'I' to 'Š' +compose '.' 'Z' to 'Ż' +compose '.' 'c' to 'ĺ' +compose '.' 'c' to 'ő' +compose '.' 'e' to 'ě' +compose '.' 'i' to 'š' +compose '.' 'z' to 'ż' +compose '/' 'D' to 'Đ' +compose '/' 'L' to 'Ł' +compose '/' 'O' to 'Ř' +compose '/' 'T' to 'Ź' +compose '/' 'c' to '˘' +compose '/' 'd' to 'đ' +compose '/' 'l' to 'ł' +compose '/' 'o' to 'ř' +compose '/' 't' to 'ź' +compose '0' 'A' to 'Ĺ' +compose '0' 'U' to 'Ů' +compose '0' 'a' to 'ĺ' +compose '0' 'u' to 'ů' +compose '1' '2' to '˝' +compose '1' '4' to 'ź' +compose '3' '4' to 'ž' +compose ':' '-' to '÷' +compose ':' 'A' to 'Ä' +compose ':' 'E' to 'Ë' +compose ':' 'O' to 'Ö' +compose ':' 'U' to 'Ü' +compose ':' 'a' to 'ä' +compose ':' 'e' to 'ë' +compose ':' 'o' to 'ö' +compose ':' 'u' to 'ü' +compose '<' '<' to 'Ť' +compose '>' '>' to 'ť' +compose '?' '?' to 'ż' +compose 'A' 'A' to 'Ĺ' +compose 'A' 'E' to 'Ć' +compose 'I' 'J' to 'ž' +compose 'L' '=' to 'Ł' +compose 'N' 'G' to '˝' +compose 'N' 'H' to 'Ń' +compose 'N' 'N' to 'Ń' +compose 'N' 'Y' to 'Ń' +compose 'N' 'h' to 'Ń' +compose 'N' 'n' to 'Ń' +compose 'N' 'y' to 'Ń' +compose 'O' 'A' to 'Ĺ' +compose 'O' 'E' to 'ź' +compose 'O' 'e' to 'ź' +compose 'T' 'H' to 'Ţ' +compose 'U' 'U' to 'Ů' +compose 'Y' '=' to 'Ľ' +compose '\'' 'A' to 'Á' +compose '\'' 'C' to 'Ć' +compose '\'' 'E' to 'É' +compose '\'' 'I' to 'Í' +compose '\'' 'L' to 'Ĺ' +compose '\'' 'N' to 'Ń' +compose '\'' 'O' to 'Ó' +compose '\'' 'R' to 'Ŕ' +compose '\'' 'S' to 'Ś' +compose '\'' 'U' to 'Ú' +compose '\'' 'Y' to 'Ý' +compose '\'' 'Z' to 'Ź' +compose '\'' 'a' to 'á' +compose '\'' 'c' to 'ć' +compose '\'' 'e' to 'é' +compose '\'' 'i' to 'í' +compose '\'' 'l' to 'ĺ' +compose '\'' 'n' to 'ń' +compose '\'' 'o' to 'ó' +compose '\'' 'r' to 'ŕ' +compose '\'' 's' to 'ś' +compose '\'' 'u' to 'ú' +compose '\'' 'y' to 'ý' +compose '\'' 'z' to 'ź' +compose '^' '!' to 'Ą' +compose '^' '*' to '×' +compose '^' '.' to 'ˇ' +compose '^' '/' to '÷' +compose '^' '1' to 'š' +compose '^' '2' to '˛' +compose '^' '3' to 'ł' +compose '^' ':' to '÷' +compose '^' '?' to 'ż' +compose '^' 'A' to 'Â' +compose '^' 'C' to 'Ç' +compose '^' 'D' to 'Đ' +compose '^' 'E' to 'Ę' +compose '^' 'G' to 'Ô' +compose '^' 'H' to 'Ś' +compose '^' 'I' to 'Î' +compose '^' 'J' to 'Ź' +compose '^' 'L' to 'Ľ' +compose '^' 'N' to 'Ń' +compose '^' 'R' to 'Ř' +compose '^' 'S' to 'Ś' +compose '^' 'T' to 'Ť' +compose '^' 'U' to 'Ű' +compose '^' 'Z' to '´' +compose '^' 'a' to 'â' +compose '^' 'c' to 'ç' +compose '^' 'd' to 'đ' +compose '^' 'e' to 'ę' +compose '^' 'g' to 'ř' +compose '^' 'h' to 'ś' +compose '^' 'i' to 'î' +compose '^' 'j' to 'ź' +compose '^' 'l' to 'ľ' +compose '^' 'n' to 'ń' +compose '^' 'o' to 'ô' +compose '^' 'r' to 'ř' +compose '^' 's' to '¨' +compose '^' 't' to 'ť' +compose '^' 'u' to 'ű' +compose '^' 'x' to '×' +compose '^' 'z' to '¸' +compose '`' 'A' to 'Ŕ' +compose '`' 'E' to 'Č' +compose '`' 'I' to 'Ě' +compose '`' 'O' to 'Ň' +compose '`' 'U' to 'Ů' +compose '`' 'a' to 'ŕ' +compose '`' 'e' to 'č' +compose '`' 'i' to 'ě' +compose '`' 'o' to 'ň' +compose '`' 'u' to 'ů' +compose 'a' 'a' to 'ĺ' +compose 'a' 'e' to 'ć' +compose 'c' '/' to '˘' +compose 'c' '=' to '˘' +compose 'e' '=' to '¤' +compose 'i' 'j' to '˙' +compose 'm' 'u' to 'ľ' +compose 'n' 'g' to 'ż' +compose 'n' 'h' to 'ń' +compose 'n' 'n' to 'ń' +compose 'o' 'a' to 'ĺ' +compose 'o' 'e' to '˝' +compose 's' 's' to 'ß' +compose 's' 'z' to 'ß' +compose 't' 'h' to 'ţ' +compose 'u' 'u' to 'ů' +compose 'v' 'S' to 'Ś' +compose 'v' 'Z' to '´' +compose 'v' 's' to '¨' +compose 'v' 'z' to '¸' +compose 'x' 'x' to '×' +compose '~' 'A' to 'Ă' +compose '~' 'G' to 'Ť' +compose '~' 'I' to 'Ľ' +compose '~' 'N' to 'Ń' +compose '~' 'O' to 'Ő' +compose '~' 'U' to 'Ý' +compose '~' 'a' to 'ă' +compose '~' 'g' to 'ť' +compose '~' 'i' to 'ľ' +compose '~' 'n' to 'ń' +compose '~' 'o' to 'ő' +compose '~' 'u' to 'ý' --- /dev/null +++ linux-2.4.21/drivers/char/input_keyb.c @@ -0,0 +1,167 @@ +/* + * linux/drivers/char/input_keyb.c by Russ Dill + * taken from pc_keyb.c + * + * This code grabs keypresses from the input layer and makes them + * available to the console. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + +#include +#include + +#include +#include + +/* Simple translation table for the SysRq keys */ + +unsigned char input_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 */ + +/* + * 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 + +/* + * 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 + +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, 0, 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, 0, 0, E0_PRSCR, /* 0x30-0x37 */ + E0_RALT, 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f */ + 0, 0, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */ + E0_UP, E0_PGUP, 0, E0_LEFT, 0, E0_RIGHT, 0, E0_END, /* 0x48-0x4f */ + E0_DOWN, E0_PGDN, 0, 0, 0, 0, 0, 0, /* 0x50-0x57 */ + 0, 0, 0, E0_MSLW, 0, 0, 0, 0, /* 0x58-0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x68-0x6f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ + 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ +}; + +int input_setkeycode(unsigned int scancode, unsigned int keycode) +{ + if (scancode > 255 || keycode > 127) return -EINVAL; + e0_keys[scancode - 128] = keycode; + return 0; +} + +int input_getkeycode(unsigned int scancode) +{ + return scancode > 255 ? -EINVAL : e0_keys[scancode - 128]; +} + +#define KBD_REPORT_UNKN +int input_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; + } + 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; + + 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 + *keycode = scancode; + return 1; +} + +char input_unexpected_up(unsigned char keycode) +{ + return 0200; +} + +/* Allow for loadable keyboard drivers */ +EXPORT_SYMBOL(input_setkeycode); +EXPORT_SYMBOL(input_unexpected_up); +EXPORT_SYMBOL(input_translate); +EXPORT_SYMBOL(input_sysrq_xlate); +EXPORT_SYMBOL(input_getkeycode); +EXPORT_SYMBOL(k_setkeycode); +EXPORT_SYMBOL(k_unexpected_up); +EXPORT_SYMBOL(k_translate); +EXPORT_SYMBOL(k_getkeycode); +#ifdef CONFIG_MAGIC_SYSRQ +EXPORT_SYMBOL(k_sysrq_key); +EXPORT_SYMBOL(k_sysrq_xlate); +#endif --- linux-2.4.21/drivers/char/keyboard.c~wedge +++ linux-2.4.21/drivers/char/keyboard.c @@ -77,6 +77,7 @@ void (*kbd_ledfunc)(unsigned int led); EXPORT_SYMBOL(handle_scancode); EXPORT_SYMBOL(kbd_ledfunc); +EXPORT_SYMBOL(key_maps); EXPORT_SYMBOL(kbd_refresh_leds); extern void ctrl_alt_del(void); --- linux-2.4.21/drivers/char/serial.c~ramses-serial +++ linux-2.4.21/drivers/char/serial.c @@ -1,138 +1,8 @@ -/* - * linux/drivers/char/serial.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, - * 1998, 1999 Theodore Ts'o - * - * Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92. Now - * much more extensible to support other serial cards based on the - * 16450/16550A UART's. Added support for the AST FourPort and the - * Accent Async board. - * - * set_serial_info fixed to set the flags, custom divisor, and uart - * type fields. Fix suggested by Michael K. Johnson 12/12/92. - * - * 11/95: TIOCMIWAIT, TIOCGICOUNT by Angelo Haritsis - * - * 03/96: Modularised by Angelo Haritsis - * - * rs_set_termios fixed to look also for changes of the input - * flags INPCK, BRKINT, PARMRK, IGNPAR and IGNBRK. - * Bernd Anhäupl 05/17/96. - * - * 1/97: Extended dumb serial ports are a config option now. - * Saves 4k. Michael A. Griffith - * - * 8/97: Fix bug in rs_set_termios with RTS - * Stanislav V. Voronyi - * - * 3/98: Change the IRQ detection, use of probe_irq_o*(), - * suppress TIOCSERGWILD and TIOCSERSWILD - * Etienne Lorrain - * - * 4/98: Added changes to support the ARM architecture proposed by - * Russell King - * - * 5/99: Updated to include support for the XR16C850 and ST16C654 - * uarts. Stuart MacDonald - * - * 8/99: Generalized PCI support added. Theodore Ts'o - * - * 3/00: Rid circular buffer of redundant xmit_cnt. Fix a - * few races on freeing buffers too. - * Alan Modra - * - * 5/00: Support for the RSA-DV II/S card added. - * Kiyokazu SUTO - * - * 6/00: Remove old-style timer, use timer_list - * Andrew Morton - * - * 7/00: Support Timedia/Sunix/Exsys PCI cards - * - * 7/00: fix some returns on failure not using MOD_DEC_USE_COUNT. - * Arnaldo Carvalho de Melo - * - * 10/00: add in optional software flow control for serial console. - * Kanoj Sarcar (Modified by Theodore Ts'o) - * - * 02/02: Fix for AMD Elan bug in transmit irq routine, by - * Christer Weinigel , - * Robert Schwebel , - * Juergen Beisert , - * Theodore Ts'o - */ - -static char *serial_version = "5.05c"; -static char *serial_revdate = "2001-07-08"; - -/* - * Serial driver configuration section. Here are the various options: - * - * CONFIG_HUB6 - * Enables support for the venerable Bell Technologies - * HUB6 card. - * - * CONFIG_SERIAL_MANY_PORTS - * Enables support for ports beyond the standard, stupid - * COM 1/2/3/4. - * - * CONFIG_SERIAL_MULTIPORT - * Enables support for special multiport board support. - * - * CONFIG_SERIAL_SHARE_IRQ - * Enables support for multiple serial ports on one IRQ - * - * CONFIG_SERIAL_DETECT_IRQ - * Enable the autodetection of IRQ on standart ports - * - * SERIAL_PARANOIA_CHECK - * Check the magic number for the async_structure where - * ever possible. - * - * CONFIG_SERIAL_ACPI - * Enable support for serial console port and serial - * debug port as defined by the SPCR and DBGP tables in - * ACPI 2.0. - */ +#undef DEBUG #include #include -#undef SERIAL_PARANOIA_CHECK -#define CONFIG_SERIAL_NOPAUSE_IO -#define SERIAL_DO_RESTART - -#if 0 -/* These defines are normally controlled by the autoconf.h */ -#define CONFIG_SERIAL_MANY_PORTS -#define CONFIG_SERIAL_SHARE_IRQ -#define CONFIG_SERIAL_DETECT_IRQ -#define CONFIG_SERIAL_MULTIPORT -#define CONFIG_HUB6 -#endif - -#ifdef CONFIG_PCI -#define ENABLE_SERIAL_PCI -#ifndef CONFIG_SERIAL_SHARE_IRQ -#define CONFIG_SERIAL_SHARE_IRQ -#endif -#ifndef CONFIG_SERIAL_MANY_PORTS -#define CONFIG_SERIAL_MANY_PORTS -#endif -#endif - -#ifdef CONFIG_SERIAL_ACPI -#define ENABLE_SERIAL_ACPI -#endif - -#if defined(CONFIG_ISAPNP)|| (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE)) -#ifndef ENABLE_SERIAL_PNP -#define ENABLE_SERIAL_PNP -#endif -#endif - #ifdef CONFIG_ARCH_PXA #define pxa_port(x) ((x) == PORT_PXA) #define pxa_buggy_port(x) ({ \ @@ -149,39 +19,16 @@ #undef SERIAL_DEBUG_OPEN #undef SERIAL_DEBUG_FLOW #undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT -#undef SERIAL_DEBUG_PCI -#undef SERIAL_DEBUG_AUTOCONF /* Sanity checks */ -#ifdef CONFIG_SERIAL_MULTIPORT -#ifndef CONFIG_SERIAL_SHARE_IRQ -#define CONFIG_SERIAL_SHARE_IRQ -#endif -#endif - -#ifdef CONFIG_HUB6 -#ifndef CONFIG_SERIAL_MANY_PORTS -#define CONFIG_SERIAL_MANY_PORTS -#endif -#ifndef CONFIG_SERIAL_SHARE_IRQ -#define CONFIG_SERIAL_SHARE_IRQ -#endif -#endif - #ifdef MODULE #undef CONFIG_SERIAL_CONSOLE #endif -#define CONFIG_SERIAL_RSA - #define RS_STROBE_TIME (10*HZ) #define RS_ISR_PASS_LIMIT 256 -#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486)) -#define SERIAL_INLINE -#endif - /* * End of serial driver configuration section. */ @@ -213,53 +60,51 @@ #include #include #include -#if (LINUX_VERSION_CODE >= 131343) #include -#endif -#if (LINUX_VERSION_CODE >= 131336) #include -#endif #include #ifdef CONFIG_SERIAL_CONSOLE #include #endif -#ifdef ENABLE_SERIAL_PCI -#include -#endif -#ifdef ENABLE_SERIAL_PNP -#include -#endif #ifdef CONFIG_MAGIC_SYSRQ #include #endif -/* - * All of the compatibilty code so we can compile serial.c against - * older kernels is hidden in serial_compat.h - */ -#if defined(LOCAL_HEADERS) || (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */ -#include "serial_compat.h" -#endif - #include #include #include #include -#if defined(CONFIG_MAC_SERIAL) -#define SERIAL_DEV_OFFSET ((_machine == _MACH_prep || _machine == _MACH_chrp) ? 0 : 2) -#else -#define SERIAL_DEV_OFFSET 0 -#endif +#define _INLINE_ -#ifdef SERIAL_INLINE -#define _INLINE_ inline +/* + * The TI16754 has 4 UARTS. They are selected with nCS3 and some + * address bits: + * + * 12 8 4 + * nA8, nCS[3] for MN_UART_1, address mask 1110 1110 0000 0000 = 0xEE00 + * nA9, nCS[3] for MN_UART_1, address mask 1110 1101 0000 0000 = 0xED00 + * nA10, nCS[3] for MN_UART_1, address mask 1110 1011 0000 0000 = 0xEB00 + * nA11, nCS[3] for MN_UART_1, address mask 1110 0111 0000 0000 = 0xE700 + */ +#define RAMSES_UARTA_PHYS (PXA_CS3_PHYS+0xEE00) +#define RAMSES_UARTB_PHYS (PXA_CS3_PHYS+0xED00) +#define RAMSES_UARTC_PHYS (PXA_CS3_PHYS+0xEB00) +#define RAMSES_UARTD_PHYS (PXA_CS3_PHYS+0xE700) +static void *ramses_uarta; // address cookie for UART A +static void *ramses_uartb; // address cookie for UART B +static void *ramses_uartc; // address cookie for UART C/Scanner +static void *ramses_uartd; // address cookie for UART D +static int ramses_stay_on = 0; + +#ifdef DEBUG +#define DPRINTK(fmt,args...) printk("//HS " fmt, ## args) +static int show_io = 1; #else -#define _INLINE_ +#define DPRINTK(fmt,args...) +static int show_io = 0; #endif -static char *serial_name = "Serial driver"; - static DECLARE_TASK_QUEUE(tq_serial); static struct tty_driver serial_driver, callout_driver; @@ -282,9 +127,6 @@ */ static struct async_struct *IRQ_ports[NR_IRQS]; -#ifdef CONFIG_SERIAL_MULTIPORT -static struct rs_multiport_struct rs_multiport[NR_IRQS]; -#endif static int IRQ_timeout[NR_IRQS]; #ifdef CONFIG_SERIAL_CONSOLE static struct console sercons; @@ -294,8 +136,6 @@ static unsigned long break_pressed; /* break, really ... */ #endif -static unsigned detect_uart_irq (struct serial_state * state); -static void autoconfig(struct serial_state * state); static void change_speed(struct async_struct *info, struct termios *old); static void rs_wait_until_sent(struct tty_struct *tty, int timeout); @@ -325,46 +165,74 @@ { 0, 0} }; -#if defined(CONFIG_SERIAL_RSA) && defined(MODULE) - -#define PORT_RSA_MAX 4 -static int probe_rsa[PORT_RSA_MAX]; -static int force_rsa[PORT_RSA_MAX]; - -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_RSA */ - -struct serial_state rs_table[RS_TABLE_SIZE] = { - SERIAL_PORT_DFNS /* Defined in serial.h */ +static struct serial_state rs_table[] = { + { + type: PORT_PXA, + xmit_fifo_size: 32, + baud_base: 921600, + iomem_base: (void *)&FFUART, + iomem_reg_shift: 2, + io_type: SERIAL_IO_MEM32, + irq: IRQ_FFUART, + flags: ASYNC_SKIP_TEST, + }, { + type: PORT_PXA, + xmit_fifo_size: 32, + baud_base: 921600, + iomem_base: (void *)&BTUART, + iomem_reg_shift: 2, + io_type: SERIAL_IO_MEM32, + irq: IRQ_BTUART, + flags: ASYNC_SKIP_TEST, + }, { + type: PORT_PXA, + xmit_fifo_size: 32, + baud_base: 921600, + iomem_base: (void *)&STUART, + iomem_reg_shift: 2, + io_type: SERIAL_IO_MEM32, + irq: IRQ_STUART, + flags: ASYNC_SKIP_TEST, + }, { + type: PORT_16750, + xmit_fifo_size: 64, + baud_base: 115200*2, + iomem_base: (void *)0, + iomem_reg_shift: 2, + io_type: SERIAL_IO_MEM, + irq: IRQ_GPIO(7), + flags: ASYNC_SKIP_TEST, + }, { + type: PORT_16750, + xmit_fifo_size: 64, + baud_base: 115200*2, + iomem_base: (void *)0, + iomem_reg_shift: 2, + io_type: SERIAL_IO_MEM, + irq: IRQ_GPIO(24), + flags: ASYNC_SKIP_TEST, + }, { + type: PORT_16750, + xmit_fifo_size: 64, + baud_base: 115200*2, + iomem_base: (void *)0, + iomem_reg_shift: 2, + io_type: SERIAL_IO_MEM, + irq: IRQ_GPIO(25), + flags: ASYNC_SKIP_TEST, + }, { + type: PORT_16750, + xmit_fifo_size: 64, + baud_base: 115200*2, + iomem_base: (void *)0, + iomem_reg_shift: 2, + io_type: SERIAL_IO_MEM, + irq: IRQ_GPIO(26), + flags: ASYNC_SKIP_TEST, + } }; #define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) -int serial_nr_ports = NR_PORTS; - -#if (defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)) -#define NR_PCI_BOARDS 8 - -static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS]; - -#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 -#endif /* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */ #ifndef PREPARE_FUNC #define PREPARE_FUNC(dev) (dev->prepare) @@ -403,39 +271,21 @@ #endif -static inline int serial_paranoia_check(struct async_struct *info, - kdev_t device, const char *routine) -{ -#ifdef SERIAL_PARANOIA_CHECK - static const char *badmagic = - "Warning: bad magic number for serial struct (%s) in %s\n"; - static const char *badinfo = - "Warning: null async_struct for (%s) in %s\n"; - - if (!info) { - printk(badinfo, kdevname(device), routine); - return 1; - } - if (info->magic != SERIAL_MAGIC) { - printk(badmagic, kdevname(device), routine); - return 1; - } -#endif - return 0; -} - static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset) { + unsigned int value; switch (info->io_type) { -#ifdef CONFIG_HUB6 - case SERIAL_IO_HUB6: - outb(info->hub6 - 1 + offset, info->port); - return inb(info->port+1); -#endif case SERIAL_IO_MEM: - return readb((unsigned long) info->iomem_base + + value = readb((unsigned long) info->iomem_base + (offset<iomem_reg_shift)); + udelay(10); + if (show_io) printk("in %02x = %02x\n", offset, value); + return value; case SERIAL_IO_MEM32: + value = readl((unsigned long) info->iomem_base + + (offset<iomem_reg_shift)); + if (show_io) printk("in %02x = %02x\n", offset, value); + return value; return readl((unsigned long) info->iomem_base + (offset<iomem_reg_shift)); default: @@ -447,17 +297,14 @@ int value) { switch (info->io_type) { -#ifdef CONFIG_HUB6 - case SERIAL_IO_HUB6: - outb(info->hub6 - 1 + offset, info->port); - outb(value, info->port+1); - break; -#endif case SERIAL_IO_MEM: + if (show_io) printk("out %02x, %02x\n", offset, value); writeb(value, (unsigned long) info->iomem_base + (offset<iomem_reg_shift)); + udelay(10); break; case SERIAL_IO_MEM32: + if (show_io) printk("out %02x, %02x\n", offset, value); writel(value, (unsigned long) info->iomem_base + (offset<iomem_reg_shift)); break; @@ -509,9 +356,6 @@ struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; - if (serial_paranoia_check(info, tty->device, "rs_stop")) - return; - save_flags(flags); cli(); if (info->IER & UART_IER_THRI) { info->IER &= ~UART_IER_THRI; @@ -529,9 +373,6 @@ struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; - if (serial_paranoia_check(info, tty->device, "rs_start")) - return; - save_flags(flags); cli(); if (info->xmit.head != info->xmit.tail && info->xmit.buf @@ -689,11 +530,7 @@ #endif *status = serial_inp(info, UART_LSR); } while ((*status & UART_LSR_DR) && (max_count-- > 0)); -#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */ tty_flip_buffer_push(tty); -#else - queue_task_irq_off(&tty->flip.tqueue, &tq_timer); -#endif } static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done) @@ -758,11 +595,6 @@ icount->dsr++; if (status & UART_MSR_DDCD) { icount->dcd++; -#ifdef CONFIG_HARD_PPS - if ((info->flags & ASYNC_HARDPPS_CD) && - (status & UART_MSR_DCD)) - hardpps(); -#endif } if (status & UART_MSR_DCTS) icount->cts++; @@ -810,120 +642,23 @@ } } -#ifdef CONFIG_SERIAL_SHARE_IRQ -/* - * This is the serial driver's generic interrupt routine - */ -static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - int status, iir; - struct async_struct * info; - int pass_counter = 0; - struct async_struct *end_mark = 0; -#ifdef CONFIG_SERIAL_MULTIPORT - int first_multi = 0; - struct rs_multiport_struct *multi; -#endif - -#ifdef SERIAL_DEBUG_INTR - printk("rs_interrupt(%d)...", irq); -#endif - - info = IRQ_ports[irq]; - if (!info) - return; - -#ifdef CONFIG_SERIAL_MULTIPORT - multi = &rs_multiport[irq]; - if (multi->port_monitor) - first_multi = inb(multi->port_monitor); -#endif - - do { - if (!info->tty || - ((iir=serial_in(info, UART_IIR)) & UART_IIR_NO_INT)) { - if (!end_mark) - end_mark = info; - goto next; - } -#ifdef SERIAL_DEBUG_INTR - printk("IIR = %x...", serial_in(info, UART_IIR)); -#endif - end_mark = 0; - - info->last_active = jiffies; - - status = serial_inp(info, UART_LSR); -#ifdef SERIAL_DEBUG_INTR - printk("status = %x...", status); -#endif - if (status & UART_LSR_DR) - receive_chars(info, &status, regs); - check_modem_status(info); -#ifdef CONFIG_MELAN - if ((status & UART_LSR_THRE) || - /* for buggy ELAN processors */ - ((iir & UART_IIR_ID) == UART_IIR_THRI)) - transmit_chars(info, 0); -#else - if (status & UART_LSR_THRE) - transmit_chars(info, 0); -#endif - - next: - info = info->next_port; - if (!info) { - info = IRQ_ports[irq]; - if (pass_counter++ > RS_ISR_PASS_LIMIT) { -#if 0 - printk("rs loop break\n"); -#endif - break; /* Prevent infinite loops */ - } - continue; - } - } while (end_mark != info); -#ifdef CONFIG_SERIAL_MULTIPORT - if (multi->port_monitor) - printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n", - info->state->irq, first_multi, - inb(multi->port_monitor)); -#endif -#ifdef SERIAL_DEBUG_INTR - printk("end.\n"); -#endif -} -#endif /* #ifdef CONFIG_SERIAL_SHARE_IRQ */ - /* * This is the serial driver's interrupt routine for a single port */ static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) { - int status, iir; + int status; int pass_counter = 0; struct async_struct * info; -#ifdef CONFIG_SERIAL_MULTIPORT - int first_multi = 0; - struct rs_multiport_struct *multi; -#endif #ifdef SERIAL_DEBUG_INTR printk("rs_interrupt_single(%d)...", irq); #endif - info = IRQ_ports[irq]; if (!info || !info->tty) return; -#ifdef CONFIG_SERIAL_MULTIPORT - multi = &rs_multiport[irq]; - if (multi->port_monitor) - first_multi = inb(multi->port_monitor); -#endif - - iir = serial_in(info, UART_IIR); do { status = serial_inp(info, UART_LSR); #ifdef SERIAL_DEBUG_INTR @@ -932,120 +667,23 @@ if (status & UART_LSR_DR) receive_chars(info, &status, regs); check_modem_status(info); - if ((status & UART_LSR_THRE) || - /* For buggy ELAN processors */ - ((iir & UART_IIR_ID) == UART_IIR_THRI)) + if (status & UART_LSR_THRE) transmit_chars(info, 0); if (pass_counter++ > RS_ISR_PASS_LIMIT) { -#if SERIAL_DEBUG_INTR +#if 0 printk("rs_single loop break.\n"); #endif break; } - iir = serial_in(info, UART_IIR); -#ifdef SERIAL_DEBUG_INTR - printk("IIR = %x...", iir); -#endif - } while ((iir & UART_IIR_NO_INT) == 0); - info->last_active = jiffies; -#ifdef CONFIG_SERIAL_MULTIPORT - if (multi->port_monitor) - printk("rs port monitor (single) irq %d: 0x%x, 0x%x\n", - info->state->irq, first_multi, - inb(multi->port_monitor)); -#endif -#ifdef SERIAL_DEBUG_INTR - printk("end.\n"); -#endif -} - -#ifdef CONFIG_SERIAL_MULTIPORT -/* - * This is the serial driver's for multiport boards - */ -static void rs_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs) -{ - int status; - struct async_struct * info; - int pass_counter = 0; - int first_multi= 0; - struct rs_multiport_struct *multi; - #ifdef SERIAL_DEBUG_INTR - printk("rs_interrupt_multi(%d)...", irq); + printk("IIR = %x...", serial_in(info, UART_IIR)); #endif - - info = IRQ_ports[irq]; - if (!info) - return; - multi = &rs_multiport[irq]; - if (!multi->port1) { - /* Should never happen */ - printk("rs_interrupt_multi: NULL port1!\n"); - return; - } - if (multi->port_monitor) - first_multi = inb(multi->port_monitor); - - while (1) { - if (!info->tty || - (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) - goto next; - + } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT)); info->last_active = jiffies; - - status = serial_inp(info, UART_LSR); -#ifdef SERIAL_DEBUG_INTR - printk("status = %x...", status); -#endif - if (status & UART_LSR_DR) - receive_chars(info, &status, regs); - check_modem_status(info); - if (status & UART_LSR_THRE) - transmit_chars(info, 0); - - next: - info = info->next_port; - if (info) - continue; - - info = IRQ_ports[irq]; - /* - * The user was a bonehead, and misconfigured their - * multiport info. Rather than lock up the kernel - * in an infinite loop, if we loop too many times, - * print a message and break out of the loop. - */ - if (pass_counter++ > RS_ISR_PASS_LIMIT) { - printk("Misconfigured multiport serial info " - "for irq %d. Breaking out irq loop\n", irq); - break; - } - if (multi->port_monitor) - printk("rs port monitor irq %d: 0x%x, 0x%x\n", - info->state->irq, first_multi, - inb(multi->port_monitor)); - if ((inb(multi->port1) & multi->mask1) != multi->match1) - continue; - if (!multi->port2) - break; - if ((inb(multi->port2) & multi->mask2) != multi->match2) - continue; - if (!multi->port3) - break; - if ((inb(multi->port3) & multi->mask3) != multi->match3) - continue; - if (!multi->port4) - break; - if ((inb(multi->port4) & multi->mask4) != multi->match4) - continue; - break; - } #ifdef SERIAL_DEBUG_INTR printk("end.\n"); #endif } -#endif /* * ------------------------------------------------------------------- @@ -1107,22 +745,6 @@ if (!info) continue; save_flags(flags); cli(); -#ifdef CONFIG_SERIAL_SHARE_IRQ - if (info->next_port) { - do { - serial_out(info, UART_IER, 0); - info->IER |= UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - info = info->next_port; - } while (info); -#ifdef CONFIG_SERIAL_MULTIPORT - if (rs_multiport[i].port1) - rs_interrupt_multi(i, NULL, NULL); - else -#endif - rs_interrupt(i, NULL, NULL); - } else -#endif /* CONFIG_SERIAL_SHARE_IRQ */ rs_interrupt_single(i, NULL, NULL); restore_flags(flags); } @@ -1132,11 +754,7 @@ if (IRQ_ports[0]) { save_flags(flags); cli(); -#ifdef CONFIG_SERIAL_SHARE_IRQ - rs_interrupt(0, NULL, NULL); -#else rs_interrupt_single(0, NULL, NULL); -#endif restore_flags(flags); mod_timer(&serial_timer, jiffies + IRQ_timeout[0]); @@ -1177,50 +795,6 @@ IRQ_timeout[irq] = (timeout > 3) ? timeout-2 : 1; } -#ifdef CONFIG_SERIAL_RSA -/* Attempts to turn on the RSA FIFO. Returns zero on failure */ -static int enable_rsa(struct async_struct *info) -{ - unsigned char mode; - int result; - unsigned long flags; - - save_flags(flags); cli(); - mode = serial_inp(info, UART_RSA_MSR); - result = mode & UART_RSA_MSR_FIFO; - - if (!result) { - serial_outp(info, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); - mode = serial_inp(info, UART_RSA_MSR); - result = mode & UART_RSA_MSR_FIFO; - } - - restore_flags(flags); - return result; -} - -/* Attempts to turn off the RSA FIFO. Returns zero on failure */ -static int disable_rsa(struct async_struct *info) -{ - unsigned char mode; - int result; - unsigned long flags; - - save_flags(flags); cli(); - mode = serial_inp(info, UART_RSA_MSR); - result = !(mode & UART_RSA_MSR_FIFO); - - if (!result) { - serial_outp(info, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); - mode = serial_inp(info, UART_RSA_MSR); - result = !(mode & UART_RSA_MSR_FIFO); - } - - restore_flags(flags); - return result; -} -#endif /* CONFIG_SERIAL_RSA */ - static int startup(struct async_struct * info) { unsigned long flags; @@ -1228,9 +802,6 @@ void (*handler)(int, void *, struct pt_regs *); struct serial_state *state= info->state; unsigned long page; -#ifdef CONFIG_SERIAL_MANY_PORTS - unsigned short ICP; -#endif page = get_zeroed_page(GFP_KERNEL); if (!page) @@ -1258,6 +829,22 @@ printk("starting up ttys%d (irq %d)...", info->line, state->irq); #endif + // Special handling to give power to devices + switch (info->line) { + case 3: + //printk("gsm on\n"); + RAMSES_GSM_ON(); + break; + case 4: + //printk("uart on\n"); + RAMSES_UART_ON(); + break; + case 5: + //printk("scanner on\n"); + RAMSES_SCANNER_ON(); + break; + } + if (uart_config[state->type].flags & UART_STARTECH) { /* Wake up UART */ serial_outp(info, UART_LCR, 0xBF); @@ -1305,25 +892,12 @@ serial_outp(info, UART_LCR, 0); } -#ifdef CONFIG_SERIAL_RSA - /* - * If this is an RSA port, see if we can kick it up to the - * higher speed clock. - */ - if (state->type == PORT_RSA) { - if (state->baud_base != SERIAL_RSA_BAUD_BASE && - enable_rsa(info)) - state->baud_base = SERIAL_RSA_BAUD_BASE; - if (state->baud_base == SERIAL_RSA_BAUD_BASE) - serial_outp(info, UART_RSA_FRR, 0); - } -#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; + //HS TODO: cerf keeps the clock on case (long)&STUART: CKEN |= CKEN5_STUART; break; } } @@ -1344,6 +918,7 @@ /* * Clear the interrupt registers. */ + (void) serial_inp(info, UART_IIR); (void) serial_inp(info, UART_LSR); (void) serial_inp(info, UART_RX); (void) serial_inp(info, UART_IIR); @@ -1371,18 +946,8 @@ if (state->irq && (!IRQ_ports[state->irq] || !IRQ_ports[state->irq]->next_port)) { if (IRQ_ports[state->irq]) { -#ifdef CONFIG_SERIAL_SHARE_IRQ - free_irq(state->irq, &IRQ_ports[state->irq]); -#ifdef CONFIG_SERIAL_MULTIPORT - if (rs_multiport[state->irq].port1) - handler = rs_interrupt_multi; - else -#endif - handler = rs_interrupt; -#else retval = -EBUSY; goto errout; -#endif /* CONFIG_SERIAL_SHARE_IRQ */ } else handler = rs_interrupt_single; @@ -1417,12 +982,6 @@ info->MCR = 0; if (info->tty->termios->c_cflag & CBAUD) info->MCR = UART_MCR_DTR | UART_MCR_RTS; -#ifdef CONFIG_SERIAL_MANY_PORTS - if (info->flags & ASYNC_FOURPORT) { - if (state->irq == 0) - info->MCR |= UART_MCR_OUT1; - } else -#endif { if (state->irq != 0) info->MCR |= UART_MCR_OUT2; @@ -1437,18 +996,9 @@ */ info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; if (pxa_port(state->type)) - info->IER |= UART_IER_UUE | UART_IER_RTOIE; + info->IER |= UART_IER_UUE | UART_IER_RTOIE; //HS TODO: UART_IER_THRI for PXA uarts? serial_outp(info, UART_IER, info->IER); /* enable interrupts */ -#ifdef CONFIG_SERIAL_MANY_PORTS - if (info->flags & ASYNC_FOURPORT) { - /* Enable interrupts on the AST Fourport board */ - ICP = (info->port & 0xFE0) | 0x01F; - outb_p(0x80, ICP); - (void) inb_p(ICP); - } -#endif - /* * And clear the interrupt registers again for luck. */ @@ -1469,7 +1019,6 @@ /* * Set up the tty->alt_speed kludge */ -#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ if (info->tty) { if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) info->tty->alt_speed = 57600; @@ -1480,7 +1029,6 @@ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) info->tty->alt_speed = 460800; } -#endif /* * and set the speed of the serial port @@ -1516,6 +1064,30 @@ state->irq); #endif + switch (info->line) { + case 3: + if (ramses_stay_on & RAMSES_CONTROL_GSM_PWR) { + //printk("gsm on\n"); + RAMSES_GSM_OFF(); + } + //else printk("gsm stays on\n"); + break; + case 4: + if (ramses_stay_on & RAMSES_CONTROL_UART_PWR) { + //printk("uart off\n"); + RAMSES_UART_OFF(); + } + //else printk("uart stays on\n"); + break; + case 5: + if (ramses_stay_on & RAMSES_CONTROL_SCANNER_PWR) { + //printk("scanner off\n"); + RAMSES_SCANNER_OFF(); + } + //else printk("scanner on\n"); + break; + } + save_flags(flags); cli(); /* Disable interrupts */ /* @@ -1561,13 +1133,6 @@ info->IER = 0; serial_outp(info, UART_IER, 0x00); /* disable all intrs */ -#ifdef CONFIG_SERIAL_MANY_PORTS - if (info->flags & ASYNC_FOURPORT) { - /* reset interrupts on the AST Fourport board */ - (void) inb((info->port & 0xFE0) | 0x01F); - info->MCR |= UART_MCR_OUT1; - } else -#endif info->MCR &= ~UART_MCR_OUT2; if (pxa_buggy_port(state->type)) info->MCR ^= UART_MCR_OUT2; @@ -1586,16 +1151,6 @@ UART_FCR_CLEAR_XMIT)); serial_outp(info, UART_FCR, 0); -#ifdef CONFIG_SERIAL_RSA - /* - * Reset the RSA board back to 115kbps compat mode. - */ - if ((state->type == PORT_RSA) && - (state->baud_base == SERIAL_RSA_BAUD_BASE && - disable_rsa(info))) - state->baud_base = SERIAL_RSA_BAUD_BASE_LO; -#endif - #ifdef CONFIG_ARCH_PXA if (state->type == PORT_PXA #ifdef CONFIG_SERIAL_CONSOLE @@ -1634,37 +1189,6 @@ restore_flags(flags); } -#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ -static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, - 600, 1200, 1800, 2400, 4800, 9600, 19200, - 38400, 57600, 115200, 230400, 460800, 0 }; - -static int tty_get_baud_rate(struct tty_struct *tty) -{ - struct async_struct * info = (struct async_struct *)tty->driver_data; - unsigned int cflag, i; - - cflag = tty->termios->c_cflag; - - i = cflag & CBAUD; - if (i & CBAUDEX) { - i &= ~CBAUDEX; - if (i < 1 || i > 2) - tty->termios->c_cflag &= ~CBAUDEX; - else - i += 15; - } - if (i == 15) { - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - i += 1; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - i += 2; - } - return baud_table[i]; -} -#endif - /* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. @@ -1711,12 +1235,6 @@ baud = tty_get_baud_rate(info->tty); if (!baud) baud = 9600; /* B0 transition handled in rs_set_termios */ -#ifdef CONFIG_SERIAL_RSA - if ((info->state->type == PORT_RSA) && - (info->state->baud_base != SERIAL_RSA_BAUD_BASE) && - enable_rsa(info)) - info->state->baud_base = SERIAL_RSA_BAUD_BASE; -#endif baud_base = info->state->baud_base; if (info->state->type == PORT_16C950) { if (baud <= baud_base) @@ -1778,10 +1296,6 @@ if (uart_config[info->state->type].flags & UART_USE_FIFO) { if ((info->state->baud_base / quot) < 2400) fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; -#ifdef CONFIG_SERIAL_RSA - else if (info->state->type == PORT_RSA) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14; -#endif else fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; } @@ -1864,9 +1378,6 @@ struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; - if (serial_paranoia_check(info, tty->device, "rs_put_char")) - return; - if (!tty || !info->xmit.buf) return; @@ -1888,9 +1399,6 @@ struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; - if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) - return; - if (info->xmit.head == info->xmit.tail || tty->stopped || tty->hw_stopped @@ -1900,8 +1408,6 @@ 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); } @@ -1912,9 +1418,6 @@ struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; - if (serial_paranoia_check(info, tty->device, "rs_write")) - return 0; - if (!tty || !info->xmit.buf || !tmp_buf) return 0; @@ -1978,11 +1481,6 @@ && !(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; } @@ -1991,8 +1489,6 @@ { struct async_struct *info = (struct async_struct *)tty->driver_data; - if (serial_paranoia_check(info, tty->device, "rs_write_room")) - return 0; return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); } @@ -2000,8 +1496,6 @@ { struct async_struct *info = (struct async_struct *)tty->driver_data; - if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer")) - return 0; return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); } @@ -2010,8 +1504,6 @@ struct async_struct *info = (struct async_struct *)tty->driver_data; unsigned long flags; - if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) - return; save_flags(flags); cli(); info->xmit.head = info->xmit.tail = 0; restore_flags(flags); @@ -2032,16 +1524,11 @@ { struct async_struct *info = (struct async_struct *)tty->driver_data; - if (serial_paranoia_check(info, tty->device, "rs_send_char")) - return; - info->x_char = ch; if (ch) { /* 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); } } @@ -2064,9 +1551,6 @@ tty->ldisc.chars_in_buffer(tty)); #endif - if (serial_paranoia_check(info, tty->device, "rs_throttle")) - return; - if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty)); @@ -2089,9 +1573,6 @@ tty->ldisc.chars_in_buffer(tty)); #endif - if (serial_paranoia_check(info, tty->device, "rs_unthrottle")) - return; - if (I_IXOFF(tty)) { if (info->x_char) info->x_char = 0; @@ -2134,7 +1615,6 @@ tmp.close_delay = state->close_delay; tmp.closing_wait = state->closing_wait; tmp.custom_divisor = state->custom_divisor; - tmp.hub6 = state->hub6; tmp.io_type = state->io_type; if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) return -EFAULT; @@ -2160,8 +1640,7 @@ new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; change_irq = new_serial.irq != state->irq; - change_port = (new_port != ((int) state->port)) || - (new_serial.hub6 != state->hub6); + change_port = (new_port != ((int) state->port)); if (!capable(CAP_SYS_ADMIN)) { if (change_irq || change_port || @@ -2198,7 +1677,6 @@ if (new_serial.type) { for (i = 0 ; i < NR_PORTS; i++) if ((state != &rs_table[i]) && - (rs_table[i].io_type == SERIAL_IO_PORT) && (rs_table[i].port == new_port) && rs_table[i].type) return -EADDRINUSE; @@ -2220,18 +1698,11 @@ 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; -#if (LINUX_VERSION_CODE > 0x20100) info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; -#endif info->xmit_fifo_size = state->xmit_fifo_size = new_serial.xmit_fifo_size; if ((state->type != PORT_UNKNOWN) && state->port) { -#ifdef CONFIG_SERIAL_RSA - if (old_state.type == PORT_RSA) - release_region(state->port + UART_RSA_BASE, 16); - else -#endif release_region(state->port,8); } state->type = new_serial.type; @@ -2243,31 +1714,19 @@ shutdown(info); state->irq = new_serial.irq; info->port = state->port = new_port; - info->hub6 = state->hub6 = new_serial.hub6; - if (info->hub6) - info->io_type = state->io_type = SERIAL_IO_HUB6; - else if (info->io_type == SERIAL_IO_HUB6) - info->io_type = state->io_type = SERIAL_IO_PORT; } if ((state->type != PORT_UNKNOWN) && state->port) { -#ifdef CONFIG_SERIAL_RSA - if (state->type == PORT_RSA) - request_region(state->port + UART_RSA_BASE, - 16, "serial_rsa(set)"); - else -#endif request_region(state->port,8,"serial(set)"); } check_and_exit: - if ((!state->port && !state->iomem_base) || !state->type) + if (!state->port || !state->type) 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 (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) info->tty->alt_speed = 57600; if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) @@ -2276,7 +1735,6 @@ info->tty->alt_speed = 230400; if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) info->tty->alt_speed = 460800; -#endif change_speed(info, 0); } } else @@ -2414,60 +1872,14 @@ return 0; } -static int do_autoconfig(struct async_struct * info) -{ - int irq, retval; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (info->state->count > 1) - return -EBUSY; - - shutdown(info); - - autoconfig(info->state); - if ((info->state->flags & ASYNC_AUTO_IRQ) && - (info->state->port != 0 || info->state->iomem_base != 0) && - (info->state->type != PORT_UNKNOWN)) { - irq = detect_uart_irq(info->state); - if (irq > 0) - info->state->irq = irq; - } - - retval = startup(info); - if (retval) - return retval; - return 0; -} - /* * rs_break() --- routine which turns the break handling on or off */ -#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ -static void send_break( struct async_struct * info, int duration) -{ - if (!CONFIGURED_SERIAL_PORT(info)) - return; - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + duration; - cli(); - info->LCR |= UART_LCR_SBC; - serial_out(info, UART_LCR, info->LCR); - schedule(); - info->LCR &= ~UART_LCR_SBC; - serial_out(info, UART_LCR, info->LCR); - sti(); -} -#else static void rs_break(struct tty_struct *tty, int break_state) { struct async_struct * info = (struct async_struct *)tty->driver_data; unsigned long flags; - if (serial_paranoia_check(info, tty->device, "rs_break")) - return; - if (!CONFIGURED_SERIAL_PORT(info)) return; save_flags(flags); cli(); @@ -2478,121 +1890,6 @@ serial_out(info, UART_LCR, info->LCR); restore_flags(flags); } -#endif - -#ifdef CONFIG_SERIAL_MULTIPORT -static int get_multiport_struct(struct async_struct * info, - struct serial_multiport_struct *retinfo) -{ - struct serial_multiport_struct ret; - struct rs_multiport_struct *multi; - - multi = &rs_multiport[info->state->irq]; - - ret.port_monitor = multi->port_monitor; - - ret.port1 = multi->port1; - ret.mask1 = multi->mask1; - ret.match1 = multi->match1; - - ret.port2 = multi->port2; - ret.mask2 = multi->mask2; - ret.match2 = multi->match2; - - ret.port3 = multi->port3; - ret.mask3 = multi->mask3; - ret.match3 = multi->match3; - - ret.port4 = multi->port4; - ret.mask4 = multi->mask4; - ret.match4 = multi->match4; - - ret.irq = info->state->irq; - - if (copy_to_user(retinfo,&ret,sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int set_multiport_struct(struct async_struct * info, - struct serial_multiport_struct *in_multi) -{ - struct serial_multiport_struct new_multi; - struct rs_multiport_struct *multi; - struct serial_state *state; - int was_multi, now_multi; - int retval; - void (*handler)(int, void *, struct pt_regs *); - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - state = info->state; - - if (copy_from_user(&new_multi, in_multi, - sizeof(struct serial_multiport_struct))) - return -EFAULT; - - if (new_multi.irq != state->irq || state->irq == 0 || - !IRQ_ports[state->irq]) - return -EINVAL; - - multi = &rs_multiport[state->irq]; - was_multi = (multi->port1 != 0); - - multi->port_monitor = new_multi.port_monitor; - - if (multi->port1) - release_region(multi->port1,1); - multi->port1 = new_multi.port1; - multi->mask1 = new_multi.mask1; - multi->match1 = new_multi.match1; - if (multi->port1) - request_region(multi->port1,1,"serial(multiport1)"); - - if (multi->port2) - release_region(multi->port2,1); - multi->port2 = new_multi.port2; - multi->mask2 = new_multi.mask2; - multi->match2 = new_multi.match2; - if (multi->port2) - request_region(multi->port2,1,"serial(multiport2)"); - - if (multi->port3) - release_region(multi->port3,1); - multi->port3 = new_multi.port3; - multi->mask3 = new_multi.mask3; - multi->match3 = new_multi.match3; - if (multi->port3) - request_region(multi->port3,1,"serial(multiport3)"); - - if (multi->port4) - release_region(multi->port4,1); - multi->port4 = new_multi.port4; - multi->mask4 = new_multi.mask4; - multi->match4 = new_multi.match4; - if (multi->port4) - request_region(multi->port4,1,"serial(multiport4)"); - - now_multi = (multi->port1 != 0); - - if (IRQ_ports[state->irq]->next_port && - (was_multi != now_multi)) { - free_irq(state->irq, &IRQ_ports[state->irq]); - if (now_multi) - handler = rs_interrupt_multi; - else - handler = rs_interrupt; - - retval = request_irq(state->irq, handler, SA_SHIRQ, - "serial", &IRQ_ports[state->irq]); - if (retval) { - printk("Couldn't reallocate serial interrupt " - "driver!!\n"); - } - } - return 0; -} -#endif static int rs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) @@ -2601,12 +1898,6 @@ struct async_icount cprev, cnow; /* kernel counter temps */ struct serial_icounter_struct icount; unsigned long flags; -#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ - int retval, tmp; -#endif - - if (serial_paranoia_check(info, tty->device, "rs_ioctl")) - return -ENODEV; if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && @@ -2616,45 +1907,6 @@ } switch (cmd) { -#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; - if (!arg) { - send_break(info, HZ/4); /* 1/4 second */ - if (signal_pending(current)) - return -EINTR; - } - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; - send_break(info, arg ? arg*(HZ/10) : HZ/4); - if (signal_pending(current)) - return -EINTR; - return 0; - case TIOCGSOFTCAR: - tmp = C_CLOCAL(tty) ? 1 : 0; - if (copy_to_user((void *)arg, &tmp, sizeof(int))) - return -EFAULT; - return 0; - case TIOCSSOFTCAR: - if (copy_from_user(&tmp, (void *)arg, sizeof(int))) - return -EFAULT; - - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (tmp ? CLOCAL : 0)); - return 0; -#endif case TIOCMGET: return get_modem_info(info, (unsigned int *) arg); case TIOCMBIS: @@ -2667,9 +1919,6 @@ case TIOCSSERIAL: return set_serial_info(info, (struct serial_struct *) arg); - case TIOCSERCONFIG: - return do_autoconfig(info); - case TIOCSERGETLSR: /* Get line status register */ return get_lsr_info(info, (unsigned int *) arg); @@ -2679,15 +1928,6 @@ return -EFAULT; return 0; -#ifdef CONFIG_SERIAL_MULTIPORT - case TIOCSERGETMULTI: - return get_multiport_struct(info, - (struct serial_multiport_struct *) arg); - case TIOCSERSETMULTI: - return set_multiport_struct(info, - (struct serial_multiport_struct *) arg); -#endif - /* * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change * - mask passed in arg for lines of interest @@ -2754,6 +1994,39 @@ printk ("TIOCSER?WILD ioctl obsolete, ignored.\n"); return 0; + case TIOCSERSETMULTI: + switch (arg) { + + // switch devices on + case 2: RAMSES_LCD_BLIGHT_ON(); break; + case 3: RAMSES_GSM_ON(); break; + case 4: RAMSES_UART_ON(); break; + case 5: RAMSES_SCANNER_ON(); break; + case 7: RAMSES_SCANNER_WAKE_ON(); break; + case 8: RAMSES_SCANNER_TRIG_ON(); break; + case 9: RAMSES_GSM_RESET_ON(); break; + + // switch devices off + case 12: RAMSES_LCD_BLIGHT_OFF(); break; + case 13: RAMSES_GSM_OFF(); break; + case 14: RAMSES_UART_OFF(); break; + case 15: RAMSES_SCANNER_OFF(); break; + case 17: RAMSES_SCANNER_WAKE_OFF(); break; + case 18: RAMSES_SCANNER_TRIG_OFF(); break; + case 19: RAMSES_GSM_RESET_OFF(); break; + + // disable automatic poweroff on file-handle close + case 23: ramses_stay_on |= RAMSES_CONTROL_GSM_PWR; break; + case 24: ramses_stay_on |= RAMSES_CONTROL_UART_PWR; break; + case 25: ramses_stay_on |= RAMSES_CONTROL_SCANNER_PWR; break; + + // enable automatic poweroff on file-handle close + case 33: ramses_stay_on &= ~RAMSES_CONTROL_GSM_PWR; break; + case 34: ramses_stay_on &= ~RAMSES_CONTROL_UART_PWR; break; + case 35: ramses_stay_on &= ~RAMSES_CONTROL_SCANNER_PWR; break; + } + return 0; + default: return -ENOIOCTLCMD; } @@ -2801,18 +2074,6 @@ tty->hw_stopped = 0; rs_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 } /* @@ -2831,9 +2092,6 @@ struct serial_state *state; unsigned long flags; - if (!info || serial_paranoia_check(info, tty->device, "rs_close")) - return; - state = info->state; save_flags(flags); cli(); @@ -2933,10 +2191,7 @@ { struct async_struct * info = (struct async_struct *)tty->driver_data; unsigned long orig_jiffies, char_time; - int lsr; - - if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent")) - return; + int lsr, old_show_io; if (info->state->type == PORT_UNKNOWN) return; @@ -2974,9 +2229,11 @@ printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); printk("jiff=%lu...", jiffies); #endif + old_show_io = show_io; + show_io = 0; while (!((lsr = serial_inp(info, UART_LSR)) & UART_LSR_TEMT)) { #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("lsr = %d (jiff=%lu)...", lsr, jiffies); + printk("lsr = %02x (jiff=%lu)...", lsr, jiffies); #endif set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(char_time); @@ -2986,8 +2243,9 @@ break; } #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); + printk("lsr = %02x (jiff=%lu)...done\n", lsr, jiffies); #endif + show_io = old_show_io; } /* @@ -2998,9 +2256,6 @@ struct async_struct * info = (struct async_struct *)tty->driver_data; struct serial_state *state = info->state; - if (serial_paranoia_check(info, tty->device, "rs_hangup")) - return; - state = info->state; rs_flush_buffer(tty); @@ -3036,12 +2291,8 @@ (info->flags & ASYNC_CLOSING)) { if (info->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); -#else - return -EAGAIN; -#endif } /* @@ -3114,14 +2365,10 @@ set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART if (info->flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; -#else - retval = -EAGAIN; -#endif break; } if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && @@ -3223,16 +2470,12 @@ } tty->driver_data = info; info->tty = tty; - if (serial_paranoia_check(info, tty->device, "rs_open")) - return -ENODEV; #ifdef SERIAL_DEBUG_OPEN printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, info->state->count); #endif -#if (LINUX_VERSION_CODE > 0x20100) info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; -#endif /* * This relies on lock_kernel() stuff so wants tidying for 2.5 @@ -3254,12 +2497,8 @@ (info->flags & ASYNC_CLOSING)) { if (info->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); -#else - return -EAGAIN; -#endif } /* @@ -3313,17 +2552,14 @@ int ret; unsigned long flags; - /* - * Return zero characters for ports not claimed by driver. - */ - if (state->type == PORT_UNKNOWN) { - return 0; /* ignore unused ports */ - } - ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d", state->line, uart_config[state->type].name, - (state->port ? state->port : (long)state->iomem_base), - state->irq); + state->port, state->irq); + + if (!state->port || (state->type == PORT_UNKNOWN)) { + ret += sprintf(buf+ret, "\n"); + return ret; + } /* * Figure out the current RS-232 lines @@ -3334,7 +2570,6 @@ info->magic = SERIAL_MAGIC; info->port = state->port; info->flags = state->flags; - info->hub6 = state->hub6; info->io_type = state->io_type; info->iomem_base = state->iomem_base; info->iomem_reg_shift = state->iomem_reg_shift; @@ -3389,13 +2624,13 @@ } static int rs_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) + int *eof, void *data) { int i, len = 0, l; off_t begin = 0; - len += sprintf(page, "serinfo:1.0 driver:%s%s revision:%s\n", - serial_version, LOCAL_VERSTRING, serial_revdate); + len += sprintf(page, "serial: %s\n", + LOCAL_VERSTRING); for (i = 0; i < NR_PORTS && len < 4000; i++) { l = line_info(page + len, &rs_table[i]); len += l; @@ -3423,2038 +2658,63 @@ */ /* - * This routine prints out the appropriate serial driver version - * number, and identifies which options were configured into this - * driver. - */ -static char serial_options[] __initdata = -#ifdef CONFIG_HUB6 - " HUB-6" -#define SERIAL_OPT -#endif -#ifdef CONFIG_SERIAL_MANY_PORTS - " MANY_PORTS" -#define SERIAL_OPT -#endif -#ifdef CONFIG_SERIAL_MULTIPORT - " MULTIPORT" -#define SERIAL_OPT -#endif -#ifdef CONFIG_SERIAL_SHARE_IRQ - " SHARE_IRQ" -#define SERIAL_OPT -#endif -#ifdef CONFIG_SERIAL_DETECT_IRQ - " DETECT_IRQ" -#define SERIAL_OPT -#endif -#ifdef ENABLE_SERIAL_PCI - " SERIAL_PCI" -#define SERIAL_OPT -#endif -#ifdef ENABLE_SERIAL_PNP - " ISAPNP" -#define SERIAL_OPT -#endif -#ifdef ENABLE_SERIAL_ACPI - " SERIAL_ACPI" -#define SERIAL_OPT -#endif -#ifdef SERIAL_OPT - " enabled\n"; -#else - " no serial options enabled\n"; -#endif -#undef SERIAL_OPT - -static _INLINE_ void show_serial_version(void) -{ - printk(KERN_INFO "%s version %s%s (%s) with%s", serial_name, - serial_version, LOCAL_VERSTRING, serial_revdate, - serial_options); -} - -/* - * This routine detect the IRQ of a serial port by clearing OUT2 when - * no UART interrupt are requested (IER = 0) (*GPL*). This seems to work at - * each time, as long as no other device permanently request the IRQ. - * If no IRQ is detected, or multiple IRQ appear, this function returns 0. - * The variable "state" and the field "state->port" should not be null. - */ -static unsigned detect_uart_irq (struct serial_state * state) -{ - int irq; - unsigned long irqs; - unsigned char save_mcr, save_ier; - struct async_struct scr_info; /* serial_{in,out} because HUB6 */ - -#ifdef CONFIG_SERIAL_MANY_PORTS - unsigned char save_ICP=0; /* no warning */ - unsigned short ICP=0; - - if (state->flags & ASYNC_FOURPORT) { - ICP = (state->port & 0xFE0) | 0x01F; - save_ICP = inb_p(ICP); - outb_p(0x80, ICP); - (void) inb_p(ICP); - } -#endif - scr_info.magic = SERIAL_MAGIC; - scr_info.state = state; - scr_info.port = state->port; - scr_info.flags = state->flags; -#ifdef CONFIG_HUB6 - scr_info.hub6 = state->hub6; -#endif - scr_info.io_type = state->io_type; - scr_info.iomem_base = state->iomem_base; - scr_info.iomem_reg_shift = state->iomem_reg_shift; - - /* forget possible initially masked and pending IRQ */ - probe_irq_off(probe_irq_on()); - save_mcr = serial_inp(&scr_info, UART_MCR); - save_ier = serial_inp(&scr_info, UART_IER); - serial_outp(&scr_info, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); - - irqs = probe_irq_on(); - serial_outp(&scr_info, UART_MCR, 0); - udelay (10); - if (state->flags & ASYNC_FOURPORT) { - serial_outp(&scr_info, UART_MCR, - UART_MCR_DTR | UART_MCR_RTS); - } else { - serial_outp(&scr_info, UART_MCR, - UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); - } - serial_outp(&scr_info, UART_IER, 0x0f); /* enable all intrs */ - (void)serial_inp(&scr_info, UART_LSR); - (void)serial_inp(&scr_info, UART_RX); - (void)serial_inp(&scr_info, UART_IIR); - (void)serial_inp(&scr_info, UART_MSR); - serial_outp(&scr_info, UART_TX, 0xFF); - udelay (20); - irq = probe_irq_off(irqs); - - serial_outp(&scr_info, UART_MCR, save_mcr); - serial_outp(&scr_info, UART_IER, save_ier); -#ifdef CONFIG_SERIAL_MANY_PORTS - if (state->flags & ASYNC_FOURPORT) - outb_p(save_ICP, ICP); -#endif - return (irq > 0)? irq : 0; -} - -/* - * 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 async_struct *info) -{ - unsigned char old_fcr, old_mcr, old_dll, old_dlm; - int count; - - old_fcr = serial_inp(info, UART_FCR); - old_mcr = serial_inp(info, UART_MCR); - serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_outp(info, UART_MCR, UART_MCR_LOOP); - serial_outp(info, UART_LCR, UART_LCR_DLAB); - old_dll = serial_inp(info, UART_DLL); - old_dlm = serial_inp(info, UART_DLM); - serial_outp(info, UART_DLL, 0x01); - serial_outp(info, UART_DLM, 0x00); - serial_outp(info, UART_LCR, 0x03); - for (count = 0; count < 256; count++) - serial_outp(info, UART_TX, count); - mdelay(20); - for (count = 0; (serial_inp(info, UART_LSR) & UART_LSR_DR) && - (count < 256); count++) - serial_inp(info, UART_RX); - serial_outp(info, UART_FCR, old_fcr); - serial_outp(info, UART_MCR, old_mcr); - serial_outp(info, UART_LCR, UART_LCR_DLAB); - serial_outp(info, UART_DLL, old_dll); - serial_outp(info, 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_startech_uarts(struct async_struct *info, - struct serial_state *state, - unsigned long flags) -{ - unsigned char scratch, scratch2, scratch3, scratch4; - - /* - * 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) - */ - if (state->type == PORT_16550A) { - /* - * 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). - */ - info->ACR = 0; - serial_out(info, UART_LCR, 0xBF); - serial_out(info, UART_EFR, 0x10); - serial_out(info, UART_LCR, 0x00); - /* Check for Oxford Semiconductor 16C950 */ - scratch = serial_icr_read(info, UART_ID1); - scratch2 = serial_icr_read(info, UART_ID2); - scratch3 = serial_icr_read(info, UART_ID3); - - if (scratch == 0x16 && scratch2 == 0xC9 && - (scratch3 == 0x50 || scratch3 == 0x52 || - scratch3 == 0x54)) { - state->type = PORT_16C950; - state->revision = serial_icr_read(info, UART_REV) | - (scratch3 << 8); - return; - } - } - - /* - * We check for a XR16C850 by setting DLL and DLM to 0, and - * then reading back DLL and DLM. If DLM reads back 0x10, - * then the UART is a XR16C850 and the DLL contains the chip - * revision. If DLM reads back 0x14, then the UART is a - * XR16C854. - * - */ - - /* Save the DLL and DLM */ - - serial_outp(info, UART_LCR, UART_LCR_DLAB); - scratch3 = serial_inp(info, UART_DLL); - scratch4 = serial_inp(info, UART_DLM); - - serial_outp(info, UART_DLL, 0); - serial_outp(info, UART_DLM, 0); - scratch2 = serial_inp(info, UART_DLL); - scratch = serial_inp(info, UART_DLM); - serial_outp(info, UART_LCR, 0); - - if (scratch == 0x10 || scratch == 0x14) { - if (scratch == 0x10) - state->revision = scratch2; - state->type = PORT_16850; - return; - } - - /* Restore the DLL and DLM */ - - serial_outp(info, UART_LCR, UART_LCR_DLAB); - serial_outp(info, UART_DLL, scratch3); - serial_outp(info, UART_DLM, scratch4); - serial_outp(info, UART_LCR, 0); - /* - * 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(info) == 64) - state->type = PORT_16654; - else - state->type = PORT_16650V2; -} - -/* - * 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 serial_state * state) -{ - unsigned char status1, status2, scratch, scratch2, scratch3; - unsigned char save_lcr, save_mcr; - struct async_struct *info, scr_info; - unsigned long flags; - - state->type = PORT_UNKNOWN; - -#ifdef SERIAL_DEBUG_AUTOCONF - printk("Testing ttyS%d (0x%04lx, 0x%04x)...\n", state->line, - state->port, (unsigned) state->iomem_base); -#endif - - if (!CONFIGURED_SERIAL_PORT(state)) - return; - - info = &scr_info; /* This is just for serial_{in,out} */ - - info->magic = SERIAL_MAGIC; - info->state = state; - info->port = state->port; - info->flags = state->flags; -#ifdef CONFIG_HUB6 - info->hub6 = state->hub6; -#endif - info->io_type = state->io_type; - info->iomem_base = state->iomem_base; - info->iomem_reg_shift = state->iomem_reg_shift; - - save_flags(flags); cli(); - - if (!(state->flags & ASYNC_BUGGY_UART) && - !state->iomem_base) { - /* - * 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. - */ - scratch = serial_inp(info, UART_IER); - serial_outp(info, UART_IER, 0); -#ifdef __i386__ - outb(0xff, 0x080); -#endif - scratch2 = serial_inp(info, UART_IER); - serial_outp(info, UART_IER, 0x0F); -#ifdef __i386__ - outb(0, 0x080); -#endif - scratch3 = serial_inp(info, UART_IER); - serial_outp(info, UART_IER, scratch); - if (scratch2 || scratch3 != 0x0F) { -#ifdef SERIAL_DEBUG_AUTOCONF - printk("serial: ttyS%d: simple autoconfig failed " - "(%02x, %02x)\n", state->line, - scratch2, scratch3); -#endif - restore_flags(flags); - return; /* We failed; there's nothing here */ - } - } - - save_mcr = serial_in(info, UART_MCR); - save_lcr = serial_in(info, 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 (!(state->flags & ASYNC_SKIP_TEST)) { - serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A); - status1 = serial_inp(info, UART_MSR) & 0xF0; - serial_outp(info, UART_MCR, save_mcr); - if (status1 != 0x90) { -#ifdef SERIAL_DEBUG_AUTOCONF - printk("serial: ttyS%d: no UART loopback failed\n", - state->line); -#endif - restore_flags(flags); - return; - } - } - serial_outp(info, UART_LCR, 0xBF); /* set up for StarTech test */ - serial_outp(info, UART_EFR, 0); /* EFR is the same as FCR */ - serial_outp(info, UART_LCR, 0); - serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); - scratch = serial_in(info, UART_IIR) >> 6; - switch (scratch) { - case 0: - state->type = PORT_16450; - break; - case 1: - state->type = PORT_UNKNOWN; - break; - case 2: - state->type = PORT_16550; - break; - case 3: - state->type = PORT_16550A; - break; - } - if (state->type == PORT_16550A) { - /* Check for Startech UART's */ - serial_outp(info, UART_LCR, UART_LCR_DLAB); - if (serial_in(info, UART_EFR) == 0) { - state->type = PORT_16650; - } else { - serial_outp(info, UART_LCR, 0xBF); - if (serial_in(info, UART_EFR) == 0) - autoconfig_startech_uarts(info, state, flags); - } - } - if (state->type == PORT_16550A) { - /* Check for TI 16750 */ - serial_outp(info, UART_LCR, save_lcr | UART_LCR_DLAB); - serial_outp(info, UART_FCR, - UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - scratch = serial_in(info, UART_IIR) >> 5; - if (scratch == 7) { - /* - * If this is a 16750, and not a cheap UART - * clone, then it should only go into 64 byte - * mode if the UART_FCR7_64BYTE bit was set - * while UART_LCR_DLAB was latched. - */ - serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_outp(info, UART_LCR, 0); - serial_outp(info, UART_FCR, - UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - scratch = serial_in(info, UART_IIR) >> 5; - if (scratch == 6) - state->type = PORT_16750; - } - serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); - } -#if defined(CONFIG_SERIAL_RSA) && defined(MODULE) - if (state->type == PORT_16550A) { - int i; - - for (i = 0 ; i < PORT_RSA_MAX ; ++i) { - if (!probe_rsa[i] && !force_rsa[i]) - break; - if (((probe_rsa[i] != state->port) || - check_region(state->port + UART_RSA_BASE, 16)) && - (force_rsa[i] != state->port)) - continue; - if (!enable_rsa(info)) - continue; - state->type = PORT_RSA; - state->baud_base = SERIAL_RSA_BAUD_BASE; - break; - } - } -#endif - serial_outp(info, UART_LCR, save_lcr); - if (state->type == PORT_16450) { - scratch = serial_in(info, UART_SCR); - serial_outp(info, UART_SCR, 0xa5); - status1 = serial_in(info, UART_SCR); - serial_outp(info, UART_SCR, 0x5a); - status2 = serial_in(info, UART_SCR); - serial_outp(info, UART_SCR, scratch); - - if ((status1 != 0xa5) || (status2 != 0x5a)) - state->type = PORT_8250; - } - state->xmit_fifo_size = uart_config[state->type].dfl_xmit_fifo_size; - - if (state->type == PORT_UNKNOWN) { - restore_flags(flags); - return; - } - - if (info->port) { -#ifdef CONFIG_SERIAL_RSA - if (state->type == PORT_RSA) - request_region(info->port + UART_RSA_BASE, 16, - "serial_rsa(auto)"); - else -#endif - request_region(info->port,8,"serial(auto)"); - } - - /* - * Reset the UART. - */ -#ifdef CONFIG_SERIAL_RSA - if (state->type == PORT_RSA) - serial_outp(info, UART_RSA_FRR, 0); -#endif - serial_outp(info, UART_MCR, save_mcr); - serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT)); - serial_outp(info, UART_FCR, 0); - (void)serial_in(info, UART_RX); - serial_outp(info, UART_IER, 0); - - restore_flags(flags); -} - -int register_serial(struct serial_struct *req); -void unregister_serial(int line); - -#if (LINUX_VERSION_CODE > 0x20100) -EXPORT_SYMBOL(register_serial); -EXPORT_SYMBOL(unregister_serial); -#else -static struct symbol_table serial_syms = { -#include - X(register_serial), - X(unregister_serial), -#include -}; -#endif - - -#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP) - -static void __devinit printk_pnp_dev_id(unsigned short vendor, - unsigned short device) -{ - printk("%c%c%c%x%x%x%x", - 'A' + ((vendor >> 2) & 0x3f) - 1, - 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1, - 'A' + ((vendor >> 8) & 0x1f) - 1, - (device >> 4) & 0x0f, - device & 0x0f, - (device >> 12) & 0x0f, - (device >> 8) & 0x0f); -} - -static _INLINE_ 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); - } - - } - - /* HP's Diva chip puts the 4th/5th serial port further out, and - * some serial ports are supposed to be hidden on certain models. - */ - if (dev->vendor == PCI_VENDOR_ID_HP && - dev->device == PCI_DEVICE_ID_HP_SAS) { - switch (dev->subsystem_device) { - case 0x104B: /* Maestro */ - if (idx == 3) idx++; - break; - case 0x1282: /* Everest / Longs Peak */ - if (idx > 0) idx++; - if (idx > 2) idx++; - break; - } - if (idx > 2) { - offset = 0x18; - } - } - - 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); -} - -/* - * Common enabler code shared by both PCI and ISAPNP probes - */ -static void __devinit start_pci_pnp_board(struct pci_dev *dev, - struct pci_board *board) -{ - int k, line; - struct serial_struct serial_req; - int base_baud; - - if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) { - printk("serial: PNP device '"); - printk_pnp_dev_id(dev->vendor, dev->device); - printk("' prepare failed\n"); - return; - } - - if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) { - printk("serial: PNP device '"); - printk_pnp_dev_id(dev->vendor, dev->device); - printk("' activate failed\n"); - return; - } - - /* - * Run the initialization function, if any - */ - if (board->init_fn && ((board->init_fn)(dev, board, 1) != 0)) - return; - - /* - * Register the serial board in the array if we need to - * shutdown the board on a module unload or card removal - */ - if (DEACTIVATE_FUNC(dev) || board->init_fn) { - for (k=0; k < NR_PCI_BOARDS; k++) - if (serial_pci_board[k].dev == 0) - break; - if (k >= NR_PCI_BOARDS) - return; - serial_pci_board[k].board = *board; - serial_pci_board[k].dev = dev; - } - - 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; - serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE; -#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 - line = register_serial(&serial_req); - if (line < 0) - break; - rs_table[line].baud_base = base_baud; - rs_table[line].dev = dev; - } -} -#endif /* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */ - -#ifdef ENABLE_SERIAL_PCI -/* - * Some PCI serial cards using the PLX 9050 PCI interface chip require - * that the card interrupt be explicitly enabled or disabled. This - * seems to be mainly needed on card using the PLX which also use I/O - * mapped memory. - */ -static int __devinit -pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable) -{ - u8 data, *p, irq_config; - int pci_config; - - irq_config = 0x41; - pci_config = PCI_COMMAND_MEMORY; - if (dev->vendor == PCI_VENDOR_ID_PANACOM) - irq_config = 0x43; - if ((dev->vendor == PCI_VENDOR_ID_PLX) && - (dev->device == PCI_DEVICE_ID_PLX_ROMULUS)) { - /* - * As the megawolf cards have the int pins active - * high, and have 2 UART chips, both ints must be - * enabled on the 9050. Also, the UARTS are set in - * 16450 mode by default, so we have to enable the - * 16C950 'enhanced' mode so that we can use the deep - * FIFOs - */ - irq_config = 0x5b; - pci_config = PCI_COMMAND_MEMORY | PCI_COMMAND_IO; - } - - pci_read_config_byte(dev, PCI_COMMAND, &data); - - if (enable) - pci_write_config_byte(dev, PCI_COMMAND, - data | pci_config); - - /* enable/disable interrupts */ - p = ioremap(pci_resource_start(dev, 0), 0x80); - writel(enable ? irq_config : 0x00, (unsigned long)p + 0x4c); - iounmap(p); - - if (!enable) - pci_write_config_byte(dev, PCI_COMMAND, - data & ~pci_config); - return 0; -} - - -/* - * SIIG serial cards have an PCI interface chip which also controls - * the UART clocking frequency. Each UART can be clocked independently - * (except cards equiped with 4 UARTs) and initial clocking settings - * are stored in the EEPROM chip. It can cause problems because this - * version of serial driver doesn't support differently clocked UART's - * on single PCI card. To prevent this, initialization functions set - * high frequency clocking for all UART's on given card. It is safe (I - * hope) because it doesn't touch EEPROM settings to prevent conflicts - * with other OSes (like M$ DOS). - * - * SIIG support added by Andrey Panin , 10/1999 - * - * There is two family of SIIG serial cards with different PCI - * interface chip and different configuration methods: - * - 10x cards have control registers in IO and/or memory space; - * - 20x cards have control registers in standard PCI configuration space. - * - * SIIG initialization functions exported for use by parport_serial.c module. - */ - -#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) - -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; -} -EXPORT_SYMBOL(pci_siig10x_fn); - -#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) - -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; -} -EXPORT_SYMBOL(pci_siig20x_fn); - -/* 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); - -#ifdef SERIAL_DEBUG_PCI - printk(KERN_DEBUG " Subsystem ID %lx (intel 960)\n", - (unsigned long) board->subdevice); -#endif - /* 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; -} - -/* - * HP's Remote Management Console. The Diva chip came in several - * different versions. N-class, L2000 and A500 have two Diva chips, each - * with 3 UARTs (the third UART on the second chip is unused). Superdome - * and Keystone have one Diva chip with 3 UARTs. Some later machines have - * one Diva chip, but it has been expanded to 5 UARTs. - */ -static int __devinit -pci_hp_diva(struct pci_dev *dev, struct pci_board *board, int enable) -{ - if (!enable) - return 0; - - switch (dev->subsystem_device) { - case 0x1049: /* Prelude Diva 1 */ - case 0x1223: /* Superdome */ - case 0x1226: /* Keystone */ - case 0x1282: /* Everest / Longs Peak */ - board->num_ports = 3; - break; - case 0x104A: /* Prelude Diva 2 */ - board->num_ports = 2; - break; - case 0x104B: /* Maestro */ - board->num_ports = 4; - break; - case 0x1227: /* Powerbar */ - board->num_ports = 1; - break; - } - - 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_b0_bt_2_921600, - - 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_1_115200, - 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, - pbn_hp_diva, -#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_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b0_bt_2_921600 */ - - { 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, 1, 115200 }, /* pbn_b2_1_115200 */ - { 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 }, - { SPCI_FL_BASE0, 5, 115200, 8, 0, pci_hp_diva, 0}, /* pbn_hp_diva */ -#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. + * The serial driver boot-time initialization code! */ -static int __devinit serial_pci_guess_board(struct pci_dev *dev, - struct pci_board *board) +static int __init rs_init(void) { - int num_iomem = 0, num_port = 0, first_port = -1; int i; + struct serial_state * state; - /* - * 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++; - } + printk("pxa & ti16c754b serial driver\n"); + set_GPIO_IRQ_edge(7, GPIO_RISING_EDGE); + set_GPIO_IRQ_edge(24, GPIO_RISING_EDGE); + set_GPIO_IRQ_edge(25, GPIO_RISING_EDGE); + set_GPIO_IRQ_edge(26, GPIO_RISING_EDGE); - /* - * 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 (!request_mem_region(RAMSES_UARTA_PHYS, 16*4, "Ramses UART A")) + printk(KERN_ERR "unable to reserve region\n"); + else { + ramses_uarta = ioremap_nocache(RAMSES_UARTA_PHYS, 16*4); + if (!ramses_uarta) + printk(KERN_ERR "unable to map region\n"); + else { + //printk("ramses_uarta cookie is: %08x\n", (unsigned int) ramses_uarta); + rs_table[3].iomem_base = ramses_uarta; } - - /* - * 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; -} - -static int __devinit serial_init_one(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - struct pci_board *board, tmp; - int rc; - - 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 (%04x,%04x,%04x,%04x)\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)); - } - - start_pci_pnp_board(dev, board); - - return 0; -} - -static void __devexit serial_remove_one(struct pci_dev *dev) -{ - int i; - - /* - * Iterate through all of the ports finding those that belong - * to this PCI device. - */ - for(i = 0; i < NR_PORTS; i++) { - if (rs_table[i].dev != dev) - continue; - unregister_serial(i); - rs_table[i].dev = 0; + if (!request_mem_region(RAMSES_UARTB_PHYS, 16*4, "Ramses UART B")) + printk(KERN_ERR "unable to reserve region\n"); + else { + ramses_uartb = ioremap_nocache(RAMSES_UARTB_PHYS, 16*4); + if (!ramses_uartb) + printk(KERN_ERR "unable to map region\n"); + else { + //printk("ramses_uartb cookie is: %08x\n", (unsigned int) ramses_uartb); + rs_table[4].iomem_base = ramses_uartb; } - /* - * Now execute any board-specific shutdown procedure - */ - for (i=0; i < NR_PCI_BOARDS; i++) { - struct pci_board_inst *brd = &serial_pci_board[i]; - - if (serial_pci_board[i].dev != dev) - continue; - if (brd->board.init_fn) - (brd->board.init_fn)(brd->dev, &brd->board, 0); - if (DEACTIVATE_FUNC(brd->dev)) - (DEACTIVATE_FUNC(brd->dev))(brd->dev); - serial_pci_board[i].dev = 0; } -} - - -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_bt_2_921600 }, - - /* 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_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_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_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_4S_20x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_4 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_4 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_4 }, - - /* Computone devices submitted by Doug McNash dmcnash@computone.com */ - { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, - PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4, - 0, 0, pbn_computone_4 }, - { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, - PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8, - 0, 0, pbn_computone_8 }, - { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, - PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6, - 0, 0, pbn_computone_6 }, - - { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_oxsemi }, - { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, - PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0, pbn_timedia }, - - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_460800 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_460800 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_460800 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_1_115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_1_460800 }, - - /* RAStel 2 port modem, gerg@moreton.com.au */ - { PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_2_115200 }, - - /* EKF addition for i960 Boards form EKF with serial port */ - { PCI_VENDOR_ID_INTEL, 0x1960, - 0xE4BF, PCI_ANY_ID, 0, 0, - pbn_intel_i960 }, - - /* Xircom Cardbus/Ethernet combos */ - { PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_xircom_combo }, - - /* - * Untested PCI modems, sent in from various folks... - */ - - /* Elsa Model 56K PCI Modem, from Andreas Rath */ - { PCI_VENDOR_ID_ROCKWELL, 0x1004, - 0x1048, 0x1500, 0, 0, - pbn_b1_1_115200 }, - - { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, - 0xFF00, 0, 0, 0, - pbn_sgi_ioc3 }, - - /* HP Diva card */ - { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_SAS, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_hp_diva }, - { PCI_VENDOR_ID_HP, 0x1290, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_1_115200 }, - -#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, }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, serial_pci_tbl); - -static struct pci_driver serial_pci_driver = { - name: "serial", - probe: serial_init_one, - remove: __devexit_p(serial_remove_one), - id_table: serial_pci_tbl, -}; - - -/* - * Query PCI space for known serial boards - * If found, add them to the PCI device space in rs_table[] - * - * Accept a maximum of eight boards - * - */ -static void __devinit probe_serial_pci(void) -{ -#ifdef SERIAL_DEBUG_PCI - printk(KERN_DEBUG "Entered probe_serial_pci()\n"); -#endif - - /* Register call PCI serial devices. Null out - * the driver name upon failure, as a signal - * not to attempt to unregister the driver later - */ - if (pci_module_init (&serial_pci_driver) != 0) - serial_pci_driver.name = ""; - -#ifdef SERIAL_DEBUG_PCI - printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n"); -#endif - return; -} - -#endif /* ENABLE_SERIAL_PCI */ - -#ifdef ENABLE_SERIAL_PNP - -struct pnp_board { - unsigned short vendor; - unsigned short device; -}; - -static struct pnp_board pnp_devices[] __devinitdata = { - /* Archtek America Corp. */ - /* Archtek SmartLink Modem 3334BT Plug & Play */ - { ISAPNP_VENDOR('A', 'A', 'C'), ISAPNP_DEVICE(0x000F) }, - /* Anchor Datacomm BV */ - /* SXPro 144 External Data Fax Modem Plug & Play */ - { ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0001) }, - /* SXPro 288 External Data Fax Modem Plug & Play */ - { ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0002) }, - /* Rockwell 56K ACF II Fax+Data+Voice Modem */ - { ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021) }, - /* AZT3005 PnP SOUND DEVICE */ - { ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001) }, - /* Best Data Products Inc. Smart One 336F PnP Modem */ - { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) }, - /* Boca Research */ - /* Boca Complete Ofc Communicator 14.4 Data-FAX */ - { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) }, - /* Boca Research 33,600 ACF Modem */ - { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400) }, - /* Boca 33.6 Kbps Internal FD34FSVD */ - { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x3400) }, - /* Boca 33.6 Kbps Internal FD34FSVD */ - { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) }, - /* Best Data Products Inc. Smart One 336F PnP Modem */ - { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) }, - /* Computer Peripherals Inc */ - /* EuroViVa CommCenter-33.6 SP PnP */ - { ISAPNP_VENDOR('C', 'P', 'I'), ISAPNP_DEVICE(0x4050) }, - /* Creative Labs */ - /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */ - { ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3001) }, - /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */ - { ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3011) }, - /* Creative */ - /* Creative Modem Blaster Flash56 DI5601-1 */ - { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032) }, - /* Creative Modem Blaster V.90 DI5660 */ - { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001) }, - /* FUJITSU */ - /* Fujitsu 33600 PnP-I2 R Plug & Play */ - { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0202) }, - /* Fujitsu FMV-FX431 Plug & Play */ - { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0205) }, - /* Fujitsu 33600 PnP-I4 R Plug & Play */ - { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0206) }, - /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */ - { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0209) }, - /* Archtek America Corp. */ - /* Archtek SmartLink Modem 3334BT Plug & Play */ - { ISAPNP_VENDOR('G', 'V', 'C'), ISAPNP_DEVICE(0x000F) }, - /* Hayes */ - /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */ - { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x0001) }, - /* Hayes Optima 336 V.34 + FAX + Voice PnP */ - { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000C) }, - /* Hayes Optima 336B V.34 + FAX + Voice PnP */ - { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000D) }, - /* Hayes Accura 56K Ext Fax Modem PnP */ - { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5670) }, - /* Hayes Accura 56K Ext Fax Modem PnP */ - { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5674) }, - /* Hayes Accura 56K Fax Modem PnP */ - { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5675) }, - /* Hayes 288, V.34 + FAX */ - { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF000) }, - /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */ - { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF001) }, - /* IBM */ - /* IBM Thinkpad 701 Internal Modem Voice */ - { ISAPNP_VENDOR('I', 'B', 'M'), ISAPNP_DEVICE(0x0033) }, - /* Intertex */ - /* Intertex 28k8 33k6 Voice EXT PnP */ - { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC801) }, - /* Intertex 33k6 56k Voice EXT PnP */ - { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC901) }, - /* Intertex 28k8 33k6 Voice SP EXT PnP */ - { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD801) }, - /* Intertex 33k6 56k Voice SP EXT PnP */ - { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD901) }, - /* Intertex 28k8 33k6 Voice SP INT PnP */ - { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF401) }, - /* Intertex 28k8 33k6 Voice SP EXT PnP */ - { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF801) }, - /* Intertex 33k6 56k Voice SP EXT PnP */ - { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF901) }, - /* Kortex International */ - /* KORTEX 28800 Externe PnP */ - { ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0x4522) }, - /* KXPro 33.6 Vocal ASVD PnP */ - { ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0xF661) }, - /* Lasat */ - /* LASAT Internet 33600 PnP */ - { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4040) }, - /* Lasat Safire 560 PnP */ - { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4540) }, - /* Lasat Safire 336 PnP */ - { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x5440) }, - /* Microcom, Inc. */ - /* Microcom TravelPorte FAST V.34 Plug & Play */ - { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x281) }, - /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */ - { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0336) }, - /* Microcom DeskPorte FAST EP 28.8 Plug & Play */ - { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0339) }, - /* Microcom DeskPorte 28.8P Plug & Play */ - { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0342) }, - /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ - { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0500) }, - /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ - { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0501) }, - /* Microcom DeskPorte 28.8S Internal Plug & Play */ - { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0502) }, - /* Motorola */ - /* Motorola BitSURFR Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1105) }, - /* Motorola TA210 Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1111) }, - /* Motorola HMTA 200 (ISDN) Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1114) }, - /* Motorola BitSURFR Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1115) }, - /* Motorola Lifestyle 28.8 Internal */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1190) }, - /* Motorola V.3400 Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1501) }, - /* Motorola Lifestyle 28.8 V.34 Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1502) }, - /* Motorola Power 28.8 V.34 Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1505) }, - /* Motorola ModemSURFR External 28.8 Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1509) }, - /* Motorola Premier 33.6 Desktop Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150A) }, - /* Motorola VoiceSURFR 56K External PnP */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150F) }, - /* Motorola ModemSURFR 56K External PnP */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1510) }, - /* Motorola ModemSURFR 56K Internal PnP */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1550) }, - /* Motorola ModemSURFR Internal 28.8 Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1560) }, - /* Motorola Premier 33.6 Internal Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1580) }, - /* Motorola OnlineSURFR 28.8 Internal Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15B0) }, - /* Motorola VoiceSURFR 56K Internal PnP */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0) }, - /* Com 1 */ - /* Deskline K56 Phone System PnP */ - { ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00A1) }, - /* PC Rider K56 Phone System PnP */ - { ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00F2) }, - /* Pace 56 Voice Internal Plug & Play Modem */ - { ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430) }, - /* Generic */ - /* Generic standard PC COM port */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0500) }, - /* Generic 16550A-compatible COM port */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0501) }, - /* Compaq 14400 Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000) }, - /* Compaq 2400/9600 Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC001) }, - /* Dial-Up Networking Serial Cable between 2 PCs */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC031) }, - /* Dial-Up Networking Parallel Cable between 2 PCs */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC032) }, - /* Standard 9600 bps Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC100) }, - /* Standard 14400 bps Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC101) }, - /* Standard 28800 bps Modem*/ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC102) }, - /* Standard Modem*/ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC103) }, - /* Standard 9600 bps Modem*/ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC104) }, - /* Standard 14400 bps Modem*/ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC105) }, - /* Standard 28800 bps Modem*/ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC106) }, - /* Standard Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC107) }, - /* Standard 9600 bps Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC108) }, - /* Standard 14400 bps Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC109) }, - /* Standard 28800 bps Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10A) }, - /* Standard Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10B) }, - /* Standard 9600 bps Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10C) }, - /* Standard 14400 bps Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10D) }, - /* Standard 28800 bps Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10E) }, - /* Standard Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10F) }, - /* Standard PCMCIA Card Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x2000) }, - /* Rockwell */ - /* Modular Technology */ - /* Rockwell 33.6 DPF Internal PnP */ - /* Modular Technology 33.6 Internal PnP */ - { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0030) }, - /* Kortex International */ - /* KORTEX 14400 Externe PnP */ - { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0100) }, - /* Viking Components, Inc */ - /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */ - { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x4920) }, - /* Rockwell */ - /* British Telecom */ - /* Modular Technology */ - /* Rockwell 33.6 DPF External PnP */ - /* BT Prologue 33.6 External PnP */ - /* Modular Technology 33.6 External PnP */ - { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x00A0) }, - /* Viking 56K FAX INT */ - { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x0262) }, - /* SupraExpress 28.8 Data/Fax PnP modem */ - { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310) }, - /* SupraExpress 33.6 Data/Fax PnP modem */ - { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1421) }, - /* SupraExpress 33.6 Data/Fax PnP modem */ - { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1590) }, - /* SupraExpress 33.6 Data/Fax PnP modem */ - { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1760) }, - /* Phoebe Micro */ - /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */ - { ISAPNP_VENDOR('T', 'E', 'X'), ISAPNP_DEVICE(0x0011) }, - /* Archtek America Corp. */ - /* Archtek SmartLink Modem 3334BT Plug & Play */ - { ISAPNP_VENDOR('U', 'A', 'C'), ISAPNP_DEVICE(0x000F) }, - /* 3Com Corp. */ - /* Gateway Telepath IIvi 33.6 */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0000) }, - /* Sportster Vi 14.4 PnP FAX Voicemail */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0004) }, - /* U.S. Robotics 33.6K Voice INT PnP */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006) }, - /* U.S. Robotics 33.6K Voice EXT PnP */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0007) }, - /* U.S. Robotics 33.6K Voice INT PnP */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2002) }, - /* U.S. Robotics 56K Voice INT PnP */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2070) }, - /* U.S. Robotics 56K Voice EXT PnP */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2080) }, - /* U.S. Robotics 56K FAX INT */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031) }, - /* U.S. Robotics 56K Voice INT PnP */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3070) }, - /* U.S. Robotics 56K Voice EXT PnP */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3080) }, - /* U.S. Robotics 56K Voice INT PnP */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3090) }, - /* U.S. Robotics 56K Message */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9100) }, - /* U.S. Robotics 56K FAX EXT PnP*/ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9160) }, - /* U.S. Robotics 56K FAX INT PnP*/ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9170) }, - /* U.S. Robotics 56K Voice EXT PnP*/ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9180) }, - /* U.S. Robotics 56K Voice INT PnP*/ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9190) }, - { 0, } -}; - -static inline void 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 = modem_names; - - while (*tmp) { - if (strstr(name, *tmp)) - return 1; - tmp++; + if (!request_mem_region(RAMSES_UARTC_PHYS, 16*4, "Ramses UART C")) + printk(KERN_ERR "unable to reserve region\n"); + else { + ramses_uartc = ioremap_nocache(RAMSES_UARTC_PHYS, 16*4); + if (!ramses_uartc) + printk(KERN_ERR "unable to map region\n"); + else { + //printk("ramses_uartc cookie is: %08x\n", (unsigned int) ramses_uartc); + rs_table[5].iomem_base = ramses_uartc; } - return 0; -} - -static inline int 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 _INLINE_ serial_pnp_guess_board(struct pci_dev *dev, - struct pci_board *board) -{ - 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 1; - - if (!res || res->next) - return 1; - - 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 1; -} - -static void __devinit probe_serial_pnp(void) -{ - struct pci_dev *dev = NULL; - struct pnp_board *pnp_board; - struct pci_board board; - -#ifdef SERIAL_DEBUG_PNP - printk("Entered probe_serial_pnp()\n"); -#endif - if (!isapnp_present()) { -#ifdef SERIAL_DEBUG_PNP - printk("Leaving probe_serial_pnp() (no isapnp)\n"); -#endif - return; + if (!request_mem_region(RAMSES_UARTD_PHYS, 16*4, "Ramses UART D")) + printk(KERN_ERR "unable to reserve region\n"); + else { + ramses_uartd = ioremap_nocache(RAMSES_UARTD_PHYS, 16*4); + if (!ramses_uartd) + printk(KERN_ERR "unable to map region\n"); + else { + //printk("ramses_uartd cookie is: %08x\n", (unsigned int) ramses_uartd); + rs_table[6].iomem_base = ramses_uartd; } - - isapnp_for_each_dev(dev) { - if (dev->active) - continue; - - memset(&board, 0, sizeof(board)); - board.flags = SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT; - board.num_ports = 1; - board.base_baud = 115200; - - for (pnp_board = pnp_devices; pnp_board->vendor; pnp_board++) - if ((dev->vendor == pnp_board->vendor) && - (dev->device == pnp_board->device)) - break; - - if (pnp_board->vendor) { - /* Special case that's more efficient to hardcode */ - if ((pnp_board->vendor == ISAPNP_VENDOR('A', 'K', 'Y') && - pnp_board->device == ISAPNP_DEVICE(0x1021))) - board.flags |= SPCI_FL_NO_SHIRQ; - } else { - if (serial_pnp_guess_board(dev, &board)) - continue; } - - if (board.flags & SPCI_FL_NO_SHIRQ) - avoid_irq_share(dev); - start_pci_pnp_board(dev, &board); - } - -#ifdef SERIAL_DEBUG_PNP - printk("Leaving probe_serial_pnp() (probe finished)\n"); -#endif - return; -} - -#endif /* ENABLE_SERIAL_PNP */ - -/* - * The serial driver boot-time initialization code! - */ -static int __init rs_init(void) -{ - int i; - struct serial_state * state; - init_bh(SERIAL_BH, do_serial_bh); init_timer(&serial_timer); serial_timer.function = rs_timer; @@ -5463,10 +2723,6 @@ for (i = 0; i < NR_IRQS; i++) { IRQ_ports[i] = 0; IRQ_timeout[i] = 0; -#ifdef CONFIG_SERIAL_MULTIPORT - memset(&rs_multiport[i], 0, - sizeof(struct rs_multiport_struct)); -#endif } #ifdef CONFIG_SERIAL_CONSOLE /* @@ -5480,29 +2736,25 @@ rs_table[i].irq = 0; } #endif - show_serial_version(); - /* Initialize the tty_driver structure */ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; -#if (LINUX_VERSION_CODE > 0x20100) serial_driver.driver_name = "serial"; -#endif -#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) +#if defined(CONFIG_DEVFS_FS) serial_driver.name = "tts/%d"; #else serial_driver.name = "ttyS"; #endif serial_driver.major = TTY_MAJOR; - serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET; - serial_driver.name_base = SERIAL_DEV_OFFSET; + serial_driver.minor_start = 64; + serial_driver.name_base = 0; serial_driver.num = NR_PORTS; serial_driver.type = TTY_DRIVER_TYPE_SERIAL; serial_driver.subtype = SERIAL_TYPE_NORMAL; serial_driver.init_termios = tty_std_termios; serial_driver.init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; + B115200 | CS8 | CREAD | HUPCL | CLOCAL; serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; serial_driver.refcount = &serial_refcount; serial_driver.table = serial_table; @@ -5524,31 +2776,25 @@ serial_driver.stop = rs_stop; serial_driver.start = rs_start; serial_driver.hangup = rs_hangup; -#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ serial_driver.break_ctl = rs_break; -#endif -#if (LINUX_VERSION_CODE >= 131343) serial_driver.send_xchar = rs_send_xchar; serial_driver.wait_until_sent = rs_wait_until_sent; serial_driver.read_proc = rs_read_proc; -#endif /* * The callout device is just like normal device except for * major number and the subtype code. */ callout_driver = serial_driver; -#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) +#if defined(CONFIG_DEVFS_FS) callout_driver.name = "cua/%d"; #else callout_driver.name = "cua"; #endif callout_driver.major = TTYAUX_MAJOR; callout_driver.subtype = SERIAL_TYPE_CALLOUT; -#if (LINUX_VERSION_CODE >= 131343) callout_driver.read_proc = 0; callout_driver.proc_entry = 0; -#endif if (tty_register_driver(&serial_driver)) panic("Couldn't register serial driver\n"); @@ -5569,53 +2815,23 @@ state->icount.frame = state->icount.parity = 0; state->icount.overrun = state->icount.brk = 0; state->irq = irq_cannonicalize(state->irq); - if (state->hub6) - state->io_type = SERIAL_IO_HUB6; 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) { - state->type = PORT_UNKNOWN; - autoconfig(state); - } } for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { if (state->type == PORT_UNKNOWN) continue; - if ( (state->flags & ASYNC_BOOT_AUTOCONF) - && (state->flags & ASYNC_AUTO_IRQ) - && (state->port != 0 || state->iomem_base != 0)) - state->irq = detect_uart_irq(state); - if (state->io_type == SERIAL_IO_MEM) { - printk(KERN_INFO"ttyS%02d%s at 0x%p (irq = %d) is a %s\n", - state->line + SERIAL_DEV_OFFSET, - (state->flags & ASYNC_FOURPORT) ? " FourPort" : "", - state->iomem_base, state->irq, - uart_config[state->type].name); - } - else { - printk(KERN_INFO "ttyS%02d%s at 0x%04lx (irq = %d) is a %s\n", - state->line + SERIAL_DEV_OFFSET, - (state->flags & ASYNC_FOURPORT) ? " FourPort" : "", - state->port, state->irq, + printk(KERN_INFO"tts/%d at irq %d is a %s\n", + state->line, + state->irq, uart_config[state->type].name); - } tty_register_devfs(&serial_driver, 0, serial_driver.minor_start + state->line); tty_register_devfs(&callout_driver, 0, callout_driver.minor_start + state->line); } -#ifdef ENABLE_SERIAL_PCI - probe_serial_pci(); -#endif -#ifdef ENABLE_SERIAL_PNP - probe_serial_pnp(); -#endif return 0; } @@ -5627,6 +2843,8 @@ { int i = req->line; + printk("%s\n", __FUNCTION__); + if (i >= NR_IRQS) return(-ENOENT); rs_table[i].magic = 0; @@ -5639,7 +2857,6 @@ rs_table[i].flags = req->flags; rs_table[i].close_delay = req->close_delay; rs_table[i].io_type = req->io_type; - rs_table[i].hub6 = req->hub6; rs_table[i].iomem_base = req->iomem_base; rs_table[i].iomem_reg_shift = req->iomem_reg_shift; rs_table[i].type = req->type; @@ -5726,7 +2943,6 @@ info->iomem_base = req->iomem_base; info->iomem_reg_shift = req->iomem_reg_shift; } - autoconfig(state); if (state->type == PORT_UNKNOWN) { restore_flags(flags); printk("register_serial(): autoconfig failed\n"); @@ -5734,11 +2950,8 @@ } restore_flags(flags); - if ((state->flags & ASYNC_AUTO_IRQ) && CONFIGURED_SERIAL_PORT(state)) - state->irq = detect_uart_irq(state); - printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n", - state->line + SERIAL_DEV_OFFSET, + state->line, state->iomem_base ? "iomem" : "port", state->iomem_base ? (unsigned long)state->iomem_base : state->port, state->irq, uart_config[state->type].name); @@ -5746,7 +2959,7 @@ serial_driver.minor_start + state->line); tty_register_devfs(&callout_driver, 0, callout_driver.minor_start + state->line); - return state->line + SERIAL_DEV_OFFSET; + return state->line; } /** @@ -5785,7 +2998,6 @@ int i; struct async_struct *info; - /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ del_timer_sync(&serial_timer); save_flags(flags); cli(); remove_bh(SERIAL_BH); @@ -5803,41 +3015,31 @@ kfree(info); } if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) { -#ifdef CONFIG_SERIAL_RSA - if (rs_table[i].type == PORT_RSA) - release_region(rs_table[i].port + - UART_RSA_BASE, 16); - else -#endif release_region(rs_table[i].port, 8); } -#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP) - if (rs_table[i].iomem_base) - iounmap(rs_table[i].iomem_base); -#endif - } -#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP) - for (i=0; i < NR_PCI_BOARDS; i++) { - struct pci_board_inst *brd = &serial_pci_board[i]; - - if (serial_pci_board[i].dev == 0) - continue; - if (brd->board.init_fn) - (brd->board.init_fn)(brd->dev, &brd->board, 0); - if (DEACTIVATE_FUNC(brd->dev)) - (DEACTIVATE_FUNC(brd->dev))(brd->dev); } -#endif if (tmp_buf) { unsigned long pg = (unsigned long) tmp_buf; tmp_buf = NULL; free_page(pg); } -#ifdef ENABLE_SERIAL_PCI - if (serial_pci_driver.name[0]) - pci_unregister_driver (&serial_pci_driver); -#endif + if (ramses_uarta) { + iounmap(ramses_uarta); + release_mem_region(RAMSES_UARTA_PHYS, 16*4); + } + if (ramses_uartb) { + iounmap(ramses_uartb); + release_mem_region(RAMSES_UARTB_PHYS, 16*4); + } + if (ramses_uartc) { + iounmap(ramses_uartc); + release_mem_region(RAMSES_UARTC_PHYS, 16*4); + } + if (ramses_uartd) { + iounmap(ramses_uartd); + release_mem_region(RAMSES_UARTD_PHYS, 16*4); + } } module_init(rs_init); @@ -5946,7 +3148,7 @@ static struct async_struct *info; struct serial_state *state; unsigned cval; - int baud = 9600; + int baud = 115200; int bits = 8; int parity = 'n'; int doflow = 0; @@ -5954,6 +3156,8 @@ int quot = 0; char *s; + printk("%s\n", __FUNCTION__); + if (options) { baud = simple_strtoul(options, NULL, 10); s = options; @@ -6028,19 +3232,12 @@ info->state = state; info->port = state->port; info->flags = state->flags; -#ifdef CONFIG_HUB6 - info->hub6 = state->hub6; -#endif info->io_type = state->io_type; info->iomem_base = state->iomem_base; info->iomem_reg_shift = state->iomem_reg_shift; quot = state->baud_base / baud; cval = cflag & (CSIZE | CSTOPB); -#if defined(__powerpc__) || defined(__alpha__) - cval >>= 8; -#else /* !__powerpc__ && !__alpha__ */ cval >>= 4; -#endif /* !__powerpc__ && !__alpha__ */ if (cflag & PARENB) cval |= UART_LCR_PARITY; if (!(cflag & PARODD)) @@ -6082,9 +3279,14 @@ */ void __init serial_console_init(void) { + printk("%s\n", __FUNCTION__); + register_console(&sercons); } #endif + +EXPORT_SYMBOL(register_serial); +EXPORT_SYMBOL(unregister_serial); /* Local variables: --- /dev/null +++ linux-2.4.21/drivers/char/sysctl.c @@ -0,0 +1,948 @@ +/* + * /proc/sys-board - Interface to the 16 bit latch and other + * ramses-related hardware settings + * + * (C) 2002,2003 by M&N Logistik-Lösungen Online GmbH + * written by H.Schurig + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../drivers/misc/ucb1x00.h" + +//#define DEBUG +//define CPLD_LED 1 +//define POTI 1 + +/* + * This is the number for the "board" entry in /proc/sys: + */ +#define RAMSES_SYSCTL 1312 + +/* + * These are the numbers for the entries in /etc/sys/board + */ +enum { + CTL_NAME=991, + CTL_CPLD_VERSION, + CTL_BOOTLOADER_CRC, + CTL_LINUX_CRC, + CTL_LED_BLUE, + CTL_LED_ORANGE, + CTL_UART, + CTL_MMC, + CTL_POWEROFF, + CTL_GSM_POWER, + CTL_GSM_RESET, + CTL_SCANNER_POWER, + CTL_SCANNER_WAKE, + CTL_SCANNER_TRIG, + CTL_SCANNER_BEAM, + CTL_KEY_SCAN, + CTL_KEY_SUSPEND, + CTL_KEY_OFF, + CTL_USBBUS_POWER, + CTL_USBCHIP_POWER, +#ifdef CPLD_LED + CTL_LED_CPLD, + CTL_LED_CPLD_RED, +#endif + CTL_LCD_VCC, + CTL_LCD_DISPOFF, + CTL_LCD_BLIGHT, +#ifdef DEBUG + CTL_LCD_PWM0, + CTL_LCD_PWM1, +#endif + CTL_LCD_BRIGHTNESS, + CTL_LCD_CONTRAST, + CTL_LCD_FBTURN, + CTL_LCD_TYPE, + CTL_CONTROL_SHADOW, + CTL_COREVOLT, +#ifdef POTI + CTL_LCD_POTI_NINC, + CTL_LCD_POTI_NCS, + CTL_LCD_POTI_UP, +#endif +#ifdef CONFIG_MCP_UCB1400_TS + CTL_ADC0, + CTL_ADC1, + CTL_ADC2, + CTL_ADC3, +#else +#error NO UCB +#endif + CTL_CHG_STS, + CTL_WALL_IN, + CTL_BATT_TMP, + CTL_BATT_LMD, + CTL_BATT_VSB, + CTL_BATT_RCAC, + CTL_BATT_CACT, + CTL_BATT_SAE, + CTL_BATT_DCR, +}; + +static const char ramses_board_name[] = "ramses"; +static int dummy_int = 0; +static char dummy_str[80]; + + + +/******************************************************************/ +/* ADC communication */ +/******************************************************************/ + + +#ifdef CONFIG_MCP_UCB1400_TS +static int adc_get(int channel) +{ + int val; + struct ucb1x00 *ucb = ucb1x00_get(); + + ucb1x00_adc_enable(ucb); + val = ucb1x00_adc_read(ucb, channel, 0); + ucb1x00_adc_disable(ucb); + + return val; +} +#endif + + + +static int +ramses_sysctl_handler(ctl_table * ctl, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + int *valp = ctl->data; + int val; + int ret; + unsigned crc; + void *flash; + +#ifdef DEBUG + printk("ramses_control_shadow: %04x\n", ramses_control_shadow); +#endif + + // Update parameters from the real registers + switch (ctl->ctl_name) { + case CTL_CPLD_VERSION: + sprintf(dummy_str,"20%02ld-%02ld-%02ld.%ld\n", + RAMSES_CPLD_YEAR & 0xff, + RAMSES_CPLD_MONTH & 0xff, + RAMSES_CPLD_DAY & 0xff, + RAMSES_CPLD_REV & 0xff); + return proc_dostring(ctl,write,filp,buffer,lenp); + + case CTL_BOOTLOADER_CRC: + flash = ioremap_nocache(RAMSES_FLASH_PHYS, 0x40000); + crc = ether_crc_le(0x40000, flash); + iounmap(flash); + sprintf(dummy_str,"%08x", crc); + return proc_dostring(ctl,write,filp,buffer,lenp); + + case CTL_LINUX_CRC: + flash = ioremap_nocache(RAMSES_FLASH_PHYS+0x40000, 3*0x40000); + crc = ether_crc_le(3*0x40000, flash); + iounmap(flash); + sprintf(dummy_str,"%08x", crc); + return proc_dostring(ctl,write,filp,buffer,lenp); + + case CTL_LED_BLUE: + *valp = (ramses_control_shadow & RAMSES_CONTROL_LED_BLUE_) == 0; + break; + case CTL_LED_ORANGE: + *valp = (ramses_control_shadow & RAMSES_CONTROL_LED_ORANGE_) == 0; + break; + case CTL_UART: + *valp = (ramses_control_shadow & RAMSES_CONTROL_UART_PWR) != 0; + break; + case CTL_MMC: + *valp = (ramses_control_shadow & RAMSES_CONTROL_MMC_PWR) != 0; + break; + case CTL_POWEROFF: + *valp = 0; + break; + case CTL_GSM_POWER: + *valp = (ramses_control_shadow & RAMSES_CONTROL_GSM_PWR) != 0; + break; + case CTL_GSM_RESET: + *valp = (ramses_control_shadow & RAMSES_CONTROL_GSM_RESET) != 0; + break; + + case CTL_SCANNER_POWER: + *valp = (ramses_control_shadow & RAMSES_CONTROL_SCANNER_PWR) != 0; + break; + case CTL_SCANNER_WAKE: + *valp = (ramses_control_shadow & RAMSES_CONTROL_SCANNER_WAKE_) == 0; + break; + case CTL_SCANNER_TRIG: + *valp = (ramses_control_shadow & RAMSES_CONTROL_SCANNER_TRIG_) == 0; + break; + case CTL_SCANNER_BEAM: + *valp = ramses_flags & RAMSES_FLAGS_SCANNER_BEAM; + break; + + case CTL_KEY_SCAN: + *valp = (ramses_flags & RAMSES_FLAGS_KEY_SCAN) != 0; + break; + case CTL_KEY_SUSPEND: + *valp = (ramses_flags & RAMSES_FLAGS_KEY_SUSPEND) != 0; + break; + case CTL_KEY_OFF: + *valp = (ramses_flags & RAMSES_FLAGS_KEY_OFF) != 0; + break; + + case CTL_USBBUS_POWER: + *valp = (ramses_control_shadow & RAMSES_CONTROL_USB) != 0; + break; + case CTL_USBCHIP_POWER: + *valp = (RAMSES_CPLD_PERIPH_PWR & USB_HOST_PWR_EN) != 0; + break; +#ifdef CPLD_LED + case CTL_LED_CPLD: + *valp = (RAMSES_CPLD_LED_CONTROL & CPLD_LED1) == 0; + break; + case CTL_LED_CPLD_RED: + *valp = (RAMSES_CPLD_LED_CONTROL & CPLD_LED2) == 0; + break; +#endif + case CTL_LCD_BLIGHT: + *valp = (ramses_control_shadow & RAMSES_CONTROL_LCD_BLIGHT) != 0; + break; + case CTL_LCD_VCC: + *valp = (RAMSES_CPLD_LCD & RAMSES_LCD_VCC) != 0; + break; + case CTL_LCD_DISPOFF: + *valp = (RAMSES_CPLD_LCD & RAMSES_LCD_DISPOFF) != 0; + break; +#ifdef DEBUG + case CTL_LCD_PWM0: + *valp = PWM_PWDUTY0; + break; + case CTL_LCD_PWM1: +#ifdef OLDCODE + *valp = ramses_lcd_pwm1_shadow; +#else + *valp = PWM_PWDUTY1; +#endif + break; +#endif + case CTL_LCD_BRIGHTNESS: + *valp = ramses_lcd_get_brightness(); + break; + case CTL_LCD_CONTRAST: + *valp = ramses_lcd_get_contrast(); + break; + case CTL_LCD_FBTURN: + *valp = (ramses_flags & RAMSES_FLAGS_LCD_FBTURN) != 0; + break; + case CTL_LCD_TYPE: + *valp = ramses_lcd_type; + break; + + case CTL_CONTROL_SHADOW: + sprintf(dummy_str,"%04x", ramses_control_shadow); + return proc_dostring(ctl,write,filp,buffer,lenp); + + case CTL_COREVOLT: + *valp = ramses_corevolt_shadow; + break; + +#ifdef POTI + case CTL_LCD_POTI_NINC: + *valp = (RAMSES_CPLD_LCD & RAMSES_LCD_PINC) != 0; + break; + case CTL_LCD_POTI_NCS: + *valp = (RAMSES_CPLD_LCD & RAMSES_LCD_PCS) != 0; + break; + case CTL_LCD_POTI_UP: + *valp = (RAMSES_CPLD_LCD & RAMSES_LCD_PUP) != 0; + break; +#endif + +#ifdef CONFIG_MCP_UCB1400_TS + case CTL_ADC0: + *valp = adc_get(UCB_ADC_INP_AD0); + break; + case CTL_ADC1: + *valp = adc_get(UCB_ADC_INP_AD1); + break; + case CTL_ADC2: + *valp = adc_get(UCB_ADC_INP_AD2); + break; + case CTL_ADC3: + *valp = adc_get(UCB_ADC_INP_AD3); + break; +#endif + + case CTL_CHG_STS: + *valp = (RAMSES_CPLD_MISC_STATUS & RAMSES_CHG_STS) == 0; + break; + case CTL_WALL_IN: + *valp = (RAMSES_CPLD_MISC_STATUS & RAMSES_WALL_IN) != 0; + break; + + case CTL_BATT_TMP: + *valp = ramses_hdq_get_reg(HDQ_TMP) >> 4; + break; + case CTL_BATT_LMD: + *valp = ramses_hdq_get_reg(HDQ_LMD); + break; + case CTL_BATT_VSB: + *valp = ramses_hdq_get_reg(HDQ_VSB); + break; + case CTL_BATT_RCAC: + *valp = ramses_hdq_get_reg(HDQ_RCAC) & 0x7f; + break; + case CTL_BATT_CACT: + *valp = ramses_hdq_get_reg(HDQ_CACT); + break; + case CTL_BATT_SAE: + *valp = ramses_hdq_get_reg(HDQ_SAEH) << 8 | ramses_hdq_get_reg(HDQ_SAEL); + break; + case CTL_BATT_DCR: + *valp = ramses_hdq_get_reg(HDQ_DCR); + break; + + default: + // Just ignore unsupported parameters + break; + } + + // Save old state + val = *valp; + + // Perform the generic integer operation + if ((ret = proc_dointvec(ctl, write, filp, buffer, lenp)) != 0) + return (ret); + + // Write changes out to the registers + if (write && *valp != val) { + + val = *valp; + switch (ctl->ctl_name) { + + case CTL_LED_BLUE: + if (val) + RAMSES_LED_BLUE_ON() + else + RAMSES_LED_BLUE_OFF(); + break; + + case CTL_LED_ORANGE: + if (val) + RAMSES_LED_ORANGE_ON() + else + RAMSES_LED_ORANGE_OFF(); + break; + + case CTL_UART: + if (val) + RAMSES_UART_ON() + else + RAMSES_UART_OFF(); + break; + + case CTL_MMC: + if (val) + RAMSES_MMC_ON() + else + RAMSES_MMC_OFF(); + break; + + case CTL_POWEROFF: + if (val) + pm_power_off(); + break; + + case CTL_GSM_POWER: + if (val) + RAMSES_GSM_ON() + else + RAMSES_GSM_OFF(); + break; + + case CTL_GSM_RESET: + if (val) + RAMSES_GSM_RESET_ON() + else + RAMSES_GSM_RESET_OFF(); + break; + + case CTL_SCANNER_POWER: + if (val) + RAMSES_SCANNER_ON() + else + RAMSES_SCANNER_OFF(); + break; + + case CTL_SCANNER_WAKE: + if (val) + RAMSES_SCANNER_WAKE_ON() + else + RAMSES_SCANNER_WAKE_OFF(); + break; + + case CTL_SCANNER_TRIG: + if (val) + RAMSES_SCANNER_TRIG_ON() + else + RAMSES_SCANNER_TRIG_OFF(); + break; + + case CTL_SCANNER_BEAM: + if (val) + ramses_flags |= RAMSES_FLAGS_SCANNER_BEAM; + else + ramses_flags &= ~RAMSES_FLAGS_SCANNER_BEAM; + break; + + case CTL_KEY_SCAN: + if (val) + ramses_flags |= RAMSES_FLAGS_KEY_SCAN; + else + ramses_flags &= ~RAMSES_FLAGS_KEY_SCAN; + break; + + case CTL_KEY_SUSPEND: + if (val) + ramses_flags |= RAMSES_FLAGS_KEY_SUSPEND; + else + ramses_flags &= ~RAMSES_FLAGS_KEY_SUSPEND; + break; + + case CTL_KEY_OFF: + if (val) + ramses_flags |= RAMSES_FLAGS_KEY_OFF; + else + ramses_flags &= ~RAMSES_FLAGS_KEY_OFF; + break; + + case CTL_USBBUS_POWER: + if (val) + RAMSES_USB_BUS_ON() + else + RAMSES_USB_BUS_OFF(); + break; + + case CTL_USBCHIP_POWER: + if (val) + RAMSES_CPLD_PERIPH_PWR |= USB_HOST_PWR_EN; + else + RAMSES_CPLD_PERIPH_PWR &= ~USB_HOST_PWR_EN; + break; + +#ifdef CPLD_LED + case CTL_LED_CPLD: + if (val) + RAMSES_CPLD_LED_CONTROL &= ~CPLD_LED1; + else + RAMSES_CPLD_LED_CONTROL |= CPLD_LED1; + break; + + case CTL_LED_CPLD_RED: + if (val) + RAMSES_CPLD_LED_CONTROL &= ~CPLD_LED2; + else + RAMSES_CPLD_LED_CONTROL |= CPLD_LED2; + break; +#endif + + case CTL_LCD_BLIGHT: + if (val) + ramses_lcd_backlight_on(); + else + ramses_lcd_backlight_off(); + break; + + case CTL_LCD_VCC: + if (val) + RAMSES_CPLD_LCD |= RAMSES_LCD_VCC; + else + RAMSES_CPLD_LCD &= ~RAMSES_LCD_VCC; + break; + + case CTL_LCD_DISPOFF: + if (val) + RAMSES_CPLD_LCD |= RAMSES_LCD_DISPOFF; + else + RAMSES_CPLD_LCD &= ~RAMSES_LCD_DISPOFF; + break; + +#ifdef DEBUG + case CTL_LCD_PWM0: + PWM_PWDUTY0 = val; + break; + + case CTL_LCD_PWM1: +#ifdef OLDCODE + ramses_lcd_set_pwm1(val); +#else + PWM_PWDUTY1 = val; +#endif + break; +#endif + + case CTL_LCD_BRIGHTNESS: + ramses_lcd_set_brightness(val); + break; + + case CTL_LCD_CONTRAST: + ramses_lcd_set_contrast(val); + break; + + case CTL_LCD_FBTURN: + if (val) + ramses_flags |= RAMSES_FLAGS_LCD_FBTURN; + else + ramses_flags &= ~RAMSES_FLAGS_LCD_FBTURN; + break; + + case CTL_COREVOLT: + ramses_set_corevolt(val); + break; + +#ifdef POTI + case CTL_LCD_POTI_NCS: + if (val) + RAMSES_CPLD_LCD |= RAMSES_LCD_PCS; + else + RAMSES_CPLD_LCD &= ~RAMSES_LCD_PCS; + break; + case CTL_LCD_POTI_NINC: + if (val) + RAMSES_CPLD_LCD |= RAMSES_LCD_PINC; + else + RAMSES_CPLD_LCD &= ~RAMSES_LCD_PINC; + break; + case CTL_LCD_POTI_UP: + if (val) + RAMSES_CPLD_LCD |= RAMSES_LCD_PUP; + else + RAMSES_CPLD_LCD &= ~RAMSES_LCD_PUP; + break; +#endif + + default: + // Just ignore unsupported parameters + break; + } + } + +#ifdef DEBUG + printk("ramses_control_shadow new: %04x\n", ramses_control_shadow); +#endif + return ret; +} + + + +static ctl_table ramses_table[] = { + { + procname: "sys_name", + ctl_name: CTL_NAME, + data: &ramses_board_name, + maxlen: sizeof(ramses_board_name), + proc_handler: &proc_dostring, + mode: 0444, // read-only + }, { + procname: "sys_cpldver", + ctl_name: CTL_CPLD_VERSION, + data: &dummy_str, + maxlen: sizeof(dummy_str), + proc_handler: &ramses_sysctl_handler, + mode: 0444, // read-only + }, { + procname: "sys_bootcrc", + ctl_name: CTL_BOOTLOADER_CRC, + data: &dummy_str, + maxlen: sizeof(dummy_str), + proc_handler: &ramses_sysctl_handler, + mode: 0444, // read-only + }, { + procname: "sys_linuxcrc", + ctl_name: CTL_LINUX_CRC, + data: &dummy_str, + maxlen: sizeof(dummy_str), + proc_handler: &ramses_sysctl_handler, + mode: 0444, // read-only + }, { + procname: "led_blue", + ctl_name: CTL_LED_BLUE, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "led_orange", + ctl_name: CTL_LED_ORANGE, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "pwr_uart", + ctl_name: CTL_UART, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "pwr_mmc", + ctl_name: CTL_MMC, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "pwr_off", + ctl_name: CTL_POWEROFF, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "gsm_power", + ctl_name: CTL_GSM_POWER, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "gsm_reset", + ctl_name: CTL_GSM_RESET, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "scanner_power", + ctl_name: CTL_SCANNER_POWER, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "scanner_wake", + ctl_name: CTL_SCANNER_WAKE, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "scanner_trig", + ctl_name: CTL_SCANNER_TRIG, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "scanner_beam", + ctl_name: CTL_SCANNER_BEAM, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "key_scan", + ctl_name: CTL_KEY_SCAN, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "key_suspend", + ctl_name: CTL_KEY_SUSPEND, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "key_off", + ctl_name: CTL_KEY_OFF, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "usb_bus_power", + ctl_name: CTL_USBBUS_POWER, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "usb_chip_power", + ctl_name: CTL_USBCHIP_POWER, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, +#if LED_CPLD + { + procname: "led_cpld", + ctl_name: CTL_LED_CPLD, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "led_cpld_red", + ctl_name: CTL_LED_CPLD_RED, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, +#endif + { + procname: "lcd_backlight", + ctl_name: CTL_LCD_BLIGHT, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "lcd_vcc", + ctl_name: CTL_LCD_VCC, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "lcd_dispoff", + ctl_name: CTL_LCD_DISPOFF, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "lcd_brightness", + ctl_name: CTL_LCD_BRIGHTNESS, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "lcd_contrast", + ctl_name: CTL_LCD_CONTRAST, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "lcd_fbturn", + ctl_name: CTL_LCD_FBTURN, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "lcd_type", + ctl_name: CTL_LCD_TYPE, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0444, + }, +#ifdef POTI + { + procname: "lcd_poti_ncs", + ctl_name: CTL_LCD_POTI_NCS, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "lcd_poti_ninc", + ctl_name: CTL_LCD_POTI_NINC, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "lcd_poti_up", + ctl_name: CTL_LCD_POTI_UP, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, +#endif +#ifdef DEBUG + { + procname: "lcd_pwm0", + ctl_name: CTL_LCD_PWM0, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, { + procname: "lcd_pwm1", + ctl_name: CTL_LCD_PWM1, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, +#endif + { + procname: "sys_shadowreg", + ctl_name: CTL_CONTROL_SHADOW, + data: &dummy_str, + maxlen: sizeof(dummy_str), + proc_handler: &ramses_sysctl_handler, + mode: 0444, + }, + { + procname: "pwr_corevolt", + ctl_name: CTL_COREVOLT, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0664, + }, +#ifdef CONFIG_MCP_UCB1400_TS + { + procname: "adc0_vcc", + ctl_name: CTL_ADC0, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0444, + }, { + procname: "adc1_ntc", + ctl_name: CTL_ADC1, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0444, + }, { + procname: "adc2_goldcap", + ctl_name: CTL_ADC2, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0444, + }, { + procname: "adc3_batt", + ctl_name: CTL_ADC3, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0444, + }, +#else +#error No UCB +#endif + { + procname: "pwr_wall_in", + ctl_name: CTL_WALL_IN, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0444, + }, { + procname: "batt_charge", + ctl_name: CTL_CHG_STS, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0444, + }, { + procname: "batt_temp", + ctl_name: CTL_BATT_TMP, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0444, + }, { + procname: "batt_lmd", + ctl_name: CTL_BATT_LMD, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0444, + }, { + procname: "batt_vsb", + ctl_name: CTL_BATT_VSB, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0444, + }, { + procname: "batt_rcac", + ctl_name: CTL_BATT_RCAC, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0444, + }, { + procname: "batt_cact", + ctl_name: CTL_BATT_CACT, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0444, + }, { + procname: "batt_sae", + ctl_name: CTL_BATT_SAE, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0444, + }, { + procname: "batt_dcr", + ctl_name: CTL_BATT_DCR, + data: &dummy_int, + maxlen: sizeof(int), + proc_handler: &ramses_sysctl_handler, + mode: 0444, + }, + + {0} + }; + +static ctl_table ramses_root_table[] = { + {RAMSES_SYSCTL, "board", NULL, 0, 0555, ramses_table}, + {0} + }; + + +static struct ctl_table_header *ramses_table_header; + + +static int __init ramses_sysctl_init(void) +{ + ramses_table_header = register_sysctl_table(ramses_root_table, 0); + if (!ramses_table_header) + return -ENOMEM; + return 0; +} + +static void __exit ramses_sysctl_exit(void) +{ + unregister_sysctl_table(ramses_table_header); +} + + +module_init(ramses_sysctl_init); +module_exit(ramses_sysctl_exit); + +MODULE_AUTHOR("Holger Schurig "); +MODULE_DESCRIPTION("Implements /proc/sys/board"); +MODULE_LICENSE("GPL"); --- linux-2.4.21/drivers/char/vt.c~linux-vtcomparison +++ linux-2.4.21/drivers/char/vt.c @@ -163,7 +163,9 @@ if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) return -EFAULT; - if (i >= NR_KEYS || s >= MAX_NR_KEYMAPS) + if (i >= NR_KEYS) + return -EINVAL; + if (s >= MAX_NR_KEYMAPS) return -EINVAL; switch (cmd) { --- linux-2.4.21/drivers/input/Config.in~keyb-input +++ linux-2.4.21/drivers/input/Config.in @@ -7,6 +7,8 @@ tristate 'Input core support' CONFIG_INPUT dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT +dep_tristate ' Ramses keyboard' CONFIG_INPUT_RAMSES_KEYB $CONFIG_INPUT_KEYBDEV $CONFIG_ARCH_RAMSES +dep_tristate ' Ramses wedge' CONFIG_INPUT_RAMSES_WEDGE $CONFIG_INPUT_RAMSES_KEYB dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 --- linux-2.4.21/drivers/input/Makefile~ramses-keyb +++ linux-2.4.21/drivers/input/Makefile @@ -8,7 +8,7 @@ # Objects that export symbols. -export-objs := input.o +export-objs := input.o ramses_keyb.o # Object file lists. @@ -21,10 +21,12 @@ obj-$(CONFIG_INPUT) += input.o obj-$(CONFIG_INPUT_KEYBDEV) += keybdev.o +obj-$(CONFIG_INPUT_RAMSES_KEYB) += ramses_keyb.o 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_RAMSES_WEDGE) += wedge.o # The global Rules.make. --- /dev/null +++ linux-2.4.21/drivers/input/ramses_cellmap.h @@ -0,0 +1,34 @@ +static int ramses_cellmap[][8] = { + { KEY_A, KEY_B, KEY_C, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 0 + { KEY_D, KEY_E, KEY_F, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 1 + { KEY_G, KEY_H, KEY_I, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 2 + { KEY_J, KEY_K, KEY_L, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 3 + { KEY_M, KEY_N, KEY_O, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 4 + { KEY_P, KEY_Q, KEY_R, KEY_S, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 5 + { KEY_T, KEY_U, KEY_V, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 6 + { KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 7 + { KEY_AE, KEY_OE, KEY_UE, KEY_SZ, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 8 + { KEY_sA, KEY_sB, KEY_sC, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 9 + { KEY_sD, KEY_sE, KEY_sF, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 10 + { KEY_sG, KEY_sH, KEY_sI, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 11 + { KEY_sJ, KEY_sK, KEY_sL, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 12 + { KEY_sM, KEY_sN, KEY_sO, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 13 + { KEY_sP, KEY_sQ, KEY_sR, KEY_sS, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 14 + { KEY_sT, KEY_sU, KEY_sV, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 15 + { KEY_sW, KEY_sX, KEY_sY, KEY_sZ, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 16 + { KEY_sAE, KEY_sOE, KEY_sUE, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 17 + { KEY_COLON, KEY_FSLASH,KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 18 + { KEY_SEMI, KEY_BSLASH,KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 19 + { KEY_COMMA, KEY_STAR, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 20 + { KEY_UNDERL,KEY_EQUAL, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 21 + { KEY_PLUS, KEY_MINUS, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 22 + { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 24 + { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 24 + { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 25 + { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 26 + { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 27 + { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 28 + { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 29 + { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 30 + { KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, // 31 +}; --- /dev/null +++ linux-2.4.21/drivers/input/ramses_keyb.c @@ -0,0 +1,596 @@ +/* + * Keyboard driver using input layer + * + * (C) 2002,2003 by M&N Logistik-Lösungen Online GmbH + * written by H.Schurig + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +// Debug +//#define DEBUG +//#define DEBUG_DUMP_KEYSTATE +#ifdef DEBUG +# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +# define PRINTK(fmt, args...) printk(fmt, ## args) +#else +# define DPRINTK(fmt, args...) +# define PRINTK(fmt, args...) +#endif + + +/* + * Timeouts + */ +#define SCANINTERVAL HZ/10 +#define TRIGOFFINTERVAL HZ*2 +#define CELLINTERVAL HZ+HZ/2 +#define MAPINTERVAL 15*HZ +#define SUSPEND_COUNTER 40 +#define SUSPEND_LED_COUNTER 8 +#define SUSPEND_NOW 0xffff +#define KEYBD_MATRIX_SETTLING_TIME_US 100 + + +/* + * macros for matrix keyboard driver + */ +#define KEYBD_MATRIX_NUMBER_INPUTS 7 +#define KEYBD_MATRIX_NUMBER_OUTPUTS 14 + +#define KEYBD_MATRIX_SET_OUTPUTS(outputs) \ +{\ + RAMSES_CPLD_KB_COL_LOW = outputs;\ + RAMSES_CPLD_KB_COL_HIGH = outputs >> 7;\ +} + +#define KEYBD_MATRIX_GET_INPUTS(inputs) \ +{\ + inputs = (RAMSES_CPLD_KB_ROW & 0x7f);\ +} + + +// External functions (are they in some #include file?) +extern int input_setkeycode(unsigned int scancode, unsigned int keycode); +extern int input_getkeycode(unsigned int scancode); +extern int input_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char input_unexpected_up(unsigned char keycode); +extern unsigned char input_sysrq_xlate[]; +extern int pm_suggest_suspend(void); + +// Keyboard-Related definitions +#define KEYBD_MATRIX_INPUT_MASK ((1 << KEYBD_MATRIX_NUMBER_INPUTS)-1) +#define KEYBD_MATRIX_OUTPUT_MASK ((1 << KEYBD_MATRIX_NUMBER_OUTPUTS)-1) + +#include "ramses_scancodes.h" +#include "ramses_keymap.h" +#include "ramses_cellmap.h" + + +static char *kbd_name = "Keyboard"; +struct input_dev ramses_kbd_dev; +static struct timer_list reenable_timer; +static struct timer_list trigoff_timer; +static struct tq_struct tq_suspend; +static __u16 keystate_cur[KEYBD_MATRIX_NUMBER_OUTPUTS]; +static __u16 keystate_prev[KEYBD_MATRIX_NUMBER_OUTPUTS]; +static __u16 keystate_keep[KEYBD_MATRIX_NUMBER_OUTPUTS]; // used for auto-repeat +static struct timer_list cell_timer; +static int curr_map = MAP_NORMAL; +static int cell_key = -1; +static int cell_sel = -1; +static struct pm_dev *pm_keyb; +static int suspend_counter = 0; + + +void ramses_key(int keycode) +{ + DPRINTK("keycode: %d 0x%x\n", keycode, keycode); + if (KVAL(keycode)) { + switch (KMOD(keycode)) { + case KM_SHIFT: + DPRINTK("shift\n"); + input_report_key(&ramses_kbd_dev, KEY_LEFTSHIFT, 1); + break; + case KM_CTRL: + DPRINTK("ctrl\n"); + input_report_key(&ramses_kbd_dev, KEY_LEFTCTRL, 1); + break; + case KM_ALT: + DPRINTK("alt\n"); + input_report_key(&ramses_kbd_dev, KEY_LEFTALT, 1); + break; + case KM_ALTGR: + DPRINTK("altgr\n"); + input_report_key(&ramses_kbd_dev, KEY_RIGHTALT, 1); + break; + case KM_ALTCTRL: + DPRINTK("alt+ctrl\n"); + input_report_key(&ramses_kbd_dev, KEY_LEFTALT, 1); + input_report_key(&ramses_kbd_dev, KEY_LEFTCTRL, 1); + break; + } + + DPRINTK("report: %d 0x%x\n", KVAL(keycode), KVAL(keycode)); + input_report_key(&ramses_kbd_dev, KVAL(keycode), 1); + input_report_key(&ramses_kbd_dev, KVAL(keycode), 0); + + switch (KMOD(keycode)) { + case KM_SHIFT: + input_report_key(&ramses_kbd_dev, KEY_LEFTSHIFT, 0); + break; + case KM_CTRL: + input_report_key(&ramses_kbd_dev, KEY_LEFTCTRL, 0); + break; + case KM_ALT: + input_report_key(&ramses_kbd_dev, KEY_LEFTALT, 0); + break; + case KM_ALTGR: + input_report_key(&ramses_kbd_dev, KEY_RIGHTALT, 0); + break; + case KM_ALTCTRL: + input_report_key(&ramses_kbd_dev, KEY_LEFTALT, 0); + input_report_key(&ramses_kbd_dev, KEY_LEFTCTRL, 0); + break; + } + } +} + +static void kbd_cell_timer(unsigned long keepmap) +{ + int keycode; + + if (cell_sel != -1) { + keycode = ramses_cellmap[cell_key][cell_sel]; + //DPRINTK("key: %d sel: %d keycode: %d 0x%x\n", cell_key, cell_sel, keycode, keycode); + ramses_key(keycode); + cell_sel = -1; + } + + if (!keepmap && curr_map!=MAP_NORMAL) { + DPRINTK("normal map because of %ld\n", keepmap); + curr_map = MAP_NORMAL; + RAMSES_LED_BLUE_OFF(); + RAMSES_LED_ORANGE_OFF(); + } +} + +static void kbd_setleds(void) +{ + if (suspend_counter >= SUSPEND_LED_COUNTER) { + if (suspend_counter & 4) { + RAMSES_LED_ORANGE_OFF(); + RAMSES_LED_BLUE_ON(); + } else { + RAMSES_LED_ORANGE_ON(); + RAMSES_LED_BLUE_OFF(); + } + return; + } + + switch (curr_map) { + case MAP_NORMAL: + RAMSES_LED_BLUE_OFF(); + RAMSES_LED_ORANGE_OFF(); + return; + + case MAP_BLUE: + RAMSES_LED_BLUE_ON(); + RAMSES_LED_ORANGE_OFF(); + return; + + case MAP_ORANGE: + RAMSES_LED_BLUE_OFF(); + RAMSES_LED_ORANGE_ON(); + return; + + case MAP_CAPS: + RAMSES_LED_BLUE_ON(); + RAMSES_LED_ORANGE_ON(); + return; + } + DPRINTK("unknown map\n"); +} + + +static void kbd_start_scanner(void) +{ + RAMSES_SCANNER_TRIG_OFF(); + RAMSES_SCANNER_WAKE_OFF(); + RAMSES_SCANNER_TRIG_ON(); + mod_timer(&trigoff_timer, jiffies + TRIGOFFINTERVAL); +} + +static void kbd_stop_scanner(unsigned long dummy) +{ + RAMSES_SCANNER_TRIG_OFF(); +} + +static int kbd_dokeycode(unsigned char scancode, int down) +{ + int i,keycode; + + //DPRINTK("calling with (%d,%x,%d)\n", scancode, scancode, down); + if (scancode >= MAX_SCANCODES) { + printk("%s: scancode too big for table\n", __FUNCTION__); + return 0; + } + + keycode = ramses_keymap[scancode][curr_map]; + + + if (keycode==KEY_SCAN) { + if ((ramses_flags & RAMSES_FLAGS_KEY_SCAN) == 0) + return 0; + + DPRINTK("scan btn\n"); + if (down) { + if (ramses_flags & RAMSES_FLAGS_SCANNER_BEAM) { + // just turn on laser beam + RAMSES_SCANNER_WAKE_ON(); + } else { + kbd_start_scanner(); + } + } else { + if (ramses_flags & RAMSES_FLAGS_SCANNER_BEAM) { + kbd_start_scanner(); + } else { + kbd_stop_scanner(0); + } + } + return 0; + } + + + if (keycode==KEY_SUSP) { + if ((ramses_flags & RAMSES_FLAGS_KEY_SUSPEND) == 0) + return 0; + + if (down) { + suspend_counter++; + if (suspend_counter >= SUSPEND_COUNTER) { + suspend_counter = SUSPEND_NOW; + } + } else { + if (suspend_counter == SUSPEND_NOW) { + curr_map = MAP_NORMAL; + schedule_task(&tq_suspend); + } + suspend_counter = 0; + } + return down; + } + + + if (keycode==KEY_OFF) { + if (down || ((ramses_flags & RAMSES_FLAGS_KEY_OFF) == 0)) + return 0; + curr_map = MAP_NORMAL; + ramses_shut_off(); + return 0; + } + + + if (!down) + return 0; + + + DPRINTK("curr_map %d scancode %d keycode %d 0x%x typ %d\n", curr_map, scancode, keycode, keycode, KMOD(keycode)); + + + // Cell-Phone keyboard handling + if (KMOD(keycode)==KM_CELL) { + //DPRINTK("cell phone key %d\n", KVAL(keycode)); + + // did we press a different cell-phone key as last time? + if (KVAL(keycode)!=cell_key) + kbd_cell_timer(1); + + cell_key = KVAL(keycode); // store current cell-phone key + cell_sel++; // increase current sub-key + if (ramses_cellmap[cell_key][cell_sel]==0) // if at end of sub-key list, back off + cell_sel = 0; + //DPRINTK("cell_key: %d cell_sel: %d\n", cell_key, cell_sel); + // auto-emit via kbd_cell_timer + mod_timer(&cell_timer, jiffies + CELLINTERVAL); + return 0; // do not revert to keys_normal + } + + + // if we pressed any other key then a cell-phone key, we look if the + // current half-pressed cell-phone key should be emitted + kbd_cell_timer(1); + + + switch(keycode) { + + // Keymap handling + + case KEY_NORM: + DPRINTK("norm key map\n"); + curr_map = MAP_NORMAL; + return 0; + + case KEY_BLUE: + //DPRINTK("blue key map\n"); + curr_map = MAP_BLUE; + mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap + return 0; + + case KEY_ORNG: + //DPRINTK("orange key map\n"); + curr_map = MAP_ORANGE; + mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap + return 0; + + case KEY_CAPS: + DPRINTK("caps key map\n"); + curr_map = MAP_CAPS; + mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap + return 0; + + case KEY_BRIP: + i = ramses_lcd_get_brightness()-6; + ramses_lcd_set_brightness(i); + mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap + return 0; + + case KEY_BRIM: + i = ramses_lcd_get_brightness()+6; + ramses_lcd_set_brightness(i); + mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap + return 0; + + case KEY_CTRM: + i = ramses_lcd_get_contrast()+3; + ramses_lcd_set_contrast(i); + mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap + return 0; + + case KEY_CTRP: + i = ramses_lcd_get_contrast()-3; + ramses_lcd_set_contrast(i); + mod_timer(&cell_timer, jiffies + MAPINTERVAL); // automatically disable keymap + return 0; + } + + // normal keys + + ramses_key(keycode); + + if (curr_map!=MAP_NORMAL) + DPRINTK("back to normal map\n"); + curr_map = MAP_NORMAL; + RAMSES_LED_BLUE_OFF(); + RAMSES_LED_ORANGE_OFF(); + return 0; +} + + +/** + * @param rescan 0 if we look for pressed keys, 1 if we look for released keys + * + * This routine get's called from the ISR (then rescan is always 0) or from + * the reenable_timer function (then rescan is 1). + */ +static void kbd_scan_keyboard(unsigned long rescan) +{ + int i,n; + int cols; + unsigned char code; + __u16 keystate_xor[KEYBD_MATRIX_NUMBER_OUTPUTS]; + + + // Find out if a key (or more) was pressed down. It's possible that + // because of spikes we got an interrupt, but when the IRQ service + // routine fired there is currently no detectable key. If this is + // true, then delay some times and re-try, but not too often. + + cols = 0; + for(n=0; n<10; n++) { + for (i = 0; i < KEYBD_MATRIX_NUMBER_OUTPUTS; i++) { + KEYBD_MATRIX_SET_OUTPUTS( 1 << i ); + udelay(KEYBD_MATRIX_SETTLING_TIME_US); + KEYBD_MATRIX_GET_INPUTS(keystate_cur[i]); + if (keystate_cur[i]) + cols++; + } + if (cols || rescan) + break; + udelay(KEYBD_MATRIX_SETTLING_TIME_US*50); + } + + // if rescan is true, we are in the process of turning on the IRQ. + // Ignore any spurious IRQ. However, if we got an IRQ but could not + // detect any key, we note this on the console, clear the keystate + // completely and make sure the IRQ gets re-enabled via the timer + // shortly. + + if (!cols && !rescan) { + printk("%s: spurious kbd int\n", __FUNCTION__); + for (i = 0; i < KEYBD_MATRIX_NUMBER_OUTPUTS; i++) { + keystate_cur[i] = 0; + keystate_prev[i] = 0; + } + mod_timer(&reenable_timer, jiffies + SCANINTERVAL); + return; + } + + pm_access(pm_keyb); + + // Okay, all went well. We now keystate_cur[] may contain the rows + // where we had keypresses, e.g. + // 0 0 0 2 0 0 0 0 0 0 0 0 0 0 + // We would see this if DEBUG_DUMP_KEYSTATE is on: + +#ifdef DEBUG_DUMP_KEYSTATE + cols = 0; + for (i = 0; i < KEYBD_MATRIX_NUMBER_OUTPUTS; i++) { + printk("%d-%d ",keystate_cur[i], keystate_keep[i]); + } + printk("\n"); +#endif + + cols = 0; + for (i = 0; i < KEYBD_MATRIX_NUMBER_OUTPUTS; i++) { + + // detect which key has changes doing an XOR of old state with new state + keystate_xor[i] = keystate_prev[i] ^ keystate_cur[i]; + //printk("%d: prev %d cur %d xor %d keep %d\n", i, keystate_prev[i], keystate_cur[i], keystate_xor[i], keystate_keep[i]); + + // some key changed, find out which one and do the scancode handling + if (keystate_xor[i] || keystate_keep[i]) { + for (n = 0; n < KEYBD_MATRIX_NUMBER_INPUTS; n++) + { + if ( (keystate_keep[i] & keystate_cur[i]) || + (keystate_xor[i] & (1 << n)) ) + { + int res; + code = n * KEYBD_MATRIX_NUMBER_OUTPUTS + i + 1; + res = kbd_dokeycode(code, keystate_cur[i] & (1 << n) ? 1 : 0); + kbd_setleds(); + if (res) { + keystate_keep[i] = 1 << n; + goto out; + } + } + } + } +out: + keystate_prev[i] = keystate_cur[i]; + } + + + // fire reenable time if we are in the ISR + if (!rescan) + mod_timer(&reenable_timer, jiffies + SCANINTERVAL); +} + + + +static void kbd_reenable_timer(unsigned long dummy) +{ + // re-scan the keyboard (to detect released keys) + kbd_scan_keyboard(1); + + // re-enable interrupts from the CPLD + KEYBD_MATRIX_SET_OUTPUTS( KEYBD_MATRIX_OUTPUT_MASK ); +} + + + + + +/** + * Referenced by request_irq() + */ +static void kbd_interrupt(int irq, void *dummy, struct pt_regs *fp) +{ + kbd_scan_keyboard(0); +} + +static void ramseskbd_suspend(void *data) +{ + pm_suggest_suspend(); +} + + +static int __init ramseskbd_init(void) +{ + int irq_gpio_pin; + + // Activate the normal pc-keycodes for the input-layer-keyboard + k_setkeycode = input_setkeycode; + k_getkeycode = input_getkeycode; + k_translate = input_translate; + k_unexpected_up = input_unexpected_up; +#ifdef CONFIG_MAGIC_SYSRQ + k_sysrq_key = 0x54; + k_sysrq_xlate = input_sysrq_xlate; +#endif + + // In linux-2.5.x we can do + // init_input_dev(&ramses_kbd_dev); + // but here we don't have this on linux-2.4, so we fill it with zeros: + memset(&ramses_kbd_dev, 0, sizeof(ramses_kbd_dev)); + ramses_kbd_dev.name = kbd_name; + + // which events we can produce (only keypresses): + ramses_kbd_dev.evbit[0] = BIT(EV_KEY); + + // which keypresses we can produce (all): + memset(&ramses_kbd_dev.keybit, 0xff, sizeof(ramses_kbd_dev.keybit)); + + // We set the 14 output columns to 0. This stops the CPLD to + // generate an IRQ before we finished our setup + KEYBD_MATRIX_SET_OUTPUTS(0); + + // Turn all LEDs off, meaning that we have the normal keymap active + RAMSES_LED_BLUE_OFF(); + RAMSES_LED_ORANGE_OFF(); + // TODO: used leds.c? + + // Now we make sure that the GPIO for our IRQ is programmed correctly + irq_gpio_pin = IRQ_TO_GPIO_2_80(RAMSES_KEYBOARD_IRQ); + GPDR(irq_gpio_pin) &= ~GPIO_bit(irq_gpio_pin); + set_GPIO_IRQ_edge(irq_gpio_pin, RAMSES_KEYBOARD_IRQ_EDGE); + request_irq(RAMSES_KEYBOARD_IRQ, kbd_interrupt, 0, kbd_name, NULL); + + // Initialize timer to re-enable IRQs. That's our method of keyboard de-prelling + init_timer(&reenable_timer); + reenable_timer.function = kbd_reenable_timer; + + init_timer(&trigoff_timer); + trigoff_timer.function = kbd_stop_scanner; + + // Initialize to escape the blue mode, so we emit the current cell-phone key + init_timer(&cell_timer); + cell_timer.function = kbd_cell_timer; + + tq_suspend.routine = ramseskbd_suspend; + + // Register with Power-Management +#ifdef PM_DEBUG + pm_keyb = pm_register(PM_SYS_DEV, PM_SYS_KBC+1, NULL, "ramses_keyb"); +#else + pm_keyb = pm_register(PM_SYS_DEV, PM_SYS_KBC+1, NULL); +#endif + + // Register our keyboard + input_register_device(&ramses_kbd_dev); + + // We set the 14 output columns to 1. This allows the CPLD to + // generate an IRQ when one of the rows goes high + KEYBD_MATRIX_SET_OUTPUTS(KEYBD_MATRIX_OUTPUT_MASK); + + return 0; +} + + +static void __exit ramseskbd_exit(void) +{ + // make IRQs impossible, return the IRQ and unregister us + KEYBD_MATRIX_SET_OUTPUTS(0); + free_irq(RAMSES_KEYBOARD_IRQ, NULL); + pm_unregister(pm_keyb); + input_unregister_device(&ramses_kbd_dev); +} + + +module_init(ramseskbd_init); +module_exit(ramseskbd_exit); + +MODULE_AUTHOR("Holger Schurig "); +MODULE_DESCRIPTION("Ramses keyboard driver"); +MODULE_LICENSE("GPL"); +EXPORT_SYMBOL(ramses_key); +EXPORT_SYMBOL(ramses_kbd_dev); --- /dev/null +++ linux-2.4.21/drivers/input/ramses_keymap.h @@ -0,0 +1,68 @@ +// Normal Map +static int ramses_keymap[][6] = { +/* Normal Blue Orange Caps Spare Spare */ +/* 0 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 1 */ {KEY_SUSP, KEY_SUSP, KEY_SUSP, KEY_OFF, KEY_SUSP, KEY_SUSP }, +/* 2 */ {KEY_UP, KEY_UP, KEY_PGUP, KEY_UP, KEY_noop, KEY_noop }, +/* 3 */ {KEY_1, KEY_SPACE, KEY_BRIM, KEY_SPACE, KEY_noop, KEY_noop }, +/* 4 */ {KEY_4, KEY_ghi , KEY_CTRM, KEY_GHI , KEY_noop, KEY_noop }, +/* 5 */ {KEY_7, KEY_pqrs, KEY_cel7, KEY_PQRS, KEY_noop, KEY_noop }, +/* 6 */ {KEY_DOT, KEY_uml, KEY_celP, KEY_UML, KEY_noop, KEY_noop }, +/* 7 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 8 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 9 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 10 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 11 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 12 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 13 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 14 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 15 */ {KEY_ENTER, KEY_ENTER, KEY_ENTER, KEY_ENTER, KEY_ENTER, KEY_ENTER}, +/* 16 */ {KEY_DOWN, KEY_DOWN, KEY_PGDN, KEY_DOWN, KEY_noop, KEY_noop }, +/* 17 */ {KEY_2, KEY_abc , KEY_BRIP, KEY_ABC , KEY_noop, KEY_noop }, +/* 18 */ {KEY_5, KEY_jkl , KEY_CTRP, KEY_JKL, KEY_noop, KEY_noop }, +/* 19 */ {KEY_8, KEY_tuv , KEY_cel8, KEY_TUV, KEY_noop, KEY_noop }, + +/* Normal Blue Orange Caps Spare Spare */ +/* 20 */ {KEY_0, KEY_TAB, KEY_cel0, KEY_BTAB, KEY_noop, KEY_noop }, +/* 21 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 22 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 23 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 24 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 25 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 26 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 27 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 28 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 29 */ {KEY_ESC, KEY_ESC, KEY_ESC, KEY_ESC, KEY_ESC, KEY_ESC }, +/* 30 */ {KEY_RIGHT, KEY_RIGHT, KEY_END, KEY_C2, KEY_noop, KEY_noop }, +/* 31 */ {KEY_3, KEY_def, KEY_FXIT, KEY_DEF, KEY_noop, KEY_noop }, +/* 32 */ {KEY_6, KEY_mno , KEY_FRST, KEY_MNO, KEY_noop, KEY_noop }, +/* 33 */ {KEY_9, KEY_wxyz, KEY_cel9, KEY_WXYZ, KEY_noop, KEY_noop }, +/* 34 */ {KEY_BACKSPACE,KEY_ATSIGN,KEY_BAR, KEY_noop, KEY_noop, KEY_noop }, +/* 35 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 36 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 37 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 38 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 39 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, + +/* Normal Blue Orange Caps Spare Spare */ +/* 40 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 41 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 42 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 43 */ {KEY_SCAN, KEY_SCAN, KEY_SCAN, KEY_SCAN, KEY_SCAN, KEY_SCAN }, +/* 44 */ {KEY_LEFT, KEY_LEFT, KEY_HOME, KEY_C1, KEY_noop, KEY_noop }, +/* 45 */ {KEY_OFF, KEY_OFF, KEY_OFF, KEY_OFF, KEY_OFF, KEY_OFF }, +/* 46 */ {KEY_F1, KEY_F4, KEY_F7, KEY_F10, KEY_noop, KEY_noop }, +/* 47 */ {KEY_F2, KEY_F5, KEY_F8, KEY_F11, KEY_noop, KEY_noop }, +/* 48 */ {KEY_F3, KEY_F6, KEY_F9, KEY_F12, KEY_noop, KEY_noop }, +/* 49 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 50 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 51 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 52 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 53 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 54 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 55 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 56 */ {KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop, KEY_noop }, +/* 57 */ {KEY_SCAN, KEY_SCAN, KEY_SCAN, KEY_SCAN, KEY_SCAN, KEY_SCAN }, +/* 58 */ {KEY_BLUE, KEY_NORM, KEY_CAPS, KEY_NORM, KEY_NORM, KEY_NORM }, +/* 59 */ {KEY_ORNG, KEY_CAPS, KEY_NORM, KEY_NORM, KEY_NORM, KEY_NORM }, +}; --- /dev/null +++ linux-2.4.21/drivers/input/ramses_scancodes.h @@ -0,0 +1,134 @@ +#ifndef _RAMSES_SCANCODES_H +#define _RAMSES_SCANCODES_H + +#define KMOD(a) (a & 0xff00) +#undef KVAL +#define KVAL(a) (a & 0x00ff) + +// which modifiers to send before/after +#define KM_SPECIAL 0x300 +#define KM_CELL 0x400 +#define KM_SHIFT 0x500 +#define KM_ALT 0x600 +#define KM_CTRL 0x700 +#define KM_ALTGR 0x800 +#define KM_ALTCTRL 0x900 + +// or special keys +#define KEY_noop KM_SPECIAL + 0 +#define KEY_OFF KM_SPECIAL + 1 +#define KEY_SUSP KM_SPECIAL + 2 +#define KEY_SCAN KM_SPECIAL + 3 +#define KEY_CTRM KM_SPECIAL + 4 +#define KEY_CTRP KM_SPECIAL + 5 +#define KEY_BRIM KM_SPECIAL + 6 +#define KEY_BRIP KM_SPECIAL + 7 + +#define KEY_NORM KM_SPECIAL + 10 +#define KEY_BLUE KM_SPECIAL + 11 +#define KEY_ORNG KM_SPECIAL + 12 +#define KEY_CAPS KM_SPECIAL + 13 + + +// our cell-phone like keys +#define KEY_abc KM_CELL + 0 +#define KEY_def KM_CELL + 1 +#define KEY_ghi KM_CELL + 2 +#define KEY_jkl KM_CELL + 3 +#define KEY_mno KM_CELL + 4 +#define KEY_pqrs KM_CELL + 5 +#define KEY_tuv KM_CELL + 6 +#define KEY_wxyz KM_CELL + 7 +#define KEY_uml KM_CELL + 8 +#define KEY_ABC KM_CELL + 9 +#define KEY_DEF KM_CELL + 10 +#define KEY_GHI KM_CELL + 11 +#define KEY_JKL KM_CELL + 12 +#define KEY_MNO KM_CELL + 13 +#define KEY_PQRS KM_CELL + 14 +#define KEY_TUV KM_CELL + 15 +#define KEY_WXYZ KM_CELL + 16 +#define KEY_UML KM_CELL + 17 +#define KEY_cel7 KM_CELL + 18 +#define KEY_cel8 KM_CELL + 19 +#define KEY_cel9 KM_CELL + 20 +#define KEY_celP KM_CELL + 21 +#define KEY_cel0 KM_CELL + 22 + +// Shift-Keys +#define KEY_sA KM_SHIFT + KEY_A +#define KEY_sB KM_SHIFT + KEY_B +#define KEY_sC KM_SHIFT + KEY_C +#define KEY_sD KM_SHIFT + KEY_D +#define KEY_sE KM_SHIFT + KEY_E +#define KEY_sF KM_SHIFT + KEY_F +#define KEY_sG KM_SHIFT + KEY_G +#define KEY_sH KM_SHIFT + KEY_H +#define KEY_sI KM_SHIFT + KEY_I +#define KEY_sJ KM_SHIFT + KEY_J +#define KEY_sK KM_SHIFT + KEY_K +#define KEY_sL KM_SHIFT + KEY_L +#define KEY_sM KM_SHIFT + KEY_M +#define KEY_sN KM_SHIFT + KEY_N +#define KEY_sO KM_SHIFT + KEY_O +#define KEY_sP KM_SHIFT + KEY_P +#define KEY_sQ KM_SHIFT + KEY_Q +#define KEY_sR KM_SHIFT + KEY_R +#define KEY_sS KM_SHIFT + KEY_S +#define KEY_sT KM_SHIFT + KEY_T +#define KEY_sU KM_SHIFT + KEY_U +#define KEY_sV KM_SHIFT + KEY_V +#define KEY_sW KM_SHIFT + KEY_W +#define KEY_sX KM_SHIFT + KEY_X +#define KEY_sY KM_SHIFT + KEY_Y +#define KEY_sZ KM_SHIFT + KEY_Z + +// Umlaute +#define KEY_sAE KM_SHIFT + 40 +#define KEY_sOE KM_SHIFT + 39 +#define KEY_sUE KM_SHIFT + 26 +#define KEY_AE 40 +#define KEY_OE 39 +#define KEY_UE 26 +#define KEY_SZ 12 + +// AS400-Keys +#define KEY_FRST KM_ALT + KEY_R +#define KEY_FXIT KM_ALT + KEY_X + +// Console-Switch +#define KEY_C1 KM_ALTCTRL + KEY_F1 +#define KEY_C2 KM_ALTCTRL + KEY_F2 + +// additional keys from the german keyboard +#undef KEY_MINUS +#undef KEY_EQUAL +#undef KEY_Y +#undef KEY_Z +#define KEY_Y 44 +#define KEY_Z 21 +#define KEY_STAR 55 +#define KEY_COLON KM_SHIFT + 52 +#define KEY_UNDERL KM_SHIFT + 53 +#define KEY_ATSIGN KM_ALTGR + 16 +#define KEY_BAR KM_ALTGR + 86 +#define KEY_EQUAL KM_SHIFT + 11 +#define KEY_SEMI KM_SHIFT + 51 +#define KEY_BSLASH KM_ALTGR + 12 +#define KEY_FSLASH KM_SHIFT + KEY_7 +#define KEY_MINUS 53 +#define KEY_PLUS 27 +#define KEY_GAENSE KM_SHIFT + 3 +#define KEY_PARA KM_SHIFT + 4 +#define KEY_HASH 43 +#define KEY_PGUP KEY_PAGEUP +#define KEY_PGDN KEY_PAGEDOWN +#define KEY_BTAB KM_SHIFT + KEY_TAB + +#define MAP_NORMAL 0 +#define MAP_BLUE 1 +#define MAP_ORANGE 2 +#define MAP_CAPS 3 +#define MAX_SCANCODES 100 + +#endif --- /dev/null +++ linux-2.4.21/drivers/input/wedge.c @@ -0,0 +1,241 @@ +/* + * Virtual keyboard wedge using input layer + * + * (C) 2002,2003 by M&N Logistik-Lösungen Online GmbH + * written by H.Schurig + * + * Creates a misc char device /dev/misc/wedge. Any output to this + * device will be translated (via a german keyboard map) into scancodes + * and re-submitted into the keyboard channel. Any console, X-Windows + * or Qt/Embedded application will be able to receive this info. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + + +// Debug +//#define DEBUG 1 +#ifdef DEBUG +# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +# define PRINTK(fmt, args...) printk(fmt, ## args) +#else +# define DPRINTK(fmt, args...) +# define PRINTK(fmt, args...) +#endif + + +// Defines +#define KBD_STUFF_MAX_BYTES 512 + +// Für den IOCTL +#define WEDGE_RAWKEY_DOWN _IOW('w', 0x72, unsigned long) +#define WEDGE_RAWKEY_UP _IOW('w', 0x73, unsigned long) +#define WEDGE_TS_ABS_X _IOW('w', 0x74, unsigned long) +#define WEDGE_TS_ABS_Y _IOW('w', 0x75, unsigned long) +#define WEDGE_TS_ABS_PRESSURE _IOW('w', 0x76, unsigned long) + +// Externs +#define MAX_NR_KEYMAPS 256 +extern void ramses_key(int keycode); +extern unsigned short *key_maps[MAX_NR_KEYMAPS]; +extern struct input_dev ramses_kbd_dev; +extern void ucb1x00_ts_evt_add(void *, u16 pressure, u16 x, u16 y); + +// for special keys +struct wedge_lookup_t { + u_short c; + u_short keysym; +}; + +struct wedge_lookup_t wedge_lookup[] = { + { 0x0a, 0x001c, }, + { 0x2f, 0x0508, }, +}; + + + + +static void *outbuf; + +static int wedge_open(struct inode *inode, struct file *filp) +{ + int ret; + + ret = -ENXIO; + outbuf = kmalloc(KBD_STUFF_MAX_BYTES, GFP_KERNEL); + if (!outbuf) + goto out; + + ret = 0; + +out: + if (ret) { + kfree(outbuf); + } + return ret; +} + + +static int wedge_close(struct inode *inode, struct file *filp) +{ + kfree(outbuf); + return 0; +} + + +static int wedge_search_map(u_short map[], int c) +{ + int i; + + for (i=0; i"); +MODULE_DESCRIPTION("PXA mcp low level support"); +MODULE_LICENSE("GPL"); --- linux-2.4.21/drivers/misc/mcp.h~ucb1x00 +++ linux-2.4.21/drivers/misc/mcp.h @@ -43,6 +43,7 @@ /* noddy implementation alert! */ struct mcp *mcp_get(void); +void mcp_put(void); int mcp_register(struct mcp *); #define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate) --- linux-2.4.21/drivers/misc/ucb1x00-core.c~pm +++ linux-2.4.21/drivers/misc/ucb1x00-core.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -181,8 +182,9 @@ if (val & UCB_ADC_DAT_VAL) break; /* yield to other processes */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); + //HS set_current_state(TASK_INTERRUPTIBLE); + //HS schedule_timeout(1); + udelay(200); } return UCB_ADC_DAT(val); @@ -209,7 +211,8 @@ struct ucb1x00 *ucb = (struct ucb1x00 *)dev->data; unsigned int isr; - if (rqst == PM_RESUME) { + switch (rqst) { + case PM_RESUME: ucb1x00_enable(ucb); isr = ucb1x00_reg_read(ucb, UCB_IE_STATUS); ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr); @@ -521,7 +524,9 @@ */ static int __init ucb1x00_configure(struct ucb1x00 *ucb) { +#ifndef CONFIG_ARCH_RAMSES unsigned int irq_gpio_pin = 0; +#endif int irq, default_irq = NO_IRQ; #ifdef CONFIG_ARCH_SA1100 @@ -611,11 +616,13 @@ /* * Eventually, this will disappear. */ +#ifndef CONFIG_ARCH_RAMSES 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 #endif irq = ucb1x00_detect_irq(ucb); if (irq != NO_IRQ) { --- linux-2.4.21/drivers/misc/ucb1x00-ts.c~ramses-ucb1x00-dejitter +++ linux-2.4.21/drivers/misc/ucb1x00-ts.c @@ -29,6 +29,7 @@ #include #include +#include #include "ucb1x00.h" @@ -97,7 +98,7 @@ }; static struct ucb1x00_ts ucbts; -static int adcsync = UCB_NOSYNC; +static int adcsync = UCB_SYNC; static int ucb1x00_ts_startup(struct ucb1x00_ts *ts); static void ucb1x00_ts_shutdown(struct ucb1x00_ts *ts); @@ -116,8 +117,14 @@ next_head = (ts->evt_head + 1) & (NR_EVENTS - 1); if (next_head != ts->evt_tail) { ts->events[ts->evt_head].pressure = pressure; +#if 0 ts->events[ts->evt_head].x = x; ts->events[ts->evt_head].y = y; +#else + // rotate by -90 + ts->events[ts->evt_head].x = y; + ts->events[ts->evt_head].y = x; +#endif do_gettimeofday(&ts->events[ts->evt_head].stamp); ts->evt_head = next_head; @@ -256,11 +263,11 @@ #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) +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_report_abs(&ucbts.idev, ABS_X, y); + input_report_abs(&ucbts.idev, ABS_Y, x); + input_report_abs(&ucbts.idev, ABS_PRESSURE, pressure); } static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts) @@ -335,7 +342,7 @@ 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); + return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSMY, ts->adcsync); } /* @@ -346,19 +353,15 @@ */ 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); + unsigned int res; 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); + udelay(600); - return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); + res = ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSMY, ts->adcsync); + return res; } /* @@ -369,19 +372,15 @@ */ static inline unsigned int ucb1x00_ts_read_ypos(struct ucb1x00_ts *ts) { + unsigned int res; 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_TSPY_GND | UCB_TS_CR_TSMY_POW | UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); - udelay(55); + udelay(300); - return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync); + res = ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync); + return res; } /* @@ -430,8 +429,9 @@ * 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; +//HS + tsk->policy = SCHED_FIFO; + tsk->rt_priority = 1; /* only want to receive SIGKILL */ spin_lock_irq(&tsk->sigmask_lock); @@ -451,8 +451,8 @@ ucb1x00_adc_enable(ts->ucb); x = ucb1x00_ts_read_xpos(ts); - y = ucb1x00_ts_read_ypos(ts); p = ucb1x00_ts_read_pressure(ts); + y = ucb1x00_ts_read_ypos(ts); /* * Switch back to interrupt mode. @@ -461,7 +461,7 @@ ucb1x00_adc_disable(ts->ucb); set_task_state(tsk, TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 100); + schedule_timeout(HZ / 200); if (signal_pending(tsk)) break; @@ -504,7 +504,7 @@ } set_task_state(tsk, TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 100); + schedule_timeout(HZ / 200); } if (signal_pending(tsk)) @@ -655,8 +655,8 @@ char *p; while ((p = strsep(&str, ",")) != NULL) { - if (strcmp(p, "sync") == 0) - adcsync = UCB_SYNC; + if (strcmp(p, "nosync") == 0) + adcsync = UCB_NOSYNC; } return 1; @@ -674,6 +674,7 @@ module_init(ucb1x00_ts_init); module_exit(ucb1x00_ts_exit); +EXPORT_SYMBOL(ucb1x00_ts_evt_add); MODULE_AUTHOR("Russell King "); MODULE_DESCRIPTION("UCB1x00 touchscreen driver"); MODULE_LICENSE("GPL"); --- linux-2.4.21/drivers/mtd/maps/Config.in~ramses-mtd +++ linux-2.4.21/drivers/mtd/maps/Config.in @@ -76,6 +76,7 @@ if [ "$CONFIG_ARM" = "y" ]; then dep_tristate ' CFI Flash device mapped on Lubbock board' CONFIG_MTD_LUBBOCK $CONFIG_MTD_CFI $CONFIG_ARCH_LUBBOCK $CONFIG_MTD_PARTITIONS + dep_tristate ' CFI Flash device mapped on Ramses board' CONFIG_MTD_RAMSES $CONFIG_MTD_CFI $CONFIG_ARCH_RAMSES $CONFIG_MTD_PARTITIONS dep_tristate ' CFI Flash device mapped on Nora' CONFIG_MTD_NORA $CONFIG_MTD_CFI dep_tristate ' CFI Flash device mapped on ARM Integrator/P720T' CONFIG_MTD_ARM_INTEGRATOR $CONFIG_MTD_CFI dep_tristate ' Cirrus CDB89712 evaluation board mappings' CONFIG_MTD_CDB89712 $CONFIG_MTD_CFI $CONFIG_ARCH_CDB89712 --- linux-2.4.21/drivers/mtd/maps/Makefile~ramses-mtd +++ linux-2.4.21/drivers/mtd/maps/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_MTD_EPXA) += epxa-flash.o obj-$(CONFIG_MTD_IQ80310) += iq80310.o obj-$(CONFIG_MTD_LUBBOCK) += lubbock.o +obj-$(CONFIG_MTD_RAMSES) += ramses.o obj-$(CONFIG_MTD_PXA_CERF) += pxa_cerf.o obj-$(CONFIG_MTD_TRIZEPS2) += trizeps2.o obj-$(CONFIG_MTD_L440GX) += l440gx.o --- /dev/null +++ linux-2.4.21/drivers/mtd/maps/ramses.c @@ -0,0 +1,167 @@ +/* + * Map driver for the Ramses developer platform. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + + +#define WINDOW_ADDR 0 +#define WINDOW_SIZE 32*1024*1024 + +static __u8 ramses_read8(struct map_info *map, unsigned long ofs) +{ + return *(__u8 *)(map->map_priv_1 + ofs); +} + +static __u16 ramses_read16(struct map_info *map, unsigned long ofs) +{ + return *(__u16 *)(map->map_priv_1 + ofs); +} + +static __u32 ramses_read32(struct map_info *map, unsigned long ofs) +{ + return *(__u32 *)(map->map_priv_1 + ofs); +} + +static void ramses_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy(to, (void *)(map->map_priv_1 + from), len); +} + +static void ramses_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + *(__u8 *)(map->map_priv_1 + adr) = d; +} + +static void ramses_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + *(__u16 *)(map->map_priv_1 + adr) = d; +} + +static void ramses_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + *(__u32 *)(map->map_priv_1 + adr) = d; +} + +static void ramses_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy((void *)(map->map_priv_1 + to), from, len); +} + +static struct map_info ramses_map = { + name: "Flash", + size: WINDOW_SIZE, + read8: ramses_read8, + read16: ramses_read16, + read32: ramses_read32, + copy_from: ramses_copy_from, + write8: ramses_write8, + write16: ramses_write16, + write32: ramses_write32, + copy_to: ramses_copy_to +}; + +static struct mtd_partition ramses_partitions[] = { + { + name: "Bootloader", + size: 0x00040000, + offset: 0, + },{ + name: "Kernel", + size: 0x00100000, + offset: 0x00040000, + },{ + name: "Filesystem", + size: MTDPART_SIZ_FULL, + offset: 0x00140000 + } +}; + +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +static struct mtd_info *mymtd; +static struct mtd_partition *parsed_parts; + +extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); + +static int __init init_ramses(void) +{ + struct mtd_partition *parts; + int nb_parts = 0; + int parsed_nr_parts = 0; + char *part_type = "static"; + + ramses_map.buswidth = (BOOT_DEF & 1) ? 2 : 4; + printk( "Probing flash at physical address 0x%08x (%d-bit buswidth)\n", + WINDOW_ADDR, ramses_map.buswidth * 8 ); +#ifdef CONFIG_ARCH_RAMSES + FLASH_WRITE_PROTECT_DISABLE(); +#endif + ramses_map.map_priv_1 = (unsigned long)__ioremap(WINDOW_ADDR, WINDOW_SIZE, 0); + if (!ramses_map.map_priv_1) { + printk("Failed to ioremap\n"); + return -EIO; + } + mymtd = do_map_probe("cfi_probe", &ramses_map); + if (!mymtd) { + iounmap((void *)ramses_map.map_priv_1); + return -ENXIO; + } + mymtd->module = THIS_MODULE; + +#ifdef CONFIG_MTD_REDBOOT_PARTS + if (parsed_nr_parts == 0) { + int ret = parse_redboot_partitions(mymtd, &parsed_parts); + + if (ret > 0) { + part_type = "RedBoot"; + parsed_nr_parts = ret; + } + } +#endif + + if (parsed_nr_parts > 0) { + parts = parsed_parts; + nb_parts = parsed_nr_parts; + } else { + parts = ramses_partitions; + nb_parts = NB_OF(ramses_partitions); + } + if (nb_parts) { + printk(KERN_NOTICE "Using %s partition definition\n", part_type); + add_mtd_partitions(mymtd, parts, nb_parts); + } else { + add_mtd_device(mymtd); + } + return 0; +} + +static void __exit cleanup_ramses(void) +{ + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + if (parsed_parts) + kfree(parsed_parts); + } + if (ramses_map.map_priv_1) + iounmap((void *)ramses_map.map_priv_1); +#ifdef CONFIG_ARCH_RAMSES + FLASH_WRITE_PROTECT_ENABLE(); +#endif + return; +} + +module_init(init_ramses); +module_exit(cleanup_ramses); + --- linux-2.4.21/drivers/net/irda/pxa_ir.c~pxa-irda +++ linux-2.4.21/drivers/net/irda/pxa_ir.c @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -786,6 +787,7 @@ * Suspend the IrDA interface. */ +/* static int pxa250_irda_shutdown(struct pxa250_irda *si) { @@ -793,6 +795,7 @@ return 0; } +*/ static int pxa250_irda_suspend(struct net_device *dev, int state) @@ -1141,11 +1144,11 @@ /* 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); + si->rxbuf_dma_virt = consistent_alloc(GFP_KERNEL | GFP_DMA ,HPSIR_MAX_RXLEN , &si->rxbuf_dma, 0); 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); + si->txbuf_dma_virt = consistent_alloc(GFP_KERNEL | GFP_DMA, HPSIR_MAX_TXLEN, &si->txbuf_dma, 0); if (! si->txbuf_dma_virt ) goto err_txbuf_dma; --- linux-2.4.21/drivers/net/smc91x.c~pxa-smc91x +++ linux-2.4.21/drivers/net/smc91x.c @@ -46,10 +46,13 @@ . 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. + . 20/08/03 Holger Schurig add ethtool support ----------------------------------------------------------------------------*/ +#define DRV_NAME "smc91x" + static const char version[] = - "smc91x.c: v1.0, mar 07 2003 by Nicolas Pitre \n"; + DRV_NAME ": v1.1 Aug 20 2003 by Nicolas Pitre \n"; /* Debugging level */ #ifndef SMC_DEBUG @@ -67,6 +70,7 @@ #include #include #include +#include #include #include @@ -78,6 +82,7 @@ #include #include #include +#include #include "smc91x.h" @@ -105,7 +110,7 @@ static int irq = SMC_IRQ; #ifndef SMC_NOWAIT -# define SMC_NOWAIT 0 +# define SMC_NOWAIT 1 #endif static int nowait = SMC_NOWAIT; @@ -116,6 +121,11 @@ MODULE_PARM_DESC(irq, "IRQ number"); MODULE_PARM_DESC(nowait, "set to 1 for no wait state"); +static int +smc_read_phy_register(unsigned long ioaddr, int phyaddr, int phyreg); +static void +smc_write_phy_register( unsigned long ioaddr, int phyaddr, + int phyreg, int phydata ); /*------------------------------------------------------------------------ . @@ -143,7 +153,12 @@ . 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 +#define THROTTLE_TX_PKTS 1 + +/* + . This defines if we want to compile ethtool support into the driver +*/ +#define WITH_ETHTOOL 1 /* store this information for the driver.. */ @@ -310,14 +325,14 @@ if (nowait) SMC_SET_CONFIG( SMC_GET_CONFIG() | CONFIG_NO_WAIT ); -#ifdef POWER_DOWN +#if 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); + smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, status); #endif /* this should pause enough for the chip to be happy */ @@ -390,10 +405,10 @@ SMC_SET_RCR( RCR_CLEAR ); SMC_SET_TCR( TCR_CLEAR ); -#ifdef POWER_DOWN +#if 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); + smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, status); /* finally, shut the chip down */ SMC_SELECT_BANK( 1 ); @@ -1628,14 +1643,18 @@ // 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->rpc_cur_mode = (RPC_ANEG | (RPC_LED_10 << RPC_LSXA_SHFT) | (RPC_LED_TX_RX << RPC_LSXB_SHFT) | RPC_DPLX); + + // 10 MBit/S, auto-negotiation only for 10 MB/s + lp->ctl_autoneg = 1; + lp->ctl_rfduplx = 1; lp->ctl_rspeed = 10; #else + lp->rpc_cur_mode = RPC_DEFAULT; + lp->ctl_autoneg = 1; lp->ctl_rfduplx = 1; lp->ctl_rspeed = 100; @@ -1680,6 +1699,127 @@ return 0; } +/*---------------------------------------------------- + . smc_ioctl + . + . This ioctl is currently only used by ethtool(8) to + . access the serial EEPROM + -----------------------------------------------------*/ + +#if WITH_ETHTOOL + +#define SMC91x_EEPROM_SIZE (0x40*2) + +u16 smc_eeprom_read(long ioaddr, u16 location) +{ + u16 val; + u16 oldBank; + u16 oldPtr; + + cli(); + // Save chip settings + oldBank = SMC_CURRENT_BANK(); + SMC_SELECT_BANK( 2 ); + oldPtr = SMC_GET_PTR(); + + // Set location in EEPROM to be read + SMC_SET_PTR(location); + + // Set EEPROM_SELECT and RELOAD bits in control register + SMC_SELECT_BANK( 1 ); + val = SMC_GET_CTL(); + SMC_SET_CTL(val | CTL_EEPROM_SELECT | CTL_RELOAD); + + // Wait until RELEAD is finished + while (SMC_GET_CTL() & CTL_RELOAD) ; + + // Get EEPROM data + val = SMC_inw(ioaddr, GP_REG); + + // Restore chip settings + SMC_SELECT_BANK( 2 ); + SMC_SET_PTR(oldPtr); + SMC_SELECT_BANK( oldBank ); + sti(); + + return val; +} + +static int smc_get_eeprom(struct net_device *dev, u8 *buf) +{ + int i; + u16 *ebuf = (u16 *)buf; + + for (i = 0; i < SMC91x_EEPROM_SIZE/2; i++) { + ebuf[i] = smc_eeprom_read(dev->base_addr, i); + } + return 0; +} + +static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + u32 etcmd; + int ret = -EINVAL; + + if (cmd != SIOCETHTOOL) + return -EOPNOTSUPP; + + if (get_user(etcmd, (u32 *)rq->ifr_data)) + return -EFAULT; + + switch (etcmd) { + + /* Get driver info */ + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo edrv; + + memset(&edrv, 0, sizeof(edrv)); + edrv.cmd = etcmd; + strcpy(edrv.driver, DRV_NAME); + sprintf(edrv.bus_info, "ISA:%8.8lx:%d", dev->base_addr, dev->irq); + edrv.eedump_len = SMC91x_EEPROM_SIZE; + ret = copy_to_user(rq->ifr_data, &edrv, sizeof(edrv)) ? -EFAULT : 0; + break; + } + + /* Get EEPROM data */ + case ETHTOOL_GEEPROM: { + struct ethtool_eeprom eeprom; + u8 eebuf[SMC91x_EEPROM_SIZE]; + int r; + + if (copy_from_user(&eeprom, rq->ifr_data, sizeof(eeprom))) + return -EFAULT; + + if (eeprom.offset > eeprom.offset+eeprom.len) + return -EINVAL; + + if ((eeprom.offset+eeprom.len) > SMC91x_EEPROM_SIZE) { + eeprom.len = SMC91x_EEPROM_SIZE-eeprom.offset; + } + eeprom.magic = 0; + if (copy_to_user(rq->ifr_data, &eeprom, sizeof(eeprom))) + return -EFAULT; + + rq->ifr_data += offsetof(struct ethtool_eeprom, data); + + r = smc_get_eeprom(dev, eebuf); + + if (r) + return r; + if (copy_to_user(rq->ifr_data, eebuf+eeprom.offset, eeprom.len)) + return -EFAULT; + return 0; + + } + } + + return ret; +} + +#endif + + /*------------------------------------------------------------ . Get the current statistics. . This may be called with the card open or closed. @@ -1925,6 +2065,9 @@ dev->watchdog_timeo = HZ/10; dev->get_stats = smc_query_statistics; dev->set_multicast_list = smc_set_multicast_list; +#if WITH_ETHTOOL + dev->do_ioctl = smc_ioctl; +#endif return 0; @@ -1961,12 +2104,17 @@ smc_shutdown(global_dev); break; case PM_RESUME: + udelay(5000); 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); + if (global_dev->flags & IFF_UP) { + if (lp->version >= 0x70) + smc_phy_configure(global_dev); + } else { + smc_shutdown(global_dev); + } break; } return 0; @@ -2054,6 +2202,15 @@ int ioaddr = RAMSES_ETH_BASE + 0x300; global_dev->irq = SMC_IRQ; ret = smc_probe(global_dev, ioaddr); +#ifdef POWER_DOWN + smc_shutdown(global_dev); +#endif + } +#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) { @@ -2083,7 +2240,11 @@ #ifdef CONFIG_PM if (ret == 0) { struct smc_local *lp = (struct smc_local *)global_dev->priv; +#ifdef PM_DEBUG + lp->pm = pm_register(PM_SYS_UNKNOWN, 0x73393178, smc_pm_callback, "smc91x"); +#else lp->pm = pm_register(PM_SYS_UNKNOWN, 0x73393178, smc_pm_callback); +#endif } #endif --- linux-2.4.21/drivers/net/smc91x.h~ramses-smc91x +++ linux-2.4.21/drivers/net/smc91x.h @@ -79,6 +79,11 @@ #include #define SMC_IOADDR (RAMSES_ETH_PHYS + 0x300) #define SMC_IRQ ETHERNET_IRQ + +#elif CONFIG_ARCH_RAMSES +#include +#define SMC_IOADDR (RAMSES_ETH_PHYS + 0x300) +#define SMC_IRQ ETHERNET_IRQ #endif #define SMC_CAN_USE_8BIT 1 --- linux-2.4.21/drivers/net/wireless/hermes.c~orinoco013e +++ linux-2.4.21/drivers/net/wireless/hermes.c @@ -52,7 +52,6 @@ #include "hermes.h" -static char version[] __initdata = "hermes.c: 4 Dec 2002 David Gibson "; MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller"); MODULE_AUTHOR("David Gibson "); #ifdef MODULE_LICENSE @@ -226,7 +225,8 @@ * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware * * Callable from any context, but locking is your problem. */ -int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, hermes_response_t *resp) +int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, + hermes_response_t *resp) { int err; int k; @@ -469,13 +469,17 @@ err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL); if (err) - goto out; + return err; err = hermes_bap_seek(hw, bap, rid, 0); if (err) - goto out; + return err; rlength = hermes_read_reg(hw, dreg); + + if (! rlength) + return -ENOENT; + rtype = hermes_read_reg(hw, dreg); if (length) @@ -495,8 +499,7 @@ nwords = min((unsigned)rlength - 1, bufsize / 2); hermes_read_words(hw, dreg, buf, nwords); - out: - return err; + return 0; } int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, @@ -511,7 +514,7 @@ err = hermes_bap_seek(hw, bap, rid, 0); if (err) - goto out; + return err; hermes_write_reg(hw, dreg, length); hermes_write_reg(hw, dreg, rid); @@ -523,7 +526,6 @@ err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, rid, NULL); - out: return err; } @@ -539,9 +541,12 @@ static int __init init_hermes(void) { - printk(KERN_DEBUG "%s\n", version); - return 0; } +static void __exit exit_hermes(void) +{ +} + module_init(init_hermes); +module_exit(exit_hermes); --- linux-2.4.21/drivers/net/wireless/hermes.h~orinoco013e +++ linux-2.4.21/drivers/net/wireless/hermes.h @@ -250,7 +250,6 @@ u16 scanreason; /* ??? */ struct hermes_scan_apinfo aps[35]; /* Scan result */ } __attribute__ ((packed)); - #define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000) #define HERMES_LINKSTATUS_CONNECTED (0x0001) #define HERMES_LINKSTATUS_DISCONNECTED (0x0002) @@ -278,7 +277,7 @@ /* Basic control structure */ typedef struct hermes { - ulong iobase; + unsigned long iobase; int io_space; /* 1 if we IO-mapped IO, 0 for memory-mapped IO? */ #define HERMES_IO 1 #define HERMES_MEM 0 @@ -368,7 +367,7 @@ if (hw->io_space) { insw(hw->iobase + off, buf, count); } else { - int i; + unsigned i; u16 *p; /* This needs to *not* byteswap (like insw()) but @@ -388,7 +387,7 @@ if (hw->io_space) { outsw(hw->iobase + off, buf, count); } else { - int i; + unsigned i; const u16 *p; /* This needs to *not* byteswap (like outsw()) but @@ -398,6 +397,21 @@ for (i = 0, p = buf; i < count; i++) { writew(le16_to_cpu(*p++), hw->iobase + off); } + } +} + +static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count) +{ + unsigned i; + + off = off << hw->reg_spacing;; + + if (hw->io_space) { + for (i = 0; i < count; i++) + outw(0, hw->iobase + off); + } else { + for (i = 0; i < count; i++) + writew(0, hw->iobase + off); } } --- linux-2.4.21/drivers/net/wireless/ieee802_11.h~orinoco013e +++ linux-2.4.21/drivers/net/wireless/ieee802_11.h @@ -9,6 +9,8 @@ bytes is allowed, which is a bit confusing, I suspect this represents the 2304 bytes of real data, plus a possible 8 bytes of WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ + + #define IEEE802_11_HLEN 30 #define IEEE802_11_FRAME_LEN (IEEE802_11_DATA_LEN + IEEE802_11_HLEN) --- linux-2.4.21/drivers/net/wireless/orinoco.c~orinoco013e +++ linux-2.4.21/drivers/net/wireless/orinoco.c @@ -1,4 +1,4 @@ -/* orinoco.c 0.13b - (formerly known as dldwd_cs.c and orinoco_cs.c) +/* orinoco.c 0.13e - (formerly known as dldwd_cs.c and orinoco_cs.c) * * A driver for Hermes or Prism 2 chipset based PCMCIA wireless * adaptors, with Lucent/Agere, Intersil or Symbol firmware. @@ -117,7 +117,7 @@ * o Init of priv->tx_rate_ctrl in firmware specific section. * o Prism2/Symbol rate, upto should be 0xF and not 0x15. Doh ! * o Spectrum card always need cor_reset (for every reset) - * o Fix cor_reset to not loose bit 7 in the register + * o Fix cor_reset to not lose bit 7 in the register * o flush_stale_links to remove zombie Pcmcia instances * o Ack previous hermes event before reset * Me (with my little hands) @@ -289,7 +289,7 @@ * which are used as the dev->open, dev->stop, priv->reset * callbacks if none are specified when alloc_orinocodev() is * called. - * o Removed orinoco_plx_interupt() and orinoco_pci_interrupt(). + * o Removed orinoco_plx_interrupt() and orinoco_pci_interrupt(). * They didn't do anything. * * v0.12 -> v0.12a - 4 Jul 2002 - David Gibson @@ -345,13 +345,54 @@ * we are connected (avoids cofusing the firmware), and only * give LINKSTATUS printk()s if the status has changed. * + * v0.13b -> v0.13c - 11 Mar 2003 - David Gibson + * o Cleanup: use dev instead of priv in various places. + * o Bug fix: Don't ReleaseConfiguration on RESET_PHYSICAL event + * if we're in the middle of a (driver initiated) hard reset. + * o Bug fix: ETH_ZLEN is supposed to include the header + * (Dionysus Blazakis & Manish Karir) + * o Convert to using workqueues instead of taskqueues (and + * backwards compatibility macros for pre 2.5.41 kernels). + * o Drop redundant (I think...) MOD_{INC,DEC}_USE_COUNT in + * airport.c + * o New orinoco_tmd.c init module from Joerg Dorchain for + * TMD7160 based PCI to PCMCIA bridges (similar to + * orinoco_plx.c). + * + * v0.13c -> v0.13d - 22 Apr 2003 - David Gibson + * o Make hw_unavailable a counter, rather than just a flag, this + * is necessary to avoid some races (such as a card being + * removed in the middle of orinoco_reset(). + * o Restore Release/RequestConfiguration in the PCMCIA event handler + * when dealing with a driver initiated hard reset. This is + * necessary to prevent hangs due to a spurious interrupt while + * the reset is in progress. + * o Clear the 802.11 header when transmitting, even though we + * don't use it. This fixes a long standing bug on some + * firmwares, which seem to get confused if that isn't done. + * o Be less eager to de-encapsulate SNAP frames, only do so if + * the OUI is 00:00:00 or 00:00:f8, leave others alone. The old + * behaviour broke CDP (Cisco Discovery Protocol). + * o Use dev instead of priv for free_irq() as well as + * request_irq() (oops). + * o Attempt to reset rather than giving up if we get too many + * IRQs. + * o Changed semantics of __orinoco_down() so it can be called + * safely with hw_unavailable set. It also now clears the + * linkstatus (since we're going to have to reassociate). + * + * v0.13d -> v0.13e - 12 May 2003 - David Gibson + * o Support for post-2.5.68 return values from irq handler. + * o Fixed bug where underlength packets would be double counted + * in the rx_dropped statistics. + * o Provided a module parameter to suppress linkstatus messages. + * * TODO - * o New wireless extensions API (patch from Moustafa - * Youssef, updated by Jim Carter). - * o Fix PCMCIA hard resets with pcmcia-cs. + * Youssef, updated by Jim Carter and Pavel Roskin). * o Handle de-encapsulation within network layer, provide 802.11 * headers (patch from Thomas 'Dent' Mirlacher) + * o RF monitor mode support * o Fix possible races in SPY handling. * o Disconnect wireless extensions from fundamental configuration. * o (maybe) Software WEP support (patch from Stano Meduna). @@ -373,27 +414,27 @@ * flag after taking the lock, and if it is set, give up on whatever * they are doing and drop the lock again. The orinoco_lock() * function handles this (it unlocks and returns -EBUSY if - * hw_unavailable is true). */ + * hw_unavailable is non-zero). */ #include #include #include #include -#include #include #include #include #include #include -#include -#include -#include #include #include #include #include +#include +#include +#include + #include "hermes.h" #include "hermes_rid.h" #include "orinoco.h" @@ -416,6 +457,9 @@ EXPORT_SYMBOL(orinoco_debug); #endif +static int suppress_linkstatus; /* = 0 */ +MODULE_PARM(suppress_linkstatus, "i"); + /********************************************************************/ /* Compile time configuration and compatibility stuff */ /********************************************************************/ @@ -443,8 +487,10 @@ #define USER_BAP 0 #define IRQ_BAP 1 #define MAX_IRQLOOPS_PER_IRQ 10 -#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of how many events the - device could legitimately generate */ +#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of + * how many events the + * device could + * legitimately generate */ #define SMALL_KEY_SIZE 5 #define LARGE_KEY_SIZE 13 #define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */ @@ -480,8 +526,8 @@ {10, 1, 1, 1}, {20, 0, 2, 2}, {20, 1, 6, 3}, - {55, 0, 4, 4}, - {55, 1, 7, 7}, + {55, 0, 4, 4}, + {55, 1, 7, 7}, {110, 0, 5, 8}, }; #define BITRATE_TABLE_SIZE (sizeof(bitrate_table) / sizeof(bitrate_table[0])) @@ -522,7 +568,7 @@ /* Hardware control routines */ -static int __orinoco_program_rids(struct orinoco_private *priv); +static int __orinoco_program_rids(struct net_device *dev); static int __orinoco_hw_set_bitrate(struct orinoco_private *priv); static int __orinoco_hw_setup_wep(struct orinoco_private *priv); @@ -535,37 +581,17 @@ static void __orinoco_set_multicast_list(struct net_device *dev); /* Interrupt handling routines */ -static void __orinoco_ev_tick(struct orinoco_private *priv, hermes_t *hw); -static void __orinoco_ev_wterr(struct orinoco_private *priv, hermes_t *hw); -static void __orinoco_ev_infdrop(struct orinoco_private *priv, hermes_t *hw); -static void __orinoco_ev_info(struct orinoco_private *priv, hermes_t *hw); -static void __orinoco_ev_rx(struct orinoco_private *priv, hermes_t *hw); -static void __orinoco_ev_txexc(struct orinoco_private *priv, hermes_t *hw); -static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw); -static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw); +static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw); +static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw); +static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw); +static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw); +static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw); +static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw); +static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw); +static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw); /* ioctl() routines */ -static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq); -static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq); -static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq); -static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq); -static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq); -static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq); -static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq); -static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq); -static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq); -static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq); -static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq); -static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq); -static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq); -static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *frq); -static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *frq); -static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq); -static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq); -static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq); -static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq); - -static int orinoco_debug_dump_recs(struct orinoco_private *priv); +static int orinoco_debug_dump_recs(struct net_device *dev); /********************************************************************/ /* Function prototypes */ @@ -577,7 +603,7 @@ struct hermes *hw = &priv->hw; int err; - err = __orinoco_program_rids(priv); + err = __orinoco_program_rids(dev); if (err) { printk(KERN_ERR "%s: Error %d configuring card\n", dev->name, err); @@ -606,14 +632,25 @@ netif_stop_queue(dev); - err = hermes_disable_port(hw, 0); - if (err) { - printk(KERN_ERR "%s: Error %d disabling MAC port\n", - dev->name, err); - return err; + if (! priv->hw_unavailable) { + if (! priv->broken_disableport) { + err = hermes_disable_port(hw, 0); + if (err) { + /* Some firmwares (e.g. Intersil 1.3.x) seem + * to have problems disabling the port, oh + * well, too bad. */ + printk(KERN_WARNING "%s: Error %d disabling MAC port\n", + dev->name, err); + priv->broken_disableport = 1; + } + } + hermes_set_irqmask(hw, 0); + hermes_write_regn(hw, EVACK, 0xffff); } - hermes_set_irqmask(hw, 0); - hermes_write_regn(hw, EVACK, 0xffff); + + /* firmware will have to reassociate */ + priv->last_linkstatus = 0xffff; + priv->connected = 0; return 0; } @@ -656,38 +693,38 @@ if (err) return err; - priv->open = 1; - err = __orinoco_up(dev); + if (! err) + priv->open = 1; + orinoco_unlock(priv, &flags); return err; } -static int orinoco_stop(struct net_device *dev) +int orinoco_stop(struct net_device *dev) { struct orinoco_private *priv = dev->priv; int err = 0; /* We mustn't use orinoco_lock() here, because we need to be - able to close the interface, even if hw_unavailable is set + able to close the interface even if hw_unavailable is set (e.g. as we're released after a PC Card removal) */ spin_lock_irq(&priv->lock); priv->open = 0; - if (! priv->hw_unavailable) - err = __orinoco_down(dev); + err = __orinoco_down(dev); spin_unlock_irq(&priv->lock); return err; } -static int __orinoco_program_rids(struct orinoco_private *priv) +static int __orinoco_program_rids(struct net_device *dev) { - struct net_device *dev = priv->ndev; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; int err; struct hermes_idstring idbuf; @@ -873,51 +910,84 @@ } /* xyzzy */ -static int orinoco_reconfigure(struct orinoco_private *priv) +static int orinoco_reconfigure(struct net_device *dev) { + struct orinoco_private *priv = dev->priv; struct hermes *hw = &priv->hw; unsigned long flags; int err = 0; - orinoco_lock(priv, &flags); + if (priv->broken_disableport) { + schedule_work(&priv->reset_work); + return 0; + } + + err = orinoco_lock(priv, &flags); + if (err) + return err; + err = hermes_disable_port(hw, 0); if (err) { - printk(KERN_ERR "%s: Unable to disable port in orinco_reconfigure()\n", - priv->ndev->name); + printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n", + dev->name); + priv->broken_disableport = 1; goto out; } - err = __orinoco_program_rids(priv); - if (err) + err = __orinoco_program_rids(dev); + if (err) { + printk(KERN_WARNING "%s: Unable to reconfigure card\n", + dev->name); goto out; + } err = hermes_enable_port(hw, 0); if (err) { - printk(KERN_ERR "%s: Unable to enable port in orinco_reconfigure()\n", - priv->ndev->name); + printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", + dev->name); goto out; } out: + if (err) { + printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); + schedule_work(&priv->reset_work); + err = 0; + } + orinoco_unlock(priv, &flags); return err; } /* This must be called from user context, without locks held - use - * schedule_task() */ + * schedule_work() */ static void orinoco_reset(struct net_device *dev) { struct orinoco_private *priv = dev->priv; + struct hermes *hw = &priv->hw; int err; unsigned long flags; err = orinoco_lock(priv, &flags); if (err) + /* When the hardware becomes available again, whatever + * detects that is responsible for re-initializing + * it. So no need for anything further*/ return; - priv->hw_unavailable = 1; + netif_stop_queue(dev); + + /* Shut off interrupts. Depending on what state the hardware + * is in, this might not work, but we'll try anyway */ + hermes_set_irqmask(hw, 0); + hermes_write_regn(hw, EVACK, 0xffff); + + priv->hw_unavailable++; + priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */ + priv->connected = 0; + orinoco_unlock(priv, &flags); if (priv->hard_reset) @@ -936,18 +1006,22 @@ return; } - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irq(&priv->lock); /* This has to be called from user context */ - priv->hw_unavailable = 0; + priv->hw_unavailable--; - err = __orinoco_up(dev); - if (err) { - printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n", - dev->name, err); - } else - dev->trans_start = jiffies; + /* priv->open or priv->hw_unavailable might have changed while + * we dropped the lock */ + if (priv->open && (! priv->hw_unavailable)) { + err = __orinoco_up(dev); + if (err) { + printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n", + dev->name, err); + } else + dev->trans_start = jiffies; + } - orinoco_unlock(priv, &flags); + spin_unlock_irq(&priv->lock); return; } @@ -979,10 +1053,18 @@ } } +/* Does the frame have a SNAP header indicating it should be + * de-encapsulated to Ethernet-II? */ static inline int -is_snap(struct header_struct *hdr) +is_ethersnap(struct header_struct *hdr) { - return (hdr->dsap == 0xAA) && (hdr->ssap == 0xAA) && (hdr->ctrl == 0x3); + /* We de-encapsulate all packets which, a) have SNAP headers + * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header + * and where b) the OUI of the SNAP header is 00:00:00 or + * 00:00:f8 - we need both because different APs appear to use + * different OUIs for some reason */ + return (memcmp(&hdr->dsap, &encaps_hdr, 5) == 0) + && ( (hdr->oui[2] == 0x00) || (hdr->oui[2] == 0xf8) ); } static void @@ -1140,7 +1222,8 @@ return 0; } -static int orinoco_hw_get_bssid(struct orinoco_private *priv, char buf[ETH_ALEN]) +static int orinoco_hw_get_bssid(struct orinoco_private *priv, + char buf[ETH_ALEN]) { hermes_t *hw = &priv->hw; int err = 0; @@ -1159,7 +1242,7 @@ } static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, - char buf[IW_ESSID_MAX_SIZE+1]) + char buf[IW_ESSID_MAX_SIZE+1]) { hermes_t *hw = &priv->hw; int err = 0; @@ -1236,9 +1319,8 @@ } if ( (channel < 1) || (channel > NUM_CHANNELS) ) { - struct net_device *dev = priv->ndev; - - printk(KERN_WARNING "%s: Channel out of range (%d)!\n", dev->name, channel); + printk(KERN_WARNING "%s: Channel out of range (%d)!\n", + priv->ndev->name, channel); err = -EBUSY; goto out; @@ -1253,8 +1335,8 @@ return err ? err : freq; } -static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates, - s32 *rates, int max) +static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, + int *numrates, s32 *rates, int max) { hermes_t *hw = &priv->hw; struct hermes_idstring list; @@ -1287,9 +1369,6 @@ } #if 0 -#ifndef ORINOCO_DEBUG -static inline void show_rx_frame(struct orinoco_rxframe_hdr *frame) {} -#else static void show_rx_frame(struct orinoco_rxframe_hdr *frame) { printk(KERN_DEBUG "RX descriptor:\n"); @@ -1346,17 +1425,16 @@ frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]); printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype); } -#endif -#endif +#endif /* 0 */ /* * Interrupt handler */ -void orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct orinoco_private *priv = (struct orinoco_private *) dev_id; + struct net_device *dev = (struct net_device *)dev_id; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; - struct net_device *dev = priv->ndev; int count = MAX_IRQLOOPS_PER_IRQ; u16 evstat, events; /* These are used to detect a runaway interrupt situation */ @@ -1367,12 +1445,17 @@ unsigned long flags; if (orinoco_lock(priv, &flags) != 0) { - /* If hw is unavailable */ - return; + /* If hw is unavailable - we don't know if the irq was + * for us or not */ + return IRQ_HANDLED; } evstat = hermes_read_regn(hw, EVSTAT); events = evstat & hw->inten; + if (! events) { + orinoco_unlock(priv, &flags); + return IRQ_NONE; + } if (jiffies != last_irq_jiffy) loops_this_jiffy = 0; @@ -1380,11 +1463,11 @@ while (events && count--) { if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) { - printk(KERN_CRIT "%s: IRQ handler is looping too \ -much! Shutting down.\n", - dev->name); - /* Perform an emergency shutdown */ + printk(KERN_WARNING "%s: IRQ handler is looping too " + "much! Resetting.\n", dev->name); + /* Disable interrupts for now */ hermes_set_irqmask(hw, 0); + schedule_work(&priv->reset_work); break; } @@ -1395,21 +1478,21 @@ } if (events & HERMES_EV_TICK) - __orinoco_ev_tick(priv, hw); + __orinoco_ev_tick(dev, hw); if (events & HERMES_EV_WTERR) - __orinoco_ev_wterr(priv, hw); + __orinoco_ev_wterr(dev, hw); if (events & HERMES_EV_INFDROP) - __orinoco_ev_infdrop(priv, hw); + __orinoco_ev_infdrop(dev, hw); if (events & HERMES_EV_INFO) - __orinoco_ev_info(priv, hw); + __orinoco_ev_info(dev, hw); if (events & HERMES_EV_RX) - __orinoco_ev_rx(priv, hw); + __orinoco_ev_rx(dev, hw); if (events & HERMES_EV_TXEXC) - __orinoco_ev_txexc(priv, hw); + __orinoco_ev_txexc(dev, hw); if (events & HERMES_EV_TX) - __orinoco_ev_tx(priv, hw); + __orinoco_ev_tx(dev, hw); if (events & HERMES_EV_ALLOC) - __orinoco_ev_alloc(priv, hw); + __orinoco_ev_alloc(dev, hw); hermes_write_regn(hw, EVACK, events); @@ -1418,30 +1501,34 @@ }; orinoco_unlock(priv, &flags); + return IRQ_HANDLED; } -static void __orinoco_ev_tick(struct orinoco_private *priv, hermes_t *hw) +static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw) { - printk(KERN_DEBUG "%s: TICK\n", priv->ndev->name); + printk(KERN_DEBUG "%s: TICK\n", dev->name); } -static void __orinoco_ev_wterr(struct orinoco_private *priv, hermes_t *hw) +static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw) { /* This seems to happen a fair bit under load, but ignoring it seems to work fine...*/ printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n", - priv->ndev->name); + dev->name); } -static void __orinoco_ev_infdrop(struct orinoco_private *priv, hermes_t *hw) +static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) { - printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev->name); + printk(KERN_WARNING "%s: Information frame lost.\n", dev->name); } static void print_linkstatus(struct net_device *dev, u16 status) { char * s; + if (suppress_linkstatus) + return; + switch (status) { case HERMES_LINKSTATUS_NOT_CONNECTED: s = "Not Connected"; @@ -1472,9 +1559,9 @@ dev->name, s, status); } -static void __orinoco_ev_info(struct orinoco_private *priv, hermes_t *hw) +static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) { - struct net_device *dev = priv->ndev; + struct orinoco_private *priv = dev->priv; u16 infofid; struct { u16 len; @@ -1573,9 +1660,9 @@ } } -static void __orinoco_ev_rx(struct orinoco_private *priv, hermes_t *hw) +static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) { - struct net_device *dev = priv->ndev; + struct orinoco_private *priv = dev->priv; struct net_device_stats *stats = &priv->stats; struct iw_statistics *wstats = &priv->wstats; struct sk_buff *skb = NULL; @@ -1664,14 +1751,13 @@ * So, check ourselves */ if(((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || - is_snap(&hdr)) { + is_ethersnap(&hdr)) { /* These indicate a SNAP within 802.2 LLC within 802.11 frame which we'll need to de-encapsulate to the original EthernetII frame. */ if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */ stats->rx_length_errors++; - stats->rx_dropped++; goto drop; } @@ -1726,9 +1812,9 @@ return; } -static void __orinoco_ev_txexc(struct orinoco_private *priv, hermes_t *hw) +static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) { - struct net_device *dev = priv->ndev; + struct orinoco_private *priv = dev->priv; struct net_device_stats *stats = &priv->stats; u16 fid = hermes_read_regn(hw, TXCOMPLFID); struct hermes_tx_descriptor desc; @@ -1752,8 +1838,9 @@ hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); } -static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw) +static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw) { + struct orinoco_private *priv = dev->priv; struct net_device_stats *stats = &priv->stats; stats->tx_packets++; @@ -1761,9 +1848,10 @@ hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); } -static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw) +static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw) { - struct net_device *dev = priv->ndev; + struct orinoco_private *priv = dev->priv; + u16 fid = hermes_read_regn(hw, ALLOCFID); if (fid != priv->txfid) { @@ -1945,7 +2033,7 @@ TRACE_ENTER(dev->name); - /* No need to lock, the resetting flag is already set in + /* No need to lock, the hw_unavailable flag is already set in * alloc_orinocodev() */ priv->nicbuf_size = IEEE802_11_FRAME_LEN + ETH_HLEN; @@ -2081,8 +2169,6 @@ priv->wep_on = 0; priv->tx_key = 0; - priv->hw_unavailable = 0; - err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); if (err == -EIO) { /* Try workaround for old Symbol firmware bug */ @@ -2102,6 +2188,12 @@ goto out; } + /* Make the hardware available, as long as it hasn't been + * removed elsewhere (e.g. by PCMCIA hot unplug) */ + spin_lock_irq(&priv->lock); + priv->hw_unavailable--; + spin_unlock_irq(&priv->lock); + printk(KERN_DEBUG "%s: ready\n", dev->name); out: @@ -2267,7 +2359,7 @@ /* Length of the packet body */ /* FIXME: what if the skb is smaller than this? */ - len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN); + len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN); eh = (struct ethhdr *)skb->data; @@ -2281,6 +2373,12 @@ goto fail; } + /* Clear the 802.11 header and data length fields - some + * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused + * if this isn't done. */ + hermes_clear_words(hw, HERMES_DATA0, + HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); + /* Encapsulate Ethernet-II frames */ if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */ struct header_struct hdr; @@ -2362,7 +2460,7 @@ stats->tx_errors++; - schedule_task(&priv->timeout_task); + schedule_work(&priv->reset_work); } static int @@ -2532,7 +2630,7 @@ } err = orinoco_hw_get_bitratelist(priv, &numrates, - range.bitrate, IW_MAX_BITRATES); + range.bitrate, IW_MAX_BITRATES); if (err) return err; range.num_bitrates = numrates; @@ -2799,7 +2897,7 @@ erq->flags = 1; erq->length = strlen(essidbuf) + 1; if (erq->pointer) - if ( copy_to_user(erq->pointer, essidbuf, erq->length) ) + if (copy_to_user(erq->pointer, essidbuf, erq->length)) return -EFAULT; TRACE_EXIT(dev->name); @@ -3128,7 +3226,7 @@ rrq->value = 5500000; else rrq->value = val * 1000000; - break; + break; case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */ case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ for (i = 0; i < BITRATE_TABLE_SIZE; i++) @@ -3754,7 +3852,7 @@ printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name); - schedule_task(&priv->timeout_task); + schedule_work(&priv->reset_work); break; case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */ @@ -3827,7 +3925,7 @@ break; case SIOCIWLASTPRIV: - err = orinoco_debug_dump_recs(priv); + err = orinoco_debug_dump_recs(dev); if (err) printk(KERN_ERR "%s: Unable to dump records (%d)\n", dev->name, err); @@ -3839,7 +3937,7 @@ } if (! err && changed && netif_running(dev)) { - err = orinoco_reconfigure(priv); + err = orinoco_reconfigure(dev); } TRACE_EXIT(dev->name); @@ -3924,7 +4022,7 @@ DEBUG_REC(PRIID,WORDS), DEBUG_REC(PRISUPRANGE,WORDS), DEBUG_REC(CFIACTRANGES,WORDS), - DEBUG_REC(NICSERNUM,WORDS), + DEBUG_REC(NICSERNUM,XSTRING), DEBUG_REC(NICID,WORDS), DEBUG_REC(MFISUPRANGE,WORDS), DEBUG_REC(CFISUPRANGE,WORDS), @@ -3961,8 +4059,9 @@ #define DEBUG_LTV_SIZE 128 -static int orinoco_debug_dump_recs(struct orinoco_private *priv) +static int orinoco_debug_dump_recs(struct net_device *dev) { + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; u8 *val8; u16 *val16; @@ -4051,6 +4150,7 @@ dev->do_ioctl = orinoco_ioctl; dev->change_mtu = orinoco_change_mtu; dev->set_multicast_list = orinoco_set_multicast_list; + /* we use the default eth_mac_addr for setting the MAC addr */ /* Set up default callbacks */ dev->open = orinoco_open; @@ -4062,7 +4162,7 @@ priv->hw_unavailable = 1; /* orinoco_init() must clear this * before anything else touches the * hardware */ - INIT_TQUEUE(&priv->timeout_task, (void (*)(void *))orinoco_reset, dev); + INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev); priv->last_linkstatus = 0xffff; priv->connected = 0; @@ -4079,13 +4179,14 @@ EXPORT_SYMBOL(__orinoco_up); EXPORT_SYMBOL(__orinoco_down); +EXPORT_SYMBOL(orinoco_stop); EXPORT_SYMBOL(orinoco_reinit_firmware); EXPORT_SYMBOL(orinoco_interrupt); /* Can't be declared "const" or the whole __initdata section will * become const */ -static char version[] __initdata = "orinoco.c 0.13b (David Gibson and others)"; +static char version[] __initdata = "orinoco.c 0.13e (David Gibson and others)"; static int __init init_orinoco(void) { --- linux-2.4.21/drivers/net/wireless/orinoco.h~orinoco013e +++ linux-2.4.21/drivers/net/wireless/orinoco.h @@ -11,9 +11,29 @@ #include #include #include -#include +#include #include "hermes.h" +/* Workqueue / task queue backwards compatibility stuff */ + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41) +#include +#else +#include +#define work_struct tq_struct +#define INIT_WORK INIT_TQUEUE +#define schedule_work schedule_task +#endif + +/* Interrupt handler backwards compatibility stuff */ +#ifndef IRQ_NONE + +#define IRQ_NONE +#define IRQ_HANDLED +typedef void irqreturn_t; + +#endif + /* To enable debug messages */ //#define ORINOCO_DEBUG 3 @@ -36,13 +56,13 @@ struct orinoco_private { - void *card; /* Pointer to card dependant structure */ + void *card; /* Pointer to card dependent structure */ int (*hard_reset)(struct orinoco_private *); /* Synchronisation stuff */ spinlock_t lock; int hw_unavailable; - struct tq_struct timeout_task; + struct work_struct reset_work; /* driver state */ int open; @@ -72,6 +92,7 @@ int has_sensitivity; int nicbuf_size; u16 channel_mask; + int broken_disableport; /* Configuration paramaters */ u32 iw_mode; @@ -111,9 +132,9 @@ int (*hard_reset)(struct orinoco_private *)); extern int __orinoco_up(struct net_device *dev); extern int __orinoco_down(struct net_device *dev); -int orinoco_reinit_firmware(struct net_device *dev); - -extern void orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs); +extern int orinoco_stop(struct net_device *dev); +extern int orinoco_reinit_firmware(struct net_device *dev); +extern irqreturn_t orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs); /********************************************************************/ /* Locking and synchronization functions */ --- linux-2.4.21/drivers/net/wireless/orinoco_cs.c~orinoco013e +++ linux-2.4.21/drivers/net/wireless/orinoco_cs.c @@ -1,4 +1,4 @@ -/* orinoco_cs.c 0.13b - (formerly known as dldwd_cs.c) +/* orinoco_cs.c 0.13e - (formerly known as dldwd_cs.c) * * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ @@ -22,11 +22,7 @@ #include #include #include -#include #include -#include -#include -#include #include #include #include @@ -38,7 +34,10 @@ #include #include #include -#include + +#include +#include +#include #include "orinoco.h" @@ -62,7 +61,7 @@ /* Some D-Link cards have buggy CIS. They do work at 5v properly, but * don't have any CIS entry for it. This workaround it... */ -static int ignore_cis_vcc; /* = 0 */ +static int ignore_cis_vcc = 1; MODULE_PARM(irq_mask, "i"); MODULE_PARM(irq_list, "1-4i"); @@ -145,8 +144,10 @@ /* PCMCIA stuff */ /********************************************************************/ +/* In 2.5 (as of 2.5.69 at least) there is a cs_error exported which + * does this, but it's not in 2.4 so we do our own for now. */ static void -cs_error(client_handle_t handle, int func, int ret) +orinoco_cs_error(client_handle_t handle, int func, int ret) { error_info_t err = { func, ret }; CardServices(ReportError, handle, &err); @@ -202,6 +203,7 @@ link->priv = dev; /* Initialize the dev_link_t structure */ + init_timer(&link->release); link->release.function = &orinoco_cs_release; link->release.data = (u_long) link; @@ -240,7 +242,7 @@ ret = CardServices(RegisterClient, &link->handle, &client_reg); if (ret != CS_SUCCESS) { - cs_error(link->handle, RegisterClient, ret); + orinoco_cs_error(link->handle, RegisterClient, ret); orinoco_cs_detach(link); return NULL; } @@ -269,19 +271,12 @@ return; } - /* - If the device is currently configured and active, we won't - actually delete it yet. Instead, it is marked so that when - the release() function is called, that will trigger a proper - detach(). - */ if (link->state & DEV_CONFIG) { -#ifdef PCMCIA_DEBUG - printk(KERN_DEBUG "orinoco_cs: detach postponed, '%s' " - "still locked\n", link->dev->dev_name); -#endif - link->state |= DEV_STALE_LINK; - return; + orinoco_cs_release((u_long)link); + if (link->state & DEV_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } } /* Break the link with Card Services */ @@ -368,7 +363,7 @@ CS_CHECK(GetFirstTuple, handle, &tuple); while (1) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - cistpl_cftable_entry_t dflt = { index: 0 }; + cistpl_cftable_entry_t dflt = { .index = 0 }; CFG_CHECK(GetTupleData, handle, &tuple); CFG_CHECK(ParseTuple, handle, &tuple, &parse); @@ -472,7 +467,7 @@ link->irq.IRQInfo2 |= 1 << irq_list[i]; link->irq.Handler = orinoco_interrupt; - link->irq.Instance = priv; + link->irq.Instance = dev; CS_CHECK(RequestIRQ, link->handle, &link->irq); } @@ -532,7 +527,7 @@ return; cs_failed: - cs_error(link->handle, last_fn, last_ret); + orinoco_cs_error(link->handle, last_fn, last_ret); failed: orinoco_cs_release((u_long) link); @@ -549,18 +544,13 @@ dev_link_t *link = (dev_link_t *) arg; struct net_device *dev = link->priv; struct orinoco_private *priv = dev->priv; + unsigned long flags; - /* - If the device is currently in use, we won't release until it - is actually closed, because until then, we can't be sure that - no one will try to access the device or its data structures. - */ - if (priv->open) { - DEBUG(0, "orinoco_cs: release postponed, '%s' still open\n", - link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } + /* We're committed to taking the device away now, so mark the + * hardware as unavailable */ + spin_lock_irqsave(&priv->lock, flags); + priv->hw_unavailable++; + spin_unlock_irqrestore(&priv->lock, flags); /* Don't bother checking to see if these succeed or not */ CardServices(ReleaseConfiguration, link->handle); @@ -593,14 +583,9 @@ orinoco_lock(priv, &flags); netif_device_detach(dev); - priv->hw_unavailable = 1; + priv->hw_unavailable++; orinoco_unlock(priv, &flags); - -/* if (link->open) */ -/* orinoco_cs_stop(dev); */ - - mod_timer(&link->release, jiffies + HZ / 20); } break; @@ -619,13 +604,8 @@ a better way, short of rewriting the PCMCIA layer to not suck :-( */ if (! test_bit(0, &card->hard_reset_in_progress)) { - err = orinoco_lock(priv, &flags); - if (err) { - printk(KERN_ERR "%s: hw_unavailable on SUSPEND/RESET_PHYSICAL\n", - dev->name); - break; - } - + spin_lock_irqsave(&priv->lock, flags); + err = __orinoco_down(dev); if (err) printk(KERN_WARNING "%s: %s: Error %d downing interface\n", @@ -634,9 +614,9 @@ err); netif_device_detach(dev); - priv->hw_unavailable = 1; - - orinoco_unlock(priv, &flags); + priv->hw_unavailable++; + + spin_unlock_irqrestore(&priv->lock, flags); } CardServices(ReleaseConfiguration, link->handle); @@ -653,10 +633,6 @@ CardServices(RequestConfiguration, link->handle, &link->conf); - /* If we're only getting these events because - of the ResetCard in the hard reset, we - don't need to do anything - orinoco_reset() - will handle reinitialization. */ if (! test_bit(0, &card->hard_reset_in_progress)) { err = orinoco_reinit_firmware(dev); if (err) { @@ -668,9 +644,9 @@ spin_lock_irqsave(&priv->lock, flags); netif_device_attach(dev); - priv->hw_unavailable = 0; + priv->hw_unavailable--; - if (priv->open) { + if (priv->open && ! priv->hw_unavailable) { err = __orinoco_up(dev); if (err) printk(KERN_ERR "%s: Error %d restarting card\n", @@ -678,7 +654,7 @@ } - orinoco_unlock(priv, &flags); + spin_unlock_irqrestore(&priv->lock, flags); } } break; @@ -693,7 +669,7 @@ /* Can't be declared "const" or the whole __initdata section will * become const */ -static char version[] __initdata = "orinoco_cs.c 0.13b (David Gibson and others)"; +static char version[] __initdata = "orinoco_cs.c 0.13e (David Gibson and others)"; static int __init init_orinoco_cs(void) @@ -722,7 +698,6 @@ if (dev_list) DEBUG(0, "orinoco_cs: Removing leftover devices.\n"); while (dev_list != NULL) { - del_timer(&dev_list->release); if (dev_list->state & DEV_CONFIG) orinoco_cs_release((u_long) dev_list); orinoco_cs_detach(dev_list); --- linux-2.4.21/drivers/pcmcia/pxa/Makefile~ramses-pcmcia +++ linux-2.4.21/drivers/pcmcia/pxa/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_ARCH_PXA_IDP) += pxa_idp.o obj-$(CONFIG_ARCH_TRIZEPS2) += trizeps2.o obj-$(CONFIG_ARCH_PXA_CERF) += ../sa1100_cerf.o +obj-$(CONFIG_ARCH_RAMSES) += ramses.o obj-m := $(O_TARGET) --- linux-2.4.21/drivers/pcmcia/pxa/pxa.c~pxa-pcmcia +++ linux-2.4.21/drivers/pcmcia/pxa/pxa.c @@ -187,7 +187,6 @@ 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); @@ -240,6 +239,8 @@ pcmcia_low_level=&pxa_idp_pcmcia_ops; } else if( machine_is_pxa_cerf()){ pcmcia_low_level=&cerf_pcmcia_ops; + } else if( machine_is_ramses()){ + pcmcia_low_level=&ramses_pcmcia_ops; } else if (machine_is_trizeps2()){ #ifdef CONFIG_ARCH_TRIZEPS2 pcmcia_low_level=&trizeps2_pcmcia_ops; @@ -835,7 +836,7 @@ static int pxa_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map){ unsigned int clock, speed; - unsigned long mecr, start; + unsigned long start; DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); @@ -941,7 +942,7 @@ static int pxa_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map){ unsigned int clock, speed; - unsigned long mecr, start; + unsigned long start; DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); @@ -1076,7 +1077,6 @@ 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 ":"", --- linux-2.4.21/drivers/pcmcia/pxa/pxa.h~ramses-pcmcia +++ linux-2.4.21/drivers/pcmcia/pxa/pxa.h @@ -228,6 +228,7 @@ 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 ramses_pcmcia_ops; extern struct pcmcia_low_level trizeps2_pcmcia_ops; #endif /* !defined(_PCMCIA_PXA_H) */ --- /dev/null +++ linux-2.4.21/drivers/pcmcia/pxa/ramses.c @@ -0,0 +1,223 @@ +/* + * linux/drivers/pcmcia/pxa/ramses.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) 2003 M&N Logistik-Lösungen Online GmbH + * + * Platform specific routines for the Ramses, based on those + * first done for the Lubbock and PXA IDP. + * + */ + +#include +#include + +#include + +#include +#include +#include +#include + +static int +ramses_pcmcia_init(struct pcmcia_init *init) +{ + int return_val = 0; + + /* Set PCMCIA Socket 0 power to standby mode. + * RAMSES has dedicated CPLD pins for all this stuff :-) + */ + + /* both slots disabled, reset NOT active */ + RAMSES_CPLD_PCCARD_EN = PCC0_ENABLE | PCC1_ENABLE; + + RAMSES_CPLD_PCCARD_PWR = 0; //all power to both slots off + //GPDR(IRQ_TO_GPIO_2_80(CFCARD_CD_VALID)) &= ~GPIO_bit(IRQ_TO_GPIO_2_80(CFCARD_CD_VALID)); + set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(CFCARD_CD_VALID), GPIO_BOTH_EDGES); + //GPDR(IRQ_TO_GPIO_2_80(CFCARD_RDYINT)) &= ~GPIO_bit(IRQ_TO_GPIO_2_80(CFCARD_RDYINT)); + set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(CFCARD_RDYINT), GPIO_FALLING_EDGE); + + return_val += + request_irq(CFCARD_CD_VALID, init->handler, SA_INTERRUPT, + "CF-Card CD", NULL); + + if (return_val < 0) { + return -1; + } + + return 2; +} + +static int +ramses_pcmcia_shutdown(void) +{ + + free_irq(CFCARD_CD_VALID, NULL); + + RAMSES_CPLD_PCCARD_EN = 0x03; //disable slots + udelay(200); + RAMSES_CPLD_PCCARD_PWR = 0; //shut off all power + + return 0; +} + +static int +ramses_pcmcia_socket_state(struct pcmcia_state_array *state_array) +{ + unsigned long status; + int return_val = 1; + int i; + volatile unsigned long *stat_regs[2] = { + &RAMSES_CPLD_PCCARD0_STATUS, + &RAMSES_CPLD_PCCARD1_STATUS + }; + + if (state_array->size < 2) + return -1; + + memset(state_array->state, 0, + (state_array->size) * sizeof (struct pcmcia_state)); + + for (i = 1; 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; + } + + state_array->state[0].detect = 0; + state_array->state[0].ready = 0; + state_array->state[0].bvd1 = 0; + state_array->state[0].bvd2 = 0; + state_array->state[0].wrprot = 0; + state_array->state[0].vs_3v = 0; + state_array->state[0].vs_Xv = 0; + + return return_val; +} + +static int +ramses_pcmcia_get_irq_info(struct pcmcia_irq_info *info) +{ + switch (info->sock) { + case 0: + //info->irq = PCMCIA_S0_RDYINT; + //printk("//hs ramses_pcmcia_get_irq_info called for slot 0\n"); + break; + + case 1: + info->irq = CFCARD_RDYINT; + break; + + default: + return -1; + } + + return 0; +} + +static int +ramses_pcmcia_configure_socket(unsigned int sock, socket_state_t *state) +{ + /* The Ramses uses the Maxim MAX1602, with the following connections: + * + * Socket 0 (PCMCIA): + * MAX1602 PXA_IDP Register + * Pin Signal RAMSES_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 RAMSES_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) + * + */ + + if (sock == 1) { + + switch (state->Vcc) { + case 0: + RAMSES_CPLD_PCCARD_EN |= PCC1_ENABLE; // disable socket + udelay(200); + RAMSES_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3); + break; + + case 33: + RAMSES_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3); + RAMSES_CPLD_PCCARD_PWR |= PCC1_PWR3; + RAMSES_CPLD_PCCARD_EN &= ~PCC1_ENABLE; //turn it on + break; + + case 50: + RAMSES_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3); + RAMSES_CPLD_PCCARD_PWR |= PCC1_PWR2; + RAMSES_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: + RAMSES_CPLD_PCCARD_PWR &= ~(PCC1_PWR0 | PCC1_PWR1); + break; + + case 120: + RAMSES_CPLD_PCCARD_PWR &= ~(PCC1_PWR0 | PCC1_PWR1); + RAMSES_CPLD_PCCARD_PWR |= PCC1_PWR1; + break; + + default: + if (state->Vpp == state->Vcc) + RAMSES_CPLD_PCCARD_PWR = + (RAMSES_CPLD_PCCARD_PWR & + ~(PCC1_PWR0 | PCC1_PWR1)) | PCC1_PWR0; + else { + printk(KERN_ERR "%s(): unrecognized Vpp %u\n", + __FUNCTION__, state->Vpp); + return -1; + } + } + RAMSES_CPLD_PCCARD_EN = (state->flags & SS_RESET) ? (RAMSES_CPLD_PCCARD_EN | PCC1_RESET) + : (RAMSES_CPLD_PCCARD_EN & ~PCC1_RESET); + } + return 0; +} + +struct pcmcia_low_level ramses_pcmcia_ops = { + ramses_pcmcia_init, + ramses_pcmcia_shutdown, + ramses_pcmcia_socket_state, + ramses_pcmcia_get_irq_info, + ramses_pcmcia_configure_socket +}; --- linux-2.4.21/drivers/scsi/scsi.h~usb-sonycamera +++ linux-2.4.21/drivers/scsi/scsi.h @@ -610,6 +610,7 @@ unsigned remap:1; /* support remapping */ unsigned starved:1; /* unable to process commands because host busy */ + unsigned no_start_on_add:1; /* do not issue start on add */ // Flag to allow revalidate to succeed in sd_open int allow_revalidate; --- linux-2.4.21/drivers/scsi/scsi_scan.c~usb-sonycamera +++ linux-2.4.21/drivers/scsi/scsi_scan.c @@ -37,6 +37,8 @@ #define BLIST_ISDISK 0x100 /* Treat as (removable) disk */ #define BLIST_ISROM 0x200 /* Treat as (removable) CD-ROM */ #define BLIST_LARGELUN 0x400 /* LUNs larger than 7 despite reporting as SCSI 2 */ +#define BLIST_NOSTARTONADD 0x1000 /* do not do automatic start on add */ + static void print_inquiry(unsigned char *data); static int scan_scsis_single(unsigned int channel, unsigned int dev, @@ -110,9 +112,10 @@ {"HP", "C1750A", "3226", BLIST_NOLUN}, /* scanjet iic */ {"HP", "C1790A", "", BLIST_NOLUN}, /* scanjet iip */ {"HP", "C2500A", "", BLIST_NOLUN}, /* scanjet iicx */ - {"HP", "A6188A", "*", BLIST_SPARSELUN}, /* HP Va7100 Array */ - {"HP", "A6189A", "*", BLIST_SPARSELUN}, /* HP Va7400 Array */ - {"HP", "A6189B", "*", BLIST_SPARSELUN}, /* HP Va7410 Array */ + {"HP", "A6188A", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7100 Array */ + {"HP", "A6189A", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7400 Array */ + {"HP", "A6189B", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7110 Array */ + {"HP", "A6218A", "*", BLIST_SPARSELUN | BLIST_LARGELUN},/* HP Va7410 Array */ {"YAMAHA", "CDR100", "1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 * extra reset */ @@ -145,7 +148,7 @@ {"EMULEX", "MD21/S2 ESDI", "*", BLIST_SINGLELUN}, {"CANON", "IPUBJD", "*", BLIST_SPARSELUN}, {"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN}, - {"DEC","HSG80","*", BLIST_FORCELUN}, + {"DEC","HSG80","*", BLIST_FORCELUN | BLIST_NOSTARTONADD}, {"COMPAQ","LOGICAL VOLUME","*", BLIST_FORCELUN}, {"COMPAQ","CR3500","*", BLIST_FORCELUN}, {"NEC", "PD-1 ODX654P", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, @@ -173,7 +176,11 @@ {"HP", "NetRAID-4M", "*", BLIST_FORCELUN}, {"ADAPTEC", "AACRAID", "*", BLIST_FORCELUN}, {"ADAPTEC", "Adaptec 5400S", "*", BLIST_FORCELUN}, - {"COMPAQ", "MSA1000", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"APPLE", "Xserve", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"COMPAQ", "MSA1000", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_NOSTARTONADD}, + {"COMPAQ", "MSA1000 VOLUME", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_NOSTARTONADD}, + {"COMPAQ", "HSV110", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_NOSTARTONADD}, + {"HP", "HSV100", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_NOSTARTONADD}, {"HP", "C1557A", "*", BLIST_FORCELUN}, {"IBM", "AuSaV1S2", "*", BLIST_FORCELUN}, {"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, @@ -182,7 +189,8 @@ {"HITACHI", "DF500", "*", BLIST_SPARSELUN}, {"HITACHI", "DF600", "*", BLIST_SPARSELUN}, {"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HITACHI", "OPEN-", "*", BLIST_SPARSELUN}, /* HITACHI XP Arrays */ + {"HITACHI", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HITACHI XP Arrays */ + {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HITACHI 9960 */ {"WINSYS","FLASHDISK G6", "*", BLIST_SPARSELUN}, {"DotHill","SANnet RAID X300", "*", BLIST_SPARSELUN}, {"SUN", "T300", "*", BLIST_SPARSELUN}, @@ -194,6 +202,12 @@ {"SGI", "TP9400", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"SGI", "TP9500", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"MYLEX", "DACARMRB", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"PLATYPUS", "CX5", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"Raidtec", "FCR", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"HP", "C7200", "*", BLIST_SPARSELUN}, /* Medium Changer */ + {"SMSC", "USB 2 HS", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"XYRATEX", "RS", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"NEC", "iStorage", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN}, /* * Must be at end of list... @@ -209,10 +223,14 @@ static unsigned int max_scsi_luns = 1; #endif +static unsigned int scsi_allow_ghost_devices = 0; + #ifdef MODULE MODULE_PARM(max_scsi_luns, "i"); MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 2^32-1)"); +MODULE_PARM(scsi_allow_ghost_devices, "i"); +MODULE_PARM_DESC(scsi_allow_ghost_devices, "allow devices marked as being offline to be accessed anyway (0 = off, else allow ghosts on lun 0 through scsi_allow_ghost_devices - 1"); #else @@ -232,6 +250,21 @@ __setup("max_scsi_luns=", scsi_luns_setup); +static int __init scsi_allow_ghost_devices_setup(char *str) +{ + unsigned int tmp; + + if (get_option(&str, &tmp) == 1) { + scsi_allow_ghost_devices = tmp; + return 1; + } else { + printk("scsi_allow_ghost_devices_setup: usage scsi_allow_ghost_devices=n (0: off else\nallow ghost devices (ghost devices are devices that report themselves as\nbeing offline but which we allow access to anyway) on lun 0 through n - 1.\n"); + return 0; + } +} + +__setup("scsi_allow_ghost_devices=", scsi_allow_ghost_devices_setup); + #endif static void print_inquiry(unsigned char *data) @@ -608,6 +641,7 @@ } else { /* assume no peripheral if any other sort of error */ scsi_release_request(SRpnt); + scsi_release_commandblocks(SDpnt); return 0; } } @@ -618,6 +652,24 @@ */ /* + * If we are offline and we are on a LUN != 0, then skip this entry. + * If we are on a BLIST_FORCELUN device this will stop the scan at + * the first offline LUN (typically the correct thing to do). If + * we are on a BLIST_SPARSELUN device then this won't stop the scan, + * but it will keep us from having false entries in our device + * array. DL + * + * NOTE: Need to test this to make sure it doesn't cause problems + * with tape autoloaders, multidisc CD changers, and external + * RAID chassis that might use sparse luns or multiluns... DL + */ + if (lun != 0 && (scsi_result[0] >> 5) == 1) { + scsi_release_request(SRpnt); + scsi_release_commandblocks(SDpnt); + return 0; + } + + /* * Get any flags for this device. */ bflags = get_device_flags (scsi_result); @@ -655,8 +707,11 @@ SDpnt->removable = (0x80 & scsi_result[1]) >> 7; /* Use the peripheral qualifier field to determine online/offline */ - if (((scsi_result[0] >> 5) & 7) == 1) SDpnt->online = FALSE; - else SDpnt->online = TRUE; + if ((((scsi_result[0] >> 5) & 7) == 1) && + (lun >= scsi_allow_ghost_devices)) + SDpnt->online = FALSE; + else + SDpnt->online = TRUE; SDpnt->lockable = SDpnt->removable; SDpnt->changed = 0; SDpnt->access_count = 0; @@ -742,6 +797,13 @@ if ((bflags & BLIST_BORKEN) == 0) SDpnt->borken = 0; + /* + * Some devices may not want to have a start command automatically + * issued when a device is added. + */ + if (bflags & BLIST_NOSTARTONADD) + SDpnt->no_start_on_add = 1; + /* * If we want to only allow I/O to one of the luns attached to this device * at a time, then we set this flag. @@ -857,11 +919,26 @@ * I think we need REPORT LUNS in future to avoid scanning * of unused LUNs. But, that is another item. */ + /* if (*max_dev_lun < shpnt->max_lun) *max_dev_lun = shpnt->max_lun; else if ((max_scsi_luns >> 1) >= *max_dev_lun) *max_dev_lun += shpnt->max_lun; else *max_dev_lun = max_scsi_luns; + */ + /* + * Blech...the above code is broken. When you have a device + * that is present, and it is a FORCELUN device, then we + * need to scan *all* the luns on that device. Besides, + * skipping the scanning of LUNs is a false optimization. + * Scanning for a LUN on a present device is a very fast + * operation, it's scanning for devices that don't exist that + * is expensive and slow (although if you are truly scanning + * through MAX_SCSI_LUNS devices that would be bad, I hope + * all of the controllers out there set a reasonable value + * in shpnt->max_lun). DL + */ + *max_dev_lun = shpnt->max_lun; return 1; } /* --- linux-2.4.21/drivers/scsi/sd.c~usb-sonycamera +++ linux-2.4.21/drivers/scsi/sd.c @@ -775,7 +775,8 @@ char nbuff[6]; unsigned char *buffer; unsigned long spintime_value = 0; - int the_result, retries, spintime; + int retries, spintime; + unsigned int the_result; int sector_size; Scsi_Request *SRpnt; @@ -817,7 +818,7 @@ do { retries = 0; - while (retries < 3) { + do { cmd[0] = TEST_UNIT_READY; cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ? ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0; @@ -832,10 +833,10 @@ the_result = SRpnt->sr_result; retries++; - if (the_result == 0 - || SRpnt->sr_sense_buffer[2] != UNIT_ATTENTION) - break; - } + } while (retries < 3 + && (the_result !=0 + || ((driver_byte(the_result) & DRIVER_SENSE) + && SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION))); /* * If the drive has indicated to us that it doesn't have @@ -853,24 +854,47 @@ break; } + if ((driver_byte(the_result) & DRIVER_SENSE) == 0) { + /* no sense, TUR either succeeded or failed + * with a status error */ + if(!spintime && the_result != 0) + printk(KERN_NOTICE "%s: Unit Not Ready, error = 0x%x\n", nbuff, the_result); + break; + } + + /* + * The device does not want the automatic start to be issued. + */ + if (rscsi_disks[i].device->no_start_on_add) { + break; + } + + /* + * If manual intervention is required, or this is an + * absent USB storage device, a spinup is meaningless. + */ + if (SRpnt->sr_sense_buffer[2] == NOT_READY && + SRpnt->sr_sense_buffer[12] == 4 /* not ready */ && + SRpnt->sr_sense_buffer[13] == 3) { + break; /* manual intervention required */ /* Look for non-removable devices that return NOT_READY. * Issue command to spin up drive for these cases. */ - if (the_result && !rscsi_disks[i].device->removable && - SRpnt->sr_sense_buffer[2] == NOT_READY) { + } else if (the_result && !rscsi_disks[i].device->removable && + SRpnt->sr_sense_buffer[2] == NOT_READY) { unsigned long time1; if (!spintime) { printk("%s: Spinning up disk...", nbuff); cmd[0] = START_STOP; cmd[1] = (rscsi_disks[i].device->scsi_level <= SCSI_2) ? - ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0; - cmd[1] |= 1; /* Return immediately */ + ((rscsi_disks[i].device->lun << 5) & 0xe0) : 0; + cmd[1] |= 1; /* Return immediately */ memset((void *) &cmd[2], 0, 8); - cmd[4] = 1; /* Start spin cycle */ + cmd[4] = 1; /* Start spin cycle */ SRpnt->sr_cmd_len = 0; SRpnt->sr_sense_buffer[0] = 0; SRpnt->sr_sense_buffer[2] = 0; - SRpnt->sr_data_direction = SCSI_DATA_READ; + SRpnt->sr_data_direction = SCSI_DATA_NONE; scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer, 0/*512*/, SD_TIMEOUT, MAX_RETRIES); spintime_value = jiffies; @@ -883,6 +907,14 @@ time1 = schedule_timeout(time1); } while(time1); printk("."); + } else { + /* we don't understand the sense code, so it's + * probably pointless to loop */ + if(!spintime) { + printk(KERN_NOTICE "%s: Unit Not Ready, sense:\n", nbuff); + print_req_sense("", SRpnt); + } + break; } } while (the_result && spintime && time_after(spintime_value + 100 * HZ, jiffies)); --- linux-2.4.21/drivers/sound/ac97_codec.c~ucb1x00 +++ linux-2.4.21/drivers/sound/ac97_codec.c @@ -547,6 +547,12 @@ val = SOUND_CAP_EXCL_INPUT; break; + case SOUND_MIXER_AC97: + if (get_user(val, (int *)arg)) + return -EFAULT; + val = codec->codec_read(codec, val); + return put_user(val, (int *)arg); + default: /* read a specific mixer */ i = _IOC_NR(cmd); @@ -575,6 +581,11 @@ codec->recmask_io(codec, 0, val); return 0; + + case SOUND_MIXER_AC97: + codec->codec_write(codec, val >> 16 & 0xffff, val & 0xffff); + return 0; + default: /* write a specific mixer */ i = _IOC_NR(cmd); --- linux-2.4.21/drivers/sound/pxa-ac97.c~pxa-ac97 +++ linux-2.4.21/drivers/sound/pxa-ac97.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -164,6 +165,11 @@ //pxa_ac97_write(&pxa_ac97_codec, 0x6a, 0x1ff7); pxa_ac97_write(&pxa_ac97_codec, 0x6a, 0x0050); pxa_ac97_write(&pxa_ac97_codec, 0x6c, 0x0030); +#if CONFIG_ARCH_RAMSES + pxa_ac97_codec.supported_mixers = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN; + pxa_ac97_codec.stereo_mixers = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN; + pxa_ac97_codec.record_sources = SOUND_MASK_MIC | SOUND_MASK_LINE; +#endif } pxa_ac97_refcount++; @@ -198,7 +204,7 @@ static int mixer_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int ret, val; + int ret; ret = pxa_ac97_codec.mixer_ioctl(&pxa_ac97_codec, cmd, arg); if (ret) @@ -282,6 +288,7 @@ /* fall through */ case SOUND_PCM_READ_RATE: + val = 0; if (file->f_mode & FMODE_READ) val = codec_adc_rate; if (file->f_mode & FMODE_WRITE) @@ -342,6 +349,44 @@ }; +#ifdef CONFIG_PM + +static int pxa_ac97_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + down(&pxa_ac97_mutex); + + switch (rqst) { + case PM_SUSPEND: + // TODO: set to low-power state? + GCR = GCR_ACLINK_OFF; + CKEN &= ~CKEN2_AC97; + break; + + case PM_RESUME: + CKEN |= CKEN2_AC97; + + GCR = 0; + udelay(10); + GCR = GCR_COLD_RST|GCR_CDONE_IE|GCR_SDONE_IE; + while (!(GSR & GSR_PCR)) { + schedule(); + } + + // 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, 0x0050); + pxa_ac97_write(&pxa_ac97_codec, 0x6c, 0x0030); + break; + } + + up(&pxa_ac97_mutex); + + return 0; +} + +#endif + + static int __init pxa_ac97_init(void) { int ret; @@ -354,11 +399,18 @@ ac97_audio_state.dev_dsp = register_sound_dsp(&ac97_audio_fops, -1); pxa_ac97_codec.dev_mixer = register_sound_mixer(&mixer_fops, -1); +#ifdef PM_DEBUG + ac97_audio_state.pmdev = pm_register(PM_SYS_UNKNOWN, 0x71783937, pxa_ac97_pm_callback, "pxa-ac97"); +#else + ac97_audio_state.pmdev = pm_register(PM_SYS_UNKNOWN, 0x71783937, pxa_ac97_pm_callback); +#endif + return 0; } static void __exit pxa_ac97_exit(void) { + pm_unregister(ac97_audio_state.pmdev); unregister_sound_dsp(ac97_audio_state.dev_dsp); unregister_sound_mixer(pxa_ac97_codec.dev_mixer); pxa_ac97_put(); --- linux-2.4.21/drivers/sound/pxa-audio.h~pm +++ linux-2.4.21/drivers/sound/pxa-audio.h @@ -47,6 +47,9 @@ 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 */ +#ifdef CONFIG_PM + struct pm_dev *pmdev; /* Power management */ +#endif } audio_state_t; extern int pxa_audio_attach(struct inode *inode, struct file *file, --- linux-2.4.21/drivers/usb/Config.in~pxa-usb +++ linux-2.4.21/drivers/usb/Config.in @@ -5,7 +5,7 @@ comment 'USB support' # 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 +if [ "$CONFIG_PCI" = "y" -o "$CONFIG_SA1111" = "y" -o "$CONFIG_ARCH_AT91RM9200" = "y" -o "$CONFIG_ARCH_PXA" = "y" ]; then tristate 'Support for USB' CONFIG_USB else define_bool CONFIG_USB n --- linux-2.4.21/drivers/usb/Makefile~usb-sl811 +++ linux-2.4.21/drivers/usb/Makefile @@ -80,6 +80,9 @@ ifeq ($(CONFIG_USB_OHCI),y) obj-y += host/usb-ohci.o host/usb-ohci-sa1111.o endif + +subdir-$(CONFIG_USB_SL811HS_ALT)+= host + subdir-$(CONFIG_USB_OHCI_AT91) += host ifeq ($(CONFIG_USB_OHCI_AT91),y) obj-y += host/usb-ohci.o --- linux-2.4.21/drivers/usb/hcd.c~ramses-usb +++ linux-2.4.21/drivers/usb/hcd.c @@ -662,7 +662,9 @@ pci_set_drvdata(dev, hcd); hcd->driver = driver; hcd->description = driver->description; +#ifdef TODO hcd->pdev = dev; +#endif printk (KERN_INFO "%s %s: %s\n", hcd->description, dev->slot_name, dev->name); @@ -1201,6 +1203,7 @@ return status; // NOTE: 2.5 does this if !URB_NO_DMA_MAP transfer flag +#ifdef TODO if (usb_pipecontrol (urb->pipe)) urb->setup_dma = pci_map_single ( #ifdef CONFIG_PCI @@ -1223,7 +1226,7 @@ usb_pipein (urb->pipe) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); - +#endif if (urb->dev == hcd->bus->root_hub) status = rh_urb_enqueue (hcd, urb); else @@ -1488,6 +1491,7 @@ // hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev) // NOTE: 2.5 does this if !URB_NO_DMA_MAP transfer flag +#ifdef TODO if (usb_pipecontrol (urb->pipe)) pci_unmap_single ( #ifdef CONFIG_PCI @@ -1510,6 +1514,7 @@ usb_pipein (urb->pipe) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); +#endif /* pass ownership to the completion handler */ urb->complete (urb); --- linux-2.4.21/drivers/usb/host/Config.in~usb-sl811 +++ linux-2.4.21/drivers/usb/host/Config.in @@ -13,6 +13,9 @@ 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" ]; then + dep_tristate ' SL811HS Alternate (x86, StrongARM, isosynchronous mode)' CONFIG_USB_SL811HS_ALT $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.21/drivers/usb/host/Makefile~usb-sl811 +++ linux-2.4.21/drivers/usb/host/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_USB_UHCI) += usb-uhci.o obj-$(CONFIG_USB_OHCI) += usb-ohci.o usb-ohci-pci.o obj-$(CONFIG_USB_OHCI_SA1111) += usb-ohci.o usb-ohci-sa1111.o +obj-$(CONFIG_USB_SL811HS_ALT) += sl811.o obj-$(CONFIG_USB_OHCI_AT91) += usb-ohci.o # Extract lists of the multi-part drivers. --- /dev/null +++ linux-2.4.21/drivers/usb/host/sl811.c @@ -0,0 +1,2782 @@ +/* + * SL811 Host Controller Interface driver for USB. + * + * Copyright (c) 2003/06, Courage Co., Ltd. + * + * Based on: + * 1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap, + * Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, + * Adam Richter, Gregory P. Smith; + * 2.Original SL811 driver (hc_sl811.o) by Pei Liu + * 3.Rewrited as sl811.o by Yin Aihua + * + * It's now support isochornous mode and more effective than hc_sl811.o + * Support x86 architecture now. + * + * 19.09.2003 (05.06.2003) HNE + * sl811_alloc_hc: Set "bus->bus_name" at init. + * sl811_reg_test (hc_reset,regTest): + * Stop output at first failed pattern. + * Down-Grade for Kernel 2.4.20 and from 2.4.22 + * Split hardware dependency into files sl811-x86.h and sl811-arm.h. + * + * 22.09.2003 HNE + * sl811_found_hc: First patterntest, than interrupt enable. + * Do nothing, if patterntest failed. Release IO if failed. + * Stop Interrupts first, than remove handle. (Old blocked Shared IRQ) + * Alternate IO-Base for second Controller (CF/USB1). + * + * 24.09.2003 HNE + * Remove all arm specific source (moved into include/asm/sl811-hw.h). + * + * 03.10.2003 HNE + * Low level only for port IO into hardware-include. + * + * To do: + * 1.Modify the timeout part, it's some messy + * 2.Use usb-a and usb-b set in Ping-Pong mode + * o Floppy do not work. + * o driver crash, if io region can't register + * o Only tested as module. Compiled-in version not tested! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../hcd.h" +#include "../hub.h" +#include "sl811.h" + +#define DRIVER_VERSION "v0.30" +#define MODNAME "SL811" +#define DRIVER_AUTHOR "Yin Aihua , Henry Nestler " +#define DRIVER_DESC "Sl811 USB Host Controller Alternate Driver" + +static LIST_HEAD(sl811_hcd_list); + +/* + * 0: normal prompt and information + * 1: error should not occur in normal + * 2: error maybe occur in normal + * 3: useful and detail debug information + * 4: function level enter and level inforamtion + * 5: endless information will output because of timer function or interrupt + */ +static int debug = 0; +MODULE_PARM(debug,"i"); +MODULE_PARM_DESC(debug,"debug level"); + +#include /* Include hardware and board depens */ + +static void sl811_rh_int_timer_do(unsigned long ptr); +static void sl811_transfer_done(struct sl811_hc *hc, int sof); + +/* + * Read a byte of data from the SL811H/SL11H + */ +static __u8 inline sl811_read(struct sl811_hc *hc, __u8 offset) +{ + sl811_write_index (hc, offset); + return (sl811_read_data (hc)); +} + +/* + * Write a byte of data to the SL811H/SL11H + */ +static void inline sl811_write(struct sl811_hc *hc, __u8 offset, __u8 data) +{ + sl811_write_index_data (hc, offset, data); +} + +/* + * Read consecutive bytes of data from the SL811H/SL11H buffer + */ +static void inline sl811_read_buf(struct sl811_hc *hc, __u8 offset, __u8 *buf, __u8 size) +{ + sl811_write_index (hc, offset); + while (size--) { + *buf++ = sl811_read_data(hc); + } +} + +/* + * Write consecutive bytes of data to the SL811H/SL11H buffer + */ +static void inline sl811_write_buf(struct sl811_hc *hc, __u8 offset, __u8 *buf, __u8 size) +{ + sl811_write_index (hc, offset); + while (size--) { + sl811_write_data (hc, *buf); + buf++; + } +} + +/* + * This routine test the Read/Write functionality of SL811HS registers + */ +static int sl811_reg_test(struct sl811_hc *hc) +{ + int i, data, result = 0; + __u8 buf[256]; + + for (i = 0x10; i < 256; i++) { + /* save the original buffer */ + buf[i] = sl811_read(hc, i); + + /* Write the new data to the buffer */ + sl811_write(hc, i, ~i); + } + + /* compare the written data */ + for (i = 0x10; i < 256; i++) { + data = sl811_read(hc, i); + if (data != (__u8) ~i) { + PDEBUG(1, "reg %02x expected %02x got %02x", i, (__u8) ~i, data); + result = -1; + + /* If no Debug, show only first failed Address */ + if (!debug) + break; + } + } + + /* restore the data */ + for (i = 0x10; i < 256; i++) + sl811_write(hc, i, buf[i]); + + return result; +} + +/* + * Display all SL811HS register values + */ +#if 0 /* unused (hne) */ +static void sl811_reg_show(struct sl811_hc *hc) +{ + int i; + + for (i = 0; i < 256; i++) + PDEBUG(4, "offset %d: 0x%x", i, sl811_read(hc, i)); +} +#endif + +/* + * This function enables SL811HS interrupts + */ +static void sl811_enable_interrupt(struct sl811_hc *hc) +{ + PDEBUG(4, "enter"); + sl811_write(hc, SL811_INTR, SL811_INTR_DONE_A | SL811_INTR_SOF | SL811_INTR_INSRMV); +} + +/* + * This function disables SL811HS interrupts + */ +static void sl811_disable_interrupt(struct sl811_hc *hc) +{ + PDEBUG(4, "enter"); + // Disable all other interrupt except for insert/remove. + sl811_write(hc, SL811_INTR, SL811_INTR_INSRMV); +} + +/* + * SL811 Virtual Root Hub + */ + +/* Device descriptor */ +static __u8 sl811_rh_dev_des[] = +{ + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x10, /* __u16 bcdUSB; v1.1 */ + 0x01, + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x00, /* __u8 bDeviceProtocol; */ + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + 0x00, /* __u16 idVendor; */ + 0x00, + 0x00, /* __u16 idProduct; */ + 0x00, + 0x00, /* __u16 bcdDevice; */ + 0x00, + 0x00, /* __u8 iManufacturer; */ + 0x02, /* __u8 iProduct; */ + 0x01, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + +/* Configuration descriptor */ +static __u8 sl811_rh_config_des[] = +{ + 0x09, /* __u8 bLength; */ + 0x02, /* __u8 bDescriptorType; Configuration */ + 0x19, /* __u16 wTotalLength; */ + 0x00, + 0x01, /* __u8 bNumInterfaces; */ + 0x01, /* __u8 bConfigurationValue; */ + 0x00, /* __u8 iConfiguration; */ + 0x40, /* __u8 bmAttributes; + Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, + 4..0: resvd */ + 0x00, /* __u8 MaxPower; */ + + /* interface */ + 0x09, /* __u8 if_bLength; */ + 0x04, /* __u8 if_bDescriptorType; Interface */ + 0x00, /* __u8 if_bInterfaceNumber; */ + 0x00, /* __u8 if_bAlternateSetting; */ + 0x01, /* __u8 if_bNumEndpoints; */ + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* __u8 if_bInterfaceSubClass; */ + 0x00, /* __u8 if_bInterfaceProtocol; */ + 0x00, /* __u8 if_iInterface; */ + + /* endpoint */ + 0x07, /* __u8 ep_bLength; */ + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x08, /* __u16 ep_wMaxPacketSize; */ + 0x00, + 0xff /* __u8 ep_bInterval; 255 ms */ +}; + +/* root hub class descriptor*/ +static __u8 sl811_rh_hub_des[] = +{ + 0x09, /* __u8 bLength; */ + 0x29, /* __u8 bDescriptorType; Hub-descriptor */ + 0x01, /* __u8 bNbrPorts; */ + 0x00, /* __u16 wHubCharacteristics; */ + 0x00, + 0x50, /* __u8 bPwrOn2pwrGood; 2ms */ + 0x00, /* __u8 bHubContrCurrent; 0 mA */ + 0xfc, /* __u8 DeviceRemovable; *** 7 Ports max *** */ + 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */ +}; + +/* + * This function examine the port change in the virtual root hub. HUB INTERRUPT ENDPOINT. + */ +static int sl811_rh_send_irq(struct sl811_hc *hc, __u8 *rh_change, int rh_len) +{ + __u8 data = 0; + + PDEBUG(5, "enter"); + + /* + * Right now, It is assume the power is good and no changes and only one port. + */ + if (hc->rh_status.wPortChange & (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) { + data = 1<<1; + *(__u8 *)rh_change = data; + return 1; + } else + return 0; +} + +/* + * This function creates a timer that act as interrupt pipe in the virtual hub. + * + * Note: The virtual root hub's interrupt pipe are polled by the timer + * every "interval" ms + */ +static void sl811_rh_init_int_timer(struct urb * urb) +{ + struct sl811_hc *hc = urb->dev->bus->hcpriv; + hc->rh.interval = urb->interval; + + init_timer(&hc->rh.rh_int_timer); + hc->rh.rh_int_timer.function = sl811_rh_int_timer_do; + hc->rh.rh_int_timer.data = (unsigned long)urb; + hc->rh.rh_int_timer.expires = jiffies + + (HZ * (urb->interval < 30? 30: urb->interval)) / 1000; + add_timer (&hc->rh.rh_int_timer); +} + +/* + * This function is called when the timer expires. It gets the the port + * change data and pass along to the upper protocol. + */ +static void sl811_rh_int_timer_do(unsigned long ptr) +{ + int len; + struct urb *urb = (struct urb *)ptr; + struct sl811_hc *hc = urb->dev->bus->hcpriv; + PDEBUG (5, "enter"); + + if(hc->rh.send) { + len = sl811_rh_send_irq(hc, urb->transfer_buffer, + urb->transfer_buffer_length); + if (len > 0) { + urb->actual_length = len; + if (urb->complete) + urb->complete(urb); + } + } + +#ifdef SL811_TIMEOUT + +{ + struct list_head *head, *tmp; + struct sl811_urb_priv *urbp; + struct urb *u; + int i; + static int timeout_count = 0; + +// check time out every second + if (++timeout_count > 4) { + int max_scan = hc->active_urbs; + timeout_count = 0; + for (i = 0; i < 6; ++i) { + head = &hc->urb_list[i]; + tmp = head->next; + while (tmp != head && max_scan--) { + u = list_entry(tmp, struct urb, urb_list); + urbp = (struct sl811_urb_priv *)u->hcpriv; + tmp = tmp->next; + // Check if the URB timed out + if (u->timeout && time_after_eq(jiffies, urbp->inserttime + u->timeout)) { + PDEBUG(3, "urb = %p time out, we kill it", urb); + u->transfer_flags |= USB_TIMEOUT_KILLED; + } + } + } + } +} + +#endif + // re-activate the timer + sl811_rh_init_int_timer(urb); +} + +/* helper macro */ +#define OK(x) len = (x); break + +/* + * This function handles all USB request to the the virtual root hub + */ +static int sl811_rh_submit_urb(struct urb *urb) +{ + struct usb_device *usb_dev = urb->dev; + struct sl811_hc *hc = usb_dev->bus->hcpriv; + struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *)urb->setup_packet; + void *data = urb->transfer_buffer; + int buf_len = urb->transfer_buffer_length; + unsigned int pipe = urb->pipe; + __u8 data_buf[16]; + __u8 *bufp = data_buf; + int len = 0; + int status = 0; + + __u16 bmRType_bReq; + __u16 wValue; + __u16 wIndex; + __u16 wLength; + + if (usb_pipeint(pipe)) { + hc->rh.urb = urb; + hc->rh.send = 1; + hc->rh.interval = urb->interval; + sl811_rh_init_int_timer(urb); + urb->status = 0; + + return 0; + } + + bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8); + wValue = le16_to_cpu (cmd->wValue); + wIndex = le16_to_cpu (cmd->wIndex); + wLength = le16_to_cpu (cmd->wLength); + + PDEBUG(5, "submit rh urb, req = %d(%x) len=%d", bmRType_bReq, bmRType_bReq, wLength); + + /* Request Destination: + without flags: Device, + USB_RECIP_INTERFACE: interface, + USB_RECIP_ENDPOINT: endpoint, + USB_TYPE_CLASS means HUB here, + USB_RECIP_OTHER | USB_TYPE_CLASS almost ever means HUB_PORT here + */ + switch (bmRType_bReq) { + case RH_GET_STATUS: + *(__u16 *)bufp = cpu_to_le16(1); + OK(2); + + case RH_GET_STATUS | USB_RECIP_INTERFACE: + *(__u16 *)bufp = cpu_to_le16(0); + OK(2); + + case RH_GET_STATUS | USB_RECIP_ENDPOINT: + *(__u16 *)bufp = cpu_to_le16(0); + OK(2); + + case RH_GET_STATUS | USB_TYPE_CLASS: + *(__u32 *)bufp = cpu_to_le32(0); + OK(4); + + case RH_GET_STATUS | USB_RECIP_OTHER | USB_TYPE_CLASS: + *(__u32 *)bufp = cpu_to_le32(hc->rh_status.wPortChange<<16 | hc->rh_status.wPortStatus); + OK(4); + + case RH_CLEAR_FEATURE | USB_RECIP_ENDPOINT: + switch (wValue) { + case 1: + OK(0); + } + break; + + case RH_CLEAR_FEATURE | USB_TYPE_CLASS: + switch (wValue) { + case C_HUB_LOCAL_POWER: + OK(0); + + case C_HUB_OVER_CURRENT: + OK(0); + } + break; + + case RH_CLEAR_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS: + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + hc->rh_status.wPortStatus &= ~USB_PORT_STAT_ENABLE; + OK(0); + + case USB_PORT_FEAT_SUSPEND: + hc->rh_status.wPortStatus &= ~USB_PORT_STAT_SUSPEND; + OK(0); + + case USB_PORT_FEAT_POWER: + hc->rh_status.wPortStatus &= ~USB_PORT_STAT_POWER; + OK(0); + + case USB_PORT_FEAT_C_CONNECTION: + hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_CONNECTION; + OK(0); + + case USB_PORT_FEAT_C_ENABLE: + hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_ENABLE; + OK(0); + + case USB_PORT_FEAT_C_SUSPEND: + hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_SUSPEND; + OK(0); + + case USB_PORT_FEAT_C_OVER_CURRENT: + hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_OVERCURRENT; + OK(0); + + case USB_PORT_FEAT_C_RESET: + hc->rh_status.wPortChange &= ~USB_PORT_STAT_C_RESET; + OK(0); + } + break; + + case RH_SET_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS: + switch (wValue) { + case USB_PORT_FEAT_SUSPEND: + hc->rh_status.wPortStatus |= USB_PORT_STAT_SUSPEND; + OK(0); + + case USB_PORT_FEAT_RESET: + hc->rh_status.wPortStatus |= USB_PORT_STAT_RESET; + hc->rh_status.wPortChange = 0; + hc->rh_status.wPortChange |= USB_PORT_STAT_C_RESET; + hc->rh_status.wPortStatus &= ~USB_PORT_STAT_RESET; + hc->rh_status.wPortStatus |= USB_PORT_STAT_ENABLE; + OK(0); + + case USB_PORT_FEAT_POWER: + hc->rh_status.wPortStatus |= USB_PORT_STAT_POWER; + OK(0); + + case USB_PORT_FEAT_ENABLE: + hc->rh_status.wPortStatus |= USB_PORT_STAT_ENABLE; + OK(0); + } + break; + + case RH_SET_ADDRESS: + hc->rh.devnum = wValue; + OK(0); + + case RH_GET_DESCRIPTOR: + switch ((wValue & 0xff00) >> 8) { + case USB_DT_DEVICE: + len = sizeof(sl811_rh_dev_des); + bufp = sl811_rh_dev_des; + OK(len); + + case USB_DT_CONFIG: + len = sizeof(sl811_rh_config_des); + bufp = sl811_rh_config_des; + OK(len); + + case USB_DT_STRING: + len = usb_root_hub_string(wValue & 0xff, (int)(long)0, "SL811HS", data, wLength); + if (len > 0) { + bufp = data; + OK(len); + } + + default: + status = -EPIPE; + } + break; + + case RH_GET_DESCRIPTOR | USB_TYPE_CLASS: + len = sizeof(sl811_rh_hub_des); + bufp = sl811_rh_hub_des; + OK(len); + + case RH_GET_CONFIGURATION: + bufp[0] = 0x01; + OK(1); + + case RH_SET_CONFIGURATION: + OK(0); + + default: + PDEBUG(1, "unsupported root hub command"); + status = -EPIPE; + } + + len = min(len, buf_len); + if (data != bufp) + memcpy(data, bufp, len); + urb->actual_length = len; + urb->status = status; + + PDEBUG(5, "len = %d, status = %d", len, status); + + urb->hcpriv = NULL; + urb->dev = NULL; + if (urb->complete) + urb->complete(urb); + + return 0; +} + +/* + * This function unlinks the URB + */ +static int sl811_rh_unlink_urb(struct urb *urb) +{ + struct sl811_hc *hc = urb->dev->bus->hcpriv; + + PDEBUG(5, "enter"); + + if (hc->rh.urb == urb) { + hc->rh.send = 0; + del_timer(&hc->rh.rh_int_timer); + hc->rh.urb = NULL; + urb->hcpriv = NULL; + usb_dec_dev_use(urb->dev); + urb->dev = NULL; + if (urb->transfer_flags & USB_ASYNC_UNLINK) { + urb->status = -ECONNRESET; + if (urb->complete) + urb->complete(urb); + } else + urb->status = -ENOENT; + } + + return 0; +} + +/* + * This function connect the virtual root hub to the USB stack + */ +static int sl811_connect_rh(struct sl811_hc * hc) +{ + struct usb_device *usb_dev; + + hc->rh.devnum = 0; + usb_dev = usb_alloc_dev(NULL, hc->bus); + if (!usb_dev) + return -ENOMEM; + + hc->bus->root_hub = usb_dev; + usb_connect(usb_dev); + + if (usb_new_device(usb_dev)) { + usb_free_dev(usb_dev); + return -ENODEV; + } + + PDEBUG(5, "leave success"); + + return 0; +} + +/* + * This function allocates private data space for the usb device + */ +static int sl811_alloc_dev_priv(struct usb_device *usb_dev) +{ + return 0; +} + +/* + * This function de-allocates private data space for the usb devic + */ +static int sl811_free_dev_priv (struct usb_device *usb_dev) +{ + return 0; +} + +/* + * This function allocates private data space for the urb + */ +static struct sl811_urb_priv* sl811_alloc_urb_priv(struct urb *urb) +{ + struct sl811_urb_priv *urbp; + + urbp = kmalloc(sizeof(*urbp), GFP_KERNEL); + if (!urbp) + return NULL; + + memset(urbp, 0, sizeof(*urbp)); + + INIT_LIST_HEAD(&urbp->td_list); + + urbp->urb = urb; + urb->hcpriv = urbp; + + return urbp; +} + +/* + * This function free private data space for the urb + */ +static void sl811_free_urb_priv(struct urb *urb) +{ + struct sl811_urb_priv *urbp = urb->hcpriv; + struct sl811_td *td; + struct list_head *head, *tmp; + + if (!urbp) + return ; + + head = &urbp->td_list; + tmp = head->next; + + while (tmp != head) { + td = list_entry(tmp, struct sl811_td, td_list); + tmp = tmp->next; + kfree(td); + } + + kfree(urbp); + urb->hcpriv = NULL; + + return ; +} + +/* + * This function calculate the bus time need by this td. + * Fix me! Can this use usb_calc_bus_time()? + */ +static void sl811_calc_td_time(struct sl811_td *td) +{ +#if 1 + int time; + int len = td->len; + struct sl811_hc *hc = td->urb->dev->bus->hcpriv; + + if (hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) + time = 8*8*len + 1024; + else { + if (td->ctrl & SL811_USB_CTRL_PREAMBLE) + time = 8*8*len + 2048; + else + time = 8*len + 256; + } + + time += 2*10 * len; + + td->bustime = time; + +#else + + unsigned long tmp; + int time; + int low_speed = usb_pipeslow(td->urb->pipe); + int input_dir = usb_pipein(td->urb->pipe); + int bytecount = td->len; + int isoc = usb_pipeisoc(td->urb->pipe); + + if (low_speed) { /* no isoc. here */ + if (input_dir) { + tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L; + time = (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); + } else { + tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L; + time = (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); + } + } else if (!isoc){ /* for full-speed: */ + tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; + time = (9107L + BW_HOST_DELAY + tmp); + } else { /* for isoc: */ + tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; + time = (((input_dir) ? 7268L : 6265L) + BW_HOST_DELAY + tmp); + } + + td->bustime = time / 84; + +#endif +} + +/* + * This function calculate the remainder bus time in current frame. + */ +static inline int sl811_calc_bus_remainder(struct sl811_hc *hc) +{ + return (sl811_read(hc, SL811_SOFCNTDIV) * 64); +} + +/* + * This function allocates td for the urb + */ +static struct sl811_td* sl811_alloc_td(struct urb *urb) +{ + struct sl811_urb_priv *urbp = urb->hcpriv; + struct sl811_td *td; + + td = kmalloc(sizeof (*td), GFP_KERNEL); + if (!td) + return NULL; + + memset(td, 0, sizeof(*td)); + + INIT_LIST_HEAD(&td->td_list); + + td->urb = urb; + list_add_tail(&td->td_list, &urbp->td_list); + + return td; +} + +/* + * Fill the td. + */ +static inline void sl811_fill_td(struct sl811_td *td, __u8 ctrl, __u8 addr, __u8 len, __u8 pidep, __u8 dev, __u8 *buf) +{ + td->ctrl = ctrl; + td->addr = addr; + td->len = len; + td->pidep = pidep; + td->dev = dev; + td->buf = buf; + td->left = len; + td->errcnt = 3; +} + +/* + * Fill the td. + */ +static inline void sl811_reset_td(struct sl811_td *td) +{ + td->status = 0; + td->left = td->len; + td->done = 0; + td->errcnt = 3; + td->nakcnt = 0; + td->td_status = 0; +} + +static void sl811_print_td(int level, struct sl811_td *td) +{ + PDEBUG(level, "td = %p, ctrl = %x, addr = %x, len = %x, pidep = %x\n " + "dev = %x, status = %x, left = %x, errcnt = %x, done = %x\n " + "buf = %p, bustime = %d, td_status = %d\n", + td, td->ctrl, td->addr, td->len, td->pidep, + td->dev, td->status, td->left, td->errcnt, td->done, + td->buf, td->bustime, td->td_status); +} + +/* + * Isochronous transfers + */ +static int sl811_submit_isochronous(struct urb *urb) +{ + __u8 dev = usb_pipedevice(urb->pipe); + __u8 pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe)); + __u8 ctrl = 0; + struct sl811_urb_priv *urbp = urb->hcpriv; + struct sl811_td *td = NULL; + int i; + + PDEBUG(4, "enter, urb = %p, urbp = %p", urb, urbp); + + /* Can't have low speed bulk transfers */ + if (usb_pipeslow(urb->pipe)) { + PDEBUG(1, "error, urb = %p, low speed device", urb); + return -EINVAL; + } + + if (usb_pipeout(urb->pipe)) + ctrl |= SL811_USB_CTRL_DIR_OUT; + + ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE | SL811_USB_CTRL_ISO; + + for (i = 0; i < urb->number_of_packets; i++) { + urb->iso_frame_desc[i].actual_length = 0; + urb->iso_frame_desc[i].status = -EXDEV; + + td = sl811_alloc_td(urb); + if (!td) + return -ENOMEM; + + sl811_fill_td(td, ctrl, SL811_DATA_START, + urb->iso_frame_desc[i].length, + pidep, dev, + urb->transfer_buffer + urb->iso_frame_desc[i].offset); + sl811_calc_td_time(td); + if (urbp->cur_td == NULL) + urbp->cur_td = urbp->first_td = td; + } + + urbp->last_td = td; + + PDEBUG(4, "leave success"); + +/* +// for debug + { + struct list_head *head, *tmp; + struct sl811_td *td; + int i = 0; + head = &urbp->td_list; + tmp = head->next; + + if (list_empty(&urbp->td_list)) { + PDEBUG(1, "bug!!! td list is empty!"); + return -ENODEV; + } + + while (tmp != head) { + ++i; + td = list_entry(tmp, struct sl811_td, td_list); + PDEBUG(2, "td = %p, i = %d", td, i); + tmp = tmp->next; + } + } +*/ + return 0; +} + +/* + * Reset isochronous transfers + */ +static void sl811_reset_isochronous(struct urb *urb) +{ + struct sl811_urb_priv *urbp = urb->hcpriv; + struct sl811_td *td = NULL; + struct list_head *head, *tmp; + int i; + + PDEBUG(4, "enter, urb = %p", urb); + + for (i = 0; i < urb->number_of_packets; i++) { + urb->iso_frame_desc[i].actual_length = 0; + urb->iso_frame_desc[i].status = -EXDEV; + } + + head = &urbp->td_list; + tmp = head->next; + while (tmp != head) { + td = list_entry(tmp, struct sl811_td, td_list); + tmp = tmp->next; + sl811_reset_td(td); + } + + urbp->cur_td = urbp->first_td; + + urb->status = -EINPROGRESS; + urb->actual_length = 0; + urb->error_count = 0; +} + +/* + * Result the iso urb. + */ +static void sl811_result_isochronous(struct urb *urb) +{ + struct list_head *tmp, *head; + struct sl811_urb_priv *urbp = urb->hcpriv; + int status = 0; + struct sl811_td *td; + int i; + + PDEBUG(4, "enter, urb = %p", urb); + + urb->actual_length = 0; + + i = 0; + head = &urbp->td_list; + tmp = head->next; + while (tmp != head) { + td = list_entry(tmp, struct sl811_td, td_list); + tmp = tmp->next; + + if (!td->done) { + if (urbp->unlink) + urb->status = -ENOENT; + else { + PDEBUG(1, "we should not get here!"); + urb->status = -EXDEV; + } + return ; + } + if (td->td_status) { + status = td->td_status; + urb->error_count++; + PDEBUG(1, "error: td = %p, td status = %d", td, td->td_status); + } + + urb->iso_frame_desc[i].actual_length = td->len - td->left; + urb->actual_length += td->len - td->left; + urb->iso_frame_desc[i].status = td->td_status; + ++i; + if (td->left) + PDEBUG(3, "short packet, td = %p, len = %d, left = %d", td, td->len, td->left); + } + + urb->status = status; +/* +// for debug + PDEBUG(2, "iso urb complete, len = %d, status =%d ", urb->actual_length, urb->status); +*/ + PDEBUG(4, "leave success"); +} + +/* + * Interrupt transfers + */ +static int sl811_submit_interrupt(struct urb *urb) +{ + int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + int len = urb->transfer_buffer_length; + __u8 *data = urb->transfer_buffer; + __u8 dev = usb_pipedevice(urb->pipe); + __u8 pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe)); + __u8 ctrl = 0; + struct sl811_hc *hc = urb->dev->bus->hcpriv; + struct sl811_urb_priv *urbp = urb->hcpriv; + struct sl811_td *td = NULL; + + PDEBUG(4, "enter, urb = %p", urb); + + if (len > maxsze) { + PDEBUG(1, "length is big than max packet size, len = %d, max packet = %d", len, maxsze); + return -EINVAL; + } + if (usb_pipeslow(urb->pipe) && !(hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED)) + ctrl |= SL811_USB_CTRL_PREAMBLE; + + ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE; + if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe))) + ctrl |= SL811_USB_CTRL_TOGGLE_1; + usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); + td = sl811_alloc_td(urb); + if (!td) + return -ENOMEM; + + sl811_fill_td(td, ctrl, SL811_DATA_START, len, pidep, dev, data); + sl811_calc_td_time(td); + urbp->cur_td = urbp->first_td = urbp->last_td = td; + urbp->interval = 0; + + PDEBUG(4, "leave success"); + + return 0; +} + +/* + * Reset interrupt transfers + */ +static void sl811_reset_interrupt(struct urb *urb) +{ + struct sl811_urb_priv *urbp = urb->hcpriv; + struct sl811_td *td = urbp->cur_td; + + PDEBUG(4, "enter, interval = %d", urb->interval); + + td->ctrl &= ~SL811_USB_CTRL_TOGGLE_1; + if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe))) + td->ctrl |= SL811_USB_CTRL_TOGGLE_1; + usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); + + sl811_reset_td(td); + + urbp->interval = urb->interval; + + urb->status = -EINPROGRESS; + urb->actual_length = 0; +} + +/* + * Result the interrupt urb. + */ +static void sl811_result_interrupt(struct urb *urb) +{ + struct list_head *tmp; + struct sl811_urb_priv *urbp = urb->hcpriv; + struct sl811_td *td; + int toggle; + + PDEBUG(4, "enter, urb = %p", urb); + + urb->actual_length = 0; + + tmp = &urbp->td_list; + tmp = tmp->next; + td = list_entry(tmp, struct sl811_td, td_list); + + // success. + if (td->done && td->td_status == 0) { + urb->actual_length += td->len - td->left; + urb->status = 0; + return ; + } + // tranfer is done but fail, reset the toggle. + else if (td->done && td->td_status) { + urb->status = td->td_status; +reset_toggle: + toggle = (td->ctrl & SL811_USB_CTRL_TOGGLE_1) ? 1 : 0; + usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), toggle); + PDEBUG(3, "error: td = %p, td status = %d", td, td->td_status); + return ; + } + // unlink, and not do transfer yet + else if (td->done == 0 && urbp->unlink && td->td_status == 0) { + urb->status = -ENOENT; + PDEBUG(3, "unlink and not transfer!"); + return ; + } + // unlink, and transfer not complete yet. + else if (td->done == 0 && urbp->unlink && td->td_status) { + urb->status = -ENOENT; + PDEBUG(3, "unlink and not complete!"); + goto reset_toggle; + } + // must be bug!!! + else {// (td->done == 0 && urbp->unlink == 0) + PDEBUG(1, "we should not get here!"); + urb->status = -EPIPE; + return ; + } +} + +/* + * Control transfers + */ +static int sl811_submit_control(struct urb *urb) +{ + int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + int len = urb->transfer_buffer_length; + __u8 *data = urb->transfer_buffer; + __u8 dev = usb_pipedevice(urb->pipe); + __u8 pidep = 0; + __u8 ctrl = 0; + struct sl811_hc *hc = urb->dev->bus->hcpriv; + struct sl811_urb_priv *urbp = urb->hcpriv; + struct sl811_td *td = NULL; + + PDEBUG(4, "enter, urb = %p", urb); + + if (usb_pipeslow(urb->pipe) && !(hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED)) + ctrl |= SL811_USB_CTRL_PREAMBLE; + + /* Build SETUP TD */ + pidep = PIDEP(USB_PID_SETUP, usb_pipeendpoint(urb->pipe)); + ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE | SL811_USB_CTRL_DIR_OUT; + td = sl811_alloc_td(urb); + if (!td) + return -ENOMEM; + + sl811_fill_td(td, ctrl, SL811_DATA_START, 8, pidep, dev, urb->setup_packet); + sl811_calc_td_time(td); + + urbp->cur_td = urbp->first_td = td; + + /* + * If direction is "send", change the frame from SETUP (0x2D) + * to OUT (0xE1). Else change it from SETUP to IN (0x69). + */ + pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe)); + if (usb_pipeout(urb->pipe)) + ctrl |= SL811_USB_CTRL_DIR_OUT; + else + ctrl &= ~SL811_USB_CTRL_DIR_OUT; + + /* Build the DATA TD's */ + while (len > 0) { + int pktsze = len; + + if (pktsze > maxsze) + pktsze = maxsze; + + /* Alternate Data0/1 (start with Data1) */ + ctrl ^= SL811_USB_CTRL_TOGGLE_1; + + td = sl811_alloc_td(urb); + if (!td) + return -ENOMEM; + + sl811_fill_td(td, ctrl, SL811_DATA_START, pktsze, pidep, dev, data); + sl811_calc_td_time(td); + + data += pktsze; + len -= pktsze; + } + + /* Build the final TD for control status */ + td = sl811_alloc_td(urb); + if (!td) + return -ENOMEM; + + /* It's IN if the pipe is an output pipe or we're not expecting data back */ + if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length) { + pidep = PIDEP(USB_PID_IN, usb_pipeendpoint(urb->pipe)); + ctrl &= ~SL811_USB_CTRL_DIR_OUT; + } else { + pidep = PIDEP(USB_PID_OUT, usb_pipeendpoint(urb->pipe)); + ctrl |= SL811_USB_CTRL_DIR_OUT; + } + + /* End in Data1 */ + ctrl |= SL811_USB_CTRL_TOGGLE_1; + + sl811_fill_td(td, ctrl, SL811_DATA_START, 0, pidep, dev, 0); + sl811_calc_td_time(td); + urbp->last_td = td; +/* +// for debug + { + struct list_head *head, *tmp; + struct sl811_td *td; + int i = 0; + head = &urbp->td_list; + tmp = head->next; + + if (list_empty(&urbp->td_list)) { + PDEBUG(1, "bug!!! td list is empty!"); + return -ENODEV; + } + + while (tmp != head) { + ++i; + td = list_entry(tmp, struct sl811_td, td_list); + PDEBUG(3, "td = %p, i = %d", td, i); + tmp = tmp->next; + } + } +*/ + PDEBUG(4, "leave success"); + + return 0; +} + +/* + * Result the control urb. + */ +static void sl811_result_control(struct urb *urb) +{ + struct list_head *tmp, *head; + struct sl811_urb_priv *urbp = urb->hcpriv; + struct sl811_td *td; + + PDEBUG(4, "enter, urb = %p", urb); + + if (list_empty(&urbp->td_list)) { + PDEBUG(1, "td list is empty"); + return ; + } + + head = &urbp->td_list; + + tmp = head->next; + td = list_entry(tmp, struct sl811_td, td_list); + + /* The first TD is the SETUP phase, check the status, but skip the count */ + if (!td->done) { + PDEBUG(3, "setup phase error, td = %p, done = %d", td, td->done); + goto err_done; + } + if (td->td_status) { + PDEBUG(3, "setup phase error, td = %p, td status = %d", td, td->td_status); + goto err_status; + } + + urb->actual_length = 0; + + /* The rest of the TD's (but the last) are data */ + tmp = tmp->next; + while (tmp != head && tmp->next != head) { + td = list_entry(tmp, struct sl811_td, td_list); + tmp = tmp->next; + if (!td->done) { + PDEBUG(3, "data phase error, td = %p, done = %d", td, td->done); + goto err_done; + } + if (td->td_status) { + PDEBUG(3, "data phase error, td = %p, td status = %d", td, td->td_status); + goto err_status; + } + + urb->actual_length += td->len - td->left; + // short packet. + if (td->left) { + PDEBUG(3, "data phase short packet, td = %p, count = %d", td, td->len - td->left); + break; + } + } + + /* The last td is status phase */ + td = urbp->last_td; + if (!td->done) { + PDEBUG(3, "status phase error, td = %p, done = %d", td, td->done); + goto err_done; + } + if (td->td_status) { + PDEBUG(3, "status phase error, td = %p, td status = %d", td, td->td_status); + goto err_status; + } + + PDEBUG(4, "leave success"); + + urb->status = 0; + return ; + +err_done: + if (urbp->unlink) + urb->status = -ENOENT; + else { + PDEBUG(1, "we should not get here! td = %p", td); + urb->status = -EPIPE; + } + return ; + +err_status: + urb->status = td->td_status; + return ; +} + +/* + * Bulk transfers + */ +static int sl811_submit_bulk(struct urb *urb) +{ + int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + int len = urb->transfer_buffer_length; + __u8 *data = urb->transfer_buffer; + __u8 dev = usb_pipedevice(urb->pipe); + __u8 pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe)); + __u8 ctrl = 0; + struct sl811_urb_priv *urbp = urb->hcpriv; + struct sl811_td *td = NULL; + + PDEBUG(4, "enter, urb = %p", urb); + + if (len < 0) { + PDEBUG(1, "error, urb = %p, len = %d", urb, len); + return -EINVAL; + } + + /* Can't have low speed bulk transfers */ + if (usb_pipeslow(urb->pipe)) { + PDEBUG(1, "error, urb = %p, low speed device", urb); + return -EINVAL; + } + + if (usb_pipeout(urb->pipe)) + ctrl |= SL811_USB_CTRL_DIR_OUT; + + ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE; + + /* Build the DATA TD's */ + do { /* Allow zero length packets */ + int pktsze = len; + + if (pktsze > maxsze) + pktsze = maxsze; + + td = sl811_alloc_td(urb); + if (!td) + return -ENOMEM; + + /* Alternate Data0/1 (start with Data1) */ + ctrl &= ~SL811_USB_CTRL_TOGGLE_1; + if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe))) + ctrl |= SL811_USB_CTRL_TOGGLE_1; + usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); + + sl811_fill_td(td, ctrl, SL811_DATA_START, pktsze, pidep, dev, data); + sl811_calc_td_time(td); + + if (urbp->cur_td == NULL) + urbp->cur_td = urbp->first_td = td; + + data += pktsze; + len -= maxsze; + } while (len > 0); + + /* + * USB_ZERO_PACKET means adding a 0-length packet, if + * direction is OUT and the transfer_length was an + * exact multiple of maxsze, hence + * (len = transfer_length - N * maxsze) == 0 + * however, if transfer_length == 0, the zero packet + * was already prepared above. + */ + if (usb_pipeout(urb->pipe) && (urb->transfer_flags & USB_ZERO_PACKET) && + !len && urb->transfer_buffer_length) { + + td = sl811_alloc_td(urb); + if (!td) + return -ENOMEM; + + /* Alternate Data0/1 (start with Data1) */ + ctrl &= ~SL811_USB_CTRL_TOGGLE_1; + if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe))) + ctrl |= SL811_USB_CTRL_TOGGLE_1; + usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); + + sl811_fill_td(td, ctrl, SL811_DATA_START, 0, pidep, dev, 0); + sl811_calc_td_time(td); + } + + urbp->last_td = td; + + PDEBUG(4, "leave success"); + + return 0; +} + +/* + * Reset bulk transfers + */ +static int sl811_reset_bulk(struct urb *urb) +{ + struct sl811_urb_priv *urbp = urb->hcpriv; + struct sl811_td *td; + struct list_head *head, *tmp; + + PDEBUG(4, "enter, urb = %p", urb); + + + head = &urbp->td_list; + tmp = head->next; + + while (tmp != head) { + td = list_entry(tmp, struct sl811_td, td_list); + + /* Alternate Data0/1 (start with Data1) */ + td->ctrl &= ~SL811_USB_CTRL_TOGGLE_1; + if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe))) + td->ctrl |= SL811_USB_CTRL_TOGGLE_1; + usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); + + sl811_reset_td(td); + } + + urb->status = -EINPROGRESS; + urb->actual_length = 0; + urbp->cur_td = urbp->first_td; + + PDEBUG(4, "leave success"); + + return 0; +} + +/* + * Result the bulk urb. + */ +static void sl811_result_bulk(struct urb *urb) +{ + struct list_head *tmp, *head; + struct sl811_urb_priv *urbp = urb->hcpriv; + struct sl811_td *td = NULL; + int toggle; + + PDEBUG(4, "enter, urb = %p", urb); + + urb->actual_length = 0; + + head = &urbp->td_list; + tmp = head->next; + while (tmp != head) { + td = list_entry(tmp, struct sl811_td, td_list); + tmp = tmp->next; + + // success. + if (td->done && td->td_status == 0) { + urb->actual_length += td->len - td->left; + + // short packet + if (td->left) { + urb->status = 0; + PDEBUG(3, "short packet, td = %p, count = %d", td, td->len - td->left); + goto reset_toggle; + } + } + // tranfer is done but fail, reset the toggle. + else if (td->done && td->td_status) { + urb->status = td->td_status; + PDEBUG(3, "error: td = %p, td status = %d", td, td->td_status); + goto reset_toggle; + } + // unlink, and not do transfer yet + else if (td->done == 0 && urbp->unlink && td->td_status == 0) { + urb->status = -ENOENT; + PDEBUG(3, "unlink and not transfer!"); + return ; + } + // unlink, and transfer not complete yet. + else if (td->done == 0 && urbp->unlink && td->td_status) { + PDEBUG(3, "unlink and not complete!"); + urb->status = -ENOENT; + goto reset_toggle; + } + // must be bug!!! + else {// (td->done == 0 && urbp->unlink == 0) + urb->status = -EPIPE; + PDEBUG(1, "we should not get here!"); + return ; + } + } + + PDEBUG(4, "leave success"); + urb->status = 0; + return ; + +reset_toggle: + toggle = (td->ctrl & SL811_USB_CTRL_TOGGLE_1) ? 1 : 0; + usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), toggle); +} + +/* + * Find the first urb have the same dev and endpoint. + */ +static inline int sl811_find_same_urb(struct list_head *head, struct urb *urb) +{ + struct list_head *tmp; + struct urb *u; + + if (!head || !urb) + return 0; + + tmp = head->next; + + while (tmp != head) { + u = list_entry(tmp, struct urb, urb_list); + if (u == urb) + return 1; + tmp = tmp->next; + } + + return 0; +} + +/* + * Find the first urb have the same dev and endpoint. + */ +static inline struct urb* sl811_find_same_devep(struct list_head *head, struct urb *urb) +{ + struct list_head *tmp; + struct urb *u; + + if (!head || !urb) + return NULL; + + tmp = head->next; + + while (tmp != head) { + u = list_entry(tmp, struct urb, urb_list); + if ((usb_pipe_endpdev(u->pipe)) == (usb_pipe_endpdev(urb->pipe))) + return u; + tmp = tmp->next; + } + + return NULL; +} + +/* + * This function is called by the USB core API when an URB is available to + * process. + */ +static int sl811_submit_urb(struct urb *urb) +{ + struct sl811_hc *hc = urb->dev->bus->hcpriv; + unsigned int pipe = urb->pipe; + struct list_head *head = NULL; + unsigned long flags; + int bustime; + int ret = 0; + + if (!urb) { + PDEBUG(1, "urb is null"); + return -EINVAL; + } + + if (urb->hcpriv) { + PDEBUG(1, "urbp is not null, urb = %p, urbp = %p", urb, urb->hcpriv); + return -EINVAL; + } + + if (!urb->dev || !urb->dev->bus || !hc) { + PDEBUG(1, "dev or bus or hc is null"); + return -ENODEV; + } + + if (usb_endpoint_halted(urb->dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) { + PDEBUG(2, "sl811_submit_urb: endpoint_halted"); + return -EPIPE; + } + + if (usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)) > SL811_DATA_LIMIT) { + printk(KERN_ERR "Packet size is big for SL811, should < %d!\n", SL811_DATA_LIMIT); + return -EINVAL; + } + + /* a request to the virtual root hub */ + if (usb_pipedevice(pipe) == hc->rh.devnum) + return sl811_rh_submit_urb(urb); + + spin_lock_irqsave(&hc->hc_lock, flags); + spin_lock(&urb->lock); + + switch (usb_pipetype(urb->pipe)) { + case PIPE_ISOCHRONOUS: + head = &hc->iso_list; + break; + case PIPE_INTERRUPT: + head = &hc->intr_list; + break; + case PIPE_CONTROL: + head = &hc->ctrl_list; + break; + case PIPE_BULK: + head = &hc->bulk_list; + break; + } + + if (sl811_find_same_devep(head, urb)) { + list_add(&urb->urb_list, &hc->wait_list); + PDEBUG(4, "add to wait list"); + goto out_unlock; + } + + if (!sl811_alloc_urb_priv(urb)) { + ret = -ENOMEM; + goto out_unlock; + } + + switch (usb_pipetype(urb->pipe)) { + case PIPE_ISOCHRONOUS: + if (urb->number_of_packets <= 0) { + ret = -EINVAL; + break; + } + bustime = usb_check_bandwidth(urb->dev, urb); + if (bustime < 0) { + ret = bustime; + break; + } + if (!(ret = sl811_submit_isochronous(urb))) + usb_claim_bandwidth(urb->dev, urb, bustime, 1); + break; + case PIPE_INTERRUPT: + bustime = usb_check_bandwidth(urb->dev, urb); + if (bustime < 0) + ret = bustime; + else if (!(ret = sl811_submit_interrupt(urb))) + usb_claim_bandwidth(urb->dev, urb, bustime, 0); + break; + case PIPE_CONTROL: + ret = sl811_submit_control(urb); + break; + case PIPE_BULK: + ret = sl811_submit_bulk(urb); + break; + } + + if (!ret) { + ((struct sl811_urb_priv *)urb->hcpriv)->inserttime = jiffies; + list_add(&urb->urb_list, head); + PDEBUG(4, "add to type list"); + urb->status = -EINPROGRESS; + if (++hc->active_urbs == 1) + sl811_enable_interrupt(hc); + goto out_unlock; + } else { + PDEBUG(2, "submit urb fail! error = %d", ret); + sl811_free_urb_priv(urb); + } + +out_unlock: + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&hc->hc_lock, flags); + + return ret; +} + +/* + * Submit the urb the wait list. + */ +static int sl811_submit_urb_with_lock(struct urb *urb) +{ + struct sl811_hc *hc = urb->dev->bus->hcpriv; + struct list_head *head = NULL; + int bustime; + int ret = 0; + + spin_lock(&urb->lock); + + switch (usb_pipetype(urb->pipe)) { + case PIPE_ISOCHRONOUS: + head = &hc->iso_list; + break; + case PIPE_INTERRUPT: + head = &hc->intr_list; + break; + case PIPE_CONTROL: + head = &hc->ctrl_list; + break; + case PIPE_BULK: + head = &hc->bulk_list; + break; + } + + if (!sl811_alloc_urb_priv(urb)) { + ret = -ENOMEM; + goto out_unlock; + } + + switch (usb_pipetype(urb->pipe)) { + case PIPE_ISOCHRONOUS: + if (urb->number_of_packets <= 0) { + ret = -EINVAL; + break; + } + bustime = usb_check_bandwidth(urb->dev, urb); + if (bustime < 0) { + ret = bustime; + break; + } + if (!(ret = sl811_submit_isochronous(urb))) + usb_claim_bandwidth(urb->dev, urb, bustime, 1); + break; + case PIPE_INTERRUPT: + bustime = usb_check_bandwidth(urb->dev, urb); + if (bustime < 0) + ret = bustime; + else if (!(ret = sl811_submit_interrupt(urb))) + usb_claim_bandwidth(urb->dev, urb, bustime, 0); + break; + case PIPE_CONTROL: + ret = sl811_submit_control(urb); + break; + case PIPE_BULK: + ret = sl811_submit_bulk(urb); + break; + } + + if (ret == 0) { + ((struct sl811_urb_priv *)urb->hcpriv)->inserttime = jiffies; + list_add(&urb->urb_list, head); + PDEBUG(4, "add to type list"); + urb->status = -EINPROGRESS; + if (++hc->active_urbs == 1) + sl811_enable_interrupt(hc); + goto out_unlock; + } else { + PDEBUG(2, "submit urb fail! error = %d", ret); + sl811_free_urb_priv(urb); + } + +out_unlock: + spin_unlock(&urb->lock); + + return ret; +} + +/* + * Reset the urb + */ +static void sl811_reset_urb(struct urb *urb) +{ + struct sl811_urb_priv *urbp = urb->hcpriv; + + switch (usb_pipetype(urb->pipe)) { + case PIPE_ISOCHRONOUS: + sl811_reset_isochronous(urb); + break; + case PIPE_INTERRUPT: + sl811_reset_interrupt(urb); + break; + case PIPE_CONTROL: + return; + case PIPE_BULK: + sl811_reset_bulk(urb); + break; + } + urbp->inserttime = jiffies; +} + +/* + * Return the result of a transfer + */ +static void sl811_result_urb(struct urb *urb) +{ + struct sl811_urb_priv *urbp = urb->hcpriv; + struct sl811_hc *hc = urb->dev->bus->hcpriv; + struct list_head *head = NULL; + struct urb *u = NULL; + int reset = 0; + int ring = 0; + + if (urb->status != -EINPROGRESS) { + PDEBUG(1, "urb status is not EINPROGRESS!"); + return ; + } + + spin_lock(&urb->lock); + + switch (usb_pipetype(urb->pipe)) { + case PIPE_ISOCHRONOUS: + head = &hc->iso_list; + sl811_result_isochronous(urb); + + // if the urb is not unlink and is in a urb "ring", we reset it + if (!urbp->unlink && urb->next) + ring = 1; + break; + case PIPE_INTERRUPT: + head = &hc->intr_list; + sl811_result_interrupt(urb); + + // if the urb is not unlink and not "once" query, we reset. + if (!urbp->unlink && urb->interval) + reset = 1; + break; + case PIPE_CONTROL: + head = &hc->ctrl_list; + sl811_result_control(urb); + break; + case PIPE_BULK: + head = &hc->bulk_list; + sl811_result_bulk(urb); + + // if the urb is not unlink and is in a urb "ring", we reset it + if (!urbp->unlink && urb->next) + ring = 1; + break; + } + + PDEBUG(4, "result urb status = %d", urb->status); + + if (ring && urb->next == urb) + reset = 1; + + if (!reset) { + switch (usb_pipetype(urb->pipe)) { + case PIPE_ISOCHRONOUS: + usb_release_bandwidth(urb->dev, urb, 1); + break; + case PIPE_INTERRUPT: + usb_release_bandwidth(urb->dev, urb, 0); + break; + } + sl811_free_urb_priv(urb); + } + + spin_unlock(&urb->lock); + + if (urb->complete) + urb->complete(urb); + + if (reset) { + spin_lock(&urb->lock); + sl811_reset_urb(urb); + if (usb_pipeint(urb->pipe)) + list_add(&urb->urb_list, &hc->idle_intr_list); + else + list_add(&urb->urb_list, head); + spin_unlock(&urb->lock); + } else { + if (--hc->active_urbs <= 0) { + hc->active_urbs = 0; + sl811_disable_interrupt(hc); + } + + if (ring) + u = urb->next; + else + u = sl811_find_same_devep(&hc->wait_list, urb); + + if (u) { + if (!list_empty(&u->urb_list)) + list_del(&u->urb_list); + if (sl811_submit_urb_with_lock(u)) + list_add(&u->urb_list, &hc->wait_list); + } + } +} + + +#ifdef SL811_TIMEOUT + +/* + * Unlink the urb from the urb list + */ +static int sl811_unlink_urb(struct urb *urb) +{ + unsigned long flags; + struct sl811_hc *hc; + struct sl811_urb_priv *urbp; + int call = 0; + int schedule = 0; + int count = 0; + + if (!urb) { + PDEBUG(1, "urb is null"); + return -EINVAL; + } + + if (!urb->dev || !urb->dev->bus) { + PDEBUG(1, "dev or bus is null"); + return -ENODEV; + } + + hc = urb->dev->bus->hcpriv; + urbp = urb->hcpriv; + + /* a request to the virtual root hub */ + if (usb_pipedevice(urb->pipe) == hc->rh.devnum) + return sl811_rh_unlink_urb(urb); + + spin_lock_irqsave(&hc->hc_lock, flags); + spin_lock(&urb->lock); + + // in wait list + if (sl811_find_same_urb(&hc->wait_list, urb)) { + PDEBUG(4, "unlink urb in wait list"); + list_del_init(&urb->urb_list); + urb->status = -ENOENT; + call = 1; + goto out; + } + + // in intr idle list. + if (sl811_find_same_urb(&hc->idle_intr_list, urb)) { + PDEBUG(4, "unlink urb in idle intr list"); + list_del_init(&urb->urb_list); + urb->status = -ENOENT; + sl811_free_urb_priv(urb); + usb_release_bandwidth(urb->dev, urb, 0); + if (--hc->active_urbs <= 0) { + hc->active_urbs = 0; + sl811_disable_interrupt(hc); + } + call = 1; + goto out; + } + + if (urb->status == -EINPROGRESS) { + PDEBUG(3, "urb is still in progress"); + urbp->unlink = 1; + +re_unlink: + // Is it in progress? + urbp = urb->hcpriv; + if (urbp && hc->cur_td == urbp->cur_td) { + ++count; + if (sl811_read(hc, 0) & SL811_USB_CTRL_ARM) { + PDEBUG(3, "unlink: cur td is still in progress! count = %d", count); +re_schedule: + schedule = 1; + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&hc->hc_lock, flags); + schedule_timeout(HZ/50); + spin_lock_irqsave(&hc->hc_lock, flags); + spin_lock(&urb->lock); + } else { + PDEBUG(3, "unlink: lost of interrupt? do parse! count = %d", count); + spin_unlock(&urb->lock); + sl811_transfer_done(hc, 0); + spin_lock(&urb->lock); + } + goto re_unlink; + } + + if (list_empty(&urb->urb_list)) { + PDEBUG(3, "unlink: list empty!"); + goto out; + } + + if (urb->transfer_flags & USB_TIMEOUT_KILLED) { + PDEBUG(3, "unlink: time out killed"); + // it is timeout killed by us + goto result; + } else if (urb->transfer_flags & USB_ASYNC_UNLINK) { + // we do nothing, just let it be processing later + PDEBUG(3, "unlink async, do nothing"); + goto out; + } else { + // synchron without callback + PDEBUG(3, "unlink synchron, we wait the urb complete or timeout"); + if (schedule == 0) { + PDEBUG(3, "goto re_schedule"); + goto re_schedule; + } else { + PDEBUG(3, "already scheduled"); + goto result; + } + } + } else if (!list_empty(&urb->urb_list)) { + PDEBUG(1, "urb = %p, status = %d is in a list, why?", urb, urb->status); + //list_del_init(&urb->urb_list); + //call = 1; + } + +out: + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&hc->hc_lock, flags); + + if (call && urb->complete) + urb->complete(urb); + + return 0; + +result: + spin_unlock(&urb->lock); + + list_del_init(&urb->urb_list); + sl811_result_urb(urb); + + spin_unlock_irqrestore(&hc->hc_lock, flags); + + return 0; +} + +#else + +/* + * Unlink the urb from the urb list + */ +static int sl811_unlink_urb(struct urb *urb) +{ + unsigned long flags; + struct sl811_hc *hc; + struct sl811_urb_priv *urbp; + int call = 0; + + if (!urb) { + PDEBUG(1, "urb is null"); + return -EINVAL; + } + + if (!urb->dev || !urb->dev->bus) { + PDEBUG(1, "dev or bus is null"); + return -ENODEV; + } + + hc = urb->dev->bus->hcpriv; + urbp = urb->hcpriv; + + /* a request to the virtual root hub */ + if (usb_pipedevice(urb->pipe) == hc->rh.devnum) + return sl811_rh_unlink_urb(urb); + + spin_lock_irqsave(&hc->hc_lock, flags); + spin_lock(&urb->lock); + + // in wait list + if (sl811_find_same_urb(&hc->wait_list, urb)) { + PDEBUG(2, "unlink urb in wait list"); + list_del_init(&urb->urb_list); + urb->status = -ENOENT; + call = 1; + goto out; + } + + if (urb->status == -EINPROGRESS) { + PDEBUG(2, "urb is still in progress"); + urbp->unlink = 1; + + // Is it in progress? + urbp = urb->hcpriv; + if (urbp && hc->cur_td == urbp->cur_td) { + // simple, let it out + PDEBUG(2, "unlink: cur td is still in progress!"); + hc->cur_td = NULL; + } + + goto result; + } else if (!list_empty(&urb->urb_list)) { + PDEBUG(1, "urb = %p, status = %d is in a list, why?", urb, urb->status); + list_del_init(&urb->urb_list); + if (urbp) + goto result; + else + call = 1; + } + +out: + spin_unlock(&urb->lock); + spin_unlock_irqrestore(&hc->hc_lock, flags); + + if (call && urb->complete) + urb->complete(urb); + + return 0; + +result: + spin_unlock(&urb->lock); + + list_del_init(&urb->urb_list); + sl811_result_urb(urb); + + spin_unlock_irqrestore(&hc->hc_lock, flags); + + return 0; +} + +#endif + +static int sl811_get_current_frame_number(struct usb_device *usb_dev) +{ + return ((struct sl811_hc *)(usb_dev->bus->hcpriv))->frame_number; +} + +static struct usb_operations sl811_device_operations = +{ + sl811_alloc_dev_priv, + sl811_free_dev_priv, + sl811_get_current_frame_number, + sl811_submit_urb, + sl811_unlink_urb +}; + +/* + * This functions transmit a td. + */ +static inline void sl811_trans_cur_td(struct sl811_hc *hc, struct sl811_td *td) +{ + sl811_print_td(4, td); + sl811_write_buf(hc, SL811_ADDR_A, &td->addr, 4); + if (td->len && (td->ctrl & SL811_USB_CTRL_DIR_OUT)) + sl811_write_buf(hc, td->addr, td->buf, td->len); + + sl811_write(hc, SL811_CTRL_A, td->ctrl); +} + + +/* + * This function checks the status of the transmitted or received packet + * and copy the data from the SL811HS register into a buffer. + */ +static void sl811_parse_cur_td(struct sl811_hc *hc, struct sl811_td *td) +{ + struct urb *urb = td->urb; +#ifdef SL811_DEBUG + int dev = usb_pipedevice(td->urb->pipe); + int ep = usb_pipeendpoint(td->urb->pipe); +#endif + + sl811_read_buf(hc, SL811_STS_A, &td->status, 2); + + if (td->status & SL811_USB_STS_ACK) { + td->done = 1; + +/* if ((td->ctrl & SL811_USB_CTRL_TOGGLE_1) != (td->status & SL811_USB_STS_TOGGLE_1)) { + PDEBUG(2, "dev %d endpoint %d unexpect data toggle!", dev, ep); + td->td_status = -EILSEQ; + } +*/ + if (!(td->ctrl & SL811_USB_CTRL_DIR_OUT) && td->len > 0) + sl811_read_buf(hc, td->addr, td->buf, td->len - td->left); + + if (td->left && (urb->transfer_flags & USB_DISABLE_SPD)) { + PDEBUG(2, "dev %d endpoint %d unexpect short packet! td = %p", dev, ep, td); + td->td_status = -EREMOTEIO; + } else + td->td_status = 0; + } else if (td->status & SL811_USB_STS_STALL) { + PDEBUG(2, "dev %d endpoint %d halt, td = %p", dev, ep, td); + td->td_status = -EPIPE; + if (urb->dev) + usb_endpoint_halt(td->urb->dev, usb_pipeendpoint(td->urb->pipe), usb_pipeout(td->urb->pipe)); + td->done = 1; + } else if (td->status & SL811_USB_STS_OVERFLOW) { + PDEBUG(1, "dev %d endpoint %d overflow, sl811 only support packet less than %d", dev, ep, SL811_DATA_LIMIT); + td->td_status = -EOVERFLOW; + td->done = 1; + } else if (td->status & SL811_USB_STS_TIMEOUT ) { + PDEBUG(2, "dev %d endpoint %d timeout, td = %p", dev, ep, td); + td->td_status = -ETIMEDOUT; + if (--td->errcnt == 0) + td->done = 1; + } else if (td->status & SL811_USB_STS_ERROR) { + PDEBUG(2, "dev %d endpoint %d error, td = %p", dev, ep, td); + td->td_status = -EILSEQ; + if (--td->errcnt == 0) + td->done = 1; + } else if (td->status & SL811_USB_STS_NAK) { + ++td->nakcnt; + PDEBUG(3, "dev %d endpoint %d nak, td = %p, count = %d", dev, ep, td, td->nakcnt); + td->td_status = -EINPROGRESS; + if (!usb_pipeslow(td->urb->pipe) && td->nakcnt > 1024) { + PDEBUG(2, "too many naks, td = %p, count = %d", td, td->nakcnt); + td->td_status = -ETIMEDOUT; + td->done = 1; + } + } + + sl811_print_td(4, td); +} + +/* + * This function checks the status of current urb. + */ +static int sl811_parse_cur_urb(struct urb *urb) +{ + struct sl811_urb_priv *urbp = urb->hcpriv; + struct sl811_td *td = urbp->cur_td; + struct list_head *tmp; + + sl811_print_td(5, td); + + // this td not done yet. + if (!td->done) + return 0; + + // the last ld, so the urb is done. + if (td == urbp->last_td) { + PDEBUG(4, "urb = %p is done success", td->urb); + if (usb_pipeisoc(td->urb->pipe)) + PDEBUG(4, "ISO URB DONE, td = %p", td); + return 1; + } + + // iso transfer, we always advance to next td + if (usb_pipeisoc(td->urb->pipe)) { + tmp = &td->td_list; + tmp = tmp->next; + urbp->cur_td = list_entry(tmp, struct sl811_td, td_list); + PDEBUG(4, "ISO NEXT, td = %p", urbp->cur_td); + return 0; + } + + // some error occur, so the urb is done. + if (td->td_status) { + PDEBUG(3, "urb = %p is done error, td status is = %d", td->urb, td->td_status); + return 1; + } + + // short packet. + if (td->left) { + if (usb_pipecontrol(td->urb->pipe)) { + // control packet, we advance to the last td + PDEBUG(3, "ctrl short packet, advance to last td"); + urbp->cur_td = urbp->last_td; + return 0; + } else { + // interrut and bulk packet, urb is over. + PDEBUG(3, "bulk or intr short packet, urb is over"); + return 1; + } + } + + // we advance to next td. + tmp = &td->td_list; + tmp = tmp->next; + urbp->cur_td = list_entry(tmp, struct sl811_td, td_list); +#ifdef SL811_DEBUG + PDEBUG(4, "advance to the next td, urb = %p, td = %p", urb, urbp->cur_td); + sl811_print_td(5, urbp->cur_td); + if (td == urbp->cur_td) + PDEBUG(1, "bug!!!"); +#endif + return 0; +} + +/* + * Find the next td to transfer. + */ +static inline struct sl811_td* sl811_schedule_next_td(struct urb *urb, struct sl811_td *cur_td) +{ + struct sl811_urb_priv *urbp = urb->hcpriv; + + PDEBUG(4, "urb at %p, cur td at %p", urb, cur_td); + + // iso don't schedule the td in the same frame. + if (usb_pipeisoc(cur_td->urb->pipe)) + return NULL; + + // cur td is not complete + if (!cur_td->done) + return NULL; + + // here, urbp->cur_td is already the next td; + return urbp->cur_td; +} + +/* + * Scan the list to find a active urb + */ +static inline struct urb* sl811_get_list_next_urb(struct sl811_hc *hc, struct list_head *next) +{ + struct urb *urb; + int i; + + if (list_empty(next)) + return NULL; + + if (next == hc->cur_list) + return NULL; + + for (i = 0; i < 4; ++i) + if (next == &hc->urb_list[i]) + return NULL; + + urb = list_entry(next, struct urb, urb_list); + PDEBUG(4, "next urb in list is at %p", urb); + + return urb; +} + +/* + * Find the next td to transfer. + */ +static struct sl811_td* sl811_schedule_next_urb(struct sl811_hc *hc, struct list_head *next) +{ + struct urb *urb = NULL; + int back_loop = 1; + struct list_head *old_list = hc->cur_list; + + // try to get next urb in the same list. + if (next) { + urb = sl811_get_list_next_urb(hc, next); + if (!urb) + ++hc->cur_list; + } + + // try other list. + if (!urb) { +re_loop: + // try all the list. + while (hc->cur_list < &hc->urb_list[4]) { + if ((urb = sl811_get_list_next_urb(hc, hc->cur_list->next))) + return ((struct sl811_urb_priv *)urb->hcpriv)->cur_td; + ++hc->cur_list; + } + // the last list is try + if (back_loop && (old_list >= &hc->ctrl_list)) { + hc->cur_list = &hc->ctrl_list; + back_loop = 0; + goto re_loop; + } + } + + if (hc->cur_list > &hc->urb_list[3]) + hc->cur_list = &hc->ctrl_list; + + return NULL; +} + +/* + * This function process the transfer rusult. + */ +static void sl811_transfer_done(struct sl811_hc *hc, int sof) +{ + struct sl811_td *cur_td = hc->cur_td, *next_td = NULL; + struct urb *cur_urb = NULL; + struct list_head *next = NULL; + int done; + + PDEBUG(5, "enter"); + + if (cur_td == NULL) { + PDEBUG(1, "in done interrupt, but td is null, be already parsed?"); + return ; + } + + cur_urb = cur_td->urb; + hc->cur_td = NULL; + next = &cur_urb->urb_list; + next = next->next; + + spin_lock(&cur_urb->lock); + sl811_parse_cur_td(hc, cur_td); + done = sl811_parse_cur_urb(cur_urb); + spin_unlock(&cur_urb->lock); + + if (done) { + list_del_init(&cur_urb->urb_list); + cur_td = NULL; + sl811_result_urb(cur_urb); + } + + if (sof) + return ; + + if (!done) { + next_td = sl811_schedule_next_td(cur_urb, cur_td); + if (next_td && next_td != cur_td && (sl811_calc_bus_remainder(hc) > next_td->bustime)) { + hc->cur_td = next_td; + PDEBUG(5, "ADD TD"); + sl811_trans_cur_td(hc, next_td); + return ; + } + } + + while (1) { + next_td = sl811_schedule_next_urb(hc, next); + if (!next_td) + return; + if (next_td == cur_td) + return; + next = &next_td->urb->urb_list; + next = next->next; + if (sl811_calc_bus_remainder(hc) > next_td->bustime) { + hc->cur_td = next_td; + PDEBUG(5, "ADD TD"); + sl811_trans_cur_td(hc, next_td); + return ; + } + } +} + +/* + * + */ +static void inline sl811_dec_intr_interval(struct sl811_hc *hc) +{ + struct list_head *head, *tmp; + struct urb *urb; + struct sl811_urb_priv *urbp; + + if (list_empty(&hc->idle_intr_list)) + return ; + + head = &hc->idle_intr_list; + tmp = head->next; + + while (tmp != head) { + urb = list_entry(tmp, struct urb, urb_list); + tmp = tmp->next; + spin_lock(&urb->lock); + urbp = urb->hcpriv; + if (--urbp->interval == 0) { + list_del(&urb->urb_list); + list_add(&urb->urb_list, &hc->intr_list); + PDEBUG(4, "intr urb active"); + } + spin_unlock(&urb->lock); + } +} + +/* + * The sof interrupt is happen. + */ +static void sl811_start_sof(struct sl811_hc *hc) +{ + struct sl811_td *next_td; +#ifdef SL811_DEBUG + static struct sl811_td *repeat_td = NULL; + static int repeat_cnt = 1; +#endif + if (++hc->frame_number > 1024) + hc->frame_number = 0; + + if (hc->active_urbs == 0) + return ; + + sl811_dec_intr_interval(hc); + + if (hc->cur_td) { + if (sl811_read(hc, 0) & SL811_USB_CTRL_ARM) { +#ifdef SL811_DEBUG + if (repeat_td == hc->cur_td) + ++repeat_cnt; + else { + if (repeat_cnt >= 2) + PDEBUG(2, "cur td = %p repeat %d", hc->cur_td, repeat_cnt); + repeat_cnt = 1; + repeat_td = hc->cur_td; + } +#endif + return ; + } else { + PDEBUG(2, "lost of interrupt in sof? do parse!"); + sl811_transfer_done(hc, 1); + + // let this frame idle + return; + } + } + + hc->cur_list = &hc->iso_list; + + if (hc->active_urbs == 0) + return ; + + next_td = sl811_schedule_next_urb(hc, NULL); + if (!next_td) { +#ifdef SL811_DEBUG + if (list_empty(&hc->idle_intr_list)) + PDEBUG(2, "not schedule a td, why? urbs = %d", hc->active_urbs); +#endif + return; + } + if (sl811_calc_bus_remainder(hc) > next_td->bustime) { + hc->cur_td = next_td; + sl811_trans_cur_td(hc, next_td); + } else + PDEBUG(2, "bus time if not enough, why?"); +} + +/* + * This function resets SL811HS controller and detects the speed of + * the connecting device + * + * Return: 0 = no device attached; 1 = USB device attached + */ +static int sl811_hc_reset(struct sl811_hc *hc) +{ + int status ; + + sl811_write(hc, SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI); + sl811_write(hc, SL811_CTRL1, SL811_CTRL1_RESET); + + mdelay(20); + + // Disable hardware SOF generation, clear all irq status. + sl811_write(hc, SL811_CTRL1, 0); + mdelay(2); + sl811_write(hc, SL811_INTRSTS, 0xff); + status = sl811_read(hc, SL811_INTRSTS); + + if (status & SL811_INTR_NOTPRESENT) { + // Device is not present + PDEBUG(0, "Device not present"); + hc->rh_status.wPortStatus &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE); + hc->rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION; + sl811_write(hc, SL811_INTR, SL811_INTR_INSRMV); + return 0; + } + + // Send SOF to address 0, endpoint 0. + sl811_write(hc, SL811_LEN_B, 0); + sl811_write(hc, SL811_PIDEP_B, PIDEP(USB_PID_SOF, 0)); + sl811_write(hc, SL811_DEV_B, 0x00); + sl811_write (hc, SL811_SOFLOW, SL811_12M_HI); + + if (status & SL811_INTR_SPEED_FULL) { + /* full speed device connect directly to root hub */ + PDEBUG (0, "Full speed Device attached"); + + sl811_write(hc, SL811_CTRL1, SL811_CTRL1_RESET); + mdelay(20); + sl811_write(hc, SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI); + sl811_write(hc, SL811_CTRL1, SL811_CTRL1_SOF); + + /* start the SOF or EOP */ + sl811_write(hc, SL811_CTRL_B, SL811_USB_CTRL_ARM); + hc->rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION; + hc->rh_status.wPortStatus &= ~USB_PORT_STAT_LOW_SPEED; + mdelay(2); + sl811_write (hc, SL811_INTRSTS, 0xff); + } else { + /* slow speed device connect directly to root-hub */ + PDEBUG(0, "Low speed Device attached"); + + sl811_write(hc, SL811_CTRL1, SL811_CTRL1_RESET); + mdelay(20); + sl811_write(hc, SL811_CTRL2, SL811_CTL2_HOST | SL811_CTL2_DSWAP | SL811_12M_HI); + sl811_write(hc, SL811_CTRL1, SL811_CTRL1_SPEED_LOW | SL811_CTRL1_SOF); + + /* start the SOF or EOP */ + sl811_write(hc, SL811_CTRL_B, SL811_USB_CTRL_ARM); + hc->rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION | USB_PORT_STAT_LOW_SPEED; + mdelay(2); + sl811_write(hc, SL811_INTRSTS, 0xff); + } + + hc->rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION; + sl811_write(hc, SL811_INTR, SL811_INTR_INSRMV); + + return 1; +} + +/* + * Interrupt service routine. + */ +static void sl811_interrupt(int irq, void *__hc, struct pt_regs * r) +{ + __u8 status; + struct sl811_hc *hc = __hc; + + status = sl811_read(hc, SL811_INTRSTS); + if (status == 0) + return ; /* Not me */ + + sl811_write(hc, SL811_INTRSTS, 0xff); + + if (status & SL811_INTR_INSRMV) { + sl811_write(hc, SL811_INTR, 0); + sl811_write(hc, SL811_CTRL1, 0); + // wait for device stable + mdelay(100); + sl811_hc_reset(hc); + return ; + } + + spin_lock(&hc->hc_lock); + + if (status & SL811_INTR_DONE_A) { + if (status & SL811_INTR_SOF) { + sl811_transfer_done(hc, 1); + PDEBUG(4, "sof in done!"); + sl811_start_sof(hc); + } else + sl811_transfer_done(hc, 0); + } else if (status & SL811_INTR_SOF) + sl811_start_sof(hc); + + spin_unlock(&hc->hc_lock); + + return ; +} + +/* + * This function allocates all data structure and store in the + * private data structure. + * + * Return value : data structure for the host controller + */ +static struct sl811_hc* __devinit sl811_alloc_hc(void) +{ + struct sl811_hc *hc; + struct usb_bus *bus; + int i; + + PDEBUG(4, "enter"); + + hc = (struct sl811_hc *)kmalloc(sizeof(struct sl811_hc), GFP_KERNEL); + if (!hc) + return NULL; + + memset(hc, 0, sizeof(struct sl811_hc)); + + hc->rh_status.wPortStatus = USB_PORT_STAT_POWER; + hc->rh_status.wPortChange = 0; + + hc->active_urbs = 0; + INIT_LIST_HEAD(&hc->hc_hcd_list); + list_add(&hc->hc_hcd_list, &sl811_hcd_list); + + init_waitqueue_head(&hc->waitq); + + for (i = 0; i < 6; ++i) + INIT_LIST_HEAD(&hc->urb_list[i]); + + hc->cur_list = &hc->iso_list; + + bus = usb_alloc_bus(&sl811_device_operations); + if (!bus) { + kfree (hc); + return NULL; + } + + hc->bus = bus; + bus->bus_name = MODNAME; + bus->hcpriv = hc; + + return hc; +} + +/* + * This function De-allocate all resources + */ +static void sl811_release_hc(struct sl811_hc *hc) +{ + PDEBUG(4, "enter"); + + /* disconnect all devices */ + if (hc->bus->root_hub) + usb_disconnect(&hc->bus->root_hub); + + // Stop interrupt handle + if (hc->irq) + free_irq(hc->irq, hc); + hc->irq = 0; + + /* Stop interrupt for sharing */ + if (hc->addr_io) { + /* Disable Interrupts */ + sl811_write(hc, SL811_INTR, 0); + + /* Remove all Interrupt events */ + mdelay(2); + sl811_write(hc, SL811_INTRSTS, 0xff); + } + + /* free io regions */ + sl811_release_regions(hc); + + usb_deregister_bus(hc->bus); + usb_free_bus(hc->bus); + + list_del(&hc->hc_hcd_list); + INIT_LIST_HEAD(&hc->hc_hcd_list); + + kfree (hc); +} + +/* + * This function request IO memory regions, request IRQ, and + * allocate all other resources. + * + * Input: addr_io = first IO address + * data_io = second IO address + * irq = interrupt number + * + * Return: 0 = success or error condition + */ +static int __devinit sl811_found_hc(int addr_io, int data_io, int irq) +{ + struct sl811_hc *hc; + + PDEBUG(4, "enter"); + + hc = sl811_alloc_hc(); + if (!hc) + return -ENOMEM; + + if (sl811_request_regions (hc, addr_io, data_io, MODNAME)) { + PDEBUG(1, "ioport %X,%X is in use!", addr_io, data_io); + sl811_release_hc(hc); + return -EBUSY; + } + + if (sl811_reg_test(hc)) { + PDEBUG(1, "SL811 register test failed!"); + sl811_release_hc(hc); + return -ENODEV; + } + +//#ifdef SL811_DEBUG_VERBOSE + { + __u8 u = sl811_read(hc, SL811_HWREV); + + // Show the hardware revision of chip + PDEBUG(1, "SL811 HW: %02Xh", u); + switch (u & 0xF0) { + case 0x00: PDEBUG(1, "SL11H"); break; + case 0x10: PDEBUG(1, "SL811HS rev1.2"); break; + case 0x20: PDEBUG(1, "SL811HS rev1.5"); break; + default: PDEBUG(1, "Revision unknown!"); + } + } +//#endif // SL811_DEBUG_VERBOSE + + sl811_init_irq(); + + usb_register_bus(hc->bus); + + if (request_irq(irq, sl811_interrupt, SA_SHIRQ, MODNAME, hc)) { + PDEBUG(1, "request interrupt %d failed", irq); + sl811_release_hc(hc); + return -EBUSY; + } + hc->irq = irq; + + printk(KERN_INFO __FILE__ ": USB SL811 at %08x,%08x, IRQ %d\n", + hc->addr_io, hc->data_io, irq); + + sl811_hc_reset(hc); + sl811_connect_rh(hc); + + return 0; +} + +/* + * This is an init function, and it is the first function being called + * + * Return: 0 = success or error condition + */ +static int __init sl811_hcd_init(void) +{ + int ret = -ENODEV; + + PDEBUG(4, "enter"); + + info(DRIVER_VERSION " : " DRIVER_DESC); + +#ifdef CONFIG_X86 + { + int count; + // registering some instance + for (count = 0; count < MAX_CONTROLERS; count++) { + if (io[count]) { + ret = sl811_found_hc(io[count], io[count]+OFFSET_DATA_REG, irq[count]); + if (ret) + return (ret); + } + } + } +#endif +#ifdef CONFIG_ARCH_RAMSES + ret = sl811_found_hc(0,0,SL811HS_IRQ); +#endif + + return ret; +} + +/* + * This is a cleanup function, and it is called when module is unloaded. + */ +static void __exit sl811_hcd_cleanup(void) +{ + struct list_head *list = sl811_hcd_list.next; + struct sl811_hc *hc; + + PDEBUG(4, "enter"); + + for (; list != &sl811_hcd_list; ) { + hc = list_entry(list, struct sl811_hc, hc_hcd_list); + list = list->next; + sl811_release_hc(hc); + } +} + +module_init(sl811_hcd_init); +module_exit(sl811_hcd_cleanup); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); --- /dev/null +++ linux-2.4.21/drivers/usb/host/sl811.h @@ -0,0 +1,177 @@ +#ifndef __LINUX_SL811_H +#define __LINUX_SL811_H + +#define SL811_DEBUG + +#ifdef SL811_DEBUG + #define PDEBUG(level, fmt, args...) \ + if (debug >= (level)) info("[%s:%d] " fmt, \ + __PRETTY_FUNCTION__, __LINE__ , ## args) +#else + #define PDEBUG(level, fmt, args...) do {} while(0) +#endif + +//#define SL811_TIMEOUT + +/* Sl811 host control register */ +#define SL811_CTRL_A 0x00 +#define SL811_ADDR_A 0x01 +#define SL811_LEN_A 0x02 +#define SL811_STS_A 0x03 /* read */ +#define SL811_PIDEP_A 0x03 /* write */ +#define SL811_CNT_A 0x04 /* read */ +#define SL811_DEV_A 0x04 /* write */ +#define SL811_CTRL1 0x05 +#define SL811_INTR 0x06 +#define SL811_CTRL_B 0x08 +#define SL811_ADDR_B 0x09 +#define SL811_LEN_B 0x0A +#define SL811_STS_B 0x0B /* read */ +#define SL811_PIDEP_B 0x0B /* write */ +#define SL811_CNT_B 0x0C /* read */ +#define SL811_DEV_B 0x0C /* write */ +#define SL811_INTRSTS 0x0D /* write clears bitwise */ +#define SL811_HWREV 0x0E /* read */ +#define SL811_SOFLOW 0x0E /* write */ +#define SL811_SOFCNTDIV 0x0F /* read */ +#define SL811_CTRL2 0x0F /* write */ + +/* USB control register bits (addr 0x00 and addr 0x08) */ +#define SL811_USB_CTRL_ARM 0x01 +#define SL811_USB_CTRL_ENABLE 0x02 +#define SL811_USB_CTRL_DIR_OUT 0x04 +#define SL811_USB_CTRL_ISO 0x10 +#define SL811_USB_CTRL_SOF 0x20 +#define SL811_USB_CTRL_TOGGLE_1 0x40 +#define SL811_USB_CTRL_PREAMBLE 0x80 + +/* USB status register bits (addr 0x03 and addr 0x0B) */ +#define SL811_USB_STS_ACK 0x01 +#define SL811_USB_STS_ERROR 0x02 +#define SL811_USB_STS_TIMEOUT 0x04 +#define SL811_USB_STS_TOGGLE_1 0x08 +#define SL811_USB_STS_SETUP 0x10 +#define SL811_USB_STS_OVERFLOW 0x20 +#define SL811_USB_STS_NAK 0x40 +#define SL811_USB_STS_STALL 0x80 + +/* Control register 1 bits (addr 0x05) */ +#define SL811_CTRL1_SOF 0x01 +#define SL811_CTRL1_RESET 0x08 +#define SL811_CTRL1_JKSTATE 0x10 +#define SL811_CTRL1_SPEED_LOW 0x20 +#define SL811_CTRL1_SUSPEND 0x40 + +/* Interrut enable (addr 0x06) and interrupt status register bits (addr 0x0D) */ +#define SL811_INTR_DONE_A 0x01 +#define SL811_INTR_DONE_B 0x02 +#define SL811_INTR_SOF 0x10 +#define SL811_INTR_INSRMV 0x20 +#define SL811_INTR_DETECT 0x40 +#define SL811_INTR_NOTPRESENT 0x40 +#define SL811_INTR_SPEED_FULL 0x80 /* only in status reg */ + +/* HW rev and SOF lo register bits (addr 0x0E) */ +#define SL811_HWR_HWREV 0xF0 + +/* SOF counter and control reg 2 (addr 0x0F) */ +#define SL811_CTL2_SOFHI 0x3F +#define SL811_CTL2_DSWAP 0x40 +#define SL811_CTL2_HOST 0x80 + +/* Set up for 1-ms SOF time. */ +#define SL811_12M_LOW 0xE0 +#define SL811_12M_HI 0x2E + +#define SL811_DATA_START 0x10 +#define SL811_DATA_LIMIT 240 + + +/* Requests: bRequest << 8 | bmRequestType */ +#define RH_GET_STATUS 0x0080 +#define RH_CLEAR_FEATURE 0x0100 +#define RH_SET_FEATURE 0x0300 +#define RH_SET_ADDRESS 0x0500 +#define RH_GET_DESCRIPTOR 0x0680 +#define RH_SET_DESCRIPTOR 0x0700 +#define RH_GET_CONFIGURATION 0x0880 +#define RH_SET_CONFIGURATION 0x0900 +#define RH_GET_STATE 0x0280 +#define RH_GET_INTERFACE 0x0A80 +#define RH_SET_INTERFACE 0x0B00 +#define RH_SYNC_FRAME 0x0C80 + + +#define PIDEP(pid, ep) (((pid) & 0x0f) << 4 | (ep)) + +/* Virtual Root HUB */ +struct virt_root_hub { + int devnum; /* Address of Root Hub endpoint */ + void *urb; /* interrupt URB of root hub */ + int send; /* active flag */ + int interval; /* intervall of roothub interrupt transfers */ + struct timer_list rh_int_timer; /* intervall timer for rh interrupt EP */ +}; + +struct sl811_td { + /* hardware */ + __u8 ctrl; /* control register */ + + /* write */ + __u8 addr; /* base adrress register */ + __u8 len; /* base length register */ + __u8 pidep; /* PId and endpoint register */ + __u8 dev; /* device address register */ + + /* read */ + __u8 status; /* status register */ + __u8 left; /* transfer count register */ + + /* software */ + __u8 errcnt; /* error count, begin with 3 */ + __u8 done; /* is this td tranfer done */ + __u8 *buf; /* point to data buffer for tranfer */ + int bustime; /* the bus time need by this td */ + int td_status; /* the status of this td */ + int nakcnt; /* number of naks */ + struct urb *urb; /* the urb this td belongs to */ + struct list_head td_list; /* link to a list of the urb */ +}; + +struct sl811_urb_priv { + struct urb *urb; /* the urb this priv beloings to */ + struct list_head td_list; /* list of all the td of this urb */ + struct sl811_td *cur_td; /* current td is in processing or it will be */ + struct sl811_td *first_td; /* the first td of this urb */ + struct sl811_td *last_td; /* the last td of this urb */ + int interval; /* the query time value for intr urb */ + int unlink; /* is the this urb unlinked */ + unsigned long inserttime; /* the time when insert to list */ +}; + +struct sl811_hc { + spinlock_t hc_lock; /* Lock for this structure */ + + int irq; /* IRQ number this hc use */ + int addr_io; /* I/O address line address */ + int data_io; /* I/O data line address */ + struct virt_root_hub rh; /* root hub */ + struct usb_port_status rh_status;/* root hub port status */ + struct list_head urb_list[6]; /* set of urbs, the order is iso,intr,ctrl,bulk,inactive intr, wait */ + struct list_head *cur_list; /* the current list is in process */ + wait_queue_head_t waitq; /* deletion of URBs and devices needs a waitqueue */ + struct sl811_td *cur_td; /* point to the td is in process */ + struct list_head hc_hcd_list; /* list of all hci_hcd */ + struct usb_bus *bus; /* our bus */ + int active_urbs; /* total number of active usbs */ + int frame_number; /* the current frame number, we do't use it, any one need it? */ +}; + +#define iso_list urb_list[0] /* set of isoc urbs */ +#define intr_list urb_list[1] /* ordered (tree) set of int urbs */ +#define ctrl_list urb_list[2] /* set of ctrl urbs */ +#define bulk_list urb_list[3] /* set of bulk urbs */ +#define idle_intr_list urb_list[4] /* set of intr urbs in its idle time*/ +#define wait_list urb_list[5] /* set of wait urbs */ + +#endif --- linux-2.4.21/drivers/usb/storage/transport.h~usb-sonycamera +++ linux-2.4.21/drivers/usb/storage/transport.h @@ -75,6 +75,8 @@ #define US_PR_JUMPSHOT 0xf3 /* Lexar Jumpshot */ #endif +#define US_PR_DEVICE 0xff /* Use device's value */ + /* * Bulk only data structures */ --- linux-2.4.21/drivers/usb/storage/unusual_devs.h~usb-sonycamera +++ linux-2.4.21/drivers/usb/storage/unusual_devs.h @@ -223,10 +223,10 @@ US_FL_FIX_INQUIRY | US_FL_START_STOP ), /* This entry is needed because the device reports Sub=ff */ -UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0440, +UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450, "Sony", - "DSC-S30/S70/S75/505V/F505/F707/F717", - US_SC_SCSI, US_PR_CB, NULL, + "DSC-S30/S70/S75/505V/F505/F707/F717/P8", + US_SC_SCSI, US_PR_DEVICE, NULL, US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ), /* Reported by wim@geeks.nl */ --- linux-2.4.21/drivers/usb/storage/usb.c~usb-sonycamera +++ linux-2.4.21/drivers/usb/storage/usb.c @@ -622,7 +622,9 @@ /* Determine subclass and protocol, or copy from the interface */ subclass = unusual_dev->useProtocol; - protocol = unusual_dev->useTransport; + protocol = (unusual_dev->useTransport == US_PR_DEVICE) ? + altsetting->bInterfaceProtocol : + unusual_dev->useTransport; flags = unusual_dev->flags; /* --- linux-2.4.21/drivers/video/fbcon-cfb16.c~fb-turn180 +++ linux-2.4.21/drivers/video/fbcon-cfb16.c @@ -34,6 +34,41 @@ #endif }; +static u8 mirrortab_cfb16[] = { + 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0, + 0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0, + 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8, + 0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8, + 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4, + 0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4, + 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC, + 0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC, + 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2, + 0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2, + 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA, + 0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA, + 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6, + 0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6, + 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE, + 0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE, + 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1, + 0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1, + 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9, + 0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9, + 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5, + 0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5, + 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED, + 0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD, + 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3, + 0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3, + 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB, + 0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB, + 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7, + 0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7, + 0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF, + 0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF +}; + void fbcon_cfb16_setup(struct display *p) { p->next_line = p->line_length ? p->line_length : p->var.xres_virtual<<1; @@ -46,6 +81,53 @@ int bytes = p->next_line, linesize = bytes * fontheight(p), rows; u8 *src, *dst; + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + char *scrn_end = p->screen_base + p->var.xres*p->var.yres * 2; +/* + printk("---@paul@-------------------------\n"\ + "fbcon_cfb16_bmove() %d %d %d %d %d %d\n", + sx,sy,dx,dy,height,width + ); +*/ + if (sx == 0 && dx == 0 && width * fontwidth(p) * 2 == bytes) + { + fb_memmove( + scrn_end - dy * linesize, + scrn_end - sy * linesize, + height * linesize + ); + return; + } + if (fontwidthlog(p)) { + sx <<= fontwidthlog(p)+1; + dx <<= fontwidthlog(p)+1; + width <<= fontwidthlog(p)+1; + } else { + sx *= fontwidth(p)*2; + dx *= fontwidth(p)*2; + width *= fontwidth(p)*2; + } + if (dy < sy || (dy == sy && dx < sx)) { + src = scrn_end + sy * linesize + sx; + dst = scrn_end + dy * linesize + dx; + for (rows = height * fontheight(p); rows--;) + { + fb_memmove(dst, src, width); + src += bytes; + dst += bytes; + } + } else { + src = scrn_end + (sy+height) * linesize + sx - bytes; + dst = scrn_end + (dy+height) * linesize + dx - bytes; + for (rows = height * fontheight(p); rows--;) + { + fb_memmove(dst, src, width); + src -= bytes; + dst -= bytes; + } + } +/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */ + } else { if (sx == 0 && dx == 0 && width * fontwidth(p) * 2 == bytes) { fb_memmove(p->screen_base + dy * linesize, p->screen_base + sy * linesize, @@ -78,6 +160,8 @@ dst -= bytes; } } + } +/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */ } static inline void rectfill(u8 *dest, int width, int height, u32 data, @@ -108,10 +192,16 @@ int bytes = p->next_line, lines = height * fontheight(p); u32 bgx; - dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p) * 2; - - bgx = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]; - + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + dest = p->screen_base + + p->var.xres*p->var.yres * 2 + - (sy+height) * fontheight(p) * bytes + + sx * fontwidth(p) * 2; + bgx = 1; + } else { + dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p) * 2; + bgx = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]; + } width *= fontwidth(p)/4; if (width * 8 == bytes) rectfill(dest, lines * width * 4, 1, bgx, bytes); @@ -126,14 +216,69 @@ int bytes = p->next_line, rows; u32 eorx, fgx, bgx; - dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2; - fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p, c)]; bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p, c)]; fgx |= (fgx << 16); bgx |= (bgx << 16); eorx = fgx ^ bgx; + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + dest = p->screen_base + + p->var.xres*p->var.yres * 2 + - yy * fontheight(p) * bytes + - xx * fontwidth(p) * 2; + + switch (fontwidth(p)) { + case 4: + cdat = p->fontdata + (c & p->charmask) * fontheight(p); + for (rows = fontheight(p); rows--; dest += bytes) + { + bits = mirrortab_cfb16[*cdat++]; + fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-8); + fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-4); + } + case 8: + cdat = p->fontdata + (c & p->charmask) * fontheight(p); + for (rows = fontheight(p); rows--; dest += bytes) + { + bits = mirrortab_cfb16[*cdat++]; + fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-16); + fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-12); + fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-8); + fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-4); + } + break; + case 12: + cdat = p->fontdata + ((c & p->charmask) * fontheight(p) << 1); + for (rows = fontheight(p); rows--; dest += bytes) { + bits = mirrortab_cfb16[*cdat++]; + fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-24); + fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-20); + fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-16); + fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-12); + bits = mirrortab_cfb16[*cdat++]; + fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-8); + fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-4); + } + case 16: + cdat = p->fontdata + ((c & p->charmask) * fontheight(p) << 1); + for (rows = fontheight(p); rows--; dest += bytes) { + bits = mirrortab_cfb16[*cdat++]; + fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-32); + fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-28); + fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-24); + fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-20); + bits = mirrortab_cfb16[*cdat++]; + fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-16); + fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-12); + fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-8); + fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-4); + } + break; + } +/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */ + } else { + dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2; switch (fontwidth(p)) { case 4: case 8: @@ -167,6 +312,8 @@ } break; } + } +/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */ } void fbcon_cfb16_putcs(struct vc_data *conp, struct display *p, @@ -177,7 +324,6 @@ int rows, bytes = p->next_line; u32 eorx, fgx, bgx; - dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2; c = scr_readw(s); fgx = ((u16 *)p->dispsw_data)[attr_fgcol(p, c)]; bgx = ((u16 *)p->dispsw_data)[attr_bgcol(p, c)]; @@ -185,6 +331,81 @@ bgx |= (bgx << 16); eorx = fgx ^ bgx; + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + dest0 = p->screen_base + + p->var.xres * p->var.yres * 2 + - yy * fontheight(p) * bytes + - xx * fontwidth(p) * 2; + + switch (fontwidth(p)) { + case 4: + while (count--) { + c = scr_readw(s++) & p->charmask; + cdat = p->fontdata + c * fontheight(p); + for (rows = fontheight(p), dest = dest0; rows--; dest -= bytes) + { + u8 bits = mirrortab_cfb16[*cdat++]; + fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-8); + fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-4); + } + dest0 -= fontwidth(p)*2; + } + case 8: + while (count--) { + c = scr_readw(s++) & p->charmask; + cdat = p->fontdata + c * fontheight(p); + for (rows = fontheight(p), dest = dest0; rows--; dest -= bytes) + { + u8 bits = mirrortab_cfb16[*cdat++]; + fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-16); + fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-12); + fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-8); + fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-4); + } + dest0 -= fontwidth(p)*2; + } + break; + case 12: + while (count--) { + c = scr_readw(s++) & p->charmask; + cdat = p->fontdata + (c * fontheight(p) << 1); + for (rows = fontheight(p), dest = dest0; rows--; dest -= bytes) + { + u8 bits = mirrortab_cfb16[*cdat++]; + fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-24); + fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-20); + fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-16); + fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-12); + bits = mirrortab_cfb16[*cdat++]; + fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-8); + fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-4); + } + dest0 -= fontwidth(p)*2; + } + case 16: + while (count--) { + c = scr_readw(s++) & p->charmask; + cdat = p->fontdata + (c * fontheight(p) << 1); + for (rows = fontheight(p), dest = dest0; rows--; dest -= bytes) + { + u8 bits = mirrortab_cfb16[*cdat++]; + fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-32); + fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-28); + fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-24); + fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-20); + bits = mirrortab_cfb16[*cdat++]; + fb_writel((tab_cfb16[bits >> 6] & eorx) ^ bgx, dest-16); + fb_writel((tab_cfb16[bits >> 4 & 3] & eorx) ^ bgx, dest-12); + fb_writel((tab_cfb16[bits >> 2 & 3] & eorx) ^ bgx, dest-8); + fb_writel((tab_cfb16[bits & 3] & eorx) ^ bgx, dest-4); + } + dest0 -= fontwidth(p)*2; + } + break; + } +/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */ + } else { + dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p) * 2; switch (fontwidth(p)) { case 4: case 8: @@ -226,6 +447,8 @@ } break; } + } +/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */ } void fbcon_cfb16_revc(struct display *p, int xx, int yy) @@ -233,6 +456,32 @@ u8 *dest; int bytes = p->next_line, rows; + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + dest = p->screen_base + + p->var.xres*p->var.yres * 2 + - yy * fontheight(p) * bytes + - xx * fontwidth(p) * 2; + for (rows = fontheight(p); rows--; dest -= bytes) { + switch (fontwidth(p)) { + case 16: + fb_writel(fb_readl(dest-32) ^ 0xffffffff, dest-32); + fb_writel(fb_readl(dest-28) ^ 0xffffffff, dest-28); + /* FALL THROUGH */ + case 12: + fb_writel(fb_readl(dest-24) ^ 0xffffffff, dest-24); + fb_writel(fb_readl(dest-20) ^ 0xffffffff, dest-20); + /* FALL THROUGH */ + case 8: + fb_writel(fb_readl(dest-16) ^ 0xffffffff, dest-16); + fb_writel(fb_readl(dest-12) ^ 0xffffffff, dest-12); + /* FALL THROUGH */ + case 4: + fb_writel(fb_readl(dest-8) ^ 0xffffffff, dest-8); + fb_writel(fb_readl(dest-4) ^ 0xffffffff, dest-4); + } + } +/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */ + } else { dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p)*2; for (rows = fontheight(p); rows--; dest += bytes) { switch (fontwidth(p)) { @@ -253,6 +502,8 @@ fb_writel(fb_readl(dest+4) ^ 0xffffffff, dest+4); } } + } +/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */ } void fbcon_cfb16_clear_margins(struct vc_data *conp, struct display *p, @@ -268,6 +519,9 @@ bgx = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)]; if (!bottom_only && (right_width = p->var.xres-right_start)) + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + printk("---@paul@------------------------- fbcon-cfb16 clear margins\n"); + } rectfill(p->screen_base+right_start*2, right_width, p->var.yres_virtual, bgx, bytes); if ((bottom_width = p->var.yres-bottom_start)) --- linux-2.4.21/drivers/video/fbcon-cfb8.c~fb-turn180 +++ linux-2.4.21/drivers/video/fbcon-cfb8.c @@ -39,6 +39,41 @@ #endif }; +static u8 mirrortab_cfb8[] = { + 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0, + 0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0, + 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8, + 0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8, + 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4, + 0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4, + 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC, + 0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC, + 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2, + 0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2, + 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA, + 0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA, + 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6, + 0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6, + 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE, + 0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE, + 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1, + 0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1, + 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9, + 0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9, + 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5, + 0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5, + 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED, + 0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD, + 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3, + 0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3, + 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB, + 0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB, + 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7, + 0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7, + 0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF, + 0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF +}; + void fbcon_cfb8_setup(struct display *p) { p->next_line = p->line_length ? p->line_length : p->var.xres_virtual; @@ -51,10 +86,57 @@ int bytes = p->next_line, linesize = bytes * fontheight(p), rows; u8 *src,*dst; + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { +/* + printk("---@paul@-------------------------\n"\ + "fbcon_cfb8_bmove() %d %d %d %d %d %d\n", + sx,sy,dx,dy,height,width + ); +*/ + if (sx == 0 && dx == 0 && width * fontwidth(p) == bytes) + { + fb_memmove( + p->screen_base + p->var.xres*p->var.yres - dy * linesize, + p->screen_base + p->var.xres*p->var.yres - sy * linesize, + height * linesize); + return; + } + if (fontwidthlog(p)) { + sx <<= fontwidthlog(p); dx <<= fontwidthlog(p); width <<= fontwidthlog(p); + } else { + sx *= fontwidth(p); dx *= fontwidth(p); width *= fontwidth(p); + } + if (dy < sy || (dy == sy && dx < sx)) + { + src = p->screen_base + p->var.xres*p->var.yres + - sy * linesize - sx; + dst = p->screen_base + p->var.xres*p->var.yres + - dy * linesize - dx; + for (rows = height * fontheight(p) ; rows-- ;) + { + fb_memmove(dst, src, width); + src += bytes; + dst += bytes; + } + } else + { + src = p->screen_base + p->var.xres*p->var.yres + - (sy+height) * linesize - sx + bytes; + dst = p->screen_base + p->var.xres*p->var.yres + - (dy+height) * linesize - dx + bytes; + for (rows = height * fontheight(p) ; rows-- ;) + { + fb_memmove(dst, src, width); + src -= bytes; + dst -= bytes; + } + } +/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */ + } else { if (sx == 0 && dx == 0 && width * fontwidth(p) == bytes) { - fb_memmove(p->screen_base + dy * linesize, - p->screen_base + sy * linesize, - height * linesize); + fb_memmove(p->screen_base + dy * linesize, + p->screen_base + sy * linesize, + height * linesize); return; } if (fontwidthlog(p)) { @@ -79,6 +161,7 @@ dst -= bytes; } } +/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */ } static inline void rectfill(u8 *dest, int width, int height, u8 data, @@ -97,11 +180,17 @@ int bytes=p->next_line,lines=height * fontheight(p); u8 bgx; - dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p); - - bgx=attr_bgcol_ec(p,conp); - - width *= fontwidth(p); + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + bgx=attr_bgcol_ec(p,conp); + width *= fontwidth(p); + dest = p->screen_base + p->var.xres*p->var.yres + - (sy+height) * fontheight(p) * bytes + + sx * fontwidth(p); + } else { + dest = p->screen_base + sy * fontheight(p) * bytes + sx * fontwidth(p); + bgx=attr_bgcol_ec(p,conp); + width *= fontwidth(p); + } if (width == bytes) rectfill(dest, lines * width, 1, bgx, bytes); else @@ -114,8 +203,8 @@ u8 *dest,*cdat; int bytes=p->next_line,rows; u32 eorx,fgx,bgx; + u8 chrrow; - dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p); if (fontwidth(p) <= 8) cdat = p->fontdata + (c & p->charmask) * fontheight(p); else @@ -129,6 +218,53 @@ bgx |= (bgx << 16); eorx = fgx ^ bgx; + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + dest = p->screen_base + + p->var.xres*p->var.yres + - yy * fontheight(p) * bytes + - xx * fontwidth(p); + + switch (fontwidth(p)) { + case 4: + for (rows = fontheight(p) ; rows-- ; dest += bytes) + { + chrrow = mirrortab_cfb8[*cdat++]; + fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-4); + } + break; + case 8: + for (rows = fontheight(p) ; rows-- ; dest += bytes) + { + chrrow = mirrortab_cfb8[*cdat++]; + fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-8); + fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-4); + } + break; + case 12: + for (rows = fontheight(p) ; rows-- ; dest += bytes) + { + chrrow = mirrortab_cfb8[*cdat++]; + fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-12); + fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-8); + chrrow = mirrortab_cfb8[*cdat++]; + fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-4); + } + break; + case 16: + for (rows = fontheight(p) ; rows-- ; dest += bytes) + { + chrrow = mirrortab_cfb8[*cdat++]; + fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-16); + fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-12); + chrrow = mirrortab_cfb8[*cdat++]; + fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-8); + fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-4); + } + break; + } +/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */ + } else { + dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p); switch (fontwidth(p)) { case 4: for (rows = fontheight(p) ; rows-- ; dest += bytes) @@ -152,6 +288,8 @@ } break; } + } +/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */ } void fbcon_cfb8_putcs(struct vc_data *conp, struct display *p, @@ -161,8 +299,8 @@ u16 c; int rows,bytes=p->next_line; u32 eorx, fgx, bgx; + u8 chrrow; - dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p); c = scr_readw(s); fgx = attr_fgcol(p, c); bgx = attr_bgcol(p, c); @@ -171,6 +309,76 @@ bgx |= (bgx << 8); bgx |= (bgx << 16); eorx = fgx ^ bgx; + + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + dest0 = p->screen_base + + p->var.xres*p->var.yres + - yy * fontheight(p) * bytes + - xx * fontwidth(p); + switch (fontwidth(p)) { + case 4: + while (count--) { + c = scr_readw(s++) & p->charmask; + cdat = p->fontdata + c * fontheight(p); + + for (rows = fontheight(p), dest = dest0; rows-- ; dest -= bytes) + { + chrrow = mirrortab_cfb8[*cdat++]; + fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-4); + } + dest0 -= 4; + } + break; + case 8: + while (count--) { + c = scr_readw(s++) & p->charmask; + cdat = p->fontdata + c * fontheight(p); + for (rows = fontheight(p), dest = dest0; rows-- ; dest -= bytes) + { + chrrow = mirrortab_cfb8[*cdat++]; + fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-8); + fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-4); + } + dest0 -= 8; + } + break; + case 12: + while (count--) { + c = scr_readw(s++) & p->charmask; + cdat = p->fontdata + (c * fontheight(p) << 1); + + for (rows = fontheight(p), dest = dest0; rows-- ; dest -= bytes) + { + chrrow = mirrortab_cfb8[*cdat++]; + fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-12); + fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-8); + chrrow = mirrortab_cfb8[*cdat++]; + fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-4); + } + dest0 -= fontwidth(p); + } + break; + case 16: + while (count--) { + c = scr_readw(s++) & p->charmask; + cdat = p->fontdata + (c * fontheight(p) << 1); + + for (rows = fontheight(p), dest = dest0; rows-- ; dest -= bytes) + { + chrrow = mirrortab_cfb8[*cdat++]; + fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-16); + fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-12); + chrrow = mirrortab_cfb8[*cdat++]; + fb_writel((nibbletab_cfb8[chrrow >> 4] & eorx) ^ bgx, dest-8); + fb_writel((nibbletab_cfb8[chrrow & 0xf] & eorx) ^ bgx, dest-4); + } + dest0 -= fontwidth(p); + } + break; + } /* switch (fontwidth(p)) */ +/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */ + } else { + dest0 = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p); switch (fontwidth(p)) { case 4: while (count--) { @@ -212,6 +420,8 @@ } break; } + } +/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */ } void fbcon_cfb8_revc(struct display *p, int xx, int yy) @@ -219,6 +429,21 @@ u8 *dest; int bytes=p->next_line, rows; + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + dest = p->screen_base + p->var.xres*p->var.yres + - yy * fontheight(p) * bytes + - xx * fontwidth(p); + for (rows = fontheight(p) ; rows-- ; dest -= bytes) { + switch (fontwidth(p)) { + case 16: fb_writel(fb_readl(dest-16) ^ 0x0f0f0f0f, dest-16); /* fall thru */ + case 12: fb_writel(fb_readl(dest-12) ^ 0x0f0f0f0f, dest-12); /* fall thru */ + case 8: fb_writel(fb_readl(dest-8) ^ 0x0f0f0f0f, dest-8); /* fall thru */ + case 4: fb_writel(fb_readl(dest-4) ^ 0x0f0f0f0f, dest-4); /* fall thru */ + default: break; + } + } +/* if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */ + } else { dest = p->screen_base + yy * fontheight(p) * bytes + xx * fontwidth(p); for (rows = fontheight(p) ; rows-- ; dest += bytes) { switch (fontwidth(p)) { @@ -229,6 +454,8 @@ default: break; } } + } +/* elseif ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) */ } void fbcon_cfb8_clear_margins(struct vc_data *conp, struct display *p, @@ -244,6 +471,9 @@ bgx=attr_bgcol_ec(p,conp); if (!bottom_only && (right_width = p->var.xres-right_start)) + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + printk("---@paul@------------------------- fbcon-cfb8 clear margins\n"); + } rectfill(p->screen_base+right_start, right_width, p->var.yres_virtual, bgx, bytes); if ((bottom_width = p->var.yres-bottom_start)) --- linux-2.4.21/drivers/video/fbcon.c~fb-turn180 +++ linux-2.4.21/drivers/video/fbcon.c @@ -1558,6 +1558,7 @@ update_region(fg_console, conp->vc_origin + conp->vc_size_row * conp->vc_top, conp->vc_size_row * (conp->vc_bottom - conp->vc_top) / 2); + conp->vc_top = 0; return 0; } return 1; @@ -2209,7 +2210,16 @@ src = logo; bdepth = depth/8; for( y1 = 0; y1 < LOGO_H; y1++ ) { - dst = fb + y1*line + x*bdepth; + + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { +/* + Das ist NICHT die richtige Stelle für den Ramses 16 BPP Modus + aber dafür die weiter unten. +*/ + dst = fb + p->var.xres*p->var.yres*bdepth -1 - y1*line - x*bdepth; + } else { + dst = fb + y1*line + x*bdepth; + } for( x1 = 0; x1 < LOGO_W; x1++, src++ ) { val = (*src << redshift) | (*src << greenshift) | @@ -2217,18 +2227,32 @@ if (bdepth == 4 && !((long)dst & 3)) { /* Some cards require 32bit access */ fb_writel (val, dst); - dst += 4; + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + dst -= 4; + } else { + dst += 4; + } } else if (bdepth == 2 && !((long)dst & 1)) { /* others require 16bit access */ fb_writew (val,dst); - dst +=2; + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + dst -= 2; + } else { + dst +=2; + } } else { + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + for( i = bdepth-1; i >= 0; --i ) + fb_writeb (val >> (i*8), dst--); + + } else { #ifdef __LITTLE_ENDIAN - for( i = 0; i < bdepth; ++i ) + for( i = 0; i < bdepth; ++i ) #else - for( i = bdepth-1; i >= 0; --i ) + for( i = bdepth-1; i >= 0; --i ) #endif - fb_writeb (val >> (i*8), dst++); + fb_writeb (val >> (i*8), dst++); + } } } } @@ -2239,28 +2263,42 @@ src = linux_logo16; bdepth = (depth+7)/8; for( y1 = 0; y1 < LOGO_H; y1++ ) { - dst = fb + y1*line + x*bdepth; + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + dst = fb + p->var.xres*p->var.yres*bdepth -1 - y1*line - x*bdepth; + } else { + dst = fb + y1*line + x*bdepth; + } for( x1 = 0; x1 < LOGO_W/2; x1++, src++ ) { pix = *src >> 4; /* upper nibble */ val = (pix << redshift) | (pix << greenshift) | (pix << blueshift); + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + for( i = bdepth-1; i >= 0; --i ) + fb_writeb (val >> (i*8), dst--); + } else { #ifdef __LITTLE_ENDIAN - for( i = 0; i < bdepth; ++i ) + for( i = 0; i < bdepth; ++i ) #else - for( i = bdepth-1; i >= 0; --i ) + for( i = bdepth-1; i >= 0; --i ) #endif - fb_writeb (val >> (i*8), dst++); + fb_writeb (val >> (i*8), dst++); + } pix = *src & 0x0f; /* lower nibble */ val = (pix << redshift) | (pix << greenshift) | (pix << blueshift); + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + for( i = bdepth-1; i >= 0; --i ) + fb_writeb (val >> (i*8), dst--); + } else { #ifdef __LITTLE_ENDIAN - for( i = 0; i < bdepth; ++i ) + for( i = 0; i < bdepth; ++i ) #else - for( i = bdepth-1; i >= 0; --i ) + for( i = bdepth-1; i >= 0; --i ) #endif - fb_writeb (val >> (i*8), dst++); + fb_writeb (val >> (i*8), dst++); + } } } } @@ -2287,7 +2325,11 @@ src = logo; for( y1 = 0; y1 < LOGO_H; y1++ ) { - dst = fb + y1*line + x*bdepth; + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + dst = fb + p->var.xres*p->var.yres*bdepth -1 - y1*line - x*bdepth; + } else { + dst = fb + y1*line + x*bdepth; + } for( x1 = 0; x1 < LOGO_W; x1++, src++ ) { val = safe_shift((linux_logo_red[*src-32] & redmask), redshift) | safe_shift((linux_logo_green[*src-32] & greenmask), greenshift) | @@ -2295,18 +2337,31 @@ if (bdepth == 4 && !((long)dst & 3)) { /* Some cards require 32bit access */ fb_writel (val, dst); - dst += 4; + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + dst -= 4; + } else { + dst += 4; + } } else if (bdepth == 2 && !((long)dst & 1)) { /* others require 16bit access */ fb_writew (val,dst); - dst +=2; + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + dst -= 2; + } else { + dst +=2; + } } else { + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + for( i = bdepth-1; i >= 0; --i ) + fb_writeb (val >> (i*8), dst--); + } else { #ifdef __LITTLE_ENDIAN - for( i = 0; i < bdepth; ++i ) + for( i = 0; i < bdepth; ++i ) #else - for( i = bdepth-1; i >= 0; --i ) + for( i = bdepth-1; i >= 0; --i ) #endif - fb_writeb (val >> (i*8), dst++); + fb_writeb (val >> (i*8), dst++); + } } } } @@ -2331,13 +2386,24 @@ if (depth == 8 && p->type == FB_TYPE_PACKED_PIXELS) { /* depth 8 or more, packed, with color registers */ - src = logo; - for( y1 = 0; y1 < LOGO_H; y1++ ) { - dst = fb + y1*line + x; - for( x1 = 0; x1 < LOGO_W; x1++ ) - fb_writeb (*src++, dst++); - } - done = 1; + if ( ramses_flags & RAMSES_FLAGS_LCD_FBTURN) { + src = logo; + for( y1 = 0; y1 < LOGO_H; y1++ ) + { + dst = fb + p->var.xres*p->var.yres -1 - y1*line - x; + for( x1 = 0; x1 < LOGO_W; x1++ ) + fb_writeb (*src++, dst--); + } + done = 1; + } else { + src = logo; + for( y1 = 0; y1 < LOGO_H; y1++ ) { + dst = fb + y1*line + x; + for( x1 = 0; x1 < LOGO_W; x1++ ) + fb_writeb (*src++, dst++); + } + done = 1; + } } #endif #if defined(CONFIG_FBCON_AFB) || defined(CONFIG_FBCON_ILBM) || \ --- linux-2.4.21/drivers/video/fbmem.c~fb-buffered +++ linux-2.4.21/drivers/video/fbmem.c @@ -302,7 +302,7 @@ { "sa1100", sa1100fb_init, NULL }, #endif #ifdef CONFIG_FB_PXA - { "pxa", pxafb_init, NULL }, + { "pxa", pxafb_init, NULL }, #endif #ifdef CONFIG_FB_SUN3 { "sun3", sun3fb_init, sun3fb_setup }, @@ -672,7 +672,11 @@ #elif defined(__hppa__) pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; #elif defined(__ia64__) || defined(__arm__) +#ifdef CONFIG_PXA + vma->vm_page_prot = pgprot_noncached_buffered(vma->vm_page_prot); +#else vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); +#endif #elif defined(__hppa__) pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; #else --- linux-2.4.21/drivers/video/pxafb.c~ramses-lcd +++ linux-2.4.21/drivers/video/pxafb.c @@ -45,8 +45,6 @@ #include