linux-cvs-patches
[Top] [All Lists]

CVS Update@linux-mips.org: linux

To: linux-cvs-patches@linux-mips.org
Subject: CVS Update@linux-mips.org: linux
From: ralf@linux-mips.org
Date: Mon, 01 Aug 2005 19:25:19 +0100
Reply-to: linux-mips@linux-mips.org
Sender: linux-cvs-patches-bounce@linux-mips.org
CVSROOT:        /home/cvs
Module name:    linux
Changes by:     ralf@ftp.linux-mips.org 05/08/01 19:25:09

Modified files:
        .              : CREDITS MAINTAINERS Makefile README 
        Documentation  : Changes dontdiff feature-removal-schedule.txt 
        Documentation/filesystems: inotify.txt ntfs.txt 
        Documentation/infiniband: user_mad.txt 
        Documentation/pcmcia: driver-changes.txt 
        Documentation/scsi: scsi_mid_low_api.txt 
        Documentation/sound/alsa: ALSA-Configuration.txt 
        arch/alpha/kernel: process.c systbls.S 
        arch/arm/boot/compressed: head-shark.S 
        arch/arm/configs: bast_defconfig s3c2410_defconfig 
                          shark_defconfig 
        arch/arm/kernel: process.c smp.c traps.c 
        arch/arm/lib   : bitops.h io-shark.c 
        arch/arm/mach-integrator: platsmp.c 
        arch/arm/mach-omap1: leds-h2p2-debug.c 
        arch/arm/mach-s3c2410: Makefile clock.c dma.c irq.c mach-bast.c 
        arch/arm/mach-shark: core.c 
        arch/arm/mm    : mm-armv.c 
        arch/arm/nwfpe : fpa11.h fpmodule.c fpmodule.inl 
        arch/arm/plat-omap: ocpi.c 
        arch/arm26/kernel: process.c 
        arch/cris      : Kconfig.debug Makefile defconfig 
        arch/cris/arch-v10: Kconfig 
        arch/cris/arch-v10/boot: Makefile 
        arch/cris/arch-v10/boot/compressed: Makefile head.S 
        arch/cris/arch-v10/boot/rescue: Makefile head.S 
        arch/cris/arch-v10/drivers: Kconfig axisflashmap.c ds1302.c 
                                    eeprom.c gpio.c i2c.c pcf8563.c 
        arch/cris/arch-v10/kernel: Makefile debugport.c entry.S 
                                   fasttimer.c head.S irq.c kgdb.c 
                                   process.c ptrace.c shadows.c traps.c 
        arch/cris/arch-v10/mm: fault.c init.c tlb.c 
        arch/cris/kernel: Makefile crisksyms.c irq.c module.c process.c 
                          ptrace.c setup.c time.c traps.c 
        arch/cris/mm   : fault.c ioremap.c tlb.c 
        arch/h8300/kernel: process.c 
        arch/i386      : Kconfig.debug 
        arch/i386/kernel: apm.c i387.c process.c reboot.c setup.c 
        arch/i386/kernel/cpu/cpufreq: powernow-k8.c 
        arch/i386/mach-visws: reboot.c 
        arch/i386/mach-voyager: voyager_basic.c voyager_smp.c 
        arch/i386/pci  : irq.c 
        arch/ia64      : Kconfig 
        arch/ia64/configs: sn2_defconfig 
        arch/ia64/kernel: entry.S process.c setup.c topology.c unwind.c 
        arch/ia64/lib  : flush.S 
        arch/ia64/pci  : pci.c 
        arch/ia64/sn/kernel: io_init.c xpc_channel.c xpc_main.c 
        arch/ia64/sn/pci: pci_dma.c tioca_provider.c 
        arch/ia64/sn/pci/pcibr: pcibr_provider.c 
        arch/m32r      : Kconfig.debug 
        arch/m32r/kernel: process.c 
        arch/m68k/kernel: process.c 
        arch/m68knommu/kernel: process.c 
        arch/mips      : defconfig 
        arch/mips/configs: atlas_defconfig capcella_defconfig 
                           cobalt_defconfig db1000_defconfig 
                           db1100_defconfig db1500_defconfig 
                           db1550_defconfig ddb5476_defconfig 
                           ddb5477_defconfig decstation_defconfig 
                           e55_defconfig ev64120_defconfig 
                           ev96100_defconfig ip22_defconfig 
                           ip27_defconfig ip32_defconfig 
                           it8172_defconfig ivr_defconfig 
                           jaguar-atx_defconfig jmr3927_defconfig 
                           lasat200_defconfig malta_defconfig 
                           mpc30x_defconfig ocelot_3_defconfig 
                           ocelot_c_defconfig ocelot_defconfig 
                           ocelot_g_defconfig pb1100_defconfig 
                           pb1500_defconfig pb1550_defconfig 
                           pnx8550-jbs_defconfig pnx8550-v2pci_defconfig 
                           qemu_defconfig rbhma4500_defconfig 
                           rm200_defconfig sb1250-swarm_defconfig 
                           sead_defconfig tb0226_defconfig 
                           tb0229_defconfig workpad_defconfig 
                           yosemite_defconfig 
        arch/mips/kernel: reset.c 
        arch/parisc/kernel: pci.c process.c 
        arch/ppc       : Kconfig 
        arch/ppc/boot/images: Makefile 
        arch/ppc/configs: common_defconfig pmac_defconfig 
                          radstone_ppc7d_defconfig sandpoint_defconfig 
        arch/ppc/kernel: head_8xx.S setup.c 
        arch/ppc/mm    : init.c 
        arch/ppc/platforms: pmac_setup.c prpmc750.c sandpoint.c 
                            tqm8260_setup.c 
        arch/ppc/platforms/4xx: ibm440sp.c 
        arch/ppc/platforms/85xx: mpc8560_ads.c mpc85xx_cds_common.c 
                                 stx_gp3.c 
        arch/ppc/syslib: cpm2_common.c m8260_setup.c m82xx_pci.c 
                         mpc10x_common.c ppc85xx_setup.c 
        arch/ppc64     : Kconfig defconfig 
        arch/ppc64/configs: g5_defconfig iSeries_defconfig 
                            maple_defconfig pSeries_defconfig 
        arch/ppc64/kernel: LparData.c cpu_setup_power4.S cputable.c 
                           head.S iSeries_htab.c iSeries_setup.c 
                           pSeries_lpar.c pmac_setup.c setup.c smp.c 
                           udbg.c 
        arch/ppc64/mm  : hash_low.S hash_native.c hash_utils.c 
                         hugetlbpage.c init.c stab.c 
        arch/s390/kernel: compat_linux.c compat_wrapper.S entry.S 
                          entry64.S head.S head64.S s390_ext.c setup.c 
                          smp.c 
        arch/s390/lib  : Makefile 
        arch/sh/kernel : process.c signal.c 
        arch/sh64/kernel: signal.c 
        arch/sparc/kernel: process.c systbls.S 
        arch/sparc64/kernel: entry.S irq.c power.c process.c smp.c 
                             systbls.S traps.c 
        arch/sparc64/mm: init.c 
        arch/um        : Kconfig_net Makefile Makefile-i386 
                         Makefile-x86_64 
        arch/um/drivers: Makefile cow.h hostaudio_kern.c 
        arch/um/kernel : helper.c process.c reboot.c um_arch.c uml.lds.S 
        arch/um/kernel/skas: syscall_user.c 
        arch/um/os-Linux: elf_aux.c 
        arch/um/scripts: Makefile.unmap 
        arch/um/sys-i386: ldt.c unmap.c 
        arch/um/sys-x86_64: signal.c unmap.c 
        arch/v850      : Makefile README 
        arch/v850/kernel: anna.c as85ep1.c fpga85e2c.c rte_cb.c 
                          rte_mb_a_pci.c sim.c sim85e2.c vmlinux.lds.S 
        arch/x86_64/ia32: ia32_aout.c ia32entry.S sys_ia32.c syscall32.c 
        arch/x86_64/kernel: reboot.c smpboot.c 
        crypto         : aes.c cipher.c internal.h 
        drivers/acpi   : ec.c 
        drivers/acpi/sleep: poweroff.c 
        drivers/atm    : ambassador.c firestream.c he.c idt77252.c 
                         zatm.c zatm.h 
        drivers/block  : as-iosched.c cciss.c cciss.h sx8.c ub.c 
        drivers/cdrom  : isp16.c mcdx.c optcd.c 
        drivers/char   : Kconfig hangcheck-timer.c rocket.c sysrq.c vt.c 
        drivers/char/drm: via_dma.c via_drm.h via_ds.c via_ds.h 
                          via_map.c via_mm.c via_video.c 
        drivers/char/ipmi: ipmi_si_intf.c ipmi_watchdog.c 
        drivers/char/rio: rioboot.c rioroute.c riotable.c 
        drivers/char/tpm: Kconfig Makefile 
        drivers/char/watchdog: acquirewdt.c advantechwdt.c 
                               alim1535_wdt.c alim7101_wdt.c 
                               eurotechwdt.c i8xx_tco.c ib700wdt.c 
                               indydog.c ixp2000_wdt.c ixp4xx_wdt.c 
                               machzwd.c mixcomwd.c pcwd.c pcwd_pci.c 
                               pcwd_usb.c s3c2410_wdt.c sa1100_wdt.c 
                               sbc60xxwdt.c sc1200wdt.c sc520_wdt.c 
                               scx200_wdt.c shwdt.c softdog.c 
                               w83627hf_wdt.c w83877f_wdt.c 
                               wafer5823wdt.c wdt.c wdt977.c wdt_pci.c 
        drivers/fc4    : fc.c 
        drivers/firmware: pcdp.c pcdp.h 
        drivers/i2c/busses: i2c-mpc.c 
        drivers/ide/cris: Makefile 
        drivers/ide/legacy: ide-cs.c 
        drivers/ide/pci: cmd640.c trm290.c 
        drivers/ieee1394: ohci1394.c sbp2.c 
        drivers/infiniband/core: Makefile agent.c agent_priv.h 
                                 fmr_pool.c mad.c mad_priv.h sa_query.c 
                                 user_mad.c uverbs.h uverbs_main.c 
                                 verbs.c 
        drivers/infiniband/hw/mthca: mthca_cq.c mthca_provider.c 
        drivers/infiniband/include: ib_fmr_pool.h ib_mad.h ib_sa.h 
                                    ib_user_mad.h ib_verbs.h 
        drivers/infiniband/ulp/ipoib: ipoib_ib.c 
        drivers/input/joystick: amijoy.c 
        drivers/isdn/hisax: avm_a1.c config.c gazel.c isdnl2.c l3dss1.c 
                            teles3.c 
        drivers/macintosh: Kconfig 
        drivers/md     : bitmap.c md.c raid0.c raid1.c raid5.c 
                         raid6main.c 
        drivers/media/dvb/frontends: Kconfig Makefile dvb-pll.c 
        drivers/media/radio: radio-maestro.c radio-maxiradio.c 
        drivers/media/video: Kconfig bttv-cards.c mxb.c tea5767.c 
                             tuner-core.c tvaudio.c tveeprom.c 
        drivers/media/video/cx88: Makefile cx88-cards.c cx88-dvb.c 
                                  cx88-i2c.c cx88-video.c cx88.h 
        drivers/media/video/saa7134: Makefile saa7134-dvb.c 
        drivers/message/fusion: mptfc.c mptscsih.c mptscsih.h mptspi.c 
        drivers/mmc    : wbsd.c 
        drivers/mtd/chips: Kconfig cfi_cmdset_0020.c 
        drivers/mtd/devices: docecc.c 
        drivers/mtd/nand: nand_base.c nand_bbt.c 
        drivers/net    : 3c505.c 8139too.c Kconfig amd8111e.c cs89x0.c 
                         eql.c ne.c plip.c tg3.c tg3.h via-velocity.h 
        drivers/net/e1000: e1000_main.c 
        drivers/net/pcmcia: nmclan_cs.c pcnet_cs.c smc91c92_cs.c 
                            xirc2ps_cs.c 
        drivers/net/wan: sdla_fr.c sdla_ft1.c sdla_ppp.c sdla_x25.c 
                         wanpipe_multppp.c 
        drivers/net/wireless: airo.c orinoco_cs.c 
        drivers/oprofile: cpu_buffer.c 
        drivers/pcmcia : au1000_generic.c cistpl.c ds.c o2micro.h 
                         pcmcia_resource.c sa1100_jornada720.c 
                         yenta_socket.c 
        drivers/pnp/pnpbios: rsparser.c 
        drivers/s390/block: dasd.c dasd_fba.c 
        drivers/s390/char: tape.h tape_core.c vmcp.c vmwatchdog.c 
        drivers/s390/cio: chsc.c device_status.c qdio.c 
        drivers/s390/net: qeth.h 
        drivers/sbus/char: Kconfig aurora.c bbc_envctrl.c envctrl.c 
                           vfc_i2c.c 
        drivers/scsi   : NCR53c406a.c advansys.c aic7xxx_old.c 
                         cpqfcTSinit.c dc395x.c dpt_i2o.c dtc.c dtc.h 
                         eata.c eata_pio.c fdomain.c gdth.c hosts.c 
                         initio.c ips.h libata-core.c megaraid.c 
                         megaraid.h ncr53c8xx.c nsp32.c pas16.c 
                         qla1280.c qlogicfc.c qlogicisp.c scsi.c 
                         scsi_error.c scsi_lib.c scsi_priv.h scsi_scan.c 
                         scsi_transport_spi.c sd.c t128.h u14-34f.c 
        drivers/scsi/aacraid: README TODO aachba.c aacraid.h commctrl.c 
                              linit.c 
        drivers/scsi/aic7xxx: aic7770.c aic7770_osm.c aic79xx_osm.c 
                              aic79xx_pci.c aic7xxx.h aic7xxx_core.c 
                              aic7xxx_osm.c aic7xxx_osm.h 
                              aic7xxx_osm_pci.c aic7xxx_pci.c 
                              aic7xxx_proc.c 
        drivers/scsi/dpt: dptsig.h 
        drivers/scsi/ibmvscsi: ibmvscsi.c rpa_vscsi.c srp.h 
        drivers/scsi/lpfc: Makefile lpfc.h lpfc_attr.c lpfc_compat.h 
                           lpfc_crtn.h lpfc_ct.c lpfc_disc.h lpfc_els.c 
                           lpfc_hbadisc.c lpfc_hw.h lpfc_init.c 
                           lpfc_logmsg.h lpfc_mbox.c lpfc_mem.c 
                           lpfc_nportdisc.c lpfc_scsi.c lpfc_scsi.h 
                           lpfc_sli.c lpfc_sli.h lpfc_version.h 
        drivers/scsi/megaraid: megaraid_mbox.c 
        drivers/scsi/qla2xxx: Kconfig Makefile ql2100.c ql2100_fw.c 
                              ql2200.c ql2200_fw.c ql2300.c ql2300_fw.c 
                              ql2322.c ql2322_fw.c ql6312.c ql6312_fw.c 
                              qla_attr.c qla_dbg.c qla_dbg.h qla_def.h 
                              qla_devtbl.h qla_gbl.h qla_gs.c qla_init.c 
                              qla_inline.h qla_iocb.c qla_isr.c 
                              qla_mbx.c qla_os.c qla_rscn.c 
                              qla_settings.h qla_sup.c qla_version.h 
        drivers/scsi/sym53c8xx_2: sym_hipd.h sym_nvram.c 
        drivers/serial : 68328serial.c 8250_pci.c Kconfig Makefile 
                         crisv10.c icom.c serial_cs.c 
        drivers/serial/cpm_uart: cpm_uart_cpm1.c 
        drivers/serial/jsm: jsm.h jsm_driver.c jsm_neo.c 
        drivers/usb/image: microtek.c 
        drivers/usb/serial: option.c 
        drivers/video  : Kconfig fbcmap.c fbmem.c fbmon.c fbsysfs.c 
                         imxfb.c imxfb.h pm2fb.c 
        drivers/video/aty: radeon_base.c 
        drivers/video/console: fbcon.c 
        drivers/video/riva: fbdev.c 
        drivers/w1     : w1_int.c 
        fs             : bio.c fcntl.c inode.c inotify.c locks.c 
                         mbcache.c 
        fs/autofs4     : autofs_i.h inode.c 
        fs/ext2        : ialloc.c xattr.c xip.c 
        fs/ext3        : ialloc.c xattr.c 
        fs/hostfs      : hostfs_kern.c 
        fs/hppfs       : hppfs_kern.c 
        fs/jffs        : intrep.c 
        fs/jffs2       : build.c erase.c nodelist.c os-linux.h 
                         readinode.c super.c 
        fs/jfs         : jfs_dmap.c jfs_dtree.c jfs_dtree.h jfs_imap.c 
                         jfs_logmgr.c jfs_metapage.c jfs_unicode.c 
                         jfs_xtree.c jfs_xtree.h xattr.c 
        fs/lockd       : svc.c 
        fs/ntfs        : ChangeLog Makefile aops.c attrib.c attrib.h 
                         compress.c debug.c dir.c file.c index.c inode.c 
                         inode.h layout.h lcnalloc.c logfile.c mft.c 
                         namei.c ntfs.h runlist.c runlist.h super.c 
                         sysctl.c sysctl.h time.h types.h unistr.c 
                         volume.h 
        fs/reiserfs    : inode.c journal.c xattr.c 
        include/asm-alpha: unistd.h 
        include/asm-arm: bitops.h locks.h smp.h spinlock.h system.h 
        include/asm-arm/arch-imx: imxfb.h 
        include/asm-arm/arch-s3c2410: regs-iis.h 
        include/asm-arm/arch-shark: io.h 
        include/asm-cris: atomic.h axisflashmap.h bitops.h dma-mapping.h 
                          dma.h elf.h etraxgpio.h hardirq.h io.h irq.h 
                          kmap_types.h mmu_context.h page.h pci.h 
                          pgalloc.h pgtable.h processor.h ptrace.h 
                          semaphore.h smp.h termbits.h thread_info.h 
                          timex.h tlbflush.h types.h unistd.h 
        include/asm-cris/arch-v10: bitops.h dma.h elf.h io.h irq.h mmu.h 
                                   offset.h processor.h system.h 
        include/asm-i386: bitops.h i387.h ptrace.h 
        include/asm-ia64: pci.h topology.h unistd.h 
        include/asm-ia64/sn: pcibr_provider.h pcibus_provider_defs.h 
                             simulator.h 
        include/asm-ppc: cpm2.h dma-mapping.h mmu_context.h mpc10x.h 
        include/asm-ppc64: machdep.h mmu.h 
        include/asm-ppc64/iSeries: HvCallHpt.h HvReleaseData.h LparMap.h 
        include/asm-s390: atomic.h bitops.h lowcore.h processor.h 
                          spinlock.h 
        include/asm-sparc: unistd.h 
        include/asm-sparc64: bitops.h ptrace.h rwsem.h spitfire.h 
                             system.h thread_info.h timer.h unistd.h 
        include/asm-v850: bitops.h cache.h io.h page.h pci.h pgtable.h 
                          v850e2_cache.h 
        include/asm-x86_64: ia32_unistd.h unistd.h 
        include/linux  : fadvise.h fs.h fsnotify.h ftape.h mbcache.h 
                         netlink.h pci_ids.h reboot.h serial.h serialP.h 
                         serial_core.h skbuff.h slab.h sysctl.h 
                         watchdog.h 
        include/linux/netfilter_ipv4: ip_conntrack.h 
                                      ip_conntrack_helper.h 
        include/linux/raid: bitmap.h 
        include/linux/tc_ematch: tc_em_meta.h 
        include/media  : tveeprom.h 
        include/net    : xfrm.h 
        include/net/sctp: sctp.h 
        include/scsi   : scsi.h scsi_cmnd.h scsi_device.h scsi_host.h 
        include/sound  : core.h driver.h emu10k1.h version.h vx_core.h 
        init           : Kconfig do_mounts.c 
        kernel         : capability.c cpuset.c crash_dump.c itimer.c 
                         panic.c sched.c sys.c sysctl.c time.c 
        kernel/power   : disk.c poweroff.c smp.c 
        lib            : Makefile 
        mm             : filemap_xip.c madvise.c memory.c mempolicy.c 
                         page_alloc.c 
        net            : Kconfig 
        net/atm        : Kconfig svc.c 
        net/bridge/netfilter: Kconfig 
        net/core       : Makefile pktgen.c skbuff.c sock.c utils.c 
        net/ipv4       : Kconfig Makefile af_inet.c fib_trie.c ipip.c 
                         xfrm4_tunnel.c 
        net/ipv4/netfilter: ip_conntrack_amanda.c ip_conntrack_core.c 
                            ip_conntrack_ftp.c ip_conntrack_irc.c 
                            ip_conntrack_standalone.c 
                            ip_conntrack_tftp.c ip_nat_amanda.c 
                            ip_nat_ftp.c ip_nat_irc.c 
                            ip_nat_proto_icmp.c ip_nat_proto_tcp.c 
                            ip_nat_proto_udp.c ip_nat_tftp.c 
        net/ipv6       : Kconfig ip6_output.c ip6_tunnel.c 
        net/ipv6/netfilter: ip6_queue.c ip6t_LOG.c 
        net/netlink    : af_netlink.c 
        net/sched      : em_meta.c em_text.c sch_generic.c 
        net/sctp       : input.c ipv6.c objcnt.c 
        net/xfrm       : xfrm_user.c 
        scripts        : Lindent 
        scripts/kconfig: gconf.c gconf.glade 
        security/selinux: hooks.c 
        security/selinux/include: security.h 
        security/selinux/ss: mls.c mls.h services.c 
        sound/arm      : Kconfig Makefile 
        sound/core     : device.c info.c memalloc.c memory.c wrappers.c 
        sound/core/seq : Makefile seq_memory.c seq_midi.c 
                         seq_midi_event.c 
        sound/core/seq/instr: ainstr_gf1.c ainstr_iw.c 
        sound/core/seq/oss: seq_oss_device.h 
        sound/drivers  : serial-u16550.c 
        sound/drivers/vx: vx_uer.c 
        sound/i2c/other: ak4114.c 
        sound/isa/gus  : gus_main.c 
        sound/isa/sb   : emu8000_patch.c sb_mixer.c 
        sound/isa/wavefront: wavefront_fx.c 
        sound/oss      : pss.c 
        sound/oss/dmasound: dmasound_awacs.c 
        sound/pci      : atiixp_modem.c cmipci.c cs4281.c ens1370.c 
                         es1968.c intel8x0.c maestro3.c via82xx.c 
                         via82xx_modem.c 
        sound/pci/ac97 : ac97_codec.c ac97_patch.c 
        sound/pci/ali5451: ali5451.c 
        sound/pci/cs46xx: cs46xx_lib.c 
        sound/pci/emu10k1: emu10k1.c emu10k1_main.c memory.c p16v.c 
        sound/pci/hda  : hda_codec.h hda_intel.c patch_cmedia.c 
                         patch_realtek.c patch_sigmatel.c 
        sound/pci/mixart: mixart.c 
        sound/pci/nm256: nm256.c 
        sound/pci/rme9652: hdsp.c rme9652.c 
        sound/pci/trident: trident_main.c trident_memory.c 
        sound/pci/vx222: vx222_ops.c 
        sound/pci/ymfpci: ymfpci_main.c 
        sound/pcmcia   : Kconfig 
        sound/pcmcia/vx: Makefile vxp_ops.c vxpocket.c vxpocket.h 
        sound/ppc      : awacs.c burgundy.c pmac.c pmac.h tumbler.c 
        sound/sparc    : Kconfig Makefile 
        sound/usb      : usbaudio.c usbaudio.h usbmidi.c usbmixer.c 
                         usbquirks.h 
        sound/usb/usx2y: usX2Yhwdep.c usx2yhwdeppcm.c 
Added files:
        Documentation/infiniband: core_locking.txt 
        arch/arm/mach-s3c2410: irq.h s3c2440-clock.c s3c2440-irq.c 
        arch/cris/arch-v10/kernel: dma.c io_interface_mux.c 
        arch/cris/arch-v32: Kconfig output_arch.ld vmlinux.lds.S 
        arch/cris/arch-v32/boot: Makefile 
        arch/cris/arch-v32/boot/compressed: Makefile README 
                                            decompress.ld head.S misc.c 
        arch/cris/arch-v32/boot/rescue: Makefile head.S rescue.ld 
        arch/cris/arch-v32/drivers: Kconfig Makefile axisflashmap.c 
                                    cryptocop.c gpio.c i2c.c i2c.h 
                                    iop_fw_load.c nandflash.c pcf8563.c 
                                    sync_serial.c 
        arch/cris/arch-v32/drivers/pci: Makefile bios.c dma.c 
        arch/cris/arch-v32/kernel: Makefile arbiter.c asm-offsets.c 
                                   crisksyms.c debugport.c dma.c entry.S 
                                   fasttimer.c head.S io.c irq.c kgdb.c 
                                   kgdb_asm.S pinmux.c process.c 
                                   ptrace.c setup.c signal.c smp.c 
                                   time.c traps.c vcs_hook.c vcs_hook.h 
        arch/cris/arch-v32/lib: Makefile checksum.S checksumcopy.S 
                                csumcpfruser.S dram_init.S hw_settings.S 
                                memset.c nand_init.S spinlock.S string.c 
                                usercopy.c 
        arch/cris/arch-v32/mm: Makefile init.c intmem.c mmu.S tlb.c 
        arch/cris/kernel: profile.c 
        arch/s390/lib  : spinlock.c 
        arch/v850/configs: rte-ma1-cb_defconfig rte-me2-cb_defconfig 
                           sim_defconfig 
        drivers/char/tpm: tpm_infineon.c 
        drivers/ide/cris: ide-cris.c 
        drivers/infiniband/core: cm.c cm_msgs.h mad_rmpp.c mad_rmpp.h 
                                 ucm.c ucm.h 
        drivers/infiniband/include: ib_cm.h ib_user_cm.h 
        drivers/media/dvb/frontends: lgdt330x.c lgdt330x.h 
                                     lgdt330x_priv.h 
        drivers/scsi/qla2xxx: qla_fw.h 
        fs/ntfs        : usnjrnl.c usnjrnl.h 
        include/asm-alpha: emergency-restart.h 
        include/asm-arm: emergency-restart.h 
        include/asm-arm26: emergency-restart.h 
        include/asm-cris: emergency-restart.h hw_irq.h ide.h spinlock.h 
                          sync_serial.h 
        include/asm-cris/arch-v10: atomic.h ide.h io_interface_mux.h 
                                   memmap.h 
        include/asm-cris/arch-v32: arbiter.h atomic.h bitops.h 
                                   byteorder.h cache.h checksum.h 
                                   cryptocop.h delay.h dma.h elf.h ide.h 
                                   intmem.h io.h irq.h juliette.h 
                                   memmap.h mmu.h offset.h page.h 
                                   pgtable.h pinmux.h processor.h 
                                   ptrace.h spinlock.h system.h 
                                   thread_info.h timex.h tlb.h uaccess.h 
                                   unistd.h user.h 
        include/asm-cris/arch-v32/hwregs: Makefile ata_defs.h 
                                          bif_core_defs.h bif_dma_defs.h 
                                          bif_slave_defs.h config_defs.h 
                                          cpu_vect.h dma.h dma_defs.h 
                                          eth_defs.h extmem_defs.h 
                                          gio_defs.h intr_vect.h 
                                          intr_vect_defs.h 
                                          irq_nmi_defs.h marb_bp_defs.h 
                                          marb_defs.h pinmux_defs.h 
                                          reg_map.h reg_rdwr.h 
                                          rt_trace_defs.h ser_defs.h 
                                          sser_defs.h strcop.h 
                                          strcop_defs.h strmux_defs.h 
                                          supp_reg.h timer_defs.h 
        include/asm-cris/arch-v32/hwregs/asm: ata_defs_asm.h 
                                              bif_core_defs_asm.h 
                                              bif_dma_defs_asm.h 
                                              bif_slave_defs_asm.h 
                                              config_defs_asm.h 
                                              cpu_vect.h cris_defs_asm.h 
                                              cris_supp_reg.h 
                                              dma_defs_asm.h 
                                              eth_defs_asm.h 
                                              gio_defs_asm.h intr_vect.h 
                                              intr_vect_defs_asm.h 
                                              irq_nmi_defs_asm.h 
                                              marb_defs_asm.h 
                                              mmu_defs_asm.h 
                                              mmu_supp_reg.h 
                                              pinmux_defs_asm.h 
                                              reg_map_asm.h 
                                              rt_trace_defs_asm.h 
                                              ser_defs_asm.h 
                                              sser_defs_asm.h 
                                              strcop_defs_asm.h 
                                              strmux_defs_asm.h 
                                              timer_defs_asm.h 
        include/asm-cris/arch-v32/hwregs/iop: Makefile 
                                              iop_crc_par_defs.h 
                                              iop_dmc_in_defs.h 
                                              iop_dmc_out_defs.h 
                                              iop_fifo_in_defs.h 
                                              iop_fifo_in_extra_defs.h 
                                              iop_fifo_out_defs.h 
                                              iop_fifo_out_extra_defs.h 
                                              iop_mpu_defs.h 
                                              iop_mpu_macros.h 
                                              iop_reg_space.h 
                                              iop_sap_in_defs.h 
                                              iop_sap_out_defs.h 
                                              iop_scrc_in_defs.h 
                                              iop_scrc_out_defs.h 
                                              iop_spu_defs.h 
                                              iop_sw_cfg_defs.h 
                                              iop_sw_cpu_defs.h 
                                              iop_sw_mpu_defs.h 
                                              iop_sw_spu_defs.h 
                                              iop_timer_grp_defs.h 
                                              iop_trigger_grp_defs.h 
                                              iop_version_defs.h 
        include/asm-cris/arch-v32/hwregs/iop/asm: iop_crc_par_defs_asm.h 
                                                  iop_dmc_in_defs_asm.h 
                                                  iop_dmc_out_defs_asm.h 
                                                  iop_fifo_in_defs_asm.h 
                                                  iop_fifo_in_extra_defs_asm.h 
                                                  iop_fifo_out_defs_asm.h 
                                                  iop_fifo_out_extra_defs_asm.h 
                                                  iop_mpu_defs_asm.h 
                                                  iop_reg_space_asm.h 
                                                  iop_sap_in_defs_asm.h 
                                                  iop_sap_out_defs_asm.h 
                                                  iop_scrc_in_defs_asm.h 
                                                  iop_scrc_out_defs_asm.h 
                                                  iop_spu_defs_asm.h 
                                                  iop_sw_cfg_defs_asm.h 
                                                  iop_sw_cpu_defs_asm.h 
                                                  iop_sw_mpu_defs_asm.h 
                                                  iop_sw_spu_defs_asm.h 
                                                  iop_timer_grp_defs_asm.h 
                                                  iop_trigger_grp_defs_asm.h 
                                                  iop_version_defs_asm.h 
        include/asm-frv: emergency-restart.h 
        include/asm-generic: emergency-restart.h 
        include/asm-h8300: emergency-restart.h 
        include/asm-i386: emergency-restart.h 
        include/asm-ia64: emergency-restart.h 
        include/asm-m32r: emergency-restart.h 
        include/asm-m68k: emergency-restart.h 
        include/asm-m68knommu: emergency-restart.h 
        include/asm-mips: emergency-restart.h 
        include/asm-parisc: emergency-restart.h 
        include/asm-ppc: emergency-restart.h 
        include/asm-ppc64: emergency-restart.h 
        include/asm-s390: emergency-restart.h 
        include/asm-sh : emergency-restart.h 
        include/asm-sh64: emergency-restart.h 
        include/asm-sparc: emergency-restart.h 
        include/asm-sparc64: emergency-restart.h 
        include/asm-um : emergency-restart.h ldt.h 
        include/asm-v850: emergency-restart.h 
        include/asm-x86_64: emergency-restart.h 
        include/asm-xtensa: emergency-restart.h 
        sound/arm      : pxa2xx-ac97.c pxa2xx-pcm.c pxa2xx-pcm.h 
        sound/sparc    : dbri.c 
Removed files:
        drivers/ide/cris: ide-v10.c 
        drivers/media/dvb/frontends: lgdt3302.c lgdt3302.h 
                                     lgdt3302_priv.h 
        drivers/serial : bast_sio.c 
        net/ipv4       : utils.c 
        sound/pcmcia/vx: vx_entry.c vxp440.c 

Log message:
        Merge with Linux 2.6.13-rc4.

diff -urN linux/CREDITS linux/CREDITS
--- linux/CREDITS       2005/07/11 20:45:51     1.146
+++ linux/CREDITS       2005/08/01 18:23:35     1.147
@@ -1624,10 +1624,10 @@
 D: fbdev hacking
 
 N: Jesper Juhl
-E: juhl-lkml@dif.dk
-D: Various small janitor fixes, cleanups etc.
+E: jesper.juhl@gmail.com
+D: Various fixes, cleanups and minor features.
 S: Lemnosvej 1, 3.tv
-S: 2300 Copenhagen S
+S: 2300 Copenhagen S.
 S: Denmark
 
 N: Jozsef Kadlecsik
diff -urN linux/MAINTAINERS linux/MAINTAINERS
--- linux/MAINTAINERS   2005/07/13 11:48:45     1.184
+++ linux/MAINTAINERS   2005/08/01 18:23:35     1.185
@@ -1169,6 +1169,12 @@
 L:     linux-joystick@atrey.karlin.mff.cuni.cz
 S:     Maintained
 
+INOTIFY
+P:     John McCutchan and Robert Love
+M:     ttb@tentacle.dhs.org and rml@novell.com
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+
 INTEL 810/815 FRAMEBUFFER DRIVER
 P:      Antonino Daplas
 M:      adaplas@pol.net
@@ -1410,13 +1416,20 @@
 L:     linuxppc-embedded@ozlabs.org
 S:     Maintained
 
-LINUX FOR POWERPC EMBEDDED PPC8XX AND BOOT CODE
+LINUX FOR POWERPC BOOT CODE
 P:     Tom Rini
 M:     trini@kernel.crashing.org
 W:     http://www.penguinppc.org/
 L:     linuxppc-embedded@ozlabs.org
 S:     Maintained
 
+LINUX FOR POWERPC EMBEDDED PPC8XX
+P:     Marcelo Tosatti
+M:     marcelo.tosatti@cyclades.com
+W:     http://www.penguinppc.org/
+L:     linuxppc-embedded@ozlabs.org
+S:     Maintained
+
 LINUX FOR POWERPC EMBEDDED PPC83XX AND PPC85XX
 P:     Kumar Gala
 M:     kumar.gala@freescale.com
@@ -2420,6 +2433,12 @@
 L:     linux-usb-devel@lists.sourceforge.net
 S:     Maintained
 
+USB OPTION-CARD DRIVER
+P:     Matthias Urlichs
+M:     smurf@smurf.noris.de
+L:     linux-usb-devel@lists.sourceforge.net
+S:     Maintained
+
 USB OV511 DRIVER
 P:     Mark McClelland
 M:     mmcclell@bigfoot.com
diff -urN linux/Makefile linux/Makefile
--- linux/Makefile      2005/07/13 11:48:45     1.257
+++ linux/Makefile      2005/08/01 18:23:35     1.258
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 13
-EXTRAVERSION =-rc3
+EXTRAVERSION =-rc4
 NAME=Woozy Numbat
 
 # *DOCUMENTATION*
diff -urN linux/README linux/README
--- linux/README        2004/08/06 00:33:20     1.26
+++ linux/README        2005/08/01 18:23:35     1.27
@@ -87,6 +87,16 @@
    kernel source.  Patches are applied from the current directory, but
    an alternative directory can be specified as the second argument.
 
+ - If you are upgrading between releases using the stable series patches
+   (for example, patch-2.6.xx.y), note that these "dot-releases" are
+   not incremental and must be applied to the 2.6.xx base tree. For
+   example, if your base kernel is 2.6.12 and you want to apply the
+   2.6.12.3 patch, you do not and indeed must not first apply the
+   2.6.12.1 and 2.6.12.2 patches. Similarly, if you are running kernel
+   version 2.6.12.2 and want to jump to 2.6.12.3, you must first
+   reverse the 2.6.12.2 patch (that is, patch -R) _before_ applying
+   the 2.6.12.3 patch.
+
  - Make sure you have no stale .o files and dependencies lying around:
 
                cd linux
diff -urN linux/Documentation/Changes linux/Documentation/Changes
--- linux/Documentation/Changes 2005/07/12 09:18:54     1.85
+++ linux/Documentation/Changes 2005/08/01 18:23:35     1.86
@@ -65,6 +65,7 @@
 o  nfs-utils              1.0.5                   # showmount --version
 o  procps                 3.2.0                   # ps --version
 o  oprofile               0.9                     # oprofiled --version
+o  udev                   058                     # udevinfo -V
 
 Kernel compilation
 ==================
diff -urN linux/Documentation/dontdiff linux/Documentation/dontdiff
--- linux/Documentation/dontdiff        2005/07/11 20:45:51     1.3
+++ linux/Documentation/dontdiff        2005/08/01 18:23:35     1.4
@@ -41,6 +41,7 @@
 CREDITS
 CVS
 ChangeSet
+Image
 Kerntypes
 MODS.txt
 Module.symvers
@@ -103,6 +104,7 @@
 logo_*_clut224.c
 logo_*_mono.c
 lxdialog
+mach-types.h
 make_times_h
 map
 maui_boot.h
diff -urN linux/Documentation/feature-removal-schedule.txt 
linux/Documentation/feature-removal-schedule.txt
--- linux/Documentation/feature-removal-schedule.txt    2005/07/13 11:48:46     
1.9
+++ linux/Documentation/feature-removal-schedule.txt    2005/08/01 18:23:36     
1.10
@@ -103,11 +103,11 @@
 ---------------------------
 
 What:  register_serial/unregister_serial
-When:  December 2005
+When:  September 2005
 Why:   This interface does not allow serial ports to be registered against
        a struct device, and as such does not allow correct power management
        of such ports.  8250-based ports should use serial8250_register_port
-       and serial8250_unregister_port instead.
+       and serial8250_unregister_port, or platform devices instead.
 Who:   Russell King <rmk@arm.linux.org.uk>
 
 ---------------------------
diff -urN linux/Documentation/filesystems/inotify.txt 
linux/Documentation/filesystems/inotify.txt
--- linux/Documentation/filesystems/inotify.txt 2005/07/13 11:48:46     1.1
+++ linux/Documentation/filesystems/inotify.txt 2005/08/01 18:23:36     1.2
@@ -1,18 +1,22 @@
-                                   inotify
-            a powerful yet simple file change notification system
+                                  inotify
+           a powerful yet simple file change notification system
 
 
 
 Document started 15 Mar 2005 by Robert Love <rml@novell.com>
 
+
 (i) User Interface
 
-Inotify is controlled by a set of three sys calls 
+Inotify is controlled by a set of three system calls and normal file I/O on a
+returned file descriptor.
 
-First step in using inotify is to initialise an inotify instance
+First step in using inotify is to initialise an inotify instance:
 
        int fd = inotify_init ();
 
+Each instance is associated with a unique, ordered queue.
+
 Change events are managed by "watches".  A watch is an (object,mask) pair where
 the object is a file or directory and the mask is a bit mask of one or more
 inotify events that the application wishes to receive.  See <linux/inotify.h>
@@ -22,43 +26,52 @@
 
 Watches on a directory will return events on any files inside of the directory.
 
-Adding a watch is simple,
+Adding a watch is simple:
 
        int wd = inotify_add_watch (fd, path, mask);
 
-You can add a large number of files via something like
-
-       for each file to watch {
-               int wd = inotify_add_watch (fd, file, mask);
-       }
+Where "fd" is the return value from inotify_init(), path is the path to the
+object to watch, and mask is the watch mask (see <linux/inotify.h>).
 
 You can update an existing watch in the same manner, by passing in a new mask.
 
-An existing watch is removed via the INOTIFY_IGNORE ioctl, for example
+An existing watch is removed via
 
-       inotify_rm_watch (fd, wd);
+       int ret = inotify_rm_watch (fd, wd);
 
 Events are provided in the form of an inotify_event structure that is read(2)
-from a inotify instance fd.  The filename is of dynamic length and follows the 
-struct. It is of size len.  The filename is padded with null bytes to ensure 
-proper alignment.  This padding is reflected in len.
+from a given inotify instance.  The filename is of dynamic length and follows
+the struct. It is of size len.  The filename is padded with null bytes to
+ensure proper alignment.  This padding is reflected in len.
 
 You can slurp multiple events by passing a large buffer, for example
 
        size_t len = read (fd, buf, BUF_LEN);
 
-Will return as many events as are available and fit in BUF_LEN.
+Where "buf" is a pointer to an array of "inotify_event" structures at least
+BUF_LEN bytes in size.  The above example will return as many events as are
+available and fit in BUF_LEN.
 
-each inotify instance fd is also select()- and poll()-able.
+Each inotify instance fd is also select()- and poll()-able.
 
-You can find the size of the current event queue via the FIONREAD ioctl.
+You can find the size of the current event queue via the standard FIONREAD
+ioctl on the fd returned by inotify_init().
 
 All watches are destroyed and cleaned up on close.
 
 
-(ii) Internal Kernel Implementation
+(ii)
+
+Prototypes:
+
+       int inotify_init (void);
+       int inotify_add_watch (int fd, const char *path, __u32 mask);
+       int inotify_rm_watch (int fd, __u32 mask);
+
 
-Each open inotify instance is associated with an inotify_device structure.
+(iii) Internal Kernel Implementation
+
+Each inotify instance is associated with an inotify_device structure.
 
 Each watch is associated with an inotify_watch structure.  Watches are chained
 off of each associated device and each associated inode.
@@ -66,7 +79,7 @@
 See fs/inotify.c for the locking and lifetime rules.
 
 
-(iii) Rationale
+(iv) Rationale
 
 Q: What is the design decision behind not tying the watch to the open fd of
    the watched object?
@@ -75,9 +88,9 @@
    This solves the primary problem with dnotify: keeping the file open pins
    the file and thus, worse, pins the mount.  Dnotify is therefore infeasible
    for use on a desktop system with removable media as the media cannot be
-   unmounted.
+   unmounted.  Watching a file should not require that it be open.
 
-Q: What is the design decision behind using an-fd-per-device as opposed to
+Q: What is the design decision behind using an-fd-per-instance as opposed to
    an fd-per-watch?
 
 A: An fd-per-watch quickly consumes more file descriptors than are allowed,
@@ -86,8 +99,8 @@
    can use epoll, but requiring both is a silly and extraneous requirement.
    A watch consumes less memory than an open file, separating the number
    spaces is thus sensible.  The current design is what user-space developers
-   want: Users initialize inotify, once, and add n watches, requiring but one 
fd
-   and no twiddling with fd limits.  Initializing an inotify instance two
+   want: Users initialize inotify, once, and add n watches, requiring but one
+   fd and no twiddling with fd limits.  Initializing an inotify instance two
    thousand times is silly.  If we can implement user-space's preferences 
    cleanly--and we can, the idr layer makes stuff like this trivial--then we 
    should.
@@ -111,9 +124,6 @@
      example, love it.  Trust me, I asked.  It is not a surprise: Who'd want
      to manage and block on 1000 fd's via select?
 
-   - You'd have to manage the fd's, as an example: Call close() when you
-     received a delete event.
-
    - No way to get out of band data.
 
    - 1024 is still too low.  ;-)
@@ -122,6 +132,11 @@
    scales to 1000s of directories, juggling 1000s of fd's just does not seem
    the right interface.  It is too heavy.
 
+   Additionally, it _is_ possible to  more than one instance  and
+   juggle more than one queue and thus more than one associated fd.  There
+   need not be a one-fd-per-process mapping; it is one-fd-per-queue and a
+   process can easily want more than one queue.
+
 Q: Why the system call approach?
 
 A: The poor user-space interface is the second biggest problem with dnotify.
@@ -131,8 +146,6 @@
    Obtaining the fd and managing the watches could have been done either via a
    device file or a family of new system calls.  We decided to implement a
    family of system calls because that is the preffered approach for new kernel
-   features and it means our user interface requirements.
-
-   Additionally, it _is_ possible to  more than one instance  and
-   juggle more than one queue and thus more than one associated fd.
+   interfaces.  The only real difference was whether we wanted to use open(2)
+   and ioctl(2) or a couple of new system calls.  System calls beat ioctls.
 
diff -urN linux/Documentation/filesystems/ntfs.txt 
linux/Documentation/filesystems/ntfs.txt
--- linux/Documentation/filesystems/ntfs.txt    2004/11/15 11:49:12     1.34
+++ linux/Documentation/filesystems/ntfs.txt    2005/08/01 18:23:36     1.35
@@ -21,7 +21,7 @@
 ========
 
 Linux-NTFS comes with a number of user-space programs known as ntfsprogs.
-These include mkntfs, a full-featured ntfs file system format utility,
+These include mkntfs, a full-featured ntfs filesystem format utility,
 ntfsundelete used for recovering files that were unintentionally deleted
 from an NTFS volume and ntfsresize which is used to resize an NTFS partition.
 See the web site for more information.
@@ -149,7 +149,14 @@
                        name, if it exists.  If case_sensitive, you will need
                        to provide the correct case of the short file name.
 
-errors=opt             What to do when critical file system errors are found.
+disable_sparse=<BOOL>  If disable_sparse is specified, creation of sparse
+                       regions, i.e. holes, inside files is disabled for the
+                       volume (for the duration of this mount only).  By
+                       default, creation of sparse regions is enabled, which
+                       is consistent with the behaviour of traditional Unix
+                       filesystems.
+
+errors=opt             What to do when critical filesystem errors are found.
                        Following values can be used for "opt":
                          continue: DEFAULT, try to clean-up as much as
                                    possible, e.g. marking a corrupt inode as
@@ -432,6 +439,24 @@
 
 Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
 
+2.1.23:
+       - Stamp the user space journal, aka transaction log, aka $UsnJrnl, if
+         it is present and active thus telling Windows and applications using
+         the transaction log that changes can have happened on the volume
+         which are not recorded in $UsnJrnl.
+       - Detect the case when Windows has been hibernated (suspended to disk)
+         and if this is the case do not allow (re)mounting read-write to
+         prevent data corruption when you boot back into the suspended
+         Windows session.
+       - Implement extension of resident files using the normal file write
+         code paths, i.e. most very small files can be extended to be a little
+         bit bigger but not by much.
+       - Add new mount option "disable_sparse".  (See list of mount options
+         above for details.)
+       - Improve handling of ntfs volumes with errors and strange boot sectors
+         in particular.
+       - Fix various bugs including a nasty deadlock that appeared in recent
+         kernels (around 2.6.11-2.6.12 timeframe).
 2.1.22:
        - Improve handling of ntfs volumes with errors.
        - Fix various bugs and race conditions.
diff -urN linux/Documentation/infiniband/core_locking.txt 
linux/Documentation/infiniband/core_locking.txt
--- linux/Documentation/infiniband/core_locking.txt     1970/01/01 00:00:00
+++ linux/Documentation/infiniband/core_locking.txt     2005-08-01 
19:23:36.511960000 +0100     1.1
@@ -0,0 +1,114 @@
+INFINIBAND MIDLAYER LOCKING
+
+  This guide is an attempt to make explicit the locking assumptions
+  made by the InfiniBand midlayer.  It describes the requirements on
+  both low-level drivers that sit below the midlayer and upper level
+  protocols that use the midlayer.
+
+Sleeping and interrupt context
+
+  With the following exceptions, a low-level driver implementation of
+  all of the methods in struct ib_device may sleep.  The exceptions
+  are any methods from the list:
+
+    create_ah
+    modify_ah
+    query_ah
+    destroy_ah
+    bind_mw
+    post_send
+    post_recv
+    poll_cq
+    req_notify_cq
+    map_phys_fmr
+
+  which may not sleep and must be callable from any context.
+
+  The corresponding functions exported to upper level protocol
+  consumers:
+
+    ib_create_ah
+    ib_modify_ah
+    ib_query_ah
+    ib_destroy_ah
+    ib_bind_mw
+    ib_post_send
+    ib_post_recv
+    ib_req_notify_cq
+    ib_map_phys_fmr
+
+  are therefore safe to call from any context.
+
+  In addition, the function
+
+    ib_dispatch_event
+
+  used by low-level drivers to dispatch asynchronous events through
+  the midlayer is also safe to call from any context.
+
+Reentrancy
+
+  All of the methods in struct ib_device exported by a low-level
+  driver must be fully reentrant.  The low-level driver is required to
+  perform all synchronization necessary to maintain consistency, even
+  if multiple function calls using the same object are run
+  simultaneously.
+
+  The IB midlayer does not perform any serialization of function calls.
+
+  Because low-level drivers are reentrant, upper level protocol
+  consumers are not required to perform any serialization.  However,
+  some serialization may be required to get sensible results.  For
+  example, a consumer may safely call ib_poll_cq() on multiple CPUs
+  simultaneously.  However, the ordering of the work completion
+  information between different calls of ib_poll_cq() is not defined.
+
+Callbacks
+
+  A low-level driver must not perform a callback directly from the
+  same callchain as an ib_device method call.  For example, it is not
+  allowed for a low-level driver to call a consumer's completion event
+  handler directly from its post_send method.  Instead, the low-level
+  driver should defer this callback by, for example, scheduling a
+  tasklet to perform the callback.
+
+  The low-level driver is responsible for ensuring that multiple
+  completion event handlers for the same CQ are not called
+  simultaneously.  The driver must guarantee that only one CQ event
+  handler for a given CQ is running at a time.  In other words, the
+  following situation is not allowed:
+
+        CPU1                                    CPU2
+
+  low-level driver ->
+    consumer CQ event callback:
+      /* ... */
+      ib_req_notify_cq(cq, ...);
+                                        low-level driver ->
+      /* ... */                           consumer CQ event callback:
+                                            /* ... */
+      return from CQ event handler
+
+  The context in which completion event and asynchronous event
+  callbacks run is not defined.  Depending on the low-level driver, it
+  may be process context, softirq context, or interrupt context.
+  Upper level protocol consumers may not sleep in a callback.
+
+Hot-plug
+
+  A low-level driver announces that a device is ready for use by
+  consumers when it calls ib_register_device(), all initialization
+  must be complete before this call.  The device must remain usable
+  until the driver's call to ib_unregister_device() has returned.
+
+  A low-level driver must call ib_register_device() and
+  ib_unregister_device() from process context.  It must not hold any
+  semaphores that could cause deadlock if a consumer calls back into
+  the driver across these calls.
+
+  An upper level protocol consumer may begin using an IB device as
+  soon as the add method of its struct ib_client is called for that
+  device.  A consumer must finish all cleanup and free all resources
+  relating to a device before returning from the remove method.
+
+  A consumer is permitted to sleep in its add and remove methods.
diff -urN linux/Documentation/infiniband/user_mad.txt 
linux/Documentation/infiniband/user_mad.txt
--- linux/Documentation/infiniband/user_mad.txt 2005/02/07 02:54:30     1.2
+++ linux/Documentation/infiniband/user_mad.txt 2005/08/01 18:23:36     1.3
@@ -28,13 +28,37 @@
 
 Receiving MADs
 
-  MADs are received using read().  The buffer passed to read() must be
-  large enough to hold at least one struct ib_user_mad.  For example:
+  MADs are received using read().  The receive side now supports
+  RMPP. The buffer passed to read() must be at least one
+  struct ib_user_mad + 256 bytes. For example:
+
+  If the buffer passed is not large enough to hold the received
+  MAD (RMPP), the errno is set to ENOSPC and the length of the
+  buffer needed is set in mad.length.
+
+  Example for normal MAD (non RMPP) reads:
+       struct ib_user_mad *mad;
+       mad = malloc(sizeof *mad + 256);
+       ret = read(fd, mad, sizeof *mad + 256);
+       if (ret != sizeof mad + 256) {
+               perror("read");
+               free(mad);
+       }
 
-       struct ib_user_mad mad;
-       ret = read(fd, &mad, sizeof mad);
-       if (ret != sizeof mad)
+  Example for RMPP reads:
+       struct ib_user_mad *mad;
+       mad = malloc(sizeof *mad + 256);
+       ret = read(fd, mad, sizeof *mad + 256);
+       if (ret == -ENOSPC)) {
+               length = mad.length;
+               free(mad);
+               mad = malloc(sizeof *mad + length);
+               ret = read(fd, mad, sizeof *mad + length);
+       }
+       if (ret < 0) {
                perror("read");
+               free(mad);
+       }
 
   In addition to the actual MAD contents, the other struct ib_user_mad
   fields will be filled in with information on the received MAD.  For
@@ -50,18 +74,21 @@
 
   MADs are sent using write().  The agent ID for sending should be
   filled into the id field of the MAD, the destination LID should be
-  filled into the lid field, and so on.  For example:
+  filled into the lid field, and so on.  The send side does support
+  RMPP so arbitrary length MAD can be sent. For example:
+
+       struct ib_user_mad *mad;
 
-       struct ib_user_mad mad;
+       mad = malloc(sizeof *mad + mad_length);
 
-       /* fill in mad.data */
+       /* fill in mad->data */
 
-       mad.id  = my_agent;     /* req.id from agent registration */
-       mad.lid = my_dest;      /* in network byte order... */
+       mad->hdr.id  = my_agent;        /* req.id from agent registration */
+       mad->hdr.lid = my_dest;         /* in network byte order... */
        /* etc. */
 
-       ret = write(fd, &mad, sizeof mad);
-       if (ret != sizeof mad)
+       ret = write(fd, &mad, sizeof *mad + mad_length);
+       if (ret != sizeof *mad + mad_length)
                perror("write");
 
 Setting IsSM Capability Bit
diff -urN linux/Documentation/pcmcia/driver-changes.txt 
linux/Documentation/pcmcia/driver-changes.txt
--- linux/Documentation/pcmcia/driver-changes.txt       2005/07/13 11:48:48     
1.2
+++ linux/Documentation/pcmcia/driver-changes.txt       2005/08/01 18:23:36     
1.3
@@ -56,3 +56,12 @@
    memory regions in-use. The name argument should be a pointer to
    your driver name. Eg, for pcnet_cs, name should point to the
    string "pcnet_cs".
+
+* CardServices is gone
+  CardServices() in 2.4 is just a big switch statement to call various
+  services.  In 2.6, all of those entry points are exported and called
+  directly (except for pcmcia_report_error(), just use cs_error() instead).
+
+* struct pcmcia_driver
+  You need to use struct pcmcia_driver and pcmcia_{un,}register_driver
+  instead of {un,}register_pccard_driver
diff -urN linux/Documentation/scsi/scsi_mid_low_api.txt 
linux/Documentation/scsi/scsi_mid_low_api.txt
--- linux/Documentation/scsi/scsi_mid_low_api.txt       2005/07/11 20:45:56     
1.16
+++ linux/Documentation/scsi/scsi_mid_low_api.txt       2005/08/01 18:23:36     
1.17
@@ -388,7 +388,6 @@
    scsi_remove_device - detach and remove a SCSI device
    scsi_remove_host - detach and remove all SCSI devices owned by host
    scsi_report_bus_reset - report scsi _bus_ reset observed
-   scsi_set_device - place device reference in host structure
    scsi_track_queue_full - track successive QUEUE_FULL events 
    scsi_unblock_requests - allow further commands to be queued to given host
    scsi_unregister - [calls scsi_host_put()]
@@ -741,20 +740,6 @@
 
 
 /**
- * scsi_set_device - place device reference in host structure
- * @shost: a pointer to a scsi host instance
- * @pdev: pointer to device instance to assign
- *
- *      Returns nothing
- *
- *      Might block: no
- *
- *      Defined in: include/scsi/scsi_host.h .
- **/
-void scsi_set_device(struct Scsi_Host * shost, struct device * dev)
-
-
-/**
  * scsi_track_queue_full - track successive QUEUE_FULL events on given
  *                      device to determine if and when there is a need
  *                      to adjust the queue depth on the device.
diff -urN linux/Documentation/sound/alsa/ALSA-Configuration.txt 
linux/Documentation/sound/alsa/ALSA-Configuration.txt
--- linux/Documentation/sound/alsa/ALSA-Configuration.txt       2005/07/11 
20:45:57     1.18
+++ linux/Documentation/sound/alsa/ALSA-Configuration.txt       2005/08/01 
18:23:36     1.19
@@ -636,11 +636,16 @@
          3stack-digout 3-jack in back, a HP out and a SPDIF out
          5stack        5-jack in back, 2-jack in front
          5stack-digout 5-jack in back, 2-jack in front, a SPDIF out
+         6stack        6-jack in back, 2-jack in front
+         6stack-digout 6-jack with a SPDIF out
          w810          3-jack
          z71v          3-jack (HP shared SPDIF)
          asus          3-jack
          uniwill       3-jack
          F1734         2-jack
+         test          for testing/debugging purpose, almost all controls can 
be
+                       adjusted.  Appearing only when compiled with
+                       $CONFIG_SND_DEBUG=y
 
        CMI9880
          minimal       3-jack in back
@@ -1054,6 +1059,13 @@
 
     The power-management is supported.
 
+  Module snd-pxa2xx-ac97 (on arm only)
+  ------------------------------------
+
+    Module for AC97 driver for the Intel PXA2xx chip
+
+    For ARM architecture only.
+
   Module snd-rme32
   ----------------
 
@@ -1173,6 +1185,13 @@
 
     Module supports up to 8 cards.
 
+  Module snd-sun-dbri (on sparc only)
+  -----------------------------------
+
+    Module for DBRI sound chips found on Sparcs.
+
+    Module supports up to 8 cards.
+
   Module snd-wavefront
   --------------------
 
@@ -1371,7 +1390,7 @@
   Module snd-vxpocket
   -------------------
 
-    Module for Digigram VX-Pocket VX2 PCMCIA card.
+    Module for Digigram VX-Pocket VX2 and 440 PCMCIA cards.
 
     ibl      - Capture IBL size. (default = 0, minimum size)
 
@@ -1391,29 +1410,6 @@
 
     Note: the driver is build only when CONFIG_ISA is set.
     
-  Module snd-vxp440
-  -----------------
-
-    Module for Digigram VX-Pocket 440 PCMCIA card.
-
-    ibl      - Capture IBL size. (default = 0, minimum size)
-
-    Module supports up to 8 cards.  The module is compiled only when
-    PCMCIA is supported on kernel.
-
-    To activate the driver via the card manager, you'll need to set
-    up /etc/pcmcia/vxp440.conf.  See the sound/pcmcia/vx/vxp440.c.
-
-    When the driver is compiled as a module and the hotplug firmware
-    is supported, the firmware data is loaded via hotplug automatically.
-    Install the necessary firmware files in alsa-firmware package.
-    When no hotplug fw loader is available, you need to load the
-    firmware via vxloader utility in alsa-tools package.
-
-    About capture IBL, see the description of snd-vx222 module.
-
-    Note: the driver is build only when CONFIG_ISA is set.
-    
   Module snd-ymfpci
   -----------------
 
diff -urN linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- linux/arch/alpha/kernel/process.c   2004/09/19 12:30:01     1.50
+++ linux/arch/alpha/kernel/process.c   2005/08/01 18:23:37     1.51
@@ -165,7 +165,6 @@
        common_shutdown(LINUX_REBOOT_CMD_RESTART, restart_cmd);
 }
 
-EXPORT_SYMBOL(machine_restart);
 
 void
 machine_halt(void)
@@ -173,7 +172,6 @@
        common_shutdown(LINUX_REBOOT_CMD_HALT, NULL);
 }
 
-EXPORT_SYMBOL(machine_halt);
 
 void
 machine_power_off(void)
@@ -181,7 +179,6 @@
        common_shutdown(LINUX_REBOOT_CMD_POWER_OFF, NULL);
 }
 
-EXPORT_SYMBOL(machine_power_off);
 
 /* Used by sysrq-p, among others.  I don't believe r9-r15 are ever
    saved in the context it's used.  */
diff -urN linux/arch/alpha/kernel/systbls.S linux/arch/alpha/kernel/systbls.S
--- linux/arch/alpha/kernel/systbls.S   2005/05/19 12:08:06     1.13
+++ linux/arch/alpha/kernel/systbls.S   2005/08/01 18:23:37     1.14
@@ -461,6 +461,11 @@
        .quad sys_add_key
        .quad sys_request_key                   /* 440 */
        .quad sys_keyctl
+       .quad sys_ioprio_set
+       .quad sys_ioprio_get
+       .quad sys_inotify_init
+       .quad sys_inotify_add_watch             /* 445 */
+       .quad sys_inotify_rm_watch
 
        .size sys_call_table, . - sys_call_table
        .type sys_call_table, @object
diff -urN linux/arch/arm/boot/compressed/head-shark.S 
linux/arch/arm/boot/compressed/head-shark.S
--- linux/arch/arm/boot/compressed/head-shark.S 2002/09/03 03:16:04     1.5
+++ linux/arch/arm/boot/compressed/head-shark.S 2005/08/01 18:23:37     1.6
@@ -63,8 +63,8 @@
 
                mov     pc, r2
 
-__copy_target: .long   0x08508000
-__copy_end:    .long   0x08608000
+__copy_target: .long   0x08507FFC
+__copy_end:    .long   0x08607FFC
                
                .word   _start
                .word   __bss_start
@@ -73,9 +73,10 @@
 __temp_stack:  .space 128
 
 __mmu_off:
-               adr     r0, __ofw_data
+               adr     r0, __ofw_data                  @ read the 1. entry of 
the memory map
                ldr     r0, [r0, #4]
                orr     r0, r0, #0x00600000
+               sub     r0, r0, #4
        
                ldr     r1, __copy_end
                ldr     r3, __copy_target
@@ -89,20 +90,43 @@
  * from 0x08500000 to 0x08508000 if we have only 8MB
  */
 
+/* As we get more 2.6-kernels it gets more and more
+ * uncomfortable to be bound to kernel images of 1MB only.
+ * So we add a loop here, to be able to copy some more.
+ * Alexander Schulz 2005-07-17
+ */
+
+               mov     r4, #3                          @ How many megabytes to 
copy
+
+
+__MoveCode:    sub     r4, r4, #1
        
 __Copy:                ldr     r2, [r0], #-4
                str     r2, [r1], #-4
                teq     r1, r3
                bne     __Copy
+
+               /* The firmware maps us in blocks of 1 MB, the next block is
+                  _below_ the last one. So our decrementing source pointer
+                  ist right here, but the destination pointer must be increased
+                  by 2 MB */
+               add     r1, r1, #0x00200000
+               add     r3, r3, #0x00100000
+
+               teq     r4, #0
+               bne     __MoveCode
+
+
                /* and jump to it */
-               adr     r2, __go_on
-               adr     r0, __ofw_data
+               adr     r2, __go_on                     @ where we want to jump
+               adr     r0, __ofw_data                  @ read the 1. entry of 
the memory map
                ldr     r0, [r0, #4]
-               sub     r2, r2, r0
-               sub     r2, r2, #0x00500000
-               ldr     r0, __copy_target
+               sub     r2, r2, r0                      @ we are mapped add 
0e50 now, sub that (-0e00)
+               sub     r2, r2, #0x00500000             @ -0050
+               ldr     r0, __copy_target               @ and add 0850 8000 
instead
+               add     r0, r0, #4
                add     r2, r2, r0
-               mov     pc, r2
+               mov     pc, r2                          @ and jump there
 
 __go_on:
                adr     sp, __temp_stack
diff -urN linux/arch/arm/configs/bast_defconfig 
linux/arch/arm/configs/bast_defconfig
--- linux/arch/arm/configs/bast_defconfig       2005/04/08 18:57:49     1.7
+++ linux/arch/arm/configs/bast_defconfig       2005/08/01 18:23:37     1.8
@@ -561,7 +561,6 @@
 #
 CONFIG_SERIAL_S3C2410=y
 CONFIG_SERIAL_S3C2410_CONSOLE=y
-CONFIG_SERIAL_BAST_SIO=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
diff -urN linux/arch/arm/configs/s3c2410_defconfig 
linux/arch/arm/configs/s3c2410_defconfig
--- linux/arch/arm/configs/s3c2410_defconfig    2005/07/11 20:45:59     1.11
+++ linux/arch/arm/configs/s3c2410_defconfig    2005/08/01 18:23:37     1.12
@@ -570,7 +570,6 @@
 #
 CONFIG_SERIAL_S3C2410=y
 CONFIG_SERIAL_S3C2410_CONSOLE=y
-CONFIG_SERIAL_BAST_SIO=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
diff -urN linux/arch/arm/configs/shark_defconfig 
linux/arch/arm/configs/shark_defconfig
--- linux/arch/arm/configs/shark_defconfig      2005/04/08 18:57:49     1.5
+++ linux/arch/arm/configs/shark_defconfig      2005/08/01 18:23:37     1.6
@@ -1,22 +1,21 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 23:59:14 2005
+# Linux kernel version: 2.6.12-git3
+# Sat Jul 16 15:21:47 2005
 #
 CONFIG_ARM=y
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-# CONFIG_CLEAN_COMPILE is not set
-CONFIG_BROKEN=y
+CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -33,7 +32,10 @@
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
@@ -81,6 +83,7 @@
 # CONFIG_ARCH_VERSATILE is not set
 # CONFIG_ARCH_IMX is not set
 # CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
 
 #
 # Processor Type
@@ -103,10 +106,12 @@
 #
 CONFIG_ISA=y
 CONFIG_ISA_DMA=y
+CONFIG_ISA_DMA_API=y
 CONFIG_PCI=y
 CONFIG_PCI_HOST_VIA82C505=y
 CONFIG_PCI_LEGACY_PROC=y
 # CONFIG_PCI_NAMES is not set
+# CONFIG_PCI_DEBUG is not set
 
 #
 # PCCARD (PCMCIA/CardBus) support
@@ -116,7 +121,9 @@
 #
 # Kernel Features
 #
+# CONFIG_SMP is not set
 # CONFIG_PREEMPT is not set
+# CONFIG_DISCONTIGMEM is not set
 CONFIG_LEDS=y
 CONFIG_LEDS_TIMER=y
 # CONFIG_LEDS_CPU is not set
@@ -163,6 +170,7 @@
 # CONFIG_STANDALONE is not set
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -172,8 +180,8 @@
 #
 # Parallel port support
 #
-CONFIG_PARPORT=y
-CONFIG_PARPORT_PC=y
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
 # CONFIG_PARPORT_SERIAL is not set
 # CONFIG_PARPORT_PC_FIFO is not set
 # CONFIG_PARPORT_PC_SUPERIO is not set
@@ -189,7 +197,6 @@
 #
 # 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
@@ -229,7 +236,7 @@
 # CONFIG_BLK_DEV_IDE_SATA is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
-CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDECD=m
 # CONFIG_BLK_DEV_IDETAPE is not set
 CONFIG_BLK_DEV_IDEFLOPPY=y
 # CONFIG_BLK_DEV_IDESCSI is not set
@@ -261,6 +268,7 @@
 CONFIG_BLK_DEV_SR=m
 # CONFIG_BLK_DEV_SR_VENDOR is not set
 CONFIG_CHR_DEV_SG=m
+# CONFIG_CHR_DEV_SCH is not set
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -290,17 +298,14 @@
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC79XX is not set
 # CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_MEGARAID_NEWGEN is not set
 # CONFIG_MEGARAID_LEGACY is not set
 # CONFIG_SCSI_SATA is not set
 # CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_DTC3280 is not set
 # CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_PIO is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
@@ -314,11 +319,8 @@
 # CONFIG_SCSI_SYM53C8XX_2 is not set
 # CONFIG_SCSI_IPR is not set
 # CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
 CONFIG_SCSI_QLA2XXX=m
@@ -327,6 +329,7 @@
 # CONFIG_SCSI_QLA2300 is not set
 # CONFIG_SCSI_QLA2322 is not set
 # CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
@@ -344,6 +347,8 @@
 # Fusion MPT device support
 #
 # CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -365,7 +370,6 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
@@ -380,7 +384,7 @@
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
 # CONFIG_INET_TUNNEL is not set
-# CONFIG_IP_TCPDIAG is not set
+CONFIG_IP_TCPDIAG=y
 # CONFIG_IP_TCPDIAG_IPV6 is not set
 # CONFIG_IPV6 is not set
 # CONFIG_NETFILTER is not set
@@ -439,6 +443,7 @@
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 
 #
@@ -483,9 +488,11 @@
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
+# CONFIG_SKGE is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -569,7 +576,6 @@
 CONFIG_SERIO_LIBPS2=y
 # CONFIG_SERIO_RAW is not set
 # CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
 
 #
 # Character devices
@@ -592,6 +598,7 @@
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -653,6 +660,7 @@
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
 CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
 # CONFIG_FB_MODE_HELPERS is not set
 # CONFIG_FB_TILEBLITTING is not set
 # CONFIG_FB_CIRRUS is not set
@@ -674,7 +682,7 @@
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_PM3 is not set
+# CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
 
 #
@@ -808,7 +816,7 @@
 #
 # CD-ROM/DVD Filesystems
 #
-CONFIG_ISO9660_FS=y
+CONFIG_ISO9660_FS=m
 CONFIG_JOLIET=y
 # CONFIG_ZISOFS is not set
 # CONFIG_UDF_FS is not set
@@ -816,9 +824,9 @@
 #
 # DOS/FAT/NT Filesystems
 #
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
 CONFIG_FAT_DEFAULT_CODEPAGE=437
 CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 # CONFIG_NTFS_FS is not set
@@ -833,7 +841,6 @@
 # CONFIG_DEVFS_DEBUG is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 # CONFIG_TMPFS is not set
-# CONFIG_HUGETLBFS is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
@@ -857,13 +864,14 @@
 #
 # Network File Systems
 #
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
 # CONFIG_NFS_V4 is not set
 # CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
-CONFIG_LOCKD=y
-CONFIG_SUNRPC=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_SUNRPC=m
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
@@ -895,12 +903,12 @@
 #
 # Native Language Support
 #
-CONFIG_NLS=y
+CONFIG_NLS=m
 CONFIG_NLS_DEFAULT="iso8859-1"
-CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_437=m
 # CONFIG_NLS_CODEPAGE_737 is not set
 # CONFIG_NLS_CODEPAGE_775 is not set
-CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_850=m
 # CONFIG_NLS_CODEPAGE_852 is not set
 # CONFIG_NLS_CODEPAGE_855 is not set
 # CONFIG_NLS_CODEPAGE_857 is not set
@@ -921,7 +929,7 @@
 # CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 # CONFIG_NLS_ASCII is not set
-CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_1=m
 # CONFIG_NLS_ISO8859_2 is not set
 # CONFIG_NLS_ISO8859_3 is not set
 # CONFIG_NLS_ISO8859_4 is not set
@@ -945,11 +953,22 @@
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
-# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_MAGIC_SYSRQ is not set
 CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
 CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
 CONFIG_FRAME_POINTER=y
 CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
 
 #
 # Security options
diff -urN linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c
--- linux/arch/arm/kernel/process.c     2005/07/11 20:45:59     1.52
+++ linux/arch/arm/kernel/process.c     2005/08/01 18:23:37     1.53
@@ -131,7 +131,6 @@
 {
 }
 
-EXPORT_SYMBOL(machine_halt);
 
 void machine_power_off(void)
 {
@@ -139,7 +138,6 @@
                pm_power_off();
 }
 
-EXPORT_SYMBOL(machine_power_off);
 
 void machine_restart(char * __unused)
 {
@@ -169,8 +167,6 @@
        while (1);
 }
 
-EXPORT_SYMBOL(machine_restart);
-
 void __show_regs(struct pt_regs *regs)
 {
        unsigned long flags = condition_codes(regs);
diff -urN linux/arch/arm/kernel/smp.c linux/arch/arm/kernel/smp.c
--- linux/arch/arm/kernel/smp.c 2005/07/12 09:18:55     1.4
+++ linux/arch/arm/kernel/smp.c 2005/08/01 18:23:37     1.5
@@ -36,7 +36,7 @@
  * The present bitmask indicates that the CPU is physically present.
  * The online bitmask indicates that the CPU is up and running.
  */
-cpumask_t cpu_present_mask;
+cpumask_t cpu_possible_map;
 cpumask_t cpu_online_map;
 
 /*
@@ -78,7 +78,7 @@
 static struct smp_call_struct * volatile smp_call_function_data;
 static DEFINE_SPINLOCK(smp_call_function_lock);
 
-int __init __cpu_up(unsigned int cpu)
+int __cpuinit __cpu_up(unsigned int cpu)
 {
        struct task_struct *idle;
        pgd_t *pgd;
@@ -159,7 +159,7 @@
  * This is the secondary CPU boot entry.  We're using this CPUs
  * idle thread stack, but a set of temporary page tables.
  */
-asmlinkage void __init secondary_start_kernel(void)
+asmlinkage void __cpuinit secondary_start_kernel(void)
 {
        struct mm_struct *mm = &init_mm;
        unsigned int cpu = smp_processor_id();
@@ -209,7 +209,7 @@
  * Called by both boot and secondaries to move global data into
  * per-processor storage.
  */
-void __init smp_store_cpu_info(unsigned int cpuid)
+void __cpuinit smp_store_cpu_info(unsigned int cpuid)
 {
        struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid);
 
@@ -235,7 +235,8 @@
 {
        unsigned int cpu = smp_processor_id();
 
-       cpu_set(cpu, cpu_present_mask);
+       cpu_set(cpu, cpu_possible_map);
+       cpu_set(cpu, cpu_present_map);
        cpu_set(cpu, cpu_online_map);
 }
 
@@ -355,7 +356,7 @@
 
        seq_puts(p, "IPI:");
 
-       for_each_online_cpu(cpu)
+       for_each_present_cpu(cpu)
                seq_printf(p, " %10lu", per_cpu(ipi_data, cpu).ipi_count);
 
        seq_putc(p, '\n');
diff -urN linux/arch/arm/kernel/traps.c linux/arch/arm/kernel/traps.c
--- linux/arch/arm/kernel/traps.c       2005/07/12 09:18:55     1.54
+++ linux/arch/arm/kernel/traps.c       2005/08/01 18:23:37     1.55
@@ -248,16 +248,20 @@
 
 void register_undef_hook(struct undef_hook *hook)
 {
-       spin_lock_irq(&undef_lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&undef_lock, flags);
        list_add(&hook->node, &undef_hook);
-       spin_unlock_irq(&undef_lock);
+       spin_unlock_irqrestore(&undef_lock, flags);
 }
 
 void unregister_undef_hook(struct undef_hook *hook)
 {
-       spin_lock_irq(&undef_lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&undef_lock, flags);
        list_del(&hook->node);
-       spin_unlock_irq(&undef_lock);
+       spin_unlock_irqrestore(&undef_lock, flags);
 }
 
 asmlinkage void do_undefinstr(struct pt_regs *regs)
diff -urN linux/arch/arm/lib/bitops.h linux/arch/arm/lib/bitops.h
--- linux/arch/arm/lib/bitops.h 2005/04/29 11:15:00     1.1
+++ linux/arch/arm/lib/bitops.h 2005/08/01 18:23:37     1.2
@@ -1,3 +1,33 @@
+#if __LINUX_ARM_ARCH__ >= 6
+       .macro  bitop, instr
+       mov     r2, #1
+       and     r3, r0, #7              @ Get bit offset
+       add     r1, r1, r0, lsr #3      @ Get byte offset
+       mov     r3, r2, lsl r3
+1:     ldrexb  r2, [r1]
+       \instr  r2, r2, r3
+       strexb  r0, r2, [r1]
+       cmpne   r0, #0
+       bne     1b
+       mov     pc, lr
+       .endm
+
+       .macro  testop, instr, store
+       and     r3, r0, #7              @ Get bit offset
+       mov     r2, #1
+       add     r1, r1, r0, lsr #3      @ Get byte offset
+       mov     r3, r2, lsl r3          @ create mask
+1:     ldrexb  r2, [r1]
+       ands    r0, r2, r3              @ save old value of bit
+       \instr  r2, r2, r3                      @ toggle bit
+       strexb  ip, r2, [r1]
+       cmp     ip, #0
+       bne     1b
+       cmp     r0, #0
+       movne   r0, #1
+2:     mov     pc, lr
+       .endm
+#else
        .macro  bitop, instr
        and     r2, r0, #7
        mov     r3, #1
@@ -31,3 +61,4 @@
        moveq   r0, #0
        mov     pc, lr
        .endm
+#endif
diff -urN linux/arch/arm/lib/io-shark.c linux/arch/arm/lib/io-shark.c
--- linux/arch/arm/lib/io-shark.c       2002/07/05 05:04:37     1.4
+++ linux/arch/arm/lib/io-shark.c       2005/08/01 18:23:37     1.5
@@ -11,73 +11,3 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <linux/kernel.h>
-
-#include <asm/io.h>
-
-void print_warning(void)
-{
-       printk(KERN_WARNING "ins?/outs? not implemented on this 
architecture\n");
-}
-
-void insl(unsigned int port, void *to, int len)
-{
-       print_warning();
-}
-
-void insb(unsigned int port, void *to, int len)
-{
-       print_warning();
-}
-
-void outsl(unsigned int port, const void *from, int len)
-{
-       print_warning();
-}
-
-void outsb(unsigned int port, const void *from, int len)
-{
-       print_warning();
-}
-
-/* these should be in assembler again */
-
-/*
- * Purpose: read a block of data from a hardware register to memory.
- * Proto  : insw(int from_port, void *to, int len_in_words);
- * Proto  : inswb(int from_port, void *to, int len_in_bytes);
- * Notes  : increment to
- */
-
-void insw(unsigned int port, void *to, int len)
-{
-       int i;
-
-       for (i = 0; i < len; i++)
-               ((unsigned short *) to)[i] = inw(port);
-}
-
-void inswb(unsigned int port, void *to, int len)
-{
-       insw(port, to, len >> 2);
-}
-
-/*
- * Purpose: write a block of data from memory to a hardware register.
- * Proto  : outsw(int to_reg, void *from, int len_in_words);
- * Proto  : outswb(int to_reg, void *from, int len_in_bytes);
- * Notes  : increments from
- */
-
-void outsw(unsigned int port, const void *from, int len)
-{
-       int i;
-
-       for (i = 0; i < len; i++)
-               outw(((unsigned short *) from)[i], port);
-}
-
-void outswb(unsigned int port, const void *from, int len)
-{
-       outsw(port, from, len >> 2);
-}
diff -urN linux/arch/arm/mach-integrator/platsmp.c 
linux/arch/arm/mach-integrator/platsmp.c
--- linux/arch/arm/mach-integrator/platsmp.c    2005/07/11 20:46:02     1.1
+++ linux/arch/arm/mach-integrator/platsmp.c    2005/08/01 18:23:38     1.2
@@ -27,12 +27,12 @@
  * control for which core is the next to come out of the secondary
  * boot "holding pen"
  */
-volatile int __initdata pen_release = -1;
-unsigned long __initdata phys_pen_release = 0;
+volatile int __cpuinitdata pen_release = -1;
+unsigned long __cpuinitdata phys_pen_release = 0;
 
 static DEFINE_SPINLOCK(boot_lock);
 
-void __init platform_secondary_init(unsigned int cpu)
+void __cpuinit platform_secondary_init(unsigned int cpu)
 {
        /*
         * the primary core may have used a "cross call" soft interrupt
@@ -61,7 +61,7 @@
        spin_unlock(&boot_lock);
 }
 
-int __init boot_secondary(unsigned int cpu, struct task_struct *idle)
+int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
        unsigned long timeout;
 
@@ -174,11 +174,13 @@
                max_cpus = ncores;
 
        /*
-        * Initialise the present mask - this tells us which CPUs should
-        * be present.
+        * Initialise the possible/present maps.
+        * cpu_possible_map describes the set of CPUs which may be present
+        * cpu_present_map describes the set of CPUs populated
         */
        for (i = 0; i < max_cpus; i++) {
-               cpu_set(i, cpu_present_mask);
+               cpu_set(i, cpu_possible_map);
+               cpu_set(i, cpu_present_map);
        }
 
        /*
diff -urN linux/arch/arm/mach-omap1/leds-h2p2-debug.c 
linux/arch/arm/mach-omap1/leds-h2p2-debug.c
--- linux/arch/arm/mach-omap1/leds-h2p2-debug.c 2005/07/13 11:48:52     1.1
+++ linux/arch/arm/mach-omap1/leds-h2p2-debug.c 2005/08/01 18:23:38     1.2
@@ -13,7 +13,6 @@
 #include <linux/init.h>
 #include <linux/kernel_stat.h>
 #include <linux/sched.h>
-#include <linux/version.h>
 
 #include <asm/io.h>
 #include <asm/hardware.h>
diff -urN linux/arch/arm/mach-s3c2410/irq.h linux/arch/arm/mach-s3c2410/irq.h
--- linux/arch/arm/mach-s3c2410/irq.h   1970/01/01 00:00:00
+++ linux/arch/arm/mach-s3c2410/irq.h   2005-08-01 19:23:38.387034000 +0100     
1.1
@@ -0,0 +1,99 @@
+/* arch/arm/mach-s3c2410/irq.h
+ *
+ * Copyright (c) 2004-2005 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Header file for S3C24XX CPU IRQ support
+ *
+ * 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.
+ *
+ * Modifications:
+*/
+
+#define irqdbf(x...)
+#define irqdbf2(x...)
+
+#define EXTINT_OFF (IRQ_EINT4 - 4)
+
+extern struct irqchip s3c_irq_level_chip;
+
+static inline void
+s3c_irqsub_mask(unsigned int irqno, unsigned int parentbit,
+               int subcheck)
+{
+       unsigned long mask;
+       unsigned long submask;
+
+       submask = __raw_readl(S3C2410_INTSUBMSK);
+       mask = __raw_readl(S3C2410_INTMSK);
+
+       submask |= (1UL << (irqno - IRQ_S3CUART_RX0));
+
+       /* check to see if we need to mask the parent IRQ */
+
+       if ((submask  & subcheck) == subcheck) {
+               __raw_writel(mask | parentbit, S3C2410_INTMSK);
+       }
+
+       /* write back masks */
+       __raw_writel(submask, S3C2410_INTSUBMSK);
+
+}
+
+static inline void
+s3c_irqsub_unmask(unsigned int irqno, unsigned int parentbit)
+{
+       unsigned long mask;
+       unsigned long submask;
+
+       submask = __raw_readl(S3C2410_INTSUBMSK);
+       mask = __raw_readl(S3C2410_INTMSK);
+
+       submask &= ~(1UL << (irqno - IRQ_S3CUART_RX0));
+       mask &= ~parentbit;
+
+       /* write back masks */
+       __raw_writel(submask, S3C2410_INTSUBMSK);
+       __raw_writel(mask, S3C2410_INTMSK);
+}
+
+
+static inline void
+s3c_irqsub_maskack(unsigned int irqno, unsigned int parentmask, unsigned int 
group)
+{
+       unsigned int bit = 1UL << (irqno - IRQ_S3CUART_RX0);
+
+       s3c_irqsub_mask(irqno, parentmask, group);
+
+       __raw_writel(bit, S3C2410_SUBSRCPND);
+
+       /* only ack parent if we've got all the irqs (seems we must
+        * ack, all and hope that the irq system retriggers ok when
+        * the interrupt goes off again)
+        */
+
+       if (1) {
+               __raw_writel(parentmask, S3C2410_SRCPND);
+               __raw_writel(parentmask, S3C2410_INTPND);
+       }
+}
+
+static inline void
+s3c_irqsub_ack(unsigned int irqno, unsigned int parentmask, unsigned int group)
+{
+       unsigned int bit = 1UL << (irqno - IRQ_S3CUART_RX0);
+
+       __raw_writel(bit, S3C2410_SUBSRCPND);
+
+       /* only ack parent if we've got all the irqs (seems we must
+        * ack, all and hope that the irq system retriggers ok when
+        * the interrupt goes off again)
+        */
+
+       if (1) {
+               __raw_writel(parentmask, S3C2410_SRCPND);
+               __raw_writel(parentmask, S3C2410_INTPND);
+       }
+}
diff -urN linux/arch/arm/mach-s3c2410/s3c2440-clock.c 
linux/arch/arm/mach-s3c2410/s3c2440-clock.c
--- linux/arch/arm/mach-s3c2410/s3c2440-clock.c 1970/01/01 00:00:00
+++ linux/arch/arm/mach-s3c2410/s3c2440-clock.c 2005-08-01 19:23:38.399186000 
+0100     1.1
@@ -0,0 +1,116 @@
+/* linux/arch/arm/mach-s3c2410/s3c2440-clock.c
+ *
+ * Copyright (c) 2004-2005 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2440 Clock support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/sysdev.h>
+
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include <asm/hardware.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/hardware/clock.h>
+#include <asm/arch/regs-clock.h>
+
+#include "clock.h"
+#include "cpu.h"
+
+/* S3C2440 extended clock support */
+
+static struct clk s3c2440_clk_upll = {
+       .name           = "upll",
+       .id             = -1,
+};
+
+static struct clk s3c2440_clk_cam = {
+       .name           = "camif",
+       .id             = -1,
+       .enable         = s3c24xx_clkcon_enable,
+       .ctrlbit        = S3C2440_CLKCON_CAMERA,
+};
+
+static struct clk s3c2440_clk_ac97 = {
+       .name           = "ac97",
+       .id             = -1,
+       .enable         = s3c24xx_clkcon_enable,
+       .ctrlbit        = S3C2440_CLKCON_CAMERA,
+};
+
+static int s3c2440_clk_add(struct sys_device *sysdev)
+{
+       unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
+       struct clk *clk_h;
+       struct clk *clk_p;
+       struct clk *clk_xtal;
+
+       clk_xtal = clk_get(NULL, "xtal");
+       if (IS_ERR(clk_xtal)) {
+               printk(KERN_ERR "S3C2440: Failed to get clk_xtal\n");
+               return -EINVAL;
+       }
+
+       s3c2440_clk_upll.rate = s3c2410_get_pll(upllcon, clk_xtal->rate);
+
+       printk("S3C2440: Clock Support, UPLL %ld.%03ld MHz\n",
+              print_mhz(s3c2440_clk_upll.rate));
+
+       clk_p = clk_get(NULL, "pclk");
+       clk_h = clk_get(NULL, "hclk");
+
+       if (IS_ERR(clk_p) || IS_ERR(clk_h)) {
+               printk(KERN_ERR "S3C2440: Failed to get parent clocks\n");
+               return -EINVAL;
+       }
+
+       s3c2440_clk_cam.parent = clk_h;
+       s3c2440_clk_ac97.parent = clk_p;
+
+       s3c24xx_register_clock(&s3c2440_clk_ac97);
+       s3c24xx_register_clock(&s3c2440_clk_cam);
+       s3c24xx_register_clock(&s3c2440_clk_upll);
+
+       clk_disable(&s3c2440_clk_ac97);
+       clk_disable(&s3c2440_clk_cam);
+
+       return 0;
+}
+
+static struct sysdev_driver s3c2440_clk_driver = {
+       .add    = s3c2440_clk_add,
+};
+
+static __init int s3c24xx_clk_driver(void)
+{
+       return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_clk_driver);
+}
+
+arch_initcall(s3c24xx_clk_driver);
diff -urN linux/arch/arm/mach-s3c2410/s3c2440-irq.c 
linux/arch/arm/mach-s3c2410/s3c2440-irq.c
--- linux/arch/arm/mach-s3c2410/s3c2440-irq.c   1970/01/01 00:00:00
+++ linux/arch/arm/mach-s3c2410/s3c2440-irq.c   2005-08-01 19:23:38.414519000 
+0100     1.1
@@ -0,0 +1,207 @@
+/* linux/arch/arm/mach-s3c2410/s3c2440-irq.c
+ *
+ * Copyright (c) 2003,2004 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Changelog:
+ *     25-Jul-2005 BJD         Split from irq.c
+ *
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/ptrace.h>
+#include <linux/sysdev.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/mach/irq.h>
+
+#include <asm/arch/regs-irq.h>
+#include <asm/arch/regs-gpio.h>
+
+#include "cpu.h"
+#include "pm.h"
+#include "irq.h"
+
+/* WDT/AC97 */
+
+static void s3c_irq_demux_wdtac97(unsigned int irq,
+                                 struct irqdesc *desc,
+                                 struct pt_regs *regs)
+{
+       unsigned int subsrc, submsk;
+       struct irqdesc *mydesc;
+
+       /* read the current pending interrupts, and the mask
+        * for what it is available */
+
+       subsrc = __raw_readl(S3C2410_SUBSRCPND);
+       submsk = __raw_readl(S3C2410_INTSUBMSK);
+
+       subsrc &= ~submsk;
+       subsrc >>= 13;
+       subsrc &= 3;
+
+       if (subsrc != 0) {
+               if (subsrc & 1) {
+                       mydesc = irq_desc + IRQ_S3C2440_WDT;
+                       mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs);
+               }
+               if (subsrc & 2) {
+                       mydesc = irq_desc + IRQ_S3C2440_AC97;
+                       mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs);
+               }
+       }
+}
+
+
+#define INTMSK_WDT      (1UL << (IRQ_WDT - IRQ_EINT0))
+
+static void
+s3c_irq_wdtac97_mask(unsigned int irqno)
+{
+       s3c_irqsub_mask(irqno, INTMSK_WDT, 3<<13);
+}
+
+static void
+s3c_irq_wdtac97_unmask(unsigned int irqno)
+{
+       s3c_irqsub_unmask(irqno, INTMSK_WDT);
+}
+
+static void
+s3c_irq_wdtac97_ack(unsigned int irqno)
+{
+       s3c_irqsub_maskack(irqno, INTMSK_WDT, 3<<13);
+}
+
+static struct irqchip s3c_irq_wdtac97 = {
+       .mask       = s3c_irq_wdtac97_mask,
+       .unmask     = s3c_irq_wdtac97_unmask,
+       .ack        = s3c_irq_wdtac97_ack,
+};
+
+/* camera irq */
+
+static void s3c_irq_demux_cam(unsigned int irq,
+                             struct irqdesc *desc,
+                             struct pt_regs *regs)
+{
+       unsigned int subsrc, submsk;
+       struct irqdesc *mydesc;
+
+       /* read the current pending interrupts, and the mask
+        * for what it is available */
+
+       subsrc = __raw_readl(S3C2410_SUBSRCPND);
+       submsk = __raw_readl(S3C2410_INTSUBMSK);
+
+       subsrc &= ~submsk;
+       subsrc >>= 11;
+       subsrc &= 3;
+
+       if (subsrc != 0) {
+               if (subsrc & 1) {
+                       mydesc = irq_desc + IRQ_S3C2440_CAM_C;
+                       mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs);
+               }
+               if (subsrc & 2) {
+                       mydesc = irq_desc + IRQ_S3C2440_CAM_P;
+                       mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs);
+               }
+       }
+}
+
+#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
+
+static void
+s3c_irq_cam_mask(unsigned int irqno)
+{
+       s3c_irqsub_mask(irqno, INTMSK_CAM, 3<<11);
+}
+
+static void
+s3c_irq_cam_unmask(unsigned int irqno)
+{
+       s3c_irqsub_unmask(irqno, INTMSK_CAM);
+}
+
+static void
+s3c_irq_cam_ack(unsigned int irqno)
+{
+       s3c_irqsub_maskack(irqno, INTMSK_CAM, 3<<11);
+}
+
+static struct irqchip s3c_irq_cam = {
+       .mask       = s3c_irq_cam_mask,
+       .unmask     = s3c_irq_cam_unmask,
+       .ack        = s3c_irq_cam_ack,
+};
+
+static int s3c2440_irq_add(struct sys_device *sysdev)
+{
+       unsigned int irqno;
+
+       printk("S3C2440: IRQ Support\n");
+
+       set_irq_chip(IRQ_NFCON, &s3c_irq_level_chip);
+       set_irq_handler(IRQ_NFCON, do_level_IRQ);
+       set_irq_flags(IRQ_NFCON, IRQF_VALID);
+
+       /* add new chained handler for wdt, ac7 */
+
+       set_irq_chip(IRQ_WDT, &s3c_irq_level_chip);
+       set_irq_handler(IRQ_WDT, do_level_IRQ);
+       set_irq_chained_handler(IRQ_WDT, s3c_irq_demux_wdtac97);
+
+       for (irqno = IRQ_S3C2440_WDT; irqno <= IRQ_S3C2440_AC97; irqno++) {
+               set_irq_chip(irqno, &s3c_irq_wdtac97);
+               set_irq_handler(irqno, do_level_IRQ);
+               set_irq_flags(irqno, IRQF_VALID);
+       }
+
+       /* add chained handler for camera */
+
+       set_irq_chip(IRQ_CAM, &s3c_irq_level_chip);
+       set_irq_handler(IRQ_CAM, do_level_IRQ);
+       set_irq_chained_handler(IRQ_CAM, s3c_irq_demux_cam);
+
+       for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) {
+               set_irq_chip(irqno, &s3c_irq_cam);
+               set_irq_handler(irqno, do_level_IRQ);
+               set_irq_flags(irqno, IRQF_VALID);
+       }
+
+       return 0;
+}
+
+static struct sysdev_driver s3c2440_irq_driver = {
+       .add    = s3c2440_irq_add,
+};
+
+static int s3c24xx_irq_driver(void)
+{
+       return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_irq_driver);
+}
+
+arch_initcall(s3c24xx_irq_driver);
+
diff -urN linux/arch/arm/mach-s3c2410/Makefile 
linux/arch/arm/mach-s3c2410/Makefile
--- linux/arch/arm/mach-s3c2410/Makefile        2005/07/12 09:18:58     1.10
+++ linux/arch/arm/mach-s3c2410/Makefile        2005/08/01 18:23:38     1.11
@@ -23,6 +23,8 @@
 # S3C2440 support
 
 obj-$(CONFIG_CPU_S3C2440)  += s3c2440.o s3c2440-dsc.o
+obj-$(CONFIG_CPU_S3C2440)  += s3c2440-irq.o
+obj-$(CONFIG_CPU_S3C2440)  += s3c2440-clock.o
 
 # machine specific support
 
diff -urN linux/arch/arm/mach-s3c2410/clock.c 
linux/arch/arm/mach-s3c2410/clock.c
--- linux/arch/arm/mach-s3c2410/clock.c 2005/05/26 09:12:36     1.8
+++ linux/arch/arm/mach-s3c2410/clock.c 2005/08/01 18:23:38     1.9
@@ -448,60 +448,3 @@
 
        return 0;
 }
-
-/* S3C2440 extended clock support */
-
-#ifdef CONFIG_CPU_S3C2440
-
-static struct clk s3c2440_clk_upll = {
-       .name           = "upll",
-       .id             = -1,
-};
-
-static struct clk s3c2440_clk_cam = {
-       .name           = "camif",
-       .parent         = &clk_h,
-       .id             = -1,
-       .enable         = s3c24xx_clkcon_enable,
-       .ctrlbit        = S3C2440_CLKCON_CAMERA,
-};
-
-static struct clk s3c2440_clk_ac97 = {
-       .name           = "ac97",
-       .parent         = &clk_p,
-       .id             = -1,
-       .enable         = s3c24xx_clkcon_enable,
-       .ctrlbit        = S3C2440_CLKCON_CAMERA,
-};
-
-static int s3c2440_clk_add(struct sys_device *sysdev)
-{
-       unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
-
-       s3c2440_clk_upll.rate = s3c2410_get_pll(upllcon, clk_xtal.rate);
-
-       printk("S3C2440: Clock Support, UPLL %ld.%03ld MHz\n",
-              print_mhz(s3c2440_clk_upll.rate));
-
-       s3c24xx_register_clock(&s3c2440_clk_ac97);
-       s3c24xx_register_clock(&s3c2440_clk_cam);
-       s3c24xx_register_clock(&s3c2440_clk_upll);
-
-       clk_disable(&s3c2440_clk_ac97);
-       clk_disable(&s3c2440_clk_cam);
-
-       return 0;
-}
-
-static struct sysdev_driver s3c2440_clk_driver = {
-       .add    = s3c2440_clk_add,
-};
-
-static int s3c24xx_clk_driver(void)
-{
-       return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_clk_driver);
-}
-
-arch_initcall(s3c24xx_clk_driver);
-
-#endif /* CONFIG_CPU_S3C2440 */
diff -urN linux/arch/arm/mach-s3c2410/dma.c linux/arch/arm/mach-s3c2410/dma.c
--- linux/arch/arm/mach-s3c2410/dma.c   2005/06/18 14:42:39     1.7
+++ linux/arch/arm/mach-s3c2410/dma.c   2005/08/01 18:23:38     1.8
@@ -436,7 +436,7 @@
 
        buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC);
        if (buf == NULL) {
-               pr_debug("%s: out of memory (%d alloc)\n",
+               pr_debug("%s: out of memory (%ld alloc)\n",
                         __FUNCTION__, sizeof(*buf));
                return -ENOMEM;
        }
diff -urN linux/arch/arm/mach-s3c2410/irq.c linux/arch/arm/mach-s3c2410/irq.c
--- linux/arch/arm/mach-s3c2410/irq.c   2005/07/11 20:46:03     1.7
+++ linux/arch/arm/mach-s3c2410/irq.c   2005/08/01 18:23:38     1.8
@@ -45,6 +45,9 @@
  *
  *   28-Jun-2005  Ben Dooks
  *               Mark IRQ_LCD valid
+ *
+ *   25-Jul-2005  Ben Dooks
+ *               Split the S3C2440 IRQ code to seperate file
 */
 
 #include <linux/init.h>
@@ -65,11 +68,7 @@
 
 #include "cpu.h"
 #include "pm.h"
-
-#define irqdbf(x...)
-#define irqdbf2(x...)
-
-#define EXTINT_OFF (IRQ_EINT4 - 4)
+#include "irq.h"
 
 /* wakeup irq control */
 
@@ -181,7 +180,7 @@
        __raw_writel(mask, S3C2410_INTMSK);
 }
 
-static struct irqchip s3c_irq_level_chip = {
+struct irqchip s3c_irq_level_chip = {
        .ack       = s3c_irq_maskack,
        .mask      = s3c_irq_mask,
        .unmask    = s3c_irq_unmask,
@@ -370,84 +369,6 @@
 #define INTMSK_UART2    (1UL << (IRQ_UART2 - IRQ_EINT0))
 #define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0))
 
-static inline void
-s3c_irqsub_mask(unsigned int irqno, unsigned int parentbit,
-               int subcheck)
-{
-       unsigned long mask;
-       unsigned long submask;
-
-       submask = __raw_readl(S3C2410_INTSUBMSK);
-       mask = __raw_readl(S3C2410_INTMSK);
-
-       submask |= (1UL << (irqno - IRQ_S3CUART_RX0));
-
-       /* check to see if we need to mask the parent IRQ */
-
-       if ((submask  & subcheck) == subcheck) {
-               __raw_writel(mask | parentbit, S3C2410_INTMSK);
-       }
-
-       /* write back masks */
-       __raw_writel(submask, S3C2410_INTSUBMSK);
-
-}
-
-static inline void
-s3c_irqsub_unmask(unsigned int irqno, unsigned int parentbit)
-{
-       unsigned long mask;
-       unsigned long submask;
-
-       submask = __raw_readl(S3C2410_INTSUBMSK);
-       mask = __raw_readl(S3C2410_INTMSK);
-
-       submask &= ~(1UL << (irqno - IRQ_S3CUART_RX0));
-       mask &= ~parentbit;
-
-       /* write back masks */
-       __raw_writel(submask, S3C2410_INTSUBMSK);
-       __raw_writel(mask, S3C2410_INTMSK);
-}
-
-
-static inline void
-s3c_irqsub_maskack(unsigned int irqno, unsigned int parentmask, unsigned int 
group)
-{
-       unsigned int bit = 1UL << (irqno - IRQ_S3CUART_RX0);
-
-       s3c_irqsub_mask(irqno, parentmask, group);
-
-       __raw_writel(bit, S3C2410_SUBSRCPND);
-
-       /* only ack parent if we've got all the irqs (seems we must
-        * ack, all and hope that the irq system retriggers ok when
-        * the interrupt goes off again)
-        */
-
-       if (1) {
-               __raw_writel(parentmask, S3C2410_SRCPND);
-               __raw_writel(parentmask, S3C2410_INTPND);
-       }
-}
-
-static inline void
-s3c_irqsub_ack(unsigned int irqno, unsigned int parentmask, unsigned int group)
-{
-       unsigned int bit = 1UL << (irqno - IRQ_S3CUART_RX0);
-
-       __raw_writel(bit, S3C2410_SUBSRCPND);
-
-       /* only ack parent if we've got all the irqs (seems we must
-        * ack, all and hope that the irq system retriggers ok when
-        * the interrupt goes off again)
-        */
-
-       if (1) {
-               __raw_writel(parentmask, S3C2410_SRCPND);
-               __raw_writel(parentmask, S3C2410_INTPND);
-       }
-}
 
 /* UART0 */
 
@@ -794,174 +715,3 @@
 
        irqdbf("s3c2410: registered interrupt handlers\n");
 }
-
-/* s3c2440 irq code
-*/
-
-#ifdef CONFIG_CPU_S3C2440
-
-/* WDT/AC97 */
-
-static void s3c_irq_demux_wdtac97(unsigned int irq,
-                                 struct irqdesc *desc,
-                                 struct pt_regs *regs)
-{
-       unsigned int subsrc, submsk;
-       struct irqdesc *mydesc;
-
-       /* read the current pending interrupts, and the mask
-        * for what it is available */
-
-       subsrc = __raw_readl(S3C2410_SUBSRCPND);
-       submsk = __raw_readl(S3C2410_INTSUBMSK);
-
-       subsrc &= ~submsk;
-       subsrc >>= 13;
-       subsrc &= 3;
-
-       if (subsrc != 0) {
-               if (subsrc & 1) {
-                       mydesc = irq_desc + IRQ_S3C2440_WDT;
-                       mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs);
-               }
-               if (subsrc & 2) {
-                       mydesc = irq_desc + IRQ_S3C2440_AC97;
-                       mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs);
-               }
-       }
-}
-
-
-#define INTMSK_WDT      (1UL << (IRQ_WDT - IRQ_EINT0))
-
-static void
-s3c_irq_wdtac97_mask(unsigned int irqno)
-{
-       s3c_irqsub_mask(irqno, INTMSK_WDT, 3<<13);
-}
-
-static void
-s3c_irq_wdtac97_unmask(unsigned int irqno)
-{
-       s3c_irqsub_unmask(irqno, INTMSK_WDT);
-}
-
-static void
-s3c_irq_wdtac97_ack(unsigned int irqno)
-{
-       s3c_irqsub_maskack(irqno, INTMSK_WDT, 3<<13);
-}
-
-static struct irqchip s3c_irq_wdtac97 = {
-       .mask       = s3c_irq_wdtac97_mask,
-       .unmask     = s3c_irq_wdtac97_unmask,
-       .ack        = s3c_irq_wdtac97_ack,
-};
-
-/* camera irq */
-
-static void s3c_irq_demux_cam(unsigned int irq,
-                             struct irqdesc *desc,
-                             struct pt_regs *regs)
-{
-       unsigned int subsrc, submsk;
-       struct irqdesc *mydesc;
-
-       /* read the current pending interrupts, and the mask
-        * for what it is available */
-
-       subsrc = __raw_readl(S3C2410_SUBSRCPND);
-       submsk = __raw_readl(S3C2410_INTSUBMSK);
-
-       subsrc &= ~submsk;
-       subsrc >>= 11;
-       subsrc &= 3;
-
-       if (subsrc != 0) {
-               if (subsrc & 1) {
-                       mydesc = irq_desc + IRQ_S3C2440_CAM_C;
-                       mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs);
-               }
-               if (subsrc & 2) {
-                       mydesc = irq_desc + IRQ_S3C2440_CAM_P;
-                       mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs);
-               }
-       }
-}
-
-#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
-
-static void
-s3c_irq_cam_mask(unsigned int irqno)
-{
-       s3c_irqsub_mask(irqno, INTMSK_CAM, 3<<11);
-}
-
-static void
-s3c_irq_cam_unmask(unsigned int irqno)
-{
-       s3c_irqsub_unmask(irqno, INTMSK_CAM);
-}
-
-static void
-s3c_irq_cam_ack(unsigned int irqno)
-{
-       s3c_irqsub_maskack(irqno, INTMSK_CAM, 3<<11);
-}
-
-static struct irqchip s3c_irq_cam = {
-       .mask       = s3c_irq_cam_mask,
-       .unmask     = s3c_irq_cam_unmask,
-       .ack        = s3c_irq_cam_ack,
-};
-
-static int s3c2440_irq_add(struct sys_device *sysdev)
-{
-       unsigned int irqno;
-
-       printk("S3C2440: IRQ Support\n");
-
-       set_irq_chip(IRQ_NFCON, &s3c_irq_level_chip);
-       set_irq_handler(IRQ_NFCON, do_level_IRQ);
-       set_irq_flags(IRQ_NFCON, IRQF_VALID);
-
-       /* add new chained handler for wdt, ac7 */
-
-       set_irq_chip(IRQ_WDT, &s3c_irq_level_chip);
-       set_irq_handler(IRQ_WDT, do_level_IRQ);
-       set_irq_chained_handler(IRQ_WDT, s3c_irq_demux_wdtac97);
-
-       for (irqno = IRQ_S3C2440_WDT; irqno <= IRQ_S3C2440_AC97; irqno++) {
-               set_irq_chip(irqno, &s3c_irq_wdtac97);
-               set_irq_handler(irqno, do_level_IRQ);
-               set_irq_flags(irqno, IRQF_VALID);
-       }
-
-       /* add chained handler for camera */
-
-       set_irq_chip(IRQ_CAM, &s3c_irq_level_chip);
-       set_irq_handler(IRQ_CAM, do_level_IRQ);
-       set_irq_chained_handler(IRQ_CAM, s3c_irq_demux_cam);
-
-       for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) {
-               set_irq_chip(irqno, &s3c_irq_cam);
-               set_irq_handler(irqno, do_level_IRQ);
-               set_irq_flags(irqno, IRQF_VALID);
-       }
-
-       return 0;
-}
-
-static struct sysdev_driver s3c2440_irq_driver = {
-       .add    = s3c2440_irq_add,
-};
-
-static int s3c24xx_irq_driver(void)
-{
-       return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_irq_driver);
-}
-
-arch_initcall(s3c24xx_irq_driver);
-
-#endif /* CONFIG_CPU_S3C2440 */
-
diff -urN linux/arch/arm/mach-s3c2410/mach-bast.c 
linux/arch/arm/mach-s3c2410/mach-bast.c
--- linux/arch/arm/mach-s3c2410/mach-bast.c     2005/07/12 09:18:58     1.12
+++ linux/arch/arm/mach-s3c2410/mach-bast.c     2005/08/01 18:23:38     1.13
@@ -25,9 +25,11 @@
  *     14-Jan-2005 BJD  Add support for muitlple NAND devices
  *     03-Mar-2005 BJD  Ensured that bast-cpld.h is included
  *     10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
- *     14-Mar-2006 BJD  Updated for __iomem changes
- *     22-Jun-2006 BJD  Added DM9000 platform information
- *     28-Jun-2006 BJD  Moved pm functionality out to common code
+ *     14-Mar-2005 BJD  Updated for __iomem changes
+ *     22-Jun-2005 BJD  Added DM9000 platform information
+ *     28-Jun-2005 BJD  Moved pm functionality out to common code
+ *     17-Jul-2005 BJD  Changed to platform device for SuperIO 16550s
+ *     25-Jul-2005 BJD  Removed ASIX static mappings
 */
 
 #include <linux/kernel.h>
@@ -64,6 +66,8 @@
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 
+#include <linux/serial_8250.h>
+
 #include "clock.h"
 #include "devs.h"
 #include "cpu.h"
@@ -113,7 +117,6 @@
   /* slow, byte */
   { VA_C2(BAST_VA_ISAIO),   PA_CS2(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
   { VA_C2(BAST_VA_ISAMEM),  PA_CS2(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
-  { VA_C2(BAST_VA_ASIXNET), PA_CS3(BAST_PA_ASIXNET),  SZ_1M,  MT_DEVICE },
   { VA_C2(BAST_VA_SUPERIO), PA_CS2(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
   { VA_C2(BAST_VA_IDEPRI),  PA_CS3(BAST_PA_IDEPRI),   SZ_1M,  MT_DEVICE },
   { VA_C2(BAST_VA_IDESEC),  PA_CS3(BAST_PA_IDESEC),   SZ_1M,  MT_DEVICE },
@@ -123,7 +126,6 @@
   /* slow, word */
   { VA_C3(BAST_VA_ISAIO),   PA_CS3(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
   { VA_C3(BAST_VA_ISAMEM),  PA_CS3(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
-  { VA_C3(BAST_VA_ASIXNET), PA_CS3(BAST_PA_ASIXNET),  SZ_1M,  MT_DEVICE },
   { VA_C3(BAST_VA_SUPERIO), PA_CS3(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
   { VA_C3(BAST_VA_IDEPRI),  PA_CS3(BAST_PA_IDEPRI),   SZ_1M,  MT_DEVICE },
   { VA_C3(BAST_VA_IDESEC),  PA_CS3(BAST_PA_IDESEC),   SZ_1M,  MT_DEVICE },
@@ -133,7 +135,6 @@
   /* fast, byte */
   { VA_C4(BAST_VA_ISAIO),   PA_CS4(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
   { VA_C4(BAST_VA_ISAMEM),  PA_CS4(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
-  { VA_C4(BAST_VA_ASIXNET), PA_CS5(BAST_PA_ASIXNET),  SZ_1M,  MT_DEVICE },
   { VA_C4(BAST_VA_SUPERIO), PA_CS4(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
   { VA_C4(BAST_VA_IDEPRI),  PA_CS5(BAST_PA_IDEPRI),   SZ_1M,  MT_DEVICE },
   { VA_C4(BAST_VA_IDESEC),  PA_CS5(BAST_PA_IDESEC),   SZ_1M,  MT_DEVICE },
@@ -143,7 +144,6 @@
   /* fast, word */
   { VA_C5(BAST_VA_ISAIO),   PA_CS5(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE },
   { VA_C5(BAST_VA_ISAMEM),  PA_CS5(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE },
-  { VA_C5(BAST_VA_ASIXNET), PA_CS5(BAST_PA_ASIXNET),  SZ_1M,  MT_DEVICE },
   { VA_C5(BAST_VA_SUPERIO), PA_CS5(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE },
   { VA_C5(BAST_VA_IDEPRI),  PA_CS5(BAST_PA_IDEPRI),   SZ_1M,  MT_DEVICE },
   { VA_C5(BAST_VA_IDESEC),  PA_CS5(BAST_PA_IDESEC),   SZ_1M,  MT_DEVICE },
@@ -351,6 +351,39 @@
        }
 };
 
+/* serial devices */
+
+#define SERIAL_BASE  (S3C2410_CS2 + BAST_PA_SUPERIO)
+#define SERIAL_FLAGS (UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SHARE_IRQ)
+#define SERIAL_CLK   (1843200)
+
+static struct plat_serial8250_port bast_sio_data[] = {
+       [0] = {
+               .mapbase        = SERIAL_BASE + 0x2f8,
+               .irq            = IRQ_PCSERIAL1,
+               .flags          = SERIAL_FLAGS,
+               .iotype         = UPIO_MEM,
+               .regshift       = 0,
+               .uartclk        = SERIAL_CLK,
+       },
+       [1] = {
+               .mapbase        = SERIAL_BASE + 0x3f8,
+               .irq            = IRQ_PCSERIAL2,
+               .flags          = SERIAL_FLAGS,
+               .iotype         = UPIO_MEM,
+               .regshift       = 0,
+               .uartclk        = SERIAL_CLK,
+       },
+       { }
+};
+
+static struct platform_device bast_sio = {
+       .name                   = "serial8250",
+       .id                     = 0,
+       .dev                    = {
+               .platform_data  = &bast_sio_data,
+       },
+};
 
 /* Standard BAST devices */
 
@@ -364,6 +397,7 @@
        &s3c_device_nand,
        &bast_device_nor,
        &bast_device_dm9k,
+       &bast_sio,
 };
 
 static struct clk *bast_clocks[] = {
diff -urN linux/arch/arm/mach-shark/core.c linux/arch/arm/mach-shark/core.c
--- linux/arch/arm/mach-shark/core.c    2005/07/12 09:18:59     1.8
+++ linux/arch/arm/mach-shark/core.c    2005/08/01 18:23:38     1.9
@@ -24,7 +24,7 @@
                .iobase         = 0x3f8,
                .irq            = 4,
                .uartclk        = 1843200,
-               .regshift       = 2,
+               .regshift       = 0,
                .iotype         = UPIO_PORT,
                .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
        },
@@ -32,7 +32,7 @@
                .iobase         = 0x2f8,
                .irq            = 3,
                .uartclk        = 1843200,
-               .regshift       = 2,
+               .regshift       = 0,
                .iotype         = UPIO_PORT,
                .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
        },
diff -urN linux/arch/arm/mm/mm-armv.c linux/arch/arm/mm/mm-armv.c
--- linux/arch/arm/mm/mm-armv.c 2005/07/13 11:48:53     1.51
+++ linux/arch/arm/mm/mm-armv.c 2005/08/01 18:23:38     1.52
@@ -425,6 +425,9 @@
                mem_types[MT_ROM].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
                mem_types[MT_MINICLEAN].prot_sect |= 
PMD_SECT_APX|PMD_SECT_AP_WRITE;
                mem_types[MT_CACHECLEAN].prot_sect |= 
PMD_SECT_APX|PMD_SECT_AP_WRITE;
+
+               mem_types[MT_DEVICE].prot_pte |= L_PTE_BUFFERABLE;
+               mem_types[MT_DEVICE].prot_sect |= PMD_SECT_BUFFERED;
        }
 
        cp = &cache_policies[cachepolicy];
diff -urN linux/arch/arm/nwfpe/fpa11.h linux/arch/arm/nwfpe/fpa11.h
--- linux/arch/arm/nwfpe/fpa11.h        2004/08/13 07:18:51     1.9
+++ linux/arch/arm/nwfpe/fpa11.h        2005/08/01 18:23:38     1.10
@@ -29,9 +29,7 @@
  * stack+task struct.  Use the same method as 'current' uses to
  * reach them.
  */
-register unsigned long *user_registers asm("sl");
-
-#define GET_USERREG() (user_registers)
+#define GET_USERREG() ((struct pt_regs *)(THREAD_START_SP + (unsigned 
long)current_thread_info()) - 1)
 
 #include <linux/config.h>
 #include <linux/thread_info.h>
diff -urN linux/arch/arm/nwfpe/fpmodule.c linux/arch/arm/nwfpe/fpmodule.c
--- linux/arch/arm/nwfpe/fpmodule.c     2004/08/13 07:18:51     1.14
+++ linux/arch/arm/nwfpe/fpmodule.c     2005/08/01 18:23:38     1.15
@@ -24,7 +24,6 @@
 #include "fpa11.h"
 
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/config.h>
 
 /* XXX */
@@ -133,7 +132,7 @@
        printk(KERN_DEBUG
               "NWFPE: %s[%d] takes exception %08x at %p from %08lx\n",
               current->comm, current->pid, flags,
-              __builtin_return_address(0), GET_USERREG()[15]);
+              __builtin_return_address(0), GET_USERREG()->ARM_pc);
 #endif
 
        /* Keep SoftFloat exception flags up to date.  */
diff -urN linux/arch/arm/nwfpe/fpmodule.inl linux/arch/arm/nwfpe/fpmodule.inl
--- linux/arch/arm/nwfpe/fpmodule.inl   2004/08/13 07:18:51     1.6
+++ linux/arch/arm/nwfpe/fpmodule.inl   2005/08/01 18:23:38     1.7
@@ -28,8 +28,8 @@
           for this in this routine.  LDF/STF instructions with Rn = PC
           depend on the PC being correct, as they use PC+8 in their
           address calculations. */
-       unsigned long *userRegisters = GET_USERREG();
-       unsigned int val = userRegisters[nReg];
+       struct pt_regs *regs = GET_USERREG();
+       unsigned int val = regs->uregs[nReg];
        if (REG_PC == nReg)
                val -= 4;
        return val;
@@ -38,8 +38,8 @@
 static inline void
 writeRegister(const unsigned int nReg, const unsigned long val)
 {
-       unsigned long *userRegisters = GET_USERREG();
-       userRegisters[nReg] = val;
+       struct pt_regs *regs = GET_USERREG();
+       regs->uregs[nReg] = val;
 }
 
 static inline unsigned long readCPSR(void)
@@ -63,12 +63,12 @@
 
 static inline void writeConditionCodes(const unsigned long val)
 {
-       unsigned long *userRegisters = GET_USERREG();
+       struct pt_regs *regs = GET_USERREG();
        unsigned long rval;
        /*
         * Operate directly on userRegisters since
         * the CPSR may be the PC register itself.
         */
-       rval = userRegisters[REG_CPSR] & ~CC_MASK;
-       userRegisters[REG_CPSR] = rval | (val & CC_MASK);
+       rval = regs->ARM_cpsr & ~CC_MASK;
+       regs->ARM_cpsr = rval | (val & CC_MASK);
 }
diff -urN linux/arch/arm/plat-omap/ocpi.c linux/arch/arm/plat-omap/ocpi.c
--- linux/arch/arm/plat-omap/ocpi.c     2005/07/13 11:48:53     1.1
+++ linux/arch/arm/plat-omap/ocpi.c     2005/08/01 18:23:39     1.2
@@ -25,7 +25,6 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
diff -urN linux/arch/arm26/kernel/process.c linux/arch/arm26/kernel/process.c
--- linux/arch/arm26/kernel/process.c   2005/02/07 02:54:31     1.8
+++ linux/arch/arm26/kernel/process.c   2005/08/01 18:23:39     1.9
@@ -103,9 +103,6 @@
 {
 }
 
-EXPORT_SYMBOL(machine_halt);
-EXPORT_SYMBOL(machine_power_off);
-
 void machine_restart(char * __unused)
 {
        /*
@@ -136,8 +133,6 @@
        while (1);
 }
 
-EXPORT_SYMBOL(machine_restart);
-
 void show_regs(struct pt_regs * regs)
 {
        unsigned long flags;
diff -urN linux/arch/cris/Kconfig.debug linux/arch/cris/Kconfig.debug
--- linux/arch/cris/Kconfig.debug       2004/11/15 11:49:15     1.2
+++ linux/arch/cris/Kconfig.debug       2005/08/01 18:23:39     1.3
@@ -38,4 +38,9 @@
           If you don't debug the kernel, you can say N, but we may not be able
           to solve problems without frame pointers.
 
+config DEBUG_NMI_OOPS
+       bool "NMI causes oops printout"
+       help
+         If the system locks up without any debug information you can say Y
+         here to make it possible to dump an OOPS with an external NMI.
 endmenu
diff -urN linux/arch/cris/Makefile linux/arch/cris/Makefile
--- linux/arch/cris/Makefile    2004/11/15 11:49:15     1.19
+++ linux/arch/cris/Makefile    2005/08/01 18:23:39     1.20
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.23 2004/10/19 13:07:34 starvik Exp $
+# $Id: Makefile,v 1.28 2005/03/17 10:44:37 larsv Exp $
 # cris/Makefile
 #
 # This file is included by the global makefile so that you can add your own
@@ -15,6 +15,7 @@
 
 arch-y := v10
 arch-$(CONFIG_ETRAX_ARCH_V10) := v10
+arch-$(CONFIG_ETRAX_ARCH_V32) := v32
 
 # No config avaiable for make clean etc
 ifneq ($(arch-y),)
@@ -46,6 +47,21 @@
 drivers-y      += arch/$(ARCH)/$(SARCH)/drivers/
 libs-y         += arch/$(ARCH)/$(SARCH)/lib/ $(LIBGCC)
 
+# cris source path
+SRC_ARCH              = $(srctree)/arch/$(ARCH)
+# cris object files path
+OBJ_ARCH              = $(objtree)/arch/$(ARCH)
+
+target_boot_arch_dir  = $(OBJ_ARCH)/$(SARCH)/boot
+target_boot_dir       = $(OBJ_ARCH)/boot
+src_boot_dir          = $(SRC_ARCH)/boot
+target_compressed_dir = $(OBJ_ARCH)/boot/compressed
+src_compressed_dir    = $(SRC_ARCH)/boot/compressed
+target_rescue_dir     = $(OBJ_ARCH)/boot/rescue
+src_rescue_dir        = $(SRC_ARCH)/boot/rescue
+
+export target_boot_arch_dir target_boot_dir src_boot_dir target_compressed_dir 
src_compressed_dir target_rescue_dir src_rescue_dir
+
 vmlinux.bin: vmlinux
        $(OBJCOPY) $(OBJCOPYFLAGS) vmlinux vmlinux.bin
 
@@ -65,44 +81,52 @@
 
 clinux: vmlinux.bin decompress.bin rescue.bin
 
-decompress.bin: FORCE
-       @make -C arch/$(ARCH)/boot/compressed decompress.bin
+decompress.bin: $(target_boot_dir)
+       @$(MAKE) -f $(src_compressed_dir)/Makefile 
$(target_compressed_dir)/decompress.bin
 
-rescue.bin: FORCE
-       @make -C arch/$(ARCH)/boot/rescue rescue.bin
+$(target_rescue_dir)/rescue.bin: $(target_boot_dir)
+       @$(MAKE) -f $(src_rescue_dir)/Makefile $(target_rescue_dir)/rescue.bin
 
-zImage: vmlinux.bin rescue.bin
+zImage: $(target_boot_dir) vmlinux.bin $(target_rescue_dir)/rescue.bin
 ## zImage     - Compressed kernel (gzip)
-       @make -C arch/$(ARCH)/boot/ zImage
+       @$(MAKE) -f $(src_boot_dir)/Makefile zImage
+
+$(target_boot_dir): $(target_boot_arch_dir)
+       ln -sfn $< $@
+
+$(target_boot_arch_dir):
+       mkdir -p $@
 
 compressed: zImage
 
 archmrproper:
 archclean:
-       $(Q)$(MAKE) $(clean)=arch/$(ARCH)/boot
+       @if [ -d arch/$(ARCH)/boot ]; then \
+               $(MAKE) $(clean)=arch/$(ARCH)/boot ; \
+       fi
        rm -f timage vmlinux.bin decompress.bin rescue.bin cramfs.img
        rm -rf $(LD_SCRIPT).tmp
 
-prepare: arch/$(ARCH)/.links include/asm-$(ARCH)/.arch \
+prepare: $(SRC_ARCH)/.links $(srctree)/include/asm-$(ARCH)/.arch \
         include/asm-$(ARCH)/$(SARCH)/offset.h
 
 # Create some links to make all tools happy
-arch/$(ARCH)/.links:
-       @rm -rf arch/$(ARCH)/drivers
-       @ln -sfn $(SARCH)/drivers arch/$(ARCH)/drivers
-       @rm -rf arch/$(ARCH)/boot
-       @ln -sfn $(SARCH)/boot arch/$(ARCH)/boot
-       @rm -rf arch/$(ARCH)/lib
-       @ln -sfn $(SARCH)/lib arch/$(ARCH)/lib
-       @ln -sfn $(SARCH) arch/$(ARCH)/arch
-       @ln -sfn ../$(SARCH)/vmlinux.lds.S arch/$(ARCH)/kernel/vmlinux.lds.S
+$(SRC_ARCH)/.links:
+       @rm -rf $(SRC_ARCH)/drivers
+       @ln -sfn $(SRC_ARCH)/$(SARCH)/drivers $(SRC_ARCH)/drivers
+       @rm -rf $(SRC_ARCH)/boot
+       @ln -sfn $(SRC_ARCH)/$(SARCH)/boot $(SRC_ARCH)/boot
+       @rm -rf $(SRC_ARCH)/lib
+       @ln -sfn $(SRC_ARCH)/$(SARCH)/lib $(SRC_ARCH)/lib
+       @ln -sfn $(SRC_ARCH)/$(SARCH) $(SRC_ARCH)/arch
+       @ln -sfn $(SRC_ARCH)/$(SARCH)/vmlinux.lds.S 
$(SRC_ARCH)/kernel/vmlinux.lds.S
        @touch $@
 
 # Create link to sub arch includes
-include/asm-$(ARCH)/.arch: $(wildcard include/config/arch/*.h)
-       @echo '  Making asm-$(ARCH)/arch -> asm-$(ARCH)/$(SARCH) symlink'
+$(srctree)/include/asm-$(ARCH)/.arch: $(wildcard include/config/arch/*.h)
+       @echo '  Making $(srctree)/include/asm-$(ARCH)/arch -> 
$(srctree)/include/asm-$(ARCH)/$(SARCH) symlink'
        @rm -f include/asm-$(ARCH)/arch
-       @ln -sf $(SARCH) include/asm-$(ARCH)/arch
+       @ln -sf $(srctree)/include/asm-$(ARCH)/$(SARCH) 
$(srctree)/include/asm-$(ARCH)/arch
        @touch $@
 
 arch/$(ARCH)/$(SARCH)/kernel/asm-offsets.s: include/asm 
include/linux/version.h \
diff -urN linux/arch/cris/defconfig linux/arch/cris/defconfig
--- linux/arch/cris/defconfig   2004/08/14 16:16:40     1.13
+++ linux/arch/cris/defconfig   2005/08/01 18:23:39     1.14
@@ -1,22 +1,27 @@
 #
 # Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11
+# Mon Jun 20 13:42:02 2005
 #
 CONFIG_MMU=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_CRIS=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
-CONFIG_SWAP=y
+CONFIG_LOCALVERSION=""
+# CONFIG_SWAP is not set
 # CONFIG_SYSVIPC is not set
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
@@ -24,16 +29,19 @@
 # CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 # CONFIG_KALLSYMS is not set
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
 
 #
 # Loadable module support
@@ -45,23 +53,28 @@
 #
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_SMP is not set
 CONFIG_ETRAX_CMDLINE="root=/dev/mtdblock3 init=/linuxrc"
-CONFIG_ETRAX_WATCHDOG=y
-CONFIG_ETRAX_WATCHDOG_NICE_DOGGY=y
+# CONFIG_ETRAX_WATCHDOG is not set
 CONFIG_ETRAX_FAST_TIMER=y
 # CONFIG_PREEMPT is not set
+# CONFIG_OOM_REBOOT is not set
 
 #
 # Hardware setup
 #
-CONFIG_ETRAX100LX=y
-# CONFIG_ETRAX100LX_V2 is not set
+# CONFIG_ETRAX100LX is not set
+CONFIG_ETRAX100LX_V2=y
 # CONFIG_SVINTO_SIM is not set
+# CONFIG_ETRAXFS is not set
+# CONFIG_ETRAXFS_SIM is not set
 CONFIG_ETRAX_ARCH_V10=y
-CONFIG_ETRAX_DRAM_SIZE=16
+# CONFIG_ETRAX_ARCH_V32 is not set
+CONFIG_ETRAX_DRAM_SIZE=32
 CONFIG_ETRAX_FLASH_BUSWIDTH=2
-CONFIG_CRIS_LOW_MAP=y
-CONFIG_ETRAX_DRAM_VIRTUAL_BASE=60000000
+CONFIG_ETRAX_FLASH1_SIZE=4
+CONFIG_ETRAX_DRAM_VIRTUAL_BASE=c0000000
 CONFIG_ETRAX_PA_LEDS=y
 # CONFIG_ETRAX_PB_LEDS is not set
 # CONFIG_ETRAX_CSP0_LEDS is not set
@@ -81,13 +94,13 @@
 # CONFIG_ETRAX_RESCUE_SER1 is not set
 # CONFIG_ETRAX_RESCUE_SER2 is not set
 # CONFIG_ETRAX_RESCUE_SER3 is not set
-CONFIG_ETRAX_DEF_R_WAITSTATES=0x95f8
-CONFIG_ETRAX_DEF_R_BUS_CONFIG=0x104
+CONFIG_ETRAX_DEF_R_WAITSTATES=0x95a6
+CONFIG_ETRAX_DEF_R_BUS_CONFIG=0x4
 CONFIG_ETRAX_SDRAM=y
-CONFIG_ETRAX_DEF_R_SDRAM_CONFIG=0x00e03636
+CONFIG_ETRAX_DEF_R_SDRAM_CONFIG=0x09e05757
 CONFIG_ETRAX_DEF_R_SDRAM_TIMING=0x80008002
 CONFIG_ETRAX_DEF_R_PORT_PA_DIR=0x1d
-CONFIG_ETRAX_DEF_R_PORT_PA_DATA=0xf0
+CONFIG_ETRAX_DEF_R_PORT_PA_DATA=0x00
 CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG=0x00
 CONFIG_ETRAX_DEF_R_PORT_PB_DIR=0x1e
 CONFIG_ETRAX_DEF_R_PORT_PB_DATA=0xf3
@@ -97,16 +110,17 @@
 # Drivers for built-in interfaces
 #
 CONFIG_ETRAX_ETHERNET=y
-CONFIG_NET_ETHERNET=y
 # CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK is not set
 CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY=y
 CONFIG_ETRAX_SERIAL=y
-CONFIG_ETRAX_SERIAL_FAST_TIMER=y
+# CONFIG_ETRAX_SERIAL_FAST_TIMER is not set
+# CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST is not set
+CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS=5
 CONFIG_ETRAX_SERIAL_PORT0=y
-# CONFIG_CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_OUT is not set
-CONFIG_CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT=y
-# CONFIG_CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_IN is not set
-CONFIG_CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN=y
+# CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_OUT is not set
+CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT=y
+# CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_IN is not set
+CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN=y
 CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_NONE=y
 # CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PA is not set
 # CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB is not set
@@ -121,10 +135,10 @@
 CONFIG_ETRAX_SER0_CD_ON_PB_BIT=-1
 # CONFIG_ETRAX_SERIAL_PORT1 is not set
 CONFIG_ETRAX_SERIAL_PORT2=y
-# CONFIG_CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_OUT is not set
-CONFIG_CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT=y
-# CONFIG_CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_IN is not set
-CONFIG_CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN=y
+# CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_OUT is not set
+CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT=y
+# CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_IN is not set
+CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN=y
 CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_NONE=y
 # CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA is not set
 # CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PB is not set
@@ -138,44 +152,51 @@
 CONFIG_ETRAX_SER2_DSR_ON_PB_BIT=-1
 CONFIG_ETRAX_SER2_CD_ON_PB_BIT=-1
 # CONFIG_ETRAX_SERIAL_PORT3 is not set
-# CONFIG_ETRAX_RS485 is not set
-# CONFIG_ETRAX_IDE is not set
-# CONFIG_IDE is not set
-# CONFIG_ETRAX_USB_HOST is not set
+CONFIG_ETRAX_RS485=y
+# CONFIG_ETRAX_RS485_ON_PA is not set
+# CONFIG_ETRAX_RS485_DISABLE_RECEIVER is not set
+CONFIG_ETRAX_IDE=y
+CONFIG_ETRAX_IDE_DELAY=15
+CONFIG_ETRAX_IDE_PB7_RESET=y
+# CONFIG_ETRAX_IDE_G27_RESET is not set
+CONFIG_ETRAX_USB_HOST=y
+CONFIG_ETRAX_USB_HOST_PORT1=y
+CONFIG_ETRAX_USB_HOST_PORT2=y
 CONFIG_ETRAX_AXISFLASHMAP=y
 CONFIG_ETRAX_PTABLE_SECTOR=65536
-CONFIG_MTD=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_OBSOLETE_CHIPS=y
-CONFIG_MTD_AMDSTD=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CONCAT=y
 # CONFIG_ETRAX_I2C is not set
-CONFIG_ETRAX_GPIO=y
-CONFIG_ETRAX_PA_BUTTON_BITMASK=0x02
-CONFIG_ETRAX_PA_CHANGEABLE_DIR=0x00
-CONFIG_ETRAX_PA_CHANGEABLE_BITS=0xFF
-CONFIG_ETRAX_PB_CHANGEABLE_DIR=0x00
-CONFIG_ETRAX_PB_CHANGEABLE_BITS=0xFF
-# CONFIG_ETRAX_RTC is not set
+# CONFIG_ETRAX_GPIO is not set
+CONFIG_ETRAX_RTC=y
+CONFIG_ETRAX_DS1302=y
+# CONFIG_ETRAX_PCF8563 is not set
+CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT=y
+CONFIG_ETRAX_DS1302_RSTBIT=0
+CONFIG_ETRAX_DS1302_SCLBIT=1
+CONFIG_ETRAX_DS1302_SDABIT=0
+CONFIG_ETRAX_DS1302_TRICKLE_CHARGE=0
 
 #
 # Generic Driver Options
 #
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
 
 #
 # Memory Technology Devices (MTD)
 #
+CONFIG_MTD=y
 # CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CONCAT=y
 # CONFIG_MTD_REDBOOT_PARTS is not set
 # CONFIG_MTD_CMDLINE_PARTS is not set
 
 #
 # User Modules And Translation Layers
 #
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
 # CONFIG_INFTL is not set
@@ -183,14 +204,30 @@
 #
 # RAM/ROM/Flash chip drivers
 #
+CONFIG_MTD_CFI=y
 # CONFIG_MTD_JEDECPROBE is not set
 CONFIG_MTD_GEN_PROBE=y
 # CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 # CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
 # CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 CONFIG_MTD_RAM=y
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
+CONFIG_MTD_OBSOLETE_CHIPS=y
+CONFIG_MTD_AMDSTD=y
 # CONFIG_MTD_SHARP is not set
 # CONFIG_MTD_JEDEC is not set
 
@@ -204,11 +241,13 @@
 # Self-contained MTD device drivers
 #
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 CONFIG_MTD_MTDRAM=y
 CONFIG_MTDRAM_TOTAL_SIZE=0
 CONFIG_MTDRAM_ERASE_SIZE=64
 CONFIG_MTDRAM_ABS_POS=0x0
 # CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
 
 #
 # Disk-On-Chip Device Drivers
@@ -235,11 +274,25 @@
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
 CONFIG_BLK_DEV_RAM_SIZE=4096
 # CONFIG_BLK_DEV_INITRD is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -249,6 +302,28 @@
 #
 # ATA/ATAPI/MFM/RLL support
 #
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_IDE_GENERIC is not set
+# CONFIG_IDE_ARM is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
 
 #
 # SCSI device support
@@ -258,7 +333,6 @@
 #
 # IEEE 1394 (FireWire) support
 #
-# CONFIG_IEEE1394 is not set
 
 #
 # I2O device support
@@ -288,6 +362,9 @@
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 is not set
 
 #
 # IP: Virtual Server Configuration
@@ -301,11 +378,10 @@
 # IP: Netfilter Configuration
 #
 # CONFIG_IP_NF_CONNTRACK is not set
+# CONFIG_IP_NF_CONNTRACK_MARK is not set
 # CONFIG_IP_NF_QUEUE is not set
 # CONFIG_IP_NF_IPTABLES is not set
 # CONFIG_IP_NF_ARPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
 
 #
 # SCTP Configuration (EXPERIMENTAL)
@@ -323,12 +399,12 @@
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
 # QoS and/or fair queueing
 #
 # CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
 
 #
 # Network testing
@@ -338,7 +414,26 @@
 # CONFIG_NET_POLL_CONTROLLER is not set
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
-# CONFIG_BT is not set
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+# CONFIG_BT_SCO is not set
+CONFIG_BT_RFCOMM=y
+# CONFIG_BT_RFCOMM_TTY is not set
+CONFIG_BT_BNEP=y
+# CONFIG_BT_BNEP_MC_FILTER is not set
+# CONFIG_BT_BNEP_PROTO_FILTER is not set
+# CONFIG_BT_HIDP is not set
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=y
+# CONFIG_BT_HCIUSB_SCO is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIVHCI is not set
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
@@ -348,6 +443,7 @@
 #
 # Ethernet (10 or 100Mbit)
 #
+CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
 
 #
@@ -389,11 +485,19 @@
 #
 # Input device support
 #
-# CONFIG_INPUT is not set
+CONFIG_INPUT=y
 
 #
 # Userland interfaces
 #
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
 
 #
 # Input I/O drivers
@@ -404,10 +508,25 @@
 # CONFIG_SERIO_I8042 is not set
 # CONFIG_SERIO_SERPORT is not set
 # CONFIG_SERIO_CT82C710 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
 
 #
 # Input Device Drivers
 #
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
 
 #
 # Character devices
@@ -426,7 +545,6 @@
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_QIC02_TAPE is not set
 
 #
 # IPMI
@@ -441,13 +559,10 @@
 # CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
 
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
 
@@ -469,10 +584,15 @@
 # CONFIG_JBD is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
 # CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 
@@ -485,7 +605,8 @@
 #
 # DOS/FAT/NT Filesystems
 #
-# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_NTFS_FS is not set
 
 #
@@ -497,6 +618,7 @@
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
@@ -512,7 +634,15 @@
 # CONFIG_EFS_FS is not set
 CONFIG_JFFS_FS=y
 CONFIG_JFFS_FS_VERBOSE=0
-# CONFIG_JFFS2_FS is not set
+# CONFIG_JFFS_PROC_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_FS_NOR_ECC is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
 CONFIG_CRAMFS=y
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -530,14 +660,13 @@
 # CONFIG_NFSD is not set
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
@@ -557,8 +686,120 @@
 # CONFIG_SOUND is not set
 
 #
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
 # USB support
 #
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+
+#
+# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; 
see USB_STORAGE Help for more information
+#
+# CONFIG_USB_STORAGE is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_RTL8150=y
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB ATM/DSL drivers
+#
 
 #
 # USB Gadget Support
@@ -568,14 +809,17 @@
 #
 # Kernel hacking
 #
-# CONFIG_PROFILE is not set
+# CONFIG_PROFILING is not set
+# CONFIG_SYSTEM_PROFILER is not set
 # CONFIG_ETRAX_KGDB is not set
 # CONFIG_DEBUG_INFO is not set
 # CONFIG_FRAME_POINTER is not set
+# CONFIG_DEBUG_NMI_OOPS is not set
 
 #
 # Security options
 #
+# CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
 
 #
@@ -584,8 +828,14 @@
 # CONFIG_CRYPTO is not set
 
 #
+# Hardware crypto devices
+#
+
+#
 # Library routines
 #
-# CONFIG_CRC32 is not set
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
 # CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff -urN linux/arch/cris/arch-v10/Kconfig linux/arch/cris/arch-v10/Kconfig
--- linux/arch/cris/arch-v10/Kconfig    2003/07/11 02:13:09     1.1
+++ linux/arch/cris/arch-v10/Kconfig    2005/08/01 18:23:39     1.2
@@ -260,6 +260,37 @@
 endchoice
 
 choice
+       prompt "Kernel GDB port"
+       depends on ETRAX_KGDB
+       default ETRAX_KGDB_PORT0
+       help
+         Choose a serial port for kernel debugging.  NOTE: This port should
+         not be enabled under Drivers for built-in interfaces (as it has its
+         own initialization code) and should not be the same as the debug port.
+
+config ETRAX_KGDB_PORT0
+       bool "Serial-0"
+       help
+         Use serial port 0 for kernel debugging.
+
+config ETRAX_KGDB_PORT1
+       bool "Serial-1"
+       help
+         Use serial port 1 for kernel debugging.
+
+config ETRAX_KGDB_PORT2
+       bool "Serial-2"
+       help
+         Use serial port 2 for kernel debugging.
+
+config ETRAX_KGDB_PORT3
+       bool "Serial-3"
+       help
+         Use serial port 3 for kernel debugging.
+
+endchoice
+
+choice
        prompt "Product rescue-port"
        depends on ETRAX_ARCH_V10
        default ETRAX_RESCUE_SER0
diff -urN linux/arch/cris/arch-v10/boot/Makefile 
linux/arch/cris/arch-v10/boot/Makefile
--- linux/arch/cris/arch-v10/boot/Makefile      2003/07/11 02:13:09     1.1
+++ linux/arch/cris/arch-v10/boot/Makefile      2005/08/01 18:23:39     1.2
@@ -1,12 +1,13 @@
 #
 # arch/cris/boot/Makefile
 #
+target = $(target_boot_dir)
+src    = $(src_boot_dir)
 
 zImage: compressed/vmlinuz
 
-compressed/vmlinuz: $(TOPDIR)/vmlinux
-       @$(MAKE) -C compressed vmlinuz
+compressed/vmlinuz:
+       @$(MAKE) -f $(src)/compressed/Makefile $(target_compressed_dir)/vmlinuz
 
 clean:
-       rm -f zImage tools/build compressed/vmlinux.out
-       @$(MAKE) -C compressed clean
+       @$(MAKE) -f $(src)/compressed/Makefile clean
diff -urN linux/arch/cris/arch-v10/boot/compressed/Makefile 
linux/arch/cris/arch-v10/boot/compressed/Makefile
--- linux/arch/cris/arch-v10/boot/compressed/Makefile   2003/07/11 02:13:09     
1.1
+++ linux/arch/cris/arch-v10/boot/compressed/Makefile   2005/08/01 18:23:39     
1.2
@@ -1,40 +1,45 @@
 #
-# linux/arch/etrax100/boot/compressed/Makefile
-#
-# create a compressed vmlinux image from the original vmlinux files and romfs
+# create a compressed vmlinuz image from the binary vmlinux.bin file
 #
+target = $(target_compressed_dir)
+src    = $(src_compressed_dir)
 
-CC = gcc-cris -melf -I $(TOPDIR)/include
+CC = gcc-cris -melf $(LINUXINCLUDE)
 CFLAGS = -O2
 LD = ld-cris
 OBJCOPY = objcopy-cris
 OBJCOPYFLAGS = -O binary --remove-section=.bss
-OBJECTS = head.o misc.o
+OBJECTS = $(target)/head.o $(target)/misc.o
 
 # files to compress
-SYSTEM = $(TOPDIR)/vmlinux.bin
+SYSTEM = $(objtree)/vmlinux.bin
 
-all: vmlinuz
+all: $(target_compressed_dir)/vmlinuz
 
-decompress.bin: $(OBJECTS)
-       $(LD) -T decompress.ld -o decompress.o $(OBJECTS)
-       $(OBJCOPY) $(OBJCOPYFLAGS) decompress.o decompress.bin
-# save it for mkprod in the topdir.
-       cp decompress.bin $(TOPDIR)
+$(target)/decompress.bin: $(OBJECTS)
+       $(LD) -T $(src)/decompress.ld -o $(target)/decompress.o $(OBJECTS)
+       $(OBJCOPY) $(OBJCOPYFLAGS) $(target)/decompress.o 
$(target)/decompress.bin
 
+# Create vmlinuz image in top-level build directory
+$(target_compressed_dir)/vmlinuz: $(target) piggy.img $(target)/decompress.bin
+       @echo "  COMPR   vmlinux.bin --> vmlinuz"
+       @cat $(target)/decompress.bin piggy.img > 
$(target_compressed_dir)/vmlinuz
+       @rm -f piggy.img
 
-vmlinuz: piggy.img decompress.bin
-       cat decompress.bin piggy.img > vmlinuz
-       rm -f piggy.img
+$(target)/head.o: $(src)/head.S
+       $(CC) -D__ASSEMBLY__ -traditional -c $< -o $@
 
-head.o: head.S
-       $(CC) -D__ASSEMBLY__ -traditional -c head.S -o head.o
+$(target)/misc.o: $(src)/misc.c
+       $(CC) -D__KERNEL__ -c $< -o $@
 
 # gzip the kernel image
 
 piggy.img: $(SYSTEM)
-       cat $(SYSTEM) | gzip -f -9 > piggy.img
+       @cat $(SYSTEM) | gzip -f -9 > piggy.img
+
+$(target):
+       mkdir -p $(target)
 
 clean:
-       rm -f piggy.img vmlinuz vmlinuz.o
+       rm -f piggy.img $(objtree)/vmlinuz
 
diff -urN linux/arch/cris/arch-v10/boot/compressed/head.S 
linux/arch/cris/arch-v10/boot/compressed/head.S
--- linux/arch/cris/arch-v10/boot/compressed/head.S     2003/07/11 02:13:09     
1.1
+++ linux/arch/cris/arch-v10/boot/compressed/head.S     2005/08/01 18:23:39     
1.2
@@ -13,7 +13,8 @@
 #include <asm/arch/sv_addr_ag.h>
 
 #define RAM_INIT_MAGIC 0x56902387
-       
+#define COMMAND_LINE_MAGIC 0x87109563
+
        ;; Exported symbols
        
        .globl  _input_data
@@ -88,6 +89,12 @@
        cmp.d   r2, r1
        bcs     1b
        nop
+
+       ;;  Save command line magic and address.
+       move.d  _cmd_line_magic, $r12
+       move.d  $r10, [$r12]
+       move.d  _cmd_line_addr, $r12
+       move.d  $r11, [$r12]
        
        ;; Do the decompression and save compressed size in _inptr
 
@@ -98,7 +105,13 @@
 
        move.d  [_input_data], r9       ; flash address of compressed kernel
        add.d   [_inptr], r9            ; size of compressed kernel
-        
+
+       ;; Restore command line magic and address.
+       move.d  _cmd_line_magic, $r10
+       move.d  [$r10], $r10
+       move.d  _cmd_line_addr, $r11
+       move.d  [$r11], $r11
+
        ;; Enter the decompressed kernel
        move.d  RAM_INIT_MAGIC, r8      ; Tell kernel that DRAM is initialized
        jump    0x40004000      ; kernel is linked to this address
@@ -107,5 +120,8 @@
 
 _input_data:
        .dword  0               ; used by the decompressor
-
+_cmd_line_magic:
+       .dword 0
+_cmd_line_addr:
+       .dword 0
 #include "../../lib/hw_settings.S"
diff -urN linux/arch/cris/arch-v10/boot/rescue/Makefile 
linux/arch/cris/arch-v10/boot/rescue/Makefile
--- linux/arch/cris/arch-v10/boot/rescue/Makefile       2003/07/11 02:13:09     
1.1
+++ linux/arch/cris/arch-v10/boot/rescue/Makefile       2005/08/01 18:23:39     
1.2
@@ -1,52 +1,53 @@
 #
 # Makefile for rescue code
 #
-ifndef TOPDIR
-TOPDIR = ../../../..
-endif
-CC = gcc-cris -mlinux -I $(TOPDIR)/include
+target = $(target_rescue_dir)
+src    = $(src_rescue_dir)
+
+CC = gcc-cris -mlinux $(LINUXINCLUDE)
 CFLAGS = -O2
 LD = gcc-cris -mlinux -nostdlib
 OBJCOPY = objcopy-cris
 OBJCOPYFLAGS = -O binary --remove-section=.bss
 
-all: rescue.bin testrescue.bin kimagerescue.bin
-
-rescue: rescue.bin
-       # do nothing
+all: $(target)/rescue.bin $(target)/testrescue.bin $(target)/kimagerescue.bin
 
-rescue.bin: head.o
-       $(LD) -T rescue.ld -o rescue.o head.o
-       $(OBJCOPY) $(OBJCOPYFLAGS) rescue.o rescue.bin
-       cp rescue.bin $(TOPDIR)
+$(target)/rescue.bin: $(target) $(target)/head.o
+       $(LD) -T $(src)/rescue.ld -o $(target)/rescue.o $(target)/head.o
+       $(OBJCOPY) $(OBJCOPYFLAGS) $(target)/rescue.o $(target)/rescue.bin
+# Place a copy in top-level build directory
+       cp -p $(target)/rescue.bin $(objtree)
 
-testrescue.bin: testrescue.o
-       $(OBJCOPY) $(OBJCOPYFLAGS) testrescue.o tr.bin
+$(target)/testrescue.bin: $(target) $(target)/testrescue.o
+       $(OBJCOPY) $(OBJCOPYFLAGS) $(target)/testrescue.o tr.bin
 # Pad it to 784 bytes
        dd if=/dev/zero of=tmp2423 bs=1 count=784
        cat tr.bin tmp2423 >testrescue_tmp.bin
-       dd if=testrescue_tmp.bin of=testrescue.bin bs=1 count=784
+       dd if=testrescue_tmp.bin of=$(target)/testrescue.bin bs=1 count=784
        rm tr.bin tmp2423 testrescue_tmp.bin
 
-kimagerescue.bin: kimagerescue.o
-       $(OBJCOPY) $(OBJCOPYFLAGS) kimagerescue.o ktr.bin
+$(target)/kimagerescue.bin: $(target) $(target)/kimagerescue.o
+       $(OBJCOPY) $(OBJCOPYFLAGS) $(target)/kimagerescue.o ktr.bin
 # Pad it to 784 bytes, that's what the rescue loader expects
        dd if=/dev/zero of=tmp2423 bs=1 count=784
        cat ktr.bin tmp2423 >kimagerescue_tmp.bin
-       dd if=kimagerescue_tmp.bin of=kimagerescue.bin bs=1 count=784
+       dd if=kimagerescue_tmp.bin of=$(target)/kimagerescue.bin bs=1 count=784
        rm ktr.bin tmp2423 kimagerescue_tmp.bin
 
-head.o: head.S
+$(target):
+       mkdir -p $(target)
+
+$(target)/head.o: $(src)/head.S
        $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
 
-testrescue.o: testrescue.S
+$(target)/testrescue.o: $(src)/testrescue.S
        $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
 
-kimagerescue.o: kimagerescue.S
+$(target)/kimagerescue.o: $(src)/kimagerescue.S
        $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
 
 clean:
-       rm -f *.o *.bin
+       rm -f $(target)/*.o $(target)/*.bin
 
 fastdep:
 
diff -urN linux/arch/cris/arch-v10/boot/rescue/head.S 
linux/arch/cris/arch-v10/boot/rescue/head.S
--- linux/arch/cris/arch-v10/boot/rescue/head.S 2003/07/11 02:13:09     1.1
+++ linux/arch/cris/arch-v10/boot/rescue/head.S 2005/08/01 18:23:39     1.2
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.6 2003/04/09 08:12:43 pkj Exp $
+/* $Id: head.S,v 1.7 2005/03/07 12:11:06 starvik Exp $
  * 
  * Rescue code, made to reside at the beginning of the
  * flash-memory. when it starts, it checks a partition
@@ -121,12 +121,13 @@
        ;; 0x80000000 if loaded in flash (as it should be)
        ;; since etrax actually starts at address 2 when booting from flash, we
        ;; put a nop (2 bytes) here first so we dont accidentally skip the di
-       
+
        nop     
        di
 
        jump    in_cache        ; enter cached area instead
-in_cache:      
+in_cache:
+
 
        ;; first put a jump test to give a possibility of upgrading the rescue 
code
        ;; without erasing/reflashing the sector. we put a longword of -1 here 
and if
@@ -325,9 +326,29 @@
        ;; result will be in r0
 checksum:
        moveq   0, $r0
-1:     addu.b  [$r1+], $r0
-       subq    1, $r2
-       bne     1b
+       moveq   CONFIG_ETRAX_FLASH1_SIZE, $r6
+
+       ;; If the first physical flash memory is exceeded wrap to the second 
one.
+       btstq   26, $r1         ; Are we addressing first flash?
+       bpl     1f
+       nop
+       clear.d $r6
+
+1:     test.d  $r6             ; 0 = no wrapping
+       beq     2f
+       nop
+       lslq    20, $r6         ; Convert MB to bytes
+       sub.d   $r1, $r6
+
+2:     addu.b  [$r1+], $r0
+       subq    1, $r6          ; Flash memory left
+       beq     3f
+       subq    1, $r2          ; Length left
+       bne     2b
        nop
        ret
        nop
+
+3:     move.d  MEM_CSE1_START, $r1 ; wrap to second flash
+       ba      2b
+       nop
diff -urN linux/arch/cris/arch-v10/drivers/Kconfig 
linux/arch/cris/arch-v10/drivers/Kconfig
--- linux/arch/cris/arch-v10/drivers/Kconfig    2005/01/25 04:27:54     1.4
+++ linux/arch/cris/arch-v10/drivers/Kconfig    2005/08/01 18:23:39     1.5
@@ -1,17 +1,11 @@
 config ETRAX_ETHERNET
        bool "Ethernet support"
        depends on ETRAX_ARCH_V10
+       select NET_ETHERNET
        help
          This option enables the ETRAX 100LX built-in 10/100Mbit Ethernet
          controller.
 
-# this is just so that the user does not have to go into the
-# normal ethernet driver section just to enable ethernetworking
-config NET_ETHERNET
-       bool
-       depends on ETRAX_ETHERNET
-       default y
-
 choice
        prompt "Network LED behavior"
        depends on ETRAX_ETHERNET
@@ -20,26 +14,26 @@
 config ETRAX_NETWORK_LED_ON_WHEN_LINK
        bool "LED_on_when_link"
        help
-         Selecting LED_on_when_link will light the LED when there is a 
-         connection and will flash off when there is activity. 
+         Selecting LED_on_when_link will light the LED when there is a
+         connection and will flash off when there is activity.
 
-         Selecting LED_on_when_activity will light the LED only when 
+         Selecting LED_on_when_activity will light the LED only when
          there is activity.
 
-         This setting will also affect the behaviour of other activity LEDs 
-         e.g. Bluetooth. 
+         This setting will also affect the behaviour of other activity LEDs
+         e.g. Bluetooth.
 
 config ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY
        bool "LED_on_when_activity"
        help
-         Selecting LED_on_when_link will light the LED when there is a 
-         connection and will flash off when there is activity. 
+         Selecting LED_on_when_link will light the LED when there is a
+         connection and will flash off when there is activity.
 
-         Selecting LED_on_when_activity will light the LED only when 
+         Selecting LED_on_when_activity will light the LED only when
          there is activity.
 
-         This setting will also affect the behaviour of other activity LEDs 
-         e.g. Bluetooth. 
+         This setting will also affect the behaviour of other activity LEDs
+         e.g. Bluetooth.
 
 endchoice
 
@@ -91,11 +85,11 @@
        depends on ETRAX_SERIAL_PORT0
        default ETRAX_SERIAL_PORT0_DMA6_OUT
 
-config CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_OUT
-       bool "No DMA out"
+config ETRAX_SERIAL_PORT0_NO_DMA_OUT
+       bool "No DMA out"
 
-config CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
-       bool "DMA 6"
+config ETRAX_SERIAL_PORT0_DMA6_OUT
+       bool "DMA 6"
 
 endchoice
 
@@ -104,11 +98,11 @@
        depends on ETRAX_SERIAL_PORT0
        default ETRAX_SERIAL_PORT0_DMA7_IN
 
-config CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_IN
-       bool "No DMA in"
+config ETRAX_SERIAL_PORT0_NO_DMA_IN
+       bool "No DMA in"
 
-config CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
-       bool "DMA 7"
+config ETRAX_SERIAL_PORT0_DMA7_IN
+       bool "DMA 7"
 
 endchoice
 
@@ -205,11 +199,11 @@
        depends on ETRAX_SERIAL_PORT1
        default ETRAX_SERIAL_PORT1_DMA8_OUT
 
-config CONFIG_ETRAX_SERIAL_PORT1_NO_DMA_OUT
-       bool "No DMA out"
+config ETRAX_SERIAL_PORT1_NO_DMA_OUT
+       bool "No DMA out"
 
-config CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT
-       bool "DMA 8"
+config ETRAX_SERIAL_PORT1_DMA8_OUT
+       bool "DMA 8"
 
 endchoice
 
@@ -218,11 +212,11 @@
        depends on ETRAX_SERIAL_PORT1
        default ETRAX_SERIAL_PORT1_DMA9_IN
 
-config CONFIG_ETRAX_SERIAL_PORT1_NO_DMA_IN
-       bool "No DMA in"
+config ETRAX_SERIAL_PORT1_NO_DMA_IN
+       bool "No DMA in"
 
-config CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN
-       bool "DMA 9"
+config ETRAX_SERIAL_PORT1_DMA9_IN
+       bool "DMA 9"
 
 endchoice
 
@@ -308,7 +302,7 @@
          Specify the pin of the PB port to carry the CD signal for serial
          port 1.
 
-comment "Make sure you dont have the same PB bits more than once!"
+comment "Make sure you do not have the same PB bits more than once!"
        depends on ETRAX_SERIAL && ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && 
ETRAX_SER1_DTR_RI_DSR_CD_ON_PB
 
 config ETRAX_SERIAL_PORT2
@@ -322,11 +316,11 @@
        depends on ETRAX_SERIAL_PORT2
        default ETRAX_SERIAL_PORT2_DMA2_OUT
 
-config CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_OUT
-       bool "No DMA out"
+config ETRAX_SERIAL_PORT2_NO_DMA_OUT
+       bool "No DMA out"
 
-config CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
-       bool "DMA 2"
+config ETRAX_SERIAL_PORT2_DMA2_OUT
+       bool "DMA 2"
 
 endchoice
 
@@ -335,11 +329,11 @@
        depends on ETRAX_SERIAL_PORT2
        default ETRAX_SERIAL_PORT2_DMA3_IN
 
-config CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_IN
-       bool "No DMA in"
+config ETRAX_SERIAL_PORT2_NO_DMA_IN
+       bool "No DMA in"
 
-config CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
-       bool "DMA 3"
+config ETRAX_SERIAL_PORT2_DMA3_IN
+       bool "DMA 3"
 
 endchoice
 
@@ -436,11 +430,11 @@
        depends on ETRAX_SERIAL_PORT3
        default ETRAX_SERIAL_PORT3_DMA4_OUT
 
-config CONFIG_ETRAX_SERIAL_PORT3_NO_DMA_OUT
-       bool "No DMA out"
+config ETRAX_SERIAL_PORT3_NO_DMA_OUT
+       bool "No DMA out"
 
-config CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT
-       bool "DMA 4"
+config ETRAX_SERIAL_PORT3_DMA4_OUT
+       bool "DMA 4"
 
 endchoice
 
@@ -449,11 +443,11 @@
        depends on ETRAX_SERIAL_PORT3
        default ETRAX_SERIAL_PORT3_DMA5_IN
 
-config CONFIG_ETRAX_SERIAL_PORT3_NO_DMA_IN
-       bool "No DMA in"
+config ETRAX_SERIAL_PORT3_NO_DMA_IN
+       bool "No DMA in"
 
-config CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN
-       bool "DMA 5"
+config ETRAX_SERIAL_PORT3_DMA5_IN
+       bool "DMA 5"
 
 endchoice
 
@@ -554,7 +548,6 @@
        select BLK_DEV_IDEDISK
        select BLK_DEV_IDECD
        select BLK_DEV_IDEDMA
-       select DMA_NONPCI
        help
          Enable this to get support for ATA/IDE.
          You can't use paralell ports or SCSI ports
@@ -579,7 +572,7 @@
          IDE reset on pin 7 on port B
 
 config ETRAX_IDE_G27_RESET
-        bool "Port_G_Bit_27"
+       bool "Port_G_Bit_27"
        help
          IDE reset on pin 27 on port G
 
@@ -588,30 +581,36 @@
 
 config ETRAX_USB_HOST
        bool "USB host"
+       select USB
        help
           This option enables the host functionality of the ETRAX 100LX
           built-in USB controller. In host mode the controller is designed
           for CTRL and BULK traffic only, INTR traffic may work as well
           however (depending on the requirements of timeliness).
 
-config USB
-       tristate
-       depends on ETRAX_USB_HOST
-       default y
-
 config ETRAX_USB_HOST_PORT1
-       bool "  USB port 1 enabled"
-       depends on ETRAX_USB_HOST
-       default n
+       bool "USB port 1 enabled"
+       depends on ETRAX_USB_HOST
+       default n
 
 config ETRAX_USB_HOST_PORT2
-       bool "  USB port 2 enabled"
-       depends on ETRAX_USB_HOST
-       default n
+       bool "USB port 2 enabled"
+       depends on ETRAX_USB_HOST
+       default n
 
 config ETRAX_AXISFLASHMAP
        bool "Axis flash-map support"
        depends on ETRAX_ARCH_V10
+       select MTD
+       select MTD_CFI
+       select MTD_CFI_AMDSTD
+       select MTD_OBSOLETE_CHIPS
+       select MTD_AMDSTD
+       select MTD_CHAR
+       select MTD_BLOCK
+       select MTD_PARTITIONS
+       select MTD_CONCAT
+       select MTD_COMPLEX_MAPPINGS
        help
          This option enables MTD mapping of flash devices.  Needed to use
          flash memories.  If unsure, say Y.
@@ -627,119 +626,6 @@
          for changing this is when the flash block size is bigger
          than 64kB (e.g. when using two parallel 16 bit flashes).
 
-# here we define the CONFIG_'s necessary to enable MTD support
-# for the flash
-config MTD
-       tristate
-       depends on ETRAX_AXISFLASHMAP
-       default y
-       help
-         Memory Technology Devices are flash, RAM and similar chips, often
-         used for solid state file systems on embedded devices. This option
-         will provide the generic support for MTD drivers to register
-         themselves with the kernel and for potential users of MTD devices
-         to enumerate the devices which are present and obtain a handle on
-         them. It will also allow you to select individual drivers for 
-         particular hardware and users of MTD devices. If unsure, say N.
-
-config MTD_CFI
-       tristate
-       depends on ETRAX_AXISFLASHMAP
-       default y
-       help
-         The Common Flash Interface specification was developed by Intel,
-         AMD and other flash manufactures that provides a universal method
-         for probing the capabilities of flash devices. If you wish to
-         support any device that is CFI-compliant, you need to enable this
-         option. Visit <http://www.amd.com/products/nvd/overview/cfi.html>
-         for more information on CFI.
-
-config MTD_CFI_AMDSTD
-       tristate
-       depends on ETRAX_AXISFLASHMAP
-       default y
-       help
-         The Common Flash Interface defines a number of different command
-         sets which a CFI-compliant chip may claim to implement. This code
-         provides support for one of those command sets, used on chips 
-         chips including the AMD Am29LV320.
-
-config MTD_OBSOLETE_CHIPS
-       bool
-       depends on ETRAX_AXISFLASHMAP
-       default y
-       help
-         This option does not enable any code directly, but will allow you to
-         select some other chip drivers which are now considered obsolete,
-         because the generic CONFIG_JEDEC_PROBE code above should now detect
-         the chips which are supported by these drivers, and allow the generic
-         CFI-compatible drivers to drive the chips. Say 'N' here unless you 
have
-         already tried the CONFIG_JEDEC_PROBE method and reported its failure
-         to the MTD mailing list at <linux-mtd@lists.infradead.org>
-
-config MTD_AMDSTD
-       tristate
-       depends on ETRAX_AXISFLASHMAP
-       default y
-       help
-         This option enables support for flash chips using AMD-compatible
-         commands, including some which are not CFI-compatible and hence 
-         cannot be used with the CONFIG_MTD_CFI_AMDSTD option.
-
-         It also works on AMD compatible chips that do conform to CFI.
-
-config MTD_CHAR
-       tristate
-       depends on ETRAX_AXISFLASHMAP
-       default y
-       help
-         This provides a character device for each MTD device present in
-         the system, allowing the user to read and write directly to the
-         memory chips, and also use ioctl() to obtain information about
-         the device, or to erase parts of it.
-
-config MTD_BLOCK
-       tristate
-       depends on ETRAX_AXISFLASHMAP
-       default y
-       ---help---
-         Although most flash chips have an erase size too large to be useful
-         as block devices, it is possible to use MTD devices which are based
-         on RAM chips in this manner. This block device is a user of MTD
-         devices performing that function.
-
-         At the moment, it is also required for the Journalling Flash File
-         System(s) to obtain a handle on the MTD device when it's mounted
-         (although JFFS and JFFS2 don't actually use any of the functionality
-         of the mtdblock device).
-
-         Later, it may be extended to perform read/erase/modify/write cycles
-         on flash chips to emulate a smaller block size. Needless to say,
-         this is very unsafe, but could be useful for file systems which are
-         almost never written to.
-
-         You do not need this option for use with the DiskOnChip devices. For
-         those, enable NFTL support (CONFIG_NFTL) instead.
-
-config MTD_PARTITIONS
-       tristate
-       depends on ETRAX_AXISFLASHMAP
-       default y
-       help
-         If you have a device which needs to divide its flash chip(s) up
-         into multiple 'partitions', each of which appears to the user as
-         a separate MTD device, you require this option to be enabled. If
-         unsure, say 'Y'.
-
-         Note, however, that you don't need this option for the DiskOnChip
-         devices. Partitioning on NFTL 'devices' is a different - that's the
-         'normal' form of partitioning used on a block device.
-
-config MTD_CONCAT
-       tristate
-       depends on ETRAX_AXISFLASHMAP
-       default y
-
 config ETRAX_I2C
        bool "I2C support"
        depends on ETRAX_ARCH_V10
@@ -752,7 +638,7 @@
          val = ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_READREG), i2c_arg);
 
 # this is true for most products since PB-I2C seems to be somewhat
-# flawed.. 
+# flawed..
 config ETRAX_I2C_USES_PB_NOT_PB_I2C
        bool "I2C uses PB not PB-I2C"
        depends on ETRAX_I2C
@@ -886,7 +772,7 @@
        bool "Real Time Clock support"
        depends on ETRAX_ARCH_V10
        help
-         Enables drivers for the Real-Time Clock battery-backed chips on 
+         Enables drivers for the Real-Time Clock battery-backed chips on
          some products. The kernel reads the time when booting, and
          the date can be set using ioctl(fd, RTC_SET_TIME, &rt) with rt a
          rtc_time struct (see <file:include/asm-cris/rtc.h>) on the /dev/rtc
@@ -903,13 +789,13 @@
        bool "DS1302"
        help
          Enables the driver for the DS1302 Real-Time Clock battery-backed
-         chip on some products. 
+         chip on some products.
 
 config ETRAX_PCF8563
        bool "PCF8563"
        help
          Enables the driver for the PCF8563 Real-Time Clock battery-backed
-         chip on some products.  
+         chip on some products.
 
 endchoice
 
@@ -954,10 +840,8 @@
        help
          This controls the initial value of the trickle charge register.
          0 = disabled (use this if you are unsure or have a non rechargable 
battery)
-         Otherwise the following values can be OR:ed together to control the 
+         Otherwise the following values can be OR:ed together to control the
          charge current:
          1 = 2kohm, 2 = 4kohm, 3 = 4kohm
          4 = 1 diode, 8 = 2 diodes
          Allowed values are (increasing current): 0, 11, 10, 9, 7, 6, 5
-
-
diff -urN linux/arch/cris/arch-v10/drivers/axisflashmap.c 
linux/arch/cris/arch-v10/drivers/axisflashmap.c
--- linux/arch/cris/arch-v10/drivers/axisflashmap.c     2004/11/15 11:49:15     
1.3
+++ linux/arch/cris/arch-v10/drivers/axisflashmap.c     2005/08/01 18:23:39     
1.4
@@ -11,6 +11,9 @@
  * partition split defined below.
  *
  * $Log: axisflashmap.c,v $
+ * Revision 1.11  2004/11/15 10:27:14  starvik
+ * Corrected typo (Thanks to Milton Miller <miltonm@bga.com>).
+ *
  * Revision 1.10  2004/08/16 12:37:22  starvik
  * Merge of Linux 2.6.8
  *
@@ -161,7 +164,7 @@
 #elif CONFIG_ETRAX_FLASH_BUSWIDTH==2
 #define flash_data __u16
 #elif CONFIG_ETRAX_FLASH_BUSWIDTH==4
-#define flash_data __u16
+#define flash_data __u32
 #endif
 
 /* From head.S */
diff -urN linux/arch/cris/arch-v10/drivers/ds1302.c 
linux/arch/cris/arch-v10/drivers/ds1302.c
--- linux/arch/cris/arch-v10/drivers/ds1302.c   2004/11/15 11:49:15     1.4
+++ linux/arch/cris/arch-v10/drivers/ds1302.c   2005/08/01 18:23:39     1.5
@@ -7,6 +7,15 @@
 *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init
 *!
 *! $Log: ds1302.c,v $
+*! Revision 1.18  2005/01/24 09:11:26  mikaelam
+*! Minor changes to get DS1302 RTC chip driver to work
+*!
+*! Revision 1.17  2005/01/05 06:11:22  starvik
+*! No need to do local_irq_disable after local_irq_save.
+*!
+*! Revision 1.16  2004/12/13 12:21:52  starvik
+*! Added I/O and DMA allocators from Linux 2.4
+*!
 *! Revision 1.14  2004/08/24 06:48:43  starvik
 *! Whitespace cleanup
 *!
@@ -124,9 +133,9 @@
 *!
 *! ---------------------------------------------------------------------------
 *!
-*! (C) Copyright 1999, 2000, 2001  Axis Communications AB, LUND, SWEDEN
+*! (C) Copyright 1999, 2000, 2001, 2002, 2003, 2004  Axis Communications AB, 
LUND, SWEDEN
 *!
-*! $Id: ds1302.c,v 1.14 2004/08/24 06:48:43 starvik Exp $
+*! $Id: ds1302.c,v 1.18 2005/01/24 09:11:26 mikaelam Exp $
 *!
 *!***************************************************************************/
 
@@ -145,6 +154,7 @@
 #include <asm/arch/svinto.h>
 #include <asm/io.h>
 #include <asm/rtc.h>
+#include <asm/arch/io_interface_mux.h>
 
 #define RTC_MAJOR_NR 121 /* local major, change later */
 
@@ -320,7 +330,6 @@
        unsigned long flags;
 
        local_irq_save(flags);
-       local_irq_disable();
 
        rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
        rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
@@ -358,7 +367,7 @@
 rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
          unsigned long arg) 
 {
-        unsigned long flags;
+       unsigned long flags;
 
        switch(cmd) {
                case RTC_RD_TIME:       /* read the time/date from RTC  */
@@ -382,7 +391,7 @@
                                return -EPERM;
 
                        if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, 
sizeof(struct rtc_time)))
-                               return -EFAULT;         
+                               return -EFAULT;
 
                        yrs = rtc_tm.tm_year + 1900;
                        mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
@@ -419,7 +428,6 @@
                        BIN_TO_BCD(yrs);
 
                        local_irq_save(flags);
-                       local_irq_disable();
                        CMOS_WRITE(yrs, RTC_YEAR);
                        CMOS_WRITE(mon, RTC_MONTH);
                        CMOS_WRITE(day, RTC_DAY_OF_MONTH);
@@ -438,7 +446,7 @@
 
                case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */
                {
-                       int tcs_val;                        
+                       int tcs_val;
 
                        if (!capable(CAP_SYS_TIME))
                                return -EPERM;
@@ -492,8 +500,8 @@
 /* The various file operations we support. */
 
 static struct file_operations rtc_fops = {
-        .owner          = THIS_MODULE,
-        .ioctl          = rtc_ioctl,   
+       .owner =        THIS_MODULE,
+       .ioctl =        rtc_ioctl,
 }; 
 
 /* Probe for the chip by writing something to its RAM and try reading it back. 
*/
@@ -532,7 +540,7 @@
                       "PB",
 #endif
                       CONFIG_ETRAX_DS1302_RSTBIT);
-                print_rtc_status();
+                      print_rtc_status();
                retval = 1;
        } else {
                stop();
@@ -548,7 +556,9 @@
 int __init
 ds1302_init(void) 
 {
+#ifdef CONFIG_ETRAX_I2C
        i2c_init();
+#endif
 
        if (!ds1302_probe()) {
 #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
@@ -558,25 +568,42 @@
                 *
                 * Make sure that R_GEN_CONFIG is setup correct.
                 */
-               genconfig_shadow = ((genconfig_shadow &
-                                    ~IO_MASK(R_GEN_CONFIG, ata)) | 
-                                  (IO_STATE(R_GEN_CONFIG, ata, select)));    
-               *R_GEN_CONFIG = genconfig_shadow;
+               /* Allocating the ATA interface will grab almost all
+                * pins in I/O groups a, b, c and d.  A consequence of
+                * allocating the ATA interface is that the fixed
+                * interfaces shared RAM, parallel port 0, parallel
+                * port 1, parallel port W, SCSI-8 port 0, SCSI-8 port
+                * 1, SCSI-W, serial port 2, serial port 3,
+                * synchronous serial port 3 and USB port 2 and almost
+                * all GPIO pins on port g cannot be used.
+                */
+               if (cris_request_io_interface(if_ata, "ds1302/ATA")) {
+                       printk(KERN_WARNING "ds1302: Failed to get IO 
interface\n");
+                       return -1;
+               }
+
 #elif CONFIG_ETRAX_DS1302_RSTBIT == 0
-               
-               /* Set the direction of this bit to out. */             
-               genconfig_shadow = ((genconfig_shadow &
-                                    ~IO_MASK(R_GEN_CONFIG, g0dir)) | 
-                                  (IO_STATE(R_GEN_CONFIG, g0dir, out)));    
-               *R_GEN_CONFIG = genconfig_shadow;
+               if (cris_io_interface_allocate_pins(if_gpio_grp_a,
+                                                   'g',
+                                                   CONFIG_ETRAX_DS1302_RSTBIT,
+                                                   
CONFIG_ETRAX_DS1302_RSTBIT)) {
+                       printk(KERN_WARNING "ds1302: Failed to get IO 
interface\n");
+                       return -1;
+               }
+
+               /* Set the direction of this bit to out. */
+               genconfig_shadow = ((genconfig_shadow &
+                                    ~IO_MASK(R_GEN_CONFIG, g0dir)) |
+                                  (IO_STATE(R_GEN_CONFIG, g0dir, out)));
+               *R_GEN_CONFIG = genconfig_shadow;
 #endif
                if (!ds1302_probe()) {
                        printk(KERN_WARNING "%s: RTC not found.\n", 
ds1302_name);
-                       return -1;
+                       return -1;
                }
 #else
                printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name);
-               return -1;
+               return -1;
 #endif
        }
        /* Initialise trickle charger */
diff -urN linux/arch/cris/arch-v10/drivers/eeprom.c 
linux/arch/cris/arch-v10/drivers/eeprom.c
--- linux/arch/cris/arch-v10/drivers/eeprom.c   2005/03/18 17:36:48     1.4
+++ linux/arch/cris/arch-v10/drivers/eeprom.c   2005/08/01 18:23:39     1.5
@@ -20,6 +20,12 @@
 *!                                  in the spin-lock.
 *!
 *!  $Log: eeprom.c,v $
+*!  Revision 1.12  2005/06/19 17:06:46  starvik
+*!  Merge of Linux 2.6.12.
+*!
+*!  Revision 1.11  2005/01/26 07:14:46  starvik
+*!  Applied diff from kernel janitors (Nish Aravamudan).
+*!
 *!  Revision 1.10  2003/09/11 07:29:48  starvik
 *!  Merge of Linux 2.6.0-test5
 *!
@@ -94,6 +100,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/wait.h>
 #include <asm/uaccess.h>
 #include "i2c.h"
 
@@ -526,15 +533,10 @@
     return -EFAULT;
   }
   
-  while(eeprom.busy)
-  {
-    interruptible_sleep_on(&eeprom.wait_q);
+  wait_event_interruptible(eeprom.wait_q, !eeprom.busy);
+  if (signal_pending(current))
+    return -EINTR;
 
-    /* bail out if we get interrupted */
-    if (signal_pending(current))
-      return -EINTR;
-    
-  }
   eeprom.busy++;
 
   page = (unsigned char) (p >> 8);
@@ -604,13 +606,10 @@
     return -EFAULT;
   }
 
-  while(eeprom.busy)
-  {
-    interruptible_sleep_on(&eeprom.wait_q);
-    /* bail out if we get interrupted */
-    if (signal_pending(current))
-      return -EINTR;
-  }
+  wait_event_interruptible(eeprom.wait_q, !eeprom.busy);
+  /* bail out if we get interrupted */
+  if (signal_pending(current))
+    return -EINTR;
   eeprom.busy++;
   for(i = 0; (i < EEPROM_RETRIES) && (restart > 0); i++)
   {
diff -urN linux/arch/cris/arch-v10/drivers/gpio.c 
linux/arch/cris/arch-v10/drivers/gpio.c
--- linux/arch/cris/arch-v10/drivers/gpio.c     2005/03/18 17:36:48     1.5
+++ linux/arch/cris/arch-v10/drivers/gpio.c     2005/08/01 18:23:40     1.6
@@ -1,4 +1,4 @@
-/* $Id: gpio.c,v 1.12 2004/08/24 07:19:59 starvik Exp $
+/* $Id: gpio.c,v 1.17 2005/06/19 17:06:46 starvik Exp $
  *
  * Etrax general port I/O device
  *
@@ -9,6 +9,18 @@
  *             Johan Adolfsson  (read/set directions, write, port G)
  *
  * $Log: gpio.c,v $
+ * Revision 1.17  2005/06/19 17:06:46  starvik
+ * Merge of Linux 2.6.12.
+ *
+ * Revision 1.16  2005/03/07 13:02:29  starvik
+ * Protect driver global states with spinlock
+ *
+ * Revision 1.15  2005/01/05 06:08:55  starvik
+ * No need to do local_irq_disable after local_irq_save.
+ *
+ * Revision 1.14  2004/12/13 12:21:52  starvik
+ * Added I/O and DMA allocators from Linux 2.4
+ *
  * Revision 1.12  2004/08/24 07:19:59  starvik
  * Whitespace cleanup
  *
@@ -142,6 +154,7 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/irq.h>
+#include <asm/arch/io_interface_mux.h>
 
 #define GPIO_MAJOR 120  /* experimental MAJOR number */
 
@@ -194,6 +207,8 @@
 static int gpio_some_alarms = 0; /* Set if someone uses alarm */
 static unsigned long gpio_pa_irq_enabled_mask = 0;
 
+static DEFINE_SPINLOCK(gpio_lock); /* Protect directions etc */
+
 /* Port A and B use 8 bit access, but Port G is 32 bit */
 #define NUM_PORTS (GPIO_MINOR_B+1)
 
@@ -241,6 +256,9 @@
        &port_pb_dir_shadow 
 };
 
+/* All bits in port g that can change dir. */
+static const unsigned long int changeable_dir_g_mask = 0x01FFFF01;
+
 /* Port G is 32 bit, handle it special, some bits are both inputs 
    and outputs at the same time, only some of the bits can change direction
    and some of them in groups of 8 bit. */
@@ -260,6 +278,7 @@
        unsigned int mask = 0;
        struct gpio_private *priv = (struct gpio_private *)file->private_data;
        unsigned long data;
+       spin_lock(&gpio_lock);
        poll_wait(file, &priv->alarm_wq, wait);
        if (priv->minor == GPIO_MINOR_A) {
                unsigned long flags;
@@ -270,10 +289,10 @@
                 */
                tmp = ~data & priv->highalarm & 0xFF;
                tmp = (tmp << R_IRQ_MASK1_SET__pa0__BITNR);
-               save_flags(flags); cli();
+               local_irq_save(flags);
                gpio_pa_irq_enabled_mask |= tmp;
                *R_IRQ_MASK1_SET = tmp;
-               restore_flags(flags);
+               local_irq_restore(flags);
 
        } else if (priv->minor == GPIO_MINOR_B)
                data = *R_PORT_PB_DATA;
@@ -286,8 +305,11 @@
            (~data & priv->lowalarm)) {
                mask = POLLIN|POLLRDNORM;
        }
+
+       spin_unlock(&gpio_lock);
        
        DP(printk("gpio_poll ready: mask 0x%08X\n", mask));
+
        return mask;
 }
 
@@ -296,6 +318,7 @@
        struct gpio_private *priv = alarmlist;
        unsigned long data = 0;
         int ret = 0;
+       spin_lock(&gpio_lock);
        while (priv) {
                if (USE_PORTS(priv)) {
                        data = *priv->port;
@@ -310,6 +333,7 @@
                }
                priv = priv->next;
        }
+       spin_unlock(&gpio_lock);
         return ret;
 }
 
@@ -327,6 +351,7 @@
 gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        unsigned long tmp;
+       spin_lock(&gpio_lock);
        /* Find what PA interrupts are active */
        tmp = (*R_IRQ_READ1);
 
@@ -337,6 +362,8 @@
        *R_IRQ_MASK1_CLR = tmp;
        gpio_pa_irq_enabled_mask &= ~tmp;
 
+       spin_unlock(&gpio_lock);
+
        if (gpio_some_alarms) {
                return IRQ_RETVAL(etrax_gpio_wake_up_check());
        }
@@ -350,6 +377,9 @@
        struct gpio_private *priv = (struct gpio_private *)file->private_data;
        unsigned char data, clk_mask, data_mask, write_msb;
        unsigned long flags;
+
+       spin_lock(&gpio_lock);
+
        ssize_t retval = count;
        if (priv->minor !=GPIO_MINOR_A && priv->minor != GPIO_MINOR_B) {
                return -EFAULT;
@@ -372,7 +402,7 @@
                data = *buf++;
                if (priv->write_msb) {
                        for (i = 7; i >= 0;i--) {
-                               local_irq_save(flags); local_irq_disable();
+                               local_irq_save(flags);
                                *priv->port = *priv->shadow &= ~clk_mask;
                                if (data & 1<<i)
                                        *priv->port = *priv->shadow |= 
data_mask;
@@ -384,7 +414,7 @@
                        }
                } else {
                        for (i = 0; i <= 7;i++) {
-                               local_irq_save(flags); local_irq_disable();
+                               local_irq_save(flags);
                                *priv->port = *priv->shadow &= ~clk_mask;
                                if (data & 1<<i)
                                        *priv->port = *priv->shadow |= 
data_mask;
@@ -396,6 +426,7 @@
                        }
                }
        }
+       spin_unlock(&gpio_lock);
        return retval;
 }
 
@@ -452,9 +483,14 @@
 static int
 gpio_release(struct inode *inode, struct file *filp)
 {
-       struct gpio_private *p = alarmlist;
-       struct gpio_private *todel = (struct gpio_private *)filp->private_data;
-       
+       struct gpio_private *p;
+       struct gpio_private *todel;
+
+       spin_lock(&gpio_lock);
+
+        p = alarmlist;
+        todel = (struct gpio_private *)filp->private_data;
+
        /* unlink from alarmlist and free the private structure */
 
        if (p == todel) {
@@ -476,7 +512,7 @@
                p = p->next;
        }
        gpio_some_alarms = 0;
-               
+       spin_unlock(&gpio_lock);
        return 0;
 }
 
@@ -491,14 +527,14 @@
         */
        unsigned long flags;
        if (USE_PORTS(priv)) {
-               local_irq_save(flags); local_irq_disable();
+               local_irq_save(flags);
                *priv->dir = *priv->dir_shadow &= 
                ~((unsigned char)arg & priv->changeable_dir);
                local_irq_restore(flags);
                return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */
        } else if (priv->minor == GPIO_MINOR_G) {
                /* We must fiddle with R_GEN_CONFIG to change dir */
-               save_flags(flags); cli();
+               local_irq_save(flags);
                if (((arg & dir_g_in_bits) != arg) && 
                    (arg & changeable_dir_g)) {
                        arg &= changeable_dir_g;
@@ -533,7 +569,7 @@
                        /* Must be a >120 ns delay before writing this again */
                                
                }
-               restore_flags(flags);
+               local_irq_restore(flags);
                return dir_g_in_bits;
        }
        return 0;
@@ -543,14 +579,14 @@
 {
        unsigned long flags;
        if (USE_PORTS(priv)) {
-               local_irq_save(flags); local_irq_disable();
+               local_irq_save(flags);
                *priv->dir = *priv->dir_shadow |= 
                  ((unsigned char)arg & priv->changeable_dir);
                local_irq_restore(flags);
                return *priv->dir_shadow;
        } else if (priv->minor == GPIO_MINOR_G) {
                /* We must fiddle with R_GEN_CONFIG to change dir */            
        
-               save_flags(flags); cli();
+               local_irq_save(flags);
                if (((arg & dir_g_out_bits) != arg) &&
                    (arg & changeable_dir_g)) {
                        /* Set bits in genconfig to set to output */
@@ -583,7 +619,7 @@
                        *R_GEN_CONFIG = genconfig_shadow;
                        /* Must be a >120 ns delay before writing this again */
                }
-               restore_flags(flags);
+               local_irq_restore(flags);
                return dir_g_out_bits & 0x7FFFFFFF;
        }
        return 0;
@@ -598,22 +634,26 @@
 {
        unsigned long flags;
        unsigned long val;
+        int ret = 0;
+
        struct gpio_private *priv = (struct gpio_private *)file->private_data;
        if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {
                return -EINVAL;
        }
 
+       spin_lock(&gpio_lock);
+
        switch (_IOC_NR(cmd)) {
        case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */
                // read the port
                if (USE_PORTS(priv)) {
-                       return *priv->port;
+                       ret =  *priv->port;
                } else if (priv->minor == GPIO_MINOR_G) {
-                       return (*R_PORT_G_DATA) & 0x7FFFFFFF;
+                       ret =  (*R_PORT_G_DATA) & 0x7FFFFFFF;
                }
                break;
        case IO_SETBITS:
-               local_irq_save(flags); local_irq_disable();
+               local_irq_save(flags);
                // set changeable bits with a 1 in arg
                if (USE_PORTS(priv)) {
                        *priv->port = *priv->shadow |= 
@@ -624,7 +664,7 @@
                local_irq_restore(flags);
                break;
        case IO_CLRBITS:
-               local_irq_save(flags); local_irq_disable();
+               local_irq_save(flags);
                // clear changeable bits with a 1 in arg
                if (USE_PORTS(priv)) {
                        *priv->port = *priv->shadow &= 
@@ -666,33 +706,34 @@
        case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */
                /* Read direction 0=input 1=output */
                if (USE_PORTS(priv)) {
-                       return *priv->dir_shadow;
+                       ret = *priv->dir_shadow;
                } else if (priv->minor == GPIO_MINOR_G) {
                        /* Note: Some bits are both in and out,
                         * Those that are dual is set here as well.
                         */
-                       return (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF;
+                       ret = (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF;
                }
+               break;
        case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */
                /* Set direction 0=unchanged 1=input, 
                 * return mask with 1=input 
                 */
-               return setget_input(priv, arg) & 0x7FFFFFFF;
+               ret = setget_input(priv, arg) & 0x7FFFFFFF;
                break;
        case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */
                /* Set direction 0=unchanged 1=output, 
                 * return mask with 1=output 
                 */
-               return setget_output(priv, arg) & 0x7FFFFFFF;
-
+               ret =  setget_output(priv, arg) & 0x7FFFFFFF;
+               break;
        case IO_SHUTDOWN:
                SOFT_SHUTDOWN();
                break;
        case IO_GET_PWR_BT:
 #if defined (CONFIG_ETRAX_SOFT_SHUTDOWN)
-               return (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT));
+               ret = (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT));
 #else
-               return 0;
+               ret = 0;
 #endif
                break;
        case IO_CFG_WRITE_MODE:
@@ -709,7 +750,7 @@
                {
                        priv->clk_mask = 0;
                        priv->data_mask = 0;
-                       return -EPERM;
+                       ret = -EPERM;
                }
                break;
        case IO_READ_INBITS: 
@@ -720,8 +761,7 @@
                        val = *R_PORT_G_DATA;
                }
                if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
-                       return -EFAULT;
-               return 0;
+                       ret = -EFAULT;
                break;
        case IO_READ_OUTBITS:
                 /* *arg is result of reading the output shadow */
@@ -731,36 +771,43 @@
                        val = port_g_data_shadow;
                }
                if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
-                       return -EFAULT;
+                       ret = -EFAULT;
                break;
        case IO_SETGET_INPUT: 
                /* bits set in *arg is set to input,
                 * *arg updated with current input pins.
                 */
                if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
-                       return -EFAULT;
+               {
+                       ret = -EFAULT;
+                       break;
+               }
                val = setget_input(priv, val);
                if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
-                       return -EFAULT;
+                       ret = -EFAULT;
                break;
        case IO_SETGET_OUTPUT:
                /* bits set in *arg is set to output,
                 * *arg updated with current output pins.
                 */
                if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
-                       return -EFAULT;
+               {
+                       ret = -EFAULT;
+                       break;
+               }
                val = setget_output(priv, val);
                if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
-                       return -EFAULT;
+                       ret = -EFAULT;
                break;
        default:
                if (priv->minor == GPIO_MINOR_LEDS)
-                       return gpio_leds_ioctl(cmd, arg);
+                       ret = gpio_leds_ioctl(cmd, arg);
                else
-                       return -EINVAL;
+                       ret = -EINVAL;
        } /* switch */
-       
-       return 0;
+
+       spin_unlock(&gpio_lock);
+       return ret;
 }
 
 static int
@@ -802,60 +849,20 @@
 };
 
 
-static void __init gpio_init_port_g(void)
-{
-#define GROUPA (0x0000FF3F)
-#define GROUPB (1<<6 | 1<<7)
-#define GROUPC (1<<30 | 1<<31)
-#define GROUPD (0x3FFF0000)
-#define GROUPD_LOW (0x00FF0000)
-       unsigned long used_in_bits = 0;
-       unsigned long used_out_bits = 0;
-       if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi0, select)){
-               used_in_bits  |= GROUPA | GROUPB | 0 | 0;
-               used_out_bits |= GROUPA | GROUPB | 0 | 0;
-       }
-       if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ata, select)) {
-               used_in_bits  |= GROUPA | GROUPB | GROUPC | (GROUPD & 
~(1<<25|1<<26));
-               used_out_bits |= GROUPA | GROUPB | GROUPC | GROUPD;
-       }
-
-       if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, par0, select)) {
-               used_in_bits  |= (GROUPA & ~(1<<0)) | 0 | 0 | 0;
-               used_out_bits |= (GROUPA & ~(1<<0)) | 0 | 0 | 0;
-       }
-       if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ser2, select)) {
-               used_in_bits  |= 0 | GROUPB | 0 | 0;
-               used_out_bits |= 0 | GROUPB | 0 | 0;
-       }
-       /* mio same as shared RAM ? */
-       if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, mio, select)) {
-               used_in_bits  |= (GROUPA & ~(1<<0)) | 0 |0 |GROUPD_LOW;
-               used_out_bits |= (GROUPA & ~(1<<0|1<<1|1<<2)) | 0 |0 
|GROUPD_LOW;
-       }
-       if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi1, select)) {
-               used_in_bits  |= 0 | 0 | GROUPC | GROUPD;
-               used_out_bits |= 0 | 0 | GROUPC | GROUPD;
-       }
-       if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi0w, select)) {
-               used_in_bits  |= GROUPA | GROUPB | 0 | (GROUPD_LOW | 1<<24);
-               used_out_bits |= GROUPA | GROUPB | 0 | (GROUPD_LOW | 1<<24 | 
1<<25|1<<26);
-       }
-
-       if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, par1, select)) {
-               used_in_bits  |= 0 | 0 | 0 | (GROUPD & ~(1<<24));
-               used_out_bits |= 0 | 0 | 0 | (GROUPD & ~(1<<24));
-       }
-       if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ser3, select)) {
-               used_in_bits  |= 0 | 0 | GROUPC | 0;
-               used_out_bits |= 0 | 0 | GROUPC | 0;
-       }
-       /* mio same as shared RAM-W? */
-       if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, mio_w, select)) {
-               used_in_bits  |= (GROUPA & ~(1<<0)) | 0 | 0 |GROUPD_LOW;
-               used_out_bits |= (GROUPA & ~(1<<0|1<<1|1<<2)) | 0 | 0 
|GROUPD_LOW;
-       }
-       /* TODO: USB p2, parw, sync ser3? */
+void ioif_watcher(const unsigned int gpio_in_available,
+                 const unsigned int gpio_out_available,
+                 const unsigned char pa_available,
+                 const unsigned char pb_available)
+{
+       unsigned long int flags;
+       D(printk("gpio.c: ioif_watcher called\n"));
+       D(printk("gpio.c: G in: 0x%08x G out: 0x%08x PA: 0x%02x PB: 0x%02x\n",
+                gpio_in_available, gpio_out_available, pa_available, 
pb_available));
+
+       spin_lock_irqsave(&gpio_lock, flags);
+
+       dir_g_in_bits = gpio_in_available;
+       dir_g_out_bits = gpio_out_available;
 
        /* Initialise the dir_g_shadow etc. depending on genconfig */
        /* 0=input 1=output */
@@ -868,10 +875,7 @@
        if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g24dir, out))
                dir_g_shadow |= (1 << 24);
 
-       dir_g_in_bits = ~used_in_bits;
-       dir_g_out_bits = ~used_out_bits;
-
-       changeable_dir_g = 0x01FFFF01; /* all that can change dir */
+       changeable_dir_g = changeable_dir_g_mask;
        changeable_dir_g &= dir_g_out_bits;
        changeable_dir_g &= dir_g_in_bits;
        /* Correct the bits that can change direction */ 
@@ -880,6 +884,7 @@
        dir_g_in_bits &= ~changeable_dir_g;
        dir_g_in_bits |= (~dir_g_shadow & changeable_dir_g);
 
+       spin_unlock_irqrestore(&gpio_lock, flags);
 
        printk(KERN_INFO "GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX val: 
%08lX\n",
               dir_g_in_bits, dir_g_out_bits, (unsigned long)*R_PORT_G_DATA);
@@ -896,6 +901,7 @@
 #if defined (CONFIG_ETRAX_CSP0_LEDS)
        int i;
 #endif
+        printk("gpio init\n");
 
        /* do the formalities */
 
@@ -919,8 +925,13 @@
 #endif
 
 #endif
-       gpio_init_port_g();
-       printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002 Axis 
Communications AB\n");
+       /* The I/O interface allocation watcher will be called when
+        * registering it. */
+       if (cris_io_interface_register_watcher(ioif_watcher)){
+               printk(KERN_WARNING "gpio_init: Failed to install IO if 
allocator watcher\n");
+       }
+
+       printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002, 2003, 
2004 Axis Communications AB\n");
        /* We call etrax_gpio_wake_up_check() from timer interrupt and
         * from cpu_idle() in kernel/process.c
         * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms
diff -urN linux/arch/cris/arch-v10/drivers/i2c.c 
linux/arch/cris/arch-v10/drivers/i2c.c
--- linux/arch/cris/arch-v10/drivers/i2c.c      2004/11/15 11:49:15     1.3
+++ linux/arch/cris/arch-v10/drivers/i2c.c      2005/08/01 18:23:40     1.4
@@ -12,6 +12,15 @@
 *!                                 don't use PB_I2C if DS1302 uses same bits,
 *!                                 use PB.
 *! $Log: i2c.c,v $
+*! Revision 1.13  2005/03/07 13:13:07  starvik
+*! Added spinlocks to protect states etc
+*!
+*! Revision 1.12  2005/01/05 06:11:22  starvik
+*! No need to do local_irq_disable after local_irq_save.
+*!
+*! Revision 1.11  2004/12/13 12:21:52  starvik
+*! Added I/O and DMA allocators from Linux 2.4
+*!
 *! Revision 1.9  2004/08/24 06:49:14  starvik
 *! Whitespace cleanup
 *!
@@ -75,7 +84,7 @@
 *! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN
 *!
 *!***************************************************************************/
-/* $Id: i2c.c,v 1.9 2004/08/24 06:49:14 starvik Exp $ */
+/* $Id: i2c.c,v 1.13 2005/03/07 13:13:07 starvik Exp $ */
 
 /****************** INCLUDE FILES SECTION ***********************************/
 
@@ -95,6 +104,7 @@
 #include <asm/arch/svinto.h>
 #include <asm/io.h>
 #include <asm/delay.h>
+#include <asm/arch/io_interface_mux.h>
 
 #include "i2c.h"
 
@@ -184,6 +194,7 @@
 
 #define i2c_delay(usecs) udelay(usecs)
 
+static DEFINE_SPINLOCK(i2c_lock); /* Protect directions etc */
 
 /****************** FUNCTION DEFINITION SECTION *************************/
 
@@ -488,13 +499,14 @@
        int error, cntr = 3;
        unsigned long flags;
 
+       spin_lock(&i2c_lock);
+
        do {
                error = 0;
                /*
                 * we don't like to be interrupted
                 */
                local_irq_save(flags);
-               local_irq_disable();
 
                i2c_start();
                /*
@@ -538,6 +550,8 @@
 
        i2c_delay(CLOCK_LOW_TIME);
 
+       spin_unlock(&i2c_lock);
+
        return -error;
 }
 
@@ -555,13 +569,14 @@
        int error, cntr = 3;
        unsigned long flags;
 
+       spin_lock(&i2c_lock);
+
        do {
                error = 0;
                /*
                 * we don't like to be interrupted
                 */
                local_irq_save(flags);
-               local_irq_disable();
                /*
                 * generate start condition
                 */
@@ -620,6 +635,8 @@
                
        } while(error && cntr--);
 
+       spin_unlock(&i2c_lock);
+
        return b;
 }
 
@@ -686,15 +703,26 @@
 int __init
 i2c_init(void)
 {
+       static int res = 0;
+       static int first = 1;
+
+       if (!first) {
+               return res;
+       }
+
        /* Setup and enable the Port B I2C interface */
 
 #ifndef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
+       if ((res = cris_request_io_interface(if_i2c, "I2C"))) {
+               printk(KERN_CRIT "i2c_init: Failed to get IO interface\n");
+               return res;
+       }
+
        *R_PORT_PB_I2C = port_pb_i2c_shadow |= 
                IO_STATE(R_PORT_PB_I2C, i2c_en,  on) |
                IO_FIELD(R_PORT_PB_I2C, i2c_d,   1)  |
                IO_FIELD(R_PORT_PB_I2C, i2c_clk, 1)  |
                IO_STATE(R_PORT_PB_I2C, i2c_oe_, enable);
-#endif
 
        port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir0);
        port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir1);
@@ -702,8 +730,26 @@
        *R_PORT_PB_DIR = (port_pb_dir_shadow |=
                          IO_STATE(R_PORT_PB_DIR, dir0, input)  |
                          IO_STATE(R_PORT_PB_DIR, dir1, output));
+#else
+        if ((res = cris_io_interface_allocate_pins(if_i2c,
+                                                  'b',
+                                                   CONFIG_ETRAX_I2C_DATA_PORT,
+                                                  
CONFIG_ETRAX_I2C_DATA_PORT))) {
+               printk(KERN_WARNING "i2c_init: Failed to get IO pin for I2C 
data port\n");
+               return res;
+       } else if ((res = cris_io_interface_allocate_pins(if_i2c,
+                                                         'b',
+                                                         
CONFIG_ETRAX_I2C_CLK_PORT,
+                                                         
CONFIG_ETRAX_I2C_CLK_PORT))) {
+               cris_io_interface_free_pins(if_i2c,
+                                           'b',
+                                           CONFIG_ETRAX_I2C_DATA_PORT,
+                                           CONFIG_ETRAX_I2C_DATA_PORT);
+               printk(KERN_WARNING "i2c_init: Failed to get IO pin for I2C clk 
port\n");
+       }
+#endif
 
-       return 0;
+       return res;
 }
 
 static int __init
@@ -711,14 +757,16 @@
 {
        int res;
 
-       i2c_init();
+       res = i2c_init();
+       if (res < 0)
+               return res;
        res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops);
        if(res < 0) {
                printk(KERN_ERR "i2c: couldn't get a major number.\n");
                return res;
        }
 
-       printk(KERN_INFO "I2C driver v2.2, (c) 1999-2001 Axis Communications 
AB\n");
+       printk(KERN_INFO "I2C driver v2.2, (c) 1999-2004 Axis Communications 
AB\n");
        
        return 0;
 }
diff -urN linux/arch/cris/arch-v10/drivers/pcf8563.c 
linux/arch/cris/arch-v10/drivers/pcf8563.c
--- linux/arch/cris/arch-v10/drivers/pcf8563.c  2004/11/15 11:49:15     1.7
+++ linux/arch/cris/arch-v10/drivers/pcf8563.c  2005/08/01 18:23:40     1.8
@@ -15,7 +15,7 @@
  *
  * Author: Tobias Anderberg <tobiasa@axis.com>.
  *
- * $Id: pcf8563.c,v 1.8 2004/08/24 06:42:51 starvik Exp $
+ * $Id: pcf8563.c,v 1.11 2005/03/07 13:13:07 starvik Exp $
  */
 
 #include <linux/config.h>
@@ -40,7 +40,7 @@
 #define PCF8563_MAJOR 121              /* Local major number. */
 #define DEVICE_NAME "rtc"              /* Name which is registered in 
/proc/devices. */
 #define PCF8563_NAME "PCF8563"
-#define DRIVER_VERSION "$Revision: 1.8 $"
+#define DRIVER_VERSION "$Revision: 1.11 $"
 
 /* I2C bus slave registers. */
 #define RTC_I2C_READ           0xa3
@@ -49,6 +49,8 @@
 /* Two simple wrapper macros, saves a few keystrokes. */
 #define rtc_read(x) i2c_readreg(RTC_I2C_READ, x)
 #define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y)
+
+static DEFINE_SPINLOCK(rtc_lock); /* Protect state etc */
        
 static const unsigned char days_in_month[] =
        { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
@@ -125,9 +127,12 @@
 int __init
 pcf8563_init(void)
 {
-       unsigned char ret;
+       int ret;
 
-       i2c_init();
+       if ((ret = i2c_init())) {
+               printk(KERN_CRIT "pcf8563_init: failed to init i2c\n");
+               return ret;
+       }
 
        /*
         * First of all we need to reset the chip. This is done by
@@ -200,12 +205,15 @@
                        {
                                struct rtc_time tm;
 
+                               spin_lock(&rtc_lock);
                                get_rtc_time(&tm);
 
                                if (copy_to_user((struct rtc_time *) arg, &tm, 
sizeof(struct rtc_time))) {
+                                       spin_unlock(&rtc_lock);
                                        return -EFAULT;
                                }
 
+                               spin_unlock(&rtc_lock);
                                return 0;
                        }
                        break;
@@ -250,6 +258,8 @@
                                BIN_TO_BCD(tm.tm_min);
                                BIN_TO_BCD(tm.tm_sec);
                                tm.tm_mon |= century;
+
+                               spin_lock(&rtc_lock);
                                
                                rtc_write(RTC_YEAR, tm.tm_year);
                                rtc_write(RTC_MONTH, tm.tm_mon);
@@ -258,6 +268,8 @@
                                rtc_write(RTC_MINUTES, tm.tm_min);
                                rtc_write(RTC_SECONDS, tm.tm_sec);
 
+                               spin_unlock(&rtc_lock);
+
                                return 0;
 #endif /* !CONFIG_ETRAX_RTC_READONLY */
                        }
diff -urN linux/arch/cris/arch-v10/kernel/dma.c 
linux/arch/cris/arch-v10/kernel/dma.c
--- linux/arch/cris/arch-v10/kernel/dma.c       1970/01/01 00:00:00
+++ linux/arch/cris/arch-v10/kernel/dma.c       2005-08-01 19:23:40.628913000 
+0100     1.1
@@ -0,0 +1,287 @@
+/* Wrapper for DMA channel allocator that updates DMA client muxing.
+ * Copyright 2004, Axis Communications AB
+ * $Id: dma.c,v 1.1 2004/12/13 12:21:51 starvik Exp $
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+
+#include <asm/dma.h>
+#include <asm/arch/svinto.h>
+
+/* Macro to access ETRAX 100 registers */
+#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | 
\
+                                         IO_STATE_(reg##_, field##_, _##val)
+
+
+static char used_dma_channels[MAX_DMA_CHANNELS];
+static const char * used_dma_channels_users[MAX_DMA_CHANNELS];
+
+int cris_request_dma(unsigned int dmanr, const char * device_id,
+                    unsigned options, enum dma_owner owner)
+{
+       unsigned long flags;
+       unsigned long int gens;
+       int fail = -EINVAL;
+
+       if ((dmanr < 0) || (dmanr >= MAX_DMA_CHANNELS)) {
+               printk(KERN_CRIT "cris_request_dma: invalid DMA channel %u\n", 
dmanr);
+               return -EINVAL;
+       }
+
+       local_irq_save(flags);
+       if (used_dma_channels[dmanr]) {
+               local_irq_restore(flags);
+               if (options & DMA_VERBOSE_ON_ERROR) {
+                       printk(KERN_CRIT "Failed to request DMA %i for %s, 
already allocated by %s\n", dmanr, device_id, used_dma_channels_users[dmanr]);
+               }
+               if (options & DMA_PANIC_ON_ERROR) {
+                       panic("request_dma error!");
+               }
+               return -EBUSY;
+       }
+
+       gens = genconfig_shadow;
+
+       switch(owner)
+       {
+       case dma_eth:
+               if ((dmanr != NETWORK_TX_DMA_NBR) &&
+                   (dmanr != NETWORK_RX_DMA_NBR)) {
+                       printk(KERN_CRIT "Invalid DMA channel for eth\n");
+                       goto bail;
+               }
+               break;
+       case dma_ser0:
+               if (dmanr == SER0_TX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma6, serial0);
+               } else if (dmanr == SER0_RX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma7, serial0);
+               } else {
+                       printk(KERN_CRIT "Invalid DMA channel for ser0\n");
+                       goto bail;
+               }
+               break;
+       case dma_ser1:
+               if (dmanr == SER1_TX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma8, serial1);
+               } else if (dmanr == SER1_RX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma9, serial1);
+               } else {
+                       printk(KERN_CRIT "Invalid DMA channel for ser1\n");
+                       goto bail;
+               }
+               break;
+       case dma_ser2:
+               if (dmanr == SER2_TX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma2, serial2);
+               } else if (dmanr == SER2_RX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma3, serial2);
+               } else {
+                       printk(KERN_CRIT "Invalid DMA channel for ser2\n");
+                       goto bail;
+               }
+               break;
+       case dma_ser3:
+               if (dmanr == SER3_TX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma4, serial3);
+               } else if (dmanr == SER3_RX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma5, serial3);
+               } else {
+                       printk(KERN_CRIT "Invalid DMA channel for ser3\n");
+                       goto bail;
+               }
+               break;
+       case dma_ata:
+               if (dmanr == ATA_TX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma2, ata);
+               } else if (dmanr == ATA_RX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma3, ata);
+               } else {
+                       printk(KERN_CRIT "Invalid DMA channel for ata\n");
+                       goto bail;
+               }
+               break;
+       case dma_ext0:
+               if (dmanr == EXTDMA0_TX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma4, extdma0);
+               } else if (dmanr == EXTDMA0_RX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma5, extdma0);
+               } else {
+                       printk(KERN_CRIT "Invalid DMA channel for ext0\n");
+                       goto bail;
+               }
+               break;
+       case dma_ext1:
+               if (dmanr == EXTDMA1_TX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma6, extdma1);
+               } else if (dmanr == EXTDMA1_RX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma7, extdma1);
+               } else {
+                       printk(KERN_CRIT "Invalid DMA channel for ext1\n");
+                       goto bail;
+               }
+               break;
+       case dma_int6:
+               if (dmanr == MEM2MEM_RX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma7, intdma6);
+               } else {
+                       printk(KERN_CRIT "Invalid DMA channel for int6\n");
+                       goto bail;
+               }
+               break;
+       case dma_int7:
+               if (dmanr == MEM2MEM_TX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma6, intdma7);
+               } else {
+                       printk(KERN_CRIT "Invalid DMA channel for int7\n");
+                       goto bail;
+               }
+               break;
+       case dma_usb:
+               if (dmanr == USB_TX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma8, usb);
+               } else if (dmanr == USB_RX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma9, usb);
+               } else {
+                       printk(KERN_CRIT "Invalid DMA channel for usb\n");
+                       goto bail;
+               }
+               break;
+       case dma_scsi0:
+               if (dmanr == SCSI0_TX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma2, scsi0);
+               } else if (dmanr == SCSI0_RX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma3, scsi0);
+               } else {
+                       printk(KERN_CRIT "Invalid DMA channel for scsi0\n");
+                       goto bail;
+               }
+               break;
+       case dma_scsi1:
+               if (dmanr == SCSI1_TX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma4, scsi1);
+               } else if (dmanr == SCSI1_RX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma5, scsi1);
+               } else {
+                       printk(KERN_CRIT "Invalid DMA channel for scsi1\n");
+                       goto bail;
+               }
+               break;
+       case dma_par0:
+               if (dmanr == PAR0_TX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma2, par0);
+               } else if (dmanr == PAR0_RX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma3, par0);
+               } else {
+                       printk(KERN_CRIT "Invalid DMA channel for par0\n");
+                       goto bail;
+               }
+               break;
+       case dma_par1:
+               if (dmanr == PAR1_TX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma4, par1);
+               } else if (dmanr == PAR1_RX_DMA_NBR) {
+                       SETS(gens, R_GEN_CONFIG, dma5, par1);
+               } else {
+                       printk(KERN_CRIT "Invalid DMA channel for par1\n");
+                       goto bail;
+               }
+               break;
+       default:
+               printk(KERN_CRIT "Invalid DMA owner.\n");
+               goto bail;
+       }
+
+       used_dma_channels[dmanr] = 1;
+       used_dma_channels_users[dmanr] = device_id;
+
+       {
+               volatile int i;
+               genconfig_shadow = gens;
+               *R_GEN_CONFIG = genconfig_shadow;
+               /* Wait 12 cycles before doing any DMA command */
+               for(i = 6; i > 0; i--)
+                       nop();
+       }
+       fail = 0;
+ bail:
+       local_irq_restore(flags);
+       return fail;
+}
+
+void cris_free_dma(unsigned int dmanr, const char * device_id)
+{
+       unsigned long flags;
+       if ((dmanr < 0) || (dmanr >= MAX_DMA_CHANNELS)) {
+               printk(KERN_CRIT "cris_free_dma: invalid DMA channel %u\n", 
dmanr);
+               return;
+       }
+
+       local_irq_save(flags);
+       if (!used_dma_channels[dmanr]) {
+               printk(KERN_CRIT "cris_free_dma: DMA channel %u not 
allocated\n", dmanr);
+       } else if (device_id != used_dma_channels_users[dmanr]) {
+               printk(KERN_CRIT "cris_free_dma: DMA channel %u not allocated 
by device\n", dmanr);
+       } else {
+               switch(dmanr)
+               {
+               case 0:
+                       *R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, reset);
+                       while (IO_EXTRACT(R_DMA_CH0_CMD, cmd, *R_DMA_CH0_CMD) ==
+                              IO_STATE_VALUE(R_DMA_CH0_CMD, cmd, reset));
+                       break;
+               case 1:
+                       *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, reset);
+                       while (IO_EXTRACT(R_DMA_CH1_CMD, cmd, *R_DMA_CH1_CMD) ==
+                              IO_STATE_VALUE(R_DMA_CH1_CMD, cmd, reset));
+                       break;
+               case 2:
+                       *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, reset);
+                       while (IO_EXTRACT(R_DMA_CH2_CMD, cmd, *R_DMA_CH2_CMD) ==
+                              IO_STATE_VALUE(R_DMA_CH2_CMD, cmd, reset));
+                       break;
+               case 3:
+                       *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, reset);
+                       while (IO_EXTRACT(R_DMA_CH3_CMD, cmd, *R_DMA_CH3_CMD) ==
+                              IO_STATE_VALUE(R_DMA_CH3_CMD, cmd, reset));
+                       break;
+               case 4:
+                       *R_DMA_CH4_CMD = IO_STATE(R_DMA_CH4_CMD, cmd, reset);
+                       while (IO_EXTRACT(R_DMA_CH4_CMD, cmd, *R_DMA_CH4_CMD) ==
+                              IO_STATE_VALUE(R_DMA_CH4_CMD, cmd, reset));
+                       break;
+               case 5:
+                       *R_DMA_CH5_CMD = IO_STATE(R_DMA_CH5_CMD, cmd, reset);
+                       while (IO_EXTRACT(R_DMA_CH5_CMD, cmd, *R_DMA_CH5_CMD) ==
+                              IO_STATE_VALUE(R_DMA_CH5_CMD, cmd, reset));
+                       break;
+               case 6:
+                       *R_DMA_CH6_CMD = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+                       while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *R_DMA_CH6_CMD) ==
+                              IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
+                       break;
+               case 7:
+                       *R_DMA_CH7_CMD = IO_STATE(R_DMA_CH7_CMD, cmd, reset);
+                       while (IO_EXTRACT(R_DMA_CH7_CMD, cmd, *R_DMA_CH7_CMD) ==
+                              IO_STATE_VALUE(R_DMA_CH7_CMD, cmd, reset));
+                       break;
+               case 8:
+                       *R_DMA_CH8_CMD = IO_STATE(R_DMA_CH8_CMD, cmd, reset);
+                       while (IO_EXTRACT(R_DMA_CH8_CMD, cmd, *R_DMA_CH8_CMD) ==
+                              IO_STATE_VALUE(R_DMA_CH8_CMD, cmd, reset));
+                       break;
+               case 9:
+                       *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, reset);
+                       while (IO_EXTRACT(R_DMA_CH9_CMD, cmd, *R_DMA_CH9_CMD) ==
+                              IO_STATE_VALUE(R_DMA_CH9_CMD, cmd, reset));
+                       break;
+               }
+               used_dma_channels[dmanr] = 0;
+       }
+       local_irq_restore(flags);
+}
+
+EXPORT_SYMBOL(cris_request_dma);
+EXPORT_SYMBOL(cris_free_dma);
diff -urN linux/arch/cris/arch-v10/kernel/io_interface_mux.c 
linux/arch/cris/arch-v10/kernel/io_interface_mux.c
--- linux/arch/cris/arch-v10/kernel/io_interface_mux.c  1970/01/01 00:00:00
+++ linux/arch/cris/arch-v10/kernel/io_interface_mux.c  2005-08-01 
19:23:40.653200000 +0100     1.1
@@ -0,0 +1,879 @@
+/* IO interface mux allocator for ETRAX100LX.
+ * Copyright 2004, Axis Communications AB
+ * $Id: io_interface_mux.c,v 1.2 2004/12/21 12:08:38 starvik Exp $
+ */
+
+
+/* C.f. ETRAX100LX Designer's Reference 20.9 */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <asm/arch/svinto.h>
+#include <asm/io.h>
+#include <asm/arch/io_interface_mux.h>
+
+
+#define DBG(s)
+
+/* Macro to access ETRAX 100 registers */
+#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | 
\
+                                         IO_STATE_(reg##_, field##_, _##val)
+
+enum io_if_group {
+       group_a = (1<<0),
+       group_b = (1<<1),
+       group_c = (1<<2),
+       group_d = (1<<3),
+       group_e = (1<<4),
+       group_f = (1<<5)
+};
+
+struct watcher
+{
+       void (*notify)(const unsigned int gpio_in_available,
+                      const unsigned int gpio_out_available,
+                      const unsigned char pa_available,
+                      const unsigned char pb_available);
+       struct watcher *next;
+};
+
+
+struct if_group
+{
+       enum io_if_group        group;
+       unsigned char           used;
+       enum cris_io_interface  owner;
+};
+
+
+struct interface
+{
+       enum cris_io_interface   ioif;
+       unsigned char            groups;
+       unsigned char            used;
+       char                    *owner;
+       unsigned int             gpio_g_in;
+       unsigned int             gpio_g_out;
+       unsigned char            gpio_b;
+};
+
+static struct if_group if_groups[6] = {
+       {
+               .group = group_a,
+               .used = 0,
+       },
+       {
+               .group = group_b,
+               .used = 0,
+       },
+       {
+               .group = group_c,
+               .used = 0,
+       },
+       {
+               .group = group_d,
+               .used = 0,
+       },
+       {
+               .group = group_e,
+               .used = 0,
+       },
+       {
+               .group = group_f,
+               .used = 0,
+       }
+};
+
+/* The order in the array must match the order of enum
+ * cris_io_interface in io_interface_mux.h */
+static struct interface interfaces[] = {
+       /* Begin Non-multiplexed interfaces */
+       {
+               .ioif = if_eth,
+               .groups = 0,
+               .gpio_g_in = 0,
+               .gpio_g_out = 0,
+               .gpio_b = 0
+       },
+       {
+               .ioif = if_serial_0,
+               .groups = 0,
+               .gpio_g_in = 0,
+               .gpio_g_out = 0,
+               .gpio_b = 0
+       },
+       /* End Non-multiplexed interfaces */
+       {
+               .ioif = if_serial_1,
+               .groups = group_e,
+               .gpio_g_in =  0x00000000,
+               .gpio_g_out = 0x00000000,
+               .gpio_b = 0x00
+       },
+       {
+               .ioif = if_serial_2,
+               .groups = group_b,
+               .gpio_g_in =  0x000000c0,
+               .gpio_g_out = 0x000000c0,
+               .gpio_b = 0x00
+       },
+       {
+               .ioif = if_serial_3,
+               .groups = group_c,
+               .gpio_g_in =  0xc0000000,
+               .gpio_g_out = 0xc0000000,
+               .gpio_b = 0x00
+       },
+       {
+               .ioif = if_sync_serial_1,
+               .groups = group_e | group_f, /* if_sync_serial_1 and 
if_sync_serial_3
+                                              can be used simultaneously */
+               .gpio_g_in =  0x00000000,
+               .gpio_g_out = 0x00000000,
+               .gpio_b = 0x10
+       },
+       {
+               .ioif = if_sync_serial_3,
+               .groups = group_c | group_f,
+               .gpio_g_in =  0xc0000000,
+               .gpio_g_out = 0xc0000000,
+               .gpio_b = 0x80
+       },
+       {
+               .ioif = if_shared_ram,
+               .groups = group_a,
+               .gpio_g_in =  0x0000ff3e,
+               .gpio_g_out = 0x0000ff38,
+               .gpio_b = 0x00
+       },
+       {
+               .ioif = if_shared_ram_w,
+               .groups = group_a | group_d,
+               .gpio_g_in =  0x00ffff3e,
+               .gpio_g_out = 0x00ffff38,
+               .gpio_b = 0x00
+       },
+       {
+               .ioif = if_par_0,
+               .groups = group_a,
+               .gpio_g_in =  0x0000ff3e,
+               .gpio_g_out = 0x0000ff3e,
+               .gpio_b = 0x00
+       },
+       {
+               .ioif = if_par_1,
+               .groups = group_d,
+               .gpio_g_in =  0x3eff0000,
+               .gpio_g_out = 0x3eff0000,
+               .gpio_b = 0x00
+       },
+       {
+               .ioif = if_par_w,
+               .groups = group_a | group_d,
+               .gpio_g_in =  0x00ffff3e,
+               .gpio_g_out = 0x00ffff3e,
+               .gpio_b = 0x00
+       },
+       {
+               .ioif = if_scsi8_0,
+               .groups = group_a | group_b | group_f, /* if_scsi8_0 and 
if_scsi8_1
+                                                         can be used 
simultaneously */
+               .gpio_g_in =  0x0000ffff,
+               .gpio_g_out = 0x0000ffff,
+               .gpio_b = 0x10
+       },
+       {
+               .ioif = if_scsi8_1,
+               .groups = group_c | group_d | group_f, /* if_scsi8_0 and 
if_scsi8_1
+                                                         can be used 
simultaneously */
+               .gpio_g_in =  0xffff0000,
+               .gpio_g_out = 0xffff0000,
+               .gpio_b = 0x80
+       },
+       {
+               .ioif = if_scsi_w,
+               .groups = group_a | group_b | group_d | group_f,
+               .gpio_g_in =  0x01ffffff,
+               .gpio_g_out = 0x07ffffff,
+               .gpio_b = 0x80
+       },
+       {
+               .ioif = if_ata,
+               .groups = group_a | group_b | group_c | group_d,
+               .gpio_g_in =  0xf9ffffff,
+               .gpio_g_out = 0xffffffff,
+               .gpio_b = 0x80
+       },
+       {
+               .ioif = if_csp,
+               .groups = group_f, /* if_csp and if_i2c can be used 
simultaneously */
+               .gpio_g_in =  0x00000000,
+               .gpio_g_out = 0x00000000,
+               .gpio_b = 0xfc
+       },
+       {
+               .ioif = if_i2c,
+               .groups = group_f, /* if_csp and if_i2c can be used 
simultaneously */
+               .gpio_g_in =  0x00000000,
+               .gpio_g_out = 0x00000000,
+               .gpio_b = 0x03
+       },
+       {
+               .ioif = if_usb_1,
+               .groups = group_e | group_f,
+               .gpio_g_in =  0x00000000,
+               .gpio_g_out = 0x00000000,
+               .gpio_b = 0x2c
+       },
+       {
+               .ioif = if_usb_2,
+               .groups = group_d,
+               .gpio_g_in =  0x0e000000,
+               .gpio_g_out = 0x3c000000,
+               .gpio_b = 0x00
+       },
+       /* GPIO pins */
+       {
+               .ioif = if_gpio_grp_a,
+               .groups = group_a,
+               .gpio_g_in =  0x0000ff3f,
+               .gpio_g_out = 0x0000ff3f,
+               .gpio_b = 0x00
+       },
+       {
+               .ioif = if_gpio_grp_b,
+               .groups = group_b,
+               .gpio_g_in =  0x000000c0,
+               .gpio_g_out = 0x000000c0,
+               .gpio_b = 0x00
+       },
+       {
+               .ioif = if_gpio_grp_c,
+               .groups = group_c,
+               .gpio_g_in =  0xc0000000,
+               .gpio_g_out = 0xc0000000,
+               .gpio_b = 0x00
+       },
+       {
+               .ioif = if_gpio_grp_d,
+               .groups = group_d,
+               .gpio_g_in =  0x3fff0000,
+               .gpio_g_out = 0x3fff0000,
+               .gpio_b = 0x00
+       },
+       {
+               .ioif = if_gpio_grp_e,
+               .groups = group_e,
+               .gpio_g_in =  0x00000000,
+               .gpio_g_out = 0x00000000,
+               .gpio_b = 0x00
+       },
+       {
+               .ioif = if_gpio_grp_f,
+               .groups = group_f,
+               .gpio_g_in =  0x00000000,
+               .gpio_g_out = 0x00000000,
+               .gpio_b = 0xff
+       }
+       /* Array end */
+};
+
+static struct watcher *watchers = NULL;
+
+static unsigned int gpio_in_pins =  0xffffffff;
+static unsigned int gpio_out_pins = 0xffffffff;
+static unsigned char gpio_pb_pins = 0xff;
+static unsigned char gpio_pa_pins = 0xff;
+
+static enum cris_io_interface gpio_pa_owners[8];
+static enum cris_io_interface gpio_pb_owners[8];
+static enum cris_io_interface gpio_pg_owners[32];
+
+static int cris_io_interface_init(void);
+
+static unsigned char clear_group_from_set(const unsigned char groups, struct 
if_group *group)
+{
+       return (groups & ~group->group);
+}
+
+
+static struct if_group *get_group(const unsigned char groups)
+{
+       int i;
+       for (i = 0; i < sizeof(if_groups)/sizeof(struct if_group); i++) {
+               if (groups & if_groups[i].group) {
+                       return &if_groups[i];
+               }
+       }
+       return NULL;
+}
+
+
+static void notify_watchers(void)
+{
+       struct watcher *w = watchers;
+
+       DBG(printk("io_interface_mux: notifying watchers\n"));
+
+       while (NULL != w) {
+               w->notify((const unsigned int)gpio_in_pins,
+                         (const unsigned int)gpio_out_pins,
+                         (const unsigned char)gpio_pa_pins,
+                         (const unsigned char)gpio_pb_pins);
+               w = w->next;
+       }
+}
+
+
+int cris_request_io_interface(enum cris_io_interface ioif, const char 
*device_id)
+{
+       int set_gen_config = 0;
+       int set_gen_config_ii = 0;
+       unsigned long int gens;
+       unsigned long int gens_ii;
+       struct if_group *grp;
+       unsigned char group_set;
+       unsigned long flags;
+
+       (void)cris_io_interface_init();
+
+       DBG(printk("cris_request_io_interface(%d, \"%s\")\n", ioif, device_id));
+
+       if ((ioif >= if_max_interfaces) || (ioif < 0)) {
+               printk(KERN_CRIT "cris_request_io_interface: Bad interface %u 
submitted for %s\n",
+                      ioif,
+                      device_id);
+               return -EINVAL;
+       }
+
+       local_irq_save(flags);
+
+       if (interfaces[ioif].used) {
+               local_irq_restore(flags);
+               printk(KERN_CRIT "cris_io_interface: Cannot allocate interface 
for %s, in use by %s\n",
+                      device_id,
+                      interfaces[ioif].owner);
+               return -EBUSY;
+       }
+
+       /* Check that all required groups are free before allocating, */
+       group_set = interfaces[ioif].groups;
+       while (NULL != (grp = get_group(group_set))) {
+               if (grp->used) {
+                       if (grp->group == group_f) {
+                               if ((if_sync_serial_1 ==  ioif) ||
+                                   (if_sync_serial_3 ==  ioif)) {
+                                       if ((grp->owner != if_sync_serial_1) &&
+                                           (grp->owner != if_sync_serial_3)) {
+                                               local_irq_restore(flags);
+                                               return -EBUSY;
+                                       }
+                               } else if ((if_scsi8_0 == ioif) ||
+                                          (if_scsi8_1 == ioif)) {
+                                       if ((grp->owner != if_scsi8_0) &&
+                                           (grp->owner != if_scsi8_1)) {
+                                               local_irq_restore(flags);
+                                               return -EBUSY;
+                                       }
+                               }
+                       } else {
+                               local_irq_restore(flags);
+                               return -EBUSY;
+                       }
+               }
+               group_set = clear_group_from_set(group_set, grp);
+       }
+
+       /* Are the required GPIO pins available too? */
+       if (((interfaces[ioif].gpio_g_in & gpio_in_pins) != 
interfaces[ioif].gpio_g_in) ||
+           ((interfaces[ioif].gpio_g_out & gpio_out_pins) != 
interfaces[ioif].gpio_g_out) ||
+           ((interfaces[ioif].gpio_b & gpio_pb_pins) != 
interfaces[ioif].gpio_b)) {
+               printk(KERN_CRIT "cris_request_io_interface: Could not get 
required pins for interface %u\n",
+                      ioif);
+               return -EBUSY;
+       }
+
+       /* All needed I/O pins and pin groups are free, allocate. */
+       group_set = interfaces[ioif].groups;
+       while (NULL != (grp = get_group(group_set))) {
+               grp->used = 1;
+               grp->owner = ioif;
+               group_set = clear_group_from_set(group_set, grp);
+       }
+
+       gens = genconfig_shadow;
+       gens_ii = gen_config_ii_shadow;
+
+       set_gen_config = 1;
+       switch (ioif)
+       {
+       /* Begin Non-multiplexed interfaces */
+       case if_eth:
+               /* fall through */
+       case if_serial_0:
+               set_gen_config = 0;
+               break;
+       /* End Non-multiplexed interfaces */
+       case if_serial_1:
+               set_gen_config_ii = 1;
+               SETS(gens_ii, R_GEN_CONFIG_II, sermode1, async);
+               break;
+       case if_serial_2:
+               SETS(gens, R_GEN_CONFIG, ser2, select);
+               break;
+       case if_serial_3:
+               SETS(gens, R_GEN_CONFIG, ser3, select);
+               set_gen_config_ii = 1;
+               SETS(gens_ii, R_GEN_CONFIG_II, sermode3, async);
+               break;
+       case if_sync_serial_1:
+               set_gen_config_ii = 1;
+               SETS(gens_ii, R_GEN_CONFIG_II, sermode1, sync);
+               break;
+       case if_sync_serial_3:
+               SETS(gens, R_GEN_CONFIG, ser3, select);
+               set_gen_config_ii = 1;
+               SETS(gens_ii, R_GEN_CONFIG_II, sermode3, sync);
+               break;
+       case if_shared_ram:
+               SETS(gens, R_GEN_CONFIG, mio, select);
+               break;
+       case if_shared_ram_w:
+               SETS(gens, R_GEN_CONFIG, mio_w, select);
+               break;
+       case if_par_0:
+               SETS(gens, R_GEN_CONFIG, par0, select);
+               break;
+       case if_par_1:
+               SETS(gens, R_GEN_CONFIG, par1, select);
+               break;
+       case if_par_w:
+               SETS(gens, R_GEN_CONFIG, par0, select);
+               SETS(gens, R_GEN_CONFIG, par_w, select);
+               break;
+       case if_scsi8_0:
+               SETS(gens, R_GEN_CONFIG, scsi0, select);
+               break;
+       case if_scsi8_1:
+               SETS(gens, R_GEN_CONFIG, scsi1, select);
+               break;
+       case if_scsi_w:
+               SETS(gens, R_GEN_CONFIG, scsi0, select);
+               SETS(gens, R_GEN_CONFIG, scsi0w, select);
+               break;
+       case if_ata:
+               SETS(gens, R_GEN_CONFIG, ata, select);
+               break;
+       case if_csp:
+               /* fall through */
+       case if_i2c:
+               set_gen_config = 0;
+               break;
+       case if_usb_1:
+               SETS(gens, R_GEN_CONFIG, usb1, select);
+               break;
+       case if_usb_2:
+               SETS(gens, R_GEN_CONFIG, usb2, select);
+               break;
+       case if_gpio_grp_a:
+               /* GPIO groups are only accounted, don't do configuration 
changes. */
+               /* fall through */
+       case if_gpio_grp_b:
+               /* fall through */
+       case if_gpio_grp_c:
+               /* fall through */
+       case if_gpio_grp_d:
+               /* fall through */
+       case if_gpio_grp_e:
+               /* fall through */
+       case if_gpio_grp_f:
+               set_gen_config = 0;
+               break;
+       default:
+               panic("cris_request_io_interface: Bad interface %u submitted 
for %s\n",
+                     ioif,
+                     device_id);
+       }
+
+       interfaces[ioif].used = 1;
+       interfaces[ioif].owner = (char*)device_id;
+
+       if (set_gen_config) {
+               volatile int i;
+               genconfig_shadow = gens;
+               *R_GEN_CONFIG = genconfig_shadow;
+               /* Wait 12 cycles before doing any DMA command */
+               for(i = 6; i > 0; i--)
+                       nop();
+       }
+       if (set_gen_config_ii) {
+               gen_config_ii_shadow = gens_ii;
+               *R_GEN_CONFIG_II = gen_config_ii_shadow;
+       }
+
+       DBG(printk("GPIO pins: available before: g_in=0x%08x g_out=0x%08x 
pb=0x%02x\n",
+                  gpio_in_pins, gpio_out_pins, gpio_pb_pins));
+       DBG(printk("grabbing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
+                  interfaces[ioif].gpio_g_in,
+                  interfaces[ioif].gpio_g_out,
+                  interfaces[ioif].gpio_b));
+
+       gpio_in_pins &= ~interfaces[ioif].gpio_g_in;
+       gpio_out_pins &= ~interfaces[ioif].gpio_g_out;
+       gpio_pb_pins &= ~interfaces[ioif].gpio_b;
+
+       DBG(printk("GPIO pins: available after: g_in=0x%08x g_out=0x%08x 
pb=0x%02x\n",
+                  gpio_in_pins, gpio_out_pins, gpio_pb_pins));
+
+       local_irq_restore(flags);
+
+       notify_watchers();
+
+       return 0;
+}
+
+
+void cris_free_io_interface(enum cris_io_interface ioif)
+{
+       struct if_group *grp;
+       unsigned char group_set;
+       unsigned long flags;
+
+       (void)cris_io_interface_init();
+
+       if ((ioif >= if_max_interfaces) || (ioif < 0)) {
+               printk(KERN_CRIT "cris_free_io_interface: Bad interface %u\n",
+                      ioif);
+               return;
+       }
+       local_irq_save(flags);
+       if (!interfaces[ioif].used) {
+               printk(KERN_CRIT "cris_free_io_interface: Freeing free 
interface %u\n",
+                      ioif);
+               local_irq_restore(flags);
+               return;
+       }
+       group_set = interfaces[ioif].groups;
+       while (NULL != (grp = get_group(group_set))) {
+               if (grp->group == group_f) {
+                       switch (ioif)
+                       {
+                       case if_sync_serial_1:
+                               if ((grp->owner == if_sync_serial_1) &&
+                                   interfaces[if_sync_serial_3].used) {
+                                       grp->owner = if_sync_serial_3;
+                               } else
+                                       grp->used = 0;
+                               break;
+                       case if_sync_serial_3:
+                               if ((grp->owner == if_sync_serial_3) &&
+                                   interfaces[if_sync_serial_1].used) {
+                                       grp->owner = if_sync_serial_1;
+                               } else
+                                       grp->used = 0;
+                               break;
+                       case if_scsi8_0:
+                               if ((grp->owner == if_scsi8_0) &&
+                                   interfaces[if_scsi8_1].used) {
+                                       grp->owner = if_scsi8_1;
+                               } else
+                                       grp->used = 0;
+                               break;
+                       case if_scsi8_1:
+                               if ((grp->owner == if_scsi8_1) &&
+                                   interfaces[if_scsi8_0].used) {
+                                       grp->owner = if_scsi8_0;
+                               } else
+                                       grp->used = 0;
+                               break;
+                       default:
+                               grp->used = 0;
+                       }
+               } else {
+                       grp->used = 0;
+               }
+               group_set = clear_group_from_set(group_set, grp);
+       }
+       interfaces[ioif].used = 0;
+       interfaces[ioif].owner = NULL;
+
+       DBG(printk("GPIO pins: available before: g_in=0x%08x g_out=0x%08x 
pb=0x%02x\n",
+                  gpio_in_pins, gpio_out_pins, gpio_pb_pins));
+       DBG(printk("freeing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
+                  interfaces[ioif].gpio_g_in,
+                  interfaces[ioif].gpio_g_out,
+                  interfaces[ioif].gpio_b));
+
+       gpio_in_pins |= interfaces[ioif].gpio_g_in;
+       gpio_out_pins |= interfaces[ioif].gpio_g_out;
+       gpio_pb_pins |= interfaces[ioif].gpio_b;
+
+       DBG(printk("GPIO pins: available after: g_in=0x%08x g_out=0x%08x 
pb=0x%02x\n",
+                  gpio_in_pins, gpio_out_pins, gpio_pb_pins));
+
+       local_irq_restore(flags);
+
+       notify_watchers();
+}
+
+/* Create a bitmask from bit 0 (inclusive) to bit stop_bit
+   (non-inclusive).  stop_bit == 0 returns 0x0 */
+static inline unsigned int create_mask(const unsigned stop_bit)
+{
+       /* Avoid overflow */
+       if (stop_bit >= 32) {
+               return 0xffffffff;
+       }
+       return (1<<stop_bit)-1;
+}
+
+
+/* port can be 'a', 'b' or 'g' */
+int cris_io_interface_allocate_pins(const enum cris_io_interface ioif,
+                                   const char port,
+                                   const unsigned start_bit,
+                                   const unsigned stop_bit)
+{
+       unsigned int i;
+       unsigned int mask = 0;
+       unsigned int tmp_mask;
+       unsigned long int flags;
+       enum cris_io_interface *owners;
+
+       (void)cris_io_interface_init();
+
+       DBG(printk("cris_io_interface_allocate_pins: if=%d port=%c start=%u 
stop=%u\n",
+                  ioif, port, start_bit, stop_bit));
+
+       if (!((start_bit <= stop_bit) &&
+             ((((port == 'a') || (port == 'b')) && (stop_bit < 8)) ||
+              ((port == 'g') && (stop_bit < 32))))) {
+               return -EINVAL;
+       }
+
+       mask = create_mask(stop_bit + 1);
+       tmp_mask = create_mask(start_bit);
+       mask &= ~tmp_mask;
+
+       DBG(printk("cris_io_interface_allocate_pins: port=%c start=%u stop=%u 
mask=0x%08x\n",
+                  port, start_bit, stop_bit, mask));
+
+       local_irq_save(flags);
+
+       switch (port) {
+       case 'a':
+               if ((gpio_pa_pins & mask) != mask) {
+                       local_irq_restore(flags);
+                       return -EBUSY;
+               }
+               owners = gpio_pa_owners;
+               gpio_pa_pins &= ~mask;
+               break;
+       case 'b':
+               if ((gpio_pb_pins & mask) != mask) {
+                       local_irq_restore(flags);
+                       return -EBUSY;
+               }
+               owners = gpio_pb_owners;
+               gpio_pb_pins &= ~mask;
+               break;
+       case 'g':
+               if (((gpio_in_pins & mask) != mask) ||
+                   ((gpio_out_pins & mask) != mask)) {
+                       local_irq_restore(flags);
+                       return -EBUSY;
+               }
+               owners = gpio_pg_owners;
+               gpio_in_pins &= ~mask;
+               gpio_out_pins &= ~mask;
+               break;
+       default:
+               local_irq_restore(flags);
+               return -EINVAL;
+       }
+
+       for (i = start_bit; i <= stop_bit; i++) {
+               owners[i] = ioif;
+       }
+       local_irq_restore(flags);
+
+       notify_watchers();
+       return 0;
+}
+
+
+/* port can be 'a', 'b' or 'g' */
+int cris_io_interface_free_pins(const enum cris_io_interface ioif,
+                                const char port,
+                                const unsigned start_bit,
+                                const unsigned stop_bit)
+{
+       unsigned int i;
+       unsigned int mask = 0;
+       unsigned int tmp_mask;
+       unsigned long int flags;
+       enum cris_io_interface *owners;
+
+       (void)cris_io_interface_init();
+
+       if (!((start_bit <= stop_bit) &&
+             ((((port == 'a') || (port == 'b')) && (stop_bit < 8)) ||
+              ((port == 'g') && (stop_bit < 32))))) {
+               return -EINVAL;
+       }
+
+       mask = create_mask(stop_bit + 1);
+       tmp_mask = create_mask(start_bit);
+       mask &= ~tmp_mask;
+
+       DBG(printk("cris_io_interface_free_pins: port=%c start=%u stop=%u 
mask=0x%08x\n",
+                  port, start_bit, stop_bit, mask));
+
+       local_irq_save(flags);
+
+       switch (port) {
+       case 'a':
+               if ((~gpio_pa_pins & mask) != mask) {
+                       local_irq_restore(flags);
+                       printk(KERN_CRIT "cris_io_interface_free_pins: Freeing 
free pins");
+               }
+               owners = gpio_pa_owners;
+               break;
+       case 'b':
+               if ((~gpio_pb_pins & mask) != mask) {
+                       local_irq_restore(flags);
+                       printk(KERN_CRIT "cris_io_interface_free_pins: Freeing 
free pins");
+               }
+               owners = gpio_pb_owners;
+               break;
+       case 'g':
+               if (((~gpio_in_pins & mask) != mask) ||
+                   ((~gpio_out_pins & mask) != mask)) {
+                       local_irq_restore(flags);
+                       printk(KERN_CRIT "cris_io_interface_free_pins: Freeing 
free pins");
+               }
+               owners = gpio_pg_owners;
+               break;
+       default:
+               owners = NULL; /* Cannot happen. Shut up, gcc! */
+       }
+
+       for (i = start_bit; i <= stop_bit; i++) {
+               if (owners[i] != ioif) {
+                       printk(KERN_CRIT "cris_io_interface_free_pins: Freeing 
unowned pins");
+               }
+       }
+
+       /* All was ok, change data. */
+       switch (port) {
+       case 'a':
+               gpio_pa_pins |= mask;
+               break;
+       case 'b':
+               gpio_pb_pins |= mask;
+               break;
+       case 'g':
+               gpio_in_pins |= mask;
+               gpio_out_pins |= mask;
+               break;
+       }
+
+       for (i = start_bit; i <= stop_bit; i++) {
+               owners[i] = if_unclaimed;
+       }
+       local_irq_restore(flags);
+       notify_watchers();
+
+        return 0;
+}
+
+
+int cris_io_interface_register_watcher(void (*notify)(const unsigned int 
gpio_in_available,
+                                                      const unsigned int 
gpio_out_available,
+                                                      const unsigned char 
pa_available,
+                                                      const unsigned char 
pb_available))
+{
+       struct watcher *w;
+
+       (void)cris_io_interface_init();
+
+       if (NULL == notify) {
+               return -EINVAL;
+       }
+       w = kmalloc(sizeof(*w), GFP_KERNEL);
+       if (!w) {
+               return -ENOMEM;
+       }
+       w->notify = notify;
+       w->next = watchers;
+       watchers = w;
+
+       w->notify((const unsigned int)gpio_in_pins,
+                 (const unsigned int)gpio_out_pins,
+                 (const unsigned char)gpio_pa_pins,
+                 (const unsigned char)gpio_pb_pins);
+
+       return 0;
+}
+
+void cris_io_interface_delete_watcher(void (*notify)(const unsigned int 
gpio_in_available,
+                                                    const unsigned int 
gpio_out_available,
+                                                     const unsigned char 
pa_available,
+                                                    const unsigned char 
pb_available))
+{
+       struct watcher *w = watchers, *prev = NULL;
+
+       (void)cris_io_interface_init();
+
+       while ((NULL != w) && (w->notify != notify)){
+               prev = w;
+               w = w->next;
+       }
+       if (NULL != w) {
+               if (NULL != prev) {
+                       prev->next = w->next;
+               } else {
+                       watchers = w->next;
+               }
+               kfree(w);
+               return;
+       }
+       printk(KERN_WARNING "cris_io_interface_delete_watcher: Deleting unknown 
watcher 0x%p\n", notify);
+}
+
+
+static int cris_io_interface_init(void)
+{
+       static int first = 1;
+       int i;
+
+       if (!first) {
+               return 0;
+       }
+       first = 0;
+
+       for (i = 0; i<8; i++) {
+               gpio_pa_owners[i] = if_unclaimed;
+               gpio_pb_owners[i] = if_unclaimed;
+               gpio_pg_owners[i] = if_unclaimed;
+       }
+       for (; i<32; i++) {
+               gpio_pg_owners[i] = if_unclaimed;
+       }
+       return 0;
+}
+
+
+module_init(cris_io_interface_init);
+
+
+EXPORT_SYMBOL(cris_request_io_interface);
+EXPORT_SYMBOL(cris_free_io_interface);
+EXPORT_SYMBOL(cris_io_interface_allocate_pins);
+EXPORT_SYMBOL(cris_io_interface_free_pins);
+EXPORT_SYMBOL(cris_io_interface_register_watcher);
+EXPORT_SYMBOL(cris_io_interface_delete_watcher);
diff -urN linux/arch/cris/arch-v10/kernel/Makefile 
linux/arch/cris/arch-v10/kernel/Makefile
--- linux/arch/cris/arch-v10/kernel/Makefile    2004/11/15 11:49:15     1.2
+++ linux/arch/cris/arch-v10/kernel/Makefile    2005/08/01 18:23:40     1.3
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.5 2004/06/02 08:24:38 starvik Exp $
+# $Id: Makefile,v 1.6 2004/12/13 12:21:51 starvik Exp $
 #
 # Makefile for the linux kernel.
 #
@@ -7,7 +7,8 @@
 
 
 obj-y   := entry.o traps.o shadows.o debugport.o irq.o \
-          process.o setup.o signal.o traps.o time.o ptrace.o
+          process.o setup.o signal.o traps.o time.o ptrace.o \
+          dma.o io_interface_mux.o
 
 obj-$(CONFIG_ETRAX_KGDB) += kgdb.o
 obj-$(CONFIG_ETRAX_FAST_TIMER) += fasttimer.o
diff -urN linux/arch/cris/arch-v10/kernel/debugport.c 
linux/arch/cris/arch-v10/kernel/debugport.c
--- linux/arch/cris/arch-v10/kernel/debugport.c 2004/11/15 11:49:15     1.4
+++ linux/arch/cris/arch-v10/kernel/debugport.c 2005/08/01 18:23:40     1.5
@@ -12,6 +12,31 @@
  *    init_etrax_debug()
  *
  * $Log: debugport.c,v $
+ * Revision 1.27  2005/06/10 10:34:14  starvik
+ * Real console support
+ *
+ * Revision 1.26  2005/06/07 07:06:07  starvik
+ * Added LF->CR translation to make ETRAX customers happy.
+ *
+ * Revision 1.25  2005/03/08 08:56:47  mikaelam
+ * Do only set index as port->index if port is defined, otherwise use the 
index from the command line
+ *
+ * Revision 1.24  2005/01/19 10:26:33  mikaelam
+ * Return the cris serial driver in console device driver callback function
+ *
+ * Revision 1.23  2005/01/14 10:12:17  starvik
+ * KGDB on separate port.
+ * Console fixes from 2.4.
+ *
+ * Revision 1.22  2005/01/11 16:06:13  starvik
+ * typo
+ *
+ * Revision 1.21  2005/01/11 13:49:14  starvik
+ * Added raw_printk to be used where we don't trust the console.
+ *
+ * Revision 1.20  2004/12/27 11:18:32  starvik
+ * Merge of Linux 2.6.10 (not functional yet).
+ *
  * Revision 1.19  2004/10/21 07:26:16  starvik
  * Made it possible to specify console settings on kernel command line.
  *
@@ -114,7 +139,11 @@
     R_SERIAL0_BAUD,
     R_SERIAL0_TR_CTRL,
     R_SERIAL0_REC_CTRL,
-    IO_STATE(R_IRQ_MASK1_SET, ser0_data, set)
+    IO_STATE(R_IRQ_MASK1_SET, ser0_data, set),
+    0,
+    115200,
+    'N',
+    8
   },
   {
     1,
@@ -124,7 +153,11 @@
     R_SERIAL1_BAUD,
     R_SERIAL1_TR_CTRL,
     R_SERIAL1_REC_CTRL,
-    IO_STATE(R_IRQ_MASK1_SET, ser1_data, set)
+    IO_STATE(R_IRQ_MASK1_SET, ser1_data, set),
+    0,
+    115200,
+    'N',
+    8
   },
   {
     2,
@@ -134,7 +167,11 @@
     R_SERIAL2_BAUD,
     R_SERIAL2_TR_CTRL,
     R_SERIAL2_REC_CTRL,
-    IO_STATE(R_IRQ_MASK1_SET, ser2_data, set)
+    IO_STATE(R_IRQ_MASK1_SET, ser2_data, set),
+    0,
+    115200,
+    'N',
+    8
   },
   {
     3,
@@ -144,11 +181,15 @@
     R_SERIAL3_BAUD,
     R_SERIAL3_TR_CTRL,
     R_SERIAL3_REC_CTRL,
-    IO_STATE(R_IRQ_MASK1_SET, ser3_data, set)
+    IO_STATE(R_IRQ_MASK1_SET, ser3_data, set),
+    0,
+    115200,
+    'N',
+    8
   }
 };
 
-static struct tty_driver *serial_driver;
+extern struct tty_driver *serial_driver;
 
 struct dbg_port* port =
 #if defined(CONFIG_ETRAX_DEBUG_PORT0)
@@ -162,37 +203,44 @@
 #else
   NULL;
 #endif
-/* Used by serial.c to register a debug_write_function so that the normal
- * serial driver is used for kernel debug output
- */
-typedef int (*debugport_write_function)(int i, const char *buf, unsigned int 
len);
 
-debugport_write_function debug_write_function = NULL;
+static struct dbg_port* kgdb_port =
+#if defined(CONFIG_ETRAX_KGDB_PORT0)
+  &ports[0];
+#elif defined(CONFIG_ETRAX_KGDB_PORT1)
+  &ports[1];
+#elif defined(CONFIG_ETRAX_KGDB_PORT2)
+  &ports[2];
+#elif defined(CONFIG_ETRAX_KGDB_PORT3)
+  &ports[3];
+#else
+  NULL;
+#endif
 
 static void
-start_port(void)
+start_port(struct dbg_port* p)
 {
        unsigned long rec_ctrl = 0;
        unsigned long tr_ctrl = 0;
 
-       if (!port)
+       if (!p)
                return;
 
-       if (port->started)
+       if (p->started)
                return;
-       port->started = 1;
+       p->started = 1;
 
-       if (port->index == 0)
+       if (p->index == 0)
        {
                genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6);
                genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused);
        }
-       else if (port->index == 1)
+       else if (p->index == 1)
        {
                genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8);
                genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb);
        }
-       else if (port->index == 2)
+       else if (p->index == 2)
        {
                genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2);
                genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0);
@@ -211,69 +259,69 @@
 
        *R_GEN_CONFIG = genconfig_shadow;
 
-       *port->xoff =
+       *p->xoff =
                IO_STATE(R_SERIAL0_XOFF, tx_stop, enable) |
                IO_STATE(R_SERIAL0_XOFF, auto_xoff, disable) |
                IO_FIELD(R_SERIAL0_XOFF, xoff_char, 0);
 
-       switch (port->baudrate)
+       switch (p->baudrate)
        {
        case 0:
        case 115200:
-               *port->baud =
+               *p->baud =
                  IO_STATE(R_SERIAL0_BAUD, tr_baud, c115k2Hz) |
                  IO_STATE(R_SERIAL0_BAUD, rec_baud, c115k2Hz);
                break;
        case 1200:
-               *port->baud =
+               *p->baud =
                  IO_STATE(R_SERIAL0_BAUD, tr_baud, c1200Hz) |
                  IO_STATE(R_SERIAL0_BAUD, rec_baud, c1200Hz);
                break;
        case 2400:
-               *port->baud =
+               *p->baud =
                  IO_STATE(R_SERIAL0_BAUD, tr_baud, c2400Hz) |
                  IO_STATE(R_SERIAL0_BAUD, rec_baud, c2400Hz);
                break;
        case 4800:
-               *port->baud =
+               *p->baud =
                  IO_STATE(R_SERIAL0_BAUD, tr_baud, c4800Hz) |
                  IO_STATE(R_SERIAL0_BAUD, rec_baud, c4800Hz);
                break;
        case 9600:
-               *port->baud =
+               *p->baud =
                  IO_STATE(R_SERIAL0_BAUD, tr_baud, c9600Hz) |
                  IO_STATE(R_SERIAL0_BAUD, rec_baud, c9600Hz);
                  break;
        case 19200:
-               *port->baud =
+               *p->baud =
                  IO_STATE(R_SERIAL0_BAUD, tr_baud, c19k2Hz) |
                  IO_STATE(R_SERIAL0_BAUD, rec_baud, c19k2Hz);
                 break;
        case 38400:
-               *port->baud =
+               *p->baud =
                  IO_STATE(R_SERIAL0_BAUD, tr_baud, c38k4Hz) |
                  IO_STATE(R_SERIAL0_BAUD, rec_baud, c38k4Hz);
                break;
        case 57600:
-               *port->baud =
+               *p->baud =
                  IO_STATE(R_SERIAL0_BAUD, tr_baud, c57k6Hz) |
                  IO_STATE(R_SERIAL0_BAUD, rec_baud, c57k6Hz);
                break;
        default:
-               *port->baud =
+               *p->baud =
                  IO_STATE(R_SERIAL0_BAUD, tr_baud, c115k2Hz) |
                  IO_STATE(R_SERIAL0_BAUD, rec_baud, c115k2Hz);
                  break;
         }
 
-       if (port->parity == 'E') {
+       if (p->parity == 'E') {
                rec_ctrl =
                  IO_STATE(R_SERIAL0_REC_CTRL, rec_par, even) |
                  IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable);
                tr_ctrl =
                  IO_STATE(R_SERIAL0_TR_CTRL, tr_par, even) |
                  IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable);
-       } else if (port->parity == 'O') {
+       } else if (p->parity == 'O') {
                rec_ctrl =
                  IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd) |
                  IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable);
@@ -288,8 +336,7 @@
                  IO_STATE(R_SERIAL0_TR_CTRL, tr_par, even) |
                  IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, disable);
        }
-
-       if (port->bits == 7)
+       if (p->bits == 7)
        {
                rec_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit);
                tr_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit);
@@ -300,7 +347,7 @@
                tr_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_8bit);
        }
 
-       *port->rec_ctrl =
+       *p->rec_ctrl =
                IO_STATE(R_SERIAL0_REC_CTRL, dma_err, stop) |
                IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable) |
                IO_STATE(R_SERIAL0_REC_CTRL, rts_, active) |
@@ -308,7 +355,7 @@
                IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, normal) |
                rec_ctrl;
 
-       *port->tr_ctrl =
+       *p->tr_ctrl =
                IO_FIELD(R_SERIAL0_TR_CTRL, txd, 0) |
                IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable) |
                IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, disabled) |
@@ -323,8 +370,18 @@
        int i;
        unsigned long flags;
        local_irq_save(flags);
+
+        if (!port)
+               return;
+
        /* Send data */
        for (i = 0; i < len; i++) {
+               /* LF -> CRLF */
+               if (buf[i] == '\n') {
+                       while (!(*port->read & IO_MASK(R_SERIAL0_READ, 
tr_ready)))
+                       ;
+                       *port->write = '\r';
+               }
                /* Wait until transmitter is ready and send.*/
                while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready)))
                        ;
@@ -333,6 +390,25 @@
        local_irq_restore(flags);
 }
 
+int raw_printk(const char *fmt, ...)
+{
+       static char buf[1024];
+       int printed_len;
+       static int first = 1;
+       if (first) {
+               /* Force reinitialization of the port to get manual mode. */
+               port->started = 0;
+               start_port(port);
+               first = 0;
+       }
+       va_list args;
+       va_start(args, fmt);
+       printed_len = vsnprintf(buf, sizeof(buf), fmt, args);
+       va_end(args);
+       console_write_direct(NULL, buf, strlen(buf));
+       return printed_len;
+}
+
 static void
 console_write(struct console *co, const char *buf, unsigned int len)
 {
@@ -345,18 +421,7 @@
        return;
 #endif
 
-       start_port();
-
-#ifdef CONFIG_ETRAX_KGDB
-       /* kgdb needs to output debug info using the gdb protocol */
-       putDebugString(buf, len);
-       return;
-#endif
-
-       if (debug_write_function)
-               debug_write_function(co->index, buf, len);
-       else
-               console_write_direct(co, buf, len);
+        console_write_direct(co, buf, len);
 }
 
 /* legacy function */
@@ -374,8 +439,11 @@
 {
        unsigned long readval;
 
+       if (!kgdb_port)
+               return 0;
+
        do {
-               readval = *port->read;
+               readval = *kgdb_port->read;
        } while (!(readval & IO_MASK(R_SERIAL0_READ, data_avail)));
 
        return (readval & IO_MASK(R_SERIAL0_READ, data_in));
@@ -386,9 +454,12 @@
 void
 putDebugChar(int val)
 {
-       while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready)))
+       if (!kgdb_port)
+               return;
+
+       while (!(*kgdb_port->read & IO_MASK(R_SERIAL0_READ, tr_ready)))
                ;
-       *port->write = val;
+       *kgdb_port->write = val;
 }
 
 /* Enable irq for receiving chars on the debug port, used by kgdb */
@@ -396,19 +467,16 @@
 void
 enableDebugIRQ(void)
 {
-       *R_IRQ_MASK1_SET = port->irq;
+       if (!kgdb_port)
+               return;
+
+       *R_IRQ_MASK1_SET = kgdb_port->irq;
        /* use R_VECT_MASK directly, since we really bypass Linux normal
         * IRQ handling in kgdb anyway, we don't need to use enable_irq
         */
        *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set);
 
-       *port->rec_ctrl = IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable);
-}
-
-static struct tty_driver*
-etrax_console_device(struct console* co, int *index)
-{
-       return serial_driver;
+       *kgdb_port->rec_ctrl = IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable);
 }
 
 static int __init
@@ -428,11 +496,69 @@
                if (*s) port->parity = *s++;
                if (*s) port->bits   = *s++ - '0';
                port->started = 0;
-               start_port();
+               start_port(0);
        }
        return 0;
 }
 
+/* This is a dummy serial device that throws away anything written to it.
+ * This is used when no debug output is wanted.
+ */
+static struct tty_driver dummy_driver;
+
+static int dummy_open(struct tty_struct *tty, struct file * filp)
+{
+       return 0;
+}
+
+static void dummy_close(struct tty_struct *tty, struct file * filp)
+{
+}
+
+static int dummy_write(struct tty_struct * tty,
+                       const unsigned char *buf, int count)
+{
+       return count;
+}
+
+static int
+dummy_write_room(struct tty_struct *tty)
+{
+       return 8192;
+}
+
+void __init
+init_dummy_console(void)
+{
+       memset(&dummy_driver, 0, sizeof(struct tty_driver));
+       dummy_driver.driver_name = "serial";
+       dummy_driver.name = "ttyS";
+       dummy_driver.major = TTY_MAJOR;
+       dummy_driver.minor_start = 68;
+       dummy_driver.num = 1;       /* etrax100 has 4 serial ports */
+       dummy_driver.type = TTY_DRIVER_TYPE_SERIAL;
+       dummy_driver.subtype = SERIAL_TYPE_NORMAL;
+       dummy_driver.init_termios = tty_std_termios;
+       dummy_driver.init_termios.c_cflag =
+               B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 
default... */
+       dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+
+       dummy_driver.open = dummy_open;
+       dummy_driver.close = dummy_close;
+       dummy_driver.write = dummy_write;
+       dummy_driver.write_room = dummy_write_room;
+       if (tty_register_driver(&dummy_driver))
+               panic("Couldn't register dummy serial driver\n");
+}
+
+static struct tty_driver*
+etrax_console_device(struct console* co, int *index)
+{
+       if (port)
+               *index = port->index;
+        return port ? serial_driver : &dummy_driver;
+}
+
 static struct console sercons = {
        name : "ttyS",
        write: console_write,
@@ -504,28 +630,21 @@
        static int first = 1;
 
        if (!first) {
-               if (!port) {
-                       register_console(&sercons0);
-                       register_console(&sercons1);
-                       register_console(&sercons2);
-                       register_console(&sercons3);
-                       unregister_console(&sercons);
-               }
+               unregister_console(&sercons);
+               register_console(&sercons0);
+               register_console(&sercons1);
+               register_console(&sercons2);
+               register_console(&sercons3);
+                init_dummy_console();
                return 0;
        }
-       first = 0;
-       if (port)
-               register_console(&sercons);
-       return 0;
-}
 
-int __init
-init_console(void)
-{
-       serial_driver = alloc_tty_driver(1);
-       if (!serial_driver)
-               return -ENOMEM;
+       first = 0;
+       register_console(&sercons);
+       start_port(port);
+#ifdef CONFIG_ETRAX_KGDB
+       start_port(kgdb_port);
+#endif
        return 0;
 }
-
 __initcall(init_etrax_debug);
diff -urN linux/arch/cris/arch-v10/kernel/entry.S 
linux/arch/cris/arch-v10/kernel/entry.S
--- linux/arch/cris/arch-v10/kernel/entry.S     2004/11/15 11:49:15     1.3
+++ linux/arch/cris/arch-v10/kernel/entry.S     2005/08/01 18:23:40     1.4
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.23 2004/10/19 13:07:37 starvik Exp $
+/* $Id: entry.S,v 1.28 2005/06/20 05:06:30 starvik Exp $
  *
  *  linux/arch/cris/entry.S
  *
@@ -7,6 +7,22 @@
  *  Authors:   Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: entry.S,v $
+ *  Revision 1.28  2005/06/20 05:06:30  starvik
+ *  Remove unnecessary diff to kernel.org tree
+ *
+ *  Revision 1.27  2005/03/04 08:16:16  starvik
+ *  Merge of Linux 2.6.11.
+ *
+ *  Revision 1.26  2005/01/11 13:49:47  starvik
+ *  Added NMI handler.
+ *
+ *  Revision 1.25  2004/12/27 11:18:32  starvik
+ *  Merge of Linux 2.6.10 (not functional yet).
+ *
+ *  Revision 1.24  2004/12/22 10:41:23  starvik
+ *  Updates to make v10 compile with the latest SMP aware generic code (even
+ *  though v10 will never have SMP).
+ *
  *  Revision 1.23  2004/10/19 13:07:37  starvik
  *  Merge of Linux 2.6.9
  *
@@ -279,6 +295,7 @@
 #ifdef CONFIG_PREEMPT  
        ; Check if preemptive kernel scheduling should be done
 _resume_kernel:
+       di
        ; Load current task struct
        movs.w  -8192, $r0      ;  THREAD_SIZE = 8192
        and.d   $sp, $r0
@@ -291,12 +308,7 @@
        bpl     _Rexit
        nop
        ; Ok, lets's do some preemptive kernel scheduling
-       move.d  PREEMPT_ACTIVE, $r10
-       move.d  $r10, [$r0+TI_preempt_count] ; Mark as active
-       ei
-       jsr     schedule
-       clear.d [$r0+TI_preempt_count] ;  Mark as inactive
-       di
+       jsr     preempt_schedule_irq
        ; Load new task struct
        movs.w  -8192, $r0      ;  THREAD_SIZE = 8192
        and.d   $sp, $r0
@@ -590,15 +602,15 @@
        move.d  $r0, [$sp+16]
 1:     btstq   12, $r1            ; Refill?
        bpl     2f
-       lsrq    PMD_SHIFT, $r1     ; Get PMD index into PGD (bit 24-31)
-       move.d  [current_pgd], $r0 ; PGD for the current process
+       lsrq    24, $r1     ; Get PGD index (bit 24-31)
+       move.d  [per_cpu__current_pgd], $r0 ; PGD for the current process
        move.d  [$r0+$r1.d], $r0   ; Get PMD
        beq     2f
        nop
        and.w   PAGE_MASK, $r0     ; Remove PMD flags
        move.d  [R_MMU_CAUSE], $r1
        lsrq    PAGE_SHIFT, $r1
-       and.d   0x7ff, $r1         ; Get PTE index into PMD (bit 13-24)
+       and.d   0x7ff, $r1         ; Get PTE index into PGD (bit 13-23)
        move.d  [$r0+$r1.d], $r1   ; Get PTE
        beq     2f
        nop
@@ -656,11 +668,6 @@
        nop
        
 IRQ1_interrupt:
-
-#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
-;; If we receive a watchdog interrupt while it is not expected, then set
-;; up a canonical frame and dump register contents before dying.
-
        ;; this prologue MUST match the one in irq.h and the struct in 
ptregs.h!!!
        move    $brp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS 
frame
        push    $srp
@@ -672,9 +679,16 @@
        push    $r10            ; push orig_r10
        clear.d [$sp=$sp-4]     ; frametype == 0, normal frame
 
-;; We don't check that we actually were bit by the watchdog as opposed to
-;; an external NMI, since there is currently no handler for external NMI.
-
+       move.d  [R_IRQ_MASK0_RD], $r1 ; External NMI or watchdog?
+       and.d   0x80000000, $r1
+       beq     wdog
+       move.d  $sp, $r10
+       jsr     handle_nmi
+       setf m                  ; Enable NMI again
+       retb                    ; Return from NMI
+       nop
+wdog:
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
 ;; Check if we're waiting for reset to happen, as signalled by
 ;; hard_reset_now setting cause_of_death to a magic value.  If so, just
 ;; get stuck until reset happens.
@@ -1118,6 +1132,10 @@
        .long sys_mq_getsetattr
        .long sys_ni_syscall            /* reserved for kexec */
        .long sys_waitid
+       .long sys_ni_syscall            /* 285 */ /* available */
+       .long sys_add_key
+       .long sys_request_key
+       .long sys_keyctl
 
         /*
          * NOTE!! This doesn't have to be exact - we just have
diff -urN linux/arch/cris/arch-v10/kernel/fasttimer.c 
linux/arch/cris/arch-v10/kernel/fasttimer.c
--- linux/arch/cris/arch-v10/kernel/fasttimer.c 2005/01/13 14:05:22     1.5
+++ linux/arch/cris/arch-v10/kernel/fasttimer.c 2005/08/01 18:23:40     1.6
@@ -1,10 +1,20 @@
-/* $Id: fasttimer.c,v 1.6 2004/05/14 10:18:39 starvik Exp $
+/* $Id: fasttimer.c,v 1.9 2005/03/04 08:16:16 starvik Exp $
  * linux/arch/cris/kernel/fasttimer.c
  *
  * Fast timers for ETRAX100/ETRAX100LX
  * This may be useful in other OS than Linux so use 2 space indentation...
  *
  * $Log: fasttimer.c,v $
+ * Revision 1.9  2005/03/04 08:16:16  starvik
+ * Merge of Linux 2.6.11.
+ *
+ * Revision 1.8  2005/01/05 06:09:29  starvik
+ * cli()/sti() will be obsolete in 2.6.11.
+ *
+ * Revision 1.7  2005/01/03 13:35:46  starvik
+ * Removed obsolete stuff.
+ * Mark fast timer IRQ as not shared.
+ *
  * Revision 1.6  2004/05/14 10:18:39  starvik
  * Export fast_timer_list
  *
@@ -148,8 +158,7 @@
 #define DEBUG_LOG(string, value) \
 { \
   unsigned long log_flags; \
-  save_flags(log_flags); \
-  cli(); \
+  local_irq_save(log_flags); \
   debug_log_string[debug_log_cnt] = (string); \
   debug_log_value[debug_log_cnt] = (unsigned long)(value); \
   if (++debug_log_cnt >= DEBUG_LOG_MAX) \
@@ -157,7 +166,7 @@
     debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \
     debug_log_cnt_wrapped = 1; \
   } \
-  restore_flags(log_flags); \
+  local_irq_restore(log_flags); \
 }
 #else
 #define DEBUG_LOG(string, value)
@@ -320,8 +329,7 @@
 
   D1(printk("sft %s %d us\n", name, delay_us));
 
-  save_flags(flags);
-  cli();
+  local_irq_save(flags);
 
   do_gettimeofday_fast(&t->tv_set);
   tmp = fast_timer_list;
@@ -395,7 +403,7 @@
 
   D2(printk("start_one_shot_timer: %d us done\n", delay_us));
 
-  restore_flags(flags);
+  local_irq_restore(flags);
 } /* start_one_shot_timer */
 
 static inline int fast_timer_pending (const struct fast_timer * t)
@@ -425,11 +433,10 @@
   unsigned long flags;
   int ret;
   
-  save_flags(flags);
-  cli();
+  local_irq_save(flags);
   ret = detach_fast_timer(t);
   t->next = t->prev = NULL;
-  restore_flags(flags);
+  local_irq_restore(flags);
   return ret;
 } /* del_fast_timer */
 
@@ -444,8 +451,7 @@
   struct fast_timer *t;
   unsigned long flags;
 
-  save_flags(flags);
-  cli();
+  local_irq_save(flags);
 
   /* Clear timer1 irq */
   *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr);
@@ -462,7 +468,7 @@
   fast_timer_running = 0;
   fast_timer_ints++;
 
-  restore_flags(flags);
+  local_irq_restore(flags);
 
   t = fast_timer_list;
   while (t)
@@ -482,8 +488,7 @@
       fast_timers_expired++;
 
       /* Remove this timer before call, since it may reuse the timer */
-      save_flags(flags);
-      cli();
+      local_irq_save(flags);
       if (t->prev)
       {
         t->prev->next = t->next;
@@ -498,7 +503,7 @@
       }
       t->prev = NULL;
       t->next = NULL;
-      restore_flags(flags);
+      local_irq_restore(flags);
 
       if (t->function != NULL)
       {
@@ -515,8 +520,7 @@
       D1(printk(".\n"));
     }
 
-    save_flags(flags);
-    cli();
+    local_irq_save(flags);
     if ((t = fast_timer_list) != NULL)
     {
       /* Start next timer.. */
@@ -535,7 +539,7 @@
 #endif
           start_timer1(us);
         }
-        restore_flags(flags);
+        local_irq_restore(flags);
         break;
       }
       else
@@ -546,7 +550,7 @@
         D1(printk("e! %d\n", us));
       }
     }
-    restore_flags(flags);
+    local_irq_restore(flags);
   }
 
   if (!t)
@@ -748,13 +752,12 @@
 #endif
 
     used += sprintf(bigbuf + used, "Active timers:\n");
-    save_flags(flags);
-    cli();
+    local_irq_save(flags);
     t = fast_timer_list;
     while (t != NULL && (used+100 < BIG_BUF_SIZE))
     {
       nextt = t->next;
-      restore_flags(flags);
+      local_irq_restore(flags);
       used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
                       "d: %6li us data: 0x%08lX"
 /*                      " func: 0x%08lX" */
@@ -768,14 +771,14 @@
                       t->data
 /*                      , t->function */
                       );
-      cli();
+      local_irq_disable();
       if (t->next != nextt)
       {
         printk(KERN_WARNING "timer removed!\n");
       }
       t = nextt;
     }
-    restore_flags(flags);
+    local_irq_restore(flags);
   }
 
   if (used - offset < len)
@@ -963,7 +966,7 @@
    if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 )))
      fasttimer_proc_entry->read_proc = proc_fasttimer_read;
 #endif /* PROC_FS */
-    if(request_irq(TIMER1_IRQ_NBR, timer1_handler, SA_SHIRQ,
+    if(request_irq(TIMER1_IRQ_NBR, timer1_handler, 0,
                    "fast timer int", NULL))
     {
       printk("err: timer1 irq\n");
diff -urN linux/arch/cris/arch-v10/kernel/head.S 
linux/arch/cris/arch-v10/kernel/head.S
--- linux/arch/cris/arch-v10/kernel/head.S      2004/06/09 14:12:04     1.2
+++ linux/arch/cris/arch-v10/kernel/head.S      2005/08/01 18:23:40     1.3
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.7 2004/05/14 07:58:01 starvik Exp $
+/* $Id: head.S,v 1.10 2005/06/20 05:12:54 starvik Exp $
  * 
  * Head of the kernel - alter with care
  *
@@ -7,6 +7,16 @@
  * Authors:    Bjorn Wesen (bjornw@axis.com)
  * 
  * $Log: head.S,v $
+ * Revision 1.10  2005/06/20 05:12:54  starvik
+ * Remove unnecessary diff to kernel.org tree
+ *
+ * Revision 1.9  2004/12/13 12:21:51  starvik
+ * Added I/O and DMA allocators from Linux 2.4
+ *
+ * Revision 1.8  2004/11/22 11:41:14  starvik
+ * Kernel command line may be supplied to kernel. Not used by Axis but may
+ * be used by customers.
+ *
  * Revision 1.7  2004/05/14 07:58:01  starvik
  * Merge of changes from 2.4
  *
@@ -181,6 +191,7 @@
 
 #define CRAMFS_MAGIC 0x28cd3d45
 #define RAM_INIT_MAGIC 0x56902387
+#define COMMAND_LINE_MAGIC 0x87109563
 
 #define START_ETHERNET_CLOCK IO_STATE(R_NETWORK_GEN_CONFIG, enable, on) |\
                              IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk)
@@ -490,6 +501,23 @@
        
 _start_it:
 
+       ;; Check if kernel command line is supplied
+       cmp.d   COMMAND_LINE_MAGIC, $r10
+       bne     no_command_line
+       nop
+
+       move.d  256, $r13
+       move.d  cris_command_line, $r10
+       or.d    0x80000000, $r11 ; Make it virtual
+1:
+       move.b  [$r11+], $r12
+       move.b  $r12, [$r10+]
+       subq    1, $r13
+       bne     1b
+       nop
+
+no_command_line:
+
        ;; the kernel stack is overlayed with the task structure for each
        ;; task. thus the initial kernel stack is in the same page as the
        ;; init_task (but starts in the top of the page, size 8192)
@@ -567,76 +595,32 @@
        ;; Etrax product HW genconfig setup
 
        moveq   0,$r0
-#if (!defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT0)) \
-       && !defined(CONFIG_DMA_MEMCPY)
-       ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA
-       or.d      IO_STATE (R_GEN_CONFIG, dma7, serial0)        \
-               | IO_STATE (R_GEN_CONFIG, dma6, serial0),$r0
-#endif
-#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT1)
-       ; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA
-       or.d      IO_STATE (R_GEN_CONFIG, dma9, serial1)        \
-               | IO_STATE (R_GEN_CONFIG, dma8, serial1),$r0
-#endif 
-#ifdef CONFIG_DMA_MEMCPY
-       ; 6/7 memory-memory DMA
-       or.d      IO_STATE (R_GEN_CONFIG, dma7, intdma6)        \
-               | IO_STATE (R_GEN_CONFIG, dma6, intdma7),$r0
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT2
-       ; Enable serial port 2
-       or.w    IO_STATE (R_GEN_CONFIG, ser2, select),$r0
-#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT2)
-       ; DMA channels 2 and 3 to ser2, kgdb doesnt want DMA
-       or.d      IO_STATE (R_GEN_CONFIG, dma3, serial2)        \
-               | IO_STATE (R_GEN_CONFIG, dma2, serial2),$r0
-#endif
-#endif
-#if defined(CONFIG_ETRAX_SERIAL_PORT3) || 
defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)
-       ; Enable serial port 3
-       or.w    IO_STATE (R_GEN_CONFIG, ser3, select),$r0
-#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT3)
-       ; DMA channels 4 and 5 to ser3, kgdb doesnt want DMA
-       or.d      IO_STATE (R_GEN_CONFIG, dma5, serial3)        \
-               | IO_STATE (R_GEN_CONFIG, dma4, serial3),$r0
-#endif
-#endif
-#if defined(CONFIG_ETRAX_PARALLEL_PORT0) || 
defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
-       ; parport 0 enabled using DMA 2/3
-       or.w    IO_STATE (R_GEN_CONFIG, par0, select),$r0
-#endif
-#if defined(CONFIG_ETRAX_PARALLEL_PORT1) || 
defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
-       ; parport 1 enabled using DMA 4/5
-       or.w    IO_STATE (R_GEN_CONFIG, par1, select),$r0
-#endif
-#ifdef CONFIG_ETRAX_IDE
-       ; DMA channels 2 and 3 to ATA, ATA enabled
-       or.d      IO_STATE (R_GEN_CONFIG, dma3, ata)    \
-               | IO_STATE (R_GEN_CONFIG, dma2, ata)    \
-               | IO_STATE (R_GEN_CONFIG, ata, select),$r0
-#endif
-       
-#ifdef CONFIG_ETRAX_USB_HOST_PORT1
-       ; Set the USB port 1 enable bit
-       or.d    IO_STATE (R_GEN_CONFIG, usb1, select),$r0
-#endif
-#ifdef CONFIG_ETRAX_USB_HOST_PORT2
-       ; Set the USB port 2 enable bit
-       or.d    IO_STATE (R_GEN_CONFIG, usb2, select),$r0
-#endif
-#ifdef CONFIG_ETRAX_USB_HOST
-       ; Connect DMA channels 8 and 9 to USB
-       and.d   (~(IO_MASK (R_GEN_CONFIG, dma9)         \
-                  | IO_MASK (R_GEN_CONFIG, dma8)))     \
-               | IO_STATE (R_GEN_CONFIG, dma9, usb)    \
-               | IO_STATE (R_GEN_CONFIG, dma8, usb),$r0
-#endif
-       
-#ifdef CONFIG_JULIETTE
-       ; DMA channels 4 and 5 to EXTDMA0, for Juliette
-       or.d      IO_STATE (R_GEN_CONFIG, dma5, extdma0)        \
-               | IO_STATE (R_GEN_CONFIG, dma4, extdma0),$r0
-#endif
+
+       ;; Init interfaces (disable them).
+       or.d      IO_STATE (R_GEN_CONFIG, scsi0, disable) \
+               | IO_STATE (R_GEN_CONFIG, ata, disable) \
+               | IO_STATE (R_GEN_CONFIG, par0, disable) \
+               | IO_STATE (R_GEN_CONFIG, ser2, disable) \
+               | IO_STATE (R_GEN_CONFIG, mio, disable) \
+               | IO_STATE (R_GEN_CONFIG, scsi1, disable) \
+               | IO_STATE (R_GEN_CONFIG, scsi0w, disable) \
+               | IO_STATE (R_GEN_CONFIG, par1, disable) \
+               | IO_STATE (R_GEN_CONFIG, ser3, disable) \
+               | IO_STATE (R_GEN_CONFIG, mio_w, disable) \
+               | IO_STATE (R_GEN_CONFIG, usb1, disable) \
+               | IO_STATE (R_GEN_CONFIG, usb2, disable) \
+               | IO_STATE (R_GEN_CONFIG, par_w, disable),$r0
+
+       ;; Init DMA channel muxing (set to unused clients).
+       or.d      IO_STATE (R_GEN_CONFIG, dma2, ata)    \
+               | IO_STATE (R_GEN_CONFIG, dma3, ata) \
+               | IO_STATE (R_GEN_CONFIG, dma4, scsi1) \
+               | IO_STATE (R_GEN_CONFIG, dma5, scsi1) \
+               | IO_STATE (R_GEN_CONFIG, dma6, unused) \
+               | IO_STATE (R_GEN_CONFIG, dma7, unused) \
+               | IO_STATE (R_GEN_CONFIG, dma8, usb) \
+               | IO_STATE (R_GEN_CONFIG, dma9, usb),$r0
+
 
 #if defined(CONFIG_ETRAX_DEF_R_PORT_G0_DIR_OUT)
         or.d      IO_STATE (R_GEN_CONFIG, g0dir, out),$r0
diff -urN linux/arch/cris/arch-v10/kernel/irq.c 
linux/arch/cris/arch-v10/kernel/irq.c
--- linux/arch/cris/arch-v10/kernel/irq.c       2004/11/15 11:49:15     1.2
+++ linux/arch/cris/arch-v10/kernel/irq.c       2005/08/01 18:23:40     1.3
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.2 2004/06/09 05:30:27 starvik Exp $
+/* $Id: irq.c,v 1.4 2005/01/04 12:22:28 starvik Exp $
  *
  *     linux/arch/cris/kernel/irq.c
  *
@@ -12,11 +12,13 @@
  */
 
 #include <asm/irq.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/config.h>
 
-irqvectptr irq_shortcuts[NR_IRQS]; /* vector of shortcut jumps after the irq 
prologue */
+#define mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr));
+#define unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr));
 
 /* don't use set_int_vector, it bypasses the linux interrupt handlers. it is
  * global just so that the kernel gdb can use it.
@@ -102,41 +104,52 @@
        IRQ31_interrupt
 };
 
-static void (*bad_interrupt[NR_IRQS])(void) = {
-        NULL, NULL,
-       NULL, bad_IRQ3_interrupt,
-       bad_IRQ4_interrupt, bad_IRQ5_interrupt,
-       bad_IRQ6_interrupt, bad_IRQ7_interrupt,
-       bad_IRQ8_interrupt, bad_IRQ9_interrupt,
-       bad_IRQ10_interrupt, bad_IRQ11_interrupt,
-       bad_IRQ12_interrupt, bad_IRQ13_interrupt,
-       NULL, NULL,
-       bad_IRQ16_interrupt, bad_IRQ17_interrupt,
-       bad_IRQ18_interrupt, bad_IRQ19_interrupt,
-       bad_IRQ20_interrupt, bad_IRQ21_interrupt,
-       bad_IRQ22_interrupt, bad_IRQ23_interrupt,
-       bad_IRQ24_interrupt, bad_IRQ25_interrupt,
-       NULL, NULL, NULL, NULL, NULL,
-       bad_IRQ31_interrupt
-};
+static void enable_crisv10_irq(unsigned int irq);
+
+static unsigned int startup_crisv10_irq(unsigned int irq)
+{
+       enable_crisv10_irq(irq);
+       return 0;
+}
+
+#define shutdown_crisv10_irq   disable_crisv10_irq
 
-void arch_setup_irq(int irq)
+static void enable_crisv10_irq(unsigned int irq)
 {
-  set_int_vector(irq, interrupt[irq]);
+       unmask_irq(irq);
 }
 
-void arch_free_irq(int irq)
+static void disable_crisv10_irq(unsigned int irq)
 {
-  set_int_vector(irq, bad_interrupt[irq]);
+       mask_irq(irq);
 }
 
+static void ack_crisv10_irq(unsigned int irq)
+{
+}
+
+static void end_crisv10_irq(unsigned int irq)
+{
+}
+
+static struct hw_interrupt_type crisv10_irq_type = {
+       .typename =    "CRISv10",
+       .startup =     startup_crisv10_irq,
+       .shutdown =    shutdown_crisv10_irq,
+       .enable =      enable_crisv10_irq,
+       .disable =     disable_crisv10_irq,
+       .ack =         ack_crisv10_irq,
+       .end =         end_crisv10_irq,
+       .set_affinity = NULL
+};
+
 void weird_irq(void);
 void system_call(void);  /* from entry.S */
 void do_sigtrap(void); /* from entry.S */
 void gdb_handle_breakpoint(void); /* from entry.S */
 
 /* init_IRQ() is called by start_kernel and is responsible for fixing IRQ 
masks and
-   setting the irq vector table to point to bad_interrupt ptrs.
+   setting the irq vector table.
 */
 
 void __init
@@ -154,14 +167,15 @@
 
        *R_VECT_MASK_CLR = 0xffffffff;
 
-       /* clear the shortcut entry points */
-
-       for(i = 0; i < NR_IRQS; i++)
-               irq_shortcuts[i] = NULL;
-        
         for (i = 0; i < 256; i++)
                etrax_irv->v[i] = weird_irq;
 
+       /* Initialize IRQ handler descriptiors. */
+       for(i = 2; i < NR_IRQS; i++) {
+               irq_desc[i].handler = &crisv10_irq_type;
+               set_int_vector(i, interrupt[i]);
+       }
+
         /* the entries in the break vector contain actual code to be
            executed by the associated break handler, rather than just a jump
            address. therefore we need to setup a default breakpoint handler
@@ -170,10 +184,6 @@
        for (i = 0; i < 16; i++)
                 set_break_vector(i, do_sigtrap);
         
-       /* set all etrax irq's to the bad handlers */
-       for (i = 2; i < NR_IRQS; i++)
-               set_int_vector(i, bad_interrupt[i]);
-        
        /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */
 
        set_int_vector(15, multiple_interrupt);
diff -urN linux/arch/cris/arch-v10/kernel/kgdb.c 
linux/arch/cris/arch-v10/kernel/kgdb.c
--- linux/arch/cris/arch-v10/kernel/kgdb.c      2004/11/15 11:49:15     1.2
+++ linux/arch/cris/arch-v10/kernel/kgdb.c      2005/08/01 18:23:40     1.3
@@ -18,6 +18,10 @@
 *! Jul 21 1999  Bjorn Wesen     eLinux port
 *!
 *! $Log: kgdb.c,v $
+*! Revision 1.6  2005/01/14 10:12:17  starvik
+*! KGDB on separate port.
+*! Console fixes from 2.4.
+*!
 *! Revision 1.5  2004/10/07 13:59:08  starvik
 *! Corrected call to set_int_vector
 *!
@@ -71,7 +75,7 @@
 *!
 *!---------------------------------------------------------------------------
 *!
-*! $Id: kgdb.c,v 1.5 2004/10/07 13:59:08 starvik Exp $
+*! $Id: kgdb.c,v 1.6 2005/01/14 10:12:17 starvik Exp $
 *!
 *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN
 *!
@@ -225,6 +229,7 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/linkage.h>
+#include <linux/reboot.h>
 
 #include <asm/setup.h>
 #include <asm/ptrace.h>
@@ -1344,12 +1349,11 @@
        }
 }
 
-/* The jump is to the address 0x00000002. Performs a complete re-start
-   from scratch. */
+/* Performs a complete re-start from scratch. */
 static void
 kill_restart ()
 {
-       __asm__ volatile ("jump 2");
+       machine_restart("");
 }
 
 /********************************** Breakpoint *******************************/
@@ -1506,6 +1510,11 @@
   bne goback
   nop
 
+  move.d  [reg+0x5E], $r10             ; Get DCCR
+  btstq           8, $r10                      ; Test the U-flag.
+  bmi     goback
+  nop
+
 ;;
 ;; Handle the communication
 ;;
diff -urN linux/arch/cris/arch-v10/kernel/process.c 
linux/arch/cris/arch-v10/kernel/process.c
--- linux/arch/cris/arch-v10/kernel/process.c   2004/11/15 11:49:15     1.7
+++ linux/arch/cris/arch-v10/kernel/process.c   2005/08/01 18:23:40     1.8
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.9 2004/10/19 13:07:37 starvik Exp $
+/* $Id: process.c,v 1.12 2004/12/27 11:18:32 starvik Exp $
  * 
  *  linux/arch/cris/kernel/process.c
  *
@@ -101,6 +101,7 @@
        regs.r11 = (unsigned long)fn;
        regs.r12 = (unsigned long)arg;
        regs.irp = (unsigned long)kernel_thread_helper;
+       regs.dccr = 1 << I_DCCR_BITNR;
 
        /* Ok, create the new process.. */
         return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, 
NULL);
diff -urN linux/arch/cris/arch-v10/kernel/ptrace.c 
linux/arch/cris/arch-v10/kernel/ptrace.c
--- linux/arch/cris/arch-v10/kernel/ptrace.c    2005/05/19 12:08:07     1.6
+++ linux/arch/cris/arch-v10/kernel/ptrace.c    2005/08/01 18:23:40     1.7
@@ -11,6 +11,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/signal.h>
+#include <linux/security.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -86,9 +87,13 @@
        ret = -EPERM;
        
        if (request == PTRACE_TRACEME) {
+               /* are we already being traced? */
                if (current->ptrace & PT_PTRACED)
                        goto out;
-
+               ret = security_ptrace(current->parent, current);
+               if (ret)
+                       goto out;
+               /* set the ptrace bit in the process flags. */
                current->ptrace |= PT_PTRACED;
                ret = 0;
                goto out;
@@ -207,7 +212,7 @@
                case PTRACE_KILL:
                        ret = 0;
                        
-                       if (child->state == TASK_ZOMBIE)
+                       if (child->exit_state == EXIT_ZOMBIE)
                                break;
                        
                        child->exit_code = SIGKILL;
diff -urN linux/arch/cris/arch-v10/kernel/shadows.c 
linux/arch/cris/arch-v10/kernel/shadows.c
--- linux/arch/cris/arch-v10/kernel/shadows.c   2003/07/11 02:13:09     1.1
+++ linux/arch/cris/arch-v10/kernel/shadows.c   2005/08/01 18:23:40     1.2
@@ -1,4 +1,4 @@
-/* $Id: shadows.c,v 1.1 2001/12/17 13:59:27 bjornw Exp $
+/* $Id: shadows.c,v 1.2 2004/12/13 12:21:51 starvik Exp $
  * 
  * Various shadow registers. Defines for these are in include/asm-etrax100/io.h
  */
@@ -6,6 +6,7 @@
 /* Shadows for internal Etrax-registers */
 
 unsigned long genconfig_shadow;
+unsigned long gen_config_ii_shadow;
 unsigned long port_g_data_shadow;
 unsigned char port_pa_dir_shadow;
 unsigned char port_pa_data_shadow;
diff -urN linux/arch/cris/arch-v10/kernel/traps.c 
linux/arch/cris/arch-v10/kernel/traps.c
--- linux/arch/cris/arch-v10/kernel/traps.c     2003/07/11 02:13:09     1.1
+++ linux/arch/cris/arch-v10/kernel/traps.c     2005/08/01 18:23:40     1.2
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.2 2003/07/04 08:27:41 starvik Exp $
+/* $Id: traps.c,v 1.4 2005/04/24 18:47:55 starvik Exp $
  *
  *  linux/arch/cris/arch-v10/traps.c
  *
@@ -16,6 +16,8 @@
 #include <asm/uaccess.h>
 #include <asm/arch/sv_addr_ag.h>
 
+extern int raw_printk(const char *fmt, ...);
+
 void 
 show_registers(struct pt_regs * regs)
 {
@@ -26,18 +28,18 @@
           register.  */
        unsigned long usp = rdusp();
 
-       printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n",
+       raw_printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n",
               regs->irp, regs->srp, regs->dccr, usp, regs->mof );
-       printk(" r0: %08lx  r1: %08lx   r2: %08lx  r3: %08lx\n",
+       raw_printk(" r0: %08lx  r1: %08lx   r2: %08lx  r3: %08lx\n",
               regs->r0, regs->r1, regs->r2, regs->r3);
-       printk(" r4: %08lx  r5: %08lx   r6: %08lx  r7: %08lx\n",
+       raw_printk(" r4: %08lx  r5: %08lx   r6: %08lx  r7: %08lx\n",
               regs->r4, regs->r5, regs->r6, regs->r7);
-       printk(" r8: %08lx  r9: %08lx  r10: %08lx r11: %08lx\n",
+       raw_printk(" r8: %08lx  r9: %08lx  r10: %08lx r11: %08lx\n",
               regs->r8, regs->r9, regs->r10, regs->r11);
-       printk("r12: %08lx r13: %08lx oR10: %08lx\n",
-              regs->r12, regs->r13, regs->orig_r10);
-       printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE);
-       printk("Process %s (pid: %d, stackpage=%08lx)\n",
+       raw_printk("r12: %08lx r13: %08lx oR10: %08lx  sp: %08lx\n",
+              regs->r12, regs->r13, regs->orig_r10, regs);
+       raw_printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE);
+       raw_printk("Process %s (pid: %d, stackpage=%08lx)\n",
               current->comm, current->pid, (unsigned long)current);
 
        /*
@@ -53,7 +55,7 @@
                if (usp != 0)
                        show_stack (NULL, NULL);
 
-                printk("\nCode: ");
+                raw_printk("\nCode: ");
                 if(regs->irp < PAGE_OFFSET)
                         goto bad;
 
@@ -70,16 +72,16 @@
                         unsigned char c;
                         if(__get_user(c, &((unsigned char*)regs->irp)[i])) {
 bad:
-                                printk(" Bad IP value.");
+                                raw_printk(" Bad IP value.");
                                 break;
                         }
 
                        if (i == 0)
-                         printk("(%02x) ", c);
+                         raw_printk("(%02x) ", c);
                        else
-                         printk("%02x ", c);
+                         raw_printk("%02x ", c);
                 }
-               printk("\n");
+               raw_printk("\n");
         }
 }
 
@@ -121,7 +123,7 @@
        stop_watchdog();
 #endif
 
-       printk("%s: %04lx\n", str, err & 0xffff);
+       raw_printk("%s: %04lx\n", str, err & 0xffff);
 
        show_registers(regs);
 
@@ -130,3 +132,8 @@
 #endif
        do_exit(SIGSEGV);
 }
+
+void arch_enable_nmi(void)
+{
+  asm volatile("setf m");
+}
diff -urN linux/arch/cris/arch-v10/mm/fault.c 
linux/arch/cris/arch-v10/mm/fault.c
--- linux/arch/cris/arch-v10/mm/fault.c 2004/11/15 11:49:15     1.3
+++ linux/arch/cris/arch-v10/mm/fault.c 2005/08/01 18:23:41     1.4
@@ -14,6 +14,7 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/arch/svinto.h>
+#include <asm/mmu_context.h>
 
 /* debug of low-level TLB reload */
 #undef DEBUG
@@ -24,8 +25,6 @@
 #define D(x)
 #endif
 
-extern volatile pgd_t *current_pgd;
-
 extern const struct exception_table_entry
        *search_exception_tables(unsigned long addr);
 
@@ -46,7 +45,7 @@
        int page_id;
        int acc, inv;
 #endif
-       pgd_t* pgd = (pgd_t*)current_pgd;
+       pgd_t* pgd = (pgd_t*)per_cpu(current_pgd, smp_processor_id());
        pmd_t *pmd;
        pte_t pte;
        int miss, we, writeac;
@@ -94,24 +93,3 @@
        *R_TLB_LO = pte_val(pte);
        local_irq_restore(flags);
 }
-
-/* Called from arch/cris/mm/fault.c to find fixup code. */
-int
-find_fixup_code(struct pt_regs *regs)
-{
-       const struct exception_table_entry *fixup;
-
-       if ((fixup = search_exception_tables(regs->irp)) != 0) {
-               /* Adjust the instruction pointer in the stackframe. */
-               regs->irp = fixup->fixup;
-               
-               /* 
-                * Don't return by restoring the CPU state, so switch
-                * frame-type. 
-                */
-               regs->frametype = CRIS_FRAME_NORMAL;
-               return 1;
-       }
-
-       return 0;
-}
diff -urN linux/arch/cris/arch-v10/mm/init.c linux/arch/cris/arch-v10/mm/init.c
--- linux/arch/cris/arch-v10/mm/init.c  2005/03/18 17:36:48     1.3
+++ linux/arch/cris/arch-v10/mm/init.c  2005/08/01 18:23:41     1.4
@@ -42,7 +42,7 @@
         *  switch_mm)
         */
 
-       current_pgd = init_mm.pgd;
+       per_cpu(current_pgd, smp_processor_id()) = init_mm.pgd;
 
        /* initialise the TLB (tlb.c) */
 
diff -urN linux/arch/cris/arch-v10/mm/tlb.c linux/arch/cris/arch-v10/mm/tlb.c
--- linux/arch/cris/arch-v10/mm/tlb.c   2004/11/15 11:49:15     1.3
+++ linux/arch/cris/arch-v10/mm/tlb.c   2005/08/01 18:23:41     1.4
@@ -139,53 +139,6 @@
        local_irq_restore(flags);
 }
 
-/* invalidate a page range */
-
-void
-flush_tlb_range(struct vm_area_struct *vma, 
-               unsigned long start,
-               unsigned long end)
-{
-       struct mm_struct *mm = vma->vm_mm;
-       int page_id = mm->context.page_id;
-       int i;
-       unsigned long flags;
-
-       D(printk("tlb: flush range %p<->%p in context %d (%p)\n",
-                start, end, page_id, mm));
-
-       if(page_id == NO_CONTEXT)
-               return;
-
-       start &= PAGE_MASK;  /* probably not necessary */
-       end &= PAGE_MASK;    /* dito */
-
-       /* invalidate those TLB entries that match both the mm context
-        * and the virtual address range
-        */
-
-       local_save_flags(flags);
-       local_irq_disable();
-       for(i = 0; i < NUM_TLB_ENTRIES; i++) {
-               unsigned long tlb_hi, vpn;
-               *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
-               tlb_hi = *R_TLB_HI;
-               vpn = tlb_hi & PAGE_MASK;
-               if (IO_EXTRACT(R_TLB_HI, page_id, tlb_hi) == page_id &&
-                   vpn >= start && vpn < end) {
-                       *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, 
INVALID_PAGEID ) |
-                                     IO_FIELD(R_TLB_HI, vpn,     i & 0xf ) );
-                       
-                       *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no  ) |
-                                     IO_STATE(R_TLB_LO, valid, no  ) |
-                                     IO_STATE(R_TLB_LO, kernel,no  ) |
-                                     IO_STATE(R_TLB_LO, we,    no  ) |
-                                     IO_FIELD(R_TLB_LO, pfn,   0   ) );
-               }
-       }
-       local_irq_restore(flags);
-}
-
 /* dump the entire TLB for debug purposes */
 
 #if 0
@@ -237,7 +190,7 @@
         * the pgd.
         */
 
-       current_pgd = next->pgd;
+       per_cpu(current_pgd, smp_processor_id()) = next->pgd;
 
        /* switch context in the MMU */
        
diff -urN linux/arch/cris/arch-v32/Kconfig linux/arch/cris/arch-v32/Kconfig
--- linux/arch/cris/arch-v32/Kconfig    1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/Kconfig    2005-08-01 19:23:41.384845000 +0100     
1.1
@@ -0,0 +1,296 @@
+config ETRAX_DRAM_VIRTUAL_BASE
+       hex
+       depends on ETRAX_ARCH_V32
+       default "c0000000"
+
+config ETRAX_LED1G
+       string "First green LED bit"
+       depends on ETRAX_ARCH_V32
+       default "PA3"
+       help
+         Bit to use for the first green LED (network LED).
+         Most Axis products use bit A3 here.
+
+config ETRAX_LED1R
+       string "First red LED bit"
+       depends on ETRAX_ARCH_V32
+       default "PA4"
+       help
+         Bit to use for the first red LED (network LED).
+         Most Axis products use bit A4 here.
+
+config ETRAX_LED2G
+       string "Second green LED bit"
+       depends on ETRAX_ARCH_V32
+       default "PA5"
+       help
+         Bit to use for the first green LED (status LED).
+         Most Axis products use bit A5 here.
+
+config ETRAX_LED2R
+       string "Second red LED bit"
+       depends on ETRAX_ARCH_V32
+       default "PA6"
+       help
+         Bit to use for the first red LED (network LED).
+         Most Axis products use bit A6 here.
+
+config ETRAX_LED3G
+       string "Third green LED bit"
+       depends on ETRAX_ARCH_V32
+       default "PA7"
+       help
+         Bit to use for the first green LED (drive/power LED).
+         Most Axis products use bit A7 here.
+
+config ETRAX_LED3R
+       string "Third red LED bit"
+       depends on ETRAX_ARCH_V32
+       default "PA7"
+       help
+         Bit to use for the first red LED (drive/power LED).
+         Most Axis products use bit A7 here.
+
+choice
+       prompt "Product debug-port"
+       depends on ETRAX_ARCH_V32
+       default ETRAX_DEBUG_PORT0
+
+config ETRAX_DEBUG_PORT0
+       bool "Serial-0"
+       help
+         Choose a serial port for the ETRAX debug console.  Default to
+         port 0.
+
+config ETRAX_DEBUG_PORT1
+       bool "Serial-1"
+       help
+         Use serial port 1 for the console.
+
+config ETRAX_DEBUG_PORT2
+       bool "Serial-2"
+       help
+         Use serial port 2 for the console.
+
+config ETRAX_DEBUG_PORT3
+       bool "Serial-3"
+       help
+         Use serial port 3 for the console.
+
+config ETRAX_DEBUG_PORT_NULL
+       bool "disabled"
+       help
+         Disable serial-port debugging.
+
+endchoice
+
+choice
+       prompt "Kernel GDB port"
+       depends on ETRAX_KGDB
+       default ETRAX_KGDB_PORT0
+       help
+         Choose a serial port for kernel debugging.  NOTE: This port should
+         not be enabled under Drivers for built-in interfaces (as it has its
+         own initialization code) and should not be the same as the debug port.
+
+config ETRAX_KGDB_PORT0
+       bool "Serial-0"
+       help
+         Use serial port 0 for kernel debugging.
+
+config ETRAX_KGDB_PORT1
+       bool "Serial-1"
+       help
+         Use serial port 1 for kernel debugging.
+
+config ETRAX_KGDB_PORT2
+       bool "Serial-2"
+       help
+         Use serial port 2 for kernel debugging.
+
+config ETRAX_KGDB_PORT3
+       bool "Serial-3"
+       help
+         Use serial port 3 for kernel debugging.
+
+endchoice
+
+config ETRAX_MEM_GRP1_CONFIG
+       hex "MEM_GRP1_CONFIG"
+       depends on ETRAX_ARCH_V32
+       default "4044a"
+       help
+         Waitstates for flash. The default value is suitable for the
+         standard flashes used in axis products (120 ns).
+
+config ETRAX_MEM_GRP2_CONFIG
+       hex "MEM_GRP2_CONFIG"
+       depends on ETRAX_ARCH_V32
+       default "0"
+       help
+         Waitstates for SRAM. 0 is a good choice for most Axis products.
+
+config ETRAX_MEM_GRP3_CONFIG
+       hex "MEM_GRP3_CONFIG"
+       depends on ETRAX_ARCH_V32
+       default "0"
+       help
+         Waitstates for CSP0-3. 0 is a good choice for most Axis products.
+         It may need to be changed if external devices such as extra
+         register-mapped LEDs are used.
+
+config ETRAX_MEM_GRP4_CONFIG
+       hex "MEM_GRP4_CONFIG"
+       depends on ETRAX_ARCH_V32
+       default "0"
+       help
+         Waitstates for CSP4-6. 0 is a good choice for most Axis products.
+
+config ETRAX_SDRAM_GRP0_CONFIG
+       hex "SDRAM_GRP0_CONFIG"
+       depends on ETRAX_ARCH_V32
+       default "336"
+       help
+         SDRAM configuration for group 0. The value depends on the
+         hardware configuration. The default value is suitable
+         for 32 MB organized as two 16 bits chips (e.g. Axis
+         part number 18550) connected as one 32 bit device (i.e. in
+         the same group).
+
+config ETRAX_SDRAM_GRP1_CONFIG
+       hex "SDRAM_GRP1_CONFIG"
+       depends on ETRAX_ARCH_V32
+       default "0"
+       help
+         SDRAM configuration for group 1. The defult value is 0
+         because group 1 is not used in the default configuration,
+         described in the help for SDRAM_GRP0_CONFIG.
+
+config ETRAX_SDRAM_TIMING
+       hex "SDRAM_TIMING"
+       depends on ETRAX_ARCH_V32
+       default "104a"
+       help
+         SDRAM timing parameters. The default value is ok for
+         most hardwares but large SDRAMs may require a faster
+         refresh (a.k.a 8K refresh). The default value implies
+         100MHz clock and SDR mode.
+
+config ETRAX_SDRAM_COMMAND
+       hex "SDRAM_COMMAND"
+       depends on ETRAX_ARCH_V32
+       default "0"
+       help
+         SDRAM command. Should be 0 unless you really know what
+         you are doing (may be != 0 for unusual address line
+         mappings such as in a MCM)..
+
+config ETRAX_DEF_GIO_PA_OE
+       hex "GIO_PA_OE"
+       depends on ETRAX_ARCH_V32
+       default "1c"
+       help
+         Configures the direction of general port A bits.  1 is out, 0 is in.
+         This is often totally different depending on the product used.
+         There are some guidelines though - if you know that only LED's are
+         connected to port PA, then they are usually connected to bits 2-4
+         and you can therefore use 1c.  On other boards which don't have the
+         LED's at the general ports, these bits are used for all kinds of
+         stuff.  If you don't know what to use, it is always safe to put all
+         as inputs, although floating inputs isn't good.
+
+config ETRAX_DEF_GIO_PA_OUT
+       hex "GIO_PA_OUT"
+       depends on ETRAX_ARCH_V32
+       default "00"
+       help
+         Configures the initial data for the general port A bits.  Most
+         products should use 00 here.
+
+config ETRAX_DEF_GIO_PB_OE
+       hex "GIO_PB_OE"
+       depends on ETRAX_ARCH_V32
+       default "00000"
+       help
+         Configures the direction of general port B bits.  1 is out, 0 is in.
+         This is often totally different depending on the product used.
+         There are some guidelines though - if you know that only LED's are
+         connected to port PA, then they are usually connected to bits 2-4
+         and you can therefore use 1c.  On other boards which don't have the
+         LED's at the general ports, these bits are used for all kinds of
+         stuff.  If you don't know what to use, it is always safe to put all
+         as inputs, although floating inputs isn't good.
+
+config ETRAX_DEF_GIO_PB_OUT
+       hex "GIO_PB_OUT"
+       depends on ETRAX_ARCH_V32
+       default "00000"
+       help
+         Configures the initial data for the general port B bits.  Most
+         products should use 00000 here.
+
+config ETRAX_DEF_GIO_PC_OE
+       hex "GIO_PC_OE"
+       depends on ETRAX_ARCH_V32
+       default "00000"
+       help
+         Configures the direction of general port C bits.  1 is out, 0 is in.
+         This is often totally different depending on the product used.
+         There are some guidelines though - if you know that only LED's are
+         connected to port PA, then they are usually connected to bits 2-4
+         and you can therefore use 1c.  On other boards which don't have the
+         LED's at the general ports, these bits are used for all kinds of
+         stuff.  If you don't know what to use, it is always safe to put all
+         as inputs, although floating inputs isn't good.
+
+config ETRAX_DEF_GIO_PC_OUT
+       hex "GIO_PC_OUT"
+       depends on ETRAX_ARCH_V32
+       default "00000"
+       help
+         Configures the initial data for the general port C bits.  Most
+         products should use 00000 here.
+
+config ETRAX_DEF_GIO_PD_OE
+       hex "GIO_PD_OE"
+       depends on ETRAX_ARCH_V32
+       default "00000"
+       help
+         Configures the direction of general port D bits.  1 is out, 0 is in.
+         This is often totally different depending on the product used.
+         There are some guidelines though - if you know that only LED's are
+         connected to port PA, then they are usually connected to bits 2-4
+         and you can therefore use 1c.  On other boards which don't have the
+         LED's at the general ports, these bits are used for all kinds of
+         stuff.  If you don't know what to use, it is always safe to put all
+         as inputs, although floating inputs isn't good.
+
+config ETRAX_DEF_GIO_PD_OUT
+       hex "GIO_PD_OUT"
+       depends on ETRAX_ARCH_V32
+       default "00000"
+       help
+         Configures the initial data for the general port D bits.  Most
+         products should use 00000 here.
+
+config ETRAX_DEF_GIO_PE_OE
+       hex "GIO_PE_OE"
+       depends on ETRAX_ARCH_V32
+       default "00000"
+       help
+         Configures the direction of general port E bits.  1 is out, 0 is in.
+         This is often totally different depending on the product used.
+         There are some guidelines though - if you know that only LED's are
+         connected to port PA, then they are usually connected to bits 2-4
+         and you can therefore use 1c.  On other boards which don't have the
+         LED's at the general ports, these bits are used for all kinds of
+         stuff.  If you don't know what to use, it is always safe to put all
+         as inputs, although floating inputs isn't good.
+
+config ETRAX_DEF_GIO_PE_OUT
+       hex "GIO_PE_OUT"
+       depends on ETRAX_ARCH_V32
+       default "00000"
+       help
+         Configures the initial data for the general port E bits.  Most
+         products should use 00000 here.
diff -urN linux/arch/cris/arch-v32/output_arch.ld 
linux/arch/cris/arch-v32/output_arch.ld
--- linux/arch/cris/arch-v32/output_arch.ld     1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/output_arch.ld     2005-08-01 19:23:41.411550000 
+0100     1.1
@@ -0,0 +1,2 @@
+/* At the time of this writing, there's no equivalent ld option. */
+OUTPUT_ARCH (crisv32)
diff -urN linux/arch/cris/arch-v32/vmlinux.lds.S 
linux/arch/cris/arch-v32/vmlinux.lds.S
--- linux/arch/cris/arch-v32/vmlinux.lds.S      1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/vmlinux.lds.S      2005-08-01 19:23:41.431631000 
+0100     1.1
@@ -0,0 +1,134 @@
+/* ld script to make the Linux/CRIS kernel
+ * Authors: Bjorn Wesen (bjornw@axis.com)
+ *
+ * It is VERY DANGEROUS to fiddle around with the symbols in this
+ * script. It is for example quite vital that all generated sections
+ * that are used are actually named here, otherwise the linker will
+ * put them at the end, where the init stuff is which is FREED after
+ * the kernel has booted.
+ */
+
+#include <linux/config.h>
+#include <asm-generic/vmlinux.lds.h>
+
+jiffies = jiffies_64;
+SECTIONS
+{
+       . = DRAM_VIRTUAL_BASE;
+       dram_start = .;
+       ebp_start = .;
+
+       /* The boot section is only necessary until the VCS top level testbench 
*/
+       /* includes both flash and DRAM. */
+       .boot : { *(.boot) }
+
+       . = DRAM_VIRTUAL_BASE + 0x4000;         /* See head.S and pages 
reserved at the start. */
+
+       _text = .;              /* Text and read-only data. */
+       text_start = .;         /* Lots of aliases. */
+       _stext = .;
+       __stext = .;
+       .text : {
+               *(.text)
+               SCHED_TEXT
+               LOCK_TEXT
+               *(.fixup)
+               *(.text.__*)
+       }
+
+       _etext = . ;            /* End of text section. */
+       __etext = .;
+
+       . = ALIGN(4);           /* Exception table. */
+       __start___ex_table = .;
+       __ex_table : { *(__ex_table) }
+       __stop___ex_table = .;
+
+       RODATA
+
+       . = ALIGN (4);
+       ___data_start = . ;
+       __Sdata = . ;
+       .data : {                     /* Data */
+               *(.data)
+       }
+       __edata = . ;           /* End of data section. */
+       _edata = . ;
+
+       . = ALIGN(8192);        /* init_task and stack, must be aligned. */
+       .data.init_task : { *(.data.init_task) }
+
+       . = ALIGN(8192);        /* Init code and data. */
+       __init_begin = .;
+       .init.text : {
+                  _sinittext = .;
+                  *(.init.text)
+                  _einittext = .;
+       }
+       .init.data : { *(.init.data) }
+       . = ALIGN(16);
+       __setup_start = .;
+       .init.setup : { *(.init.setup) }
+       __setup_end = .;
+       __start___param = .;
+       __param : { *(__param) }
+       __stop___param = .;
+       .initcall.init : {
+               __initcall_start = .;
+               *(.initcall1.init);
+               *(.initcall2.init);
+               *(.initcall3.init);
+               *(.initcall4.init);
+               *(.initcall5.init);
+               *(.initcall6.init);
+               *(.initcall7.init);
+               __initcall_end = .;
+       }
+
+       .con_initcall.init : {
+               __con_initcall_start = .;
+               *(.con_initcall.init)
+               __con_initcall_end = .;
+       }
+       SECURITY_INIT
+
+       __per_cpu_start = .;
+       .data.percpu  : { *(.data.percpu) }
+       __per_cpu_end = .;
+
+       .init.ramfs : {
+               __initramfs_start = .;
+               *(.init.ramfs)
+               __initramfs_end = .;
+               /*
+                * We fill to the next page, so we can discard all init
+                * pages without needing to consider what payload might be
+                * appended to the kernel image.
+                */
+               FILL (0);
+               . = ALIGN (8192);
+       }
+
+       __vmlinux_end = .;      /* Last address of the physical file. */
+       __init_end = .;
+
+       __data_end = . ;        /* Move to _edata? */
+       __bss_start = .;        /* BSS. */
+       .bss : {
+               *(COMMON)
+               *(.bss)
+       }
+
+       . =  ALIGN (0x20);
+       _end = .;
+       __end = .;
+
+       /* Sections to be discarded */
+       /DISCARD/ : {
+               *(.text.exit)
+               *(.data.exit)
+               *(.exitcall.exit)
+        }
+
+       dram_end = dram_start + CONFIG_ETRAX_DRAM_SIZE*1024*1024;
+}
diff -urN linux/arch/cris/arch-v32/boot/Makefile 
linux/arch/cris/arch-v32/boot/Makefile
--- linux/arch/cris/arch-v32/boot/Makefile      1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/boot/Makefile      2005-08-01 19:23:41.560694000 
+0100     1.1
@@ -0,0 +1,14 @@
+#
+# arch/cris/arch-v32/boot/Makefile
+#
+target = $(target_boot_dir)
+src    = $(src_boot_dir)
+
+zImage: compressed/vmlinuz
+
+compressed/vmlinuz: $(objtree)/vmlinux
+       @$(MAKE) -f $(src)/compressed/Makefile $(objtree)/vmlinuz
+
+clean:
+       rm -f zImage tools/build compressed/vmlinux.out
+       @$(MAKE) -f $(src)/compressed/Makefile clean
diff -urN linux/arch/cris/arch-v32/boot/compressed/Makefile 
linux/arch/cris/arch-v32/boot/compressed/Makefile
--- linux/arch/cris/arch-v32/boot/compressed/Makefile   1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/boot/compressed/Makefile   2005-08-01 
19:23:41.691711000 +0100     1.1
@@ -0,0 +1,41 @@
+#
+# lx25/arch/cris/arch-v32/boot/compressed/Makefile
+#
+# create a compressed vmlinux image from the original vmlinux files and romfs
+#
+
+target = $(target_compressed_dir)
+src    = $(src_compressed_dir)
+
+CC = gcc-cris -mlinux -march=v32 -I $(TOPDIR)/include
+CFLAGS = -O2
+LD = gcc-cris -mlinux -march=v32 -nostdlib
+OBJCOPY = objcopy-cris
+OBJCOPYFLAGS = -O binary --remove-section=.bss
+OBJECTS = $(target)/head.o $(target)/misc.o
+
+# files to compress
+SYSTEM = $(objtree)/vmlinux.bin
+
+all: vmlinuz
+
+$(target)/decompress.bin: $(OBJECTS)
+       $(LD) -T $(src)/decompress.ld -o $(target)/decompress.o $(OBJECTS)
+       $(OBJCOPY) $(OBJCOPYFLAGS) $(target)/decompress.o 
$(target)/decompress.bin
+
+$(objtree)/vmlinuz: $(target) piggy.img $(target)/decompress.bin
+       cat $(target)/decompress.bin piggy.img > $(objtree)/vmlinuz
+       rm -f piggy.img
+       cp $(objtree)/vmlinuz $(src)
+
+$(target)/head.o: $(src)/head.S
+       $(CC) -D__ASSEMBLY__ -c $< -o $@
+
+# gzip the kernel image
+
+piggy.img: $(SYSTEM)
+       cat $(SYSTEM) | gzip -f -9 > piggy.img
+
+clean:
+       rm -f piggy.img $(objtree)/vmlinuz vmlinuz.o decompress.o 
decompress.bin $(OBJECTS)
+
diff -urN linux/arch/cris/arch-v32/boot/compressed/README 
linux/arch/cris/arch-v32/boot/compressed/README
--- linux/arch/cris/arch-v32/boot/compressed/README     1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/boot/compressed/README     2005-08-01 
19:23:41.718506000 +0100     1.1
@@ -0,0 +1,25 @@
+Creation of the self-extracting compressed kernel image (vmlinuz)
+-----------------------------------------------------------------
+$Id: README,v 1.1 2003/08/21 09:37:03 johana Exp $
+
+This can be slightly confusing because it's a process with many steps.
+
+The kernel object built by the arch/etrax100/Makefile, vmlinux, is split
+by that makefile into text and data binary files, vmlinux.text and
+vmlinux.data.
+
+Those files together with a ROM filesystem can be catted together and
+burned into a flash or executed directly at the DRAM origin.
+
+They can also be catted together and compressed with gzip, which is what
+happens in this makefile. Together they make up piggy.img.
+
+The decompressor is built into the file decompress.o. It is turned into
+the binary file decompress.bin, which is catted together with piggy.img
+into the file vmlinuz. It can be executed in an arbitrary place in flash.
+
+Be careful - it assumes some things about free locations in DRAM. It
+assumes the DRAM starts at 0x40000000 and that it is at least 8 MB,
+so it puts its code at 0x40700000, and initial stack at 0x40800000.
+
+-Bjorn
diff -urN linux/arch/cris/arch-v32/boot/compressed/decompress.ld 
linux/arch/cris/arch-v32/boot/compressed/decompress.ld
--- linux/arch/cris/arch-v32/boot/compressed/decompress.ld      1970/01/01 
00:00:00
+++ linux/arch/cris/arch-v32/boot/compressed/decompress.ld      2005-08-01 
19:23:41.742138000 +0100     1.1
@@ -0,0 +1,30 @@
+/*#OUTPUT_FORMAT(elf32-us-cris) */
+OUTPUT_ARCH (crisv32)
+
+MEMORY
+       {
+       dram : ORIGIN = 0x40700000,
+              LENGTH = 0x00100000
+       }
+
+SECTIONS
+{
+       .text :
+       {
+               _stext = . ;
+               *(.text)
+               *(.rodata)
+               *(.rodata.*)
+               _etext = . ;
+       } > dram
+       .data :
+       {
+               *(.data)
+               _edata = . ;
+       } > dram
+       .bss :
+       {
+               *(.bss)
+               _end = ALIGN( 0x10 ) ;
+       } > dram
+}
diff -urN linux/arch/cris/arch-v32/boot/compressed/head.S 
linux/arch/cris/arch-v32/boot/compressed/head.S
--- linux/arch/cris/arch-v32/boot/compressed/head.S     1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/boot/compressed/head.S     2005-08-01 
19:23:41.757698000 +0100     1.1
@@ -0,0 +1,193 @@
+/*
+ *  Code that sets up the DRAM registers, calls the
+ *  decompressor to unpack the piggybacked kernel, and jumps.
+ *
+ *  Copyright (C) 1999 - 2003, Axis Communications AB
+ */
+
+#include <linux/config.h>
+#define ASSEMBLER_MACROS_ONLY
+#include <asm/arch/hwregs/asm/reg_map_asm.h>
+#include <asm/arch/hwregs/asm/gio_defs_asm.h>
+#include <asm/arch/hwregs/asm/config_defs_asm.h>
+
+#define RAM_INIT_MAGIC 0x56902387
+#define COMMAND_LINE_MAGIC 0x87109563
+
+       ;; Exported symbols
+
+       .globl  input_data
+
+       .text
+start:
+       di
+
+       ;; Start clocks for used blocks.
+       move.d REG_ADDR(config, regi_config, rw_clk_ctrl), $r1
+       move.d [$r1], $r0
+       or.d   REG_STATE(config, rw_clk_ctrl, cpu, yes) | \
+              REG_STATE(config, rw_clk_ctrl, bif, yes) | \
+              REG_STATE(config, rw_clk_ctrl, fix_io, yes), $r0
+       move.d $r0, [$r1]
+
+       ;; If booting from NAND flash we first have to copy some
+       ;; data from NAND flash to internal RAM to get the code
+       ;; that initializes the SDRAM. Lets copy 20 KB. This
+       ;; code executes at 0x38010000 if booting from NAND and
+       ;; we are guaranted that at least 0x200 bytes are good so
+       ;; lets start from there. The first 8192 bytes in the nand
+       ;; flash is spliced with zeroes and is thus 16384 bytes.
+       move.d 0x38010200, $r10
+       move.d 0x14200, $r11    ; Start offset in NAND flash 0x10200 + 16384
+       move.d 0x5000, $r12     ; Length of copy
+
+       ;; Before this code the tools add a partitiontable so the PC
+       ;; has an offset from the linked address.
+offset1:
+       lapcq  ., $r13          ; get PC
+       add.d   first_copy_complete-offset1, $r13
+
+#include "../../lib/nand_init.S"
+
+first_copy_complete:
+       ;; Initialze the DRAM registers.
+       cmp.d   RAM_INIT_MAGIC, $r8     ; Already initialized?
+       beq     dram_init_finished
+       nop
+
+#include "../../lib/dram_init.S"
+
+dram_init_finished:
+       lapcq  ., $r13          ; get PC
+       add.d   second_copy_complete-dram_init_finished, $r13
+
+       move.d REG_ADDR(config, regi_config, r_bootsel), $r0
+       move.d [$r0], $r0
+       and.d  REG_MASK(config, r_bootsel, boot_mode), $r0
+       cmp.d  REG_STATE(config, r_bootsel, boot_mode, nand), $r0
+       bne second_copy_complete ; No NAND boot
+       nop
+
+       ;; Copy 2MB from NAND flash to SDRAM (at 2-4MB into the SDRAM)
+       move.d 0x40204000, $r10
+       move.d 0x8000, $r11
+       move.d 0x200000, $r12
+       ba copy_nand_to_ram
+       nop
+second_copy_complete:
+
+       ;; Initiate the PA port.
+       move.d  CONFIG_ETRAX_DEF_GIO_PA_OUT, $r0
+       move.d  REG_ADDR(gio, regi_gio, rw_pa_dout), $r1
+       move.d  $r0, [$r1]
+
+       move.d  CONFIG_ETRAX_DEF_GIO_PA_OE, $r0
+       move.d  REG_ADDR(gio, regi_gio, rw_pa_oe), $r1
+       move.d  $r0, [$r1]
+
+       ;; Setup the stack to a suitably high address.
+       ;; We assume 8 MB is the minimum DRAM and put
+       ;; the SP at the top for now.
+
+       move.d  0x40800000, $sp
+
+       ;; Figure out where the compressed piggyback image is
+       ;; in the flash (since we wont try to copy it to DRAM
+       ;; before unpacking). It is at _edata, but in flash.
+       ;; Use (_edata - herami) as offset to the current PC.
+
+       move.d REG_ADDR(config, regi_config, r_bootsel), $r0
+       move.d [$r0], $r0
+       and.d  REG_MASK(config, r_bootsel, boot_mode), $r0
+       cmp.d  REG_STATE(config, r_bootsel, boot_mode, nand), $r0
+       beq hereami2
+       nop
+hereami:
+       lapcq   ., $r5          ; get PC
+       and.d   0x7fffffff, $r5 ; strip any non-cache bit
+       move.d  $r5, $r0        ; save for later - flash address of 'herami'
+       add.d   _edata, $r5
+       sub.d   hereami, $r5    ; r5 = flash address of '_edata'
+       move.d  hereami, $r1    ; destination
+       ba 2f
+       nop
+hereami2:
+       lapcq   ., $r5          ; get PC
+       and.d   0x00ffffff, $r5 ; strip any non-cache bit
+       move.d  $r5, $r6
+       or.d    0x40200000, $r6
+       move.d  $r6, $r0        ; save for later - flash address of 'herami'
+       add.d   _edata, $r5
+       sub.d   hereami2, $r5   ; r5 = flash address of '_edata'
+       add.d   0x40200000, $r5
+       move.d  hereami2, $r1   ; destination
+2:
+       ;; Copy text+data to DRAM
+
+       move.d  _edata, $r2     ; end destination
+1:     move.w  [$r0+], $r3
+       move.w  $r3, [$r1+]
+       cmp.d   $r2, $r1
+       bcs     1b
+       nop
+
+       move.d  input_data, $r0 ; for the decompressor
+       move.d  $r5, [$r0]      ; for the decompressor
+
+       ;; Clear the decompressors BSS (between _edata and _end)
+
+       moveq   0, $r0
+       move.d  _edata, $r1
+       move.d  _end, $r2
+1:     move.w  $r0, [$r1+]
+       cmp.d   $r2, $r1
+       bcs     1b
+       nop
+
+       ;;  Save command line magic and address.
+       move.d  _cmd_line_magic, $r12
+       move.d  $r10, [$r12]
+       move.d  _cmd_line_addr, $r12
+       move.d  $r11, [$r12]
+
+       ;; Do the decompression and save compressed size in _inptr
+
+       jsr     decompress_kernel
+       nop
+
+       ;; Restore command line magic and address.
+       move.d  _cmd_line_magic, $r10
+       move.d  [$r10], $r10
+       move.d  _cmd_line_addr, $r11
+       move.d  [$r11], $r11
+
+       ;; Put start address of root partition in r9 so the kernel can use it
+       ;; when mounting from flash
+       move.d  input_data, $r0
+       move.d  [$r0], $r9              ; flash address of compressed kernel
+       move.d  inptr, $r0
+       add.d   [$r0], $r9              ; size of compressed kernel
+       cmp.d   0x40200000, $r9
+       blo     enter_kernel
+       nop
+       sub.d   0x40200000, $r9
+       add.d   0x4000, $r9
+
+enter_kernel:
+       ;; Enter the decompressed kernel
+       move.d  RAM_INIT_MAGIC, $r8     ; Tell kernel that DRAM is initialized
+       jump    0x40004000      ; kernel is linked to this address
+       nop
+
+       .data
+
+input_data:
+       .dword  0               ; used by the decompressor
+_cmd_line_magic:
+       .dword 0
+_cmd_line_addr:
+       .dword 0
+is_nand_boot:
+       .dword  0
+
+#include "../../lib/hw_settings.S"
diff -urN linux/arch/cris/arch-v32/boot/compressed/misc.c 
linux/arch/cris/arch-v32/boot/compressed/misc.c
--- linux/arch/cris/arch-v32/boot/compressed/misc.c     1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/boot/compressed/misc.c     2005-08-01 
19:23:41.784409000 +0100     1.1
@@ -0,0 +1,318 @@
+/*
+ * misc.c
+ *
+ * $Id: misc.c,v 1.8 2005/04/24 18:34:29 starvik Exp $
+ *
+ * This is a collection of several routines from gzip-1.0.3
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ * puts by Nick Holloway 1993, better puts by Martin Mares 1995
+ * adoptation for Linux/CRIS Axis Communications AB, 1999
+ *
+ */
+
+/* where the piggybacked kernel image expects itself to live.
+ * it is the same address we use when we network load an uncompressed
+ * image into DRAM, and it is the address the kernel is linked to live
+ * at by vmlinux.lds.S
+ */
+
+#define KERNEL_LOAD_ADR 0x40004000
+
+#include <linux/config.h>
+
+#include <linux/types.h>
+#include <asm/arch/hwregs/reg_rdwr.h>
+#include <asm/arch/hwregs/reg_map.h>
+#include <asm/arch/hwregs/ser_defs.h>
+
+/*
+ * gzip declarations
+ */
+
+#define OF(args)  args
+#define STATIC static
+
+void* memset(void* s, int c, size_t n);
+void* memcpy(void* __dest, __const void* __src,
+            size_t __n);
+
+#define memzero(s, n)     memset ((s), 0, (n))
+
+
+typedef unsigned char  uch;
+typedef unsigned short ush;
+typedef unsigned long  ulg;
+
+#define WSIZE 0x8000           /* Window size must be at least 32k, */
+                               /* and a power of two */
+
+static uch *inbuf;          /* input buffer */
+static uch window[WSIZE];    /* Sliding window buffer */
+
+unsigned inptr = 0;    /* index of next byte to be processed in inbuf
+                        * After decompression it will contain the
+                        * compressed size, and head.S will read it.
+                        */
+
+static unsigned outcnt = 0;  /* bytes in output buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
+#define RESERVED     0xC0 /* bit 6,7:   reserved */
+
+#define get_byte() inbuf[inptr++]
+
+/* Diagnostic functions */
+#ifdef DEBUG
+#  define Assert(cond,msg) {if(!(cond)) error(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+static int  fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+extern char *input_data;  /* lives in head.S */
+
+static long bytes_out = 0;
+static uch *output_data;
+static unsigned long output_ptr = 0;
+
+static void *malloc(int size);
+static void free(void *where);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+static void puts(const char *);
+
+/* the "heap" is put directly after the BSS ends, at end */
+
+extern int _end;
+static long free_mem_ptr = (long)&_end;
+
+#include "../../../../../lib/inflate.c"
+
+static void *malloc(int size)
+{
+       void *p;
+
+       if (size <0) error("Malloc error");
+
+       free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
+
+       p = (void *)free_mem_ptr;
+       free_mem_ptr += size;
+
+       return p;
+}
+
+static void free(void *where)
+{      /* Don't care */
+}
+
+static void gzip_mark(void **ptr)
+{
+       *ptr = (void *) free_mem_ptr;
+}
+
+static void gzip_release(void **ptr)
+{
+       free_mem_ptr = (long) *ptr;
+}
+
+/* decompressor info and error messages to serial console */
+
+static inline void
+serout(const char *s, reg_scope_instances regi_ser)
+{
+       reg_ser_rs_stat_din rs;
+       reg_ser_rw_dout dout = {.data = *s};
+
+       do {
+               rs = REG_RD(ser, regi_ser, rs_stat_din);
+       }
+       while (!rs.tr_rdy);/* Wait for tranceiver. */
+
+       REG_WR(ser, regi_ser, rw_dout, dout);
+}
+
+static void
+puts(const char *s)
+{
+#ifndef CONFIG_ETRAX_DEBUG_PORT_NULL
+       while (*s) {
+#ifdef CONFIG_ETRAX_DEBUG_PORT0
+               serout(s, regi_ser0);
+#endif
+#ifdef CONFIG_ETRAX_DEBUG_PORT1
+               serout(s, regi_ser1);
+#endif
+#ifdef CONFIG_ETRAX_DEBUG_PORT2
+               serout(s, regi_ser2);
+#endif
+#ifdef CONFIG_ETRAX_DEBUG_PORT3
+               serout(s, regi_ser3);
+#endif
+               *s++;
+       }
+/* CONFIG_ETRAX_DEBUG_PORT_NULL */
+#endif
+}
+
+void*
+memset(void* s, int c, size_t n)
+{
+       int i;
+       char *ss = (char*)s;
+
+       for (i=0;i<n;i++) ss[i] = c;
+}
+
+void*
+memcpy(void* __dest, __const void* __src,
+                           size_t __n)
+{
+       int i;
+       char *d = (char *)__dest, *s = (char *)__src;
+
+       for (i=0;i<__n;i++) d[i] = s[i];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+
+static void
+flush_window()
+{
+    ulg c = crc;         /* temporary variable */
+    unsigned n;
+    uch *in, *out, ch;
+
+    in = window;
+    out = &output_data[output_ptr];
+    for (n = 0; n < outcnt; n++) {
+           ch = *out++ = *in++;
+           c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+    }
+    crc = c;
+    bytes_out += (ulg)outcnt;
+    output_ptr += (ulg)outcnt;
+    outcnt = 0;
+}
+
+static void
+error(char *x)
+{
+       puts("\n\n");
+       puts(x);
+       puts("\n\n -- System halted\n");
+
+       while(1);       /* Halt */
+}
+
+void
+setup_normal_output_buffer()
+{
+       output_data = (char *)KERNEL_LOAD_ADR;
+}
+
+static inline void
+serial_setup(reg_scope_instances regi_ser)
+{
+       reg_ser_rw_xoff xoff;
+       reg_ser_rw_tr_ctrl tr_ctrl;
+       reg_ser_rw_rec_ctrl rec_ctrl;
+       reg_ser_rw_tr_baud_div tr_baud;
+       reg_ser_rw_rec_baud_div rec_baud;
+
+       /* Turn off XOFF. */
+       xoff = REG_RD(ser, regi_ser, rw_xoff);
+
+       xoff.chr = 0;
+       xoff.automatic = regk_ser_no;
+
+       REG_WR(ser, regi_ser, rw_xoff, xoff);
+
+       /* Set baudrate and stopbits. */
+       tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
+       rec_ctrl = REG_RD(ser, regi_ser, rw_rec_ctrl);
+       tr_baud = REG_RD(ser, regi_ser, rw_tr_baud_div);
+       rec_baud = REG_RD(ser, regi_ser, rw_rec_baud_div);
+
+       tr_ctrl.stop_bits = 1;  /* 2 stop bits. */
+
+       /*
+        * The baudrate setup is a bit fishy, but in the end the tranceiver is
+        * set to 4800 and the receiver to 115200. The magic value is
+        * 29.493 MHz.
+        */
+       tr_ctrl.base_freq = regk_ser_f29_493;
+       rec_ctrl.base_freq = regk_ser_f29_493;
+       tr_baud.div = (29493000 / 8) / 4800;
+       rec_baud.div = (29493000 / 8) / 115200;
+
+       REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
+       REG_WR(ser, regi_ser, rw_tr_baud_div, tr_baud);
+       REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl);
+       REG_WR(ser, regi_ser, rw_rec_baud_div, rec_baud);
+}
+
+void
+decompress_kernel()
+{
+       char revision;
+
+       /* input_data is set in head.S */
+       inbuf = input_data;
+
+#ifdef CONFIG_ETRAX_DEBUG_PORT0
+       serial_setup(regi_ser0);
+#endif
+#ifdef CONFIG_ETRAX_DEBUG_PORT1
+       serial_setup(regi_ser1);
+#endif
+#ifdef CONFIG_ETRAX_DEBUG_PORT2
+       serial_setup(regi_ser2);
+#endif
+#ifdef CONFIG_ETRAX_DEBUG_PORT3
+       serial_setup(regi_ser3);
+#endif
+
+       setup_normal_output_buffer();
+
+       makecrc();
+
+       __asm__ volatile ("move $vr,%0" : "=rm" (revision));
+       if (revision < 32)
+       {
+               puts("You need an ETRAX FS to run Linux 2.6/crisv32.\n");
+               while(1);
+       }
+
+       puts("Uncompressing Linux...\n");
+       gunzip();
+       puts("Done. Now booting the kernel.\n");
+}
diff -urN linux/arch/cris/arch-v32/boot/rescue/Makefile 
linux/arch/cris/arch-v32/boot/rescue/Makefile
--- linux/arch/cris/arch-v32/boot/rescue/Makefile       1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/boot/rescue/Makefile       2005-08-01 
19:23:41.913614000 +0100     1.1
@@ -0,0 +1,36 @@
+#
+# Makefile for rescue code
+#
+target = $(target_rescue_dir)
+src    = $(src_rescue_dir)
+
+CC = gcc-cris -mlinux -march=v32 $(LINUXINCLUDE)
+CFLAGS = -O2
+LD = gcc-cris -mlinux -march=v32 -nostdlib
+OBJCOPY = objcopy-cris
+OBJCOPYFLAGS = -O binary --remove-section=.bss
+
+all: $(target)/rescue.bin
+
+rescue: rescue.bin
+       # do nothing
+
+$(target)/rescue.bin: $(target) $(target)/head.o
+       $(LD) -T $(src)/rescue.ld -o $(target)/rescue.o $(target)/head.o
+       $(OBJCOPY) $(OBJCOPYFLAGS) $(target)/rescue.o $(target)/rescue.bin
+       cp -p $(target)/rescue.bin $(objtree)
+
+$(target):
+       mkdir -p $(target)
+
+$(target)/head.o: $(src)/head.S
+       $(CC) -D__ASSEMBLY__ -c $< -o $*.o
+
+clean:
+       rm -f $(target)/*.o $(target)/*.bin
+
+fastdep:
+
+modules:
+
+modules-install:
diff -urN linux/arch/cris/arch-v32/boot/rescue/head.S 
linux/arch/cris/arch-v32/boot/rescue/head.S
--- linux/arch/cris/arch-v32/boot/rescue/head.S 1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/boot/rescue/head.S 2005-08-01 19:23:41.939981000 
+0100     1.1
@@ -0,0 +1,39 @@
+/* $Id: head.S,v 1.4 2004/11/01 16:10:28 starvik Exp $
+ *
+ * This used to be the rescue code but now that is handled by the
+ * RedBoot based RFL instead. Nothing to see here, move along.
+ */
+
+#include <linux/config.h>
+#include <asm/arch/hwregs/reg_map_asm.h>
+#include <asm/arch/hwregs/config_defs_asm.h>
+
+       .text
+
+       ;; Start clocks for used blocks.
+       move.d REG_ADDR(config, regi_config, rw_clk_ctrl), $r1
+       move.d [$r1], $r0
+       or.d   REG_STATE(config, rw_clk_ctrl, cpu, yes) | \
+              REG_STATE(config, rw_clk_ctrl, bif, yes) | \
+              REG_STATE(config, rw_clk_ctrl, fix_io, yes), $r0
+       move.d $r0, [$r1]
+
+       ;; Copy 68KB NAND flash to Internal RAM (if NAND boot)
+       move.d 0x38004000, $r10
+       move.d 0x8000, $r11
+       move.d 0x11000, $r12
+       move.d copy_complete, $r13
+       and.d  0x000fffff, $r13
+       or.d   0x38000000, $r13
+
+#include "../../lib/nand_init.S"
+
+       ;; No NAND found
+       move.d  CONFIG_ETRAX_PTABLE_SECTOR, $r10
+       jump    $r10 ; Jump to decompresser
+       nop
+
+copy_complete:
+       move.d  0x38000000 + CONFIG_ETRAX_PTABLE_SECTOR, $r10
+       jump    $r10 ; Jump to decompresser
+       nop
diff -urN linux/arch/cris/arch-v32/boot/rescue/rescue.ld 
linux/arch/cris/arch-v32/boot/rescue/rescue.ld
--- linux/arch/cris/arch-v32/boot/rescue/rescue.ld      1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/boot/rescue/rescue.ld      2005-08-01 
19:23:41.963696000 +0100     1.1
@@ -0,0 +1,20 @@
+MEMORY
+       {
+       flash : ORIGIN = 0x00000000,
+               LENGTH = 0x00100000
+       }
+
+SECTIONS
+{
+       .text :
+       {
+               stext = . ;
+               *(.text)
+               etext = . ;
+       } > flash
+       .data :
+       {
+               *(.data)
+               edata = . ;
+       } > flash
+}
diff -urN linux/arch/cris/arch-v32/drivers/Kconfig 
linux/arch/cris/arch-v32/drivers/Kconfig
--- linux/arch/cris/arch-v32/drivers/Kconfig    1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/drivers/Kconfig    2005-08-01 19:23:42.116574000 
+0100     1.1
@@ -0,0 +1,625 @@
+config ETRAX_ETHERNET
+       bool "Ethernet support"
+       depends on ETRAX_ARCH_V32
+       select NET_ETHERNET
+       help
+         This option enables the ETRAX FS built-in 10/100Mbit Ethernet
+         controller.
+
+config ETRAX_ETHERNET_HW_CSUM
+       bool "Hardware accelerated ethernet checksum and scatter/gather"
+       depends on ETRAX_ETHERNET
+       depends on ETRAX_STREAMCOPROC
+       default y
+       help
+         Hardware acceleration of checksumming and scatter/gather
+
+config ETRAX_ETHERNET_IFACE0
+       depends on ETRAX_ETHERNET
+       bool "Enable network interface 0"
+
+config ETRAX_ETHERNET_IFACE1
+       depends on ETRAX_ETHERNET
+       bool "Enable network interface 1 (uses DMA6 and DMA7)"
+
+choice
+       prompt "Network LED behavior"
+       depends on ETRAX_ETHERNET
+       default ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY
+
+config ETRAX_NETWORK_LED_ON_WHEN_LINK
+       bool "LED_on_when_link"
+       help
+         Selecting LED_on_when_link will light the LED when there is a
+         connection and will flash off when there is activity.
+
+         Selecting LED_on_when_activity will light the LED only when
+         there is activity.
+
+         This setting will also affect the behaviour of other activity LEDs
+         e.g. Bluetooth.
+
+config ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY
+       bool "LED_on_when_activity"
+       help
+         Selecting LED_on_when_link will light the LED when there is a
+         connection and will flash off when there is activity.
+
+         Selecting LED_on_when_activity will light the LED only when
+         there is activity.
+
+         This setting will also affect the behaviour of other activity LEDs
+         e.g. Bluetooth.
+
+endchoice
+
+config ETRAXFS_SERIAL
+       bool "Serial-port support"
+       depends on ETRAX_ARCH_V32
+       help
+         Enables the ETRAX FS serial driver for ser0 (ttyS0)
+         You probably want this enabled.
+
+config ETRAX_SERIAL_PORT0
+       bool "Serial port 0 enabled"
+       depends on ETRAXFS_SERIAL
+       help
+         Enables the ETRAX FS serial driver for ser0 (ttyS0)
+         Normally you want this on. You can control what DMA channels to use
+         if you do not need DMA to something else.
+         ser0 can use dma4 or dma6 for output and dma5 or dma7 for input.
+
+choice
+       prompt "Ser0 DMA in channel "
+       depends on ETRAX_SERIAL_PORT0
+       default ETRAX_SERIAL_PORT0_NO_DMA_IN
+       help
+         What DMA channel to use for ser0.
+
+
+config ETRAX_SERIAL_PORT0_NO_DMA_IN
+       bool "Ser0 uses no DMA for input"
+       help
+         Do not use DMA for ser0 input.
+
+config ETRAX_SERIAL_PORT0_DMA7_IN
+       bool "Ser0 uses DMA7 for input"
+       depends on ETRAX_SERIAL_PORT0
+       help
+         Enables the DMA7 input channel for ser0 (ttyS0).
+         If you do not enable DMA, an interrupt for each character will be
+         used when receiveing data.
+         Normally you want to use DMA, unless you use the DMA channel for
+         something else.
+
+endchoice
+
+choice
+       prompt "Ser0 DMA out channel"
+       depends on ETRAX_SERIAL_PORT0
+       default ETRAX_SERIAL_PORT0_NO_DMA_OUT
+
+config ETRAX_SERIAL_PORT0_NO_DMA_OUT
+       bool "Ser0 uses no DMA for output"
+       help
+         Do not use DMA for ser0 output.
+
+config ETRAX_SERIAL_PORT0_DMA6_OUT
+       bool "Ser0 uses DMA6 for output"
+       depends on ETRAX_SERIAL_PORT0
+       help
+         Enables the DMA6 output channel for ser0 (ttyS0).
+         If you do not enable DMA, an interrupt for each character will be
+         used when transmitting data.
+         Normally you want to use DMA, unless you use the DMA channel for
+         something else.
+
+endchoice
+
+config ETRAX_SER0_DTR_BIT
+       string "Ser 0 DTR bit (empty = not used)"
+       depends on ETRAX_SERIAL_PORT0
+
+config ETRAX_SER0_RI_BIT
+       string "Ser 0 RI bit (empty = not used)"
+       depends on ETRAX_SERIAL_PORT0
+
+config ETRAX_SER0_DSR_BIT
+       string "Ser 0 DSR bit (empty = not used)"
+       depends on ETRAX_SERIAL_PORT0
+
+config ETRAX_SER0_CD_BIT
+       string "Ser 0 CD bit (empty = not used)"
+       depends on ETRAX_SERIAL_PORT0
+
+config ETRAX_SERIAL_PORT1
+       bool "Serial port 1 enabled"
+       depends on ETRAXFS_SERIAL
+       help
+         Enables the ETRAX FS serial driver for ser1 (ttyS1).
+
+choice
+       prompt "Ser1 DMA in channel "
+       depends on ETRAX_SERIAL_PORT1
+       default ETRAX_SERIAL_PORT1_NO_DMA_IN
+       help
+         What DMA channel to use for ser1.
+
+
+config ETRAX_SERIAL_PORT1_NO_DMA_IN
+       bool "Ser1 uses no DMA for input"
+       help
+         Do not use DMA for ser1 input.
+
+config ETRAX_SERIAL_PORT1_DMA5_IN
+       bool "Ser1 uses DMA5 for input"
+       depends on ETRAX_SERIAL_PORT1
+       help
+         Enables the DMA5 input channel for ser1 (ttyS1).
+         If you do not enable DMA, an interrupt for each character will be
+         used when receiveing data.
+         Normally you want this on, unless you use the DMA channel for
+         something else.
+
+endchoice
+
+choice
+       prompt "Ser1 DMA out channel "
+       depends on ETRAX_SERIAL_PORT1
+       default ETRAX_SERIAL_PORT1_NO_DMA_OUT
+       help
+         What DMA channel to use for ser1.
+
+config ETRAX_SERIAL_PORT1_NO_DMA_OUT
+       bool "Ser1 uses no DMA for output"
+       help
+         Do not use DMA for ser1 output.
+
+config ETRAX_SERIAL_PORT1_DMA4_OUT
+       bool "Ser1 uses DMA4 for output"
+       depends on ETRAX_SERIAL_PORT1
+       help
+         Enables the DMA4 output channel for ser1 (ttyS1).
+         If you do not enable DMA, an interrupt for each character will be
+         used when transmitting data.
+         Normally you want this on, unless you use the DMA channel for
+         something else.
+
+endchoice
+
+config ETRAX_SER1_DTR_BIT
+       string "Ser 1 DTR bit (empty = not used)"
+       depends on ETRAX_SERIAL_PORT1
+
+config ETRAX_SER1_RI_BIT
+       string "Ser 1 RI bit (empty = not used)"
+       depends on ETRAX_SERIAL_PORT1
+
+config ETRAX_SER1_DSR_BIT
+       string "Ser 1 DSR bit (empty = not used)"
+       depends on ETRAX_SERIAL_PORT1
+
+config ETRAX_SER1_CD_BIT
+       string "Ser 1 CD bit (empty = not used)"
+       depends on ETRAX_SERIAL_PORT1
+
+config ETRAX_SERIAL_PORT2
+       bool "Serial port 2 enabled"
+       depends on ETRAXFS_SERIAL
+       help
+         Enables the ETRAX FS serial driver for ser2 (ttyS2).
+
+choice
+       prompt "Ser2 DMA in channel "
+       depends on ETRAX_SERIAL_PORT2
+       default ETRAX_SERIAL_PORT2_NO_DMA_IN
+       help
+         What DMA channel to use for ser2.
+
+
+config ETRAX_SERIAL_PORT2_NO_DMA_IN
+       bool "Ser2 uses no DMA for input"
+       help
+         Do not use DMA for ser2 input.
+
+config ETRAX_SERIAL_PORT2_DMA3_IN
+       bool "Ser2 uses DMA3 for input"
+       depends on ETRAX_SERIAL_PORT2
+       help
+         Enables the DMA3 input channel for ser2 (ttyS2).
+         If you do not enable DMA, an interrupt for each character will be
+         used when receiveing data.
+         Normally you want to use DMA, unless you use the DMA channel for
+         something else.
+
+endchoice
+
+choice
+       prompt "Ser2 DMA out channel"
+       depends on ETRAX_SERIAL_PORT2
+       default ETRAX_SERIAL_PORT2_NO_DMA_OUT
+
+config ETRAX_SERIAL_PORT2_NO_DMA_OUT
+       bool "Ser2 uses no DMA for output"
+       help
+         Do not use DMA for ser2 output.
+
+config ETRAX_SERIAL_PORT2_DMA2_OUT
+       bool "Ser2 uses DMA2 for output"
+       depends on ETRAX_SERIAL_PORT2
+       help
+         Enables the DMA2 output channel for ser2 (ttyS2).
+         If you do not enable DMA, an interrupt for each character will be
+         used when transmitting data.
+         Normally you want to use DMA, unless you use the DMA channel for
+         something else.
+
+endchoice
+
+config ETRAX_SER2_DTR_BIT
+       string "Ser 2 DTR bit (empty = not used)"
+       depends on ETRAX_SERIAL_PORT2
+
+config ETRAX_SER2_RI_BIT
+       string "Ser 2 RI bit (empty = not used)"
+       depends on ETRAX_SERIAL_PORT2
+
+config ETRAX_SER2_DSR_BIT
+       string "Ser 2 DSR bit (empty = not used)"
+       depends on ETRAX_SERIAL_PORT2
+
+config ETRAX_SER2_CD_BIT
+       string "Ser 2 CD bit (empty = not used)"
+       depends on ETRAX_SERIAL_PORT2
+
+config ETRAX_SERIAL_PORT3
+       bool "Serial port 3 enabled"
+       depends on ETRAXFS_SERIAL
+       help
+         Enables the ETRAX FS serial driver for ser3 (ttyS3).
+
+choice
+       prompt "Ser3 DMA in channel "
+       depends on ETRAX_SERIAL_PORT3
+       default ETRAX_SERIAL_PORT3_NO_DMA_IN
+       help
+         What DMA channel to use for ser3.
+
+
+config ETRAX_SERIAL_PORT3_NO_DMA_IN
+       bool "Ser3 uses no DMA for input"
+       help
+         Do not use DMA for ser3 input.
+
+config ETRAX_SERIAL_PORT3_DMA9_IN
+       bool "Ser3 uses DMA9 for input"
+       depends on ETRAX_SERIAL_PORT3
+       help
+         Enables the DMA9 input channel for ser3 (ttyS3).
+         If you do not enable DMA, an interrupt for each character will be
+         used when receiveing data.
+         Normally you want to use DMA, unless you use the DMA channel for
+         something else.
+
+endchoice
+
+choice
+       prompt "Ser3 DMA out channel"
+       depends on ETRAX_SERIAL_PORT3
+       default ETRAX_SERIAL_PORT3_NO_DMA_OUT
+
+config ETRAX_SERIAL_PORT3_NO_DMA_OUT
+       bool "Ser3 uses no DMA for output"
+       help
+         Do not use DMA for ser3 output.
+
+config ETRAX_SERIAL_PORT3_DMA8_OUT
+       bool "Ser3 uses DMA8 for output"
+       depends on ETRAX_SERIAL_PORT3
+       help
+         Enables the DMA8 output channel for ser3 (ttyS3).
+         If you do not enable DMA, an interrupt for each character will be
+         used when transmitting data.
+         Normally you want to use DMA, unless you use the DMA channel for
+         something else.
+
+endchoice
+
+config ETRAX_SER3_DTR_BIT
+       string "Ser 3 DTR bit (empty = not used)"
+       depends on ETRAX_SERIAL_PORT3
+
+config ETRAX_SER3_RI_BIT
+       string "Ser 3 RI bit (empty = not used)"
+       depends on ETRAX_SERIAL_PORT3
+
+config ETRAX_SER3_DSR_BIT
+       string "Ser 3 DSR bit (empty = not used)"
+       depends on ETRAX_SERIAL_PORT3
+
+config ETRAX_SER3_CD_BIT
+       string "Ser 3 CD bit (empty = not used)"
+       depends on ETRAX_SERIAL_PORT3
+
+config ETRAX_RS485
+       bool "RS-485 support"
+       depends on ETRAX_SERIAL
+       help
+         Enables support for RS-485 serial communication.  For a primer on
+         RS-485, see <http://www.hw.cz/english/docs/rs485/rs485.html>.
+
+config ETRAX_RS485_DISABLE_RECEIVER
+       bool "Disable serial receiver"
+       depends on ETRAX_RS485
+       help
+         It is necessary to disable the serial receiver to avoid serial
+         loopback.  Not all products are able to do this in software only.
+         Axis 2400/2401 must disable receiver.
+
+config ETRAX_AXISFLASHMAP
+       bool "Axis flash-map support"
+       depends on ETRAX_ARCH_V32
+       select MTD
+       select MTD_CFI
+       select MTD_CFI_AMDSTD
+       select MTD_OBSOLETE_CHIPS
+       select MTD_AMDSTD
+       select MTD_CHAR
+       select MTD_BLOCK
+       select MTD_PARTITIONS
+       select MTD_CONCAT
+       select MTD_COMPLEX_MAPPINGS
+       help
+         This option enables MTD mapping of flash devices.  Needed to use
+         flash memories.  If unsure, say Y.
+
+config ETRAX_SYNCHRONOUS_SERIAL
+       bool "Synchronous serial-port support"
+       depends on ETRAX_ARCH_V32
+       help
+         Enables the ETRAX FS synchronous serial driver.
+
+config ETRAX_SYNCHRONOUS_SERIAL_PORT0
+         bool "Synchronous serial port 0 enabled"
+         depends on ETRAX_SYNCHRONOUS_SERIAL
+         help
+           Enabled synchronous serial port 0.
+
+config ETRAX_SYNCHRONOUS_SERIAL0_DMA
+         bool "Enable DMA on synchronous serial port 0."
+         depends on ETRAX_SYNCHRONOUS_SERIAL_PORT0
+         help
+           A synchronous serial port can run in manual or DMA mode.
+           Selecting this option will make it run in DMA mode.
+
+config ETRAX_SYNCHRONOUS_SERIAL_PORT1
+         bool "Synchronous serial port 1 enabled"
+         depends on ETRAX_SYNCHRONOUS_SERIAL
+         help
+           Enabled synchronous serial port 1.
+
+config ETRAX_SYNCHRONOUS_SERIAL1_DMA
+         bool "Enable DMA on synchronous serial port 1."
+         depends on ETRAX_SYNCHRONOUS_SERIAL_PORT1
+         help
+           A synchronous serial port can run in manual or DMA mode.
+           Selecting this option will make it run in DMA mode.
+
+config ETRAX_PTABLE_SECTOR
+       int "Byte-offset of partition table sector"
+       depends on ETRAX_AXISFLASHMAP
+       default "65536"
+       help
+         Byte-offset of the partition table in the first flash chip.
+         The default value is 64kB and should not be changed unless
+         you know exactly what you are doing. The only valid reason
+         for changing this is when the flash block size is bigger
+         than 64kB (e.g. when using two parallel 16 bit flashes).
+
+config ETRAX_NANDFLASH
+       bool "NAND flash support"
+       depends on ETRAX_ARCH_V32
+       select MTD_NAND
+       select MTD_NAND_IDS
+       help
+         This option enables MTD mapping of NAND flash devices.  Needed to use
+         NAND flash memories.  If unsure, say Y.
+
+config ETRAX_I2C
+       bool "I2C driver"
+       depends on ETRAX_ARCH_V32
+       help
+         This option enabled the I2C driver used by e.g. the RTC driver.
+
+config ETRAX_I2C_DATA_PORT
+       string "I2C data pin"
+       depends on ETRAX_I2C
+       help
+         The pin to use for I2C data.
+
+config ETRAX_I2C_CLK_PORT
+       string "I2C clock pin"
+       depends on ETRAX_I2C
+       help
+         The pin to use for I2C clock.
+
+config ETRAX_RTC
+       bool "Real Time Clock support"
+       depends on ETRAX_ARCH_V32
+       help
+         Enabled RTC support.
+
+choice
+       prompt "RTC chip"
+       depends on ETRAX_RTC
+       default ETRAX_PCF8563
+
+config ETRAX_PCF8563
+       bool "PCF8563"
+       help
+         Philips PCF8563 RTC
+
+endchoice
+
+config ETRAX_GPIO
+       bool "GPIO support"
+       depends on ETRAX_ARCH_V32
+       ---help---
+         Enables the ETRAX general port device (major 120, minors 0-4).
+         You can use this driver to access the general port bits. It supports
+         these ioctl's:
+         #include <linux/etraxgpio.h>
+         fd = open("/dev/gpioa", O_RDWR); // or /dev/gpiob
+         ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_SETBITS), bits_to_set);
+         ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_CLRBITS), bits_to_clear);
+         err = ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_READ_INBITS), &val);
+         Remember that you need to setup the port directions appropriately in
+         the General configuration.
+
+config ETRAX_PA_BUTTON_BITMASK
+       hex "PA-buttons bitmask"
+       depends on ETRAX_GPIO
+       default "0x02"
+       help
+         This is a bitmask (8 bits) with information about what bits on PA
+         that are used for buttons.
+         Most products has a so called TEST button on PA1, if that is true
+         use 0x02 here.
+         Use 00 if there are no buttons on PA.
+         If the bitmask is <> 00 a button driver will be included in the gpio
+         driver. ETRAX general I/O support must be enabled.
+
+config ETRAX_PA_CHANGEABLE_DIR
+       hex "PA user changeable dir mask"
+       depends on ETRAX_GPIO
+       default "0x00"
+       help
+         This is a bitmask (8 bits) with information of what bits in PA that a
+         user can change direction on using ioctl's.
+         Bit set = changeable.
+         You probably want 0x00 here, but it depends on your hardware.
+
+config ETRAX_PA_CHANGEABLE_BITS
+       hex "PA user changeable bits mask"
+       depends on ETRAX_GPIO
+       default "0x00"
+       help
+         This is a bitmask (8 bits) with information of what bits in PA
+         that a user can change the value on using ioctl's.
+         Bit set = changeable.
+
+config ETRAX_PB_CHANGEABLE_DIR
+       hex "PB user changeable dir mask"
+       depends on ETRAX_GPIO
+       default "0x00000"
+       help
+         This is a bitmask (18 bits) with information of what bits in PB
+         that a user can change direction on using ioctl's.
+         Bit set = changeable.
+         You probably want 0x00000 here, but it depends on your hardware.
+
+config ETRAX_PB_CHANGEABLE_BITS
+       hex "PB user changeable bits mask"
+       depends on ETRAX_GPIO
+       default "0x00000"
+       help
+         This is a bitmask (18 bits) with information of what bits in PB
+         that a user can change the value on using ioctl's.
+         Bit set = changeable.
+
+config ETRAX_PC_CHANGEABLE_DIR
+       hex "PC user changeable dir mask"
+       depends on ETRAX_GPIO
+       default "0x00000"
+       help
+         This is a bitmask (18 bits) with information of what bits in PC
+         that a user can change direction on using ioctl's.
+         Bit set = changeable.
+         You probably want 0x00000 here, but it depends on your hardware.
+
+config ETRAX_PC_CHANGEABLE_BITS
+       hex "PC user changeable bits mask"
+       depends on ETRAX_GPIO
+       default "0x00000"
+       help
+         This is a bitmask (18 bits) with information of what bits in PC
+         that a user can change the value on using ioctl's.
+         Bit set = changeable.
+
+config ETRAX_PD_CHANGEABLE_DIR
+       hex "PD user changeable dir mask"
+       depends on ETRAX_GPIO
+       default "0x00000"
+       help
+         This is a bitmask (18 bits) with information of what bits in PD
+         that a user can change direction on using ioctl's.
+         Bit set = changeable.
+         You probably want 0x00000 here, but it depends on your hardware.
+
+config ETRAX_PD_CHANGEABLE_BITS
+       hex "PD user changeable bits mask"
+       depends on ETRAX_GPIO
+       default "0x00000"
+       help
+         This is a bitmask (18 bits) with information of what bits in PD
+         that a user can change the value on using ioctl's.
+         Bit set = changeable.
+
+config ETRAX_PE_CHANGEABLE_DIR
+       hex "PE user changeable dir mask"
+       depends on ETRAX_GPIO
+       default "0x00000"
+       help
+         This is a bitmask (18 bits) with information of what bits in PE
+         that a user can change direction on using ioctl's.
+         Bit set = changeable.
+         You probably want 0x00000 here, but it depends on your hardware.
+
+config ETRAX_PE_CHANGEABLE_BITS
+       hex "PE user changeable bits mask"
+       depends on ETRAX_GPIO
+       default "0x00000"
+       help
+         This is a bitmask (18 bits) with information of what bits in PE
+         that a user can change the value on using ioctl's.
+         Bit set = changeable.
+
+config ETRAX_IDE
+       bool "ATA/IDE support"
+       depends on ETRAX_ARCH_V32
+       select IDE
+       select BLK_DEV_IDE
+       select BLK_DEV_IDEDISK
+       select BLK_DEV_IDECD
+       select BLK_DEV_IDEDMA
+       help
+         Enables the ETRAX IDE driver.
+
+config ETRAX_CARDBUS
+        bool "Cardbus support"
+        depends on ETRAX_ARCH_V32
+        select PCCARD
+        select CARDBUS
+        select HOTPLUG
+        select PCCARD_NONSTATIC
+        help
+        Enabled the ETRAX Carbus driver.
+
+config PCI
+       bool
+       depends on ETRAX_CARDBUS
+       default y
+
+config ETRAX_IOP_FW_LOAD
+       tristate "IO-processor hotplug firmware loading support"
+       depends on ETRAX_ARCH_V32
+       select FW_LOADER
+       help
+         Enables IO-processor hotplug firmware loading support.
+
+config ETRAX_STREAMCOPROC
+       tristate "Stream co-processor driver enabled"
+       depends on ETRAX_ARCH_V32
+       help
+         This option enables a driver for the stream co-processor
+         for cryptographic operations.
diff -urN linux/arch/cris/arch-v32/drivers/Makefile 
linux/arch/cris/arch-v32/drivers/Makefile
--- linux/arch/cris/arch-v32/drivers/Makefile   1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/drivers/Makefile   2005-08-01 19:23:42.149584000 
+0100     1.1
@@ -0,0 +1,13 @@
+#
+# Makefile for Etrax-specific drivers
+#
+
+obj-$(CONFIG_ETRAX_STREAMCOPROC)        += cryptocop.o
+obj-$(CONFIG_ETRAX_AXISFLASHMAP)        += axisflashmap.o
+obj-$(CONFIG_ETRAX_NANDFLASH)           += nandflash.o
+obj-$(CONFIG_ETRAX_GPIO)               += gpio.o
+obj-$(CONFIG_ETRAX_IOP_FW_LOAD)         += iop_fw_load.o
+obj-$(CONFIG_ETRAX_PCF8563)            += pcf8563.o
+obj-$(CONFIG_ETRAX_I2C)                        += i2c.o
+obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o
+obj-$(CONFIG_PCI)                      += pci/
diff -urN linux/arch/cris/arch-v32/drivers/axisflashmap.c 
linux/arch/cris/arch-v32/drivers/axisflashmap.c
--- linux/arch/cris/arch-v32/drivers/axisflashmap.c     1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/drivers/axisflashmap.c     2005-08-01 
19:23:42.167504000 +0100     1.1
@@ -0,0 +1,455 @@
+/*
+ * Physical mapping layer for MTD using the Axis partitiontable format
+ *
+ * Copyright (c) 2001, 2002, 2003 Axis Communications AB
+ *
+ * This file is under the GPL.
+ *
+ * First partition is always sector 0 regardless of if we find a partitiontable
+ * or not. In the start of the next sector, there can be a partitiontable that
+ * tells us what other partitions to define. If there isn't, we use a default
+ * partition split defined below.
+ *
+ * Copy of os/lx25/arch/cris/arch-v10/drivers/axisflashmap.c 1.5
+ * with minor changes.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <linux/mtd/concat.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/mtdram.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/arch/hwregs/config_defs.h>
+#include <asm/axisflashmap.h>
+#include <asm/mmu.h>
+
+#define MEM_CSE0_SIZE (0x04000000)
+#define MEM_CSE1_SIZE (0x04000000)
+
+#define FLASH_UNCACHED_ADDR  KSEG_E
+#define FLASH_CACHED_ADDR    KSEG_F
+
+#if CONFIG_ETRAX_FLASH_BUSWIDTH==1
+#define flash_data __u8
+#elif CONFIG_ETRAX_FLASH_BUSWIDTH==2
+#define flash_data __u16
+#elif CONFIG_ETRAX_FLASH_BUSWIDTH==4
+#define flash_data __u16
+#endif
+
+/* From head.S */
+extern unsigned long romfs_start, romfs_length, romfs_in_flash;
+
+/* The master mtd for the entire flash. */
+struct mtd_info* axisflash_mtd = NULL;
+
+/* Map driver functions. */
+
+static map_word flash_read(struct map_info *map, unsigned long ofs)
+{
+       map_word tmp;
+       tmp.x[0] = *(flash_data *)(map->map_priv_1 + ofs);
+       return tmp;
+}
+
+static void flash_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 flash_write(struct map_info *map, map_word d, unsigned long adr)
+{
+       *(flash_data *)(map->map_priv_1 + adr) = (flash_data)d.x[0];
+}
+
+/*
+ * The map for chip select e0.
+ *
+ * We run into tricky coherence situations if we mix cached with uncached
+ * accesses to we only use the uncached version here.
+ *
+ * The size field is the total size where the flash chips may be mapped on the
+ * chip select. MTD probes should find all devices there and it does not matter
+ * if there are unmapped gaps or aliases (mirrors of flash devices). The MTD
+ * probes will ignore them.
+ *
+ * The start address in map_priv_1 is in virtual memory so we cannot use
+ * MEM_CSE0_START but must rely on that FLASH_UNCACHED_ADDR is the start
+ * address of cse0.
+ */
+static struct map_info map_cse0 = {
+       .name = "cse0",
+       .size = MEM_CSE0_SIZE,
+       .bankwidth = CONFIG_ETRAX_FLASH_BUSWIDTH,
+       .read = flash_read,
+       .copy_from = flash_copy_from,
+       .write = flash_write,
+       .map_priv_1 = FLASH_UNCACHED_ADDR
+};
+
+/*
+ * The map for chip select e1.
+ *
+ * If there was a gap between cse0 and cse1, map_priv_1 would get the wrong
+ * address, but there isn't.
+ */
+static struct map_info map_cse1 = {
+       .name = "cse1",
+       .size = MEM_CSE1_SIZE,
+       .bankwidth = CONFIG_ETRAX_FLASH_BUSWIDTH,
+       .read = flash_read,
+       .copy_from = flash_copy_from,
+       .write = flash_write,
+       .map_priv_1 = FLASH_UNCACHED_ADDR + MEM_CSE0_SIZE
+};
+
+/* If no partition-table was found, we use this default-set. */
+#define MAX_PARTITIONS         7
+#define NUM_DEFAULT_PARTITIONS 3
+
+/*
+ * Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the
+ * size of one flash block and "filesystem"-partition needs 5 blocks to be able
+ * to use JFFS.
+ */
+static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = {
+       {
+               .name = "boot firmware",
+               .size = CONFIG_ETRAX_PTABLE_SECTOR,
+               .offset = 0
+       },
+       {
+               .name = "kernel",
+               .size = 0x200000 - (6 * CONFIG_ETRAX_PTABLE_SECTOR),
+               .offset = CONFIG_ETRAX_PTABLE_SECTOR
+       },
+       {
+               .name = "filesystem",
+               .size = 5 * CONFIG_ETRAX_PTABLE_SECTOR,
+               .offset = 0x200000 - (5 * CONFIG_ETRAX_PTABLE_SECTOR)
+       }
+};
+
+/* Initialize the ones normally used. */
+static struct mtd_partition axis_partitions[MAX_PARTITIONS] = {
+       {
+               .name = "part0",
+               .size = CONFIG_ETRAX_PTABLE_SECTOR,
+               .offset = 0
+       },
+       {
+               .name = "part1",
+               .size = 0,
+               .offset = 0
+       },
+       {
+               .name = "part2",
+               .size = 0,
+               .offset = 0
+       },
+       {
+               .name = "part3",
+               .size = 0,
+               .offset = 0
+       },
+       {
+               .name = "part4",
+               .size = 0,
+               .offset = 0
+       },
+       {
+               .name = "part5",
+               .size = 0,
+               .offset = 0
+       },
+       {
+               .name = "part6",
+               .size = 0,
+               .offset = 0
+       },
+};
+
+/*
+ * Probe a chip select for AMD-compatible (JEDEC) or CFI-compatible flash
+ * chips in that order (because the amd_flash-driver is faster).
+ */
+static struct mtd_info *probe_cs(struct map_info *map_cs)
+{
+       struct mtd_info *mtd_cs = NULL;
+
+       printk(KERN_INFO
+              "%s: Probing a 0x%08lx bytes large window at 0x%08lx.\n",
+              map_cs->name, map_cs->size, map_cs->map_priv_1);
+
+#ifdef CONFIG_MTD_AMDSTD
+       mtd_cs = do_map_probe("amd_flash", map_cs);
+#endif
+#ifdef CONFIG_MTD_CFI
+       if (!mtd_cs) {
+               mtd_cs = do_map_probe("cfi_probe", map_cs);
+       }
+#endif
+
+       return mtd_cs;
+}
+
+/*
+ * Probe each chip select individually for flash chips. If there are chips on
+ * both cse0 and cse1, the mtd_info structs will be concatenated to one struct
+ * so that MTD partitions can cross chip boundries.
+ *
+ * The only known restriction to how you can mount your chips is that each
+ * chip select must hold similar flash chips. But you need external hardware
+ * to do that anyway and you can put totally different chips on cse0 and cse1
+ * so it isn't really much of a restriction.
+ */
+extern struct mtd_info* __init crisv32_nand_flash_probe (void);
+static struct mtd_info *flash_probe(void)
+{
+       struct mtd_info *mtd_cse0;
+       struct mtd_info *mtd_cse1;
+       struct mtd_info *mtd_nand = NULL;
+       struct mtd_info *mtd_total;
+       struct mtd_info *mtds[3];
+       int count = 0;
+
+       if ((mtd_cse0 = probe_cs(&map_cse0)) != NULL)
+               mtds[count++] = mtd_cse0;
+       if ((mtd_cse1 = probe_cs(&map_cse1)) != NULL)
+               mtds[count++] = mtd_cse1;
+
+#ifdef CONFIG_ETRAX_NANDFLASH
+       if ((mtd_nand = crisv32_nand_flash_probe()) != NULL)
+               mtds[count++] = mtd_nand;
+#endif
+
+       if (!mtd_cse0 && !mtd_cse1 && !mtd_nand) {
+               /* No chip found. */
+               return NULL;
+       }
+
+       if (count > 1) {
+#ifdef CONFIG_MTD_CONCAT
+               /* Since the concatenation layer adds a small overhead we
+                * could try to figure out if the chips in cse0 and cse1 are
+                * identical and reprobe the whole cse0+cse1 window. But since
+                * flash chips are slow, the overhead is relatively small.
+                * So we use the MTD concatenation layer instead of further
+                * complicating the probing procedure.
+                */
+               mtd_total = mtd_concat_create(mtds,
+                                             count,
+                                             "cse0+cse1+nand");
+#else
+               printk(KERN_ERR "%s and %s: Cannot concatenate due to kernel "
+                      "(mis)configuration!\n", map_cse0.name, map_cse1.name);
+               mtd_toal = NULL;
+#endif
+               if (!mtd_total) {
+                       printk(KERN_ERR "%s and %s: Concatenation failed!\n",
+                              map_cse0.name, map_cse1.name);
+
+                       /* The best we can do now is to only use what we found
+                        * at cse0.
+                        */
+                       mtd_total = mtd_cse0;
+                       map_destroy(mtd_cse1);
+               }
+       } else {
+               mtd_total = mtd_cse0? mtd_cse0 : mtd_cse1 ? mtd_cse1 : mtd_nand;
+
+       }
+
+       return mtd_total;
+}
+
+extern unsigned long crisv32_nand_boot;
+extern unsigned long crisv32_nand_cramfs_offset;
+
+/*
+ * Probe the flash chip(s) and, if it succeeds, read the partition-table
+ * and register the partitions with MTD.
+ */
+static int __init init_axis_flash(void)
+{
+       struct mtd_info *mymtd;
+       int err = 0;
+       int pidx = 0;
+       struct partitiontable_head *ptable_head = NULL;
+       struct partitiontable_entry *ptable;
+       int use_default_ptable = 1; /* Until proven otherwise. */
+       const char *pmsg = KERN_INFO "  /dev/flash%d at 0x%08x, size 0x%08x\n";
+       static char page[512];
+       size_t len;
+
+#ifndef CONFIG_ETRAXFS_SIM
+       mymtd = flash_probe();
+       mymtd->read(mymtd, CONFIG_ETRAX_PTABLE_SECTOR, 512, &len, page);
+       ptable_head = (struct partitiontable_head *)(page + 
PARTITION_TABLE_OFFSET);
+
+       if (!mymtd) {
+               /* There's no reason to use this module if no flash chip can
+                * be identified. Make sure that's understood.
+                */
+               printk(KERN_INFO "axisflashmap: Found no flash chip.\n");
+       } else {
+               printk(KERN_INFO "%s: 0x%08x bytes of flash memory.\n",
+                      mymtd->name, mymtd->size);
+               axisflash_mtd = mymtd;
+       }
+
+       if (mymtd) {
+               mymtd->owner = THIS_MODULE;
+       }
+       pidx++;  /* First partition is always set to the default. */
+
+       if (ptable_head && (ptable_head->magic == PARTITION_TABLE_MAGIC)
+           && (ptable_head->size <
+               (MAX_PARTITIONS * sizeof(struct partitiontable_entry) +
+               PARTITIONTABLE_END_MARKER_SIZE))
+           && (*(unsigned long*)((void*)ptable_head + sizeof(*ptable_head) +
+                                 ptable_head->size -
+                                 PARTITIONTABLE_END_MARKER_SIZE)
+               == PARTITIONTABLE_END_MARKER)) {
+               /* Looks like a start, sane length and end of a
+                * partition table, lets check csum etc.
+                */
+               int ptable_ok = 0;
+               struct partitiontable_entry *max_addr =
+                       (struct partitiontable_entry *)
+                       ((unsigned long)ptable_head + sizeof(*ptable_head) +
+                        ptable_head->size);
+               unsigned long offset = CONFIG_ETRAX_PTABLE_SECTOR;
+               unsigned char *p;
+               unsigned long csum = 0;
+
+               ptable = (struct partitiontable_entry *)
+                       ((unsigned long)ptable_head + sizeof(*ptable_head));
+
+               /* Lets be PARANOID, and check the checksum. */
+               p = (unsigned char*) ptable;
+
+               while (p <= (unsigned char*)max_addr) {
+                       csum += *p++;
+                       csum += *p++;
+                       csum += *p++;
+                       csum += *p++;
+               }
+               ptable_ok = (csum == ptable_head->checksum);
+
+               /* Read the entries and use/show the info.  */
+               printk(KERN_INFO " Found a%s partition table at 0x%p-0x%p.\n",
+                      (ptable_ok ? " valid" : "n invalid"), ptable_head,
+                      max_addr);
+
+               /* We have found a working bootblock.  Now read the
+                * partition table.  Scan the table.  It ends when
+                * there is 0xffffffff, that is, empty flash.
+                */
+               while (ptable_ok
+                      && ptable->offset != 0xffffffff
+                      && ptable < max_addr
+                      && pidx < MAX_PARTITIONS) {
+
+                       axis_partitions[pidx].offset = offset + ptable->offset 
+ (crisv32_nand_boot ? 16384 : 0);
+                       axis_partitions[pidx].size = ptable->size;
+
+                       printk(pmsg, pidx, axis_partitions[pidx].offset,
+                              axis_partitions[pidx].size);
+                       pidx++;
+                       ptable++;
+               }
+               use_default_ptable = !ptable_ok;
+       }
+
+       if (romfs_in_flash) {
+               /* Add an overlapping device for the root partition (romfs). */
+
+               axis_partitions[pidx].name = "romfs";
+               if (crisv32_nand_boot) {
+                       char* data = kmalloc(1024, GFP_KERNEL);
+                       int len;
+                       int offset = crisv32_nand_cramfs_offset & ~(1024-1);
+                       char* tmp;
+
+                       mymtd->read(mymtd, offset, 1024, &len, data);
+                       tmp = &data[crisv32_nand_cramfs_offset % 512];
+                       axis_partitions[pidx].size = *(unsigned*)(tmp + 4);
+                       axis_partitions[pidx].offset = 
crisv32_nand_cramfs_offset;
+                       kfree(data);
+               } else {
+                       axis_partitions[pidx].size = romfs_length;
+                       axis_partitions[pidx].offset = romfs_start - 
FLASH_CACHED_ADDR;
+               }
+
+               axis_partitions[pidx].mask_flags |= MTD_WRITEABLE;
+
+               printk(KERN_INFO
+                       " Adding readonly flash partition for romfs image:\n");
+               printk(pmsg, pidx, axis_partitions[pidx].offset,
+                      axis_partitions[pidx].size);
+               pidx++;
+       }
+
+        if (mymtd) {
+               if (use_default_ptable) {
+                       printk(KERN_INFO " Using default partition table.\n");
+                       err = add_mtd_partitions(mymtd, axis_default_partitions,
+                                                NUM_DEFAULT_PARTITIONS);
+               } else {
+                       err = add_mtd_partitions(mymtd, axis_partitions, pidx);
+               }
+
+               if (err) {
+                       panic("axisflashmap could not add MTD partitions!\n");
+               }
+       }
+/* CONFIG_EXTRAXFS_SIM */
+#endif
+
+       if (!romfs_in_flash) {
+               /* Create an RAM device for the root partition (romfs). */
+
+#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || 
(CONFIG_MTDRAM_ABS_POS != 0)
+               /* No use trying to boot this kernel from RAM. Panic! */
+               printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM "
+                      "device due to kernel (mis)configuration!\n");
+               panic("This kernel cannot boot from RAM!\n");
+#else
+               struct mtd_info *mtd_ram;
+
+               mtd_ram = (struct mtd_info *)kmalloc(sizeof(struct mtd_info),
+                                                    GFP_KERNEL);
+               if (!mtd_ram) {
+                       panic("axisflashmap couldn't allocate memory for "
+                             "mtd_info!\n");
+               }
+
+               printk(KERN_INFO " Adding RAM partition for romfs image:\n");
+               printk(pmsg, pidx, romfs_start, romfs_length);
+
+               err = mtdram_init_device(mtd_ram, (void*)romfs_start,
+                                        romfs_length, "romfs");
+               if (err) {
+                       panic("axisflashmap could not initialize MTD RAM "
+                             "device!\n");
+               }
+#endif
+       }
+
+       return err;
+}
+
+/* This adds the above to the kernels init-call chain. */
+module_init(init_axis_flash);
+
+EXPORT_SYMBOL(axisflash_mtd);
diff -urN linux/arch/cris/arch-v32/drivers/cryptocop.c 
linux/arch/cris/arch-v32/drivers/cryptocop.c
--- linux/arch/cris/arch-v32/drivers/cryptocop.c        1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/drivers/cryptocop.c        2005-08-01 
19:23:42.195548000 +0100     1.1
@@ -0,0 +1,3522 @@
+/* $Id: cryptocop.c,v 1.13 2005/04/21 17:27:55 henriken Exp $
+ *
+ * Stream co-processor driver for the ETRAX FS
+ *
+ *    Copyright (C) 2003-2005  Axis Communications AB
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/stddef.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+
+#include <linux/list.h>
+#include <linux/interrupt.h>
+
+#include <asm/signal.h>
+#include <asm/irq.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/hwregs/dma.h>
+#include <asm/arch/hwregs/reg_map.h>
+#include <asm/arch/hwregs/reg_rdwr.h>
+#include <asm/arch/hwregs/intr_vect_defs.h>
+
+#include <asm/arch/hwregs/strcop.h>
+#include <asm/arch/hwregs/strcop_defs.h>
+#include <asm/arch/cryptocop.h>
+
+
+
+#define DESCR_ALLOC_PAD  (31)
+
+struct cryptocop_dma_desc {
+       char *free_buf; /* If non-null will be kfreed in free_cdesc() */
+       dma_descr_data *dma_descr;
+
+       unsigned char dma_descr_buf[sizeof(dma_descr_data) + DESCR_ALLOC_PAD];
+
+       unsigned int from_pool:1; /* If 1 'allocated' from the descriptor pool. 
*/
+       struct cryptocop_dma_desc *next;
+};
+
+
+struct cryptocop_int_operation{
+       void                        *alloc_ptr;
+       cryptocop_session_id        sid;
+
+       dma_descr_context           ctx_out;
+       dma_descr_context           ctx_in;
+
+       /* DMA descriptors allocated by driver. */
+       struct cryptocop_dma_desc   *cdesc_out;
+       struct cryptocop_dma_desc   *cdesc_in;
+
+       /* Strcop config to use. */
+       cryptocop_3des_mode         tdes_mode;
+       cryptocop_csum_type         csum_mode;
+
+       /* DMA descrs provided by consumer. */
+       dma_descr_data              *ddesc_out;
+       dma_descr_data              *ddesc_in;
+};
+
+
+struct cryptocop_tfrm_ctx {
+       cryptocop_tfrm_id tid;
+       unsigned int blocklength;
+
+       unsigned int start_ix;
+
+       struct cryptocop_tfrm_cfg *tcfg;
+       struct cryptocop_transform_ctx *tctx;
+
+       unsigned char previous_src;
+       unsigned char current_src;
+
+       /* Values to use in metadata out. */
+       unsigned char hash_conf;
+       unsigned char hash_mode;
+       unsigned char ciph_conf;
+       unsigned char cbcmode;
+       unsigned char decrypt;
+
+       unsigned int requires_padding:1;
+       unsigned int strict_block_length:1;
+       unsigned int active:1;
+       unsigned int done:1;
+       size_t consumed;
+       size_t produced;
+
+       /* Pad (input) descriptors to put in the DMA out list when the transform
+        * output is put on the DMA in list. */
+       struct cryptocop_dma_desc *pad_descs;
+
+       struct cryptocop_tfrm_ctx *prev_src;
+       struct cryptocop_tfrm_ctx *curr_src;
+
+       /* Mapping to HW. */
+       unsigned char unit_no;
+};
+
+
+struct cryptocop_private{
+       cryptocop_session_id sid;
+       struct cryptocop_private *next;
+};
+
+/* Session list. */
+
+struct cryptocop_transform_ctx{
+       struct cryptocop_transform_init init;
+       unsigned char dec_key[CRYPTOCOP_MAX_KEY_LENGTH];
+       unsigned int dec_key_set:1;
+
+       struct cryptocop_transform_ctx *next;
+};
+
+
+struct cryptocop_session{
+       cryptocop_session_id sid;
+
+       struct cryptocop_transform_ctx *tfrm_ctx;
+
+       struct cryptocop_session *next;
+};
+
+/* Priority levels for jobs sent to the cryptocop.  Checksum operations from
+   kernel have highest priority since TCPIP stack processing must not
+   be a bottleneck. */
+typedef enum {
+       cryptocop_prio_kernel_csum = 0,
+       cryptocop_prio_kernel = 1,
+       cryptocop_prio_user = 2,
+       cryptocop_prio_no_prios = 3
+} cryptocop_queue_priority;
+
+struct cryptocop_prio_queue{
+       struct list_head jobs;
+       cryptocop_queue_priority prio;
+};
+
+struct cryptocop_prio_job{
+       struct list_head node;
+       cryptocop_queue_priority prio;
+
+       struct cryptocop_operation *oper;
+       struct cryptocop_int_operation *iop;
+};
+
+struct ioctl_job_cb_ctx {
+       unsigned int processed:1;
+};
+
+
+static struct cryptocop_session *cryptocop_sessions = NULL;
+spinlock_t cryptocop_sessions_lock;
+
+/* Next Session ID to assign. */
+static cryptocop_session_id next_sid = 1;
+
+/* Pad for checksum. */
+static const char csum_zero_pad[1] = {0x00};
+
+/* Trash buffer for mem2mem operations. */
+#define MEM2MEM_DISCARD_BUF_LENGTH  (512)
+static unsigned char mem2mem_discard_buf[MEM2MEM_DISCARD_BUF_LENGTH];
+
+/* Descriptor pool. */
+/* FIXME Tweak this value. */
+#define CRYPTOCOP_DESCRIPTOR_POOL_SIZE   (100)
+static struct cryptocop_dma_desc descr_pool[CRYPTOCOP_DESCRIPTOR_POOL_SIZE];
+static struct cryptocop_dma_desc *descr_pool_free_list;
+static int descr_pool_no_free;
+static spinlock_t descr_pool_lock;
+
+/* Lock to stop cryptocop to start processing of a new operation. The holder
+   of this lock MUST call cryptocop_start_job() after it is unlocked. */
+spinlock_t cryptocop_process_lock;
+
+static struct cryptocop_prio_queue 
cryptocop_job_queues[cryptocop_prio_no_prios];
+static spinlock_t cryptocop_job_queue_lock;
+static struct cryptocop_prio_job *cryptocop_running_job = NULL;
+static spinlock_t running_job_lock;
+
+/* The interrupt handler appends completed jobs to this list. The scehduled
+ * tasklet removes them upon sending the response to the crypto consumer. */
+static struct list_head cryptocop_completed_jobs;
+static spinlock_t cryptocop_completed_jobs_lock;
+
+DECLARE_WAIT_QUEUE_HEAD(cryptocop_ioc_process_wq);
+
+
+/** Local functions. **/
+
+static int cryptocop_open(struct inode *, struct file *);
+
+static int cryptocop_release(struct inode *, struct file *);
+
+static int cryptocop_ioctl(struct inode *inode, struct file *file,
+                          unsigned int cmd, unsigned long arg);
+
+static void cryptocop_start_job(void);
+
+static int cryptocop_job_queue_insert(cryptocop_queue_priority prio, struct 
cryptocop_operation *operation);
+static int cryptocop_job_setup(struct cryptocop_prio_job **pj, struct 
cryptocop_operation *operation);
+
+static int cryptocop_job_queue_init(void);
+static void cryptocop_job_queue_close(void);
+
+static int create_md5_pad(int alloc_flag, unsigned long long hashed_length, 
char **pad, size_t *pad_length);
+
+static int create_sha1_pad(int alloc_flag, unsigned long long hashed_length, 
char **pad, size_t *pad_length);
+
+static int transform_ok(struct cryptocop_transform_init *tinit);
+
+static struct cryptocop_session *get_session(cryptocop_session_id sid);
+
+static struct cryptocop_transform_ctx *get_transform_ctx(struct 
cryptocop_session *sess, cryptocop_tfrm_id tid);
+
+static void delete_internal_operation(struct cryptocop_int_operation *iop);
+
+static void get_aes_decrypt_key(unsigned char *dec_key, const unsigned  char 
*key, unsigned int keylength);
+
+static int init_stream_coprocessor(void);
+
+static void __exit exit_stream_coprocessor(void);
+
+/*#define LDEBUG*/
+#ifdef LDEBUG
+#define DEBUG(s) s
+#define DEBUG_API(s) s
+static void print_cryptocop_operation(struct cryptocop_operation *cop);
+static void print_dma_descriptors(struct cryptocop_int_operation *iop);
+static void print_strcop_crypto_op(struct strcop_crypto_op *cop);
+static void print_lock_status(void);
+static void print_user_dma_lists(struct cryptocop_dma_list_operation *dma_op);
+#define assert(s) do{if (!(s)) panic(#s);} while(0);
+#else
+#define DEBUG(s)
+#define DEBUG_API(s)
+#define assert(s)
+#endif
+
+
+/* Transform constants. */
+#define DES_BLOCK_LENGTH   (8)
+#define AES_BLOCK_LENGTH   (16)
+#define MD5_BLOCK_LENGTH   (64)
+#define SHA1_BLOCK_LENGTH  (64)
+#define CSUM_BLOCK_LENGTH  (2)
+#define MD5_STATE_LENGTH   (16)
+#define SHA1_STATE_LENGTH  (20)
+
+/* The device number. */
+#define CRYPTOCOP_MAJOR    (254)
+#define CRYPTOCOP_MINOR    (0)
+
+
+
+struct file_operations cryptocop_fops = {
+       owner: THIS_MODULE,
+       open: cryptocop_open,
+       release: cryptocop_release,
+       ioctl: cryptocop_ioctl
+};
+
+
+static void free_cdesc(struct cryptocop_dma_desc *cdesc)
+{
+       DEBUG(printk("free_cdesc: cdesc 0x%p, from_pool=%d\n", cdesc, 
cdesc->from_pool));
+       if (cdesc->free_buf) kfree(cdesc->free_buf);
+
+       if (cdesc->from_pool) {
+               unsigned long int flags;
+               spin_lock_irqsave(&descr_pool_lock, flags);
+               cdesc->next = descr_pool_free_list;
+               descr_pool_free_list = cdesc;
+               ++descr_pool_no_free;
+               spin_unlock_irqrestore(&descr_pool_lock, flags);
+       } else {
+               kfree(cdesc);
+       }
+}
+
+
+static struct cryptocop_dma_desc *alloc_cdesc(int alloc_flag)
+{
+       int use_pool = (alloc_flag & GFP_ATOMIC) ? 1 : 0;
+       struct cryptocop_dma_desc *cdesc;
+
+       if (use_pool) {
+               unsigned long int flags;
+               spin_lock_irqsave(&descr_pool_lock, flags);
+               if (!descr_pool_free_list) {
+                       spin_unlock_irqrestore(&descr_pool_lock, flags);
+                       DEBUG_API(printk("alloc_cdesc: pool is empty\n"));
+                       return NULL;
+               }
+               cdesc = descr_pool_free_list;
+               descr_pool_free_list = descr_pool_free_list->next;
+               --descr_pool_no_free;
+               spin_unlock_irqrestore(&descr_pool_lock, flags);
+               cdesc->from_pool = 1;
+       } else {
+               cdesc = kmalloc(sizeof(struct cryptocop_dma_desc), alloc_flag);
+               if (!cdesc) {
+                       DEBUG_API(printk("alloc_cdesc: kmalloc\n"));
+                       return NULL;
+               }
+               cdesc->from_pool = 0;
+       }
+       cdesc->dma_descr = (dma_descr_data*)(((unsigned long int)cdesc + 
offsetof(struct cryptocop_dma_desc, dma_descr_buf) + DESCR_ALLOC_PAD) & 
~0x0000001F);
+
+       cdesc->next = NULL;
+
+       cdesc->free_buf = NULL;
+       cdesc->dma_descr->out_eop = 0;
+       cdesc->dma_descr->in_eop = 0;
+       cdesc->dma_descr->intr = 0;
+       cdesc->dma_descr->eol = 0;
+       cdesc->dma_descr->wait = 0;
+       cdesc->dma_descr->buf = NULL;
+       cdesc->dma_descr->after = NULL;
+
+       DEBUG_API(printk("alloc_cdesc: return 0x%p, cdesc->dma_descr=0x%p, 
from_pool=%d\n", cdesc, cdesc->dma_descr, cdesc->from_pool));
+       return cdesc;
+}
+
+
+static void setup_descr_chain(struct cryptocop_dma_desc *cd)
+{
+       DEBUG(printk("setup_descr_chain: entering\n"));
+       while (cd) {
+               if (cd->next) {
+                       cd->dma_descr->next = 
(dma_descr_data*)virt_to_phys(cd->next->dma_descr);
+               } else {
+                       cd->dma_descr->next = NULL;
+               }
+               cd = cd->next;
+       }
+       DEBUG(printk("setup_descr_chain: exit\n"));
+}
+
+
+/* Create a pad descriptor for the transform.
+ * Return -1 for error, 0 if pad created. */
+static int create_pad_descriptor(struct cryptocop_tfrm_ctx *tc, struct 
cryptocop_dma_desc **pad_desc, int alloc_flag)
+{
+       struct cryptocop_dma_desc        *cdesc = NULL;
+       int                              error = 0;
+       struct strcop_meta_out           mo = {
+               .ciphsel = src_none,
+               .hashsel = src_none,
+               .csumsel = src_none
+       };
+       char                             *pad;
+       size_t                           plen;
+
+       DEBUG(printk("create_pad_descriptor: start.\n"));
+       /* Setup pad descriptor. */
+
+       DEBUG(printk("create_pad_descriptor: setting up padding.\n"));
+       cdesc = alloc_cdesc(alloc_flag);
+       if (!cdesc){
+               DEBUG_API(printk("create_pad_descriptor: alloc pad desc\n"));
+               goto error_cleanup;
+       }
+       switch (tc->unit_no) {
+       case src_md5:
+               error = create_md5_pad(alloc_flag, tc->consumed, &pad, &plen);
+               if (error){
+                       DEBUG_API(printk("create_pad_descriptor: 
create_md5_pad_failed\n"));
+                       goto error_cleanup;
+               }
+               cdesc->free_buf = pad;
+               mo.hashsel = src_dma;
+               mo.hashconf = tc->hash_conf;
+               mo.hashmode = tc->hash_mode;
+               break;
+       case src_sha1:
+               error = create_sha1_pad(alloc_flag, tc->consumed, &pad, &plen);
+               if (error){
+                       DEBUG_API(printk("create_pad_descriptor: 
create_sha1_pad_failed\n"));
+                       goto error_cleanup;
+               }
+               cdesc->free_buf = pad;
+               mo.hashsel = src_dma;
+               mo.hashconf = tc->hash_conf;
+               mo.hashmode = tc->hash_mode;
+               break;
+       case src_csum:
+               if (tc->consumed % tc->blocklength){
+                       pad = (char*)csum_zero_pad;
+                       plen = 1;
+               } else {
+                       pad = (char*)cdesc; /* Use any pointer. */
+                       plen = 0;
+               }
+               mo.csumsel = src_dma;
+               break;
+       }
+       cdesc->dma_descr->wait = 1;
+       cdesc->dma_descr->out_eop = 1; /* Since this is a pad output is pushed. 
 EOP is ok here since the padded unit is the only one active. */
+       cdesc->dma_descr->buf = (char*)virt_to_phys((char*)pad);
+       cdesc->dma_descr->after = cdesc->dma_descr->buf + plen;
+
+       cdesc->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct 
strcop_meta_out, mo);
+       *pad_desc = cdesc;
+
+       return 0;
+
+ error_cleanup:
+       if (cdesc) free_cdesc(cdesc);
+       return -1;
+}
+
+
+static int setup_key_dl_desc(struct cryptocop_tfrm_ctx *tc, struct 
cryptocop_dma_desc **kd, int alloc_flag)
+{
+       struct cryptocop_dma_desc  *key_desc = alloc_cdesc(alloc_flag);
+       struct strcop_meta_out     mo = {0};
+
+       DEBUG(printk("setup_key_dl_desc\n"));
+
+       if (!key_desc) {
+               DEBUG_API(printk("setup_key_dl_desc: failed descriptor 
allocation.\n"));
+               return -ENOMEM;
+       }
+
+       /* Download key. */
+       if ((tc->tctx->init.alg == cryptocop_alg_aes) && (tc->tcfg->flags & 
CRYPTOCOP_DECRYPT)) {
+               /* Precook the AES decrypt key. */
+               if (!tc->tctx->dec_key_set){
+                       get_aes_decrypt_key(tc->tctx->dec_key, 
tc->tctx->init.key, tc->tctx->init.keylen);
+                       tc->tctx->dec_key_set = 1;
+               }
+               key_desc->dma_descr->buf = 
(char*)virt_to_phys(tc->tctx->dec_key);
+               key_desc->dma_descr->after = key_desc->dma_descr->buf + 
tc->tctx->init.keylen/8;
+       } else {
+               key_desc->dma_descr->buf = 
(char*)virt_to_phys(tc->tctx->init.key);
+               key_desc->dma_descr->after = key_desc->dma_descr->buf + 
tc->tctx->init.keylen/8;
+       }
+       /* Setup metadata. */
+       mo.dlkey = 1;
+       switch (tc->tctx->init.keylen) {
+       case 64:
+               mo.decrypt = 0;
+               mo.hashmode = 0;
+               break;
+       case 128:
+               mo.decrypt = 0;
+               mo.hashmode = 1;
+               break;
+       case 192:
+               mo.decrypt = 1;
+               mo.hashmode = 0;
+               break;
+       case 256:
+               mo.decrypt = 1;
+               mo.hashmode = 1;
+               break;
+       default:
+               break;
+       }
+       mo.ciphsel = mo.hashsel = mo.csumsel = src_none;
+       key_desc->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct 
strcop_meta_out, mo);
+
+       key_desc->dma_descr->out_eop = 1;
+       key_desc->dma_descr->wait = 1;
+       key_desc->dma_descr->intr = 0;
+
+       *kd = key_desc;
+       return 0;
+}
+
+static int setup_cipher_iv_desc(struct cryptocop_tfrm_ctx *tc, struct 
cryptocop_dma_desc **id, int alloc_flag)
+{
+       struct cryptocop_dma_desc  *iv_desc = alloc_cdesc(alloc_flag);
+       struct strcop_meta_out     mo = {0};
+
+       DEBUG(printk("setup_cipher_iv_desc\n"));
+
+       if (!iv_desc) {
+               DEBUG_API(printk("setup_cipher_iv_desc: failed CBC IV 
descriptor allocation.\n"));
+               return -ENOMEM;
+       }
+       /* Download IV. */
+       iv_desc->dma_descr->buf = (char*)virt_to_phys(tc->tcfg->iv);
+       iv_desc->dma_descr->after = iv_desc->dma_descr->buf + tc->blocklength;
+
+       /* Setup metadata. */
+       mo.hashsel = mo.csumsel = src_none;
+       mo.ciphsel = src_dma;
+       mo.ciphconf = tc->ciph_conf;
+       mo.cbcmode = tc->cbcmode;
+
+       iv_desc->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct 
strcop_meta_out, mo);
+
+       iv_desc->dma_descr->out_eop = 0;
+       iv_desc->dma_descr->wait = 1;
+       iv_desc->dma_descr->intr = 0;
+
+       *id = iv_desc;
+       return 0;
+}
+
+/* Map the ouput length of the transform to operation output starting on the 
inject index. */
+static int create_input_descriptors(struct cryptocop_operation *operation, 
struct cryptocop_tfrm_ctx *tc, struct cryptocop_dma_desc **id, int alloc_flag)
+{
+       int                        err = 0;
+       struct cryptocop_dma_desc  head = {0};
+       struct cryptocop_dma_desc  *outdesc = &head;
+       size_t                     iov_offset = 0;
+       size_t                     out_ix = 0;
+       int                        outiov_ix = 0;
+       struct strcop_meta_in      mi = {0};
+
+       size_t                     out_length = tc->produced;
+       int                        rem_length;
+       int                        dlength;
+
+       assert(out_length != 0);
+       if (((tc->produced + tc->tcfg->inject_ix) > operation->tfrm_op.outlen) 
|| (tc->produced && (operation->tfrm_op.outlen == 0))) {
+               DEBUG_API(printk("create_input_descriptors: operation outdata 
too small\n"));
+               return -EINVAL;
+       }
+       /* Traverse the out iovec until the result inject index is reached. */
+       while ((outiov_ix < operation->tfrm_op.outcount) && ((out_ix + 
operation->tfrm_op.outdata[outiov_ix].iov_len) <= tc->tcfg->inject_ix)){
+               out_ix += operation->tfrm_op.outdata[outiov_ix].iov_len;
+               outiov_ix++;
+       }
+       if (outiov_ix >= operation->tfrm_op.outcount){
+               DEBUG_API(printk("create_input_descriptors: operation outdata 
too small\n"));
+               return -EINVAL;
+       }
+       iov_offset = tc->tcfg->inject_ix - out_ix;
+       mi.dmasel = tc->unit_no;
+
+       /* Setup the output descriptors. */
+       while ((out_length > 0) && (outiov_ix < operation->tfrm_op.outcount)) {
+               outdesc->next = alloc_cdesc(alloc_flag);
+               if (!outdesc->next) {
+                       DEBUG_API(printk("create_input_descriptors: 
alloc_cdesc\n"));
+                       err = -ENOMEM;
+                       goto error_cleanup;
+               }
+               outdesc = outdesc->next;
+               rem_length = operation->tfrm_op.outdata[outiov_ix].iov_len - 
iov_offset;
+               dlength = (out_length < rem_length) ? out_length : rem_length;
+
+               DEBUG(printk("create_input_descriptors:\n"
+                            "outiov_ix=%d, rem_length=%d, dlength=%d\n"
+                            "iov_offset=%d, outdata[outiov_ix].iov_len=%d\n"
+                            "outcount=%d, outiov_ix=%d\n",
+                            outiov_ix, rem_length, dlength, iov_offset, 
operation->tfrm_op.outdata[outiov_ix].iov_len, operation->tfrm_op.outcount, 
outiov_ix));
+
+               outdesc->dma_descr->buf = 
(char*)virt_to_phys(operation->tfrm_op.outdata[outiov_ix].iov_base + 
iov_offset);
+               outdesc->dma_descr->after = outdesc->dma_descr->buf + dlength;
+               outdesc->dma_descr->md = REG_TYPE_CONV(unsigned short int, 
struct strcop_meta_in, mi);
+
+               out_length -= dlength;
+               iov_offset += dlength;
+               if (iov_offset >= 
operation->tfrm_op.outdata[outiov_ix].iov_len) {
+                       iov_offset = 0;
+                       ++outiov_ix;
+               }
+       }
+       if (out_length > 0){
+               DEBUG_API(printk("create_input_descriptors: not enough room for 
output, %d remained\n", out_length));
+               err = -EINVAL;
+               goto error_cleanup;
+       }
+       /* Set sync in last descriptor. */
+       mi.sync = 1;
+       outdesc->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct 
strcop_meta_in, mi);
+
+       *id = head.next;
+       return 0;
+
+ error_cleanup:
+       while (head.next) {
+               outdesc = head.next->next;
+               free_cdesc(head.next);
+               head.next = outdesc;
+       }
+       return err;
+}
+
+
+static int create_output_descriptors(struct cryptocop_operation *operation, 
int *iniov_ix, int *iniov_offset, size_t desc_len, struct cryptocop_dma_desc 
**current_out_cdesc, struct strcop_meta_out *meta_out, int alloc_flag)
+{
+       while (desc_len != 0) {
+               struct cryptocop_dma_desc  *cdesc;
+               int                        rem_length = 
operation->tfrm_op.indata[*iniov_ix].iov_len - *iniov_offset;
+               int                        dlength = (desc_len < rem_length) ? 
desc_len : rem_length;
+
+               cdesc = alloc_cdesc(alloc_flag);
+               if (!cdesc) {
+                       DEBUG_API(printk("create_output_descriptors: 
alloc_cdesc\n"));
+                       return -ENOMEM;
+               }
+               (*current_out_cdesc)->next = cdesc;
+               (*current_out_cdesc) = cdesc;
+
+               cdesc->free_buf = NULL;
+
+               cdesc->dma_descr->buf = 
(char*)virt_to_phys(operation->tfrm_op.indata[*iniov_ix].iov_base + 
*iniov_offset);
+               cdesc->dma_descr->after = cdesc->dma_descr->buf + dlength;
+
+               desc_len -= dlength;
+               *iniov_offset += dlength;
+               assert(desc_len >= 0);
+               if (*iniov_offset >= 
operation->tfrm_op.indata[*iniov_ix].iov_len) {
+                       *iniov_offset = 0;
+                       ++(*iniov_ix);
+                       if (*iniov_ix > operation->tfrm_op.incount) {
+                               DEBUG_API(printk("create_output_descriptors: 
not enough indata in operation."));
+                               return  -EINVAL;
+                       }
+               }
+               cdesc->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct 
strcop_meta_out, (*meta_out));
+       } /* while (desc_len != 0) */
+       /* Last DMA descriptor gets a 'wait' bit to signal expected change in 
metadata. */
+       (*current_out_cdesc)->dma_descr->wait = 1; /* This will set extraneous 
WAIT in some situations, e.g. when padding hashes and checksums. */
+
+       return 0;
+}
+
+
+static int append_input_descriptors(struct cryptocop_operation *operation, 
struct cryptocop_dma_desc **current_in_cdesc, struct cryptocop_dma_desc 
**current_out_cdesc, struct cryptocop_tfrm_ctx *tc, int alloc_flag)
+{
+       DEBUG(printk("append_input_descriptors, tc=0x%p, unit_no=%d\n", tc, 
tc->unit_no));
+       if (tc->tcfg) {
+               int                        failed = 0;
+               struct cryptocop_dma_desc  *idescs = NULL;
+               DEBUG(printk("append_input_descriptors: pushing output, 
consumed %d produced %d bytes.\n", tc->consumed, tc->produced));
+               if (tc->pad_descs) {
+                       DEBUG(printk("append_input_descriptors: append pad 
descriptors to DMA out list.\n"));
+                       while (tc->pad_descs) {
+                               DEBUG(printk("append descriptor 0x%p\n", 
tc->pad_descs));
+                               (*current_out_cdesc)->next = tc->pad_descs;
+                               tc->pad_descs = tc->pad_descs->next;
+                               (*current_out_cdesc) = 
(*current_out_cdesc)->next;
+                       }
+               }
+
+               /* Setup and append output descriptors to DMA in list. */
+               if (tc->unit_no == src_dma){
+                       /* mem2mem.  Setup DMA in descriptors to discard all 
input prior to the requested mem2mem data. */
+                       struct strcop_meta_in mi = {.sync = 0, .dmasel = 
src_dma};
+                       unsigned int start_ix = tc->start_ix;
+                       while (start_ix){
+                               unsigned int desclen = start_ix < 
MEM2MEM_DISCARD_BUF_LENGTH ? start_ix : MEM2MEM_DISCARD_BUF_LENGTH;
+                               (*current_in_cdesc)->next = 
alloc_cdesc(alloc_flag);
+                               if (!(*current_in_cdesc)->next){
+                                       
DEBUG_API(printk("append_input_descriptors: alloc_cdesc mem2mem discard 
failed\n"));
+                                       return -ENOMEM;
+                               }
+                               (*current_in_cdesc) = (*current_in_cdesc)->next;
+                               (*current_in_cdesc)->dma_descr->buf = 
(char*)virt_to_phys(mem2mem_discard_buf);
+                               (*current_in_cdesc)->dma_descr->after = 
(*current_in_cdesc)->dma_descr->buf + desclen;
+                               (*current_in_cdesc)->dma_descr->md = 
REG_TYPE_CONV(unsigned short int, struct strcop_meta_in, mi);
+                               start_ix -= desclen;
+                       }
+                       mi.sync = 1;
+                       (*current_in_cdesc)->dma_descr->md = 
REG_TYPE_CONV(unsigned short int, struct strcop_meta_in, mi);
+               }
+
+               failed = create_input_descriptors(operation, tc, &idescs, 
alloc_flag);
+               if (failed){
+                       DEBUG_API(printk("append_input_descriptors: output 
descriptor setup failed\n"));
+                       return failed;
+               }
+               DEBUG(printk("append_input_descriptors: append output 
descriptors to DMA in list.\n"));
+               while (idescs) {
+                       DEBUG(printk("append descriptor 0x%p\n", idescs));
+                       (*current_in_cdesc)->next = idescs;
+                       idescs = idescs->next;
+                       (*current_in_cdesc) = (*current_in_cdesc)->next;
+               }
+       }
+       return 0;
+}
+
+
+
+static int cryptocop_setup_dma_list(struct cryptocop_operation *operation, 
struct cryptocop_int_operation **int_op, int alloc_flag)
+{
+       struct cryptocop_session *sess;
+       struct cryptocop_transform_ctx *tctx;
+
+       struct cryptocop_tfrm_ctx digest_ctx = {
+               .previous_src = src_none,
+               .current_src = src_none,
+               .start_ix = 0,
+               .requires_padding = 1,
+               .strict_block_length = 0,
+               .hash_conf = 0,
+               .hash_mode = 0,
+               .ciph_conf = 0,
+               .cbcmode = 0,
+               .decrypt = 0,
+               .consumed = 0,
+               .produced = 0,
+               .pad_descs = NULL,
+               .active = 0,
+               .done = 0,
+               .prev_src = NULL,
+               .curr_src = NULL,
+               .tcfg = NULL};
+       struct cryptocop_tfrm_ctx cipher_ctx = {
+               .previous_src = src_none,
+               .current_src = src_none,
+               .start_ix = 0,
+               .requires_padding = 0,
+               .strict_block_length = 1,
+               .hash_conf = 0,
+               .hash_mode = 0,
+               .ciph_conf = 0,
+               .cbcmode = 0,
+               .decrypt = 0,
+               .consumed = 0,
+               .produced = 0,
+               .pad_descs = NULL,
+               .active = 0,
+               .done = 0,
+               .prev_src = NULL,
+               .curr_src = NULL,
+               .tcfg = NULL};
+       struct cryptocop_tfrm_ctx csum_ctx = {
+               .previous_src = src_none,
+               .current_src = src_none,
+               .start_ix = 0,
+               .blocklength = 2,
+               .requires_padding = 1,
+               .strict_block_length = 0,
+               .hash_conf = 0,
+               .hash_mode = 0,
+               .ciph_conf = 0,
+               .cbcmode = 0,
+               .decrypt = 0,
+               .consumed = 0,
+               .produced = 0,
+               .pad_descs = NULL,
+               .active = 0,
+               .done = 0,
+               .tcfg = NULL,
+               .prev_src = NULL,
+               .curr_src = NULL,
+               .unit_no = src_csum};
+       struct cryptocop_tfrm_cfg *tcfg = operation->tfrm_op.tfrm_cfg;
+
+       unsigned int indata_ix = 0;
+
+       /* iovec accounting. */
+       int iniov_ix = 0;
+       int iniov_offset = 0;
+
+       /* Operation descriptor cfg traversal pointer. */
+       struct cryptocop_desc *odsc;
+
+       int failed = 0;
+       /* List heads for allocated descriptors. */
+       struct cryptocop_dma_desc out_cdesc_head = {0};
+       struct cryptocop_dma_desc in_cdesc_head = {0};
+
+       struct cryptocop_dma_desc *current_out_cdesc = &out_cdesc_head;
+       struct cryptocop_dma_desc *current_in_cdesc = &in_cdesc_head;
+
+       struct cryptocop_tfrm_ctx *output_tc = NULL;
+       void                      *iop_alloc_ptr;
+
+       assert(operation != NULL);
+       assert(int_op != NULL);
+
+       DEBUG(printk("cryptocop_setup_dma_list: start\n"));
+       DEBUG(print_cryptocop_operation(operation));
+
+       sess = get_session(operation->sid);
+       if (!sess) {
+               DEBUG_API(printk("cryptocop_setup_dma_list: no session found 
for operation.\n"));
+               failed = -EINVAL;
+               goto error_cleanup;
+       }
+       iop_alloc_ptr = kmalloc(DESCR_ALLOC_PAD + sizeof(struct 
cryptocop_int_operation), alloc_flag);
+       if (!iop_alloc_ptr) {
+               DEBUG_API(printk("cryptocop_setup_dma_list:  kmalloc 
cryptocop_int_operation\n"));
+               failed = -ENOMEM;
+               goto error_cleanup;
+       }
+       (*int_op) = (struct cryptocop_int_operation*)(((unsigned long 
int)(iop_alloc_ptr + DESCR_ALLOC_PAD + offsetof(struct cryptocop_int_operation, 
ctx_out)) & ~0x0000001F) - offsetof(struct cryptocop_int_operation, ctx_out));
+       DEBUG(memset((*int_op), 0xff, sizeof(struct cryptocop_int_operation)));
+       (*int_op)->alloc_ptr = iop_alloc_ptr;
+       DEBUG(printk("cryptocop_setup_dma_list: *int_op=0x%p, 
alloc_ptr=0x%p\n", *int_op, (*int_op)->alloc_ptr));
+
+       (*int_op)->sid = operation->sid;
+       (*int_op)->cdesc_out = NULL;
+       (*int_op)->cdesc_in = NULL;
+       (*int_op)->tdes_mode = cryptocop_3des_ede;
+       (*int_op)->csum_mode = cryptocop_csum_le;
+       (*int_op)->ddesc_out = NULL;
+       (*int_op)->ddesc_in = NULL;
+
+       /* Scan operation->tfrm_op.tfrm_cfg for bad configuration and set up 
the local contexts. */
+       if (!tcfg) {
+               DEBUG_API(printk("cryptocop_setup_dma_list: no configured 
transforms in operation.\n"));
+               failed = -EINVAL;
+               goto error_cleanup;
+       }
+       while (tcfg) {
+               tctx = get_transform_ctx(sess, tcfg->tid);
+               if (!tctx) {
+                       DEBUG_API(printk("cryptocop_setup_dma_list: no 
transform id %d in session.\n", tcfg->tid));
+                       failed = -EINVAL;
+                       goto error_cleanup;
+               }
+               if (tcfg->inject_ix > operation->tfrm_op.outlen){
+                       DEBUG_API(printk("cryptocop_setup_dma_list: transform 
id %d inject_ix (%d) > operation->tfrm_op.outlen(%d)", tcfg->tid, 
tcfg->inject_ix, operation->tfrm_op.outlen));
+                       failed = -EINVAL;
+                       goto error_cleanup;
+               }
+               switch (tctx->init.alg){
+               case cryptocop_alg_mem2mem:
+                       if (cipher_ctx.tcfg != NULL){
+                               DEBUG_API(printk("cryptocop_setup_dma_list: 
multiple ciphers in operation.\n"));
+                               failed = -EINVAL;
+                               goto error_cleanup;
+                       }
+                       /* mem2mem is handled as a NULL cipher. */
+                       cipher_ctx.cbcmode = 0;
+                       cipher_ctx.decrypt = 0;
+                       cipher_ctx.blocklength = 1;
+                       cipher_ctx.ciph_conf = 0;
+                       cipher_ctx.unit_no = src_dma;
+                       cipher_ctx.tcfg = tcfg;
+                       cipher_ctx.tctx = tctx;
+                       break;
+               case cryptocop_alg_des:
+               case cryptocop_alg_3des:
+               case cryptocop_alg_aes:
+                       /* cipher */
+                       if (cipher_ctx.tcfg != NULL){
+                               DEBUG_API(printk("cryptocop_setup_dma_list: 
multiple ciphers in operation.\n"));
+                               failed = -EINVAL;
+                               goto error_cleanup;
+                       }
+                       cipher_ctx.tcfg = tcfg;
+                       cipher_ctx.tctx = tctx;
+                       if (cipher_ctx.tcfg->flags & CRYPTOCOP_DECRYPT){
+                               cipher_ctx.decrypt = 1;
+                       }
+                       switch (tctx->init.cipher_mode) {
+                       case cryptocop_cipher_mode_ecb:
+                               cipher_ctx.cbcmode = 0;
+                               break;
+                       case cryptocop_cipher_mode_cbc:
+                               cipher_ctx.cbcmode = 1;
+                               break;
+                       default:
+                               DEBUG_API(printk("cryptocop_setup_dma_list: 
cipher_ctx, bad cipher mode==%d\n", tctx->init.cipher_mode));
+                               failed = -EINVAL;
+                               goto error_cleanup;
+                       }
+                       DEBUG(printk("cryptocop_setup_dma_list: cipher_ctx, set 
CBC mode==%d\n", cipher_ctx.cbcmode));
+                       switch (tctx->init.alg){
+                       case cryptocop_alg_des:
+                               cipher_ctx.ciph_conf = 0;
+                               cipher_ctx.unit_no = src_des;
+                               cipher_ctx.blocklength = DES_BLOCK_LENGTH;
+                               break;
+                       case cryptocop_alg_3des:
+                               cipher_ctx.ciph_conf = 1;
+                               cipher_ctx.unit_no = src_des;
+                               cipher_ctx.blocklength = DES_BLOCK_LENGTH;
+                               break;
+                       case cryptocop_alg_aes:
+                               cipher_ctx.ciph_conf = 2;
+                               cipher_ctx.unit_no = src_aes;
+                               cipher_ctx.blocklength = AES_BLOCK_LENGTH;
+                               break;
+                       default:
+                               panic("cryptocop_setup_dma_list: impossible 
algorithm %d\n", tctx->init.alg);
+                       }
+                       (*int_op)->tdes_mode = tctx->init.tdes_mode;
+                       break;
+               case cryptocop_alg_md5:
+               case cryptocop_alg_sha1:
+                       /* digest */
+                       if (digest_ctx.tcfg != NULL){
+                               DEBUG_API(printk("cryptocop_setup_dma_list: 
multiple digests in operation.\n"));
+                               failed = -EINVAL;
+                               goto error_cleanup;
+                       }
+                       digest_ctx.tcfg = tcfg;
+                       digest_ctx.tctx = tctx;
+                       digest_ctx.hash_mode = 0; /* Don't use explicit IV in 
this API. */
+                       switch (tctx->init.alg){
+                       case cryptocop_alg_md5:
+                               digest_ctx.blocklength = MD5_BLOCK_LENGTH;
+                               digest_ctx.unit_no = src_md5;
+                               digest_ctx.hash_conf = 1; /* 1 => MD-5 */
+                               break;
+                       case cryptocop_alg_sha1:
+                               digest_ctx.blocklength = SHA1_BLOCK_LENGTH;
+                               digest_ctx.unit_no = src_sha1;
+                               digest_ctx.hash_conf = 0; /* 0 => SHA-1 */
+                               break;
+                       default:
+                               panic("cryptocop_setup_dma_list: impossible 
digest algorithm\n");
+                       }
+                       break;
+               case cryptocop_alg_csum:
+                       /* digest */
+                       if (csum_ctx.tcfg != NULL){
+                               DEBUG_API(printk("cryptocop_setup_dma_list: 
multiple checksums in operation.\n"));
+                               failed = -EINVAL;
+                               goto error_cleanup;
+                       }
+                       (*int_op)->csum_mode = tctx->init.csum_mode;
+                       csum_ctx.tcfg = tcfg;
+                       csum_ctx.tctx = tctx;
+                       break;
+               default:
+                       /* no algorithm. */
+                       DEBUG_API(printk("cryptocop_setup_dma_list: invalid 
algorithm %d specified in tfrm %d.\n", tctx->init.alg, tcfg->tid));
+                       failed = -EINVAL;
+                       goto error_cleanup;
+               }
+               tcfg = tcfg->next;
+       }
+       /* Download key if a cipher is used. */
+       if (cipher_ctx.tcfg && (cipher_ctx.tctx->init.alg != 
cryptocop_alg_mem2mem)){
+               struct cryptocop_dma_desc  *key_desc = NULL;
+
+               failed = setup_key_dl_desc(&cipher_ctx, &key_desc, alloc_flag);
+               if (failed) {
+                       DEBUG_API(printk("cryptocop_setup_dma_list: setup key 
dl\n"));
+                       goto error_cleanup;
+               }
+               current_out_cdesc->next = key_desc;
+               current_out_cdesc = key_desc;
+               indata_ix += (unsigned int)(key_desc->dma_descr->after - 
key_desc->dma_descr->buf);
+
+               /* Download explicit IV if a cipher is used and CBC mode and 
explicit IV selected. */
+               if ((cipher_ctx.tctx->init.cipher_mode == 
cryptocop_cipher_mode_cbc) && (cipher_ctx.tcfg->flags & CRYPTOCOP_EXPLICIT_IV)) 
{
+                       struct cryptocop_dma_desc  *iv_desc = NULL;
+
+                       DEBUG(printk("cryptocop_setup_dma_list: setup cipher 
CBC IV descriptor.\n"));
+
+                       failed = setup_cipher_iv_desc(&cipher_ctx, &iv_desc, 
alloc_flag);
+                       if (failed) {
+                               DEBUG_API(printk("cryptocop_setup_dma_list: CBC 
IV descriptor.\n"));
+                               goto error_cleanup;
+                       }
+                       current_out_cdesc->next = iv_desc;
+                       current_out_cdesc = iv_desc;
+                       indata_ix += (unsigned int)(iv_desc->dma_descr->after - 
iv_desc->dma_descr->buf);
+               }
+       }
+
+       /* Process descriptors. */
+       odsc = operation->tfrm_op.desc;
+       while (odsc) {
+               struct cryptocop_desc_cfg   *dcfg = odsc->cfg;
+               struct strcop_meta_out      meta_out = {0};
+               size_t                      desc_len = odsc->length;
+               int                         active_count, eop_needed_count;
+
+               output_tc = NULL;
+
+               DEBUG(printk("cryptocop_setup_dma_list: parsing an operation 
descriptor\n"));
+
+               while (dcfg) {
+                       struct cryptocop_tfrm_ctx  *tc = NULL;
+
+                       DEBUG(printk("cryptocop_setup_dma_list: parsing an 
operation descriptor configuration.\n"));
+                       /* Get the local context for the transform and mark it 
as the output unit if it produces output. */
+                       if (digest_ctx.tcfg && (digest_ctx.tcfg->tid == 
dcfg->tid)){
+                               tc = &digest_ctx;
+                       } else if (cipher_ctx.tcfg && (cipher_ctx.tcfg->tid == 
dcfg->tid)){
+                               tc = &cipher_ctx;
+                       } else if (csum_ctx.tcfg && (csum_ctx.tcfg->tid == 
dcfg->tid)){
+                               tc = &csum_ctx;
+                       }
+                       if (!tc) {
+                               DEBUG_API(printk("cryptocop_setup_dma_list: 
invalid transform %d specified in descriptor.\n", dcfg->tid));
+                               failed = -EINVAL;
+                               goto error_cleanup;
+                       }
+                       if (tc->done) {
+                               DEBUG_API(printk("cryptocop_setup_dma_list: 
completed transform %d reused.\n", dcfg->tid));
+                               failed = -EINVAL;
+                               goto error_cleanup;
+                       }
+                       if (!tc->active) {
+                               tc->start_ix = indata_ix;
+                               tc->active = 1;
+                       }
+
+                       tc->previous_src = tc->current_src;
+                       tc->prev_src = tc->curr_src;
+                       /* Map source unit id to DMA source config. */
+                       switch (dcfg->src){
+                       case cryptocop_source_dma:
+                               tc->current_src = src_dma;
+                               break;
+                       case cryptocop_source_des:
+                               tc->current_src = src_des;
+                               break;
+                       case cryptocop_source_3des:
+                               tc->current_src = src_des;
+                               break;
+                       case cryptocop_source_aes:
+                               tc->current_src = src_aes;
+                               break;
+                       case cryptocop_source_md5:
+                       case cryptocop_source_sha1:
+                       case cryptocop_source_csum:
+                       case cryptocop_source_none:
+                       default:
+                               /* We do not allow using accumulating style 
units (SHA-1, MD5, checksum) as sources to other units.
+                                */
+                               DEBUG_API(printk("cryptocop_setup_dma_list: bad 
unit source configured %d.\n", dcfg->src));
+                               failed = -EINVAL;
+                               goto error_cleanup;
+                       }
+                       if (tc->current_src != src_dma) {
+                               /* Find the unit we are sourcing from. */
+                               if (digest_ctx.unit_no == tc->current_src){
+                                       tc->curr_src = &digest_ctx;
+                               } else if (cipher_ctx.unit_no == 
tc->current_src){
+                                       tc->curr_src = &cipher_ctx;
+                               } else if (csum_ctx.unit_no == tc->current_src){
+                                       tc->curr_src = &csum_ctx;
+                               }
+                               if ((tc->curr_src == tc) && (tc->unit_no != 
src_dma)){
+                                       
DEBUG_API(printk("cryptocop_setup_dma_list: unit %d configured to source from 
itself.\n", tc->unit_no));
+                                       failed = -EINVAL;
+                                       goto error_cleanup;
+                               }
+                       } else {
+                               tc->curr_src = NULL;
+                       }
+
+                       /* Detect source switch. */
+                       DEBUG(printk("cryptocop_setup_dma_list: tc->active=%d 
tc->unit_no=%d tc->current_src=%d tc->previous_src=%d, tc->curr_src=0x%p, 
tc->prev_srv=0x%p\n", tc->active, tc->unit_no, tc->current_src, 
tc->previous_src, tc->curr_src, tc->prev_src));
+                       if (tc->active && (tc->current_src != 
tc->previous_src)) {
+                               /* Only allow source switch when both the old 
source unit and the new one have
+                                * no pending data to process (i.e. the 
consumed length must be a multiple of the
+                                * transform blocklength). */
+                               /* Note: if the src == NULL we are actually 
sourcing from DMA out. */
+                               if (((tc->prev_src != NULL) && 
(tc->prev_src->consumed % tc->prev_src->blocklength)) ||
+                                   ((tc->curr_src != NULL) && 
(tc->curr_src->consumed % tc->curr_src->blocklength)))
+                               {
+                                       
DEBUG_API(printk("cryptocop_setup_dma_list: can only disconnect from or connect 
to a unit on a multiple of the blocklength, old: cons=%d, prod=%d, block=%d, 
new: cons=%d prod=%d, block=%d.\n", tc->prev_src ? tc->prev_src->consumed : 
INT_MIN, tc->prev_src ? tc->prev_src->produced : INT_MIN, tc->prev_src ? 
tc->prev_src->blocklength : INT_MIN, tc->curr_src ? tc->curr_src->consumed : 
INT_MIN, tc->curr_src ? tc->curr_src->produced : INT_MIN, tc->curr_src ? 
tc->curr_src->blocklength : INT_MIN));
+                                       failed = -EINVAL;
+                                       goto error_cleanup;
+                               }
+                       }
+                       /* Detect unit deactivation. */
+                       if (dcfg->last) {
+                               /* Length check of this is handled below. */
+                               tc->done = 1;
+                       }
+                       dcfg = dcfg->next;
+               } /* while (dcfg) */
+               DEBUG(printk("cryptocop_setup_dma_list: parsing operation 
descriptor configuration complete.\n"));
+
+               if (cipher_ctx.active && (cipher_ctx.curr_src != NULL) && 
!cipher_ctx.curr_src->active){
+                       DEBUG_API(printk("cryptocop_setup_dma_list: cipher 
source from inactive unit %d\n", cipher_ctx.curr_src->unit_no));
+                       failed = -EINVAL;
+                       goto error_cleanup;
+               }
+               if (digest_ctx.active && (digest_ctx.curr_src != NULL) && 
!digest_ctx.curr_src->active){
+                       DEBUG_API(printk("cryptocop_setup_dma_list: digest 
source from inactive unit %d\n", digest_ctx.curr_src->unit_no));
+                       failed = -EINVAL;
+                       goto error_cleanup;
+               }
+               if (csum_ctx.active && (csum_ctx.curr_src != NULL) && 
!csum_ctx.curr_src->active){
+                       DEBUG_API(printk("cryptocop_setup_dma_list: cipher 
source from inactive unit %d\n", csum_ctx.curr_src->unit_no));
+                       failed = -EINVAL;
+                       goto error_cleanup;
+               }
+
+               /* Update consumed and produced lengths.
+
+                  The consumed length accounting here is actually cheating.  
If a unit source from DMA (or any
+                  other unit that process data in blocks of one octet) it is 
correct, but if it source from a
+                  block processing unit, i.e. a cipher, it will be temporarily 
incorrect at some times.  However
+                  since it is only allowed--by the HW--to change source to or 
from a block processing unit at times where that
+                  unit has processed an exact multiple of its block length the 
end result will be correct.
+                  Beware that if the source change restriction change this 
code will need to be (much) reworked.
+               */
+               DEBUG(printk("cryptocop_setup_dma_list: desc->length=%d, 
desc_len=%d.\n", odsc->length, desc_len));
+
+               if (csum_ctx.active) {
+                       csum_ctx.consumed += desc_len;
+                       if (csum_ctx.done) {
+                               csum_ctx.produced = 2;
+                       }
+                       DEBUG(printk("cryptocop_setup_dma_list: csum_ctx 
producing: consumed=%d, produced=%d, blocklength=%d.\n", csum_ctx.consumed, 
csum_ctx.produced, csum_ctx.blocklength));
+               }
+               if (digest_ctx.active) {
+                       digest_ctx.consumed += desc_len;
+                       if (digest_ctx.done) {
+                               if (digest_ctx.unit_no == src_md5) {
+                                       digest_ctx.produced = MD5_STATE_LENGTH;
+                               } else {
+                                       digest_ctx.produced = SHA1_STATE_LENGTH;
+                               }
+                       }
+                       DEBUG(printk("cryptocop_setup_dma_list: digest_ctx 
producing: consumed=%d, produced=%d, blocklength=%d.\n", digest_ctx.consumed, 
digest_ctx.produced, digest_ctx.blocklength));
+               }
+               if (cipher_ctx.active) {
+                       /* Ciphers are allowed only to source from DMA out.  
That is filtered above. */
+                       assert(cipher_ctx.current_src == src_dma);
+                       cipher_ctx.consumed += desc_len;
+                       cipher_ctx.produced = cipher_ctx.blocklength * 
(cipher_ctx.consumed / cipher_ctx.blocklength);
+                       if (cipher_ctx.cbcmode && !(cipher_ctx.tcfg->flags & 
CRYPTOCOP_EXPLICIT_IV) && cipher_ctx.produced){
+                               cipher_ctx.produced -= cipher_ctx.blocklength; 
/* Compensate for CBC iv. */
+                       }
+                       DEBUG(printk("cryptocop_setup_dma_list: cipher_ctx 
producing: consumed=%d, produced=%d, blocklength=%d.\n", cipher_ctx.consumed, 
cipher_ctx.produced, cipher_ctx.blocklength));
+               }
+
+               /* Setup the DMA out descriptors. */
+               /* Configure the metadata. */
+               active_count = 0;
+               eop_needed_count = 0;
+               if (cipher_ctx.active) {
+                       ++active_count;
+                       if (cipher_ctx.unit_no == src_dma){
+                               /* mem2mem */
+                               meta_out.ciphsel = src_none;
+                       } else {
+                               meta_out.ciphsel = cipher_ctx.current_src;
+                       }
+                       meta_out.ciphconf = cipher_ctx.ciph_conf;
+                       meta_out.cbcmode = cipher_ctx.cbcmode;
+                       meta_out.decrypt = cipher_ctx.decrypt;
+                       DEBUG(printk("set ciphsel=%d ciphconf=%d cbcmode=%d 
decrypt=%d\n", meta_out.ciphsel, meta_out.ciphconf, meta_out.cbcmode, 
meta_out.decrypt));
+                       if (cipher_ctx.done) ++eop_needed_count;
+               } else {
+                       meta_out.ciphsel = src_none;
+               }
+
+               if (digest_ctx.active) {
+                       ++active_count;
+                       meta_out.hashsel = digest_ctx.current_src;
+                       meta_out.hashconf = digest_ctx.hash_conf;
+                       meta_out.hashmode = 0; /* Explicit mode is not used 
here. */
+                       DEBUG(printk("set hashsel=%d hashconf=%d 
hashmode=%d\n", meta_out.hashsel, meta_out.hashconf, meta_out.hashmode));
+                       if (digest_ctx.done) {
+                               assert(digest_ctx.pad_descs == NULL);
+                               failed = create_pad_descriptor(&digest_ctx, 
&digest_ctx.pad_descs, alloc_flag);
+                               if (failed) {
+                                       
DEBUG_API(printk("cryptocop_setup_dma_list: failed digest pad creation.\n"));
+                                       goto error_cleanup;
+                               }
+                       }
+               } else {
+                       meta_out.hashsel = src_none;
+               }
+
+               if (csum_ctx.active) {
+                       ++active_count;
+                       meta_out.csumsel = csum_ctx.current_src;
+                       if (csum_ctx.done) {
+                               assert(csum_ctx.pad_descs == NULL);
+                               failed = create_pad_descriptor(&csum_ctx, 
&csum_ctx.pad_descs, alloc_flag);
+                               if (failed) {
+                                       
DEBUG_API(printk("cryptocop_setup_dma_list: failed csum pad creation.\n"));
+                                       goto error_cleanup;
+                               }
+                       }
+               } else {
+                       meta_out.csumsel = src_none;
+               }
+               DEBUG(printk("cryptocop_setup_dma_list: %d eop needed, %d 
active units\n", eop_needed_count, active_count));
+               /* Setup DMA out descriptors for the indata. */
+               failed = create_output_descriptors(operation, &iniov_ix, 
&iniov_offset, desc_len, &current_out_cdesc, &meta_out, alloc_flag);
+               if (failed) {
+                       DEBUG_API(printk("cryptocop_setup_dma_list: 
create_output_descriptors %d\n", failed));
+                       goto error_cleanup;
+               }
+               /* Setup out EOP.  If there are active units that are not done 
here they cannot get an EOP
+                * so we ust setup a zero length descriptor to DMA to signal 
EOP only to done units.
+                * If there is a pad descriptor EOP for the padded unit will be 
EOPed by it.
+                */
+               assert(active_count >= eop_needed_count);
+               assert((eop_needed_count == 0) || (eop_needed_count == 1));
+               if (eop_needed_count) {
+                       /* This means that the bulk operation (cipeher/m2m) is 
terminated. */
+                       if (active_count > 1) {
+                               /* Use zero length EOP descriptor. */
+                               struct cryptocop_dma_desc *ed = 
alloc_cdesc(alloc_flag);
+                               struct strcop_meta_out    ed_mo = {0};
+                               if (!ed) {
+                                       
DEBUG_API(printk("cryptocop_setup_dma_list: alloc EOP descriptor for 
cipher\n"));
+                                       failed = -ENOMEM;
+                                       goto error_cleanup;
+                               }
+
+                               assert(cipher_ctx.active && cipher_ctx.done);
+
+                               if (cipher_ctx.unit_no == src_dma){
+                                       /* mem2mem */
+                                       ed_mo.ciphsel = src_none;
+                               } else {
+                                       ed_mo.ciphsel = cipher_ctx.current_src;
+                               }
+                               ed_mo.ciphconf = cipher_ctx.ciph_conf;
+                               ed_mo.cbcmode = cipher_ctx.cbcmode;
+                               ed_mo.decrypt = cipher_ctx.decrypt;
+
+                               ed->free_buf = NULL;
+                               ed->dma_descr->wait = 1;
+                               ed->dma_descr->out_eop = 1;
+
+                               ed->dma_descr->buf = (char*)virt_to_phys(&ed); 
/* Use any valid physical address for zero length descriptor. */
+                               ed->dma_descr->after = ed->dma_descr->buf;
+                               ed->dma_descr->md = REG_TYPE_CONV(unsigned 
short int, struct strcop_meta_out, ed_mo);
+                               current_out_cdesc->next = ed;
+                               current_out_cdesc = ed;
+                       } else {
+                               /* Set EOP in the current out descriptor since 
the only active module is
+                                * the one needing the EOP. */
+
+                               current_out_cdesc->dma_descr->out_eop = 1;
+                       }
+               }
+
+               if (cipher_ctx.done && cipher_ctx.active) cipher_ctx.active = 0;
+               if (digest_ctx.done && digest_ctx.active) digest_ctx.active = 0;
+               if (csum_ctx.done && csum_ctx.active) csum_ctx.active = 0;
+               indata_ix += odsc->length;
+               odsc = odsc->next;
+       } /* while (odsc) */ /* Process descriptors. */
+       DEBUG(printk("cryptocop_setup_dma_list: done parsing operation 
descriptors\n"));
+       if (cipher_ctx.tcfg && (cipher_ctx.active || !cipher_ctx.done)){
+               DEBUG_API(printk("cryptocop_setup_dma_list: cipher operation 
not terminated.\n"));
+               failed = -EINVAL;
+               goto error_cleanup;
+       }
+       if (digest_ctx.tcfg && (digest_ctx.active || !digest_ctx.done)){
+               DEBUG_API(printk("cryptocop_setup_dma_list: digest operation 
not terminated.\n"));
+               failed = -EINVAL;
+               goto error_cleanup;
+       }
+       if (csum_ctx.tcfg && (csum_ctx.active || !csum_ctx.done)){
+               DEBUG_API(printk("cryptocop_setup_dma_list: csum operation not 
terminated.\n"));
+               failed = -EINVAL;
+               goto error_cleanup;
+       }
+
+       failed = append_input_descriptors(operation, &current_in_cdesc, 
&current_out_cdesc, &cipher_ctx, alloc_flag);
+       if (failed){
+               DEBUG_API(printk("cryptocop_setup_dma_list: 
append_input_descriptors cipher_ctx %d\n", failed));
+               goto error_cleanup;
+       }
+       failed = append_input_descriptors(operation, &current_in_cdesc, 
&current_out_cdesc, &digest_ctx, alloc_flag);
+       if (failed){
+               DEBUG_API(printk("cryptocop_setup_dma_list: 
append_input_descriptors cipher_ctx %d\n", failed));
+               goto error_cleanup;
+       }
+       failed = append_input_descriptors(operation, &current_in_cdesc, 
&current_out_cdesc, &csum_ctx, alloc_flag);
+       if (failed){
+               DEBUG_API(printk("cryptocop_setup_dma_list: 
append_input_descriptors cipher_ctx %d\n", failed));
+               goto error_cleanup;
+       }
+
+       DEBUG(printk("cryptocop_setup_dma_list: int_op=0x%p, *int_op=0x%p\n", 
int_op, *int_op));
+       (*int_op)->cdesc_out = out_cdesc_head.next;
+       (*int_op)->cdesc_in = in_cdesc_head.next;
+       DEBUG(printk("cryptocop_setup_dma_list: out_cdesc_head=0x%p 
in_cdesc_head=0x%p\n", (*int_op)->cdesc_out, (*int_op)->cdesc_in));
+
+       setup_descr_chain(out_cdesc_head.next);
+       setup_descr_chain(in_cdesc_head.next);
+
+       /* Last but not least: mark the last DMA in descriptor for a INTR and 
EOL and the the
+        * last DMA out descriptor for EOL.
+        */
+       current_in_cdesc->dma_descr->intr = 1;
+       current_in_cdesc->dma_descr->eol = 1;
+       current_out_cdesc->dma_descr->eol = 1;
+
+       /* Setup DMA contexts. */
+       (*int_op)->ctx_out.next = NULL;
+       (*int_op)->ctx_out.eol = 1;
+       (*int_op)->ctx_out.intr = 0;
+       (*int_op)->ctx_out.store_mode = 0;
+       (*int_op)->ctx_out.en = 0;
+       (*int_op)->ctx_out.dis = 0;
+       (*int_op)->ctx_out.md0 = 0;
+       (*int_op)->ctx_out.md1 = 0;
+       (*int_op)->ctx_out.md2 = 0;
+       (*int_op)->ctx_out.md3 = 0;
+       (*int_op)->ctx_out.md4 = 0;
+       (*int_op)->ctx_out.saved_data = 
(dma_descr_data*)virt_to_phys((*int_op)->cdesc_out->dma_descr);
+       (*int_op)->ctx_out.saved_data_buf = 
(*int_op)->cdesc_out->dma_descr->buf; /* Already physical address. */
+
+       (*int_op)->ctx_in.next = NULL;
+       (*int_op)->ctx_in.eol = 1;
+       (*int_op)->ctx_in.intr = 0;
+       (*int_op)->ctx_in.store_mode = 0;
+       (*int_op)->ctx_in.en = 0;
+       (*int_op)->ctx_in.dis = 0;
+       (*int_op)->ctx_in.md0 = 0;
+       (*int_op)->ctx_in.md1 = 0;
+       (*int_op)->ctx_in.md2 = 0;
+       (*int_op)->ctx_in.md3 = 0;
+       (*int_op)->ctx_in.md4 = 0;
+
+       (*int_op)->ctx_in.saved_data = 
(dma_descr_data*)virt_to_phys((*int_op)->cdesc_in->dma_descr);
+       (*int_op)->ctx_in.saved_data_buf = (*int_op)->cdesc_in->dma_descr->buf; 
/* Already physical address. */
+
+       DEBUG(printk("cryptocop_setup_dma_list: done\n"));
+       return 0;
+
+error_cleanup:
+       {
+               /* Free all allocated resources. */
+               struct cryptocop_dma_desc *tmp_cdesc;
+               while (digest_ctx.pad_descs){
+                       tmp_cdesc = digest_ctx.pad_descs->next;
+                       free_cdesc(digest_ctx.pad_descs);
+                       digest_ctx.pad_descs = tmp_cdesc;
+               }
+               while (csum_ctx.pad_descs){
+                       tmp_cdesc = csum_ctx.pad_descs->next;
+                       free_cdesc(csum_ctx.pad_descs);
+                       csum_ctx.pad_descs = tmp_cdesc;
+               }
+               assert(cipher_ctx.pad_descs == NULL); /* The ciphers are never 
padded. */
+
+               if (*int_op != NULL) delete_internal_operation(*int_op);
+       }
+       DEBUG_API(printk("cryptocop_setup_dma_list: done with error %d\n", 
failed));
+       return failed;
+}
+
+
+static void delete_internal_operation(struct cryptocop_int_operation *iop)
+{
+       void                      *ptr = iop->alloc_ptr;
+       struct cryptocop_dma_desc *cd = iop->cdesc_out;
+       struct cryptocop_dma_desc *next;
+
+       DEBUG(printk("delete_internal_operation: iop=0x%p, alloc_ptr=0x%p\n", 
iop, ptr));
+
+       while (cd) {
+               next = cd->next;
+               free_cdesc(cd);
+               cd = next;
+       }
+       cd = iop->cdesc_in;
+       while (cd) {
+               next = cd->next;
+               free_cdesc(cd);
+               cd = next;
+       }
+       kfree(ptr);
+}
+
+#define MD5_MIN_PAD_LENGTH (9)
+#define MD5_PAD_LENGTH_FIELD_LENGTH (8)
+
+static int create_md5_pad(int alloc_flag, unsigned long long hashed_length, 
char **pad, size_t *pad_length)
+{
+       size_t                  padlen = MD5_BLOCK_LENGTH - (hashed_length % 
MD5_BLOCK_LENGTH);
+       unsigned char           *p;
+       int                     i;
+       unsigned long long int  bit_length = hashed_length << 3;
+
+       if (padlen < MD5_MIN_PAD_LENGTH) padlen += MD5_BLOCK_LENGTH;
+
+       p = kmalloc(padlen, alloc_flag);
+       if (!pad) return -ENOMEM;
+
+       *p = 0x80;
+       memset(p+1, 0, padlen - 1);
+
+       DEBUG(printk("create_md5_pad: hashed_length=%lld bits == %lld bytes\n", 
bit_length, hashed_length));
+
+       i = padlen - MD5_PAD_LENGTH_FIELD_LENGTH;
+       while (bit_length != 0){
+               p[i++] = bit_length % 0x100;
+               bit_length >>= 8;
+       }
+
+       *pad = (char*)p;
+       *pad_length = padlen;
+
+       return 0;
+}
+
+#define SHA1_MIN_PAD_LENGTH (9)
+#define SHA1_PAD_LENGTH_FIELD_LENGTH (8)
+
+static int create_sha1_pad(int alloc_flag, unsigned long long hashed_length, 
char **pad, size_t *pad_length)
+{
+       size_t                  padlen = SHA1_BLOCK_LENGTH - (hashed_length % 
SHA1_BLOCK_LENGTH);
+       unsigned char           *p;
+       int                     i;
+       unsigned long long int  bit_length = hashed_length << 3;
+
+       if (padlen < SHA1_MIN_PAD_LENGTH) padlen += SHA1_BLOCK_LENGTH;
+
+       p = kmalloc(padlen, alloc_flag);
+       if (!pad) return -ENOMEM;
+
+       *p = 0x80;
+       memset(p+1, 0, padlen - 1);
+
+       DEBUG(printk("create_sha1_pad: hashed_length=%lld bits == %lld 
bytes\n", bit_length, hashed_length));
+
+       i = padlen - 1;
+       while (bit_length != 0){
+               p[i--] = bit_length % 0x100;
+               bit_length >>= 8;
+       }
+
+       *pad = (char*)p;
+       *pad_length = padlen;
+
+       return 0;
+}
+
+
+static int transform_ok(struct cryptocop_transform_init *tinit)
+{
+       switch (tinit->alg){
+       case cryptocop_alg_csum:
+               switch (tinit->csum_mode){
+               case cryptocop_csum_le:
+               case cryptocop_csum_be:
+                       break;
+               default:
+                       DEBUG_API(printk("transform_ok: Bad mode set for csum 
transform\n"));
+                       return -EINVAL;
+               }
+       case cryptocop_alg_mem2mem:
+       case cryptocop_alg_md5:
+       case cryptocop_alg_sha1:
+               if (tinit->keylen != 0) {
+                       DEBUG_API(printk("transform_ok: non-zero keylength, %d, 
for a digest/csum algorithm\n", tinit->keylen));
+                       return -EINVAL; /* This check is a bit strict. */
+               }
+               break;
+       case cryptocop_alg_des:
+               if (tinit->keylen != 64) {
+                       DEBUG_API(printk("transform_ok: keylen %d invalid for 
DES\n", tinit->keylen));
+                       return -EINVAL;
+               }
+               break;
+       case cryptocop_alg_3des:
+               if (tinit->keylen != 192) {
+                       DEBUG_API(printk("transform_ok: keylen %d invalid for 
3DES\n", tinit->keylen));
+                       return -EINVAL;
+               }
+               break;
+       case cryptocop_alg_aes:
+               if (tinit->keylen != 128 && tinit->keylen != 192 && 
tinit->keylen != 256) {
+                       DEBUG_API(printk("transform_ok: keylen %d invalid for 
AES\n", tinit->keylen));
+                       return -EINVAL;
+               }
+               break;
+       case cryptocop_no_alg:
+       default:
+               DEBUG_API(printk("transform_ok: no such algorithm %d\n", 
tinit->alg));
+               return -EINVAL;
+       }
+
+       switch (tinit->alg){
+       case cryptocop_alg_des:
+       case cryptocop_alg_3des:
+       case cryptocop_alg_aes:
+               if (tinit->cipher_mode != cryptocop_cipher_mode_ecb && 
tinit->cipher_mode != cryptocop_cipher_mode_cbc) return -EINVAL;
+       default:
+                break;
+       }
+       return 0;
+}
+
+
+int cryptocop_new_session(cryptocop_session_id *sid, struct 
cryptocop_transform_init *tinit, int alloc_flag)
+{
+       struct cryptocop_session         *sess;
+       struct cryptocop_transform_init  *tfrm_in = tinit;
+       struct cryptocop_transform_init  *tmp_in;
+       int                              no_tfrms = 0;
+       int                              i;
+       unsigned long int                flags;
+
+       init_stream_coprocessor(); /* For safety if we are called early */
+
+       while (tfrm_in){
+               int err;
+               ++no_tfrms;
+               if ((err = transform_ok(tfrm_in))) {
+                       DEBUG_API(printk("cryptocop_new_session, bad 
transform\n"));
+                       return err;
+               }
+               tfrm_in = tfrm_in->next;
+       }
+       if (0 == no_tfrms) {
+               DEBUG_API(printk("cryptocop_new_session, no transforms 
specified\n"));
+               return -EINVAL;
+       }
+
+       sess = kmalloc(sizeof(struct cryptocop_session), alloc_flag);
+       if (!sess){
+               DEBUG_API(printk("cryptocop_new_session, kmalloc 
cryptocop_session\n"));
+               return -ENOMEM;
+       }
+
+       sess->tfrm_ctx = kmalloc(no_tfrms * sizeof(struct 
cryptocop_transform_ctx), alloc_flag);
+       if (!sess->tfrm_ctx) {
+               DEBUG_API(printk("cryptocop_new_session, kmalloc 
cryptocop_transform_ctx\n"));
+               kfree(sess);
+               return -ENOMEM;
+       }
+
+       tfrm_in = tinit;
+       for (i = 0; i < no_tfrms; i++){
+               tmp_in = tfrm_in->next;
+               while (tmp_in){
+                       if (tmp_in->tid == tfrm_in->tid) {
+                               DEBUG_API(printk("cryptocop_new_session, 
duplicate transform ids\n"));
+                               kfree(sess->tfrm_ctx);
+                               kfree(sess);
+                               return -EINVAL;
+                       }
+                       tmp_in = tmp_in->next;
+               }
+               memcpy(&sess->tfrm_ctx[i].init, tfrm_in, sizeof(struct 
cryptocop_transform_init));
+               sess->tfrm_ctx[i].dec_key_set = 0;
+               sess->tfrm_ctx[i].next = &sess->tfrm_ctx[i] + 1;
+
+               tfrm_in = tfrm_in->next;
+       }
+       sess->tfrm_ctx[i-1].next = NULL;
+
+       spin_lock_irqsave(&cryptocop_sessions_lock, flags);
+       sess->sid = next_sid;
+       next_sid++;
+       /* TODO If we are really paranoid we should do duplicate check to 
handle sid wraparound.
+        *      OTOH 2^64 is a really large number of session. */
+       if (next_sid == 0) next_sid = 1;
+
+       /* Prepend to session list. */
+       sess->next = cryptocop_sessions;
+       cryptocop_sessions = sess;
+       spin_unlock_irqrestore(&cryptocop_sessions_lock, flags);
+       *sid = sess->sid;
+       return 0;
+}
+
+
+int cryptocop_free_session(cryptocop_session_id sid)
+{
+       struct cryptocop_transform_ctx    *tc;
+       struct cryptocop_session          *sess = NULL;
+       struct cryptocop_session          *psess = NULL;
+       unsigned long int                 flags;
+       int                               i;
+       LIST_HEAD(remove_list);
+       struct list_head                  *node, *tmp;
+       struct cryptocop_prio_job         *pj;
+
+       DEBUG(printk("cryptocop_free_session: sid=%lld\n", sid));
+
+       spin_lock_irqsave(&cryptocop_sessions_lock, flags);
+       sess = cryptocop_sessions;
+       while (sess && sess->sid != sid){
+               psess = sess;
+               sess = sess->next;
+       }
+       if (sess){
+               if (psess){
+                       psess->next = sess->next;
+               } else {
+                       cryptocop_sessions = sess->next;
+               }
+       }
+       spin_unlock_irqrestore(&cryptocop_sessions_lock, flags);
+
+       if (!sess) return -EINVAL;
+
+       /* Remove queued jobs. */
+       spin_lock_irqsave(&cryptocop_job_queue_lock, flags);
+
+       for (i = 0; i < cryptocop_prio_no_prios; i++){
+               if (!list_empty(&(cryptocop_job_queues[i].jobs))){
+                       list_for_each_safe(node, tmp, 
&(cryptocop_job_queues[i].jobs)) {
+                               pj = list_entry(node, struct 
cryptocop_prio_job, node);
+                               if (pj->oper->sid == sid) {
+                                       list_move_tail(node, &remove_list);
+                               }
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&cryptocop_job_queue_lock, flags);
+
+       list_for_each_safe(node, tmp, &remove_list) {
+               list_del(node);
+               pj = list_entry(node, struct cryptocop_prio_job, node);
+               pj->oper->operation_status = -EAGAIN;  /* EAGAIN is not ideal 
for job/session terminated but it's the best choice I know of. */
+               DEBUG(printk("cryptocop_free_session: pj=0x%p, pj->oper=0x%p, 
pj->iop=0x%p\n", pj, pj->oper, pj->iop));
+               pj->oper->cb(pj->oper, pj->oper->cb_data);
+               delete_internal_operation(pj->iop);
+               kfree(pj);
+       }
+
+       tc = sess->tfrm_ctx;
+       /* Erase keying data. */
+       while (tc){
+               DEBUG(printk("cryptocop_free_session: memset keys, tfrm 
id=%d\n", tc->init.tid));
+               memset(tc->init.key, 0xff, CRYPTOCOP_MAX_KEY_LENGTH);
+               memset(tc->dec_key, 0xff, CRYPTOCOP_MAX_KEY_LENGTH);
+               tc = tc->next;
+       }
+       kfree(sess->tfrm_ctx);
+       kfree(sess);
+
+       return 0;
+}
+
+static struct cryptocop_session *get_session(cryptocop_session_id sid)
+{
+       struct cryptocop_session    *sess;
+       unsigned long int           flags;
+
+       spin_lock_irqsave(&cryptocop_sessions_lock, flags);
+       sess = cryptocop_sessions;
+       while (sess && (sess->sid != sid)){
+               sess = sess->next;
+       }
+       spin_unlock_irqrestore(&cryptocop_sessions_lock, flags);
+
+       return sess;
+}
+
+static struct cryptocop_transform_ctx *get_transform_ctx(struct 
cryptocop_session *sess, cryptocop_tfrm_id tid)
+{
+       struct cryptocop_transform_ctx *tc = sess->tfrm_ctx;
+
+       DEBUG(printk("get_transform_ctx, sess=0x%p, tid=%d\n", sess, tid));
+       assert(sess != NULL);
+       while (tc && tc->init.tid != tid){
+               DEBUG(printk("tc=0x%p, tc->next=0x%p\n", tc, tc->next));
+               tc = tc->next;
+       }
+       DEBUG(printk("get_transform_ctx, returning tc=0x%p\n", tc));
+       return tc;
+}
+
+
+
+/* The AES s-transform matrix (s-box). */
+static const u8 aes_sbox[256] = {
+       99,  124, 119, 123, 242, 107, 111, 197, 48,  1,   103, 43,  254, 215, 
171, 118,
+       202, 130, 201, 125, 250, 89,  71,  240, 173, 212, 162, 175, 156, 164, 
114, 192,
+       183, 253, 147, 38,  54,  63,  247, 204, 52,  165, 229, 241, 113, 216, 
49,  21,
+       4,   199, 35,  195, 24,  150, 5,   154, 7,   18,  128, 226, 235, 39,  
178, 117,
+       9,   131, 44,  26,  27,  110, 90,  160, 82,  59,  214, 179, 41,  227, 
47,  132,
+       83,  209, 0,   237, 32,  252, 177, 91,  106, 203, 190, 57,  74,  76,  
88,  207,
+       208, 239, 170, 251, 67,  77,  51,  133, 69,  249, 2,   127, 80,  60,  
159, 168,
+       81,  163, 64,  143, 146, 157, 56,  245, 188, 182, 218, 33,  16,  255, 
243, 210,
+       205, 12,  19,  236, 95,  151, 68,  23,  196, 167, 126, 61,  100, 93,  
25,  115,
+       96,  129, 79,  220, 34,  42,  144, 136, 70,  238, 184, 20,  222, 94,  
11,  219,
+       224, 50,  58,  10,  73,  6,   36,  92,  194, 211, 172, 98,  145, 149, 
228, 121,
+       231, 200, 55,  109, 141, 213, 78,  169, 108, 86,  244, 234, 101, 122, 
174, 8,
+       186, 120, 37,  46,  28,  166, 180, 198, 232, 221, 116, 31,  75,  189, 
139, 138,
+       112, 62,  181, 102, 72,  3,   246, 14,  97,  53,  87,  185, 134, 193, 
29,  158,
+       225, 248, 152, 17,  105, 217, 142, 148, 155, 30,  135, 233, 206, 85,  
40,  223,
+       140, 161, 137, 13,  191, 230, 66,  104, 65,  153, 45,  15,  176, 84,  
187, 22
+};
+
+/* AES has a 32 bit word round constants for each round in the
+ * key schedule.  round_constant[i] is really Rcon[i+1] in FIPS187.
+ */
+static u32 round_constant[11] = {
+       0x01000000, 0x02000000, 0x04000000, 0x08000000,
+       0x10000000, 0x20000000, 0x40000000, 0x80000000,
+       0x1B000000, 0x36000000, 0x6C000000
+};
+
+/* Apply the s-box to each of the four occtets in w. */
+static u32 aes_ks_subword(const u32 w)
+{
+       u8 bytes[4];
+
+       *(u32*)(&bytes[0]) = w;
+       bytes[0] = aes_sbox[bytes[0]];
+       bytes[1] = aes_sbox[bytes[1]];
+       bytes[2] = aes_sbox[bytes[2]];
+       bytes[3] = aes_sbox[bytes[3]];
+       return *(u32*)(&bytes[0]);
+}
+
+/* The encrypt (forward) Rijndael key schedule algorithm pseudo code:
+ * (Note that AES words are 32 bit long)
+ *
+ * KeyExpansion(byte key[4*Nk], word w[Nb*(Nr+1)], Nk){
+ * word temp
+ * i = 0
+ * while (i < Nk) {
+ *   w[i] = word(key[4*i, 4*i + 1, 4*i + 2, 4*i + 3])
+ *   i = i + 1
+ * }
+ * i = Nk
+ *
+ * while (i < (Nb * (Nr + 1))) {
+ *   temp = w[i - 1]
+ *   if ((i mod Nk) == 0) {
+ *     temp = SubWord(RotWord(temp)) xor Rcon[i/Nk]
+ *   }
+ *   else if ((Nk > 6) && ((i mod Nk) == 4)) {
+ *     temp = SubWord(temp)
+ *   }
+ *   w[i] = w[i - Nk] xor temp
+ * }
+ * RotWord(t) does a 8 bit cyclic shift left on a 32 bit word.
+ * SubWord(t) applies the AES s-box individually to each octet
+ * in a 32 bit word.
+ *
+ * For AES Nk can have the values 4, 6, and 8 (corresponding to
+ * values for Nr of 10, 12, and 14).  Nb is always 4.
+ *
+ * To construct w[i], w[i - 1] and w[i - Nk] must be
+ * available.  Consequently we must keep a state of the last Nk words
+ * to be able to create the last round keys.
+ */
+static void get_aes_decrypt_key(unsigned char *dec_key, const unsigned  char 
*key, unsigned int keylength)
+{
+       u32 temp;
+       u32 w_ring[8]; /* nk is max 8, use elements 0..(nk - 1) as a ringbuffer 
*/
+       u8  w_last_ix;
+       int i;
+       u8  nr, nk;
+
+       switch (keylength){
+       case 128:
+               nk = 4;
+               nr = 10;
+               break;
+       case 192:
+               nk = 6;
+               nr = 12;
+               break;
+       case 256:
+               nk = 8;
+               nr = 14;
+               break;
+       default:
+               panic("stream co-processor: bad aes key length in 
get_aes_decrypt_key\n");
+       };
+
+       /* Need to do host byte order correction here since key is byte 
oriented and the
+        * kx algorithm is word (u32) oriented. */
+       for (i = 0; i < nk; i+=1) {
+               w_ring[i] = be32_to_cpu(*(u32*)&key[4*i]);
+       }
+
+       i = (int)nk;
+       w_last_ix = i - 1;
+       while (i < (4 * (nr + 2))) {
+               temp = w_ring[w_last_ix];
+               if (!(i % nk)) {
+                       /* RotWord(temp) */
+                       temp = (temp << 8) | (temp >> 24);
+                       temp = aes_ks_subword(temp);
+                       temp ^= round_constant[i/nk - 1];
+               } else if ((nk > 6) && ((i % nk) == 4)) {
+                       temp = aes_ks_subword(temp);
+               }
+               w_last_ix = (w_last_ix + 1) % nk; /* This is the same as (i-Nk) 
mod Nk */
+               temp ^= w_ring[w_last_ix];
+               w_ring[w_last_ix] = temp;
+
+               /* We need the round keys for round Nr+1 and Nr+2 (round key
+                * Nr+2 is the round key beyond the last one used when
+                * encrypting).  Rounds are numbered starting from 0, Nr=10
+                * implies 11 rounds are used in encryption/decryption.
+                */
+               if (i >= (4 * nr)) {
+                       /* Need to do host byte order correction here, the key
+                        * is byte oriented. */
+                       *(u32*)dec_key = cpu_to_be32(temp);
+                       dec_key += 4;
+               }
+               ++i;
+       }
+}
+
+
+/**** Job/operation management. ****/
+
+int cryptocop_job_queue_insert_csum(struct cryptocop_operation *operation)
+{
+       return cryptocop_job_queue_insert(cryptocop_prio_kernel_csum, 
operation);
+}
+
+int cryptocop_job_queue_insert_crypto(struct cryptocop_operation *operation)
+{
+       return cryptocop_job_queue_insert(cryptocop_prio_kernel, operation);
+}
+
+int cryptocop_job_queue_insert_user_job(struct cryptocop_operation *operation)
+{
+       return cryptocop_job_queue_insert(cryptocop_prio_user, operation);
+}
+
+static int cryptocop_job_queue_insert(cryptocop_queue_priority prio, struct 
cryptocop_operation *operation)
+{
+       int                           ret;
+       struct cryptocop_prio_job     *pj = NULL;
+       unsigned long int             flags;
+
+       DEBUG(printk("cryptocop_job_queue_insert(%d, 0x%p)\n", prio, 
operation));
+
+       if (!operation || !operation->cb){
+               DEBUG_API(printk("cryptocop_job_queue_insert oper=0x%p, NULL 
operation or callback\n", operation));
+               return -EINVAL;
+       }
+
+       if ((ret = cryptocop_job_setup(&pj, operation)) != 0){
+               DEBUG_API(printk("cryptocop_job_queue_insert: job setup 
failed\n"));
+               return ret;
+       }
+       assert(pj != NULL);
+
+       spin_lock_irqsave(&cryptocop_job_queue_lock, flags);
+       list_add_tail(&pj->node, &cryptocop_job_queues[prio].jobs);
+       spin_unlock_irqrestore(&cryptocop_job_queue_lock, flags);
+
+       /* Make sure a job is running */
+       cryptocop_start_job();
+       return 0;
+}
+
+static void cryptocop_do_tasklet(unsigned long unused);
+DECLARE_TASKLET (cryptocop_tasklet, cryptocop_do_tasklet, 0);
+
+static void cryptocop_do_tasklet(unsigned long unused)
+{
+       struct list_head             *node;
+       struct cryptocop_prio_job    *pj = NULL;
+       unsigned long                flags;
+
+       DEBUG(printk("cryptocop_do_tasklet: entering\n"));
+
+       do {
+               spin_lock_irqsave(&cryptocop_completed_jobs_lock, flags);
+               if (!list_empty(&cryptocop_completed_jobs)){
+                       node = cryptocop_completed_jobs.next;
+                       list_del(node);
+                       pj = list_entry(node, struct cryptocop_prio_job, node);
+               } else {
+                       pj = NULL;
+               }
+               spin_unlock_irqrestore(&cryptocop_completed_jobs_lock, flags);
+               if (pj) {
+                       assert(pj->oper != NULL);
+
+                       /* Notify consumer of operation completeness. */
+                       DEBUG(printk("cryptocop_do_tasklet: callback 0x%p, data 
0x%p\n", pj->oper->cb, pj->oper->cb_data));
+
+                       pj->oper->operation_status = 0; /* Job is completed. */
+                       pj->oper->cb(pj->oper, pj->oper->cb_data);
+                       delete_internal_operation(pj->iop);
+                       kfree(pj);
+               }
+       } while (pj != NULL);
+
+       DEBUG(printk("cryptocop_do_tasklet: exiting\n"));
+}
+
+static irqreturn_t
+dma_done_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+       struct cryptocop_prio_job *done_job;
+       reg_dma_rw_ack_intr ack_intr = {
+               .data = 1,
+       };
+
+       REG_WR (dma, regi_dma9, rw_ack_intr, ack_intr);
+
+       DEBUG(printk("cryptocop DMA done\n"));
+
+       spin_lock(&running_job_lock);
+       if (cryptocop_running_job == NULL){
+               printk("stream co-processor got interrupt when not busy\n");
+               spin_unlock(&running_job_lock);
+               return IRQ_HANDLED;
+       }
+       done_job = cryptocop_running_job;
+       cryptocop_running_job = NULL;
+       spin_unlock(&running_job_lock);
+
+       /* Start processing a job. */
+       if (!spin_trylock(&cryptocop_process_lock)){
+               DEBUG(printk("cryptocop irq handler, not starting a job\n"));
+       } else {
+               cryptocop_start_job();
+               spin_unlock(&cryptocop_process_lock);
+       }
+
+       done_job->oper->operation_status = 0; /* Job is completed. */
+       if (done_job->oper->fast_callback){
+               /* This operation wants callback from interrupt. */
+               done_job->oper->cb(done_job->oper, done_job->oper->cb_data);
+               delete_internal_operation(done_job->iop);
+               kfree(done_job);
+       } else {
+               spin_lock(&cryptocop_completed_jobs_lock);
+               list_add_tail(&(done_job->node), &cryptocop_completed_jobs);
+               spin_unlock(&cryptocop_completed_jobs_lock);
+               tasklet_schedule(&cryptocop_tasklet);
+       }
+
+       DEBUG(printk("cryptocop leave irq handler\n"));
+       return IRQ_HANDLED;
+}
+
+
+/* Setup interrupts and DMA channels. */
+static int init_cryptocop(void)
+{
+       unsigned long          flags;
+       reg_intr_vect_rw_mask  intr_mask;
+       reg_dma_rw_cfg         dma_cfg = {.en = 1};
+       reg_dma_rw_intr_mask   intr_mask_in = {.data = regk_dma_yes}; /* Only 
want descriptor interrupts from the DMA in channel. */
+       reg_dma_rw_ack_intr    ack_intr = {.data = 1,.in_eop = 1 };
+       reg_strcop_rw_cfg      strcop_cfg = {
+               .ipend = regk_strcop_little,
+               .td1 = regk_strcop_e,
+               .td2 = regk_strcop_d,
+               .td3 = regk_strcop_e,
+               .ignore_sync = 0,
+               .en = 1
+       };
+
+       if (request_irq(DMA9_INTR_VECT, dma_done_interrupt, 0, "stream 
co-processor DMA", NULL)) panic("request_irq stream co-processor irq dma9");
+
+       (void)crisv32_request_dma(8, "strcop", DMA_PANIC_ON_ERROR, 0, dma_strp);
+       (void)crisv32_request_dma(9, "strcop", DMA_PANIC_ON_ERROR, 0, dma_strp);
+
+       local_irq_save(flags);
+
+       /* Reset and enable the cryptocop. */
+       strcop_cfg.en = 0;
+       REG_WR(strcop, regi_strcop, rw_cfg, strcop_cfg);
+       strcop_cfg.en = 1;
+       REG_WR(strcop, regi_strcop, rw_cfg, strcop_cfg);
+
+       /* Enable DMA9 interrupt */
+       intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
+       intr_mask.dma9 = 1;
+       REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
+
+       /* Enable DMAs. */
+       REG_WR(dma, regi_dma9, rw_cfg, dma_cfg); /* input DMA */
+       REG_WR(dma, regi_dma8, rw_cfg, dma_cfg); /* output DMA */
+
+       /* Set up wordsize = 4 for DMAs. */
+       DMA_WR_CMD (regi_dma8, regk_dma_set_w_size4);
+       DMA_WR_CMD (regi_dma9, regk_dma_set_w_size4);
+
+       /* Enable interrupts. */
+       REG_WR(dma, regi_dma9, rw_intr_mask, intr_mask_in);
+
+       /* Clear intr ack. */
+       REG_WR(dma, regi_dma9, rw_ack_intr, ack_intr);
+
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+/* Free used cryptocop hw resources (interrupt and DMA channels). */
+static void release_cryptocop(void)
+{
+       unsigned long          flags;
+       reg_intr_vect_rw_mask  intr_mask;
+       reg_dma_rw_cfg         dma_cfg = {.en = 0};
+       reg_dma_rw_intr_mask   intr_mask_in = {0};
+       reg_dma_rw_ack_intr    ack_intr = {.data = 1,.in_eop = 1 };
+
+       local_irq_save(flags);
+
+       /* Clear intr ack. */
+       REG_WR(dma, regi_dma9, rw_ack_intr, ack_intr);
+
+       /* Disable DMA9 interrupt */
+       intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
+       intr_mask.dma9 = 0;
+       REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
+
+       /* Disable DMAs. */
+       REG_WR(dma, regi_dma9, rw_cfg, dma_cfg); /* input DMA */
+       REG_WR(dma, regi_dma8, rw_cfg, dma_cfg); /* output DMA */
+
+       /* Disable interrupts. */
+       REG_WR(dma, regi_dma9, rw_intr_mask, intr_mask_in);
+
+       local_irq_restore(flags);
+
+       free_irq(DMA9_INTR_VECT, NULL);
+
+       (void)crisv32_free_dma(8);
+       (void)crisv32_free_dma(9);
+}
+
+
+/* Init job queue. */
+static int cryptocop_job_queue_init(void)
+{
+       int i;
+
+       INIT_LIST_HEAD(&cryptocop_completed_jobs);
+
+       for (i = 0; i < cryptocop_prio_no_prios; i++){
+               cryptocop_job_queues[i].prio = (cryptocop_queue_priority)i;
+               INIT_LIST_HEAD(&cryptocop_job_queues[i].jobs);
+       }
+       return 0;
+}
+
+
+static void cryptocop_job_queue_close(void)
+{
+       struct list_head               *node, *tmp;
+       struct cryptocop_prio_job      *pj = NULL;
+       unsigned long int              process_flags, flags;
+       int                            i;
+
+       /* FIXME: This is as yet untested code. */
+
+       /* Stop strcop from getting an operation to process while we are 
closing the
+          module. */
+       spin_lock_irqsave(&cryptocop_process_lock, process_flags);
+
+       /* Empty the job queue. */
+       spin_lock_irqsave(&cryptocop_process_lock, process_flags);
+       for (i = 0; i < cryptocop_prio_no_prios; i++){
+               if (!list_empty(&(cryptocop_job_queues[i].jobs))){
+                       list_for_each_safe(node, tmp, 
&(cryptocop_job_queues[i].jobs)) {
+                               pj = list_entry(node, struct 
cryptocop_prio_job, node);
+                               list_del(node);
+
+                               /* Call callback to notify consumer of job 
removal. */
+                               DEBUG(printk("cryptocop_job_queue_close: 
callback 0x%p, data 0x%p\n", pj->oper->cb, pj->oper->cb_data));
+                               pj->oper->operation_status = -EINTR; /* Job is 
terminated without completion. */
+                               pj->oper->cb(pj->oper, pj->oper->cb_data);
+
+                               delete_internal_operation(pj->iop);
+                               kfree(pj);
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&cryptocop_process_lock, process_flags);
+
+       /* Remove the running job, if any. */
+       spin_lock_irqsave(&running_job_lock, flags);
+       if (cryptocop_running_job){
+               reg_strcop_rw_cfg rw_cfg;
+               reg_dma_rw_cfg    dma_out_cfg, dma_in_cfg;
+
+               /* Stop DMA. */
+               dma_out_cfg = REG_RD(dma, regi_dma8, rw_cfg);
+               dma_out_cfg.en = regk_dma_no;
+               REG_WR(dma, regi_dma8, rw_cfg, dma_out_cfg);
+
+               dma_in_cfg = REG_RD(dma, regi_dma9, rw_cfg);
+               dma_in_cfg.en = regk_dma_no;
+               REG_WR(dma, regi_dma9, rw_cfg, dma_in_cfg);
+
+               /* Disble the cryptocop. */
+               rw_cfg = REG_RD(strcop, regi_strcop, rw_cfg);
+               rw_cfg.en = 0;
+               REG_WR(strcop, regi_strcop, rw_cfg, rw_cfg);
+
+               pj = cryptocop_running_job;
+               cryptocop_running_job = NULL;
+
+               /* Call callback to notify consumer of job removal. */
+               DEBUG(printk("cryptocop_job_queue_close: callback 0x%p, data 
0x%p\n", pj->oper->cb, pj->oper->cb_data));
+               pj->oper->operation_status = -EINTR; /* Job is terminated 
without completion. */
+               pj->oper->cb(pj->oper, pj->oper->cb_data);
+
+               delete_internal_operation(pj->iop);
+               kfree(pj);
+       }
+       spin_unlock_irqrestore(&running_job_lock, flags);
+
+       /* Remove completed jobs, if any. */
+       spin_lock_irqsave(&cryptocop_completed_jobs_lock, flags);
+
+       list_for_each_safe(node, tmp, &cryptocop_completed_jobs) {
+               pj = list_entry(node, struct cryptocop_prio_job, node);
+               list_del(node);
+               /* Call callback to notify consumer of job removal. */
+               DEBUG(printk("cryptocop_job_queue_close: callback 0x%p, data 
0x%p\n", pj->oper->cb, pj->oper->cb_data));
+               pj->oper->operation_status = -EINTR; /* Job is terminated 
without completion. */
+               pj->oper->cb(pj->oper, pj->oper->cb_data);
+
+               delete_internal_operation(pj->iop);
+               kfree(pj);
+       }
+       spin_unlock_irqrestore(&cryptocop_completed_jobs_lock, flags);
+}
+
+
+static void cryptocop_start_job(void)
+{
+       int                          i;
+       struct cryptocop_prio_job    *pj;
+       unsigned long int            flags;
+       unsigned long int            running_job_flags;
+       reg_strcop_rw_cfg            rw_cfg = {.en = 1, .ignore_sync = 0};
+
+       DEBUG(printk("cryptocop_start_job: entering\n"));
+
+       spin_lock_irqsave(&running_job_lock, running_job_flags);
+       if (cryptocop_running_job != NULL){
+               /* Already running. */
+               DEBUG(printk("cryptocop_start_job: already running, exit\n"));
+               spin_unlock_irqrestore(&running_job_lock, running_job_flags);
+               return;
+       }
+       spin_lock_irqsave(&cryptocop_job_queue_lock, flags);
+
+       /* Check the queues in priority order. */
+       for (i = cryptocop_prio_kernel_csum; (i < cryptocop_prio_no_prios) && 
list_empty(&cryptocop_job_queues[i].jobs); i++);
+       if (i == cryptocop_prio_no_prios) {
+               spin_unlock_irqrestore(&cryptocop_job_queue_lock, flags);
+               spin_unlock_irqrestore(&running_job_lock, running_job_flags);
+               DEBUG(printk("cryptocop_start_job: no jobs to run\n"));
+               return; /* No jobs to run */
+       }
+       DEBUG(printk("starting job for prio %d\n", i));
+
+       /* TODO: Do not starve lower priority jobs.  Let in a lower
+        * prio job for every N-th processed higher prio job or some
+        * other scheduling policy.  This could reasonably be
+        * tweakable since the optimal balance would depend on the
+        * type of load on the system. */
+
+       /* Pull the DMA lists from the job and start the DMA client. */
+       pj = list_entry(cryptocop_job_queues[i].jobs.next, struct 
cryptocop_prio_job, node);
+       list_del(&pj->node);
+       spin_unlock_irqrestore(&cryptocop_job_queue_lock, flags);
+       cryptocop_running_job = pj;
+
+       /* Set config register (3DES and CSUM modes). */
+       switch (pj->iop->tdes_mode){
+       case cryptocop_3des_eee:
+               rw_cfg.td1 = regk_strcop_e;
+               rw_cfg.td2 = regk_strcop_e;
+               rw_cfg.td3 = regk_strcop_e;
+               break;
+       case cryptocop_3des_eed:
+               rw_cfg.td1 = regk_strcop_e;
+               rw_cfg.td2 = regk_strcop_e;
+               rw_cfg.td3 = regk_strcop_d;
+               break;
+       case cryptocop_3des_ede:
+               rw_cfg.td1 = regk_strcop_e;
+               rw_cfg.td2 = regk_strcop_d;
+               rw_cfg.td3 = regk_strcop_e;
+               break;
+       case cryptocop_3des_edd:
+               rw_cfg.td1 = regk_strcop_e;
+               rw_cfg.td2 = regk_strcop_d;
+               rw_cfg.td3 = regk_strcop_d;
+               break;
+       case cryptocop_3des_dee:
+               rw_cfg.td1 = regk_strcop_d;
+               rw_cfg.td2 = regk_strcop_e;
+               rw_cfg.td3 = regk_strcop_e;
+               break;
+       case cryptocop_3des_ded:
+               rw_cfg.td1 = regk_strcop_d;
+               rw_cfg.td2 = regk_strcop_e;
+               rw_cfg.td3 = regk_strcop_d;
+               break;
+       case cryptocop_3des_dde:
+               rw_cfg.td1 = regk_strcop_d;
+               rw_cfg.td2 = regk_strcop_d;
+               rw_cfg.td3 = regk_strcop_e;
+               break;
+       case cryptocop_3des_ddd:
+               rw_cfg.td1 = regk_strcop_d;
+               rw_cfg.td2 = regk_strcop_d;
+               rw_cfg.td3 = regk_strcop_d;
+               break;
+       default:
+               DEBUG(printk("cryptocop_setup_dma_list: bad 3DES mode\n"));
+       }
+       switch (pj->iop->csum_mode){
+       case cryptocop_csum_le:
+               rw_cfg.ipend = regk_strcop_little;
+               break;
+       case cryptocop_csum_be:
+               rw_cfg.ipend = regk_strcop_big;
+               break;
+       default:
+               DEBUG(printk("cryptocop_setup_dma_list: bad checksum mode\n"));
+       }
+       REG_WR(strcop, regi_strcop, rw_cfg, rw_cfg);
+
+       DEBUG(printk("cryptocop_start_job: starting DMA, new 
cryptocop_running_job=0x%p\n"
+                    "ctx_in: 0x%p, phys: 0x%p\n"
+                    "ctx_out: 0x%p, phys: 0x%p\n",
+                    pj,
+                    &pj->iop->ctx_in, (char*)virt_to_phys(&pj->iop->ctx_in),
+                    &pj->iop->ctx_out, 
(char*)virt_to_phys(&pj->iop->ctx_out)));
+
+       /* Start input DMA. */
+       DMA_START_CONTEXT(regi_dma9, virt_to_phys(&pj->iop->ctx_in));
+
+       /* Start output DMA. */
+       DMA_START_CONTEXT(regi_dma8, virt_to_phys(&pj->iop->ctx_out));
+
+       spin_unlock_irqrestore(&running_job_lock, running_job_flags);
+       DEBUG(printk("cryptocop_start_job: exiting\n"));
+}
+
+
+static int cryptocop_job_setup(struct cryptocop_prio_job **pj, struct 
cryptocop_operation *operation)
+{
+       int  err;
+       int  alloc_flag = operation->in_interrupt ? GFP_ATOMIC : GFP_KERNEL;
+       void *iop_alloc_ptr = NULL;
+
+       *pj = kmalloc(sizeof (struct cryptocop_prio_job), alloc_flag);
+       if (!*pj) return -ENOMEM;
+
+       DEBUG(printk("cryptocop_job_setup: operation=0x%p\n", operation));
+
+       (*pj)->oper = operation;
+       DEBUG(printk("cryptocop_job_setup, cb=0x%p cb_data=0x%p\n",  
(*pj)->oper->cb, (*pj)->oper->cb_data));
+
+       if (operation->use_dmalists) {
+               DEBUG(print_user_dma_lists(&operation->list_op));
+               if (!operation->list_op.inlist || !operation->list_op.outlist 
|| !operation->list_op.out_data_buf || !operation->list_op.in_data_buf){
+                       DEBUG_API(printk("cryptocop_job_setup: bad indata 
(use_dmalists)\n"));
+                       kfree(*pj);
+                       return -EINVAL;
+               }
+               iop_alloc_ptr = kmalloc(DESCR_ALLOC_PAD + sizeof(struct 
cryptocop_int_operation), alloc_flag);
+               if (!iop_alloc_ptr) {
+                       DEBUG_API(printk("cryptocop_job_setup: kmalloc 
cryptocop_int_operation\n"));
+                       kfree(*pj);
+                       return -ENOMEM;
+               }
+               (*pj)->iop = (struct cryptocop_int_operation*)(((unsigned long 
int)(iop_alloc_ptr + DESCR_ALLOC_PAD + offsetof(struct cryptocop_int_operation, 
ctx_out)) & ~0x0000001F) - offsetof(struct cryptocop_int_operation, ctx_out));
+               DEBUG(memset((*pj)->iop, 0xff, sizeof(struct 
cryptocop_int_operation)));
+               (*pj)->iop->alloc_ptr = iop_alloc_ptr;
+               (*pj)->iop->sid = operation->sid;
+               (*pj)->iop->cdesc_out = NULL;
+               (*pj)->iop->cdesc_in = NULL;
+               (*pj)->iop->tdes_mode = operation->list_op.tdes_mode;
+               (*pj)->iop->csum_mode = operation->list_op.csum_mode;
+               (*pj)->iop->ddesc_out = operation->list_op.outlist;
+               (*pj)->iop->ddesc_in = operation->list_op.inlist;
+
+               /* Setup DMA contexts. */
+               (*pj)->iop->ctx_out.next = NULL;
+               (*pj)->iop->ctx_out.eol = 1;
+               (*pj)->iop->ctx_out.saved_data = operation->list_op.outlist;
+               (*pj)->iop->ctx_out.saved_data_buf = 
operation->list_op.out_data_buf;
+
+               (*pj)->iop->ctx_in.next = NULL;
+               (*pj)->iop->ctx_in.eol = 1;
+               (*pj)->iop->ctx_in.saved_data = operation->list_op.inlist;
+               (*pj)->iop->ctx_in.saved_data_buf = 
operation->list_op.in_data_buf;
+       } else {
+               if ((err = cryptocop_setup_dma_list(operation, &(*pj)->iop, 
alloc_flag))) {
+                       DEBUG_API(printk("cryptocop_job_setup: 
cryptocop_setup_dma_list failed %d\n", err));
+                       kfree(*pj);
+                       return err;
+               }
+       }
+       DEBUG(print_dma_descriptors((*pj)->iop));
+
+       DEBUG(printk("cryptocop_job_setup, DMA list setup successful\n"));
+
+       return 0;
+}
+
+
+static int cryptocop_open(struct inode *inode, struct file *filp)
+{
+       int p = MINOR(inode->i_rdev);
+
+       if (p != CRYPTOCOP_MINOR) return -EINVAL;
+
+       filp->private_data = NULL;
+       return 0;
+}
+
+
+static int cryptocop_release(struct inode *inode, struct file *filp)
+{
+       struct cryptocop_private *dev = filp->private_data;
+       struct cryptocop_private *dev_next;
+
+       while (dev){
+               dev_next = dev->next;
+               if (dev->sid != CRYPTOCOP_SESSION_ID_NONE) {
+                       (void)cryptocop_free_session(dev->sid);
+               }
+               kfree(dev);
+               dev = dev_next;
+       }
+
+       return 0;
+}
+
+
+static int cryptocop_ioctl_close_session(struct inode *inode, struct file 
*filp,
+                                        unsigned int cmd, unsigned long arg)
+{
+       struct cryptocop_private  *dev = filp->private_data;
+       struct cryptocop_private  *prev_dev = NULL;
+       struct strcop_session_op  *sess_op = (struct strcop_session_op *)arg;
+       struct strcop_session_op  sop;
+       int                       err;
+
+       DEBUG(printk("cryptocop_ioctl_close_session\n"));
+
+       if (!access_ok(VERIFY_READ, sess_op, sizeof(struct strcop_session_op)))
+               return -EFAULT;
+       err = copy_from_user(&sop, sess_op, sizeof(struct strcop_session_op));
+       if (err) return -EFAULT;
+
+       while (dev && (dev->sid != sop.ses_id)) {
+               prev_dev = dev;
+               dev = dev->next;
+       }
+       if (dev){
+               if (prev_dev){
+                       prev_dev->next = dev->next;
+               } else {
+                       filp->private_data = dev->next;
+               }
+               err = cryptocop_free_session(dev->sid);
+               if (err) return -EFAULT;
+       } else {
+               DEBUG_API(printk("cryptocop_ioctl_close_session: session %lld 
not found\n", sop.ses_id));
+               return -EINVAL;
+       }
+       return 0;
+}
+
+
+static void ioctl_process_job_callback(struct cryptocop_operation *op, 
void*cb_data)
+{
+       struct ioctl_job_cb_ctx *jc = (struct ioctl_job_cb_ctx *)cb_data;
+
+       DEBUG(printk("ioctl_process_job_callback: op=0x%p, cb_data=0x%p\n", op, 
cb_data));
+
+       jc->processed = 1;
+       wake_up(&cryptocop_ioc_process_wq);
+}
+
+
+#define CRYPTOCOP_IOCTL_CIPHER_TID  (1)
+#define CRYPTOCOP_IOCTL_DIGEST_TID  (2)
+#define CRYPTOCOP_IOCTL_CSUM_TID    (3)
+
+static size_t first_cfg_change_ix(struct strcop_crypto_op *crp_op)
+{
+       size_t ch_ix = 0;
+
+       if (crp_op->do_cipher) ch_ix = crp_op->cipher_start;
+       if (crp_op->do_digest && (crp_op->digest_start < ch_ix)) ch_ix = 
crp_op->digest_start;
+       if (crp_op->do_csum && (crp_op->csum_start < ch_ix)) ch_ix = 
crp_op->csum_start;
+
+       DEBUG(printk("first_cfg_change_ix: ix=%d\n", ch_ix));
+       return ch_ix;
+}
+
+
+static size_t next_cfg_change_ix(struct strcop_crypto_op *crp_op, size_t ix)
+{
+       size_t ch_ix = INT_MAX;
+       size_t tmp_ix = 0;
+
+       if (crp_op->do_cipher && ((crp_op->cipher_start + crp_op->cipher_len) > 
ix)){
+               if (crp_op->cipher_start > ix) {
+                       ch_ix = crp_op->cipher_start;
+               } else {
+                       ch_ix = crp_op->cipher_start + crp_op->cipher_len;
+               }
+       }
+       if (crp_op->do_digest && ((crp_op->digest_start + crp_op->digest_len) > 
ix)){
+               if (crp_op->digest_start > ix) {
+                       tmp_ix = crp_op->digest_start;
+               } else {
+                       tmp_ix = crp_op->digest_start + crp_op->digest_len;
+               }
+               if (tmp_ix < ch_ix) ch_ix = tmp_ix;
+       }
+       if (crp_op->do_csum && ((crp_op->csum_start + crp_op->csum_len) > ix)){
+               if (crp_op->csum_start > ix) {
+                       tmp_ix = crp_op->csum_start;
+               } else {
+                       tmp_ix = crp_op->csum_start + crp_op->csum_len;
+               }
+               if (tmp_ix < ch_ix) ch_ix = tmp_ix;
+       }
+       if (ch_ix == INT_MAX) ch_ix = ix;
+       DEBUG(printk("next_cfg_change_ix prev ix=%d, next ix=%d\n", ix, ch_ix));
+       return ch_ix;
+}
+
+
+/* Map map_length bytes from the pages starting on *pageix and *pageoffset to 
iovecs starting on *iovix.
+ * Return -1 for ok, 0 for fail. */
+static int map_pages_to_iovec(struct iovec *iov, int iovlen, int *iovix, 
struct page **pages, int nopages, int *pageix, int *pageoffset, int map_length )
+{
+       int tmplen;
+
+       assert(iov != NULL);
+       assert(iovix != NULL);
+       assert(pages != NULL);
+       assert(pageix != NULL);
+       assert(pageoffset != NULL);
+
+       DEBUG(printk("map_pages_to_iovec, map_length=%d, iovlen=%d, *iovix=%d, 
nopages=%d, *pageix=%d, *pageoffset=%d\n", map_length, iovlen, *iovix, nopages, 
*pageix, *pageoffset));
+
+       while (map_length > 0){
+               DEBUG(printk("map_pages_to_iovec, map_length=%d, iovlen=%d, 
*iovix=%d, nopages=%d, *pageix=%d, *pageoffset=%d\n", map_length, iovlen, 
*iovix, nopages, *pageix, *pageoffset));
+               if (*iovix >= iovlen){
+                       DEBUG_API(printk("map_page_to_iovec: *iovix=%d >= 
iovlen=%d\n", *iovix, iovlen));
+                       return 0;
+               }
+               if (*pageix >= nopages){
+                       DEBUG_API(printk("map_page_to_iovec: *pageix=%d >= 
nopages=%d\n", *pageix, nopages));
+                       return 0;
+               }
+               iov[*iovix].iov_base = (unsigned 
char*)page_address(pages[*pageix]) + *pageoffset;
+               tmplen = PAGE_SIZE - *pageoffset;
+               if (tmplen < map_length){
+                       (*pageoffset) = 0;
+                       (*pageix)++;
+               } else {
+                       tmplen = map_length;
+                       (*pageoffset) += map_length;
+               }
+               DEBUG(printk("mapping %d bytes from page %d (or %d) to iovec 
%d\n", tmplen, *pageix, *pageix-1, *iovix));
+               iov[*iovix].iov_len = tmplen;
+               map_length -= tmplen;
+               (*iovix)++;
+       }
+       DEBUG(printk("map_page_to_iovec, exit, *iovix=%d\n", *iovix));
+       return -1;
+}
+
+
+
+static int cryptocop_ioctl_process(struct inode *inode, struct file *filp, 
unsigned int cmd, unsigned long arg)
+{
+       int                             i;
+       struct cryptocop_private        *dev = filp->private_data;
+       struct strcop_crypto_op         *crp_oper = (struct strcop_crypto_op 
*)arg;
+       struct strcop_crypto_op         oper = {0};
+       int                             err = 0;
+       struct cryptocop_operation      *cop = NULL;
+
+       struct ioctl_job_cb_ctx         *jc = NULL;
+
+       struct page                     **inpages = NULL;
+       struct page                     **outpages = NULL;
+       int                             noinpages = 0;
+       int                             nooutpages = 0;
+
+       struct cryptocop_desc           descs[5]; /* Max 5 descriptors are 
needed, there are three transforms that
+                                                  * can get 
connected/disconnected on different places in the indata. */
+       struct cryptocop_desc_cfg       dcfgs[5*3];
+       int                             desc_ix = 0;
+       int                             dcfg_ix = 0;
+       struct cryptocop_tfrm_cfg       ciph_tcfg = {0};
+       struct cryptocop_tfrm_cfg       digest_tcfg = {0};
+       struct cryptocop_tfrm_cfg       csum_tcfg = {0};
+
+       unsigned char                   *digest_result = NULL;
+       int                             digest_length = 0;
+       int                             cblocklen = 0;
+       unsigned char                   csum_result[CSUM_BLOCK_LENGTH];
+       struct cryptocop_session        *sess;
+
+       int    iovlen = 0;
+       int    iovix = 0;
+       int    pageix = 0;
+       int    pageoffset = 0;
+
+       size_t prev_ix = 0;
+       size_t next_ix;
+
+       int    cipher_active, digest_active, csum_active;
+       int    end_digest, end_csum;
+       int    digest_done = 0;
+       int    cipher_done = 0;
+       int    csum_done = 0;
+
+       DEBUG(printk("cryptocop_ioctl_process\n"));
+
+       if (!access_ok(VERIFY_WRITE, crp_oper, sizeof(struct 
strcop_crypto_op))){
+               DEBUG_API(printk("cryptocop_ioctl_process: !access_ok 
crp_oper!\n"));
+               return -EFAULT;
+       }
+       if (copy_from_user(&oper, crp_oper, sizeof(struct strcop_crypto_op))) {
+               DEBUG_API(printk("cryptocop_ioctl_process: copy_from_user\n"));
+               return -EFAULT;
+       }
+       DEBUG(print_strcop_crypto_op(&oper));
+
+       while (dev && dev->sid != oper.ses_id) dev = dev->next;
+       if (!dev){
+               DEBUG_API(printk("cryptocop_ioctl_process: session %lld not 
found\n", oper.ses_id));
+               return -EINVAL;
+       }
+
+       /* Check buffers. */
+       if (((oper.indata + oper.inlen) < oper.indata) || ((oper.cipher_outdata 
+ oper.cipher_outlen) < oper.cipher_outdata)){
+               DEBUG_API(printk("cryptocop_ioctl_process: user buffers wrapped 
around, bad user!\n"));
+               return -EINVAL;
+       }
+
+       if (!access_ok(VERIFY_WRITE, oper.cipher_outdata, oper.cipher_outlen)){
+               DEBUG_API(printk("cryptocop_ioctl_process: !access_ok out 
data!\n"));
+               return -EFAULT;
+       }
+       if (!access_ok(VERIFY_READ, oper.indata, oper.inlen)){
+               DEBUG_API(printk("cryptocop_ioctl_process: !access_ok in 
data!\n"));
+               return -EFAULT;
+       }
+
+       cop = kmalloc(sizeof(struct cryptocop_operation), GFP_KERNEL);
+       if (!cop) {
+               DEBUG_API(printk("cryptocop_ioctl_process: kmalloc\n"));
+               return -ENOMEM;
+       }
+       jc = kmalloc(sizeof(struct ioctl_job_cb_ctx), GFP_KERNEL);
+       if (!jc) {
+               DEBUG_API(printk("cryptocop_ioctl_process: kmalloc\n"));
+               err = -ENOMEM;
+               goto error_cleanup;
+       }
+       jc->processed = 0;
+
+       cop->cb_data = jc;
+       cop->cb = ioctl_process_job_callback;
+       cop->operation_status = 0;
+       cop->use_dmalists = 0;
+       cop->in_interrupt = 0;
+       cop->fast_callback = 0;
+       cop->tfrm_op.tfrm_cfg = NULL;
+       cop->tfrm_op.desc = NULL;
+       cop->tfrm_op.indata = NULL;
+       cop->tfrm_op.incount = 0;
+       cop->tfrm_op.inlen = 0;
+       cop->tfrm_op.outdata = NULL;
+       cop->tfrm_op.outcount = 0;
+       cop->tfrm_op.outlen = 0;
+
+       sess = get_session(oper.ses_id);
+       if (!sess){
+               DEBUG_API(printk("cryptocop_ioctl_process: bad session id.\n"));
+               kfree(cop);
+               kfree(jc);
+               return -EINVAL;
+       }
+
+       if (oper.do_cipher) {
+               unsigned int                    cipher_outlen = 0;
+               struct cryptocop_transform_ctx  *tc = get_transform_ctx(sess, 
CRYPTOCOP_IOCTL_CIPHER_TID);
+               if (!tc) {
+                       DEBUG_API(printk("cryptocop_ioctl_process: no cipher 
transform in session.\n"));
+                       err = -EINVAL;
+                       goto error_cleanup;
+               }
+               ciph_tcfg.tid = CRYPTOCOP_IOCTL_CIPHER_TID;
+               ciph_tcfg.inject_ix = 0;
+               ciph_tcfg.flags = 0;
+               if ((oper.cipher_start < 0) || (oper.cipher_len <= 0) || 
(oper.cipher_start > oper.inlen) || ((oper.cipher_start + oper.cipher_len) > 
oper.inlen)){
+                       DEBUG_API(printk("cryptocop_ioctl_process: bad cipher 
length\n"));
+                       kfree(cop);
+                       kfree(jc);
+                       return -EINVAL;
+               }
+               cblocklen = tc->init.alg == cryptocop_alg_aes ? 
AES_BLOCK_LENGTH : DES_BLOCK_LENGTH;
+               if (oper.cipher_len % cblocklen) {
+                       kfree(cop);
+                       kfree(jc);
+                       DEBUG_API(printk("cryptocop_ioctl_process: cipher 
inlength not multiple of block length.\n"));
+                       return -EINVAL;
+               }
+               cipher_outlen = oper.cipher_len;
+               if (tc->init.cipher_mode == cryptocop_cipher_mode_cbc){
+                       if (oper.cipher_explicit) {
+                               ciph_tcfg.flags |= CRYPTOCOP_EXPLICIT_IV;
+                               memcpy(ciph_tcfg.iv, oper.cipher_iv, cblocklen);
+                       } else {
+                               cipher_outlen = oper.cipher_len - cblocklen;
+                       }
+               } else {
+                       if (oper.cipher_explicit){
+                               kfree(cop);
+                               kfree(jc);
+                               DEBUG_API(printk("cryptocop_ioctl_process: 
explicit_iv when not CBC mode\n"));
+                               return -EINVAL;
+                       }
+               }
+               if (oper.cipher_outlen != cipher_outlen) {
+                       kfree(cop);
+                       kfree(jc);
+                       DEBUG_API(printk("cryptocop_ioctl_process: 
cipher_outlen incorrect, should be %d not %d.\n", cipher_outlen, 
oper.cipher_outlen));
+                       return -EINVAL;
+               }
+
+               if (oper.decrypt){
+                       ciph_tcfg.flags |= CRYPTOCOP_DECRYPT;
+               } else {
+                       ciph_tcfg.flags |= CRYPTOCOP_ENCRYPT;
+               }
+               ciph_tcfg.next = cop->tfrm_op.tfrm_cfg;
+               cop->tfrm_op.tfrm_cfg = &ciph_tcfg;
+       }
+       if (oper.do_digest){
+               struct cryptocop_transform_ctx *tc = get_transform_ctx(sess, 
CRYPTOCOP_IOCTL_DIGEST_TID);
+               if (!tc) {
+                       DEBUG_API(printk("cryptocop_ioctl_process: no digest 
transform in session.\n"));
+                       err = -EINVAL;
+                       goto error_cleanup;
+               }
+               digest_length = tc->init.alg == cryptocop_alg_md5 ? 16 : 20;
+               digest_result = kmalloc(digest_length, GFP_KERNEL);
+               if (!digest_result) {
+                       DEBUG_API(printk("cryptocop_ioctl_process: kmalloc 
digest_result\n"));
+                       err = -EINVAL;
+                       goto error_cleanup;
+               }
+               DEBUG(memset(digest_result, 0xff, digest_length));
+
+               digest_tcfg.tid = CRYPTOCOP_IOCTL_DIGEST_TID;
+               digest_tcfg.inject_ix = 0;
+               ciph_tcfg.inject_ix += digest_length;
+               if ((oper.digest_start < 0) || (oper.digest_len <= 0) || 
(oper.digest_start > oper.inlen) || ((oper.digest_start + oper.digest_len) > 
oper.inlen)){
+                       DEBUG_API(printk("cryptocop_ioctl_process: bad digest 
length\n"));
+                       err = -EINVAL;
+                       goto error_cleanup;
+               }
+
+               digest_tcfg.next = cop->tfrm_op.tfrm_cfg;
+               cop->tfrm_op.tfrm_cfg = &digest_tcfg;
+       }
+       if (oper.do_csum){
+               csum_tcfg.tid = CRYPTOCOP_IOCTL_CSUM_TID;
+               csum_tcfg.inject_ix = digest_length;
+               ciph_tcfg.inject_ix += 2;
+
+               if ((oper.csum_start < 0) || (oper.csum_len <= 0) || 
(oper.csum_start > oper.inlen) || ((oper.csum_start + oper.csum_len) > 
oper.inlen)){
+                       DEBUG_API(printk("cryptocop_ioctl_process: bad csum 
length\n"));
+                       kfree(cop);
+                       kfree(jc);
+                       return -EINVAL;
+               }
+
+               csum_tcfg.next = cop->tfrm_op.tfrm_cfg;
+               cop->tfrm_op.tfrm_cfg = &csum_tcfg;
+       }
+
+       prev_ix = first_cfg_change_ix(&oper);
+       if (prev_ix > oper.inlen) {
+               DEBUG_API(printk("cryptocop_ioctl_process: length mismatch\n"));
+               nooutpages = noinpages = 0;
+               err = -EINVAL;
+               goto error_cleanup;
+       }
+       DEBUG(printk("cryptocop_ioctl_process: inlen=%d, cipher_outlen=%d\n", 
oper.inlen, oper.cipher_outlen));
+
+       /* Map user pages for in and out data of the operation. */
+       noinpages = (((unsigned long int)(oper.indata + prev_ix) & ~PAGE_MASK) 
+ oper.inlen - 1 - prev_ix + ~PAGE_MASK) >> PAGE_SHIFT;
+       DEBUG(printk("cryptocop_ioctl_process: noinpages=%d\n", noinpages));
+       inpages = kmalloc(noinpages * sizeof(struct page*), GFP_KERNEL);
+       if (!inpages){
+               DEBUG_API(printk("cryptocop_ioctl_process: kmalloc inpages\n"));
+               nooutpages = noinpages = 0;
+               err = -ENOMEM;
+               goto error_cleanup;
+       }
+       if (oper.do_cipher){
+               nooutpages = (((unsigned long int)oper.cipher_outdata & 
~PAGE_MASK) + oper.cipher_outlen - 1 + ~PAGE_MASK) >> PAGE_SHIFT;
+               DEBUG(printk("cryptocop_ioctl_process: nooutpages=%d\n", 
nooutpages));
+               outpages = kmalloc(nooutpages * sizeof(struct page*), 
GFP_KERNEL);
+               if (!outpages){
+                       DEBUG_API(printk("cryptocop_ioctl_process: kmalloc 
outpages\n"));
+                       nooutpages = noinpages = 0;
+                       err = -ENOMEM;
+                       goto error_cleanup;
+               }
+       }
+
+       /* Acquire the mm page semaphore. */
+       down_read(&current->mm->mmap_sem);
+
+       err = get_user_pages(current,
+                            current->mm,
+                            (unsigned long int)(oper.indata + prev_ix),
+                            noinpages,
+                            0,  /* read access only for in data */
+                            0, /* no force */
+                            inpages,
+                            NULL);
+
+       if (err < 0) {
+               up_read(&current->mm->mmap_sem);
+               nooutpages = noinpages = 0;
+               DEBUG_API(printk("cryptocop_ioctl_process: get_user_pages 
indata\n"));
+               goto error_cleanup;
+       }
+       noinpages = err;
+       if (oper.do_cipher){
+               err = get_user_pages(current,
+                                    current->mm,
+                                    (unsigned long int)oper.cipher_outdata,
+                                    nooutpages,
+                                    1, /* write access for out data */
+                                    0, /* no force */
+                                    outpages,
+                                    NULL);
+               up_read(&current->mm->mmap_sem);
+               if (err < 0) {
+                       nooutpages = 0;
+                       DEBUG_API(printk("cryptocop_ioctl_process: 
get_user_pages outdata\n"));
+                       goto error_cleanup;
+               }
+               nooutpages = err;
+       } else {
+               up_read(&current->mm->mmap_sem);
+       }
+
+       /* Add 6 to nooutpages to make room for possibly inserted buffers for 
storing digest and
+        * csum output and splits when units are (dis-)connected. */
+       cop->tfrm_op.indata = kmalloc((noinpages) * sizeof(struct iovec), 
GFP_KERNEL);
+       cop->tfrm_op.outdata = kmalloc((6 + nooutpages) * sizeof(struct iovec), 
GFP_KERNEL);
+       if (!cop->tfrm_op.indata || !cop->tfrm_op.outdata) {
+               DEBUG_API(printk("cryptocop_ioctl_process: kmalloc iovecs\n"));
+               err = -ENOMEM;
+               goto error_cleanup;
+       }
+
+       cop->tfrm_op.inlen = oper.inlen - prev_ix;
+       cop->tfrm_op.outlen = 0;
+       if (oper.do_cipher) cop->tfrm_op.outlen += oper.cipher_outlen;
+       if (oper.do_digest) cop->tfrm_op.outlen += digest_length;
+       if (oper.do_csum) cop->tfrm_op.outlen += 2;
+
+       /* Setup the in iovecs. */
+       cop->tfrm_op.incount = noinpages;
+       if (noinpages > 1){
+               size_t tmplen = cop->tfrm_op.inlen;
+
+               cop->tfrm_op.indata[0].iov_len = PAGE_SIZE - ((unsigned long 
int)(oper.indata + prev_ix) & ~PAGE_MASK);
+               cop->tfrm_op.indata[0].iov_base = (unsigned 
char*)page_address(inpages[0]) + ((unsigned long int)(oper.indata + prev_ix) & 
~PAGE_MASK);
+               tmplen -= cop->tfrm_op.indata[0].iov_len;
+               for (i = 1; i<noinpages; i++){
+                       cop->tfrm_op.indata[i].iov_len = tmplen < PAGE_SIZE ? 
tmplen : PAGE_SIZE;
+                       cop->tfrm_op.indata[i].iov_base = (unsigned 
char*)page_address(inpages[i]);
+                       tmplen -= PAGE_SIZE;
+               }
+       } else {
+               cop->tfrm_op.indata[0].iov_len = oper.inlen - prev_ix;
+               cop->tfrm_op.indata[0].iov_base = (unsigned 
char*)page_address(inpages[0]) + ((unsigned long int)(oper.indata + prev_ix) & 
~PAGE_MASK);
+       }
+
+       iovlen = nooutpages + 6;
+       pageoffset = oper.do_cipher ? ((unsigned long int)oper.cipher_outdata & 
~PAGE_MASK) : 0;
+
+       next_ix = next_cfg_change_ix(&oper, prev_ix);
+       if (prev_ix == next_ix){
+               DEBUG_API(printk("cryptocop_ioctl_process: length configuration 
broken.\n"));
+               err = -EINVAL;  /* This should be impossible barring bugs. */
+               goto error_cleanup;
+       }
+       while (prev_ix != next_ix){
+               end_digest = end_csum = cipher_active = digest_active = 
csum_active = 0;
+               descs[desc_ix].cfg = NULL;
+               descs[desc_ix].length = next_ix - prev_ix;
+
+               if (oper.do_cipher && (oper.cipher_start < next_ix) && (prev_ix 
< (oper.cipher_start + oper.cipher_len))) {
+                       dcfgs[dcfg_ix].tid = CRYPTOCOP_IOCTL_CIPHER_TID;
+                       dcfgs[dcfg_ix].src = cryptocop_source_dma;
+                       cipher_active = 1;
+
+                       if (next_ix == (oper.cipher_start + oper.cipher_len)){
+                               cipher_done = 1;
+                               dcfgs[dcfg_ix].last = 1;
+                       } else {
+                               dcfgs[dcfg_ix].last = 0;
+                       }
+                       dcfgs[dcfg_ix].next = descs[desc_ix].cfg;
+                       descs[desc_ix].cfg = &dcfgs[dcfg_ix];
+                       ++dcfg_ix;
+               }
+               if (oper.do_digest && (oper.digest_start < next_ix) && (prev_ix 
< (oper.digest_start + oper.digest_len))) {
+                       digest_active = 1;
+                       dcfgs[dcfg_ix].tid = CRYPTOCOP_IOCTL_DIGEST_TID;
+                       dcfgs[dcfg_ix].src = cryptocop_source_dma;
+                       if (next_ix == (oper.digest_start + oper.digest_len)){
+                               assert(!digest_done);
+                               digest_done = 1;
+                               dcfgs[dcfg_ix].last = 1;
+                       } else {
+                               dcfgs[dcfg_ix].last = 0;
+                       }
+                       dcfgs[dcfg_ix].next = descs[desc_ix].cfg;
+                       descs[desc_ix].cfg = &dcfgs[dcfg_ix];
+                       ++dcfg_ix;
+               }
+               if (oper.do_csum && (oper.csum_start < next_ix) && (prev_ix < 
(oper.csum_start + oper.csum_len))){
+                       csum_active = 1;
+                       dcfgs[dcfg_ix].tid = CRYPTOCOP_IOCTL_CSUM_TID;
+                       dcfgs[dcfg_ix].src = cryptocop_source_dma;
+                       if (next_ix == (oper.csum_start + oper.csum_len)){
+                               csum_done = 1;
+                               dcfgs[dcfg_ix].last = 1;
+                       } else {
+                               dcfgs[dcfg_ix].last = 0;
+                       }
+                       dcfgs[dcfg_ix].next = descs[desc_ix].cfg;
+                       descs[desc_ix].cfg = &dcfgs[dcfg_ix];
+                       ++dcfg_ix;
+               }
+               if (!descs[desc_ix].cfg){
+                       DEBUG_API(printk("cryptocop_ioctl_process: data segment 
%d (%d to %d) had no active transforms\n", desc_ix, prev_ix, next_ix));
+                       err = -EINVAL;
+                       goto error_cleanup;
+               }
+               descs[desc_ix].next = &(descs[desc_ix]) + 1;
+               ++desc_ix;
+               prev_ix = next_ix;
+               next_ix = next_cfg_change_ix(&oper, prev_ix);
+       }
+       if (desc_ix > 0){
+               descs[desc_ix-1].next = NULL;
+       } else {
+               descs[0].next = NULL;
+       }
+       if (oper.do_digest) {
+               DEBUG(printk("cryptocop_ioctl_process: mapping %d byte digest 
output to iovec %d\n", digest_length, iovix));
+               /* Add outdata iovec, length == <length of type of digest> */
+               cop->tfrm_op.outdata[iovix].iov_base = digest_result;
+               cop->tfrm_op.outdata[iovix].iov_len = digest_length;
+               ++iovix;
+       }
+       if (oper.do_csum) {
+               /* Add outdata iovec, length == 2, the length of csum. */
+               DEBUG(printk("cryptocop_ioctl_process: mapping 2 byte csum 
output to iovec %d\n", iovix));
+               /* Add outdata iovec, length == <length of type of digest> */
+               cop->tfrm_op.outdata[iovix].iov_base = csum_result;
+               cop->tfrm_op.outdata[iovix].iov_len = 2;
+               ++iovix;
+       }
+       if (oper.do_cipher) {
+               if (!map_pages_to_iovec(cop->tfrm_op.outdata, iovlen, &iovix, 
outpages, nooutpages, &pageix, &pageoffset, oper.cipher_outlen)){
+                       DEBUG_API(printk("cryptocop_ioctl_process: failed to 
map pages to iovec.\n"));
+                       err = -ENOSYS; /* This should be impossible barring 
bugs. */
+                       goto error_cleanup;
+               }
+       }
+       DEBUG(printk("cryptocop_ioctl_process: setting cop->tfrm_op.outcount 
%d\n", iovix));
+       cop->tfrm_op.outcount = iovix;
+       assert(iovix <= (nooutpages + 6));
+
+       cop->sid = oper.ses_id;
+       cop->tfrm_op.desc = &descs[0];
+
+       DEBUG(printk("cryptocop_ioctl_process: inserting job, cb_data=0x%p\n", 
cop->cb_data));
+
+       if ((err = cryptocop_job_queue_insert_user_job(cop)) != 0) {
+               DEBUG_API(printk("cryptocop_ioctl_process: insert job %d\n", 
err));
+               err = -EINVAL;
+               goto error_cleanup;
+       }
+
+       DEBUG(printk("cryptocop_ioctl_process: begin wait for result\n"));
+
+       wait_event(cryptocop_ioc_process_wq, (jc->processed != 0));
+       DEBUG(printk("cryptocop_ioctl_process: end wait for result\n"));
+        if (!jc->processed){
+               printk(KERN_WARNING "cryptocop_ioctl_process: job not processed 
at completion\n");
+               err = -EIO;
+               goto error_cleanup;
+       }
+
+       /* Job process done.  Cipher output should already be correct in job so 
no post processing of outdata. */
+       DEBUG(printk("cryptocop_ioctl_process: operation_status = %d\n", 
cop->operation_status));
+       if (cop->operation_status == 0){
+               if (oper.do_digest){
+                       DEBUG(printk("cryptocop_ioctl_process: copy %d bytes 
digest to user\n", digest_length));
+                       err = copy_to_user((unsigned char*)crp_oper + 
offsetof(struct strcop_crypto_op, digest), digest_result, digest_length);
+                       if (0 != err){
+                               DEBUG_API(printk("cryptocop_ioctl_process: 
copy_to_user, digest length %d, err %d\n", digest_length, err));
+                               err = -EFAULT;
+                               goto error_cleanup;
+                       }
+               }
+               if (oper.do_csum){
+                       DEBUG(printk("cryptocop_ioctl_process: copy 2 bytes 
checksum to user\n"));
+                       err = copy_to_user((unsigned char*)crp_oper + 
offsetof(struct strcop_crypto_op, csum), csum_result, 2);
+                       if (0 != err){
+                               DEBUG_API(printk("cryptocop_ioctl_process: 
copy_to_user, csum, err %d\n", err));
+                               err = -EFAULT;
+                               goto error_cleanup;
+                       }
+               }
+               err = 0;
+       } else {
+               DEBUG(printk("cryptocop_ioctl_process: returning err = 
operation_status = %d\n", cop->operation_status));
+               err = cop->operation_status;
+       }
+
+ error_cleanup:
+       /* Release page caches. */
+       for (i = 0; i < noinpages; i++){
+               put_page(inpages[i]);
+       }
+       for (i = 0; i < nooutpages; i++){
+               int spdl_err;
+               /* Mark output pages dirty. */
+               spdl_err = set_page_dirty_lock(outpages[i]);
+               DEBUG(if (spdl_err)printk("cryptocop_ioctl_process: 
set_page_dirty_lock returned %d\n", spdl_err));
+       }
+       for (i = 0; i < nooutpages; i++){
+               put_page(outpages[i]);
+       }
+
+       if (digest_result) kfree(digest_result);
+       if (inpages) kfree(inpages);
+       if (outpages) kfree(outpages);
+       if (cop){
+               if (cop->tfrm_op.indata) kfree(cop->tfrm_op.indata);
+               if (cop->tfrm_op.outdata) kfree(cop->tfrm_op.outdata);
+               kfree(cop);
+       }
+       if (jc) kfree(jc);
+
+       DEBUG(print_lock_status());
+
+       return err;
+}
+
+
+static int cryptocop_ioctl_create_session(struct inode *inode, struct file 
*filp, unsigned int cmd, unsigned long arg)
+{
+       cryptocop_session_id             sid;
+       int                              err;
+       struct cryptocop_private         *dev;
+       struct strcop_session_op         *sess_op = (struct strcop_session_op 
*)arg;
+       struct strcop_session_op         sop;
+       struct cryptocop_transform_init  *tis = NULL;
+       struct cryptocop_transform_init  ti_cipher = {0};
+       struct cryptocop_transform_init  ti_digest = {0};
+       struct cryptocop_transform_init  ti_csum = {0};
+
+       if (!access_ok(VERIFY_WRITE, sess_op, sizeof(struct strcop_session_op)))
+               return -EFAULT;
+       err = copy_from_user(&sop, sess_op, sizeof(struct strcop_session_op));
+       if (err) return -EFAULT;
+       if (sop.cipher != cryptocop_cipher_none) {
+               if (!access_ok(VERIFY_READ, sop.key, sop.keylen)) return 
-EFAULT;
+       }
+       DEBUG(printk("cryptocop_ioctl_create_session, sess_op:\n"));
+
+       DEBUG(printk("\tcipher:%d\n"
+                    "\tcipher_mode:%d\n"
+                    "\tdigest:%d\n"
+                    "\tcsum:%d\n",
+                    (int)sop.cipher,
+                    (int)sop.cmode,
+                    (int)sop.digest,
+                    (int)sop.csum));
+
+       if (sop.cipher != cryptocop_cipher_none){
+               /* Init the cipher. */
+               switch (sop.cipher){
+               case cryptocop_cipher_des:
+                       ti_cipher.alg = cryptocop_alg_des;
+                       break;
+               case cryptocop_cipher_3des:
+                       ti_cipher.alg = cryptocop_alg_3des;
+                       break;
+               case cryptocop_cipher_aes:
+                       ti_cipher.alg = cryptocop_alg_aes;
+                       break;
+               default:
+                       DEBUG_API(printk("create session, bad cipher algorithm 
%d\n", sop.cipher));
+                       return -EINVAL;
+               };
+               DEBUG(printk("setting cipher transform %d\n", ti_cipher.alg));
+               copy_from_user(ti_cipher.key, sop.key, sop.keylen/8);
+               ti_cipher.keylen = sop.keylen;
+               switch (sop.cmode){
+               case cryptocop_cipher_mode_cbc:
+               case cryptocop_cipher_mode_ecb:
+                       ti_cipher.cipher_mode = sop.cmode;
+                       break;
+               default:
+                       DEBUG_API(printk("create session, bad cipher mode 
%d\n", sop.cmode));
+                       return -EINVAL;
+               }
+               DEBUG(printk("cryptocop_ioctl_create_session: setting CBC mode 
%d\n", ti_cipher.cipher_mode));
+               switch (sop.des3_mode){
+               case cryptocop_3des_eee:
+               case cryptocop_3des_eed:
+               case cryptocop_3des_ede:
+               case cryptocop_3des_edd:
+               case cryptocop_3des_dee:
+               case cryptocop_3des_ded:
+               case cryptocop_3des_dde:
+               case cryptocop_3des_ddd:
+                       ti_cipher.tdes_mode = sop.des3_mode;
+                       break;
+               default:
+                       DEBUG_API(printk("create session, bad 3DES mode %d\n", 
sop.des3_mode));
+                       return -EINVAL;
+               }
+               ti_cipher.tid = CRYPTOCOP_IOCTL_CIPHER_TID;
+               ti_cipher.next = tis;
+               tis = &ti_cipher;
+       } /* if (sop.cipher != cryptocop_cipher_none) */
+       if (sop.digest != cryptocop_digest_none){
+               DEBUG(printk("setting digest transform\n"));
+               switch (sop.digest){
+               case cryptocop_digest_md5:
+                       ti_digest.alg = cryptocop_alg_md5;
+                       break;
+               case cryptocop_digest_sha1:
+                       ti_digest.alg = cryptocop_alg_sha1;
+                       break;
+               default:
+                       DEBUG_API(printk("create session, bad digest algorithm 
%d\n", sop.digest));
+                       return -EINVAL;
+               }
+               ti_digest.tid = CRYPTOCOP_IOCTL_DIGEST_TID;
+               ti_digest.next = tis;
+               tis = &ti_digest;
+       } /* if (sop.digest != cryptocop_digest_none) */
+       if (sop.csum != cryptocop_csum_none){
+               DEBUG(printk("setting csum transform\n"));
+               switch (sop.csum){
+               case cryptocop_csum_le:
+               case cryptocop_csum_be:
+                       ti_csum.csum_mode = sop.csum;
+                       break;
+               default:
+                       DEBUG_API(printk("create session, bad checksum 
algorithm %d\n", sop.csum));
+                       return -EINVAL;
+               }
+               ti_csum.alg = cryptocop_alg_csum;
+               ti_csum.tid = CRYPTOCOP_IOCTL_CSUM_TID;
+               ti_csum.next = tis;
+               tis = &ti_csum;
+       } /* (sop.csum != cryptocop_csum_none) */
+       dev = kmalloc(sizeof(struct cryptocop_private), GFP_KERNEL);
+       if (!dev){
+               DEBUG_API(printk("create session, alloc dev\n"));
+               return -ENOMEM;
+       }
+
+       err = cryptocop_new_session(&sid, tis, GFP_KERNEL);
+       DEBUG({ if (err) printk("create session, cryptocop_new_session %d\n", 
err);});
+
+       if (err) {
+               kfree(dev);
+               return err;
+       }
+       sess_op->ses_id = sid;
+       dev->sid = sid;
+       dev->next = filp->private_data;
+       filp->private_data = dev;
+
+       return 0;
+}
+
+static int cryptocop_ioctl(struct inode *inode, struct file *filp, unsigned 
int cmd, unsigned long arg)
+{
+       int err = 0;
+       if (_IOC_TYPE(cmd) != ETRAXCRYPTOCOP_IOCTYPE) {
+               DEBUG_API(printk("cryptocop_ioctl: wrong type\n"));
+               return -ENOTTY;
+       }
+       if (_IOC_NR(cmd) > CRYPTOCOP_IO_MAXNR){
+               return -ENOTTY;
+       }
+       /* Access check of the argument.  Some commands, e.g. create session 
and process op,
+          needs additional checks.  Those are handled in the command handling 
functions. */
+       if (_IOC_DIR(cmd) & _IOC_READ)
+               err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
+       else if (_IOC_DIR(cmd) & _IOC_WRITE)
+               err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
+       if (err) return -EFAULT;
+
+       switch (cmd) {
+       case CRYPTOCOP_IO_CREATE_SESSION:
+               return cryptocop_ioctl_create_session(inode, filp, cmd, arg);
+       case CRYPTOCOP_IO_CLOSE_SESSION:
+               return cryptocop_ioctl_close_session(inode, filp, cmd, arg);
+       case CRYPTOCOP_IO_PROCESS_OP:
+               return cryptocop_ioctl_process(inode, filp, cmd, arg);
+       default:
+               DEBUG_API(printk("cryptocop_ioctl: unknown command\n"));
+               return -ENOTTY;
+       }
+       return 0;
+}
+
+
+#ifdef LDEBUG
+static void print_dma_descriptors(struct cryptocop_int_operation *iop)
+{
+       struct cryptocop_dma_desc *cdesc_out = iop->cdesc_out;
+       struct cryptocop_dma_desc *cdesc_in = iop->cdesc_in;
+       int                       i;
+
+       printk("print_dma_descriptors start\n");
+
+       printk("iop:\n");
+       printk("\tsid: 0x%lld\n", iop->sid);
+
+       printk("\tcdesc_out: 0x%p\n", iop->cdesc_out);
+       printk("\tcdesc_in: 0x%p\n", iop->cdesc_in);
+       printk("\tddesc_out: 0x%p\n", iop->ddesc_out);
+       printk("\tddesc_in: 0x%p\n", iop->ddesc_in);
+
+       printk("\niop->ctx_out: 0x%p phys: 0x%p\n", &iop->ctx_out, 
(char*)virt_to_phys(&iop->ctx_out));
+       printk("\tnext: 0x%p\n"
+              "\tsaved_data: 0x%p\n"
+              "\tsaved_data_buf: 0x%p\n",
+              iop->ctx_out.next,
+              iop->ctx_out.saved_data,
+              iop->ctx_out.saved_data_buf);
+
+       printk("\niop->ctx_in: 0x%p phys: 0x%p\n", &iop->ctx_in, 
(char*)virt_to_phys(&iop->ctx_in));
+       printk("\tnext: 0x%p\n"
+              "\tsaved_data: 0x%p\n"
+              "\tsaved_data_buf: 0x%p\n",
+              iop->ctx_in.next,
+              iop->ctx_in.saved_data,
+              iop->ctx_in.saved_data_buf);
+
+       i = 0;
+       while (cdesc_out) {
+               dma_descr_data *td;
+               printk("cdesc_out %d, desc=0x%p\n", i, cdesc_out->dma_descr);
+               printk("\n\tvirt_to_phys(desc): 0x%p\n", 
(char*)virt_to_phys(cdesc_out->dma_descr));
+               td = cdesc_out->dma_descr;
+               printk("\n\tbuf: 0x%p\n"
+                      "\tafter: 0x%p\n"
+                      "\tmd: 0x%04x\n"
+                      "\tnext: 0x%p\n",
+                      td->buf,
+                      td->after,
+                      td->md,
+                      td->next);
+               printk("flags:\n"
+                      "\twait:\t%d\n"
+                      "\teol:\t%d\n"
+                      "\touteop:\t%d\n"
+                      "\tineop:\t%d\n"
+                      "\tintr:\t%d\n",
+                      td->wait,
+                      td->eol,
+                      td->out_eop,
+                      td->in_eop,
+                      td->intr);
+               cdesc_out = cdesc_out->next;
+               i++;
+       }
+       i = 0;
+       while (cdesc_in) {
+               dma_descr_data *td;
+               printk("cdesc_in %d, desc=0x%p\n", i, cdesc_in->dma_descr);
+               printk("\n\tvirt_to_phys(desc): 0x%p\n", 
(char*)virt_to_phys(cdesc_in->dma_descr));
+               td = cdesc_in->dma_descr;
+               printk("\n\tbuf: 0x%p\n"
+                      "\tafter: 0x%p\n"
+                      "\tmd: 0x%04x\n"
+                      "\tnext: 0x%p\n",
+                      td->buf,
+                      td->after,
+                      td->md,
+                      td->next);
+               printk("flags:\n"
+                      "\twait:\t%d\n"
+                      "\teol:\t%d\n"
+                      "\touteop:\t%d\n"
+                      "\tineop:\t%d\n"
+                      "\tintr:\t%d\n",
+                      td->wait,
+                      td->eol,
+                      td->out_eop,
+                      td->in_eop,
+                      td->intr);
+               cdesc_in = cdesc_in->next;
+               i++;
+       }
+
+       printk("print_dma_descriptors end\n");
+}
+
+
+static void print_strcop_crypto_op(struct strcop_crypto_op *cop)
+{
+       printk("print_strcop_crypto_op, 0x%p\n", cop);
+
+       /* Indata. */
+       printk("indata=0x%p\n"
+              "inlen=%d\n"
+              "do_cipher=%d\n"
+              "decrypt=%d\n"
+              "cipher_explicit=%d\n"
+              "cipher_start=%d\n"
+              "cipher_len=%d\n"
+              "outdata=0x%p\n"
+              "outlen=%d\n",
+              cop->indata,
+              cop->inlen,
+              cop->do_cipher,
+              cop->decrypt,
+              cop->cipher_explicit,
+              cop->cipher_start,
+              cop->cipher_len,
+              cop->cipher_outdata,
+              cop->cipher_outlen);
+
+       printk("do_digest=%d\n"
+              "digest_start=%d\n"
+              "digest_len=%d\n",
+              cop->do_digest,
+              cop->digest_start,
+              cop->digest_len);
+
+       printk("do_csum=%d\n"
+              "csum_start=%d\n"
+              "csum_len=%d\n",
+              cop->do_csum,
+              cop->csum_start,
+              cop->csum_len);
+}
+
+static void print_cryptocop_operation(struct cryptocop_operation *cop)
+{
+       struct cryptocop_desc      *d;
+       struct cryptocop_tfrm_cfg  *tc;
+       struct cryptocop_desc_cfg  *dc;
+       int                        i;
+
+       printk("print_cryptocop_operation, cop=0x%p\n\n", cop);
+       printk("sid: %lld\n", cop->sid);
+       printk("operation_status=%d\n"
+              "use_dmalists=%d\n"
+              "in_interrupt=%d\n"
+              "fast_callback=%d\n",
+              cop->operation_status,
+              cop->use_dmalists,
+              cop->in_interrupt,
+              cop->fast_callback);
+
+       if (cop->use_dmalists){
+               print_user_dma_lists(&cop->list_op);
+       } else {
+               printk("cop->tfrm_op\n"
+                      "tfrm_cfg=0x%p\n"
+                      "desc=0x%p\n"
+                      "indata=0x%p\n"
+                      "incount=%d\n"
+                      "inlen=%d\n"
+                      "outdata=0x%p\n"
+                      "outcount=%d\n"
+                      "outlen=%d\n\n",
+                      cop->tfrm_op.tfrm_cfg,
+                      cop->tfrm_op.desc,
+                      cop->tfrm_op.indata,
+                      cop->tfrm_op.incount,
+                      cop->tfrm_op.inlen,
+                      cop->tfrm_op.outdata,
+                      cop->tfrm_op.outcount,
+                      cop->tfrm_op.outlen);
+
+               tc = cop->tfrm_op.tfrm_cfg;
+               while (tc){
+                       printk("tfrm_cfg, 0x%p\n"
+                              "tid=%d\n"
+                              "flags=%d\n"
+                              "inject_ix=%d\n"
+                              "next=0x%p\n",
+                              tc,
+                              tc->tid,
+                              tc->flags,
+                              tc->inject_ix,
+                              tc->next);
+                       tc = tc->next;
+               }
+               d = cop->tfrm_op.desc;
+               while (d){
+                       printk("\n======================desc, 0x%p\n"
+                              "length=%d\n"
+                              "cfg=0x%p\n"
+                              "next=0x%p\n",
+                              d,
+                              d->length,
+                              d->cfg,
+                              d->next);
+                       dc = d->cfg;
+                       while (dc){
+                               printk("=========desc_cfg, 0x%p\n"
+                                      "tid=%d\n"
+                                      "src=%d\n"
+                                      "last=%d\n"
+                                      "next=0x%p\n",
+                                      dc,
+                                      dc->tid,
+                                      dc->src,
+                                      dc->last,
+                                      dc->next);
+                               dc = dc->next;
+                       }
+                       d = d->next;
+               }
+               printk("\n====iniov\n");
+               for (i = 0; i < cop->tfrm_op.incount; i++){
+                       printk("indata[%d]\n"
+                              "base=0x%p\n"
+                              "len=%d\n",
+                              i,
+                              cop->tfrm_op.indata[i].iov_base,
+                              cop->tfrm_op.indata[i].iov_len);
+               }
+               printk("\n====outiov\n");
+               for (i = 0; i < cop->tfrm_op.outcount; i++){
+                       printk("outdata[%d]\n"
+                              "base=0x%p\n"
+                              "len=%d\n",
+                              i,
+                              cop->tfrm_op.outdata[i].iov_base,
+                              cop->tfrm_op.outdata[i].iov_len);
+               }
+       }
+       printk("------------end print_cryptocop_operation\n");
+}
+
+
+static void print_user_dma_lists(struct cryptocop_dma_list_operation *dma_op)
+{
+       dma_descr_data *dd;
+       int i;
+
+       printk("print_user_dma_lists, dma_op=0x%p\n", dma_op);
+
+       printk("out_data_buf = 0x%p, phys_to_virt(out_data_buf) = 0x%p\n", 
dma_op->out_data_buf, phys_to_virt((unsigned long int)dma_op->out_data_buf));
+       printk("in_data_buf = 0x%p, phys_to_virt(in_data_buf) = 0x%p\n", 
dma_op->in_data_buf, phys_to_virt((unsigned long int)dma_op->in_data_buf));
+
+       printk("##############outlist\n");
+       dd = phys_to_virt((unsigned long int)dma_op->outlist);
+       i = 0;
+       while (dd != NULL) {
+               printk("#%d phys_to_virt(desc) 0x%p\n", i, dd);
+               printk("\n\tbuf: 0x%p\n"
+                      "\tafter: 0x%p\n"
+                      "\tmd: 0x%04x\n"
+                      "\tnext: 0x%p\n",
+                      dd->buf,
+                      dd->after,
+                      dd->md,
+                      dd->next);
+               printk("flags:\n"
+                      "\twait:\t%d\n"
+                      "\teol:\t%d\n"
+                      "\touteop:\t%d\n"
+                      "\tineop:\t%d\n"
+                      "\tintr:\t%d\n",
+                      dd->wait,
+                      dd->eol,
+                      dd->out_eop,
+                      dd->in_eop,
+                      dd->intr);
+               if (dd->eol)
+                       dd = NULL;
+               else
+                       dd = phys_to_virt((unsigned long int)dd->next);
+               ++i;
+       }
+
+       printk("##############inlist\n");
+       dd = phys_to_virt((unsigned long int)dma_op->inlist);
+       i = 0;
+       while (dd != NULL) {
+               printk("#%d phys_to_virt(desc) 0x%p\n", i, dd);
+               printk("\n\tbuf: 0x%p\n"
+                      "\tafter: 0x%p\n"
+                      "\tmd: 0x%04x\n"
+                      "\tnext: 0x%p\n",
+                      dd->buf,
+                      dd->after,
+                      dd->md,
+                      dd->next);
+               printk("flags:\n"
+                      "\twait:\t%d\n"
+                      "\teol:\t%d\n"
+                      "\touteop:\t%d\n"
+                      "\tineop:\t%d\n"
+                      "\tintr:\t%d\n",
+                      dd->wait,
+                      dd->eol,
+                      dd->out_eop,
+                      dd->in_eop,
+                      dd->intr);
+               if (dd->eol)
+                       dd = NULL;
+               else
+                       dd = phys_to_virt((unsigned long int)dd->next);
+               ++i;
+       }
+}
+
+
+static void print_lock_status(void)
+{
+       printk("**********************print_lock_status\n");
+       printk("cryptocop_completed_jobs_lock %d\n", 
spin_is_locked(&cryptocop_completed_jobs_lock));
+       printk("cryptocop_job_queue_lock %d\n", 
spin_is_locked(&cryptocop_job_queue_lock));
+       printk("descr_pool_lock %d\n", spin_is_locked(&descr_pool_lock));
+       printk("cryptocop_sessions_lock %d\n", 
spin_is_locked(cryptocop_sessions_lock));
+       printk("running_job_lock %d\n", spin_is_locked(running_job_lock));
+       printk("cryptocop_process_lock %d\n", 
spin_is_locked(cryptocop_process_lock));
+}
+#endif /* LDEBUG */
+
+
+static const char cryptocop_name[] = "ETRAX FS stream co-processor";
+
+static int init_stream_coprocessor(void)
+{
+       int err;
+       int i;
+       static int initialized = 0;
+
+       if (initialized)
+               return 0;
+
+       initialized = 1;
+
+       printk("ETRAX FS stream co-processor driver v0.01, (c) 2003 Axis 
Communications AB\n");
+
+       err = register_chrdev(CRYPTOCOP_MAJOR, cryptocop_name, &cryptocop_fops);
+       if (err < 0) {
+               printk(KERN_ERR "stream co-processor: could not get major 
number.\n");
+               return err;
+       }
+
+       err = init_cryptocop();
+       if (err) {
+               (void)unregister_chrdev(CRYPTOCOP_MAJOR, cryptocop_name);
+               return err;
+       }
+       err = cryptocop_job_queue_init();
+       if (err) {
+               release_cryptocop();
+               (void)unregister_chrdev(CRYPTOCOP_MAJOR, cryptocop_name);
+               return err;
+       }
+       /* Init the descriptor pool. */
+       for (i = 0; i < CRYPTOCOP_DESCRIPTOR_POOL_SIZE - 1; i++) {
+               descr_pool[i].from_pool = 1;
+               descr_pool[i].next = &descr_pool[i + 1];
+       }
+       descr_pool[i].from_pool = 1;
+       descr_pool[i].next = NULL;
+       descr_pool_free_list = &descr_pool[0];
+       descr_pool_no_free = CRYPTOCOP_DESCRIPTOR_POOL_SIZE;
+
+       spin_lock_init(&cryptocop_completed_jobs_lock);
+       spin_lock_init(&cryptocop_job_queue_lock);
+       spin_lock_init(&descr_pool_lock);
+       spin_lock_init(&cryptocop_sessions_lock);
+       spin_lock_init(&running_job_lock);
+       spin_lock_init(&cryptocop_process_lock);
+
+       cryptocop_sessions = NULL;
+       next_sid = 1;
+
+       cryptocop_running_job = NULL;
+
+       printk("stream co-processor: init done.\n");
+       return 0;
+}
+
+static void __exit exit_stream_coprocessor(void)
+{
+       release_cryptocop();
+       cryptocop_job_queue_close();
+}
+
+module_init(init_stream_coprocessor);
+module_exit(exit_stream_coprocessor);
+
diff -urN linux/arch/cris/arch-v32/drivers/gpio.c 
linux/arch/cris/arch-v32/drivers/gpio.c
--- linux/arch/cris/arch-v32/drivers/gpio.c     1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/drivers/gpio.c     2005-08-01 19:23:42.268250000 
+0100     1.1
@@ -0,0 +1,766 @@
+/* $Id: gpio.c,v 1.16 2005/06/19 17:06:49 starvik Exp $
+ *
+ * ETRAX CRISv32 general port I/O device
+ *
+ * Copyright (c) 1999, 2000, 2001, 2002, 2003 Axis Communications AB
+ *
+ * Authors:    Bjorn Wesen      (initial version)
+ *             Ola Knutsson     (LED handling)
+ *             Johan Adolfsson  (read/set directions, write, port G,
+ *                               port to ETRAX FS.
+ *
+ * $Log: gpio.c,v $
+ * Revision 1.16  2005/06/19 17:06:49  starvik
+ * Merge of Linux 2.6.12.
+ *
+ * Revision 1.15  2005/05/25 08:22:20  starvik
+ * Changed GPIO port order to fit packages/devices/axis-2.4.
+ *
+ * Revision 1.14  2005/04/24 18:35:08  starvik
+ * Updated with final register headers.
+ *
+ * Revision 1.13  2005/03/15 15:43:00  starvik
+ * dev_id needs to be supplied for shared IRQs.
+ *
+ * Revision 1.12  2005/03/10 17:12:00  starvik
+ * Protect alarm list with spinlock.
+ *
+ * Revision 1.11  2005/01/05 06:08:59  starvik
+ * No need to do local_irq_disable after local_irq_save.
+ *
+ * Revision 1.10  2004/11/19 08:38:31  starvik
+ * Removed old crap.
+ *
+ * Revision 1.9  2004/05/14 07:58:02  starvik
+ * Merge of changes from 2.4
+ *
+ * Revision 1.8  2003/09/11 07:29:50  starvik
+ * Merge of Linux 2.6.0-test5
+ *
+ * Revision 1.7  2003/07/10 13:25:46  starvik
+ * Compiles for 2.5.74
+ * Lindented ethernet.c
+ *
+ * Revision 1.6  2003/07/04 08:27:46  starvik
+ * Merge of Linux 2.5.74
+ *
+ * Revision 1.5  2003/06/10 08:26:37  johana
+ * Etrax -> ETRAX CRISv32
+ *
+ * Revision 1.4  2003/06/05 14:22:48  johana
+ * Initialise some_alarms.
+ *
+ * Revision 1.3  2003/06/05 10:15:46  johana
+ * New INTR_VECT macros.
+ * Enable interrupts in global config.
+ *
+ * Revision 1.2  2003/06/03 15:52:50  johana
+ * Initial CRIS v32 version.
+ *
+ * Revision 1.1  2003/06/03 08:53:15  johana
+ * Copy of os/lx25/arch/cris/arch-v10/drivers/gpio.c version 1.7.
+ *
+ */
+
+#include <linux/config.h>
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+#include <asm/etraxgpio.h>
+#include <asm/arch/hwregs/reg_map.h>
+#include <asm/arch/hwregs/reg_rdwr.h>
+#include <asm/arch/hwregs/gio_defs.h>
+#include <asm/arch/hwregs/intr_vect_defs.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+
+/* The following gio ports on ETRAX FS is available:
+ * pa  8 bits, supports interrupts off, hi, low, set, posedge, negedge anyedge
+ * pb 18 bits
+ * pc 18 bits
+ * pd 18 bits
+ * pe 18 bits
+ * each port has a rw_px_dout, r_px_din and rw_px_oe register.
+ */
+
+#define GPIO_MAJOR 120  /* experimental MAJOR number */
+
+#define D(x)
+
+#if 0
+static int dp_cnt;
+#define DP(x) do { dp_cnt++; if (dp_cnt % 1000 == 0) x; }while(0)
+#else
+#define DP(x)
+#endif
+
+static char gpio_name[] = "etrax gpio";
+
+#if 0
+static wait_queue_head_t *gpio_wq;
+#endif
+
+static int gpio_ioctl(struct inode *inode, struct file *file,
+                     unsigned int cmd, unsigned long arg);
+static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
+                          loff_t *off);
+static int gpio_open(struct inode *inode, struct file *filp);
+static int gpio_release(struct inode *inode, struct file *filp);
+static unsigned int gpio_poll(struct file *filp, struct poll_table_struct 
*wait);
+
+/* private data per open() of this driver */
+
+struct gpio_private {
+       struct gpio_private *next;
+       /* The IO_CFG_WRITE_MODE_VALUE only support 8 bits: */
+       unsigned char clk_mask;
+       unsigned char data_mask;
+       unsigned char write_msb;
+       unsigned char pad1;
+       /* These fields are generic */
+       unsigned long highalarm, lowalarm;
+       wait_queue_head_t alarm_wq;
+       int minor;
+};
+
+/* linked list of alarms to check for */
+
+static struct gpio_private *alarmlist = 0;
+
+static int gpio_some_alarms = 0; /* Set if someone uses alarm */
+static unsigned long gpio_pa_high_alarms = 0;
+static unsigned long gpio_pa_low_alarms = 0;
+
+static DEFINE_SPINLOCK(alarm_lock);
+
+#define NUM_PORTS (GPIO_MINOR_LAST+1)
+#define GIO_REG_RD_ADDR(reg) (volatile unsigned long*) (regi_gio + 
REG_RD_ADDR_gio_##reg )
+#define GIO_REG_WR_ADDR(reg) (volatile unsigned long*) (regi_gio + 
REG_RD_ADDR_gio_##reg )
+unsigned long led_dummy;
+
+static volatile unsigned long *data_out[NUM_PORTS] = {
+       GIO_REG_WR_ADDR(rw_pa_dout),
+       GIO_REG_WR_ADDR(rw_pb_dout),
+       &led_dummy,
+       GIO_REG_WR_ADDR(rw_pc_dout),
+       GIO_REG_WR_ADDR(rw_pd_dout),
+       GIO_REG_WR_ADDR(rw_pe_dout),
+};
+
+static volatile unsigned long *data_in[NUM_PORTS] = {
+       GIO_REG_RD_ADDR(r_pa_din),
+       GIO_REG_RD_ADDR(r_pb_din),
+       &led_dummy,
+       GIO_REG_RD_ADDR(r_pc_din),
+       GIO_REG_RD_ADDR(r_pd_din),
+       GIO_REG_RD_ADDR(r_pe_din),
+};
+
+static unsigned long changeable_dir[NUM_PORTS] = {
+       CONFIG_ETRAX_PA_CHANGEABLE_DIR,
+       CONFIG_ETRAX_PB_CHANGEABLE_DIR,
+       0,
+       CONFIG_ETRAX_PC_CHANGEABLE_DIR,
+       CONFIG_ETRAX_PD_CHANGEABLE_DIR,
+       CONFIG_ETRAX_PE_CHANGEABLE_DIR,
+};
+
+static unsigned long changeable_bits[NUM_PORTS] = {
+       CONFIG_ETRAX_PA_CHANGEABLE_BITS,
+       CONFIG_ETRAX_PB_CHANGEABLE_BITS,
+       0,
+       CONFIG_ETRAX_PC_CHANGEABLE_BITS,
+       CONFIG_ETRAX_PD_CHANGEABLE_BITS,
+       CONFIG_ETRAX_PE_CHANGEABLE_BITS,
+};
+
+static volatile unsigned long *dir_oe[NUM_PORTS] = {
+       GIO_REG_WR_ADDR(rw_pa_oe),
+       GIO_REG_WR_ADDR(rw_pb_oe),
+       &led_dummy,
+       GIO_REG_WR_ADDR(rw_pc_oe),
+       GIO_REG_WR_ADDR(rw_pd_oe),
+       GIO_REG_WR_ADDR(rw_pe_oe),
+};
+
+
+
+static unsigned int
+gpio_poll(struct file *file,
+         poll_table *wait)
+{
+       unsigned int mask = 0;
+       struct gpio_private *priv = (struct gpio_private *)file->private_data;
+       unsigned long data;
+       poll_wait(file, &priv->alarm_wq, wait);
+       if (priv->minor == GPIO_MINOR_A) {
+               reg_gio_rw_intr_cfg intr_cfg;
+               unsigned long tmp;
+               unsigned long flags;
+
+               local_irq_save(flags);
+               data = REG_TYPE_CONV(unsigned long, reg_gio_r_pa_din, 
REG_RD(gio, regi_gio, r_pa_din));
+               /* PA has support for interrupt
+                * lets activate high for those low and with highalarm set
+                */
+               intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg);
+
+               tmp = ~data & priv->highalarm & 0xFF;
+                if (tmp & (1 << 0)) {
+                       intr_cfg.pa0 = regk_gio_hi;
+               }
+                if (tmp & (1 << 1)) {
+                       intr_cfg.pa1 = regk_gio_hi;
+               }
+                if (tmp & (1 << 2)) {
+                       intr_cfg.pa2 = regk_gio_hi;
+               }
+                if (tmp & (1 << 3)) {
+                       intr_cfg.pa3 = regk_gio_hi;
+               }
+                if (tmp & (1 << 4)) {
+                       intr_cfg.pa4 = regk_gio_hi;
+               }
+                if (tmp & (1 << 5)) {
+                       intr_cfg.pa5 = regk_gio_hi;
+               }
+                if (tmp & (1 << 6)) {
+                       intr_cfg.pa6 = regk_gio_hi;
+               }
+                if (tmp & (1 << 7)) {
+                       intr_cfg.pa7 = regk_gio_hi;
+               }
+               /*
+                * lets activate low for those high and with lowalarm set
+                */
+               tmp = data & priv->lowalarm & 0xFF;
+                if (tmp & (1 << 0)) {
+                       intr_cfg.pa0 = regk_gio_lo;
+               }
+                if (tmp & (1 << 1)) {
+                       intr_cfg.pa1 = regk_gio_lo;
+               }
+                if (tmp & (1 << 2)) {
+                       intr_cfg.pa2 = regk_gio_lo;
+               }
+                if (tmp & (1 << 3)) {
+                       intr_cfg.pa3 = regk_gio_lo;
+               }
+                if (tmp & (1 << 4)) {
+                       intr_cfg.pa4 = regk_gio_lo;
+               }
+                if (tmp & (1 << 5)) {
+                       intr_cfg.pa5 = regk_gio_lo;
+               }
+                if (tmp & (1 << 6)) {
+                       intr_cfg.pa6 = regk_gio_lo;
+               }
+                if (tmp & (1 << 7)) {
+                       intr_cfg.pa7 = regk_gio_lo;
+               }
+
+               REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg);
+               local_irq_restore(flags);
+       } else if (priv->minor <= GPIO_MINOR_E)
+               data = *data_in[priv->minor];
+       else
+               return 0;
+
+       if ((data & priv->highalarm) ||
+           (~data & priv->lowalarm)) {
+               mask = POLLIN|POLLRDNORM;
+       }
+
+       DP(printk("gpio_poll ready: mask 0x%08X\n", mask));
+       return mask;
+}
+
+int etrax_gpio_wake_up_check(void)
+{
+       struct gpio_private *priv = alarmlist;
+       unsigned long data = 0;
+        int ret = 0;
+       while (priv) {
+               data = *data_in[priv->minor];
+               if ((data & priv->highalarm) ||
+                   (~data & priv->lowalarm)) {
+                       DP(printk("etrax_gpio_wake_up_check %i\n",priv->minor));
+                       wake_up_interruptible(&priv->alarm_wq);
+                        ret = 1;
+               }
+               priv = priv->next;
+       }
+        return ret;
+}
+
+static irqreturn_t
+gpio_poll_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       if (gpio_some_alarms) {
+               return IRQ_RETVAL(etrax_gpio_wake_up_check());
+       }
+        return IRQ_NONE;
+}
+
+static irqreturn_t
+gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       reg_gio_rw_intr_mask intr_mask;
+       reg_gio_r_masked_intr masked_intr;
+       reg_gio_rw_ack_intr ack_intr;
+       unsigned long tmp;
+       unsigned long tmp2;
+
+       /* Find what PA interrupts are active */
+       masked_intr = REG_RD(gio, regi_gio, r_masked_intr);
+       tmp = REG_TYPE_CONV(unsigned long, reg_gio_r_masked_intr, masked_intr);
+
+       /* Find those that we have enabled */
+       spin_lock(&alarm_lock);
+       tmp &= (gpio_pa_high_alarms | gpio_pa_low_alarms);
+       spin_unlock(&alarm_lock);
+
+       /* Ack them */
+       ack_intr = REG_TYPE_CONV(reg_gio_rw_ack_intr, unsigned long, tmp);
+       REG_WR(gio, regi_gio, rw_ack_intr, ack_intr);
+
+       /* Disable those interrupts.. */
+       intr_mask = REG_RD(gio, regi_gio, rw_intr_mask);
+       tmp2 = REG_TYPE_CONV(unsigned long, reg_gio_rw_intr_mask, intr_mask);
+       tmp2 &= ~tmp;
+       intr_mask = REG_TYPE_CONV(reg_gio_rw_intr_mask, unsigned long, tmp2);
+       REG_WR(gio, regi_gio, rw_intr_mask, intr_mask);
+
+       if (gpio_some_alarms) {
+               return IRQ_RETVAL(etrax_gpio_wake_up_check());
+       }
+        return IRQ_NONE;
+}
+
+
+static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
+                          loff_t *off)
+{
+       struct gpio_private *priv = (struct gpio_private *)file->private_data;
+       unsigned char data, clk_mask, data_mask, write_msb;
+       unsigned long flags;
+       unsigned long shadow;
+       volatile unsigned long *port;
+       ssize_t retval = count;
+       /* Only bits 0-7 may be used for write operations but allow all
+          devices except leds... */
+       if (priv->minor == GPIO_MINOR_LEDS) {
+               return -EFAULT;
+       }
+
+       if (!access_ok(VERIFY_READ, buf, count)) {
+               return -EFAULT;
+       }
+       clk_mask = priv->clk_mask;
+       data_mask = priv->data_mask;
+       /* It must have been configured using the IO_CFG_WRITE_MODE */
+       /* Perhaps a better error code? */
+       if (clk_mask == 0 || data_mask == 0) {
+               return -EPERM;
+       }
+       write_msb = priv->write_msb;
+       D(printk("gpio_write: %lu to data 0x%02X clk 0x%02X msb: %i\n",count, 
data_mask, clk_mask, write_msb));
+       port = data_out[priv->minor];
+
+       while (count--) {
+               int i;
+               data = *buf++;
+               if (priv->write_msb) {
+                       for (i = 7; i >= 0;i--) {
+                               local_irq_save(flags);
+                               shadow = *port;
+                               *port = shadow &= ~clk_mask;
+                               if (data & 1<<i)
+                                       *port = shadow |= data_mask;
+                               else
+                                       *port = shadow &= ~data_mask;
+                       /* For FPGA: min 5.0ns (DCC) before CCLK high */
+                               *port = shadow |= clk_mask;
+                               local_irq_restore(flags);
+                       }
+               } else {
+                       for (i = 0; i <= 7;i++) {
+                               local_irq_save(flags);
+                               shadow = *port;
+                               *port = shadow &= ~clk_mask;
+                               if (data & 1<<i)
+                                       *port = shadow |= data_mask;
+                               else
+                                       *port = shadow &= ~data_mask;
+                       /* For FPGA: min 5.0ns (DCC) before CCLK high */
+                               *port = shadow |= clk_mask;
+                               local_irq_restore(flags);
+                       }
+               }
+       }
+       return retval;
+}
+
+
+
+static int
+gpio_open(struct inode *inode, struct file *filp)
+{
+       struct gpio_private *priv;
+       int p = MINOR(inode->i_rdev);
+
+       if (p > GPIO_MINOR_LAST)
+               return -EINVAL;
+
+       priv = (struct gpio_private *)kmalloc(sizeof(struct gpio_private),
+                                             GFP_KERNEL);
+
+       if (!priv)
+               return -ENOMEM;
+
+       priv->minor = p;
+
+       /* initialize the io/alarm struct and link it into our alarmlist */
+
+       priv->next = alarmlist;
+       alarmlist = priv;
+       priv->clk_mask = 0;
+       priv->data_mask = 0;
+       priv->highalarm = 0;
+       priv->lowalarm = 0;
+       init_waitqueue_head(&priv->alarm_wq);
+
+       filp->private_data = (void *)priv;
+
+       return 0;
+}
+
+static int
+gpio_release(struct inode *inode, struct file *filp)
+{
+       struct gpio_private *p = alarmlist;
+       struct gpio_private *todel = (struct gpio_private *)filp->private_data;
+       /* local copies while updating them: */
+       unsigned long a_high, a_low;
+       unsigned long some_alarms;
+
+       /* unlink from alarmlist and free the private structure */
+
+       if (p == todel) {
+               alarmlist = todel->next;
+       } else {
+               while (p->next != todel)
+                       p = p->next;
+               p->next = todel->next;
+       }
+
+       kfree(todel);
+       /* Check if there are still any alarms set */
+       p = alarmlist;
+        some_alarms = 0;
+       a_high = 0;
+       a_low = 0;
+       while (p) {
+               if (p->minor == GPIO_MINOR_A) {
+                       a_high |= p->highalarm;
+                       a_low |= p->lowalarm;
+               }
+
+               if (p->highalarm | p->lowalarm) {
+                       some_alarms = 1;
+               }
+               p = p->next;
+       }
+
+       spin_lock(&alarm_lock);
+       gpio_some_alarms = some_alarms;
+       gpio_pa_high_alarms = a_high;
+       gpio_pa_low_alarms = a_low;
+       spin_unlock(&alarm_lock);
+
+       return 0;
+}
+
+/* Main device API. ioctl's to read/set/clear bits, as well as to
+ * set alarms to wait for using a subsequent select().
+ */
+
+unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg)
+{
+       /* Set direction 0=unchanged 1=input,
+        * return mask with 1=input
+        */
+       unsigned long flags;
+       unsigned long dir_shadow;
+
+       local_irq_save(flags);
+       dir_shadow = *dir_oe[priv->minor];
+       dir_shadow &= ~(arg & changeable_dir[priv->minor]);
+       *dir_oe[priv->minor] = dir_shadow;
+       local_irq_restore(flags);
+
+       if (priv->minor == GPIO_MINOR_A)
+               dir_shadow ^= 0xFF;    /* Only 8 bits */
+       else
+               dir_shadow ^= 0x3FFFF; /* Only 18 bits */
+       return dir_shadow;
+
+} /* setget_input */
+
+unsigned long inline setget_output(struct gpio_private *priv, unsigned long 
arg)
+{
+       unsigned long flags;
+       unsigned long dir_shadow;
+
+       local_irq_save(flags);
+       dir_shadow = *dir_oe[priv->minor];
+       dir_shadow |=  (arg & changeable_dir[priv->minor]);
+       *dir_oe[priv->minor] = dir_shadow;
+       local_irq_restore(flags);
+       return dir_shadow;
+} /* setget_output */
+
+static int
+gpio_leds_ioctl(unsigned int cmd, unsigned long arg);
+
+static int
+gpio_ioctl(struct inode *inode, struct file *file,
+          unsigned int cmd, unsigned long arg)
+{
+       unsigned long flags;
+       unsigned long val;
+       unsigned long shadow;
+       struct gpio_private *priv = (struct gpio_private *)file->private_data;
+       if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {
+               return -EINVAL;
+       }
+
+       switch (_IOC_NR(cmd)) {
+       case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */
+               // read the port
+               return *data_in[priv->minor];
+               break;
+       case IO_SETBITS:
+               local_irq_save(flags);
+                if (arg & 0x04)
+                  printk("GPIO SET 2\n");
+               // set changeable bits with a 1 in arg
+               shadow = *data_out[priv->minor];
+               shadow |=  (arg & changeable_bits[priv->minor]);
+               *data_out[priv->minor] = shadow;
+               local_irq_restore(flags);
+               break;
+       case IO_CLRBITS:
+               local_irq_save(flags);
+                if (arg & 0x04)
+                  printk("GPIO CLR 2\n");
+               // clear changeable bits with a 1 in arg
+               shadow = *data_out[priv->minor];
+               shadow &=  ~(arg & changeable_bits[priv->minor]);
+               *data_out[priv->minor] = shadow;
+               local_irq_restore(flags);
+               break;
+       case IO_HIGHALARM:
+               // set alarm when bits with 1 in arg go high
+               priv->highalarm |= arg;
+               spin_lock(&alarm_lock);
+               gpio_some_alarms = 1;
+               if (priv->minor == GPIO_MINOR_A) {
+                       gpio_pa_high_alarms |= arg;
+               }
+               spin_unlock(&alarm_lock);
+               break;
+       case IO_LOWALARM:
+               // set alarm when bits with 1 in arg go low
+               priv->lowalarm |= arg;
+               spin_lock(&alarm_lock);
+               gpio_some_alarms = 1;
+               if (priv->minor == GPIO_MINOR_A) {
+                       gpio_pa_low_alarms |= arg;
+               }
+               spin_unlock(&alarm_lock);
+               break;
+       case IO_CLRALARM:
+               // clear alarm for bits with 1 in arg
+               priv->highalarm &= ~arg;
+               priv->lowalarm  &= ~arg;
+               spin_lock(&alarm_lock);
+               if (priv->minor == GPIO_MINOR_A) {
+                       if (gpio_pa_high_alarms & arg ||
+                           gpio_pa_low_alarms & arg) {
+                               /* Must update the gpio_pa_*alarms masks */
+                       }
+               }
+               spin_unlock(&alarm_lock);
+               break;
+       case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */
+               /* Read direction 0=input 1=output */
+               return *dir_oe[priv->minor];
+       case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */
+               /* Set direction 0=unchanged 1=input,
+                * return mask with 1=input
+                */
+               return setget_input(priv, arg);
+               break;
+       case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */
+               /* Set direction 0=unchanged 1=output,
+                * return mask with 1=output
+                */
+               return setget_output(priv, arg);
+
+       case IO_CFG_WRITE_MODE:
+       {
+               unsigned long dir_shadow;
+               dir_shadow = *dir_oe[priv->minor];
+
+               priv->clk_mask = arg & 0xFF;
+               priv->data_mask = (arg >> 8) & 0xFF;
+               priv->write_msb = (arg >> 16) & 0x01;
+               /* Check if we're allowed to change the bits and
+                * the direction is correct
+                */
+               if (!((priv->clk_mask & changeable_bits[priv->minor]) &&
+                     (priv->data_mask & changeable_bits[priv->minor]) &&
+                     (priv->clk_mask & dir_shadow) &&
+                     (priv->data_mask & dir_shadow)))
+               {
+                       priv->clk_mask = 0;
+                       priv->data_mask = 0;
+                       return -EPERM;
+               }
+               break;
+       }
+       case IO_READ_INBITS:
+               /* *arg is result of reading the input pins */
+               val = *data_in[priv->minor];
+               if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+                       return -EFAULT;
+               return 0;
+               break;
+       case IO_READ_OUTBITS:
+                /* *arg is result of reading the output shadow */
+               val = *data_out[priv->minor];
+               if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+                       return -EFAULT;
+               break;
+       case IO_SETGET_INPUT:
+               /* bits set in *arg is set to input,
+                * *arg updated with current input pins.
+                */
+               if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
+                       return -EFAULT;
+               val = setget_input(priv, val);
+               if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+                       return -EFAULT;
+               break;
+       case IO_SETGET_OUTPUT:
+               /* bits set in *arg is set to output,
+                * *arg updated with current output pins.
+                */
+               if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
+                       return -EFAULT;
+               val = setget_output(priv, val);
+               if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
+                       return -EFAULT;
+               break;
+       default:
+               if (priv->minor == GPIO_MINOR_LEDS)
+                       return gpio_leds_ioctl(cmd, arg);
+               else
+                       return -EINVAL;
+       } /* switch */
+
+       return 0;
+}
+
+static int
+gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
+{
+       unsigned char green;
+       unsigned char red;
+
+       switch (_IOC_NR(cmd)) {
+       case IO_LEDACTIVE_SET:
+               green = ((unsigned char) arg) & 1;
+               red   = (((unsigned char) arg) >> 1) & 1;
+               LED_ACTIVE_SET_G(green);
+               LED_ACTIVE_SET_R(red);
+               break;
+
+       default:
+               return -EINVAL;
+       } /* switch */
+
+       return 0;
+}
+
+struct file_operations gpio_fops = {
+       .owner       = THIS_MODULE,
+       .poll        = gpio_poll,
+       .ioctl       = gpio_ioctl,
+       .write       = gpio_write,
+       .open        = gpio_open,
+       .release     = gpio_release,
+};
+
+
+/* main driver initialization routine, called from mem.c */
+
+static __init int
+gpio_init(void)
+{
+       int res;
+       reg_intr_vect_rw_mask intr_mask;
+
+       /* do the formalities */
+
+       res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops);
+       if (res < 0) {
+               printk(KERN_ERR "gpio: couldn't get a major number.\n");
+               return res;
+       }
+
+       /* Clear all leds */
+       LED_NETWORK_SET(0);
+       LED_ACTIVE_SET(0);
+       LED_DISK_READ(0);
+       LED_DISK_WRITE(0);
+
+       printk("ETRAX FS GPIO driver v2.5, (c) 2003-2005 Axis Communications 
AB\n");
+       /* We call etrax_gpio_wake_up_check() from timer interrupt and
+        * from cpu_idle() in kernel/process.c
+        * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms
+        * in some tests.
+        */
+       if (request_irq(TIMER_INTR_VECT, gpio_poll_timer_interrupt,
+                       SA_SHIRQ | SA_INTERRUPT,"gpio poll", &alarmlist)) {
+               printk("err: timer0 irq for gpio\n");
+       }
+       if (request_irq(GEN_IO_INTR_VECT, gpio_pa_interrupt,
+                       SA_SHIRQ | SA_INTERRUPT,"gpio PA", &alarmlist)) {
+               printk("err: PA irq for gpio\n");
+       }
+       /* enable the gio and timer irq in global config */
+       intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
+       intr_mask.timer = 1;
+       intr_mask.gen_io = 1;
+       REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
+
+       return res;
+}
+
+/* this makes sure that gpio_init is called during kernel boot */
+
+module_init(gpio_init);
diff -urN linux/arch/cris/arch-v32/drivers/i2c.c 
linux/arch/cris/arch-v32/drivers/i2c.c
--- linux/arch/cris/arch-v32/drivers/i2c.c      1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/drivers/i2c.c      2005-08-01 19:23:42.295726000 
+0100     1.1
@@ -0,0 +1,611 @@
+/*!***************************************************************************
+*!
+*! FILE NAME  : i2c.c
+*!
+*! DESCRIPTION: implements an interface for IIC/I2C, both directly from other
+*!              kernel modules (i2c_writereg/readreg) and from userspace using
+*!              ioctl()'s
+*!
+*! Nov 30 1998  Torbjorn Eliasson  Initial version.
+*!              Bjorn Wesen        Elinux kernel version.
+*! Jan 14 2000  Johan Adolfsson    Fixed PB shadow register stuff -
+*!                                 don't use PB_I2C if DS1302 uses same bits,
+*!                                 use PB.
+*| June 23 2003 Pieter Grimmerink  Added 'i2c_sendnack'. i2c_readreg now
+*|                                 generates nack on last received byte,
+*|                                 instead of ack.
+*|                                 i2c_getack changed data level while clock
+*|                                 was high, causing DS75 to see  a stop 
condition
+*!
+*! ---------------------------------------------------------------------------
+*!
+*! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN
+*!
+*!***************************************************************************/
+/* $Id: i2c.c,v 1.2 2005/05/09 15:29:49 starvik Exp $ */
+/****************** INCLUDE FILES SECTION ***********************************/
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/config.h>
+
+#include <asm/etraxi2c.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+
+#include "i2c.h"
+
+/****************** I2C DEFINITION SECTION *************************/
+
+#define D(x)
+
+#define I2C_MAJOR 123  /* LOCAL/EXPERIMENTAL */
+static const char i2c_name[] = "i2c";
+
+#define CLOCK_LOW_TIME            8
+#define CLOCK_HIGH_TIME           8
+#define START_CONDITION_HOLD_TIME 8
+#define STOP_CONDITION_HOLD_TIME  8
+#define ENABLE_OUTPUT 0x01
+#define ENABLE_INPUT 0x00
+#define I2C_CLOCK_HIGH 1
+#define I2C_CLOCK_LOW 0
+#define I2C_DATA_HIGH 1
+#define I2C_DATA_LOW 0
+
+#define i2c_enable()
+#define i2c_disable()
+
+/* enable or disable output-enable, to select output or input on the i2c bus */
+
+#define i2c_dir_out() crisv32_io_set_dir(&cris_i2c_data, crisv32_io_dir_out)
+#define i2c_dir_in() crisv32_io_set_dir(&cris_i2c_data, crisv32_io_dir_in)
+
+/* control the i2c clock and data signals */
+
+#define i2c_clk(x) crisv32_io_set(&cris_i2c_clk, x)
+#define i2c_data(x) crisv32_io_set(&cris_i2c_data, x)
+
+/* read a bit from the i2c interface */
+
+#define i2c_getbit() crisv32_io_rd(&cris_i2c_data)
+
+#define i2c_delay(usecs) udelay(usecs)
+
+/****************** VARIABLE SECTION ************************************/
+
+static struct crisv32_iopin cris_i2c_clk;
+static struct crisv32_iopin cris_i2c_data;
+
+/****************** FUNCTION DEFINITION SECTION *************************/
+
+
+/* generate i2c start condition */
+
+void
+i2c_start(void)
+{
+       /*
+        * SCL=1 SDA=1
+        */
+       i2c_dir_out();
+       i2c_delay(CLOCK_HIGH_TIME/6);
+       i2c_data(I2C_DATA_HIGH);
+       i2c_clk(I2C_CLOCK_HIGH);
+       i2c_delay(CLOCK_HIGH_TIME);
+       /*
+        * SCL=1 SDA=0
+        */
+       i2c_data(I2C_DATA_LOW);
+       i2c_delay(START_CONDITION_HOLD_TIME);
+       /*
+        * SCL=0 SDA=0
+        */
+       i2c_clk(I2C_CLOCK_LOW);
+       i2c_delay(CLOCK_LOW_TIME);
+}
+
+/* generate i2c stop condition */
+
+void
+i2c_stop(void)
+{
+       i2c_dir_out();
+
+       /*
+        * SCL=0 SDA=0
+        */
+       i2c_clk(I2C_CLOCK_LOW);
+       i2c_data(I2C_DATA_LOW);
+       i2c_delay(CLOCK_LOW_TIME*2);
+       /*
+        * SCL=1 SDA=0
+        */
+       i2c_clk(I2C_CLOCK_HIGH);
+       i2c_delay(CLOCK_HIGH_TIME*2);
+       /*
+        * SCL=1 SDA=1
+        */
+       i2c_data(I2C_DATA_HIGH);
+       i2c_delay(STOP_CONDITION_HOLD_TIME);
+
+       i2c_dir_in();
+}
+
+/* write a byte to the i2c interface */
+
+void
+i2c_outbyte(unsigned char x)
+{
+       int i;
+
+       i2c_dir_out();
+
+       for (i = 0; i < 8; i++) {
+               if (x & 0x80) {
+                       i2c_data(I2C_DATA_HIGH);
+               } else {
+                       i2c_data(I2C_DATA_LOW);
+               }
+
+               i2c_delay(CLOCK_LOW_TIME/2);
+               i2c_clk(I2C_CLOCK_HIGH);
+               i2c_delay(CLOCK_HIGH_TIME);
+               i2c_clk(I2C_CLOCK_LOW);
+               i2c_delay(CLOCK_LOW_TIME/2);
+               x <<= 1;
+       }
+       i2c_data(I2C_DATA_LOW);
+       i2c_delay(CLOCK_LOW_TIME/2);
+
+       /*
+        * enable input
+        */
+       i2c_dir_in();
+}
+
+/* read a byte from the i2c interface */
+
+unsigned char
+i2c_inbyte(void)
+{
+       unsigned char aBitByte = 0;
+       int i;
+
+       /* Switch off I2C to get bit */
+       i2c_disable();
+       i2c_dir_in();
+       i2c_delay(CLOCK_HIGH_TIME/2);
+
+       /* Get bit */
+       aBitByte |= i2c_getbit();
+
+       /* Enable I2C */
+       i2c_enable();
+       i2c_delay(CLOCK_LOW_TIME/2);
+
+       for (i = 1; i < 8; i++) {
+               aBitByte <<= 1;
+               /* Clock pulse */
+               i2c_clk(I2C_CLOCK_HIGH);
+               i2c_delay(CLOCK_HIGH_TIME);
+               i2c_clk(I2C_CLOCK_LOW);
+               i2c_delay(CLOCK_LOW_TIME);
+
+               /* Switch off I2C to get bit */
+               i2c_disable();
+               i2c_dir_in();
+               i2c_delay(CLOCK_HIGH_TIME/2);
+
+               /* Get bit */
+               aBitByte |= i2c_getbit();
+
+               /* Enable I2C */
+               i2c_enable();
+               i2c_delay(CLOCK_LOW_TIME/2);
+       }
+       i2c_clk(I2C_CLOCK_HIGH);
+       i2c_delay(CLOCK_HIGH_TIME);
+
+       /*
+        * we leave the clock low, getbyte is usually followed
+        * by sendack/nack, they assume the clock to be low
+        */
+       i2c_clk(I2C_CLOCK_LOW);
+       return aBitByte;
+}
+
+/*#---------------------------------------------------------------------------
+*#
+*# FUNCTION NAME: i2c_getack
+*#
+*# DESCRIPTION  : checks if ack was received from ic2
+*#
+*#--------------------------------------------------------------------------*/
+
+int
+i2c_getack(void)
+{
+       int ack = 1;
+       /*
+        * enable output
+        */
+       i2c_dir_out();
+       /*
+        * Release data bus by setting
+        * data high
+        */
+       i2c_data(I2C_DATA_HIGH);
+       /*
+        * enable input
+        */
+       i2c_dir_in();
+       i2c_delay(CLOCK_HIGH_TIME/4);
+       /*
+        * generate ACK clock pulse
+        */
+       i2c_clk(I2C_CLOCK_HIGH);
+       /*
+        * Use PORT PB instead of I2C
+        * for input. (I2C not working)
+        */
+       i2c_clk(1);
+       i2c_data(1);
+       /*
+        * switch off I2C
+        */
+       i2c_data(1);
+       i2c_disable();
+       i2c_dir_in();
+       /*
+        * now wait for ack
+        */
+       i2c_delay(CLOCK_HIGH_TIME/2);
+       /*
+        * check for ack
+        */
+       if(i2c_getbit())
+               ack = 0;
+       i2c_delay(CLOCK_HIGH_TIME/2);
+       if(!ack){
+               if(!i2c_getbit()) /* receiver pulld SDA low */
+                       ack = 1;
+               i2c_delay(CLOCK_HIGH_TIME/2);
+       }
+
+   /*
+    * our clock is high now, make sure data is low
+    * before we enable our output. If we keep data high
+    * and enable output, we would generate a stop condition.
+    */
+   i2c_data(I2C_DATA_LOW);
+
+       /*
+        * end clock pulse
+        */
+       i2c_enable();
+       i2c_dir_out();
+       i2c_clk(I2C_CLOCK_LOW);
+       i2c_delay(CLOCK_HIGH_TIME/4);
+       /*
+        * enable output
+        */
+       i2c_dir_out();
+       /*
+        * remove ACK clock pulse
+        */
+       i2c_data(I2C_DATA_HIGH);
+       i2c_delay(CLOCK_LOW_TIME/2);
+       return ack;
+}
+
+/*#---------------------------------------------------------------------------
+*#
+*# FUNCTION NAME: I2C::sendAck
+*#
+*# DESCRIPTION  : Send ACK on received data
+*#
+*#--------------------------------------------------------------------------*/
+void
+i2c_sendack(void)
+{
+       /*
+        * enable output
+        */
+       i2c_delay(CLOCK_LOW_TIME);
+       i2c_dir_out();
+       /*
+        * set ack pulse high
+        */
+       i2c_data(I2C_DATA_LOW);
+       /*
+        * generate clock pulse
+        */
+       i2c_delay(CLOCK_HIGH_TIME/6);
+       i2c_clk(I2C_CLOCK_HIGH);
+       i2c_delay(CLOCK_HIGH_TIME);
+       i2c_clk(I2C_CLOCK_LOW);
+       i2c_delay(CLOCK_LOW_TIME/6);
+       /*
+        * reset data out
+        */
+       i2c_data(I2C_DATA_HIGH);
+       i2c_delay(CLOCK_LOW_TIME);
+
+       i2c_dir_in();
+}
+
+/*#---------------------------------------------------------------------------
+*#
+*# FUNCTION NAME: i2c_sendnack
+*#
+*# DESCRIPTION  : Sends NACK on received data
+*#
+*#--------------------------------------------------------------------------*/
+void
+i2c_sendnack(void)
+{
+       /*
+        * enable output
+        */
+       i2c_delay(CLOCK_LOW_TIME);
+       i2c_dir_out();
+       /*
+        * set data high
+        */
+       i2c_data(I2C_DATA_HIGH);
+       /*
+        * generate clock pulse
+        */
+       i2c_delay(CLOCK_HIGH_TIME/6);
+       i2c_clk(I2C_CLOCK_HIGH);
+       i2c_delay(CLOCK_HIGH_TIME);
+       i2c_clk(I2C_CLOCK_LOW);
+       i2c_delay(CLOCK_LOW_TIME);
+
+       i2c_dir_in();
+}
+
+/*#---------------------------------------------------------------------------
+*#
+*# FUNCTION NAME: i2c_writereg
+*#
+*# DESCRIPTION  : Writes a value to an I2C device
+*#
+*#--------------------------------------------------------------------------*/
+int
+i2c_writereg(unsigned char theSlave, unsigned char theReg,
+            unsigned char theValue)
+{
+       int error, cntr = 3;
+       unsigned long flags;
+
+       do {
+               error = 0;
+               /*
+                * we don't like to be interrupted
+                */
+                local_irq_save(flags);
+
+               i2c_start();
+               /*
+                * send slave address
+                */
+               i2c_outbyte((theSlave & 0xfe));
+               /*
+                * wait for ack
+                */
+               if(!i2c_getack())
+                       error = 1;
+               /*
+                * now select register
+                */
+               i2c_dir_out();
+               i2c_outbyte(theReg);
+               /*
+                * now it's time to wait for ack
+                */
+               if(!i2c_getack())
+                       error |= 2;
+               /*
+                * send register register data
+                */
+               i2c_outbyte(theValue);
+               /*
+                * now it's time to wait for ack
+                */
+               if(!i2c_getack())
+                       error |= 4;
+               /*
+                * end byte stream
+                */
+               i2c_stop();
+               /*
+                * enable interrupt again
+                */
+               local_irq_restore(flags);
+
+       } while(error && cntr--);
+
+       i2c_delay(CLOCK_LOW_TIME);
+
+       return -error;
+}
+
+/*#---------------------------------------------------------------------------
+*#
+*# FUNCTION NAME: i2c_readreg
+*#
+*# DESCRIPTION  : Reads a value from the decoder registers.
+*#
+*#--------------------------------------------------------------------------*/
+unsigned char
+i2c_readreg(unsigned char theSlave, unsigned char theReg)
+{
+       unsigned char b = 0;
+       int error, cntr = 3;
+       unsigned long flags;
+
+       do {
+               error = 0;
+               /*
+                * we don't like to be interrupted
+                */
+                local_irq_save(flags);
+               /*
+                * generate start condition
+                */
+               i2c_start();
+
+               /*
+                * send slave address
+                */
+               i2c_outbyte((theSlave & 0xfe));
+               /*
+                * wait for ack
+                */
+               if(!i2c_getack())
+                       error = 1;
+               /*
+                * now select register
+                */
+               i2c_dir_out();
+               i2c_outbyte(theReg);
+               /*
+                * now it's time to wait for ack
+                */
+               if(!i2c_getack())
+                       error = 1;
+               /*
+                * repeat start condition
+                */
+               i2c_delay(CLOCK_LOW_TIME);
+               i2c_start();
+               /*
+                * send slave address
+                */
+               i2c_outbyte(theSlave | 0x01);
+               /*
+                * wait for ack
+                */
+               if(!i2c_getack())
+                       error = 1;
+               /*
+                * fetch register
+                */
+               b = i2c_inbyte();
+               /*
+                * last received byte needs to be nacked
+                * instead of acked
+                */
+               i2c_sendnack();
+               /*
+                * end sequence
+                */
+               i2c_stop();
+               /*
+                * enable interrupt again
+                */
+               local_irq_restore(flags);
+
+       } while(error && cntr--);
+
+       return b;
+}
+
+static int
+i2c_open(struct inode *inode, struct file *filp)
+{
+       return 0;
+}
+
+static int
+i2c_release(struct inode *inode, struct file *filp)
+{
+       return 0;
+}
+
+/* Main device API. ioctl's to write or read to/from i2c registers.
+ */
+
+static int
+i2c_ioctl(struct inode *inode, struct file *file,
+         unsigned int cmd, unsigned long arg)
+{
+       if(_IOC_TYPE(cmd) != ETRAXI2C_IOCTYPE) {
+               return -EINVAL;
+       }
+
+       switch (_IOC_NR(cmd)) {
+               case I2C_WRITEREG:
+                       /* write to an i2c slave */
+                       D(printk("i2cw %d %d %d\n",
+                                I2C_ARGSLAVE(arg),
+                                I2C_ARGREG(arg),
+                                I2C_ARGVALUE(arg)));
+
+                       return i2c_writereg(I2C_ARGSLAVE(arg),
+                                           I2C_ARGREG(arg),
+                                           I2C_ARGVALUE(arg));
+               case I2C_READREG:
+               {
+                       unsigned char val;
+                       /* read from an i2c slave */
+                       D(printk("i2cr %d %d ",
+                               I2C_ARGSLAVE(arg),
+                               I2C_ARGREG(arg)));
+                       val = i2c_readreg(I2C_ARGSLAVE(arg), I2C_ARGREG(arg));
+                       D(printk("= %d\n", val));
+                       return val;
+               }
+               default:
+                       return -EINVAL;
+
+       }
+
+       return 0;
+}
+
+static struct file_operations i2c_fops = {
+       owner:    THIS_MODULE,
+       ioctl:    i2c_ioctl,
+       open:     i2c_open,
+       release:  i2c_release,
+};
+
+int __init
+i2c_init(void)
+{
+       int res;
+
+       /* Setup and enable the Port B I2C interface */
+
+        crisv32_io_get_name(&cris_i2c_data, CONFIG_ETRAX_I2C_DATA_PORT);
+        crisv32_io_get_name(&cris_i2c_clk, CONFIG_ETRAX_I2C_CLK_PORT);
+
+       /* register char device */
+
+       res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops);
+       if(res < 0) {
+               printk(KERN_ERR "i2c: couldn't get a major number.\n");
+               return res;
+       }
+
+       printk(KERN_INFO "I2C driver v2.2, (c) 1999-2001 Axis Communications 
AB\n");
+
+       return 0;
+}
+
+/* this makes sure that i2c_init is called during boot */
+
+module_init(i2c_init);
+
+/****************** END OF FILE i2c.c ********************************/
diff -urN linux/arch/cris/arch-v32/drivers/i2c.h 
linux/arch/cris/arch-v32/drivers/i2c.h
--- linux/arch/cris/arch-v32/drivers/i2c.h      1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/drivers/i2c.h      2005-08-01 19:23:42.320276000 
+0100     1.1
@@ -0,0 +1,15 @@
+
+#include <linux/init.h>
+
+/* High level I2C actions */
+int __init i2c_init(void);
+int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char 
theValue);
+unsigned char i2c_readreg(unsigned char theSlave, unsigned char theReg);
+
+/* Low level I2C */
+void i2c_start(void);
+void i2c_stop(void);
+void i2c_outbyte(unsigned char x);
+unsigned char i2c_inbyte(void);
+int i2c_getack(void);
+void i2c_sendack(void);
diff -urN linux/arch/cris/arch-v32/drivers/iop_fw_load.c 
linux/arch/cris/arch-v32/drivers/iop_fw_load.c
--- linux/arch/cris/arch-v32/drivers/iop_fw_load.c      1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/drivers/iop_fw_load.c      2005-08-01 
19:23:42.332539000 +0100     1.1
@@ -0,0 +1,219 @@
+/* $Id: iop_fw_load.c,v 1.4 2005/04/07 09:27:46 larsv Exp $
+ *
+ * Firmware loader for ETRAX FS IO-Processor
+ *
+ * Copyright (C) 2004  Axis Communications AB
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+
+#include <asm/arch/hwregs/reg_map.h>
+#include <asm/arch/hwregs/iop/iop_reg_space.h>
+#include <asm/arch/hwregs/iop/iop_mpu_macros.h>
+#include <asm/arch/hwregs/iop/iop_mpu_defs.h>
+#include <asm/arch/hwregs/iop/iop_spu_defs.h>
+#include <asm/arch/hwregs/iop/iop_sw_cpu_defs.h>
+
+#define IOP_TIMEOUT 100
+
+static struct device iop_spu_device[2] = {
+       { .bus_id =     "iop-spu0", },
+       { .bus_id =     "iop-spu1", },
+};
+
+static struct device iop_mpu_device = {
+       .bus_id =       "iop-mpu",
+};
+
+static int wait_mpu_idle(void)
+{
+       reg_iop_mpu_r_stat mpu_stat;
+       unsigned int timeout = IOP_TIMEOUT;
+
+       do {
+               mpu_stat = REG_RD(iop_mpu, regi_iop_mpu, r_stat);
+       } while (mpu_stat.instr_reg_busy == regk_iop_mpu_yes && --timeout > 0);
+       if (timeout == 0) {
+               printk(KERN_ERR "Timeout waiting for MPU to be idle\n");
+               return -EBUSY;
+       }
+       return 0;
+}
+
+int iop_fw_load_spu(const unsigned char *fw_name, unsigned int spu_inst)
+{
+       reg_iop_sw_cpu_rw_mc_ctrl mc_ctrl = {
+               .wr_spu0_mem =    regk_iop_sw_cpu_no,
+               .wr_spu1_mem =    regk_iop_sw_cpu_no,
+               .size =           4,
+               .cmd =            regk_iop_sw_cpu_reg_copy,
+               .keep_owner =     regk_iop_sw_cpu_yes
+       };
+       reg_iop_spu_rw_ctrl spu_ctrl = {
+               .en  =            regk_iop_spu_no,
+               .fsm =            regk_iop_spu_no,
+       };
+       reg_iop_sw_cpu_r_mc_stat mc_stat;
+        const struct firmware *fw_entry;
+       u32 *data;
+       unsigned int timeout;
+       int retval, i;
+
+       if (spu_inst > 1)
+               return -ENODEV;
+
+       /* get firmware */
+       retval = request_firmware(&fw_entry,
+                                 fw_name,
+                                 &iop_spu_device[spu_inst]);
+       if (retval != 0)
+       {
+               printk(KERN_ERR
+                      "iop_load_spu: Failed to load firmware \"%s\"\n",
+                      fw_name);
+               return retval;
+       }
+       data = (u32 *) fw_entry->data;
+
+       /* acquire ownership of memory controller */
+       switch (spu_inst) {
+       case 0:
+               mc_ctrl.wr_spu0_mem = regk_iop_sw_cpu_yes;
+               REG_WR(iop_spu, regi_iop_spu0, rw_ctrl, spu_ctrl);
+               break;
+       case 1:
+               mc_ctrl.wr_spu1_mem = regk_iop_sw_cpu_yes;
+               REG_WR(iop_spu, regi_iop_spu1, rw_ctrl, spu_ctrl);
+               break;
+       }
+       timeout = IOP_TIMEOUT;
+       do {
+               REG_WR(iop_sw_cpu, regi_iop_sw_cpu, rw_mc_ctrl, mc_ctrl);
+               mc_stat = REG_RD(iop_sw_cpu, regi_iop_sw_cpu, r_mc_stat);
+       } while (mc_stat.owned_by_cpu == regk_iop_sw_cpu_no && --timeout > 0);
+       if (timeout == 0) {
+               printk(KERN_ERR "Timeout waiting to acquire MC\n");
+               retval = -EBUSY;
+               goto out;
+       }
+
+       /* write to SPU memory */
+       for (i = 0; i < (fw_entry->size/4); i++) {
+               switch (spu_inst) {
+               case 0:
+                       REG_WR_INT(iop_spu, regi_iop_spu0, rw_seq_pc, (i*4));
+                       break;
+               case 1:
+                       REG_WR_INT(iop_spu, regi_iop_spu1, rw_seq_pc, (i*4));
+                       break;
+               }
+               REG_WR_INT(iop_sw_cpu, regi_iop_sw_cpu, rw_mc_data, *data);
+               data++;
+       }
+
+       /* release ownership of memory controller */
+       (void) REG_RD(iop_sw_cpu, regi_iop_sw_cpu, rs_mc_data);
+
+ out:
+       release_firmware(fw_entry);
+       return retval;
+}
+
+int iop_fw_load_mpu(unsigned char *fw_name)
+{
+       const unsigned int start_addr = 0;
+       reg_iop_mpu_rw_ctrl mpu_ctrl;
+        const struct firmware *fw_entry;
+       u32 *data;
+       int retval, i;
+
+       /* get firmware */
+       retval = request_firmware(&fw_entry, fw_name, &iop_mpu_device);
+       if (retval != 0)
+       {
+               printk(KERN_ERR
+                      "iop_load_spu: Failed to load firmware \"%s\"\n",
+                      fw_name);
+               return retval;
+       }
+       data = (u32 *) fw_entry->data;
+
+       /* disable MPU */
+       mpu_ctrl.en = regk_iop_mpu_no;
+       REG_WR(iop_mpu, regi_iop_mpu, rw_ctrl, mpu_ctrl);
+       /* put start address in R0 */
+       REG_WR_VECT(iop_mpu, regi_iop_mpu, rw_r, 0, start_addr);
+       /* write to memory by executing 'SWX i, 4, R0' for each word */
+       if ((retval = wait_mpu_idle()) != 0)
+               goto out;
+       REG_WR(iop_mpu, regi_iop_mpu, rw_instr, MPU_SWX_IIR_INSTR(0, 4, 0));
+       for (i = 0; i < (fw_entry->size / 4); i++) {
+               REG_WR_INT(iop_mpu, regi_iop_mpu, rw_immediate, *data);
+               if ((retval = wait_mpu_idle()) != 0)
+                       goto out;
+               data++;
+       }
+
+ out:
+       release_firmware(fw_entry);
+       return retval;
+}
+
+int iop_start_mpu(unsigned int start_addr)
+{
+       reg_iop_mpu_rw_ctrl mpu_ctrl = { .en = regk_iop_mpu_yes };
+       int retval;
+
+       /* disable MPU */
+       if ((retval = wait_mpu_idle()) != 0)
+               goto out;
+       REG_WR(iop_mpu, regi_iop_mpu, rw_instr, MPU_HALT());
+       if ((retval = wait_mpu_idle()) != 0)
+               goto out;
+       /* set PC and wait for it to bite */
+       if ((retval = wait_mpu_idle()) != 0)
+               goto out;
+       REG_WR_INT(iop_mpu, regi_iop_mpu, rw_instr, MPU_BA_I(start_addr));
+       if ((retval = wait_mpu_idle()) != 0)
+               goto out;
+       /* make sure the MPU starts executing with interrupts disabled */
+       REG_WR(iop_mpu, regi_iop_mpu, rw_instr, MPU_DI());
+       if ((retval = wait_mpu_idle()) != 0)
+               goto out;
+       /* enable MPU */
+       REG_WR(iop_mpu, regi_iop_mpu, rw_ctrl, mpu_ctrl);
+ out:
+       return retval;
+}
+
+static int __init iop_fw_load_init(void)
+{
+       device_initialize(&iop_spu_device[0]);
+       kobject_set_name(&iop_spu_device[0].kobj, "iop-spu0");
+       kobject_add(&iop_spu_device[0].kobj);
+       device_initialize(&iop_spu_device[1]);
+       kobject_set_name(&iop_spu_device[1].kobj, "iop-spu1");
+       kobject_add(&iop_spu_device[1].kobj);
+       device_initialize(&iop_mpu_device);
+       kobject_set_name(&iop_mpu_device.kobj, "iop-mpu");
+       kobject_add(&iop_mpu_device.kobj);
+       return 0;
+}
+
+static void __exit iop_fw_load_exit(void)
+{
+}
+
+module_init(iop_fw_load_init);
+module_exit(iop_fw_load_exit);
+
+MODULE_DESCRIPTION("ETRAX FS IO-Processor Firmware Loader");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(iop_fw_load_spu);
+EXPORT_SYMBOL(iop_fw_load_mpu);
+EXPORT_SYMBOL(iop_start_mpu);
diff -urN linux/arch/cris/arch-v32/drivers/nandflash.c 
linux/arch/cris/arch-v32/drivers/nandflash.c
--- linux/arch/cris/arch-v32/drivers/nandflash.c        1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/drivers/nandflash.c        2005-08-01 
19:23:42.353691000 +0100     1.1
@@ -0,0 +1,157 @@
+/*
+ *  arch/cris/arch-v32/drivers/nandflash.c
+ *
+ *  Copyright (c) 2004
+ *
+ *  Derived from drivers/mtd/nand/spia.c
+ *       Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ *
+ * $Id: nandflash.c,v 1.3 2005/06/01 10:57:12 starvik Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/arch/memmap.h>
+#include <asm/arch/hwregs/reg_map.h>
+#include <asm/arch/hwregs/reg_rdwr.h>
+#include <asm/arch/hwregs/gio_defs.h>
+#include <asm/arch/hwregs/bif_core_defs.h>
+#include <asm/io.h>
+
+#define CE_BIT 4
+#define CLE_BIT 5
+#define ALE_BIT 6
+#define BY_BIT 7
+
+static struct mtd_info *crisv32_mtd = NULL;
+/*
+ *     hardware specific access to control-lines
+*/
+static void crisv32_hwcontrol(struct mtd_info *mtd, int cmd)
+{
+       unsigned long flags;
+       reg_gio_rw_pa_dout dout = REG_RD(gio, regi_gio, rw_pa_dout);
+
+       local_irq_save(flags);
+       switch(cmd){
+               case NAND_CTL_SETCLE:
+                    dout.data |= (1<<CLE_BIT);
+                    break;
+               case NAND_CTL_CLRCLE:
+                    dout.data &= ~(1<<CLE_BIT);
+                    break;
+               case NAND_CTL_SETALE:
+                    dout.data |= (1<<ALE_BIT);
+                    break;
+               case NAND_CTL_CLRALE:
+                    dout.data &= ~(1<<ALE_BIT);
+                    break;
+               case NAND_CTL_SETNCE:
+                    dout.data |= (1<<CE_BIT);
+                    break;
+               case NAND_CTL_CLRNCE:
+                    dout.data &= ~(1<<CE_BIT);
+                    break;
+       }
+       REG_WR(gio, regi_gio, rw_pa_dout, dout);
+       local_irq_restore(flags);
+}
+
+/*
+*      read device ready pin
+*/
+int crisv32_device_ready(struct mtd_info *mtd)
+{
+       reg_gio_r_pa_din din = REG_RD(gio, regi_gio, r_pa_din);
+       return ((din.data & (1 << BY_BIT)) >> BY_BIT);
+}
+
+/*
+ * Main initialization routine
+ */
+struct mtd_info* __init crisv32_nand_flash_probe (void)
+{
+       void __iomem *read_cs;
+       void __iomem *write_cs;
+
+       reg_bif_core_rw_grp3_cfg bif_cfg = REG_RD(bif_core, regi_bif_core, 
rw_grp3_cfg);
+       reg_gio_rw_pa_oe pa_oe = REG_RD(gio, regi_gio, rw_pa_oe);
+       struct nand_chip *this;
+       int err = 0;
+
+       /* Allocate memory for MTD device structure and private data */
+       crisv32_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct 
nand_chip),
+                               GFP_KERNEL);
+       if (!crisv32_mtd) {
+               printk ("Unable to allocate CRISv32 NAND MTD device 
structure.\n");
+               err = -ENOMEM;
+               return NULL;
+       }
+
+       read_cs = ioremap(MEM_CSP0_START | MEM_NON_CACHEABLE, 8192);
+       write_cs = ioremap(MEM_CSP1_START | MEM_NON_CACHEABLE, 8192);
+
+       if (!read_cs || !write_cs) {
+               printk("CRISv32 NAND ioremap failed\n");
+               err = -EIO;
+               goto out_mtd;
+       }
+
+       /* Get pointer to private data */
+       this = (struct nand_chip *) (&crisv32_mtd[1]);
+
+       pa_oe.oe |= 1 << CE_BIT;
+       pa_oe.oe |= 1 << ALE_BIT;
+       pa_oe.oe |= 1 << CLE_BIT;
+       pa_oe.oe &= ~ (1 << BY_BIT);
+       REG_WR(gio, regi_gio, rw_pa_oe, pa_oe);
+
+       bif_cfg.gated_csp0 = regk_bif_core_rd;
+       bif_cfg.gated_csp1 = regk_bif_core_wr;
+       REG_WR(bif_core, regi_bif_core, rw_grp3_cfg, bif_cfg);
+
+       /* Initialize structures */
+       memset((char *) crisv32_mtd, 0, sizeof(struct mtd_info));
+       memset((char *) this, 0, sizeof(struct nand_chip));
+
+       /* Link the private data with the MTD structure */
+       crisv32_mtd->priv = this;
+
+       /* Set address of NAND IO lines */
+       this->IO_ADDR_R = read_cs;
+       this->IO_ADDR_W = write_cs;
+       this->hwcontrol = crisv32_hwcontrol;
+       this->dev_ready = crisv32_device_ready;
+       /* 20 us command delay time */
+       this->chip_delay = 20;
+       this->eccmode = NAND_ECC_SOFT;
+
+       /* Enable the following for a flash based bad block table */
+       this->options = NAND_USE_FLASH_BBT;
+
+       /* Scan to find existance of the device */
+       if (nand_scan (crisv32_mtd, 1)) {
+               err = -ENXIO;
+               goto out_ior;
+       }
+
+       return crisv32_mtd;
+
+out_ior:
+       iounmap((void *)read_cs);
+       iounmap((void *)write_cs);
+out_mtd:
+       kfree (crisv32_mtd);
+        return NULL;
+}
+
diff -urN linux/arch/cris/arch-v32/drivers/pcf8563.c 
linux/arch/cris/arch-v32/drivers/pcf8563.c
--- linux/arch/cris/arch-v32/drivers/pcf8563.c  1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/drivers/pcf8563.c  2005-08-01 19:23:42.376638000 
+0100     1.1
@@ -0,0 +1,341 @@
+/*
+ * PCF8563 RTC
+ *
+ * From Phillips' datasheet:
+ *
+ * The PCF8563 is a CMOS real-time clock/calendar optimized for low power
+ * consumption. A programmable clock output, interupt output and voltage
+ * low detector are also provided. All address and data are transferred
+ * serially via two-line bidirectional I2C-bus. Maximum bus speed is
+ * 400 kbits/s. The built-in word address register is incremented
+ * automatically after each written or read byte.
+ *
+ * Copyright (c) 2002-2003, Axis Communications AB
+ * All rights reserved.
+ *
+ * Author: Tobias Anderberg <tobiasa@axis.com>.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/bcd.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/rtc.h>
+
+#include "i2c.h"
+
+#define PCF8563_MAJOR  121     /* Local major number. */
+#define DEVICE_NAME    "rtc"   /* Name which is registered in /proc/devices. */
+#define PCF8563_NAME   "PCF8563"
+#define DRIVER_VERSION "$Revision: 1.1 $"
+
+/* Two simple wrapper macros, saves a few keystrokes. */
+#define rtc_read(x) i2c_readreg(RTC_I2C_READ, x)
+#define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y)
+
+static const unsigned char days_in_month[] =
+       { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+int pcf8563_open(struct inode *, struct file *);
+int pcf8563_release(struct inode *, struct file *);
+
+static struct file_operations pcf8563_fops = {
+       owner: THIS_MODULE,
+       ioctl: pcf8563_ioctl,
+       open: pcf8563_open,
+       release: pcf8563_release,
+};
+
+unsigned char
+pcf8563_readreg(int reg)
+{
+       unsigned char res = rtc_read(reg);
+
+       /* The PCF8563 does not return 0 for unimplemented bits */
+       switch (reg) {
+               case RTC_SECONDS:
+               case RTC_MINUTES:
+                       res &= 0x7F;
+                       break;
+               case RTC_HOURS:
+               case RTC_DAY_OF_MONTH:
+                       res &= 0x3F;
+                       break;
+               case RTC_WEEKDAY:
+                       res &= 0x07;
+                       break;
+               case RTC_MONTH:
+                       res &= 0x1F;
+                       break;
+               case RTC_CONTROL1:
+                       res &= 0xA8;
+                       break;
+               case RTC_CONTROL2:
+                       res &= 0x1F;
+                       break;
+               case RTC_CLOCKOUT_FREQ:
+               case RTC_TIMER_CONTROL:
+                       res &= 0x83;
+                       break;
+       }
+       return res;
+}
+
+void
+pcf8563_writereg(int reg, unsigned char val)
+{
+#ifdef CONFIG_ETRAX_RTC_READONLY
+       if (reg == RTC_CONTROL1 || (reg >= RTC_SECONDS && reg <= RTC_YEAR))
+               return;
+#endif
+
+       rtc_write(reg, val);
+}
+
+void
+get_rtc_time(struct rtc_time *tm)
+{
+       tm->tm_sec  = rtc_read(RTC_SECONDS);
+       tm->tm_min  = rtc_read(RTC_MINUTES);
+       tm->tm_hour = rtc_read(RTC_HOURS);
+       tm->tm_mday = rtc_read(RTC_DAY_OF_MONTH);
+       tm->tm_wday = rtc_read(RTC_WEEKDAY);
+       tm->tm_mon  = rtc_read(RTC_MONTH);
+       tm->tm_year = rtc_read(RTC_YEAR);
+
+       if (tm->tm_sec & 0x80)
+               printk(KERN_WARNING "%s: RTC Voltage Low - reliable date/time "
+                      "information is no longer guaranteed!\n", PCF8563_NAME);
+
+       tm->tm_year  = BCD_TO_BIN(tm->tm_year) + ((tm->tm_mon & 0x80) ? 100 : 
0);
+       tm->tm_sec  &= 0x7F;
+       tm->tm_min  &= 0x7F;
+       tm->tm_hour &= 0x3F;
+       tm->tm_mday &= 0x3F;
+       tm->tm_wday &= 0x07; /* Not coded in BCD. */
+       tm->tm_mon  &= 0x1F;
+
+       BCD_TO_BIN(tm->tm_sec);
+       BCD_TO_BIN(tm->tm_min);
+       BCD_TO_BIN(tm->tm_hour);
+       BCD_TO_BIN(tm->tm_mday);
+       BCD_TO_BIN(tm->tm_mon);
+       tm->tm_mon--; /* Month is 1..12 in RTC but 0..11 in linux */
+}
+
+int __init
+pcf8563_init(void)
+{
+       /* Initiate the i2c protocol. */
+       i2c_init();
+
+       /*
+        * First of all we need to reset the chip. This is done by
+        * clearing control1, control2 and clk freq and resetting
+        * all alarms.
+        */
+       if (rtc_write(RTC_CONTROL1, 0x00) < 0)
+               goto err;
+
+       if (rtc_write(RTC_CONTROL2, 0x00) < 0)
+               goto err;
+
+       if (rtc_write(RTC_CLOCKOUT_FREQ, 0x00) < 0)
+               goto err;
+
+       if (rtc_write(RTC_TIMER_CONTROL, 0x03) < 0)
+               goto err;
+
+       /* Reset the alarms. */
+       if (rtc_write(RTC_MINUTE_ALARM, 0x80) < 0)
+               goto err;
+
+       if (rtc_write(RTC_HOUR_ALARM, 0x80) < 0)
+               goto err;
+
+       if (rtc_write(RTC_DAY_ALARM, 0x80) < 0)
+               goto err;
+
+       if (rtc_write(RTC_WEEKDAY_ALARM, 0x80) < 0)
+               goto err;
+
+       if (register_chrdev(PCF8563_MAJOR, DEVICE_NAME, &pcf8563_fops) < 0) {
+               printk(KERN_INFO "%s: Unable to get major numer %d for RTC 
device.\n",
+                      PCF8563_NAME, PCF8563_MAJOR);
+               return -1;
+       }
+
+       printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME, 
DRIVER_VERSION);
+
+       /* Check for low voltage, and warn about it.. */
+       if (rtc_read(RTC_SECONDS) & 0x80)
+               printk(KERN_WARNING "%s: RTC Voltage Low - reliable date/time "
+                      "information is no longer guaranteed!\n", PCF8563_NAME);
+
+       return 0;
+
+err:
+       printk(KERN_INFO "%s: Error initializing chip.\n", PCF8563_NAME);
+       return -1;
+}
+
+void __exit
+pcf8563_exit(void)
+{
+       if (unregister_chrdev(PCF8563_MAJOR, DEVICE_NAME) < 0) {
+               printk(KERN_INFO "%s: Unable to unregister device.\n", 
PCF8563_NAME);
+       }
+}
+
+/*
+ * ioctl calls for this driver. Why return -ENOTTY upon error? Because
+ * POSIX says so!
+ */
+int
+pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, 
unsigned long arg)
+{
+       /* Some sanity checks. */
+       if (_IOC_TYPE(cmd) != RTC_MAGIC)
+               return -ENOTTY;
+
+       if (_IOC_NR(cmd) > RTC_MAX_IOCTL)
+               return -ENOTTY;
+
+       switch (cmd) {
+               case RTC_RD_TIME:
+               {
+                       struct rtc_time tm;
+
+                       memset(&tm, 0, sizeof (struct rtc_time));
+                       get_rtc_time(&tm);
+
+                       if (copy_to_user((struct rtc_time *) arg, &tm, sizeof 
tm)) {
+                               return -EFAULT;
+                       }
+
+                       return 0;
+               }
+
+               case RTC_SET_TIME:
+               {
+#ifdef CONFIG_ETRAX_RTC_READONLY
+                       return -EPERM;
+#else
+                       int leap;
+                       int year;
+                       int century;
+                       struct rtc_time tm;
+
+                       if (!capable(CAP_SYS_TIME))
+                               return -EPERM;
+
+                       if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof 
tm))
+                               return -EFAULT;
+
+                       /* Convert from struct tm to struct rtc_time. */
+                       tm.tm_year += 1900;
+                       tm.tm_mon += 1;
+
+                       /*
+                        * Check if tm.tm_year is a leap year. A year is a leap
+                        * year if it is divisible by 4 but not 100, except
+                        * that years divisible by 400 _are_ leap years.
+                        */
+                       year = tm.tm_year;
+                       leap = (tm.tm_mon == 2) && ((year % 4 == 0 && year % 
100 != 0) || year % 400 == 0);
+
+                       /* Perform some sanity checks. */
+                       if ((tm.tm_year < 1970) ||
+                           (tm.tm_mon > 12) ||
+                           (tm.tm_mday == 0) ||
+                           (tm.tm_mday > days_in_month[tm.tm_mon] + leap) ||
+                           (tm.tm_wday >= 7) ||
+                           (tm.tm_hour >= 24) ||
+                           (tm.tm_min >= 60) ||
+                           (tm.tm_sec >= 60))
+                               return -EINVAL;
+
+                       century = (tm.tm_year >= 2000) ? 0x80 : 0;
+                       tm.tm_year = tm.tm_year % 100;
+
+                       BIN_TO_BCD(tm.tm_year);
+                       BIN_TO_BCD(tm.tm_mday);
+                       BIN_TO_BCD(tm.tm_hour);
+                       BIN_TO_BCD(tm.tm_min);
+                       BIN_TO_BCD(tm.tm_sec);
+                       tm.tm_mon |= century;
+
+                       rtc_write(RTC_YEAR, tm.tm_year);
+                       rtc_write(RTC_MONTH, tm.tm_mon);
+                       rtc_write(RTC_WEEKDAY, tm.tm_wday); /* Not coded in 
BCD. */
+                       rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday);
+                       rtc_write(RTC_HOURS, tm.tm_hour);
+                       rtc_write(RTC_MINUTES, tm.tm_min);
+                       rtc_write(RTC_SECONDS, tm.tm_sec);
+
+                       return 0;
+#endif /* !CONFIG_ETRAX_RTC_READONLY */
+               }
+
+               case RTC_VLOW_RD:
+               {
+                       int vl_bit = 0;
+
+                       if (rtc_read(RTC_SECONDS) & 0x80) {
+                               vl_bit = 1;
+                               printk(KERN_WARNING "%s: RTC Voltage Low - 
reliable "
+                                      "date/time information is no longer 
guaranteed!\n",
+                                      PCF8563_NAME);
+                       }
+                       if (copy_to_user((int *) arg, &vl_bit, sizeof(int)))
+                               return -EFAULT;
+
+                       return 0;
+               }
+
+               case RTC_VLOW_SET:
+               {
+                       /* Clear the VL bit in the seconds register */
+                       int ret = rtc_read(RTC_SECONDS);
+
+                       rtc_write(RTC_SECONDS, (ret & 0x7F));
+
+                       return 0;
+               }
+
+               default:
+                       return -ENOTTY;
+       }
+
+       return 0;
+}
+
+int
+pcf8563_open(struct inode *inode, struct file *filp)
+{
+       MOD_INC_USE_COUNT;
+       return 0;
+}
+
+int
+pcf8563_release(struct inode *inode, struct file *filp)
+{
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+module_init(pcf8563_init);
+module_exit(pcf8563_exit);
diff -urN linux/arch/cris/arch-v32/drivers/sync_serial.c 
linux/arch/cris/arch-v32/drivers/sync_serial.c
--- linux/arch/cris/arch-v32/drivers/sync_serial.c      1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/drivers/sync_serial.c      2005-08-01 
19:23:42.400054000 +0100     1.1
@@ -0,0 +1,1283 @@
+/*
+ * Simple synchronous serial port driver for ETRAX FS.
+ *
+ * Copyright (c) 2005 Axis Communications AB
+ *
+ * Author: Mikael Starvik
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+
+#include <asm/io.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/hwregs/reg_rdwr.h>
+#include <asm/arch/hwregs/sser_defs.h>
+#include <asm/arch/hwregs/dma_defs.h>
+#include <asm/arch/hwregs/dma.h>
+#include <asm/arch/hwregs/intr_vect_defs.h>
+#include <asm/arch/hwregs/intr_vect.h>
+#include <asm/arch/hwregs/reg_map.h>
+#include <asm/sync_serial.h>
+
+/* The receiver is a bit tricky beacuse of the continuous stream of data.*/
+/*                                                                       */
+/* Three DMA descriptors are linked together. Each DMA descriptor is     */
+/* responsible for port->bufchunk of a common buffer.                    */
+/*                                                                       */
+/* +---------------------------------------------+                       */
+/* |   +----------+   +----------+   +----------+ |                      */
+/* +-> | Descr[0] |-->| Descr[1] |-->| Descr[2] |-+                      */
+/*     +----------+   +----------+   +----------+                        */
+/*         |            |              |                                 */
+/*         v            v              v                                 */
+/*   +-------------------------------------+                             */
+/*   |        BUFFER                       |                             */
+/*   +-------------------------------------+                             */
+/*      |<- data_avail ->|                                               */
+/*    readp          writep                                              */
+/*                                                                       */
+/* If the application keeps up the pace readp will be right after writep.*/
+/* If the application can't keep the pace we have to throw away data.    */
+/* The idea is that readp should be ready with the data pointed out by  */
+/* Descr[i] when the DMA has filled in Descr[i+1].                       */
+/* Otherwise we will discard                                            */
+/* the rest of the data pointed out by Descr1 and set readp to the start */
+/* of Descr2                                                             */
+
+#define SYNC_SERIAL_MAJOR 125
+
+/* IN_BUFFER_SIZE should be a multiple of 6 to make sure that 24 bit */
+/* words can be handled */
+#define IN_BUFFER_SIZE 12288
+#define IN_DESCR_SIZE 256
+#define NUM_IN_DESCR (IN_BUFFER_SIZE/IN_DESCR_SIZE)
+#define OUT_BUFFER_SIZE 4096
+
+#define DEFAULT_FRAME_RATE 0
+#define DEFAULT_WORD_RATE 7
+
+/* NOTE: Enabling some debug will likely cause overrun or underrun,
+ * especially if manual mode is use.
+ */
+#define DEBUG(x)
+#define DEBUGREAD(x)
+#define DEBUGWRITE(x)
+#define DEBUGPOLL(x)
+#define DEBUGRXINT(x)
+#define DEBUGTXINT(x)
+
+typedef struct sync_port
+{
+       reg_scope_instances regi_sser;
+       reg_scope_instances regi_dmain;
+       reg_scope_instances regi_dmaout;
+
+       char started; /* 1 if port has been started */
+       char port_nbr; /* Port 0 or 1 */
+       char busy; /* 1 if port is busy */
+
+       char enabled;  /* 1 if port is enabled */
+       char use_dma;  /* 1 if port uses dma */
+       char tr_running;
+
+       char init_irqs;
+       int output;
+       int input;
+
+       volatile unsigned int out_count; /* Remaining bytes for current 
transfer */
+       unsigned char* outp; /* Current position in out_buffer */
+       volatile unsigned char* volatile readp;  /* Next byte to be read by 
application */
+       volatile unsigned char* volatile writep; /* Next byte to be written by 
etrax */
+       unsigned int in_buffer_size;
+       unsigned int inbufchunk;
+       unsigned char out_buffer[OUT_BUFFER_SIZE] __attribute__ ((aligned(32)));
+       unsigned char in_buffer[IN_BUFFER_SIZE]__attribute__ ((aligned(32)));
+       unsigned char flip[IN_BUFFER_SIZE] __attribute__ ((aligned(32)));
+       struct dma_descr_data* next_rx_desc;
+       struct dma_descr_data* prev_rx_desc;
+       int full;
+
+       dma_descr_data in_descr[NUM_IN_DESCR] __attribute__ ((__aligned__(16)));
+       dma_descr_context in_context __attribute__ ((__aligned__(32)));
+       dma_descr_data out_descr __attribute__ ((__aligned__(16)));
+       dma_descr_context out_context __attribute__ ((__aligned__(32)));
+       wait_queue_head_t out_wait_q;
+       wait_queue_head_t in_wait_q;
+
+       spinlock_t lock;
+} sync_port;
+
+static int etrax_sync_serial_init(void);
+static void initialize_port(int portnbr);
+static inline int sync_data_avail(struct sync_port *port);
+
+static int sync_serial_open(struct inode *, struct file*);
+static int sync_serial_release(struct inode*, struct file*);
+static unsigned int sync_serial_poll(struct file *filp, poll_table *wait);
+
+static int sync_serial_ioctl(struct inode*, struct file*,
+                            unsigned int cmd, unsigned long arg);
+static ssize_t sync_serial_write(struct file * file, const char * buf,
+                                size_t count, loff_t *ppos);
+static ssize_t sync_serial_read(struct file *file, char *buf,
+                               size_t count, loff_t *ppos);
+
+#if (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \
+     defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)) || \
+    (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) && \
+     defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA))
+#define SYNC_SER_DMA
+#endif
+
+static void send_word(sync_port* port);
+static void start_dma(struct sync_port *port, const char* data, int count);
+static void start_dma_in(sync_port* port);
+#ifdef SYNC_SER_DMA
+static irqreturn_t tr_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+static irqreturn_t rx_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+#endif
+
+#if (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \
+     !defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)) || \
+    (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) && \
+     !defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA))
+#define SYNC_SER_MANUAL
+#endif
+#ifdef SYNC_SER_MANUAL
+static irqreturn_t manual_interrupt(int irq, void *dev_id, struct pt_regs * 
regs);
+#endif
+
+/* The ports */
+static struct sync_port ports[]=
+{
+       {
+               .regi_sser             = regi_sser0,
+               .regi_dmaout           = regi_dma4,
+               .regi_dmain            = regi_dma5,
+#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)
+                .use_dma               = 1,
+#else
+                .use_dma               = 0,
+#endif
+       },
+       {
+               .regi_sser             = regi_sser1,
+               .regi_dmaout           = regi_dma6,
+               .regi_dmain            = regi_dma7,
+#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA)
+                .use_dma               = 1,
+#else
+                .use_dma               = 0,
+#endif
+       }
+};
+
+#define NUMBER_OF_PORTS (sizeof(ports)/sizeof(sync_port))
+
+static struct file_operations sync_serial_fops = {
+       .owner   = THIS_MODULE,
+       .write   = sync_serial_write,
+       .read    = sync_serial_read,
+       .poll    = sync_serial_poll,
+       .ioctl   = sync_serial_ioctl,
+       .open    = sync_serial_open,
+       .release = sync_serial_release
+};
+
+static int __init etrax_sync_serial_init(void)
+{
+       ports[0].enabled = 0;
+       ports[1].enabled = 0;
+
+       if (register_chrdev(SYNC_SERIAL_MAJOR,"sync serial", &sync_serial_fops) 
<0 )
+       {
+               printk("unable to get major for synchronous serial port\n");
+               return -EBUSY;
+       }
+
+       /* Initialize Ports */
+#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0)
+       if (crisv32_pinmux_alloc_fixed(pinmux_sser0))
+       {
+               printk("Unable to allocate pins for syncrhronous serial port 
0\n");
+               return -EIO;
+       }
+       ports[0].enabled = 1;
+       initialize_port(0);
+#endif
+
+#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)
+       if (crisv32_pinmux_alloc_fixed(pinmux_sser1))
+       {
+               printk("Unable to allocate pins for syncrhronous serial port 
0\n");
+               return -EIO;
+       }
+       ports[1].enabled = 1;
+       initialize_port(1);
+#endif
+
+       printk("ETRAX FS synchronous serial port driver\n");
+       return 0;
+}
+
+static void __init initialize_port(int portnbr)
+{
+       struct sync_port* port = &ports[portnbr];
+       reg_sser_rw_cfg cfg = {0};
+       reg_sser_rw_frm_cfg frm_cfg = {0};
+       reg_sser_rw_tr_cfg tr_cfg = {0};
+       reg_sser_rw_rec_cfg rec_cfg = {0};
+
+       DEBUG(printk("Init sync serial port %d\n", portnbr));
+
+       port->port_nbr = portnbr;
+       port->init_irqs = 1;
+
+       port->outp = port->out_buffer;
+       port->output = 1;
+       port->input = 0;
+
+       port->readp = port->flip;
+       port->writep = port->flip;
+       port->in_buffer_size = IN_BUFFER_SIZE;
+       port->inbufchunk = IN_DESCR_SIZE;
+       port->next_rx_desc = &port->in_descr[0];
+       port->prev_rx_desc = &port->in_descr[NUM_IN_DESCR-1];
+       port->prev_rx_desc->eol = 1;
+
+       init_waitqueue_head(&port->out_wait_q);
+       init_waitqueue_head(&port->in_wait_q);
+
+       spin_lock_init(&port->lock);
+
+       cfg.out_clk_src = regk_sser_intern_clk;
+       cfg.out_clk_pol = regk_sser_pos;
+       cfg.clk_od_mode = regk_sser_no;
+       cfg.clk_dir = regk_sser_out;
+       cfg.gate_clk = regk_sser_no;
+       cfg.base_freq = regk_sser_f29_493;
+       cfg.clk_div = 256;
+       REG_WR(sser, port->regi_sser, rw_cfg, cfg);
+
+       frm_cfg.wordrate = DEFAULT_WORD_RATE;
+       frm_cfg.type = regk_sser_edge;
+       frm_cfg.frame_pin_dir = regk_sser_out;
+       frm_cfg.frame_pin_use = regk_sser_frm;
+       frm_cfg.status_pin_dir = regk_sser_in;
+       frm_cfg.status_pin_use = regk_sser_hold;
+       frm_cfg.out_on = regk_sser_tr;
+       frm_cfg.tr_delay = 1;
+       REG_WR(sser, port->regi_sser, rw_frm_cfg, frm_cfg);
+
+       tr_cfg.urun_stop = regk_sser_no;
+       tr_cfg.sample_size = 7;
+       tr_cfg.sh_dir = regk_sser_msbfirst;
+       tr_cfg.use_dma = port->use_dma ? regk_sser_yes : regk_sser_no;
+       tr_cfg.rate_ctrl = regk_sser_bulk;
+       tr_cfg.data_pin_use = regk_sser_dout;
+       tr_cfg.bulk_wspace = 1;
+       REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg);
+
+       rec_cfg.sample_size = 7;
+       rec_cfg.sh_dir = regk_sser_msbfirst;
+       rec_cfg.use_dma = port->use_dma ? regk_sser_yes : regk_sser_no;
+       rec_cfg.fifo_thr = regk_sser_inf;
+       REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg);
+}
+
+static inline int sync_data_avail(struct sync_port *port)
+{
+       int avail;
+       unsigned char *start;
+       unsigned char *end;
+
+       start = (unsigned char*)port->readp; /* cast away volatile */
+       end = (unsigned char*)port->writep;  /* cast away volatile */
+       /* 0123456789  0123456789
+        *  -----      -    -----
+        *  ^rp  ^wp    ^wp ^rp
+        */
+
+       if (end >= start)
+               avail = end - start;
+       else
+               avail = port->in_buffer_size - (start - end);
+       return avail;
+}
+
+static inline int sync_data_avail_to_end(struct sync_port *port)
+{
+       int avail;
+       unsigned char *start;
+       unsigned char *end;
+
+       start = (unsigned char*)port->readp; /* cast away volatile */
+       end = (unsigned char*)port->writep;  /* cast away volatile */
+       /* 0123456789  0123456789
+        *  -----           -----
+        *  ^rp  ^wp    ^wp ^rp
+        */
+
+       if (end >= start)
+               avail = end - start;
+       else
+               avail = port->flip + port->in_buffer_size - start;
+       return avail;
+}
+
+static int sync_serial_open(struct inode *inode, struct file *file)
+{
+       int dev = MINOR(inode->i_rdev);
+       sync_port* port;
+       reg_dma_rw_cfg cfg = {.en = regk_dma_yes};
+       reg_dma_rw_intr_mask intr_mask = {.data = regk_dma_yes};
+
+       DEBUG(printk("Open sync serial port %d\n", dev));
+
+       if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled)
+       {
+               DEBUG(printk("Invalid minor %d\n", dev));
+               return -ENODEV;
+       }
+       port = &ports[dev];
+       /* Allow open this device twice (assuming one reader and one writer) */
+       if (port->busy == 2)
+       {
+               DEBUG(printk("Device is busy.. \n"));
+               return -EBUSY;
+       }
+       if (port->init_irqs) {
+               if (port->use_dma) {
+                       if (port == &ports[0]){
+#ifdef SYNC_SER_DMA
+                               if(request_irq(DMA4_INTR_VECT,
+                                              tr_interrupt,
+                                              0,
+                                              "synchronous serial 0 dma tr",
+                                              &ports[0])) {
+                                       printk(KERN_CRIT "Can't allocate sync 
serial port 0 IRQ");
+                                       return -EBUSY;
+                               } else if(request_irq(DMA5_INTR_VECT,
+                                                     rx_interrupt,
+                                                     0,
+                                                     "synchronous serial 1 dma 
rx",
+                                                     &ports[0])) {
+                                       free_irq(DMA4_INTR_VECT, &port[0]);
+                                       printk(KERN_CRIT "Can't allocate sync 
serial port 0 IRQ");
+                                       return -EBUSY;
+                               } else if 
(crisv32_request_dma(SYNC_SER0_TX_DMA_NBR,
+                                                               "synchronous 
serial 0 dma tr",
+                                                               
DMA_VERBOSE_ON_ERROR,
+                                                               0,
+                                                               dma_sser0)) {
+                                       free_irq(DMA4_INTR_VECT, &port[0]);
+                                       free_irq(DMA5_INTR_VECT, &port[0]);
+                                       printk(KERN_CRIT "Can't allocate sync 
serial port 0 TX DMA channel");
+                                       return -EBUSY;
+                               } else if 
(crisv32_request_dma(SYNC_SER0_RX_DMA_NBR,
+                                                               "synchronous 
serial 0 dma rec",
+                                                               
DMA_VERBOSE_ON_ERROR,
+                                                               0,
+                                                               dma_sser0)) {
+                                       crisv32_free_dma(SYNC_SER0_TX_DMA_NBR);
+                                       free_irq(DMA4_INTR_VECT, &port[0]);
+                                       free_irq(DMA5_INTR_VECT, &port[0]);
+                                       printk(KERN_CRIT "Can't allocate sync 
serial port 1 RX DMA channel");
+                                       return -EBUSY;
+                               }
+#endif
+                       }
+                       else if (port == &ports[1]){
+#ifdef SYNC_SER_DMA
+                               if (request_irq(DMA6_INTR_VECT,
+                                               tr_interrupt,
+                                               0,
+                                               "synchronous serial 1 dma tr",
+                                               &ports[1])) {
+                                       printk(KERN_CRIT "Can't allocate sync 
serial port 1 IRQ");
+                                       return -EBUSY;
+                               } else if (request_irq(DMA7_INTR_VECT,
+                                                      rx_interrupt,
+                                                      0,
+                                                      "synchronous serial 1 
dma rx",
+                                                      &ports[1])) {
+                                       free_irq(DMA6_INTR_VECT, &ports[1]);
+                                       printk(KERN_CRIT "Can't allocate sync 
serial port 3 IRQ");
+                                       return -EBUSY;
+                               } else if 
(crisv32_request_dma(SYNC_SER1_TX_DMA_NBR,
+                                                               "synchronous 
serial 1 dma tr",
+                                                               
DMA_VERBOSE_ON_ERROR,
+                                                               0,
+                                                               dma_sser1)) {
+                                       free_irq(21, &ports[1]);
+                                       free_irq(20, &ports[1]);
+                                       printk(KERN_CRIT "Can't allocate sync 
serial port 3 TX DMA channel");
+                                       return -EBUSY;
+                               } else if 
(crisv32_request_dma(SYNC_SER1_RX_DMA_NBR,
+                                                           "synchronous serial 
3 dma rec",
+                                                           
DMA_VERBOSE_ON_ERROR,
+                                                           0,
+                                                           dma_sser1)) {
+                                       crisv32_free_dma(SYNC_SER1_TX_DMA_NBR);
+                                       free_irq(DMA6_INTR_VECT, &ports[1]);
+                                       free_irq(DMA7_INTR_VECT, &ports[1]);
+                                       printk(KERN_CRIT "Can't allocate sync 
serial port 3 RX DMA channel");
+                                       return -EBUSY;
+                               }
+#endif
+                       }
+
+                        /* Enable DMAs */
+                       REG_WR(dma, port->regi_dmain, rw_cfg, cfg);
+                       REG_WR(dma, port->regi_dmaout, rw_cfg, cfg);
+                       /* Enable DMA IRQs */
+                       REG_WR(dma, port->regi_dmain, rw_intr_mask, intr_mask);
+                       REG_WR(dma, port->regi_dmaout, rw_intr_mask, intr_mask);
+                       /* Set up wordsize = 2 for DMAs. */
+                       DMA_WR_CMD (port->regi_dmain, regk_dma_set_w_size1);
+                       DMA_WR_CMD (port->regi_dmaout, regk_dma_set_w_size1);
+
+                       start_dma_in(port);
+                       port->init_irqs = 0;
+               } else { /* !port->use_dma */
+#ifdef SYNC_SER_MANUAL
+                       if (port == &ports[0]) {
+                               if (request_irq(SSER0_INTR_VECT,
+                                               manual_interrupt,
+                                               0,
+                                               "synchronous serial manual irq",
+                                               &ports[0])) {
+                                       printk("Can't allocate sync serial 
manual irq");
+                                       return -EBUSY;
+                               }
+                       } else if (port == &ports[1]) {
+                               if (request_irq(SSER1_INTR_VECT,
+                                               manual_interrupt,
+                                               0,
+                                               "synchronous serial manual irq",
+                                               &ports[1])) {
+                                       printk(KERN_CRIT "Can't allocate sync 
serial manual irq");
+                                       return -EBUSY;
+                               }
+                       }
+                       port->init_irqs = 0;
+#else
+                       panic("sync_serial: Manual mode not supported.\n");
+#endif /* SYNC_SER_MANUAL */
+               }
+       } /* port->init_irqs */
+
+       port->busy++;
+       return 0;
+}
+
+static int sync_serial_release(struct inode *inode, struct file *file)
+{
+       int dev = MINOR(inode->i_rdev);
+       sync_port* port;
+
+       if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled)
+       {
+               DEBUG(printk("Invalid minor %d\n", dev));
+               return -ENODEV;
+       }
+       port = &ports[dev];
+       if (port->busy)
+               port->busy--;
+       if (!port->busy)
+          /* XXX */ ;
+       return 0;
+}
+
+static unsigned int sync_serial_poll(struct file *file, poll_table *wait)
+{
+       int dev = MINOR(file->f_dentry->d_inode->i_rdev);
+       unsigned int mask = 0;
+       sync_port* port;
+       DEBUGPOLL( static unsigned int prev_mask = 0; );
+
+       port = &ports[dev];
+       poll_wait(file, &port->out_wait_q, wait);
+       poll_wait(file, &port->in_wait_q, wait);
+       /* Some room to write */
+       if (port->out_count < OUT_BUFFER_SIZE)
+               mask |=  POLLOUT | POLLWRNORM;
+       /* At least an inbufchunk of data */
+       if (sync_data_avail(port) >= port->inbufchunk)
+               mask |= POLLIN | POLLRDNORM;
+
+       DEBUGPOLL(if (mask != prev_mask)
+             printk("sync_serial_poll: mask 0x%08X %s %s\n", mask,
+                    mask&POLLOUT?"POLLOUT":"", mask&POLLIN?"POLLIN":"");
+             prev_mask = mask;
+             );
+       return mask;
+}
+
+static int sync_serial_ioctl(struct inode *inode, struct file *file,
+                 unsigned int cmd, unsigned long arg)
+{
+       int return_val = 0;
+       int dev = MINOR(file->f_dentry->d_inode->i_rdev);
+       sync_port* port;
+       reg_sser_rw_tr_cfg tr_cfg;
+       reg_sser_rw_rec_cfg rec_cfg;
+       reg_sser_rw_frm_cfg frm_cfg;
+       reg_sser_rw_cfg gen_cfg;
+       reg_sser_rw_intr_mask intr_mask;
+
+       if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled)
+       {
+               DEBUG(printk("Invalid minor %d\n", dev));
+               return -1;
+       }
+        port = &ports[dev];
+       spin_lock_irq(&port->lock);
+
+       tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg);
+       rec_cfg = REG_RD(sser, port->regi_sser, rw_rec_cfg);
+       frm_cfg = REG_RD(sser, port->regi_sser, rw_frm_cfg);
+       gen_cfg = REG_RD(sser, port->regi_sser, rw_cfg);
+       intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask);
+
+       switch(cmd)
+       {
+       case SSP_SPEED:
+               if (GET_SPEED(arg) == CODEC)
+               {
+                       gen_cfg.base_freq = regk_sser_f32;
+                       /* FREQ = 0 => 4 MHz => clk_div = 7*/
+                       gen_cfg.clk_div = 6 + (1 << GET_FREQ(arg));
+               }
+               else
+               {
+                       gen_cfg.base_freq = regk_sser_f29_493;
+                       switch (GET_SPEED(arg))
+                       {
+                               case SSP150:
+                                       gen_cfg.clk_div = 29493000 / (150 * 8) 
- 1;
+                                       break;
+                               case SSP300:
+                                       gen_cfg.clk_div = 29493000 / (300 * 8) 
- 1;
+                                       break;
+                               case SSP600:
+                                       gen_cfg.clk_div = 29493000 / (600 * 8) 
- 1;
+                                       break;
+                               case SSP1200:
+                                       gen_cfg.clk_div = 29493000 / (1200 * 8) 
- 1;
+                                       break;
+                               case SSP2400:
+                                       gen_cfg.clk_div = 29493000 / (2400 * 8) 
- 1;
+                                       break;
+                               case SSP4800:
+                                       gen_cfg.clk_div = 29493000 / (4800 * 8) 
- 1;
+                                       break;
+                               case SSP9600:
+                                       gen_cfg.clk_div = 29493000 / (9600 * 8) 
- 1;
+                                       break;
+                               case SSP19200:
+                                       gen_cfg.clk_div = 29493000 / (19200 * 
8) - 1;
+                                       break;
+                               case SSP28800:
+                                       gen_cfg.clk_div = 29493000 / (28800 * 
8) - 1;
+                                       break;
+                               case SSP57600:
+                                       gen_cfg.clk_div = 29493000 / (57600 * 
8) - 1;
+                                       break;
+                               case SSP115200:
+                                       gen_cfg.clk_div = 29493000 / (115200 * 
8) - 1;
+                                       break;
+                               case SSP230400:
+                                       gen_cfg.clk_div = 29493000 / (230400 * 
8) - 1;
+                                       break;
+                               case SSP460800:
+                                       gen_cfg.clk_div = 29493000 / (460800 * 
8) - 1;
+                                       break;
+                               case SSP921600:
+                                       gen_cfg.clk_div = 29493000 / (921600 * 
8) - 1;
+                                       break;
+                               case SSP3125000:
+                                       gen_cfg.base_freq = regk_sser_f100;
+                                       gen_cfg.clk_div = 100000000 / (3125000 
* 8) - 1;
+                                       break;
+
+                       }
+               }
+               frm_cfg.wordrate = GET_WORD_RATE(arg);
+
+               break;
+       case SSP_MODE:
+               switch(arg)
+               {
+                       case MASTER_OUTPUT:
+                               port->output = 1;
+                               port->input = 0;
+                               gen_cfg.clk_dir = regk_sser_out;
+                               break;
+                       case SLAVE_OUTPUT:
+                               port->output = 1;
+                               port->input = 0;
+                               gen_cfg.clk_dir = regk_sser_in;
+                               break;
+                       case MASTER_INPUT:
+                               port->output = 0;
+                               port->input = 1;
+                               gen_cfg.clk_dir = regk_sser_out;
+                               break;
+                       case SLAVE_INPUT:
+                               port->output = 0;
+                               port->input = 1;
+                               gen_cfg.clk_dir = regk_sser_in;
+                               break;
+                       case MASTER_BIDIR:
+                               port->output = 1;
+                               port->input = 1;
+                               gen_cfg.clk_dir = regk_sser_out;
+                               break;
+                       case SLAVE_BIDIR:
+                               port->output = 1;
+                               port->input = 1;
+                               gen_cfg.clk_dir = regk_sser_in;
+                               break;
+                       default:
+                               spin_unlock_irq(&port->lock);
+                               return -EINVAL;
+
+               }
+               if (!port->use_dma || (arg == MASTER_OUTPUT || arg == 
SLAVE_OUTPUT))
+                       intr_mask.rdav = regk_sser_yes;
+               break;
+       case SSP_FRAME_SYNC:
+               if (arg & NORMAL_SYNC)
+                       frm_cfg.tr_delay = 1;
+               else if (arg & EARLY_SYNC)
+                       frm_cfg.tr_delay = 0;
+
+               tr_cfg.bulk_wspace = frm_cfg.tr_delay;
+               frm_cfg.early_wend = regk_sser_yes;
+               if (arg & BIT_SYNC)
+                       frm_cfg.type = regk_sser_edge;
+               else if (arg & WORD_SYNC)
+                       frm_cfg.type = regk_sser_level;
+               else if (arg & EXTENDED_SYNC)
+                       frm_cfg.early_wend = regk_sser_no;
+
+               if (arg & SYNC_ON)
+                       frm_cfg.frame_pin_use = regk_sser_frm;
+               else if (arg & SYNC_OFF)
+                       frm_cfg.frame_pin_use = regk_sser_gio0;
+
+               if (arg & WORD_SIZE_8)
+                       rec_cfg.sample_size = tr_cfg.sample_size = 7;
+               else if (arg & WORD_SIZE_12)
+                       rec_cfg.sample_size = tr_cfg.sample_size = 11;
+               else if (arg & WORD_SIZE_16)
+                       rec_cfg.sample_size = tr_cfg.sample_size = 15;
+               else if (arg & WORD_SIZE_24)
+                       rec_cfg.sample_size = tr_cfg.sample_size = 23;
+               else if (arg & WORD_SIZE_32)
+                       rec_cfg.sample_size = tr_cfg.sample_size = 31;
+
+               if (arg & BIT_ORDER_MSB)
+                       rec_cfg.sh_dir = tr_cfg.sh_dir = regk_sser_msbfirst;
+               else if (arg & BIT_ORDER_LSB)
+                       rec_cfg.sh_dir = tr_cfg.sh_dir = regk_sser_lsbfirst;
+
+               if (arg & FLOW_CONTROL_ENABLE)
+                       rec_cfg.fifo_thr = regk_sser_thr16;
+               else if (arg & FLOW_CONTROL_DISABLE)
+                       rec_cfg.fifo_thr = regk_sser_inf;
+
+               if (arg & CLOCK_NOT_GATED)
+                       gen_cfg.gate_clk = regk_sser_no;
+               else if (arg & CLOCK_GATED)
+                       gen_cfg.gate_clk = regk_sser_yes;
+
+               break;
+       case SSP_IPOLARITY:
+               /* NOTE!! negedge is considered NORMAL */
+               if (arg & CLOCK_NORMAL)
+                       rec_cfg.clk_pol = regk_sser_neg;
+               else if (arg & CLOCK_INVERT)
+                       rec_cfg.clk_pol = regk_sser_pos;
+
+               if (arg & FRAME_NORMAL)
+                       frm_cfg.level = regk_sser_pos_hi;
+               else if (arg & FRAME_INVERT)
+                       frm_cfg.level = regk_sser_neg_lo;
+
+               if (arg & STATUS_NORMAL)
+                       gen_cfg.hold_pol = regk_sser_pos;
+               else if (arg & STATUS_INVERT)
+                       gen_cfg.hold_pol = regk_sser_neg;
+               break;
+       case SSP_OPOLARITY:
+               if (arg & CLOCK_NORMAL)
+                       gen_cfg.out_clk_pol = regk_sser_neg;
+               else if (arg & CLOCK_INVERT)
+                       gen_cfg.out_clk_pol = regk_sser_pos;
+
+               if (arg & FRAME_NORMAL)
+                       frm_cfg.level = regk_sser_pos_hi;
+               else if (arg & FRAME_INVERT)
+                       frm_cfg.level = regk_sser_neg_lo;
+
+               if (arg & STATUS_NORMAL)
+                       gen_cfg.hold_pol = regk_sser_pos;
+               else if (arg & STATUS_INVERT)
+                       gen_cfg.hold_pol = regk_sser_neg;
+               break;
+       case SSP_SPI:
+               rec_cfg.fifo_thr = regk_sser_inf;
+               rec_cfg.sh_dir = tr_cfg.sh_dir = regk_sser_msbfirst;
+               rec_cfg.sample_size = tr_cfg.sample_size = 7;
+               frm_cfg.frame_pin_use = regk_sser_frm;
+               frm_cfg.type = regk_sser_level;
+               frm_cfg.tr_delay = 1;
+               frm_cfg.level = regk_sser_neg_lo;
+               if (arg & SPI_SLAVE)
+               {
+                       rec_cfg.clk_pol = regk_sser_neg;
+                       gen_cfg.clk_dir = regk_sser_in;
+                       port->input = 1;
+                       port->output = 0;
+               }
+               else
+               {
+                       gen_cfg.out_clk_pol = regk_sser_pos;
+                       port->input = 0;
+                       port->output = 1;
+                       gen_cfg.clk_dir = regk_sser_out;
+               }
+               break;
+       case SSP_INBUFCHUNK:
+               break;
+       default:
+               return_val = -1;
+       }
+
+
+       if (port->started)
+       {
+               tr_cfg.tr_en = port->output;
+               rec_cfg.rec_en = port->input;
+       }
+
+       REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg);
+       REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg);
+       REG_WR(sser, port->regi_sser, rw_frm_cfg, frm_cfg);
+       REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask);
+       REG_WR(sser, port->regi_sser, rw_cfg, gen_cfg);
+
+       spin_unlock_irq(&port->lock);
+       return return_val;
+}
+
+static ssize_t sync_serial_write(struct file * file, const char * buf,
+                                 size_t count, loff_t *ppos)
+{
+       int dev = MINOR(file->f_dentry->d_inode->i_rdev);
+       DECLARE_WAITQUEUE(wait, current);
+       sync_port *port;
+       unsigned long c, c1;
+       unsigned long free_outp;
+       unsigned long outp;
+       unsigned long out_buffer;
+       unsigned long flags;
+
+       if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled)
+       {
+               DEBUG(printk("Invalid minor %d\n", dev));
+               return -ENODEV;
+       }
+       port = &ports[dev];
+
+       DEBUGWRITE(printk("W d%d c %lu (%d/%d)\n", port->port_nbr, count, 
port->out_count, OUT_BUFFER_SIZE));
+       /* Space to end of buffer */
+       /*
+        * out_buffer <c1>012345<-   c    ->OUT_BUFFER_SIZE
+        *            outp^    +out_count
+                               ^free_outp
+        * out_buffer 45<-     c      ->0123OUT_BUFFER_SIZE
+        *             +out_count   outp^
+        *              free_outp
+        *
+        */
+
+       /* Read variables that may be updated by interrupts */
+       spin_lock_irqsave(&port->lock, flags);
+       count = count > OUT_BUFFER_SIZE - port->out_count ? OUT_BUFFER_SIZE  - 
port->out_count : count;
+       outp = (unsigned long)port->outp;
+       free_outp = outp + port->out_count;
+       spin_unlock_irqrestore(&port->lock, flags);
+       out_buffer = (unsigned long)port->out_buffer;
+
+       /* Find out where and how much to write */
+       if (free_outp >= out_buffer + OUT_BUFFER_SIZE)
+               free_outp -= OUT_BUFFER_SIZE;
+       if (free_outp >= outp)
+               c = out_buffer + OUT_BUFFER_SIZE - free_outp;
+       else
+               c = outp - free_outp;
+       if (c > count)
+               c = count;
+
+//     DEBUGWRITE(printk("w op %08lX fop %08lX c %lu\n", outp, free_outp, c));
+       if (copy_from_user((void*)free_outp, buf, c))
+               return -EFAULT;
+
+       if (c != count) {
+               buf += c;
+               c1 = count - c;
+               DEBUGWRITE(printk("w2 fi %lu c %lu c1 %lu\n", 
free_outp-out_buffer, c, c1));
+               if (copy_from_user((void*)out_buffer, buf, c1))
+                       return -EFAULT;
+       }
+       spin_lock_irqsave(&port->lock, flags);
+       port->out_count += count;
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       /* Make sure transmitter/receiver is running */
+       if (!port->started)
+       {
+               reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg);
+               reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, 
rw_tr_cfg);
+               reg_sser_rw_rec_cfg rec_cfg = REG_RD(sser, port->regi_sser, 
rw_rec_cfg);
+               cfg.en = regk_sser_yes;
+               tr_cfg.tr_en = port->output;
+               rec_cfg.rec_en = port->input;
+               REG_WR(sser, port->regi_sser, rw_cfg, cfg);
+               REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg);
+               REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg);
+               port->started = 1;
+       }
+
+       if (file->f_flags & O_NONBLOCK) {
+               spin_lock_irqsave(&port->lock, flags);
+               if (!port->tr_running) {
+                       if (!port->use_dma) {
+                               reg_sser_rw_intr_mask intr_mask;
+                               intr_mask = REG_RD(sser, port->regi_sser, 
rw_intr_mask);
+                               /* Start sender by writing data */
+                               send_word(port);
+                               /* and enable transmitter ready IRQ */
+                               intr_mask.trdy = 1;
+                               REG_WR(sser, port->regi_sser, rw_intr_mask, 
intr_mask);
+                       } else {
+                               start_dma(port, (unsigned char* volatile 
)port->outp, c);
+                       }
+               }
+               spin_unlock_irqrestore(&port->lock, flags);
+               DEBUGWRITE(printk("w d%d c %lu NB\n",
+                                 port->port_nbr, count));
+               return count;
+       }
+
+       /* Sleep until all sent */
+
+       add_wait_queue(&port->out_wait_q, &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+       spin_lock_irqsave(&port->lock, flags);
+       if (!port->tr_running) {
+               if (!port->use_dma) {
+                       reg_sser_rw_intr_mask intr_mask;
+                       intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask);
+                       /* Start sender by writing data */
+                       send_word(port);
+                       /* and enable transmitter ready IRQ */
+                       intr_mask.trdy = 1;
+                       REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask);
+               } else {
+                       start_dma(port, port->outp, c);
+               }
+       }
+       spin_unlock_irqrestore(&port->lock, flags);
+       schedule();
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&port->out_wait_q, &wait);
+       if (signal_pending(current))
+       {
+               return -EINTR;
+       }
+       DEBUGWRITE(printk("w d%d c %lu\n", port->port_nbr, count));
+       return count;
+}
+
+static ssize_t sync_serial_read(struct file * file, char * buf,
+                               size_t count, loff_t *ppos)
+{
+       int dev = MINOR(file->f_dentry->d_inode->i_rdev);
+       int avail;
+       sync_port *port;
+       unsigned char* start;
+       unsigned char* end;
+       unsigned long flags;
+
+       if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled)
+       {
+               DEBUG(printk("Invalid minor %d\n", dev));
+               return -ENODEV;
+       }
+       port = &ports[dev];
+
+       DEBUGREAD(printk("R%d c %d ri %lu wi %lu /%lu\n", dev, count, 
port->readp - port->flip, port->writep - port->flip, port->in_buffer_size));
+
+       if (!port->started)
+       {
+               reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg);
+               reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, 
rw_tr_cfg);
+               reg_sser_rw_rec_cfg rec_cfg = REG_RD(sser, port->regi_sser, 
rw_rec_cfg);
+               cfg.en = regk_sser_yes;
+               tr_cfg.tr_en = regk_sser_yes;
+               rec_cfg.rec_en = regk_sser_yes;
+               REG_WR(sser, port->regi_sser, rw_cfg, cfg);
+               REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg);
+               REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg);
+               port->started = 1;
+       }
+
+
+       /* Calculate number of available bytes */
+       /* Save pointers to avoid that they are modified by interrupt */
+       spin_lock_irqsave(&port->lock, flags);
+       start = (unsigned char*)port->readp; /* cast away volatile */
+       end = (unsigned char*)port->writep;  /* cast away volatile */
+       spin_unlock_irqrestore(&port->lock, flags);
+       while ((start == end) && !port->full) /* No data */
+       {
+               if (file->f_flags & O_NONBLOCK)
+               {
+                       return -EAGAIN;
+               }
+
+               interruptible_sleep_on(&port->in_wait_q);
+               if (signal_pending(current))
+               {
+                       return -EINTR;
+               }
+               spin_lock_irqsave(&port->lock, flags);
+               start = (unsigned char*)port->readp; /* cast away volatile */
+               end = (unsigned char*)port->writep;  /* cast away volatile */
+               spin_unlock_irqrestore(&port->lock, flags);
+       }
+
+       /* Lazy read, never return wrapped data. */
+       if (port->full)
+               avail = port->in_buffer_size;
+       else if (end > start)
+               avail = end - start;
+       else
+               avail = port->flip + port->in_buffer_size - start;
+
+       count = count > avail ? avail : count;
+       if (copy_to_user(buf, start, count))
+               return -EFAULT;
+       /* Disable interrupts while updating readp */
+       spin_lock_irqsave(&port->lock, flags);
+       port->readp += count;
+       if (port->readp >= port->flip + port->in_buffer_size) /* Wrap? */
+               port->readp = port->flip;
+       port->full = 0;
+       spin_unlock_irqrestore(&port->lock, flags);
+       DEBUGREAD(printk("r %d\n", count));
+       return count;
+}
+
+static void send_word(sync_port* port)
+{
+       reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg);
+       reg_sser_rw_tr_data tr_data =  {0};
+
+       switch(tr_cfg.sample_size)
+       {
+        case 8:
+                port->out_count--;
+                tr_data.data = *port->outp++;
+                REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);
+                if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE)
+                        port->outp = port->out_buffer;
+                break;
+        case 12:
+        {
+               int data = (*port->outp++) << 8;
+               data |= *port->outp++;
+               port->out_count-=2;
+               tr_data.data = data;
+               REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);
+               if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE)
+                       port->outp = port->out_buffer;
+       }
+       break;
+       case 16:
+               port->out_count-=2;
+               tr_data.data = *(unsigned short *)port->outp;
+               REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);
+               port->outp+=2;
+               if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE)
+                       port->outp = port->out_buffer;
+               break;
+       case 24:
+               port->out_count-=3;
+               tr_data.data = *(unsigned short *)port->outp;
+               REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);
+               port->outp+=2;
+               tr_data.data = *port->outp++;
+               REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);
+               if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE)
+                       port->outp = port->out_buffer;
+               break;
+       case 32:
+               port->out_count-=4;
+               tr_data.data = *(unsigned short *)port->outp;
+               REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);
+               port->outp+=2;
+               tr_data.data = *(unsigned short *)port->outp;
+               REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);
+               port->outp+=2;
+               if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE)
+                       port->outp = port->out_buffer;
+               break;
+       }
+}
+
+
+static void start_dma(struct sync_port* port, const char* data, int count)
+{
+       port->tr_running = 1;
+       port->out_descr.buf = (char*)virt_to_phys((char*)data);
+       port->out_descr.after = port->out_descr.buf + count;
+       port->out_descr.eol = port->out_descr.intr = 1;
+
+       port->out_context.saved_data = 
(dma_descr_data*)virt_to_phys(&port->out_descr);
+       port->out_context.saved_data_buf = port->out_descr.buf;
+
+       DMA_START_CONTEXT(port->regi_dmaout, 
virt_to_phys((char*)&port->out_context));
+       DEBUGTXINT(printk("dma %08lX c %d\n", (unsigned long)data, count));
+}
+
+static void start_dma_in(sync_port* port)
+{
+       int i;
+       char* buf;
+       port->writep = port->flip;
+
+       if (port->writep > port->flip + port->in_buffer_size)
+       {
+               panic("Offset too large in sync serial driver\n");
+               return;
+       }
+       buf = (char*)virt_to_phys(port->in_buffer);
+       for (i = 0; i < NUM_IN_DESCR; i++) {
+               port->in_descr[i].buf = buf;
+               port->in_descr[i].after = buf + port->inbufchunk;
+               port->in_descr[i].intr = 1;
+               port->in_descr[i].next = 
(dma_descr_data*)virt_to_phys(&port->in_descr[i+1]);
+               port->in_descr[i].buf = buf;
+               buf += port->inbufchunk;
+       }
+       /* Link the last descriptor to the first */
+       port->in_descr[i-1].next = 
(dma_descr_data*)virt_to_phys(&port->in_descr[0]);
+       port->in_descr[i-1].eol = regk_sser_yes;
+       port->next_rx_desc = &port->in_descr[0];
+       port->prev_rx_desc = &port->in_descr[NUM_IN_DESCR - 1];
+       port->in_context.saved_data = 
(dma_descr_data*)virt_to_phys(&port->in_descr[0]);
+       port->in_context.saved_data_buf = port->in_descr[0].buf;
+       DMA_START_CONTEXT(port->regi_dmain, virt_to_phys(&port->in_context));
+}
+
+#ifdef SYNC_SER_DMA
+static irqreturn_t tr_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+       reg_dma_r_masked_intr masked;
+       reg_dma_rw_ack_intr ack_intr = {.data = regk_dma_yes};
+       int i;
+       struct dma_descr_data *descr;
+       unsigned int sentl;
+       int found = 0;
+
+       for (i = 0; i < NUMBER_OF_PORTS; i++)
+       {
+               sync_port *port = &ports[i];
+               if (!port->enabled  || !port->use_dma )
+                       continue;
+
+               masked = REG_RD(dma, port->regi_dmaout, r_masked_intr);
+
+               if (masked.data) /* IRQ active for the port? */
+               {
+                       found = 1;
+                       /* Clear IRQ */
+                       REG_WR(dma, port->regi_dmaout, rw_ack_intr, ack_intr);
+                       descr = &port->out_descr;
+                       sentl = descr->after - descr->buf;
+                       port->out_count -= sentl;
+                       port->outp += sentl;
+                       if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE)
+                               port->outp = port->out_buffer;
+                       if (port->out_count)  {
+                               int c;
+                               c = port->out_buffer + OUT_BUFFER_SIZE - 
port->outp;
+                               if (c > port->out_count)
+                                       c = port->out_count;
+                               DEBUGTXINT(printk("tx_int DMAWRITE %i %i\n", 
sentl, c));
+                               start_dma(port, port->outp, c);
+                       } else  {
+                               DEBUGTXINT(printk("tx_int DMA stop %i\n", 
sentl));
+                               port->tr_running = 0;
+                       }
+                       wake_up_interruptible(&port->out_wait_q); /* wake up 
the waiting process */
+               }
+       }
+       return IRQ_RETVAL(found);
+} /* tr_interrupt */
+
+static irqreturn_t rx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+       reg_dma_r_masked_intr masked;
+       reg_dma_rw_ack_intr ack_intr = {.data = regk_dma_yes};
+
+       int i;
+       int found = 0;
+
+       for (i = 0; i < NUMBER_OF_PORTS; i++)
+       {
+               sync_port *port = &ports[i];
+
+               if (!port->enabled || !port->use_dma )
+                       continue;
+
+               masked = REG_RD(dma, port->regi_dmain, r_masked_intr);
+
+               if (masked.data) /* Descriptor interrupt */
+               {
+                       found = 1;
+                       while (REG_RD(dma, port->regi_dmain, rw_data) !=
+                              virt_to_phys(port->next_rx_desc)) {
+
+                               if (port->writep + port->inbufchunk > 
port->flip + port->in_buffer_size) {
+                                       int first_size = port->flip + 
port->in_buffer_size - port->writep;
+                                       memcpy((char*)port->writep, 
phys_to_virt((unsigned)port->next_rx_desc->buf), first_size);
+                                       memcpy(port->flip, 
phys_to_virt((unsigned)port->next_rx_desc->buf+first_size), port->inbufchunk - 
first_size);
+                                       port->writep = port->flip + 
port->inbufchunk - first_size;
+                               } else {
+                                       memcpy((char*)port->writep,
+                                              
phys_to_virt((unsigned)port->next_rx_desc->buf),
+                                              port->inbufchunk);
+                                       port->writep += port->inbufchunk;
+                                       if (port->writep >= port->flip + 
port->in_buffer_size)
+                                               port->writep = port->flip;
+                               }
+                                if (port->writep == port->readp)
+                                {
+                                 port->full = 1;
+                                }
+
+                               port->next_rx_desc->eol = 0;
+                               port->prev_rx_desc->eol = 1;
+                               port->prev_rx_desc = 
phys_to_virt((unsigned)port->next_rx_desc);
+                               port->next_rx_desc = 
phys_to_virt((unsigned)port->next_rx_desc->next);
+                               wake_up_interruptible(&port->in_wait_q); /* 
wake up the waiting process */
+                               DMA_CONTINUE(port->regi_dmain);
+                               REG_WR(dma, port->regi_dmain, rw_ack_intr, 
ack_intr);
+
+                       }
+               }
+       }
+       return IRQ_RETVAL(found);
+} /* rx_interrupt */
+#endif /* SYNC_SER_DMA */
+
+#ifdef SYNC_SER_MANUAL
+static irqreturn_t manual_interrupt(int irq, void *dev_id, struct pt_regs * 
regs)
+{
+       int i;
+       int found = 0;
+       reg_sser_r_masked_intr masked;
+
+       for (i = 0; i < NUMBER_OF_PORTS; i++)
+       {
+               sync_port* port = &ports[i];
+
+               if (!port->enabled || port->use_dma)
+               {
+                       continue;
+               }
+
+               masked = REG_RD(sser, port->regi_sser, r_masked_intr);
+               if (masked.rdav)        /* Data received? */
+               {
+                       reg_sser_rw_rec_cfg rec_cfg = REG_RD(sser, 
port->regi_sser, rw_rec_cfg);
+                       reg_sser_r_rec_data data = REG_RD(sser, 
port->regi_sser, r_rec_data);
+                       found = 1;
+                       /* Read data */
+                       switch(rec_cfg.sample_size)
+                       {
+                       case 8:
+                               *port->writep++ = data.data & 0xff;
+                               break;
+                       case 12:
+                               *port->writep = (data.data & 0x0ff0) >> 4;
+                               *(port->writep + 1) = data.data & 0x0f;
+                               port->writep+=2;
+                               break;
+                       case 16:
+                               *(unsigned short*)port->writep = data.data;
+                               port->writep+=2;
+                               break;
+                       case 24:
+                               *(unsigned int*)port->writep = data.data;
+                               port->writep+=3;
+                               break;
+                       case 32:
+                               *(unsigned int*)port->writep = data.data;
+                               port->writep+=4;
+                               break;
+                       }
+
+                       if (port->writep >= port->flip + port->in_buffer_size) 
/* Wrap? */
+                               port->writep = port->flip;
+                       if (port->writep == port->readp) {
+                               /* receive buffer overrun, discard oldest data
+                                */
+                               port->readp++;
+                               if (port->readp >= port->flip + 
port->in_buffer_size) /* Wrap? */
+                                       port->readp = port->flip;
+                       }
+                       if (sync_data_avail(port) >= port->inbufchunk)
+                               wake_up_interruptible(&port->in_wait_q); /* 
Wake up application */
+               }
+
+               if (masked.trdy) /* Transmitter ready? */
+               {
+                       found = 1;
+                       if (port->out_count > 0) /* More data to send */
+                               send_word(port);
+                       else /* transmission finished */
+                       {
+                               reg_sser_rw_intr_mask intr_mask;
+                               intr_mask = REG_RD(sser, port->regi_sser, 
rw_intr_mask);
+                               intr_mask.trdy = 0;
+                               REG_WR(sser, port->regi_sser, rw_intr_mask, 
intr_mask);
+                               wake_up_interruptible(&port->out_wait_q); /* 
Wake up application */
+                       }
+               }
+       }
+       return IRQ_RETVAL(found);
+}
+#endif
+
+module_init(etrax_sync_serial_init);
diff -urN linux/arch/cris/arch-v32/drivers/pci/Makefile 
linux/arch/cris/arch-v32/drivers/pci/Makefile
--- linux/arch/cris/arch-v32/drivers/pci/Makefile       1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/drivers/pci/Makefile       2005-08-01 
19:23:42.579311000 +0100     1.1
@@ -0,0 +1,5 @@
+#
+# Makefile for Etrax cardbus driver
+#
+
+obj-$(CONFIG_ETRAX_CARDBUS)        += bios.o dma.o
diff -urN linux/arch/cris/arch-v32/drivers/pci/bios.c 
linux/arch/cris/arch-v32/drivers/pci/bios.c
--- linux/arch/cris/arch-v32/drivers/pci/bios.c 1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/drivers/pci/bios.c 2005-08-01 19:23:42.602879000 
+0100     1.1
@@ -0,0 +1,131 @@
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <asm/arch/hwregs/intr_vect.h>
+
+void __devinit  pcibios_fixup_bus(struct pci_bus *b)
+{
+}
+
+char * __devinit  pcibios_setup(char *str)
+{
+       return NULL;
+}
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+       u8 lat;
+       pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+       printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", 
pci_name(dev), lat);
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+}
+
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+                       enum pci_mmap_state mmap_state, int write_combine)
+{
+       unsigned long prot;
+
+       /* Leave vm_pgoff as-is, the PCI space address is the physical
+        * address on this platform.
+        */
+       vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO);
+
+       prot = pgprot_val(vma->vm_page_prot);
+       vma->vm_page_prot = __pgprot(prot);
+
+       /* Write-combine setting is ignored, it is changed via the mtrr
+        * interfaces on this platform.
+        */
+       if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+                            vma->vm_end - vma->vm_start,
+                            vma->vm_page_prot))
+               return -EAGAIN;
+
+       return 0;
+}
+
+void
+pcibios_align_resource(void *data, struct resource *res,
+                      unsigned long size, unsigned long align)
+{
+       if (res->flags & IORESOURCE_IO) {
+               unsigned long start = res->start;
+
+               if (start & 0x300) {
+                       start = (start + 0x3ff) & ~0x3ff;
+                       res->start = start;
+               }
+       }
+}
+
+int pcibios_enable_resources(struct pci_dev *dev, int mask)
+{
+       u16 cmd, old_cmd;
+       int idx;
+       struct resource *r;
+
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       old_cmd = cmd;
+       for(idx=0; idx<6; idx++) {
+               /* Only set up the requested stuff */
+               if (!(mask & (1<<idx)))
+                       continue;
+
+               r = &dev->resource[idx];
+               if (!r->start && r->end) {
+                       printk(KERN_ERR "PCI: Device %s not available because 
of resource collisions\n", pci_name(dev));
+                       return -EINVAL;
+               }
+               if (r->flags & IORESOURCE_IO)
+                       cmd |= PCI_COMMAND_IO;
+               if (r->flags & IORESOURCE_MEM)
+                       cmd |= PCI_COMMAND_MEMORY;
+       }
+       if (dev->resource[PCI_ROM_RESOURCE].start)
+               cmd |= PCI_COMMAND_MEMORY;
+       if (cmd != old_cmd) {
+               printk("PCI: Enabling device %s (%04x -> %04x)\n", 
pci_name(dev), old_cmd, cmd);
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+       }
+       return 0;
+}
+
+int pcibios_enable_irq(struct pci_dev *dev)
+{
+       dev->irq = EXT_INTR_VECT;
+       return 0;
+}
+
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+       int err;
+
+       if ((err = pcibios_enable_resources(dev, mask)) < 0)
+               return err;
+
+       return pcibios_enable_irq(dev);
+}
+
+int pcibios_assign_resources(void)
+{
+       struct pci_dev *dev = NULL;
+       int idx;
+       struct resource *r;
+
+       while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+               int class = dev->class >> 8;
+
+               /* Don't touch classless devices and host bridges */
+               if (!class || class == PCI_CLASS_BRIDGE_HOST)
+                       continue;
+
+               for(idx=0; idx<6; idx++) {
+                       r = &dev->resource[idx];
+
+                       if (!r->start && r->end)
+                               pci_assign_resource(dev, idx);
+               }
+       }
+       return 0;
+}
+
+EXPORT_SYMBOL(pcibios_assign_resources);
diff -urN linux/arch/cris/arch-v32/drivers/pci/dma.c 
linux/arch/cris/arch-v32/drivers/pci/dma.c
--- linux/arch/cris/arch-v32/drivers/pci/dma.c  1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/drivers/pci/dma.c  2005-08-01 19:23:42.624087000 
+0100     1.1
@@ -0,0 +1,149 @@
+/*
+ * Dynamic DMA mapping support.
+ *
+ * On cris there is no hardware dynamic DMA address translation,
+ * so consistent alloc/free are merely page allocation/freeing.
+ * The rest of the dynamic DMA mapping interface is implemented
+ * in asm/pci.h.
+ *
+ * Borrowed from i386.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+struct dma_coherent_mem {
+       void            *virt_base;
+       u32             device_base;
+       int             size;
+       int             flags;
+       unsigned long   *bitmap;
+};
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+                          dma_addr_t *dma_handle, unsigned int __nocast gfp)
+{
+       void *ret;
+       struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
+       int order = get_order(size);
+       /* ignore region specifiers */
+       gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
+
+       if (mem) {
+               int page = bitmap_find_free_region(mem->bitmap, mem->size,
+                                                    order);
+               if (page >= 0) {
+                       *dma_handle = mem->device_base + (page << PAGE_SHIFT);
+                       ret = mem->virt_base + (page << PAGE_SHIFT);
+                       memset(ret, 0, size);
+                       return ret;
+               }
+               if (mem->flags & DMA_MEMORY_EXCLUSIVE)
+                       return NULL;
+       }
+
+       if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
+               gfp |= GFP_DMA;
+
+       ret = (void *)__get_free_pages(gfp, order);
+
+       if (ret != NULL) {
+               memset(ret, 0, size);
+               *dma_handle = virt_to_phys(ret);
+       }
+       return ret;
+}
+
+void dma_free_coherent(struct device *dev, size_t size,
+                        void *vaddr, dma_addr_t dma_handle)
+{
+       struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
+       int order = get_order(size);
+
+       if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + 
(mem->size << PAGE_SHIFT))) {
+               int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
+
+               bitmap_release_region(mem->bitmap, page, order);
+       } else
+               free_pages((unsigned long)vaddr, order);
+}
+
+int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
+                               dma_addr_t device_addr, size_t size, int flags)
+{
+       void __iomem *mem_base;
+       int pages = size >> PAGE_SHIFT;
+       int bitmap_size = (pages + 31)/32;
+
+       if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0)
+               goto out;
+       if (!size)
+               goto out;
+       if (dev->dma_mem)
+               goto out;
+
+       /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
+
+       mem_base = ioremap(bus_addr, size);
+       if (!mem_base)
+               goto out;
+
+       dev->dma_mem = kmalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
+       if (!dev->dma_mem)
+               goto out;
+       memset(dev->dma_mem, 0, sizeof(struct dma_coherent_mem));
+       dev->dma_mem->bitmap = kmalloc(bitmap_size, GFP_KERNEL);
+       if (!dev->dma_mem->bitmap)
+               goto free1_out;
+       memset(dev->dma_mem->bitmap, 0, bitmap_size);
+
+       dev->dma_mem->virt_base = mem_base;
+       dev->dma_mem->device_base = device_addr;
+       dev->dma_mem->size = pages;
+       dev->dma_mem->flags = flags;
+
+       if (flags & DMA_MEMORY_MAP)
+               return DMA_MEMORY_MAP;
+
+       return DMA_MEMORY_IO;
+
+ free1_out:
+       kfree(dev->dma_mem->bitmap);
+ out:
+       return 0;
+}
+EXPORT_SYMBOL(dma_declare_coherent_memory);
+
+void dma_release_declared_memory(struct device *dev)
+{
+       struct dma_coherent_mem *mem = dev->dma_mem;
+
+       if(!mem)
+               return;
+       dev->dma_mem = NULL;
+       iounmap(mem->virt_base);
+       kfree(mem->bitmap);
+       kfree(mem);
+}
+EXPORT_SYMBOL(dma_release_declared_memory);
+
+void *dma_mark_declared_memory_occupied(struct device *dev,
+                                       dma_addr_t device_addr, size_t size)
+{
+       struct dma_coherent_mem *mem = dev->dma_mem;
+       int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1) >> 
PAGE_SHIFT;
+       int pos, err;
+
+       if (!mem)
+               return ERR_PTR(-EINVAL);
+
+       pos = (device_addr - mem->device_base) >> PAGE_SHIFT;
+       err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages));
+       if (err != 0)
+               return ERR_PTR(err);
+       return mem->virt_base + (pos << PAGE_SHIFT);
+}
+EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
diff -urN linux/arch/cris/arch-v32/kernel/Makefile 
linux/arch/cris/arch-v32/kernel/Makefile
--- linux/arch/cris/arch-v32/kernel/Makefile    1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/Makefile    2005-08-01 19:23:42.806403000 
+0100     1.1
@@ -0,0 +1,21 @@
+# $Id: Makefile,v 1.11 2004/12/17 10:16:13 starvik Exp $
+#
+# Makefile for the linux kernel.
+#
+
+extra-y        := head.o
+
+
+obj-y   := entry.o traps.o irq.o debugport.o dma.o pinmux.o \
+          process.o ptrace.o setup.o signal.o traps.o time.o \
+          arbiter.o io.o
+
+obj-$(CONFIG_ETRAXFS_SIM) += vcs_hook.o
+
+obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_ETRAX_KGDB) += kgdb.o kgdb_asm.o
+obj-$(CONFIG_ETRAX_FAST_TIMER) += fasttimer.o
+obj-$(CONFIG_MODULES)    += crisksyms.o
+
+clean:
+
diff -urN linux/arch/cris/arch-v32/kernel/arbiter.c 
linux/arch/cris/arch-v32/kernel/arbiter.c
--- linux/arch/cris/arch-v32/kernel/arbiter.c   1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/arbiter.c   2005-08-01 19:23:42.829942000 
+0100     1.1
@@ -0,0 +1,297 @@
+/*
+ * Memory arbiter functions. Allocates bandwith through the
+ * arbiter and sets up arbiter breakpoints.
+ *
+ * The algorithm first assigns slots to the clients that has specified
+ * bandwith (e.g. ethernet) and then the remaining slots are divided
+ * on all the active clients.
+ *
+ * Copyright (c) 2004, 2005 Axis Communications AB.
+ */
+
+#include <linux/config.h>
+#include <asm/arch/hwregs/reg_map.h>
+#include <asm/arch/hwregs/reg_rdwr.h>
+#include <asm/arch/hwregs/marb_defs.h>
+#include <asm/arch/arbiter.h>
+#include <asm/arch/hwregs/intr_vect.h>
+#include <linux/interrupt.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+
+struct crisv32_watch_entry
+{
+  unsigned long instance;
+  watch_callback* cb;
+  unsigned long start;
+  unsigned long end;
+  int used;
+};
+
+#define NUMBER_OF_BP 4
+#define NBR_OF_CLIENTS 14
+#define NBR_OF_SLOTS 64
+#define SDRAM_BANDWIDTH 100000000 /* Some kind of expected value */
+#define INTMEM_BANDWIDTH 400000000
+#define NBR_OF_REGIONS 2
+
+static struct crisv32_watch_entry watches[NUMBER_OF_BP] =
+{
+  {regi_marb_bp0},
+  {regi_marb_bp1},
+  {regi_marb_bp2},
+  {regi_marb_bp3}
+};
+
+static int requested_slots[NBR_OF_REGIONS][NBR_OF_CLIENTS];
+static int active_clients[NBR_OF_REGIONS][NBR_OF_CLIENTS];
+static int max_bandwidth[NBR_OF_REGIONS] = {SDRAM_BANDWIDTH, INTMEM_BANDWIDTH};
+
+DEFINE_SPINLOCK(arbiter_lock);
+
+static irqreturn_t
+crisv32_arbiter_irq(int irq, void* dev_id, struct pt_regs* regs);
+
+static void crisv32_arbiter_config(int region)
+{
+       int slot;
+       int client;
+       int interval = 0;
+       int val[NBR_OF_SLOTS];
+
+       for (slot = 0; slot < NBR_OF_SLOTS; slot++)
+           val[slot] = NBR_OF_CLIENTS + 1;
+
+       for (client = 0; client < NBR_OF_CLIENTS; client++)
+       {
+           int pos;
+           if (!requested_slots[region][client])
+              continue;
+           interval = NBR_OF_SLOTS / requested_slots[region][client];
+           pos = 0;
+           while (pos < NBR_OF_SLOTS)
+           {
+               if (val[pos] != NBR_OF_CLIENTS + 1)
+                  pos++;
+               else
+               {
+                       val[pos] = client;
+                       pos += interval;
+               }
+           }
+       }
+
+       client = 0;
+       for (slot = 0; slot < NBR_OF_SLOTS; slot++)
+       {
+               if (val[slot] == NBR_OF_CLIENTS + 1)
+               {
+                       int first = client;
+                       while(!active_clients[region][client]) {
+                               client = (client + 1) % NBR_OF_CLIENTS;
+                               if (client == first)
+                                  break;
+                       }
+                       val[slot] = client;
+                       client = (client + 1) % NBR_OF_CLIENTS;
+               }
+               if (region == EXT_REGION)
+                  REG_WR_INT_VECT(marb, regi_marb, rw_ext_slots, slot, 
val[slot]);
+               else if (region == INT_REGION)
+                  REG_WR_INT_VECT(marb, regi_marb, rw_int_slots, slot, 
val[slot]);
+       }
+}
+
+extern char _stext, _etext;
+
+static void crisv32_arbiter_init(void)
+{
+       static int initialized = 0;
+
+       if (initialized)
+               return;
+
+       initialized = 1;
+
+       /* CPU caches are active. */
+       active_clients[EXT_REGION][10] = active_clients[EXT_REGION][11] = 1;
+        crisv32_arbiter_config(EXT_REGION);
+        crisv32_arbiter_config(INT_REGION);
+
+       if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, SA_INTERRUPT,
+                        "arbiter", NULL))
+               printk(KERN_ERR "Couldn't allocate arbiter IRQ\n");
+
+#ifndef CONFIG_ETRAX_KGDB
+        /* Global watch for writes to kernel text segment. */
+        crisv32_arbiter_watch(virt_to_phys(&_stext), &_etext - &_stext,
+                              arbiter_all_clients, arbiter_all_write, NULL);
+#endif
+}
+
+
+
+int crisv32_arbiter_allocate_bandwith(int client, int region,
+                                     unsigned long bandwidth)
+{
+       int i;
+       int total_assigned = 0;
+       int total_clients = 0;
+       int req;
+
+       crisv32_arbiter_init();
+
+       for (i = 0; i < NBR_OF_CLIENTS; i++)
+       {
+               total_assigned += requested_slots[region][i];
+               total_clients += active_clients[region][i];
+       }
+       req = NBR_OF_SLOTS / (max_bandwidth[region] / bandwidth);
+
+       if (total_assigned + total_clients + req + 1 > NBR_OF_SLOTS)
+          return -ENOMEM;
+
+       active_clients[region][client] = 1;
+       requested_slots[region][client] = req;
+       crisv32_arbiter_config(region);
+
+       return 0;
+}
+
+int crisv32_arbiter_watch(unsigned long start, unsigned long size,
+                          unsigned long clients, unsigned long accesses,
+                          watch_callback* cb)
+{
+       int i;
+
+       crisv32_arbiter_init();
+
+       if (start > 0x80000000) {
+               printk("Arbiter: %lX doesn't look like a physical address", 
start);
+               return -EFAULT;
+       }
+
+       spin_lock(&arbiter_lock);
+
+       for (i = 0; i < NUMBER_OF_BP; i++) {
+               if (!watches[i].used) {
+                       reg_marb_rw_intr_mask intr_mask = REG_RD(marb, 
regi_marb, rw_intr_mask);
+
+                       watches[i].used = 1;
+                       watches[i].start = start;
+                       watches[i].end = start + size;
+                       watches[i].cb = cb;
+
+                       REG_WR_INT(marb_bp, watches[i].instance, rw_first_addr, 
watches[i].start);
+                       REG_WR_INT(marb_bp, watches[i].instance, rw_last_addr, 
watches[i].end);
+                       REG_WR_INT(marb_bp, watches[i].instance, rw_op, 
accesses);
+                       REG_WR_INT(marb_bp, watches[i].instance, rw_clients, 
clients);
+
+                       if (i == 0)
+                               intr_mask.bp0 = regk_marb_yes;
+                       else if (i == 1)
+                               intr_mask.bp1 = regk_marb_yes;
+                       else if (i == 2)
+                               intr_mask.bp2 = regk_marb_yes;
+                       else if (i == 3)
+                               intr_mask.bp3 = regk_marb_yes;
+
+                       REG_WR(marb, regi_marb, rw_intr_mask, intr_mask);
+                       spin_unlock(&arbiter_lock);
+
+                       return i;
+               }
+       }
+       spin_unlock(&arbiter_lock);
+       return -ENOMEM;
+}
+
+int crisv32_arbiter_unwatch(int id)
+{
+       reg_marb_rw_intr_mask intr_mask = REG_RD(marb, regi_marb, rw_intr_mask);
+
+       crisv32_arbiter_init();
+
+       spin_lock(&arbiter_lock);
+
+       if ((id < 0) || (id >= NUMBER_OF_BP) || (!watches[id].used)) {
+               spin_unlock(&arbiter_lock);
+               return -EINVAL;
+       }
+
+       memset(&watches[id], 0, sizeof(struct crisv32_watch_entry));
+
+       if (id == 0)
+               intr_mask.bp0 = regk_marb_no;
+       else if (id == 1)
+               intr_mask.bp2 = regk_marb_no;
+       else if (id == 2)
+               intr_mask.bp2 = regk_marb_no;
+       else if (id == 3)
+               intr_mask.bp3 = regk_marb_no;
+
+       REG_WR(marb, regi_marb, rw_intr_mask, intr_mask);
+
+       spin_unlock(&arbiter_lock);
+       return 0;
+}
+
+extern void show_registers(struct pt_regs *regs);
+
+static irqreturn_t
+crisv32_arbiter_irq(int irq, void* dev_id, struct pt_regs* regs)
+{
+       reg_marb_r_masked_intr masked_intr = REG_RD(marb, regi_marb, 
r_masked_intr);
+       reg_marb_bp_r_brk_clients r_clients;
+       reg_marb_bp_r_brk_addr r_addr;
+       reg_marb_bp_r_brk_op r_op;
+       reg_marb_bp_r_brk_first_client r_first;
+       reg_marb_bp_r_brk_size r_size;
+       reg_marb_bp_rw_ack ack = {0};
+       reg_marb_rw_ack_intr ack_intr = {.bp0=1,.bp1=1,.bp2=1,.bp3=1};
+       struct crisv32_watch_entry* watch;
+
+       if (masked_intr.bp0) {
+               watch = &watches[0];
+               ack_intr.bp0 = regk_marb_yes;
+       } else if (masked_intr.bp1) {
+               watch = &watches[1];
+               ack_intr.bp1 = regk_marb_yes;
+       } else if (masked_intr.bp2) {
+               watch = &watches[2];
+               ack_intr.bp2 = regk_marb_yes;
+       } else if (masked_intr.bp3) {
+               watch = &watches[3];
+               ack_intr.bp3 = regk_marb_yes;
+       } else {
+               return IRQ_NONE;
+       }
+
+       /* Retrieve all useful information and print it. */
+       r_clients = REG_RD(marb_bp, watch->instance, r_brk_clients);
+       r_addr = REG_RD(marb_bp, watch->instance, r_brk_addr);
+       r_op = REG_RD(marb_bp, watch->instance, r_brk_op);
+       r_first = REG_RD(marb_bp, watch->instance, r_brk_first_client);
+       r_size = REG_RD(marb_bp, watch->instance, r_brk_size);
+
+       printk("Arbiter IRQ\n");
+       printk("Clients %X addr %X op %X first %X size %X\n",
+              REG_TYPE_CONV(int, reg_marb_bp_r_brk_clients, r_clients),
+              REG_TYPE_CONV(int, reg_marb_bp_r_brk_addr, r_addr),
+              REG_TYPE_CONV(int, reg_marb_bp_r_brk_op, r_op),
+              REG_TYPE_CONV(int, reg_marb_bp_r_brk_first_client, r_first),
+              REG_TYPE_CONV(int, reg_marb_bp_r_brk_size, r_size));
+
+       REG_WR(marb_bp, watch->instance, rw_ack, ack);
+       REG_WR(marb, regi_marb, rw_ack_intr, ack_intr);
+
+       printk("IRQ occured at %lX\n", regs->erp);
+
+       if (watch->cb)
+               watch->cb();
+
+
+       return IRQ_HANDLED;
+}
diff -urN linux/arch/cris/arch-v32/kernel/asm-offsets.c 
linux/arch/cris/arch-v32/kernel/asm-offsets.c
--- linux/arch/cris/arch-v32/kernel/asm-offsets.c       1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/asm-offsets.c       2005-08-01 
19:23:42.850418000 +0100     1.1
@@ -0,0 +1,49 @@
+#include <linux/sched.h>
+#include <asm/thread_info.h>
+
+/*
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed to extract
+ * and format the required data.
+ */
+
+#define DEFINE(sym, val) \
+        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+int main(void)
+{
+#define ENTRY(entry) DEFINE(PT_ ## entry, offsetof(struct pt_regs, entry))
+       ENTRY(orig_r10);
+       ENTRY(r13);
+       ENTRY(r12);
+       ENTRY(r11);
+        ENTRY(r10);
+        ENTRY(r9);
+       ENTRY(acr);
+       ENTRY(srs);
+        ENTRY(mof);
+        ENTRY(ccs);
+        ENTRY(srp);
+       BLANK();
+#undef ENTRY
+#define ENTRY(entry) DEFINE(TI_ ## entry, offsetof(struct thread_info, entry))
+        ENTRY(task);
+        ENTRY(flags);
+        ENTRY(preempt_count);
+        BLANK();
+#undef ENTRY
+#define ENTRY(entry) DEFINE(THREAD_ ## entry, offsetof(struct thread_struct, 
entry))
+       ENTRY(ksp);
+        ENTRY(usp);
+        ENTRY(ccs);
+        BLANK();
+#undef ENTRY
+#define ENTRY(entry) DEFINE(TASK_ ## entry, offsetof(struct task_struct, 
entry))
+        ENTRY(pid);
+        BLANK();
+        DEFINE(LCLONE_VM, CLONE_VM);
+        DEFINE(LCLONE_UNTRACED, CLONE_UNTRACED);
+        return 0;
+}
diff -urN linux/arch/cris/arch-v32/kernel/crisksyms.c 
linux/arch/cris/arch-v32/kernel/crisksyms.c
--- linux/arch/cris/arch-v32/kernel/crisksyms.c 1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/crisksyms.c 2005-08-01 19:23:42.872669000 
+0100     1.1
@@ -0,0 +1,24 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/intmem.h>
+#include <asm/arch/pinmux.h>
+
+/* Functions for allocating DMA channels */
+EXPORT_SYMBOL(crisv32_request_dma);
+EXPORT_SYMBOL(crisv32_free_dma);
+
+/* Functions for handling internal RAM */
+EXPORT_SYMBOL(crisv32_intmem_alloc);
+EXPORT_SYMBOL(crisv32_intmem_free);
+EXPORT_SYMBOL(crisv32_intmem_phys_to_virt);
+EXPORT_SYMBOL(crisv32_intmem_virt_to_phys);
+
+/* Functions for handling pinmux */
+EXPORT_SYMBOL(crisv32_pinmux_alloc);
+EXPORT_SYMBOL(crisv32_pinmux_dealloc);
+
+/* Functions masking/unmasking interrupts */
+EXPORT_SYMBOL(mask_irq);
+EXPORT_SYMBOL(unmask_irq);
diff -urN linux/arch/cris/arch-v32/kernel/debugport.c 
linux/arch/cris/arch-v32/kernel/debugport.c
--- linux/arch/cris/arch-v32/kernel/debugport.c 1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/debugport.c 2005-08-01 19:23:42.894414000 
+0100     1.1
@@ -0,0 +1,461 @@
+/*
+ * Copyright (C) 2003, Axis Communications AB.
+ */
+
+#include <linux/config.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/arch/hwregs/ser_defs.h>
+#include <asm/arch/hwregs/dma_defs.h>
+#include <asm/arch/pinmux.h>
+
+#include <asm/irq.h>
+#include <asm/arch/hwregs/intr_vect_defs.h>
+
+struct dbg_port
+{
+       unsigned char nbr;
+       unsigned long instance;
+       unsigned int started;
+       unsigned long baudrate;
+       unsigned char parity;
+       unsigned int bits;
+};
+
+struct dbg_port ports[] =
+{
+  {
+    0,
+    regi_ser0,
+    0,
+    115200,
+    'N',
+    8
+  },
+  {
+    1,
+    regi_ser1,
+    0,
+    115200,
+    'N',
+    8
+  },
+  {
+    2,
+    regi_ser2,
+    0,
+    115200,
+    'N',
+    8
+  },
+  {
+    3,
+    regi_ser3,
+    0,
+    115200,
+    'N',
+    8
+  }
+};
+static struct dbg_port *port =
+#if defined(CONFIG_ETRAX_DEBUG_PORT0)
+&ports[0];
+#elif defined(CONFIG_ETRAX_DEBUG_PORT1)
+&ports[1];
+#elif defined(CONFIG_ETRAX_DEBUG_PORT2)
+&ports[2];
+#elif defined(CONFIG_ETRAX_DEBUG_PORT3)
+&ports[3];
+#else
+NULL;
+#endif
+
+#ifdef CONFIG_ETRAX_KGDB
+static struct dbg_port *kgdb_port =
+#if defined(CONFIG_ETRAX_KGDB_PORT0)
+&ports[0];
+#elif defined(CONFIG_ETRAX_KGDB_PORT1)
+&ports[1];
+#elif defined(CONFIG_ETRAX_KGDB_PORT2)
+&ports[2];
+#elif defined(CONFIG_ETRAX_KGDB_PORT3)
+&ports[3];
+#else
+NULL;
+#endif
+#endif
+
+#ifdef CONFIG_ETRAXFS_SIM
+extern void print_str( const char *str );
+static char buffer[1024];
+static char msg[] = "Debug: ";
+static int buffer_pos = sizeof(msg) - 1;
+#endif
+
+extern struct tty_driver *serial_driver;
+
+static void
+start_port(struct dbg_port* p)
+{
+       if (!p)
+               return;
+
+       if (p->started)
+               return;
+       p->started = 1;
+
+       if (p->nbr == 1)
+               crisv32_pinmux_alloc_fixed(pinmux_ser1);
+       else if (p->nbr == 2)
+               crisv32_pinmux_alloc_fixed(pinmux_ser2);
+       else if (p->nbr == 3)
+               crisv32_pinmux_alloc_fixed(pinmux_ser3);
+
+       /* Set up serial port registers */
+       reg_ser_rw_tr_ctrl tr_ctrl = {0};
+       reg_ser_rw_tr_dma_en tr_dma_en = {0};
+
+       reg_ser_rw_rec_ctrl rec_ctrl = {0};
+       reg_ser_rw_tr_baud_div tr_baud_div = {0};
+       reg_ser_rw_rec_baud_div rec_baud_div = {0};
+
+       tr_ctrl.base_freq = rec_ctrl.base_freq = regk_ser_f29_493;
+       tr_dma_en.en = rec_ctrl.dma_mode = regk_ser_no;
+       tr_baud_div.div = rec_baud_div.div = 29493000 / p->baudrate / 8;
+       tr_ctrl.en = rec_ctrl.en = 1;
+
+       if (p->parity == 'O')
+       {
+               tr_ctrl.par_en = regk_ser_yes;
+               tr_ctrl.par = regk_ser_odd;
+               rec_ctrl.par_en = regk_ser_yes;
+               rec_ctrl.par = regk_ser_odd;
+       }
+       else if (p->parity == 'E')
+       {
+               tr_ctrl.par_en = regk_ser_yes;
+               tr_ctrl.par = regk_ser_even;
+               rec_ctrl.par_en = regk_ser_yes;
+               rec_ctrl.par = regk_ser_odd;
+       }
+
+       if (p->bits == 7)
+       {
+               tr_ctrl.data_bits = regk_ser_bits7;
+               rec_ctrl.data_bits = regk_ser_bits7;
+       }
+
+       REG_WR (ser, p->instance, rw_tr_baud_div, tr_baud_div);
+       REG_WR (ser, p->instance, rw_rec_baud_div, rec_baud_div);
+       REG_WR (ser, p->instance, rw_tr_dma_en, tr_dma_en);
+       REG_WR (ser, p->instance, rw_tr_ctrl, tr_ctrl);
+       REG_WR (ser, p->instance, rw_rec_ctrl, rec_ctrl);
+}
+
+/* No debug */
+#ifdef CONFIG_ETRAX_DEBUG_PORT_NULL
+
+static void
+console_write(struct console *co, const char *buf, unsigned int len)
+{
+       return;
+}
+
+/* Target debug */
+#elif !defined(CONFIG_ETRAXFS_SIM)
+
+static void
+console_write_direct(struct console *co, const char *buf, unsigned int len)
+{
+       int i;
+       reg_ser_r_stat_din stat;
+       reg_ser_rw_tr_dma_en tr_dma_en, old;
+
+       /* Switch to manual mode */
+       tr_dma_en = old = REG_RD (ser, port->instance, rw_tr_dma_en);
+       if (tr_dma_en.en == regk_ser_yes) {
+               tr_dma_en.en = regk_ser_no;
+               REG_WR(ser, port->instance, rw_tr_dma_en, tr_dma_en);
+       }
+
+       /* Send data */
+       for (i = 0; i < len; i++) {
+               /* LF -> CRLF */
+               if (buf[i] == '\n') {
+                       do {
+                               stat = REG_RD (ser, port->instance, r_stat_din);
+                       } while (!stat.tr_rdy);
+                       REG_WR_INT (ser, port->instance, rw_dout, '\r');
+               }
+               /* Wait until transmitter is ready and send.*/
+               do {
+                       stat = REG_RD (ser, port->instance, r_stat_din);
+               } while (!stat.tr_rdy);
+               REG_WR_INT (ser, port->instance, rw_dout, buf[i]);
+       }
+
+       /* Restore mode */
+       if (tr_dma_en.en != old.en)
+               REG_WR(ser, port->instance, rw_tr_dma_en, old);
+}
+
+static void
+console_write(struct console *co, const char *buf, unsigned int len)
+{
+       if (!port)
+               return;
+        console_write_direct(co, buf, len);
+}
+
+
+
+#else
+
+/* VCS debug */
+
+static void
+console_write(struct console *co, const char *buf, unsigned int len)
+{
+       char* pos;
+       pos = memchr(buf, '\n', len);
+       if (pos) {
+               int l = ++pos - buf;
+               memcpy(buffer + buffer_pos, buf, l);
+               memcpy(buffer, msg, sizeof(msg) - 1);
+               buffer[buffer_pos + l] = '\0';
+               print_str(buffer);
+               buffer_pos = sizeof(msg) - 1;
+               if (pos - buf != len) {
+                       memcpy(buffer + buffer_pos, pos, len - l);
+                       buffer_pos += len - l;
+               }
+       } else {
+               memcpy(buffer + buffer_pos, buf, len);
+               buffer_pos += len;
+       }
+}
+
+#endif
+
+int raw_printk(const char *fmt, ...)
+{
+       static char buf[1024];
+       int printed_len;
+       va_list args;
+       va_start(args, fmt);
+       printed_len = vsnprintf(buf, sizeof(buf), fmt, args);
+       va_end(args);
+       console_write(NULL, buf, strlen(buf));
+       return printed_len;
+}
+
+void
+stupid_debug(char* buf)
+{
+  console_write(NULL, buf, strlen(buf));
+}
+
+#ifdef CONFIG_ETRAX_KGDB
+/* Use polling to get a single character from the kernel debug port */
+int
+getDebugChar(void)
+{
+       reg_ser_rs_status_data stat;
+       reg_ser_rw_ack_intr ack_intr = { 0 };
+
+       do {
+               stat = REG_RD(ser, kgdb_instance, rs_status_data);
+       } while (!stat.data_avail);
+
+       /* Ack the data_avail interrupt. */
+       ack_intr.data_avail = 1;
+       REG_WR(ser, kgdb_instance, rw_ack_intr, ack_intr);
+
+       return stat.data;
+}
+
+/* Use polling to put a single character to the kernel debug port */
+void
+putDebugChar(int val)
+{
+       reg_ser_r_status_data stat;
+       do {
+               stat = REG_RD (ser, kgdb_instance, r_status_data);
+       } while (!stat.tr_ready);
+       REG_WR (ser, kgdb_instance, rw_data_out, 
REG_TYPE_CONV(reg_ser_rw_data_out, int, val));
+}
+#endif /* CONFIG_ETRAX_KGDB */
+
+static int __init
+console_setup(struct console *co, char *options)
+{
+       char* s;
+
+       if (options) {
+               port = &ports[co->index];
+               port->baudrate = 115200;
+               port->parity = 'N';
+               port->bits = 8;
+               port->baudrate = simple_strtoul(options, NULL, 10);
+               s = options;
+               while(*s >= '0' && *s <= '9')
+                       s++;
+               if (*s) port->parity = *s++;
+               if (*s) port->bits   = *s++ - '0';
+               port->started = 0;
+               start_port(port);
+       }
+       return 0;
+}
+
+/* This is a dummy serial device that throws away anything written to it.
+ * This is used when no debug output is wanted.
+ */
+static struct tty_driver dummy_driver;
+
+static int dummy_open(struct tty_struct *tty, struct file * filp)
+{
+       return 0;
+}
+
+static void dummy_close(struct tty_struct *tty, struct file * filp)
+{
+}
+
+static int dummy_write(struct tty_struct * tty,
+                       const unsigned char *buf, int count)
+{
+       return count;
+}
+
+static int
+dummy_write_room(struct tty_struct *tty)
+{
+       return 8192;
+}
+
+void __init
+init_dummy_console(void)
+{
+       memset(&dummy_driver, 0, sizeof(struct tty_driver));
+       dummy_driver.driver_name = "serial";
+       dummy_driver.name = "ttyS";
+       dummy_driver.major = TTY_MAJOR;
+       dummy_driver.minor_start = 68;
+       dummy_driver.num = 1;       /* etrax100 has 4 serial ports */
+       dummy_driver.type = TTY_DRIVER_TYPE_SERIAL;
+       dummy_driver.subtype = SERIAL_TYPE_NORMAL;
+       dummy_driver.init_termios = tty_std_termios;
+       dummy_driver.init_termios.c_cflag =
+               B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 
default... */
+       dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+
+       dummy_driver.open = dummy_open;
+       dummy_driver.close = dummy_close;
+       dummy_driver.write = dummy_write;
+       dummy_driver.write_room = dummy_write_room;
+       if (tty_register_driver(&dummy_driver))
+               panic("Couldn't register dummy serial driver\n");
+}
+
+static struct tty_driver*
+crisv32_console_device(struct console* co, int *index)
+{
+       if (port)
+               *index = port->nbr;
+        return port ? serial_driver : &dummy_driver;
+}
+
+static struct console sercons = {
+       name : "ttyS",
+       write: console_write,
+       read : NULL,
+       device : crisv32_console_device,
+       unblank : NULL,
+       setup : console_setup,
+       flags : CON_PRINTBUFFER,
+       index : -1,
+       cflag : 0,
+       next : NULL
+};
+static struct console sercons0 = {
+       name : "ttyS",
+       write: console_write,
+       read : NULL,
+       device : crisv32_console_device,
+       unblank : NULL,
+       setup : console_setup,
+       flags : CON_PRINTBUFFER,
+       index : 0,
+       cflag : 0,
+       next : NULL
+};
+
+static struct console sercons1 = {
+       name : "ttyS",
+       write: console_write,
+       read : NULL,
+       device : crisv32_console_device,
+       unblank : NULL,
+       setup : console_setup,
+       flags : CON_PRINTBUFFER,
+       index : 1,
+       cflag : 0,
+       next : NULL
+};
+static struct console sercons2 = {
+       name : "ttyS",
+       write: console_write,
+       read : NULL,
+       device : crisv32_console_device,
+       unblank : NULL,
+       setup : console_setup,
+       flags : CON_PRINTBUFFER,
+       index : 2,
+       cflag : 0,
+       next : NULL
+};
+static struct console sercons3 = {
+       name : "ttyS",
+       write: console_write,
+       read : NULL,
+       device : crisv32_console_device,
+       unblank : NULL,
+       setup : console_setup,
+       flags : CON_PRINTBUFFER,
+       index : 3,
+       cflag : 0,
+       next : NULL
+};
+
+/* Register console for printk's, etc. */
+int __init
+init_etrax_debug(void)
+{
+       static int first = 1;
+
+       if (!first) {
+               unregister_console(&sercons);
+               register_console(&sercons0);
+               register_console(&sercons1);
+               register_console(&sercons2);
+               register_console(&sercons3);
+               init_dummy_console();
+               return 0;
+       }
+       first = 0;
+        register_console(&sercons);
+        start_port(port);
+
+#ifdef CONFIG_ETRAX_KGDB
+       start_port(kgdb_port);
+#endif /* CONFIG_ETRAX_KGDB */
+       return 0;
+}
+
+__initcall(init_etrax_debug);
diff -urN linux/arch/cris/arch-v32/kernel/dma.c 
linux/arch/cris/arch-v32/kernel/dma.c
--- linux/arch/cris/arch-v32/kernel/dma.c       1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/dma.c       2005-08-01 19:23:42.924987000 
+0100     1.1
@@ -0,0 +1,224 @@
+/* Wrapper for DMA channel allocator that starts clocks etc */
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <asm/dma.h>
+#include <asm/arch/hwregs/reg_map.h>
+#include <asm/arch/hwregs/reg_rdwr.h>
+#include <asm/arch/hwregs/marb_defs.h>
+#include <asm/arch/hwregs/config_defs.h>
+#include <asm/arch/hwregs/strmux_defs.h>
+#include <linux/errno.h>
+#include <asm/system.h>
+#include <asm/arch/arbiter.h>
+
+static char used_dma_channels[MAX_DMA_CHANNELS];
+static const char * used_dma_channels_users[MAX_DMA_CHANNELS];
+
+static DEFINE_SPINLOCK(dma_lock);
+
+int crisv32_request_dma(unsigned int dmanr, const char * device_id,
+                        unsigned options, unsigned int bandwidth,
+                       enum dma_owner owner)
+{
+       unsigned long flags;
+       reg_config_rw_clk_ctrl clk_ctrl;
+       reg_strmux_rw_cfg strmux_cfg;
+
+        if (crisv32_arbiter_allocate_bandwith(dmanr,
+                                              options & DMA_INT_MEM ? 
INT_REGION : EXT_REGION,
+                                              bandwidth))
+          return -ENOMEM;
+
+       spin_lock_irqsave(&dma_lock, flags);
+
+       if (used_dma_channels[dmanr]) {
+               spin_unlock_irqrestore(&dma_lock, flags);
+               if (options & DMA_VERBOSE_ON_ERROR) {
+                       printk("Failed to request DMA %i for %s, already 
allocated by %s\n", dmanr, device_id, used_dma_channels_users[dmanr]);
+               }
+               if (options & DMA_PANIC_ON_ERROR)
+                       panic("request_dma error!");
+               return -EBUSY;
+       }
+       clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl);
+       strmux_cfg = REG_RD(strmux, regi_strmux, rw_cfg);
+
+       switch(dmanr)
+       {
+       case 0:
+       case 1:
+               clk_ctrl.dma01_eth0 = 1;
+               break;
+       case 2:
+       case 3:
+               clk_ctrl.dma23 = 1;
+               break;
+       case 4:
+       case 5:
+               clk_ctrl.dma45 = 1;
+               break;
+       case 6:
+       case 7:
+               clk_ctrl.dma67 = 1;
+               break;
+       case 8:
+       case 9:
+               clk_ctrl.dma89_strcop = 1;
+               break;
+#if MAX_DMA_CHANNELS-1 != 9
+#error Check dma.c
+#endif
+       default:
+               spin_unlock_irqrestore(&dma_lock, flags);
+               if (options & DMA_VERBOSE_ON_ERROR) {
+                       printk("Failed to request DMA %i for %s, only 0-%i 
valid)\n", dmanr, device_id, MAX_DMA_CHANNELS-1);
+               }
+
+               if (options & DMA_PANIC_ON_ERROR)
+                       panic("request_dma error!");
+               return -EINVAL;
+       }
+
+       switch(owner)
+       {
+       case dma_eth0:
+               if (dmanr == 0)
+                       strmux_cfg.dma0 = regk_strmux_eth0;
+               else if (dmanr == 1)
+                       strmux_cfg.dma1 = regk_strmux_eth0;
+               else
+                       panic("Invalid DMA channel for eth0\n");
+               break;
+       case dma_eth1:
+               if (dmanr == 6)
+                       strmux_cfg.dma6 = regk_strmux_eth1;
+               else if (dmanr == 7)
+                       strmux_cfg.dma7 = regk_strmux_eth1;
+               else
+                       panic("Invalid DMA channel for eth1\n");
+               break;
+       case dma_iop0:
+               if (dmanr == 2)
+                       strmux_cfg.dma2 = regk_strmux_iop0;
+               else if (dmanr == 3)
+                       strmux_cfg.dma3 = regk_strmux_iop0;
+               else
+                       panic("Invalid DMA channel for iop0\n");
+               break;
+       case dma_iop1:
+               if (dmanr == 4)
+                       strmux_cfg.dma4 = regk_strmux_iop1;
+               else if (dmanr == 5)
+                       strmux_cfg.dma5 = regk_strmux_iop1;
+               else
+                       panic("Invalid DMA channel for iop1\n");
+               break;
+       case dma_ser0:
+               if (dmanr == 6)
+                       strmux_cfg.dma6 = regk_strmux_ser0;
+               else if (dmanr == 7)
+                       strmux_cfg.dma7 = regk_strmux_ser0;
+               else
+                       panic("Invalid DMA channel for ser0\n");
+               break;
+       case dma_ser1:
+               if (dmanr == 4)
+                       strmux_cfg.dma4 = regk_strmux_ser1;
+               else if (dmanr == 5)
+                       strmux_cfg.dma5 = regk_strmux_ser1;
+               else
+                       panic("Invalid DMA channel for ser1\n");
+               break;
+       case dma_ser2:
+               if (dmanr == 2)
+                       strmux_cfg.dma2 = regk_strmux_ser2;
+               else if (dmanr == 3)
+                       strmux_cfg.dma3 = regk_strmux_ser2;
+               else
+                       panic("Invalid DMA channel for ser2\n");
+               break;
+       case dma_ser3:
+               if (dmanr == 8)
+                       strmux_cfg.dma8 = regk_strmux_ser3;
+               else if (dmanr == 9)
+                       strmux_cfg.dma9 = regk_strmux_ser3;
+               else
+                       panic("Invalid DMA channel for ser3\n");
+               break;
+       case dma_sser0:
+               if (dmanr == 4)
+                       strmux_cfg.dma4 = regk_strmux_sser0;
+               else if (dmanr == 5)
+                       strmux_cfg.dma5 = regk_strmux_sser0;
+               else
+                       panic("Invalid DMA channel for sser0\n");
+               break;
+       case dma_sser1:
+               if (dmanr == 6)
+                       strmux_cfg.dma6 = regk_strmux_sser1;
+               else if (dmanr == 7)
+                       strmux_cfg.dma7 = regk_strmux_sser1;
+               else
+                       panic("Invalid DMA channel for sser1\n");
+               break;
+       case dma_ata:
+               if (dmanr == 2)
+                       strmux_cfg.dma2 = regk_strmux_ata;
+               else if (dmanr == 3)
+                       strmux_cfg.dma3 = regk_strmux_ata;
+               else
+                       panic("Invalid DMA channel for ata\n");
+               break;
+       case dma_strp:
+               if (dmanr == 8)
+                       strmux_cfg.dma8 = regk_strmux_strcop;
+               else if (dmanr == 9)
+                       strmux_cfg.dma9 = regk_strmux_strcop;
+               else
+                       panic("Invalid DMA channel for strp\n");
+               break;
+       case dma_ext0:
+               if (dmanr == 6)
+                       strmux_cfg.dma6 = regk_strmux_ext0;
+               else
+                       panic("Invalid DMA channel for ext0\n");
+               break;
+       case dma_ext1:
+               if (dmanr == 7)
+                       strmux_cfg.dma7 = regk_strmux_ext1;
+               else
+                       panic("Invalid DMA channel for ext1\n");
+               break;
+       case dma_ext2:
+               if (dmanr == 2)
+                       strmux_cfg.dma2 = regk_strmux_ext2;
+               else if (dmanr == 8)
+                       strmux_cfg.dma8 = regk_strmux_ext2;
+               else
+                       panic("Invalid DMA channel for ext2\n");
+               break;
+       case dma_ext3:
+               if (dmanr == 3)
+                       strmux_cfg.dma3 = regk_strmux_ext3;
+               else if (dmanr == 9)
+                       strmux_cfg.dma9 = regk_strmux_ext2;
+               else
+                       panic("Invalid DMA channel for ext2\n");
+               break;
+       }
+
+       used_dma_channels[dmanr] = 1;
+       used_dma_channels_users[dmanr] = device_id;
+       REG_WR(config, regi_config, rw_clk_ctrl, clk_ctrl);
+       REG_WR(strmux, regi_strmux, rw_cfg, strmux_cfg);
+       spin_unlock_irqrestore(&dma_lock,flags);
+       return 0;
+}
+
+void crisv32_free_dma(unsigned int dmanr)
+{
+       spin_lock(&dma_lock);
+       used_dma_channels[dmanr] = 0;
+       spin_unlock(&dma_lock);
+}
diff -urN linux/arch/cris/arch-v32/kernel/entry.S 
linux/arch/cris/arch-v32/kernel/entry.S
--- linux/arch/cris/arch-v32/kernel/entry.S     1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/entry.S     2005-08-01 19:23:42.946941000 
+0100     1.1
@@ -0,0 +1,820 @@
+/*
+ *  Copyright (C) 2000-2003 Axis Communications AB
+ *
+ *  Authors:   Bjorn Wesen (bjornw@axis.com)
+ *              Tobias Anderberg (tobiasa@axis.com), CRISv32 port.
+ *
+ * Code for the system-call and fault low-level handling routines.
+ *
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call.
+ *
+ * Stack layout in 'ret_from_system_call':
+ *     ptrace needs to have all regs on the stack.
+ *     if the order here is changed, it needs to be
+ *     updated in fork.c:copy_process, signal.c:do_signal,
+ *     ptrace.c and ptrace.h
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <linux/sys.h>
+#include <asm/unistd.h>
+#include <asm/errno.h>
+#include <asm/thread_info.h>
+#include <asm/arch/offset.h>
+
+#include <asm/arch/hwregs/asm/reg_map_asm.h>
+#include <asm/arch/hwregs/asm/intr_vect_defs_asm.h>
+
+       ;; Exported functions.
+       .globl system_call
+       .globl ret_from_intr
+       .globl ret_from_fork
+       .globl resume
+       .globl multiple_interrupt
+       .globl nmi_interrupt
+       .globl spurious_interrupt
+       .globl do_sigtrap
+       .globl gdb_handle_exception
+       .globl sys_call_table
+
+       ; Check if preemptive kernel scheduling should be done.
+#ifdef CONFIG_PREEMPT
+_resume_kernel:
+       di
+       ; Load current task struct.
+       movs.w  -8192, $r0              ; THREAD_SIZE = 8192
+       and.d   $sp, $r0
+
+       addoq   +TI_preempt_count, $r0, $acr
+       move.d  [$acr], $r10            ; Preemption disabled?
+       bne     _Rexit
+       nop
+
+_need_resched:
+       addoq   +TI_flags, $r0, $acr
+       move.d  [$acr], $r10
+       btstq   TIF_NEED_RESCHED, $r10  ; Check if need_resched is set.
+       bpl     _Rexit
+       nop
+
+       ; Do preemptive kernel scheduling.
+       jsr     preempt_schedule_irq
+       nop
+
+       ; Load new task struct.
+       movs.w  -8192, $r0              ; THREAD_SIZE = 8192.
+       and.d   $sp, $r0
+
+       ; One more time with new task.
+       ba      _need_resched
+       nop
+#else
+#define _resume_kernel _Rexit
+#endif
+
+       ; Called at exit from fork. schedule_tail must be called to drop
+       ; spinlock if CONFIG_PREEMPT.
+ret_from_fork:
+       jsr schedule_tail
+       nop
+       ba  ret_from_sys_call
+       nop
+
+ret_from_intr:
+       ;; Check for resched if preemptive kernel, or if we're going back to
+       ;; user-mode. This test matches the user_regs(regs) macro. Don't simply
+       ;; test CCS since that doesn't necessarily reflect what mode we'll
+       ;; return into.
+       addoq   +PT_ccs, $sp, $acr
+       move.d  [$acr], $r0
+       btstq   16, $r0                 ; User-mode flag.
+       bpl     _resume_kernel
+
+       ; Note that di below is in delay slot.
+
+_resume_userspace:
+       di                      ; So need_resched and sigpending don't change.
+
+       movs.w  -8192, $r0              ; THREAD_SIZE == 8192
+       and.d   $sp, $r0
+
+       addoq   +TI_flags, $r0, $acr    ; current->work
+       move.d  [$acr], $r10
+       and.d   _TIF_WORK_MASK, $r10    ; Work to be done on return?
+       bne     _work_pending
+       nop
+       ba      _Rexit
+       nop
+
+       ;; The system_call is called by a BREAK instruction, which looks pretty
+       ;; much like any other exception.
+       ;;
+       ;; System calls can't be made from interrupts but we still stack ERP
+       ;; to have a complete stack frame.
+       ;;
+       ;; In r9 we have the wanted syscall number. Arguments come in 
r10,r11,r12,
+       ;; r13,mof,srp
+       ;;
+       ;; This function looks on the _surface_ like spaghetti programming, but 
it's
+       ;; really designed so that the fast-path does not force cache-loading of
+       ;; non-used instructions. Only the non-common cases cause the outlined 
code
+       ;; to run..
+
+system_call:
+       ;; Stack-frame similar to the irq heads, which is reversed in
+       ;; ret_from_sys_call.
+       subq    12, $sp         ; Skip EXS, EDA.
+       move    $erp, [$sp]
+       subq    4, $sp
+       move    $srp, [$sp]
+       subq    4, $sp
+       move    $ccs, [$sp]
+       subq    4, $sp
+       ei                      ; Allow IRQs while handling system call
+       move    $spc, [$sp]
+       subq    4, $sp
+       move    $mof, [$sp]
+       subq    4, $sp
+       move    $srs, [$sp]
+       subq    4, $sp
+       move.d  $acr, [$sp]
+       subq    14*4, $sp       ; Make room for R0-R13.
+       movem   $r13, [$sp]     ; Push R0-R13
+       subq    4, $sp
+       move.d  $r10, [$sp]     ; Push orig_r10.
+
+; Set S-bit when kernel debugging to keep hardware breakpoints active.
+#ifdef CONFIG_ETRAX_KGDB
+       move $ccs, $r0
+       or.d (1<<9), $r0
+       move $r0, $ccs
+#endif
+
+       movs.w  -ENOSYS, $r0
+       addoq   +PT_r10, $sp, $acr
+       move.d  $r0, [$acr]
+
+       ;; Check if this process is syscall-traced.
+       movs.w  -8192, $r0      ; THREAD_SIZE == 8192
+       and.d   $sp, $r0
+
+       addoq   +TI_flags, $r0, $acr
+       move.d  [$acr], $r0
+       btstq   TIF_SYSCALL_TRACE, $r0
+       bmi     _syscall_trace_entry
+       nop
+
+_syscall_traced:
+       ;; Check for sanity in the requested syscall number.
+       cmpu.w  NR_syscalls, $r9
+       bhs     ret_from_sys_call
+       lslq    2, $r9          ;  Multiply by 4, in the delay slot.
+
+       ;; The location on the stack for the register structure is passed as a
+       ;; seventh argument. Some system calls need this.
+       move.d  $sp, $r0
+       subq    4, $sp
+       move.d  $r0, [$sp]
+
+       ;; The registers carrying parameters (R10-R13) are intact. The optional
+       ;; fifth and sixth parameters is in MOF and SRP respectivly. Put them
+       ;; back on the stack.
+       subq    4, $sp
+       move    $srp, [$sp]
+       subq    4, $sp
+       move    $mof, [$sp]
+
+       ;; Actually to the system call.
+       addo.d  +sys_call_table, $r9, $acr
+       move.d  [$acr], $acr
+       jsr     $acr
+       nop
+
+       addq    3*4, $sp                ; Pop the mof, srp and regs parameters.
+       addoq   +PT_r10, $sp, $acr
+       move.d  $r10, [$acr]            ; Save the return value.
+
+       moveq   1, $r9                  ; "Parameter" to ret_from_sys_call to
+                                       ; show it was a sys call.
+
+       ;; Fall through into ret_from_sys_call to return.
+
+ret_from_sys_call:
+       ;; R9 is a parameter:
+       ;;  >= 1 from syscall
+       ;;     0 from irq
+
+       ;; Get the current task-struct pointer.
+       movs.w  -8192, $r0      ; THREAD_SIZE == 8192
+       and.d   $sp, $r0
+
+       di              ; Make sure need_resched and sigpending don't change.
+
+       addoq   +TI_flags, $r0, $acr
+       move.d  [$acr], $r1
+       and.d   _TIF_ALLWORK_MASK, $r1
+       bne     _syscall_exit_work
+       nop
+
+_Rexit:
+       ;; This epilogue MUST match the prologues in multiple_interrupt, irq.h
+       ;; and ptregs.h.
+       addq    4, $sp          ; Skip orig_r10.
+       movem   [$sp+], $r13    ; Registers R0-R13.
+       move.d  [$sp+], $acr
+       move    [$sp], $srs
+       addq    4, $sp
+       move    [$sp+], $mof
+       move    [$sp+], $spc
+       move    [$sp+], $ccs
+       move    [$sp+], $srp
+       move    [$sp+], $erp
+       addq    8, $sp          ; Skip EXS, EDA.
+       jump    $erp
+       rfe                     ; Restore condition code stack in delay-slot.
+
+       ;; We get here after doing a syscall if extra work might need to be done
+       ;; perform syscall exit tracing if needed.
+
+_syscall_exit_work:
+       ;; R0 contains current at this point and irq's are disabled.
+
+       addoq   +TI_flags, $r0, $acr
+       move.d  [$acr], $r1
+       btstq   TIF_SYSCALL_TRACE, $r1
+       bpl     _work_pending
+       nop
+       ei
+       move.d  $r9, $r1                ; Preserve R9.
+       jsr     do_syscall_trace
+       nop
+       move.d  $r1, $r9
+       ba      _resume_userspace
+       nop
+
+_work_pending:
+       addoq   +TI_flags, $r0, $acr
+       move.d  [$acr], $r10
+       btstq   TIF_NEED_RESCHED, $r10  ; Need resched?
+       bpl     _work_notifysig         ; No, must be signal/notify.
+       nop
+
+_work_resched:
+       move.d  $r9, $r1                ; Preserve R9.
+       jsr     schedule
+       nop
+       move.d  $r1, $r9
+       di
+
+       addoq   +TI_flags, $r0, $acr
+       move.d  [$acr], $r1
+       and.d   _TIF_WORK_MASK, $r1     ; Ignore sycall trace counter.
+       beq     _Rexit
+       nop
+       btstq   TIF_NEED_RESCHED, $r1
+       bmi     _work_resched           ; current->work.need_resched.
+       nop
+
+_work_notifysig:
+       ;; Deal with pending signals and notify-resume requests.
+
+       addoq   +TI_flags, $r0, $acr
+       move.d  [$acr], $r13            ; The thread_info_flags parameter.
+       move.d  $r9, $r10               ; do_notify_resume syscall/irq param.
+       moveq   0, $r11                 ; oldset param - 0 in this case.
+       move.d  $sp, $r12               ; The regs param.
+       jsr     do_notify_resume
+       nop
+
+       ba _Rexit
+       nop
+
+       ;; We get here as a sidetrack when we've entered a syscall with the
+       ;; trace-bit set. We need to call do_syscall_trace and then continue
+       ;; with the call.
+
+_syscall_trace_entry:
+       ;; PT_r10 in the frame contains -ENOSYS as required, at this point.
+
+       jsr     do_syscall_trace
+       nop
+
+       ;; Now re-enter the syscall code to do the syscall itself. We need to
+       ;; restore R9 here to contain the wanted syscall, and the other
+       ;; parameter-bearing registers.
+       addoq   +PT_r9, $sp, $acr
+       move.d  [$acr], $r9
+       addoq   +PT_orig_r10, $sp, $acr
+       move.d  [$acr], $r10            ; PT_r10 is already -ENOSYS.
+       addoq   +PT_r11, $sp, $acr
+       move.d  [$acr], $r11
+       addoq   +PT_r12, $sp, $acr
+       move.d  [$acr], $r12
+       addoq   +PT_r13, $sp, $acr
+       move.d  [$acr], $r13
+       addoq   +PT_mof, $sp, $acr
+       move    [$acr], $mof
+       addoq   +PT_srp, $sp, $acr
+       move    [$acr], $srp
+
+       ba      _syscall_traced
+       nop
+
+       ;; Resume performs the actual task-switching, by switching stack
+       ;; pointers. Input arguments are:
+       ;;
+       ;; R10 = prev
+       ;; R11 = next
+       ;; R12 = thread offset in task struct.
+       ;;
+       ;; Returns old current in R10.
+
+resume:
+       subq    4, $sp
+       move    $srp, [$sp]             ; Keep old/new PC on the stack.
+       add.d   $r12, $r10              ; R10 = current tasks tss.
+       addoq   +THREAD_ccs, $r10, $acr
+       move    $ccs, [$acr]            ; Save IRQ enable state.
+       di
+
+       addoq   +THREAD_usp, $r10, $acr
+       move    $usp, [$acr]            ; Save user-mode stackpointer.
+
+       ;; See copy_thread for the reason why register R9 is saved.
+       subq    10*4, $sp
+       movem   $r9, [$sp]              ; Save non-scratch registers and R9.
+
+       addoq   +THREAD_ksp, $r10, $acr
+       move.d  $sp, [$acr]             ; Save kernel SP for old task.
+
+       move.d  $sp, $r10               ; Return last running task in R10.
+       and.d   -8192, $r10             ; Get thread_info from stackpointer.
+       addoq   +TI_task, $r10, $acr
+       move.d  [$acr], $r10            ; Get task.
+       add.d   $r12, $r11              ; Find the new tasks tss.
+       addoq   +THREAD_ksp, $r11, $acr
+       move.d  [$acr], $sp             ; Switch to new stackframe.
+       movem   [$sp+], $r9             ; Restore non-scratch registers and R9.
+
+       addoq   +THREAD_usp, $r11, $acr
+       move    [$acr], $usp            ; Restore user-mode stackpointer.
+
+       addoq   +THREAD_ccs, $r11, $acr
+       move    [$acr], $ccs            ; Restore IRQ enable status.
+       move.d  [$sp+], $acr
+       jump    $acr                    ; Restore PC.
+       nop
+
+nmi_interrupt:
+
+;; If we receive a watchdog interrupt while it is not expected, then set
+;; up a canonical frame and dump register contents before dying.
+
+       ;; This prologue MUST match the one in irq.h and the struct in ptregs.h!
+       subq    12, $sp         ;  Skip EXS, EDA.
+       move    $nrp, [$sp]
+       subq    4, $sp
+       move    $srp, [$sp]
+       subq    4, $sp
+       move    $ccs, [$sp]
+       subq    4, $sp
+       move    $spc, [$sp]
+       subq    4, $sp
+       move    $mof, [$sp]
+       subq    4, $sp
+       move    $srs, [$sp]
+       subq    4, $sp
+       move.d  $acr, [$sp]
+       subq    14*4, $sp               ; Make room for R0-R13.
+       movem   $r13, [$sp]             ; Push R0-R13.
+       subq    4, $sp
+       move.d  $r10, [$sp]             ; Push orig_r10.
+       move.d  REG_ADDR(intr_vect, regi_irq, r_nmi), $r0
+       move.d  [$r0], $r0
+       btstq   REG_BIT(intr_vect, r_nmi, watchdog), $r0
+       bpl     1f
+       nop
+       jsr     handle_watchdog_bite    ; In time.c.
+        move.d $sp, $r10               ; Pointer to registers
+1:     btstq   REG_BIT(intr_vect, r_nmi, ext), $r0
+       bpl     1f
+       nop
+       jsr     handle_nmi
+       move.d  $sp, $r10               ; Pointer to registers
+1:     addq    4, $sp                  ; Skip orig_r10
+       movem   [$sp+], $r13
+       move.d  [$sp+], $acr
+       move    [$sp], $srs
+       addq    4, $sp
+       move    [$sp+], $mof
+       move    [$sp+], $spc
+       move    [$sp+], $ccs
+       move    [$sp+], $srp
+       move    [$sp+], $nrp
+       addq    8, $sp                  ; Skip EXS, EDA.
+       jump    $nrp
+       rfn
+
+       .comm   cause_of_death, 4       ;; Don't declare this anywhere.
+
+spurious_interrupt:
+       di
+       jump hard_reset_now
+       nop
+
+       ;; This handles the case when multiple interrupts arrive at the same
+       ;; time. Jump to the first set interrupt bit in a priotiry fashion. The
+       ;; hardware will call the unserved interrupts after the handler
+       ;; finishes.
+multiple_interrupt:
+       ;; This prologue MUST match the one in irq.h and the struct in ptregs.h!
+       subq    12, $sp         ; Skip EXS, EDA.
+       move    $erp, [$sp]
+       subq    4, $sp
+       move    $srp, [$sp]
+       subq    4, $sp
+       move    $ccs, [$sp]
+       subq    4, $sp
+       move    $spc, [$sp]
+       subq    4, $sp
+       move    $mof, [$sp]
+       subq    4, $sp
+       move    $srs, [$sp]
+       subq    4, $sp
+       move.d  $acr, [$sp]
+       subq    14*4, $sp       ; Make room for R0-R13.
+       movem   $r13, [$sp]     ; Push R0-R13.
+       subq    4, $sp
+       move.d  $r10, [$sp]     ; Push orig_r10.
+
+; Set S-bit when kernel debugging to keep hardware breakpoints active.
+#ifdef CONFIG_ETRAX_KGDB
+       move $ccs, $r0
+       or.d (1<<9), $r0
+       move $r0, $ccs
+#endif
+
+       jsr     crisv32_do_multiple
+       move.d  $sp, $r10
+       jump    ret_from_intr
+       nop
+
+do_sigtrap:
+       ;; Sigtraps the process that executed the BREAK instruction. Creates a
+       ;; frame that Rexit expects.
+       subq    4, $sp
+       move    $eda, [$sp]
+       subq    4, $sp
+       move    $exs, [$sp]
+       subq    4, $sp
+       move    $erp, [$sp]
+       subq    4, $sp
+       move    $srp, [$sp]
+       subq    4, $sp
+       move    $ccs, [$sp]
+       subq    4, $sp
+       move    $spc, [$sp]
+       subq    4, $sp
+       move    $mof, [$sp]
+       subq    4, $sp
+       move    $srs, [$sp]
+       subq    4, $sp
+       move.d  $acr, [$sp]
+       di                              ; Need to disable irq's at this point.
+       subq    14*4, $sp               ; Make room for r0-r13.
+       movem   $r13, [$sp]             ; Push the r0-r13 registers.
+       subq    4, $sp
+       move.d  $r10, [$sp]             ; Push orig_r10.
+
+       movs.w  -8192, $r9              ; THREAD_SIZE == 8192
+       and.d   $sp, $r9
+
+       ;; thread_info as first parameter
+       move.d  $r9, $r10
+       moveq   5, $r11                 ; SIGTRAP as second argument.
+       jsr     ugdb_trap_user
+       nop
+       jump    ret_from_intr           ; Use the return routine for interrupts.
+       nop
+
+gdb_handle_exception:
+       subq    4, $sp
+       move.d  $r0, [$sp]
+#ifdef CONFIG_ETRAX_KGDB
+       move    $ccs, $r0               ; U-flag not affected by previous insns.
+       btstq   16, $r0                 ; Test the U-flag.
+       bmi     _ugdb_handle_exception  ; Go to user mode debugging.
+       nop                             ; Empty delay-slot (cannot pop R0 here).
+       ba      kgdb_handle_exception   ; Go to kernel debugging.
+       move.d  [$sp+], $r0             ; Restore R0 in delay slot.
+#endif
+
+_ugdb_handle_exception:
+       ba      do_sigtrap              ; SIGTRAP the offending process.
+       move.d  [$sp+], $r0             ; Restore R0 in delay slot.
+
+       .data
+
+       .section .rodata,"a"
+sys_call_table:
+       .long sys_restart_syscall       ; 0 - old "setup()" system call, used
+                                       ; for restarting.
+       .long sys_exit
+       .long sys_fork
+       .long sys_read
+       .long sys_write
+       .long sys_open          /* 5 */
+       .long sys_close
+       .long sys_waitpid
+       .long sys_creat
+       .long sys_link
+       .long sys_unlink        /* 10 */
+       .long sys_execve
+       .long sys_chdir
+       .long sys_time
+       .long sys_mknod
+       .long sys_chmod         /* 15 */
+       .long sys_lchown16
+       .long sys_ni_syscall    /* old break syscall holder */
+       .long sys_stat
+       .long sys_lseek
+       .long sys_getpid        /* 20 */
+       .long sys_mount
+       .long sys_oldumount
+       .long sys_setuid16
+       .long sys_getuid16
+       .long sys_stime         /* 25 */
+       .long sys_ptrace
+       .long sys_alarm
+       .long sys_fstat
+       .long sys_pause
+       .long sys_utime         /* 30 */
+       .long sys_ni_syscall    /* old stty syscall holder */
+       .long sys_ni_syscall    /* old gtty syscall holder */
+       .long sys_access
+       .long sys_nice
+       .long sys_ni_syscall    /* 35  old ftime syscall holder */
+       .long sys_sync
+       .long sys_kill
+       .long sys_rename
+       .long sys_mkdir
+       .long sys_rmdir         /* 40 */
+       .long sys_dup
+       .long sys_pipe
+       .long sys_times
+       .long sys_ni_syscall    /* old prof syscall holder */
+       .long sys_brk           /* 45 */
+       .long sys_setgid16
+       .long sys_getgid16
+       .long sys_signal
+       .long sys_geteuid16
+       .long sys_getegid16     /* 50 */
+       .long sys_acct
+       .long sys_umount        /* recycled never used phys( */
+       .long sys_ni_syscall    /* old lock syscall holder */
+       .long sys_ioctl
+       .long sys_fcntl         /* 55 */
+       .long sys_ni_syscall    /* old mpx syscall holder */
+       .long sys_setpgid
+       .long sys_ni_syscall    /* old ulimit syscall holder */
+       .long sys_ni_syscall    /* old sys_olduname holder */
+       .long sys_umask         /* 60 */
+       .long sys_chroot
+       .long sys_ustat
+       .long sys_dup2
+       .long sys_getppid
+       .long sys_getpgrp       /* 65 */
+       .long sys_setsid
+       .long sys_sigaction
+       .long sys_sgetmask
+       .long sys_ssetmask
+       .long sys_setreuid16    /* 70 */
+       .long sys_setregid16
+       .long sys_sigsuspend
+       .long sys_sigpending
+       .long sys_sethostname
+       .long sys_setrlimit     /* 75 */
+       .long sys_old_getrlimit
+       .long sys_getrusage
+       .long sys_gettimeofday
+       .long sys_settimeofday
+       .long sys_getgroups16   /* 80 */
+       .long sys_setgroups16
+       .long sys_select        /* was old_select in Linux/E100 */
+       .long sys_symlink
+       .long sys_lstat
+       .long sys_readlink      /* 85 */
+       .long sys_uselib
+       .long sys_swapon
+       .long sys_reboot
+       .long old_readdir
+       .long old_mmap          /* 90 */
+       .long sys_munmap
+       .long sys_truncate
+       .long sys_ftruncate
+       .long sys_fchmod
+       .long sys_fchown16      /* 95 */
+       .long sys_getpriority
+       .long sys_setpriority
+       .long sys_ni_syscall    /* old profil syscall holder */
+       .long sys_statfs
+       .long sys_fstatfs       /* 100 */
+       .long sys_ni_syscall    /* sys_ioperm in i386 */
+       .long sys_socketcall
+       .long sys_syslog
+       .long sys_setitimer
+       .long sys_getitimer     /* 105 */
+       .long sys_newstat
+       .long sys_newlstat
+       .long sys_newfstat
+       .long sys_ni_syscall    /* old sys_uname holder */
+       .long sys_ni_syscall    /* sys_iopl in i386 */
+       .long sys_vhangup
+       .long sys_ni_syscall    /* old "idle" system call */
+       .long sys_ni_syscall    /* vm86old in i386 */
+       .long sys_wait4
+       .long sys_swapoff       /* 115 */
+       .long sys_sysinfo
+       .long sys_ipc
+       .long sys_fsync
+       .long sys_sigreturn
+       .long sys_clone         /* 120 */
+       .long sys_setdomainname
+       .long sys_newuname
+       .long sys_ni_syscall    /* sys_modify_ldt */
+       .long sys_adjtimex
+       .long sys_mprotect      /* 125 */
+       .long sys_sigprocmask
+       .long sys_ni_syscall    /* old "create_module" */
+       .long sys_init_module
+       .long sys_delete_module
+       .long sys_ni_syscall    /* 130: old "get_kernel_syms" */
+       .long sys_quotactl
+       .long sys_getpgid
+       .long sys_fchdir
+       .long sys_bdflush
+       .long sys_sysfs         /* 135 */
+       .long sys_personality
+       .long sys_ni_syscall    /* for afs_syscall */
+       .long sys_setfsuid16
+       .long sys_setfsgid16
+       .long sys_llseek        /* 140 */
+       .long sys_getdents
+       .long sys_select
+       .long sys_flock
+       .long sys_msync
+       .long sys_readv         /* 145 */
+       .long sys_writev
+       .long sys_getsid
+       .long sys_fdatasync
+       .long sys_sysctl
+       .long sys_mlock         /* 150 */
+       .long sys_munlock
+       .long sys_mlockall
+       .long sys_munlockall
+       .long sys_sched_setparam
+       .long sys_sched_getparam        /* 155 */
+       .long sys_sched_setscheduler
+       .long sys_sched_getscheduler
+       .long sys_sched_yield
+       .long sys_sched_get_priority_max
+       .long sys_sched_get_priority_min        /* 160 */
+       .long sys_sched_rr_get_interval
+       .long sys_nanosleep
+       .long sys_mremap
+       .long sys_setresuid16
+       .long sys_getresuid16   /* 165 */
+       .long sys_ni_syscall    /* sys_vm86 */
+       .long sys_ni_syscall    /* Old sys_query_module */
+       .long sys_poll
+       .long sys_nfsservctl
+       .long sys_setresgid16   /* 170 */
+       .long sys_getresgid16
+       .long sys_prctl
+       .long sys_rt_sigreturn
+       .long sys_rt_sigaction
+       .long sys_rt_sigprocmask        /* 175 */
+       .long sys_rt_sigpending
+       .long sys_rt_sigtimedwait
+       .long sys_rt_sigqueueinfo
+       .long sys_rt_sigsuspend
+       .long sys_pread64       /* 180 */
+       .long sys_pwrite64
+       .long sys_chown16
+       .long sys_getcwd
+       .long sys_capget
+       .long sys_capset        /* 185 */
+       .long sys_sigaltstack
+       .long sys_sendfile
+       .long sys_ni_syscall    /* streams1 */
+       .long sys_ni_syscall    /* streams2 */
+       .long sys_vfork         /* 190 */
+       .long sys_getrlimit
+       .long sys_mmap2
+       .long sys_truncate64
+       .long sys_ftruncate64
+       .long sys_stat64        /* 195 */
+       .long sys_lstat64
+       .long sys_fstat64
+       .long sys_lchown
+       .long sys_getuid
+       .long sys_getgid        /* 200 */
+       .long sys_geteuid
+       .long sys_getegid
+       .long sys_setreuid
+       .long sys_setregid
+       .long sys_getgroups     /* 205 */
+       .long sys_setgroups
+       .long sys_fchown
+       .long sys_setresuid
+       .long sys_getresuid
+       .long sys_setresgid     /* 210 */
+       .long sys_getresgid
+       .long sys_chown
+       .long sys_setuid
+       .long sys_setgid
+       .long sys_setfsuid      /* 215 */
+       .long sys_setfsgid
+       .long sys_pivot_root
+       .long sys_mincore
+       .long sys_madvise
+       .long sys_getdents64    /* 220 */
+       .long sys_fcntl64
+       .long sys_ni_syscall    /* reserved for TUX */
+       .long sys_ni_syscall
+       .long sys_gettid
+       .long sys_readahead     /* 225 */
+       .long sys_setxattr
+       .long sys_lsetxattr
+       .long sys_fsetxattr
+       .long sys_getxattr
+       .long sys_lgetxattr     /* 230 */
+       .long sys_fgetxattr
+       .long sys_listxattr
+       .long sys_llistxattr
+       .long sys_flistxattr
+       .long sys_removexattr   /* 235 */
+       .long sys_lremovexattr
+       .long sys_fremovexattr
+       .long sys_tkill
+       .long sys_sendfile64
+       .long sys_futex         /* 240 */
+       .long sys_sched_setaffinity
+       .long sys_sched_getaffinity
+       .long sys_ni_syscall    /* sys_set_thread_area */
+       .long sys_ni_syscall    /* sys_get_thread_area */
+       .long sys_io_setup      /* 245 */
+       .long sys_io_destroy
+       .long sys_io_getevents
+       .long sys_io_submit
+       .long sys_io_cancel
+       .long sys_fadvise64     /* 250 */
+       .long sys_ni_syscall
+       .long sys_exit_group
+       .long sys_lookup_dcookie
+       .long sys_epoll_create
+       .long sys_epoll_ctl     /* 255 */
+       .long sys_epoll_wait
+       .long sys_remap_file_pages
+       .long sys_set_tid_address
+       .long sys_timer_create
+       .long sys_timer_settime         /* 260 */
+       .long sys_timer_gettime
+       .long sys_timer_getoverrun
+       .long sys_timer_delete
+       .long sys_clock_settime
+       .long sys_clock_gettime         /* 265 */
+       .long sys_clock_getres
+       .long sys_clock_nanosleep
+       .long sys_statfs64
+       .long sys_fstatfs64
+       .long sys_tgkill        /* 270 */
+       .long sys_utimes
+       .long sys_fadvise64_64
+       .long sys_ni_syscall    /* sys_vserver */
+       .long sys_ni_syscall    /* sys_mbind */
+       .long sys_ni_syscall    /* 275 sys_get_mempolicy */
+       .long sys_ni_syscall    /* sys_set_mempolicy */
+       .long sys_mq_open
+       .long sys_mq_unlink
+       .long sys_mq_timedsend
+       .long sys_mq_timedreceive       /* 280 */
+       .long sys_mq_notify
+       .long sys_mq_getsetattr
+       .long sys_ni_syscall            /* reserved for kexec */
+       .long sys_waitid
+
+        /*
+         * NOTE!! This doesn't have to be exact - we just have
+         * to make sure we have _enough_ of the "sys_ni_syscall"
+         * entries. Don't panic if you notice that this hasn't
+         * been shrunk every time we add a new system call.
+         */
+
+       .rept NR_syscalls - (.-sys_call_table) / 4
+               .long sys_ni_syscall
+       .endr
+
diff -urN linux/arch/cris/arch-v32/kernel/fasttimer.c 
linux/arch/cris/arch-v32/kernel/fasttimer.c
--- linux/arch/cris/arch-v32/kernel/fasttimer.c 1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/fasttimer.c 2005-08-01 19:23:42.974690000 
+0100     1.1
@@ -0,0 +1,996 @@
+/* $Id: fasttimer.c,v 1.11 2005/01/04 11:15:46 starvik Exp $
+ * linux/arch/cris/kernel/fasttimer.c
+ *
+ * Fast timers for ETRAX FS
+ * This may be useful in other OS than Linux so use 2 space indentation...
+ *
+ * $Log: fasttimer.c,v $
+ * Revision 1.11  2005/01/04 11:15:46  starvik
+ * Don't share timer IRQ.
+ *
+ * Revision 1.10  2004/12/07 09:19:38  starvik
+ * Corrected includes.
+ * Use correct interrupt macros.
+ *
+ * Revision 1.9  2004/05/14 10:18:58  starvik
+ * Export fast_timer_list
+ *
+ * Revision 1.8  2004/05/14 07:58:03  starvik
+ * Merge of changes from 2.4
+ *
+ * Revision 1.7  2003/07/10 12:06:14  starvik
+ * Return IRQ_NONE if irq wasn't handled
+ *
+ * Revision 1.6  2003/07/04 08:27:49  starvik
+ * Merge of Linux 2.5.74
+ *
+ * Revision 1.5  2003/06/05 10:16:22  johana
+ * New INTR_VECT macros.
+ *
+ * Revision 1.4  2003/06/03 08:49:45  johana
+ * Fixed typo.
+ *
+ * Revision 1.3  2003/06/02 12:51:27  johana
+ * Now compiles.
+ * Commented some include files that probably can be removed.
+ *
+ * Revision 1.2  2003/06/02 12:09:41  johana
+ * Ported to ETRAX FS using the trig interrupt instead of timer1.
+ *
+ * Revision 1.3  2002/12/12 08:26:32  starvik
+ * Don't use C-comments inside CVS comments
+ *
+ * Revision 1.2  2002/12/11 15:42:02  starvik
+ * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/
+ *
+ * Revision 1.1  2002/11/18 07:58:06  starvik
+ * Fast timers (from Linux 2.4)
+ *
+ * Revision 1.5  2002/10/15 06:21:39  starvik
+ * Added call to init_waitqueue_head
+ *
+ * Revision 1.4  2002/05/28 17:47:59  johana
+ * Added del_fast_timer()
+ *
+ * Revision 1.3  2002/05/28 16:16:07  johana
+ * Handle empty fast_timer_list
+ *
+ * Revision 1.2  2002/05/27 15:38:42  johana
+ * Made it compile without warnings on Linux 2.4.
+ * (includes, wait_queue, PROC_FS and snprintf)
+ *
+ * Revision 1.1  2002/05/27 15:32:25  johana
+ * arch/etrax100/kernel/fasttimer.c v1.8 from the elinux tree.
+ *
+ * Revision 1.8  2001/11/27 13:50:40  pkj
+ * Disable interrupts while stopping the timer and while modifying the
+ * list of active timers in timer1_handler() as it may be interrupted
+ * by other interrupts (e.g., the serial interrupt) which may add fast
+ * timers.
+ *
+ * Revision 1.7  2001/11/22 11:50:32  pkj
+ * * Only store information about the last 16 timers.
+ * * proc_fasttimer_read() now uses an allocated buffer, since it
+ *   requires more space than just a page even for only writing the
+ *   last 16 timers. The buffer is only allocated on request, so
+ *   unless /proc/fasttimer is read, it is never allocated.
+ * * Renamed fast_timer_started to fast_timers_started to match
+ *   fast_timers_added and fast_timers_expired.
+ * * Some clean-up.
+ *
+ * Revision 1.6  2000/12/13 14:02:08  johana
+ * Removed volatile for fast_timer_list
+ *
+ * Revision 1.5  2000/12/13 13:55:35  johana
+ * Added DEBUG_LOG, added som cli() and cleanup
+ *
+ * Revision 1.4  2000/12/05 13:48:50  johana
+ * Added range check when writing proc file, modified timer int handling
+ *
+ * Revision 1.3  2000/11/23 10:10:20  johana
+ * More debug/logging possibilities.
+ * Moved GET_JIFFIES_USEC() to timex.h and time.c
+ *
+ * Revision 1.2  2000/11/01 13:41:04  johana
+ * Clean up and bugfixes.
+ * Created new do_gettimeofday_fast() that gets a timeval struct
+ * with time based on jiffies and *R_TIMER0_DATA, uses a table
+ * for fast conversion of timer value to microseconds.
+ * (Much faster the standard do_gettimeofday() and we don't really
+ * wan't to use the true time - we wan't the "uptime" so timers don't screw up
+ * when we change the time.
+ * TODO: Add efficient support for continuous timers as well.
+ *
+ * Revision 1.1  2000/10/26 15:49:16  johana
+ * Added fasttimer, highresolution timers.
+ *
+ * Copyright (C) 2000,2001 2002, 2003 Axis Communications AB, Lund, Sweden
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include <asm/arch/hwregs/reg_map.h>
+#include <asm/arch/hwregs/reg_rdwr.h>
+#include <asm/arch/hwregs/timer_defs.h>
+#include <asm/fasttimer.h>
+#include <linux/proc_fs.h>
+
+/*
+ * timer0 is running at 100MHz and generating jiffies timer ticks
+ * at 100 or 1000 HZ.
+ * fasttimer gives an API that gives timers that expire "between" the jiffies
+ * giving microsecond resolution (10 ns).
+ * fasttimer uses reg_timer_rw_trig register to get interrupt when
+ * r_time reaches a certain value.
+ */
+
+
+#define DEBUG_LOG_INCLUDED
+#define FAST_TIMER_LOG
+//#define FAST_TIMER_TEST
+
+#define FAST_TIMER_SANITY_CHECKS
+
+#ifdef FAST_TIMER_SANITY_CHECKS
+#define SANITYCHECK(x) x
+static int sanity_failed = 0;
+#else
+#define SANITYCHECK(x)
+#endif
+
+#define D1(x)
+#define D2(x)
+#define DP(x)
+
+#define __INLINE__ inline
+
+static int fast_timer_running = 0;
+static int fast_timers_added = 0;
+static int fast_timers_started = 0;
+static int fast_timers_expired = 0;
+static int fast_timers_deleted = 0;
+static int fast_timer_is_init = 0;
+static int fast_timer_ints = 0;
+
+struct fast_timer *fast_timer_list = NULL;
+
+#ifdef DEBUG_LOG_INCLUDED
+#define DEBUG_LOG_MAX 128
+static const char * debug_log_string[DEBUG_LOG_MAX];
+static unsigned long debug_log_value[DEBUG_LOG_MAX];
+static int debug_log_cnt = 0;
+static int debug_log_cnt_wrapped = 0;
+
+#define DEBUG_LOG(string, value) \
+{ \
+  unsigned long log_flags; \
+  local_irq_save(log_flags); \
+  debug_log_string[debug_log_cnt] = (string); \
+  debug_log_value[debug_log_cnt] = (unsigned long)(value); \
+  if (++debug_log_cnt >= DEBUG_LOG_MAX) \
+  { \
+    debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \
+    debug_log_cnt_wrapped = 1; \
+  } \
+  local_irq_restore(log_flags); \
+}
+#else
+#define DEBUG_LOG(string, value)
+#endif
+
+
+#define NUM_TIMER_STATS 16
+#ifdef FAST_TIMER_LOG
+struct fast_timer timer_added_log[NUM_TIMER_STATS];
+struct fast_timer timer_started_log[NUM_TIMER_STATS];
+struct fast_timer timer_expired_log[NUM_TIMER_STATS];
+#endif
+
+int timer_div_settings[NUM_TIMER_STATS];
+int timer_delay_settings[NUM_TIMER_STATS];
+
+
+static void
+timer_trig_handler(void);
+
+
+
+/* Not true gettimeofday, only checks the jiffies (uptime) + useconds */
+void __INLINE__ do_gettimeofday_fast(struct timeval *tv)
+{
+  unsigned long sec = jiffies;
+  unsigned long usec = GET_JIFFIES_USEC();
+
+  usec += (sec % HZ) * (1000000 / HZ);
+  sec = sec / HZ;
+
+  if (usec > 1000000)
+  {
+    usec -= 1000000;
+    sec++;
+  }
+  tv->tv_sec = sec;
+  tv->tv_usec = usec;
+}
+
+int __INLINE__ timeval_cmp(struct timeval *t0, struct timeval *t1)
+{
+  if (t0->tv_sec < t1->tv_sec)
+  {
+    return -1;
+  }
+  else if (t0->tv_sec > t1->tv_sec)
+  {
+    return 1;
+  }
+  if (t0->tv_usec < t1->tv_usec)
+  {
+    return -1;
+  }
+  else if (t0->tv_usec > t1->tv_usec)
+  {
+    return 1;
+  }
+  return 0;
+}
+
+/* Called with ints off */
+void __INLINE__ start_timer_trig(unsigned long delay_us)
+{
+  reg_timer_rw_ack_intr ack_intr = { 0 };
+  reg_timer_rw_intr_mask intr_mask;
+  reg_timer_rw_trig trig;
+  reg_timer_rw_trig_cfg trig_cfg = { 0 };
+  reg_timer_r_time r_time;
+
+  r_time = REG_RD(timer, regi_timer, r_time);
+
+  D1(printk("start_timer_trig : %d us freq: %i div: %i\n",
+            delay_us, freq_index, div));
+  /* Clear trig irq */
+  intr_mask = REG_RD(timer, regi_timer, rw_intr_mask);
+  intr_mask.trig = 0;
+  REG_WR(timer, regi_timer, rw_intr_mask, intr_mask);
+
+  /* Set timer values */
+  /* r_time is 100MHz (10 ns resolution) */
+  trig = r_time + delay_us*(1000/10);
+
+  timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = trig;
+  timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us;
+
+  /* Ack interrupt */
+  ack_intr.trig = 1;
+  REG_WR(timer, regi_timer, rw_ack_intr, ack_intr);
+
+  /* Start timer */
+  REG_WR(timer, regi_timer, rw_trig, trig);
+  trig_cfg.tmr = regk_timer_time;
+  REG_WR(timer, regi_timer, rw_trig_cfg, trig_cfg);
+
+  /* Check if we have already passed the trig time */
+  r_time = REG_RD(timer, regi_timer, r_time);
+  if (r_time < trig) {
+    /* No, Enable trig irq */
+    intr_mask = REG_RD(timer, regi_timer, rw_intr_mask);
+    intr_mask.trig = 1;
+    REG_WR(timer, regi_timer, rw_intr_mask, intr_mask);
+    fast_timers_started++;
+    fast_timer_running = 1;
+  }
+  else
+  {
+    /* We have passed the time, disable trig point, ack intr */
+    trig_cfg.tmr = regk_timer_off;
+    REG_WR(timer, regi_timer, rw_trig_cfg, trig_cfg);
+    REG_WR(timer, regi_timer, rw_ack_intr, ack_intr);
+    /* call the int routine directly */
+    timer_trig_handler();
+  }
+
+}
+
+/* In version 1.4 this function takes 27 - 50 us */
+void start_one_shot_timer(struct fast_timer *t,
+                          fast_timer_function_type *function,
+                          unsigned long data,
+                          unsigned long delay_us,
+                          const char *name)
+{
+  unsigned long flags;
+  struct fast_timer *tmp;
+
+  D1(printk("sft %s %d us\n", name, delay_us));
+
+  local_irq_save(flags);
+
+  do_gettimeofday_fast(&t->tv_set);
+  tmp = fast_timer_list;
+
+  SANITYCHECK({ /* Check so this is not in the list already... */
+    while (tmp != NULL)
+    {
+      if (tmp == t)
+      {
+        printk("timer name: %s data: 0x%08lX already in list!\n", name, data);
+        sanity_failed++;
+        return;
+      }
+      else
+      {
+        tmp = tmp->next;
+      }
+    }
+    tmp = fast_timer_list;
+  });
+
+  t->delay_us = delay_us;
+  t->function = function;
+  t->data = data;
+  t->name = name;
+
+  t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000;
+  t->tv_expires.tv_sec  = t->tv_set.tv_sec  + delay_us / 1000000;
+  if (t->tv_expires.tv_usec > 1000000)
+  {
+    t->tv_expires.tv_usec -= 1000000;
+    t->tv_expires.tv_sec++;
+  }
+#ifdef FAST_TIMER_LOG
+  timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t;
+#endif
+  fast_timers_added++;
+
+  /* Check if this should timeout before anything else */
+  if (tmp == NULL || timeval_cmp(&t->tv_expires, &tmp->tv_expires) < 0)
+  {
+    /* Put first in list and modify the timer value */
+    t->prev = NULL;
+    t->next = fast_timer_list;
+    if (fast_timer_list)
+    {
+      fast_timer_list->prev = t;
+    }
+    fast_timer_list = t;
+#ifdef FAST_TIMER_LOG
+    timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
+#endif
+    start_timer_trig(delay_us);
+  } else {
+    /* Put in correct place in list */
+    while (tmp->next &&
+           timeval_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0)
+    {
+      tmp = tmp->next;
+    }
+    /* Insert t after tmp */
+    t->prev = tmp;
+    t->next = tmp->next;
+    if (tmp->next)
+    {
+      tmp->next->prev = t;
+    }
+    tmp->next = t;
+  }
+
+  D2(printk("start_one_shot_timer: %d us done\n", delay_us));
+
+  local_irq_restore(flags);
+} /* start_one_shot_timer */
+
+static inline int fast_timer_pending (const struct fast_timer * t)
+{
+  return (t->next != NULL) || (t->prev != NULL) || (t == fast_timer_list);
+}
+
+static inline int detach_fast_timer (struct fast_timer *t)
+{
+  struct fast_timer *next, *prev;
+  if (!fast_timer_pending(t))
+    return 0;
+  next = t->next;
+  prev = t->prev;
+  if (next)
+    next->prev = prev;
+  if (prev)
+    prev->next = next;
+  else
+    fast_timer_list = next;
+  fast_timers_deleted++;
+  return 1;
+}
+
+int del_fast_timer(struct fast_timer * t)
+{
+  unsigned long flags;
+  int ret;
+
+  local_irq_save(flags);
+  ret = detach_fast_timer(t);
+  t->next = t->prev = NULL;
+  local_irq_restore(flags);
+  return ret;
+} /* del_fast_timer */
+
+
+/* Interrupt routines or functions called in interrupt context */
+
+/* Timer interrupt handler for trig interrupts */
+
+static irqreturn_t
+timer_trig_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+  reg_timer_r_masked_intr masked_intr;
+
+  /* Check if the timer interrupt is for us (a trig int) */
+  masked_intr = REG_RD(timer, regi_timer, r_masked_intr);
+  if (!masked_intr.trig)
+    return IRQ_NONE;
+  timer_trig_handler();
+  return IRQ_HANDLED;
+}
+
+static void timer_trig_handler(void)
+{
+  reg_timer_rw_ack_intr ack_intr = { 0 };
+  reg_timer_rw_intr_mask intr_mask;
+  reg_timer_rw_trig_cfg trig_cfg = { 0 };
+  struct fast_timer *t;
+  unsigned long flags;
+
+  local_irq_save(flags);
+
+  /* Clear timer trig interrupt */
+  intr_mask = REG_RD(timer, regi_timer, rw_intr_mask);
+  intr_mask.trig = 0;
+  REG_WR(timer, regi_timer, rw_intr_mask, intr_mask);
+
+  /* First stop timer, then ack interrupt */
+  /* Stop timer */
+  trig_cfg.tmr = regk_timer_off;
+  REG_WR(timer, regi_timer, rw_trig_cfg, trig_cfg);
+
+  /* Ack interrupt */
+  ack_intr.trig = 1;
+  REG_WR(timer, regi_timer, rw_ack_intr, ack_intr);
+
+  fast_timer_running = 0;
+  fast_timer_ints++;
+
+  local_irq_restore(flags);
+
+  t = fast_timer_list;
+  while (t)
+  {
+    struct timeval tv;
+
+    /* Has it really expired? */
+    do_gettimeofday_fast(&tv);
+    D1(printk("t: %is %06ius\n", tv.tv_sec, tv.tv_usec));
+
+    if (timeval_cmp(&t->tv_expires, &tv) <= 0)
+    {
+      /* Yes it has expired */
+#ifdef FAST_TIMER_LOG
+      timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t;
+#endif
+      fast_timers_expired++;
+
+      /* Remove this timer before call, since it may reuse the timer */
+      local_irq_save(flags);
+      if (t->prev)
+      {
+        t->prev->next = t->next;
+      }
+      else
+      {
+        fast_timer_list = t->next;
+      }
+      if (t->next)
+      {
+        t->next->prev = t->prev;
+      }
+      t->prev = NULL;
+      t->next = NULL;
+      local_irq_restore(flags);
+
+      if (t->function != NULL)
+      {
+        t->function(t->data);
+      }
+      else
+      {
+        DEBUG_LOG("!trimertrig %i function==NULL!\n", fast_timer_ints);
+      }
+    }
+    else
+    {
+      /* Timer is to early, let's set it again using the normal routines */
+      D1(printk(".\n"));
+    }
+
+    local_irq_save(flags);
+    if ((t = fast_timer_list) != NULL)
+    {
+      /* Start next timer.. */
+      long us;
+      struct timeval tv;
+
+      do_gettimeofday_fast(&tv);
+      us = ((t->tv_expires.tv_sec - tv.tv_sec) * 1000000 +
+            t->tv_expires.tv_usec - tv.tv_usec);
+      if (us > 0)
+      {
+        if (!fast_timer_running)
+        {
+#ifdef FAST_TIMER_LOG
+          timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
+#endif
+          start_timer_trig(us);
+        }
+        local_irq_restore(flags);
+        break;
+      }
+      else
+      {
+        /* Timer already expired, let's handle it better late than never.
+         * The normal loop handles it
+         */
+        D1(printk("e! %d\n", us));
+      }
+    }
+    local_irq_restore(flags);
+  }
+
+  if (!t)
+  {
+    D1(printk("ttrig stop!\n"));
+  }
+}
+
+static void wake_up_func(unsigned long data)
+{
+#ifdef DECLARE_WAITQUEUE
+  wait_queue_head_t  *sleep_wait_p = (wait_queue_head_t*)data;
+#else
+  struct wait_queue **sleep_wait_p = (struct wait_queue **)data;
+#endif
+  wake_up(sleep_wait_p);
+}
+
+
+/* Useful API */
+
+void schedule_usleep(unsigned long us)
+{
+  struct fast_timer t;
+#ifdef DECLARE_WAITQUEUE
+  wait_queue_head_t sleep_wait;
+  init_waitqueue_head(&sleep_wait);
+  {
+  DECLARE_WAITQUEUE(wait, current);
+#else
+  struct wait_queue *sleep_wait = NULL;
+  struct wait_queue wait = { current, NULL };
+#endif
+
+  D1(printk("schedule_usleep(%d)\n", us));
+  add_wait_queue(&sleep_wait, &wait);
+  set_current_state(TASK_INTERRUPTIBLE);
+  start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us,
+                       "usleep");
+  schedule();
+  set_current_state(TASK_RUNNING);
+  remove_wait_queue(&sleep_wait, &wait);
+  D1(printk("done schedule_usleep(%d)\n", us));
+#ifdef DECLARE_WAITQUEUE
+  }
+#endif
+}
+
+#ifdef CONFIG_PROC_FS
+static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+                       ,int *eof, void *data_unused
+#else
+                        ,int unused
+#endif
+                               );
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+static struct proc_dir_entry *fasttimer_proc_entry;
+#else
+static struct proc_dir_entry fasttimer_proc_entry =
+{
+  0, 9, "fasttimer",
+  S_IFREG | S_IRUGO, 1, 0, 0,
+  0, NULL /* ops -- default to array */,
+  &proc_fasttimer_read /* get_info */,
+};
+#endif
+#endif /* CONFIG_PROC_FS */
+
+#ifdef CONFIG_PROC_FS
+
+/* This value is very much based on testing */
+#define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300)
+
+static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+                       ,int *eof, void *data_unused
+#else
+                        ,int unused
+#endif
+                               )
+{
+  unsigned long flags;
+  int i = 0;
+  int num_to_show;
+  struct timeval tv;
+  struct fast_timer *t, *nextt;
+  static char *bigbuf = NULL;
+  static unsigned long used;
+
+  if (!bigbuf && !(bigbuf = vmalloc(BIG_BUF_SIZE)))
+  {
+    used = 0;
+    bigbuf[0] = '\0';
+    return 0;
+  }
+
+  if (!offset || !used)
+  {
+    do_gettimeofday_fast(&tv);
+
+    used = 0;
+    used += sprintf(bigbuf + used, "Fast timers added:     %i\n",
+                    fast_timers_added);
+    used += sprintf(bigbuf + used, "Fast timers started:   %i\n",
+                    fast_timers_started);
+    used += sprintf(bigbuf + used, "Fast timer interrupts: %i\n",
+                    fast_timer_ints);
+    used += sprintf(bigbuf + used, "Fast timers expired:   %i\n",
+                    fast_timers_expired);
+    used += sprintf(bigbuf + used, "Fast timers deleted:   %i\n",
+                    fast_timers_deleted);
+    used += sprintf(bigbuf + used, "Fast timer running:    %s\n",
+                    fast_timer_running ? "yes" : "no");
+    used += sprintf(bigbuf + used, "Current time:          %lu.%06lu\n",
+                    (unsigned long)tv.tv_sec,
+                    (unsigned long)tv.tv_usec);
+#ifdef FAST_TIMER_SANITY_CHECKS
+    used += sprintf(bigbuf + used, "Sanity failed:         %i\n",
+                    sanity_failed);
+#endif
+    used += sprintf(bigbuf + used, "\n");
+
+#ifdef DEBUG_LOG_INCLUDED
+    {
+      int end_i = debug_log_cnt;
+      i = 0;
+
+      if (debug_log_cnt_wrapped)
+      {
+        i = debug_log_cnt;
+      }
+
+      while ((i != end_i || (debug_log_cnt_wrapped && !used)) &&
+             used+100 < BIG_BUF_SIZE)
+      {
+        used += sprintf(bigbuf + used, debug_log_string[i],
+                        debug_log_value[i]);
+        i = (i+1) % DEBUG_LOG_MAX;
+      }
+    }
+    used += sprintf(bigbuf + used, "\n");
+#endif
+
+    num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started:
+                   NUM_TIMER_STATS);
+    used += sprintf(bigbuf + used, "Timers started: %i\n", 
fast_timers_started);
+    for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE) ; i++)
+    {
+      int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS;
+
+#if 1 //ndef FAST_TIMER_LOG
+      used += sprintf(bigbuf + used, "div: %i delay: %i"
+                      "\n",
+                      timer_div_settings[cur],
+                      timer_delay_settings[cur]
+                      );
+#endif
+#ifdef FAST_TIMER_LOG
+      t = &timer_started_log[cur];
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+                      );
+#endif
+    }
+    used += sprintf(bigbuf + used, "\n");
+
+#ifdef FAST_TIMER_LOG
+    num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added:
+                   NUM_TIMER_STATS);
+    used += sprintf(bigbuf + used, "Timers added: %i\n", fast_timers_added);
+    for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
+    {
+      t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS];
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+                      );
+    }
+    used += sprintf(bigbuf + used, "\n");
+
+    num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired:
+                   NUM_TIMER_STATS);
+    used += sprintf(bigbuf + used, "Timers expired: %i\n", 
fast_timers_expired);
+    for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++)
+    {
+      t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS];
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+                      );
+    }
+    used += sprintf(bigbuf + used, "\n");
+#endif
+
+    used += sprintf(bigbuf + used, "Active timers:\n");
+    local_irq_save(flags);
+    local_irq_save(flags);
+    t = fast_timer_list;
+    while (t != NULL && (used+100 < BIG_BUF_SIZE))
+    {
+      nextt = t->next;
+      local_irq_restore(flags);
+      used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
+                      "d: %6li us data: 0x%08lX"
+/*                      " func: 0x%08lX" */
+                      "\n",
+                      t->name,
+                      (unsigned long)t->tv_set.tv_sec,
+                      (unsigned long)t->tv_set.tv_usec,
+                      (unsigned long)t->tv_expires.tv_sec,
+                      (unsigned long)t->tv_expires.tv_usec,
+                      t->delay_us,
+                      t->data
+/*                      , t->function */
+                      );
+      local_irq_disable();
+      if (t->next != nextt)
+      {
+        printk("timer removed!\n");
+      }
+      t = nextt;
+    }
+    local_irq_restore(flags);
+  }
+
+  if (used - offset < len)
+  {
+    len = used - offset;
+  }
+
+  memcpy(buf, bigbuf + offset, len);
+  *start = buf;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+  *eof = 1;
+#endif
+
+  return len;
+}
+#endif /* PROC_FS */
+
+#ifdef FAST_TIMER_TEST
+static volatile unsigned long i = 0;
+static volatile int num_test_timeout = 0;
+static struct fast_timer tr[10];
+static int exp_num[10];
+
+static struct timeval tv_exp[100];
+
+static void test_timeout(unsigned long data)
+{
+  do_gettimeofday_fast(&tv_exp[data]);
+  exp_num[data] = num_test_timeout;
+
+  num_test_timeout++;
+}
+
+static void test_timeout1(unsigned long data)
+{
+  do_gettimeofday_fast(&tv_exp[data]);
+  exp_num[data] = num_test_timeout;
+  if (data < 7)
+  {
+    start_one_shot_timer(&tr[i], test_timeout1, i, 1000, "timeout1");
+    i++;
+  }
+  num_test_timeout++;
+}
+
+DP(
+static char buf0[2000];
+static char buf1[2000];
+static char buf2[2000];
+static char buf3[2000];
+static char buf4[2000];
+);
+
+static char buf5[6000];
+static int j_u[1000];
+
+static void fast_timer_test(void)
+{
+  int prev_num;
+  int j;
+
+  struct timeval tv, tv0, tv1, tv2;
+
+  printk("fast_timer_test() start\n");
+  do_gettimeofday_fast(&tv);
+
+  for (j = 0; j < 1000; j++)
+  {
+    j_u[j] = GET_JIFFIES_USEC();
+  }
+  for (j = 0; j < 100; j++)
+  {
+    do_gettimeofday_fast(&tv_exp[j]);
+  }
+  printk("fast_timer_test() %is %06i\n", tv.tv_sec, tv.tv_usec);
+
+  for (j = 0; j < 1000; j++)
+  {
+    printk("%i %i %i %i %i\n",j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]);
+    j += 4;
+  }
+  for (j = 0; j < 100; j++)
+  {
+    printk("%i.%i %i.%i %i.%i %i.%i %i.%i\n",
+           tv_exp[j].tv_sec,tv_exp[j].tv_usec,
+           tv_exp[j+1].tv_sec,tv_exp[j+1].tv_usec,
+           tv_exp[j+2].tv_sec,tv_exp[j+2].tv_usec,
+           tv_exp[j+3].tv_sec,tv_exp[j+3].tv_usec,
+           tv_exp[j+4].tv_sec,tv_exp[j+4].tv_usec);
+    j += 4;
+  }
+  do_gettimeofday_fast(&tv0);
+  start_one_shot_timer(&tr[i], test_timeout, i, 50000, "test0");
+  DP(proc_fasttimer_read(buf0, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout, i, 70000, "test1");
+  DP(proc_fasttimer_read(buf1, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout, i, 40000, "test2");
+  DP(proc_fasttimer_read(buf2, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout, i, 60000, "test3");
+  DP(proc_fasttimer_read(buf3, NULL, 0, 0, 0));
+  i++;
+  start_one_shot_timer(&tr[i], test_timeout1, i, 55000, "test4xx");
+  DP(proc_fasttimer_read(buf4, NULL, 0, 0, 0));
+  i++;
+  do_gettimeofday_fast(&tv1);
+
+  proc_fasttimer_read(buf5, NULL, 0, 0, 0);
+
+  prev_num = num_test_timeout;
+  while (num_test_timeout < i)
+  {
+    if (num_test_timeout != prev_num)
+    {
+      prev_num = num_test_timeout;
+    }
+  }
+  do_gettimeofday_fast(&tv2);
+  printk("Timers started    %is %06i\n", tv0.tv_sec, tv0.tv_usec);
+  printk("Timers started at %is %06i\n", tv1.tv_sec, tv1.tv_usec);
+  printk("Timers done       %is %06i\n", tv2.tv_sec, tv2.tv_usec);
+  DP(printk("buf0:\n");
+     printk(buf0);
+     printk("buf1:\n");
+     printk(buf1);
+     printk("buf2:\n");
+     printk(buf2);
+     printk("buf3:\n");
+     printk(buf3);
+     printk("buf4:\n");
+     printk(buf4);
+  );
+  printk("buf5:\n");
+  printk(buf5);
+
+  printk("timers set:\n");
+  for(j = 0; j<i; j++)
+  {
+    struct fast_timer *t = &tr[j];
+    printk("%-10s set: %6is %06ius exp: %6is %06ius "
+           "data: 0x%08X func: 0x%08X\n",
+           t->name,
+           t->tv_set.tv_sec,
+           t->tv_set.tv_usec,
+           t->tv_expires.tv_sec,
+           t->tv_expires.tv_usec,
+           t->data,
+           t->function
+           );
+
+    printk("           del: %6ius     did exp: %6is %06ius as #%i error: 
%6li\n",
+           t->delay_us,
+           tv_exp[j].tv_sec,
+           tv_exp[j].tv_usec,
+           exp_num[j],
+           (tv_exp[j].tv_sec - t->tv_expires.tv_sec)*1000000 + 
tv_exp[j].tv_usec - t->tv_expires.tv_usec);
+  }
+  proc_fasttimer_read(buf5, NULL, 0, 0, 0);
+  printk("buf5 after all done:\n");
+  printk(buf5);
+  printk("fast_timer_test() done\n");
+}
+#endif
+
+
+void fast_timer_init(void)
+{
+  /* For some reason, request_irq() hangs when called froom time_init() */
+  if (!fast_timer_is_init)
+  {
+    printk("fast_timer_init()\n");
+
+#ifdef CONFIG_PROC_FS
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+   if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 )))
+     fasttimer_proc_entry->read_proc = proc_fasttimer_read;
+#else
+    proc_register_dynamic(&proc_root, &fasttimer_proc_entry);
+#endif
+#endif /* PROC_FS */
+    if(request_irq(TIMER_INTR_VECT, timer_trig_interrupt, SA_INTERRUPT,
+                   "fast timer int", NULL))
+    {
+      printk("err: timer1 irq\n");
+    }
+    fast_timer_is_init = 1;
+#ifdef FAST_TIMER_TEST
+    printk("do test\n");
+    fast_timer_test();
+#endif
+  }
+}
diff -urN linux/arch/cris/arch-v32/kernel/head.S 
linux/arch/cris/arch-v32/kernel/head.S
--- linux/arch/cris/arch-v32/kernel/head.S      1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/head.S      2005-08-01 19:23:43.005485000 
+0100     1.1
@@ -0,0 +1,448 @@
+/*
+ * CRISv32 kernel startup code.
+ *
+ * Copyright (C) 2003, Axis Communications AB
+ */
+
+#include <linux/config.h>
+
+#define ASSEMBLER_MACROS_ONLY
+
+/*
+ * The macros found in mmu_defs_asm.h uses the ## concatenation operator, so
+ * -traditional must not be used when assembling this file.
+ */
+#include <asm/arch/hwregs/reg_rdwr.h>
+#include <asm/arch/hwregs/asm/mmu_defs_asm.h>
+#include <asm/arch/hwregs/asm/reg_map_asm.h>
+#include <asm/arch/hwregs/asm/config_defs_asm.h>
+#include <asm/arch/hwregs/asm/bif_core_defs_asm.h>
+
+#define CRAMFS_MAGIC 0x28cd3d45
+#define RAM_INIT_MAGIC 0x56902387
+#define COMMAND_LINE_MAGIC 0x87109563
+
+       ;; NOTE: R8 and R9 carry information from the decompressor (if the
+       ;; kernel was compressed). They must not be used in the code below
+       ;; until they are read!
+
+       ;; Exported symbols.
+       .global etrax_irv
+       .global romfs_start
+       .global romfs_length
+       .global romfs_in_flash
+       .global swapper_pg_dir
+       .global crisv32_nand_boot
+       .global crisv32_nand_cramfs_offset
+
+       ;; Dummy section to make it bootable with current VCS simulator
+#ifdef CONFIG_ETRAXFS_SIM
+       .section ".boot", "ax"
+       ba tstart
+       nop
+#endif
+
+       .text
+tstart:
+       ;; This is the entry point of the kernel. The CPU is currently in
+       ;; supervisor mode.
+       ;;
+       ;; 0x00000000 if flash.
+       ;; 0x40004000 if DRAM.
+       ;;
+       di
+
+       ;; Start clocks for used blocks.
+       move.d REG_ADDR(config, regi_config, rw_clk_ctrl), $r1
+       move.d [$r1], $r0
+       or.d   REG_STATE(config, rw_clk_ctrl, cpu, yes) | \
+              REG_STATE(config, rw_clk_ctrl, bif, yes) | \
+              REG_STATE(config, rw_clk_ctrl, fix_io, yes), $r0
+       move.d $r0, [$r1]
+
+       ;; Set up waitstates etc
+       move.d   REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg), $r0
+       move.d   CONFIG_ETRAX_MEM_GRP1_CONFIG, $r1
+       move.d   $r1, [$r0]
+       move.d   REG_ADDR(bif_core, regi_bif_core, rw_grp2_cfg), $r0
+       move.d   CONFIG_ETRAX_MEM_GRP2_CONFIG, $r1
+       move.d   $r1, [$r0]
+       move.d   REG_ADDR(bif_core, regi_bif_core, rw_grp3_cfg), $r0
+       move.d   CONFIG_ETRAX_MEM_GRP3_CONFIG, $r1
+       move.d   $r1, [$r0]
+       move.d   REG_ADDR(bif_core, regi_bif_core, rw_grp4_cfg), $r0
+       move.d   CONFIG_ETRAX_MEM_GRP4_CONFIG, $r1
+       move.d   $r1, [$r0]
+
+#ifdef CONFIG_ETRAXFS_SIM
+       ;; Set up minimal flash waitstates
+       move.d 0, $r10
+       move.d REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg), $r11
+       move.d $r10, [$r11]
+#endif
+
+       ;; Setup and enable the MMU. Use same configuration for both the data
+       ;; and the instruction MMU.
+       ;;
+       ;; Note; 3 cycles is needed for a bank-select to take effect. Further;
+       ;; bank 1 is the instruction MMU, bank 2 is the data MMU.
+#ifndef CONFIG_ETRAXFS_SIM
+       move.d  REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8)       \
+               | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4)     \
+               | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0
+#else
+       ;; Map the virtual DRAM to the RW eprom area at address 0.
+       ;; Also map 0xa for the hook calls,
+       move.d  REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8)       \
+               | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0)     \
+               | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb)   \
+               | REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa), $r0
+#endif
+
+       ;; Temporary map of 0x40 -> 0x40 and 0x00 -> 0x00.
+       move.d  REG_FIELD(mmu, rw_mm_kbase_lo, base_4, 4)  \
+               | REG_FIELD(mmu, rw_mm_kbase_lo, base_0, 0), $r1
+
+       ;; Enable certain page protections and setup linear mapping
+       ;; for f,e,c,b,4,0.
+#ifndef CONFIG_ETRAXFS_SIM
+       move.d  REG_STATE(mmu, rw_mm_cfg, we, on)               \
+               | REG_STATE(mmu, rw_mm_cfg, acc, on)            \
+               | REG_STATE(mmu, rw_mm_cfg, ex, on)             \
+               | REG_STATE(mmu, rw_mm_cfg, inv, on)            \
+               | REG_STATE(mmu, rw_mm_cfg, seg_f, linear)      \
+               | REG_STATE(mmu, rw_mm_cfg, seg_e, linear)      \
+               | REG_STATE(mmu, rw_mm_cfg, seg_d, page)        \
+               | REG_STATE(mmu, rw_mm_cfg, seg_c, linear)      \
+               | REG_STATE(mmu, rw_mm_cfg, seg_b, linear)      \
+               | REG_STATE(mmu, rw_mm_cfg, seg_a, page)        \
+               | REG_STATE(mmu, rw_mm_cfg, seg_9, page)        \
+               | REG_STATE(mmu, rw_mm_cfg, seg_8, page)        \
+               | REG_STATE(mmu, rw_mm_cfg, seg_7, page)        \
+               | REG_STATE(mmu, rw_mm_cfg, seg_6, page)        \
+               | REG_STATE(mmu, rw_mm_cfg, seg_5, page)        \
+               | REG_STATE(mmu, rw_mm_cfg, seg_4, linear)      \
+               | REG_STATE(mmu, rw_mm_cfg, seg_3, page)        \
+               | REG_STATE(mmu, rw_mm_cfg, seg_2, page)        \
+               | REG_STATE(mmu, rw_mm_cfg, seg_1, page)        \
+               | REG_STATE(mmu, rw_mm_cfg, seg_0, linear), $r2
+#else
+       move.d  REG_STATE(mmu, rw_mm_cfg, we, on)               \
+               | REG_STATE(mmu, rw_mm_cfg, acc, on)            \
+               | REG_STATE(mmu, rw_mm_cfg, ex, on)             \
+               | REG_STATE(mmu, rw_mm_cfg, inv, on)            \
+               | REG_STATE(mmu, rw_mm_cfg, seg_f, linear)      \
+               | REG_STATE(mmu, rw_mm_cfg, seg_e, linear)      \
+               | REG_STATE(mmu, rw_mm_cfg, seg_d, page)        \
+               | REG_STATE(mmu, rw_mm_cfg, seg_c, linear)      \
+               | REG_STATE(mmu, rw_mm_cfg, seg_b, linear)      \
+               | REG_STATE(mmu, rw_mm_cfg, seg_a, linear)      \
+               | REG_STATE(mmu, rw_mm_cfg, seg_9, page)        \
+               | REG_STATE(mmu, rw_mm_cfg, seg_8, page)        \
+               | REG_STATE(mmu, rw_mm_cfg, seg_7, page)        \
+               | REG_STATE(mmu, rw_mm_cfg, seg_6, page)        \
+               | REG_STATE(mmu, rw_mm_cfg, seg_5, page)        \
+               | REG_STATE(mmu, rw_mm_cfg, seg_4, linear)      \
+               | REG_STATE(mmu, rw_mm_cfg, seg_3, page)        \
+               | REG_STATE(mmu, rw_mm_cfg, seg_2, page)        \
+               | REG_STATE(mmu, rw_mm_cfg, seg_1, page)        \
+               | REG_STATE(mmu, rw_mm_cfg, seg_0, linear), $r2
+#endif
+
+       ;; Update instruction MMU.
+       move    1, $srs
+       nop
+       nop
+       nop
+       move    $r0, $s2        ; kbase_hi.
+       move    $r1, $s1        ; kbase_lo.
+       move    $r2, $s0        ; mm_cfg, virtual memory configuration.
+
+       ;; Update data MMU.
+       move    2, $srs
+       nop
+       nop
+       nop
+       move    $r0, $s2        ; kbase_hi.
+       move    $r1, $s1        ; kbase_lo
+       move    $r2, $s0        ; mm_cfg, virtual memory configuration.
+
+       ;; Enable data and instruction MMU.
+       move    0, $srs
+       moveq   0xf, $r0        ;  IMMU, DMMU, DCache, Icache on
+       nop
+       nop
+       nop
+       move    $r0, $s0
+       nop
+       nop
+       nop
+
+#ifdef CONFIG_SMP
+       ;; Read CPU ID
+       move    0, $srs
+       nop
+       nop
+       nop
+       move    $s10, $r0
+       cmpq    0, $r0
+       beq     master_cpu
+       nop
+slave_cpu:
+       ; A slave waits for cpu_now_booting to be equal to CPU ID.
+       move.d  cpu_now_booting, $r1
+slave_wait:
+       cmp.d   [$r1], $r0
+       bne     slave_wait
+       nop
+       ; Time to boot-up. Get stack location provided by master CPU.
+       move.d  smp_init_current_idle_thread, $r1
+       move.d  [$r1], $sp
+       add.d   8192, $sp
+       move.d  ebp_start, $r0  ; Defined in linker-script.
+       move    $r0, $ebp
+       jsr     smp_callin
+       nop
+master_cpu:
+#endif
+#ifndef CONFIG_ETRAXFS_SIM
+       ;; Check if starting from DRAM or flash.
+       lapcq   ., $r0
+       and.d   0x7fffffff, $r0 ; Mask off the non-cache bit.
+       cmp.d   0x10000, $r0    ; Arbitrary, something above this code.
+       blo     _inflash0
+       nop
+#endif
+
+       jump    _inram          ; Jump to cached RAM.
+       nop
+
+       ;; Jumpgate.
+_inflash0:
+       jump _inflash
+       nop
+
+       ;; Put the following in a section so that storage for it can be
+       ;; reclaimed after init is finished.
+       .section ".init.text", "ax"
+
+_inflash:
+
+       ;; Initialize DRAM.
+       cmp.d   RAM_INIT_MAGIC, $r8 ; Already initialized?
+       beq     _dram_initialized
+       nop
+
+#include "../lib/dram_init.S"
+
+_dram_initialized:
+       ;; Copy the text and data section to DRAM. This depends on that the
+       ;; variables used below are correctly set up by the linker script.
+       ;; The calculated value stored in R4 is used below.
+       moveq   0, $r0          ; Source.
+       move.d  text_start, $r1 ; Destination.
+       move.d  __vmlinux_end, $r2
+       move.d  $r2, $r4
+       sub.d   $r1, $r4
+1:     move.w  [$r0+], $r3
+       move.w  $r3, [$r1+]
+       cmp.d   $r2, $r1
+       blo     1b
+       nop
+
+       ;; Keep CRAMFS in flash.
+       moveq   0, $r0
+       move.d  romfs_length, $r1
+       move.d  $r0, [$r1]
+       move.d  [$r4], $r0      ; cramfs_super.magic
+       cmp.d   CRAMFS_MAGIC, $r0
+       bne 1f
+       nop
+
+       addoq   +4, $r4, $acr
+       move.d  [$acr], $r0
+       move.d  romfs_length, $r1
+       move.d  $r0, [$r1]
+       add.d   0xf0000000, $r4 ; Add cached flash start in virtual memory.
+       move.d  romfs_start, $r1
+       move.d  $r4, [$r1]
+1:     moveq   1, $r0
+       move.d  romfs_in_flash, $r1
+       move.d  $r0, [$r1]
+
+       jump    _start_it       ; Jump to cached code.
+       nop
+
+_inram:
+       ;; Check if booting from NAND flash (in that case we just remember the 
offset
+       ;; into the flash where cramfs should be).
+       move.d  REG_ADDR(config, regi_config, r_bootsel), $r0
+       move.d  [$r0], $r0
+       and.d   REG_MASK(config, r_bootsel, boot_mode), $r0
+       cmp.d   REG_STATE(config, r_bootsel, boot_mode, nand), $r0
+       bne     move_cramfs
+       moveq   1,$r0
+       move.d  crisv32_nand_boot, $r1
+       move.d  $r0, [$r1]
+       move.d  crisv32_nand_cramfs_offset, $r1
+       move.d  $r9, [$r1]
+       moveq   1, $r0
+       move.d  romfs_in_flash, $r1
+       move.d  $r0, [$r1]
+       jump    _start_it
+       nop
+
+move_cramfs:
+       ;; Move the cramfs after BSS.
+       moveq   0, $r0
+       move.d  romfs_length, $r1
+       move.d  $r0, [$r1]
+
+#ifndef CONFIG_ETRAXFS_SIM
+       ;; The kernel could have been unpacked to DRAM by the loader, but
+       ;; the cramfs image could still be inte the flash immediately
+       ;; following the compressed kernel image. The loaded passes the address
+       ;; of the bute succeeding the last compressed byte in the flash in
+       ;; register R9 when starting the kernel.
+       cmp.d   0x0ffffff8, $r9
+       bhs     _no_romfs_in_flash ; R9 points outside the flash area.
+       nop
+#else
+       ba _no_romfs_in_flash
+       nop
+#endif
+       move.d  [$r9], $r0      ; cramfs_super.magic
+       cmp.d   CRAMFS_MAGIC, $r0
+       bne     _no_romfs_in_flash
+       nop
+
+       addoq   +4, $r9, $acr
+       move.d  [$acr], $r0
+       move.d  romfs_length, $r1
+       move.d  $r0, [$r1]
+       add.d   0xf0000000, $r9 ; Add cached flash start in virtual memory.
+       move.d  romfs_start, $r1
+       move.d  $r9, [$r1]
+       moveq   1, $r0
+       move.d  romfs_in_flash, $r1
+       move.d  $r0, [$r1]
+
+       jump    _start_it       ; Jump to cached code.
+       nop
+
+_no_romfs_in_flash:
+       ;; Look for cramfs.
+#ifndef CONFIG_ETRAXFS_SIM
+       move.d  __vmlinux_end, $r0
+#else
+       move.d  __end, $r0
+#endif
+       move.d  [$r0], $r1
+       cmp.d   CRAMFS_MAGIC, $r1
+       bne     2f
+       nop
+
+       addoq   +4, $r0, $acr
+       move.d  [$acr], $r2
+       move.d  _end, $r1
+       move.d  romfs_start, $r3
+       move.d  $r1, [$r3]
+       move.d  romfs_length, $r3
+       move.d  $r2, [$r3]
+
+#ifndef CONFIG_ETRAXFS_SIM
+       add.d   $r2, $r0
+       add.d   $r2, $r1
+
+       lsrq    1, $r2          ; Size is in bytes, we copy words.
+       addq    1, $r2
+1:
+       move.w  [$r0], $r3
+       move.w  $r3, [$r1]
+       subq    2, $r0
+       subq    2, $r1
+       subq    1, $r2
+       bne     1b
+       nop
+#endif
+
+2:
+       moveq   0, $r0
+       move.d  romfs_in_flash, $r1
+       move.d  $r0, [$r1]
+
+       jump    _start_it       ; Jump to cached code.
+       nop
+
+_start_it:
+
+       ;; Check if kernel command line is supplied
+       cmp.d   COMMAND_LINE_MAGIC, $r10
+       bne     no_command_line
+       nop
+
+       move.d  256, $r13
+       move.d  cris_command_line, $r10
+       or.d    0x80000000, $r11 ; Make it virtual
+1:
+       move.b  [$r11+], $r12
+       move.b  $r12, [$r10+]
+       subq    1, $r13
+       bne     1b
+       nop
+
+no_command_line:
+
+       ;; The kernel stack contains a task structure for each task. This
+       ;; the initial kernel stack is in the same page as the init_task,
+       ;; but starts at the top of the page, i.e. + 8192 bytes.
+       move.d  init_thread_union + 8192, $sp
+       move.d  ebp_start, $r0  ; Defined in linker-script.
+       move    $r0, $ebp
+       move.d  etrax_irv, $r1  ; Set the exception base register and pointer.
+       move.d  $r0, [$r1]
+
+#ifndef CONFIG_ETRAXFS_SIM
+       ;; Clear the BSS region from _bss_start to _end.
+       move.d  __bss_start, $r0
+       move.d  _end, $r1
+1:     clear.d [$r0+]
+       cmp.d   $r1, $r0
+       blo 1b
+       nop
+#endif
+
+#ifdef CONFIG_ETRAXFS_SIM
+       /* Set the watchdog timeout to something big. Will be removed when */
+       /* watchdog can be disabled with command line option */
+       move.d  0x7fffffff, $r10
+       jsr     CPU_WATCHDOG_TIMEOUT
+       nop
+#endif
+
+       ; Initialize registers to increase determinism
+       move.d __bss_start, $r0
+       movem [$r0], $r13
+
+       jump    start_kernel    ; Jump to start_kernel() in init/main.c.
+       nop
+
+       .data
+etrax_irv:
+       .dword 0
+romfs_start:
+       .dword 0
+romfs_length:
+       .dword 0
+romfs_in_flash:
+       .dword 0
+crisv32_nand_boot:
+       .dword 0
+crisv32_nand_cramfs_offset:
+       .dword 0
+
+swapper_pg_dir = 0xc0002000
+
+       .section ".init.data", "aw"
+
+#include "../lib/hw_settings.S"
diff -urN linux/arch/cris/arch-v32/kernel/io.c 
linux/arch/cris/arch-v32/kernel/io.c
--- linux/arch/cris/arch-v32/kernel/io.c        1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/io.c        2005-08-01 19:23:43.029939000 
+0100     1.1
@@ -0,0 +1,154 @@
+/*
+ * Helper functions for I/O pins.
+ *
+ * Copyright (c) 2004 Axis Communications AB.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/io.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/hwregs/gio_defs.h>
+
+struct crisv32_ioport crisv32_ioports[] =
+{
+       {
+               (unsigned long*)REG_ADDR(gio, regi_gio, rw_pa_oe),
+               (unsigned long*)REG_ADDR(gio, regi_gio, rw_pa_dout),
+               (unsigned long*)REG_ADDR(gio, regi_gio, r_pa_din),
+               8
+       },
+       {
+               (unsigned long*)REG_ADDR(gio, regi_gio, rw_pb_oe),
+               (unsigned long*)REG_ADDR(gio, regi_gio, rw_pb_dout),
+               (unsigned long*)REG_ADDR(gio, regi_gio, r_pb_din),
+               18
+       },
+       {
+               (unsigned long*)REG_ADDR(gio, regi_gio, rw_pc_oe),
+               (unsigned long*)REG_ADDR(gio, regi_gio, rw_pc_dout),
+               (unsigned long*)REG_ADDR(gio, regi_gio, r_pc_din),
+               18
+       },
+       {
+               (unsigned long*)REG_ADDR(gio, regi_gio, rw_pd_oe),
+               (unsigned long*)REG_ADDR(gio, regi_gio, rw_pd_dout),
+               (unsigned long*)REG_ADDR(gio, regi_gio, r_pd_din),
+               18
+       },
+       {
+               (unsigned long*)REG_ADDR(gio, regi_gio, rw_pe_oe),
+               (unsigned long*)REG_ADDR(gio, regi_gio, rw_pe_dout),
+               (unsigned long*)REG_ADDR(gio, regi_gio, r_pe_din),
+               18
+       }
+};
+
+#define NBR_OF_PORTS sizeof(crisv32_ioports)/sizeof(struct crisv32_ioport)
+
+struct crisv32_iopin crisv32_led1_green;
+struct crisv32_iopin crisv32_led1_red;
+struct crisv32_iopin crisv32_led2_green;
+struct crisv32_iopin crisv32_led2_red;
+struct crisv32_iopin crisv32_led3_green;
+struct crisv32_iopin crisv32_led3_red;
+
+/* Dummy port used when green LED and red LED is on the same bit */
+static unsigned long io_dummy;
+static struct crisv32_ioport dummy_port =
+{
+       &io_dummy,
+       &io_dummy,
+       &io_dummy,
+       18
+};
+static struct crisv32_iopin dummy_led =
+{
+       &dummy_port,
+       0
+};
+
+static int __init crisv32_io_init(void)
+{
+       int ret = 0;
+       /* Initialize LEDs */
+       ret += crisv32_io_get_name(&crisv32_led1_green, CONFIG_ETRAX_LED1G);
+       ret += crisv32_io_get_name(&crisv32_led1_red, CONFIG_ETRAX_LED1R);
+       ret += crisv32_io_get_name(&crisv32_led2_green, CONFIG_ETRAX_LED2G);
+       ret += crisv32_io_get_name(&crisv32_led2_red, CONFIG_ETRAX_LED2R);
+       ret += crisv32_io_get_name(&crisv32_led3_green, CONFIG_ETRAX_LED3G);
+       ret += crisv32_io_get_name(&crisv32_led3_red, CONFIG_ETRAX_LED3R);
+       crisv32_io_set_dir(&crisv32_led1_green, crisv32_io_dir_out);
+       crisv32_io_set_dir(&crisv32_led1_red, crisv32_io_dir_out);
+       crisv32_io_set_dir(&crisv32_led2_green, crisv32_io_dir_out);
+       crisv32_io_set_dir(&crisv32_led2_red, crisv32_io_dir_out);
+       crisv32_io_set_dir(&crisv32_led3_green, crisv32_io_dir_out);
+       crisv32_io_set_dir(&crisv32_led3_red, crisv32_io_dir_out);
+
+       if (!strcmp(CONFIG_ETRAX_LED1G, CONFIG_ETRAX_LED1R))
+               crisv32_led1_red = dummy_led;
+       if (!strcmp(CONFIG_ETRAX_LED2G, CONFIG_ETRAX_LED2R))
+               crisv32_led2_red = dummy_led;
+
+       return ret;
+}
+
+__initcall(crisv32_io_init);
+
+int crisv32_io_get(struct crisv32_iopin* iopin,
+                   unsigned int port, unsigned int pin)
+{
+       if (port > NBR_OF_PORTS)
+               return -EINVAL;
+       if (port > crisv32_ioports[port].pin_count)
+               return -EINVAL;
+
+       iopin->bit = 1 << pin;
+       iopin->port = &crisv32_ioports[port];
+
+       if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio))
+               return -EIO;
+
+       return 0;
+}
+
+int crisv32_io_get_name(struct crisv32_iopin* iopin,
+                         char* name)
+{
+       int port;
+       int pin;
+
+       if (toupper(*name) == 'P')
+               name++;
+
+       if (toupper(*name) < 'A' || toupper(*name) > 'E')
+               return -EINVAL;
+
+       port = toupper(*name) - 'A';
+       name++;
+       pin = simple_strtoul(name, NULL, 10);
+
+       if (pin < 0 || pin > crisv32_ioports[port].pin_count)
+               return -EINVAL;
+
+       iopin->bit = 1 << pin;
+       iopin->port = &crisv32_ioports[port];
+
+       if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio))
+               return -EIO;
+
+       return 0;
+}
+
+#ifdef CONFIG_PCI
+/* PCI I/O access stuff */
+struct cris_io_operations* cris_iops = NULL;
+EXPORT_SYMBOL(cris_iops);
+#endif
+
diff -urN linux/arch/cris/arch-v32/kernel/irq.c 
linux/arch/cris/arch-v32/kernel/irq.c
--- linux/arch/cris/arch-v32/kernel/irq.c       1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/irq.c       2005-08-01 19:23:43.052459000 
+0100     1.1
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2003, Axis Communications AB.
+ */
+
+#include <asm/irq.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/profile.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/threads.h>
+#include <linux/spinlock.h>
+#include <linux/kernel_stat.h>
+#include <asm/arch/hwregs/reg_map.h>
+#include <asm/arch/hwregs/reg_rdwr.h>
+#include <asm/arch/hwregs/intr_vect.h>
+#include <asm/arch/hwregs/intr_vect_defs.h>
+
+#define CPU_FIXED -1
+
+/* IRQ masks (refer to comment for crisv32_do_multiple) */
+#define TIMER_MASK (1 << (TIMER_INTR_VECT - FIRST_IRQ))
+#ifdef CONFIG_ETRAX_KGDB
+#if defined(CONFIG_ETRAX_KGDB_PORT0)
+#define IGNOREMASK (1 << (SER0_INTR_VECT - FIRST_IRQ))
+#elif defined(CONFIG_ETRAX_KGDB_PORT1)
+#define IGNOREMASK (1 << (SER1_INTR_VECT - FIRST_IRQ))
+#elif defined(CONFIG_ETRAX_KGB_PORT2)
+#define IGNOREMASK (1 << (SER2_INTR_VECT - FIRST_IRQ))
+#elif defined(CONFIG_ETRAX_KGDB_PORT3)
+#define IGNOREMASK (1 << (SER3_INTR_VECT - FIRST_IRQ))
+#endif
+#endif
+
+DEFINE_SPINLOCK(irq_lock);
+
+struct cris_irq_allocation
+{
+  int cpu; /* The CPU to which the IRQ is currently allocated. */
+  cpumask_t mask; /* The CPUs to which the IRQ may be allocated. */
+};
+
+struct cris_irq_allocation irq_allocations[NR_IRQS] =
+  {[0 ... NR_IRQS - 1] = {0, CPU_MASK_ALL}};
+
+static unsigned long irq_regs[NR_CPUS] =
+{
+  regi_irq,
+#ifdef CONFIG_SMP
+  regi_irq2,
+#endif
+};
+
+unsigned long cpu_irq_counters[NR_CPUS];
+unsigned long irq_counters[NR_REAL_IRQS];
+
+/* From irq.c. */
+extern void weird_irq(void);
+
+/* From entry.S. */
+extern void system_call(void);
+extern void nmi_interrupt(void);
+extern void multiple_interrupt(void);
+extern void gdb_handle_exception(void);
+extern void i_mmu_refill(void);
+extern void i_mmu_invalid(void);
+extern void i_mmu_access(void);
+extern void i_mmu_execute(void);
+extern void d_mmu_refill(void);
+extern void d_mmu_invalid(void);
+extern void d_mmu_access(void);
+extern void d_mmu_write(void);
+
+/* From kgdb.c. */
+extern void kgdb_init(void);
+extern void breakpoint(void);
+
+/*
+ * Build the IRQ handler stubs using macros from irq.h. First argument is the
+ * IRQ number, the second argument is the corresponding bit in
+ * intr_rw_vect_mask found in asm/arch/hwregs/intr_vect_defs.h.
+ */
+BUILD_IRQ(0x31, (1 << 0))      /* memarb */
+BUILD_IRQ(0x32, (1 << 1))      /* gen_io */
+BUILD_IRQ(0x33, (1 << 2))      /* iop0 */
+BUILD_IRQ(0x34, (1 << 3))      /* iop1 */
+BUILD_IRQ(0x35, (1 << 4))      /* iop2 */
+BUILD_IRQ(0x36, (1 << 5))      /* iop3 */
+BUILD_IRQ(0x37, (1 << 6))      /* dma0 */
+BUILD_IRQ(0x38, (1 << 7))      /* dma1 */
+BUILD_IRQ(0x39, (1 << 8))      /* dma2 */
+BUILD_IRQ(0x3a, (1 << 9))      /* dma3 */
+BUILD_IRQ(0x3b, (1 << 10))     /* dma4 */
+BUILD_IRQ(0x3c, (1 << 11))     /* dma5 */
+BUILD_IRQ(0x3d, (1 << 12))     /* dma6 */
+BUILD_IRQ(0x3e, (1 << 13))     /* dma7 */
+BUILD_IRQ(0x3f, (1 << 14))     /* dma8 */
+BUILD_IRQ(0x40, (1 << 15))     /* dma9 */
+BUILD_IRQ(0x41, (1 << 16))     /* ata */
+BUILD_IRQ(0x42, (1 << 17))     /* sser0 */
+BUILD_IRQ(0x43, (1 << 18))     /* sser1 */
+BUILD_IRQ(0x44, (1 << 19))     /* ser0 */
+BUILD_IRQ(0x45, (1 << 20))     /* ser1 */
+BUILD_IRQ(0x46, (1 << 21))     /* ser2 */
+BUILD_IRQ(0x47, (1 << 22))     /* ser3 */
+BUILD_IRQ(0x48, (1 << 23))
+BUILD_IRQ(0x49, (1 << 24))     /* eth0 */
+BUILD_IRQ(0x4a, (1 << 25))     /* eth1 */
+BUILD_TIMER_IRQ(0x4b, (1 << 26))/* timer */
+BUILD_IRQ(0x4c, (1 << 27))     /* bif_arb */
+BUILD_IRQ(0x4d, (1 << 28))     /* bif_dma */
+BUILD_IRQ(0x4e, (1 << 29))     /* ext */
+BUILD_IRQ(0x4f, (1 << 29))     /* ipi */
+
+/* Pointers to the low-level handlers. */
+static void (*interrupt[NR_IRQS])(void) = {
+       IRQ0x31_interrupt, IRQ0x32_interrupt, IRQ0x33_interrupt,
+       IRQ0x34_interrupt, IRQ0x35_interrupt, IRQ0x36_interrupt,
+       IRQ0x37_interrupt, IRQ0x38_interrupt, IRQ0x39_interrupt,
+       IRQ0x3a_interrupt, IRQ0x3b_interrupt, IRQ0x3c_interrupt,
+       IRQ0x3d_interrupt, IRQ0x3e_interrupt, IRQ0x3f_interrupt,
+       IRQ0x40_interrupt, IRQ0x41_interrupt, IRQ0x42_interrupt,
+       IRQ0x43_interrupt, IRQ0x44_interrupt, IRQ0x45_interrupt,
+       IRQ0x46_interrupt, IRQ0x47_interrupt, IRQ0x48_interrupt,
+       IRQ0x49_interrupt, IRQ0x4a_interrupt, IRQ0x4b_interrupt,
+       IRQ0x4c_interrupt, IRQ0x4d_interrupt, IRQ0x4e_interrupt,
+       IRQ0x4f_interrupt
+};
+
+void
+block_irq(int irq, int cpu)
+{
+       int intr_mask;
+        unsigned long flags;
+
+        spin_lock_irqsave(&irq_lock, flags);
+        intr_mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask);
+
+       /* Remember; 1 let thru, 0 block. */
+       intr_mask &= ~(1 << (irq - FIRST_IRQ));
+
+       REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, intr_mask);
+        spin_unlock_irqrestore(&irq_lock, flags);
+}
+
+void
+unblock_irq(int irq, int cpu)
+{
+       int intr_mask;
+        unsigned long flags;
+
+        spin_lock_irqsave(&irq_lock, flags);
+        intr_mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask);
+
+       /* Remember; 1 let thru, 0 block. */
+       intr_mask |= (1 << (irq - FIRST_IRQ));
+
+       REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, intr_mask);
+        spin_unlock_irqrestore(&irq_lock, flags);
+}
+
+/* Find out which CPU the irq should be allocated to. */
+static int irq_cpu(int irq)
+{
+       int cpu;
+        unsigned long flags;
+
+        spin_lock_irqsave(&irq_lock, flags);
+        cpu = irq_allocations[irq - FIRST_IRQ].cpu;
+
+       /* Fixed interrupts stay on the local CPU. */
+       if (cpu == CPU_FIXED)
+        {
+               spin_unlock_irqrestore(&irq_lock, flags);
+               return smp_processor_id();
+        }
+
+
+       /* Let the interrupt stay if possible */
+       if (cpu_isset(cpu, irq_allocations[irq - FIRST_IRQ].mask))
+               goto out;
+
+       /* IRQ must be moved to another CPU. */
+       cpu = first_cpu(irq_allocations[irq - FIRST_IRQ].mask);
+       irq_allocations[irq - FIRST_IRQ].cpu = cpu;
+out:
+       spin_unlock_irqrestore(&irq_lock, flags);
+       return cpu;
+}
+
+void
+mask_irq(int irq)
+{
+       int cpu;
+
+       for (cpu = 0; cpu < NR_CPUS; cpu++)
+               block_irq(irq, cpu);
+}
+
+void
+unmask_irq(int irq)
+{
+       unblock_irq(irq, irq_cpu(irq));
+}
+
+
+static unsigned int startup_crisv32_irq(unsigned int irq)
+{
+       unmask_irq(irq);
+       return 0;
+}
+
+static void shutdown_crisv32_irq(unsigned int irq)
+{
+       mask_irq(irq);
+}
+
+static void enable_crisv32_irq(unsigned int irq)
+{
+       unmask_irq(irq);
+}
+
+static void disable_crisv32_irq(unsigned int irq)
+{
+       mask_irq(irq);
+}
+
+static void ack_crisv32_irq(unsigned int irq)
+{
+}
+
+static void end_crisv32_irq(unsigned int irq)
+{
+}
+
+void set_affinity_crisv32_irq(unsigned int irq, cpumask_t dest)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&irq_lock, flags);
+       irq_allocations[irq - FIRST_IRQ].mask = dest;
+       spin_unlock_irqrestore(&irq_lock, flags);
+}
+
+static struct hw_interrupt_type crisv32_irq_type = {
+       .typename =    "CRISv32",
+       .startup =     startup_crisv32_irq,
+       .shutdown =    shutdown_crisv32_irq,
+       .enable =      enable_crisv32_irq,
+       .disable =     disable_crisv32_irq,
+       .ack =         ack_crisv32_irq,
+       .end =         end_crisv32_irq,
+       .set_affinity = set_affinity_crisv32_irq
+};
+
+void
+set_exception_vector(int n, irqvectptr addr)
+{
+       etrax_irv->v[n] = (irqvectptr) addr;
+}
+
+extern void do_IRQ(int irq, struct pt_regs * regs);
+
+void
+crisv32_do_IRQ(int irq, int block, struct pt_regs* regs)
+{
+       /* Interrupts that may not be moved to another CPU and
+         * are SA_INTERRUPT may skip blocking. This is currently
+         * only valid for the timer IRQ and the IPI and is used
+         * for the timer interrupt to avoid watchdog starvation.
+         */
+       if (!block) {
+               do_IRQ(irq, regs);
+               return;
+       }
+
+       block_irq(irq, smp_processor_id());
+       do_IRQ(irq, regs);
+
+       unblock_irq(irq, irq_cpu(irq));
+}
+
+/* If multiple interrupts occur simultaneously we get a multiple
+ * interrupt from the CPU and software has to sort out which
+ * interrupts that happened. There are two special cases here:
+ *
+ * 1. Timer interrupts may never be blocked because of the
+ *    watchdog (refer to comment in include/asr/arch/irq.h)
+ * 2. GDB serial port IRQs are unhandled here and will be handled
+ *    as a single IRQ when it strikes again because the GDB
+ *    stubb wants to save the registers in its own fashion.
+ */
+void
+crisv32_do_multiple(struct pt_regs* regs)
+{
+       int cpu;
+       int mask;
+       int masked;
+       int bit;
+
+       cpu = smp_processor_id();
+
+       /* An extra irq_enter here to prevent softIRQs to run after
+         * each do_IRQ. This will decrease the interrupt latency.
+        */
+       irq_enter();
+
+       /* Get which IRQs that happend. */
+       masked = REG_RD_INT(intr_vect, irq_regs[cpu], r_masked_vect);
+
+       /* Calculate new IRQ mask with these IRQs disabled. */
+       mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask);
+       mask &= ~masked;
+
+       /* Timer IRQ is never masked */
+       if (masked & TIMER_MASK)
+               mask |= TIMER_MASK;
+
+       /* Block all the IRQs */
+       REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, mask);
+
+       /* Check for timer IRQ and handle it special. */
+       if (masked & TIMER_MASK) {
+               masked &= ~TIMER_MASK;
+               do_IRQ(TIMER_INTR_VECT, regs);
+       }
+
+#ifdef IGNORE_MASK
+       /* Remove IRQs that can't be handled as multiple. */
+       masked &= ~IGNORE_MASK;
+#endif
+
+       /* Handle the rest of the IRQs. */
+       for (bit = 0; bit < 32; bit++)
+       {
+               if (masked & (1 << bit))
+                       do_IRQ(bit + FIRST_IRQ, regs);
+       }
+
+       /* Unblock all the IRQs. */
+       mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask);
+       mask |= masked;
+       REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, mask);
+
+       /* This irq_exit() will trigger the soft IRQs. */
+       irq_exit();
+}
+
+/*
+ * This is called by start_kernel. It fixes the IRQ masks and setup the
+ * interrupt vector table to point to bad_interrupt pointers.
+ */
+void __init
+init_IRQ(void)
+{
+       int i;
+       int j;
+       reg_intr_vect_rw_mask vect_mask = {0};
+
+       /* Clear all interrupts masks. */
+       REG_WR(intr_vect, regi_irq, rw_mask, vect_mask);
+
+       for (i = 0; i < 256; i++)
+               etrax_irv->v[i] = weird_irq;
+
+       /* Point all IRQ's to bad handlers. */
+       for (i = FIRST_IRQ, j = 0; j < NR_IRQS; i++, j++) {
+               irq_desc[j].handler = &crisv32_irq_type;
+               set_exception_vector(i, interrupt[j]);
+       }
+
+        /* Mark Timer and IPI IRQs as CPU local */
+       irq_allocations[TIMER_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED;
+       irq_desc[TIMER_INTR_VECT].status |= IRQ_PER_CPU;
+       irq_allocations[IPI_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED;
+       irq_desc[IPI_INTR_VECT].status |= IRQ_PER_CPU;
+
+       set_exception_vector(0x00, nmi_interrupt);
+       set_exception_vector(0x30, multiple_interrupt);
+
+       /* Set up handler for various MMU bus faults. */
+       set_exception_vector(0x04, i_mmu_refill);
+       set_exception_vector(0x05, i_mmu_invalid);
+       set_exception_vector(0x06, i_mmu_access);
+       set_exception_vector(0x07, i_mmu_execute);
+       set_exception_vector(0x08, d_mmu_refill);
+       set_exception_vector(0x09, d_mmu_invalid);
+       set_exception_vector(0x0a, d_mmu_access);
+       set_exception_vector(0x0b, d_mmu_write);
+
+       /* The system-call trap is reached by "break 13". */
+       set_exception_vector(0x1d, system_call);
+
+       /* Exception handlers for debugging, both user-mode and kernel-mode. */
+
+       /* Break 8. */
+       set_exception_vector(0x18, gdb_handle_exception);
+       /* Hardware single step. */
+       set_exception_vector(0x3, gdb_handle_exception);
+       /* Hardware breakpoint. */
+       set_exception_vector(0xc, gdb_handle_exception);
+
+#ifdef CONFIG_ETRAX_KGDB
+       kgdb_init();
+       /* Everything is set up; now trap the kernel. */
+       breakpoint();
+#endif
+}
+
diff -urN linux/arch/cris/arch-v32/kernel/kgdb.c 
linux/arch/cris/arch-v32/kernel/kgdb.c
--- linux/arch/cris/arch-v32/kernel/kgdb.c      1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/kgdb.c      2005-08-01 19:23:43.068370000 
+0100     1.1
@@ -0,0 +1,1660 @@
+/*
+ *  arch/cris/arch-v32/kernel/kgdb.c
+ *
+ *  CRIS v32 version by Orjan Friberg, Axis Communications AB.
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *
+ *  Originally written by Glenn Engel, Lake Stevens Instrument Division
+ *
+ *  Contributed by HP Systems
+ *
+ *  Modified for SPARC by Stu Grossman, Cygnus Support.
+ *
+ *  Modified for Linux/MIPS (and MIPS in general) by Andreas Busse
+ *  Send complaints, suggestions etc. to <andy@waldorf-gmbh.de>
+ *
+ *  Copyright (C) 1995 Andreas Busse
+ */
+
+/* FIXME: Check the documentation. */
+
+/*
+ *  kgdb usage notes:
+ *  -----------------
+ *
+ * If you select CONFIG_ETRAX_KGDB in the configuration, the kernel will be
+ * built with different gcc flags: "-g" is added to get debug infos, and
+ * "-fomit-frame-pointer" is omitted to make debugging easier. Since the
+ * resulting kernel will be quite big (approx. > 7 MB), it will be stripped
+ * before compresion. Such a kernel will behave just as usually, except if
+ * given a "debug=<device>" command line option. (Only serial devices are
+ * allowed for <device>, i.e. no printers or the like; possible values are
+ * machine depedend and are the same as for the usual debug device, the one
+ * for logging kernel messages.) If that option is given and the device can be
+ * initialized, the kernel will connect to the remote gdb in trap_init(). The
+ * serial parameters are fixed to 8N1 and 115200 bps, for easyness of
+ * implementation.
+ *
+ * To start a debugging session, start that gdb with the debugging kernel
+ * image (the one with the symbols, vmlinux.debug) named on the command line.
+ * This file will be used by gdb to get symbol and debugging infos about the
+ * kernel. Next, select remote debug mode by
+ *    target remote <device>
+ * where <device> is the name of the serial device over which the debugged
+ * machine is connected. Maybe you have to adjust the baud rate by
+ *    set remotebaud <rate>
+ * or also other parameters with stty:
+ *    shell stty ... </dev/...
+ * If the kernel to debug has already booted, it waited for gdb and now
+ * connects, and you'll see a breakpoint being reported. If the kernel isn't
+ * running yet, start it now. The order of gdb and the kernel doesn't matter.
+ * Another thing worth knowing about in the getting-started phase is how to
+ * debug the remote protocol itself. This is activated with
+ *    set remotedebug 1
+ * gdb will then print out each packet sent or received. You'll also get some
+ * messages about the gdb stub on the console of the debugged machine.
+ *
+ * If all that works, you can use lots of the usual debugging techniques on
+ * the kernel, e.g. inspecting and changing variables/memory, setting
+ * breakpoints, single stepping and so on. It's also possible to interrupt the
+ * debugged kernel by pressing C-c in gdb. Have fun! :-)
+ *
+ * The gdb stub is entered (and thus the remote gdb gets control) in the
+ * following situations:
+ *
+ *  - If breakpoint() is called. This is just after kgdb initialization, or if
+ *    a breakpoint() call has been put somewhere into the kernel source.
+ *    (Breakpoints can of course also be set the usual way in gdb.)
+ *    In eLinux, we call breakpoint() in init/main.c after IRQ initialization.
+ *
+ *  - If there is a kernel exception, i.e. bad_super_trap() or die_if_kernel()
+ *    are entered. All the CPU exceptions are mapped to (more or less..., see
+ *    the hard_trap_info array below) appropriate signal, which are reported
+ *    to gdb. die_if_kernel() is usually called after some kind of access
+ *    error and thus is reported as SIGSEGV.
+ *
+ *  - When panic() is called. This is reported as SIGABRT.
+ *
+ *  - If C-c is received over the serial line, which is treated as
+ *    SIGINT.
+ *
+ * Of course, all these signals are just faked for gdb, since there is no
+ * signal concept as such for the kernel. It also isn't possible --obviously--
+ * to set signal handlers from inside gdb, or restart the kernel with a
+ * signal.
+ *
+ * Current limitations:
+ *
+ *  - While the kernel is stopped, interrupts are disabled for safety reasons
+ *    (i.e., variables not changing magically or the like). But this also
+ *    means that the clock isn't running anymore, and that interrupts from the
+ *    hardware may get lost/not be served in time. This can cause some device
+ *    errors...
+ *
+ *  - When single-stepping, only one instruction of the current thread is
+ *    executed, but interrupts are allowed for that time and will be serviced
+ *    if pending. Be prepared for that.
+ *
+ *  - All debugging happens in kernel virtual address space. There's no way to
+ *    access physical memory not mapped in kernel space, or to access user
+ *    space. A way to work around this is using get_user_long & Co. in gdb
+ *    expressions, but only for the current process.
+ *
+ *  - Interrupting the kernel only works if interrupts are currently allowed,
+ *    and the interrupt of the serial line isn't blocked by some other means
+ *    (IPL too high, disabled, ...)
+ *
+ *  - The gdb stub is currently not reentrant, i.e. errors that happen therein
+ *    (e.g. accessing invalid memory) may not be caught correctly. This could
+ *    be removed in future by introducing a stack of struct registers.
+ *
+ */
+
+/*
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to kgdb_init() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().
+ *
+ *    The following gdb commands are supported:
+ *
+ * command          function                               Return value
+ *
+ *    g             return the value of the CPU registers  hex data or ENN
+ *    G             set the value of the CPU registers     OK or ENN
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
+ *
+ *    c             Resume at current address              SNN   ( signal NN)
+ *    cAA..AA       Continue at address AA..AA             SNN
+ *
+ *    s             Step one instruction                   SNN
+ *    sAA..AA       Step one instruction from AA..AA       SNN
+ *
+ *    k             kill
+ *
+ *    ?             What was the last sigval ?             SNN   (signal NN)
+ *
+ *    bBB..BB      Set baud rate to BB..BB                OK or BNN, then sets
+ *                                                        baud rate
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>    :: < two hex digits computed as modulo 256 sum of 
<packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.  '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:                  Reply:
+ * $m0,10#2a               +$00010203040506070809101112131415#42
+ *
+ */
+
+
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/linkage.h>
+#include <linux/reboot.h>
+
+#include <asm/setup.h>
+#include <asm/ptrace.h>
+
+#include <asm/irq.h>
+#include <asm/arch/hwregs/reg_map.h>
+#include <asm/arch/hwregs/reg_rdwr.h>
+#include <asm/arch/hwregs/intr_vect_defs.h>
+#include <asm/arch/hwregs/ser_defs.h>
+
+/* From entry.S. */
+extern void gdb_handle_exception(void);
+/* From kgdb_asm.S. */
+extern void kgdb_handle_exception(void);
+
+static int kgdb_started = 0;
+
+/********************************* Register image ****************************/
+
+typedef
+struct register_image
+{
+                             /* Offset */
+       unsigned int   r0;    /* 0x00 */
+       unsigned int   r1;    /* 0x04 */
+       unsigned int   r2;    /* 0x08 */
+       unsigned int   r3;    /* 0x0C */
+       unsigned int   r4;    /* 0x10 */
+       unsigned int   r5;    /* 0x14 */
+       unsigned int   r6;    /* 0x18 */
+       unsigned int   r7;    /* 0x1C */
+       unsigned int   r8;    /* 0x20; Frame pointer (if any) */
+       unsigned int   r9;    /* 0x24 */
+       unsigned int   r10;   /* 0x28 */
+       unsigned int   r11;   /* 0x2C */
+       unsigned int   r12;   /* 0x30 */
+       unsigned int   r13;   /* 0x34 */
+       unsigned int   sp;    /* 0x38; R14, Stack pointer */
+       unsigned int   acr;   /* 0x3C; R15, Address calculation register. */
+
+       unsigned char  bz;    /* 0x40; P0, 8-bit zero register */
+       unsigned char  vr;    /* 0x41; P1, Version register (8-bit) */
+       unsigned int   pid;   /* 0x42; P2, Process ID */
+       unsigned char  srs;   /* 0x46; P3, Support register select (8-bit) */
+        unsigned short wz;    /* 0x47; P4, 16-bit zero register */
+       unsigned int   exs;   /* 0x49; P5, Exception status */
+       unsigned int   eda;   /* 0x4D; P6, Exception data address */
+       unsigned int   mof;   /* 0x51; P7, Multiply overflow register */
+       unsigned int   dz;    /* 0x55; P8, 32-bit zero register */
+       unsigned int   ebp;   /* 0x59; P9, Exception base pointer */
+       unsigned int   erp;   /* 0x5D; P10, Exception return pointer. Contains 
the PC we are interested in. */
+       unsigned int   srp;   /* 0x61; P11, Subroutine return pointer */
+       unsigned int   nrp;   /* 0x65; P12, NMI return pointer */
+       unsigned int   ccs;   /* 0x69; P13, Condition code stack */
+       unsigned int   usp;   /* 0x6D; P14, User mode stack pointer */
+       unsigned int   spc;   /* 0x71; P15, Single step PC */
+       unsigned int   pc;    /* 0x75; Pseudo register (for the most part set 
to ERP). */
+
+} registers;
+
+typedef
+struct bp_register_image
+{
+       /* Support register bank 0. */
+       unsigned int   s0_0;
+       unsigned int   s1_0;
+       unsigned int   s2_0;
+       unsigned int   s3_0;
+       unsigned int   s4_0;
+       unsigned int   s5_0;
+       unsigned int   s6_0;
+       unsigned int   s7_0;
+       unsigned int   s8_0;
+       unsigned int   s9_0;
+       unsigned int   s10_0;
+       unsigned int   s11_0;
+       unsigned int   s12_0;
+       unsigned int   s13_0;
+       unsigned int   s14_0;
+       unsigned int   s15_0;
+
+       /* Support register bank 1. */
+       unsigned int   s0_1;
+       unsigned int   s1_1;
+       unsigned int   s2_1;
+       unsigned int   s3_1;
+       unsigned int   s4_1;
+       unsigned int   s5_1;
+       unsigned int   s6_1;
+       unsigned int   s7_1;
+       unsigned int   s8_1;
+       unsigned int   s9_1;
+       unsigned int   s10_1;
+       unsigned int   s11_1;
+       unsigned int   s12_1;
+       unsigned int   s13_1;
+       unsigned int   s14_1;
+       unsigned int   s15_1;
+
+       /* Support register bank 2. */
+       unsigned int   s0_2;
+       unsigned int   s1_2;
+       unsigned int   s2_2;
+       unsigned int   s3_2;
+       unsigned int   s4_2;
+       unsigned int   s5_2;
+       unsigned int   s6_2;
+       unsigned int   s7_2;
+       unsigned int   s8_2;
+       unsigned int   s9_2;
+       unsigned int   s10_2;
+       unsigned int   s11_2;
+       unsigned int   s12_2;
+       unsigned int   s13_2;
+       unsigned int   s14_2;
+       unsigned int   s15_2;
+
+       /* Support register bank 3. */
+       unsigned int   s0_3; /* BP_CTRL */
+       unsigned int   s1_3; /* BP_I0_START */
+       unsigned int   s2_3; /* BP_I0_END */
+       unsigned int   s3_3; /* BP_D0_START */
+       unsigned int   s4_3; /* BP_D0_END */
+       unsigned int   s5_3; /* BP_D1_START */
+       unsigned int   s6_3; /* BP_D1_END */
+       unsigned int   s7_3; /* BP_D2_START */
+       unsigned int   s8_3; /* BP_D2_END */
+       unsigned int   s9_3; /* BP_D3_START */
+       unsigned int   s10_3; /* BP_D3_END */
+       unsigned int   s11_3; /* BP_D4_START */
+       unsigned int   s12_3; /* BP_D4_END */
+       unsigned int   s13_3; /* BP_D5_START */
+       unsigned int   s14_3; /* BP_D5_END */
+       unsigned int   s15_3; /* BP_RESERVED */
+
+} support_registers;
+
+enum register_name
+{
+       R0,  R1,  R2,  R3,
+       R4,  R5,  R6,  R7,
+       R8,  R9,  R10, R11,
+       R12, R13, SP,  ACR,
+
+       BZ,  VR,  PID, SRS,
+       WZ,  EXS, EDA, MOF,
+       DZ,  EBP, ERP, SRP,
+       NRP, CCS, USP, SPC,
+       PC,
+
+       S0,  S1,  S2,  S3,
+       S4,  S5,  S6,  S7,
+       S8,  S9,  S10, S11,
+       S12, S13, S14, S15
+
+};
+
+/* The register sizes of the registers in register_name. An unimplemented 
register
+   is designated by size 0 in this array. */
+static int register_size[] =
+{
+       4, 4, 4, 4,
+       4, 4, 4, 4,
+       4, 4, 4, 4,
+       4, 4, 4, 4,
+
+       1, 1, 4, 1,
+       2, 4, 4, 4,
+       4, 4, 4, 4,
+       4, 4, 4, 4,
+
+       4,
+
+       4, 4, 4, 4,
+       4, 4, 4, 4,
+       4, 4, 4, 4,
+       4, 4, 4
+
+};
+
+/* Contains the register image of the kernel.
+   (Global so that they can be reached from assembler code.) */
+registers reg;
+support_registers sreg;
+
+/************** Prototypes for local library functions ***********************/
+
+/* Copy of strcpy from libc. */
+static char *gdb_cris_strcpy(char *s1, const char *s2);
+
+/* Copy of strlen from libc. */
+static int gdb_cris_strlen(const char *s);
+
+/* Copy of memchr from libc. */
+static void *gdb_cris_memchr(const void *s, int c, int n);
+
+/* Copy of strtol from libc. Does only support base 16. */
+static int gdb_cris_strtol(const char *s, char **endptr, int base);
+
+/********************** Prototypes for local functions. **********************/
+
+/* Write a value to a specified register regno in the register image
+   of the current thread. */
+static int write_register(int regno, char *val);
+
+/* Read a value from a specified register in the register image. Returns the
+   status of the read operation. The register value is returned in valptr. */
+static int read_register(char regno, unsigned int *valptr);
+
+/* Serial port, reads one character. ETRAX 100 specific. from debugport.c */
+int getDebugChar(void);
+
+#ifdef CONFIG_ETRAXFS_SIM
+int getDebugChar(void)
+{
+  return socketread();
+}
+#endif
+
+/* Serial port, writes one character. ETRAX 100 specific. from debugport.c */
+void putDebugChar(int val);
+
+#ifdef CONFIG_ETRAXFS_SIM
+void putDebugChar(int val)
+{
+  socketwrite((char *)&val, 1);
+}
+#endif
+
+/* Returns the character equivalent of a nibble, bit 7, 6, 5, and 4 of a byte,
+   represented by int x. */
+static char highhex(int x);
+
+/* Returns the character equivalent of a nibble, bit 3, 2, 1, and 0 of a byte,
+   represented by int x. */
+static char lowhex(int x);
+
+/* Returns the integer equivalent of a hexadecimal character. */
+static int hex(char ch);
+
+/* Convert the memory, pointed to by mem into hexadecimal representation.
+   Put the result in buf, and return a pointer to the last character
+   in buf (null). */
+static char *mem2hex(char *buf, unsigned char *mem, int count);
+
+/* Convert the array, in hexadecimal representation, pointed to by buf into
+   binary representation. Put the result in mem, and return a pointer to
+   the character after the last byte written. */
+static unsigned char *hex2mem(unsigned char *mem, char *buf, int count);
+
+/* Put the content of the array, in binary representation, pointed to by buf
+   into memory pointed to by mem, and return a pointer to
+   the character after the last byte written. */
+static unsigned char *bin2mem(unsigned char *mem, unsigned char *buf, int 
count);
+
+/* Await the sequence $<data>#<checksum> and store <data> in the array buffer
+   returned. */
+static void getpacket(char *buffer);
+
+/* Send $<data>#<checksum> from the <data> in the array buffer. */
+static void putpacket(char *buffer);
+
+/* Build and send a response packet in order to inform the host the
+   stub is stopped. */
+static void stub_is_stopped(int sigval);
+
+/* All expected commands are sent from remote.c. Send a response according
+   to the description in remote.c. Not static since it needs to be reached
+   from assembler code. */
+void handle_exception(int sigval);
+
+/* Performs a complete re-start from scratch. ETRAX specific. */
+static void kill_restart(void);
+
+/******************** Prototypes for global functions. ***********************/
+
+/* The string str is prepended with the GDB printout token and sent. */
+void putDebugString(const unsigned char *str, int len);
+
+/* A static breakpoint to be used at startup. */
+void breakpoint(void);
+
+/* Avoid warning as the internal_stack is not used in the C-code. */
+#define USEDVAR(name)    { if (name) { ; } }
+#define USEDFUN(name) { void (*pf)(void) = (void *)name; USEDVAR(pf) }
+
+/********************************** Packet I/O ******************************/
+/* BUFMAX defines the maximum number of characters in
+   inbound/outbound buffers */
+/* FIXME: How do we know it's enough? */
+#define BUFMAX 512
+
+/* Run-length encoding maximum length. Send 64 at most. */
+#define RUNLENMAX 64
+
+/* Definition of all valid hexadecimal characters */
+static const char hexchars[] = "0123456789abcdef";
+
+/* The inbound/outbound buffers used in packet I/O */
+static char input_buffer[BUFMAX];
+static char output_buffer[BUFMAX];
+
+/* Error and warning messages. */
+enum error_type
+{
+       SUCCESS, E01, E02, E03, E04, E05, E06,
+};
+
+static char *error_message[] =
+{
+       "",
+       "E01 Set current or general thread - H[c,g] - internal error.",
+       "E02 Change register content - P - cannot change read-only register.",
+       "E03 Thread is not alive.", /* T, not used. */
+       "E04 The command is not supported - [s,C,S,!,R,d,r] - internal error.",
+       "E05 Change register content - P - the register is not implemented..",
+       "E06 Change memory content - M - internal error.",
+};
+
+/********************************** Breakpoint *******************************/
+/* Use an internal stack in the breakpoint and interrupt response routines.
+   FIXME: How do we know the size of this stack is enough?
+   Global so it can be reached from assembler code. */
+#define INTERNAL_STACK_SIZE 1024
+char internal_stack[INTERNAL_STACK_SIZE];
+
+/* Due to the breakpoint return pointer, a state variable is needed to keep
+   track of whether it is a static (compiled) or dynamic (gdb-invoked)
+   breakpoint to be handled. A static breakpoint uses the content of register
+   ERP as it is whereas a dynamic breakpoint requires subtraction with 2
+   in order to execute the instruction. The first breakpoint is static; all
+   following are assumed to be dynamic. */
+static int dynamic_bp = 0;
+
+/********************************* String library ****************************/
+/* Single-step over library functions creates trap loops. */
+
+/* Copy char s2[] to s1[]. */
+static char*
+gdb_cris_strcpy(char *s1, const char *s2)
+{
+       char *s = s1;
+
+       for (s = s1; (*s++ = *s2++) != '\0'; )
+               ;
+       return s1;
+}
+
+/* Find length of s[]. */
+static int
+gdb_cris_strlen(const char *s)
+{
+       const char *sc;
+
+       for (sc = s; *sc != '\0'; sc++)
+               ;
+       return (sc - s);
+}
+
+/* Find first occurrence of c in s[n]. */
+static void*
+gdb_cris_memchr(const void *s, int c, int n)
+{
+       const unsigned char uc = c;
+       const unsigned char *su;
+
+       for (su = s; 0 < n; ++su, --n)
+               if (*su == uc)
+                       return (void *)su;
+       return NULL;
+}
+/******************************* Standard library ****************************/
+/* Single-step over library functions creates trap loops. */
+/* Convert string to long. */
+static int
+gdb_cris_strtol(const char *s, char **endptr, int base)
+{
+       char *s1;
+       char *sd;
+       int x = 0;
+
+       for (s1 = (char*)s; (sd = gdb_cris_memchr(hexchars, *s1, base)) != 
NULL; ++s1)
+               x = x * base + (sd - hexchars);
+
+        if (endptr) {
+                /* Unconverted suffix is stored in endptr unless endptr is 
NULL. */
+                *endptr = s1;
+        }
+
+       return x;
+}
+
+/********************************* Register image ****************************/
+
+/* Write a value to a specified register in the register image of the current
+   thread. Returns status code SUCCESS, E02 or E05. */
+static int
+write_register(int regno, char *val)
+{
+       int status = SUCCESS;
+
+        if (regno >= R0 && regno <= ACR) {
+               /* Consecutive 32-bit registers. */
+               hex2mem((unsigned char *)&reg.r0 + (regno - R0) * 
sizeof(unsigned int),
+                       val, sizeof(unsigned int));
+
+       } else if (regno == BZ || regno == VR || regno == WZ || regno == DZ) {
+               /* Read-only registers. */
+               status = E02;
+
+       } else if (regno == PID) {
+               /* 32-bit register. (Even though we already checked SRS and WZ, 
we cannot
+                  combine this with the EXS - SPC write since SRS and WZ have 
different size.) */
+               hex2mem((unsigned char *)&reg.pid, val, sizeof(unsigned int));
+
+       } else if (regno == SRS) {
+               /* 8-bit register. */
+               hex2mem((unsigned char *)&reg.srs, val, sizeof(unsigned char));
+
+       } else if (regno >= EXS && regno <= SPC) {
+               /* Consecutive 32-bit registers. */
+               hex2mem((unsigned char *)&reg.exs + (regno - EXS) * 
sizeof(unsigned int),
+                        val, sizeof(unsigned int));
+
+       } else if (regno == PC) {
+               /* Pseudo-register. Treat as read-only. */
+               status = E02;
+
+       } else if (regno >= S0 && regno <= S15) {
+               /* 32-bit registers. */
+               hex2mem((unsigned char *)&sreg.s0_0 + (reg.srs * 16 * 
sizeof(unsigned int)) + (regno - S0) * sizeof(unsigned int), val, 
sizeof(unsigned int));
+       } else {
+               /* Non-existing register. */
+               status = E05;
+       }
+       return status;
+}
+
+/* Read a value from a specified register in the register image. Returns the
+   value in the register or -1 for non-implemented registers. */
+static int
+read_register(char regno, unsigned int *valptr)
+{
+       int status = SUCCESS;
+
+       /* We read the zero registers from the register struct (instead of just 
returning 0)
+          to catch errors. */
+
+       if (regno >= R0 && regno <= ACR) {
+               /* Consecutive 32-bit registers. */
+               *valptr = *(unsigned int *)((char *)&reg.r0 + (regno - R0) * 
sizeof(unsigned int));
+
+       } else if (regno == BZ || regno == VR) {
+               /* Consecutive 8-bit registers. */
+               *valptr = (unsigned int)(*(unsigned char *)
+                                         ((char *)&reg.bz + (regno - BZ) * 
sizeof(char)));
+
+       } else if (regno == PID) {
+               /* 32-bit register. */
+               *valptr =  *(unsigned int *)((char *)&reg.pid);
+
+       } else if (regno == SRS) {
+               /* 8-bit register. */
+               *valptr = (unsigned int)(*(unsigned char *)((char *)&reg.srs));
+
+       } else if (regno == WZ) {
+               /* 16-bit register. */
+               *valptr = (unsigned int)(*(unsigned short *)(char *)&reg.wz);
+
+       } else if (regno >= EXS && regno <= PC) {
+               /* Consecutive 32-bit registers. */
+               *valptr = *(unsigned int *)((char *)&reg.exs + (regno - EXS) * 
sizeof(unsigned int));
+
+       } else if (regno >= S0 && regno <= S15) {
+               /* Consecutive 32-bit registers, located elsewhere. */
+               *valptr = *(unsigned int *)((char *)&sreg.s0_0 + (reg.srs * 16 
* sizeof(unsigned int)) + (regno - S0) * sizeof(unsigned int));
+
+       } else {
+               /* Non-existing register. */
+               status = E05;
+       }
+       return status;
+
+}
+
+/********************************** Packet I/O ******************************/
+/* Returns the character equivalent of a nibble, bit 7, 6, 5, and 4 of a byte,
+   represented by int x. */
+static inline char
+highhex(int x)
+{
+       return hexchars[(x >> 4) & 0xf];
+}
+
+/* Returns the character equivalent of a nibble, bit 3, 2, 1, and 0 of a byte,
+   represented by int x. */
+static inline char
+lowhex(int x)
+{
+       return hexchars[x & 0xf];
+}
+
+/* Returns the integer equivalent of a hexadecimal character. */
+static int
+hex(char ch)
+{
+       if ((ch >= 'a') && (ch <= 'f'))
+               return (ch - 'a' + 10);
+       if ((ch >= '0') && (ch <= '9'))
+               return (ch - '0');
+       if ((ch >= 'A') && (ch <= 'F'))
+               return (ch - 'A' + 10);
+       return -1;
+}
+
+/* Convert the memory, pointed to by mem into hexadecimal representation.
+   Put the result in buf, and return a pointer to the last character
+   in buf (null). */
+
+static char *
+mem2hex(char *buf, unsigned char *mem, int count)
+{
+       int i;
+       int ch;
+
+        if (mem == NULL) {
+               /* Invalid address, caught by 'm' packet handler. */
+                for (i = 0; i < count; i++) {
+                        *buf++ = '0';
+                        *buf++ = '0';
+                }
+        } else {
+                /* Valid mem address. */
+               for (i = 0; i < count; i++) {
+                       ch = *mem++;
+                       *buf++ = highhex (ch);
+                       *buf++ = lowhex (ch);
+               }
+        }
+        /* Terminate properly. */
+       *buf = '\0';
+       return buf;
+}
+
+/* Same as mem2hex, but puts it in network byte order. */
+static char *
+mem2hex_nbo(char *buf, unsigned char *mem, int count)
+{
+       int i;
+       int ch;
+
+       mem += count - 1;
+       for (i = 0; i < count; i++) {
+               ch = *mem--;
+               *buf++ = highhex (ch);
+               *buf++ = lowhex (ch);
+        }
+
+        /* Terminate properly. */
+       *buf = '\0';
+       return buf;
+}
+
+/* Convert the array, in hexadecimal representation, pointed to by buf into
+   binary representation. Put the result in mem, and return a pointer to
+   the character after the last byte written. */
+static unsigned char*
+hex2mem(unsigned char *mem, char *buf, int count)
+{
+       int i;
+       unsigned char ch;
+       for (i = 0; i < count; i++) {
+               ch = hex (*buf++) << 4;
+               ch = ch + hex (*buf++);
+               *mem++ = ch;
+       }
+       return mem;
+}
+
+/* Put the content of the array, in binary representation, pointed to by buf
+   into memory pointed to by mem, and return a pointer to the character after
+   the last byte written.
+   Gdb will escape $, #, and the escape char (0x7d). */
+static unsigned char*
+bin2mem(unsigned char *mem, unsigned char *buf, int count)
+{
+       int i;
+       unsigned char *next;
+       for (i = 0; i < count; i++) {
+               /* Check for any escaped characters. Be paranoid and
+                  only unescape chars that should be escaped. */
+               if (*buf == 0x7d) {
+                       next = buf + 1;
+                       if (*next == 0x3 || *next == 0x4 || *next == 0x5D) {
+                                /* #, $, ESC */
+                               buf++;
+                               *buf += 0x20;
+                       }
+               }
+               *mem++ = *buf++;
+       }
+       return mem;
+}
+
+/* Await the sequence $<data>#<checksum> and store <data> in the array buffer
+   returned. */
+static void
+getpacket(char *buffer)
+{
+       unsigned char checksum;
+       unsigned char xmitcsum;
+       int i;
+       int count;
+       char ch;
+
+       do {
+               while((ch = getDebugChar ()) != '$')
+                       /* Wait for the start character $ and ignore all other 
characters */;
+               checksum = 0;
+               xmitcsum = -1;
+               count = 0;
+               /* Read until a # or the end of the buffer is reached */
+               while (count < BUFMAX) {
+                       ch = getDebugChar();
+                       if (ch == '#')
+                               break;
+                       checksum = checksum + ch;
+                       buffer[count] = ch;
+                       count = count + 1;
+               }
+
+               if (count >= BUFMAX)
+                       continue;
+
+               buffer[count] = 0;
+
+               if (ch == '#') {
+                       xmitcsum = hex(getDebugChar()) << 4;
+                       xmitcsum += hex(getDebugChar());
+                       if (checksum != xmitcsum) {
+                               /* Wrong checksum */
+                               putDebugChar('-');
+                       } else {
+                               /* Correct checksum */
+                               putDebugChar('+');
+                               /* If sequence characters are received, reply 
with them */
+                               if (buffer[2] == ':') {
+                                       putDebugChar(buffer[0]);
+                                       putDebugChar(buffer[1]);
+                                       /* Remove the sequence characters from 
the buffer */
+                                       count = gdb_cris_strlen(buffer);
+                                       for (i = 3; i <= count; i++)
+                                               buffer[i - 3] = buffer[i];
+                               }
+                       }
+               }
+       } while (checksum != xmitcsum);
+}
+
+/* Send $<data>#<checksum> from the <data> in the array buffer. */
+
+static void
+putpacket(char *buffer)
+{
+       int checksum;
+       int runlen;
+       int encode;
+
+       do {
+               char *src = buffer;
+               putDebugChar('$');
+               checksum = 0;
+               while (*src) {
+                       /* Do run length encoding */
+                       putDebugChar(*src);
+                       checksum += *src;
+                       runlen = 0;
+                       while (runlen < RUNLENMAX && *src == src[runlen]) {
+                               runlen++;
+                       }
+                       if (runlen > 3) {
+                               /* Got a useful amount */
+                               putDebugChar ('*');
+                               checksum += '*';
+                               encode = runlen + ' ' - 4;
+                               putDebugChar(encode);
+                               checksum += encode;
+                               src += runlen;
+                       } else {
+                               src++;
+                       }
+               }
+               putDebugChar('#');
+               putDebugChar(highhex (checksum));
+               putDebugChar(lowhex (checksum));
+       } while(kgdb_started && (getDebugChar() != '+'));
+}
+
+/* The string str is prepended with the GDB printout token and sent. Required
+   in traditional implementations. */
+void
+putDebugString(const unsigned char *str, int len)
+{
+       /* Move SPC forward if we are single-stepping. */
+       asm("spchere:");
+       asm("move $spc, $r10");
+       asm("cmp.d spchere, $r10");
+       asm("bne nosstep");
+       asm("nop");
+       asm("move.d spccont, $r10");
+       asm("move $r10, $spc");
+       asm("nosstep:");
+
+        output_buffer[0] = 'O';
+        mem2hex(&output_buffer[1], (unsigned char *)str, len);
+        putpacket(output_buffer);
+
+       asm("spccont:");
+}
+
+/********************************** Handle exceptions ************************/
+/* Build and send a response packet in order to inform the host the
+   stub is stopped. TAAn...:r...;n...:r...;n...:r...;
+                    AA = signal number
+                    n... = register number (hex)
+                    r... = register contents
+                    n... = `thread'
+                    r... = thread process ID.  This is a hex integer.
+                    n... = other string not starting with valid hex digit.
+                    gdb should ignore this n,r pair and go on to the next.
+                    This way we can extend the protocol. */
+static void
+stub_is_stopped(int sigval)
+{
+       char *ptr = output_buffer;
+       unsigned int reg_cont;
+
+       /* Send trap type (converted to signal) */
+
+       *ptr++ = 'T';
+       *ptr++ = highhex(sigval);
+       *ptr++ = lowhex(sigval);
+
+       if (((reg.exs & 0xff00) >> 8) == 0xc) {
+
+               /* Some kind of hardware watchpoint triggered. Find which one
+                  and determine its type (read/write/access).  */
+               int S, bp, trig_bits = 0, rw_bits = 0;
+               int trig_mask = 0;
+               unsigned int *bp_d_regs = &sreg.s3_3;
+               /* In a lot of cases, the stopped data address will simply be 
EDA.
+                  In some cases, we adjust it to match the watched data range.
+                  (We don't want to change the actual EDA though). */
+               unsigned int stopped_data_address;
+               /* The S field of EXS. */
+               S = (reg.exs & 0xffff0000) >> 16;
+
+               if (S & 1) {
+                       /* Instruction watchpoint. */
+                       /* FIXME: Check against, and possibly adjust reported 
EDA. */
+               } else {
+                       /* Data watchpoint.  Find the one that triggered. */
+                       for (bp = 0; bp < 6; bp++) {
+
+                               /* Dx_RD, Dx_WR in the S field of EXS for this 
BP. */
+                               int bitpos_trig = 1 + bp * 2;
+                               /* Dx_BPRD, Dx_BPWR in BP_CTRL for this BP. */
+                               int bitpos_config = 2 + bp * 4;
+
+                               /* Get read/write trig bits for this BP. */
+                               trig_bits = (S & (3 << bitpos_trig)) >> 
bitpos_trig;
+
+                               /* Read/write config bits for this BP. */
+                               rw_bits = (sreg.s0_3 & (3 << bitpos_config)) >> 
bitpos_config;
+                               if (trig_bits) {
+                                       /* Sanity check: the BP shouldn't 
trigger for accesses
+                                          that it isn't configured for. */
+                                       if ((rw_bits == 0x1 && trig_bits != 
0x1) ||
+                                           (rw_bits == 0x2 && trig_bits != 
0x2))
+                                               panic("Invalid r/w trigging for 
this BP");
+
+                                       /* Mark this BP as trigged for future 
reference. */
+                                       trig_mask |= (1 << bp);
+
+                                       if (reg.eda >= bp_d_regs[bp * 2] &&
+                                           reg.eda <= bp_d_regs[bp * 2 + 1]) {
+                                               /* EDA withing range for this 
BP; it must be the one
+                                                  we're looking for. */
+                                               stopped_data_address = reg.eda;
+                                               break;
+                                       }
+                               }
+                       }
+                       if (bp < 6) {
+                               /* Found a trigged BP with EDA within its 
configured data range. */
+                       } else if (trig_mask) {
+                               /* Something triggered, but EDA doesn't match 
any BP's range. */
+                               for (bp = 0; bp < 6; bp++) {
+                                       /* Dx_BPRD, Dx_BPWR in BP_CTRL for this 
BP. */
+                                       int bitpos_config = 2 + bp * 4;
+
+                                       /* Read/write config bits for this BP 
(needed later). */
+                                       rw_bits = (sreg.s0_3 & (3 << 
bitpos_config)) >> bitpos_config;
+
+                                       if (trig_mask & (1 << bp)) {
+                                               /* EDA within 31 bytes of the 
configured start address? */
+                                               if (reg.eda + 31 >= 
bp_d_regs[bp * 2]) {
+                                                       /* Changing the 
reported address to match
+                                                          the start address of 
the first applicable BP. */
+                                                       stopped_data_address = 
bp_d_regs[bp * 2];
+                                                       break;
+                                               } else {
+                                                       /* We continue since we 
might find another useful BP. */
+                                                       printk("EDA doesn't 
match trigged BP's range");
+                                               }
+                                       }
+                               }
+                       }
+
+                       /* No match yet? */
+                       BUG_ON(bp >= 6);
+                       /* Note that we report the type according to what the 
BP is configured
+                          for (otherwise we'd never report an 'awatch'), not 
according to how
+                          it trigged. We did check that the trigged bits match 
what the BP is
+                          configured for though. */
+                       if (rw_bits == 0x1) {
+                               /* read */
+                               strncpy(ptr, "rwatch", 6);
+                               ptr += 6;
+                       } else if (rw_bits == 0x2) {
+                               /* write */
+                               strncpy(ptr, "watch", 5);
+                               ptr += 5;
+                       } else if (rw_bits == 0x3) {
+                               /* access */
+                               strncpy(ptr, "awatch", 6);
+                               ptr += 6;
+                       } else {
+                               panic("Invalid r/w bits for this BP.");
+                       }
+
+                       *ptr++ = ':';
+                       /* Note that we don't read_register(EDA, ...) */
+                       ptr = mem2hex_nbo(ptr, (unsigned char 
*)&stopped_data_address, register_size[EDA]);
+                       *ptr++ = ';';
+               }
+       }
+       /* Only send PC, frame and stack pointer. */
+       read_register(PC, &reg_cont);
+       *ptr++ = highhex(PC);
+       *ptr++ = lowhex(PC);
+       *ptr++ = ':';
+       ptr = mem2hex(ptr, (unsigned char *)&reg_cont, register_size[PC]);
+       *ptr++ = ';';
+
+       read_register(R8, &reg_cont);
+       *ptr++ = highhex(R8);
+       *ptr++ = lowhex(R8);
+       *ptr++ = ':';
+       ptr = mem2hex(ptr, (unsigned char *)&reg_cont, register_size[R8]);
+       *ptr++ = ';';
+
+       read_register(SP, &reg_cont);
+       *ptr++ = highhex(SP);
+       *ptr++ = lowhex(SP);
+       *ptr++ = ':';
+       ptr = mem2hex(ptr, (unsigned char *)&reg_cont, register_size[SP]);
+       *ptr++ = ';';
+
+       /* Send ERP as well; this will save us an entire register fetch in some 
cases. */
+        read_register(ERP, &reg_cont);
+        *ptr++ = highhex(ERP);
+        *ptr++ = lowhex(ERP);
+        *ptr++ = ':';
+        ptr = mem2hex(ptr, (unsigned char *)&reg_cont, register_size[ERP]);
+        *ptr++ = ';';
+
+       /* null-terminate and send it off */
+       *ptr = 0;
+       putpacket(output_buffer);
+}
+
+/* Returns the size of an instruction that has a delay slot. */
+
+int insn_size(unsigned long pc)
+{
+       unsigned short opcode = *(unsigned short *)pc;
+       int size = 0;
+
+       switch ((opcode & 0x0f00) >> 8) {
+       case 0x0:
+       case 0x9:
+       case 0xb:
+               size = 2;
+               break;
+       case 0xe:
+       case 0xf:
+               size = 6;
+               break;
+       case 0xd:
+               /* Could be 4 or 6; check more bits. */
+               if ((opcode & 0xff) == 0xff)
+                       size = 4;
+               else
+                       size = 6;
+               break;
+       default:
+               panic("Couldn't find size of opcode 0x%x at 0x%lx\n", opcode, 
pc);
+       }
+
+       return size;
+}
+
+void register_fixup(int sigval)
+{
+       /* Compensate for ACR push at the beginning of exception handler. */
+       reg.sp += 4;
+
+       /* Standard case. */
+       reg.pc = reg.erp;
+       if (reg.erp & 0x1) {
+               /* Delay slot bit set.  Report as stopped on proper 
instruction.  */
+               if (reg.spc) {
+                       /* Rely on SPC if set. */
+                       reg.pc = reg.spc;
+               } else {
+                       /* Calculate the PC from the size of the instruction
+                          that the delay slot we're in belongs to. */
+                       reg.pc += insn_size(reg.erp & ~1) - 1 ;
+               }
+       }
+
+       if ((reg.exs & 0x3) == 0x0) {
+               /* Bits 1 - 0 indicate the type of memory operation performed
+                  by the interrupted instruction. 0 means no memory operation,
+                  and EDA is undefined in that case. We zero it to avoid 
confusion. */
+               reg.eda = 0;
+       }
+
+       if (sigval == SIGTRAP) {
+               /* Break 8, single step or hardware breakpoint exception. */
+
+               /* Check IDX field of EXS. */
+               if (((reg.exs & 0xff00) >> 8) == 0x18) {
+
+                       /* Break 8. */
+
+                        /* Static (compiled) breakpoints must return to the 
next instruction
+                          in order to avoid infinite loops (default value of 
ERP). Dynamic
+                          (gdb-invoked) must subtract the size of the break 
instruction from
+                          the ERP so that the instruction that was originally 
in the break
+                          instruction's place will be run when we return from 
the exception. */
+                       if (!dynamic_bp) {
+                               /* Assuming that all breakpoints are dynamic 
from now on. */
+                               dynamic_bp = 1;
+                       } else {
+
+                               /* Only if not in a delay slot. */
+                               if (!(reg.erp & 0x1)) {
+                                       reg.erp -= 2;
+                                       reg.pc -= 2;
+                               }
+                       }
+
+               } else if (((reg.exs & 0xff00) >> 8) == 0x3) {
+                       /* Single step. */
+                       /* Don't fiddle with S1. */
+
+               } else if (((reg.exs & 0xff00) >> 8) == 0xc) {
+
+                       /* Hardware watchpoint exception. */
+
+                       /* SPC has been updated so that we will get a single 
step exception
+                          when we return, but we don't want that. */
+                       reg.spc = 0;
+
+                       /* Don't fiddle with S1. */
+               }
+
+       } else if (sigval == SIGINT) {
+               /* Nothing special. */
+       }
+}
+
+static void insert_watchpoint(char type, int addr, int len)
+{
+       /* Breakpoint/watchpoint types (GDB terminology):
+          0 = memory breakpoint for instructions
+          (not supported; done via memory write instead)
+          1 = hardware breakpoint for instructions (supported)
+          2 = write watchpoint (supported)
+          3 = read watchpoint (supported)
+          4 = access watchpoint (supported) */
+
+       if (type < '1' || type > '4') {
+               output_buffer[0] = 0;
+               return;
+       }
+
+       /* Read watchpoints are set as access watchpoints, because of GDB's
+          inability to deal with pure read watchpoints. */
+       if (type == '3')
+               type = '4';
+
+       if (type == '1') {
+               /* Hardware (instruction) breakpoint. */
+               /* Bit 0 in BP_CTRL holds the configuration for I0. */
+               if (sreg.s0_3 & 0x1) {
+                       /* Already in use. */
+                       gdb_cris_strcpy(output_buffer, error_message[E04]);
+                       return;
+               }
+               /* Configure. */
+               sreg.s1_3 = addr;
+               sreg.s2_3 = (addr + len - 1);
+               sreg.s0_3 |= 1;
+       } else {
+               int bp;
+               unsigned int *bp_d_regs = &sreg.s3_3;
+
+               /* The watchpoint allocation scheme is the simplest possible.
+                  For example, if a region is watched for read and
+                  a write watch is requested, a new watchpoint will
+                  be used. Also, if a watch for a region that is already
+                  covered by one or more existing watchpoints, a new
+                  watchpoint will be used. */
+
+               /* First, find a free data watchpoint. */
+               for (bp = 0; bp < 6; bp++) {
+                       /* Each data watchpoint's control registers occupy 2 
bits
+                          (hence the 3), starting at bit 2 for D0 (hence the 2)
+                          with 4 bits between for each watchpoint (yes, the 
4). */
+                       if (!(sreg.s0_3 & (0x3 << (2 + (bp * 4))))) {
+                               break;
+                       }
+               }
+
+               if (bp > 5) {
+                       /* We're out of watchpoints. */
+                       gdb_cris_strcpy(output_buffer, error_message[E04]);
+                       return;
+               }
+
+               /* Configure the control register first. */
+               if (type == '3' || type == '4') {
+                       /* Trigger on read. */
+                       sreg.s0_3 |= (1 << (2 + bp * 4));
+               }
+               if (type == '2' || type == '4') {
+                       /* Trigger on write. */
+                       sreg.s0_3 |= (2 << (2 + bp * 4));
+               }
+
+               /* Ugly pointer arithmetics to configure the watched range. */
+               bp_d_regs[bp * 2] = addr;
+               bp_d_regs[bp * 2 + 1] = (addr + len - 1);
+       }
+
+       /* Set the S1 flag to enable watchpoints. */
+       reg.ccs |= (1 << (S_CCS_BITNR + CCS_SHIFT));
+       gdb_cris_strcpy(output_buffer, "OK");
+}
+
+static void remove_watchpoint(char type, int addr, int len)
+{
+       /* Breakpoint/watchpoint types:
+          0 = memory breakpoint for instructions
+          (not supported; done via memory write instead)
+          1 = hardware breakpoint for instructions (supported)
+          2 = write watchpoint (supported)
+          3 = read watchpoint (supported)
+          4 = access watchpoint (supported) */
+       if (type < '1' || type > '4') {
+               output_buffer[0] = 0;
+               return;
+       }
+
+       /* Read watchpoints are set as access watchpoints, because of GDB's
+          inability to deal with pure read watchpoints. */
+       if (type == '3')
+               type = '4';
+
+       if (type == '1') {
+               /* Hardware breakpoint. */
+               /* Bit 0 in BP_CTRL holds the configuration for I0. */
+               if (!(sreg.s0_3 & 0x1)) {
+                       /* Not in use. */
+                       gdb_cris_strcpy(output_buffer, error_message[E04]);
+                       return;
+               }
+               /* Deconfigure. */
+               sreg.s1_3 = 0;
+               sreg.s2_3 = 0;
+               sreg.s0_3 &= ~1;
+       } else {
+               int bp;
+               unsigned int *bp_d_regs = &sreg.s3_3;
+               /* Try to find a watchpoint that is configured for the
+                  specified range, then check that read/write also matches. */
+
+               /* Ugly pointer arithmetic, since I cannot rely on a
+                  single switch (addr) as there may be several watchpoints with
+                  the same start address for example. */
+
+               for (bp = 0; bp < 6; bp++) {
+                       if (bp_d_regs[bp * 2] == addr &&
+                           bp_d_regs[bp * 2 + 1] == (addr + len - 1)) {
+                               /* Matching range. */
+                               int bitpos = 2 + bp * 4;
+                               int rw_bits;
+
+                               /* Read/write bits for this BP. */
+                               rw_bits = (sreg.s0_3 & (0x3 << bitpos)) >> 
bitpos;
+
+                               if ((type == '3' && rw_bits == 0x1) ||
+                                   (type == '2' && rw_bits == 0x2) ||
+                                   (type == '4' && rw_bits == 0x3)) {
+                                       /* Read/write matched. */
+                                       break;
+                               }
+                       }
+               }
+
+               if (bp > 5) {
+                       /* No watchpoint matched. */
+                       gdb_cris_strcpy(output_buffer, error_message[E04]);
+                       return;
+               }
+
+               /* Found a matching watchpoint. Now, deconfigure it by
+                  both disabling read/write in bp_ctrl and zeroing its
+                  start/end addresses. */
+               sreg.s0_3 &= ~(3 << (2 + (bp * 4)));
+               bp_d_regs[bp * 2] = 0;
+               bp_d_regs[bp * 2 + 1] = 0;
+       }
+
+       /* Note that we don't clear the S1 flag here. It's done when 
continuing.  */
+       gdb_cris_strcpy(output_buffer, "OK");
+}
+
+
+
+/* All expected commands are sent from remote.c. Send a response according
+   to the description in remote.c. */
+void
+handle_exception(int sigval)
+{
+       /* Avoid warning of not used. */
+
+       USEDFUN(handle_exception);
+       USEDVAR(internal_stack[0]);
+
+       register_fixup(sigval);
+
+       /* Send response. */
+       stub_is_stopped(sigval);
+
+       for (;;) {
+               output_buffer[0] = '\0';
+               getpacket(input_buffer);
+               switch (input_buffer[0]) {
+                       case 'g':
+                               /* Read registers: g
+                                  Success: Each byte of register data is 
described by two hex digits.
+                                  Registers are in the internal order for GDB, 
and the bytes
+                                  in a register  are in the same order the 
machine uses.
+                                  Failure: void. */
+                       {
+                               char *buf;
+                               /* General and special registers. */
+                               buf = mem2hex(output_buffer, (char *)&reg, 
sizeof(registers));
+                               /* Support registers. */
+                               /* -1 because of the null termination that 
mem2hex adds. */
+                               mem2hex(buf,
+                                       (char *)&sreg + (reg.srs * 16 * 
sizeof(unsigned int)),
+                                       16 * sizeof(unsigned int));
+                               break;
+                       }
+                       case 'G':
+                               /* Write registers. GXX..XX
+                                  Each byte of register data  is described by 
two hex digits.
+                                  Success: OK
+                                  Failure: void. */
+                               /* General and special registers. */
+                               hex2mem((char *)&reg, &input_buffer[1], 
sizeof(registers));
+                               /* Support registers. */
+                               hex2mem((char *)&sreg + (reg.srs * 16 * 
sizeof(unsigned int)),
+                                       &input_buffer[1] + sizeof(registers),
+                                       16 * sizeof(unsigned int));
+                               gdb_cris_strcpy(output_buffer, "OK");
+                               break;
+
+                       case 'P':
+                               /* Write register. Pn...=r...
+                                  Write register n..., hex value without 0x, 
with value r...,
+                                  which contains a hex value without 0x and 
two hex digits
+                                  for each byte in the register (target byte 
order). P1f=11223344 means
+                                  set register 31 to 44332211.
+                                  Success: OK
+                                  Failure: E02, E05 */
+                               {
+                                       char *suffix;
+                                       int regno = 
gdb_cris_strtol(&input_buffer[1], &suffix, 16);
+                                       int status;
+
+                                       status = write_register(regno, 
suffix+1);
+
+                                       switch (status) {
+                                               case E02:
+                                                       /* Do not support 
read-only registers. */
+                                                       
gdb_cris_strcpy(output_buffer, error_message[E02]);
+                                                       break;
+                                               case E05:
+                                                       /* Do not support 
non-existing registers. */
+                                                       
gdb_cris_strcpy(output_buffer, error_message[E05]);
+                                                       break;
+                                               default:
+                                                       /* Valid register 
number. */
+                                                       
gdb_cris_strcpy(output_buffer, "OK");
+                                                       break;
+                                       }
+                               }
+                               break;
+
+                       case 'm':
+                               /* Read from memory. mAA..AA,LLLL
+                                  AA..AA is the address and LLLL is the length.
+                                  Success: XX..XX is the memory content.  Can 
be fewer bytes than
+                                  requested if only part of the data may be 
read. m6000120a,6c means
+                                  retrieve 108 byte from base address 6000120a.
+                                  Failure: void. */
+                               {
+                                        char *suffix;
+                                       unsigned char *addr = (unsigned char 
*)gdb_cris_strtol(&input_buffer[1],
+                                                                               
                &suffix, 16);
+                                       int len = gdb_cris_strtol(suffix+1, 0, 
16);
+
+                                       /* Bogus read (i.e. outside the kernel's
+                                          segment)? . */
+                                       if (!((unsigned int)addr >= 0xc0000000 
&&
+                                             (unsigned int)addr < 0xd0000000))
+                                               addr = NULL;
+
+                                        mem2hex(output_buffer, addr, len);
+                                }
+                               break;
+
+                       case 'X':
+                               /* Write to memory. XAA..AA,LLLL:XX..XX
+                                  AA..AA is the start address,  LLLL is the 
number of bytes, and
+                                  XX..XX is the binary data.
+                                  Success: OK
+                                  Failure: void. */
+                       case 'M':
+                               /* Write to memory. MAA..AA,LLLL:XX..XX
+                                  AA..AA is the start address,  LLLL is the 
number of bytes, and
+                                  XX..XX is the hexadecimal data.
+                                  Success: OK
+                                  Failure: void. */
+                               {
+                                       char *lenptr;
+                                       char *dataptr;
+                                       unsigned char *addr = (unsigned char 
*)gdb_cris_strtol(&input_buffer[1],
+                                                                               
      &lenptr, 16);
+                                       int len = gdb_cris_strtol(lenptr+1, 
&dataptr, 16);
+                                       if (*lenptr == ',' && *dataptr == ':') {
+                                               if (input_buffer[0] == 'M') {
+                                                       hex2mem(addr, dataptr + 
1, len);
+                                               } else /* X */ {
+                                                       bin2mem(addr, dataptr + 
1, len);
+                                               }
+                                               gdb_cris_strcpy(output_buffer, 
"OK");
+                                       }
+                                       else {
+                                               gdb_cris_strcpy(output_buffer, 
error_message[E06]);
+                                       }
+                               }
+                               break;
+
+                       case 'c':
+                               /* Continue execution. cAA..AA
+                                  AA..AA is the address where execution is 
resumed. If AA..AA is
+                                  omitted, resume at the present address.
+                                  Success: return to the executing thread.
+                                  Failure: will never know. */
+
+                               if (input_buffer[1] != '\0') {
+                                       /* FIXME: Doesn't handle address 
argument. */
+                                       gdb_cris_strcpy(output_buffer, 
error_message[E04]);
+                                       break;
+                               }
+
+                               /* Before continuing, make sure everything is 
set up correctly. */
+
+                               /* Set the SPC to some unlikely value.  */
+                               reg.spc = 0;
+                               /* Set the S1 flag to 0 unless some watchpoint 
is enabled (since setting
+                                  S1 to 0 would also disable watchpoints). 
(Note that bits 26-31 in BP_CTRL
+                                  are reserved, so don't check against those). 
*/
+                               if ((sreg.s0_3 & 0x3fff) == 0) {
+                                       reg.ccs &= ~(1 << (S_CCS_BITNR + 
CCS_SHIFT));
+                               }
+
+                               return;
+
+                       case 's':
+                               /* Step. sAA..AA
+                                  AA..AA is the address where execution is 
resumed. If AA..AA is
+                                  omitted, resume at the present address. 
Success: return to the
+                                  executing thread. Failure: will never know. 
*/
+
+                               if (input_buffer[1] != '\0') {
+                                       /* FIXME: Doesn't handle address 
argument. */
+                                       gdb_cris_strcpy(output_buffer, 
error_message[E04]);
+                                       break;
+                               }
+
+                               /* Set the SPC to PC, which is where we'll 
return
+                                  (deduced previously). */
+                               reg.spc = reg.pc;
+
+                               /* Set the S1 (first stacked, not current) 
flag, which will
+                                  kick into action when we rfe. */
+                               reg.ccs |= (1 << (S_CCS_BITNR + CCS_SHIFT));
+                               return;
+
+                       case 'Z':
+
+                               /* Insert breakpoint or watchpoint, 
Ztype,addr,length.
+                                  Remote protocol says: A remote target shall 
return an empty string
+                                  for an unrecognized breakpoint or watchpoint 
packet type. */
+                               {
+                                       char *lenptr;
+                                       char *dataptr;
+                                       int addr = 
gdb_cris_strtol(&input_buffer[3], &lenptr, 16);
+                                       int len = gdb_cris_strtol(lenptr + 1, 
&dataptr, 16);
+                                       char type = input_buffer[1];
+
+                                      insert_watchpoint(type, addr, len);
+                                       break;
+                               }
+
+                       case 'z':
+                               /* Remove breakpoint or watchpoint, 
Ztype,addr,length.
+                                  Remote protocol says: A remote target shall 
return an empty string
+                                  for an unrecognized breakpoint or watchpoint 
packet type. */
+                               {
+                                       char *lenptr;
+                                       char *dataptr;
+                                       int addr = 
gdb_cris_strtol(&input_buffer[3], &lenptr, 16);
+                                       int len = gdb_cris_strtol(lenptr + 1, 
&dataptr, 16);
+                                       char type = input_buffer[1];
+
+                                       remove_watchpoint(type, addr, len);
+                                       break;
+                               }
+
+
+                       case '?':
+                               /* The last signal which caused a stop. ?
+                                  Success: SAA, where AA is the signal number.
+                                  Failure: void. */
+                               output_buffer[0] = 'S';
+                               output_buffer[1] = highhex(sigval);
+                               output_buffer[2] = lowhex(sigval);
+                               output_buffer[3] = 0;
+                               break;
+
+                       case 'D':
+                               /* Detach from host. D
+                                  Success: OK, and return to the executing 
thread.
+                                  Failure: will never know */
+                               putpacket("OK");
+                               return;
+
+                       case 'k':
+                       case 'r':
+                               /* kill request or reset request.
+                                  Success: restart of target.
+                                  Failure: will never know. */
+                               kill_restart();
+                               break;
+
+                       case 'C':
+                       case 'S':
+                       case '!':
+                       case 'R':
+                       case 'd':
+                               /* Continue with signal sig. Csig;AA..AA
+                                  Step with signal sig. Ssig;AA..AA
+                                  Use the extended remote protocol. !
+                                  Restart the target system. R0
+                                  Toggle debug flag. d
+                                  Search backwards. tAA:PP,MM
+                                  Not supported: E04 */
+
+                               /* FIXME: What's the difference between not 
supported
+                                  and ignored (below)? */
+                               gdb_cris_strcpy(output_buffer, 
error_message[E04]);
+                               break;
+
+                       default:
+                               /* The stub should ignore other request and 
send an empty
+                                  response ($#<checksum>). This way we can 
extend the protocol and GDB
+                                  can tell whether the stub it is talking to 
uses the old or the new. */
+                               output_buffer[0] = 0;
+                               break;
+               }
+               putpacket(output_buffer);
+       }
+}
+
+void
+kgdb_init(void)
+{
+       reg_intr_vect_rw_mask intr_mask;
+       reg_ser_rw_intr_mask ser_intr_mask;
+
+       /* Configure the kgdb serial port. */
+#if defined(CONFIG_ETRAX_KGDB_PORT0)
+       /* Note: no shortcut registered (not handled by multiple_interrupt).
+          See entry.S.  */
+       set_exception_vector(SER0_INTR_VECT, kgdb_handle_exception);
+       /* Enable the ser irq in the global config. */
+       intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
+       intr_mask.ser0 = 1;
+       REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
+
+       ser_intr_mask = REG_RD(ser, regi_ser0, rw_intr_mask);
+       ser_intr_mask.data_avail = regk_ser_yes;
+       REG_WR(ser, regi_ser0, rw_intr_mask, ser_intr_mask);
+#elif defined(CONFIG_ETRAX_KGDB_PORT1)
+       /* Note: no shortcut registered (not handled by multiple_interrupt).
+          See entry.S.  */
+       set_exception_vector(SER1_INTR_VECT, kgdb_handle_exception);
+       /* Enable the ser irq in the global config. */
+       intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
+       intr_mask.ser1 = 1;
+       REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
+
+       ser_intr_mask = REG_RD(ser, regi_ser1, rw_intr_mask);
+       ser_intr_mask.data_avail = regk_ser_yes;
+       REG_WR(ser, regi_ser1, rw_intr_mask, ser_intr_mask);
+#elif defined(CONFIG_ETRAX_KGDB_PORT2)
+       /* Note: no shortcut registered (not handled by multiple_interrupt).
+          See entry.S.  */
+       set_exception_vector(SER2_INTR_VECT, kgdb_handle_exception);
+       /* Enable the ser irq in the global config. */
+       intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
+       intr_mask.ser2 = 1;
+       REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
+
+       ser_intr_mask = REG_RD(ser, regi_ser2, rw_intr_mask);
+       ser_intr_mask.data_avail = regk_ser_yes;
+       REG_WR(ser, regi_ser2, rw_intr_mask, ser_intr_mask);
+#elif defined(CONFIG_ETRAX_KGDB_PORT3)
+       /* Note: no shortcut registered (not handled by multiple_interrupt).
+          See entry.S.  */
+       set_exception_vector(SER3_INTR_VECT, kgdb_handle_exception);
+       /* Enable the ser irq in the global config. */
+       intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
+       intr_mask.ser3 = 1;
+       REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
+
+       ser_intr_mask = REG_RD(ser, regi_ser3, rw_intr_mask);
+       ser_intr_mask.data_avail = regk_ser_yes;
+       REG_WR(ser, regi_ser3, rw_intr_mask, ser_intr_mask);
+#endif
+
+}
+/* Performs a complete re-start from scratch. */
+static void
+kill_restart(void)
+{
+       machine_restart("");
+}
+
+/* Use this static breakpoint in the start-up only. */
+
+void
+breakpoint(void)
+{
+       kgdb_started = 1;
+       dynamic_bp = 0;     /* This is a static, not a dynamic breakpoint. */
+       __asm__ volatile ("break 8"); /* Jump to kgdb_handle_breakpoint. */
+}
+
+/****************************** End of file **********************************/
diff -urN linux/arch/cris/arch-v32/kernel/kgdb_asm.S 
linux/arch/cris/arch-v32/kernel/kgdb_asm.S
--- linux/arch/cris/arch-v32/kernel/kgdb_asm.S  1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/kgdb_asm.S  2005-08-01 19:23:43.111330000 
+0100     1.1
@@ -0,0 +1,552 @@
+/*
+ *  Copyright (C) 2004 Axis Communications AB
+ *
+ * Code for handling break 8, hardware breakpoint, single step, and serial
+ * port exceptions for kernel debugging purposes.
+ */
+
+#include <linux/config.h>
+#include <asm/arch/hwregs/intr_vect.h>
+
+       ;; Exported functions.
+       .globl kgdb_handle_exception
+
+kgdb_handle_exception:
+
+;; Create a register image of the caller.
+;;
+;; First of all, save the ACR on the stack since we need it for address 
calculations.
+;; We put it into the register struct later.
+
+  subq     4, $sp
+  move.d   $acr, [$sp]
+
+;; Now we are free to use ACR all we want.
+;; If we were running this handler with interrupts on, we would have to be 
careful
+;; to save and restore CCS manually, but since we aren't we treat it like 
every other
+;; register.
+
+  move.d   reg,  $acr
+  move.d   $r0,  [$acr]        ; Save R0 (start of register struct)
+  addq     4,    $acr
+  move.d   $r1,  [$acr]        ; Save R1
+  addq     4,    $acr
+  move.d   $r2,  [$acr]        ; Save R2
+  addq     4,    $acr
+  move.d   $r3,  [$acr]        ; Save R3
+  addq     4,    $acr
+  move.d   $r4,  [$acr]        ; Save R4
+  addq     4,    $acr
+  move.d   $r5,  [$acr]        ; Save R5
+  addq     4,    $acr
+  move.d   $r6,  [$acr]        ; Save R6
+  addq     4,    $acr
+  move.d   $r7,  [$acr]        ; Save R7
+  addq     4,    $acr
+  move.d   $r8,  [$acr]        ; Save R8
+  addq     4,    $acr
+  move.d   $r9,  [$acr]        ; Save R9
+  addq     4,    $acr
+  move.d   $r10, [$acr]        ; Save R10
+  addq     4,    $acr
+  move.d   $r11, [$acr]        ; Save R11
+  addq     4,    $acr
+  move.d   $r12, [$acr]        ; Save R12
+  addq     4,    $acr
+  move.d   $r13, [$acr]        ; Save R13
+  addq     4,    $acr
+  move.d   $sp,  [$acr]        ; Save SP (R14)
+  addq     4,    $acr
+
+  ;; The ACR register is already saved on the stack, so pop it from there.
+  move.d   [$sp],$r0
+  move.d   $r0,  [$acr]
+  addq     4,    $acr
+
+  move     $bz,  [$acr]
+  addq     1,    $acr
+  move     $vr,  [$acr]
+  addq     1,    $acr
+  move     $pid, [$acr]
+  addq     4,    $acr
+  move     $srs, [$acr]
+  addq     1,    $acr
+  move     $wz,  [$acr]
+  addq     2,    $acr
+  move     $exs, [$acr]
+  addq     4,    $acr
+  move     $eda, [$acr]
+  addq     4,    $acr
+  move     $mof, [$acr]
+  addq     4,    $acr
+  move     $dz,  [$acr]
+  addq     4,    $acr
+  move     $ebp, [$acr]
+  addq     4,    $acr
+  move     $erp, [$acr]
+  addq     4,    $acr
+  move     $srp, [$acr]
+  addq     4,    $acr
+  move     $nrp, [$acr]
+  addq     4,    $acr
+  move     $ccs, [$acr]
+  addq     4,    $acr
+  move     $usp, [$acr]
+  addq     4,    $acr
+  move     $spc, [$acr]
+  addq     4,     $acr
+
+;; Skip the pseudo-PC.
+  addq     4,     $acr
+
+;; Save the support registers in bank 0 - 3.
+  clear.d $r1 ; Bank counter
+  move.d  sreg, $acr
+
+;; Bank 0
+  move    $r1,  $srs
+  nop
+  nop
+  nop
+  move    $s0,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s1,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s2,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s3,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s4,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s5,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s6,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s7,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s8,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s9,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s10,  $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s11,  $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s12,  $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+
+  ;; Nothing in S13 - S15, bank 0
+  clear.d [$acr]
+  addq    4,     $acr
+  clear.d [$acr]
+  addq    4,     $acr
+  clear.d [$acr]
+  addq    4,     $acr
+
+;; Bank 1 and bank 2 have the same layout, hence the loop.
+  addq    1, $r1
+1:
+  move    $r1,  $srs
+  nop
+  nop
+  nop
+  move    $s0,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s1,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s2,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s3,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s4,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s5,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s6,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+
+  ;; Nothing in S7 - S15, bank 1 and 2
+  clear.d [$acr]
+  addq    4,     $acr
+  clear.d [$acr]
+  addq    4,     $acr
+  clear.d [$acr]
+  addq    4,     $acr
+  clear.d [$acr]
+  addq    4,     $acr
+  clear.d [$acr]
+  addq    4,     $acr
+  clear.d [$acr]
+  addq    4,     $acr
+  clear.d [$acr]
+  addq    4,     $acr
+  clear.d [$acr]
+  addq    4,     $acr
+  clear.d [$acr]
+  addq    4,     $acr
+
+  addq 1, $r1
+  cmpq 3, $r1
+  bne 1b
+  nop
+
+;; Bank 3
+  move    $r1,  $srs
+  nop
+  nop
+  nop
+  move    $s0,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s1,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s2,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s3,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s4,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s5,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s6,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s7,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s8,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s9,   $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s10,  $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s11,  $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s12,  $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s13,  $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+  move    $s14,  $r0
+  move.d  $r0,   [$acr]
+  addq    4,     $acr
+;; Nothing in S15, bank 3
+  clear.d [$acr]
+  addq    4,     $acr
+
+;; Check what got us here: get IDX field of EXS.
+  move $exs,    $r10
+  and.d 0xff00, $r10
+  lsrq 8,       $r10
+#if defined(CONFIG_ETRAX_KGDB_PORT0)
+  cmp.d SER0_INTR_VECT,   $r10 ; IRQ for serial port 0
+  beq sigint
+  nop
+#elif defined(CONFIG_ETRAX_KGDB_PORT1)
+  cmp.d SER1_INTR_VECT,   $r10 ; IRQ for serial port 1
+  beq sigint
+  nop
+#elif defined(CONFIG_ETRAX_KGDB_PORT2)
+  cmp.d SER2_INTR_VECT,   $r10 ; IRQ for serial port 2
+  beq sigint
+  nop
+#elif defined(CONFIG_ETRAX_KGDB_PORT3)
+  cmp.d SER3_INTR_VECT,   $r10 ; IRQ for serial port 3
+  beq sigint
+  nop
+#endif
+;; Multiple interrupt must be due to serial break.
+  cmp.d 0x30,   $r10 ; Multiple interrupt
+  beq sigint
+  nop
+;; Neither of those? Then it's a sigtrap.
+  ba handle_comm
+  moveq 5, $r10      ; Set SIGTRAP (delay slot)
+
+sigint:
+  ;; Serial interrupt; get character
+  jsr getDebugChar
+  nop                ; Delay slot
+  cmp.b 3, $r10      ; \003 (Ctrl-C)?
+  bne return         ; No, get out of here
+  nop
+  moveq 2, $r10      ; Set SIGINT
+
+;;
+;; Handle the communication
+;;
+handle_comm:
+  move.d   internal_stack+1020, $sp ; Use the internal stack which grows 
upwards
+  jsr      handle_exception         ; Interactive routine
+  nop
+
+;;
+;; Return to the caller
+;;
+return:
+
+;; First of all, write the support registers.
+  clear.d $r1 ; Bank counter
+  move.d  sreg, $acr
+
+;; Bank 0
+  move    $r1,  $srs
+  nop
+  nop
+  nop
+  move.d  [$acr], $r0
+  move    $r0,    $s0
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s1
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s2
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s3
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s4
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s5
+  addq    4,      $acr
+
+;; Nothing in S6 - S7, bank 0.
+  addq    4,      $acr
+  addq    4,      $acr
+
+  move.d  [$acr], $r0
+  move    $r0,    $s8
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s9
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s10
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s11
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s12
+  addq    4,      $acr
+
+;; Nothing in S13 - S15, bank 0
+  addq    4,      $acr
+  addq    4,      $acr
+  addq    4,      $acr
+
+;; Bank 1 and bank 2 have the same layout, hence the loop.
+  addq    1, $r1
+2:
+  move    $r1,  $srs
+  nop
+  nop
+  nop
+  move.d  [$acr], $r0
+  move    $r0,    $s0
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s1
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s2
+  addq    4,      $acr
+
+;; S3 (MM_CAUSE) is read-only.
+  addq    4,      $acr
+
+  move.d  [$acr], $r0
+  move    $r0,    $s4
+  addq    4,      $acr
+
+;; FIXME: Actually write S5/S6? (Affects MM_CAUSE.)
+  addq    4,      $acr
+  addq    4,      $acr
+
+;; Nothing in S7 - S15, bank 1 and 2
+  addq    4,      $acr
+  addq    4,      $acr
+  addq    4,      $acr
+  addq    4,      $acr
+  addq    4,      $acr
+  addq    4,      $acr
+  addq    4,      $acr
+  addq    4,      $acr
+  addq    4,      $acr
+
+  addq 1, $r1
+  cmpq 3, $r1
+  bne 2b
+  nop
+
+;; Bank 3
+  move    $r1,  $srs
+  nop
+  nop
+  nop
+  move.d  [$acr], $r0
+  move    $r0,    $s0
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s1
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s2
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s3
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s4
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s5
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s6
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s7
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s8
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s9
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s10
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s11
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s12
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s13
+  addq    4,      $acr
+  move.d  [$acr], $r0
+  move    $r0,    $s14
+  addq    4,      $acr
+
+;; Nothing in S15, bank 3
+  addq    4,      $acr
+
+;; Now, move on to the regular register restoration process.
+
+   move.d  reg,    $acr   ; Reset ACR to point at the beginning of the 
register image
+   move.d  [$acr], $r0    ; Restore R0
+   addq    4,      $acr
+   move.d  [$acr], $r1    ; Restore R1
+   addq    4,      $acr
+   move.d  [$acr], $r2    ; Restore R2
+   addq    4,      $acr
+   move.d  [$acr], $r3    ; Restore R3
+   addq    4,      $acr
+   move.d  [$acr], $r4    ; Restore R4
+   addq    4,      $acr
+   move.d  [$acr], $r5    ; Restore R5
+   addq    4,      $acr
+   move.d  [$acr], $r6    ; Restore R6
+   addq    4,      $acr
+   move.d  [$acr], $r7    ; Restore R7
+   addq    4,      $acr
+   move.d  [$acr], $r8    ; Restore R8
+   addq    4,      $acr
+   move.d  [$acr], $r9    ; Restore R9
+   addq    4,      $acr
+   move.d  [$acr], $r10   ; Restore R10
+   addq    4,      $acr
+   move.d  [$acr], $r11   ; Restore R11
+   addq    4,      $acr
+   move.d  [$acr], $r12   ; Restore R12
+   addq    4,      $acr
+   move.d  [$acr], $r13   ; Restore R13
+
+;;
+;; We restore all registers, even though some of them probably haven't changed.
+;;
+
+   addq    4,      $acr
+   move.d  [$acr], $sp    ; Restore SP (R14)
+
+   ;; ACR cannot be restored just yet.
+   addq    8,      $acr
+
+   ;; Skip BZ, VR.
+   addq    2,      $acr
+
+   move    [$acr], $pid   ; Restore PID
+   addq    4,      $acr
+   move    [$acr], $srs   ; Restore SRS
+   nop
+   nop
+   nop
+   addq    1,      $acr
+
+   ;; Skip WZ.
+   addq    2,      $acr
+
+   move    [$acr], $exs    ; Restore EXS.
+   addq    4,      $acr
+   move    [$acr], $eda    ; Restore EDA.
+   addq    4,      $acr
+   move    [$acr], $mof    ; Restore MOF.
+
+   ;; Skip DZ.
+   addq    8,      $acr
+
+   move    [$acr], $ebp    ; Restore EBP.
+   addq    4,      $acr
+   move    [$acr], $erp    ; Restore ERP.
+   addq    4,      $acr
+   move    [$acr], $srp    ; Restore SRP.
+   addq    4,      $acr
+   move    [$acr], $nrp    ; Restore NRP.
+   addq    4,      $acr
+   move    [$acr], $ccs    ; Restore CCS like an ordinary register.
+   addq    4,      $acr
+   move    [$acr], $usp    ; Restore USP
+   addq    4,      $acr
+   move    [$acr], $spc    ; Restore SPC
+                           ; No restoration of pseudo-PC of course.
+
+   move.d  reg,    $acr    ; Reset ACR to point at the beginning of the 
register image
+   add.d   15*4,   $acr
+   move.d  [$acr], $acr    ; Finally, restore ACR.
+   rete                    ; Same as jump ERP
+   rfe                     ; Shifts CCS
diff -urN linux/arch/cris/arch-v32/kernel/pinmux.c 
linux/arch/cris/arch-v32/kernel/pinmux.c
--- linux/arch/cris/arch-v32/kernel/pinmux.c    1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/pinmux.c    2005-08-01 19:23:43.139285000 
+0100     1.1
@@ -0,0 +1,229 @@
+/*
+ * Allocator for I/O pins. All pins are allocated to GPIO at bootup.
+ * Unassigned pins and GPIO pins can be allocated to a fixed interface
+ * or the I/O processor instead.
+ *
+ * Copyright (c) 2004 Axis Communications AB.
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <asm/arch/hwregs/reg_map.h>
+#include <asm/arch/hwregs/reg_rdwr.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/hwregs/pinmux_defs.h>
+
+#undef DEBUG
+
+#define PORT_PINS 18
+#define PORTS 4
+
+static char pins[PORTS][PORT_PINS];
+static DEFINE_SPINLOCK(pinmux_lock);
+
+static void crisv32_pinmux_set(int port);
+
+int
+crisv32_pinmux_init(void)
+{
+       static int initialized = 0;
+
+       if (!initialized) {
+               reg_pinmux_rw_pa pa = REG_RD(pinmux, regi_pinmux, rw_pa);
+               initialized = 1;
+               pa.pa0 = pa.pa1 = pa.pa2 = pa.pa3 =
+               pa.pa4 = pa.pa5 = pa.pa6 = pa.pa7 = regk_pinmux_yes;
+               REG_WR(pinmux, regi_pinmux, rw_pa, pa);
+               crisv32_pinmux_alloc(PORT_B, 0, PORT_PINS - 1, pinmux_gpio);
+               crisv32_pinmux_alloc(PORT_C, 0, PORT_PINS - 1, pinmux_gpio);
+               crisv32_pinmux_alloc(PORT_D, 0, PORT_PINS - 1, pinmux_gpio);
+               crisv32_pinmux_alloc(PORT_E, 0, PORT_PINS - 1, pinmux_gpio);
+       }
+
+       return 0;
+}
+
+int
+crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode)
+{
+       int i;
+       unsigned long flags;
+
+       crisv32_pinmux_init();
+
+       if (port > PORTS)
+               return -EINVAL;
+
+       spin_lock_irqsave(&pinmux_lock, flags);
+
+       for (i = first_pin; i <= last_pin; i++)
+       {
+               if ((pins[port][i] != pinmux_none) && (pins[port][i] != 
pinmux_gpio) &&
+                   (pins[port][i] != mode))
+               {
+                       spin_unlock_irqrestore(&pinmux_lock, flags);
+#ifdef DEBUG
+                       panic("Pinmux alloc failed!\n");
+#endif
+                       return -EPERM;
+               }
+       }
+
+       for (i = first_pin; i <= last_pin; i++)
+               pins[port][i] = mode;
+
+       crisv32_pinmux_set(port);
+
+       spin_unlock_irqrestore(&pinmux_lock, flags);
+
+       return 0;
+}
+
+int
+crisv32_pinmux_alloc_fixed(enum fixed_function function)
+{
+       int ret = -EINVAL;
+       char saved[sizeof pins];
+       unsigned long flags;
+
+       spin_lock_irqsave(&pinmux_lock, flags);
+
+       /* Save internal data for recovery */
+       memcpy(saved, pins, sizeof pins);
+
+       reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot);
+
+       switch(function)
+       {
+       case pinmux_ser1:
+               ret = crisv32_pinmux_alloc(PORT_C, 4, 7, pinmux_fixed);
+               hwprot.ser1 = regk_pinmux_yes;
+               break;
+       case pinmux_ser2:
+               ret = crisv32_pinmux_alloc(PORT_C, 8, 11, pinmux_fixed);
+               hwprot.ser2 = regk_pinmux_yes;
+               break;
+       case pinmux_ser3:
+               ret = crisv32_pinmux_alloc(PORT_C, 12, 15, pinmux_fixed);
+               hwprot.ser3 = regk_pinmux_yes;
+               break;
+       case pinmux_sser0:
+               ret = crisv32_pinmux_alloc(PORT_C, 0, 3, pinmux_fixed);
+               ret |= crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed);
+               hwprot.sser0 = regk_pinmux_yes;
+               break;
+       case pinmux_sser1:
+               ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed);
+               hwprot.sser1 = regk_pinmux_yes;
+               break;
+       case pinmux_ata0:
+               ret = crisv32_pinmux_alloc(PORT_D, 5, 7, pinmux_fixed);
+               ret |= crisv32_pinmux_alloc(PORT_D, 15, 17, pinmux_fixed);
+               hwprot.ata0 = regk_pinmux_yes;
+               break;
+       case pinmux_ata1:
+               ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed);
+               ret |= crisv32_pinmux_alloc(PORT_E, 17, 17, pinmux_fixed);
+               hwprot.ata1 = regk_pinmux_yes;
+               break;
+       case pinmux_ata2:
+               ret = crisv32_pinmux_alloc(PORT_C, 11, 15, pinmux_fixed);
+               ret |= crisv32_pinmux_alloc(PORT_E, 3, 3, pinmux_fixed);
+               hwprot.ata2 = regk_pinmux_yes;
+               break;
+       case pinmux_ata3:
+               ret = crisv32_pinmux_alloc(PORT_C, 8, 10, pinmux_fixed);
+               ret |= crisv32_pinmux_alloc(PORT_C, 0, 2, pinmux_fixed);
+               hwprot.ata2 = regk_pinmux_yes;
+               break;
+       case pinmux_ata:
+               ret = crisv32_pinmux_alloc(PORT_B, 0, 15, pinmux_fixed);
+               ret |= crisv32_pinmux_alloc(PORT_D, 8, 15, pinmux_fixed);
+               hwprot.ata = regk_pinmux_yes;
+               break;
+       case pinmux_eth1:
+               ret = crisv32_pinmux_alloc(PORT_E, 0, 17, pinmux_fixed);
+               hwprot.eth1 = regk_pinmux_yes;
+               hwprot.eth1_mgm = regk_pinmux_yes;
+               break;
+       case pinmux_timer:
+               ret = crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed);
+               hwprot.timer = regk_pinmux_yes;
+               spin_unlock_irqrestore(&pinmux_lock, flags);
+               return ret;
+       }
+
+       if (!ret)
+               REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot);
+       else
+               memcpy(pins, saved, sizeof pins);
+
+  spin_unlock_irqrestore(&pinmux_lock, flags);
+
+  return ret;
+}
+
+void
+crisv32_pinmux_set(int port)
+{
+       int i;
+       int gpio_val = 0;
+       int iop_val = 0;
+
+       for (i = 0; i < PORT_PINS; i++)
+       {
+               if (pins[port][i] == pinmux_gpio)
+                       gpio_val |= (1 << i);
+               else if (pins[port][i] == pinmux_iop)
+                       iop_val |= (1 << i);
+       }
+
+       REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_gio + 8*port, 
gpio_val);
+       REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_iop + 8*port, 
iop_val);
+
+#ifdef DEBUG
+       crisv32_pinmux_dump();
+#endif
+}
+
+int
+crisv32_pinmux_dealloc(int port, int first_pin, int last_pin)
+{
+       int i;
+       unsigned long flags;
+
+       crisv32_pinmux_init();
+
+       if (port > PORTS)
+               return -EINVAL;
+
+       spin_lock_irqsave(&pinmux_lock, flags);
+
+       for (i = first_pin; i <= last_pin; i++)
+               pins[port][i] = pinmux_none;
+
+       crisv32_pinmux_set(port);
+       spin_unlock_irqrestore(&pinmux_lock, flags);
+
+       return 0;
+}
+
+void
+crisv32_pinmux_dump(void)
+{
+       int i, j;
+
+       crisv32_pinmux_init();
+
+       for (i = 0; i < PORTS; i++)
+       {
+               printk("Port %c\n", 'B'+i);
+               for (j = 0; j < PORT_PINS; j++)
+                       printk("  Pin %d = %d\n", j, pins[i][j]);
+       }
+}
+
+__initcall(crisv32_pinmux_init);
diff -urN linux/arch/cris/arch-v32/kernel/process.c 
linux/arch/cris/arch-v32/kernel/process.c
--- linux/arch/cris/arch-v32/kernel/process.c   1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/process.c   2005-08-01 19:23:43.164230000 
+0100     1.1
@@ -0,0 +1,270 @@
+/*
+ *  Copyright (C) 2000-2003  Axis Communications AB
+ *
+ *  Authors:   Bjorn Wesen (bjornw@axis.com)
+ *             Mikael Starvik (starvik@axis.com)
+ *             Tobias Anderberg (tobiasa@axis.com), CRISv32 port.
+ *
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <asm/arch/hwregs/reg_rdwr.h>
+#include <asm/arch/hwregs/reg_map.h>
+#include <asm/arch/hwregs/timer_defs.h>
+#include <asm/arch/hwregs/intr_vect_defs.h>
+
+extern void stop_watchdog(void);
+
+#ifdef CONFIG_ETRAX_GPIO
+extern void etrax_gpio_wake_up_check(void); /* Defined in drivers/gpio.c. */
+#endif
+
+extern int cris_hlt_counter;
+
+/* We use this if we don't have any better idle routine. */
+void default_idle(void)
+{
+       local_irq_disable();
+       if (!need_resched() && !cris_hlt_counter) {
+               /* Halt until exception. */
+               __asm__ volatile("ei    \n\t"
+                                 "halt      ");
+       }
+       local_irq_enable();
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+
+extern void deconfigure_bp(long pid);
+void exit_thread(void)
+{
+       deconfigure_bp(current->pid);
+}
+
+/*
+ * If the watchdog is enabled, disable interrupts and enter an infinite loop.
+ * The watchdog will reset the CPU after 0.1s. If the watchdog isn't enabled
+ * then enable it and wait.
+ */
+extern void arch_enable_nmi(void);
+
+void
+hard_reset_now(void)
+{
+       /*
+        * Don't declare this variable elsewhere.  We don't want any other
+        * code to know about it than the watchdog handler in entry.S and
+        * this code, implementing hard reset through the watchdog.
+        */
+#if defined(CONFIG_ETRAX_WATCHDOG)
+       extern int cause_of_death;
+#endif
+
+       printk("*** HARD RESET ***\n");
+       local_irq_disable();
+
+#if defined(CONFIG_ETRAX_WATCHDOG)
+       cause_of_death = 0xbedead;
+#else
+{
+       reg_timer_rw_wd_ctrl wd_ctrl = {0};
+
+       stop_watchdog();
+
+       wd_ctrl.key = 16;       /* Arbitrary key. */
+       wd_ctrl.cnt = 1;        /* Minimum time. */
+       wd_ctrl.cmd = regk_timer_start;
+
+        arch_enable_nmi();
+       REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl);
+}
+#endif
+
+       while (1)
+               ; /* Wait for reset. */
+}
+
+/*
+ * Return saved PC of a blocked thread.
+ */
+unsigned long thread_saved_pc(struct task_struct *t)
+{
+       return (unsigned long)user_regs(t->thread_info)->erp;
+}
+
+static void
+kernel_thread_helper(void* dummy, int (*fn)(void *), void * arg)
+{
+       fn(arg);
+       do_exit(-1); /* Should never be called, return bad exit value. */
+}
+
+/* Create a kernel thread. */
+int
+kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+       struct pt_regs regs;
+
+       memset(&regs, 0, sizeof(regs));
+
+        /* Don't use r10 since that is set to 0 in copy_thread. */
+       regs.r11 = (unsigned long) fn;
+       regs.r12 = (unsigned long) arg;
+       regs.erp = (unsigned long) kernel_thread_helper;
+       regs.ccs = 1 << (I_CCS_BITNR + CCS_SHIFT);
+
+       /* Create the new process. */
+        return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, 
NULL);
+}
+
+/*
+ * Setup the child's kernel stack with a pt_regs and call switch_stack() on it.
+ * It will be unnested during _resume and _ret_from_sys_call when the new 
thread
+ * is scheduled.
+ *
+ * Also setup the thread switching structure which is used to keep
+ * thread-specific data during _resumes.
+ */
+
+extern asmlinkage void ret_from_fork(void);
+
+int
+copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+       unsigned long unused,
+       struct task_struct *p, struct pt_regs *regs)
+{
+       struct pt_regs *childregs;
+       struct switch_stack *swstack;
+
+       /*
+        * Put the pt_regs structure at the end of the new kernel stack page and
+        * fix it up. Note: the task_struct doubles as the kernel stack for the
+        * task.
+        */
+       childregs = user_regs(p->thread_info);
+       *childregs = *regs;     /* Struct copy of pt_regs. */
+        p->set_child_tid = p->clear_child_tid = NULL;
+        childregs->r10 = 0;    /* Child returns 0 after a fork/clone. */
+
+       /* Set a new TLS ?
+        * The TLS is in $mof beacuse it is the 5th argument to sys_clone.
+        */
+       if (p->mm && (clone_flags & CLONE_SETTLS)) {
+               p->thread_info->tls = regs->mof;
+       }
+
+       /* Put the switch stack right below the pt_regs. */
+       swstack = ((struct switch_stack *) childregs) - 1;
+
+       /* Paramater to ret_from_sys_call. 0 is don't restart the syscall. */
+       swstack->r9 = 0;
+
+       /*
+        * We want to return into ret_from_sys_call after the _resume.
+        * ret_from_fork will call ret_from_sys_call.
+        */
+       swstack->return_ip = (unsigned long) ret_from_fork;
+
+       /* Fix the user-mode and kernel-mode stackpointer. */
+       p->thread.usp = usp;
+       p->thread.ksp = (unsigned long) swstack;
+
+       return 0;
+}
+
+/*
+ * Be aware of the "magic" 7th argument in the four system-calls below.
+ * They need the latest stackframe, which is put as the 7th argument by
+ * entry.S. The previous arguments are dummies or actually used, but need
+ * to be defined to reach the 7th argument.
+ *
+ * N.B.: Another method to get the stackframe is to use current_regs(). But
+ * it returns the latest stack-frame stacked when going from _user mode_ and
+ * some of these (at least sys_clone) are called from kernel-mode sometimes
+ * (for example during kernel_thread, above) and thus cannot use it. Thus,
+ * to be sure not to get any surprises, we use the method for the other calls
+ * as well.
+ */
+asmlinkage int
+sys_fork(long r10, long r11, long r12, long r13, long mof, long srp,
+       struct pt_regs *regs)
+{
+       return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
+}
+
+/* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */
+asmlinkage int
+sys_clone(unsigned long newusp, unsigned long flags, int *parent_tid, int 
*child_tid,
+       unsigned long tls, long srp, struct pt_regs *regs)
+{
+       if (!newusp)
+               newusp = rdusp();
+
+       return do_fork(flags, newusp, regs, 0, parent_tid, child_tid);
+}
+
+/*
+ * vfork is a system call in i386 because of register-pressure - maybe
+ * we can remove it and handle it in libc but we put it here until then.
+ */
+asmlinkage int
+sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp,
+       struct pt_regs *regs)
+{
+       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, 
NULL, NULL);
+}
+
+/* sys_execve() executes a new program. */
+asmlinkage int
+sys_execve(const char *fname, char **argv, char **envp, long r13, long mof, 
long srp,
+       struct pt_regs *regs)
+{
+       int error;
+       char *filename;
+
+       filename = getname(fname);
+       error = PTR_ERR(filename);
+
+       if (IS_ERR(filename))
+               goto out;
+
+       error = do_execve(filename, argv, envp, regs);
+       putname(filename);
+ out:
+       return error;
+}
+
+unsigned long
+get_wchan(struct task_struct *p)
+{
+       /* TODO */
+       return 0;
+}
+#undef last_sched
+#undef first_sched
+
+void show_regs(struct pt_regs * regs)
+{
+       unsigned long usp = rdusp();
+        printk("ERP: %08lx SRP: %08lx  CCS: %08lx USP: %08lx MOF: %08lx\n",
+               regs->erp, regs->srp, regs->ccs, usp, regs->mof);
+
+       printk(" r0: %08lx  r1: %08lx   r2: %08lx  r3: %08lx\n",
+               regs->r0, regs->r1, regs->r2, regs->r3);
+
+       printk(" r4: %08lx  r5: %08lx   r6: %08lx  r7: %08lx\n",
+               regs->r4, regs->r5, regs->r6, regs->r7);
+
+       printk(" r8: %08lx  r9: %08lx  r10: %08lx r11: %08lx\n",
+               regs->r8, regs->r9, regs->r10, regs->r11);
+
+       printk("r12: %08lx r13: %08lx oR10: %08lx\n",
+               regs->r12, regs->r13, regs->orig_r10);
+}
diff -urN linux/arch/cris/arch-v32/kernel/ptrace.c 
linux/arch/cris/arch-v32/kernel/ptrace.c
--- linux/arch/cris/arch-v32/kernel/ptrace.c    1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/ptrace.c    2005-08-01 19:23:43.186522000 
+0100     1.1
@@ -0,0 +1,597 @@
+/*
+ * Copyright (C) 2000-2003, Axis Communications AB.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/signal.h>
+#include <linux/security.h>
+
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/arch/hwregs/supp_reg.h>
+
+/*
+ * Determines which bits in CCS the user has access to.
+ * 1 = access, 0 = no access.
+ */
+#define CCS_MASK 0x00087c00     /* SXNZVC */
+
+#define SBIT_USER (1 << (S_CCS_BITNR + CCS_SHIFT))
+
+static int put_debugreg(long pid, unsigned int regno, long data);
+static long get_debugreg(long pid, unsigned int regno);
+static unsigned long get_pseudo_pc(struct task_struct *child);
+void deconfigure_bp(long pid);
+
+extern unsigned long cris_signal_return_page;
+
+/*
+ * Get contents of register REGNO in task TASK.
+ */
+long get_reg(struct task_struct *task, unsigned int regno)
+{
+       /* USP is a special case, it's not in the pt_regs struct but
+        * in the tasks thread struct
+        */
+       unsigned long ret;
+
+       if (regno <= PT_EDA)
+               ret = ((unsigned long *)user_regs(task->thread_info))[regno];
+       else if (regno == PT_USP)
+               ret = task->thread.usp;
+       else if (regno == PT_PPC)
+               ret = get_pseudo_pc(task);
+       else if (regno <= PT_MAX)
+               ret = get_debugreg(task->pid, regno);
+       else
+               ret = 0;
+
+       return ret;
+}
+
+/*
+ * Write contents of register REGNO in task TASK.
+ */
+int put_reg(struct task_struct *task, unsigned int regno, unsigned long data)
+{
+       if (regno <= PT_EDA)
+               ((unsigned long *)user_regs(task->thread_info))[regno] = data;
+       else if (regno == PT_USP)
+               task->thread.usp = data;
+       else if (regno == PT_PPC) {
+               /* Write pseudo-PC to ERP only if changed. */
+               if (data != get_pseudo_pc(task))
+                       ((unsigned long *)user_regs(task->thread_info))[PT_ERP] 
= data;
+       } else if (regno <= PT_MAX)
+               return put_debugreg(task->pid, regno, data);
+       else
+               return -1;
+       return 0;
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching.
+ *
+ * Make sure the single step bit is not set.
+ */
+void
+ptrace_disable(struct task_struct *child)
+{
+       unsigned long tmp;
+
+       /* Deconfigure SPC and S-bit. */
+       tmp = get_reg(child, PT_CCS) & ~SBIT_USER;
+       put_reg(child, PT_CCS, tmp);
+       put_reg(child, PT_SPC, 0);
+
+       /* Deconfigure any watchpoints associated with the child. */
+       deconfigure_bp(child->pid);
+}
+
+
+asmlinkage int
+sys_ptrace(long request, long pid, long addr, long data)
+{
+       struct task_struct *child;
+       int ret;
+       unsigned long __user *datap = (unsigned long __user *)data;
+
+       lock_kernel();
+       ret = -EPERM;
+
+       if (request == PTRACE_TRACEME) {
+               /* are we already being traced? */
+               if (current->ptrace & PT_PTRACED)
+                       goto out;
+               ret = security_ptrace(current->parent, current);
+               if (ret)
+                       goto out;
+               /* set the ptrace bit in the process flags. */
+               current->ptrace |= PT_PTRACED;
+               ret = 0;
+               goto out;
+       }
+
+       ret = -ESRCH;
+       read_lock(&tasklist_lock);
+       child = find_task_by_pid(pid);
+
+       if (child)
+               get_task_struct(child);
+
+       read_unlock(&tasklist_lock);
+
+       if (!child)
+               goto out;
+
+       ret = -EPERM;
+
+       if (pid == 1)           /* Leave the init process alone! */
+               goto out_tsk;
+
+       if (request == PTRACE_ATTACH) {
+               ret = ptrace_attach(child);
+               goto out_tsk;
+       }
+
+       ret = ptrace_check_attach(child, request == PTRACE_KILL);
+       if (ret < 0)
+               goto out_tsk;
+
+       switch (request) {
+               /* Read word at location address. */
+               case PTRACE_PEEKTEXT:
+               case PTRACE_PEEKDATA: {
+                       unsigned long tmp;
+                       int copied;
+
+                       ret = -EIO;
+
+                       /* The signal trampoline page is outside the normal 
user-addressable
+                        * space but still accessible. This is hack to make it 
possible to
+                        * access the signal handler code in GDB.
+                        */
+                       if ((addr & PAGE_MASK) == cris_signal_return_page) {
+                               /* The trampoline page is globally mapped, no 
page table to traverse.*/
+                               tmp = *(unsigned long*)addr;
+                       } else {
+                               copied = access_process_vm(child, addr, &tmp, 
sizeof(tmp), 0);
+
+                               if (copied != sizeof(tmp))
+                                       break;
+                       }
+
+                       ret = put_user(tmp,datap);
+                       break;
+               }
+
+               /* Read the word at location address in the USER area. */
+               case PTRACE_PEEKUSR: {
+                       unsigned long tmp;
+
+                       ret = -EIO;
+                       if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+                               break;
+
+                       tmp = get_reg(child, addr >> 2);
+                       ret = put_user(tmp, datap);
+                       break;
+               }
+
+               /* Write the word at location address. */
+               case PTRACE_POKETEXT:
+               case PTRACE_POKEDATA:
+                       ret = 0;
+
+                       if (access_process_vm(child, addr, &data, sizeof(data), 
1) == sizeof(data))
+                               break;
+
+                       ret = -EIO;
+                       break;
+
+               /* Write the word at location address in the USER area. */
+               case PTRACE_POKEUSR:
+                       ret = -EIO;
+                       if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
+                               break;
+
+                       addr >>= 2;
+
+                       if (addr == PT_CCS) {
+                               /* don't allow the tracing process to change 
stuff like
+                                * interrupt enable, kernel/user bit, dma 
enables etc.
+                                */
+                               data &= CCS_MASK;
+                               data |= get_reg(child, PT_CCS) & ~CCS_MASK;
+                       }
+                       if (put_reg(child, addr, data))
+                               break;
+                       ret = 0;
+                       break;
+
+               case PTRACE_SYSCALL:
+               case PTRACE_CONT:
+                       ret = -EIO;
+
+                       if (!valid_signal(data))
+                               break;
+
+                       /* Continue means no single-step. */
+                       put_reg(child, PT_SPC, 0);
+
+                       if (!get_debugreg(child->pid, PT_BP_CTRL)) {
+                               unsigned long tmp;
+                               /* If no h/w bp configured, disable S bit. */
+                               tmp = get_reg(child, PT_CCS) & ~SBIT_USER;
+                               put_reg(child, PT_CCS, tmp);
+                       }
+
+                       if (request == PTRACE_SYSCALL) {
+                               set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+                       }
+                       else {
+                               clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+                       }
+
+                       child->exit_code = data;
+
+                       /* TODO: make sure any pending breakpoint is killed */
+                       wake_up_process(child);
+                       ret = 0;
+
+                       break;
+
+               /* Make the child exit by sending it a sigkill. */
+               case PTRACE_KILL:
+                       ret = 0;
+
+                       if (child->exit_state == EXIT_ZOMBIE)
+                               break;
+
+                       child->exit_code = SIGKILL;
+
+                       /* Deconfigure single-step and h/w bp. */
+                       ptrace_disable(child);
+
+                       /* TODO: make sure any pending breakpoint is killed */
+                       wake_up_process(child);
+                       break;
+
+               /* Set the trap flag. */
+               case PTRACE_SINGLESTEP: {
+                       unsigned long tmp;
+                       ret = -EIO;
+
+                       /* Set up SPC if not set already (in which case we have
+                          no other choice but to trust it). */
+                       if (!get_reg(child, PT_SPC)) {
+                               /* In case we're stopped in a delay slot. */
+                               tmp = get_reg(child, PT_ERP) & ~1;
+                               put_reg(child, PT_SPC, tmp);
+                       }
+                       tmp = get_reg(child, PT_CCS) | SBIT_USER;
+                       put_reg(child, PT_CCS, tmp);
+
+                       if (!valid_signal(data))
+                               break;
+
+                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+
+                       /* TODO: set some clever breakpoint mechanism... */
+
+                       child->exit_code = data;
+                       wake_up_process(child);
+                       ret = 0;
+                       break;
+
+               }
+               case PTRACE_DETACH:
+                       ret = ptrace_detach(child, data);
+                       break;
+
+               /* Get all GP registers from the child. */
+               case PTRACE_GETREGS: {
+                       int i;
+                       unsigned long tmp;
+
+                       for (i = 0; i <= PT_MAX; i++) {
+                               tmp = get_reg(child, i);
+
+                               if (put_user(tmp, datap)) {
+                                       ret = -EFAULT;
+                                       goto out_tsk;
+                               }
+
+                               datap++;
+                       }
+
+                       ret = 0;
+                       break;
+               }
+
+               /* Set all GP registers in the child. */
+               case PTRACE_SETREGS: {
+                       int i;
+                       unsigned long tmp;
+
+                       for (i = 0; i <= PT_MAX; i++) {
+                               if (get_user(tmp, datap)) {
+                                       ret = -EFAULT;
+                                       goto out_tsk;
+                               }
+
+                               if (i == PT_CCS) {
+                                       tmp &= CCS_MASK;
+                                       tmp |= get_reg(child, PT_CCS) & 
~CCS_MASK;
+                               }
+
+                               put_reg(child, i, tmp);
+                               datap++;
+                       }
+
+                       ret = 0;
+                       break;
+               }
+
+               default:
+                       ret = ptrace_request(child, request, addr, data);
+                       break;
+       }
+out_tsk:
+       put_task_struct(child);
+out:
+       unlock_kernel();
+       return ret;
+}
+
+void do_syscall_trace(void)
+{
+       if (!test_thread_flag(TIF_SYSCALL_TRACE))
+               return;
+
+       if (!(current->ptrace & PT_PTRACED))
+               return;
+
+       /* the 0x80 provides a way for the tracing parent to distinguish
+          between a syscall stop and SIGTRAP delivery */
+       ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+                                ? 0x80 : 0));
+
+       /*
+        * This isn't the same as continuing with a signal, but it will do for
+        * normal use.
+        */
+       if (current->exit_code) {
+               send_sig(current->exit_code, current, 1);
+               current->exit_code = 0;
+       }
+}
+
+/* Returns the size of an instruction that has a delay slot. */
+
+static int insn_size(struct task_struct *child, unsigned long pc)
+{
+  unsigned long opcode;
+  int copied;
+  int opsize = 0;
+
+  /* Read the opcode at pc (do what PTRACE_PEEKTEXT would do). */
+  copied = access_process_vm(child, pc, &opcode, sizeof(opcode), 0);
+  if (copied != sizeof(opcode))
+    return 0;
+
+  switch ((opcode & 0x0f00) >> 8) {
+  case 0x0:
+  case 0x9:
+  case 0xb:
+         opsize = 2;
+         break;
+  case 0xe:
+  case 0xf:
+         opsize = 6;
+         break;
+  case 0xd:
+         /* Could be 4 or 6; check more bits. */
+         if ((opcode & 0xff) == 0xff)
+                 opsize = 4;
+         else
+                 opsize = 6;
+         break;
+  default:
+         panic("ERROR: Couldn't find size of opcode 0x%lx at 0x%lx\n",
+               opcode, pc);
+  }
+
+  return opsize;
+}
+
+static unsigned long get_pseudo_pc(struct task_struct *child)
+{
+       /* Default value for PC is ERP. */
+       unsigned long pc = get_reg(child, PT_ERP);
+
+       if (pc & 0x1) {
+               unsigned long spc = get_reg(child, PT_SPC);
+               /* Delay slot bit set. Report as stopped on proper
+                  instruction. */
+               if (spc) {
+                       /* Rely on SPC if set. FIXME: We might want to check
+                          that EXS indicates we stopped due to a single-step
+                          exception. */
+                       pc = spc;
+               } else {
+                       /* Calculate the PC from the size of the instruction
+                          that the delay slot we're in belongs to. */
+                       pc += insn_size(child, pc & ~1) - 1;
+               }
+       }
+       return pc;
+}
+
+static long bp_owner = 0;
+
+/* Reachable from exit_thread in signal.c, so not static. */
+void deconfigure_bp(long pid)
+{
+       int bp;
+
+       /* Only deconfigure if the pid is the owner. */
+       if (bp_owner != pid)
+               return;
+
+       for (bp = 0; bp < 6; bp++) {
+               unsigned long tmp;
+               /* Deconfigure start and end address (also gets rid of 
ownership). */
+               put_debugreg(pid, PT_BP + 3 + (bp * 2), 0);
+               put_debugreg(pid, PT_BP + 4 + (bp * 2), 0);
+
+               /* Deconfigure relevant bits in control register. */
+               tmp = get_debugreg(pid, PT_BP_CTRL) & ~(3 << (2 + (bp * 4)));
+               put_debugreg(pid, PT_BP_CTRL, tmp);
+       }
+       /* No owner now. */
+       bp_owner = 0;
+}
+
+static int put_debugreg(long pid, unsigned int regno, long data)
+{
+       int ret = 0;
+       register int old_srs;
+
+#ifdef CONFIG_ETRAX_KGDB
+       /* Ignore write, but pretend it was ok if value is 0
+          (we don't want POKEUSR/SETREGS failing unnessecarily). */
+       return (data == 0) ? ret : -1;
+#endif
+
+       /* Simple owner management. */
+       if (!bp_owner)
+               bp_owner = pid;
+       else if (bp_owner != pid) {
+               /* Ignore write, but pretend it was ok if value is 0
+                  (we don't want POKEUSR/SETREGS failing unnessecarily). */
+               return (data == 0) ? ret : -1;
+       }
+
+       /* Remember old SRS. */
+       SPEC_REG_RD(SPEC_REG_SRS, old_srs);
+       /* Switch to BP bank. */
+       SUPP_BANK_SEL(BANK_BP);
+
+       switch (regno - PT_BP) {
+       case 0:
+               SUPP_REG_WR(0, data); break;
+       case 1:
+       case 2:
+               if (data)
+                       ret = -1;
+               break;
+       case 3:
+               SUPP_REG_WR(3, data); break;
+       case 4:
+               SUPP_REG_WR(4, data); break;
+       case 5:
+               SUPP_REG_WR(5, data); break;
+       case 6:
+               SUPP_REG_WR(6, data); break;
+       case 7:
+               SUPP_REG_WR(7, data); break;
+       case 8:
+               SUPP_REG_WR(8, data); break;
+       case 9:
+               SUPP_REG_WR(9, data); break;
+       case 10:
+               SUPP_REG_WR(10, data); break;
+       case 11:
+               SUPP_REG_WR(11, data); break;
+       case 12:
+               SUPP_REG_WR(12, data); break;
+       case 13:
+               SUPP_REG_WR(13, data); break;
+       case 14:
+               SUPP_REG_WR(14, data); break;
+       default:
+               ret = -1;
+               break;
+       }
+
+       /* Restore SRS. */
+       SPEC_REG_WR(SPEC_REG_SRS, old_srs);
+       /* Just for show. */
+       NOP();
+       NOP();
+       NOP();
+
+       return ret;
+}
+
+static long get_debugreg(long pid, unsigned int regno)
+{
+       register int old_srs;
+       register long data;
+
+       if (pid != bp_owner) {
+               return 0;
+       }
+
+       /* Remember old SRS. */
+       SPEC_REG_RD(SPEC_REG_SRS, old_srs);
+       /* Switch to BP bank. */
+       SUPP_BANK_SEL(BANK_BP);
+
+       switch (regno - PT_BP) {
+       case 0:
+               SUPP_REG_RD(0, data); break;
+       case 1:
+       case 2:
+               /* error return value? */
+               data = 0;
+               break;
+       case 3:
+               SUPP_REG_RD(3, data); break;
+       case 4:
+               SUPP_REG_RD(4, data); break;
+       case 5:
+               SUPP_REG_RD(5, data); break;
+       case 6:
+               SUPP_REG_RD(6, data); break;
+       case 7:
+               SUPP_REG_RD(7, data); break;
+       case 8:
+               SUPP_REG_RD(8, data); break;
+       case 9:
+               SUPP_REG_RD(9, data); break;
+       case 10:
+               SUPP_REG_RD(10, data); break;
+       case 11:
+               SUPP_REG_RD(11, data); break;
+       case 12:
+               SUPP_REG_RD(12, data); break;
+       case 13:
+               SUPP_REG_RD(13, data); break;
+       case 14:
+               SUPP_REG_RD(14, data); break;
+       default:
+               /* error return value? */
+               data = 0;
+       }
+
+       /* Restore SRS. */
+       SPEC_REG_WR(SPEC_REG_SRS, old_srs);
+       /* Just for show. */
+       NOP();
+       NOP();
+       NOP();
+
+       return data;
+}
diff -urN linux/arch/cris/arch-v32/kernel/setup.c 
linux/arch/cris/arch-v32/kernel/setup.c
--- linux/arch/cris/arch-v32/kernel/setup.c     1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/setup.c     2005-08-01 19:23:43.210318000 
+0100     1.1
@@ -0,0 +1,118 @@
+/*
+ * Display CPU info in /proc/cpuinfo.
+ *
+ * Copyright (C) 2003, Axis Communications AB.
+ */
+
+#include <linux/config.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/param.h>
+
+#ifdef CONFIG_PROC_FS
+
+#define HAS_FPU         0x0001
+#define HAS_MMU         0x0002
+#define HAS_ETHERNET100 0x0004
+#define HAS_TOKENRING   0x0008
+#define HAS_SCSI        0x0010
+#define HAS_ATA         0x0020
+#define HAS_USB         0x0040
+#define HAS_IRQ_BUG     0x0080
+#define HAS_MMU_BUG     0x0100
+
+struct cpu_info {
+       char *cpu_model;
+       unsigned short rev;
+       unsigned short cache_size;
+       unsigned short flags;
+};
+
+/* Some of these model are here for historical reasons only. */
+static struct cpu_info cpinfo[] = {
+       {"ETRAX 1", 0, 0, 0},
+       {"ETRAX 2", 1, 0, 0},
+       {"ETRAX 3", 2, 0, 0},
+       {"ETRAX 4", 3, 0, 0},
+       {"Simulator", 7, 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA},
+       {"ETRAX 100", 8, 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG},
+       {"ETRAX 100", 9, 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA},
+
+       {"ETRAX 100LX", 10, 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB
+                            | HAS_MMU | HAS_MMU_BUG},
+
+       {"ETRAX 100LX v2", 11, 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB
+                               | HAS_MMU},
+
+       {"ETRAX FS", 32, 32, HAS_ETHERNET100 | HAS_ATA | HAS_MMU},
+
+       {"Unknown", 0, 0, 0}
+};
+
+int
+show_cpuinfo(struct seq_file *m, void *v)
+{
+       int i;
+       int cpu = (int)v - 1;
+       int entries;
+       unsigned long revision;
+       struct cpu_info *info;
+
+       entries = sizeof cpinfo / sizeof(struct cpu_info);
+       info = &cpinfo[entries - 1];
+
+#ifdef CONFIG_SMP
+       if (!cpu_online(cpu))
+               return 0;
+#endif
+
+       revision = rdvr();
+
+       for (i = 0; i < entries; i++) {
+               if (cpinfo[i].rev == revision) {
+                       info = &cpinfo[i];
+                       break;
+               }
+       }
+
+       return seq_printf(m,
+               "processor\t: %d\n"
+               "cpu\t\t: CRIS\n"
+               "cpu revision\t: %lu\n"
+               "cpu model\t: %s\n"
+               "cache size\t: %d KB\n"
+               "fpu\t\t: %s\n"
+               "mmu\t\t: %s\n"
+               "mmu DMA bug\t: %s\n"
+               "ethernet\t: %s Mbps\n"
+               "token ring\t: %s\n"
+               "scsi\t\t: %s\n"
+               "ata\t\t: %s\n"
+               "usb\t\t: %s\n"
+               "bogomips\t: %lu.%02lu\n\n",
+
+               cpu,
+               revision,
+               info->cpu_model,
+               info->cache_size,
+               info->flags & HAS_FPU ? "yes" : "no",
+               info->flags & HAS_MMU ? "yes" : "no",
+               info->flags & HAS_MMU_BUG ? "yes" : "no",
+               info->flags & HAS_ETHERNET100 ? "10/100" : "10",
+               info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no",
+               info->flags & HAS_SCSI ? "yes" : "no",
+               info->flags & HAS_ATA ? "yes" : "no",
+               info->flags & HAS_USB ? "yes" : "no",
+               (loops_per_jiffy * HZ + 500) / 500000,
+               ((loops_per_jiffy * HZ + 500) / 5000) % 100);
+}
+
+#endif /* CONFIG_PROC_FS */
+
+void
+show_etrax_copyright(void)
+{
+       printk(KERN_INFO
+               "Linux/CRISv32 port on ETRAX FS (C) 2003, 2004 Axis 
Communications AB\n");
+}
diff -urN linux/arch/cris/arch-v32/kernel/signal.c 
linux/arch/cris/arch-v32/kernel/signal.c
--- linux/arch/cris/arch-v32/kernel/signal.c    1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/signal.c    2005-08-01 19:23:43.233417000 
+0100     1.1
@@ -0,0 +1,708 @@
+/*
+ * Copyright (C) 2003, Axis Communications AB.
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/syscalls.h>
+#include <linux/vmalloc.h>
+
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+#include <asm/arch/ptrace.h>
+#include <asm/arch/hwregs/cpu_vect.h>
+
+extern unsigned long cris_signal_return_page;
+
+/* Flag to check if a signal is blockable. */
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+/*
+ * A syscall in CRIS is really a "break 13" instruction, which is 2
+ * bytes. The registers is manipulated so upon return the instruction
+ * will be executed again.
+ *
+ * This relies on that PC points to the instruction after the break call.
+ */
+#define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->erp -= 2;
+
+/* Signal frames. */
+struct signal_frame {
+       struct sigcontext sc;
+       unsigned long extramask[_NSIG_WORDS - 1];
+       unsigned char retcode[8];       /* Trampoline code. */
+};
+
+struct rt_signal_frame {
+       struct siginfo *pinfo;
+       void *puc;
+       struct siginfo info;
+       struct ucontext uc;
+       unsigned char retcode[8];       /* Trampoline code. */
+};
+
+int do_signal(int restart, sigset_t *oldset, struct pt_regs *regs);
+void keep_debug_flags(unsigned long oldccs, unsigned long oldspc,
+                     struct pt_regs *regs);
+/*
+ * Swap in the new signal mask, and wait for a signal. Define some
+ * dummy arguments to be able to reach the regs argument.
+ */
+int
+sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof,
+              long srp, struct pt_regs *regs)
+{
+       sigset_t saveset;
+
+       mask &= _BLOCKABLE;
+
+       spin_lock_irq(&current->sighand->siglock);
+
+       saveset = current->blocked;
+
+       siginitset(&current->blocked, mask);
+
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+
+       regs->r10 = -EINTR;
+
+       while (1) {
+               current->state = TASK_INTERRUPTIBLE;
+               schedule();
+
+               if (do_signal(0, &saveset, regs)) {
+                       /*
+                        * This point is reached twice: once to call
+                        * the signal handler, then again to return
+                        * from the sigsuspend system call. When
+                        * calling the signal handler, R10 hold the
+                        * signal number as set by do_signal(). The
+                        * sigsuspend  call will always return with
+                        * the restored value above; -EINTR.
+                        */
+                       return regs->r10;
+               }
+       }
+}
+
+/* Define some dummy arguments to be able to reach the regs argument. */
+int
+sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13,
+                 long mof, long srp, struct pt_regs *regs)
+{
+       sigset_t saveset;
+       sigset_t newset;
+
+       if (sigsetsize != sizeof(sigset_t))
+               return -EINVAL;
+
+       if (copy_from_user(&newset, unewset, sizeof(newset)))
+               return -EFAULT;
+
+       sigdelsetmask(&newset, ~_BLOCKABLE);
+       spin_lock_irq(&current->sighand->siglock);
+
+       saveset = current->blocked;
+       current->blocked = newset;
+
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+
+       regs->r10 = -EINTR;
+
+       while (1) {
+               current->state = TASK_INTERRUPTIBLE;
+               schedule();
+
+               if (do_signal(0, &saveset, regs)) {
+                       /* See comment in function above. */
+                       return regs->r10;
+               }
+       }
+}
+
+int
+sys_sigaction(int signal, const struct old_sigaction *act,
+             struct old_sigaction *oact)
+{
+       int retval;
+       struct k_sigaction newk;
+       struct k_sigaction oldk;
+
+       if (act) {
+               old_sigset_t mask;
+
+               if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+                   __get_user(newk.sa.sa_handler, &act->sa_handler) ||
+                   __get_user(newk.sa.sa_restorer, &act->sa_restorer))
+                       return -EFAULT;
+
+               __get_user(newk.sa.sa_flags, &act->sa_flags);
+               __get_user(mask, &act->sa_mask);
+               siginitset(&newk.sa.sa_mask, mask);
+       }
+
+       retval = do_sigaction(signal, act ? &newk : NULL, oact ? &oldk : NULL);
+
+       if (!retval && oact) {
+               if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+                   __put_user(oldk.sa.sa_handler, &oact->sa_handler) ||
+                   __put_user(oldk.sa.sa_restorer, &oact->sa_restorer))
+                       return -EFAULT;
+
+               __put_user(oldk.sa.sa_flags, &oact->sa_flags);
+               __put_user(oldk.sa.sa_mask.sig[0], &oact->sa_mask);
+       }
+
+       return retval;
+}
+
+int
+sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
+{
+       return do_sigaltstack(uss, uoss, rdusp());
+}
+
+static int
+restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
+{
+       unsigned int err = 0;
+       unsigned long old_usp;
+
+        /* Always make any pending restarted system calls return -EINTR */
+       current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+       /*
+        * Restore the registers from &sc->regs. sc is already checked
+        * for VERIFY_READ since the signal_frame was previously
+        * checked in sys_sigreturn().
+        */
+       if (__copy_from_user(regs, sc, sizeof(struct pt_regs)))
+               goto badframe;
+
+       /* Make that the user-mode flag is set. */
+       regs->ccs |= (1 << (U_CCS_BITNR + CCS_SHIFT));
+
+       /* Restore the old USP. */
+       err |= __get_user(old_usp, &sc->usp);
+       wrusp(old_usp);
+
+       return err;
+
+badframe:
+       return 1;
+}
+
+/* Define some dummy arguments to be able to reach the regs argument. */
+asmlinkage int
+sys_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp,
+             struct pt_regs *regs)
+{
+       sigset_t set;
+       struct signal_frame __user *frame;
+       unsigned long oldspc = regs->spc;
+       unsigned long oldccs = regs->ccs;
+
+       frame = (struct signal_frame *) rdusp();
+
+       /*
+        * Since the signal is stacked on a dword boundary, the frame
+        * should be dword aligned here as well. It it's not, then the
+        * user is trying some funny business.
+        */
+       if (((long)frame) & 3)
+               goto badframe;
+
+       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+               goto badframe;
+
+       if (__get_user(set.sig[0], &frame->sc.oldmask) ||
+           (_NSIG_WORDS > 1 && __copy_from_user(&set.sig[1],
+                                                frame->extramask,
+                                                sizeof(frame->extramask))))
+               goto badframe;
+
+       sigdelsetmask(&set, ~_BLOCKABLE);
+       spin_lock_irq(&current->sighand->siglock);
+
+       current->blocked = set;
+
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+
+       if (restore_sigcontext(regs, &frame->sc))
+               goto badframe;
+
+       keep_debug_flags(oldccs, oldspc, regs);
+
+       return regs->r10;
+
+badframe:
+       force_sig(SIGSEGV, current);
+       return 0;
+}
+
+/* Define some dummy variables to be able to reach the regs argument. */
+asmlinkage int
+sys_rt_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp,
+                struct pt_regs *regs)
+{
+       sigset_t set;
+       struct rt_signal_frame __user *frame;
+       unsigned long oldspc = regs->spc;
+       unsigned long oldccs = regs->ccs;
+
+       frame = (struct rt_signal_frame *) rdusp();
+
+       /*
+        * Since the signal is stacked on a dword boundary, the frame
+        * should be dword aligned here as well. It it's not, then the
+        * user is trying some funny business.
+        */
+       if (((long)frame) & 3)
+               goto badframe;
+
+       if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+               goto badframe;
+
+       if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+               goto badframe;
+
+       sigdelsetmask(&set, ~_BLOCKABLE);
+       spin_lock_irq(&current->sighand->siglock);
+
+       current->blocked = set;
+
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+
+       if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
+               goto badframe;
+
+       if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT)
+               goto badframe;
+
+       keep_debug_flags(oldccs, oldspc, regs);
+
+       return regs->r10;
+
+badframe:
+       force_sig(SIGSEGV, current);
+       return 0;
+}
+
+/* Setup a signal frame. */
+static int
+setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
+                unsigned long mask)
+{
+       int err;
+       unsigned long usp;
+
+       err = 0;
+       usp = rdusp();
+
+       /*
+        * Copy the registers. They are located first in sc, so it's
+        * possible to use sc directly.
+        */
+       err |= __copy_to_user(sc, regs, sizeof(struct pt_regs));
+
+       err |= __put_user(mask, &sc->oldmask);
+       err |= __put_user(usp, &sc->usp);
+
+       return err;
+}
+
+/* Figure out where to put the new signal frame - usually on the stack. */
+static inline void __user *
+get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
+{
+       unsigned long sp;
+
+       sp = rdusp();
+
+       /* This is the X/Open sanctioned signal stack switching. */
+       if (ka->sa.sa_flags & SA_ONSTACK) {
+               if (!on_sig_stack(sp))
+                       sp = current->sas_ss_sp + current->sas_ss_size;
+       }
+
+       /* Make sure the frame is dword-aligned. */
+       sp &= ~3;
+
+       return (void __user *)(sp - frame_size);
+}
+
+/* Grab and setup a signal frame.
+ *
+ * Basically a lot of state-info is stacked, and arranged for the
+ * user-mode program to return to the kernel using either a trampiline
+ * which performs the syscall sigreturn(), or a provided user-mode
+ * trampoline.
+  */
+static void
+setup_frame(int sig, struct k_sigaction *ka,  sigset_t *set,
+           struct pt_regs * regs)
+{
+       int err;
+       unsigned long return_ip;
+       struct signal_frame __user *frame;
+
+       err = 0;
+       frame = get_sigframe(ka, regs, sizeof(*frame));
+
+       if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+               goto give_sigsegv;
+
+       err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
+
+       if (err)
+               goto give_sigsegv;
+
+       if (_NSIG_WORDS > 1) {
+               err |= __copy_to_user(frame->extramask, &set->sig[1],
+                                     sizeof(frame->extramask));
+       }
+
+       if (err)
+               goto give_sigsegv;
+
+       /*
+        * Set up to return from user-space. If provided, use a stub
+        * already located in user-space.
+        */
+       if (ka->sa.sa_flags & SA_RESTORER) {
+               return_ip = (unsigned long)ka->sa.sa_restorer;
+       } else {
+               /* Trampoline - the desired return ip is in the signal return 
page. */
+               return_ip = cris_signal_return_page;
+
+               /*
+                * This is movu.w __NR_sigreturn, r9; break 13;
+                *
+                * WE DO NOT USE IT ANY MORE! It's only left here for historical
+                * reasons and because gdb uses it as a signature to notice
+                * signal handler stack frames.
+                */
+               err |= __put_user(0x9c5f,         (short 
__user*)(frame->retcode+0));
+               err |= __put_user(__NR_sigreturn, (short 
__user*)(frame->retcode+2));
+               err |= __put_user(0xe93d,         (short 
__user*)(frame->retcode+4));
+       }
+
+       if (err)
+               goto give_sigsegv;
+
+       /*
+        * Set up registers for signal handler.
+        *
+        * Where the code enters now.
+        * Where the code enter later.
+        * First argument, signo.
+        */
+       regs->erp = (unsigned long) ka->sa.sa_handler;
+       regs->srp = return_ip;
+       regs->r10 = sig;
+
+       /* Actually move the USP to reflect the stacked frame. */
+       wrusp((unsigned long)frame);
+
+       return;
+
+give_sigsegv:
+       if (sig == SIGSEGV)
+               ka->sa.sa_handler = SIG_DFL;
+
+       force_sig(SIGSEGV, current);
+}
+
+static void
+setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+              sigset_t *set, struct pt_regs * regs)
+{
+       int err;
+       unsigned long return_ip;
+       struct rt_signal_frame __user *frame;
+
+       err = 0;
+       frame = get_sigframe(ka, regs, sizeof(*frame));
+
+       if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+               goto give_sigsegv;
+
+       /* TODO: what is the current->exec_domain stuff and invmap ? */
+
+       err |= __put_user(&frame->info, &frame->pinfo);
+       err |= __put_user(&frame->uc, &frame->puc);
+       err |= copy_siginfo_to_user(&frame->info, info);
+
+       if (err)
+               goto give_sigsegv;
+
+       /* Clear all the bits of the ucontext we don't use.  */
+       err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
+       err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
+       err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+       if (err)
+               goto give_sigsegv;
+
+       /*
+        * Set up to return from user-space. If provided, use a stub
+        * already located in user-space.
+        */
+       if (ka->sa.sa_flags & SA_RESTORER) {
+               return_ip = (unsigned long) ka->sa.sa_restorer;
+       } else {
+               /* Trampoline - the desired return ip is in the signal return 
page. */
+               return_ip = cris_signal_return_page + 6;
+
+               /*
+                * This is movu.w __NR_rt_sigreturn, r9; break 13;
+                *
+                * WE DO NOT USE IT ANY MORE! It's only left here for historical
+                * reasons and because gdb uses it as a signature to notice
+                * signal handler stack frames.
+                */
+               err |= __put_user(0x9c5f, (short __user*)(frame->retcode+0));
+
+               err |= __put_user(__NR_rt_sigreturn,
+                                 (short __user*)(frame->retcode+2));
+
+               err |= __put_user(0xe93d, (short __user*)(frame->retcode+4));
+       }
+
+       if (err)
+               goto give_sigsegv;
+
+       /*
+        * Set up registers for signal handler.
+        *
+        * Where the code enters now.
+        * Where the code enters later.
+        * First argument is signo.
+        * Second argument is (siginfo_t *).
+        * Third argument is unused.
+        */
+       regs->erp = (unsigned long) ka->sa.sa_handler;
+       regs->srp = return_ip;
+       regs->r10 = sig;
+       regs->r11 = (unsigned long) &frame->info;
+       regs->r12 = 0;
+
+       /* Actually move the usp to reflect the stacked frame. */
+       wrusp((unsigned long)frame);
+
+       return;
+
+give_sigsegv:
+       if (sig == SIGSEGV)
+               ka->sa.sa_handler = SIG_DFL;
+
+       force_sig(SIGSEGV, current);
+}
+
+/* Invoke a singal handler to, well, handle the signal. */
+extern inline void
+handle_signal(int canrestart, unsigned long sig,
+             siginfo_t *info, struct k_sigaction *ka,
+              sigset_t *oldset, struct pt_regs * regs)
+{
+       /* Check if this got called from a system call. */
+       if (canrestart) {
+               /* If so, check system call restarting. */
+               switch (regs->r10) {
+                       case -ERESTART_RESTARTBLOCK:
+                       case -ERESTARTNOHAND:
+                               /*
+                                * This means that the syscall should
+                                * only be restarted if there was no
+                                * handler for the signal, and since
+                                * this point isn't reached unless
+                                * there is a handler, there's no need
+                                * to restart.
+                                */
+                               regs->r10 = -EINTR;
+                               break;
+
+                        case -ERESTARTSYS:
+                               /*
+                                * This means restart the syscall if
+                                 * there is no handler, or the handler
+                                 * was registered with SA_RESTART.
+                                */
+                               if (!(ka->sa.sa_flags & SA_RESTART)) {
+                                       regs->r10 = -EINTR;
+                                       break;
+                               }
+
+                               /* Fall through. */
+
+                       case -ERESTARTNOINTR:
+                               /*
+                                * This means that the syscall should
+                                 * be called again after the signal
+                                 * handler returns.
+                                */
+                               RESTART_CRIS_SYS(regs);
+                               break;
+                }
+        }
+
+       /* Set up the stack frame. */
+       if (ka->sa.sa_flags & SA_SIGINFO)
+               setup_rt_frame(sig, ka, info, oldset, regs);
+       else
+               setup_frame(sig, ka, oldset, regs);
+
+       if (ka->sa.sa_flags & SA_ONESHOT)
+               ka->sa.sa_handler = SIG_DFL;
+
+       if (!(ka->sa.sa_flags & SA_NODEFER)) {
+               spin_lock_irq(&current->sighand->siglock);
+               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+               sigaddset(&current->blocked,sig);
+               recalc_sigpending();
+               spin_unlock_irq(&current->sighand->siglock);
+       }
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ *
+ * Also note that the regs structure given here as an argument, is the latest
+ * pushed pt_regs. It may or may not be the same as the first pushed registers
+ * when the initial usermode->kernelmode transition took place. Therefore
+ * we can use user_mode(regs) to see if we came directly from kernel or user
+ * mode below.
+ */
+int
+do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
+{
+       int signr;
+       siginfo_t info;
+        struct k_sigaction ka;
+
+       /*
+        * The common case should go fast, which is why this point is
+        * reached from kernel-mode. If that's the case, just return
+        * without doing anything.
+        */
+       if (!user_mode(regs))
+               return 1;
+
+       if (!oldset)
+               oldset = &current->blocked;
+
+       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+
+       if (signr > 0) {
+               /* Deliver the signal. */
+               handle_signal(canrestart, signr, &info, &ka, oldset, regs);
+               return 1;
+       }
+
+       /* Got here from a system call? */
+       if (canrestart) {
+               /* Restart the system call - no handlers present. */
+               if (regs->r10 == -ERESTARTNOHAND ||
+                   regs->r10 == -ERESTARTSYS ||
+                   regs->r10 == -ERESTARTNOINTR) {
+                       RESTART_CRIS_SYS(regs);
+               }
+
+               if (regs->r10 == -ERESTART_RESTARTBLOCK){
+                       regs->r10 = __NR_restart_syscall;
+                       regs->erp -= 2;
+               }
+       }
+
+       return 0;
+}
+
+asmlinkage void
+ugdb_trap_user(struct thread_info *ti, int sig)
+{
+       if (((user_regs(ti)->exs & 0xff00) >> 8) != SINGLE_STEP_INTR_VECT) {
+               /* Zero single-step PC if the reason we stopped wasn't a single
+                  step exception. This is to avoid relying on it when it isn't
+                  reliable. */
+               user_regs(ti)->spc = 0;
+       }
+       /* FIXME: Filter out false h/w breakpoint hits (i.e. EDA
+          not withing any configured h/w breakpoint range). Synchronize with
+          what already exists for kernel debugging.  */
+       if (((user_regs(ti)->exs & 0xff00) >> 8) == BREAK_8_INTR_VECT) {
+               /* Break 8: subtract 2 from ERP unless in a delay slot. */
+               if (!(user_regs(ti)->erp & 0x1))
+                       user_regs(ti)->erp -= 2;
+       }
+       sys_kill(ti->task->pid, sig);
+}
+
+void
+keep_debug_flags(unsigned long oldccs, unsigned long oldspc,
+                struct pt_regs *regs)
+{
+       if (oldccs & (1 << Q_CCS_BITNR)) {
+               /* Pending single step due to single-stepping the break 13
+                  in the signal trampoline: keep the Q flag. */
+               regs->ccs |= (1 << Q_CCS_BITNR);
+               /* S flag should be set - complain if it's not. */
+               if (!(oldccs & (1 << (S_CCS_BITNR + CCS_SHIFT)))) {
+                       printk("Q flag but no S flag?");
+               }
+               regs->ccs |= (1 << (S_CCS_BITNR + CCS_SHIFT));
+               /* Assume the SPC is valid and interesting. */
+               regs->spc = oldspc;
+
+       } else if (oldccs & (1 << (S_CCS_BITNR + CCS_SHIFT))) {
+               /* If a h/w bp was set in the signal handler we need
+                  to keep the S flag. */
+               regs->ccs |= (1 << (S_CCS_BITNR + CCS_SHIFT));
+               /* Don't keep the old SPC though; if we got here due to
+                  a single-step, the Q flag should have been set. */
+       } else if (regs->spc) {
+               /* If we were single-stepping *before* the signal was taken,
+                  we don't want to restore that state now, because GDB will
+                  have forgotten all about it. */
+               regs->spc = 0;
+               regs->ccs &= ~(1 << (S_CCS_BITNR + CCS_SHIFT));
+       }
+}
+
+/* Set up the trampolines on the signal return page. */
+int __init
+cris_init_signal(void)
+{
+       u16* data = (u16*)kmalloc(PAGE_SIZE, GFP_KERNEL);
+
+       /* This is movu.w __NR_sigreturn, r9; break 13; */
+       data[0] = 0x9c5f;
+       data[1] = __NR_sigreturn;
+       data[2] = 0xe93d;
+       /* This is movu.w __NR_rt_sigreturn, r9; break 13; */
+       data[3] = 0x9c5f;
+       data[4] = __NR_rt_sigreturn;
+       data[5] = 0xe93d;
+
+       /* Map to userspace with appropriate permissions (no write access...) */
+       cris_signal_return_page = (unsigned long)
+          __ioremap_prot(virt_to_phys(data), PAGE_SIZE, 
PAGE_SIGNAL_TRAMPOLINE);
+
+       return 0;
+}
+
+__initcall(cris_init_signal);
diff -urN linux/arch/cris/arch-v32/kernel/smp.c 
linux/arch/cris/arch-v32/kernel/smp.c
--- linux/arch/cris/arch-v32/kernel/smp.c       1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/smp.c       2005-08-01 19:23:43.258321000 
+0100     1.1
@@ -0,0 +1,348 @@
+#include <asm/delay.h>
+#include <asm/arch/irq.h>
+#include <asm/arch/hwregs/intr_vect.h>
+#include <asm/arch/hwregs/intr_vect_defs.h>
+#include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
+#include <asm/arch/hwregs/mmu_defs_asm.h>
+#include <asm/arch/hwregs/supp_reg.h>
+#include <asm/atomic.h>
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/timex.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/cpumask.h>
+#include <linux/interrupt.h>
+
+#define IPI_SCHEDULE 1
+#define IPI_CALL 2
+#define IPI_FLUSH_TLB 4
+
+#define FLUSH_ALL (void*)0xffffffff
+
+/* Vector of locks used for various atomic operations */
+spinlock_t cris_atomic_locks[] = { [0 ... LOCK_COUNT - 1] = 
SPIN_LOCK_UNLOCKED};
+
+/* CPU masks */
+cpumask_t cpu_online_map = CPU_MASK_NONE;
+cpumask_t phys_cpu_present_map = CPU_MASK_NONE;
+
+/* Variables used during SMP boot */
+volatile int cpu_now_booting = 0;
+volatile struct thread_info *smp_init_current_idle_thread;
+
+/* Variables used during IPI */
+static DEFINE_SPINLOCK(call_lock);
+static DEFINE_SPINLOCK(tlbstate_lock);
+
+struct call_data_struct {
+       void (*func) (void *info);
+       void *info;
+       int wait;
+};
+
+static struct call_data_struct * call_data;
+
+static struct mm_struct* flush_mm;
+static struct vm_area_struct* flush_vma;
+static unsigned long flush_addr;
+
+extern int setup_irq(int, struct irqaction *);
+
+/* Mode registers */
+static unsigned long irq_regs[NR_CPUS] =
+{
+  regi_irq,
+  regi_irq2
+};
+
+static irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id, struct pt_regs 
*regs);
+static int send_ipi(int vector, int wait, cpumask_t cpu_mask);
+static struct irqaction irq_ipi  = { crisv32_ipi_interrupt, SA_INTERRUPT,
+                                     CPU_MASK_NONE, "ipi", NULL, NULL};
+
+extern void cris_mmu_init(void);
+extern void cris_timer_init(void);
+
+/* SMP initialization */
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+       int i;
+
+       /* From now on we can expect IPIs so set them up */
+       setup_irq(IPI_INTR_VECT, &irq_ipi);
+
+       /* Mark all possible CPUs as present */
+       for (i = 0; i < max_cpus; i++)
+           cpu_set(i, phys_cpu_present_map);
+}
+
+void __devinit smp_prepare_boot_cpu(void)
+{
+       /* PGD pointer has moved after per_cpu initialization so
+        * update the MMU.
+        */
+       pgd_t **pgd;
+       pgd = (pgd_t**)&per_cpu(current_pgd, smp_processor_id());
+
+       SUPP_BANK_SEL(1);
+       SUPP_REG_WR(RW_MM_TLB_PGD, pgd);
+       SUPP_BANK_SEL(2);
+       SUPP_REG_WR(RW_MM_TLB_PGD, pgd);
+
+       cpu_set(0, cpu_online_map);
+       cpu_set(0, phys_cpu_present_map);
+}
+
+void __init smp_cpus_done(unsigned int max_cpus)
+{
+}
+
+/* Bring one cpu online.*/
+static int __init
+smp_boot_one_cpu(int cpuid)
+{
+       unsigned timeout;
+       struct task_struct *idle;
+
+       idle = fork_idle(cpuid);
+       if (IS_ERR(idle))
+               panic("SMP: fork failed for CPU:%d", cpuid);
+
+       idle->thread_info->cpu = cpuid;
+
+       /* Information to the CPU that is about to boot */
+       smp_init_current_idle_thread = idle->thread_info;
+       cpu_now_booting = cpuid;
+
+       /* Wait for CPU to come online */
+       for (timeout = 0; timeout < 10000; timeout++) {
+               if(cpu_online(cpuid)) {
+                       cpu_now_booting = 0;
+                       smp_init_current_idle_thread = NULL;
+                       return 0; /* CPU online */
+               }
+               udelay(100);
+               barrier();
+       }
+
+       put_task_struct(idle);
+       idle = NULL;
+
+       printk(KERN_CRIT "SMP: CPU:%d is stuck.\n", cpuid);
+       return -1;
+}
+
+/* Secondary CPUs starts uing C here. Here we need to setup CPU
+ * specific stuff such as the local timer and the MMU. */
+void __init smp_callin(void)
+{
+       extern void cpu_idle(void);
+
+       int cpu = cpu_now_booting;
+       reg_intr_vect_rw_mask vect_mask = {0};
+
+       /* Initialise the idle task for this CPU */
+       atomic_inc(&init_mm.mm_count);
+       current->active_mm = &init_mm;
+
+       /* Set up MMU */
+       cris_mmu_init();
+       __flush_tlb_all();
+
+       /* Setup local timer. */
+       cris_timer_init();
+
+       /* Enable IRQ and idle */
+       REG_WR(intr_vect, irq_regs[cpu], rw_mask, vect_mask);
+       unmask_irq(IPI_INTR_VECT);
+       unmask_irq(TIMER_INTR_VECT);
+       local_irq_enable();
+
+       cpu_set(cpu, cpu_online_map);
+       cpu_idle();
+}
+
+/* Stop execution on this CPU.*/
+void stop_this_cpu(void* dummy)
+{
+       local_irq_disable();
+       asm volatile("halt");
+}
+
+/* Other calls */
+void smp_send_stop(void)
+{
+       smp_call_function(stop_this_cpu, NULL, 1, 0);
+}
+
+int setup_profiling_timer(unsigned int multiplier)
+{
+       return -EINVAL;
+}
+
+
+/* cache_decay_ticks is used by the scheduler to decide if a process
+ * is "hot" on one CPU. A higher value means a higher penalty to move
+ * a process to another CPU. Our cache is rather small so we report
+ * 1 tick.
+ */
+unsigned long cache_decay_ticks = 1;
+
+int __devinit __cpu_up(unsigned int cpu)
+{
+       smp_boot_one_cpu(cpu);
+       return cpu_online(cpu) ? 0 : -ENOSYS;
+}
+
+void smp_send_reschedule(int cpu)
+{
+       cpumask_t cpu_mask = CPU_MASK_NONE;
+       cpu_set(cpu, cpu_mask);
+       send_ipi(IPI_SCHEDULE, 0, cpu_mask);
+}
+
+/* TLB flushing
+ *
+ * Flush needs to be done on the local CPU and on any other CPU that
+ * may have the same mapping. The mm->cpu_vm_mask is used to keep track
+ * of which CPUs that a specific process has been executed on.
+ */
+void flush_tlb_common(struct mm_struct* mm, struct vm_area_struct* vma, 
unsigned long addr)
+{
+       unsigned long flags;
+       cpumask_t cpu_mask;
+
+       spin_lock_irqsave(&tlbstate_lock, flags);
+       cpu_mask = (mm == FLUSH_ALL ? CPU_MASK_ALL : mm->cpu_vm_mask);
+       cpu_clear(smp_processor_id(), cpu_mask);
+       flush_mm = mm;
+       flush_vma = vma;
+       flush_addr = addr;
+       send_ipi(IPI_FLUSH_TLB, 1, cpu_mask);
+       spin_unlock_irqrestore(&tlbstate_lock, flags);
+}
+
+void flush_tlb_all(void)
+{
+       __flush_tlb_all();
+       flush_tlb_common(FLUSH_ALL, FLUSH_ALL, 0);
+}
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+       __flush_tlb_mm(mm);
+       flush_tlb_common(mm, FLUSH_ALL, 0);
+       /* No more mappings in other CPUs */
+       cpus_clear(mm->cpu_vm_mask);
+       cpu_set(smp_processor_id(), mm->cpu_vm_mask);
+}
+
+void flush_tlb_page(struct vm_area_struct *vma,
+                          unsigned long addr)
+{
+       __flush_tlb_page(vma, addr);
+       flush_tlb_common(vma->vm_mm, vma, addr);
+}
+
+/* Inter processor interrupts
+ *
+ * The IPIs are used for:
+ *   * Force a schedule on a CPU
+ *   * FLush TLB on other CPUs
+ *   * Call a function on other CPUs
+ */
+
+int send_ipi(int vector, int wait, cpumask_t cpu_mask)
+{
+       int i = 0;
+       reg_intr_vect_rw_ipi ipi = REG_RD(intr_vect, irq_regs[i], rw_ipi);
+       int ret = 0;
+
+       /* Calculate CPUs to send to. */
+       cpus_and(cpu_mask, cpu_mask, cpu_online_map);
+
+       /* Send the IPI. */
+       for_each_cpu_mask(i, cpu_mask)
+       {
+               ipi.vector |= vector;
+               REG_WR(intr_vect, irq_regs[i], rw_ipi, ipi);
+       }
+
+       /* Wait for IPI to finish on other CPUS */
+       if (wait) {
+               for_each_cpu_mask(i, cpu_mask) {
+                        int j;
+                        for (j = 0 ; j < 1000; j++) {
+                               ipi = REG_RD(intr_vect, irq_regs[i], rw_ipi);
+                               if (!ipi.vector)
+                                       break;
+                               udelay(100);
+                       }
+
+                       /* Timeout? */
+                       if (ipi.vector) {
+                               printk("SMP call timeout from %d to %d\n", 
smp_processor_id(), i);
+                               ret = -ETIMEDOUT;
+                               dump_stack();
+                       }
+               }
+       }
+       return ret;
+}
+
+/*
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler or from a bottom half handler.
+ */
+int smp_call_function(void (*func)(void *info), void *info,
+                     int nonatomic, int wait)
+{
+       cpumask_t cpu_mask = CPU_MASK_ALL;
+       struct call_data_struct data;
+       int ret;
+
+       cpu_clear(smp_processor_id(), cpu_mask);
+
+       WARN_ON(irqs_disabled());
+
+       data.func = func;
+       data.info = info;
+       data.wait = wait;
+
+       spin_lock(&call_lock);
+       call_data = &data;
+       ret = send_ipi(IPI_CALL, wait, cpu_mask);
+       spin_unlock(&call_lock);
+
+       return ret;
+}
+
+irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       void (*func) (void *info) = call_data->func;
+       void *info = call_data->info;
+       reg_intr_vect_rw_ipi ipi;
+
+       ipi = REG_RD(intr_vect, irq_regs[smp_processor_id()], rw_ipi);
+
+       if (ipi.vector & IPI_CALL) {
+                func(info);
+       }
+       if (ipi.vector & IPI_FLUSH_TLB) {
+                    if (flush_mm == FLUSH_ALL)
+                        __flush_tlb_all();
+                    else if (flush_vma == FLUSH_ALL)
+                       __flush_tlb_mm(flush_mm);
+                    else
+                       __flush_tlb_page(flush_vma, flush_addr);
+       }
+
+       ipi.vector = 0;
+       REG_WR(intr_vect, irq_regs[smp_processor_id()], rw_ipi, ipi);
+
+       return IRQ_HANDLED;
+}
+
diff -urN linux/arch/cris/arch-v32/kernel/time.c 
linux/arch/cris/arch-v32/kernel/time.c
--- linux/arch/cris/arch-v32/kernel/time.c      1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/time.c      2005-08-01 19:23:43.288766000 
+0100     1.1
@@ -0,0 +1,341 @@
+/* $Id: time.c,v 1.19 2005/04/29 05:40:09 starvik Exp $
+ *
+ *  linux/arch/cris/arch-v32/kernel/time.c
+ *
+ *  Copyright (C) 2003 Axis Communications AB
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/timex.h>
+#include <linux/time.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/swap.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/threads.h>
+#include <asm/types.h>
+#include <asm/signal.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/rtc.h>
+#include <asm/irq.h>
+
+#include <asm/arch/hwregs/reg_map.h>
+#include <asm/arch/hwregs/reg_rdwr.h>
+#include <asm/arch/hwregs/timer_defs.h>
+#include <asm/arch/hwregs/intr_vect_defs.h>
+
+/* Watchdog defines */
+#define ETRAX_WD_KEY_MASK 0x7F /* key is 7 bit */
+#define ETRAX_WD_HZ       763 /* watchdog counts at 763 Hz */
+#define ETRAX_WD_CNT      ((2*ETRAX_WD_HZ)/HZ + 1) /* Number of 763 counts 
before watchdog bites */
+
+unsigned long timer_regs[NR_CPUS] =
+{
+  regi_timer,
+#ifdef CONFIG_SMP
+  regi_timer2
+#endif
+};
+
+extern void update_xtime_from_cmos(void);
+extern int set_rtc_mmss(unsigned long nowtime);
+extern int setup_irq(int, struct irqaction *);
+extern int have_rtc;
+
+unsigned long get_ns_in_jiffie(void)
+{
+       reg_timer_r_tmr0_data data;
+       unsigned long ns;
+
+       data = REG_RD(timer, regi_timer, r_tmr0_data);
+       ns = (TIMER0_DIV - data) * 10;
+       return ns;
+}
+
+unsigned long do_slow_gettimeoffset(void)
+{
+       unsigned long count;
+       unsigned long usec_count = 0;
+
+       static unsigned long count_p = TIMER0_DIV;/* for the first call after 
boot */
+       static unsigned long jiffies_p = 0;
+
+       /*
+        * cache volatile jiffies temporarily; we have IRQs turned off.
+        */
+       unsigned long jiffies_t;
+
+       /* The timer interrupt comes from Etrax timer 0. In order to get
+        * better precision, we check the current value. It might have
+        * underflowed already though.
+        */
+
+       count = REG_RD(timer, regi_timer, r_tmr0_data);
+       jiffies_t = jiffies;
+
+       /*
+        * avoiding timer inconsistencies (they are rare, but they happen)...
+        * there are one problem that must be avoided here:
+        *  1. the timer counter underflows
+        */
+       if( jiffies_t == jiffies_p ) {
+               if( count > count_p ) {
+                       /* Timer wrapped, use new count and prescale
+                        * increase the time corresponding to one jiffie
+                        */
+                       usec_count = 1000000/HZ;
+               }
+       } else
+               jiffies_p = jiffies_t;
+        count_p = count;
+       /* Convert timer value to usec */
+       /* 100 MHz timer, divide by 100 to get usec */
+       usec_count +=  (TIMER0_DIV - count) / 100;
+       return usec_count;
+}
+
+/* From timer MDS describing the hardware watchdog:
+ * 4.3.1 Watchdog Operation
+ * The watchdog timer is an 8-bit timer with a configurable start value.
+ * Once started the whatchdog counts downwards with a frequency of 763 Hz
+ * (100/131072 MHz). When the watchdog counts down to 1, it generates an
+ * NMI (Non Maskable Interrupt), and when it counts down to 0, it resets the
+ * chip.
+ */
+/* This gives us 1.3 ms to do something useful when the NMI comes */
+
+/* right now, starting the watchdog is the same as resetting it */
+#define start_watchdog reset_watchdog
+
+#if defined(CONFIG_ETRAX_WATCHDOG)
+static short int watchdog_key = 42;  /* arbitrary 7 bit number */
+#endif
+
+/* number of pages to consider "out of memory". it is normal that the memory
+ * is used though, so put this really low.
+ */
+
+#define WATCHDOG_MIN_FREE_PAGES 8
+
+void
+reset_watchdog(void)
+{
+#if defined(CONFIG_ETRAX_WATCHDOG)
+       reg_timer_rw_wd_ctrl wd_ctrl = { 0 };
+
+       /* only keep watchdog happy as long as we have memory left! */
+       if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) {
+               /* reset the watchdog with the inverse of the old key */
+               watchdog_key ^= ETRAX_WD_KEY_MASK; /* invert key, which is 7 
bits */
+               wd_ctrl.cnt = ETRAX_WD_CNT;
+               wd_ctrl.cmd = regk_timer_start;
+               wd_ctrl.key = watchdog_key;
+               REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl);
+       }
+#endif
+}
+
+/* stop the watchdog - we still need the correct key */
+
+void
+stop_watchdog(void)
+{
+#if defined(CONFIG_ETRAX_WATCHDOG)
+       reg_timer_rw_wd_ctrl wd_ctrl = { 0 };
+       watchdog_key ^= ETRAX_WD_KEY_MASK; /* invert key, which is 7 bits */
+       wd_ctrl.cnt = ETRAX_WD_CNT;
+       wd_ctrl.cmd = regk_timer_stop;
+       wd_ctrl.key = watchdog_key;
+       REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl);
+#endif
+}
+
+extern void show_registers(struct pt_regs *regs);
+
+void
+handle_watchdog_bite(struct pt_regs* regs)
+{
+#if defined(CONFIG_ETRAX_WATCHDOG)
+       extern int cause_of_death;
+
+       raw_printk("Watchdog bite\n");
+
+       /* Check if forced restart or unexpected watchdog */
+       if (cause_of_death == 0xbedead) {
+               while(1);
+       }
+
+       /* Unexpected watchdog, stop the watchdog and dump registers*/
+       stop_watchdog();
+       raw_printk("Oops: bitten by watchdog\n");
+        show_registers(regs);
+#ifndef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+       reset_watchdog();
+#endif
+       while(1) /* nothing */;
+#endif
+}
+
+/* last time the cmos clock got updated */
+static long last_rtc_update = 0;
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+
+//static unsigned short myjiff; /* used by our debug routine print_timestamp */
+
+extern void cris_do_profile(struct pt_regs *regs);
+
+static inline irqreturn_t
+timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       int cpu = smp_processor_id();
+       reg_timer_r_masked_intr masked_intr;
+       reg_timer_rw_ack_intr ack_intr = { 0 };
+
+       /* Check if the timer interrupt is for us (a tmr0 int) */
+       masked_intr = REG_RD(timer, timer_regs[cpu], r_masked_intr);
+       if (!masked_intr.tmr0)
+               return IRQ_NONE;
+
+       /* acknowledge the timer irq */
+       ack_intr.tmr0 = 1;
+       REG_WR(timer, timer_regs[cpu], rw_ack_intr, ack_intr);
+
+       /* reset watchdog otherwise it resets us! */
+       reset_watchdog();
+
+        /* Update statistics. */
+       update_process_times(user_mode(regs));
+
+       cris_do_profile(regs); /* Save profiling information */
+
+       /* The master CPU is responsible for the time keeping. */
+       if (cpu != 0)
+               return IRQ_HANDLED;
+
+       /* call the real timer interrupt handler */
+       do_timer(regs);
+
+       /*
+        * If we have an externally synchronized Linux clock, then update
+        * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+        * called as close as possible to 500 ms before the new second starts.
+        *
+        * The division here is not time critical since it will run once in
+        * 11 minutes
+        */
+       if ((time_status & STA_UNSYNC) == 0 &&
+           xtime.tv_sec > last_rtc_update + 660 &&
+           (xtime.tv_nsec / 1000) >= 500000 - (tick_nsec / 1000) / 2 &&
+           (xtime.tv_nsec / 1000) <= 500000 + (tick_nsec / 1000) / 2) {
+               if (set_rtc_mmss(xtime.tv_sec) == 0)
+                       last_rtc_update = xtime.tv_sec;
+               else
+                       last_rtc_update = xtime.tv_sec - 600; /* do it again in 
60 s */
+       }
+        return IRQ_HANDLED;
+}
+
+/* timer is SA_SHIRQ so drivers can add stuff to the timer irq chain
+ * it needs to be SA_INTERRUPT to make the jiffies update work properly
+ */
+
+static struct irqaction irq_timer  = { timer_interrupt, SA_SHIRQ | 
SA_INTERRUPT,
+                                 CPU_MASK_NONE, "timer", NULL, NULL};
+
+void __init
+cris_timer_init(void)
+{
+       int cpu = smp_processor_id();
+       reg_timer_rw_tmr0_ctrl tmr0_ctrl = { 0 };
+               reg_timer_rw_tmr0_div tmr0_div = TIMER0_DIV;
+       reg_timer_rw_intr_mask timer_intr_mask;
+
+       /* Setup the etrax timers
+        * Base frequency is 100MHz, divider 1000000 -> 100 HZ
+        * We use timer0, so timer1 is free.
+        * The trig timer is used by the fasttimer API if enabled.
+        */
+
+               tmr0_ctrl.op = regk_timer_ld;
+       tmr0_ctrl.freq = regk_timer_f100;
+               REG_WR(timer, timer_regs[cpu], rw_tmr0_div, tmr0_div);
+               REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* 
Load */
+               tmr0_ctrl.op = regk_timer_run;
+               REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* 
Start */
+
+               /* enable the timer irq */
+               timer_intr_mask = REG_RD(timer, timer_regs[cpu], rw_intr_mask);
+               timer_intr_mask.tmr0 = 1;
+               REG_WR(timer, timer_regs[cpu], rw_intr_mask, timer_intr_mask);
+}
+
+void __init
+time_init(void)
+{
+       reg_intr_vect_rw_mask intr_mask;
+
+       /* probe for the RTC and read it if it exists
+        * Before the RTC can be probed the loops_per_usec variable needs
+        * to be initialized to make usleep work. A better value for
+        * loops_per_usec is calculated by the kernel later once the
+        * clock has started.
+        */
+       loops_per_usec = 50;
+
+       if(RTC_INIT() < 0) {
+               /* no RTC, start at 1980 */
+               xtime.tv_sec = 0;
+               xtime.tv_nsec = 0;
+               have_rtc = 0;
+       } else {
+               /* get the current time */
+               have_rtc = 1;
+               update_xtime_from_cmos();
+       }
+
+       /*
+        * Initialize wall_to_monotonic such that adding it to xtime will yield 
zero, the
+        * tv_nsec field must be normalized (i.e., 0 <= nsec < NSEC_PER_SEC).
+        */
+       set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, 
-xtime.tv_nsec);
+
+       /* Start CPU local timer */
+       cris_timer_init();
+
+       /* enable the timer irq in global config */
+       intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
+       intr_mask.timer = 1;
+       REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
+
+       /* now actually register the timer irq handler that calls 
timer_interrupt() */
+
+       setup_irq(TIMER_INTR_VECT, &irq_timer);
+
+       /* enable watchdog if we should use one */
+
+#if defined(CONFIG_ETRAX_WATCHDOG)
+       printk("Enabling watchdog...\n");
+       start_watchdog();
+
+       /* If we use the hardware watchdog, we want to trap it as an NMI
+          and dump registers before it resets us.  For this to happen, we
+          must set the "m" NMI enable flag (which once set, is unset only
+          when an NMI is taken).
+
+          The same goes for the external NMI, but that doesn't have any
+          driver or infrastructure support yet.  */
+        {
+          unsigned long flags;
+          local_save_flags(flags);
+          flags |= (1<<30); /* NMI M flag is at bit 30 */
+          local_irq_restore(flags);
+        }
+#endif
+}
diff -urN linux/arch/cris/arch-v32/kernel/traps.c 
linux/arch/cris/arch-v32/kernel/traps.c
--- linux/arch/cris/arch-v32/kernel/traps.c     1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/traps.c     2005-08-01 19:23:43.313449000 
+0100     1.1
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2003, Axis Communications AB.
+ */
+
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <asm/uaccess.h>
+
+#include <asm/arch/hwregs/supp_reg.h>
+
+extern void reset_watchdog(void);
+extern void stop_watchdog(void);
+
+extern int raw_printk(const char *fmt, ...);
+
+void
+show_registers(struct pt_regs *regs)
+{
+       /*
+        * It's possible to use either the USP register or current->thread.usp.
+        * USP might not correspond to the current proccess for all cases this
+        * function is called, and current->thread.usp isn't up to date for the
+        * current proccess. Experience shows that using USP is the way to go.
+        */
+       unsigned long usp;
+       unsigned long d_mmu_cause;
+       unsigned long i_mmu_cause;
+
+       usp = rdusp();
+
+       raw_printk("CPU: %d\n", smp_processor_id());
+
+       raw_printk("ERP: %08lx SRP: %08lx  CCS: %08lx USP: %08lx MOF: %08lx\n",
+               regs->erp, regs->srp, regs->ccs, usp, regs->mof);
+
+       raw_printk(" r0: %08lx  r1: %08lx   r2: %08lx  r3: %08lx\n",
+               regs->r0, regs->r1, regs->r2, regs->r3);
+
+       raw_printk(" r4: %08lx  r5: %08lx   r6: %08lx  r7: %08lx\n",
+               regs->r4, regs->r5, regs->r6, regs->r7);
+
+       raw_printk(" r8: %08lx  r9: %08lx  r10: %08lx r11: %08lx\n",
+               regs->r8, regs->r9, regs->r10, regs->r11);
+
+       raw_printk("r12: %08lx r13: %08lx oR10: %08lx acr: %08lx\n",
+               regs->r12, regs->r13, regs->orig_r10, regs->acr);
+
+       raw_printk("sp: %08lx\n", regs);
+
+       SUPP_BANK_SEL(BANK_IM);
+       SUPP_REG_RD(RW_MM_CAUSE, i_mmu_cause);
+
+       SUPP_BANK_SEL(BANK_DM);
+       SUPP_REG_RD(RW_MM_CAUSE, d_mmu_cause);
+
+       raw_printk("       Data MMU Cause: %08lx\n", d_mmu_cause);
+       raw_printk("Instruction MMU Cause: %08lx\n", i_mmu_cause);
+
+       raw_printk("Process %s (pid: %d, stackpage: %08lx)\n",
+               current->comm, current->pid, (unsigned long) current);
+
+       /* Show additional info if in kernel-mode. */
+       if (!user_mode(regs)) {
+               int i;
+               unsigned char c;
+
+               show_stack(NULL, (unsigned long *) usp);
+
+               /*
+                * If the previous stack-dump wasn't a kernel one, dump the
+                * kernel stack now.
+                */
+               if (usp != 0)
+                       show_stack(NULL, NULL);
+
+               raw_printk("\nCode: ");
+
+               if (regs->erp < PAGE_OFFSET)
+                       goto bad_value;
+
+               /*
+                * Quite often the value at regs->erp doesn't point to the
+                * interesting instruction, which often is the previous
+                * instruction. So dump at an offset large enough that the
+                * instruction decoding should be in sync at the interesting
+                * point, but small enough to fit on a row. The regs->erp
+                * location is pointed out in a ksymoops-friendly way by
+                * wrapping the byte for that address in parenthesis.
+                */
+               for (i = -12; i < 12; i++) {
+                       if (__get_user(c, &((unsigned char *) regs->erp)[i])) {
+bad_value:
+                               raw_printk(" Bad IP value.");
+                               break;
+                       }
+
+                       if (i == 0)
+                               raw_printk("(%02x) ", c);
+                       else
+                               raw_printk("%02x ", c);
+               }
+
+               raw_printk("\n");
+       }
+}
+
+/*
+ * This gets called from entry.S when the watchdog has bitten. Show something
+ * similiar to an Oops dump, and if the kernel if configured to be a nice 
doggy;
+ * halt instead of reboot.
+ */
+void
+watchdog_bite_hook(struct pt_regs *regs)
+{
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+       local_irq_disable();
+       stop_watchdog();
+       show_registers(regs);
+
+       while (1)
+               ; /* Do nothing. */
+#else
+       show_registers(regs);
+#endif
+}
+
+/* This is normally the Oops function. */
+void
+die_if_kernel(const char *str, struct pt_regs *regs, long err)
+{
+       if (user_mode(regs))
+               return;
+
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+       /*
+        * This printout might take too long and could trigger
+        * the watchdog normally. If NICE_DOGGY is set, simply
+        * stop the watchdog during the printout.
+        */
+       stop_watchdog();
+#endif
+
+       raw_printk("%s: %04lx\n", str, err & 0xffff);
+
+       show_registers(regs);
+
+#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
+       reset_watchdog();
+#endif
+
+       do_exit(SIGSEGV);
+}
+
+void arch_enable_nmi(void)
+{
+       unsigned long flags;
+       local_save_flags(flags);
+       flags |= (1<<30); /* NMI M flag is at bit 30 */
+       local_irq_restore(flags);
+}
diff -urN linux/arch/cris/arch-v32/kernel/vcs_hook.c 
linux/arch/cris/arch-v32/kernel/vcs_hook.c
--- linux/arch/cris/arch-v32/kernel/vcs_hook.c  1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/vcs_hook.c  2005-08-01 19:23:43.338575000 
+0100     1.1
@@ -0,0 +1,96 @@
+// $Id: vcs_hook.c,v 1.2 2003/08/12 12:01:06 starvik Exp $
+//
+// Call simulator hook. This is the part running in the
+// simulated program.
+//
+
+#include "vcs_hook.h"
+#include <stdarg.h>
+#include <asm/arch-v32/hwregs/reg_map.h>
+#include <asm/arch-v32/hwregs/intr_vect_defs.h>
+
+#define HOOK_TRIG_ADDR     0xb7000000   /* hook cvlog model reg address */
+#define HOOK_MEM_BASE_ADDR 0xa0000000   /* csp4 (shared mem) base addr */
+
+#define HOOK_DATA(offset) ((unsigned*) HOOK_MEM_BASE_ADDR)[offset]
+#define VHOOK_DATA(offset) ((volatile unsigned*) HOOK_MEM_BASE_ADDR)[offset]
+#define HOOK_TRIG(funcid) do { *((unsigned *) HOOK_TRIG_ADDR) = funcid; } 
while(0)
+#define HOOK_DATA_BYTE(offset) ((unsigned char*) HOOK_MEM_BASE_ADDR)[offset]
+
+
+// ------------------------------------------------------------------ hook_call
+int hook_call( unsigned id, unsigned pcnt, ...) {
+  va_list ap;
+  unsigned i;
+  unsigned ret;
+#ifdef USING_SOS
+  PREEMPT_OFF_SAVE();
+#endif
+
+  // pass parameters
+  HOOK_DATA(0) = id;
+
+  /* Have to make hook_print_str a special case since we call with a
+     parameter of byte type. Should perhaps be a separate
+     hook_call. */
+
+  if (id == hook_print_str) {
+    int i;
+    char *str;
+
+    HOOK_DATA(1) = pcnt;
+
+    va_start(ap, pcnt);
+    str = (char*)va_arg(ap,unsigned);
+
+    for (i=0; i!=pcnt; i++) {
+      HOOK_DATA_BYTE(8+i) = str[i];
+    }
+    HOOK_DATA_BYTE(8+i) = 0;   /* null byte */
+  }
+  else {
+    va_start(ap, pcnt);
+    for( i = 1; i <= pcnt; i++ ) HOOK_DATA(i) = va_arg(ap,unsigned);
+    va_end(ap);
+  }
+
+  // read from mem to make sure data has propagated to memory before trigging
+  *((volatile unsigned*) HOOK_MEM_BASE_ADDR);
+
+  // trigger hook
+  HOOK_TRIG(id);
+
+  // wait for call to finish
+  while( VHOOK_DATA(0) > 0 ) {}
+
+  // extract return value
+
+  ret = VHOOK_DATA(1);
+
+#ifdef USING_SOS
+  PREEMPT_RESTORE();
+#endif
+  return ret;
+}
+
+unsigned
+hook_buf(unsigned i)
+{
+  return (HOOK_DATA(i));
+}
+
+void print_str( const char *str ) {
+  int i;
+  for (i=1; str[i]; i++);         /* find null at end of string */
+  hook_call(hook_print_str, i, str);
+}
+
+// --------------------------------------------------------------- CPU_KICK_DOG
+void CPU_KICK_DOG(void) {
+  (void) hook_call( hook_kick_dog, 0 );
+}
+
+// ------------------------------------------------------- CPU_WATCHDOG_TIMEOUT
+void CPU_WATCHDOG_TIMEOUT( unsigned t ) {
+  (void) hook_call( hook_dog_timeout, 1, t );
+}
diff -urN linux/arch/cris/arch-v32/kernel/vcs_hook.h 
linux/arch/cris/arch-v32/kernel/vcs_hook.h
--- linux/arch/cris/arch-v32/kernel/vcs_hook.h  1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/kernel/vcs_hook.h  2005-08-01 19:23:43.363450000 
+0100     1.1
@@ -0,0 +1,42 @@
+// $Id: vcs_hook.h,v 1.1 2003/08/12 12:01:06 starvik Exp $
+//
+// Call simulator hook functions
+
+#ifndef HOOK_H
+#define HOOK_H
+
+int hook_call( unsigned id, unsigned pcnt, ...);
+
+enum hook_ids {
+  hook_debug_on = 1,
+  hook_debug_off,
+  hook_stop_sim_ok,
+  hook_stop_sim_fail,
+  hook_alloc_shared,
+  hook_ptr_shared,
+  hook_free_shared,
+  hook_file2shared,
+  hook_cmp_shared,
+  hook_print_params,
+  hook_sim_time,
+  hook_stop_sim,
+  hook_kick_dog,
+  hook_dog_timeout,
+  hook_rand,
+  hook_srand,
+  hook_rand_range,
+  hook_print_str,
+  hook_print_hex,
+  hook_cmp_offset_shared,
+  hook_fill_random_shared,
+  hook_alloc_random_data,
+  hook_calloc_random_data,
+  hook_print_int,
+  hook_print_uint,
+  hook_fputc,
+  hook_init_fd,
+  hook_sbrk
+
+};
+
+#endif
diff -urN linux/arch/cris/arch-v32/lib/Makefile 
linux/arch/cris/arch-v32/lib/Makefile
--- linux/arch/cris/arch-v32/lib/Makefile       1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/lib/Makefile       2005-08-01 19:23:43.515303000 
+0100     1.1
@@ -0,0 +1,6 @@
+#
+# Makefile for Etrax-specific library files..
+#
+
+lib-y  = checksum.o checksumcopy.o string.o usercopy.o memset.o csumcpfruser.o 
spinlock.o
+
diff -urN linux/arch/cris/arch-v32/lib/checksum.S 
linux/arch/cris/arch-v32/lib/checksum.S
--- linux/arch/cris/arch-v32/lib/checksum.S     1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/lib/checksum.S     2005-08-01 19:23:43.530304000 
+0100     1.1
@@ -0,0 +1,111 @@
+/*
+ * A fast checksum routine using movem
+ * Copyright (c) 1998-2001, 2003 Axis Communications AB
+ *
+ * csum_partial(const unsigned char * buff, int len, unsigned int sum)
+ */
+
+       .globl  csum_partial
+csum_partial:
+
+       ;; r10 - src
+       ;; r11 - length
+       ;; r12 - checksum
+
+       ;; check for breakeven length between movem and normal word looping 
versions
+       ;; we also do _NOT_ want to compute a checksum over more than the
+       ;; actual length when length < 40
+
+       cmpu.w  80,$r11
+       blo     _word_loop
+       nop
+
+       ;; need to save the registers we use below in the movem loop
+       ;; this overhead is why we have a check above for breakeven length
+       ;; only r0 - r8 have to be saved, the other ones are clobber-able
+       ;; according to the ABI
+
+       subq    9*4,$sp
+       subq    10*4,$r11       ; update length for the first loop
+       movem   $r8,[$sp]
+
+       ;; do a movem checksum
+
+_mloop:        movem   [$r10+],$r9     ; read 10 longwords
+
+       ;; perform dword checksumming on the 10 longwords
+
+       add.d   $r0,$r12
+       addc    $r1,$r12
+       addc    $r2,$r12
+       addc    $r3,$r12
+       addc    $r4,$r12
+       addc    $r5,$r12
+       addc    $r6,$r12
+       addc    $r7,$r12
+       addc    $r8,$r12
+       addc    $r9,$r12
+
+       ;; fold the carry into the checksum, to avoid having to loop the carry
+       ;; back into the top
+
+       addc    0,$r12
+       addc    0,$r12          ; do it again, since we might have generated a 
carry
+
+       subq    10*4,$r11
+       bge     _mloop
+       nop
+
+       addq    10*4,$r11       ; compensate for last loop underflowing length
+
+       movem   [$sp+],$r8      ; restore regs
+
+_word_loop:
+       ;; only fold if there is anything to fold.
+
+       cmpq    0,$r12
+       beq     _no_fold
+
+       ;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below.
+       ;; r9 and r13 can be used as temporaries.
+
+       moveq   -1,$r9          ; put 0xffff in r9, faster than move.d 0xffff,r9
+       lsrq    16,$r9
+
+       move.d  $r12,$r13
+       lsrq    16,$r13         ; r13 = checksum >> 16
+       and.d   $r9,$r12                ; checksum = checksum & 0xffff
+       add.d   $r13,$r12               ; checksum += r13
+       move.d  $r12,$r13               ; do the same again, maybe we got a 
carry last add
+       lsrq    16,$r13
+       and.d   $r9,$r12
+       add.d   $r13,$r12
+
+_no_fold:
+       cmpq    2,$r11
+       blt     _no_words
+       nop
+
+       ;; checksum the rest of the words
+
+       subq    2,$r11
+
+_wloop:        subq    2,$r11
+       bge     _wloop
+       addu.w  [$r10+],$r12
+
+       addq    2,$r11
+
+_no_words:
+       ;; see if we have one odd byte more
+       cmpq    1,$r11
+       beq     _do_byte
+       nop
+       ret
+       move.d  $r12,$r10
+
+_do_byte:
+       ;; copy and checksum the last byte
+       addu.b  [$r10],$r12
+       ret
+       move.d  $r12,$r10
diff -urN linux/arch/cris/arch-v32/lib/checksumcopy.S 
linux/arch/cris/arch-v32/lib/checksumcopy.S
--- linux/arch/cris/arch-v32/lib/checksumcopy.S 1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/lib/checksumcopy.S 2005-08-01 19:23:43.556956000 
+0100     1.1
@@ -0,0 +1,120 @@
+/*
+ * A fast checksum+copy routine using movem
+ * Copyright (c) 1998, 2001, 2003 Axis Communications AB
+ *
+ * Authors:    Bjorn Wesen
+ *
+ * csum_partial_copy_nocheck(const char *src, char *dst,
+ *                          int len, unsigned int sum)
+ */
+
+       .globl  csum_partial_copy_nocheck
+csum_partial_copy_nocheck:
+
+       ;; r10 - src
+       ;; r11 - dst
+       ;; r12 - length
+       ;; r13 - checksum
+
+       ;; check for breakeven length between movem and normal word looping 
versions
+       ;; we also do _NOT_ want to compute a checksum over more than the
+       ;; actual length when length < 40
+
+       cmpu.w  80,$r12
+       blo     _word_loop
+       nop
+
+       ;; need to save the registers we use below in the movem loop
+       ;; this overhead is why we have a check above for breakeven length
+       ;; only r0 - r8 have to be saved, the other ones are clobber-able
+       ;; according to the ABI
+
+       subq    9*4,$sp
+       subq    10*4,$r12       ; update length for the first loop
+       movem   $r8,[$sp]
+
+       ;; do a movem copy and checksum
+
+1:     ;; A failing userspace access (the read) will have this as PC.
+_mloop:        movem   [$r10+],$r9     ; read 10 longwords
+       movem   $r9,[$r11+]     ; write 10 longwords
+
+       ;; perform dword checksumming on the 10 longwords
+
+       add.d   $r0,$r13
+       addc    $r1,$r13
+       addc    $r2,$r13
+       addc    $r3,$r13
+       addc    $r4,$r13
+       addc    $r5,$r13
+       addc    $r6,$r13
+       addc    $r7,$r13
+       addc    $r8,$r13
+       addc    $r9,$r13
+
+       ;; fold the carry into the checksum, to avoid having to loop the carry
+       ;; back into the top
+
+       addc    0,$r13
+       addc    0,$r13          ; do it again, since we might have generated a 
carry
+
+       subq    10*4,$r12
+       bge     _mloop
+       nop
+
+       addq    10*4,$r12       ; compensate for last loop underflowing length
+
+       movem   [$sp+],$r8      ; restore regs
+
+_word_loop:
+       ;; only fold if there is anything to fold.
+
+       cmpq    0,$r13
+       beq     _no_fold
+
+       ;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below
+       ;; r9 can be used as temporary.
+
+       move.d  $r13,$r9
+       lsrq    16,$r9          ; r0 = checksum >> 16
+       and.d   0xffff,$r13     ; checksum = checksum & 0xffff
+       add.d   $r9,$r13        ; checksum += r0
+       move.d  $r13,$r9        ; do the same again, maybe we got a carry last 
add
+       lsrq    16,$r9
+       and.d   0xffff,$r13
+       add.d   $r9,$r13
+
+_no_fold:
+       cmpq    2,$r12
+       blt     _no_words
+       nop
+
+       ;; copy and checksum the rest of the words
+
+       subq    2,$r12
+
+2:     ;; A failing userspace access for the read below will have this as PC.
+_wloop:        move.w  [$r10+],$r9
+       addu.w  $r9,$r13
+       subq    2,$r12
+       bge     _wloop
+       move.w  $r9,[$r11+]
+
+       addq    2,$r12
+
+_no_words:
+       ;; see if we have one odd byte more
+       cmpq    1,$r12
+       beq     _do_byte
+       nop
+       ret
+       move.d  $r13,$r10
+
+_do_byte:
+       ;; copy and checksum the last byte
+3:     ;; A failing userspace access for the read below will have this as PC.
+       move.b  [$r10],$r9
+       addu.b  $r9,$r13
+       move.b  $r9,[$r11]
+       ret
+       move.d  $r13,$r10
diff -urN linux/arch/cris/arch-v32/lib/csumcpfruser.S 
linux/arch/cris/arch-v32/lib/csumcpfruser.S
--- linux/arch/cris/arch-v32/lib/csumcpfruser.S 1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/lib/csumcpfruser.S 2005-08-01 19:23:43.581603000 
+0100     1.1
@@ -0,0 +1,69 @@
+/*
+ * Add-on to transform csum_partial_copy_nocheck in checksumcopy.S into
+ * csum_partial_copy_from_user by adding exception records.
+ *
+ * Copyright (C) 2001, 2003 Axis Communications AB.
+ *
+ * Author: Hans-Peter Nilsson.
+ */
+
+#include <asm/errno.h>
+
+/* Same function body, but a different name.  If we just added exception
+   records to _csum_partial_copy_nocheck and made it generic, we wouldn't
+   know a user fault from a kernel fault and we would have overhead in
+   each kernel caller for the error-pointer argument.
+
+   unsigned int csum_partial_copy_from_user
+     (const char *src, char *dst, int len, unsigned int sum, int *errptr);
+
+   Note that the errptr argument is only set if we encounter an error.
+   It is conveniently located on the stack, so the normal function body
+   does not have to handle it.  */
+
+#define csum_partial_copy_nocheck csum_partial_copy_from_user
+
+/* There are local labels numbered 1, 2 and 3 present to mark the
+   different from-user accesses.  */
+#include "checksumcopy.S"
+
+       .section .fixup,"ax"
+
+;; Here from the movem loop; restore stack.
+4:
+       movem   [$sp+],$r8
+;; r12 is already decremented.  Add back chunk_size-2.
+       addq    40-2,$r12
+
+;; Here from the word loop; r12 is off by 2; add it back.
+5:
+       addq    2,$r12
+
+;; Here from a failing single byte.
+6:
+
+;; Signal in *errptr that we had a failing access.
+       move.d  [$sp],$acr
+       moveq   -EFAULT,$r9
+       subq    4,$sp
+       move.d  $r9,[$acr]
+
+;; Clear the rest of the destination area using memset.  Preserve the
+;; checksum for the readable bytes.
+       move.d  $r13,[$sp]
+       subq    4,$sp
+       move.d  $r11,$r10
+       move    $srp,[$sp]
+       jsr     memset
+       clear.d $r11
+
+       move    [$sp+],$srp
+       ret
+       move.d  [$sp+],$r10
+
+       .previous
+       .section __ex_table,"a"
+       .dword 1b,4b
+       .dword 2b,5b
+       .dword 3b,6b
+       .previous
diff -urN linux/arch/cris/arch-v32/lib/dram_init.S 
linux/arch/cris/arch-v32/lib/dram_init.S
--- linux/arch/cris/arch-v32/lib/dram_init.S    1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/lib/dram_init.S    2005-08-01 19:23:43.603019000 
+0100     1.1
@@ -0,0 +1,120 @@
+/* $Id: dram_init.S,v 1.4 2005/04/24 18:48:32 starvik Exp $
+ *
+ * DRAM/SDRAM initialization - alter with care
+ * This file is intended to be included from other assembler files
+ *
+ * Note: This file may not modify r8 or r9 because they are used to
+ * carry information from the decompresser to the kernel
+ *
+ * Copyright (C) 2000-2003 Axis Communications AB
+ *
+ * Authors:  Mikael Starvik (starvik@axis.com)
+ */
+
+/* Just to be certain the config file is included, we include it here
+ * explicitely instead of depending on it being included in the file that
+ * uses this code.
+ */
+
+#include <linux/config.h>
+#include <asm/arch/hwregs/asm/reg_map_asm.h>
+#include <asm/arch/hwregs/asm/bif_core_defs_asm.h>
+
+       ;; WARNING! The registers r8 and r9 are used as parameters carrying
+       ;; information from the decompressor (if the kernel was compressed).
+       ;; They should not be used in the code below.
+
+       ; Refer to BIF MDS for a description of SDRAM initialization
+
+       ; Bank configuration
+       move.d   REG_ADDR(bif_core, regi_bif_core, rw_sdram_cfg_grp0), $r0
+       move.d   CONFIG_ETRAX_SDRAM_GRP0_CONFIG, $r1
+       move.d   $r1, [$r0]
+       move.d   REG_ADDR(bif_core, regi_bif_core, rw_sdram_cfg_grp1), $r0
+       move.d   CONFIG_ETRAX_SDRAM_GRP1_CONFIG, $r1
+       move.d   $r1, [$r0]
+
+       ; Calculate value of mrs_data
+       ; CAS latency = 2 && bus_width = 32 => 0x40
+       ; CAS latency = 3 && bus_width = 32 => 0x60
+       ; CAS latency = 2 && bus_width = 16 => 0x20
+       ; CAS latency = 3 && bus_width = 16 => 0x30
+
+       ; Check if value is already supplied in kernel config
+       move.d   CONFIG_ETRAX_SDRAM_COMMAND, $r2
+       bne      _set_timing
+       nop
+
+       move.d   0x40, $r4       ; Assume 32 bits and CAS latency = 2
+       move.d   CONFIG_ETRAX_SDRAM_TIMING, $r1
+       and.d    0x07, $r1       ; Get CAS latency
+       cmpq     2, $r1          ; CL = 2 ?
+       beq      _bw_check
+       nop
+       move.d   0x60, $r4
+
+_bw_check:
+       ; Assume that group 0 width is equal to group 1. This assumption
+       ; is wrong for a group 1 only hardware (such as the grand old
+       ; StorPoint+).
+       move.d   CONFIG_ETRAX_SDRAM_GRP0_CONFIG, $r1
+       and.d    0x200, $r1     ; DRAM width is bit 9
+       beq      _set_timing
+       lslq     2, $r4         ;  mrs_data starts at bit 2
+       lsrq     1, $r4         ;  16 bits. Shift down value.
+
+       ; Set timing parameters (refresh off to avoid Guinness TR 83)
+_set_timing:
+       move.d   CONFIG_ETRAX_SDRAM_TIMING, $r1
+       and.d    ~(3 << reg_bif_core_rw_sdram_timing___ref___lsb), $r1
+       move.d   REG_ADDR(bif_core, regi_bif_core, rw_sdram_timing), $r0
+       move.d   $r1, [$r0]
+
+       ; Issue NOP command
+       move.d REG_ADDR(bif_core, regi_bif_core, rw_sdram_cmd), $r5
+       moveq regk_bif_core_nop, $r1
+       move.d $r1, [$r5]
+
+       ; Wait 200us
+       move.d   10000, $r2
+1:     bne      1b
+       subq     1, $r2
+
+       ; Issue initialization command sequence
+       move.d   _sdram_commands_start, $r2
+       and.d    0x000fffff, $r2 ; Make sure commands are read from flash
+       move.d   _sdram_commands_end,  $r3
+       and.d    0x000fffff, $r3
+1:     clear.d  $r6
+       move.b   [$r2+], $r6    ; Load command
+       or.d     $r4, $r6       ; Add calculated mrs
+       move.d   $r6, [$r5]     ; Write rw_sdram_cmd
+       ; Wait 80 ns between each command
+       move.d   4000, $r7
+2:     bne      2b
+       subq     1, $r7
+       cmp.d    $r2, $r3       ; Last command?
+       bne      1b
+       nop
+
+       ; Start refresh
+       move.d   CONFIG_ETRAX_SDRAM_TIMING, $r1
+       move.d   REG_ADDR(bif_core, regi_bif_core, rw_sdram_timing), $r0
+       move.d   $r1, [$r0]
+
+       ; Initialization finished
+       ba       _sdram_commands_end
+       nop
+
+_sdram_commands_start:
+       .byte   regk_bif_core_pre ; Precharge
+       .byte   regk_bif_core_ref ; refresh
+       .byte   regk_bif_core_ref ; refresh
+       .byte   regk_bif_core_ref ; refresh
+       .byte   regk_bif_core_ref ; refresh
+       .byte   regk_bif_core_ref ; refresh
+       .byte   regk_bif_core_ref ; refresh
+       .byte   regk_bif_core_ref ; refresh
+       .byte   regk_bif_core_ref ; refresh
+       .byte   regk_bif_core_mrs ; mrs
+_sdram_commands_end:
diff -urN linux/arch/cris/arch-v32/lib/hw_settings.S 
linux/arch/cris/arch-v32/lib/hw_settings.S
--- linux/arch/cris/arch-v32/lib/hw_settings.S  1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/lib/hw_settings.S  2005-08-01 19:23:43.615268000 
+0100     1.1
@@ -0,0 +1,73 @@
+/*
+ * $Id: hw_settings.S,v 1.3 2005/04/24 18:36:57 starvik Exp $
+ *
+ * This table is used by some tools to extract hardware parameters.
+ * The table should be included in the kernel and the decompressor.
+ * Don't forget to update the tools if you change this table.
+ *
+ * Copyright (C) 2001 Axis Communications AB
+ *
+ * Authors:  Mikael Starvik (starvik@axis.com)
+ */
+
+#include <linux/config.h>
+#include <asm/arch/hwregs/asm/reg_map_asm.h>
+#include <asm/arch/hwregs/asm/bif_core_defs_asm.h>
+#include <asm/arch/hwregs/asm/gio_defs_asm.h>
+
+       .ascii "HW_PARAM_MAGIC" ; Magic number
+       .dword 0xc0004000       ; Kernel start address
+
+       ; Debug port
+#ifdef CONFIG_ETRAX_DEBUG_PORT0
+       .dword 0
+#elif defined(CONFIG_ETRAX_DEBUG_PORT1)
+       .dword 1
+#elif defined(CONFIG_ETRAX_DEBUG_PORT2)
+       .dword 2
+#elif defined(CONFIG_ETRAX_DEBUG_PORT3)
+       .dword 3
+#else
+       .dword 4 ; No debug
+#endif
+
+       ; Register values
+       .dword REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg)
+       .dword CONFIG_ETRAX_MEM_GRP1_CONFIG
+       .dword REG_ADDR(bif_core, regi_bif_core, rw_grp2_cfg)
+       .dword CONFIG_ETRAX_MEM_GRP2_CONFIG
+       .dword REG_ADDR(bif_core, regi_bif_core, rw_grp3_cfg)
+       .dword CONFIG_ETRAX_MEM_GRP3_CONFIG
+       .dword REG_ADDR(bif_core, regi_bif_core, rw_grp4_cfg)
+       .dword CONFIG_ETRAX_MEM_GRP4_CONFIG
+       .dword REG_ADDR(bif_core, regi_bif_core, rw_sdram_cfg_grp0)
+       .dword CONFIG_ETRAX_SDRAM_GRP0_CONFIG
+       .dword REG_ADDR(bif_core, regi_bif_core, rw_sdram_cfg_grp1)
+       .dword CONFIG_ETRAX_SDRAM_GRP1_CONFIG
+       .dword REG_ADDR(bif_core, regi_bif_core, rw_sdram_timing)
+       .dword CONFIG_ETRAX_SDRAM_TIMING
+       .dword REG_ADDR(bif_core, regi_bif_core, rw_sdram_cmd)
+       .dword CONFIG_ETRAX_SDRAM_COMMAND
+
+       .dword REG_ADDR(gio, regi_gio, rw_pa_dout)
+       .dword CONFIG_ETRAX_DEF_GIO_PA_OUT
+       .dword REG_ADDR(gio, regi_gio, rw_pa_oe)
+       .dword CONFIG_ETRAX_DEF_GIO_PA_OE
+       .dword REG_ADDR(gio, regi_gio, rw_pb_dout)
+       .dword CONFIG_ETRAX_DEF_GIO_PB_OUT
+       .dword REG_ADDR(gio, regi_gio, rw_pb_oe)
+       .dword CONFIG_ETRAX_DEF_GIO_PB_OE
+       .dword REG_ADDR(gio, regi_gio, rw_pc_dout)
+       .dword CONFIG_ETRAX_DEF_GIO_PC_OUT
+       .dword REG_ADDR(gio, regi_gio, rw_pc_oe)
+       .dword CONFIG_ETRAX_DEF_GIO_PC_OE
+       .dword REG_ADDR(gio, regi_gio, rw_pd_dout)
+       .dword CONFIG_ETRAX_DEF_GIO_PD_OUT
+       .dword REG_ADDR(gio, regi_gio, rw_pd_oe)
+       .dword CONFIG_ETRAX_DEF_GIO_PD_OE
+       .dword REG_ADDR(gio, regi_gio, rw_pe_dout)
+       .dword CONFIG_ETRAX_DEF_GIO_PE_OUT
+       .dword REG_ADDR(gio, regi_gio, rw_pe_oe)
+       .dword CONFIG_ETRAX_DEF_GIO_PE_OE
+
+       .dword 0 ; No more register values
diff -urN linux/arch/cris/arch-v32/lib/memset.c 
linux/arch/cris/arch-v32/lib/memset.c
--- linux/arch/cris/arch-v32/lib/memset.c       1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/lib/memset.c       2005-08-01 19:23:43.638845000 
+0100     1.1
@@ -0,0 +1,253 @@
+/*#************************************************************************#*/
+/*#-------------------------------------------------------------------------*/
+/*#                                                                         */
+/*# FUNCTION NAME: memset()                                                 */
+/*#                                                                         */
+/*# PARAMETERS:  void* dst;   Destination address.                          */
+/*#              int     c;   Value of byte to write.                       */
+/*#              int   len;   Number of bytes to write.                     */
+/*#                                                                         */
+/*# RETURNS:     dst.                                                       */
+/*#                                                                         */
+/*# DESCRIPTION: Sets the memory dst of length len bytes to c, as standard. */
+/*#              Framework taken from memcpy.  This routine is              */
+/*#              very sensitive to compiler changes in register allocation. */
+/*#              Should really be rewritten to avoid this problem.          */
+/*#                                                                         */
+/*#-------------------------------------------------------------------------*/
+/*#                                                                         */
+/*# HISTORY                                                                 */
+/*#                                                                         */
+/*# DATE      NAME            CHANGES                                       */
+/*# ----      ----            -------                                       */
+/*# 990713    HP              Tired of watching this function (or           */
+/*#                           really, the nonoptimized generic              */
+/*#                           implementation) take up 90% of simulator      */
+/*#                           output.  Measurements needed.                 */
+/*#                                                                         */
+/*#-------------------------------------------------------------------------*/
+
+#include <linux/types.h>
+
+/* No, there's no macro saying 12*4, since it is "hard" to get it into
+   the asm in a good way.  Thus better to expose the problem everywhere.
+   */
+
+/* Assuming 1 cycle per dword written or read (ok, not really true), and
+   one per instruction, then 43+3*(n/48-1) <= 24+24*(n/48-1)
+   so n >= 45.7; n >= 0.9; we win on the first full 48-byte block to set. */
+
+#define ZERO_BLOCK_SIZE (1*12*4)
+
+void *memset(void *pdst,
+             int c,
+             size_t plen)
+{
+  /* Ok.  Now we want the parameters put in special registers.
+     Make sure the compiler is able to make something useful of this. */
+
+  register char *return_dst __asm__ ("r10") = pdst;
+  register int n __asm__ ("r12") = plen;
+  register int lc __asm__ ("r11") = c;
+
+  /* Most apps use memset sanely.  Only those memsetting about 3..4
+     bytes or less get penalized compared to the generic implementation
+     - and that's not really sane use. */
+
+  /* Ugh.  This is fragile at best.  Check with newer GCC releases, if
+     they compile cascaded "x |= x << 8" sanely! */
+  __asm__("movu.b %0,$r13      \n\
+           lslq 8,$r13         \n\
+          move.b %0,$r13       \n\
+          move.d $r13,%0       \n\
+          lslq 16,$r13         \n\
+          or.d $r13,%0"
+          : "=r" (lc) : "0" (lc) : "r13");
+
+  {
+    register char *dst __asm__ ("r13") = pdst;
+
+  /* This is NONPORTABLE, but since this whole routine is     */
+  /* grossly nonportable that doesn't matter.                 */
+
+  if (((unsigned long) pdst & 3) != 0
+     /* Oops! n=0 must be a legal call, regardless of alignment. */
+      && n >= 3)
+  {
+    if ((unsigned long)dst & 1)
+    {
+      *dst = (char) lc;
+      n--;
+      dst++;
+    }
+
+    if ((unsigned long)dst & 2)
+    {
+      *(short *)dst = lc;
+      n -= 2;
+      dst += 2;
+    }
+  }
+
+  /* Now the fun part.  For the threshold value of this, check the equation
+     above. */
+  /* Decide which copying method to use. */
+  if (n >= ZERO_BLOCK_SIZE)
+  {
+    /* For large copies we use 'movem' */
+
+  /* It is not optimal to tell the compiler about clobbering any
+     registers; that will move the saving/restoring of those registers
+     to the function prologue/epilogue, and make non-movem sizes
+     suboptimal.
+
+      This method is not foolproof; it assumes that the "asm reg"
+     declarations at the beginning of the function really are used
+     here (beware: they may be moved to temporary registers).
+      This way, we do not have to save/move the registers around into
+     temporaries; we can safely use them straight away.
+
+      If you want to check that the allocation was right; then
+      check the equalities in the first comment.  It should say
+      "r13=r13, r12=r12, r11=r11" */
+    __asm__ volatile ("                                                        
\n\
+        ;; Check that the register asm declaration got right.          \n\
+        ;; The GCC manual says it will work, but there *has* been bugs.        
\n\
+       .ifnc %0-%1-%4,$r13-$r12-$r11                                   \n\
+       .err                                                            \n\
+       .endif                                                          \n\
+                                                                       \n\
+       ;; Save the registers we'll clobber in the movem process        \n\
+       ;; on the stack.  Don't mention them to gcc, it will only be    \n\
+       ;; upset.                                                       \n\
+       subq    11*4,$sp                                                \n\
+        movem   $r10,[$sp]                                             \n\
+                                                                       \n\
+        move.d  $r11,$r0                                               \n\
+        move.d  $r11,$r1                                               \n\
+        move.d  $r11,$r2                                               \n\
+        move.d  $r11,$r3                                               \n\
+        move.d  $r11,$r4                                               \n\
+        move.d  $r11,$r5                                               \n\
+        move.d  $r11,$r6                                               \n\
+        move.d  $r11,$r7                                               \n\
+        move.d  $r11,$r8                                               \n\
+        move.d  $r11,$r9                                               \n\
+        move.d  $r11,$r10                                              \n\
+                                                                       \n\
+        ;; Now we've got this:                                         \n\
+       ;; r13 - dst                                                    \n\
+       ;; r12 - n                                                      \n\
+                                                                       \n\
+        ;; Update n for the first loop                                 \n\
+        subq    12*4,$r12                                              \n\
+0:                                                                     \n\
+        subq   12*4,$r12                                               \n\
+        bge     0b                                                     \n\
+       movem   $r11,[$r13+]                                            \n\
+                                                                       \n\
+        addq   12*4,$r12  ;; compensate for last loop underflowing n   \n\
+                                                                       \n\
+       ;; Restore registers from stack                                 \n\
+        movem [$sp+],$r10"
+
+     /* Outputs */ : "=r" (dst), "=r" (n)
+     /* Inputs */ : "0" (dst), "1" (n), "r" (lc));
+  }
+
+    /* Either we directly starts copying, using dword copying
+       in a loop, or we copy as much as possible with 'movem'
+       and then the last block (<44 bytes) is copied here.
+       This will work since 'movem' will have updated src,dst,n. */
+
+    while ( n >= 16 )
+    {
+      *((long*)dst)++ = lc;
+      *((long*)dst)++ = lc;
+      *((long*)dst)++ = lc;
+      *((long*)dst)++ = lc;
+      n -= 16;
+    }
+
+    /* A switch() is definitely the fastest although it takes a LOT of code.
+     * Particularly if you inline code this.
+     */
+    switch (n)
+    {
+      case 0:
+        break;
+      case 1:
+        *(char*)dst = (char) lc;
+        break;
+      case 2:
+        *(short*)dst = (short) lc;
+        break;
+      case 3:
+        *((short*)dst)++ = (short) lc;
+        *(char*)dst = (char) lc;
+        break;
+      case 4:
+        *((long*)dst)++ = lc;
+        break;
+      case 5:
+        *((long*)dst)++ = lc;
+        *(char*)dst = (char) lc;
+        break;
+      case 6:
+        *((long*)dst)++ = lc;
+        *(short*)dst = (short) lc;
+        break;
+      case 7:
+        *((long*)dst)++ = lc;
+        *((short*)dst)++ = (short) lc;
+        *(char*)dst = (char) lc;
+        break;
+      case 8:
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        break;
+      case 9:
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *(char*)dst = (char) lc;
+        break;
+      case 10:
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *(short*)dst = (short) lc;
+        break;
+      case 11:
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *((short*)dst)++ = (short) lc;
+        *(char*)dst = (char) lc;
+        break;
+      case 12:
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        break;
+      case 13:
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *(char*)dst = (char) lc;
+        break;
+      case 14:
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *(short*)dst = (short) lc;
+        break;
+      case 15:
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *((long*)dst)++ = lc;
+        *((short*)dst)++ = (short) lc;
+        *(char*)dst = (char) lc;
+        break;
+    }
+  }
+
+  return return_dst; /* destination pointer. */
+} /* memset() */
diff -urN linux/arch/cris/arch-v32/lib/nand_init.S 
linux/arch/cris/arch-v32/lib/nand_init.S
--- linux/arch/cris/arch-v32/lib/nand_init.S    1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/lib/nand_init.S    2005-08-01 19:23:43.664346000 
+0100     1.1
@@ -0,0 +1,179 @@
+##=============================================================================
+##
+##      nand_init.S
+##
+##      The bootrom copies data from the NAND flash to the internal RAM but
+##      due to a bug/feature we can only trust the 256 first bytes. So this
+##      code copies more data from NAND flash to internal RAM. Obvioulsy this
+##      code must fit in the first 256 bytes so alter with care.
+##
+##     Some notes about the bug/feature for future reference:
+##        The bootrom copies the first 127 KB from NAND flash to internal
+##        memory. The problem is that it does a bytewise copy. NAND flashes
+##        does autoincrement on the address so for a 16-bite device each
+##        read/write increases the address by two. So the copy loop in the
+##        bootrom will discard every second byte. This is solved by inserting
+##        zeroes in every second byte in the first erase block.
+##
+##        The bootrom also incorrectly assumes that it can read the flash
+##        linear with only one read command but the flash will actually
+##        switch between normal area and spare area if you do that so we
+##        can't trust more than the first 256 bytes.
+##
+##=============================================================================
+
+#include <asm/arch/hwregs/asm/reg_map_asm.h>
+#include <asm/arch/hwregs/asm/gio_defs_asm.h>
+#include <asm/arch/hwregs/asm/pinmux_defs_asm.h>
+#include <asm/arch/hwregs/asm/bif_core_defs_asm.h>
+#include <asm/arch/hwregs/asm/config_defs_asm.h>
+#include <linux/config.h>
+
+;; There are 8-bit NAND flashes and 16-bit NAND flashes.
+;; We need to treat them slightly different.
+#if CONFIG_ETRAX_FLASH_BUSWIDTH==2
+#define PAGE_SIZE 256
+#else
+#error 2
+#define PAGE_SIZE 512
+#endif
+#define ERASE_BLOCK 16384
+
+;; GPIO pins connected to NAND flash
+#define CE 4
+#define CLE 5
+#define ALE 6
+#define BY 7
+
+;; Address space for NAND flash
+#define NAND_RD_ADDR 0x90000000
+#define NAND_WR_ADDR 0x94000000
+
+#define READ_CMD 0x00
+
+;; Readability macros
+#define CSP_MASK \
+       REG_MASK(bif_core, rw_grp3_cfg, gated_csp0) | \
+       REG_MASK(bif_core, rw_grp3_cfg, gated_csp1)
+#define CSP_VAL \
+       REG_STATE(bif_core, rw_grp3_cfg, gated_csp0, rd) | \
+       REG_STATE(bif_core, rw_grp3_cfg, gated_csp1, wr)
+
+;;----------------------------------------------------------------------------
+;; Macros to set/clear GPIO bits
+
+.macro SET x
+       or.b   (1<<\x),$r9
+       move.d $r9, [$r2]
+.endm
+
+.macro CLR x
+       and.b  ~(1<<\x),$r9
+       move.d $r9, [$r2]
+.endm
+
+;;----------------------------------------------------------------------------
+
+nand_boot:
+       ;; Check if nand boot was selected
+       move.d REG_ADDR(config, regi_config, r_bootsel), $r0
+       move.d [$r0], $r0
+       and.d  REG_MASK(config, r_bootsel, boot_mode), $r0
+       cmp.d  REG_STATE(config, r_bootsel, boot_mode, nand), $r0
+       bne normal_boot ; No NAND boot
+       nop
+
+copy_nand_to_ram:
+       ;; copy_nand_to_ram
+       ;; Arguments
+       ;;   r10 - destination
+       ;;   r11 - source offset
+       ;;   r12 - size
+       ;;   r13 - Address to jump to after completion
+       ;; Note : r10-r12 are clobbered on return
+       ;; Registers used:
+       ;;   r0 - NAND_RD_ADDR
+       ;;   r1 - NAND_WR_ADDR
+       ;;   r2 - reg_gio_rw_pa_dout
+       ;;   r3 - reg_gio_r_pa_din
+       ;;   r4 - tmp
+       ;;   r5 - byte counter within a page
+       ;;   r6 - reg_pinmux_rw_pa
+       ;;   r7 - reg_gio_rw_pa_oe
+       ;;   r8 - reg_bif_core_rw_grp3_cfg
+       ;;   r9 - reg_gio_rw_pa_dout shadow
+       move.d 0x90000000, $r0
+       move.d 0x94000000, $r1
+       move.d REG_ADDR(gio, regi_gio, rw_pa_dout), $r2
+       move.d REG_ADDR(gio, regi_gio, r_pa_din), $r3
+       move.d REG_ADDR(pinmux, regi_pinmux, rw_pa), $r6
+       move.d REG_ADDR(gio, regi_gio, rw_pa_oe), $r7
+       move.d REG_ADDR(bif_core, regi_bif_core, rw_grp3_cfg), $r8
+
+#if CONFIG_ETRAX_FLASH_BUSWIDTH==2
+       lsrq    1, $r11
+#endif
+       ;; Set up GPIO
+       move.d [$r2], $r9
+       move.d [$r7], $r4
+       or.b (1<<ALE) | (1 << CLE) | (1<<CE), $r4
+       move.d $r4, [$r7]
+
+       ;; Set up bif
+       move.d [$r8], $r4
+       and.d CSP_MASK, $r4
+       or.d CSP_VAL, $r4
+       move.d $r4, [$r8]
+
+1:     ;; Copy one page
+       CLR CE
+       SET CLE
+       moveq   READ_CMD, $r4
+       move.b  $r4, [$r1]
+       moveq   20, $r4
+2:     bne     2b
+       subq    1, $r4
+       CLR CLE
+       SET ALE
+       clear.w [$r1]           ; Column address = 0
+       move.d  $r11, $r4
+       lsrq    8, $r4
+       move.b  $r4, [$r1]      ; Row address
+       lsrq    8, $r4
+       move.b  $r4, [$r1]      ; Row adddress
+       moveq   20, $r4
+2:     bne     2b
+       subq    1, $r4
+       CLR ALE
+2:     move.d  [$r3], $r4
+       and.d   1 << BY, $r4
+       beq 2b
+       movu.w  PAGE_SIZE, $r5
+2:     ; Copy one byte/word
+#if CONFIG_ETRAX_FLASH_BUSWIDTH==2
+       move.w  [$r0], $r4
+#else
+       move.b  [$r0], $r4
+#endif
+       subq    1, $r5
+       bne     2b
+#if CONFIG_ETRAX_FLASH_BUSWIDTH==2
+       move.w  $r4, [$r10+]
+       subu.w  PAGE_SIZE*2, $r12
+#else
+       move.b  $r4, [$r10+]
+       subu.w  PAGE_SIZE, $r12
+#endif
+       bpl     1b
+       addu.w  PAGE_SIZE, $r11
+
+       ;; End of copy
+       jump    $r13
+       nop
+
+       ;; This will warn if the code above is too large. If you consider
+       ;; to remove this you don't understand the bug/feature.
+       .org 256
+       .org ERASE_BLOCK
+
+normal_boot:
diff -urN linux/arch/cris/arch-v32/lib/spinlock.S 
linux/arch/cris/arch-v32/lib/spinlock.S
--- linux/arch/cris/arch-v32/lib/spinlock.S     1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/lib/spinlock.S     2005-08-01 19:23:43.688960000 
+0100     1.1
@@ -0,0 +1,33 @@
+;; Core of the spinlock implementation
+;;
+;; Copyright (C) 2004 Axis Communications AB.
+;;
+;; Author: Mikael Starvik
+
+
+       .global cris_spin_lock
+       .global cris_spin_trylock
+
+       .text
+
+cris_spin_lock:
+       clearf  p
+1:     test.d  [$r10]
+       beq     1b
+       clearf  p
+       ax
+       clear.d [$r10]
+       bcs     1b
+       clearf  p
+       ret
+       nop
+
+cris_spin_trylock:
+       clearf  p
+1:     move.d  [$r10], $r11
+       ax
+       clear.d [$r10]
+        bcs    1b
+        clearf p
+       ret
+       move.d  $r11,$r10
diff -urN linux/arch/cris/arch-v32/lib/string.c 
linux/arch/cris/arch-v32/lib/string.c
--- linux/arch/cris/arch-v32/lib/string.c       1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/lib/string.c       2005-08-01 19:23:43.709319000 
+0100     1.1
@@ -0,0 +1,219 @@
+/*#************************************************************************#*/
+/*#-------------------------------------------------------------------------*/
+/*#                                                                         */
+/*# FUNCTION NAME: memcpy()                                                 */
+/*#                                                                         */
+/*# PARAMETERS:  void* dst;   Destination address.                          */
+/*#              void* src;   Source address.                               */
+/*#              int   len;   Number of bytes to copy.                      */
+/*#                                                                         */
+/*# RETURNS:     dst.                                                       */
+/*#                                                                         */
+/*# DESCRIPTION: Copies len bytes of memory from src to dst.  No guarantees */
+/*#              about copying of overlapping memory areas. This routine is */
+/*#              very sensitive to compiler changes in register allocation. */
+/*#              Should really be rewritten to avoid this problem.          */
+/*#                                                                         */
+/*#-------------------------------------------------------------------------*/
+/*#                                                                         */
+/*# HISTORY                                                                 */
+/*#                                                                         */
+/*# DATE      NAME            CHANGES                                       */
+/*# ----      ----            -------                                       */
+/*# 941007    Kenny R         Creation                                      */
+/*# 941011    Kenny R         Lots of optimizations and inlining.           */
+/*# 941129    Ulf A           Adapted for use in libc.                      */
+/*# 950216    HP              N==0 forgotten if non-aligned src/dst.        */
+/*#                           Added some optimizations.                     */
+/*# 001025    HP              Make src and dst char *.  Align dst to       */
+/*#                          dword, not just word-if-both-src-and-dst-     */
+/*#                          are-misaligned.                               */
+/*#                                                                         */
+/*#-------------------------------------------------------------------------*/
+
+#include <linux/types.h>
+
+void *memcpy(void *pdst,
+             const void *psrc,
+             size_t pn)
+{
+  /* Ok.  Now we want the parameters put in special registers.
+     Make sure the compiler is able to make something useful of this.
+      As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop).
+
+     If gcc was allright, it really would need no temporaries, and no
+     stack space to save stuff on. */
+
+  register void *return_dst __asm__ ("r10") = pdst;
+  register char *dst __asm__ ("r13") = pdst;
+  register const char *src __asm__ ("r11") = psrc;
+  register int n __asm__ ("r12") = pn;
+
+
+  /* When src is aligned but not dst, this makes a few extra needless
+     cycles.  I believe it would take as many to check that the
+     re-alignment was unnecessary.  */
+  if (((unsigned long) dst & 3) != 0
+      /* Don't align if we wouldn't copy more than a few bytes; so we
+        don't have to check further for overflows.  */
+      && n >= 3)
+  {
+    if ((unsigned long) dst & 1)
+    {
+      n--;
+      *(char*)dst = *(char*)src;
+      src++;
+      dst++;
+    }
+
+    if ((unsigned long) dst & 2)
+    {
+      n -= 2;
+      *(short*)dst = *(short*)src;
+      src += 2;
+      dst += 2;
+    }
+  }
+
+  /* Decide which copying method to use.  Movem is dirt cheap, so the
+     overheap is low enough to always use the minimum block size as the
+     threshold.  */
+  if (n >= 44)
+  {
+    /* For large copies we use 'movem' */
+
+  /* It is not optimal to tell the compiler about clobbering any
+     registers; that will move the saving/restoring of those registers
+     to the function prologue/epilogue, and make non-movem sizes
+     suboptimal.  */
+    __asm__ volatile ("                                                        
\n\
+        ;; Check that the register asm declaration got right.          \n\
+        ;; The GCC manual explicitly says TRT will happen.             \n\
+       .ifnc %0-%1-%2,$r13-$r11-$r12                                   \n\
+       .err                                                            \n\
+       .endif                                                          \n\
+                                                                       \n\
+       ;; Save the registers we'll use in the movem process            \n\
+                                                                       \n\
+       ;; on the stack.                                                \n\
+       subq    11*4,$sp                                                \n\
+       movem   $r10,[$sp]                                              \n\
+                                                                       \n\
+        ;; Now we've got this:                                         \n\
+       ;; r11 - src                                                    \n\
+       ;; r13 - dst                                                    \n\
+       ;; r12 - n                                                      \n\
+                                                                       \n\
+        ;; Update n for the first loop                                 \n\
+        subq    44,$r12                                                        
\n\
+0:                                                                     \n\
+       movem   [$r11+],$r10                                            \n\
+        subq   44,$r12                                                 \n\
+        bge     0b                                                     \n\
+       movem   $r10,[$r13+]                                            \n\
+                                                                       \n\
+        addq   44,$r12  ;; compensate for last loop underflowing n     \n\
+                                                                       \n\
+       ;; Restore registers from stack                                 \n\
+        movem [$sp+],$r10"
+
+     /* Outputs */ : "=r" (dst), "=r" (src), "=r" (n)
+     /* Inputs */ : "0" (dst), "1" (src), "2" (n));
+
+  }
+
+  /* Either we directly starts copying, using dword copying
+     in a loop, or we copy as much as possible with 'movem'
+     and then the last block (<44 bytes) is copied here.
+     This will work since 'movem' will have updated src,dst,n. */
+
+  while ( n >= 16 )
+  {
+    *((long*)dst)++ = *((long*)src)++;
+    *((long*)dst)++ = *((long*)src)++;
+    *((long*)dst)++ = *((long*)src)++;
+    *((long*)dst)++ = *((long*)src)++;
+    n -= 16;
+  }
+
+  /* A switch() is definitely the fastest although it takes a LOT of code.
+   * Particularly if you inline code this.
+   */
+  switch (n)
+  {
+    case 0:
+      break;
+    case 1:
+      *(char*)dst = *(char*)src;
+      break;
+    case 2:
+      *(short*)dst = *(short*)src;
+      break;
+    case 3:
+      *((short*)dst)++ = *((short*)src)++;
+      *(char*)dst = *(char*)src;
+      break;
+    case 4:
+      *((long*)dst)++ = *((long*)src)++;
+      break;
+    case 5:
+      *((long*)dst)++ = *((long*)src)++;
+      *(char*)dst = *(char*)src;
+      break;
+    case 6:
+      *((long*)dst)++ = *((long*)src)++;
+      *(short*)dst = *(short*)src;
+      break;
+    case 7:
+      *((long*)dst)++ = *((long*)src)++;
+      *((short*)dst)++ = *((short*)src)++;
+      *(char*)dst = *(char*)src;
+      break;
+    case 8:
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      break;
+    case 9:
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *(char*)dst = *(char*)src;
+      break;
+    case 10:
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *(short*)dst = *(short*)src;
+      break;
+    case 11:
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *((short*)dst)++ = *((short*)src)++;
+      *(char*)dst = *(char*)src;
+      break;
+    case 12:
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      break;
+    case 13:
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *(char*)dst = *(char*)src;
+      break;
+    case 14:
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *(short*)dst = *(short*)src;
+      break;
+    case 15:
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *((long*)dst)++ = *((long*)src)++;
+      *((short*)dst)++ = *((short*)src)++;
+      *(char*)dst = *(char*)src;
+      break;
+  }
+
+  return return_dst; /* destination pointer. */
+} /* memcpy() */
diff -urN linux/arch/cris/arch-v32/lib/usercopy.c 
linux/arch/cris/arch-v32/lib/usercopy.c
--- linux/arch/cris/arch-v32/lib/usercopy.c     1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/lib/usercopy.c     2005-08-01 19:23:43.730891000 
+0100     1.1
@@ -0,0 +1,470 @@
+/*
+ * User address space access functions.
+ * The non-inlined parts of asm-cris/uaccess.h are here.
+ *
+ * Copyright (C) 2000, 2003 Axis Communications AB.
+ *
+ * Written by Hans-Peter Nilsson.
+ * Pieces used from memcpy, originally by Kenny Ranerup long time ago.
+ */
+
+#include <asm/uaccess.h>
+
+/* Asm:s have been tweaked (within the domain of correctness) to give
+   satisfactory results for "gcc version 3.2.1 Axis release R53/1.53-v32".
+
+   Check regularly...
+
+   Note that for CRISv32, the PC saved at a bus-fault is the address
+   *at* the faulting instruction, with a special case for instructions
+   in delay slots: then it's the address of the branch.  Note also that
+   in contrast to v10, a postincrement in the instruction is *not*
+   performed at a bus-fault; the register is seen having the original
+   value in fault handlers.  */
+
+
+/* Copy to userspace.  This is based on the memcpy used for
+   kernel-to-kernel copying; see "string.c".  */
+
+unsigned long
+__copy_user (void __user *pdst, const void *psrc, unsigned long pn)
+{
+  /* We want the parameters put in special registers.
+     Make sure the compiler is able to make something useful of this.
+     As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop).
+
+     FIXME: Comment for old gcc version.  Check.
+     If gcc was allright, it really would need no temporaries, and no
+     stack space to save stuff on. */
+
+  register char *dst __asm__ ("r13") = pdst;
+  register const char *src __asm__ ("r11") = psrc;
+  register int n __asm__ ("r12") = pn;
+  register int retn __asm__ ("r10") = 0;
+
+
+  /* When src is aligned but not dst, this makes a few extra needless
+     cycles.  I believe it would take as many to check that the
+     re-alignment was unnecessary.  */
+  if (((unsigned long) dst & 3) != 0
+      /* Don't align if we wouldn't copy more than a few bytes; so we
+        don't have to check further for overflows.  */
+      && n >= 3)
+  {
+    if ((unsigned long) dst & 1)
+    {
+      __asm_copy_to_user_1 (dst, src, retn);
+      n--;
+    }
+
+    if ((unsigned long) dst & 2)
+    {
+      __asm_copy_to_user_2 (dst, src, retn);
+      n -= 2;
+    }
+  }
+
+  /* Movem is dirt cheap.  The overheap is low enough to always use the
+     minimum possible block size as the threshold.  */
+  if (n >= 44)
+  {
+    /* For large copies we use 'movem'.  */
+
+    /* It is not optimal to tell the compiler about clobbering any
+       registers; that will move the saving/restoring of those registers
+       to the function prologue/epilogue, and make non-movem sizes
+       suboptimal.  */
+    __asm__ volatile ("\
+        ;; Check that the register asm declaration got right.          \n\
+        ;; The GCC manual explicitly says TRT will happen.             \n\
+       .ifnc %0%1%2%3,$r13$r11$r12$r10                                 \n\
+       .err                                                            \n\
+       .endif                                                          \n\
+                                                                       \n\
+       ;; Save the registers we'll use in the movem process            \n\
+       ;; on the stack.                                                \n\
+       subq    11*4,$sp                                                \n\
+       movem   $r10,[$sp]                                              \n\
+                                                                       \n\
+       ;; Now we've got this:                                          \n\
+       ;; r11 - src                                                    \n\
+       ;; r13 - dst                                                    \n\
+       ;; r12 - n                                                      \n\
+                                                                       \n\
+       ;; Update n for the first loop                                  \n\
+       subq    44,$r12                                                 \n\
+0:                                                                     \n\
+       movem   [$r11+],$r10                                            \n\
+       subq   44,$r12                                                  \n\
+1:     bge     0b                                                      \n\
+       movem   $r10,[$r13+]                                            \n\
+3:                                                                     \n\
+       addq   44,$r12  ;; compensate for last loop underflowing n      \n\
+                                                                       \n\
+       ;; Restore registers from stack                                 \n\
+       movem [$sp+],$r10                                               \n\
+2:                                                                     \n\
+       .section .fixup,\"ax\"                                          \n\
+4:                                                                     \n\
+; When failing on any of the 1..44 bytes in a chunk, we adjust back the        
\n\
+; source pointer and just drop through to the by-16 and by-4 loops to  \n\
+; get the correct number of failing bytes.  This necessarily means a   \n\
+; few extra exceptions, but invalid user pointers shouldn't happen in  \n\
+; time-critical code anyway.                                           \n\
+       jump 3b                                                         \n\
+       subq 44,$r11                                                    \n\
+                                                                       \n\
+       .previous                                                       \n\
+       .section __ex_table,\"a\"                                       \n\
+       .dword 1b,4b                                                    \n\
+       .previous"
+
+     /* Outputs */ : "=r" (dst), "=r" (src), "=r" (n), "=r" (retn)
+     /* Inputs */ : "0" (dst), "1" (src), "2" (n), "3" (retn));
+
+  }
+
+  while (n >= 16)
+  {
+    __asm_copy_to_user_16 (dst, src, retn);
+    n -= 16;
+  }
+
+  /* Having a separate by-four loops cuts down on cache footprint.
+     FIXME:  Test with and without; increasing switch to be 0..15.  */
+  while (n >= 4)
+  {
+    __asm_copy_to_user_4 (dst, src, retn);
+    n -= 4;
+  }
+
+  switch (n)
+  {
+    case 0:
+      break;
+    case 1:
+      __asm_copy_to_user_1 (dst, src, retn);
+      break;
+    case 2:
+      __asm_copy_to_user_2 (dst, src, retn);
+      break;
+    case 3:
+      __asm_copy_to_user_3 (dst, src, retn);
+      break;
+  }
+
+  return retn;
+}
+
+/* Copy from user to kernel, zeroing the bytes that were inaccessible in
+   userland.  The return-value is the number of bytes that were
+   inaccessible.  */
+
+unsigned long
+__copy_user_zeroing (void __user *pdst, const void *psrc, unsigned long pn)
+{
+  /* We want the parameters put in special registers.
+     Make sure the compiler is able to make something useful of this.
+     As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop).
+
+     FIXME: Comment for old gcc version.  Check.
+     If gcc was allright, it really would need no temporaries, and no
+     stack space to save stuff on.  */
+
+  register char *dst __asm__ ("r13") = pdst;
+  register const char *src __asm__ ("r11") = psrc;
+  register int n __asm__ ("r12") = pn;
+  register int retn __asm__ ("r10") = 0;
+
+  /* The best reason to align src is that we then know that a read-fault
+     was for aligned bytes; there's no 1..3 remaining good bytes to
+     pickle.  */
+  if (((unsigned long) src & 3) != 0)
+  {
+    if (((unsigned long) src & 1) && n != 0)
+    {
+      __asm_copy_from_user_1 (dst, src, retn);
+      n--;
+    }
+
+    if (((unsigned long) src & 2) && n >= 2)
+    {
+      __asm_copy_from_user_2 (dst, src, retn);
+      n -= 2;
+    }
+
+    /* We only need one check after the unalignment-adjustments, because
+       if both adjustments were done, either both or neither reference
+       had an exception.  */
+    if (retn != 0)
+      goto copy_exception_bytes;
+  }
+
+  /* Movem is dirt cheap.  The overheap is low enough to always use the
+     minimum possible block size as the threshold.  */
+  if (n >= 44)
+  {
+    /* It is not optimal to tell the compiler about clobbering any
+       registers; that will move the saving/restoring of those registers
+       to the function prologue/epilogue, and make non-movem sizes
+       suboptimal.  */
+    __asm__ volatile ("\
+       .ifnc %0%1%2%3,$r13$r11$r12$r10                                 \n\
+       .err                                                            \n\
+       .endif                                                          \n\
+                                                                       \n\
+       ;; Save the registers we'll use in the movem process            \n\
+       ;; on the stack.                                                \n\
+       subq    11*4,$sp                                                \n\
+       movem   $r10,[$sp]                                              \n\
+                                                                       \n\
+       ;; Now we've got this:                                          \n\
+       ;; r11 - src                                                    \n\
+       ;; r13 - dst                                                    \n\
+       ;; r12 - n                                                      \n\
+                                                                       \n\
+       ;; Update n for the first loop                                  \n\
+       subq    44,$r12                                                 \n\
+0:                                                                     \n\
+       movem   [$r11+],$r10                                            \n\
+                                                                       \n\
+       subq   44,$r12                                                  \n\
+       bge     0b                                                      \n\
+       movem   $r10,[$r13+]                                            \n\
+                                                                       \n\
+4:                                                                     \n\
+       addq   44,$r12  ;; compensate for last loop underflowing n      \n\
+                                                                       \n\
+       ;; Restore registers from stack                                 \n\
+       movem [$sp+],$r10                                               \n\
+       .section .fixup,\"ax\"                                          \n\
+                                                                       \n\
+;; Do not jump back into the loop if we fail.  For some uses, we get a \n\
+;; page fault somewhere on the line.  Without checking for page limits,        
\n\
+;; we don't know where, but we need to copy accurately and keep an     \n\
+;; accurate count; not just clear the whole line.  To do that, we fall \n\
+;; down in the code below, proceeding with smaller amounts.  It should \n\
+;; be kept in mind that we have to cater to code like what at one time \n\
+;; was in fs/super.c:                                                  \n\
+;;  i = size - copy_from_user((void *)page, data, size);               \n\
+;; which would cause repeated faults while clearing the remainder of   \n\
+;; the SIZE bytes at PAGE after the first fault.                       \n\
+;; A caveat here is that we must not fall through from a failing page  \n\
+;; to a valid page.                                                    \n\
+                                                                       \n\
+3:                                                                     \n\
+       jump    4b ;; Fall through, pretending the fault didn't happen. \n\
+       nop                                                             \n\
+                                                                       \n\
+       .previous                                                       \n\
+       .section __ex_table,\"a\"                                       \n\
+       .dword 0b,3b                                                    \n\
+       .previous"
+
+     /* Outputs */ : "=r" (dst), "=r" (src), "=r" (n), "=r" (retn)
+     /* Inputs */ : "0" (dst), "1" (src), "2" (n), "3" (retn));
+  }
+
+  /* Either we directly start copying here, using dword copying in a loop,
+     or we copy as much as possible with 'movem' and then the last block
+     (<44 bytes) is copied here.  This will work since 'movem' will have
+     updated src, dst and n.  (Except with failing src.)
+
+     Since we want to keep src accurate, we can't use
+     __asm_copy_from_user_N with N != (1, 2, 4); it updates dst and
+     retn, but not src (by design; it's value is ignored elsewhere).  */
+
+  while (n >= 4)
+  {
+    __asm_copy_from_user_4 (dst, src, retn);
+    n -= 4;
+
+    if (retn)
+      goto copy_exception_bytes;
+  }
+
+  /* If we get here, there were no memory read faults.  */
+  switch (n)
+  {
+    /* These copies are at least "naturally aligned" (so we don't have
+       to check each byte), due to the src alignment code before the
+       movem loop.  The *_3 case *will* get the correct count for retn.  */
+    case 0:
+      /* This case deliberately left in (if you have doubts check the
+        generated assembly code).  */
+      break;
+    case 1:
+      __asm_copy_from_user_1 (dst, src, retn);
+      break;
+    case 2:
+      __asm_copy_from_user_2 (dst, src, retn);
+      break;
+    case 3:
+      __asm_copy_from_user_3 (dst, src, retn);
+      break;
+  }
+
+  /* If we get here, retn correctly reflects the number of failing
+     bytes.  */
+  return retn;
+
+copy_exception_bytes:
+  /* We already have "retn" bytes cleared, and need to clear the
+     remaining "n" bytes.  A non-optimized simple byte-for-byte in-line
+     memset is preferred here, since this isn't speed-critical code and
+     we'd rather have this a leaf-function than calling memset.  */
+  {
+    char *endp;
+    for (endp = dst + n; dst < endp; dst++)
+      *dst = 0;
+  }
+
+  return retn + n;
+}
+
+/* Zero userspace.  */
+
+unsigned long
+__do_clear_user (void __user *pto, unsigned long pn)
+{
+  /* We want the parameters put in special registers.
+     Make sure the compiler is able to make something useful of this.
+      As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop).
+
+     FIXME: Comment for old gcc version.  Check.
+     If gcc was allright, it really would need no temporaries, and no
+     stack space to save stuff on. */
+
+  register char *dst __asm__ ("r13") = pto;
+  register int n __asm__ ("r12") = pn;
+  register int retn __asm__ ("r10") = 0;
+
+
+  if (((unsigned long) dst & 3) != 0
+     /* Don't align if we wouldn't copy more than a few bytes.  */
+      && n >= 3)
+  {
+    if ((unsigned long) dst & 1)
+    {
+      __asm_clear_1 (dst, retn);
+      n--;
+    }
+
+    if ((unsigned long) dst & 2)
+    {
+      __asm_clear_2 (dst, retn);
+      n -= 2;
+    }
+  }
+
+  /* Decide which copying method to use.
+     FIXME: This number is from the "ordinary" kernel memset.  */
+  if (n >= 48)
+  {
+    /* For large clears we use 'movem' */
+
+    /* It is not optimal to tell the compiler about clobbering any
+       call-saved registers; that will move the saving/restoring of
+       those registers to the function prologue/epilogue, and make
+       non-movem sizes suboptimal.
+
+       This method is not foolproof; it assumes that the "asm reg"
+       declarations at the beginning of the function really are used
+       here (beware: they may be moved to temporary registers).
+       This way, we do not have to save/move the registers around into
+       temporaries; we can safely use them straight away.
+
+      If you want to check that the allocation was right; then
+      check the equalities in the first comment.  It should say
+      something like "r13=r13, r11=r11, r12=r12". */
+    __asm__ volatile ("\
+       .ifnc %0%1%2,$r13$r12$r10                                       \n\
+       .err                                                            \n\
+       .endif                                                          \n\
+                                                                       \n\
+       ;; Save the registers we'll clobber in the movem process        \n\
+       ;; on the stack.  Don't mention them to gcc, it will only be    \n\
+       ;; upset.                                                       \n\
+       subq    11*4,$sp                                                \n\
+       movem   $r10,[$sp]                                              \n\
+                                                                       \n\
+       clear.d $r0                                                     \n\
+       clear.d $r1                                                     \n\
+       clear.d $r2                                                     \n\
+       clear.d $r3                                                     \n\
+       clear.d $r4                                                     \n\
+       clear.d $r5                                                     \n\
+       clear.d $r6                                                     \n\
+       clear.d $r7                                                     \n\
+       clear.d $r8                                                     \n\
+       clear.d $r9                                                     \n\
+       clear.d $r10                                                    \n\
+       clear.d $r11                                                    \n\
+                                                                       \n\
+       ;; Now we've got this:                                          \n\
+       ;; r13 - dst                                                    \n\
+       ;; r12 - n                                                      \n\
+                                                                       \n\
+       ;; Update n for the first loop                                  \n\
+       subq    12*4,$r12                                               \n\
+0:                                                                     \n\
+       subq   12*4,$r12                                                \n\
+1:                                                                     \n\
+       bge     0b                                                      \n\
+       movem   $r11,[$r13+]                                            \n\
+                                                                       \n\
+       addq   12*4,$r12 ;; compensate for last loop underflowing n     \n\
+                                                                       \n\
+       ;; Restore registers from stack                                 \n\
+       movem [$sp+],$r10                                               \n\
+2:                                                                     \n\
+       .section .fixup,\"ax\"                                          \n\
+3:                                                                     \n\
+       movem [$sp],$r10                                                \n\
+       addq 12*4,$r10                                                  \n\
+       addq 12*4,$r13                                                  \n\
+       movem $r10,[$sp]                                                \n\
+       jump 0b                                                         \n\
+       clear.d $r10                                                    \n\
+                                                                       \n\
+       .previous                                                       \n\
+       .section __ex_table,\"a\"                                       \n\
+       .dword 1b,3b                                                    \n\
+       .previous"
+
+     /* Outputs */ : "=r" (dst), "=r" (n), "=r" (retn)
+     /* Inputs */ : "0" (dst), "1" (n), "2" (retn)
+     /* Clobber */ : "r11");
+  }
+
+  while (n >= 16)
+  {
+    __asm_clear_16 (dst, retn);
+    n -= 16;
+  }
+
+  /* Having a separate by-four loops cuts down on cache footprint.
+     FIXME:  Test with and without; increasing switch to be 0..15.  */
+  while (n >= 4)
+  {
+    __asm_clear_4 (dst, retn);
+    n -= 4;
+  }
+
+  switch (n)
+  {
+    case 0:
+      break;
+    case 1:
+      __asm_clear_1 (dst, retn);
+      break;
+    case 2:
+      __asm_clear_2 (dst, retn);
+      break;
+    case 3:
+      __asm_clear_3 (dst, retn);
+      break;
+  }
+
+  return retn;
+}
diff -urN linux/arch/cris/arch-v32/mm/Makefile 
linux/arch/cris/arch-v32/mm/Makefile
--- linux/arch/cris/arch-v32/mm/Makefile        1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/mm/Makefile        2005-08-01 19:23:43.867183000 
+0100     1.1
@@ -0,0 +1,3 @@
+# Makefile for the Linux/cris parts of the memory manager.
+
+obj-y   := mmu.o init.o tlb.o intmem.o
diff -urN linux/arch/cris/arch-v32/mm/init.c linux/arch/cris/arch-v32/mm/init.c
--- linux/arch/cris/arch-v32/mm/init.c  1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/mm/init.c  2005-08-01 19:23:43.892862000 +0100     
1.1
@@ -0,0 +1,174 @@
+/*
+ * Set up paging and the MMU.
+ *
+ * Copyright (C) 2000-2003, Axis Communications AB.
+ *
+ * Authors:   Bjorn Wesen <bjornw@axis.com>
+ *            Tobias Anderberg <tobiasa@axis.com>, CRISv32 port.
+ */
+#include <linux/config.h>
+#include <linux/mmzone.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/mm.h>
+#include <linux/config.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/types.h>
+#include <asm/mmu.h>
+#include <asm/io.h>
+#include <asm/mmu_context.h>
+#include <asm/arch/hwregs/asm/mmu_defs_asm.h>
+#include <asm/arch/hwregs/supp_reg.h>
+
+extern void tlb_init(void);
+
+/*
+ * The kernel is already mapped with linear mapping at kseg_c so there's no
+ * need to map it with a page table. However, head.S also temporarily mapped it
+ * at kseg_4 thus the ksegs are set up again. Also clear the TLB and do various
+ * other paging stuff.
+ */
+void __init
+cris_mmu_init(void)
+{
+       unsigned long mmu_config;
+       unsigned long mmu_kbase_hi;
+       unsigned long mmu_kbase_lo;
+       unsigned short mmu_page_id;
+
+       /*
+        * Make sure the current pgd table points to something sane, even if it
+        * is most probably not used until the next switch_mm.
+        */
+       per_cpu(current_pgd, smp_processor_id()) = init_mm.pgd;
+
+#ifdef CONFIG_SMP
+       {
+               pgd_t **pgd;
+               pgd = (pgd_t**)&per_cpu(current_pgd, smp_processor_id());
+               SUPP_BANK_SEL(1);
+               SUPP_REG_WR(RW_MM_TLB_PGD, pgd);
+               SUPP_BANK_SEL(2);
+               SUPP_REG_WR(RW_MM_TLB_PGD, pgd);
+       }
+#endif
+
+       /* Initialise the TLB. Function found in tlb.c. */
+       tlb_init();
+
+       /* Enable exceptions and initialize the kernel segments. */
+       mmu_config = ( REG_STATE(mmu, rw_mm_cfg, we, on)        |
+                      REG_STATE(mmu, rw_mm_cfg, acc, on)       |
+                      REG_STATE(mmu, rw_mm_cfg, ex, on)        |
+                      REG_STATE(mmu, rw_mm_cfg, inv, on)       |
+                      REG_STATE(mmu, rw_mm_cfg, seg_f, linear) |
+                      REG_STATE(mmu, rw_mm_cfg, seg_e, linear) |
+                      REG_STATE(mmu, rw_mm_cfg, seg_d, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_c, linear) |
+                      REG_STATE(mmu, rw_mm_cfg, seg_b, linear) |
+#ifndef CONFIG_ETRAXFS_SIM
+                       REG_STATE(mmu, rw_mm_cfg, seg_a, page)   |
+#else
+                      REG_STATE(mmu, rw_mm_cfg, seg_a, linear) |
+#endif
+                      REG_STATE(mmu, rw_mm_cfg, seg_9, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_8, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_7, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_6, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_5, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_4, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_3, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_2, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_1, page)   |
+                      REG_STATE(mmu, rw_mm_cfg, seg_0, page));
+
+       mmu_kbase_hi = ( REG_FIELD(mmu, rw_mm_kbase_hi, base_f, 0x0) |
+                        REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 0x8) |
+                        REG_FIELD(mmu, rw_mm_kbase_hi, base_d, 0x0) |
+#ifndef CONFIG_ETRAXFS_SIM
+                         REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0x4) |
+#else
+                        REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0x0) |
+#endif
+                        REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb) |
+#ifndef CONFIG_ETRAXFS_SIM
+                        REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0x0) |
+#else
+                         REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa) |
+#endif
+                        REG_FIELD(mmu, rw_mm_kbase_hi, base_9, 0x0) |
+                        REG_FIELD(mmu, rw_mm_kbase_hi, base_8, 0x0));
+
+       mmu_kbase_lo = ( REG_FIELD(mmu, rw_mm_kbase_lo, base_7, 0x0) |
+                        REG_FIELD(mmu, rw_mm_kbase_lo, base_6, 0x0) |
+                        REG_FIELD(mmu, rw_mm_kbase_lo, base_5, 0x0) |
+                        REG_FIELD(mmu, rw_mm_kbase_lo, base_4, 0x0) |
+                        REG_FIELD(mmu, rw_mm_kbase_lo, base_3, 0x0) |
+                        REG_FIELD(mmu, rw_mm_kbase_lo, base_2, 0x0) |
+                        REG_FIELD(mmu, rw_mm_kbase_lo, base_1, 0x0) |
+                        REG_FIELD(mmu, rw_mm_kbase_lo, base_0, 0x0));
+
+       mmu_page_id = REG_FIELD(mmu, rw_mm_tlb_hi, pid, 0);
+
+       /* Update the instruction MMU. */
+       SUPP_BANK_SEL(BANK_IM);
+       SUPP_REG_WR(RW_MM_CFG, mmu_config);
+       SUPP_REG_WR(RW_MM_KBASE_HI, mmu_kbase_hi);
+       SUPP_REG_WR(RW_MM_KBASE_LO, mmu_kbase_lo);
+       SUPP_REG_WR(RW_MM_TLB_HI, mmu_page_id);
+
+       /* Update the data MMU. */
+       SUPP_BANK_SEL(BANK_DM);
+       SUPP_REG_WR(RW_MM_CFG, mmu_config);
+       SUPP_REG_WR(RW_MM_KBASE_HI, mmu_kbase_hi);
+       SUPP_REG_WR(RW_MM_KBASE_LO, mmu_kbase_lo);
+       SUPP_REG_WR(RW_MM_TLB_HI, mmu_page_id);
+
+       SPEC_REG_WR(SPEC_REG_PID, 0);
+
+       /*
+        * The MMU has been enabled ever since head.S but just to make it
+        * totally obvious enable it here as well.
+        */
+       SUPP_BANK_SEL(BANK_GC);
+       SUPP_REG_WR(RW_GC_CFG, 0xf); /* IMMU, DMMU, ICache, DCache on */
+}
+
+void __init
+paging_init(void)
+{
+       int i;
+       unsigned long zones_size[MAX_NR_ZONES];
+
+       printk("Setting up paging and the MMU.\n");
+
+       /* Clear out the init_mm.pgd that will contain the kernel's mappings. */
+       for(i = 0; i < PTRS_PER_PGD; i++)
+               swapper_pg_dir[i] = __pgd(0);
+
+       cris_mmu_init();
+
+       /*
+        * Initialize the bad page table and bad page to point to a couple of
+        * allocated pages.
+        */
+       empty_zero_page = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
+       memset((void *) empty_zero_page, 0, PAGE_SIZE);
+
+       /* All pages are DMA'able in Etrax, so put all in the DMA'able zone. */
+       zones_size[0] = ((unsigned long) high_memory - PAGE_OFFSET) >> 
PAGE_SHIFT;
+
+       for (i = 1; i < MAX_NR_ZONES; i++)
+               zones_size[i] = 0;
+
+       /*
+        * Use free_area_init_node instead of free_area_init, because it is
+        * designed for systems where the DRAM starts at an address
+        * substantially higher than 0, like us (we start at PAGE_OFFSET). This
+        * saves space in the mem_map page array.
+        */
+       free_area_init_node(0, &contig_page_data, zones_size, PAGE_OFFSET >> 
PAGE_SHIFT, 0);
+
+       mem_map = contig_page_data.node_mem_map;
+}
diff -urN linux/arch/cris/arch-v32/mm/intmem.c 
linux/arch/cris/arch-v32/mm/intmem.c
--- linux/arch/cris/arch-v32/mm/intmem.c        1970/01/01 00:00:00
+++ linux/arch/cris/arch-v32/mm/intmem.c        2005-08-01 19:23:43.914470000 
+0100     1.1
@@ -0,0 +1,139 @@
+/*
+ * Simple allocator for internal RAM in ETRAX FS
+ *
+ * Copyright (c) 2004 Axis Communications AB.
+ */
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+#include <asm/arch/memmap.h>
+
+#define STATUS_FREE 0
+#define STATUS_ALLOCATED 1
+
+struct intmem_allocation {
+       struct list_head entry;
+       unsigned int size;
+       unsigned offset;
+       char status;
+};
+
+
+static struct list_head intmem_allocations;
+static void* intmem_virtual;
+
+static void crisv32_intmem_init(void)
+{
+       static int initiated = 0;
+       if (!initiated) {
+               struct intmem_allocation* alloc =
+                 (struct intmem_allocation*)kmalloc(sizeof *alloc, GFP_KERNEL);
+               INIT_LIST_HEAD(&intmem_allocations);
+               intmem_virtual = ioremap(MEM_INTMEM_START, MEM_INTMEM_SIZE);
+               initiated = 1;
+               alloc->size = MEM_INTMEM_SIZE;
+               alloc->offset = 0;
+               alloc->status = STATUS_FREE;
+               list_add_tail(&alloc->entry, &intmem_allocations);
+       }
+}
+
+void* crisv32_intmem_alloc(unsigned size, unsigned align)
+{
+       struct intmem_allocation* allocation;
+       struct intmem_allocation* tmp;
+       void* ret = NULL;
+
+       preempt_disable();
+       crisv32_intmem_init();
+
+       list_for_each_entry_safe(allocation, tmp, &intmem_allocations, entry) {
+               int alignment = allocation->offset % align;
+               alignment = alignment ? align - alignment : alignment;
+
+               if (allocation->status == STATUS_FREE &&
+                   allocation->size >= size + alignment) {
+                       if (allocation->size > size + alignment) {
+                               struct intmem_allocation*